1 /* 2 * Copyright (c) 2002-2003 Luigi Rizzo 3 * Copyright (c) 1996 Alex Nash, Paul Traina, Poul-Henning Kamp 4 * Copyright (c) 1994 Ugen J.S.Antsilevich 5 * 6 * Idea and grammar partially left from: 7 * Copyright (c) 1993 Daniel Boulet 8 * 9 * Redistribution and use in source forms, with and without modification, 10 * are permitted provided that this entire comment appears intact. 11 * 12 * Redistribution in binary form may occur without any restrictions. 13 * Obviously, it would be nice if you gave credit where credit is due 14 * but requiring it would be too onerous. 15 * 16 * This software is provided ``AS IS'' without any warranties of any kind. 17 * 18 * NEW command line interface for IP firewall facility 19 * 20 * $FreeBSD$ 21 */ 22 23 #include <sys/types.h> 24 #include <sys/param.h> 25 #include <sys/socket.h> 26 #include <sys/sockio.h> 27 #include <sys/sysctl.h> 28 29 #include "ipfw2.h" 30 31 #include <ctype.h> 32 #include <err.h> 33 #include <errno.h> 34 #include <grp.h> 35 #include <netdb.h> 36 #include <pwd.h> 37 #include <stdio.h> 38 #include <stdarg.h> 39 #include <stdlib.h> 40 #include <string.h> 41 #include <sysexits.h> 42 #include <time.h> /* ctime */ 43 #include <timeconv.h> /* _long_to_time */ 44 #include <unistd.h> 45 #include <fcntl.h> 46 #include <stddef.h> /* offsetof */ 47 48 #include <net/ethernet.h> 49 #include <net/if.h> /* only IFNAMSIZ */ 50 #include <netinet/in.h> 51 #include <netinet/in_systm.h> /* only n_short, n_long */ 52 #include <netinet/ip.h> 53 #include <netinet/ip_icmp.h> 54 #include <netinet/ip_fw.h> 55 #include <netinet/tcp.h> 56 #include <arpa/inet.h> 57 58 struct cmdline_opts co; /* global options */ 59 60 struct format_opts { 61 int bcwidth; 62 int pcwidth; 63 int show_counters; 64 int show_time; /* show timestamp */ 65 uint32_t set_mask; /* enabled sets mask */ 66 uint32_t flags; /* request flags */ 67 uint32_t first; /* first rule to request */ 68 uint32_t last; /* last rule to request */ 69 uint32_t dcnt; /* number of dynamic states */ 70 ipfw_obj_ctlv *tstate; /* table state data */ 71 }; 72 73 int resvd_set_number = RESVD_SET; 74 75 int ipfw_socket = -1; 76 77 #define CHECK_LENGTH(v, len) do { \ 78 if ((v) < (len)) \ 79 errx(EX_DATAERR, "Rule too long"); \ 80 } while (0) 81 /* 82 * Check if we have enough space in cmd buffer. Note that since 83 * first 8? u32 words are reserved by reserved header, full cmd 84 * buffer can't be used, so we need to protect from buffer overrun 85 * only. At the beginnig, cblen is less than actual buffer size by 86 * size of ipfw_insn_u32 instruction + 1 u32 work. This eliminates need 87 * for checking small instructions fitting in given range. 88 * We also (ab)use the fact that ipfw_insn is always the first field 89 * for any custom instruction. 90 */ 91 #define CHECK_CMDLEN CHECK_LENGTH(cblen, F_LEN((ipfw_insn *)cmd)) 92 93 #define GET_UINT_ARG(arg, min, max, tok, s_x) do { \ 94 if (!av[0]) \ 95 errx(EX_USAGE, "%s: missing argument", match_value(s_x, tok)); \ 96 if (_substrcmp(*av, "tablearg") == 0) { \ 97 arg = IP_FW_TARG; \ 98 break; \ 99 } \ 100 \ 101 { \ 102 long _xval; \ 103 char *end; \ 104 \ 105 _xval = strtol(*av, &end, 10); \ 106 \ 107 if (!isdigit(**av) || *end != '\0' || (_xval == 0 && errno == EINVAL)) \ 108 errx(EX_DATAERR, "%s: invalid argument: %s", \ 109 match_value(s_x, tok), *av); \ 110 \ 111 if (errno == ERANGE || _xval < min || _xval > max) \ 112 errx(EX_DATAERR, "%s: argument is out of range (%u..%u): %s", \ 113 match_value(s_x, tok), min, max, *av); \ 114 \ 115 if (_xval == IP_FW_TARG) \ 116 errx(EX_DATAERR, "%s: illegal argument value: %s", \ 117 match_value(s_x, tok), *av); \ 118 arg = _xval; \ 119 } \ 120 } while (0) 121 122 static struct _s_x f_tcpflags[] = { 123 { "syn", TH_SYN }, 124 { "fin", TH_FIN }, 125 { "ack", TH_ACK }, 126 { "psh", TH_PUSH }, 127 { "rst", TH_RST }, 128 { "urg", TH_URG }, 129 { "tcp flag", 0 }, 130 { NULL, 0 } 131 }; 132 133 static struct _s_x f_tcpopts[] = { 134 { "mss", IP_FW_TCPOPT_MSS }, 135 { "maxseg", IP_FW_TCPOPT_MSS }, 136 { "window", IP_FW_TCPOPT_WINDOW }, 137 { "sack", IP_FW_TCPOPT_SACK }, 138 { "ts", IP_FW_TCPOPT_TS }, 139 { "timestamp", IP_FW_TCPOPT_TS }, 140 { "cc", IP_FW_TCPOPT_CC }, 141 { "tcp option", 0 }, 142 { NULL, 0 } 143 }; 144 145 /* 146 * IP options span the range 0 to 255 so we need to remap them 147 * (though in fact only the low 5 bits are significant). 148 */ 149 static struct _s_x f_ipopts[] = { 150 { "ssrr", IP_FW_IPOPT_SSRR}, 151 { "lsrr", IP_FW_IPOPT_LSRR}, 152 { "rr", IP_FW_IPOPT_RR}, 153 { "ts", IP_FW_IPOPT_TS}, 154 { "ip option", 0 }, 155 { NULL, 0 } 156 }; 157 158 static struct _s_x f_iptos[] = { 159 { "lowdelay", IPTOS_LOWDELAY}, 160 { "throughput", IPTOS_THROUGHPUT}, 161 { "reliability", IPTOS_RELIABILITY}, 162 { "mincost", IPTOS_MINCOST}, 163 { "congestion", IPTOS_ECN_CE}, 164 { "ecntransport", IPTOS_ECN_ECT0}, 165 { "ip tos option", 0}, 166 { NULL, 0 } 167 }; 168 169 struct _s_x f_ipdscp[] = { 170 { "af11", IPTOS_DSCP_AF11 >> 2 }, /* 001010 */ 171 { "af12", IPTOS_DSCP_AF12 >> 2 }, /* 001100 */ 172 { "af13", IPTOS_DSCP_AF13 >> 2 }, /* 001110 */ 173 { "af21", IPTOS_DSCP_AF21 >> 2 }, /* 010010 */ 174 { "af22", IPTOS_DSCP_AF22 >> 2 }, /* 010100 */ 175 { "af23", IPTOS_DSCP_AF23 >> 2 }, /* 010110 */ 176 { "af31", IPTOS_DSCP_AF31 >> 2 }, /* 011010 */ 177 { "af32", IPTOS_DSCP_AF32 >> 2 }, /* 011100 */ 178 { "af33", IPTOS_DSCP_AF33 >> 2 }, /* 011110 */ 179 { "af41", IPTOS_DSCP_AF41 >> 2 }, /* 100010 */ 180 { "af42", IPTOS_DSCP_AF42 >> 2 }, /* 100100 */ 181 { "af43", IPTOS_DSCP_AF43 >> 2 }, /* 100110 */ 182 { "be", IPTOS_DSCP_CS0 >> 2 }, /* 000000 */ 183 { "ef", IPTOS_DSCP_EF >> 2 }, /* 101110 */ 184 { "cs0", IPTOS_DSCP_CS0 >> 2 }, /* 000000 */ 185 { "cs1", IPTOS_DSCP_CS1 >> 2 }, /* 001000 */ 186 { "cs2", IPTOS_DSCP_CS2 >> 2 }, /* 010000 */ 187 { "cs3", IPTOS_DSCP_CS3 >> 2 }, /* 011000 */ 188 { "cs4", IPTOS_DSCP_CS4 >> 2 }, /* 100000 */ 189 { "cs5", IPTOS_DSCP_CS5 >> 2 }, /* 101000 */ 190 { "cs6", IPTOS_DSCP_CS6 >> 2 }, /* 110000 */ 191 { "cs7", IPTOS_DSCP_CS7 >> 2 }, /* 100000 */ 192 { NULL, 0 } 193 }; 194 195 static struct _s_x limit_masks[] = { 196 {"all", DYN_SRC_ADDR|DYN_SRC_PORT|DYN_DST_ADDR|DYN_DST_PORT}, 197 {"src-addr", DYN_SRC_ADDR}, 198 {"src-port", DYN_SRC_PORT}, 199 {"dst-addr", DYN_DST_ADDR}, 200 {"dst-port", DYN_DST_PORT}, 201 {NULL, 0} 202 }; 203 204 /* 205 * we use IPPROTO_ETHERTYPE as a fake protocol id to call the print routines 206 * This is only used in this code. 207 */ 208 #define IPPROTO_ETHERTYPE 0x1000 209 static struct _s_x ether_types[] = { 210 /* 211 * Note, we cannot use "-:&/" in the names because they are field 212 * separators in the type specifications. Also, we use s = NULL as 213 * end-delimiter, because a type of 0 can be legal. 214 */ 215 { "ip", 0x0800 }, 216 { "ipv4", 0x0800 }, 217 { "ipv6", 0x86dd }, 218 { "arp", 0x0806 }, 219 { "rarp", 0x8035 }, 220 { "vlan", 0x8100 }, 221 { "loop", 0x9000 }, 222 { "trail", 0x1000 }, 223 { "at", 0x809b }, 224 { "atalk", 0x809b }, 225 { "aarp", 0x80f3 }, 226 { "pppoe_disc", 0x8863 }, 227 { "pppoe_sess", 0x8864 }, 228 { "ipx_8022", 0x00E0 }, 229 { "ipx_8023", 0x0000 }, 230 { "ipx_ii", 0x8137 }, 231 { "ipx_snap", 0x8137 }, 232 { "ipx", 0x8137 }, 233 { "ns", 0x0600 }, 234 { NULL, 0 } 235 }; 236 237 238 static struct _s_x rule_actions[] = { 239 { "accept", TOK_ACCEPT }, 240 { "pass", TOK_ACCEPT }, 241 { "allow", TOK_ACCEPT }, 242 { "permit", TOK_ACCEPT }, 243 { "count", TOK_COUNT }, 244 { "pipe", TOK_PIPE }, 245 { "queue", TOK_QUEUE }, 246 { "divert", TOK_DIVERT }, 247 { "tee", TOK_TEE }, 248 { "netgraph", TOK_NETGRAPH }, 249 { "ngtee", TOK_NGTEE }, 250 { "fwd", TOK_FORWARD }, 251 { "forward", TOK_FORWARD }, 252 { "skipto", TOK_SKIPTO }, 253 { "deny", TOK_DENY }, 254 { "drop", TOK_DENY }, 255 { "reject", TOK_REJECT }, 256 { "reset6", TOK_RESET6 }, 257 { "reset", TOK_RESET }, 258 { "unreach6", TOK_UNREACH6 }, 259 { "unreach", TOK_UNREACH }, 260 { "check-state", TOK_CHECKSTATE }, 261 { "//", TOK_COMMENT }, 262 { "nat", TOK_NAT }, 263 { "reass", TOK_REASS }, 264 { "setfib", TOK_SETFIB }, 265 { "setdscp", TOK_SETDSCP }, 266 { "call", TOK_CALL }, 267 { "return", TOK_RETURN }, 268 { NULL, 0 } /* terminator */ 269 }; 270 271 static struct _s_x rule_action_params[] = { 272 { "altq", TOK_ALTQ }, 273 { "log", TOK_LOG }, 274 { "tag", TOK_TAG }, 275 { "untag", TOK_UNTAG }, 276 { NULL, 0 } /* terminator */ 277 }; 278 279 /* 280 * The 'lookup' instruction accepts one of the following arguments. 281 * -1 is a terminator for the list. 282 * Arguments are passed as v[1] in O_DST_LOOKUP options. 283 */ 284 static int lookup_key[] = { 285 TOK_DSTIP, TOK_SRCIP, TOK_DSTPORT, TOK_SRCPORT, 286 TOK_UID, TOK_JAIL, TOK_DSCP, -1 }; 287 288 static struct _s_x rule_options[] = { 289 { "tagged", TOK_TAGGED }, 290 { "uid", TOK_UID }, 291 { "gid", TOK_GID }, 292 { "jail", TOK_JAIL }, 293 { "in", TOK_IN }, 294 { "limit", TOK_LIMIT }, 295 { "keep-state", TOK_KEEPSTATE }, 296 { "bridged", TOK_LAYER2 }, 297 { "layer2", TOK_LAYER2 }, 298 { "out", TOK_OUT }, 299 { "diverted", TOK_DIVERTED }, 300 { "diverted-loopback", TOK_DIVERTEDLOOPBACK }, 301 { "diverted-output", TOK_DIVERTEDOUTPUT }, 302 { "xmit", TOK_XMIT }, 303 { "recv", TOK_RECV }, 304 { "via", TOK_VIA }, 305 { "fragment", TOK_FRAG }, 306 { "frag", TOK_FRAG }, 307 { "fib", TOK_FIB }, 308 { "ipoptions", TOK_IPOPTS }, 309 { "ipopts", TOK_IPOPTS }, 310 { "iplen", TOK_IPLEN }, 311 { "ipid", TOK_IPID }, 312 { "ipprecedence", TOK_IPPRECEDENCE }, 313 { "dscp", TOK_DSCP }, 314 { "iptos", TOK_IPTOS }, 315 { "ipttl", TOK_IPTTL }, 316 { "ipversion", TOK_IPVER }, 317 { "ipver", TOK_IPVER }, 318 { "estab", TOK_ESTAB }, 319 { "established", TOK_ESTAB }, 320 { "setup", TOK_SETUP }, 321 { "sockarg", TOK_SOCKARG }, 322 { "tcpdatalen", TOK_TCPDATALEN }, 323 { "tcpflags", TOK_TCPFLAGS }, 324 { "tcpflgs", TOK_TCPFLAGS }, 325 { "tcpoptions", TOK_TCPOPTS }, 326 { "tcpopts", TOK_TCPOPTS }, 327 { "tcpseq", TOK_TCPSEQ }, 328 { "tcpack", TOK_TCPACK }, 329 { "tcpwin", TOK_TCPWIN }, 330 { "icmptype", TOK_ICMPTYPES }, 331 { "icmptypes", TOK_ICMPTYPES }, 332 { "dst-ip", TOK_DSTIP }, 333 { "src-ip", TOK_SRCIP }, 334 { "dst-port", TOK_DSTPORT }, 335 { "src-port", TOK_SRCPORT }, 336 { "proto", TOK_PROTO }, 337 { "MAC", TOK_MAC }, 338 { "mac", TOK_MAC }, 339 { "mac-type", TOK_MACTYPE }, 340 { "verrevpath", TOK_VERREVPATH }, 341 { "versrcreach", TOK_VERSRCREACH }, 342 { "antispoof", TOK_ANTISPOOF }, 343 { "ipsec", TOK_IPSEC }, 344 { "icmp6type", TOK_ICMP6TYPES }, 345 { "icmp6types", TOK_ICMP6TYPES }, 346 { "ext6hdr", TOK_EXT6HDR}, 347 { "flow-id", TOK_FLOWID}, 348 { "ipv6", TOK_IPV6}, 349 { "ip6", TOK_IPV6}, 350 { "ipv4", TOK_IPV4}, 351 { "ip4", TOK_IPV4}, 352 { "dst-ipv6", TOK_DSTIP6}, 353 { "dst-ip6", TOK_DSTIP6}, 354 { "src-ipv6", TOK_SRCIP6}, 355 { "src-ip6", TOK_SRCIP6}, 356 { "lookup", TOK_LOOKUP}, 357 { "flow", TOK_FLOW}, 358 { "//", TOK_COMMENT }, 359 360 { "not", TOK_NOT }, /* pseudo option */ 361 { "!", /* escape ? */ TOK_NOT }, /* pseudo option */ 362 { "or", TOK_OR }, /* pseudo option */ 363 { "|", /* escape */ TOK_OR }, /* pseudo option */ 364 { "{", TOK_STARTBRACE }, /* pseudo option */ 365 { "(", TOK_STARTBRACE }, /* pseudo option */ 366 { "}", TOK_ENDBRACE }, /* pseudo option */ 367 { ")", TOK_ENDBRACE }, /* pseudo option */ 368 { NULL, 0 } /* terminator */ 369 }; 370 371 void bprint_uint_arg(struct buf_pr *bp, const char *str, uint32_t arg); 372 static int ipfw_get_config(struct cmdline_opts *co, struct format_opts *fo, 373 ipfw_cfg_lheader **pcfg, size_t *psize); 374 static int ipfw_show_config(struct cmdline_opts *co, struct format_opts *fo, 375 ipfw_cfg_lheader *cfg, size_t sz, int ac, char **av); 376 static void ipfw_list_tifaces(void); 377 378 struct tidx; 379 static uint16_t pack_object(struct tidx *tstate, char *name, int otype); 380 static uint16_t pack_table(struct tidx *tstate, char *name); 381 382 static char *table_search_ctlv(ipfw_obj_ctlv *ctlv, uint16_t idx); 383 static void object_sort_ctlv(ipfw_obj_ctlv *ctlv); 384 385 /* 386 * Simple string buffer API. 387 * Used to simplify buffer passing between function and for 388 * transparent overrun handling. 389 */ 390 391 /* 392 * Allocates new buffer of given size @sz. 393 * 394 * Returns 0 on success. 395 */ 396 int 397 bp_alloc(struct buf_pr *b, size_t size) 398 { 399 memset(b, 0, sizeof(struct buf_pr)); 400 401 if ((b->buf = calloc(1, size)) == NULL) 402 return (ENOMEM); 403 404 b->ptr = b->buf; 405 b->size = size; 406 b->avail = b->size; 407 408 return (0); 409 } 410 411 void 412 bp_free(struct buf_pr *b) 413 { 414 415 free(b->buf); 416 } 417 418 /* 419 * Flushes buffer so new writer start from beginning. 420 */ 421 void 422 bp_flush(struct buf_pr *b) 423 { 424 425 b->ptr = b->buf; 426 b->avail = b->size; 427 b->buf[0] = '\0'; 428 } 429 430 /* 431 * Print message specified by @format and args. 432 * Automatically manage buffer space and transparently handle 433 * buffer overruns. 434 * 435 * Returns number of bytes that should have been printed. 436 */ 437 int 438 bprintf(struct buf_pr *b, char *format, ...) 439 { 440 va_list args; 441 int i; 442 443 va_start(args, format); 444 445 i = vsnprintf(b->ptr, b->avail, format, args); 446 va_end(args); 447 448 if (i > b->avail || i < 0) { 449 /* Overflow or print error */ 450 b->avail = 0; 451 } else { 452 b->ptr += i; 453 b->avail -= i; 454 } 455 456 b->needed += i; 457 458 return (i); 459 } 460 461 /* 462 * Special values printer for tablearg-aware opcodes. 463 */ 464 void 465 bprint_uint_arg(struct buf_pr *bp, const char *str, uint32_t arg) 466 { 467 468 if (str != NULL) 469 bprintf(bp, "%s", str); 470 if (arg == IP_FW_TARG) 471 bprintf(bp, "tablearg"); 472 else 473 bprintf(bp, "%u", arg); 474 } 475 476 /* 477 * Helper routine to print a possibly unaligned uint64_t on 478 * various platform. If width > 0, print the value with 479 * the desired width, followed by a space; 480 * otherwise, return the required width. 481 */ 482 int 483 pr_u64(struct buf_pr *b, uint64_t *pd, int width) 484 { 485 #ifdef TCC 486 #define U64_FMT "I64" 487 #else 488 #define U64_FMT "llu" 489 #endif 490 uint64_t u; 491 unsigned long long d; 492 493 bcopy (pd, &u, sizeof(u)); 494 d = u; 495 return (width > 0) ? 496 bprintf(b, "%*" U64_FMT " ", width, d) : 497 snprintf(NULL, 0, "%" U64_FMT, d) ; 498 #undef U64_FMT 499 } 500 501 502 void * 503 safe_calloc(size_t number, size_t size) 504 { 505 void *ret = calloc(number, size); 506 507 if (ret == NULL) 508 err(EX_OSERR, "calloc"); 509 return ret; 510 } 511 512 void * 513 safe_realloc(void *ptr, size_t size) 514 { 515 void *ret = realloc(ptr, size); 516 517 if (ret == NULL) 518 err(EX_OSERR, "realloc"); 519 return ret; 520 } 521 522 /* 523 * Compare things like interface or table names. 524 */ 525 int 526 stringnum_cmp(const char *a, const char *b) 527 { 528 int la, lb; 529 530 la = strlen(a); 531 lb = strlen(b); 532 533 if (la > lb) 534 return (1); 535 else if (la < lb) 536 return (-01); 537 538 return (strcmp(a, b)); 539 } 540 541 542 /* 543 * conditionally runs the command. 544 * Selected options or negative -> getsockopt 545 */ 546 int 547 do_cmd(int optname, void *optval, uintptr_t optlen) 548 { 549 int i; 550 551 if (co.test_only) 552 return 0; 553 554 if (ipfw_socket == -1) 555 ipfw_socket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); 556 if (ipfw_socket < 0) 557 err(EX_UNAVAILABLE, "socket"); 558 559 if (optname == IP_FW_GET || optname == IP_DUMMYNET_GET || 560 optname == IP_FW_ADD || optname == IP_FW3 || 561 optname == IP_FW_NAT_GET_CONFIG || 562 optname < 0 || 563 optname == IP_FW_NAT_GET_LOG) { 564 if (optname < 0) 565 optname = -optname; 566 i = getsockopt(ipfw_socket, IPPROTO_IP, optname, optval, 567 (socklen_t *)optlen); 568 } else { 569 i = setsockopt(ipfw_socket, IPPROTO_IP, optname, optval, optlen); 570 } 571 return i; 572 } 573 574 /* 575 * do_set3 - pass ipfw control cmd to kernel 576 * @optname: option name 577 * @optval: pointer to option data 578 * @optlen: option length 579 * 580 * Assumes op3 header is already embedded. 581 * Calls setsockopt() with IP_FW3 as kernel-visible opcode. 582 * Returns 0 on success or errno otherwise. 583 */ 584 int 585 do_set3(int optname, ip_fw3_opheader *op3, uintptr_t optlen) 586 { 587 588 if (co.test_only) 589 return (0); 590 591 if (ipfw_socket == -1) 592 ipfw_socket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); 593 if (ipfw_socket < 0) 594 err(EX_UNAVAILABLE, "socket"); 595 596 op3->opcode = optname; 597 598 return (setsockopt(ipfw_socket, IPPROTO_IP, IP_FW3, op3, optlen)); 599 } 600 601 /* 602 * do_get3 - pass ipfw control cmd to kernel 603 * @optname: option name 604 * @optval: pointer to option data 605 * @optlen: pointer to option length 606 * 607 * Assumes op3 header is already embedded. 608 * Calls getsockopt() with IP_FW3 as kernel-visible opcode. 609 * Returns 0 on success or errno otherwise. 610 */ 611 int 612 do_get3(int optname, ip_fw3_opheader *op3, size_t *optlen) 613 { 614 int error; 615 616 if (co.test_only) 617 return (0); 618 619 if (ipfw_socket == -1) 620 ipfw_socket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); 621 if (ipfw_socket < 0) 622 err(EX_UNAVAILABLE, "socket"); 623 624 op3->opcode = optname; 625 626 error = getsockopt(ipfw_socket, IPPROTO_IP, IP_FW3, op3, 627 (socklen_t *)optlen); 628 629 return (error); 630 } 631 632 /** 633 * match_token takes a table and a string, returns the value associated 634 * with the string (-1 in case of failure). 635 */ 636 int 637 match_token(struct _s_x *table, char *string) 638 { 639 struct _s_x *pt; 640 uint i = strlen(string); 641 642 for (pt = table ; i && pt->s != NULL ; pt++) 643 if (strlen(pt->s) == i && !bcmp(string, pt->s, i)) 644 return pt->x; 645 return (-1); 646 } 647 648 /** 649 * match_token takes a table and a string, returns the value associated 650 * with the string for the best match. 651 * 652 * Returns: 653 * value from @table for matched records 654 * -1 for non-matched records 655 * -2 if more than one records match @string. 656 */ 657 int 658 match_token_relaxed(struct _s_x *table, char *string) 659 { 660 struct _s_x *pt, *m; 661 int i, c; 662 663 i = strlen(string); 664 c = 0; 665 666 for (pt = table ; i != 0 && pt->s != NULL ; pt++) { 667 if (strncmp(pt->s, string, i) != 0) 668 continue; 669 m = pt; 670 c++; 671 } 672 673 if (c == 1) 674 return (m->x); 675 676 return (c > 0 ? -2: -1); 677 } 678 679 /** 680 * match_value takes a table and a value, returns the string associated 681 * with the value (NULL in case of failure). 682 */ 683 char const * 684 match_value(struct _s_x *p, int value) 685 { 686 for (; p->s != NULL; p++) 687 if (p->x == value) 688 return p->s; 689 return NULL; 690 } 691 692 size_t 693 concat_tokens(char *buf, size_t bufsize, struct _s_x *table, char *delimiter) 694 { 695 struct _s_x *pt; 696 int l; 697 size_t sz; 698 699 for (sz = 0, pt = table ; pt->s != NULL; pt++) { 700 l = snprintf(buf + sz, bufsize - sz, "%s%s", 701 (sz == 0) ? "" : delimiter, pt->s); 702 sz += l; 703 bufsize += l; 704 if (sz > bufsize) 705 return (bufsize); 706 } 707 708 return (sz); 709 } 710 711 /* 712 * helper function to process a set of flags and set bits in the 713 * appropriate masks. 714 */ 715 int 716 fill_flags(struct _s_x *flags, char *p, char **e, uint32_t *set, 717 uint32_t *clear) 718 { 719 char *q; /* points to the separator */ 720 int val; 721 uint32_t *which; /* mask we are working on */ 722 723 while (p && *p) { 724 if (*p == '!') { 725 p++; 726 which = clear; 727 } else 728 which = set; 729 q = strchr(p, ','); 730 if (q) 731 *q++ = '\0'; 732 val = match_token(flags, p); 733 if (val <= 0) { 734 if (e != NULL) 735 *e = p; 736 return (-1); 737 } 738 *which |= (uint32_t)val; 739 p = q; 740 } 741 return (0); 742 } 743 744 void 745 print_flags_buffer(char *buf, size_t sz, struct _s_x *list, uint32_t set) 746 { 747 char const *comma = ""; 748 int i, l; 749 750 for (i = 0; list[i].x != 0; i++) { 751 if ((set & list[i].x) == 0) 752 continue; 753 754 set &= ~list[i].x; 755 l = snprintf(buf, sz, "%s%s", comma, list[i].s); 756 if (l >= sz) 757 return; 758 comma = ","; 759 buf += l; 760 sz -=l; 761 } 762 } 763 764 /* 765 * _substrcmp takes two strings and returns 1 if they do not match, 766 * and 0 if they match exactly or the first string is a sub-string 767 * of the second. A warning is printed to stderr in the case that the 768 * first string is a sub-string of the second. 769 * 770 * This function will be removed in the future through the usual 771 * deprecation process. 772 */ 773 int 774 _substrcmp(const char *str1, const char* str2) 775 { 776 777 if (strncmp(str1, str2, strlen(str1)) != 0) 778 return 1; 779 780 if (strlen(str1) != strlen(str2)) 781 warnx("DEPRECATED: '%s' matched '%s' as a sub-string", 782 str1, str2); 783 return 0; 784 } 785 786 /* 787 * _substrcmp2 takes three strings and returns 1 if the first two do not match, 788 * and 0 if they match exactly or the second string is a sub-string 789 * of the first. A warning is printed to stderr in the case that the 790 * first string does not match the third. 791 * 792 * This function exists to warn about the bizarre construction 793 * strncmp(str, "by", 2) which is used to allow people to use a shortcut 794 * for "bytes". The problem is that in addition to accepting "by", 795 * "byt", "byte", and "bytes", it also excepts "by_rabid_dogs" and any 796 * other string beginning with "by". 797 * 798 * This function will be removed in the future through the usual 799 * deprecation process. 800 */ 801 int 802 _substrcmp2(const char *str1, const char* str2, const char* str3) 803 { 804 805 if (strncmp(str1, str2, strlen(str2)) != 0) 806 return 1; 807 808 if (strcmp(str1, str3) != 0) 809 warnx("DEPRECATED: '%s' matched '%s'", 810 str1, str3); 811 return 0; 812 } 813 814 /* 815 * prints one port, symbolic or numeric 816 */ 817 static void 818 print_port(struct buf_pr *bp, int proto, uint16_t port) 819 { 820 821 if (proto == IPPROTO_ETHERTYPE) { 822 char const *s; 823 824 if (co.do_resolv && (s = match_value(ether_types, port)) ) 825 bprintf(bp, "%s", s); 826 else 827 bprintf(bp, "0x%04x", port); 828 } else { 829 struct servent *se = NULL; 830 if (co.do_resolv) { 831 struct protoent *pe = getprotobynumber(proto); 832 833 se = getservbyport(htons(port), pe ? pe->p_name : NULL); 834 } 835 if (se) 836 bprintf(bp, "%s", se->s_name); 837 else 838 bprintf(bp, "%d", port); 839 } 840 } 841 842 static struct _s_x _port_name[] = { 843 {"dst-port", O_IP_DSTPORT}, 844 {"src-port", O_IP_SRCPORT}, 845 {"ipid", O_IPID}, 846 {"iplen", O_IPLEN}, 847 {"ipttl", O_IPTTL}, 848 {"mac-type", O_MAC_TYPE}, 849 {"tcpdatalen", O_TCPDATALEN}, 850 {"tcpwin", O_TCPWIN}, 851 {"tagged", O_TAGGED}, 852 {NULL, 0} 853 }; 854 855 /* 856 * Print the values in a list 16-bit items of the types above. 857 * XXX todo: add support for mask. 858 */ 859 static void 860 print_newports(struct buf_pr *bp, ipfw_insn_u16 *cmd, int proto, int opcode) 861 { 862 uint16_t *p = cmd->ports; 863 int i; 864 char const *sep; 865 866 if (opcode != 0) { 867 sep = match_value(_port_name, opcode); 868 if (sep == NULL) 869 sep = "???"; 870 bprintf(bp, " %s", sep); 871 } 872 sep = " "; 873 for (i = F_LEN((ipfw_insn *)cmd) - 1; i > 0; i--, p += 2) { 874 bprintf(bp, "%s", sep); 875 print_port(bp, proto, p[0]); 876 if (p[0] != p[1]) { 877 bprintf(bp, "-"); 878 print_port(bp, proto, p[1]); 879 } 880 sep = ","; 881 } 882 } 883 884 /* 885 * Like strtol, but also translates service names into port numbers 886 * for some protocols. 887 * In particular: 888 * proto == -1 disables the protocol check; 889 * proto == IPPROTO_ETHERTYPE looks up an internal table 890 * proto == <some value in /etc/protocols> matches the values there. 891 * Returns *end == s in case the parameter is not found. 892 */ 893 static int 894 strtoport(char *s, char **end, int base, int proto) 895 { 896 char *p, *buf; 897 char *s1; 898 int i; 899 900 *end = s; /* default - not found */ 901 if (*s == '\0') 902 return 0; /* not found */ 903 904 if (isdigit(*s)) 905 return strtol(s, end, base); 906 907 /* 908 * find separator. '\\' escapes the next char. 909 */ 910 for (s1 = s; *s1 && (isalnum(*s1) || *s1 == '\\') ; s1++) 911 if (*s1 == '\\' && s1[1] != '\0') 912 s1++; 913 914 buf = safe_calloc(s1 - s + 1, 1); 915 916 /* 917 * copy into a buffer skipping backslashes 918 */ 919 for (p = s, i = 0; p != s1 ; p++) 920 if (*p != '\\') 921 buf[i++] = *p; 922 buf[i++] = '\0'; 923 924 if (proto == IPPROTO_ETHERTYPE) { 925 i = match_token(ether_types, buf); 926 free(buf); 927 if (i != -1) { /* found */ 928 *end = s1; 929 return i; 930 } 931 } else { 932 struct protoent *pe = NULL; 933 struct servent *se; 934 935 if (proto != 0) 936 pe = getprotobynumber(proto); 937 setservent(1); 938 se = getservbyname(buf, pe ? pe->p_name : NULL); 939 free(buf); 940 if (se != NULL) { 941 *end = s1; 942 return ntohs(se->s_port); 943 } 944 } 945 return 0; /* not found */ 946 } 947 948 /* 949 * Fill the body of the command with the list of port ranges. 950 */ 951 static int 952 fill_newports(ipfw_insn_u16 *cmd, char *av, int proto, int cblen) 953 { 954 uint16_t a, b, *p = cmd->ports; 955 int i = 0; 956 char *s = av; 957 958 while (*s) { 959 a = strtoport(av, &s, 0, proto); 960 if (s == av) /* empty or invalid argument */ 961 return (0); 962 963 CHECK_LENGTH(cblen, i + 2); 964 965 switch (*s) { 966 case '-': /* a range */ 967 av = s + 1; 968 b = strtoport(av, &s, 0, proto); 969 /* Reject expressions like '1-abc' or '1-2-3'. */ 970 if (s == av || (*s != ',' && *s != '\0')) 971 return (0); 972 p[0] = a; 973 p[1] = b; 974 break; 975 case ',': /* comma separated list */ 976 case '\0': 977 p[0] = p[1] = a; 978 break; 979 default: 980 warnx("port list: invalid separator <%c> in <%s>", 981 *s, av); 982 return (0); 983 } 984 985 i++; 986 p += 2; 987 av = s + 1; 988 } 989 if (i > 0) { 990 if (i + 1 > F_LEN_MASK) 991 errx(EX_DATAERR, "too many ports/ranges\n"); 992 cmd->o.len |= i + 1; /* leave F_NOT and F_OR untouched */ 993 } 994 return (i); 995 } 996 997 /* 998 * Fill the body of the command with the list of DiffServ codepoints. 999 */ 1000 static void 1001 fill_dscp(ipfw_insn *cmd, char *av, int cblen) 1002 { 1003 uint32_t *low, *high; 1004 char *s = av, *a; 1005 int code; 1006 1007 cmd->opcode = O_DSCP; 1008 cmd->len |= F_INSN_SIZE(ipfw_insn_u32) + 1; 1009 1010 CHECK_CMDLEN; 1011 1012 low = (uint32_t *)(cmd + 1); 1013 high = low + 1; 1014 1015 *low = 0; 1016 *high = 0; 1017 1018 while (s != NULL) { 1019 a = strchr(s, ','); 1020 1021 if (a != NULL) 1022 *a++ = '\0'; 1023 1024 if (isalpha(*s)) { 1025 if ((code = match_token(f_ipdscp, s)) == -1) 1026 errx(EX_DATAERR, "Unknown DSCP code"); 1027 } else { 1028 code = strtoul(s, NULL, 10); 1029 if (code < 0 || code > 63) 1030 errx(EX_DATAERR, "Invalid DSCP value"); 1031 } 1032 1033 if (code >= 32) 1034 *high |= 1 << (code - 32); 1035 else 1036 *low |= 1 << code; 1037 1038 s = a; 1039 } 1040 } 1041 1042 static struct _s_x icmpcodes[] = { 1043 { "net", ICMP_UNREACH_NET }, 1044 { "host", ICMP_UNREACH_HOST }, 1045 { "protocol", ICMP_UNREACH_PROTOCOL }, 1046 { "port", ICMP_UNREACH_PORT }, 1047 { "needfrag", ICMP_UNREACH_NEEDFRAG }, 1048 { "srcfail", ICMP_UNREACH_SRCFAIL }, 1049 { "net-unknown", ICMP_UNREACH_NET_UNKNOWN }, 1050 { "host-unknown", ICMP_UNREACH_HOST_UNKNOWN }, 1051 { "isolated", ICMP_UNREACH_ISOLATED }, 1052 { "net-prohib", ICMP_UNREACH_NET_PROHIB }, 1053 { "host-prohib", ICMP_UNREACH_HOST_PROHIB }, 1054 { "tosnet", ICMP_UNREACH_TOSNET }, 1055 { "toshost", ICMP_UNREACH_TOSHOST }, 1056 { "filter-prohib", ICMP_UNREACH_FILTER_PROHIB }, 1057 { "host-precedence", ICMP_UNREACH_HOST_PRECEDENCE }, 1058 { "precedence-cutoff", ICMP_UNREACH_PRECEDENCE_CUTOFF }, 1059 { NULL, 0 } 1060 }; 1061 1062 static void 1063 fill_reject_code(u_short *codep, char *str) 1064 { 1065 int val; 1066 char *s; 1067 1068 val = strtoul(str, &s, 0); 1069 if (s == str || *s != '\0' || val >= 0x100) 1070 val = match_token(icmpcodes, str); 1071 if (val < 0) 1072 errx(EX_DATAERR, "unknown ICMP unreachable code ``%s''", str); 1073 *codep = val; 1074 return; 1075 } 1076 1077 static void 1078 print_reject_code(struct buf_pr *bp, uint16_t code) 1079 { 1080 char const *s; 1081 1082 if ((s = match_value(icmpcodes, code)) != NULL) 1083 bprintf(bp, "unreach %s", s); 1084 else 1085 bprintf(bp, "unreach %u", code); 1086 } 1087 1088 /* 1089 * Returns the number of bits set (from left) in a contiguous bitmask, 1090 * or -1 if the mask is not contiguous. 1091 * XXX this needs a proper fix. 1092 * This effectively works on masks in big-endian (network) format. 1093 * when compiled on little endian architectures. 1094 * 1095 * First bit is bit 7 of the first byte -- note, for MAC addresses, 1096 * the first bit on the wire is bit 0 of the first byte. 1097 * len is the max length in bits. 1098 */ 1099 int 1100 contigmask(uint8_t *p, int len) 1101 { 1102 int i, n; 1103 1104 for (i=0; i<len ; i++) 1105 if ( (p[i/8] & (1 << (7 - (i%8)))) == 0) /* first bit unset */ 1106 break; 1107 for (n=i+1; n < len; n++) 1108 if ( (p[n/8] & (1 << (7 - (n%8)))) != 0) 1109 return -1; /* mask not contiguous */ 1110 return i; 1111 } 1112 1113 /* 1114 * print flags set/clear in the two bitmasks passed as parameters. 1115 * There is a specialized check for f_tcpflags. 1116 */ 1117 static void 1118 print_flags(struct buf_pr *bp, char const *name, ipfw_insn *cmd, 1119 struct _s_x *list) 1120 { 1121 char const *comma = ""; 1122 int i; 1123 uint8_t set = cmd->arg1 & 0xff; 1124 uint8_t clear = (cmd->arg1 >> 8) & 0xff; 1125 1126 if (list == f_tcpflags && set == TH_SYN && clear == TH_ACK) { 1127 bprintf(bp, " setup"); 1128 return; 1129 } 1130 1131 bprintf(bp, " %s ", name); 1132 for (i=0; list[i].x != 0; i++) { 1133 if (set & list[i].x) { 1134 set &= ~list[i].x; 1135 bprintf(bp, "%s%s", comma, list[i].s); 1136 comma = ","; 1137 } 1138 if (clear & list[i].x) { 1139 clear &= ~list[i].x; 1140 bprintf(bp, "%s!%s", comma, list[i].s); 1141 comma = ","; 1142 } 1143 } 1144 } 1145 1146 1147 /* 1148 * Print the ip address contained in a command. 1149 */ 1150 static void 1151 print_ip(struct buf_pr *bp, struct format_opts *fo, ipfw_insn_ip *cmd, 1152 char const *s) 1153 { 1154 struct hostent *he = NULL; 1155 struct in_addr *ia; 1156 uint32_t len = F_LEN((ipfw_insn *)cmd); 1157 uint32_t *a = ((ipfw_insn_u32 *)cmd)->d; 1158 char *t; 1159 1160 if (cmd->o.opcode == O_IP_DST_LOOKUP && len > F_INSN_SIZE(ipfw_insn_u32)) { 1161 uint32_t d = a[1]; 1162 const char *arg = "<invalid>"; 1163 1164 if (d < sizeof(lookup_key)/sizeof(lookup_key[0])) 1165 arg = match_value(rule_options, lookup_key[d]); 1166 t = table_search_ctlv(fo->tstate, ((ipfw_insn *)cmd)->arg1); 1167 bprintf(bp, "%s lookup %s %s", cmd->o.len & F_NOT ? " not": "", 1168 arg, t); 1169 return; 1170 } 1171 bprintf(bp, "%s%s ", cmd->o.len & F_NOT ? " not": "", s); 1172 1173 if (cmd->o.opcode == O_IP_SRC_ME || cmd->o.opcode == O_IP_DST_ME) { 1174 bprintf(bp, "me"); 1175 return; 1176 } 1177 if (cmd->o.opcode == O_IP_SRC_LOOKUP || 1178 cmd->o.opcode == O_IP_DST_LOOKUP) { 1179 t = table_search_ctlv(fo->tstate, ((ipfw_insn *)cmd)->arg1); 1180 bprintf(bp, "table(%s", t); 1181 if (len == F_INSN_SIZE(ipfw_insn_u32)) 1182 bprintf(bp, ",%u", *a); 1183 bprintf(bp, ")"); 1184 return; 1185 } 1186 if (cmd->o.opcode == O_IP_SRC_SET || cmd->o.opcode == O_IP_DST_SET) { 1187 uint32_t x, *map = (uint32_t *)&(cmd->mask); 1188 int i, j; 1189 char comma = '{'; 1190 1191 x = cmd->o.arg1 - 1; 1192 x = htonl( ~x ); 1193 cmd->addr.s_addr = htonl(cmd->addr.s_addr); 1194 bprintf(bp, "%s/%d", inet_ntoa(cmd->addr), 1195 contigmask((uint8_t *)&x, 32)); 1196 x = cmd->addr.s_addr = htonl(cmd->addr.s_addr); 1197 x &= 0xff; /* base */ 1198 /* 1199 * Print bits and ranges. 1200 * Locate first bit set (i), then locate first bit unset (j). 1201 * If we have 3+ consecutive bits set, then print them as a 1202 * range, otherwise only print the initial bit and rescan. 1203 */ 1204 for (i=0; i < cmd->o.arg1; i++) 1205 if (map[i/32] & (1<<(i & 31))) { 1206 for (j=i+1; j < cmd->o.arg1; j++) 1207 if (!(map[ j/32] & (1<<(j & 31)))) 1208 break; 1209 bprintf(bp, "%c%d", comma, i+x); 1210 if (j>i+2) { /* range has at least 3 elements */ 1211 bprintf(bp, "-%d", j-1+x); 1212 i = j-1; 1213 } 1214 comma = ','; 1215 } 1216 bprintf(bp, "}"); 1217 return; 1218 } 1219 /* 1220 * len == 2 indicates a single IP, whereas lists of 1 or more 1221 * addr/mask pairs have len = (2n+1). We convert len to n so we 1222 * use that to count the number of entries. 1223 */ 1224 for (len = len / 2; len > 0; len--, a += 2) { 1225 int mb = /* mask length */ 1226 (cmd->o.opcode == O_IP_SRC || cmd->o.opcode == O_IP_DST) ? 1227 32 : contigmask((uint8_t *)&(a[1]), 32); 1228 if (mb == 32 && co.do_resolv) 1229 he = gethostbyaddr((char *)&(a[0]), sizeof(u_long), AF_INET); 1230 if (he != NULL) /* resolved to name */ 1231 bprintf(bp, "%s", he->h_name); 1232 else if (mb == 0) /* any */ 1233 bprintf(bp, "any"); 1234 else { /* numeric IP followed by some kind of mask */ 1235 ia = (struct in_addr *)&a[0]; 1236 bprintf(bp, "%s", inet_ntoa(*ia)); 1237 if (mb < 0) { 1238 ia = (struct in_addr *)&a[1]; 1239 bprintf(bp, ":%s", inet_ntoa(*ia)); 1240 } else if (mb < 32) 1241 bprintf(bp, "/%d", mb); 1242 } 1243 if (len > 1) 1244 bprintf(bp, ","); 1245 } 1246 } 1247 1248 /* 1249 * prints a MAC address/mask pair 1250 */ 1251 static void 1252 print_mac(struct buf_pr *bp, uint8_t *addr, uint8_t *mask) 1253 { 1254 int l = contigmask(mask, 48); 1255 1256 if (l == 0) 1257 bprintf(bp, " any"); 1258 else { 1259 bprintf(bp, " %02x:%02x:%02x:%02x:%02x:%02x", 1260 addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); 1261 if (l == -1) 1262 bprintf(bp, "&%02x:%02x:%02x:%02x:%02x:%02x", 1263 mask[0], mask[1], mask[2], 1264 mask[3], mask[4], mask[5]); 1265 else if (l < 48) 1266 bprintf(bp, "/%d", l); 1267 } 1268 } 1269 1270 static void 1271 fill_icmptypes(ipfw_insn_u32 *cmd, char *av) 1272 { 1273 uint8_t type; 1274 1275 cmd->d[0] = 0; 1276 while (*av) { 1277 if (*av == ',') 1278 av++; 1279 1280 type = strtoul(av, &av, 0); 1281 1282 if (*av != ',' && *av != '\0') 1283 errx(EX_DATAERR, "invalid ICMP type"); 1284 1285 if (type > 31) 1286 errx(EX_DATAERR, "ICMP type out of range"); 1287 1288 cmd->d[0] |= 1 << type; 1289 } 1290 cmd->o.opcode = O_ICMPTYPE; 1291 cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32); 1292 } 1293 1294 static void 1295 print_icmptypes(struct buf_pr *bp, ipfw_insn_u32 *cmd) 1296 { 1297 int i; 1298 char sep= ' '; 1299 1300 bprintf(bp, " icmptypes"); 1301 for (i = 0; i < 32; i++) { 1302 if ( (cmd->d[0] & (1 << (i))) == 0) 1303 continue; 1304 bprintf(bp, "%c%d", sep, i); 1305 sep = ','; 1306 } 1307 } 1308 1309 static void 1310 print_dscp(struct buf_pr *bp, ipfw_insn_u32 *cmd) 1311 { 1312 int i = 0; 1313 uint32_t *v; 1314 char sep= ' '; 1315 const char *code; 1316 1317 bprintf(bp, " dscp"); 1318 v = cmd->d; 1319 while (i < 64) { 1320 if (*v & (1 << i)) { 1321 if ((code = match_value(f_ipdscp, i)) != NULL) 1322 bprintf(bp, "%c%s", sep, code); 1323 else 1324 bprintf(bp, "%c%d", sep, i); 1325 sep = ','; 1326 } 1327 1328 if ((++i % 32) == 0) 1329 v++; 1330 } 1331 } 1332 1333 /* 1334 * show_ipfw() prints the body of an ipfw rule. 1335 * Because the standard rule has at least proto src_ip dst_ip, we use 1336 * a helper function to produce these entries if not provided explicitly. 1337 * The first argument is the list of fields we have, the second is 1338 * the list of fields we want to be printed. 1339 * 1340 * Special cases if we have provided a MAC header: 1341 * + if the rule does not contain IP addresses/ports, do not print them; 1342 * + if the rule does not contain an IP proto, print "all" instead of "ip"; 1343 * 1344 * Once we have 'have_options', IP header fields are printed as options. 1345 */ 1346 #define HAVE_PROTO 0x0001 1347 #define HAVE_SRCIP 0x0002 1348 #define HAVE_DSTIP 0x0004 1349 #define HAVE_PROTO4 0x0008 1350 #define HAVE_PROTO6 0x0010 1351 #define HAVE_IP 0x0100 1352 #define HAVE_OPTIONS 0x8000 1353 1354 static void 1355 show_prerequisites(struct buf_pr *bp, int *flags, int want, int cmd) 1356 { 1357 (void)cmd; /* UNUSED */ 1358 if (co.comment_only) 1359 return; 1360 if ( (*flags & HAVE_IP) == HAVE_IP) 1361 *flags |= HAVE_OPTIONS; 1362 1363 if ( !(*flags & HAVE_OPTIONS)) { 1364 if ( !(*flags & HAVE_PROTO) && (want & HAVE_PROTO)) { 1365 if ( (*flags & HAVE_PROTO4)) 1366 bprintf(bp, " ip4"); 1367 else if ( (*flags & HAVE_PROTO6)) 1368 bprintf(bp, " ip6"); 1369 else 1370 bprintf(bp, " ip"); 1371 } 1372 if ( !(*flags & HAVE_SRCIP) && (want & HAVE_SRCIP)) 1373 bprintf(bp, " from any"); 1374 if ( !(*flags & HAVE_DSTIP) && (want & HAVE_DSTIP)) 1375 bprintf(bp, " to any"); 1376 } 1377 *flags |= want; 1378 } 1379 1380 static void 1381 show_static_rule(struct cmdline_opts *co, struct format_opts *fo, 1382 struct buf_pr *bp, struct ip_fw_rule *rule, struct ip_fw_bcounter *cntr) 1383 { 1384 static int twidth = 0; 1385 int l; 1386 ipfw_insn *cmd, *tagptr = NULL; 1387 const char *comment = NULL; /* ptr to comment if we have one */ 1388 int proto = 0; /* default */ 1389 int flags = 0; /* prerequisites */ 1390 ipfw_insn_log *logptr = NULL; /* set if we find an O_LOG */ 1391 ipfw_insn_altq *altqptr = NULL; /* set if we find an O_ALTQ */ 1392 int or_block = 0; /* we are in an or block */ 1393 uint32_t uval; 1394 1395 if ((fo->set_mask & (1 << rule->set)) == 0) { 1396 /* disabled mask */ 1397 if (!co->show_sets) 1398 return; 1399 else 1400 bprintf(bp, "# DISABLED "); 1401 } 1402 bprintf(bp, "%05u ", rule->rulenum); 1403 1404 /* Print counters if enabled */ 1405 if (fo->pcwidth > 0 || fo->bcwidth > 0) { 1406 pr_u64(bp, &cntr->pcnt, fo->pcwidth); 1407 pr_u64(bp, &cntr->bcnt, fo->bcwidth); 1408 } 1409 1410 if (co->do_time == 2) 1411 bprintf(bp, "%10u ", cntr->timestamp); 1412 else if (co->do_time == 1) { 1413 char timestr[30]; 1414 time_t t = (time_t)0; 1415 1416 if (twidth == 0) { 1417 strcpy(timestr, ctime(&t)); 1418 *strchr(timestr, '\n') = '\0'; 1419 twidth = strlen(timestr); 1420 } 1421 if (cntr->timestamp > 0) { 1422 t = _long_to_time(cntr->timestamp); 1423 1424 strcpy(timestr, ctime(&t)); 1425 *strchr(timestr, '\n') = '\0'; 1426 bprintf(bp, "%s ", timestr); 1427 } else { 1428 bprintf(bp, "%*s", twidth, " "); 1429 } 1430 } 1431 1432 if (co->show_sets) 1433 bprintf(bp, "set %d ", rule->set); 1434 1435 /* 1436 * print the optional "match probability" 1437 */ 1438 if (rule->cmd_len > 0) { 1439 cmd = rule->cmd ; 1440 if (cmd->opcode == O_PROB) { 1441 ipfw_insn_u32 *p = (ipfw_insn_u32 *)cmd; 1442 double d = 1.0 * p->d[0]; 1443 1444 d = (d / 0x7fffffff); 1445 bprintf(bp, "prob %f ", d); 1446 } 1447 } 1448 1449 /* 1450 * first print actions 1451 */ 1452 for (l = rule->cmd_len - rule->act_ofs, cmd = ACTION_PTR(rule); 1453 l > 0 ; l -= F_LEN(cmd), cmd += F_LEN(cmd)) { 1454 switch(cmd->opcode) { 1455 case O_CHECK_STATE: 1456 bprintf(bp, "check-state"); 1457 /* avoid printing anything else */ 1458 flags = HAVE_PROTO | HAVE_SRCIP | 1459 HAVE_DSTIP | HAVE_IP; 1460 break; 1461 1462 case O_ACCEPT: 1463 bprintf(bp, "allow"); 1464 break; 1465 1466 case O_COUNT: 1467 bprintf(bp, "count"); 1468 break; 1469 1470 case O_DENY: 1471 bprintf(bp, "deny"); 1472 break; 1473 1474 case O_REJECT: 1475 if (cmd->arg1 == ICMP_REJECT_RST) 1476 bprintf(bp, "reset"); 1477 else if (cmd->arg1 == ICMP_UNREACH_HOST) 1478 bprintf(bp, "reject"); 1479 else 1480 print_reject_code(bp, cmd->arg1); 1481 break; 1482 1483 case O_UNREACH6: 1484 if (cmd->arg1 == ICMP6_UNREACH_RST) 1485 bprintf(bp, "reset6"); 1486 else 1487 print_unreach6_code(cmd->arg1); 1488 break; 1489 1490 case O_SKIPTO: 1491 bprint_uint_arg(bp, "skipto ", cmd->arg1); 1492 break; 1493 1494 case O_PIPE: 1495 bprint_uint_arg(bp, "pipe ", cmd->arg1); 1496 break; 1497 1498 case O_QUEUE: 1499 bprint_uint_arg(bp, "queue ", cmd->arg1); 1500 break; 1501 1502 case O_DIVERT: 1503 bprint_uint_arg(bp, "divert ", cmd->arg1); 1504 break; 1505 1506 case O_TEE: 1507 bprint_uint_arg(bp, "tee ", cmd->arg1); 1508 break; 1509 1510 case O_NETGRAPH: 1511 bprint_uint_arg(bp, "netgraph ", cmd->arg1); 1512 break; 1513 1514 case O_NGTEE: 1515 bprint_uint_arg(bp, "ngtee ", cmd->arg1); 1516 break; 1517 1518 case O_FORWARD_IP: 1519 { 1520 ipfw_insn_sa *s = (ipfw_insn_sa *)cmd; 1521 1522 if (s->sa.sin_addr.s_addr == INADDR_ANY) { 1523 bprintf(bp, "fwd tablearg"); 1524 } else { 1525 bprintf(bp, "fwd %s",inet_ntoa(s->sa.sin_addr)); 1526 } 1527 if (s->sa.sin_port) 1528 bprintf(bp, ",%d", s->sa.sin_port); 1529 } 1530 break; 1531 1532 case O_FORWARD_IP6: 1533 { 1534 char buf[INET6_ADDRSTRLEN + IF_NAMESIZE + 2]; 1535 ipfw_insn_sa6 *s = (ipfw_insn_sa6 *)cmd; 1536 1537 bprintf(bp, "fwd "); 1538 if (getnameinfo((const struct sockaddr *)&s->sa, 1539 sizeof(struct sockaddr_in6), buf, sizeof(buf), 1540 NULL, 0, NI_NUMERICHOST) == 0) 1541 bprintf(bp, "%s", buf); 1542 if (s->sa.sin6_port) 1543 bprintf(bp, ",%d", s->sa.sin6_port); 1544 } 1545 break; 1546 1547 case O_LOG: /* O_LOG is printed last */ 1548 logptr = (ipfw_insn_log *)cmd; 1549 break; 1550 1551 case O_ALTQ: /* O_ALTQ is printed after O_LOG */ 1552 altqptr = (ipfw_insn_altq *)cmd; 1553 break; 1554 1555 case O_TAG: 1556 tagptr = cmd; 1557 break; 1558 1559 case O_NAT: 1560 if (cmd->arg1 != 0) 1561 bprint_uint_arg(bp, "nat ", cmd->arg1); 1562 else 1563 bprintf(bp, "nat global"); 1564 break; 1565 1566 case O_SETFIB: 1567 bprint_uint_arg(bp, "setfib ", cmd->arg1 & 0x7FFF); 1568 break; 1569 1570 case O_SETDSCP: 1571 { 1572 const char *code; 1573 1574 if (cmd->arg1 == IP_FW_TARG) { 1575 bprint_uint_arg(bp, "setdscp ", cmd->arg1); 1576 break; 1577 } 1578 uval = cmd->arg1 & 0x3F; 1579 if ((code = match_value(f_ipdscp, uval)) != NULL) 1580 bprintf(bp, "setdscp %s", code); 1581 else 1582 bprint_uint_arg(bp, "setdscp ", uval); 1583 } 1584 break; 1585 1586 case O_REASS: 1587 bprintf(bp, "reass"); 1588 break; 1589 1590 case O_CALLRETURN: 1591 if (cmd->len & F_NOT) 1592 bprintf(bp, "return"); 1593 else 1594 bprint_uint_arg(bp, "call ", cmd->arg1); 1595 break; 1596 1597 default: 1598 bprintf(bp, "** unrecognized action %d len %d ", 1599 cmd->opcode, cmd->len); 1600 } 1601 } 1602 if (logptr) { 1603 if (logptr->max_log > 0) 1604 bprintf(bp, " log logamount %d", logptr->max_log); 1605 else 1606 bprintf(bp, " log"); 1607 } 1608 #ifndef NO_ALTQ 1609 if (altqptr) { 1610 print_altq_cmd(bp, altqptr); 1611 } 1612 #endif 1613 if (tagptr) { 1614 if (tagptr->len & F_NOT) 1615 bprint_uint_arg(bp, " untag ", tagptr->arg1); 1616 else 1617 bprint_uint_arg(bp, " tag ", tagptr->arg1); 1618 } 1619 1620 /* 1621 * then print the body. 1622 */ 1623 for (l = rule->act_ofs, cmd = rule->cmd; 1624 l > 0 ; l -= F_LEN(cmd) , cmd += F_LEN(cmd)) { 1625 if ((cmd->len & F_OR) || (cmd->len & F_NOT)) 1626 continue; 1627 if (cmd->opcode == O_IP4) { 1628 flags |= HAVE_PROTO4; 1629 break; 1630 } else if (cmd->opcode == O_IP6) { 1631 flags |= HAVE_PROTO6; 1632 break; 1633 } 1634 } 1635 if (rule->flags & IPFW_RULE_NOOPT) { /* empty rules before options */ 1636 if (!co->do_compact) { 1637 show_prerequisites(bp, &flags, HAVE_PROTO, 0); 1638 bprintf(bp, " from any to any"); 1639 } 1640 flags |= HAVE_IP | HAVE_OPTIONS | HAVE_PROTO | 1641 HAVE_SRCIP | HAVE_DSTIP; 1642 } 1643 1644 if (co->comment_only) 1645 comment = "..."; 1646 1647 for (l = rule->act_ofs, cmd = rule->cmd; 1648 l > 0 ; l -= F_LEN(cmd) , cmd += F_LEN(cmd)) { 1649 /* useful alias */ 1650 ipfw_insn_u32 *cmd32 = (ipfw_insn_u32 *)cmd; 1651 1652 if (co->comment_only) { 1653 if (cmd->opcode != O_NOP) 1654 continue; 1655 bprintf(bp, " // %s\n", (char *)(cmd + 1)); 1656 return; 1657 } 1658 1659 show_prerequisites(bp, &flags, 0, cmd->opcode); 1660 1661 switch(cmd->opcode) { 1662 case O_PROB: 1663 break; /* done already */ 1664 1665 case O_PROBE_STATE: 1666 break; /* no need to print anything here */ 1667 1668 case O_IP_SRC: 1669 case O_IP_SRC_LOOKUP: 1670 case O_IP_SRC_MASK: 1671 case O_IP_SRC_ME: 1672 case O_IP_SRC_SET: 1673 show_prerequisites(bp, &flags, HAVE_PROTO, 0); 1674 if (!(flags & HAVE_SRCIP)) 1675 bprintf(bp, " from"); 1676 if ((cmd->len & F_OR) && !or_block) 1677 bprintf(bp, " {"); 1678 print_ip(bp, fo, (ipfw_insn_ip *)cmd, 1679 (flags & HAVE_OPTIONS) ? " src-ip" : ""); 1680 flags |= HAVE_SRCIP; 1681 break; 1682 1683 case O_IP_DST: 1684 case O_IP_DST_LOOKUP: 1685 case O_IP_DST_MASK: 1686 case O_IP_DST_ME: 1687 case O_IP_DST_SET: 1688 show_prerequisites(bp, &flags, HAVE_PROTO|HAVE_SRCIP, 0); 1689 if (!(flags & HAVE_DSTIP)) 1690 bprintf(bp, " to"); 1691 if ((cmd->len & F_OR) && !or_block) 1692 bprintf(bp, " {"); 1693 print_ip(bp, fo, (ipfw_insn_ip *)cmd, 1694 (flags & HAVE_OPTIONS) ? " dst-ip" : ""); 1695 flags |= HAVE_DSTIP; 1696 break; 1697 1698 case O_IP6_SRC: 1699 case O_IP6_SRC_MASK: 1700 case O_IP6_SRC_ME: 1701 show_prerequisites(bp, &flags, HAVE_PROTO, 0); 1702 if (!(flags & HAVE_SRCIP)) 1703 bprintf(bp, " from"); 1704 if ((cmd->len & F_OR) && !or_block) 1705 bprintf(bp, " {"); 1706 print_ip6(bp, (ipfw_insn_ip6 *)cmd, 1707 (flags & HAVE_OPTIONS) ? " src-ip6" : ""); 1708 flags |= HAVE_SRCIP | HAVE_PROTO; 1709 break; 1710 1711 case O_IP6_DST: 1712 case O_IP6_DST_MASK: 1713 case O_IP6_DST_ME: 1714 show_prerequisites(bp, &flags, HAVE_PROTO|HAVE_SRCIP, 0); 1715 if (!(flags & HAVE_DSTIP)) 1716 bprintf(bp, " to"); 1717 if ((cmd->len & F_OR) && !or_block) 1718 bprintf(bp, " {"); 1719 print_ip6(bp, (ipfw_insn_ip6 *)cmd, 1720 (flags & HAVE_OPTIONS) ? " dst-ip6" : ""); 1721 flags |= HAVE_DSTIP; 1722 break; 1723 1724 case O_FLOW6ID: 1725 print_flow6id(bp, (ipfw_insn_u32 *) cmd ); 1726 flags |= HAVE_OPTIONS; 1727 break; 1728 1729 case O_IP_DSTPORT: 1730 show_prerequisites(bp, &flags, 1731 HAVE_PROTO | HAVE_SRCIP | 1732 HAVE_DSTIP | HAVE_IP, 0); 1733 case O_IP_SRCPORT: 1734 if (flags & HAVE_DSTIP) 1735 flags |= HAVE_IP; 1736 show_prerequisites(bp, &flags, 1737 HAVE_PROTO | HAVE_SRCIP, 0); 1738 if ((cmd->len & F_OR) && !or_block) 1739 bprintf(bp, " {"); 1740 if (cmd->len & F_NOT) 1741 bprintf(bp, " not"); 1742 print_newports(bp, (ipfw_insn_u16 *)cmd, proto, 1743 (flags & HAVE_OPTIONS) ? cmd->opcode : 0); 1744 break; 1745 1746 case O_PROTO: { 1747 struct protoent *pe = NULL; 1748 1749 if ((cmd->len & F_OR) && !or_block) 1750 bprintf(bp, " {"); 1751 if (cmd->len & F_NOT) 1752 bprintf(bp, " not"); 1753 proto = cmd->arg1; 1754 pe = getprotobynumber(cmd->arg1); 1755 if ((flags & (HAVE_PROTO4 | HAVE_PROTO6)) && 1756 !(flags & HAVE_PROTO)) 1757 show_prerequisites(bp, &flags, 1758 HAVE_PROTO | HAVE_IP | HAVE_SRCIP | 1759 HAVE_DSTIP | HAVE_OPTIONS, 0); 1760 if (flags & HAVE_OPTIONS) 1761 bprintf(bp, " proto"); 1762 if (pe) 1763 bprintf(bp, " %s", pe->p_name); 1764 else 1765 bprintf(bp, " %u", cmd->arg1); 1766 } 1767 flags |= HAVE_PROTO; 1768 break; 1769 1770 default: /*options ... */ 1771 if (!(cmd->len & (F_OR|F_NOT))) 1772 if (((cmd->opcode == O_IP6) && 1773 (flags & HAVE_PROTO6)) || 1774 ((cmd->opcode == O_IP4) && 1775 (flags & HAVE_PROTO4))) 1776 break; 1777 show_prerequisites(bp, &flags, HAVE_PROTO | HAVE_SRCIP | 1778 HAVE_DSTIP | HAVE_IP | HAVE_OPTIONS, 0); 1779 if ((cmd->len & F_OR) && !or_block) 1780 bprintf(bp, " {"); 1781 if (cmd->len & F_NOT && cmd->opcode != O_IN) 1782 bprintf(bp, " not"); 1783 switch(cmd->opcode) { 1784 case O_MACADDR2: { 1785 ipfw_insn_mac *m = (ipfw_insn_mac *)cmd; 1786 1787 bprintf(bp, " MAC"); 1788 print_mac(bp, m->addr, m->mask); 1789 print_mac(bp, m->addr + 6, m->mask + 6); 1790 } 1791 break; 1792 1793 case O_MAC_TYPE: 1794 print_newports(bp, (ipfw_insn_u16 *)cmd, 1795 IPPROTO_ETHERTYPE, cmd->opcode); 1796 break; 1797 1798 1799 case O_FRAG: 1800 bprintf(bp, " frag"); 1801 break; 1802 1803 case O_FIB: 1804 bprintf(bp, " fib %u", cmd->arg1 ); 1805 break; 1806 case O_SOCKARG: 1807 bprintf(bp, " sockarg"); 1808 break; 1809 1810 case O_IN: 1811 bprintf(bp, cmd->len & F_NOT ? " out" : " in"); 1812 break; 1813 1814 case O_DIVERTED: 1815 switch (cmd->arg1) { 1816 case 3: 1817 bprintf(bp, " diverted"); 1818 break; 1819 case 1: 1820 bprintf(bp, " diverted-loopback"); 1821 break; 1822 case 2: 1823 bprintf(bp, " diverted-output"); 1824 break; 1825 default: 1826 bprintf(bp, " diverted-?<%u>", cmd->arg1); 1827 break; 1828 } 1829 break; 1830 1831 case O_LAYER2: 1832 bprintf(bp, " layer2"); 1833 break; 1834 case O_XMIT: 1835 case O_RECV: 1836 case O_VIA: 1837 { 1838 char const *s, *t; 1839 ipfw_insn_if *cmdif = (ipfw_insn_if *)cmd; 1840 1841 if (cmd->opcode == O_XMIT) 1842 s = "xmit"; 1843 else if (cmd->opcode == O_RECV) 1844 s = "recv"; 1845 else /* if (cmd->opcode == O_VIA) */ 1846 s = "via"; 1847 if (cmdif->name[0] == '\0') 1848 bprintf(bp, " %s %s", s, 1849 inet_ntoa(cmdif->p.ip)); 1850 else if (cmdif->name[0] == '\1') { 1851 /* interface table */ 1852 t = table_search_ctlv(fo->tstate, 1853 cmdif->p.kidx); 1854 bprintf(bp, " %s table(%s)", s, t); 1855 } else 1856 bprintf(bp, " %s %s", s, cmdif->name); 1857 1858 break; 1859 } 1860 case O_IP_FLOW_LOOKUP: 1861 { 1862 char *t; 1863 1864 t = table_search_ctlv(fo->tstate, cmd->arg1); 1865 bprintf(bp, " flow table(%s", t); 1866 if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn_u32)) 1867 bprintf(bp, ",%u", 1868 ((ipfw_insn_u32 *)cmd)->d[0]); 1869 bprintf(bp, ")"); 1870 break; 1871 } 1872 case O_IPID: 1873 if (F_LEN(cmd) == 1) 1874 bprintf(bp, " ipid %u", cmd->arg1 ); 1875 else 1876 print_newports(bp, (ipfw_insn_u16 *)cmd, 0, 1877 O_IPID); 1878 break; 1879 1880 case O_IPTTL: 1881 if (F_LEN(cmd) == 1) 1882 bprintf(bp, " ipttl %u", cmd->arg1 ); 1883 else 1884 print_newports(bp, (ipfw_insn_u16 *)cmd, 0, 1885 O_IPTTL); 1886 break; 1887 1888 case O_IPVER: 1889 bprintf(bp, " ipver %u", cmd->arg1 ); 1890 break; 1891 1892 case O_IPPRECEDENCE: 1893 bprintf(bp, " ipprecedence %u", cmd->arg1 >> 5); 1894 break; 1895 1896 case O_DSCP: 1897 print_dscp(bp, (ipfw_insn_u32 *)cmd); 1898 break; 1899 1900 case O_IPLEN: 1901 if (F_LEN(cmd) == 1) 1902 bprintf(bp, " iplen %u", cmd->arg1 ); 1903 else 1904 print_newports(bp, (ipfw_insn_u16 *)cmd, 0, 1905 O_IPLEN); 1906 break; 1907 1908 case O_IPOPT: 1909 print_flags(bp, "ipoptions", cmd, f_ipopts); 1910 break; 1911 1912 case O_IPTOS: 1913 print_flags(bp, "iptos", cmd, f_iptos); 1914 break; 1915 1916 case O_ICMPTYPE: 1917 print_icmptypes(bp, (ipfw_insn_u32 *)cmd); 1918 break; 1919 1920 case O_ESTAB: 1921 bprintf(bp, " established"); 1922 break; 1923 1924 case O_TCPDATALEN: 1925 if (F_LEN(cmd) == 1) 1926 bprintf(bp, " tcpdatalen %u", cmd->arg1 ); 1927 else 1928 print_newports(bp, (ipfw_insn_u16 *)cmd, 0, 1929 O_TCPDATALEN); 1930 break; 1931 1932 case O_TCPFLAGS: 1933 print_flags(bp, "tcpflags", cmd, f_tcpflags); 1934 break; 1935 1936 case O_TCPOPTS: 1937 print_flags(bp, "tcpoptions", cmd, f_tcpopts); 1938 break; 1939 1940 case O_TCPWIN: 1941 if (F_LEN(cmd) == 1) 1942 bprintf(bp, " tcpwin %u", cmd->arg1); 1943 else 1944 print_newports(bp, (ipfw_insn_u16 *)cmd, 0, 1945 O_TCPWIN); 1946 break; 1947 1948 case O_TCPACK: 1949 bprintf(bp, " tcpack %d", ntohl(cmd32->d[0])); 1950 break; 1951 1952 case O_TCPSEQ: 1953 bprintf(bp, " tcpseq %d", ntohl(cmd32->d[0])); 1954 break; 1955 1956 case O_UID: 1957 { 1958 struct passwd *pwd = getpwuid(cmd32->d[0]); 1959 1960 if (pwd) 1961 bprintf(bp, " uid %s", pwd->pw_name); 1962 else 1963 bprintf(bp, " uid %u", cmd32->d[0]); 1964 } 1965 break; 1966 1967 case O_GID: 1968 { 1969 struct group *grp = getgrgid(cmd32->d[0]); 1970 1971 if (grp) 1972 bprintf(bp, " gid %s", grp->gr_name); 1973 else 1974 bprintf(bp, " gid %u", cmd32->d[0]); 1975 } 1976 break; 1977 1978 case O_JAIL: 1979 bprintf(bp, " jail %d", cmd32->d[0]); 1980 break; 1981 1982 case O_VERREVPATH: 1983 bprintf(bp, " verrevpath"); 1984 break; 1985 1986 case O_VERSRCREACH: 1987 bprintf(bp, " versrcreach"); 1988 break; 1989 1990 case O_ANTISPOOF: 1991 bprintf(bp, " antispoof"); 1992 break; 1993 1994 case O_IPSEC: 1995 bprintf(bp, " ipsec"); 1996 break; 1997 1998 case O_NOP: 1999 comment = (char *)(cmd + 1); 2000 break; 2001 2002 case O_KEEP_STATE: 2003 bprintf(bp, " keep-state"); 2004 break; 2005 2006 case O_LIMIT: { 2007 struct _s_x *p = limit_masks; 2008 ipfw_insn_limit *c = (ipfw_insn_limit *)cmd; 2009 uint8_t x = c->limit_mask; 2010 char const *comma = " "; 2011 2012 bprintf(bp, " limit"); 2013 for (; p->x != 0 ; p++) 2014 if ((x & p->x) == p->x) { 2015 x &= ~p->x; 2016 bprintf(bp, "%s%s", comma,p->s); 2017 comma = ","; 2018 } 2019 bprint_uint_arg(bp, " ", c->conn_limit); 2020 break; 2021 } 2022 2023 case O_IP6: 2024 bprintf(bp, " ip6"); 2025 break; 2026 2027 case O_IP4: 2028 bprintf(bp, " ip4"); 2029 break; 2030 2031 case O_ICMP6TYPE: 2032 print_icmp6types(bp, (ipfw_insn_u32 *)cmd); 2033 break; 2034 2035 case O_EXT_HDR: 2036 print_ext6hdr(bp, (ipfw_insn *)cmd); 2037 break; 2038 2039 case O_TAGGED: 2040 if (F_LEN(cmd) == 1) 2041 bprint_uint_arg(bp, " tagged ", 2042 cmd->arg1); 2043 else 2044 print_newports(bp, (ipfw_insn_u16 *)cmd, 2045 0, O_TAGGED); 2046 break; 2047 2048 default: 2049 bprintf(bp, " [opcode %d len %d]", 2050 cmd->opcode, cmd->len); 2051 } 2052 } 2053 if (cmd->len & F_OR) { 2054 bprintf(bp, " or"); 2055 or_block = 1; 2056 } else if (or_block) { 2057 bprintf(bp, " }"); 2058 or_block = 0; 2059 } 2060 } 2061 show_prerequisites(bp, &flags, HAVE_PROTO | HAVE_SRCIP | HAVE_DSTIP 2062 | HAVE_IP, 0); 2063 if (comment) 2064 bprintf(bp, " // %s", comment); 2065 bprintf(bp, "\n"); 2066 } 2067 2068 static void 2069 show_dyn_state(struct cmdline_opts *co, struct format_opts *fo, 2070 struct buf_pr *bp, ipfw_dyn_rule *d) 2071 { 2072 struct protoent *pe; 2073 struct in_addr a; 2074 uint16_t rulenum; 2075 char buf[INET6_ADDRSTRLEN]; 2076 2077 if (!co->do_expired) { 2078 if (!d->expire && !(d->dyn_type == O_LIMIT_PARENT)) 2079 return; 2080 } 2081 bcopy(&d->rule, &rulenum, sizeof(rulenum)); 2082 bprintf(bp, "%05d", rulenum); 2083 if (fo->pcwidth > 0 || fo->bcwidth > 0) { 2084 bprintf(bp, " "); 2085 pr_u64(bp, &d->pcnt, fo->pcwidth); 2086 pr_u64(bp, &d->bcnt, fo->bcwidth); 2087 bprintf(bp, "(%ds)", d->expire); 2088 } 2089 switch (d->dyn_type) { 2090 case O_LIMIT_PARENT: 2091 bprintf(bp, " PARENT %d", d->count); 2092 break; 2093 case O_LIMIT: 2094 bprintf(bp, " LIMIT"); 2095 break; 2096 case O_KEEP_STATE: /* bidir, no mask */ 2097 bprintf(bp, " STATE"); 2098 break; 2099 } 2100 2101 if ((pe = getprotobynumber(d->id.proto)) != NULL) 2102 bprintf(bp, " %s", pe->p_name); 2103 else 2104 bprintf(bp, " proto %u", d->id.proto); 2105 2106 if (d->id.addr_type == 4) { 2107 a.s_addr = htonl(d->id.src_ip); 2108 bprintf(bp, " %s %d", inet_ntoa(a), d->id.src_port); 2109 2110 a.s_addr = htonl(d->id.dst_ip); 2111 bprintf(bp, " <-> %s %d", inet_ntoa(a), d->id.dst_port); 2112 } else if (d->id.addr_type == 6) { 2113 bprintf(bp, " %s %d", inet_ntop(AF_INET6, &d->id.src_ip6, buf, 2114 sizeof(buf)), d->id.src_port); 2115 bprintf(bp, " <-> %s %d", inet_ntop(AF_INET6, &d->id.dst_ip6, 2116 buf, sizeof(buf)), d->id.dst_port); 2117 } else 2118 bprintf(bp, " UNKNOWN <-> UNKNOWN\n"); 2119 } 2120 2121 static int 2122 do_range_cmd(int cmd, ipfw_range_tlv *rt) 2123 { 2124 ipfw_range_header rh; 2125 size_t sz; 2126 2127 memset(&rh, 0, sizeof(rh)); 2128 memcpy(&rh.range, rt, sizeof(*rt)); 2129 rh.range.head.length = sizeof(*rt); 2130 rh.range.head.type = IPFW_TLV_RANGE; 2131 sz = sizeof(rh); 2132 2133 if (do_get3(cmd, &rh.opheader, &sz) != 0) 2134 return (-1); 2135 /* Save number of matched objects */ 2136 rt->new_set = rh.range.new_set; 2137 return (0); 2138 } 2139 2140 /* 2141 * This one handles all set-related commands 2142 * ipfw set { show | enable | disable } 2143 * ipfw set swap X Y 2144 * ipfw set move X to Y 2145 * ipfw set move rule X to Y 2146 */ 2147 void 2148 ipfw_sets_handler(char *av[]) 2149 { 2150 uint32_t masks[2]; 2151 int i; 2152 uint8_t cmd, rulenum; 2153 ipfw_range_tlv rt; 2154 char *msg; 2155 size_t size; 2156 2157 av++; 2158 memset(&rt, 0, sizeof(rt)); 2159 2160 if (av[0] == NULL) 2161 errx(EX_USAGE, "set needs command"); 2162 if (_substrcmp(*av, "show") == 0) { 2163 struct format_opts fo; 2164 ipfw_cfg_lheader *cfg; 2165 2166 memset(&fo, 0, sizeof(fo)); 2167 if (ipfw_get_config(&co, &fo, &cfg, &size) != 0) 2168 err(EX_OSERR, "requesting config failed"); 2169 2170 for (i = 0, msg = "disable"; i < RESVD_SET; i++) 2171 if ((cfg->set_mask & (1<<i)) == 0) { 2172 printf("%s %d", msg, i); 2173 msg = ""; 2174 } 2175 msg = (cfg->set_mask != (uint32_t)-1) ? " enable" : "enable"; 2176 for (i = 0; i < RESVD_SET; i++) 2177 if ((cfg->set_mask & (1<<i)) != 0) { 2178 printf("%s %d", msg, i); 2179 msg = ""; 2180 } 2181 printf("\n"); 2182 free(cfg); 2183 } else if (_substrcmp(*av, "swap") == 0) { 2184 av++; 2185 if ( av[0] == NULL || av[1] == NULL ) 2186 errx(EX_USAGE, "set swap needs 2 set numbers\n"); 2187 rt.set = atoi(av[0]); 2188 rt.new_set = atoi(av[1]); 2189 if (!isdigit(*(av[0])) || rt.set > RESVD_SET) 2190 errx(EX_DATAERR, "invalid set number %s\n", av[0]); 2191 if (!isdigit(*(av[1])) || rt.new_set > RESVD_SET) 2192 errx(EX_DATAERR, "invalid set number %s\n", av[1]); 2193 i = do_range_cmd(IP_FW_SET_SWAP, &rt); 2194 } else if (_substrcmp(*av, "move") == 0) { 2195 av++; 2196 if (av[0] && _substrcmp(*av, "rule") == 0) { 2197 rt.flags = IPFW_RCFLAG_RANGE; /* move rules to new set */ 2198 cmd = IP_FW_XMOVE; 2199 av++; 2200 } else 2201 cmd = IP_FW_SET_MOVE; /* Move set to new one */ 2202 if (av[0] == NULL || av[1] == NULL || av[2] == NULL || 2203 av[3] != NULL || _substrcmp(av[1], "to") != 0) 2204 errx(EX_USAGE, "syntax: set move [rule] X to Y\n"); 2205 rulenum = atoi(av[0]); 2206 rt.new_set = atoi(av[2]); 2207 if (cmd == IP_FW_XMOVE) { 2208 rt.start_rule = rulenum; 2209 rt.end_rule = rulenum; 2210 } else 2211 rt.set = rulenum; 2212 rt.new_set = atoi(av[2]); 2213 if (!isdigit(*(av[0])) || (cmd == 3 && rt.set > RESVD_SET) || 2214 (cmd == 2 && rt.start_rule == IPFW_DEFAULT_RULE) ) 2215 errx(EX_DATAERR, "invalid source number %s\n", av[0]); 2216 if (!isdigit(*(av[2])) || rt.new_set > RESVD_SET) 2217 errx(EX_DATAERR, "invalid dest. set %s\n", av[1]); 2218 i = do_range_cmd(cmd, &rt); 2219 } else if (_substrcmp(*av, "disable") == 0 || 2220 _substrcmp(*av, "enable") == 0 ) { 2221 int which = _substrcmp(*av, "enable") == 0 ? 1 : 0; 2222 2223 av++; 2224 masks[0] = masks[1] = 0; 2225 2226 while (av[0]) { 2227 if (isdigit(**av)) { 2228 i = atoi(*av); 2229 if (i < 0 || i > RESVD_SET) 2230 errx(EX_DATAERR, 2231 "invalid set number %d\n", i); 2232 masks[which] |= (1<<i); 2233 } else if (_substrcmp(*av, "disable") == 0) 2234 which = 0; 2235 else if (_substrcmp(*av, "enable") == 0) 2236 which = 1; 2237 else 2238 errx(EX_DATAERR, 2239 "invalid set command %s\n", *av); 2240 av++; 2241 } 2242 if ( (masks[0] & masks[1]) != 0 ) 2243 errx(EX_DATAERR, 2244 "cannot enable and disable the same set\n"); 2245 2246 rt.set = masks[0]; 2247 rt.new_set = masks[1]; 2248 i = do_range_cmd(IP_FW_SET_ENABLE, &rt); 2249 if (i) 2250 warn("set enable/disable: setsockopt(IP_FW_SET_ENABLE)"); 2251 } else 2252 errx(EX_USAGE, "invalid set command %s\n", *av); 2253 } 2254 2255 void 2256 ipfw_sysctl_handler(char *av[], int which) 2257 { 2258 av++; 2259 2260 if (av[0] == NULL) { 2261 warnx("missing keyword to enable/disable\n"); 2262 } else if (_substrcmp(*av, "firewall") == 0) { 2263 sysctlbyname("net.inet.ip.fw.enable", NULL, 0, 2264 &which, sizeof(which)); 2265 sysctlbyname("net.inet6.ip6.fw.enable", NULL, 0, 2266 &which, sizeof(which)); 2267 } else if (_substrcmp(*av, "one_pass") == 0) { 2268 sysctlbyname("net.inet.ip.fw.one_pass", NULL, 0, 2269 &which, sizeof(which)); 2270 } else if (_substrcmp(*av, "debug") == 0) { 2271 sysctlbyname("net.inet.ip.fw.debug", NULL, 0, 2272 &which, sizeof(which)); 2273 } else if (_substrcmp(*av, "verbose") == 0) { 2274 sysctlbyname("net.inet.ip.fw.verbose", NULL, 0, 2275 &which, sizeof(which)); 2276 } else if (_substrcmp(*av, "dyn_keepalive") == 0) { 2277 sysctlbyname("net.inet.ip.fw.dyn_keepalive", NULL, 0, 2278 &which, sizeof(which)); 2279 #ifndef NO_ALTQ 2280 } else if (_substrcmp(*av, "altq") == 0) { 2281 altq_set_enabled(which); 2282 #endif 2283 } else { 2284 warnx("unrecognize enable/disable keyword: %s\n", *av); 2285 } 2286 } 2287 2288 typedef void state_cb(struct cmdline_opts *co, struct format_opts *fo, 2289 void *arg, void *state); 2290 2291 static void 2292 prepare_format_dyn(struct cmdline_opts *co, struct format_opts *fo, 2293 void *arg, void *_state) 2294 { 2295 ipfw_dyn_rule *d; 2296 int width; 2297 uint8_t set; 2298 2299 d = (ipfw_dyn_rule *)_state; 2300 /* Count _ALL_ states */ 2301 fo->dcnt++; 2302 2303 if (fo->show_counters == 0) 2304 return; 2305 2306 if (co->use_set) { 2307 /* skip states from another set */ 2308 bcopy((char *)&d->rule + sizeof(uint16_t), &set, 2309 sizeof(uint8_t)); 2310 if (set != co->use_set - 1) 2311 return; 2312 } 2313 2314 width = pr_u64(NULL, &d->pcnt, 0); 2315 if (width > fo->pcwidth) 2316 fo->pcwidth = width; 2317 2318 width = pr_u64(NULL, &d->bcnt, 0); 2319 if (width > fo->bcwidth) 2320 fo->bcwidth = width; 2321 } 2322 2323 static int 2324 foreach_state(struct cmdline_opts *co, struct format_opts *fo, 2325 caddr_t base, size_t sz, state_cb dyn_bc, void *dyn_arg) 2326 { 2327 int ttype; 2328 state_cb *fptr; 2329 void *farg; 2330 ipfw_obj_tlv *tlv; 2331 ipfw_obj_ctlv *ctlv; 2332 2333 fptr = NULL; 2334 ttype = 0; 2335 2336 while (sz > 0) { 2337 ctlv = (ipfw_obj_ctlv *)base; 2338 switch (ctlv->head.type) { 2339 case IPFW_TLV_DYNSTATE_LIST: 2340 base += sizeof(*ctlv); 2341 sz -= sizeof(*ctlv); 2342 ttype = IPFW_TLV_DYN_ENT; 2343 fptr = dyn_bc; 2344 farg = dyn_arg; 2345 break; 2346 default: 2347 return (sz); 2348 } 2349 2350 while (sz > 0) { 2351 tlv = (ipfw_obj_tlv *)base; 2352 if (tlv->type != ttype) 2353 break; 2354 2355 fptr(co, fo, farg, tlv + 1); 2356 sz -= tlv->length; 2357 base += tlv->length; 2358 } 2359 } 2360 2361 return (sz); 2362 } 2363 2364 static void 2365 prepare_format_opts(struct cmdline_opts *co, struct format_opts *fo, 2366 ipfw_obj_tlv *rtlv, int rcnt, caddr_t dynbase, size_t dynsz) 2367 { 2368 int bcwidth, pcwidth, width; 2369 int n; 2370 struct ip_fw_bcounter *cntr; 2371 struct ip_fw_rule *r; 2372 2373 bcwidth = 0; 2374 pcwidth = 0; 2375 if (fo->show_counters != 0) { 2376 for (n = 0; n < rcnt; n++, 2377 rtlv = (ipfw_obj_tlv *)((caddr_t)rtlv + rtlv->length)) { 2378 cntr = (struct ip_fw_bcounter *)(rtlv + 1); 2379 r = (struct ip_fw_rule *)((caddr_t)cntr + cntr->size); 2380 /* skip rules from another set */ 2381 if (co->use_set && r->set != co->use_set - 1) 2382 continue; 2383 2384 /* packet counter */ 2385 width = pr_u64(NULL, &cntr->pcnt, 0); 2386 if (width > pcwidth) 2387 pcwidth = width; 2388 2389 /* byte counter */ 2390 width = pr_u64(NULL, &cntr->bcnt, 0); 2391 if (width > bcwidth) 2392 bcwidth = width; 2393 } 2394 } 2395 fo->bcwidth = bcwidth; 2396 fo->pcwidth = pcwidth; 2397 2398 fo->dcnt = 0; 2399 if (co->do_dynamic && dynsz > 0) 2400 foreach_state(co, fo, dynbase, dynsz, prepare_format_dyn, NULL); 2401 } 2402 2403 static int 2404 list_static_range(struct cmdline_opts *co, struct format_opts *fo, 2405 struct buf_pr *bp, ipfw_obj_tlv *rtlv, int rcnt) 2406 { 2407 int n, seen; 2408 struct ip_fw_rule *r; 2409 struct ip_fw_bcounter *cntr; 2410 int c = 0; 2411 2412 for (n = seen = 0; n < rcnt; n++, 2413 rtlv = (ipfw_obj_tlv *)((caddr_t)rtlv + rtlv->length)) { 2414 2415 if ((fo->show_counters | fo->show_time) != 0) { 2416 cntr = (struct ip_fw_bcounter *)(rtlv + 1); 2417 r = (struct ip_fw_rule *)((caddr_t)cntr + cntr->size); 2418 } else { 2419 cntr = NULL; 2420 r = (struct ip_fw_rule *)(rtlv + 1); 2421 } 2422 if (r->rulenum > fo->last) 2423 break; 2424 if (co->use_set && r->set != co->use_set - 1) 2425 continue; 2426 if (r->rulenum >= fo->first && r->rulenum <= fo->last) { 2427 show_static_rule(co, fo, bp, r, cntr); 2428 printf("%s", bp->buf); 2429 c += rtlv->length; 2430 bp_flush(bp); 2431 seen++; 2432 } 2433 } 2434 2435 return (seen); 2436 } 2437 2438 static void 2439 list_dyn_state(struct cmdline_opts *co, struct format_opts *fo, 2440 void *_arg, void *_state) 2441 { 2442 uint16_t rulenum; 2443 uint8_t set; 2444 ipfw_dyn_rule *d; 2445 struct buf_pr *bp; 2446 2447 d = (ipfw_dyn_rule *)_state; 2448 bp = (struct buf_pr *)_arg; 2449 2450 bcopy(&d->rule, &rulenum, sizeof(rulenum)); 2451 if (rulenum > fo->last) 2452 return; 2453 if (co->use_set) { 2454 bcopy((char *)&d->rule + sizeof(uint16_t), 2455 &set, sizeof(uint8_t)); 2456 if (set != co->use_set - 1) 2457 return; 2458 } 2459 if (rulenum >= fo->first) { 2460 show_dyn_state(co, fo, bp, d); 2461 printf("%s\n", bp->buf); 2462 bp_flush(bp); 2463 } 2464 } 2465 2466 static int 2467 list_dyn_range(struct cmdline_opts *co, struct format_opts *fo, 2468 struct buf_pr *bp, caddr_t base, size_t sz) 2469 { 2470 2471 sz = foreach_state(co, fo, base, sz, list_dyn_state, bp); 2472 return (sz); 2473 } 2474 2475 void 2476 ipfw_list(int ac, char *av[], int show_counters) 2477 { 2478 ipfw_cfg_lheader *cfg; 2479 struct format_opts sfo; 2480 size_t sz; 2481 int error; 2482 int lac; 2483 char **lav; 2484 uint32_t rnum; 2485 char *endptr; 2486 2487 if (co.test_only) { 2488 fprintf(stderr, "Testing only, list disabled\n"); 2489 return; 2490 } 2491 if (co.do_pipe) { 2492 dummynet_list(ac, av, show_counters); 2493 return; 2494 } 2495 2496 ac--; 2497 av++; 2498 memset(&sfo, 0, sizeof(sfo)); 2499 2500 /* Determine rule range to request */ 2501 if (ac > 0) { 2502 for (lac = ac, lav = av; lac != 0; lac--) { 2503 rnum = strtoul(*lav++, &endptr, 10); 2504 if (sfo.first == 0 || rnum < sfo.first) 2505 sfo.first = rnum; 2506 2507 if (*endptr == '-') 2508 rnum = strtoul(endptr + 1, &endptr, 10); 2509 if (sfo.last == 0 || rnum > sfo.last) 2510 sfo.last = rnum; 2511 } 2512 } 2513 2514 /* get configuraion from kernel */ 2515 cfg = NULL; 2516 sfo.show_counters = show_counters; 2517 sfo.show_time = co.do_time; 2518 sfo.flags = IPFW_CFG_GET_STATIC; 2519 if (co.do_dynamic != 0) 2520 sfo.flags |= IPFW_CFG_GET_STATES; 2521 if ((sfo.show_counters | sfo.show_time) != 0) 2522 sfo.flags |= IPFW_CFG_GET_COUNTERS; 2523 if (ipfw_get_config(&co, &sfo, &cfg, &sz) != 0) 2524 err(EX_OSERR, "retrieving config failed"); 2525 2526 error = ipfw_show_config(&co, &sfo, cfg, sz, ac, av); 2527 2528 free(cfg); 2529 2530 if (error != EX_OK) 2531 exit(error); 2532 } 2533 2534 static int 2535 ipfw_show_config(struct cmdline_opts *co, struct format_opts *fo, 2536 ipfw_cfg_lheader *cfg, size_t sz, int ac, char *av[]) 2537 { 2538 caddr_t dynbase; 2539 size_t dynsz; 2540 int rcnt; 2541 int exitval = EX_OK; 2542 int lac; 2543 char **lav; 2544 char *endptr; 2545 size_t readsz; 2546 struct buf_pr bp; 2547 ipfw_obj_ctlv *ctlv, *tstate; 2548 ipfw_obj_tlv *rbase; 2549 2550 /* 2551 * Handle tablenames TLV first, if any 2552 */ 2553 tstate = NULL; 2554 rbase = NULL; 2555 dynbase = NULL; 2556 dynsz = 0; 2557 readsz = sizeof(*cfg); 2558 rcnt = 0; 2559 2560 fo->set_mask = cfg->set_mask; 2561 2562 ctlv = (ipfw_obj_ctlv *)(cfg + 1); 2563 2564 if (cfg->flags & IPFW_CFG_GET_STATIC) { 2565 /* We've requested static rules */ 2566 if (ctlv->head.type == IPFW_TLV_TBLNAME_LIST) { 2567 object_sort_ctlv(ctlv); 2568 fo->tstate = ctlv; 2569 readsz += ctlv->head.length; 2570 ctlv = (ipfw_obj_ctlv *)((caddr_t)ctlv + 2571 ctlv->head.length); 2572 } 2573 2574 if (ctlv->head.type == IPFW_TLV_RULE_LIST) { 2575 rbase = (ipfw_obj_tlv *)(ctlv + 1); 2576 rcnt = ctlv->count; 2577 readsz += ctlv->head.length; 2578 ctlv = (ipfw_obj_ctlv *)((caddr_t)ctlv + 2579 ctlv->head.length); 2580 } 2581 } 2582 2583 if ((cfg->flags & IPFW_CFG_GET_STATES) && (readsz != sz)) { 2584 /* We may have some dynamic states */ 2585 dynsz = sz - readsz; 2586 /* Skip empty header */ 2587 if (dynsz != sizeof(ipfw_obj_ctlv)) 2588 dynbase = (caddr_t)ctlv; 2589 else 2590 dynsz = 0; 2591 } 2592 2593 prepare_format_opts(co, fo, rbase, rcnt, dynbase, dynsz); 2594 bp_alloc(&bp, 4096); 2595 2596 /* if no rule numbers were specified, list all rules */ 2597 if (ac == 0) { 2598 fo->first = 0; 2599 fo->last = IPFW_DEFAULT_RULE; 2600 list_static_range(co, fo, &bp, rbase, rcnt); 2601 2602 if (co->do_dynamic && dynsz > 0) { 2603 printf("## Dynamic rules (%d %zu):\n", fo->dcnt, dynsz); 2604 list_dyn_range(co, fo, &bp, dynbase, dynsz); 2605 } 2606 2607 bp_free(&bp); 2608 return (EX_OK); 2609 } 2610 2611 /* display specific rules requested on command line */ 2612 for (lac = ac, lav = av; lac != 0; lac--) { 2613 /* convert command line rule # */ 2614 fo->last = fo->first = strtoul(*lav++, &endptr, 10); 2615 if (*endptr == '-') 2616 fo->last = strtoul(endptr + 1, &endptr, 10); 2617 if (*endptr) { 2618 exitval = EX_USAGE; 2619 warnx("invalid rule number: %s", *(lav - 1)); 2620 continue; 2621 } 2622 2623 if (list_static_range(co, fo, &bp, rbase, rcnt) == 0) { 2624 /* give precedence to other error(s) */ 2625 if (exitval == EX_OK) 2626 exitval = EX_UNAVAILABLE; 2627 if (fo->first == fo->last) 2628 warnx("rule %u does not exist", fo->first); 2629 else 2630 warnx("no rules in range %u-%u", 2631 fo->first, fo->last); 2632 } 2633 } 2634 2635 if (co->do_dynamic && dynsz > 0) { 2636 printf("## Dynamic rules:\n"); 2637 for (lac = ac, lav = av; lac != 0; lac--) { 2638 fo->last = fo->first = strtoul(*lav++, &endptr, 10); 2639 if (*endptr == '-') 2640 fo->last = strtoul(endptr+1, &endptr, 10); 2641 if (*endptr) 2642 /* already warned */ 2643 continue; 2644 list_dyn_range(co, fo, &bp, dynbase, dynsz); 2645 } 2646 } 2647 2648 bp_free(&bp); 2649 return (exitval); 2650 } 2651 2652 2653 /* 2654 * Retrieves current ipfw configuration of given type 2655 * and stores its pointer to @pcfg. 2656 * 2657 * Caller is responsible for freeing @pcfg. 2658 * 2659 * Returns 0 on success. 2660 */ 2661 2662 static int 2663 ipfw_get_config(struct cmdline_opts *co, struct format_opts *fo, 2664 ipfw_cfg_lheader **pcfg, size_t *psize) 2665 { 2666 ipfw_cfg_lheader *cfg; 2667 size_t sz; 2668 int i; 2669 2670 2671 if (co->test_only != 0) { 2672 fprintf(stderr, "Testing only, list disabled\n"); 2673 return (0); 2674 } 2675 2676 /* Start with some data size */ 2677 sz = 4096; 2678 cfg = NULL; 2679 2680 for (i = 0; i < 16; i++) { 2681 if (cfg != NULL) 2682 free(cfg); 2683 if ((cfg = calloc(1, sz)) == NULL) 2684 return (ENOMEM); 2685 2686 cfg->flags = fo->flags; 2687 cfg->start_rule = fo->first; 2688 cfg->end_rule = fo->last; 2689 2690 if (do_get3(IP_FW_XGET, &cfg->opheader, &sz) != 0) { 2691 if (errno != ENOMEM) { 2692 free(cfg); 2693 return (errno); 2694 } 2695 2696 /* Buffer size is not enough. Try to increase */ 2697 sz = sz * 2; 2698 if (sz < cfg->size) 2699 sz = cfg->size; 2700 continue; 2701 } 2702 2703 *pcfg = cfg; 2704 *psize = sz; 2705 return (0); 2706 } 2707 2708 free(cfg); 2709 return (ENOMEM); 2710 } 2711 2712 static int 2713 lookup_host (char *host, struct in_addr *ipaddr) 2714 { 2715 struct hostent *he; 2716 2717 if (!inet_aton(host, ipaddr)) { 2718 if ((he = gethostbyname(host)) == NULL) 2719 return(-1); 2720 *ipaddr = *(struct in_addr *)he->h_addr_list[0]; 2721 } 2722 return(0); 2723 } 2724 2725 struct tidx { 2726 ipfw_obj_ntlv *idx; 2727 uint32_t count; 2728 uint32_t size; 2729 uint16_t counter; 2730 uint8_t set; 2731 }; 2732 2733 static uint16_t 2734 pack_object(struct tidx *tstate, char *name, int otype) 2735 { 2736 int i; 2737 ipfw_obj_ntlv *ntlv; 2738 2739 for (i = 0; i < tstate->count; i++) { 2740 if (strcmp(tstate->idx[i].name, name) != 0) 2741 continue; 2742 if (tstate->idx[i].set != tstate->set) 2743 continue; 2744 if (tstate->idx[i].head.type != otype) 2745 continue; 2746 2747 return (tstate->idx[i].idx); 2748 } 2749 2750 if (tstate->count + 1 > tstate->size) { 2751 tstate->size += 4; 2752 tstate->idx = realloc(tstate->idx, tstate->size * 2753 sizeof(ipfw_obj_ntlv)); 2754 if (tstate->idx == NULL) 2755 return (0); 2756 } 2757 2758 ntlv = &tstate->idx[i]; 2759 memset(ntlv, 0, sizeof(ipfw_obj_ntlv)); 2760 strlcpy(ntlv->name, name, sizeof(ntlv->name)); 2761 ntlv->head.type = otype; 2762 ntlv->head.length = sizeof(ipfw_obj_ntlv); 2763 ntlv->set = tstate->set; 2764 ntlv->idx = ++tstate->counter; 2765 tstate->count++; 2766 2767 return (ntlv->idx); 2768 } 2769 2770 static uint16_t 2771 pack_table(struct tidx *tstate, char *name) 2772 { 2773 2774 if (table_check_name(name) != 0) 2775 return (0); 2776 2777 return (pack_object(tstate, name, IPFW_TLV_TBL_NAME)); 2778 } 2779 2780 static void 2781 fill_table(ipfw_insn *cmd, char *av, uint8_t opcode, struct tidx *tstate) 2782 { 2783 uint32_t *d = ((ipfw_insn_u32 *)cmd)->d; 2784 uint16_t uidx; 2785 char *p; 2786 2787 if ((p = strchr(av + 6, ')')) == NULL) 2788 errx(EX_DATAERR, "forgotten parenthesis: '%s'", av); 2789 *p = '\0'; 2790 p = strchr(av + 6, ','); 2791 if (p) 2792 *p++ = '\0'; 2793 2794 if ((uidx = pack_table(tstate, av + 6)) == 0) 2795 errx(EX_DATAERR, "Invalid table name: %s", av + 6); 2796 2797 cmd->opcode = opcode; 2798 cmd->arg1 = uidx; 2799 if (p) { 2800 cmd->len |= F_INSN_SIZE(ipfw_insn_u32); 2801 d[0] = strtoul(p, NULL, 0); 2802 } else 2803 cmd->len |= F_INSN_SIZE(ipfw_insn); 2804 } 2805 2806 2807 /* 2808 * fills the addr and mask fields in the instruction as appropriate from av. 2809 * Update length as appropriate. 2810 * The following formats are allowed: 2811 * me returns O_IP_*_ME 2812 * 1.2.3.4 single IP address 2813 * 1.2.3.4:5.6.7.8 address:mask 2814 * 1.2.3.4/24 address/mask 2815 * 1.2.3.4/26{1,6,5,4,23} set of addresses in a subnet 2816 * We can have multiple comma-separated address/mask entries. 2817 */ 2818 static void 2819 fill_ip(ipfw_insn_ip *cmd, char *av, int cblen, struct tidx *tstate) 2820 { 2821 int len = 0; 2822 uint32_t *d = ((ipfw_insn_u32 *)cmd)->d; 2823 2824 cmd->o.len &= ~F_LEN_MASK; /* zero len */ 2825 2826 if (_substrcmp(av, "any") == 0) 2827 return; 2828 2829 if (_substrcmp(av, "me") == 0) { 2830 cmd->o.len |= F_INSN_SIZE(ipfw_insn); 2831 return; 2832 } 2833 2834 if (strncmp(av, "table(", 6) == 0) { 2835 fill_table(&cmd->o, av, O_IP_DST_LOOKUP, tstate); 2836 return; 2837 } 2838 2839 while (av) { 2840 /* 2841 * After the address we can have '/' or ':' indicating a mask, 2842 * ',' indicating another address follows, '{' indicating a 2843 * set of addresses of unspecified size. 2844 */ 2845 char *t = NULL, *p = strpbrk(av, "/:,{"); 2846 int masklen; 2847 char md, nd = '\0'; 2848 2849 CHECK_LENGTH(cblen, F_INSN_SIZE(ipfw_insn) + 2 + len); 2850 2851 if (p) { 2852 md = *p; 2853 *p++ = '\0'; 2854 if ((t = strpbrk(p, ",{")) != NULL) { 2855 nd = *t; 2856 *t = '\0'; 2857 } 2858 } else 2859 md = '\0'; 2860 2861 if (lookup_host(av, (struct in_addr *)&d[0]) != 0) 2862 errx(EX_NOHOST, "hostname ``%s'' unknown", av); 2863 switch (md) { 2864 case ':': 2865 if (!inet_aton(p, (struct in_addr *)&d[1])) 2866 errx(EX_DATAERR, "bad netmask ``%s''", p); 2867 break; 2868 case '/': 2869 masklen = atoi(p); 2870 if (masklen == 0) 2871 d[1] = htonl(0U); /* mask */ 2872 else if (masklen > 32) 2873 errx(EX_DATAERR, "bad width ``%s''", p); 2874 else 2875 d[1] = htonl(~0U << (32 - masklen)); 2876 break; 2877 case '{': /* no mask, assume /24 and put back the '{' */ 2878 d[1] = htonl(~0U << (32 - 24)); 2879 *(--p) = md; 2880 break; 2881 2882 case ',': /* single address plus continuation */ 2883 *(--p) = md; 2884 /* FALLTHROUGH */ 2885 case 0: /* initialization value */ 2886 default: 2887 d[1] = htonl(~0U); /* force /32 */ 2888 break; 2889 } 2890 d[0] &= d[1]; /* mask base address with mask */ 2891 if (t) 2892 *t = nd; 2893 /* find next separator */ 2894 if (p) 2895 p = strpbrk(p, ",{"); 2896 if (p && *p == '{') { 2897 /* 2898 * We have a set of addresses. They are stored as follows: 2899 * arg1 is the set size (powers of 2, 2..256) 2900 * addr is the base address IN HOST FORMAT 2901 * mask.. is an array of arg1 bits (rounded up to 2902 * the next multiple of 32) with bits set 2903 * for each host in the map. 2904 */ 2905 uint32_t *map = (uint32_t *)&cmd->mask; 2906 int low, high; 2907 int i = contigmask((uint8_t *)&(d[1]), 32); 2908 2909 if (len > 0) 2910 errx(EX_DATAERR, "address set cannot be in a list"); 2911 if (i < 24 || i > 31) 2912 errx(EX_DATAERR, "invalid set with mask %d\n", i); 2913 cmd->o.arg1 = 1<<(32-i); /* map length */ 2914 d[0] = ntohl(d[0]); /* base addr in host format */ 2915 cmd->o.opcode = O_IP_DST_SET; /* default */ 2916 cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32) + (cmd->o.arg1+31)/32; 2917 for (i = 0; i < (cmd->o.arg1+31)/32 ; i++) 2918 map[i] = 0; /* clear map */ 2919 2920 av = p + 1; 2921 low = d[0] & 0xff; 2922 high = low + cmd->o.arg1 - 1; 2923 /* 2924 * Here, i stores the previous value when we specify a range 2925 * of addresses within a mask, e.g. 45-63. i = -1 means we 2926 * have no previous value. 2927 */ 2928 i = -1; /* previous value in a range */ 2929 while (isdigit(*av)) { 2930 char *s; 2931 int a = strtol(av, &s, 0); 2932 2933 if (s == av) { /* no parameter */ 2934 if (*av != '}') 2935 errx(EX_DATAERR, "set not closed\n"); 2936 if (i != -1) 2937 errx(EX_DATAERR, "incomplete range %d-", i); 2938 break; 2939 } 2940 if (a < low || a > high) 2941 errx(EX_DATAERR, "addr %d out of range [%d-%d]\n", 2942 a, low, high); 2943 a -= low; 2944 if (i == -1) /* no previous in range */ 2945 i = a; 2946 else { /* check that range is valid */ 2947 if (i > a) 2948 errx(EX_DATAERR, "invalid range %d-%d", 2949 i+low, a+low); 2950 if (*s == '-') 2951 errx(EX_DATAERR, "double '-' in range"); 2952 } 2953 for (; i <= a; i++) 2954 map[i/32] |= 1<<(i & 31); 2955 i = -1; 2956 if (*s == '-') 2957 i = a; 2958 else if (*s == '}') 2959 break; 2960 av = s+1; 2961 } 2962 return; 2963 } 2964 av = p; 2965 if (av) /* then *av must be a ',' */ 2966 av++; 2967 2968 /* Check this entry */ 2969 if (d[1] == 0) { /* "any", specified as x.x.x.x/0 */ 2970 /* 2971 * 'any' turns the entire list into a NOP. 2972 * 'not any' never matches, so it is removed from the 2973 * list unless it is the only item, in which case we 2974 * report an error. 2975 */ 2976 if (cmd->o.len & F_NOT) { /* "not any" never matches */ 2977 if (av == NULL && len == 0) /* only this entry */ 2978 errx(EX_DATAERR, "not any never matches"); 2979 } 2980 /* else do nothing and skip this entry */ 2981 return; 2982 } 2983 /* A single IP can be stored in an optimized format */ 2984 if (d[1] == (uint32_t)~0 && av == NULL && len == 0) { 2985 cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32); 2986 return; 2987 } 2988 len += 2; /* two words... */ 2989 d += 2; 2990 } /* end while */ 2991 if (len + 1 > F_LEN_MASK) 2992 errx(EX_DATAERR, "address list too long"); 2993 cmd->o.len |= len+1; 2994 } 2995 2996 2997 /* n2mask sets n bits of the mask */ 2998 void 2999 n2mask(struct in6_addr *mask, int n) 3000 { 3001 static int minimask[9] = 3002 { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff }; 3003 u_char *p; 3004 3005 memset(mask, 0, sizeof(struct in6_addr)); 3006 p = (u_char *) mask; 3007 for (; n > 0; p++, n -= 8) { 3008 if (n >= 8) 3009 *p = 0xff; 3010 else 3011 *p = minimask[n]; 3012 } 3013 return; 3014 } 3015 3016 static void 3017 fill_flags_cmd(ipfw_insn *cmd, enum ipfw_opcodes opcode, 3018 struct _s_x *flags, char *p) 3019 { 3020 char *e; 3021 uint32_t set = 0, clear = 0; 3022 3023 if (fill_flags(flags, p, &e, &set, &clear) != 0) 3024 errx(EX_DATAERR, "invalid flag %s", e); 3025 3026 cmd->opcode = opcode; 3027 cmd->len = (cmd->len & (F_NOT | F_OR)) | 1; 3028 cmd->arg1 = (set & 0xff) | ( (clear & 0xff) << 8); 3029 } 3030 3031 3032 void 3033 ipfw_delete(char *av[]) 3034 { 3035 int i, j; 3036 int exitval = EX_OK; 3037 int do_set = 0; 3038 char *sep; 3039 ipfw_range_tlv rt; 3040 3041 av++; 3042 NEED1("missing rule specification"); 3043 memset(&rt, 0, sizeof(rt)); 3044 if ( *av && _substrcmp(*av, "set") == 0) { 3045 /* Do not allow using the following syntax: 3046 * ipfw set N delete set M 3047 */ 3048 if (co.use_set) 3049 errx(EX_DATAERR, "invalid syntax"); 3050 do_set = 1; /* delete set */ 3051 av++; 3052 } 3053 3054 /* Rule number */ 3055 while (*av && isdigit(**av)) { 3056 i = strtol(*av, &sep, 10); 3057 j = i; 3058 if (*sep== '-') 3059 j = strtol(sep + 1, NULL, 10); 3060 av++; 3061 if (co.do_nat) { 3062 exitval = do_cmd(IP_FW_NAT_DEL, &i, sizeof i); 3063 if (exitval) { 3064 exitval = EX_UNAVAILABLE; 3065 warn("rule %u not available", i); 3066 } 3067 } else if (co.do_pipe) { 3068 exitval = ipfw_delete_pipe(co.do_pipe, i); 3069 } else { 3070 if (do_set != 0) { 3071 rt.set = i & 31; 3072 rt.flags = IPFW_RCFLAG_SET; 3073 } else { 3074 rt.start_rule = i & 0xffff; 3075 rt.end_rule = j & 0xffff; 3076 if (rt.start_rule == 0 && rt.end_rule == 0) 3077 rt.flags |= IPFW_RCFLAG_ALL; 3078 else 3079 rt.flags |= IPFW_RCFLAG_RANGE; 3080 if (co.use_set != 0) { 3081 rt.set = co.use_set - 1; 3082 rt.flags |= IPFW_RCFLAG_SET; 3083 } 3084 } 3085 i = do_range_cmd(IP_FW_XDEL, &rt); 3086 if (i != 0) { 3087 exitval = EX_UNAVAILABLE; 3088 warn("rule %u: setsockopt(IP_FW_XDEL)", 3089 rt.start_rule); 3090 } else if (rt.new_set == 0) { 3091 exitval = EX_UNAVAILABLE; 3092 if (rt.start_rule != rt.end_rule) 3093 warnx("no rules rules in %u-%u range", 3094 rt.start_rule, rt.end_rule); 3095 else 3096 warnx("rule %u not found", 3097 rt.start_rule); 3098 } 3099 } 3100 } 3101 if (exitval != EX_OK) 3102 exit(exitval); 3103 } 3104 3105 3106 /* 3107 * fill the interface structure. We do not check the name as we can 3108 * create interfaces dynamically, so checking them at insert time 3109 * makes relatively little sense. 3110 * Interface names containing '*', '?', or '[' are assumed to be shell 3111 * patterns which match interfaces. 3112 */ 3113 static void 3114 fill_iface(ipfw_insn_if *cmd, char *arg, int cblen, struct tidx *tstate) 3115 { 3116 char *p; 3117 uint16_t uidx; 3118 3119 cmd->name[0] = '\0'; 3120 cmd->o.len |= F_INSN_SIZE(ipfw_insn_if); 3121 3122 CHECK_CMDLEN; 3123 3124 /* Parse the interface or address */ 3125 if (strcmp(arg, "any") == 0) 3126 cmd->o.len = 0; /* effectively ignore this command */ 3127 else if (strncmp(arg, "table(", 6) == 0) { 3128 if ((p = strchr(arg + 6, ')')) == NULL) 3129 errx(EX_DATAERR, "forgotten parenthesis: '%s'", arg); 3130 *p = '\0'; 3131 p = strchr(arg + 6, ','); 3132 if (p) 3133 *p++ = '\0'; 3134 if ((uidx = pack_table(tstate, arg + 6)) == 0) 3135 errx(EX_DATAERR, "Invalid table name: %s", arg + 6); 3136 3137 cmd->name[0] = '\1'; /* Special value indicating table */ 3138 cmd->p.kidx = uidx; 3139 } else if (!isdigit(*arg)) { 3140 strlcpy(cmd->name, arg, sizeof(cmd->name)); 3141 cmd->p.glob = strpbrk(arg, "*?[") != NULL ? 1 : 0; 3142 } else if (!inet_aton(arg, &cmd->p.ip)) 3143 errx(EX_DATAERR, "bad ip address ``%s''", arg); 3144 } 3145 3146 static void 3147 get_mac_addr_mask(const char *p, uint8_t *addr, uint8_t *mask) 3148 { 3149 int i; 3150 size_t l; 3151 char *ap, *ptr, *optr; 3152 struct ether_addr *mac; 3153 const char *macset = "0123456789abcdefABCDEF:"; 3154 3155 if (strcmp(p, "any") == 0) { 3156 for (i = 0; i < ETHER_ADDR_LEN; i++) 3157 addr[i] = mask[i] = 0; 3158 return; 3159 } 3160 3161 optr = ptr = strdup(p); 3162 if ((ap = strsep(&ptr, "&/")) != NULL && *ap != 0) { 3163 l = strlen(ap); 3164 if (strspn(ap, macset) != l || (mac = ether_aton(ap)) == NULL) 3165 errx(EX_DATAERR, "Incorrect MAC address"); 3166 bcopy(mac, addr, ETHER_ADDR_LEN); 3167 } else 3168 errx(EX_DATAERR, "Incorrect MAC address"); 3169 3170 if (ptr != NULL) { /* we have mask? */ 3171 if (p[ptr - optr - 1] == '/') { /* mask len */ 3172 long ml = strtol(ptr, &ap, 10); 3173 if (*ap != 0 || ml > ETHER_ADDR_LEN * 8 || ml < 0) 3174 errx(EX_DATAERR, "Incorrect mask length"); 3175 for (i = 0; ml > 0 && i < ETHER_ADDR_LEN; ml -= 8, i++) 3176 mask[i] = (ml >= 8) ? 0xff: (~0) << (8 - ml); 3177 } else { /* mask */ 3178 l = strlen(ptr); 3179 if (strspn(ptr, macset) != l || 3180 (mac = ether_aton(ptr)) == NULL) 3181 errx(EX_DATAERR, "Incorrect mask"); 3182 bcopy(mac, mask, ETHER_ADDR_LEN); 3183 } 3184 } else { /* default mask: ff:ff:ff:ff:ff:ff */ 3185 for (i = 0; i < ETHER_ADDR_LEN; i++) 3186 mask[i] = 0xff; 3187 } 3188 for (i = 0; i < ETHER_ADDR_LEN; i++) 3189 addr[i] &= mask[i]; 3190 3191 free(optr); 3192 } 3193 3194 /* 3195 * helper function, updates the pointer to cmd with the length 3196 * of the current command, and also cleans up the first word of 3197 * the new command in case it has been clobbered before. 3198 */ 3199 static ipfw_insn * 3200 next_cmd(ipfw_insn *cmd, int *len) 3201 { 3202 *len -= F_LEN(cmd); 3203 CHECK_LENGTH(*len, 0); 3204 cmd += F_LEN(cmd); 3205 bzero(cmd, sizeof(*cmd)); 3206 return cmd; 3207 } 3208 3209 /* 3210 * Takes arguments and copies them into a comment 3211 */ 3212 static void 3213 fill_comment(ipfw_insn *cmd, char **av, int cblen) 3214 { 3215 int i, l; 3216 char *p = (char *)(cmd + 1); 3217 3218 cmd->opcode = O_NOP; 3219 cmd->len = (cmd->len & (F_NOT | F_OR)); 3220 3221 /* Compute length of comment string. */ 3222 for (i = 0, l = 0; av[i] != NULL; i++) 3223 l += strlen(av[i]) + 1; 3224 if (l == 0) 3225 return; 3226 if (l > 84) 3227 errx(EX_DATAERR, 3228 "comment too long (max 80 chars)"); 3229 l = 1 + (l+3)/4; 3230 cmd->len = (cmd->len & (F_NOT | F_OR)) | l; 3231 CHECK_CMDLEN; 3232 3233 for (i = 0; av[i] != NULL; i++) { 3234 strcpy(p, av[i]); 3235 p += strlen(av[i]); 3236 *p++ = ' '; 3237 } 3238 *(--p) = '\0'; 3239 } 3240 3241 /* 3242 * A function to fill simple commands of size 1. 3243 * Existing flags are preserved. 3244 */ 3245 static void 3246 fill_cmd(ipfw_insn *cmd, enum ipfw_opcodes opcode, int flags, uint16_t arg) 3247 { 3248 cmd->opcode = opcode; 3249 cmd->len = ((cmd->len | flags) & (F_NOT | F_OR)) | 1; 3250 cmd->arg1 = arg; 3251 } 3252 3253 /* 3254 * Fetch and add the MAC address and type, with masks. This generates one or 3255 * two microinstructions, and returns the pointer to the last one. 3256 */ 3257 static ipfw_insn * 3258 add_mac(ipfw_insn *cmd, char *av[], int cblen) 3259 { 3260 ipfw_insn_mac *mac; 3261 3262 if ( ( av[0] == NULL ) || ( av[1] == NULL ) ) 3263 errx(EX_DATAERR, "MAC dst src"); 3264 3265 cmd->opcode = O_MACADDR2; 3266 cmd->len = (cmd->len & (F_NOT | F_OR)) | F_INSN_SIZE(ipfw_insn_mac); 3267 CHECK_CMDLEN; 3268 3269 mac = (ipfw_insn_mac *)cmd; 3270 get_mac_addr_mask(av[0], mac->addr, mac->mask); /* dst */ 3271 get_mac_addr_mask(av[1], &(mac->addr[ETHER_ADDR_LEN]), 3272 &(mac->mask[ETHER_ADDR_LEN])); /* src */ 3273 return cmd; 3274 } 3275 3276 static ipfw_insn * 3277 add_mactype(ipfw_insn *cmd, char *av, int cblen) 3278 { 3279 if (!av) 3280 errx(EX_DATAERR, "missing MAC type"); 3281 if (strcmp(av, "any") != 0) { /* we have a non-null type */ 3282 fill_newports((ipfw_insn_u16 *)cmd, av, IPPROTO_ETHERTYPE, 3283 cblen); 3284 cmd->opcode = O_MAC_TYPE; 3285 return cmd; 3286 } else 3287 return NULL; 3288 } 3289 3290 static ipfw_insn * 3291 add_proto0(ipfw_insn *cmd, char *av, u_char *protop) 3292 { 3293 struct protoent *pe; 3294 char *ep; 3295 int proto; 3296 3297 proto = strtol(av, &ep, 10); 3298 if (*ep != '\0' || proto <= 0) { 3299 if ((pe = getprotobyname(av)) == NULL) 3300 return NULL; 3301 proto = pe->p_proto; 3302 } 3303 3304 fill_cmd(cmd, O_PROTO, 0, proto); 3305 *protop = proto; 3306 return cmd; 3307 } 3308 3309 static ipfw_insn * 3310 add_proto(ipfw_insn *cmd, char *av, u_char *protop) 3311 { 3312 u_char proto = IPPROTO_IP; 3313 3314 if (_substrcmp(av, "all") == 0 || strcmp(av, "ip") == 0) 3315 ; /* do not set O_IP4 nor O_IP6 */ 3316 else if (strcmp(av, "ip4") == 0) 3317 /* explicit "just IPv4" rule */ 3318 fill_cmd(cmd, O_IP4, 0, 0); 3319 else if (strcmp(av, "ip6") == 0) { 3320 /* explicit "just IPv6" rule */ 3321 proto = IPPROTO_IPV6; 3322 fill_cmd(cmd, O_IP6, 0, 0); 3323 } else 3324 return add_proto0(cmd, av, protop); 3325 3326 *protop = proto; 3327 return cmd; 3328 } 3329 3330 static ipfw_insn * 3331 add_proto_compat(ipfw_insn *cmd, char *av, u_char *protop) 3332 { 3333 u_char proto = IPPROTO_IP; 3334 3335 if (_substrcmp(av, "all") == 0 || strcmp(av, "ip") == 0) 3336 ; /* do not set O_IP4 nor O_IP6 */ 3337 else if (strcmp(av, "ipv4") == 0 || strcmp(av, "ip4") == 0) 3338 /* explicit "just IPv4" rule */ 3339 fill_cmd(cmd, O_IP4, 0, 0); 3340 else if (strcmp(av, "ipv6") == 0 || strcmp(av, "ip6") == 0) { 3341 /* explicit "just IPv6" rule */ 3342 proto = IPPROTO_IPV6; 3343 fill_cmd(cmd, O_IP6, 0, 0); 3344 } else 3345 return add_proto0(cmd, av, protop); 3346 3347 *protop = proto; 3348 return cmd; 3349 } 3350 3351 static ipfw_insn * 3352 add_srcip(ipfw_insn *cmd, char *av, int cblen, struct tidx *tstate) 3353 { 3354 fill_ip((ipfw_insn_ip *)cmd, av, cblen, tstate); 3355 if (cmd->opcode == O_IP_DST_SET) /* set */ 3356 cmd->opcode = O_IP_SRC_SET; 3357 else if (cmd->opcode == O_IP_DST_LOOKUP) /* table */ 3358 cmd->opcode = O_IP_SRC_LOOKUP; 3359 else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) /* me */ 3360 cmd->opcode = O_IP_SRC_ME; 3361 else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn_u32)) /* one IP */ 3362 cmd->opcode = O_IP_SRC; 3363 else /* addr/mask */ 3364 cmd->opcode = O_IP_SRC_MASK; 3365 return cmd; 3366 } 3367 3368 static ipfw_insn * 3369 add_dstip(ipfw_insn *cmd, char *av, int cblen, struct tidx *tstate) 3370 { 3371 fill_ip((ipfw_insn_ip *)cmd, av, cblen, tstate); 3372 if (cmd->opcode == O_IP_DST_SET) /* set */ 3373 ; 3374 else if (cmd->opcode == O_IP_DST_LOOKUP) /* table */ 3375 ; 3376 else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) /* me */ 3377 cmd->opcode = O_IP_DST_ME; 3378 else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn_u32)) /* one IP */ 3379 cmd->opcode = O_IP_DST; 3380 else /* addr/mask */ 3381 cmd->opcode = O_IP_DST_MASK; 3382 return cmd; 3383 } 3384 3385 static struct _s_x f_reserved_keywords[] = { 3386 { "altq", TOK_OR }, 3387 { "//", TOK_OR }, 3388 { "diverted", TOK_OR }, 3389 { "dst-port", TOK_OR }, 3390 { "src-port", TOK_OR }, 3391 { "established", TOK_OR }, 3392 { "keep-state", TOK_OR }, 3393 { "frag", TOK_OR }, 3394 { "icmptypes", TOK_OR }, 3395 { "in", TOK_OR }, 3396 { "out", TOK_OR }, 3397 { "ip6", TOK_OR }, 3398 { "any", TOK_OR }, 3399 { "to", TOK_OR }, 3400 { "via", TOK_OR }, 3401 { "{", TOK_OR }, 3402 { NULL, 0 } /* terminator */ 3403 }; 3404 3405 static ipfw_insn * 3406 add_ports(ipfw_insn *cmd, char *av, u_char proto, int opcode, int cblen) 3407 { 3408 3409 if (match_token(f_reserved_keywords, av) != -1) 3410 return (NULL); 3411 3412 if (fill_newports((ipfw_insn_u16 *)cmd, av, proto, cblen)) { 3413 /* XXX todo: check that we have a protocol with ports */ 3414 cmd->opcode = opcode; 3415 return cmd; 3416 } 3417 return NULL; 3418 } 3419 3420 static ipfw_insn * 3421 add_src(ipfw_insn *cmd, char *av, u_char proto, int cblen, struct tidx *tstate) 3422 { 3423 struct in6_addr a; 3424 char *host, *ch, buf[INET6_ADDRSTRLEN]; 3425 ipfw_insn *ret = NULL; 3426 int len; 3427 3428 /* Copy first address in set if needed */ 3429 if ((ch = strpbrk(av, "/,")) != NULL) { 3430 len = ch - av; 3431 strlcpy(buf, av, sizeof(buf)); 3432 if (len < sizeof(buf)) 3433 buf[len] = '\0'; 3434 host = buf; 3435 } else 3436 host = av; 3437 3438 if (proto == IPPROTO_IPV6 || strcmp(av, "me6") == 0 || 3439 inet_pton(AF_INET6, host, &a) == 1) 3440 ret = add_srcip6(cmd, av, cblen); 3441 /* XXX: should check for IPv4, not !IPv6 */ 3442 if (ret == NULL && (proto == IPPROTO_IP || strcmp(av, "me") == 0 || 3443 inet_pton(AF_INET6, host, &a) != 1)) 3444 ret = add_srcip(cmd, av, cblen, tstate); 3445 if (ret == NULL && strcmp(av, "any") != 0) 3446 ret = cmd; 3447 3448 return ret; 3449 } 3450 3451 static ipfw_insn * 3452 add_dst(ipfw_insn *cmd, char *av, u_char proto, int cblen, struct tidx *tstate) 3453 { 3454 struct in6_addr a; 3455 char *host, *ch, buf[INET6_ADDRSTRLEN]; 3456 ipfw_insn *ret = NULL; 3457 int len; 3458 3459 /* Copy first address in set if needed */ 3460 if ((ch = strpbrk(av, "/,")) != NULL) { 3461 len = ch - av; 3462 strlcpy(buf, av, sizeof(buf)); 3463 if (len < sizeof(buf)) 3464 buf[len] = '\0'; 3465 host = buf; 3466 } else 3467 host = av; 3468 3469 if (proto == IPPROTO_IPV6 || strcmp(av, "me6") == 0 || 3470 inet_pton(AF_INET6, host, &a) == 1) 3471 ret = add_dstip6(cmd, av, cblen); 3472 /* XXX: should check for IPv4, not !IPv6 */ 3473 if (ret == NULL && (proto == IPPROTO_IP || strcmp(av, "me") == 0 || 3474 inet_pton(AF_INET6, host, &a) != 1)) 3475 ret = add_dstip(cmd, av, cblen, tstate); 3476 if (ret == NULL && strcmp(av, "any") != 0) 3477 ret = cmd; 3478 3479 return ret; 3480 } 3481 3482 /* 3483 * Parse arguments and assemble the microinstructions which make up a rule. 3484 * Rules are added into the 'rulebuf' and then copied in the correct order 3485 * into the actual rule. 3486 * 3487 * The syntax for a rule starts with the action, followed by 3488 * optional action parameters, and the various match patterns. 3489 * In the assembled microcode, the first opcode must be an O_PROBE_STATE 3490 * (generated if the rule includes a keep-state option), then the 3491 * various match patterns, log/altq actions, and the actual action. 3492 * 3493 */ 3494 void 3495 compile_rule(char *av[], uint32_t *rbuf, int *rbufsize, struct tidx *tstate) 3496 { 3497 /* 3498 * rules are added into the 'rulebuf' and then copied in 3499 * the correct order into the actual rule. 3500 * Some things that need to go out of order (prob, action etc.) 3501 * go into actbuf[]. 3502 */ 3503 static uint32_t actbuf[255], cmdbuf[255]; 3504 int rblen, ablen, cblen; 3505 3506 ipfw_insn *src, *dst, *cmd, *action, *prev=NULL; 3507 ipfw_insn *first_cmd; /* first match pattern */ 3508 3509 struct ip_fw_rule *rule; 3510 3511 /* 3512 * various flags used to record that we entered some fields. 3513 */ 3514 ipfw_insn *have_state = NULL; /* check-state or keep-state */ 3515 ipfw_insn *have_log = NULL, *have_altq = NULL, *have_tag = NULL; 3516 size_t len; 3517 3518 int i; 3519 3520 int open_par = 0; /* open parenthesis ( */ 3521 3522 /* proto is here because it is used to fetch ports */ 3523 u_char proto = IPPROTO_IP; /* default protocol */ 3524 3525 double match_prob = 1; /* match probability, default is always match */ 3526 3527 bzero(actbuf, sizeof(actbuf)); /* actions go here */ 3528 bzero(cmdbuf, sizeof(cmdbuf)); 3529 bzero(rbuf, *rbufsize); 3530 3531 rule = (struct ip_fw_rule *)rbuf; 3532 cmd = (ipfw_insn *)cmdbuf; 3533 action = (ipfw_insn *)actbuf; 3534 3535 rblen = *rbufsize / sizeof(uint32_t); 3536 rblen -= sizeof(struct ip_fw_rule) / sizeof(uint32_t); 3537 ablen = sizeof(actbuf) / sizeof(actbuf[0]); 3538 cblen = sizeof(cmdbuf) / sizeof(cmdbuf[0]); 3539 cblen -= F_INSN_SIZE(ipfw_insn_u32) + 1; 3540 3541 #define CHECK_RBUFLEN(len) { CHECK_LENGTH(rblen, len); rblen -= len; } 3542 #define CHECK_ACTLEN CHECK_LENGTH(ablen, action->len) 3543 3544 av++; 3545 3546 /* [rule N] -- Rule number optional */ 3547 if (av[0] && isdigit(**av)) { 3548 rule->rulenum = atoi(*av); 3549 av++; 3550 } 3551 3552 /* [set N] -- set number (0..RESVD_SET), optional */ 3553 if (av[0] && av[1] && _substrcmp(*av, "set") == 0) { 3554 int set = strtoul(av[1], NULL, 10); 3555 if (set < 0 || set > RESVD_SET) 3556 errx(EX_DATAERR, "illegal set %s", av[1]); 3557 rule->set = set; 3558 tstate->set = set; 3559 av += 2; 3560 } 3561 3562 /* [prob D] -- match probability, optional */ 3563 if (av[0] && av[1] && _substrcmp(*av, "prob") == 0) { 3564 match_prob = strtod(av[1], NULL); 3565 3566 if (match_prob <= 0 || match_prob > 1) 3567 errx(EX_DATAERR, "illegal match prob. %s", av[1]); 3568 av += 2; 3569 } 3570 3571 /* action -- mandatory */ 3572 NEED1("missing action"); 3573 i = match_token(rule_actions, *av); 3574 av++; 3575 action->len = 1; /* default */ 3576 CHECK_ACTLEN; 3577 switch(i) { 3578 case TOK_CHECKSTATE: 3579 have_state = action; 3580 action->opcode = O_CHECK_STATE; 3581 break; 3582 3583 case TOK_ACCEPT: 3584 action->opcode = O_ACCEPT; 3585 break; 3586 3587 case TOK_DENY: 3588 action->opcode = O_DENY; 3589 action->arg1 = 0; 3590 break; 3591 3592 case TOK_REJECT: 3593 action->opcode = O_REJECT; 3594 action->arg1 = ICMP_UNREACH_HOST; 3595 break; 3596 3597 case TOK_RESET: 3598 action->opcode = O_REJECT; 3599 action->arg1 = ICMP_REJECT_RST; 3600 break; 3601 3602 case TOK_RESET6: 3603 action->opcode = O_UNREACH6; 3604 action->arg1 = ICMP6_UNREACH_RST; 3605 break; 3606 3607 case TOK_UNREACH: 3608 action->opcode = O_REJECT; 3609 NEED1("missing reject code"); 3610 fill_reject_code(&action->arg1, *av); 3611 av++; 3612 break; 3613 3614 case TOK_UNREACH6: 3615 action->opcode = O_UNREACH6; 3616 NEED1("missing unreach code"); 3617 fill_unreach6_code(&action->arg1, *av); 3618 av++; 3619 break; 3620 3621 case TOK_COUNT: 3622 action->opcode = O_COUNT; 3623 break; 3624 3625 case TOK_NAT: 3626 action->opcode = O_NAT; 3627 action->len = F_INSN_SIZE(ipfw_insn_nat); 3628 CHECK_ACTLEN; 3629 if (*av != NULL && _substrcmp(*av, "global") == 0) { 3630 action->arg1 = 0; 3631 av++; 3632 break; 3633 } else 3634 goto chkarg; 3635 case TOK_QUEUE: 3636 action->opcode = O_QUEUE; 3637 goto chkarg; 3638 case TOK_PIPE: 3639 action->opcode = O_PIPE; 3640 goto chkarg; 3641 case TOK_SKIPTO: 3642 action->opcode = O_SKIPTO; 3643 goto chkarg; 3644 case TOK_NETGRAPH: 3645 action->opcode = O_NETGRAPH; 3646 goto chkarg; 3647 case TOK_NGTEE: 3648 action->opcode = O_NGTEE; 3649 goto chkarg; 3650 case TOK_DIVERT: 3651 action->opcode = O_DIVERT; 3652 goto chkarg; 3653 case TOK_TEE: 3654 action->opcode = O_TEE; 3655 goto chkarg; 3656 case TOK_CALL: 3657 action->opcode = O_CALLRETURN; 3658 chkarg: 3659 if (!av[0]) 3660 errx(EX_USAGE, "missing argument for %s", *(av - 1)); 3661 if (isdigit(**av)) { 3662 action->arg1 = strtoul(*av, NULL, 10); 3663 if (action->arg1 <= 0 || action->arg1 >= IP_FW_TABLEARG) 3664 errx(EX_DATAERR, "illegal argument for %s", 3665 *(av - 1)); 3666 } else if (_substrcmp(*av, "tablearg") == 0) { 3667 action->arg1 = IP_FW_TARG; 3668 } else if (i == TOK_DIVERT || i == TOK_TEE) { 3669 struct servent *s; 3670 setservent(1); 3671 s = getservbyname(av[0], "divert"); 3672 if (s != NULL) 3673 action->arg1 = ntohs(s->s_port); 3674 else 3675 errx(EX_DATAERR, "illegal divert/tee port"); 3676 } else 3677 errx(EX_DATAERR, "illegal argument for %s", *(av - 1)); 3678 av++; 3679 break; 3680 3681 case TOK_FORWARD: { 3682 /* 3683 * Locate the address-port separator (':' or ','). 3684 * Could be one of the following: 3685 * hostname:port 3686 * IPv4 a.b.c.d,port 3687 * IPv4 a.b.c.d:port 3688 * IPv6 w:x:y::z,port 3689 * The ':' can only be used with hostname and IPv4 address. 3690 * XXX-BZ Should we also support [w:x:y::z]:port? 3691 */ 3692 struct sockaddr_storage result; 3693 struct addrinfo *res; 3694 char *s, *end; 3695 int family; 3696 u_short port_number; 3697 3698 NEED1("missing forward address[:port]"); 3699 3700 /* 3701 * locate the address-port separator (':' or ',') 3702 */ 3703 s = strchr(*av, ','); 3704 if (s == NULL) { 3705 /* Distinguish between IPv4:port and IPv6 cases. */ 3706 s = strchr(*av, ':'); 3707 if (s && strchr(s+1, ':')) 3708 s = NULL; /* no port */ 3709 } 3710 3711 port_number = 0; 3712 if (s != NULL) { 3713 /* Terminate host portion and set s to start of port. */ 3714 *(s++) = '\0'; 3715 i = strtoport(s, &end, 0 /* base */, 0 /* proto */); 3716 if (s == end) 3717 errx(EX_DATAERR, 3718 "illegal forwarding port ``%s''", s); 3719 port_number = (u_short)i; 3720 } 3721 3722 if (_substrcmp(*av, "tablearg") == 0) { 3723 family = PF_INET; 3724 ((struct sockaddr_in*)&result)->sin_addr.s_addr = 3725 INADDR_ANY; 3726 } else { 3727 /* 3728 * Resolve the host name or address to a family and a 3729 * network representation of the address. 3730 */ 3731 if (getaddrinfo(*av, NULL, NULL, &res)) 3732 errx(EX_DATAERR, NULL); 3733 /* Just use the first host in the answer. */ 3734 family = res->ai_family; 3735 memcpy(&result, res->ai_addr, res->ai_addrlen); 3736 freeaddrinfo(res); 3737 } 3738 3739 if (family == PF_INET) { 3740 ipfw_insn_sa *p = (ipfw_insn_sa *)action; 3741 3742 action->opcode = O_FORWARD_IP; 3743 action->len = F_INSN_SIZE(ipfw_insn_sa); 3744 CHECK_ACTLEN; 3745 3746 /* 3747 * In the kernel we assume AF_INET and use only 3748 * sin_port and sin_addr. Remember to set sin_len as 3749 * the routing code seems to use it too. 3750 */ 3751 p->sa.sin_len = sizeof(struct sockaddr_in); 3752 p->sa.sin_family = AF_INET; 3753 p->sa.sin_port = port_number; 3754 p->sa.sin_addr.s_addr = 3755 ((struct sockaddr_in *)&result)->sin_addr.s_addr; 3756 } else if (family == PF_INET6) { 3757 ipfw_insn_sa6 *p = (ipfw_insn_sa6 *)action; 3758 3759 action->opcode = O_FORWARD_IP6; 3760 action->len = F_INSN_SIZE(ipfw_insn_sa6); 3761 CHECK_ACTLEN; 3762 3763 p->sa.sin6_len = sizeof(struct sockaddr_in6); 3764 p->sa.sin6_family = AF_INET6; 3765 p->sa.sin6_port = port_number; 3766 p->sa.sin6_flowinfo = 0; 3767 p->sa.sin6_scope_id = 3768 ((struct sockaddr_in6 *)&result)->sin6_scope_id; 3769 bcopy(&((struct sockaddr_in6*)&result)->sin6_addr, 3770 &p->sa.sin6_addr, sizeof(p->sa.sin6_addr)); 3771 } else { 3772 errx(EX_DATAERR, "Invalid address family in forward action"); 3773 } 3774 av++; 3775 break; 3776 } 3777 case TOK_COMMENT: 3778 /* pretend it is a 'count' rule followed by the comment */ 3779 action->opcode = O_COUNT; 3780 av--; /* go back... */ 3781 break; 3782 3783 case TOK_SETFIB: 3784 { 3785 int numfibs; 3786 size_t intsize = sizeof(int); 3787 3788 action->opcode = O_SETFIB; 3789 NEED1("missing fib number"); 3790 if (_substrcmp(*av, "tablearg") == 0) { 3791 action->arg1 = IP_FW_TARG; 3792 } else { 3793 action->arg1 = strtoul(*av, NULL, 10); 3794 if (sysctlbyname("net.fibs", &numfibs, &intsize, 3795 NULL, 0) == -1) 3796 errx(EX_DATAERR, "fibs not suported.\n"); 3797 if (action->arg1 >= numfibs) /* Temporary */ 3798 errx(EX_DATAERR, "fib too large.\n"); 3799 /* Add high-order bit to fib to make room for tablearg*/ 3800 action->arg1 |= 0x8000; 3801 } 3802 av++; 3803 break; 3804 } 3805 3806 case TOK_SETDSCP: 3807 { 3808 int code; 3809 3810 action->opcode = O_SETDSCP; 3811 NEED1("missing DSCP code"); 3812 if (_substrcmp(*av, "tablearg") == 0) { 3813 action->arg1 = IP_FW_TARG; 3814 } else if (isalpha(*av[0])) { 3815 if ((code = match_token(f_ipdscp, *av)) == -1) 3816 errx(EX_DATAERR, "Unknown DSCP code"); 3817 action->arg1 = code; 3818 } else 3819 action->arg1 = strtoul(*av, NULL, 10); 3820 /* Add high-order bit to DSCP to make room for tablearg */ 3821 if (action->arg1 != IP_FW_TARG) 3822 action->arg1 |= 0x8000; 3823 av++; 3824 break; 3825 } 3826 3827 case TOK_REASS: 3828 action->opcode = O_REASS; 3829 break; 3830 3831 case TOK_RETURN: 3832 fill_cmd(action, O_CALLRETURN, F_NOT, 0); 3833 break; 3834 3835 default: 3836 errx(EX_DATAERR, "invalid action %s\n", av[-1]); 3837 } 3838 action = next_cmd(action, &ablen); 3839 3840 /* 3841 * [altq queuename] -- altq tag, optional 3842 * [log [logamount N]] -- log, optional 3843 * 3844 * If they exist, it go first in the cmdbuf, but then it is 3845 * skipped in the copy section to the end of the buffer. 3846 */ 3847 while (av[0] != NULL && (i = match_token(rule_action_params, *av)) != -1) { 3848 av++; 3849 switch (i) { 3850 case TOK_LOG: 3851 { 3852 ipfw_insn_log *c = (ipfw_insn_log *)cmd; 3853 int l; 3854 3855 if (have_log) 3856 errx(EX_DATAERR, 3857 "log cannot be specified more than once"); 3858 have_log = (ipfw_insn *)c; 3859 cmd->len = F_INSN_SIZE(ipfw_insn_log); 3860 CHECK_CMDLEN; 3861 cmd->opcode = O_LOG; 3862 if (av[0] && _substrcmp(*av, "logamount") == 0) { 3863 av++; 3864 NEED1("logamount requires argument"); 3865 l = atoi(*av); 3866 if (l < 0) 3867 errx(EX_DATAERR, 3868 "logamount must be positive"); 3869 c->max_log = l; 3870 av++; 3871 } else { 3872 len = sizeof(c->max_log); 3873 if (sysctlbyname("net.inet.ip.fw.verbose_limit", 3874 &c->max_log, &len, NULL, 0) == -1) { 3875 if (co.test_only) { 3876 c->max_log = 0; 3877 break; 3878 } 3879 errx(1, "sysctlbyname(\"%s\")", 3880 "net.inet.ip.fw.verbose_limit"); 3881 } 3882 } 3883 } 3884 break; 3885 3886 #ifndef NO_ALTQ 3887 case TOK_ALTQ: 3888 { 3889 ipfw_insn_altq *a = (ipfw_insn_altq *)cmd; 3890 3891 NEED1("missing altq queue name"); 3892 if (have_altq) 3893 errx(EX_DATAERR, 3894 "altq cannot be specified more than once"); 3895 have_altq = (ipfw_insn *)a; 3896 cmd->len = F_INSN_SIZE(ipfw_insn_altq); 3897 CHECK_CMDLEN; 3898 cmd->opcode = O_ALTQ; 3899 a->qid = altq_name_to_qid(*av); 3900 av++; 3901 } 3902 break; 3903 #endif 3904 3905 case TOK_TAG: 3906 case TOK_UNTAG: { 3907 uint16_t tag; 3908 3909 if (have_tag) 3910 errx(EX_USAGE, "tag and untag cannot be " 3911 "specified more than once"); 3912 GET_UINT_ARG(tag, IPFW_ARG_MIN, IPFW_ARG_MAX, i, 3913 rule_action_params); 3914 have_tag = cmd; 3915 fill_cmd(cmd, O_TAG, (i == TOK_TAG) ? 0: F_NOT, tag); 3916 av++; 3917 break; 3918 } 3919 3920 default: 3921 abort(); 3922 } 3923 cmd = next_cmd(cmd, &cblen); 3924 } 3925 3926 if (have_state) /* must be a check-state, we are done */ 3927 goto done; 3928 3929 #define OR_START(target) \ 3930 if (av[0] && (*av[0] == '(' || *av[0] == '{')) { \ 3931 if (open_par) \ 3932 errx(EX_USAGE, "nested \"(\" not allowed\n"); \ 3933 prev = NULL; \ 3934 open_par = 1; \ 3935 if ( (av[0])[1] == '\0') { \ 3936 av++; \ 3937 } else \ 3938 (*av)++; \ 3939 } \ 3940 target: \ 3941 3942 3943 #define CLOSE_PAR \ 3944 if (open_par) { \ 3945 if (av[0] && ( \ 3946 strcmp(*av, ")") == 0 || \ 3947 strcmp(*av, "}") == 0)) { \ 3948 prev = NULL; \ 3949 open_par = 0; \ 3950 av++; \ 3951 } else \ 3952 errx(EX_USAGE, "missing \")\"\n"); \ 3953 } 3954 3955 #define NOT_BLOCK \ 3956 if (av[0] && _substrcmp(*av, "not") == 0) { \ 3957 if (cmd->len & F_NOT) \ 3958 errx(EX_USAGE, "double \"not\" not allowed\n"); \ 3959 cmd->len |= F_NOT; \ 3960 av++; \ 3961 } 3962 3963 #define OR_BLOCK(target) \ 3964 if (av[0] && _substrcmp(*av, "or") == 0) { \ 3965 if (prev == NULL || open_par == 0) \ 3966 errx(EX_DATAERR, "invalid OR block"); \ 3967 prev->len |= F_OR; \ 3968 av++; \ 3969 goto target; \ 3970 } \ 3971 CLOSE_PAR; 3972 3973 first_cmd = cmd; 3974 3975 #if 0 3976 /* 3977 * MAC addresses, optional. 3978 * If we have this, we skip the part "proto from src to dst" 3979 * and jump straight to the option parsing. 3980 */ 3981 NOT_BLOCK; 3982 NEED1("missing protocol"); 3983 if (_substrcmp(*av, "MAC") == 0 || 3984 _substrcmp(*av, "mac") == 0) { 3985 av++; /* the "MAC" keyword */ 3986 add_mac(cmd, av); /* exits in case of errors */ 3987 cmd = next_cmd(cmd); 3988 av += 2; /* dst-mac and src-mac */ 3989 NOT_BLOCK; 3990 NEED1("missing mac type"); 3991 if (add_mactype(cmd, av[0])) 3992 cmd = next_cmd(cmd); 3993 av++; /* any or mac-type */ 3994 goto read_options; 3995 } 3996 #endif 3997 3998 /* 3999 * protocol, mandatory 4000 */ 4001 OR_START(get_proto); 4002 NOT_BLOCK; 4003 NEED1("missing protocol"); 4004 if (add_proto_compat(cmd, *av, &proto)) { 4005 av++; 4006 if (F_LEN(cmd) != 0) { 4007 prev = cmd; 4008 cmd = next_cmd(cmd, &cblen); 4009 } 4010 } else if (first_cmd != cmd) { 4011 errx(EX_DATAERR, "invalid protocol ``%s''", *av); 4012 } else 4013 goto read_options; 4014 OR_BLOCK(get_proto); 4015 4016 /* 4017 * "from", mandatory 4018 */ 4019 if ((av[0] == NULL) || _substrcmp(*av, "from") != 0) 4020 errx(EX_USAGE, "missing ``from''"); 4021 av++; 4022 4023 /* 4024 * source IP, mandatory 4025 */ 4026 OR_START(source_ip); 4027 NOT_BLOCK; /* optional "not" */ 4028 NEED1("missing source address"); 4029 if (add_src(cmd, *av, proto, cblen, tstate)) { 4030 av++; 4031 if (F_LEN(cmd) != 0) { /* ! any */ 4032 prev = cmd; 4033 cmd = next_cmd(cmd, &cblen); 4034 } 4035 } else 4036 errx(EX_USAGE, "bad source address %s", *av); 4037 OR_BLOCK(source_ip); 4038 4039 /* 4040 * source ports, optional 4041 */ 4042 NOT_BLOCK; /* optional "not" */ 4043 if ( av[0] != NULL ) { 4044 if (_substrcmp(*av, "any") == 0 || 4045 add_ports(cmd, *av, proto, O_IP_SRCPORT, cblen)) { 4046 av++; 4047 if (F_LEN(cmd) != 0) 4048 cmd = next_cmd(cmd, &cblen); 4049 } 4050 } 4051 4052 /* 4053 * "to", mandatory 4054 */ 4055 if ( (av[0] == NULL) || _substrcmp(*av, "to") != 0 ) 4056 errx(EX_USAGE, "missing ``to''"); 4057 av++; 4058 4059 /* 4060 * destination, mandatory 4061 */ 4062 OR_START(dest_ip); 4063 NOT_BLOCK; /* optional "not" */ 4064 NEED1("missing dst address"); 4065 if (add_dst(cmd, *av, proto, cblen, tstate)) { 4066 av++; 4067 if (F_LEN(cmd) != 0) { /* ! any */ 4068 prev = cmd; 4069 cmd = next_cmd(cmd, &cblen); 4070 } 4071 } else 4072 errx( EX_USAGE, "bad destination address %s", *av); 4073 OR_BLOCK(dest_ip); 4074 4075 /* 4076 * dest. ports, optional 4077 */ 4078 NOT_BLOCK; /* optional "not" */ 4079 if (av[0]) { 4080 if (_substrcmp(*av, "any") == 0 || 4081 add_ports(cmd, *av, proto, O_IP_DSTPORT, cblen)) { 4082 av++; 4083 if (F_LEN(cmd) != 0) 4084 cmd = next_cmd(cmd, &cblen); 4085 } 4086 } 4087 4088 read_options: 4089 if (av[0] && first_cmd == cmd) { 4090 /* 4091 * nothing specified so far, store in the rule to ease 4092 * printout later. 4093 */ 4094 rule->flags |= IPFW_RULE_NOOPT; 4095 } 4096 prev = NULL; 4097 while ( av[0] != NULL ) { 4098 char *s; 4099 ipfw_insn_u32 *cmd32; /* alias for cmd */ 4100 4101 s = *av; 4102 cmd32 = (ipfw_insn_u32 *)cmd; 4103 4104 if (*s == '!') { /* alternate syntax for NOT */ 4105 if (cmd->len & F_NOT) 4106 errx(EX_USAGE, "double \"not\" not allowed\n"); 4107 cmd->len = F_NOT; 4108 s++; 4109 } 4110 i = match_token(rule_options, s); 4111 av++; 4112 switch(i) { 4113 case TOK_NOT: 4114 if (cmd->len & F_NOT) 4115 errx(EX_USAGE, "double \"not\" not allowed\n"); 4116 cmd->len = F_NOT; 4117 break; 4118 4119 case TOK_OR: 4120 if (open_par == 0 || prev == NULL) 4121 errx(EX_USAGE, "invalid \"or\" block\n"); 4122 prev->len |= F_OR; 4123 break; 4124 4125 case TOK_STARTBRACE: 4126 if (open_par) 4127 errx(EX_USAGE, "+nested \"(\" not allowed\n"); 4128 open_par = 1; 4129 break; 4130 4131 case TOK_ENDBRACE: 4132 if (!open_par) 4133 errx(EX_USAGE, "+missing \")\"\n"); 4134 open_par = 0; 4135 prev = NULL; 4136 break; 4137 4138 case TOK_IN: 4139 fill_cmd(cmd, O_IN, 0, 0); 4140 break; 4141 4142 case TOK_OUT: 4143 cmd->len ^= F_NOT; /* toggle F_NOT */ 4144 fill_cmd(cmd, O_IN, 0, 0); 4145 break; 4146 4147 case TOK_DIVERTED: 4148 fill_cmd(cmd, O_DIVERTED, 0, 3); 4149 break; 4150 4151 case TOK_DIVERTEDLOOPBACK: 4152 fill_cmd(cmd, O_DIVERTED, 0, 1); 4153 break; 4154 4155 case TOK_DIVERTEDOUTPUT: 4156 fill_cmd(cmd, O_DIVERTED, 0, 2); 4157 break; 4158 4159 case TOK_FRAG: 4160 fill_cmd(cmd, O_FRAG, 0, 0); 4161 break; 4162 4163 case TOK_LAYER2: 4164 fill_cmd(cmd, O_LAYER2, 0, 0); 4165 break; 4166 4167 case TOK_XMIT: 4168 case TOK_RECV: 4169 case TOK_VIA: 4170 NEED1("recv, xmit, via require interface name" 4171 " or address"); 4172 fill_iface((ipfw_insn_if *)cmd, av[0], cblen, tstate); 4173 av++; 4174 if (F_LEN(cmd) == 0) /* not a valid address */ 4175 break; 4176 if (i == TOK_XMIT) 4177 cmd->opcode = O_XMIT; 4178 else if (i == TOK_RECV) 4179 cmd->opcode = O_RECV; 4180 else if (i == TOK_VIA) 4181 cmd->opcode = O_VIA; 4182 break; 4183 4184 case TOK_ICMPTYPES: 4185 NEED1("icmptypes requires list of types"); 4186 fill_icmptypes((ipfw_insn_u32 *)cmd, *av); 4187 av++; 4188 break; 4189 4190 case TOK_ICMP6TYPES: 4191 NEED1("icmptypes requires list of types"); 4192 fill_icmp6types((ipfw_insn_icmp6 *)cmd, *av, cblen); 4193 av++; 4194 break; 4195 4196 case TOK_IPTTL: 4197 NEED1("ipttl requires TTL"); 4198 if (strpbrk(*av, "-,")) { 4199 if (!add_ports(cmd, *av, 0, O_IPTTL, cblen)) 4200 errx(EX_DATAERR, "invalid ipttl %s", *av); 4201 } else 4202 fill_cmd(cmd, O_IPTTL, 0, strtoul(*av, NULL, 0)); 4203 av++; 4204 break; 4205 4206 case TOK_IPID: 4207 NEED1("ipid requires id"); 4208 if (strpbrk(*av, "-,")) { 4209 if (!add_ports(cmd, *av, 0, O_IPID, cblen)) 4210 errx(EX_DATAERR, "invalid ipid %s", *av); 4211 } else 4212 fill_cmd(cmd, O_IPID, 0, strtoul(*av, NULL, 0)); 4213 av++; 4214 break; 4215 4216 case TOK_IPLEN: 4217 NEED1("iplen requires length"); 4218 if (strpbrk(*av, "-,")) { 4219 if (!add_ports(cmd, *av, 0, O_IPLEN, cblen)) 4220 errx(EX_DATAERR, "invalid ip len %s", *av); 4221 } else 4222 fill_cmd(cmd, O_IPLEN, 0, strtoul(*av, NULL, 0)); 4223 av++; 4224 break; 4225 4226 case TOK_IPVER: 4227 NEED1("ipver requires version"); 4228 fill_cmd(cmd, O_IPVER, 0, strtoul(*av, NULL, 0)); 4229 av++; 4230 break; 4231 4232 case TOK_IPPRECEDENCE: 4233 NEED1("ipprecedence requires value"); 4234 fill_cmd(cmd, O_IPPRECEDENCE, 0, 4235 (strtoul(*av, NULL, 0) & 7) << 5); 4236 av++; 4237 break; 4238 4239 case TOK_DSCP: 4240 NEED1("missing DSCP code"); 4241 fill_dscp(cmd, *av, cblen); 4242 av++; 4243 break; 4244 4245 case TOK_IPOPTS: 4246 NEED1("missing argument for ipoptions"); 4247 fill_flags_cmd(cmd, O_IPOPT, f_ipopts, *av); 4248 av++; 4249 break; 4250 4251 case TOK_IPTOS: 4252 NEED1("missing argument for iptos"); 4253 fill_flags_cmd(cmd, O_IPTOS, f_iptos, *av); 4254 av++; 4255 break; 4256 4257 case TOK_UID: 4258 NEED1("uid requires argument"); 4259 { 4260 char *end; 4261 uid_t uid; 4262 struct passwd *pwd; 4263 4264 cmd->opcode = O_UID; 4265 uid = strtoul(*av, &end, 0); 4266 pwd = (*end == '\0') ? getpwuid(uid) : getpwnam(*av); 4267 if (pwd == NULL) 4268 errx(EX_DATAERR, "uid \"%s\" nonexistent", *av); 4269 cmd32->d[0] = pwd->pw_uid; 4270 cmd->len |= F_INSN_SIZE(ipfw_insn_u32); 4271 av++; 4272 } 4273 break; 4274 4275 case TOK_GID: 4276 NEED1("gid requires argument"); 4277 { 4278 char *end; 4279 gid_t gid; 4280 struct group *grp; 4281 4282 cmd->opcode = O_GID; 4283 gid = strtoul(*av, &end, 0); 4284 grp = (*end == '\0') ? getgrgid(gid) : getgrnam(*av); 4285 if (grp == NULL) 4286 errx(EX_DATAERR, "gid \"%s\" nonexistent", *av); 4287 cmd32->d[0] = grp->gr_gid; 4288 cmd->len |= F_INSN_SIZE(ipfw_insn_u32); 4289 av++; 4290 } 4291 break; 4292 4293 case TOK_JAIL: 4294 NEED1("jail requires argument"); 4295 { 4296 char *end; 4297 int jid; 4298 4299 cmd->opcode = O_JAIL; 4300 jid = (int)strtol(*av, &end, 0); 4301 if (jid < 0 || *end != '\0') 4302 errx(EX_DATAERR, "jail requires prison ID"); 4303 cmd32->d[0] = (uint32_t)jid; 4304 cmd->len |= F_INSN_SIZE(ipfw_insn_u32); 4305 av++; 4306 } 4307 break; 4308 4309 case TOK_ESTAB: 4310 fill_cmd(cmd, O_ESTAB, 0, 0); 4311 break; 4312 4313 case TOK_SETUP: 4314 fill_cmd(cmd, O_TCPFLAGS, 0, 4315 (TH_SYN) | ( (TH_ACK) & 0xff) <<8 ); 4316 break; 4317 4318 case TOK_TCPDATALEN: 4319 NEED1("tcpdatalen requires length"); 4320 if (strpbrk(*av, "-,")) { 4321 if (!add_ports(cmd, *av, 0, O_TCPDATALEN, cblen)) 4322 errx(EX_DATAERR, "invalid tcpdata len %s", *av); 4323 } else 4324 fill_cmd(cmd, O_TCPDATALEN, 0, 4325 strtoul(*av, NULL, 0)); 4326 av++; 4327 break; 4328 4329 case TOK_TCPOPTS: 4330 NEED1("missing argument for tcpoptions"); 4331 fill_flags_cmd(cmd, O_TCPOPTS, f_tcpopts, *av); 4332 av++; 4333 break; 4334 4335 case TOK_TCPSEQ: 4336 case TOK_TCPACK: 4337 NEED1("tcpseq/tcpack requires argument"); 4338 cmd->len = F_INSN_SIZE(ipfw_insn_u32); 4339 cmd->opcode = (i == TOK_TCPSEQ) ? O_TCPSEQ : O_TCPACK; 4340 cmd32->d[0] = htonl(strtoul(*av, NULL, 0)); 4341 av++; 4342 break; 4343 4344 case TOK_TCPWIN: 4345 NEED1("tcpwin requires length"); 4346 if (strpbrk(*av, "-,")) { 4347 if (!add_ports(cmd, *av, 0, O_TCPWIN, cblen)) 4348 errx(EX_DATAERR, "invalid tcpwin len %s", *av); 4349 } else 4350 fill_cmd(cmd, O_TCPWIN, 0, 4351 strtoul(*av, NULL, 0)); 4352 av++; 4353 break; 4354 4355 case TOK_TCPFLAGS: 4356 NEED1("missing argument for tcpflags"); 4357 cmd->opcode = O_TCPFLAGS; 4358 fill_flags_cmd(cmd, O_TCPFLAGS, f_tcpflags, *av); 4359 av++; 4360 break; 4361 4362 case TOK_KEEPSTATE: 4363 if (open_par) 4364 errx(EX_USAGE, "keep-state cannot be part " 4365 "of an or block"); 4366 if (have_state) 4367 errx(EX_USAGE, "only one of keep-state " 4368 "and limit is allowed"); 4369 have_state = cmd; 4370 fill_cmd(cmd, O_KEEP_STATE, 0, 0); 4371 break; 4372 4373 case TOK_LIMIT: { 4374 ipfw_insn_limit *c = (ipfw_insn_limit *)cmd; 4375 int val; 4376 4377 if (open_par) 4378 errx(EX_USAGE, 4379 "limit cannot be part of an or block"); 4380 if (have_state) 4381 errx(EX_USAGE, "only one of keep-state and " 4382 "limit is allowed"); 4383 have_state = cmd; 4384 4385 cmd->len = F_INSN_SIZE(ipfw_insn_limit); 4386 CHECK_CMDLEN; 4387 cmd->opcode = O_LIMIT; 4388 c->limit_mask = c->conn_limit = 0; 4389 4390 while ( av[0] != NULL ) { 4391 if ((val = match_token(limit_masks, *av)) <= 0) 4392 break; 4393 c->limit_mask |= val; 4394 av++; 4395 } 4396 4397 if (c->limit_mask == 0) 4398 errx(EX_USAGE, "limit: missing limit mask"); 4399 4400 GET_UINT_ARG(c->conn_limit, IPFW_ARG_MIN, IPFW_ARG_MAX, 4401 TOK_LIMIT, rule_options); 4402 4403 av++; 4404 break; 4405 } 4406 4407 case TOK_PROTO: 4408 NEED1("missing protocol"); 4409 if (add_proto(cmd, *av, &proto)) { 4410 av++; 4411 } else 4412 errx(EX_DATAERR, "invalid protocol ``%s''", 4413 *av); 4414 break; 4415 4416 case TOK_SRCIP: 4417 NEED1("missing source IP"); 4418 if (add_srcip(cmd, *av, cblen, tstate)) { 4419 av++; 4420 } 4421 break; 4422 4423 case TOK_DSTIP: 4424 NEED1("missing destination IP"); 4425 if (add_dstip(cmd, *av, cblen, tstate)) { 4426 av++; 4427 } 4428 break; 4429 4430 case TOK_SRCIP6: 4431 NEED1("missing source IP6"); 4432 if (add_srcip6(cmd, *av, cblen)) { 4433 av++; 4434 } 4435 break; 4436 4437 case TOK_DSTIP6: 4438 NEED1("missing destination IP6"); 4439 if (add_dstip6(cmd, *av, cblen)) { 4440 av++; 4441 } 4442 break; 4443 4444 case TOK_SRCPORT: 4445 NEED1("missing source port"); 4446 if (_substrcmp(*av, "any") == 0 || 4447 add_ports(cmd, *av, proto, O_IP_SRCPORT, cblen)) { 4448 av++; 4449 } else 4450 errx(EX_DATAERR, "invalid source port %s", *av); 4451 break; 4452 4453 case TOK_DSTPORT: 4454 NEED1("missing destination port"); 4455 if (_substrcmp(*av, "any") == 0 || 4456 add_ports(cmd, *av, proto, O_IP_DSTPORT, cblen)) { 4457 av++; 4458 } else 4459 errx(EX_DATAERR, "invalid destination port %s", 4460 *av); 4461 break; 4462 4463 case TOK_MAC: 4464 if (add_mac(cmd, av, cblen)) 4465 av += 2; 4466 break; 4467 4468 case TOK_MACTYPE: 4469 NEED1("missing mac type"); 4470 if (!add_mactype(cmd, *av, cblen)) 4471 errx(EX_DATAERR, "invalid mac type %s", *av); 4472 av++; 4473 break; 4474 4475 case TOK_VERREVPATH: 4476 fill_cmd(cmd, O_VERREVPATH, 0, 0); 4477 break; 4478 4479 case TOK_VERSRCREACH: 4480 fill_cmd(cmd, O_VERSRCREACH, 0, 0); 4481 break; 4482 4483 case TOK_ANTISPOOF: 4484 fill_cmd(cmd, O_ANTISPOOF, 0, 0); 4485 break; 4486 4487 case TOK_IPSEC: 4488 fill_cmd(cmd, O_IPSEC, 0, 0); 4489 break; 4490 4491 case TOK_IPV6: 4492 fill_cmd(cmd, O_IP6, 0, 0); 4493 break; 4494 4495 case TOK_IPV4: 4496 fill_cmd(cmd, O_IP4, 0, 0); 4497 break; 4498 4499 case TOK_EXT6HDR: 4500 fill_ext6hdr( cmd, *av ); 4501 av++; 4502 break; 4503 4504 case TOK_FLOWID: 4505 if (proto != IPPROTO_IPV6 ) 4506 errx( EX_USAGE, "flow-id filter is active " 4507 "only for ipv6 protocol\n"); 4508 fill_flow6( (ipfw_insn_u32 *) cmd, *av, cblen); 4509 av++; 4510 break; 4511 4512 case TOK_COMMENT: 4513 fill_comment(cmd, av, cblen); 4514 av[0]=NULL; 4515 break; 4516 4517 case TOK_TAGGED: 4518 if (av[0] && strpbrk(*av, "-,")) { 4519 if (!add_ports(cmd, *av, 0, O_TAGGED, cblen)) 4520 errx(EX_DATAERR, "tagged: invalid tag" 4521 " list: %s", *av); 4522 } 4523 else { 4524 uint16_t tag; 4525 4526 GET_UINT_ARG(tag, IPFW_ARG_MIN, IPFW_ARG_MAX, 4527 TOK_TAGGED, rule_options); 4528 fill_cmd(cmd, O_TAGGED, 0, tag); 4529 } 4530 av++; 4531 break; 4532 4533 case TOK_FIB: 4534 NEED1("fib requires fib number"); 4535 fill_cmd(cmd, O_FIB, 0, strtoul(*av, NULL, 0)); 4536 av++; 4537 break; 4538 case TOK_SOCKARG: 4539 fill_cmd(cmd, O_SOCKARG, 0, 0); 4540 break; 4541 4542 case TOK_LOOKUP: { 4543 ipfw_insn_u32 *c = (ipfw_insn_u32 *)cmd; 4544 int j; 4545 4546 if (!av[0] || !av[1]) 4547 errx(EX_USAGE, "format: lookup argument tablenum"); 4548 cmd->opcode = O_IP_DST_LOOKUP; 4549 cmd->len |= F_INSN_SIZE(ipfw_insn) + 2; 4550 i = match_token(rule_options, *av); 4551 for (j = 0; lookup_key[j] >= 0 ; j++) { 4552 if (i == lookup_key[j]) 4553 break; 4554 } 4555 if (lookup_key[j] <= 0) 4556 errx(EX_USAGE, "format: cannot lookup on %s", *av); 4557 __PAST_END(c->d, 1) = j; // i converted to option 4558 av++; 4559 4560 if ((j = pack_table(tstate, *av)) == 0) 4561 errx(EX_DATAERR, "Invalid table name: %s", *av); 4562 4563 cmd->arg1 = j; 4564 av++; 4565 } 4566 break; 4567 case TOK_FLOW: 4568 NEED1("missing table name"); 4569 if (strncmp(*av, "table(", 6) != 0) 4570 errx(EX_DATAERR, 4571 "enclose table name into \"table()\""); 4572 fill_table(cmd, *av, O_IP_FLOW_LOOKUP, tstate); 4573 av++; 4574 break; 4575 4576 default: 4577 errx(EX_USAGE, "unrecognised option [%d] %s\n", i, s); 4578 } 4579 if (F_LEN(cmd) > 0) { /* prepare to advance */ 4580 prev = cmd; 4581 cmd = next_cmd(cmd, &cblen); 4582 } 4583 } 4584 4585 done: 4586 /* 4587 * Now copy stuff into the rule. 4588 * If we have a keep-state option, the first instruction 4589 * must be a PROBE_STATE (which is generated here). 4590 * If we have a LOG option, it was stored as the first command, 4591 * and now must be moved to the top of the action part. 4592 */ 4593 dst = (ipfw_insn *)rule->cmd; 4594 4595 /* 4596 * First thing to write into the command stream is the match probability. 4597 */ 4598 if (match_prob != 1) { /* 1 means always match */ 4599 dst->opcode = O_PROB; 4600 dst->len = 2; 4601 *((int32_t *)(dst+1)) = (int32_t)(match_prob * 0x7fffffff); 4602 dst += dst->len; 4603 } 4604 4605 /* 4606 * generate O_PROBE_STATE if necessary 4607 */ 4608 if (have_state && have_state->opcode != O_CHECK_STATE) { 4609 fill_cmd(dst, O_PROBE_STATE, 0, 0); 4610 dst = next_cmd(dst, &rblen); 4611 } 4612 4613 /* copy all commands but O_LOG, O_KEEP_STATE, O_LIMIT, O_ALTQ, O_TAG */ 4614 for (src = (ipfw_insn *)cmdbuf; src != cmd; src += i) { 4615 i = F_LEN(src); 4616 CHECK_RBUFLEN(i); 4617 4618 switch (src->opcode) { 4619 case O_LOG: 4620 case O_KEEP_STATE: 4621 case O_LIMIT: 4622 case O_ALTQ: 4623 case O_TAG: 4624 break; 4625 default: 4626 bcopy(src, dst, i * sizeof(uint32_t)); 4627 dst += i; 4628 } 4629 } 4630 4631 /* 4632 * put back the have_state command as last opcode 4633 */ 4634 if (have_state && have_state->opcode != O_CHECK_STATE) { 4635 i = F_LEN(have_state); 4636 CHECK_RBUFLEN(i); 4637 bcopy(have_state, dst, i * sizeof(uint32_t)); 4638 dst += i; 4639 } 4640 /* 4641 * start action section 4642 */ 4643 rule->act_ofs = dst - rule->cmd; 4644 4645 /* put back O_LOG, O_ALTQ, O_TAG if necessary */ 4646 if (have_log) { 4647 i = F_LEN(have_log); 4648 CHECK_RBUFLEN(i); 4649 bcopy(have_log, dst, i * sizeof(uint32_t)); 4650 dst += i; 4651 } 4652 if (have_altq) { 4653 i = F_LEN(have_altq); 4654 CHECK_RBUFLEN(i); 4655 bcopy(have_altq, dst, i * sizeof(uint32_t)); 4656 dst += i; 4657 } 4658 if (have_tag) { 4659 i = F_LEN(have_tag); 4660 CHECK_RBUFLEN(i); 4661 bcopy(have_tag, dst, i * sizeof(uint32_t)); 4662 dst += i; 4663 } 4664 4665 /* 4666 * copy all other actions 4667 */ 4668 for (src = (ipfw_insn *)actbuf; src != action; src += i) { 4669 i = F_LEN(src); 4670 CHECK_RBUFLEN(i); 4671 bcopy(src, dst, i * sizeof(uint32_t)); 4672 dst += i; 4673 } 4674 4675 rule->cmd_len = (uint32_t *)dst - (uint32_t *)(rule->cmd); 4676 *rbufsize = (char *)dst - (char *)rule; 4677 } 4678 4679 static int 4680 compare_ntlv(const void *_a, const void *_b) 4681 { 4682 ipfw_obj_ntlv *a, *b; 4683 4684 a = (ipfw_obj_ntlv *)_a; 4685 b = (ipfw_obj_ntlv *)_b; 4686 4687 if (a->set < b->set) 4688 return (-1); 4689 else if (a->set > b->set) 4690 return (1); 4691 4692 if (a->idx < b->idx) 4693 return (-1); 4694 else if (a->idx > b->idx) 4695 return (1); 4696 4697 if (a->head.type < b->head.type) 4698 return (-1); 4699 else if (a->head.type > b->head.type) 4700 return (1); 4701 4702 return (0); 4703 } 4704 4705 /* 4706 * Provide kernel with sorted list of referenced objects 4707 */ 4708 static void 4709 object_sort_ctlv(ipfw_obj_ctlv *ctlv) 4710 { 4711 4712 qsort(ctlv + 1, ctlv->count, ctlv->objsize, compare_ntlv); 4713 } 4714 4715 struct object_kt { 4716 uint16_t uidx; 4717 uint16_t type; 4718 }; 4719 static int 4720 compare_object_kntlv(const void *k, const void *v) 4721 { 4722 ipfw_obj_ntlv *ntlv; 4723 struct object_kt key; 4724 4725 key = *((struct object_kt *)k); 4726 ntlv = (ipfw_obj_ntlv *)v; 4727 4728 if (key.uidx < ntlv->idx) 4729 return (-1); 4730 else if (key.uidx > ntlv->idx) 4731 return (1); 4732 4733 if (key.type < ntlv->head.type) 4734 return (-1); 4735 else if (key.type > ntlv->head.type) 4736 return (1); 4737 4738 return (0); 4739 } 4740 4741 /* 4742 * Finds object name in @ctlv by @idx and @type. 4743 * Uses the following facts: 4744 * 1) All TLVs are the same size 4745 * 2) Kernel implementation provides already sorted list. 4746 * 4747 * Returns table name or NULL. 4748 */ 4749 static char * 4750 object_search_ctlv(ipfw_obj_ctlv *ctlv, uint16_t idx, uint16_t type) 4751 { 4752 ipfw_obj_ntlv *ntlv; 4753 struct object_kt key; 4754 4755 key.uidx = idx; 4756 key.type = type; 4757 4758 ntlv = bsearch(&key, (ctlv + 1), ctlv->count, ctlv->objsize, 4759 compare_object_kntlv); 4760 4761 if (ntlv != 0) 4762 return (ntlv->name); 4763 4764 return (NULL); 4765 } 4766 4767 static char * 4768 table_search_ctlv(ipfw_obj_ctlv *ctlv, uint16_t idx) 4769 { 4770 4771 return (object_search_ctlv(ctlv, idx, IPFW_TLV_TBL_NAME)); 4772 } 4773 4774 /* 4775 * Adds one or more rules to ipfw chain. 4776 * Data layout: 4777 * Request: 4778 * [ 4779 * ip_fw3_opheader 4780 * [ ipfw_obj_ctlv(IPFW_TLV_TBL_LIST) ipfw_obj_ntlv x N ] (optional *1) 4781 * [ ipfw_obj_ctlv(IPFW_TLV_RULE_LIST) [ ip_fw_rule ip_fw_insn ] x N ] (*2) (*3) 4782 * ] 4783 * Reply: 4784 * [ 4785 * ip_fw3_opheader 4786 * [ ipfw_obj_ctlv(IPFW_TLV_TBL_LIST) ipfw_obj_ntlv x N ] (optional) 4787 * [ ipfw_obj_ctlv(IPFW_TLV_RULE_LIST) [ ip_fw_rule ip_fw_insn ] x N ] 4788 * ] 4789 * 4790 * Rules in reply are modified to store their actual ruleset number. 4791 * 4792 * (*1) TLVs inside IPFW_TLV_TBL_LIST needs to be sorted ascending 4793 * accoring to their idx field and there has to be no duplicates. 4794 * (*2) Numbered rules inside IPFW_TLV_RULE_LIST needs to be sorted ascending. 4795 * (*3) Each ip_fw structure needs to be aligned to u64 boundary. 4796 */ 4797 void 4798 ipfw_add(char *av[]) 4799 { 4800 uint32_t rulebuf[1024]; 4801 int rbufsize, default_off, tlen, rlen; 4802 size_t sz; 4803 struct tidx ts; 4804 struct ip_fw_rule *rule; 4805 caddr_t tbuf; 4806 ip_fw3_opheader *op3; 4807 ipfw_obj_ctlv *ctlv, *tstate; 4808 4809 rbufsize = sizeof(rulebuf); 4810 memset(rulebuf, 0, rbufsize); 4811 memset(&ts, 0, sizeof(ts)); 4812 4813 /* Optimize case with no tables */ 4814 default_off = sizeof(ipfw_obj_ctlv) + sizeof(ip_fw3_opheader); 4815 op3 = (ip_fw3_opheader *)rulebuf; 4816 ctlv = (ipfw_obj_ctlv *)(op3 + 1); 4817 rule = (struct ip_fw_rule *)(ctlv + 1); 4818 rbufsize -= default_off; 4819 4820 compile_rule(av, (uint32_t *)rule, &rbufsize, &ts); 4821 /* Align rule size to u64 boundary */ 4822 rlen = roundup2(rbufsize, sizeof(uint64_t)); 4823 4824 tbuf = NULL; 4825 sz = 0; 4826 tstate = NULL; 4827 if (ts.count != 0) { 4828 /* Some tables. We have to alloc more data */ 4829 tlen = ts.count * sizeof(ipfw_obj_ntlv); 4830 sz = default_off + sizeof(ipfw_obj_ctlv) + tlen + rlen; 4831 4832 if ((tbuf = calloc(1, sz)) == NULL) 4833 err(EX_UNAVAILABLE, "malloc() failed for IP_FW_ADD"); 4834 op3 = (ip_fw3_opheader *)tbuf; 4835 /* Tables first */ 4836 ctlv = (ipfw_obj_ctlv *)(op3 + 1); 4837 ctlv->head.type = IPFW_TLV_TBLNAME_LIST; 4838 ctlv->head.length = sizeof(ipfw_obj_ctlv) + tlen; 4839 ctlv->count = ts.count; 4840 ctlv->objsize = sizeof(ipfw_obj_ntlv); 4841 memcpy(ctlv + 1, ts.idx, tlen); 4842 object_sort_ctlv(ctlv); 4843 tstate = ctlv; 4844 /* Rule next */ 4845 ctlv = (ipfw_obj_ctlv *)((caddr_t)ctlv + ctlv->head.length); 4846 ctlv->head.type = IPFW_TLV_RULE_LIST; 4847 ctlv->head.length = sizeof(ipfw_obj_ctlv) + rlen; 4848 ctlv->count = 1; 4849 memcpy(ctlv + 1, rule, rbufsize); 4850 } else { 4851 /* Simply add header */ 4852 sz = rlen + default_off; 4853 memset(ctlv, 0, sizeof(*ctlv)); 4854 ctlv->head.type = IPFW_TLV_RULE_LIST; 4855 ctlv->head.length = sizeof(ipfw_obj_ctlv) + rlen; 4856 ctlv->count = 1; 4857 } 4858 4859 if (do_get3(IP_FW_XADD, op3, &sz) != 0) 4860 err(EX_UNAVAILABLE, "getsockopt(%s)", "IP_FW_XADD"); 4861 4862 if (!co.do_quiet) { 4863 struct format_opts sfo; 4864 struct buf_pr bp; 4865 memset(&sfo, 0, sizeof(sfo)); 4866 sfo.tstate = tstate; 4867 sfo.set_mask = (uint32_t)(-1); 4868 bp_alloc(&bp, 4096); 4869 show_static_rule(&co, &sfo, &bp, rule, NULL); 4870 printf("%s", bp.buf); 4871 bp_free(&bp); 4872 } 4873 4874 if (tbuf != NULL) 4875 free(tbuf); 4876 4877 if (ts.idx != NULL) 4878 free(ts.idx); 4879 } 4880 4881 /* 4882 * clear the counters or the log counters. 4883 * optname has the following values: 4884 * 0 (zero both counters and logging) 4885 * 1 (zero logging only) 4886 */ 4887 void 4888 ipfw_zero(int ac, char *av[], int optname) 4889 { 4890 ipfw_range_tlv rt; 4891 uint32_t arg; 4892 int failed = EX_OK; 4893 char const *errstr; 4894 char const *name = optname ? "RESETLOG" : "ZERO"; 4895 4896 optname = optname ? IP_FW_XRESETLOG : IP_FW_XZERO; 4897 memset(&rt, 0, sizeof(rt)); 4898 4899 av++; ac--; 4900 4901 if (ac == 0) { 4902 /* clear all entries */ 4903 rt.flags = IPFW_RCFLAG_ALL; 4904 if (do_range_cmd(optname, &rt) < 0) 4905 err(EX_UNAVAILABLE, "setsockopt(IP_FW_X%s)", name); 4906 if (!co.do_quiet) 4907 printf("%s.\n", optname == IP_FW_XZERO ? 4908 "Accounting cleared":"Logging counts reset"); 4909 4910 return; 4911 } 4912 4913 while (ac) { 4914 /* Rule number */ 4915 if (isdigit(**av)) { 4916 arg = strtonum(*av, 0, 0xffff, &errstr); 4917 if (errstr) 4918 errx(EX_DATAERR, 4919 "invalid rule number %s\n", *av); 4920 rt.start_rule = arg; 4921 rt.end_rule = arg; 4922 rt.flags |= IPFW_RCFLAG_RANGE; 4923 if (co.use_set != 0) { 4924 rt.set = co.use_set - 1; 4925 rt.flags |= IPFW_RCFLAG_SET; 4926 } 4927 if (do_range_cmd(optname, &rt) != 0) { 4928 warn("rule %u: setsockopt(IP_FW_X%s)", 4929 arg, name); 4930 failed = EX_UNAVAILABLE; 4931 } else if (rt.new_set == 0) { 4932 printf("Entry %d not found\n", arg); 4933 failed = EX_UNAVAILABLE; 4934 } else if (!co.do_quiet) 4935 printf("Entry %d %s.\n", arg, 4936 optname == IP_FW_XZERO ? 4937 "cleared" : "logging count reset"); 4938 } else { 4939 errx(EX_USAGE, "invalid rule number ``%s''", *av); 4940 } 4941 av++; ac--; 4942 } 4943 if (failed != EX_OK) 4944 exit(failed); 4945 } 4946 4947 void 4948 ipfw_flush(int force) 4949 { 4950 ipfw_range_tlv rt; 4951 4952 if (!force && !co.do_quiet) { /* need to ask user */ 4953 int c; 4954 4955 printf("Are you sure? [yn] "); 4956 fflush(stdout); 4957 do { 4958 c = toupper(getc(stdin)); 4959 while (c != '\n' && getc(stdin) != '\n') 4960 if (feof(stdin)) 4961 return; /* and do not flush */ 4962 } while (c != 'Y' && c != 'N'); 4963 printf("\n"); 4964 if (c == 'N') /* user said no */ 4965 return; 4966 } 4967 if (co.do_pipe) { 4968 dummynet_flush(); 4969 return; 4970 } 4971 /* `ipfw set N flush` - is the same that `ipfw delete set N` */ 4972 memset(&rt, 0, sizeof(rt)); 4973 if (co.use_set != 0) { 4974 rt.set = co.use_set - 1; 4975 rt.flags = IPFW_RCFLAG_SET; 4976 } else 4977 rt.flags = IPFW_RCFLAG_ALL; 4978 if (do_range_cmd(IP_FW_XDEL, &rt) != 0) 4979 err(EX_UNAVAILABLE, "setsockopt(IP_FW_XDEL)"); 4980 if (!co.do_quiet) 4981 printf("Flushed all %s.\n", co.do_pipe ? "pipes" : "rules"); 4982 } 4983 4984 static struct _s_x intcmds[] = { 4985 { "talist", TOK_TALIST }, 4986 { "iflist", TOK_IFLIST }, 4987 { "olist", TOK_OLIST }, 4988 { "vlist", TOK_VLIST }, 4989 { NULL, 0 } 4990 }; 4991 4992 static void 4993 ipfw_list_objects(int ac, char *av[]) 4994 { 4995 ipfw_obj_lheader req, *olh; 4996 ipfw_obj_ntlv *ntlv; 4997 size_t sz; 4998 int i; 4999 5000 memset(&req, 0, sizeof(req)); 5001 sz = sizeof(req); 5002 if (do_get3(IP_FW_DUMP_SRVOBJECTS, &req.opheader, &sz) != 0) 5003 if (errno != ENOMEM) 5004 return; 5005 5006 sz = req.size; 5007 if ((olh = calloc(1, sz)) == NULL) 5008 return; 5009 5010 olh->size = sz; 5011 if (do_get3(IP_FW_DUMP_SRVOBJECTS, &olh->opheader, &sz) != 0) { 5012 free(olh); 5013 return; 5014 } 5015 5016 if (olh->count > 0) 5017 printf("Objects list:\n"); 5018 else 5019 printf("There are no objects\n"); 5020 ntlv = (ipfw_obj_ntlv *)(olh + 1); 5021 for (i = 0; i < olh->count; i++) { 5022 printf(" kidx: %4d\ttype: %2d\tname: %s\n", ntlv->idx, 5023 ntlv->head.type, ntlv->name); 5024 ntlv++; 5025 } 5026 free(olh); 5027 } 5028 5029 void 5030 ipfw_internal_handler(int ac, char *av[]) 5031 { 5032 int tcmd; 5033 5034 ac--; av++; 5035 NEED1("internal cmd required"); 5036 5037 if ((tcmd = match_token(intcmds, *av)) == -1) 5038 errx(EX_USAGE, "invalid internal sub-cmd: %s", *av); 5039 5040 switch (tcmd) { 5041 case TOK_IFLIST: 5042 ipfw_list_tifaces(); 5043 break; 5044 case TOK_TALIST: 5045 ipfw_list_ta(ac, av); 5046 break; 5047 case TOK_OLIST: 5048 ipfw_list_objects(ac, av); 5049 break; 5050 case TOK_VLIST: 5051 ipfw_list_values(ac, av); 5052 break; 5053 } 5054 } 5055 5056 static int 5057 ipfw_get_tracked_ifaces(ipfw_obj_lheader **polh) 5058 { 5059 ipfw_obj_lheader req, *olh; 5060 size_t sz; 5061 5062 memset(&req, 0, sizeof(req)); 5063 sz = sizeof(req); 5064 5065 if (do_get3(IP_FW_XIFLIST, &req.opheader, &sz) != 0) { 5066 if (errno != ENOMEM) 5067 return (errno); 5068 } 5069 5070 sz = req.size; 5071 if ((olh = calloc(1, sz)) == NULL) 5072 return (ENOMEM); 5073 5074 olh->size = sz; 5075 if (do_get3(IP_FW_XIFLIST, &olh->opheader, &sz) != 0) { 5076 free(olh); 5077 return (errno); 5078 } 5079 5080 *polh = olh; 5081 return (0); 5082 } 5083 5084 static int 5085 ifinfo_cmp(const void *a, const void *b) 5086 { 5087 ipfw_iface_info *ia, *ib; 5088 5089 ia = (ipfw_iface_info *)a; 5090 ib = (ipfw_iface_info *)b; 5091 5092 return (stringnum_cmp(ia->ifname, ib->ifname)); 5093 } 5094 5095 /* 5096 * Retrieves table list from kernel, 5097 * optionally sorts it and calls requested function for each table. 5098 * Returns 0 on success. 5099 */ 5100 static void 5101 ipfw_list_tifaces() 5102 { 5103 ipfw_obj_lheader *olh; 5104 ipfw_iface_info *info; 5105 int i, error; 5106 5107 if ((error = ipfw_get_tracked_ifaces(&olh)) != 0) 5108 err(EX_OSERR, "Unable to request ipfw tracked interface list"); 5109 5110 5111 qsort(olh + 1, olh->count, olh->objsize, ifinfo_cmp); 5112 5113 info = (ipfw_iface_info *)(olh + 1); 5114 for (i = 0; i < olh->count; i++) { 5115 if (info->flags & IPFW_IFFLAG_RESOLVED) 5116 printf("%s ifindex: %d refcount: %u changes: %u\n", 5117 info->ifname, info->ifindex, info->refcnt, 5118 info->gencnt); 5119 else 5120 printf("%s ifindex: unresolved refcount: %u changes: %u\n", 5121 info->ifname, info->refcnt, info->gencnt); 5122 info = (ipfw_iface_info *)((caddr_t)info + olh->objsize); 5123 } 5124 5125 free(olh); 5126 } 5127 5128 5129 5130 5131