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