libnetfilter_conntrack 1.1.0
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
16static int
17nfct_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
44static int
45nfct_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
82int
83nfct_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
93int
94nfct_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;
107err:
108 mnl_attr_nest_cancel(nlh, nest);
109 return -1;
110}
111
112static int
113nfct_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
217static int
218nfct_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
229static int
230nfct_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
244static int
245nfct_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
265static int
266nfct_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
283static int
284nfct_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
296static int
297nfct_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
307static int
308nfct_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
318static int
319nfct_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
329static int
330nfct_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
342static int
343nfct_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
353static int
354nfct_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
364static int
365nfct_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
375static int
376nfct_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
382static int
383nfct_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
389static int
390nfct_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
396static int
397nfct_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
403static int
404nfct_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
419static int
420nfct_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
426static void
427nfct_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
440static 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
452int
453nfct_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
598static uint32_t get_flags_from_ct(const struct nf_conntrack *ct, int family)
599{
600 uint32_t tuple_flags = 0;
601
602 if (family == AF_INET) {
603 if (test_bit(ATTR_ORIG_IPV4_SRC, ct->head.set))
604 tuple_flags |= CTA_FILTER_FLAG_CTA_IP_SRC;
605 if (test_bit(ATTR_ORIG_IPV4_DST, ct->head.set))
606 tuple_flags |= CTA_FILTER_FLAG_CTA_IP_DST;
607
608 if (test_bit(ATTR_ICMP_TYPE, ct->head.set))
609 tuple_flags |= CTA_FILTER_FLAG_CTA_PROTO_ICMP_TYPE;
610 if (test_bit(ATTR_ICMP_CODE, ct->head.set))
611 tuple_flags |= CTA_FILTER_FLAG_CTA_PROTO_ICMP_CODE;
612 if (test_bit(ATTR_ICMP_ID, ct->head.set))
613 tuple_flags |= CTA_FILTER_FLAG_CTA_PROTO_ICMP_ID;
614 } else if (family == AF_INET6) {
615 if (test_bit(ATTR_ORIG_IPV6_SRC, ct->head.set))
616 tuple_flags |= CTA_FILTER_FLAG_CTA_IP_SRC;
617 if (test_bit(ATTR_ORIG_IPV6_DST, ct->head.set))
618 tuple_flags |= CTA_FILTER_FLAG_CTA_IP_DST;
619
620 if (test_bit(ATTR_ICMP_TYPE, ct->head.set))
621 tuple_flags |= CTA_FILTER_FLAG_CTA_PROTO_ICMPV6_TYPE;
622 if (test_bit(ATTR_ICMP_CODE, ct->head.set))
623 tuple_flags |= CTA_FILTER_FLAG_CTA_PROTO_ICMPV6_CODE;
624 if (test_bit(ATTR_ICMP_ID, ct->head.set))
625 tuple_flags |= CTA_FILTER_FLAG_CTA_PROTO_ICMPV6_ID;
626 }
627
628 if (test_bit(ATTR_ORIG_ZONE, ct->head.set))
629 tuple_flags |= CTA_FILTER_FLAG_CTA_TUPLE_ZONE;
630
631 if (test_bit(ATTR_ORIG_L4PROTO, ct->head.set))
632 tuple_flags |= CTA_FILTER_FLAG_CTA_PROTO_NUM;
633 if (test_bit(ATTR_ORIG_PORT_SRC, ct->head.set))
634 tuple_flags |= CTA_FILTER_FLAG_CTA_PROTO_SRC_PORT;
635 if (test_bit(ATTR_ORIG_PORT_DST, ct->head.set))
636 tuple_flags |= CTA_FILTER_FLAG_CTA_PROTO_DST_PORT;
637
638 return tuple_flags;
639}
640
641int nfct_nlmsg_build_filter(struct nlmsghdr *nlh,
642 const struct nfct_filter_dump *filter_dump)
643{
644 struct nfgenmsg *nfg;
645
646 if (filter_dump->set & (1 << NFCT_FILTER_DUMP_MARK)) {
647 mnl_attr_put_u32(nlh, CTA_MARK, htonl(filter_dump->mark.val));
648 mnl_attr_put_u32(nlh, CTA_MARK_MASK, htonl(filter_dump->mark.mask));
649 }
650 if (filter_dump->set & (1 << NFCT_FILTER_DUMP_L3NUM)) {
651 nfg = mnl_nlmsg_get_payload(nlh);
652 nfg->nfgen_family = filter_dump->l3num;
653 }
654 if (filter_dump->set & (1 << NFCT_FILTER_DUMP_STATUS)) {
655 mnl_attr_put_u32(nlh, CTA_STATUS, htonl(filter_dump->status.val));
656 mnl_attr_put_u32(nlh, CTA_STATUS_MASK,
657 htonl(filter_dump->status.mask));
658 }
659 if (filter_dump->set & (1 << NFCT_FILTER_DUMP_ZONE)) {
660 mnl_attr_put_u16(nlh, CTA_ZONE, htons(filter_dump->zone));
661 }
662 if (filter_dump->set & (1 << NFCT_FILTER_DUMP_TUPLE)) {
663 const struct nf_conntrack *ct = &filter_dump->ct;
664 struct nlattr *nest;
665 int ret;
666
667 ret = nfct_nlmsg_build(nlh, ct);
668 if (ret == -1)
669 return -1;
670
671 nest = mnl_attr_nest_start(nlh, CTA_FILTER);
672 if (nest == NULL)
673 return -1;
674
675 nfg = mnl_nlmsg_get_payload(nlh);
676
677 if (test_bit(ATTR_ORIG_L3PROTO, ct->head.set)) {
678 if (filter_dump->set & (1 << NFCT_FILTER_DUMP_L3NUM) &&
679 filter_dump->l3num != ct->head.orig.l3protonum) {
680 errno = EINVAL;
681 return -1;
682 }
683
684 nfg->nfgen_family = ct->head.orig.l3protonum;
685 }
686
687 mnl_attr_put_u32(nlh, CTA_FILTER_ORIG_FLAGS,
688 get_flags_from_ct(&filter_dump->ct,
689 nfg->nfgen_family));
690 mnl_attr_put_u32(nlh, CTA_FILTER_REPLY_FLAGS, 0);
691 mnl_attr_nest_end(nlh, nest);
692 }
693 return 0;
694}