manpages: do not include v4-only modules in ip6tables manpage
[jleu-iptables.git] / extensions / libxt_conntrack.c
blob96ea3ec5722444aa388145e3f181d9b5fa6fe0ad
1 /*
2 * libxt_conntrack
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>
8 */
9 #include <sys/socket.h>
10 #include <sys/types.h>
11 #include <ctype.h>
12 #include <getopt.h>
13 #include <netdb.h>
14 #include <stdbool.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <xtables.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)
26 printf(
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'},
57 { .name = NULL }
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'},
74 {.name = NULL},
77 static int
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;
94 else
95 return 0;
96 return 1;
99 static void
100 parse_states(const char *arg, struct xt_conntrack_info *sinfo)
102 const char *comma;
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);
107 arg = comma+1;
109 if (!*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);
117 static bool
118 conntrack_ps_state(struct xt_conntrack_mtinfo1 *info, const char *state,
119 size_t z)
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;
135 else
136 return false;
137 return true;
140 static void
141 conntrack_ps_states(struct xt_conntrack_mtinfo1 *info, const char *arg)
143 const char *comma;
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);
149 arg = comma + 1;
152 if (strlen(arg) == 0 || !conntrack_ps_state(info, arg, strlen(arg)))
153 xtables_error(PARAMETER_PROBLEM, "Bad ctstate \"%s\"", arg);
156 static int
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;
167 #ifdef IPS_CONFIRMED
168 else if (strncasecmp(status, "CONFIRMED", len) == 0)
169 sinfo->statusmask |= IPS_CONFIRMED;
170 #endif
171 else
172 return 0;
173 return 1;
176 static void
177 parse_statuses(const char *arg, struct xt_conntrack_info *sinfo)
179 const char *comma;
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);
184 arg = comma+1;
187 if (strlen(arg) == 0 || !parse_status(arg, strlen(arg), sinfo))
188 xtables_error(PARAMETER_PROBLEM, "Bad ctstatus \"%s\"", arg);
191 static bool
192 conntrack_ps_status(struct xt_conntrack_mtinfo1 *info, const char *status,
193 size_t z)
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;
205 else
206 return false;
207 return true;
210 static void
211 conntrack_ps_statuses(struct xt_conntrack_mtinfo1 *info, const char *arg)
213 const char *comma;
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);
219 arg = comma + 1;
222 if (strlen(arg) == 0 || !conntrack_ps_status(info, arg, strlen(arg)))
223 xtables_error(PARAMETER_PROBLEM, "Bad ctstatus \"%s\"", arg);
226 static unsigned long
227 parse_expire(const char *s)
229 unsigned int len;
231 if (!xtables_strtoui(s, NULL, &len, 0, UINT32_MAX))
232 xtables_error(PARAMETER_PROBLEM, "expire value invalid: \"%s\"\n", s);
233 else
234 return len;
237 /* If a single value is provided, min and max are both set to the value */
238 static void
239 parse_expires(const char *s, struct xt_conntrack_info *sinfo)
241 char *buffer;
242 char *cp;
244 buffer = strdup(s);
245 if ((cp = strchr(buffer, ':')) == NULL)
246 sinfo->expires_min = sinfo->expires_max =
247 parse_expire(buffer);
248 else {
249 *cp = '\0';
250 cp++;
252 sinfo->expires_min = buffer[0] ? parse_expire(buffer) : 0;
253 sinfo->expires_max = cp[0]
254 ? parse_expire(cp)
255 : (unsigned long)-1;
257 free(buffer);
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);
265 static void
266 conntrack_ps_expires(struct xt_conntrack_mtinfo1 *info, const char *s)
268 unsigned int min, max;
269 char *end;
271 if (!xtables_strtoui(s, &end, &min, 0, UINT32_MAX))
272 xtables_param_act(XTF_BAD_VALUE, "conntrack", "--expires", s);
273 max = min;
274 if (*end == ':')
275 if (!xtables_strtoui(s, &end, &max, 0, UINT32_MAX))
276 xtables_param_act(XTF_BAD_VALUE, "conntrack", "--expires", s);
277 if (*end != '\0')
278 xtables_param_act(XTF_BAD_VALUE, "conntrack", "--expires", s);
280 if (min > max)
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;
298 switch (c) {
299 case '1':
300 xtables_check_inverse(optarg, &invert, &optind, 0);
302 parse_states(argv[optind-1], sinfo);
303 if (invert) {
304 sinfo->invflags |= XT_CONNTRACK_STATE;
306 sinfo->flags |= XT_CONNTRACK_STATE;
307 break;
309 case '2':
310 xtables_check_inverse(optarg, &invert, &optind, 0);
312 if(invert)
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;
329 break;
331 case '3':
332 xtables_check_inverse(optarg, &invert, &optind, 0);
334 if (invert)
335 sinfo->invflags |= XT_CONNTRACK_ORIGSRC;
337 xtables_ipparse_any(argv[optind-1], &addrs,
338 &sinfo->sipmsk[IP_CT_DIR_ORIGINAL],
339 &naddrs);
340 if(naddrs > 1)
341 xtables_error(PARAMETER_PROBLEM,
342 "multiple IP addresses not allowed");
344 if(naddrs == 1) {
345 sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip = addrs[0].s_addr;
348 sinfo->flags |= XT_CONNTRACK_ORIGSRC;
349 break;
351 case '4':
352 xtables_check_inverse(optarg, &invert, &optind, 0);
354 if (invert)
355 sinfo->invflags |= XT_CONNTRACK_ORIGDST;
357 xtables_ipparse_any(argv[optind-1], &addrs,
358 &sinfo->dipmsk[IP_CT_DIR_ORIGINAL],
359 &naddrs);
360 if(naddrs > 1)
361 xtables_error(PARAMETER_PROBLEM,
362 "multiple IP addresses not allowed");
364 if(naddrs == 1) {
365 sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip = addrs[0].s_addr;
368 sinfo->flags |= XT_CONNTRACK_ORIGDST;
369 break;
371 case '5':
372 xtables_check_inverse(optarg, &invert, &optind, 0);
374 if (invert)
375 sinfo->invflags |= XT_CONNTRACK_REPLSRC;
377 xtables_ipparse_any(argv[optind-1], &addrs,
378 &sinfo->sipmsk[IP_CT_DIR_REPLY],
379 &naddrs);
380 if(naddrs > 1)
381 xtables_error(PARAMETER_PROBLEM,
382 "multiple IP addresses not allowed");
384 if(naddrs == 1) {
385 sinfo->tuple[IP_CT_DIR_REPLY].src.ip = addrs[0].s_addr;
388 sinfo->flags |= XT_CONNTRACK_REPLSRC;
389 break;
391 case '6':
392 xtables_check_inverse(optarg, &invert, &optind, 0);
394 if (invert)
395 sinfo->invflags |= XT_CONNTRACK_REPLDST;
397 xtables_ipparse_any(argv[optind-1], &addrs,
398 &sinfo->dipmsk[IP_CT_DIR_REPLY],
399 &naddrs);
400 if(naddrs > 1)
401 xtables_error(PARAMETER_PROBLEM,
402 "multiple IP addresses not allowed");
404 if(naddrs == 1) {
405 sinfo->tuple[IP_CT_DIR_REPLY].dst.ip = addrs[0].s_addr;
408 sinfo->flags |= XT_CONNTRACK_REPLDST;
409 break;
411 case '7':
412 xtables_check_inverse(optarg, &invert, &optind, 0);
414 parse_statuses(argv[optind-1], sinfo);
415 if (invert) {
416 sinfo->invflags |= XT_CONNTRACK_STATUS;
418 sinfo->flags |= XT_CONNTRACK_STATUS;
419 break;
421 case '8':
422 xtables_check_inverse(optarg, &invert, &optind, 0);
424 parse_expires(argv[optind-1], sinfo);
425 if (invert) {
426 sinfo->invflags |= XT_CONNTRACK_EXPIRES;
428 sinfo->flags |= XT_CONNTRACK_EXPIRES;
429 break;
431 default:
432 return 0;
435 *flags = sinfo->flags;
436 return 1;
439 static int
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;
444 unsigned int port;
445 char *p;
447 switch (c) {
448 case '1': /* --ctstate */
449 conntrack_ps_states(info, optarg);
450 info->match_flags |= XT_CONNTRACK_STATE;
451 if (invert)
452 info->invert_flags |= XT_CONNTRACK_STATE;
453 break;
455 case '2': /* --ctproto */
456 /* Canonicalize into lower case */
457 for (p = optarg; *p != '\0'; ++p)
458 *p = tolower(*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;
466 if (invert)
467 info->invert_flags |= XT_CONNTRACK_PROTO;
468 break;
470 case '7': /* --ctstatus */
471 conntrack_ps_statuses(info, optarg);
472 info->match_flags |= XT_CONNTRACK_STATUS;
473 if (invert)
474 info->invert_flags |= XT_CONNTRACK_STATUS;
475 break;
477 case '8': /* --ctexpire */
478 conntrack_ps_expires(info, optarg);
479 info->match_flags |= XT_CONNTRACK_EXPIRES;
480 if (invert)
481 info->invert_flags |= XT_CONNTRACK_EXPIRES;
482 break;
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);
490 if (invert)
491 info->invert_flags |= XT_CONNTRACK_ORIGSRC_PORT;
492 break;
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);
500 if (invert)
501 info->invert_flags |= XT_CONNTRACK_ORIGDST_PORT;
502 break;
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);
510 if (invert)
511 info->invert_flags |= XT_CONNTRACK_REPLSRC_PORT;
512 break;
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);
520 if (invert)
521 info->invert_flags |= XT_CONNTRACK_REPLDST_PORT;
522 break;
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;
532 } else {
533 xtables_param_act(XTF_BAD_VALUE, "conntrack", "--ctdir", optarg);
535 break;
537 default:
538 return false;
541 *flags = info->match_flags;
542 return true;
545 static int
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;
553 switch (c) {
554 case '3': /* --ctorigsrc */
555 xtables_ipparse_any(optarg, &addr, &info->origsrc_mask.in,
556 &naddrs);
557 if (naddrs > 1)
558 xtables_error(PARAMETER_PROBLEM,
559 "multiple IP addresses not allowed");
560 if (naddrs == 1)
561 memcpy(&info->origsrc_addr.in, addr, sizeof(*addr));
562 info->match_flags |= XT_CONNTRACK_ORIGSRC;
563 if (invert)
564 info->invert_flags |= XT_CONNTRACK_ORIGSRC;
565 break;
567 case '4': /* --ctorigdst */
568 xtables_ipparse_any(optarg, &addr, &info->origdst_mask.in,
569 &naddrs);
570 if (naddrs > 1)
571 xtables_error(PARAMETER_PROBLEM,
572 "multiple IP addresses not allowed");
573 if (naddrs == 1)
574 memcpy(&info->origdst_addr.in, addr, sizeof(*addr));
575 info->match_flags |= XT_CONNTRACK_ORIGDST;
576 if (invert)
577 info->invert_flags |= XT_CONNTRACK_ORIGDST;
578 break;
580 case '5': /* --ctreplsrc */
581 xtables_ipparse_any(optarg, &addr, &info->replsrc_mask.in,
582 &naddrs);
583 if (naddrs > 1)
584 xtables_error(PARAMETER_PROBLEM,
585 "multiple IP addresses not allowed");
586 if (naddrs == 1)
587 memcpy(&info->replsrc_addr.in, addr, sizeof(*addr));
588 info->match_flags |= XT_CONNTRACK_REPLSRC;
589 if (invert)
590 info->invert_flags |= XT_CONNTRACK_REPLSRC;
591 break;
593 case '6': /* --ctrepldst */
594 xtables_ipparse_any(optarg, &addr, &info->repldst_mask.in,
595 &naddrs);
596 if (naddrs > 1)
597 xtables_error(PARAMETER_PROBLEM,
598 "multiple IP addresses not allowed");
599 if (naddrs == 1)
600 memcpy(&info->repldst_addr.in, addr, sizeof(*addr));
601 info->match_flags |= XT_CONNTRACK_REPLDST;
602 if (invert)
603 info->invert_flags |= XT_CONNTRACK_REPLDST;
604 break;
607 default:
608 return conntrack_mt_parse(c, argv, invert, flags, match);
611 *flags = info->match_flags;
612 return true;
615 static int
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;
623 switch (c) {
624 case '3': /* --ctorigsrc */
625 xtables_ip6parse_any(optarg, &addr,
626 &info->origsrc_mask.in6, &naddrs);
627 if (naddrs > 1)
628 xtables_error(PARAMETER_PROBLEM,
629 "multiple IP addresses not allowed");
630 if (naddrs == 1)
631 memcpy(&info->origsrc_addr.in6, addr, sizeof(*addr));
632 info->match_flags |= XT_CONNTRACK_ORIGSRC;
633 if (invert)
634 info->invert_flags |= XT_CONNTRACK_ORIGSRC;
635 break;
637 case '4': /* --ctorigdst */
638 xtables_ip6parse_any(optarg, &addr,
639 &info->origdst_mask.in6, &naddrs);
640 if (naddrs > 1)
641 xtables_error(PARAMETER_PROBLEM,
642 "multiple IP addresses not allowed");
643 if (naddrs == 1)
644 memcpy(&info->origdst_addr.in, addr, sizeof(*addr));
645 info->match_flags |= XT_CONNTRACK_ORIGDST;
646 if (invert)
647 info->invert_flags |= XT_CONNTRACK_ORIGDST;
648 break;
650 case '5': /* --ctreplsrc */
651 xtables_ip6parse_any(optarg, &addr,
652 &info->replsrc_mask.in6, &naddrs);
653 if (naddrs > 1)
654 xtables_error(PARAMETER_PROBLEM,
655 "multiple IP addresses not allowed");
656 if (naddrs == 1)
657 memcpy(&info->replsrc_addr.in, addr, sizeof(*addr));
658 info->match_flags |= XT_CONNTRACK_REPLSRC;
659 if (invert)
660 info->invert_flags |= XT_CONNTRACK_REPLSRC;
661 break;
663 case '6': /* --ctrepldst */
664 xtables_ip6parse_any(optarg, &addr,
665 &info->repldst_mask.in6, &naddrs);
666 if (naddrs > 1)
667 xtables_error(PARAMETER_PROBLEM,
668 "multiple IP addresses not allowed");
669 if (naddrs == 1)
670 memcpy(&info->repldst_addr.in, addr, sizeof(*addr));
671 info->match_flags |= XT_CONNTRACK_REPLDST;
672 if (invert)
673 info->invert_flags |= XT_CONNTRACK_REPLDST;
674 break;
677 default:
678 return conntrack_mt_parse(c, argv, invert, flags, match);
681 *flags = info->match_flags;
682 return true;
685 static void conntrack_mt_check(unsigned int flags)
687 if (flags == 0)
688 xtables_error(PARAMETER_PROBLEM, "conntrack: At least one option "
689 "is required");
692 static void
693 print_state(unsigned int statemask)
695 const char *sep = "";
697 if (statemask & XT_CONNTRACK_STATE_INVALID) {
698 printf("%sINVALID", sep);
699 sep = ",";
701 if (statemask & XT_CONNTRACK_STATE_BIT(IP_CT_NEW)) {
702 printf("%sNEW", sep);
703 sep = ",";
705 if (statemask & XT_CONNTRACK_STATE_BIT(IP_CT_RELATED)) {
706 printf("%sRELATED", sep);
707 sep = ",";
709 if (statemask & XT_CONNTRACK_STATE_BIT(IP_CT_ESTABLISHED)) {
710 printf("%sESTABLISHED", sep);
711 sep = ",";
713 if (statemask & XT_CONNTRACK_STATE_UNTRACKED) {
714 printf("%sUNTRACKED", sep);
715 sep = ",";
717 if (statemask & XT_CONNTRACK_STATE_SNAT) {
718 printf("%sSNAT", sep);
719 sep = ",";
721 if (statemask & XT_CONNTRACK_STATE_DNAT) {
722 printf("%sDNAT", sep);
723 sep = ",";
725 printf(" ");
728 static void
729 print_status(unsigned int statusmask)
731 const char *sep = "";
733 if (statusmask & IPS_EXPECTED) {
734 printf("%sEXPECTED", sep);
735 sep = ",";
737 if (statusmask & IPS_SEEN_REPLY) {
738 printf("%sSEEN_REPLY", sep);
739 sep = ",";
741 if (statusmask & IPS_ASSURED) {
742 printf("%sASSURED", sep);
743 sep = ",";
745 if (statusmask & IPS_CONFIRMED) {
746 printf("%sCONFIRMED", sep);
747 sep = ",";
749 if (statusmask == 0)
750 printf("%sNONE", sep);
751 printf(" ");
754 static void
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) {
761 printf("anywhere ");
762 return;
764 if (numeric)
765 printf("%s ", xtables_ipaddr_to_numeric(&addr->in));
766 else
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) {
771 printf("anywhere ");
772 return;
774 if (numeric)
775 printf("%s ", xtables_ip6addr_to_numeric(&addr->in6));
776 else
777 printf("%s ", xtables_ip6addr_to_anyname(&addr->in6));
781 static void
782 print_addr(const struct in_addr *addr, const struct in_addr *mask,
783 int inv, int numeric)
785 char buf[BUFSIZ];
787 if (inv)
788 printf("! ");
790 if (mask->s_addr == 0L && !numeric)
791 printf("%s ", "anywhere");
792 else {
793 if (numeric)
794 strcpy(buf, xtables_ipaddr_to_numeric(addr));
795 else
796 strcpy(buf, xtables_ipaddr_to_anyname(addr));
797 strcat(buf, xtables_ipmask_to_numeric(mask));
798 printf("%s ", buf);
802 static void
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)
809 printf("! ");
810 printf("%sctstate ", optpfx);
811 print_state(sinfo->statemask);
814 if(sinfo->flags & XT_CONNTRACK_PROTO) {
815 if (sinfo->invflags & XT_CONNTRACK_PROTO)
816 printf("! ");
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)
823 printf("! ");
824 printf("%sctorigsrc ", optpfx);
826 print_addr(
827 (struct in_addr *)&sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip,
828 &sinfo->sipmsk[IP_CT_DIR_ORIGINAL],
829 false,
830 numeric);
833 if(sinfo->flags & XT_CONNTRACK_ORIGDST) {
834 if (sinfo->invflags & XT_CONNTRACK_ORIGDST)
835 printf("! ");
836 printf("%sctorigdst ", optpfx);
838 print_addr(
839 (struct in_addr *)&sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip,
840 &sinfo->dipmsk[IP_CT_DIR_ORIGINAL],
841 false,
842 numeric);
845 if(sinfo->flags & XT_CONNTRACK_REPLSRC) {
846 if (sinfo->invflags & XT_CONNTRACK_REPLSRC)
847 printf("! ");
848 printf("%sctreplsrc ", optpfx);
850 print_addr(
851 (struct in_addr *)&sinfo->tuple[IP_CT_DIR_REPLY].src.ip,
852 &sinfo->sipmsk[IP_CT_DIR_REPLY],
853 false,
854 numeric);
857 if(sinfo->flags & XT_CONNTRACK_REPLDST) {
858 if (sinfo->invflags & XT_CONNTRACK_REPLDST)
859 printf("! ");
860 printf("%sctrepldst ", optpfx);
862 print_addr(
863 (struct in_addr *)&sinfo->tuple[IP_CT_DIR_REPLY].dst.ip,
864 &sinfo->dipmsk[IP_CT_DIR_REPLY],
865 false,
866 numeric);
869 if(sinfo->flags & XT_CONNTRACK_STATUS) {
870 if (sinfo->invflags & XT_CONNTRACK_STATUS)
871 printf("! ");
872 printf("%sctstatus ", optpfx);
873 print_status(sinfo->statusmask);
876 if(sinfo->flags & XT_CONNTRACK_EXPIRES) {
877 if (sinfo->invflags & XT_CONNTRACK_EXPIRES)
878 printf("! ");
879 printf("%sctexpire ", optpfx);
881 if (sinfo->expires_max == sinfo->expires_min)
882 printf("%lu ", sinfo->expires_min);
883 else
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);
890 else
891 printf("%sctdir ORIGINAL", optpfx);
896 static void
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)
902 printf("! ");
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)
909 printf("! ");
910 printf("%sctproto %u ", prefix, info->l4proto);
913 if (info->match_flags & XT_CONNTRACK_ORIGSRC) {
914 if (info->invert_flags & XT_CONNTRACK_ORIGSRC)
915 printf("! ");
916 printf("%sctorigsrc ", prefix);
917 conntrack_dump_addr(&info->origsrc_addr, &info->origsrc_mask,
918 family, numeric);
921 if (info->match_flags & XT_CONNTRACK_ORIGDST) {
922 if (info->invert_flags & XT_CONNTRACK_ORIGDST)
923 printf("! ");
924 printf("%sctorigdst ", prefix);
925 conntrack_dump_addr(&info->origdst_addr, &info->origdst_mask,
926 family, numeric);
929 if (info->match_flags & XT_CONNTRACK_REPLSRC) {
930 if (info->invert_flags & XT_CONNTRACK_REPLSRC)
931 printf("! ");
932 printf("%sctreplsrc ", prefix);
933 conntrack_dump_addr(&info->replsrc_addr, &info->replsrc_mask,
934 family, numeric);
937 if (info->match_flags & XT_CONNTRACK_REPLDST) {
938 if (info->invert_flags & XT_CONNTRACK_REPLDST)
939 printf("! ");
940 printf("%sctrepldst ", prefix);
941 conntrack_dump_addr(&info->repldst_addr, &info->repldst_mask,
942 family, numeric);
945 if (info->match_flags & XT_CONNTRACK_ORIGSRC_PORT) {
946 if (info->invert_flags & XT_CONNTRACK_ORIGSRC_PORT)
947 printf("! ");
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)
954 printf("! ");
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)
961 printf("! ");
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)
968 printf("! ");
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)
975 printf("! ");
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)
982 printf("! ");
983 printf("%sctexpire ", prefix);
985 if (info->expires_max == info->expires_min)
986 printf("%u ", (unsigned int)info->expires_min);
987 else
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);
995 else
996 printf("%sctdir ORIGINAL", prefix);
1000 static void conntrack_print(const void *ip, const struct xt_entry_match *match,
1001 int numeric)
1003 matchinfo_print(ip, match, numeric, "");
1006 static void
1007 conntrack_mt_print(const void *ip, const struct xt_entry_match *match,
1008 int numeric)
1010 conntrack_dump((const void *)match->data, "", NFPROTO_IPV4, numeric);
1013 static void
1014 conntrack_mt6_print(const void *ip, const struct xt_entry_match *match,
1015 int numeric)
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",
1040 .revision = 0,
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",
1055 .revision = 1,
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",
1070 .revision = 1,
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,
1082 void _init(void)
1084 xtables_register_match(&conntrack_match);
1085 xtables_register_match(&conntrack_mt_reg);
1086 xtables_register_match(&conntrack_mt6_reg);