libxt_conntrack.c revision 0f16c725aadaac7e670d632ecbaea3661ff00827
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 <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> 23 24static void conntrack_mt_help(void) 25{ 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"); 46} 47 48static 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 } 58}; 59 60static 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}, 75}; 76 77static int 78parse_state(const char *state, size_t len, struct xt_conntrack_info *sinfo) 79{ 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; 97} 98 99static void 100parse_states(const char *arg, struct xt_conntrack_info *sinfo) 101{ 102 const char *comma; 103 104 while ((comma = strchr(arg, ',')) != NULL) { 105 if (comma == arg || !parse_state(arg, comma-arg, sinfo)) 106 exit_error(PARAMETER_PROBLEM, "Bad ctstate `%s'", arg); 107 arg = comma+1; 108 } 109 if (!*arg) 110 exit_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 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 len, struct xt_conntrack_info *sinfo) 158{ 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; 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 (!xtables_strtoui(s, NULL, &len, 0, UINT32_MAX)) 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 (!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); 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 289static int conntrack_parse(int c, char **argv, int invert, unsigned int *flags, 290 const void *entry, struct xt_entry_match **match) 291{ 292 struct xt_conntrack_info *sinfo = (void *)(*match)->data; 293 char *protocol = NULL; 294 unsigned int naddrs = 0; 295 struct in_addr *addrs = NULL; 296 297 298 switch (c) { 299 case '1': 300 xtables_check_inverse(optarg, &invert, &optind, 0); 301 302 parse_states(argv[optind-1], sinfo); 303 if (invert) { 304 sinfo->invflags |= XT_CONNTRACK_STATE; 305 } 306 sinfo->flags |= XT_CONNTRACK_STATE; 307 break; 308 309 case '2': 310 xtables_check_inverse(optarg, &invert, &optind, 0); 311 312 if(invert) 313 sinfo->invflags |= XT_CONNTRACK_PROTO; 314 315 /* Canonicalize into lower case */ 316 for (protocol = argv[optind-1]; *protocol; protocol++) 317 *protocol = tolower(*protocol); 318 319 protocol = argv[optind-1]; 320 sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum = parse_protocol(protocol); 321 322 if (sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum == 0 323 && (sinfo->invflags & XT_INV_PROTO)) 324 exit_error(PARAMETER_PROBLEM, 325 "rule would never match protocol"); 326 327 sinfo->flags |= XT_CONNTRACK_PROTO; 328 break; 329 330 case '3': 331 xtables_check_inverse(optarg, &invert, &optind, 0); 332 333 if (invert) 334 sinfo->invflags |= XT_CONNTRACK_ORIGSRC; 335 336 xtables_ipparse_any(argv[optind-1], &addrs, 337 &sinfo->sipmsk[IP_CT_DIR_ORIGINAL], 338 &naddrs); 339 if(naddrs > 1) 340 exit_error(PARAMETER_PROBLEM, 341 "multiple IP addresses not allowed"); 342 343 if(naddrs == 1) { 344 sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip = addrs[0].s_addr; 345 } 346 347 sinfo->flags |= XT_CONNTRACK_ORIGSRC; 348 break; 349 350 case '4': 351 xtables_check_inverse(optarg, &invert, &optind, 0); 352 353 if (invert) 354 sinfo->invflags |= XT_CONNTRACK_ORIGDST; 355 356 xtables_ipparse_any(argv[optind-1], &addrs, 357 &sinfo->dipmsk[IP_CT_DIR_ORIGINAL], 358 &naddrs); 359 if(naddrs > 1) 360 exit_error(PARAMETER_PROBLEM, 361 "multiple IP addresses not allowed"); 362 363 if(naddrs == 1) { 364 sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip = addrs[0].s_addr; 365 } 366 367 sinfo->flags |= XT_CONNTRACK_ORIGDST; 368 break; 369 370 case '5': 371 xtables_check_inverse(optarg, &invert, &optind, 0); 372 373 if (invert) 374 sinfo->invflags |= XT_CONNTRACK_REPLSRC; 375 376 xtables_ipparse_any(argv[optind-1], &addrs, 377 &sinfo->sipmsk[IP_CT_DIR_REPLY], 378 &naddrs); 379 if(naddrs > 1) 380 exit_error(PARAMETER_PROBLEM, 381 "multiple IP addresses not allowed"); 382 383 if(naddrs == 1) { 384 sinfo->tuple[IP_CT_DIR_REPLY].src.ip = addrs[0].s_addr; 385 } 386 387 sinfo->flags |= XT_CONNTRACK_REPLSRC; 388 break; 389 390 case '6': 391 xtables_check_inverse(optarg, &invert, &optind, 0); 392 393 if (invert) 394 sinfo->invflags |= XT_CONNTRACK_REPLDST; 395 396 xtables_ipparse_any(argv[optind-1], &addrs, 397 &sinfo->dipmsk[IP_CT_DIR_REPLY], 398 &naddrs); 399 if(naddrs > 1) 400 exit_error(PARAMETER_PROBLEM, 401 "multiple IP addresses not allowed"); 402 403 if(naddrs == 1) { 404 sinfo->tuple[IP_CT_DIR_REPLY].dst.ip = addrs[0].s_addr; 405 } 406 407 sinfo->flags |= XT_CONNTRACK_REPLDST; 408 break; 409 410 case '7': 411 xtables_check_inverse(optarg, &invert, &optind, 0); 412 413 parse_statuses(argv[optind-1], sinfo); 414 if (invert) { 415 sinfo->invflags |= XT_CONNTRACK_STATUS; 416 } 417 sinfo->flags |= XT_CONNTRACK_STATUS; 418 break; 419 420 case '8': 421 xtables_check_inverse(optarg, &invert, &optind, 0); 422 423 parse_expires(argv[optind-1], sinfo); 424 if (invert) { 425 sinfo->invflags |= XT_CONNTRACK_EXPIRES; 426 } 427 sinfo->flags |= XT_CONNTRACK_EXPIRES; 428 break; 429 430 default: 431 return 0; 432 } 433 434 *flags = sinfo->flags; 435 return 1; 436} 437 438static int 439conntrack_mt_parse(int c, char **argv, int invert, unsigned int *flags, 440 struct xt_entry_match **match) 441{ 442 struct xt_conntrack_mtinfo1 *info = (void *)(*match)->data; 443 unsigned int port; 444 char *p; 445 446 switch (c) { 447 case '1': /* --ctstate */ 448 conntrack_ps_states(info, optarg); 449 info->match_flags |= XT_CONNTRACK_STATE; 450 if (invert) 451 info->invert_flags |= XT_CONNTRACK_STATE; 452 break; 453 454 case '2': /* --ctproto */ 455 /* Canonicalize into lower case */ 456 for (p = optarg; *p != '\0'; ++p) 457 *p = tolower(*p); 458 info->l4proto = parse_protocol(optarg); 459 460 if (info->l4proto == 0 && (info->invert_flags & XT_INV_PROTO)) 461 exit_error(PARAMETER_PROBLEM, "conntrack: rule would " 462 "never match protocol"); 463 464 info->match_flags |= XT_CONNTRACK_PROTO; 465 if (invert) 466 info->invert_flags |= XT_CONNTRACK_PROTO; 467 break; 468 469 case '7': /* --ctstatus */ 470 conntrack_ps_statuses(info, optarg); 471 info->match_flags |= XT_CONNTRACK_STATUS; 472 if (invert) 473 info->invert_flags |= XT_CONNTRACK_STATUS; 474 break; 475 476 case '8': /* --ctexpire */ 477 conntrack_ps_expires(info, optarg); 478 info->match_flags |= XT_CONNTRACK_EXPIRES; 479 if (invert) 480 info->invert_flags |= XT_CONNTRACK_EXPIRES; 481 break; 482 483 case 'a': /* --ctorigsrcport */ 484 if (!xtables_strtoui(optarg, NULL, &port, 0, UINT16_MAX)) 485 xtables_param_act(XTF_BAD_VALUE, "conntrack", 486 "--ctorigsrcport", optarg); 487 info->match_flags |= XT_CONNTRACK_ORIGSRC_PORT; 488 info->origsrc_port = htons(port); 489 if (invert) 490 info->invert_flags |= XT_CONNTRACK_ORIGSRC_PORT; 491 break; 492 493 case 'b': /* --ctorigdstport */ 494 if (!xtables_strtoui(optarg, NULL, &port, 0, UINT16_MAX)) 495 xtables_param_act(XTF_BAD_VALUE, "conntrack", 496 "--ctorigdstport", optarg); 497 info->match_flags |= XT_CONNTRACK_ORIGDST_PORT; 498 info->origdst_port = htons(port); 499 if (invert) 500 info->invert_flags |= XT_CONNTRACK_ORIGDST_PORT; 501 break; 502 503 case 'c': /* --ctreplsrcport */ 504 if (!xtables_strtoui(optarg, NULL, &port, 0, UINT16_MAX)) 505 xtables_param_act(XTF_BAD_VALUE, "conntrack", 506 "--ctreplsrcport", optarg); 507 info->match_flags |= XT_CONNTRACK_REPLSRC_PORT; 508 info->replsrc_port = htons(port); 509 if (invert) 510 info->invert_flags |= XT_CONNTRACK_REPLSRC_PORT; 511 break; 512 513 case 'd': /* --ctrepldstport */ 514 if (!xtables_strtoui(optarg, NULL, &port, 0, UINT16_MAX)) 515 xtables_param_act(XTF_BAD_VALUE, "conntrack", 516 "--ctrepldstport", optarg); 517 info->match_flags |= XT_CONNTRACK_REPLDST_PORT; 518 info->repldst_port = htons(port); 519 if (invert) 520 info->invert_flags |= XT_CONNTRACK_REPLDST_PORT; 521 break; 522 523 case 'e': /* --ctdir */ 524 xtables_param_act(XTF_NO_INVERT, "conntrack", "--ctdir", invert); 525 if (strcasecmp(optarg, "ORIGINAL") == 0) { 526 info->match_flags |= XT_CONNTRACK_DIRECTION; 527 info->invert_flags &= ~XT_CONNTRACK_DIRECTION; 528 } else if (strcasecmp(optarg, "REPLY") == 0) { 529 info->match_flags |= XT_CONNTRACK_DIRECTION; 530 info->invert_flags |= XT_CONNTRACK_DIRECTION; 531 } else { 532 xtables_param_act(XTF_BAD_VALUE, "conntrack", "--ctdir", optarg); 533 } 534 break; 535 536 default: 537 return false; 538 } 539 540 *flags = info->match_flags; 541 return true; 542} 543 544static int 545conntrack_mt4_parse(int c, char **argv, int invert, unsigned int *flags, 546 const void *entry, struct xt_entry_match **match) 547{ 548 struct xt_conntrack_mtinfo1 *info = (void *)(*match)->data; 549 struct in_addr *addr = NULL; 550 unsigned int naddrs = 0; 551 552 switch (c) { 553 case '3': /* --ctorigsrc */ 554 xtables_ipparse_any(optarg, &addr, &info->origsrc_mask.in, 555 &naddrs); 556 if (naddrs > 1) 557 exit_error(PARAMETER_PROBLEM, 558 "multiple IP addresses not allowed"); 559 if (naddrs == 1) 560 memcpy(&info->origsrc_addr.in, addr, sizeof(*addr)); 561 info->match_flags |= XT_CONNTRACK_ORIGSRC; 562 if (invert) 563 info->invert_flags |= XT_CONNTRACK_ORIGSRC; 564 break; 565 566 case '4': /* --ctorigdst */ 567 xtables_ipparse_any(optarg, &addr, &info->origdst_mask.in, 568 &naddrs); 569 if (naddrs > 1) 570 exit_error(PARAMETER_PROBLEM, 571 "multiple IP addresses not allowed"); 572 if (naddrs == 1) 573 memcpy(&info->origdst_addr.in, addr, sizeof(*addr)); 574 info->match_flags |= XT_CONNTRACK_ORIGDST; 575 if (invert) 576 info->invert_flags |= XT_CONNTRACK_ORIGDST; 577 break; 578 579 case '5': /* --ctreplsrc */ 580 xtables_ipparse_any(optarg, &addr, &info->replsrc_mask.in, 581 &naddrs); 582 if (naddrs > 1) 583 exit_error(PARAMETER_PROBLEM, 584 "multiple IP addresses not allowed"); 585 if (naddrs == 1) 586 memcpy(&info->replsrc_addr.in, addr, sizeof(*addr)); 587 info->match_flags |= XT_CONNTRACK_REPLSRC; 588 if (invert) 589 info->invert_flags |= XT_CONNTRACK_REPLSRC; 590 break; 591 592 case '6': /* --ctrepldst */ 593 xtables_ipparse_any(optarg, &addr, &info->repldst_mask.in, 594 &naddrs); 595 if (naddrs > 1) 596 exit_error(PARAMETER_PROBLEM, 597 "multiple IP addresses not allowed"); 598 if (naddrs == 1) 599 memcpy(&info->repldst_addr.in, addr, sizeof(*addr)); 600 info->match_flags |= XT_CONNTRACK_REPLDST; 601 if (invert) 602 info->invert_flags |= XT_CONNTRACK_REPLDST; 603 break; 604 605 606 default: 607 return conntrack_mt_parse(c, argv, invert, flags, match); 608 } 609 610 *flags = info->match_flags; 611 return true; 612} 613 614static int 615conntrack_mt6_parse(int c, char **argv, int invert, unsigned int *flags, 616 const void *entry, struct xt_entry_match **match) 617{ 618 struct xt_conntrack_mtinfo1 *info = (void *)(*match)->data; 619 struct in6_addr *addr = NULL; 620 unsigned int naddrs = 0; 621 622 switch (c) { 623 case '3': /* --ctorigsrc */ 624 xtables_ip6parse_any(optarg, &addr, 625 &info->origsrc_mask.in6, &naddrs); 626 if (naddrs > 1) 627 exit_error(PARAMETER_PROBLEM, 628 "multiple IP addresses not allowed"); 629 if (naddrs == 1) 630 memcpy(&info->origsrc_addr.in6, addr, sizeof(*addr)); 631 info->match_flags |= XT_CONNTRACK_ORIGSRC; 632 if (invert) 633 info->invert_flags |= XT_CONNTRACK_ORIGSRC; 634 break; 635 636 case '4': /* --ctorigdst */ 637 xtables_ip6parse_any(optarg, &addr, 638 &info->origdst_mask.in6, &naddrs); 639 if (naddrs > 1) 640 exit_error(PARAMETER_PROBLEM, 641 "multiple IP addresses not allowed"); 642 if (naddrs == 1) 643 memcpy(&info->origdst_addr.in, addr, sizeof(*addr)); 644 info->match_flags |= XT_CONNTRACK_ORIGDST; 645 if (invert) 646 info->invert_flags |= XT_CONNTRACK_ORIGDST; 647 break; 648 649 case '5': /* --ctreplsrc */ 650 xtables_ip6parse_any(optarg, &addr, 651 &info->replsrc_mask.in6, &naddrs); 652 if (naddrs > 1) 653 exit_error(PARAMETER_PROBLEM, 654 "multiple IP addresses not allowed"); 655 if (naddrs == 1) 656 memcpy(&info->replsrc_addr.in, addr, sizeof(*addr)); 657 info->match_flags |= XT_CONNTRACK_REPLSRC; 658 if (invert) 659 info->invert_flags |= XT_CONNTRACK_REPLSRC; 660 break; 661 662 case '6': /* --ctrepldst */ 663 xtables_ip6parse_any(optarg, &addr, 664 &info->repldst_mask.in6, &naddrs); 665 if (naddrs > 1) 666 exit_error(PARAMETER_PROBLEM, 667 "multiple IP addresses not allowed"); 668 if (naddrs == 1) 669 memcpy(&info->repldst_addr.in, addr, sizeof(*addr)); 670 info->match_flags |= XT_CONNTRACK_REPLDST; 671 if (invert) 672 info->invert_flags |= XT_CONNTRACK_REPLDST; 673 break; 674 675 676 default: 677 return conntrack_mt_parse(c, argv, invert, flags, match); 678 } 679 680 *flags = info->match_flags; 681 return true; 682} 683 684static void conntrack_mt_check(unsigned int flags) 685{ 686 if (flags == 0) 687 exit_error(PARAMETER_PROBLEM, "conntrack: At least one option " 688 "is required"); 689} 690 691static void 692print_state(unsigned int statemask) 693{ 694 const char *sep = ""; 695 696 if (statemask & XT_CONNTRACK_STATE_INVALID) { 697 printf("%sINVALID", sep); 698 sep = ","; 699 } 700 if (statemask & XT_CONNTRACK_STATE_BIT(IP_CT_NEW)) { 701 printf("%sNEW", sep); 702 sep = ","; 703 } 704 if (statemask & XT_CONNTRACK_STATE_BIT(IP_CT_RELATED)) { 705 printf("%sRELATED", sep); 706 sep = ","; 707 } 708 if (statemask & XT_CONNTRACK_STATE_BIT(IP_CT_ESTABLISHED)) { 709 printf("%sESTABLISHED", sep); 710 sep = ","; 711 } 712 if (statemask & XT_CONNTRACK_STATE_UNTRACKED) { 713 printf("%sUNTRACKED", sep); 714 sep = ","; 715 } 716 if (statemask & XT_CONNTRACK_STATE_SNAT) { 717 printf("%sSNAT", sep); 718 sep = ","; 719 } 720 if (statemask & XT_CONNTRACK_STATE_DNAT) { 721 printf("%sDNAT", sep); 722 sep = ","; 723 } 724 printf(" "); 725} 726 727static void 728print_status(unsigned int statusmask) 729{ 730 const char *sep = ""; 731 732 if (statusmask & IPS_EXPECTED) { 733 printf("%sEXPECTED", sep); 734 sep = ","; 735 } 736 if (statusmask & IPS_SEEN_REPLY) { 737 printf("%sSEEN_REPLY", sep); 738 sep = ","; 739 } 740 if (statusmask & IPS_ASSURED) { 741 printf("%sASSURED", sep); 742 sep = ","; 743 } 744 if (statusmask & IPS_CONFIRMED) { 745 printf("%sCONFIRMED", sep); 746 sep = ","; 747 } 748 if (statusmask == 0) 749 printf("%sNONE", sep); 750 printf(" "); 751} 752 753static void 754conntrack_dump_addr(const union nf_inet_addr *addr, 755 const union nf_inet_addr *mask, 756 unsigned int family, bool numeric) 757{ 758 if (family == NFPROTO_IPV4) { 759 if (!numeric && addr->ip == 0) { 760 printf("anywhere "); 761 return; 762 } 763 if (numeric) 764 printf("%s ", xtables_ipaddr_to_numeric(&addr->in)); 765 else 766 printf("%s ", xtables_ipaddr_to_anyname(&addr->in)); 767 } else if (family == NFPROTO_IPV6) { 768 if (!numeric && addr->ip6[0] == 0 && addr->ip6[1] == 0 && 769 addr->ip6[2] == 0 && addr->ip6[3] == 0) { 770 printf("anywhere "); 771 return; 772 } 773 if (numeric) 774 printf("%s ", xtables_ip6addr_to_numeric(&addr->in6)); 775 else 776 printf("%s ", xtables_ip6addr_to_anyname(&addr->in6)); 777 } 778} 779 780static void 781print_addr(struct in_addr *addr, struct in_addr *mask, int inv, int numeric) 782{ 783 char buf[BUFSIZ]; 784 785 if (inv) 786 printf("! "); 787 788 if (mask->s_addr == 0L && !numeric) 789 printf("%s ", "anywhere"); 790 else { 791 if (numeric) 792 strcpy(buf, xtables_ipaddr_to_numeric(addr)); 793 else 794 strcpy(buf, xtables_ipaddr_to_anyname(addr)); 795 strcat(buf, xtables_ipmask_to_numeric(mask)); 796 printf("%s ", buf); 797 } 798} 799 800static void 801matchinfo_print(const void *ip, const struct xt_entry_match *match, int numeric, const char *optpfx) 802{ 803 struct xt_conntrack_info *sinfo = (void *)match->data; 804 805 if(sinfo->flags & XT_CONNTRACK_STATE) { 806 if (sinfo->invflags & XT_CONNTRACK_STATE) 807 printf("! "); 808 printf("%sctstate ", optpfx); 809 print_state(sinfo->statemask); 810 } 811 812 if(sinfo->flags & XT_CONNTRACK_PROTO) { 813 if (sinfo->invflags & XT_CONNTRACK_PROTO) 814 printf("! "); 815 printf("%sctproto ", optpfx); 816 printf("%u ", sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum); 817 } 818 819 if(sinfo->flags & XT_CONNTRACK_ORIGSRC) { 820 if (sinfo->invflags & XT_CONNTRACK_ORIGSRC) 821 printf("! "); 822 printf("%sctorigsrc ", optpfx); 823 824 print_addr( 825 (struct in_addr *)&sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip, 826 &sinfo->sipmsk[IP_CT_DIR_ORIGINAL], 827 false, 828 numeric); 829 } 830 831 if(sinfo->flags & XT_CONNTRACK_ORIGDST) { 832 if (sinfo->invflags & XT_CONNTRACK_ORIGDST) 833 printf("! "); 834 printf("%sctorigdst ", optpfx); 835 836 print_addr( 837 (struct in_addr *)&sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip, 838 &sinfo->dipmsk[IP_CT_DIR_ORIGINAL], 839 false, 840 numeric); 841 } 842 843 if(sinfo->flags & XT_CONNTRACK_REPLSRC) { 844 if (sinfo->invflags & XT_CONNTRACK_REPLSRC) 845 printf("! "); 846 printf("%sctreplsrc ", optpfx); 847 848 print_addr( 849 (struct in_addr *)&sinfo->tuple[IP_CT_DIR_REPLY].src.ip, 850 &sinfo->sipmsk[IP_CT_DIR_REPLY], 851 false, 852 numeric); 853 } 854 855 if(sinfo->flags & XT_CONNTRACK_REPLDST) { 856 if (sinfo->invflags & XT_CONNTRACK_REPLDST) 857 printf("! "); 858 printf("%sctrepldst ", optpfx); 859 860 print_addr( 861 (struct in_addr *)&sinfo->tuple[IP_CT_DIR_REPLY].dst.ip, 862 &sinfo->dipmsk[IP_CT_DIR_REPLY], 863 false, 864 numeric); 865 } 866 867 if(sinfo->flags & XT_CONNTRACK_STATUS) { 868 if (sinfo->invflags & XT_CONNTRACK_STATUS) 869 printf("! "); 870 printf("%sctstatus ", optpfx); 871 print_status(sinfo->statusmask); 872 } 873 874 if(sinfo->flags & XT_CONNTRACK_EXPIRES) { 875 if (sinfo->invflags & XT_CONNTRACK_EXPIRES) 876 printf("! "); 877 printf("%sctexpire ", optpfx); 878 879 if (sinfo->expires_max == sinfo->expires_min) 880 printf("%lu ", sinfo->expires_min); 881 else 882 printf("%lu:%lu ", sinfo->expires_min, sinfo->expires_max); 883 } 884 885 if (sinfo->flags & XT_CONNTRACK_DIRECTION) { 886 if (sinfo->invflags & XT_CONNTRACK_DIRECTION) 887 printf("%sctdir REPLY", optpfx); 888 else 889 printf("%sctdir ORIGINAL", optpfx); 890 } 891 892} 893 894static void 895conntrack_dump(const struct xt_conntrack_mtinfo1 *info, const char *prefix, 896 unsigned int family, bool numeric) 897{ 898 if (info->match_flags & XT_CONNTRACK_STATE) { 899 if (info->invert_flags & XT_CONNTRACK_STATE) 900 printf("! "); 901 printf("%sctstate ", prefix); 902 print_state(info->state_mask); 903 } 904 905 if (info->match_flags & XT_CONNTRACK_PROTO) { 906 if (info->invert_flags & XT_CONNTRACK_PROTO) 907 printf("! "); 908 printf("%sctproto %u ", prefix, info->l4proto); 909 } 910 911 if (info->match_flags & XT_CONNTRACK_ORIGSRC) { 912 if (info->invert_flags & XT_CONNTRACK_PROTO) 913 printf("! "); 914 printf("%sctorigsrc ", prefix); 915 conntrack_dump_addr(&info->origsrc_addr, &info->origsrc_mask, 916 family, numeric); 917 } 918 919 if (info->match_flags & XT_CONNTRACK_ORIGDST) { 920 if (info->invert_flags & XT_CONNTRACK_PROTO) 921 printf("! "); 922 printf("%sctorigdst ", prefix); 923 conntrack_dump_addr(&info->origdst_addr, &info->origdst_mask, 924 family, numeric); 925 } 926 927 if (info->match_flags & XT_CONNTRACK_REPLSRC) { 928 if (info->invert_flags & XT_CONNTRACK_PROTO) 929 printf("! "); 930 printf("%sctreplsrc ", prefix); 931 conntrack_dump_addr(&info->replsrc_addr, &info->replsrc_mask, 932 family, numeric); 933 } 934 935 if (info->match_flags & XT_CONNTRACK_REPLDST) { 936 if (info->invert_flags & XT_CONNTRACK_PROTO) 937 printf("! "); 938 printf("%sctrepldst ", prefix); 939 conntrack_dump_addr(&info->repldst_addr, &info->repldst_mask, 940 family, numeric); 941 } 942 943 if (info->match_flags & XT_CONNTRACK_ORIGSRC_PORT) { 944 if (info->invert_flags & XT_CONNTRACK_ORIGSRC_PORT) 945 printf("! "); 946 printf("%sctorigsrcport %u ", prefix, 947 ntohs(info->origsrc_port)); 948 } 949 950 if (info->match_flags & XT_CONNTRACK_ORIGDST_PORT) { 951 if (info->invert_flags & XT_CONNTRACK_ORIGDST_PORT) 952 printf("! "); 953 printf("%sctorigdstport %u ", prefix, 954 ntohs(info->origdst_port)); 955 } 956 957 if (info->match_flags & XT_CONNTRACK_REPLSRC_PORT) { 958 if (info->invert_flags & XT_CONNTRACK_REPLSRC_PORT) 959 printf("! "); 960 printf("%sctreplsrcport %u ", prefix, 961 ntohs(info->replsrc_port)); 962 } 963 964 if (info->match_flags & XT_CONNTRACK_REPLDST_PORT) { 965 if (info->invert_flags & XT_CONNTRACK_REPLDST_PORT) 966 printf("! "); 967 printf("%sctrepldstport %u ", prefix, 968 ntohs(info->repldst_port)); 969 } 970 971 if (info->match_flags & XT_CONNTRACK_STATUS) { 972 if (info->invert_flags & XT_CONNTRACK_STATUS) 973 printf("! "); 974 printf("%sctstatus ", prefix); 975 print_status(info->status_mask); 976 } 977 978 if (info->match_flags & XT_CONNTRACK_EXPIRES) { 979 if (info->invert_flags & XT_CONNTRACK_EXPIRES) 980 printf("! "); 981 printf("%sctexpire ", prefix); 982 983 if (info->expires_max == info->expires_min) 984 printf("%u ", (unsigned int)info->expires_min); 985 else 986 printf("%u:%u ", (unsigned int)info->expires_min, 987 (unsigned int)info->expires_max); 988 } 989 990 if (info->match_flags & XT_CONNTRACK_DIRECTION) { 991 if (info->invert_flags & XT_CONNTRACK_DIRECTION) 992 printf("%sctdir REPLY", prefix); 993 else 994 printf("%sctdir ORIGINAL", prefix); 995 } 996} 997 998static void conntrack_print(const void *ip, const struct xt_entry_match *match, 999 int numeric) 1000{ 1001 matchinfo_print(ip, match, numeric, ""); 1002} 1003 1004static void 1005conntrack_mt_print(const void *ip, const struct xt_entry_match *match, 1006 int numeric) 1007{ 1008 conntrack_dump((const void *)match->data, "", NFPROTO_IPV4, numeric); 1009} 1010 1011static void 1012conntrack_mt6_print(const void *ip, const struct xt_entry_match *match, 1013 int numeric) 1014{ 1015 conntrack_dump((const void *)match->data, "", NFPROTO_IPV6, numeric); 1016} 1017 1018static void conntrack_save(const void *ip, const struct xt_entry_match *match) 1019{ 1020 matchinfo_print(ip, match, 1, "--"); 1021} 1022 1023static void conntrack_mt_save(const void *ip, 1024 const struct xt_entry_match *match) 1025{ 1026 conntrack_dump((const void *)match->data, "--", NFPROTO_IPV4, true); 1027} 1028 1029static void conntrack_mt6_save(const void *ip, 1030 const struct xt_entry_match *match) 1031{ 1032 conntrack_dump((const void *)match->data, "--", NFPROTO_IPV6, true); 1033} 1034 1035static struct xtables_match conntrack_match = { 1036 .version = XTABLES_VERSION, 1037 .name = "conntrack", 1038 .revision = 0, 1039 .family = NFPROTO_IPV4, 1040 .size = XT_ALIGN(sizeof(struct xt_conntrack_info)), 1041 .userspacesize = XT_ALIGN(sizeof(struct xt_conntrack_info)), 1042 .help = conntrack_mt_help, 1043 .parse = conntrack_parse, 1044 .final_check = conntrack_mt_check, 1045 .print = conntrack_print, 1046 .save = conntrack_save, 1047 .extra_opts = conntrack_mt_opts_v0, 1048}; 1049 1050static struct xtables_match conntrack_mt_reg = { 1051 .version = XTABLES_VERSION, 1052 .name = "conntrack", 1053 .revision = 1, 1054 .family = NFPROTO_IPV4, 1055 .size = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo1)), 1056 .userspacesize = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo1)), 1057 .help = conntrack_mt_help, 1058 .parse = conntrack_mt4_parse, 1059 .final_check = conntrack_mt_check, 1060 .print = conntrack_mt_print, 1061 .save = conntrack_mt_save, 1062 .extra_opts = conntrack_mt_opts, 1063}; 1064 1065static struct xtables_match conntrack_mt6_reg = { 1066 .version = XTABLES_VERSION, 1067 .name = "conntrack", 1068 .revision = 1, 1069 .family = NFPROTO_IPV6, 1070 .size = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo1)), 1071 .userspacesize = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo1)), 1072 .help = conntrack_mt_help, 1073 .parse = conntrack_mt6_parse, 1074 .final_check = conntrack_mt_check, 1075 .print = conntrack_mt6_print, 1076 .save = conntrack_mt6_save, 1077 .extra_opts = conntrack_mt_opts, 1078}; 1079 1080void _init(void) 1081{ 1082 xtables_register_match(&conntrack_match); 1083 xtables_register_match(&conntrack_mt_reg); 1084 xtables_register_match(&conntrack_mt6_reg); 1085} 1086