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 50bb5081a7SRobert Watson #define IPFW_INTERNAL /* Access to protected structures in ip_fw.h. */ 51bb5081a7SRobert Watson 52bd1d3456SMaxim Konovalov #include <net/ethernet.h> 539758b77fSLuigi Rizzo #include <net/if.h> 54ff2f6fe8SPaolo Pisati #include <net/if_dl.h> 55974dfe30SBrian Feldman #include <net/pfvar.h> 568195404bSBrooks Davis #include <net/route.h> /* def. of struct route */ 579758b77fSLuigi Rizzo #include <netinet/in.h> 589758b77fSLuigi Rizzo #include <netinet/in_systm.h> 599758b77fSLuigi Rizzo #include <netinet/ip.h> 609758b77fSLuigi Rizzo #include <netinet/ip_icmp.h> 618195404bSBrooks Davis #include <netinet/icmp6.h> 629758b77fSLuigi Rizzo #include <netinet/ip_fw.h> 639758b77fSLuigi Rizzo #include <netinet/ip_dummynet.h> 649758b77fSLuigi Rizzo #include <netinet/tcp.h> 659758b77fSLuigi Rizzo #include <arpa/inet.h> 66ff2f6fe8SPaolo Pisati #include <alias.h> 679758b77fSLuigi Rizzo 68571f8c1bSLuigi Rizzo int 690943a3b7SJulian Elischer do_value_as_ip, /* show table value as IP */ 709758b77fSLuigi Rizzo do_resolv, /* Would try to resolve all */ 719758b77fSLuigi Rizzo do_time, /* Show time stamps */ 729758b77fSLuigi Rizzo do_quiet, /* Be quiet in add and flush */ 739758b77fSLuigi Rizzo do_pipe, /* this cmd refers to a pipe */ 74ff2f6fe8SPaolo Pisati do_nat, /* Nat configuration. */ 759758b77fSLuigi Rizzo do_sort, /* field to sort results (0 = no) */ 769758b77fSLuigi Rizzo do_dynamic, /* display dynamic rules */ 779758b77fSLuigi Rizzo do_expired, /* display expired dynamic rules */ 785a155b40SLuigi Rizzo do_compact, /* show rules in compact mode */ 79cec4ab6aSMaxim Konovalov do_force, /* do not ask for confirmation */ 80d069a5d4SMaxim Konovalov use_set, /* work with specified set number */ 8143405724SLuigi Rizzo show_sets, /* display rule sets */ 82571f8c1bSLuigi Rizzo test_only, /* only check syntax */ 83ac6cec51SLuigi Rizzo comment_only, /* only print action and comment */ 849758b77fSLuigi Rizzo verbose; 859758b77fSLuigi Rizzo 869758b77fSLuigi Rizzo #define IP_MASK_ALL 0xffffffff 8704f70834SChristian S.J. Peron /* 8804f70834SChristian S.J. Peron * the following macro returns an error message if we run out of 8904f70834SChristian S.J. Peron * arguments. 9004f70834SChristian S.J. Peron */ 9104f70834SChristian S.J. Peron #define NEED1(msg) {if (!ac) errx(EX_USAGE, msg);} 929758b77fSLuigi Rizzo 93254c4725SOleg Bulyzhin #define GET_UINT_ARG(arg, min, max, tok, s_x) do { \ 94254c4725SOleg Bulyzhin if (!ac) \ 95254c4725SOleg Bulyzhin errx(EX_USAGE, "%s: missing argument", match_value(s_x, tok)); \ 96254c4725SOleg Bulyzhin if (_substrcmp(*av, "tablearg") == 0) { \ 97254c4725SOleg Bulyzhin arg = IP_FW_TABLEARG; \ 98254c4725SOleg Bulyzhin break; \ 996a7d5cb6SOleg Bulyzhin } \ 100254c4725SOleg Bulyzhin \ 101254c4725SOleg Bulyzhin { \ 102254c4725SOleg Bulyzhin long val; \ 103254c4725SOleg Bulyzhin char *end; \ 104254c4725SOleg Bulyzhin \ 105254c4725SOleg Bulyzhin val = strtol(*av, &end, 10); \ 106254c4725SOleg Bulyzhin \ 107254c4725SOleg Bulyzhin if (!isdigit(**av) || *end != '\0' || (val == 0 && errno == EINVAL)) \ 108254c4725SOleg Bulyzhin errx(EX_DATAERR, "%s: invalid argument: %s", \ 109254c4725SOleg Bulyzhin match_value(s_x, tok), *av); \ 110254c4725SOleg Bulyzhin \ 111254c4725SOleg Bulyzhin if (errno == ERANGE || val < min || val > max) \ 112254c4725SOleg Bulyzhin errx(EX_DATAERR, "%s: argument is out of range (%u..%u): %s", \ 113254c4725SOleg Bulyzhin match_value(s_x, tok), min, max, *av); \ 114254c4725SOleg Bulyzhin \ 115254c4725SOleg Bulyzhin if (val == IP_FW_TABLEARG) \ 116254c4725SOleg Bulyzhin errx(EX_DATAERR, "%s: illegal argument value: %s", \ 117254c4725SOleg Bulyzhin match_value(s_x, tok), *av); \ 118254c4725SOleg Bulyzhin arg = val; \ 119254c4725SOleg Bulyzhin } \ 120254c4725SOleg Bulyzhin } while (0) 121254c4725SOleg Bulyzhin 122254c4725SOleg Bulyzhin #define PRINT_UINT_ARG(str, arg) do { \ 123254c4725SOleg Bulyzhin if (str != NULL) \ 124254c4725SOleg Bulyzhin printf("%s",str); \ 125254c4725SOleg Bulyzhin if (arg == IP_FW_TABLEARG) \ 126254c4725SOleg Bulyzhin printf("tablearg"); \ 127254c4725SOleg Bulyzhin else \ 128254c4725SOleg Bulyzhin printf("%u", (uint32_t)arg); \ 1296a7d5cb6SOleg Bulyzhin } while (0) 1306a7d5cb6SOleg Bulyzhin 1319758b77fSLuigi Rizzo /* 132571f8c1bSLuigi Rizzo * _s_x is a structure that stores a string <-> token pairs, used in 133571f8c1bSLuigi Rizzo * various places in the parser. Entries are stored in arrays, 134571f8c1bSLuigi Rizzo * with an entry with s=NULL as terminator. 135571f8c1bSLuigi Rizzo * The search routines are match_token() and match_value(). 136571f8c1bSLuigi Rizzo * Often, an element with x=0 contains an error string. 1379758b77fSLuigi Rizzo * 1389758b77fSLuigi Rizzo */ 1399758b77fSLuigi Rizzo struct _s_x { 14062ff38aeSLuigi Rizzo char const *s; 1419758b77fSLuigi Rizzo int x; 1429758b77fSLuigi Rizzo }; 1439758b77fSLuigi Rizzo 1449758b77fSLuigi Rizzo static struct _s_x f_tcpflags[] = { 1459758b77fSLuigi Rizzo { "syn", TH_SYN }, 1469758b77fSLuigi Rizzo { "fin", TH_FIN }, 1479758b77fSLuigi Rizzo { "ack", TH_ACK }, 1489758b77fSLuigi Rizzo { "psh", TH_PUSH }, 1499758b77fSLuigi Rizzo { "rst", TH_RST }, 1509758b77fSLuigi Rizzo { "urg", TH_URG }, 1519758b77fSLuigi Rizzo { "tcp flag", 0 }, 1529758b77fSLuigi Rizzo { NULL, 0 } 1539758b77fSLuigi Rizzo }; 1549758b77fSLuigi Rizzo 1559758b77fSLuigi Rizzo static struct _s_x f_tcpopts[] = { 1569758b77fSLuigi Rizzo { "mss", IP_FW_TCPOPT_MSS }, 1579758b77fSLuigi Rizzo { "maxseg", IP_FW_TCPOPT_MSS }, 1589758b77fSLuigi Rizzo { "window", IP_FW_TCPOPT_WINDOW }, 1599758b77fSLuigi Rizzo { "sack", IP_FW_TCPOPT_SACK }, 1609758b77fSLuigi Rizzo { "ts", IP_FW_TCPOPT_TS }, 1619758b77fSLuigi Rizzo { "timestamp", IP_FW_TCPOPT_TS }, 1629758b77fSLuigi Rizzo { "cc", IP_FW_TCPOPT_CC }, 1639758b77fSLuigi Rizzo { "tcp option", 0 }, 1649758b77fSLuigi Rizzo { NULL, 0 } 1659758b77fSLuigi Rizzo }; 1669758b77fSLuigi Rizzo 1679758b77fSLuigi Rizzo /* 1689758b77fSLuigi Rizzo * IP options span the range 0 to 255 so we need to remap them 1699758b77fSLuigi Rizzo * (though in fact only the low 5 bits are significant). 1709758b77fSLuigi Rizzo */ 1719758b77fSLuigi Rizzo static struct _s_x f_ipopts[] = { 1729758b77fSLuigi Rizzo { "ssrr", IP_FW_IPOPT_SSRR}, 1739758b77fSLuigi Rizzo { "lsrr", IP_FW_IPOPT_LSRR}, 1749758b77fSLuigi Rizzo { "rr", IP_FW_IPOPT_RR}, 1759758b77fSLuigi Rizzo { "ts", IP_FW_IPOPT_TS}, 1769758b77fSLuigi Rizzo { "ip option", 0 }, 1779758b77fSLuigi Rizzo { NULL, 0 } 1789758b77fSLuigi Rizzo }; 1799758b77fSLuigi Rizzo 1809758b77fSLuigi Rizzo static struct _s_x f_iptos[] = { 1819758b77fSLuigi Rizzo { "lowdelay", IPTOS_LOWDELAY}, 1829758b77fSLuigi Rizzo { "throughput", IPTOS_THROUGHPUT}, 1839758b77fSLuigi Rizzo { "reliability", IPTOS_RELIABILITY}, 1849758b77fSLuigi Rizzo { "mincost", IPTOS_MINCOST}, 18506d703efSRui Paulo { "congestion", IPTOS_ECN_CE}, 18606d703efSRui Paulo { "ecntransport", IPTOS_ECN_ECT0}, 1879758b77fSLuigi Rizzo { "ip tos option", 0}, 1889758b77fSLuigi Rizzo { NULL, 0 } 1899758b77fSLuigi Rizzo }; 1909758b77fSLuigi Rizzo 1919758b77fSLuigi Rizzo static struct _s_x limit_masks[] = { 1929758b77fSLuigi Rizzo {"all", DYN_SRC_ADDR|DYN_SRC_PORT|DYN_DST_ADDR|DYN_DST_PORT}, 1939758b77fSLuigi Rizzo {"src-addr", DYN_SRC_ADDR}, 1949758b77fSLuigi Rizzo {"src-port", DYN_SRC_PORT}, 1959758b77fSLuigi Rizzo {"dst-addr", DYN_DST_ADDR}, 1969758b77fSLuigi Rizzo {"dst-port", DYN_DST_PORT}, 1979758b77fSLuigi Rizzo {NULL, 0} 1989758b77fSLuigi Rizzo }; 1999758b77fSLuigi Rizzo 2009758b77fSLuigi Rizzo /* 2019758b77fSLuigi Rizzo * we use IPPROTO_ETHERTYPE as a fake protocol id to call the print routines 2029758b77fSLuigi Rizzo * This is only used in this code. 2039758b77fSLuigi Rizzo */ 2049758b77fSLuigi Rizzo #define IPPROTO_ETHERTYPE 0x1000 2059758b77fSLuigi Rizzo static struct _s_x ether_types[] = { 2069758b77fSLuigi Rizzo /* 2079758b77fSLuigi Rizzo * Note, we cannot use "-:&/" in the names because they are field 2089758b77fSLuigi Rizzo * separators in the type specifications. Also, we use s = NULL as 2099758b77fSLuigi Rizzo * end-delimiter, because a type of 0 can be legal. 2109758b77fSLuigi Rizzo */ 2119758b77fSLuigi Rizzo { "ip", 0x0800 }, 2129758b77fSLuigi Rizzo { "ipv4", 0x0800 }, 2139758b77fSLuigi Rizzo { "ipv6", 0x86dd }, 2149758b77fSLuigi Rizzo { "arp", 0x0806 }, 2159758b77fSLuigi Rizzo { "rarp", 0x8035 }, 2169758b77fSLuigi Rizzo { "vlan", 0x8100 }, 2179758b77fSLuigi Rizzo { "loop", 0x9000 }, 2189758b77fSLuigi Rizzo { "trail", 0x1000 }, 2199758b77fSLuigi Rizzo { "at", 0x809b }, 2209758b77fSLuigi Rizzo { "atalk", 0x809b }, 2219758b77fSLuigi Rizzo { "aarp", 0x80f3 }, 2229758b77fSLuigi Rizzo { "pppoe_disc", 0x8863 }, 2239758b77fSLuigi Rizzo { "pppoe_sess", 0x8864 }, 2249758b77fSLuigi Rizzo { "ipx_8022", 0x00E0 }, 2259758b77fSLuigi Rizzo { "ipx_8023", 0x0000 }, 2269758b77fSLuigi Rizzo { "ipx_ii", 0x8137 }, 2279758b77fSLuigi Rizzo { "ipx_snap", 0x8137 }, 2289758b77fSLuigi Rizzo { "ipx", 0x8137 }, 2299758b77fSLuigi Rizzo { "ns", 0x0600 }, 2309758b77fSLuigi Rizzo { NULL, 0 } 2319758b77fSLuigi Rizzo }; 2329758b77fSLuigi Rizzo 2339758b77fSLuigi Rizzo static void show_usage(void); 2349758b77fSLuigi Rizzo 2359758b77fSLuigi Rizzo enum tokens { 2369758b77fSLuigi Rizzo TOK_NULL=0, 2379758b77fSLuigi Rizzo 2389758b77fSLuigi Rizzo TOK_OR, 2399758b77fSLuigi Rizzo TOK_NOT, 2408ed2d749SLuigi Rizzo TOK_STARTBRACE, 2418ed2d749SLuigi Rizzo TOK_ENDBRACE, 2429758b77fSLuigi Rizzo 2439758b77fSLuigi Rizzo TOK_ACCEPT, 2449758b77fSLuigi Rizzo TOK_COUNT, 2459758b77fSLuigi Rizzo TOK_PIPE, 2469758b77fSLuigi Rizzo TOK_QUEUE, 2479758b77fSLuigi Rizzo TOK_DIVERT, 2489758b77fSLuigi Rizzo TOK_TEE, 249670742a1SGleb Smirnoff TOK_NETGRAPH, 250670742a1SGleb Smirnoff TOK_NGTEE, 2519758b77fSLuigi Rizzo TOK_FORWARD, 2529758b77fSLuigi Rizzo TOK_SKIPTO, 2539758b77fSLuigi Rizzo TOK_DENY, 2549758b77fSLuigi Rizzo TOK_REJECT, 2559758b77fSLuigi Rizzo TOK_RESET, 2569758b77fSLuigi Rizzo TOK_UNREACH, 2579758b77fSLuigi Rizzo TOK_CHECKSTATE, 258ff2f6fe8SPaolo Pisati TOK_NAT, 2599758b77fSLuigi Rizzo 260974dfe30SBrian Feldman TOK_ALTQ, 261974dfe30SBrian Feldman TOK_LOG, 2626a7d5cb6SOleg Bulyzhin TOK_TAG, 2636a7d5cb6SOleg Bulyzhin TOK_UNTAG, 264974dfe30SBrian Feldman 2656a7d5cb6SOleg Bulyzhin TOK_TAGGED, 2669758b77fSLuigi Rizzo TOK_UID, 2679758b77fSLuigi Rizzo TOK_GID, 26831c88a30SChristian S.J. Peron TOK_JAIL, 2699758b77fSLuigi Rizzo TOK_IN, 2709758b77fSLuigi Rizzo TOK_LIMIT, 2719758b77fSLuigi Rizzo TOK_KEEPSTATE, 2729758b77fSLuigi Rizzo TOK_LAYER2, 2739758b77fSLuigi Rizzo TOK_OUT, 2746daf7ebdSBrian Feldman TOK_DIVERTED, 2756daf7ebdSBrian Feldman TOK_DIVERTEDLOOPBACK, 2766daf7ebdSBrian Feldman TOK_DIVERTEDOUTPUT, 2779758b77fSLuigi Rizzo TOK_XMIT, 2789758b77fSLuigi Rizzo TOK_RECV, 2799758b77fSLuigi Rizzo TOK_VIA, 2809758b77fSLuigi Rizzo TOK_FRAG, 2819758b77fSLuigi Rizzo TOK_IPOPTS, 2829758b77fSLuigi Rizzo TOK_IPLEN, 2839758b77fSLuigi Rizzo TOK_IPID, 2849758b77fSLuigi Rizzo TOK_IPPRECEDENCE, 2859758b77fSLuigi Rizzo TOK_IPTOS, 2869758b77fSLuigi Rizzo TOK_IPTTL, 2879758b77fSLuigi Rizzo TOK_IPVER, 2889758b77fSLuigi Rizzo TOK_ESTAB, 2899758b77fSLuigi Rizzo TOK_SETUP, 290c99ee9e0SBrian Feldman TOK_TCPDATALEN, 2919758b77fSLuigi Rizzo TOK_TCPFLAGS, 2929758b77fSLuigi Rizzo TOK_TCPOPTS, 2939758b77fSLuigi Rizzo TOK_TCPSEQ, 2949758b77fSLuigi Rizzo TOK_TCPACK, 2959758b77fSLuigi Rizzo TOK_TCPWIN, 2969758b77fSLuigi Rizzo TOK_ICMPTYPES, 297e706181bSLuigi Rizzo TOK_MAC, 298e706181bSLuigi Rizzo TOK_MACTYPE, 299010dabb0SCrist J. Clark TOK_VERREVPATH, 30022b5770bSAndre Oppermann TOK_VERSRCREACH, 3015f9541ecSAndre Oppermann TOK_ANTISPOOF, 302c3e5b9f1SLuigi Rizzo TOK_IPSEC, 30362ff38aeSLuigi Rizzo TOK_COMMENT, 3049758b77fSLuigi Rizzo 3059758b77fSLuigi Rizzo TOK_PLR, 30699e5e645SLuigi Rizzo TOK_NOERROR, 3079758b77fSLuigi Rizzo TOK_BUCKETS, 3089758b77fSLuigi Rizzo TOK_DSTIP, 3099758b77fSLuigi Rizzo TOK_SRCIP, 3109758b77fSLuigi Rizzo TOK_DSTPORT, 3119758b77fSLuigi Rizzo TOK_SRCPORT, 3129758b77fSLuigi Rizzo TOK_ALL, 3139758b77fSLuigi Rizzo TOK_MASK, 3149758b77fSLuigi Rizzo TOK_BW, 3159758b77fSLuigi Rizzo TOK_DELAY, 3169758b77fSLuigi Rizzo TOK_RED, 3179758b77fSLuigi Rizzo TOK_GRED, 3189758b77fSLuigi Rizzo TOK_DROPTAIL, 3199758b77fSLuigi Rizzo TOK_PROTO, 3209758b77fSLuigi Rizzo TOK_WEIGHT, 321ff2f6fe8SPaolo Pisati TOK_IP, 322ff2f6fe8SPaolo Pisati TOK_IF, 323ff2f6fe8SPaolo Pisati TOK_ALOG, 324ff2f6fe8SPaolo Pisati TOK_DENY_INC, 325ff2f6fe8SPaolo Pisati TOK_SAME_PORTS, 326ff2f6fe8SPaolo Pisati TOK_UNREG_ONLY, 327ff2f6fe8SPaolo Pisati TOK_RESET_ADDR, 328ff2f6fe8SPaolo Pisati TOK_ALIAS_REV, 329ff2f6fe8SPaolo Pisati TOK_PROXY_ONLY, 330ff2f6fe8SPaolo Pisati TOK_REDIR_ADDR, 331ff2f6fe8SPaolo Pisati TOK_REDIR_PORT, 332ff2f6fe8SPaolo Pisati TOK_REDIR_PROTO, 3338195404bSBrooks Davis 3348195404bSBrooks Davis TOK_IPV6, 3358195404bSBrooks Davis TOK_FLOWID, 3368195404bSBrooks Davis TOK_ICMP6TYPES, 3378195404bSBrooks Davis TOK_EXT6HDR, 3388195404bSBrooks Davis TOK_DSTIP6, 3398195404bSBrooks Davis TOK_SRCIP6, 34057cd6d26SMax Laier 34157cd6d26SMax Laier TOK_IPV4, 3429066356bSBjoern A. Zeeb TOK_UNREACH6, 3439066356bSBjoern A. Zeeb TOK_RESET6, 3448b07e49aSJulian Elischer 3458b07e49aSJulian Elischer TOK_FIB, 3468b07e49aSJulian Elischer TOK_SETFIB, 3479758b77fSLuigi Rizzo }; 3489758b77fSLuigi Rizzo 3499758b77fSLuigi Rizzo struct _s_x dummynet_params[] = { 3509758b77fSLuigi Rizzo { "plr", TOK_PLR }, 35199e5e645SLuigi Rizzo { "noerror", TOK_NOERROR }, 3529758b77fSLuigi Rizzo { "buckets", TOK_BUCKETS }, 3539758b77fSLuigi Rizzo { "dst-ip", TOK_DSTIP }, 3549758b77fSLuigi Rizzo { "src-ip", TOK_SRCIP }, 3559758b77fSLuigi Rizzo { "dst-port", TOK_DSTPORT }, 3569758b77fSLuigi Rizzo { "src-port", TOK_SRCPORT }, 3579758b77fSLuigi Rizzo { "proto", TOK_PROTO }, 3589758b77fSLuigi Rizzo { "weight", TOK_WEIGHT }, 3599758b77fSLuigi Rizzo { "all", TOK_ALL }, 3609758b77fSLuigi Rizzo { "mask", TOK_MASK }, 3619758b77fSLuigi Rizzo { "droptail", TOK_DROPTAIL }, 3629758b77fSLuigi Rizzo { "red", TOK_RED }, 3639758b77fSLuigi Rizzo { "gred", TOK_GRED }, 3649758b77fSLuigi Rizzo { "bw", TOK_BW }, 3659758b77fSLuigi Rizzo { "bandwidth", TOK_BW }, 3669758b77fSLuigi Rizzo { "delay", TOK_DELAY }, 3675e43aef8SLuigi Rizzo { "pipe", TOK_PIPE }, 3689758b77fSLuigi Rizzo { "queue", TOK_QUEUE }, 3698195404bSBrooks Davis { "flow-id", TOK_FLOWID}, 3708195404bSBrooks Davis { "dst-ipv6", TOK_DSTIP6}, 3718195404bSBrooks Davis { "dst-ip6", TOK_DSTIP6}, 3728195404bSBrooks Davis { "src-ipv6", TOK_SRCIP6}, 3738195404bSBrooks Davis { "src-ip6", TOK_SRCIP6}, 3749758b77fSLuigi Rizzo { "dummynet-params", TOK_NULL }, 375571f8c1bSLuigi Rizzo { NULL, 0 } /* terminator */ 3769758b77fSLuigi Rizzo }; 3779758b77fSLuigi Rizzo 378ff2f6fe8SPaolo Pisati struct _s_x nat_params[] = { 379ff2f6fe8SPaolo Pisati { "ip", TOK_IP }, 380ff2f6fe8SPaolo Pisati { "if", TOK_IF }, 381ff2f6fe8SPaolo Pisati { "log", TOK_ALOG }, 382ff2f6fe8SPaolo Pisati { "deny_in", TOK_DENY_INC }, 383ff2f6fe8SPaolo Pisati { "same_ports", TOK_SAME_PORTS }, 384ff2f6fe8SPaolo Pisati { "unreg_only", TOK_UNREG_ONLY }, 385ff2f6fe8SPaolo Pisati { "reset", TOK_RESET_ADDR }, 386ff2f6fe8SPaolo Pisati { "reverse", TOK_ALIAS_REV }, 387ff2f6fe8SPaolo Pisati { "proxy_only", TOK_PROXY_ONLY }, 388ff2f6fe8SPaolo Pisati { "redirect_addr", TOK_REDIR_ADDR }, 389ff2f6fe8SPaolo Pisati { "redirect_port", TOK_REDIR_PORT }, 390ff2f6fe8SPaolo Pisati { "redirect_proto", TOK_REDIR_PROTO }, 391ff2f6fe8SPaolo Pisati { NULL, 0 } /* terminator */ 392ff2f6fe8SPaolo Pisati }; 393ff2f6fe8SPaolo Pisati 3949758b77fSLuigi Rizzo struct _s_x rule_actions[] = { 3959758b77fSLuigi Rizzo { "accept", TOK_ACCEPT }, 3969758b77fSLuigi Rizzo { "pass", TOK_ACCEPT }, 3979758b77fSLuigi Rizzo { "allow", TOK_ACCEPT }, 3989758b77fSLuigi Rizzo { "permit", TOK_ACCEPT }, 3999758b77fSLuigi Rizzo { "count", TOK_COUNT }, 4009758b77fSLuigi Rizzo { "pipe", TOK_PIPE }, 4019758b77fSLuigi Rizzo { "queue", TOK_QUEUE }, 4029758b77fSLuigi Rizzo { "divert", TOK_DIVERT }, 4039758b77fSLuigi Rizzo { "tee", TOK_TEE }, 404670742a1SGleb Smirnoff { "netgraph", TOK_NETGRAPH }, 405670742a1SGleb Smirnoff { "ngtee", TOK_NGTEE }, 4069758b77fSLuigi Rizzo { "fwd", TOK_FORWARD }, 4079758b77fSLuigi Rizzo { "forward", TOK_FORWARD }, 4089758b77fSLuigi Rizzo { "skipto", TOK_SKIPTO }, 4099758b77fSLuigi Rizzo { "deny", TOK_DENY }, 4109758b77fSLuigi Rizzo { "drop", TOK_DENY }, 4119758b77fSLuigi Rizzo { "reject", TOK_REJECT }, 4129066356bSBjoern A. Zeeb { "reset6", TOK_RESET6 }, 4139758b77fSLuigi Rizzo { "reset", TOK_RESET }, 4149066356bSBjoern A. Zeeb { "unreach6", TOK_UNREACH6 }, 4155e43aef8SLuigi Rizzo { "unreach", TOK_UNREACH }, 4169758b77fSLuigi Rizzo { "check-state", TOK_CHECKSTATE }, 41762ff38aeSLuigi Rizzo { "//", TOK_COMMENT }, 418ff2f6fe8SPaolo Pisati { "nat", TOK_NAT }, 4198b07e49aSJulian Elischer { "setfib", TOK_SETFIB }, 420571f8c1bSLuigi Rizzo { NULL, 0 } /* terminator */ 4219758b77fSLuigi Rizzo }; 4229758b77fSLuigi Rizzo 423974dfe30SBrian Feldman struct _s_x rule_action_params[] = { 424974dfe30SBrian Feldman { "altq", TOK_ALTQ }, 425974dfe30SBrian Feldman { "log", TOK_LOG }, 4266a7d5cb6SOleg Bulyzhin { "tag", TOK_TAG }, 4276a7d5cb6SOleg Bulyzhin { "untag", TOK_UNTAG }, 428974dfe30SBrian Feldman { NULL, 0 } /* terminator */ 429974dfe30SBrian Feldman }; 430974dfe30SBrian Feldman 4319758b77fSLuigi Rizzo struct _s_x rule_options[] = { 4326a7d5cb6SOleg Bulyzhin { "tagged", TOK_TAGGED }, 4339758b77fSLuigi Rizzo { "uid", TOK_UID }, 4349758b77fSLuigi Rizzo { "gid", TOK_GID }, 43531c88a30SChristian S.J. Peron { "jail", TOK_JAIL }, 4369758b77fSLuigi Rizzo { "in", TOK_IN }, 4379758b77fSLuigi Rizzo { "limit", TOK_LIMIT }, 4389758b77fSLuigi Rizzo { "keep-state", TOK_KEEPSTATE }, 4399758b77fSLuigi Rizzo { "bridged", TOK_LAYER2 }, 4409758b77fSLuigi Rizzo { "layer2", TOK_LAYER2 }, 4419758b77fSLuigi Rizzo { "out", TOK_OUT }, 4426daf7ebdSBrian Feldman { "diverted", TOK_DIVERTED }, 4436daf7ebdSBrian Feldman { "diverted-loopback", TOK_DIVERTEDLOOPBACK }, 4446daf7ebdSBrian Feldman { "diverted-output", TOK_DIVERTEDOUTPUT }, 4459758b77fSLuigi Rizzo { "xmit", TOK_XMIT }, 4469758b77fSLuigi Rizzo { "recv", TOK_RECV }, 4479758b77fSLuigi Rizzo { "via", TOK_VIA }, 4489758b77fSLuigi Rizzo { "fragment", TOK_FRAG }, 4499758b77fSLuigi Rizzo { "frag", TOK_FRAG }, 4508b07e49aSJulian Elischer { "fib", TOK_FIB }, 4519758b77fSLuigi Rizzo { "ipoptions", TOK_IPOPTS }, 4529758b77fSLuigi Rizzo { "ipopts", TOK_IPOPTS }, 4539758b77fSLuigi Rizzo { "iplen", TOK_IPLEN }, 4549758b77fSLuigi Rizzo { "ipid", TOK_IPID }, 4559758b77fSLuigi Rizzo { "ipprecedence", TOK_IPPRECEDENCE }, 4569758b77fSLuigi Rizzo { "iptos", TOK_IPTOS }, 4579758b77fSLuigi Rizzo { "ipttl", TOK_IPTTL }, 4589758b77fSLuigi Rizzo { "ipversion", TOK_IPVER }, 4599758b77fSLuigi Rizzo { "ipver", TOK_IPVER }, 4609758b77fSLuigi Rizzo { "estab", TOK_ESTAB }, 4619758b77fSLuigi Rizzo { "established", TOK_ESTAB }, 4629758b77fSLuigi Rizzo { "setup", TOK_SETUP }, 463c99ee9e0SBrian Feldman { "tcpdatalen", TOK_TCPDATALEN }, 4649758b77fSLuigi Rizzo { "tcpflags", TOK_TCPFLAGS }, 4659758b77fSLuigi Rizzo { "tcpflgs", TOK_TCPFLAGS }, 4669758b77fSLuigi Rizzo { "tcpoptions", TOK_TCPOPTS }, 4679758b77fSLuigi Rizzo { "tcpopts", TOK_TCPOPTS }, 4689758b77fSLuigi Rizzo { "tcpseq", TOK_TCPSEQ }, 4699758b77fSLuigi Rizzo { "tcpack", TOK_TCPACK }, 4709758b77fSLuigi Rizzo { "tcpwin", TOK_TCPWIN }, 4710a7197a8SLuigi Rizzo { "icmptype", TOK_ICMPTYPES }, 4729758b77fSLuigi Rizzo { "icmptypes", TOK_ICMPTYPES }, 473e706181bSLuigi Rizzo { "dst-ip", TOK_DSTIP }, 474e706181bSLuigi Rizzo { "src-ip", TOK_SRCIP }, 475e706181bSLuigi Rizzo { "dst-port", TOK_DSTPORT }, 476e706181bSLuigi Rizzo { "src-port", TOK_SRCPORT }, 477e706181bSLuigi Rizzo { "proto", TOK_PROTO }, 478e706181bSLuigi Rizzo { "MAC", TOK_MAC }, 479e706181bSLuigi Rizzo { "mac", TOK_MAC }, 480e706181bSLuigi Rizzo { "mac-type", TOK_MACTYPE }, 481010dabb0SCrist J. Clark { "verrevpath", TOK_VERREVPATH }, 48222b5770bSAndre Oppermann { "versrcreach", TOK_VERSRCREACH }, 4835f9541ecSAndre Oppermann { "antispoof", TOK_ANTISPOOF }, 484c3e5b9f1SLuigi Rizzo { "ipsec", TOK_IPSEC }, 4858195404bSBrooks Davis { "icmp6type", TOK_ICMP6TYPES }, 4868195404bSBrooks Davis { "icmp6types", TOK_ICMP6TYPES }, 4878195404bSBrooks Davis { "ext6hdr", TOK_EXT6HDR}, 4888195404bSBrooks Davis { "flow-id", TOK_FLOWID}, 4898195404bSBrooks Davis { "ipv6", TOK_IPV6}, 4908195404bSBrooks Davis { "ip6", TOK_IPV6}, 49157cd6d26SMax Laier { "ipv4", TOK_IPV4}, 49257cd6d26SMax Laier { "ip4", TOK_IPV4}, 4938195404bSBrooks Davis { "dst-ipv6", TOK_DSTIP6}, 4948195404bSBrooks Davis { "dst-ip6", TOK_DSTIP6}, 4958195404bSBrooks Davis { "src-ipv6", TOK_SRCIP6}, 4968195404bSBrooks Davis { "src-ip6", TOK_SRCIP6}, 49762ff38aeSLuigi Rizzo { "//", TOK_COMMENT }, 4989758b77fSLuigi Rizzo 4999758b77fSLuigi Rizzo { "not", TOK_NOT }, /* pseudo option */ 5009758b77fSLuigi Rizzo { "!", /* escape ? */ TOK_NOT }, /* pseudo option */ 5019758b77fSLuigi Rizzo { "or", TOK_OR }, /* pseudo option */ 5029758b77fSLuigi Rizzo { "|", /* escape */ TOK_OR }, /* pseudo option */ 5038ed2d749SLuigi Rizzo { "{", TOK_STARTBRACE }, /* pseudo option */ 5048ed2d749SLuigi Rizzo { "(", TOK_STARTBRACE }, /* pseudo option */ 5058ed2d749SLuigi Rizzo { "}", TOK_ENDBRACE }, /* pseudo option */ 5068ed2d749SLuigi Rizzo { ")", TOK_ENDBRACE }, /* pseudo option */ 507571f8c1bSLuigi Rizzo { NULL, 0 } /* terminator */ 5089758b77fSLuigi Rizzo }; 5099758b77fSLuigi Rizzo 51040b1ae9eSGleb Smirnoff #define TABLEARG "tablearg" 51140b1ae9eSGleb Smirnoff 512571f8c1bSLuigi Rizzo static __inline uint64_t 513571f8c1bSLuigi Rizzo align_uint64(uint64_t *pll) { 514571f8c1bSLuigi Rizzo uint64_t ret; 515330462a3SBernd Walter 516330462a3SBernd Walter bcopy (pll, &ret, sizeof(ret)); 517330462a3SBernd Walter return ret; 518c85c1d27SStefan Farfeleder } 519330462a3SBernd Walter 520571f8c1bSLuigi Rizzo /* 521571f8c1bSLuigi Rizzo * conditionally runs the command. 522571f8c1bSLuigi Rizzo */ 52362ff38aeSLuigi Rizzo static int 524884be75cSThomas Moestl do_cmd(int optname, void *optval, uintptr_t optlen) 525571f8c1bSLuigi Rizzo { 526571f8c1bSLuigi Rizzo static int s = -1; /* the socket */ 527571f8c1bSLuigi Rizzo int i; 528571f8c1bSLuigi Rizzo 529571f8c1bSLuigi Rizzo if (test_only) 530571f8c1bSLuigi Rizzo return 0; 531571f8c1bSLuigi Rizzo 532571f8c1bSLuigi Rizzo if (s == -1) 533571f8c1bSLuigi Rizzo s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); 534571f8c1bSLuigi Rizzo if (s < 0) 535571f8c1bSLuigi Rizzo err(EX_UNAVAILABLE, "socket"); 536571f8c1bSLuigi Rizzo 537571f8c1bSLuigi Rizzo if (optname == IP_FW_GET || optname == IP_DUMMYNET_GET || 538cd8b5ae0SRuslan Ermilov optname == IP_FW_ADD || optname == IP_FW_TABLE_LIST || 539ff2f6fe8SPaolo Pisati optname == IP_FW_TABLE_GETSIZE || 540ff2f6fe8SPaolo Pisati optname == IP_FW_NAT_GET_CONFIG || 541ff2f6fe8SPaolo Pisati optname == IP_FW_NAT_GET_LOG) 542571f8c1bSLuigi Rizzo i = getsockopt(s, IPPROTO_IP, optname, optval, 543571f8c1bSLuigi Rizzo (socklen_t *)optlen); 544571f8c1bSLuigi Rizzo else 545571f8c1bSLuigi Rizzo i = setsockopt(s, IPPROTO_IP, optname, optval, optlen); 546571f8c1bSLuigi Rizzo return i; 547571f8c1bSLuigi Rizzo } 548571f8c1bSLuigi Rizzo 5499758b77fSLuigi Rizzo /** 5509758b77fSLuigi Rizzo * match_token takes a table and a string, returns the value associated 551571f8c1bSLuigi Rizzo * with the string (-1 in case of failure). 5529758b77fSLuigi Rizzo */ 5539758b77fSLuigi Rizzo static int 5549758b77fSLuigi Rizzo match_token(struct _s_x *table, char *string) 5559758b77fSLuigi Rizzo { 5569758b77fSLuigi Rizzo struct _s_x *pt; 55762ff38aeSLuigi Rizzo uint i = strlen(string); 5589758b77fSLuigi Rizzo 5599758b77fSLuigi Rizzo for (pt = table ; i && pt->s != NULL ; pt++) 5609758b77fSLuigi Rizzo if (strlen(pt->s) == i && !bcmp(string, pt->s, i)) 5619758b77fSLuigi Rizzo return pt->x; 5629758b77fSLuigi Rizzo return -1; 563c85c1d27SStefan Farfeleder } 5649758b77fSLuigi Rizzo 565571f8c1bSLuigi Rizzo /** 566571f8c1bSLuigi Rizzo * match_value takes a table and a value, returns the string associated 567571f8c1bSLuigi Rizzo * with the value (NULL in case of failure). 568571f8c1bSLuigi Rizzo */ 56962ff38aeSLuigi Rizzo static char const * 57062ff38aeSLuigi Rizzo match_value(struct _s_x *p, int value) 5719758b77fSLuigi Rizzo { 5729758b77fSLuigi Rizzo for (; p->s != NULL; p++) 5739758b77fSLuigi Rizzo if (p->x == value) 5749758b77fSLuigi Rizzo return p->s; 5759758b77fSLuigi Rizzo return NULL; 5769758b77fSLuigi Rizzo } 5779758b77fSLuigi Rizzo 5789758b77fSLuigi Rizzo /* 57901750186SBrooks Davis * _substrcmp takes two strings and returns 1 if they do not match, 58001750186SBrooks Davis * and 0 if they match exactly or the first string is a sub-string 58101750186SBrooks Davis * of the second. A warning is printed to stderr in the case that the 58201750186SBrooks Davis * first string is a sub-string of the second. 58301750186SBrooks Davis * 58401750186SBrooks Davis * This function will be removed in the future through the usual 58501750186SBrooks Davis * deprecation process. 58601750186SBrooks Davis */ 58701750186SBrooks Davis static int 58801750186SBrooks Davis _substrcmp(const char *str1, const char* str2) 58901750186SBrooks Davis { 59001750186SBrooks Davis 59101750186SBrooks Davis if (strncmp(str1, str2, strlen(str1)) != 0) 59201750186SBrooks Davis return 1; 59301750186SBrooks Davis 59401750186SBrooks Davis if (strlen(str1) != strlen(str2)) 59501750186SBrooks Davis warnx("DEPRECATED: '%s' matched '%s' as a sub-string", 59601750186SBrooks Davis str1, str2); 59701750186SBrooks Davis return 0; 59801750186SBrooks Davis } 59901750186SBrooks Davis 60001750186SBrooks Davis /* 60101750186SBrooks Davis * _substrcmp2 takes three strings and returns 1 if the first two do not match, 60201750186SBrooks Davis * and 0 if they match exactly or the second string is a sub-string 60301750186SBrooks Davis * of the first. A warning is printed to stderr in the case that the 60401750186SBrooks Davis * first string does not match the third. 60501750186SBrooks Davis * 60601750186SBrooks Davis * This function exists to warn about the bizzare construction 60701750186SBrooks Davis * strncmp(str, "by", 2) which is used to allow people to use a shotcut 60801750186SBrooks Davis * for "bytes". The problem is that in addition to accepting "by", 60901750186SBrooks Davis * "byt", "byte", and "bytes", it also excepts "by_rabid_dogs" and any 61001750186SBrooks Davis * other string beginning with "by". 61101750186SBrooks Davis * 61201750186SBrooks Davis * This function will be removed in the future through the usual 61301750186SBrooks Davis * deprecation process. 61401750186SBrooks Davis */ 61501750186SBrooks Davis static int 61601750186SBrooks Davis _substrcmp2(const char *str1, const char* str2, const char* str3) 61701750186SBrooks Davis { 61801750186SBrooks Davis 61901750186SBrooks Davis if (strncmp(str1, str2, strlen(str2)) != 0) 62001750186SBrooks Davis return 1; 62101750186SBrooks Davis 62201750186SBrooks Davis if (strcmp(str1, str3) != 0) 62301750186SBrooks Davis warnx("DEPRECATED: '%s' matched '%s'", 62401750186SBrooks Davis str1, str3); 62501750186SBrooks Davis return 0; 62601750186SBrooks Davis } 62701750186SBrooks Davis 62801750186SBrooks Davis /* 6299758b77fSLuigi Rizzo * prints one port, symbolic or numeric 6309758b77fSLuigi Rizzo */ 6319758b77fSLuigi Rizzo static void 632571f8c1bSLuigi Rizzo print_port(int proto, uint16_t port) 6339758b77fSLuigi Rizzo { 6349758b77fSLuigi Rizzo 6359758b77fSLuigi Rizzo if (proto == IPPROTO_ETHERTYPE) { 63662ff38aeSLuigi Rizzo char const *s; 6379758b77fSLuigi Rizzo 6389758b77fSLuigi Rizzo if (do_resolv && (s = match_value(ether_types, port)) ) 6399758b77fSLuigi Rizzo printf("%s", s); 6409758b77fSLuigi Rizzo else 6419758b77fSLuigi Rizzo printf("0x%04x", port); 6429758b77fSLuigi Rizzo } else { 6439758b77fSLuigi Rizzo struct servent *se = NULL; 6449758b77fSLuigi Rizzo if (do_resolv) { 6459758b77fSLuigi Rizzo struct protoent *pe = getprotobynumber(proto); 6469758b77fSLuigi Rizzo 6479758b77fSLuigi Rizzo se = getservbyport(htons(port), pe ? pe->p_name : NULL); 6489758b77fSLuigi Rizzo } 6499758b77fSLuigi Rizzo if (se) 6509758b77fSLuigi Rizzo printf("%s", se->s_name); 6519758b77fSLuigi Rizzo else 6529758b77fSLuigi Rizzo printf("%d", port); 6539758b77fSLuigi Rizzo } 6549758b77fSLuigi Rizzo } 6559758b77fSLuigi Rizzo 656571f8c1bSLuigi Rizzo struct _s_x _port_name[] = { 657571f8c1bSLuigi Rizzo {"dst-port", O_IP_DSTPORT}, 658571f8c1bSLuigi Rizzo {"src-port", O_IP_SRCPORT}, 659571f8c1bSLuigi Rizzo {"ipid", O_IPID}, 660571f8c1bSLuigi Rizzo {"iplen", O_IPLEN}, 661571f8c1bSLuigi Rizzo {"ipttl", O_IPTTL}, 662571f8c1bSLuigi Rizzo {"mac-type", O_MAC_TYPE}, 663c99ee9e0SBrian Feldman {"tcpdatalen", O_TCPDATALEN}, 6646a7d5cb6SOleg Bulyzhin {"tagged", O_TAGGED}, 665571f8c1bSLuigi Rizzo {NULL, 0} 666571f8c1bSLuigi Rizzo }; 667571f8c1bSLuigi Rizzo 6689758b77fSLuigi Rizzo /* 669571f8c1bSLuigi Rizzo * Print the values in a list 16-bit items of the types above. 6709758b77fSLuigi Rizzo * XXX todo: add support for mask. 6719758b77fSLuigi Rizzo */ 6729758b77fSLuigi Rizzo static void 673e706181bSLuigi Rizzo print_newports(ipfw_insn_u16 *cmd, int proto, int opcode) 6749758b77fSLuigi Rizzo { 675571f8c1bSLuigi Rizzo uint16_t *p = cmd->ports; 6769758b77fSLuigi Rizzo int i; 67762ff38aeSLuigi Rizzo char const *sep; 6789758b77fSLuigi Rizzo 67944c884e1SLuigi Rizzo if (opcode != 0) { 680571f8c1bSLuigi Rizzo sep = match_value(_port_name, opcode); 681571f8c1bSLuigi Rizzo if (sep == NULL) 68244c884e1SLuigi Rizzo sep = "???"; 68344c884e1SLuigi Rizzo printf (" %s", sep); 68444c884e1SLuigi Rizzo } 68544c884e1SLuigi Rizzo sep = " "; 6869758b77fSLuigi Rizzo for (i = F_LEN((ipfw_insn *)cmd) - 1; i > 0; i--, p += 2) { 6879758b77fSLuigi Rizzo printf(sep); 6889758b77fSLuigi Rizzo print_port(proto, p[0]); 6899758b77fSLuigi Rizzo if (p[0] != p[1]) { 6909758b77fSLuigi Rizzo printf("-"); 6919758b77fSLuigi Rizzo print_port(proto, p[1]); 6929758b77fSLuigi Rizzo } 6939758b77fSLuigi Rizzo sep = ","; 6949758b77fSLuigi Rizzo } 6959758b77fSLuigi Rizzo } 6969758b77fSLuigi Rizzo 6979758b77fSLuigi Rizzo /* 6989758b77fSLuigi Rizzo * Like strtol, but also translates service names into port numbers 6999758b77fSLuigi Rizzo * for some protocols. 7009758b77fSLuigi Rizzo * In particular: 7019758b77fSLuigi Rizzo * proto == -1 disables the protocol check; 7029758b77fSLuigi Rizzo * proto == IPPROTO_ETHERTYPE looks up an internal table 7039758b77fSLuigi Rizzo * proto == <some value in /etc/protocols> matches the values there. 70443405724SLuigi Rizzo * Returns *end == s in case the parameter is not found. 7059758b77fSLuigi Rizzo */ 7069758b77fSLuigi Rizzo static int 7079758b77fSLuigi Rizzo strtoport(char *s, char **end, int base, int proto) 7089758b77fSLuigi Rizzo { 70943405724SLuigi Rizzo char *p, *buf; 71043405724SLuigi Rizzo char *s1; 7119758b77fSLuigi Rizzo int i; 7129758b77fSLuigi Rizzo 71343405724SLuigi Rizzo *end = s; /* default - not found */ 7149758b77fSLuigi Rizzo if (*s == '\0') 71543405724SLuigi Rizzo return 0; /* not found */ 7169758b77fSLuigi Rizzo 7179758b77fSLuigi Rizzo if (isdigit(*s)) 7189758b77fSLuigi Rizzo return strtol(s, end, base); 7199758b77fSLuigi Rizzo 7209758b77fSLuigi Rizzo /* 72143405724SLuigi Rizzo * find separator. '\\' escapes the next char. 7229758b77fSLuigi Rizzo */ 72343405724SLuigi Rizzo for (s1 = s; *s1 && (isalnum(*s1) || *s1 == '\\') ; s1++) 72443405724SLuigi Rizzo if (*s1 == '\\' && s1[1] != '\0') 72543405724SLuigi Rizzo s1++; 72643405724SLuigi Rizzo 72743405724SLuigi Rizzo buf = malloc(s1 - s + 1); 72843405724SLuigi Rizzo if (buf == NULL) 72943405724SLuigi Rizzo return 0; 73043405724SLuigi Rizzo 73143405724SLuigi Rizzo /* 73243405724SLuigi Rizzo * copy into a buffer skipping backslashes 73343405724SLuigi Rizzo */ 73443405724SLuigi Rizzo for (p = s, i = 0; p != s1 ; p++) 73543405724SLuigi Rizzo if (*p != '\\') 73643405724SLuigi Rizzo buf[i++] = *p; 73743405724SLuigi Rizzo buf[i++] = '\0'; 7389758b77fSLuigi Rizzo 7399758b77fSLuigi Rizzo if (proto == IPPROTO_ETHERTYPE) { 74043405724SLuigi Rizzo i = match_token(ether_types, buf); 74143405724SLuigi Rizzo free(buf); 74243405724SLuigi Rizzo if (i != -1) { /* found */ 7439758b77fSLuigi Rizzo *end = s1; 7449758b77fSLuigi Rizzo return i; 7459758b77fSLuigi Rizzo } 7469758b77fSLuigi Rizzo } else { 7479758b77fSLuigi Rizzo struct protoent *pe = NULL; 7489758b77fSLuigi Rizzo struct servent *se; 7499758b77fSLuigi Rizzo 7509758b77fSLuigi Rizzo if (proto != 0) 7519758b77fSLuigi Rizzo pe = getprotobynumber(proto); 7529758b77fSLuigi Rizzo setservent(1); 75343405724SLuigi Rizzo se = getservbyname(buf, pe ? pe->p_name : NULL); 75443405724SLuigi Rizzo free(buf); 7559758b77fSLuigi Rizzo if (se != NULL) { 7569758b77fSLuigi Rizzo *end = s1; 7579758b77fSLuigi Rizzo return ntohs(se->s_port); 7589758b77fSLuigi Rizzo } 7599758b77fSLuigi Rizzo } 76043405724SLuigi Rizzo return 0; /* not found */ 7619758b77fSLuigi Rizzo } 7629758b77fSLuigi Rizzo 7639758b77fSLuigi Rizzo /* 764974dfe30SBrian Feldman * Map between current altq queue id numbers and names. 765974dfe30SBrian Feldman */ 766974dfe30SBrian Feldman static int altq_fetched = 0; 767974dfe30SBrian Feldman static TAILQ_HEAD(, pf_altq) altq_entries = 768974dfe30SBrian Feldman TAILQ_HEAD_INITIALIZER(altq_entries); 769974dfe30SBrian Feldman 770974dfe30SBrian Feldman static void 771974dfe30SBrian Feldman altq_set_enabled(int enabled) 772974dfe30SBrian Feldman { 773974dfe30SBrian Feldman int pffd; 774974dfe30SBrian Feldman 775974dfe30SBrian Feldman pffd = open("/dev/pf", O_RDWR); 776974dfe30SBrian Feldman if (pffd == -1) 777974dfe30SBrian Feldman err(EX_UNAVAILABLE, 778974dfe30SBrian Feldman "altq support opening pf(4) control device"); 779974dfe30SBrian Feldman if (enabled) { 780974dfe30SBrian Feldman if (ioctl(pffd, DIOCSTARTALTQ) != 0 && errno != EEXIST) 781974dfe30SBrian Feldman err(EX_UNAVAILABLE, "enabling altq"); 782974dfe30SBrian Feldman } else { 783974dfe30SBrian Feldman if (ioctl(pffd, DIOCSTOPALTQ) != 0 && errno != ENOENT) 784974dfe30SBrian Feldman err(EX_UNAVAILABLE, "disabling altq"); 785974dfe30SBrian Feldman } 786974dfe30SBrian Feldman close(pffd); 787974dfe30SBrian Feldman } 788974dfe30SBrian Feldman 789974dfe30SBrian Feldman static void 790974dfe30SBrian Feldman altq_fetch() 791974dfe30SBrian Feldman { 792974dfe30SBrian Feldman struct pfioc_altq pfioc; 793974dfe30SBrian Feldman struct pf_altq *altq; 794974dfe30SBrian Feldman int pffd, mnr; 795974dfe30SBrian Feldman 796974dfe30SBrian Feldman if (altq_fetched) 797974dfe30SBrian Feldman return; 798974dfe30SBrian Feldman altq_fetched = 1; 799974dfe30SBrian Feldman pffd = open("/dev/pf", O_RDONLY); 800974dfe30SBrian Feldman if (pffd == -1) { 801974dfe30SBrian Feldman warn("altq support opening pf(4) control device"); 802974dfe30SBrian Feldman return; 803974dfe30SBrian Feldman } 804974dfe30SBrian Feldman bzero(&pfioc, sizeof(pfioc)); 805974dfe30SBrian Feldman if (ioctl(pffd, DIOCGETALTQS, &pfioc) != 0) { 806974dfe30SBrian Feldman warn("altq support getting queue list"); 807974dfe30SBrian Feldman close(pffd); 808974dfe30SBrian Feldman return; 809974dfe30SBrian Feldman } 810974dfe30SBrian Feldman mnr = pfioc.nr; 811974dfe30SBrian Feldman for (pfioc.nr = 0; pfioc.nr < mnr; pfioc.nr++) { 812974dfe30SBrian Feldman if (ioctl(pffd, DIOCGETALTQ, &pfioc) != 0) { 813974dfe30SBrian Feldman if (errno == EBUSY) 814974dfe30SBrian Feldman break; 815974dfe30SBrian Feldman warn("altq support getting queue list"); 816974dfe30SBrian Feldman close(pffd); 817974dfe30SBrian Feldman return; 818974dfe30SBrian Feldman } 819974dfe30SBrian Feldman if (pfioc.altq.qid == 0) 820974dfe30SBrian Feldman continue; 821974dfe30SBrian Feldman altq = malloc(sizeof(*altq)); 822974dfe30SBrian Feldman if (altq == NULL) 823974dfe30SBrian Feldman err(EX_OSERR, "malloc"); 824974dfe30SBrian Feldman *altq = pfioc.altq; 825974dfe30SBrian Feldman TAILQ_INSERT_TAIL(&altq_entries, altq, entries); 826974dfe30SBrian Feldman } 827974dfe30SBrian Feldman close(pffd); 828974dfe30SBrian Feldman } 829974dfe30SBrian Feldman 830974dfe30SBrian Feldman static u_int32_t 831974dfe30SBrian Feldman altq_name_to_qid(const char *name) 832974dfe30SBrian Feldman { 833974dfe30SBrian Feldman struct pf_altq *altq; 834974dfe30SBrian Feldman 835974dfe30SBrian Feldman altq_fetch(); 836974dfe30SBrian Feldman TAILQ_FOREACH(altq, &altq_entries, entries) 837974dfe30SBrian Feldman if (strcmp(name, altq->qname) == 0) 838974dfe30SBrian Feldman break; 839974dfe30SBrian Feldman if (altq == NULL) 840974dfe30SBrian Feldman errx(EX_DATAERR, "altq has no queue named `%s'", name); 841974dfe30SBrian Feldman return altq->qid; 842974dfe30SBrian Feldman } 843974dfe30SBrian Feldman 844974dfe30SBrian Feldman static const char * 845974dfe30SBrian Feldman altq_qid_to_name(u_int32_t qid) 846974dfe30SBrian Feldman { 847974dfe30SBrian Feldman struct pf_altq *altq; 848974dfe30SBrian Feldman 849974dfe30SBrian Feldman altq_fetch(); 850974dfe30SBrian Feldman TAILQ_FOREACH(altq, &altq_entries, entries) 851974dfe30SBrian Feldman if (qid == altq->qid) 852974dfe30SBrian Feldman break; 853974dfe30SBrian Feldman if (altq == NULL) 854974dfe30SBrian Feldman return NULL; 855974dfe30SBrian Feldman return altq->qname; 856974dfe30SBrian Feldman } 857974dfe30SBrian Feldman 858974dfe30SBrian Feldman static void 859974dfe30SBrian Feldman fill_altq_qid(u_int32_t *qid, const char *av) 860974dfe30SBrian Feldman { 861974dfe30SBrian Feldman *qid = altq_name_to_qid(av); 862974dfe30SBrian Feldman } 863974dfe30SBrian Feldman 864974dfe30SBrian Feldman /* 865571f8c1bSLuigi Rizzo * Fill the body of the command with the list of port ranges. 8669758b77fSLuigi Rizzo */ 8679758b77fSLuigi Rizzo static int 8689758b77fSLuigi Rizzo fill_newports(ipfw_insn_u16 *cmd, char *av, int proto) 8699758b77fSLuigi Rizzo { 870571f8c1bSLuigi Rizzo uint16_t a, b, *p = cmd->ports; 8719758b77fSLuigi Rizzo int i = 0; 872e706181bSLuigi Rizzo char *s = av; 8739758b77fSLuigi Rizzo 874e706181bSLuigi Rizzo while (*s) { 8759758b77fSLuigi Rizzo a = strtoport(av, &s, 0, proto); 876254c4725SOleg Bulyzhin if (s == av) /* empty or invalid argument */ 877254c4725SOleg Bulyzhin return (0); 878254c4725SOleg Bulyzhin 879254c4725SOleg Bulyzhin switch (*s) { 880254c4725SOleg Bulyzhin case '-': /* a range */ 8819758b77fSLuigi Rizzo av = s + 1; 8829758b77fSLuigi Rizzo b = strtoport(av, &s, 0, proto); 883254c4725SOleg Bulyzhin /* Reject expressions like '1-abc' or '1-2-3'. */ 884254c4725SOleg Bulyzhin if (s == av || (*s != ',' && *s != '\0')) 885254c4725SOleg Bulyzhin return (0); 8869758b77fSLuigi Rizzo p[0] = a; 8879758b77fSLuigi Rizzo p[1] = b; 888254c4725SOleg Bulyzhin break; 889254c4725SOleg Bulyzhin case ',': /* comma separated list */ 890254c4725SOleg Bulyzhin case '\0': 8919758b77fSLuigi Rizzo p[0] = p[1] = a; 892254c4725SOleg Bulyzhin break; 893254c4725SOleg Bulyzhin default: 894254c4725SOleg Bulyzhin warnx("port list: invalid separator <%c> in <%s>", 89599e5e645SLuigi Rizzo *s, av); 896254c4725SOleg Bulyzhin return (0); 897254c4725SOleg Bulyzhin } 898254c4725SOleg Bulyzhin 899e706181bSLuigi Rizzo i++; 900e706181bSLuigi Rizzo p += 2; 9019758b77fSLuigi Rizzo av = s + 1; 9029758b77fSLuigi Rizzo } 9039758b77fSLuigi Rizzo if (i > 0) { 9049758b77fSLuigi Rizzo if (i + 1 > F_LEN_MASK) 905e706181bSLuigi Rizzo errx(EX_DATAERR, "too many ports/ranges\n"); 9069758b77fSLuigi Rizzo cmd->o.len |= i + 1; /* leave F_NOT and F_OR untouched */ 9079758b77fSLuigi Rizzo } 908254c4725SOleg Bulyzhin return (i); 9099758b77fSLuigi Rizzo } 9109758b77fSLuigi Rizzo 9119758b77fSLuigi Rizzo static struct _s_x icmpcodes[] = { 9129758b77fSLuigi Rizzo { "net", ICMP_UNREACH_NET }, 9139758b77fSLuigi Rizzo { "host", ICMP_UNREACH_HOST }, 9149758b77fSLuigi Rizzo { "protocol", ICMP_UNREACH_PROTOCOL }, 9159758b77fSLuigi Rizzo { "port", ICMP_UNREACH_PORT }, 9169758b77fSLuigi Rizzo { "needfrag", ICMP_UNREACH_NEEDFRAG }, 9179758b77fSLuigi Rizzo { "srcfail", ICMP_UNREACH_SRCFAIL }, 9189758b77fSLuigi Rizzo { "net-unknown", ICMP_UNREACH_NET_UNKNOWN }, 9199758b77fSLuigi Rizzo { "host-unknown", ICMP_UNREACH_HOST_UNKNOWN }, 9209758b77fSLuigi Rizzo { "isolated", ICMP_UNREACH_ISOLATED }, 9219758b77fSLuigi Rizzo { "net-prohib", ICMP_UNREACH_NET_PROHIB }, 9229758b77fSLuigi Rizzo { "host-prohib", ICMP_UNREACH_HOST_PROHIB }, 9239758b77fSLuigi Rizzo { "tosnet", ICMP_UNREACH_TOSNET }, 9249758b77fSLuigi Rizzo { "toshost", ICMP_UNREACH_TOSHOST }, 9259758b77fSLuigi Rizzo { "filter-prohib", ICMP_UNREACH_FILTER_PROHIB }, 9269758b77fSLuigi Rizzo { "host-precedence", ICMP_UNREACH_HOST_PRECEDENCE }, 9279758b77fSLuigi Rizzo { "precedence-cutoff", ICMP_UNREACH_PRECEDENCE_CUTOFF }, 9289758b77fSLuigi Rizzo { NULL, 0 } 9299758b77fSLuigi Rizzo }; 9309758b77fSLuigi Rizzo 9319758b77fSLuigi Rizzo static void 9329758b77fSLuigi Rizzo fill_reject_code(u_short *codep, char *str) 9339758b77fSLuigi Rizzo { 9349758b77fSLuigi Rizzo int val; 9359758b77fSLuigi Rizzo char *s; 9369758b77fSLuigi Rizzo 9379758b77fSLuigi Rizzo val = strtoul(str, &s, 0); 9389758b77fSLuigi Rizzo if (s == str || *s != '\0' || val >= 0x100) 9399758b77fSLuigi Rizzo val = match_token(icmpcodes, str); 940e706181bSLuigi Rizzo if (val < 0) 9419758b77fSLuigi Rizzo errx(EX_DATAERR, "unknown ICMP unreachable code ``%s''", str); 9429758b77fSLuigi Rizzo *codep = val; 9439758b77fSLuigi Rizzo return; 9449758b77fSLuigi Rizzo } 9459758b77fSLuigi Rizzo 9469758b77fSLuigi Rizzo static void 947571f8c1bSLuigi Rizzo print_reject_code(uint16_t code) 9489758b77fSLuigi Rizzo { 94962ff38aeSLuigi Rizzo char const *s = match_value(icmpcodes, code); 9509758b77fSLuigi Rizzo 9519758b77fSLuigi Rizzo if (s != NULL) 9525e43aef8SLuigi Rizzo printf("unreach %s", s); 9539758b77fSLuigi Rizzo else 9545e43aef8SLuigi Rizzo printf("unreach %u", code); 9559758b77fSLuigi Rizzo } 9569758b77fSLuigi Rizzo 9579066356bSBjoern A. Zeeb static struct _s_x icmp6codes[] = { 9589066356bSBjoern A. Zeeb { "no-route", ICMP6_DST_UNREACH_NOROUTE }, 9599066356bSBjoern A. Zeeb { "admin-prohib", ICMP6_DST_UNREACH_ADMIN }, 9609066356bSBjoern A. Zeeb { "address", ICMP6_DST_UNREACH_ADDR }, 9619066356bSBjoern A. Zeeb { "port", ICMP6_DST_UNREACH_NOPORT }, 9629066356bSBjoern A. Zeeb { NULL, 0 } 9639066356bSBjoern A. Zeeb }; 9649066356bSBjoern A. Zeeb 9659066356bSBjoern A. Zeeb static void 9669066356bSBjoern A. Zeeb fill_unreach6_code(u_short *codep, char *str) 9679066356bSBjoern A. Zeeb { 9689066356bSBjoern A. Zeeb int val; 9699066356bSBjoern A. Zeeb char *s; 9709066356bSBjoern A. Zeeb 9719066356bSBjoern A. Zeeb val = strtoul(str, &s, 0); 9729066356bSBjoern A. Zeeb if (s == str || *s != '\0' || val >= 0x100) 9739066356bSBjoern A. Zeeb val = match_token(icmp6codes, str); 9749066356bSBjoern A. Zeeb if (val < 0) 9759066356bSBjoern A. Zeeb errx(EX_DATAERR, "unknown ICMPv6 unreachable code ``%s''", str); 9769066356bSBjoern A. Zeeb *codep = val; 9779066356bSBjoern A. Zeeb return; 9789066356bSBjoern A. Zeeb } 9799066356bSBjoern A. Zeeb 9809066356bSBjoern A. Zeeb static void 9819066356bSBjoern A. Zeeb print_unreach6_code(uint16_t code) 9829066356bSBjoern A. Zeeb { 9839066356bSBjoern A. Zeeb char const *s = match_value(icmp6codes, code); 9849066356bSBjoern A. Zeeb 9859066356bSBjoern A. Zeeb if (s != NULL) 9869066356bSBjoern A. Zeeb printf("unreach6 %s", s); 9879066356bSBjoern A. Zeeb else 9889066356bSBjoern A. Zeeb printf("unreach6 %u", code); 9899066356bSBjoern A. Zeeb } 9909066356bSBjoern A. Zeeb 9919758b77fSLuigi Rizzo /* 9929758b77fSLuigi Rizzo * Returns the number of bits set (from left) in a contiguous bitmask, 9939758b77fSLuigi Rizzo * or -1 if the mask is not contiguous. 9949758b77fSLuigi Rizzo * XXX this needs a proper fix. 9959758b77fSLuigi Rizzo * This effectively works on masks in big-endian (network) format. 9969758b77fSLuigi Rizzo * when compiled on little endian architectures. 9979758b77fSLuigi Rizzo * 9989758b77fSLuigi Rizzo * First bit is bit 7 of the first byte -- note, for MAC addresses, 9999758b77fSLuigi Rizzo * the first bit on the wire is bit 0 of the first byte. 10009758b77fSLuigi Rizzo * len is the max length in bits. 10019758b77fSLuigi Rizzo */ 10029758b77fSLuigi Rizzo static int 1003f3a126d3SLuigi Rizzo contigmask(uint8_t *p, int len) 10049758b77fSLuigi Rizzo { 10059758b77fSLuigi Rizzo int i, n; 1006f3a126d3SLuigi Rizzo 10079758b77fSLuigi Rizzo for (i=0; i<len ; i++) 10089758b77fSLuigi Rizzo if ( (p[i/8] & (1 << (7 - (i%8)))) == 0) /* first bit unset */ 10099758b77fSLuigi Rizzo break; 10109758b77fSLuigi Rizzo for (n=i+1; n < len; n++) 10119758b77fSLuigi Rizzo if ( (p[n/8] & (1 << (7 - (n%8)))) != 0) 10129758b77fSLuigi Rizzo return -1; /* mask not contiguous */ 10139758b77fSLuigi Rizzo return i; 10149758b77fSLuigi Rizzo } 10159758b77fSLuigi Rizzo 10169758b77fSLuigi Rizzo /* 10179758b77fSLuigi Rizzo * print flags set/clear in the two bitmasks passed as parameters. 10189758b77fSLuigi Rizzo * There is a specialized check for f_tcpflags. 10199758b77fSLuigi Rizzo */ 10209758b77fSLuigi Rizzo static void 102162ff38aeSLuigi Rizzo print_flags(char const *name, ipfw_insn *cmd, struct _s_x *list) 10229758b77fSLuigi Rizzo { 102362ff38aeSLuigi Rizzo char const *comma = ""; 10249758b77fSLuigi Rizzo int i; 1025f3a126d3SLuigi Rizzo uint8_t set = cmd->arg1 & 0xff; 1026f3a126d3SLuigi Rizzo uint8_t clear = (cmd->arg1 >> 8) & 0xff; 10279758b77fSLuigi Rizzo 10289758b77fSLuigi Rizzo if (list == f_tcpflags && set == TH_SYN && clear == TH_ACK) { 10299758b77fSLuigi Rizzo printf(" setup"); 10309758b77fSLuigi Rizzo return; 10319758b77fSLuigi Rizzo } 10329758b77fSLuigi Rizzo 10339758b77fSLuigi Rizzo printf(" %s ", name); 10349758b77fSLuigi Rizzo for (i=0; list[i].x != 0; i++) { 10359758b77fSLuigi Rizzo if (set & list[i].x) { 10369758b77fSLuigi Rizzo set &= ~list[i].x; 10379758b77fSLuigi Rizzo printf("%s%s", comma, list[i].s); 10389758b77fSLuigi Rizzo comma = ","; 10399758b77fSLuigi Rizzo } 10409758b77fSLuigi Rizzo if (clear & list[i].x) { 10419758b77fSLuigi Rizzo clear &= ~list[i].x; 10429758b77fSLuigi Rizzo printf("%s!%s", comma, list[i].s); 10439758b77fSLuigi Rizzo comma = ","; 10449758b77fSLuigi Rizzo } 10459758b77fSLuigi Rizzo } 10469758b77fSLuigi Rizzo } 10479758b77fSLuigi Rizzo 10489758b77fSLuigi Rizzo /* 10499758b77fSLuigi Rizzo * Print the ip address contained in a command. 10509758b77fSLuigi Rizzo */ 10519758b77fSLuigi Rizzo static void 105262ff38aeSLuigi Rizzo print_ip(ipfw_insn_ip *cmd, char const *s) 10539758b77fSLuigi Rizzo { 10549758b77fSLuigi Rizzo struct hostent *he = NULL; 1055571f8c1bSLuigi Rizzo int len = F_LEN((ipfw_insn *)cmd); 1056571f8c1bSLuigi Rizzo uint32_t *a = ((ipfw_insn_u32 *)cmd)->d; 10579758b77fSLuigi Rizzo 1058e706181bSLuigi Rizzo printf("%s%s ", cmd->o.len & F_NOT ? " not": "", s); 10599758b77fSLuigi Rizzo 10609758b77fSLuigi Rizzo if (cmd->o.opcode == O_IP_SRC_ME || cmd->o.opcode == O_IP_DST_ME) { 10619758b77fSLuigi Rizzo printf("me"); 10629758b77fSLuigi Rizzo return; 10639758b77fSLuigi Rizzo } 1064cd8b5ae0SRuslan Ermilov if (cmd->o.opcode == O_IP_SRC_LOOKUP || 1065cd8b5ae0SRuslan Ermilov cmd->o.opcode == O_IP_DST_LOOKUP) { 1066cd8b5ae0SRuslan Ermilov printf("table(%u", ((ipfw_insn *)cmd)->arg1); 1067cd8b5ae0SRuslan Ermilov if (len == F_INSN_SIZE(ipfw_insn_u32)) 1068cd8b5ae0SRuslan Ermilov printf(",%u", *a); 1069cd8b5ae0SRuslan Ermilov printf(")"); 1070cd8b5ae0SRuslan Ermilov return; 1071cd8b5ae0SRuslan Ermilov } 10729758b77fSLuigi Rizzo if (cmd->o.opcode == O_IP_SRC_SET || cmd->o.opcode == O_IP_DST_SET) { 1073571f8c1bSLuigi Rizzo uint32_t x, *map = (uint32_t *)&(cmd->mask); 10749ef3f16dSLuigi Rizzo int i, j; 10759758b77fSLuigi Rizzo char comma = '{'; 10769758b77fSLuigi Rizzo 10779758b77fSLuigi Rizzo x = cmd->o.arg1 - 1; 10789758b77fSLuigi Rizzo x = htonl( ~x ); 10799758b77fSLuigi Rizzo cmd->addr.s_addr = htonl(cmd->addr.s_addr); 10809758b77fSLuigi Rizzo printf("%s/%d", inet_ntoa(cmd->addr), 1081f3a126d3SLuigi Rizzo contigmask((uint8_t *)&x, 32)); 10829758b77fSLuigi Rizzo x = cmd->addr.s_addr = htonl(cmd->addr.s_addr); 10839758b77fSLuigi Rizzo x &= 0xff; /* base */ 10849ef3f16dSLuigi Rizzo /* 10859ef3f16dSLuigi Rizzo * Print bits and ranges. 10869ef3f16dSLuigi Rizzo * Locate first bit set (i), then locate first bit unset (j). 10879ef3f16dSLuigi Rizzo * If we have 3+ consecutive bits set, then print them as a 10889ef3f16dSLuigi Rizzo * range, otherwise only print the initial bit and rescan. 10899ef3f16dSLuigi Rizzo */ 10909758b77fSLuigi Rizzo for (i=0; i < cmd->o.arg1; i++) 1091571f8c1bSLuigi Rizzo if (map[i/32] & (1<<(i & 31))) { 10929ef3f16dSLuigi Rizzo for (j=i+1; j < cmd->o.arg1; j++) 1093571f8c1bSLuigi Rizzo if (!(map[ j/32] & (1<<(j & 31)))) 10949ef3f16dSLuigi Rizzo break; 10959758b77fSLuigi Rizzo printf("%c%d", comma, i+x); 10969ef3f16dSLuigi Rizzo if (j>i+2) { /* range has at least 3 elements */ 10979ef3f16dSLuigi Rizzo printf("-%d", j-1+x); 10989ef3f16dSLuigi Rizzo i = j-1; 10999ef3f16dSLuigi Rizzo } 11009758b77fSLuigi Rizzo comma = ','; 11019758b77fSLuigi Rizzo } 11029758b77fSLuigi Rizzo printf("}"); 11039758b77fSLuigi Rizzo return; 11049758b77fSLuigi Rizzo } 1105571f8c1bSLuigi Rizzo /* 1106571f8c1bSLuigi Rizzo * len == 2 indicates a single IP, whereas lists of 1 or more 1107571f8c1bSLuigi Rizzo * addr/mask pairs have len = (2n+1). We convert len to n so we 1108571f8c1bSLuigi Rizzo * use that to count the number of entries. 1109571f8c1bSLuigi Rizzo */ 1110571f8c1bSLuigi Rizzo for (len = len / 2; len > 0; len--, a += 2) { 1111571f8c1bSLuigi Rizzo int mb = /* mask length */ 1112571f8c1bSLuigi Rizzo (cmd->o.opcode == O_IP_SRC || cmd->o.opcode == O_IP_DST) ? 1113f3a126d3SLuigi Rizzo 32 : contigmask((uint8_t *)&(a[1]), 32); 11149758b77fSLuigi Rizzo if (mb == 32 && do_resolv) 1115571f8c1bSLuigi Rizzo he = gethostbyaddr((char *)&(a[0]), sizeof(u_long), AF_INET); 11169758b77fSLuigi Rizzo if (he != NULL) /* resolved to name */ 11179758b77fSLuigi Rizzo printf("%s", he->h_name); 11189758b77fSLuigi Rizzo else if (mb == 0) /* any */ 11199758b77fSLuigi Rizzo printf("any"); 11209758b77fSLuigi Rizzo else { /* numeric IP followed by some kind of mask */ 1121571f8c1bSLuigi Rizzo printf("%s", inet_ntoa( *((struct in_addr *)&a[0]) ) ); 11229758b77fSLuigi Rizzo if (mb < 0) 1123571f8c1bSLuigi Rizzo printf(":%s", inet_ntoa( *((struct in_addr *)&a[1]) ) ); 11249758b77fSLuigi Rizzo else if (mb < 32) 11259758b77fSLuigi Rizzo printf("/%d", mb); 11269758b77fSLuigi Rizzo } 1127571f8c1bSLuigi Rizzo if (len > 1) 1128571f8c1bSLuigi Rizzo printf(","); 1129571f8c1bSLuigi Rizzo } 11309758b77fSLuigi Rizzo } 11319758b77fSLuigi Rizzo 11329758b77fSLuigi Rizzo /* 11339758b77fSLuigi Rizzo * prints a MAC address/mask pair 11349758b77fSLuigi Rizzo */ 11359758b77fSLuigi Rizzo static void 1136f3a126d3SLuigi Rizzo print_mac(uint8_t *addr, uint8_t *mask) 11379758b77fSLuigi Rizzo { 11389758b77fSLuigi Rizzo int l = contigmask(mask, 48); 11399758b77fSLuigi Rizzo 11409758b77fSLuigi Rizzo if (l == 0) 11419758b77fSLuigi Rizzo printf(" any"); 11429758b77fSLuigi Rizzo else { 11439758b77fSLuigi Rizzo printf(" %02x:%02x:%02x:%02x:%02x:%02x", 11449758b77fSLuigi Rizzo addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); 11459758b77fSLuigi Rizzo if (l == -1) 11469758b77fSLuigi Rizzo printf("&%02x:%02x:%02x:%02x:%02x:%02x", 11479758b77fSLuigi Rizzo mask[0], mask[1], mask[2], 11489758b77fSLuigi Rizzo mask[3], mask[4], mask[5]); 11499758b77fSLuigi Rizzo else if (l < 48) 11509758b77fSLuigi Rizzo printf("/%d", l); 11519758b77fSLuigi Rizzo } 11529758b77fSLuigi Rizzo } 11539758b77fSLuigi Rizzo 11545e43aef8SLuigi Rizzo static void 11555e43aef8SLuigi Rizzo fill_icmptypes(ipfw_insn_u32 *cmd, char *av) 11565e43aef8SLuigi Rizzo { 1157571f8c1bSLuigi Rizzo uint8_t type; 11585e43aef8SLuigi Rizzo 11595e43aef8SLuigi Rizzo cmd->d[0] = 0; 11605e43aef8SLuigi Rizzo while (*av) { 11615e43aef8SLuigi Rizzo if (*av == ',') 11625e43aef8SLuigi Rizzo av++; 11635e43aef8SLuigi Rizzo 11645e43aef8SLuigi Rizzo type = strtoul(av, &av, 0); 11655e43aef8SLuigi Rizzo 11665e43aef8SLuigi Rizzo if (*av != ',' && *av != '\0') 11675e43aef8SLuigi Rizzo errx(EX_DATAERR, "invalid ICMP type"); 11685e43aef8SLuigi Rizzo 11695e43aef8SLuigi Rizzo if (type > 31) 11705e43aef8SLuigi Rizzo errx(EX_DATAERR, "ICMP type out of range"); 11715e43aef8SLuigi Rizzo 11725e43aef8SLuigi Rizzo cmd->d[0] |= 1 << type; 11735e43aef8SLuigi Rizzo } 11745e43aef8SLuigi Rizzo cmd->o.opcode = O_ICMPTYPE; 11755e43aef8SLuigi Rizzo cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32); 11765e43aef8SLuigi Rizzo } 11775e43aef8SLuigi Rizzo 11785e43aef8SLuigi Rizzo static void 11795e43aef8SLuigi Rizzo print_icmptypes(ipfw_insn_u32 *cmd) 11805e43aef8SLuigi Rizzo { 11815e43aef8SLuigi Rizzo int i; 11825e43aef8SLuigi Rizzo char sep= ' '; 11835e43aef8SLuigi Rizzo 11845e43aef8SLuigi Rizzo printf(" icmptypes"); 11855e43aef8SLuigi Rizzo for (i = 0; i < 32; i++) { 11865e43aef8SLuigi Rizzo if ( (cmd->d[0] & (1 << (i))) == 0) 11875e43aef8SLuigi Rizzo continue; 11885e43aef8SLuigi Rizzo printf("%c%d", sep, i); 11895e43aef8SLuigi Rizzo sep = ','; 11905e43aef8SLuigi Rizzo } 11915e43aef8SLuigi Rizzo } 11929758b77fSLuigi Rizzo 11939758b77fSLuigi Rizzo /* 11948195404bSBrooks Davis * Print the ip address contained in a command. 11958195404bSBrooks Davis */ 11968195404bSBrooks Davis static void 11978195404bSBrooks Davis print_ip6(ipfw_insn_ip6 *cmd, char const *s) 11988195404bSBrooks Davis { 11998195404bSBrooks Davis struct hostent *he = NULL; 12008195404bSBrooks Davis int len = F_LEN((ipfw_insn *) cmd) - 1; 12018195404bSBrooks Davis struct in6_addr *a = &(cmd->addr6); 12028195404bSBrooks Davis char trad[255]; 12038195404bSBrooks Davis 12048195404bSBrooks Davis printf("%s%s ", cmd->o.len & F_NOT ? " not": "", s); 12058195404bSBrooks Davis 12068195404bSBrooks Davis if (cmd->o.opcode == O_IP6_SRC_ME || cmd->o.opcode == O_IP6_DST_ME) { 12078195404bSBrooks Davis printf("me6"); 12088195404bSBrooks Davis return; 12098195404bSBrooks Davis } 12108195404bSBrooks Davis if (cmd->o.opcode == O_IP6) { 121136c263ccSHajimu UMEMOTO printf(" ip6"); 12128195404bSBrooks Davis return; 12138195404bSBrooks Davis } 12148195404bSBrooks Davis 12158195404bSBrooks Davis /* 12168195404bSBrooks Davis * len == 4 indicates a single IP, whereas lists of 1 or more 12178195404bSBrooks Davis * addr/mask pairs have len = (2n+1). We convert len to n so we 12188195404bSBrooks Davis * use that to count the number of entries. 12198195404bSBrooks Davis */ 12208195404bSBrooks Davis 12218195404bSBrooks Davis for (len = len / 4; len > 0; len -= 2, a += 2) { 12228195404bSBrooks Davis int mb = /* mask length */ 12238195404bSBrooks Davis (cmd->o.opcode == O_IP6_SRC || cmd->o.opcode == O_IP6_DST) ? 12248195404bSBrooks Davis 128 : contigmask((uint8_t *)&(a[1]), 128); 12258195404bSBrooks Davis 12268195404bSBrooks Davis if (mb == 128 && do_resolv) 12278195404bSBrooks Davis he = gethostbyaddr((char *)a, sizeof(*a), AF_INET6); 12288195404bSBrooks Davis if (he != NULL) /* resolved to name */ 12298195404bSBrooks Davis printf("%s", he->h_name); 12308195404bSBrooks Davis else if (mb == 0) /* any */ 12318195404bSBrooks Davis printf("any"); 12328195404bSBrooks Davis else { /* numeric IP followed by some kind of mask */ 12338195404bSBrooks Davis if (inet_ntop(AF_INET6, a, trad, sizeof( trad ) ) == NULL) 12348195404bSBrooks Davis printf("Error ntop in print_ip6\n"); 12358195404bSBrooks Davis printf("%s", trad ); 12368195404bSBrooks Davis if (mb < 0) /* XXX not really legal... */ 12378195404bSBrooks Davis printf(":%s", 12388195404bSBrooks Davis inet_ntop(AF_INET6, &a[1], trad, sizeof(trad))); 12398195404bSBrooks Davis else if (mb < 128) 12408195404bSBrooks Davis printf("/%d", mb); 12418195404bSBrooks Davis } 12428195404bSBrooks Davis if (len > 2) 12438195404bSBrooks Davis printf(","); 12448195404bSBrooks Davis } 12458195404bSBrooks Davis } 12468195404bSBrooks Davis 12478195404bSBrooks Davis static void 12488195404bSBrooks Davis fill_icmp6types(ipfw_insn_icmp6 *cmd, char *av) 12498195404bSBrooks Davis { 12508195404bSBrooks Davis uint8_t type; 12518195404bSBrooks Davis 1252e7f2ec53SJohn Hay bzero(cmd, sizeof(*cmd)); 12538195404bSBrooks Davis while (*av) { 12548195404bSBrooks Davis if (*av == ',') 12558195404bSBrooks Davis av++; 12568195404bSBrooks Davis type = strtoul(av, &av, 0); 12578195404bSBrooks Davis if (*av != ',' && *av != '\0') 12588195404bSBrooks Davis errx(EX_DATAERR, "invalid ICMP6 type"); 12598195404bSBrooks Davis /* 12608195404bSBrooks Davis * XXX: shouldn't this be 0xFF? I can't see any reason why 12618195404bSBrooks Davis * we shouldn't be able to filter all possiable values 12628195404bSBrooks Davis * regardless of the ability of the rest of the kernel to do 12638195404bSBrooks Davis * anything useful with them. 12648195404bSBrooks Davis */ 12658195404bSBrooks Davis if (type > ICMP6_MAXTYPE) 12668195404bSBrooks Davis errx(EX_DATAERR, "ICMP6 type out of range"); 12678195404bSBrooks Davis cmd->d[type / 32] |= ( 1 << (type % 32)); 12688195404bSBrooks Davis } 12698195404bSBrooks Davis cmd->o.opcode = O_ICMP6TYPE; 12708195404bSBrooks Davis cmd->o.len |= F_INSN_SIZE(ipfw_insn_icmp6); 12718195404bSBrooks Davis } 12728195404bSBrooks Davis 12738195404bSBrooks Davis 12748195404bSBrooks Davis static void 12758195404bSBrooks Davis print_icmp6types(ipfw_insn_u32 *cmd) 12768195404bSBrooks Davis { 12778195404bSBrooks Davis int i, j; 12788195404bSBrooks Davis char sep= ' '; 12798195404bSBrooks Davis 128036c263ccSHajimu UMEMOTO printf(" ip6 icmp6types"); 12818195404bSBrooks Davis for (i = 0; i < 7; i++) 12828195404bSBrooks Davis for (j=0; j < 32; ++j) { 12838195404bSBrooks Davis if ( (cmd->d[i] & (1 << (j))) == 0) 12848195404bSBrooks Davis continue; 12858195404bSBrooks Davis printf("%c%d", sep, (i*32 + j)); 12868195404bSBrooks Davis sep = ','; 12878195404bSBrooks Davis } 12888195404bSBrooks Davis } 12898195404bSBrooks Davis 12908195404bSBrooks Davis static void 12918195404bSBrooks Davis print_flow6id( ipfw_insn_u32 *cmd) 12928195404bSBrooks Davis { 12938195404bSBrooks Davis uint16_t i, limit = cmd->o.arg1; 12948195404bSBrooks Davis char sep = ','; 12958195404bSBrooks Davis 12968195404bSBrooks Davis printf(" flow-id "); 12978195404bSBrooks Davis for( i=0; i < limit; ++i) { 12988195404bSBrooks Davis if (i == limit - 1) 12998195404bSBrooks Davis sep = ' '; 13008195404bSBrooks Davis printf("%d%c", cmd->d[i], sep); 13018195404bSBrooks Davis } 13028195404bSBrooks Davis } 13038195404bSBrooks Davis 13048195404bSBrooks Davis /* structure and define for the extension header in ipv6 */ 13058195404bSBrooks Davis static struct _s_x ext6hdrcodes[] = { 13068195404bSBrooks Davis { "frag", EXT_FRAGMENT }, 13078195404bSBrooks Davis { "hopopt", EXT_HOPOPTS }, 13088195404bSBrooks Davis { "route", EXT_ROUTING }, 13099066356bSBjoern A. Zeeb { "dstopt", EXT_DSTOPTS }, 13108195404bSBrooks Davis { "ah", EXT_AH }, 13118195404bSBrooks Davis { "esp", EXT_ESP }, 13127a92401aSBjoern A. Zeeb { "rthdr0", EXT_RTHDR0 }, 13137a92401aSBjoern A. Zeeb { "rthdr2", EXT_RTHDR2 }, 13148195404bSBrooks Davis { NULL, 0 } 13158195404bSBrooks Davis }; 13168195404bSBrooks Davis 13178195404bSBrooks Davis /* fills command for the extension header filtering */ 13188195404bSBrooks Davis int 13198195404bSBrooks Davis fill_ext6hdr( ipfw_insn *cmd, char *av) 13208195404bSBrooks Davis { 13218195404bSBrooks Davis int tok; 13228195404bSBrooks Davis char *s = av; 13238195404bSBrooks Davis 13248195404bSBrooks Davis cmd->arg1 = 0; 13258195404bSBrooks Davis 13268195404bSBrooks Davis while(s) { 13278195404bSBrooks Davis av = strsep( &s, ",") ; 13288195404bSBrooks Davis tok = match_token(ext6hdrcodes, av); 13298195404bSBrooks Davis switch (tok) { 13308195404bSBrooks Davis case EXT_FRAGMENT: 13318195404bSBrooks Davis cmd->arg1 |= EXT_FRAGMENT; 13328195404bSBrooks Davis break; 13338195404bSBrooks Davis 13348195404bSBrooks Davis case EXT_HOPOPTS: 13358195404bSBrooks Davis cmd->arg1 |= EXT_HOPOPTS; 13368195404bSBrooks Davis break; 13378195404bSBrooks Davis 13388195404bSBrooks Davis case EXT_ROUTING: 13398195404bSBrooks Davis cmd->arg1 |= EXT_ROUTING; 13408195404bSBrooks Davis break; 13418195404bSBrooks Davis 13429066356bSBjoern A. Zeeb case EXT_DSTOPTS: 13439066356bSBjoern A. Zeeb cmd->arg1 |= EXT_DSTOPTS; 13449066356bSBjoern A. Zeeb break; 13459066356bSBjoern A. Zeeb 13468195404bSBrooks Davis case EXT_AH: 13478195404bSBrooks Davis cmd->arg1 |= EXT_AH; 13488195404bSBrooks Davis break; 13498195404bSBrooks Davis 13508195404bSBrooks Davis case EXT_ESP: 13518195404bSBrooks Davis cmd->arg1 |= EXT_ESP; 13528195404bSBrooks Davis break; 13538195404bSBrooks Davis 13547a92401aSBjoern A. Zeeb case EXT_RTHDR0: 13557a92401aSBjoern A. Zeeb cmd->arg1 |= EXT_RTHDR0; 13567a92401aSBjoern A. Zeeb break; 13577a92401aSBjoern A. Zeeb 13587a92401aSBjoern A. Zeeb case EXT_RTHDR2: 13597a92401aSBjoern A. Zeeb cmd->arg1 |= EXT_RTHDR2; 13607a92401aSBjoern A. Zeeb break; 13617a92401aSBjoern A. Zeeb 13628195404bSBrooks Davis default: 13638195404bSBrooks Davis errx( EX_DATAERR, "invalid option for ipv6 exten header" ); 13648195404bSBrooks Davis break; 13658195404bSBrooks Davis } 13668195404bSBrooks Davis } 13678195404bSBrooks Davis if (cmd->arg1 == 0 ) 13688195404bSBrooks Davis return 0; 13698195404bSBrooks Davis cmd->opcode = O_EXT_HDR; 13708195404bSBrooks Davis cmd->len |= F_INSN_SIZE( ipfw_insn ); 13718195404bSBrooks Davis return 1; 13728195404bSBrooks Davis } 13738195404bSBrooks Davis 13748195404bSBrooks Davis void 13758195404bSBrooks Davis print_ext6hdr( ipfw_insn *cmd ) 13768195404bSBrooks Davis { 13778195404bSBrooks Davis char sep = ' '; 13788195404bSBrooks Davis 13798195404bSBrooks Davis printf(" extension header:"); 13808195404bSBrooks Davis if (cmd->arg1 & EXT_FRAGMENT ) { 13818195404bSBrooks Davis printf("%cfragmentation", sep); 13828195404bSBrooks Davis sep = ','; 13838195404bSBrooks Davis } 13848195404bSBrooks Davis if (cmd->arg1 & EXT_HOPOPTS ) { 13858195404bSBrooks Davis printf("%chop options", sep); 13868195404bSBrooks Davis sep = ','; 13878195404bSBrooks Davis } 13888195404bSBrooks Davis if (cmd->arg1 & EXT_ROUTING ) { 13898195404bSBrooks Davis printf("%crouting options", sep); 13908195404bSBrooks Davis sep = ','; 13918195404bSBrooks Davis } 13927a92401aSBjoern A. Zeeb if (cmd->arg1 & EXT_RTHDR0 ) { 13937a92401aSBjoern A. Zeeb printf("%crthdr0", sep); 13947a92401aSBjoern A. Zeeb sep = ','; 13957a92401aSBjoern A. Zeeb } 13967a92401aSBjoern A. Zeeb if (cmd->arg1 & EXT_RTHDR2 ) { 13977a92401aSBjoern A. Zeeb printf("%crthdr2", sep); 13987a92401aSBjoern A. Zeeb sep = ','; 13997a92401aSBjoern A. Zeeb } 14009066356bSBjoern A. Zeeb if (cmd->arg1 & EXT_DSTOPTS ) { 14019066356bSBjoern A. Zeeb printf("%cdestination options", sep); 14029066356bSBjoern A. Zeeb sep = ','; 14039066356bSBjoern A. Zeeb } 14048195404bSBrooks Davis if (cmd->arg1 & EXT_AH ) { 14058195404bSBrooks Davis printf("%cauthentication header", sep); 14068195404bSBrooks Davis sep = ','; 14078195404bSBrooks Davis } 14088195404bSBrooks Davis if (cmd->arg1 & EXT_ESP ) { 14098195404bSBrooks Davis printf("%cencapsulated security payload", sep); 14108195404bSBrooks Davis } 14118195404bSBrooks Davis } 14128195404bSBrooks Davis 14138195404bSBrooks Davis /* 14149758b77fSLuigi Rizzo * show_ipfw() prints the body of an ipfw rule. 14159758b77fSLuigi Rizzo * Because the standard rule has at least proto src_ip dst_ip, we use 14169758b77fSLuigi Rizzo * a helper function to produce these entries if not provided explicitly. 1417e706181bSLuigi Rizzo * The first argument is the list of fields we have, the second is 1418e706181bSLuigi Rizzo * the list of fields we want to be printed. 141999e5e645SLuigi Rizzo * 1420e706181bSLuigi Rizzo * Special cases if we have provided a MAC header: 1421e706181bSLuigi Rizzo * + if the rule does not contain IP addresses/ports, do not print them; 1422e706181bSLuigi Rizzo * + if the rule does not contain an IP proto, print "all" instead of "ip"; 1423e706181bSLuigi Rizzo * 1424e706181bSLuigi Rizzo * Once we have 'have_options', IP header fields are printed as options. 14259758b77fSLuigi Rizzo */ 142699e5e645SLuigi Rizzo #define HAVE_PROTO 0x0001 142799e5e645SLuigi Rizzo #define HAVE_SRCIP 0x0002 142899e5e645SLuigi Rizzo #define HAVE_DSTIP 0x0004 14295b41efddSMaxim Konovalov #define HAVE_PROTO4 0x0008 14305b41efddSMaxim Konovalov #define HAVE_PROTO6 0x0010 1431e706181bSLuigi Rizzo #define HAVE_OPTIONS 0x8000 14329758b77fSLuigi Rizzo 143399e5e645SLuigi Rizzo #define HAVE_IP (HAVE_PROTO | HAVE_SRCIP | HAVE_DSTIP) 14349758b77fSLuigi Rizzo static void 1435e706181bSLuigi Rizzo show_prerequisites(int *flags, int want, int cmd) 14369758b77fSLuigi Rizzo { 1437ac6cec51SLuigi Rizzo if (comment_only) 1438ac6cec51SLuigi Rizzo return; 1439e706181bSLuigi Rizzo if ( (*flags & HAVE_IP) == HAVE_IP) 1440e706181bSLuigi Rizzo *flags |= HAVE_OPTIONS; 144199e5e645SLuigi Rizzo 1442e706181bSLuigi Rizzo if ( !(*flags & HAVE_OPTIONS)) { 14439758b77fSLuigi Rizzo if ( !(*flags & HAVE_PROTO) && (want & HAVE_PROTO)) 144457cd6d26SMax Laier if ( (*flags & HAVE_PROTO4)) 144557cd6d26SMax Laier printf(" ip4"); 144657cd6d26SMax Laier else if ( (*flags & HAVE_PROTO6)) 144757cd6d26SMax Laier printf(" ip6"); 144857cd6d26SMax Laier else 1449e706181bSLuigi Rizzo printf(" ip"); 145057cd6d26SMax Laier 14519758b77fSLuigi Rizzo if ( !(*flags & HAVE_SRCIP) && (want & HAVE_SRCIP)) 14529758b77fSLuigi Rizzo printf(" from any"); 14539758b77fSLuigi Rizzo if ( !(*flags & HAVE_DSTIP) && (want & HAVE_DSTIP)) 14549758b77fSLuigi Rizzo printf(" to any"); 1455e706181bSLuigi Rizzo } 14569758b77fSLuigi Rizzo *flags |= want; 14579758b77fSLuigi Rizzo } 14589758b77fSLuigi Rizzo 14599758b77fSLuigi Rizzo static void 146045f61351SMaxim Konovalov show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth) 14619758b77fSLuigi Rizzo { 14623d2209aeSGiorgos Keramidas static int twidth = 0; 14639758b77fSLuigi Rizzo int l; 14646a7d5cb6SOleg Bulyzhin ipfw_insn *cmd, *tagptr = NULL; 1465bbc39c83SLuigi Rizzo char *comment = NULL; /* ptr to comment if we have one */ 14669758b77fSLuigi Rizzo int proto = 0; /* default */ 14679758b77fSLuigi Rizzo int flags = 0; /* prerequisites */ 14689758b77fSLuigi Rizzo ipfw_insn_log *logptr = NULL; /* set if we find an O_LOG */ 1469974dfe30SBrian Feldman ipfw_insn_altq *altqptr = NULL; /* set if we find an O_ALTQ */ 14709758b77fSLuigi Rizzo int or_block = 0; /* we are in an or block */ 1471571f8c1bSLuigi Rizzo uint32_t set_disable; 14729758b77fSLuigi Rizzo 1473330462a3SBernd Walter bcopy(&rule->next_rule, &set_disable, sizeof(set_disable)); 147443405724SLuigi Rizzo 147543405724SLuigi Rizzo if (set_disable & (1 << rule->set)) { /* disabled */ 147643405724SLuigi Rizzo if (!show_sets) 147743405724SLuigi Rizzo return; 147843405724SLuigi Rizzo else 147943405724SLuigi Rizzo printf("# DISABLED "); 148043405724SLuigi Rizzo } 14819758b77fSLuigi Rizzo printf("%05u ", rule->rulenum); 14829758b77fSLuigi Rizzo 148362ff38aeSLuigi Rizzo if (pcwidth>0 || bcwidth>0) 1484330462a3SBernd Walter printf("%*llu %*llu ", pcwidth, align_uint64(&rule->pcnt), 1485330462a3SBernd Walter bcwidth, align_uint64(&rule->bcnt)); 14869758b77fSLuigi Rizzo 14871b43a426SLuigi Rizzo if (do_time == 2) 14881b43a426SLuigi Rizzo printf("%10u ", rule->timestamp); 14891b43a426SLuigi Rizzo else if (do_time == 1) { 14909758b77fSLuigi Rizzo char timestr[30]; 14913d2209aeSGiorgos Keramidas time_t t = (time_t)0; 14923d2209aeSGiorgos Keramidas 14933d2209aeSGiorgos Keramidas if (twidth == 0) { 14943d2209aeSGiorgos Keramidas strcpy(timestr, ctime(&t)); 14953d2209aeSGiorgos Keramidas *strchr(timestr, '\n') = '\0'; 14963d2209aeSGiorgos Keramidas twidth = strlen(timestr); 14973d2209aeSGiorgos Keramidas } 14983d2209aeSGiorgos Keramidas if (rule->timestamp) { 14993d2209aeSGiorgos Keramidas t = _long_to_time(rule->timestamp); 15009758b77fSLuigi Rizzo 15019758b77fSLuigi Rizzo strcpy(timestr, ctime(&t)); 15029758b77fSLuigi Rizzo *strchr(timestr, '\n') = '\0'; 15039758b77fSLuigi Rizzo printf("%s ", timestr); 15049758b77fSLuigi Rizzo } else { 15053d2209aeSGiorgos Keramidas printf("%*s", twidth, " "); 15069758b77fSLuigi Rizzo } 15079758b77fSLuigi Rizzo } 15089758b77fSLuigi Rizzo 150943405724SLuigi Rizzo if (show_sets) 151043405724SLuigi Rizzo printf("set %d ", rule->set); 151143405724SLuigi Rizzo 15129758b77fSLuigi Rizzo /* 151312b5dc6aSLuigi Rizzo * print the optional "match probability" 151412b5dc6aSLuigi Rizzo */ 151512b5dc6aSLuigi Rizzo if (rule->cmd_len > 0) { 151612b5dc6aSLuigi Rizzo cmd = rule->cmd ; 151712b5dc6aSLuigi Rizzo if (cmd->opcode == O_PROB) { 151812b5dc6aSLuigi Rizzo ipfw_insn_u32 *p = (ipfw_insn_u32 *)cmd; 151912b5dc6aSLuigi Rizzo double d = 1.0 * p->d[0]; 152012b5dc6aSLuigi Rizzo 152112b5dc6aSLuigi Rizzo d = (d / 0x7fffffff); 152212b5dc6aSLuigi Rizzo printf("prob %f ", d); 152312b5dc6aSLuigi Rizzo } 152412b5dc6aSLuigi Rizzo } 152512b5dc6aSLuigi Rizzo 152612b5dc6aSLuigi Rizzo /* 15279758b77fSLuigi Rizzo * first print actions 15289758b77fSLuigi Rizzo */ 15299758b77fSLuigi Rizzo for (l = rule->cmd_len - rule->act_ofs, cmd = ACTION_PTR(rule); 15309758b77fSLuigi Rizzo l > 0 ; l -= F_LEN(cmd), cmd += F_LEN(cmd)) { 15319758b77fSLuigi Rizzo switch(cmd->opcode) { 15329758b77fSLuigi Rizzo case O_CHECK_STATE: 15339758b77fSLuigi Rizzo printf("check-state"); 1534e706181bSLuigi Rizzo flags = HAVE_IP; /* avoid printing anything else */ 15359758b77fSLuigi Rizzo break; 15369758b77fSLuigi Rizzo 15379758b77fSLuigi Rizzo case O_ACCEPT: 15389758b77fSLuigi Rizzo printf("allow"); 15399758b77fSLuigi Rizzo break; 15409758b77fSLuigi Rizzo 15419758b77fSLuigi Rizzo case O_COUNT: 15429758b77fSLuigi Rizzo printf("count"); 15439758b77fSLuigi Rizzo break; 15449758b77fSLuigi Rizzo 15459758b77fSLuigi Rizzo case O_DENY: 15469758b77fSLuigi Rizzo printf("deny"); 15479758b77fSLuigi Rizzo break; 15489758b77fSLuigi Rizzo 15495e43aef8SLuigi Rizzo case O_REJECT: 15505e43aef8SLuigi Rizzo if (cmd->arg1 == ICMP_REJECT_RST) 15515e43aef8SLuigi Rizzo printf("reset"); 15525e43aef8SLuigi Rizzo else if (cmd->arg1 == ICMP_UNREACH_HOST) 15535e43aef8SLuigi Rizzo printf("reject"); 15545e43aef8SLuigi Rizzo else 15555e43aef8SLuigi Rizzo print_reject_code(cmd->arg1); 15565e43aef8SLuigi Rizzo break; 15575e43aef8SLuigi Rizzo 15589066356bSBjoern A. Zeeb case O_UNREACH6: 15599066356bSBjoern A. Zeeb if (cmd->arg1 == ICMP6_UNREACH_RST) 15609066356bSBjoern A. Zeeb printf("reset6"); 15619066356bSBjoern A. Zeeb else 15629066356bSBjoern A. Zeeb print_unreach6_code(cmd->arg1); 15639066356bSBjoern A. Zeeb break; 15649066356bSBjoern A. Zeeb 1565254c4725SOleg Bulyzhin case O_SKIPTO: 1566254c4725SOleg Bulyzhin PRINT_UINT_ARG("skipto ", cmd->arg1); 156740b1ae9eSGleb Smirnoff break; 156840b1ae9eSGleb Smirnoff 15699758b77fSLuigi Rizzo case O_PIPE: 1570254c4725SOleg Bulyzhin PRINT_UINT_ARG("pipe ", cmd->arg1); 1571254c4725SOleg Bulyzhin break; 1572254c4725SOleg Bulyzhin 15739758b77fSLuigi Rizzo case O_QUEUE: 1574254c4725SOleg Bulyzhin PRINT_UINT_ARG("queue ", cmd->arg1); 1575254c4725SOleg Bulyzhin break; 1576254c4725SOleg Bulyzhin 15779758b77fSLuigi Rizzo case O_DIVERT: 1578254c4725SOleg Bulyzhin PRINT_UINT_ARG("divert ", cmd->arg1); 1579254c4725SOleg Bulyzhin break; 1580254c4725SOleg Bulyzhin 15819758b77fSLuigi Rizzo case O_TEE: 1582254c4725SOleg Bulyzhin PRINT_UINT_ARG("tee ", cmd->arg1); 1583254c4725SOleg Bulyzhin break; 1584254c4725SOleg Bulyzhin 1585670742a1SGleb Smirnoff case O_NETGRAPH: 1586254c4725SOleg Bulyzhin PRINT_UINT_ARG("netgraph ", cmd->arg1); 1587254c4725SOleg Bulyzhin break; 1588254c4725SOleg Bulyzhin 1589670742a1SGleb Smirnoff case O_NGTEE: 1590254c4725SOleg Bulyzhin PRINT_UINT_ARG("ngtee ", cmd->arg1); 1591254c4725SOleg Bulyzhin break; 1592670742a1SGleb Smirnoff 15939758b77fSLuigi Rizzo case O_FORWARD_IP: 15949758b77fSLuigi Rizzo { 15959758b77fSLuigi Rizzo ipfw_insn_sa *s = (ipfw_insn_sa *)cmd; 15969758b77fSLuigi Rizzo 1597c487be96SJulian Elischer if (s->sa.sin_addr.s_addr == INADDR_ANY) { 1598c487be96SJulian Elischer printf("fwd tablearg"); 1599c487be96SJulian Elischer } else { 16009758b77fSLuigi Rizzo printf("fwd %s", inet_ntoa(s->sa.sin_addr)); 1601c487be96SJulian Elischer } 16029758b77fSLuigi Rizzo if (s->sa.sin_port) 16034f531a53SLuigi Rizzo printf(",%d", s->sa.sin_port); 16049758b77fSLuigi Rizzo } 16059758b77fSLuigi Rizzo break; 16069758b77fSLuigi Rizzo 16079758b77fSLuigi Rizzo case O_LOG: /* O_LOG is printed last */ 16089758b77fSLuigi Rizzo logptr = (ipfw_insn_log *)cmd; 16099758b77fSLuigi Rizzo break; 16109758b77fSLuigi Rizzo 1611974dfe30SBrian Feldman case O_ALTQ: /* O_ALTQ is printed after O_LOG */ 1612974dfe30SBrian Feldman altqptr = (ipfw_insn_altq *)cmd; 1613974dfe30SBrian Feldman break; 1614974dfe30SBrian Feldman 16156a7d5cb6SOleg Bulyzhin case O_TAG: 16166a7d5cb6SOleg Bulyzhin tagptr = cmd; 16176a7d5cb6SOleg Bulyzhin break; 16186a7d5cb6SOleg Bulyzhin 1619ff2f6fe8SPaolo Pisati case O_NAT: 1620f94a7fc0SPaolo Pisati PRINT_UINT_ARG("nat ", cmd->arg1); 1621ff2f6fe8SPaolo Pisati break; 1622ff2f6fe8SPaolo Pisati 16238b07e49aSJulian Elischer case O_SETFIB: 16248b07e49aSJulian Elischer PRINT_UINT_ARG("setfib ", cmd->arg1); 16258b07e49aSJulian Elischer break; 16268b07e49aSJulian Elischer 16279758b77fSLuigi Rizzo default: 16289758b77fSLuigi Rizzo printf("** unrecognized action %d len %d ", 16299758b77fSLuigi Rizzo cmd->opcode, cmd->len); 16309758b77fSLuigi Rizzo } 16319758b77fSLuigi Rizzo } 16329758b77fSLuigi Rizzo if (logptr) { 16339758b77fSLuigi Rizzo if (logptr->max_log > 0) 16349758b77fSLuigi Rizzo printf(" log logamount %d", logptr->max_log); 16359758b77fSLuigi Rizzo else 16369758b77fSLuigi Rizzo printf(" log"); 16379758b77fSLuigi Rizzo } 1638974dfe30SBrian Feldman if (altqptr) { 1639974dfe30SBrian Feldman const char *qname; 1640974dfe30SBrian Feldman 1641974dfe30SBrian Feldman qname = altq_qid_to_name(altqptr->qid); 1642974dfe30SBrian Feldman if (qname == NULL) 1643974dfe30SBrian Feldman printf(" altq ?<%u>", altqptr->qid); 1644974dfe30SBrian Feldman else 1645974dfe30SBrian Feldman printf(" altq %s", qname); 1646974dfe30SBrian Feldman } 16476a7d5cb6SOleg Bulyzhin if (tagptr) { 16486a7d5cb6SOleg Bulyzhin if (tagptr->len & F_NOT) 1649254c4725SOleg Bulyzhin PRINT_UINT_ARG(" untag ", tagptr->arg1); 16506a7d5cb6SOleg Bulyzhin else 1651254c4725SOleg Bulyzhin PRINT_UINT_ARG(" tag ", tagptr->arg1); 16526a7d5cb6SOleg Bulyzhin } 1653e706181bSLuigi Rizzo 16549758b77fSLuigi Rizzo /* 1655e706181bSLuigi Rizzo * then print the body. 16569758b77fSLuigi Rizzo */ 165757cd6d26SMax Laier for (l = rule->act_ofs, cmd = rule->cmd ; 165857cd6d26SMax Laier l > 0 ; l -= F_LEN(cmd) , cmd += F_LEN(cmd)) { 165957cd6d26SMax Laier if ((cmd->len & F_OR) || (cmd->len & F_NOT)) 166057cd6d26SMax Laier continue; 166157cd6d26SMax Laier if (cmd->opcode == O_IP4) { 166257cd6d26SMax Laier flags |= HAVE_PROTO4; 166357cd6d26SMax Laier break; 166457cd6d26SMax Laier } else if (cmd->opcode == O_IP6) { 166557cd6d26SMax Laier flags |= HAVE_PROTO6; 166657cd6d26SMax Laier break; 166757cd6d26SMax Laier } 166857cd6d26SMax Laier } 1669e706181bSLuigi Rizzo if (rule->_pad & 1) { /* empty rules before options */ 167057cd6d26SMax Laier if (!do_compact) { 167157cd6d26SMax Laier show_prerequisites(&flags, HAVE_PROTO, 0); 167257cd6d26SMax Laier printf(" from any to any"); 167357cd6d26SMax Laier } 1674e706181bSLuigi Rizzo flags |= HAVE_IP | HAVE_OPTIONS; 1675e706181bSLuigi Rizzo } 1676e706181bSLuigi Rizzo 1677ac6cec51SLuigi Rizzo if (comment_only) 1678ac6cec51SLuigi Rizzo comment = "..."; 1679ac6cec51SLuigi Rizzo 16809758b77fSLuigi Rizzo for (l = rule->act_ofs, cmd = rule->cmd ; 16819758b77fSLuigi Rizzo l > 0 ; l -= F_LEN(cmd) , cmd += F_LEN(cmd)) { 16825e43aef8SLuigi Rizzo /* useful alias */ 16835e43aef8SLuigi Rizzo ipfw_insn_u32 *cmd32 = (ipfw_insn_u32 *)cmd; 16849758b77fSLuigi Rizzo 1685ac6cec51SLuigi Rizzo if (comment_only) { 1686ac6cec51SLuigi Rizzo if (cmd->opcode != O_NOP) 1687ac6cec51SLuigi Rizzo continue; 1688ac6cec51SLuigi Rizzo printf(" // %s\n", (char *)(cmd + 1)); 1689ac6cec51SLuigi Rizzo return; 1690ac6cec51SLuigi Rizzo } 1691ac6cec51SLuigi Rizzo 1692e706181bSLuigi Rizzo show_prerequisites(&flags, 0, cmd->opcode); 1693e706181bSLuigi Rizzo 16949758b77fSLuigi Rizzo switch(cmd->opcode) { 169512b5dc6aSLuigi Rizzo case O_PROB: 169612b5dc6aSLuigi Rizzo break; /* done already */ 169712b5dc6aSLuigi Rizzo 16989758b77fSLuigi Rizzo case O_PROBE_STATE: 16999758b77fSLuigi Rizzo break; /* no need to print anything here */ 17009758b77fSLuigi Rizzo 17019758b77fSLuigi Rizzo case O_IP_SRC: 1702cd8b5ae0SRuslan Ermilov case O_IP_SRC_LOOKUP: 17039758b77fSLuigi Rizzo case O_IP_SRC_MASK: 17049758b77fSLuigi Rizzo case O_IP_SRC_ME: 17059758b77fSLuigi Rizzo case O_IP_SRC_SET: 1706e706181bSLuigi Rizzo show_prerequisites(&flags, HAVE_PROTO, 0); 17079758b77fSLuigi Rizzo if (!(flags & HAVE_SRCIP)) 17089758b77fSLuigi Rizzo printf(" from"); 17099758b77fSLuigi Rizzo if ((cmd->len & F_OR) && !or_block) 17109758b77fSLuigi Rizzo printf(" {"); 1711e706181bSLuigi Rizzo print_ip((ipfw_insn_ip *)cmd, 1712e706181bSLuigi Rizzo (flags & HAVE_OPTIONS) ? " src-ip" : ""); 17139758b77fSLuigi Rizzo flags |= HAVE_SRCIP; 17149758b77fSLuigi Rizzo break; 17159758b77fSLuigi Rizzo 17169758b77fSLuigi Rizzo case O_IP_DST: 1717cd8b5ae0SRuslan Ermilov case O_IP_DST_LOOKUP: 17189758b77fSLuigi Rizzo case O_IP_DST_MASK: 17199758b77fSLuigi Rizzo case O_IP_DST_ME: 17209758b77fSLuigi Rizzo case O_IP_DST_SET: 1721e706181bSLuigi Rizzo show_prerequisites(&flags, HAVE_PROTO|HAVE_SRCIP, 0); 17229758b77fSLuigi Rizzo if (!(flags & HAVE_DSTIP)) 17239758b77fSLuigi Rizzo printf(" to"); 17249758b77fSLuigi Rizzo if ((cmd->len & F_OR) && !or_block) 17259758b77fSLuigi Rizzo printf(" {"); 1726e706181bSLuigi Rizzo print_ip((ipfw_insn_ip *)cmd, 1727e706181bSLuigi Rizzo (flags & HAVE_OPTIONS) ? " dst-ip" : ""); 17289758b77fSLuigi Rizzo flags |= HAVE_DSTIP; 17299758b77fSLuigi Rizzo break; 17309758b77fSLuigi Rizzo 17318195404bSBrooks Davis case O_IP6_SRC: 17328195404bSBrooks Davis case O_IP6_SRC_MASK: 17338195404bSBrooks Davis case O_IP6_SRC_ME: 1734b730879fSMax Laier show_prerequisites(&flags, HAVE_PROTO, 0); 17358195404bSBrooks Davis if (!(flags & HAVE_SRCIP)) 17368195404bSBrooks Davis printf(" from"); 17378195404bSBrooks Davis if ((cmd->len & F_OR) && !or_block) 17388195404bSBrooks Davis printf(" {"); 17398195404bSBrooks Davis print_ip6((ipfw_insn_ip6 *)cmd, 17408195404bSBrooks Davis (flags & HAVE_OPTIONS) ? " src-ip6" : ""); 17418195404bSBrooks Davis flags |= HAVE_SRCIP | HAVE_PROTO; 17428195404bSBrooks Davis break; 17438195404bSBrooks Davis 17448195404bSBrooks Davis case O_IP6_DST: 17458195404bSBrooks Davis case O_IP6_DST_MASK: 17468195404bSBrooks Davis case O_IP6_DST_ME: 17478195404bSBrooks Davis show_prerequisites(&flags, HAVE_PROTO|HAVE_SRCIP, 0); 17488195404bSBrooks Davis if (!(flags & HAVE_DSTIP)) 17498195404bSBrooks Davis printf(" to"); 17508195404bSBrooks Davis if ((cmd->len & F_OR) && !or_block) 17518195404bSBrooks Davis printf(" {"); 17528195404bSBrooks Davis print_ip6((ipfw_insn_ip6 *)cmd, 17538195404bSBrooks Davis (flags & HAVE_OPTIONS) ? " dst-ip6" : ""); 17548195404bSBrooks Davis flags |= HAVE_DSTIP; 17558195404bSBrooks Davis break; 17568195404bSBrooks Davis 17578195404bSBrooks Davis case O_FLOW6ID: 17588195404bSBrooks Davis print_flow6id( (ipfw_insn_u32 *) cmd ); 17598195404bSBrooks Davis flags |= HAVE_OPTIONS; 17608195404bSBrooks Davis break; 17618195404bSBrooks Davis 17629758b77fSLuigi Rizzo case O_IP_DSTPORT: 1763e706181bSLuigi Rizzo show_prerequisites(&flags, HAVE_IP, 0); 17649758b77fSLuigi Rizzo case O_IP_SRCPORT: 1765e706181bSLuigi Rizzo show_prerequisites(&flags, HAVE_PROTO|HAVE_SRCIP, 0); 17668ed2d749SLuigi Rizzo if ((cmd->len & F_OR) && !or_block) 17678ed2d749SLuigi Rizzo printf(" {"); 1768087aa087SMaxim Konovalov if (cmd->len & F_NOT) 1769087aa087SMaxim Konovalov printf(" not"); 1770e706181bSLuigi Rizzo print_newports((ipfw_insn_u16 *)cmd, proto, 1771e706181bSLuigi Rizzo (flags & HAVE_OPTIONS) ? cmd->opcode : 0); 17729758b77fSLuigi Rizzo break; 17739758b77fSLuigi Rizzo 17749758b77fSLuigi Rizzo case O_PROTO: { 17758195404bSBrooks Davis struct protoent *pe = NULL; 17769758b77fSLuigi Rizzo 17779758b77fSLuigi Rizzo if ((cmd->len & F_OR) && !or_block) 17789758b77fSLuigi Rizzo printf(" {"); 17799758b77fSLuigi Rizzo if (cmd->len & F_NOT) 17809758b77fSLuigi Rizzo printf(" not"); 17819758b77fSLuigi Rizzo proto = cmd->arg1; 1782d360073bSBrooks Davis pe = getprotobynumber(cmd->arg1); 178357cd6d26SMax Laier if ((flags & (HAVE_PROTO4 | HAVE_PROTO6)) && 178457cd6d26SMax Laier !(flags & HAVE_PROTO)) 178557cd6d26SMax Laier show_prerequisites(&flags, 178657cd6d26SMax Laier HAVE_IP | HAVE_OPTIONS, 0); 1787e706181bSLuigi Rizzo if (flags & HAVE_OPTIONS) 1788e706181bSLuigi Rizzo printf(" proto"); 17899758b77fSLuigi Rizzo if (pe) 17909758b77fSLuigi Rizzo printf(" %s", pe->p_name); 17919758b77fSLuigi Rizzo else 17929758b77fSLuigi Rizzo printf(" %u", cmd->arg1); 17939758b77fSLuigi Rizzo } 17949758b77fSLuigi Rizzo flags |= HAVE_PROTO; 17959758b77fSLuigi Rizzo break; 17969758b77fSLuigi Rizzo 17979758b77fSLuigi Rizzo default: /*options ... */ 179857cd6d26SMax Laier if (!(cmd->len & (F_OR|F_NOT))) 179957cd6d26SMax Laier if (((cmd->opcode == O_IP6) && 180057cd6d26SMax Laier (flags & HAVE_PROTO6)) || 180157cd6d26SMax Laier ((cmd->opcode == O_IP4) && 180257cd6d26SMax Laier (flags & HAVE_PROTO4))) 180357cd6d26SMax Laier break; 1804e706181bSLuigi Rizzo show_prerequisites(&flags, HAVE_IP | HAVE_OPTIONS, 0); 18059758b77fSLuigi Rizzo if ((cmd->len & F_OR) && !or_block) 18069758b77fSLuigi Rizzo printf(" {"); 18079758b77fSLuigi Rizzo if (cmd->len & F_NOT && cmd->opcode != O_IN) 18089758b77fSLuigi Rizzo printf(" not"); 18099758b77fSLuigi Rizzo switch(cmd->opcode) { 18105b41efddSMaxim Konovalov case O_MACADDR2: { 18115b41efddSMaxim Konovalov ipfw_insn_mac *m = (ipfw_insn_mac *)cmd; 18125b41efddSMaxim Konovalov 18135b41efddSMaxim Konovalov printf(" MAC"); 18145b41efddSMaxim Konovalov print_mac(m->addr, m->mask); 18155b41efddSMaxim Konovalov print_mac(m->addr + 6, m->mask + 6); 18165b41efddSMaxim Konovalov } 18175b41efddSMaxim Konovalov break; 18185b41efddSMaxim Konovalov 18195b41efddSMaxim Konovalov case O_MAC_TYPE: 18205b41efddSMaxim Konovalov print_newports((ipfw_insn_u16 *)cmd, 18215b41efddSMaxim Konovalov IPPROTO_ETHERTYPE, cmd->opcode); 18225b41efddSMaxim Konovalov break; 18235b41efddSMaxim Konovalov 18245b41efddSMaxim Konovalov 18259758b77fSLuigi Rizzo case O_FRAG: 18269758b77fSLuigi Rizzo printf(" frag"); 18279758b77fSLuigi Rizzo break; 18289758b77fSLuigi Rizzo 18298b07e49aSJulian Elischer case O_FIB: 18308b07e49aSJulian Elischer printf(" fib %u", cmd->arg1 ); 18318b07e49aSJulian Elischer break; 18328b07e49aSJulian Elischer 18339758b77fSLuigi Rizzo case O_IN: 18349758b77fSLuigi Rizzo printf(cmd->len & F_NOT ? " out" : " in"); 18359758b77fSLuigi Rizzo break; 18369758b77fSLuigi Rizzo 18376daf7ebdSBrian Feldman case O_DIVERTED: 18386daf7ebdSBrian Feldman switch (cmd->arg1) { 18396daf7ebdSBrian Feldman case 3: 18406daf7ebdSBrian Feldman printf(" diverted"); 18416daf7ebdSBrian Feldman break; 18426daf7ebdSBrian Feldman case 1: 18436daf7ebdSBrian Feldman printf(" diverted-loopback"); 18446daf7ebdSBrian Feldman break; 18456daf7ebdSBrian Feldman case 2: 18466daf7ebdSBrian Feldman printf(" diverted-output"); 18476daf7ebdSBrian Feldman break; 18486daf7ebdSBrian Feldman default: 18496daf7ebdSBrian Feldman printf(" diverted-?<%u>", cmd->arg1); 18506daf7ebdSBrian Feldman break; 18516daf7ebdSBrian Feldman } 18526daf7ebdSBrian Feldman break; 18536daf7ebdSBrian Feldman 18549758b77fSLuigi Rizzo case O_LAYER2: 18559758b77fSLuigi Rizzo printf(" layer2"); 18569758b77fSLuigi Rizzo break; 18579758b77fSLuigi Rizzo case O_XMIT: 18589758b77fSLuigi Rizzo case O_RECV: 1859bd528823SGleb Smirnoff case O_VIA: 1860bd528823SGleb Smirnoff { 186162ff38aeSLuigi Rizzo char const *s; 18629758b77fSLuigi Rizzo ipfw_insn_if *cmdif = (ipfw_insn_if *)cmd; 18639758b77fSLuigi Rizzo 18649758b77fSLuigi Rizzo if (cmd->opcode == O_XMIT) 18659758b77fSLuigi Rizzo s = "xmit"; 18669758b77fSLuigi Rizzo else if (cmd->opcode == O_RECV) 18679758b77fSLuigi Rizzo s = "recv"; 186862ff38aeSLuigi Rizzo else /* if (cmd->opcode == O_VIA) */ 18699758b77fSLuigi Rizzo s = "via"; 18709758b77fSLuigi Rizzo if (cmdif->name[0] == '\0') 18715e43aef8SLuigi Rizzo printf(" %s %s", s, 18725e43aef8SLuigi Rizzo inet_ntoa(cmdif->p.ip)); 1873bd528823SGleb Smirnoff else 18749bf40edeSBrooks Davis printf(" %s %s", s, cmdif->name); 18759758b77fSLuigi Rizzo 1876bd528823SGleb Smirnoff break; 1877bd528823SGleb Smirnoff } 18789758b77fSLuigi Rizzo case O_IPID: 187944c884e1SLuigi Rizzo if (F_LEN(cmd) == 1) 18809758b77fSLuigi Rizzo printf(" ipid %u", cmd->arg1 ); 188144c884e1SLuigi Rizzo else 188244c884e1SLuigi Rizzo print_newports((ipfw_insn_u16 *)cmd, 0, 188344c884e1SLuigi Rizzo O_IPID); 18849758b77fSLuigi Rizzo break; 18859758b77fSLuigi Rizzo 18869758b77fSLuigi Rizzo case O_IPTTL: 188744c884e1SLuigi Rizzo if (F_LEN(cmd) == 1) 18889758b77fSLuigi Rizzo printf(" ipttl %u", cmd->arg1 ); 188944c884e1SLuigi Rizzo else 189044c884e1SLuigi Rizzo print_newports((ipfw_insn_u16 *)cmd, 0, 189144c884e1SLuigi Rizzo O_IPTTL); 18929758b77fSLuigi Rizzo break; 18939758b77fSLuigi Rizzo 18949758b77fSLuigi Rizzo case O_IPVER: 18959758b77fSLuigi Rizzo printf(" ipver %u", cmd->arg1 ); 18969758b77fSLuigi Rizzo break; 18979758b77fSLuigi Rizzo 18985e43aef8SLuigi Rizzo case O_IPPRECEDENCE: 18995e43aef8SLuigi Rizzo printf(" ipprecedence %u", (cmd->arg1) >> 5 ); 19005e43aef8SLuigi Rizzo break; 19015e43aef8SLuigi Rizzo 19029758b77fSLuigi Rizzo case O_IPLEN: 190344c884e1SLuigi Rizzo if (F_LEN(cmd) == 1) 19049758b77fSLuigi Rizzo printf(" iplen %u", cmd->arg1 ); 190544c884e1SLuigi Rizzo else 190644c884e1SLuigi Rizzo print_newports((ipfw_insn_u16 *)cmd, 0, 190744c884e1SLuigi Rizzo O_IPLEN); 19089758b77fSLuigi Rizzo break; 19099758b77fSLuigi Rizzo 191052bc23abSLuigi Rizzo case O_IPOPT: 19119758b77fSLuigi Rizzo print_flags("ipoptions", cmd, f_ipopts); 19129758b77fSLuigi Rizzo break; 19139758b77fSLuigi Rizzo 19145e43aef8SLuigi Rizzo case O_IPTOS: 19155e43aef8SLuigi Rizzo print_flags("iptos", cmd, f_iptos); 19165e43aef8SLuigi Rizzo break; 19175e43aef8SLuigi Rizzo 19185e43aef8SLuigi Rizzo case O_ICMPTYPE: 19195e43aef8SLuigi Rizzo print_icmptypes((ipfw_insn_u32 *)cmd); 19205e43aef8SLuigi Rizzo break; 19215e43aef8SLuigi Rizzo 19229758b77fSLuigi Rizzo case O_ESTAB: 19239758b77fSLuigi Rizzo printf(" established"); 19249758b77fSLuigi Rizzo break; 19259758b77fSLuigi Rizzo 1926c99ee9e0SBrian Feldman case O_TCPDATALEN: 1927c99ee9e0SBrian Feldman if (F_LEN(cmd) == 1) 1928c99ee9e0SBrian Feldman printf(" tcpdatalen %u", cmd->arg1 ); 1929c99ee9e0SBrian Feldman else 1930c99ee9e0SBrian Feldman print_newports((ipfw_insn_u16 *)cmd, 0, 1931c99ee9e0SBrian Feldman O_TCPDATALEN); 1932c99ee9e0SBrian Feldman break; 1933c99ee9e0SBrian Feldman 19349758b77fSLuigi Rizzo case O_TCPFLAGS: 19359758b77fSLuigi Rizzo print_flags("tcpflags", cmd, f_tcpflags); 19369758b77fSLuigi Rizzo break; 19379758b77fSLuigi Rizzo 19389758b77fSLuigi Rizzo case O_TCPOPTS: 19399758b77fSLuigi Rizzo print_flags("tcpoptions", cmd, f_tcpopts); 19409758b77fSLuigi Rizzo break; 19419758b77fSLuigi Rizzo 19429758b77fSLuigi Rizzo case O_TCPWIN: 19439758b77fSLuigi Rizzo printf(" tcpwin %d", ntohs(cmd->arg1)); 19449758b77fSLuigi Rizzo break; 19459758b77fSLuigi Rizzo 19469758b77fSLuigi Rizzo case O_TCPACK: 19479758b77fSLuigi Rizzo printf(" tcpack %d", ntohl(cmd32->d[0])); 19489758b77fSLuigi Rizzo break; 19499758b77fSLuigi Rizzo 19509758b77fSLuigi Rizzo case O_TCPSEQ: 19519758b77fSLuigi Rizzo printf(" tcpseq %d", ntohl(cmd32->d[0])); 19529758b77fSLuigi Rizzo break; 19539758b77fSLuigi Rizzo 19549758b77fSLuigi Rizzo case O_UID: 19559758b77fSLuigi Rizzo { 19569758b77fSLuigi Rizzo struct passwd *pwd = getpwuid(cmd32->d[0]); 19579758b77fSLuigi Rizzo 19589758b77fSLuigi Rizzo if (pwd) 19599758b77fSLuigi Rizzo printf(" uid %s", pwd->pw_name); 19609758b77fSLuigi Rizzo else 19619758b77fSLuigi Rizzo printf(" uid %u", cmd32->d[0]); 19629758b77fSLuigi Rizzo } 19639758b77fSLuigi Rizzo break; 19649758b77fSLuigi Rizzo 19659758b77fSLuigi Rizzo case O_GID: 19669758b77fSLuigi Rizzo { 19679758b77fSLuigi Rizzo struct group *grp = getgrgid(cmd32->d[0]); 19689758b77fSLuigi Rizzo 19699758b77fSLuigi Rizzo if (grp) 19709758b77fSLuigi Rizzo printf(" gid %s", grp->gr_name); 19719758b77fSLuigi Rizzo else 19729758b77fSLuigi Rizzo printf(" gid %u", cmd32->d[0]); 19739758b77fSLuigi Rizzo } 19749758b77fSLuigi Rizzo break; 19759758b77fSLuigi Rizzo 197631c88a30SChristian S.J. Peron case O_JAIL: 197731c88a30SChristian S.J. Peron printf(" jail %d", cmd32->d[0]); 197831c88a30SChristian S.J. Peron break; 197931c88a30SChristian S.J. Peron 1980010dabb0SCrist J. Clark case O_VERREVPATH: 1981010dabb0SCrist J. Clark printf(" verrevpath"); 1982010dabb0SCrist J. Clark break; 1983010dabb0SCrist J. Clark 198422b5770bSAndre Oppermann case O_VERSRCREACH: 198522b5770bSAndre Oppermann printf(" versrcreach"); 198622b5770bSAndre Oppermann break; 198722b5770bSAndre Oppermann 19885f9541ecSAndre Oppermann case O_ANTISPOOF: 19895f9541ecSAndre Oppermann printf(" antispoof"); 19905f9541ecSAndre Oppermann break; 19915f9541ecSAndre Oppermann 1992c3e5b9f1SLuigi Rizzo case O_IPSEC: 1993c3e5b9f1SLuigi Rizzo printf(" ipsec"); 1994c3e5b9f1SLuigi Rizzo break; 1995c3e5b9f1SLuigi Rizzo 199662ff38aeSLuigi Rizzo case O_NOP: 1997bbc39c83SLuigi Rizzo comment = (char *)(cmd + 1); 199862ff38aeSLuigi Rizzo break; 199962ff38aeSLuigi Rizzo 20009758b77fSLuigi Rizzo case O_KEEP_STATE: 20019758b77fSLuigi Rizzo printf(" keep-state"); 20029758b77fSLuigi Rizzo break; 20039758b77fSLuigi Rizzo 2004254c4725SOleg Bulyzhin case O_LIMIT: { 20059758b77fSLuigi Rizzo struct _s_x *p = limit_masks; 20069758b77fSLuigi Rizzo ipfw_insn_limit *c = (ipfw_insn_limit *)cmd; 2007571f8c1bSLuigi Rizzo uint8_t x = c->limit_mask; 200862ff38aeSLuigi Rizzo char const *comma = " "; 20099758b77fSLuigi Rizzo 20109758b77fSLuigi Rizzo printf(" limit"); 20119758b77fSLuigi Rizzo for (; p->x != 0 ; p++) 20120a7197a8SLuigi Rizzo if ((x & p->x) == p->x) { 20139758b77fSLuigi Rizzo x &= ~p->x; 20149758b77fSLuigi Rizzo printf("%s%s", comma, p->s); 20159758b77fSLuigi Rizzo comma = ","; 20169758b77fSLuigi Rizzo } 2017254c4725SOleg Bulyzhin PRINT_UINT_ARG(" ", c->conn_limit); 20189758b77fSLuigi Rizzo break; 2019254c4725SOleg Bulyzhin } 20209758b77fSLuigi Rizzo 20218195404bSBrooks Davis case O_IP6: 202236c263ccSHajimu UMEMOTO printf(" ip6"); 20238195404bSBrooks Davis break; 20248195404bSBrooks Davis 202557cd6d26SMax Laier case O_IP4: 202636c263ccSHajimu UMEMOTO printf(" ip4"); 202757cd6d26SMax Laier break; 202857cd6d26SMax Laier 20298195404bSBrooks Davis case O_ICMP6TYPE: 20308195404bSBrooks Davis print_icmp6types((ipfw_insn_u32 *)cmd); 20318195404bSBrooks Davis break; 20328195404bSBrooks Davis 20338195404bSBrooks Davis case O_EXT_HDR: 20348195404bSBrooks Davis print_ext6hdr( (ipfw_insn *) cmd ); 20358195404bSBrooks Davis break; 20368195404bSBrooks Davis 20376a7d5cb6SOleg Bulyzhin case O_TAGGED: 20386a7d5cb6SOleg Bulyzhin if (F_LEN(cmd) == 1) 2039254c4725SOleg Bulyzhin PRINT_UINT_ARG(" tagged ", cmd->arg1); 20406a7d5cb6SOleg Bulyzhin else 20416a7d5cb6SOleg Bulyzhin print_newports((ipfw_insn_u16 *)cmd, 0, 20426a7d5cb6SOleg Bulyzhin O_TAGGED); 20436a7d5cb6SOleg Bulyzhin break; 20446a7d5cb6SOleg Bulyzhin 20459758b77fSLuigi Rizzo default: 20469758b77fSLuigi Rizzo printf(" [opcode %d len %d]", 20479758b77fSLuigi Rizzo cmd->opcode, cmd->len); 20489758b77fSLuigi Rizzo } 20499758b77fSLuigi Rizzo } 20509758b77fSLuigi Rizzo if (cmd->len & F_OR) { 20519758b77fSLuigi Rizzo printf(" or"); 20529758b77fSLuigi Rizzo or_block = 1; 20539758b77fSLuigi Rizzo } else if (or_block) { 20549758b77fSLuigi Rizzo printf(" }"); 20559758b77fSLuigi Rizzo or_block = 0; 20569758b77fSLuigi Rizzo } 20579758b77fSLuigi Rizzo } 2058e706181bSLuigi Rizzo show_prerequisites(&flags, HAVE_IP, 0); 2059bbc39c83SLuigi Rizzo if (comment) 2060bbc39c83SLuigi Rizzo printf(" // %s", comment); 20619758b77fSLuigi Rizzo printf("\n"); 20629758b77fSLuigi Rizzo } 20639758b77fSLuigi Rizzo 20649758b77fSLuigi Rizzo static void 206545f61351SMaxim Konovalov show_dyn_ipfw(ipfw_dyn_rule *d, int pcwidth, int bcwidth) 20669758b77fSLuigi Rizzo { 20679758b77fSLuigi Rizzo struct protoent *pe; 20689758b77fSLuigi Rizzo struct in_addr a; 2069330462a3SBernd Walter uint16_t rulenum; 207081bd0dc0SMax Laier char buf[INET6_ADDRSTRLEN]; 20719758b77fSLuigi Rizzo 20729758b77fSLuigi Rizzo if (!do_expired) { 20739758b77fSLuigi Rizzo if (!d->expire && !(d->dyn_type == O_LIMIT_PARENT)) 20749758b77fSLuigi Rizzo return; 20759758b77fSLuigi Rizzo } 2076330462a3SBernd Walter bcopy(&d->rule, &rulenum, sizeof(rulenum)); 2077571f8c1bSLuigi Rizzo printf("%05d", rulenum); 207862ff38aeSLuigi Rizzo if (pcwidth>0 || bcwidth>0) 2079571f8c1bSLuigi Rizzo printf(" %*llu %*llu (%ds)", pcwidth, 2080330462a3SBernd Walter align_uint64(&d->pcnt), bcwidth, 2081330462a3SBernd Walter align_uint64(&d->bcnt), d->expire); 20829758b77fSLuigi Rizzo switch (d->dyn_type) { 20839758b77fSLuigi Rizzo case O_LIMIT_PARENT: 20849758b77fSLuigi Rizzo printf(" PARENT %d", d->count); 20859758b77fSLuigi Rizzo break; 20869758b77fSLuigi Rizzo case O_LIMIT: 20879758b77fSLuigi Rizzo printf(" LIMIT"); 20889758b77fSLuigi Rizzo break; 20899758b77fSLuigi Rizzo case O_KEEP_STATE: /* bidir, no mask */ 20909758b77fSLuigi Rizzo printf(" STATE"); 20919758b77fSLuigi Rizzo break; 20929758b77fSLuigi Rizzo } 20939758b77fSLuigi Rizzo 20949758b77fSLuigi Rizzo if ((pe = getprotobynumber(d->id.proto)) != NULL) 20959758b77fSLuigi Rizzo printf(" %s", pe->p_name); 20969758b77fSLuigi Rizzo else 20979758b77fSLuigi Rizzo printf(" proto %u", d->id.proto); 20989758b77fSLuigi Rizzo 209981bd0dc0SMax Laier if (d->id.addr_type == 4) { 21009758b77fSLuigi Rizzo a.s_addr = htonl(d->id.src_ip); 21019758b77fSLuigi Rizzo printf(" %s %d", inet_ntoa(a), d->id.src_port); 21029758b77fSLuigi Rizzo 21039758b77fSLuigi Rizzo a.s_addr = htonl(d->id.dst_ip); 21049758b77fSLuigi Rizzo printf(" <-> %s %d", inet_ntoa(a), d->id.dst_port); 210581bd0dc0SMax Laier } else if (d->id.addr_type == 6) { 210681bd0dc0SMax Laier printf(" %s %d", inet_ntop(AF_INET6, &d->id.src_ip6, buf, 210781bd0dc0SMax Laier sizeof(buf)), d->id.src_port); 210881bd0dc0SMax Laier printf(" <-> %s %d", inet_ntop(AF_INET6, &d->id.dst_ip6, buf, 210981bd0dc0SMax Laier sizeof(buf)), d->id.dst_port); 211081bd0dc0SMax Laier } else 211181bd0dc0SMax Laier printf(" UNKNOWN <-> UNKNOWN\n"); 211281bd0dc0SMax Laier 21139758b77fSLuigi Rizzo printf("\n"); 21149758b77fSLuigi Rizzo } 21159758b77fSLuigi Rizzo 211662ff38aeSLuigi Rizzo static int 21179758b77fSLuigi Rizzo sort_q(const void *pa, const void *pb) 21189758b77fSLuigi Rizzo { 21199758b77fSLuigi Rizzo int rev = (do_sort < 0); 21209758b77fSLuigi Rizzo int field = rev ? -do_sort : do_sort; 21219758b77fSLuigi Rizzo long long res = 0; 21229758b77fSLuigi Rizzo const struct dn_flow_queue *a = pa; 21239758b77fSLuigi Rizzo const struct dn_flow_queue *b = pb; 21249758b77fSLuigi Rizzo 21259758b77fSLuigi Rizzo switch (field) { 21269758b77fSLuigi Rizzo case 1: /* pkts */ 21279758b77fSLuigi Rizzo res = a->len - b->len; 21289758b77fSLuigi Rizzo break; 21299758b77fSLuigi Rizzo case 2: /* bytes */ 21309758b77fSLuigi Rizzo res = a->len_bytes - b->len_bytes; 21319758b77fSLuigi Rizzo break; 21329758b77fSLuigi Rizzo 21339758b77fSLuigi Rizzo case 3: /* tot pkts */ 21349758b77fSLuigi Rizzo res = a->tot_pkts - b->tot_pkts; 21359758b77fSLuigi Rizzo break; 21369758b77fSLuigi Rizzo 21379758b77fSLuigi Rizzo case 4: /* tot bytes */ 21389758b77fSLuigi Rizzo res = a->tot_bytes - b->tot_bytes; 21399758b77fSLuigi Rizzo break; 21409758b77fSLuigi Rizzo } 21419758b77fSLuigi Rizzo if (res < 0) 21429758b77fSLuigi Rizzo res = -1; 21439758b77fSLuigi Rizzo if (res > 0) 21449758b77fSLuigi Rizzo res = 1; 21459758b77fSLuigi Rizzo return (int)(rev ? res : -res); 21469758b77fSLuigi Rizzo } 21479758b77fSLuigi Rizzo 21489758b77fSLuigi Rizzo static void 21499758b77fSLuigi Rizzo list_queues(struct dn_flow_set *fs, struct dn_flow_queue *q) 21509758b77fSLuigi Rizzo { 21519758b77fSLuigi Rizzo int l; 21528195404bSBrooks Davis int index_printed, indexes = 0; 21538195404bSBrooks Davis char buff[255]; 21548195404bSBrooks Davis struct protoent *pe; 21559758b77fSLuigi Rizzo 21569758b77fSLuigi Rizzo if (fs->rq_elements == 0) 21579758b77fSLuigi Rizzo return; 21589758b77fSLuigi Rizzo 21599758b77fSLuigi Rizzo if (do_sort != 0) 21609758b77fSLuigi Rizzo heapsort(q, fs->rq_elements, sizeof *q, sort_q); 21618195404bSBrooks Davis 21628195404bSBrooks Davis /* Print IPv4 flows */ 21638195404bSBrooks Davis index_printed = 0; 21649758b77fSLuigi Rizzo for (l = 0; l < fs->rq_elements; l++) { 21659758b77fSLuigi Rizzo struct in_addr ina; 21669758b77fSLuigi Rizzo 21678195404bSBrooks Davis /* XXX: Should check for IPv4 flows */ 21688195404bSBrooks Davis if (IS_IP6_FLOW_ID(&(q[l].id))) 21698195404bSBrooks Davis continue; 21708195404bSBrooks Davis 21718195404bSBrooks Davis if (!index_printed) { 21728195404bSBrooks Davis index_printed = 1; 21738195404bSBrooks Davis if (indexes > 0) /* currently a no-op */ 21748195404bSBrooks Davis printf("\n"); 21758195404bSBrooks Davis indexes++; 21768195404bSBrooks Davis printf(" " 21778195404bSBrooks Davis "mask: 0x%02x 0x%08x/0x%04x -> 0x%08x/0x%04x\n", 21788195404bSBrooks Davis fs->flow_mask.proto, 21798195404bSBrooks Davis fs->flow_mask.src_ip, fs->flow_mask.src_port, 21808195404bSBrooks Davis fs->flow_mask.dst_ip, fs->flow_mask.dst_port); 21818195404bSBrooks Davis 21828195404bSBrooks Davis printf("BKT Prot ___Source IP/port____ " 21838195404bSBrooks Davis "____Dest. IP/port____ " 21848195404bSBrooks Davis "Tot_pkt/bytes Pkt/Byte Drp\n"); 21858195404bSBrooks Davis } 21868195404bSBrooks Davis 21879758b77fSLuigi Rizzo printf("%3d ", q[l].hash_slot); 21889758b77fSLuigi Rizzo pe = getprotobynumber(q[l].id.proto); 21899758b77fSLuigi Rizzo if (pe) 21909758b77fSLuigi Rizzo printf("%-4s ", pe->p_name); 21919758b77fSLuigi Rizzo else 21929758b77fSLuigi Rizzo printf("%4u ", q[l].id.proto); 21938195404bSBrooks Davis ina.s_addr = htonl(q[l].id.src_ip); 21949758b77fSLuigi Rizzo printf("%15s/%-5d ", 21959758b77fSLuigi Rizzo inet_ntoa(ina), q[l].id.src_port); 21969758b77fSLuigi Rizzo ina.s_addr = htonl(q[l].id.dst_ip); 21979758b77fSLuigi Rizzo printf("%15s/%-5d ", 21989758b77fSLuigi Rizzo inet_ntoa(ina), q[l].id.dst_port); 21999758b77fSLuigi Rizzo printf("%4qu %8qu %2u %4u %3u\n", 22009758b77fSLuigi Rizzo q[l].tot_pkts, q[l].tot_bytes, 22019758b77fSLuigi Rizzo q[l].len, q[l].len_bytes, q[l].drops); 22029758b77fSLuigi Rizzo if (verbose) 22039758b77fSLuigi Rizzo printf(" S %20qd F %20qd\n", 22049758b77fSLuigi Rizzo q[l].S, q[l].F); 22059758b77fSLuigi Rizzo } 22068195404bSBrooks Davis 22078195404bSBrooks Davis /* Print IPv6 flows */ 22088195404bSBrooks Davis index_printed = 0; 22098195404bSBrooks Davis for (l = 0; l < fs->rq_elements; l++) { 22108195404bSBrooks Davis if (!IS_IP6_FLOW_ID(&(q[l].id))) 22118195404bSBrooks Davis continue; 22128195404bSBrooks Davis 22138195404bSBrooks Davis if (!index_printed) { 22148195404bSBrooks Davis index_printed = 1; 22158195404bSBrooks Davis if (indexes > 0) 22168195404bSBrooks Davis printf("\n"); 22178195404bSBrooks Davis indexes++; 22188195404bSBrooks Davis printf("\n mask: proto: 0x%02x, flow_id: 0x%08x, ", 22198195404bSBrooks Davis fs->flow_mask.proto, fs->flow_mask.flow_id6); 22208195404bSBrooks Davis inet_ntop(AF_INET6, &(fs->flow_mask.src_ip6), 22218195404bSBrooks Davis buff, sizeof(buff)); 22228195404bSBrooks Davis printf("%s/0x%04x -> ", buff, fs->flow_mask.src_port); 22238195404bSBrooks Davis inet_ntop( AF_INET6, &(fs->flow_mask.dst_ip6), 22248195404bSBrooks Davis buff, sizeof(buff) ); 22258195404bSBrooks Davis printf("%s/0x%04x\n", buff, fs->flow_mask.dst_port); 22268195404bSBrooks Davis 22278195404bSBrooks Davis printf("BKT ___Prot___ _flow-id_ " 22288195404bSBrooks Davis "______________Source IPv6/port_______________ " 22298195404bSBrooks Davis "_______________Dest. IPv6/port_______________ " 22308195404bSBrooks Davis "Tot_pkt/bytes Pkt/Byte Drp\n"); 22318195404bSBrooks Davis } 22328195404bSBrooks Davis printf("%3d ", q[l].hash_slot); 22338195404bSBrooks Davis pe = getprotobynumber(q[l].id.proto); 22348195404bSBrooks Davis if (pe != NULL) 22358195404bSBrooks Davis printf("%9s ", pe->p_name); 22368195404bSBrooks Davis else 22378195404bSBrooks Davis printf("%9u ", q[l].id.proto); 22388195404bSBrooks Davis printf("%7d %39s/%-5d ", q[l].id.flow_id6, 22398195404bSBrooks Davis inet_ntop(AF_INET6, &(q[l].id.src_ip6), buff, sizeof(buff)), 22408195404bSBrooks Davis q[l].id.src_port); 22418195404bSBrooks Davis printf(" %39s/%-5d ", 22428195404bSBrooks Davis inet_ntop(AF_INET6, &(q[l].id.dst_ip6), buff, sizeof(buff)), 22438195404bSBrooks Davis q[l].id.dst_port); 22448195404bSBrooks Davis printf(" %4qu %8qu %2u %4u %3u\n", 22458195404bSBrooks Davis q[l].tot_pkts, q[l].tot_bytes, 22468195404bSBrooks Davis q[l].len, q[l].len_bytes, q[l].drops); 22478195404bSBrooks Davis if (verbose) 22488195404bSBrooks Davis printf(" S %20qd F %20qd\n", q[l].S, q[l].F); 22498195404bSBrooks Davis } 22509758b77fSLuigi Rizzo } 22519758b77fSLuigi Rizzo 22529758b77fSLuigi Rizzo static void 22539758b77fSLuigi Rizzo print_flowset_parms(struct dn_flow_set *fs, char *prefix) 22549758b77fSLuigi Rizzo { 22559758b77fSLuigi Rizzo int l; 22569758b77fSLuigi Rizzo char qs[30]; 22579758b77fSLuigi Rizzo char plr[30]; 22589758b77fSLuigi Rizzo char red[90]; /* Display RED parameters */ 22599758b77fSLuigi Rizzo 22609758b77fSLuigi Rizzo l = fs->qsize; 22619758b77fSLuigi Rizzo if (fs->flags_fs & DN_QSIZE_IS_BYTES) { 22629758b77fSLuigi Rizzo if (l >= 8192) 22639758b77fSLuigi Rizzo sprintf(qs, "%d KB", l / 1024); 22649758b77fSLuigi Rizzo else 22659758b77fSLuigi Rizzo sprintf(qs, "%d B", l); 22669758b77fSLuigi Rizzo } else 22679758b77fSLuigi Rizzo sprintf(qs, "%3d sl.", l); 22689758b77fSLuigi Rizzo if (fs->plr) 22699758b77fSLuigi Rizzo sprintf(plr, "plr %f", 1.0 * fs->plr / (double)(0x7fffffff)); 22709758b77fSLuigi Rizzo else 22719758b77fSLuigi Rizzo plr[0] = '\0'; 22729758b77fSLuigi Rizzo if (fs->flags_fs & DN_IS_RED) /* RED parameters */ 22739758b77fSLuigi Rizzo sprintf(red, 22749758b77fSLuigi Rizzo "\n\t %cRED w_q %f min_th %d max_th %d max_p %f", 22759758b77fSLuigi Rizzo (fs->flags_fs & DN_IS_GENTLE_RED) ? 'G' : ' ', 22769758b77fSLuigi Rizzo 1.0 * fs->w_q / (double)(1 << SCALE_RED), 22779758b77fSLuigi Rizzo SCALE_VAL(fs->min_th), 22789758b77fSLuigi Rizzo SCALE_VAL(fs->max_th), 22799758b77fSLuigi Rizzo 1.0 * fs->max_p / (double)(1 << SCALE_RED)); 22809758b77fSLuigi Rizzo else 22819758b77fSLuigi Rizzo sprintf(red, "droptail"); 22829758b77fSLuigi Rizzo 22839758b77fSLuigi Rizzo printf("%s %s%s %d queues (%d buckets) %s\n", 22849758b77fSLuigi Rizzo prefix, qs, plr, fs->rq_elements, fs->rq_size, red); 22859758b77fSLuigi Rizzo } 22869758b77fSLuigi Rizzo 22879758b77fSLuigi Rizzo static void 228862ff38aeSLuigi Rizzo list_pipes(void *data, uint nbytes, int ac, char *av[]) 22899758b77fSLuigi Rizzo { 229062ff38aeSLuigi Rizzo int rulenum; 22919758b77fSLuigi Rizzo void *next = data; 22929758b77fSLuigi Rizzo struct dn_pipe *p = (struct dn_pipe *) data; 22939758b77fSLuigi Rizzo struct dn_flow_set *fs; 22949758b77fSLuigi Rizzo struct dn_flow_queue *q; 22959758b77fSLuigi Rizzo int l; 22969758b77fSLuigi Rizzo 22979758b77fSLuigi Rizzo if (ac > 0) 22989758b77fSLuigi Rizzo rulenum = strtoul(*av++, NULL, 10); 22999758b77fSLuigi Rizzo else 23009758b77fSLuigi Rizzo rulenum = 0; 23019758b77fSLuigi Rizzo for (; nbytes >= sizeof *p; p = (struct dn_pipe *)next) { 23029758b77fSLuigi Rizzo double b = p->bandwidth; 23039758b77fSLuigi Rizzo char buf[30]; 23049758b77fSLuigi Rizzo char prefix[80]; 23059758b77fSLuigi Rizzo 2306299652afSStefan Farfeleder if (SLIST_NEXT(p, next) != (struct dn_pipe *)DN_IS_PIPE) 23079758b77fSLuigi Rizzo break; /* done with pipes, now queues */ 23089758b77fSLuigi Rizzo 23099758b77fSLuigi Rizzo /* 23109758b77fSLuigi Rizzo * compute length, as pipe have variable size 23119758b77fSLuigi Rizzo */ 23129758b77fSLuigi Rizzo l = sizeof(*p) + p->fs.rq_elements * sizeof(*q); 231362ff38aeSLuigi Rizzo next = (char *)p + l; 23149758b77fSLuigi Rizzo nbytes -= l; 23159758b77fSLuigi Rizzo 2316c3d6fe74SPawel Jakub Dawidek if ((rulenum != 0 && rulenum != p->pipe_nr) || do_pipe == 2) 23179758b77fSLuigi Rizzo continue; 23189758b77fSLuigi Rizzo 23199758b77fSLuigi Rizzo /* 23209758b77fSLuigi Rizzo * Print rate (or clocking interface) 23219758b77fSLuigi Rizzo */ 23229758b77fSLuigi Rizzo if (p->if_name[0] != '\0') 23239758b77fSLuigi Rizzo sprintf(buf, "%s", p->if_name); 23249758b77fSLuigi Rizzo else if (b == 0) 23259758b77fSLuigi Rizzo sprintf(buf, "unlimited"); 23269758b77fSLuigi Rizzo else if (b >= 1000000) 23279758b77fSLuigi Rizzo sprintf(buf, "%7.3f Mbit/s", b/1000000); 23289758b77fSLuigi Rizzo else if (b >= 1000) 23299758b77fSLuigi Rizzo sprintf(buf, "%7.3f Kbit/s", b/1000); 23309758b77fSLuigi Rizzo else 23319758b77fSLuigi Rizzo sprintf(buf, "%7.3f bit/s ", b); 23329758b77fSLuigi Rizzo 23339758b77fSLuigi Rizzo sprintf(prefix, "%05d: %s %4d ms ", 23349758b77fSLuigi Rizzo p->pipe_nr, buf, p->delay); 23359758b77fSLuigi Rizzo print_flowset_parms(&(p->fs), prefix); 23369758b77fSLuigi Rizzo if (verbose) 23379758b77fSLuigi Rizzo printf(" V %20qd\n", p->V >> MY_M); 23389758b77fSLuigi Rizzo 23399758b77fSLuigi Rizzo q = (struct dn_flow_queue *)(p+1); 23409758b77fSLuigi Rizzo list_queues(&(p->fs), q); 23419758b77fSLuigi Rizzo } 23429758b77fSLuigi Rizzo for (fs = next; nbytes >= sizeof *fs; fs = next) { 23439758b77fSLuigi Rizzo char prefix[80]; 23449758b77fSLuigi Rizzo 2345299652afSStefan Farfeleder if (SLIST_NEXT(fs, next) != (struct dn_flow_set *)DN_IS_QUEUE) 23469758b77fSLuigi Rizzo break; 23479758b77fSLuigi Rizzo l = sizeof(*fs) + fs->rq_elements * sizeof(*q); 234862ff38aeSLuigi Rizzo next = (char *)fs + l; 23499758b77fSLuigi Rizzo nbytes -= l; 2350c3d6fe74SPawel Jakub Dawidek 2351c3d6fe74SPawel Jakub Dawidek if (rulenum != 0 && ((rulenum != fs->fs_nr && do_pipe == 2) || 2352c3d6fe74SPawel Jakub Dawidek (rulenum != fs->parent_nr && do_pipe == 1))) { 2353c3d6fe74SPawel Jakub Dawidek continue; 2354c3d6fe74SPawel Jakub Dawidek } 2355c3d6fe74SPawel Jakub Dawidek 23569758b77fSLuigi Rizzo q = (struct dn_flow_queue *)(fs+1); 23579758b77fSLuigi Rizzo sprintf(prefix, "q%05d: weight %d pipe %d ", 23589758b77fSLuigi Rizzo fs->fs_nr, fs->weight, fs->parent_nr); 23599758b77fSLuigi Rizzo print_flowset_parms(fs, prefix); 23609758b77fSLuigi Rizzo list_queues(fs, q); 23619758b77fSLuigi Rizzo } 23629758b77fSLuigi Rizzo } 23639758b77fSLuigi Rizzo 236499e5e645SLuigi Rizzo /* 236599e5e645SLuigi Rizzo * This one handles all set-related commands 236699e5e645SLuigi Rizzo * ipfw set { show | enable | disable } 236799e5e645SLuigi Rizzo * ipfw set swap X Y 236899e5e645SLuigi Rizzo * ipfw set move X to Y 236999e5e645SLuigi Rizzo * ipfw set move rule X to Y 237099e5e645SLuigi Rizzo */ 237199e5e645SLuigi Rizzo static void 237299e5e645SLuigi Rizzo sets_handler(int ac, char *av[]) 237399e5e645SLuigi Rizzo { 2374571f8c1bSLuigi Rizzo uint32_t set_disable, masks[2]; 237599e5e645SLuigi Rizzo int i, nbytes; 2376571f8c1bSLuigi Rizzo uint16_t rulenum; 2377571f8c1bSLuigi Rizzo uint8_t cmd, new_set; 237899e5e645SLuigi Rizzo 237999e5e645SLuigi Rizzo ac--; 238099e5e645SLuigi Rizzo av++; 238199e5e645SLuigi Rizzo 238299e5e645SLuigi Rizzo if (!ac) 238399e5e645SLuigi Rizzo errx(EX_USAGE, "set needs command"); 238401750186SBrooks Davis if (_substrcmp(*av, "show") == 0) { 238599e5e645SLuigi Rizzo void *data; 238662ff38aeSLuigi Rizzo char const *msg; 238799e5e645SLuigi Rizzo 238899e5e645SLuigi Rizzo nbytes = sizeof(struct ip_fw); 2389571f8c1bSLuigi Rizzo if ((data = calloc(1, nbytes)) == NULL) 2390571f8c1bSLuigi Rizzo err(EX_OSERR, "calloc"); 2391884be75cSThomas Moestl if (do_cmd(IP_FW_GET, data, (uintptr_t)&nbytes) < 0) 239299e5e645SLuigi Rizzo err(EX_OSERR, "getsockopt(IP_FW_GET)"); 2393330462a3SBernd Walter bcopy(&((struct ip_fw *)data)->next_rule, 2394330462a3SBernd Walter &set_disable, sizeof(set_disable)); 2395330462a3SBernd Walter 23963004afcaSLuigi Rizzo for (i = 0, msg = "disable" ; i < RESVD_SET; i++) 239799e5e645SLuigi Rizzo if ((set_disable & (1<<i))) { 239899e5e645SLuigi Rizzo printf("%s %d", msg, i); 239999e5e645SLuigi Rizzo msg = ""; 240099e5e645SLuigi Rizzo } 240199e5e645SLuigi Rizzo msg = (set_disable) ? " enable" : "enable"; 24023004afcaSLuigi Rizzo for (i = 0; i < RESVD_SET; i++) 240399e5e645SLuigi Rizzo if (!(set_disable & (1<<i))) { 240499e5e645SLuigi Rizzo printf("%s %d", msg, i); 240599e5e645SLuigi Rizzo msg = ""; 240699e5e645SLuigi Rizzo } 240799e5e645SLuigi Rizzo printf("\n"); 240801750186SBrooks Davis } else if (_substrcmp(*av, "swap") == 0) { 240999e5e645SLuigi Rizzo ac--; av++; 241099e5e645SLuigi Rizzo if (ac != 2) 241199e5e645SLuigi Rizzo errx(EX_USAGE, "set swap needs 2 set numbers\n"); 241299e5e645SLuigi Rizzo rulenum = atoi(av[0]); 241399e5e645SLuigi Rizzo new_set = atoi(av[1]); 24143004afcaSLuigi Rizzo if (!isdigit(*(av[0])) || rulenum > RESVD_SET) 241599e5e645SLuigi Rizzo errx(EX_DATAERR, "invalid set number %s\n", av[0]); 24163004afcaSLuigi Rizzo if (!isdigit(*(av[1])) || new_set > RESVD_SET) 241799e5e645SLuigi Rizzo errx(EX_DATAERR, "invalid set number %s\n", av[1]); 241899e5e645SLuigi Rizzo masks[0] = (4 << 24) | (new_set << 16) | (rulenum); 2419571f8c1bSLuigi Rizzo i = do_cmd(IP_FW_DEL, masks, sizeof(uint32_t)); 242001750186SBrooks Davis } else if (_substrcmp(*av, "move") == 0) { 242199e5e645SLuigi Rizzo ac--; av++; 242201750186SBrooks Davis if (ac && _substrcmp(*av, "rule") == 0) { 242399e5e645SLuigi Rizzo cmd = 2; 242499e5e645SLuigi Rizzo ac--; av++; 242599e5e645SLuigi Rizzo } else 242699e5e645SLuigi Rizzo cmd = 3; 242701750186SBrooks Davis if (ac != 3 || _substrcmp(av[1], "to") != 0) 242899e5e645SLuigi Rizzo errx(EX_USAGE, "syntax: set move [rule] X to Y\n"); 242999e5e645SLuigi Rizzo rulenum = atoi(av[0]); 243099e5e645SLuigi Rizzo new_set = atoi(av[2]); 24313004afcaSLuigi Rizzo if (!isdigit(*(av[0])) || (cmd == 3 && rulenum > RESVD_SET) || 243299e5e645SLuigi Rizzo (cmd == 2 && rulenum == 65535) ) 243399e5e645SLuigi Rizzo errx(EX_DATAERR, "invalid source number %s\n", av[0]); 24343004afcaSLuigi Rizzo if (!isdigit(*(av[2])) || new_set > RESVD_SET) 243599e5e645SLuigi Rizzo errx(EX_DATAERR, "invalid dest. set %s\n", av[1]); 243699e5e645SLuigi Rizzo masks[0] = (cmd << 24) | (new_set << 16) | (rulenum); 2437571f8c1bSLuigi Rizzo i = do_cmd(IP_FW_DEL, masks, sizeof(uint32_t)); 243801750186SBrooks Davis } else if (_substrcmp(*av, "disable") == 0 || 243901750186SBrooks Davis _substrcmp(*av, "enable") == 0 ) { 244001750186SBrooks Davis int which = _substrcmp(*av, "enable") == 0 ? 1 : 0; 244199e5e645SLuigi Rizzo 244299e5e645SLuigi Rizzo ac--; av++; 244399e5e645SLuigi Rizzo masks[0] = masks[1] = 0; 244499e5e645SLuigi Rizzo 244599e5e645SLuigi Rizzo while (ac) { 244699e5e645SLuigi Rizzo if (isdigit(**av)) { 244799e5e645SLuigi Rizzo i = atoi(*av); 24483004afcaSLuigi Rizzo if (i < 0 || i > RESVD_SET) 244999e5e645SLuigi Rizzo errx(EX_DATAERR, 245099e5e645SLuigi Rizzo "invalid set number %d\n", i); 245199e5e645SLuigi Rizzo masks[which] |= (1<<i); 245201750186SBrooks Davis } else if (_substrcmp(*av, "disable") == 0) 245399e5e645SLuigi Rizzo which = 0; 245401750186SBrooks Davis else if (_substrcmp(*av, "enable") == 0) 245599e5e645SLuigi Rizzo which = 1; 245699e5e645SLuigi Rizzo else 245799e5e645SLuigi Rizzo errx(EX_DATAERR, 245899e5e645SLuigi Rizzo "invalid set command %s\n", *av); 245999e5e645SLuigi Rizzo av++; ac--; 246099e5e645SLuigi Rizzo } 246199e5e645SLuigi Rizzo if ( (masks[0] & masks[1]) != 0 ) 246299e5e645SLuigi Rizzo errx(EX_DATAERR, 246399e5e645SLuigi Rizzo "cannot enable and disable the same set\n"); 246499e5e645SLuigi Rizzo 2465571f8c1bSLuigi Rizzo i = do_cmd(IP_FW_DEL, masks, sizeof(masks)); 246699e5e645SLuigi Rizzo if (i) 246799e5e645SLuigi Rizzo warn("set enable/disable: setsockopt(IP_FW_DEL)"); 246899e5e645SLuigi Rizzo } else 246999e5e645SLuigi Rizzo errx(EX_USAGE, "invalid set command %s\n", *av); 247099e5e645SLuigi Rizzo } 247199e5e645SLuigi Rizzo 24729758b77fSLuigi Rizzo static void 24736690be9eSMatthew Dillon sysctl_handler(int ac, char *av[], int which) 24746690be9eSMatthew Dillon { 24756690be9eSMatthew Dillon ac--; 24766690be9eSMatthew Dillon av++; 24776690be9eSMatthew Dillon 24781c56ad9bSMaxim Konovalov if (ac == 0) { 24796690be9eSMatthew Dillon warnx("missing keyword to enable/disable\n"); 248001750186SBrooks Davis } else if (_substrcmp(*av, "firewall") == 0) { 248129c1402aSLuigi Rizzo sysctlbyname("net.inet.ip.fw.enable", NULL, 0, 248229c1402aSLuigi Rizzo &which, sizeof(which)); 248301750186SBrooks Davis } else if (_substrcmp(*av, "one_pass") == 0) { 248429c1402aSLuigi Rizzo sysctlbyname("net.inet.ip.fw.one_pass", NULL, 0, 248529c1402aSLuigi Rizzo &which, sizeof(which)); 248601750186SBrooks Davis } else if (_substrcmp(*av, "debug") == 0) { 248729c1402aSLuigi Rizzo sysctlbyname("net.inet.ip.fw.debug", NULL, 0, 248829c1402aSLuigi Rizzo &which, sizeof(which)); 248901750186SBrooks Davis } else if (_substrcmp(*av, "verbose") == 0) { 249029c1402aSLuigi Rizzo sysctlbyname("net.inet.ip.fw.verbose", NULL, 0, 249129c1402aSLuigi Rizzo &which, sizeof(which)); 249201750186SBrooks Davis } else if (_substrcmp(*av, "dyn_keepalive") == 0) { 249329c1402aSLuigi Rizzo sysctlbyname("net.inet.ip.fw.dyn_keepalive", NULL, 0, 249429c1402aSLuigi Rizzo &which, sizeof(which)); 249501750186SBrooks Davis } else if (_substrcmp(*av, "altq") == 0) { 2496974dfe30SBrian Feldman altq_set_enabled(which); 24976690be9eSMatthew Dillon } else { 24986690be9eSMatthew Dillon warnx("unrecognize enable/disable keyword: %s\n", *av); 24996690be9eSMatthew Dillon } 25006690be9eSMatthew Dillon } 25016690be9eSMatthew Dillon 25026690be9eSMatthew Dillon static void 250362ff38aeSLuigi Rizzo list(int ac, char *av[], int show_counters) 25049758b77fSLuigi Rizzo { 25059758b77fSLuigi Rizzo struct ip_fw *r; 25069758b77fSLuigi Rizzo ipfw_dyn_rule *dynrules, *d; 25079758b77fSLuigi Rizzo 250862ff38aeSLuigi Rizzo #define NEXT(r) ((struct ip_fw *)((char *)r + RULESIZE(r))) 250962ff38aeSLuigi Rizzo char *lim; 251062ff38aeSLuigi Rizzo void *data = NULL; 251145f61351SMaxim Konovalov int bcwidth, n, nbytes, nstat, ndyn, pcwidth, width; 25129758b77fSLuigi Rizzo int exitval = EX_OK; 25139758b77fSLuigi Rizzo int lac; 25149758b77fSLuigi Rizzo char **lav; 251562ff38aeSLuigi Rizzo u_long rnum, last; 25169758b77fSLuigi Rizzo char *endptr; 25179758b77fSLuigi Rizzo int seen = 0; 2518d069a5d4SMaxim Konovalov uint8_t set; 25199758b77fSLuigi Rizzo 25209758b77fSLuigi Rizzo const int ocmd = do_pipe ? IP_DUMMYNET_GET : IP_FW_GET; 25219758b77fSLuigi Rizzo int nalloc = 1024; /* start somewhere... */ 25229758b77fSLuigi Rizzo 252300ed6609SMaxim Konovalov last = 0; 252400ed6609SMaxim Konovalov 2525571f8c1bSLuigi Rizzo if (test_only) { 2526571f8c1bSLuigi Rizzo fprintf(stderr, "Testing only, list disabled\n"); 2527571f8c1bSLuigi Rizzo return; 2528571f8c1bSLuigi Rizzo } 2529571f8c1bSLuigi Rizzo 25309758b77fSLuigi Rizzo ac--; 25319758b77fSLuigi Rizzo av++; 25329758b77fSLuigi Rizzo 25339758b77fSLuigi Rizzo /* get rules or pipes from kernel, resizing array as necessary */ 25349758b77fSLuigi Rizzo nbytes = nalloc; 25359758b77fSLuigi Rizzo 25369758b77fSLuigi Rizzo while (nbytes >= nalloc) { 25379758b77fSLuigi Rizzo nalloc = nalloc * 2 + 200; 25389758b77fSLuigi Rizzo nbytes = nalloc; 25399758b77fSLuigi Rizzo if ((data = realloc(data, nbytes)) == NULL) 25409758b77fSLuigi Rizzo err(EX_OSERR, "realloc"); 2541884be75cSThomas Moestl if (do_cmd(ocmd, data, (uintptr_t)&nbytes) < 0) 25429758b77fSLuigi Rizzo err(EX_OSERR, "getsockopt(IP_%s_GET)", 25439758b77fSLuigi Rizzo do_pipe ? "DUMMYNET" : "FW"); 25449758b77fSLuigi Rizzo } 25459758b77fSLuigi Rizzo 25469758b77fSLuigi Rizzo if (do_pipe) { 25479758b77fSLuigi Rizzo list_pipes(data, nbytes, ac, av); 25489758b77fSLuigi Rizzo goto done; 25499758b77fSLuigi Rizzo } 25509758b77fSLuigi Rizzo 25519758b77fSLuigi Rizzo /* 25529758b77fSLuigi Rizzo * Count static rules. They have variable size so we 25539758b77fSLuigi Rizzo * need to scan the list to count them. 25549758b77fSLuigi Rizzo */ 255562ff38aeSLuigi Rizzo for (nstat = 1, r = data, lim = (char *)data + nbytes; 255662ff38aeSLuigi Rizzo r->rulenum < 65535 && (char *)r < lim; 255762ff38aeSLuigi Rizzo ++nstat, r = NEXT(r) ) 25589758b77fSLuigi Rizzo ; /* nothing */ 25599758b77fSLuigi Rizzo 25609758b77fSLuigi Rizzo /* 25619758b77fSLuigi Rizzo * Count dynamic rules. This is easier as they have 25629758b77fSLuigi Rizzo * fixed size. 25639758b77fSLuigi Rizzo */ 256462ff38aeSLuigi Rizzo r = NEXT(r); 25659758b77fSLuigi Rizzo dynrules = (ipfw_dyn_rule *)r ; 256662ff38aeSLuigi Rizzo n = (char *)r - (char *)data; 25679758b77fSLuigi Rizzo ndyn = (nbytes - n) / sizeof *dynrules; 25689758b77fSLuigi Rizzo 256945f61351SMaxim Konovalov /* if showing stats, figure out column widths ahead of time */ 257045f61351SMaxim Konovalov bcwidth = pcwidth = 0; 257162ff38aeSLuigi Rizzo if (show_counters) { 257262ff38aeSLuigi Rizzo for (n = 0, r = data; n < nstat; n++, r = NEXT(r)) { 2573d069a5d4SMaxim Konovalov /* skip rules from another set */ 2574d069a5d4SMaxim Konovalov if (use_set && r->set != use_set - 1) 2575d069a5d4SMaxim Konovalov continue; 2576d069a5d4SMaxim Konovalov 257745f61351SMaxim Konovalov /* packet counter */ 2578330462a3SBernd Walter width = snprintf(NULL, 0, "%llu", 2579330462a3SBernd Walter align_uint64(&r->pcnt)); 258045f61351SMaxim Konovalov if (width > pcwidth) 258145f61351SMaxim Konovalov pcwidth = width; 258245f61351SMaxim Konovalov 258345f61351SMaxim Konovalov /* byte counter */ 2584330462a3SBernd Walter width = snprintf(NULL, 0, "%llu", 2585330462a3SBernd Walter align_uint64(&r->bcnt)); 258645f61351SMaxim Konovalov if (width > bcwidth) 258745f61351SMaxim Konovalov bcwidth = width; 258845f61351SMaxim Konovalov } 258945f61351SMaxim Konovalov } 259045f61351SMaxim Konovalov if (do_dynamic && ndyn) { 259145f61351SMaxim Konovalov for (n = 0, d = dynrules; n < ndyn; n++, d++) { 2592d069a5d4SMaxim Konovalov if (use_set) { 2593d069a5d4SMaxim Konovalov /* skip rules from another set */ 25944a296ec7SMaxim Konovalov bcopy((char *)&d->rule + sizeof(uint16_t), 2595d069a5d4SMaxim Konovalov &set, sizeof(uint8_t)); 2596d069a5d4SMaxim Konovalov if (set != use_set - 1) 2597d069a5d4SMaxim Konovalov continue; 2598d069a5d4SMaxim Konovalov } 2599330462a3SBernd Walter width = snprintf(NULL, 0, "%llu", 2600330462a3SBernd Walter align_uint64(&d->pcnt)); 260145f61351SMaxim Konovalov if (width > pcwidth) 260245f61351SMaxim Konovalov pcwidth = width; 260345f61351SMaxim Konovalov 2604330462a3SBernd Walter width = snprintf(NULL, 0, "%llu", 2605330462a3SBernd Walter align_uint64(&d->bcnt)); 260645f61351SMaxim Konovalov if (width > bcwidth) 260745f61351SMaxim Konovalov bcwidth = width; 260845f61351SMaxim Konovalov } 260945f61351SMaxim Konovalov } 26109758b77fSLuigi Rizzo /* if no rule numbers were specified, list all rules */ 26119758b77fSLuigi Rizzo if (ac == 0) { 2612d069a5d4SMaxim Konovalov for (n = 0, r = data; n < nstat; n++, r = NEXT(r)) { 2613d069a5d4SMaxim Konovalov if (use_set && r->set != use_set - 1) 2614d069a5d4SMaxim Konovalov continue; 261545f61351SMaxim Konovalov show_ipfw(r, pcwidth, bcwidth); 2616d069a5d4SMaxim Konovalov } 26179758b77fSLuigi Rizzo 26189758b77fSLuigi Rizzo if (do_dynamic && ndyn) { 26199758b77fSLuigi Rizzo printf("## Dynamic rules (%d):\n", ndyn); 2620d069a5d4SMaxim Konovalov for (n = 0, d = dynrules; n < ndyn; n++, d++) { 2621d069a5d4SMaxim Konovalov if (use_set) { 26224a296ec7SMaxim Konovalov bcopy((char *)&d->rule + sizeof(uint16_t), 2623d069a5d4SMaxim Konovalov &set, sizeof(uint8_t)); 2624d069a5d4SMaxim Konovalov if (set != use_set - 1) 2625d069a5d4SMaxim Konovalov continue; 2626d069a5d4SMaxim Konovalov } 262745f61351SMaxim Konovalov show_dyn_ipfw(d, pcwidth, bcwidth); 26289758b77fSLuigi Rizzo } 2629d069a5d4SMaxim Konovalov } 26309758b77fSLuigi Rizzo goto done; 26319758b77fSLuigi Rizzo } 26329758b77fSLuigi Rizzo 26339758b77fSLuigi Rizzo /* display specific rules requested on command line */ 26349758b77fSLuigi Rizzo 26359758b77fSLuigi Rizzo for (lac = ac, lav = av; lac != 0; lac--) { 26369758b77fSLuigi Rizzo /* convert command line rule # */ 263762ff38aeSLuigi Rizzo last = rnum = strtoul(*lav++, &endptr, 10); 263862ff38aeSLuigi Rizzo if (*endptr == '-') 263962ff38aeSLuigi Rizzo last = strtoul(endptr+1, &endptr, 10); 26409758b77fSLuigi Rizzo if (*endptr) { 26419758b77fSLuigi Rizzo exitval = EX_USAGE; 26429758b77fSLuigi Rizzo warnx("invalid rule number: %s", *(lav - 1)); 26439758b77fSLuigi Rizzo continue; 26449758b77fSLuigi Rizzo } 264562ff38aeSLuigi Rizzo for (n = seen = 0, r = data; n < nstat; n++, r = NEXT(r) ) { 264662ff38aeSLuigi Rizzo if (r->rulenum > last) 26479758b77fSLuigi Rizzo break; 2648d069a5d4SMaxim Konovalov if (use_set && r->set != use_set - 1) 2649d069a5d4SMaxim Konovalov continue; 265062ff38aeSLuigi Rizzo if (r->rulenum >= rnum && r->rulenum <= last) { 265145f61351SMaxim Konovalov show_ipfw(r, pcwidth, bcwidth); 26529758b77fSLuigi Rizzo seen = 1; 26539758b77fSLuigi Rizzo } 26549758b77fSLuigi Rizzo } 26559758b77fSLuigi Rizzo if (!seen) { 26569758b77fSLuigi Rizzo /* give precedence to other error(s) */ 26579758b77fSLuigi Rizzo if (exitval == EX_OK) 26589758b77fSLuigi Rizzo exitval = EX_UNAVAILABLE; 26599758b77fSLuigi Rizzo warnx("rule %lu does not exist", rnum); 26609758b77fSLuigi Rizzo } 26619758b77fSLuigi Rizzo } 26629758b77fSLuigi Rizzo 26639758b77fSLuigi Rizzo if (do_dynamic && ndyn) { 26649758b77fSLuigi Rizzo printf("## Dynamic rules:\n"); 26659758b77fSLuigi Rizzo for (lac = ac, lav = av; lac != 0; lac--) { 26668195404bSBrooks Davis last = rnum = strtoul(*lav++, &endptr, 10); 266762ff38aeSLuigi Rizzo if (*endptr == '-') 266862ff38aeSLuigi Rizzo last = strtoul(endptr+1, &endptr, 10); 26699758b77fSLuigi Rizzo if (*endptr) 26709758b77fSLuigi Rizzo /* already warned */ 26719758b77fSLuigi Rizzo continue; 26729758b77fSLuigi Rizzo for (n = 0, d = dynrules; n < ndyn; n++, d++) { 2673330462a3SBernd Walter uint16_t rulenum; 2674330462a3SBernd Walter 2675330462a3SBernd Walter bcopy(&d->rule, &rulenum, sizeof(rulenum)); 2676330462a3SBernd Walter if (rulenum > rnum) 26779758b77fSLuigi Rizzo break; 2678d069a5d4SMaxim Konovalov if (use_set) { 26794a296ec7SMaxim Konovalov bcopy((char *)&d->rule + sizeof(uint16_t), 2680d069a5d4SMaxim Konovalov &set, sizeof(uint8_t)); 2681d069a5d4SMaxim Konovalov if (set != use_set - 1) 2682d069a5d4SMaxim Konovalov continue; 2683d069a5d4SMaxim Konovalov } 268462ff38aeSLuigi Rizzo if (r->rulenum >= rnum && r->rulenum <= last) 268545f61351SMaxim Konovalov show_dyn_ipfw(d, pcwidth, bcwidth); 26869758b77fSLuigi Rizzo } 26879758b77fSLuigi Rizzo } 26889758b77fSLuigi Rizzo } 26899758b77fSLuigi Rizzo 26909758b77fSLuigi Rizzo ac = 0; 26919758b77fSLuigi Rizzo 26929758b77fSLuigi Rizzo done: 26939758b77fSLuigi Rizzo free(data); 26949758b77fSLuigi Rizzo 26959758b77fSLuigi Rizzo if (exitval != EX_OK) 26969758b77fSLuigi Rizzo exit(exitval); 269762ff38aeSLuigi Rizzo #undef NEXT 26989758b77fSLuigi Rizzo } 26999758b77fSLuigi Rizzo 27009758b77fSLuigi Rizzo static void 27019758b77fSLuigi Rizzo show_usage(void) 27029758b77fSLuigi Rizzo { 27039758b77fSLuigi Rizzo fprintf(stderr, "usage: ipfw [options]\n" 27049758b77fSLuigi Rizzo "do \"ipfw -h\" or see ipfw manpage for details\n" 27059758b77fSLuigi Rizzo ); 27069758b77fSLuigi Rizzo exit(EX_USAGE); 27079758b77fSLuigi Rizzo } 27089758b77fSLuigi Rizzo 27099758b77fSLuigi Rizzo static void 27109758b77fSLuigi Rizzo help(void) 27119758b77fSLuigi Rizzo { 2712571f8c1bSLuigi Rizzo fprintf(stderr, 2713571f8c1bSLuigi Rizzo "ipfw syntax summary (but please do read the ipfw(8) manpage):\n" 2714ac6cec51SLuigi Rizzo "ipfw [-abcdefhnNqStTv] <command> where <command> is one of:\n" 2715571f8c1bSLuigi Rizzo "add [num] [set N] [prob x] RULE-BODY\n" 2716571f8c1bSLuigi Rizzo "{pipe|queue} N config PIPE-BODY\n" 2717571f8c1bSLuigi Rizzo "[pipe|queue] {zero|delete|show} [N{,N}]\n" 2718ff2f6fe8SPaolo Pisati "nat N config {ip IPADDR|if IFNAME|log|deny_in|same_ports|unreg_only|reset|\n" 2719ff2f6fe8SPaolo Pisati " reverse|proxy_only|redirect_addr linkspec|\n" 2720ff2f6fe8SPaolo Pisati " redirect_port linkspec|redirect_proto linkspec}\n" 2721571f8c1bSLuigi Rizzo "set [disable N... enable N...] | move [rule] X to Y | swap X Y | show\n" 2722d069a5d4SMaxim Konovalov "set N {show|list|zero|resetlog|delete} [N{,N}] | flush\n" 2723cd8b5ae0SRuslan Ermilov "table N {add ip[/bits] [value] | delete ip[/bits] | flush | list}\n" 27249758b77fSLuigi Rizzo "\n" 2725974dfe30SBrian Feldman "RULE-BODY: check-state [PARAMS] | ACTION [PARAMS] ADDR [OPTION_LIST]\n" 27269066356bSBjoern A. Zeeb "ACTION: check-state | allow | count | deny | unreach{,6} CODE |\n" 27279066356bSBjoern A. Zeeb " skipto N | {divert|tee} PORT | forward ADDR |\n" 27288b07e49aSJulian Elischer " pipe N | queue N | nat N | setfib FIB\n" 2729974dfe30SBrian Feldman "PARAMS: [log [logamount LOGLIMIT]] [altq QUEUE_NAME]\n" 27309758b77fSLuigi Rizzo "ADDR: [ MAC dst src ether_type ] \n" 27318195404bSBrooks Davis " [ ip from IPADDR [ PORT ] to IPADDR [ PORTLIST ] ]\n" 27328195404bSBrooks Davis " [ ipv6|ip6 from IP6ADDR [ PORT ] to IP6ADDR [ PORTLIST ] ]\n" 2733cd8b5ae0SRuslan Ermilov "IPADDR: [not] { any | me | ip/bits{x,y,z} | table(t[,v]) | IPLIST }\n" 27348195404bSBrooks Davis "IP6ADDR: [not] { any | me | me6 | ip6/bits | IP6LIST }\n" 27358195404bSBrooks Davis "IP6LIST: { ip6 | ip6/bits }[,IP6LIST]\n" 273626bf4d78SLuigi Rizzo "IPLIST: { ip | ip/bits | ip:mask }[,IPLIST]\n" 273726bf4d78SLuigi Rizzo "OPTION_LIST: OPTION [OPTION_LIST]\n" 273817db1a04SBrian Feldman "OPTION: bridged | diverted | diverted-loopback | diverted-output |\n" 27398195404bSBrooks Davis " {dst-ip|src-ip} IPADDR | {dst-ip6|src-ip6|dst-ipv6|src-ipv6} IP6ADDR |\n" 27408195404bSBrooks Davis " {dst-port|src-port} LIST |\n" 2741571f8c1bSLuigi Rizzo " estab | frag | {gid|uid} N | icmptypes LIST | in | out | ipid LIST |\n" 2742571f8c1bSLuigi Rizzo " iplen LIST | ipoptions SPEC | ipprecedence | ipsec | iptos SPEC |\n" 2743571f8c1bSLuigi Rizzo " ipttl LIST | ipversion VER | keep-state | layer2 | limit ... |\n" 27448b07e49aSJulian Elischer " icmp6types LIST | ext6hdr LIST | flow-id N[,N] | fib FIB |\n" 2745571f8c1bSLuigi Rizzo " mac ... | mac-type LIST | proto LIST | {recv|xmit|via} {IF|IPADDR} |\n" 2746571f8c1bSLuigi Rizzo " setup | {tcpack|tcpseq|tcpwin} NN | tcpflags SPEC | tcpoptions SPEC |\n" 2747c99ee9e0SBrian Feldman " tcpdatalen LIST | verrevpath | versrcreach | antispoof\n" 27489758b77fSLuigi Rizzo ); 27499758b77fSLuigi Rizzo exit(0); 27509758b77fSLuigi Rizzo } 27519758b77fSLuigi Rizzo 27529758b77fSLuigi Rizzo 27539758b77fSLuigi Rizzo static int 27549758b77fSLuigi Rizzo lookup_host (char *host, struct in_addr *ipaddr) 27559758b77fSLuigi Rizzo { 27569758b77fSLuigi Rizzo struct hostent *he; 27579758b77fSLuigi Rizzo 27589758b77fSLuigi Rizzo if (!inet_aton(host, ipaddr)) { 27599758b77fSLuigi Rizzo if ((he = gethostbyname(host)) == NULL) 27609758b77fSLuigi Rizzo return(-1); 27619758b77fSLuigi Rizzo *ipaddr = *(struct in_addr *)he->h_addr_list[0]; 27629758b77fSLuigi Rizzo } 27639758b77fSLuigi Rizzo return(0); 27649758b77fSLuigi Rizzo } 27659758b77fSLuigi Rizzo 27669758b77fSLuigi Rizzo /* 27679758b77fSLuigi Rizzo * fills the addr and mask fields in the instruction as appropriate from av. 27689758b77fSLuigi Rizzo * Update length as appropriate. 27699758b77fSLuigi Rizzo * The following formats are allowed: 27709758b77fSLuigi Rizzo * me returns O_IP_*_ME 27719758b77fSLuigi Rizzo * 1.2.3.4 single IP address 27729758b77fSLuigi Rizzo * 1.2.3.4:5.6.7.8 address:mask 27739758b77fSLuigi Rizzo * 1.2.3.4/24 address/mask 27749758b77fSLuigi Rizzo * 1.2.3.4/26{1,6,5,4,23} set of addresses in a subnet 2775571f8c1bSLuigi Rizzo * We can have multiple comma-separated address/mask entries. 27769758b77fSLuigi Rizzo */ 27779758b77fSLuigi Rizzo static void 27789758b77fSLuigi Rizzo fill_ip(ipfw_insn_ip *cmd, char *av) 27799758b77fSLuigi Rizzo { 2780571f8c1bSLuigi Rizzo int len = 0; 2781571f8c1bSLuigi Rizzo uint32_t *d = ((ipfw_insn_u32 *)cmd)->d; 27829758b77fSLuigi Rizzo 27839758b77fSLuigi Rizzo cmd->o.len &= ~F_LEN_MASK; /* zero len */ 27849758b77fSLuigi Rizzo 278501750186SBrooks Davis if (_substrcmp(av, "any") == 0) 27869758b77fSLuigi Rizzo return; 27879758b77fSLuigi Rizzo 278801750186SBrooks Davis if (_substrcmp(av, "me") == 0) { 27899758b77fSLuigi Rizzo cmd->o.len |= F_INSN_SIZE(ipfw_insn); 27909758b77fSLuigi Rizzo return; 27919758b77fSLuigi Rizzo } 27929758b77fSLuigi Rizzo 279301750186SBrooks Davis if (strncmp(av, "table(", 6) == 0) { 2794cd8b5ae0SRuslan Ermilov char *p = strchr(av + 6, ','); 2795cd8b5ae0SRuslan Ermilov 2796cd8b5ae0SRuslan Ermilov if (p) 2797cd8b5ae0SRuslan Ermilov *p++ = '\0'; 2798cd8b5ae0SRuslan Ermilov cmd->o.opcode = O_IP_DST_LOOKUP; 2799cd8b5ae0SRuslan Ermilov cmd->o.arg1 = strtoul(av + 6, NULL, 0); 2800cd8b5ae0SRuslan Ermilov if (p) { 2801cd8b5ae0SRuslan Ermilov cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32); 2802cd8b5ae0SRuslan Ermilov d[0] = strtoul(p, NULL, 0); 2803cd8b5ae0SRuslan Ermilov } else 2804cd8b5ae0SRuslan Ermilov cmd->o.len |= F_INSN_SIZE(ipfw_insn); 2805cd8b5ae0SRuslan Ermilov return; 2806cd8b5ae0SRuslan Ermilov } 2807cd8b5ae0SRuslan Ermilov 2808571f8c1bSLuigi Rizzo while (av) { 2809571f8c1bSLuigi Rizzo /* 2810571f8c1bSLuigi Rizzo * After the address we can have '/' or ':' indicating a mask, 2811571f8c1bSLuigi Rizzo * ',' indicating another address follows, '{' indicating a 2812571f8c1bSLuigi Rizzo * set of addresses of unspecified size. 2813571f8c1bSLuigi Rizzo */ 2814c2221c35SMax Laier char *t = NULL, *p = strpbrk(av, "/:,{"); 2815571f8c1bSLuigi Rizzo int masklen; 2816c2221c35SMax Laier char md, nd; 2817571f8c1bSLuigi Rizzo 28189758b77fSLuigi Rizzo if (p) { 28199758b77fSLuigi Rizzo md = *p; 28209758b77fSLuigi Rizzo *p++ = '\0'; 2821c2221c35SMax Laier if ((t = strpbrk(p, ",{")) != NULL) { 2822c2221c35SMax Laier nd = *t; 2823c2221c35SMax Laier *t = '\0'; 2824c2221c35SMax Laier } 2825571f8c1bSLuigi Rizzo } else 2826571f8c1bSLuigi Rizzo md = '\0'; 28279758b77fSLuigi Rizzo 2828571f8c1bSLuigi Rizzo if (lookup_host(av, (struct in_addr *)&d[0]) != 0) 28299758b77fSLuigi Rizzo errx(EX_NOHOST, "hostname ``%s'' unknown", av); 28309758b77fSLuigi Rizzo switch (md) { 28319758b77fSLuigi Rizzo case ':': 2832571f8c1bSLuigi Rizzo if (!inet_aton(p, (struct in_addr *)&d[1])) 28339758b77fSLuigi Rizzo errx(EX_DATAERR, "bad netmask ``%s''", p); 28349758b77fSLuigi Rizzo break; 28359758b77fSLuigi Rizzo case '/': 2836571f8c1bSLuigi Rizzo masklen = atoi(p); 2837571f8c1bSLuigi Rizzo if (masklen == 0) 2838571f8c1bSLuigi Rizzo d[1] = htonl(0); /* mask */ 2839571f8c1bSLuigi Rizzo else if (masklen > 32) 28409758b77fSLuigi Rizzo errx(EX_DATAERR, "bad width ``%s''", p); 28419758b77fSLuigi Rizzo else 2842571f8c1bSLuigi Rizzo d[1] = htonl(~0 << (32 - masklen)); 28439758b77fSLuigi Rizzo break; 2844571f8c1bSLuigi Rizzo case '{': /* no mask, assume /24 and put back the '{' */ 2845571f8c1bSLuigi Rizzo d[1] = htonl(~0 << (32 - 24)); 2846571f8c1bSLuigi Rizzo *(--p) = md; 2847571f8c1bSLuigi Rizzo break; 2848571f8c1bSLuigi Rizzo 2849571f8c1bSLuigi Rizzo case ',': /* single address plus continuation */ 2850571f8c1bSLuigi Rizzo *(--p) = md; 2851571f8c1bSLuigi Rizzo /* FALLTHROUGH */ 2852571f8c1bSLuigi Rizzo case 0: /* initialization value */ 28539758b77fSLuigi Rizzo default: 2854571f8c1bSLuigi Rizzo d[1] = htonl(~0); /* force /32 */ 28559758b77fSLuigi Rizzo break; 28569758b77fSLuigi Rizzo } 2857571f8c1bSLuigi Rizzo d[0] &= d[1]; /* mask base address with mask */ 2858c2221c35SMax Laier if (t) 2859c2221c35SMax Laier *t = nd; 2860571f8c1bSLuigi Rizzo /* find next separator */ 2861571f8c1bSLuigi Rizzo if (p) 2862571f8c1bSLuigi Rizzo p = strpbrk(p, ",{"); 2863571f8c1bSLuigi Rizzo if (p && *p == '{') { 28649758b77fSLuigi Rizzo /* 2865571f8c1bSLuigi Rizzo * We have a set of addresses. They are stored as follows: 28669758b77fSLuigi Rizzo * arg1 is the set size (powers of 2, 2..256) 28679758b77fSLuigi Rizzo * addr is the base address IN HOST FORMAT 2868571f8c1bSLuigi Rizzo * mask.. is an array of arg1 bits (rounded up to 2869571f8c1bSLuigi Rizzo * the next multiple of 32) with bits set 2870571f8c1bSLuigi Rizzo * for each host in the map. 28719758b77fSLuigi Rizzo */ 2872571f8c1bSLuigi Rizzo uint32_t *map = (uint32_t *)&cmd->mask; 28739758b77fSLuigi Rizzo int low, high; 2874f3a126d3SLuigi Rizzo int i = contigmask((uint8_t *)&(d[1]), 32); 28759758b77fSLuigi Rizzo 2876571f8c1bSLuigi Rizzo if (len > 0) 2877571f8c1bSLuigi Rizzo errx(EX_DATAERR, "address set cannot be in a list"); 2878571f8c1bSLuigi Rizzo if (i < 24 || i > 31) 2879571f8c1bSLuigi Rizzo errx(EX_DATAERR, "invalid set with mask %d\n", i); 2880571f8c1bSLuigi Rizzo cmd->o.arg1 = 1<<(32-i); /* map length */ 2881571f8c1bSLuigi Rizzo d[0] = ntohl(d[0]); /* base addr in host format */ 28829758b77fSLuigi Rizzo cmd->o.opcode = O_IP_DST_SET; /* default */ 28839758b77fSLuigi Rizzo cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32) + (cmd->o.arg1+31)/32; 288461360012SLuigi Rizzo for (i = 0; i < (cmd->o.arg1+31)/32 ; i++) 2885571f8c1bSLuigi Rizzo map[i] = 0; /* clear map */ 28869758b77fSLuigi Rizzo 28879758b77fSLuigi Rizzo av = p + 1; 2888571f8c1bSLuigi Rizzo low = d[0] & 0xff; 28899758b77fSLuigi Rizzo high = low + cmd->o.arg1 - 1; 2890571f8c1bSLuigi Rizzo /* 2891571f8c1bSLuigi Rizzo * Here, i stores the previous value when we specify a range 2892571f8c1bSLuigi Rizzo * of addresses within a mask, e.g. 45-63. i = -1 means we 2893571f8c1bSLuigi Rizzo * have no previous value. 2894571f8c1bSLuigi Rizzo */ 28959ef3f16dSLuigi Rizzo i = -1; /* previous value in a range */ 28969758b77fSLuigi Rizzo while (isdigit(*av)) { 28979758b77fSLuigi Rizzo char *s; 2898571f8c1bSLuigi Rizzo int a = strtol(av, &s, 0); 28999758b77fSLuigi Rizzo 2900571f8c1bSLuigi Rizzo if (s == av) { /* no parameter */ 2901571f8c1bSLuigi Rizzo if (*av != '}') 2902571f8c1bSLuigi Rizzo errx(EX_DATAERR, "set not closed\n"); 2903571f8c1bSLuigi Rizzo if (i != -1) 2904571f8c1bSLuigi Rizzo errx(EX_DATAERR, "incomplete range %d-", i); 29059758b77fSLuigi Rizzo break; 29069758b77fSLuigi Rizzo } 2907571f8c1bSLuigi Rizzo if (a < low || a > high) 2908571f8c1bSLuigi Rizzo errx(EX_DATAERR, "addr %d out of range [%d-%d]\n", 2909571f8c1bSLuigi Rizzo a, low, high); 29109758b77fSLuigi Rizzo a -= low; 29119ef3f16dSLuigi Rizzo if (i == -1) /* no previous in range */ 29129ef3f16dSLuigi Rizzo i = a; 29139ef3f16dSLuigi Rizzo else { /* check that range is valid */ 29149ef3f16dSLuigi Rizzo if (i > a) 29159ef3f16dSLuigi Rizzo errx(EX_DATAERR, "invalid range %d-%d", 29169ef3f16dSLuigi Rizzo i+low, a+low); 29179ef3f16dSLuigi Rizzo if (*s == '-') 29189ef3f16dSLuigi Rizzo errx(EX_DATAERR, "double '-' in range"); 29199ef3f16dSLuigi Rizzo } 29209ef3f16dSLuigi Rizzo for (; i <= a; i++) 2921571f8c1bSLuigi Rizzo map[i/32] |= 1<<(i & 31); 29229ef3f16dSLuigi Rizzo i = -1; 29239ef3f16dSLuigi Rizzo if (*s == '-') 29249ef3f16dSLuigi Rizzo i = a; 2925571f8c1bSLuigi Rizzo else if (*s == '}') 29269758b77fSLuigi Rizzo break; 29279758b77fSLuigi Rizzo av = s+1; 29289758b77fSLuigi Rizzo } 29299758b77fSLuigi Rizzo return; 29309758b77fSLuigi Rizzo } 2931571f8c1bSLuigi Rizzo av = p; 2932571f8c1bSLuigi Rizzo if (av) /* then *av must be a ',' */ 2933571f8c1bSLuigi Rizzo av++; 29349758b77fSLuigi Rizzo 2935571f8c1bSLuigi Rizzo /* Check this entry */ 2936571f8c1bSLuigi Rizzo if (d[1] == 0) { /* "any", specified as x.x.x.x/0 */ 2937571f8c1bSLuigi Rizzo /* 2938571f8c1bSLuigi Rizzo * 'any' turns the entire list into a NOP. 2939571f8c1bSLuigi Rizzo * 'not any' never matches, so it is removed from the 2940571f8c1bSLuigi Rizzo * list unless it is the only item, in which case we 2941571f8c1bSLuigi Rizzo * report an error. 2942571f8c1bSLuigi Rizzo */ 2943571f8c1bSLuigi Rizzo if (cmd->o.len & F_NOT) { /* "not any" never matches */ 2944571f8c1bSLuigi Rizzo if (av == NULL && len == 0) /* only this entry */ 29459758b77fSLuigi Rizzo errx(EX_DATAERR, "not any never matches"); 2946571f8c1bSLuigi Rizzo } 2947571f8c1bSLuigi Rizzo /* else do nothing and skip this entry */ 294814533a98SMaxim Konovalov return; 2949571f8c1bSLuigi Rizzo } 2950571f8c1bSLuigi Rizzo /* A single IP can be stored in an optimized format */ 2951571f8c1bSLuigi Rizzo if (d[1] == IP_MASK_ALL && av == NULL && len == 0) { 29529758b77fSLuigi Rizzo cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32); 2953571f8c1bSLuigi Rizzo return; 2954571f8c1bSLuigi Rizzo } 2955571f8c1bSLuigi Rizzo len += 2; /* two words... */ 2956571f8c1bSLuigi Rizzo d += 2; 2957571f8c1bSLuigi Rizzo } /* end while */ 2958268f526cSJohn Hay if (len + 1 > F_LEN_MASK) 2959268f526cSJohn Hay errx(EX_DATAERR, "address list too long"); 2960571f8c1bSLuigi Rizzo cmd->o.len |= len+1; 29619758b77fSLuigi Rizzo } 29629758b77fSLuigi Rizzo 29639758b77fSLuigi Rizzo 29648195404bSBrooks Davis /* Try to find ipv6 address by hostname */ 29658195404bSBrooks Davis static int 29668195404bSBrooks Davis lookup_host6 (char *host, struct in6_addr *ip6addr) 29678195404bSBrooks Davis { 29688195404bSBrooks Davis struct hostent *he; 29698195404bSBrooks Davis 29708195404bSBrooks Davis if (!inet_pton(AF_INET6, host, ip6addr)) { 29718195404bSBrooks Davis if ((he = gethostbyname2(host, AF_INET6)) == NULL) 29728195404bSBrooks Davis return(-1); 29738195404bSBrooks Davis memcpy(ip6addr, he->h_addr_list[0], sizeof( struct in6_addr)); 29748195404bSBrooks Davis } 29758195404bSBrooks Davis return(0); 29768195404bSBrooks Davis } 29778195404bSBrooks Davis 29788195404bSBrooks Davis 29798195404bSBrooks Davis /* n2mask sets n bits of the mask */ 29808195404bSBrooks Davis static void 29818195404bSBrooks Davis n2mask(struct in6_addr *mask, int n) 29828195404bSBrooks Davis { 29838195404bSBrooks Davis static int minimask[9] = 29848195404bSBrooks Davis { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff }; 29858195404bSBrooks Davis u_char *p; 29868195404bSBrooks Davis 29878195404bSBrooks Davis memset(mask, 0, sizeof(struct in6_addr)); 29888195404bSBrooks Davis p = (u_char *) mask; 29898195404bSBrooks Davis for (; n > 0; p++, n -= 8) { 29908195404bSBrooks Davis if (n >= 8) 29918195404bSBrooks Davis *p = 0xff; 29928195404bSBrooks Davis else 29938195404bSBrooks Davis *p = minimask[n]; 29948195404bSBrooks Davis } 29958195404bSBrooks Davis return; 29968195404bSBrooks Davis } 29978195404bSBrooks Davis 29988195404bSBrooks Davis 29998195404bSBrooks Davis /* 30008195404bSBrooks Davis * fill the addr and mask fields in the instruction as appropriate from av. 30018195404bSBrooks Davis * Update length as appropriate. 30028195404bSBrooks Davis * The following formats are allowed: 30038195404bSBrooks Davis * any matches any IP6. Actually returns an empty instruction. 30048195404bSBrooks Davis * me returns O_IP6_*_ME 30058195404bSBrooks Davis * 30068195404bSBrooks Davis * 03f1::234:123:0342 single IP6 addres 30078195404bSBrooks Davis * 03f1::234:123:0342/24 address/mask 30088195404bSBrooks Davis * 03f1::234:123:0342/24,03f1::234:123:0343/ List of address 30098195404bSBrooks Davis * 30108195404bSBrooks Davis * Set of address (as in ipv6) not supported because ipv6 address 30118195404bSBrooks Davis * are typically random past the initial prefix. 30128195404bSBrooks Davis * Return 1 on success, 0 on failure. 30138195404bSBrooks Davis */ 30148195404bSBrooks Davis static int 30158195404bSBrooks Davis fill_ip6(ipfw_insn_ip6 *cmd, char *av) 30168195404bSBrooks Davis { 30178195404bSBrooks Davis int len = 0; 30188195404bSBrooks Davis struct in6_addr *d = &(cmd->addr6); 30198195404bSBrooks Davis /* 30208195404bSBrooks Davis * Needed for multiple address. 30218195404bSBrooks Davis * Note d[1] points to struct in6_add r mask6 of cmd 30228195404bSBrooks Davis */ 30238195404bSBrooks Davis 30248195404bSBrooks Davis cmd->o.len &= ~F_LEN_MASK; /* zero len */ 30258195404bSBrooks Davis 30268195404bSBrooks Davis if (strcmp(av, "any") == 0) 30278195404bSBrooks Davis return (1); 30288195404bSBrooks Davis 30298195404bSBrooks Davis 30308195404bSBrooks Davis if (strcmp(av, "me") == 0) { /* Set the data for "me" opt*/ 30318195404bSBrooks Davis cmd->o.len |= F_INSN_SIZE(ipfw_insn); 30328195404bSBrooks Davis return (1); 30338195404bSBrooks Davis } 30348195404bSBrooks Davis 30358195404bSBrooks Davis if (strcmp(av, "me6") == 0) { /* Set the data for "me" opt*/ 30368195404bSBrooks Davis cmd->o.len |= F_INSN_SIZE(ipfw_insn); 30378195404bSBrooks Davis return (1); 30388195404bSBrooks Davis } 30398195404bSBrooks Davis 30408195404bSBrooks Davis av = strdup(av); 30418195404bSBrooks Davis while (av) { 30428195404bSBrooks Davis /* 30438195404bSBrooks Davis * After the address we can have '/' indicating a mask, 30448195404bSBrooks Davis * or ',' indicating another address follows. 30458195404bSBrooks Davis */ 30468195404bSBrooks Davis 30478195404bSBrooks Davis char *p; 30488195404bSBrooks Davis int masklen; 30498195404bSBrooks Davis char md = '\0'; 30508195404bSBrooks Davis 30518195404bSBrooks Davis if ((p = strpbrk(av, "/,")) ) { 30528195404bSBrooks Davis md = *p; /* save the separator */ 30538195404bSBrooks Davis *p = '\0'; /* terminate address string */ 30548195404bSBrooks Davis p++; /* and skip past it */ 30558195404bSBrooks Davis } 30568195404bSBrooks Davis /* now p points to NULL, mask or next entry */ 30578195404bSBrooks Davis 30588195404bSBrooks Davis /* lookup stores address in *d as a side effect */ 30598195404bSBrooks Davis if (lookup_host6(av, d) != 0) { 30608195404bSBrooks Davis /* XXX: failed. Free memory and go */ 30618195404bSBrooks Davis errx(EX_DATAERR, "bad address \"%s\"", av); 30628195404bSBrooks Davis } 30638195404bSBrooks Davis /* next, look at the mask, if any */ 30648195404bSBrooks Davis masklen = (md == '/') ? atoi(p) : 128; 30658195404bSBrooks Davis if (masklen > 128 || masklen < 0) 30668195404bSBrooks Davis errx(EX_DATAERR, "bad width \"%s\''", p); 30678195404bSBrooks Davis else 30688195404bSBrooks Davis n2mask(&d[1], masklen); 30698195404bSBrooks Davis 30708195404bSBrooks Davis APPLY_MASK(d, &d[1]) /* mask base address with mask */ 30718195404bSBrooks Davis 30728195404bSBrooks Davis /* find next separator */ 30738195404bSBrooks Davis 30748195404bSBrooks Davis if (md == '/') { /* find separator past the mask */ 30758195404bSBrooks Davis p = strpbrk(p, ","); 30768195404bSBrooks Davis if (p != NULL) 30778195404bSBrooks Davis p++; 30788195404bSBrooks Davis } 30798195404bSBrooks Davis av = p; 30808195404bSBrooks Davis 30818195404bSBrooks Davis /* Check this entry */ 30828195404bSBrooks Davis if (masklen == 0) { 30838195404bSBrooks Davis /* 30848195404bSBrooks Davis * 'any' turns the entire list into a NOP. 30858195404bSBrooks Davis * 'not any' never matches, so it is removed from the 30868195404bSBrooks Davis * list unless it is the only item, in which case we 30878195404bSBrooks Davis * report an error. 30888195404bSBrooks Davis */ 30898195404bSBrooks Davis if (cmd->o.len & F_NOT && av == NULL && len == 0) 30908195404bSBrooks Davis errx(EX_DATAERR, "not any never matches"); 30918195404bSBrooks Davis continue; 30928195404bSBrooks Davis } 30938195404bSBrooks Davis 30948195404bSBrooks Davis /* 30958195404bSBrooks Davis * A single IP can be stored alone 30968195404bSBrooks Davis */ 30978195404bSBrooks Davis if (masklen == 128 && av == NULL && len == 0) { 30988195404bSBrooks Davis len = F_INSN_SIZE(struct in6_addr); 30998195404bSBrooks Davis break; 31008195404bSBrooks Davis } 31018195404bSBrooks Davis 31028195404bSBrooks Davis /* Update length and pointer to arguments */ 31038195404bSBrooks Davis len += F_INSN_SIZE(struct in6_addr)*2; 31048195404bSBrooks Davis d += 2; 31058195404bSBrooks Davis } /* end while */ 31068195404bSBrooks Davis 31078195404bSBrooks Davis /* 31088195404bSBrooks Davis * Total length of the command, remember that 1 is the size of 31098195404bSBrooks Davis * the base command. 31108195404bSBrooks Davis */ 3111268f526cSJohn Hay if (len + 1 > F_LEN_MASK) 3112268f526cSJohn Hay errx(EX_DATAERR, "address list too long"); 31138195404bSBrooks Davis cmd->o.len |= len+1; 31148195404bSBrooks Davis free(av); 31158195404bSBrooks Davis return (1); 31168195404bSBrooks Davis } 31178195404bSBrooks Davis 31188195404bSBrooks Davis /* 31198195404bSBrooks Davis * fills command for ipv6 flow-id filtering 31208195404bSBrooks Davis * note that the 20 bit flow number is stored in a array of u_int32_t 31218195404bSBrooks Davis * it's supported lists of flow-id, so in the o.arg1 we store how many 31228195404bSBrooks Davis * additional flow-id we want to filter, the basic is 1 31238195404bSBrooks Davis */ 31248195404bSBrooks Davis void 31258195404bSBrooks Davis fill_flow6( ipfw_insn_u32 *cmd, char *av ) 31268195404bSBrooks Davis { 31278195404bSBrooks Davis u_int32_t type; /* Current flow number */ 31288195404bSBrooks Davis u_int16_t nflow = 0; /* Current flow index */ 31298195404bSBrooks Davis char *s = av; 31308195404bSBrooks Davis cmd->d[0] = 0; /* Initializing the base number*/ 31318195404bSBrooks Davis 31328195404bSBrooks Davis while (s) { 31338195404bSBrooks Davis av = strsep( &s, ",") ; 31348195404bSBrooks Davis type = strtoul(av, &av, 0); 31358195404bSBrooks Davis if (*av != ',' && *av != '\0') 31368195404bSBrooks Davis errx(EX_DATAERR, "invalid ipv6 flow number %s", av); 31378195404bSBrooks Davis if (type > 0xfffff) 31388195404bSBrooks Davis errx(EX_DATAERR, "flow number out of range %s", av); 31398195404bSBrooks Davis cmd->d[nflow] |= type; 31408195404bSBrooks Davis nflow++; 31418195404bSBrooks Davis } 31428195404bSBrooks Davis if( nflow > 0 ) { 31438195404bSBrooks Davis cmd->o.opcode = O_FLOW6ID; 31448195404bSBrooks Davis cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32) + nflow; 31458195404bSBrooks Davis cmd->o.arg1 = nflow; 31468195404bSBrooks Davis } 31478195404bSBrooks Davis else { 31488195404bSBrooks Davis errx(EX_DATAERR, "invalid ipv6 flow number %s", av); 31498195404bSBrooks Davis } 31508195404bSBrooks Davis } 31518195404bSBrooks Davis 31528195404bSBrooks Davis static ipfw_insn * 31538195404bSBrooks Davis add_srcip6(ipfw_insn *cmd, char *av) 31548195404bSBrooks Davis { 31558195404bSBrooks Davis 31568195404bSBrooks Davis fill_ip6((ipfw_insn_ip6 *)cmd, av); 31578195404bSBrooks Davis if (F_LEN(cmd) == 0) /* any */ 31588195404bSBrooks Davis ; 31598195404bSBrooks Davis if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) { /* "me" */ 31608195404bSBrooks Davis cmd->opcode = O_IP6_SRC_ME; 31618195404bSBrooks Davis } else if (F_LEN(cmd) == 31628195404bSBrooks Davis (F_INSN_SIZE(struct in6_addr) + F_INSN_SIZE(ipfw_insn))) { 31638195404bSBrooks Davis /* single IP, no mask*/ 31648195404bSBrooks Davis cmd->opcode = O_IP6_SRC; 31658195404bSBrooks Davis } else { /* addr/mask opt */ 31668195404bSBrooks Davis cmd->opcode = O_IP6_SRC_MASK; 31678195404bSBrooks Davis } 31688195404bSBrooks Davis return cmd; 31698195404bSBrooks Davis } 31708195404bSBrooks Davis 31718195404bSBrooks Davis static ipfw_insn * 31728195404bSBrooks Davis add_dstip6(ipfw_insn *cmd, char *av) 31738195404bSBrooks Davis { 31748195404bSBrooks Davis 31758195404bSBrooks Davis fill_ip6((ipfw_insn_ip6 *)cmd, av); 31768195404bSBrooks Davis if (F_LEN(cmd) == 0) /* any */ 31778195404bSBrooks Davis ; 31788195404bSBrooks Davis if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) { /* "me" */ 31798195404bSBrooks Davis cmd->opcode = O_IP6_DST_ME; 31808195404bSBrooks Davis } else if (F_LEN(cmd) == 31818195404bSBrooks Davis (F_INSN_SIZE(struct in6_addr) + F_INSN_SIZE(ipfw_insn))) { 31828195404bSBrooks Davis /* single IP, no mask*/ 31838195404bSBrooks Davis cmd->opcode = O_IP6_DST; 31848195404bSBrooks Davis } else { /* addr/mask opt */ 31858195404bSBrooks Davis cmd->opcode = O_IP6_DST_MASK; 31868195404bSBrooks Davis } 31878195404bSBrooks Davis return cmd; 31888195404bSBrooks Davis } 31898195404bSBrooks Davis 31908195404bSBrooks Davis 31919758b77fSLuigi Rizzo /* 31929758b77fSLuigi Rizzo * helper function to process a set of flags and set bits in the 31939758b77fSLuigi Rizzo * appropriate masks. 31949758b77fSLuigi Rizzo */ 31959758b77fSLuigi Rizzo static void 31969758b77fSLuigi Rizzo fill_flags(ipfw_insn *cmd, enum ipfw_opcodes opcode, 31979758b77fSLuigi Rizzo struct _s_x *flags, char *p) 31989758b77fSLuigi Rizzo { 3199571f8c1bSLuigi Rizzo uint8_t set=0, clear=0; 32009758b77fSLuigi Rizzo 32019758b77fSLuigi Rizzo while (p && *p) { 32029758b77fSLuigi Rizzo char *q; /* points to the separator */ 32039758b77fSLuigi Rizzo int val; 3204571f8c1bSLuigi Rizzo uint8_t *which; /* mask we are working on */ 32059758b77fSLuigi Rizzo 32069758b77fSLuigi Rizzo if (*p == '!') { 32079758b77fSLuigi Rizzo p++; 32089758b77fSLuigi Rizzo which = &clear; 32099758b77fSLuigi Rizzo } else 32109758b77fSLuigi Rizzo which = &set; 32119758b77fSLuigi Rizzo q = strchr(p, ','); 32129758b77fSLuigi Rizzo if (q) 32139758b77fSLuigi Rizzo *q++ = '\0'; 32149758b77fSLuigi Rizzo val = match_token(flags, p); 32159758b77fSLuigi Rizzo if (val <= 0) 32169758b77fSLuigi Rizzo errx(EX_DATAERR, "invalid flag %s", p); 3217571f8c1bSLuigi Rizzo *which |= (uint8_t)val; 32189758b77fSLuigi Rizzo p = q; 32199758b77fSLuigi Rizzo } 32209758b77fSLuigi Rizzo cmd->opcode = opcode; 32219758b77fSLuigi Rizzo cmd->len = (cmd->len & (F_NOT | F_OR)) | 1; 32229758b77fSLuigi Rizzo cmd->arg1 = (set & 0xff) | ( (clear & 0xff) << 8); 32239758b77fSLuigi Rizzo } 32249758b77fSLuigi Rizzo 32259758b77fSLuigi Rizzo 32269758b77fSLuigi Rizzo static void 32279758b77fSLuigi Rizzo delete(int ac, char *av[]) 32289758b77fSLuigi Rizzo { 3229571f8c1bSLuigi Rizzo uint32_t rulenum; 323062ff38aeSLuigi Rizzo struct dn_pipe p; 32319758b77fSLuigi Rizzo int i; 32329758b77fSLuigi Rizzo int exitval = EX_OK; 323343405724SLuigi Rizzo int do_set = 0; 32349758b77fSLuigi Rizzo 323562ff38aeSLuigi Rizzo memset(&p, 0, sizeof p); 32369758b77fSLuigi Rizzo 32379758b77fSLuigi Rizzo av++; ac--; 323804f70834SChristian S.J. Peron NEED1("missing rule specification"); 323901750186SBrooks Davis if (ac > 0 && _substrcmp(*av, "set") == 0) { 3240d069a5d4SMaxim Konovalov /* Do not allow using the following syntax: 3241d069a5d4SMaxim Konovalov * ipfw set N delete set M 3242d069a5d4SMaxim Konovalov */ 3243d069a5d4SMaxim Konovalov if (use_set) 3244d069a5d4SMaxim Konovalov errx(EX_DATAERR, "invalid syntax"); 324543405724SLuigi Rizzo do_set = 1; /* delete set */ 324643405724SLuigi Rizzo ac--; av++; 324799e5e645SLuigi Rizzo } 32489758b77fSLuigi Rizzo 32499758b77fSLuigi Rizzo /* Rule number */ 32509758b77fSLuigi Rizzo while (ac && isdigit(**av)) { 32519758b77fSLuigi Rizzo i = atoi(*av); av++; ac--; 3252ff2f6fe8SPaolo Pisati if (do_nat) { 3253ff2f6fe8SPaolo Pisati exitval = do_cmd(IP_FW_NAT_DEL, &i, sizeof i); 3254ff2f6fe8SPaolo Pisati if (exitval) { 3255ff2f6fe8SPaolo Pisati exitval = EX_UNAVAILABLE; 3256ff2f6fe8SPaolo Pisati warn("rule %u not available", i); 3257ff2f6fe8SPaolo Pisati } 3258ff2f6fe8SPaolo Pisati } else if (do_pipe) { 32599758b77fSLuigi Rizzo if (do_pipe == 1) 326062ff38aeSLuigi Rizzo p.pipe_nr = i; 32619758b77fSLuigi Rizzo else 326262ff38aeSLuigi Rizzo p.fs.fs_nr = i; 326362ff38aeSLuigi Rizzo i = do_cmd(IP_DUMMYNET_DEL, &p, sizeof p); 32649758b77fSLuigi Rizzo if (i) { 32659758b77fSLuigi Rizzo exitval = 1; 32669758b77fSLuigi Rizzo warn("rule %u: setsockopt(IP_DUMMYNET_DEL)", 326762ff38aeSLuigi Rizzo do_pipe == 1 ? p.pipe_nr : p.fs.fs_nr); 32689758b77fSLuigi Rizzo } 32699758b77fSLuigi Rizzo } else { 3270d069a5d4SMaxim Konovalov if (use_set) 3271d069a5d4SMaxim Konovalov rulenum = (i & 0xffff) | (5 << 24) | 3272d069a5d4SMaxim Konovalov ((use_set - 1) << 16); 3273d069a5d4SMaxim Konovalov else 327499e5e645SLuigi Rizzo rulenum = (i & 0xffff) | (do_set << 24); 3275571f8c1bSLuigi Rizzo i = do_cmd(IP_FW_DEL, &rulenum, sizeof rulenum); 32769758b77fSLuigi Rizzo if (i) { 32779758b77fSLuigi Rizzo exitval = EX_UNAVAILABLE; 32789758b77fSLuigi Rizzo warn("rule %u: setsockopt(IP_FW_DEL)", 32799758b77fSLuigi Rizzo rulenum); 32809758b77fSLuigi Rizzo } 32819758b77fSLuigi Rizzo } 32829758b77fSLuigi Rizzo } 32839758b77fSLuigi Rizzo if (exitval != EX_OK) 32849758b77fSLuigi Rizzo exit(exitval); 32859758b77fSLuigi Rizzo } 32869758b77fSLuigi Rizzo 32879758b77fSLuigi Rizzo 32889758b77fSLuigi Rizzo /* 32899758b77fSLuigi Rizzo * fill the interface structure. We do not check the name as we can 32909758b77fSLuigi Rizzo * create interfaces dynamically, so checking them at insert time 32919758b77fSLuigi Rizzo * makes relatively little sense. 32929bf40edeSBrooks Davis * Interface names containing '*', '?', or '[' are assumed to be shell 32939bf40edeSBrooks Davis * patterns which match interfaces. 32949758b77fSLuigi Rizzo */ 32959758b77fSLuigi Rizzo static void 32969758b77fSLuigi Rizzo fill_iface(ipfw_insn_if *cmd, char *arg) 32979758b77fSLuigi Rizzo { 32989758b77fSLuigi Rizzo cmd->name[0] = '\0'; 32999758b77fSLuigi Rizzo cmd->o.len |= F_INSN_SIZE(ipfw_insn_if); 33009758b77fSLuigi Rizzo 33019758b77fSLuigi Rizzo /* Parse the interface or address */ 330201750186SBrooks Davis if (strcmp(arg, "any") == 0) 33039758b77fSLuigi Rizzo cmd->o.len = 0; /* effectively ignore this command */ 33049758b77fSLuigi Rizzo else if (!isdigit(*arg)) { 33059bf40edeSBrooks Davis strlcpy(cmd->name, arg, sizeof(cmd->name)); 33069bf40edeSBrooks Davis cmd->p.glob = strpbrk(arg, "*?[") != NULL ? 1 : 0; 33079758b77fSLuigi Rizzo } else if (!inet_aton(arg, &cmd->p.ip)) 33089758b77fSLuigi Rizzo errx(EX_DATAERR, "bad ip address ``%s''", arg); 33099758b77fSLuigi Rizzo } 33109758b77fSLuigi Rizzo 3311ff2f6fe8SPaolo Pisati /* 3312ff2f6fe8SPaolo Pisati * Search for interface with name "ifn", and fill n accordingly: 3313ff2f6fe8SPaolo Pisati * 3314ff2f6fe8SPaolo Pisati * n->ip ip address of interface "ifn" 3315ff2f6fe8SPaolo Pisati * n->if_name copy of interface name "ifn" 3316ff2f6fe8SPaolo Pisati */ 3317ff2f6fe8SPaolo Pisati static void 3318ff2f6fe8SPaolo Pisati set_addr_dynamic(const char *ifn, struct cfg_nat *n) 3319ff2f6fe8SPaolo Pisati { 3320ff2f6fe8SPaolo Pisati size_t needed; 3321ff2f6fe8SPaolo Pisati int mib[6]; 3322ff2f6fe8SPaolo Pisati char *buf, *lim, *next; 3323ff2f6fe8SPaolo Pisati struct if_msghdr *ifm; 3324ff2f6fe8SPaolo Pisati struct ifa_msghdr *ifam; 3325ff2f6fe8SPaolo Pisati struct sockaddr_dl *sdl; 3326ff2f6fe8SPaolo Pisati struct sockaddr_in *sin; 3327ff2f6fe8SPaolo Pisati int ifIndex, ifMTU; 3328ff2f6fe8SPaolo Pisati 3329ff2f6fe8SPaolo Pisati mib[0] = CTL_NET; 3330ff2f6fe8SPaolo Pisati mib[1] = PF_ROUTE; 3331ff2f6fe8SPaolo Pisati mib[2] = 0; 3332ff2f6fe8SPaolo Pisati mib[3] = AF_INET; 3333ff2f6fe8SPaolo Pisati mib[4] = NET_RT_IFLIST; 3334ff2f6fe8SPaolo Pisati mib[5] = 0; 3335ff2f6fe8SPaolo Pisati /* 3336ff2f6fe8SPaolo Pisati * Get interface data. 3337ff2f6fe8SPaolo Pisati */ 3338ff2f6fe8SPaolo Pisati if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1) 3339ff2f6fe8SPaolo Pisati err(1, "iflist-sysctl-estimate"); 3340ff2f6fe8SPaolo Pisati if ((buf = malloc(needed)) == NULL) 3341ff2f6fe8SPaolo Pisati errx(1, "malloc failed"); 3342ff2f6fe8SPaolo Pisati if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1) 3343ff2f6fe8SPaolo Pisati err(1, "iflist-sysctl-get"); 3344ff2f6fe8SPaolo Pisati lim = buf + needed; 3345ff2f6fe8SPaolo Pisati /* 3346ff2f6fe8SPaolo Pisati * Loop through interfaces until one with 3347ff2f6fe8SPaolo Pisati * given name is found. This is done to 3348ff2f6fe8SPaolo Pisati * find correct interface index for routing 3349ff2f6fe8SPaolo Pisati * message processing. 3350ff2f6fe8SPaolo Pisati */ 3351ff2f6fe8SPaolo Pisati ifIndex = 0; 3352ff2f6fe8SPaolo Pisati next = buf; 3353ff2f6fe8SPaolo Pisati while (next < lim) { 3354ff2f6fe8SPaolo Pisati ifm = (struct if_msghdr *)next; 3355ff2f6fe8SPaolo Pisati next += ifm->ifm_msglen; 3356ff2f6fe8SPaolo Pisati if (ifm->ifm_version != RTM_VERSION) { 3357ff2f6fe8SPaolo Pisati if (verbose) 3358ff2f6fe8SPaolo Pisati warnx("routing message version %d " 3359ff2f6fe8SPaolo Pisati "not understood", ifm->ifm_version); 3360ff2f6fe8SPaolo Pisati continue; 3361ff2f6fe8SPaolo Pisati } 3362ff2f6fe8SPaolo Pisati if (ifm->ifm_type == RTM_IFINFO) { 3363ff2f6fe8SPaolo Pisati sdl = (struct sockaddr_dl *)(ifm + 1); 3364ff2f6fe8SPaolo Pisati if (strlen(ifn) == sdl->sdl_nlen && 3365ff2f6fe8SPaolo Pisati strncmp(ifn, sdl->sdl_data, sdl->sdl_nlen) == 0) { 3366ff2f6fe8SPaolo Pisati ifIndex = ifm->ifm_index; 3367ff2f6fe8SPaolo Pisati ifMTU = ifm->ifm_data.ifi_mtu; 3368ff2f6fe8SPaolo Pisati break; 3369ff2f6fe8SPaolo Pisati } 3370ff2f6fe8SPaolo Pisati } 3371ff2f6fe8SPaolo Pisati } 3372ff2f6fe8SPaolo Pisati if (!ifIndex) 3373ff2f6fe8SPaolo Pisati errx(1, "unknown interface name %s", ifn); 3374ff2f6fe8SPaolo Pisati /* 3375ff2f6fe8SPaolo Pisati * Get interface address. 3376ff2f6fe8SPaolo Pisati */ 3377ff2f6fe8SPaolo Pisati sin = NULL; 3378ff2f6fe8SPaolo Pisati while (next < lim) { 3379ff2f6fe8SPaolo Pisati ifam = (struct ifa_msghdr *)next; 3380ff2f6fe8SPaolo Pisati next += ifam->ifam_msglen; 3381ff2f6fe8SPaolo Pisati if (ifam->ifam_version != RTM_VERSION) { 3382ff2f6fe8SPaolo Pisati if (verbose) 3383ff2f6fe8SPaolo Pisati warnx("routing message version %d " 3384ff2f6fe8SPaolo Pisati "not understood", ifam->ifam_version); 3385ff2f6fe8SPaolo Pisati continue; 3386ff2f6fe8SPaolo Pisati } 3387ff2f6fe8SPaolo Pisati if (ifam->ifam_type != RTM_NEWADDR) 3388ff2f6fe8SPaolo Pisati break; 3389ff2f6fe8SPaolo Pisati if (ifam->ifam_addrs & RTA_IFA) { 3390ff2f6fe8SPaolo Pisati int i; 3391ff2f6fe8SPaolo Pisati char *cp = (char *)(ifam + 1); 3392ff2f6fe8SPaolo Pisati 3393ff2f6fe8SPaolo Pisati for (i = 1; i < RTA_IFA; i <<= 1) { 3394ff2f6fe8SPaolo Pisati if (ifam->ifam_addrs & i) 3395ff2f6fe8SPaolo Pisati cp += SA_SIZE((struct sockaddr *)cp); 3396ff2f6fe8SPaolo Pisati } 3397ff2f6fe8SPaolo Pisati if (((struct sockaddr *)cp)->sa_family == AF_INET) { 3398ff2f6fe8SPaolo Pisati sin = (struct sockaddr_in *)cp; 3399ff2f6fe8SPaolo Pisati break; 3400ff2f6fe8SPaolo Pisati } 3401ff2f6fe8SPaolo Pisati } 3402ff2f6fe8SPaolo Pisati } 3403ff2f6fe8SPaolo Pisati if (sin == NULL) 3404ff2f6fe8SPaolo Pisati errx(1, "%s: cannot get interface address", ifn); 3405ff2f6fe8SPaolo Pisati 3406ff2f6fe8SPaolo Pisati n->ip = sin->sin_addr; 3407ff2f6fe8SPaolo Pisati strncpy(n->if_name, ifn, IF_NAMESIZE); 3408ff2f6fe8SPaolo Pisati 3409ff2f6fe8SPaolo Pisati free(buf); 3410ff2f6fe8SPaolo Pisati } 3411ff2f6fe8SPaolo Pisati 3412ff2f6fe8SPaolo Pisati /* 3413ff2f6fe8SPaolo Pisati * XXX - The following functions, macros and definitions come from natd.c: 3414ff2f6fe8SPaolo Pisati * it would be better to move them outside natd.c, in a file 3415ff2f6fe8SPaolo Pisati * (redirect_support.[ch]?) shared by ipfw and natd, but for now i can live 3416ff2f6fe8SPaolo Pisati * with it. 3417ff2f6fe8SPaolo Pisati */ 3418ff2f6fe8SPaolo Pisati 3419ff2f6fe8SPaolo Pisati /* 3420ff2f6fe8SPaolo Pisati * Definition of a port range, and macros to deal with values. 3421ff2f6fe8SPaolo Pisati * FORMAT: HI 16-bits == first port in range, 0 == all ports. 3422ff2f6fe8SPaolo Pisati * LO 16-bits == number of ports in range 3423ff2f6fe8SPaolo Pisati * NOTES: - Port values are not stored in network byte order. 3424ff2f6fe8SPaolo Pisati */ 3425ff2f6fe8SPaolo Pisati 3426ff2f6fe8SPaolo Pisati #define port_range u_long 3427ff2f6fe8SPaolo Pisati 3428ff2f6fe8SPaolo Pisati #define GETLOPORT(x) ((x) >> 0x10) 3429ff2f6fe8SPaolo Pisati #define GETNUMPORTS(x) ((x) & 0x0000ffff) 3430ff2f6fe8SPaolo Pisati #define GETHIPORT(x) (GETLOPORT((x)) + GETNUMPORTS((x))) 3431ff2f6fe8SPaolo Pisati 3432ff2f6fe8SPaolo Pisati /* Set y to be the low-port value in port_range variable x. */ 3433ff2f6fe8SPaolo Pisati #define SETLOPORT(x,y) ((x) = ((x) & 0x0000ffff) | ((y) << 0x10)) 3434ff2f6fe8SPaolo Pisati 3435ff2f6fe8SPaolo Pisati /* Set y to be the number of ports in port_range variable x. */ 3436ff2f6fe8SPaolo Pisati #define SETNUMPORTS(x,y) ((x) = ((x) & 0xffff0000) | (y)) 3437ff2f6fe8SPaolo Pisati 3438ff2f6fe8SPaolo Pisati static void 3439ff2f6fe8SPaolo Pisati StrToAddr (const char* str, struct in_addr* addr) 3440ff2f6fe8SPaolo Pisati { 3441ff2f6fe8SPaolo Pisati struct hostent* hp; 3442ff2f6fe8SPaolo Pisati 3443ff2f6fe8SPaolo Pisati if (inet_aton (str, addr)) 3444ff2f6fe8SPaolo Pisati return; 3445ff2f6fe8SPaolo Pisati 3446ff2f6fe8SPaolo Pisati hp = gethostbyname (str); 3447ff2f6fe8SPaolo Pisati if (!hp) 3448ff2f6fe8SPaolo Pisati errx (1, "unknown host %s", str); 3449ff2f6fe8SPaolo Pisati 3450ff2f6fe8SPaolo Pisati memcpy (addr, hp->h_addr, sizeof (struct in_addr)); 3451ff2f6fe8SPaolo Pisati } 3452ff2f6fe8SPaolo Pisati 3453ff2f6fe8SPaolo Pisati static int 3454ff2f6fe8SPaolo Pisati StrToPortRange (const char* str, const char* proto, port_range *portRange) 3455ff2f6fe8SPaolo Pisati { 3456ff2f6fe8SPaolo Pisati char* sep; 3457ff2f6fe8SPaolo Pisati struct servent* sp; 3458ff2f6fe8SPaolo Pisati char* end; 3459ff2f6fe8SPaolo Pisati u_short loPort; 3460ff2f6fe8SPaolo Pisati u_short hiPort; 3461ff2f6fe8SPaolo Pisati 3462ff2f6fe8SPaolo Pisati /* First see if this is a service, return corresponding port if so. */ 3463ff2f6fe8SPaolo Pisati sp = getservbyname (str,proto); 3464ff2f6fe8SPaolo Pisati if (sp) { 3465ff2f6fe8SPaolo Pisati SETLOPORT(*portRange, ntohs(sp->s_port)); 3466ff2f6fe8SPaolo Pisati SETNUMPORTS(*portRange, 1); 3467ff2f6fe8SPaolo Pisati return 0; 3468ff2f6fe8SPaolo Pisati } 3469ff2f6fe8SPaolo Pisati 3470ff2f6fe8SPaolo Pisati /* Not a service, see if it's a single port or port range. */ 3471ff2f6fe8SPaolo Pisati sep = strchr (str, '-'); 3472ff2f6fe8SPaolo Pisati if (sep == NULL) { 3473ff2f6fe8SPaolo Pisati SETLOPORT(*portRange, strtol(str, &end, 10)); 3474ff2f6fe8SPaolo Pisati if (end != str) { 3475ff2f6fe8SPaolo Pisati /* Single port. */ 3476ff2f6fe8SPaolo Pisati SETNUMPORTS(*portRange, 1); 3477ff2f6fe8SPaolo Pisati return 0; 3478ff2f6fe8SPaolo Pisati } 3479ff2f6fe8SPaolo Pisati 3480ff2f6fe8SPaolo Pisati /* Error in port range field. */ 3481ff2f6fe8SPaolo Pisati errx (EX_DATAERR, "%s/%s: unknown service", str, proto); 3482ff2f6fe8SPaolo Pisati } 3483ff2f6fe8SPaolo Pisati 3484ff2f6fe8SPaolo Pisati /* Port range, get the values and sanity check. */ 3485ff2f6fe8SPaolo Pisati sscanf (str, "%hu-%hu", &loPort, &hiPort); 3486ff2f6fe8SPaolo Pisati SETLOPORT(*portRange, loPort); 3487ff2f6fe8SPaolo Pisati SETNUMPORTS(*portRange, 0); /* Error by default */ 3488ff2f6fe8SPaolo Pisati if (loPort <= hiPort) 3489ff2f6fe8SPaolo Pisati SETNUMPORTS(*portRange, hiPort - loPort + 1); 3490ff2f6fe8SPaolo Pisati 3491ff2f6fe8SPaolo Pisati if (GETNUMPORTS(*portRange) == 0) 3492ff2f6fe8SPaolo Pisati errx (EX_DATAERR, "invalid port range %s", str); 3493ff2f6fe8SPaolo Pisati 3494ff2f6fe8SPaolo Pisati return 0; 3495ff2f6fe8SPaolo Pisati } 3496ff2f6fe8SPaolo Pisati 3497ff2f6fe8SPaolo Pisati static int 3498ff2f6fe8SPaolo Pisati StrToProto (const char* str) 3499ff2f6fe8SPaolo Pisati { 3500ff2f6fe8SPaolo Pisati if (!strcmp (str, "tcp")) 3501ff2f6fe8SPaolo Pisati return IPPROTO_TCP; 3502ff2f6fe8SPaolo Pisati 3503ff2f6fe8SPaolo Pisati if (!strcmp (str, "udp")) 3504ff2f6fe8SPaolo Pisati return IPPROTO_UDP; 3505ff2f6fe8SPaolo Pisati 3506ff2f6fe8SPaolo Pisati errx (EX_DATAERR, "unknown protocol %s. Expected tcp or udp", str); 3507ff2f6fe8SPaolo Pisati } 3508ff2f6fe8SPaolo Pisati 3509ff2f6fe8SPaolo Pisati static int 3510ff2f6fe8SPaolo Pisati StrToAddrAndPortRange (const char* str, struct in_addr* addr, char* proto, 3511ff2f6fe8SPaolo Pisati port_range *portRange) 3512ff2f6fe8SPaolo Pisati { 3513ff2f6fe8SPaolo Pisati char* ptr; 3514ff2f6fe8SPaolo Pisati 3515ff2f6fe8SPaolo Pisati ptr = strchr (str, ':'); 3516ff2f6fe8SPaolo Pisati if (!ptr) 3517ff2f6fe8SPaolo Pisati errx (EX_DATAERR, "%s is missing port number", str); 3518ff2f6fe8SPaolo Pisati 3519ff2f6fe8SPaolo Pisati *ptr = '\0'; 3520ff2f6fe8SPaolo Pisati ++ptr; 3521ff2f6fe8SPaolo Pisati 3522ff2f6fe8SPaolo Pisati StrToAddr (str, addr); 3523ff2f6fe8SPaolo Pisati return StrToPortRange (ptr, proto, portRange); 3524ff2f6fe8SPaolo Pisati } 3525ff2f6fe8SPaolo Pisati 3526ff2f6fe8SPaolo Pisati /* End of stuff taken from natd.c. */ 3527ff2f6fe8SPaolo Pisati 3528ff2f6fe8SPaolo Pisati #define INC_ARGCV() do { \ 3529ff2f6fe8SPaolo Pisati (*_av)++; \ 3530ff2f6fe8SPaolo Pisati (*_ac)--; \ 3531ff2f6fe8SPaolo Pisati av = *_av; \ 3532ff2f6fe8SPaolo Pisati ac = *_ac; \ 3533ff2f6fe8SPaolo Pisati } while(0) 3534ff2f6fe8SPaolo Pisati 3535ff2f6fe8SPaolo Pisati /* 3536ff2f6fe8SPaolo Pisati * The next 3 functions add support for the addr, port and proto redirect and 3537ff2f6fe8SPaolo Pisati * their logic is loosely based on SetupAddressRedirect(), SetupPortRedirect() 3538ff2f6fe8SPaolo Pisati * and SetupProtoRedirect() from natd.c. 3539ff2f6fe8SPaolo Pisati * 3540ff2f6fe8SPaolo Pisati * Every setup_* function fills at least one redirect entry 3541ff2f6fe8SPaolo Pisati * (struct cfg_redir) and zero or more server pool entry (struct cfg_spool) 3542ff2f6fe8SPaolo Pisati * in buf. 3543ff2f6fe8SPaolo Pisati * 3544ff2f6fe8SPaolo Pisati * The format of data in buf is: 3545ff2f6fe8SPaolo Pisati * 3546ff2f6fe8SPaolo Pisati * 3547ff2f6fe8SPaolo Pisati * cfg_nat cfg_redir cfg_spool ...... cfg_spool 3548ff2f6fe8SPaolo Pisati * 3549ff2f6fe8SPaolo Pisati * ------------------------------------- ------------ 3550ff2f6fe8SPaolo Pisati * | | .....X ... | | | | ..... 3551ff2f6fe8SPaolo Pisati * ------------------------------------- ...... ------------ 3552ff2f6fe8SPaolo Pisati * ^ 3553ff2f6fe8SPaolo Pisati * spool_cnt n=0 ...... n=(X-1) 3554ff2f6fe8SPaolo Pisati * 3555ff2f6fe8SPaolo Pisati * len points to the amount of available space in buf 3556ff2f6fe8SPaolo Pisati * space counts the memory consumed by every function 3557ff2f6fe8SPaolo Pisati * 3558ff2f6fe8SPaolo Pisati * XXX - Every function get all the argv params so it 3559ff2f6fe8SPaolo Pisati * has to check, in optional parameters, that the next 3560ff2f6fe8SPaolo Pisati * args is a valid option for the redir entry and not 3561ff2f6fe8SPaolo Pisati * another token. Only redir_port and redir_proto are 3562ff2f6fe8SPaolo Pisati * affected by this. 3563ff2f6fe8SPaolo Pisati */ 3564ff2f6fe8SPaolo Pisati 3565ff2f6fe8SPaolo Pisati static int 3566ff2f6fe8SPaolo Pisati setup_redir_addr(char *spool_buf, int len, 3567ff2f6fe8SPaolo Pisati int *_ac, char ***_av) 3568ff2f6fe8SPaolo Pisati { 3569ff2f6fe8SPaolo Pisati char **av, *sep; /* Token separator. */ 3570ff2f6fe8SPaolo Pisati /* Temporary buffer used to hold server pool ip's. */ 3571ff2f6fe8SPaolo Pisati char tmp_spool_buf[NAT_BUF_LEN]; 3572ff2f6fe8SPaolo Pisati int ac, i, space, lsnat; 3573ff2f6fe8SPaolo Pisati struct cfg_redir *r; 3574ff2f6fe8SPaolo Pisati struct cfg_spool *tmp; 3575ff2f6fe8SPaolo Pisati 3576ff2f6fe8SPaolo Pisati av = *_av; 3577ff2f6fe8SPaolo Pisati ac = *_ac; 3578ff2f6fe8SPaolo Pisati space = 0; 3579ff2f6fe8SPaolo Pisati lsnat = 0; 3580ff2f6fe8SPaolo Pisati if (len >= SOF_REDIR) { 3581ff2f6fe8SPaolo Pisati r = (struct cfg_redir *)spool_buf; 3582ff2f6fe8SPaolo Pisati /* Skip cfg_redir at beginning of buf. */ 3583ff2f6fe8SPaolo Pisati spool_buf = &spool_buf[SOF_REDIR]; 3584ff2f6fe8SPaolo Pisati space = SOF_REDIR; 3585ff2f6fe8SPaolo Pisati len -= SOF_REDIR; 3586ff2f6fe8SPaolo Pisati } else 3587ff2f6fe8SPaolo Pisati goto nospace; 3588ff2f6fe8SPaolo Pisati r->mode = REDIR_ADDR; 3589ff2f6fe8SPaolo Pisati /* Extract local address. */ 3590ff2f6fe8SPaolo Pisati if (ac == 0) 3591ff2f6fe8SPaolo Pisati errx(EX_DATAERR, "redirect_addr: missing local address"); 3592ff2f6fe8SPaolo Pisati sep = strchr(*av, ','); 3593ff2f6fe8SPaolo Pisati if (sep) { /* LSNAT redirection syntax. */ 3594ff2f6fe8SPaolo Pisati r->laddr.s_addr = INADDR_NONE; 3595ff2f6fe8SPaolo Pisati /* Preserve av, copy spool servers to tmp_spool_buf. */ 3596ff2f6fe8SPaolo Pisati strncpy(tmp_spool_buf, *av, strlen(*av)+1); 3597ff2f6fe8SPaolo Pisati lsnat = 1; 3598ff2f6fe8SPaolo Pisati } else 3599ff2f6fe8SPaolo Pisati StrToAddr(*av, &r->laddr); 3600ff2f6fe8SPaolo Pisati INC_ARGCV(); 3601ff2f6fe8SPaolo Pisati 3602ff2f6fe8SPaolo Pisati /* Extract public address. */ 3603ff2f6fe8SPaolo Pisati if (ac == 0) 3604ff2f6fe8SPaolo Pisati errx(EX_DATAERR, "redirect_addr: missing public address"); 3605ff2f6fe8SPaolo Pisati StrToAddr(*av, &r->paddr); 3606ff2f6fe8SPaolo Pisati INC_ARGCV(); 3607ff2f6fe8SPaolo Pisati 3608ff2f6fe8SPaolo Pisati /* Setup LSNAT server pool. */ 3609ff2f6fe8SPaolo Pisati if (sep) { 3610ff2f6fe8SPaolo Pisati sep = strtok(tmp_spool_buf, ","); 3611ff2f6fe8SPaolo Pisati while (sep != NULL) { 3612ff2f6fe8SPaolo Pisati tmp = (struct cfg_spool *)spool_buf; 3613ff2f6fe8SPaolo Pisati if (len < SOF_SPOOL) 3614ff2f6fe8SPaolo Pisati goto nospace; 3615ff2f6fe8SPaolo Pisati len -= SOF_SPOOL; 3616ff2f6fe8SPaolo Pisati space += SOF_SPOOL; 3617ff2f6fe8SPaolo Pisati StrToAddr(sep, &tmp->addr); 3618ff2f6fe8SPaolo Pisati tmp->port = ~0; 3619ff2f6fe8SPaolo Pisati r->spool_cnt++; 3620ff2f6fe8SPaolo Pisati /* Point to the next possible cfg_spool. */ 3621ff2f6fe8SPaolo Pisati spool_buf = &spool_buf[SOF_SPOOL]; 3622ff2f6fe8SPaolo Pisati sep = strtok(NULL, ","); 3623ff2f6fe8SPaolo Pisati } 3624ff2f6fe8SPaolo Pisati } 3625ff2f6fe8SPaolo Pisati return(space); 3626ff2f6fe8SPaolo Pisati nospace: 3627ff2f6fe8SPaolo Pisati errx(EX_DATAERR, "redirect_addr: buf is too small\n"); 3628ff2f6fe8SPaolo Pisati } 3629ff2f6fe8SPaolo Pisati 3630ff2f6fe8SPaolo Pisati static int 3631ff2f6fe8SPaolo Pisati setup_redir_port(char *spool_buf, int len, 3632ff2f6fe8SPaolo Pisati int *_ac, char ***_av) 3633ff2f6fe8SPaolo Pisati { 3634ff2f6fe8SPaolo Pisati char **av, *sep, *protoName; 3635ff2f6fe8SPaolo Pisati char tmp_spool_buf[NAT_BUF_LEN]; 3636ff2f6fe8SPaolo Pisati int ac, space, lsnat; 3637ff2f6fe8SPaolo Pisati struct cfg_redir *r; 3638ff2f6fe8SPaolo Pisati struct cfg_spool *tmp; 3639ff2f6fe8SPaolo Pisati u_short numLocalPorts; 3640ff2f6fe8SPaolo Pisati port_range portRange; 3641ff2f6fe8SPaolo Pisati 3642ff2f6fe8SPaolo Pisati av = *_av; 3643ff2f6fe8SPaolo Pisati ac = *_ac; 3644ff2f6fe8SPaolo Pisati space = 0; 3645ff2f6fe8SPaolo Pisati lsnat = 0; 3646ff2f6fe8SPaolo Pisati numLocalPorts = 0; 3647ff2f6fe8SPaolo Pisati 3648ff2f6fe8SPaolo Pisati if (len >= SOF_REDIR) { 3649ff2f6fe8SPaolo Pisati r = (struct cfg_redir *)spool_buf; 3650ff2f6fe8SPaolo Pisati /* Skip cfg_redir at beginning of buf. */ 3651ff2f6fe8SPaolo Pisati spool_buf = &spool_buf[SOF_REDIR]; 3652ff2f6fe8SPaolo Pisati space = SOF_REDIR; 3653ff2f6fe8SPaolo Pisati len -= SOF_REDIR; 3654ff2f6fe8SPaolo Pisati } else 3655ff2f6fe8SPaolo Pisati goto nospace; 3656ff2f6fe8SPaolo Pisati r->mode = REDIR_PORT; 3657ff2f6fe8SPaolo Pisati /* 3658ff2f6fe8SPaolo Pisati * Extract protocol. 3659ff2f6fe8SPaolo Pisati */ 3660ff2f6fe8SPaolo Pisati if (ac == 0) 3661ff2f6fe8SPaolo Pisati errx (EX_DATAERR, "redirect_port: missing protocol"); 3662ff2f6fe8SPaolo Pisati r->proto = StrToProto(*av); 3663ff2f6fe8SPaolo Pisati protoName = *av; 3664ff2f6fe8SPaolo Pisati INC_ARGCV(); 3665ff2f6fe8SPaolo Pisati 3666ff2f6fe8SPaolo Pisati /* 3667ff2f6fe8SPaolo Pisati * Extract local address. 3668ff2f6fe8SPaolo Pisati */ 3669ff2f6fe8SPaolo Pisati if (ac == 0) 3670ff2f6fe8SPaolo Pisati errx (EX_DATAERR, "redirect_port: missing local address"); 3671ff2f6fe8SPaolo Pisati 3672ff2f6fe8SPaolo Pisati sep = strchr(*av, ','); 3673ff2f6fe8SPaolo Pisati /* LSNAT redirection syntax. */ 3674ff2f6fe8SPaolo Pisati if (sep) { 3675ff2f6fe8SPaolo Pisati r->laddr.s_addr = INADDR_NONE; 3676ff2f6fe8SPaolo Pisati r->lport = ~0; 3677ff2f6fe8SPaolo Pisati numLocalPorts = 1; 3678ff2f6fe8SPaolo Pisati /* Preserve av, copy spool servers to tmp_spool_buf. */ 3679ff2f6fe8SPaolo Pisati strncpy(tmp_spool_buf, *av, strlen(*av)+1); 3680ff2f6fe8SPaolo Pisati lsnat = 1; 3681ff2f6fe8SPaolo Pisati } else { 3682ff2f6fe8SPaolo Pisati if (StrToAddrAndPortRange (*av, &r->laddr, protoName, 3683ff2f6fe8SPaolo Pisati &portRange) != 0) 3684ff2f6fe8SPaolo Pisati errx(EX_DATAERR, "redirect_port:" 3685ff2f6fe8SPaolo Pisati "invalid local port range"); 3686ff2f6fe8SPaolo Pisati 3687ff2f6fe8SPaolo Pisati r->lport = GETLOPORT(portRange); 3688ff2f6fe8SPaolo Pisati numLocalPorts = GETNUMPORTS(portRange); 3689ff2f6fe8SPaolo Pisati } 3690ff2f6fe8SPaolo Pisati INC_ARGCV(); 3691ff2f6fe8SPaolo Pisati 3692ff2f6fe8SPaolo Pisati /* 3693ff2f6fe8SPaolo Pisati * Extract public port and optionally address. 3694ff2f6fe8SPaolo Pisati */ 3695ff2f6fe8SPaolo Pisati if (ac == 0) 3696ff2f6fe8SPaolo Pisati errx (EX_DATAERR, "redirect_port: missing public port"); 3697ff2f6fe8SPaolo Pisati 3698ff2f6fe8SPaolo Pisati sep = strchr (*av, ':'); 3699ff2f6fe8SPaolo Pisati if (sep) { 3700ff2f6fe8SPaolo Pisati if (StrToAddrAndPortRange (*av, &r->paddr, protoName, 3701ff2f6fe8SPaolo Pisati &portRange) != 0) 3702ff2f6fe8SPaolo Pisati errx(EX_DATAERR, "redirect_port:" 3703ff2f6fe8SPaolo Pisati "invalid public port range"); 3704ff2f6fe8SPaolo Pisati } else { 3705ff2f6fe8SPaolo Pisati r->paddr.s_addr = INADDR_ANY; 3706ff2f6fe8SPaolo Pisati if (StrToPortRange (*av, protoName, &portRange) != 0) 3707ff2f6fe8SPaolo Pisati errx(EX_DATAERR, "redirect_port:" 3708ff2f6fe8SPaolo Pisati "invalid public port range"); 3709ff2f6fe8SPaolo Pisati } 3710ff2f6fe8SPaolo Pisati 3711ff2f6fe8SPaolo Pisati r->pport = GETLOPORT(portRange); 3712ff2f6fe8SPaolo Pisati r->pport_cnt = GETNUMPORTS(portRange); 3713ff2f6fe8SPaolo Pisati INC_ARGCV(); 3714ff2f6fe8SPaolo Pisati 3715ff2f6fe8SPaolo Pisati /* 3716ff2f6fe8SPaolo Pisati * Extract remote address and optionally port. 3717ff2f6fe8SPaolo Pisati */ 3718ff2f6fe8SPaolo Pisati /* 3719ff2f6fe8SPaolo Pisati * NB: isalpha(**av) => we've to check that next parameter is really an 3720ff2f6fe8SPaolo Pisati * option for this redirect entry, else stop here processing arg[cv]. 3721ff2f6fe8SPaolo Pisati */ 3722ff2f6fe8SPaolo Pisati if (ac != 0 && !isalpha(**av)) { 3723ff2f6fe8SPaolo Pisati sep = strchr (*av, ':'); 3724ff2f6fe8SPaolo Pisati if (sep) { 3725ff2f6fe8SPaolo Pisati if (StrToAddrAndPortRange (*av, &r->raddr, protoName, 3726ff2f6fe8SPaolo Pisati &portRange) != 0) 3727ff2f6fe8SPaolo Pisati errx(EX_DATAERR, "redirect_port:" 3728ff2f6fe8SPaolo Pisati "invalid remote port range"); 3729ff2f6fe8SPaolo Pisati } else { 3730ff2f6fe8SPaolo Pisati SETLOPORT(portRange, 0); 3731ff2f6fe8SPaolo Pisati SETNUMPORTS(portRange, 1); 3732ff2f6fe8SPaolo Pisati StrToAddr (*av, &r->raddr); 3733ff2f6fe8SPaolo Pisati } 3734ff2f6fe8SPaolo Pisati INC_ARGCV(); 3735ff2f6fe8SPaolo Pisati } else { 3736ff2f6fe8SPaolo Pisati SETLOPORT(portRange, 0); 3737ff2f6fe8SPaolo Pisati SETNUMPORTS(portRange, 1); 3738ff2f6fe8SPaolo Pisati r->raddr.s_addr = INADDR_ANY; 3739ff2f6fe8SPaolo Pisati } 3740ff2f6fe8SPaolo Pisati r->rport = GETLOPORT(portRange); 3741ff2f6fe8SPaolo Pisati r->rport_cnt = GETNUMPORTS(portRange); 3742ff2f6fe8SPaolo Pisati 3743ff2f6fe8SPaolo Pisati /* 3744ff2f6fe8SPaolo Pisati * Make sure port ranges match up, then add the redirect ports. 3745ff2f6fe8SPaolo Pisati */ 3746ff2f6fe8SPaolo Pisati if (numLocalPorts != r->pport_cnt) 3747ff2f6fe8SPaolo Pisati errx(EX_DATAERR, "redirect_port:" 3748ff2f6fe8SPaolo Pisati "port ranges must be equal in size"); 3749ff2f6fe8SPaolo Pisati 3750ff2f6fe8SPaolo Pisati /* Remote port range is allowed to be '0' which means all ports. */ 3751ff2f6fe8SPaolo Pisati if (r->rport_cnt != numLocalPorts && 3752ff2f6fe8SPaolo Pisati (r->rport_cnt != 1 || r->rport != 0)) 3753ff2f6fe8SPaolo Pisati errx(EX_DATAERR, "redirect_port: remote port must" 3754ff2f6fe8SPaolo Pisati "be 0 or equal to local port range in size"); 3755ff2f6fe8SPaolo Pisati 3756ff2f6fe8SPaolo Pisati /* 3757ff2f6fe8SPaolo Pisati * Setup LSNAT server pool. 3758ff2f6fe8SPaolo Pisati */ 3759ff2f6fe8SPaolo Pisati if (lsnat) { 3760ff2f6fe8SPaolo Pisati sep = strtok(tmp_spool_buf, ","); 3761ff2f6fe8SPaolo Pisati while (sep != NULL) { 3762ff2f6fe8SPaolo Pisati tmp = (struct cfg_spool *)spool_buf; 3763ff2f6fe8SPaolo Pisati if (len < SOF_SPOOL) 3764ff2f6fe8SPaolo Pisati goto nospace; 3765ff2f6fe8SPaolo Pisati len -= SOF_SPOOL; 3766ff2f6fe8SPaolo Pisati space += SOF_SPOOL; 3767ff2f6fe8SPaolo Pisati if (StrToAddrAndPortRange(sep, &tmp->addr, protoName, 3768ff2f6fe8SPaolo Pisati &portRange) != 0) 3769ff2f6fe8SPaolo Pisati errx(EX_DATAERR, "redirect_port:" 3770ff2f6fe8SPaolo Pisati "invalid local port range"); 3771ff2f6fe8SPaolo Pisati if (GETNUMPORTS(portRange) != 1) 3772ff2f6fe8SPaolo Pisati errx(EX_DATAERR, "redirect_port: local port" 3773ff2f6fe8SPaolo Pisati "must be single in this context"); 3774ff2f6fe8SPaolo Pisati tmp->port = GETLOPORT(portRange); 3775ff2f6fe8SPaolo Pisati r->spool_cnt++; 3776ff2f6fe8SPaolo Pisati /* Point to the next possible cfg_spool. */ 3777ff2f6fe8SPaolo Pisati spool_buf = &spool_buf[SOF_SPOOL]; 3778ff2f6fe8SPaolo Pisati sep = strtok(NULL, ","); 3779ff2f6fe8SPaolo Pisati } 3780ff2f6fe8SPaolo Pisati } 3781ff2f6fe8SPaolo Pisati return (space); 3782ff2f6fe8SPaolo Pisati nospace: 3783ff2f6fe8SPaolo Pisati errx(EX_DATAERR, "redirect_port: buf is too small\n"); 3784ff2f6fe8SPaolo Pisati } 3785ff2f6fe8SPaolo Pisati 3786ff2f6fe8SPaolo Pisati static int 3787ff2f6fe8SPaolo Pisati setup_redir_proto(char *spool_buf, int len, 3788ff2f6fe8SPaolo Pisati int *_ac, char ***_av) 3789ff2f6fe8SPaolo Pisati { 3790ff2f6fe8SPaolo Pisati char **av; 3791ff2f6fe8SPaolo Pisati int ac, i, space; 3792ff2f6fe8SPaolo Pisati struct protoent *protoent; 3793ff2f6fe8SPaolo Pisati struct cfg_redir *r; 3794ff2f6fe8SPaolo Pisati 3795ff2f6fe8SPaolo Pisati av = *_av; 3796ff2f6fe8SPaolo Pisati ac = *_ac; 3797ff2f6fe8SPaolo Pisati if (len >= SOF_REDIR) { 3798ff2f6fe8SPaolo Pisati r = (struct cfg_redir *)spool_buf; 3799ff2f6fe8SPaolo Pisati /* Skip cfg_redir at beginning of buf. */ 3800ff2f6fe8SPaolo Pisati spool_buf = &spool_buf[SOF_REDIR]; 3801ff2f6fe8SPaolo Pisati space = SOF_REDIR; 3802ff2f6fe8SPaolo Pisati len -= SOF_REDIR; 3803ff2f6fe8SPaolo Pisati } else 3804ff2f6fe8SPaolo Pisati goto nospace; 3805ff2f6fe8SPaolo Pisati r->mode = REDIR_PROTO; 3806ff2f6fe8SPaolo Pisati /* 3807ff2f6fe8SPaolo Pisati * Extract protocol. 3808ff2f6fe8SPaolo Pisati */ 3809ff2f6fe8SPaolo Pisati if (ac == 0) 3810ff2f6fe8SPaolo Pisati errx(EX_DATAERR, "redirect_proto: missing protocol"); 3811ff2f6fe8SPaolo Pisati 3812ff2f6fe8SPaolo Pisati protoent = getprotobyname(*av); 3813ff2f6fe8SPaolo Pisati if (protoent == NULL) 3814ff2f6fe8SPaolo Pisati errx(EX_DATAERR, "redirect_proto: unknown protocol %s", *av); 3815ff2f6fe8SPaolo Pisati else 3816ff2f6fe8SPaolo Pisati r->proto = protoent->p_proto; 3817ff2f6fe8SPaolo Pisati 3818ff2f6fe8SPaolo Pisati INC_ARGCV(); 3819ff2f6fe8SPaolo Pisati 3820ff2f6fe8SPaolo Pisati /* 3821ff2f6fe8SPaolo Pisati * Extract local address. 3822ff2f6fe8SPaolo Pisati */ 3823ff2f6fe8SPaolo Pisati if (ac == 0) 3824ff2f6fe8SPaolo Pisati errx(EX_DATAERR, "redirect_proto: missing local address"); 3825ff2f6fe8SPaolo Pisati else 3826ff2f6fe8SPaolo Pisati StrToAddr(*av, &r->laddr); 3827ff2f6fe8SPaolo Pisati 3828ff2f6fe8SPaolo Pisati INC_ARGCV(); 3829ff2f6fe8SPaolo Pisati 3830ff2f6fe8SPaolo Pisati /* 3831ff2f6fe8SPaolo Pisati * Extract optional public address. 3832ff2f6fe8SPaolo Pisati */ 3833ff2f6fe8SPaolo Pisati if (ac == 0) { 3834ff2f6fe8SPaolo Pisati r->paddr.s_addr = INADDR_ANY; 3835ff2f6fe8SPaolo Pisati r->raddr.s_addr = INADDR_ANY; 3836ff2f6fe8SPaolo Pisati } else { 3837ff2f6fe8SPaolo Pisati /* see above in setup_redir_port() */ 3838ff2f6fe8SPaolo Pisati if (!isalpha(**av)) { 3839ff2f6fe8SPaolo Pisati StrToAddr(*av, &r->paddr); 3840ff2f6fe8SPaolo Pisati INC_ARGCV(); 3841ff2f6fe8SPaolo Pisati 3842ff2f6fe8SPaolo Pisati /* 3843ff2f6fe8SPaolo Pisati * Extract optional remote address. 3844ff2f6fe8SPaolo Pisati */ 3845ff2f6fe8SPaolo Pisati /* see above in setup_redir_port() */ 3846ff2f6fe8SPaolo Pisati if (ac!=0 && !isalpha(**av)) { 3847ff2f6fe8SPaolo Pisati StrToAddr(*av, &r->raddr); 3848ff2f6fe8SPaolo Pisati INC_ARGCV(); 3849ff2f6fe8SPaolo Pisati } 3850ff2f6fe8SPaolo Pisati } 3851ff2f6fe8SPaolo Pisati } 3852ff2f6fe8SPaolo Pisati return (space); 3853ff2f6fe8SPaolo Pisati nospace: 3854ff2f6fe8SPaolo Pisati errx(EX_DATAERR, "redirect_proto: buf is too small\n"); 3855ff2f6fe8SPaolo Pisati } 3856ff2f6fe8SPaolo Pisati 3857ff2f6fe8SPaolo Pisati static void 3858ff2f6fe8SPaolo Pisati show_nat(int ac, char **av); 3859ff2f6fe8SPaolo Pisati 3860ff2f6fe8SPaolo Pisati static void 3861ff2f6fe8SPaolo Pisati print_nat_config(char *buf) { 3862ff2f6fe8SPaolo Pisati struct cfg_nat *n; 3863ff2f6fe8SPaolo Pisati int i, cnt, flag, off; 3864ff2f6fe8SPaolo Pisati struct cfg_redir *t; 3865ff2f6fe8SPaolo Pisati struct cfg_spool *s; 3866ff2f6fe8SPaolo Pisati struct protoent *p; 3867ff2f6fe8SPaolo Pisati 3868ff2f6fe8SPaolo Pisati n = (struct cfg_nat *)buf; 3869ff2f6fe8SPaolo Pisati flag = 1; 3870ff2f6fe8SPaolo Pisati off = sizeof(*n); 3871ff2f6fe8SPaolo Pisati printf("ipfw nat %u config", n->id); 3872ff2f6fe8SPaolo Pisati if (strlen(n->if_name) != 0) 3873ff2f6fe8SPaolo Pisati printf(" if %s", n->if_name); 3874ff2f6fe8SPaolo Pisati else if (n->ip.s_addr != 0) 3875ff2f6fe8SPaolo Pisati printf(" ip %s", inet_ntoa(n->ip)); 3876ff2f6fe8SPaolo Pisati while (n->mode != 0) { 3877ff2f6fe8SPaolo Pisati if (n->mode & PKT_ALIAS_LOG) { 3878ff2f6fe8SPaolo Pisati printf(" log"); 3879ff2f6fe8SPaolo Pisati n->mode &= ~PKT_ALIAS_LOG; 3880ff2f6fe8SPaolo Pisati } else if (n->mode & PKT_ALIAS_DENY_INCOMING) { 3881ff2f6fe8SPaolo Pisati printf(" deny_in"); 3882ff2f6fe8SPaolo Pisati n->mode &= ~PKT_ALIAS_DENY_INCOMING; 3883ff2f6fe8SPaolo Pisati } else if (n->mode & PKT_ALIAS_SAME_PORTS) { 3884ff2f6fe8SPaolo Pisati printf(" same_ports"); 3885ff2f6fe8SPaolo Pisati n->mode &= ~PKT_ALIAS_SAME_PORTS; 3886ff2f6fe8SPaolo Pisati } else if (n->mode & PKT_ALIAS_UNREGISTERED_ONLY) { 3887ff2f6fe8SPaolo Pisati printf(" unreg_only"); 3888ff2f6fe8SPaolo Pisati n->mode &= ~PKT_ALIAS_UNREGISTERED_ONLY; 3889ff2f6fe8SPaolo Pisati } else if (n->mode & PKT_ALIAS_RESET_ON_ADDR_CHANGE) { 3890ff2f6fe8SPaolo Pisati printf(" reset"); 3891ff2f6fe8SPaolo Pisati n->mode &= ~PKT_ALIAS_RESET_ON_ADDR_CHANGE; 3892ff2f6fe8SPaolo Pisati } else if (n->mode & PKT_ALIAS_REVERSE) { 3893ff2f6fe8SPaolo Pisati printf(" reverse"); 3894ff2f6fe8SPaolo Pisati n->mode &= ~PKT_ALIAS_REVERSE; 3895ff2f6fe8SPaolo Pisati } else if (n->mode & PKT_ALIAS_PROXY_ONLY) { 3896ff2f6fe8SPaolo Pisati printf(" proxy_only"); 3897ff2f6fe8SPaolo Pisati n->mode &= ~PKT_ALIAS_PROXY_ONLY; 3898ff2f6fe8SPaolo Pisati } 3899ff2f6fe8SPaolo Pisati } 3900ff2f6fe8SPaolo Pisati /* Print all the redirect's data configuration. */ 3901ff2f6fe8SPaolo Pisati for (cnt = 0; cnt < n->redir_cnt; cnt++) { 3902ff2f6fe8SPaolo Pisati t = (struct cfg_redir *)&buf[off]; 3903ff2f6fe8SPaolo Pisati off += SOF_REDIR; 3904ff2f6fe8SPaolo Pisati switch (t->mode) { 3905ff2f6fe8SPaolo Pisati case REDIR_ADDR: 3906ff2f6fe8SPaolo Pisati printf(" redirect_addr"); 3907ff2f6fe8SPaolo Pisati if (t->spool_cnt == 0) 3908ff2f6fe8SPaolo Pisati printf(" %s", inet_ntoa(t->laddr)); 3909ff2f6fe8SPaolo Pisati else 3910ff2f6fe8SPaolo Pisati for (i = 0; i < t->spool_cnt; i++) { 3911ff2f6fe8SPaolo Pisati s = (struct cfg_spool *)&buf[off]; 3912ff2f6fe8SPaolo Pisati if (i) 3913ff2f6fe8SPaolo Pisati printf(","); 3914ff2f6fe8SPaolo Pisati else 3915ff2f6fe8SPaolo Pisati printf(" "); 3916ff2f6fe8SPaolo Pisati printf("%s", inet_ntoa(s->addr)); 3917ff2f6fe8SPaolo Pisati off += SOF_SPOOL; 3918ff2f6fe8SPaolo Pisati } 3919ff2f6fe8SPaolo Pisati printf(" %s", inet_ntoa(t->paddr)); 3920ff2f6fe8SPaolo Pisati break; 3921ff2f6fe8SPaolo Pisati case REDIR_PORT: 3922ff2f6fe8SPaolo Pisati p = getprotobynumber(t->proto); 3923ff2f6fe8SPaolo Pisati printf(" redirect_port %s ", p->p_name); 3924ff2f6fe8SPaolo Pisati if (!t->spool_cnt) { 3925ff2f6fe8SPaolo Pisati printf("%s:%u", inet_ntoa(t->laddr), t->lport); 3926ff2f6fe8SPaolo Pisati if (t->pport_cnt > 1) 3927ff2f6fe8SPaolo Pisati printf("-%u", t->lport + 3928ff2f6fe8SPaolo Pisati t->pport_cnt - 1); 3929ff2f6fe8SPaolo Pisati } else 3930ff2f6fe8SPaolo Pisati for (i=0; i < t->spool_cnt; i++) { 3931ff2f6fe8SPaolo Pisati s = (struct cfg_spool *)&buf[off]; 3932ff2f6fe8SPaolo Pisati if (i) 3933ff2f6fe8SPaolo Pisati printf(","); 3934ff2f6fe8SPaolo Pisati printf("%s:%u", inet_ntoa(s->addr), 3935ff2f6fe8SPaolo Pisati s->port); 3936ff2f6fe8SPaolo Pisati off += SOF_SPOOL; 3937ff2f6fe8SPaolo Pisati } 3938ff2f6fe8SPaolo Pisati 3939ff2f6fe8SPaolo Pisati printf(" "); 3940ff2f6fe8SPaolo Pisati if (t->paddr.s_addr) 3941ff2f6fe8SPaolo Pisati printf("%s:", inet_ntoa(t->paddr)); 3942ff2f6fe8SPaolo Pisati printf("%u", t->pport); 3943ff2f6fe8SPaolo Pisati if (!t->spool_cnt && t->pport_cnt > 1) 3944ff2f6fe8SPaolo Pisati printf("-%u", t->pport + t->pport_cnt - 1); 3945ff2f6fe8SPaolo Pisati 3946ff2f6fe8SPaolo Pisati if (t->raddr.s_addr) { 3947ff2f6fe8SPaolo Pisati printf(" %s", inet_ntoa(t->raddr)); 3948ff2f6fe8SPaolo Pisati if (t->rport) { 3949ff2f6fe8SPaolo Pisati printf(":%u", t->rport); 3950ff2f6fe8SPaolo Pisati if (!t->spool_cnt && t->rport_cnt > 1) 3951ff2f6fe8SPaolo Pisati printf("-%u", t->rport + 3952ff2f6fe8SPaolo Pisati t->rport_cnt - 1); 3953ff2f6fe8SPaolo Pisati } 3954ff2f6fe8SPaolo Pisati } 3955ff2f6fe8SPaolo Pisati break; 3956ff2f6fe8SPaolo Pisati case REDIR_PROTO: 3957ff2f6fe8SPaolo Pisati p = getprotobynumber(t->proto); 3958ff2f6fe8SPaolo Pisati printf(" redirect_proto %s %s", p->p_name, 3959ff2f6fe8SPaolo Pisati inet_ntoa(t->laddr)); 3960ff2f6fe8SPaolo Pisati if (t->paddr.s_addr != 0) { 3961ff2f6fe8SPaolo Pisati printf(" %s", inet_ntoa(t->paddr)); 3962ff2f6fe8SPaolo Pisati if (t->raddr.s_addr) 3963ff2f6fe8SPaolo Pisati printf(" %s", inet_ntoa(t->raddr)); 3964ff2f6fe8SPaolo Pisati } 3965ff2f6fe8SPaolo Pisati break; 3966ff2f6fe8SPaolo Pisati default: 3967ff2f6fe8SPaolo Pisati errx(EX_DATAERR, "unknown redir mode"); 3968ff2f6fe8SPaolo Pisati break; 3969ff2f6fe8SPaolo Pisati } 3970ff2f6fe8SPaolo Pisati } 3971ff2f6fe8SPaolo Pisati printf("\n"); 3972ff2f6fe8SPaolo Pisati } 3973ff2f6fe8SPaolo Pisati 3974ff2f6fe8SPaolo Pisati static void 3975ff2f6fe8SPaolo Pisati config_nat(int ac, char **av) 3976ff2f6fe8SPaolo Pisati { 3977ff2f6fe8SPaolo Pisati struct cfg_nat *n; /* Nat instance configuration. */ 3978ff2f6fe8SPaolo Pisati struct in_addr ip; 3979ff2f6fe8SPaolo Pisati int i, len, off, tok; 3980ff2f6fe8SPaolo Pisati char *id, buf[NAT_BUF_LEN]; /* Buffer for serialized data. */ 3981ff2f6fe8SPaolo Pisati 3982ff2f6fe8SPaolo Pisati len = NAT_BUF_LEN; 3983ff2f6fe8SPaolo Pisati /* Offset in buf: save space for n at the beginning. */ 3984ff2f6fe8SPaolo Pisati off = sizeof(*n); 3985ff2f6fe8SPaolo Pisati memset(buf, 0, sizeof(buf)); 3986ff2f6fe8SPaolo Pisati n = (struct cfg_nat *)buf; 3987ff2f6fe8SPaolo Pisati 3988ff2f6fe8SPaolo Pisati av++; ac--; 3989ff2f6fe8SPaolo Pisati /* Nat id. */ 3990ff2f6fe8SPaolo Pisati if (ac && isdigit(**av)) { 3991ff2f6fe8SPaolo Pisati id = *av; 3992ff2f6fe8SPaolo Pisati i = atoi(*av); 3993ff2f6fe8SPaolo Pisati ac--; av++; 3994ff2f6fe8SPaolo Pisati n->id = i; 3995ff2f6fe8SPaolo Pisati } else 3996ff2f6fe8SPaolo Pisati errx(EX_DATAERR, "missing nat id"); 3997ff2f6fe8SPaolo Pisati if (ac == 0) 3998ff2f6fe8SPaolo Pisati errx(EX_DATAERR, "missing option"); 3999ff2f6fe8SPaolo Pisati 4000ff2f6fe8SPaolo Pisati while (ac > 0) { 4001ff2f6fe8SPaolo Pisati tok = match_token(nat_params, *av); 4002ff2f6fe8SPaolo Pisati ac--; av++; 4003ff2f6fe8SPaolo Pisati switch (tok) { 4004ff2f6fe8SPaolo Pisati case TOK_IP: 4005ff2f6fe8SPaolo Pisati if (ac == 0) 4006ff2f6fe8SPaolo Pisati errx(EX_DATAERR, "missing option"); 4007ff2f6fe8SPaolo Pisati if (!inet_aton(av[0], &(n->ip))) 4008ff2f6fe8SPaolo Pisati errx(EX_DATAERR, "bad ip address ``%s''", 4009ff2f6fe8SPaolo Pisati av[0]); 4010ff2f6fe8SPaolo Pisati ac--; av++; 4011ff2f6fe8SPaolo Pisati break; 4012ff2f6fe8SPaolo Pisati case TOK_IF: 40138c03c6c0SMaxim Konovalov if (ac == 0) 40148c03c6c0SMaxim Konovalov errx(EX_DATAERR, "missing option"); 4015ff2f6fe8SPaolo Pisati set_addr_dynamic(av[0], n); 4016ff2f6fe8SPaolo Pisati ac--; av++; 4017ff2f6fe8SPaolo Pisati break; 4018ff2f6fe8SPaolo Pisati case TOK_ALOG: 4019ff2f6fe8SPaolo Pisati n->mode |= PKT_ALIAS_LOG; 4020ff2f6fe8SPaolo Pisati break; 4021ff2f6fe8SPaolo Pisati case TOK_DENY_INC: 4022ff2f6fe8SPaolo Pisati n->mode |= PKT_ALIAS_DENY_INCOMING; 4023ff2f6fe8SPaolo Pisati break; 4024ff2f6fe8SPaolo Pisati case TOK_SAME_PORTS: 4025ff2f6fe8SPaolo Pisati n->mode |= PKT_ALIAS_SAME_PORTS; 4026ff2f6fe8SPaolo Pisati break; 4027ff2f6fe8SPaolo Pisati case TOK_UNREG_ONLY: 4028ff2f6fe8SPaolo Pisati n->mode |= PKT_ALIAS_UNREGISTERED_ONLY; 4029ff2f6fe8SPaolo Pisati break; 4030ff2f6fe8SPaolo Pisati case TOK_RESET_ADDR: 4031ff2f6fe8SPaolo Pisati n->mode |= PKT_ALIAS_RESET_ON_ADDR_CHANGE; 4032ff2f6fe8SPaolo Pisati break; 4033ff2f6fe8SPaolo Pisati case TOK_ALIAS_REV: 4034ff2f6fe8SPaolo Pisati n->mode |= PKT_ALIAS_REVERSE; 4035ff2f6fe8SPaolo Pisati break; 4036ff2f6fe8SPaolo Pisati case TOK_PROXY_ONLY: 4037ff2f6fe8SPaolo Pisati n->mode |= PKT_ALIAS_PROXY_ONLY; 4038ff2f6fe8SPaolo Pisati break; 4039ff2f6fe8SPaolo Pisati /* 4040ff2f6fe8SPaolo Pisati * All the setup_redir_* functions work directly in the final 4041ff2f6fe8SPaolo Pisati * buffer, see above for details. 4042ff2f6fe8SPaolo Pisati */ 4043ff2f6fe8SPaolo Pisati case TOK_REDIR_ADDR: 4044ff2f6fe8SPaolo Pisati case TOK_REDIR_PORT: 4045ff2f6fe8SPaolo Pisati case TOK_REDIR_PROTO: 4046ff2f6fe8SPaolo Pisati switch (tok) { 4047ff2f6fe8SPaolo Pisati case TOK_REDIR_ADDR: 4048ff2f6fe8SPaolo Pisati i = setup_redir_addr(&buf[off], len, &ac, &av); 4049ff2f6fe8SPaolo Pisati break; 4050ff2f6fe8SPaolo Pisati case TOK_REDIR_PORT: 4051ff2f6fe8SPaolo Pisati i = setup_redir_port(&buf[off], len, &ac, &av); 4052ff2f6fe8SPaolo Pisati break; 4053ff2f6fe8SPaolo Pisati case TOK_REDIR_PROTO: 4054ff2f6fe8SPaolo Pisati i = setup_redir_proto(&buf[off], len, &ac, &av); 4055ff2f6fe8SPaolo Pisati break; 4056ff2f6fe8SPaolo Pisati } 4057ff2f6fe8SPaolo Pisati n->redir_cnt++; 4058ff2f6fe8SPaolo Pisati off += i; 4059ff2f6fe8SPaolo Pisati len -= i; 4060ff2f6fe8SPaolo Pisati break; 4061ff2f6fe8SPaolo Pisati default: 4062ff2f6fe8SPaolo Pisati errx(EX_DATAERR, "unrecognised option ``%s''", av[-1]); 4063ff2f6fe8SPaolo Pisati } 4064ff2f6fe8SPaolo Pisati } 4065ff2f6fe8SPaolo Pisati 4066ff2f6fe8SPaolo Pisati i = do_cmd(IP_FW_NAT_CFG, buf, off); 4067ff2f6fe8SPaolo Pisati if (i) 4068ff2f6fe8SPaolo Pisati err(1, "setsockopt(%s)", "IP_FW_NAT_CFG"); 4069ff2f6fe8SPaolo Pisati 4070ff2f6fe8SPaolo Pisati /* After every modification, we show the resultant rule. */ 4071ff2f6fe8SPaolo Pisati int _ac = 3; 4072ff2f6fe8SPaolo Pisati char *_av[] = {"show", "config", id}; 4073ff2f6fe8SPaolo Pisati show_nat(_ac, _av); 4074ff2f6fe8SPaolo Pisati } 4075ff2f6fe8SPaolo Pisati 40769758b77fSLuigi Rizzo static void 40779758b77fSLuigi Rizzo config_pipe(int ac, char **av) 40789758b77fSLuigi Rizzo { 407962ff38aeSLuigi Rizzo struct dn_pipe p; 40809758b77fSLuigi Rizzo int i; 40819758b77fSLuigi Rizzo char *end; 40829758b77fSLuigi Rizzo void *par = NULL; 40839758b77fSLuigi Rizzo 408462ff38aeSLuigi Rizzo memset(&p, 0, sizeof p); 40859758b77fSLuigi Rizzo 40869758b77fSLuigi Rizzo av++; ac--; 40879758b77fSLuigi Rizzo /* Pipe number */ 40889758b77fSLuigi Rizzo if (ac && isdigit(**av)) { 40899758b77fSLuigi Rizzo i = atoi(*av); av++; ac--; 40909758b77fSLuigi Rizzo if (do_pipe == 1) 409162ff38aeSLuigi Rizzo p.pipe_nr = i; 40929758b77fSLuigi Rizzo else 409362ff38aeSLuigi Rizzo p.fs.fs_nr = i; 40949758b77fSLuigi Rizzo } 40955e43aef8SLuigi Rizzo while (ac > 0) { 40969758b77fSLuigi Rizzo double d; 40979758b77fSLuigi Rizzo int tok = match_token(dummynet_params, *av); 40989758b77fSLuigi Rizzo ac--; av++; 40999758b77fSLuigi Rizzo 41009758b77fSLuigi Rizzo switch(tok) { 410199e5e645SLuigi Rizzo case TOK_NOERROR: 410262ff38aeSLuigi Rizzo p.fs.flags_fs |= DN_NOERROR; 410399e5e645SLuigi Rizzo break; 410499e5e645SLuigi Rizzo 41059758b77fSLuigi Rizzo case TOK_PLR: 41069758b77fSLuigi Rizzo NEED1("plr needs argument 0..1\n"); 41079758b77fSLuigi Rizzo d = strtod(av[0], NULL); 41089758b77fSLuigi Rizzo if (d > 1) 41099758b77fSLuigi Rizzo d = 1; 41109758b77fSLuigi Rizzo else if (d < 0) 41119758b77fSLuigi Rizzo d = 0; 411262ff38aeSLuigi Rizzo p.fs.plr = (int)(d*0x7fffffff); 41139758b77fSLuigi Rizzo ac--; av++; 41149758b77fSLuigi Rizzo break; 41159758b77fSLuigi Rizzo 41169758b77fSLuigi Rizzo case TOK_QUEUE: 41179758b77fSLuigi Rizzo NEED1("queue needs queue size\n"); 41189758b77fSLuigi Rizzo end = NULL; 411962ff38aeSLuigi Rizzo p.fs.qsize = strtoul(av[0], &end, 0); 41209758b77fSLuigi Rizzo if (*end == 'K' || *end == 'k') { 412162ff38aeSLuigi Rizzo p.fs.flags_fs |= DN_QSIZE_IS_BYTES; 412262ff38aeSLuigi Rizzo p.fs.qsize *= 1024; 412301750186SBrooks Davis } else if (*end == 'B' || 412401750186SBrooks Davis _substrcmp2(end, "by", "bytes") == 0) { 412562ff38aeSLuigi Rizzo p.fs.flags_fs |= DN_QSIZE_IS_BYTES; 41269758b77fSLuigi Rizzo } 41279758b77fSLuigi Rizzo ac--; av++; 41289758b77fSLuigi Rizzo break; 41299758b77fSLuigi Rizzo 41309758b77fSLuigi Rizzo case TOK_BUCKETS: 41319758b77fSLuigi Rizzo NEED1("buckets needs argument\n"); 413262ff38aeSLuigi Rizzo p.fs.rq_size = strtoul(av[0], NULL, 0); 41339758b77fSLuigi Rizzo ac--; av++; 41349758b77fSLuigi Rizzo break; 41359758b77fSLuigi Rizzo 41369758b77fSLuigi Rizzo case TOK_MASK: 41379758b77fSLuigi Rizzo NEED1("mask needs mask specifier\n"); 41389758b77fSLuigi Rizzo /* 41399758b77fSLuigi Rizzo * per-flow queue, mask is dst_ip, dst_port, 41409758b77fSLuigi Rizzo * src_ip, src_port, proto measured in bits 41419758b77fSLuigi Rizzo */ 41429758b77fSLuigi Rizzo par = NULL; 41439758b77fSLuigi Rizzo 41448195404bSBrooks Davis bzero(&p.fs.flow_mask, sizeof(p.fs.flow_mask)); 41459758b77fSLuigi Rizzo end = NULL; 41469758b77fSLuigi Rizzo 41479758b77fSLuigi Rizzo while (ac >= 1) { 4148571f8c1bSLuigi Rizzo uint32_t *p32 = NULL; 4149571f8c1bSLuigi Rizzo uint16_t *p16 = NULL; 41508195404bSBrooks Davis uint32_t *p20 = NULL; 41518195404bSBrooks Davis struct in6_addr *pa6 = NULL; 41528195404bSBrooks Davis uint32_t a; 41539758b77fSLuigi Rizzo 41549758b77fSLuigi Rizzo tok = match_token(dummynet_params, *av); 41559758b77fSLuigi Rizzo ac--; av++; 41569758b77fSLuigi Rizzo switch(tok) { 41579758b77fSLuigi Rizzo case TOK_ALL: 41589758b77fSLuigi Rizzo /* 41599758b77fSLuigi Rizzo * special case, all bits significant 41609758b77fSLuigi Rizzo */ 416162ff38aeSLuigi Rizzo p.fs.flow_mask.dst_ip = ~0; 416262ff38aeSLuigi Rizzo p.fs.flow_mask.src_ip = ~0; 416362ff38aeSLuigi Rizzo p.fs.flow_mask.dst_port = ~0; 416462ff38aeSLuigi Rizzo p.fs.flow_mask.src_port = ~0; 416562ff38aeSLuigi Rizzo p.fs.flow_mask.proto = ~0; 41668195404bSBrooks Davis n2mask(&(p.fs.flow_mask.dst_ip6), 128); 41678195404bSBrooks Davis n2mask(&(p.fs.flow_mask.src_ip6), 128); 41688195404bSBrooks Davis p.fs.flow_mask.flow_id6 = ~0; 416962ff38aeSLuigi Rizzo p.fs.flags_fs |= DN_HAVE_FLOW_MASK; 41709758b77fSLuigi Rizzo goto end_mask; 41719758b77fSLuigi Rizzo 41729758b77fSLuigi Rizzo case TOK_DSTIP: 417362ff38aeSLuigi Rizzo p32 = &p.fs.flow_mask.dst_ip; 41749758b77fSLuigi Rizzo break; 41759758b77fSLuigi Rizzo 41769758b77fSLuigi Rizzo case TOK_SRCIP: 417762ff38aeSLuigi Rizzo p32 = &p.fs.flow_mask.src_ip; 41789758b77fSLuigi Rizzo break; 41799758b77fSLuigi Rizzo 41808195404bSBrooks Davis case TOK_DSTIP6: 41818195404bSBrooks Davis pa6 = &(p.fs.flow_mask.dst_ip6); 41828195404bSBrooks Davis break; 41838195404bSBrooks Davis 41848195404bSBrooks Davis case TOK_SRCIP6: 41858195404bSBrooks Davis pa6 = &(p.fs.flow_mask.src_ip6); 41868195404bSBrooks Davis break; 41878195404bSBrooks Davis 41888195404bSBrooks Davis case TOK_FLOWID: 41898195404bSBrooks Davis p20 = &p.fs.flow_mask.flow_id6; 41908195404bSBrooks Davis break; 41918195404bSBrooks Davis 41929758b77fSLuigi Rizzo case TOK_DSTPORT: 419362ff38aeSLuigi Rizzo p16 = &p.fs.flow_mask.dst_port; 41949758b77fSLuigi Rizzo break; 41959758b77fSLuigi Rizzo 41969758b77fSLuigi Rizzo case TOK_SRCPORT: 419762ff38aeSLuigi Rizzo p16 = &p.fs.flow_mask.src_port; 41989758b77fSLuigi Rizzo break; 41999758b77fSLuigi Rizzo 42009758b77fSLuigi Rizzo case TOK_PROTO: 42019758b77fSLuigi Rizzo break; 42029758b77fSLuigi Rizzo 42039758b77fSLuigi Rizzo default: 42049758b77fSLuigi Rizzo ac++; av--; /* backtrack */ 42059758b77fSLuigi Rizzo goto end_mask; 42069758b77fSLuigi Rizzo } 42079758b77fSLuigi Rizzo if (ac < 1) 42089758b77fSLuigi Rizzo errx(EX_USAGE, "mask: value missing"); 42099758b77fSLuigi Rizzo if (*av[0] == '/') { 42109758b77fSLuigi Rizzo a = strtoul(av[0]+1, &end, 0); 42118195404bSBrooks Davis if (pa6 == NULL) 42129758b77fSLuigi Rizzo a = (a == 32) ? ~0 : (1 << a) - 1; 42139758b77fSLuigi Rizzo } else 42140a7197a8SLuigi Rizzo a = strtoul(av[0], &end, 0); 42159758b77fSLuigi Rizzo if (p32 != NULL) 42169758b77fSLuigi Rizzo *p32 = a; 42179758b77fSLuigi Rizzo else if (p16 != NULL) { 4218610055c9SBrooks Davis if (a > 0xFFFF) 42199758b77fSLuigi Rizzo errx(EX_DATAERR, 4220776c1005SBrooks Davis "port mask must be 16 bit"); 4221571f8c1bSLuigi Rizzo *p16 = (uint16_t)a; 42228195404bSBrooks Davis } else if (p20 != NULL) { 42238195404bSBrooks Davis if (a > 0xfffff) 42248195404bSBrooks Davis errx(EX_DATAERR, 42258195404bSBrooks Davis "flow_id mask must be 20 bit"); 42268195404bSBrooks Davis *p20 = (uint32_t)a; 42278195404bSBrooks Davis } else if (pa6 != NULL) { 42288195404bSBrooks Davis if (a < 0 || a > 128) 42298195404bSBrooks Davis errx(EX_DATAERR, 42308195404bSBrooks Davis "in6addr invalid mask len"); 42318195404bSBrooks Davis else 42328195404bSBrooks Davis n2mask(pa6, a); 42339758b77fSLuigi Rizzo } else { 4234610055c9SBrooks Davis if (a > 0xFF) 42359758b77fSLuigi Rizzo errx(EX_DATAERR, 4236776c1005SBrooks Davis "proto mask must be 8 bit"); 423762ff38aeSLuigi Rizzo p.fs.flow_mask.proto = (uint8_t)a; 42389758b77fSLuigi Rizzo } 42399758b77fSLuigi Rizzo if (a != 0) 424062ff38aeSLuigi Rizzo p.fs.flags_fs |= DN_HAVE_FLOW_MASK; 42419758b77fSLuigi Rizzo ac--; av++; 42429758b77fSLuigi Rizzo } /* end while, config masks */ 42439758b77fSLuigi Rizzo end_mask: 42449758b77fSLuigi Rizzo break; 42459758b77fSLuigi Rizzo 42469758b77fSLuigi Rizzo case TOK_RED: 42479758b77fSLuigi Rizzo case TOK_GRED: 42489758b77fSLuigi Rizzo NEED1("red/gred needs w_q/min_th/max_th/max_p\n"); 424962ff38aeSLuigi Rizzo p.fs.flags_fs |= DN_IS_RED; 42509758b77fSLuigi Rizzo if (tok == TOK_GRED) 425162ff38aeSLuigi Rizzo p.fs.flags_fs |= DN_IS_GENTLE_RED; 42529758b77fSLuigi Rizzo /* 42539758b77fSLuigi Rizzo * the format for parameters is w_q/min_th/max_th/max_p 42549758b77fSLuigi Rizzo */ 42559758b77fSLuigi Rizzo if ((end = strsep(&av[0], "/"))) { 42569758b77fSLuigi Rizzo double w_q = strtod(end, NULL); 42579758b77fSLuigi Rizzo if (w_q > 1 || w_q <= 0) 42589758b77fSLuigi Rizzo errx(EX_DATAERR, "0 < w_q <= 1"); 425962ff38aeSLuigi Rizzo p.fs.w_q = (int) (w_q * (1 << SCALE_RED)); 42609758b77fSLuigi Rizzo } 42619758b77fSLuigi Rizzo if ((end = strsep(&av[0], "/"))) { 426262ff38aeSLuigi Rizzo p.fs.min_th = strtoul(end, &end, 0); 42639758b77fSLuigi Rizzo if (*end == 'K' || *end == 'k') 426462ff38aeSLuigi Rizzo p.fs.min_th *= 1024; 42659758b77fSLuigi Rizzo } 42669758b77fSLuigi Rizzo if ((end = strsep(&av[0], "/"))) { 426762ff38aeSLuigi Rizzo p.fs.max_th = strtoul(end, &end, 0); 42689758b77fSLuigi Rizzo if (*end == 'K' || *end == 'k') 426962ff38aeSLuigi Rizzo p.fs.max_th *= 1024; 42709758b77fSLuigi Rizzo } 42719758b77fSLuigi Rizzo if ((end = strsep(&av[0], "/"))) { 42729758b77fSLuigi Rizzo double max_p = strtod(end, NULL); 42739758b77fSLuigi Rizzo if (max_p > 1 || max_p <= 0) 42749758b77fSLuigi Rizzo errx(EX_DATAERR, "0 < max_p <= 1"); 427562ff38aeSLuigi Rizzo p.fs.max_p = (int)(max_p * (1 << SCALE_RED)); 42769758b77fSLuigi Rizzo } 42779758b77fSLuigi Rizzo ac--; av++; 42789758b77fSLuigi Rizzo break; 42799758b77fSLuigi Rizzo 42809758b77fSLuigi Rizzo case TOK_DROPTAIL: 428162ff38aeSLuigi Rizzo p.fs.flags_fs &= ~(DN_IS_RED|DN_IS_GENTLE_RED); 42829758b77fSLuigi Rizzo break; 42839758b77fSLuigi Rizzo 42849758b77fSLuigi Rizzo case TOK_BW: 42859758b77fSLuigi Rizzo NEED1("bw needs bandwidth or interface\n"); 42869758b77fSLuigi Rizzo if (do_pipe != 1) 42879758b77fSLuigi Rizzo errx(EX_DATAERR, "bandwidth only valid for pipes"); 42889758b77fSLuigi Rizzo /* 42899758b77fSLuigi Rizzo * set clocking interface or bandwidth value 42909758b77fSLuigi Rizzo */ 42919758b77fSLuigi Rizzo if (av[0][0] >= 'a' && av[0][0] <= 'z') { 429262ff38aeSLuigi Rizzo int l = sizeof(p.if_name)-1; 42939758b77fSLuigi Rizzo /* interface name */ 429462ff38aeSLuigi Rizzo strncpy(p.if_name, av[0], l); 429562ff38aeSLuigi Rizzo p.if_name[l] = '\0'; 429662ff38aeSLuigi Rizzo p.bandwidth = 0; 42979758b77fSLuigi Rizzo } else { 429862ff38aeSLuigi Rizzo p.if_name[0] = '\0'; 429962ff38aeSLuigi Rizzo p.bandwidth = strtoul(av[0], &end, 0); 43009758b77fSLuigi Rizzo if (*end == 'K' || *end == 'k') { 43019758b77fSLuigi Rizzo end++; 430262ff38aeSLuigi Rizzo p.bandwidth *= 1000; 43039758b77fSLuigi Rizzo } else if (*end == 'M') { 43049758b77fSLuigi Rizzo end++; 430562ff38aeSLuigi Rizzo p.bandwidth *= 1000000; 43069758b77fSLuigi Rizzo } 4307cb0bfd9bSDavid Malone if ((*end == 'B' && 4308cb0bfd9bSDavid Malone _substrcmp2(end, "Bi", "Bit/s") != 0) || 430901750186SBrooks Davis _substrcmp2(end, "by", "bytes") == 0) 431062ff38aeSLuigi Rizzo p.bandwidth *= 8; 431162ff38aeSLuigi Rizzo if (p.bandwidth < 0) 43129758b77fSLuigi Rizzo errx(EX_DATAERR, "bandwidth too large"); 43139758b77fSLuigi Rizzo } 43149758b77fSLuigi Rizzo ac--; av++; 43159758b77fSLuigi Rizzo break; 43169758b77fSLuigi Rizzo 43179758b77fSLuigi Rizzo case TOK_DELAY: 43189758b77fSLuigi Rizzo if (do_pipe != 1) 43199758b77fSLuigi Rizzo errx(EX_DATAERR, "delay only valid for pipes"); 43209758b77fSLuigi Rizzo NEED1("delay needs argument 0..10000ms\n"); 432162ff38aeSLuigi Rizzo p.delay = strtoul(av[0], NULL, 0); 43229758b77fSLuigi Rizzo ac--; av++; 43239758b77fSLuigi Rizzo break; 43249758b77fSLuigi Rizzo 43259758b77fSLuigi Rizzo case TOK_WEIGHT: 43269758b77fSLuigi Rizzo if (do_pipe == 1) 43279758b77fSLuigi Rizzo errx(EX_DATAERR,"weight only valid for queues"); 43289758b77fSLuigi Rizzo NEED1("weight needs argument 0..100\n"); 432962ff38aeSLuigi Rizzo p.fs.weight = strtoul(av[0], &end, 0); 43309758b77fSLuigi Rizzo ac--; av++; 43319758b77fSLuigi Rizzo break; 43329758b77fSLuigi Rizzo 43339758b77fSLuigi Rizzo case TOK_PIPE: 43349758b77fSLuigi Rizzo if (do_pipe == 1) 43359758b77fSLuigi Rizzo errx(EX_DATAERR,"pipe only valid for queues"); 43369758b77fSLuigi Rizzo NEED1("pipe needs pipe_number\n"); 433762ff38aeSLuigi Rizzo p.fs.parent_nr = strtoul(av[0], &end, 0); 43389758b77fSLuigi Rizzo ac--; av++; 43399758b77fSLuigi Rizzo break; 43409758b77fSLuigi Rizzo 43419758b77fSLuigi Rizzo default: 434266d217f8SMaxim Konovalov errx(EX_DATAERR, "unrecognised option ``%s''", av[-1]); 43439758b77fSLuigi Rizzo } 43449758b77fSLuigi Rizzo } 43459758b77fSLuigi Rizzo if (do_pipe == 1) { 434662ff38aeSLuigi Rizzo if (p.pipe_nr == 0) 43479758b77fSLuigi Rizzo errx(EX_DATAERR, "pipe_nr must be > 0"); 434862ff38aeSLuigi Rizzo if (p.delay > 10000) 43499758b77fSLuigi Rizzo errx(EX_DATAERR, "delay must be < 10000"); 43509758b77fSLuigi Rizzo } else { /* do_pipe == 2, queue */ 435162ff38aeSLuigi Rizzo if (p.fs.parent_nr == 0) 43529758b77fSLuigi Rizzo errx(EX_DATAERR, "pipe must be > 0"); 435362ff38aeSLuigi Rizzo if (p.fs.weight >100) 43549758b77fSLuigi Rizzo errx(EX_DATAERR, "weight must be <= 100"); 43559758b77fSLuigi Rizzo } 435662ff38aeSLuigi Rizzo if (p.fs.flags_fs & DN_QSIZE_IS_BYTES) { 43572b2c3b23SDavid Malone size_t len; 43582b2c3b23SDavid Malone long limit; 43592b2c3b23SDavid Malone 43602b2c3b23SDavid Malone len = sizeof(limit); 43612b2c3b23SDavid Malone if (sysctlbyname("net.inet.ip.dummynet.pipe_byte_limit", 43622b2c3b23SDavid Malone &limit, &len, NULL, 0) == -1) 43632b2c3b23SDavid Malone limit = 1024*1024; 43642b2c3b23SDavid Malone if (p.fs.qsize > limit) 43652b2c3b23SDavid Malone errx(EX_DATAERR, "queue size must be < %ldB", limit); 43669758b77fSLuigi Rizzo } else { 43672b2c3b23SDavid Malone size_t len; 43682b2c3b23SDavid Malone long limit; 43692b2c3b23SDavid Malone 43702b2c3b23SDavid Malone len = sizeof(limit); 43712b2c3b23SDavid Malone if (sysctlbyname("net.inet.ip.dummynet.pipe_slot_limit", 43722b2c3b23SDavid Malone &limit, &len, NULL, 0) == -1) 43732b2c3b23SDavid Malone limit = 100; 43742b2c3b23SDavid Malone if (p.fs.qsize > limit) 43752b2c3b23SDavid Malone errx(EX_DATAERR, "2 <= queue size <= %ld", limit); 43769758b77fSLuigi Rizzo } 437762ff38aeSLuigi Rizzo if (p.fs.flags_fs & DN_IS_RED) { 43789758b77fSLuigi Rizzo size_t len; 43799758b77fSLuigi Rizzo int lookup_depth, avg_pkt_size; 43809758b77fSLuigi Rizzo double s, idle, weight, w_q; 438162ff38aeSLuigi Rizzo struct clockinfo ck; 43829758b77fSLuigi Rizzo int t; 43839758b77fSLuigi Rizzo 438462ff38aeSLuigi Rizzo if (p.fs.min_th >= p.fs.max_th) 43859758b77fSLuigi Rizzo errx(EX_DATAERR, "min_th %d must be < than max_th %d", 438662ff38aeSLuigi Rizzo p.fs.min_th, p.fs.max_th); 438762ff38aeSLuigi Rizzo if (p.fs.max_th == 0) 43889758b77fSLuigi Rizzo errx(EX_DATAERR, "max_th must be > 0"); 43899758b77fSLuigi Rizzo 43909758b77fSLuigi Rizzo len = sizeof(int); 43919758b77fSLuigi Rizzo if (sysctlbyname("net.inet.ip.dummynet.red_lookup_depth", 43929758b77fSLuigi Rizzo &lookup_depth, &len, NULL, 0) == -1) 43939758b77fSLuigi Rizzo errx(1, "sysctlbyname(\"%s\")", 43949758b77fSLuigi Rizzo "net.inet.ip.dummynet.red_lookup_depth"); 43959758b77fSLuigi Rizzo if (lookup_depth == 0) 43969758b77fSLuigi Rizzo errx(EX_DATAERR, "net.inet.ip.dummynet.red_lookup_depth" 43979758b77fSLuigi Rizzo " must be greater than zero"); 43989758b77fSLuigi Rizzo 43999758b77fSLuigi Rizzo len = sizeof(int); 44009758b77fSLuigi Rizzo if (sysctlbyname("net.inet.ip.dummynet.red_avg_pkt_size", 44019758b77fSLuigi Rizzo &avg_pkt_size, &len, NULL, 0) == -1) 44029758b77fSLuigi Rizzo 44039758b77fSLuigi Rizzo errx(1, "sysctlbyname(\"%s\")", 44049758b77fSLuigi Rizzo "net.inet.ip.dummynet.red_avg_pkt_size"); 44059758b77fSLuigi Rizzo if (avg_pkt_size == 0) 44069758b77fSLuigi Rizzo errx(EX_DATAERR, 44079758b77fSLuigi Rizzo "net.inet.ip.dummynet.red_avg_pkt_size must" 44089758b77fSLuigi Rizzo " be greater than zero"); 44099758b77fSLuigi Rizzo 44109758b77fSLuigi Rizzo len = sizeof(struct clockinfo); 441162ff38aeSLuigi Rizzo if (sysctlbyname("kern.clockrate", &ck, &len, NULL, 0) == -1) 44129758b77fSLuigi Rizzo errx(1, "sysctlbyname(\"%s\")", "kern.clockrate"); 44139758b77fSLuigi Rizzo 44149758b77fSLuigi Rizzo /* 44159758b77fSLuigi Rizzo * Ticks needed for sending a medium-sized packet. 44169758b77fSLuigi Rizzo * Unfortunately, when we are configuring a WF2Q+ queue, we 44179758b77fSLuigi Rizzo * do not have bandwidth information, because that is stored 44189758b77fSLuigi Rizzo * in the parent pipe, and also we have multiple queues 44199758b77fSLuigi Rizzo * competing for it. So we set s=0, which is not very 44209758b77fSLuigi Rizzo * correct. But on the other hand, why do we want RED with 44219758b77fSLuigi Rizzo * WF2Q+ ? 44229758b77fSLuigi Rizzo */ 442362ff38aeSLuigi Rizzo if (p.bandwidth==0) /* this is a WF2Q+ queue */ 44249758b77fSLuigi Rizzo s = 0; 44259758b77fSLuigi Rizzo else 4426d60810f2SOleg Bulyzhin s = (double)ck.hz * avg_pkt_size * 8 / p.bandwidth; 44279758b77fSLuigi Rizzo 44289758b77fSLuigi Rizzo /* 44299758b77fSLuigi Rizzo * max idle time (in ticks) before avg queue size becomes 0. 44309758b77fSLuigi Rizzo * NOTA: (3/w_q) is approx the value x so that 44319758b77fSLuigi Rizzo * (1-w_q)^x < 10^-3. 44329758b77fSLuigi Rizzo */ 443362ff38aeSLuigi Rizzo w_q = ((double)p.fs.w_q) / (1 << SCALE_RED); 44349758b77fSLuigi Rizzo idle = s * 3. / w_q; 443562ff38aeSLuigi Rizzo p.fs.lookup_step = (int)idle / lookup_depth; 443662ff38aeSLuigi Rizzo if (!p.fs.lookup_step) 443762ff38aeSLuigi Rizzo p.fs.lookup_step = 1; 44389758b77fSLuigi Rizzo weight = 1 - w_q; 4439d60810f2SOleg Bulyzhin for (t = p.fs.lookup_step; t > 1; --t) 4440d60810f2SOleg Bulyzhin weight *= 1 - w_q; 444162ff38aeSLuigi Rizzo p.fs.lookup_weight = (int)(weight * (1 << SCALE_RED)); 44429758b77fSLuigi Rizzo } 444362ff38aeSLuigi Rizzo i = do_cmd(IP_DUMMYNET_CONFIGURE, &p, sizeof p); 44449758b77fSLuigi Rizzo if (i) 44459758b77fSLuigi Rizzo err(1, "setsockopt(%s)", "IP_DUMMYNET_CONFIGURE"); 44469758b77fSLuigi Rizzo } 44479758b77fSLuigi Rizzo 44489758b77fSLuigi Rizzo static void 4449bd1d3456SMaxim Konovalov get_mac_addr_mask(const char *p, uint8_t *addr, uint8_t *mask) 44509758b77fSLuigi Rizzo { 44519758b77fSLuigi Rizzo int i, l; 4452bd1d3456SMaxim Konovalov char *ap, *ptr, *optr; 4453bd1d3456SMaxim Konovalov struct ether_addr *mac; 4454bd1d3456SMaxim Konovalov const char *macset = "0123456789abcdefABCDEF:"; 44559758b77fSLuigi Rizzo 4456bd1d3456SMaxim Konovalov if (strcmp(p, "any") == 0) { 4457bd1d3456SMaxim Konovalov for (i = 0; i < ETHER_ADDR_LEN; i++) 44589758b77fSLuigi Rizzo addr[i] = mask[i] = 0; 44599758b77fSLuigi Rizzo return; 4460bd1d3456SMaxim Konovalov } 44619758b77fSLuigi Rizzo 4462bd1d3456SMaxim Konovalov optr = ptr = strdup(p); 4463bd1d3456SMaxim Konovalov if ((ap = strsep(&ptr, "&/")) != NULL && *ap != 0) { 4464bd1d3456SMaxim Konovalov l = strlen(ap); 4465bd1d3456SMaxim Konovalov if (strspn(ap, macset) != l || (mac = ether_aton(ap)) == NULL) 4466bd1d3456SMaxim Konovalov errx(EX_DATAERR, "Incorrect MAC address"); 4467bd1d3456SMaxim Konovalov bcopy(mac, addr, ETHER_ADDR_LEN); 4468bd1d3456SMaxim Konovalov } else 4469bd1d3456SMaxim Konovalov errx(EX_DATAERR, "Incorrect MAC address"); 4470bd1d3456SMaxim Konovalov 4471bd1d3456SMaxim Konovalov if (ptr != NULL) { /* we have mask? */ 4472bd1d3456SMaxim Konovalov if (p[ptr - optr - 1] == '/') { /* mask len */ 4473bd1d3456SMaxim Konovalov l = strtol(ptr, &ap, 10); 4474bd1d3456SMaxim Konovalov if (*ap != 0 || l > ETHER_ADDR_LEN * 8 || l < 0) 4475bd1d3456SMaxim Konovalov errx(EX_DATAERR, "Incorrect mask length"); 4476bd1d3456SMaxim Konovalov for (i = 0; l > 0 && i < ETHER_ADDR_LEN; l -= 8, i++) 44779758b77fSLuigi Rizzo mask[i] = (l >= 8) ? 0xff: (~0) << (8 - l); 4478bd1d3456SMaxim Konovalov } else { /* mask */ 4479bd1d3456SMaxim Konovalov l = strlen(ptr); 4480bd1d3456SMaxim Konovalov if (strspn(ptr, macset) != l || 4481bd1d3456SMaxim Konovalov (mac = ether_aton(ptr)) == NULL) 4482bd1d3456SMaxim Konovalov errx(EX_DATAERR, "Incorrect mask"); 4483bd1d3456SMaxim Konovalov bcopy(mac, mask, ETHER_ADDR_LEN); 44849758b77fSLuigi Rizzo } 4485bd1d3456SMaxim Konovalov } else { /* default mask: ff:ff:ff:ff:ff:ff */ 4486bd1d3456SMaxim Konovalov for (i = 0; i < ETHER_ADDR_LEN; i++) 44879758b77fSLuigi Rizzo mask[i] = 0xff; 44889758b77fSLuigi Rizzo } 4489bd1d3456SMaxim Konovalov for (i = 0; i < ETHER_ADDR_LEN; i++) 44909758b77fSLuigi Rizzo addr[i] &= mask[i]; 4491bd1d3456SMaxim Konovalov 4492bd1d3456SMaxim Konovalov free(optr); 44939758b77fSLuigi Rizzo } 44949758b77fSLuigi Rizzo 44959758b77fSLuigi Rizzo /* 44969758b77fSLuigi Rizzo * helper function, updates the pointer to cmd with the length 44979758b77fSLuigi Rizzo * of the current command, and also cleans up the first word of 44989758b77fSLuigi Rizzo * the new command in case it has been clobbered before. 44999758b77fSLuigi Rizzo */ 45009758b77fSLuigi Rizzo static ipfw_insn * 45019758b77fSLuigi Rizzo next_cmd(ipfw_insn *cmd) 45029758b77fSLuigi Rizzo { 45039758b77fSLuigi Rizzo cmd += F_LEN(cmd); 45049758b77fSLuigi Rizzo bzero(cmd, sizeof(*cmd)); 45059758b77fSLuigi Rizzo return cmd; 45069758b77fSLuigi Rizzo } 45079758b77fSLuigi Rizzo 45089758b77fSLuigi Rizzo /* 450962ff38aeSLuigi Rizzo * Takes arguments and copies them into a comment 451062ff38aeSLuigi Rizzo */ 451162ff38aeSLuigi Rizzo static void 451262ff38aeSLuigi Rizzo fill_comment(ipfw_insn *cmd, int ac, char **av) 451362ff38aeSLuigi Rizzo { 451462ff38aeSLuigi Rizzo int i, l; 451562ff38aeSLuigi Rizzo char *p = (char *)(cmd + 1); 451662ff38aeSLuigi Rizzo 451762ff38aeSLuigi Rizzo cmd->opcode = O_NOP; 451862ff38aeSLuigi Rizzo cmd->len = (cmd->len & (F_NOT | F_OR)); 451962ff38aeSLuigi Rizzo 452062ff38aeSLuigi Rizzo /* Compute length of comment string. */ 452162ff38aeSLuigi Rizzo for (i = 0, l = 0; i < ac; i++) 452262ff38aeSLuigi Rizzo l += strlen(av[i]) + 1; 452362ff38aeSLuigi Rizzo if (l == 0) 452462ff38aeSLuigi Rizzo return; 452562ff38aeSLuigi Rizzo if (l > 84) 452662ff38aeSLuigi Rizzo errx(EX_DATAERR, 452762ff38aeSLuigi Rizzo "comment too long (max 80 chars)"); 452862ff38aeSLuigi Rizzo l = 1 + (l+3)/4; 452962ff38aeSLuigi Rizzo cmd->len = (cmd->len & (F_NOT | F_OR)) | l; 453062ff38aeSLuigi Rizzo for (i = 0; i < ac; i++) { 453162ff38aeSLuigi Rizzo strcpy(p, av[i]); 453262ff38aeSLuigi Rizzo p += strlen(av[i]); 453362ff38aeSLuigi Rizzo *p++ = ' '; 453462ff38aeSLuigi Rizzo } 453562ff38aeSLuigi Rizzo *(--p) = '\0'; 453662ff38aeSLuigi Rizzo } 453762ff38aeSLuigi Rizzo 453862ff38aeSLuigi Rizzo /* 45399758b77fSLuigi Rizzo * A function to fill simple commands of size 1. 45409758b77fSLuigi Rizzo * Existing flags are preserved. 45419758b77fSLuigi Rizzo */ 45429758b77fSLuigi Rizzo static void 4543571f8c1bSLuigi Rizzo fill_cmd(ipfw_insn *cmd, enum ipfw_opcodes opcode, int flags, uint16_t arg) 45449758b77fSLuigi Rizzo { 45459758b77fSLuigi Rizzo cmd->opcode = opcode; 45469758b77fSLuigi Rizzo cmd->len = ((cmd->len | flags) & (F_NOT | F_OR)) | 1; 45479758b77fSLuigi Rizzo cmd->arg1 = arg; 45489758b77fSLuigi Rizzo } 45499758b77fSLuigi Rizzo 45509758b77fSLuigi Rizzo /* 45519758b77fSLuigi Rizzo * Fetch and add the MAC address and type, with masks. This generates one or 45529758b77fSLuigi Rizzo * two microinstructions, and returns the pointer to the last one. 45539758b77fSLuigi Rizzo */ 45549758b77fSLuigi Rizzo static ipfw_insn * 45559758b77fSLuigi Rizzo add_mac(ipfw_insn *cmd, int ac, char *av[]) 45569758b77fSLuigi Rizzo { 4557e706181bSLuigi Rizzo ipfw_insn_mac *mac; 45589758b77fSLuigi Rizzo 455999e5e645SLuigi Rizzo if (ac < 2) 45605a155b40SLuigi Rizzo errx(EX_DATAERR, "MAC dst src"); 45619758b77fSLuigi Rizzo 45629758b77fSLuigi Rizzo cmd->opcode = O_MACADDR2; 45639758b77fSLuigi Rizzo cmd->len = (cmd->len & (F_NOT | F_OR)) | F_INSN_SIZE(ipfw_insn_mac); 45649758b77fSLuigi Rizzo 45659758b77fSLuigi Rizzo mac = (ipfw_insn_mac *)cmd; 45669758b77fSLuigi Rizzo get_mac_addr_mask(av[0], mac->addr, mac->mask); /* dst */ 4567bd1d3456SMaxim Konovalov get_mac_addr_mask(av[1], &(mac->addr[ETHER_ADDR_LEN]), 4568bd1d3456SMaxim Konovalov &(mac->mask[ETHER_ADDR_LEN])); /* src */ 4569e706181bSLuigi Rizzo return cmd; 45709758b77fSLuigi Rizzo } 45719758b77fSLuigi Rizzo 4572e706181bSLuigi Rizzo static ipfw_insn * 4573e706181bSLuigi Rizzo add_mactype(ipfw_insn *cmd, int ac, char *av) 4574e706181bSLuigi Rizzo { 4575e706181bSLuigi Rizzo if (ac < 1) 4576e706181bSLuigi Rizzo errx(EX_DATAERR, "missing MAC type"); 4577e706181bSLuigi Rizzo if (strcmp(av, "any") != 0) { /* we have a non-null type */ 4578e706181bSLuigi Rizzo fill_newports((ipfw_insn_u16 *)cmd, av, IPPROTO_ETHERTYPE); 4579e706181bSLuigi Rizzo cmd->opcode = O_MAC_TYPE; 45809758b77fSLuigi Rizzo return cmd; 4581e706181bSLuigi Rizzo } else 4582e706181bSLuigi Rizzo return NULL; 4583e706181bSLuigi Rizzo } 4584e706181bSLuigi Rizzo 4585e706181bSLuigi Rizzo static ipfw_insn * 458636c263ccSHajimu UMEMOTO add_proto0(ipfw_insn *cmd, char *av, u_char *protop) 4587e706181bSLuigi Rizzo { 4588e706181bSLuigi Rizzo struct protoent *pe; 458936c263ccSHajimu UMEMOTO char *ep; 459036c263ccSHajimu UMEMOTO int proto; 45918195404bSBrooks Davis 4592c6ec0226SHajimu UMEMOTO proto = strtol(av, &ep, 10); 4593c6ec0226SHajimu UMEMOTO if (*ep != '\0' || proto <= 0) { 459436c263ccSHajimu UMEMOTO if ((pe = getprotobyname(av)) == NULL) 459536c263ccSHajimu UMEMOTO return NULL; 459636c263ccSHajimu UMEMOTO proto = pe->p_proto; 459736c263ccSHajimu UMEMOTO } 459836c263ccSHajimu UMEMOTO 459936c263ccSHajimu UMEMOTO fill_cmd(cmd, O_PROTO, 0, proto); 460036c263ccSHajimu UMEMOTO *protop = proto; 460136c263ccSHajimu UMEMOTO return cmd; 460236c263ccSHajimu UMEMOTO } 460336c263ccSHajimu UMEMOTO 460436c263ccSHajimu UMEMOTO static ipfw_insn * 460536c263ccSHajimu UMEMOTO add_proto(ipfw_insn *cmd, char *av, u_char *protop) 460636c263ccSHajimu UMEMOTO { 460736c263ccSHajimu UMEMOTO u_char proto = IPPROTO_IP; 4608e706181bSLuigi Rizzo 4609c6ec0226SHajimu UMEMOTO if (_substrcmp(av, "all") == 0 || strcmp(av, "ip") == 0) 461057cd6d26SMax Laier ; /* do not set O_IP4 nor O_IP6 */ 461136c263ccSHajimu UMEMOTO else if (strcmp(av, "ip4") == 0) 461236c263ccSHajimu UMEMOTO /* explicit "just IPv4" rule */ 461336c263ccSHajimu UMEMOTO fill_cmd(cmd, O_IP4, 0, 0); 461436c263ccSHajimu UMEMOTO else if (strcmp(av, "ip6") == 0) { 461536c263ccSHajimu UMEMOTO /* explicit "just IPv6" rule */ 461636c263ccSHajimu UMEMOTO proto = IPPROTO_IPV6; 461736c263ccSHajimu UMEMOTO fill_cmd(cmd, O_IP6, 0, 0); 461836c263ccSHajimu UMEMOTO } else 461936c263ccSHajimu UMEMOTO return add_proto0(cmd, av, protop); 462036c263ccSHajimu UMEMOTO 462136c263ccSHajimu UMEMOTO *protop = proto; 462236c263ccSHajimu UMEMOTO return cmd; 462336c263ccSHajimu UMEMOTO } 462436c263ccSHajimu UMEMOTO 462536c263ccSHajimu UMEMOTO static ipfw_insn * 462636c263ccSHajimu UMEMOTO add_proto_compat(ipfw_insn *cmd, char *av, u_char *protop) 462736c263ccSHajimu UMEMOTO { 462836c263ccSHajimu UMEMOTO u_char proto = IPPROTO_IP; 462936c263ccSHajimu UMEMOTO 463036c263ccSHajimu UMEMOTO if (_substrcmp(av, "all") == 0 || strcmp(av, "ip") == 0) 463136c263ccSHajimu UMEMOTO ; /* do not set O_IP4 nor O_IP6 */ 463257cd6d26SMax Laier else if (strcmp(av, "ipv4") == 0 || strcmp(av, "ip4") == 0) 463357cd6d26SMax Laier /* explicit "just IPv4" rule */ 463457cd6d26SMax Laier fill_cmd(cmd, O_IP4, 0, 0); 463557cd6d26SMax Laier else if (strcmp(av, "ipv6") == 0 || strcmp(av, "ip6") == 0) { 463657cd6d26SMax Laier /* explicit "just IPv6" rule */ 463736c263ccSHajimu UMEMOTO proto = IPPROTO_IPV6; 463857cd6d26SMax Laier fill_cmd(cmd, O_IP6, 0, 0); 463936c263ccSHajimu UMEMOTO } else 464036c263ccSHajimu UMEMOTO return add_proto0(cmd, av, protop); 46418195404bSBrooks Davis 464236c263ccSHajimu UMEMOTO *protop = proto; 4643e706181bSLuigi Rizzo return cmd; 4644e706181bSLuigi Rizzo } 4645e706181bSLuigi Rizzo 4646e706181bSLuigi Rizzo static ipfw_insn * 4647e706181bSLuigi Rizzo add_srcip(ipfw_insn *cmd, char *av) 4648e706181bSLuigi Rizzo { 4649e706181bSLuigi Rizzo fill_ip((ipfw_insn_ip *)cmd, av); 4650e706181bSLuigi Rizzo if (cmd->opcode == O_IP_DST_SET) /* set */ 4651e706181bSLuigi Rizzo cmd->opcode = O_IP_SRC_SET; 4652cd8b5ae0SRuslan Ermilov else if (cmd->opcode == O_IP_DST_LOOKUP) /* table */ 4653cd8b5ae0SRuslan Ermilov cmd->opcode = O_IP_SRC_LOOKUP; 4654e706181bSLuigi Rizzo else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) /* me */ 4655e706181bSLuigi Rizzo cmd->opcode = O_IP_SRC_ME; 4656e706181bSLuigi Rizzo else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn_u32)) /* one IP */ 4657e706181bSLuigi Rizzo cmd->opcode = O_IP_SRC; 4658571f8c1bSLuigi Rizzo else /* addr/mask */ 4659e706181bSLuigi Rizzo cmd->opcode = O_IP_SRC_MASK; 4660e706181bSLuigi Rizzo return cmd; 4661e706181bSLuigi Rizzo } 4662e706181bSLuigi Rizzo 4663e706181bSLuigi Rizzo static ipfw_insn * 4664e706181bSLuigi Rizzo add_dstip(ipfw_insn *cmd, char *av) 4665e706181bSLuigi Rizzo { 4666e706181bSLuigi Rizzo fill_ip((ipfw_insn_ip *)cmd, av); 4667e706181bSLuigi Rizzo if (cmd->opcode == O_IP_DST_SET) /* set */ 4668e706181bSLuigi Rizzo ; 4669cd8b5ae0SRuslan Ermilov else if (cmd->opcode == O_IP_DST_LOOKUP) /* table */ 4670cd8b5ae0SRuslan Ermilov ; 4671e706181bSLuigi Rizzo else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) /* me */ 4672e706181bSLuigi Rizzo cmd->opcode = O_IP_DST_ME; 4673e706181bSLuigi Rizzo else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn_u32)) /* one IP */ 4674e706181bSLuigi Rizzo cmd->opcode = O_IP_DST; 4675571f8c1bSLuigi Rizzo else /* addr/mask */ 4676e706181bSLuigi Rizzo cmd->opcode = O_IP_DST_MASK; 4677e706181bSLuigi Rizzo return cmd; 4678e706181bSLuigi Rizzo } 4679e706181bSLuigi Rizzo 4680e706181bSLuigi Rizzo static ipfw_insn * 4681e706181bSLuigi Rizzo add_ports(ipfw_insn *cmd, char *av, u_char proto, int opcode) 4682e706181bSLuigi Rizzo { 468301750186SBrooks Davis if (_substrcmp(av, "any") == 0) { 4684e706181bSLuigi Rizzo return NULL; 4685e706181bSLuigi Rizzo } else if (fill_newports((ipfw_insn_u16 *)cmd, av, proto)) { 4686e706181bSLuigi Rizzo /* XXX todo: check that we have a protocol with ports */ 4687e706181bSLuigi Rizzo cmd->opcode = opcode; 4688e706181bSLuigi Rizzo return cmd; 4689e706181bSLuigi Rizzo } 4690e706181bSLuigi Rizzo return NULL; 46919758b77fSLuigi Rizzo } 46929758b77fSLuigi Rizzo 46938195404bSBrooks Davis static ipfw_insn * 46948195404bSBrooks Davis add_src(ipfw_insn *cmd, char *av, u_char proto) 46958195404bSBrooks Davis { 46968195404bSBrooks Davis struct in6_addr a; 4697926bbf90SMax Laier char *host, *ch; 4698926bbf90SMax Laier ipfw_insn *ret = NULL; 4699926bbf90SMax Laier 4700926bbf90SMax Laier if ((host = strdup(av)) == NULL) 4701926bbf90SMax Laier return NULL; 4702926bbf90SMax Laier if ((ch = strrchr(host, '/')) != NULL) 4703926bbf90SMax Laier *ch = '\0'; 47048195404bSBrooks Davis 47058195404bSBrooks Davis if (proto == IPPROTO_IPV6 || strcmp(av, "me6") == 0 || 4706926bbf90SMax Laier inet_pton(AF_INET6, host, &a)) 4707926bbf90SMax Laier ret = add_srcip6(cmd, av); 47088195404bSBrooks Davis /* XXX: should check for IPv4, not !IPv6 */ 4709e28cb025SDavid Malone if (ret == NULL && (proto == IPPROTO_IP || strcmp(av, "me") == 0 || 4710e28cb025SDavid Malone !inet_pton(AF_INET6, host, &a))) 4711926bbf90SMax Laier ret = add_srcip(cmd, av); 4712e28cb025SDavid Malone if (ret == NULL && strcmp(av, "any") != 0) 4713926bbf90SMax Laier ret = cmd; 47148195404bSBrooks Davis 4715926bbf90SMax Laier free(host); 4716926bbf90SMax Laier return ret; 47178195404bSBrooks Davis } 47188195404bSBrooks Davis 47198195404bSBrooks Davis static ipfw_insn * 47208195404bSBrooks Davis add_dst(ipfw_insn *cmd, char *av, u_char proto) 47218195404bSBrooks Davis { 47228195404bSBrooks Davis struct in6_addr a; 4723926bbf90SMax Laier char *host, *ch; 4724926bbf90SMax Laier ipfw_insn *ret = NULL; 4725926bbf90SMax Laier 4726926bbf90SMax Laier if ((host = strdup(av)) == NULL) 4727926bbf90SMax Laier return NULL; 4728926bbf90SMax Laier if ((ch = strrchr(host, '/')) != NULL) 4729926bbf90SMax Laier *ch = '\0'; 47308195404bSBrooks Davis 47318195404bSBrooks Davis if (proto == IPPROTO_IPV6 || strcmp(av, "me6") == 0 || 4732926bbf90SMax Laier inet_pton(AF_INET6, host, &a)) 4733926bbf90SMax Laier ret = add_dstip6(cmd, av); 47348195404bSBrooks Davis /* XXX: should check for IPv4, not !IPv6 */ 4735e28cb025SDavid Malone if (ret == NULL && (proto == IPPROTO_IP || strcmp(av, "me") == 0 || 4736e28cb025SDavid Malone !inet_pton(AF_INET6, host, &a))) 4737926bbf90SMax Laier ret = add_dstip(cmd, av); 4738e28cb025SDavid Malone if (ret == NULL && strcmp(av, "any") != 0) 4739926bbf90SMax Laier ret = cmd; 47408195404bSBrooks Davis 4741926bbf90SMax Laier free(host); 4742926bbf90SMax Laier return ret; 47438195404bSBrooks Davis } 47448195404bSBrooks Davis 47459758b77fSLuigi Rizzo /* 47469758b77fSLuigi Rizzo * Parse arguments and assemble the microinstructions which make up a rule. 47479758b77fSLuigi Rizzo * Rules are added into the 'rulebuf' and then copied in the correct order 47489758b77fSLuigi Rizzo * into the actual rule. 47499758b77fSLuigi Rizzo * 4750974dfe30SBrian Feldman * The syntax for a rule starts with the action, followed by 4751974dfe30SBrian Feldman * optional action parameters, and the various match patterns. 47529d5abbddSJens Schweikhardt * In the assembled microcode, the first opcode must be an O_PROBE_STATE 47539758b77fSLuigi Rizzo * (generated if the rule includes a keep-state option), then the 4754974dfe30SBrian Feldman * various match patterns, log/altq actions, and the actual action. 47559758b77fSLuigi Rizzo * 47569758b77fSLuigi Rizzo */ 47579758b77fSLuigi Rizzo static void 47589758b77fSLuigi Rizzo add(int ac, char *av[]) 47599758b77fSLuigi Rizzo { 47609758b77fSLuigi Rizzo /* 47619758b77fSLuigi Rizzo * rules are added into the 'rulebuf' and then copied in 47629758b77fSLuigi Rizzo * the correct order into the actual rule. 47639758b77fSLuigi Rizzo * Some things that need to go out of order (prob, action etc.) 47649758b77fSLuigi Rizzo * go into actbuf[]. 47659758b77fSLuigi Rizzo */ 4766571f8c1bSLuigi Rizzo static uint32_t rulebuf[255], actbuf[255], cmdbuf[255]; 47679758b77fSLuigi Rizzo 476862ff38aeSLuigi Rizzo ipfw_insn *src, *dst, *cmd, *action, *prev=NULL; 4769e706181bSLuigi Rizzo ipfw_insn *first_cmd; /* first match pattern */ 47709758b77fSLuigi Rizzo 47719758b77fSLuigi Rizzo struct ip_fw *rule; 47729758b77fSLuigi Rizzo 47739758b77fSLuigi Rizzo /* 47749758b77fSLuigi Rizzo * various flags used to record that we entered some fields. 47759758b77fSLuigi Rizzo */ 477652bc23abSLuigi Rizzo ipfw_insn *have_state = NULL; /* check-state or keep-state */ 47776a7d5cb6SOleg Bulyzhin ipfw_insn *have_log = NULL, *have_altq = NULL, *have_tag = NULL; 47789ec4f2e1SMaxim Konovalov size_t len; 47799758b77fSLuigi Rizzo 47809758b77fSLuigi Rizzo int i; 47819758b77fSLuigi Rizzo 47829758b77fSLuigi Rizzo int open_par = 0; /* open parenthesis ( */ 47839758b77fSLuigi Rizzo 47849758b77fSLuigi Rizzo /* proto is here because it is used to fetch ports */ 47859758b77fSLuigi Rizzo u_char proto = IPPROTO_IP; /* default protocol */ 47869758b77fSLuigi Rizzo 478712b5dc6aSLuigi Rizzo double match_prob = 1; /* match probability, default is always match */ 478812b5dc6aSLuigi Rizzo 47899758b77fSLuigi Rizzo bzero(actbuf, sizeof(actbuf)); /* actions go here */ 47909758b77fSLuigi Rizzo bzero(cmdbuf, sizeof(cmdbuf)); 47919758b77fSLuigi Rizzo bzero(rulebuf, sizeof(rulebuf)); 47929758b77fSLuigi Rizzo 47939758b77fSLuigi Rizzo rule = (struct ip_fw *)rulebuf; 47949758b77fSLuigi Rizzo cmd = (ipfw_insn *)cmdbuf; 47959758b77fSLuigi Rizzo action = (ipfw_insn *)actbuf; 47969758b77fSLuigi Rizzo 47979758b77fSLuigi Rizzo av++; ac--; 47989758b77fSLuigi Rizzo 47999758b77fSLuigi Rizzo /* [rule N] -- Rule number optional */ 48009758b77fSLuigi Rizzo if (ac && isdigit(**av)) { 48019758b77fSLuigi Rizzo rule->rulenum = atoi(*av); 48029758b77fSLuigi Rizzo av++; 48039758b77fSLuigi Rizzo ac--; 48049758b77fSLuigi Rizzo } 48059758b77fSLuigi Rizzo 48063004afcaSLuigi Rizzo /* [set N] -- set number (0..RESVD_SET), optional */ 480701750186SBrooks Davis if (ac > 1 && _substrcmp(*av, "set") == 0) { 480843405724SLuigi Rizzo int set = strtoul(av[1], NULL, 10); 48093004afcaSLuigi Rizzo if (set < 0 || set > RESVD_SET) 481043405724SLuigi Rizzo errx(EX_DATAERR, "illegal set %s", av[1]); 481143405724SLuigi Rizzo rule->set = set; 481243405724SLuigi Rizzo av += 2; ac -= 2; 481343405724SLuigi Rizzo } 481443405724SLuigi Rizzo 48159758b77fSLuigi Rizzo /* [prob D] -- match probability, optional */ 481601750186SBrooks Davis if (ac > 1 && _substrcmp(*av, "prob") == 0) { 481712b5dc6aSLuigi Rizzo match_prob = strtod(av[1], NULL); 48189758b77fSLuigi Rizzo 481912b5dc6aSLuigi Rizzo if (match_prob <= 0 || match_prob > 1) 48209758b77fSLuigi Rizzo errx(EX_DATAERR, "illegal match prob. %s", av[1]); 48219758b77fSLuigi Rizzo av += 2; ac -= 2; 48229758b77fSLuigi Rizzo } 48239758b77fSLuigi Rizzo 48249758b77fSLuigi Rizzo /* action -- mandatory */ 48259758b77fSLuigi Rizzo NEED1("missing action"); 48269758b77fSLuigi Rizzo i = match_token(rule_actions, *av); 48279758b77fSLuigi Rizzo ac--; av++; 48289758b77fSLuigi Rizzo action->len = 1; /* default */ 48299758b77fSLuigi Rizzo switch(i) { 48309758b77fSLuigi Rizzo case TOK_CHECKSTATE: 483152bc23abSLuigi Rizzo have_state = action; 48329758b77fSLuigi Rizzo action->opcode = O_CHECK_STATE; 48339758b77fSLuigi Rizzo break; 48349758b77fSLuigi Rizzo 48359758b77fSLuigi Rizzo case TOK_ACCEPT: 48369758b77fSLuigi Rizzo action->opcode = O_ACCEPT; 48379758b77fSLuigi Rizzo break; 48389758b77fSLuigi Rizzo 48399758b77fSLuigi Rizzo case TOK_DENY: 48409758b77fSLuigi Rizzo action->opcode = O_DENY; 48415e43aef8SLuigi Rizzo action->arg1 = 0; 48425e43aef8SLuigi Rizzo break; 48435e43aef8SLuigi Rizzo 48445e43aef8SLuigi Rizzo case TOK_REJECT: 48455e43aef8SLuigi Rizzo action->opcode = O_REJECT; 48465e43aef8SLuigi Rizzo action->arg1 = ICMP_UNREACH_HOST; 48475e43aef8SLuigi Rizzo break; 48485e43aef8SLuigi Rizzo 48495e43aef8SLuigi Rizzo case TOK_RESET: 48505e43aef8SLuigi Rizzo action->opcode = O_REJECT; 48515e43aef8SLuigi Rizzo action->arg1 = ICMP_REJECT_RST; 48525e43aef8SLuigi Rizzo break; 48535e43aef8SLuigi Rizzo 48549066356bSBjoern A. Zeeb case TOK_RESET6: 48559066356bSBjoern A. Zeeb action->opcode = O_UNREACH6; 48569066356bSBjoern A. Zeeb action->arg1 = ICMP6_UNREACH_RST; 48579066356bSBjoern A. Zeeb break; 48589066356bSBjoern A. Zeeb 48595e43aef8SLuigi Rizzo case TOK_UNREACH: 48605e43aef8SLuigi Rizzo action->opcode = O_REJECT; 48615e43aef8SLuigi Rizzo NEED1("missing reject code"); 48625e43aef8SLuigi Rizzo fill_reject_code(&action->arg1, *av); 48635e43aef8SLuigi Rizzo ac--; av++; 48649758b77fSLuigi Rizzo break; 48659758b77fSLuigi Rizzo 48669066356bSBjoern A. Zeeb case TOK_UNREACH6: 48679066356bSBjoern A. Zeeb action->opcode = O_UNREACH6; 48689066356bSBjoern A. Zeeb NEED1("missing unreach code"); 48699066356bSBjoern A. Zeeb fill_unreach6_code(&action->arg1, *av); 48709066356bSBjoern A. Zeeb ac--; av++; 48719066356bSBjoern A. Zeeb break; 48729066356bSBjoern A. Zeeb 48739758b77fSLuigi Rizzo case TOK_COUNT: 48749758b77fSLuigi Rizzo action->opcode = O_COUNT; 48759758b77fSLuigi Rizzo break; 48769758b77fSLuigi Rizzo 4877f94a7fc0SPaolo Pisati case TOK_NAT: 4878f94a7fc0SPaolo Pisati action->opcode = O_NAT; 4879f94a7fc0SPaolo Pisati action->len = F_INSN_SIZE(ipfw_insn_nat); 4880f94a7fc0SPaolo Pisati goto chkarg; 48818b07e49aSJulian Elischer 48829758b77fSLuigi Rizzo case TOK_QUEUE: 48839758b77fSLuigi Rizzo action->opcode = O_QUEUE; 488440b1ae9eSGleb Smirnoff goto chkarg; 488540b1ae9eSGleb Smirnoff case TOK_PIPE: 48869758b77fSLuigi Rizzo action->opcode = O_PIPE; 488740b1ae9eSGleb Smirnoff goto chkarg; 488840b1ae9eSGleb Smirnoff case TOK_SKIPTO: 48899758b77fSLuigi Rizzo action->opcode = O_SKIPTO; 489040b1ae9eSGleb Smirnoff goto chkarg; 489140b1ae9eSGleb Smirnoff case TOK_NETGRAPH: 489240b1ae9eSGleb Smirnoff action->opcode = O_NETGRAPH; 489340b1ae9eSGleb Smirnoff goto chkarg; 489440b1ae9eSGleb Smirnoff case TOK_NGTEE: 489540b1ae9eSGleb Smirnoff action->opcode = O_NGTEE; 489640b1ae9eSGleb Smirnoff goto chkarg; 48979758b77fSLuigi Rizzo case TOK_DIVERT: 489840b1ae9eSGleb Smirnoff action->opcode = O_DIVERT; 489940b1ae9eSGleb Smirnoff goto chkarg; 49009758b77fSLuigi Rizzo case TOK_TEE: 490140b1ae9eSGleb Smirnoff action->opcode = O_TEE; 490240b1ae9eSGleb Smirnoff chkarg: 490340b1ae9eSGleb Smirnoff if (!ac) 490440b1ae9eSGleb Smirnoff errx(EX_USAGE, "missing argument for %s", *(av - 1)); 490540b1ae9eSGleb Smirnoff if (isdigit(**av)) { 490640b1ae9eSGleb Smirnoff action->arg1 = strtoul(*av, NULL, 10); 490740b1ae9eSGleb Smirnoff if (action->arg1 <= 0 || action->arg1 >= IP_FW_TABLEARG) 490840b1ae9eSGleb Smirnoff errx(EX_DATAERR, "illegal argument for %s", 490940b1ae9eSGleb Smirnoff *(av - 1)); 491040b1ae9eSGleb Smirnoff } else if (_substrcmp(*av, TABLEARG) == 0) { 491140b1ae9eSGleb Smirnoff action->arg1 = IP_FW_TABLEARG; 491240b1ae9eSGleb Smirnoff } else if (i == TOK_DIVERT || i == TOK_TEE) { 49139758b77fSLuigi Rizzo struct servent *s; 49149758b77fSLuigi Rizzo setservent(1); 49159758b77fSLuigi Rizzo s = getservbyname(av[0], "divert"); 49169758b77fSLuigi Rizzo if (s != NULL) 49179758b77fSLuigi Rizzo action->arg1 = ntohs(s->s_port); 49189758b77fSLuigi Rizzo else 49199758b77fSLuigi Rizzo errx(EX_DATAERR, "illegal divert/tee port"); 492040b1ae9eSGleb Smirnoff } else 492140b1ae9eSGleb Smirnoff errx(EX_DATAERR, "illegal argument for %s", *(av - 1)); 4922670742a1SGleb Smirnoff ac--; av++; 4923670742a1SGleb Smirnoff break; 4924670742a1SGleb Smirnoff 49259758b77fSLuigi Rizzo case TOK_FORWARD: { 49269758b77fSLuigi Rizzo ipfw_insn_sa *p = (ipfw_insn_sa *)action; 49279758b77fSLuigi Rizzo char *s, *end; 49289758b77fSLuigi Rizzo 49299758b77fSLuigi Rizzo NEED1("missing forward address[:port]"); 49309758b77fSLuigi Rizzo 49319758b77fSLuigi Rizzo action->opcode = O_FORWARD_IP; 49329758b77fSLuigi Rizzo action->len = F_INSN_SIZE(ipfw_insn_sa); 49339758b77fSLuigi Rizzo 49349758b77fSLuigi Rizzo p->sa.sin_len = sizeof(struct sockaddr_in); 49359758b77fSLuigi Rizzo p->sa.sin_family = AF_INET; 49369758b77fSLuigi Rizzo p->sa.sin_port = 0; 49379758b77fSLuigi Rizzo /* 49389758b77fSLuigi Rizzo * locate the address-port separator (':' or ',') 49399758b77fSLuigi Rizzo */ 49409758b77fSLuigi Rizzo s = strchr(*av, ':'); 49419758b77fSLuigi Rizzo if (s == NULL) 49429758b77fSLuigi Rizzo s = strchr(*av, ','); 49439758b77fSLuigi Rizzo if (s != NULL) { 49449758b77fSLuigi Rizzo *(s++) = '\0'; 49459758b77fSLuigi Rizzo i = strtoport(s, &end, 0 /* base */, 0 /* proto */); 49469758b77fSLuigi Rizzo if (s == end) 49479758b77fSLuigi Rizzo errx(EX_DATAERR, 49489758b77fSLuigi Rizzo "illegal forwarding port ``%s''", s); 49494f531a53SLuigi Rizzo p->sa.sin_port = (u_short)i; 49509758b77fSLuigi Rizzo } 4951afad78e2SJulian Elischer if (_substrcmp(*av, "tablearg") == 0) 4952afad78e2SJulian Elischer p->sa.sin_addr.s_addr = INADDR_ANY; 4953afad78e2SJulian Elischer else 49549758b77fSLuigi Rizzo lookup_host(*av, &(p->sa.sin_addr)); 49559758b77fSLuigi Rizzo ac--; av++; 49569758b77fSLuigi Rizzo break; 4957c487be96SJulian Elischer } 495862ff38aeSLuigi Rizzo case TOK_COMMENT: 495962ff38aeSLuigi Rizzo /* pretend it is a 'count' rule followed by the comment */ 496062ff38aeSLuigi Rizzo action->opcode = O_COUNT; 496162ff38aeSLuigi Rizzo ac++; av--; /* go back... */ 496262ff38aeSLuigi Rizzo break; 496362ff38aeSLuigi Rizzo 49648b07e49aSJulian Elischer case TOK_SETFIB: 49658b07e49aSJulian Elischer { 49668b07e49aSJulian Elischer int numfibs; 49678b07e49aSJulian Elischer 49688b07e49aSJulian Elischer action->opcode = O_SETFIB; 49698b07e49aSJulian Elischer NEED1("missing fib number"); 49708b07e49aSJulian Elischer action->arg1 = strtoul(*av, NULL, 10); 49718b07e49aSJulian Elischer if (sysctlbyname("net.fibs", &numfibs, &i, NULL, 0) == -1) 49728b07e49aSJulian Elischer errx(EX_DATAERR, "fibs not suported.\n"); 49738b07e49aSJulian Elischer if (action->arg1 >= numfibs) /* Temporary */ 49748b07e49aSJulian Elischer errx(EX_DATAERR, "fib too large.\n"); 49758b07e49aSJulian Elischer ac--; av++; 49768b07e49aSJulian Elischer break; 49778b07e49aSJulian Elischer } 49788b07e49aSJulian Elischer 49799758b77fSLuigi Rizzo default: 4980e706181bSLuigi Rizzo errx(EX_DATAERR, "invalid action %s\n", av[-1]); 49819758b77fSLuigi Rizzo } 49829758b77fSLuigi Rizzo action = next_cmd(action); 49839758b77fSLuigi Rizzo 49849758b77fSLuigi Rizzo /* 4985974dfe30SBrian Feldman * [altq queuename] -- altq tag, optional 49869758b77fSLuigi Rizzo * [log [logamount N]] -- log, optional 49879758b77fSLuigi Rizzo * 4988974dfe30SBrian Feldman * If they exist, it go first in the cmdbuf, but then it is 49899758b77fSLuigi Rizzo * skipped in the copy section to the end of the buffer. 49909758b77fSLuigi Rizzo */ 4991974dfe30SBrian Feldman while (ac != 0 && (i = match_token(rule_action_params, *av)) != -1) { 4992974dfe30SBrian Feldman ac--; av++; 4993974dfe30SBrian Feldman switch (i) { 4994974dfe30SBrian Feldman case TOK_LOG: 4995974dfe30SBrian Feldman { 49969758b77fSLuigi Rizzo ipfw_insn_log *c = (ipfw_insn_log *)cmd; 499762ff38aeSLuigi Rizzo int l; 49989758b77fSLuigi Rizzo 4999974dfe30SBrian Feldman if (have_log) 5000974dfe30SBrian Feldman errx(EX_DATAERR, 5001974dfe30SBrian Feldman "log cannot be specified more than once"); 5002974dfe30SBrian Feldman have_log = (ipfw_insn *)c; 50039758b77fSLuigi Rizzo cmd->len = F_INSN_SIZE(ipfw_insn_log); 50049758b77fSLuigi Rizzo cmd->opcode = O_LOG; 500501750186SBrooks Davis if (ac && _substrcmp(*av, "logamount") == 0) { 50069758b77fSLuigi Rizzo ac--; av++; 50079758b77fSLuigi Rizzo NEED1("logamount requires argument"); 500862ff38aeSLuigi Rizzo l = atoi(*av); 500962ff38aeSLuigi Rizzo if (l < 0) 5010974dfe30SBrian Feldman errx(EX_DATAERR, 5011974dfe30SBrian Feldman "logamount must be positive"); 501262ff38aeSLuigi Rizzo c->max_log = l; 50139758b77fSLuigi Rizzo ac--; av++; 50149ec4f2e1SMaxim Konovalov } else { 50159ec4f2e1SMaxim Konovalov len = sizeof(c->max_log); 50169ec4f2e1SMaxim Konovalov if (sysctlbyname("net.inet.ip.fw.verbose_limit", 50179ec4f2e1SMaxim Konovalov &c->max_log, &len, NULL, 0) == -1) 50189ec4f2e1SMaxim Konovalov errx(1, "sysctlbyname(\"%s\")", 50199ec4f2e1SMaxim Konovalov "net.inet.ip.fw.verbose_limit"); 50209758b77fSLuigi Rizzo } 5021974dfe30SBrian Feldman } 5022974dfe30SBrian Feldman break; 5023974dfe30SBrian Feldman 5024974dfe30SBrian Feldman case TOK_ALTQ: 5025974dfe30SBrian Feldman { 5026974dfe30SBrian Feldman ipfw_insn_altq *a = (ipfw_insn_altq *)cmd; 5027974dfe30SBrian Feldman 5028974dfe30SBrian Feldman NEED1("missing altq queue name"); 5029974dfe30SBrian Feldman if (have_altq) 5030974dfe30SBrian Feldman errx(EX_DATAERR, 5031974dfe30SBrian Feldman "altq cannot be specified more than once"); 5032974dfe30SBrian Feldman have_altq = (ipfw_insn *)a; 5033974dfe30SBrian Feldman cmd->len = F_INSN_SIZE(ipfw_insn_altq); 5034974dfe30SBrian Feldman cmd->opcode = O_ALTQ; 5035974dfe30SBrian Feldman fill_altq_qid(&a->qid, *av); 5036974dfe30SBrian Feldman ac--; av++; 5037974dfe30SBrian Feldman } 5038974dfe30SBrian Feldman break; 5039974dfe30SBrian Feldman 50406a7d5cb6SOleg Bulyzhin case TOK_TAG: 5041254c4725SOleg Bulyzhin case TOK_UNTAG: { 5042254c4725SOleg Bulyzhin uint16_t tag; 5043254c4725SOleg Bulyzhin 50446a7d5cb6SOleg Bulyzhin if (have_tag) 5045254c4725SOleg Bulyzhin errx(EX_USAGE, "tag and untag cannot be " 5046254c4725SOleg Bulyzhin "specified more than once"); 5047254c4725SOleg Bulyzhin GET_UINT_ARG(tag, 1, 65534, i, rule_action_params); 50486a7d5cb6SOleg Bulyzhin have_tag = cmd; 5049254c4725SOleg Bulyzhin fill_cmd(cmd, O_TAG, (i == TOK_TAG) ? 0: F_NOT, tag); 50506a7d5cb6SOleg Bulyzhin ac--; av++; 50516a7d5cb6SOleg Bulyzhin break; 5052254c4725SOleg Bulyzhin } 50536a7d5cb6SOleg Bulyzhin 5054974dfe30SBrian Feldman default: 5055974dfe30SBrian Feldman abort(); 5056974dfe30SBrian Feldman } 50579758b77fSLuigi Rizzo cmd = next_cmd(cmd); 50589758b77fSLuigi Rizzo } 50599758b77fSLuigi Rizzo 506052bc23abSLuigi Rizzo if (have_state) /* must be a check-state, we are done */ 50619758b77fSLuigi Rizzo goto done; 50629758b77fSLuigi Rizzo 50639758b77fSLuigi Rizzo #define OR_START(target) \ 50649758b77fSLuigi Rizzo if (ac && (*av[0] == '(' || *av[0] == '{')) { \ 50659758b77fSLuigi Rizzo if (open_par) \ 50669758b77fSLuigi Rizzo errx(EX_USAGE, "nested \"(\" not allowed\n"); \ 50678ed2d749SLuigi Rizzo prev = NULL; \ 50689758b77fSLuigi Rizzo open_par = 1; \ 50699758b77fSLuigi Rizzo if ( (av[0])[1] == '\0') { \ 50709758b77fSLuigi Rizzo ac--; av++; \ 50719758b77fSLuigi Rizzo } else \ 50729758b77fSLuigi Rizzo (*av)++; \ 50739758b77fSLuigi Rizzo } \ 50749758b77fSLuigi Rizzo target: \ 50759758b77fSLuigi Rizzo 50769758b77fSLuigi Rizzo 50779758b77fSLuigi Rizzo #define CLOSE_PAR \ 50789758b77fSLuigi Rizzo if (open_par) { \ 50799758b77fSLuigi Rizzo if (ac && ( \ 508001750186SBrooks Davis strcmp(*av, ")") == 0 || \ 508101750186SBrooks Davis strcmp(*av, "}") == 0)) { \ 50828ed2d749SLuigi Rizzo prev = NULL; \ 50839758b77fSLuigi Rizzo open_par = 0; \ 50849758b77fSLuigi Rizzo ac--; av++; \ 50859758b77fSLuigi Rizzo } else \ 50869758b77fSLuigi Rizzo errx(EX_USAGE, "missing \")\"\n"); \ 50879758b77fSLuigi Rizzo } 50889758b77fSLuigi Rizzo 50899758b77fSLuigi Rizzo #define NOT_BLOCK \ 509001750186SBrooks Davis if (ac && _substrcmp(*av, "not") == 0) { \ 50919758b77fSLuigi Rizzo if (cmd->len & F_NOT) \ 50929758b77fSLuigi Rizzo errx(EX_USAGE, "double \"not\" not allowed\n"); \ 50939758b77fSLuigi Rizzo cmd->len |= F_NOT; \ 50949758b77fSLuigi Rizzo ac--; av++; \ 50959758b77fSLuigi Rizzo } 50969758b77fSLuigi Rizzo 50979758b77fSLuigi Rizzo #define OR_BLOCK(target) \ 509801750186SBrooks Davis if (ac && _substrcmp(*av, "or") == 0) { \ 50999758b77fSLuigi Rizzo if (prev == NULL || open_par == 0) \ 51009758b77fSLuigi Rizzo errx(EX_DATAERR, "invalid OR block"); \ 51019758b77fSLuigi Rizzo prev->len |= F_OR; \ 51029758b77fSLuigi Rizzo ac--; av++; \ 51039758b77fSLuigi Rizzo goto target; \ 51049758b77fSLuigi Rizzo } \ 51059758b77fSLuigi Rizzo CLOSE_PAR; 51069758b77fSLuigi Rizzo 5107e706181bSLuigi Rizzo first_cmd = cmd; 51085a155b40SLuigi Rizzo 51095a155b40SLuigi Rizzo #if 0 5110e706181bSLuigi Rizzo /* 5111e706181bSLuigi Rizzo * MAC addresses, optional. 5112e706181bSLuigi Rizzo * If we have this, we skip the part "proto from src to dst" 5113e706181bSLuigi Rizzo * and jump straight to the option parsing. 5114e706181bSLuigi Rizzo */ 5115e706181bSLuigi Rizzo NOT_BLOCK; 5116e706181bSLuigi Rizzo NEED1("missing protocol"); 511701750186SBrooks Davis if (_substrcmp(*av, "MAC") == 0 || 511801750186SBrooks Davis _substrcmp(*av, "mac") == 0) { 5119e706181bSLuigi Rizzo ac--; av++; /* the "MAC" keyword */ 5120e706181bSLuigi Rizzo add_mac(cmd, ac, av); /* exits in case of errors */ 5121e706181bSLuigi Rizzo cmd = next_cmd(cmd); 5122e706181bSLuigi Rizzo ac -= 2; av += 2; /* dst-mac and src-mac */ 5123e706181bSLuigi Rizzo NOT_BLOCK; 5124e706181bSLuigi Rizzo NEED1("missing mac type"); 5125e706181bSLuigi Rizzo if (add_mactype(cmd, ac, av[0])) 5126e706181bSLuigi Rizzo cmd = next_cmd(cmd); 5127e706181bSLuigi Rizzo ac--; av++; /* any or mac-type */ 5128e706181bSLuigi Rizzo goto read_options; 5129e706181bSLuigi Rizzo } 51305a155b40SLuigi Rizzo #endif 5131e706181bSLuigi Rizzo 51329758b77fSLuigi Rizzo /* 51339758b77fSLuigi Rizzo * protocol, mandatory 51349758b77fSLuigi Rizzo */ 51359758b77fSLuigi Rizzo OR_START(get_proto); 51369758b77fSLuigi Rizzo NOT_BLOCK; 51379758b77fSLuigi Rizzo NEED1("missing protocol"); 513836c263ccSHajimu UMEMOTO if (add_proto_compat(cmd, *av, &proto)) { 51399758b77fSLuigi Rizzo av++; ac--; 5140b730879fSMax Laier if (F_LEN(cmd) != 0) { 5141e706181bSLuigi Rizzo prev = cmd; 51429758b77fSLuigi Rizzo cmd = next_cmd(cmd); 5143e706181bSLuigi Rizzo } 51445a155b40SLuigi Rizzo } else if (first_cmd != cmd) { 5145c82b8dceSMaxim Konovalov errx(EX_DATAERR, "invalid protocol ``%s''", *av); 51465a155b40SLuigi Rizzo } else 51475a155b40SLuigi Rizzo goto read_options; 51489758b77fSLuigi Rizzo OR_BLOCK(get_proto); 51499758b77fSLuigi Rizzo 51509758b77fSLuigi Rizzo /* 5151e706181bSLuigi Rizzo * "from", mandatory 51529758b77fSLuigi Rizzo */ 515301750186SBrooks Davis if (!ac || _substrcmp(*av, "from") != 0) 51549758b77fSLuigi Rizzo errx(EX_USAGE, "missing ``from''"); 51559758b77fSLuigi Rizzo ac--; av++; 51569758b77fSLuigi Rizzo 51579758b77fSLuigi Rizzo /* 51589758b77fSLuigi Rizzo * source IP, mandatory 51599758b77fSLuigi Rizzo */ 51609758b77fSLuigi Rizzo OR_START(source_ip); 51619758b77fSLuigi Rizzo NOT_BLOCK; /* optional "not" */ 51629758b77fSLuigi Rizzo NEED1("missing source address"); 51638195404bSBrooks Davis if (add_src(cmd, *av, proto)) { 51649758b77fSLuigi Rizzo ac--; av++; 5165e706181bSLuigi Rizzo if (F_LEN(cmd) != 0) { /* ! any */ 5166e706181bSLuigi Rizzo prev = cmd; 51679758b77fSLuigi Rizzo cmd = next_cmd(cmd); 5168e706181bSLuigi Rizzo } 51698195404bSBrooks Davis } else 51708195404bSBrooks Davis errx(EX_USAGE, "bad source address %s", *av); 51719758b77fSLuigi Rizzo OR_BLOCK(source_ip); 51729758b77fSLuigi Rizzo 51739758b77fSLuigi Rizzo /* 51749758b77fSLuigi Rizzo * source ports, optional 51759758b77fSLuigi Rizzo */ 51769758b77fSLuigi Rizzo NOT_BLOCK; /* optional "not" */ 51778ed2d749SLuigi Rizzo if (ac) { 517801750186SBrooks Davis if (_substrcmp(*av, "any") == 0 || 5179e706181bSLuigi Rizzo add_ports(cmd, *av, proto, O_IP_SRCPORT)) { 5180e706181bSLuigi Rizzo ac--; av++; 5181e706181bSLuigi Rizzo if (F_LEN(cmd) != 0) 51829758b77fSLuigi Rizzo cmd = next_cmd(cmd); 51839758b77fSLuigi Rizzo } 51848ed2d749SLuigi Rizzo } 51859758b77fSLuigi Rizzo 51869758b77fSLuigi Rizzo /* 5187e706181bSLuigi Rizzo * "to", mandatory 51889758b77fSLuigi Rizzo */ 518901750186SBrooks Davis if (!ac || _substrcmp(*av, "to") != 0) 51909758b77fSLuigi Rizzo errx(EX_USAGE, "missing ``to''"); 51919758b77fSLuigi Rizzo av++; ac--; 51929758b77fSLuigi Rizzo 51939758b77fSLuigi Rizzo /* 51949758b77fSLuigi Rizzo * destination, mandatory 51959758b77fSLuigi Rizzo */ 51969758b77fSLuigi Rizzo OR_START(dest_ip); 51979758b77fSLuigi Rizzo NOT_BLOCK; /* optional "not" */ 51989758b77fSLuigi Rizzo NEED1("missing dst address"); 51998195404bSBrooks Davis if (add_dst(cmd, *av, proto)) { 5200e706181bSLuigi Rizzo ac--; av++; 5201e706181bSLuigi Rizzo if (F_LEN(cmd) != 0) { /* ! any */ 52029758b77fSLuigi Rizzo prev = cmd; 52039758b77fSLuigi Rizzo cmd = next_cmd(cmd); 5204e706181bSLuigi Rizzo } 52058195404bSBrooks Davis } else 52068195404bSBrooks Davis errx( EX_USAGE, "bad destination address %s", *av); 52079758b77fSLuigi Rizzo OR_BLOCK(dest_ip); 52089758b77fSLuigi Rizzo 52099758b77fSLuigi Rizzo /* 52109758b77fSLuigi Rizzo * dest. ports, optional 52119758b77fSLuigi Rizzo */ 52129758b77fSLuigi Rizzo NOT_BLOCK; /* optional "not" */ 52138ed2d749SLuigi Rizzo if (ac) { 521401750186SBrooks Davis if (_substrcmp(*av, "any") == 0 || 5215e706181bSLuigi Rizzo add_ports(cmd, *av, proto, O_IP_DSTPORT)) { 5216e706181bSLuigi Rizzo ac--; av++; 5217e706181bSLuigi Rizzo if (F_LEN(cmd) != 0) 5218e706181bSLuigi Rizzo cmd = next_cmd(cmd); 52199758b77fSLuigi Rizzo } 52208ed2d749SLuigi Rizzo } 52219758b77fSLuigi Rizzo 52229758b77fSLuigi Rizzo read_options: 5223e706181bSLuigi Rizzo if (ac && first_cmd == cmd) { 5224e706181bSLuigi Rizzo /* 5225e706181bSLuigi Rizzo * nothing specified so far, store in the rule to ease 5226e706181bSLuigi Rizzo * printout later. 5227e706181bSLuigi Rizzo */ 5228e706181bSLuigi Rizzo rule->_pad = 1; 5229e706181bSLuigi Rizzo } 52309758b77fSLuigi Rizzo prev = NULL; 52319758b77fSLuigi Rizzo while (ac) { 52328ed2d749SLuigi Rizzo char *s; 52338ed2d749SLuigi Rizzo ipfw_insn_u32 *cmd32; /* alias for cmd */ 52348ed2d749SLuigi Rizzo 52358ed2d749SLuigi Rizzo s = *av; 52368ed2d749SLuigi Rizzo cmd32 = (ipfw_insn_u32 *)cmd; 52379758b77fSLuigi Rizzo 52389758b77fSLuigi Rizzo if (*s == '!') { /* alternate syntax for NOT */ 52399758b77fSLuigi Rizzo if (cmd->len & F_NOT) 52409758b77fSLuigi Rizzo errx(EX_USAGE, "double \"not\" not allowed\n"); 52419758b77fSLuigi Rizzo cmd->len = F_NOT; 52429758b77fSLuigi Rizzo s++; 52439758b77fSLuigi Rizzo } 52449758b77fSLuigi Rizzo i = match_token(rule_options, s); 52459758b77fSLuigi Rizzo ac--; av++; 52469758b77fSLuigi Rizzo switch(i) { 52479758b77fSLuigi Rizzo case TOK_NOT: 52489758b77fSLuigi Rizzo if (cmd->len & F_NOT) 52499758b77fSLuigi Rizzo errx(EX_USAGE, "double \"not\" not allowed\n"); 52509758b77fSLuigi Rizzo cmd->len = F_NOT; 52519758b77fSLuigi Rizzo break; 52529758b77fSLuigi Rizzo 52539758b77fSLuigi Rizzo case TOK_OR: 52548ed2d749SLuigi Rizzo if (open_par == 0 || prev == NULL) 52559758b77fSLuigi Rizzo errx(EX_USAGE, "invalid \"or\" block\n"); 52569758b77fSLuigi Rizzo prev->len |= F_OR; 52579758b77fSLuigi Rizzo break; 52589758b77fSLuigi Rizzo 52598ed2d749SLuigi Rizzo case TOK_STARTBRACE: 52608ed2d749SLuigi Rizzo if (open_par) 52618ed2d749SLuigi Rizzo errx(EX_USAGE, "+nested \"(\" not allowed\n"); 52628ed2d749SLuigi Rizzo open_par = 1; 52638ed2d749SLuigi Rizzo break; 52648ed2d749SLuigi Rizzo 52658ed2d749SLuigi Rizzo case TOK_ENDBRACE: 52668ed2d749SLuigi Rizzo if (!open_par) 52678ed2d749SLuigi Rizzo errx(EX_USAGE, "+missing \")\"\n"); 52688ed2d749SLuigi Rizzo open_par = 0; 5269e706181bSLuigi Rizzo prev = NULL; 52708ed2d749SLuigi Rizzo break; 52718ed2d749SLuigi Rizzo 52729758b77fSLuigi Rizzo case TOK_IN: 52739758b77fSLuigi Rizzo fill_cmd(cmd, O_IN, 0, 0); 52749758b77fSLuigi Rizzo break; 52759758b77fSLuigi Rizzo 52769758b77fSLuigi Rizzo case TOK_OUT: 52779758b77fSLuigi Rizzo cmd->len ^= F_NOT; /* toggle F_NOT */ 52789758b77fSLuigi Rizzo fill_cmd(cmd, O_IN, 0, 0); 52799758b77fSLuigi Rizzo break; 52809758b77fSLuigi Rizzo 52816daf7ebdSBrian Feldman case TOK_DIVERTED: 52826daf7ebdSBrian Feldman fill_cmd(cmd, O_DIVERTED, 0, 3); 52836daf7ebdSBrian Feldman break; 52846daf7ebdSBrian Feldman 52856daf7ebdSBrian Feldman case TOK_DIVERTEDLOOPBACK: 52866daf7ebdSBrian Feldman fill_cmd(cmd, O_DIVERTED, 0, 1); 52876daf7ebdSBrian Feldman break; 52886daf7ebdSBrian Feldman 52896daf7ebdSBrian Feldman case TOK_DIVERTEDOUTPUT: 52906daf7ebdSBrian Feldman fill_cmd(cmd, O_DIVERTED, 0, 2); 52916daf7ebdSBrian Feldman break; 52926daf7ebdSBrian Feldman 52939758b77fSLuigi Rizzo case TOK_FRAG: 52949758b77fSLuigi Rizzo fill_cmd(cmd, O_FRAG, 0, 0); 52959758b77fSLuigi Rizzo break; 52969758b77fSLuigi Rizzo 52979758b77fSLuigi Rizzo case TOK_LAYER2: 52989758b77fSLuigi Rizzo fill_cmd(cmd, O_LAYER2, 0, 0); 52999758b77fSLuigi Rizzo break; 53009758b77fSLuigi Rizzo 53019758b77fSLuigi Rizzo case TOK_XMIT: 53029758b77fSLuigi Rizzo case TOK_RECV: 53039758b77fSLuigi Rizzo case TOK_VIA: 53049758b77fSLuigi Rizzo NEED1("recv, xmit, via require interface name" 53059758b77fSLuigi Rizzo " or address"); 53069758b77fSLuigi Rizzo fill_iface((ipfw_insn_if *)cmd, av[0]); 53079758b77fSLuigi Rizzo ac--; av++; 53089758b77fSLuigi Rizzo if (F_LEN(cmd) == 0) /* not a valid address */ 53099758b77fSLuigi Rizzo break; 53109758b77fSLuigi Rizzo if (i == TOK_XMIT) 53119758b77fSLuigi Rizzo cmd->opcode = O_XMIT; 53129758b77fSLuigi Rizzo else if (i == TOK_RECV) 53139758b77fSLuigi Rizzo cmd->opcode = O_RECV; 53149758b77fSLuigi Rizzo else if (i == TOK_VIA) 53159758b77fSLuigi Rizzo cmd->opcode = O_VIA; 53169758b77fSLuigi Rizzo break; 53179758b77fSLuigi Rizzo 53185e43aef8SLuigi Rizzo case TOK_ICMPTYPES: 53195e43aef8SLuigi Rizzo NEED1("icmptypes requires list of types"); 53205e43aef8SLuigi Rizzo fill_icmptypes((ipfw_insn_u32 *)cmd, *av); 53215e43aef8SLuigi Rizzo av++; ac--; 53225e43aef8SLuigi Rizzo break; 53235e43aef8SLuigi Rizzo 53248195404bSBrooks Davis case TOK_ICMP6TYPES: 53258195404bSBrooks Davis NEED1("icmptypes requires list of types"); 53268195404bSBrooks Davis fill_icmp6types((ipfw_insn_icmp6 *)cmd, *av); 53278195404bSBrooks Davis av++; ac--; 53288195404bSBrooks Davis break; 53298195404bSBrooks Davis 53309758b77fSLuigi Rizzo case TOK_IPTTL: 53319758b77fSLuigi Rizzo NEED1("ipttl requires TTL"); 533244c884e1SLuigi Rizzo if (strpbrk(*av, "-,")) { 533344c884e1SLuigi Rizzo if (!add_ports(cmd, *av, 0, O_IPTTL)) 533444c884e1SLuigi Rizzo errx(EX_DATAERR, "invalid ipttl %s", *av); 533544c884e1SLuigi Rizzo } else 53369758b77fSLuigi Rizzo fill_cmd(cmd, O_IPTTL, 0, strtoul(*av, NULL, 0)); 53379758b77fSLuigi Rizzo ac--; av++; 53389758b77fSLuigi Rizzo break; 53399758b77fSLuigi Rizzo 53409758b77fSLuigi Rizzo case TOK_IPID: 534144c884e1SLuigi Rizzo NEED1("ipid requires id"); 534244c884e1SLuigi Rizzo if (strpbrk(*av, "-,")) { 534344c884e1SLuigi Rizzo if (!add_ports(cmd, *av, 0, O_IPID)) 534444c884e1SLuigi Rizzo errx(EX_DATAERR, "invalid ipid %s", *av); 534544c884e1SLuigi Rizzo } else 53469758b77fSLuigi Rizzo fill_cmd(cmd, O_IPID, 0, strtoul(*av, NULL, 0)); 53479758b77fSLuigi Rizzo ac--; av++; 53489758b77fSLuigi Rizzo break; 53499758b77fSLuigi Rizzo 53509758b77fSLuigi Rizzo case TOK_IPLEN: 53519758b77fSLuigi Rizzo NEED1("iplen requires length"); 535244c884e1SLuigi Rizzo if (strpbrk(*av, "-,")) { 535344c884e1SLuigi Rizzo if (!add_ports(cmd, *av, 0, O_IPLEN)) 535444c884e1SLuigi Rizzo errx(EX_DATAERR, "invalid ip len %s", *av); 535544c884e1SLuigi Rizzo } else 53569758b77fSLuigi Rizzo fill_cmd(cmd, O_IPLEN, 0, strtoul(*av, NULL, 0)); 53579758b77fSLuigi Rizzo ac--; av++; 53589758b77fSLuigi Rizzo break; 53599758b77fSLuigi Rizzo 53609758b77fSLuigi Rizzo case TOK_IPVER: 53619758b77fSLuigi Rizzo NEED1("ipver requires version"); 53629758b77fSLuigi Rizzo fill_cmd(cmd, O_IPVER, 0, strtoul(*av, NULL, 0)); 53639758b77fSLuigi Rizzo ac--; av++; 53649758b77fSLuigi Rizzo break; 53659758b77fSLuigi Rizzo 53665e43aef8SLuigi Rizzo case TOK_IPPRECEDENCE: 53675e43aef8SLuigi Rizzo NEED1("ipprecedence requires value"); 53685e43aef8SLuigi Rizzo fill_cmd(cmd, O_IPPRECEDENCE, 0, 53695e43aef8SLuigi Rizzo (strtoul(*av, NULL, 0) & 7) << 5); 53705e43aef8SLuigi Rizzo ac--; av++; 53715e43aef8SLuigi Rizzo break; 53725e43aef8SLuigi Rizzo 53739758b77fSLuigi Rizzo case TOK_IPOPTS: 53749758b77fSLuigi Rizzo NEED1("missing argument for ipoptions"); 537552bc23abSLuigi Rizzo fill_flags(cmd, O_IPOPT, f_ipopts, *av); 53769758b77fSLuigi Rizzo ac--; av++; 53779758b77fSLuigi Rizzo break; 53789758b77fSLuigi Rizzo 53795e43aef8SLuigi Rizzo case TOK_IPTOS: 53805e43aef8SLuigi Rizzo NEED1("missing argument for iptos"); 538152bc23abSLuigi Rizzo fill_flags(cmd, O_IPTOS, f_iptos, *av); 53825e43aef8SLuigi Rizzo ac--; av++; 53835e43aef8SLuigi Rizzo break; 53845e43aef8SLuigi Rizzo 53859758b77fSLuigi Rizzo case TOK_UID: 53869758b77fSLuigi Rizzo NEED1("uid requires argument"); 53879758b77fSLuigi Rizzo { 53889758b77fSLuigi Rizzo char *end; 53899758b77fSLuigi Rizzo uid_t uid; 53909758b77fSLuigi Rizzo struct passwd *pwd; 53919758b77fSLuigi Rizzo 53929758b77fSLuigi Rizzo cmd->opcode = O_UID; 53939758b77fSLuigi Rizzo uid = strtoul(*av, &end, 0); 53949758b77fSLuigi Rizzo pwd = (*end == '\0') ? getpwuid(uid) : getpwnam(*av); 53959758b77fSLuigi Rizzo if (pwd == NULL) 53969758b77fSLuigi Rizzo errx(EX_DATAERR, "uid \"%s\" nonexistent", *av); 5397d6abaeebSMaxim Konovalov cmd32->d[0] = pwd->pw_uid; 53983a27af0dSChristian S.J. Peron cmd->len |= F_INSN_SIZE(ipfw_insn_u32); 53999758b77fSLuigi Rizzo ac--; av++; 54009758b77fSLuigi Rizzo } 54019758b77fSLuigi Rizzo break; 54029758b77fSLuigi Rizzo 54039758b77fSLuigi Rizzo case TOK_GID: 54049758b77fSLuigi Rizzo NEED1("gid requires argument"); 54059758b77fSLuigi Rizzo { 54069758b77fSLuigi Rizzo char *end; 54079758b77fSLuigi Rizzo gid_t gid; 54089758b77fSLuigi Rizzo struct group *grp; 54099758b77fSLuigi Rizzo 54109758b77fSLuigi Rizzo cmd->opcode = O_GID; 54119758b77fSLuigi Rizzo gid = strtoul(*av, &end, 0); 54129758b77fSLuigi Rizzo grp = (*end == '\0') ? getgrgid(gid) : getgrnam(*av); 54139758b77fSLuigi Rizzo if (grp == NULL) 54149758b77fSLuigi Rizzo errx(EX_DATAERR, "gid \"%s\" nonexistent", *av); 5415d6abaeebSMaxim Konovalov cmd32->d[0] = grp->gr_gid; 54163a27af0dSChristian S.J. Peron cmd->len |= F_INSN_SIZE(ipfw_insn_u32); 54179758b77fSLuigi Rizzo ac--; av++; 54189758b77fSLuigi Rizzo } 54199758b77fSLuigi Rizzo break; 54209758b77fSLuigi Rizzo 542131c88a30SChristian S.J. Peron case TOK_JAIL: 542231c88a30SChristian S.J. Peron NEED1("jail requires argument"); 542331c88a30SChristian S.J. Peron { 542431c88a30SChristian S.J. Peron char *end; 542531c88a30SChristian S.J. Peron int jid; 542631c88a30SChristian S.J. Peron 542731c88a30SChristian S.J. Peron cmd->opcode = O_JAIL; 542831c88a30SChristian S.J. Peron jid = (int)strtol(*av, &end, 0); 542931c88a30SChristian S.J. Peron if (jid < 0 || *end != '\0') 543031c88a30SChristian S.J. Peron errx(EX_DATAERR, "jail requires prison ID"); 5431d413c2e4SChristian S.J. Peron cmd32->d[0] = (uint32_t)jid; 54323a27af0dSChristian S.J. Peron cmd->len |= F_INSN_SIZE(ipfw_insn_u32); 543331c88a30SChristian S.J. Peron ac--; av++; 543431c88a30SChristian S.J. Peron } 543531c88a30SChristian S.J. Peron break; 543631c88a30SChristian S.J. Peron 54379758b77fSLuigi Rizzo case TOK_ESTAB: 54389758b77fSLuigi Rizzo fill_cmd(cmd, O_ESTAB, 0, 0); 54399758b77fSLuigi Rizzo break; 54409758b77fSLuigi Rizzo 54419758b77fSLuigi Rizzo case TOK_SETUP: 54429758b77fSLuigi Rizzo fill_cmd(cmd, O_TCPFLAGS, 0, 54439758b77fSLuigi Rizzo (TH_SYN) | ( (TH_ACK) & 0xff) <<8 ); 54449758b77fSLuigi Rizzo break; 54459758b77fSLuigi Rizzo 5446c99ee9e0SBrian Feldman case TOK_TCPDATALEN: 5447c99ee9e0SBrian Feldman NEED1("tcpdatalen requires length"); 5448c99ee9e0SBrian Feldman if (strpbrk(*av, "-,")) { 5449c99ee9e0SBrian Feldman if (!add_ports(cmd, *av, 0, O_TCPDATALEN)) 5450c99ee9e0SBrian Feldman errx(EX_DATAERR, "invalid tcpdata len %s", *av); 5451c99ee9e0SBrian Feldman } else 5452c99ee9e0SBrian Feldman fill_cmd(cmd, O_TCPDATALEN, 0, 5453c99ee9e0SBrian Feldman strtoul(*av, NULL, 0)); 5454c99ee9e0SBrian Feldman ac--; av++; 5455c99ee9e0SBrian Feldman break; 5456c99ee9e0SBrian Feldman 54579758b77fSLuigi Rizzo case TOK_TCPOPTS: 54589758b77fSLuigi Rizzo NEED1("missing argument for tcpoptions"); 54599758b77fSLuigi Rizzo fill_flags(cmd, O_TCPOPTS, f_tcpopts, *av); 54609758b77fSLuigi Rizzo ac--; av++; 54619758b77fSLuigi Rizzo break; 54629758b77fSLuigi Rizzo 54639758b77fSLuigi Rizzo case TOK_TCPSEQ: 54649758b77fSLuigi Rizzo case TOK_TCPACK: 54659758b77fSLuigi Rizzo NEED1("tcpseq/tcpack requires argument"); 54669758b77fSLuigi Rizzo cmd->len = F_INSN_SIZE(ipfw_insn_u32); 54679758b77fSLuigi Rizzo cmd->opcode = (i == TOK_TCPSEQ) ? O_TCPSEQ : O_TCPACK; 54689758b77fSLuigi Rizzo cmd32->d[0] = htonl(strtoul(*av, NULL, 0)); 54699758b77fSLuigi Rizzo ac--; av++; 54709758b77fSLuigi Rizzo break; 54719758b77fSLuigi Rizzo 54729758b77fSLuigi Rizzo case TOK_TCPWIN: 54739758b77fSLuigi Rizzo NEED1("tcpwin requires length"); 54749758b77fSLuigi Rizzo fill_cmd(cmd, O_TCPWIN, 0, 54759758b77fSLuigi Rizzo htons(strtoul(*av, NULL, 0))); 54769758b77fSLuigi Rizzo ac--; av++; 54779758b77fSLuigi Rizzo break; 54789758b77fSLuigi Rizzo 54799758b77fSLuigi Rizzo case TOK_TCPFLAGS: 54809758b77fSLuigi Rizzo NEED1("missing argument for tcpflags"); 54819758b77fSLuigi Rizzo cmd->opcode = O_TCPFLAGS; 54829758b77fSLuigi Rizzo fill_flags(cmd, O_TCPFLAGS, f_tcpflags, *av); 54839758b77fSLuigi Rizzo ac--; av++; 54849758b77fSLuigi Rizzo break; 54859758b77fSLuigi Rizzo 54869758b77fSLuigi Rizzo case TOK_KEEPSTATE: 54878ed2d749SLuigi Rizzo if (open_par) 54888ed2d749SLuigi Rizzo errx(EX_USAGE, "keep-state cannot be part " 54898ed2d749SLuigi Rizzo "of an or block"); 54900a7197a8SLuigi Rizzo if (have_state) 549152bc23abSLuigi Rizzo errx(EX_USAGE, "only one of keep-state " 54920a7197a8SLuigi Rizzo "and limit is allowed"); 549352bc23abSLuigi Rizzo have_state = cmd; 54949758b77fSLuigi Rizzo fill_cmd(cmd, O_KEEP_STATE, 0, 0); 54959758b77fSLuigi Rizzo break; 54969758b77fSLuigi Rizzo 5497254c4725SOleg Bulyzhin case TOK_LIMIT: { 54989758b77fSLuigi Rizzo ipfw_insn_limit *c = (ipfw_insn_limit *)cmd; 5499254c4725SOleg Bulyzhin int val; 5500254c4725SOleg Bulyzhin 5501254c4725SOleg Bulyzhin if (open_par) 5502254c4725SOleg Bulyzhin errx(EX_USAGE, 5503254c4725SOleg Bulyzhin "limit cannot be part of an or block"); 5504254c4725SOleg Bulyzhin if (have_state) 5505254c4725SOleg Bulyzhin errx(EX_USAGE, "only one of keep-state and " 5506254c4725SOleg Bulyzhin "limit is allowed"); 5507254c4725SOleg Bulyzhin have_state = cmd; 55089758b77fSLuigi Rizzo 55099758b77fSLuigi Rizzo cmd->len = F_INSN_SIZE(ipfw_insn_limit); 55109758b77fSLuigi Rizzo cmd->opcode = O_LIMIT; 5511254c4725SOleg Bulyzhin c->limit_mask = c->conn_limit = 0; 55129758b77fSLuigi Rizzo 5513254c4725SOleg Bulyzhin while (ac > 0) { 5514254c4725SOleg Bulyzhin if ((val = match_token(limit_masks, *av)) <= 0) 55159758b77fSLuigi Rizzo break; 55169758b77fSLuigi Rizzo c->limit_mask |= val; 55179758b77fSLuigi Rizzo ac--; av++; 55189758b77fSLuigi Rizzo } 5519254c4725SOleg Bulyzhin 55209758b77fSLuigi Rizzo if (c->limit_mask == 0) 5521254c4725SOleg Bulyzhin errx(EX_USAGE, "limit: missing limit mask"); 5522254c4725SOleg Bulyzhin 5523254c4725SOleg Bulyzhin GET_UINT_ARG(c->conn_limit, 1, 65534, TOK_LIMIT, 5524254c4725SOleg Bulyzhin rule_options); 5525254c4725SOleg Bulyzhin 55269758b77fSLuigi Rizzo ac--; av++; 55279758b77fSLuigi Rizzo break; 5528254c4725SOleg Bulyzhin } 55299758b77fSLuigi Rizzo 5530e706181bSLuigi Rizzo case TOK_PROTO: 5531e706181bSLuigi Rizzo NEED1("missing protocol"); 55328195404bSBrooks Davis if (add_proto(cmd, *av, &proto)) { 5533e706181bSLuigi Rizzo ac--; av++; 55345a155b40SLuigi Rizzo } else 5535c82b8dceSMaxim Konovalov errx(EX_DATAERR, "invalid protocol ``%s''", 5536c82b8dceSMaxim Konovalov *av); 5537e706181bSLuigi Rizzo break; 5538e706181bSLuigi Rizzo 5539e706181bSLuigi Rizzo case TOK_SRCIP: 5540e706181bSLuigi Rizzo NEED1("missing source IP"); 5541e706181bSLuigi Rizzo if (add_srcip(cmd, *av)) { 5542e706181bSLuigi Rizzo ac--; av++; 5543e706181bSLuigi Rizzo } 5544e706181bSLuigi Rizzo break; 5545e706181bSLuigi Rizzo 5546e706181bSLuigi Rizzo case TOK_DSTIP: 5547e706181bSLuigi Rizzo NEED1("missing destination IP"); 5548e706181bSLuigi Rizzo if (add_dstip(cmd, *av)) { 5549e706181bSLuigi Rizzo ac--; av++; 5550e706181bSLuigi Rizzo } 5551e706181bSLuigi Rizzo break; 5552e706181bSLuigi Rizzo 55538195404bSBrooks Davis case TOK_SRCIP6: 55548195404bSBrooks Davis NEED1("missing source IP6"); 55558195404bSBrooks Davis if (add_srcip6(cmd, *av)) { 55568195404bSBrooks Davis ac--; av++; 55578195404bSBrooks Davis } 55588195404bSBrooks Davis break; 55598195404bSBrooks Davis 55608195404bSBrooks Davis case TOK_DSTIP6: 55618195404bSBrooks Davis NEED1("missing destination IP6"); 55628195404bSBrooks Davis if (add_dstip6(cmd, *av)) { 55638195404bSBrooks Davis ac--; av++; 55648195404bSBrooks Davis } 55658195404bSBrooks Davis break; 55668195404bSBrooks Davis 5567e706181bSLuigi Rizzo case TOK_SRCPORT: 5568e706181bSLuigi Rizzo NEED1("missing source port"); 556901750186SBrooks Davis if (_substrcmp(*av, "any") == 0 || 5570e706181bSLuigi Rizzo add_ports(cmd, *av, proto, O_IP_SRCPORT)) { 5571e706181bSLuigi Rizzo ac--; av++; 5572e706181bSLuigi Rizzo } else 5573e706181bSLuigi Rizzo errx(EX_DATAERR, "invalid source port %s", *av); 5574e706181bSLuigi Rizzo break; 5575e706181bSLuigi Rizzo 5576e706181bSLuigi Rizzo case TOK_DSTPORT: 5577e706181bSLuigi Rizzo NEED1("missing destination port"); 557801750186SBrooks Davis if (_substrcmp(*av, "any") == 0 || 5579e706181bSLuigi Rizzo add_ports(cmd, *av, proto, O_IP_DSTPORT)) { 5580e706181bSLuigi Rizzo ac--; av++; 5581e706181bSLuigi Rizzo } else 5582e706181bSLuigi Rizzo errx(EX_DATAERR, "invalid destination port %s", 5583e706181bSLuigi Rizzo *av); 5584e706181bSLuigi Rizzo break; 5585e706181bSLuigi Rizzo 5586e706181bSLuigi Rizzo case TOK_MAC: 5587e706181bSLuigi Rizzo if (add_mac(cmd, ac, av)) { 5588e706181bSLuigi Rizzo ac -= 2; av += 2; 5589e706181bSLuigi Rizzo } 5590e706181bSLuigi Rizzo break; 5591e706181bSLuigi Rizzo 5592e706181bSLuigi Rizzo case TOK_MACTYPE: 5593e706181bSLuigi Rizzo NEED1("missing mac type"); 5594e706181bSLuigi Rizzo if (!add_mactype(cmd, ac, *av)) 5595c82b8dceSMaxim Konovalov errx(EX_DATAERR, "invalid mac type %s", *av); 5596e706181bSLuigi Rizzo ac--; av++; 5597e706181bSLuigi Rizzo break; 5598e706181bSLuigi Rizzo 5599010dabb0SCrist J. Clark case TOK_VERREVPATH: 5600010dabb0SCrist J. Clark fill_cmd(cmd, O_VERREVPATH, 0, 0); 5601010dabb0SCrist J. Clark break; 5602010dabb0SCrist J. Clark 560322b5770bSAndre Oppermann case TOK_VERSRCREACH: 560422b5770bSAndre Oppermann fill_cmd(cmd, O_VERSRCREACH, 0, 0); 560522b5770bSAndre Oppermann break; 560622b5770bSAndre Oppermann 56075f9541ecSAndre Oppermann case TOK_ANTISPOOF: 56085f9541ecSAndre Oppermann fill_cmd(cmd, O_ANTISPOOF, 0, 0); 56095f9541ecSAndre Oppermann break; 56105f9541ecSAndre Oppermann 5611c3e5b9f1SLuigi Rizzo case TOK_IPSEC: 5612c3e5b9f1SLuigi Rizzo fill_cmd(cmd, O_IPSEC, 0, 0); 5613c3e5b9f1SLuigi Rizzo break; 5614c3e5b9f1SLuigi Rizzo 56158195404bSBrooks Davis case TOK_IPV6: 56168195404bSBrooks Davis fill_cmd(cmd, O_IP6, 0, 0); 56178195404bSBrooks Davis break; 56188195404bSBrooks Davis 561957cd6d26SMax Laier case TOK_IPV4: 562057cd6d26SMax Laier fill_cmd(cmd, O_IP4, 0, 0); 562157cd6d26SMax Laier break; 562257cd6d26SMax Laier 56238195404bSBrooks Davis case TOK_EXT6HDR: 56248195404bSBrooks Davis fill_ext6hdr( cmd, *av ); 56258195404bSBrooks Davis ac--; av++; 56268195404bSBrooks Davis break; 56278195404bSBrooks Davis 56288195404bSBrooks Davis case TOK_FLOWID: 56298195404bSBrooks Davis if (proto != IPPROTO_IPV6 ) 56308195404bSBrooks Davis errx( EX_USAGE, "flow-id filter is active " 56318195404bSBrooks Davis "only for ipv6 protocol\n"); 56328195404bSBrooks Davis fill_flow6( (ipfw_insn_u32 *) cmd, *av ); 56338195404bSBrooks Davis ac--; av++; 56348195404bSBrooks Davis break; 56358195404bSBrooks Davis 563662ff38aeSLuigi Rizzo case TOK_COMMENT: 563762ff38aeSLuigi Rizzo fill_comment(cmd, ac, av); 563862ff38aeSLuigi Rizzo av += ac; 563962ff38aeSLuigi Rizzo ac = 0; 564062ff38aeSLuigi Rizzo break; 564162ff38aeSLuigi Rizzo 56426a7d5cb6SOleg Bulyzhin case TOK_TAGGED: 5643254c4725SOleg Bulyzhin if (ac > 0 && strpbrk(*av, "-,")) { 56446a7d5cb6SOleg Bulyzhin if (!add_ports(cmd, *av, 0, O_TAGGED)) 5645254c4725SOleg Bulyzhin errx(EX_DATAERR, "tagged: invalid tag" 5646254c4725SOleg Bulyzhin " list: %s", *av); 5647254c4725SOleg Bulyzhin } 5648254c4725SOleg Bulyzhin else { 5649254c4725SOleg Bulyzhin uint16_t tag; 5650254c4725SOleg Bulyzhin 5651254c4725SOleg Bulyzhin GET_UINT_ARG(tag, 1, 65534, TOK_TAGGED, 5652254c4725SOleg Bulyzhin rule_options); 5653254c4725SOleg Bulyzhin fill_cmd(cmd, O_TAGGED, 0, tag); 56546a7d5cb6SOleg Bulyzhin } 56556a7d5cb6SOleg Bulyzhin ac--; av++; 56566a7d5cb6SOleg Bulyzhin break; 56576a7d5cb6SOleg Bulyzhin 56588b07e49aSJulian Elischer case TOK_FIB: 56598b07e49aSJulian Elischer NEED1("fib requires fib number"); 56608b07e49aSJulian Elischer fill_cmd(cmd, O_FIB, 0, strtoul(*av, NULL, 0)); 56618b07e49aSJulian Elischer ac--; av++; 56628b07e49aSJulian Elischer break; 56638b07e49aSJulian Elischer 56649758b77fSLuigi Rizzo default: 56659758b77fSLuigi Rizzo errx(EX_USAGE, "unrecognised option [%d] %s\n", i, s); 56669758b77fSLuigi Rizzo } 56679758b77fSLuigi Rizzo if (F_LEN(cmd) > 0) { /* prepare to advance */ 56689758b77fSLuigi Rizzo prev = cmd; 56699758b77fSLuigi Rizzo cmd = next_cmd(cmd); 56709758b77fSLuigi Rizzo } 56719758b77fSLuigi Rizzo } 56729758b77fSLuigi Rizzo 56739758b77fSLuigi Rizzo done: 56749758b77fSLuigi Rizzo /* 56759758b77fSLuigi Rizzo * Now copy stuff into the rule. 56769758b77fSLuigi Rizzo * If we have a keep-state option, the first instruction 56779758b77fSLuigi Rizzo * must be a PROBE_STATE (which is generated here). 56789758b77fSLuigi Rizzo * If we have a LOG option, it was stored as the first command, 56799758b77fSLuigi Rizzo * and now must be moved to the top of the action part. 56809758b77fSLuigi Rizzo */ 56819758b77fSLuigi Rizzo dst = (ipfw_insn *)rule->cmd; 56829758b77fSLuigi Rizzo 56839758b77fSLuigi Rizzo /* 568412b5dc6aSLuigi Rizzo * First thing to write into the command stream is the match probability. 568512b5dc6aSLuigi Rizzo */ 568612b5dc6aSLuigi Rizzo if (match_prob != 1) { /* 1 means always match */ 568712b5dc6aSLuigi Rizzo dst->opcode = O_PROB; 568812b5dc6aSLuigi Rizzo dst->len = 2; 568912b5dc6aSLuigi Rizzo *((int32_t *)(dst+1)) = (int32_t)(match_prob * 0x7fffffff); 569012b5dc6aSLuigi Rizzo dst += dst->len; 569112b5dc6aSLuigi Rizzo } 569212b5dc6aSLuigi Rizzo 569312b5dc6aSLuigi Rizzo /* 56949758b77fSLuigi Rizzo * generate O_PROBE_STATE if necessary 56959758b77fSLuigi Rizzo */ 569652bc23abSLuigi Rizzo if (have_state && have_state->opcode != O_CHECK_STATE) { 56979758b77fSLuigi Rizzo fill_cmd(dst, O_PROBE_STATE, 0, 0); 56989758b77fSLuigi Rizzo dst = next_cmd(dst); 56999758b77fSLuigi Rizzo } 57006a7d5cb6SOleg Bulyzhin 57016a7d5cb6SOleg Bulyzhin /* copy all commands but O_LOG, O_KEEP_STATE, O_LIMIT, O_ALTQ, O_TAG */ 57029758b77fSLuigi Rizzo for (src = (ipfw_insn *)cmdbuf; src != cmd; src += i) { 57039758b77fSLuigi Rizzo i = F_LEN(src); 57049758b77fSLuigi Rizzo 570552bc23abSLuigi Rizzo switch (src->opcode) { 570652bc23abSLuigi Rizzo case O_LOG: 570752bc23abSLuigi Rizzo case O_KEEP_STATE: 570852bc23abSLuigi Rizzo case O_LIMIT: 5709974dfe30SBrian Feldman case O_ALTQ: 57106a7d5cb6SOleg Bulyzhin case O_TAG: 571152bc23abSLuigi Rizzo break; 571252bc23abSLuigi Rizzo default: 5713571f8c1bSLuigi Rizzo bcopy(src, dst, i * sizeof(uint32_t)); 57149758b77fSLuigi Rizzo dst += i; 57159758b77fSLuigi Rizzo } 57169758b77fSLuigi Rizzo } 57179758b77fSLuigi Rizzo 57189758b77fSLuigi Rizzo /* 571952bc23abSLuigi Rizzo * put back the have_state command as last opcode 572052bc23abSLuigi Rizzo */ 5721b985a624SLuigi Rizzo if (have_state && have_state->opcode != O_CHECK_STATE) { 572252bc23abSLuigi Rizzo i = F_LEN(have_state); 5723571f8c1bSLuigi Rizzo bcopy(have_state, dst, i * sizeof(uint32_t)); 572452bc23abSLuigi Rizzo dst += i; 572552bc23abSLuigi Rizzo } 572652bc23abSLuigi Rizzo /* 57279758b77fSLuigi Rizzo * start action section 57289758b77fSLuigi Rizzo */ 57299758b77fSLuigi Rizzo rule->act_ofs = dst - rule->cmd; 57309758b77fSLuigi Rizzo 57316a7d5cb6SOleg Bulyzhin /* put back O_LOG, O_ALTQ, O_TAG if necessary */ 5732974dfe30SBrian Feldman if (have_log) { 5733974dfe30SBrian Feldman i = F_LEN(have_log); 5734974dfe30SBrian Feldman bcopy(have_log, dst, i * sizeof(uint32_t)); 5735974dfe30SBrian Feldman dst += i; 5736974dfe30SBrian Feldman } 5737974dfe30SBrian Feldman if (have_altq) { 5738974dfe30SBrian Feldman i = F_LEN(have_altq); 5739974dfe30SBrian Feldman bcopy(have_altq, dst, i * sizeof(uint32_t)); 57409758b77fSLuigi Rizzo dst += i; 57419758b77fSLuigi Rizzo } 57426a7d5cb6SOleg Bulyzhin if (have_tag) { 57436a7d5cb6SOleg Bulyzhin i = F_LEN(have_tag); 57446a7d5cb6SOleg Bulyzhin bcopy(have_tag, dst, i * sizeof(uint32_t)); 57456a7d5cb6SOleg Bulyzhin dst += i; 57466a7d5cb6SOleg Bulyzhin } 57479758b77fSLuigi Rizzo /* 57489758b77fSLuigi Rizzo * copy all other actions 57499758b77fSLuigi Rizzo */ 57509758b77fSLuigi Rizzo for (src = (ipfw_insn *)actbuf; src != action; src += i) { 57519758b77fSLuigi Rizzo i = F_LEN(src); 5752571f8c1bSLuigi Rizzo bcopy(src, dst, i * sizeof(uint32_t)); 57539758b77fSLuigi Rizzo dst += i; 57549758b77fSLuigi Rizzo } 57559758b77fSLuigi Rizzo 5756571f8c1bSLuigi Rizzo rule->cmd_len = (uint32_t *)dst - (uint32_t *)(rule->cmd); 575762ff38aeSLuigi Rizzo i = (char *)dst - (char *)rule; 5758884be75cSThomas Moestl if (do_cmd(IP_FW_ADD, rule, (uintptr_t)&i) == -1) 57599758b77fSLuigi Rizzo err(EX_UNAVAILABLE, "getsockopt(%s)", "IP_FW_ADD"); 57609758b77fSLuigi Rizzo if (!do_quiet) 576162ff38aeSLuigi Rizzo show_ipfw(rule, 0, 0); 57629758b77fSLuigi Rizzo } 57639758b77fSLuigi Rizzo 57649758b77fSLuigi Rizzo static void 5765571f8c1bSLuigi Rizzo zero(int ac, char *av[], int optname /* IP_FW_ZERO or IP_FW_RESETLOG */) 57669758b77fSLuigi Rizzo { 5767d069a5d4SMaxim Konovalov uint32_t arg, saved_arg; 57689758b77fSLuigi Rizzo int failed = EX_OK; 576962ff38aeSLuigi Rizzo char const *name = optname == IP_FW_ZERO ? "ZERO" : "RESETLOG"; 5770d069a5d4SMaxim Konovalov char const *errstr; 57719758b77fSLuigi Rizzo 57729758b77fSLuigi Rizzo av++; ac--; 57739758b77fSLuigi Rizzo 57749758b77fSLuigi Rizzo if (!ac) { 57759758b77fSLuigi Rizzo /* clear all entries */ 5776571f8c1bSLuigi Rizzo if (do_cmd(optname, NULL, 0) < 0) 5777571f8c1bSLuigi Rizzo err(EX_UNAVAILABLE, "setsockopt(IP_FW_%s)", name); 57789758b77fSLuigi Rizzo if (!do_quiet) 5779571f8c1bSLuigi Rizzo printf("%s.\n", optname == IP_FW_ZERO ? 5780571f8c1bSLuigi Rizzo "Accounting cleared":"Logging counts reset"); 57819758b77fSLuigi Rizzo 57829758b77fSLuigi Rizzo return; 57839758b77fSLuigi Rizzo } 57849758b77fSLuigi Rizzo 57859758b77fSLuigi Rizzo while (ac) { 57869758b77fSLuigi Rizzo /* Rule number */ 57879758b77fSLuigi Rizzo if (isdigit(**av)) { 5788d069a5d4SMaxim Konovalov arg = strtonum(*av, 0, 0xffff, &errstr); 5789d069a5d4SMaxim Konovalov if (errstr) 5790d069a5d4SMaxim Konovalov errx(EX_DATAERR, 5791d069a5d4SMaxim Konovalov "invalid rule number %s\n", *av); 5792d069a5d4SMaxim Konovalov saved_arg = arg; 5793d069a5d4SMaxim Konovalov if (use_set) 5794d069a5d4SMaxim Konovalov arg |= (1 << 24) | ((use_set - 1) << 16); 57959758b77fSLuigi Rizzo av++; 57969758b77fSLuigi Rizzo ac--; 5797d069a5d4SMaxim Konovalov if (do_cmd(optname, &arg, sizeof(arg))) { 5798571f8c1bSLuigi Rizzo warn("rule %u: setsockopt(IP_FW_%s)", 5799d069a5d4SMaxim Konovalov saved_arg, name); 58009758b77fSLuigi Rizzo failed = EX_UNAVAILABLE; 58019758b77fSLuigi Rizzo } else if (!do_quiet) 5802d069a5d4SMaxim Konovalov printf("Entry %d %s.\n", saved_arg, 5803571f8c1bSLuigi Rizzo optname == IP_FW_ZERO ? 5804571f8c1bSLuigi Rizzo "cleared" : "logging count reset"); 58059758b77fSLuigi Rizzo } else { 58069758b77fSLuigi Rizzo errx(EX_USAGE, "invalid rule number ``%s''", *av); 58079758b77fSLuigi Rizzo } 58089758b77fSLuigi Rizzo } 58099758b77fSLuigi Rizzo if (failed != EX_OK) 58109758b77fSLuigi Rizzo exit(failed); 58119758b77fSLuigi Rizzo } 58129758b77fSLuigi Rizzo 58139758b77fSLuigi Rizzo static void 581426bf4d78SLuigi Rizzo flush(int force) 58159758b77fSLuigi Rizzo { 58169758b77fSLuigi Rizzo int cmd = do_pipe ? IP_DUMMYNET_FLUSH : IP_FW_FLUSH; 58179758b77fSLuigi Rizzo 581826bf4d78SLuigi Rizzo if (!force && !do_quiet) { /* need to ask user */ 58199758b77fSLuigi Rizzo int c; 58209758b77fSLuigi Rizzo 58219758b77fSLuigi Rizzo printf("Are you sure? [yn] "); 58229758b77fSLuigi Rizzo fflush(stdout); 58239758b77fSLuigi Rizzo do { 58249758b77fSLuigi Rizzo c = toupper(getc(stdin)); 58259758b77fSLuigi Rizzo while (c != '\n' && getc(stdin) != '\n') 58269758b77fSLuigi Rizzo if (feof(stdin)) 58279758b77fSLuigi Rizzo return; /* and do not flush */ 58289758b77fSLuigi Rizzo } while (c != 'Y' && c != 'N'); 58299758b77fSLuigi Rizzo printf("\n"); 58309758b77fSLuigi Rizzo if (c == 'N') /* user said no */ 58319758b77fSLuigi Rizzo return; 58329758b77fSLuigi Rizzo } 5833d069a5d4SMaxim Konovalov /* `ipfw set N flush` - is the same that `ipfw delete set N` */ 5834d069a5d4SMaxim Konovalov if (use_set) { 5835d069a5d4SMaxim Konovalov uint32_t arg = ((use_set - 1) & 0xffff) | (1 << 24); 5836d069a5d4SMaxim Konovalov if (do_cmd(IP_FW_DEL, &arg, sizeof(arg)) < 0) 5837d069a5d4SMaxim Konovalov err(EX_UNAVAILABLE, "setsockopt(IP_FW_DEL)"); 5838d069a5d4SMaxim Konovalov } else if (do_cmd(cmd, NULL, 0) < 0) 58399758b77fSLuigi Rizzo err(EX_UNAVAILABLE, "setsockopt(IP_%s_FLUSH)", 58409758b77fSLuigi Rizzo do_pipe ? "DUMMYNET" : "FW"); 58419758b77fSLuigi Rizzo if (!do_quiet) 58429758b77fSLuigi Rizzo printf("Flushed all %s.\n", do_pipe ? "pipes" : "rules"); 58439758b77fSLuigi Rizzo } 58449758b77fSLuigi Rizzo 584562ff38aeSLuigi Rizzo /* 584626bf4d78SLuigi Rizzo * Free a the (locally allocated) copy of command line arguments. 584726bf4d78SLuigi Rizzo */ 584826bf4d78SLuigi Rizzo static void 584926bf4d78SLuigi Rizzo free_args(int ac, char **av) 585026bf4d78SLuigi Rizzo { 585126bf4d78SLuigi Rizzo int i; 585226bf4d78SLuigi Rizzo 585326bf4d78SLuigi Rizzo for (i=0; i < ac; i++) 585426bf4d78SLuigi Rizzo free(av[i]); 585526bf4d78SLuigi Rizzo free(av); 585626bf4d78SLuigi Rizzo } 585726bf4d78SLuigi Rizzo 585826bf4d78SLuigi Rizzo /* 5859cd8b5ae0SRuslan Ermilov * This one handles all table-related commands 5860cd8b5ae0SRuslan Ermilov * ipfw table N add addr[/masklen] [value] 5861cd8b5ae0SRuslan Ermilov * ipfw table N delete addr[/masklen] 5862cd8b5ae0SRuslan Ermilov * ipfw table N flush 5863cd8b5ae0SRuslan Ermilov * ipfw table N list 5864cd8b5ae0SRuslan Ermilov */ 5865cd8b5ae0SRuslan Ermilov static void 5866cd8b5ae0SRuslan Ermilov table_handler(int ac, char *av[]) 5867cd8b5ae0SRuslan Ermilov { 5868cd8b5ae0SRuslan Ermilov ipfw_table_entry ent; 5869cd8b5ae0SRuslan Ermilov ipfw_table *tbl; 5870cd8b5ae0SRuslan Ermilov int do_add; 5871cd8b5ae0SRuslan Ermilov char *p; 5872cd8b5ae0SRuslan Ermilov socklen_t l; 5873cd8b5ae0SRuslan Ermilov uint32_t a; 5874cd8b5ae0SRuslan Ermilov 5875cd8b5ae0SRuslan Ermilov ac--; av++; 5876cd8b5ae0SRuslan Ermilov if (ac && isdigit(**av)) { 5877cd8b5ae0SRuslan Ermilov ent.tbl = atoi(*av); 5878cd8b5ae0SRuslan Ermilov ac--; av++; 5879cd8b5ae0SRuslan Ermilov } else 5880cd8b5ae0SRuslan Ermilov errx(EX_USAGE, "table number required"); 5881cd8b5ae0SRuslan Ermilov NEED1("table needs command"); 588201750186SBrooks Davis if (_substrcmp(*av, "add") == 0 || 588301750186SBrooks Davis _substrcmp(*av, "delete") == 0) { 5884cd8b5ae0SRuslan Ermilov do_add = **av == 'a'; 5885cd8b5ae0SRuslan Ermilov ac--; av++; 5886cd8b5ae0SRuslan Ermilov if (!ac) 5887cd8b5ae0SRuslan Ermilov errx(EX_USAGE, "IP address required"); 5888cd8b5ae0SRuslan Ermilov p = strchr(*av, '/'); 5889cd8b5ae0SRuslan Ermilov if (p) { 5890cd8b5ae0SRuslan Ermilov *p++ = '\0'; 5891cd8b5ae0SRuslan Ermilov ent.masklen = atoi(p); 5892cd8b5ae0SRuslan Ermilov if (ent.masklen > 32) 5893cd8b5ae0SRuslan Ermilov errx(EX_DATAERR, "bad width ``%s''", p); 5894cd8b5ae0SRuslan Ermilov } else 5895cd8b5ae0SRuslan Ermilov ent.masklen = 32; 5896cd8b5ae0SRuslan Ermilov if (lookup_host(*av, (struct in_addr *)&ent.addr) != 0) 58971a41a8e4SRuslan Ermilov errx(EX_NOHOST, "hostname ``%s'' unknown", *av); 5898cd8b5ae0SRuslan Ermilov ac--; av++; 5899c487be96SJulian Elischer if (do_add && ac) { 5900c487be96SJulian Elischer unsigned int tval; 5901c487be96SJulian Elischer /* isdigit is a bit of a hack here.. */ 5902c487be96SJulian Elischer if (strchr(*av, (int)'.') == NULL && isdigit(**av)) { 5903cd8b5ae0SRuslan Ermilov ent.value = strtoul(*av, NULL, 0); 5904c487be96SJulian Elischer } else { 5905c487be96SJulian Elischer if (lookup_host(*av, (struct in_addr *)&tval) == 0) { 5906c487be96SJulian Elischer /* The value must be stored in host order * 5907c487be96SJulian Elischer * so that the values < 65k can be distinguished */ 5908c487be96SJulian Elischer ent.value = ntohl(tval); 5909c487be96SJulian Elischer } else { 5910c487be96SJulian Elischer errx(EX_NOHOST, "hostname ``%s'' unknown", *av); 5911c487be96SJulian Elischer } 5912c487be96SJulian Elischer } 5913c487be96SJulian Elischer } else 5914cd8b5ae0SRuslan Ermilov ent.value = 0; 5915cd8b5ae0SRuslan Ermilov if (do_cmd(do_add ? IP_FW_TABLE_ADD : IP_FW_TABLE_DEL, 5916905c41b5SJulian Elischer &ent, sizeof(ent)) < 0) { 591721899082SJulian Elischer /* If running silent, don't bomb out on these errors. */ 591821899082SJulian Elischer if (!(do_quiet && (errno == (do_add ? EEXIST : ESRCH)))) 591921899082SJulian Elischer err(EX_OSERR, "setsockopt(IP_FW_TABLE_%s)", 592021899082SJulian Elischer do_add ? "ADD" : "DEL"); 592121899082SJulian Elischer /* In silent mode, react to a failed add by deleting */ 5922dbadd6b0SJulian Elischer if (do_add) { 592321899082SJulian Elischer do_cmd(IP_FW_TABLE_DEL, &ent, sizeof(ent)); 592421899082SJulian Elischer if (do_cmd(IP_FW_TABLE_ADD, 592521899082SJulian Elischer &ent, sizeof(ent)) < 0) 592621899082SJulian Elischer err(EX_OSERR, 592721899082SJulian Elischer "setsockopt(IP_FW_TABLE_ADD)"); 5928dbadd6b0SJulian Elischer } 5929905c41b5SJulian Elischer } 593001750186SBrooks Davis } else if (_substrcmp(*av, "flush") == 0) { 5931cd8b5ae0SRuslan Ermilov if (do_cmd(IP_FW_TABLE_FLUSH, &ent.tbl, sizeof(ent.tbl)) < 0) 5932cd8b5ae0SRuslan Ermilov err(EX_OSERR, "setsockopt(IP_FW_TABLE_FLUSH)"); 593301750186SBrooks Davis } else if (_substrcmp(*av, "list") == 0) { 5934cd8b5ae0SRuslan Ermilov a = ent.tbl; 5935cd8b5ae0SRuslan Ermilov l = sizeof(a); 5936cd8b5ae0SRuslan Ermilov if (do_cmd(IP_FW_TABLE_GETSIZE, &a, (uintptr_t)&l) < 0) 5937cd8b5ae0SRuslan Ermilov err(EX_OSERR, "getsockopt(IP_FW_TABLE_GETSIZE)"); 5938cd8b5ae0SRuslan Ermilov l = sizeof(*tbl) + a * sizeof(ipfw_table_entry); 5939cd8b5ae0SRuslan Ermilov tbl = malloc(l); 5940cd8b5ae0SRuslan Ermilov if (tbl == NULL) 5941cd8b5ae0SRuslan Ermilov err(EX_OSERR, "malloc"); 5942cd8b5ae0SRuslan Ermilov tbl->tbl = ent.tbl; 5943cd8b5ae0SRuslan Ermilov if (do_cmd(IP_FW_TABLE_LIST, tbl, (uintptr_t)&l) < 0) 5944cd8b5ae0SRuslan Ermilov err(EX_OSERR, "getsockopt(IP_FW_TABLE_LIST)"); 5945cd8b5ae0SRuslan Ermilov for (a = 0; a < tbl->cnt; a++) { 5946c487be96SJulian Elischer unsigned int tval; 5947c487be96SJulian Elischer tval = tbl->ent[a].value; 59480943a3b7SJulian Elischer if (do_value_as_ip) { 5949c487be96SJulian Elischer char tbuf[128]; 5950afad78e2SJulian Elischer strncpy(tbuf, inet_ntoa(*(struct in_addr *) 5951c487be96SJulian Elischer &tbl->ent[a].addr), 127); 59520943a3b7SJulian Elischer /* inet_ntoa expects network order */ 5953c487be96SJulian Elischer tval = htonl(tval); 5954afad78e2SJulian Elischer printf("%s/%u %s\n", tbuf, tbl->ent[a].masklen, 5955c487be96SJulian Elischer inet_ntoa(*(struct in_addr *)&tval)); 5956c487be96SJulian Elischer } else { 5957cd8b5ae0SRuslan Ermilov printf("%s/%u %u\n", 5958cd8b5ae0SRuslan Ermilov inet_ntoa(*(struct in_addr *)&tbl->ent[a].addr), 59590943a3b7SJulian Elischer tbl->ent[a].masklen, tval); 5960cd8b5ae0SRuslan Ermilov } 5961c487be96SJulian Elischer } 5962cd8b5ae0SRuslan Ermilov } else 5963cd8b5ae0SRuslan Ermilov errx(EX_USAGE, "invalid table command %s", *av); 5964cd8b5ae0SRuslan Ermilov } 5965cd8b5ae0SRuslan Ermilov 5966ff2f6fe8SPaolo Pisati static void 5967ff2f6fe8SPaolo Pisati show_nat(int ac, char **av) { 5968ff2f6fe8SPaolo Pisati struct cfg_nat *n; 5969ff2f6fe8SPaolo Pisati struct cfg_redir *e; 5970ff2f6fe8SPaolo Pisati int cmd, i, nbytes, do_cfg, do_rule, frule, lrule, nalloc, size; 5971c879f6ecSPaolo Pisati int nat_cnt, redir_cnt, r; 5972ff2f6fe8SPaolo Pisati uint8_t *data, *p; 5973ff2f6fe8SPaolo Pisati char **lav, *endptr; 5974ff2f6fe8SPaolo Pisati 5975ff2f6fe8SPaolo Pisati do_rule = 0; 5976ff2f6fe8SPaolo Pisati nalloc = 1024; 5977ff2f6fe8SPaolo Pisati size = 0; 5978ff2f6fe8SPaolo Pisati data = NULL; 5979d956bdf3SPaolo Pisati frule = 0; 5980d956bdf3SPaolo Pisati lrule = 65535; /* max ipfw rule number */ 5981ff2f6fe8SPaolo Pisati ac--; av++; 5982ff2f6fe8SPaolo Pisati 5983ff2f6fe8SPaolo Pisati /* Parse parameters. */ 5984ff2f6fe8SPaolo Pisati for (cmd = IP_FW_NAT_GET_LOG, do_cfg = 0; ac != 0; ac--, av++) { 5985ff2f6fe8SPaolo Pisati if (!strncmp(av[0], "config", strlen(av[0]))) { 5986ff2f6fe8SPaolo Pisati cmd = IP_FW_NAT_GET_CONFIG, do_cfg = 1; 5987ff2f6fe8SPaolo Pisati continue; 5988ff2f6fe8SPaolo Pisati } 5989ff2f6fe8SPaolo Pisati /* Convert command line rule #. */ 5990ff2f6fe8SPaolo Pisati frule = lrule = strtoul(av[0], &endptr, 10); 5991ff2f6fe8SPaolo Pisati if (*endptr == '-') 5992ff2f6fe8SPaolo Pisati lrule = strtoul(endptr+1, &endptr, 10); 5993ff2f6fe8SPaolo Pisati if (lrule == 0) 5994ff2f6fe8SPaolo Pisati err(EX_USAGE, "invalid rule number: %s", av[0]); 5995ff2f6fe8SPaolo Pisati do_rule = 1; 5996ff2f6fe8SPaolo Pisati } 5997ff2f6fe8SPaolo Pisati 5998ff2f6fe8SPaolo Pisati nbytes = nalloc; 5999ff2f6fe8SPaolo Pisati while (nbytes >= nalloc) { 6000ff2f6fe8SPaolo Pisati nalloc = nalloc * 2; 6001ff2f6fe8SPaolo Pisati nbytes = nalloc; 6002ff2f6fe8SPaolo Pisati if ((data = realloc(data, nbytes)) == NULL) 6003ff2f6fe8SPaolo Pisati err(EX_OSERR, "realloc"); 6004ff2f6fe8SPaolo Pisati if (do_cmd(cmd, data, (uintptr_t)&nbytes) < 0) 6005ff2f6fe8SPaolo Pisati err(EX_OSERR, "getsockopt(IP_FW_GET_%s)", 6006ff2f6fe8SPaolo Pisati (cmd == IP_FW_NAT_GET_LOG) ? "LOG" : "CONFIG"); 6007ff2f6fe8SPaolo Pisati } 6008ff2f6fe8SPaolo Pisati if (nbytes == 0) 6009ff2f6fe8SPaolo Pisati exit(0); 6010ff2f6fe8SPaolo Pisati if (do_cfg) { 6011ff2f6fe8SPaolo Pisati nat_cnt = *((int *)data); 6012ff2f6fe8SPaolo Pisati for (i = sizeof(nat_cnt); nat_cnt; nat_cnt--) { 6013ff2f6fe8SPaolo Pisati n = (struct cfg_nat *)&data[i]; 6014d956bdf3SPaolo Pisati if (frule <= n->id && lrule >= n->id) 6015ff2f6fe8SPaolo Pisati print_nat_config(&data[i]); 6016ff2f6fe8SPaolo Pisati i += sizeof(struct cfg_nat); 6017c879f6ecSPaolo Pisati for (redir_cnt = 0; redir_cnt < n->redir_cnt; redir_cnt++) { 6018ff2f6fe8SPaolo Pisati e = (struct cfg_redir *)&data[i]; 6019ff2f6fe8SPaolo Pisati i += sizeof(struct cfg_redir) + e->spool_cnt * 6020ff2f6fe8SPaolo Pisati sizeof(struct cfg_spool); 6021ff2f6fe8SPaolo Pisati } 6022c879f6ecSPaolo Pisati } 6023ff2f6fe8SPaolo Pisati } else { 6024ff2f6fe8SPaolo Pisati for (i = 0; 1; i += LIBALIAS_BUF_SIZE + sizeof(int)) { 6025ff2f6fe8SPaolo Pisati p = &data[i]; 6026ff2f6fe8SPaolo Pisati if (p == data + nbytes) 6027ff2f6fe8SPaolo Pisati break; 6028ff2f6fe8SPaolo Pisati bcopy(p, &r, sizeof(int)); 6029ff2f6fe8SPaolo Pisati if (do_rule) { 6030ff2f6fe8SPaolo Pisati if (!(frule <= r && lrule >= r)) 6031ff2f6fe8SPaolo Pisati continue; 6032ff2f6fe8SPaolo Pisati } 6033ff2f6fe8SPaolo Pisati printf("nat %u: %s\n", r, p+sizeof(int)); 6034ff2f6fe8SPaolo Pisati } 6035ff2f6fe8SPaolo Pisati } 6036ff2f6fe8SPaolo Pisati } 6037ff2f6fe8SPaolo Pisati 6038cd8b5ae0SRuslan Ermilov /* 603926bf4d78SLuigi Rizzo * Called with the arguments (excluding program name). 604026bf4d78SLuigi Rizzo * Returns 0 if successful, 1 if empty command, errx() in case of errors. 604162ff38aeSLuigi Rizzo */ 60429758b77fSLuigi Rizzo static int 6043571f8c1bSLuigi Rizzo ipfw_main(int oldac, char **oldav) 60449758b77fSLuigi Rizzo { 604562ff38aeSLuigi Rizzo int ch, ac, save_ac; 6046d069a5d4SMaxim Konovalov const char *errstr; 604762ff38aeSLuigi Rizzo char **av, **save_av; 604862ff38aeSLuigi Rizzo int do_acct = 0; /* Show packet/byte count */ 6049571f8c1bSLuigi Rizzo 605062ff38aeSLuigi Rizzo #define WHITESP " \t\f\v\n\r" 605126bf4d78SLuigi Rizzo if (oldac == 0) 605226bf4d78SLuigi Rizzo return 1; 605326bf4d78SLuigi Rizzo else if (oldac == 1) { 6054571f8c1bSLuigi Rizzo /* 6055571f8c1bSLuigi Rizzo * If we are called with a single string, try to split it into 6056571f8c1bSLuigi Rizzo * arguments for subsequent parsing. 6057571f8c1bSLuigi Rizzo * But first, remove spaces after a ',', by copying the string 6058571f8c1bSLuigi Rizzo * in-place. 6059571f8c1bSLuigi Rizzo */ 606062ff38aeSLuigi Rizzo char *arg = oldav[0]; /* The string... */ 6061571f8c1bSLuigi Rizzo int l = strlen(arg); 6062571f8c1bSLuigi Rizzo int copy = 0; /* 1 if we need to copy, 0 otherwise */ 6063571f8c1bSLuigi Rizzo int i, j; 606462ff38aeSLuigi Rizzo for (i = j = 0; i < l; i++) { 606562ff38aeSLuigi Rizzo if (arg[i] == '#') /* comment marker */ 606662ff38aeSLuigi Rizzo break; 6067571f8c1bSLuigi Rizzo if (copy) { 6068571f8c1bSLuigi Rizzo arg[j++] = arg[i]; 606962ff38aeSLuigi Rizzo copy = !index("," WHITESP, arg[i]); 6070571f8c1bSLuigi Rizzo } else { 607162ff38aeSLuigi Rizzo copy = !index(WHITESP, arg[i]); 6072571f8c1bSLuigi Rizzo if (copy) 6073571f8c1bSLuigi Rizzo arg[j++] = arg[i]; 6074571f8c1bSLuigi Rizzo } 607562ff38aeSLuigi Rizzo } 6076571f8c1bSLuigi Rizzo if (!copy && j > 0) /* last char was a 'blank', remove it */ 6077571f8c1bSLuigi Rizzo j--; 6078571f8c1bSLuigi Rizzo l = j; /* the new argument length */ 6079571f8c1bSLuigi Rizzo arg[j++] = '\0'; 608062ff38aeSLuigi Rizzo if (l == 0) /* empty string! */ 608126bf4d78SLuigi Rizzo return 1; 6082571f8c1bSLuigi Rizzo 6083571f8c1bSLuigi Rizzo /* 6084571f8c1bSLuigi Rizzo * First, count number of arguments. Because of the previous 608562ff38aeSLuigi Rizzo * processing, this is just the number of blanks plus 1. 6086571f8c1bSLuigi Rizzo */ 6087571f8c1bSLuigi Rizzo for (i = 0, ac = 1; i < l; i++) 608862ff38aeSLuigi Rizzo if (index(WHITESP, arg[i]) != NULL) 6089571f8c1bSLuigi Rizzo ac++; 6090571f8c1bSLuigi Rizzo 6091571f8c1bSLuigi Rizzo av = calloc(ac, sizeof(char *)); 6092571f8c1bSLuigi Rizzo 6093571f8c1bSLuigi Rizzo /* 6094571f8c1bSLuigi Rizzo * Second, copy arguments from cmd[] to av[]. For each one, 6095571f8c1bSLuigi Rizzo * j is the initial character, i is the one past the end. 6096571f8c1bSLuigi Rizzo */ 609762ff38aeSLuigi Rizzo for (ac = 0, i = j = 0; i < l; i++) 609862ff38aeSLuigi Rizzo if (index(WHITESP, arg[i]) != NULL || i == l-1) { 6099571f8c1bSLuigi Rizzo if (i == l-1) 6100571f8c1bSLuigi Rizzo i++; 6101571f8c1bSLuigi Rizzo av[ac] = calloc(i-j+1, 1); 6102571f8c1bSLuigi Rizzo bcopy(arg+j, av[ac], i-j); 6103571f8c1bSLuigi Rizzo ac++; 6104571f8c1bSLuigi Rizzo j = i + 1; 6105571f8c1bSLuigi Rizzo } 6106571f8c1bSLuigi Rizzo } else { 6107571f8c1bSLuigi Rizzo /* 6108571f8c1bSLuigi Rizzo * If an argument ends with ',' join with the next one. 6109571f8c1bSLuigi Rizzo */ 6110571f8c1bSLuigi Rizzo int first, i, l; 6111571f8c1bSLuigi Rizzo 6112571f8c1bSLuigi Rizzo av = calloc(oldac, sizeof(char *)); 6113571f8c1bSLuigi Rizzo for (first = i = ac = 0, l = 0; i < oldac; i++) { 6114571f8c1bSLuigi Rizzo char *arg = oldav[i]; 6115571f8c1bSLuigi Rizzo int k = strlen(arg); 6116571f8c1bSLuigi Rizzo 6117571f8c1bSLuigi Rizzo l += k; 6118571f8c1bSLuigi Rizzo if (arg[k-1] != ',' || i == oldac-1) { 6119571f8c1bSLuigi Rizzo /* Time to copy. */ 6120571f8c1bSLuigi Rizzo av[ac] = calloc(l+1, 1); 6121571f8c1bSLuigi Rizzo for (l=0; first <= i; first++) { 6122571f8c1bSLuigi Rizzo strcat(av[ac]+l, oldav[first]); 6123571f8c1bSLuigi Rizzo l += strlen(oldav[first]); 6124571f8c1bSLuigi Rizzo } 6125571f8c1bSLuigi Rizzo ac++; 6126571f8c1bSLuigi Rizzo l = 0; 6127571f8c1bSLuigi Rizzo first = i+1; 6128571f8c1bSLuigi Rizzo } 6129571f8c1bSLuigi Rizzo } 6130571f8c1bSLuigi Rizzo } 61319758b77fSLuigi Rizzo 61329758b77fSLuigi Rizzo /* Set the force flag for non-interactive processes */ 6133cec4ab6aSMaxim Konovalov if (!do_force) 61349758b77fSLuigi Rizzo do_force = !isatty(STDIN_FILENO); 61359758b77fSLuigi Rizzo 613662ff38aeSLuigi Rizzo /* Save arguments for final freeing of memory. */ 613762ff38aeSLuigi Rizzo save_ac = ac; 613862ff38aeSLuigi Rizzo save_av = av; 613962ff38aeSLuigi Rizzo 614062ff38aeSLuigi Rizzo optind = optreset = 0; 61410943a3b7SJulian Elischer while ((ch = getopt(ac, av, "abcdefhinNqs:STtv")) != -1) 61429758b77fSLuigi Rizzo switch (ch) { 6143571f8c1bSLuigi Rizzo case 'a': 6144571f8c1bSLuigi Rizzo do_acct = 1; 6145571f8c1bSLuigi Rizzo break; 6146571f8c1bSLuigi Rizzo 6147ac6cec51SLuigi Rizzo case 'b': 6148ac6cec51SLuigi Rizzo comment_only = 1; 6149ac6cec51SLuigi Rizzo do_compact = 1; 6150ac6cec51SLuigi Rizzo break; 6151ac6cec51SLuigi Rizzo 6152571f8c1bSLuigi Rizzo case 'c': 6153571f8c1bSLuigi Rizzo do_compact = 1; 6154571f8c1bSLuigi Rizzo break; 6155571f8c1bSLuigi Rizzo 6156571f8c1bSLuigi Rizzo case 'd': 6157571f8c1bSLuigi Rizzo do_dynamic = 1; 6158571f8c1bSLuigi Rizzo break; 6159571f8c1bSLuigi Rizzo 6160571f8c1bSLuigi Rizzo case 'e': 6161571f8c1bSLuigi Rizzo do_expired = 1; 6162571f8c1bSLuigi Rizzo break; 6163571f8c1bSLuigi Rizzo 6164571f8c1bSLuigi Rizzo case 'f': 6165571f8c1bSLuigi Rizzo do_force = 1; 6166571f8c1bSLuigi Rizzo break; 6167571f8c1bSLuigi Rizzo 61689758b77fSLuigi Rizzo case 'h': /* help */ 616926bf4d78SLuigi Rizzo free_args(save_ac, save_av); 61709758b77fSLuigi Rizzo help(); 61719758b77fSLuigi Rizzo break; /* NOTREACHED */ 61729758b77fSLuigi Rizzo 61730943a3b7SJulian Elischer case 'i': 61740943a3b7SJulian Elischer do_value_as_ip = 1; 61750943a3b7SJulian Elischer break; 61760943a3b7SJulian Elischer 6177571f8c1bSLuigi Rizzo case 'n': 6178571f8c1bSLuigi Rizzo test_only = 1; 61799758b77fSLuigi Rizzo break; 6180571f8c1bSLuigi Rizzo 61819758b77fSLuigi Rizzo case 'N': 61829758b77fSLuigi Rizzo do_resolv = 1; 61839758b77fSLuigi Rizzo break; 6184571f8c1bSLuigi Rizzo 61859758b77fSLuigi Rizzo case 'q': 61869758b77fSLuigi Rizzo do_quiet = 1; 61879758b77fSLuigi Rizzo break; 6188571f8c1bSLuigi Rizzo 6189571f8c1bSLuigi Rizzo case 's': /* sort */ 6190571f8c1bSLuigi Rizzo do_sort = atoi(optarg); 6191571f8c1bSLuigi Rizzo break; 6192571f8c1bSLuigi Rizzo 619343405724SLuigi Rizzo case 'S': 619443405724SLuigi Rizzo show_sets = 1; 619543405724SLuigi Rizzo break; 6196571f8c1bSLuigi Rizzo 61979758b77fSLuigi Rizzo case 't': 61989758b77fSLuigi Rizzo do_time = 1; 61999758b77fSLuigi Rizzo break; 6200571f8c1bSLuigi Rizzo 62011b43a426SLuigi Rizzo case 'T': 62021b43a426SLuigi Rizzo do_time = 2; /* numeric timestamp */ 62031b43a426SLuigi Rizzo break; 62041b43a426SLuigi Rizzo 62059758b77fSLuigi Rizzo case 'v': /* verbose */ 6206571f8c1bSLuigi Rizzo verbose = 1; 62079758b77fSLuigi Rizzo break; 6208571f8c1bSLuigi Rizzo 62099758b77fSLuigi Rizzo default: 621026bf4d78SLuigi Rizzo free_args(save_ac, save_av); 621126bf4d78SLuigi Rizzo return 1; 62129758b77fSLuigi Rizzo } 62139758b77fSLuigi Rizzo 62149758b77fSLuigi Rizzo ac -= optind; 62159758b77fSLuigi Rizzo av += optind; 62169758b77fSLuigi Rizzo NEED1("bad arguments, for usage summary ``ipfw''"); 62179758b77fSLuigi Rizzo 62189758b77fSLuigi Rizzo /* 621926bf4d78SLuigi Rizzo * An undocumented behaviour of ipfw1 was to allow rule numbers first, 622026bf4d78SLuigi Rizzo * e.g. "100 add allow ..." instead of "add 100 allow ...". 622126bf4d78SLuigi Rizzo * In case, swap first and second argument to get the normal form. 622226bf4d78SLuigi Rizzo */ 622326bf4d78SLuigi Rizzo if (ac > 1 && isdigit(*av[0])) { 622426bf4d78SLuigi Rizzo char *p = av[0]; 622526bf4d78SLuigi Rizzo 622626bf4d78SLuigi Rizzo av[0] = av[1]; 622726bf4d78SLuigi Rizzo av[1] = p; 622826bf4d78SLuigi Rizzo } 622926bf4d78SLuigi Rizzo 623026bf4d78SLuigi Rizzo /* 6231ff2f6fe8SPaolo Pisati * Optional: pipe, queue or nat. 62329758b77fSLuigi Rizzo */ 6233ff2f6fe8SPaolo Pisati do_nat = 0; 62346fa74f7dSMaxim Konovalov do_pipe = 0; 6235ff2f6fe8SPaolo Pisati if (!strncmp(*av, "nat", strlen(*av))) 6236ff2f6fe8SPaolo Pisati do_nat = 1; 6237ff2f6fe8SPaolo Pisati else if (!strncmp(*av, "pipe", strlen(*av))) 62389758b77fSLuigi Rizzo do_pipe = 1; 623901750186SBrooks Davis else if (_substrcmp(*av, "queue") == 0) 62409758b77fSLuigi Rizzo do_pipe = 2; 6241d069a5d4SMaxim Konovalov else if (!strncmp(*av, "set", strlen(*av))) { 6242d069a5d4SMaxim Konovalov if (ac > 1 && isdigit(av[1][0])) { 6243d069a5d4SMaxim Konovalov use_set = strtonum(av[1], 0, RESVD_SET, &errstr); 6244d069a5d4SMaxim Konovalov if (errstr) 6245d069a5d4SMaxim Konovalov errx(EX_DATAERR, 6246d069a5d4SMaxim Konovalov "invalid set number %s\n", av[1]); 6247d069a5d4SMaxim Konovalov ac -= 2; av += 2; use_set++; 6248d069a5d4SMaxim Konovalov } 6249d069a5d4SMaxim Konovalov } 6250d069a5d4SMaxim Konovalov 6251ff2f6fe8SPaolo Pisati if (do_pipe || do_nat) { 62529758b77fSLuigi Rizzo ac--; 62539758b77fSLuigi Rizzo av++; 62549758b77fSLuigi Rizzo } 62559758b77fSLuigi Rizzo NEED1("missing command"); 62569758b77fSLuigi Rizzo 62579758b77fSLuigi Rizzo /* 6258ff2f6fe8SPaolo Pisati * For pipes, queues and nats we normally say 'nat|pipe NN config' 6259ff2f6fe8SPaolo Pisati * but the code is easier to parse as 'nat|pipe config NN' 62609758b77fSLuigi Rizzo * so we swap the two arguments. 62619758b77fSLuigi Rizzo */ 6262ff2f6fe8SPaolo Pisati if ((do_pipe || do_nat) && ac > 1 && isdigit(*av[0])) { 62639758b77fSLuigi Rizzo char *p = av[0]; 626426bf4d78SLuigi Rizzo 62659758b77fSLuigi Rizzo av[0] = av[1]; 62669758b77fSLuigi Rizzo av[1] = p; 62679758b77fSLuigi Rizzo } 6268571f8c1bSLuigi Rizzo 6269d069a5d4SMaxim Konovalov int try_next = 0; 6270d069a5d4SMaxim Konovalov if (use_set == 0) { 627101750186SBrooks Davis if (_substrcmp(*av, "add") == 0) 62729758b77fSLuigi Rizzo add(ac, av); 6273ff2f6fe8SPaolo Pisati else if (do_nat && _substrcmp(*av, "show") == 0) 6274ff2f6fe8SPaolo Pisati show_nat(ac, av); 627501750186SBrooks Davis else if (do_pipe && _substrcmp(*av, "config") == 0) 62769758b77fSLuigi Rizzo config_pipe(ac, av); 6277ff2f6fe8SPaolo Pisati else if (do_nat && _substrcmp(*av, "config") == 0) 6278ff2f6fe8SPaolo Pisati config_nat(ac, av); 6279d069a5d4SMaxim Konovalov else if (_substrcmp(*av, "set") == 0) 6280d069a5d4SMaxim Konovalov sets_handler(ac, av); 6281d069a5d4SMaxim Konovalov else if (_substrcmp(*av, "table") == 0) 6282d069a5d4SMaxim Konovalov table_handler(ac, av); 6283d069a5d4SMaxim Konovalov else if (_substrcmp(*av, "enable") == 0) 6284d069a5d4SMaxim Konovalov sysctl_handler(ac, av, 1); 6285d069a5d4SMaxim Konovalov else if (_substrcmp(*av, "disable") == 0) 6286d069a5d4SMaxim Konovalov sysctl_handler(ac, av, 0); 6287d069a5d4SMaxim Konovalov else 6288d069a5d4SMaxim Konovalov try_next = 1; 6289d069a5d4SMaxim Konovalov } 6290d069a5d4SMaxim Konovalov 6291d069a5d4SMaxim Konovalov if (use_set || try_next) { 6292d069a5d4SMaxim Konovalov if (_substrcmp(*av, "delete") == 0) 62939758b77fSLuigi Rizzo delete(ac, av); 629401750186SBrooks Davis else if (_substrcmp(*av, "flush") == 0) 629526bf4d78SLuigi Rizzo flush(do_force); 629601750186SBrooks Davis else if (_substrcmp(*av, "zero") == 0) 6297571f8c1bSLuigi Rizzo zero(ac, av, IP_FW_ZERO); 629801750186SBrooks Davis else if (_substrcmp(*av, "resetlog") == 0) 6299571f8c1bSLuigi Rizzo zero(ac, av, IP_FW_RESETLOG); 630001750186SBrooks Davis else if (_substrcmp(*av, "print") == 0 || 630101750186SBrooks Davis _substrcmp(*av, "list") == 0) 630262ff38aeSLuigi Rizzo list(ac, av, do_acct); 630301750186SBrooks Davis else if (_substrcmp(*av, "show") == 0) 630462ff38aeSLuigi Rizzo list(ac, av, 1 /* show counters */); 630562ff38aeSLuigi Rizzo else 63069758b77fSLuigi Rizzo errx(EX_USAGE, "bad command `%s'", *av); 6307d069a5d4SMaxim Konovalov } 630862ff38aeSLuigi Rizzo 630962ff38aeSLuigi Rizzo /* Free memory allocated in the argument parsing. */ 631026bf4d78SLuigi Rizzo free_args(save_ac, save_av); 63119758b77fSLuigi Rizzo return 0; 63129758b77fSLuigi Rizzo } 63139758b77fSLuigi Rizzo 63149758b77fSLuigi Rizzo 63159758b77fSLuigi Rizzo static void 63169758b77fSLuigi Rizzo ipfw_readfile(int ac, char *av[]) 63179758b77fSLuigi Rizzo { 63189758b77fSLuigi Rizzo #define MAX_ARGS 32 63199758b77fSLuigi Rizzo char buf[BUFSIZ]; 632062ff38aeSLuigi Rizzo char *cmd = NULL, *filename = av[ac-1]; 632162ff38aeSLuigi Rizzo int c, lineno=0; 63229758b77fSLuigi Rizzo FILE *f = NULL; 63239758b77fSLuigi Rizzo pid_t preproc = 0; 63249758b77fSLuigi Rizzo 632562ff38aeSLuigi Rizzo filename = av[ac-1]; 632662ff38aeSLuigi Rizzo 6327cec4ab6aSMaxim Konovalov while ((c = getopt(ac, av, "cfNnp:qS")) != -1) { 63289758b77fSLuigi Rizzo switch(c) { 632962ff38aeSLuigi Rizzo case 'c': 633062ff38aeSLuigi Rizzo do_compact = 1; 633162ff38aeSLuigi Rizzo break; 633262ff38aeSLuigi Rizzo 6333cec4ab6aSMaxim Konovalov case 'f': 6334cec4ab6aSMaxim Konovalov do_force = 1; 6335cec4ab6aSMaxim Konovalov break; 6336cec4ab6aSMaxim Konovalov 633762ff38aeSLuigi Rizzo case 'N': 633862ff38aeSLuigi Rizzo do_resolv = 1; 633962ff38aeSLuigi Rizzo break; 634062ff38aeSLuigi Rizzo 6341571f8c1bSLuigi Rizzo case 'n': 6342571f8c1bSLuigi Rizzo test_only = 1; 6343571f8c1bSLuigi Rizzo break; 6344571f8c1bSLuigi Rizzo 63459758b77fSLuigi Rizzo case 'p': 63469758b77fSLuigi Rizzo cmd = optarg; 634762ff38aeSLuigi Rizzo /* 634862ff38aeSLuigi Rizzo * Skip previous args and delete last one, so we 634962ff38aeSLuigi Rizzo * pass all but the last argument to the preprocessor 635062ff38aeSLuigi Rizzo * via av[optind-1] 635162ff38aeSLuigi Rizzo */ 635262ff38aeSLuigi Rizzo av += optind - 1; 635362ff38aeSLuigi Rizzo ac -= optind - 1; 6354c2438409SMaxim Konovalov if (ac < 2) 6355c2438409SMaxim Konovalov errx(EX_USAGE, "no filename argument"); 635662ff38aeSLuigi Rizzo av[ac-1] = NULL; 635762ff38aeSLuigi Rizzo fprintf(stderr, "command is %s\n", av[0]); 63589758b77fSLuigi Rizzo break; 63599758b77fSLuigi Rizzo 63609758b77fSLuigi Rizzo case 'q': 636162ff38aeSLuigi Rizzo do_quiet = 1; 636262ff38aeSLuigi Rizzo break; 636362ff38aeSLuigi Rizzo 636462ff38aeSLuigi Rizzo case 'S': 636562ff38aeSLuigi Rizzo show_sets = 1; 63669758b77fSLuigi Rizzo break; 63679758b77fSLuigi Rizzo 63689758b77fSLuigi Rizzo default: 63699758b77fSLuigi Rizzo errx(EX_USAGE, "bad arguments, for usage" 63709758b77fSLuigi Rizzo " summary ``ipfw''"); 63719758b77fSLuigi Rizzo } 63729758b77fSLuigi Rizzo 637362ff38aeSLuigi Rizzo if (cmd != NULL) 6374ca6e3cb0SKelly Yancey break; 6375ca6e3cb0SKelly Yancey } 6376ca6e3cb0SKelly Yancey 637762ff38aeSLuigi Rizzo if (cmd == NULL && ac != optind + 1) { 637862ff38aeSLuigi Rizzo fprintf(stderr, "ac %d, optind %d\n", ac, optind); 63799758b77fSLuigi Rizzo errx(EX_USAGE, "extraneous filename arguments"); 638062ff38aeSLuigi Rizzo } 63819758b77fSLuigi Rizzo 638262ff38aeSLuigi Rizzo if ((f = fopen(filename, "r")) == NULL) 638362ff38aeSLuigi Rizzo err(EX_UNAVAILABLE, "fopen: %s", filename); 63849758b77fSLuigi Rizzo 638562ff38aeSLuigi Rizzo if (cmd != NULL) { /* pipe through preprocessor */ 63869758b77fSLuigi Rizzo int pipedes[2]; 63879758b77fSLuigi Rizzo 63889758b77fSLuigi Rizzo if (pipe(pipedes) == -1) 63899758b77fSLuigi Rizzo err(EX_OSERR, "cannot create pipe"); 63909758b77fSLuigi Rizzo 639162ff38aeSLuigi Rizzo preproc = fork(); 639262ff38aeSLuigi Rizzo if (preproc == -1) 63939758b77fSLuigi Rizzo err(EX_OSERR, "cannot fork"); 63949758b77fSLuigi Rizzo 639562ff38aeSLuigi Rizzo if (preproc == 0) { 639662ff38aeSLuigi Rizzo /* 639762ff38aeSLuigi Rizzo * Child, will run the preprocessor with the 639862ff38aeSLuigi Rizzo * file on stdin and the pipe on stdout. 639962ff38aeSLuigi Rizzo */ 64009758b77fSLuigi Rizzo if (dup2(fileno(f), 0) == -1 64019758b77fSLuigi Rizzo || dup2(pipedes[1], 1) == -1) 64029758b77fSLuigi Rizzo err(EX_OSERR, "dup2()"); 64039758b77fSLuigi Rizzo fclose(f); 64049758b77fSLuigi Rizzo close(pipedes[1]); 64059758b77fSLuigi Rizzo close(pipedes[0]); 640662ff38aeSLuigi Rizzo execvp(cmd, av); 64079758b77fSLuigi Rizzo err(EX_OSERR, "execvp(%s) failed", cmd); 640862ff38aeSLuigi Rizzo } else { /* parent, will reopen f as the pipe */ 64099758b77fSLuigi Rizzo fclose(f); 64109758b77fSLuigi Rizzo close(pipedes[1]); 64119758b77fSLuigi Rizzo if ((f = fdopen(pipedes[0], "r")) == NULL) { 64129758b77fSLuigi Rizzo int savederrno = errno; 64139758b77fSLuigi Rizzo 64149758b77fSLuigi Rizzo (void)kill(preproc, SIGTERM); 64159758b77fSLuigi Rizzo errno = savederrno; 64169758b77fSLuigi Rizzo err(EX_OSERR, "fdopen()"); 64179758b77fSLuigi Rizzo } 64189758b77fSLuigi Rizzo } 64199758b77fSLuigi Rizzo } 64209758b77fSLuigi Rizzo 642162ff38aeSLuigi Rizzo while (fgets(buf, BUFSIZ, f)) { /* read commands */ 642262ff38aeSLuigi Rizzo char linename[10]; 642362ff38aeSLuigi Rizzo char *args[1]; 642462ff38aeSLuigi Rizzo 64259758b77fSLuigi Rizzo lineno++; 6426571f8c1bSLuigi Rizzo sprintf(linename, "Line %d", lineno); 6427571f8c1bSLuigi Rizzo setprogname(linename); /* XXX */ 642862ff38aeSLuigi Rizzo args[0] = buf; 642962ff38aeSLuigi Rizzo ipfw_main(1, args); 64309758b77fSLuigi Rizzo } 64319758b77fSLuigi Rizzo fclose(f); 643262ff38aeSLuigi Rizzo if (cmd != NULL) { 643362ff38aeSLuigi Rizzo int status; 643462ff38aeSLuigi Rizzo 64359758b77fSLuigi Rizzo if (waitpid(preproc, &status, 0) == -1) 64369758b77fSLuigi Rizzo errx(EX_OSERR, "waitpid()"); 64379758b77fSLuigi Rizzo if (WIFEXITED(status) && WEXITSTATUS(status) != EX_OK) 64389758b77fSLuigi Rizzo errx(EX_UNAVAILABLE, 64399758b77fSLuigi Rizzo "preprocessor exited with status %d", 64409758b77fSLuigi Rizzo WEXITSTATUS(status)); 64419758b77fSLuigi Rizzo else if (WIFSIGNALED(status)) 64429758b77fSLuigi Rizzo errx(EX_UNAVAILABLE, 64439758b77fSLuigi Rizzo "preprocessor exited with signal %d", 64449758b77fSLuigi Rizzo WTERMSIG(status)); 64459758b77fSLuigi Rizzo } 64469758b77fSLuigi Rizzo } 64479758b77fSLuigi Rizzo 64489758b77fSLuigi Rizzo int 64499758b77fSLuigi Rizzo main(int ac, char *av[]) 64509758b77fSLuigi Rizzo { 64519758b77fSLuigi Rizzo /* 64529758b77fSLuigi Rizzo * If the last argument is an absolute pathname, interpret it 64539758b77fSLuigi Rizzo * as a file to be preprocessed. 64549758b77fSLuigi Rizzo */ 64559758b77fSLuigi Rizzo 64569758b77fSLuigi Rizzo if (ac > 1 && av[ac - 1][0] == '/' && access(av[ac - 1], R_OK) == 0) 64579758b77fSLuigi Rizzo ipfw_readfile(ac, av); 645826bf4d78SLuigi Rizzo else { 645926bf4d78SLuigi Rizzo if (ipfw_main(ac-1, av+1)) 646026bf4d78SLuigi Rizzo show_usage(); 646126bf4d78SLuigi Rizzo } 64629758b77fSLuigi Rizzo return EX_OK; 64639758b77fSLuigi Rizzo } 6464