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