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