libnetfilter_conntrack  1.0.8
conntrack/build_mnl.c
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 static void nfct_build_synproxy(struct nlmsghdr *nlh,
442  const struct nf_conntrack *ct)
443 {
444  struct nlattr *nest;
445 
446  nest = mnl_attr_nest_start(nlh, CTA_SYNPROXY);
447  mnl_attr_put_u32(nlh, CTA_SYNPROXY_ISN, htonl(ct->synproxy.isn));
448  mnl_attr_put_u32(nlh, CTA_SYNPROXY_ITS, htonl(ct->synproxy.its));
449  mnl_attr_put_u32(nlh, CTA_SYNPROXY_TSOFF, htonl(ct->synproxy.tsoff));
450  mnl_attr_nest_end(nlh, nest);
451 }
452 
453 int
454 nfct_nlmsg_build(struct nlmsghdr *nlh, const struct nf_conntrack *ct)
455 {
456  if (!test_bit(ATTR_ORIG_L3PROTO, ct->head.set)) {
457  errno = EINVAL;
458  return -1;
459  }
460 
461  if (test_bit(ATTR_ORIG_IPV4_SRC, ct->head.set) ||
462  test_bit(ATTR_ORIG_IPV4_DST, ct->head.set) ||
463  test_bit(ATTR_ORIG_IPV6_SRC, ct->head.set) ||
464  test_bit(ATTR_ORIG_IPV6_DST, ct->head.set) ||
465  test_bit(ATTR_ORIG_PORT_SRC, ct->head.set) ||
466  test_bit(ATTR_ORIG_PORT_DST, ct->head.set) ||
467  test_bit(ATTR_ORIG_L3PROTO, ct->head.set) ||
468  test_bit(ATTR_ORIG_L4PROTO, ct->head.set) ||
469  test_bit(ATTR_ORIG_ZONE, ct->head.set) ||
470  test_bit(ATTR_ICMP_TYPE, ct->head.set) ||
471  test_bit(ATTR_ICMP_CODE, ct->head.set) ||
472  test_bit(ATTR_ICMP_ID, ct->head.set)) {
473  const struct __nfct_tuple *t = &ct->head.orig;
474  struct nlattr *nest;
475 
476  nest = mnl_attr_nest_start(nlh, CTA_TUPLE_ORIG);
477  if (nest == NULL)
478  return -1;
479 
480  if (nfct_build_tuple_raw(nlh, t) < 0) {
481  mnl_attr_nest_cancel(nlh, nest);
482  return -1;
483  }
484 
485  if (test_bit(ATTR_ORIG_ZONE, ct->head.set))
486  mnl_attr_put_u16(nlh, CTA_TUPLE_ZONE, htons(t->zone));
487 
488  mnl_attr_nest_end(nlh, nest);
489  }
490 
491  if (test_bit(ATTR_REPL_IPV4_SRC, ct->head.set) ||
492  test_bit(ATTR_REPL_IPV4_DST, ct->head.set) ||
493  test_bit(ATTR_REPL_IPV6_SRC, ct->head.set) ||
494  test_bit(ATTR_REPL_IPV6_DST, ct->head.set) ||
495  test_bit(ATTR_REPL_PORT_SRC, ct->head.set) ||
496  test_bit(ATTR_REPL_PORT_DST, ct->head.set) ||
497  test_bit(ATTR_REPL_L3PROTO, ct->head.set) ||
498  test_bit(ATTR_REPL_L4PROTO, ct->head.set) ||
499  test_bit(ATTR_REPL_ZONE, ct->head.set) ||
500  test_bit(ATTR_ICMP_TYPE, ct->head.set) ||
501  test_bit(ATTR_ICMP_CODE, ct->head.set) ||
502  test_bit(ATTR_ICMP_ID, ct->head.set)) {
503  const struct __nfct_tuple *t = &ct->repl;
504  struct nlattr *nest;
505 
506  nest = mnl_attr_nest_start(nlh, CTA_TUPLE_REPLY);
507  if (nest == NULL)
508  return -1;
509 
510  if (nfct_build_tuple_raw(nlh, t) < 0) {
511  mnl_attr_nest_cancel(nlh, nest);
512  return -1;
513  }
514 
515  if (test_bit(ATTR_REPL_ZONE, ct->head.set))
516  mnl_attr_put_u16(nlh, CTA_TUPLE_ZONE, htons(t->zone));
517 
518  mnl_attr_nest_end(nlh, nest);
519  }
520 
521  if (test_bit(ATTR_MASTER_IPV4_SRC, ct->head.set) ||
522  test_bit(ATTR_MASTER_IPV4_DST, ct->head.set) ||
523  test_bit(ATTR_MASTER_IPV6_SRC, ct->head.set) ||
524  test_bit(ATTR_MASTER_IPV6_DST, ct->head.set) ||
525  test_bit(ATTR_MASTER_PORT_SRC, ct->head.set) ||
526  test_bit(ATTR_MASTER_PORT_DST, ct->head.set) ||
527  test_bit(ATTR_MASTER_L3PROTO, ct->head.set) ||
528  test_bit(ATTR_MASTER_L4PROTO, ct->head.set)) {
529  nfct_build_tuple(nlh, &ct->master, CTA_TUPLE_MASTER);
530  }
531 
532  if (test_bit(ATTR_STATUS, ct->head.set))
533  nfct_build_status(nlh, ct);
534 
535  if (test_bit(ATTR_TIMEOUT, ct->head.set))
536  nfct_build_timeout(nlh, ct);
537 
538  if (test_bit(ATTR_MARK, ct->head.set))
539  nfct_build_mark(nlh, ct);
540 
541  if (test_bit(ATTR_SECMARK, ct->head.set))
542  nfct_build_secmark(nlh, ct);
543 
544  nfct_build_protoinfo(nlh, ct);
545 
546  if (test_bit(ATTR_SNAT_IPV4, ct->head.set) &&
547  test_bit(ATTR_SNAT_PORT, ct->head.set)) {
548  nfct_build_snat(nlh, ct, AF_INET);
549  } else if (test_bit(ATTR_SNAT_IPV6, ct->head.set) &&
550  test_bit(ATTR_SNAT_PORT, ct->head.set)) {
551  nfct_build_snat(nlh, ct, AF_INET6);
552  } else if (test_bit(ATTR_SNAT_IPV4, ct->head.set)) {
553  nfct_build_snat_ipv4(nlh, ct);
554  } else if (test_bit(ATTR_SNAT_IPV6, ct->head.set)) {
555  nfct_build_snat_ipv6(nlh, ct);
556  } else if (test_bit(ATTR_SNAT_PORT, ct->head.set)) {
557  nfct_build_snat_port(nlh, ct);
558  }
559 
560  if (test_bit(ATTR_DNAT_IPV4, ct->head.set) &&
561  test_bit(ATTR_DNAT_PORT, ct->head.set)) {
562  nfct_build_dnat(nlh, ct, AF_INET);
563  } else if (test_bit(ATTR_DNAT_IPV6, ct->head.set) &&
564  test_bit(ATTR_DNAT_PORT, ct->head.set)) {
565  nfct_build_dnat(nlh, ct, AF_INET6);
566  } else if (test_bit(ATTR_DNAT_IPV4, ct->head.set)) {
567  nfct_build_dnat_ipv4(nlh, ct);
568  } else if (test_bit(ATTR_DNAT_IPV6, ct->head.set)) {
569  nfct_build_dnat_ipv6(nlh, ct);
570  } else if (test_bit(ATTR_DNAT_PORT, ct->head.set)) {
571  nfct_build_dnat_port(nlh, ct);
572  }
573 
574  if (test_bit(ATTR_ORIG_NAT_SEQ_CORRECTION_POS, ct->head.set) &&
575  test_bit(ATTR_ORIG_NAT_SEQ_OFFSET_BEFORE, ct->head.set) &&
576  test_bit(ATTR_ORIG_NAT_SEQ_OFFSET_AFTER, ct->head.set)) {
577  nfct_build_nat_seq_adj(nlh, ct, __DIR_ORIG);
578  }
579  if (test_bit(ATTR_REPL_NAT_SEQ_CORRECTION_POS, ct->head.set) &&
580  test_bit(ATTR_REPL_NAT_SEQ_OFFSET_BEFORE, ct->head.set) &&
581  test_bit(ATTR_REPL_NAT_SEQ_OFFSET_AFTER, ct->head.set)) {
582  nfct_build_nat_seq_adj(nlh, ct, __DIR_REPL);
583  }
584 
585  if (test_bit(ATTR_HELPER_NAME, ct->head.set))
586  nfct_build_helper_name(nlh, ct);
587 
588  if (test_bit(ATTR_ZONE, ct->head.set))
589  nfct_build_zone(nlh, ct);
590 
591  if (test_bit(ATTR_CONNLABELS, ct->head.set))
592  nfct_build_labels(nlh, ct);
593 
594  if (test_bit(ATTR_SYNPROXY_ISN, ct->head.set) &&
595  test_bit(ATTR_SYNPROXY_ITS, ct->head.set) &&
596  test_bit(ATTR_SYNPROXY_TSOFF, ct->head.set))
597  nfct_build_synproxy(nlh, ct);
598 
599  return 0;
600 }