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