• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * (C) 2005-2012 by Pablo Neira Ayuso <pablo@netfilter.org>
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This code has been sponsored by Vyatta Inc. <http://www.vyatta.com>
10  */
11 
12 #include "internal/internal.h"
13 #include <limits.h>
14 #include <libmnl/libmnl.h>
15 
16 static int
nfct_build_tuple_ip(struct nlmsghdr * nlh,const struct __nfct_tuple * t)17 nfct_build_tuple_ip(struct nlmsghdr *nlh, const struct __nfct_tuple *t)
18 {
19 	struct nlattr *nest;
20 
21 	nest = mnl_attr_nest_start(nlh, CTA_TUPLE_IP);
22 	if (nest == NULL)
23 		return -1;
24 
25 	switch(t->l3protonum) {
26 	case AF_INET:
27 		mnl_attr_put_u32(nlh, CTA_IP_V4_SRC, t->src.v4);
28 		mnl_attr_put_u32(nlh, CTA_IP_V4_DST, t->dst.v4);
29 		break;
30 	case AF_INET6:
31 		mnl_attr_put(nlh, CTA_IP_V6_SRC, sizeof(struct in6_addr),
32 				&t->src.v6);
33 		mnl_attr_put(nlh, CTA_IP_V6_DST, sizeof(struct in6_addr),
34 				&t->dst.v6);
35 		break;
36 	default:
37 		mnl_attr_nest_cancel(nlh, nest);
38 		return -1;
39 	}
40 	mnl_attr_nest_end(nlh, nest);
41 	return 0;
42 }
43 
44 static int
nfct_build_tuple_proto(struct nlmsghdr * nlh,const struct __nfct_tuple * t)45 nfct_build_tuple_proto(struct nlmsghdr *nlh, const struct __nfct_tuple *t)
46 {
47 	struct nlattr *nest;
48 
49 	nest = mnl_attr_nest_start(nlh, CTA_TUPLE_PROTO);
50 	if (nest == NULL)
51 		return -1;
52 
53 	mnl_attr_put_u8(nlh, CTA_PROTO_NUM, t->protonum);
54 
55 	switch(t->protonum) {
56 	case IPPROTO_UDP:
57 	case IPPROTO_TCP:
58 	case IPPROTO_SCTP:
59 	case IPPROTO_DCCP:
60 	case IPPROTO_GRE:
61 	case IPPROTO_UDPLITE:
62 		mnl_attr_put_u16(nlh, CTA_PROTO_SRC_PORT, t->l4src.tcp.port);
63 		mnl_attr_put_u16(nlh, CTA_PROTO_DST_PORT, t->l4dst.tcp.port);
64 		break;
65 	case IPPROTO_ICMP:
66 		mnl_attr_put_u8(nlh, CTA_PROTO_ICMP_CODE, t->l4dst.icmp.code);
67 		mnl_attr_put_u8(nlh, CTA_PROTO_ICMP_TYPE, t->l4dst.icmp.type);
68 		mnl_attr_put_u16(nlh, CTA_PROTO_ICMP_ID, t->l4src.icmp.id);
69 		break;
70 	case IPPROTO_ICMPV6:
71 		mnl_attr_put_u8(nlh, CTA_PROTO_ICMPV6_CODE, t->l4dst.icmp.code);
72 		mnl_attr_put_u8(nlh, CTA_PROTO_ICMPV6_TYPE, t->l4dst.icmp.type);
73 		mnl_attr_put_u16(nlh, CTA_PROTO_ICMPV6_ID, t->l4src.icmp.id);
74 		break;
75 	default:
76 		mnl_attr_nest_cancel(nlh, nest);
77 		return -1;
78 	}
79 	mnl_attr_nest_end(nlh, nest);
80 	return 0;
81 }
82 
83 int
nfct_build_tuple_raw(struct nlmsghdr * nlh,const struct __nfct_tuple * t)84 nfct_build_tuple_raw(struct nlmsghdr *nlh, const struct __nfct_tuple *t)
85 {
86 	if (nfct_build_tuple_ip(nlh, t) < 0)
87 		return -1;
88 	if (nfct_build_tuple_proto(nlh, t) < 0)
89 		return -1;
90 
91 	return 0;
92 }
93 
94 int
nfct_build_tuple(struct nlmsghdr * nlh,const struct __nfct_tuple * t,int type)95 nfct_build_tuple(struct nlmsghdr *nlh, const struct __nfct_tuple *t, int type)
96 {
97 	struct nlattr *nest;
98 
99 	nest = mnl_attr_nest_start(nlh, type);
100 	if (nest == NULL)
101 		return -1;
102 
103 	if (nfct_build_tuple_raw(nlh, t) < 0)
104 		goto err;
105 
106 	mnl_attr_nest_end(nlh, nest);
107 	return 0;
108 err:
109 	mnl_attr_nest_cancel(nlh, nest);
110 	return -1;
111 }
112 
113 static int
nfct_build_protoinfo(struct nlmsghdr * nlh,const struct nf_conntrack * ct)114 nfct_build_protoinfo(struct nlmsghdr *nlh, const struct nf_conntrack *ct)
115 {
116 	struct nlattr *nest, *nest_proto;
117 
118 	switch(ct->head.orig.protonum) {
119 	case IPPROTO_TCP:
120 		/* Preliminary attribute check to avoid sending an empty
121 		 * CTA_PROTOINFO_TCP nest, which results in EINVAL in
122 		 * Linux kernel <= 2.6.25. */
123 		if (!(test_bit(ATTR_TCP_STATE, ct->head.set) ||
124 		      test_bit(ATTR_TCP_FLAGS_ORIG, ct->head.set) ||
125 		      test_bit(ATTR_TCP_FLAGS_REPL, ct->head.set) ||
126 		      test_bit(ATTR_TCP_MASK_ORIG, ct->head.set) ||
127 		      test_bit(ATTR_TCP_MASK_REPL, ct->head.set) ||
128 		      test_bit(ATTR_TCP_WSCALE_ORIG, ct->head.set) ||
129 		      test_bit(ATTR_TCP_WSCALE_REPL, ct->head.set))) {
130 			break;
131 		}
132 		nest = mnl_attr_nest_start(nlh, CTA_PROTOINFO);
133 		nest_proto = mnl_attr_nest_start(nlh, CTA_PROTOINFO_TCP);
134 		if (test_bit(ATTR_TCP_STATE, ct->head.set)) {
135 			mnl_attr_put_u8(nlh, CTA_PROTOINFO_TCP_STATE,
136 					ct->protoinfo.tcp.state);
137 		}
138 		if (test_bit(ATTR_TCP_FLAGS_ORIG, ct->head.set) &&
139 		    test_bit(ATTR_TCP_MASK_ORIG, ct->head.set)) {
140 			mnl_attr_put(nlh, CTA_PROTOINFO_TCP_FLAGS_ORIGINAL,
141 				     sizeof(struct nf_ct_tcp_flags),
142 				     &ct->protoinfo.tcp.flags[0]);
143 		}
144 		if (test_bit(ATTR_TCP_FLAGS_REPL, ct->head.set) &&
145 		    test_bit(ATTR_TCP_MASK_REPL, ct->head.set)) {
146 			mnl_attr_put(nlh, CTA_PROTOINFO_TCP_FLAGS_REPLY,
147 				     sizeof(struct nf_ct_tcp_flags),
148 				     &ct->protoinfo.tcp.flags[1]);
149 		}
150 		if (test_bit(ATTR_TCP_WSCALE_ORIG, ct->head.set)) {
151 			mnl_attr_put_u8(nlh, CTA_PROTOINFO_TCP_WSCALE_ORIGINAL,
152 					ct->protoinfo.tcp.wscale[__DIR_ORIG]);
153 		}
154 		if (test_bit(ATTR_TCP_WSCALE_REPL, ct->head.set)) {
155 			mnl_attr_put_u8(nlh, CTA_PROTOINFO_TCP_WSCALE_REPLY,
156 					ct->protoinfo.tcp.wscale[__DIR_REPL]);
157 		}
158 		mnl_attr_nest_end(nlh, nest_proto);
159 		mnl_attr_nest_end(nlh, nest);
160 		break;
161 	case IPPROTO_SCTP:
162 		/* See comment above on TCP. */
163 		if (!(test_bit(ATTR_SCTP_STATE, ct->head.set) ||
164 		      test_bit(ATTR_SCTP_VTAG_ORIG, ct->head.set) ||
165 		      test_bit(ATTR_SCTP_VTAG_REPL, ct->head.set))) {
166 			break;
167 		}
168 		nest = mnl_attr_nest_start(nlh, CTA_PROTOINFO);
169 		nest_proto = mnl_attr_nest_start(nlh, CTA_PROTOINFO_SCTP);
170 
171 		if (test_bit(ATTR_SCTP_STATE, ct->head.set)) {
172 			mnl_attr_put_u8(nlh, CTA_PROTOINFO_SCTP_STATE,
173 					ct->protoinfo.sctp.state);
174 		}
175 		if (test_bit(ATTR_SCTP_VTAG_ORIG, ct->head.set)) {
176 			mnl_attr_put_u32(nlh, CTA_PROTOINFO_SCTP_VTAG_ORIGINAL,
177 				htonl(ct->protoinfo.sctp.vtag[__DIR_ORIG]));
178 		}
179 		if (test_bit(ATTR_SCTP_VTAG_REPL, ct->head.set)) {
180 			mnl_attr_put_u32(nlh, CTA_PROTOINFO_SCTP_VTAG_REPLY,
181 				htonl(ct->protoinfo.sctp.vtag[__DIR_REPL]));
182 		}
183 		mnl_attr_nest_end(nlh, nest_proto);
184 		mnl_attr_nest_end(nlh, nest);
185 		break;
186 	case IPPROTO_DCCP:
187 		/* See comment above on TCP. */
188 		if (!(test_bit(ATTR_DCCP_STATE, ct->head.set) ||
189 		      test_bit(ATTR_DCCP_ROLE, ct->head.set) ||
190 		      test_bit(ATTR_DCCP_HANDSHAKE_SEQ, ct->head.set))) {
191 			break;
192 		}
193 		nest = mnl_attr_nest_start(nlh, CTA_PROTOINFO);
194 		nest_proto = mnl_attr_nest_start(nlh, CTA_PROTOINFO_DCCP);
195 		if (test_bit(ATTR_DCCP_STATE, ct->head.set)) {
196 			mnl_attr_put_u8(nlh, CTA_PROTOINFO_DCCP_STATE,
197 					ct->protoinfo.dccp.state);
198 		}
199 		if (test_bit(ATTR_DCCP_ROLE, ct->head.set)) {
200 			mnl_attr_put_u8(nlh, CTA_PROTOINFO_DCCP_ROLE,
201 					ct->protoinfo.dccp.role);
202 		}
203 		if (test_bit(ATTR_DCCP_HANDSHAKE_SEQ, ct->head.set)) {
204 			uint64_t handshake_seq =
205 				be64toh(ct->protoinfo.dccp.handshake_seq);
206 
207 			mnl_attr_put_u64(nlh, CTA_PROTOINFO_DCCP_HANDSHAKE_SEQ,
208 					 handshake_seq);
209 		}
210 		mnl_attr_nest_end(nlh, nest_proto);
211 		mnl_attr_nest_end(nlh, nest);
212 	default:
213 		break;
214 	}
215 	return 0;
216 }
217 
218 static int
nfct_nat_seq_adj(struct nlmsghdr * nlh,const struct nf_conntrack * ct,int dir)219 nfct_nat_seq_adj(struct nlmsghdr *nlh, const struct nf_conntrack *ct, int dir)
220 {
221 	mnl_attr_put_u32(nlh, CTA_NAT_SEQ_CORRECTION_POS,
222 			 htonl(ct->natseq[dir].correction_pos));
223 	mnl_attr_put_u32(nlh, CTA_NAT_SEQ_OFFSET_BEFORE,
224 			 htonl(ct->natseq[dir].offset_before));
225 	mnl_attr_put_u32(nlh, CTA_NAT_SEQ_OFFSET_AFTER,
226 			 htonl(ct->natseq[dir].offset_after));
227 	return 0;
228 }
229 
230 static int
nfct_build_nat_seq_adj(struct nlmsghdr * nlh,const struct nf_conntrack * ct,int dir)231 nfct_build_nat_seq_adj(struct nlmsghdr *nlh, const struct nf_conntrack *ct,
232 		      int dir)
233 {
234 	int type = (dir == __DIR_ORIG) ? CTA_NAT_SEQ_ADJ_ORIG :
235 					 CTA_NAT_SEQ_ADJ_REPLY;
236 	struct nlattr *nest;
237 
238 	nest = mnl_attr_nest_start(nlh, type);
239 	nfct_nat_seq_adj(nlh, ct, dir);
240 	mnl_attr_nest_end(nlh, nest);
241 
242 	return 0;
243 }
244 
245 static int
nfct_build_protonat(struct nlmsghdr * nlh,const struct nf_conntrack * ct,const struct __nfct_nat * nat)246 nfct_build_protonat(struct nlmsghdr *nlh, const struct nf_conntrack *ct,
247 		   const struct __nfct_nat *nat)
248 {
249 	struct nlattr *nest;
250 
251 	nest = mnl_attr_nest_start(nlh, CTA_NAT_PROTO);
252 
253 	switch (ct->head.orig.protonum) {
254 	case IPPROTO_TCP:
255 	case IPPROTO_UDP:
256 		mnl_attr_put_u16(nlh, CTA_PROTONAT_PORT_MIN,
257 				 nat->l4min.tcp.port);
258 		mnl_attr_put_u16(nlh, CTA_PROTONAT_PORT_MAX,
259 				 nat->l4max.tcp.port);
260 	break;
261 	}
262 	mnl_attr_nest_end(nlh, nest);
263 	return 0;
264 }
265 
266 static int
nfct_build_nat(struct nlmsghdr * nlh,const struct __nfct_nat * nat,uint8_t l3protonum)267 nfct_build_nat(struct nlmsghdr *nlh, const struct __nfct_nat *nat,
268 	       uint8_t l3protonum)
269 {
270 	switch (l3protonum) {
271 	case AF_INET:
272 		mnl_attr_put_u32(nlh, CTA_NAT_MINIP, nat->min_ip.v4);
273 		break;
274 	case AF_INET6:
275 		mnl_attr_put(nlh, CTA_NAT_V6_MINIP, sizeof(struct in6_addr),
276 			     &nat->min_ip.v6);
277 		break;
278 	default:
279 		break;
280 	}
281 	return 0;
282 }
283 
284 static int
nfct_build_snat(struct nlmsghdr * nlh,const struct nf_conntrack * ct,uint8_t l3protonum)285 nfct_build_snat(struct nlmsghdr *nlh, const struct nf_conntrack *ct,
286 		uint8_t l3protonum)
287 {
288 	struct nlattr *nest;
289 
290 	nest = mnl_attr_nest_start(nlh, CTA_NAT_SRC);
291 	nfct_build_nat(nlh, &ct->snat, l3protonum);
292 	nfct_build_protonat(nlh, ct, &ct->snat);
293 	mnl_attr_nest_end(nlh, nest);
294 	return 0;
295 }
296 
297 static int
nfct_build_snat_ipv4(struct nlmsghdr * nlh,const struct nf_conntrack * ct)298 nfct_build_snat_ipv4(struct nlmsghdr *nlh, const struct nf_conntrack *ct)
299 {
300 	struct nlattr *nest;
301 
302 	nest = mnl_attr_nest_start(nlh, CTA_NAT_SRC);
303 	nfct_build_nat(nlh, &ct->snat, AF_INET);
304 	mnl_attr_nest_end(nlh, nest);
305 	return 0;
306 }
307 
308 static int
nfct_build_snat_ipv6(struct nlmsghdr * nlh,const struct nf_conntrack * ct)309 nfct_build_snat_ipv6(struct nlmsghdr *nlh, const struct nf_conntrack *ct)
310 {
311 	struct nlattr *nest;
312 
313 	nest = mnl_attr_nest_start(nlh, CTA_NAT_SRC);
314 	nfct_build_nat(nlh, &ct->snat, AF_INET6);
315 	mnl_attr_nest_end(nlh, nest);
316 	return 0;
317 }
318 
319 static int
nfct_build_snat_port(struct nlmsghdr * nlh,const struct nf_conntrack * ct)320 nfct_build_snat_port(struct nlmsghdr *nlh, const struct nf_conntrack *ct)
321 {
322 	struct nlattr *nest;
323 
324 	nest = mnl_attr_nest_start(nlh, CTA_NAT_SRC);
325 	nfct_build_protonat(nlh, ct, &ct->snat);
326 	mnl_attr_nest_end(nlh, nest);
327 	return 0;
328 }
329 
330 static int
nfct_build_dnat(struct nlmsghdr * nlh,const struct nf_conntrack * ct,uint8_t l3protonum)331 nfct_build_dnat(struct nlmsghdr *nlh, const struct nf_conntrack *ct,
332 		uint8_t l3protonum)
333 {
334 	struct nlattr *nest;
335 
336 	nest = mnl_attr_nest_start(nlh, CTA_NAT_DST);
337 	nfct_build_nat(nlh, &ct->dnat, l3protonum);
338 	nfct_build_protonat(nlh, ct, &ct->dnat);
339 	mnl_attr_nest_end(nlh, nest);
340 	return 0;
341 }
342 
343 static int
nfct_build_dnat_ipv4(struct nlmsghdr * nlh,const struct nf_conntrack * ct)344 nfct_build_dnat_ipv4(struct nlmsghdr *nlh, const struct nf_conntrack *ct)
345 {
346 	struct nlattr *nest;
347 
348 	nest = mnl_attr_nest_start(nlh, CTA_NAT_DST);
349 	nfct_build_nat(nlh, &ct->dnat, AF_INET);
350 	mnl_attr_nest_end(nlh, nest);
351 	return 0;
352 }
353 
354 static int
nfct_build_dnat_ipv6(struct nlmsghdr * nlh,const struct nf_conntrack * ct)355 nfct_build_dnat_ipv6(struct nlmsghdr *nlh, const struct nf_conntrack *ct)
356 {
357 	struct nlattr *nest;
358 
359 	nest = mnl_attr_nest_start(nlh, CTA_NAT_DST);
360 	nfct_build_nat(nlh, &ct->dnat, AF_INET6);
361 	mnl_attr_nest_end(nlh, nest);
362 	return 0;
363 }
364 
365 static int
nfct_build_dnat_port(struct nlmsghdr * nlh,const struct nf_conntrack * ct)366 nfct_build_dnat_port(struct nlmsghdr *nlh, const struct nf_conntrack *ct)
367 {
368 	struct nlattr *nest;
369 
370 	nest = mnl_attr_nest_start(nlh, CTA_NAT_DST);
371 	nfct_build_protonat(nlh, ct, &ct->dnat);
372 	mnl_attr_nest_end(nlh, nest);
373 	return 0;
374 }
375 
376 static int
nfct_build_status(struct nlmsghdr * nlh,const struct nf_conntrack * ct)377 nfct_build_status(struct nlmsghdr *nlh, const struct nf_conntrack *ct)
378 {
379 	mnl_attr_put_u32(nlh, CTA_STATUS, htonl(ct->status | IPS_CONFIRMED));
380 	return 0;
381 }
382 
383 static int
nfct_build_timeout(struct nlmsghdr * nlh,const struct nf_conntrack * ct)384 nfct_build_timeout(struct nlmsghdr *nlh, const struct nf_conntrack *ct)
385 {
386 	mnl_attr_put_u32(nlh, CTA_TIMEOUT, htonl(ct->timeout));
387 	return 0;
388 }
389 
390 static int
nfct_build_mark(struct nlmsghdr * nlh,const struct nf_conntrack * ct)391 nfct_build_mark(struct nlmsghdr *nlh, const struct nf_conntrack *ct)
392 {
393 	mnl_attr_put_u32(nlh, CTA_MARK, htonl(ct->mark));
394 	return 0;
395 }
396 
397 static int
nfct_build_secmark(struct nlmsghdr * nlh,const struct nf_conntrack * ct)398 nfct_build_secmark(struct nlmsghdr *nlh, const struct nf_conntrack *ct)
399 {
400 	mnl_attr_put_u32(nlh, CTA_SECMARK, htonl(ct->secmark));
401 	return 0;
402 }
403 
404 static int
nfct_build_helper_name(struct nlmsghdr * nlh,const struct nf_conntrack * ct)405 nfct_build_helper_name(struct nlmsghdr *nlh, const struct nf_conntrack *ct)
406 {
407 	struct nlattr *nest;
408 
409 	nest = mnl_attr_nest_start(nlh, CTA_HELP);
410 	mnl_attr_put_strz(nlh, CTA_HELP_NAME, ct->helper_name);
411 
412 	if (ct->helper_info != NULL) {
413 		mnl_attr_put(nlh, CTA_HELP_INFO, ct->helper_info_len,
414 				ct->helper_info);
415 	}
416 	mnl_attr_nest_end(nlh, nest);
417 	return 0;
418 }
419 
420 static int
nfct_build_zone(struct nlmsghdr * nlh,const struct nf_conntrack * ct)421 nfct_build_zone(struct nlmsghdr *nlh, const struct nf_conntrack *ct)
422 {
423 	mnl_attr_put_u16(nlh, CTA_ZONE, htons(ct->zone));
424 	return 0;
425 }
426 
427 static void
nfct_build_labels(struct nlmsghdr * nlh,const struct nf_conntrack * ct)428 nfct_build_labels(struct nlmsghdr *nlh, const struct nf_conntrack *ct)
429 {
430 	struct nfct_bitmask *b = ct->connlabels;
431 	unsigned int size = b->words * sizeof(b->bits[0]);
432 	mnl_attr_put(nlh, CTA_LABELS, size, b->bits);
433 
434 	if (test_bit(ATTR_CONNLABELS_MASK, ct->head.set)) {
435 		b = ct->connlabels_mask;
436 		if (size == (b->words * sizeof(b->bits[0])))
437 			mnl_attr_put(nlh, CTA_LABELS_MASK, size, b->bits);
438 	}
439 }
440 
441 int
nfct_nlmsg_build(struct nlmsghdr * nlh,const struct nf_conntrack * ct)442 nfct_nlmsg_build(struct nlmsghdr *nlh, const struct nf_conntrack *ct)
443 {
444 	if (!test_bit(ATTR_ORIG_L3PROTO, ct->head.set)) {
445 		errno = EINVAL;
446 		return -1;
447 	}
448 
449 	if (test_bit(ATTR_ORIG_IPV4_SRC, ct->head.set) ||
450 	    test_bit(ATTR_ORIG_IPV4_DST, ct->head.set) ||
451 	    test_bit(ATTR_ORIG_IPV6_SRC, ct->head.set) ||
452 	    test_bit(ATTR_ORIG_IPV6_DST, ct->head.set) ||
453 	    test_bit(ATTR_ORIG_PORT_SRC, ct->head.set) ||
454 	    test_bit(ATTR_ORIG_PORT_DST, ct->head.set) ||
455 	    test_bit(ATTR_ORIG_L3PROTO, ct->head.set) ||
456 	    test_bit(ATTR_ORIG_L4PROTO, ct->head.set) ||
457 	    test_bit(ATTR_ORIG_ZONE, ct->head.set) ||
458 	    test_bit(ATTR_ICMP_TYPE, ct->head.set) ||
459 	    test_bit(ATTR_ICMP_CODE, ct->head.set) ||
460 	    test_bit(ATTR_ICMP_ID, ct->head.set)) {
461 		const struct __nfct_tuple *t = &ct->head.orig;
462 		struct nlattr *nest;
463 
464 		nest = mnl_attr_nest_start(nlh, CTA_TUPLE_ORIG);
465 		if (nest == NULL)
466 			return -1;
467 
468 		if (nfct_build_tuple_raw(nlh, t) < 0) {
469 			mnl_attr_nest_cancel(nlh, nest);
470 			return -1;
471 		}
472 
473 		if (test_bit(ATTR_ORIG_ZONE, ct->head.set))
474 			mnl_attr_put_u16(nlh, CTA_TUPLE_ZONE, htons(t->zone));
475 
476 		mnl_attr_nest_end(nlh, nest);
477 	}
478 
479 	if (test_bit(ATTR_REPL_IPV4_SRC, ct->head.set) ||
480 	    test_bit(ATTR_REPL_IPV4_DST, ct->head.set) ||
481 	    test_bit(ATTR_REPL_IPV6_SRC, ct->head.set) ||
482 	    test_bit(ATTR_REPL_IPV6_DST, ct->head.set) ||
483 	    test_bit(ATTR_REPL_PORT_SRC, ct->head.set) ||
484 	    test_bit(ATTR_REPL_PORT_DST, ct->head.set) ||
485 	    test_bit(ATTR_REPL_L3PROTO, ct->head.set) ||
486 	    test_bit(ATTR_REPL_L4PROTO, ct->head.set) ||
487 	    test_bit(ATTR_REPL_ZONE, ct->head.set) ||
488 	    test_bit(ATTR_ICMP_TYPE, ct->head.set) ||
489 	    test_bit(ATTR_ICMP_CODE, ct->head.set) ||
490 	    test_bit(ATTR_ICMP_ID, ct->head.set)) {
491 		const struct __nfct_tuple *t = &ct->repl;
492 		struct nlattr *nest;
493 
494 		nest = mnl_attr_nest_start(nlh, CTA_TUPLE_REPLY);
495 		if (nest == NULL)
496 			return -1;
497 
498 		if (nfct_build_tuple_raw(nlh, t) < 0) {
499 			mnl_attr_nest_cancel(nlh, nest);
500 			return -1;
501 		}
502 
503 		if (test_bit(ATTR_REPL_ZONE, ct->head.set))
504 			mnl_attr_put_u16(nlh, CTA_TUPLE_ZONE, htons(t->zone));
505 
506 		mnl_attr_nest_end(nlh, nest);
507 	}
508 
509 	if (test_bit(ATTR_MASTER_IPV4_SRC, ct->head.set) ||
510 	    test_bit(ATTR_MASTER_IPV4_DST, ct->head.set) ||
511 	    test_bit(ATTR_MASTER_IPV6_SRC, ct->head.set) ||
512 	    test_bit(ATTR_MASTER_IPV6_DST, ct->head.set) ||
513 	    test_bit(ATTR_MASTER_PORT_SRC, ct->head.set) ||
514 	    test_bit(ATTR_MASTER_PORT_DST, ct->head.set) ||
515 	    test_bit(ATTR_MASTER_L3PROTO, ct->head.set) ||
516 	    test_bit(ATTR_MASTER_L4PROTO, ct->head.set)) {
517 		nfct_build_tuple(nlh, &ct->master, CTA_TUPLE_MASTER);
518 	}
519 
520 	if (test_bit(ATTR_STATUS, ct->head.set))
521 		nfct_build_status(nlh, ct);
522 
523 	if (test_bit(ATTR_TIMEOUT, ct->head.set))
524 		nfct_build_timeout(nlh, ct);
525 
526 	if (test_bit(ATTR_MARK, ct->head.set))
527 		nfct_build_mark(nlh, ct);
528 
529 	if (test_bit(ATTR_SECMARK, ct->head.set))
530 		nfct_build_secmark(nlh, ct);
531 
532 	nfct_build_protoinfo(nlh, ct);
533 
534 	if (test_bit(ATTR_SNAT_IPV4, ct->head.set) &&
535 	    test_bit(ATTR_SNAT_PORT, ct->head.set)) {
536 		nfct_build_snat(nlh, ct, AF_INET);
537 	} else if (test_bit(ATTR_SNAT_IPV6, ct->head.set) &&
538 		   test_bit(ATTR_SNAT_PORT, ct->head.set)) {
539 		nfct_build_snat(nlh, ct, AF_INET6);
540 	} else if (test_bit(ATTR_SNAT_IPV4, ct->head.set)) {
541 		nfct_build_snat_ipv4(nlh, ct);
542 	} else if (test_bit(ATTR_SNAT_IPV6, ct->head.set)) {
543 		nfct_build_snat_ipv6(nlh, ct);
544 	} else if (test_bit(ATTR_SNAT_PORT, ct->head.set)) {
545 		nfct_build_snat_port(nlh, ct);
546 	}
547 
548 	if (test_bit(ATTR_DNAT_IPV4, ct->head.set) &&
549 	    test_bit(ATTR_DNAT_PORT, ct->head.set)) {
550 		nfct_build_dnat(nlh, ct, AF_INET);
551 	} else if (test_bit(ATTR_DNAT_IPV6, ct->head.set) &&
552 		   test_bit(ATTR_DNAT_PORT, ct->head.set)) {
553 		nfct_build_dnat(nlh, ct, AF_INET6);
554 	} else if (test_bit(ATTR_DNAT_IPV4, ct->head.set)) {
555 		nfct_build_dnat_ipv4(nlh, ct);
556 	} else if (test_bit(ATTR_DNAT_IPV6, ct->head.set)) {
557 		nfct_build_dnat_ipv6(nlh, ct);
558 	} else if (test_bit(ATTR_DNAT_PORT, ct->head.set)) {
559 		nfct_build_dnat_port(nlh, ct);
560 	}
561 
562 	if (test_bit(ATTR_ORIG_NAT_SEQ_CORRECTION_POS, ct->head.set) &&
563 	    test_bit(ATTR_ORIG_NAT_SEQ_OFFSET_BEFORE, ct->head.set) &&
564 	    test_bit(ATTR_ORIG_NAT_SEQ_OFFSET_AFTER, ct->head.set)) {
565 		nfct_build_nat_seq_adj(nlh, ct, __DIR_ORIG);
566 	}
567 	if (test_bit(ATTR_REPL_NAT_SEQ_CORRECTION_POS, ct->head.set) &&
568 	    test_bit(ATTR_REPL_NAT_SEQ_OFFSET_BEFORE, ct->head.set) &&
569 	    test_bit(ATTR_REPL_NAT_SEQ_OFFSET_AFTER, ct->head.set)) {
570 		nfct_build_nat_seq_adj(nlh, ct, __DIR_REPL);
571 	}
572 
573 	if (test_bit(ATTR_HELPER_NAME, ct->head.set))
574 		nfct_build_helper_name(nlh, ct);
575 
576 	if (test_bit(ATTR_ZONE, ct->head.set))
577 		nfct_build_zone(nlh, ct);
578 
579 	if (test_bit(ATTR_CONNLABELS, ct->head.set))
580 		nfct_build_labels(nlh, ct);
581 
582 	return 0;
583 }
584