19758b77fSLuigi Rizzo /* 2571f8c1bSLuigi Rizzo * Copyright (c) 2002-2003 Luigi Rizzo 39758b77fSLuigi Rizzo * Copyright (c) 1996 Alex Nash, Paul Traina, Poul-Henning Kamp 49758b77fSLuigi Rizzo * Copyright (c) 1994 Ugen J.S.Antsilevich 59758b77fSLuigi Rizzo * 69758b77fSLuigi Rizzo * Idea and grammar partially left from: 79758b77fSLuigi Rizzo * Copyright (c) 1993 Daniel Boulet 89758b77fSLuigi Rizzo * 99758b77fSLuigi Rizzo * Redistribution and use in source forms, with and without modification, 109758b77fSLuigi Rizzo * are permitted provided that this entire comment appears intact. 119758b77fSLuigi Rizzo * 129758b77fSLuigi Rizzo * Redistribution in binary form may occur without any restrictions. 139758b77fSLuigi Rizzo * Obviously, it would be nice if you gave credit where credit is due 149758b77fSLuigi Rizzo * but requiring it would be too onerous. 159758b77fSLuigi Rizzo * 169758b77fSLuigi Rizzo * This software is provided ``AS IS'' without any warranties of any kind. 179758b77fSLuigi Rizzo * 189758b77fSLuigi Rizzo * NEW command line interface for IP firewall facility 199758b77fSLuigi Rizzo * 209758b77fSLuigi Rizzo * $FreeBSD$ 219758b77fSLuigi Rizzo */ 229758b77fSLuigi Rizzo 239758b77fSLuigi Rizzo #include <sys/param.h> 249758b77fSLuigi Rizzo #include <sys/mbuf.h> 259758b77fSLuigi Rizzo #include <sys/socket.h> 269758b77fSLuigi Rizzo #include <sys/sockio.h> 279758b77fSLuigi Rizzo #include <sys/sysctl.h> 289758b77fSLuigi Rizzo #include <sys/time.h> 299758b77fSLuigi Rizzo #include <sys/wait.h> 30974dfe30SBrian Feldman #include <sys/queue.h> 319758b77fSLuigi Rizzo 329758b77fSLuigi Rizzo #include <ctype.h> 339758b77fSLuigi Rizzo #include <err.h> 349758b77fSLuigi Rizzo #include <errno.h> 359758b77fSLuigi Rizzo #include <grp.h> 369758b77fSLuigi Rizzo #include <limits.h> 379758b77fSLuigi Rizzo #include <netdb.h> 389758b77fSLuigi Rizzo #include <pwd.h> 399758b77fSLuigi Rizzo #include <signal.h> 409758b77fSLuigi Rizzo #include <stdio.h> 419758b77fSLuigi Rizzo #include <stdlib.h> 429758b77fSLuigi Rizzo #include <stdarg.h> 439758b77fSLuigi Rizzo #include <string.h> 4462ff38aeSLuigi Rizzo #include <timeconv.h> /* XXX do we need this ? */ 459758b77fSLuigi Rizzo #include <unistd.h> 469758b77fSLuigi Rizzo #include <sysexits.h> 47974dfe30SBrian Feldman #include <unistd.h> 48974dfe30SBrian Feldman #include <fcntl.h> 499758b77fSLuigi Rizzo 50bd1d3456SMaxim Konovalov #include <net/ethernet.h> 519758b77fSLuigi Rizzo #include <net/if.h> 52ff2f6fe8SPaolo Pisati #include <net/if_dl.h> 53974dfe30SBrian Feldman #include <net/pfvar.h> 548195404bSBrooks Davis #include <net/route.h> /* def. of struct route */ 559758b77fSLuigi Rizzo #include <netinet/in.h> 569758b77fSLuigi Rizzo #include <netinet/in_systm.h> 579758b77fSLuigi Rizzo #include <netinet/ip.h> 589758b77fSLuigi Rizzo #include <netinet/ip_icmp.h> 598195404bSBrooks Davis #include <netinet/icmp6.h> 609758b77fSLuigi Rizzo #include <netinet/ip_fw.h> 619758b77fSLuigi Rizzo #include <netinet/ip_dummynet.h> 629758b77fSLuigi Rizzo #include <netinet/tcp.h> 639758b77fSLuigi Rizzo #include <arpa/inet.h> 64ff2f6fe8SPaolo Pisati #include <alias.h> 659758b77fSLuigi Rizzo 66571f8c1bSLuigi Rizzo int 679758b77fSLuigi Rizzo do_resolv, /* Would try to resolve all */ 689758b77fSLuigi Rizzo do_time, /* Show time stamps */ 699758b77fSLuigi Rizzo do_quiet, /* Be quiet in add and flush */ 709758b77fSLuigi Rizzo do_pipe, /* this cmd refers to a pipe */ 71ff2f6fe8SPaolo Pisati do_nat, /* Nat configuration. */ 729758b77fSLuigi Rizzo do_sort, /* field to sort results (0 = no) */ 739758b77fSLuigi Rizzo do_dynamic, /* display dynamic rules */ 749758b77fSLuigi Rizzo do_expired, /* display expired dynamic rules */ 755a155b40SLuigi Rizzo do_compact, /* show rules in compact mode */ 76cec4ab6aSMaxim Konovalov do_force, /* do not ask for confirmation */ 7743405724SLuigi Rizzo show_sets, /* display rule sets */ 78571f8c1bSLuigi Rizzo test_only, /* only check syntax */ 79ac6cec51SLuigi Rizzo comment_only, /* only print action and comment */ 809758b77fSLuigi Rizzo verbose; 819758b77fSLuigi Rizzo 829758b77fSLuigi Rizzo #define IP_MASK_ALL 0xffffffff 8304f70834SChristian S.J. Peron /* 8404f70834SChristian S.J. Peron * the following macro returns an error message if we run out of 8504f70834SChristian S.J. Peron * arguments. 8604f70834SChristian S.J. Peron */ 8704f70834SChristian S.J. Peron #define NEED1(msg) {if (!ac) errx(EX_USAGE, msg);} 889758b77fSLuigi Rizzo 89254c4725SOleg Bulyzhin #define GET_UINT_ARG(arg, min, max, tok, s_x) do { \ 90254c4725SOleg Bulyzhin if (!ac) \ 91254c4725SOleg Bulyzhin errx(EX_USAGE, "%s: missing argument", match_value(s_x, tok)); \ 92254c4725SOleg Bulyzhin if (_substrcmp(*av, "tablearg") == 0) { \ 93254c4725SOleg Bulyzhin arg = IP_FW_TABLEARG; \ 94254c4725SOleg Bulyzhin break; \ 956a7d5cb6SOleg Bulyzhin } \ 96254c4725SOleg Bulyzhin \ 97254c4725SOleg Bulyzhin { \ 98254c4725SOleg Bulyzhin long val; \ 99254c4725SOleg Bulyzhin char *end; \ 100254c4725SOleg Bulyzhin \ 101254c4725SOleg Bulyzhin val = strtol(*av, &end, 10); \ 102254c4725SOleg Bulyzhin \ 103254c4725SOleg Bulyzhin if (!isdigit(**av) || *end != '\0' || (val == 0 && errno == EINVAL)) \ 104254c4725SOleg Bulyzhin errx(EX_DATAERR, "%s: invalid argument: %s", \ 105254c4725SOleg Bulyzhin match_value(s_x, tok), *av); \ 106254c4725SOleg Bulyzhin \ 107254c4725SOleg Bulyzhin if (errno == ERANGE || val < min || val > max) \ 108254c4725SOleg Bulyzhin errx(EX_DATAERR, "%s: argument is out of range (%u..%u): %s", \ 109254c4725SOleg Bulyzhin match_value(s_x, tok), min, max, *av); \ 110254c4725SOleg Bulyzhin \ 111254c4725SOleg Bulyzhin if (val == IP_FW_TABLEARG) \ 112254c4725SOleg Bulyzhin errx(EX_DATAERR, "%s: illegal argument value: %s", \ 113254c4725SOleg Bulyzhin match_value(s_x, tok), *av); \ 114254c4725SOleg Bulyzhin arg = val; \ 115254c4725SOleg Bulyzhin } \ 116254c4725SOleg Bulyzhin } while (0) 117254c4725SOleg Bulyzhin 118254c4725SOleg Bulyzhin #define PRINT_UINT_ARG(str, arg) do { \ 119254c4725SOleg Bulyzhin if (str != NULL) \ 120254c4725SOleg Bulyzhin printf("%s",str); \ 121254c4725SOleg Bulyzhin if (arg == IP_FW_TABLEARG) \ 122254c4725SOleg Bulyzhin printf("tablearg"); \ 123254c4725SOleg Bulyzhin else \ 124254c4725SOleg Bulyzhin printf("%u", (uint32_t)arg); \ 1256a7d5cb6SOleg Bulyzhin } while (0) 1266a7d5cb6SOleg Bulyzhin 1279758b77fSLuigi Rizzo /* 128571f8c1bSLuigi Rizzo * _s_x is a structure that stores a string <-> token pairs, used in 129571f8c1bSLuigi Rizzo * various places in the parser. Entries are stored in arrays, 130571f8c1bSLuigi Rizzo * with an entry with s=NULL as terminator. 131571f8c1bSLuigi Rizzo * The search routines are match_token() and match_value(). 132571f8c1bSLuigi Rizzo * Often, an element with x=0 contains an error string. 1339758b77fSLuigi Rizzo * 1349758b77fSLuigi Rizzo */ 1359758b77fSLuigi Rizzo struct _s_x { 13662ff38aeSLuigi Rizzo char const *s; 1379758b77fSLuigi Rizzo int x; 1389758b77fSLuigi Rizzo }; 1399758b77fSLuigi Rizzo 1409758b77fSLuigi Rizzo static struct _s_x f_tcpflags[] = { 1419758b77fSLuigi Rizzo { "syn", TH_SYN }, 1429758b77fSLuigi Rizzo { "fin", TH_FIN }, 1439758b77fSLuigi Rizzo { "ack", TH_ACK }, 1449758b77fSLuigi Rizzo { "psh", TH_PUSH }, 1459758b77fSLuigi Rizzo { "rst", TH_RST }, 1469758b77fSLuigi Rizzo { "urg", TH_URG }, 1479758b77fSLuigi Rizzo { "tcp flag", 0 }, 1489758b77fSLuigi Rizzo { NULL, 0 } 1499758b77fSLuigi Rizzo }; 1509758b77fSLuigi Rizzo 1519758b77fSLuigi Rizzo static struct _s_x f_tcpopts[] = { 1529758b77fSLuigi Rizzo { "mss", IP_FW_TCPOPT_MSS }, 1539758b77fSLuigi Rizzo { "maxseg", IP_FW_TCPOPT_MSS }, 1549758b77fSLuigi Rizzo { "window", IP_FW_TCPOPT_WINDOW }, 1559758b77fSLuigi Rizzo { "sack", IP_FW_TCPOPT_SACK }, 1569758b77fSLuigi Rizzo { "ts", IP_FW_TCPOPT_TS }, 1579758b77fSLuigi Rizzo { "timestamp", IP_FW_TCPOPT_TS }, 1589758b77fSLuigi Rizzo { "cc", IP_FW_TCPOPT_CC }, 1599758b77fSLuigi Rizzo { "tcp option", 0 }, 1609758b77fSLuigi Rizzo { NULL, 0 } 1619758b77fSLuigi Rizzo }; 1629758b77fSLuigi Rizzo 1639758b77fSLuigi Rizzo /* 1649758b77fSLuigi Rizzo * IP options span the range 0 to 255 so we need to remap them 1659758b77fSLuigi Rizzo * (though in fact only the low 5 bits are significant). 1669758b77fSLuigi Rizzo */ 1679758b77fSLuigi Rizzo static struct _s_x f_ipopts[] = { 1689758b77fSLuigi Rizzo { "ssrr", IP_FW_IPOPT_SSRR}, 1699758b77fSLuigi Rizzo { "lsrr", IP_FW_IPOPT_LSRR}, 1709758b77fSLuigi Rizzo { "rr", IP_FW_IPOPT_RR}, 1719758b77fSLuigi Rizzo { "ts", IP_FW_IPOPT_TS}, 1729758b77fSLuigi Rizzo { "ip option", 0 }, 1739758b77fSLuigi Rizzo { NULL, 0 } 1749758b77fSLuigi Rizzo }; 1759758b77fSLuigi Rizzo 1769758b77fSLuigi Rizzo static struct _s_x f_iptos[] = { 1779758b77fSLuigi Rizzo { "lowdelay", IPTOS_LOWDELAY}, 1789758b77fSLuigi Rizzo { "throughput", IPTOS_THROUGHPUT}, 1799758b77fSLuigi Rizzo { "reliability", IPTOS_RELIABILITY}, 1809758b77fSLuigi Rizzo { "mincost", IPTOS_MINCOST}, 1819758b77fSLuigi Rizzo { "congestion", IPTOS_CE}, 1829758b77fSLuigi Rizzo { "ecntransport", IPTOS_ECT}, 1839758b77fSLuigi Rizzo { "ip tos option", 0}, 1849758b77fSLuigi Rizzo { NULL, 0 } 1859758b77fSLuigi Rizzo }; 1869758b77fSLuigi Rizzo 1879758b77fSLuigi Rizzo static struct _s_x limit_masks[] = { 1889758b77fSLuigi Rizzo {"all", DYN_SRC_ADDR|DYN_SRC_PORT|DYN_DST_ADDR|DYN_DST_PORT}, 1899758b77fSLuigi Rizzo {"src-addr", DYN_SRC_ADDR}, 1909758b77fSLuigi Rizzo {"src-port", DYN_SRC_PORT}, 1919758b77fSLuigi Rizzo {"dst-addr", DYN_DST_ADDR}, 1929758b77fSLuigi Rizzo {"dst-port", DYN_DST_PORT}, 1939758b77fSLuigi Rizzo {NULL, 0} 1949758b77fSLuigi Rizzo }; 1959758b77fSLuigi Rizzo 1969758b77fSLuigi Rizzo /* 1979758b77fSLuigi Rizzo * we use IPPROTO_ETHERTYPE as a fake protocol id to call the print routines 1989758b77fSLuigi Rizzo * This is only used in this code. 1999758b77fSLuigi Rizzo */ 2009758b77fSLuigi Rizzo #define IPPROTO_ETHERTYPE 0x1000 2019758b77fSLuigi Rizzo static struct _s_x ether_types[] = { 2029758b77fSLuigi Rizzo /* 2039758b77fSLuigi Rizzo * Note, we cannot use "-:&/" in the names because they are field 2049758b77fSLuigi Rizzo * separators in the type specifications. Also, we use s = NULL as 2059758b77fSLuigi Rizzo * end-delimiter, because a type of 0 can be legal. 2069758b77fSLuigi Rizzo */ 2079758b77fSLuigi Rizzo { "ip", 0x0800 }, 2089758b77fSLuigi Rizzo { "ipv4", 0x0800 }, 2099758b77fSLuigi Rizzo { "ipv6", 0x86dd }, 2109758b77fSLuigi Rizzo { "arp", 0x0806 }, 2119758b77fSLuigi Rizzo { "rarp", 0x8035 }, 2129758b77fSLuigi Rizzo { "vlan", 0x8100 }, 2139758b77fSLuigi Rizzo { "loop", 0x9000 }, 2149758b77fSLuigi Rizzo { "trail", 0x1000 }, 2159758b77fSLuigi Rizzo { "at", 0x809b }, 2169758b77fSLuigi Rizzo { "atalk", 0x809b }, 2179758b77fSLuigi Rizzo { "aarp", 0x80f3 }, 2189758b77fSLuigi Rizzo { "pppoe_disc", 0x8863 }, 2199758b77fSLuigi Rizzo { "pppoe_sess", 0x8864 }, 2209758b77fSLuigi Rizzo { "ipx_8022", 0x00E0 }, 2219758b77fSLuigi Rizzo { "ipx_8023", 0x0000 }, 2229758b77fSLuigi Rizzo { "ipx_ii", 0x8137 }, 2239758b77fSLuigi Rizzo { "ipx_snap", 0x8137 }, 2249758b77fSLuigi Rizzo { "ipx", 0x8137 }, 2259758b77fSLuigi Rizzo { "ns", 0x0600 }, 2269758b77fSLuigi Rizzo { NULL, 0 } 2279758b77fSLuigi Rizzo }; 2289758b77fSLuigi Rizzo 2299758b77fSLuigi Rizzo static void show_usage(void); 2309758b77fSLuigi Rizzo 2319758b77fSLuigi Rizzo enum tokens { 2329758b77fSLuigi Rizzo TOK_NULL=0, 2339758b77fSLuigi Rizzo 2349758b77fSLuigi Rizzo TOK_OR, 2359758b77fSLuigi Rizzo TOK_NOT, 2368ed2d749SLuigi Rizzo TOK_STARTBRACE, 2378ed2d749SLuigi Rizzo TOK_ENDBRACE, 2389758b77fSLuigi Rizzo 2399758b77fSLuigi Rizzo TOK_ACCEPT, 2409758b77fSLuigi Rizzo TOK_COUNT, 2419758b77fSLuigi Rizzo TOK_PIPE, 2429758b77fSLuigi Rizzo TOK_QUEUE, 2439758b77fSLuigi Rizzo TOK_DIVERT, 2449758b77fSLuigi Rizzo TOK_TEE, 245670742a1SGleb Smirnoff TOK_NETGRAPH, 246670742a1SGleb Smirnoff TOK_NGTEE, 2479758b77fSLuigi Rizzo TOK_FORWARD, 2489758b77fSLuigi Rizzo TOK_SKIPTO, 2499758b77fSLuigi Rizzo TOK_DENY, 2509758b77fSLuigi Rizzo TOK_REJECT, 2519758b77fSLuigi Rizzo TOK_RESET, 2529758b77fSLuigi Rizzo TOK_UNREACH, 2539758b77fSLuigi Rizzo TOK_CHECKSTATE, 254ff2f6fe8SPaolo Pisati TOK_NAT, 2559758b77fSLuigi Rizzo 256974dfe30SBrian Feldman TOK_ALTQ, 257974dfe30SBrian Feldman TOK_LOG, 2586a7d5cb6SOleg Bulyzhin TOK_TAG, 2596a7d5cb6SOleg Bulyzhin TOK_UNTAG, 260974dfe30SBrian Feldman 2616a7d5cb6SOleg Bulyzhin TOK_TAGGED, 2629758b77fSLuigi Rizzo TOK_UID, 2639758b77fSLuigi Rizzo TOK_GID, 26431c88a30SChristian S.J. Peron TOK_JAIL, 2659758b77fSLuigi Rizzo TOK_IN, 2669758b77fSLuigi Rizzo TOK_LIMIT, 2679758b77fSLuigi Rizzo TOK_KEEPSTATE, 2689758b77fSLuigi Rizzo TOK_LAYER2, 2699758b77fSLuigi Rizzo TOK_OUT, 2706daf7ebdSBrian Feldman TOK_DIVERTED, 2716daf7ebdSBrian Feldman TOK_DIVERTEDLOOPBACK, 2726daf7ebdSBrian Feldman TOK_DIVERTEDOUTPUT, 2739758b77fSLuigi Rizzo TOK_XMIT, 2749758b77fSLuigi Rizzo TOK_RECV, 2759758b77fSLuigi Rizzo TOK_VIA, 2769758b77fSLuigi Rizzo TOK_FRAG, 2779758b77fSLuigi Rizzo TOK_IPOPTS, 2789758b77fSLuigi Rizzo TOK_IPLEN, 2799758b77fSLuigi Rizzo TOK_IPID, 2809758b77fSLuigi Rizzo TOK_IPPRECEDENCE, 2819758b77fSLuigi Rizzo TOK_IPTOS, 2829758b77fSLuigi Rizzo TOK_IPTTL, 2839758b77fSLuigi Rizzo TOK_IPVER, 2849758b77fSLuigi Rizzo TOK_ESTAB, 2859758b77fSLuigi Rizzo TOK_SETUP, 286c99ee9e0SBrian Feldman TOK_TCPDATALEN, 2879758b77fSLuigi Rizzo TOK_TCPFLAGS, 2889758b77fSLuigi Rizzo TOK_TCPOPTS, 2899758b77fSLuigi Rizzo TOK_TCPSEQ, 2909758b77fSLuigi Rizzo TOK_TCPACK, 2919758b77fSLuigi Rizzo TOK_TCPWIN, 2929758b77fSLuigi Rizzo TOK_ICMPTYPES, 293e706181bSLuigi Rizzo TOK_MAC, 294e706181bSLuigi Rizzo TOK_MACTYPE, 295010dabb0SCrist J. Clark TOK_VERREVPATH, 29622b5770bSAndre Oppermann TOK_VERSRCREACH, 2975f9541ecSAndre Oppermann TOK_ANTISPOOF, 298c3e5b9f1SLuigi Rizzo TOK_IPSEC, 29962ff38aeSLuigi Rizzo TOK_COMMENT, 3009758b77fSLuigi Rizzo 3019758b77fSLuigi Rizzo TOK_PLR, 30299e5e645SLuigi Rizzo TOK_NOERROR, 3039758b77fSLuigi Rizzo TOK_BUCKETS, 3049758b77fSLuigi Rizzo TOK_DSTIP, 3059758b77fSLuigi Rizzo TOK_SRCIP, 3069758b77fSLuigi Rizzo TOK_DSTPORT, 3079758b77fSLuigi Rizzo TOK_SRCPORT, 3089758b77fSLuigi Rizzo TOK_ALL, 3099758b77fSLuigi Rizzo TOK_MASK, 3109758b77fSLuigi Rizzo TOK_BW, 3119758b77fSLuigi Rizzo TOK_DELAY, 3129758b77fSLuigi Rizzo TOK_RED, 3139758b77fSLuigi Rizzo TOK_GRED, 3149758b77fSLuigi Rizzo TOK_DROPTAIL, 3159758b77fSLuigi Rizzo TOK_PROTO, 3169758b77fSLuigi Rizzo TOK_WEIGHT, 317ff2f6fe8SPaolo Pisati TOK_IP, 318ff2f6fe8SPaolo Pisati TOK_IF, 319ff2f6fe8SPaolo Pisati TOK_ALOG, 320ff2f6fe8SPaolo Pisati TOK_DENY_INC, 321ff2f6fe8SPaolo Pisati TOK_SAME_PORTS, 322ff2f6fe8SPaolo Pisati TOK_UNREG_ONLY, 323ff2f6fe8SPaolo Pisati TOK_RESET_ADDR, 324ff2f6fe8SPaolo Pisati TOK_ALIAS_REV, 325ff2f6fe8SPaolo Pisati TOK_PROXY_ONLY, 326ff2f6fe8SPaolo Pisati TOK_REDIR_ADDR, 327ff2f6fe8SPaolo Pisati TOK_REDIR_PORT, 328ff2f6fe8SPaolo Pisati TOK_REDIR_PROTO, 3298195404bSBrooks Davis 3308195404bSBrooks Davis TOK_IPV6, 3318195404bSBrooks Davis TOK_FLOWID, 3328195404bSBrooks Davis TOK_ICMP6TYPES, 3338195404bSBrooks Davis TOK_EXT6HDR, 3348195404bSBrooks Davis TOK_DSTIP6, 3358195404bSBrooks Davis TOK_SRCIP6, 33657cd6d26SMax Laier 33757cd6d26SMax Laier TOK_IPV4, 3389066356bSBjoern A. Zeeb TOK_UNREACH6, 3399066356bSBjoern A. Zeeb TOK_RESET6, 3409758b77fSLuigi Rizzo }; 3419758b77fSLuigi Rizzo 3429758b77fSLuigi Rizzo struct _s_x dummynet_params[] = { 3439758b77fSLuigi Rizzo { "plr", TOK_PLR }, 34499e5e645SLuigi Rizzo { "noerror", TOK_NOERROR }, 3459758b77fSLuigi Rizzo { "buckets", TOK_BUCKETS }, 3469758b77fSLuigi Rizzo { "dst-ip", TOK_DSTIP }, 3479758b77fSLuigi Rizzo { "src-ip", TOK_SRCIP }, 3489758b77fSLuigi Rizzo { "dst-port", TOK_DSTPORT }, 3499758b77fSLuigi Rizzo { "src-port", TOK_SRCPORT }, 3509758b77fSLuigi Rizzo { "proto", TOK_PROTO }, 3519758b77fSLuigi Rizzo { "weight", TOK_WEIGHT }, 3529758b77fSLuigi Rizzo { "all", TOK_ALL }, 3539758b77fSLuigi Rizzo { "mask", TOK_MASK }, 3549758b77fSLuigi Rizzo { "droptail", TOK_DROPTAIL }, 3559758b77fSLuigi Rizzo { "red", TOK_RED }, 3569758b77fSLuigi Rizzo { "gred", TOK_GRED }, 3579758b77fSLuigi Rizzo { "bw", TOK_BW }, 3589758b77fSLuigi Rizzo { "bandwidth", TOK_BW }, 3599758b77fSLuigi Rizzo { "delay", TOK_DELAY }, 3605e43aef8SLuigi Rizzo { "pipe", TOK_PIPE }, 3619758b77fSLuigi Rizzo { "queue", TOK_QUEUE }, 3628195404bSBrooks Davis { "flow-id", TOK_FLOWID}, 3638195404bSBrooks Davis { "dst-ipv6", TOK_DSTIP6}, 3648195404bSBrooks Davis { "dst-ip6", TOK_DSTIP6}, 3658195404bSBrooks Davis { "src-ipv6", TOK_SRCIP6}, 3668195404bSBrooks Davis { "src-ip6", TOK_SRCIP6}, 3679758b77fSLuigi Rizzo { "dummynet-params", TOK_NULL }, 368571f8c1bSLuigi Rizzo { NULL, 0 } /* terminator */ 3699758b77fSLuigi Rizzo }; 3709758b77fSLuigi Rizzo 371ff2f6fe8SPaolo Pisati struct _s_x nat_params[] = { 372ff2f6fe8SPaolo Pisati { "ip", TOK_IP }, 373ff2f6fe8SPaolo Pisati { "if", TOK_IF }, 374ff2f6fe8SPaolo Pisati { "log", TOK_ALOG }, 375ff2f6fe8SPaolo Pisati { "deny_in", TOK_DENY_INC }, 376ff2f6fe8SPaolo Pisati { "same_ports", TOK_SAME_PORTS }, 377ff2f6fe8SPaolo Pisati { "unreg_only", TOK_UNREG_ONLY }, 378ff2f6fe8SPaolo Pisati { "reset", TOK_RESET_ADDR }, 379ff2f6fe8SPaolo Pisati { "reverse", TOK_ALIAS_REV }, 380ff2f6fe8SPaolo Pisati { "proxy_only", TOK_PROXY_ONLY }, 381ff2f6fe8SPaolo Pisati { "redirect_addr", TOK_REDIR_ADDR }, 382ff2f6fe8SPaolo Pisati { "redirect_port", TOK_REDIR_PORT }, 383ff2f6fe8SPaolo Pisati { "redirect_proto", TOK_REDIR_PROTO }, 384ff2f6fe8SPaolo Pisati { NULL, 0 } /* terminator */ 385ff2f6fe8SPaolo Pisati }; 386ff2f6fe8SPaolo Pisati 3879758b77fSLuigi Rizzo struct _s_x rule_actions[] = { 3889758b77fSLuigi Rizzo { "accept", TOK_ACCEPT }, 3899758b77fSLuigi Rizzo { "pass", TOK_ACCEPT }, 3909758b77fSLuigi Rizzo { "allow", TOK_ACCEPT }, 3919758b77fSLuigi Rizzo { "permit", TOK_ACCEPT }, 3929758b77fSLuigi Rizzo { "count", TOK_COUNT }, 3939758b77fSLuigi Rizzo { "pipe", TOK_PIPE }, 3949758b77fSLuigi Rizzo { "queue", TOK_QUEUE }, 3959758b77fSLuigi Rizzo { "divert", TOK_DIVERT }, 3969758b77fSLuigi Rizzo { "tee", TOK_TEE }, 397670742a1SGleb Smirnoff { "netgraph", TOK_NETGRAPH }, 398670742a1SGleb Smirnoff { "ngtee", TOK_NGTEE }, 3999758b77fSLuigi Rizzo { "fwd", TOK_FORWARD }, 4009758b77fSLuigi Rizzo { "forward", TOK_FORWARD }, 4019758b77fSLuigi Rizzo { "skipto", TOK_SKIPTO }, 4029758b77fSLuigi Rizzo { "deny", TOK_DENY }, 4039758b77fSLuigi Rizzo { "drop", TOK_DENY }, 4049758b77fSLuigi Rizzo { "reject", TOK_REJECT }, 4059066356bSBjoern A. Zeeb { "reset6", TOK_RESET6 }, 4069758b77fSLuigi Rizzo { "reset", TOK_RESET }, 4079066356bSBjoern A. Zeeb { "unreach6", TOK_UNREACH6 }, 4085e43aef8SLuigi Rizzo { "unreach", TOK_UNREACH }, 4099758b77fSLuigi Rizzo { "check-state", TOK_CHECKSTATE }, 41062ff38aeSLuigi Rizzo { "//", TOK_COMMENT }, 411ff2f6fe8SPaolo Pisati { "nat", TOK_NAT }, 412571f8c1bSLuigi Rizzo { NULL, 0 } /* terminator */ 4139758b77fSLuigi Rizzo }; 4149758b77fSLuigi Rizzo 415974dfe30SBrian Feldman struct _s_x rule_action_params[] = { 416974dfe30SBrian Feldman { "altq", TOK_ALTQ }, 417974dfe30SBrian Feldman { "log", TOK_LOG }, 4186a7d5cb6SOleg Bulyzhin { "tag", TOK_TAG }, 4196a7d5cb6SOleg Bulyzhin { "untag", TOK_UNTAG }, 420974dfe30SBrian Feldman { NULL, 0 } /* terminator */ 421974dfe30SBrian Feldman }; 422974dfe30SBrian Feldman 4239758b77fSLuigi Rizzo struct _s_x rule_options[] = { 4246a7d5cb6SOleg Bulyzhin { "tagged", TOK_TAGGED }, 4259758b77fSLuigi Rizzo { "uid", TOK_UID }, 4269758b77fSLuigi Rizzo { "gid", TOK_GID }, 42731c88a30SChristian S.J. Peron { "jail", TOK_JAIL }, 4289758b77fSLuigi Rizzo { "in", TOK_IN }, 4299758b77fSLuigi Rizzo { "limit", TOK_LIMIT }, 4309758b77fSLuigi Rizzo { "keep-state", TOK_KEEPSTATE }, 4319758b77fSLuigi Rizzo { "bridged", TOK_LAYER2 }, 4329758b77fSLuigi Rizzo { "layer2", TOK_LAYER2 }, 4339758b77fSLuigi Rizzo { "out", TOK_OUT }, 4346daf7ebdSBrian Feldman { "diverted", TOK_DIVERTED }, 4356daf7ebdSBrian Feldman { "diverted-loopback", TOK_DIVERTEDLOOPBACK }, 4366daf7ebdSBrian Feldman { "diverted-output", TOK_DIVERTEDOUTPUT }, 4379758b77fSLuigi Rizzo { "xmit", TOK_XMIT }, 4389758b77fSLuigi Rizzo { "recv", TOK_RECV }, 4399758b77fSLuigi Rizzo { "via", TOK_VIA }, 4409758b77fSLuigi Rizzo { "fragment", TOK_FRAG }, 4419758b77fSLuigi Rizzo { "frag", TOK_FRAG }, 4429758b77fSLuigi Rizzo { "ipoptions", TOK_IPOPTS }, 4439758b77fSLuigi Rizzo { "ipopts", TOK_IPOPTS }, 4449758b77fSLuigi Rizzo { "iplen", TOK_IPLEN }, 4459758b77fSLuigi Rizzo { "ipid", TOK_IPID }, 4469758b77fSLuigi Rizzo { "ipprecedence", TOK_IPPRECEDENCE }, 4479758b77fSLuigi Rizzo { "iptos", TOK_IPTOS }, 4489758b77fSLuigi Rizzo { "ipttl", TOK_IPTTL }, 4499758b77fSLuigi Rizzo { "ipversion", TOK_IPVER }, 4509758b77fSLuigi Rizzo { "ipver", TOK_IPVER }, 4519758b77fSLuigi Rizzo { "estab", TOK_ESTAB }, 4529758b77fSLuigi Rizzo { "established", TOK_ESTAB }, 4539758b77fSLuigi Rizzo { "setup", TOK_SETUP }, 454c99ee9e0SBrian Feldman { "tcpdatalen", TOK_TCPDATALEN }, 4559758b77fSLuigi Rizzo { "tcpflags", TOK_TCPFLAGS }, 4569758b77fSLuigi Rizzo { "tcpflgs", TOK_TCPFLAGS }, 4579758b77fSLuigi Rizzo { "tcpoptions", TOK_TCPOPTS }, 4589758b77fSLuigi Rizzo { "tcpopts", TOK_TCPOPTS }, 4599758b77fSLuigi Rizzo { "tcpseq", TOK_TCPSEQ }, 4609758b77fSLuigi Rizzo { "tcpack", TOK_TCPACK }, 4619758b77fSLuigi Rizzo { "tcpwin", TOK_TCPWIN }, 4620a7197a8SLuigi Rizzo { "icmptype", TOK_ICMPTYPES }, 4639758b77fSLuigi Rizzo { "icmptypes", TOK_ICMPTYPES }, 464e706181bSLuigi Rizzo { "dst-ip", TOK_DSTIP }, 465e706181bSLuigi Rizzo { "src-ip", TOK_SRCIP }, 466e706181bSLuigi Rizzo { "dst-port", TOK_DSTPORT }, 467e706181bSLuigi Rizzo { "src-port", TOK_SRCPORT }, 468e706181bSLuigi Rizzo { "proto", TOK_PROTO }, 469e706181bSLuigi Rizzo { "MAC", TOK_MAC }, 470e706181bSLuigi Rizzo { "mac", TOK_MAC }, 471e706181bSLuigi Rizzo { "mac-type", TOK_MACTYPE }, 472010dabb0SCrist J. Clark { "verrevpath", TOK_VERREVPATH }, 47322b5770bSAndre Oppermann { "versrcreach", TOK_VERSRCREACH }, 4745f9541ecSAndre Oppermann { "antispoof", TOK_ANTISPOOF }, 475c3e5b9f1SLuigi Rizzo { "ipsec", TOK_IPSEC }, 4768195404bSBrooks Davis { "icmp6type", TOK_ICMP6TYPES }, 4778195404bSBrooks Davis { "icmp6types", TOK_ICMP6TYPES }, 4788195404bSBrooks Davis { "ext6hdr", TOK_EXT6HDR}, 4798195404bSBrooks Davis { "flow-id", TOK_FLOWID}, 4808195404bSBrooks Davis { "ipv6", TOK_IPV6}, 4818195404bSBrooks Davis { "ip6", TOK_IPV6}, 48257cd6d26SMax Laier { "ipv4", TOK_IPV4}, 48357cd6d26SMax Laier { "ip4", TOK_IPV4}, 4848195404bSBrooks Davis { "dst-ipv6", TOK_DSTIP6}, 4858195404bSBrooks Davis { "dst-ip6", TOK_DSTIP6}, 4868195404bSBrooks Davis { "src-ipv6", TOK_SRCIP6}, 4878195404bSBrooks Davis { "src-ip6", TOK_SRCIP6}, 48862ff38aeSLuigi Rizzo { "//", TOK_COMMENT }, 4899758b77fSLuigi Rizzo 4909758b77fSLuigi Rizzo { "not", TOK_NOT }, /* pseudo option */ 4919758b77fSLuigi Rizzo { "!", /* escape ? */ TOK_NOT }, /* pseudo option */ 4929758b77fSLuigi Rizzo { "or", TOK_OR }, /* pseudo option */ 4939758b77fSLuigi Rizzo { "|", /* escape */ TOK_OR }, /* pseudo option */ 4948ed2d749SLuigi Rizzo { "{", TOK_STARTBRACE }, /* pseudo option */ 4958ed2d749SLuigi Rizzo { "(", TOK_STARTBRACE }, /* pseudo option */ 4968ed2d749SLuigi Rizzo { "}", TOK_ENDBRACE }, /* pseudo option */ 4978ed2d749SLuigi Rizzo { ")", TOK_ENDBRACE }, /* pseudo option */ 498571f8c1bSLuigi Rizzo { NULL, 0 } /* terminator */ 4999758b77fSLuigi Rizzo }; 5009758b77fSLuigi Rizzo 50140b1ae9eSGleb Smirnoff #define TABLEARG "tablearg" 50240b1ae9eSGleb Smirnoff 503571f8c1bSLuigi Rizzo static __inline uint64_t 504571f8c1bSLuigi Rizzo align_uint64(uint64_t *pll) { 505571f8c1bSLuigi Rizzo uint64_t ret; 506330462a3SBernd Walter 507330462a3SBernd Walter bcopy (pll, &ret, sizeof(ret)); 508330462a3SBernd Walter return ret; 509c85c1d27SStefan Farfeleder } 510330462a3SBernd Walter 511571f8c1bSLuigi Rizzo /* 512571f8c1bSLuigi Rizzo * conditionally runs the command. 513571f8c1bSLuigi Rizzo */ 51462ff38aeSLuigi Rizzo static int 515884be75cSThomas Moestl do_cmd(int optname, void *optval, uintptr_t optlen) 516571f8c1bSLuigi Rizzo { 517571f8c1bSLuigi Rizzo static int s = -1; /* the socket */ 518571f8c1bSLuigi Rizzo int i; 519571f8c1bSLuigi Rizzo 520571f8c1bSLuigi Rizzo if (test_only) 521571f8c1bSLuigi Rizzo return 0; 522571f8c1bSLuigi Rizzo 523571f8c1bSLuigi Rizzo if (s == -1) 524571f8c1bSLuigi Rizzo s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); 525571f8c1bSLuigi Rizzo if (s < 0) 526571f8c1bSLuigi Rizzo err(EX_UNAVAILABLE, "socket"); 527571f8c1bSLuigi Rizzo 528571f8c1bSLuigi Rizzo if (optname == IP_FW_GET || optname == IP_DUMMYNET_GET || 529cd8b5ae0SRuslan Ermilov optname == IP_FW_ADD || optname == IP_FW_TABLE_LIST || 530ff2f6fe8SPaolo Pisati optname == IP_FW_TABLE_GETSIZE || 531ff2f6fe8SPaolo Pisati optname == IP_FW_NAT_GET_CONFIG || 532ff2f6fe8SPaolo Pisati optname == IP_FW_NAT_GET_LOG) 533571f8c1bSLuigi Rizzo i = getsockopt(s, IPPROTO_IP, optname, optval, 534571f8c1bSLuigi Rizzo (socklen_t *)optlen); 535571f8c1bSLuigi Rizzo else 536571f8c1bSLuigi Rizzo i = setsockopt(s, IPPROTO_IP, optname, optval, optlen); 537571f8c1bSLuigi Rizzo return i; 538571f8c1bSLuigi Rizzo } 539571f8c1bSLuigi Rizzo 5409758b77fSLuigi Rizzo /** 5419758b77fSLuigi Rizzo * match_token takes a table and a string, returns the value associated 542571f8c1bSLuigi Rizzo * with the string (-1 in case of failure). 5439758b77fSLuigi Rizzo */ 5449758b77fSLuigi Rizzo static int 5459758b77fSLuigi Rizzo match_token(struct _s_x *table, char *string) 5469758b77fSLuigi Rizzo { 5479758b77fSLuigi Rizzo struct _s_x *pt; 54862ff38aeSLuigi Rizzo uint i = strlen(string); 5499758b77fSLuigi Rizzo 5509758b77fSLuigi Rizzo for (pt = table ; i && pt->s != NULL ; pt++) 5519758b77fSLuigi Rizzo if (strlen(pt->s) == i && !bcmp(string, pt->s, i)) 5529758b77fSLuigi Rizzo return pt->x; 5539758b77fSLuigi Rizzo return -1; 554c85c1d27SStefan Farfeleder } 5559758b77fSLuigi Rizzo 556571f8c1bSLuigi Rizzo /** 557571f8c1bSLuigi Rizzo * match_value takes a table and a value, returns the string associated 558571f8c1bSLuigi Rizzo * with the value (NULL in case of failure). 559571f8c1bSLuigi Rizzo */ 56062ff38aeSLuigi Rizzo static char const * 56162ff38aeSLuigi Rizzo match_value(struct _s_x *p, int value) 5629758b77fSLuigi Rizzo { 5639758b77fSLuigi Rizzo for (; p->s != NULL; p++) 5649758b77fSLuigi Rizzo if (p->x == value) 5659758b77fSLuigi Rizzo return p->s; 5669758b77fSLuigi Rizzo return NULL; 5679758b77fSLuigi Rizzo } 5689758b77fSLuigi Rizzo 5699758b77fSLuigi Rizzo /* 57001750186SBrooks Davis * _substrcmp takes two strings and returns 1 if they do not match, 57101750186SBrooks Davis * and 0 if they match exactly or the first string is a sub-string 57201750186SBrooks Davis * of the second. A warning is printed to stderr in the case that the 57301750186SBrooks Davis * first string is a sub-string of the second. 57401750186SBrooks Davis * 57501750186SBrooks Davis * This function will be removed in the future through the usual 57601750186SBrooks Davis * deprecation process. 57701750186SBrooks Davis */ 57801750186SBrooks Davis static int 57901750186SBrooks Davis _substrcmp(const char *str1, const char* str2) 58001750186SBrooks Davis { 58101750186SBrooks Davis 58201750186SBrooks Davis if (strncmp(str1, str2, strlen(str1)) != 0) 58301750186SBrooks Davis return 1; 58401750186SBrooks Davis 58501750186SBrooks Davis if (strlen(str1) != strlen(str2)) 58601750186SBrooks Davis warnx("DEPRECATED: '%s' matched '%s' as a sub-string", 58701750186SBrooks Davis str1, str2); 58801750186SBrooks Davis return 0; 58901750186SBrooks Davis } 59001750186SBrooks Davis 59101750186SBrooks Davis /* 59201750186SBrooks Davis * _substrcmp2 takes three strings and returns 1 if the first two do not match, 59301750186SBrooks Davis * and 0 if they match exactly or the second string is a sub-string 59401750186SBrooks Davis * of the first. A warning is printed to stderr in the case that the 59501750186SBrooks Davis * first string does not match the third. 59601750186SBrooks Davis * 59701750186SBrooks Davis * This function exists to warn about the bizzare construction 59801750186SBrooks Davis * strncmp(str, "by", 2) which is used to allow people to use a shotcut 59901750186SBrooks Davis * for "bytes". The problem is that in addition to accepting "by", 60001750186SBrooks Davis * "byt", "byte", and "bytes", it also excepts "by_rabid_dogs" and any 60101750186SBrooks Davis * other string beginning with "by". 60201750186SBrooks Davis * 60301750186SBrooks Davis * This function will be removed in the future through the usual 60401750186SBrooks Davis * deprecation process. 60501750186SBrooks Davis */ 60601750186SBrooks Davis static int 60701750186SBrooks Davis _substrcmp2(const char *str1, const char* str2, const char* str3) 60801750186SBrooks Davis { 60901750186SBrooks Davis 61001750186SBrooks Davis if (strncmp(str1, str2, strlen(str2)) != 0) 61101750186SBrooks Davis return 1; 61201750186SBrooks Davis 61301750186SBrooks Davis if (strcmp(str1, str3) != 0) 61401750186SBrooks Davis warnx("DEPRECATED: '%s' matched '%s'", 61501750186SBrooks Davis str1, str3); 61601750186SBrooks Davis return 0; 61701750186SBrooks Davis } 61801750186SBrooks Davis 61901750186SBrooks Davis /* 6209758b77fSLuigi Rizzo * prints one port, symbolic or numeric 6219758b77fSLuigi Rizzo */ 6229758b77fSLuigi Rizzo static void 623571f8c1bSLuigi Rizzo print_port(int proto, uint16_t port) 6249758b77fSLuigi Rizzo { 6259758b77fSLuigi Rizzo 6269758b77fSLuigi Rizzo if (proto == IPPROTO_ETHERTYPE) { 62762ff38aeSLuigi Rizzo char const *s; 6289758b77fSLuigi Rizzo 6299758b77fSLuigi Rizzo if (do_resolv && (s = match_value(ether_types, port)) ) 6309758b77fSLuigi Rizzo printf("%s", s); 6319758b77fSLuigi Rizzo else 6329758b77fSLuigi Rizzo printf("0x%04x", port); 6339758b77fSLuigi Rizzo } else { 6349758b77fSLuigi Rizzo struct servent *se = NULL; 6359758b77fSLuigi Rizzo if (do_resolv) { 6369758b77fSLuigi Rizzo struct protoent *pe = getprotobynumber(proto); 6379758b77fSLuigi Rizzo 6389758b77fSLuigi Rizzo se = getservbyport(htons(port), pe ? pe->p_name : NULL); 6399758b77fSLuigi Rizzo } 6409758b77fSLuigi Rizzo if (se) 6419758b77fSLuigi Rizzo printf("%s", se->s_name); 6429758b77fSLuigi Rizzo else 6439758b77fSLuigi Rizzo printf("%d", port); 6449758b77fSLuigi Rizzo } 6459758b77fSLuigi Rizzo } 6469758b77fSLuigi Rizzo 647571f8c1bSLuigi Rizzo struct _s_x _port_name[] = { 648571f8c1bSLuigi Rizzo {"dst-port", O_IP_DSTPORT}, 649571f8c1bSLuigi Rizzo {"src-port", O_IP_SRCPORT}, 650571f8c1bSLuigi Rizzo {"ipid", O_IPID}, 651571f8c1bSLuigi Rizzo {"iplen", O_IPLEN}, 652571f8c1bSLuigi Rizzo {"ipttl", O_IPTTL}, 653571f8c1bSLuigi Rizzo {"mac-type", O_MAC_TYPE}, 654c99ee9e0SBrian Feldman {"tcpdatalen", O_TCPDATALEN}, 6556a7d5cb6SOleg Bulyzhin {"tagged", O_TAGGED}, 656571f8c1bSLuigi Rizzo {NULL, 0} 657571f8c1bSLuigi Rizzo }; 658571f8c1bSLuigi Rizzo 6599758b77fSLuigi Rizzo /* 660571f8c1bSLuigi Rizzo * Print the values in a list 16-bit items of the types above. 6619758b77fSLuigi Rizzo * XXX todo: add support for mask. 6629758b77fSLuigi Rizzo */ 6639758b77fSLuigi Rizzo static void 664e706181bSLuigi Rizzo print_newports(ipfw_insn_u16 *cmd, int proto, int opcode) 6659758b77fSLuigi Rizzo { 666571f8c1bSLuigi Rizzo uint16_t *p = cmd->ports; 6679758b77fSLuigi Rizzo int i; 66862ff38aeSLuigi Rizzo char const *sep; 6699758b77fSLuigi Rizzo 6709758b77fSLuigi Rizzo if (cmd->o.len & F_NOT) 6719758b77fSLuigi Rizzo printf(" not"); 67244c884e1SLuigi Rizzo if (opcode != 0) { 673571f8c1bSLuigi Rizzo sep = match_value(_port_name, opcode); 674571f8c1bSLuigi Rizzo if (sep == NULL) 67544c884e1SLuigi Rizzo sep = "???"; 67644c884e1SLuigi Rizzo printf (" %s", sep); 67744c884e1SLuigi Rizzo } 67844c884e1SLuigi Rizzo sep = " "; 6799758b77fSLuigi Rizzo for (i = F_LEN((ipfw_insn *)cmd) - 1; i > 0; i--, p += 2) { 6809758b77fSLuigi Rizzo printf(sep); 6819758b77fSLuigi Rizzo print_port(proto, p[0]); 6829758b77fSLuigi Rizzo if (p[0] != p[1]) { 6839758b77fSLuigi Rizzo printf("-"); 6849758b77fSLuigi Rizzo print_port(proto, p[1]); 6859758b77fSLuigi Rizzo } 6869758b77fSLuigi Rizzo sep = ","; 6879758b77fSLuigi Rizzo } 6889758b77fSLuigi Rizzo } 6899758b77fSLuigi Rizzo 6909758b77fSLuigi Rizzo /* 6919758b77fSLuigi Rizzo * Like strtol, but also translates service names into port numbers 6929758b77fSLuigi Rizzo * for some protocols. 6939758b77fSLuigi Rizzo * In particular: 6949758b77fSLuigi Rizzo * proto == -1 disables the protocol check; 6959758b77fSLuigi Rizzo * proto == IPPROTO_ETHERTYPE looks up an internal table 6969758b77fSLuigi Rizzo * proto == <some value in /etc/protocols> matches the values there. 69743405724SLuigi Rizzo * Returns *end == s in case the parameter is not found. 6989758b77fSLuigi Rizzo */ 6999758b77fSLuigi Rizzo static int 7009758b77fSLuigi Rizzo strtoport(char *s, char **end, int base, int proto) 7019758b77fSLuigi Rizzo { 70243405724SLuigi Rizzo char *p, *buf; 70343405724SLuigi Rizzo char *s1; 7049758b77fSLuigi Rizzo int i; 7059758b77fSLuigi Rizzo 70643405724SLuigi Rizzo *end = s; /* default - not found */ 7079758b77fSLuigi Rizzo if (*s == '\0') 70843405724SLuigi Rizzo return 0; /* not found */ 7099758b77fSLuigi Rizzo 7109758b77fSLuigi Rizzo if (isdigit(*s)) 7119758b77fSLuigi Rizzo return strtol(s, end, base); 7129758b77fSLuigi Rizzo 7139758b77fSLuigi Rizzo /* 71443405724SLuigi Rizzo * find separator. '\\' escapes the next char. 7159758b77fSLuigi Rizzo */ 71643405724SLuigi Rizzo for (s1 = s; *s1 && (isalnum(*s1) || *s1 == '\\') ; s1++) 71743405724SLuigi Rizzo if (*s1 == '\\' && s1[1] != '\0') 71843405724SLuigi Rizzo s1++; 71943405724SLuigi Rizzo 72043405724SLuigi Rizzo buf = malloc(s1 - s + 1); 72143405724SLuigi Rizzo if (buf == NULL) 72243405724SLuigi Rizzo return 0; 72343405724SLuigi Rizzo 72443405724SLuigi Rizzo /* 72543405724SLuigi Rizzo * copy into a buffer skipping backslashes 72643405724SLuigi Rizzo */ 72743405724SLuigi Rizzo for (p = s, i = 0; p != s1 ; p++) 72843405724SLuigi Rizzo if (*p != '\\') 72943405724SLuigi Rizzo buf[i++] = *p; 73043405724SLuigi Rizzo buf[i++] = '\0'; 7319758b77fSLuigi Rizzo 7329758b77fSLuigi Rizzo if (proto == IPPROTO_ETHERTYPE) { 73343405724SLuigi Rizzo i = match_token(ether_types, buf); 73443405724SLuigi Rizzo free(buf); 73543405724SLuigi Rizzo if (i != -1) { /* found */ 7369758b77fSLuigi Rizzo *end = s1; 7379758b77fSLuigi Rizzo return i; 7389758b77fSLuigi Rizzo } 7399758b77fSLuigi Rizzo } else { 7409758b77fSLuigi Rizzo struct protoent *pe = NULL; 7419758b77fSLuigi Rizzo struct servent *se; 7429758b77fSLuigi Rizzo 7439758b77fSLuigi Rizzo if (proto != 0) 7449758b77fSLuigi Rizzo pe = getprotobynumber(proto); 7459758b77fSLuigi Rizzo setservent(1); 74643405724SLuigi Rizzo se = getservbyname(buf, pe ? pe->p_name : NULL); 74743405724SLuigi Rizzo free(buf); 7489758b77fSLuigi Rizzo if (se != NULL) { 7499758b77fSLuigi Rizzo *end = s1; 7509758b77fSLuigi Rizzo return ntohs(se->s_port); 7519758b77fSLuigi Rizzo } 7529758b77fSLuigi Rizzo } 75343405724SLuigi Rizzo return 0; /* not found */ 7549758b77fSLuigi Rizzo } 7559758b77fSLuigi Rizzo 7569758b77fSLuigi Rizzo /* 757974dfe30SBrian Feldman * Map between current altq queue id numbers and names. 758974dfe30SBrian Feldman */ 759974dfe30SBrian Feldman static int altq_fetched = 0; 760974dfe30SBrian Feldman static TAILQ_HEAD(, pf_altq) altq_entries = 761974dfe30SBrian Feldman TAILQ_HEAD_INITIALIZER(altq_entries); 762974dfe30SBrian Feldman 763974dfe30SBrian Feldman static void 764974dfe30SBrian Feldman altq_set_enabled(int enabled) 765974dfe30SBrian Feldman { 766974dfe30SBrian Feldman int pffd; 767974dfe30SBrian Feldman 768974dfe30SBrian Feldman pffd = open("/dev/pf", O_RDWR); 769974dfe30SBrian Feldman if (pffd == -1) 770974dfe30SBrian Feldman err(EX_UNAVAILABLE, 771974dfe30SBrian Feldman "altq support opening pf(4) control device"); 772974dfe30SBrian Feldman if (enabled) { 773974dfe30SBrian Feldman if (ioctl(pffd, DIOCSTARTALTQ) != 0 && errno != EEXIST) 774974dfe30SBrian Feldman err(EX_UNAVAILABLE, "enabling altq"); 775974dfe30SBrian Feldman } else { 776974dfe30SBrian Feldman if (ioctl(pffd, DIOCSTOPALTQ) != 0 && errno != ENOENT) 777974dfe30SBrian Feldman err(EX_UNAVAILABLE, "disabling altq"); 778974dfe30SBrian Feldman } 779974dfe30SBrian Feldman close(pffd); 780974dfe30SBrian Feldman } 781974dfe30SBrian Feldman 782974dfe30SBrian Feldman static void 783974dfe30SBrian Feldman altq_fetch() 784974dfe30SBrian Feldman { 785974dfe30SBrian Feldman struct pfioc_altq pfioc; 786974dfe30SBrian Feldman struct pf_altq *altq; 787974dfe30SBrian Feldman int pffd, mnr; 788974dfe30SBrian Feldman 789974dfe30SBrian Feldman if (altq_fetched) 790974dfe30SBrian Feldman return; 791974dfe30SBrian Feldman altq_fetched = 1; 792974dfe30SBrian Feldman pffd = open("/dev/pf", O_RDONLY); 793974dfe30SBrian Feldman if (pffd == -1) { 794974dfe30SBrian Feldman warn("altq support opening pf(4) control device"); 795974dfe30SBrian Feldman return; 796974dfe30SBrian Feldman } 797974dfe30SBrian Feldman bzero(&pfioc, sizeof(pfioc)); 798974dfe30SBrian Feldman if (ioctl(pffd, DIOCGETALTQS, &pfioc) != 0) { 799974dfe30SBrian Feldman warn("altq support getting queue list"); 800974dfe30SBrian Feldman close(pffd); 801974dfe30SBrian Feldman return; 802974dfe30SBrian Feldman } 803974dfe30SBrian Feldman mnr = pfioc.nr; 804974dfe30SBrian Feldman for (pfioc.nr = 0; pfioc.nr < mnr; pfioc.nr++) { 805974dfe30SBrian Feldman if (ioctl(pffd, DIOCGETALTQ, &pfioc) != 0) { 806974dfe30SBrian Feldman if (errno == EBUSY) 807974dfe30SBrian Feldman break; 808974dfe30SBrian Feldman warn("altq support getting queue list"); 809974dfe30SBrian Feldman close(pffd); 810974dfe30SBrian Feldman return; 811974dfe30SBrian Feldman } 812974dfe30SBrian Feldman if (pfioc.altq.qid == 0) 813974dfe30SBrian Feldman continue; 814974dfe30SBrian Feldman altq = malloc(sizeof(*altq)); 815974dfe30SBrian Feldman if (altq == NULL) 816974dfe30SBrian Feldman err(EX_OSERR, "malloc"); 817974dfe30SBrian Feldman *altq = pfioc.altq; 818974dfe30SBrian Feldman TAILQ_INSERT_TAIL(&altq_entries, altq, entries); 819974dfe30SBrian Feldman } 820974dfe30SBrian Feldman close(pffd); 821974dfe30SBrian Feldman } 822974dfe30SBrian Feldman 823974dfe30SBrian Feldman static u_int32_t 824974dfe30SBrian Feldman altq_name_to_qid(const char *name) 825974dfe30SBrian Feldman { 826974dfe30SBrian Feldman struct pf_altq *altq; 827974dfe30SBrian Feldman 828974dfe30SBrian Feldman altq_fetch(); 829974dfe30SBrian Feldman TAILQ_FOREACH(altq, &altq_entries, entries) 830974dfe30SBrian Feldman if (strcmp(name, altq->qname) == 0) 831974dfe30SBrian Feldman break; 832974dfe30SBrian Feldman if (altq == NULL) 833974dfe30SBrian Feldman errx(EX_DATAERR, "altq has no queue named `%s'", name); 834974dfe30SBrian Feldman return altq->qid; 835974dfe30SBrian Feldman } 836974dfe30SBrian Feldman 837974dfe30SBrian Feldman static const char * 838974dfe30SBrian Feldman altq_qid_to_name(u_int32_t qid) 839974dfe30SBrian Feldman { 840974dfe30SBrian Feldman struct pf_altq *altq; 841974dfe30SBrian Feldman 842974dfe30SBrian Feldman altq_fetch(); 843974dfe30SBrian Feldman TAILQ_FOREACH(altq, &altq_entries, entries) 844974dfe30SBrian Feldman if (qid == altq->qid) 845974dfe30SBrian Feldman break; 846974dfe30SBrian Feldman if (altq == NULL) 847974dfe30SBrian Feldman return NULL; 848974dfe30SBrian Feldman return altq->qname; 849974dfe30SBrian Feldman } 850974dfe30SBrian Feldman 851974dfe30SBrian Feldman static void 852974dfe30SBrian Feldman fill_altq_qid(u_int32_t *qid, const char *av) 853974dfe30SBrian Feldman { 854974dfe30SBrian Feldman *qid = altq_name_to_qid(av); 855974dfe30SBrian Feldman } 856974dfe30SBrian Feldman 857974dfe30SBrian Feldman /* 858571f8c1bSLuigi Rizzo * Fill the body of the command with the list of port ranges. 8599758b77fSLuigi Rizzo */ 8609758b77fSLuigi Rizzo static int 8619758b77fSLuigi Rizzo fill_newports(ipfw_insn_u16 *cmd, char *av, int proto) 8629758b77fSLuigi Rizzo { 863571f8c1bSLuigi Rizzo uint16_t a, b, *p = cmd->ports; 8649758b77fSLuigi Rizzo int i = 0; 865e706181bSLuigi Rizzo char *s = av; 8669758b77fSLuigi Rizzo 867e706181bSLuigi Rizzo while (*s) { 8689758b77fSLuigi Rizzo a = strtoport(av, &s, 0, proto); 869254c4725SOleg Bulyzhin if (s == av) /* empty or invalid argument */ 870254c4725SOleg Bulyzhin return (0); 871254c4725SOleg Bulyzhin 872254c4725SOleg Bulyzhin switch (*s) { 873254c4725SOleg Bulyzhin case '-': /* a range */ 8749758b77fSLuigi Rizzo av = s + 1; 8759758b77fSLuigi Rizzo b = strtoport(av, &s, 0, proto); 876254c4725SOleg Bulyzhin /* Reject expressions like '1-abc' or '1-2-3'. */ 877254c4725SOleg Bulyzhin if (s == av || (*s != ',' && *s != '\0')) 878254c4725SOleg Bulyzhin return (0); 8799758b77fSLuigi Rizzo p[0] = a; 8809758b77fSLuigi Rizzo p[1] = b; 881254c4725SOleg Bulyzhin break; 882254c4725SOleg Bulyzhin case ',': /* comma separated list */ 883254c4725SOleg Bulyzhin case '\0': 8849758b77fSLuigi Rizzo p[0] = p[1] = a; 885254c4725SOleg Bulyzhin break; 886254c4725SOleg Bulyzhin default: 887254c4725SOleg Bulyzhin warnx("port list: invalid separator <%c> in <%s>", 88899e5e645SLuigi Rizzo *s, av); 889254c4725SOleg Bulyzhin return (0); 890254c4725SOleg Bulyzhin } 891254c4725SOleg Bulyzhin 892e706181bSLuigi Rizzo i++; 893e706181bSLuigi Rizzo p += 2; 8949758b77fSLuigi Rizzo av = s + 1; 8959758b77fSLuigi Rizzo } 8969758b77fSLuigi Rizzo if (i > 0) { 8979758b77fSLuigi Rizzo if (i + 1 > F_LEN_MASK) 898e706181bSLuigi Rizzo errx(EX_DATAERR, "too many ports/ranges\n"); 8999758b77fSLuigi Rizzo cmd->o.len |= i + 1; /* leave F_NOT and F_OR untouched */ 9009758b77fSLuigi Rizzo } 901254c4725SOleg Bulyzhin return (i); 9029758b77fSLuigi Rizzo } 9039758b77fSLuigi Rizzo 9049758b77fSLuigi Rizzo static struct _s_x icmpcodes[] = { 9059758b77fSLuigi Rizzo { "net", ICMP_UNREACH_NET }, 9069758b77fSLuigi Rizzo { "host", ICMP_UNREACH_HOST }, 9079758b77fSLuigi Rizzo { "protocol", ICMP_UNREACH_PROTOCOL }, 9089758b77fSLuigi Rizzo { "port", ICMP_UNREACH_PORT }, 9099758b77fSLuigi Rizzo { "needfrag", ICMP_UNREACH_NEEDFRAG }, 9109758b77fSLuigi Rizzo { "srcfail", ICMP_UNREACH_SRCFAIL }, 9119758b77fSLuigi Rizzo { "net-unknown", ICMP_UNREACH_NET_UNKNOWN }, 9129758b77fSLuigi Rizzo { "host-unknown", ICMP_UNREACH_HOST_UNKNOWN }, 9139758b77fSLuigi Rizzo { "isolated", ICMP_UNREACH_ISOLATED }, 9149758b77fSLuigi Rizzo { "net-prohib", ICMP_UNREACH_NET_PROHIB }, 9159758b77fSLuigi Rizzo { "host-prohib", ICMP_UNREACH_HOST_PROHIB }, 9169758b77fSLuigi Rizzo { "tosnet", ICMP_UNREACH_TOSNET }, 9179758b77fSLuigi Rizzo { "toshost", ICMP_UNREACH_TOSHOST }, 9189758b77fSLuigi Rizzo { "filter-prohib", ICMP_UNREACH_FILTER_PROHIB }, 9199758b77fSLuigi Rizzo { "host-precedence", ICMP_UNREACH_HOST_PRECEDENCE }, 9209758b77fSLuigi Rizzo { "precedence-cutoff", ICMP_UNREACH_PRECEDENCE_CUTOFF }, 9219758b77fSLuigi Rizzo { NULL, 0 } 9229758b77fSLuigi Rizzo }; 9239758b77fSLuigi Rizzo 9249758b77fSLuigi Rizzo static void 9259758b77fSLuigi Rizzo fill_reject_code(u_short *codep, char *str) 9269758b77fSLuigi Rizzo { 9279758b77fSLuigi Rizzo int val; 9289758b77fSLuigi Rizzo char *s; 9299758b77fSLuigi Rizzo 9309758b77fSLuigi Rizzo val = strtoul(str, &s, 0); 9319758b77fSLuigi Rizzo if (s == str || *s != '\0' || val >= 0x100) 9329758b77fSLuigi Rizzo val = match_token(icmpcodes, str); 933e706181bSLuigi Rizzo if (val < 0) 9349758b77fSLuigi Rizzo errx(EX_DATAERR, "unknown ICMP unreachable code ``%s''", str); 9359758b77fSLuigi Rizzo *codep = val; 9369758b77fSLuigi Rizzo return; 9379758b77fSLuigi Rizzo } 9389758b77fSLuigi Rizzo 9399758b77fSLuigi Rizzo static void 940571f8c1bSLuigi Rizzo print_reject_code(uint16_t code) 9419758b77fSLuigi Rizzo { 94262ff38aeSLuigi Rizzo char const *s = match_value(icmpcodes, code); 9439758b77fSLuigi Rizzo 9449758b77fSLuigi Rizzo if (s != NULL) 9455e43aef8SLuigi Rizzo printf("unreach %s", s); 9469758b77fSLuigi Rizzo else 9475e43aef8SLuigi Rizzo printf("unreach %u", code); 9489758b77fSLuigi Rizzo } 9499758b77fSLuigi Rizzo 9509066356bSBjoern A. Zeeb static struct _s_x icmp6codes[] = { 9519066356bSBjoern A. Zeeb { "no-route", ICMP6_DST_UNREACH_NOROUTE }, 9529066356bSBjoern A. Zeeb { "admin-prohib", ICMP6_DST_UNREACH_ADMIN }, 9539066356bSBjoern A. Zeeb { "address", ICMP6_DST_UNREACH_ADDR }, 9549066356bSBjoern A. Zeeb { "port", ICMP6_DST_UNREACH_NOPORT }, 9559066356bSBjoern A. Zeeb { NULL, 0 } 9569066356bSBjoern A. Zeeb }; 9579066356bSBjoern A. Zeeb 9589066356bSBjoern A. Zeeb static void 9599066356bSBjoern A. Zeeb fill_unreach6_code(u_short *codep, char *str) 9609066356bSBjoern A. Zeeb { 9619066356bSBjoern A. Zeeb int val; 9629066356bSBjoern A. Zeeb char *s; 9639066356bSBjoern A. Zeeb 9649066356bSBjoern A. Zeeb val = strtoul(str, &s, 0); 9659066356bSBjoern A. Zeeb if (s == str || *s != '\0' || val >= 0x100) 9669066356bSBjoern A. Zeeb val = match_token(icmp6codes, str); 9679066356bSBjoern A. Zeeb if (val < 0) 9689066356bSBjoern A. Zeeb errx(EX_DATAERR, "unknown ICMPv6 unreachable code ``%s''", str); 9699066356bSBjoern A. Zeeb *codep = val; 9709066356bSBjoern A. Zeeb return; 9719066356bSBjoern A. Zeeb } 9729066356bSBjoern A. Zeeb 9739066356bSBjoern A. Zeeb static void 9749066356bSBjoern A. Zeeb print_unreach6_code(uint16_t code) 9759066356bSBjoern A. Zeeb { 9769066356bSBjoern A. Zeeb char const *s = match_value(icmp6codes, code); 9779066356bSBjoern A. Zeeb 9789066356bSBjoern A. Zeeb if (s != NULL) 9799066356bSBjoern A. Zeeb printf("unreach6 %s", s); 9809066356bSBjoern A. Zeeb else 9819066356bSBjoern A. Zeeb printf("unreach6 %u", code); 9829066356bSBjoern A. Zeeb } 9839066356bSBjoern A. Zeeb 9849758b77fSLuigi Rizzo /* 9859758b77fSLuigi Rizzo * Returns the number of bits set (from left) in a contiguous bitmask, 9869758b77fSLuigi Rizzo * or -1 if the mask is not contiguous. 9879758b77fSLuigi Rizzo * XXX this needs a proper fix. 9889758b77fSLuigi Rizzo * This effectively works on masks in big-endian (network) format. 9899758b77fSLuigi Rizzo * when compiled on little endian architectures. 9909758b77fSLuigi Rizzo * 9919758b77fSLuigi Rizzo * First bit is bit 7 of the first byte -- note, for MAC addresses, 9929758b77fSLuigi Rizzo * the first bit on the wire is bit 0 of the first byte. 9939758b77fSLuigi Rizzo * len is the max length in bits. 9949758b77fSLuigi Rizzo */ 9959758b77fSLuigi Rizzo static int 996f3a126d3SLuigi Rizzo contigmask(uint8_t *p, int len) 9979758b77fSLuigi Rizzo { 9989758b77fSLuigi Rizzo int i, n; 999f3a126d3SLuigi Rizzo 10009758b77fSLuigi Rizzo for (i=0; i<len ; i++) 10019758b77fSLuigi Rizzo if ( (p[i/8] & (1 << (7 - (i%8)))) == 0) /* first bit unset */ 10029758b77fSLuigi Rizzo break; 10039758b77fSLuigi Rizzo for (n=i+1; n < len; n++) 10049758b77fSLuigi Rizzo if ( (p[n/8] & (1 << (7 - (n%8)))) != 0) 10059758b77fSLuigi Rizzo return -1; /* mask not contiguous */ 10069758b77fSLuigi Rizzo return i; 10079758b77fSLuigi Rizzo } 10089758b77fSLuigi Rizzo 10099758b77fSLuigi Rizzo /* 10109758b77fSLuigi Rizzo * print flags set/clear in the two bitmasks passed as parameters. 10119758b77fSLuigi Rizzo * There is a specialized check for f_tcpflags. 10129758b77fSLuigi Rizzo */ 10139758b77fSLuigi Rizzo static void 101462ff38aeSLuigi Rizzo print_flags(char const *name, ipfw_insn *cmd, struct _s_x *list) 10159758b77fSLuigi Rizzo { 101662ff38aeSLuigi Rizzo char const *comma = ""; 10179758b77fSLuigi Rizzo int i; 1018f3a126d3SLuigi Rizzo uint8_t set = cmd->arg1 & 0xff; 1019f3a126d3SLuigi Rizzo uint8_t clear = (cmd->arg1 >> 8) & 0xff; 10209758b77fSLuigi Rizzo 10219758b77fSLuigi Rizzo if (list == f_tcpflags && set == TH_SYN && clear == TH_ACK) { 10229758b77fSLuigi Rizzo printf(" setup"); 10239758b77fSLuigi Rizzo return; 10249758b77fSLuigi Rizzo } 10259758b77fSLuigi Rizzo 10269758b77fSLuigi Rizzo printf(" %s ", name); 10279758b77fSLuigi Rizzo for (i=0; list[i].x != 0; i++) { 10289758b77fSLuigi Rizzo if (set & list[i].x) { 10299758b77fSLuigi Rizzo set &= ~list[i].x; 10309758b77fSLuigi Rizzo printf("%s%s", comma, list[i].s); 10319758b77fSLuigi Rizzo comma = ","; 10329758b77fSLuigi Rizzo } 10339758b77fSLuigi Rizzo if (clear & list[i].x) { 10349758b77fSLuigi Rizzo clear &= ~list[i].x; 10359758b77fSLuigi Rizzo printf("%s!%s", comma, list[i].s); 10369758b77fSLuigi Rizzo comma = ","; 10379758b77fSLuigi Rizzo } 10389758b77fSLuigi Rizzo } 10399758b77fSLuigi Rizzo } 10409758b77fSLuigi Rizzo 10419758b77fSLuigi Rizzo /* 10429758b77fSLuigi Rizzo * Print the ip address contained in a command. 10439758b77fSLuigi Rizzo */ 10449758b77fSLuigi Rizzo static void 104562ff38aeSLuigi Rizzo print_ip(ipfw_insn_ip *cmd, char const *s) 10469758b77fSLuigi Rizzo { 10479758b77fSLuigi Rizzo struct hostent *he = NULL; 1048571f8c1bSLuigi Rizzo int len = F_LEN((ipfw_insn *)cmd); 1049571f8c1bSLuigi Rizzo uint32_t *a = ((ipfw_insn_u32 *)cmd)->d; 10509758b77fSLuigi Rizzo 1051e706181bSLuigi Rizzo printf("%s%s ", cmd->o.len & F_NOT ? " not": "", s); 10529758b77fSLuigi Rizzo 10539758b77fSLuigi Rizzo if (cmd->o.opcode == O_IP_SRC_ME || cmd->o.opcode == O_IP_DST_ME) { 10549758b77fSLuigi Rizzo printf("me"); 10559758b77fSLuigi Rizzo return; 10569758b77fSLuigi Rizzo } 1057cd8b5ae0SRuslan Ermilov if (cmd->o.opcode == O_IP_SRC_LOOKUP || 1058cd8b5ae0SRuslan Ermilov cmd->o.opcode == O_IP_DST_LOOKUP) { 1059cd8b5ae0SRuslan Ermilov printf("table(%u", ((ipfw_insn *)cmd)->arg1); 1060cd8b5ae0SRuslan Ermilov if (len == F_INSN_SIZE(ipfw_insn_u32)) 1061cd8b5ae0SRuslan Ermilov printf(",%u", *a); 1062cd8b5ae0SRuslan Ermilov printf(")"); 1063cd8b5ae0SRuslan Ermilov return; 1064cd8b5ae0SRuslan Ermilov } 10659758b77fSLuigi Rizzo if (cmd->o.opcode == O_IP_SRC_SET || cmd->o.opcode == O_IP_DST_SET) { 1066571f8c1bSLuigi Rizzo uint32_t x, *map = (uint32_t *)&(cmd->mask); 10679ef3f16dSLuigi Rizzo int i, j; 10689758b77fSLuigi Rizzo char comma = '{'; 10699758b77fSLuigi Rizzo 10709758b77fSLuigi Rizzo x = cmd->o.arg1 - 1; 10719758b77fSLuigi Rizzo x = htonl( ~x ); 10729758b77fSLuigi Rizzo cmd->addr.s_addr = htonl(cmd->addr.s_addr); 10739758b77fSLuigi Rizzo printf("%s/%d", inet_ntoa(cmd->addr), 1074f3a126d3SLuigi Rizzo contigmask((uint8_t *)&x, 32)); 10759758b77fSLuigi Rizzo x = cmd->addr.s_addr = htonl(cmd->addr.s_addr); 10769758b77fSLuigi Rizzo x &= 0xff; /* base */ 10779ef3f16dSLuigi Rizzo /* 10789ef3f16dSLuigi Rizzo * Print bits and ranges. 10799ef3f16dSLuigi Rizzo * Locate first bit set (i), then locate first bit unset (j). 10809ef3f16dSLuigi Rizzo * If we have 3+ consecutive bits set, then print them as a 10819ef3f16dSLuigi Rizzo * range, otherwise only print the initial bit and rescan. 10829ef3f16dSLuigi Rizzo */ 10839758b77fSLuigi Rizzo for (i=0; i < cmd->o.arg1; i++) 1084571f8c1bSLuigi Rizzo if (map[i/32] & (1<<(i & 31))) { 10859ef3f16dSLuigi Rizzo for (j=i+1; j < cmd->o.arg1; j++) 1086571f8c1bSLuigi Rizzo if (!(map[ j/32] & (1<<(j & 31)))) 10879ef3f16dSLuigi Rizzo break; 10889758b77fSLuigi Rizzo printf("%c%d", comma, i+x); 10899ef3f16dSLuigi Rizzo if (j>i+2) { /* range has at least 3 elements */ 10909ef3f16dSLuigi Rizzo printf("-%d", j-1+x); 10919ef3f16dSLuigi Rizzo i = j-1; 10929ef3f16dSLuigi Rizzo } 10939758b77fSLuigi Rizzo comma = ','; 10949758b77fSLuigi Rizzo } 10959758b77fSLuigi Rizzo printf("}"); 10969758b77fSLuigi Rizzo return; 10979758b77fSLuigi Rizzo } 1098571f8c1bSLuigi Rizzo /* 1099571f8c1bSLuigi Rizzo * len == 2 indicates a single IP, whereas lists of 1 or more 1100571f8c1bSLuigi Rizzo * addr/mask pairs have len = (2n+1). We convert len to n so we 1101571f8c1bSLuigi Rizzo * use that to count the number of entries. 1102571f8c1bSLuigi Rizzo */ 1103571f8c1bSLuigi Rizzo for (len = len / 2; len > 0; len--, a += 2) { 1104571f8c1bSLuigi Rizzo int mb = /* mask length */ 1105571f8c1bSLuigi Rizzo (cmd->o.opcode == O_IP_SRC || cmd->o.opcode == O_IP_DST) ? 1106f3a126d3SLuigi Rizzo 32 : contigmask((uint8_t *)&(a[1]), 32); 11079758b77fSLuigi Rizzo if (mb == 32 && do_resolv) 1108571f8c1bSLuigi Rizzo he = gethostbyaddr((char *)&(a[0]), sizeof(u_long), AF_INET); 11099758b77fSLuigi Rizzo if (he != NULL) /* resolved to name */ 11109758b77fSLuigi Rizzo printf("%s", he->h_name); 11119758b77fSLuigi Rizzo else if (mb == 0) /* any */ 11129758b77fSLuigi Rizzo printf("any"); 11139758b77fSLuigi Rizzo else { /* numeric IP followed by some kind of mask */ 1114571f8c1bSLuigi Rizzo printf("%s", inet_ntoa( *((struct in_addr *)&a[0]) ) ); 11159758b77fSLuigi Rizzo if (mb < 0) 1116571f8c1bSLuigi Rizzo printf(":%s", inet_ntoa( *((struct in_addr *)&a[1]) ) ); 11179758b77fSLuigi Rizzo else if (mb < 32) 11189758b77fSLuigi Rizzo printf("/%d", mb); 11199758b77fSLuigi Rizzo } 1120571f8c1bSLuigi Rizzo if (len > 1) 1121571f8c1bSLuigi Rizzo printf(","); 1122571f8c1bSLuigi Rizzo } 11239758b77fSLuigi Rizzo } 11249758b77fSLuigi Rizzo 11259758b77fSLuigi Rizzo /* 11269758b77fSLuigi Rizzo * prints a MAC address/mask pair 11279758b77fSLuigi Rizzo */ 11289758b77fSLuigi Rizzo static void 1129f3a126d3SLuigi Rizzo print_mac(uint8_t *addr, uint8_t *mask) 11309758b77fSLuigi Rizzo { 11319758b77fSLuigi Rizzo int l = contigmask(mask, 48); 11329758b77fSLuigi Rizzo 11339758b77fSLuigi Rizzo if (l == 0) 11349758b77fSLuigi Rizzo printf(" any"); 11359758b77fSLuigi Rizzo else { 11369758b77fSLuigi Rizzo printf(" %02x:%02x:%02x:%02x:%02x:%02x", 11379758b77fSLuigi Rizzo addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); 11389758b77fSLuigi Rizzo if (l == -1) 11399758b77fSLuigi Rizzo printf("&%02x:%02x:%02x:%02x:%02x:%02x", 11409758b77fSLuigi Rizzo mask[0], mask[1], mask[2], 11419758b77fSLuigi Rizzo mask[3], mask[4], mask[5]); 11429758b77fSLuigi Rizzo else if (l < 48) 11439758b77fSLuigi Rizzo printf("/%d", l); 11449758b77fSLuigi Rizzo } 11459758b77fSLuigi Rizzo } 11469758b77fSLuigi Rizzo 11475e43aef8SLuigi Rizzo static void 11485e43aef8SLuigi Rizzo fill_icmptypes(ipfw_insn_u32 *cmd, char *av) 11495e43aef8SLuigi Rizzo { 1150571f8c1bSLuigi Rizzo uint8_t type; 11515e43aef8SLuigi Rizzo 11525e43aef8SLuigi Rizzo cmd->d[0] = 0; 11535e43aef8SLuigi Rizzo while (*av) { 11545e43aef8SLuigi Rizzo if (*av == ',') 11555e43aef8SLuigi Rizzo av++; 11565e43aef8SLuigi Rizzo 11575e43aef8SLuigi Rizzo type = strtoul(av, &av, 0); 11585e43aef8SLuigi Rizzo 11595e43aef8SLuigi Rizzo if (*av != ',' && *av != '\0') 11605e43aef8SLuigi Rizzo errx(EX_DATAERR, "invalid ICMP type"); 11615e43aef8SLuigi Rizzo 11625e43aef8SLuigi Rizzo if (type > 31) 11635e43aef8SLuigi Rizzo errx(EX_DATAERR, "ICMP type out of range"); 11645e43aef8SLuigi Rizzo 11655e43aef8SLuigi Rizzo cmd->d[0] |= 1 << type; 11665e43aef8SLuigi Rizzo } 11675e43aef8SLuigi Rizzo cmd->o.opcode = O_ICMPTYPE; 11685e43aef8SLuigi Rizzo cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32); 11695e43aef8SLuigi Rizzo } 11705e43aef8SLuigi Rizzo 11715e43aef8SLuigi Rizzo static void 11725e43aef8SLuigi Rizzo print_icmptypes(ipfw_insn_u32 *cmd) 11735e43aef8SLuigi Rizzo { 11745e43aef8SLuigi Rizzo int i; 11755e43aef8SLuigi Rizzo char sep= ' '; 11765e43aef8SLuigi Rizzo 11775e43aef8SLuigi Rizzo printf(" icmptypes"); 11785e43aef8SLuigi Rizzo for (i = 0; i < 32; i++) { 11795e43aef8SLuigi Rizzo if ( (cmd->d[0] & (1 << (i))) == 0) 11805e43aef8SLuigi Rizzo continue; 11815e43aef8SLuigi Rizzo printf("%c%d", sep, i); 11825e43aef8SLuigi Rizzo sep = ','; 11835e43aef8SLuigi Rizzo } 11845e43aef8SLuigi Rizzo } 11859758b77fSLuigi Rizzo 11869758b77fSLuigi Rizzo /* 11878195404bSBrooks Davis * Print the ip address contained in a command. 11888195404bSBrooks Davis */ 11898195404bSBrooks Davis static void 11908195404bSBrooks Davis print_ip6(ipfw_insn_ip6 *cmd, char const *s) 11918195404bSBrooks Davis { 11928195404bSBrooks Davis struct hostent *he = NULL; 11938195404bSBrooks Davis int len = F_LEN((ipfw_insn *) cmd) - 1; 11948195404bSBrooks Davis struct in6_addr *a = &(cmd->addr6); 11958195404bSBrooks Davis char trad[255]; 11968195404bSBrooks Davis 11978195404bSBrooks Davis printf("%s%s ", cmd->o.len & F_NOT ? " not": "", s); 11988195404bSBrooks Davis 11998195404bSBrooks Davis if (cmd->o.opcode == O_IP6_SRC_ME || cmd->o.opcode == O_IP6_DST_ME) { 12008195404bSBrooks Davis printf("me6"); 12018195404bSBrooks Davis return; 12028195404bSBrooks Davis } 12038195404bSBrooks Davis if (cmd->o.opcode == O_IP6) { 120436c263ccSHajimu UMEMOTO printf(" ip6"); 12058195404bSBrooks Davis return; 12068195404bSBrooks Davis } 12078195404bSBrooks Davis 12088195404bSBrooks Davis /* 12098195404bSBrooks Davis * len == 4 indicates a single IP, whereas lists of 1 or more 12108195404bSBrooks Davis * addr/mask pairs have len = (2n+1). We convert len to n so we 12118195404bSBrooks Davis * use that to count the number of entries. 12128195404bSBrooks Davis */ 12138195404bSBrooks Davis 12148195404bSBrooks Davis for (len = len / 4; len > 0; len -= 2, a += 2) { 12158195404bSBrooks Davis int mb = /* mask length */ 12168195404bSBrooks Davis (cmd->o.opcode == O_IP6_SRC || cmd->o.opcode == O_IP6_DST) ? 12178195404bSBrooks Davis 128 : contigmask((uint8_t *)&(a[1]), 128); 12188195404bSBrooks Davis 12198195404bSBrooks Davis if (mb == 128 && do_resolv) 12208195404bSBrooks Davis he = gethostbyaddr((char *)a, sizeof(*a), AF_INET6); 12218195404bSBrooks Davis if (he != NULL) /* resolved to name */ 12228195404bSBrooks Davis printf("%s", he->h_name); 12238195404bSBrooks Davis else if (mb == 0) /* any */ 12248195404bSBrooks Davis printf("any"); 12258195404bSBrooks Davis else { /* numeric IP followed by some kind of mask */ 12268195404bSBrooks Davis if (inet_ntop(AF_INET6, a, trad, sizeof( trad ) ) == NULL) 12278195404bSBrooks Davis printf("Error ntop in print_ip6\n"); 12288195404bSBrooks Davis printf("%s", trad ); 12298195404bSBrooks Davis if (mb < 0) /* XXX not really legal... */ 12308195404bSBrooks Davis printf(":%s", 12318195404bSBrooks Davis inet_ntop(AF_INET6, &a[1], trad, sizeof(trad))); 12328195404bSBrooks Davis else if (mb < 128) 12338195404bSBrooks Davis printf("/%d", mb); 12348195404bSBrooks Davis } 12358195404bSBrooks Davis if (len > 2) 12368195404bSBrooks Davis printf(","); 12378195404bSBrooks Davis } 12388195404bSBrooks Davis } 12398195404bSBrooks Davis 12408195404bSBrooks Davis static void 12418195404bSBrooks Davis fill_icmp6types(ipfw_insn_icmp6 *cmd, char *av) 12428195404bSBrooks Davis { 12438195404bSBrooks Davis uint8_t type; 12448195404bSBrooks Davis 1245e7f2ec53SJohn Hay bzero(cmd, sizeof(*cmd)); 12468195404bSBrooks Davis while (*av) { 12478195404bSBrooks Davis if (*av == ',') 12488195404bSBrooks Davis av++; 12498195404bSBrooks Davis type = strtoul(av, &av, 0); 12508195404bSBrooks Davis if (*av != ',' && *av != '\0') 12518195404bSBrooks Davis errx(EX_DATAERR, "invalid ICMP6 type"); 12528195404bSBrooks Davis /* 12538195404bSBrooks Davis * XXX: shouldn't this be 0xFF? I can't see any reason why 12548195404bSBrooks Davis * we shouldn't be able to filter all possiable values 12558195404bSBrooks Davis * regardless of the ability of the rest of the kernel to do 12568195404bSBrooks Davis * anything useful with them. 12578195404bSBrooks Davis */ 12588195404bSBrooks Davis if (type > ICMP6_MAXTYPE) 12598195404bSBrooks Davis errx(EX_DATAERR, "ICMP6 type out of range"); 12608195404bSBrooks Davis cmd->d[type / 32] |= ( 1 << (type % 32)); 12618195404bSBrooks Davis } 12628195404bSBrooks Davis cmd->o.opcode = O_ICMP6TYPE; 12638195404bSBrooks Davis cmd->o.len |= F_INSN_SIZE(ipfw_insn_icmp6); 12648195404bSBrooks Davis } 12658195404bSBrooks Davis 12668195404bSBrooks Davis 12678195404bSBrooks Davis static void 12688195404bSBrooks Davis print_icmp6types(ipfw_insn_u32 *cmd) 12698195404bSBrooks Davis { 12708195404bSBrooks Davis int i, j; 12718195404bSBrooks Davis char sep= ' '; 12728195404bSBrooks Davis 127336c263ccSHajimu UMEMOTO printf(" ip6 icmp6types"); 12748195404bSBrooks Davis for (i = 0; i < 7; i++) 12758195404bSBrooks Davis for (j=0; j < 32; ++j) { 12768195404bSBrooks Davis if ( (cmd->d[i] & (1 << (j))) == 0) 12778195404bSBrooks Davis continue; 12788195404bSBrooks Davis printf("%c%d", sep, (i*32 + j)); 12798195404bSBrooks Davis sep = ','; 12808195404bSBrooks Davis } 12818195404bSBrooks Davis } 12828195404bSBrooks Davis 12838195404bSBrooks Davis static void 12848195404bSBrooks Davis print_flow6id( ipfw_insn_u32 *cmd) 12858195404bSBrooks Davis { 12868195404bSBrooks Davis uint16_t i, limit = cmd->o.arg1; 12878195404bSBrooks Davis char sep = ','; 12888195404bSBrooks Davis 12898195404bSBrooks Davis printf(" flow-id "); 12908195404bSBrooks Davis for( i=0; i < limit; ++i) { 12918195404bSBrooks Davis if (i == limit - 1) 12928195404bSBrooks Davis sep = ' '; 12938195404bSBrooks Davis printf("%d%c", cmd->d[i], sep); 12948195404bSBrooks Davis } 12958195404bSBrooks Davis } 12968195404bSBrooks Davis 12978195404bSBrooks Davis /* structure and define for the extension header in ipv6 */ 12988195404bSBrooks Davis static struct _s_x ext6hdrcodes[] = { 12998195404bSBrooks Davis { "frag", EXT_FRAGMENT }, 13008195404bSBrooks Davis { "hopopt", EXT_HOPOPTS }, 13018195404bSBrooks Davis { "route", EXT_ROUTING }, 13029066356bSBjoern A. Zeeb { "dstopt", EXT_DSTOPTS }, 13038195404bSBrooks Davis { "ah", EXT_AH }, 13048195404bSBrooks Davis { "esp", EXT_ESP }, 13057a92401aSBjoern A. Zeeb { "rthdr0", EXT_RTHDR0 }, 13067a92401aSBjoern A. Zeeb { "rthdr2", EXT_RTHDR2 }, 13078195404bSBrooks Davis { NULL, 0 } 13088195404bSBrooks Davis }; 13098195404bSBrooks Davis 13108195404bSBrooks Davis /* fills command for the extension header filtering */ 13118195404bSBrooks Davis int 13128195404bSBrooks Davis fill_ext6hdr( ipfw_insn *cmd, char *av) 13138195404bSBrooks Davis { 13148195404bSBrooks Davis int tok; 13158195404bSBrooks Davis char *s = av; 13168195404bSBrooks Davis 13178195404bSBrooks Davis cmd->arg1 = 0; 13188195404bSBrooks Davis 13198195404bSBrooks Davis while(s) { 13208195404bSBrooks Davis av = strsep( &s, ",") ; 13218195404bSBrooks Davis tok = match_token(ext6hdrcodes, av); 13228195404bSBrooks Davis switch (tok) { 13238195404bSBrooks Davis case EXT_FRAGMENT: 13248195404bSBrooks Davis cmd->arg1 |= EXT_FRAGMENT; 13258195404bSBrooks Davis break; 13268195404bSBrooks Davis 13278195404bSBrooks Davis case EXT_HOPOPTS: 13288195404bSBrooks Davis cmd->arg1 |= EXT_HOPOPTS; 13298195404bSBrooks Davis break; 13308195404bSBrooks Davis 13318195404bSBrooks Davis case EXT_ROUTING: 13328195404bSBrooks Davis cmd->arg1 |= EXT_ROUTING; 13338195404bSBrooks Davis break; 13348195404bSBrooks Davis 13359066356bSBjoern A. Zeeb case EXT_DSTOPTS: 13369066356bSBjoern A. Zeeb cmd->arg1 |= EXT_DSTOPTS; 13379066356bSBjoern A. Zeeb break; 13389066356bSBjoern A. Zeeb 13398195404bSBrooks Davis case EXT_AH: 13408195404bSBrooks Davis cmd->arg1 |= EXT_AH; 13418195404bSBrooks Davis break; 13428195404bSBrooks Davis 13438195404bSBrooks Davis case EXT_ESP: 13448195404bSBrooks Davis cmd->arg1 |= EXT_ESP; 13458195404bSBrooks Davis break; 13468195404bSBrooks Davis 13477a92401aSBjoern A. Zeeb case EXT_RTHDR0: 13487a92401aSBjoern A. Zeeb cmd->arg1 |= EXT_RTHDR0; 13497a92401aSBjoern A. Zeeb break; 13507a92401aSBjoern A. Zeeb 13517a92401aSBjoern A. Zeeb case EXT_RTHDR2: 13527a92401aSBjoern A. Zeeb cmd->arg1 |= EXT_RTHDR2; 13537a92401aSBjoern A. Zeeb break; 13547a92401aSBjoern A. Zeeb 13558195404bSBrooks Davis default: 13568195404bSBrooks Davis errx( EX_DATAERR, "invalid option for ipv6 exten header" ); 13578195404bSBrooks Davis break; 13588195404bSBrooks Davis } 13598195404bSBrooks Davis } 13608195404bSBrooks Davis if (cmd->arg1 == 0 ) 13618195404bSBrooks Davis return 0; 13628195404bSBrooks Davis cmd->opcode = O_EXT_HDR; 13638195404bSBrooks Davis cmd->len |= F_INSN_SIZE( ipfw_insn ); 13648195404bSBrooks Davis return 1; 13658195404bSBrooks Davis } 13668195404bSBrooks Davis 13678195404bSBrooks Davis void 13688195404bSBrooks Davis print_ext6hdr( ipfw_insn *cmd ) 13698195404bSBrooks Davis { 13708195404bSBrooks Davis char sep = ' '; 13718195404bSBrooks Davis 13728195404bSBrooks Davis printf(" extension header:"); 13738195404bSBrooks Davis if (cmd->arg1 & EXT_FRAGMENT ) { 13748195404bSBrooks Davis printf("%cfragmentation", sep); 13758195404bSBrooks Davis sep = ','; 13768195404bSBrooks Davis } 13778195404bSBrooks Davis if (cmd->arg1 & EXT_HOPOPTS ) { 13788195404bSBrooks Davis printf("%chop options", sep); 13798195404bSBrooks Davis sep = ','; 13808195404bSBrooks Davis } 13818195404bSBrooks Davis if (cmd->arg1 & EXT_ROUTING ) { 13828195404bSBrooks Davis printf("%crouting options", sep); 13838195404bSBrooks Davis sep = ','; 13848195404bSBrooks Davis } 13857a92401aSBjoern A. Zeeb if (cmd->arg1 & EXT_RTHDR0 ) { 13867a92401aSBjoern A. Zeeb printf("%crthdr0", sep); 13877a92401aSBjoern A. Zeeb sep = ','; 13887a92401aSBjoern A. Zeeb } 13897a92401aSBjoern A. Zeeb if (cmd->arg1 & EXT_RTHDR2 ) { 13907a92401aSBjoern A. Zeeb printf("%crthdr2", sep); 13917a92401aSBjoern A. Zeeb sep = ','; 13927a92401aSBjoern A. Zeeb } 13939066356bSBjoern A. Zeeb if (cmd->arg1 & EXT_DSTOPTS ) { 13949066356bSBjoern A. Zeeb printf("%cdestination options", sep); 13959066356bSBjoern A. Zeeb sep = ','; 13969066356bSBjoern A. Zeeb } 13978195404bSBrooks Davis if (cmd->arg1 & EXT_AH ) { 13988195404bSBrooks Davis printf("%cauthentication header", sep); 13998195404bSBrooks Davis sep = ','; 14008195404bSBrooks Davis } 14018195404bSBrooks Davis if (cmd->arg1 & EXT_ESP ) { 14028195404bSBrooks Davis printf("%cencapsulated security payload", sep); 14038195404bSBrooks Davis } 14048195404bSBrooks Davis } 14058195404bSBrooks Davis 14068195404bSBrooks Davis /* 14079758b77fSLuigi Rizzo * show_ipfw() prints the body of an ipfw rule. 14089758b77fSLuigi Rizzo * Because the standard rule has at least proto src_ip dst_ip, we use 14099758b77fSLuigi Rizzo * a helper function to produce these entries if not provided explicitly. 1410e706181bSLuigi Rizzo * The first argument is the list of fields we have, the second is 1411e706181bSLuigi Rizzo * the list of fields we want to be printed. 141299e5e645SLuigi Rizzo * 1413e706181bSLuigi Rizzo * Special cases if we have provided a MAC header: 1414e706181bSLuigi Rizzo * + if the rule does not contain IP addresses/ports, do not print them; 1415e706181bSLuigi Rizzo * + if the rule does not contain an IP proto, print "all" instead of "ip"; 1416e706181bSLuigi Rizzo * 1417e706181bSLuigi Rizzo * Once we have 'have_options', IP header fields are printed as options. 14189758b77fSLuigi Rizzo */ 141999e5e645SLuigi Rizzo #define HAVE_PROTO 0x0001 142099e5e645SLuigi Rizzo #define HAVE_SRCIP 0x0002 142199e5e645SLuigi Rizzo #define HAVE_DSTIP 0x0004 14225b41efddSMaxim Konovalov #define HAVE_PROTO4 0x0008 14235b41efddSMaxim Konovalov #define HAVE_PROTO6 0x0010 1424e706181bSLuigi Rizzo #define HAVE_OPTIONS 0x8000 14259758b77fSLuigi Rizzo 142699e5e645SLuigi Rizzo #define HAVE_IP (HAVE_PROTO | HAVE_SRCIP | HAVE_DSTIP) 14279758b77fSLuigi Rizzo static void 1428e706181bSLuigi Rizzo show_prerequisites(int *flags, int want, int cmd) 14299758b77fSLuigi Rizzo { 1430ac6cec51SLuigi Rizzo if (comment_only) 1431ac6cec51SLuigi Rizzo return; 1432e706181bSLuigi Rizzo if ( (*flags & HAVE_IP) == HAVE_IP) 1433e706181bSLuigi Rizzo *flags |= HAVE_OPTIONS; 143499e5e645SLuigi Rizzo 1435e706181bSLuigi Rizzo if ( !(*flags & HAVE_OPTIONS)) { 14369758b77fSLuigi Rizzo if ( !(*flags & HAVE_PROTO) && (want & HAVE_PROTO)) 143757cd6d26SMax Laier if ( (*flags & HAVE_PROTO4)) 143857cd6d26SMax Laier printf(" ip4"); 143957cd6d26SMax Laier else if ( (*flags & HAVE_PROTO6)) 144057cd6d26SMax Laier printf(" ip6"); 144157cd6d26SMax Laier else 1442e706181bSLuigi Rizzo printf(" ip"); 144357cd6d26SMax Laier 14449758b77fSLuigi Rizzo if ( !(*flags & HAVE_SRCIP) && (want & HAVE_SRCIP)) 14459758b77fSLuigi Rizzo printf(" from any"); 14469758b77fSLuigi Rizzo if ( !(*flags & HAVE_DSTIP) && (want & HAVE_DSTIP)) 14479758b77fSLuigi Rizzo printf(" to any"); 1448e706181bSLuigi Rizzo } 14499758b77fSLuigi Rizzo *flags |= want; 14509758b77fSLuigi Rizzo } 14519758b77fSLuigi Rizzo 14529758b77fSLuigi Rizzo static void 145345f61351SMaxim Konovalov show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth) 14549758b77fSLuigi Rizzo { 14553d2209aeSGiorgos Keramidas static int twidth = 0; 14569758b77fSLuigi Rizzo int l; 14576a7d5cb6SOleg Bulyzhin ipfw_insn *cmd, *tagptr = NULL; 1458bbc39c83SLuigi Rizzo char *comment = NULL; /* ptr to comment if we have one */ 14599758b77fSLuigi Rizzo int proto = 0; /* default */ 14609758b77fSLuigi Rizzo int flags = 0; /* prerequisites */ 14619758b77fSLuigi Rizzo ipfw_insn_log *logptr = NULL; /* set if we find an O_LOG */ 1462974dfe30SBrian Feldman ipfw_insn_altq *altqptr = NULL; /* set if we find an O_ALTQ */ 14639758b77fSLuigi Rizzo int or_block = 0; /* we are in an or block */ 1464571f8c1bSLuigi Rizzo uint32_t set_disable; 14659758b77fSLuigi Rizzo 1466330462a3SBernd Walter bcopy(&rule->next_rule, &set_disable, sizeof(set_disable)); 146743405724SLuigi Rizzo 146843405724SLuigi Rizzo if (set_disable & (1 << rule->set)) { /* disabled */ 146943405724SLuigi Rizzo if (!show_sets) 147043405724SLuigi Rizzo return; 147143405724SLuigi Rizzo else 147243405724SLuigi Rizzo printf("# DISABLED "); 147343405724SLuigi Rizzo } 14749758b77fSLuigi Rizzo printf("%05u ", rule->rulenum); 14759758b77fSLuigi Rizzo 147662ff38aeSLuigi Rizzo if (pcwidth>0 || bcwidth>0) 1477330462a3SBernd Walter printf("%*llu %*llu ", pcwidth, align_uint64(&rule->pcnt), 1478330462a3SBernd Walter bcwidth, align_uint64(&rule->bcnt)); 14799758b77fSLuigi Rizzo 14801b43a426SLuigi Rizzo if (do_time == 2) 14811b43a426SLuigi Rizzo printf("%10u ", rule->timestamp); 14821b43a426SLuigi Rizzo else if (do_time == 1) { 14839758b77fSLuigi Rizzo char timestr[30]; 14843d2209aeSGiorgos Keramidas time_t t = (time_t)0; 14853d2209aeSGiorgos Keramidas 14863d2209aeSGiorgos Keramidas if (twidth == 0) { 14873d2209aeSGiorgos Keramidas strcpy(timestr, ctime(&t)); 14883d2209aeSGiorgos Keramidas *strchr(timestr, '\n') = '\0'; 14893d2209aeSGiorgos Keramidas twidth = strlen(timestr); 14903d2209aeSGiorgos Keramidas } 14913d2209aeSGiorgos Keramidas if (rule->timestamp) { 14923d2209aeSGiorgos Keramidas t = _long_to_time(rule->timestamp); 14939758b77fSLuigi Rizzo 14949758b77fSLuigi Rizzo strcpy(timestr, ctime(&t)); 14959758b77fSLuigi Rizzo *strchr(timestr, '\n') = '\0'; 14969758b77fSLuigi Rizzo printf("%s ", timestr); 14979758b77fSLuigi Rizzo } else { 14983d2209aeSGiorgos Keramidas printf("%*s", twidth, " "); 14999758b77fSLuigi Rizzo } 15009758b77fSLuigi Rizzo } 15019758b77fSLuigi Rizzo 150243405724SLuigi Rizzo if (show_sets) 150343405724SLuigi Rizzo printf("set %d ", rule->set); 150443405724SLuigi Rizzo 15059758b77fSLuigi Rizzo /* 150612b5dc6aSLuigi Rizzo * print the optional "match probability" 150712b5dc6aSLuigi Rizzo */ 150812b5dc6aSLuigi Rizzo if (rule->cmd_len > 0) { 150912b5dc6aSLuigi Rizzo cmd = rule->cmd ; 151012b5dc6aSLuigi Rizzo if (cmd->opcode == O_PROB) { 151112b5dc6aSLuigi Rizzo ipfw_insn_u32 *p = (ipfw_insn_u32 *)cmd; 151212b5dc6aSLuigi Rizzo double d = 1.0 * p->d[0]; 151312b5dc6aSLuigi Rizzo 151412b5dc6aSLuigi Rizzo d = (d / 0x7fffffff); 151512b5dc6aSLuigi Rizzo printf("prob %f ", d); 151612b5dc6aSLuigi Rizzo } 151712b5dc6aSLuigi Rizzo } 151812b5dc6aSLuigi Rizzo 151912b5dc6aSLuigi Rizzo /* 15209758b77fSLuigi Rizzo * first print actions 15219758b77fSLuigi Rizzo */ 15229758b77fSLuigi Rizzo for (l = rule->cmd_len - rule->act_ofs, cmd = ACTION_PTR(rule); 15239758b77fSLuigi Rizzo l > 0 ; l -= F_LEN(cmd), cmd += F_LEN(cmd)) { 15249758b77fSLuigi Rizzo switch(cmd->opcode) { 15259758b77fSLuigi Rizzo case O_CHECK_STATE: 15269758b77fSLuigi Rizzo printf("check-state"); 1527e706181bSLuigi Rizzo flags = HAVE_IP; /* avoid printing anything else */ 15289758b77fSLuigi Rizzo break; 15299758b77fSLuigi Rizzo 15309758b77fSLuigi Rizzo case O_ACCEPT: 15319758b77fSLuigi Rizzo printf("allow"); 15329758b77fSLuigi Rizzo break; 15339758b77fSLuigi Rizzo 15349758b77fSLuigi Rizzo case O_COUNT: 15359758b77fSLuigi Rizzo printf("count"); 15369758b77fSLuigi Rizzo break; 15379758b77fSLuigi Rizzo 15389758b77fSLuigi Rizzo case O_DENY: 15399758b77fSLuigi Rizzo printf("deny"); 15409758b77fSLuigi Rizzo break; 15419758b77fSLuigi Rizzo 15425e43aef8SLuigi Rizzo case O_REJECT: 15435e43aef8SLuigi Rizzo if (cmd->arg1 == ICMP_REJECT_RST) 15445e43aef8SLuigi Rizzo printf("reset"); 15455e43aef8SLuigi Rizzo else if (cmd->arg1 == ICMP_UNREACH_HOST) 15465e43aef8SLuigi Rizzo printf("reject"); 15475e43aef8SLuigi Rizzo else 15485e43aef8SLuigi Rizzo print_reject_code(cmd->arg1); 15495e43aef8SLuigi Rizzo break; 15505e43aef8SLuigi Rizzo 15519066356bSBjoern A. Zeeb case O_UNREACH6: 15529066356bSBjoern A. Zeeb if (cmd->arg1 == ICMP6_UNREACH_RST) 15539066356bSBjoern A. Zeeb printf("reset6"); 15549066356bSBjoern A. Zeeb else 15559066356bSBjoern A. Zeeb print_unreach6_code(cmd->arg1); 15569066356bSBjoern A. Zeeb break; 15579066356bSBjoern A. Zeeb 1558254c4725SOleg Bulyzhin case O_SKIPTO: 1559254c4725SOleg Bulyzhin PRINT_UINT_ARG("skipto ", cmd->arg1); 156040b1ae9eSGleb Smirnoff break; 156140b1ae9eSGleb Smirnoff 15629758b77fSLuigi Rizzo case O_PIPE: 1563254c4725SOleg Bulyzhin PRINT_UINT_ARG("pipe ", cmd->arg1); 1564254c4725SOleg Bulyzhin break; 1565254c4725SOleg Bulyzhin 15669758b77fSLuigi Rizzo case O_QUEUE: 1567254c4725SOleg Bulyzhin PRINT_UINT_ARG("queue ", cmd->arg1); 1568254c4725SOleg Bulyzhin break; 1569254c4725SOleg Bulyzhin 15709758b77fSLuigi Rizzo case O_DIVERT: 1571254c4725SOleg Bulyzhin PRINT_UINT_ARG("divert ", cmd->arg1); 1572254c4725SOleg Bulyzhin break; 1573254c4725SOleg Bulyzhin 15749758b77fSLuigi Rizzo case O_TEE: 1575254c4725SOleg Bulyzhin PRINT_UINT_ARG("tee ", cmd->arg1); 1576254c4725SOleg Bulyzhin break; 1577254c4725SOleg Bulyzhin 1578670742a1SGleb Smirnoff case O_NETGRAPH: 1579254c4725SOleg Bulyzhin PRINT_UINT_ARG("netgraph ", cmd->arg1); 1580254c4725SOleg Bulyzhin break; 1581254c4725SOleg Bulyzhin 1582670742a1SGleb Smirnoff case O_NGTEE: 1583254c4725SOleg Bulyzhin PRINT_UINT_ARG("ngtee ", cmd->arg1); 1584254c4725SOleg Bulyzhin break; 1585670742a1SGleb Smirnoff 15869758b77fSLuigi Rizzo case O_FORWARD_IP: 15879758b77fSLuigi Rizzo { 15889758b77fSLuigi Rizzo ipfw_insn_sa *s = (ipfw_insn_sa *)cmd; 15899758b77fSLuigi Rizzo 1590c487be96SJulian Elischer if (s->sa.sin_addr.s_addr == INADDR_ANY) { 1591c487be96SJulian Elischer printf("fwd tablearg"); 1592c487be96SJulian Elischer } else { 15939758b77fSLuigi Rizzo printf("fwd %s", inet_ntoa(s->sa.sin_addr)); 1594c487be96SJulian Elischer } 15959758b77fSLuigi Rizzo if (s->sa.sin_port) 15964f531a53SLuigi Rizzo printf(",%d", s->sa.sin_port); 15979758b77fSLuigi Rizzo } 15989758b77fSLuigi Rizzo break; 15999758b77fSLuigi Rizzo 16009758b77fSLuigi Rizzo case O_LOG: /* O_LOG is printed last */ 16019758b77fSLuigi Rizzo logptr = (ipfw_insn_log *)cmd; 16029758b77fSLuigi Rizzo break; 16039758b77fSLuigi Rizzo 1604974dfe30SBrian Feldman case O_ALTQ: /* O_ALTQ is printed after O_LOG */ 1605974dfe30SBrian Feldman altqptr = (ipfw_insn_altq *)cmd; 1606974dfe30SBrian Feldman break; 1607974dfe30SBrian Feldman 16086a7d5cb6SOleg Bulyzhin case O_TAG: 16096a7d5cb6SOleg Bulyzhin tagptr = cmd; 16106a7d5cb6SOleg Bulyzhin break; 16116a7d5cb6SOleg Bulyzhin 1612ff2f6fe8SPaolo Pisati case O_NAT: 1613ff2f6fe8SPaolo Pisati printf("nat %u", cmd->arg1); 1614ff2f6fe8SPaolo Pisati break; 1615ff2f6fe8SPaolo Pisati 16169758b77fSLuigi Rizzo default: 16179758b77fSLuigi Rizzo printf("** unrecognized action %d len %d ", 16189758b77fSLuigi Rizzo cmd->opcode, cmd->len); 16199758b77fSLuigi Rizzo } 16209758b77fSLuigi Rizzo } 16219758b77fSLuigi Rizzo if (logptr) { 16229758b77fSLuigi Rizzo if (logptr->max_log > 0) 16239758b77fSLuigi Rizzo printf(" log logamount %d", logptr->max_log); 16249758b77fSLuigi Rizzo else 16259758b77fSLuigi Rizzo printf(" log"); 16269758b77fSLuigi Rizzo } 1627974dfe30SBrian Feldman if (altqptr) { 1628974dfe30SBrian Feldman const char *qname; 1629974dfe30SBrian Feldman 1630974dfe30SBrian Feldman qname = altq_qid_to_name(altqptr->qid); 1631974dfe30SBrian Feldman if (qname == NULL) 1632974dfe30SBrian Feldman printf(" altq ?<%u>", altqptr->qid); 1633974dfe30SBrian Feldman else 1634974dfe30SBrian Feldman printf(" altq %s", qname); 1635974dfe30SBrian Feldman } 16366a7d5cb6SOleg Bulyzhin if (tagptr) { 16376a7d5cb6SOleg Bulyzhin if (tagptr->len & F_NOT) 1638254c4725SOleg Bulyzhin PRINT_UINT_ARG(" untag ", tagptr->arg1); 16396a7d5cb6SOleg Bulyzhin else 1640254c4725SOleg Bulyzhin PRINT_UINT_ARG(" tag ", tagptr->arg1); 16416a7d5cb6SOleg Bulyzhin } 1642e706181bSLuigi Rizzo 16439758b77fSLuigi Rizzo /* 1644e706181bSLuigi Rizzo * then print the body. 16459758b77fSLuigi Rizzo */ 164657cd6d26SMax Laier for (l = rule->act_ofs, cmd = rule->cmd ; 164757cd6d26SMax Laier l > 0 ; l -= F_LEN(cmd) , cmd += F_LEN(cmd)) { 164857cd6d26SMax Laier if ((cmd->len & F_OR) || (cmd->len & F_NOT)) 164957cd6d26SMax Laier continue; 165057cd6d26SMax Laier if (cmd->opcode == O_IP4) { 165157cd6d26SMax Laier flags |= HAVE_PROTO4; 165257cd6d26SMax Laier break; 165357cd6d26SMax Laier } else if (cmd->opcode == O_IP6) { 165457cd6d26SMax Laier flags |= HAVE_PROTO6; 165557cd6d26SMax Laier break; 165657cd6d26SMax Laier } 165757cd6d26SMax Laier } 1658e706181bSLuigi Rizzo if (rule->_pad & 1) { /* empty rules before options */ 165957cd6d26SMax Laier if (!do_compact) { 166057cd6d26SMax Laier show_prerequisites(&flags, HAVE_PROTO, 0); 166157cd6d26SMax Laier printf(" from any to any"); 166257cd6d26SMax Laier } 1663e706181bSLuigi Rizzo flags |= HAVE_IP | HAVE_OPTIONS; 1664e706181bSLuigi Rizzo } 1665e706181bSLuigi Rizzo 1666ac6cec51SLuigi Rizzo if (comment_only) 1667ac6cec51SLuigi Rizzo comment = "..."; 1668ac6cec51SLuigi Rizzo 16699758b77fSLuigi Rizzo for (l = rule->act_ofs, cmd = rule->cmd ; 16709758b77fSLuigi Rizzo l > 0 ; l -= F_LEN(cmd) , cmd += F_LEN(cmd)) { 16715e43aef8SLuigi Rizzo /* useful alias */ 16725e43aef8SLuigi Rizzo ipfw_insn_u32 *cmd32 = (ipfw_insn_u32 *)cmd; 16739758b77fSLuigi Rizzo 1674ac6cec51SLuigi Rizzo if (comment_only) { 1675ac6cec51SLuigi Rizzo if (cmd->opcode != O_NOP) 1676ac6cec51SLuigi Rizzo continue; 1677ac6cec51SLuigi Rizzo printf(" // %s\n", (char *)(cmd + 1)); 1678ac6cec51SLuigi Rizzo return; 1679ac6cec51SLuigi Rizzo } 1680ac6cec51SLuigi Rizzo 1681e706181bSLuigi Rizzo show_prerequisites(&flags, 0, cmd->opcode); 1682e706181bSLuigi Rizzo 16839758b77fSLuigi Rizzo switch(cmd->opcode) { 168412b5dc6aSLuigi Rizzo case O_PROB: 168512b5dc6aSLuigi Rizzo break; /* done already */ 168612b5dc6aSLuigi Rizzo 16879758b77fSLuigi Rizzo case O_PROBE_STATE: 16889758b77fSLuigi Rizzo break; /* no need to print anything here */ 16899758b77fSLuigi Rizzo 16909758b77fSLuigi Rizzo case O_IP_SRC: 1691cd8b5ae0SRuslan Ermilov case O_IP_SRC_LOOKUP: 16929758b77fSLuigi Rizzo case O_IP_SRC_MASK: 16939758b77fSLuigi Rizzo case O_IP_SRC_ME: 16949758b77fSLuigi Rizzo case O_IP_SRC_SET: 1695e706181bSLuigi Rizzo show_prerequisites(&flags, HAVE_PROTO, 0); 16969758b77fSLuigi Rizzo if (!(flags & HAVE_SRCIP)) 16979758b77fSLuigi Rizzo printf(" from"); 16989758b77fSLuigi Rizzo if ((cmd->len & F_OR) && !or_block) 16999758b77fSLuigi Rizzo printf(" {"); 1700e706181bSLuigi Rizzo print_ip((ipfw_insn_ip *)cmd, 1701e706181bSLuigi Rizzo (flags & HAVE_OPTIONS) ? " src-ip" : ""); 17029758b77fSLuigi Rizzo flags |= HAVE_SRCIP; 17039758b77fSLuigi Rizzo break; 17049758b77fSLuigi Rizzo 17059758b77fSLuigi Rizzo case O_IP_DST: 1706cd8b5ae0SRuslan Ermilov case O_IP_DST_LOOKUP: 17079758b77fSLuigi Rizzo case O_IP_DST_MASK: 17089758b77fSLuigi Rizzo case O_IP_DST_ME: 17099758b77fSLuigi Rizzo case O_IP_DST_SET: 1710e706181bSLuigi Rizzo show_prerequisites(&flags, HAVE_PROTO|HAVE_SRCIP, 0); 17119758b77fSLuigi Rizzo if (!(flags & HAVE_DSTIP)) 17129758b77fSLuigi Rizzo printf(" to"); 17139758b77fSLuigi Rizzo if ((cmd->len & F_OR) && !or_block) 17149758b77fSLuigi Rizzo printf(" {"); 1715e706181bSLuigi Rizzo print_ip((ipfw_insn_ip *)cmd, 1716e706181bSLuigi Rizzo (flags & HAVE_OPTIONS) ? " dst-ip" : ""); 17179758b77fSLuigi Rizzo flags |= HAVE_DSTIP; 17189758b77fSLuigi Rizzo break; 17199758b77fSLuigi Rizzo 17208195404bSBrooks Davis case O_IP6_SRC: 17218195404bSBrooks Davis case O_IP6_SRC_MASK: 17228195404bSBrooks Davis case O_IP6_SRC_ME: 1723b730879fSMax Laier show_prerequisites(&flags, HAVE_PROTO, 0); 17248195404bSBrooks Davis if (!(flags & HAVE_SRCIP)) 17258195404bSBrooks Davis printf(" from"); 17268195404bSBrooks Davis if ((cmd->len & F_OR) && !or_block) 17278195404bSBrooks Davis printf(" {"); 17288195404bSBrooks Davis print_ip6((ipfw_insn_ip6 *)cmd, 17298195404bSBrooks Davis (flags & HAVE_OPTIONS) ? " src-ip6" : ""); 17308195404bSBrooks Davis flags |= HAVE_SRCIP | HAVE_PROTO; 17318195404bSBrooks Davis break; 17328195404bSBrooks Davis 17338195404bSBrooks Davis case O_IP6_DST: 17348195404bSBrooks Davis case O_IP6_DST_MASK: 17358195404bSBrooks Davis case O_IP6_DST_ME: 17368195404bSBrooks Davis show_prerequisites(&flags, HAVE_PROTO|HAVE_SRCIP, 0); 17378195404bSBrooks Davis if (!(flags & HAVE_DSTIP)) 17388195404bSBrooks Davis printf(" to"); 17398195404bSBrooks Davis if ((cmd->len & F_OR) && !or_block) 17408195404bSBrooks Davis printf(" {"); 17418195404bSBrooks Davis print_ip6((ipfw_insn_ip6 *)cmd, 17428195404bSBrooks Davis (flags & HAVE_OPTIONS) ? " dst-ip6" : ""); 17438195404bSBrooks Davis flags |= HAVE_DSTIP; 17448195404bSBrooks Davis break; 17458195404bSBrooks Davis 17468195404bSBrooks Davis case O_FLOW6ID: 17478195404bSBrooks Davis print_flow6id( (ipfw_insn_u32 *) cmd ); 17488195404bSBrooks Davis flags |= HAVE_OPTIONS; 17498195404bSBrooks Davis break; 17508195404bSBrooks Davis 17519758b77fSLuigi Rizzo case O_IP_DSTPORT: 1752e706181bSLuigi Rizzo show_prerequisites(&flags, HAVE_IP, 0); 17539758b77fSLuigi Rizzo case O_IP_SRCPORT: 1754e706181bSLuigi Rizzo show_prerequisites(&flags, HAVE_PROTO|HAVE_SRCIP, 0); 17558ed2d749SLuigi Rizzo if ((cmd->len & F_OR) && !or_block) 17568ed2d749SLuigi Rizzo printf(" {"); 1757e706181bSLuigi Rizzo print_newports((ipfw_insn_u16 *)cmd, proto, 1758e706181bSLuigi Rizzo (flags & HAVE_OPTIONS) ? cmd->opcode : 0); 17599758b77fSLuigi Rizzo break; 17609758b77fSLuigi Rizzo 17619758b77fSLuigi Rizzo case O_PROTO: { 17628195404bSBrooks Davis struct protoent *pe = NULL; 17639758b77fSLuigi Rizzo 17649758b77fSLuigi Rizzo if ((cmd->len & F_OR) && !or_block) 17659758b77fSLuigi Rizzo printf(" {"); 17669758b77fSLuigi Rizzo if (cmd->len & F_NOT) 17679758b77fSLuigi Rizzo printf(" not"); 17689758b77fSLuigi Rizzo proto = cmd->arg1; 1769d360073bSBrooks Davis pe = getprotobynumber(cmd->arg1); 177057cd6d26SMax Laier if ((flags & (HAVE_PROTO4 | HAVE_PROTO6)) && 177157cd6d26SMax Laier !(flags & HAVE_PROTO)) 177257cd6d26SMax Laier show_prerequisites(&flags, 177357cd6d26SMax Laier HAVE_IP | HAVE_OPTIONS, 0); 1774e706181bSLuigi Rizzo if (flags & HAVE_OPTIONS) 1775e706181bSLuigi Rizzo printf(" proto"); 17769758b77fSLuigi Rizzo if (pe) 17779758b77fSLuigi Rizzo printf(" %s", pe->p_name); 17789758b77fSLuigi Rizzo else 17799758b77fSLuigi Rizzo printf(" %u", cmd->arg1); 17809758b77fSLuigi Rizzo } 17819758b77fSLuigi Rizzo flags |= HAVE_PROTO; 17829758b77fSLuigi Rizzo break; 17839758b77fSLuigi Rizzo 17849758b77fSLuigi Rizzo default: /*options ... */ 178557cd6d26SMax Laier if (!(cmd->len & (F_OR|F_NOT))) 178657cd6d26SMax Laier if (((cmd->opcode == O_IP6) && 178757cd6d26SMax Laier (flags & HAVE_PROTO6)) || 178857cd6d26SMax Laier ((cmd->opcode == O_IP4) && 178957cd6d26SMax Laier (flags & HAVE_PROTO4))) 179057cd6d26SMax Laier break; 1791e706181bSLuigi Rizzo show_prerequisites(&flags, HAVE_IP | HAVE_OPTIONS, 0); 17929758b77fSLuigi Rizzo if ((cmd->len & F_OR) && !or_block) 17939758b77fSLuigi Rizzo printf(" {"); 17949758b77fSLuigi Rizzo if (cmd->len & F_NOT && cmd->opcode != O_IN) 17959758b77fSLuigi Rizzo printf(" not"); 17969758b77fSLuigi Rizzo switch(cmd->opcode) { 17975b41efddSMaxim Konovalov case O_MACADDR2: { 17985b41efddSMaxim Konovalov ipfw_insn_mac *m = (ipfw_insn_mac *)cmd; 17995b41efddSMaxim Konovalov 18005b41efddSMaxim Konovalov printf(" MAC"); 18015b41efddSMaxim Konovalov print_mac(m->addr, m->mask); 18025b41efddSMaxim Konovalov print_mac(m->addr + 6, m->mask + 6); 18035b41efddSMaxim Konovalov } 18045b41efddSMaxim Konovalov break; 18055b41efddSMaxim Konovalov 18065b41efddSMaxim Konovalov case O_MAC_TYPE: 18075b41efddSMaxim Konovalov print_newports((ipfw_insn_u16 *)cmd, 18085b41efddSMaxim Konovalov IPPROTO_ETHERTYPE, cmd->opcode); 18095b41efddSMaxim Konovalov break; 18105b41efddSMaxim Konovalov 18115b41efddSMaxim Konovalov 18129758b77fSLuigi Rizzo case O_FRAG: 18139758b77fSLuigi Rizzo printf(" frag"); 18149758b77fSLuigi Rizzo break; 18159758b77fSLuigi Rizzo 18169758b77fSLuigi Rizzo case O_IN: 18179758b77fSLuigi Rizzo printf(cmd->len & F_NOT ? " out" : " in"); 18189758b77fSLuigi Rizzo break; 18199758b77fSLuigi Rizzo 18206daf7ebdSBrian Feldman case O_DIVERTED: 18216daf7ebdSBrian Feldman switch (cmd->arg1) { 18226daf7ebdSBrian Feldman case 3: 18236daf7ebdSBrian Feldman printf(" diverted"); 18246daf7ebdSBrian Feldman break; 18256daf7ebdSBrian Feldman case 1: 18266daf7ebdSBrian Feldman printf(" diverted-loopback"); 18276daf7ebdSBrian Feldman break; 18286daf7ebdSBrian Feldman case 2: 18296daf7ebdSBrian Feldman printf(" diverted-output"); 18306daf7ebdSBrian Feldman break; 18316daf7ebdSBrian Feldman default: 18326daf7ebdSBrian Feldman printf(" diverted-?<%u>", cmd->arg1); 18336daf7ebdSBrian Feldman break; 18346daf7ebdSBrian Feldman } 18356daf7ebdSBrian Feldman break; 18366daf7ebdSBrian Feldman 18379758b77fSLuigi Rizzo case O_LAYER2: 18389758b77fSLuigi Rizzo printf(" layer2"); 18399758b77fSLuigi Rizzo break; 18409758b77fSLuigi Rizzo case O_XMIT: 18419758b77fSLuigi Rizzo case O_RECV: 1842bd528823SGleb Smirnoff case O_VIA: 1843bd528823SGleb Smirnoff { 184462ff38aeSLuigi Rizzo char const *s; 18459758b77fSLuigi Rizzo ipfw_insn_if *cmdif = (ipfw_insn_if *)cmd; 18469758b77fSLuigi Rizzo 18479758b77fSLuigi Rizzo if (cmd->opcode == O_XMIT) 18489758b77fSLuigi Rizzo s = "xmit"; 18499758b77fSLuigi Rizzo else if (cmd->opcode == O_RECV) 18509758b77fSLuigi Rizzo s = "recv"; 185162ff38aeSLuigi Rizzo else /* if (cmd->opcode == O_VIA) */ 18529758b77fSLuigi Rizzo s = "via"; 18539758b77fSLuigi Rizzo if (cmdif->name[0] == '\0') 18545e43aef8SLuigi Rizzo printf(" %s %s", s, 18555e43aef8SLuigi Rizzo inet_ntoa(cmdif->p.ip)); 1856bd528823SGleb Smirnoff else 18579bf40edeSBrooks Davis printf(" %s %s", s, cmdif->name); 18589758b77fSLuigi Rizzo 1859bd528823SGleb Smirnoff break; 1860bd528823SGleb Smirnoff } 18619758b77fSLuigi Rizzo case O_IPID: 186244c884e1SLuigi Rizzo if (F_LEN(cmd) == 1) 18639758b77fSLuigi Rizzo printf(" ipid %u", cmd->arg1 ); 186444c884e1SLuigi Rizzo else 186544c884e1SLuigi Rizzo print_newports((ipfw_insn_u16 *)cmd, 0, 186644c884e1SLuigi Rizzo O_IPID); 18679758b77fSLuigi Rizzo break; 18689758b77fSLuigi Rizzo 18699758b77fSLuigi Rizzo case O_IPTTL: 187044c884e1SLuigi Rizzo if (F_LEN(cmd) == 1) 18719758b77fSLuigi Rizzo printf(" ipttl %u", cmd->arg1 ); 187244c884e1SLuigi Rizzo else 187344c884e1SLuigi Rizzo print_newports((ipfw_insn_u16 *)cmd, 0, 187444c884e1SLuigi Rizzo O_IPTTL); 18759758b77fSLuigi Rizzo break; 18769758b77fSLuigi Rizzo 18779758b77fSLuigi Rizzo case O_IPVER: 18789758b77fSLuigi Rizzo printf(" ipver %u", cmd->arg1 ); 18799758b77fSLuigi Rizzo break; 18809758b77fSLuigi Rizzo 18815e43aef8SLuigi Rizzo case O_IPPRECEDENCE: 18825e43aef8SLuigi Rizzo printf(" ipprecedence %u", (cmd->arg1) >> 5 ); 18835e43aef8SLuigi Rizzo break; 18845e43aef8SLuigi Rizzo 18859758b77fSLuigi Rizzo case O_IPLEN: 188644c884e1SLuigi Rizzo if (F_LEN(cmd) == 1) 18879758b77fSLuigi Rizzo printf(" iplen %u", cmd->arg1 ); 188844c884e1SLuigi Rizzo else 188944c884e1SLuigi Rizzo print_newports((ipfw_insn_u16 *)cmd, 0, 189044c884e1SLuigi Rizzo O_IPLEN); 18919758b77fSLuigi Rizzo break; 18929758b77fSLuigi Rizzo 189352bc23abSLuigi Rizzo case O_IPOPT: 18949758b77fSLuigi Rizzo print_flags("ipoptions", cmd, f_ipopts); 18959758b77fSLuigi Rizzo break; 18969758b77fSLuigi Rizzo 18975e43aef8SLuigi Rizzo case O_IPTOS: 18985e43aef8SLuigi Rizzo print_flags("iptos", cmd, f_iptos); 18995e43aef8SLuigi Rizzo break; 19005e43aef8SLuigi Rizzo 19015e43aef8SLuigi Rizzo case O_ICMPTYPE: 19025e43aef8SLuigi Rizzo print_icmptypes((ipfw_insn_u32 *)cmd); 19035e43aef8SLuigi Rizzo break; 19045e43aef8SLuigi Rizzo 19059758b77fSLuigi Rizzo case O_ESTAB: 19069758b77fSLuigi Rizzo printf(" established"); 19079758b77fSLuigi Rizzo break; 19089758b77fSLuigi Rizzo 1909c99ee9e0SBrian Feldman case O_TCPDATALEN: 1910c99ee9e0SBrian Feldman if (F_LEN(cmd) == 1) 1911c99ee9e0SBrian Feldman printf(" tcpdatalen %u", cmd->arg1 ); 1912c99ee9e0SBrian Feldman else 1913c99ee9e0SBrian Feldman print_newports((ipfw_insn_u16 *)cmd, 0, 1914c99ee9e0SBrian Feldman O_TCPDATALEN); 1915c99ee9e0SBrian Feldman break; 1916c99ee9e0SBrian Feldman 19179758b77fSLuigi Rizzo case O_TCPFLAGS: 19189758b77fSLuigi Rizzo print_flags("tcpflags", cmd, f_tcpflags); 19199758b77fSLuigi Rizzo break; 19209758b77fSLuigi Rizzo 19219758b77fSLuigi Rizzo case O_TCPOPTS: 19229758b77fSLuigi Rizzo print_flags("tcpoptions", cmd, f_tcpopts); 19239758b77fSLuigi Rizzo break; 19249758b77fSLuigi Rizzo 19259758b77fSLuigi Rizzo case O_TCPWIN: 19269758b77fSLuigi Rizzo printf(" tcpwin %d", ntohs(cmd->arg1)); 19279758b77fSLuigi Rizzo break; 19289758b77fSLuigi Rizzo 19299758b77fSLuigi Rizzo case O_TCPACK: 19309758b77fSLuigi Rizzo printf(" tcpack %d", ntohl(cmd32->d[0])); 19319758b77fSLuigi Rizzo break; 19329758b77fSLuigi Rizzo 19339758b77fSLuigi Rizzo case O_TCPSEQ: 19349758b77fSLuigi Rizzo printf(" tcpseq %d", ntohl(cmd32->d[0])); 19359758b77fSLuigi Rizzo break; 19369758b77fSLuigi Rizzo 19379758b77fSLuigi Rizzo case O_UID: 19389758b77fSLuigi Rizzo { 19399758b77fSLuigi Rizzo struct passwd *pwd = getpwuid(cmd32->d[0]); 19409758b77fSLuigi Rizzo 19419758b77fSLuigi Rizzo if (pwd) 19429758b77fSLuigi Rizzo printf(" uid %s", pwd->pw_name); 19439758b77fSLuigi Rizzo else 19449758b77fSLuigi Rizzo printf(" uid %u", cmd32->d[0]); 19459758b77fSLuigi Rizzo } 19469758b77fSLuigi Rizzo break; 19479758b77fSLuigi Rizzo 19489758b77fSLuigi Rizzo case O_GID: 19499758b77fSLuigi Rizzo { 19509758b77fSLuigi Rizzo struct group *grp = getgrgid(cmd32->d[0]); 19519758b77fSLuigi Rizzo 19529758b77fSLuigi Rizzo if (grp) 19539758b77fSLuigi Rizzo printf(" gid %s", grp->gr_name); 19549758b77fSLuigi Rizzo else 19559758b77fSLuigi Rizzo printf(" gid %u", cmd32->d[0]); 19569758b77fSLuigi Rizzo } 19579758b77fSLuigi Rizzo break; 19589758b77fSLuigi Rizzo 195931c88a30SChristian S.J. Peron case O_JAIL: 196031c88a30SChristian S.J. Peron printf(" jail %d", cmd32->d[0]); 196131c88a30SChristian S.J. Peron break; 196231c88a30SChristian S.J. Peron 1963010dabb0SCrist J. Clark case O_VERREVPATH: 1964010dabb0SCrist J. Clark printf(" verrevpath"); 1965010dabb0SCrist J. Clark break; 1966010dabb0SCrist J. Clark 196722b5770bSAndre Oppermann case O_VERSRCREACH: 196822b5770bSAndre Oppermann printf(" versrcreach"); 196922b5770bSAndre Oppermann break; 197022b5770bSAndre Oppermann 19715f9541ecSAndre Oppermann case O_ANTISPOOF: 19725f9541ecSAndre Oppermann printf(" antispoof"); 19735f9541ecSAndre Oppermann break; 19745f9541ecSAndre Oppermann 1975c3e5b9f1SLuigi Rizzo case O_IPSEC: 1976c3e5b9f1SLuigi Rizzo printf(" ipsec"); 1977c3e5b9f1SLuigi Rizzo break; 1978c3e5b9f1SLuigi Rizzo 197962ff38aeSLuigi Rizzo case O_NOP: 1980bbc39c83SLuigi Rizzo comment = (char *)(cmd + 1); 198162ff38aeSLuigi Rizzo break; 198262ff38aeSLuigi Rizzo 19839758b77fSLuigi Rizzo case O_KEEP_STATE: 19849758b77fSLuigi Rizzo printf(" keep-state"); 19859758b77fSLuigi Rizzo break; 19869758b77fSLuigi Rizzo 1987254c4725SOleg Bulyzhin case O_LIMIT: { 19889758b77fSLuigi Rizzo struct _s_x *p = limit_masks; 19899758b77fSLuigi Rizzo ipfw_insn_limit *c = (ipfw_insn_limit *)cmd; 1990571f8c1bSLuigi Rizzo uint8_t x = c->limit_mask; 199162ff38aeSLuigi Rizzo char const *comma = " "; 19929758b77fSLuigi Rizzo 19939758b77fSLuigi Rizzo printf(" limit"); 19949758b77fSLuigi Rizzo for (; p->x != 0 ; p++) 19950a7197a8SLuigi Rizzo if ((x & p->x) == p->x) { 19969758b77fSLuigi Rizzo x &= ~p->x; 19979758b77fSLuigi Rizzo printf("%s%s", comma, p->s); 19989758b77fSLuigi Rizzo comma = ","; 19999758b77fSLuigi Rizzo } 2000254c4725SOleg Bulyzhin PRINT_UINT_ARG(" ", c->conn_limit); 20019758b77fSLuigi Rizzo break; 2002254c4725SOleg Bulyzhin } 20039758b77fSLuigi Rizzo 20048195404bSBrooks Davis case O_IP6: 200536c263ccSHajimu UMEMOTO printf(" ip6"); 20068195404bSBrooks Davis break; 20078195404bSBrooks Davis 200857cd6d26SMax Laier case O_IP4: 200936c263ccSHajimu UMEMOTO printf(" ip4"); 201057cd6d26SMax Laier break; 201157cd6d26SMax Laier 20128195404bSBrooks Davis case O_ICMP6TYPE: 20138195404bSBrooks Davis print_icmp6types((ipfw_insn_u32 *)cmd); 20148195404bSBrooks Davis break; 20158195404bSBrooks Davis 20168195404bSBrooks Davis case O_EXT_HDR: 20178195404bSBrooks Davis print_ext6hdr( (ipfw_insn *) cmd ); 20188195404bSBrooks Davis break; 20198195404bSBrooks Davis 20206a7d5cb6SOleg Bulyzhin case O_TAGGED: 20216a7d5cb6SOleg Bulyzhin if (F_LEN(cmd) == 1) 2022254c4725SOleg Bulyzhin PRINT_UINT_ARG(" tagged ", cmd->arg1); 20236a7d5cb6SOleg Bulyzhin else 20246a7d5cb6SOleg Bulyzhin print_newports((ipfw_insn_u16 *)cmd, 0, 20256a7d5cb6SOleg Bulyzhin O_TAGGED); 20266a7d5cb6SOleg Bulyzhin break; 20276a7d5cb6SOleg Bulyzhin 20289758b77fSLuigi Rizzo default: 20299758b77fSLuigi Rizzo printf(" [opcode %d len %d]", 20309758b77fSLuigi Rizzo cmd->opcode, cmd->len); 20319758b77fSLuigi Rizzo } 20329758b77fSLuigi Rizzo } 20339758b77fSLuigi Rizzo if (cmd->len & F_OR) { 20349758b77fSLuigi Rizzo printf(" or"); 20359758b77fSLuigi Rizzo or_block = 1; 20369758b77fSLuigi Rizzo } else if (or_block) { 20379758b77fSLuigi Rizzo printf(" }"); 20389758b77fSLuigi Rizzo or_block = 0; 20399758b77fSLuigi Rizzo } 20409758b77fSLuigi Rizzo } 2041e706181bSLuigi Rizzo show_prerequisites(&flags, HAVE_IP, 0); 2042bbc39c83SLuigi Rizzo if (comment) 2043bbc39c83SLuigi Rizzo printf(" // %s", comment); 20449758b77fSLuigi Rizzo printf("\n"); 20459758b77fSLuigi Rizzo } 20469758b77fSLuigi Rizzo 20479758b77fSLuigi Rizzo static void 204845f61351SMaxim Konovalov show_dyn_ipfw(ipfw_dyn_rule *d, int pcwidth, int bcwidth) 20499758b77fSLuigi Rizzo { 20509758b77fSLuigi Rizzo struct protoent *pe; 20519758b77fSLuigi Rizzo struct in_addr a; 2052330462a3SBernd Walter uint16_t rulenum; 205381bd0dc0SMax Laier char buf[INET6_ADDRSTRLEN]; 20549758b77fSLuigi Rizzo 20559758b77fSLuigi Rizzo if (!do_expired) { 20569758b77fSLuigi Rizzo if (!d->expire && !(d->dyn_type == O_LIMIT_PARENT)) 20579758b77fSLuigi Rizzo return; 20589758b77fSLuigi Rizzo } 2059330462a3SBernd Walter bcopy(&d->rule, &rulenum, sizeof(rulenum)); 2060571f8c1bSLuigi Rizzo printf("%05d", rulenum); 206162ff38aeSLuigi Rizzo if (pcwidth>0 || bcwidth>0) 2062571f8c1bSLuigi Rizzo printf(" %*llu %*llu (%ds)", pcwidth, 2063330462a3SBernd Walter align_uint64(&d->pcnt), bcwidth, 2064330462a3SBernd Walter align_uint64(&d->bcnt), d->expire); 20659758b77fSLuigi Rizzo switch (d->dyn_type) { 20669758b77fSLuigi Rizzo case O_LIMIT_PARENT: 20679758b77fSLuigi Rizzo printf(" PARENT %d", d->count); 20689758b77fSLuigi Rizzo break; 20699758b77fSLuigi Rizzo case O_LIMIT: 20709758b77fSLuigi Rizzo printf(" LIMIT"); 20719758b77fSLuigi Rizzo break; 20729758b77fSLuigi Rizzo case O_KEEP_STATE: /* bidir, no mask */ 20739758b77fSLuigi Rizzo printf(" STATE"); 20749758b77fSLuigi Rizzo break; 20759758b77fSLuigi Rizzo } 20769758b77fSLuigi Rizzo 20779758b77fSLuigi Rizzo if ((pe = getprotobynumber(d->id.proto)) != NULL) 20789758b77fSLuigi Rizzo printf(" %s", pe->p_name); 20799758b77fSLuigi Rizzo else 20809758b77fSLuigi Rizzo printf(" proto %u", d->id.proto); 20819758b77fSLuigi Rizzo 208281bd0dc0SMax Laier if (d->id.addr_type == 4) { 20839758b77fSLuigi Rizzo a.s_addr = htonl(d->id.src_ip); 20849758b77fSLuigi Rizzo printf(" %s %d", inet_ntoa(a), d->id.src_port); 20859758b77fSLuigi Rizzo 20869758b77fSLuigi Rizzo a.s_addr = htonl(d->id.dst_ip); 20879758b77fSLuigi Rizzo printf(" <-> %s %d", inet_ntoa(a), d->id.dst_port); 208881bd0dc0SMax Laier } else if (d->id.addr_type == 6) { 208981bd0dc0SMax Laier printf(" %s %d", inet_ntop(AF_INET6, &d->id.src_ip6, buf, 209081bd0dc0SMax Laier sizeof(buf)), d->id.src_port); 209181bd0dc0SMax Laier printf(" <-> %s %d", inet_ntop(AF_INET6, &d->id.dst_ip6, buf, 209281bd0dc0SMax Laier sizeof(buf)), d->id.dst_port); 209381bd0dc0SMax Laier } else 209481bd0dc0SMax Laier printf(" UNKNOWN <-> UNKNOWN\n"); 209581bd0dc0SMax Laier 20969758b77fSLuigi Rizzo printf("\n"); 20979758b77fSLuigi Rizzo } 20989758b77fSLuigi Rizzo 209962ff38aeSLuigi Rizzo static int 21009758b77fSLuigi Rizzo sort_q(const void *pa, const void *pb) 21019758b77fSLuigi Rizzo { 21029758b77fSLuigi Rizzo int rev = (do_sort < 0); 21039758b77fSLuigi Rizzo int field = rev ? -do_sort : do_sort; 21049758b77fSLuigi Rizzo long long res = 0; 21059758b77fSLuigi Rizzo const struct dn_flow_queue *a = pa; 21069758b77fSLuigi Rizzo const struct dn_flow_queue *b = pb; 21079758b77fSLuigi Rizzo 21089758b77fSLuigi Rizzo switch (field) { 21099758b77fSLuigi Rizzo case 1: /* pkts */ 21109758b77fSLuigi Rizzo res = a->len - b->len; 21119758b77fSLuigi Rizzo break; 21129758b77fSLuigi Rizzo case 2: /* bytes */ 21139758b77fSLuigi Rizzo res = a->len_bytes - b->len_bytes; 21149758b77fSLuigi Rizzo break; 21159758b77fSLuigi Rizzo 21169758b77fSLuigi Rizzo case 3: /* tot pkts */ 21179758b77fSLuigi Rizzo res = a->tot_pkts - b->tot_pkts; 21189758b77fSLuigi Rizzo break; 21199758b77fSLuigi Rizzo 21209758b77fSLuigi Rizzo case 4: /* tot bytes */ 21219758b77fSLuigi Rizzo res = a->tot_bytes - b->tot_bytes; 21229758b77fSLuigi Rizzo break; 21239758b77fSLuigi Rizzo } 21249758b77fSLuigi Rizzo if (res < 0) 21259758b77fSLuigi Rizzo res = -1; 21269758b77fSLuigi Rizzo if (res > 0) 21279758b77fSLuigi Rizzo res = 1; 21289758b77fSLuigi Rizzo return (int)(rev ? res : -res); 21299758b77fSLuigi Rizzo } 21309758b77fSLuigi Rizzo 21319758b77fSLuigi Rizzo static void 21329758b77fSLuigi Rizzo list_queues(struct dn_flow_set *fs, struct dn_flow_queue *q) 21339758b77fSLuigi Rizzo { 21349758b77fSLuigi Rizzo int l; 21358195404bSBrooks Davis int index_printed, indexes = 0; 21368195404bSBrooks Davis char buff[255]; 21378195404bSBrooks Davis struct protoent *pe; 21389758b77fSLuigi Rizzo 21399758b77fSLuigi Rizzo if (fs->rq_elements == 0) 21409758b77fSLuigi Rizzo return; 21419758b77fSLuigi Rizzo 21429758b77fSLuigi Rizzo if (do_sort != 0) 21439758b77fSLuigi Rizzo heapsort(q, fs->rq_elements, sizeof *q, sort_q); 21448195404bSBrooks Davis 21458195404bSBrooks Davis /* Print IPv4 flows */ 21468195404bSBrooks Davis index_printed = 0; 21479758b77fSLuigi Rizzo for (l = 0; l < fs->rq_elements; l++) { 21489758b77fSLuigi Rizzo struct in_addr ina; 21499758b77fSLuigi Rizzo 21508195404bSBrooks Davis /* XXX: Should check for IPv4 flows */ 21518195404bSBrooks Davis if (IS_IP6_FLOW_ID(&(q[l].id))) 21528195404bSBrooks Davis continue; 21538195404bSBrooks Davis 21548195404bSBrooks Davis if (!index_printed) { 21558195404bSBrooks Davis index_printed = 1; 21568195404bSBrooks Davis if (indexes > 0) /* currently a no-op */ 21578195404bSBrooks Davis printf("\n"); 21588195404bSBrooks Davis indexes++; 21598195404bSBrooks Davis printf(" " 21608195404bSBrooks Davis "mask: 0x%02x 0x%08x/0x%04x -> 0x%08x/0x%04x\n", 21618195404bSBrooks Davis fs->flow_mask.proto, 21628195404bSBrooks Davis fs->flow_mask.src_ip, fs->flow_mask.src_port, 21638195404bSBrooks Davis fs->flow_mask.dst_ip, fs->flow_mask.dst_port); 21648195404bSBrooks Davis 21658195404bSBrooks Davis printf("BKT Prot ___Source IP/port____ " 21668195404bSBrooks Davis "____Dest. IP/port____ " 21678195404bSBrooks Davis "Tot_pkt/bytes Pkt/Byte Drp\n"); 21688195404bSBrooks Davis } 21698195404bSBrooks Davis 21709758b77fSLuigi Rizzo printf("%3d ", q[l].hash_slot); 21719758b77fSLuigi Rizzo pe = getprotobynumber(q[l].id.proto); 21729758b77fSLuigi Rizzo if (pe) 21739758b77fSLuigi Rizzo printf("%-4s ", pe->p_name); 21749758b77fSLuigi Rizzo else 21759758b77fSLuigi Rizzo printf("%4u ", q[l].id.proto); 21768195404bSBrooks Davis ina.s_addr = htonl(q[l].id.src_ip); 21779758b77fSLuigi Rizzo printf("%15s/%-5d ", 21789758b77fSLuigi Rizzo inet_ntoa(ina), q[l].id.src_port); 21799758b77fSLuigi Rizzo ina.s_addr = htonl(q[l].id.dst_ip); 21809758b77fSLuigi Rizzo printf("%15s/%-5d ", 21819758b77fSLuigi Rizzo inet_ntoa(ina), q[l].id.dst_port); 21829758b77fSLuigi Rizzo printf("%4qu %8qu %2u %4u %3u\n", 21839758b77fSLuigi Rizzo q[l].tot_pkts, q[l].tot_bytes, 21849758b77fSLuigi Rizzo q[l].len, q[l].len_bytes, q[l].drops); 21859758b77fSLuigi Rizzo if (verbose) 21869758b77fSLuigi Rizzo printf(" S %20qd F %20qd\n", 21879758b77fSLuigi Rizzo q[l].S, q[l].F); 21889758b77fSLuigi Rizzo } 21898195404bSBrooks Davis 21908195404bSBrooks Davis /* Print IPv6 flows */ 21918195404bSBrooks Davis index_printed = 0; 21928195404bSBrooks Davis for (l = 0; l < fs->rq_elements; l++) { 21938195404bSBrooks Davis if (!IS_IP6_FLOW_ID(&(q[l].id))) 21948195404bSBrooks Davis continue; 21958195404bSBrooks Davis 21968195404bSBrooks Davis if (!index_printed) { 21978195404bSBrooks Davis index_printed = 1; 21988195404bSBrooks Davis if (indexes > 0) 21998195404bSBrooks Davis printf("\n"); 22008195404bSBrooks Davis indexes++; 22018195404bSBrooks Davis printf("\n mask: proto: 0x%02x, flow_id: 0x%08x, ", 22028195404bSBrooks Davis fs->flow_mask.proto, fs->flow_mask.flow_id6); 22038195404bSBrooks Davis inet_ntop(AF_INET6, &(fs->flow_mask.src_ip6), 22048195404bSBrooks Davis buff, sizeof(buff)); 22058195404bSBrooks Davis printf("%s/0x%04x -> ", buff, fs->flow_mask.src_port); 22068195404bSBrooks Davis inet_ntop( AF_INET6, &(fs->flow_mask.dst_ip6), 22078195404bSBrooks Davis buff, sizeof(buff) ); 22088195404bSBrooks Davis printf("%s/0x%04x\n", buff, fs->flow_mask.dst_port); 22098195404bSBrooks Davis 22108195404bSBrooks Davis printf("BKT ___Prot___ _flow-id_ " 22118195404bSBrooks Davis "______________Source IPv6/port_______________ " 22128195404bSBrooks Davis "_______________Dest. IPv6/port_______________ " 22138195404bSBrooks Davis "Tot_pkt/bytes Pkt/Byte Drp\n"); 22148195404bSBrooks Davis } 22158195404bSBrooks Davis printf("%3d ", q[l].hash_slot); 22168195404bSBrooks Davis pe = getprotobynumber(q[l].id.proto); 22178195404bSBrooks Davis if (pe != NULL) 22188195404bSBrooks Davis printf("%9s ", pe->p_name); 22198195404bSBrooks Davis else 22208195404bSBrooks Davis printf("%9u ", q[l].id.proto); 22218195404bSBrooks Davis printf("%7d %39s/%-5d ", q[l].id.flow_id6, 22228195404bSBrooks Davis inet_ntop(AF_INET6, &(q[l].id.src_ip6), buff, sizeof(buff)), 22238195404bSBrooks Davis q[l].id.src_port); 22248195404bSBrooks Davis printf(" %39s/%-5d ", 22258195404bSBrooks Davis inet_ntop(AF_INET6, &(q[l].id.dst_ip6), buff, sizeof(buff)), 22268195404bSBrooks Davis q[l].id.dst_port); 22278195404bSBrooks Davis printf(" %4qu %8qu %2u %4u %3u\n", 22288195404bSBrooks Davis q[l].tot_pkts, q[l].tot_bytes, 22298195404bSBrooks Davis q[l].len, q[l].len_bytes, q[l].drops); 22308195404bSBrooks Davis if (verbose) 22318195404bSBrooks Davis printf(" S %20qd F %20qd\n", q[l].S, q[l].F); 22328195404bSBrooks Davis } 22339758b77fSLuigi Rizzo } 22349758b77fSLuigi Rizzo 22359758b77fSLuigi Rizzo static void 22369758b77fSLuigi Rizzo print_flowset_parms(struct dn_flow_set *fs, char *prefix) 22379758b77fSLuigi Rizzo { 22389758b77fSLuigi Rizzo int l; 22399758b77fSLuigi Rizzo char qs[30]; 22409758b77fSLuigi Rizzo char plr[30]; 22419758b77fSLuigi Rizzo char red[90]; /* Display RED parameters */ 22429758b77fSLuigi Rizzo 22439758b77fSLuigi Rizzo l = fs->qsize; 22449758b77fSLuigi Rizzo if (fs->flags_fs & DN_QSIZE_IS_BYTES) { 22459758b77fSLuigi Rizzo if (l >= 8192) 22469758b77fSLuigi Rizzo sprintf(qs, "%d KB", l / 1024); 22479758b77fSLuigi Rizzo else 22489758b77fSLuigi Rizzo sprintf(qs, "%d B", l); 22499758b77fSLuigi Rizzo } else 22509758b77fSLuigi Rizzo sprintf(qs, "%3d sl.", l); 22519758b77fSLuigi Rizzo if (fs->plr) 22529758b77fSLuigi Rizzo sprintf(plr, "plr %f", 1.0 * fs->plr / (double)(0x7fffffff)); 22539758b77fSLuigi Rizzo else 22549758b77fSLuigi Rizzo plr[0] = '\0'; 22559758b77fSLuigi Rizzo if (fs->flags_fs & DN_IS_RED) /* RED parameters */ 22569758b77fSLuigi Rizzo sprintf(red, 22579758b77fSLuigi Rizzo "\n\t %cRED w_q %f min_th %d max_th %d max_p %f", 22589758b77fSLuigi Rizzo (fs->flags_fs & DN_IS_GENTLE_RED) ? 'G' : ' ', 22599758b77fSLuigi Rizzo 1.0 * fs->w_q / (double)(1 << SCALE_RED), 22609758b77fSLuigi Rizzo SCALE_VAL(fs->min_th), 22619758b77fSLuigi Rizzo SCALE_VAL(fs->max_th), 22629758b77fSLuigi Rizzo 1.0 * fs->max_p / (double)(1 << SCALE_RED)); 22639758b77fSLuigi Rizzo else 22649758b77fSLuigi Rizzo sprintf(red, "droptail"); 22659758b77fSLuigi Rizzo 22669758b77fSLuigi Rizzo printf("%s %s%s %d queues (%d buckets) %s\n", 22679758b77fSLuigi Rizzo prefix, qs, plr, fs->rq_elements, fs->rq_size, red); 22689758b77fSLuigi Rizzo } 22699758b77fSLuigi Rizzo 22709758b77fSLuigi Rizzo static void 227162ff38aeSLuigi Rizzo list_pipes(void *data, uint nbytes, int ac, char *av[]) 22729758b77fSLuigi Rizzo { 227362ff38aeSLuigi Rizzo int rulenum; 22749758b77fSLuigi Rizzo void *next = data; 22759758b77fSLuigi Rizzo struct dn_pipe *p = (struct dn_pipe *) data; 22769758b77fSLuigi Rizzo struct dn_flow_set *fs; 22779758b77fSLuigi Rizzo struct dn_flow_queue *q; 22789758b77fSLuigi Rizzo int l; 22799758b77fSLuigi Rizzo 22809758b77fSLuigi Rizzo if (ac > 0) 22819758b77fSLuigi Rizzo rulenum = strtoul(*av++, NULL, 10); 22829758b77fSLuigi Rizzo else 22839758b77fSLuigi Rizzo rulenum = 0; 22849758b77fSLuigi Rizzo for (; nbytes >= sizeof *p; p = (struct dn_pipe *)next) { 22859758b77fSLuigi Rizzo double b = p->bandwidth; 22869758b77fSLuigi Rizzo char buf[30]; 22879758b77fSLuigi Rizzo char prefix[80]; 22889758b77fSLuigi Rizzo 2289299652afSStefan Farfeleder if (SLIST_NEXT(p, next) != (struct dn_pipe *)DN_IS_PIPE) 22909758b77fSLuigi Rizzo break; /* done with pipes, now queues */ 22919758b77fSLuigi Rizzo 22929758b77fSLuigi Rizzo /* 22939758b77fSLuigi Rizzo * compute length, as pipe have variable size 22949758b77fSLuigi Rizzo */ 22959758b77fSLuigi Rizzo l = sizeof(*p) + p->fs.rq_elements * sizeof(*q); 229662ff38aeSLuigi Rizzo next = (char *)p + l; 22979758b77fSLuigi Rizzo nbytes -= l; 22989758b77fSLuigi Rizzo 2299c3d6fe74SPawel Jakub Dawidek if ((rulenum != 0 && rulenum != p->pipe_nr) || do_pipe == 2) 23009758b77fSLuigi Rizzo continue; 23019758b77fSLuigi Rizzo 23029758b77fSLuigi Rizzo /* 23039758b77fSLuigi Rizzo * Print rate (or clocking interface) 23049758b77fSLuigi Rizzo */ 23059758b77fSLuigi Rizzo if (p->if_name[0] != '\0') 23069758b77fSLuigi Rizzo sprintf(buf, "%s", p->if_name); 23079758b77fSLuigi Rizzo else if (b == 0) 23089758b77fSLuigi Rizzo sprintf(buf, "unlimited"); 23099758b77fSLuigi Rizzo else if (b >= 1000000) 23109758b77fSLuigi Rizzo sprintf(buf, "%7.3f Mbit/s", b/1000000); 23119758b77fSLuigi Rizzo else if (b >= 1000) 23129758b77fSLuigi Rizzo sprintf(buf, "%7.3f Kbit/s", b/1000); 23139758b77fSLuigi Rizzo else 23149758b77fSLuigi Rizzo sprintf(buf, "%7.3f bit/s ", b); 23159758b77fSLuigi Rizzo 23169758b77fSLuigi Rizzo sprintf(prefix, "%05d: %s %4d ms ", 23179758b77fSLuigi Rizzo p->pipe_nr, buf, p->delay); 23189758b77fSLuigi Rizzo print_flowset_parms(&(p->fs), prefix); 23199758b77fSLuigi Rizzo if (verbose) 23209758b77fSLuigi Rizzo printf(" V %20qd\n", p->V >> MY_M); 23219758b77fSLuigi Rizzo 23229758b77fSLuigi Rizzo q = (struct dn_flow_queue *)(p+1); 23239758b77fSLuigi Rizzo list_queues(&(p->fs), q); 23249758b77fSLuigi Rizzo } 23259758b77fSLuigi Rizzo for (fs = next; nbytes >= sizeof *fs; fs = next) { 23269758b77fSLuigi Rizzo char prefix[80]; 23279758b77fSLuigi Rizzo 2328299652afSStefan Farfeleder if (SLIST_NEXT(fs, next) != (struct dn_flow_set *)DN_IS_QUEUE) 23299758b77fSLuigi Rizzo break; 23309758b77fSLuigi Rizzo l = sizeof(*fs) + fs->rq_elements * sizeof(*q); 233162ff38aeSLuigi Rizzo next = (char *)fs + l; 23329758b77fSLuigi Rizzo nbytes -= l; 2333c3d6fe74SPawel Jakub Dawidek 2334c3d6fe74SPawel Jakub Dawidek if (rulenum != 0 && ((rulenum != fs->fs_nr && do_pipe == 2) || 2335c3d6fe74SPawel Jakub Dawidek (rulenum != fs->parent_nr && do_pipe == 1))) { 2336c3d6fe74SPawel Jakub Dawidek continue; 2337c3d6fe74SPawel Jakub Dawidek } 2338c3d6fe74SPawel Jakub Dawidek 23399758b77fSLuigi Rizzo q = (struct dn_flow_queue *)(fs+1); 23409758b77fSLuigi Rizzo sprintf(prefix, "q%05d: weight %d pipe %d ", 23419758b77fSLuigi Rizzo fs->fs_nr, fs->weight, fs->parent_nr); 23429758b77fSLuigi Rizzo print_flowset_parms(fs, prefix); 23439758b77fSLuigi Rizzo list_queues(fs, q); 23449758b77fSLuigi Rizzo } 23459758b77fSLuigi Rizzo } 23469758b77fSLuigi Rizzo 234799e5e645SLuigi Rizzo /* 234899e5e645SLuigi Rizzo * This one handles all set-related commands 234999e5e645SLuigi Rizzo * ipfw set { show | enable | disable } 235099e5e645SLuigi Rizzo * ipfw set swap X Y 235199e5e645SLuigi Rizzo * ipfw set move X to Y 235299e5e645SLuigi Rizzo * ipfw set move rule X to Y 235399e5e645SLuigi Rizzo */ 235499e5e645SLuigi Rizzo static void 235599e5e645SLuigi Rizzo sets_handler(int ac, char *av[]) 235699e5e645SLuigi Rizzo { 2357571f8c1bSLuigi Rizzo uint32_t set_disable, masks[2]; 235899e5e645SLuigi Rizzo int i, nbytes; 2359571f8c1bSLuigi Rizzo uint16_t rulenum; 2360571f8c1bSLuigi Rizzo uint8_t cmd, new_set; 236199e5e645SLuigi Rizzo 236299e5e645SLuigi Rizzo ac--; 236399e5e645SLuigi Rizzo av++; 236499e5e645SLuigi Rizzo 236599e5e645SLuigi Rizzo if (!ac) 236699e5e645SLuigi Rizzo errx(EX_USAGE, "set needs command"); 236701750186SBrooks Davis if (_substrcmp(*av, "show") == 0) { 236899e5e645SLuigi Rizzo void *data; 236962ff38aeSLuigi Rizzo char const *msg; 237099e5e645SLuigi Rizzo 237199e5e645SLuigi Rizzo nbytes = sizeof(struct ip_fw); 2372571f8c1bSLuigi Rizzo if ((data = calloc(1, nbytes)) == NULL) 2373571f8c1bSLuigi Rizzo err(EX_OSERR, "calloc"); 2374884be75cSThomas Moestl if (do_cmd(IP_FW_GET, data, (uintptr_t)&nbytes) < 0) 237599e5e645SLuigi Rizzo err(EX_OSERR, "getsockopt(IP_FW_GET)"); 2376330462a3SBernd Walter bcopy(&((struct ip_fw *)data)->next_rule, 2377330462a3SBernd Walter &set_disable, sizeof(set_disable)); 2378330462a3SBernd Walter 23793004afcaSLuigi Rizzo for (i = 0, msg = "disable" ; i < RESVD_SET; i++) 238099e5e645SLuigi Rizzo if ((set_disable & (1<<i))) { 238199e5e645SLuigi Rizzo printf("%s %d", msg, i); 238299e5e645SLuigi Rizzo msg = ""; 238399e5e645SLuigi Rizzo } 238499e5e645SLuigi Rizzo msg = (set_disable) ? " enable" : "enable"; 23853004afcaSLuigi Rizzo for (i = 0; i < RESVD_SET; i++) 238699e5e645SLuigi Rizzo if (!(set_disable & (1<<i))) { 238799e5e645SLuigi Rizzo printf("%s %d", msg, i); 238899e5e645SLuigi Rizzo msg = ""; 238999e5e645SLuigi Rizzo } 239099e5e645SLuigi Rizzo printf("\n"); 239101750186SBrooks Davis } else if (_substrcmp(*av, "swap") == 0) { 239299e5e645SLuigi Rizzo ac--; av++; 239399e5e645SLuigi Rizzo if (ac != 2) 239499e5e645SLuigi Rizzo errx(EX_USAGE, "set swap needs 2 set numbers\n"); 239599e5e645SLuigi Rizzo rulenum = atoi(av[0]); 239699e5e645SLuigi Rizzo new_set = atoi(av[1]); 23973004afcaSLuigi Rizzo if (!isdigit(*(av[0])) || rulenum > RESVD_SET) 239899e5e645SLuigi Rizzo errx(EX_DATAERR, "invalid set number %s\n", av[0]); 23993004afcaSLuigi Rizzo if (!isdigit(*(av[1])) || new_set > RESVD_SET) 240099e5e645SLuigi Rizzo errx(EX_DATAERR, "invalid set number %s\n", av[1]); 240199e5e645SLuigi Rizzo masks[0] = (4 << 24) | (new_set << 16) | (rulenum); 2402571f8c1bSLuigi Rizzo i = do_cmd(IP_FW_DEL, masks, sizeof(uint32_t)); 240301750186SBrooks Davis } else if (_substrcmp(*av, "move") == 0) { 240499e5e645SLuigi Rizzo ac--; av++; 240501750186SBrooks Davis if (ac && _substrcmp(*av, "rule") == 0) { 240699e5e645SLuigi Rizzo cmd = 2; 240799e5e645SLuigi Rizzo ac--; av++; 240899e5e645SLuigi Rizzo } else 240999e5e645SLuigi Rizzo cmd = 3; 241001750186SBrooks Davis if (ac != 3 || _substrcmp(av[1], "to") != 0) 241199e5e645SLuigi Rizzo errx(EX_USAGE, "syntax: set move [rule] X to Y\n"); 241299e5e645SLuigi Rizzo rulenum = atoi(av[0]); 241399e5e645SLuigi Rizzo new_set = atoi(av[2]); 24143004afcaSLuigi Rizzo if (!isdigit(*(av[0])) || (cmd == 3 && rulenum > RESVD_SET) || 241599e5e645SLuigi Rizzo (cmd == 2 && rulenum == 65535) ) 241699e5e645SLuigi Rizzo errx(EX_DATAERR, "invalid source number %s\n", av[0]); 24173004afcaSLuigi Rizzo if (!isdigit(*(av[2])) || new_set > RESVD_SET) 241899e5e645SLuigi Rizzo errx(EX_DATAERR, "invalid dest. set %s\n", av[1]); 241999e5e645SLuigi Rizzo masks[0] = (cmd << 24) | (new_set << 16) | (rulenum); 2420571f8c1bSLuigi Rizzo i = do_cmd(IP_FW_DEL, masks, sizeof(uint32_t)); 242101750186SBrooks Davis } else if (_substrcmp(*av, "disable") == 0 || 242201750186SBrooks Davis _substrcmp(*av, "enable") == 0 ) { 242301750186SBrooks Davis int which = _substrcmp(*av, "enable") == 0 ? 1 : 0; 242499e5e645SLuigi Rizzo 242599e5e645SLuigi Rizzo ac--; av++; 242699e5e645SLuigi Rizzo masks[0] = masks[1] = 0; 242799e5e645SLuigi Rizzo 242899e5e645SLuigi Rizzo while (ac) { 242999e5e645SLuigi Rizzo if (isdigit(**av)) { 243099e5e645SLuigi Rizzo i = atoi(*av); 24313004afcaSLuigi Rizzo if (i < 0 || i > RESVD_SET) 243299e5e645SLuigi Rizzo errx(EX_DATAERR, 243399e5e645SLuigi Rizzo "invalid set number %d\n", i); 243499e5e645SLuigi Rizzo masks[which] |= (1<<i); 243501750186SBrooks Davis } else if (_substrcmp(*av, "disable") == 0) 243699e5e645SLuigi Rizzo which = 0; 243701750186SBrooks Davis else if (_substrcmp(*av, "enable") == 0) 243899e5e645SLuigi Rizzo which = 1; 243999e5e645SLuigi Rizzo else 244099e5e645SLuigi Rizzo errx(EX_DATAERR, 244199e5e645SLuigi Rizzo "invalid set command %s\n", *av); 244299e5e645SLuigi Rizzo av++; ac--; 244399e5e645SLuigi Rizzo } 244499e5e645SLuigi Rizzo if ( (masks[0] & masks[1]) != 0 ) 244599e5e645SLuigi Rizzo errx(EX_DATAERR, 244699e5e645SLuigi Rizzo "cannot enable and disable the same set\n"); 244799e5e645SLuigi Rizzo 2448571f8c1bSLuigi Rizzo i = do_cmd(IP_FW_DEL, masks, sizeof(masks)); 244999e5e645SLuigi Rizzo if (i) 245099e5e645SLuigi Rizzo warn("set enable/disable: setsockopt(IP_FW_DEL)"); 245199e5e645SLuigi Rizzo } else 245299e5e645SLuigi Rizzo errx(EX_USAGE, "invalid set command %s\n", *av); 245399e5e645SLuigi Rizzo } 245499e5e645SLuigi Rizzo 24559758b77fSLuigi Rizzo static void 24566690be9eSMatthew Dillon sysctl_handler(int ac, char *av[], int which) 24576690be9eSMatthew Dillon { 24586690be9eSMatthew Dillon ac--; 24596690be9eSMatthew Dillon av++; 24606690be9eSMatthew Dillon 24611c56ad9bSMaxim Konovalov if (ac == 0) { 24626690be9eSMatthew Dillon warnx("missing keyword to enable/disable\n"); 246301750186SBrooks Davis } else if (_substrcmp(*av, "firewall") == 0) { 246429c1402aSLuigi Rizzo sysctlbyname("net.inet.ip.fw.enable", NULL, 0, 246529c1402aSLuigi Rizzo &which, sizeof(which)); 246601750186SBrooks Davis } else if (_substrcmp(*av, "one_pass") == 0) { 246729c1402aSLuigi Rizzo sysctlbyname("net.inet.ip.fw.one_pass", NULL, 0, 246829c1402aSLuigi Rizzo &which, sizeof(which)); 246901750186SBrooks Davis } else if (_substrcmp(*av, "debug") == 0) { 247029c1402aSLuigi Rizzo sysctlbyname("net.inet.ip.fw.debug", NULL, 0, 247129c1402aSLuigi Rizzo &which, sizeof(which)); 247201750186SBrooks Davis } else if (_substrcmp(*av, "verbose") == 0) { 247329c1402aSLuigi Rizzo sysctlbyname("net.inet.ip.fw.verbose", NULL, 0, 247429c1402aSLuigi Rizzo &which, sizeof(which)); 247501750186SBrooks Davis } else if (_substrcmp(*av, "dyn_keepalive") == 0) { 247629c1402aSLuigi Rizzo sysctlbyname("net.inet.ip.fw.dyn_keepalive", NULL, 0, 247729c1402aSLuigi Rizzo &which, sizeof(which)); 247801750186SBrooks Davis } else if (_substrcmp(*av, "altq") == 0) { 2479974dfe30SBrian Feldman altq_set_enabled(which); 24806690be9eSMatthew Dillon } else { 24816690be9eSMatthew Dillon warnx("unrecognize enable/disable keyword: %s\n", *av); 24826690be9eSMatthew Dillon } 24836690be9eSMatthew Dillon } 24846690be9eSMatthew Dillon 24856690be9eSMatthew Dillon static void 248662ff38aeSLuigi Rizzo list(int ac, char *av[], int show_counters) 24879758b77fSLuigi Rizzo { 24889758b77fSLuigi Rizzo struct ip_fw *r; 24899758b77fSLuigi Rizzo ipfw_dyn_rule *dynrules, *d; 24909758b77fSLuigi Rizzo 249162ff38aeSLuigi Rizzo #define NEXT(r) ((struct ip_fw *)((char *)r + RULESIZE(r))) 249262ff38aeSLuigi Rizzo char *lim; 249362ff38aeSLuigi Rizzo void *data = NULL; 249445f61351SMaxim Konovalov int bcwidth, n, nbytes, nstat, ndyn, pcwidth, width; 24959758b77fSLuigi Rizzo int exitval = EX_OK; 24969758b77fSLuigi Rizzo int lac; 24979758b77fSLuigi Rizzo char **lav; 249862ff38aeSLuigi Rizzo u_long rnum, last; 24999758b77fSLuigi Rizzo char *endptr; 25009758b77fSLuigi Rizzo int seen = 0; 25019758b77fSLuigi Rizzo 25029758b77fSLuigi Rizzo const int ocmd = do_pipe ? IP_DUMMYNET_GET : IP_FW_GET; 25039758b77fSLuigi Rizzo int nalloc = 1024; /* start somewhere... */ 25049758b77fSLuigi Rizzo 250500ed6609SMaxim Konovalov last = 0; 250600ed6609SMaxim Konovalov 2507571f8c1bSLuigi Rizzo if (test_only) { 2508571f8c1bSLuigi Rizzo fprintf(stderr, "Testing only, list disabled\n"); 2509571f8c1bSLuigi Rizzo return; 2510571f8c1bSLuigi Rizzo } 2511571f8c1bSLuigi Rizzo 25129758b77fSLuigi Rizzo ac--; 25139758b77fSLuigi Rizzo av++; 25149758b77fSLuigi Rizzo 25159758b77fSLuigi Rizzo /* get rules or pipes from kernel, resizing array as necessary */ 25169758b77fSLuigi Rizzo nbytes = nalloc; 25179758b77fSLuigi Rizzo 25189758b77fSLuigi Rizzo while (nbytes >= nalloc) { 25199758b77fSLuigi Rizzo nalloc = nalloc * 2 + 200; 25209758b77fSLuigi Rizzo nbytes = nalloc; 25219758b77fSLuigi Rizzo if ((data = realloc(data, nbytes)) == NULL) 25229758b77fSLuigi Rizzo err(EX_OSERR, "realloc"); 2523884be75cSThomas Moestl if (do_cmd(ocmd, data, (uintptr_t)&nbytes) < 0) 25249758b77fSLuigi Rizzo err(EX_OSERR, "getsockopt(IP_%s_GET)", 25259758b77fSLuigi Rizzo do_pipe ? "DUMMYNET" : "FW"); 25269758b77fSLuigi Rizzo } 25279758b77fSLuigi Rizzo 25289758b77fSLuigi Rizzo if (do_pipe) { 25299758b77fSLuigi Rizzo list_pipes(data, nbytes, ac, av); 25309758b77fSLuigi Rizzo goto done; 25319758b77fSLuigi Rizzo } 25329758b77fSLuigi Rizzo 25339758b77fSLuigi Rizzo /* 25349758b77fSLuigi Rizzo * Count static rules. They have variable size so we 25359758b77fSLuigi Rizzo * need to scan the list to count them. 25369758b77fSLuigi Rizzo */ 253762ff38aeSLuigi Rizzo for (nstat = 1, r = data, lim = (char *)data + nbytes; 253862ff38aeSLuigi Rizzo r->rulenum < 65535 && (char *)r < lim; 253962ff38aeSLuigi Rizzo ++nstat, r = NEXT(r) ) 25409758b77fSLuigi Rizzo ; /* nothing */ 25419758b77fSLuigi Rizzo 25429758b77fSLuigi Rizzo /* 25439758b77fSLuigi Rizzo * Count dynamic rules. This is easier as they have 25449758b77fSLuigi Rizzo * fixed size. 25459758b77fSLuigi Rizzo */ 254662ff38aeSLuigi Rizzo r = NEXT(r); 25479758b77fSLuigi Rizzo dynrules = (ipfw_dyn_rule *)r ; 254862ff38aeSLuigi Rizzo n = (char *)r - (char *)data; 25499758b77fSLuigi Rizzo ndyn = (nbytes - n) / sizeof *dynrules; 25509758b77fSLuigi Rizzo 255145f61351SMaxim Konovalov /* if showing stats, figure out column widths ahead of time */ 255245f61351SMaxim Konovalov bcwidth = pcwidth = 0; 255362ff38aeSLuigi Rizzo if (show_counters) { 255462ff38aeSLuigi Rizzo for (n = 0, r = data; n < nstat; n++, r = NEXT(r)) { 255545f61351SMaxim Konovalov /* packet counter */ 2556330462a3SBernd Walter width = snprintf(NULL, 0, "%llu", 2557330462a3SBernd Walter align_uint64(&r->pcnt)); 255845f61351SMaxim Konovalov if (width > pcwidth) 255945f61351SMaxim Konovalov pcwidth = width; 256045f61351SMaxim Konovalov 256145f61351SMaxim Konovalov /* byte counter */ 2562330462a3SBernd Walter width = snprintf(NULL, 0, "%llu", 2563330462a3SBernd Walter align_uint64(&r->bcnt)); 256445f61351SMaxim Konovalov if (width > bcwidth) 256545f61351SMaxim Konovalov bcwidth = width; 256645f61351SMaxim Konovalov } 256745f61351SMaxim Konovalov } 256845f61351SMaxim Konovalov if (do_dynamic && ndyn) { 256945f61351SMaxim Konovalov for (n = 0, d = dynrules; n < ndyn; n++, d++) { 2570330462a3SBernd Walter width = snprintf(NULL, 0, "%llu", 2571330462a3SBernd Walter align_uint64(&d->pcnt)); 257245f61351SMaxim Konovalov if (width > pcwidth) 257345f61351SMaxim Konovalov pcwidth = width; 257445f61351SMaxim Konovalov 2575330462a3SBernd Walter width = snprintf(NULL, 0, "%llu", 2576330462a3SBernd Walter align_uint64(&d->bcnt)); 257745f61351SMaxim Konovalov if (width > bcwidth) 257845f61351SMaxim Konovalov bcwidth = width; 257945f61351SMaxim Konovalov } 258045f61351SMaxim Konovalov } 25819758b77fSLuigi Rizzo /* if no rule numbers were specified, list all rules */ 25829758b77fSLuigi Rizzo if (ac == 0) { 258362ff38aeSLuigi Rizzo for (n = 0, r = data; n < nstat; n++, r = NEXT(r) ) 258445f61351SMaxim Konovalov show_ipfw(r, pcwidth, bcwidth); 25859758b77fSLuigi Rizzo 25869758b77fSLuigi Rizzo if (do_dynamic && ndyn) { 25879758b77fSLuigi Rizzo printf("## Dynamic rules (%d):\n", ndyn); 25889758b77fSLuigi Rizzo for (n = 0, d = dynrules; n < ndyn; n++, d++) 258945f61351SMaxim Konovalov show_dyn_ipfw(d, pcwidth, bcwidth); 25909758b77fSLuigi Rizzo } 25919758b77fSLuigi Rizzo goto done; 25929758b77fSLuigi Rizzo } 25939758b77fSLuigi Rizzo 25949758b77fSLuigi Rizzo /* display specific rules requested on command line */ 25959758b77fSLuigi Rizzo 25969758b77fSLuigi Rizzo for (lac = ac, lav = av; lac != 0; lac--) { 25979758b77fSLuigi Rizzo /* convert command line rule # */ 259862ff38aeSLuigi Rizzo last = rnum = strtoul(*lav++, &endptr, 10); 259962ff38aeSLuigi Rizzo if (*endptr == '-') 260062ff38aeSLuigi Rizzo last = strtoul(endptr+1, &endptr, 10); 26019758b77fSLuigi Rizzo if (*endptr) { 26029758b77fSLuigi Rizzo exitval = EX_USAGE; 26039758b77fSLuigi Rizzo warnx("invalid rule number: %s", *(lav - 1)); 26049758b77fSLuigi Rizzo continue; 26059758b77fSLuigi Rizzo } 260662ff38aeSLuigi Rizzo for (n = seen = 0, r = data; n < nstat; n++, r = NEXT(r) ) { 260762ff38aeSLuigi Rizzo if (r->rulenum > last) 26089758b77fSLuigi Rizzo break; 260962ff38aeSLuigi Rizzo if (r->rulenum >= rnum && r->rulenum <= last) { 261045f61351SMaxim Konovalov show_ipfw(r, pcwidth, bcwidth); 26119758b77fSLuigi Rizzo seen = 1; 26129758b77fSLuigi Rizzo } 26139758b77fSLuigi Rizzo } 26149758b77fSLuigi Rizzo if (!seen) { 26159758b77fSLuigi Rizzo /* give precedence to other error(s) */ 26169758b77fSLuigi Rizzo if (exitval == EX_OK) 26179758b77fSLuigi Rizzo exitval = EX_UNAVAILABLE; 26189758b77fSLuigi Rizzo warnx("rule %lu does not exist", rnum); 26199758b77fSLuigi Rizzo } 26209758b77fSLuigi Rizzo } 26219758b77fSLuigi Rizzo 26229758b77fSLuigi Rizzo if (do_dynamic && ndyn) { 26239758b77fSLuigi Rizzo printf("## Dynamic rules:\n"); 26249758b77fSLuigi Rizzo for (lac = ac, lav = av; lac != 0; lac--) { 26258195404bSBrooks Davis last = rnum = strtoul(*lav++, &endptr, 10); 262662ff38aeSLuigi Rizzo if (*endptr == '-') 262762ff38aeSLuigi Rizzo last = strtoul(endptr+1, &endptr, 10); 26289758b77fSLuigi Rizzo if (*endptr) 26299758b77fSLuigi Rizzo /* already warned */ 26309758b77fSLuigi Rizzo continue; 26319758b77fSLuigi Rizzo for (n = 0, d = dynrules; n < ndyn; n++, d++) { 2632330462a3SBernd Walter uint16_t rulenum; 2633330462a3SBernd Walter 2634330462a3SBernd Walter bcopy(&d->rule, &rulenum, sizeof(rulenum)); 2635330462a3SBernd Walter if (rulenum > rnum) 26369758b77fSLuigi Rizzo break; 263762ff38aeSLuigi Rizzo if (r->rulenum >= rnum && r->rulenum <= last) 263845f61351SMaxim Konovalov show_dyn_ipfw(d, pcwidth, bcwidth); 26399758b77fSLuigi Rizzo } 26409758b77fSLuigi Rizzo } 26419758b77fSLuigi Rizzo } 26429758b77fSLuigi Rizzo 26439758b77fSLuigi Rizzo ac = 0; 26449758b77fSLuigi Rizzo 26459758b77fSLuigi Rizzo done: 26469758b77fSLuigi Rizzo free(data); 26479758b77fSLuigi Rizzo 26489758b77fSLuigi Rizzo if (exitval != EX_OK) 26499758b77fSLuigi Rizzo exit(exitval); 265062ff38aeSLuigi Rizzo #undef NEXT 26519758b77fSLuigi Rizzo } 26529758b77fSLuigi Rizzo 26539758b77fSLuigi Rizzo static void 26549758b77fSLuigi Rizzo show_usage(void) 26559758b77fSLuigi Rizzo { 26569758b77fSLuigi Rizzo fprintf(stderr, "usage: ipfw [options]\n" 26579758b77fSLuigi Rizzo "do \"ipfw -h\" or see ipfw manpage for details\n" 26589758b77fSLuigi Rizzo ); 26599758b77fSLuigi Rizzo exit(EX_USAGE); 26609758b77fSLuigi Rizzo } 26619758b77fSLuigi Rizzo 26629758b77fSLuigi Rizzo static void 26639758b77fSLuigi Rizzo help(void) 26649758b77fSLuigi Rizzo { 2665571f8c1bSLuigi Rizzo fprintf(stderr, 2666571f8c1bSLuigi Rizzo "ipfw syntax summary (but please do read the ipfw(8) manpage):\n" 2667ac6cec51SLuigi Rizzo "ipfw [-abcdefhnNqStTv] <command> where <command> is one of:\n" 2668571f8c1bSLuigi Rizzo "add [num] [set N] [prob x] RULE-BODY\n" 2669571f8c1bSLuigi Rizzo "{pipe|queue} N config PIPE-BODY\n" 2670571f8c1bSLuigi Rizzo "[pipe|queue] {zero|delete|show} [N{,N}]\n" 2671ff2f6fe8SPaolo Pisati "nat N config {ip IPADDR|if IFNAME|log|deny_in|same_ports|unreg_only|reset|\n" 2672ff2f6fe8SPaolo Pisati " reverse|proxy_only|redirect_addr linkspec|\n" 2673ff2f6fe8SPaolo Pisati " redirect_port linkspec|redirect_proto linkspec}\n" 2674571f8c1bSLuigi Rizzo "set [disable N... enable N...] | move [rule] X to Y | swap X Y | show\n" 2675cd8b5ae0SRuslan Ermilov "table N {add ip[/bits] [value] | delete ip[/bits] | flush | list}\n" 26769758b77fSLuigi Rizzo "\n" 2677974dfe30SBrian Feldman "RULE-BODY: check-state [PARAMS] | ACTION [PARAMS] ADDR [OPTION_LIST]\n" 26789066356bSBjoern A. Zeeb "ACTION: check-state | allow | count | deny | unreach{,6} CODE |\n" 26799066356bSBjoern A. Zeeb " skipto N | {divert|tee} PORT | forward ADDR |\n" 2680ff2f6fe8SPaolo Pisati " pipe N | queue N | nat N\n" 2681974dfe30SBrian Feldman "PARAMS: [log [logamount LOGLIMIT]] [altq QUEUE_NAME]\n" 26829758b77fSLuigi Rizzo "ADDR: [ MAC dst src ether_type ] \n" 26838195404bSBrooks Davis " [ ip from IPADDR [ PORT ] to IPADDR [ PORTLIST ] ]\n" 26848195404bSBrooks Davis " [ ipv6|ip6 from IP6ADDR [ PORT ] to IP6ADDR [ PORTLIST ] ]\n" 2685cd8b5ae0SRuslan Ermilov "IPADDR: [not] { any | me | ip/bits{x,y,z} | table(t[,v]) | IPLIST }\n" 26868195404bSBrooks Davis "IP6ADDR: [not] { any | me | me6 | ip6/bits | IP6LIST }\n" 26878195404bSBrooks Davis "IP6LIST: { ip6 | ip6/bits }[,IP6LIST]\n" 268826bf4d78SLuigi Rizzo "IPLIST: { ip | ip/bits | ip:mask }[,IPLIST]\n" 268926bf4d78SLuigi Rizzo "OPTION_LIST: OPTION [OPTION_LIST]\n" 269017db1a04SBrian Feldman "OPTION: bridged | diverted | diverted-loopback | diverted-output |\n" 26918195404bSBrooks Davis " {dst-ip|src-ip} IPADDR | {dst-ip6|src-ip6|dst-ipv6|src-ipv6} IP6ADDR |\n" 26928195404bSBrooks Davis " {dst-port|src-port} LIST |\n" 2693571f8c1bSLuigi Rizzo " estab | frag | {gid|uid} N | icmptypes LIST | in | out | ipid LIST |\n" 2694571f8c1bSLuigi Rizzo " iplen LIST | ipoptions SPEC | ipprecedence | ipsec | iptos SPEC |\n" 2695571f8c1bSLuigi Rizzo " ipttl LIST | ipversion VER | keep-state | layer2 | limit ... |\n" 26968195404bSBrooks Davis " icmp6types LIST | ext6hdr LIST | flow-id N[,N] |\n" 2697571f8c1bSLuigi Rizzo " mac ... | mac-type LIST | proto LIST | {recv|xmit|via} {IF|IPADDR} |\n" 2698571f8c1bSLuigi Rizzo " setup | {tcpack|tcpseq|tcpwin} NN | tcpflags SPEC | tcpoptions SPEC |\n" 2699c99ee9e0SBrian Feldman " tcpdatalen LIST | verrevpath | versrcreach | antispoof\n" 27009758b77fSLuigi Rizzo ); 27019758b77fSLuigi Rizzo exit(0); 27029758b77fSLuigi Rizzo } 27039758b77fSLuigi Rizzo 27049758b77fSLuigi Rizzo 27059758b77fSLuigi Rizzo static int 27069758b77fSLuigi Rizzo lookup_host (char *host, struct in_addr *ipaddr) 27079758b77fSLuigi Rizzo { 27089758b77fSLuigi Rizzo struct hostent *he; 27099758b77fSLuigi Rizzo 27109758b77fSLuigi Rizzo if (!inet_aton(host, ipaddr)) { 27119758b77fSLuigi Rizzo if ((he = gethostbyname(host)) == NULL) 27129758b77fSLuigi Rizzo return(-1); 27139758b77fSLuigi Rizzo *ipaddr = *(struct in_addr *)he->h_addr_list[0]; 27149758b77fSLuigi Rizzo } 27159758b77fSLuigi Rizzo return(0); 27169758b77fSLuigi Rizzo } 27179758b77fSLuigi Rizzo 27189758b77fSLuigi Rizzo /* 27199758b77fSLuigi Rizzo * fills the addr and mask fields in the instruction as appropriate from av. 27209758b77fSLuigi Rizzo * Update length as appropriate. 27219758b77fSLuigi Rizzo * The following formats are allowed: 27229758b77fSLuigi Rizzo * me returns O_IP_*_ME 27239758b77fSLuigi Rizzo * 1.2.3.4 single IP address 27249758b77fSLuigi Rizzo * 1.2.3.4:5.6.7.8 address:mask 27259758b77fSLuigi Rizzo * 1.2.3.4/24 address/mask 27269758b77fSLuigi Rizzo * 1.2.3.4/26{1,6,5,4,23} set of addresses in a subnet 2727571f8c1bSLuigi Rizzo * We can have multiple comma-separated address/mask entries. 27289758b77fSLuigi Rizzo */ 27299758b77fSLuigi Rizzo static void 27309758b77fSLuigi Rizzo fill_ip(ipfw_insn_ip *cmd, char *av) 27319758b77fSLuigi Rizzo { 2732571f8c1bSLuigi Rizzo int len = 0; 2733571f8c1bSLuigi Rizzo uint32_t *d = ((ipfw_insn_u32 *)cmd)->d; 27349758b77fSLuigi Rizzo 27359758b77fSLuigi Rizzo cmd->o.len &= ~F_LEN_MASK; /* zero len */ 27369758b77fSLuigi Rizzo 273701750186SBrooks Davis if (_substrcmp(av, "any") == 0) 27389758b77fSLuigi Rizzo return; 27399758b77fSLuigi Rizzo 274001750186SBrooks Davis if (_substrcmp(av, "me") == 0) { 27419758b77fSLuigi Rizzo cmd->o.len |= F_INSN_SIZE(ipfw_insn); 27429758b77fSLuigi Rizzo return; 27439758b77fSLuigi Rizzo } 27449758b77fSLuigi Rizzo 274501750186SBrooks Davis if (strncmp(av, "table(", 6) == 0) { 2746cd8b5ae0SRuslan Ermilov char *p = strchr(av + 6, ','); 2747cd8b5ae0SRuslan Ermilov 2748cd8b5ae0SRuslan Ermilov if (p) 2749cd8b5ae0SRuslan Ermilov *p++ = '\0'; 2750cd8b5ae0SRuslan Ermilov cmd->o.opcode = O_IP_DST_LOOKUP; 2751cd8b5ae0SRuslan Ermilov cmd->o.arg1 = strtoul(av + 6, NULL, 0); 2752cd8b5ae0SRuslan Ermilov if (p) { 2753cd8b5ae0SRuslan Ermilov cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32); 2754cd8b5ae0SRuslan Ermilov d[0] = strtoul(p, NULL, 0); 2755cd8b5ae0SRuslan Ermilov } else 2756cd8b5ae0SRuslan Ermilov cmd->o.len |= F_INSN_SIZE(ipfw_insn); 2757cd8b5ae0SRuslan Ermilov return; 2758cd8b5ae0SRuslan Ermilov } 2759cd8b5ae0SRuslan Ermilov 2760571f8c1bSLuigi Rizzo while (av) { 2761571f8c1bSLuigi Rizzo /* 2762571f8c1bSLuigi Rizzo * After the address we can have '/' or ':' indicating a mask, 2763571f8c1bSLuigi Rizzo * ',' indicating another address follows, '{' indicating a 2764571f8c1bSLuigi Rizzo * set of addresses of unspecified size. 2765571f8c1bSLuigi Rizzo */ 2766c2221c35SMax Laier char *t = NULL, *p = strpbrk(av, "/:,{"); 2767571f8c1bSLuigi Rizzo int masklen; 2768c2221c35SMax Laier char md, nd; 2769571f8c1bSLuigi Rizzo 27709758b77fSLuigi Rizzo if (p) { 27719758b77fSLuigi Rizzo md = *p; 27729758b77fSLuigi Rizzo *p++ = '\0'; 2773c2221c35SMax Laier if ((t = strpbrk(p, ",{")) != NULL) { 2774c2221c35SMax Laier nd = *t; 2775c2221c35SMax Laier *t = '\0'; 2776c2221c35SMax Laier } 2777571f8c1bSLuigi Rizzo } else 2778571f8c1bSLuigi Rizzo md = '\0'; 27799758b77fSLuigi Rizzo 2780571f8c1bSLuigi Rizzo if (lookup_host(av, (struct in_addr *)&d[0]) != 0) 27819758b77fSLuigi Rizzo errx(EX_NOHOST, "hostname ``%s'' unknown", av); 27829758b77fSLuigi Rizzo switch (md) { 27839758b77fSLuigi Rizzo case ':': 2784571f8c1bSLuigi Rizzo if (!inet_aton(p, (struct in_addr *)&d[1])) 27859758b77fSLuigi Rizzo errx(EX_DATAERR, "bad netmask ``%s''", p); 27869758b77fSLuigi Rizzo break; 27879758b77fSLuigi Rizzo case '/': 2788571f8c1bSLuigi Rizzo masklen = atoi(p); 2789571f8c1bSLuigi Rizzo if (masklen == 0) 2790571f8c1bSLuigi Rizzo d[1] = htonl(0); /* mask */ 2791571f8c1bSLuigi Rizzo else if (masklen > 32) 27929758b77fSLuigi Rizzo errx(EX_DATAERR, "bad width ``%s''", p); 27939758b77fSLuigi Rizzo else 2794571f8c1bSLuigi Rizzo d[1] = htonl(~0 << (32 - masklen)); 27959758b77fSLuigi Rizzo break; 2796571f8c1bSLuigi Rizzo case '{': /* no mask, assume /24 and put back the '{' */ 2797571f8c1bSLuigi Rizzo d[1] = htonl(~0 << (32 - 24)); 2798571f8c1bSLuigi Rizzo *(--p) = md; 2799571f8c1bSLuigi Rizzo break; 2800571f8c1bSLuigi Rizzo 2801571f8c1bSLuigi Rizzo case ',': /* single address plus continuation */ 2802571f8c1bSLuigi Rizzo *(--p) = md; 2803571f8c1bSLuigi Rizzo /* FALLTHROUGH */ 2804571f8c1bSLuigi Rizzo case 0: /* initialization value */ 28059758b77fSLuigi Rizzo default: 2806571f8c1bSLuigi Rizzo d[1] = htonl(~0); /* force /32 */ 28079758b77fSLuigi Rizzo break; 28089758b77fSLuigi Rizzo } 2809571f8c1bSLuigi Rizzo d[0] &= d[1]; /* mask base address with mask */ 2810c2221c35SMax Laier if (t) 2811c2221c35SMax Laier *t = nd; 2812571f8c1bSLuigi Rizzo /* find next separator */ 2813571f8c1bSLuigi Rizzo if (p) 2814571f8c1bSLuigi Rizzo p = strpbrk(p, ",{"); 2815571f8c1bSLuigi Rizzo if (p && *p == '{') { 28169758b77fSLuigi Rizzo /* 2817571f8c1bSLuigi Rizzo * We have a set of addresses. They are stored as follows: 28189758b77fSLuigi Rizzo * arg1 is the set size (powers of 2, 2..256) 28199758b77fSLuigi Rizzo * addr is the base address IN HOST FORMAT 2820571f8c1bSLuigi Rizzo * mask.. is an array of arg1 bits (rounded up to 2821571f8c1bSLuigi Rizzo * the next multiple of 32) with bits set 2822571f8c1bSLuigi Rizzo * for each host in the map. 28239758b77fSLuigi Rizzo */ 2824571f8c1bSLuigi Rizzo uint32_t *map = (uint32_t *)&cmd->mask; 28259758b77fSLuigi Rizzo int low, high; 2826f3a126d3SLuigi Rizzo int i = contigmask((uint8_t *)&(d[1]), 32); 28279758b77fSLuigi Rizzo 2828571f8c1bSLuigi Rizzo if (len > 0) 2829571f8c1bSLuigi Rizzo errx(EX_DATAERR, "address set cannot be in a list"); 2830571f8c1bSLuigi Rizzo if (i < 24 || i > 31) 2831571f8c1bSLuigi Rizzo errx(EX_DATAERR, "invalid set with mask %d\n", i); 2832571f8c1bSLuigi Rizzo cmd->o.arg1 = 1<<(32-i); /* map length */ 2833571f8c1bSLuigi Rizzo d[0] = ntohl(d[0]); /* base addr in host format */ 28349758b77fSLuigi Rizzo cmd->o.opcode = O_IP_DST_SET; /* default */ 28359758b77fSLuigi Rizzo cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32) + (cmd->o.arg1+31)/32; 283661360012SLuigi Rizzo for (i = 0; i < (cmd->o.arg1+31)/32 ; i++) 2837571f8c1bSLuigi Rizzo map[i] = 0; /* clear map */ 28389758b77fSLuigi Rizzo 28399758b77fSLuigi Rizzo av = p + 1; 2840571f8c1bSLuigi Rizzo low = d[0] & 0xff; 28419758b77fSLuigi Rizzo high = low + cmd->o.arg1 - 1; 2842571f8c1bSLuigi Rizzo /* 2843571f8c1bSLuigi Rizzo * Here, i stores the previous value when we specify a range 2844571f8c1bSLuigi Rizzo * of addresses within a mask, e.g. 45-63. i = -1 means we 2845571f8c1bSLuigi Rizzo * have no previous value. 2846571f8c1bSLuigi Rizzo */ 28479ef3f16dSLuigi Rizzo i = -1; /* previous value in a range */ 28489758b77fSLuigi Rizzo while (isdigit(*av)) { 28499758b77fSLuigi Rizzo char *s; 2850571f8c1bSLuigi Rizzo int a = strtol(av, &s, 0); 28519758b77fSLuigi Rizzo 2852571f8c1bSLuigi Rizzo if (s == av) { /* no parameter */ 2853571f8c1bSLuigi Rizzo if (*av != '}') 2854571f8c1bSLuigi Rizzo errx(EX_DATAERR, "set not closed\n"); 2855571f8c1bSLuigi Rizzo if (i != -1) 2856571f8c1bSLuigi Rizzo errx(EX_DATAERR, "incomplete range %d-", i); 28579758b77fSLuigi Rizzo break; 28589758b77fSLuigi Rizzo } 2859571f8c1bSLuigi Rizzo if (a < low || a > high) 2860571f8c1bSLuigi Rizzo errx(EX_DATAERR, "addr %d out of range [%d-%d]\n", 2861571f8c1bSLuigi Rizzo a, low, high); 28629758b77fSLuigi Rizzo a -= low; 28639ef3f16dSLuigi Rizzo if (i == -1) /* no previous in range */ 28649ef3f16dSLuigi Rizzo i = a; 28659ef3f16dSLuigi Rizzo else { /* check that range is valid */ 28669ef3f16dSLuigi Rizzo if (i > a) 28679ef3f16dSLuigi Rizzo errx(EX_DATAERR, "invalid range %d-%d", 28689ef3f16dSLuigi Rizzo i+low, a+low); 28699ef3f16dSLuigi Rizzo if (*s == '-') 28709ef3f16dSLuigi Rizzo errx(EX_DATAERR, "double '-' in range"); 28719ef3f16dSLuigi Rizzo } 28729ef3f16dSLuigi Rizzo for (; i <= a; i++) 2873571f8c1bSLuigi Rizzo map[i/32] |= 1<<(i & 31); 28749ef3f16dSLuigi Rizzo i = -1; 28759ef3f16dSLuigi Rizzo if (*s == '-') 28769ef3f16dSLuigi Rizzo i = a; 2877571f8c1bSLuigi Rizzo else if (*s == '}') 28789758b77fSLuigi Rizzo break; 28799758b77fSLuigi Rizzo av = s+1; 28809758b77fSLuigi Rizzo } 28819758b77fSLuigi Rizzo return; 28829758b77fSLuigi Rizzo } 2883571f8c1bSLuigi Rizzo av = p; 2884571f8c1bSLuigi Rizzo if (av) /* then *av must be a ',' */ 2885571f8c1bSLuigi Rizzo av++; 28869758b77fSLuigi Rizzo 2887571f8c1bSLuigi Rizzo /* Check this entry */ 2888571f8c1bSLuigi Rizzo if (d[1] == 0) { /* "any", specified as x.x.x.x/0 */ 2889571f8c1bSLuigi Rizzo /* 2890571f8c1bSLuigi Rizzo * 'any' turns the entire list into a NOP. 2891571f8c1bSLuigi Rizzo * 'not any' never matches, so it is removed from the 2892571f8c1bSLuigi Rizzo * list unless it is the only item, in which case we 2893571f8c1bSLuigi Rizzo * report an error. 2894571f8c1bSLuigi Rizzo */ 2895571f8c1bSLuigi Rizzo if (cmd->o.len & F_NOT) { /* "not any" never matches */ 2896571f8c1bSLuigi Rizzo if (av == NULL && len == 0) /* only this entry */ 28979758b77fSLuigi Rizzo errx(EX_DATAERR, "not any never matches"); 2898571f8c1bSLuigi Rizzo } 2899571f8c1bSLuigi Rizzo /* else do nothing and skip this entry */ 290014533a98SMaxim Konovalov return; 2901571f8c1bSLuigi Rizzo } 2902571f8c1bSLuigi Rizzo /* A single IP can be stored in an optimized format */ 2903571f8c1bSLuigi Rizzo if (d[1] == IP_MASK_ALL && av == NULL && len == 0) { 29049758b77fSLuigi Rizzo cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32); 2905571f8c1bSLuigi Rizzo return; 2906571f8c1bSLuigi Rizzo } 2907571f8c1bSLuigi Rizzo len += 2; /* two words... */ 2908571f8c1bSLuigi Rizzo d += 2; 2909571f8c1bSLuigi Rizzo } /* end while */ 2910268f526cSJohn Hay if (len + 1 > F_LEN_MASK) 2911268f526cSJohn Hay errx(EX_DATAERR, "address list too long"); 2912571f8c1bSLuigi Rizzo cmd->o.len |= len+1; 29139758b77fSLuigi Rizzo } 29149758b77fSLuigi Rizzo 29159758b77fSLuigi Rizzo 29168195404bSBrooks Davis /* Try to find ipv6 address by hostname */ 29178195404bSBrooks Davis static int 29188195404bSBrooks Davis lookup_host6 (char *host, struct in6_addr *ip6addr) 29198195404bSBrooks Davis { 29208195404bSBrooks Davis struct hostent *he; 29218195404bSBrooks Davis 29228195404bSBrooks Davis if (!inet_pton(AF_INET6, host, ip6addr)) { 29238195404bSBrooks Davis if ((he = gethostbyname2(host, AF_INET6)) == NULL) 29248195404bSBrooks Davis return(-1); 29258195404bSBrooks Davis memcpy(ip6addr, he->h_addr_list[0], sizeof( struct in6_addr)); 29268195404bSBrooks Davis } 29278195404bSBrooks Davis return(0); 29288195404bSBrooks Davis } 29298195404bSBrooks Davis 29308195404bSBrooks Davis 29318195404bSBrooks Davis /* n2mask sets n bits of the mask */ 29328195404bSBrooks Davis static void 29338195404bSBrooks Davis n2mask(struct in6_addr *mask, int n) 29348195404bSBrooks Davis { 29358195404bSBrooks Davis static int minimask[9] = 29368195404bSBrooks Davis { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff }; 29378195404bSBrooks Davis u_char *p; 29388195404bSBrooks Davis 29398195404bSBrooks Davis memset(mask, 0, sizeof(struct in6_addr)); 29408195404bSBrooks Davis p = (u_char *) mask; 29418195404bSBrooks Davis for (; n > 0; p++, n -= 8) { 29428195404bSBrooks Davis if (n >= 8) 29438195404bSBrooks Davis *p = 0xff; 29448195404bSBrooks Davis else 29458195404bSBrooks Davis *p = minimask[n]; 29468195404bSBrooks Davis } 29478195404bSBrooks Davis return; 29488195404bSBrooks Davis } 29498195404bSBrooks Davis 29508195404bSBrooks Davis 29518195404bSBrooks Davis /* 29528195404bSBrooks Davis * fill the addr and mask fields in the instruction as appropriate from av. 29538195404bSBrooks Davis * Update length as appropriate. 29548195404bSBrooks Davis * The following formats are allowed: 29558195404bSBrooks Davis * any matches any IP6. Actually returns an empty instruction. 29568195404bSBrooks Davis * me returns O_IP6_*_ME 29578195404bSBrooks Davis * 29588195404bSBrooks Davis * 03f1::234:123:0342 single IP6 addres 29598195404bSBrooks Davis * 03f1::234:123:0342/24 address/mask 29608195404bSBrooks Davis * 03f1::234:123:0342/24,03f1::234:123:0343/ List of address 29618195404bSBrooks Davis * 29628195404bSBrooks Davis * Set of address (as in ipv6) not supported because ipv6 address 29638195404bSBrooks Davis * are typically random past the initial prefix. 29648195404bSBrooks Davis * Return 1 on success, 0 on failure. 29658195404bSBrooks Davis */ 29668195404bSBrooks Davis static int 29678195404bSBrooks Davis fill_ip6(ipfw_insn_ip6 *cmd, char *av) 29688195404bSBrooks Davis { 29698195404bSBrooks Davis int len = 0; 29708195404bSBrooks Davis struct in6_addr *d = &(cmd->addr6); 29718195404bSBrooks Davis /* 29728195404bSBrooks Davis * Needed for multiple address. 29738195404bSBrooks Davis * Note d[1] points to struct in6_add r mask6 of cmd 29748195404bSBrooks Davis */ 29758195404bSBrooks Davis 29768195404bSBrooks Davis cmd->o.len &= ~F_LEN_MASK; /* zero len */ 29778195404bSBrooks Davis 29788195404bSBrooks Davis if (strcmp(av, "any") == 0) 29798195404bSBrooks Davis return (1); 29808195404bSBrooks Davis 29818195404bSBrooks Davis 29828195404bSBrooks Davis if (strcmp(av, "me") == 0) { /* Set the data for "me" opt*/ 29838195404bSBrooks Davis cmd->o.len |= F_INSN_SIZE(ipfw_insn); 29848195404bSBrooks Davis return (1); 29858195404bSBrooks Davis } 29868195404bSBrooks Davis 29878195404bSBrooks Davis if (strcmp(av, "me6") == 0) { /* Set the data for "me" opt*/ 29888195404bSBrooks Davis cmd->o.len |= F_INSN_SIZE(ipfw_insn); 29898195404bSBrooks Davis return (1); 29908195404bSBrooks Davis } 29918195404bSBrooks Davis 29928195404bSBrooks Davis av = strdup(av); 29938195404bSBrooks Davis while (av) { 29948195404bSBrooks Davis /* 29958195404bSBrooks Davis * After the address we can have '/' indicating a mask, 29968195404bSBrooks Davis * or ',' indicating another address follows. 29978195404bSBrooks Davis */ 29988195404bSBrooks Davis 29998195404bSBrooks Davis char *p; 30008195404bSBrooks Davis int masklen; 30018195404bSBrooks Davis char md = '\0'; 30028195404bSBrooks Davis 30038195404bSBrooks Davis if ((p = strpbrk(av, "/,")) ) { 30048195404bSBrooks Davis md = *p; /* save the separator */ 30058195404bSBrooks Davis *p = '\0'; /* terminate address string */ 30068195404bSBrooks Davis p++; /* and skip past it */ 30078195404bSBrooks Davis } 30088195404bSBrooks Davis /* now p points to NULL, mask or next entry */ 30098195404bSBrooks Davis 30108195404bSBrooks Davis /* lookup stores address in *d as a side effect */ 30118195404bSBrooks Davis if (lookup_host6(av, d) != 0) { 30128195404bSBrooks Davis /* XXX: failed. Free memory and go */ 30138195404bSBrooks Davis errx(EX_DATAERR, "bad address \"%s\"", av); 30148195404bSBrooks Davis } 30158195404bSBrooks Davis /* next, look at the mask, if any */ 30168195404bSBrooks Davis masklen = (md == '/') ? atoi(p) : 128; 30178195404bSBrooks Davis if (masklen > 128 || masklen < 0) 30188195404bSBrooks Davis errx(EX_DATAERR, "bad width \"%s\''", p); 30198195404bSBrooks Davis else 30208195404bSBrooks Davis n2mask(&d[1], masklen); 30218195404bSBrooks Davis 30228195404bSBrooks Davis APPLY_MASK(d, &d[1]) /* mask base address with mask */ 30238195404bSBrooks Davis 30248195404bSBrooks Davis /* find next separator */ 30258195404bSBrooks Davis 30268195404bSBrooks Davis if (md == '/') { /* find separator past the mask */ 30278195404bSBrooks Davis p = strpbrk(p, ","); 30288195404bSBrooks Davis if (p != NULL) 30298195404bSBrooks Davis p++; 30308195404bSBrooks Davis } 30318195404bSBrooks Davis av = p; 30328195404bSBrooks Davis 30338195404bSBrooks Davis /* Check this entry */ 30348195404bSBrooks Davis if (masklen == 0) { 30358195404bSBrooks Davis /* 30368195404bSBrooks Davis * 'any' turns the entire list into a NOP. 30378195404bSBrooks Davis * 'not any' never matches, so it is removed from the 30388195404bSBrooks Davis * list unless it is the only item, in which case we 30398195404bSBrooks Davis * report an error. 30408195404bSBrooks Davis */ 30418195404bSBrooks Davis if (cmd->o.len & F_NOT && av == NULL && len == 0) 30428195404bSBrooks Davis errx(EX_DATAERR, "not any never matches"); 30438195404bSBrooks Davis continue; 30448195404bSBrooks Davis } 30458195404bSBrooks Davis 30468195404bSBrooks Davis /* 30478195404bSBrooks Davis * A single IP can be stored alone 30488195404bSBrooks Davis */ 30498195404bSBrooks Davis if (masklen == 128 && av == NULL && len == 0) { 30508195404bSBrooks Davis len = F_INSN_SIZE(struct in6_addr); 30518195404bSBrooks Davis break; 30528195404bSBrooks Davis } 30538195404bSBrooks Davis 30548195404bSBrooks Davis /* Update length and pointer to arguments */ 30558195404bSBrooks Davis len += F_INSN_SIZE(struct in6_addr)*2; 30568195404bSBrooks Davis d += 2; 30578195404bSBrooks Davis } /* end while */ 30588195404bSBrooks Davis 30598195404bSBrooks Davis /* 30608195404bSBrooks Davis * Total length of the command, remember that 1 is the size of 30618195404bSBrooks Davis * the base command. 30628195404bSBrooks Davis */ 3063268f526cSJohn Hay if (len + 1 > F_LEN_MASK) 3064268f526cSJohn Hay errx(EX_DATAERR, "address list too long"); 30658195404bSBrooks Davis cmd->o.len |= len+1; 30668195404bSBrooks Davis free(av); 30678195404bSBrooks Davis return (1); 30688195404bSBrooks Davis } 30698195404bSBrooks Davis 30708195404bSBrooks Davis /* 30718195404bSBrooks Davis * fills command for ipv6 flow-id filtering 30728195404bSBrooks Davis * note that the 20 bit flow number is stored in a array of u_int32_t 30738195404bSBrooks Davis * it's supported lists of flow-id, so in the o.arg1 we store how many 30748195404bSBrooks Davis * additional flow-id we want to filter, the basic is 1 30758195404bSBrooks Davis */ 30768195404bSBrooks Davis void 30778195404bSBrooks Davis fill_flow6( ipfw_insn_u32 *cmd, char *av ) 30788195404bSBrooks Davis { 30798195404bSBrooks Davis u_int32_t type; /* Current flow number */ 30808195404bSBrooks Davis u_int16_t nflow = 0; /* Current flow index */ 30818195404bSBrooks Davis char *s = av; 30828195404bSBrooks Davis cmd->d[0] = 0; /* Initializing the base number*/ 30838195404bSBrooks Davis 30848195404bSBrooks Davis while (s) { 30858195404bSBrooks Davis av = strsep( &s, ",") ; 30868195404bSBrooks Davis type = strtoul(av, &av, 0); 30878195404bSBrooks Davis if (*av != ',' && *av != '\0') 30888195404bSBrooks Davis errx(EX_DATAERR, "invalid ipv6 flow number %s", av); 30898195404bSBrooks Davis if (type > 0xfffff) 30908195404bSBrooks Davis errx(EX_DATAERR, "flow number out of range %s", av); 30918195404bSBrooks Davis cmd->d[nflow] |= type; 30928195404bSBrooks Davis nflow++; 30938195404bSBrooks Davis } 30948195404bSBrooks Davis if( nflow > 0 ) { 30958195404bSBrooks Davis cmd->o.opcode = O_FLOW6ID; 30968195404bSBrooks Davis cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32) + nflow; 30978195404bSBrooks Davis cmd->o.arg1 = nflow; 30988195404bSBrooks Davis } 30998195404bSBrooks Davis else { 31008195404bSBrooks Davis errx(EX_DATAERR, "invalid ipv6 flow number %s", av); 31018195404bSBrooks Davis } 31028195404bSBrooks Davis } 31038195404bSBrooks Davis 31048195404bSBrooks Davis static ipfw_insn * 31058195404bSBrooks Davis add_srcip6(ipfw_insn *cmd, char *av) 31068195404bSBrooks Davis { 31078195404bSBrooks Davis 31088195404bSBrooks Davis fill_ip6((ipfw_insn_ip6 *)cmd, av); 31098195404bSBrooks Davis if (F_LEN(cmd) == 0) /* any */ 31108195404bSBrooks Davis ; 31118195404bSBrooks Davis if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) { /* "me" */ 31128195404bSBrooks Davis cmd->opcode = O_IP6_SRC_ME; 31138195404bSBrooks Davis } else if (F_LEN(cmd) == 31148195404bSBrooks Davis (F_INSN_SIZE(struct in6_addr) + F_INSN_SIZE(ipfw_insn))) { 31158195404bSBrooks Davis /* single IP, no mask*/ 31168195404bSBrooks Davis cmd->opcode = O_IP6_SRC; 31178195404bSBrooks Davis } else { /* addr/mask opt */ 31188195404bSBrooks Davis cmd->opcode = O_IP6_SRC_MASK; 31198195404bSBrooks Davis } 31208195404bSBrooks Davis return cmd; 31218195404bSBrooks Davis } 31228195404bSBrooks Davis 31238195404bSBrooks Davis static ipfw_insn * 31248195404bSBrooks Davis add_dstip6(ipfw_insn *cmd, char *av) 31258195404bSBrooks Davis { 31268195404bSBrooks Davis 31278195404bSBrooks Davis fill_ip6((ipfw_insn_ip6 *)cmd, av); 31288195404bSBrooks Davis if (F_LEN(cmd) == 0) /* any */ 31298195404bSBrooks Davis ; 31308195404bSBrooks Davis if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) { /* "me" */ 31318195404bSBrooks Davis cmd->opcode = O_IP6_DST_ME; 31328195404bSBrooks Davis } else if (F_LEN(cmd) == 31338195404bSBrooks Davis (F_INSN_SIZE(struct in6_addr) + F_INSN_SIZE(ipfw_insn))) { 31348195404bSBrooks Davis /* single IP, no mask*/ 31358195404bSBrooks Davis cmd->opcode = O_IP6_DST; 31368195404bSBrooks Davis } else { /* addr/mask opt */ 31378195404bSBrooks Davis cmd->opcode = O_IP6_DST_MASK; 31388195404bSBrooks Davis } 31398195404bSBrooks Davis return cmd; 31408195404bSBrooks Davis } 31418195404bSBrooks Davis 31428195404bSBrooks Davis 31439758b77fSLuigi Rizzo /* 31449758b77fSLuigi Rizzo * helper function to process a set of flags and set bits in the 31459758b77fSLuigi Rizzo * appropriate masks. 31469758b77fSLuigi Rizzo */ 31479758b77fSLuigi Rizzo static void 31489758b77fSLuigi Rizzo fill_flags(ipfw_insn *cmd, enum ipfw_opcodes opcode, 31499758b77fSLuigi Rizzo struct _s_x *flags, char *p) 31509758b77fSLuigi Rizzo { 3151571f8c1bSLuigi Rizzo uint8_t set=0, clear=0; 31529758b77fSLuigi Rizzo 31539758b77fSLuigi Rizzo while (p && *p) { 31549758b77fSLuigi Rizzo char *q; /* points to the separator */ 31559758b77fSLuigi Rizzo int val; 3156571f8c1bSLuigi Rizzo uint8_t *which; /* mask we are working on */ 31579758b77fSLuigi Rizzo 31589758b77fSLuigi Rizzo if (*p == '!') { 31599758b77fSLuigi Rizzo p++; 31609758b77fSLuigi Rizzo which = &clear; 31619758b77fSLuigi Rizzo } else 31629758b77fSLuigi Rizzo which = &set; 31639758b77fSLuigi Rizzo q = strchr(p, ','); 31649758b77fSLuigi Rizzo if (q) 31659758b77fSLuigi Rizzo *q++ = '\0'; 31669758b77fSLuigi Rizzo val = match_token(flags, p); 31679758b77fSLuigi Rizzo if (val <= 0) 31689758b77fSLuigi Rizzo errx(EX_DATAERR, "invalid flag %s", p); 3169571f8c1bSLuigi Rizzo *which |= (uint8_t)val; 31709758b77fSLuigi Rizzo p = q; 31719758b77fSLuigi Rizzo } 31729758b77fSLuigi Rizzo cmd->opcode = opcode; 31739758b77fSLuigi Rizzo cmd->len = (cmd->len & (F_NOT | F_OR)) | 1; 31749758b77fSLuigi Rizzo cmd->arg1 = (set & 0xff) | ( (clear & 0xff) << 8); 31759758b77fSLuigi Rizzo } 31769758b77fSLuigi Rizzo 31779758b77fSLuigi Rizzo 31789758b77fSLuigi Rizzo static void 31799758b77fSLuigi Rizzo delete(int ac, char *av[]) 31809758b77fSLuigi Rizzo { 3181571f8c1bSLuigi Rizzo uint32_t rulenum; 318262ff38aeSLuigi Rizzo struct dn_pipe p; 31839758b77fSLuigi Rizzo int i; 31849758b77fSLuigi Rizzo int exitval = EX_OK; 318543405724SLuigi Rizzo int do_set = 0; 31869758b77fSLuigi Rizzo 318762ff38aeSLuigi Rizzo memset(&p, 0, sizeof p); 31889758b77fSLuigi Rizzo 31899758b77fSLuigi Rizzo av++; ac--; 319004f70834SChristian S.J. Peron NEED1("missing rule specification"); 319101750186SBrooks Davis if (ac > 0 && _substrcmp(*av, "set") == 0) { 319243405724SLuigi Rizzo do_set = 1; /* delete set */ 319343405724SLuigi Rizzo ac--; av++; 319499e5e645SLuigi Rizzo } 31959758b77fSLuigi Rizzo 31969758b77fSLuigi Rizzo /* Rule number */ 31979758b77fSLuigi Rizzo while (ac && isdigit(**av)) { 31989758b77fSLuigi Rizzo i = atoi(*av); av++; ac--; 3199ff2f6fe8SPaolo Pisati if (do_nat) { 3200ff2f6fe8SPaolo Pisati exitval = do_cmd(IP_FW_NAT_DEL, &i, sizeof i); 3201ff2f6fe8SPaolo Pisati if (exitval) { 3202ff2f6fe8SPaolo Pisati exitval = EX_UNAVAILABLE; 3203ff2f6fe8SPaolo Pisati warn("rule %u not available", i); 3204ff2f6fe8SPaolo Pisati } 3205ff2f6fe8SPaolo Pisati } else if (do_pipe) { 32069758b77fSLuigi Rizzo if (do_pipe == 1) 320762ff38aeSLuigi Rizzo p.pipe_nr = i; 32089758b77fSLuigi Rizzo else 320962ff38aeSLuigi Rizzo p.fs.fs_nr = i; 321062ff38aeSLuigi Rizzo i = do_cmd(IP_DUMMYNET_DEL, &p, sizeof p); 32119758b77fSLuigi Rizzo if (i) { 32129758b77fSLuigi Rizzo exitval = 1; 32139758b77fSLuigi Rizzo warn("rule %u: setsockopt(IP_DUMMYNET_DEL)", 321462ff38aeSLuigi Rizzo do_pipe == 1 ? p.pipe_nr : p.fs.fs_nr); 32159758b77fSLuigi Rizzo } 32169758b77fSLuigi Rizzo } else { 321799e5e645SLuigi Rizzo rulenum = (i & 0xffff) | (do_set << 24); 3218571f8c1bSLuigi Rizzo i = do_cmd(IP_FW_DEL, &rulenum, sizeof rulenum); 32199758b77fSLuigi Rizzo if (i) { 32209758b77fSLuigi Rizzo exitval = EX_UNAVAILABLE; 32219758b77fSLuigi Rizzo warn("rule %u: setsockopt(IP_FW_DEL)", 32229758b77fSLuigi Rizzo rulenum); 32239758b77fSLuigi Rizzo } 32249758b77fSLuigi Rizzo } 32259758b77fSLuigi Rizzo } 32269758b77fSLuigi Rizzo if (exitval != EX_OK) 32279758b77fSLuigi Rizzo exit(exitval); 32289758b77fSLuigi Rizzo } 32299758b77fSLuigi Rizzo 32309758b77fSLuigi Rizzo 32319758b77fSLuigi Rizzo /* 32329758b77fSLuigi Rizzo * fill the interface structure. We do not check the name as we can 32339758b77fSLuigi Rizzo * create interfaces dynamically, so checking them at insert time 32349758b77fSLuigi Rizzo * makes relatively little sense. 32359bf40edeSBrooks Davis * Interface names containing '*', '?', or '[' are assumed to be shell 32369bf40edeSBrooks Davis * patterns which match interfaces. 32379758b77fSLuigi Rizzo */ 32389758b77fSLuigi Rizzo static void 32399758b77fSLuigi Rizzo fill_iface(ipfw_insn_if *cmd, char *arg) 32409758b77fSLuigi Rizzo { 32419758b77fSLuigi Rizzo cmd->name[0] = '\0'; 32429758b77fSLuigi Rizzo cmd->o.len |= F_INSN_SIZE(ipfw_insn_if); 32439758b77fSLuigi Rizzo 32449758b77fSLuigi Rizzo /* Parse the interface or address */ 324501750186SBrooks Davis if (strcmp(arg, "any") == 0) 32469758b77fSLuigi Rizzo cmd->o.len = 0; /* effectively ignore this command */ 32479758b77fSLuigi Rizzo else if (!isdigit(*arg)) { 32489bf40edeSBrooks Davis strlcpy(cmd->name, arg, sizeof(cmd->name)); 32499bf40edeSBrooks Davis cmd->p.glob = strpbrk(arg, "*?[") != NULL ? 1 : 0; 32509758b77fSLuigi Rizzo } else if (!inet_aton(arg, &cmd->p.ip)) 32519758b77fSLuigi Rizzo errx(EX_DATAERR, "bad ip address ``%s''", arg); 32529758b77fSLuigi Rizzo } 32539758b77fSLuigi Rizzo 3254ff2f6fe8SPaolo Pisati /* 3255ff2f6fe8SPaolo Pisati * Search for interface with name "ifn", and fill n accordingly: 3256ff2f6fe8SPaolo Pisati * 3257ff2f6fe8SPaolo Pisati * n->ip ip address of interface "ifn" 3258ff2f6fe8SPaolo Pisati * n->if_name copy of interface name "ifn" 3259ff2f6fe8SPaolo Pisati */ 3260ff2f6fe8SPaolo Pisati static void 3261ff2f6fe8SPaolo Pisati set_addr_dynamic(const char *ifn, struct cfg_nat *n) 3262ff2f6fe8SPaolo Pisati { 3263ff2f6fe8SPaolo Pisati size_t needed; 3264ff2f6fe8SPaolo Pisati int mib[6]; 3265ff2f6fe8SPaolo Pisati char *buf, *lim, *next; 3266ff2f6fe8SPaolo Pisati struct if_msghdr *ifm; 3267ff2f6fe8SPaolo Pisati struct ifa_msghdr *ifam; 3268ff2f6fe8SPaolo Pisati struct sockaddr_dl *sdl; 3269ff2f6fe8SPaolo Pisati struct sockaddr_in *sin; 3270ff2f6fe8SPaolo Pisati int ifIndex, ifMTU; 3271ff2f6fe8SPaolo Pisati 3272ff2f6fe8SPaolo Pisati mib[0] = CTL_NET; 3273ff2f6fe8SPaolo Pisati mib[1] = PF_ROUTE; 3274ff2f6fe8SPaolo Pisati mib[2] = 0; 3275ff2f6fe8SPaolo Pisati mib[3] = AF_INET; 3276ff2f6fe8SPaolo Pisati mib[4] = NET_RT_IFLIST; 3277ff2f6fe8SPaolo Pisati mib[5] = 0; 3278ff2f6fe8SPaolo Pisati /* 3279ff2f6fe8SPaolo Pisati * Get interface data. 3280ff2f6fe8SPaolo Pisati */ 3281ff2f6fe8SPaolo Pisati if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1) 3282ff2f6fe8SPaolo Pisati err(1, "iflist-sysctl-estimate"); 3283ff2f6fe8SPaolo Pisati if ((buf = malloc(needed)) == NULL) 3284ff2f6fe8SPaolo Pisati errx(1, "malloc failed"); 3285ff2f6fe8SPaolo Pisati if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1) 3286ff2f6fe8SPaolo Pisati err(1, "iflist-sysctl-get"); 3287ff2f6fe8SPaolo Pisati lim = buf + needed; 3288ff2f6fe8SPaolo Pisati /* 3289ff2f6fe8SPaolo Pisati * Loop through interfaces until one with 3290ff2f6fe8SPaolo Pisati * given name is found. This is done to 3291ff2f6fe8SPaolo Pisati * find correct interface index for routing 3292ff2f6fe8SPaolo Pisati * message processing. 3293ff2f6fe8SPaolo Pisati */ 3294ff2f6fe8SPaolo Pisati ifIndex = 0; 3295ff2f6fe8SPaolo Pisati next = buf; 3296ff2f6fe8SPaolo Pisati while (next < lim) { 3297ff2f6fe8SPaolo Pisati ifm = (struct if_msghdr *)next; 3298ff2f6fe8SPaolo Pisati next += ifm->ifm_msglen; 3299ff2f6fe8SPaolo Pisati if (ifm->ifm_version != RTM_VERSION) { 3300ff2f6fe8SPaolo Pisati if (verbose) 3301ff2f6fe8SPaolo Pisati warnx("routing message version %d " 3302ff2f6fe8SPaolo Pisati "not understood", ifm->ifm_version); 3303ff2f6fe8SPaolo Pisati continue; 3304ff2f6fe8SPaolo Pisati } 3305ff2f6fe8SPaolo Pisati if (ifm->ifm_type == RTM_IFINFO) { 3306ff2f6fe8SPaolo Pisati sdl = (struct sockaddr_dl *)(ifm + 1); 3307ff2f6fe8SPaolo Pisati if (strlen(ifn) == sdl->sdl_nlen && 3308ff2f6fe8SPaolo Pisati strncmp(ifn, sdl->sdl_data, sdl->sdl_nlen) == 0) { 3309ff2f6fe8SPaolo Pisati ifIndex = ifm->ifm_index; 3310ff2f6fe8SPaolo Pisati ifMTU = ifm->ifm_data.ifi_mtu; 3311ff2f6fe8SPaolo Pisati break; 3312ff2f6fe8SPaolo Pisati } 3313ff2f6fe8SPaolo Pisati } 3314ff2f6fe8SPaolo Pisati } 3315ff2f6fe8SPaolo Pisati if (!ifIndex) 3316ff2f6fe8SPaolo Pisati errx(1, "unknown interface name %s", ifn); 3317ff2f6fe8SPaolo Pisati /* 3318ff2f6fe8SPaolo Pisati * Get interface address. 3319ff2f6fe8SPaolo Pisati */ 3320ff2f6fe8SPaolo Pisati sin = NULL; 3321ff2f6fe8SPaolo Pisati while (next < lim) { 3322ff2f6fe8SPaolo Pisati ifam = (struct ifa_msghdr *)next; 3323ff2f6fe8SPaolo Pisati next += ifam->ifam_msglen; 3324ff2f6fe8SPaolo Pisati if (ifam->ifam_version != RTM_VERSION) { 3325ff2f6fe8SPaolo Pisati if (verbose) 3326ff2f6fe8SPaolo Pisati warnx("routing message version %d " 3327ff2f6fe8SPaolo Pisati "not understood", ifam->ifam_version); 3328ff2f6fe8SPaolo Pisati continue; 3329ff2f6fe8SPaolo Pisati } 3330ff2f6fe8SPaolo Pisati if (ifam->ifam_type != RTM_NEWADDR) 3331ff2f6fe8SPaolo Pisati break; 3332ff2f6fe8SPaolo Pisati if (ifam->ifam_addrs & RTA_IFA) { 3333ff2f6fe8SPaolo Pisati int i; 3334ff2f6fe8SPaolo Pisati char *cp = (char *)(ifam + 1); 3335ff2f6fe8SPaolo Pisati 3336ff2f6fe8SPaolo Pisati for (i = 1; i < RTA_IFA; i <<= 1) { 3337ff2f6fe8SPaolo Pisati if (ifam->ifam_addrs & i) 3338ff2f6fe8SPaolo Pisati cp += SA_SIZE((struct sockaddr *)cp); 3339ff2f6fe8SPaolo Pisati } 3340ff2f6fe8SPaolo Pisati if (((struct sockaddr *)cp)->sa_family == AF_INET) { 3341ff2f6fe8SPaolo Pisati sin = (struct sockaddr_in *)cp; 3342ff2f6fe8SPaolo Pisati break; 3343ff2f6fe8SPaolo Pisati } 3344ff2f6fe8SPaolo Pisati } 3345ff2f6fe8SPaolo Pisati } 3346ff2f6fe8SPaolo Pisati if (sin == NULL) 3347ff2f6fe8SPaolo Pisati errx(1, "%s: cannot get interface address", ifn); 3348ff2f6fe8SPaolo Pisati 3349ff2f6fe8SPaolo Pisati n->ip = sin->sin_addr; 3350ff2f6fe8SPaolo Pisati strncpy(n->if_name, ifn, IF_NAMESIZE); 3351ff2f6fe8SPaolo Pisati 3352ff2f6fe8SPaolo Pisati free(buf); 3353ff2f6fe8SPaolo Pisati } 3354ff2f6fe8SPaolo Pisati 3355ff2f6fe8SPaolo Pisati /* 3356ff2f6fe8SPaolo Pisati * XXX - The following functions, macros and definitions come from natd.c: 3357ff2f6fe8SPaolo Pisati * it would be better to move them outside natd.c, in a file 3358ff2f6fe8SPaolo Pisati * (redirect_support.[ch]?) shared by ipfw and natd, but for now i can live 3359ff2f6fe8SPaolo Pisati * with it. 3360ff2f6fe8SPaolo Pisati */ 3361ff2f6fe8SPaolo Pisati 3362ff2f6fe8SPaolo Pisati /* 3363ff2f6fe8SPaolo Pisati * Definition of a port range, and macros to deal with values. 3364ff2f6fe8SPaolo Pisati * FORMAT: HI 16-bits == first port in range, 0 == all ports. 3365ff2f6fe8SPaolo Pisati * LO 16-bits == number of ports in range 3366ff2f6fe8SPaolo Pisati * NOTES: - Port values are not stored in network byte order. 3367ff2f6fe8SPaolo Pisati */ 3368ff2f6fe8SPaolo Pisati 3369ff2f6fe8SPaolo Pisati #define port_range u_long 3370ff2f6fe8SPaolo Pisati 3371ff2f6fe8SPaolo Pisati #define GETLOPORT(x) ((x) >> 0x10) 3372ff2f6fe8SPaolo Pisati #define GETNUMPORTS(x) ((x) & 0x0000ffff) 3373ff2f6fe8SPaolo Pisati #define GETHIPORT(x) (GETLOPORT((x)) + GETNUMPORTS((x))) 3374ff2f6fe8SPaolo Pisati 3375ff2f6fe8SPaolo Pisati /* Set y to be the low-port value in port_range variable x. */ 3376ff2f6fe8SPaolo Pisati #define SETLOPORT(x,y) ((x) = ((x) & 0x0000ffff) | ((y) << 0x10)) 3377ff2f6fe8SPaolo Pisati 3378ff2f6fe8SPaolo Pisati /* Set y to be the number of ports in port_range variable x. */ 3379ff2f6fe8SPaolo Pisati #define SETNUMPORTS(x,y) ((x) = ((x) & 0xffff0000) | (y)) 3380ff2f6fe8SPaolo Pisati 3381ff2f6fe8SPaolo Pisati static void 3382ff2f6fe8SPaolo Pisati StrToAddr (const char* str, struct in_addr* addr) 3383ff2f6fe8SPaolo Pisati { 3384ff2f6fe8SPaolo Pisati struct hostent* hp; 3385ff2f6fe8SPaolo Pisati 3386ff2f6fe8SPaolo Pisati if (inet_aton (str, addr)) 3387ff2f6fe8SPaolo Pisati return; 3388ff2f6fe8SPaolo Pisati 3389ff2f6fe8SPaolo Pisati hp = gethostbyname (str); 3390ff2f6fe8SPaolo Pisati if (!hp) 3391ff2f6fe8SPaolo Pisati errx (1, "unknown host %s", str); 3392ff2f6fe8SPaolo Pisati 3393ff2f6fe8SPaolo Pisati memcpy (addr, hp->h_addr, sizeof (struct in_addr)); 3394ff2f6fe8SPaolo Pisati } 3395ff2f6fe8SPaolo Pisati 3396ff2f6fe8SPaolo Pisati static int 3397ff2f6fe8SPaolo Pisati StrToPortRange (const char* str, const char* proto, port_range *portRange) 3398ff2f6fe8SPaolo Pisati { 3399ff2f6fe8SPaolo Pisati char* sep; 3400ff2f6fe8SPaolo Pisati struct servent* sp; 3401ff2f6fe8SPaolo Pisati char* end; 3402ff2f6fe8SPaolo Pisati u_short loPort; 3403ff2f6fe8SPaolo Pisati u_short hiPort; 3404ff2f6fe8SPaolo Pisati 3405ff2f6fe8SPaolo Pisati /* First see if this is a service, return corresponding port if so. */ 3406ff2f6fe8SPaolo Pisati sp = getservbyname (str,proto); 3407ff2f6fe8SPaolo Pisati if (sp) { 3408ff2f6fe8SPaolo Pisati SETLOPORT(*portRange, ntohs(sp->s_port)); 3409ff2f6fe8SPaolo Pisati SETNUMPORTS(*portRange, 1); 3410ff2f6fe8SPaolo Pisati return 0; 3411ff2f6fe8SPaolo Pisati } 3412ff2f6fe8SPaolo Pisati 3413ff2f6fe8SPaolo Pisati /* Not a service, see if it's a single port or port range. */ 3414ff2f6fe8SPaolo Pisati sep = strchr (str, '-'); 3415ff2f6fe8SPaolo Pisati if (sep == NULL) { 3416ff2f6fe8SPaolo Pisati SETLOPORT(*portRange, strtol(str, &end, 10)); 3417ff2f6fe8SPaolo Pisati if (end != str) { 3418ff2f6fe8SPaolo Pisati /* Single port. */ 3419ff2f6fe8SPaolo Pisati SETNUMPORTS(*portRange, 1); 3420ff2f6fe8SPaolo Pisati return 0; 3421ff2f6fe8SPaolo Pisati } 3422ff2f6fe8SPaolo Pisati 3423ff2f6fe8SPaolo Pisati /* Error in port range field. */ 3424ff2f6fe8SPaolo Pisati errx (EX_DATAERR, "%s/%s: unknown service", str, proto); 3425ff2f6fe8SPaolo Pisati } 3426ff2f6fe8SPaolo Pisati 3427ff2f6fe8SPaolo Pisati /* Port range, get the values and sanity check. */ 3428ff2f6fe8SPaolo Pisati sscanf (str, "%hu-%hu", &loPort, &hiPort); 3429ff2f6fe8SPaolo Pisati SETLOPORT(*portRange, loPort); 3430ff2f6fe8SPaolo Pisati SETNUMPORTS(*portRange, 0); /* Error by default */ 3431ff2f6fe8SPaolo Pisati if (loPort <= hiPort) 3432ff2f6fe8SPaolo Pisati SETNUMPORTS(*portRange, hiPort - loPort + 1); 3433ff2f6fe8SPaolo Pisati 3434ff2f6fe8SPaolo Pisati if (GETNUMPORTS(*portRange) == 0) 3435ff2f6fe8SPaolo Pisati errx (EX_DATAERR, "invalid port range %s", str); 3436ff2f6fe8SPaolo Pisati 3437ff2f6fe8SPaolo Pisati return 0; 3438ff2f6fe8SPaolo Pisati } 3439ff2f6fe8SPaolo Pisati 3440ff2f6fe8SPaolo Pisati static int 3441ff2f6fe8SPaolo Pisati StrToProto (const char* str) 3442ff2f6fe8SPaolo Pisati { 3443ff2f6fe8SPaolo Pisati if (!strcmp (str, "tcp")) 3444ff2f6fe8SPaolo Pisati return IPPROTO_TCP; 3445ff2f6fe8SPaolo Pisati 3446ff2f6fe8SPaolo Pisati if (!strcmp (str, "udp")) 3447ff2f6fe8SPaolo Pisati return IPPROTO_UDP; 3448ff2f6fe8SPaolo Pisati 3449ff2f6fe8SPaolo Pisati errx (EX_DATAERR, "unknown protocol %s. Expected tcp or udp", str); 3450ff2f6fe8SPaolo Pisati } 3451ff2f6fe8SPaolo Pisati 3452ff2f6fe8SPaolo Pisati static int 3453ff2f6fe8SPaolo Pisati StrToAddrAndPortRange (const char* str, struct in_addr* addr, char* proto, 3454ff2f6fe8SPaolo Pisati port_range *portRange) 3455ff2f6fe8SPaolo Pisati { 3456ff2f6fe8SPaolo Pisati char* ptr; 3457ff2f6fe8SPaolo Pisati 3458ff2f6fe8SPaolo Pisati ptr = strchr (str, ':'); 3459ff2f6fe8SPaolo Pisati if (!ptr) 3460ff2f6fe8SPaolo Pisati errx (EX_DATAERR, "%s is missing port number", str); 3461ff2f6fe8SPaolo Pisati 3462ff2f6fe8SPaolo Pisati *ptr = '\0'; 3463ff2f6fe8SPaolo Pisati ++ptr; 3464ff2f6fe8SPaolo Pisati 3465ff2f6fe8SPaolo Pisati StrToAddr (str, addr); 3466ff2f6fe8SPaolo Pisati return StrToPortRange (ptr, proto, portRange); 3467ff2f6fe8SPaolo Pisati } 3468ff2f6fe8SPaolo Pisati 3469ff2f6fe8SPaolo Pisati /* End of stuff taken from natd.c. */ 3470ff2f6fe8SPaolo Pisati 3471ff2f6fe8SPaolo Pisati #define INC_ARGCV() do { \ 3472ff2f6fe8SPaolo Pisati (*_av)++; \ 3473ff2f6fe8SPaolo Pisati (*_ac)--; \ 3474ff2f6fe8SPaolo Pisati av = *_av; \ 3475ff2f6fe8SPaolo Pisati ac = *_ac; \ 3476ff2f6fe8SPaolo Pisati } while(0) 3477ff2f6fe8SPaolo Pisati 3478ff2f6fe8SPaolo Pisati /* 3479ff2f6fe8SPaolo Pisati * The next 3 functions add support for the addr, port and proto redirect and 3480ff2f6fe8SPaolo Pisati * their logic is loosely based on SetupAddressRedirect(), SetupPortRedirect() 3481ff2f6fe8SPaolo Pisati * and SetupProtoRedirect() from natd.c. 3482ff2f6fe8SPaolo Pisati * 3483ff2f6fe8SPaolo Pisati * Every setup_* function fills at least one redirect entry 3484ff2f6fe8SPaolo Pisati * (struct cfg_redir) and zero or more server pool entry (struct cfg_spool) 3485ff2f6fe8SPaolo Pisati * in buf. 3486ff2f6fe8SPaolo Pisati * 3487ff2f6fe8SPaolo Pisati * The format of data in buf is: 3488ff2f6fe8SPaolo Pisati * 3489ff2f6fe8SPaolo Pisati * 3490ff2f6fe8SPaolo Pisati * cfg_nat cfg_redir cfg_spool ...... cfg_spool 3491ff2f6fe8SPaolo Pisati * 3492ff2f6fe8SPaolo Pisati * ------------------------------------- ------------ 3493ff2f6fe8SPaolo Pisati * | | .....X ... | | | | ..... 3494ff2f6fe8SPaolo Pisati * ------------------------------------- ...... ------------ 3495ff2f6fe8SPaolo Pisati * ^ 3496ff2f6fe8SPaolo Pisati * spool_cnt n=0 ...... n=(X-1) 3497ff2f6fe8SPaolo Pisati * 3498ff2f6fe8SPaolo Pisati * len points to the amount of available space in buf 3499ff2f6fe8SPaolo Pisati * space counts the memory consumed by every function 3500ff2f6fe8SPaolo Pisati * 3501ff2f6fe8SPaolo Pisati * XXX - Every function get all the argv params so it 3502ff2f6fe8SPaolo Pisati * has to check, in optional parameters, that the next 3503ff2f6fe8SPaolo Pisati * args is a valid option for the redir entry and not 3504ff2f6fe8SPaolo Pisati * another token. Only redir_port and redir_proto are 3505ff2f6fe8SPaolo Pisati * affected by this. 3506ff2f6fe8SPaolo Pisati */ 3507ff2f6fe8SPaolo Pisati 3508ff2f6fe8SPaolo Pisati static int 3509ff2f6fe8SPaolo Pisati setup_redir_addr(char *spool_buf, int len, 3510ff2f6fe8SPaolo Pisati int *_ac, char ***_av) 3511ff2f6fe8SPaolo Pisati { 3512ff2f6fe8SPaolo Pisati char **av, *sep; /* Token separator. */ 3513ff2f6fe8SPaolo Pisati /* Temporary buffer used to hold server pool ip's. */ 3514ff2f6fe8SPaolo Pisati char tmp_spool_buf[NAT_BUF_LEN]; 3515ff2f6fe8SPaolo Pisati int ac, i, space, lsnat; 3516ff2f6fe8SPaolo Pisati struct cfg_redir *r; 3517ff2f6fe8SPaolo Pisati struct cfg_spool *tmp; 3518ff2f6fe8SPaolo Pisati 3519ff2f6fe8SPaolo Pisati av = *_av; 3520ff2f6fe8SPaolo Pisati ac = *_ac; 3521ff2f6fe8SPaolo Pisati space = 0; 3522ff2f6fe8SPaolo Pisati lsnat = 0; 3523ff2f6fe8SPaolo Pisati if (len >= SOF_REDIR) { 3524ff2f6fe8SPaolo Pisati r = (struct cfg_redir *)spool_buf; 3525ff2f6fe8SPaolo Pisati /* Skip cfg_redir at beginning of buf. */ 3526ff2f6fe8SPaolo Pisati spool_buf = &spool_buf[SOF_REDIR]; 3527ff2f6fe8SPaolo Pisati space = SOF_REDIR; 3528ff2f6fe8SPaolo Pisati len -= SOF_REDIR; 3529ff2f6fe8SPaolo Pisati } else 3530ff2f6fe8SPaolo Pisati goto nospace; 3531ff2f6fe8SPaolo Pisati r->mode = REDIR_ADDR; 3532ff2f6fe8SPaolo Pisati /* Extract local address. */ 3533ff2f6fe8SPaolo Pisati if (ac == 0) 3534ff2f6fe8SPaolo Pisati errx(EX_DATAERR, "redirect_addr: missing local address"); 3535ff2f6fe8SPaolo Pisati sep = strchr(*av, ','); 3536ff2f6fe8SPaolo Pisati if (sep) { /* LSNAT redirection syntax. */ 3537ff2f6fe8SPaolo Pisati r->laddr.s_addr = INADDR_NONE; 3538ff2f6fe8SPaolo Pisati /* Preserve av, copy spool servers to tmp_spool_buf. */ 3539ff2f6fe8SPaolo Pisati strncpy(tmp_spool_buf, *av, strlen(*av)+1); 3540ff2f6fe8SPaolo Pisati lsnat = 1; 3541ff2f6fe8SPaolo Pisati } else 3542ff2f6fe8SPaolo Pisati StrToAddr(*av, &r->laddr); 3543ff2f6fe8SPaolo Pisati INC_ARGCV(); 3544ff2f6fe8SPaolo Pisati 3545ff2f6fe8SPaolo Pisati /* Extract public address. */ 3546ff2f6fe8SPaolo Pisati if (ac == 0) 3547ff2f6fe8SPaolo Pisati errx(EX_DATAERR, "redirect_addr: missing public address"); 3548ff2f6fe8SPaolo Pisati StrToAddr(*av, &r->paddr); 3549ff2f6fe8SPaolo Pisati INC_ARGCV(); 3550ff2f6fe8SPaolo Pisati 3551ff2f6fe8SPaolo Pisati /* Setup LSNAT server pool. */ 3552ff2f6fe8SPaolo Pisati if (sep) { 3553ff2f6fe8SPaolo Pisati sep = strtok(tmp_spool_buf, ","); 3554ff2f6fe8SPaolo Pisati while (sep != NULL) { 3555ff2f6fe8SPaolo Pisati tmp = (struct cfg_spool *)spool_buf; 3556ff2f6fe8SPaolo Pisati if (len < SOF_SPOOL) 3557ff2f6fe8SPaolo Pisati goto nospace; 3558ff2f6fe8SPaolo Pisati len -= SOF_SPOOL; 3559ff2f6fe8SPaolo Pisati space += SOF_SPOOL; 3560ff2f6fe8SPaolo Pisati StrToAddr(sep, &tmp->addr); 3561ff2f6fe8SPaolo Pisati tmp->port = ~0; 3562ff2f6fe8SPaolo Pisati r->spool_cnt++; 3563ff2f6fe8SPaolo Pisati /* Point to the next possible cfg_spool. */ 3564ff2f6fe8SPaolo Pisati spool_buf = &spool_buf[SOF_SPOOL]; 3565ff2f6fe8SPaolo Pisati sep = strtok(NULL, ","); 3566ff2f6fe8SPaolo Pisati } 3567ff2f6fe8SPaolo Pisati } 3568ff2f6fe8SPaolo Pisati return(space); 3569ff2f6fe8SPaolo Pisati nospace: 3570ff2f6fe8SPaolo Pisati errx(EX_DATAERR, "redirect_addr: buf is too small\n"); 3571ff2f6fe8SPaolo Pisati } 3572ff2f6fe8SPaolo Pisati 3573ff2f6fe8SPaolo Pisati static int 3574ff2f6fe8SPaolo Pisati setup_redir_port(char *spool_buf, int len, 3575ff2f6fe8SPaolo Pisati int *_ac, char ***_av) 3576ff2f6fe8SPaolo Pisati { 3577ff2f6fe8SPaolo Pisati char **av, *sep, *protoName; 3578ff2f6fe8SPaolo Pisati char tmp_spool_buf[NAT_BUF_LEN]; 3579ff2f6fe8SPaolo Pisati int ac, space, lsnat; 3580ff2f6fe8SPaolo Pisati struct cfg_redir *r; 3581ff2f6fe8SPaolo Pisati struct cfg_spool *tmp; 3582ff2f6fe8SPaolo Pisati u_short numLocalPorts; 3583ff2f6fe8SPaolo Pisati port_range portRange; 3584ff2f6fe8SPaolo Pisati 3585ff2f6fe8SPaolo Pisati av = *_av; 3586ff2f6fe8SPaolo Pisati ac = *_ac; 3587ff2f6fe8SPaolo Pisati space = 0; 3588ff2f6fe8SPaolo Pisati lsnat = 0; 3589ff2f6fe8SPaolo Pisati numLocalPorts = 0; 3590ff2f6fe8SPaolo Pisati 3591ff2f6fe8SPaolo Pisati if (len >= SOF_REDIR) { 3592ff2f6fe8SPaolo Pisati r = (struct cfg_redir *)spool_buf; 3593ff2f6fe8SPaolo Pisati /* Skip cfg_redir at beginning of buf. */ 3594ff2f6fe8SPaolo Pisati spool_buf = &spool_buf[SOF_REDIR]; 3595ff2f6fe8SPaolo Pisati space = SOF_REDIR; 3596ff2f6fe8SPaolo Pisati len -= SOF_REDIR; 3597ff2f6fe8SPaolo Pisati } else 3598ff2f6fe8SPaolo Pisati goto nospace; 3599ff2f6fe8SPaolo Pisati r->mode = REDIR_PORT; 3600ff2f6fe8SPaolo Pisati /* 3601ff2f6fe8SPaolo Pisati * Extract protocol. 3602ff2f6fe8SPaolo Pisati */ 3603ff2f6fe8SPaolo Pisati if (ac == 0) 3604ff2f6fe8SPaolo Pisati errx (EX_DATAERR, "redirect_port: missing protocol"); 3605ff2f6fe8SPaolo Pisati r->proto = StrToProto(*av); 3606ff2f6fe8SPaolo Pisati protoName = *av; 3607ff2f6fe8SPaolo Pisati INC_ARGCV(); 3608ff2f6fe8SPaolo Pisati 3609ff2f6fe8SPaolo Pisati /* 3610ff2f6fe8SPaolo Pisati * Extract local address. 3611ff2f6fe8SPaolo Pisati */ 3612ff2f6fe8SPaolo Pisati if (ac == 0) 3613ff2f6fe8SPaolo Pisati errx (EX_DATAERR, "redirect_port: missing local address"); 3614ff2f6fe8SPaolo Pisati 3615ff2f6fe8SPaolo Pisati sep = strchr(*av, ','); 3616ff2f6fe8SPaolo Pisati /* LSNAT redirection syntax. */ 3617ff2f6fe8SPaolo Pisati if (sep) { 3618ff2f6fe8SPaolo Pisati r->laddr.s_addr = INADDR_NONE; 3619ff2f6fe8SPaolo Pisati r->lport = ~0; 3620ff2f6fe8SPaolo Pisati numLocalPorts = 1; 3621ff2f6fe8SPaolo Pisati /* Preserve av, copy spool servers to tmp_spool_buf. */ 3622ff2f6fe8SPaolo Pisati strncpy(tmp_spool_buf, *av, strlen(*av)+1); 3623ff2f6fe8SPaolo Pisati lsnat = 1; 3624ff2f6fe8SPaolo Pisati } else { 3625ff2f6fe8SPaolo Pisati if (StrToAddrAndPortRange (*av, &r->laddr, protoName, 3626ff2f6fe8SPaolo Pisati &portRange) != 0) 3627ff2f6fe8SPaolo Pisati errx(EX_DATAERR, "redirect_port:" 3628ff2f6fe8SPaolo Pisati "invalid local port range"); 3629ff2f6fe8SPaolo Pisati 3630ff2f6fe8SPaolo Pisati r->lport = GETLOPORT(portRange); 3631ff2f6fe8SPaolo Pisati numLocalPorts = GETNUMPORTS(portRange); 3632ff2f6fe8SPaolo Pisati } 3633ff2f6fe8SPaolo Pisati INC_ARGCV(); 3634ff2f6fe8SPaolo Pisati 3635ff2f6fe8SPaolo Pisati /* 3636ff2f6fe8SPaolo Pisati * Extract public port and optionally address. 3637ff2f6fe8SPaolo Pisati */ 3638ff2f6fe8SPaolo Pisati if (ac == 0) 3639ff2f6fe8SPaolo Pisati errx (EX_DATAERR, "redirect_port: missing public port"); 3640ff2f6fe8SPaolo Pisati 3641ff2f6fe8SPaolo Pisati sep = strchr (*av, ':'); 3642ff2f6fe8SPaolo Pisati if (sep) { 3643ff2f6fe8SPaolo Pisati if (StrToAddrAndPortRange (*av, &r->paddr, protoName, 3644ff2f6fe8SPaolo Pisati &portRange) != 0) 3645ff2f6fe8SPaolo Pisati errx(EX_DATAERR, "redirect_port:" 3646ff2f6fe8SPaolo Pisati "invalid public port range"); 3647ff2f6fe8SPaolo Pisati } else { 3648ff2f6fe8SPaolo Pisati r->paddr.s_addr = INADDR_ANY; 3649ff2f6fe8SPaolo Pisati if (StrToPortRange (*av, protoName, &portRange) != 0) 3650ff2f6fe8SPaolo Pisati errx(EX_DATAERR, "redirect_port:" 3651ff2f6fe8SPaolo Pisati "invalid public port range"); 3652ff2f6fe8SPaolo Pisati } 3653ff2f6fe8SPaolo Pisati 3654ff2f6fe8SPaolo Pisati r->pport = GETLOPORT(portRange); 3655ff2f6fe8SPaolo Pisati r->pport_cnt = GETNUMPORTS(portRange); 3656ff2f6fe8SPaolo Pisati INC_ARGCV(); 3657ff2f6fe8SPaolo Pisati 3658ff2f6fe8SPaolo Pisati /* 3659ff2f6fe8SPaolo Pisati * Extract remote address and optionally port. 3660ff2f6fe8SPaolo Pisati */ 3661ff2f6fe8SPaolo Pisati /* 3662ff2f6fe8SPaolo Pisati * NB: isalpha(**av) => we've to check that next parameter is really an 3663ff2f6fe8SPaolo Pisati * option for this redirect entry, else stop here processing arg[cv]. 3664ff2f6fe8SPaolo Pisati */ 3665ff2f6fe8SPaolo Pisati if (ac != 0 && !isalpha(**av)) { 3666ff2f6fe8SPaolo Pisati sep = strchr (*av, ':'); 3667ff2f6fe8SPaolo Pisati if (sep) { 3668ff2f6fe8SPaolo Pisati if (StrToAddrAndPortRange (*av, &r->raddr, protoName, 3669ff2f6fe8SPaolo Pisati &portRange) != 0) 3670ff2f6fe8SPaolo Pisati errx(EX_DATAERR, "redirect_port:" 3671ff2f6fe8SPaolo Pisati "invalid remote port range"); 3672ff2f6fe8SPaolo Pisati } else { 3673ff2f6fe8SPaolo Pisati SETLOPORT(portRange, 0); 3674ff2f6fe8SPaolo Pisati SETNUMPORTS(portRange, 1); 3675ff2f6fe8SPaolo Pisati StrToAddr (*av, &r->raddr); 3676ff2f6fe8SPaolo Pisati } 3677ff2f6fe8SPaolo Pisati INC_ARGCV(); 3678ff2f6fe8SPaolo Pisati } else { 3679ff2f6fe8SPaolo Pisati SETLOPORT(portRange, 0); 3680ff2f6fe8SPaolo Pisati SETNUMPORTS(portRange, 1); 3681ff2f6fe8SPaolo Pisati r->raddr.s_addr = INADDR_ANY; 3682ff2f6fe8SPaolo Pisati } 3683ff2f6fe8SPaolo Pisati r->rport = GETLOPORT(portRange); 3684ff2f6fe8SPaolo Pisati r->rport_cnt = GETNUMPORTS(portRange); 3685ff2f6fe8SPaolo Pisati 3686ff2f6fe8SPaolo Pisati /* 3687ff2f6fe8SPaolo Pisati * Make sure port ranges match up, then add the redirect ports. 3688ff2f6fe8SPaolo Pisati */ 3689ff2f6fe8SPaolo Pisati if (numLocalPorts != r->pport_cnt) 3690ff2f6fe8SPaolo Pisati errx(EX_DATAERR, "redirect_port:" 3691ff2f6fe8SPaolo Pisati "port ranges must be equal in size"); 3692ff2f6fe8SPaolo Pisati 3693ff2f6fe8SPaolo Pisati /* Remote port range is allowed to be '0' which means all ports. */ 3694ff2f6fe8SPaolo Pisati if (r->rport_cnt != numLocalPorts && 3695ff2f6fe8SPaolo Pisati (r->rport_cnt != 1 || r->rport != 0)) 3696ff2f6fe8SPaolo Pisati errx(EX_DATAERR, "redirect_port: remote port must" 3697ff2f6fe8SPaolo Pisati "be 0 or equal to local port range in size"); 3698ff2f6fe8SPaolo Pisati 3699ff2f6fe8SPaolo Pisati /* 3700ff2f6fe8SPaolo Pisati * Setup LSNAT server pool. 3701ff2f6fe8SPaolo Pisati */ 3702ff2f6fe8SPaolo Pisati if (lsnat) { 3703ff2f6fe8SPaolo Pisati sep = strtok(tmp_spool_buf, ","); 3704ff2f6fe8SPaolo Pisati while (sep != NULL) { 3705ff2f6fe8SPaolo Pisati tmp = (struct cfg_spool *)spool_buf; 3706ff2f6fe8SPaolo Pisati if (len < SOF_SPOOL) 3707ff2f6fe8SPaolo Pisati goto nospace; 3708ff2f6fe8SPaolo Pisati len -= SOF_SPOOL; 3709ff2f6fe8SPaolo Pisati space += SOF_SPOOL; 3710ff2f6fe8SPaolo Pisati if (StrToAddrAndPortRange(sep, &tmp->addr, protoName, 3711ff2f6fe8SPaolo Pisati &portRange) != 0) 3712ff2f6fe8SPaolo Pisati errx(EX_DATAERR, "redirect_port:" 3713ff2f6fe8SPaolo Pisati "invalid local port range"); 3714ff2f6fe8SPaolo Pisati if (GETNUMPORTS(portRange) != 1) 3715ff2f6fe8SPaolo Pisati errx(EX_DATAERR, "redirect_port: local port" 3716ff2f6fe8SPaolo Pisati "must be single in this context"); 3717ff2f6fe8SPaolo Pisati tmp->port = GETLOPORT(portRange); 3718ff2f6fe8SPaolo Pisati r->spool_cnt++; 3719ff2f6fe8SPaolo Pisati /* Point to the next possible cfg_spool. */ 3720ff2f6fe8SPaolo Pisati spool_buf = &spool_buf[SOF_SPOOL]; 3721ff2f6fe8SPaolo Pisati sep = strtok(NULL, ","); 3722ff2f6fe8SPaolo Pisati } 3723ff2f6fe8SPaolo Pisati } 3724ff2f6fe8SPaolo Pisati return (space); 3725ff2f6fe8SPaolo Pisati nospace: 3726ff2f6fe8SPaolo Pisati errx(EX_DATAERR, "redirect_port: buf is too small\n"); 3727ff2f6fe8SPaolo Pisati } 3728ff2f6fe8SPaolo Pisati 3729ff2f6fe8SPaolo Pisati static int 3730ff2f6fe8SPaolo Pisati setup_redir_proto(char *spool_buf, int len, 3731ff2f6fe8SPaolo Pisati int *_ac, char ***_av) 3732ff2f6fe8SPaolo Pisati { 3733ff2f6fe8SPaolo Pisati char **av; 3734ff2f6fe8SPaolo Pisati int ac, i, space; 3735ff2f6fe8SPaolo Pisati struct protoent *protoent; 3736ff2f6fe8SPaolo Pisati struct cfg_redir *r; 3737ff2f6fe8SPaolo Pisati 3738ff2f6fe8SPaolo Pisati av = *_av; 3739ff2f6fe8SPaolo Pisati ac = *_ac; 3740ff2f6fe8SPaolo Pisati if (len >= SOF_REDIR) { 3741ff2f6fe8SPaolo Pisati r = (struct cfg_redir *)spool_buf; 3742ff2f6fe8SPaolo Pisati /* Skip cfg_redir at beginning of buf. */ 3743ff2f6fe8SPaolo Pisati spool_buf = &spool_buf[SOF_REDIR]; 3744ff2f6fe8SPaolo Pisati space = SOF_REDIR; 3745ff2f6fe8SPaolo Pisati len -= SOF_REDIR; 3746ff2f6fe8SPaolo Pisati } else 3747ff2f6fe8SPaolo Pisati goto nospace; 3748ff2f6fe8SPaolo Pisati r->mode = REDIR_PROTO; 3749ff2f6fe8SPaolo Pisati /* 3750ff2f6fe8SPaolo Pisati * Extract protocol. 3751ff2f6fe8SPaolo Pisati */ 3752ff2f6fe8SPaolo Pisati if (ac == 0) 3753ff2f6fe8SPaolo Pisati errx(EX_DATAERR, "redirect_proto: missing protocol"); 3754ff2f6fe8SPaolo Pisati 3755ff2f6fe8SPaolo Pisati protoent = getprotobyname(*av); 3756ff2f6fe8SPaolo Pisati if (protoent == NULL) 3757ff2f6fe8SPaolo Pisati errx(EX_DATAERR, "redirect_proto: unknown protocol %s", *av); 3758ff2f6fe8SPaolo Pisati else 3759ff2f6fe8SPaolo Pisati r->proto = protoent->p_proto; 3760ff2f6fe8SPaolo Pisati 3761ff2f6fe8SPaolo Pisati INC_ARGCV(); 3762ff2f6fe8SPaolo Pisati 3763ff2f6fe8SPaolo Pisati /* 3764ff2f6fe8SPaolo Pisati * Extract local address. 3765ff2f6fe8SPaolo Pisati */ 3766ff2f6fe8SPaolo Pisati if (ac == 0) 3767ff2f6fe8SPaolo Pisati errx(EX_DATAERR, "redirect_proto: missing local address"); 3768ff2f6fe8SPaolo Pisati else 3769ff2f6fe8SPaolo Pisati StrToAddr(*av, &r->laddr); 3770ff2f6fe8SPaolo Pisati 3771ff2f6fe8SPaolo Pisati INC_ARGCV(); 3772ff2f6fe8SPaolo Pisati 3773ff2f6fe8SPaolo Pisati /* 3774ff2f6fe8SPaolo Pisati * Extract optional public address. 3775ff2f6fe8SPaolo Pisati */ 3776ff2f6fe8SPaolo Pisati if (ac == 0) { 3777ff2f6fe8SPaolo Pisati r->paddr.s_addr = INADDR_ANY; 3778ff2f6fe8SPaolo Pisati r->raddr.s_addr = INADDR_ANY; 3779ff2f6fe8SPaolo Pisati } else { 3780ff2f6fe8SPaolo Pisati /* see above in setup_redir_port() */ 3781ff2f6fe8SPaolo Pisati if (!isalpha(**av)) { 3782ff2f6fe8SPaolo Pisati StrToAddr(*av, &r->paddr); 3783ff2f6fe8SPaolo Pisati INC_ARGCV(); 3784ff2f6fe8SPaolo Pisati 3785ff2f6fe8SPaolo Pisati /* 3786ff2f6fe8SPaolo Pisati * Extract optional remote address. 3787ff2f6fe8SPaolo Pisati */ 3788ff2f6fe8SPaolo Pisati /* see above in setup_redir_port() */ 3789ff2f6fe8SPaolo Pisati if (ac!=0 && !isalpha(**av)) { 3790ff2f6fe8SPaolo Pisati StrToAddr(*av, &r->raddr); 3791ff2f6fe8SPaolo Pisati INC_ARGCV(); 3792ff2f6fe8SPaolo Pisati } 3793ff2f6fe8SPaolo Pisati } 3794ff2f6fe8SPaolo Pisati } 3795ff2f6fe8SPaolo Pisati return (space); 3796ff2f6fe8SPaolo Pisati nospace: 3797ff2f6fe8SPaolo Pisati errx(EX_DATAERR, "redirect_proto: buf is too small\n"); 3798ff2f6fe8SPaolo Pisati } 3799ff2f6fe8SPaolo Pisati 3800ff2f6fe8SPaolo Pisati static void 3801ff2f6fe8SPaolo Pisati show_nat(int ac, char **av); 3802ff2f6fe8SPaolo Pisati 3803ff2f6fe8SPaolo Pisati static void 3804ff2f6fe8SPaolo Pisati print_nat_config(char *buf) { 3805ff2f6fe8SPaolo Pisati struct cfg_nat *n; 3806ff2f6fe8SPaolo Pisati int i, cnt, flag, off; 3807ff2f6fe8SPaolo Pisati struct cfg_redir *t; 3808ff2f6fe8SPaolo Pisati struct cfg_spool *s; 3809ff2f6fe8SPaolo Pisati struct protoent *p; 3810ff2f6fe8SPaolo Pisati 3811ff2f6fe8SPaolo Pisati n = (struct cfg_nat *)buf; 3812ff2f6fe8SPaolo Pisati flag = 1; 3813ff2f6fe8SPaolo Pisati off = sizeof(*n); 3814ff2f6fe8SPaolo Pisati printf("ipfw nat %u config", n->id); 3815ff2f6fe8SPaolo Pisati if (strlen(n->if_name) != 0) 3816ff2f6fe8SPaolo Pisati printf(" if %s", n->if_name); 3817ff2f6fe8SPaolo Pisati else if (n->ip.s_addr != 0) 3818ff2f6fe8SPaolo Pisati printf(" ip %s", inet_ntoa(n->ip)); 3819ff2f6fe8SPaolo Pisati while (n->mode != 0) { 3820ff2f6fe8SPaolo Pisati if (n->mode & PKT_ALIAS_LOG) { 3821ff2f6fe8SPaolo Pisati printf(" log"); 3822ff2f6fe8SPaolo Pisati n->mode &= ~PKT_ALIAS_LOG; 3823ff2f6fe8SPaolo Pisati } else if (n->mode & PKT_ALIAS_DENY_INCOMING) { 3824ff2f6fe8SPaolo Pisati printf(" deny_in"); 3825ff2f6fe8SPaolo Pisati n->mode &= ~PKT_ALIAS_DENY_INCOMING; 3826ff2f6fe8SPaolo Pisati } else if (n->mode & PKT_ALIAS_SAME_PORTS) { 3827ff2f6fe8SPaolo Pisati printf(" same_ports"); 3828ff2f6fe8SPaolo Pisati n->mode &= ~PKT_ALIAS_SAME_PORTS; 3829ff2f6fe8SPaolo Pisati } else if (n->mode & PKT_ALIAS_UNREGISTERED_ONLY) { 3830ff2f6fe8SPaolo Pisati printf(" unreg_only"); 3831ff2f6fe8SPaolo Pisati n->mode &= ~PKT_ALIAS_UNREGISTERED_ONLY; 3832ff2f6fe8SPaolo Pisati } else if (n->mode & PKT_ALIAS_RESET_ON_ADDR_CHANGE) { 3833ff2f6fe8SPaolo Pisati printf(" reset"); 3834ff2f6fe8SPaolo Pisati n->mode &= ~PKT_ALIAS_RESET_ON_ADDR_CHANGE; 3835ff2f6fe8SPaolo Pisati } else if (n->mode & PKT_ALIAS_REVERSE) { 3836ff2f6fe8SPaolo Pisati printf(" reverse"); 3837ff2f6fe8SPaolo Pisati n->mode &= ~PKT_ALIAS_REVERSE; 3838ff2f6fe8SPaolo Pisati } else if (n->mode & PKT_ALIAS_PROXY_ONLY) { 3839ff2f6fe8SPaolo Pisati printf(" proxy_only"); 3840ff2f6fe8SPaolo Pisati n->mode &= ~PKT_ALIAS_PROXY_ONLY; 3841ff2f6fe8SPaolo Pisati } 3842ff2f6fe8SPaolo Pisati } 3843ff2f6fe8SPaolo Pisati /* Print all the redirect's data configuration. */ 3844ff2f6fe8SPaolo Pisati for (cnt = 0; cnt < n->redir_cnt; cnt++) { 3845ff2f6fe8SPaolo Pisati t = (struct cfg_redir *)&buf[off]; 3846ff2f6fe8SPaolo Pisati off += SOF_REDIR; 3847ff2f6fe8SPaolo Pisati switch (t->mode) { 3848ff2f6fe8SPaolo Pisati case REDIR_ADDR: 3849ff2f6fe8SPaolo Pisati printf(" redirect_addr"); 3850ff2f6fe8SPaolo Pisati if (t->spool_cnt == 0) 3851ff2f6fe8SPaolo Pisati printf(" %s", inet_ntoa(t->laddr)); 3852ff2f6fe8SPaolo Pisati else 3853ff2f6fe8SPaolo Pisati for (i = 0; i < t->spool_cnt; i++) { 3854ff2f6fe8SPaolo Pisati s = (struct cfg_spool *)&buf[off]; 3855ff2f6fe8SPaolo Pisati if (i) 3856ff2f6fe8SPaolo Pisati printf(","); 3857ff2f6fe8SPaolo Pisati else 3858ff2f6fe8SPaolo Pisati printf(" "); 3859ff2f6fe8SPaolo Pisati printf("%s", inet_ntoa(s->addr)); 3860ff2f6fe8SPaolo Pisati off += SOF_SPOOL; 3861ff2f6fe8SPaolo Pisati } 3862ff2f6fe8SPaolo Pisati printf(" %s", inet_ntoa(t->paddr)); 3863ff2f6fe8SPaolo Pisati break; 3864ff2f6fe8SPaolo Pisati case REDIR_PORT: 3865ff2f6fe8SPaolo Pisati p = getprotobynumber(t->proto); 3866ff2f6fe8SPaolo Pisati printf(" redirect_port %s ", p->p_name); 3867ff2f6fe8SPaolo Pisati if (!t->spool_cnt) { 3868ff2f6fe8SPaolo Pisati printf("%s:%u", inet_ntoa(t->laddr), t->lport); 3869ff2f6fe8SPaolo Pisati if (t->pport_cnt > 1) 3870ff2f6fe8SPaolo Pisati printf("-%u", t->lport + 3871ff2f6fe8SPaolo Pisati t->pport_cnt - 1); 3872ff2f6fe8SPaolo Pisati } else 3873ff2f6fe8SPaolo Pisati for (i=0; i < t->spool_cnt; i++) { 3874ff2f6fe8SPaolo Pisati s = (struct cfg_spool *)&buf[off]; 3875ff2f6fe8SPaolo Pisati if (i) 3876ff2f6fe8SPaolo Pisati printf(","); 3877ff2f6fe8SPaolo Pisati printf("%s:%u", inet_ntoa(s->addr), 3878ff2f6fe8SPaolo Pisati s->port); 3879ff2f6fe8SPaolo Pisati off += SOF_SPOOL; 3880ff2f6fe8SPaolo Pisati } 3881ff2f6fe8SPaolo Pisati 3882ff2f6fe8SPaolo Pisati printf(" "); 3883ff2f6fe8SPaolo Pisati if (t->paddr.s_addr) 3884ff2f6fe8SPaolo Pisati printf("%s:", inet_ntoa(t->paddr)); 3885ff2f6fe8SPaolo Pisati printf("%u", t->pport); 3886ff2f6fe8SPaolo Pisati if (!t->spool_cnt && t->pport_cnt > 1) 3887ff2f6fe8SPaolo Pisati printf("-%u", t->pport + t->pport_cnt - 1); 3888ff2f6fe8SPaolo Pisati 3889ff2f6fe8SPaolo Pisati if (t->raddr.s_addr) { 3890ff2f6fe8SPaolo Pisati printf(" %s", inet_ntoa(t->raddr)); 3891ff2f6fe8SPaolo Pisati if (t->rport) { 3892ff2f6fe8SPaolo Pisati printf(":%u", t->rport); 3893ff2f6fe8SPaolo Pisati if (!t->spool_cnt && t->rport_cnt > 1) 3894ff2f6fe8SPaolo Pisati printf("-%u", t->rport + 3895ff2f6fe8SPaolo Pisati t->rport_cnt - 1); 3896ff2f6fe8SPaolo Pisati } 3897ff2f6fe8SPaolo Pisati } 3898ff2f6fe8SPaolo Pisati break; 3899ff2f6fe8SPaolo Pisati case REDIR_PROTO: 3900ff2f6fe8SPaolo Pisati p = getprotobynumber(t->proto); 3901ff2f6fe8SPaolo Pisati printf(" redirect_proto %s %s", p->p_name, 3902ff2f6fe8SPaolo Pisati inet_ntoa(t->laddr)); 3903ff2f6fe8SPaolo Pisati if (t->paddr.s_addr != 0) { 3904ff2f6fe8SPaolo Pisati printf(" %s", inet_ntoa(t->paddr)); 3905ff2f6fe8SPaolo Pisati if (t->raddr.s_addr) 3906ff2f6fe8SPaolo Pisati printf(" %s", inet_ntoa(t->raddr)); 3907ff2f6fe8SPaolo Pisati } 3908ff2f6fe8SPaolo Pisati break; 3909ff2f6fe8SPaolo Pisati default: 3910ff2f6fe8SPaolo Pisati errx(EX_DATAERR, "unknown redir mode"); 3911ff2f6fe8SPaolo Pisati break; 3912ff2f6fe8SPaolo Pisati } 3913ff2f6fe8SPaolo Pisati } 3914ff2f6fe8SPaolo Pisati printf("\n"); 3915ff2f6fe8SPaolo Pisati } 3916ff2f6fe8SPaolo Pisati 3917ff2f6fe8SPaolo Pisati static void 3918ff2f6fe8SPaolo Pisati config_nat(int ac, char **av) 3919ff2f6fe8SPaolo Pisati { 3920ff2f6fe8SPaolo Pisati struct cfg_nat *n; /* Nat instance configuration. */ 3921ff2f6fe8SPaolo Pisati struct in_addr ip; 3922ff2f6fe8SPaolo Pisati int i, len, off, tok; 3923ff2f6fe8SPaolo Pisati char *id, buf[NAT_BUF_LEN]; /* Buffer for serialized data. */ 3924ff2f6fe8SPaolo Pisati 3925ff2f6fe8SPaolo Pisati len = NAT_BUF_LEN; 3926ff2f6fe8SPaolo Pisati /* Offset in buf: save space for n at the beginning. */ 3927ff2f6fe8SPaolo Pisati off = sizeof(*n); 3928ff2f6fe8SPaolo Pisati memset(buf, 0, sizeof(buf)); 3929ff2f6fe8SPaolo Pisati n = (struct cfg_nat *)buf; 3930ff2f6fe8SPaolo Pisati 3931ff2f6fe8SPaolo Pisati av++; ac--; 3932ff2f6fe8SPaolo Pisati /* Nat id. */ 3933ff2f6fe8SPaolo Pisati if (ac && isdigit(**av)) { 3934ff2f6fe8SPaolo Pisati id = *av; 3935ff2f6fe8SPaolo Pisati i = atoi(*av); 3936ff2f6fe8SPaolo Pisati ac--; av++; 3937ff2f6fe8SPaolo Pisati n->id = i; 3938ff2f6fe8SPaolo Pisati } else 3939ff2f6fe8SPaolo Pisati errx(EX_DATAERR, "missing nat id"); 3940ff2f6fe8SPaolo Pisati if (ac == 0) 3941ff2f6fe8SPaolo Pisati errx(EX_DATAERR, "missing option"); 3942ff2f6fe8SPaolo Pisati 3943ff2f6fe8SPaolo Pisati while (ac > 0) { 3944ff2f6fe8SPaolo Pisati tok = match_token(nat_params, *av); 3945ff2f6fe8SPaolo Pisati ac--; av++; 3946ff2f6fe8SPaolo Pisati switch (tok) { 3947ff2f6fe8SPaolo Pisati case TOK_IP: 3948ff2f6fe8SPaolo Pisati if (ac == 0) 3949ff2f6fe8SPaolo Pisati errx(EX_DATAERR, "missing option"); 3950ff2f6fe8SPaolo Pisati if (!inet_aton(av[0], &(n->ip))) 3951ff2f6fe8SPaolo Pisati errx(EX_DATAERR, "bad ip address ``%s''", 3952ff2f6fe8SPaolo Pisati av[0]); 3953ff2f6fe8SPaolo Pisati ac--; av++; 3954ff2f6fe8SPaolo Pisati break; 3955ff2f6fe8SPaolo Pisati case TOK_IF: 3956ff2f6fe8SPaolo Pisati set_addr_dynamic(av[0], n); 3957ff2f6fe8SPaolo Pisati ac--; av++; 3958ff2f6fe8SPaolo Pisati break; 3959ff2f6fe8SPaolo Pisati case TOK_ALOG: 3960ff2f6fe8SPaolo Pisati n->mode |= PKT_ALIAS_LOG; 3961ff2f6fe8SPaolo Pisati break; 3962ff2f6fe8SPaolo Pisati case TOK_DENY_INC: 3963ff2f6fe8SPaolo Pisati n->mode |= PKT_ALIAS_DENY_INCOMING; 3964ff2f6fe8SPaolo Pisati break; 3965ff2f6fe8SPaolo Pisati case TOK_SAME_PORTS: 3966ff2f6fe8SPaolo Pisati n->mode |= PKT_ALIAS_SAME_PORTS; 3967ff2f6fe8SPaolo Pisati break; 3968ff2f6fe8SPaolo Pisati case TOK_UNREG_ONLY: 3969ff2f6fe8SPaolo Pisati n->mode |= PKT_ALIAS_UNREGISTERED_ONLY; 3970ff2f6fe8SPaolo Pisati break; 3971ff2f6fe8SPaolo Pisati case TOK_RESET_ADDR: 3972ff2f6fe8SPaolo Pisati n->mode |= PKT_ALIAS_RESET_ON_ADDR_CHANGE; 3973ff2f6fe8SPaolo Pisati break; 3974ff2f6fe8SPaolo Pisati case TOK_ALIAS_REV: 3975ff2f6fe8SPaolo Pisati n->mode |= PKT_ALIAS_REVERSE; 3976ff2f6fe8SPaolo Pisati break; 3977ff2f6fe8SPaolo Pisati case TOK_PROXY_ONLY: 3978ff2f6fe8SPaolo Pisati n->mode |= PKT_ALIAS_PROXY_ONLY; 3979ff2f6fe8SPaolo Pisati break; 3980ff2f6fe8SPaolo Pisati /* 3981ff2f6fe8SPaolo Pisati * All the setup_redir_* functions work directly in the final 3982ff2f6fe8SPaolo Pisati * buffer, see above for details. 3983ff2f6fe8SPaolo Pisati */ 3984ff2f6fe8SPaolo Pisati case TOK_REDIR_ADDR: 3985ff2f6fe8SPaolo Pisati case TOK_REDIR_PORT: 3986ff2f6fe8SPaolo Pisati case TOK_REDIR_PROTO: 3987ff2f6fe8SPaolo Pisati switch (tok) { 3988ff2f6fe8SPaolo Pisati case TOK_REDIR_ADDR: 3989ff2f6fe8SPaolo Pisati i = setup_redir_addr(&buf[off], len, &ac, &av); 3990ff2f6fe8SPaolo Pisati break; 3991ff2f6fe8SPaolo Pisati case TOK_REDIR_PORT: 3992ff2f6fe8SPaolo Pisati i = setup_redir_port(&buf[off], len, &ac, &av); 3993ff2f6fe8SPaolo Pisati break; 3994ff2f6fe8SPaolo Pisati case TOK_REDIR_PROTO: 3995ff2f6fe8SPaolo Pisati i = setup_redir_proto(&buf[off], len, &ac, &av); 3996ff2f6fe8SPaolo Pisati break; 3997ff2f6fe8SPaolo Pisati } 3998ff2f6fe8SPaolo Pisati n->redir_cnt++; 3999ff2f6fe8SPaolo Pisati off += i; 4000ff2f6fe8SPaolo Pisati len -= i; 4001ff2f6fe8SPaolo Pisati break; 4002ff2f6fe8SPaolo Pisati default: 4003ff2f6fe8SPaolo Pisati errx(EX_DATAERR, "unrecognised option ``%s''", av[-1]); 4004ff2f6fe8SPaolo Pisati } 4005ff2f6fe8SPaolo Pisati } 4006ff2f6fe8SPaolo Pisati 4007ff2f6fe8SPaolo Pisati i = do_cmd(IP_FW_NAT_CFG, buf, off); 4008ff2f6fe8SPaolo Pisati if (i) 4009ff2f6fe8SPaolo Pisati err(1, "setsockopt(%s)", "IP_FW_NAT_CFG"); 4010ff2f6fe8SPaolo Pisati 4011ff2f6fe8SPaolo Pisati /* After every modification, we show the resultant rule. */ 4012ff2f6fe8SPaolo Pisati int _ac = 3; 4013ff2f6fe8SPaolo Pisati char *_av[] = {"show", "config", id}; 4014ff2f6fe8SPaolo Pisati show_nat(_ac, _av); 4015ff2f6fe8SPaolo Pisati } 4016ff2f6fe8SPaolo Pisati 40179758b77fSLuigi Rizzo static void 40189758b77fSLuigi Rizzo config_pipe(int ac, char **av) 40199758b77fSLuigi Rizzo { 402062ff38aeSLuigi Rizzo struct dn_pipe p; 40219758b77fSLuigi Rizzo int i; 40229758b77fSLuigi Rizzo char *end; 40239758b77fSLuigi Rizzo void *par = NULL; 40249758b77fSLuigi Rizzo 402562ff38aeSLuigi Rizzo memset(&p, 0, sizeof p); 40269758b77fSLuigi Rizzo 40279758b77fSLuigi Rizzo av++; ac--; 40289758b77fSLuigi Rizzo /* Pipe number */ 40299758b77fSLuigi Rizzo if (ac && isdigit(**av)) { 40309758b77fSLuigi Rizzo i = atoi(*av); av++; ac--; 40319758b77fSLuigi Rizzo if (do_pipe == 1) 403262ff38aeSLuigi Rizzo p.pipe_nr = i; 40339758b77fSLuigi Rizzo else 403462ff38aeSLuigi Rizzo p.fs.fs_nr = i; 40359758b77fSLuigi Rizzo } 40365e43aef8SLuigi Rizzo while (ac > 0) { 40379758b77fSLuigi Rizzo double d; 40389758b77fSLuigi Rizzo int tok = match_token(dummynet_params, *av); 40399758b77fSLuigi Rizzo ac--; av++; 40409758b77fSLuigi Rizzo 40419758b77fSLuigi Rizzo switch(tok) { 404299e5e645SLuigi Rizzo case TOK_NOERROR: 404362ff38aeSLuigi Rizzo p.fs.flags_fs |= DN_NOERROR; 404499e5e645SLuigi Rizzo break; 404599e5e645SLuigi Rizzo 40469758b77fSLuigi Rizzo case TOK_PLR: 40479758b77fSLuigi Rizzo NEED1("plr needs argument 0..1\n"); 40489758b77fSLuigi Rizzo d = strtod(av[0], NULL); 40499758b77fSLuigi Rizzo if (d > 1) 40509758b77fSLuigi Rizzo d = 1; 40519758b77fSLuigi Rizzo else if (d < 0) 40529758b77fSLuigi Rizzo d = 0; 405362ff38aeSLuigi Rizzo p.fs.plr = (int)(d*0x7fffffff); 40549758b77fSLuigi Rizzo ac--; av++; 40559758b77fSLuigi Rizzo break; 40569758b77fSLuigi Rizzo 40579758b77fSLuigi Rizzo case TOK_QUEUE: 40589758b77fSLuigi Rizzo NEED1("queue needs queue size\n"); 40599758b77fSLuigi Rizzo end = NULL; 406062ff38aeSLuigi Rizzo p.fs.qsize = strtoul(av[0], &end, 0); 40619758b77fSLuigi Rizzo if (*end == 'K' || *end == 'k') { 406262ff38aeSLuigi Rizzo p.fs.flags_fs |= DN_QSIZE_IS_BYTES; 406362ff38aeSLuigi Rizzo p.fs.qsize *= 1024; 406401750186SBrooks Davis } else if (*end == 'B' || 406501750186SBrooks Davis _substrcmp2(end, "by", "bytes") == 0) { 406662ff38aeSLuigi Rizzo p.fs.flags_fs |= DN_QSIZE_IS_BYTES; 40679758b77fSLuigi Rizzo } 40689758b77fSLuigi Rizzo ac--; av++; 40699758b77fSLuigi Rizzo break; 40709758b77fSLuigi Rizzo 40719758b77fSLuigi Rizzo case TOK_BUCKETS: 40729758b77fSLuigi Rizzo NEED1("buckets needs argument\n"); 407362ff38aeSLuigi Rizzo p.fs.rq_size = strtoul(av[0], NULL, 0); 40749758b77fSLuigi Rizzo ac--; av++; 40759758b77fSLuigi Rizzo break; 40769758b77fSLuigi Rizzo 40779758b77fSLuigi Rizzo case TOK_MASK: 40789758b77fSLuigi Rizzo NEED1("mask needs mask specifier\n"); 40799758b77fSLuigi Rizzo /* 40809758b77fSLuigi Rizzo * per-flow queue, mask is dst_ip, dst_port, 40819758b77fSLuigi Rizzo * src_ip, src_port, proto measured in bits 40829758b77fSLuigi Rizzo */ 40839758b77fSLuigi Rizzo par = NULL; 40849758b77fSLuigi Rizzo 40858195404bSBrooks Davis bzero(&p.fs.flow_mask, sizeof(p.fs.flow_mask)); 40869758b77fSLuigi Rizzo end = NULL; 40879758b77fSLuigi Rizzo 40889758b77fSLuigi Rizzo while (ac >= 1) { 4089571f8c1bSLuigi Rizzo uint32_t *p32 = NULL; 4090571f8c1bSLuigi Rizzo uint16_t *p16 = NULL; 40918195404bSBrooks Davis uint32_t *p20 = NULL; 40928195404bSBrooks Davis struct in6_addr *pa6 = NULL; 40938195404bSBrooks Davis uint32_t a; 40949758b77fSLuigi Rizzo 40959758b77fSLuigi Rizzo tok = match_token(dummynet_params, *av); 40969758b77fSLuigi Rizzo ac--; av++; 40979758b77fSLuigi Rizzo switch(tok) { 40989758b77fSLuigi Rizzo case TOK_ALL: 40999758b77fSLuigi Rizzo /* 41009758b77fSLuigi Rizzo * special case, all bits significant 41019758b77fSLuigi Rizzo */ 410262ff38aeSLuigi Rizzo p.fs.flow_mask.dst_ip = ~0; 410362ff38aeSLuigi Rizzo p.fs.flow_mask.src_ip = ~0; 410462ff38aeSLuigi Rizzo p.fs.flow_mask.dst_port = ~0; 410562ff38aeSLuigi Rizzo p.fs.flow_mask.src_port = ~0; 410662ff38aeSLuigi Rizzo p.fs.flow_mask.proto = ~0; 41078195404bSBrooks Davis n2mask(&(p.fs.flow_mask.dst_ip6), 128); 41088195404bSBrooks Davis n2mask(&(p.fs.flow_mask.src_ip6), 128); 41098195404bSBrooks Davis p.fs.flow_mask.flow_id6 = ~0; 411062ff38aeSLuigi Rizzo p.fs.flags_fs |= DN_HAVE_FLOW_MASK; 41119758b77fSLuigi Rizzo goto end_mask; 41129758b77fSLuigi Rizzo 41139758b77fSLuigi Rizzo case TOK_DSTIP: 411462ff38aeSLuigi Rizzo p32 = &p.fs.flow_mask.dst_ip; 41159758b77fSLuigi Rizzo break; 41169758b77fSLuigi Rizzo 41179758b77fSLuigi Rizzo case TOK_SRCIP: 411862ff38aeSLuigi Rizzo p32 = &p.fs.flow_mask.src_ip; 41199758b77fSLuigi Rizzo break; 41209758b77fSLuigi Rizzo 41218195404bSBrooks Davis case TOK_DSTIP6: 41228195404bSBrooks Davis pa6 = &(p.fs.flow_mask.dst_ip6); 41238195404bSBrooks Davis break; 41248195404bSBrooks Davis 41258195404bSBrooks Davis case TOK_SRCIP6: 41268195404bSBrooks Davis pa6 = &(p.fs.flow_mask.src_ip6); 41278195404bSBrooks Davis break; 41288195404bSBrooks Davis 41298195404bSBrooks Davis case TOK_FLOWID: 41308195404bSBrooks Davis p20 = &p.fs.flow_mask.flow_id6; 41318195404bSBrooks Davis break; 41328195404bSBrooks Davis 41339758b77fSLuigi Rizzo case TOK_DSTPORT: 413462ff38aeSLuigi Rizzo p16 = &p.fs.flow_mask.dst_port; 41359758b77fSLuigi Rizzo break; 41369758b77fSLuigi Rizzo 41379758b77fSLuigi Rizzo case TOK_SRCPORT: 413862ff38aeSLuigi Rizzo p16 = &p.fs.flow_mask.src_port; 41399758b77fSLuigi Rizzo break; 41409758b77fSLuigi Rizzo 41419758b77fSLuigi Rizzo case TOK_PROTO: 41429758b77fSLuigi Rizzo break; 41439758b77fSLuigi Rizzo 41449758b77fSLuigi Rizzo default: 41459758b77fSLuigi Rizzo ac++; av--; /* backtrack */ 41469758b77fSLuigi Rizzo goto end_mask; 41479758b77fSLuigi Rizzo } 41489758b77fSLuigi Rizzo if (ac < 1) 41499758b77fSLuigi Rizzo errx(EX_USAGE, "mask: value missing"); 41509758b77fSLuigi Rizzo if (*av[0] == '/') { 41519758b77fSLuigi Rizzo a = strtoul(av[0]+1, &end, 0); 41528195404bSBrooks Davis if (pa6 == NULL) 41539758b77fSLuigi Rizzo a = (a == 32) ? ~0 : (1 << a) - 1; 41549758b77fSLuigi Rizzo } else 41550a7197a8SLuigi Rizzo a = strtoul(av[0], &end, 0); 41569758b77fSLuigi Rizzo if (p32 != NULL) 41579758b77fSLuigi Rizzo *p32 = a; 41589758b77fSLuigi Rizzo else if (p16 != NULL) { 4159610055c9SBrooks Davis if (a > 0xFFFF) 41609758b77fSLuigi Rizzo errx(EX_DATAERR, 4161776c1005SBrooks Davis "port mask must be 16 bit"); 4162571f8c1bSLuigi Rizzo *p16 = (uint16_t)a; 41638195404bSBrooks Davis } else if (p20 != NULL) { 41648195404bSBrooks Davis if (a > 0xfffff) 41658195404bSBrooks Davis errx(EX_DATAERR, 41668195404bSBrooks Davis "flow_id mask must be 20 bit"); 41678195404bSBrooks Davis *p20 = (uint32_t)a; 41688195404bSBrooks Davis } else if (pa6 != NULL) { 41698195404bSBrooks Davis if (a < 0 || a > 128) 41708195404bSBrooks Davis errx(EX_DATAERR, 41718195404bSBrooks Davis "in6addr invalid mask len"); 41728195404bSBrooks Davis else 41738195404bSBrooks Davis n2mask(pa6, a); 41749758b77fSLuigi Rizzo } else { 4175610055c9SBrooks Davis if (a > 0xFF) 41769758b77fSLuigi Rizzo errx(EX_DATAERR, 4177776c1005SBrooks Davis "proto mask must be 8 bit"); 417862ff38aeSLuigi Rizzo p.fs.flow_mask.proto = (uint8_t)a; 41799758b77fSLuigi Rizzo } 41809758b77fSLuigi Rizzo if (a != 0) 418162ff38aeSLuigi Rizzo p.fs.flags_fs |= DN_HAVE_FLOW_MASK; 41829758b77fSLuigi Rizzo ac--; av++; 41839758b77fSLuigi Rizzo } /* end while, config masks */ 41849758b77fSLuigi Rizzo end_mask: 41859758b77fSLuigi Rizzo break; 41869758b77fSLuigi Rizzo 41879758b77fSLuigi Rizzo case TOK_RED: 41889758b77fSLuigi Rizzo case TOK_GRED: 41899758b77fSLuigi Rizzo NEED1("red/gred needs w_q/min_th/max_th/max_p\n"); 419062ff38aeSLuigi Rizzo p.fs.flags_fs |= DN_IS_RED; 41919758b77fSLuigi Rizzo if (tok == TOK_GRED) 419262ff38aeSLuigi Rizzo p.fs.flags_fs |= DN_IS_GENTLE_RED; 41939758b77fSLuigi Rizzo /* 41949758b77fSLuigi Rizzo * the format for parameters is w_q/min_th/max_th/max_p 41959758b77fSLuigi Rizzo */ 41969758b77fSLuigi Rizzo if ((end = strsep(&av[0], "/"))) { 41979758b77fSLuigi Rizzo double w_q = strtod(end, NULL); 41989758b77fSLuigi Rizzo if (w_q > 1 || w_q <= 0) 41999758b77fSLuigi Rizzo errx(EX_DATAERR, "0 < w_q <= 1"); 420062ff38aeSLuigi Rizzo p.fs.w_q = (int) (w_q * (1 << SCALE_RED)); 42019758b77fSLuigi Rizzo } 42029758b77fSLuigi Rizzo if ((end = strsep(&av[0], "/"))) { 420362ff38aeSLuigi Rizzo p.fs.min_th = strtoul(end, &end, 0); 42049758b77fSLuigi Rizzo if (*end == 'K' || *end == 'k') 420562ff38aeSLuigi Rizzo p.fs.min_th *= 1024; 42069758b77fSLuigi Rizzo } 42079758b77fSLuigi Rizzo if ((end = strsep(&av[0], "/"))) { 420862ff38aeSLuigi Rizzo p.fs.max_th = strtoul(end, &end, 0); 42099758b77fSLuigi Rizzo if (*end == 'K' || *end == 'k') 421062ff38aeSLuigi Rizzo p.fs.max_th *= 1024; 42119758b77fSLuigi Rizzo } 42129758b77fSLuigi Rizzo if ((end = strsep(&av[0], "/"))) { 42139758b77fSLuigi Rizzo double max_p = strtod(end, NULL); 42149758b77fSLuigi Rizzo if (max_p > 1 || max_p <= 0) 42159758b77fSLuigi Rizzo errx(EX_DATAERR, "0 < max_p <= 1"); 421662ff38aeSLuigi Rizzo p.fs.max_p = (int)(max_p * (1 << SCALE_RED)); 42179758b77fSLuigi Rizzo } 42189758b77fSLuigi Rizzo ac--; av++; 42199758b77fSLuigi Rizzo break; 42209758b77fSLuigi Rizzo 42219758b77fSLuigi Rizzo case TOK_DROPTAIL: 422262ff38aeSLuigi Rizzo p.fs.flags_fs &= ~(DN_IS_RED|DN_IS_GENTLE_RED); 42239758b77fSLuigi Rizzo break; 42249758b77fSLuigi Rizzo 42259758b77fSLuigi Rizzo case TOK_BW: 42269758b77fSLuigi Rizzo NEED1("bw needs bandwidth or interface\n"); 42279758b77fSLuigi Rizzo if (do_pipe != 1) 42289758b77fSLuigi Rizzo errx(EX_DATAERR, "bandwidth only valid for pipes"); 42299758b77fSLuigi Rizzo /* 42309758b77fSLuigi Rizzo * set clocking interface or bandwidth value 42319758b77fSLuigi Rizzo */ 42329758b77fSLuigi Rizzo if (av[0][0] >= 'a' && av[0][0] <= 'z') { 423362ff38aeSLuigi Rizzo int l = sizeof(p.if_name)-1; 42349758b77fSLuigi Rizzo /* interface name */ 423562ff38aeSLuigi Rizzo strncpy(p.if_name, av[0], l); 423662ff38aeSLuigi Rizzo p.if_name[l] = '\0'; 423762ff38aeSLuigi Rizzo p.bandwidth = 0; 42389758b77fSLuigi Rizzo } else { 423962ff38aeSLuigi Rizzo p.if_name[0] = '\0'; 424062ff38aeSLuigi Rizzo p.bandwidth = strtoul(av[0], &end, 0); 42419758b77fSLuigi Rizzo if (*end == 'K' || *end == 'k') { 42429758b77fSLuigi Rizzo end++; 424362ff38aeSLuigi Rizzo p.bandwidth *= 1000; 42449758b77fSLuigi Rizzo } else if (*end == 'M') { 42459758b77fSLuigi Rizzo end++; 424662ff38aeSLuigi Rizzo p.bandwidth *= 1000000; 42479758b77fSLuigi Rizzo } 4248cb0bfd9bSDavid Malone if ((*end == 'B' && 4249cb0bfd9bSDavid Malone _substrcmp2(end, "Bi", "Bit/s") != 0) || 425001750186SBrooks Davis _substrcmp2(end, "by", "bytes") == 0) 425162ff38aeSLuigi Rizzo p.bandwidth *= 8; 425262ff38aeSLuigi Rizzo if (p.bandwidth < 0) 42539758b77fSLuigi Rizzo errx(EX_DATAERR, "bandwidth too large"); 42549758b77fSLuigi Rizzo } 42559758b77fSLuigi Rizzo ac--; av++; 42569758b77fSLuigi Rizzo break; 42579758b77fSLuigi Rizzo 42589758b77fSLuigi Rizzo case TOK_DELAY: 42599758b77fSLuigi Rizzo if (do_pipe != 1) 42609758b77fSLuigi Rizzo errx(EX_DATAERR, "delay only valid for pipes"); 42619758b77fSLuigi Rizzo NEED1("delay needs argument 0..10000ms\n"); 426262ff38aeSLuigi Rizzo p.delay = strtoul(av[0], NULL, 0); 42639758b77fSLuigi Rizzo ac--; av++; 42649758b77fSLuigi Rizzo break; 42659758b77fSLuigi Rizzo 42669758b77fSLuigi Rizzo case TOK_WEIGHT: 42679758b77fSLuigi Rizzo if (do_pipe == 1) 42689758b77fSLuigi Rizzo errx(EX_DATAERR,"weight only valid for queues"); 42699758b77fSLuigi Rizzo NEED1("weight needs argument 0..100\n"); 427062ff38aeSLuigi Rizzo p.fs.weight = strtoul(av[0], &end, 0); 42719758b77fSLuigi Rizzo ac--; av++; 42729758b77fSLuigi Rizzo break; 42739758b77fSLuigi Rizzo 42749758b77fSLuigi Rizzo case TOK_PIPE: 42759758b77fSLuigi Rizzo if (do_pipe == 1) 42769758b77fSLuigi Rizzo errx(EX_DATAERR,"pipe only valid for queues"); 42779758b77fSLuigi Rizzo NEED1("pipe needs pipe_number\n"); 427862ff38aeSLuigi Rizzo p.fs.parent_nr = strtoul(av[0], &end, 0); 42799758b77fSLuigi Rizzo ac--; av++; 42809758b77fSLuigi Rizzo break; 42819758b77fSLuigi Rizzo 42829758b77fSLuigi Rizzo default: 428366d217f8SMaxim Konovalov errx(EX_DATAERR, "unrecognised option ``%s''", av[-1]); 42849758b77fSLuigi Rizzo } 42859758b77fSLuigi Rizzo } 42869758b77fSLuigi Rizzo if (do_pipe == 1) { 428762ff38aeSLuigi Rizzo if (p.pipe_nr == 0) 42889758b77fSLuigi Rizzo errx(EX_DATAERR, "pipe_nr must be > 0"); 428962ff38aeSLuigi Rizzo if (p.delay > 10000) 42909758b77fSLuigi Rizzo errx(EX_DATAERR, "delay must be < 10000"); 42919758b77fSLuigi Rizzo } else { /* do_pipe == 2, queue */ 429262ff38aeSLuigi Rizzo if (p.fs.parent_nr == 0) 42939758b77fSLuigi Rizzo errx(EX_DATAERR, "pipe must be > 0"); 429462ff38aeSLuigi Rizzo if (p.fs.weight >100) 42959758b77fSLuigi Rizzo errx(EX_DATAERR, "weight must be <= 100"); 42969758b77fSLuigi Rizzo } 429762ff38aeSLuigi Rizzo if (p.fs.flags_fs & DN_QSIZE_IS_BYTES) { 429862ff38aeSLuigi Rizzo if (p.fs.qsize > 1024*1024) 42999758b77fSLuigi Rizzo errx(EX_DATAERR, "queue size must be < 1MB"); 43009758b77fSLuigi Rizzo } else { 430162ff38aeSLuigi Rizzo if (p.fs.qsize > 100) 43029758b77fSLuigi Rizzo errx(EX_DATAERR, "2 <= queue size <= 100"); 43039758b77fSLuigi Rizzo } 430462ff38aeSLuigi Rizzo if (p.fs.flags_fs & DN_IS_RED) { 43059758b77fSLuigi Rizzo size_t len; 43069758b77fSLuigi Rizzo int lookup_depth, avg_pkt_size; 43079758b77fSLuigi Rizzo double s, idle, weight, w_q; 430862ff38aeSLuigi Rizzo struct clockinfo ck; 43099758b77fSLuigi Rizzo int t; 43109758b77fSLuigi Rizzo 431162ff38aeSLuigi Rizzo if (p.fs.min_th >= p.fs.max_th) 43129758b77fSLuigi Rizzo errx(EX_DATAERR, "min_th %d must be < than max_th %d", 431362ff38aeSLuigi Rizzo p.fs.min_th, p.fs.max_th); 431462ff38aeSLuigi Rizzo if (p.fs.max_th == 0) 43159758b77fSLuigi Rizzo errx(EX_DATAERR, "max_th must be > 0"); 43169758b77fSLuigi Rizzo 43179758b77fSLuigi Rizzo len = sizeof(int); 43189758b77fSLuigi Rizzo if (sysctlbyname("net.inet.ip.dummynet.red_lookup_depth", 43199758b77fSLuigi Rizzo &lookup_depth, &len, NULL, 0) == -1) 43209758b77fSLuigi Rizzo 43219758b77fSLuigi Rizzo errx(1, "sysctlbyname(\"%s\")", 43229758b77fSLuigi Rizzo "net.inet.ip.dummynet.red_lookup_depth"); 43239758b77fSLuigi Rizzo if (lookup_depth == 0) 43249758b77fSLuigi Rizzo errx(EX_DATAERR, "net.inet.ip.dummynet.red_lookup_depth" 43259758b77fSLuigi Rizzo " must be greater than zero"); 43269758b77fSLuigi Rizzo 43279758b77fSLuigi Rizzo len = sizeof(int); 43289758b77fSLuigi Rizzo if (sysctlbyname("net.inet.ip.dummynet.red_avg_pkt_size", 43299758b77fSLuigi Rizzo &avg_pkt_size, &len, NULL, 0) == -1) 43309758b77fSLuigi Rizzo 43319758b77fSLuigi Rizzo errx(1, "sysctlbyname(\"%s\")", 43329758b77fSLuigi Rizzo "net.inet.ip.dummynet.red_avg_pkt_size"); 43339758b77fSLuigi Rizzo if (avg_pkt_size == 0) 43349758b77fSLuigi Rizzo errx(EX_DATAERR, 43359758b77fSLuigi Rizzo "net.inet.ip.dummynet.red_avg_pkt_size must" 43369758b77fSLuigi Rizzo " be greater than zero"); 43379758b77fSLuigi Rizzo 43389758b77fSLuigi Rizzo len = sizeof(struct clockinfo); 433962ff38aeSLuigi Rizzo if (sysctlbyname("kern.clockrate", &ck, &len, NULL, 0) == -1) 43409758b77fSLuigi Rizzo errx(1, "sysctlbyname(\"%s\")", "kern.clockrate"); 43419758b77fSLuigi Rizzo 43429758b77fSLuigi Rizzo /* 43439758b77fSLuigi Rizzo * Ticks needed for sending a medium-sized packet. 43449758b77fSLuigi Rizzo * Unfortunately, when we are configuring a WF2Q+ queue, we 43459758b77fSLuigi Rizzo * do not have bandwidth information, because that is stored 43469758b77fSLuigi Rizzo * in the parent pipe, and also we have multiple queues 43479758b77fSLuigi Rizzo * competing for it. So we set s=0, which is not very 43489758b77fSLuigi Rizzo * correct. But on the other hand, why do we want RED with 43499758b77fSLuigi Rizzo * WF2Q+ ? 43509758b77fSLuigi Rizzo */ 435162ff38aeSLuigi Rizzo if (p.bandwidth==0) /* this is a WF2Q+ queue */ 43529758b77fSLuigi Rizzo s = 0; 43539758b77fSLuigi Rizzo else 435462ff38aeSLuigi Rizzo s = ck.hz * avg_pkt_size * 8 / p.bandwidth; 43559758b77fSLuigi Rizzo 43569758b77fSLuigi Rizzo /* 43579758b77fSLuigi Rizzo * max idle time (in ticks) before avg queue size becomes 0. 43589758b77fSLuigi Rizzo * NOTA: (3/w_q) is approx the value x so that 43599758b77fSLuigi Rizzo * (1-w_q)^x < 10^-3. 43609758b77fSLuigi Rizzo */ 436162ff38aeSLuigi Rizzo w_q = ((double)p.fs.w_q) / (1 << SCALE_RED); 43629758b77fSLuigi Rizzo idle = s * 3. / w_q; 436362ff38aeSLuigi Rizzo p.fs.lookup_step = (int)idle / lookup_depth; 436462ff38aeSLuigi Rizzo if (!p.fs.lookup_step) 436562ff38aeSLuigi Rizzo p.fs.lookup_step = 1; 43669758b77fSLuigi Rizzo weight = 1 - w_q; 436762ff38aeSLuigi Rizzo for (t = p.fs.lookup_step; t > 0; --t) 43689758b77fSLuigi Rizzo weight *= weight; 436962ff38aeSLuigi Rizzo p.fs.lookup_weight = (int)(weight * (1 << SCALE_RED)); 43709758b77fSLuigi Rizzo } 437162ff38aeSLuigi Rizzo i = do_cmd(IP_DUMMYNET_CONFIGURE, &p, sizeof p); 43729758b77fSLuigi Rizzo if (i) 43739758b77fSLuigi Rizzo err(1, "setsockopt(%s)", "IP_DUMMYNET_CONFIGURE"); 43749758b77fSLuigi Rizzo } 43759758b77fSLuigi Rizzo 43769758b77fSLuigi Rizzo static void 4377bd1d3456SMaxim Konovalov get_mac_addr_mask(const char *p, uint8_t *addr, uint8_t *mask) 43789758b77fSLuigi Rizzo { 43799758b77fSLuigi Rizzo int i, l; 4380bd1d3456SMaxim Konovalov char *ap, *ptr, *optr; 4381bd1d3456SMaxim Konovalov struct ether_addr *mac; 4382bd1d3456SMaxim Konovalov const char *macset = "0123456789abcdefABCDEF:"; 43839758b77fSLuigi Rizzo 4384bd1d3456SMaxim Konovalov if (strcmp(p, "any") == 0) { 4385bd1d3456SMaxim Konovalov for (i = 0; i < ETHER_ADDR_LEN; i++) 43869758b77fSLuigi Rizzo addr[i] = mask[i] = 0; 43879758b77fSLuigi Rizzo return; 4388bd1d3456SMaxim Konovalov } 43899758b77fSLuigi Rizzo 4390bd1d3456SMaxim Konovalov optr = ptr = strdup(p); 4391bd1d3456SMaxim Konovalov if ((ap = strsep(&ptr, "&/")) != NULL && *ap != 0) { 4392bd1d3456SMaxim Konovalov l = strlen(ap); 4393bd1d3456SMaxim Konovalov if (strspn(ap, macset) != l || (mac = ether_aton(ap)) == NULL) 4394bd1d3456SMaxim Konovalov errx(EX_DATAERR, "Incorrect MAC address"); 4395bd1d3456SMaxim Konovalov bcopy(mac, addr, ETHER_ADDR_LEN); 4396bd1d3456SMaxim Konovalov } else 4397bd1d3456SMaxim Konovalov errx(EX_DATAERR, "Incorrect MAC address"); 4398bd1d3456SMaxim Konovalov 4399bd1d3456SMaxim Konovalov if (ptr != NULL) { /* we have mask? */ 4400bd1d3456SMaxim Konovalov if (p[ptr - optr - 1] == '/') { /* mask len */ 4401bd1d3456SMaxim Konovalov l = strtol(ptr, &ap, 10); 4402bd1d3456SMaxim Konovalov if (*ap != 0 || l > ETHER_ADDR_LEN * 8 || l < 0) 4403bd1d3456SMaxim Konovalov errx(EX_DATAERR, "Incorrect mask length"); 4404bd1d3456SMaxim Konovalov for (i = 0; l > 0 && i < ETHER_ADDR_LEN; l -= 8, i++) 44059758b77fSLuigi Rizzo mask[i] = (l >= 8) ? 0xff: (~0) << (8 - l); 4406bd1d3456SMaxim Konovalov } else { /* mask */ 4407bd1d3456SMaxim Konovalov l = strlen(ptr); 4408bd1d3456SMaxim Konovalov if (strspn(ptr, macset) != l || 4409bd1d3456SMaxim Konovalov (mac = ether_aton(ptr)) == NULL) 4410bd1d3456SMaxim Konovalov errx(EX_DATAERR, "Incorrect mask"); 4411bd1d3456SMaxim Konovalov bcopy(mac, mask, ETHER_ADDR_LEN); 44129758b77fSLuigi Rizzo } 4413bd1d3456SMaxim Konovalov } else { /* default mask: ff:ff:ff:ff:ff:ff */ 4414bd1d3456SMaxim Konovalov for (i = 0; i < ETHER_ADDR_LEN; i++) 44159758b77fSLuigi Rizzo mask[i] = 0xff; 44169758b77fSLuigi Rizzo } 4417bd1d3456SMaxim Konovalov for (i = 0; i < ETHER_ADDR_LEN; i++) 44189758b77fSLuigi Rizzo addr[i] &= mask[i]; 4419bd1d3456SMaxim Konovalov 4420bd1d3456SMaxim Konovalov free(optr); 44219758b77fSLuigi Rizzo } 44229758b77fSLuigi Rizzo 44239758b77fSLuigi Rizzo /* 44249758b77fSLuigi Rizzo * helper function, updates the pointer to cmd with the length 44259758b77fSLuigi Rizzo * of the current command, and also cleans up the first word of 44269758b77fSLuigi Rizzo * the new command in case it has been clobbered before. 44279758b77fSLuigi Rizzo */ 44289758b77fSLuigi Rizzo static ipfw_insn * 44299758b77fSLuigi Rizzo next_cmd(ipfw_insn *cmd) 44309758b77fSLuigi Rizzo { 44319758b77fSLuigi Rizzo cmd += F_LEN(cmd); 44329758b77fSLuigi Rizzo bzero(cmd, sizeof(*cmd)); 44339758b77fSLuigi Rizzo return cmd; 44349758b77fSLuigi Rizzo } 44359758b77fSLuigi Rizzo 44369758b77fSLuigi Rizzo /* 443762ff38aeSLuigi Rizzo * Takes arguments and copies them into a comment 443862ff38aeSLuigi Rizzo */ 443962ff38aeSLuigi Rizzo static void 444062ff38aeSLuigi Rizzo fill_comment(ipfw_insn *cmd, int ac, char **av) 444162ff38aeSLuigi Rizzo { 444262ff38aeSLuigi Rizzo int i, l; 444362ff38aeSLuigi Rizzo char *p = (char *)(cmd + 1); 444462ff38aeSLuigi Rizzo 444562ff38aeSLuigi Rizzo cmd->opcode = O_NOP; 444662ff38aeSLuigi Rizzo cmd->len = (cmd->len & (F_NOT | F_OR)); 444762ff38aeSLuigi Rizzo 444862ff38aeSLuigi Rizzo /* Compute length of comment string. */ 444962ff38aeSLuigi Rizzo for (i = 0, l = 0; i < ac; i++) 445062ff38aeSLuigi Rizzo l += strlen(av[i]) + 1; 445162ff38aeSLuigi Rizzo if (l == 0) 445262ff38aeSLuigi Rizzo return; 445362ff38aeSLuigi Rizzo if (l > 84) 445462ff38aeSLuigi Rizzo errx(EX_DATAERR, 445562ff38aeSLuigi Rizzo "comment too long (max 80 chars)"); 445662ff38aeSLuigi Rizzo l = 1 + (l+3)/4; 445762ff38aeSLuigi Rizzo cmd->len = (cmd->len & (F_NOT | F_OR)) | l; 445862ff38aeSLuigi Rizzo for (i = 0; i < ac; i++) { 445962ff38aeSLuigi Rizzo strcpy(p, av[i]); 446062ff38aeSLuigi Rizzo p += strlen(av[i]); 446162ff38aeSLuigi Rizzo *p++ = ' '; 446262ff38aeSLuigi Rizzo } 446362ff38aeSLuigi Rizzo *(--p) = '\0'; 446462ff38aeSLuigi Rizzo } 446562ff38aeSLuigi Rizzo 446662ff38aeSLuigi Rizzo /* 44679758b77fSLuigi Rizzo * A function to fill simple commands of size 1. 44689758b77fSLuigi Rizzo * Existing flags are preserved. 44699758b77fSLuigi Rizzo */ 44709758b77fSLuigi Rizzo static void 4471571f8c1bSLuigi Rizzo fill_cmd(ipfw_insn *cmd, enum ipfw_opcodes opcode, int flags, uint16_t arg) 44729758b77fSLuigi Rizzo { 44739758b77fSLuigi Rizzo cmd->opcode = opcode; 44749758b77fSLuigi Rizzo cmd->len = ((cmd->len | flags) & (F_NOT | F_OR)) | 1; 44759758b77fSLuigi Rizzo cmd->arg1 = arg; 44769758b77fSLuigi Rizzo } 44779758b77fSLuigi Rizzo 44789758b77fSLuigi Rizzo /* 44799758b77fSLuigi Rizzo * Fetch and add the MAC address and type, with masks. This generates one or 44809758b77fSLuigi Rizzo * two microinstructions, and returns the pointer to the last one. 44819758b77fSLuigi Rizzo */ 44829758b77fSLuigi Rizzo static ipfw_insn * 44839758b77fSLuigi Rizzo add_mac(ipfw_insn *cmd, int ac, char *av[]) 44849758b77fSLuigi Rizzo { 4485e706181bSLuigi Rizzo ipfw_insn_mac *mac; 44869758b77fSLuigi Rizzo 448799e5e645SLuigi Rizzo if (ac < 2) 44885a155b40SLuigi Rizzo errx(EX_DATAERR, "MAC dst src"); 44899758b77fSLuigi Rizzo 44909758b77fSLuigi Rizzo cmd->opcode = O_MACADDR2; 44919758b77fSLuigi Rizzo cmd->len = (cmd->len & (F_NOT | F_OR)) | F_INSN_SIZE(ipfw_insn_mac); 44929758b77fSLuigi Rizzo 44939758b77fSLuigi Rizzo mac = (ipfw_insn_mac *)cmd; 44949758b77fSLuigi Rizzo get_mac_addr_mask(av[0], mac->addr, mac->mask); /* dst */ 4495bd1d3456SMaxim Konovalov get_mac_addr_mask(av[1], &(mac->addr[ETHER_ADDR_LEN]), 4496bd1d3456SMaxim Konovalov &(mac->mask[ETHER_ADDR_LEN])); /* src */ 4497e706181bSLuigi Rizzo return cmd; 44989758b77fSLuigi Rizzo } 44999758b77fSLuigi Rizzo 4500e706181bSLuigi Rizzo static ipfw_insn * 4501e706181bSLuigi Rizzo add_mactype(ipfw_insn *cmd, int ac, char *av) 4502e706181bSLuigi Rizzo { 4503e706181bSLuigi Rizzo if (ac < 1) 4504e706181bSLuigi Rizzo errx(EX_DATAERR, "missing MAC type"); 4505e706181bSLuigi Rizzo if (strcmp(av, "any") != 0) { /* we have a non-null type */ 4506e706181bSLuigi Rizzo fill_newports((ipfw_insn_u16 *)cmd, av, IPPROTO_ETHERTYPE); 4507e706181bSLuigi Rizzo cmd->opcode = O_MAC_TYPE; 45089758b77fSLuigi Rizzo return cmd; 4509e706181bSLuigi Rizzo } else 4510e706181bSLuigi Rizzo return NULL; 4511e706181bSLuigi Rizzo } 4512e706181bSLuigi Rizzo 4513e706181bSLuigi Rizzo static ipfw_insn * 451436c263ccSHajimu UMEMOTO add_proto0(ipfw_insn *cmd, char *av, u_char *protop) 4515e706181bSLuigi Rizzo { 4516e706181bSLuigi Rizzo struct protoent *pe; 451736c263ccSHajimu UMEMOTO char *ep; 451836c263ccSHajimu UMEMOTO int proto; 45198195404bSBrooks Davis 4520c6ec0226SHajimu UMEMOTO proto = strtol(av, &ep, 10); 4521c6ec0226SHajimu UMEMOTO if (*ep != '\0' || proto <= 0) { 452236c263ccSHajimu UMEMOTO if ((pe = getprotobyname(av)) == NULL) 452336c263ccSHajimu UMEMOTO return NULL; 452436c263ccSHajimu UMEMOTO proto = pe->p_proto; 452536c263ccSHajimu UMEMOTO } 452636c263ccSHajimu UMEMOTO 452736c263ccSHajimu UMEMOTO fill_cmd(cmd, O_PROTO, 0, proto); 452836c263ccSHajimu UMEMOTO *protop = proto; 452936c263ccSHajimu UMEMOTO return cmd; 453036c263ccSHajimu UMEMOTO } 453136c263ccSHajimu UMEMOTO 453236c263ccSHajimu UMEMOTO static ipfw_insn * 453336c263ccSHajimu UMEMOTO add_proto(ipfw_insn *cmd, char *av, u_char *protop) 453436c263ccSHajimu UMEMOTO { 453536c263ccSHajimu UMEMOTO u_char proto = IPPROTO_IP; 4536e706181bSLuigi Rizzo 4537c6ec0226SHajimu UMEMOTO if (_substrcmp(av, "all") == 0 || strcmp(av, "ip") == 0) 453857cd6d26SMax Laier ; /* do not set O_IP4 nor O_IP6 */ 453936c263ccSHajimu UMEMOTO else if (strcmp(av, "ip4") == 0) 454036c263ccSHajimu UMEMOTO /* explicit "just IPv4" rule */ 454136c263ccSHajimu UMEMOTO fill_cmd(cmd, O_IP4, 0, 0); 454236c263ccSHajimu UMEMOTO else if (strcmp(av, "ip6") == 0) { 454336c263ccSHajimu UMEMOTO /* explicit "just IPv6" rule */ 454436c263ccSHajimu UMEMOTO proto = IPPROTO_IPV6; 454536c263ccSHajimu UMEMOTO fill_cmd(cmd, O_IP6, 0, 0); 454636c263ccSHajimu UMEMOTO } else 454736c263ccSHajimu UMEMOTO return add_proto0(cmd, av, protop); 454836c263ccSHajimu UMEMOTO 454936c263ccSHajimu UMEMOTO *protop = proto; 455036c263ccSHajimu UMEMOTO return cmd; 455136c263ccSHajimu UMEMOTO } 455236c263ccSHajimu UMEMOTO 455336c263ccSHajimu UMEMOTO static ipfw_insn * 455436c263ccSHajimu UMEMOTO add_proto_compat(ipfw_insn *cmd, char *av, u_char *protop) 455536c263ccSHajimu UMEMOTO { 455636c263ccSHajimu UMEMOTO u_char proto = IPPROTO_IP; 455736c263ccSHajimu UMEMOTO 455836c263ccSHajimu UMEMOTO if (_substrcmp(av, "all") == 0 || strcmp(av, "ip") == 0) 455936c263ccSHajimu UMEMOTO ; /* do not set O_IP4 nor O_IP6 */ 456057cd6d26SMax Laier else if (strcmp(av, "ipv4") == 0 || strcmp(av, "ip4") == 0) 456157cd6d26SMax Laier /* explicit "just IPv4" rule */ 456257cd6d26SMax Laier fill_cmd(cmd, O_IP4, 0, 0); 456357cd6d26SMax Laier else if (strcmp(av, "ipv6") == 0 || strcmp(av, "ip6") == 0) { 456457cd6d26SMax Laier /* explicit "just IPv6" rule */ 456536c263ccSHajimu UMEMOTO proto = IPPROTO_IPV6; 456657cd6d26SMax Laier fill_cmd(cmd, O_IP6, 0, 0); 456736c263ccSHajimu UMEMOTO } else 456836c263ccSHajimu UMEMOTO return add_proto0(cmd, av, protop); 45698195404bSBrooks Davis 457036c263ccSHajimu UMEMOTO *protop = proto; 4571e706181bSLuigi Rizzo return cmd; 4572e706181bSLuigi Rizzo } 4573e706181bSLuigi Rizzo 4574e706181bSLuigi Rizzo static ipfw_insn * 4575e706181bSLuigi Rizzo add_srcip(ipfw_insn *cmd, char *av) 4576e706181bSLuigi Rizzo { 4577e706181bSLuigi Rizzo fill_ip((ipfw_insn_ip *)cmd, av); 4578e706181bSLuigi Rizzo if (cmd->opcode == O_IP_DST_SET) /* set */ 4579e706181bSLuigi Rizzo cmd->opcode = O_IP_SRC_SET; 4580cd8b5ae0SRuslan Ermilov else if (cmd->opcode == O_IP_DST_LOOKUP) /* table */ 4581cd8b5ae0SRuslan Ermilov cmd->opcode = O_IP_SRC_LOOKUP; 4582e706181bSLuigi Rizzo else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) /* me */ 4583e706181bSLuigi Rizzo cmd->opcode = O_IP_SRC_ME; 4584e706181bSLuigi Rizzo else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn_u32)) /* one IP */ 4585e706181bSLuigi Rizzo cmd->opcode = O_IP_SRC; 4586571f8c1bSLuigi Rizzo else /* addr/mask */ 4587e706181bSLuigi Rizzo cmd->opcode = O_IP_SRC_MASK; 4588e706181bSLuigi Rizzo return cmd; 4589e706181bSLuigi Rizzo } 4590e706181bSLuigi Rizzo 4591e706181bSLuigi Rizzo static ipfw_insn * 4592e706181bSLuigi Rizzo add_dstip(ipfw_insn *cmd, char *av) 4593e706181bSLuigi Rizzo { 4594e706181bSLuigi Rizzo fill_ip((ipfw_insn_ip *)cmd, av); 4595e706181bSLuigi Rizzo if (cmd->opcode == O_IP_DST_SET) /* set */ 4596e706181bSLuigi Rizzo ; 4597cd8b5ae0SRuslan Ermilov else if (cmd->opcode == O_IP_DST_LOOKUP) /* table */ 4598cd8b5ae0SRuslan Ermilov ; 4599e706181bSLuigi Rizzo else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) /* me */ 4600e706181bSLuigi Rizzo cmd->opcode = O_IP_DST_ME; 4601e706181bSLuigi Rizzo else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn_u32)) /* one IP */ 4602e706181bSLuigi Rizzo cmd->opcode = O_IP_DST; 4603571f8c1bSLuigi Rizzo else /* addr/mask */ 4604e706181bSLuigi Rizzo cmd->opcode = O_IP_DST_MASK; 4605e706181bSLuigi Rizzo return cmd; 4606e706181bSLuigi Rizzo } 4607e706181bSLuigi Rizzo 4608e706181bSLuigi Rizzo static ipfw_insn * 4609e706181bSLuigi Rizzo add_ports(ipfw_insn *cmd, char *av, u_char proto, int opcode) 4610e706181bSLuigi Rizzo { 461101750186SBrooks Davis if (_substrcmp(av, "any") == 0) { 4612e706181bSLuigi Rizzo return NULL; 4613e706181bSLuigi Rizzo } else if (fill_newports((ipfw_insn_u16 *)cmd, av, proto)) { 4614e706181bSLuigi Rizzo /* XXX todo: check that we have a protocol with ports */ 4615e706181bSLuigi Rizzo cmd->opcode = opcode; 4616e706181bSLuigi Rizzo return cmd; 4617e706181bSLuigi Rizzo } 4618e706181bSLuigi Rizzo return NULL; 46199758b77fSLuigi Rizzo } 46209758b77fSLuigi Rizzo 46218195404bSBrooks Davis static ipfw_insn * 46228195404bSBrooks Davis add_src(ipfw_insn *cmd, char *av, u_char proto) 46238195404bSBrooks Davis { 46248195404bSBrooks Davis struct in6_addr a; 4625926bbf90SMax Laier char *host, *ch; 4626926bbf90SMax Laier ipfw_insn *ret = NULL; 4627926bbf90SMax Laier 4628926bbf90SMax Laier if ((host = strdup(av)) == NULL) 4629926bbf90SMax Laier return NULL; 4630926bbf90SMax Laier if ((ch = strrchr(host, '/')) != NULL) 4631926bbf90SMax Laier *ch = '\0'; 46328195404bSBrooks Davis 46338195404bSBrooks Davis if (proto == IPPROTO_IPV6 || strcmp(av, "me6") == 0 || 4634926bbf90SMax Laier inet_pton(AF_INET6, host, &a)) 4635926bbf90SMax Laier ret = add_srcip6(cmd, av); 46368195404bSBrooks Davis /* XXX: should check for IPv4, not !IPv6 */ 4637e28cb025SDavid Malone if (ret == NULL && (proto == IPPROTO_IP || strcmp(av, "me") == 0 || 4638e28cb025SDavid Malone !inet_pton(AF_INET6, host, &a))) 4639926bbf90SMax Laier ret = add_srcip(cmd, av); 4640e28cb025SDavid Malone if (ret == NULL && strcmp(av, "any") != 0) 4641926bbf90SMax Laier ret = cmd; 46428195404bSBrooks Davis 4643926bbf90SMax Laier free(host); 4644926bbf90SMax Laier return ret; 46458195404bSBrooks Davis } 46468195404bSBrooks Davis 46478195404bSBrooks Davis static ipfw_insn * 46488195404bSBrooks Davis add_dst(ipfw_insn *cmd, char *av, u_char proto) 46498195404bSBrooks Davis { 46508195404bSBrooks Davis struct in6_addr a; 4651926bbf90SMax Laier char *host, *ch; 4652926bbf90SMax Laier ipfw_insn *ret = NULL; 4653926bbf90SMax Laier 4654926bbf90SMax Laier if ((host = strdup(av)) == NULL) 4655926bbf90SMax Laier return NULL; 4656926bbf90SMax Laier if ((ch = strrchr(host, '/')) != NULL) 4657926bbf90SMax Laier *ch = '\0'; 46588195404bSBrooks Davis 46598195404bSBrooks Davis if (proto == IPPROTO_IPV6 || strcmp(av, "me6") == 0 || 4660926bbf90SMax Laier inet_pton(AF_INET6, host, &a)) 4661926bbf90SMax Laier ret = add_dstip6(cmd, av); 46628195404bSBrooks Davis /* XXX: should check for IPv4, not !IPv6 */ 4663e28cb025SDavid Malone if (ret == NULL && (proto == IPPROTO_IP || strcmp(av, "me") == 0 || 4664e28cb025SDavid Malone !inet_pton(AF_INET6, host, &a))) 4665926bbf90SMax Laier ret = add_dstip(cmd, av); 4666e28cb025SDavid Malone if (ret == NULL && strcmp(av, "any") != 0) 4667926bbf90SMax Laier ret = cmd; 46688195404bSBrooks Davis 4669926bbf90SMax Laier free(host); 4670926bbf90SMax Laier return ret; 46718195404bSBrooks Davis } 46728195404bSBrooks Davis 46739758b77fSLuigi Rizzo /* 46749758b77fSLuigi Rizzo * Parse arguments and assemble the microinstructions which make up a rule. 46759758b77fSLuigi Rizzo * Rules are added into the 'rulebuf' and then copied in the correct order 46769758b77fSLuigi Rizzo * into the actual rule. 46779758b77fSLuigi Rizzo * 4678974dfe30SBrian Feldman * The syntax for a rule starts with the action, followed by 4679974dfe30SBrian Feldman * optional action parameters, and the various match patterns. 46809d5abbddSJens Schweikhardt * In the assembled microcode, the first opcode must be an O_PROBE_STATE 46819758b77fSLuigi Rizzo * (generated if the rule includes a keep-state option), then the 4682974dfe30SBrian Feldman * various match patterns, log/altq actions, and the actual action. 46839758b77fSLuigi Rizzo * 46849758b77fSLuigi Rizzo */ 46859758b77fSLuigi Rizzo static void 46869758b77fSLuigi Rizzo add(int ac, char *av[]) 46879758b77fSLuigi Rizzo { 46889758b77fSLuigi Rizzo /* 46899758b77fSLuigi Rizzo * rules are added into the 'rulebuf' and then copied in 46909758b77fSLuigi Rizzo * the correct order into the actual rule. 46919758b77fSLuigi Rizzo * Some things that need to go out of order (prob, action etc.) 46929758b77fSLuigi Rizzo * go into actbuf[]. 46939758b77fSLuigi Rizzo */ 4694571f8c1bSLuigi Rizzo static uint32_t rulebuf[255], actbuf[255], cmdbuf[255]; 46959758b77fSLuigi Rizzo 469662ff38aeSLuigi Rizzo ipfw_insn *src, *dst, *cmd, *action, *prev=NULL; 4697e706181bSLuigi Rizzo ipfw_insn *first_cmd; /* first match pattern */ 46989758b77fSLuigi Rizzo 46999758b77fSLuigi Rizzo struct ip_fw *rule; 47009758b77fSLuigi Rizzo 47019758b77fSLuigi Rizzo /* 47029758b77fSLuigi Rizzo * various flags used to record that we entered some fields. 47039758b77fSLuigi Rizzo */ 470452bc23abSLuigi Rizzo ipfw_insn *have_state = NULL; /* check-state or keep-state */ 47056a7d5cb6SOleg Bulyzhin ipfw_insn *have_log = NULL, *have_altq = NULL, *have_tag = NULL; 47069ec4f2e1SMaxim Konovalov size_t len; 47079758b77fSLuigi Rizzo 47089758b77fSLuigi Rizzo int i; 47099758b77fSLuigi Rizzo 47109758b77fSLuigi Rizzo int open_par = 0; /* open parenthesis ( */ 47119758b77fSLuigi Rizzo 47129758b77fSLuigi Rizzo /* proto is here because it is used to fetch ports */ 47139758b77fSLuigi Rizzo u_char proto = IPPROTO_IP; /* default protocol */ 47149758b77fSLuigi Rizzo 471512b5dc6aSLuigi Rizzo double match_prob = 1; /* match probability, default is always match */ 471612b5dc6aSLuigi Rizzo 47179758b77fSLuigi Rizzo bzero(actbuf, sizeof(actbuf)); /* actions go here */ 47189758b77fSLuigi Rizzo bzero(cmdbuf, sizeof(cmdbuf)); 47199758b77fSLuigi Rizzo bzero(rulebuf, sizeof(rulebuf)); 47209758b77fSLuigi Rizzo 47219758b77fSLuigi Rizzo rule = (struct ip_fw *)rulebuf; 47229758b77fSLuigi Rizzo cmd = (ipfw_insn *)cmdbuf; 47239758b77fSLuigi Rizzo action = (ipfw_insn *)actbuf; 47249758b77fSLuigi Rizzo 47259758b77fSLuigi Rizzo av++; ac--; 47269758b77fSLuigi Rizzo 47279758b77fSLuigi Rizzo /* [rule N] -- Rule number optional */ 47289758b77fSLuigi Rizzo if (ac && isdigit(**av)) { 47299758b77fSLuigi Rizzo rule->rulenum = atoi(*av); 47309758b77fSLuigi Rizzo av++; 47319758b77fSLuigi Rizzo ac--; 47329758b77fSLuigi Rizzo } 47339758b77fSLuigi Rizzo 47343004afcaSLuigi Rizzo /* [set N] -- set number (0..RESVD_SET), optional */ 473501750186SBrooks Davis if (ac > 1 && _substrcmp(*av, "set") == 0) { 473643405724SLuigi Rizzo int set = strtoul(av[1], NULL, 10); 47373004afcaSLuigi Rizzo if (set < 0 || set > RESVD_SET) 473843405724SLuigi Rizzo errx(EX_DATAERR, "illegal set %s", av[1]); 473943405724SLuigi Rizzo rule->set = set; 474043405724SLuigi Rizzo av += 2; ac -= 2; 474143405724SLuigi Rizzo } 474243405724SLuigi Rizzo 47439758b77fSLuigi Rizzo /* [prob D] -- match probability, optional */ 474401750186SBrooks Davis if (ac > 1 && _substrcmp(*av, "prob") == 0) { 474512b5dc6aSLuigi Rizzo match_prob = strtod(av[1], NULL); 47469758b77fSLuigi Rizzo 474712b5dc6aSLuigi Rizzo if (match_prob <= 0 || match_prob > 1) 47489758b77fSLuigi Rizzo errx(EX_DATAERR, "illegal match prob. %s", av[1]); 47499758b77fSLuigi Rizzo av += 2; ac -= 2; 47509758b77fSLuigi Rizzo } 47519758b77fSLuigi Rizzo 47529758b77fSLuigi Rizzo /* action -- mandatory */ 47539758b77fSLuigi Rizzo NEED1("missing action"); 47549758b77fSLuigi Rizzo i = match_token(rule_actions, *av); 47559758b77fSLuigi Rizzo ac--; av++; 47569758b77fSLuigi Rizzo action->len = 1; /* default */ 47579758b77fSLuigi Rizzo switch(i) { 47589758b77fSLuigi Rizzo case TOK_CHECKSTATE: 475952bc23abSLuigi Rizzo have_state = action; 47609758b77fSLuigi Rizzo action->opcode = O_CHECK_STATE; 47619758b77fSLuigi Rizzo break; 47629758b77fSLuigi Rizzo 47639758b77fSLuigi Rizzo case TOK_ACCEPT: 47649758b77fSLuigi Rizzo action->opcode = O_ACCEPT; 47659758b77fSLuigi Rizzo break; 47669758b77fSLuigi Rizzo 47679758b77fSLuigi Rizzo case TOK_DENY: 47689758b77fSLuigi Rizzo action->opcode = O_DENY; 47695e43aef8SLuigi Rizzo action->arg1 = 0; 47705e43aef8SLuigi Rizzo break; 47715e43aef8SLuigi Rizzo 47725e43aef8SLuigi Rizzo case TOK_REJECT: 47735e43aef8SLuigi Rizzo action->opcode = O_REJECT; 47745e43aef8SLuigi Rizzo action->arg1 = ICMP_UNREACH_HOST; 47755e43aef8SLuigi Rizzo break; 47765e43aef8SLuigi Rizzo 47775e43aef8SLuigi Rizzo case TOK_RESET: 47785e43aef8SLuigi Rizzo action->opcode = O_REJECT; 47795e43aef8SLuigi Rizzo action->arg1 = ICMP_REJECT_RST; 47805e43aef8SLuigi Rizzo break; 47815e43aef8SLuigi Rizzo 47829066356bSBjoern A. Zeeb case TOK_RESET6: 47839066356bSBjoern A. Zeeb action->opcode = O_UNREACH6; 47849066356bSBjoern A. Zeeb action->arg1 = ICMP6_UNREACH_RST; 47859066356bSBjoern A. Zeeb break; 47869066356bSBjoern A. Zeeb 47875e43aef8SLuigi Rizzo case TOK_UNREACH: 47885e43aef8SLuigi Rizzo action->opcode = O_REJECT; 47895e43aef8SLuigi Rizzo NEED1("missing reject code"); 47905e43aef8SLuigi Rizzo fill_reject_code(&action->arg1, *av); 47915e43aef8SLuigi Rizzo ac--; av++; 47929758b77fSLuigi Rizzo break; 47939758b77fSLuigi Rizzo 47949066356bSBjoern A. Zeeb case TOK_UNREACH6: 47959066356bSBjoern A. Zeeb action->opcode = O_UNREACH6; 47969066356bSBjoern A. Zeeb NEED1("missing unreach code"); 47979066356bSBjoern A. Zeeb fill_unreach6_code(&action->arg1, *av); 47989066356bSBjoern A. Zeeb ac--; av++; 47999066356bSBjoern A. Zeeb break; 48009066356bSBjoern A. Zeeb 48019758b77fSLuigi Rizzo case TOK_COUNT: 48029758b77fSLuigi Rizzo action->opcode = O_COUNT; 48039758b77fSLuigi Rizzo break; 48049758b77fSLuigi Rizzo 48059758b77fSLuigi Rizzo case TOK_QUEUE: 48069758b77fSLuigi Rizzo action->opcode = O_QUEUE; 480740b1ae9eSGleb Smirnoff goto chkarg; 480840b1ae9eSGleb Smirnoff case TOK_PIPE: 48099758b77fSLuigi Rizzo action->opcode = O_PIPE; 481040b1ae9eSGleb Smirnoff goto chkarg; 481140b1ae9eSGleb Smirnoff case TOK_SKIPTO: 48129758b77fSLuigi Rizzo action->opcode = O_SKIPTO; 481340b1ae9eSGleb Smirnoff goto chkarg; 481440b1ae9eSGleb Smirnoff case TOK_NETGRAPH: 481540b1ae9eSGleb Smirnoff action->opcode = O_NETGRAPH; 481640b1ae9eSGleb Smirnoff goto chkarg; 481740b1ae9eSGleb Smirnoff case TOK_NGTEE: 481840b1ae9eSGleb Smirnoff action->opcode = O_NGTEE; 481940b1ae9eSGleb Smirnoff goto chkarg; 48209758b77fSLuigi Rizzo case TOK_DIVERT: 482140b1ae9eSGleb Smirnoff action->opcode = O_DIVERT; 482240b1ae9eSGleb Smirnoff goto chkarg; 48239758b77fSLuigi Rizzo case TOK_TEE: 482440b1ae9eSGleb Smirnoff action->opcode = O_TEE; 482540b1ae9eSGleb Smirnoff chkarg: 482640b1ae9eSGleb Smirnoff if (!ac) 482740b1ae9eSGleb Smirnoff errx(EX_USAGE, "missing argument for %s", *(av - 1)); 482840b1ae9eSGleb Smirnoff if (isdigit(**av)) { 482940b1ae9eSGleb Smirnoff action->arg1 = strtoul(*av, NULL, 10); 483040b1ae9eSGleb Smirnoff if (action->arg1 <= 0 || action->arg1 >= IP_FW_TABLEARG) 483140b1ae9eSGleb Smirnoff errx(EX_DATAERR, "illegal argument for %s", 483240b1ae9eSGleb Smirnoff *(av - 1)); 483340b1ae9eSGleb Smirnoff } else if (_substrcmp(*av, TABLEARG) == 0) { 483440b1ae9eSGleb Smirnoff action->arg1 = IP_FW_TABLEARG; 483540b1ae9eSGleb Smirnoff } else if (i == TOK_DIVERT || i == TOK_TEE) { 48369758b77fSLuigi Rizzo struct servent *s; 48379758b77fSLuigi Rizzo setservent(1); 48389758b77fSLuigi Rizzo s = getservbyname(av[0], "divert"); 48399758b77fSLuigi Rizzo if (s != NULL) 48409758b77fSLuigi Rizzo action->arg1 = ntohs(s->s_port); 48419758b77fSLuigi Rizzo else 48429758b77fSLuigi Rizzo errx(EX_DATAERR, "illegal divert/tee port"); 484340b1ae9eSGleb Smirnoff } else 484440b1ae9eSGleb Smirnoff errx(EX_DATAERR, "illegal argument for %s", *(av - 1)); 4845670742a1SGleb Smirnoff ac--; av++; 4846670742a1SGleb Smirnoff break; 4847670742a1SGleb Smirnoff 48489758b77fSLuigi Rizzo case TOK_FORWARD: { 48499758b77fSLuigi Rizzo ipfw_insn_sa *p = (ipfw_insn_sa *)action; 48509758b77fSLuigi Rizzo char *s, *end; 48519758b77fSLuigi Rizzo 48529758b77fSLuigi Rizzo NEED1("missing forward address[:port]"); 48539758b77fSLuigi Rizzo 48549758b77fSLuigi Rizzo action->opcode = O_FORWARD_IP; 48559758b77fSLuigi Rizzo action->len = F_INSN_SIZE(ipfw_insn_sa); 48569758b77fSLuigi Rizzo 48579758b77fSLuigi Rizzo p->sa.sin_len = sizeof(struct sockaddr_in); 48589758b77fSLuigi Rizzo p->sa.sin_family = AF_INET; 48599758b77fSLuigi Rizzo p->sa.sin_port = 0; 48609758b77fSLuigi Rizzo /* 48619758b77fSLuigi Rizzo * locate the address-port separator (':' or ',') 48629758b77fSLuigi Rizzo */ 48639758b77fSLuigi Rizzo s = strchr(*av, ':'); 48649758b77fSLuigi Rizzo if (s == NULL) 48659758b77fSLuigi Rizzo s = strchr(*av, ','); 48669758b77fSLuigi Rizzo if (s != NULL) { 48679758b77fSLuigi Rizzo *(s++) = '\0'; 48689758b77fSLuigi Rizzo i = strtoport(s, &end, 0 /* base */, 0 /* proto */); 48699758b77fSLuigi Rizzo if (s == end) 48709758b77fSLuigi Rizzo errx(EX_DATAERR, 48719758b77fSLuigi Rizzo "illegal forwarding port ``%s''", s); 48724f531a53SLuigi Rizzo p->sa.sin_port = (u_short)i; 48739758b77fSLuigi Rizzo } 4874afad78e2SJulian Elischer if (_substrcmp(*av, "tablearg") == 0) 4875afad78e2SJulian Elischer p->sa.sin_addr.s_addr = INADDR_ANY; 4876afad78e2SJulian Elischer else 48779758b77fSLuigi Rizzo lookup_host(*av, &(p->sa.sin_addr)); 48789758b77fSLuigi Rizzo ac--; av++; 48799758b77fSLuigi Rizzo break; 4880c487be96SJulian Elischer } 488162ff38aeSLuigi Rizzo case TOK_COMMENT: 488262ff38aeSLuigi Rizzo /* pretend it is a 'count' rule followed by the comment */ 488362ff38aeSLuigi Rizzo action->opcode = O_COUNT; 488462ff38aeSLuigi Rizzo ac++; av--; /* go back... */ 488562ff38aeSLuigi Rizzo break; 488662ff38aeSLuigi Rizzo 4887ff2f6fe8SPaolo Pisati case TOK_NAT: 4888ff2f6fe8SPaolo Pisati action->opcode = O_NAT; 4889ff2f6fe8SPaolo Pisati action->len = F_INSN_SIZE(ipfw_insn_nat); 4890ff2f6fe8SPaolo Pisati NEED1("missing nat number"); 4891ff2f6fe8SPaolo Pisati action->arg1 = strtoul(*av, NULL, 10); 4892ff2f6fe8SPaolo Pisati ac--; av++; 4893ff2f6fe8SPaolo Pisati break; 4894ff2f6fe8SPaolo Pisati 48959758b77fSLuigi Rizzo default: 4896e706181bSLuigi Rizzo errx(EX_DATAERR, "invalid action %s\n", av[-1]); 48979758b77fSLuigi Rizzo } 48989758b77fSLuigi Rizzo action = next_cmd(action); 48999758b77fSLuigi Rizzo 49009758b77fSLuigi Rizzo /* 4901974dfe30SBrian Feldman * [altq queuename] -- altq tag, optional 49029758b77fSLuigi Rizzo * [log [logamount N]] -- log, optional 49039758b77fSLuigi Rizzo * 4904974dfe30SBrian Feldman * If they exist, it go first in the cmdbuf, but then it is 49059758b77fSLuigi Rizzo * skipped in the copy section to the end of the buffer. 49069758b77fSLuigi Rizzo */ 4907974dfe30SBrian Feldman while (ac != 0 && (i = match_token(rule_action_params, *av)) != -1) { 4908974dfe30SBrian Feldman ac--; av++; 4909974dfe30SBrian Feldman switch (i) { 4910974dfe30SBrian Feldman case TOK_LOG: 4911974dfe30SBrian Feldman { 49129758b77fSLuigi Rizzo ipfw_insn_log *c = (ipfw_insn_log *)cmd; 491362ff38aeSLuigi Rizzo int l; 49149758b77fSLuigi Rizzo 4915974dfe30SBrian Feldman if (have_log) 4916974dfe30SBrian Feldman errx(EX_DATAERR, 4917974dfe30SBrian Feldman "log cannot be specified more than once"); 4918974dfe30SBrian Feldman have_log = (ipfw_insn *)c; 49199758b77fSLuigi Rizzo cmd->len = F_INSN_SIZE(ipfw_insn_log); 49209758b77fSLuigi Rizzo cmd->opcode = O_LOG; 492101750186SBrooks Davis if (ac && _substrcmp(*av, "logamount") == 0) { 49229758b77fSLuigi Rizzo ac--; av++; 49239758b77fSLuigi Rizzo NEED1("logamount requires argument"); 492462ff38aeSLuigi Rizzo l = atoi(*av); 492562ff38aeSLuigi Rizzo if (l < 0) 4926974dfe30SBrian Feldman errx(EX_DATAERR, 4927974dfe30SBrian Feldman "logamount must be positive"); 492862ff38aeSLuigi Rizzo c->max_log = l; 49299758b77fSLuigi Rizzo ac--; av++; 49309ec4f2e1SMaxim Konovalov } else { 49319ec4f2e1SMaxim Konovalov len = sizeof(c->max_log); 49329ec4f2e1SMaxim Konovalov if (sysctlbyname("net.inet.ip.fw.verbose_limit", 49339ec4f2e1SMaxim Konovalov &c->max_log, &len, NULL, 0) == -1) 49349ec4f2e1SMaxim Konovalov errx(1, "sysctlbyname(\"%s\")", 49359ec4f2e1SMaxim Konovalov "net.inet.ip.fw.verbose_limit"); 49369758b77fSLuigi Rizzo } 4937974dfe30SBrian Feldman } 4938974dfe30SBrian Feldman break; 4939974dfe30SBrian Feldman 4940974dfe30SBrian Feldman case TOK_ALTQ: 4941974dfe30SBrian Feldman { 4942974dfe30SBrian Feldman ipfw_insn_altq *a = (ipfw_insn_altq *)cmd; 4943974dfe30SBrian Feldman 4944974dfe30SBrian Feldman NEED1("missing altq queue name"); 4945974dfe30SBrian Feldman if (have_altq) 4946974dfe30SBrian Feldman errx(EX_DATAERR, 4947974dfe30SBrian Feldman "altq cannot be specified more than once"); 4948974dfe30SBrian Feldman have_altq = (ipfw_insn *)a; 4949974dfe30SBrian Feldman cmd->len = F_INSN_SIZE(ipfw_insn_altq); 4950974dfe30SBrian Feldman cmd->opcode = O_ALTQ; 4951974dfe30SBrian Feldman fill_altq_qid(&a->qid, *av); 4952974dfe30SBrian Feldman ac--; av++; 4953974dfe30SBrian Feldman } 4954974dfe30SBrian Feldman break; 4955974dfe30SBrian Feldman 49566a7d5cb6SOleg Bulyzhin case TOK_TAG: 4957254c4725SOleg Bulyzhin case TOK_UNTAG: { 4958254c4725SOleg Bulyzhin uint16_t tag; 4959254c4725SOleg Bulyzhin 49606a7d5cb6SOleg Bulyzhin if (have_tag) 4961254c4725SOleg Bulyzhin errx(EX_USAGE, "tag and untag cannot be " 4962254c4725SOleg Bulyzhin "specified more than once"); 4963254c4725SOleg Bulyzhin GET_UINT_ARG(tag, 1, 65534, i, rule_action_params); 49646a7d5cb6SOleg Bulyzhin have_tag = cmd; 4965254c4725SOleg Bulyzhin fill_cmd(cmd, O_TAG, (i == TOK_TAG) ? 0: F_NOT, tag); 49666a7d5cb6SOleg Bulyzhin ac--; av++; 49676a7d5cb6SOleg Bulyzhin break; 4968254c4725SOleg Bulyzhin } 49696a7d5cb6SOleg Bulyzhin 4970974dfe30SBrian Feldman default: 4971974dfe30SBrian Feldman abort(); 4972974dfe30SBrian Feldman } 49739758b77fSLuigi Rizzo cmd = next_cmd(cmd); 49749758b77fSLuigi Rizzo } 49759758b77fSLuigi Rizzo 497652bc23abSLuigi Rizzo if (have_state) /* must be a check-state, we are done */ 49779758b77fSLuigi Rizzo goto done; 49789758b77fSLuigi Rizzo 49799758b77fSLuigi Rizzo #define OR_START(target) \ 49809758b77fSLuigi Rizzo if (ac && (*av[0] == '(' || *av[0] == '{')) { \ 49819758b77fSLuigi Rizzo if (open_par) \ 49829758b77fSLuigi Rizzo errx(EX_USAGE, "nested \"(\" not allowed\n"); \ 49838ed2d749SLuigi Rizzo prev = NULL; \ 49849758b77fSLuigi Rizzo open_par = 1; \ 49859758b77fSLuigi Rizzo if ( (av[0])[1] == '\0') { \ 49869758b77fSLuigi Rizzo ac--; av++; \ 49879758b77fSLuigi Rizzo } else \ 49889758b77fSLuigi Rizzo (*av)++; \ 49899758b77fSLuigi Rizzo } \ 49909758b77fSLuigi Rizzo target: \ 49919758b77fSLuigi Rizzo 49929758b77fSLuigi Rizzo 49939758b77fSLuigi Rizzo #define CLOSE_PAR \ 49949758b77fSLuigi Rizzo if (open_par) { \ 49959758b77fSLuigi Rizzo if (ac && ( \ 499601750186SBrooks Davis strcmp(*av, ")") == 0 || \ 499701750186SBrooks Davis strcmp(*av, "}") == 0)) { \ 49988ed2d749SLuigi Rizzo prev = NULL; \ 49999758b77fSLuigi Rizzo open_par = 0; \ 50009758b77fSLuigi Rizzo ac--; av++; \ 50019758b77fSLuigi Rizzo } else \ 50029758b77fSLuigi Rizzo errx(EX_USAGE, "missing \")\"\n"); \ 50039758b77fSLuigi Rizzo } 50049758b77fSLuigi Rizzo 50059758b77fSLuigi Rizzo #define NOT_BLOCK \ 500601750186SBrooks Davis if (ac && _substrcmp(*av, "not") == 0) { \ 50079758b77fSLuigi Rizzo if (cmd->len & F_NOT) \ 50089758b77fSLuigi Rizzo errx(EX_USAGE, "double \"not\" not allowed\n"); \ 50099758b77fSLuigi Rizzo cmd->len |= F_NOT; \ 50109758b77fSLuigi Rizzo ac--; av++; \ 50119758b77fSLuigi Rizzo } 50129758b77fSLuigi Rizzo 50139758b77fSLuigi Rizzo #define OR_BLOCK(target) \ 501401750186SBrooks Davis if (ac && _substrcmp(*av, "or") == 0) { \ 50159758b77fSLuigi Rizzo if (prev == NULL || open_par == 0) \ 50169758b77fSLuigi Rizzo errx(EX_DATAERR, "invalid OR block"); \ 50179758b77fSLuigi Rizzo prev->len |= F_OR; \ 50189758b77fSLuigi Rizzo ac--; av++; \ 50199758b77fSLuigi Rizzo goto target; \ 50209758b77fSLuigi Rizzo } \ 50219758b77fSLuigi Rizzo CLOSE_PAR; 50229758b77fSLuigi Rizzo 5023e706181bSLuigi Rizzo first_cmd = cmd; 50245a155b40SLuigi Rizzo 50255a155b40SLuigi Rizzo #if 0 5026e706181bSLuigi Rizzo /* 5027e706181bSLuigi Rizzo * MAC addresses, optional. 5028e706181bSLuigi Rizzo * If we have this, we skip the part "proto from src to dst" 5029e706181bSLuigi Rizzo * and jump straight to the option parsing. 5030e706181bSLuigi Rizzo */ 5031e706181bSLuigi Rizzo NOT_BLOCK; 5032e706181bSLuigi Rizzo NEED1("missing protocol"); 503301750186SBrooks Davis if (_substrcmp(*av, "MAC") == 0 || 503401750186SBrooks Davis _substrcmp(*av, "mac") == 0) { 5035e706181bSLuigi Rizzo ac--; av++; /* the "MAC" keyword */ 5036e706181bSLuigi Rizzo add_mac(cmd, ac, av); /* exits in case of errors */ 5037e706181bSLuigi Rizzo cmd = next_cmd(cmd); 5038e706181bSLuigi Rizzo ac -= 2; av += 2; /* dst-mac and src-mac */ 5039e706181bSLuigi Rizzo NOT_BLOCK; 5040e706181bSLuigi Rizzo NEED1("missing mac type"); 5041e706181bSLuigi Rizzo if (add_mactype(cmd, ac, av[0])) 5042e706181bSLuigi Rizzo cmd = next_cmd(cmd); 5043e706181bSLuigi Rizzo ac--; av++; /* any or mac-type */ 5044e706181bSLuigi Rizzo goto read_options; 5045e706181bSLuigi Rizzo } 50465a155b40SLuigi Rizzo #endif 5047e706181bSLuigi Rizzo 50489758b77fSLuigi Rizzo /* 50499758b77fSLuigi Rizzo * protocol, mandatory 50509758b77fSLuigi Rizzo */ 50519758b77fSLuigi Rizzo OR_START(get_proto); 50529758b77fSLuigi Rizzo NOT_BLOCK; 50539758b77fSLuigi Rizzo NEED1("missing protocol"); 505436c263ccSHajimu UMEMOTO if (add_proto_compat(cmd, *av, &proto)) { 50559758b77fSLuigi Rizzo av++; ac--; 5056b730879fSMax Laier if (F_LEN(cmd) != 0) { 5057e706181bSLuigi Rizzo prev = cmd; 50589758b77fSLuigi Rizzo cmd = next_cmd(cmd); 5059e706181bSLuigi Rizzo } 50605a155b40SLuigi Rizzo } else if (first_cmd != cmd) { 5061c82b8dceSMaxim Konovalov errx(EX_DATAERR, "invalid protocol ``%s''", *av); 50625a155b40SLuigi Rizzo } else 50635a155b40SLuigi Rizzo goto read_options; 50649758b77fSLuigi Rizzo OR_BLOCK(get_proto); 50659758b77fSLuigi Rizzo 50669758b77fSLuigi Rizzo /* 5067e706181bSLuigi Rizzo * "from", mandatory 50689758b77fSLuigi Rizzo */ 506901750186SBrooks Davis if (!ac || _substrcmp(*av, "from") != 0) 50709758b77fSLuigi Rizzo errx(EX_USAGE, "missing ``from''"); 50719758b77fSLuigi Rizzo ac--; av++; 50729758b77fSLuigi Rizzo 50739758b77fSLuigi Rizzo /* 50749758b77fSLuigi Rizzo * source IP, mandatory 50759758b77fSLuigi Rizzo */ 50769758b77fSLuigi Rizzo OR_START(source_ip); 50779758b77fSLuigi Rizzo NOT_BLOCK; /* optional "not" */ 50789758b77fSLuigi Rizzo NEED1("missing source address"); 50798195404bSBrooks Davis if (add_src(cmd, *av, proto)) { 50809758b77fSLuigi Rizzo ac--; av++; 5081e706181bSLuigi Rizzo if (F_LEN(cmd) != 0) { /* ! any */ 5082e706181bSLuigi Rizzo prev = cmd; 50839758b77fSLuigi Rizzo cmd = next_cmd(cmd); 5084e706181bSLuigi Rizzo } 50858195404bSBrooks Davis } else 50868195404bSBrooks Davis errx(EX_USAGE, "bad source address %s", *av); 50879758b77fSLuigi Rizzo OR_BLOCK(source_ip); 50889758b77fSLuigi Rizzo 50899758b77fSLuigi Rizzo /* 50909758b77fSLuigi Rizzo * source ports, optional 50919758b77fSLuigi Rizzo */ 50929758b77fSLuigi Rizzo NOT_BLOCK; /* optional "not" */ 50938ed2d749SLuigi Rizzo if (ac) { 509401750186SBrooks Davis if (_substrcmp(*av, "any") == 0 || 5095e706181bSLuigi Rizzo add_ports(cmd, *av, proto, O_IP_SRCPORT)) { 5096e706181bSLuigi Rizzo ac--; av++; 5097e706181bSLuigi Rizzo if (F_LEN(cmd) != 0) 50989758b77fSLuigi Rizzo cmd = next_cmd(cmd); 50999758b77fSLuigi Rizzo } 51008ed2d749SLuigi Rizzo } 51019758b77fSLuigi Rizzo 51029758b77fSLuigi Rizzo /* 5103e706181bSLuigi Rizzo * "to", mandatory 51049758b77fSLuigi Rizzo */ 510501750186SBrooks Davis if (!ac || _substrcmp(*av, "to") != 0) 51069758b77fSLuigi Rizzo errx(EX_USAGE, "missing ``to''"); 51079758b77fSLuigi Rizzo av++; ac--; 51089758b77fSLuigi Rizzo 51099758b77fSLuigi Rizzo /* 51109758b77fSLuigi Rizzo * destination, mandatory 51119758b77fSLuigi Rizzo */ 51129758b77fSLuigi Rizzo OR_START(dest_ip); 51139758b77fSLuigi Rizzo NOT_BLOCK; /* optional "not" */ 51149758b77fSLuigi Rizzo NEED1("missing dst address"); 51158195404bSBrooks Davis if (add_dst(cmd, *av, proto)) { 5116e706181bSLuigi Rizzo ac--; av++; 5117e706181bSLuigi Rizzo if (F_LEN(cmd) != 0) { /* ! any */ 51189758b77fSLuigi Rizzo prev = cmd; 51199758b77fSLuigi Rizzo cmd = next_cmd(cmd); 5120e706181bSLuigi Rizzo } 51218195404bSBrooks Davis } else 51228195404bSBrooks Davis errx( EX_USAGE, "bad destination address %s", *av); 51239758b77fSLuigi Rizzo OR_BLOCK(dest_ip); 51249758b77fSLuigi Rizzo 51259758b77fSLuigi Rizzo /* 51269758b77fSLuigi Rizzo * dest. ports, optional 51279758b77fSLuigi Rizzo */ 51289758b77fSLuigi Rizzo NOT_BLOCK; /* optional "not" */ 51298ed2d749SLuigi Rizzo if (ac) { 513001750186SBrooks Davis if (_substrcmp(*av, "any") == 0 || 5131e706181bSLuigi Rizzo add_ports(cmd, *av, proto, O_IP_DSTPORT)) { 5132e706181bSLuigi Rizzo ac--; av++; 5133e706181bSLuigi Rizzo if (F_LEN(cmd) != 0) 5134e706181bSLuigi Rizzo cmd = next_cmd(cmd); 51359758b77fSLuigi Rizzo } 51368ed2d749SLuigi Rizzo } 51379758b77fSLuigi Rizzo 51389758b77fSLuigi Rizzo read_options: 5139e706181bSLuigi Rizzo if (ac && first_cmd == cmd) { 5140e706181bSLuigi Rizzo /* 5141e706181bSLuigi Rizzo * nothing specified so far, store in the rule to ease 5142e706181bSLuigi Rizzo * printout later. 5143e706181bSLuigi Rizzo */ 5144e706181bSLuigi Rizzo rule->_pad = 1; 5145e706181bSLuigi Rizzo } 51469758b77fSLuigi Rizzo prev = NULL; 51479758b77fSLuigi Rizzo while (ac) { 51488ed2d749SLuigi Rizzo char *s; 51498ed2d749SLuigi Rizzo ipfw_insn_u32 *cmd32; /* alias for cmd */ 51508ed2d749SLuigi Rizzo 51518ed2d749SLuigi Rizzo s = *av; 51528ed2d749SLuigi Rizzo cmd32 = (ipfw_insn_u32 *)cmd; 51539758b77fSLuigi Rizzo 51549758b77fSLuigi Rizzo if (*s == '!') { /* alternate syntax for NOT */ 51559758b77fSLuigi Rizzo if (cmd->len & F_NOT) 51569758b77fSLuigi Rizzo errx(EX_USAGE, "double \"not\" not allowed\n"); 51579758b77fSLuigi Rizzo cmd->len = F_NOT; 51589758b77fSLuigi Rizzo s++; 51599758b77fSLuigi Rizzo } 51609758b77fSLuigi Rizzo i = match_token(rule_options, s); 51619758b77fSLuigi Rizzo ac--; av++; 51629758b77fSLuigi Rizzo switch(i) { 51639758b77fSLuigi Rizzo case TOK_NOT: 51649758b77fSLuigi Rizzo if (cmd->len & F_NOT) 51659758b77fSLuigi Rizzo errx(EX_USAGE, "double \"not\" not allowed\n"); 51669758b77fSLuigi Rizzo cmd->len = F_NOT; 51679758b77fSLuigi Rizzo break; 51689758b77fSLuigi Rizzo 51699758b77fSLuigi Rizzo case TOK_OR: 51708ed2d749SLuigi Rizzo if (open_par == 0 || prev == NULL) 51719758b77fSLuigi Rizzo errx(EX_USAGE, "invalid \"or\" block\n"); 51729758b77fSLuigi Rizzo prev->len |= F_OR; 51739758b77fSLuigi Rizzo break; 51749758b77fSLuigi Rizzo 51758ed2d749SLuigi Rizzo case TOK_STARTBRACE: 51768ed2d749SLuigi Rizzo if (open_par) 51778ed2d749SLuigi Rizzo errx(EX_USAGE, "+nested \"(\" not allowed\n"); 51788ed2d749SLuigi Rizzo open_par = 1; 51798ed2d749SLuigi Rizzo break; 51808ed2d749SLuigi Rizzo 51818ed2d749SLuigi Rizzo case TOK_ENDBRACE: 51828ed2d749SLuigi Rizzo if (!open_par) 51838ed2d749SLuigi Rizzo errx(EX_USAGE, "+missing \")\"\n"); 51848ed2d749SLuigi Rizzo open_par = 0; 5185e706181bSLuigi Rizzo prev = NULL; 51868ed2d749SLuigi Rizzo break; 51878ed2d749SLuigi Rizzo 51889758b77fSLuigi Rizzo case TOK_IN: 51899758b77fSLuigi Rizzo fill_cmd(cmd, O_IN, 0, 0); 51909758b77fSLuigi Rizzo break; 51919758b77fSLuigi Rizzo 51929758b77fSLuigi Rizzo case TOK_OUT: 51939758b77fSLuigi Rizzo cmd->len ^= F_NOT; /* toggle F_NOT */ 51949758b77fSLuigi Rizzo fill_cmd(cmd, O_IN, 0, 0); 51959758b77fSLuigi Rizzo break; 51969758b77fSLuigi Rizzo 51976daf7ebdSBrian Feldman case TOK_DIVERTED: 51986daf7ebdSBrian Feldman fill_cmd(cmd, O_DIVERTED, 0, 3); 51996daf7ebdSBrian Feldman break; 52006daf7ebdSBrian Feldman 52016daf7ebdSBrian Feldman case TOK_DIVERTEDLOOPBACK: 52026daf7ebdSBrian Feldman fill_cmd(cmd, O_DIVERTED, 0, 1); 52036daf7ebdSBrian Feldman break; 52046daf7ebdSBrian Feldman 52056daf7ebdSBrian Feldman case TOK_DIVERTEDOUTPUT: 52066daf7ebdSBrian Feldman fill_cmd(cmd, O_DIVERTED, 0, 2); 52076daf7ebdSBrian Feldman break; 52086daf7ebdSBrian Feldman 52099758b77fSLuigi Rizzo case TOK_FRAG: 52109758b77fSLuigi Rizzo fill_cmd(cmd, O_FRAG, 0, 0); 52119758b77fSLuigi Rizzo break; 52129758b77fSLuigi Rizzo 52139758b77fSLuigi Rizzo case TOK_LAYER2: 52149758b77fSLuigi Rizzo fill_cmd(cmd, O_LAYER2, 0, 0); 52159758b77fSLuigi Rizzo break; 52169758b77fSLuigi Rizzo 52179758b77fSLuigi Rizzo case TOK_XMIT: 52189758b77fSLuigi Rizzo case TOK_RECV: 52199758b77fSLuigi Rizzo case TOK_VIA: 52209758b77fSLuigi Rizzo NEED1("recv, xmit, via require interface name" 52219758b77fSLuigi Rizzo " or address"); 52229758b77fSLuigi Rizzo fill_iface((ipfw_insn_if *)cmd, av[0]); 52239758b77fSLuigi Rizzo ac--; av++; 52249758b77fSLuigi Rizzo if (F_LEN(cmd) == 0) /* not a valid address */ 52259758b77fSLuigi Rizzo break; 52269758b77fSLuigi Rizzo if (i == TOK_XMIT) 52279758b77fSLuigi Rizzo cmd->opcode = O_XMIT; 52289758b77fSLuigi Rizzo else if (i == TOK_RECV) 52299758b77fSLuigi Rizzo cmd->opcode = O_RECV; 52309758b77fSLuigi Rizzo else if (i == TOK_VIA) 52319758b77fSLuigi Rizzo cmd->opcode = O_VIA; 52329758b77fSLuigi Rizzo break; 52339758b77fSLuigi Rizzo 52345e43aef8SLuigi Rizzo case TOK_ICMPTYPES: 52355e43aef8SLuigi Rizzo NEED1("icmptypes requires list of types"); 52365e43aef8SLuigi Rizzo fill_icmptypes((ipfw_insn_u32 *)cmd, *av); 52375e43aef8SLuigi Rizzo av++; ac--; 52385e43aef8SLuigi Rizzo break; 52395e43aef8SLuigi Rizzo 52408195404bSBrooks Davis case TOK_ICMP6TYPES: 52418195404bSBrooks Davis NEED1("icmptypes requires list of types"); 52428195404bSBrooks Davis fill_icmp6types((ipfw_insn_icmp6 *)cmd, *av); 52438195404bSBrooks Davis av++; ac--; 52448195404bSBrooks Davis break; 52458195404bSBrooks Davis 52469758b77fSLuigi Rizzo case TOK_IPTTL: 52479758b77fSLuigi Rizzo NEED1("ipttl requires TTL"); 524844c884e1SLuigi Rizzo if (strpbrk(*av, "-,")) { 524944c884e1SLuigi Rizzo if (!add_ports(cmd, *av, 0, O_IPTTL)) 525044c884e1SLuigi Rizzo errx(EX_DATAERR, "invalid ipttl %s", *av); 525144c884e1SLuigi Rizzo } else 52529758b77fSLuigi Rizzo fill_cmd(cmd, O_IPTTL, 0, strtoul(*av, NULL, 0)); 52539758b77fSLuigi Rizzo ac--; av++; 52549758b77fSLuigi Rizzo break; 52559758b77fSLuigi Rizzo 52569758b77fSLuigi Rizzo case TOK_IPID: 525744c884e1SLuigi Rizzo NEED1("ipid requires id"); 525844c884e1SLuigi Rizzo if (strpbrk(*av, "-,")) { 525944c884e1SLuigi Rizzo if (!add_ports(cmd, *av, 0, O_IPID)) 526044c884e1SLuigi Rizzo errx(EX_DATAERR, "invalid ipid %s", *av); 526144c884e1SLuigi Rizzo } else 52629758b77fSLuigi Rizzo fill_cmd(cmd, O_IPID, 0, strtoul(*av, NULL, 0)); 52639758b77fSLuigi Rizzo ac--; av++; 52649758b77fSLuigi Rizzo break; 52659758b77fSLuigi Rizzo 52669758b77fSLuigi Rizzo case TOK_IPLEN: 52679758b77fSLuigi Rizzo NEED1("iplen requires length"); 526844c884e1SLuigi Rizzo if (strpbrk(*av, "-,")) { 526944c884e1SLuigi Rizzo if (!add_ports(cmd, *av, 0, O_IPLEN)) 527044c884e1SLuigi Rizzo errx(EX_DATAERR, "invalid ip len %s", *av); 527144c884e1SLuigi Rizzo } else 52729758b77fSLuigi Rizzo fill_cmd(cmd, O_IPLEN, 0, strtoul(*av, NULL, 0)); 52739758b77fSLuigi Rizzo ac--; av++; 52749758b77fSLuigi Rizzo break; 52759758b77fSLuigi Rizzo 52769758b77fSLuigi Rizzo case TOK_IPVER: 52779758b77fSLuigi Rizzo NEED1("ipver requires version"); 52789758b77fSLuigi Rizzo fill_cmd(cmd, O_IPVER, 0, strtoul(*av, NULL, 0)); 52799758b77fSLuigi Rizzo ac--; av++; 52809758b77fSLuigi Rizzo break; 52819758b77fSLuigi Rizzo 52825e43aef8SLuigi Rizzo case TOK_IPPRECEDENCE: 52835e43aef8SLuigi Rizzo NEED1("ipprecedence requires value"); 52845e43aef8SLuigi Rizzo fill_cmd(cmd, O_IPPRECEDENCE, 0, 52855e43aef8SLuigi Rizzo (strtoul(*av, NULL, 0) & 7) << 5); 52865e43aef8SLuigi Rizzo ac--; av++; 52875e43aef8SLuigi Rizzo break; 52885e43aef8SLuigi Rizzo 52899758b77fSLuigi Rizzo case TOK_IPOPTS: 52909758b77fSLuigi Rizzo NEED1("missing argument for ipoptions"); 529152bc23abSLuigi Rizzo fill_flags(cmd, O_IPOPT, f_ipopts, *av); 52929758b77fSLuigi Rizzo ac--; av++; 52939758b77fSLuigi Rizzo break; 52949758b77fSLuigi Rizzo 52955e43aef8SLuigi Rizzo case TOK_IPTOS: 52965e43aef8SLuigi Rizzo NEED1("missing argument for iptos"); 529752bc23abSLuigi Rizzo fill_flags(cmd, O_IPTOS, f_iptos, *av); 52985e43aef8SLuigi Rizzo ac--; av++; 52995e43aef8SLuigi Rizzo break; 53005e43aef8SLuigi Rizzo 53019758b77fSLuigi Rizzo case TOK_UID: 53029758b77fSLuigi Rizzo NEED1("uid requires argument"); 53039758b77fSLuigi Rizzo { 53049758b77fSLuigi Rizzo char *end; 53059758b77fSLuigi Rizzo uid_t uid; 53069758b77fSLuigi Rizzo struct passwd *pwd; 53079758b77fSLuigi Rizzo 53089758b77fSLuigi Rizzo cmd->opcode = O_UID; 53099758b77fSLuigi Rizzo uid = strtoul(*av, &end, 0); 53109758b77fSLuigi Rizzo pwd = (*end == '\0') ? getpwuid(uid) : getpwnam(*av); 53119758b77fSLuigi Rizzo if (pwd == NULL) 53129758b77fSLuigi Rizzo errx(EX_DATAERR, "uid \"%s\" nonexistent", *av); 5313d6abaeebSMaxim Konovalov cmd32->d[0] = pwd->pw_uid; 53143a27af0dSChristian S.J. Peron cmd->len |= F_INSN_SIZE(ipfw_insn_u32); 53159758b77fSLuigi Rizzo ac--; av++; 53169758b77fSLuigi Rizzo } 53179758b77fSLuigi Rizzo break; 53189758b77fSLuigi Rizzo 53199758b77fSLuigi Rizzo case TOK_GID: 53209758b77fSLuigi Rizzo NEED1("gid requires argument"); 53219758b77fSLuigi Rizzo { 53229758b77fSLuigi Rizzo char *end; 53239758b77fSLuigi Rizzo gid_t gid; 53249758b77fSLuigi Rizzo struct group *grp; 53259758b77fSLuigi Rizzo 53269758b77fSLuigi Rizzo cmd->opcode = O_GID; 53279758b77fSLuigi Rizzo gid = strtoul(*av, &end, 0); 53289758b77fSLuigi Rizzo grp = (*end == '\0') ? getgrgid(gid) : getgrnam(*av); 53299758b77fSLuigi Rizzo if (grp == NULL) 53309758b77fSLuigi Rizzo errx(EX_DATAERR, "gid \"%s\" nonexistent", *av); 5331d6abaeebSMaxim Konovalov cmd32->d[0] = grp->gr_gid; 53323a27af0dSChristian S.J. Peron cmd->len |= F_INSN_SIZE(ipfw_insn_u32); 53339758b77fSLuigi Rizzo ac--; av++; 53349758b77fSLuigi Rizzo } 53359758b77fSLuigi Rizzo break; 53369758b77fSLuigi Rizzo 533731c88a30SChristian S.J. Peron case TOK_JAIL: 533831c88a30SChristian S.J. Peron NEED1("jail requires argument"); 533931c88a30SChristian S.J. Peron { 534031c88a30SChristian S.J. Peron char *end; 534131c88a30SChristian S.J. Peron int jid; 534231c88a30SChristian S.J. Peron 534331c88a30SChristian S.J. Peron cmd->opcode = O_JAIL; 534431c88a30SChristian S.J. Peron jid = (int)strtol(*av, &end, 0); 534531c88a30SChristian S.J. Peron if (jid < 0 || *end != '\0') 534631c88a30SChristian S.J. Peron errx(EX_DATAERR, "jail requires prison ID"); 5347d413c2e4SChristian S.J. Peron cmd32->d[0] = (uint32_t)jid; 53483a27af0dSChristian S.J. Peron cmd->len |= F_INSN_SIZE(ipfw_insn_u32); 534931c88a30SChristian S.J. Peron ac--; av++; 535031c88a30SChristian S.J. Peron } 535131c88a30SChristian S.J. Peron break; 535231c88a30SChristian S.J. Peron 53539758b77fSLuigi Rizzo case TOK_ESTAB: 53549758b77fSLuigi Rizzo fill_cmd(cmd, O_ESTAB, 0, 0); 53559758b77fSLuigi Rizzo break; 53569758b77fSLuigi Rizzo 53579758b77fSLuigi Rizzo case TOK_SETUP: 53589758b77fSLuigi Rizzo fill_cmd(cmd, O_TCPFLAGS, 0, 53599758b77fSLuigi Rizzo (TH_SYN) | ( (TH_ACK) & 0xff) <<8 ); 53609758b77fSLuigi Rizzo break; 53619758b77fSLuigi Rizzo 5362c99ee9e0SBrian Feldman case TOK_TCPDATALEN: 5363c99ee9e0SBrian Feldman NEED1("tcpdatalen requires length"); 5364c99ee9e0SBrian Feldman if (strpbrk(*av, "-,")) { 5365c99ee9e0SBrian Feldman if (!add_ports(cmd, *av, 0, O_TCPDATALEN)) 5366c99ee9e0SBrian Feldman errx(EX_DATAERR, "invalid tcpdata len %s", *av); 5367c99ee9e0SBrian Feldman } else 5368c99ee9e0SBrian Feldman fill_cmd(cmd, O_TCPDATALEN, 0, 5369c99ee9e0SBrian Feldman strtoul(*av, NULL, 0)); 5370c99ee9e0SBrian Feldman ac--; av++; 5371c99ee9e0SBrian Feldman break; 5372c99ee9e0SBrian Feldman 53739758b77fSLuigi Rizzo case TOK_TCPOPTS: 53749758b77fSLuigi Rizzo NEED1("missing argument for tcpoptions"); 53759758b77fSLuigi Rizzo fill_flags(cmd, O_TCPOPTS, f_tcpopts, *av); 53769758b77fSLuigi Rizzo ac--; av++; 53779758b77fSLuigi Rizzo break; 53789758b77fSLuigi Rizzo 53799758b77fSLuigi Rizzo case TOK_TCPSEQ: 53809758b77fSLuigi Rizzo case TOK_TCPACK: 53819758b77fSLuigi Rizzo NEED1("tcpseq/tcpack requires argument"); 53829758b77fSLuigi Rizzo cmd->len = F_INSN_SIZE(ipfw_insn_u32); 53839758b77fSLuigi Rizzo cmd->opcode = (i == TOK_TCPSEQ) ? O_TCPSEQ : O_TCPACK; 53849758b77fSLuigi Rizzo cmd32->d[0] = htonl(strtoul(*av, NULL, 0)); 53859758b77fSLuigi Rizzo ac--; av++; 53869758b77fSLuigi Rizzo break; 53879758b77fSLuigi Rizzo 53889758b77fSLuigi Rizzo case TOK_TCPWIN: 53899758b77fSLuigi Rizzo NEED1("tcpwin requires length"); 53909758b77fSLuigi Rizzo fill_cmd(cmd, O_TCPWIN, 0, 53919758b77fSLuigi Rizzo htons(strtoul(*av, NULL, 0))); 53929758b77fSLuigi Rizzo ac--; av++; 53939758b77fSLuigi Rizzo break; 53949758b77fSLuigi Rizzo 53959758b77fSLuigi Rizzo case TOK_TCPFLAGS: 53969758b77fSLuigi Rizzo NEED1("missing argument for tcpflags"); 53979758b77fSLuigi Rizzo cmd->opcode = O_TCPFLAGS; 53989758b77fSLuigi Rizzo fill_flags(cmd, O_TCPFLAGS, f_tcpflags, *av); 53999758b77fSLuigi Rizzo ac--; av++; 54009758b77fSLuigi Rizzo break; 54019758b77fSLuigi Rizzo 54029758b77fSLuigi Rizzo case TOK_KEEPSTATE: 54038ed2d749SLuigi Rizzo if (open_par) 54048ed2d749SLuigi Rizzo errx(EX_USAGE, "keep-state cannot be part " 54058ed2d749SLuigi Rizzo "of an or block"); 54060a7197a8SLuigi Rizzo if (have_state) 540752bc23abSLuigi Rizzo errx(EX_USAGE, "only one of keep-state " 54080a7197a8SLuigi Rizzo "and limit is allowed"); 540952bc23abSLuigi Rizzo have_state = cmd; 54109758b77fSLuigi Rizzo fill_cmd(cmd, O_KEEP_STATE, 0, 0); 54119758b77fSLuigi Rizzo break; 54129758b77fSLuigi Rizzo 5413254c4725SOleg Bulyzhin case TOK_LIMIT: { 54149758b77fSLuigi Rizzo ipfw_insn_limit *c = (ipfw_insn_limit *)cmd; 5415254c4725SOleg Bulyzhin int val; 5416254c4725SOleg Bulyzhin 5417254c4725SOleg Bulyzhin if (open_par) 5418254c4725SOleg Bulyzhin errx(EX_USAGE, 5419254c4725SOleg Bulyzhin "limit cannot be part of an or block"); 5420254c4725SOleg Bulyzhin if (have_state) 5421254c4725SOleg Bulyzhin errx(EX_USAGE, "only one of keep-state and " 5422254c4725SOleg Bulyzhin "limit is allowed"); 5423254c4725SOleg Bulyzhin have_state = cmd; 54249758b77fSLuigi Rizzo 54259758b77fSLuigi Rizzo cmd->len = F_INSN_SIZE(ipfw_insn_limit); 54269758b77fSLuigi Rizzo cmd->opcode = O_LIMIT; 5427254c4725SOleg Bulyzhin c->limit_mask = c->conn_limit = 0; 54289758b77fSLuigi Rizzo 5429254c4725SOleg Bulyzhin while (ac > 0) { 5430254c4725SOleg Bulyzhin if ((val = match_token(limit_masks, *av)) <= 0) 54319758b77fSLuigi Rizzo break; 54329758b77fSLuigi Rizzo c->limit_mask |= val; 54339758b77fSLuigi Rizzo ac--; av++; 54349758b77fSLuigi Rizzo } 5435254c4725SOleg Bulyzhin 54369758b77fSLuigi Rizzo if (c->limit_mask == 0) 5437254c4725SOleg Bulyzhin errx(EX_USAGE, "limit: missing limit mask"); 5438254c4725SOleg Bulyzhin 5439254c4725SOleg Bulyzhin GET_UINT_ARG(c->conn_limit, 1, 65534, TOK_LIMIT, 5440254c4725SOleg Bulyzhin rule_options); 5441254c4725SOleg Bulyzhin 54429758b77fSLuigi Rizzo ac--; av++; 54439758b77fSLuigi Rizzo break; 5444254c4725SOleg Bulyzhin } 54459758b77fSLuigi Rizzo 5446e706181bSLuigi Rizzo case TOK_PROTO: 5447e706181bSLuigi Rizzo NEED1("missing protocol"); 54488195404bSBrooks Davis if (add_proto(cmd, *av, &proto)) { 5449e706181bSLuigi Rizzo ac--; av++; 54505a155b40SLuigi Rizzo } else 5451c82b8dceSMaxim Konovalov errx(EX_DATAERR, "invalid protocol ``%s''", 5452c82b8dceSMaxim Konovalov *av); 5453e706181bSLuigi Rizzo break; 5454e706181bSLuigi Rizzo 5455e706181bSLuigi Rizzo case TOK_SRCIP: 5456e706181bSLuigi Rizzo NEED1("missing source IP"); 5457e706181bSLuigi Rizzo if (add_srcip(cmd, *av)) { 5458e706181bSLuigi Rizzo ac--; av++; 5459e706181bSLuigi Rizzo } 5460e706181bSLuigi Rizzo break; 5461e706181bSLuigi Rizzo 5462e706181bSLuigi Rizzo case TOK_DSTIP: 5463e706181bSLuigi Rizzo NEED1("missing destination IP"); 5464e706181bSLuigi Rizzo if (add_dstip(cmd, *av)) { 5465e706181bSLuigi Rizzo ac--; av++; 5466e706181bSLuigi Rizzo } 5467e706181bSLuigi Rizzo break; 5468e706181bSLuigi Rizzo 54698195404bSBrooks Davis case TOK_SRCIP6: 54708195404bSBrooks Davis NEED1("missing source IP6"); 54718195404bSBrooks Davis if (add_srcip6(cmd, *av)) { 54728195404bSBrooks Davis ac--; av++; 54738195404bSBrooks Davis } 54748195404bSBrooks Davis break; 54758195404bSBrooks Davis 54768195404bSBrooks Davis case TOK_DSTIP6: 54778195404bSBrooks Davis NEED1("missing destination IP6"); 54788195404bSBrooks Davis if (add_dstip6(cmd, *av)) { 54798195404bSBrooks Davis ac--; av++; 54808195404bSBrooks Davis } 54818195404bSBrooks Davis break; 54828195404bSBrooks Davis 5483e706181bSLuigi Rizzo case TOK_SRCPORT: 5484e706181bSLuigi Rizzo NEED1("missing source port"); 548501750186SBrooks Davis if (_substrcmp(*av, "any") == 0 || 5486e706181bSLuigi Rizzo add_ports(cmd, *av, proto, O_IP_SRCPORT)) { 5487e706181bSLuigi Rizzo ac--; av++; 5488e706181bSLuigi Rizzo } else 5489e706181bSLuigi Rizzo errx(EX_DATAERR, "invalid source port %s", *av); 5490e706181bSLuigi Rizzo break; 5491e706181bSLuigi Rizzo 5492e706181bSLuigi Rizzo case TOK_DSTPORT: 5493e706181bSLuigi Rizzo NEED1("missing destination port"); 549401750186SBrooks Davis if (_substrcmp(*av, "any") == 0 || 5495e706181bSLuigi Rizzo add_ports(cmd, *av, proto, O_IP_DSTPORT)) { 5496e706181bSLuigi Rizzo ac--; av++; 5497e706181bSLuigi Rizzo } else 5498e706181bSLuigi Rizzo errx(EX_DATAERR, "invalid destination port %s", 5499e706181bSLuigi Rizzo *av); 5500e706181bSLuigi Rizzo break; 5501e706181bSLuigi Rizzo 5502e706181bSLuigi Rizzo case TOK_MAC: 5503e706181bSLuigi Rizzo if (add_mac(cmd, ac, av)) { 5504e706181bSLuigi Rizzo ac -= 2; av += 2; 5505e706181bSLuigi Rizzo } 5506e706181bSLuigi Rizzo break; 5507e706181bSLuigi Rizzo 5508e706181bSLuigi Rizzo case TOK_MACTYPE: 5509e706181bSLuigi Rizzo NEED1("missing mac type"); 5510e706181bSLuigi Rizzo if (!add_mactype(cmd, ac, *av)) 5511c82b8dceSMaxim Konovalov errx(EX_DATAERR, "invalid mac type %s", *av); 5512e706181bSLuigi Rizzo ac--; av++; 5513e706181bSLuigi Rizzo break; 5514e706181bSLuigi Rizzo 5515010dabb0SCrist J. Clark case TOK_VERREVPATH: 5516010dabb0SCrist J. Clark fill_cmd(cmd, O_VERREVPATH, 0, 0); 5517010dabb0SCrist J. Clark break; 5518010dabb0SCrist J. Clark 551922b5770bSAndre Oppermann case TOK_VERSRCREACH: 552022b5770bSAndre Oppermann fill_cmd(cmd, O_VERSRCREACH, 0, 0); 552122b5770bSAndre Oppermann break; 552222b5770bSAndre Oppermann 55235f9541ecSAndre Oppermann case TOK_ANTISPOOF: 55245f9541ecSAndre Oppermann fill_cmd(cmd, O_ANTISPOOF, 0, 0); 55255f9541ecSAndre Oppermann break; 55265f9541ecSAndre Oppermann 5527c3e5b9f1SLuigi Rizzo case TOK_IPSEC: 5528c3e5b9f1SLuigi Rizzo fill_cmd(cmd, O_IPSEC, 0, 0); 5529c3e5b9f1SLuigi Rizzo break; 5530c3e5b9f1SLuigi Rizzo 55318195404bSBrooks Davis case TOK_IPV6: 55328195404bSBrooks Davis fill_cmd(cmd, O_IP6, 0, 0); 55338195404bSBrooks Davis break; 55348195404bSBrooks Davis 553557cd6d26SMax Laier case TOK_IPV4: 553657cd6d26SMax Laier fill_cmd(cmd, O_IP4, 0, 0); 553757cd6d26SMax Laier break; 553857cd6d26SMax Laier 55398195404bSBrooks Davis case TOK_EXT6HDR: 55408195404bSBrooks Davis fill_ext6hdr( cmd, *av ); 55418195404bSBrooks Davis ac--; av++; 55428195404bSBrooks Davis break; 55438195404bSBrooks Davis 55448195404bSBrooks Davis case TOK_FLOWID: 55458195404bSBrooks Davis if (proto != IPPROTO_IPV6 ) 55468195404bSBrooks Davis errx( EX_USAGE, "flow-id filter is active " 55478195404bSBrooks Davis "only for ipv6 protocol\n"); 55488195404bSBrooks Davis fill_flow6( (ipfw_insn_u32 *) cmd, *av ); 55498195404bSBrooks Davis ac--; av++; 55508195404bSBrooks Davis break; 55518195404bSBrooks Davis 555262ff38aeSLuigi Rizzo case TOK_COMMENT: 555362ff38aeSLuigi Rizzo fill_comment(cmd, ac, av); 555462ff38aeSLuigi Rizzo av += ac; 555562ff38aeSLuigi Rizzo ac = 0; 555662ff38aeSLuigi Rizzo break; 555762ff38aeSLuigi Rizzo 55586a7d5cb6SOleg Bulyzhin case TOK_TAGGED: 5559254c4725SOleg Bulyzhin if (ac > 0 && strpbrk(*av, "-,")) { 55606a7d5cb6SOleg Bulyzhin if (!add_ports(cmd, *av, 0, O_TAGGED)) 5561254c4725SOleg Bulyzhin errx(EX_DATAERR, "tagged: invalid tag" 5562254c4725SOleg Bulyzhin " list: %s", *av); 5563254c4725SOleg Bulyzhin } 5564254c4725SOleg Bulyzhin else { 5565254c4725SOleg Bulyzhin uint16_t tag; 5566254c4725SOleg Bulyzhin 5567254c4725SOleg Bulyzhin GET_UINT_ARG(tag, 1, 65534, TOK_TAGGED, 5568254c4725SOleg Bulyzhin rule_options); 5569254c4725SOleg Bulyzhin fill_cmd(cmd, O_TAGGED, 0, tag); 55706a7d5cb6SOleg Bulyzhin } 55716a7d5cb6SOleg Bulyzhin ac--; av++; 55726a7d5cb6SOleg Bulyzhin break; 55736a7d5cb6SOleg Bulyzhin 55749758b77fSLuigi Rizzo default: 55759758b77fSLuigi Rizzo errx(EX_USAGE, "unrecognised option [%d] %s\n", i, s); 55769758b77fSLuigi Rizzo } 55779758b77fSLuigi Rizzo if (F_LEN(cmd) > 0) { /* prepare to advance */ 55789758b77fSLuigi Rizzo prev = cmd; 55799758b77fSLuigi Rizzo cmd = next_cmd(cmd); 55809758b77fSLuigi Rizzo } 55819758b77fSLuigi Rizzo } 55829758b77fSLuigi Rizzo 55839758b77fSLuigi Rizzo done: 55849758b77fSLuigi Rizzo /* 55859758b77fSLuigi Rizzo * Now copy stuff into the rule. 55869758b77fSLuigi Rizzo * If we have a keep-state option, the first instruction 55879758b77fSLuigi Rizzo * must be a PROBE_STATE (which is generated here). 55889758b77fSLuigi Rizzo * If we have a LOG option, it was stored as the first command, 55899758b77fSLuigi Rizzo * and now must be moved to the top of the action part. 55909758b77fSLuigi Rizzo */ 55919758b77fSLuigi Rizzo dst = (ipfw_insn *)rule->cmd; 55929758b77fSLuigi Rizzo 55939758b77fSLuigi Rizzo /* 559412b5dc6aSLuigi Rizzo * First thing to write into the command stream is the match probability. 559512b5dc6aSLuigi Rizzo */ 559612b5dc6aSLuigi Rizzo if (match_prob != 1) { /* 1 means always match */ 559712b5dc6aSLuigi Rizzo dst->opcode = O_PROB; 559812b5dc6aSLuigi Rizzo dst->len = 2; 559912b5dc6aSLuigi Rizzo *((int32_t *)(dst+1)) = (int32_t)(match_prob * 0x7fffffff); 560012b5dc6aSLuigi Rizzo dst += dst->len; 560112b5dc6aSLuigi Rizzo } 560212b5dc6aSLuigi Rizzo 560312b5dc6aSLuigi Rizzo /* 56049758b77fSLuigi Rizzo * generate O_PROBE_STATE if necessary 56059758b77fSLuigi Rizzo */ 560652bc23abSLuigi Rizzo if (have_state && have_state->opcode != O_CHECK_STATE) { 56079758b77fSLuigi Rizzo fill_cmd(dst, O_PROBE_STATE, 0, 0); 56089758b77fSLuigi Rizzo dst = next_cmd(dst); 56099758b77fSLuigi Rizzo } 56106a7d5cb6SOleg Bulyzhin 56116a7d5cb6SOleg Bulyzhin /* copy all commands but O_LOG, O_KEEP_STATE, O_LIMIT, O_ALTQ, O_TAG */ 56129758b77fSLuigi Rizzo for (src = (ipfw_insn *)cmdbuf; src != cmd; src += i) { 56139758b77fSLuigi Rizzo i = F_LEN(src); 56149758b77fSLuigi Rizzo 561552bc23abSLuigi Rizzo switch (src->opcode) { 561652bc23abSLuigi Rizzo case O_LOG: 561752bc23abSLuigi Rizzo case O_KEEP_STATE: 561852bc23abSLuigi Rizzo case O_LIMIT: 5619974dfe30SBrian Feldman case O_ALTQ: 56206a7d5cb6SOleg Bulyzhin case O_TAG: 562152bc23abSLuigi Rizzo break; 562252bc23abSLuigi Rizzo default: 5623571f8c1bSLuigi Rizzo bcopy(src, dst, i * sizeof(uint32_t)); 56249758b77fSLuigi Rizzo dst += i; 56259758b77fSLuigi Rizzo } 56269758b77fSLuigi Rizzo } 56279758b77fSLuigi Rizzo 56289758b77fSLuigi Rizzo /* 562952bc23abSLuigi Rizzo * put back the have_state command as last opcode 563052bc23abSLuigi Rizzo */ 5631b985a624SLuigi Rizzo if (have_state && have_state->opcode != O_CHECK_STATE) { 563252bc23abSLuigi Rizzo i = F_LEN(have_state); 5633571f8c1bSLuigi Rizzo bcopy(have_state, dst, i * sizeof(uint32_t)); 563452bc23abSLuigi Rizzo dst += i; 563552bc23abSLuigi Rizzo } 563652bc23abSLuigi Rizzo /* 56379758b77fSLuigi Rizzo * start action section 56389758b77fSLuigi Rizzo */ 56399758b77fSLuigi Rizzo rule->act_ofs = dst - rule->cmd; 56409758b77fSLuigi Rizzo 56416a7d5cb6SOleg Bulyzhin /* put back O_LOG, O_ALTQ, O_TAG if necessary */ 5642974dfe30SBrian Feldman if (have_log) { 5643974dfe30SBrian Feldman i = F_LEN(have_log); 5644974dfe30SBrian Feldman bcopy(have_log, dst, i * sizeof(uint32_t)); 5645974dfe30SBrian Feldman dst += i; 5646974dfe30SBrian Feldman } 5647974dfe30SBrian Feldman if (have_altq) { 5648974dfe30SBrian Feldman i = F_LEN(have_altq); 5649974dfe30SBrian Feldman bcopy(have_altq, dst, i * sizeof(uint32_t)); 56509758b77fSLuigi Rizzo dst += i; 56519758b77fSLuigi Rizzo } 56526a7d5cb6SOleg Bulyzhin if (have_tag) { 56536a7d5cb6SOleg Bulyzhin i = F_LEN(have_tag); 56546a7d5cb6SOleg Bulyzhin bcopy(have_tag, dst, i * sizeof(uint32_t)); 56556a7d5cb6SOleg Bulyzhin dst += i; 56566a7d5cb6SOleg Bulyzhin } 56579758b77fSLuigi Rizzo /* 56589758b77fSLuigi Rizzo * copy all other actions 56599758b77fSLuigi Rizzo */ 56609758b77fSLuigi Rizzo for (src = (ipfw_insn *)actbuf; src != action; src += i) { 56619758b77fSLuigi Rizzo i = F_LEN(src); 5662571f8c1bSLuigi Rizzo bcopy(src, dst, i * sizeof(uint32_t)); 56639758b77fSLuigi Rizzo dst += i; 56649758b77fSLuigi Rizzo } 56659758b77fSLuigi Rizzo 5666571f8c1bSLuigi Rizzo rule->cmd_len = (uint32_t *)dst - (uint32_t *)(rule->cmd); 566762ff38aeSLuigi Rizzo i = (char *)dst - (char *)rule; 5668884be75cSThomas Moestl if (do_cmd(IP_FW_ADD, rule, (uintptr_t)&i) == -1) 56699758b77fSLuigi Rizzo err(EX_UNAVAILABLE, "getsockopt(%s)", "IP_FW_ADD"); 56709758b77fSLuigi Rizzo if (!do_quiet) 567162ff38aeSLuigi Rizzo show_ipfw(rule, 0, 0); 56729758b77fSLuigi Rizzo } 56739758b77fSLuigi Rizzo 56749758b77fSLuigi Rizzo static void 5675571f8c1bSLuigi Rizzo zero(int ac, char *av[], int optname /* IP_FW_ZERO or IP_FW_RESETLOG */) 56769758b77fSLuigi Rizzo { 56779758b77fSLuigi Rizzo int rulenum; 56789758b77fSLuigi Rizzo int failed = EX_OK; 567962ff38aeSLuigi Rizzo char const *name = optname == IP_FW_ZERO ? "ZERO" : "RESETLOG"; 56809758b77fSLuigi Rizzo 56819758b77fSLuigi Rizzo av++; ac--; 56829758b77fSLuigi Rizzo 56839758b77fSLuigi Rizzo if (!ac) { 56849758b77fSLuigi Rizzo /* clear all entries */ 5685571f8c1bSLuigi Rizzo if (do_cmd(optname, NULL, 0) < 0) 5686571f8c1bSLuigi Rizzo err(EX_UNAVAILABLE, "setsockopt(IP_FW_%s)", name); 56879758b77fSLuigi Rizzo if (!do_quiet) 5688571f8c1bSLuigi Rizzo printf("%s.\n", optname == IP_FW_ZERO ? 5689571f8c1bSLuigi Rizzo "Accounting cleared":"Logging counts reset"); 56909758b77fSLuigi Rizzo 56919758b77fSLuigi Rizzo return; 56929758b77fSLuigi Rizzo } 56939758b77fSLuigi Rizzo 56949758b77fSLuigi Rizzo while (ac) { 56959758b77fSLuigi Rizzo /* Rule number */ 56969758b77fSLuigi Rizzo if (isdigit(**av)) { 56979758b77fSLuigi Rizzo rulenum = atoi(*av); 56989758b77fSLuigi Rizzo av++; 56999758b77fSLuigi Rizzo ac--; 5700571f8c1bSLuigi Rizzo if (do_cmd(optname, &rulenum, sizeof rulenum)) { 5701571f8c1bSLuigi Rizzo warn("rule %u: setsockopt(IP_FW_%s)", 5702571f8c1bSLuigi Rizzo rulenum, name); 57039758b77fSLuigi Rizzo failed = EX_UNAVAILABLE; 57049758b77fSLuigi Rizzo } else if (!do_quiet) 5705571f8c1bSLuigi Rizzo printf("Entry %d %s.\n", rulenum, 5706571f8c1bSLuigi Rizzo optname == IP_FW_ZERO ? 5707571f8c1bSLuigi Rizzo "cleared" : "logging count reset"); 57089758b77fSLuigi Rizzo } else { 57099758b77fSLuigi Rizzo errx(EX_USAGE, "invalid rule number ``%s''", *av); 57109758b77fSLuigi Rizzo } 57119758b77fSLuigi Rizzo } 57129758b77fSLuigi Rizzo if (failed != EX_OK) 57139758b77fSLuigi Rizzo exit(failed); 57149758b77fSLuigi Rizzo } 57159758b77fSLuigi Rizzo 57169758b77fSLuigi Rizzo static void 571726bf4d78SLuigi Rizzo flush(int force) 57189758b77fSLuigi Rizzo { 57199758b77fSLuigi Rizzo int cmd = do_pipe ? IP_DUMMYNET_FLUSH : IP_FW_FLUSH; 57209758b77fSLuigi Rizzo 572126bf4d78SLuigi Rizzo if (!force && !do_quiet) { /* need to ask user */ 57229758b77fSLuigi Rizzo int c; 57239758b77fSLuigi Rizzo 57249758b77fSLuigi Rizzo printf("Are you sure? [yn] "); 57259758b77fSLuigi Rizzo fflush(stdout); 57269758b77fSLuigi Rizzo do { 57279758b77fSLuigi Rizzo c = toupper(getc(stdin)); 57289758b77fSLuigi Rizzo while (c != '\n' && getc(stdin) != '\n') 57299758b77fSLuigi Rizzo if (feof(stdin)) 57309758b77fSLuigi Rizzo return; /* and do not flush */ 57319758b77fSLuigi Rizzo } while (c != 'Y' && c != 'N'); 57329758b77fSLuigi Rizzo printf("\n"); 57339758b77fSLuigi Rizzo if (c == 'N') /* user said no */ 57349758b77fSLuigi Rizzo return; 57359758b77fSLuigi Rizzo } 5736571f8c1bSLuigi Rizzo if (do_cmd(cmd, NULL, 0) < 0) 57379758b77fSLuigi Rizzo err(EX_UNAVAILABLE, "setsockopt(IP_%s_FLUSH)", 57389758b77fSLuigi Rizzo do_pipe ? "DUMMYNET" : "FW"); 57399758b77fSLuigi Rizzo if (!do_quiet) 57409758b77fSLuigi Rizzo printf("Flushed all %s.\n", do_pipe ? "pipes" : "rules"); 57419758b77fSLuigi Rizzo } 57429758b77fSLuigi Rizzo 574362ff38aeSLuigi Rizzo /* 574426bf4d78SLuigi Rizzo * Free a the (locally allocated) copy of command line arguments. 574526bf4d78SLuigi Rizzo */ 574626bf4d78SLuigi Rizzo static void 574726bf4d78SLuigi Rizzo free_args(int ac, char **av) 574826bf4d78SLuigi Rizzo { 574926bf4d78SLuigi Rizzo int i; 575026bf4d78SLuigi Rizzo 575126bf4d78SLuigi Rizzo for (i=0; i < ac; i++) 575226bf4d78SLuigi Rizzo free(av[i]); 575326bf4d78SLuigi Rizzo free(av); 575426bf4d78SLuigi Rizzo } 575526bf4d78SLuigi Rizzo 575626bf4d78SLuigi Rizzo /* 5757cd8b5ae0SRuslan Ermilov * This one handles all table-related commands 5758cd8b5ae0SRuslan Ermilov * ipfw table N add addr[/masklen] [value] 5759cd8b5ae0SRuslan Ermilov * ipfw table N delete addr[/masklen] 5760cd8b5ae0SRuslan Ermilov * ipfw table N flush 5761cd8b5ae0SRuslan Ermilov * ipfw table N list 5762cd8b5ae0SRuslan Ermilov */ 5763cd8b5ae0SRuslan Ermilov static void 5764cd8b5ae0SRuslan Ermilov table_handler(int ac, char *av[]) 5765cd8b5ae0SRuslan Ermilov { 5766cd8b5ae0SRuslan Ermilov ipfw_table_entry ent; 5767cd8b5ae0SRuslan Ermilov ipfw_table *tbl; 5768cd8b5ae0SRuslan Ermilov int do_add; 5769cd8b5ae0SRuslan Ermilov char *p; 5770cd8b5ae0SRuslan Ermilov socklen_t l; 5771cd8b5ae0SRuslan Ermilov uint32_t a; 5772cd8b5ae0SRuslan Ermilov 5773cd8b5ae0SRuslan Ermilov ac--; av++; 5774cd8b5ae0SRuslan Ermilov if (ac && isdigit(**av)) { 5775cd8b5ae0SRuslan Ermilov ent.tbl = atoi(*av); 5776cd8b5ae0SRuslan Ermilov ac--; av++; 5777cd8b5ae0SRuslan Ermilov } else 5778cd8b5ae0SRuslan Ermilov errx(EX_USAGE, "table number required"); 5779cd8b5ae0SRuslan Ermilov NEED1("table needs command"); 578001750186SBrooks Davis if (_substrcmp(*av, "add") == 0 || 578101750186SBrooks Davis _substrcmp(*av, "delete") == 0) { 5782cd8b5ae0SRuslan Ermilov do_add = **av == 'a'; 5783cd8b5ae0SRuslan Ermilov ac--; av++; 5784cd8b5ae0SRuslan Ermilov if (!ac) 5785cd8b5ae0SRuslan Ermilov errx(EX_USAGE, "IP address required"); 5786cd8b5ae0SRuslan Ermilov p = strchr(*av, '/'); 5787cd8b5ae0SRuslan Ermilov if (p) { 5788cd8b5ae0SRuslan Ermilov *p++ = '\0'; 5789cd8b5ae0SRuslan Ermilov ent.masklen = atoi(p); 5790cd8b5ae0SRuslan Ermilov if (ent.masklen > 32) 5791cd8b5ae0SRuslan Ermilov errx(EX_DATAERR, "bad width ``%s''", p); 5792cd8b5ae0SRuslan Ermilov } else 5793cd8b5ae0SRuslan Ermilov ent.masklen = 32; 5794cd8b5ae0SRuslan Ermilov if (lookup_host(*av, (struct in_addr *)&ent.addr) != 0) 57951a41a8e4SRuslan Ermilov errx(EX_NOHOST, "hostname ``%s'' unknown", *av); 5796cd8b5ae0SRuslan Ermilov ac--; av++; 5797c487be96SJulian Elischer if (do_add && ac) { 5798c487be96SJulian Elischer unsigned int tval; 5799c487be96SJulian Elischer /* isdigit is a bit of a hack here.. */ 5800c487be96SJulian Elischer if (strchr(*av, (int)'.') == NULL && isdigit(**av)) { 5801cd8b5ae0SRuslan Ermilov ent.value = strtoul(*av, NULL, 0); 5802c487be96SJulian Elischer } else { 5803c487be96SJulian Elischer if (lookup_host(*av, (struct in_addr *)&tval) == 0) { 5804c487be96SJulian Elischer /* The value must be stored in host order * 5805c487be96SJulian Elischer * so that the values < 65k can be distinguished */ 5806c487be96SJulian Elischer ent.value = ntohl(tval); 5807c487be96SJulian Elischer } else { 5808c487be96SJulian Elischer errx(EX_NOHOST, "hostname ``%s'' unknown", *av); 5809c487be96SJulian Elischer } 5810c487be96SJulian Elischer } 5811c487be96SJulian Elischer } else 5812cd8b5ae0SRuslan Ermilov ent.value = 0; 5813cd8b5ae0SRuslan Ermilov if (do_cmd(do_add ? IP_FW_TABLE_ADD : IP_FW_TABLE_DEL, 5814905c41b5SJulian Elischer &ent, sizeof(ent)) < 0) { 581521899082SJulian Elischer /* If running silent, don't bomb out on these errors. */ 581621899082SJulian Elischer if (!(do_quiet && (errno == (do_add ? EEXIST : ESRCH)))) 581721899082SJulian Elischer err(EX_OSERR, "setsockopt(IP_FW_TABLE_%s)", 581821899082SJulian Elischer do_add ? "ADD" : "DEL"); 581921899082SJulian Elischer /* In silent mode, react to a failed add by deleting */ 5820dbadd6b0SJulian Elischer if (do_add) { 582121899082SJulian Elischer do_cmd(IP_FW_TABLE_DEL, &ent, sizeof(ent)); 582221899082SJulian Elischer if (do_cmd(IP_FW_TABLE_ADD, 582321899082SJulian Elischer &ent, sizeof(ent)) < 0) 582421899082SJulian Elischer err(EX_OSERR, 582521899082SJulian Elischer "setsockopt(IP_FW_TABLE_ADD)"); 5826dbadd6b0SJulian Elischer } 5827905c41b5SJulian Elischer } 582801750186SBrooks Davis } else if (_substrcmp(*av, "flush") == 0) { 5829cd8b5ae0SRuslan Ermilov if (do_cmd(IP_FW_TABLE_FLUSH, &ent.tbl, sizeof(ent.tbl)) < 0) 5830cd8b5ae0SRuslan Ermilov err(EX_OSERR, "setsockopt(IP_FW_TABLE_FLUSH)"); 583101750186SBrooks Davis } else if (_substrcmp(*av, "list") == 0) { 5832cd8b5ae0SRuslan Ermilov a = ent.tbl; 5833cd8b5ae0SRuslan Ermilov l = sizeof(a); 5834cd8b5ae0SRuslan Ermilov if (do_cmd(IP_FW_TABLE_GETSIZE, &a, (uintptr_t)&l) < 0) 5835cd8b5ae0SRuslan Ermilov err(EX_OSERR, "getsockopt(IP_FW_TABLE_GETSIZE)"); 5836cd8b5ae0SRuslan Ermilov l = sizeof(*tbl) + a * sizeof(ipfw_table_entry); 5837cd8b5ae0SRuslan Ermilov tbl = malloc(l); 5838cd8b5ae0SRuslan Ermilov if (tbl == NULL) 5839cd8b5ae0SRuslan Ermilov err(EX_OSERR, "malloc"); 5840cd8b5ae0SRuslan Ermilov tbl->tbl = ent.tbl; 5841cd8b5ae0SRuslan Ermilov if (do_cmd(IP_FW_TABLE_LIST, tbl, (uintptr_t)&l) < 0) 5842cd8b5ae0SRuslan Ermilov err(EX_OSERR, "getsockopt(IP_FW_TABLE_LIST)"); 5843cd8b5ae0SRuslan Ermilov for (a = 0; a < tbl->cnt; a++) { 5844c487be96SJulian Elischer /* Heuristic to print it the right way */ 5845afad78e2SJulian Elischer /* values < 64k are printed as numbers */ 5846c487be96SJulian Elischer unsigned int tval; 5847c487be96SJulian Elischer tval = tbl->ent[a].value; 5848c487be96SJulian Elischer if (tval > 0xffff) { 5849c487be96SJulian Elischer char tbuf[128]; 5850afad78e2SJulian Elischer strncpy(tbuf, inet_ntoa(*(struct in_addr *) 5851c487be96SJulian Elischer &tbl->ent[a].addr), 127); 5852c487be96SJulian Elischer /* inet_ntoa expects host order */ 5853c487be96SJulian Elischer tval = htonl(tval); 5854afad78e2SJulian Elischer printf("%s/%u %s\n", tbuf, tbl->ent[a].masklen, 5855c487be96SJulian Elischer inet_ntoa(*(struct in_addr *)&tval)); 5856c487be96SJulian Elischer } else { 5857cd8b5ae0SRuslan Ermilov printf("%s/%u %u\n", 5858cd8b5ae0SRuslan Ermilov inet_ntoa(*(struct in_addr *)&tbl->ent[a].addr), 5859cd8b5ae0SRuslan Ermilov tbl->ent[a].masklen, tbl->ent[a].value); 5860cd8b5ae0SRuslan Ermilov } 5861c487be96SJulian Elischer } 5862cd8b5ae0SRuslan Ermilov } else 5863cd8b5ae0SRuslan Ermilov errx(EX_USAGE, "invalid table command %s", *av); 5864cd8b5ae0SRuslan Ermilov } 5865cd8b5ae0SRuslan Ermilov 5866ff2f6fe8SPaolo Pisati static void 5867ff2f6fe8SPaolo Pisati show_nat(int ac, char **av) { 5868ff2f6fe8SPaolo Pisati struct cfg_nat *n; 5869ff2f6fe8SPaolo Pisati struct cfg_redir *e; 5870ff2f6fe8SPaolo Pisati int cmd, i, nbytes, do_cfg, do_rule, frule, lrule, nalloc, size; 5871ff2f6fe8SPaolo Pisati int nat_cnt, r; 5872ff2f6fe8SPaolo Pisati uint8_t *data, *p; 5873ff2f6fe8SPaolo Pisati char **lav, *endptr; 5874ff2f6fe8SPaolo Pisati 5875ff2f6fe8SPaolo Pisati do_rule = 0; 5876ff2f6fe8SPaolo Pisati nalloc = 1024; 5877ff2f6fe8SPaolo Pisati size = 0; 5878ff2f6fe8SPaolo Pisati data = NULL; 5879ff2f6fe8SPaolo Pisati ac--; av++; 5880ff2f6fe8SPaolo Pisati 5881ff2f6fe8SPaolo Pisati /* Parse parameters. */ 5882ff2f6fe8SPaolo Pisati for (cmd = IP_FW_NAT_GET_LOG, do_cfg = 0; ac != 0; ac--, av++) { 5883ff2f6fe8SPaolo Pisati if (!strncmp(av[0], "config", strlen(av[0]))) { 5884ff2f6fe8SPaolo Pisati cmd = IP_FW_NAT_GET_CONFIG, do_cfg = 1; 5885ff2f6fe8SPaolo Pisati continue; 5886ff2f6fe8SPaolo Pisati } 5887ff2f6fe8SPaolo Pisati /* Convert command line rule #. */ 5888ff2f6fe8SPaolo Pisati frule = lrule = strtoul(av[0], &endptr, 10); 5889ff2f6fe8SPaolo Pisati if (*endptr == '-') 5890ff2f6fe8SPaolo Pisati lrule = strtoul(endptr+1, &endptr, 10); 5891ff2f6fe8SPaolo Pisati if (lrule == 0) 5892ff2f6fe8SPaolo Pisati err(EX_USAGE, "invalid rule number: %s", av[0]); 5893ff2f6fe8SPaolo Pisati do_rule = 1; 5894ff2f6fe8SPaolo Pisati } 5895ff2f6fe8SPaolo Pisati 5896ff2f6fe8SPaolo Pisati nbytes = nalloc; 5897ff2f6fe8SPaolo Pisati while (nbytes >= nalloc) { 5898ff2f6fe8SPaolo Pisati nalloc = nalloc * 2; 5899ff2f6fe8SPaolo Pisati nbytes = nalloc; 5900ff2f6fe8SPaolo Pisati if ((data = realloc(data, nbytes)) == NULL) 5901ff2f6fe8SPaolo Pisati err(EX_OSERR, "realloc"); 5902ff2f6fe8SPaolo Pisati if (do_cmd(cmd, data, (uintptr_t)&nbytes) < 0) 5903ff2f6fe8SPaolo Pisati err(EX_OSERR, "getsockopt(IP_FW_GET_%s)", 5904ff2f6fe8SPaolo Pisati (cmd == IP_FW_NAT_GET_LOG) ? "LOG" : "CONFIG"); 5905ff2f6fe8SPaolo Pisati } 5906ff2f6fe8SPaolo Pisati if (nbytes == 0) 5907ff2f6fe8SPaolo Pisati exit(0); 5908ff2f6fe8SPaolo Pisati if (do_cfg) { 5909ff2f6fe8SPaolo Pisati nat_cnt = *((int *)data); 5910ff2f6fe8SPaolo Pisati for (i = sizeof(nat_cnt); nat_cnt; nat_cnt--) { 5911ff2f6fe8SPaolo Pisati n = (struct cfg_nat *)&data[i]; 5912ff2f6fe8SPaolo Pisati if (do_rule) { 5913ff2f6fe8SPaolo Pisati if (!(frule <= n->id && lrule >= n->id)) 5914ff2f6fe8SPaolo Pisati continue; 5915ff2f6fe8SPaolo Pisati } 5916ff2f6fe8SPaolo Pisati print_nat_config(&data[i]); 5917ff2f6fe8SPaolo Pisati i += sizeof(struct cfg_nat); 5918ff2f6fe8SPaolo Pisati e = (struct cfg_redir *)&data[i]; 5919ff2f6fe8SPaolo Pisati if (e->mode == REDIR_ADDR || e->mode == REDIR_PORT || 5920ff2f6fe8SPaolo Pisati e->mode == REDIR_PROTO) 5921ff2f6fe8SPaolo Pisati i += sizeof(struct cfg_redir) + e->spool_cnt * 5922ff2f6fe8SPaolo Pisati sizeof(struct cfg_spool); 5923ff2f6fe8SPaolo Pisati } 5924ff2f6fe8SPaolo Pisati } else { 5925ff2f6fe8SPaolo Pisati for (i = 0; 1; i += LIBALIAS_BUF_SIZE + sizeof(int)) { 5926ff2f6fe8SPaolo Pisati p = &data[i]; 5927ff2f6fe8SPaolo Pisati if (p == data + nbytes) 5928ff2f6fe8SPaolo Pisati break; 5929ff2f6fe8SPaolo Pisati bcopy(p, &r, sizeof(int)); 5930ff2f6fe8SPaolo Pisati if (do_rule) { 5931ff2f6fe8SPaolo Pisati if (!(frule <= r && lrule >= r)) 5932ff2f6fe8SPaolo Pisati continue; 5933ff2f6fe8SPaolo Pisati } 5934ff2f6fe8SPaolo Pisati printf("nat %u: %s\n", r, p+sizeof(int)); 5935ff2f6fe8SPaolo Pisati } 5936ff2f6fe8SPaolo Pisati } 5937ff2f6fe8SPaolo Pisati } 5938ff2f6fe8SPaolo Pisati 5939cd8b5ae0SRuslan Ermilov /* 594026bf4d78SLuigi Rizzo * Called with the arguments (excluding program name). 594126bf4d78SLuigi Rizzo * Returns 0 if successful, 1 if empty command, errx() in case of errors. 594262ff38aeSLuigi Rizzo */ 59439758b77fSLuigi Rizzo static int 5944571f8c1bSLuigi Rizzo ipfw_main(int oldac, char **oldav) 59459758b77fSLuigi Rizzo { 594662ff38aeSLuigi Rizzo int ch, ac, save_ac; 594762ff38aeSLuigi Rizzo char **av, **save_av; 594862ff38aeSLuigi Rizzo int do_acct = 0; /* Show packet/byte count */ 5949571f8c1bSLuigi Rizzo 595062ff38aeSLuigi Rizzo #define WHITESP " \t\f\v\n\r" 595126bf4d78SLuigi Rizzo if (oldac == 0) 595226bf4d78SLuigi Rizzo return 1; 595326bf4d78SLuigi Rizzo else if (oldac == 1) { 5954571f8c1bSLuigi Rizzo /* 5955571f8c1bSLuigi Rizzo * If we are called with a single string, try to split it into 5956571f8c1bSLuigi Rizzo * arguments for subsequent parsing. 5957571f8c1bSLuigi Rizzo * But first, remove spaces after a ',', by copying the string 5958571f8c1bSLuigi Rizzo * in-place. 5959571f8c1bSLuigi Rizzo */ 596062ff38aeSLuigi Rizzo char *arg = oldav[0]; /* The string... */ 5961571f8c1bSLuigi Rizzo int l = strlen(arg); 5962571f8c1bSLuigi Rizzo int copy = 0; /* 1 if we need to copy, 0 otherwise */ 5963571f8c1bSLuigi Rizzo int i, j; 596462ff38aeSLuigi Rizzo for (i = j = 0; i < l; i++) { 596562ff38aeSLuigi Rizzo if (arg[i] == '#') /* comment marker */ 596662ff38aeSLuigi Rizzo break; 5967571f8c1bSLuigi Rizzo if (copy) { 5968571f8c1bSLuigi Rizzo arg[j++] = arg[i]; 596962ff38aeSLuigi Rizzo copy = !index("," WHITESP, arg[i]); 5970571f8c1bSLuigi Rizzo } else { 597162ff38aeSLuigi Rizzo copy = !index(WHITESP, arg[i]); 5972571f8c1bSLuigi Rizzo if (copy) 5973571f8c1bSLuigi Rizzo arg[j++] = arg[i]; 5974571f8c1bSLuigi Rizzo } 597562ff38aeSLuigi Rizzo } 5976571f8c1bSLuigi Rizzo if (!copy && j > 0) /* last char was a 'blank', remove it */ 5977571f8c1bSLuigi Rizzo j--; 5978571f8c1bSLuigi Rizzo l = j; /* the new argument length */ 5979571f8c1bSLuigi Rizzo arg[j++] = '\0'; 598062ff38aeSLuigi Rizzo if (l == 0) /* empty string! */ 598126bf4d78SLuigi Rizzo return 1; 5982571f8c1bSLuigi Rizzo 5983571f8c1bSLuigi Rizzo /* 5984571f8c1bSLuigi Rizzo * First, count number of arguments. Because of the previous 598562ff38aeSLuigi Rizzo * processing, this is just the number of blanks plus 1. 5986571f8c1bSLuigi Rizzo */ 5987571f8c1bSLuigi Rizzo for (i = 0, ac = 1; i < l; i++) 598862ff38aeSLuigi Rizzo if (index(WHITESP, arg[i]) != NULL) 5989571f8c1bSLuigi Rizzo ac++; 5990571f8c1bSLuigi Rizzo 5991571f8c1bSLuigi Rizzo av = calloc(ac, sizeof(char *)); 5992571f8c1bSLuigi Rizzo 5993571f8c1bSLuigi Rizzo /* 5994571f8c1bSLuigi Rizzo * Second, copy arguments from cmd[] to av[]. For each one, 5995571f8c1bSLuigi Rizzo * j is the initial character, i is the one past the end. 5996571f8c1bSLuigi Rizzo */ 599762ff38aeSLuigi Rizzo for (ac = 0, i = j = 0; i < l; i++) 599862ff38aeSLuigi Rizzo if (index(WHITESP, arg[i]) != NULL || i == l-1) { 5999571f8c1bSLuigi Rizzo if (i == l-1) 6000571f8c1bSLuigi Rizzo i++; 6001571f8c1bSLuigi Rizzo av[ac] = calloc(i-j+1, 1); 6002571f8c1bSLuigi Rizzo bcopy(arg+j, av[ac], i-j); 6003571f8c1bSLuigi Rizzo ac++; 6004571f8c1bSLuigi Rizzo j = i + 1; 6005571f8c1bSLuigi Rizzo } 6006571f8c1bSLuigi Rizzo } else { 6007571f8c1bSLuigi Rizzo /* 6008571f8c1bSLuigi Rizzo * If an argument ends with ',' join with the next one. 6009571f8c1bSLuigi Rizzo */ 6010571f8c1bSLuigi Rizzo int first, i, l; 6011571f8c1bSLuigi Rizzo 6012571f8c1bSLuigi Rizzo av = calloc(oldac, sizeof(char *)); 6013571f8c1bSLuigi Rizzo for (first = i = ac = 0, l = 0; i < oldac; i++) { 6014571f8c1bSLuigi Rizzo char *arg = oldav[i]; 6015571f8c1bSLuigi Rizzo int k = strlen(arg); 6016571f8c1bSLuigi Rizzo 6017571f8c1bSLuigi Rizzo l += k; 6018571f8c1bSLuigi Rizzo if (arg[k-1] != ',' || i == oldac-1) { 6019571f8c1bSLuigi Rizzo /* Time to copy. */ 6020571f8c1bSLuigi Rizzo av[ac] = calloc(l+1, 1); 6021571f8c1bSLuigi Rizzo for (l=0; first <= i; first++) { 6022571f8c1bSLuigi Rizzo strcat(av[ac]+l, oldav[first]); 6023571f8c1bSLuigi Rizzo l += strlen(oldav[first]); 6024571f8c1bSLuigi Rizzo } 6025571f8c1bSLuigi Rizzo ac++; 6026571f8c1bSLuigi Rizzo l = 0; 6027571f8c1bSLuigi Rizzo first = i+1; 6028571f8c1bSLuigi Rizzo } 6029571f8c1bSLuigi Rizzo } 6030571f8c1bSLuigi Rizzo } 60319758b77fSLuigi Rizzo 60329758b77fSLuigi Rizzo /* Set the force flag for non-interactive processes */ 6033cec4ab6aSMaxim Konovalov if (!do_force) 60349758b77fSLuigi Rizzo do_force = !isatty(STDIN_FILENO); 60359758b77fSLuigi Rizzo 603662ff38aeSLuigi Rizzo /* Save arguments for final freeing of memory. */ 603762ff38aeSLuigi Rizzo save_ac = ac; 603862ff38aeSLuigi Rizzo save_av = av; 603962ff38aeSLuigi Rizzo 604062ff38aeSLuigi Rizzo optind = optreset = 0; 6041ac6cec51SLuigi Rizzo while ((ch = getopt(ac, av, "abcdefhnNqs:STtv")) != -1) 60429758b77fSLuigi Rizzo switch (ch) { 6043571f8c1bSLuigi Rizzo case 'a': 6044571f8c1bSLuigi Rizzo do_acct = 1; 6045571f8c1bSLuigi Rizzo break; 6046571f8c1bSLuigi Rizzo 6047ac6cec51SLuigi Rizzo case 'b': 6048ac6cec51SLuigi Rizzo comment_only = 1; 6049ac6cec51SLuigi Rizzo do_compact = 1; 6050ac6cec51SLuigi Rizzo break; 6051ac6cec51SLuigi Rizzo 6052571f8c1bSLuigi Rizzo case 'c': 6053571f8c1bSLuigi Rizzo do_compact = 1; 6054571f8c1bSLuigi Rizzo break; 6055571f8c1bSLuigi Rizzo 6056571f8c1bSLuigi Rizzo case 'd': 6057571f8c1bSLuigi Rizzo do_dynamic = 1; 6058571f8c1bSLuigi Rizzo break; 6059571f8c1bSLuigi Rizzo 6060571f8c1bSLuigi Rizzo case 'e': 6061571f8c1bSLuigi Rizzo do_expired = 1; 6062571f8c1bSLuigi Rizzo break; 6063571f8c1bSLuigi Rizzo 6064571f8c1bSLuigi Rizzo case 'f': 6065571f8c1bSLuigi Rizzo do_force = 1; 6066571f8c1bSLuigi Rizzo break; 6067571f8c1bSLuigi Rizzo 60689758b77fSLuigi Rizzo case 'h': /* help */ 606926bf4d78SLuigi Rizzo free_args(save_ac, save_av); 60709758b77fSLuigi Rizzo help(); 60719758b77fSLuigi Rizzo break; /* NOTREACHED */ 60729758b77fSLuigi Rizzo 6073571f8c1bSLuigi Rizzo case 'n': 6074571f8c1bSLuigi Rizzo test_only = 1; 60759758b77fSLuigi Rizzo break; 6076571f8c1bSLuigi Rizzo 60779758b77fSLuigi Rizzo case 'N': 60789758b77fSLuigi Rizzo do_resolv = 1; 60799758b77fSLuigi Rizzo break; 6080571f8c1bSLuigi Rizzo 60819758b77fSLuigi Rizzo case 'q': 60829758b77fSLuigi Rizzo do_quiet = 1; 60839758b77fSLuigi Rizzo break; 6084571f8c1bSLuigi Rizzo 6085571f8c1bSLuigi Rizzo case 's': /* sort */ 6086571f8c1bSLuigi Rizzo do_sort = atoi(optarg); 6087571f8c1bSLuigi Rizzo break; 6088571f8c1bSLuigi Rizzo 608943405724SLuigi Rizzo case 'S': 609043405724SLuigi Rizzo show_sets = 1; 609143405724SLuigi Rizzo break; 6092571f8c1bSLuigi Rizzo 60939758b77fSLuigi Rizzo case 't': 60949758b77fSLuigi Rizzo do_time = 1; 60959758b77fSLuigi Rizzo break; 6096571f8c1bSLuigi Rizzo 60971b43a426SLuigi Rizzo case 'T': 60981b43a426SLuigi Rizzo do_time = 2; /* numeric timestamp */ 60991b43a426SLuigi Rizzo break; 61001b43a426SLuigi Rizzo 61019758b77fSLuigi Rizzo case 'v': /* verbose */ 6102571f8c1bSLuigi Rizzo verbose = 1; 61039758b77fSLuigi Rizzo break; 6104571f8c1bSLuigi Rizzo 61059758b77fSLuigi Rizzo default: 610626bf4d78SLuigi Rizzo free_args(save_ac, save_av); 610726bf4d78SLuigi Rizzo return 1; 61089758b77fSLuigi Rizzo } 61099758b77fSLuigi Rizzo 61109758b77fSLuigi Rizzo ac -= optind; 61119758b77fSLuigi Rizzo av += optind; 61129758b77fSLuigi Rizzo NEED1("bad arguments, for usage summary ``ipfw''"); 61139758b77fSLuigi Rizzo 61149758b77fSLuigi Rizzo /* 611526bf4d78SLuigi Rizzo * An undocumented behaviour of ipfw1 was to allow rule numbers first, 611626bf4d78SLuigi Rizzo * e.g. "100 add allow ..." instead of "add 100 allow ...". 611726bf4d78SLuigi Rizzo * In case, swap first and second argument to get the normal form. 611826bf4d78SLuigi Rizzo */ 611926bf4d78SLuigi Rizzo if (ac > 1 && isdigit(*av[0])) { 612026bf4d78SLuigi Rizzo char *p = av[0]; 612126bf4d78SLuigi Rizzo 612226bf4d78SLuigi Rizzo av[0] = av[1]; 612326bf4d78SLuigi Rizzo av[1] = p; 612426bf4d78SLuigi Rizzo } 612526bf4d78SLuigi Rizzo 612626bf4d78SLuigi Rizzo /* 6127ff2f6fe8SPaolo Pisati * Optional: pipe, queue or nat. 61289758b77fSLuigi Rizzo */ 6129ff2f6fe8SPaolo Pisati do_nat = 0; 61306fa74f7dSMaxim Konovalov do_pipe = 0; 6131ff2f6fe8SPaolo Pisati if (!strncmp(*av, "nat", strlen(*av))) 6132ff2f6fe8SPaolo Pisati do_nat = 1; 6133ff2f6fe8SPaolo Pisati else if (!strncmp(*av, "pipe", strlen(*av))) 61349758b77fSLuigi Rizzo do_pipe = 1; 613501750186SBrooks Davis else if (_substrcmp(*av, "queue") == 0) 61369758b77fSLuigi Rizzo do_pipe = 2; 6137ff2f6fe8SPaolo Pisati if (do_pipe || do_nat) { 61389758b77fSLuigi Rizzo ac--; 61399758b77fSLuigi Rizzo av++; 61409758b77fSLuigi Rizzo } 61419758b77fSLuigi Rizzo NEED1("missing command"); 61429758b77fSLuigi Rizzo 61439758b77fSLuigi Rizzo /* 6144ff2f6fe8SPaolo Pisati * For pipes, queues and nats we normally say 'nat|pipe NN config' 6145ff2f6fe8SPaolo Pisati * but the code is easier to parse as 'nat|pipe config NN' 61469758b77fSLuigi Rizzo * so we swap the two arguments. 61479758b77fSLuigi Rizzo */ 6148ff2f6fe8SPaolo Pisati if ((do_pipe || do_nat) && ac > 1 && isdigit(*av[0])) { 61499758b77fSLuigi Rizzo char *p = av[0]; 615026bf4d78SLuigi Rizzo 61519758b77fSLuigi Rizzo av[0] = av[1]; 61529758b77fSLuigi Rizzo av[1] = p; 61539758b77fSLuigi Rizzo } 6154571f8c1bSLuigi Rizzo 615501750186SBrooks Davis if (_substrcmp(*av, "add") == 0) 61569758b77fSLuigi Rizzo add(ac, av); 6157ff2f6fe8SPaolo Pisati else if (do_nat && _substrcmp(*av, "show") == 0) 6158ff2f6fe8SPaolo Pisati show_nat(ac, av); 615901750186SBrooks Davis else if (do_pipe && _substrcmp(*av, "config") == 0) 61609758b77fSLuigi Rizzo config_pipe(ac, av); 6161ff2f6fe8SPaolo Pisati else if (do_nat && _substrcmp(*av, "config") == 0) 6162ff2f6fe8SPaolo Pisati config_nat(ac, av); 616301750186SBrooks Davis else if (_substrcmp(*av, "delete") == 0) 61649758b77fSLuigi Rizzo delete(ac, av); 616501750186SBrooks Davis else if (_substrcmp(*av, "flush") == 0) 616626bf4d78SLuigi Rizzo flush(do_force); 616701750186SBrooks Davis else if (_substrcmp(*av, "zero") == 0) 6168571f8c1bSLuigi Rizzo zero(ac, av, IP_FW_ZERO); 616901750186SBrooks Davis else if (_substrcmp(*av, "resetlog") == 0) 6170571f8c1bSLuigi Rizzo zero(ac, av, IP_FW_RESETLOG); 617101750186SBrooks Davis else if (_substrcmp(*av, "print") == 0 || 617201750186SBrooks Davis _substrcmp(*av, "list") == 0) 617362ff38aeSLuigi Rizzo list(ac, av, do_acct); 617401750186SBrooks Davis else if (_substrcmp(*av, "set") == 0) 617599e5e645SLuigi Rizzo sets_handler(ac, av); 617601750186SBrooks Davis else if (_substrcmp(*av, "table") == 0) 6177cd8b5ae0SRuslan Ermilov table_handler(ac, av); 617801750186SBrooks Davis else if (_substrcmp(*av, "enable") == 0) 61796690be9eSMatthew Dillon sysctl_handler(ac, av, 1); 618001750186SBrooks Davis else if (_substrcmp(*av, "disable") == 0) 61816690be9eSMatthew Dillon sysctl_handler(ac, av, 0); 618201750186SBrooks Davis else if (_substrcmp(*av, "show") == 0) 618362ff38aeSLuigi Rizzo list(ac, av, 1 /* show counters */); 618462ff38aeSLuigi Rizzo else 61859758b77fSLuigi Rizzo errx(EX_USAGE, "bad command `%s'", *av); 618662ff38aeSLuigi Rizzo 618762ff38aeSLuigi Rizzo /* Free memory allocated in the argument parsing. */ 618826bf4d78SLuigi Rizzo free_args(save_ac, save_av); 61899758b77fSLuigi Rizzo return 0; 61909758b77fSLuigi Rizzo } 61919758b77fSLuigi Rizzo 61929758b77fSLuigi Rizzo 61939758b77fSLuigi Rizzo static void 61949758b77fSLuigi Rizzo ipfw_readfile(int ac, char *av[]) 61959758b77fSLuigi Rizzo { 61969758b77fSLuigi Rizzo #define MAX_ARGS 32 61979758b77fSLuigi Rizzo char buf[BUFSIZ]; 619862ff38aeSLuigi Rizzo char *cmd = NULL, *filename = av[ac-1]; 619962ff38aeSLuigi Rizzo int c, lineno=0; 62009758b77fSLuigi Rizzo FILE *f = NULL; 62019758b77fSLuigi Rizzo pid_t preproc = 0; 62029758b77fSLuigi Rizzo 620362ff38aeSLuigi Rizzo filename = av[ac-1]; 620462ff38aeSLuigi Rizzo 6205cec4ab6aSMaxim Konovalov while ((c = getopt(ac, av, "cfNnp:qS")) != -1) { 62069758b77fSLuigi Rizzo switch(c) { 620762ff38aeSLuigi Rizzo case 'c': 620862ff38aeSLuigi Rizzo do_compact = 1; 620962ff38aeSLuigi Rizzo break; 621062ff38aeSLuigi Rizzo 6211cec4ab6aSMaxim Konovalov case 'f': 6212cec4ab6aSMaxim Konovalov do_force = 1; 6213cec4ab6aSMaxim Konovalov break; 6214cec4ab6aSMaxim Konovalov 621562ff38aeSLuigi Rizzo case 'N': 621662ff38aeSLuigi Rizzo do_resolv = 1; 621762ff38aeSLuigi Rizzo break; 621862ff38aeSLuigi Rizzo 6219571f8c1bSLuigi Rizzo case 'n': 6220571f8c1bSLuigi Rizzo test_only = 1; 6221571f8c1bSLuigi Rizzo break; 6222571f8c1bSLuigi Rizzo 62239758b77fSLuigi Rizzo case 'p': 62249758b77fSLuigi Rizzo cmd = optarg; 622562ff38aeSLuigi Rizzo /* 622662ff38aeSLuigi Rizzo * Skip previous args and delete last one, so we 622762ff38aeSLuigi Rizzo * pass all but the last argument to the preprocessor 622862ff38aeSLuigi Rizzo * via av[optind-1] 622962ff38aeSLuigi Rizzo */ 623062ff38aeSLuigi Rizzo av += optind - 1; 623162ff38aeSLuigi Rizzo ac -= optind - 1; 6232c2438409SMaxim Konovalov if (ac < 2) 6233c2438409SMaxim Konovalov errx(EX_USAGE, "no filename argument"); 623462ff38aeSLuigi Rizzo av[ac-1] = NULL; 623562ff38aeSLuigi Rizzo fprintf(stderr, "command is %s\n", av[0]); 62369758b77fSLuigi Rizzo break; 62379758b77fSLuigi Rizzo 62389758b77fSLuigi Rizzo case 'q': 623962ff38aeSLuigi Rizzo do_quiet = 1; 624062ff38aeSLuigi Rizzo break; 624162ff38aeSLuigi Rizzo 624262ff38aeSLuigi Rizzo case 'S': 624362ff38aeSLuigi Rizzo show_sets = 1; 62449758b77fSLuigi Rizzo break; 62459758b77fSLuigi Rizzo 62469758b77fSLuigi Rizzo default: 62479758b77fSLuigi Rizzo errx(EX_USAGE, "bad arguments, for usage" 62489758b77fSLuigi Rizzo " summary ``ipfw''"); 62499758b77fSLuigi Rizzo } 62509758b77fSLuigi Rizzo 625162ff38aeSLuigi Rizzo if (cmd != NULL) 6252ca6e3cb0SKelly Yancey break; 6253ca6e3cb0SKelly Yancey } 6254ca6e3cb0SKelly Yancey 625562ff38aeSLuigi Rizzo if (cmd == NULL && ac != optind + 1) { 625662ff38aeSLuigi Rizzo fprintf(stderr, "ac %d, optind %d\n", ac, optind); 62579758b77fSLuigi Rizzo errx(EX_USAGE, "extraneous filename arguments"); 625862ff38aeSLuigi Rizzo } 62599758b77fSLuigi Rizzo 626062ff38aeSLuigi Rizzo if ((f = fopen(filename, "r")) == NULL) 626162ff38aeSLuigi Rizzo err(EX_UNAVAILABLE, "fopen: %s", filename); 62629758b77fSLuigi Rizzo 626362ff38aeSLuigi Rizzo if (cmd != NULL) { /* pipe through preprocessor */ 62649758b77fSLuigi Rizzo int pipedes[2]; 62659758b77fSLuigi Rizzo 62669758b77fSLuigi Rizzo if (pipe(pipedes) == -1) 62679758b77fSLuigi Rizzo err(EX_OSERR, "cannot create pipe"); 62689758b77fSLuigi Rizzo 626962ff38aeSLuigi Rizzo preproc = fork(); 627062ff38aeSLuigi Rizzo if (preproc == -1) 62719758b77fSLuigi Rizzo err(EX_OSERR, "cannot fork"); 62729758b77fSLuigi Rizzo 627362ff38aeSLuigi Rizzo if (preproc == 0) { 627462ff38aeSLuigi Rizzo /* 627562ff38aeSLuigi Rizzo * Child, will run the preprocessor with the 627662ff38aeSLuigi Rizzo * file on stdin and the pipe on stdout. 627762ff38aeSLuigi Rizzo */ 62789758b77fSLuigi Rizzo if (dup2(fileno(f), 0) == -1 62799758b77fSLuigi Rizzo || dup2(pipedes[1], 1) == -1) 62809758b77fSLuigi Rizzo err(EX_OSERR, "dup2()"); 62819758b77fSLuigi Rizzo fclose(f); 62829758b77fSLuigi Rizzo close(pipedes[1]); 62839758b77fSLuigi Rizzo close(pipedes[0]); 628462ff38aeSLuigi Rizzo execvp(cmd, av); 62859758b77fSLuigi Rizzo err(EX_OSERR, "execvp(%s) failed", cmd); 628662ff38aeSLuigi Rizzo } else { /* parent, will reopen f as the pipe */ 62879758b77fSLuigi Rizzo fclose(f); 62889758b77fSLuigi Rizzo close(pipedes[1]); 62899758b77fSLuigi Rizzo if ((f = fdopen(pipedes[0], "r")) == NULL) { 62909758b77fSLuigi Rizzo int savederrno = errno; 62919758b77fSLuigi Rizzo 62929758b77fSLuigi Rizzo (void)kill(preproc, SIGTERM); 62939758b77fSLuigi Rizzo errno = savederrno; 62949758b77fSLuigi Rizzo err(EX_OSERR, "fdopen()"); 62959758b77fSLuigi Rizzo } 62969758b77fSLuigi Rizzo } 62979758b77fSLuigi Rizzo } 62989758b77fSLuigi Rizzo 629962ff38aeSLuigi Rizzo while (fgets(buf, BUFSIZ, f)) { /* read commands */ 630062ff38aeSLuigi Rizzo char linename[10]; 630162ff38aeSLuigi Rizzo char *args[1]; 630262ff38aeSLuigi Rizzo 63039758b77fSLuigi Rizzo lineno++; 6304571f8c1bSLuigi Rizzo sprintf(linename, "Line %d", lineno); 6305571f8c1bSLuigi Rizzo setprogname(linename); /* XXX */ 630662ff38aeSLuigi Rizzo args[0] = buf; 630762ff38aeSLuigi Rizzo ipfw_main(1, args); 63089758b77fSLuigi Rizzo } 63099758b77fSLuigi Rizzo fclose(f); 631062ff38aeSLuigi Rizzo if (cmd != NULL) { 631162ff38aeSLuigi Rizzo int status; 631262ff38aeSLuigi Rizzo 63139758b77fSLuigi Rizzo if (waitpid(preproc, &status, 0) == -1) 63149758b77fSLuigi Rizzo errx(EX_OSERR, "waitpid()"); 63159758b77fSLuigi Rizzo if (WIFEXITED(status) && WEXITSTATUS(status) != EX_OK) 63169758b77fSLuigi Rizzo errx(EX_UNAVAILABLE, 63179758b77fSLuigi Rizzo "preprocessor exited with status %d", 63189758b77fSLuigi Rizzo WEXITSTATUS(status)); 63199758b77fSLuigi Rizzo else if (WIFSIGNALED(status)) 63209758b77fSLuigi Rizzo errx(EX_UNAVAILABLE, 63219758b77fSLuigi Rizzo "preprocessor exited with signal %d", 63229758b77fSLuigi Rizzo WTERMSIG(status)); 63239758b77fSLuigi Rizzo } 63249758b77fSLuigi Rizzo } 63259758b77fSLuigi Rizzo 63269758b77fSLuigi Rizzo int 63279758b77fSLuigi Rizzo main(int ac, char *av[]) 63289758b77fSLuigi Rizzo { 63299758b77fSLuigi Rizzo /* 63309758b77fSLuigi Rizzo * If the last argument is an absolute pathname, interpret it 63319758b77fSLuigi Rizzo * as a file to be preprocessed. 63329758b77fSLuigi Rizzo */ 63339758b77fSLuigi Rizzo 63349758b77fSLuigi Rizzo if (ac > 1 && av[ac - 1][0] == '/' && access(av[ac - 1], R_OK) == 0) 63359758b77fSLuigi Rizzo ipfw_readfile(ac, av); 633626bf4d78SLuigi Rizzo else { 633726bf4d78SLuigi Rizzo if (ipfw_main(ac-1, av+1)) 633826bf4d78SLuigi Rizzo show_usage(); 633926bf4d78SLuigi Rizzo } 63409758b77fSLuigi Rizzo return EX_OK; 63419758b77fSLuigi Rizzo } 6342