libnetfilter_conntrack  1.0.9
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  break;
77  }
78  mnl_attr_nest_end(nlh, nest);
79  return 0;
80 }
81 
82 int
83 nfct_build_tuple_raw(struct nlmsghdr *nlh, const struct __nfct_tuple *t)
84 {
85  if (nfct_build_tuple_ip(nlh, t) < 0)
86  return -1;
87  if (nfct_build_tuple_proto(nlh, t) < 0)
88  return -1;
89 
90  return 0;
91 }
92 
93 int
94 nfct_build_tuple(struct nlmsghdr *nlh, const struct __nfct_tuple *t, int type)
95 {
96  struct nlattr *nest;
97 
98  nest = mnl_attr_nest_start(nlh, type);
99  if (nest == NULL)
100  return -1;
101 
102  if (nfct_build_tuple_raw(nlh, t) < 0)
103  goto err;
104 
105  mnl_attr_nest_end(nlh, nest);
106  return 0;
107 err:
108  mnl_attr_nest_cancel(nlh, nest);
109  return -1;
110 }
111 
112 static int
113 nfct_build_protoinfo(struct nlmsghdr *nlh, const struct nf_conntrack *ct)
114 {
115  struct nlattr *nest, *nest_proto;
116 
117  switch(ct->head.orig.protonum) {
118  case IPPROTO_TCP:
119  /* Preliminary attribute check to avoid sending an empty
120  * CTA_PROTOINFO_TCP nest, which results in EINVAL in
121  * Linux kernel <= 2.6.25. */
122  if (!(test_bit(ATTR_TCP_STATE, ct->head.set) ||
123  test_bit(ATTR_TCP_FLAGS_ORIG, ct->head.set) ||
124  test_bit(ATTR_TCP_FLAGS_REPL, ct->head.set) ||
125  test_bit(ATTR_TCP_MASK_ORIG, ct->head.set) ||
126  test_bit(ATTR_TCP_MASK_REPL, ct->head.set) ||
127  test_bit(ATTR_TCP_WSCALE_ORIG, ct->head.set) ||
128  test_bit(ATTR_TCP_WSCALE_REPL, ct->head.set))) {
129  break;
130  }
131  nest = mnl_attr_nest_start(nlh, CTA_PROTOINFO);
132  nest_proto = mnl_attr_nest_start(nlh, CTA_PROTOINFO_TCP);
133  if (test_bit(ATTR_TCP_STATE, ct->head.set)) {
134  mnl_attr_put_u8(nlh, CTA_PROTOINFO_TCP_STATE,
135  ct->protoinfo.tcp.state);
136  }
137  if (test_bit(ATTR_TCP_FLAGS_ORIG, ct->head.set) &&
138  test_bit(ATTR_TCP_MASK_ORIG, ct->head.set)) {
139  mnl_attr_put(nlh, CTA_PROTOINFO_TCP_FLAGS_ORIGINAL,
140  sizeof(struct nf_ct_tcp_flags),
141  &ct->protoinfo.tcp.flags[0]);
142  }
143  if (test_bit(ATTR_TCP_FLAGS_REPL, ct->head.set) &&
144  test_bit(ATTR_TCP_MASK_REPL, ct->head.set)) {
145  mnl_attr_put(nlh, CTA_PROTOINFO_TCP_FLAGS_REPLY,
146  sizeof(struct nf_ct_tcp_flags),
147  &ct->protoinfo.tcp.flags[1]);
148  }
149  if (test_bit(ATTR_TCP_WSCALE_ORIG, ct->head.set)) {
150  mnl_attr_put_u8(nlh, CTA_PROTOINFO_TCP_WSCALE_ORIGINAL,
151  ct->protoinfo.tcp.wscale[__DIR_ORIG]);
152  }
153  if (test_bit(ATTR_TCP_WSCALE_REPL, ct->head.set)) {
154  mnl_attr_put_u8(nlh, CTA_PROTOINFO_TCP_WSCALE_REPLY,
155  ct->protoinfo.tcp.wscale[__DIR_REPL]);
156  }
157  mnl_attr_nest_end(nlh, nest_proto);
158  mnl_attr_nest_end(nlh, nest);
159  break;
160  case IPPROTO_SCTP:
161  /* See comment above on TCP. */
162  if (!(test_bit(ATTR_SCTP_STATE, ct->head.set) ||
163  test_bit(ATTR_SCTP_VTAG_ORIG, ct->head.set) ||
164  test_bit(ATTR_SCTP_VTAG_REPL, ct->head.set))) {
165  break;
166  }
167  nest = mnl_attr_nest_start(nlh, CTA_PROTOINFO);
168  nest_proto = mnl_attr_nest_start(nlh, CTA_PROTOINFO_SCTP);
169 
170  if (test_bit(ATTR_SCTP_STATE, ct->head.set)) {
171  mnl_attr_put_u8(nlh, CTA_PROTOINFO_SCTP_STATE,
172  ct->protoinfo.sctp.state);
173  }
174  if (test_bit(ATTR_SCTP_VTAG_ORIG, ct->head.set)) {
175  mnl_attr_put_u32(nlh, CTA_PROTOINFO_SCTP_VTAG_ORIGINAL,
176  htonl(ct->protoinfo.sctp.vtag[__DIR_ORIG]));
177  }
178  if (test_bit(ATTR_SCTP_VTAG_REPL, ct->head.set)) {
179  mnl_attr_put_u32(nlh, CTA_PROTOINFO_SCTP_VTAG_REPLY,
180  htonl(ct->protoinfo.sctp.vtag[__DIR_REPL]));
181  }
182  mnl_attr_nest_end(nlh, nest_proto);
183  mnl_attr_nest_end(nlh, nest);
184  break;
185  case IPPROTO_DCCP:
186  /* See comment above on TCP. */
187  if (!(test_bit(ATTR_DCCP_STATE, ct->head.set) ||
188  test_bit(ATTR_DCCP_ROLE, ct->head.set) ||
189  test_bit(ATTR_DCCP_HANDSHAKE_SEQ, ct->head.set))) {
190  break;
191  }
192  nest = mnl_attr_nest_start(nlh, CTA_PROTOINFO);
193  nest_proto = mnl_attr_nest_start(nlh, CTA_PROTOINFO_DCCP);
194  if (test_bit(ATTR_DCCP_STATE, ct->head.set)) {
195  mnl_attr_put_u8(nlh, CTA_PROTOINFO_DCCP_STATE,
196  ct->protoinfo.dccp.state);
197  }
198  if (test_bit(ATTR_DCCP_ROLE, ct->head.set)) {
199  mnl_attr_put_u8(nlh, CTA_PROTOINFO_DCCP_ROLE,
200  ct->protoinfo.dccp.role);
201  }
202  if (test_bit(ATTR_DCCP_HANDSHAKE_SEQ, ct->head.set)) {
203  uint64_t handshake_seq =
204  be64toh(ct->protoinfo.dccp.handshake_seq);
205 
206  mnl_attr_put_u64(nlh, CTA_PROTOINFO_DCCP_HANDSHAKE_SEQ,
207  handshake_seq);
208  }
209  mnl_attr_nest_end(nlh, nest_proto);
210  mnl_attr_nest_end(nlh, nest);
211  default:
212  break;
213  }
214  return 0;
215 }
216 
217 static int
218 nfct_nat_seq_adj(struct nlmsghdr *nlh, const struct nf_conntrack *ct, int dir)
219 {
220  mnl_attr_put_u32(nlh, CTA_NAT_SEQ_CORRECTION_POS,
221  htonl(ct->natseq[dir].correction_pos));
222  mnl_attr_put_u32(nlh, CTA_NAT_SEQ_OFFSET_BEFORE,
223  htonl(ct->natseq[dir].offset_before));
224  mnl_attr_put_u32(nlh, CTA_NAT_SEQ_OFFSET_AFTER,
225  htonl(ct->natseq[dir].offset_after));
226  return 0;
227 }
228 
229 static int
230 nfct_build_nat_seq_adj(struct nlmsghdr *nlh, const struct nf_conntrack *ct,
231  int dir)
232 {
233  int type = (dir == __DIR_ORIG) ? CTA_NAT_SEQ_ADJ_ORIG :
234  CTA_NAT_SEQ_ADJ_REPLY;
235  struct nlattr *nest;
236 
237  nest = mnl_attr_nest_start(nlh, type);
238  nfct_nat_seq_adj(nlh, ct, dir);
239  mnl_attr_nest_end(nlh, nest);
240 
241  return 0;
242 }
243 
244 static int
245 nfct_build_protonat(struct nlmsghdr *nlh, const struct nf_conntrack *ct,
246  const struct __nfct_nat *nat)
247 {
248  struct nlattr *nest;
249 
250  nest = mnl_attr_nest_start(nlh, CTA_NAT_PROTO);
251 
252  switch (ct->head.orig.protonum) {
253  case IPPROTO_TCP:
254  case IPPROTO_UDP:
255  mnl_attr_put_u16(nlh, CTA_PROTONAT_PORT_MIN,
256  nat->l4min.tcp.port);
257  mnl_attr_put_u16(nlh, CTA_PROTONAT_PORT_MAX,
258  nat->l4max.tcp.port);
259  break;
260  }
261  mnl_attr_nest_end(nlh, nest);
262  return 0;
263 }
264 
265 static int
266 nfct_build_nat(struct nlmsghdr *nlh, const struct __nfct_nat *nat,
267  uint8_t l3protonum)
268 {
269  switch (l3protonum) {
270  case AF_INET:
271  mnl_attr_put_u32(nlh, CTA_NAT_MINIP, nat->min_ip.v4);
272  break;
273  case AF_INET6:
274  mnl_attr_put(nlh, CTA_NAT_V6_MINIP, sizeof(struct in6_addr),
275  &nat->min_ip.v6);
276  break;
277  default:
278  break;
279  }
280  return 0;
281 }
282 
283 static int
284 nfct_build_snat(struct nlmsghdr *nlh, const struct nf_conntrack *ct,
285  uint8_t l3protonum)
286 {
287  struct nlattr *nest;
288 
289  nest = mnl_attr_nest_start(nlh, CTA_NAT_SRC);
290  nfct_build_nat(nlh, &ct->snat, l3protonum);
291  nfct_build_protonat(nlh, ct, &ct->snat);
292  mnl_attr_nest_end(nlh, nest);
293  return 0;
294 }
295 
296 static int
297 nfct_build_snat_ipv4(struct nlmsghdr *nlh, const struct nf_conntrack *ct)
298 {
299  struct nlattr *nest;
300 
301  nest = mnl_attr_nest_start(nlh, CTA_NAT_SRC);
302  nfct_build_nat(nlh, &ct->snat, AF_INET);
303  mnl_attr_nest_end(nlh, nest);
304  return 0;
305 }
306 
307 static int
308 nfct_build_snat_ipv6(struct nlmsghdr *nlh, const struct nf_conntrack *ct)
309 {
310  struct nlattr *nest;
311 
312  nest = mnl_attr_nest_start(nlh, CTA_NAT_SRC);
313  nfct_build_nat(nlh, &ct->snat, AF_INET6);
314  mnl_attr_nest_end(nlh, nest);
315  return 0;
316 }
317 
318 static int
319 nfct_build_snat_port(struct nlmsghdr *nlh, const struct nf_conntrack *ct)
320 {
321  struct nlattr *nest;
322 
323  nest = mnl_attr_nest_start(nlh, CTA_NAT_SRC);
324  nfct_build_protonat(nlh, ct, &ct->snat);
325  mnl_attr_nest_end(nlh, nest);
326  return 0;
327 }
328 
329 static int
330 nfct_build_dnat(struct nlmsghdr *nlh, const struct nf_conntrack *ct,
331  uint8_t l3protonum)
332 {
333  struct nlattr *nest;
334 
335  nest = mnl_attr_nest_start(nlh, CTA_NAT_DST);
336  nfct_build_nat(nlh, &ct->dnat, l3protonum);
337  nfct_build_protonat(nlh, ct, &ct->dnat);
338  mnl_attr_nest_end(nlh, nest);
339  return 0;
340 }
341 
342 static int
343 nfct_build_dnat_ipv4(struct nlmsghdr *nlh, const struct nf_conntrack *ct)
344 {
345  struct nlattr *nest;
346 
347  nest = mnl_attr_nest_start(nlh, CTA_NAT_DST);
348  nfct_build_nat(nlh, &ct->dnat, AF_INET);
349  mnl_attr_nest_end(nlh, nest);
350  return 0;
351 }
352 
353 static int
354 nfct_build_dnat_ipv6(struct nlmsghdr *nlh, const struct nf_conntrack *ct)
355 {
356  struct nlattr *nest;
357 
358  nest = mnl_attr_nest_start(nlh, CTA_NAT_DST);
359  nfct_build_nat(nlh, &ct->dnat, AF_INET6);
360  mnl_attr_nest_end(nlh, nest);
361  return 0;
362 }
363 
364 static int
365 nfct_build_dnat_port(struct nlmsghdr *nlh, const struct nf_conntrack *ct)
366 {
367  struct nlattr *nest;
368 
369  nest = mnl_attr_nest_start(nlh, CTA_NAT_DST);
370  nfct_build_protonat(nlh, ct, &ct->dnat);
371  mnl_attr_nest_end(nlh, nest);
372  return 0;
373 }
374 
375 static int
376 nfct_build_status(struct nlmsghdr *nlh, const struct nf_conntrack *ct)
377 {
378  mnl_attr_put_u32(nlh, CTA_STATUS, htonl(ct->status | IPS_CONFIRMED));
379  return 0;
380 }
381 
382 static int
383 nfct_build_timeout(struct nlmsghdr *nlh, const struct nf_conntrack *ct)
384 {
385  mnl_attr_put_u32(nlh, CTA_TIMEOUT, htonl(ct->timeout));
386  return 0;
387 }
388 
389 static int
390 nfct_build_mark(struct nlmsghdr *nlh, const struct nf_conntrack *ct)
391 {
392  mnl_attr_put_u32(nlh, CTA_MARK, htonl(ct->mark));
393  return 0;
394 }
395 
396 static int
397 nfct_build_secmark(struct nlmsghdr *nlh, const struct nf_conntrack *ct)
398 {
399  mnl_attr_put_u32(nlh, CTA_SECMARK, htonl(ct->secmark));
400  return 0;
401 }
402 
403 static int
404 nfct_build_helper_name(struct nlmsghdr *nlh, const struct nf_conntrack *ct)
405 {
406  struct nlattr *nest;
407 
408  nest = mnl_attr_nest_start(nlh, CTA_HELP);
409  mnl_attr_put_strz(nlh, CTA_HELP_NAME, ct->helper_name);
410 
411  if (ct->helper_info != NULL) {
412  mnl_attr_put(nlh, CTA_HELP_INFO, ct->helper_info_len,
413  ct->helper_info);
414  }
415  mnl_attr_nest_end(nlh, nest);
416  return 0;
417 }
418 
419 static int
420 nfct_build_zone(struct nlmsghdr *nlh, const struct nf_conntrack *ct)
421 {
422  mnl_attr_put_u16(nlh, CTA_ZONE, htons(ct->zone));
423  return 0;
424 }
425 
426 static void
427 nfct_build_labels(struct nlmsghdr *nlh, const struct nf_conntrack *ct)
428 {
429  struct nfct_bitmask *b = ct->connlabels;
430  unsigned int size = b->words * sizeof(b->bits[0]);
431  mnl_attr_put(nlh, CTA_LABELS, size, b->bits);
432 
433  if (test_bit(ATTR_CONNLABELS_MASK, ct->head.set)) {
434  b = ct->connlabels_mask;
435  if (size == (b->words * sizeof(b->bits[0])))
436  mnl_attr_put(nlh, CTA_LABELS_MASK, size, b->bits);
437  }
438 }
439 
440 static void nfct_build_synproxy(struct nlmsghdr *nlh,
441  const struct nf_conntrack *ct)
442 {
443  struct nlattr *nest;
444 
445  nest = mnl_attr_nest_start(nlh, CTA_SYNPROXY);
446  mnl_attr_put_u32(nlh, CTA_SYNPROXY_ISN, htonl(ct->synproxy.isn));
447  mnl_attr_put_u32(nlh, CTA_SYNPROXY_ITS, htonl(ct->synproxy.its));
448  mnl_attr_put_u32(nlh, CTA_SYNPROXY_TSOFF, htonl(ct->synproxy.tsoff));
449  mnl_attr_nest_end(nlh, nest);
450 }
451 
452 int
453 nfct_nlmsg_build(struct nlmsghdr *nlh, const struct nf_conntrack *ct)
454 {
455  if (!test_bit(ATTR_ORIG_L3PROTO, ct->head.set)) {
456  errno = EINVAL;
457  return -1;
458  }
459 
460  if (test_bit(ATTR_ORIG_IPV4_SRC, ct->head.set) ||
461  test_bit(ATTR_ORIG_IPV4_DST, ct->head.set) ||
462  test_bit(ATTR_ORIG_IPV6_SRC, ct->head.set) ||
463  test_bit(ATTR_ORIG_IPV6_DST, ct->head.set) ||
464  test_bit(ATTR_ORIG_PORT_SRC, ct->head.set) ||
465  test_bit(ATTR_ORIG_PORT_DST, ct->head.set) ||
466  test_bit(ATTR_ORIG_L3PROTO, ct->head.set) ||
467  test_bit(ATTR_ORIG_L4PROTO, ct->head.set) ||
468  test_bit(ATTR_ORIG_ZONE, ct->head.set) ||
469  test_bit(ATTR_ICMP_TYPE, ct->head.set) ||
470  test_bit(ATTR_ICMP_CODE, ct->head.set) ||
471  test_bit(ATTR_ICMP_ID, ct->head.set)) {
472  const struct __nfct_tuple *t = &ct->head.orig;
473  struct nlattr *nest;
474 
475  nest = mnl_attr_nest_start(nlh, CTA_TUPLE_ORIG);
476  if (nest == NULL)
477  return -1;
478 
479  if (nfct_build_tuple_raw(nlh, t) < 0) {
480  mnl_attr_nest_cancel(nlh, nest);
481  return -1;
482  }
483 
484  if (test_bit(ATTR_ORIG_ZONE, ct->head.set))
485  mnl_attr_put_u16(nlh, CTA_TUPLE_ZONE, htons(t->zone));
486 
487  mnl_attr_nest_end(nlh, nest);
488  }
489 
490  if (test_bit(ATTR_REPL_IPV4_SRC, ct->head.set) ||
491  test_bit(ATTR_REPL_IPV4_DST, ct->head.set) ||
492  test_bit(ATTR_REPL_IPV6_SRC, ct->head.set) ||
493  test_bit(ATTR_REPL_IPV6_DST, ct->head.set) ||
494  test_bit(ATTR_REPL_PORT_SRC, ct->head.set) ||
495  test_bit(ATTR_REPL_PORT_DST, ct->head.set) ||
496  test_bit(ATTR_REPL_L3PROTO, ct->head.set) ||
497  test_bit(ATTR_REPL_L4PROTO, ct->head.set) ||
498  test_bit(ATTR_REPL_ZONE, ct->head.set)) {
499  const struct __nfct_tuple *t = &ct->repl;
500  struct nlattr *nest;
501 
502  nest = mnl_attr_nest_start(nlh, CTA_TUPLE_REPLY);
503  if (nest == NULL)
504  return -1;
505 
506  if (nfct_build_tuple_raw(nlh, t) < 0) {
507  mnl_attr_nest_cancel(nlh, nest);
508  return -1;
509  }
510 
511  if (test_bit(ATTR_REPL_ZONE, ct->head.set))
512  mnl_attr_put_u16(nlh, CTA_TUPLE_ZONE, htons(t->zone));
513 
514  mnl_attr_nest_end(nlh, nest);
515  }
516 
517  if (test_bit(ATTR_MASTER_IPV4_SRC, ct->head.set) ||
518  test_bit(ATTR_MASTER_IPV4_DST, ct->head.set) ||
519  test_bit(ATTR_MASTER_IPV6_SRC, ct->head.set) ||
520  test_bit(ATTR_MASTER_IPV6_DST, ct->head.set) ||
521  test_bit(ATTR_MASTER_PORT_SRC, ct->head.set) ||
522  test_bit(ATTR_MASTER_PORT_DST, ct->head.set) ||
523  test_bit(ATTR_MASTER_L3PROTO, ct->head.set) ||
524  test_bit(ATTR_MASTER_L4PROTO, ct->head.set)) {
525  nfct_build_tuple(nlh, &ct->master, CTA_TUPLE_MASTER);
526  }
527 
528  if (test_bit(ATTR_STATUS, ct->head.set))
529  nfct_build_status(nlh, ct);
530 
531  if (test_bit(ATTR_TIMEOUT, ct->head.set))
532  nfct_build_timeout(nlh, ct);
533 
534  if (test_bit(ATTR_MARK, ct->head.set))
535  nfct_build_mark(nlh, ct);
536 
537  if (test_bit(ATTR_SECMARK, ct->head.set))
538  nfct_build_secmark(nlh, ct);
539 
540  nfct_build_protoinfo(nlh, ct);
541 
542  if (test_bit(ATTR_SNAT_IPV4, ct->head.set) &&
543  test_bit(ATTR_SNAT_PORT, ct->head.set)) {
544  nfct_build_snat(nlh, ct, AF_INET);
545  } else if (test_bit(ATTR_SNAT_IPV6, ct->head.set) &&
546  test_bit(ATTR_SNAT_PORT, ct->head.set)) {
547  nfct_build_snat(nlh, ct, AF_INET6);
548  } else if (test_bit(ATTR_SNAT_IPV4, ct->head.set)) {
549  nfct_build_snat_ipv4(nlh, ct);
550  } else if (test_bit(ATTR_SNAT_IPV6, ct->head.set)) {
551  nfct_build_snat_ipv6(nlh, ct);
552  } else if (test_bit(ATTR_SNAT_PORT, ct->head.set)) {
553  nfct_build_snat_port(nlh, ct);
554  }
555 
556  if (test_bit(ATTR_DNAT_IPV4, ct->head.set) &&
557  test_bit(ATTR_DNAT_PORT, ct->head.set)) {
558  nfct_build_dnat(nlh, ct, AF_INET);
559  } else if (test_bit(ATTR_DNAT_IPV6, ct->head.set) &&
560  test_bit(ATTR_DNAT_PORT, ct->head.set)) {
561  nfct_build_dnat(nlh, ct, AF_INET6);
562  } else if (test_bit(ATTR_DNAT_IPV4, ct->head.set)) {
563  nfct_build_dnat_ipv4(nlh, ct);
564  } else if (test_bit(ATTR_DNAT_IPV6, ct->head.set)) {
565  nfct_build_dnat_ipv6(nlh, ct);
566  } else if (test_bit(ATTR_DNAT_PORT, ct->head.set)) {
567  nfct_build_dnat_port(nlh, ct);
568  }
569 
570  if (test_bit(ATTR_ORIG_NAT_SEQ_CORRECTION_POS, ct->head.set) &&
571  test_bit(ATTR_ORIG_NAT_SEQ_OFFSET_BEFORE, ct->head.set) &&
572  test_bit(ATTR_ORIG_NAT_SEQ_OFFSET_AFTER, ct->head.set)) {
573  nfct_build_nat_seq_adj(nlh, ct, __DIR_ORIG);
574  }
575  if (test_bit(ATTR_REPL_NAT_SEQ_CORRECTION_POS, ct->head.set) &&
576  test_bit(ATTR_REPL_NAT_SEQ_OFFSET_BEFORE, ct->head.set) &&
577  test_bit(ATTR_REPL_NAT_SEQ_OFFSET_AFTER, ct->head.set)) {
578  nfct_build_nat_seq_adj(nlh, ct, __DIR_REPL);
579  }
580 
581  if (test_bit(ATTR_HELPER_NAME, ct->head.set))
582  nfct_build_helper_name(nlh, ct);
583 
584  if (test_bit(ATTR_ZONE, ct->head.set))
585  nfct_build_zone(nlh, ct);
586 
587  if (test_bit(ATTR_CONNLABELS, ct->head.set))
588  nfct_build_labels(nlh, ct);
589 
590  if (test_bit(ATTR_SYNPROXY_ISN, ct->head.set) &&
591  test_bit(ATTR_SYNPROXY_ITS, ct->head.set) &&
592  test_bit(ATTR_SYNPROXY_TSOFF, ct->head.set))
593  nfct_build_synproxy(nlh, ct);
594 
595  return 0;
596 }
597 
598 int nfct_nlmsg_build_filter(struct nlmsghdr *nlh,
599  const struct nfct_filter_dump *filter_dump)
600 {
601  struct nfgenmsg *nfg;
602 
603  if (filter_dump->set & (1 << NFCT_FILTER_DUMP_MARK)) {
604  mnl_attr_put_u32(nlh, CTA_MARK, htonl(filter_dump->mark.val));
605  mnl_attr_put_u32(nlh, CTA_MARK_MASK, htonl(filter_dump->mark.mask));
606  }
607  if (filter_dump->set & (1 << NFCT_FILTER_DUMP_L3NUM)) {
608  nfg = mnl_nlmsg_get_payload(nlh);
609  nfg->nfgen_family = filter_dump->l3num;
610  }
611  if (filter_dump->set & (1 << NFCT_FILTER_DUMP_STATUS)) {
612  mnl_attr_put_u32(nlh, CTA_STATUS, htonl(filter_dump->status.val));
613  mnl_attr_put_u32(nlh, CTA_STATUS_MASK,
614  htonl(filter_dump->status.mask));
615  }
616 
617  return 0;
618 }