1 /* 2 * libxt_conntrack 3 * Shared library add-on to iptables for conntrack matching support. 4 * 5 * GPL (C) 2001 Marc Boucher (marc (at) mbsi.ca). 6 * Copyright CC Computer Consultants GmbH, 2007 - 2008 7 * Jan Engelhardt <jengelh (at) 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/xt_state.h> 17 #include <linux/netfilter/nf_conntrack_common.h> 18 #ifndef XT_STATE_UNTRACKED 19 #define XT_STATE_UNTRACKED (1 << (IP_CT_NUMBER + 1)) 20 #endif 21 22 struct ip_conntrack_old_tuple { 23 struct { 24 __be32 ip; 25 union { 26 __u16 all; 27 } u; 28 } src; 29 30 struct { 31 __be32 ip; 32 union { 33 __u16 all; 34 } u; 35 36 /* The protocol. */ 37 __u16 protonum; 38 } dst; 39 }; 40 41 struct xt_conntrack_info { 42 unsigned int statemask, statusmask; 43 44 struct ip_conntrack_old_tuple tuple[IP_CT_DIR_MAX]; 45 struct in_addr sipmsk[IP_CT_DIR_MAX], dipmsk[IP_CT_DIR_MAX]; 46 47 unsigned long expires_min, expires_max; 48 49 /* Flags word */ 50 uint8_t flags; 51 /* Inverse flags */ 52 uint8_t invflags; 53 }; 54 55 enum { 56 O_CTSTATE = 0, 57 O_CTPROTO, 58 O_CTORIGSRC, 59 O_CTORIGDST, 60 O_CTREPLSRC, 61 O_CTREPLDST, 62 O_CTORIGSRCPORT, 63 O_CTORIGDSTPORT, 64 O_CTREPLSRCPORT, 65 O_CTREPLDSTPORT, 66 O_CTSTATUS, 67 O_CTEXPIRE, 68 O_CTDIR, 69 }; 70 71 static void conntrack_mt_help(void) 72 { 73 printf( 74 "conntrack match options:\n" 75 "[!] --ctstate {INVALID|ESTABLISHED|NEW|RELATED|UNTRACKED|SNAT|DNAT}[,...]\n" 76 " State(s) to match\n" 77 "[!] --ctproto proto Protocol to match; by number or name, e.g. \"tcp\"\n" 78 "[!] --ctorigsrc address[/mask]\n" 79 "[!] --ctorigdst address[/mask]\n" 80 "[!] --ctreplsrc address[/mask]\n" 81 "[!] --ctrepldst address[/mask]\n" 82 " Original/Reply source/destination address\n" 83 "[!] --ctorigsrcport port\n" 84 "[!] --ctorigdstport port\n" 85 "[!] --ctreplsrcport port\n" 86 "[!] --ctrepldstport port\n" 87 " TCP/UDP/SCTP orig./reply source/destination port\n" 88 "[!] --ctstatus {NONE|EXPECTED|SEEN_REPLY|ASSURED|CONFIRMED}[,...]\n" 89 " Status(es) to match\n" 90 "[!] --ctexpire time[:time] Match remaining lifetime in seconds against\n" 91 " value or range of values (inclusive)\n" 92 " --ctdir {ORIGINAL|REPLY} Flow direction of packet\n"); 93 } 94 95 #define s struct xt_conntrack_info /* for v0 */ 96 static const struct xt_option_entry conntrack_mt_opts_v0[] = { 97 {.name = "ctstate", .id = O_CTSTATE, .type = XTTYPE_STRING, 98 .flags = XTOPT_INVERT}, 99 {.name = "ctproto", .id = O_CTPROTO, .type = XTTYPE_PROTOCOL, 100 .flags = XTOPT_INVERT}, 101 {.name = "ctorigsrc", .id = O_CTORIGSRC, .type = XTTYPE_HOST, 102 .flags = XTOPT_INVERT}, 103 {.name = "ctorigdst", .id = O_CTORIGDST, .type = XTTYPE_HOST, 104 .flags = XTOPT_INVERT}, 105 {.name = "ctreplsrc", .id = O_CTREPLSRC, .type = XTTYPE_HOST, 106 .flags = XTOPT_INVERT}, 107 {.name = "ctrepldst", .id = O_CTREPLDST, .type = XTTYPE_HOST, 108 .flags = XTOPT_INVERT}, 109 {.name = "ctstatus", .id = O_CTSTATUS, .type = XTTYPE_STRING, 110 .flags = XTOPT_INVERT}, 111 {.name = "ctexpire", .id = O_CTEXPIRE, .type = XTTYPE_UINT32RC, 112 .flags = XTOPT_INVERT}, 113 XTOPT_TABLEEND, 114 }; 115 #undef s 116 117 #define s struct xt_conntrack_mtinfo2 118 /* We exploit the fact that v1-v2 share the same xt_o_e layout */ 119 static const struct xt_option_entry conntrack2_mt_opts[] = { 120 {.name = "ctstate", .id = O_CTSTATE, .type = XTTYPE_STRING, 121 .flags = XTOPT_INVERT}, 122 {.name = "ctproto", .id = O_CTPROTO, .type = XTTYPE_PROTOCOL, 123 .flags = XTOPT_INVERT}, 124 {.name = "ctorigsrc", .id = O_CTORIGSRC, .type = XTTYPE_HOSTMASK, 125 .flags = XTOPT_INVERT}, 126 {.name = "ctorigdst", .id = O_CTORIGDST, .type = XTTYPE_HOSTMASK, 127 .flags = XTOPT_INVERT}, 128 {.name = "ctreplsrc", .id = O_CTREPLSRC, .type = XTTYPE_HOSTMASK, 129 .flags = XTOPT_INVERT}, 130 {.name = "ctrepldst", .id = O_CTREPLDST, .type = XTTYPE_HOSTMASK, 131 .flags = XTOPT_INVERT}, 132 {.name = "ctstatus", .id = O_CTSTATUS, .type = XTTYPE_STRING, 133 .flags = XTOPT_INVERT}, 134 {.name = "ctexpire", .id = O_CTEXPIRE, .type = XTTYPE_UINT32RC, 135 .flags = XTOPT_INVERT}, 136 /* 137 * Rev 1 and 2 only store one port, and we would normally use 138 * %XTTYPE_PORT (rather than %XTTYPE_PORTRC) for that. The resulting 139 * error message - in case a user passed a range nevertheless - 140 * "port 22:23 resolved to nothing" is not quite as useful as using 141 * %XTTYPE_PORTC and libxt_conntrack's own range test. 142 */ 143 {.name = "ctorigsrcport", .id = O_CTORIGSRCPORT, .type = XTTYPE_PORTRC, 144 .flags = XTOPT_INVERT | XTOPT_NBO}, 145 {.name = "ctorigdstport", .id = O_CTORIGDSTPORT, .type = XTTYPE_PORTRC, 146 .flags = XTOPT_INVERT | XTOPT_NBO}, 147 {.name = "ctreplsrcport", .id = O_CTREPLSRCPORT, .type = XTTYPE_PORTRC, 148 .flags = XTOPT_INVERT | XTOPT_NBO}, 149 {.name = "ctrepldstport", .id = O_CTREPLDSTPORT, .type = XTTYPE_PORTRC, 150 .flags = XTOPT_INVERT | XTOPT_NBO}, 151 {.name = "ctdir", .id = O_CTDIR, .type = XTTYPE_STRING}, 152 XTOPT_TABLEEND, 153 }; 154 #undef s 155 156 #define s struct xt_conntrack_mtinfo3 157 /* Difference from v2 is the non-NBO form. */ 158 static const struct xt_option_entry conntrack3_mt_opts[] = { 159 {.name = "ctstate", .id = O_CTSTATE, .type = XTTYPE_STRING, 160 .flags = XTOPT_INVERT}, 161 {.name = "ctproto", .id = O_CTPROTO, .type = XTTYPE_PROTOCOL, 162 .flags = XTOPT_INVERT}, 163 {.name = "ctorigsrc", .id = O_CTORIGSRC, .type = XTTYPE_HOSTMASK, 164 .flags = XTOPT_INVERT}, 165 {.name = "ctorigdst", .id = O_CTORIGDST, .type = XTTYPE_HOSTMASK, 166 .flags = XTOPT_INVERT}, 167 {.name = "ctreplsrc", .id = O_CTREPLSRC, .type = XTTYPE_HOSTMASK, 168 .flags = XTOPT_INVERT}, 169 {.name = "ctrepldst", .id = O_CTREPLDST, .type = XTTYPE_HOSTMASK, 170 .flags = XTOPT_INVERT}, 171 {.name = "ctstatus", .id = O_CTSTATUS, .type = XTTYPE_STRING, 172 .flags = XTOPT_INVERT}, 173 {.name = "ctexpire", .id = O_CTEXPIRE, .type = XTTYPE_UINT32RC, 174 .flags = XTOPT_INVERT}, 175 {.name = "ctorigsrcport", .id = O_CTORIGSRCPORT, .type = XTTYPE_PORTRC, 176 .flags = XTOPT_INVERT}, 177 {.name = "ctorigdstport", .id = O_CTORIGDSTPORT, .type = XTTYPE_PORTRC, 178 .flags = XTOPT_INVERT}, 179 {.name = "ctreplsrcport", .id = O_CTREPLSRCPORT, .type = XTTYPE_PORTRC, 180 .flags = XTOPT_INVERT}, 181 {.name = "ctrepldstport", .id = O_CTREPLDSTPORT, .type = XTTYPE_PORTRC, 182 .flags = XTOPT_INVERT}, 183 {.name = "ctdir", .id = O_CTDIR, .type = XTTYPE_STRING}, 184 XTOPT_TABLEEND, 185 }; 186 #undef s 187 188 static int 189 parse_state(const char *state, size_t len, struct xt_conntrack_info *sinfo) 190 { 191 if (strncasecmp(state, "INVALID", len) == 0) 192 sinfo->statemask |= XT_CONNTRACK_STATE_INVALID; 193 else if (strncasecmp(state, "NEW", len) == 0) 194 sinfo->statemask |= XT_CONNTRACK_STATE_BIT(IP_CT_NEW); 195 else if (strncasecmp(state, "ESTABLISHED", len) == 0) 196 sinfo->statemask |= XT_CONNTRACK_STATE_BIT(IP_CT_ESTABLISHED); 197 else if (strncasecmp(state, "RELATED", len) == 0) 198 sinfo->statemask |= XT_CONNTRACK_STATE_BIT(IP_CT_RELATED); 199 else if (strncasecmp(state, "UNTRACKED", len) == 0) 200 sinfo->statemask |= XT_CONNTRACK_STATE_UNTRACKED; 201 else if (strncasecmp(state, "SNAT", len) == 0) 202 sinfo->statemask |= XT_CONNTRACK_STATE_SNAT; 203 else if (strncasecmp(state, "DNAT", len) == 0) 204 sinfo->statemask |= XT_CONNTRACK_STATE_DNAT; 205 else 206 return 0; 207 return 1; 208 } 209 210 static void 211 parse_states(const char *arg, struct xt_conntrack_info *sinfo) 212 { 213 const char *comma; 214 215 while ((comma = strchr(arg, ',')) != NULL) { 216 if (comma == arg || !parse_state(arg, comma-arg, sinfo)) 217 xtables_error(PARAMETER_PROBLEM, "Bad ctstate \"%s\"", arg); 218 arg = comma+1; 219 } 220 if (!*arg) 221 xtables_error(PARAMETER_PROBLEM, "\"--ctstate\" requires a list of " 222 "states with no spaces, e.g. " 223 "ESTABLISHED,RELATED"); 224 if (strlen(arg) == 0 || !parse_state(arg, strlen(arg), sinfo)) 225 xtables_error(PARAMETER_PROBLEM, "Bad ctstate \"%s\"", arg); 226 } 227 228 static bool 229 conntrack_ps_state(struct xt_conntrack_mtinfo3 *info, const char *state, 230 size_t z) 231 { 232 if (strncasecmp(state, "INVALID", z) == 0) 233 info->state_mask |= XT_CONNTRACK_STATE_INVALID; 234 else if (strncasecmp(state, "NEW", z) == 0) 235 info->state_mask |= XT_CONNTRACK_STATE_BIT(IP_CT_NEW); 236 else if (strncasecmp(state, "ESTABLISHED", z) == 0) 237 info->state_mask |= XT_CONNTRACK_STATE_BIT(IP_CT_ESTABLISHED); 238 else if (strncasecmp(state, "RELATED", z) == 0) 239 info->state_mask |= XT_CONNTRACK_STATE_BIT(IP_CT_RELATED); 240 else if (strncasecmp(state, "UNTRACKED", z) == 0) 241 info->state_mask |= XT_CONNTRACK_STATE_UNTRACKED; 242 else if (strncasecmp(state, "SNAT", z) == 0) 243 info->state_mask |= XT_CONNTRACK_STATE_SNAT; 244 else if (strncasecmp(state, "DNAT", z) == 0) 245 info->state_mask |= XT_CONNTRACK_STATE_DNAT; 246 else 247 return false; 248 return true; 249 } 250 251 static void 252 conntrack_ps_states(struct xt_conntrack_mtinfo3 *info, const char *arg) 253 { 254 const char *comma; 255 256 while ((comma = strchr(arg, ',')) != NULL) { 257 if (comma == arg || !conntrack_ps_state(info, arg, comma - arg)) 258 xtables_error(PARAMETER_PROBLEM, 259 "Bad ctstate \"%s\"", arg); 260 arg = comma + 1; 261 } 262 263 if (strlen(arg) == 0 || !conntrack_ps_state(info, arg, strlen(arg))) 264 xtables_error(PARAMETER_PROBLEM, "Bad ctstate \"%s\"", arg); 265 } 266 267 static int 268 parse_status(const char *status, size_t len, struct xt_conntrack_info *sinfo) 269 { 270 if (strncasecmp(status, "NONE", len) == 0) 271 sinfo->statusmask |= 0; 272 else if (strncasecmp(status, "EXPECTED", len) == 0) 273 sinfo->statusmask |= IPS_EXPECTED; 274 else if (strncasecmp(status, "SEEN_REPLY", len) == 0) 275 sinfo->statusmask |= IPS_SEEN_REPLY; 276 else if (strncasecmp(status, "ASSURED", len) == 0) 277 sinfo->statusmask |= IPS_ASSURED; 278 #ifdef IPS_CONFIRMED 279 else if (strncasecmp(status, "CONFIRMED", len) == 0) 280 sinfo->statusmask |= IPS_CONFIRMED; 281 #endif 282 else 283 return 0; 284 return 1; 285 } 286 287 static void 288 parse_statuses(const char *arg, struct xt_conntrack_info *sinfo) 289 { 290 const char *comma; 291 292 while ((comma = strchr(arg, ',')) != NULL) { 293 if (comma == arg || !parse_status(arg, comma-arg, sinfo)) 294 xtables_error(PARAMETER_PROBLEM, "Bad ctstatus \"%s\"", arg); 295 arg = comma+1; 296 } 297 298 if (strlen(arg) == 0 || !parse_status(arg, strlen(arg), sinfo)) 299 xtables_error(PARAMETER_PROBLEM, "Bad ctstatus \"%s\"", arg); 300 } 301 302 static bool 303 conntrack_ps_status(struct xt_conntrack_mtinfo3 *info, const char *status, 304 size_t z) 305 { 306 if (strncasecmp(status, "NONE", z) == 0) 307 info->status_mask |= 0; 308 else if (strncasecmp(status, "EXPECTED", z) == 0) 309 info->status_mask |= IPS_EXPECTED; 310 else if (strncasecmp(status, "SEEN_REPLY", z) == 0) 311 info->status_mask |= IPS_SEEN_REPLY; 312 else if (strncasecmp(status, "ASSURED", z) == 0) 313 info->status_mask |= IPS_ASSURED; 314 else if (strncasecmp(status, "CONFIRMED", z) == 0) 315 info->status_mask |= IPS_CONFIRMED; 316 else 317 return false; 318 return true; 319 } 320 321 static void 322 conntrack_ps_statuses(struct xt_conntrack_mtinfo3 *info, const char *arg) 323 { 324 const char *comma; 325 326 while ((comma = strchr(arg, ',')) != NULL) { 327 if (comma == arg || !conntrack_ps_status(info, arg, comma - arg)) 328 xtables_error(PARAMETER_PROBLEM, 329 "Bad ctstatus \"%s\"", arg); 330 arg = comma + 1; 331 } 332 333 if (strlen(arg) == 0 || !conntrack_ps_status(info, arg, strlen(arg))) 334 xtables_error(PARAMETER_PROBLEM, "Bad ctstatus \"%s\"", arg); 335 } 336 337 static void conntrack_parse(struct xt_option_call *cb) 338 { 339 struct xt_conntrack_info *sinfo = cb->data; 340 341 xtables_option_parse(cb); 342 switch (cb->entry->id) { 343 case O_CTSTATE: 344 parse_states(cb->arg, sinfo); 345 if (cb->invert) 346 sinfo->invflags |= XT_CONNTRACK_STATE; 347 break; 348 case O_CTPROTO: 349 sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum = cb->val.protocol; 350 if (cb->invert) 351 sinfo->invflags |= XT_CONNTRACK_PROTO; 352 if (sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum == 0 353 && (sinfo->invflags & XT_INV_PROTO)) 354 xtables_error(PARAMETER_PROBLEM, 355 "rule would never match protocol"); 356 357 sinfo->flags |= XT_CONNTRACK_PROTO; 358 break; 359 case O_CTORIGSRC: 360 if (cb->invert) 361 sinfo->invflags |= XT_CONNTRACK_ORIGSRC; 362 sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip = cb->val.haddr.ip; 363 sinfo->flags |= XT_CONNTRACK_ORIGSRC; 364 break; 365 case O_CTORIGDST: 366 if (cb->invert) 367 sinfo->invflags |= XT_CONNTRACK_ORIGDST; 368 sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip = cb->val.haddr.ip; 369 sinfo->flags |= XT_CONNTRACK_ORIGDST; 370 break; 371 case O_CTREPLSRC: 372 if (cb->invert) 373 sinfo->invflags |= XT_CONNTRACK_REPLSRC; 374 sinfo->tuple[IP_CT_DIR_REPLY].src.ip = cb->val.haddr.ip; 375 sinfo->flags |= XT_CONNTRACK_REPLSRC; 376 break; 377 case O_CTREPLDST: 378 if (cb->invert) 379 sinfo->invflags |= XT_CONNTRACK_REPLDST; 380 sinfo->tuple[IP_CT_DIR_REPLY].dst.ip = cb->val.haddr.ip; 381 sinfo->flags |= XT_CONNTRACK_REPLDST; 382 break; 383 case O_CTSTATUS: 384 parse_statuses(cb->arg, sinfo); 385 if (cb->invert) 386 sinfo->invflags |= XT_CONNTRACK_STATUS; 387 sinfo->flags |= XT_CONNTRACK_STATUS; 388 break; 389 case O_CTEXPIRE: 390 sinfo->expires_min = cb->val.u32_range[0]; 391 sinfo->expires_max = cb->val.u32_range[0]; 392 if (cb->nvals >= 2) 393 sinfo->expires_max = cb->val.u32_range[1]; 394 if (cb->invert) 395 sinfo->invflags |= XT_CONNTRACK_EXPIRES; 396 sinfo->flags |= XT_CONNTRACK_EXPIRES; 397 break; 398 } 399 } 400 401 static void conntrack_mt_parse(struct xt_option_call *cb, uint8_t rev) 402 { 403 struct xt_conntrack_mtinfo3 *info = cb->data; 404 405 xtables_option_parse(cb); 406 switch (cb->entry->id) { 407 case O_CTSTATE: 408 conntrack_ps_states(info, cb->arg); 409 info->match_flags |= XT_CONNTRACK_STATE; 410 if (cb->invert) 411 info->invert_flags |= XT_CONNTRACK_STATE; 412 break; 413 case O_CTPROTO: 414 info->l4proto = cb->val.protocol; 415 if (info->l4proto == 0 && (info->invert_flags & XT_INV_PROTO)) 416 xtables_error(PARAMETER_PROBLEM, "conntrack: rule would " 417 "never match protocol"); 418 419 info->match_flags |= XT_CONNTRACK_PROTO; 420 if (cb->invert) 421 info->invert_flags |= XT_CONNTRACK_PROTO; 422 break; 423 case O_CTORIGSRC: 424 info->origsrc_addr = cb->val.haddr; 425 info->origsrc_mask = cb->val.hmask; 426 info->match_flags |= XT_CONNTRACK_ORIGSRC; 427 if (cb->invert) 428 info->invert_flags |= XT_CONNTRACK_ORIGSRC; 429 break; 430 case O_CTORIGDST: 431 info->origdst_addr = cb->val.haddr; 432 info->origdst_mask = cb->val.hmask; 433 info->match_flags |= XT_CONNTRACK_ORIGDST; 434 if (cb->invert) 435 info->invert_flags |= XT_CONNTRACK_ORIGDST; 436 break; 437 case O_CTREPLSRC: 438 info->replsrc_addr = cb->val.haddr; 439 info->replsrc_mask = cb->val.hmask; 440 info->match_flags |= XT_CONNTRACK_REPLSRC; 441 if (cb->invert) 442 info->invert_flags |= XT_CONNTRACK_REPLSRC; 443 break; 444 case O_CTREPLDST: 445 info->repldst_addr = cb->val.haddr; 446 info->repldst_mask = cb->val.hmask; 447 info->match_flags |= XT_CONNTRACK_REPLDST; 448 if (cb->invert) 449 info->invert_flags |= XT_CONNTRACK_REPLDST; 450 break; 451 case O_CTSTATUS: 452 conntrack_ps_statuses(info, cb->arg); 453 info->match_flags |= XT_CONNTRACK_STATUS; 454 if (cb->invert) 455 info->invert_flags |= XT_CONNTRACK_STATUS; 456 break; 457 case O_CTEXPIRE: 458 info->expires_min = cb->val.u32_range[0]; 459 info->expires_max = cb->val.u32_range[0]; 460 if (cb->nvals >= 2) 461 info->expires_max = cb->val.u32_range[1]; 462 info->match_flags |= XT_CONNTRACK_EXPIRES; 463 if (cb->invert) 464 info->invert_flags |= XT_CONNTRACK_EXPIRES; 465 break; 466 case O_CTORIGSRCPORT: 467 info->origsrc_port = cb->val.port_range[0]; 468 info->origsrc_port_high = cb->val.port_range[cb->nvals >= 2]; 469 info->match_flags |= XT_CONNTRACK_ORIGSRC_PORT; 470 if (cb->invert) 471 info->invert_flags |= XT_CONNTRACK_ORIGSRC_PORT; 472 break; 473 case O_CTORIGDSTPORT: 474 info->origdst_port = cb->val.port_range[0]; 475 info->origdst_port_high = cb->val.port_range[cb->nvals >= 2]; 476 info->match_flags |= XT_CONNTRACK_ORIGDST_PORT; 477 if (cb->invert) 478 info->invert_flags |= XT_CONNTRACK_ORIGDST_PORT; 479 break; 480 case O_CTREPLSRCPORT: 481 info->replsrc_port = cb->val.port_range[0]; 482 info->replsrc_port_high = cb->val.port_range[cb->nvals >= 2]; 483 info->match_flags |= XT_CONNTRACK_REPLSRC_PORT; 484 if (cb->invert) 485 info->invert_flags |= XT_CONNTRACK_REPLSRC_PORT; 486 break; 487 case O_CTREPLDSTPORT: 488 info->repldst_port = cb->val.port_range[0]; 489 info->repldst_port_high = cb->val.port_range[cb->nvals >= 2]; 490 info->match_flags |= XT_CONNTRACK_REPLDST_PORT; 491 if (cb->invert) 492 info->invert_flags |= XT_CONNTRACK_REPLDST_PORT; 493 break; 494 case O_CTDIR: 495 if (strcasecmp(cb->arg, "ORIGINAL") == 0) { 496 info->match_flags |= XT_CONNTRACK_DIRECTION; 497 info->invert_flags &= ~XT_CONNTRACK_DIRECTION; 498 } else if (strcasecmp(cb->arg, "REPLY") == 0) { 499 info->match_flags |= XT_CONNTRACK_DIRECTION; 500 info->invert_flags |= XT_CONNTRACK_DIRECTION; 501 } else { 502 xtables_param_act(XTF_BAD_VALUE, "conntrack", "--ctdir", cb->arg); 503 } 504 break; 505 } 506 } 507 508 #define cinfo_transform(r, l) \ 509 do { \ 510 memcpy((r), (l), offsetof(typeof(*(l)), state_mask)); \ 511 (r)->state_mask = (l)->state_mask; \ 512 (r)->status_mask = (l)->status_mask; \ 513 } while (false); 514 515 static void conntrack1_mt_parse(struct xt_option_call *cb) 516 { 517 struct xt_conntrack_mtinfo1 *info = cb->data; 518 struct xt_conntrack_mtinfo3 up; 519 520 memset(&up, 0, sizeof(up)); 521 cinfo_transform(&up, info); 522 up.origsrc_port_high = up.origsrc_port; 523 up.origdst_port_high = up.origdst_port; 524 up.replsrc_port_high = up.replsrc_port; 525 up.repldst_port_high = up.repldst_port; 526 cb->data = &up; 527 conntrack_mt_parse(cb, 3); 528 if (up.origsrc_port != up.origsrc_port_high || 529 up.origdst_port != up.origdst_port_high || 530 up.replsrc_port != up.replsrc_port_high || 531 up.repldst_port != up.repldst_port_high) 532 xtables_error(PARAMETER_PROBLEM, 533 "conntrack rev 1 does not support port ranges"); 534 cinfo_transform(info, &up); 535 cb->data = info; 536 } 537 538 static void conntrack2_mt_parse(struct xt_option_call *cb) 539 { 540 #define cinfo2_transform(r, l) \ 541 memcpy((r), (l), offsetof(typeof(*(l)), sizeof(*info)); 542 543 struct xt_conntrack_mtinfo2 *info = cb->data; 544 struct xt_conntrack_mtinfo3 up; 545 546 memset(&up, 0, sizeof(up)); 547 memcpy(&up, info, sizeof(*info)); 548 up.origsrc_port_high = up.origsrc_port; 549 up.origdst_port_high = up.origdst_port; 550 up.replsrc_port_high = up.replsrc_port; 551 up.repldst_port_high = up.repldst_port; 552 cb->data = &up; 553 conntrack_mt_parse(cb, 3); 554 if (up.origsrc_port != up.origsrc_port_high || 555 up.origdst_port != up.origdst_port_high || 556 up.replsrc_port != up.replsrc_port_high || 557 up.repldst_port != up.repldst_port_high) 558 xtables_error(PARAMETER_PROBLEM, 559 "conntrack rev 2 does not support port ranges"); 560 memcpy(info, &up, sizeof(*info)); 561 cb->data = info; 562 #undef cinfo2_transform 563 } 564 565 static void conntrack3_mt_parse(struct xt_option_call *cb) 566 { 567 conntrack_mt_parse(cb, 3); 568 } 569 570 static void conntrack_mt_check(struct xt_fcheck_call *cb) 571 { 572 if (cb->xflags == 0) 573 xtables_error(PARAMETER_PROBLEM, "conntrack: At least one option " 574 "is required"); 575 } 576 577 static void 578 print_state(unsigned int statemask) 579 { 580 const char *sep = " "; 581 582 if (statemask & XT_CONNTRACK_STATE_INVALID) { 583 printf("%sINVALID", sep); 584 sep = ","; 585 } 586 if (statemask & XT_CONNTRACK_STATE_BIT(IP_CT_NEW)) { 587 printf("%sNEW", sep); 588 sep = ","; 589 } 590 if (statemask & XT_CONNTRACK_STATE_BIT(IP_CT_RELATED)) { 591 printf("%sRELATED", sep); 592 sep = ","; 593 } 594 if (statemask & XT_CONNTRACK_STATE_BIT(IP_CT_ESTABLISHED)) { 595 printf("%sESTABLISHED", sep); 596 sep = ","; 597 } 598 if (statemask & XT_CONNTRACK_STATE_UNTRACKED) { 599 printf("%sUNTRACKED", sep); 600 sep = ","; 601 } 602 if (statemask & XT_CONNTRACK_STATE_SNAT) { 603 printf("%sSNAT", sep); 604 sep = ","; 605 } 606 if (statemask & XT_CONNTRACK_STATE_DNAT) { 607 printf("%sDNAT", sep); 608 sep = ","; 609 } 610 } 611 612 static void 613 print_status(unsigned int statusmask) 614 { 615 const char *sep = " "; 616 617 if (statusmask & IPS_EXPECTED) { 618 printf("%sEXPECTED", sep); 619 sep = ","; 620 } 621 if (statusmask & IPS_SEEN_REPLY) { 622 printf("%sSEEN_REPLY", sep); 623 sep = ","; 624 } 625 if (statusmask & IPS_ASSURED) { 626 printf("%sASSURED", sep); 627 sep = ","; 628 } 629 if (statusmask & IPS_CONFIRMED) { 630 printf("%sCONFIRMED", sep); 631 sep = ","; 632 } 633 if (statusmask == 0) 634 printf("%sNONE", sep); 635 } 636 637 static void 638 conntrack_dump_addr(const union nf_inet_addr *addr, 639 const union nf_inet_addr *mask, 640 unsigned int family, bool numeric) 641 { 642 if (family == NFPROTO_IPV4) { 643 if (!numeric && addr->ip == 0) { 644 printf(" anywhere"); 645 return; 646 } 647 if (numeric) 648 printf(" %s%s", 649 xtables_ipaddr_to_numeric(&addr->in), 650 xtables_ipmask_to_numeric(&mask->in)); 651 else 652 printf(" %s%s", 653 xtables_ipaddr_to_anyname(&addr->in), 654 xtables_ipmask_to_numeric(&mask->in)); 655 } else if (family == NFPROTO_IPV6) { 656 if (!numeric && addr->ip6[0] == 0 && addr->ip6[1] == 0 && 657 addr->ip6[2] == 0 && addr->ip6[3] == 0) { 658 printf(" anywhere"); 659 return; 660 } 661 if (numeric) 662 printf(" %s%s", 663 xtables_ip6addr_to_numeric(&addr->in6), 664 xtables_ip6mask_to_numeric(&mask->in6)); 665 else 666 printf(" %s%s", 667 xtables_ip6addr_to_anyname(&addr->in6), 668 xtables_ip6mask_to_numeric(&mask->in6)); 669 } 670 } 671 672 static void 673 print_addr(const struct in_addr *addr, const struct in_addr *mask, 674 int inv, int numeric) 675 { 676 char buf[BUFSIZ]; 677 678 if (inv) 679 printf(" !"); 680 681 if (mask->s_addr == 0L && !numeric) 682 printf(" %s", "anywhere"); 683 else { 684 if (numeric) 685 strcpy(buf, xtables_ipaddr_to_numeric(addr)); 686 else 687 strcpy(buf, xtables_ipaddr_to_anyname(addr)); 688 strcat(buf, xtables_ipmask_to_numeric(mask)); 689 printf(" %s", buf); 690 } 691 } 692 693 static void 694 matchinfo_print(const void *ip, const struct xt_entry_match *match, int numeric, const char *optpfx) 695 { 696 const struct xt_conntrack_info *sinfo = (const void *)match->data; 697 698 if(sinfo->flags & XT_CONNTRACK_STATE) { 699 if (sinfo->invflags & XT_CONNTRACK_STATE) 700 printf(" !"); 701 printf(" %sctstate", optpfx); 702 print_state(sinfo->statemask); 703 } 704 705 if(sinfo->flags & XT_CONNTRACK_PROTO) { 706 if (sinfo->invflags & XT_CONNTRACK_PROTO) 707 printf(" !"); 708 printf(" %sctproto", optpfx); 709 printf(" %u", sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum); 710 } 711 712 if(sinfo->flags & XT_CONNTRACK_ORIGSRC) { 713 if (sinfo->invflags & XT_CONNTRACK_ORIGSRC) 714 printf(" !"); 715 printf(" %sctorigsrc", optpfx); 716 717 print_addr( 718 (struct in_addr *)&sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip, 719 &sinfo->sipmsk[IP_CT_DIR_ORIGINAL], 720 false, 721 numeric); 722 } 723 724 if(sinfo->flags & XT_CONNTRACK_ORIGDST) { 725 if (sinfo->invflags & XT_CONNTRACK_ORIGDST) 726 printf(" !"); 727 printf(" %sctorigdst", optpfx); 728 729 print_addr( 730 (struct in_addr *)&sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip, 731 &sinfo->dipmsk[IP_CT_DIR_ORIGINAL], 732 false, 733 numeric); 734 } 735 736 if(sinfo->flags & XT_CONNTRACK_REPLSRC) { 737 if (sinfo->invflags & XT_CONNTRACK_REPLSRC) 738 printf(" !"); 739 printf(" %sctreplsrc", optpfx); 740 741 print_addr( 742 (struct in_addr *)&sinfo->tuple[IP_CT_DIR_REPLY].src.ip, 743 &sinfo->sipmsk[IP_CT_DIR_REPLY], 744 false, 745 numeric); 746 } 747 748 if(sinfo->flags & XT_CONNTRACK_REPLDST) { 749 if (sinfo->invflags & XT_CONNTRACK_REPLDST) 750 printf(" !"); 751 printf(" %sctrepldst", optpfx); 752 753 print_addr( 754 (struct in_addr *)&sinfo->tuple[IP_CT_DIR_REPLY].dst.ip, 755 &sinfo->dipmsk[IP_CT_DIR_REPLY], 756 false, 757 numeric); 758 } 759 760 if(sinfo->flags & XT_CONNTRACK_STATUS) { 761 if (sinfo->invflags & XT_CONNTRACK_STATUS) 762 printf(" !"); 763 printf(" %sctstatus", optpfx); 764 print_status(sinfo->statusmask); 765 } 766 767 if(sinfo->flags & XT_CONNTRACK_EXPIRES) { 768 if (sinfo->invflags & XT_CONNTRACK_EXPIRES) 769 printf(" !"); 770 printf(" %sctexpire ", optpfx); 771 772 if (sinfo->expires_max == sinfo->expires_min) 773 printf("%lu", sinfo->expires_min); 774 else 775 printf("%lu:%lu", sinfo->expires_min, sinfo->expires_max); 776 } 777 778 if (sinfo->flags & XT_CONNTRACK_DIRECTION) { 779 if (sinfo->invflags & XT_CONNTRACK_DIRECTION) 780 printf(" %sctdir REPLY", optpfx); 781 else 782 printf(" %sctdir ORIGINAL", optpfx); 783 } 784 785 } 786 787 static void 788 conntrack_dump_ports(const char *prefix, const char *opt, 789 u_int16_t port_low, u_int16_t port_high) 790 { 791 if (port_high == 0 || port_low == port_high) 792 printf(" %s%s %u", prefix, opt, port_low); 793 else 794 printf(" %s%s %u:%u", prefix, opt, port_low, port_high); 795 } 796 797 static void 798 conntrack_dump(const struct xt_conntrack_mtinfo3 *info, const char *prefix, 799 unsigned int family, bool numeric, bool v3) 800 { 801 if (info->match_flags & XT_CONNTRACK_STATE) { 802 if (info->invert_flags & XT_CONNTRACK_STATE) 803 printf(" !"); 804 printf(" %s%s", prefix, 805 info->match_flags & XT_CONNTRACK_STATE_ALIAS 806 ? "state" : "ctstate"); 807 print_state(info->state_mask); 808 } 809 810 if (info->match_flags & XT_CONNTRACK_PROTO) { 811 if (info->invert_flags & XT_CONNTRACK_PROTO) 812 printf(" !"); 813 printf(" %sctproto %u", prefix, info->l4proto); 814 } 815 816 if (info->match_flags & XT_CONNTRACK_ORIGSRC) { 817 if (info->invert_flags & XT_CONNTRACK_ORIGSRC) 818 printf(" !"); 819 printf(" %sctorigsrc", prefix); 820 conntrack_dump_addr(&info->origsrc_addr, &info->origsrc_mask, 821 family, numeric); 822 } 823 824 if (info->match_flags & XT_CONNTRACK_ORIGDST) { 825 if (info->invert_flags & XT_CONNTRACK_ORIGDST) 826 printf(" !"); 827 printf(" %sctorigdst", prefix); 828 conntrack_dump_addr(&info->origdst_addr, &info->origdst_mask, 829 family, numeric); 830 } 831 832 if (info->match_flags & XT_CONNTRACK_REPLSRC) { 833 if (info->invert_flags & XT_CONNTRACK_REPLSRC) 834 printf(" !"); 835 printf(" %sctreplsrc", prefix); 836 conntrack_dump_addr(&info->replsrc_addr, &info->replsrc_mask, 837 family, numeric); 838 } 839 840 if (info->match_flags & XT_CONNTRACK_REPLDST) { 841 if (info->invert_flags & XT_CONNTRACK_REPLDST) 842 printf(" !"); 843 printf(" %sctrepldst", prefix); 844 conntrack_dump_addr(&info->repldst_addr, &info->repldst_mask, 845 family, numeric); 846 } 847 848 if (info->match_flags & XT_CONNTRACK_ORIGSRC_PORT) { 849 if (info->invert_flags & XT_CONNTRACK_ORIGSRC_PORT) 850 printf(" !"); 851 conntrack_dump_ports(prefix, "ctorigsrcport", 852 v3 ? info->origsrc_port : ntohs(info->origsrc_port), 853 v3 ? info->origsrc_port_high : 0); 854 } 855 856 if (info->match_flags & XT_CONNTRACK_ORIGDST_PORT) { 857 if (info->invert_flags & XT_CONNTRACK_ORIGDST_PORT) 858 printf(" !"); 859 conntrack_dump_ports(prefix, "ctorigdstport", 860 v3 ? info->origdst_port : ntohs(info->origdst_port), 861 v3 ? info->origdst_port_high : 0); 862 } 863 864 if (info->match_flags & XT_CONNTRACK_REPLSRC_PORT) { 865 if (info->invert_flags & XT_CONNTRACK_REPLSRC_PORT) 866 printf(" !"); 867 conntrack_dump_ports(prefix, "ctreplsrcport", 868 v3 ? info->replsrc_port : ntohs(info->replsrc_port), 869 v3 ? info->replsrc_port_high : 0); 870 } 871 872 if (info->match_flags & XT_CONNTRACK_REPLDST_PORT) { 873 if (info->invert_flags & XT_CONNTRACK_REPLDST_PORT) 874 printf(" !"); 875 conntrack_dump_ports(prefix, "ctrepldstport", 876 v3 ? info->repldst_port : ntohs(info->repldst_port), 877 v3 ? info->repldst_port_high : 0); 878 } 879 880 if (info->match_flags & XT_CONNTRACK_STATUS) { 881 if (info->invert_flags & XT_CONNTRACK_STATUS) 882 printf(" !"); 883 printf(" %sctstatus", prefix); 884 print_status(info->status_mask); 885 } 886 887 if (info->match_flags & XT_CONNTRACK_EXPIRES) { 888 if (info->invert_flags & XT_CONNTRACK_EXPIRES) 889 printf(" !"); 890 printf(" %sctexpire ", prefix); 891 892 if (info->expires_max == info->expires_min) 893 printf("%u", (unsigned int)info->expires_min); 894 else 895 printf("%u:%u", (unsigned int)info->expires_min, 896 (unsigned int)info->expires_max); 897 } 898 899 if (info->match_flags & XT_CONNTRACK_DIRECTION) { 900 if (info->invert_flags & XT_CONNTRACK_DIRECTION) 901 printf(" %sctdir REPLY", prefix); 902 else 903 printf(" %sctdir ORIGINAL", prefix); 904 } 905 } 906 907 static const char * 908 conntrack_print_name_alias(const struct xt_entry_match *match) 909 { 910 struct xt_conntrack_mtinfo1 *info = (void *)match->data; 911 912 return info->match_flags & XT_CONNTRACK_STATE_ALIAS 913 ? "state" : "conntrack"; 914 } 915 916 static void conntrack_print(const void *ip, const struct xt_entry_match *match, 917 int numeric) 918 { 919 matchinfo_print(ip, match, numeric, ""); 920 } 921 922 static void 923 conntrack1_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 933 static void 934 conntrack1_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 944 static void 945 conntrack2_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 951 static void 952 conntrack2_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 958 static void 959 conntrack3_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 965 static void 966 conntrack3_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 972 static void conntrack_save(const void *ip, const struct xt_entry_match *match) 973 { 974 matchinfo_print(ip, match, 1, "--"); 975 } 976 977 static 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 983 static 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 989 static 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 995 static 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 1001 static void 1002 conntrack1_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 1011 static void 1012 conntrack1_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 1021 static void 1022 state_help(void) 1023 { 1024 printf( 1025 "state match options:\n" 1026 " [!] --state [INVALID|ESTABLISHED|NEW|RELATED|UNTRACKED][,...]\n" 1027 " State(s) to match\n"); 1028 } 1029 1030 static const struct xt_option_entry state_opts[] = { 1031 {.name = "state", .id = O_CTSTATE, .type = XTTYPE_STRING, 1032 .flags = XTOPT_MAND | XTOPT_INVERT}, 1033 XTOPT_TABLEEND, 1034 }; 1035 1036 static unsigned int 1037 state_parse_state(const char *state, size_t len) 1038 { 1039 if (strncasecmp(state, "INVALID", len) == 0) 1040 return XT_CONNTRACK_STATE_INVALID; 1041 else if (strncasecmp(state, "NEW", len) == 0) 1042 return XT_CONNTRACK_STATE_BIT(IP_CT_NEW); 1043 else if (strncasecmp(state, "ESTABLISHED", len) == 0) 1044 return XT_CONNTRACK_STATE_BIT(IP_CT_ESTABLISHED); 1045 else if (strncasecmp(state, "RELATED", len) == 0) 1046 return XT_CONNTRACK_STATE_BIT(IP_CT_RELATED); 1047 else if (strncasecmp(state, "UNTRACKED", len) == 0) 1048 return XT_CONNTRACK_STATE_UNTRACKED; 1049 return 0; 1050 } 1051 1052 static unsigned int 1053 state_parse_states(const char *arg) 1054 { 1055 const char *comma; 1056 unsigned int mask = 0, flag; 1057 1058 while ((comma = strchr(arg, ',')) != NULL) { 1059 if (comma == arg) 1060 goto badstate; 1061 flag = state_parse_state(arg, comma-arg); 1062 if (flag == 0) 1063 goto badstate; 1064 mask |= flag; 1065 arg = comma+1; 1066 } 1067 if (!*arg) 1068 xtables_error(PARAMETER_PROBLEM, "\"--state\" requires a list of " 1069 "states with no spaces, e.g. " 1070 "ESTABLISHED,RELATED"); 1071 if (strlen(arg) == 0) 1072 goto badstate; 1073 flag = state_parse_state(arg, strlen(arg)); 1074 if (flag == 0) 1075 goto badstate; 1076 mask |= flag; 1077 return mask; 1078 badstate: 1079 xtables_error(PARAMETER_PROBLEM, "Bad state \"%s\"", arg); 1080 } 1081 1082 static void state_parse(struct xt_option_call *cb) 1083 { 1084 struct xt_state_info *sinfo = cb->data; 1085 1086 xtables_option_parse(cb); 1087 sinfo->statemask = state_parse_states(cb->arg); 1088 if (cb->invert) 1089 sinfo->statemask = ~sinfo->statemask; 1090 } 1091 1092 static void state_ct1_parse(struct xt_option_call *cb) 1093 { 1094 struct xt_conntrack_mtinfo1 *sinfo = cb->data; 1095 1096 xtables_option_parse(cb); 1097 sinfo->match_flags = XT_CONNTRACK_STATE | XT_CONNTRACK_STATE_ALIAS; 1098 sinfo->state_mask = state_parse_states(cb->arg); 1099 if (cb->invert) 1100 sinfo->invert_flags |= XT_CONNTRACK_STATE; 1101 } 1102 1103 static void state_ct23_parse(struct xt_option_call *cb) 1104 { 1105 struct xt_conntrack_mtinfo3 *sinfo = cb->data; 1106 1107 xtables_option_parse(cb); 1108 sinfo->match_flags = XT_CONNTRACK_STATE | XT_CONNTRACK_STATE_ALIAS; 1109 sinfo->state_mask = state_parse_states(cb->arg); 1110 if (cb->invert) 1111 sinfo->invert_flags |= XT_CONNTRACK_STATE; 1112 } 1113 1114 static void state_print_state(unsigned int statemask) 1115 { 1116 const char *sep = ""; 1117 1118 if (statemask & XT_CONNTRACK_STATE_INVALID) { 1119 printf("%sINVALID", sep); 1120 sep = ","; 1121 } 1122 if (statemask & XT_CONNTRACK_STATE_BIT(IP_CT_NEW)) { 1123 printf("%sNEW", sep); 1124 sep = ","; 1125 } 1126 if (statemask & XT_CONNTRACK_STATE_BIT(IP_CT_RELATED)) { 1127 printf("%sRELATED", sep); 1128 sep = ","; 1129 } 1130 if (statemask & XT_CONNTRACK_STATE_BIT(IP_CT_ESTABLISHED)) { 1131 printf("%sESTABLISHED", sep); 1132 sep = ","; 1133 } 1134 if (statemask & XT_CONNTRACK_STATE_UNTRACKED) { 1135 printf("%sUNTRACKED", sep); 1136 sep = ","; 1137 } 1138 } 1139 1140 static void 1141 state_print(const void *ip, 1142 const struct xt_entry_match *match, 1143 int numeric) 1144 { 1145 const struct xt_state_info *sinfo = (const void *)match->data; 1146 1147 printf(" state "); 1148 state_print_state(sinfo->statemask); 1149 } 1150 1151 static void state_save(const void *ip, const struct xt_entry_match *match) 1152 { 1153 const struct xt_state_info *sinfo = (const void *)match->data; 1154 1155 printf(" --state "); 1156 state_print_state(sinfo->statemask); 1157 } 1158 1159 static void state_xlate_print(struct xt_xlate *xl, unsigned int statemask) 1160 { 1161 const char *sep = ""; 1162 1163 if (statemask & XT_CONNTRACK_STATE_INVALID) { 1164 xt_xlate_add(xl, "%s%s", sep, "invalid"); 1165 sep = ","; 1166 } 1167 if (statemask & XT_CONNTRACK_STATE_BIT(IP_CT_NEW)) { 1168 xt_xlate_add(xl, "%s%s", sep, "new"); 1169 sep = ","; 1170 } 1171 if (statemask & XT_CONNTRACK_STATE_BIT(IP_CT_RELATED)) { 1172 xt_xlate_add(xl, "%s%s", sep, "related"); 1173 sep = ","; 1174 } 1175 if (statemask & XT_CONNTRACK_STATE_BIT(IP_CT_ESTABLISHED)) { 1176 xt_xlate_add(xl, "%s%s", sep, "established"); 1177 sep = ","; 1178 } 1179 if (statemask & XT_CONNTRACK_STATE_UNTRACKED) { 1180 xt_xlate_add(xl, "%s%s", sep, "untracked"); 1181 sep = ","; 1182 } 1183 } 1184 1185 static int state_xlate(struct xt_xlate *xl, 1186 const struct xt_xlate_mt_params *params) 1187 { 1188 const struct xt_conntrack_mtinfo3 *sinfo = 1189 (const void *)params->match->data; 1190 1191 xt_xlate_add(xl, "ct state %s", sinfo->invert_flags & XT_CONNTRACK_STATE ? 1192 "!= " : ""); 1193 state_xlate_print(xl, sinfo->state_mask); 1194 xt_xlate_add(xl, " "); 1195 return 1; 1196 } 1197 1198 static void status_xlate_print(struct xt_xlate *xl, unsigned int statusmask) 1199 { 1200 const char *sep = ""; 1201 1202 if (statusmask & IPS_EXPECTED) { 1203 xt_xlate_add(xl, "%s%s", sep, "expected"); 1204 sep = ","; 1205 } 1206 if (statusmask & IPS_SEEN_REPLY) { 1207 xt_xlate_add(xl, "%s%s", sep, "seen-reply"); 1208 sep = ","; 1209 } 1210 if (statusmask & IPS_ASSURED) { 1211 xt_xlate_add(xl, "%s%s", sep, "assured"); 1212 sep = ","; 1213 } 1214 if (statusmask & IPS_CONFIRMED) { 1215 xt_xlate_add(xl, "%s%s", sep, "confirmed"); 1216 sep = ","; 1217 } 1218 } 1219 1220 static void addr_xlate_print(struct xt_xlate *xl, 1221 const union nf_inet_addr *addr, 1222 const union nf_inet_addr *mask, 1223 unsigned int family) 1224 { 1225 if (family == NFPROTO_IPV4) { 1226 xt_xlate_add(xl, "%s%s", xtables_ipaddr_to_numeric(&addr->in), 1227 xtables_ipmask_to_numeric(&mask->in)); 1228 } else if (family == NFPROTO_IPV6) { 1229 xt_xlate_add(xl, "%s%s", xtables_ip6addr_to_numeric(&addr->in6), 1230 xtables_ip6mask_to_numeric(&mask->in6)); 1231 } 1232 } 1233 1234 static int _conntrack3_mt_xlate(struct xt_xlate *xl, 1235 const struct xt_xlate_mt_params *params, 1236 int family) 1237 { 1238 const struct xt_conntrack_mtinfo3 *sinfo = 1239 (const void *)params->match->data; 1240 char *space = ""; 1241 1242 if (sinfo->match_flags & XT_CONNTRACK_DIRECTION) { 1243 xt_xlate_add(xl, "ct direction %s", 1244 sinfo->invert_flags & XT_CONNTRACK_DIRECTION ? 1245 "reply" : "original"); 1246 space = " "; 1247 } 1248 1249 if (sinfo->match_flags & XT_CONNTRACK_PROTO) { 1250 xt_xlate_add(xl, "%sct %s protocol %s%u", space, 1251 sinfo->invert_flags & XT_CONNTRACK_DIRECTION ? 1252 "reply" : "original", 1253 sinfo->invert_flags & XT_CONNTRACK_PROTO ? 1254 "!= " : "", 1255 sinfo->l4proto); 1256 space = " "; 1257 } 1258 1259 if (sinfo->match_flags & XT_CONNTRACK_STATE) { 1260 xt_xlate_add(xl, "%sct state %s", space, 1261 sinfo->invert_flags & XT_CONNTRACK_STATE ? 1262 "!= " : ""); 1263 state_xlate_print(xl, sinfo->state_mask); 1264 space = " "; 1265 } 1266 1267 if (sinfo->match_flags & XT_CONNTRACK_STATUS) { 1268 if (sinfo->status_mask == 1) 1269 return 0; 1270 xt_xlate_add(xl, "%sct status %s", space, 1271 sinfo->invert_flags & XT_CONNTRACK_STATUS ? 1272 "!= " : ""); 1273 status_xlate_print(xl, sinfo->status_mask); 1274 space = " "; 1275 } 1276 1277 if (sinfo->match_flags & XT_CONNTRACK_EXPIRES) { 1278 xt_xlate_add(xl, "%sct expiration %s", space, 1279 sinfo->invert_flags & XT_CONNTRACK_EXPIRES ? 1280 "!= " : ""); 1281 if (sinfo->expires_max == sinfo->expires_min) 1282 xt_xlate_add(xl, "%lu", sinfo->expires_min); 1283 else 1284 xt_xlate_add(xl, "%lu-%lu", sinfo->expires_min, 1285 sinfo->expires_max); 1286 space = " "; 1287 } 1288 1289 if (sinfo->match_flags & XT_CONNTRACK_ORIGSRC) { 1290 if (&sinfo->origsrc_addr == 0L) 1291 return 0; 1292 1293 xt_xlate_add(xl, "%sct original saddr %s", space, 1294 sinfo->invert_flags & XT_CONNTRACK_ORIGSRC ? 1295 "!= " : ""); 1296 addr_xlate_print(xl, &sinfo->origsrc_addr, 1297 &sinfo->origsrc_mask, family); 1298 space = " "; 1299 } 1300 1301 if (sinfo->match_flags & XT_CONNTRACK_ORIGDST) { 1302 if (&sinfo->origdst_addr == 0L) 1303 return 0; 1304 1305 xt_xlate_add(xl, "%sct original daddr %s", space, 1306 sinfo->invert_flags & XT_CONNTRACK_ORIGDST ? 1307 "!= " : ""); 1308 addr_xlate_print(xl, &sinfo->origdst_addr, 1309 &sinfo->origdst_mask, family); 1310 space = " "; 1311 } 1312 1313 if (sinfo->match_flags & XT_CONNTRACK_REPLSRC) { 1314 if (&sinfo->replsrc_addr == 0L) 1315 return 0; 1316 1317 xt_xlate_add(xl, "%sct reply saddr %s", space, 1318 sinfo->invert_flags & XT_CONNTRACK_REPLSRC ? 1319 "!= " : ""); 1320 addr_xlate_print(xl, &sinfo->replsrc_addr, 1321 &sinfo->replsrc_mask, family); 1322 space = " "; 1323 } 1324 1325 if (sinfo->match_flags & XT_CONNTRACK_REPLDST) { 1326 if (&sinfo->repldst_addr == 0L) 1327 return 0; 1328 1329 xt_xlate_add(xl, "%sct reply daddr %s", space, 1330 sinfo->invert_flags & XT_CONNTRACK_REPLDST ? 1331 "!= " : ""); 1332 addr_xlate_print(xl, &sinfo->repldst_addr, 1333 &sinfo->repldst_mask, family); 1334 space = " "; 1335 } 1336 1337 if (sinfo->match_flags & XT_CONNTRACK_ORIGSRC_PORT) { 1338 xt_xlate_add(xl, "%sct original proto-src %s", space, 1339 sinfo->invert_flags & XT_CONNTRACK_ORIGSRC_PORT ? 1340 "!= " : ""); 1341 if (sinfo->origsrc_port == sinfo->origsrc_port_high) 1342 xt_xlate_add(xl, "%u", sinfo->origsrc_port); 1343 else 1344 xt_xlate_add(xl, "%u-%u", sinfo->origsrc_port, 1345 sinfo->origsrc_port_high); 1346 space = " "; 1347 } 1348 1349 if (sinfo->match_flags & XT_CONNTRACK_ORIGDST_PORT) { 1350 xt_xlate_add(xl, "%sct original proto-dst %s", space, 1351 sinfo->invert_flags & XT_CONNTRACK_ORIGDST_PORT ? 1352 "!= " : ""); 1353 if (sinfo->origdst_port == sinfo->origdst_port_high) 1354 xt_xlate_add(xl, "%u", sinfo->origdst_port); 1355 else 1356 xt_xlate_add(xl, "%u-%u", sinfo->origdst_port, 1357 sinfo->origdst_port_high); 1358 space = " "; 1359 } 1360 1361 if (sinfo->match_flags & XT_CONNTRACK_REPLSRC_PORT) { 1362 xt_xlate_add(xl, "%sct reply proto-src %s", space, 1363 sinfo->invert_flags & XT_CONNTRACK_REPLSRC_PORT ? 1364 "!= " : ""); 1365 if (sinfo->replsrc_port == sinfo->replsrc_port_high) 1366 xt_xlate_add(xl, "%u", sinfo->replsrc_port); 1367 else 1368 xt_xlate_add(xl, "%u-%u", sinfo->replsrc_port, 1369 sinfo->replsrc_port_high); 1370 space = " "; 1371 } 1372 1373 if (sinfo->match_flags & XT_CONNTRACK_REPLDST_PORT) { 1374 xt_xlate_add(xl, "%sct reply proto-dst %s", space, 1375 sinfo->invert_flags & XT_CONNTRACK_REPLDST_PORT ? 1376 "!= " : "", sinfo->repldst_port); 1377 if (sinfo->repldst_port == sinfo->repldst_port_high) 1378 xt_xlate_add(xl, "%u", sinfo->repldst_port); 1379 else 1380 xt_xlate_add(xl, "%u-%u", sinfo->repldst_port, 1381 sinfo->repldst_port_high); 1382 } 1383 1384 return 1; 1385 } 1386 1387 static int conntrack3_mt4_xlate(struct xt_xlate *xl, 1388 const struct xt_xlate_mt_params *params) 1389 { 1390 return _conntrack3_mt_xlate(xl, params, NFPROTO_IPV4); 1391 } 1392 1393 static int conntrack3_mt6_xlate(struct xt_xlate *xl, 1394 const struct xt_xlate_mt_params *params) 1395 { 1396 return _conntrack3_mt_xlate(xl, params, NFPROTO_IPV6); 1397 } 1398 1399 static struct xtables_match conntrack_mt_reg[] = { 1400 { 1401 .version = XTABLES_VERSION, 1402 .name = "conntrack", 1403 .revision = 0, 1404 .family = NFPROTO_IPV4, 1405 .size = XT_ALIGN(sizeof(struct xt_conntrack_info)), 1406 .userspacesize = XT_ALIGN(sizeof(struct xt_conntrack_info)), 1407 .help = conntrack_mt_help, 1408 .x6_parse = conntrack_parse, 1409 .x6_fcheck = conntrack_mt_check, 1410 .print = conntrack_print, 1411 .save = conntrack_save, 1412 .alias = conntrack_print_name_alias, 1413 .x6_options = conntrack_mt_opts_v0, 1414 }, 1415 { 1416 .version = XTABLES_VERSION, 1417 .name = "conntrack", 1418 .revision = 1, 1419 .family = NFPROTO_IPV4, 1420 .size = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo1)), 1421 .userspacesize = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo1)), 1422 .help = conntrack_mt_help, 1423 .x6_parse = conntrack1_mt_parse, 1424 .x6_fcheck = conntrack_mt_check, 1425 .print = conntrack1_mt4_print, 1426 .save = conntrack1_mt4_save, 1427 .alias = conntrack_print_name_alias, 1428 .x6_options = conntrack2_mt_opts, 1429 }, 1430 { 1431 .version = XTABLES_VERSION, 1432 .name = "conntrack", 1433 .revision = 1, 1434 .family = NFPROTO_IPV6, 1435 .size = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo1)), 1436 .userspacesize = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo1)), 1437 .help = conntrack_mt_help, 1438 .x6_parse = conntrack1_mt_parse, 1439 .x6_fcheck = conntrack_mt_check, 1440 .print = conntrack1_mt6_print, 1441 .save = conntrack1_mt6_save, 1442 .alias = conntrack_print_name_alias, 1443 .x6_options = conntrack2_mt_opts, 1444 }, 1445 { 1446 .version = XTABLES_VERSION, 1447 .name = "conntrack", 1448 .revision = 2, 1449 .family = NFPROTO_IPV4, 1450 .size = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo2)), 1451 .userspacesize = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo2)), 1452 .help = conntrack_mt_help, 1453 .x6_parse = conntrack2_mt_parse, 1454 .x6_fcheck = conntrack_mt_check, 1455 .print = conntrack2_mt_print, 1456 .save = conntrack2_mt_save, 1457 .alias = conntrack_print_name_alias, 1458 .x6_options = conntrack2_mt_opts, 1459 }, 1460 { 1461 .version = XTABLES_VERSION, 1462 .name = "conntrack", 1463 .revision = 2, 1464 .family = NFPROTO_IPV6, 1465 .size = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo2)), 1466 .userspacesize = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo2)), 1467 .help = conntrack_mt_help, 1468 .x6_parse = conntrack2_mt_parse, 1469 .x6_fcheck = conntrack_mt_check, 1470 .print = conntrack2_mt6_print, 1471 .save = conntrack2_mt6_save, 1472 .alias = conntrack_print_name_alias, 1473 .x6_options = conntrack2_mt_opts, 1474 }, 1475 { 1476 .version = XTABLES_VERSION, 1477 .name = "conntrack", 1478 .revision = 3, 1479 .family = NFPROTO_IPV4, 1480 .size = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo3)), 1481 .userspacesize = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo3)), 1482 .help = conntrack_mt_help, 1483 .x6_parse = conntrack3_mt_parse, 1484 .x6_fcheck = conntrack_mt_check, 1485 .print = conntrack3_mt_print, 1486 .save = conntrack3_mt_save, 1487 .alias = conntrack_print_name_alias, 1488 .x6_options = conntrack3_mt_opts, 1489 .xlate = conntrack3_mt4_xlate, 1490 }, 1491 { 1492 .version = XTABLES_VERSION, 1493 .name = "conntrack", 1494 .revision = 3, 1495 .family = NFPROTO_IPV6, 1496 .size = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo3)), 1497 .userspacesize = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo3)), 1498 .help = conntrack_mt_help, 1499 .x6_parse = conntrack3_mt_parse, 1500 .x6_fcheck = conntrack_mt_check, 1501 .print = conntrack3_mt6_print, 1502 .save = conntrack3_mt6_save, 1503 .alias = conntrack_print_name_alias, 1504 .x6_options = conntrack3_mt_opts, 1505 .xlate = conntrack3_mt6_xlate, 1506 }, 1507 { 1508 .family = NFPROTO_UNSPEC, 1509 .name = "state", 1510 .real_name = "conntrack", 1511 .revision = 1, 1512 .ext_flags = XTABLES_EXT_ALIAS, 1513 .version = XTABLES_VERSION, 1514 .size = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo1)), 1515 .userspacesize = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo1)), 1516 .help = state_help, 1517 .print = state_print, 1518 .save = state_save, 1519 .x6_parse = state_ct1_parse, 1520 .x6_options = state_opts, 1521 }, 1522 { 1523 .family = NFPROTO_UNSPEC, 1524 .name = "state", 1525 .real_name = "conntrack", 1526 .revision = 2, 1527 .ext_flags = XTABLES_EXT_ALIAS, 1528 .version = XTABLES_VERSION, 1529 .size = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo2)), 1530 .userspacesize = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo2)), 1531 .help = state_help, 1532 .print = state_print, 1533 .save = state_save, 1534 .x6_parse = state_ct23_parse, 1535 .x6_options = state_opts, 1536 }, 1537 { 1538 .family = NFPROTO_UNSPEC, 1539 .name = "state", 1540 .real_name = "conntrack", 1541 .revision = 3, 1542 .ext_flags = XTABLES_EXT_ALIAS, 1543 .version = XTABLES_VERSION, 1544 .size = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo3)), 1545 .userspacesize = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo3)), 1546 .help = state_help, 1547 .print = state_print, 1548 .save = state_save, 1549 .x6_parse = state_ct23_parse, 1550 .x6_options = state_opts, 1551 .xlate = state_xlate, 1552 }, 1553 { 1554 .family = NFPROTO_UNSPEC, 1555 .name = "state", 1556 .revision = 0, 1557 .version = XTABLES_VERSION, 1558 .size = XT_ALIGN(sizeof(struct xt_state_info)), 1559 .userspacesize = XT_ALIGN(sizeof(struct xt_state_info)), 1560 .help = state_help, 1561 .print = state_print, 1562 .save = state_save, 1563 .x6_parse = state_parse, 1564 .x6_options = state_opts, 1565 }, 1566 }; 1567 1568 void _init(void) 1569 { 1570 xtables_register_matches(conntrack_mt_reg, ARRAY_SIZE(conntrack_mt_reg)); 1571 } 1572