libxt_conntrack.c revision 73866357e4a7a0fdc1b293bf8863fee2bd56da9e
1/* 2 * libxt_conntrack 3 * Shared library add-on to iptables for conntrack matching support. 4 * 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 <stddef.h> 16#include <stdio.h> 17#include <stdlib.h> 18#include <string.h> 19#include <xtables.h> 20#include <linux/netfilter.h> 21#include <linux/netfilter/xt_conntrack.h> 22#include <linux/netfilter/nf_conntrack_common.h> 23#include <arpa/inet.h> 24 25struct ip_conntrack_old_tuple { 26 struct { 27 __be32 ip; 28 union { 29 __u16 all; 30 } u; 31 } src; 32 33 struct { 34 __be32 ip; 35 union { 36 __u16 all; 37 } u; 38 39 /* The protocol. */ 40 __u16 protonum; 41 } dst; 42}; 43 44struct xt_conntrack_info { 45 unsigned int statemask, statusmask; 46 47 struct ip_conntrack_old_tuple tuple[IP_CT_DIR_MAX]; 48 struct in_addr sipmsk[IP_CT_DIR_MAX], dipmsk[IP_CT_DIR_MAX]; 49 50 unsigned long expires_min, expires_max; 51 52 /* Flags word */ 53 uint8_t flags; 54 /* Inverse flags */ 55 uint8_t invflags; 56}; 57 58static void conntrack_mt_help(void) 59{ 60 printf( 61"conntrack match options:\n" 62"[!] --ctstate {INVALID|ESTABLISHED|NEW|RELATED|UNTRACKED|SNAT|DNAT}[,...]\n" 63" State(s) to match\n" 64"[!] --ctproto proto Protocol to match; by number or name, e.g. \"tcp\"\n" 65"[!] --ctorigsrc address[/mask]\n" 66"[!] --ctorigdst address[/mask]\n" 67"[!] --ctreplsrc address[/mask]\n" 68"[!] --ctrepldst address[/mask]\n" 69" Original/Reply source/destination address\n" 70"[!] --ctorigsrcport port\n" 71"[!] --ctorigdstport port\n" 72"[!] --ctreplsrcport port\n" 73"[!] --ctrepldstport port\n" 74" TCP/UDP/SCTP orig./reply source/destination port\n" 75"[!] --ctstatus {NONE|EXPECTED|SEEN_REPLY|ASSURED|CONFIRMED}[,...]\n" 76" Status(es) to match\n" 77"[!] --ctexpire time[:time] Match remaining lifetime in seconds against\n" 78" value or range of values (inclusive)\n" 79" --ctdir {ORIGINAL|REPLY} Flow direction of packet\n"); 80} 81 82static const struct option conntrack_mt_opts_v0[] = { 83 {.name = "ctstate", .has_arg = true, .val = '1'}, 84 {.name = "ctproto", .has_arg = true, .val = '2'}, 85 {.name = "ctorigsrc", .has_arg = true, .val = '3'}, 86 {.name = "ctorigdst", .has_arg = true, .val = '4'}, 87 {.name = "ctreplsrc", .has_arg = true, .val = '5'}, 88 {.name = "ctrepldst", .has_arg = true, .val = '6'}, 89 {.name = "ctstatus", .has_arg = true, .val = '7'}, 90 {.name = "ctexpire", .has_arg = true, .val = '8'}, 91 XT_GETOPT_TABLEEND, 92}; 93 94static const struct option conntrack_mt_opts[] = { 95 {.name = "ctstate", .has_arg = true, .val = '1'}, 96 {.name = "ctproto", .has_arg = true, .val = '2'}, 97 {.name = "ctorigsrc", .has_arg = true, .val = '3'}, 98 {.name = "ctorigdst", .has_arg = true, .val = '4'}, 99 {.name = "ctreplsrc", .has_arg = true, .val = '5'}, 100 {.name = "ctrepldst", .has_arg = true, .val = '6'}, 101 {.name = "ctstatus", .has_arg = true, .val = '7'}, 102 {.name = "ctexpire", .has_arg = true, .val = '8'}, 103 {.name = "ctorigsrcport", .has_arg = true, .val = 'a'}, 104 {.name = "ctorigdstport", .has_arg = true, .val = 'b'}, 105 {.name = "ctreplsrcport", .has_arg = true, .val = 'c'}, 106 {.name = "ctrepldstport", .has_arg = true, .val = 'd'}, 107 {.name = "ctdir", .has_arg = true, .val = 'e'}, 108 {.name = NULL}, 109}; 110 111static int 112parse_state(const char *state, size_t len, struct xt_conntrack_info *sinfo) 113{ 114 if (strncasecmp(state, "INVALID", len) == 0) 115 sinfo->statemask |= XT_CONNTRACK_STATE_INVALID; 116 else if (strncasecmp(state, "NEW", len) == 0) 117 sinfo->statemask |= XT_CONNTRACK_STATE_BIT(IP_CT_NEW); 118 else if (strncasecmp(state, "ESTABLISHED", len) == 0) 119 sinfo->statemask |= XT_CONNTRACK_STATE_BIT(IP_CT_ESTABLISHED); 120 else if (strncasecmp(state, "RELATED", len) == 0) 121 sinfo->statemask |= XT_CONNTRACK_STATE_BIT(IP_CT_RELATED); 122 else if (strncasecmp(state, "UNTRACKED", len) == 0) 123 sinfo->statemask |= XT_CONNTRACK_STATE_UNTRACKED; 124 else if (strncasecmp(state, "SNAT", len) == 0) 125 sinfo->statemask |= XT_CONNTRACK_STATE_SNAT; 126 else if (strncasecmp(state, "DNAT", len) == 0) 127 sinfo->statemask |= XT_CONNTRACK_STATE_DNAT; 128 else 129 return 0; 130 return 1; 131} 132 133static void 134parse_states(const char *arg, struct xt_conntrack_info *sinfo) 135{ 136 const char *comma; 137 138 while ((comma = strchr(arg, ',')) != NULL) { 139 if (comma == arg || !parse_state(arg, comma-arg, sinfo)) 140 xtables_error(PARAMETER_PROBLEM, "Bad ctstate \"%s\"", arg); 141 arg = comma+1; 142 } 143 if (!*arg) 144 xtables_error(PARAMETER_PROBLEM, "\"--ctstate\" requires a list of " 145 "states with no spaces, e.g. " 146 "ESTABLISHED,RELATED"); 147 if (strlen(arg) == 0 || !parse_state(arg, strlen(arg), sinfo)) 148 xtables_error(PARAMETER_PROBLEM, "Bad ctstate \"%s\"", arg); 149} 150 151static bool 152conntrack_ps_state(struct xt_conntrack_mtinfo3 *info, const char *state, 153 size_t z) 154{ 155 if (strncasecmp(state, "INVALID", z) == 0) 156 info->state_mask |= XT_CONNTRACK_STATE_INVALID; 157 else if (strncasecmp(state, "NEW", z) == 0) 158 info->state_mask |= XT_CONNTRACK_STATE_BIT(IP_CT_NEW); 159 else if (strncasecmp(state, "ESTABLISHED", z) == 0) 160 info->state_mask |= XT_CONNTRACK_STATE_BIT(IP_CT_ESTABLISHED); 161 else if (strncasecmp(state, "RELATED", z) == 0) 162 info->state_mask |= XT_CONNTRACK_STATE_BIT(IP_CT_RELATED); 163 else if (strncasecmp(state, "UNTRACKED", z) == 0) 164 info->state_mask |= XT_CONNTRACK_STATE_UNTRACKED; 165 else if (strncasecmp(state, "SNAT", z) == 0) 166 info->state_mask |= XT_CONNTRACK_STATE_SNAT; 167 else if (strncasecmp(state, "DNAT", z) == 0) 168 info->state_mask |= XT_CONNTRACK_STATE_DNAT; 169 else 170 return false; 171 return true; 172} 173 174static void 175conntrack_ps_states(struct xt_conntrack_mtinfo3 *info, const char *arg) 176{ 177 const char *comma; 178 179 while ((comma = strchr(arg, ',')) != NULL) { 180 if (comma == arg || !conntrack_ps_state(info, arg, comma - arg)) 181 xtables_error(PARAMETER_PROBLEM, 182 "Bad ctstate \"%s\"", arg); 183 arg = comma + 1; 184 } 185 186 if (strlen(arg) == 0 || !conntrack_ps_state(info, arg, strlen(arg))) 187 xtables_error(PARAMETER_PROBLEM, "Bad ctstate \"%s\"", arg); 188} 189 190static int 191parse_status(const char *status, size_t len, struct xt_conntrack_info *sinfo) 192{ 193 if (strncasecmp(status, "NONE", len) == 0) 194 sinfo->statusmask |= 0; 195 else if (strncasecmp(status, "EXPECTED", len) == 0) 196 sinfo->statusmask |= IPS_EXPECTED; 197 else if (strncasecmp(status, "SEEN_REPLY", len) == 0) 198 sinfo->statusmask |= IPS_SEEN_REPLY; 199 else if (strncasecmp(status, "ASSURED", len) == 0) 200 sinfo->statusmask |= IPS_ASSURED; 201#ifdef IPS_CONFIRMED 202 else if (strncasecmp(status, "CONFIRMED", len) == 0) 203 sinfo->statusmask |= IPS_CONFIRMED; 204#endif 205 else 206 return 0; 207 return 1; 208} 209 210static void 211parse_statuses(const char *arg, struct xt_conntrack_info *sinfo) 212{ 213 const char *comma; 214 215 while ((comma = strchr(arg, ',')) != NULL) { 216 if (comma == arg || !parse_status(arg, comma-arg, sinfo)) 217 xtables_error(PARAMETER_PROBLEM, "Bad ctstatus \"%s\"", arg); 218 arg = comma+1; 219 } 220 221 if (strlen(arg) == 0 || !parse_status(arg, strlen(arg), sinfo)) 222 xtables_error(PARAMETER_PROBLEM, "Bad ctstatus \"%s\"", arg); 223} 224 225static bool 226conntrack_ps_status(struct xt_conntrack_mtinfo3 *info, const char *status, 227 size_t z) 228{ 229 if (strncasecmp(status, "NONE", z) == 0) 230 info->status_mask |= 0; 231 else if (strncasecmp(status, "EXPECTED", z) == 0) 232 info->status_mask |= IPS_EXPECTED; 233 else if (strncasecmp(status, "SEEN_REPLY", z) == 0) 234 info->status_mask |= IPS_SEEN_REPLY; 235 else if (strncasecmp(status, "ASSURED", z) == 0) 236 info->status_mask |= IPS_ASSURED; 237 else if (strncasecmp(status, "CONFIRMED", z) == 0) 238 info->status_mask |= IPS_CONFIRMED; 239 else 240 return false; 241 return true; 242} 243 244static void 245conntrack_ps_statuses(struct xt_conntrack_mtinfo3 *info, const char *arg) 246{ 247 const char *comma; 248 249 while ((comma = strchr(arg, ',')) != NULL) { 250 if (comma == arg || !conntrack_ps_status(info, arg, comma - arg)) 251 xtables_error(PARAMETER_PROBLEM, 252 "Bad ctstatus \"%s\"", arg); 253 arg = comma + 1; 254 } 255 256 if (strlen(arg) == 0 || !conntrack_ps_status(info, arg, strlen(arg))) 257 xtables_error(PARAMETER_PROBLEM, "Bad ctstatus \"%s\"", arg); 258} 259 260static unsigned long 261parse_expire(const char *s) 262{ 263 unsigned int len; 264 265 if (!xtables_strtoui(s, NULL, &len, 0, UINT32_MAX)) 266 xtables_error(PARAMETER_PROBLEM, "expire value invalid: \"%s\"\n", s); 267 else 268 return len; 269} 270 271/* If a single value is provided, min and max are both set to the value */ 272static void 273parse_expires(const char *s, struct xt_conntrack_info *sinfo) 274{ 275 char *buffer; 276 char *cp; 277 278 buffer = strdup(s); 279 if ((cp = strchr(buffer, ':')) == NULL) 280 sinfo->expires_min = sinfo->expires_max = 281 parse_expire(buffer); 282 else { 283 *cp = '\0'; 284 cp++; 285 286 sinfo->expires_min = buffer[0] ? parse_expire(buffer) : 0; 287 sinfo->expires_max = cp[0] 288 ? parse_expire(cp) 289 : (unsigned long)-1; 290 } 291 free(buffer); 292 293 if (sinfo->expires_min > sinfo->expires_max) 294 xtables_error(PARAMETER_PROBLEM, 295 "expire min. range value `%lu' greater than max. " 296 "range value `%lu'", sinfo->expires_min, sinfo->expires_max); 297} 298 299static void 300conntrack_ps_expires(struct xt_conntrack_mtinfo3 *info, const char *s) 301{ 302 unsigned int min, max; 303 char *end; 304 305 if (!xtables_strtoui(s, &end, &min, 0, UINT32_MAX)) 306 xtables_param_act(XTF_BAD_VALUE, "conntrack", "--expires", s); 307 max = min; 308 if (*end == ':') 309 if (!xtables_strtoui(end + 1, &end, &max, 0, UINT32_MAX)) 310 xtables_param_act(XTF_BAD_VALUE, "conntrack", "--expires", s); 311 if (*end != '\0') 312 xtables_param_act(XTF_BAD_VALUE, "conntrack", "--expires", s); 313 314 if (min > max) 315 xtables_error(PARAMETER_PROBLEM, 316 "expire min. range value \"%u\" greater than max. " 317 "range value \"%u\"", min, max); 318 319 info->expires_min = min; 320 info->expires_max = max; 321} 322 323static int conntrack_parse(int c, char **argv, int invert, unsigned int *flags, 324 const void *entry, struct xt_entry_match **match) 325{ 326 struct xt_conntrack_info *sinfo = (void *)(*match)->data; 327 char *protocol = NULL; 328 unsigned int naddrs = 0; 329 struct in_addr *addrs = NULL; 330 331 332 switch (c) { 333 case '1': 334 xtables_check_inverse(optarg, &invert, &optind, 0, argv); 335 336 parse_states(optarg, sinfo); 337 if (invert) { 338 sinfo->invflags |= XT_CONNTRACK_STATE; 339 } 340 sinfo->flags |= XT_CONNTRACK_STATE; 341 break; 342 343 case '2': 344 xtables_check_inverse(optarg, &invert, &optind, 0, argv); 345 346 if(invert) 347 sinfo->invflags |= XT_CONNTRACK_PROTO; 348 349 /* Canonicalize into lower case */ 350 for (protocol = optarg; *protocol; protocol++) 351 *protocol = tolower(*protocol); 352 353 protocol = optarg; 354 sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum = 355 xtables_parse_protocol(protocol); 356 357 if (sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum == 0 358 && (sinfo->invflags & XT_INV_PROTO)) 359 xtables_error(PARAMETER_PROBLEM, 360 "rule would never match protocol"); 361 362 sinfo->flags |= XT_CONNTRACK_PROTO; 363 break; 364 365 case '3': 366 xtables_check_inverse(optarg, &invert, &optind, 0, argv); 367 368 if (invert) 369 sinfo->invflags |= XT_CONNTRACK_ORIGSRC; 370 371 xtables_ipparse_any(optarg, &addrs, 372 &sinfo->sipmsk[IP_CT_DIR_ORIGINAL], 373 &naddrs); 374 if(naddrs > 1) 375 xtables_error(PARAMETER_PROBLEM, 376 "multiple IP addresses not allowed"); 377 378 if(naddrs == 1) { 379 sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip = addrs[0].s_addr; 380 } 381 382 sinfo->flags |= XT_CONNTRACK_ORIGSRC; 383 break; 384 385 case '4': 386 xtables_check_inverse(optarg, &invert, &optind, 0, argv); 387 388 if (invert) 389 sinfo->invflags |= XT_CONNTRACK_ORIGDST; 390 391 xtables_ipparse_any(optarg, &addrs, 392 &sinfo->dipmsk[IP_CT_DIR_ORIGINAL], 393 &naddrs); 394 if(naddrs > 1) 395 xtables_error(PARAMETER_PROBLEM, 396 "multiple IP addresses not allowed"); 397 398 if(naddrs == 1) { 399 sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip = addrs[0].s_addr; 400 } 401 402 sinfo->flags |= XT_CONNTRACK_ORIGDST; 403 break; 404 405 case '5': 406 xtables_check_inverse(optarg, &invert, &optind, 0, argv); 407 408 if (invert) 409 sinfo->invflags |= XT_CONNTRACK_REPLSRC; 410 411 xtables_ipparse_any(optarg, &addrs, 412 &sinfo->sipmsk[IP_CT_DIR_REPLY], 413 &naddrs); 414 if(naddrs > 1) 415 xtables_error(PARAMETER_PROBLEM, 416 "multiple IP addresses not allowed"); 417 418 if(naddrs == 1) { 419 sinfo->tuple[IP_CT_DIR_REPLY].src.ip = addrs[0].s_addr; 420 } 421 422 sinfo->flags |= XT_CONNTRACK_REPLSRC; 423 break; 424 425 case '6': 426 xtables_check_inverse(optarg, &invert, &optind, 0, argv); 427 428 if (invert) 429 sinfo->invflags |= XT_CONNTRACK_REPLDST; 430 431 xtables_ipparse_any(optarg, &addrs, 432 &sinfo->dipmsk[IP_CT_DIR_REPLY], 433 &naddrs); 434 if(naddrs > 1) 435 xtables_error(PARAMETER_PROBLEM, 436 "multiple IP addresses not allowed"); 437 438 if(naddrs == 1) { 439 sinfo->tuple[IP_CT_DIR_REPLY].dst.ip = addrs[0].s_addr; 440 } 441 442 sinfo->flags |= XT_CONNTRACK_REPLDST; 443 break; 444 445 case '7': 446 xtables_check_inverse(optarg, &invert, &optind, 0, argv); 447 448 parse_statuses(optarg, sinfo); 449 if (invert) { 450 sinfo->invflags |= XT_CONNTRACK_STATUS; 451 } 452 sinfo->flags |= XT_CONNTRACK_STATUS; 453 break; 454 455 case '8': 456 xtables_check_inverse(optarg, &invert, &optind, 0, argv); 457 458 parse_expires(optarg, sinfo); 459 if (invert) { 460 sinfo->invflags |= XT_CONNTRACK_EXPIRES; 461 } 462 sinfo->flags |= XT_CONNTRACK_EXPIRES; 463 break; 464 } 465 466 *flags = sinfo->flags; 467 return 1; 468} 469 470static void 471ct_parse_ports(const char *param, const char *str, 472 u_int16_t *port_low, u_int16_t *port_high) 473{ 474 unsigned int port; 475 char *buf, *cp; 476 477 buf = strdup(str); 478 cp = strchr(buf, ':'); 479 if (cp != NULL) 480 *cp = '\0'; 481 482 if (!xtables_strtoui(buf, NULL, &port, 0, UINT16_MAX)) 483 xtables_param_act(XTF_BAD_VALUE, "conntrack", param, buf); 484 485 if (port_high == NULL) { 486 /* revision 0-2 do not support ranges */ 487 if (cp != NULL) 488 xtables_error(PARAMETER_PROBLEM, "conntrack: " 489 "port ranges not supported"); 490 491 *port_low = htons(port); 492 } else { 493 *port_low = port; 494 495 if (cp != NULL) { 496 if (!xtables_strtoui(cp + 1, NULL, &port, 0, UINT16_MAX)) 497 xtables_param_act(XTF_BAD_VALUE, "conntrack", param, buf); 498 499 *port_high = port; 500 if (*port_low > *port_high) 501 xtables_error(PARAMETER_PROBLEM, 502 "invalid portrange (min > max)"); 503 } else 504 *port_high = port; 505 } 506 507 free(buf); 508} 509 510 511static int 512conntrack_mt_parse(int c, bool invert, unsigned int *flags, 513 struct xt_conntrack_mtinfo3 *info, bool v3) 514{ 515 char *p; 516 517 switch (c) { 518 case '1': /* --ctstate */ 519 conntrack_ps_states(info, optarg); 520 info->match_flags |= XT_CONNTRACK_STATE; 521 if (invert) 522 info->invert_flags |= XT_CONNTRACK_STATE; 523 break; 524 525 case '2': /* --ctproto */ 526 /* Canonicalize into lower case */ 527 for (p = optarg; *p != '\0'; ++p) 528 *p = tolower(*p); 529 info->l4proto = xtables_parse_protocol(optarg); 530 531 if (info->l4proto == 0 && (info->invert_flags & XT_INV_PROTO)) 532 xtables_error(PARAMETER_PROBLEM, "conntrack: rule would " 533 "never match protocol"); 534 535 info->match_flags |= XT_CONNTRACK_PROTO; 536 if (invert) 537 info->invert_flags |= XT_CONNTRACK_PROTO; 538 break; 539 540 case '7': /* --ctstatus */ 541 conntrack_ps_statuses(info, optarg); 542 info->match_flags |= XT_CONNTRACK_STATUS; 543 if (invert) 544 info->invert_flags |= XT_CONNTRACK_STATUS; 545 break; 546 547 case '8': /* --ctexpire */ 548 conntrack_ps_expires(info, optarg); 549 info->match_flags |= XT_CONNTRACK_EXPIRES; 550 if (invert) 551 info->invert_flags |= XT_CONNTRACK_EXPIRES; 552 break; 553 554 case 'a': /* --ctorigsrcport */ 555 ct_parse_ports("--ctorigsrcport", optarg, 556 &info->origsrc_port, 557 v3 ? &info->origsrc_port_high : NULL); 558 559 info->match_flags |= XT_CONNTRACK_ORIGSRC_PORT; 560 if (invert) 561 info->invert_flags |= XT_CONNTRACK_ORIGSRC_PORT; 562 break; 563 564 case 'b': /* --ctorigdstport */ 565 ct_parse_ports("--ctorigdstport", optarg, 566 &info->origdst_port, 567 v3 ? &info->origdst_port_high : NULL); 568 569 info->match_flags |= XT_CONNTRACK_ORIGDST_PORT; 570 if (invert) 571 info->invert_flags |= XT_CONNTRACK_ORIGDST_PORT; 572 break; 573 574 case 'c': /* --ctreplsrcport */ 575 ct_parse_ports("--ctreplsrcport", optarg, 576 &info->replsrc_port, 577 v3 ? &info->replsrc_port_high : NULL); 578 579 info->match_flags |= XT_CONNTRACK_REPLSRC_PORT; 580 if (invert) 581 info->invert_flags |= XT_CONNTRACK_REPLSRC_PORT; 582 break; 583 584 case 'd': /* --ctrepldstport */ 585 ct_parse_ports("--ctrepldstport", optarg, 586 &info->repldst_port, 587 v3 ? &info->repldst_port_high : NULL); 588 589 info->match_flags |= XT_CONNTRACK_REPLDST_PORT; 590 if (invert) 591 info->invert_flags |= XT_CONNTRACK_REPLDST_PORT; 592 break; 593 594 case 'e': /* --ctdir */ 595 xtables_param_act(XTF_NO_INVERT, "conntrack", "--ctdir", invert); 596 if (strcasecmp(optarg, "ORIGINAL") == 0) { 597 info->match_flags |= XT_CONNTRACK_DIRECTION; 598 info->invert_flags &= ~XT_CONNTRACK_DIRECTION; 599 } else if (strcasecmp(optarg, "REPLY") == 0) { 600 info->match_flags |= XT_CONNTRACK_DIRECTION; 601 info->invert_flags |= XT_CONNTRACK_DIRECTION; 602 } else { 603 xtables_param_act(XTF_BAD_VALUE, "conntrack", "--ctdir", optarg); 604 } 605 break; 606 } 607 608 *flags = info->match_flags; 609 return true; 610} 611 612static int 613conntrack_mt4_parse(int c, bool invert, unsigned int *flags, 614 struct xt_conntrack_mtinfo3 *info, bool v3) 615{ 616 struct in_addr *addr = NULL; 617 unsigned int naddrs = 0; 618 619 switch (c) { 620 case '3': /* --ctorigsrc */ 621 xtables_ipparse_any(optarg, &addr, &info->origsrc_mask.in, 622 &naddrs); 623 if (naddrs > 1) 624 xtables_error(PARAMETER_PROBLEM, 625 "multiple IP addresses not allowed"); 626 if (naddrs == 1) 627 memcpy(&info->origsrc_addr.in, addr, sizeof(*addr)); 628 info->match_flags |= XT_CONNTRACK_ORIGSRC; 629 if (invert) 630 info->invert_flags |= XT_CONNTRACK_ORIGSRC; 631 break; 632 633 case '4': /* --ctorigdst */ 634 xtables_ipparse_any(optarg, &addr, &info->origdst_mask.in, 635 &naddrs); 636 if (naddrs > 1) 637 xtables_error(PARAMETER_PROBLEM, 638 "multiple IP addresses not allowed"); 639 if (naddrs == 1) 640 memcpy(&info->origdst_addr.in, addr, sizeof(*addr)); 641 info->match_flags |= XT_CONNTRACK_ORIGDST; 642 if (invert) 643 info->invert_flags |= XT_CONNTRACK_ORIGDST; 644 break; 645 646 case '5': /* --ctreplsrc */ 647 xtables_ipparse_any(optarg, &addr, &info->replsrc_mask.in, 648 &naddrs); 649 if (naddrs > 1) 650 xtables_error(PARAMETER_PROBLEM, 651 "multiple IP addresses not allowed"); 652 if (naddrs == 1) 653 memcpy(&info->replsrc_addr.in, addr, sizeof(*addr)); 654 info->match_flags |= XT_CONNTRACK_REPLSRC; 655 if (invert) 656 info->invert_flags |= XT_CONNTRACK_REPLSRC; 657 break; 658 659 case '6': /* --ctrepldst */ 660 xtables_ipparse_any(optarg, &addr, &info->repldst_mask.in, 661 &naddrs); 662 if (naddrs > 1) 663 xtables_error(PARAMETER_PROBLEM, 664 "multiple IP addresses not allowed"); 665 if (naddrs == 1) 666 memcpy(&info->repldst_addr.in, addr, sizeof(*addr)); 667 info->match_flags |= XT_CONNTRACK_REPLDST; 668 if (invert) 669 info->invert_flags |= XT_CONNTRACK_REPLDST; 670 break; 671 672 673 default: 674 return conntrack_mt_parse(c, invert, flags, info, v3); 675 } 676 677 *flags = info->match_flags; 678 return true; 679} 680 681static int 682conntrack_mt6_parse(int c, bool invert, unsigned int *flags, 683 struct xt_conntrack_mtinfo3 *info, bool v3) 684{ 685 struct in6_addr *addr = NULL; 686 unsigned int naddrs = 0; 687 688 switch (c) { 689 case '3': /* --ctorigsrc */ 690 xtables_ip6parse_any(optarg, &addr, 691 &info->origsrc_mask.in6, &naddrs); 692 if (naddrs > 1) 693 xtables_error(PARAMETER_PROBLEM, 694 "multiple IP addresses not allowed"); 695 if (naddrs == 1) 696 memcpy(&info->origsrc_addr.in6, addr, sizeof(*addr)); 697 info->match_flags |= XT_CONNTRACK_ORIGSRC; 698 if (invert) 699 info->invert_flags |= XT_CONNTRACK_ORIGSRC; 700 break; 701 702 case '4': /* --ctorigdst */ 703 xtables_ip6parse_any(optarg, &addr, 704 &info->origdst_mask.in6, &naddrs); 705 if (naddrs > 1) 706 xtables_error(PARAMETER_PROBLEM, 707 "multiple IP addresses not allowed"); 708 if (naddrs == 1) 709 memcpy(&info->origdst_addr.in, addr, sizeof(*addr)); 710 info->match_flags |= XT_CONNTRACK_ORIGDST; 711 if (invert) 712 info->invert_flags |= XT_CONNTRACK_ORIGDST; 713 break; 714 715 case '5': /* --ctreplsrc */ 716 xtables_ip6parse_any(optarg, &addr, 717 &info->replsrc_mask.in6, &naddrs); 718 if (naddrs > 1) 719 xtables_error(PARAMETER_PROBLEM, 720 "multiple IP addresses not allowed"); 721 if (naddrs == 1) 722 memcpy(&info->replsrc_addr.in, addr, sizeof(*addr)); 723 info->match_flags |= XT_CONNTRACK_REPLSRC; 724 if (invert) 725 info->invert_flags |= XT_CONNTRACK_REPLSRC; 726 break; 727 728 case '6': /* --ctrepldst */ 729 xtables_ip6parse_any(optarg, &addr, 730 &info->repldst_mask.in6, &naddrs); 731 if (naddrs > 1) 732 xtables_error(PARAMETER_PROBLEM, 733 "multiple IP addresses not allowed"); 734 if (naddrs == 1) 735 memcpy(&info->repldst_addr.in, addr, sizeof(*addr)); 736 info->match_flags |= XT_CONNTRACK_REPLDST; 737 if (invert) 738 info->invert_flags |= XT_CONNTRACK_REPLDST; 739 break; 740 741 742 default: 743 return conntrack_mt_parse(c, invert, flags, info, v3); 744 } 745 746 *flags = info->match_flags; 747 return true; 748} 749 750#define cinfo_transform(r, l) \ 751 do { \ 752 memcpy((r), (l), offsetof(typeof(*(l)), state_mask)); \ 753 (r)->state_mask = (l)->state_mask; \ 754 (r)->status_mask = (l)->status_mask; \ 755 } while (false); 756 757static int 758conntrack1_mt4_parse(int c, char **argv, int invert, unsigned int *flags, 759 const void *entry, struct xt_entry_match **match) 760{ 761 struct xt_conntrack_mtinfo1 *info = (void *)(*match)->data; 762 struct xt_conntrack_mtinfo3 up; 763 764 cinfo_transform(&up, info); 765 if (!conntrack_mt4_parse(c, invert, flags, &up, false)) 766 return false; 767 cinfo_transform(info, &up); 768 return true; 769} 770 771static int 772conntrack1_mt6_parse(int c, char **argv, int invert, unsigned int *flags, 773 const void *entry, struct xt_entry_match **match) 774{ 775 struct xt_conntrack_mtinfo1 *info = (void *)(*match)->data; 776 struct xt_conntrack_mtinfo3 up; 777 778 cinfo_transform(&up, info); 779 if (!conntrack_mt6_parse(c, invert, flags, &up, false)) 780 return false; 781 cinfo_transform(info, &up); 782 return true; 783} 784 785static int 786conntrack2_mt4_parse(int c, char **argv, int invert, unsigned int *flags, 787 const void *entry, struct xt_entry_match **match) 788{ 789 return conntrack_mt4_parse(c, invert, flags, (void *)(*match)->data, false); 790} 791 792static int 793conntrack2_mt6_parse(int c, char **argv, int invert, unsigned int *flags, 794 const void *entry, struct xt_entry_match **match) 795{ 796 return conntrack_mt6_parse(c, invert, flags, (void *)(*match)->data, false); 797} 798 799static int 800conntrack3_mt4_parse(int c, char **argv, int invert, unsigned int *flags, 801 const void *entry, struct xt_entry_match **match) 802{ 803 return conntrack_mt4_parse(c, invert, flags, (void *)(*match)->data, true); 804} 805 806static int 807conntrack3_mt6_parse(int c, char **argv, int invert, unsigned int *flags, 808 const void *entry, struct xt_entry_match **match) 809{ 810 return conntrack_mt6_parse(c, invert, flags, (void *)(*match)->data, true); 811} 812 813static void conntrack_mt_check(unsigned int flags) 814{ 815 if (flags == 0) 816 xtables_error(PARAMETER_PROBLEM, "conntrack: At least one option " 817 "is required"); 818} 819 820static void 821print_state(unsigned int statemask) 822{ 823 const char *sep = " "; 824 825 if (statemask & XT_CONNTRACK_STATE_INVALID) { 826 printf("%sINVALID", sep); 827 sep = ","; 828 } 829 if (statemask & XT_CONNTRACK_STATE_BIT(IP_CT_NEW)) { 830 printf("%sNEW", sep); 831 sep = ","; 832 } 833 if (statemask & XT_CONNTRACK_STATE_BIT(IP_CT_RELATED)) { 834 printf("%sRELATED", sep); 835 sep = ","; 836 } 837 if (statemask & XT_CONNTRACK_STATE_BIT(IP_CT_ESTABLISHED)) { 838 printf("%sESTABLISHED", sep); 839 sep = ","; 840 } 841 if (statemask & XT_CONNTRACK_STATE_UNTRACKED) { 842 printf("%sUNTRACKED", sep); 843 sep = ","; 844 } 845 if (statemask & XT_CONNTRACK_STATE_SNAT) { 846 printf("%sSNAT", sep); 847 sep = ","; 848 } 849 if (statemask & XT_CONNTRACK_STATE_DNAT) { 850 printf("%sDNAT", sep); 851 sep = ","; 852 } 853} 854 855static void 856print_status(unsigned int statusmask) 857{ 858 const char *sep = " "; 859 860 if (statusmask & IPS_EXPECTED) { 861 printf("%sEXPECTED", sep); 862 sep = ","; 863 } 864 if (statusmask & IPS_SEEN_REPLY) { 865 printf("%sSEEN_REPLY", sep); 866 sep = ","; 867 } 868 if (statusmask & IPS_ASSURED) { 869 printf("%sASSURED", sep); 870 sep = ","; 871 } 872 if (statusmask & IPS_CONFIRMED) { 873 printf("%sCONFIRMED", sep); 874 sep = ","; 875 } 876 if (statusmask == 0) 877 printf("%sNONE", sep); 878} 879 880static void 881conntrack_dump_addr(const union nf_inet_addr *addr, 882 const union nf_inet_addr *mask, 883 unsigned int family, bool numeric) 884{ 885 if (family == NFPROTO_IPV4) { 886 if (!numeric && addr->ip == 0) { 887 printf(" anywhere"); 888 return; 889 } 890 if (numeric) 891 printf(" %s%s", 892 xtables_ipaddr_to_numeric(&addr->in), 893 xtables_ipmask_to_numeric(&mask->in)); 894 else 895 printf(" %s%s", 896 xtables_ipaddr_to_anyname(&addr->in), 897 xtables_ipmask_to_numeric(&mask->in)); 898 } else if (family == NFPROTO_IPV6) { 899 if (!numeric && addr->ip6[0] == 0 && addr->ip6[1] == 0 && 900 addr->ip6[2] == 0 && addr->ip6[3] == 0) { 901 printf(" anywhere"); 902 return; 903 } 904 if (numeric) 905 printf(" %s%s", 906 xtables_ip6addr_to_numeric(&addr->in6), 907 xtables_ip6mask_to_numeric(&mask->in6)); 908 else 909 printf(" %s%s", 910 xtables_ip6addr_to_anyname(&addr->in6), 911 xtables_ip6mask_to_numeric(&mask->in6)); 912 } 913} 914 915static void 916print_addr(const struct in_addr *addr, const struct in_addr *mask, 917 int inv, int numeric) 918{ 919 char buf[BUFSIZ]; 920 921 if (inv) 922 printf(" !"); 923 924 if (mask->s_addr == 0L && !numeric) 925 printf(" %s", "anywhere"); 926 else { 927 if (numeric) 928 strcpy(buf, xtables_ipaddr_to_numeric(addr)); 929 else 930 strcpy(buf, xtables_ipaddr_to_anyname(addr)); 931 strcat(buf, xtables_ipmask_to_numeric(mask)); 932 printf(" %s", buf); 933 } 934} 935 936static void 937matchinfo_print(const void *ip, const struct xt_entry_match *match, int numeric, const char *optpfx) 938{ 939 const struct xt_conntrack_info *sinfo = (const void *)match->data; 940 941 if(sinfo->flags & XT_CONNTRACK_STATE) { 942 if (sinfo->invflags & XT_CONNTRACK_STATE) 943 printf(" !"); 944 printf(" %sctstate", optpfx); 945 print_state(sinfo->statemask); 946 } 947 948 if(sinfo->flags & XT_CONNTRACK_PROTO) { 949 if (sinfo->invflags & XT_CONNTRACK_PROTO) 950 printf(" !"); 951 printf(" %sctproto", optpfx); 952 printf(" %u", sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum); 953 } 954 955 if(sinfo->flags & XT_CONNTRACK_ORIGSRC) { 956 if (sinfo->invflags & XT_CONNTRACK_ORIGSRC) 957 printf(" !"); 958 printf(" %sctorigsrc", optpfx); 959 960 print_addr( 961 (struct in_addr *)&sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip, 962 &sinfo->sipmsk[IP_CT_DIR_ORIGINAL], 963 false, 964 numeric); 965 } 966 967 if(sinfo->flags & XT_CONNTRACK_ORIGDST) { 968 if (sinfo->invflags & XT_CONNTRACK_ORIGDST) 969 printf(" !"); 970 printf(" %sctorigdst", optpfx); 971 972 print_addr( 973 (struct in_addr *)&sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip, 974 &sinfo->dipmsk[IP_CT_DIR_ORIGINAL], 975 false, 976 numeric); 977 } 978 979 if(sinfo->flags & XT_CONNTRACK_REPLSRC) { 980 if (sinfo->invflags & XT_CONNTRACK_REPLSRC) 981 printf(" !"); 982 printf(" %sctreplsrc", optpfx); 983 984 print_addr( 985 (struct in_addr *)&sinfo->tuple[IP_CT_DIR_REPLY].src.ip, 986 &sinfo->sipmsk[IP_CT_DIR_REPLY], 987 false, 988 numeric); 989 } 990 991 if(sinfo->flags & XT_CONNTRACK_REPLDST) { 992 if (sinfo->invflags & XT_CONNTRACK_REPLDST) 993 printf(" !"); 994 printf(" %sctrepldst", optpfx); 995 996 print_addr( 997 (struct in_addr *)&sinfo->tuple[IP_CT_DIR_REPLY].dst.ip, 998 &sinfo->dipmsk[IP_CT_DIR_REPLY], 999 false, 1000 numeric); 1001 } 1002 1003 if(sinfo->flags & XT_CONNTRACK_STATUS) { 1004 if (sinfo->invflags & XT_CONNTRACK_STATUS) 1005 printf(" !"); 1006 printf(" %sctstatus", optpfx); 1007 print_status(sinfo->statusmask); 1008 } 1009 1010 if(sinfo->flags & XT_CONNTRACK_EXPIRES) { 1011 if (sinfo->invflags & XT_CONNTRACK_EXPIRES) 1012 printf(" !"); 1013 printf(" %sctexpire ", optpfx); 1014 1015 if (sinfo->expires_max == sinfo->expires_min) 1016 printf("%lu", sinfo->expires_min); 1017 else 1018 printf("%lu:%lu", sinfo->expires_min, sinfo->expires_max); 1019 } 1020 1021 if (sinfo->flags & XT_CONNTRACK_DIRECTION) { 1022 if (sinfo->invflags & XT_CONNTRACK_DIRECTION) 1023 printf(" %sctdir REPLY", optpfx); 1024 else 1025 printf(" %sctdir ORIGINAL", optpfx); 1026 } 1027 1028} 1029 1030static void 1031conntrack_dump_ports(const char *prefix, const char *opt, 1032 u_int16_t port_low, u_int16_t port_high) 1033{ 1034 if (port_high == 0 || port_low == port_high) 1035 printf(" %s%s %u", prefix, opt, port_low); 1036 else 1037 printf(" %s%s %u:%u", prefix, opt, port_low, port_high); 1038} 1039 1040static void 1041conntrack_dump(const struct xt_conntrack_mtinfo3 *info, const char *prefix, 1042 unsigned int family, bool numeric, bool v3) 1043{ 1044 if (info->match_flags & XT_CONNTRACK_STATE) { 1045 if (info->invert_flags & XT_CONNTRACK_STATE) 1046 printf(" !"); 1047 printf(" %sctstate", prefix); 1048 print_state(info->state_mask); 1049 } 1050 1051 if (info->match_flags & XT_CONNTRACK_PROTO) { 1052 if (info->invert_flags & XT_CONNTRACK_PROTO) 1053 printf(" !"); 1054 printf(" %sctproto %u", prefix, info->l4proto); 1055 } 1056 1057 if (info->match_flags & XT_CONNTRACK_ORIGSRC) { 1058 if (info->invert_flags & XT_CONNTRACK_ORIGSRC) 1059 printf(" !"); 1060 printf(" %sctorigsrc", prefix); 1061 conntrack_dump_addr(&info->origsrc_addr, &info->origsrc_mask, 1062 family, numeric); 1063 } 1064 1065 if (info->match_flags & XT_CONNTRACK_ORIGDST) { 1066 if (info->invert_flags & XT_CONNTRACK_ORIGDST) 1067 printf(" !"); 1068 printf(" %sctorigdst", prefix); 1069 conntrack_dump_addr(&info->origdst_addr, &info->origdst_mask, 1070 family, numeric); 1071 } 1072 1073 if (info->match_flags & XT_CONNTRACK_REPLSRC) { 1074 if (info->invert_flags & XT_CONNTRACK_REPLSRC) 1075 printf(" !"); 1076 printf(" %sctreplsrc", prefix); 1077 conntrack_dump_addr(&info->replsrc_addr, &info->replsrc_mask, 1078 family, numeric); 1079 } 1080 1081 if (info->match_flags & XT_CONNTRACK_REPLDST) { 1082 if (info->invert_flags & XT_CONNTRACK_REPLDST) 1083 printf(" !"); 1084 printf(" %sctrepldst", prefix); 1085 conntrack_dump_addr(&info->repldst_addr, &info->repldst_mask, 1086 family, numeric); 1087 } 1088 1089 if (info->match_flags & XT_CONNTRACK_ORIGSRC_PORT) { 1090 if (info->invert_flags & XT_CONNTRACK_ORIGSRC_PORT) 1091 printf(" !"); 1092 conntrack_dump_ports(prefix, "ctorigsrcport", 1093 v3 ? info->origsrc_port : ntohs(info->origsrc_port), 1094 v3 ? info->origsrc_port_high : 0); 1095 } 1096 1097 if (info->match_flags & XT_CONNTRACK_ORIGDST_PORT) { 1098 if (info->invert_flags & XT_CONNTRACK_ORIGDST_PORT) 1099 printf(" !"); 1100 conntrack_dump_ports(prefix, "ctorigdstport", 1101 v3 ? info->origdst_port : ntohs(info->origdst_port), 1102 v3 ? info->origdst_port_high : 0); 1103 } 1104 1105 if (info->match_flags & XT_CONNTRACK_REPLSRC_PORT) { 1106 if (info->invert_flags & XT_CONNTRACK_REPLSRC_PORT) 1107 printf(" !"); 1108 conntrack_dump_ports(prefix, "ctreplsrcport", 1109 v3 ? info->replsrc_port : ntohs(info->replsrc_port), 1110 v3 ? info->replsrc_port_high : 0); 1111 } 1112 1113 if (info->match_flags & XT_CONNTRACK_REPLDST_PORT) { 1114 if (info->invert_flags & XT_CONNTRACK_REPLDST_PORT) 1115 printf(" !"); 1116 conntrack_dump_ports(prefix, "ctrepldstport", 1117 v3 ? info->repldst_port : ntohs(info->repldst_port), 1118 v3 ? info->repldst_port_high : 0); 1119 } 1120 1121 if (info->match_flags & XT_CONNTRACK_STATUS) { 1122 if (info->invert_flags & XT_CONNTRACK_STATUS) 1123 printf(" !"); 1124 printf(" %sctstatus", prefix); 1125 print_status(info->status_mask); 1126 } 1127 1128 if (info->match_flags & XT_CONNTRACK_EXPIRES) { 1129 if (info->invert_flags & XT_CONNTRACK_EXPIRES) 1130 printf(" !"); 1131 printf(" %sctexpire ", prefix); 1132 1133 if (info->expires_max == info->expires_min) 1134 printf("%u", (unsigned int)info->expires_min); 1135 else 1136 printf("%u:%u", (unsigned int)info->expires_min, 1137 (unsigned int)info->expires_max); 1138 } 1139 1140 if (info->match_flags & XT_CONNTRACK_DIRECTION) { 1141 if (info->invert_flags & XT_CONNTRACK_DIRECTION) 1142 printf(" %sctdir REPLY", prefix); 1143 else 1144 printf(" %sctdir ORIGINAL", prefix); 1145 } 1146} 1147 1148static void conntrack_print(const void *ip, const struct xt_entry_match *match, 1149 int numeric) 1150{ 1151 matchinfo_print(ip, match, numeric, ""); 1152} 1153 1154static void 1155conntrack1_mt4_print(const void *ip, const struct xt_entry_match *match, 1156 int numeric) 1157{ 1158 const struct xt_conntrack_mtinfo1 *info = (void *)match->data; 1159 struct xt_conntrack_mtinfo3 up; 1160 1161 cinfo_transform(&up, info); 1162 conntrack_dump(&up, "", NFPROTO_IPV4, numeric, false); 1163} 1164 1165static void 1166conntrack1_mt6_print(const void *ip, const struct xt_entry_match *match, 1167 int numeric) 1168{ 1169 const struct xt_conntrack_mtinfo1 *info = (void *)match->data; 1170 struct xt_conntrack_mtinfo3 up; 1171 1172 cinfo_transform(&up, info); 1173 conntrack_dump(&up, "", NFPROTO_IPV6, numeric, false); 1174} 1175 1176static void 1177conntrack2_mt_print(const void *ip, const struct xt_entry_match *match, 1178 int numeric) 1179{ 1180 conntrack_dump((const void *)match->data, "", NFPROTO_IPV4, numeric, false); 1181} 1182 1183static void 1184conntrack2_mt6_print(const void *ip, const struct xt_entry_match *match, 1185 int numeric) 1186{ 1187 conntrack_dump((const void *)match->data, "", NFPROTO_IPV6, numeric, false); 1188} 1189 1190static void 1191conntrack3_mt_print(const void *ip, const struct xt_entry_match *match, 1192 int numeric) 1193{ 1194 conntrack_dump((const void *)match->data, "", NFPROTO_IPV4, numeric, true); 1195} 1196 1197static void 1198conntrack3_mt6_print(const void *ip, const struct xt_entry_match *match, 1199 int numeric) 1200{ 1201 conntrack_dump((const void *)match->data, "", NFPROTO_IPV6, numeric, true); 1202} 1203 1204static void conntrack_save(const void *ip, const struct xt_entry_match *match) 1205{ 1206 matchinfo_print(ip, match, 1, "--"); 1207} 1208 1209static void conntrack3_mt_save(const void *ip, 1210 const struct xt_entry_match *match) 1211{ 1212 conntrack_dump((const void *)match->data, "--", NFPROTO_IPV4, true, true); 1213} 1214 1215static void conntrack3_mt6_save(const void *ip, 1216 const struct xt_entry_match *match) 1217{ 1218 conntrack_dump((const void *)match->data, "--", NFPROTO_IPV6, true, true); 1219} 1220 1221static void conntrack2_mt_save(const void *ip, 1222 const struct xt_entry_match *match) 1223{ 1224 conntrack_dump((const void *)match->data, "--", NFPROTO_IPV4, true, false); 1225} 1226 1227static void conntrack2_mt6_save(const void *ip, 1228 const struct xt_entry_match *match) 1229{ 1230 conntrack_dump((const void *)match->data, "--", NFPROTO_IPV6, true, false); 1231} 1232 1233static void 1234conntrack1_mt4_save(const void *ip, const struct xt_entry_match *match) 1235{ 1236 const struct xt_conntrack_mtinfo1 *info = (void *)match->data; 1237 struct xt_conntrack_mtinfo3 up; 1238 1239 cinfo_transform(&up, info); 1240 conntrack_dump(&up, "--", NFPROTO_IPV4, true, false); 1241} 1242 1243static void 1244conntrack1_mt6_save(const void *ip, const struct xt_entry_match *match) 1245{ 1246 const struct xt_conntrack_mtinfo1 *info = (void *)match->data; 1247 struct xt_conntrack_mtinfo3 up; 1248 1249 cinfo_transform(&up, info); 1250 conntrack_dump(&up, "--", NFPROTO_IPV6, true, false); 1251} 1252 1253static struct xtables_match conntrack_mt_reg[] = { 1254 { 1255 .version = XTABLES_VERSION, 1256 .name = "conntrack", 1257 .revision = 0, 1258 .family = NFPROTO_IPV4, 1259 .size = XT_ALIGN(sizeof(struct xt_conntrack_info)), 1260 .userspacesize = XT_ALIGN(sizeof(struct xt_conntrack_info)), 1261 .help = conntrack_mt_help, 1262 .parse = conntrack_parse, 1263 .final_check = conntrack_mt_check, 1264 .print = conntrack_print, 1265 .save = conntrack_save, 1266 .extra_opts = conntrack_mt_opts_v0, 1267 }, 1268 { 1269 .version = XTABLES_VERSION, 1270 .name = "conntrack", 1271 .revision = 1, 1272 .family = NFPROTO_IPV4, 1273 .size = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo1)), 1274 .userspacesize = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo1)), 1275 .help = conntrack_mt_help, 1276 .parse = conntrack1_mt4_parse, 1277 .final_check = conntrack_mt_check, 1278 .print = conntrack1_mt4_print, 1279 .save = conntrack1_mt4_save, 1280 .extra_opts = conntrack_mt_opts, 1281 }, 1282 { 1283 .version = XTABLES_VERSION, 1284 .name = "conntrack", 1285 .revision = 1, 1286 .family = NFPROTO_IPV6, 1287 .size = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo1)), 1288 .userspacesize = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo1)), 1289 .help = conntrack_mt_help, 1290 .parse = conntrack1_mt6_parse, 1291 .final_check = conntrack_mt_check, 1292 .print = conntrack1_mt6_print, 1293 .save = conntrack1_mt6_save, 1294 .extra_opts = conntrack_mt_opts, 1295 }, 1296 { 1297 .version = XTABLES_VERSION, 1298 .name = "conntrack", 1299 .revision = 2, 1300 .family = NFPROTO_IPV4, 1301 .size = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo2)), 1302 .userspacesize = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo2)), 1303 .help = conntrack_mt_help, 1304 .parse = conntrack2_mt4_parse, 1305 .final_check = conntrack_mt_check, 1306 .print = conntrack2_mt_print, 1307 .save = conntrack2_mt_save, 1308 .extra_opts = conntrack_mt_opts, 1309 }, 1310 { 1311 .version = XTABLES_VERSION, 1312 .name = "conntrack", 1313 .revision = 2, 1314 .family = NFPROTO_IPV6, 1315 .size = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo2)), 1316 .userspacesize = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo2)), 1317 .help = conntrack_mt_help, 1318 .parse = conntrack2_mt6_parse, 1319 .final_check = conntrack_mt_check, 1320 .print = conntrack2_mt6_print, 1321 .save = conntrack2_mt6_save, 1322 .extra_opts = conntrack_mt_opts, 1323 }, 1324 { 1325 .version = XTABLES_VERSION, 1326 .name = "conntrack", 1327 .revision = 3, 1328 .family = NFPROTO_IPV4, 1329 .size = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo3)), 1330 .userspacesize = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo3)), 1331 .help = conntrack_mt_help, 1332 .parse = conntrack3_mt4_parse, 1333 .final_check = conntrack_mt_check, 1334 .print = conntrack3_mt_print, 1335 .save = conntrack3_mt_save, 1336 .extra_opts = conntrack_mt_opts, 1337 }, 1338 { 1339 .version = XTABLES_VERSION, 1340 .name = "conntrack", 1341 .revision = 3, 1342 .family = NFPROTO_IPV6, 1343 .size = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo3)), 1344 .userspacesize = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo3)), 1345 .help = conntrack_mt_help, 1346 .parse = conntrack3_mt6_parse, 1347 .final_check = conntrack_mt_check, 1348 .print = conntrack3_mt6_print, 1349 .save = conntrack3_mt6_save, 1350 .extra_opts = conntrack_mt_opts, 1351 }, 1352}; 1353 1354void _init(void) 1355{ 1356 xtables_register_matches(conntrack_mt_reg, ARRAY_SIZE(conntrack_mt_reg)); 1357} 1358