libxt_conntrack.c revision 9ee386a1b6d7704b259460152c959ab0e79e02aa
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 <stdio.h> 16#include <stdlib.h> 17#include <string.h> 18#include <iptables.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 25/* Function which prints out usage message. */ 26static void conntrack_mt_help(void) 27{ 28 printf( 29"conntrack match options:\n" 30"[!] --ctstate {INVALID|ESTABLISHED|NEW|RELATED|UNTRACKED|SNAT|DNAT}[,...]\n" 31" State(s) to match\n" 32"[!] --ctproto proto Protocol to match; by number or name, e.g. \"tcp\"\n" 33"[!] --ctorigsrc address[/mask]\n" 34"[!] --ctorigdst address[/mask]\n" 35"[!] --ctreplsrc address[/mask]\n" 36"[!] --ctrepldst address[/mask]\n" 37" Original/Reply source/destination address\n" 38"[!] --ctorigsrcport port\n" 39"[!] --ctorigdstport port\n" 40"[!] --ctreplsrcport port\n" 41"[!] --ctrepldstport port\n" 42" TCP/UDP/SCTP orig./reply source/destination port\n" 43"[!] --ctstatus {NONE|EXPECTED|SEEN_REPLY|ASSURED|CONFIRMED}[,...]\n" 44" Status(es) to match\n" 45"[!] --ctexpire time[:time] Match remaining lifetime in seconds against\n" 46" value or range of values (inclusive)\n" 47" --ctdir {ORIGINAL|REPLY} Flow direction of packet\n" 48"\n"); 49} 50 51static const struct option conntrack_mt_opts_v0[] = { 52 {.name = "ctstate", .has_arg = true, .val = '1'}, 53 {.name = "ctproto", .has_arg = true, .val = '2'}, 54 {.name = "ctorigsrc", .has_arg = true, .val = '3'}, 55 {.name = "ctorigdst", .has_arg = true, .val = '4'}, 56 {.name = "ctreplsrc", .has_arg = true, .val = '5'}, 57 {.name = "ctrepldst", .has_arg = true, .val = '6'}, 58 {.name = "ctstatus", .has_arg = true, .val = '7'}, 59 {.name = "ctexpire", .has_arg = true, .val = '8'}, 60 { .name = NULL } 61}; 62 63static const struct option conntrack_mt_opts[] = { 64 {.name = "ctstate", .has_arg = true, .val = '1'}, 65 {.name = "ctproto", .has_arg = true, .val = '2'}, 66 {.name = "ctorigsrc", .has_arg = true, .val = '3'}, 67 {.name = "ctorigdst", .has_arg = true, .val = '4'}, 68 {.name = "ctreplsrc", .has_arg = true, .val = '5'}, 69 {.name = "ctrepldst", .has_arg = true, .val = '6'}, 70 {.name = "ctstatus", .has_arg = true, .val = '7'}, 71 {.name = "ctexpire", .has_arg = true, .val = '8'}, 72 {.name = "ctorigsrcport", .has_arg = true, .val = 'a'}, 73 {.name = "ctorigdstport", .has_arg = true, .val = 'b'}, 74 {.name = "ctreplsrcport", .has_arg = true, .val = 'c'}, 75 {.name = "ctrepldstport", .has_arg = true, .val = 'd'}, 76 {.name = "ctdir", .has_arg = true, .val = 'e'}, 77 {.name = NULL}, 78}; 79 80static int 81parse_state(const char *state, size_t strlen, struct xt_conntrack_info *sinfo) 82{ 83 if (strncasecmp(state, "INVALID", strlen) == 0) 84 sinfo->statemask |= XT_CONNTRACK_STATE_INVALID; 85 else if (strncasecmp(state, "NEW", strlen) == 0) 86 sinfo->statemask |= XT_CONNTRACK_STATE_BIT(IP_CT_NEW); 87 else if (strncasecmp(state, "ESTABLISHED", strlen) == 0) 88 sinfo->statemask |= XT_CONNTRACK_STATE_BIT(IP_CT_ESTABLISHED); 89 else if (strncasecmp(state, "RELATED", strlen) == 0) 90 sinfo->statemask |= XT_CONNTRACK_STATE_BIT(IP_CT_RELATED); 91 else if (strncasecmp(state, "UNTRACKED", strlen) == 0) 92 sinfo->statemask |= XT_CONNTRACK_STATE_UNTRACKED; 93 else if (strncasecmp(state, "SNAT", strlen) == 0) 94 sinfo->statemask |= XT_CONNTRACK_STATE_SNAT; 95 else if (strncasecmp(state, "DNAT", strlen) == 0) 96 sinfo->statemask |= XT_CONNTRACK_STATE_DNAT; 97 else 98 return 0; 99 return 1; 100} 101 102static void 103parse_states(const char *arg, struct xt_conntrack_info *sinfo) 104{ 105 const char *comma; 106 107 while ((comma = strchr(arg, ',')) != NULL) { 108 if (comma == arg || !parse_state(arg, comma-arg, sinfo)) 109 exit_error(PARAMETER_PROBLEM, "Bad ctstate `%s'", arg); 110 arg = comma+1; 111 } 112 113 if (strlen(arg) == 0 || !parse_state(arg, strlen(arg), sinfo)) 114 exit_error(PARAMETER_PROBLEM, "Bad ctstate `%s'", arg); 115} 116 117static bool 118conntrack_ps_state(struct xt_conntrack_mtinfo1 *info, const char *state, 119 size_t z) 120{ 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; 138} 139 140static void 141conntrack_ps_states(struct xt_conntrack_mtinfo1 *info, const char *arg) 142{ 143 const char *comma; 144 145 while ((comma = strchr(arg, ',')) != NULL) { 146 if (comma == arg || !conntrack_ps_state(info, arg, comma - arg)) 147 exit_error(PARAMETER_PROBLEM, 148 "Bad ctstate \"%s\"", arg); 149 arg = comma + 1; 150 } 151 152 if (strlen(arg) == 0 || !conntrack_ps_state(info, arg, strlen(arg))) 153 exit_error(PARAMETER_PROBLEM, "Bad ctstate \"%s\"", arg); 154} 155 156static int 157parse_status(const char *status, size_t strlen, struct xt_conntrack_info *sinfo) 158{ 159 if (strncasecmp(status, "NONE", strlen) == 0) 160 sinfo->statusmask |= 0; 161 else if (strncasecmp(status, "EXPECTED", strlen) == 0) 162 sinfo->statusmask |= IPS_EXPECTED; 163 else if (strncasecmp(status, "SEEN_REPLY", strlen) == 0) 164 sinfo->statusmask |= IPS_SEEN_REPLY; 165 else if (strncasecmp(status, "ASSURED", strlen) == 0) 166 sinfo->statusmask |= IPS_ASSURED; 167#ifdef IPS_CONFIRMED 168 else if (strncasecmp(status, "CONFIRMED", strlen) == 0) 169 sinfo->statusmask |= IPS_CONFIRMED; 170#endif 171 else 172 return 0; 173 return 1; 174} 175 176static void 177parse_statuses(const char *arg, struct xt_conntrack_info *sinfo) 178{ 179 const char *comma; 180 181 while ((comma = strchr(arg, ',')) != NULL) { 182 if (comma == arg || !parse_status(arg, comma-arg, sinfo)) 183 exit_error(PARAMETER_PROBLEM, "Bad ctstatus `%s'", arg); 184 arg = comma+1; 185 } 186 187 if (strlen(arg) == 0 || !parse_status(arg, strlen(arg), sinfo)) 188 exit_error(PARAMETER_PROBLEM, "Bad ctstatus `%s'", arg); 189} 190 191static bool 192conntrack_ps_status(struct xt_conntrack_mtinfo1 *info, const char *status, 193 size_t z) 194{ 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; 208} 209 210static void 211conntrack_ps_statuses(struct xt_conntrack_mtinfo1 *info, const char *arg) 212{ 213 const char *comma; 214 215 while ((comma = strchr(arg, ',')) != NULL) { 216 if (comma == arg || !conntrack_ps_status(info, arg, comma - arg)) 217 exit_error(PARAMETER_PROBLEM, 218 "Bad ctstatus \"%s\"", arg); 219 arg = comma + 1; 220 } 221 222 if (strlen(arg) == 0 || !conntrack_ps_status(info, arg, strlen(arg))) 223 exit_error(PARAMETER_PROBLEM, "Bad ctstatus \"%s\"", arg); 224} 225 226static unsigned long 227parse_expire(const char *s) 228{ 229 unsigned int len; 230 231 if (string_to_number(s, 0, 0, &len) == -1) 232 exit_error(PARAMETER_PROBLEM, "expire value invalid: `%s'\n", s); 233 else 234 return len; 235} 236 237/* If a single value is provided, min and max are both set to the value */ 238static void 239parse_expires(const char *s, struct xt_conntrack_info *sinfo) 240{ 241 char *buffer; 242 char *cp; 243 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++; 251 252 sinfo->expires_min = buffer[0] ? parse_expire(buffer) : 0; 253 sinfo->expires_max = cp[0] 254 ? parse_expire(cp) 255 : (unsigned long)-1; 256 } 257 free(buffer); 258 259 if (sinfo->expires_min > sinfo->expires_max) 260 exit_error(PARAMETER_PROBLEM, 261 "expire min. range value `%lu' greater than max. " 262 "range value `%lu'", sinfo->expires_min, sinfo->expires_max); 263} 264 265static void 266conntrack_ps_expires(struct xt_conntrack_mtinfo1 *info, const char *s) 267{ 268 unsigned int min, max; 269 char *end; 270 271 if (!strtonum(s, &end, &min, 0, ~0)) 272 param_act(P_BAD_VALUE, "conntrack", "--expires", s); 273 max = min; 274 if (*end == ':') 275 if (!strtonum(s, &end, &max, 0, ~0U)) 276 param_act(P_BAD_VALUE, "conntrack", "--expires", s); 277 if (*end != '\0') 278 param_act(P_BAD_VALUE, "conntrack", "--expires", s); 279 280 if (min > max) 281 exit_error(PARAMETER_PROBLEM, 282 "expire min. range value \"%u\" greater than max. " 283 "range value \"%u\"", min, max); 284 285 info->expires_min = min; 286 info->expires_max = max; 287} 288 289/* Function which parses command options; returns true if it 290 ate an option */ 291static int conntrack_parse(int c, char **argv, int invert, unsigned int *flags, 292 const void *entry, struct xt_entry_match **match) 293{ 294 struct xt_conntrack_info *sinfo = (void *)(*match)->data; 295 char *protocol = NULL; 296 unsigned int naddrs = 0; 297 struct in_addr *addrs = NULL; 298 299 300 switch (c) { 301 case '1': 302 check_inverse(optarg, &invert, &optind, 0); 303 304 parse_states(argv[optind-1], sinfo); 305 if (invert) { 306 sinfo->invflags |= XT_CONNTRACK_STATE; 307 } 308 sinfo->flags |= XT_CONNTRACK_STATE; 309 break; 310 311 case '2': 312 check_inverse(optarg, &invert, &optind, 0); 313 314 if(invert) 315 sinfo->invflags |= XT_CONNTRACK_PROTO; 316 317 /* Canonicalize into lower case */ 318 for (protocol = argv[optind-1]; *protocol; protocol++) 319 *protocol = tolower(*protocol); 320 321 protocol = argv[optind-1]; 322 sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum = parse_protocol(protocol); 323 324 if (sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum == 0 325 && (sinfo->invflags & XT_INV_PROTO)) 326 exit_error(PARAMETER_PROBLEM, 327 "rule would never match protocol"); 328 329 sinfo->flags |= XT_CONNTRACK_PROTO; 330 break; 331 332 case '3': 333 check_inverse(optarg, &invert, &optind, 0); 334 335 if (invert) 336 sinfo->invflags |= XT_CONNTRACK_ORIGSRC; 337 338 ipparse_hostnetworkmask(argv[optind-1], &addrs, 339 &sinfo->sipmsk[IP_CT_DIR_ORIGINAL], 340 &naddrs); 341 if(naddrs > 1) 342 exit_error(PARAMETER_PROBLEM, 343 "multiple IP addresses not allowed"); 344 345 if(naddrs == 1) { 346 sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip = addrs[0].s_addr; 347 } 348 349 sinfo->flags |= XT_CONNTRACK_ORIGSRC; 350 break; 351 352 case '4': 353 check_inverse(optarg, &invert, &optind, 0); 354 355 if (invert) 356 sinfo->invflags |= XT_CONNTRACK_ORIGDST; 357 358 ipparse_hostnetworkmask(argv[optind-1], &addrs, 359 &sinfo->dipmsk[IP_CT_DIR_ORIGINAL], 360 &naddrs); 361 if(naddrs > 1) 362 exit_error(PARAMETER_PROBLEM, 363 "multiple IP addresses not allowed"); 364 365 if(naddrs == 1) { 366 sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip = addrs[0].s_addr; 367 } 368 369 sinfo->flags |= XT_CONNTRACK_ORIGDST; 370 break; 371 372 case '5': 373 check_inverse(optarg, &invert, &optind, 0); 374 375 if (invert) 376 sinfo->invflags |= XT_CONNTRACK_REPLSRC; 377 378 ipparse_hostnetworkmask(argv[optind-1], &addrs, 379 &sinfo->sipmsk[IP_CT_DIR_REPLY], 380 &naddrs); 381 if(naddrs > 1) 382 exit_error(PARAMETER_PROBLEM, 383 "multiple IP addresses not allowed"); 384 385 if(naddrs == 1) { 386 sinfo->tuple[IP_CT_DIR_REPLY].src.ip = addrs[0].s_addr; 387 } 388 389 sinfo->flags |= XT_CONNTRACK_REPLSRC; 390 break; 391 392 case '6': 393 check_inverse(optarg, &invert, &optind, 0); 394 395 if (invert) 396 sinfo->invflags |= XT_CONNTRACK_REPLDST; 397 398 ipparse_hostnetworkmask(argv[optind-1], &addrs, 399 &sinfo->dipmsk[IP_CT_DIR_REPLY], 400 &naddrs); 401 if(naddrs > 1) 402 exit_error(PARAMETER_PROBLEM, 403 "multiple IP addresses not allowed"); 404 405 if(naddrs == 1) { 406 sinfo->tuple[IP_CT_DIR_REPLY].dst.ip = addrs[0].s_addr; 407 } 408 409 sinfo->flags |= XT_CONNTRACK_REPLDST; 410 break; 411 412 case '7': 413 check_inverse(optarg, &invert, &optind, 0); 414 415 parse_statuses(argv[optind-1], sinfo); 416 if (invert) { 417 sinfo->invflags |= XT_CONNTRACK_STATUS; 418 } 419 sinfo->flags |= XT_CONNTRACK_STATUS; 420 break; 421 422 case '8': 423 check_inverse(optarg, &invert, &optind, 0); 424 425 parse_expires(argv[optind-1], sinfo); 426 if (invert) { 427 sinfo->invflags |= XT_CONNTRACK_EXPIRES; 428 } 429 sinfo->flags |= XT_CONNTRACK_EXPIRES; 430 break; 431 432 default: 433 return 0; 434 } 435 436 *flags = sinfo->flags; 437 return 1; 438} 439 440static int 441conntrack_mt_parse(int c, char **argv, int invert, unsigned int *flags, 442 struct xt_entry_match **match) 443{ 444 struct xt_conntrack_mtinfo1 *info = (void *)(*match)->data; 445 unsigned int port; 446 char *p; 447 448 switch (c) { 449 case '1': /* --ctstate */ 450 conntrack_ps_states(info, optarg); 451 info->match_flags |= XT_CONNTRACK_STATE; 452 if (invert) 453 info->invert_flags |= XT_CONNTRACK_STATE; 454 break; 455 456 case '2': /* --ctproto */ 457 /* Canonicalize into lower case */ 458 for (p = optarg; *p != '\0'; ++p) 459 *p = tolower(*p); 460 info->l4proto = parse_protocol(optarg); 461 462 if (info->l4proto == 0 && (info->invert_flags & XT_INV_PROTO)) 463 exit_error(PARAMETER_PROBLEM, "conntrack: rule would " 464 "never match protocol"); 465 466 info->match_flags |= XT_CONNTRACK_PROTO; 467 if (invert) 468 info->invert_flags |= XT_CONNTRACK_PROTO; 469 break; 470 471 case '7': /* --ctstatus */ 472 conntrack_ps_statuses(info, optarg); 473 info->match_flags |= XT_CONNTRACK_STATUS; 474 if (invert) 475 info->invert_flags |= XT_CONNTRACK_STATUS; 476 break; 477 478 case '8': /* --ctexpire */ 479 conntrack_ps_expires(info, optarg); 480 info->match_flags |= XT_CONNTRACK_EXPIRES; 481 if (invert) 482 info->invert_flags |= XT_CONNTRACK_EXPIRES; 483 break; 484 485 case 'a': /* --ctorigsrcport */ 486 if (!strtonum(optarg, NULL, &port, 0, ~(u_int16_t)0)) 487 param_act(P_BAD_VALUE, "conntrack", 488 "--ctorigsrcport", optarg); 489 info->match_flags |= XT_CONNTRACK_ORIGSRC_PORT; 490 info->origsrc_port = htons(port); 491 if (invert) 492 info->invert_flags |= XT_CONNTRACK_ORIGSRC_PORT; 493 break; 494 495 case 'b': /* --ctorigdstport */ 496 if (!strtonum(optarg, NULL, &port, 0, ~(u_int16_t)0)) 497 param_act(P_BAD_VALUE, "conntrack", 498 "--ctorigdstport", optarg); 499 info->match_flags |= XT_CONNTRACK_ORIGDST_PORT; 500 info->origdst_port = htons(port); 501 if (invert) 502 info->invert_flags |= XT_CONNTRACK_ORIGDST_PORT; 503 break; 504 505 case 'c': /* --ctreplsrcport */ 506 if (!strtonum(optarg, NULL, &port, 0, ~(u_int16_t)0)) 507 param_act(P_BAD_VALUE, "conntrack", 508 "--ctreplsrcport", optarg); 509 info->match_flags |= XT_CONNTRACK_REPLSRC_PORT; 510 info->replsrc_port = htons(port); 511 if (invert) 512 info->invert_flags |= XT_CONNTRACK_REPLSRC_PORT; 513 break; 514 515 case 'd': /* --ctrepldstport */ 516 if (!strtonum(optarg, NULL, &port, 0, ~(u_int16_t)0)) 517 param_act(P_BAD_VALUE, "conntrack", 518 "--ctrepldstport", optarg); 519 info->match_flags |= XT_CONNTRACK_REPLDST_PORT; 520 info->repldst_port = htons(port); 521 if (invert) 522 info->invert_flags |= XT_CONNTRACK_REPLDST_PORT; 523 break; 524 525 case 'e': /* --ctdir */ 526 param_act(P_NO_INVERT, "conntrack", "--ctdir", invert); 527 if (strcasecmp(optarg, "ORIGINAL") == 0) { 528 info->match_flags |= XT_CONNTRACK_DIRECTION; 529 info->invert_flags &= ~XT_CONNTRACK_DIRECTION; 530 } else if (strcasecmp(optarg, "REPLY") == 0) { 531 info->match_flags |= XT_CONNTRACK_DIRECTION; 532 info->invert_flags |= XT_CONNTRACK_DIRECTION; 533 } else { 534 param_act(P_BAD_VALUE, "conntrack", "--ctdir", optarg); 535 } 536 break; 537 538 default: 539 return false; 540 } 541 542 *flags = info->match_flags; 543 return true; 544} 545 546static int 547conntrack_mt4_parse(int c, char **argv, int invert, unsigned int *flags, 548 const void *entry, struct xt_entry_match **match) 549{ 550 struct xt_conntrack_mtinfo1 *info = (void *)(*match)->data; 551 struct in_addr *addr = NULL; 552 unsigned int naddrs = 0; 553 554 switch (c) { 555 case '3': /* --ctorigsrc */ 556 ipparse_hostnetworkmask(optarg, &addr, &info->origsrc_mask.in, 557 &naddrs); 558 if (naddrs > 1) 559 exit_error(PARAMETER_PROBLEM, 560 "multiple IP addresses not allowed"); 561 if (naddrs == 1) 562 memcpy(&info->origsrc_addr.in, addr, sizeof(*addr)); 563 info->match_flags |= XT_CONNTRACK_ORIGSRC; 564 if (invert) 565 info->invert_flags |= XT_CONNTRACK_ORIGSRC; 566 break; 567 568 case '4': /* --ctorigdst */ 569 ipparse_hostnetworkmask(optarg, &addr, &info->origdst_mask.in, 570 &naddrs); 571 if (naddrs > 1) 572 exit_error(PARAMETER_PROBLEM, 573 "multiple IP addresses not allowed"); 574 if (naddrs == 1) 575 memcpy(&info->origdst_addr.in, addr, sizeof(*addr)); 576 info->match_flags |= XT_CONNTRACK_ORIGDST; 577 if (invert) 578 info->invert_flags |= XT_CONNTRACK_ORIGDST; 579 break; 580 581 case '5': /* --ctreplsrc */ 582 ipparse_hostnetworkmask(optarg, &addr, &info->replsrc_mask.in, 583 &naddrs); 584 if (naddrs > 1) 585 exit_error(PARAMETER_PROBLEM, 586 "multiple IP addresses not allowed"); 587 if (naddrs == 1) 588 memcpy(&info->replsrc_addr.in, addr, sizeof(*addr)); 589 info->match_flags |= XT_CONNTRACK_REPLSRC; 590 if (invert) 591 info->invert_flags |= XT_CONNTRACK_REPLSRC; 592 break; 593 594 case '6': /* --ctrepldst */ 595 ipparse_hostnetworkmask(optarg, &addr, &info->repldst_mask.in, 596 &naddrs); 597 if (naddrs > 1) 598 exit_error(PARAMETER_PROBLEM, 599 "multiple IP addresses not allowed"); 600 if (naddrs == 1) 601 memcpy(&info->repldst_addr.in, addr, sizeof(*addr)); 602 info->match_flags |= XT_CONNTRACK_REPLDST; 603 if (invert) 604 info->invert_flags |= XT_CONNTRACK_REPLDST; 605 break; 606 607 608 default: 609 return conntrack_mt_parse(c, argv, invert, flags, match); 610 } 611 612 *flags = info->match_flags; 613 return true; 614} 615 616static int 617conntrack_mt6_parse(int c, char **argv, int invert, unsigned int *flags, 618 const void *entry, struct xt_entry_match **match) 619{ 620 struct xt_conntrack_mtinfo1 *info = (void *)(*match)->data; 621 struct in6_addr *addr = NULL; 622 unsigned int naddrs = 0; 623 624 switch (c) { 625 case '3': /* --ctorigsrc */ 626 ip6parse_hostnetworkmask(optarg, &addr, 627 &info->origsrc_mask.in6, &naddrs); 628 if (naddrs > 1) 629 exit_error(PARAMETER_PROBLEM, 630 "multiple IP addresses not allowed"); 631 if (naddrs == 1) 632 memcpy(&info->origsrc_addr.in6, addr, sizeof(*addr)); 633 info->match_flags |= XT_CONNTRACK_ORIGSRC; 634 if (invert) 635 info->invert_flags |= XT_CONNTRACK_ORIGSRC; 636 break; 637 638 case '4': /* --ctorigdst */ 639 ip6parse_hostnetworkmask(optarg, &addr, 640 &info->origdst_mask.in6, &naddrs); 641 if (naddrs > 1) 642 exit_error(PARAMETER_PROBLEM, 643 "multiple IP addresses not allowed"); 644 if (naddrs == 1) 645 memcpy(&info->origdst_addr.in, addr, sizeof(*addr)); 646 info->match_flags |= XT_CONNTRACK_ORIGDST; 647 if (invert) 648 info->invert_flags |= XT_CONNTRACK_ORIGDST; 649 break; 650 651 case '5': /* --ctreplsrc */ 652 ip6parse_hostnetworkmask(optarg, &addr, 653 &info->replsrc_mask.in6, &naddrs); 654 if (naddrs > 1) 655 exit_error(PARAMETER_PROBLEM, 656 "multiple IP addresses not allowed"); 657 if (naddrs == 1) 658 memcpy(&info->replsrc_addr.in, addr, sizeof(*addr)); 659 info->match_flags |= XT_CONNTRACK_REPLSRC; 660 if (invert) 661 info->invert_flags |= XT_CONNTRACK_REPLSRC; 662 break; 663 664 case '6': /* --ctrepldst */ 665 ip6parse_hostnetworkmask(optarg, &addr, 666 &info->repldst_mask.in6, &naddrs); 667 if (naddrs > 1) 668 exit_error(PARAMETER_PROBLEM, 669 "multiple IP addresses not allowed"); 670 if (naddrs == 1) 671 memcpy(&info->repldst_addr.in, addr, sizeof(*addr)); 672 info->match_flags |= XT_CONNTRACK_REPLDST; 673 if (invert) 674 info->invert_flags |= XT_CONNTRACK_REPLDST; 675 break; 676 677 678 default: 679 return conntrack_mt_parse(c, argv, invert, flags, match); 680 } 681 682 *flags = info->match_flags; 683 return true; 684} 685 686static void conntrack_mt_check(unsigned int flags) 687{ 688 if (flags == 0) 689 exit_error(PARAMETER_PROBLEM, "conntrack: At least one option " 690 "is required"); 691} 692 693static void 694print_state(unsigned int statemask) 695{ 696 const char *sep = ""; 697 698 if (statemask & XT_CONNTRACK_STATE_INVALID) { 699 printf("%sINVALID", sep); 700 sep = ","; 701 } 702 if (statemask & XT_CONNTRACK_STATE_BIT(IP_CT_NEW)) { 703 printf("%sNEW", sep); 704 sep = ","; 705 } 706 if (statemask & XT_CONNTRACK_STATE_BIT(IP_CT_RELATED)) { 707 printf("%sRELATED", sep); 708 sep = ","; 709 } 710 if (statemask & XT_CONNTRACK_STATE_BIT(IP_CT_ESTABLISHED)) { 711 printf("%sESTABLISHED", sep); 712 sep = ","; 713 } 714 if (statemask & XT_CONNTRACK_STATE_UNTRACKED) { 715 printf("%sUNTRACKED", sep); 716 sep = ","; 717 } 718 if (statemask & XT_CONNTRACK_STATE_SNAT) { 719 printf("%sSNAT", sep); 720 sep = ","; 721 } 722 if (statemask & XT_CONNTRACK_STATE_DNAT) { 723 printf("%sDNAT", sep); 724 sep = ","; 725 } 726 printf(" "); 727} 728 729static void 730print_status(unsigned int statusmask) 731{ 732 const char *sep = ""; 733 734 if (statusmask & IPS_EXPECTED) { 735 printf("%sEXPECTED", sep); 736 sep = ","; 737 } 738 if (statusmask & IPS_SEEN_REPLY) { 739 printf("%sSEEN_REPLY", sep); 740 sep = ","; 741 } 742 if (statusmask & IPS_ASSURED) { 743 printf("%sASSURED", sep); 744 sep = ","; 745 } 746 if (statusmask & IPS_CONFIRMED) { 747 printf("%sCONFIRMED", sep); 748 sep = ","; 749 } 750 if (statusmask == 0) 751 printf("%sNONE", sep); 752 printf(" "); 753} 754 755static void 756conntrack_dump_addr(const union nf_inet_addr *addr, 757 const union nf_inet_addr *mask, 758 unsigned int family, bool numeric) 759{ 760 if (family == AF_INET) { 761 if (!numeric && addr->ip == 0) { 762 printf("anywhere "); 763 return; 764 } 765 printf("%s ", ipaddr_to_anyname(&addr->in)); 766 } else if (family == AF_INET6) { 767 if (!numeric && addr->ip6[0] == 0 && addr->ip6[1] == 0 && 768 addr->ip6[2] == 0 && addr->ip6[3] == 0) { 769 printf("anywhere "); 770 return; 771 } 772 printf("%s ", ip6addr_to_anyname(&addr->in6)); 773 } 774} 775 776static void 777print_addr(struct in_addr *addr, struct in_addr *mask, int inv, int numeric) 778{ 779 char buf[BUFSIZ]; 780 781 if (inv) 782 printf("! "); 783 784 if (mask->s_addr == 0L && !numeric) 785 printf("%s ", "anywhere"); 786 else { 787 if (numeric) 788 sprintf(buf, "%s", ipaddr_to_numeric(addr)); 789 else 790 sprintf(buf, "%s", ipaddr_to_anyname(addr)); 791 strcat(buf, ipmask_to_numeric(mask)); 792 printf("%s ", buf); 793 } 794} 795 796/* Saves the matchinfo in parsable form to stdout. */ 797static void 798matchinfo_print(const void *ip, const struct xt_entry_match *match, int numeric, const char *optpfx) 799{ 800 struct xt_conntrack_info *sinfo = (void *)match->data; 801 802 if(sinfo->flags & XT_CONNTRACK_STATE) { 803 if (sinfo->invflags & XT_CONNTRACK_STATE) 804 printf("! "); 805 printf("%sctstate ", optpfx); 806 print_state(sinfo->statemask); 807 } 808 809 if(sinfo->flags & XT_CONNTRACK_PROTO) { 810 if (sinfo->invflags & XT_CONNTRACK_PROTO) 811 printf("! "); 812 printf("%sctproto ", optpfx); 813 printf("%u ", sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum); 814 } 815 816 if(sinfo->flags & XT_CONNTRACK_ORIGSRC) { 817 if (sinfo->invflags & XT_CONNTRACK_ORIGSRC) 818 printf("! "); 819 printf("%sctorigsrc ", optpfx); 820 821 print_addr( 822 (struct in_addr *)&sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip, 823 &sinfo->sipmsk[IP_CT_DIR_ORIGINAL], 824 false, 825 numeric); 826 } 827 828 if(sinfo->flags & XT_CONNTRACK_ORIGDST) { 829 if (sinfo->invflags & XT_CONNTRACK_ORIGDST) 830 printf("! "); 831 printf("%sctorigdst ", optpfx); 832 833 print_addr( 834 (struct in_addr *)&sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip, 835 &sinfo->dipmsk[IP_CT_DIR_ORIGINAL], 836 false, 837 numeric); 838 } 839 840 if(sinfo->flags & XT_CONNTRACK_REPLSRC) { 841 if (sinfo->invflags & XT_CONNTRACK_REPLSRC) 842 printf("! "); 843 printf("%sctreplsrc ", optpfx); 844 845 print_addr( 846 (struct in_addr *)&sinfo->tuple[IP_CT_DIR_REPLY].src.ip, 847 &sinfo->sipmsk[IP_CT_DIR_REPLY], 848 false, 849 numeric); 850 } 851 852 if(sinfo->flags & XT_CONNTRACK_REPLDST) { 853 if (sinfo->invflags & XT_CONNTRACK_REPLDST) 854 printf("! "); 855 printf("%sctrepldst ", optpfx); 856 857 print_addr( 858 (struct in_addr *)&sinfo->tuple[IP_CT_DIR_REPLY].dst.ip, 859 &sinfo->dipmsk[IP_CT_DIR_REPLY], 860 false, 861 numeric); 862 } 863 864 if(sinfo->flags & XT_CONNTRACK_STATUS) { 865 if (sinfo->invflags & XT_CONNTRACK_STATUS) 866 printf("! "); 867 printf("%sctstatus ", optpfx); 868 print_status(sinfo->statusmask); 869 } 870 871 if(sinfo->flags & XT_CONNTRACK_EXPIRES) { 872 if (sinfo->invflags & XT_CONNTRACK_EXPIRES) 873 printf("! "); 874 printf("%sctexpire ", optpfx); 875 876 if (sinfo->expires_max == sinfo->expires_min) 877 printf("%lu ", sinfo->expires_min); 878 else 879 printf("%lu:%lu ", sinfo->expires_min, sinfo->expires_max); 880 } 881} 882 883static void 884conntrack_dump(const struct xt_conntrack_mtinfo1 *info, const char *prefix, 885 unsigned int family, bool numeric) 886{ 887 if (info->match_flags & XT_CONNTRACK_STATE) { 888 if (info->invert_flags & XT_CONNTRACK_STATE) 889 printf("! "); 890 printf("%sctstate ", prefix); 891 print_state(info->state_mask); 892 } 893 894 if (info->match_flags & XT_CONNTRACK_PROTO) { 895 if (info->invert_flags & XT_CONNTRACK_PROTO) 896 printf("! "); 897 printf("%sctproto %u ", prefix, info->l4proto); 898 } 899 900 if (info->match_flags & XT_CONNTRACK_ORIGSRC) { 901 if (info->invert_flags & XT_CONNTRACK_PROTO) 902 printf("! "); 903 printf("%sctorigsrc ", prefix); 904 conntrack_dump_addr(&info->origsrc_addr, &info->origsrc_mask, 905 family, numeric); 906 } 907 908 if (info->match_flags & XT_CONNTRACK_ORIGDST) { 909 if (info->invert_flags & XT_CONNTRACK_PROTO) 910 printf("! "); 911 printf("%sctorigdst ", prefix); 912 conntrack_dump_addr(&info->origdst_addr, &info->origdst_mask, 913 family, numeric); 914 } 915 916 if (info->match_flags & XT_CONNTRACK_REPLSRC) { 917 if (info->invert_flags & XT_CONNTRACK_PROTO) 918 printf("! "); 919 printf("%sctreplsrc ", prefix); 920 conntrack_dump_addr(&info->replsrc_addr, &info->replsrc_mask, 921 family, numeric); 922 } 923 924 if (info->match_flags & XT_CONNTRACK_REPLDST) { 925 if (info->invert_flags & XT_CONNTRACK_PROTO) 926 printf("! "); 927 printf("%sctrepldst ", prefix); 928 conntrack_dump_addr(&info->repldst_addr, &info->repldst_mask, 929 family, numeric); 930 } 931 932 if (info->match_flags & XT_CONNTRACK_ORIGSRC_PORT) { 933 if (info->invert_flags & XT_CONNTRACK_ORIGSRC_PORT) 934 printf("! "); 935 printf("%sctorigsrcport %u ", prefix, 936 ntohs(info->origsrc_port)); 937 } 938 939 if (info->match_flags & XT_CONNTRACK_ORIGDST_PORT) { 940 if (info->invert_flags & XT_CONNTRACK_ORIGDST_PORT) 941 printf("! "); 942 printf("%sctorigdstport %u ", prefix, 943 ntohs(info->origdst_port)); 944 } 945 946 if (info->match_flags & XT_CONNTRACK_REPLSRC_PORT) { 947 if (info->invert_flags & XT_CONNTRACK_REPLSRC_PORT) 948 printf("! "); 949 printf("%sctreplsrcport %u ", prefix, 950 ntohs(info->replsrc_port)); 951 } 952 953 if (info->match_flags & XT_CONNTRACK_REPLDST_PORT) { 954 if (info->invert_flags & XT_CONNTRACK_REPLDST_PORT) 955 printf("! "); 956 printf("%sctrepldstport %u ", prefix, 957 ntohs(info->repldst_port)); 958 } 959 960 if (info->match_flags & XT_CONNTRACK_STATUS) { 961 if (info->invert_flags & XT_CONNTRACK_STATUS) 962 printf("! "); 963 printf("%sctstatus ", prefix); 964 print_status(info->status_mask); 965 } 966 967 if (info->match_flags & XT_CONNTRACK_EXPIRES) { 968 if (info->invert_flags & XT_CONNTRACK_EXPIRES) 969 printf("! "); 970 printf("%sctexpire ", prefix); 971 972 if (info->expires_max == info->expires_min) 973 printf("%u ", (unsigned int)info->expires_min); 974 else 975 printf("%u:%u ", (unsigned int)info->expires_min, 976 (unsigned int)info->expires_max); 977 } 978} 979 980/* Prints out the matchinfo. */ 981static void conntrack_print(const void *ip, const struct xt_entry_match *match, 982 int numeric) 983{ 984 matchinfo_print(ip, match, numeric, ""); 985} 986 987static void 988conntrack_mt_print(const void *ip, const struct xt_entry_match *match, 989 int numeric) 990{ 991 conntrack_dump((const void *)match->data, "", AF_INET, numeric); 992} 993 994static void 995conntrack_mt6_print(const void *ip, const struct xt_entry_match *match, 996 int numeric) 997{ 998 conntrack_dump((const void *)match->data, "", AF_INET6, numeric); 999} 1000 1001/* Saves the matchinfo in parsable form to stdout. */ 1002static void conntrack_save(const void *ip, const struct xt_entry_match *match) 1003{ 1004 matchinfo_print(ip, match, 1, "--"); 1005} 1006 1007static void conntrack_mt_save(const void *ip, 1008 const struct xt_entry_match *match) 1009{ 1010 conntrack_dump((const void *)match->data, "--", AF_INET, true); 1011} 1012 1013static void conntrack_mt6_save(const void *ip, 1014 const struct xt_entry_match *match) 1015{ 1016 conntrack_dump((const void *)match->data, "--", AF_INET6, true); 1017} 1018 1019static struct xtables_match conntrack_match = { 1020 .version = IPTABLES_VERSION, 1021 .name = "conntrack", 1022 .revision = 0, 1023 .family = AF_INET, 1024 .size = XT_ALIGN(sizeof(struct xt_conntrack_info)), 1025 .userspacesize = XT_ALIGN(sizeof(struct xt_conntrack_info)), 1026 .help = conntrack_mt_help, 1027 .parse = conntrack_parse, 1028 .final_check = conntrack_mt_check, 1029 .print = conntrack_print, 1030 .save = conntrack_save, 1031 .extra_opts = conntrack_mt_opts_v0, 1032}; 1033 1034static struct xtables_match conntrack_mt_reg = { 1035 .version = IPTABLES_VERSION, 1036 .name = "conntrack", 1037 .revision = 1, 1038 .family = AF_INET, 1039 .size = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo1)), 1040 .userspacesize = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo1)), 1041 .help = conntrack_mt_help, 1042 .parse = conntrack_mt4_parse, 1043 .final_check = conntrack_mt_check, 1044 .print = conntrack_mt_print, 1045 .save = conntrack_mt_save, 1046 .extra_opts = conntrack_mt_opts, 1047}; 1048 1049static struct xtables_match conntrack_mt6_reg = { 1050 .version = IPTABLES_VERSION, 1051 .name = "conntrack", 1052 .revision = 1, 1053 .family = AF_INET6, 1054 .size = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo1)), 1055 .userspacesize = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo1)), 1056 .help = conntrack_mt_help, 1057 .parse = conntrack_mt6_parse, 1058 .final_check = conntrack_mt_check, 1059 .print = conntrack_mt6_print, 1060 .save = conntrack_mt6_save, 1061 .extra_opts = conntrack_mt_opts, 1062}; 1063 1064void _init(void) 1065{ 1066 xtables_register_match(&conntrack_match); 1067 xtables_register_match(&conntrack_mt_reg); 1068 xtables_register_match(&conntrack_mt6_reg); 1069} 1070