libnetfilter_conntrack  1.0.6
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 int
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 }