3 * Shared library add-on to iptables for conntrack matching support.
5 * GPL (C) 2001 Marc Boucher (marc@mbsi.ca).
6 * Copyright © CC Computer Consultants GmbH, 2007 - 2008
7 * Jan Engelhardt <jengelh@computergmbh.de>
9 #include <sys/socket.h>
10 #include <sys/types.h>
19 #include <linux/netfilter.h>
20 #include <linux/netfilter/xt_conntrack.h>
21 #include <linux/netfilter/nf_conntrack_common.h>
22 #include <arpa/inet.h>
24 static void conntrack_mt_help(void)
27 "conntrack match options:\n"
28 "[!] --ctstate {INVALID|ESTABLISHED|NEW|RELATED|UNTRACKED|SNAT|DNAT}[,...]\n"
29 " State(s) to match\n"
30 "[!] --ctproto proto Protocol to match; by number or name, e.g. \"tcp\"\n"
31 "[!] --ctorigsrc address[/mask]\n"
32 "[!] --ctorigdst address[/mask]\n"
33 "[!] --ctreplsrc address[/mask]\n"
34 "[!] --ctrepldst address[/mask]\n"
35 " Original/Reply source/destination address\n"
36 "[!] --ctorigsrcport port\n"
37 "[!] --ctorigdstport port\n"
38 "[!] --ctreplsrcport port\n"
39 "[!] --ctrepldstport port\n"
40 " TCP/UDP/SCTP orig./reply source/destination port\n"
41 "[!] --ctstatus {NONE|EXPECTED|SEEN_REPLY|ASSURED|CONFIRMED}[,...]\n"
42 " Status(es) to match\n"
43 "[!] --ctexpire time[:time] Match remaining lifetime in seconds against\n"
44 " value or range of values (inclusive)\n"
45 " --ctdir {ORIGINAL|REPLY} Flow direction of packet\n");
48 static const struct option conntrack_mt_opts_v0
[] = {
49 {.name
= "ctstate", .has_arg
= true, .val
= '1'},
50 {.name
= "ctproto", .has_arg
= true, .val
= '2'},
51 {.name
= "ctorigsrc", .has_arg
= true, .val
= '3'},
52 {.name
= "ctorigdst", .has_arg
= true, .val
= '4'},
53 {.name
= "ctreplsrc", .has_arg
= true, .val
= '5'},
54 {.name
= "ctrepldst", .has_arg
= true, .val
= '6'},
55 {.name
= "ctstatus", .has_arg
= true, .val
= '7'},
56 {.name
= "ctexpire", .has_arg
= true, .val
= '8'},
60 static const struct option conntrack_mt_opts
[] = {
61 {.name
= "ctstate", .has_arg
= true, .val
= '1'},
62 {.name
= "ctproto", .has_arg
= true, .val
= '2'},
63 {.name
= "ctorigsrc", .has_arg
= true, .val
= '3'},
64 {.name
= "ctorigdst", .has_arg
= true, .val
= '4'},
65 {.name
= "ctreplsrc", .has_arg
= true, .val
= '5'},
66 {.name
= "ctrepldst", .has_arg
= true, .val
= '6'},
67 {.name
= "ctstatus", .has_arg
= true, .val
= '7'},
68 {.name
= "ctexpire", .has_arg
= true, .val
= '8'},
69 {.name
= "ctorigsrcport", .has_arg
= true, .val
= 'a'},
70 {.name
= "ctorigdstport", .has_arg
= true, .val
= 'b'},
71 {.name
= "ctreplsrcport", .has_arg
= true, .val
= 'c'},
72 {.name
= "ctrepldstport", .has_arg
= true, .val
= 'd'},
73 {.name
= "ctdir", .has_arg
= true, .val
= 'e'},
78 parse_state(const char *state
, size_t len
, struct xt_conntrack_info
*sinfo
)
80 if (strncasecmp(state
, "INVALID", len
) == 0)
81 sinfo
->statemask
|= XT_CONNTRACK_STATE_INVALID
;
82 else if (strncasecmp(state
, "NEW", len
) == 0)
83 sinfo
->statemask
|= XT_CONNTRACK_STATE_BIT(IP_CT_NEW
);
84 else if (strncasecmp(state
, "ESTABLISHED", len
) == 0)
85 sinfo
->statemask
|= XT_CONNTRACK_STATE_BIT(IP_CT_ESTABLISHED
);
86 else if (strncasecmp(state
, "RELATED", len
) == 0)
87 sinfo
->statemask
|= XT_CONNTRACK_STATE_BIT(IP_CT_RELATED
);
88 else if (strncasecmp(state
, "UNTRACKED", len
) == 0)
89 sinfo
->statemask
|= XT_CONNTRACK_STATE_UNTRACKED
;
90 else if (strncasecmp(state
, "SNAT", len
) == 0)
91 sinfo
->statemask
|= XT_CONNTRACK_STATE_SNAT
;
92 else if (strncasecmp(state
, "DNAT", len
) == 0)
93 sinfo
->statemask
|= XT_CONNTRACK_STATE_DNAT
;
100 parse_states(const char *arg
, struct xt_conntrack_info
*sinfo
)
104 while ((comma
= strchr(arg
, ',')) != NULL
) {
105 if (comma
== arg
|| !parse_state(arg
, comma
-arg
, sinfo
))
106 xtables_error(PARAMETER_PROBLEM
, "Bad ctstate \"%s\"", arg
);
110 xtables_error(PARAMETER_PROBLEM
, "\"--ctstate\" requires a list of "
111 "states with no spaces, e.g. "
112 "ESTABLISHED,RELATED");
113 if (strlen(arg
) == 0 || !parse_state(arg
, strlen(arg
), sinfo
))
114 xtables_error(PARAMETER_PROBLEM
, "Bad ctstate \"%s\"", arg
);
118 conntrack_ps_state(struct xt_conntrack_mtinfo1
*info
, const char *state
,
121 if (strncasecmp(state
, "INVALID", z
) == 0)
122 info
->state_mask
|= XT_CONNTRACK_STATE_INVALID
;
123 else if (strncasecmp(state
, "NEW", z
) == 0)
124 info
->state_mask
|= XT_CONNTRACK_STATE_BIT(IP_CT_NEW
);
125 else if (strncasecmp(state
, "ESTABLISHED", z
) == 0)
126 info
->state_mask
|= XT_CONNTRACK_STATE_BIT(IP_CT_ESTABLISHED
);
127 else if (strncasecmp(state
, "RELATED", z
) == 0)
128 info
->state_mask
|= XT_CONNTRACK_STATE_BIT(IP_CT_RELATED
);
129 else if (strncasecmp(state
, "UNTRACKED", z
) == 0)
130 info
->state_mask
|= XT_CONNTRACK_STATE_UNTRACKED
;
131 else if (strncasecmp(state
, "SNAT", z
) == 0)
132 info
->state_mask
|= XT_CONNTRACK_STATE_SNAT
;
133 else if (strncasecmp(state
, "DNAT", z
) == 0)
134 info
->state_mask
|= XT_CONNTRACK_STATE_DNAT
;
141 conntrack_ps_states(struct xt_conntrack_mtinfo1
*info
, const char *arg
)
145 while ((comma
= strchr(arg
, ',')) != NULL
) {
146 if (comma
== arg
|| !conntrack_ps_state(info
, arg
, comma
- arg
))
147 xtables_error(PARAMETER_PROBLEM
,
148 "Bad ctstate \"%s\"", arg
);
152 if (strlen(arg
) == 0 || !conntrack_ps_state(info
, arg
, strlen(arg
)))
153 xtables_error(PARAMETER_PROBLEM
, "Bad ctstate \"%s\"", arg
);
157 parse_status(const char *status
, size_t len
, struct xt_conntrack_info
*sinfo
)
159 if (strncasecmp(status
, "NONE", len
) == 0)
160 sinfo
->statusmask
|= 0;
161 else if (strncasecmp(status
, "EXPECTED", len
) == 0)
162 sinfo
->statusmask
|= IPS_EXPECTED
;
163 else if (strncasecmp(status
, "SEEN_REPLY", len
) == 0)
164 sinfo
->statusmask
|= IPS_SEEN_REPLY
;
165 else if (strncasecmp(status
, "ASSURED", len
) == 0)
166 sinfo
->statusmask
|= IPS_ASSURED
;
168 else if (strncasecmp(status
, "CONFIRMED", len
) == 0)
169 sinfo
->statusmask
|= IPS_CONFIRMED
;
177 parse_statuses(const char *arg
, struct xt_conntrack_info
*sinfo
)
181 while ((comma
= strchr(arg
, ',')) != NULL
) {
182 if (comma
== arg
|| !parse_status(arg
, comma
-arg
, sinfo
))
183 xtables_error(PARAMETER_PROBLEM
, "Bad ctstatus \"%s\"", arg
);
187 if (strlen(arg
) == 0 || !parse_status(arg
, strlen(arg
), sinfo
))
188 xtables_error(PARAMETER_PROBLEM
, "Bad ctstatus \"%s\"", arg
);
192 conntrack_ps_status(struct xt_conntrack_mtinfo1
*info
, const char *status
,
195 if (strncasecmp(status
, "NONE", z
) == 0)
196 info
->status_mask
|= 0;
197 else if (strncasecmp(status
, "EXPECTED", z
) == 0)
198 info
->status_mask
|= IPS_EXPECTED
;
199 else if (strncasecmp(status
, "SEEN_REPLY", z
) == 0)
200 info
->status_mask
|= IPS_SEEN_REPLY
;
201 else if (strncasecmp(status
, "ASSURED", z
) == 0)
202 info
->status_mask
|= IPS_ASSURED
;
203 else if (strncasecmp(status
, "CONFIRMED", z
) == 0)
204 info
->status_mask
|= IPS_CONFIRMED
;
211 conntrack_ps_statuses(struct xt_conntrack_mtinfo1
*info
, const char *arg
)
215 while ((comma
= strchr(arg
, ',')) != NULL
) {
216 if (comma
== arg
|| !conntrack_ps_status(info
, arg
, comma
- arg
))
217 xtables_error(PARAMETER_PROBLEM
,
218 "Bad ctstatus \"%s\"", arg
);
222 if (strlen(arg
) == 0 || !conntrack_ps_status(info
, arg
, strlen(arg
)))
223 xtables_error(PARAMETER_PROBLEM
, "Bad ctstatus \"%s\"", arg
);
227 parse_expire(const char *s
)
231 if (!xtables_strtoui(s
, NULL
, &len
, 0, UINT32_MAX
))
232 xtables_error(PARAMETER_PROBLEM
, "expire value invalid: \"%s\"\n", s
);
237 /* If a single value is provided, min and max are both set to the value */
239 parse_expires(const char *s
, struct xt_conntrack_info
*sinfo
)
245 if ((cp
= strchr(buffer
, ':')) == NULL
)
246 sinfo
->expires_min
= sinfo
->expires_max
=
247 parse_expire(buffer
);
252 sinfo
->expires_min
= buffer
[0] ? parse_expire(buffer
) : 0;
253 sinfo
->expires_max
= cp
[0]
259 if (sinfo
->expires_min
> sinfo
->expires_max
)
260 xtables_error(PARAMETER_PROBLEM
,
261 "expire min. range value `%lu' greater than max. "
262 "range value `%lu'", sinfo
->expires_min
, sinfo
->expires_max
);
266 conntrack_ps_expires(struct xt_conntrack_mtinfo1
*info
, const char *s
)
268 unsigned int min
, max
;
271 if (!xtables_strtoui(s
, &end
, &min
, 0, UINT32_MAX
))
272 xtables_param_act(XTF_BAD_VALUE
, "conntrack", "--expires", s
);
275 if (!xtables_strtoui(s
, &end
, &max
, 0, UINT32_MAX
))
276 xtables_param_act(XTF_BAD_VALUE
, "conntrack", "--expires", s
);
278 xtables_param_act(XTF_BAD_VALUE
, "conntrack", "--expires", s
);
281 xtables_error(PARAMETER_PROBLEM
,
282 "expire min. range value \"%u\" greater than max. "
283 "range value \"%u\"", min
, max
);
285 info
->expires_min
= min
;
286 info
->expires_max
= max
;
289 static int conntrack_parse(int c
, char **argv
, int invert
, unsigned int *flags
,
290 const void *entry
, struct xt_entry_match
**match
)
292 struct xt_conntrack_info
*sinfo
= (void *)(*match
)->data
;
293 char *protocol
= NULL
;
294 unsigned int naddrs
= 0;
295 struct in_addr
*addrs
= NULL
;
300 xtables_check_inverse(optarg
, &invert
, &optind
, 0);
302 parse_states(argv
[optind
-1], sinfo
);
304 sinfo
->invflags
|= XT_CONNTRACK_STATE
;
306 sinfo
->flags
|= XT_CONNTRACK_STATE
;
310 xtables_check_inverse(optarg
, &invert
, &optind
, 0);
313 sinfo
->invflags
|= XT_CONNTRACK_PROTO
;
315 /* Canonicalize into lower case */
316 for (protocol
= argv
[optind
-1]; *protocol
; protocol
++)
317 *protocol
= tolower(*protocol
);
319 protocol
= argv
[optind
-1];
320 sinfo
->tuple
[IP_CT_DIR_ORIGINAL
].dst
.protonum
=
321 xtables_parse_protocol(protocol
);
323 if (sinfo
->tuple
[IP_CT_DIR_ORIGINAL
].dst
.protonum
== 0
324 && (sinfo
->invflags
& XT_INV_PROTO
))
325 xtables_error(PARAMETER_PROBLEM
,
326 "rule would never match protocol");
328 sinfo
->flags
|= XT_CONNTRACK_PROTO
;
332 xtables_check_inverse(optarg
, &invert
, &optind
, 0);
335 sinfo
->invflags
|= XT_CONNTRACK_ORIGSRC
;
337 xtables_ipparse_any(argv
[optind
-1], &addrs
,
338 &sinfo
->sipmsk
[IP_CT_DIR_ORIGINAL
],
341 xtables_error(PARAMETER_PROBLEM
,
342 "multiple IP addresses not allowed");
345 sinfo
->tuple
[IP_CT_DIR_ORIGINAL
].src
.ip
= addrs
[0].s_addr
;
348 sinfo
->flags
|= XT_CONNTRACK_ORIGSRC
;
352 xtables_check_inverse(optarg
, &invert
, &optind
, 0);
355 sinfo
->invflags
|= XT_CONNTRACK_ORIGDST
;
357 xtables_ipparse_any(argv
[optind
-1], &addrs
,
358 &sinfo
->dipmsk
[IP_CT_DIR_ORIGINAL
],
361 xtables_error(PARAMETER_PROBLEM
,
362 "multiple IP addresses not allowed");
365 sinfo
->tuple
[IP_CT_DIR_ORIGINAL
].dst
.ip
= addrs
[0].s_addr
;
368 sinfo
->flags
|= XT_CONNTRACK_ORIGDST
;
372 xtables_check_inverse(optarg
, &invert
, &optind
, 0);
375 sinfo
->invflags
|= XT_CONNTRACK_REPLSRC
;
377 xtables_ipparse_any(argv
[optind
-1], &addrs
,
378 &sinfo
->sipmsk
[IP_CT_DIR_REPLY
],
381 xtables_error(PARAMETER_PROBLEM
,
382 "multiple IP addresses not allowed");
385 sinfo
->tuple
[IP_CT_DIR_REPLY
].src
.ip
= addrs
[0].s_addr
;
388 sinfo
->flags
|= XT_CONNTRACK_REPLSRC
;
392 xtables_check_inverse(optarg
, &invert
, &optind
, 0);
395 sinfo
->invflags
|= XT_CONNTRACK_REPLDST
;
397 xtables_ipparse_any(argv
[optind
-1], &addrs
,
398 &sinfo
->dipmsk
[IP_CT_DIR_REPLY
],
401 xtables_error(PARAMETER_PROBLEM
,
402 "multiple IP addresses not allowed");
405 sinfo
->tuple
[IP_CT_DIR_REPLY
].dst
.ip
= addrs
[0].s_addr
;
408 sinfo
->flags
|= XT_CONNTRACK_REPLDST
;
412 xtables_check_inverse(optarg
, &invert
, &optind
, 0);
414 parse_statuses(argv
[optind
-1], sinfo
);
416 sinfo
->invflags
|= XT_CONNTRACK_STATUS
;
418 sinfo
->flags
|= XT_CONNTRACK_STATUS
;
422 xtables_check_inverse(optarg
, &invert
, &optind
, 0);
424 parse_expires(argv
[optind
-1], sinfo
);
426 sinfo
->invflags
|= XT_CONNTRACK_EXPIRES
;
428 sinfo
->flags
|= XT_CONNTRACK_EXPIRES
;
435 *flags
= sinfo
->flags
;
440 conntrack_mt_parse(int c
, char **argv
, int invert
, unsigned int *flags
,
441 struct xt_entry_match
**match
)
443 struct xt_conntrack_mtinfo1
*info
= (void *)(*match
)->data
;
448 case '1': /* --ctstate */
449 conntrack_ps_states(info
, optarg
);
450 info
->match_flags
|= XT_CONNTRACK_STATE
;
452 info
->invert_flags
|= XT_CONNTRACK_STATE
;
455 case '2': /* --ctproto */
456 /* Canonicalize into lower case */
457 for (p
= optarg
; *p
!= '\0'; ++p
)
459 info
->l4proto
= xtables_parse_protocol(optarg
);
461 if (info
->l4proto
== 0 && (info
->invert_flags
& XT_INV_PROTO
))
462 xtables_error(PARAMETER_PROBLEM
, "conntrack: rule would "
463 "never match protocol");
465 info
->match_flags
|= XT_CONNTRACK_PROTO
;
467 info
->invert_flags
|= XT_CONNTRACK_PROTO
;
470 case '7': /* --ctstatus */
471 conntrack_ps_statuses(info
, optarg
);
472 info
->match_flags
|= XT_CONNTRACK_STATUS
;
474 info
->invert_flags
|= XT_CONNTRACK_STATUS
;
477 case '8': /* --ctexpire */
478 conntrack_ps_expires(info
, optarg
);
479 info
->match_flags
|= XT_CONNTRACK_EXPIRES
;
481 info
->invert_flags
|= XT_CONNTRACK_EXPIRES
;
484 case 'a': /* --ctorigsrcport */
485 if (!xtables_strtoui(optarg
, NULL
, &port
, 0, UINT16_MAX
))
486 xtables_param_act(XTF_BAD_VALUE
, "conntrack",
487 "--ctorigsrcport", optarg
);
488 info
->match_flags
|= XT_CONNTRACK_ORIGSRC_PORT
;
489 info
->origsrc_port
= htons(port
);
491 info
->invert_flags
|= XT_CONNTRACK_ORIGSRC_PORT
;
494 case 'b': /* --ctorigdstport */
495 if (!xtables_strtoui(optarg
, NULL
, &port
, 0, UINT16_MAX
))
496 xtables_param_act(XTF_BAD_VALUE
, "conntrack",
497 "--ctorigdstport", optarg
);
498 info
->match_flags
|= XT_CONNTRACK_ORIGDST_PORT
;
499 info
->origdst_port
= htons(port
);
501 info
->invert_flags
|= XT_CONNTRACK_ORIGDST_PORT
;
504 case 'c': /* --ctreplsrcport */
505 if (!xtables_strtoui(optarg
, NULL
, &port
, 0, UINT16_MAX
))
506 xtables_param_act(XTF_BAD_VALUE
, "conntrack",
507 "--ctreplsrcport", optarg
);
508 info
->match_flags
|= XT_CONNTRACK_REPLSRC_PORT
;
509 info
->replsrc_port
= htons(port
);
511 info
->invert_flags
|= XT_CONNTRACK_REPLSRC_PORT
;
514 case 'd': /* --ctrepldstport */
515 if (!xtables_strtoui(optarg
, NULL
, &port
, 0, UINT16_MAX
))
516 xtables_param_act(XTF_BAD_VALUE
, "conntrack",
517 "--ctrepldstport", optarg
);
518 info
->match_flags
|= XT_CONNTRACK_REPLDST_PORT
;
519 info
->repldst_port
= htons(port
);
521 info
->invert_flags
|= XT_CONNTRACK_REPLDST_PORT
;
524 case 'e': /* --ctdir */
525 xtables_param_act(XTF_NO_INVERT
, "conntrack", "--ctdir", invert
);
526 if (strcasecmp(optarg
, "ORIGINAL") == 0) {
527 info
->match_flags
|= XT_CONNTRACK_DIRECTION
;
528 info
->invert_flags
&= ~XT_CONNTRACK_DIRECTION
;
529 } else if (strcasecmp(optarg
, "REPLY") == 0) {
530 info
->match_flags
|= XT_CONNTRACK_DIRECTION
;
531 info
->invert_flags
|= XT_CONNTRACK_DIRECTION
;
533 xtables_param_act(XTF_BAD_VALUE
, "conntrack", "--ctdir", optarg
);
541 *flags
= info
->match_flags
;
546 conntrack_mt4_parse(int c
, char **argv
, int invert
, unsigned int *flags
,
547 const void *entry
, struct xt_entry_match
**match
)
549 struct xt_conntrack_mtinfo1
*info
= (void *)(*match
)->data
;
550 struct in_addr
*addr
= NULL
;
551 unsigned int naddrs
= 0;
554 case '3': /* --ctorigsrc */
555 xtables_ipparse_any(optarg
, &addr
, &info
->origsrc_mask
.in
,
558 xtables_error(PARAMETER_PROBLEM
,
559 "multiple IP addresses not allowed");
561 memcpy(&info
->origsrc_addr
.in
, addr
, sizeof(*addr
));
562 info
->match_flags
|= XT_CONNTRACK_ORIGSRC
;
564 info
->invert_flags
|= XT_CONNTRACK_ORIGSRC
;
567 case '4': /* --ctorigdst */
568 xtables_ipparse_any(optarg
, &addr
, &info
->origdst_mask
.in
,
571 xtables_error(PARAMETER_PROBLEM
,
572 "multiple IP addresses not allowed");
574 memcpy(&info
->origdst_addr
.in
, addr
, sizeof(*addr
));
575 info
->match_flags
|= XT_CONNTRACK_ORIGDST
;
577 info
->invert_flags
|= XT_CONNTRACK_ORIGDST
;
580 case '5': /* --ctreplsrc */
581 xtables_ipparse_any(optarg
, &addr
, &info
->replsrc_mask
.in
,
584 xtables_error(PARAMETER_PROBLEM
,
585 "multiple IP addresses not allowed");
587 memcpy(&info
->replsrc_addr
.in
, addr
, sizeof(*addr
));
588 info
->match_flags
|= XT_CONNTRACK_REPLSRC
;
590 info
->invert_flags
|= XT_CONNTRACK_REPLSRC
;
593 case '6': /* --ctrepldst */
594 xtables_ipparse_any(optarg
, &addr
, &info
->repldst_mask
.in
,
597 xtables_error(PARAMETER_PROBLEM
,
598 "multiple IP addresses not allowed");
600 memcpy(&info
->repldst_addr
.in
, addr
, sizeof(*addr
));
601 info
->match_flags
|= XT_CONNTRACK_REPLDST
;
603 info
->invert_flags
|= XT_CONNTRACK_REPLDST
;
608 return conntrack_mt_parse(c
, argv
, invert
, flags
, match
);
611 *flags
= info
->match_flags
;
616 conntrack_mt6_parse(int c
, char **argv
, int invert
, unsigned int *flags
,
617 const void *entry
, struct xt_entry_match
**match
)
619 struct xt_conntrack_mtinfo1
*info
= (void *)(*match
)->data
;
620 struct in6_addr
*addr
= NULL
;
621 unsigned int naddrs
= 0;
624 case '3': /* --ctorigsrc */
625 xtables_ip6parse_any(optarg
, &addr
,
626 &info
->origsrc_mask
.in6
, &naddrs
);
628 xtables_error(PARAMETER_PROBLEM
,
629 "multiple IP addresses not allowed");
631 memcpy(&info
->origsrc_addr
.in6
, addr
, sizeof(*addr
));
632 info
->match_flags
|= XT_CONNTRACK_ORIGSRC
;
634 info
->invert_flags
|= XT_CONNTRACK_ORIGSRC
;
637 case '4': /* --ctorigdst */
638 xtables_ip6parse_any(optarg
, &addr
,
639 &info
->origdst_mask
.in6
, &naddrs
);
641 xtables_error(PARAMETER_PROBLEM
,
642 "multiple IP addresses not allowed");
644 memcpy(&info
->origdst_addr
.in
, addr
, sizeof(*addr
));
645 info
->match_flags
|= XT_CONNTRACK_ORIGDST
;
647 info
->invert_flags
|= XT_CONNTRACK_ORIGDST
;
650 case '5': /* --ctreplsrc */
651 xtables_ip6parse_any(optarg
, &addr
,
652 &info
->replsrc_mask
.in6
, &naddrs
);
654 xtables_error(PARAMETER_PROBLEM
,
655 "multiple IP addresses not allowed");
657 memcpy(&info
->replsrc_addr
.in
, addr
, sizeof(*addr
));
658 info
->match_flags
|= XT_CONNTRACK_REPLSRC
;
660 info
->invert_flags
|= XT_CONNTRACK_REPLSRC
;
663 case '6': /* --ctrepldst */
664 xtables_ip6parse_any(optarg
, &addr
,
665 &info
->repldst_mask
.in6
, &naddrs
);
667 xtables_error(PARAMETER_PROBLEM
,
668 "multiple IP addresses not allowed");
670 memcpy(&info
->repldst_addr
.in
, addr
, sizeof(*addr
));
671 info
->match_flags
|= XT_CONNTRACK_REPLDST
;
673 info
->invert_flags
|= XT_CONNTRACK_REPLDST
;
678 return conntrack_mt_parse(c
, argv
, invert
, flags
, match
);
681 *flags
= info
->match_flags
;
685 static void conntrack_mt_check(unsigned int flags
)
688 xtables_error(PARAMETER_PROBLEM
, "conntrack: At least one option "
693 print_state(unsigned int statemask
)
695 const char *sep
= "";
697 if (statemask
& XT_CONNTRACK_STATE_INVALID
) {
698 printf("%sINVALID", sep
);
701 if (statemask
& XT_CONNTRACK_STATE_BIT(IP_CT_NEW
)) {
702 printf("%sNEW", sep
);
705 if (statemask
& XT_CONNTRACK_STATE_BIT(IP_CT_RELATED
)) {
706 printf("%sRELATED", sep
);
709 if (statemask
& XT_CONNTRACK_STATE_BIT(IP_CT_ESTABLISHED
)) {
710 printf("%sESTABLISHED", sep
);
713 if (statemask
& XT_CONNTRACK_STATE_UNTRACKED
) {
714 printf("%sUNTRACKED", sep
);
717 if (statemask
& XT_CONNTRACK_STATE_SNAT
) {
718 printf("%sSNAT", sep
);
721 if (statemask
& XT_CONNTRACK_STATE_DNAT
) {
722 printf("%sDNAT", sep
);
729 print_status(unsigned int statusmask
)
731 const char *sep
= "";
733 if (statusmask
& IPS_EXPECTED
) {
734 printf("%sEXPECTED", sep
);
737 if (statusmask
& IPS_SEEN_REPLY
) {
738 printf("%sSEEN_REPLY", sep
);
741 if (statusmask
& IPS_ASSURED
) {
742 printf("%sASSURED", sep
);
745 if (statusmask
& IPS_CONFIRMED
) {
746 printf("%sCONFIRMED", sep
);
750 printf("%sNONE", sep
);
755 conntrack_dump_addr(const union nf_inet_addr
*addr
,
756 const union nf_inet_addr
*mask
,
757 unsigned int family
, bool numeric
)
759 if (family
== NFPROTO_IPV4
) {
760 if (!numeric
&& addr
->ip
== 0) {
765 printf("%s ", xtables_ipaddr_to_numeric(&addr
->in
));
767 printf("%s ", xtables_ipaddr_to_anyname(&addr
->in
));
768 } else if (family
== NFPROTO_IPV6
) {
769 if (!numeric
&& addr
->ip6
[0] == 0 && addr
->ip6
[1] == 0 &&
770 addr
->ip6
[2] == 0 && addr
->ip6
[3] == 0) {
775 printf("%s ", xtables_ip6addr_to_numeric(&addr
->in6
));
777 printf("%s ", xtables_ip6addr_to_anyname(&addr
->in6
));
782 print_addr(const struct in_addr
*addr
, const struct in_addr
*mask
,
783 int inv
, int numeric
)
790 if (mask
->s_addr
== 0L && !numeric
)
791 printf("%s ", "anywhere");
794 strcpy(buf
, xtables_ipaddr_to_numeric(addr
));
796 strcpy(buf
, xtables_ipaddr_to_anyname(addr
));
797 strcat(buf
, xtables_ipmask_to_numeric(mask
));
803 matchinfo_print(const void *ip
, const struct xt_entry_match
*match
, int numeric
, const char *optpfx
)
805 const struct xt_conntrack_info
*sinfo
= (const void *)match
->data
;
807 if(sinfo
->flags
& XT_CONNTRACK_STATE
) {
808 if (sinfo
->invflags
& XT_CONNTRACK_STATE
)
810 printf("%sctstate ", optpfx
);
811 print_state(sinfo
->statemask
);
814 if(sinfo
->flags
& XT_CONNTRACK_PROTO
) {
815 if (sinfo
->invflags
& XT_CONNTRACK_PROTO
)
817 printf("%sctproto ", optpfx
);
818 printf("%u ", sinfo
->tuple
[IP_CT_DIR_ORIGINAL
].dst
.protonum
);
821 if(sinfo
->flags
& XT_CONNTRACK_ORIGSRC
) {
822 if (sinfo
->invflags
& XT_CONNTRACK_ORIGSRC
)
824 printf("%sctorigsrc ", optpfx
);
827 (struct in_addr
*)&sinfo
->tuple
[IP_CT_DIR_ORIGINAL
].src
.ip
,
828 &sinfo
->sipmsk
[IP_CT_DIR_ORIGINAL
],
833 if(sinfo
->flags
& XT_CONNTRACK_ORIGDST
) {
834 if (sinfo
->invflags
& XT_CONNTRACK_ORIGDST
)
836 printf("%sctorigdst ", optpfx
);
839 (struct in_addr
*)&sinfo
->tuple
[IP_CT_DIR_ORIGINAL
].dst
.ip
,
840 &sinfo
->dipmsk
[IP_CT_DIR_ORIGINAL
],
845 if(sinfo
->flags
& XT_CONNTRACK_REPLSRC
) {
846 if (sinfo
->invflags
& XT_CONNTRACK_REPLSRC
)
848 printf("%sctreplsrc ", optpfx
);
851 (struct in_addr
*)&sinfo
->tuple
[IP_CT_DIR_REPLY
].src
.ip
,
852 &sinfo
->sipmsk
[IP_CT_DIR_REPLY
],
857 if(sinfo
->flags
& XT_CONNTRACK_REPLDST
) {
858 if (sinfo
->invflags
& XT_CONNTRACK_REPLDST
)
860 printf("%sctrepldst ", optpfx
);
863 (struct in_addr
*)&sinfo
->tuple
[IP_CT_DIR_REPLY
].dst
.ip
,
864 &sinfo
->dipmsk
[IP_CT_DIR_REPLY
],
869 if(sinfo
->flags
& XT_CONNTRACK_STATUS
) {
870 if (sinfo
->invflags
& XT_CONNTRACK_STATUS
)
872 printf("%sctstatus ", optpfx
);
873 print_status(sinfo
->statusmask
);
876 if(sinfo
->flags
& XT_CONNTRACK_EXPIRES
) {
877 if (sinfo
->invflags
& XT_CONNTRACK_EXPIRES
)
879 printf("%sctexpire ", optpfx
);
881 if (sinfo
->expires_max
== sinfo
->expires_min
)
882 printf("%lu ", sinfo
->expires_min
);
884 printf("%lu:%lu ", sinfo
->expires_min
, sinfo
->expires_max
);
887 if (sinfo
->flags
& XT_CONNTRACK_DIRECTION
) {
888 if (sinfo
->invflags
& XT_CONNTRACK_DIRECTION
)
889 printf("%sctdir REPLY", optpfx
);
891 printf("%sctdir ORIGINAL", optpfx
);
897 conntrack_dump(const struct xt_conntrack_mtinfo1
*info
, const char *prefix
,
898 unsigned int family
, bool numeric
)
900 if (info
->match_flags
& XT_CONNTRACK_STATE
) {
901 if (info
->invert_flags
& XT_CONNTRACK_STATE
)
903 printf("%sctstate ", prefix
);
904 print_state(info
->state_mask
);
907 if (info
->match_flags
& XT_CONNTRACK_PROTO
) {
908 if (info
->invert_flags
& XT_CONNTRACK_PROTO
)
910 printf("%sctproto %u ", prefix
, info
->l4proto
);
913 if (info
->match_flags
& XT_CONNTRACK_ORIGSRC
) {
914 if (info
->invert_flags
& XT_CONNTRACK_ORIGSRC
)
916 printf("%sctorigsrc ", prefix
);
917 conntrack_dump_addr(&info
->origsrc_addr
, &info
->origsrc_mask
,
921 if (info
->match_flags
& XT_CONNTRACK_ORIGDST
) {
922 if (info
->invert_flags
& XT_CONNTRACK_ORIGDST
)
924 printf("%sctorigdst ", prefix
);
925 conntrack_dump_addr(&info
->origdst_addr
, &info
->origdst_mask
,
929 if (info
->match_flags
& XT_CONNTRACK_REPLSRC
) {
930 if (info
->invert_flags
& XT_CONNTRACK_REPLSRC
)
932 printf("%sctreplsrc ", prefix
);
933 conntrack_dump_addr(&info
->replsrc_addr
, &info
->replsrc_mask
,
937 if (info
->match_flags
& XT_CONNTRACK_REPLDST
) {
938 if (info
->invert_flags
& XT_CONNTRACK_REPLDST
)
940 printf("%sctrepldst ", prefix
);
941 conntrack_dump_addr(&info
->repldst_addr
, &info
->repldst_mask
,
945 if (info
->match_flags
& XT_CONNTRACK_ORIGSRC_PORT
) {
946 if (info
->invert_flags
& XT_CONNTRACK_ORIGSRC_PORT
)
948 printf("%sctorigsrcport %u ", prefix
,
949 ntohs(info
->origsrc_port
));
952 if (info
->match_flags
& XT_CONNTRACK_ORIGDST_PORT
) {
953 if (info
->invert_flags
& XT_CONNTRACK_ORIGDST_PORT
)
955 printf("%sctorigdstport %u ", prefix
,
956 ntohs(info
->origdst_port
));
959 if (info
->match_flags
& XT_CONNTRACK_REPLSRC_PORT
) {
960 if (info
->invert_flags
& XT_CONNTRACK_REPLSRC_PORT
)
962 printf("%sctreplsrcport %u ", prefix
,
963 ntohs(info
->replsrc_port
));
966 if (info
->match_flags
& XT_CONNTRACK_REPLDST_PORT
) {
967 if (info
->invert_flags
& XT_CONNTRACK_REPLDST_PORT
)
969 printf("%sctrepldstport %u ", prefix
,
970 ntohs(info
->repldst_port
));
973 if (info
->match_flags
& XT_CONNTRACK_STATUS
) {
974 if (info
->invert_flags
& XT_CONNTRACK_STATUS
)
976 printf("%sctstatus ", prefix
);
977 print_status(info
->status_mask
);
980 if (info
->match_flags
& XT_CONNTRACK_EXPIRES
) {
981 if (info
->invert_flags
& XT_CONNTRACK_EXPIRES
)
983 printf("%sctexpire ", prefix
);
985 if (info
->expires_max
== info
->expires_min
)
986 printf("%u ", (unsigned int)info
->expires_min
);
988 printf("%u:%u ", (unsigned int)info
->expires_min
,
989 (unsigned int)info
->expires_max
);
992 if (info
->match_flags
& XT_CONNTRACK_DIRECTION
) {
993 if (info
->invert_flags
& XT_CONNTRACK_DIRECTION
)
994 printf("%sctdir REPLY", prefix
);
996 printf("%sctdir ORIGINAL", prefix
);
1000 static void conntrack_print(const void *ip
, const struct xt_entry_match
*match
,
1003 matchinfo_print(ip
, match
, numeric
, "");
1007 conntrack_mt_print(const void *ip
, const struct xt_entry_match
*match
,
1010 conntrack_dump((const void *)match
->data
, "", NFPROTO_IPV4
, numeric
);
1014 conntrack_mt6_print(const void *ip
, const struct xt_entry_match
*match
,
1017 conntrack_dump((const void *)match
->data
, "", NFPROTO_IPV6
, numeric
);
1020 static void conntrack_save(const void *ip
, const struct xt_entry_match
*match
)
1022 matchinfo_print(ip
, match
, 1, "--");
1025 static void conntrack_mt_save(const void *ip
,
1026 const struct xt_entry_match
*match
)
1028 conntrack_dump((const void *)match
->data
, "--", NFPROTO_IPV4
, true);
1031 static void conntrack_mt6_save(const void *ip
,
1032 const struct xt_entry_match
*match
)
1034 conntrack_dump((const void *)match
->data
, "--", NFPROTO_IPV6
, true);
1037 static struct xtables_match conntrack_match
= {
1038 .version
= XTABLES_VERSION
,
1039 .name
= "conntrack",
1041 .family
= NFPROTO_IPV4
,
1042 .size
= XT_ALIGN(sizeof(struct xt_conntrack_info
)),
1043 .userspacesize
= XT_ALIGN(sizeof(struct xt_conntrack_info
)),
1044 .help
= conntrack_mt_help
,
1045 .parse
= conntrack_parse
,
1046 .final_check
= conntrack_mt_check
,
1047 .print
= conntrack_print
,
1048 .save
= conntrack_save
,
1049 .extra_opts
= conntrack_mt_opts_v0
,
1052 static struct xtables_match conntrack_mt_reg
= {
1053 .version
= XTABLES_VERSION
,
1054 .name
= "conntrack",
1056 .family
= NFPROTO_IPV4
,
1057 .size
= XT_ALIGN(sizeof(struct xt_conntrack_mtinfo1
)),
1058 .userspacesize
= XT_ALIGN(sizeof(struct xt_conntrack_mtinfo1
)),
1059 .help
= conntrack_mt_help
,
1060 .parse
= conntrack_mt4_parse
,
1061 .final_check
= conntrack_mt_check
,
1062 .print
= conntrack_mt_print
,
1063 .save
= conntrack_mt_save
,
1064 .extra_opts
= conntrack_mt_opts
,
1067 static struct xtables_match conntrack_mt6_reg
= {
1068 .version
= XTABLES_VERSION
,
1069 .name
= "conntrack",
1071 .family
= NFPROTO_IPV6
,
1072 .size
= XT_ALIGN(sizeof(struct xt_conntrack_mtinfo1
)),
1073 .userspacesize
= XT_ALIGN(sizeof(struct xt_conntrack_mtinfo1
)),
1074 .help
= conntrack_mt_help
,
1075 .parse
= conntrack_mt6_parse
,
1076 .final_check
= conntrack_mt_check
,
1077 .print
= conntrack_mt6_print
,
1078 .save
= conntrack_mt6_save
,
1079 .extra_opts
= conntrack_mt_opts
,
1084 xtables_register_match(&conntrack_match
);
1085 xtables_register_match(&conntrack_mt_reg
);
1086 xtables_register_match(&conntrack_mt6_reg
);