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 23e5dbf736SLuigi Rizzo #include <sys/types.h> 249758b77fSLuigi Rizzo #include <sys/socket.h> 259758b77fSLuigi Rizzo #include <sys/sockio.h> 269758b77fSLuigi Rizzo #include <sys/sysctl.h> 279758b77fSLuigi Rizzo #include <sys/wait.h> 289758b77fSLuigi Rizzo 299758b77fSLuigi Rizzo #include <ctype.h> 309758b77fSLuigi Rizzo #include <err.h> 319758b77fSLuigi Rizzo #include <errno.h> 329758b77fSLuigi Rizzo #include <grp.h> 339758b77fSLuigi Rizzo #include <netdb.h> 349758b77fSLuigi Rizzo #include <pwd.h> 359758b77fSLuigi Rizzo #include <signal.h> 369758b77fSLuigi Rizzo #include <stdio.h> 379758b77fSLuigi Rizzo #include <stdlib.h> 389758b77fSLuigi Rizzo #include <string.h> 399758b77fSLuigi Rizzo #include <sysexits.h> 40e5dbf736SLuigi Rizzo #include <timeconv.h> /* _long_to_time */ 41974dfe30SBrian Feldman #include <unistd.h> 42974dfe30SBrian Feldman #include <fcntl.h> 439758b77fSLuigi Rizzo 44bb5081a7SRobert Watson #define IPFW_INTERNAL /* Access to protected structures in ip_fw.h. */ 45bb5081a7SRobert Watson 46bd1d3456SMaxim Konovalov #include <net/ethernet.h> 479758b77fSLuigi Rizzo #include <net/if.h> 48ff2f6fe8SPaolo Pisati #include <net/if_dl.h> 49974dfe30SBrian Feldman #include <net/pfvar.h> 508195404bSBrooks Davis #include <net/route.h> /* def. of struct route */ 519758b77fSLuigi Rizzo #include <netinet/in.h> 529758b77fSLuigi Rizzo #include <netinet/in_systm.h> 539758b77fSLuigi Rizzo #include <netinet/ip.h> 549758b77fSLuigi Rizzo #include <netinet/ip_icmp.h> 558195404bSBrooks Davis #include <netinet/icmp6.h> 569758b77fSLuigi Rizzo #include <netinet/ip_fw.h> 579758b77fSLuigi Rizzo #include <netinet/ip_dummynet.h> 589758b77fSLuigi Rizzo #include <netinet/tcp.h> 599758b77fSLuigi Rizzo #include <arpa/inet.h> 60ff2f6fe8SPaolo Pisati #include <alias.h> 619758b77fSLuigi Rizzo 62571f8c1bSLuigi Rizzo int 630943a3b7SJulian Elischer do_value_as_ip, /* show table value as IP */ 649758b77fSLuigi Rizzo do_resolv, /* Would try to resolve all */ 659758b77fSLuigi Rizzo do_time, /* Show time stamps */ 669758b77fSLuigi Rizzo do_quiet, /* Be quiet in add and flush */ 679758b77fSLuigi Rizzo do_pipe, /* this cmd refers to a pipe */ 68ff2f6fe8SPaolo Pisati do_nat, /* Nat configuration. */ 699758b77fSLuigi Rizzo do_sort, /* field to sort results (0 = no) */ 709758b77fSLuigi Rizzo do_dynamic, /* display dynamic rules */ 719758b77fSLuigi Rizzo do_expired, /* display expired dynamic rules */ 725a155b40SLuigi Rizzo do_compact, /* show rules in compact mode */ 73cec4ab6aSMaxim Konovalov do_force, /* do not ask for confirmation */ 74d069a5d4SMaxim Konovalov use_set, /* work with specified set number */ 7543405724SLuigi Rizzo show_sets, /* display rule sets */ 76571f8c1bSLuigi Rizzo test_only, /* only check syntax */ 77ac6cec51SLuigi Rizzo comment_only, /* only print action and comment */ 789758b77fSLuigi Rizzo verbose; 799758b77fSLuigi Rizzo 809758b77fSLuigi Rizzo #define IP_MASK_ALL 0xffffffff 8104f70834SChristian S.J. Peron /* 8204f70834SChristian S.J. Peron * the following macro returns an error message if we run out of 8304f70834SChristian S.J. Peron * arguments. 8404f70834SChristian S.J. Peron */ 8504f70834SChristian S.J. Peron #define NEED1(msg) {if (!ac) errx(EX_USAGE, msg);} 869758b77fSLuigi Rizzo 87254c4725SOleg Bulyzhin #define GET_UINT_ARG(arg, min, max, tok, s_x) do { \ 88254c4725SOleg Bulyzhin if (!ac) \ 89254c4725SOleg Bulyzhin errx(EX_USAGE, "%s: missing argument", match_value(s_x, tok)); \ 90254c4725SOleg Bulyzhin if (_substrcmp(*av, "tablearg") == 0) { \ 91254c4725SOleg Bulyzhin arg = IP_FW_TABLEARG; \ 92254c4725SOleg Bulyzhin break; \ 936a7d5cb6SOleg Bulyzhin } \ 94254c4725SOleg Bulyzhin \ 95254c4725SOleg Bulyzhin { \ 96254c4725SOleg Bulyzhin long val; \ 97254c4725SOleg Bulyzhin char *end; \ 98254c4725SOleg Bulyzhin \ 99254c4725SOleg Bulyzhin val = strtol(*av, &end, 10); \ 100254c4725SOleg Bulyzhin \ 101254c4725SOleg Bulyzhin if (!isdigit(**av) || *end != '\0' || (val == 0 && errno == EINVAL)) \ 102254c4725SOleg Bulyzhin errx(EX_DATAERR, "%s: invalid argument: %s", \ 103254c4725SOleg Bulyzhin match_value(s_x, tok), *av); \ 104254c4725SOleg Bulyzhin \ 105254c4725SOleg Bulyzhin if (errno == ERANGE || val < min || val > max) \ 106254c4725SOleg Bulyzhin errx(EX_DATAERR, "%s: argument is out of range (%u..%u): %s", \ 107254c4725SOleg Bulyzhin match_value(s_x, tok), min, max, *av); \ 108254c4725SOleg Bulyzhin \ 109254c4725SOleg Bulyzhin if (val == IP_FW_TABLEARG) \ 110254c4725SOleg Bulyzhin errx(EX_DATAERR, "%s: illegal argument value: %s", \ 111254c4725SOleg Bulyzhin match_value(s_x, tok), *av); \ 112254c4725SOleg Bulyzhin arg = val; \ 113254c4725SOleg Bulyzhin } \ 114254c4725SOleg Bulyzhin } while (0) 115254c4725SOleg Bulyzhin 116254c4725SOleg Bulyzhin #define PRINT_UINT_ARG(str, arg) do { \ 117254c4725SOleg Bulyzhin if (str != NULL) \ 118254c4725SOleg Bulyzhin printf("%s",str); \ 119254c4725SOleg Bulyzhin if (arg == IP_FW_TABLEARG) \ 120254c4725SOleg Bulyzhin printf("tablearg"); \ 121254c4725SOleg Bulyzhin else \ 122254c4725SOleg Bulyzhin printf("%u", (uint32_t)arg); \ 1236a7d5cb6SOleg Bulyzhin } while (0) 1246a7d5cb6SOleg Bulyzhin 1259758b77fSLuigi Rizzo /* 126571f8c1bSLuigi Rizzo * _s_x is a structure that stores a string <-> token pairs, used in 127571f8c1bSLuigi Rizzo * various places in the parser. Entries are stored in arrays, 128571f8c1bSLuigi Rizzo * with an entry with s=NULL as terminator. 129571f8c1bSLuigi Rizzo * The search routines are match_token() and match_value(). 130571f8c1bSLuigi Rizzo * Often, an element with x=0 contains an error string. 1319758b77fSLuigi Rizzo * 1329758b77fSLuigi Rizzo */ 1339758b77fSLuigi Rizzo struct _s_x { 13462ff38aeSLuigi Rizzo char const *s; 1359758b77fSLuigi Rizzo int x; 1369758b77fSLuigi Rizzo }; 1379758b77fSLuigi Rizzo 1389758b77fSLuigi Rizzo static struct _s_x f_tcpflags[] = { 1399758b77fSLuigi Rizzo { "syn", TH_SYN }, 1409758b77fSLuigi Rizzo { "fin", TH_FIN }, 1419758b77fSLuigi Rizzo { "ack", TH_ACK }, 1429758b77fSLuigi Rizzo { "psh", TH_PUSH }, 1439758b77fSLuigi Rizzo { "rst", TH_RST }, 1449758b77fSLuigi Rizzo { "urg", TH_URG }, 1459758b77fSLuigi Rizzo { "tcp flag", 0 }, 1469758b77fSLuigi Rizzo { NULL, 0 } 1479758b77fSLuigi Rizzo }; 1489758b77fSLuigi Rizzo 1499758b77fSLuigi Rizzo static struct _s_x f_tcpopts[] = { 1509758b77fSLuigi Rizzo { "mss", IP_FW_TCPOPT_MSS }, 1519758b77fSLuigi Rizzo { "maxseg", IP_FW_TCPOPT_MSS }, 1529758b77fSLuigi Rizzo { "window", IP_FW_TCPOPT_WINDOW }, 1539758b77fSLuigi Rizzo { "sack", IP_FW_TCPOPT_SACK }, 1549758b77fSLuigi Rizzo { "ts", IP_FW_TCPOPT_TS }, 1559758b77fSLuigi Rizzo { "timestamp", IP_FW_TCPOPT_TS }, 1569758b77fSLuigi Rizzo { "cc", IP_FW_TCPOPT_CC }, 1579758b77fSLuigi Rizzo { "tcp option", 0 }, 1589758b77fSLuigi Rizzo { NULL, 0 } 1599758b77fSLuigi Rizzo }; 1609758b77fSLuigi Rizzo 1619758b77fSLuigi Rizzo /* 1629758b77fSLuigi Rizzo * IP options span the range 0 to 255 so we need to remap them 1639758b77fSLuigi Rizzo * (though in fact only the low 5 bits are significant). 1649758b77fSLuigi Rizzo */ 1659758b77fSLuigi Rizzo static struct _s_x f_ipopts[] = { 1669758b77fSLuigi Rizzo { "ssrr", IP_FW_IPOPT_SSRR}, 1679758b77fSLuigi Rizzo { "lsrr", IP_FW_IPOPT_LSRR}, 1689758b77fSLuigi Rizzo { "rr", IP_FW_IPOPT_RR}, 1699758b77fSLuigi Rizzo { "ts", IP_FW_IPOPT_TS}, 1709758b77fSLuigi Rizzo { "ip option", 0 }, 1719758b77fSLuigi Rizzo { NULL, 0 } 1729758b77fSLuigi Rizzo }; 1739758b77fSLuigi Rizzo 1749758b77fSLuigi Rizzo static struct _s_x f_iptos[] = { 1759758b77fSLuigi Rizzo { "lowdelay", IPTOS_LOWDELAY}, 1769758b77fSLuigi Rizzo { "throughput", IPTOS_THROUGHPUT}, 1779758b77fSLuigi Rizzo { "reliability", IPTOS_RELIABILITY}, 1789758b77fSLuigi Rizzo { "mincost", IPTOS_MINCOST}, 17906d703efSRui Paulo { "congestion", IPTOS_ECN_CE}, 18006d703efSRui Paulo { "ecntransport", IPTOS_ECN_ECT0}, 1819758b77fSLuigi Rizzo { "ip tos option", 0}, 1829758b77fSLuigi Rizzo { NULL, 0 } 1839758b77fSLuigi Rizzo }; 1849758b77fSLuigi Rizzo 1859758b77fSLuigi Rizzo static struct _s_x limit_masks[] = { 1869758b77fSLuigi Rizzo {"all", DYN_SRC_ADDR|DYN_SRC_PORT|DYN_DST_ADDR|DYN_DST_PORT}, 1879758b77fSLuigi Rizzo {"src-addr", DYN_SRC_ADDR}, 1889758b77fSLuigi Rizzo {"src-port", DYN_SRC_PORT}, 1899758b77fSLuigi Rizzo {"dst-addr", DYN_DST_ADDR}, 1909758b77fSLuigi Rizzo {"dst-port", DYN_DST_PORT}, 1919758b77fSLuigi Rizzo {NULL, 0} 1929758b77fSLuigi Rizzo }; 1939758b77fSLuigi Rizzo 1949758b77fSLuigi Rizzo /* 1959758b77fSLuigi Rizzo * we use IPPROTO_ETHERTYPE as a fake protocol id to call the print routines 1969758b77fSLuigi Rizzo * This is only used in this code. 1979758b77fSLuigi Rizzo */ 1989758b77fSLuigi Rizzo #define IPPROTO_ETHERTYPE 0x1000 1999758b77fSLuigi Rizzo static struct _s_x ether_types[] = { 2009758b77fSLuigi Rizzo /* 2019758b77fSLuigi Rizzo * Note, we cannot use "-:&/" in the names because they are field 2029758b77fSLuigi Rizzo * separators in the type specifications. Also, we use s = NULL as 2039758b77fSLuigi Rizzo * end-delimiter, because a type of 0 can be legal. 2049758b77fSLuigi Rizzo */ 2059758b77fSLuigi Rizzo { "ip", 0x0800 }, 2069758b77fSLuigi Rizzo { "ipv4", 0x0800 }, 2079758b77fSLuigi Rizzo { "ipv6", 0x86dd }, 2089758b77fSLuigi Rizzo { "arp", 0x0806 }, 2099758b77fSLuigi Rizzo { "rarp", 0x8035 }, 2109758b77fSLuigi Rizzo { "vlan", 0x8100 }, 2119758b77fSLuigi Rizzo { "loop", 0x9000 }, 2129758b77fSLuigi Rizzo { "trail", 0x1000 }, 2139758b77fSLuigi Rizzo { "at", 0x809b }, 2149758b77fSLuigi Rizzo { "atalk", 0x809b }, 2159758b77fSLuigi Rizzo { "aarp", 0x80f3 }, 2169758b77fSLuigi Rizzo { "pppoe_disc", 0x8863 }, 2179758b77fSLuigi Rizzo { "pppoe_sess", 0x8864 }, 2189758b77fSLuigi Rizzo { "ipx_8022", 0x00E0 }, 2199758b77fSLuigi Rizzo { "ipx_8023", 0x0000 }, 2209758b77fSLuigi Rizzo { "ipx_ii", 0x8137 }, 2219758b77fSLuigi Rizzo { "ipx_snap", 0x8137 }, 2229758b77fSLuigi Rizzo { "ipx", 0x8137 }, 2239758b77fSLuigi Rizzo { "ns", 0x0600 }, 2249758b77fSLuigi Rizzo { NULL, 0 } 2259758b77fSLuigi Rizzo }; 2269758b77fSLuigi Rizzo 2279758b77fSLuigi Rizzo static void show_usage(void); 2289758b77fSLuigi Rizzo 2299758b77fSLuigi Rizzo enum tokens { 2309758b77fSLuigi Rizzo TOK_NULL=0, 2319758b77fSLuigi Rizzo 2329758b77fSLuigi Rizzo TOK_OR, 2339758b77fSLuigi Rizzo TOK_NOT, 2348ed2d749SLuigi Rizzo TOK_STARTBRACE, 2358ed2d749SLuigi Rizzo TOK_ENDBRACE, 2369758b77fSLuigi Rizzo 2379758b77fSLuigi Rizzo TOK_ACCEPT, 2389758b77fSLuigi Rizzo TOK_COUNT, 2399758b77fSLuigi Rizzo TOK_PIPE, 2409758b77fSLuigi Rizzo TOK_QUEUE, 2419758b77fSLuigi Rizzo TOK_DIVERT, 2429758b77fSLuigi Rizzo TOK_TEE, 243670742a1SGleb Smirnoff TOK_NETGRAPH, 244670742a1SGleb Smirnoff TOK_NGTEE, 2459758b77fSLuigi Rizzo TOK_FORWARD, 2469758b77fSLuigi Rizzo TOK_SKIPTO, 2479758b77fSLuigi Rizzo TOK_DENY, 2489758b77fSLuigi Rizzo TOK_REJECT, 2499758b77fSLuigi Rizzo TOK_RESET, 2509758b77fSLuigi Rizzo TOK_UNREACH, 2519758b77fSLuigi Rizzo TOK_CHECKSTATE, 252ff2f6fe8SPaolo Pisati TOK_NAT, 2539758b77fSLuigi Rizzo 254974dfe30SBrian Feldman TOK_ALTQ, 255974dfe30SBrian Feldman TOK_LOG, 2566a7d5cb6SOleg Bulyzhin TOK_TAG, 2576a7d5cb6SOleg Bulyzhin TOK_UNTAG, 258974dfe30SBrian Feldman 2596a7d5cb6SOleg Bulyzhin TOK_TAGGED, 2609758b77fSLuigi Rizzo TOK_UID, 2619758b77fSLuigi Rizzo TOK_GID, 26231c88a30SChristian S.J. Peron TOK_JAIL, 2639758b77fSLuigi Rizzo TOK_IN, 2649758b77fSLuigi Rizzo TOK_LIMIT, 2659758b77fSLuigi Rizzo TOK_KEEPSTATE, 2669758b77fSLuigi Rizzo TOK_LAYER2, 2679758b77fSLuigi Rizzo TOK_OUT, 2686daf7ebdSBrian Feldman TOK_DIVERTED, 2696daf7ebdSBrian Feldman TOK_DIVERTEDLOOPBACK, 2706daf7ebdSBrian Feldman TOK_DIVERTEDOUTPUT, 2719758b77fSLuigi Rizzo TOK_XMIT, 2729758b77fSLuigi Rizzo TOK_RECV, 2739758b77fSLuigi Rizzo TOK_VIA, 2749758b77fSLuigi Rizzo TOK_FRAG, 2759758b77fSLuigi Rizzo TOK_IPOPTS, 2769758b77fSLuigi Rizzo TOK_IPLEN, 2779758b77fSLuigi Rizzo TOK_IPID, 2789758b77fSLuigi Rizzo TOK_IPPRECEDENCE, 2799758b77fSLuigi Rizzo TOK_IPTOS, 2809758b77fSLuigi Rizzo TOK_IPTTL, 2819758b77fSLuigi Rizzo TOK_IPVER, 2829758b77fSLuigi Rizzo TOK_ESTAB, 2839758b77fSLuigi Rizzo TOK_SETUP, 284c99ee9e0SBrian Feldman TOK_TCPDATALEN, 2859758b77fSLuigi Rizzo TOK_TCPFLAGS, 2869758b77fSLuigi Rizzo TOK_TCPOPTS, 2879758b77fSLuigi Rizzo TOK_TCPSEQ, 2889758b77fSLuigi Rizzo TOK_TCPACK, 2899758b77fSLuigi Rizzo TOK_TCPWIN, 2909758b77fSLuigi Rizzo TOK_ICMPTYPES, 291e706181bSLuigi Rizzo TOK_MAC, 292e706181bSLuigi Rizzo TOK_MACTYPE, 293010dabb0SCrist J. Clark TOK_VERREVPATH, 29422b5770bSAndre Oppermann TOK_VERSRCREACH, 2955f9541ecSAndre Oppermann TOK_ANTISPOOF, 296c3e5b9f1SLuigi Rizzo TOK_IPSEC, 29762ff38aeSLuigi Rizzo TOK_COMMENT, 2989758b77fSLuigi Rizzo 2999758b77fSLuigi Rizzo TOK_PLR, 30099e5e645SLuigi Rizzo TOK_NOERROR, 3019758b77fSLuigi Rizzo TOK_BUCKETS, 3029758b77fSLuigi Rizzo TOK_DSTIP, 3039758b77fSLuigi Rizzo TOK_SRCIP, 3049758b77fSLuigi Rizzo TOK_DSTPORT, 3059758b77fSLuigi Rizzo TOK_SRCPORT, 3069758b77fSLuigi Rizzo TOK_ALL, 3079758b77fSLuigi Rizzo TOK_MASK, 3089758b77fSLuigi Rizzo TOK_BW, 3099758b77fSLuigi Rizzo TOK_DELAY, 3109758b77fSLuigi Rizzo TOK_RED, 3119758b77fSLuigi Rizzo TOK_GRED, 3129758b77fSLuigi Rizzo TOK_DROPTAIL, 3139758b77fSLuigi Rizzo TOK_PROTO, 3149758b77fSLuigi Rizzo TOK_WEIGHT, 315ff2f6fe8SPaolo Pisati TOK_IP, 316ff2f6fe8SPaolo Pisati TOK_IF, 317ff2f6fe8SPaolo Pisati TOK_ALOG, 318ff2f6fe8SPaolo Pisati TOK_DENY_INC, 319ff2f6fe8SPaolo Pisati TOK_SAME_PORTS, 320ff2f6fe8SPaolo Pisati TOK_UNREG_ONLY, 321ff2f6fe8SPaolo Pisati TOK_RESET_ADDR, 322ff2f6fe8SPaolo Pisati TOK_ALIAS_REV, 323ff2f6fe8SPaolo Pisati TOK_PROXY_ONLY, 324ff2f6fe8SPaolo Pisati TOK_REDIR_ADDR, 325ff2f6fe8SPaolo Pisati TOK_REDIR_PORT, 326ff2f6fe8SPaolo Pisati TOK_REDIR_PROTO, 3278195404bSBrooks Davis 3288195404bSBrooks Davis TOK_IPV6, 3298195404bSBrooks Davis TOK_FLOWID, 3308195404bSBrooks Davis TOK_ICMP6TYPES, 3318195404bSBrooks Davis TOK_EXT6HDR, 3328195404bSBrooks Davis TOK_DSTIP6, 3338195404bSBrooks Davis TOK_SRCIP6, 33457cd6d26SMax Laier 33557cd6d26SMax Laier TOK_IPV4, 3369066356bSBjoern A. Zeeb TOK_UNREACH6, 3379066356bSBjoern A. Zeeb TOK_RESET6, 3388b07e49aSJulian Elischer 3398b07e49aSJulian Elischer TOK_FIB, 3408b07e49aSJulian Elischer TOK_SETFIB, 3419758b77fSLuigi Rizzo }; 3429758b77fSLuigi Rizzo 3439758b77fSLuigi Rizzo struct _s_x dummynet_params[] = { 3449758b77fSLuigi Rizzo { "plr", TOK_PLR }, 34599e5e645SLuigi Rizzo { "noerror", TOK_NOERROR }, 3469758b77fSLuigi Rizzo { "buckets", TOK_BUCKETS }, 3479758b77fSLuigi Rizzo { "dst-ip", TOK_DSTIP }, 3489758b77fSLuigi Rizzo { "src-ip", TOK_SRCIP }, 3499758b77fSLuigi Rizzo { "dst-port", TOK_DSTPORT }, 3509758b77fSLuigi Rizzo { "src-port", TOK_SRCPORT }, 3519758b77fSLuigi Rizzo { "proto", TOK_PROTO }, 3529758b77fSLuigi Rizzo { "weight", TOK_WEIGHT }, 3539758b77fSLuigi Rizzo { "all", TOK_ALL }, 3549758b77fSLuigi Rizzo { "mask", TOK_MASK }, 3559758b77fSLuigi Rizzo { "droptail", TOK_DROPTAIL }, 3569758b77fSLuigi Rizzo { "red", TOK_RED }, 3579758b77fSLuigi Rizzo { "gred", TOK_GRED }, 3589758b77fSLuigi Rizzo { "bw", TOK_BW }, 3599758b77fSLuigi Rizzo { "bandwidth", TOK_BW }, 3609758b77fSLuigi Rizzo { "delay", TOK_DELAY }, 3615e43aef8SLuigi Rizzo { "pipe", TOK_PIPE }, 3629758b77fSLuigi Rizzo { "queue", TOK_QUEUE }, 3638195404bSBrooks Davis { "flow-id", TOK_FLOWID}, 3648195404bSBrooks Davis { "dst-ipv6", TOK_DSTIP6}, 3658195404bSBrooks Davis { "dst-ip6", TOK_DSTIP6}, 3668195404bSBrooks Davis { "src-ipv6", TOK_SRCIP6}, 3678195404bSBrooks Davis { "src-ip6", TOK_SRCIP6}, 3689758b77fSLuigi Rizzo { "dummynet-params", TOK_NULL }, 369571f8c1bSLuigi Rizzo { NULL, 0 } /* terminator */ 3709758b77fSLuigi Rizzo }; 3719758b77fSLuigi Rizzo 372ff2f6fe8SPaolo Pisati struct _s_x nat_params[] = { 373ff2f6fe8SPaolo Pisati { "ip", TOK_IP }, 374ff2f6fe8SPaolo Pisati { "if", TOK_IF }, 375ff2f6fe8SPaolo Pisati { "log", TOK_ALOG }, 376ff2f6fe8SPaolo Pisati { "deny_in", TOK_DENY_INC }, 377ff2f6fe8SPaolo Pisati { "same_ports", TOK_SAME_PORTS }, 378ff2f6fe8SPaolo Pisati { "unreg_only", TOK_UNREG_ONLY }, 379ff2f6fe8SPaolo Pisati { "reset", TOK_RESET_ADDR }, 380ff2f6fe8SPaolo Pisati { "reverse", TOK_ALIAS_REV }, 381ff2f6fe8SPaolo Pisati { "proxy_only", TOK_PROXY_ONLY }, 382ff2f6fe8SPaolo Pisati { "redirect_addr", TOK_REDIR_ADDR }, 383ff2f6fe8SPaolo Pisati { "redirect_port", TOK_REDIR_PORT }, 384ff2f6fe8SPaolo Pisati { "redirect_proto", TOK_REDIR_PROTO }, 385ff2f6fe8SPaolo Pisati { NULL, 0 } /* terminator */ 386ff2f6fe8SPaolo Pisati }; 387ff2f6fe8SPaolo Pisati 3889758b77fSLuigi Rizzo struct _s_x rule_actions[] = { 3899758b77fSLuigi Rizzo { "accept", TOK_ACCEPT }, 3909758b77fSLuigi Rizzo { "pass", TOK_ACCEPT }, 3919758b77fSLuigi Rizzo { "allow", TOK_ACCEPT }, 3929758b77fSLuigi Rizzo { "permit", TOK_ACCEPT }, 3939758b77fSLuigi Rizzo { "count", TOK_COUNT }, 3949758b77fSLuigi Rizzo { "pipe", TOK_PIPE }, 3959758b77fSLuigi Rizzo { "queue", TOK_QUEUE }, 3969758b77fSLuigi Rizzo { "divert", TOK_DIVERT }, 3979758b77fSLuigi Rizzo { "tee", TOK_TEE }, 398670742a1SGleb Smirnoff { "netgraph", TOK_NETGRAPH }, 399670742a1SGleb Smirnoff { "ngtee", TOK_NGTEE }, 4009758b77fSLuigi Rizzo { "fwd", TOK_FORWARD }, 4019758b77fSLuigi Rizzo { "forward", TOK_FORWARD }, 4029758b77fSLuigi Rizzo { "skipto", TOK_SKIPTO }, 4039758b77fSLuigi Rizzo { "deny", TOK_DENY }, 4049758b77fSLuigi Rizzo { "drop", TOK_DENY }, 4059758b77fSLuigi Rizzo { "reject", TOK_REJECT }, 4069066356bSBjoern A. Zeeb { "reset6", TOK_RESET6 }, 4079758b77fSLuigi Rizzo { "reset", TOK_RESET }, 4089066356bSBjoern A. Zeeb { "unreach6", TOK_UNREACH6 }, 4095e43aef8SLuigi Rizzo { "unreach", TOK_UNREACH }, 4109758b77fSLuigi Rizzo { "check-state", TOK_CHECKSTATE }, 41162ff38aeSLuigi Rizzo { "//", TOK_COMMENT }, 412ff2f6fe8SPaolo Pisati { "nat", TOK_NAT }, 4138b07e49aSJulian Elischer { "setfib", TOK_SETFIB }, 414571f8c1bSLuigi Rizzo { NULL, 0 } /* terminator */ 4159758b77fSLuigi Rizzo }; 4169758b77fSLuigi Rizzo 417974dfe30SBrian Feldman struct _s_x rule_action_params[] = { 418974dfe30SBrian Feldman { "altq", TOK_ALTQ }, 419974dfe30SBrian Feldman { "log", TOK_LOG }, 4206a7d5cb6SOleg Bulyzhin { "tag", TOK_TAG }, 4216a7d5cb6SOleg Bulyzhin { "untag", TOK_UNTAG }, 422974dfe30SBrian Feldman { NULL, 0 } /* terminator */ 423974dfe30SBrian Feldman }; 424974dfe30SBrian Feldman 4259758b77fSLuigi Rizzo struct _s_x rule_options[] = { 4266a7d5cb6SOleg Bulyzhin { "tagged", TOK_TAGGED }, 4279758b77fSLuigi Rizzo { "uid", TOK_UID }, 4289758b77fSLuigi Rizzo { "gid", TOK_GID }, 42931c88a30SChristian S.J. Peron { "jail", TOK_JAIL }, 4309758b77fSLuigi Rizzo { "in", TOK_IN }, 4319758b77fSLuigi Rizzo { "limit", TOK_LIMIT }, 4329758b77fSLuigi Rizzo { "keep-state", TOK_KEEPSTATE }, 4339758b77fSLuigi Rizzo { "bridged", TOK_LAYER2 }, 4349758b77fSLuigi Rizzo { "layer2", TOK_LAYER2 }, 4359758b77fSLuigi Rizzo { "out", TOK_OUT }, 4366daf7ebdSBrian Feldman { "diverted", TOK_DIVERTED }, 4376daf7ebdSBrian Feldman { "diverted-loopback", TOK_DIVERTEDLOOPBACK }, 4386daf7ebdSBrian Feldman { "diverted-output", TOK_DIVERTEDOUTPUT }, 4399758b77fSLuigi Rizzo { "xmit", TOK_XMIT }, 4409758b77fSLuigi Rizzo { "recv", TOK_RECV }, 4419758b77fSLuigi Rizzo { "via", TOK_VIA }, 4429758b77fSLuigi Rizzo { "fragment", TOK_FRAG }, 4439758b77fSLuigi Rizzo { "frag", TOK_FRAG }, 4448b07e49aSJulian Elischer { "fib", TOK_FIB }, 4459758b77fSLuigi Rizzo { "ipoptions", TOK_IPOPTS }, 4469758b77fSLuigi Rizzo { "ipopts", TOK_IPOPTS }, 4479758b77fSLuigi Rizzo { "iplen", TOK_IPLEN }, 4489758b77fSLuigi Rizzo { "ipid", TOK_IPID }, 4499758b77fSLuigi Rizzo { "ipprecedence", TOK_IPPRECEDENCE }, 4509758b77fSLuigi Rizzo { "iptos", TOK_IPTOS }, 4519758b77fSLuigi Rizzo { "ipttl", TOK_IPTTL }, 4529758b77fSLuigi Rizzo { "ipversion", TOK_IPVER }, 4539758b77fSLuigi Rizzo { "ipver", TOK_IPVER }, 4549758b77fSLuigi Rizzo { "estab", TOK_ESTAB }, 4559758b77fSLuigi Rizzo { "established", TOK_ESTAB }, 4569758b77fSLuigi Rizzo { "setup", TOK_SETUP }, 457c99ee9e0SBrian Feldman { "tcpdatalen", TOK_TCPDATALEN }, 4589758b77fSLuigi Rizzo { "tcpflags", TOK_TCPFLAGS }, 4599758b77fSLuigi Rizzo { "tcpflgs", TOK_TCPFLAGS }, 4609758b77fSLuigi Rizzo { "tcpoptions", TOK_TCPOPTS }, 4619758b77fSLuigi Rizzo { "tcpopts", TOK_TCPOPTS }, 4629758b77fSLuigi Rizzo { "tcpseq", TOK_TCPSEQ }, 4639758b77fSLuigi Rizzo { "tcpack", TOK_TCPACK }, 4649758b77fSLuigi Rizzo { "tcpwin", TOK_TCPWIN }, 4650a7197a8SLuigi Rizzo { "icmptype", TOK_ICMPTYPES }, 4669758b77fSLuigi Rizzo { "icmptypes", TOK_ICMPTYPES }, 467e706181bSLuigi Rizzo { "dst-ip", TOK_DSTIP }, 468e706181bSLuigi Rizzo { "src-ip", TOK_SRCIP }, 469e706181bSLuigi Rizzo { "dst-port", TOK_DSTPORT }, 470e706181bSLuigi Rizzo { "src-port", TOK_SRCPORT }, 471e706181bSLuigi Rizzo { "proto", TOK_PROTO }, 472e706181bSLuigi Rizzo { "MAC", TOK_MAC }, 473e706181bSLuigi Rizzo { "mac", TOK_MAC }, 474e706181bSLuigi Rizzo { "mac-type", TOK_MACTYPE }, 475010dabb0SCrist J. Clark { "verrevpath", TOK_VERREVPATH }, 47622b5770bSAndre Oppermann { "versrcreach", TOK_VERSRCREACH }, 4775f9541ecSAndre Oppermann { "antispoof", TOK_ANTISPOOF }, 478c3e5b9f1SLuigi Rizzo { "ipsec", TOK_IPSEC }, 4798195404bSBrooks Davis { "icmp6type", TOK_ICMP6TYPES }, 4808195404bSBrooks Davis { "icmp6types", TOK_ICMP6TYPES }, 4818195404bSBrooks Davis { "ext6hdr", TOK_EXT6HDR}, 4828195404bSBrooks Davis { "flow-id", TOK_FLOWID}, 4838195404bSBrooks Davis { "ipv6", TOK_IPV6}, 4848195404bSBrooks Davis { "ip6", TOK_IPV6}, 48557cd6d26SMax Laier { "ipv4", TOK_IPV4}, 48657cd6d26SMax Laier { "ip4", TOK_IPV4}, 4878195404bSBrooks Davis { "dst-ipv6", TOK_DSTIP6}, 4888195404bSBrooks Davis { "dst-ip6", TOK_DSTIP6}, 4898195404bSBrooks Davis { "src-ipv6", TOK_SRCIP6}, 4908195404bSBrooks Davis { "src-ip6", TOK_SRCIP6}, 49162ff38aeSLuigi Rizzo { "//", TOK_COMMENT }, 4929758b77fSLuigi Rizzo 4939758b77fSLuigi Rizzo { "not", TOK_NOT }, /* pseudo option */ 4949758b77fSLuigi Rizzo { "!", /* escape ? */ TOK_NOT }, /* pseudo option */ 4959758b77fSLuigi Rizzo { "or", TOK_OR }, /* pseudo option */ 4969758b77fSLuigi Rizzo { "|", /* escape */ TOK_OR }, /* pseudo option */ 4978ed2d749SLuigi Rizzo { "{", TOK_STARTBRACE }, /* pseudo option */ 4988ed2d749SLuigi Rizzo { "(", TOK_STARTBRACE }, /* pseudo option */ 4998ed2d749SLuigi Rizzo { "}", TOK_ENDBRACE }, /* pseudo option */ 5008ed2d749SLuigi Rizzo { ")", TOK_ENDBRACE }, /* pseudo option */ 501571f8c1bSLuigi Rizzo { NULL, 0 } /* terminator */ 5029758b77fSLuigi Rizzo }; 5039758b77fSLuigi Rizzo 50440b1ae9eSGleb Smirnoff #define TABLEARG "tablearg" 50540b1ae9eSGleb Smirnoff 506571f8c1bSLuigi Rizzo static __inline uint64_t 507571f8c1bSLuigi Rizzo align_uint64(uint64_t *pll) { 508571f8c1bSLuigi Rizzo uint64_t ret; 509330462a3SBernd Walter 510330462a3SBernd Walter bcopy (pll, &ret, sizeof(ret)); 511330462a3SBernd Walter return ret; 512c85c1d27SStefan Farfeleder } 513330462a3SBernd Walter 5145f356082SLuigi Rizzo static void * 5155f356082SLuigi Rizzo safe_calloc(size_t number, size_t size) 5165f356082SLuigi Rizzo { 5175f356082SLuigi Rizzo void *ret = calloc(number, size); 5185f356082SLuigi Rizzo 5195f356082SLuigi Rizzo if (ret == NULL) 5205f356082SLuigi Rizzo err(EX_OSERR, "calloc"); 5215f356082SLuigi Rizzo return ret; 5225f356082SLuigi Rizzo } 5235f356082SLuigi Rizzo 5245f356082SLuigi Rizzo static void * 5255f356082SLuigi Rizzo safe_realloc(void *ptr, size_t size) 5265f356082SLuigi Rizzo { 5275f356082SLuigi Rizzo void *ret = realloc(ptr, size); 5285f356082SLuigi Rizzo 5295f356082SLuigi Rizzo if (ret == NULL) 5305f356082SLuigi Rizzo err(EX_OSERR, "realloc"); 5315f356082SLuigi Rizzo return ret; 5325f356082SLuigi Rizzo } 5335f356082SLuigi Rizzo 534571f8c1bSLuigi Rizzo /* 535571f8c1bSLuigi Rizzo * conditionally runs the command. 536571f8c1bSLuigi Rizzo */ 53762ff38aeSLuigi Rizzo static int 538884be75cSThomas Moestl do_cmd(int optname, void *optval, uintptr_t optlen) 539571f8c1bSLuigi Rizzo { 540571f8c1bSLuigi Rizzo static int s = -1; /* the socket */ 541571f8c1bSLuigi Rizzo int i; 542571f8c1bSLuigi Rizzo 543571f8c1bSLuigi Rizzo if (test_only) 544571f8c1bSLuigi Rizzo return 0; 545571f8c1bSLuigi Rizzo 546571f8c1bSLuigi Rizzo if (s == -1) 547571f8c1bSLuigi Rizzo s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); 548571f8c1bSLuigi Rizzo if (s < 0) 549571f8c1bSLuigi Rizzo err(EX_UNAVAILABLE, "socket"); 550571f8c1bSLuigi Rizzo 551571f8c1bSLuigi Rizzo if (optname == IP_FW_GET || optname == IP_DUMMYNET_GET || 552cd8b5ae0SRuslan Ermilov optname == IP_FW_ADD || optname == IP_FW_TABLE_LIST || 553ff2f6fe8SPaolo Pisati optname == IP_FW_TABLE_GETSIZE || 554ff2f6fe8SPaolo Pisati optname == IP_FW_NAT_GET_CONFIG || 555ff2f6fe8SPaolo Pisati optname == IP_FW_NAT_GET_LOG) 556571f8c1bSLuigi Rizzo i = getsockopt(s, IPPROTO_IP, optname, optval, 557571f8c1bSLuigi Rizzo (socklen_t *)optlen); 558571f8c1bSLuigi Rizzo else 559571f8c1bSLuigi Rizzo i = setsockopt(s, IPPROTO_IP, optname, optval, optlen); 560571f8c1bSLuigi Rizzo return i; 561571f8c1bSLuigi Rizzo } 562571f8c1bSLuigi Rizzo 5639758b77fSLuigi Rizzo /** 5649758b77fSLuigi Rizzo * match_token takes a table and a string, returns the value associated 565571f8c1bSLuigi Rizzo * with the string (-1 in case of failure). 5669758b77fSLuigi Rizzo */ 5679758b77fSLuigi Rizzo static int 5689758b77fSLuigi Rizzo match_token(struct _s_x *table, char *string) 5699758b77fSLuigi Rizzo { 5709758b77fSLuigi Rizzo struct _s_x *pt; 57162ff38aeSLuigi Rizzo uint i = strlen(string); 5729758b77fSLuigi Rizzo 5739758b77fSLuigi Rizzo for (pt = table ; i && pt->s != NULL ; pt++) 5749758b77fSLuigi Rizzo if (strlen(pt->s) == i && !bcmp(string, pt->s, i)) 5759758b77fSLuigi Rizzo return pt->x; 5769758b77fSLuigi Rizzo return -1; 577c85c1d27SStefan Farfeleder } 5789758b77fSLuigi Rizzo 579571f8c1bSLuigi Rizzo /** 580571f8c1bSLuigi Rizzo * match_value takes a table and a value, returns the string associated 581571f8c1bSLuigi Rizzo * with the value (NULL in case of failure). 582571f8c1bSLuigi Rizzo */ 58362ff38aeSLuigi Rizzo static char const * 58462ff38aeSLuigi Rizzo match_value(struct _s_x *p, int value) 5859758b77fSLuigi Rizzo { 5869758b77fSLuigi Rizzo for (; p->s != NULL; p++) 5879758b77fSLuigi Rizzo if (p->x == value) 5889758b77fSLuigi Rizzo return p->s; 5899758b77fSLuigi Rizzo return NULL; 5909758b77fSLuigi Rizzo } 5919758b77fSLuigi Rizzo 5929758b77fSLuigi Rizzo /* 59301750186SBrooks Davis * _substrcmp takes two strings and returns 1 if they do not match, 59401750186SBrooks Davis * and 0 if they match exactly or the first string is a sub-string 59501750186SBrooks Davis * of the second. A warning is printed to stderr in the case that the 59601750186SBrooks Davis * first string is a sub-string of the second. 59701750186SBrooks Davis * 59801750186SBrooks Davis * This function will be removed in the future through the usual 59901750186SBrooks Davis * deprecation process. 60001750186SBrooks Davis */ 60101750186SBrooks Davis static int 60201750186SBrooks Davis _substrcmp(const char *str1, const char* str2) 60301750186SBrooks Davis { 60401750186SBrooks Davis 60501750186SBrooks Davis if (strncmp(str1, str2, strlen(str1)) != 0) 60601750186SBrooks Davis return 1; 60701750186SBrooks Davis 60801750186SBrooks Davis if (strlen(str1) != strlen(str2)) 60901750186SBrooks Davis warnx("DEPRECATED: '%s' matched '%s' as a sub-string", 61001750186SBrooks Davis str1, str2); 61101750186SBrooks Davis return 0; 61201750186SBrooks Davis } 61301750186SBrooks Davis 61401750186SBrooks Davis /* 61501750186SBrooks Davis * _substrcmp2 takes three strings and returns 1 if the first two do not match, 61601750186SBrooks Davis * and 0 if they match exactly or the second string is a sub-string 61701750186SBrooks Davis * of the first. A warning is printed to stderr in the case that the 61801750186SBrooks Davis * first string does not match the third. 61901750186SBrooks Davis * 62001750186SBrooks Davis * This function exists to warn about the bizzare construction 62101750186SBrooks Davis * strncmp(str, "by", 2) which is used to allow people to use a shotcut 62201750186SBrooks Davis * for "bytes". The problem is that in addition to accepting "by", 62301750186SBrooks Davis * "byt", "byte", and "bytes", it also excepts "by_rabid_dogs" and any 62401750186SBrooks Davis * other string beginning with "by". 62501750186SBrooks Davis * 62601750186SBrooks Davis * This function will be removed in the future through the usual 62701750186SBrooks Davis * deprecation process. 62801750186SBrooks Davis */ 62901750186SBrooks Davis static int 63001750186SBrooks Davis _substrcmp2(const char *str1, const char* str2, const char* str3) 63101750186SBrooks Davis { 63201750186SBrooks Davis 63301750186SBrooks Davis if (strncmp(str1, str2, strlen(str2)) != 0) 63401750186SBrooks Davis return 1; 63501750186SBrooks Davis 63601750186SBrooks Davis if (strcmp(str1, str3) != 0) 63701750186SBrooks Davis warnx("DEPRECATED: '%s' matched '%s'", 63801750186SBrooks Davis str1, str3); 63901750186SBrooks Davis return 0; 64001750186SBrooks Davis } 64101750186SBrooks Davis 64201750186SBrooks Davis /* 6439758b77fSLuigi Rizzo * prints one port, symbolic or numeric 6449758b77fSLuigi Rizzo */ 6459758b77fSLuigi Rizzo static void 646571f8c1bSLuigi Rizzo print_port(int proto, uint16_t port) 6479758b77fSLuigi Rizzo { 6489758b77fSLuigi Rizzo 6499758b77fSLuigi Rizzo if (proto == IPPROTO_ETHERTYPE) { 65062ff38aeSLuigi Rizzo char const *s; 6519758b77fSLuigi Rizzo 6529758b77fSLuigi Rizzo if (do_resolv && (s = match_value(ether_types, port)) ) 6539758b77fSLuigi Rizzo printf("%s", s); 6549758b77fSLuigi Rizzo else 6559758b77fSLuigi Rizzo printf("0x%04x", port); 6569758b77fSLuigi Rizzo } else { 6579758b77fSLuigi Rizzo struct servent *se = NULL; 6589758b77fSLuigi Rizzo if (do_resolv) { 6599758b77fSLuigi Rizzo struct protoent *pe = getprotobynumber(proto); 6609758b77fSLuigi Rizzo 6619758b77fSLuigi Rizzo se = getservbyport(htons(port), pe ? pe->p_name : NULL); 6629758b77fSLuigi Rizzo } 6639758b77fSLuigi Rizzo if (se) 6649758b77fSLuigi Rizzo printf("%s", se->s_name); 6659758b77fSLuigi Rizzo else 6669758b77fSLuigi Rizzo printf("%d", port); 6679758b77fSLuigi Rizzo } 6689758b77fSLuigi Rizzo } 6699758b77fSLuigi Rizzo 670571f8c1bSLuigi Rizzo struct _s_x _port_name[] = { 671571f8c1bSLuigi Rizzo {"dst-port", O_IP_DSTPORT}, 672571f8c1bSLuigi Rizzo {"src-port", O_IP_SRCPORT}, 673571f8c1bSLuigi Rizzo {"ipid", O_IPID}, 674571f8c1bSLuigi Rizzo {"iplen", O_IPLEN}, 675571f8c1bSLuigi Rizzo {"ipttl", O_IPTTL}, 676571f8c1bSLuigi Rizzo {"mac-type", O_MAC_TYPE}, 677c99ee9e0SBrian Feldman {"tcpdatalen", O_TCPDATALEN}, 6786a7d5cb6SOleg Bulyzhin {"tagged", O_TAGGED}, 679571f8c1bSLuigi Rizzo {NULL, 0} 680571f8c1bSLuigi Rizzo }; 681571f8c1bSLuigi Rizzo 6829758b77fSLuigi Rizzo /* 683571f8c1bSLuigi Rizzo * Print the values in a list 16-bit items of the types above. 6849758b77fSLuigi Rizzo * XXX todo: add support for mask. 6859758b77fSLuigi Rizzo */ 6869758b77fSLuigi Rizzo static void 687e706181bSLuigi Rizzo print_newports(ipfw_insn_u16 *cmd, int proto, int opcode) 6889758b77fSLuigi Rizzo { 689571f8c1bSLuigi Rizzo uint16_t *p = cmd->ports; 6909758b77fSLuigi Rizzo int i; 69162ff38aeSLuigi Rizzo char const *sep; 6929758b77fSLuigi Rizzo 69344c884e1SLuigi Rizzo if (opcode != 0) { 694571f8c1bSLuigi Rizzo sep = match_value(_port_name, opcode); 695571f8c1bSLuigi Rizzo if (sep == NULL) 69644c884e1SLuigi Rizzo sep = "???"; 69744c884e1SLuigi Rizzo printf (" %s", sep); 69844c884e1SLuigi Rizzo } 69944c884e1SLuigi Rizzo sep = " "; 7009758b77fSLuigi Rizzo for (i = F_LEN((ipfw_insn *)cmd) - 1; i > 0; i--, p += 2) { 7019758b77fSLuigi Rizzo printf(sep); 7029758b77fSLuigi Rizzo print_port(proto, p[0]); 7039758b77fSLuigi Rizzo if (p[0] != p[1]) { 7049758b77fSLuigi Rizzo printf("-"); 7059758b77fSLuigi Rizzo print_port(proto, p[1]); 7069758b77fSLuigi Rizzo } 7079758b77fSLuigi Rizzo sep = ","; 7089758b77fSLuigi Rizzo } 7099758b77fSLuigi Rizzo } 7109758b77fSLuigi Rizzo 7119758b77fSLuigi Rizzo /* 7129758b77fSLuigi Rizzo * Like strtol, but also translates service names into port numbers 7139758b77fSLuigi Rizzo * for some protocols. 7149758b77fSLuigi Rizzo * In particular: 7159758b77fSLuigi Rizzo * proto == -1 disables the protocol check; 7169758b77fSLuigi Rizzo * proto == IPPROTO_ETHERTYPE looks up an internal table 7179758b77fSLuigi Rizzo * proto == <some value in /etc/protocols> matches the values there. 71843405724SLuigi Rizzo * Returns *end == s in case the parameter is not found. 7199758b77fSLuigi Rizzo */ 7209758b77fSLuigi Rizzo static int 7219758b77fSLuigi Rizzo strtoport(char *s, char **end, int base, int proto) 7229758b77fSLuigi Rizzo { 72343405724SLuigi Rizzo char *p, *buf; 72443405724SLuigi Rizzo char *s1; 7259758b77fSLuigi Rizzo int i; 7269758b77fSLuigi Rizzo 72743405724SLuigi Rizzo *end = s; /* default - not found */ 7289758b77fSLuigi Rizzo if (*s == '\0') 72943405724SLuigi Rizzo return 0; /* not found */ 7309758b77fSLuigi Rizzo 7319758b77fSLuigi Rizzo if (isdigit(*s)) 7329758b77fSLuigi Rizzo return strtol(s, end, base); 7339758b77fSLuigi Rizzo 7349758b77fSLuigi Rizzo /* 73543405724SLuigi Rizzo * find separator. '\\' escapes the next char. 7369758b77fSLuigi Rizzo */ 73743405724SLuigi Rizzo for (s1 = s; *s1 && (isalnum(*s1) || *s1 == '\\') ; s1++) 73843405724SLuigi Rizzo if (*s1 == '\\' && s1[1] != '\0') 73943405724SLuigi Rizzo s1++; 74043405724SLuigi Rizzo 7415f356082SLuigi Rizzo buf = safe_calloc(s1 - s + 1, 1); 74243405724SLuigi Rizzo 74343405724SLuigi Rizzo /* 74443405724SLuigi Rizzo * copy into a buffer skipping backslashes 74543405724SLuigi Rizzo */ 74643405724SLuigi Rizzo for (p = s, i = 0; p != s1 ; p++) 74743405724SLuigi Rizzo if (*p != '\\') 74843405724SLuigi Rizzo buf[i++] = *p; 74943405724SLuigi Rizzo buf[i++] = '\0'; 7509758b77fSLuigi Rizzo 7519758b77fSLuigi Rizzo if (proto == IPPROTO_ETHERTYPE) { 75243405724SLuigi Rizzo i = match_token(ether_types, buf); 75343405724SLuigi Rizzo free(buf); 75443405724SLuigi Rizzo if (i != -1) { /* found */ 7559758b77fSLuigi Rizzo *end = s1; 7569758b77fSLuigi Rizzo return i; 7579758b77fSLuigi Rizzo } 7589758b77fSLuigi Rizzo } else { 7599758b77fSLuigi Rizzo struct protoent *pe = NULL; 7609758b77fSLuigi Rizzo struct servent *se; 7619758b77fSLuigi Rizzo 7629758b77fSLuigi Rizzo if (proto != 0) 7639758b77fSLuigi Rizzo pe = getprotobynumber(proto); 7649758b77fSLuigi Rizzo setservent(1); 76543405724SLuigi Rizzo se = getservbyname(buf, pe ? pe->p_name : NULL); 76643405724SLuigi Rizzo free(buf); 7679758b77fSLuigi Rizzo if (se != NULL) { 7689758b77fSLuigi Rizzo *end = s1; 7699758b77fSLuigi Rizzo return ntohs(se->s_port); 7709758b77fSLuigi Rizzo } 7719758b77fSLuigi Rizzo } 77243405724SLuigi Rizzo return 0; /* not found */ 7739758b77fSLuigi Rizzo } 7749758b77fSLuigi Rizzo 7759758b77fSLuigi Rizzo /* 776974dfe30SBrian Feldman * Map between current altq queue id numbers and names. 777974dfe30SBrian Feldman */ 778974dfe30SBrian Feldman static int altq_fetched = 0; 779974dfe30SBrian Feldman static TAILQ_HEAD(, pf_altq) altq_entries = 780974dfe30SBrian Feldman TAILQ_HEAD_INITIALIZER(altq_entries); 781974dfe30SBrian Feldman 782974dfe30SBrian Feldman static void 783974dfe30SBrian Feldman altq_set_enabled(int enabled) 784974dfe30SBrian Feldman { 785974dfe30SBrian Feldman int pffd; 786974dfe30SBrian Feldman 787974dfe30SBrian Feldman pffd = open("/dev/pf", O_RDWR); 788974dfe30SBrian Feldman if (pffd == -1) 789974dfe30SBrian Feldman err(EX_UNAVAILABLE, 790974dfe30SBrian Feldman "altq support opening pf(4) control device"); 791974dfe30SBrian Feldman if (enabled) { 792974dfe30SBrian Feldman if (ioctl(pffd, DIOCSTARTALTQ) != 0 && errno != EEXIST) 793974dfe30SBrian Feldman err(EX_UNAVAILABLE, "enabling altq"); 794974dfe30SBrian Feldman } else { 795974dfe30SBrian Feldman if (ioctl(pffd, DIOCSTOPALTQ) != 0 && errno != ENOENT) 796974dfe30SBrian Feldman err(EX_UNAVAILABLE, "disabling altq"); 797974dfe30SBrian Feldman } 798974dfe30SBrian Feldman close(pffd); 799974dfe30SBrian Feldman } 800974dfe30SBrian Feldman 801974dfe30SBrian Feldman static void 802daa9733aSLuigi Rizzo altq_fetch(void) 803974dfe30SBrian Feldman { 804974dfe30SBrian Feldman struct pfioc_altq pfioc; 805974dfe30SBrian Feldman struct pf_altq *altq; 806daa9733aSLuigi Rizzo int pffd; 807daa9733aSLuigi Rizzo unsigned int mnr; 808974dfe30SBrian Feldman 809974dfe30SBrian Feldman if (altq_fetched) 810974dfe30SBrian Feldman return; 811974dfe30SBrian Feldman altq_fetched = 1; 812974dfe30SBrian Feldman pffd = open("/dev/pf", O_RDONLY); 813974dfe30SBrian Feldman if (pffd == -1) { 814974dfe30SBrian Feldman warn("altq support opening pf(4) control device"); 815974dfe30SBrian Feldman return; 816974dfe30SBrian Feldman } 817974dfe30SBrian Feldman bzero(&pfioc, sizeof(pfioc)); 818974dfe30SBrian Feldman if (ioctl(pffd, DIOCGETALTQS, &pfioc) != 0) { 819974dfe30SBrian Feldman warn("altq support getting queue list"); 820974dfe30SBrian Feldman close(pffd); 821974dfe30SBrian Feldman return; 822974dfe30SBrian Feldman } 823974dfe30SBrian Feldman mnr = pfioc.nr; 824974dfe30SBrian Feldman for (pfioc.nr = 0; pfioc.nr < mnr; pfioc.nr++) { 825974dfe30SBrian Feldman if (ioctl(pffd, DIOCGETALTQ, &pfioc) != 0) { 826974dfe30SBrian Feldman if (errno == EBUSY) 827974dfe30SBrian Feldman break; 828974dfe30SBrian Feldman warn("altq support getting queue list"); 829974dfe30SBrian Feldman close(pffd); 830974dfe30SBrian Feldman return; 831974dfe30SBrian Feldman } 832974dfe30SBrian Feldman if (pfioc.altq.qid == 0) 833974dfe30SBrian Feldman continue; 8345f356082SLuigi Rizzo altq = safe_calloc(1, sizeof(*altq)); 835974dfe30SBrian Feldman *altq = pfioc.altq; 836974dfe30SBrian Feldman TAILQ_INSERT_TAIL(&altq_entries, altq, entries); 837974dfe30SBrian Feldman } 838974dfe30SBrian Feldman close(pffd); 839974dfe30SBrian Feldman } 840974dfe30SBrian Feldman 841974dfe30SBrian Feldman static u_int32_t 842974dfe30SBrian Feldman altq_name_to_qid(const char *name) 843974dfe30SBrian Feldman { 844974dfe30SBrian Feldman struct pf_altq *altq; 845974dfe30SBrian Feldman 846974dfe30SBrian Feldman altq_fetch(); 847974dfe30SBrian Feldman TAILQ_FOREACH(altq, &altq_entries, entries) 848974dfe30SBrian Feldman if (strcmp(name, altq->qname) == 0) 849974dfe30SBrian Feldman break; 850974dfe30SBrian Feldman if (altq == NULL) 851974dfe30SBrian Feldman errx(EX_DATAERR, "altq has no queue named `%s'", name); 852974dfe30SBrian Feldman return altq->qid; 853974dfe30SBrian Feldman } 854974dfe30SBrian Feldman 855974dfe30SBrian Feldman static const char * 856974dfe30SBrian Feldman altq_qid_to_name(u_int32_t qid) 857974dfe30SBrian Feldman { 858974dfe30SBrian Feldman struct pf_altq *altq; 859974dfe30SBrian Feldman 860974dfe30SBrian Feldman altq_fetch(); 861974dfe30SBrian Feldman TAILQ_FOREACH(altq, &altq_entries, entries) 862974dfe30SBrian Feldman if (qid == altq->qid) 863974dfe30SBrian Feldman break; 864974dfe30SBrian Feldman if (altq == NULL) 865974dfe30SBrian Feldman return NULL; 866974dfe30SBrian Feldman return altq->qname; 867974dfe30SBrian Feldman } 868974dfe30SBrian Feldman 869974dfe30SBrian Feldman static void 870974dfe30SBrian Feldman fill_altq_qid(u_int32_t *qid, const char *av) 871974dfe30SBrian Feldman { 872974dfe30SBrian Feldman *qid = altq_name_to_qid(av); 873974dfe30SBrian Feldman } 874974dfe30SBrian Feldman 875974dfe30SBrian Feldman /* 876571f8c1bSLuigi Rizzo * Fill the body of the command with the list of port ranges. 8779758b77fSLuigi Rizzo */ 8789758b77fSLuigi Rizzo static int 8799758b77fSLuigi Rizzo fill_newports(ipfw_insn_u16 *cmd, char *av, int proto) 8809758b77fSLuigi Rizzo { 881571f8c1bSLuigi Rizzo uint16_t a, b, *p = cmd->ports; 8829758b77fSLuigi Rizzo int i = 0; 883e706181bSLuigi Rizzo char *s = av; 8849758b77fSLuigi Rizzo 885e706181bSLuigi Rizzo while (*s) { 8869758b77fSLuigi Rizzo a = strtoport(av, &s, 0, proto); 887254c4725SOleg Bulyzhin if (s == av) /* empty or invalid argument */ 888254c4725SOleg Bulyzhin return (0); 889254c4725SOleg Bulyzhin 890254c4725SOleg Bulyzhin switch (*s) { 891254c4725SOleg Bulyzhin case '-': /* a range */ 8929758b77fSLuigi Rizzo av = s + 1; 8939758b77fSLuigi Rizzo b = strtoport(av, &s, 0, proto); 894254c4725SOleg Bulyzhin /* Reject expressions like '1-abc' or '1-2-3'. */ 895254c4725SOleg Bulyzhin if (s == av || (*s != ',' && *s != '\0')) 896254c4725SOleg Bulyzhin return (0); 8979758b77fSLuigi Rizzo p[0] = a; 8989758b77fSLuigi Rizzo p[1] = b; 899254c4725SOleg Bulyzhin break; 900254c4725SOleg Bulyzhin case ',': /* comma separated list */ 901254c4725SOleg Bulyzhin case '\0': 9029758b77fSLuigi Rizzo p[0] = p[1] = a; 903254c4725SOleg Bulyzhin break; 904254c4725SOleg Bulyzhin default: 905254c4725SOleg Bulyzhin warnx("port list: invalid separator <%c> in <%s>", 90699e5e645SLuigi Rizzo *s, av); 907254c4725SOleg Bulyzhin return (0); 908254c4725SOleg Bulyzhin } 909254c4725SOleg Bulyzhin 910e706181bSLuigi Rizzo i++; 911e706181bSLuigi Rizzo p += 2; 9129758b77fSLuigi Rizzo av = s + 1; 9139758b77fSLuigi Rizzo } 9149758b77fSLuigi Rizzo if (i > 0) { 9159758b77fSLuigi Rizzo if (i + 1 > F_LEN_MASK) 916e706181bSLuigi Rizzo errx(EX_DATAERR, "too many ports/ranges\n"); 9179758b77fSLuigi Rizzo cmd->o.len |= i + 1; /* leave F_NOT and F_OR untouched */ 9189758b77fSLuigi Rizzo } 919254c4725SOleg Bulyzhin return (i); 9209758b77fSLuigi Rizzo } 9219758b77fSLuigi Rizzo 9229758b77fSLuigi Rizzo static struct _s_x icmpcodes[] = { 9239758b77fSLuigi Rizzo { "net", ICMP_UNREACH_NET }, 9249758b77fSLuigi Rizzo { "host", ICMP_UNREACH_HOST }, 9259758b77fSLuigi Rizzo { "protocol", ICMP_UNREACH_PROTOCOL }, 9269758b77fSLuigi Rizzo { "port", ICMP_UNREACH_PORT }, 9279758b77fSLuigi Rizzo { "needfrag", ICMP_UNREACH_NEEDFRAG }, 9289758b77fSLuigi Rizzo { "srcfail", ICMP_UNREACH_SRCFAIL }, 9299758b77fSLuigi Rizzo { "net-unknown", ICMP_UNREACH_NET_UNKNOWN }, 9309758b77fSLuigi Rizzo { "host-unknown", ICMP_UNREACH_HOST_UNKNOWN }, 9319758b77fSLuigi Rizzo { "isolated", ICMP_UNREACH_ISOLATED }, 9329758b77fSLuigi Rizzo { "net-prohib", ICMP_UNREACH_NET_PROHIB }, 9339758b77fSLuigi Rizzo { "host-prohib", ICMP_UNREACH_HOST_PROHIB }, 9349758b77fSLuigi Rizzo { "tosnet", ICMP_UNREACH_TOSNET }, 9359758b77fSLuigi Rizzo { "toshost", ICMP_UNREACH_TOSHOST }, 9369758b77fSLuigi Rizzo { "filter-prohib", ICMP_UNREACH_FILTER_PROHIB }, 9379758b77fSLuigi Rizzo { "host-precedence", ICMP_UNREACH_HOST_PRECEDENCE }, 9389758b77fSLuigi Rizzo { "precedence-cutoff", ICMP_UNREACH_PRECEDENCE_CUTOFF }, 9399758b77fSLuigi Rizzo { NULL, 0 } 9409758b77fSLuigi Rizzo }; 9419758b77fSLuigi Rizzo 9429758b77fSLuigi Rizzo static void 9439758b77fSLuigi Rizzo fill_reject_code(u_short *codep, char *str) 9449758b77fSLuigi Rizzo { 9459758b77fSLuigi Rizzo int val; 9469758b77fSLuigi Rizzo char *s; 9479758b77fSLuigi Rizzo 9489758b77fSLuigi Rizzo val = strtoul(str, &s, 0); 9499758b77fSLuigi Rizzo if (s == str || *s != '\0' || val >= 0x100) 9509758b77fSLuigi Rizzo val = match_token(icmpcodes, str); 951e706181bSLuigi Rizzo if (val < 0) 9529758b77fSLuigi Rizzo errx(EX_DATAERR, "unknown ICMP unreachable code ``%s''", str); 9539758b77fSLuigi Rizzo *codep = val; 9549758b77fSLuigi Rizzo return; 9559758b77fSLuigi Rizzo } 9569758b77fSLuigi Rizzo 9579758b77fSLuigi Rizzo static void 958571f8c1bSLuigi Rizzo print_reject_code(uint16_t code) 9599758b77fSLuigi Rizzo { 96062ff38aeSLuigi Rizzo char const *s = match_value(icmpcodes, code); 9619758b77fSLuigi Rizzo 9629758b77fSLuigi Rizzo if (s != NULL) 9635e43aef8SLuigi Rizzo printf("unreach %s", s); 9649758b77fSLuigi Rizzo else 9655e43aef8SLuigi Rizzo printf("unreach %u", code); 9669758b77fSLuigi Rizzo } 9679758b77fSLuigi Rizzo 9689066356bSBjoern A. Zeeb static struct _s_x icmp6codes[] = { 9699066356bSBjoern A. Zeeb { "no-route", ICMP6_DST_UNREACH_NOROUTE }, 9709066356bSBjoern A. Zeeb { "admin-prohib", ICMP6_DST_UNREACH_ADMIN }, 9719066356bSBjoern A. Zeeb { "address", ICMP6_DST_UNREACH_ADDR }, 9729066356bSBjoern A. Zeeb { "port", ICMP6_DST_UNREACH_NOPORT }, 9739066356bSBjoern A. Zeeb { NULL, 0 } 9749066356bSBjoern A. Zeeb }; 9759066356bSBjoern A. Zeeb 9769066356bSBjoern A. Zeeb static void 9779066356bSBjoern A. Zeeb fill_unreach6_code(u_short *codep, char *str) 9789066356bSBjoern A. Zeeb { 9799066356bSBjoern A. Zeeb int val; 9809066356bSBjoern A. Zeeb char *s; 9819066356bSBjoern A. Zeeb 9829066356bSBjoern A. Zeeb val = strtoul(str, &s, 0); 9839066356bSBjoern A. Zeeb if (s == str || *s != '\0' || val >= 0x100) 9849066356bSBjoern A. Zeeb val = match_token(icmp6codes, str); 9859066356bSBjoern A. Zeeb if (val < 0) 9869066356bSBjoern A. Zeeb errx(EX_DATAERR, "unknown ICMPv6 unreachable code ``%s''", str); 9879066356bSBjoern A. Zeeb *codep = val; 9889066356bSBjoern A. Zeeb return; 9899066356bSBjoern A. Zeeb } 9909066356bSBjoern A. Zeeb 9919066356bSBjoern A. Zeeb static void 9929066356bSBjoern A. Zeeb print_unreach6_code(uint16_t code) 9939066356bSBjoern A. Zeeb { 9949066356bSBjoern A. Zeeb char const *s = match_value(icmp6codes, code); 9959066356bSBjoern A. Zeeb 9969066356bSBjoern A. Zeeb if (s != NULL) 9979066356bSBjoern A. Zeeb printf("unreach6 %s", s); 9989066356bSBjoern A. Zeeb else 9999066356bSBjoern A. Zeeb printf("unreach6 %u", code); 10009066356bSBjoern A. Zeeb } 10019066356bSBjoern A. Zeeb 10029758b77fSLuigi Rizzo /* 10039758b77fSLuigi Rizzo * Returns the number of bits set (from left) in a contiguous bitmask, 10049758b77fSLuigi Rizzo * or -1 if the mask is not contiguous. 10059758b77fSLuigi Rizzo * XXX this needs a proper fix. 10069758b77fSLuigi Rizzo * This effectively works on masks in big-endian (network) format. 10079758b77fSLuigi Rizzo * when compiled on little endian architectures. 10089758b77fSLuigi Rizzo * 10099758b77fSLuigi Rizzo * First bit is bit 7 of the first byte -- note, for MAC addresses, 10109758b77fSLuigi Rizzo * the first bit on the wire is bit 0 of the first byte. 10119758b77fSLuigi Rizzo * len is the max length in bits. 10129758b77fSLuigi Rizzo */ 10139758b77fSLuigi Rizzo static int 1014f3a126d3SLuigi Rizzo contigmask(uint8_t *p, int len) 10159758b77fSLuigi Rizzo { 10169758b77fSLuigi Rizzo int i, n; 1017f3a126d3SLuigi Rizzo 10189758b77fSLuigi Rizzo for (i=0; i<len ; i++) 10199758b77fSLuigi Rizzo if ( (p[i/8] & (1 << (7 - (i%8)))) == 0) /* first bit unset */ 10209758b77fSLuigi Rizzo break; 10219758b77fSLuigi Rizzo for (n=i+1; n < len; n++) 10229758b77fSLuigi Rizzo if ( (p[n/8] & (1 << (7 - (n%8)))) != 0) 10239758b77fSLuigi Rizzo return -1; /* mask not contiguous */ 10249758b77fSLuigi Rizzo return i; 10259758b77fSLuigi Rizzo } 10269758b77fSLuigi Rizzo 10279758b77fSLuigi Rizzo /* 10289758b77fSLuigi Rizzo * print flags set/clear in the two bitmasks passed as parameters. 10299758b77fSLuigi Rizzo * There is a specialized check for f_tcpflags. 10309758b77fSLuigi Rizzo */ 10319758b77fSLuigi Rizzo static void 103262ff38aeSLuigi Rizzo print_flags(char const *name, ipfw_insn *cmd, struct _s_x *list) 10339758b77fSLuigi Rizzo { 103462ff38aeSLuigi Rizzo char const *comma = ""; 10359758b77fSLuigi Rizzo int i; 1036f3a126d3SLuigi Rizzo uint8_t set = cmd->arg1 & 0xff; 1037f3a126d3SLuigi Rizzo uint8_t clear = (cmd->arg1 >> 8) & 0xff; 10389758b77fSLuigi Rizzo 10399758b77fSLuigi Rizzo if (list == f_tcpflags && set == TH_SYN && clear == TH_ACK) { 10409758b77fSLuigi Rizzo printf(" setup"); 10419758b77fSLuigi Rizzo return; 10429758b77fSLuigi Rizzo } 10439758b77fSLuigi Rizzo 10449758b77fSLuigi Rizzo printf(" %s ", name); 10459758b77fSLuigi Rizzo for (i=0; list[i].x != 0; i++) { 10469758b77fSLuigi Rizzo if (set & list[i].x) { 10479758b77fSLuigi Rizzo set &= ~list[i].x; 10489758b77fSLuigi Rizzo printf("%s%s", comma, list[i].s); 10499758b77fSLuigi Rizzo comma = ","; 10509758b77fSLuigi Rizzo } 10519758b77fSLuigi Rizzo if (clear & list[i].x) { 10529758b77fSLuigi Rizzo clear &= ~list[i].x; 10539758b77fSLuigi Rizzo printf("%s!%s", comma, list[i].s); 10549758b77fSLuigi Rizzo comma = ","; 10559758b77fSLuigi Rizzo } 10569758b77fSLuigi Rizzo } 10579758b77fSLuigi Rizzo } 10589758b77fSLuigi Rizzo 10599758b77fSLuigi Rizzo /* 10609758b77fSLuigi Rizzo * Print the ip address contained in a command. 10619758b77fSLuigi Rizzo */ 10629758b77fSLuigi Rizzo static void 106362ff38aeSLuigi Rizzo print_ip(ipfw_insn_ip *cmd, char const *s) 10649758b77fSLuigi Rizzo { 10659758b77fSLuigi Rizzo struct hostent *he = NULL; 1066571f8c1bSLuigi Rizzo int len = F_LEN((ipfw_insn *)cmd); 1067571f8c1bSLuigi Rizzo uint32_t *a = ((ipfw_insn_u32 *)cmd)->d; 10689758b77fSLuigi Rizzo 1069e706181bSLuigi Rizzo printf("%s%s ", cmd->o.len & F_NOT ? " not": "", s); 10709758b77fSLuigi Rizzo 10719758b77fSLuigi Rizzo if (cmd->o.opcode == O_IP_SRC_ME || cmd->o.opcode == O_IP_DST_ME) { 10729758b77fSLuigi Rizzo printf("me"); 10739758b77fSLuigi Rizzo return; 10749758b77fSLuigi Rizzo } 1075cd8b5ae0SRuslan Ermilov if (cmd->o.opcode == O_IP_SRC_LOOKUP || 1076cd8b5ae0SRuslan Ermilov cmd->o.opcode == O_IP_DST_LOOKUP) { 1077cd8b5ae0SRuslan Ermilov printf("table(%u", ((ipfw_insn *)cmd)->arg1); 1078cd8b5ae0SRuslan Ermilov if (len == F_INSN_SIZE(ipfw_insn_u32)) 1079cd8b5ae0SRuslan Ermilov printf(",%u", *a); 1080cd8b5ae0SRuslan Ermilov printf(")"); 1081cd8b5ae0SRuslan Ermilov return; 1082cd8b5ae0SRuslan Ermilov } 10839758b77fSLuigi Rizzo if (cmd->o.opcode == O_IP_SRC_SET || cmd->o.opcode == O_IP_DST_SET) { 1084571f8c1bSLuigi Rizzo uint32_t x, *map = (uint32_t *)&(cmd->mask); 10859ef3f16dSLuigi Rizzo int i, j; 10869758b77fSLuigi Rizzo char comma = '{'; 10879758b77fSLuigi Rizzo 10889758b77fSLuigi Rizzo x = cmd->o.arg1 - 1; 10899758b77fSLuigi Rizzo x = htonl( ~x ); 10909758b77fSLuigi Rizzo cmd->addr.s_addr = htonl(cmd->addr.s_addr); 10919758b77fSLuigi Rizzo printf("%s/%d", inet_ntoa(cmd->addr), 1092f3a126d3SLuigi Rizzo contigmask((uint8_t *)&x, 32)); 10939758b77fSLuigi Rizzo x = cmd->addr.s_addr = htonl(cmd->addr.s_addr); 10949758b77fSLuigi Rizzo x &= 0xff; /* base */ 10959ef3f16dSLuigi Rizzo /* 10969ef3f16dSLuigi Rizzo * Print bits and ranges. 10979ef3f16dSLuigi Rizzo * Locate first bit set (i), then locate first bit unset (j). 10989ef3f16dSLuigi Rizzo * If we have 3+ consecutive bits set, then print them as a 10999ef3f16dSLuigi Rizzo * range, otherwise only print the initial bit and rescan. 11009ef3f16dSLuigi Rizzo */ 11019758b77fSLuigi Rizzo for (i=0; i < cmd->o.arg1; i++) 1102571f8c1bSLuigi Rizzo if (map[i/32] & (1<<(i & 31))) { 11039ef3f16dSLuigi Rizzo for (j=i+1; j < cmd->o.arg1; j++) 1104571f8c1bSLuigi Rizzo if (!(map[ j/32] & (1<<(j & 31)))) 11059ef3f16dSLuigi Rizzo break; 11069758b77fSLuigi Rizzo printf("%c%d", comma, i+x); 11079ef3f16dSLuigi Rizzo if (j>i+2) { /* range has at least 3 elements */ 11089ef3f16dSLuigi Rizzo printf("-%d", j-1+x); 11099ef3f16dSLuigi Rizzo i = j-1; 11109ef3f16dSLuigi Rizzo } 11119758b77fSLuigi Rizzo comma = ','; 11129758b77fSLuigi Rizzo } 11139758b77fSLuigi Rizzo printf("}"); 11149758b77fSLuigi Rizzo return; 11159758b77fSLuigi Rizzo } 1116571f8c1bSLuigi Rizzo /* 1117571f8c1bSLuigi Rizzo * len == 2 indicates a single IP, whereas lists of 1 or more 1118571f8c1bSLuigi Rizzo * addr/mask pairs have len = (2n+1). We convert len to n so we 1119571f8c1bSLuigi Rizzo * use that to count the number of entries. 1120571f8c1bSLuigi Rizzo */ 1121571f8c1bSLuigi Rizzo for (len = len / 2; len > 0; len--, a += 2) { 1122571f8c1bSLuigi Rizzo int mb = /* mask length */ 1123571f8c1bSLuigi Rizzo (cmd->o.opcode == O_IP_SRC || cmd->o.opcode == O_IP_DST) ? 1124f3a126d3SLuigi Rizzo 32 : contigmask((uint8_t *)&(a[1]), 32); 11259758b77fSLuigi Rizzo if (mb == 32 && do_resolv) 1126571f8c1bSLuigi Rizzo he = gethostbyaddr((char *)&(a[0]), sizeof(u_long), AF_INET); 11279758b77fSLuigi Rizzo if (he != NULL) /* resolved to name */ 11289758b77fSLuigi Rizzo printf("%s", he->h_name); 11299758b77fSLuigi Rizzo else if (mb == 0) /* any */ 11309758b77fSLuigi Rizzo printf("any"); 11319758b77fSLuigi Rizzo else { /* numeric IP followed by some kind of mask */ 1132571f8c1bSLuigi Rizzo printf("%s", inet_ntoa( *((struct in_addr *)&a[0]) ) ); 11339758b77fSLuigi Rizzo if (mb < 0) 1134571f8c1bSLuigi Rizzo printf(":%s", inet_ntoa( *((struct in_addr *)&a[1]) ) ); 11359758b77fSLuigi Rizzo else if (mb < 32) 11369758b77fSLuigi Rizzo printf("/%d", mb); 11379758b77fSLuigi Rizzo } 1138571f8c1bSLuigi Rizzo if (len > 1) 1139571f8c1bSLuigi Rizzo printf(","); 1140571f8c1bSLuigi Rizzo } 11419758b77fSLuigi Rizzo } 11429758b77fSLuigi Rizzo 11439758b77fSLuigi Rizzo /* 11449758b77fSLuigi Rizzo * prints a MAC address/mask pair 11459758b77fSLuigi Rizzo */ 11469758b77fSLuigi Rizzo static void 1147f3a126d3SLuigi Rizzo print_mac(uint8_t *addr, uint8_t *mask) 11489758b77fSLuigi Rizzo { 11499758b77fSLuigi Rizzo int l = contigmask(mask, 48); 11509758b77fSLuigi Rizzo 11519758b77fSLuigi Rizzo if (l == 0) 11529758b77fSLuigi Rizzo printf(" any"); 11539758b77fSLuigi Rizzo else { 11549758b77fSLuigi Rizzo printf(" %02x:%02x:%02x:%02x:%02x:%02x", 11559758b77fSLuigi Rizzo addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); 11569758b77fSLuigi Rizzo if (l == -1) 11579758b77fSLuigi Rizzo printf("&%02x:%02x:%02x:%02x:%02x:%02x", 11589758b77fSLuigi Rizzo mask[0], mask[1], mask[2], 11599758b77fSLuigi Rizzo mask[3], mask[4], mask[5]); 11609758b77fSLuigi Rizzo else if (l < 48) 11619758b77fSLuigi Rizzo printf("/%d", l); 11629758b77fSLuigi Rizzo } 11639758b77fSLuigi Rizzo } 11649758b77fSLuigi Rizzo 11655e43aef8SLuigi Rizzo static void 11665e43aef8SLuigi Rizzo fill_icmptypes(ipfw_insn_u32 *cmd, char *av) 11675e43aef8SLuigi Rizzo { 1168571f8c1bSLuigi Rizzo uint8_t type; 11695e43aef8SLuigi Rizzo 11705e43aef8SLuigi Rizzo cmd->d[0] = 0; 11715e43aef8SLuigi Rizzo while (*av) { 11725e43aef8SLuigi Rizzo if (*av == ',') 11735e43aef8SLuigi Rizzo av++; 11745e43aef8SLuigi Rizzo 11755e43aef8SLuigi Rizzo type = strtoul(av, &av, 0); 11765e43aef8SLuigi Rizzo 11775e43aef8SLuigi Rizzo if (*av != ',' && *av != '\0') 11785e43aef8SLuigi Rizzo errx(EX_DATAERR, "invalid ICMP type"); 11795e43aef8SLuigi Rizzo 11805e43aef8SLuigi Rizzo if (type > 31) 11815e43aef8SLuigi Rizzo errx(EX_DATAERR, "ICMP type out of range"); 11825e43aef8SLuigi Rizzo 11835e43aef8SLuigi Rizzo cmd->d[0] |= 1 << type; 11845e43aef8SLuigi Rizzo } 11855e43aef8SLuigi Rizzo cmd->o.opcode = O_ICMPTYPE; 11865e43aef8SLuigi Rizzo cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32); 11875e43aef8SLuigi Rizzo } 11885e43aef8SLuigi Rizzo 11895e43aef8SLuigi Rizzo static void 11905e43aef8SLuigi Rizzo print_icmptypes(ipfw_insn_u32 *cmd) 11915e43aef8SLuigi Rizzo { 11925e43aef8SLuigi Rizzo int i; 11935e43aef8SLuigi Rizzo char sep= ' '; 11945e43aef8SLuigi Rizzo 11955e43aef8SLuigi Rizzo printf(" icmptypes"); 11965e43aef8SLuigi Rizzo for (i = 0; i < 32; i++) { 11975e43aef8SLuigi Rizzo if ( (cmd->d[0] & (1 << (i))) == 0) 11985e43aef8SLuigi Rizzo continue; 11995e43aef8SLuigi Rizzo printf("%c%d", sep, i); 12005e43aef8SLuigi Rizzo sep = ','; 12015e43aef8SLuigi Rizzo } 12025e43aef8SLuigi Rizzo } 12039758b77fSLuigi Rizzo 12049758b77fSLuigi Rizzo /* 12058195404bSBrooks Davis * Print the ip address contained in a command. 12068195404bSBrooks Davis */ 12078195404bSBrooks Davis static void 12088195404bSBrooks Davis print_ip6(ipfw_insn_ip6 *cmd, char const *s) 12098195404bSBrooks Davis { 12108195404bSBrooks Davis struct hostent *he = NULL; 12118195404bSBrooks Davis int len = F_LEN((ipfw_insn *) cmd) - 1; 12128195404bSBrooks Davis struct in6_addr *a = &(cmd->addr6); 12138195404bSBrooks Davis char trad[255]; 12148195404bSBrooks Davis 12158195404bSBrooks Davis printf("%s%s ", cmd->o.len & F_NOT ? " not": "", s); 12168195404bSBrooks Davis 12178195404bSBrooks Davis if (cmd->o.opcode == O_IP6_SRC_ME || cmd->o.opcode == O_IP6_DST_ME) { 12188195404bSBrooks Davis printf("me6"); 12198195404bSBrooks Davis return; 12208195404bSBrooks Davis } 12218195404bSBrooks Davis if (cmd->o.opcode == O_IP6) { 122236c263ccSHajimu UMEMOTO printf(" ip6"); 12238195404bSBrooks Davis return; 12248195404bSBrooks Davis } 12258195404bSBrooks Davis 12268195404bSBrooks Davis /* 12278195404bSBrooks Davis * len == 4 indicates a single IP, whereas lists of 1 or more 12288195404bSBrooks Davis * addr/mask pairs have len = (2n+1). We convert len to n so we 12298195404bSBrooks Davis * use that to count the number of entries. 12308195404bSBrooks Davis */ 12318195404bSBrooks Davis 12328195404bSBrooks Davis for (len = len / 4; len > 0; len -= 2, a += 2) { 12338195404bSBrooks Davis int mb = /* mask length */ 12348195404bSBrooks Davis (cmd->o.opcode == O_IP6_SRC || cmd->o.opcode == O_IP6_DST) ? 12358195404bSBrooks Davis 128 : contigmask((uint8_t *)&(a[1]), 128); 12368195404bSBrooks Davis 12378195404bSBrooks Davis if (mb == 128 && do_resolv) 12388195404bSBrooks Davis he = gethostbyaddr((char *)a, sizeof(*a), AF_INET6); 12398195404bSBrooks Davis if (he != NULL) /* resolved to name */ 12408195404bSBrooks Davis printf("%s", he->h_name); 12418195404bSBrooks Davis else if (mb == 0) /* any */ 12428195404bSBrooks Davis printf("any"); 12438195404bSBrooks Davis else { /* numeric IP followed by some kind of mask */ 12448195404bSBrooks Davis if (inet_ntop(AF_INET6, a, trad, sizeof( trad ) ) == NULL) 12458195404bSBrooks Davis printf("Error ntop in print_ip6\n"); 12468195404bSBrooks Davis printf("%s", trad ); 12478195404bSBrooks Davis if (mb < 0) /* XXX not really legal... */ 12488195404bSBrooks Davis printf(":%s", 12498195404bSBrooks Davis inet_ntop(AF_INET6, &a[1], trad, sizeof(trad))); 12508195404bSBrooks Davis else if (mb < 128) 12518195404bSBrooks Davis printf("/%d", mb); 12528195404bSBrooks Davis } 12538195404bSBrooks Davis if (len > 2) 12548195404bSBrooks Davis printf(","); 12558195404bSBrooks Davis } 12568195404bSBrooks Davis } 12578195404bSBrooks Davis 12588195404bSBrooks Davis static void 12598195404bSBrooks Davis fill_icmp6types(ipfw_insn_icmp6 *cmd, char *av) 12608195404bSBrooks Davis { 12618195404bSBrooks Davis uint8_t type; 12628195404bSBrooks Davis 1263e7f2ec53SJohn Hay bzero(cmd, sizeof(*cmd)); 12648195404bSBrooks Davis while (*av) { 12658195404bSBrooks Davis if (*av == ',') 12668195404bSBrooks Davis av++; 12678195404bSBrooks Davis type = strtoul(av, &av, 0); 12688195404bSBrooks Davis if (*av != ',' && *av != '\0') 12698195404bSBrooks Davis errx(EX_DATAERR, "invalid ICMP6 type"); 12708195404bSBrooks Davis /* 12718195404bSBrooks Davis * XXX: shouldn't this be 0xFF? I can't see any reason why 12728195404bSBrooks Davis * we shouldn't be able to filter all possiable values 12738195404bSBrooks Davis * regardless of the ability of the rest of the kernel to do 12748195404bSBrooks Davis * anything useful with them. 12758195404bSBrooks Davis */ 12768195404bSBrooks Davis if (type > ICMP6_MAXTYPE) 12778195404bSBrooks Davis errx(EX_DATAERR, "ICMP6 type out of range"); 12788195404bSBrooks Davis cmd->d[type / 32] |= ( 1 << (type % 32)); 12798195404bSBrooks Davis } 12808195404bSBrooks Davis cmd->o.opcode = O_ICMP6TYPE; 12818195404bSBrooks Davis cmd->o.len |= F_INSN_SIZE(ipfw_insn_icmp6); 12828195404bSBrooks Davis } 12838195404bSBrooks Davis 12848195404bSBrooks Davis 12858195404bSBrooks Davis static void 12868195404bSBrooks Davis print_icmp6types(ipfw_insn_u32 *cmd) 12878195404bSBrooks Davis { 12888195404bSBrooks Davis int i, j; 12898195404bSBrooks Davis char sep= ' '; 12908195404bSBrooks Davis 129136c263ccSHajimu UMEMOTO printf(" ip6 icmp6types"); 12928195404bSBrooks Davis for (i = 0; i < 7; i++) 12938195404bSBrooks Davis for (j=0; j < 32; ++j) { 12948195404bSBrooks Davis if ( (cmd->d[i] & (1 << (j))) == 0) 12958195404bSBrooks Davis continue; 12968195404bSBrooks Davis printf("%c%d", sep, (i*32 + j)); 12978195404bSBrooks Davis sep = ','; 12988195404bSBrooks Davis } 12998195404bSBrooks Davis } 13008195404bSBrooks Davis 13018195404bSBrooks Davis static void 13028195404bSBrooks Davis print_flow6id( ipfw_insn_u32 *cmd) 13038195404bSBrooks Davis { 13048195404bSBrooks Davis uint16_t i, limit = cmd->o.arg1; 13058195404bSBrooks Davis char sep = ','; 13068195404bSBrooks Davis 13078195404bSBrooks Davis printf(" flow-id "); 13088195404bSBrooks Davis for( i=0; i < limit; ++i) { 13098195404bSBrooks Davis if (i == limit - 1) 13108195404bSBrooks Davis sep = ' '; 13118195404bSBrooks Davis printf("%d%c", cmd->d[i], sep); 13128195404bSBrooks Davis } 13138195404bSBrooks Davis } 13148195404bSBrooks Davis 13158195404bSBrooks Davis /* structure and define for the extension header in ipv6 */ 13168195404bSBrooks Davis static struct _s_x ext6hdrcodes[] = { 13178195404bSBrooks Davis { "frag", EXT_FRAGMENT }, 13188195404bSBrooks Davis { "hopopt", EXT_HOPOPTS }, 13198195404bSBrooks Davis { "route", EXT_ROUTING }, 13209066356bSBjoern A. Zeeb { "dstopt", EXT_DSTOPTS }, 13218195404bSBrooks Davis { "ah", EXT_AH }, 13228195404bSBrooks Davis { "esp", EXT_ESP }, 13237a92401aSBjoern A. Zeeb { "rthdr0", EXT_RTHDR0 }, 13247a92401aSBjoern A. Zeeb { "rthdr2", EXT_RTHDR2 }, 13258195404bSBrooks Davis { NULL, 0 } 13268195404bSBrooks Davis }; 13278195404bSBrooks Davis 13288195404bSBrooks Davis /* fills command for the extension header filtering */ 1329daa9733aSLuigi Rizzo static int 13308195404bSBrooks Davis fill_ext6hdr( ipfw_insn *cmd, char *av) 13318195404bSBrooks Davis { 13328195404bSBrooks Davis int tok; 13338195404bSBrooks Davis char *s = av; 13348195404bSBrooks Davis 13358195404bSBrooks Davis cmd->arg1 = 0; 13368195404bSBrooks Davis 13378195404bSBrooks Davis while(s) { 13388195404bSBrooks Davis av = strsep( &s, ",") ; 13398195404bSBrooks Davis tok = match_token(ext6hdrcodes, av); 13408195404bSBrooks Davis switch (tok) { 13418195404bSBrooks Davis case EXT_FRAGMENT: 13428195404bSBrooks Davis cmd->arg1 |= EXT_FRAGMENT; 13438195404bSBrooks Davis break; 13448195404bSBrooks Davis 13458195404bSBrooks Davis case EXT_HOPOPTS: 13468195404bSBrooks Davis cmd->arg1 |= EXT_HOPOPTS; 13478195404bSBrooks Davis break; 13488195404bSBrooks Davis 13498195404bSBrooks Davis case EXT_ROUTING: 13508195404bSBrooks Davis cmd->arg1 |= EXT_ROUTING; 13518195404bSBrooks Davis break; 13528195404bSBrooks Davis 13539066356bSBjoern A. Zeeb case EXT_DSTOPTS: 13549066356bSBjoern A. Zeeb cmd->arg1 |= EXT_DSTOPTS; 13559066356bSBjoern A. Zeeb break; 13569066356bSBjoern A. Zeeb 13578195404bSBrooks Davis case EXT_AH: 13588195404bSBrooks Davis cmd->arg1 |= EXT_AH; 13598195404bSBrooks Davis break; 13608195404bSBrooks Davis 13618195404bSBrooks Davis case EXT_ESP: 13628195404bSBrooks Davis cmd->arg1 |= EXT_ESP; 13638195404bSBrooks Davis break; 13648195404bSBrooks Davis 13657a92401aSBjoern A. Zeeb case EXT_RTHDR0: 13667a92401aSBjoern A. Zeeb cmd->arg1 |= EXT_RTHDR0; 13677a92401aSBjoern A. Zeeb break; 13687a92401aSBjoern A. Zeeb 13697a92401aSBjoern A. Zeeb case EXT_RTHDR2: 13707a92401aSBjoern A. Zeeb cmd->arg1 |= EXT_RTHDR2; 13717a92401aSBjoern A. Zeeb break; 13727a92401aSBjoern A. Zeeb 13738195404bSBrooks Davis default: 13748195404bSBrooks Davis errx( EX_DATAERR, "invalid option for ipv6 exten header" ); 13758195404bSBrooks Davis break; 13768195404bSBrooks Davis } 13778195404bSBrooks Davis } 13788195404bSBrooks Davis if (cmd->arg1 == 0 ) 13798195404bSBrooks Davis return 0; 13808195404bSBrooks Davis cmd->opcode = O_EXT_HDR; 13818195404bSBrooks Davis cmd->len |= F_INSN_SIZE( ipfw_insn ); 13828195404bSBrooks Davis return 1; 13838195404bSBrooks Davis } 13848195404bSBrooks Davis 1385daa9733aSLuigi Rizzo static void 13868195404bSBrooks Davis print_ext6hdr( ipfw_insn *cmd ) 13878195404bSBrooks Davis { 13888195404bSBrooks Davis char sep = ' '; 13898195404bSBrooks Davis 13908195404bSBrooks Davis printf(" extension header:"); 13918195404bSBrooks Davis if (cmd->arg1 & EXT_FRAGMENT ) { 13928195404bSBrooks Davis printf("%cfragmentation", sep); 13938195404bSBrooks Davis sep = ','; 13948195404bSBrooks Davis } 13958195404bSBrooks Davis if (cmd->arg1 & EXT_HOPOPTS ) { 13968195404bSBrooks Davis printf("%chop options", sep); 13978195404bSBrooks Davis sep = ','; 13988195404bSBrooks Davis } 13998195404bSBrooks Davis if (cmd->arg1 & EXT_ROUTING ) { 14008195404bSBrooks Davis printf("%crouting options", sep); 14018195404bSBrooks Davis sep = ','; 14028195404bSBrooks Davis } 14037a92401aSBjoern A. Zeeb if (cmd->arg1 & EXT_RTHDR0 ) { 14047a92401aSBjoern A. Zeeb printf("%crthdr0", sep); 14057a92401aSBjoern A. Zeeb sep = ','; 14067a92401aSBjoern A. Zeeb } 14077a92401aSBjoern A. Zeeb if (cmd->arg1 & EXT_RTHDR2 ) { 14087a92401aSBjoern A. Zeeb printf("%crthdr2", sep); 14097a92401aSBjoern A. Zeeb sep = ','; 14107a92401aSBjoern A. Zeeb } 14119066356bSBjoern A. Zeeb if (cmd->arg1 & EXT_DSTOPTS ) { 14129066356bSBjoern A. Zeeb printf("%cdestination options", sep); 14139066356bSBjoern A. Zeeb sep = ','; 14149066356bSBjoern A. Zeeb } 14158195404bSBrooks Davis if (cmd->arg1 & EXT_AH ) { 14168195404bSBrooks Davis printf("%cauthentication header", sep); 14178195404bSBrooks Davis sep = ','; 14188195404bSBrooks Davis } 14198195404bSBrooks Davis if (cmd->arg1 & EXT_ESP ) { 14208195404bSBrooks Davis printf("%cencapsulated security payload", sep); 14218195404bSBrooks Davis } 14228195404bSBrooks Davis } 14238195404bSBrooks Davis 14248195404bSBrooks Davis /* 14259758b77fSLuigi Rizzo * show_ipfw() prints the body of an ipfw rule. 14269758b77fSLuigi Rizzo * Because the standard rule has at least proto src_ip dst_ip, we use 14279758b77fSLuigi Rizzo * a helper function to produce these entries if not provided explicitly. 1428e706181bSLuigi Rizzo * The first argument is the list of fields we have, the second is 1429e706181bSLuigi Rizzo * the list of fields we want to be printed. 143099e5e645SLuigi Rizzo * 1431e706181bSLuigi Rizzo * Special cases if we have provided a MAC header: 1432e706181bSLuigi Rizzo * + if the rule does not contain IP addresses/ports, do not print them; 1433e706181bSLuigi Rizzo * + if the rule does not contain an IP proto, print "all" instead of "ip"; 1434e706181bSLuigi Rizzo * 1435e706181bSLuigi Rizzo * Once we have 'have_options', IP header fields are printed as options. 14369758b77fSLuigi Rizzo */ 143799e5e645SLuigi Rizzo #define HAVE_PROTO 0x0001 143899e5e645SLuigi Rizzo #define HAVE_SRCIP 0x0002 143999e5e645SLuigi Rizzo #define HAVE_DSTIP 0x0004 14405b41efddSMaxim Konovalov #define HAVE_PROTO4 0x0008 14415b41efddSMaxim Konovalov #define HAVE_PROTO6 0x0010 1442e706181bSLuigi Rizzo #define HAVE_OPTIONS 0x8000 14439758b77fSLuigi Rizzo 144499e5e645SLuigi Rizzo #define HAVE_IP (HAVE_PROTO | HAVE_SRCIP | HAVE_DSTIP) 14459758b77fSLuigi Rizzo static void 1446daa9733aSLuigi Rizzo show_prerequisites(int *flags, int want, int cmd __unused) 14479758b77fSLuigi Rizzo { 1448ac6cec51SLuigi Rizzo if (comment_only) 1449ac6cec51SLuigi Rizzo return; 1450e706181bSLuigi Rizzo if ( (*flags & HAVE_IP) == HAVE_IP) 1451e706181bSLuigi Rizzo *flags |= HAVE_OPTIONS; 145299e5e645SLuigi Rizzo 1453e706181bSLuigi Rizzo if ( !(*flags & HAVE_OPTIONS)) { 1454daa9733aSLuigi Rizzo if ( !(*flags & HAVE_PROTO) && (want & HAVE_PROTO)) { 145557cd6d26SMax Laier if ( (*flags & HAVE_PROTO4)) 145657cd6d26SMax Laier printf(" ip4"); 145757cd6d26SMax Laier else if ( (*flags & HAVE_PROTO6)) 145857cd6d26SMax Laier printf(" ip6"); 145957cd6d26SMax Laier else 1460e706181bSLuigi Rizzo printf(" ip"); 1461daa9733aSLuigi Rizzo } 14629758b77fSLuigi Rizzo if ( !(*flags & HAVE_SRCIP) && (want & HAVE_SRCIP)) 14639758b77fSLuigi Rizzo printf(" from any"); 14649758b77fSLuigi Rizzo if ( !(*flags & HAVE_DSTIP) && (want & HAVE_DSTIP)) 14659758b77fSLuigi Rizzo printf(" to any"); 1466e706181bSLuigi Rizzo } 14679758b77fSLuigi Rizzo *flags |= want; 14689758b77fSLuigi Rizzo } 14699758b77fSLuigi Rizzo 14709758b77fSLuigi Rizzo static void 147145f61351SMaxim Konovalov show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth) 14729758b77fSLuigi Rizzo { 14733d2209aeSGiorgos Keramidas static int twidth = 0; 14749758b77fSLuigi Rizzo int l; 14756a7d5cb6SOleg Bulyzhin ipfw_insn *cmd, *tagptr = NULL; 1476daa9733aSLuigi Rizzo const char *comment = NULL; /* ptr to comment if we have one */ 14779758b77fSLuigi Rizzo int proto = 0; /* default */ 14789758b77fSLuigi Rizzo int flags = 0; /* prerequisites */ 14799758b77fSLuigi Rizzo ipfw_insn_log *logptr = NULL; /* set if we find an O_LOG */ 1480974dfe30SBrian Feldman ipfw_insn_altq *altqptr = NULL; /* set if we find an O_ALTQ */ 14819758b77fSLuigi Rizzo int or_block = 0; /* we are in an or block */ 1482571f8c1bSLuigi Rizzo uint32_t set_disable; 14839758b77fSLuigi Rizzo 1484330462a3SBernd Walter bcopy(&rule->next_rule, &set_disable, sizeof(set_disable)); 148543405724SLuigi Rizzo 148643405724SLuigi Rizzo if (set_disable & (1 << rule->set)) { /* disabled */ 148743405724SLuigi Rizzo if (!show_sets) 148843405724SLuigi Rizzo return; 148943405724SLuigi Rizzo else 149043405724SLuigi Rizzo printf("# DISABLED "); 149143405724SLuigi Rizzo } 14929758b77fSLuigi Rizzo printf("%05u ", rule->rulenum); 14939758b77fSLuigi Rizzo 149462ff38aeSLuigi Rizzo if (pcwidth>0 || bcwidth>0) 1495330462a3SBernd Walter printf("%*llu %*llu ", pcwidth, align_uint64(&rule->pcnt), 1496330462a3SBernd Walter bcwidth, align_uint64(&rule->bcnt)); 14979758b77fSLuigi Rizzo 14981b43a426SLuigi Rizzo if (do_time == 2) 14991b43a426SLuigi Rizzo printf("%10u ", rule->timestamp); 15001b43a426SLuigi Rizzo else if (do_time == 1) { 15019758b77fSLuigi Rizzo char timestr[30]; 15023d2209aeSGiorgos Keramidas time_t t = (time_t)0; 15033d2209aeSGiorgos Keramidas 15043d2209aeSGiorgos Keramidas if (twidth == 0) { 15053d2209aeSGiorgos Keramidas strcpy(timestr, ctime(&t)); 15063d2209aeSGiorgos Keramidas *strchr(timestr, '\n') = '\0'; 15073d2209aeSGiorgos Keramidas twidth = strlen(timestr); 15083d2209aeSGiorgos Keramidas } 15093d2209aeSGiorgos Keramidas if (rule->timestamp) { 15103d2209aeSGiorgos Keramidas t = _long_to_time(rule->timestamp); 15119758b77fSLuigi Rizzo 15129758b77fSLuigi Rizzo strcpy(timestr, ctime(&t)); 15139758b77fSLuigi Rizzo *strchr(timestr, '\n') = '\0'; 15149758b77fSLuigi Rizzo printf("%s ", timestr); 15159758b77fSLuigi Rizzo } else { 15163d2209aeSGiorgos Keramidas printf("%*s", twidth, " "); 15179758b77fSLuigi Rizzo } 15189758b77fSLuigi Rizzo } 15199758b77fSLuigi Rizzo 152043405724SLuigi Rizzo if (show_sets) 152143405724SLuigi Rizzo printf("set %d ", rule->set); 152243405724SLuigi Rizzo 15239758b77fSLuigi Rizzo /* 152412b5dc6aSLuigi Rizzo * print the optional "match probability" 152512b5dc6aSLuigi Rizzo */ 152612b5dc6aSLuigi Rizzo if (rule->cmd_len > 0) { 152712b5dc6aSLuigi Rizzo cmd = rule->cmd ; 152812b5dc6aSLuigi Rizzo if (cmd->opcode == O_PROB) { 152912b5dc6aSLuigi Rizzo ipfw_insn_u32 *p = (ipfw_insn_u32 *)cmd; 153012b5dc6aSLuigi Rizzo double d = 1.0 * p->d[0]; 153112b5dc6aSLuigi Rizzo 153212b5dc6aSLuigi Rizzo d = (d / 0x7fffffff); 153312b5dc6aSLuigi Rizzo printf("prob %f ", d); 153412b5dc6aSLuigi Rizzo } 153512b5dc6aSLuigi Rizzo } 153612b5dc6aSLuigi Rizzo 153712b5dc6aSLuigi Rizzo /* 15389758b77fSLuigi Rizzo * first print actions 15399758b77fSLuigi Rizzo */ 15409758b77fSLuigi Rizzo for (l = rule->cmd_len - rule->act_ofs, cmd = ACTION_PTR(rule); 15419758b77fSLuigi Rizzo l > 0 ; l -= F_LEN(cmd), cmd += F_LEN(cmd)) { 15429758b77fSLuigi Rizzo switch(cmd->opcode) { 15439758b77fSLuigi Rizzo case O_CHECK_STATE: 15449758b77fSLuigi Rizzo printf("check-state"); 1545e706181bSLuigi Rizzo flags = HAVE_IP; /* avoid printing anything else */ 15469758b77fSLuigi Rizzo break; 15479758b77fSLuigi Rizzo 15489758b77fSLuigi Rizzo case O_ACCEPT: 15499758b77fSLuigi Rizzo printf("allow"); 15509758b77fSLuigi Rizzo break; 15519758b77fSLuigi Rizzo 15529758b77fSLuigi Rizzo case O_COUNT: 15539758b77fSLuigi Rizzo printf("count"); 15549758b77fSLuigi Rizzo break; 15559758b77fSLuigi Rizzo 15569758b77fSLuigi Rizzo case O_DENY: 15579758b77fSLuigi Rizzo printf("deny"); 15589758b77fSLuigi Rizzo break; 15599758b77fSLuigi Rizzo 15605e43aef8SLuigi Rizzo case O_REJECT: 15615e43aef8SLuigi Rizzo if (cmd->arg1 == ICMP_REJECT_RST) 15625e43aef8SLuigi Rizzo printf("reset"); 15635e43aef8SLuigi Rizzo else if (cmd->arg1 == ICMP_UNREACH_HOST) 15645e43aef8SLuigi Rizzo printf("reject"); 15655e43aef8SLuigi Rizzo else 15665e43aef8SLuigi Rizzo print_reject_code(cmd->arg1); 15675e43aef8SLuigi Rizzo break; 15685e43aef8SLuigi Rizzo 15699066356bSBjoern A. Zeeb case O_UNREACH6: 15709066356bSBjoern A. Zeeb if (cmd->arg1 == ICMP6_UNREACH_RST) 15719066356bSBjoern A. Zeeb printf("reset6"); 15729066356bSBjoern A. Zeeb else 15739066356bSBjoern A. Zeeb print_unreach6_code(cmd->arg1); 15749066356bSBjoern A. Zeeb break; 15759066356bSBjoern A. Zeeb 1576254c4725SOleg Bulyzhin case O_SKIPTO: 1577254c4725SOleg Bulyzhin PRINT_UINT_ARG("skipto ", cmd->arg1); 157840b1ae9eSGleb Smirnoff break; 157940b1ae9eSGleb Smirnoff 15809758b77fSLuigi Rizzo case O_PIPE: 1581254c4725SOleg Bulyzhin PRINT_UINT_ARG("pipe ", cmd->arg1); 1582254c4725SOleg Bulyzhin break; 1583254c4725SOleg Bulyzhin 15849758b77fSLuigi Rizzo case O_QUEUE: 1585254c4725SOleg Bulyzhin PRINT_UINT_ARG("queue ", cmd->arg1); 1586254c4725SOleg Bulyzhin break; 1587254c4725SOleg Bulyzhin 15889758b77fSLuigi Rizzo case O_DIVERT: 1589254c4725SOleg Bulyzhin PRINT_UINT_ARG("divert ", cmd->arg1); 1590254c4725SOleg Bulyzhin break; 1591254c4725SOleg Bulyzhin 15929758b77fSLuigi Rizzo case O_TEE: 1593254c4725SOleg Bulyzhin PRINT_UINT_ARG("tee ", cmd->arg1); 1594254c4725SOleg Bulyzhin break; 1595254c4725SOleg Bulyzhin 1596670742a1SGleb Smirnoff case O_NETGRAPH: 1597254c4725SOleg Bulyzhin PRINT_UINT_ARG("netgraph ", cmd->arg1); 1598254c4725SOleg Bulyzhin break; 1599254c4725SOleg Bulyzhin 1600670742a1SGleb Smirnoff case O_NGTEE: 1601254c4725SOleg Bulyzhin PRINT_UINT_ARG("ngtee ", cmd->arg1); 1602254c4725SOleg Bulyzhin break; 1603670742a1SGleb Smirnoff 16049758b77fSLuigi Rizzo case O_FORWARD_IP: 16059758b77fSLuigi Rizzo { 16069758b77fSLuigi Rizzo ipfw_insn_sa *s = (ipfw_insn_sa *)cmd; 16079758b77fSLuigi Rizzo 1608c487be96SJulian Elischer if (s->sa.sin_addr.s_addr == INADDR_ANY) { 1609c487be96SJulian Elischer printf("fwd tablearg"); 1610c487be96SJulian Elischer } else { 16119758b77fSLuigi Rizzo printf("fwd %s", inet_ntoa(s->sa.sin_addr)); 1612c487be96SJulian Elischer } 16139758b77fSLuigi Rizzo if (s->sa.sin_port) 16144f531a53SLuigi Rizzo printf(",%d", s->sa.sin_port); 16159758b77fSLuigi Rizzo } 16169758b77fSLuigi Rizzo break; 16179758b77fSLuigi Rizzo 16189758b77fSLuigi Rizzo case O_LOG: /* O_LOG is printed last */ 16199758b77fSLuigi Rizzo logptr = (ipfw_insn_log *)cmd; 16209758b77fSLuigi Rizzo break; 16219758b77fSLuigi Rizzo 1622974dfe30SBrian Feldman case O_ALTQ: /* O_ALTQ is printed after O_LOG */ 1623974dfe30SBrian Feldman altqptr = (ipfw_insn_altq *)cmd; 1624974dfe30SBrian Feldman break; 1625974dfe30SBrian Feldman 16266a7d5cb6SOleg Bulyzhin case O_TAG: 16276a7d5cb6SOleg Bulyzhin tagptr = cmd; 16286a7d5cb6SOleg Bulyzhin break; 16296a7d5cb6SOleg Bulyzhin 1630ff2f6fe8SPaolo Pisati case O_NAT: 1631f94a7fc0SPaolo Pisati PRINT_UINT_ARG("nat ", cmd->arg1); 1632ff2f6fe8SPaolo Pisati break; 1633ff2f6fe8SPaolo Pisati 16348b07e49aSJulian Elischer case O_SETFIB: 16358b07e49aSJulian Elischer PRINT_UINT_ARG("setfib ", cmd->arg1); 16368b07e49aSJulian Elischer break; 16378b07e49aSJulian Elischer 16389758b77fSLuigi Rizzo default: 16399758b77fSLuigi Rizzo printf("** unrecognized action %d len %d ", 16409758b77fSLuigi Rizzo cmd->opcode, cmd->len); 16419758b77fSLuigi Rizzo } 16429758b77fSLuigi Rizzo } 16439758b77fSLuigi Rizzo if (logptr) { 16449758b77fSLuigi Rizzo if (logptr->max_log > 0) 16459758b77fSLuigi Rizzo printf(" log logamount %d", logptr->max_log); 16469758b77fSLuigi Rizzo else 16479758b77fSLuigi Rizzo printf(" log"); 16489758b77fSLuigi Rizzo } 1649974dfe30SBrian Feldman if (altqptr) { 1650974dfe30SBrian Feldman const char *qname; 1651974dfe30SBrian Feldman 1652974dfe30SBrian Feldman qname = altq_qid_to_name(altqptr->qid); 1653974dfe30SBrian Feldman if (qname == NULL) 1654974dfe30SBrian Feldman printf(" altq ?<%u>", altqptr->qid); 1655974dfe30SBrian Feldman else 1656974dfe30SBrian Feldman printf(" altq %s", qname); 1657974dfe30SBrian Feldman } 16586a7d5cb6SOleg Bulyzhin if (tagptr) { 16596a7d5cb6SOleg Bulyzhin if (tagptr->len & F_NOT) 1660254c4725SOleg Bulyzhin PRINT_UINT_ARG(" untag ", tagptr->arg1); 16616a7d5cb6SOleg Bulyzhin else 1662254c4725SOleg Bulyzhin PRINT_UINT_ARG(" tag ", tagptr->arg1); 16636a7d5cb6SOleg Bulyzhin } 1664e706181bSLuigi Rizzo 16659758b77fSLuigi Rizzo /* 1666e706181bSLuigi Rizzo * then print the body. 16679758b77fSLuigi Rizzo */ 166857cd6d26SMax Laier for (l = rule->act_ofs, cmd = rule->cmd ; 166957cd6d26SMax Laier l > 0 ; l -= F_LEN(cmd) , cmd += F_LEN(cmd)) { 167057cd6d26SMax Laier if ((cmd->len & F_OR) || (cmd->len & F_NOT)) 167157cd6d26SMax Laier continue; 167257cd6d26SMax Laier if (cmd->opcode == O_IP4) { 167357cd6d26SMax Laier flags |= HAVE_PROTO4; 167457cd6d26SMax Laier break; 167557cd6d26SMax Laier } else if (cmd->opcode == O_IP6) { 167657cd6d26SMax Laier flags |= HAVE_PROTO6; 167757cd6d26SMax Laier break; 167857cd6d26SMax Laier } 167957cd6d26SMax Laier } 1680e706181bSLuigi Rizzo if (rule->_pad & 1) { /* empty rules before options */ 168157cd6d26SMax Laier if (!do_compact) { 168257cd6d26SMax Laier show_prerequisites(&flags, HAVE_PROTO, 0); 168357cd6d26SMax Laier printf(" from any to any"); 168457cd6d26SMax Laier } 1685e706181bSLuigi Rizzo flags |= HAVE_IP | HAVE_OPTIONS; 1686e706181bSLuigi Rizzo } 1687e706181bSLuigi Rizzo 1688ac6cec51SLuigi Rizzo if (comment_only) 1689ac6cec51SLuigi Rizzo comment = "..."; 1690ac6cec51SLuigi Rizzo 16919758b77fSLuigi Rizzo for (l = rule->act_ofs, cmd = rule->cmd ; 16929758b77fSLuigi Rizzo l > 0 ; l -= F_LEN(cmd) , cmd += F_LEN(cmd)) { 16935e43aef8SLuigi Rizzo /* useful alias */ 16945e43aef8SLuigi Rizzo ipfw_insn_u32 *cmd32 = (ipfw_insn_u32 *)cmd; 16959758b77fSLuigi Rizzo 1696ac6cec51SLuigi Rizzo if (comment_only) { 1697ac6cec51SLuigi Rizzo if (cmd->opcode != O_NOP) 1698ac6cec51SLuigi Rizzo continue; 1699ac6cec51SLuigi Rizzo printf(" // %s\n", (char *)(cmd + 1)); 1700ac6cec51SLuigi Rizzo return; 1701ac6cec51SLuigi Rizzo } 1702ac6cec51SLuigi Rizzo 1703e706181bSLuigi Rizzo show_prerequisites(&flags, 0, cmd->opcode); 1704e706181bSLuigi Rizzo 17059758b77fSLuigi Rizzo switch(cmd->opcode) { 170612b5dc6aSLuigi Rizzo case O_PROB: 170712b5dc6aSLuigi Rizzo break; /* done already */ 170812b5dc6aSLuigi Rizzo 17099758b77fSLuigi Rizzo case O_PROBE_STATE: 17109758b77fSLuigi Rizzo break; /* no need to print anything here */ 17119758b77fSLuigi Rizzo 17129758b77fSLuigi Rizzo case O_IP_SRC: 1713cd8b5ae0SRuslan Ermilov case O_IP_SRC_LOOKUP: 17149758b77fSLuigi Rizzo case O_IP_SRC_MASK: 17159758b77fSLuigi Rizzo case O_IP_SRC_ME: 17169758b77fSLuigi Rizzo case O_IP_SRC_SET: 1717e706181bSLuigi Rizzo show_prerequisites(&flags, HAVE_PROTO, 0); 17189758b77fSLuigi Rizzo if (!(flags & HAVE_SRCIP)) 17199758b77fSLuigi Rizzo printf(" from"); 17209758b77fSLuigi Rizzo if ((cmd->len & F_OR) && !or_block) 17219758b77fSLuigi Rizzo printf(" {"); 1722e706181bSLuigi Rizzo print_ip((ipfw_insn_ip *)cmd, 1723e706181bSLuigi Rizzo (flags & HAVE_OPTIONS) ? " src-ip" : ""); 17249758b77fSLuigi Rizzo flags |= HAVE_SRCIP; 17259758b77fSLuigi Rizzo break; 17269758b77fSLuigi Rizzo 17279758b77fSLuigi Rizzo case O_IP_DST: 1728cd8b5ae0SRuslan Ermilov case O_IP_DST_LOOKUP: 17299758b77fSLuigi Rizzo case O_IP_DST_MASK: 17309758b77fSLuigi Rizzo case O_IP_DST_ME: 17319758b77fSLuigi Rizzo case O_IP_DST_SET: 1732e706181bSLuigi Rizzo show_prerequisites(&flags, HAVE_PROTO|HAVE_SRCIP, 0); 17339758b77fSLuigi Rizzo if (!(flags & HAVE_DSTIP)) 17349758b77fSLuigi Rizzo printf(" to"); 17359758b77fSLuigi Rizzo if ((cmd->len & F_OR) && !or_block) 17369758b77fSLuigi Rizzo printf(" {"); 1737e706181bSLuigi Rizzo print_ip((ipfw_insn_ip *)cmd, 1738e706181bSLuigi Rizzo (flags & HAVE_OPTIONS) ? " dst-ip" : ""); 17399758b77fSLuigi Rizzo flags |= HAVE_DSTIP; 17409758b77fSLuigi Rizzo break; 17419758b77fSLuigi Rizzo 17428195404bSBrooks Davis case O_IP6_SRC: 17438195404bSBrooks Davis case O_IP6_SRC_MASK: 17448195404bSBrooks Davis case O_IP6_SRC_ME: 1745b730879fSMax Laier show_prerequisites(&flags, HAVE_PROTO, 0); 17468195404bSBrooks Davis if (!(flags & HAVE_SRCIP)) 17478195404bSBrooks Davis printf(" from"); 17488195404bSBrooks Davis if ((cmd->len & F_OR) && !or_block) 17498195404bSBrooks Davis printf(" {"); 17508195404bSBrooks Davis print_ip6((ipfw_insn_ip6 *)cmd, 17518195404bSBrooks Davis (flags & HAVE_OPTIONS) ? " src-ip6" : ""); 17528195404bSBrooks Davis flags |= HAVE_SRCIP | HAVE_PROTO; 17538195404bSBrooks Davis break; 17548195404bSBrooks Davis 17558195404bSBrooks Davis case O_IP6_DST: 17568195404bSBrooks Davis case O_IP6_DST_MASK: 17578195404bSBrooks Davis case O_IP6_DST_ME: 17588195404bSBrooks Davis show_prerequisites(&flags, HAVE_PROTO|HAVE_SRCIP, 0); 17598195404bSBrooks Davis if (!(flags & HAVE_DSTIP)) 17608195404bSBrooks Davis printf(" to"); 17618195404bSBrooks Davis if ((cmd->len & F_OR) && !or_block) 17628195404bSBrooks Davis printf(" {"); 17638195404bSBrooks Davis print_ip6((ipfw_insn_ip6 *)cmd, 17648195404bSBrooks Davis (flags & HAVE_OPTIONS) ? " dst-ip6" : ""); 17658195404bSBrooks Davis flags |= HAVE_DSTIP; 17668195404bSBrooks Davis break; 17678195404bSBrooks Davis 17688195404bSBrooks Davis case O_FLOW6ID: 17698195404bSBrooks Davis print_flow6id( (ipfw_insn_u32 *) cmd ); 17708195404bSBrooks Davis flags |= HAVE_OPTIONS; 17718195404bSBrooks Davis break; 17728195404bSBrooks Davis 17739758b77fSLuigi Rizzo case O_IP_DSTPORT: 1774e706181bSLuigi Rizzo show_prerequisites(&flags, HAVE_IP, 0); 17759758b77fSLuigi Rizzo case O_IP_SRCPORT: 1776e706181bSLuigi Rizzo show_prerequisites(&flags, HAVE_PROTO|HAVE_SRCIP, 0); 17778ed2d749SLuigi Rizzo if ((cmd->len & F_OR) && !or_block) 17788ed2d749SLuigi Rizzo printf(" {"); 1779087aa087SMaxim Konovalov if (cmd->len & F_NOT) 1780087aa087SMaxim Konovalov printf(" not"); 1781e706181bSLuigi Rizzo print_newports((ipfw_insn_u16 *)cmd, proto, 1782e706181bSLuigi Rizzo (flags & HAVE_OPTIONS) ? cmd->opcode : 0); 17839758b77fSLuigi Rizzo break; 17849758b77fSLuigi Rizzo 17859758b77fSLuigi Rizzo case O_PROTO: { 17868195404bSBrooks Davis struct protoent *pe = NULL; 17879758b77fSLuigi Rizzo 17889758b77fSLuigi Rizzo if ((cmd->len & F_OR) && !or_block) 17899758b77fSLuigi Rizzo printf(" {"); 17909758b77fSLuigi Rizzo if (cmd->len & F_NOT) 17919758b77fSLuigi Rizzo printf(" not"); 17929758b77fSLuigi Rizzo proto = cmd->arg1; 1793d360073bSBrooks Davis pe = getprotobynumber(cmd->arg1); 179457cd6d26SMax Laier if ((flags & (HAVE_PROTO4 | HAVE_PROTO6)) && 179557cd6d26SMax Laier !(flags & HAVE_PROTO)) 179657cd6d26SMax Laier show_prerequisites(&flags, 179757cd6d26SMax Laier HAVE_IP | HAVE_OPTIONS, 0); 1798e706181bSLuigi Rizzo if (flags & HAVE_OPTIONS) 1799e706181bSLuigi Rizzo printf(" proto"); 18009758b77fSLuigi Rizzo if (pe) 18019758b77fSLuigi Rizzo printf(" %s", pe->p_name); 18029758b77fSLuigi Rizzo else 18039758b77fSLuigi Rizzo printf(" %u", cmd->arg1); 18049758b77fSLuigi Rizzo } 18059758b77fSLuigi Rizzo flags |= HAVE_PROTO; 18069758b77fSLuigi Rizzo break; 18079758b77fSLuigi Rizzo 18089758b77fSLuigi Rizzo default: /*options ... */ 180957cd6d26SMax Laier if (!(cmd->len & (F_OR|F_NOT))) 181057cd6d26SMax Laier if (((cmd->opcode == O_IP6) && 181157cd6d26SMax Laier (flags & HAVE_PROTO6)) || 181257cd6d26SMax Laier ((cmd->opcode == O_IP4) && 181357cd6d26SMax Laier (flags & HAVE_PROTO4))) 181457cd6d26SMax Laier break; 1815e706181bSLuigi Rizzo show_prerequisites(&flags, HAVE_IP | HAVE_OPTIONS, 0); 18169758b77fSLuigi Rizzo if ((cmd->len & F_OR) && !or_block) 18179758b77fSLuigi Rizzo printf(" {"); 18189758b77fSLuigi Rizzo if (cmd->len & F_NOT && cmd->opcode != O_IN) 18199758b77fSLuigi Rizzo printf(" not"); 18209758b77fSLuigi Rizzo switch(cmd->opcode) { 18215b41efddSMaxim Konovalov case O_MACADDR2: { 18225b41efddSMaxim Konovalov ipfw_insn_mac *m = (ipfw_insn_mac *)cmd; 18235b41efddSMaxim Konovalov 18245b41efddSMaxim Konovalov printf(" MAC"); 18255b41efddSMaxim Konovalov print_mac(m->addr, m->mask); 18265b41efddSMaxim Konovalov print_mac(m->addr + 6, m->mask + 6); 18275b41efddSMaxim Konovalov } 18285b41efddSMaxim Konovalov break; 18295b41efddSMaxim Konovalov 18305b41efddSMaxim Konovalov case O_MAC_TYPE: 18315b41efddSMaxim Konovalov print_newports((ipfw_insn_u16 *)cmd, 18325b41efddSMaxim Konovalov IPPROTO_ETHERTYPE, cmd->opcode); 18335b41efddSMaxim Konovalov break; 18345b41efddSMaxim Konovalov 18355b41efddSMaxim Konovalov 18369758b77fSLuigi Rizzo case O_FRAG: 18379758b77fSLuigi Rizzo printf(" frag"); 18389758b77fSLuigi Rizzo break; 18399758b77fSLuigi Rizzo 18408b07e49aSJulian Elischer case O_FIB: 18418b07e49aSJulian Elischer printf(" fib %u", cmd->arg1 ); 18428b07e49aSJulian Elischer break; 18438b07e49aSJulian Elischer 18449758b77fSLuigi Rizzo case O_IN: 18459758b77fSLuigi Rizzo printf(cmd->len & F_NOT ? " out" : " in"); 18469758b77fSLuigi Rizzo break; 18479758b77fSLuigi Rizzo 18486daf7ebdSBrian Feldman case O_DIVERTED: 18496daf7ebdSBrian Feldman switch (cmd->arg1) { 18506daf7ebdSBrian Feldman case 3: 18516daf7ebdSBrian Feldman printf(" diverted"); 18526daf7ebdSBrian Feldman break; 18536daf7ebdSBrian Feldman case 1: 18546daf7ebdSBrian Feldman printf(" diverted-loopback"); 18556daf7ebdSBrian Feldman break; 18566daf7ebdSBrian Feldman case 2: 18576daf7ebdSBrian Feldman printf(" diverted-output"); 18586daf7ebdSBrian Feldman break; 18596daf7ebdSBrian Feldman default: 18606daf7ebdSBrian Feldman printf(" diverted-?<%u>", cmd->arg1); 18616daf7ebdSBrian Feldman break; 18626daf7ebdSBrian Feldman } 18636daf7ebdSBrian Feldman break; 18646daf7ebdSBrian Feldman 18659758b77fSLuigi Rizzo case O_LAYER2: 18669758b77fSLuigi Rizzo printf(" layer2"); 18679758b77fSLuigi Rizzo break; 18689758b77fSLuigi Rizzo case O_XMIT: 18699758b77fSLuigi Rizzo case O_RECV: 1870bd528823SGleb Smirnoff case O_VIA: 1871bd528823SGleb Smirnoff { 187262ff38aeSLuigi Rizzo char const *s; 18739758b77fSLuigi Rizzo ipfw_insn_if *cmdif = (ipfw_insn_if *)cmd; 18749758b77fSLuigi Rizzo 18759758b77fSLuigi Rizzo if (cmd->opcode == O_XMIT) 18769758b77fSLuigi Rizzo s = "xmit"; 18779758b77fSLuigi Rizzo else if (cmd->opcode == O_RECV) 18789758b77fSLuigi Rizzo s = "recv"; 187962ff38aeSLuigi Rizzo else /* if (cmd->opcode == O_VIA) */ 18809758b77fSLuigi Rizzo s = "via"; 18819758b77fSLuigi Rizzo if (cmdif->name[0] == '\0') 18825e43aef8SLuigi Rizzo printf(" %s %s", s, 18835e43aef8SLuigi Rizzo inet_ntoa(cmdif->p.ip)); 1884bd528823SGleb Smirnoff else 18859bf40edeSBrooks Davis printf(" %s %s", s, cmdif->name); 18869758b77fSLuigi Rizzo 1887bd528823SGleb Smirnoff break; 1888bd528823SGleb Smirnoff } 18899758b77fSLuigi Rizzo case O_IPID: 189044c884e1SLuigi Rizzo if (F_LEN(cmd) == 1) 18919758b77fSLuigi Rizzo printf(" ipid %u", cmd->arg1 ); 189244c884e1SLuigi Rizzo else 189344c884e1SLuigi Rizzo print_newports((ipfw_insn_u16 *)cmd, 0, 189444c884e1SLuigi Rizzo O_IPID); 18959758b77fSLuigi Rizzo break; 18969758b77fSLuigi Rizzo 18979758b77fSLuigi Rizzo case O_IPTTL: 189844c884e1SLuigi Rizzo if (F_LEN(cmd) == 1) 18999758b77fSLuigi Rizzo printf(" ipttl %u", cmd->arg1 ); 190044c884e1SLuigi Rizzo else 190144c884e1SLuigi Rizzo print_newports((ipfw_insn_u16 *)cmd, 0, 190244c884e1SLuigi Rizzo O_IPTTL); 19039758b77fSLuigi Rizzo break; 19049758b77fSLuigi Rizzo 19059758b77fSLuigi Rizzo case O_IPVER: 19069758b77fSLuigi Rizzo printf(" ipver %u", cmd->arg1 ); 19079758b77fSLuigi Rizzo break; 19089758b77fSLuigi Rizzo 19095e43aef8SLuigi Rizzo case O_IPPRECEDENCE: 19105e43aef8SLuigi Rizzo printf(" ipprecedence %u", (cmd->arg1) >> 5 ); 19115e43aef8SLuigi Rizzo break; 19125e43aef8SLuigi Rizzo 19139758b77fSLuigi Rizzo case O_IPLEN: 191444c884e1SLuigi Rizzo if (F_LEN(cmd) == 1) 19159758b77fSLuigi Rizzo printf(" iplen %u", cmd->arg1 ); 191644c884e1SLuigi Rizzo else 191744c884e1SLuigi Rizzo print_newports((ipfw_insn_u16 *)cmd, 0, 191844c884e1SLuigi Rizzo O_IPLEN); 19199758b77fSLuigi Rizzo break; 19209758b77fSLuigi Rizzo 192152bc23abSLuigi Rizzo case O_IPOPT: 19229758b77fSLuigi Rizzo print_flags("ipoptions", cmd, f_ipopts); 19239758b77fSLuigi Rizzo break; 19249758b77fSLuigi Rizzo 19255e43aef8SLuigi Rizzo case O_IPTOS: 19265e43aef8SLuigi Rizzo print_flags("iptos", cmd, f_iptos); 19275e43aef8SLuigi Rizzo break; 19285e43aef8SLuigi Rizzo 19295e43aef8SLuigi Rizzo case O_ICMPTYPE: 19305e43aef8SLuigi Rizzo print_icmptypes((ipfw_insn_u32 *)cmd); 19315e43aef8SLuigi Rizzo break; 19325e43aef8SLuigi Rizzo 19339758b77fSLuigi Rizzo case O_ESTAB: 19349758b77fSLuigi Rizzo printf(" established"); 19359758b77fSLuigi Rizzo break; 19369758b77fSLuigi Rizzo 1937c99ee9e0SBrian Feldman case O_TCPDATALEN: 1938c99ee9e0SBrian Feldman if (F_LEN(cmd) == 1) 1939c99ee9e0SBrian Feldman printf(" tcpdatalen %u", cmd->arg1 ); 1940c99ee9e0SBrian Feldman else 1941c99ee9e0SBrian Feldman print_newports((ipfw_insn_u16 *)cmd, 0, 1942c99ee9e0SBrian Feldman O_TCPDATALEN); 1943c99ee9e0SBrian Feldman break; 1944c99ee9e0SBrian Feldman 19459758b77fSLuigi Rizzo case O_TCPFLAGS: 19469758b77fSLuigi Rizzo print_flags("tcpflags", cmd, f_tcpflags); 19479758b77fSLuigi Rizzo break; 19489758b77fSLuigi Rizzo 19499758b77fSLuigi Rizzo case O_TCPOPTS: 19509758b77fSLuigi Rizzo print_flags("tcpoptions", cmd, f_tcpopts); 19519758b77fSLuigi Rizzo break; 19529758b77fSLuigi Rizzo 19539758b77fSLuigi Rizzo case O_TCPWIN: 19549758b77fSLuigi Rizzo printf(" tcpwin %d", ntohs(cmd->arg1)); 19559758b77fSLuigi Rizzo break; 19569758b77fSLuigi Rizzo 19579758b77fSLuigi Rizzo case O_TCPACK: 19589758b77fSLuigi Rizzo printf(" tcpack %d", ntohl(cmd32->d[0])); 19599758b77fSLuigi Rizzo break; 19609758b77fSLuigi Rizzo 19619758b77fSLuigi Rizzo case O_TCPSEQ: 19629758b77fSLuigi Rizzo printf(" tcpseq %d", ntohl(cmd32->d[0])); 19639758b77fSLuigi Rizzo break; 19649758b77fSLuigi Rizzo 19659758b77fSLuigi Rizzo case O_UID: 19669758b77fSLuigi Rizzo { 19679758b77fSLuigi Rizzo struct passwd *pwd = getpwuid(cmd32->d[0]); 19689758b77fSLuigi Rizzo 19699758b77fSLuigi Rizzo if (pwd) 19709758b77fSLuigi Rizzo printf(" uid %s", pwd->pw_name); 19719758b77fSLuigi Rizzo else 19729758b77fSLuigi Rizzo printf(" uid %u", cmd32->d[0]); 19739758b77fSLuigi Rizzo } 19749758b77fSLuigi Rizzo break; 19759758b77fSLuigi Rizzo 19769758b77fSLuigi Rizzo case O_GID: 19779758b77fSLuigi Rizzo { 19789758b77fSLuigi Rizzo struct group *grp = getgrgid(cmd32->d[0]); 19799758b77fSLuigi Rizzo 19809758b77fSLuigi Rizzo if (grp) 19819758b77fSLuigi Rizzo printf(" gid %s", grp->gr_name); 19829758b77fSLuigi Rizzo else 19839758b77fSLuigi Rizzo printf(" gid %u", cmd32->d[0]); 19849758b77fSLuigi Rizzo } 19859758b77fSLuigi Rizzo break; 19869758b77fSLuigi Rizzo 198731c88a30SChristian S.J. Peron case O_JAIL: 198831c88a30SChristian S.J. Peron printf(" jail %d", cmd32->d[0]); 198931c88a30SChristian S.J. Peron break; 199031c88a30SChristian S.J. Peron 1991010dabb0SCrist J. Clark case O_VERREVPATH: 1992010dabb0SCrist J. Clark printf(" verrevpath"); 1993010dabb0SCrist J. Clark break; 1994010dabb0SCrist J. Clark 199522b5770bSAndre Oppermann case O_VERSRCREACH: 199622b5770bSAndre Oppermann printf(" versrcreach"); 199722b5770bSAndre Oppermann break; 199822b5770bSAndre Oppermann 19995f9541ecSAndre Oppermann case O_ANTISPOOF: 20005f9541ecSAndre Oppermann printf(" antispoof"); 20015f9541ecSAndre Oppermann break; 20025f9541ecSAndre Oppermann 2003c3e5b9f1SLuigi Rizzo case O_IPSEC: 2004c3e5b9f1SLuigi Rizzo printf(" ipsec"); 2005c3e5b9f1SLuigi Rizzo break; 2006c3e5b9f1SLuigi Rizzo 200762ff38aeSLuigi Rizzo case O_NOP: 2008bbc39c83SLuigi Rizzo comment = (char *)(cmd + 1); 200962ff38aeSLuigi Rizzo break; 201062ff38aeSLuigi Rizzo 20119758b77fSLuigi Rizzo case O_KEEP_STATE: 20129758b77fSLuigi Rizzo printf(" keep-state"); 20139758b77fSLuigi Rizzo break; 20149758b77fSLuigi Rizzo 2015254c4725SOleg Bulyzhin case O_LIMIT: { 20169758b77fSLuigi Rizzo struct _s_x *p = limit_masks; 20179758b77fSLuigi Rizzo ipfw_insn_limit *c = (ipfw_insn_limit *)cmd; 2018571f8c1bSLuigi Rizzo uint8_t x = c->limit_mask; 201962ff38aeSLuigi Rizzo char const *comma = " "; 20209758b77fSLuigi Rizzo 20219758b77fSLuigi Rizzo printf(" limit"); 20229758b77fSLuigi Rizzo for (; p->x != 0 ; p++) 20230a7197a8SLuigi Rizzo if ((x & p->x) == p->x) { 20249758b77fSLuigi Rizzo x &= ~p->x; 20259758b77fSLuigi Rizzo printf("%s%s", comma, p->s); 20269758b77fSLuigi Rizzo comma = ","; 20279758b77fSLuigi Rizzo } 2028254c4725SOleg Bulyzhin PRINT_UINT_ARG(" ", c->conn_limit); 20299758b77fSLuigi Rizzo break; 2030254c4725SOleg Bulyzhin } 20319758b77fSLuigi Rizzo 20328195404bSBrooks Davis case O_IP6: 203336c263ccSHajimu UMEMOTO printf(" ip6"); 20348195404bSBrooks Davis break; 20358195404bSBrooks Davis 203657cd6d26SMax Laier case O_IP4: 203736c263ccSHajimu UMEMOTO printf(" ip4"); 203857cd6d26SMax Laier break; 203957cd6d26SMax Laier 20408195404bSBrooks Davis case O_ICMP6TYPE: 20418195404bSBrooks Davis print_icmp6types((ipfw_insn_u32 *)cmd); 20428195404bSBrooks Davis break; 20438195404bSBrooks Davis 20448195404bSBrooks Davis case O_EXT_HDR: 20458195404bSBrooks Davis print_ext6hdr( (ipfw_insn *) cmd ); 20468195404bSBrooks Davis break; 20478195404bSBrooks Davis 20486a7d5cb6SOleg Bulyzhin case O_TAGGED: 20496a7d5cb6SOleg Bulyzhin if (F_LEN(cmd) == 1) 2050254c4725SOleg Bulyzhin PRINT_UINT_ARG(" tagged ", cmd->arg1); 20516a7d5cb6SOleg Bulyzhin else 20526a7d5cb6SOleg Bulyzhin print_newports((ipfw_insn_u16 *)cmd, 0, 20536a7d5cb6SOleg Bulyzhin O_TAGGED); 20546a7d5cb6SOleg Bulyzhin break; 20556a7d5cb6SOleg Bulyzhin 20569758b77fSLuigi Rizzo default: 20579758b77fSLuigi Rizzo printf(" [opcode %d len %d]", 20589758b77fSLuigi Rizzo cmd->opcode, cmd->len); 20599758b77fSLuigi Rizzo } 20609758b77fSLuigi Rizzo } 20619758b77fSLuigi Rizzo if (cmd->len & F_OR) { 20629758b77fSLuigi Rizzo printf(" or"); 20639758b77fSLuigi Rizzo or_block = 1; 20649758b77fSLuigi Rizzo } else if (or_block) { 20659758b77fSLuigi Rizzo printf(" }"); 20669758b77fSLuigi Rizzo or_block = 0; 20679758b77fSLuigi Rizzo } 20689758b77fSLuigi Rizzo } 2069e706181bSLuigi Rizzo show_prerequisites(&flags, HAVE_IP, 0); 2070bbc39c83SLuigi Rizzo if (comment) 2071bbc39c83SLuigi Rizzo printf(" // %s", comment); 20729758b77fSLuigi Rizzo printf("\n"); 20739758b77fSLuigi Rizzo } 20749758b77fSLuigi Rizzo 20759758b77fSLuigi Rizzo static void 207645f61351SMaxim Konovalov show_dyn_ipfw(ipfw_dyn_rule *d, int pcwidth, int bcwidth) 20779758b77fSLuigi Rizzo { 20789758b77fSLuigi Rizzo struct protoent *pe; 20799758b77fSLuigi Rizzo struct in_addr a; 2080330462a3SBernd Walter uint16_t rulenum; 208181bd0dc0SMax Laier char buf[INET6_ADDRSTRLEN]; 20829758b77fSLuigi Rizzo 20839758b77fSLuigi Rizzo if (!do_expired) { 20849758b77fSLuigi Rizzo if (!d->expire && !(d->dyn_type == O_LIMIT_PARENT)) 20859758b77fSLuigi Rizzo return; 20869758b77fSLuigi Rizzo } 2087330462a3SBernd Walter bcopy(&d->rule, &rulenum, sizeof(rulenum)); 2088571f8c1bSLuigi Rizzo printf("%05d", rulenum); 208962ff38aeSLuigi Rizzo if (pcwidth>0 || bcwidth>0) 2090571f8c1bSLuigi Rizzo printf(" %*llu %*llu (%ds)", pcwidth, 2091330462a3SBernd Walter align_uint64(&d->pcnt), bcwidth, 2092330462a3SBernd Walter align_uint64(&d->bcnt), d->expire); 20939758b77fSLuigi Rizzo switch (d->dyn_type) { 20949758b77fSLuigi Rizzo case O_LIMIT_PARENT: 20959758b77fSLuigi Rizzo printf(" PARENT %d", d->count); 20969758b77fSLuigi Rizzo break; 20979758b77fSLuigi Rizzo case O_LIMIT: 20989758b77fSLuigi Rizzo printf(" LIMIT"); 20999758b77fSLuigi Rizzo break; 21009758b77fSLuigi Rizzo case O_KEEP_STATE: /* bidir, no mask */ 21019758b77fSLuigi Rizzo printf(" STATE"); 21029758b77fSLuigi Rizzo break; 21039758b77fSLuigi Rizzo } 21049758b77fSLuigi Rizzo 21059758b77fSLuigi Rizzo if ((pe = getprotobynumber(d->id.proto)) != NULL) 21069758b77fSLuigi Rizzo printf(" %s", pe->p_name); 21079758b77fSLuigi Rizzo else 21089758b77fSLuigi Rizzo printf(" proto %u", d->id.proto); 21099758b77fSLuigi Rizzo 211081bd0dc0SMax Laier if (d->id.addr_type == 4) { 21119758b77fSLuigi Rizzo a.s_addr = htonl(d->id.src_ip); 21129758b77fSLuigi Rizzo printf(" %s %d", inet_ntoa(a), d->id.src_port); 21139758b77fSLuigi Rizzo 21149758b77fSLuigi Rizzo a.s_addr = htonl(d->id.dst_ip); 21159758b77fSLuigi Rizzo printf(" <-> %s %d", inet_ntoa(a), d->id.dst_port); 211681bd0dc0SMax Laier } else if (d->id.addr_type == 6) { 211781bd0dc0SMax Laier printf(" %s %d", inet_ntop(AF_INET6, &d->id.src_ip6, buf, 211881bd0dc0SMax Laier sizeof(buf)), d->id.src_port); 211981bd0dc0SMax Laier printf(" <-> %s %d", inet_ntop(AF_INET6, &d->id.dst_ip6, buf, 212081bd0dc0SMax Laier sizeof(buf)), d->id.dst_port); 212181bd0dc0SMax Laier } else 212281bd0dc0SMax Laier printf(" UNKNOWN <-> UNKNOWN\n"); 212381bd0dc0SMax Laier 21249758b77fSLuigi Rizzo printf("\n"); 21259758b77fSLuigi Rizzo } 21269758b77fSLuigi Rizzo 212762ff38aeSLuigi Rizzo static int 21289758b77fSLuigi Rizzo sort_q(const void *pa, const void *pb) 21299758b77fSLuigi Rizzo { 21309758b77fSLuigi Rizzo int rev = (do_sort < 0); 21319758b77fSLuigi Rizzo int field = rev ? -do_sort : do_sort; 21329758b77fSLuigi Rizzo long long res = 0; 21339758b77fSLuigi Rizzo const struct dn_flow_queue *a = pa; 21349758b77fSLuigi Rizzo const struct dn_flow_queue *b = pb; 21359758b77fSLuigi Rizzo 21369758b77fSLuigi Rizzo switch (field) { 21379758b77fSLuigi Rizzo case 1: /* pkts */ 21389758b77fSLuigi Rizzo res = a->len - b->len; 21399758b77fSLuigi Rizzo break; 21409758b77fSLuigi Rizzo case 2: /* bytes */ 21419758b77fSLuigi Rizzo res = a->len_bytes - b->len_bytes; 21429758b77fSLuigi Rizzo break; 21439758b77fSLuigi Rizzo 21449758b77fSLuigi Rizzo case 3: /* tot pkts */ 21459758b77fSLuigi Rizzo res = a->tot_pkts - b->tot_pkts; 21469758b77fSLuigi Rizzo break; 21479758b77fSLuigi Rizzo 21489758b77fSLuigi Rizzo case 4: /* tot bytes */ 21499758b77fSLuigi Rizzo res = a->tot_bytes - b->tot_bytes; 21509758b77fSLuigi Rizzo break; 21519758b77fSLuigi Rizzo } 21529758b77fSLuigi Rizzo if (res < 0) 21539758b77fSLuigi Rizzo res = -1; 21549758b77fSLuigi Rizzo if (res > 0) 21559758b77fSLuigi Rizzo res = 1; 21569758b77fSLuigi Rizzo return (int)(rev ? res : -res); 21579758b77fSLuigi Rizzo } 21589758b77fSLuigi Rizzo 21599758b77fSLuigi Rizzo static void 21609758b77fSLuigi Rizzo list_queues(struct dn_flow_set *fs, struct dn_flow_queue *q) 21619758b77fSLuigi Rizzo { 21629758b77fSLuigi Rizzo int l; 21638195404bSBrooks Davis int index_printed, indexes = 0; 21648195404bSBrooks Davis char buff[255]; 21658195404bSBrooks Davis struct protoent *pe; 21669758b77fSLuigi Rizzo 21679758b77fSLuigi Rizzo if (fs->rq_elements == 0) 21689758b77fSLuigi Rizzo return; 21699758b77fSLuigi Rizzo 21709758b77fSLuigi Rizzo if (do_sort != 0) 21719758b77fSLuigi Rizzo heapsort(q, fs->rq_elements, sizeof *q, sort_q); 21728195404bSBrooks Davis 21738195404bSBrooks Davis /* Print IPv4 flows */ 21748195404bSBrooks Davis index_printed = 0; 21759758b77fSLuigi Rizzo for (l = 0; l < fs->rq_elements; l++) { 21769758b77fSLuigi Rizzo struct in_addr ina; 21779758b77fSLuigi Rizzo 21788195404bSBrooks Davis /* XXX: Should check for IPv4 flows */ 21798195404bSBrooks Davis if (IS_IP6_FLOW_ID(&(q[l].id))) 21808195404bSBrooks Davis continue; 21818195404bSBrooks Davis 21828195404bSBrooks Davis if (!index_printed) { 21838195404bSBrooks Davis index_printed = 1; 21848195404bSBrooks Davis if (indexes > 0) /* currently a no-op */ 21858195404bSBrooks Davis printf("\n"); 21868195404bSBrooks Davis indexes++; 21878195404bSBrooks Davis printf(" " 21888195404bSBrooks Davis "mask: 0x%02x 0x%08x/0x%04x -> 0x%08x/0x%04x\n", 21898195404bSBrooks Davis fs->flow_mask.proto, 21908195404bSBrooks Davis fs->flow_mask.src_ip, fs->flow_mask.src_port, 21918195404bSBrooks Davis fs->flow_mask.dst_ip, fs->flow_mask.dst_port); 21928195404bSBrooks Davis 21938195404bSBrooks Davis printf("BKT Prot ___Source IP/port____ " 21948195404bSBrooks Davis "____Dest. IP/port____ " 21958195404bSBrooks Davis "Tot_pkt/bytes Pkt/Byte Drp\n"); 21968195404bSBrooks Davis } 21978195404bSBrooks Davis 21989758b77fSLuigi Rizzo printf("%3d ", q[l].hash_slot); 21999758b77fSLuigi Rizzo pe = getprotobynumber(q[l].id.proto); 22009758b77fSLuigi Rizzo if (pe) 22019758b77fSLuigi Rizzo printf("%-4s ", pe->p_name); 22029758b77fSLuigi Rizzo else 22039758b77fSLuigi Rizzo printf("%4u ", q[l].id.proto); 22048195404bSBrooks Davis ina.s_addr = htonl(q[l].id.src_ip); 22059758b77fSLuigi Rizzo printf("%15s/%-5d ", 22069758b77fSLuigi Rizzo inet_ntoa(ina), q[l].id.src_port); 22079758b77fSLuigi Rizzo ina.s_addr = htonl(q[l].id.dst_ip); 22089758b77fSLuigi Rizzo printf("%15s/%-5d ", 22099758b77fSLuigi Rizzo inet_ntoa(ina), q[l].id.dst_port); 22109758b77fSLuigi Rizzo printf("%4qu %8qu %2u %4u %3u\n", 22119758b77fSLuigi Rizzo q[l].tot_pkts, q[l].tot_bytes, 22129758b77fSLuigi Rizzo q[l].len, q[l].len_bytes, q[l].drops); 22139758b77fSLuigi Rizzo if (verbose) 22149758b77fSLuigi Rizzo printf(" S %20qd F %20qd\n", 22159758b77fSLuigi Rizzo q[l].S, q[l].F); 22169758b77fSLuigi Rizzo } 22178195404bSBrooks Davis 22188195404bSBrooks Davis /* Print IPv6 flows */ 22198195404bSBrooks Davis index_printed = 0; 22208195404bSBrooks Davis for (l = 0; l < fs->rq_elements; l++) { 22218195404bSBrooks Davis if (!IS_IP6_FLOW_ID(&(q[l].id))) 22228195404bSBrooks Davis continue; 22238195404bSBrooks Davis 22248195404bSBrooks Davis if (!index_printed) { 22258195404bSBrooks Davis index_printed = 1; 22268195404bSBrooks Davis if (indexes > 0) 22278195404bSBrooks Davis printf("\n"); 22288195404bSBrooks Davis indexes++; 22298195404bSBrooks Davis printf("\n mask: proto: 0x%02x, flow_id: 0x%08x, ", 22308195404bSBrooks Davis fs->flow_mask.proto, fs->flow_mask.flow_id6); 22318195404bSBrooks Davis inet_ntop(AF_INET6, &(fs->flow_mask.src_ip6), 22328195404bSBrooks Davis buff, sizeof(buff)); 22338195404bSBrooks Davis printf("%s/0x%04x -> ", buff, fs->flow_mask.src_port); 22348195404bSBrooks Davis inet_ntop( AF_INET6, &(fs->flow_mask.dst_ip6), 22358195404bSBrooks Davis buff, sizeof(buff) ); 22368195404bSBrooks Davis printf("%s/0x%04x\n", buff, fs->flow_mask.dst_port); 22378195404bSBrooks Davis 22388195404bSBrooks Davis printf("BKT ___Prot___ _flow-id_ " 22398195404bSBrooks Davis "______________Source IPv6/port_______________ " 22408195404bSBrooks Davis "_______________Dest. IPv6/port_______________ " 22418195404bSBrooks Davis "Tot_pkt/bytes Pkt/Byte Drp\n"); 22428195404bSBrooks Davis } 22438195404bSBrooks Davis printf("%3d ", q[l].hash_slot); 22448195404bSBrooks Davis pe = getprotobynumber(q[l].id.proto); 22458195404bSBrooks Davis if (pe != NULL) 22468195404bSBrooks Davis printf("%9s ", pe->p_name); 22478195404bSBrooks Davis else 22488195404bSBrooks Davis printf("%9u ", q[l].id.proto); 22498195404bSBrooks Davis printf("%7d %39s/%-5d ", q[l].id.flow_id6, 22508195404bSBrooks Davis inet_ntop(AF_INET6, &(q[l].id.src_ip6), buff, sizeof(buff)), 22518195404bSBrooks Davis q[l].id.src_port); 22528195404bSBrooks Davis printf(" %39s/%-5d ", 22538195404bSBrooks Davis inet_ntop(AF_INET6, &(q[l].id.dst_ip6), buff, sizeof(buff)), 22548195404bSBrooks Davis q[l].id.dst_port); 22558195404bSBrooks Davis printf(" %4qu %8qu %2u %4u %3u\n", 22568195404bSBrooks Davis q[l].tot_pkts, q[l].tot_bytes, 22578195404bSBrooks Davis q[l].len, q[l].len_bytes, q[l].drops); 22588195404bSBrooks Davis if (verbose) 22598195404bSBrooks Davis printf(" S %20qd F %20qd\n", q[l].S, q[l].F); 22608195404bSBrooks Davis } 22619758b77fSLuigi Rizzo } 22629758b77fSLuigi Rizzo 22639758b77fSLuigi Rizzo static void 22649758b77fSLuigi Rizzo print_flowset_parms(struct dn_flow_set *fs, char *prefix) 22659758b77fSLuigi Rizzo { 22669758b77fSLuigi Rizzo int l; 22679758b77fSLuigi Rizzo char qs[30]; 22689758b77fSLuigi Rizzo char plr[30]; 22699758b77fSLuigi Rizzo char red[90]; /* Display RED parameters */ 22709758b77fSLuigi Rizzo 22719758b77fSLuigi Rizzo l = fs->qsize; 22729758b77fSLuigi Rizzo if (fs->flags_fs & DN_QSIZE_IS_BYTES) { 22739758b77fSLuigi Rizzo if (l >= 8192) 22749758b77fSLuigi Rizzo sprintf(qs, "%d KB", l / 1024); 22759758b77fSLuigi Rizzo else 22769758b77fSLuigi Rizzo sprintf(qs, "%d B", l); 22779758b77fSLuigi Rizzo } else 22789758b77fSLuigi Rizzo sprintf(qs, "%3d sl.", l); 22799758b77fSLuigi Rizzo if (fs->plr) 22809758b77fSLuigi Rizzo sprintf(plr, "plr %f", 1.0 * fs->plr / (double)(0x7fffffff)); 22819758b77fSLuigi Rizzo else 22829758b77fSLuigi Rizzo plr[0] = '\0'; 22839758b77fSLuigi Rizzo if (fs->flags_fs & DN_IS_RED) /* RED parameters */ 22849758b77fSLuigi Rizzo sprintf(red, 22859758b77fSLuigi Rizzo "\n\t %cRED w_q %f min_th %d max_th %d max_p %f", 22869758b77fSLuigi Rizzo (fs->flags_fs & DN_IS_GENTLE_RED) ? 'G' : ' ', 22879758b77fSLuigi Rizzo 1.0 * fs->w_q / (double)(1 << SCALE_RED), 22889758b77fSLuigi Rizzo SCALE_VAL(fs->min_th), 22899758b77fSLuigi Rizzo SCALE_VAL(fs->max_th), 22909758b77fSLuigi Rizzo 1.0 * fs->max_p / (double)(1 << SCALE_RED)); 22919758b77fSLuigi Rizzo else 22929758b77fSLuigi Rizzo sprintf(red, "droptail"); 22939758b77fSLuigi Rizzo 22949758b77fSLuigi Rizzo printf("%s %s%s %d queues (%d buckets) %s\n", 22959758b77fSLuigi Rizzo prefix, qs, plr, fs->rq_elements, fs->rq_size, red); 22969758b77fSLuigi Rizzo } 22979758b77fSLuigi Rizzo 22989758b77fSLuigi Rizzo static void 229962ff38aeSLuigi Rizzo list_pipes(void *data, uint nbytes, int ac, char *av[]) 23009758b77fSLuigi Rizzo { 230162ff38aeSLuigi Rizzo int rulenum; 23029758b77fSLuigi Rizzo void *next = data; 23039758b77fSLuigi Rizzo struct dn_pipe *p = (struct dn_pipe *) data; 23049758b77fSLuigi Rizzo struct dn_flow_set *fs; 23059758b77fSLuigi Rizzo struct dn_flow_queue *q; 23069758b77fSLuigi Rizzo int l; 23079758b77fSLuigi Rizzo 23089758b77fSLuigi Rizzo if (ac > 0) 23099758b77fSLuigi Rizzo rulenum = strtoul(*av++, NULL, 10); 23109758b77fSLuigi Rizzo else 23119758b77fSLuigi Rizzo rulenum = 0; 23129758b77fSLuigi Rizzo for (; nbytes >= sizeof *p; p = (struct dn_pipe *)next) { 23139758b77fSLuigi Rizzo double b = p->bandwidth; 23149758b77fSLuigi Rizzo char buf[30]; 23159758b77fSLuigi Rizzo char prefix[80]; 23169758b77fSLuigi Rizzo 2317299652afSStefan Farfeleder if (SLIST_NEXT(p, next) != (struct dn_pipe *)DN_IS_PIPE) 23189758b77fSLuigi Rizzo break; /* done with pipes, now queues */ 23199758b77fSLuigi Rizzo 23209758b77fSLuigi Rizzo /* 23219758b77fSLuigi Rizzo * compute length, as pipe have variable size 23229758b77fSLuigi Rizzo */ 23239758b77fSLuigi Rizzo l = sizeof(*p) + p->fs.rq_elements * sizeof(*q); 232462ff38aeSLuigi Rizzo next = (char *)p + l; 23259758b77fSLuigi Rizzo nbytes -= l; 23269758b77fSLuigi Rizzo 2327c3d6fe74SPawel Jakub Dawidek if ((rulenum != 0 && rulenum != p->pipe_nr) || do_pipe == 2) 23289758b77fSLuigi Rizzo continue; 23299758b77fSLuigi Rizzo 23309758b77fSLuigi Rizzo /* 23319758b77fSLuigi Rizzo * Print rate (or clocking interface) 23329758b77fSLuigi Rizzo */ 23339758b77fSLuigi Rizzo if (p->if_name[0] != '\0') 23349758b77fSLuigi Rizzo sprintf(buf, "%s", p->if_name); 23359758b77fSLuigi Rizzo else if (b == 0) 23369758b77fSLuigi Rizzo sprintf(buf, "unlimited"); 23379758b77fSLuigi Rizzo else if (b >= 1000000) 23389758b77fSLuigi Rizzo sprintf(buf, "%7.3f Mbit/s", b/1000000); 23399758b77fSLuigi Rizzo else if (b >= 1000) 23409758b77fSLuigi Rizzo sprintf(buf, "%7.3f Kbit/s", b/1000); 23419758b77fSLuigi Rizzo else 23429758b77fSLuigi Rizzo sprintf(buf, "%7.3f bit/s ", b); 23439758b77fSLuigi Rizzo 23449758b77fSLuigi Rizzo sprintf(prefix, "%05d: %s %4d ms ", 23459758b77fSLuigi Rizzo p->pipe_nr, buf, p->delay); 23469758b77fSLuigi Rizzo print_flowset_parms(&(p->fs), prefix); 23479758b77fSLuigi Rizzo if (verbose) 23489758b77fSLuigi Rizzo printf(" V %20qd\n", p->V >> MY_M); 23499758b77fSLuigi Rizzo 23509758b77fSLuigi Rizzo q = (struct dn_flow_queue *)(p+1); 23519758b77fSLuigi Rizzo list_queues(&(p->fs), q); 23529758b77fSLuigi Rizzo } 23539758b77fSLuigi Rizzo for (fs = next; nbytes >= sizeof *fs; fs = next) { 23549758b77fSLuigi Rizzo char prefix[80]; 23559758b77fSLuigi Rizzo 2356299652afSStefan Farfeleder if (SLIST_NEXT(fs, next) != (struct dn_flow_set *)DN_IS_QUEUE) 23579758b77fSLuigi Rizzo break; 23589758b77fSLuigi Rizzo l = sizeof(*fs) + fs->rq_elements * sizeof(*q); 235962ff38aeSLuigi Rizzo next = (char *)fs + l; 23609758b77fSLuigi Rizzo nbytes -= l; 2361c3d6fe74SPawel Jakub Dawidek 2362c3d6fe74SPawel Jakub Dawidek if (rulenum != 0 && ((rulenum != fs->fs_nr && do_pipe == 2) || 2363c3d6fe74SPawel Jakub Dawidek (rulenum != fs->parent_nr && do_pipe == 1))) { 2364c3d6fe74SPawel Jakub Dawidek continue; 2365c3d6fe74SPawel Jakub Dawidek } 2366c3d6fe74SPawel Jakub Dawidek 23679758b77fSLuigi Rizzo q = (struct dn_flow_queue *)(fs+1); 23689758b77fSLuigi Rizzo sprintf(prefix, "q%05d: weight %d pipe %d ", 23699758b77fSLuigi Rizzo fs->fs_nr, fs->weight, fs->parent_nr); 23709758b77fSLuigi Rizzo print_flowset_parms(fs, prefix); 23719758b77fSLuigi Rizzo list_queues(fs, q); 23729758b77fSLuigi Rizzo } 23739758b77fSLuigi Rizzo } 23749758b77fSLuigi Rizzo 237599e5e645SLuigi Rizzo /* 237699e5e645SLuigi Rizzo * This one handles all set-related commands 237799e5e645SLuigi Rizzo * ipfw set { show | enable | disable } 237899e5e645SLuigi Rizzo * ipfw set swap X Y 237999e5e645SLuigi Rizzo * ipfw set move X to Y 238099e5e645SLuigi Rizzo * ipfw set move rule X to Y 238199e5e645SLuigi Rizzo */ 238299e5e645SLuigi Rizzo static void 238399e5e645SLuigi Rizzo sets_handler(int ac, char *av[]) 238499e5e645SLuigi Rizzo { 2385571f8c1bSLuigi Rizzo uint32_t set_disable, masks[2]; 238699e5e645SLuigi Rizzo int i, nbytes; 2387571f8c1bSLuigi Rizzo uint16_t rulenum; 2388571f8c1bSLuigi Rizzo uint8_t cmd, new_set; 238999e5e645SLuigi Rizzo 239099e5e645SLuigi Rizzo ac--; 239199e5e645SLuigi Rizzo av++; 239299e5e645SLuigi Rizzo 239399e5e645SLuigi Rizzo if (!ac) 239499e5e645SLuigi Rizzo errx(EX_USAGE, "set needs command"); 239501750186SBrooks Davis if (_substrcmp(*av, "show") == 0) { 239699e5e645SLuigi Rizzo void *data; 239762ff38aeSLuigi Rizzo char const *msg; 239899e5e645SLuigi Rizzo 239999e5e645SLuigi Rizzo nbytes = sizeof(struct ip_fw); 24005f356082SLuigi Rizzo data = safe_calloc(1, nbytes); 2401884be75cSThomas Moestl if (do_cmd(IP_FW_GET, data, (uintptr_t)&nbytes) < 0) 240299e5e645SLuigi Rizzo err(EX_OSERR, "getsockopt(IP_FW_GET)"); 2403330462a3SBernd Walter bcopy(&((struct ip_fw *)data)->next_rule, 2404330462a3SBernd Walter &set_disable, sizeof(set_disable)); 2405330462a3SBernd Walter 24063004afcaSLuigi Rizzo for (i = 0, msg = "disable" ; i < RESVD_SET; i++) 240799e5e645SLuigi Rizzo if ((set_disable & (1<<i))) { 240899e5e645SLuigi Rizzo printf("%s %d", msg, i); 240999e5e645SLuigi Rizzo msg = ""; 241099e5e645SLuigi Rizzo } 241199e5e645SLuigi Rizzo msg = (set_disable) ? " enable" : "enable"; 24123004afcaSLuigi Rizzo for (i = 0; i < RESVD_SET; i++) 241399e5e645SLuigi Rizzo if (!(set_disable & (1<<i))) { 241499e5e645SLuigi Rizzo printf("%s %d", msg, i); 241599e5e645SLuigi Rizzo msg = ""; 241699e5e645SLuigi Rizzo } 241799e5e645SLuigi Rizzo printf("\n"); 241801750186SBrooks Davis } else if (_substrcmp(*av, "swap") == 0) { 241999e5e645SLuigi Rizzo ac--; av++; 242099e5e645SLuigi Rizzo if (ac != 2) 242199e5e645SLuigi Rizzo errx(EX_USAGE, "set swap needs 2 set numbers\n"); 242299e5e645SLuigi Rizzo rulenum = atoi(av[0]); 242399e5e645SLuigi Rizzo new_set = atoi(av[1]); 24243004afcaSLuigi Rizzo if (!isdigit(*(av[0])) || rulenum > RESVD_SET) 242599e5e645SLuigi Rizzo errx(EX_DATAERR, "invalid set number %s\n", av[0]); 24263004afcaSLuigi Rizzo if (!isdigit(*(av[1])) || new_set > RESVD_SET) 242799e5e645SLuigi Rizzo errx(EX_DATAERR, "invalid set number %s\n", av[1]); 242899e5e645SLuigi Rizzo masks[0] = (4 << 24) | (new_set << 16) | (rulenum); 2429571f8c1bSLuigi Rizzo i = do_cmd(IP_FW_DEL, masks, sizeof(uint32_t)); 243001750186SBrooks Davis } else if (_substrcmp(*av, "move") == 0) { 243199e5e645SLuigi Rizzo ac--; av++; 243201750186SBrooks Davis if (ac && _substrcmp(*av, "rule") == 0) { 243399e5e645SLuigi Rizzo cmd = 2; 243499e5e645SLuigi Rizzo ac--; av++; 243599e5e645SLuigi Rizzo } else 243699e5e645SLuigi Rizzo cmd = 3; 243701750186SBrooks Davis if (ac != 3 || _substrcmp(av[1], "to") != 0) 243899e5e645SLuigi Rizzo errx(EX_USAGE, "syntax: set move [rule] X to Y\n"); 243999e5e645SLuigi Rizzo rulenum = atoi(av[0]); 244099e5e645SLuigi Rizzo new_set = atoi(av[2]); 24413004afcaSLuigi Rizzo if (!isdigit(*(av[0])) || (cmd == 3 && rulenum > RESVD_SET) || 2442759dd6f7SRoman Kurakin (cmd == 2 && rulenum == IPFW_DEFAULT_RULE) ) 244399e5e645SLuigi Rizzo errx(EX_DATAERR, "invalid source number %s\n", av[0]); 24443004afcaSLuigi Rizzo if (!isdigit(*(av[2])) || new_set > RESVD_SET) 244599e5e645SLuigi Rizzo errx(EX_DATAERR, "invalid dest. set %s\n", av[1]); 244699e5e645SLuigi Rizzo masks[0] = (cmd << 24) | (new_set << 16) | (rulenum); 2447571f8c1bSLuigi Rizzo i = do_cmd(IP_FW_DEL, masks, sizeof(uint32_t)); 244801750186SBrooks Davis } else if (_substrcmp(*av, "disable") == 0 || 244901750186SBrooks Davis _substrcmp(*av, "enable") == 0 ) { 245001750186SBrooks Davis int which = _substrcmp(*av, "enable") == 0 ? 1 : 0; 245199e5e645SLuigi Rizzo 245299e5e645SLuigi Rizzo ac--; av++; 245399e5e645SLuigi Rizzo masks[0] = masks[1] = 0; 245499e5e645SLuigi Rizzo 245599e5e645SLuigi Rizzo while (ac) { 245699e5e645SLuigi Rizzo if (isdigit(**av)) { 245799e5e645SLuigi Rizzo i = atoi(*av); 24583004afcaSLuigi Rizzo if (i < 0 || i > RESVD_SET) 245999e5e645SLuigi Rizzo errx(EX_DATAERR, 246099e5e645SLuigi Rizzo "invalid set number %d\n", i); 246199e5e645SLuigi Rizzo masks[which] |= (1<<i); 246201750186SBrooks Davis } else if (_substrcmp(*av, "disable") == 0) 246399e5e645SLuigi Rizzo which = 0; 246401750186SBrooks Davis else if (_substrcmp(*av, "enable") == 0) 246599e5e645SLuigi Rizzo which = 1; 246699e5e645SLuigi Rizzo else 246799e5e645SLuigi Rizzo errx(EX_DATAERR, 246899e5e645SLuigi Rizzo "invalid set command %s\n", *av); 246999e5e645SLuigi Rizzo av++; ac--; 247099e5e645SLuigi Rizzo } 247199e5e645SLuigi Rizzo if ( (masks[0] & masks[1]) != 0 ) 247299e5e645SLuigi Rizzo errx(EX_DATAERR, 247399e5e645SLuigi Rizzo "cannot enable and disable the same set\n"); 247499e5e645SLuigi Rizzo 2475571f8c1bSLuigi Rizzo i = do_cmd(IP_FW_DEL, masks, sizeof(masks)); 247699e5e645SLuigi Rizzo if (i) 247799e5e645SLuigi Rizzo warn("set enable/disable: setsockopt(IP_FW_DEL)"); 247899e5e645SLuigi Rizzo } else 247999e5e645SLuigi Rizzo errx(EX_USAGE, "invalid set command %s\n", *av); 248099e5e645SLuigi Rizzo } 248199e5e645SLuigi Rizzo 24829758b77fSLuigi Rizzo static void 24836690be9eSMatthew Dillon sysctl_handler(int ac, char *av[], int which) 24846690be9eSMatthew Dillon { 24856690be9eSMatthew Dillon ac--; 24866690be9eSMatthew Dillon av++; 24876690be9eSMatthew Dillon 24881c56ad9bSMaxim Konovalov if (ac == 0) { 24896690be9eSMatthew Dillon warnx("missing keyword to enable/disable\n"); 249001750186SBrooks Davis } else if (_substrcmp(*av, "firewall") == 0) { 249129c1402aSLuigi Rizzo sysctlbyname("net.inet.ip.fw.enable", NULL, 0, 249229c1402aSLuigi Rizzo &which, sizeof(which)); 249301750186SBrooks Davis } else if (_substrcmp(*av, "one_pass") == 0) { 249429c1402aSLuigi Rizzo sysctlbyname("net.inet.ip.fw.one_pass", NULL, 0, 249529c1402aSLuigi Rizzo &which, sizeof(which)); 249601750186SBrooks Davis } else if (_substrcmp(*av, "debug") == 0) { 249729c1402aSLuigi Rizzo sysctlbyname("net.inet.ip.fw.debug", NULL, 0, 249829c1402aSLuigi Rizzo &which, sizeof(which)); 249901750186SBrooks Davis } else if (_substrcmp(*av, "verbose") == 0) { 250029c1402aSLuigi Rizzo sysctlbyname("net.inet.ip.fw.verbose", NULL, 0, 250129c1402aSLuigi Rizzo &which, sizeof(which)); 250201750186SBrooks Davis } else if (_substrcmp(*av, "dyn_keepalive") == 0) { 250329c1402aSLuigi Rizzo sysctlbyname("net.inet.ip.fw.dyn_keepalive", NULL, 0, 250429c1402aSLuigi Rizzo &which, sizeof(which)); 250501750186SBrooks Davis } else if (_substrcmp(*av, "altq") == 0) { 2506974dfe30SBrian Feldman altq_set_enabled(which); 25076690be9eSMatthew Dillon } else { 25086690be9eSMatthew Dillon warnx("unrecognize enable/disable keyword: %s\n", *av); 25096690be9eSMatthew Dillon } 25106690be9eSMatthew Dillon } 25116690be9eSMatthew Dillon 25126690be9eSMatthew Dillon static void 251362ff38aeSLuigi Rizzo list(int ac, char *av[], int show_counters) 25149758b77fSLuigi Rizzo { 25159758b77fSLuigi Rizzo struct ip_fw *r; 25169758b77fSLuigi Rizzo ipfw_dyn_rule *dynrules, *d; 25179758b77fSLuigi Rizzo 251862ff38aeSLuigi Rizzo #define NEXT(r) ((struct ip_fw *)((char *)r + RULESIZE(r))) 251962ff38aeSLuigi Rizzo char *lim; 252062ff38aeSLuigi Rizzo void *data = NULL; 252145f61351SMaxim Konovalov int bcwidth, n, nbytes, nstat, ndyn, pcwidth, width; 25229758b77fSLuigi Rizzo int exitval = EX_OK; 25239758b77fSLuigi Rizzo int lac; 25249758b77fSLuigi Rizzo char **lav; 252562ff38aeSLuigi Rizzo u_long rnum, last; 25269758b77fSLuigi Rizzo char *endptr; 25279758b77fSLuigi Rizzo int seen = 0; 2528d069a5d4SMaxim Konovalov uint8_t set; 25299758b77fSLuigi Rizzo 25309758b77fSLuigi Rizzo const int ocmd = do_pipe ? IP_DUMMYNET_GET : IP_FW_GET; 25319758b77fSLuigi Rizzo int nalloc = 1024; /* start somewhere... */ 25329758b77fSLuigi Rizzo 253300ed6609SMaxim Konovalov last = 0; 253400ed6609SMaxim Konovalov 2535571f8c1bSLuigi Rizzo if (test_only) { 2536571f8c1bSLuigi Rizzo fprintf(stderr, "Testing only, list disabled\n"); 2537571f8c1bSLuigi Rizzo return; 2538571f8c1bSLuigi Rizzo } 2539571f8c1bSLuigi Rizzo 25409758b77fSLuigi Rizzo ac--; 25419758b77fSLuigi Rizzo av++; 25429758b77fSLuigi Rizzo 25439758b77fSLuigi Rizzo /* get rules or pipes from kernel, resizing array as necessary */ 25449758b77fSLuigi Rizzo nbytes = nalloc; 25459758b77fSLuigi Rizzo 25469758b77fSLuigi Rizzo while (nbytes >= nalloc) { 25479758b77fSLuigi Rizzo nalloc = nalloc * 2 + 200; 25489758b77fSLuigi Rizzo nbytes = nalloc; 25495f356082SLuigi Rizzo data = safe_realloc(data, nbytes); 2550884be75cSThomas Moestl if (do_cmd(ocmd, data, (uintptr_t)&nbytes) < 0) 25519758b77fSLuigi Rizzo err(EX_OSERR, "getsockopt(IP_%s_GET)", 25529758b77fSLuigi Rizzo do_pipe ? "DUMMYNET" : "FW"); 25539758b77fSLuigi Rizzo } 25549758b77fSLuigi Rizzo 25559758b77fSLuigi Rizzo if (do_pipe) { 25569758b77fSLuigi Rizzo list_pipes(data, nbytes, ac, av); 25579758b77fSLuigi Rizzo goto done; 25589758b77fSLuigi Rizzo } 25599758b77fSLuigi Rizzo 25609758b77fSLuigi Rizzo /* 25619758b77fSLuigi Rizzo * Count static rules. They have variable size so we 25629758b77fSLuigi Rizzo * need to scan the list to count them. 25639758b77fSLuigi Rizzo */ 256462ff38aeSLuigi Rizzo for (nstat = 1, r = data, lim = (char *)data + nbytes; 2565759dd6f7SRoman Kurakin r->rulenum < IPFW_DEFAULT_RULE && (char *)r < lim; 256662ff38aeSLuigi Rizzo ++nstat, r = NEXT(r) ) 25679758b77fSLuigi Rizzo ; /* nothing */ 25689758b77fSLuigi Rizzo 25699758b77fSLuigi Rizzo /* 25709758b77fSLuigi Rizzo * Count dynamic rules. This is easier as they have 25719758b77fSLuigi Rizzo * fixed size. 25729758b77fSLuigi Rizzo */ 257362ff38aeSLuigi Rizzo r = NEXT(r); 25749758b77fSLuigi Rizzo dynrules = (ipfw_dyn_rule *)r ; 257562ff38aeSLuigi Rizzo n = (char *)r - (char *)data; 25769758b77fSLuigi Rizzo ndyn = (nbytes - n) / sizeof *dynrules; 25779758b77fSLuigi Rizzo 257845f61351SMaxim Konovalov /* if showing stats, figure out column widths ahead of time */ 257945f61351SMaxim Konovalov bcwidth = pcwidth = 0; 258062ff38aeSLuigi Rizzo if (show_counters) { 258162ff38aeSLuigi Rizzo for (n = 0, r = data; n < nstat; n++, r = NEXT(r)) { 2582d069a5d4SMaxim Konovalov /* skip rules from another set */ 2583d069a5d4SMaxim Konovalov if (use_set && r->set != use_set - 1) 2584d069a5d4SMaxim Konovalov continue; 2585d069a5d4SMaxim Konovalov 258645f61351SMaxim Konovalov /* packet counter */ 2587330462a3SBernd Walter width = snprintf(NULL, 0, "%llu", 2588330462a3SBernd Walter align_uint64(&r->pcnt)); 258945f61351SMaxim Konovalov if (width > pcwidth) 259045f61351SMaxim Konovalov pcwidth = width; 259145f61351SMaxim Konovalov 259245f61351SMaxim Konovalov /* byte counter */ 2593330462a3SBernd Walter width = snprintf(NULL, 0, "%llu", 2594330462a3SBernd Walter align_uint64(&r->bcnt)); 259545f61351SMaxim Konovalov if (width > bcwidth) 259645f61351SMaxim Konovalov bcwidth = width; 259745f61351SMaxim Konovalov } 259845f61351SMaxim Konovalov } 259945f61351SMaxim Konovalov if (do_dynamic && ndyn) { 260045f61351SMaxim Konovalov for (n = 0, d = dynrules; n < ndyn; n++, d++) { 2601d069a5d4SMaxim Konovalov if (use_set) { 2602d069a5d4SMaxim Konovalov /* skip rules from another set */ 26034a296ec7SMaxim Konovalov bcopy((char *)&d->rule + sizeof(uint16_t), 2604d069a5d4SMaxim Konovalov &set, sizeof(uint8_t)); 2605d069a5d4SMaxim Konovalov if (set != use_set - 1) 2606d069a5d4SMaxim Konovalov continue; 2607d069a5d4SMaxim Konovalov } 2608330462a3SBernd Walter width = snprintf(NULL, 0, "%llu", 2609330462a3SBernd Walter align_uint64(&d->pcnt)); 261045f61351SMaxim Konovalov if (width > pcwidth) 261145f61351SMaxim Konovalov pcwidth = width; 261245f61351SMaxim Konovalov 2613330462a3SBernd Walter width = snprintf(NULL, 0, "%llu", 2614330462a3SBernd Walter align_uint64(&d->bcnt)); 261545f61351SMaxim Konovalov if (width > bcwidth) 261645f61351SMaxim Konovalov bcwidth = width; 261745f61351SMaxim Konovalov } 261845f61351SMaxim Konovalov } 26199758b77fSLuigi Rizzo /* if no rule numbers were specified, list all rules */ 26209758b77fSLuigi Rizzo if (ac == 0) { 2621d069a5d4SMaxim Konovalov for (n = 0, r = data; n < nstat; n++, r = NEXT(r)) { 2622d069a5d4SMaxim Konovalov if (use_set && r->set != use_set - 1) 2623d069a5d4SMaxim Konovalov continue; 262445f61351SMaxim Konovalov show_ipfw(r, pcwidth, bcwidth); 2625d069a5d4SMaxim Konovalov } 26269758b77fSLuigi Rizzo 26279758b77fSLuigi Rizzo if (do_dynamic && ndyn) { 26289758b77fSLuigi Rizzo printf("## Dynamic rules (%d):\n", ndyn); 2629d069a5d4SMaxim Konovalov for (n = 0, d = dynrules; n < ndyn; n++, d++) { 2630d069a5d4SMaxim Konovalov if (use_set) { 26314a296ec7SMaxim Konovalov bcopy((char *)&d->rule + sizeof(uint16_t), 2632d069a5d4SMaxim Konovalov &set, sizeof(uint8_t)); 2633d069a5d4SMaxim Konovalov if (set != use_set - 1) 2634d069a5d4SMaxim Konovalov continue; 2635d069a5d4SMaxim Konovalov } 263645f61351SMaxim Konovalov show_dyn_ipfw(d, pcwidth, bcwidth); 26379758b77fSLuigi Rizzo } 2638d069a5d4SMaxim Konovalov } 26399758b77fSLuigi Rizzo goto done; 26409758b77fSLuigi Rizzo } 26419758b77fSLuigi Rizzo 26429758b77fSLuigi Rizzo /* display specific rules requested on command line */ 26439758b77fSLuigi Rizzo 26449758b77fSLuigi Rizzo for (lac = ac, lav = av; lac != 0; lac--) { 26459758b77fSLuigi Rizzo /* convert command line rule # */ 264662ff38aeSLuigi Rizzo last = rnum = strtoul(*lav++, &endptr, 10); 264762ff38aeSLuigi Rizzo if (*endptr == '-') 264862ff38aeSLuigi Rizzo last = strtoul(endptr+1, &endptr, 10); 26499758b77fSLuigi Rizzo if (*endptr) { 26509758b77fSLuigi Rizzo exitval = EX_USAGE; 26519758b77fSLuigi Rizzo warnx("invalid rule number: %s", *(lav - 1)); 26529758b77fSLuigi Rizzo continue; 26539758b77fSLuigi Rizzo } 265462ff38aeSLuigi Rizzo for (n = seen = 0, r = data; n < nstat; n++, r = NEXT(r) ) { 265562ff38aeSLuigi Rizzo if (r->rulenum > last) 26569758b77fSLuigi Rizzo break; 2657d069a5d4SMaxim Konovalov if (use_set && r->set != use_set - 1) 2658d069a5d4SMaxim Konovalov continue; 265962ff38aeSLuigi Rizzo if (r->rulenum >= rnum && r->rulenum <= last) { 266045f61351SMaxim Konovalov show_ipfw(r, pcwidth, bcwidth); 26619758b77fSLuigi Rizzo seen = 1; 26629758b77fSLuigi Rizzo } 26639758b77fSLuigi Rizzo } 26649758b77fSLuigi Rizzo if (!seen) { 26659758b77fSLuigi Rizzo /* give precedence to other error(s) */ 26669758b77fSLuigi Rizzo if (exitval == EX_OK) 26679758b77fSLuigi Rizzo exitval = EX_UNAVAILABLE; 26689758b77fSLuigi Rizzo warnx("rule %lu does not exist", rnum); 26699758b77fSLuigi Rizzo } 26709758b77fSLuigi Rizzo } 26719758b77fSLuigi Rizzo 26729758b77fSLuigi Rizzo if (do_dynamic && ndyn) { 26739758b77fSLuigi Rizzo printf("## Dynamic rules:\n"); 26749758b77fSLuigi Rizzo for (lac = ac, lav = av; lac != 0; lac--) { 26758195404bSBrooks Davis last = rnum = strtoul(*lav++, &endptr, 10); 267662ff38aeSLuigi Rizzo if (*endptr == '-') 267762ff38aeSLuigi Rizzo last = strtoul(endptr+1, &endptr, 10); 26789758b77fSLuigi Rizzo if (*endptr) 26799758b77fSLuigi Rizzo /* already warned */ 26809758b77fSLuigi Rizzo continue; 26819758b77fSLuigi Rizzo for (n = 0, d = dynrules; n < ndyn; n++, d++) { 2682330462a3SBernd Walter uint16_t rulenum; 2683330462a3SBernd Walter 2684330462a3SBernd Walter bcopy(&d->rule, &rulenum, sizeof(rulenum)); 2685330462a3SBernd Walter if (rulenum > rnum) 26869758b77fSLuigi Rizzo break; 2687d069a5d4SMaxim Konovalov if (use_set) { 26884a296ec7SMaxim Konovalov bcopy((char *)&d->rule + sizeof(uint16_t), 2689d069a5d4SMaxim Konovalov &set, sizeof(uint8_t)); 2690d069a5d4SMaxim Konovalov if (set != use_set - 1) 2691d069a5d4SMaxim Konovalov continue; 2692d069a5d4SMaxim Konovalov } 269362ff38aeSLuigi Rizzo if (r->rulenum >= rnum && r->rulenum <= last) 269445f61351SMaxim Konovalov show_dyn_ipfw(d, pcwidth, bcwidth); 26959758b77fSLuigi Rizzo } 26969758b77fSLuigi Rizzo } 26979758b77fSLuigi Rizzo } 26989758b77fSLuigi Rizzo 26999758b77fSLuigi Rizzo ac = 0; 27009758b77fSLuigi Rizzo 27019758b77fSLuigi Rizzo done: 27029758b77fSLuigi Rizzo free(data); 27039758b77fSLuigi Rizzo 27049758b77fSLuigi Rizzo if (exitval != EX_OK) 27059758b77fSLuigi Rizzo exit(exitval); 270662ff38aeSLuigi Rizzo #undef NEXT 27079758b77fSLuigi Rizzo } 27089758b77fSLuigi Rizzo 27099758b77fSLuigi Rizzo static void 27109758b77fSLuigi Rizzo show_usage(void) 27119758b77fSLuigi Rizzo { 27129758b77fSLuigi Rizzo fprintf(stderr, "usage: ipfw [options]\n" 27139758b77fSLuigi Rizzo "do \"ipfw -h\" or see ipfw manpage for details\n" 27149758b77fSLuigi Rizzo ); 27159758b77fSLuigi Rizzo exit(EX_USAGE); 27169758b77fSLuigi Rizzo } 27179758b77fSLuigi Rizzo 27189758b77fSLuigi Rizzo static void 27199758b77fSLuigi Rizzo help(void) 27209758b77fSLuigi Rizzo { 2721571f8c1bSLuigi Rizzo fprintf(stderr, 2722571f8c1bSLuigi Rizzo "ipfw syntax summary (but please do read the ipfw(8) manpage):\n" 2723ac6cec51SLuigi Rizzo "ipfw [-abcdefhnNqStTv] <command> where <command> is one of:\n" 2724571f8c1bSLuigi Rizzo "add [num] [set N] [prob x] RULE-BODY\n" 2725571f8c1bSLuigi Rizzo "{pipe|queue} N config PIPE-BODY\n" 2726571f8c1bSLuigi Rizzo "[pipe|queue] {zero|delete|show} [N{,N}]\n" 2727ff2f6fe8SPaolo Pisati "nat N config {ip IPADDR|if IFNAME|log|deny_in|same_ports|unreg_only|reset|\n" 2728ff2f6fe8SPaolo Pisati " reverse|proxy_only|redirect_addr linkspec|\n" 2729ff2f6fe8SPaolo Pisati " redirect_port linkspec|redirect_proto linkspec}\n" 2730571f8c1bSLuigi Rizzo "set [disable N... enable N...] | move [rule] X to Y | swap X Y | show\n" 2731d069a5d4SMaxim Konovalov "set N {show|list|zero|resetlog|delete} [N{,N}] | flush\n" 2732cd8b5ae0SRuslan Ermilov "table N {add ip[/bits] [value] | delete ip[/bits] | flush | list}\n" 2733c15c2490SRoman Kurakin "table all {flush | list}\n" 27349758b77fSLuigi Rizzo "\n" 2735974dfe30SBrian Feldman "RULE-BODY: check-state [PARAMS] | ACTION [PARAMS] ADDR [OPTION_LIST]\n" 27369066356bSBjoern A. Zeeb "ACTION: check-state | allow | count | deny | unreach{,6} CODE |\n" 27379066356bSBjoern A. Zeeb " skipto N | {divert|tee} PORT | forward ADDR |\n" 27388b07e49aSJulian Elischer " pipe N | queue N | nat N | setfib FIB\n" 2739974dfe30SBrian Feldman "PARAMS: [log [logamount LOGLIMIT]] [altq QUEUE_NAME]\n" 27409758b77fSLuigi Rizzo "ADDR: [ MAC dst src ether_type ] \n" 27418195404bSBrooks Davis " [ ip from IPADDR [ PORT ] to IPADDR [ PORTLIST ] ]\n" 27428195404bSBrooks Davis " [ ipv6|ip6 from IP6ADDR [ PORT ] to IP6ADDR [ PORTLIST ] ]\n" 2743cd8b5ae0SRuslan Ermilov "IPADDR: [not] { any | me | ip/bits{x,y,z} | table(t[,v]) | IPLIST }\n" 27448195404bSBrooks Davis "IP6ADDR: [not] { any | me | me6 | ip6/bits | IP6LIST }\n" 27458195404bSBrooks Davis "IP6LIST: { ip6 | ip6/bits }[,IP6LIST]\n" 274626bf4d78SLuigi Rizzo "IPLIST: { ip | ip/bits | ip:mask }[,IPLIST]\n" 274726bf4d78SLuigi Rizzo "OPTION_LIST: OPTION [OPTION_LIST]\n" 274817db1a04SBrian Feldman "OPTION: bridged | diverted | diverted-loopback | diverted-output |\n" 27498195404bSBrooks Davis " {dst-ip|src-ip} IPADDR | {dst-ip6|src-ip6|dst-ipv6|src-ipv6} IP6ADDR |\n" 27508195404bSBrooks Davis " {dst-port|src-port} LIST |\n" 2751571f8c1bSLuigi Rizzo " estab | frag | {gid|uid} N | icmptypes LIST | in | out | ipid LIST |\n" 2752571f8c1bSLuigi Rizzo " iplen LIST | ipoptions SPEC | ipprecedence | ipsec | iptos SPEC |\n" 2753571f8c1bSLuigi Rizzo " ipttl LIST | ipversion VER | keep-state | layer2 | limit ... |\n" 27548b07e49aSJulian Elischer " icmp6types LIST | ext6hdr LIST | flow-id N[,N] | fib FIB |\n" 2755571f8c1bSLuigi Rizzo " mac ... | mac-type LIST | proto LIST | {recv|xmit|via} {IF|IPADDR} |\n" 2756571f8c1bSLuigi Rizzo " setup | {tcpack|tcpseq|tcpwin} NN | tcpflags SPEC | tcpoptions SPEC |\n" 2757c99ee9e0SBrian Feldman " tcpdatalen LIST | verrevpath | versrcreach | antispoof\n" 27589758b77fSLuigi Rizzo ); 27599758b77fSLuigi Rizzo exit(0); 27609758b77fSLuigi Rizzo } 27619758b77fSLuigi Rizzo 27629758b77fSLuigi Rizzo 27639758b77fSLuigi Rizzo static int 27649758b77fSLuigi Rizzo lookup_host (char *host, struct in_addr *ipaddr) 27659758b77fSLuigi Rizzo { 27669758b77fSLuigi Rizzo struct hostent *he; 27679758b77fSLuigi Rizzo 27689758b77fSLuigi Rizzo if (!inet_aton(host, ipaddr)) { 27699758b77fSLuigi Rizzo if ((he = gethostbyname(host)) == NULL) 27709758b77fSLuigi Rizzo return(-1); 27719758b77fSLuigi Rizzo *ipaddr = *(struct in_addr *)he->h_addr_list[0]; 27729758b77fSLuigi Rizzo } 27739758b77fSLuigi Rizzo return(0); 27749758b77fSLuigi Rizzo } 27759758b77fSLuigi Rizzo 27769758b77fSLuigi Rizzo /* 27779758b77fSLuigi Rizzo * fills the addr and mask fields in the instruction as appropriate from av. 27789758b77fSLuigi Rizzo * Update length as appropriate. 27799758b77fSLuigi Rizzo * The following formats are allowed: 27809758b77fSLuigi Rizzo * me returns O_IP_*_ME 27819758b77fSLuigi Rizzo * 1.2.3.4 single IP address 27829758b77fSLuigi Rizzo * 1.2.3.4:5.6.7.8 address:mask 27839758b77fSLuigi Rizzo * 1.2.3.4/24 address/mask 27849758b77fSLuigi Rizzo * 1.2.3.4/26{1,6,5,4,23} set of addresses in a subnet 2785571f8c1bSLuigi Rizzo * We can have multiple comma-separated address/mask entries. 27869758b77fSLuigi Rizzo */ 27879758b77fSLuigi Rizzo static void 27889758b77fSLuigi Rizzo fill_ip(ipfw_insn_ip *cmd, char *av) 27899758b77fSLuigi Rizzo { 2790571f8c1bSLuigi Rizzo int len = 0; 2791571f8c1bSLuigi Rizzo uint32_t *d = ((ipfw_insn_u32 *)cmd)->d; 27929758b77fSLuigi Rizzo 27939758b77fSLuigi Rizzo cmd->o.len &= ~F_LEN_MASK; /* zero len */ 27949758b77fSLuigi Rizzo 279501750186SBrooks Davis if (_substrcmp(av, "any") == 0) 27969758b77fSLuigi Rizzo return; 27979758b77fSLuigi Rizzo 279801750186SBrooks Davis if (_substrcmp(av, "me") == 0) { 27999758b77fSLuigi Rizzo cmd->o.len |= F_INSN_SIZE(ipfw_insn); 28009758b77fSLuigi Rizzo return; 28019758b77fSLuigi Rizzo } 28029758b77fSLuigi Rizzo 280301750186SBrooks Davis if (strncmp(av, "table(", 6) == 0) { 2804cd8b5ae0SRuslan Ermilov char *p = strchr(av + 6, ','); 2805cd8b5ae0SRuslan Ermilov 2806cd8b5ae0SRuslan Ermilov if (p) 2807cd8b5ae0SRuslan Ermilov *p++ = '\0'; 2808cd8b5ae0SRuslan Ermilov cmd->o.opcode = O_IP_DST_LOOKUP; 2809cd8b5ae0SRuslan Ermilov cmd->o.arg1 = strtoul(av + 6, NULL, 0); 2810cd8b5ae0SRuslan Ermilov if (p) { 2811cd8b5ae0SRuslan Ermilov cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32); 2812cd8b5ae0SRuslan Ermilov d[0] = strtoul(p, NULL, 0); 2813cd8b5ae0SRuslan Ermilov } else 2814cd8b5ae0SRuslan Ermilov cmd->o.len |= F_INSN_SIZE(ipfw_insn); 2815cd8b5ae0SRuslan Ermilov return; 2816cd8b5ae0SRuslan Ermilov } 2817cd8b5ae0SRuslan Ermilov 2818571f8c1bSLuigi Rizzo while (av) { 2819571f8c1bSLuigi Rizzo /* 2820571f8c1bSLuigi Rizzo * After the address we can have '/' or ':' indicating a mask, 2821571f8c1bSLuigi Rizzo * ',' indicating another address follows, '{' indicating a 2822571f8c1bSLuigi Rizzo * set of addresses of unspecified size. 2823571f8c1bSLuigi Rizzo */ 2824c2221c35SMax Laier char *t = NULL, *p = strpbrk(av, "/:,{"); 2825571f8c1bSLuigi Rizzo int masklen; 2826daa9733aSLuigi Rizzo char md, nd = '\0'; 2827571f8c1bSLuigi Rizzo 28289758b77fSLuigi Rizzo if (p) { 28299758b77fSLuigi Rizzo md = *p; 28309758b77fSLuigi Rizzo *p++ = '\0'; 2831c2221c35SMax Laier if ((t = strpbrk(p, ",{")) != NULL) { 2832c2221c35SMax Laier nd = *t; 2833c2221c35SMax Laier *t = '\0'; 2834c2221c35SMax Laier } 2835571f8c1bSLuigi Rizzo } else 2836571f8c1bSLuigi Rizzo md = '\0'; 28379758b77fSLuigi Rizzo 2838571f8c1bSLuigi Rizzo if (lookup_host(av, (struct in_addr *)&d[0]) != 0) 28399758b77fSLuigi Rizzo errx(EX_NOHOST, "hostname ``%s'' unknown", av); 28409758b77fSLuigi Rizzo switch (md) { 28419758b77fSLuigi Rizzo case ':': 2842571f8c1bSLuigi Rizzo if (!inet_aton(p, (struct in_addr *)&d[1])) 28439758b77fSLuigi Rizzo errx(EX_DATAERR, "bad netmask ``%s''", p); 28449758b77fSLuigi Rizzo break; 28459758b77fSLuigi Rizzo case '/': 2846571f8c1bSLuigi Rizzo masklen = atoi(p); 2847571f8c1bSLuigi Rizzo if (masklen == 0) 2848571f8c1bSLuigi Rizzo d[1] = htonl(0); /* mask */ 2849571f8c1bSLuigi Rizzo else if (masklen > 32) 28509758b77fSLuigi Rizzo errx(EX_DATAERR, "bad width ``%s''", p); 28519758b77fSLuigi Rizzo else 2852571f8c1bSLuigi Rizzo d[1] = htonl(~0 << (32 - masklen)); 28539758b77fSLuigi Rizzo break; 2854571f8c1bSLuigi Rizzo case '{': /* no mask, assume /24 and put back the '{' */ 2855571f8c1bSLuigi Rizzo d[1] = htonl(~0 << (32 - 24)); 2856571f8c1bSLuigi Rizzo *(--p) = md; 2857571f8c1bSLuigi Rizzo break; 2858571f8c1bSLuigi Rizzo 2859571f8c1bSLuigi Rizzo case ',': /* single address plus continuation */ 2860571f8c1bSLuigi Rizzo *(--p) = md; 2861571f8c1bSLuigi Rizzo /* FALLTHROUGH */ 2862571f8c1bSLuigi Rizzo case 0: /* initialization value */ 28639758b77fSLuigi Rizzo default: 2864571f8c1bSLuigi Rizzo d[1] = htonl(~0); /* force /32 */ 28659758b77fSLuigi Rizzo break; 28669758b77fSLuigi Rizzo } 2867571f8c1bSLuigi Rizzo d[0] &= d[1]; /* mask base address with mask */ 2868c2221c35SMax Laier if (t) 2869c2221c35SMax Laier *t = nd; 2870571f8c1bSLuigi Rizzo /* find next separator */ 2871571f8c1bSLuigi Rizzo if (p) 2872571f8c1bSLuigi Rizzo p = strpbrk(p, ",{"); 2873571f8c1bSLuigi Rizzo if (p && *p == '{') { 28749758b77fSLuigi Rizzo /* 2875571f8c1bSLuigi Rizzo * We have a set of addresses. They are stored as follows: 28769758b77fSLuigi Rizzo * arg1 is the set size (powers of 2, 2..256) 28779758b77fSLuigi Rizzo * addr is the base address IN HOST FORMAT 2878571f8c1bSLuigi Rizzo * mask.. is an array of arg1 bits (rounded up to 2879571f8c1bSLuigi Rizzo * the next multiple of 32) with bits set 2880571f8c1bSLuigi Rizzo * for each host in the map. 28819758b77fSLuigi Rizzo */ 2882571f8c1bSLuigi Rizzo uint32_t *map = (uint32_t *)&cmd->mask; 28839758b77fSLuigi Rizzo int low, high; 2884f3a126d3SLuigi Rizzo int i = contigmask((uint8_t *)&(d[1]), 32); 28859758b77fSLuigi Rizzo 2886571f8c1bSLuigi Rizzo if (len > 0) 2887571f8c1bSLuigi Rizzo errx(EX_DATAERR, "address set cannot be in a list"); 2888571f8c1bSLuigi Rizzo if (i < 24 || i > 31) 2889571f8c1bSLuigi Rizzo errx(EX_DATAERR, "invalid set with mask %d\n", i); 2890571f8c1bSLuigi Rizzo cmd->o.arg1 = 1<<(32-i); /* map length */ 2891571f8c1bSLuigi Rizzo d[0] = ntohl(d[0]); /* base addr in host format */ 28929758b77fSLuigi Rizzo cmd->o.opcode = O_IP_DST_SET; /* default */ 28939758b77fSLuigi Rizzo cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32) + (cmd->o.arg1+31)/32; 289461360012SLuigi Rizzo for (i = 0; i < (cmd->o.arg1+31)/32 ; i++) 2895571f8c1bSLuigi Rizzo map[i] = 0; /* clear map */ 28969758b77fSLuigi Rizzo 28979758b77fSLuigi Rizzo av = p + 1; 2898571f8c1bSLuigi Rizzo low = d[0] & 0xff; 28999758b77fSLuigi Rizzo high = low + cmd->o.arg1 - 1; 2900571f8c1bSLuigi Rizzo /* 2901571f8c1bSLuigi Rizzo * Here, i stores the previous value when we specify a range 2902571f8c1bSLuigi Rizzo * of addresses within a mask, e.g. 45-63. i = -1 means we 2903571f8c1bSLuigi Rizzo * have no previous value. 2904571f8c1bSLuigi Rizzo */ 29059ef3f16dSLuigi Rizzo i = -1; /* previous value in a range */ 29069758b77fSLuigi Rizzo while (isdigit(*av)) { 29079758b77fSLuigi Rizzo char *s; 2908571f8c1bSLuigi Rizzo int a = strtol(av, &s, 0); 29099758b77fSLuigi Rizzo 2910571f8c1bSLuigi Rizzo if (s == av) { /* no parameter */ 2911571f8c1bSLuigi Rizzo if (*av != '}') 2912571f8c1bSLuigi Rizzo errx(EX_DATAERR, "set not closed\n"); 2913571f8c1bSLuigi Rizzo if (i != -1) 2914571f8c1bSLuigi Rizzo errx(EX_DATAERR, "incomplete range %d-", i); 29159758b77fSLuigi Rizzo break; 29169758b77fSLuigi Rizzo } 2917571f8c1bSLuigi Rizzo if (a < low || a > high) 2918571f8c1bSLuigi Rizzo errx(EX_DATAERR, "addr %d out of range [%d-%d]\n", 2919571f8c1bSLuigi Rizzo a, low, high); 29209758b77fSLuigi Rizzo a -= low; 29219ef3f16dSLuigi Rizzo if (i == -1) /* no previous in range */ 29229ef3f16dSLuigi Rizzo i = a; 29239ef3f16dSLuigi Rizzo else { /* check that range is valid */ 29249ef3f16dSLuigi Rizzo if (i > a) 29259ef3f16dSLuigi Rizzo errx(EX_DATAERR, "invalid range %d-%d", 29269ef3f16dSLuigi Rizzo i+low, a+low); 29279ef3f16dSLuigi Rizzo if (*s == '-') 29289ef3f16dSLuigi Rizzo errx(EX_DATAERR, "double '-' in range"); 29299ef3f16dSLuigi Rizzo } 29309ef3f16dSLuigi Rizzo for (; i <= a; i++) 2931571f8c1bSLuigi Rizzo map[i/32] |= 1<<(i & 31); 29329ef3f16dSLuigi Rizzo i = -1; 29339ef3f16dSLuigi Rizzo if (*s == '-') 29349ef3f16dSLuigi Rizzo i = a; 2935571f8c1bSLuigi Rizzo else if (*s == '}') 29369758b77fSLuigi Rizzo break; 29379758b77fSLuigi Rizzo av = s+1; 29389758b77fSLuigi Rizzo } 29399758b77fSLuigi Rizzo return; 29409758b77fSLuigi Rizzo } 2941571f8c1bSLuigi Rizzo av = p; 2942571f8c1bSLuigi Rizzo if (av) /* then *av must be a ',' */ 2943571f8c1bSLuigi Rizzo av++; 29449758b77fSLuigi Rizzo 2945571f8c1bSLuigi Rizzo /* Check this entry */ 2946571f8c1bSLuigi Rizzo if (d[1] == 0) { /* "any", specified as x.x.x.x/0 */ 2947571f8c1bSLuigi Rizzo /* 2948571f8c1bSLuigi Rizzo * 'any' turns the entire list into a NOP. 2949571f8c1bSLuigi Rizzo * 'not any' never matches, so it is removed from the 2950571f8c1bSLuigi Rizzo * list unless it is the only item, in which case we 2951571f8c1bSLuigi Rizzo * report an error. 2952571f8c1bSLuigi Rizzo */ 2953571f8c1bSLuigi Rizzo if (cmd->o.len & F_NOT) { /* "not any" never matches */ 2954571f8c1bSLuigi Rizzo if (av == NULL && len == 0) /* only this entry */ 29559758b77fSLuigi Rizzo errx(EX_DATAERR, "not any never matches"); 2956571f8c1bSLuigi Rizzo } 2957571f8c1bSLuigi Rizzo /* else do nothing and skip this entry */ 295814533a98SMaxim Konovalov return; 2959571f8c1bSLuigi Rizzo } 2960571f8c1bSLuigi Rizzo /* A single IP can be stored in an optimized format */ 2961571f8c1bSLuigi Rizzo if (d[1] == IP_MASK_ALL && av == NULL && len == 0) { 29629758b77fSLuigi Rizzo cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32); 2963571f8c1bSLuigi Rizzo return; 2964571f8c1bSLuigi Rizzo } 2965571f8c1bSLuigi Rizzo len += 2; /* two words... */ 2966571f8c1bSLuigi Rizzo d += 2; 2967571f8c1bSLuigi Rizzo } /* end while */ 2968268f526cSJohn Hay if (len + 1 > F_LEN_MASK) 2969268f526cSJohn Hay errx(EX_DATAERR, "address list too long"); 2970571f8c1bSLuigi Rizzo cmd->o.len |= len+1; 29719758b77fSLuigi Rizzo } 29729758b77fSLuigi Rizzo 29739758b77fSLuigi Rizzo 29748195404bSBrooks Davis /* Try to find ipv6 address by hostname */ 29758195404bSBrooks Davis static int 29768195404bSBrooks Davis lookup_host6 (char *host, struct in6_addr *ip6addr) 29778195404bSBrooks Davis { 29788195404bSBrooks Davis struct hostent *he; 29798195404bSBrooks Davis 29808195404bSBrooks Davis if (!inet_pton(AF_INET6, host, ip6addr)) { 29818195404bSBrooks Davis if ((he = gethostbyname2(host, AF_INET6)) == NULL) 29828195404bSBrooks Davis return(-1); 29838195404bSBrooks Davis memcpy(ip6addr, he->h_addr_list[0], sizeof( struct in6_addr)); 29848195404bSBrooks Davis } 29858195404bSBrooks Davis return(0); 29868195404bSBrooks Davis } 29878195404bSBrooks Davis 29888195404bSBrooks Davis 29898195404bSBrooks Davis /* n2mask sets n bits of the mask */ 29908195404bSBrooks Davis static void 29918195404bSBrooks Davis n2mask(struct in6_addr *mask, int n) 29928195404bSBrooks Davis { 29938195404bSBrooks Davis static int minimask[9] = 29948195404bSBrooks Davis { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff }; 29958195404bSBrooks Davis u_char *p; 29968195404bSBrooks Davis 29978195404bSBrooks Davis memset(mask, 0, sizeof(struct in6_addr)); 29988195404bSBrooks Davis p = (u_char *) mask; 29998195404bSBrooks Davis for (; n > 0; p++, n -= 8) { 30008195404bSBrooks Davis if (n >= 8) 30018195404bSBrooks Davis *p = 0xff; 30028195404bSBrooks Davis else 30038195404bSBrooks Davis *p = minimask[n]; 30048195404bSBrooks Davis } 30058195404bSBrooks Davis return; 30068195404bSBrooks Davis } 30078195404bSBrooks Davis 30088195404bSBrooks Davis 30098195404bSBrooks Davis /* 30108195404bSBrooks Davis * fill the addr and mask fields in the instruction as appropriate from av. 30118195404bSBrooks Davis * Update length as appropriate. 30128195404bSBrooks Davis * The following formats are allowed: 30138195404bSBrooks Davis * any matches any IP6. Actually returns an empty instruction. 30148195404bSBrooks Davis * me returns O_IP6_*_ME 30158195404bSBrooks Davis * 30168195404bSBrooks Davis * 03f1::234:123:0342 single IP6 addres 30178195404bSBrooks Davis * 03f1::234:123:0342/24 address/mask 30188195404bSBrooks Davis * 03f1::234:123:0342/24,03f1::234:123:0343/ List of address 30198195404bSBrooks Davis * 30208195404bSBrooks Davis * Set of address (as in ipv6) not supported because ipv6 address 30218195404bSBrooks Davis * are typically random past the initial prefix. 30228195404bSBrooks Davis * Return 1 on success, 0 on failure. 30238195404bSBrooks Davis */ 30248195404bSBrooks Davis static int 30258195404bSBrooks Davis fill_ip6(ipfw_insn_ip6 *cmd, char *av) 30268195404bSBrooks Davis { 30278195404bSBrooks Davis int len = 0; 30288195404bSBrooks Davis struct in6_addr *d = &(cmd->addr6); 30298195404bSBrooks Davis /* 30308195404bSBrooks Davis * Needed for multiple address. 30318195404bSBrooks Davis * Note d[1] points to struct in6_add r mask6 of cmd 30328195404bSBrooks Davis */ 30338195404bSBrooks Davis 30348195404bSBrooks Davis cmd->o.len &= ~F_LEN_MASK; /* zero len */ 30358195404bSBrooks Davis 30368195404bSBrooks Davis if (strcmp(av, "any") == 0) 30378195404bSBrooks Davis return (1); 30388195404bSBrooks Davis 30398195404bSBrooks Davis 30408195404bSBrooks Davis if (strcmp(av, "me") == 0) { /* Set the data for "me" opt*/ 30418195404bSBrooks Davis cmd->o.len |= F_INSN_SIZE(ipfw_insn); 30428195404bSBrooks Davis return (1); 30438195404bSBrooks Davis } 30448195404bSBrooks Davis 30458195404bSBrooks Davis if (strcmp(av, "me6") == 0) { /* Set the data for "me" opt*/ 30468195404bSBrooks Davis cmd->o.len |= F_INSN_SIZE(ipfw_insn); 30478195404bSBrooks Davis return (1); 30488195404bSBrooks Davis } 30498195404bSBrooks Davis 30508195404bSBrooks Davis av = strdup(av); 30518195404bSBrooks Davis while (av) { 30528195404bSBrooks Davis /* 30538195404bSBrooks Davis * After the address we can have '/' indicating a mask, 30548195404bSBrooks Davis * or ',' indicating another address follows. 30558195404bSBrooks Davis */ 30568195404bSBrooks Davis 30578195404bSBrooks Davis char *p; 30588195404bSBrooks Davis int masklen; 30598195404bSBrooks Davis char md = '\0'; 30608195404bSBrooks Davis 30618195404bSBrooks Davis if ((p = strpbrk(av, "/,")) ) { 30628195404bSBrooks Davis md = *p; /* save the separator */ 30638195404bSBrooks Davis *p = '\0'; /* terminate address string */ 30648195404bSBrooks Davis p++; /* and skip past it */ 30658195404bSBrooks Davis } 30668195404bSBrooks Davis /* now p points to NULL, mask or next entry */ 30678195404bSBrooks Davis 30688195404bSBrooks Davis /* lookup stores address in *d as a side effect */ 30698195404bSBrooks Davis if (lookup_host6(av, d) != 0) { 30708195404bSBrooks Davis /* XXX: failed. Free memory and go */ 30718195404bSBrooks Davis errx(EX_DATAERR, "bad address \"%s\"", av); 30728195404bSBrooks Davis } 30738195404bSBrooks Davis /* next, look at the mask, if any */ 30748195404bSBrooks Davis masklen = (md == '/') ? atoi(p) : 128; 30758195404bSBrooks Davis if (masklen > 128 || masklen < 0) 30768195404bSBrooks Davis errx(EX_DATAERR, "bad width \"%s\''", p); 30778195404bSBrooks Davis else 30788195404bSBrooks Davis n2mask(&d[1], masklen); 30798195404bSBrooks Davis 30808195404bSBrooks Davis APPLY_MASK(d, &d[1]) /* mask base address with mask */ 30818195404bSBrooks Davis 30828195404bSBrooks Davis /* find next separator */ 30838195404bSBrooks Davis 30848195404bSBrooks Davis if (md == '/') { /* find separator past the mask */ 30858195404bSBrooks Davis p = strpbrk(p, ","); 30868195404bSBrooks Davis if (p != NULL) 30878195404bSBrooks Davis p++; 30888195404bSBrooks Davis } 30898195404bSBrooks Davis av = p; 30908195404bSBrooks Davis 30918195404bSBrooks Davis /* Check this entry */ 30928195404bSBrooks Davis if (masklen == 0) { 30938195404bSBrooks Davis /* 30948195404bSBrooks Davis * 'any' turns the entire list into a NOP. 30958195404bSBrooks Davis * 'not any' never matches, so it is removed from the 30968195404bSBrooks Davis * list unless it is the only item, in which case we 30978195404bSBrooks Davis * report an error. 30988195404bSBrooks Davis */ 30998195404bSBrooks Davis if (cmd->o.len & F_NOT && av == NULL && len == 0) 31008195404bSBrooks Davis errx(EX_DATAERR, "not any never matches"); 31018195404bSBrooks Davis continue; 31028195404bSBrooks Davis } 31038195404bSBrooks Davis 31048195404bSBrooks Davis /* 31058195404bSBrooks Davis * A single IP can be stored alone 31068195404bSBrooks Davis */ 31078195404bSBrooks Davis if (masklen == 128 && av == NULL && len == 0) { 31088195404bSBrooks Davis len = F_INSN_SIZE(struct in6_addr); 31098195404bSBrooks Davis break; 31108195404bSBrooks Davis } 31118195404bSBrooks Davis 31128195404bSBrooks Davis /* Update length and pointer to arguments */ 31138195404bSBrooks Davis len += F_INSN_SIZE(struct in6_addr)*2; 31148195404bSBrooks Davis d += 2; 31158195404bSBrooks Davis } /* end while */ 31168195404bSBrooks Davis 31178195404bSBrooks Davis /* 31188195404bSBrooks Davis * Total length of the command, remember that 1 is the size of 31198195404bSBrooks Davis * the base command. 31208195404bSBrooks Davis */ 3121268f526cSJohn Hay if (len + 1 > F_LEN_MASK) 3122268f526cSJohn Hay errx(EX_DATAERR, "address list too long"); 31238195404bSBrooks Davis cmd->o.len |= len+1; 31248195404bSBrooks Davis free(av); 31258195404bSBrooks Davis return (1); 31268195404bSBrooks Davis } 31278195404bSBrooks Davis 31288195404bSBrooks Davis /* 31298195404bSBrooks Davis * fills command for ipv6 flow-id filtering 31308195404bSBrooks Davis * note that the 20 bit flow number is stored in a array of u_int32_t 31318195404bSBrooks Davis * it's supported lists of flow-id, so in the o.arg1 we store how many 31328195404bSBrooks Davis * additional flow-id we want to filter, the basic is 1 31338195404bSBrooks Davis */ 3134daa9733aSLuigi Rizzo static void 31358195404bSBrooks Davis fill_flow6( ipfw_insn_u32 *cmd, char *av ) 31368195404bSBrooks Davis { 31378195404bSBrooks Davis u_int32_t type; /* Current flow number */ 31388195404bSBrooks Davis u_int16_t nflow = 0; /* Current flow index */ 31398195404bSBrooks Davis char *s = av; 31408195404bSBrooks Davis cmd->d[0] = 0; /* Initializing the base number*/ 31418195404bSBrooks Davis 31428195404bSBrooks Davis while (s) { 31438195404bSBrooks Davis av = strsep( &s, ",") ; 31448195404bSBrooks Davis type = strtoul(av, &av, 0); 31458195404bSBrooks Davis if (*av != ',' && *av != '\0') 31468195404bSBrooks Davis errx(EX_DATAERR, "invalid ipv6 flow number %s", av); 31478195404bSBrooks Davis if (type > 0xfffff) 31488195404bSBrooks Davis errx(EX_DATAERR, "flow number out of range %s", av); 31498195404bSBrooks Davis cmd->d[nflow] |= type; 31508195404bSBrooks Davis nflow++; 31518195404bSBrooks Davis } 31528195404bSBrooks Davis if( nflow > 0 ) { 31538195404bSBrooks Davis cmd->o.opcode = O_FLOW6ID; 31548195404bSBrooks Davis cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32) + nflow; 31558195404bSBrooks Davis cmd->o.arg1 = nflow; 31568195404bSBrooks Davis } 31578195404bSBrooks Davis else { 31588195404bSBrooks Davis errx(EX_DATAERR, "invalid ipv6 flow number %s", av); 31598195404bSBrooks Davis } 31608195404bSBrooks Davis } 31618195404bSBrooks Davis 31628195404bSBrooks Davis static ipfw_insn * 31638195404bSBrooks Davis add_srcip6(ipfw_insn *cmd, char *av) 31648195404bSBrooks Davis { 31658195404bSBrooks Davis 31668195404bSBrooks Davis fill_ip6((ipfw_insn_ip6 *)cmd, av); 3167daa9733aSLuigi Rizzo if (F_LEN(cmd) == 0) { /* any */ 3168daa9733aSLuigi Rizzo } else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) { /* "me" */ 31698195404bSBrooks Davis cmd->opcode = O_IP6_SRC_ME; 31708195404bSBrooks Davis } else if (F_LEN(cmd) == 31718195404bSBrooks Davis (F_INSN_SIZE(struct in6_addr) + F_INSN_SIZE(ipfw_insn))) { 31728195404bSBrooks Davis /* single IP, no mask*/ 31738195404bSBrooks Davis cmd->opcode = O_IP6_SRC; 31748195404bSBrooks Davis } else { /* addr/mask opt */ 31758195404bSBrooks Davis cmd->opcode = O_IP6_SRC_MASK; 31768195404bSBrooks Davis } 31778195404bSBrooks Davis return cmd; 31788195404bSBrooks Davis } 31798195404bSBrooks Davis 31808195404bSBrooks Davis static ipfw_insn * 31818195404bSBrooks Davis add_dstip6(ipfw_insn *cmd, char *av) 31828195404bSBrooks Davis { 31838195404bSBrooks Davis 31848195404bSBrooks Davis fill_ip6((ipfw_insn_ip6 *)cmd, av); 3185daa9733aSLuigi Rizzo if (F_LEN(cmd) == 0) { /* any */ 3186daa9733aSLuigi Rizzo } else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) { /* "me" */ 31878195404bSBrooks Davis cmd->opcode = O_IP6_DST_ME; 31888195404bSBrooks Davis } else if (F_LEN(cmd) == 31898195404bSBrooks Davis (F_INSN_SIZE(struct in6_addr) + F_INSN_SIZE(ipfw_insn))) { 31908195404bSBrooks Davis /* single IP, no mask*/ 31918195404bSBrooks Davis cmd->opcode = O_IP6_DST; 31928195404bSBrooks Davis } else { /* addr/mask opt */ 31938195404bSBrooks Davis cmd->opcode = O_IP6_DST_MASK; 31948195404bSBrooks Davis } 31958195404bSBrooks Davis return cmd; 31968195404bSBrooks Davis } 31978195404bSBrooks Davis 31988195404bSBrooks Davis 31999758b77fSLuigi Rizzo /* 32009758b77fSLuigi Rizzo * helper function to process a set of flags and set bits in the 32019758b77fSLuigi Rizzo * appropriate masks. 32029758b77fSLuigi Rizzo */ 32039758b77fSLuigi Rizzo static void 32049758b77fSLuigi Rizzo fill_flags(ipfw_insn *cmd, enum ipfw_opcodes opcode, 32059758b77fSLuigi Rizzo struct _s_x *flags, char *p) 32069758b77fSLuigi Rizzo { 3207571f8c1bSLuigi Rizzo uint8_t set=0, clear=0; 32089758b77fSLuigi Rizzo 32099758b77fSLuigi Rizzo while (p && *p) { 32109758b77fSLuigi Rizzo char *q; /* points to the separator */ 32119758b77fSLuigi Rizzo int val; 3212571f8c1bSLuigi Rizzo uint8_t *which; /* mask we are working on */ 32139758b77fSLuigi Rizzo 32149758b77fSLuigi Rizzo if (*p == '!') { 32159758b77fSLuigi Rizzo p++; 32169758b77fSLuigi Rizzo which = &clear; 32179758b77fSLuigi Rizzo } else 32189758b77fSLuigi Rizzo which = &set; 32199758b77fSLuigi Rizzo q = strchr(p, ','); 32209758b77fSLuigi Rizzo if (q) 32219758b77fSLuigi Rizzo *q++ = '\0'; 32229758b77fSLuigi Rizzo val = match_token(flags, p); 32239758b77fSLuigi Rizzo if (val <= 0) 32249758b77fSLuigi Rizzo errx(EX_DATAERR, "invalid flag %s", p); 3225571f8c1bSLuigi Rizzo *which |= (uint8_t)val; 32269758b77fSLuigi Rizzo p = q; 32279758b77fSLuigi Rizzo } 32289758b77fSLuigi Rizzo cmd->opcode = opcode; 32299758b77fSLuigi Rizzo cmd->len = (cmd->len & (F_NOT | F_OR)) | 1; 32309758b77fSLuigi Rizzo cmd->arg1 = (set & 0xff) | ( (clear & 0xff) << 8); 32319758b77fSLuigi Rizzo } 32329758b77fSLuigi Rizzo 32339758b77fSLuigi Rizzo 32349758b77fSLuigi Rizzo static void 32359758b77fSLuigi Rizzo delete(int ac, char *av[]) 32369758b77fSLuigi Rizzo { 3237571f8c1bSLuigi Rizzo uint32_t rulenum; 323862ff38aeSLuigi Rizzo struct dn_pipe p; 32399758b77fSLuigi Rizzo int i; 32409758b77fSLuigi Rizzo int exitval = EX_OK; 324143405724SLuigi Rizzo int do_set = 0; 32429758b77fSLuigi Rizzo 324362ff38aeSLuigi Rizzo memset(&p, 0, sizeof p); 32449758b77fSLuigi Rizzo 32459758b77fSLuigi Rizzo av++; ac--; 324604f70834SChristian S.J. Peron NEED1("missing rule specification"); 324701750186SBrooks Davis if (ac > 0 && _substrcmp(*av, "set") == 0) { 3248d069a5d4SMaxim Konovalov /* Do not allow using the following syntax: 3249d069a5d4SMaxim Konovalov * ipfw set N delete set M 3250d069a5d4SMaxim Konovalov */ 3251d069a5d4SMaxim Konovalov if (use_set) 3252d069a5d4SMaxim Konovalov errx(EX_DATAERR, "invalid syntax"); 325343405724SLuigi Rizzo do_set = 1; /* delete set */ 325443405724SLuigi Rizzo ac--; av++; 325599e5e645SLuigi Rizzo } 32569758b77fSLuigi Rizzo 32579758b77fSLuigi Rizzo /* Rule number */ 32589758b77fSLuigi Rizzo while (ac && isdigit(**av)) { 32599758b77fSLuigi Rizzo i = atoi(*av); av++; ac--; 3260ff2f6fe8SPaolo Pisati if (do_nat) { 3261ff2f6fe8SPaolo Pisati exitval = do_cmd(IP_FW_NAT_DEL, &i, sizeof i); 3262ff2f6fe8SPaolo Pisati if (exitval) { 3263ff2f6fe8SPaolo Pisati exitval = EX_UNAVAILABLE; 3264ff2f6fe8SPaolo Pisati warn("rule %u not available", i); 3265ff2f6fe8SPaolo Pisati } 3266ff2f6fe8SPaolo Pisati } else if (do_pipe) { 32679758b77fSLuigi Rizzo if (do_pipe == 1) 326862ff38aeSLuigi Rizzo p.pipe_nr = i; 32699758b77fSLuigi Rizzo else 327062ff38aeSLuigi Rizzo p.fs.fs_nr = i; 327162ff38aeSLuigi Rizzo i = do_cmd(IP_DUMMYNET_DEL, &p, sizeof p); 32729758b77fSLuigi Rizzo if (i) { 32739758b77fSLuigi Rizzo exitval = 1; 32749758b77fSLuigi Rizzo warn("rule %u: setsockopt(IP_DUMMYNET_DEL)", 327562ff38aeSLuigi Rizzo do_pipe == 1 ? p.pipe_nr : p.fs.fs_nr); 32769758b77fSLuigi Rizzo } 32779758b77fSLuigi Rizzo } else { 3278d069a5d4SMaxim Konovalov if (use_set) 3279d069a5d4SMaxim Konovalov rulenum = (i & 0xffff) | (5 << 24) | 3280d069a5d4SMaxim Konovalov ((use_set - 1) << 16); 3281d069a5d4SMaxim Konovalov else 328299e5e645SLuigi Rizzo rulenum = (i & 0xffff) | (do_set << 24); 3283571f8c1bSLuigi Rizzo i = do_cmd(IP_FW_DEL, &rulenum, sizeof rulenum); 32849758b77fSLuigi Rizzo if (i) { 32859758b77fSLuigi Rizzo exitval = EX_UNAVAILABLE; 32869758b77fSLuigi Rizzo warn("rule %u: setsockopt(IP_FW_DEL)", 32879758b77fSLuigi Rizzo rulenum); 32889758b77fSLuigi Rizzo } 32899758b77fSLuigi Rizzo } 32909758b77fSLuigi Rizzo } 32919758b77fSLuigi Rizzo if (exitval != EX_OK) 32929758b77fSLuigi Rizzo exit(exitval); 32939758b77fSLuigi Rizzo } 32949758b77fSLuigi Rizzo 32959758b77fSLuigi Rizzo 32969758b77fSLuigi Rizzo /* 32979758b77fSLuigi Rizzo * fill the interface structure. We do not check the name as we can 32989758b77fSLuigi Rizzo * create interfaces dynamically, so checking them at insert time 32999758b77fSLuigi Rizzo * makes relatively little sense. 33009bf40edeSBrooks Davis * Interface names containing '*', '?', or '[' are assumed to be shell 33019bf40edeSBrooks Davis * patterns which match interfaces. 33029758b77fSLuigi Rizzo */ 33039758b77fSLuigi Rizzo static void 33049758b77fSLuigi Rizzo fill_iface(ipfw_insn_if *cmd, char *arg) 33059758b77fSLuigi Rizzo { 33069758b77fSLuigi Rizzo cmd->name[0] = '\0'; 33079758b77fSLuigi Rizzo cmd->o.len |= F_INSN_SIZE(ipfw_insn_if); 33089758b77fSLuigi Rizzo 33099758b77fSLuigi Rizzo /* Parse the interface or address */ 331001750186SBrooks Davis if (strcmp(arg, "any") == 0) 33119758b77fSLuigi Rizzo cmd->o.len = 0; /* effectively ignore this command */ 33129758b77fSLuigi Rizzo else if (!isdigit(*arg)) { 33139bf40edeSBrooks Davis strlcpy(cmd->name, arg, sizeof(cmd->name)); 33149bf40edeSBrooks Davis cmd->p.glob = strpbrk(arg, "*?[") != NULL ? 1 : 0; 33159758b77fSLuigi Rizzo } else if (!inet_aton(arg, &cmd->p.ip)) 33169758b77fSLuigi Rizzo errx(EX_DATAERR, "bad ip address ``%s''", arg); 33179758b77fSLuigi Rizzo } 33189758b77fSLuigi Rizzo 3319ff2f6fe8SPaolo Pisati /* 3320ff2f6fe8SPaolo Pisati * Search for interface with name "ifn", and fill n accordingly: 3321ff2f6fe8SPaolo Pisati * 3322ff2f6fe8SPaolo Pisati * n->ip ip address of interface "ifn" 3323ff2f6fe8SPaolo Pisati * n->if_name copy of interface name "ifn" 3324ff2f6fe8SPaolo Pisati */ 3325ff2f6fe8SPaolo Pisati static void 3326ff2f6fe8SPaolo Pisati set_addr_dynamic(const char *ifn, struct cfg_nat *n) 3327ff2f6fe8SPaolo Pisati { 3328ff2f6fe8SPaolo Pisati size_t needed; 3329ff2f6fe8SPaolo Pisati int mib[6]; 3330ff2f6fe8SPaolo Pisati char *buf, *lim, *next; 3331ff2f6fe8SPaolo Pisati struct if_msghdr *ifm; 3332ff2f6fe8SPaolo Pisati struct ifa_msghdr *ifam; 3333ff2f6fe8SPaolo Pisati struct sockaddr_dl *sdl; 3334ff2f6fe8SPaolo Pisati struct sockaddr_in *sin; 3335ff2f6fe8SPaolo Pisati int ifIndex, ifMTU; 3336ff2f6fe8SPaolo Pisati 3337ff2f6fe8SPaolo Pisati mib[0] = CTL_NET; 3338ff2f6fe8SPaolo Pisati mib[1] = PF_ROUTE; 3339ff2f6fe8SPaolo Pisati mib[2] = 0; 3340ff2f6fe8SPaolo Pisati mib[3] = AF_INET; 3341ff2f6fe8SPaolo Pisati mib[4] = NET_RT_IFLIST; 3342ff2f6fe8SPaolo Pisati mib[5] = 0; 3343ff2f6fe8SPaolo Pisati /* 3344ff2f6fe8SPaolo Pisati * Get interface data. 3345ff2f6fe8SPaolo Pisati */ 3346ff2f6fe8SPaolo Pisati if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1) 3347ff2f6fe8SPaolo Pisati err(1, "iflist-sysctl-estimate"); 33485f356082SLuigi Rizzo buf = safe_calloc(1, needed); 3349ff2f6fe8SPaolo Pisati if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1) 3350ff2f6fe8SPaolo Pisati err(1, "iflist-sysctl-get"); 3351ff2f6fe8SPaolo Pisati lim = buf + needed; 3352ff2f6fe8SPaolo Pisati /* 3353ff2f6fe8SPaolo Pisati * Loop through interfaces until one with 3354ff2f6fe8SPaolo Pisati * given name is found. This is done to 3355ff2f6fe8SPaolo Pisati * find correct interface index for routing 3356ff2f6fe8SPaolo Pisati * message processing. 3357ff2f6fe8SPaolo Pisati */ 3358ff2f6fe8SPaolo Pisati ifIndex = 0; 3359ff2f6fe8SPaolo Pisati next = buf; 3360ff2f6fe8SPaolo Pisati while (next < lim) { 3361ff2f6fe8SPaolo Pisati ifm = (struct if_msghdr *)next; 3362ff2f6fe8SPaolo Pisati next += ifm->ifm_msglen; 3363ff2f6fe8SPaolo Pisati if (ifm->ifm_version != RTM_VERSION) { 3364ff2f6fe8SPaolo Pisati if (verbose) 3365ff2f6fe8SPaolo Pisati warnx("routing message version %d " 3366ff2f6fe8SPaolo Pisati "not understood", ifm->ifm_version); 3367ff2f6fe8SPaolo Pisati continue; 3368ff2f6fe8SPaolo Pisati } 3369ff2f6fe8SPaolo Pisati if (ifm->ifm_type == RTM_IFINFO) { 3370ff2f6fe8SPaolo Pisati sdl = (struct sockaddr_dl *)(ifm + 1); 3371ff2f6fe8SPaolo Pisati if (strlen(ifn) == sdl->sdl_nlen && 3372ff2f6fe8SPaolo Pisati strncmp(ifn, sdl->sdl_data, sdl->sdl_nlen) == 0) { 3373ff2f6fe8SPaolo Pisati ifIndex = ifm->ifm_index; 3374ff2f6fe8SPaolo Pisati ifMTU = ifm->ifm_data.ifi_mtu; 3375ff2f6fe8SPaolo Pisati break; 3376ff2f6fe8SPaolo Pisati } 3377ff2f6fe8SPaolo Pisati } 3378ff2f6fe8SPaolo Pisati } 3379ff2f6fe8SPaolo Pisati if (!ifIndex) 3380ff2f6fe8SPaolo Pisati errx(1, "unknown interface name %s", ifn); 3381ff2f6fe8SPaolo Pisati /* 3382ff2f6fe8SPaolo Pisati * Get interface address. 3383ff2f6fe8SPaolo Pisati */ 3384ff2f6fe8SPaolo Pisati sin = NULL; 3385ff2f6fe8SPaolo Pisati while (next < lim) { 3386ff2f6fe8SPaolo Pisati ifam = (struct ifa_msghdr *)next; 3387ff2f6fe8SPaolo Pisati next += ifam->ifam_msglen; 3388ff2f6fe8SPaolo Pisati if (ifam->ifam_version != RTM_VERSION) { 3389ff2f6fe8SPaolo Pisati if (verbose) 3390ff2f6fe8SPaolo Pisati warnx("routing message version %d " 3391ff2f6fe8SPaolo Pisati "not understood", ifam->ifam_version); 3392ff2f6fe8SPaolo Pisati continue; 3393ff2f6fe8SPaolo Pisati } 3394ff2f6fe8SPaolo Pisati if (ifam->ifam_type != RTM_NEWADDR) 3395ff2f6fe8SPaolo Pisati break; 3396ff2f6fe8SPaolo Pisati if (ifam->ifam_addrs & RTA_IFA) { 3397ff2f6fe8SPaolo Pisati int i; 3398ff2f6fe8SPaolo Pisati char *cp = (char *)(ifam + 1); 3399ff2f6fe8SPaolo Pisati 3400ff2f6fe8SPaolo Pisati for (i = 1; i < RTA_IFA; i <<= 1) { 3401ff2f6fe8SPaolo Pisati if (ifam->ifam_addrs & i) 3402ff2f6fe8SPaolo Pisati cp += SA_SIZE((struct sockaddr *)cp); 3403ff2f6fe8SPaolo Pisati } 3404ff2f6fe8SPaolo Pisati if (((struct sockaddr *)cp)->sa_family == AF_INET) { 3405ff2f6fe8SPaolo Pisati sin = (struct sockaddr_in *)cp; 3406ff2f6fe8SPaolo Pisati break; 3407ff2f6fe8SPaolo Pisati } 3408ff2f6fe8SPaolo Pisati } 3409ff2f6fe8SPaolo Pisati } 3410ff2f6fe8SPaolo Pisati if (sin == NULL) 3411ff2f6fe8SPaolo Pisati errx(1, "%s: cannot get interface address", ifn); 3412ff2f6fe8SPaolo Pisati 3413ff2f6fe8SPaolo Pisati n->ip = sin->sin_addr; 3414ff2f6fe8SPaolo Pisati strncpy(n->if_name, ifn, IF_NAMESIZE); 3415ff2f6fe8SPaolo Pisati 3416ff2f6fe8SPaolo Pisati free(buf); 3417ff2f6fe8SPaolo Pisati } 3418ff2f6fe8SPaolo Pisati 3419ff2f6fe8SPaolo Pisati /* 3420ff2f6fe8SPaolo Pisati * XXX - The following functions, macros and definitions come from natd.c: 3421ff2f6fe8SPaolo Pisati * it would be better to move them outside natd.c, in a file 3422ff2f6fe8SPaolo Pisati * (redirect_support.[ch]?) shared by ipfw and natd, but for now i can live 3423ff2f6fe8SPaolo Pisati * with it. 3424ff2f6fe8SPaolo Pisati */ 3425ff2f6fe8SPaolo Pisati 3426ff2f6fe8SPaolo Pisati /* 3427ff2f6fe8SPaolo Pisati * Definition of a port range, and macros to deal with values. 3428ff2f6fe8SPaolo Pisati * FORMAT: HI 16-bits == first port in range, 0 == all ports. 3429ff2f6fe8SPaolo Pisati * LO 16-bits == number of ports in range 3430ff2f6fe8SPaolo Pisati * NOTES: - Port values are not stored in network byte order. 3431ff2f6fe8SPaolo Pisati */ 3432ff2f6fe8SPaolo Pisati 3433ff2f6fe8SPaolo Pisati #define port_range u_long 3434ff2f6fe8SPaolo Pisati 3435ff2f6fe8SPaolo Pisati #define GETLOPORT(x) ((x) >> 0x10) 3436ff2f6fe8SPaolo Pisati #define GETNUMPORTS(x) ((x) & 0x0000ffff) 3437ff2f6fe8SPaolo Pisati #define GETHIPORT(x) (GETLOPORT((x)) + GETNUMPORTS((x))) 3438ff2f6fe8SPaolo Pisati 3439ff2f6fe8SPaolo Pisati /* Set y to be the low-port value in port_range variable x. */ 3440ff2f6fe8SPaolo Pisati #define SETLOPORT(x,y) ((x) = ((x) & 0x0000ffff) | ((y) << 0x10)) 3441ff2f6fe8SPaolo Pisati 3442ff2f6fe8SPaolo Pisati /* Set y to be the number of ports in port_range variable x. */ 3443ff2f6fe8SPaolo Pisati #define SETNUMPORTS(x,y) ((x) = ((x) & 0xffff0000) | (y)) 3444ff2f6fe8SPaolo Pisati 3445ff2f6fe8SPaolo Pisati static void 3446ff2f6fe8SPaolo Pisati StrToAddr (const char* str, struct in_addr* addr) 3447ff2f6fe8SPaolo Pisati { 3448ff2f6fe8SPaolo Pisati struct hostent* hp; 3449ff2f6fe8SPaolo Pisati 3450ff2f6fe8SPaolo Pisati if (inet_aton (str, addr)) 3451ff2f6fe8SPaolo Pisati return; 3452ff2f6fe8SPaolo Pisati 3453ff2f6fe8SPaolo Pisati hp = gethostbyname (str); 3454ff2f6fe8SPaolo Pisati if (!hp) 3455ff2f6fe8SPaolo Pisati errx (1, "unknown host %s", str); 3456ff2f6fe8SPaolo Pisati 3457ff2f6fe8SPaolo Pisati memcpy (addr, hp->h_addr, sizeof (struct in_addr)); 3458ff2f6fe8SPaolo Pisati } 3459ff2f6fe8SPaolo Pisati 3460ff2f6fe8SPaolo Pisati static int 3461ff2f6fe8SPaolo Pisati StrToPortRange (const char* str, const char* proto, port_range *portRange) 3462ff2f6fe8SPaolo Pisati { 3463ff2f6fe8SPaolo Pisati char* sep; 3464ff2f6fe8SPaolo Pisati struct servent* sp; 3465ff2f6fe8SPaolo Pisati char* end; 3466ff2f6fe8SPaolo Pisati u_short loPort; 3467ff2f6fe8SPaolo Pisati u_short hiPort; 3468ff2f6fe8SPaolo Pisati 3469ff2f6fe8SPaolo Pisati /* First see if this is a service, return corresponding port if so. */ 3470ff2f6fe8SPaolo Pisati sp = getservbyname (str,proto); 3471ff2f6fe8SPaolo Pisati if (sp) { 3472ff2f6fe8SPaolo Pisati SETLOPORT(*portRange, ntohs(sp->s_port)); 3473ff2f6fe8SPaolo Pisati SETNUMPORTS(*portRange, 1); 3474ff2f6fe8SPaolo Pisati return 0; 3475ff2f6fe8SPaolo Pisati } 3476ff2f6fe8SPaolo Pisati 3477ff2f6fe8SPaolo Pisati /* Not a service, see if it's a single port or port range. */ 3478ff2f6fe8SPaolo Pisati sep = strchr (str, '-'); 3479ff2f6fe8SPaolo Pisati if (sep == NULL) { 3480ff2f6fe8SPaolo Pisati SETLOPORT(*portRange, strtol(str, &end, 10)); 3481ff2f6fe8SPaolo Pisati if (end != str) { 3482ff2f6fe8SPaolo Pisati /* Single port. */ 3483ff2f6fe8SPaolo Pisati SETNUMPORTS(*portRange, 1); 3484ff2f6fe8SPaolo Pisati return 0; 3485ff2f6fe8SPaolo Pisati } 3486ff2f6fe8SPaolo Pisati 3487ff2f6fe8SPaolo Pisati /* Error in port range field. */ 3488ff2f6fe8SPaolo Pisati errx (EX_DATAERR, "%s/%s: unknown service", str, proto); 3489ff2f6fe8SPaolo Pisati } 3490ff2f6fe8SPaolo Pisati 3491ff2f6fe8SPaolo Pisati /* Port range, get the values and sanity check. */ 3492ff2f6fe8SPaolo Pisati sscanf (str, "%hu-%hu", &loPort, &hiPort); 3493ff2f6fe8SPaolo Pisati SETLOPORT(*portRange, loPort); 3494ff2f6fe8SPaolo Pisati SETNUMPORTS(*portRange, 0); /* Error by default */ 3495ff2f6fe8SPaolo Pisati if (loPort <= hiPort) 3496ff2f6fe8SPaolo Pisati SETNUMPORTS(*portRange, hiPort - loPort + 1); 3497ff2f6fe8SPaolo Pisati 3498ff2f6fe8SPaolo Pisati if (GETNUMPORTS(*portRange) == 0) 3499ff2f6fe8SPaolo Pisati errx (EX_DATAERR, "invalid port range %s", str); 3500ff2f6fe8SPaolo Pisati 3501ff2f6fe8SPaolo Pisati return 0; 3502ff2f6fe8SPaolo Pisati } 3503ff2f6fe8SPaolo Pisati 3504ff2f6fe8SPaolo Pisati static int 3505ff2f6fe8SPaolo Pisati StrToProto (const char* str) 3506ff2f6fe8SPaolo Pisati { 3507ff2f6fe8SPaolo Pisati if (!strcmp (str, "tcp")) 3508ff2f6fe8SPaolo Pisati return IPPROTO_TCP; 3509ff2f6fe8SPaolo Pisati 3510ff2f6fe8SPaolo Pisati if (!strcmp (str, "udp")) 3511ff2f6fe8SPaolo Pisati return IPPROTO_UDP; 3512ff2f6fe8SPaolo Pisati 3513ff2f6fe8SPaolo Pisati errx (EX_DATAERR, "unknown protocol %s. Expected tcp or udp", str); 3514ff2f6fe8SPaolo Pisati } 3515ff2f6fe8SPaolo Pisati 3516ff2f6fe8SPaolo Pisati static int 3517ff2f6fe8SPaolo Pisati StrToAddrAndPortRange (const char* str, struct in_addr* addr, char* proto, 3518ff2f6fe8SPaolo Pisati port_range *portRange) 3519ff2f6fe8SPaolo Pisati { 3520ff2f6fe8SPaolo Pisati char* ptr; 3521ff2f6fe8SPaolo Pisati 3522ff2f6fe8SPaolo Pisati ptr = strchr (str, ':'); 3523ff2f6fe8SPaolo Pisati if (!ptr) 3524ff2f6fe8SPaolo Pisati errx (EX_DATAERR, "%s is missing port number", str); 3525ff2f6fe8SPaolo Pisati 3526ff2f6fe8SPaolo Pisati *ptr = '\0'; 3527ff2f6fe8SPaolo Pisati ++ptr; 3528ff2f6fe8SPaolo Pisati 3529ff2f6fe8SPaolo Pisati StrToAddr (str, addr); 3530ff2f6fe8SPaolo Pisati return StrToPortRange (ptr, proto, portRange); 3531ff2f6fe8SPaolo Pisati } 3532ff2f6fe8SPaolo Pisati 3533ff2f6fe8SPaolo Pisati /* End of stuff taken from natd.c. */ 3534ff2f6fe8SPaolo Pisati 3535ff2f6fe8SPaolo Pisati #define INC_ARGCV() do { \ 3536ff2f6fe8SPaolo Pisati (*_av)++; \ 3537ff2f6fe8SPaolo Pisati (*_ac)--; \ 3538ff2f6fe8SPaolo Pisati av = *_av; \ 3539ff2f6fe8SPaolo Pisati ac = *_ac; \ 3540ff2f6fe8SPaolo Pisati } while(0) 3541ff2f6fe8SPaolo Pisati 3542ff2f6fe8SPaolo Pisati /* 3543ff2f6fe8SPaolo Pisati * The next 3 functions add support for the addr, port and proto redirect and 3544ff2f6fe8SPaolo Pisati * their logic is loosely based on SetupAddressRedirect(), SetupPortRedirect() 3545ff2f6fe8SPaolo Pisati * and SetupProtoRedirect() from natd.c. 3546ff2f6fe8SPaolo Pisati * 3547ff2f6fe8SPaolo Pisati * Every setup_* function fills at least one redirect entry 3548ff2f6fe8SPaolo Pisati * (struct cfg_redir) and zero or more server pool entry (struct cfg_spool) 3549ff2f6fe8SPaolo Pisati * in buf. 3550ff2f6fe8SPaolo Pisati * 3551ff2f6fe8SPaolo Pisati * The format of data in buf is: 3552ff2f6fe8SPaolo Pisati * 3553ff2f6fe8SPaolo Pisati * 3554ff2f6fe8SPaolo Pisati * cfg_nat cfg_redir cfg_spool ...... cfg_spool 3555ff2f6fe8SPaolo Pisati * 3556ff2f6fe8SPaolo Pisati * ------------------------------------- ------------ 3557ff2f6fe8SPaolo Pisati * | | .....X ... | | | | ..... 3558ff2f6fe8SPaolo Pisati * ------------------------------------- ...... ------------ 3559ff2f6fe8SPaolo Pisati * ^ 3560ff2f6fe8SPaolo Pisati * spool_cnt n=0 ...... n=(X-1) 3561ff2f6fe8SPaolo Pisati * 3562ff2f6fe8SPaolo Pisati * len points to the amount of available space in buf 3563ff2f6fe8SPaolo Pisati * space counts the memory consumed by every function 3564ff2f6fe8SPaolo Pisati * 3565ff2f6fe8SPaolo Pisati * XXX - Every function get all the argv params so it 3566ff2f6fe8SPaolo Pisati * has to check, in optional parameters, that the next 3567ff2f6fe8SPaolo Pisati * args is a valid option for the redir entry and not 3568ff2f6fe8SPaolo Pisati * another token. Only redir_port and redir_proto are 3569ff2f6fe8SPaolo Pisati * affected by this. 3570ff2f6fe8SPaolo Pisati */ 3571ff2f6fe8SPaolo Pisati 3572ff2f6fe8SPaolo Pisati static int 3573ff2f6fe8SPaolo Pisati setup_redir_addr(char *spool_buf, int len, 3574ff2f6fe8SPaolo Pisati int *_ac, char ***_av) 3575ff2f6fe8SPaolo Pisati { 3576ff2f6fe8SPaolo Pisati char **av, *sep; /* Token separator. */ 3577ff2f6fe8SPaolo Pisati /* Temporary buffer used to hold server pool ip's. */ 3578ff2f6fe8SPaolo Pisati char tmp_spool_buf[NAT_BUF_LEN]; 3579015002dfSRoman Kurakin int ac, space, lsnat; 3580ff2f6fe8SPaolo Pisati struct cfg_redir *r; 3581ff2f6fe8SPaolo Pisati struct cfg_spool *tmp; 3582ff2f6fe8SPaolo Pisati 3583ff2f6fe8SPaolo Pisati av = *_av; 3584ff2f6fe8SPaolo Pisati ac = *_ac; 3585ff2f6fe8SPaolo Pisati space = 0; 3586ff2f6fe8SPaolo Pisati lsnat = 0; 3587ff2f6fe8SPaolo Pisati if (len >= SOF_REDIR) { 3588ff2f6fe8SPaolo Pisati r = (struct cfg_redir *)spool_buf; 3589ff2f6fe8SPaolo Pisati /* Skip cfg_redir at beginning of buf. */ 3590ff2f6fe8SPaolo Pisati spool_buf = &spool_buf[SOF_REDIR]; 3591ff2f6fe8SPaolo Pisati space = SOF_REDIR; 3592ff2f6fe8SPaolo Pisati len -= SOF_REDIR; 3593ff2f6fe8SPaolo Pisati } else 3594ff2f6fe8SPaolo Pisati goto nospace; 3595ff2f6fe8SPaolo Pisati r->mode = REDIR_ADDR; 3596ff2f6fe8SPaolo Pisati /* Extract local address. */ 3597ff2f6fe8SPaolo Pisati if (ac == 0) 3598ff2f6fe8SPaolo Pisati errx(EX_DATAERR, "redirect_addr: missing local address"); 3599ff2f6fe8SPaolo Pisati sep = strchr(*av, ','); 3600ff2f6fe8SPaolo Pisati if (sep) { /* LSNAT redirection syntax. */ 3601ff2f6fe8SPaolo Pisati r->laddr.s_addr = INADDR_NONE; 3602ff2f6fe8SPaolo Pisati /* Preserve av, copy spool servers to tmp_spool_buf. */ 3603ff2f6fe8SPaolo Pisati strncpy(tmp_spool_buf, *av, strlen(*av)+1); 3604ff2f6fe8SPaolo Pisati lsnat = 1; 3605ff2f6fe8SPaolo Pisati } else 3606ff2f6fe8SPaolo Pisati StrToAddr(*av, &r->laddr); 3607ff2f6fe8SPaolo Pisati INC_ARGCV(); 3608ff2f6fe8SPaolo Pisati 3609ff2f6fe8SPaolo Pisati /* Extract public address. */ 3610ff2f6fe8SPaolo Pisati if (ac == 0) 3611ff2f6fe8SPaolo Pisati errx(EX_DATAERR, "redirect_addr: missing public address"); 3612ff2f6fe8SPaolo Pisati StrToAddr(*av, &r->paddr); 3613ff2f6fe8SPaolo Pisati INC_ARGCV(); 3614ff2f6fe8SPaolo Pisati 3615ff2f6fe8SPaolo Pisati /* Setup LSNAT server pool. */ 3616ff2f6fe8SPaolo Pisati if (sep) { 3617ff2f6fe8SPaolo Pisati sep = strtok(tmp_spool_buf, ","); 3618ff2f6fe8SPaolo Pisati while (sep != NULL) { 3619ff2f6fe8SPaolo Pisati tmp = (struct cfg_spool *)spool_buf; 3620ff2f6fe8SPaolo Pisati if (len < SOF_SPOOL) 3621ff2f6fe8SPaolo Pisati goto nospace; 3622ff2f6fe8SPaolo Pisati len -= SOF_SPOOL; 3623ff2f6fe8SPaolo Pisati space += SOF_SPOOL; 3624ff2f6fe8SPaolo Pisati StrToAddr(sep, &tmp->addr); 3625ff2f6fe8SPaolo Pisati tmp->port = ~0; 3626ff2f6fe8SPaolo Pisati r->spool_cnt++; 3627ff2f6fe8SPaolo Pisati /* Point to the next possible cfg_spool. */ 3628ff2f6fe8SPaolo Pisati spool_buf = &spool_buf[SOF_SPOOL]; 3629ff2f6fe8SPaolo Pisati sep = strtok(NULL, ","); 3630ff2f6fe8SPaolo Pisati } 3631ff2f6fe8SPaolo Pisati } 3632ff2f6fe8SPaolo Pisati return(space); 3633ff2f6fe8SPaolo Pisati nospace: 3634ff2f6fe8SPaolo Pisati errx(EX_DATAERR, "redirect_addr: buf is too small\n"); 3635ff2f6fe8SPaolo Pisati } 3636ff2f6fe8SPaolo Pisati 3637ff2f6fe8SPaolo Pisati static int 3638ff2f6fe8SPaolo Pisati setup_redir_port(char *spool_buf, int len, 3639ff2f6fe8SPaolo Pisati int *_ac, char ***_av) 3640ff2f6fe8SPaolo Pisati { 3641ff2f6fe8SPaolo Pisati char **av, *sep, *protoName; 3642ff2f6fe8SPaolo Pisati char tmp_spool_buf[NAT_BUF_LEN]; 3643ff2f6fe8SPaolo Pisati int ac, space, lsnat; 3644ff2f6fe8SPaolo Pisati struct cfg_redir *r; 3645ff2f6fe8SPaolo Pisati struct cfg_spool *tmp; 3646ff2f6fe8SPaolo Pisati u_short numLocalPorts; 3647ff2f6fe8SPaolo Pisati port_range portRange; 3648ff2f6fe8SPaolo Pisati 3649ff2f6fe8SPaolo Pisati av = *_av; 3650ff2f6fe8SPaolo Pisati ac = *_ac; 3651ff2f6fe8SPaolo Pisati space = 0; 3652ff2f6fe8SPaolo Pisati lsnat = 0; 3653ff2f6fe8SPaolo Pisati numLocalPorts = 0; 3654ff2f6fe8SPaolo Pisati 3655ff2f6fe8SPaolo Pisati if (len >= SOF_REDIR) { 3656ff2f6fe8SPaolo Pisati r = (struct cfg_redir *)spool_buf; 3657ff2f6fe8SPaolo Pisati /* Skip cfg_redir at beginning of buf. */ 3658ff2f6fe8SPaolo Pisati spool_buf = &spool_buf[SOF_REDIR]; 3659ff2f6fe8SPaolo Pisati space = SOF_REDIR; 3660ff2f6fe8SPaolo Pisati len -= SOF_REDIR; 3661ff2f6fe8SPaolo Pisati } else 3662ff2f6fe8SPaolo Pisati goto nospace; 3663ff2f6fe8SPaolo Pisati r->mode = REDIR_PORT; 3664ff2f6fe8SPaolo Pisati /* 3665ff2f6fe8SPaolo Pisati * Extract protocol. 3666ff2f6fe8SPaolo Pisati */ 3667ff2f6fe8SPaolo Pisati if (ac == 0) 3668ff2f6fe8SPaolo Pisati errx (EX_DATAERR, "redirect_port: missing protocol"); 3669ff2f6fe8SPaolo Pisati r->proto = StrToProto(*av); 3670ff2f6fe8SPaolo Pisati protoName = *av; 3671ff2f6fe8SPaolo Pisati INC_ARGCV(); 3672ff2f6fe8SPaolo Pisati 3673ff2f6fe8SPaolo Pisati /* 3674ff2f6fe8SPaolo Pisati * Extract local address. 3675ff2f6fe8SPaolo Pisati */ 3676ff2f6fe8SPaolo Pisati if (ac == 0) 3677ff2f6fe8SPaolo Pisati errx (EX_DATAERR, "redirect_port: missing local address"); 3678ff2f6fe8SPaolo Pisati 3679ff2f6fe8SPaolo Pisati sep = strchr(*av, ','); 3680ff2f6fe8SPaolo Pisati /* LSNAT redirection syntax. */ 3681ff2f6fe8SPaolo Pisati if (sep) { 3682ff2f6fe8SPaolo Pisati r->laddr.s_addr = INADDR_NONE; 3683ff2f6fe8SPaolo Pisati r->lport = ~0; 3684ff2f6fe8SPaolo Pisati numLocalPorts = 1; 3685ff2f6fe8SPaolo Pisati /* Preserve av, copy spool servers to tmp_spool_buf. */ 3686ff2f6fe8SPaolo Pisati strncpy(tmp_spool_buf, *av, strlen(*av)+1); 3687ff2f6fe8SPaolo Pisati lsnat = 1; 3688ff2f6fe8SPaolo Pisati } else { 3689ff2f6fe8SPaolo Pisati if (StrToAddrAndPortRange (*av, &r->laddr, protoName, 3690ff2f6fe8SPaolo Pisati &portRange) != 0) 3691ff2f6fe8SPaolo Pisati errx(EX_DATAERR, "redirect_port:" 3692ff2f6fe8SPaolo Pisati "invalid local port range"); 3693ff2f6fe8SPaolo Pisati 3694ff2f6fe8SPaolo Pisati r->lport = GETLOPORT(portRange); 3695ff2f6fe8SPaolo Pisati numLocalPorts = GETNUMPORTS(portRange); 3696ff2f6fe8SPaolo Pisati } 3697ff2f6fe8SPaolo Pisati INC_ARGCV(); 3698ff2f6fe8SPaolo Pisati 3699ff2f6fe8SPaolo Pisati /* 3700ff2f6fe8SPaolo Pisati * Extract public port and optionally address. 3701ff2f6fe8SPaolo Pisati */ 3702ff2f6fe8SPaolo Pisati if (ac == 0) 3703ff2f6fe8SPaolo Pisati errx (EX_DATAERR, "redirect_port: missing public port"); 3704ff2f6fe8SPaolo Pisati 3705ff2f6fe8SPaolo Pisati sep = strchr (*av, ':'); 3706ff2f6fe8SPaolo Pisati if (sep) { 3707ff2f6fe8SPaolo Pisati if (StrToAddrAndPortRange (*av, &r->paddr, protoName, 3708ff2f6fe8SPaolo Pisati &portRange) != 0) 3709ff2f6fe8SPaolo Pisati errx(EX_DATAERR, "redirect_port:" 3710ff2f6fe8SPaolo Pisati "invalid public port range"); 3711ff2f6fe8SPaolo Pisati } else { 3712ff2f6fe8SPaolo Pisati r->paddr.s_addr = INADDR_ANY; 3713ff2f6fe8SPaolo Pisati if (StrToPortRange (*av, protoName, &portRange) != 0) 3714ff2f6fe8SPaolo Pisati errx(EX_DATAERR, "redirect_port:" 3715ff2f6fe8SPaolo Pisati "invalid public port range"); 3716ff2f6fe8SPaolo Pisati } 3717ff2f6fe8SPaolo Pisati 3718ff2f6fe8SPaolo Pisati r->pport = GETLOPORT(portRange); 3719ff2f6fe8SPaolo Pisati r->pport_cnt = GETNUMPORTS(portRange); 3720ff2f6fe8SPaolo Pisati INC_ARGCV(); 3721ff2f6fe8SPaolo Pisati 3722ff2f6fe8SPaolo Pisati /* 3723ff2f6fe8SPaolo Pisati * Extract remote address and optionally port. 3724ff2f6fe8SPaolo Pisati */ 3725ff2f6fe8SPaolo Pisati /* 3726ff2f6fe8SPaolo Pisati * NB: isalpha(**av) => we've to check that next parameter is really an 3727ff2f6fe8SPaolo Pisati * option for this redirect entry, else stop here processing arg[cv]. 3728ff2f6fe8SPaolo Pisati */ 3729ff2f6fe8SPaolo Pisati if (ac != 0 && !isalpha(**av)) { 3730ff2f6fe8SPaolo Pisati sep = strchr (*av, ':'); 3731ff2f6fe8SPaolo Pisati if (sep) { 3732ff2f6fe8SPaolo Pisati if (StrToAddrAndPortRange (*av, &r->raddr, protoName, 3733ff2f6fe8SPaolo Pisati &portRange) != 0) 3734ff2f6fe8SPaolo Pisati errx(EX_DATAERR, "redirect_port:" 3735ff2f6fe8SPaolo Pisati "invalid remote port range"); 3736ff2f6fe8SPaolo Pisati } else { 3737ff2f6fe8SPaolo Pisati SETLOPORT(portRange, 0); 3738ff2f6fe8SPaolo Pisati SETNUMPORTS(portRange, 1); 3739ff2f6fe8SPaolo Pisati StrToAddr (*av, &r->raddr); 3740ff2f6fe8SPaolo Pisati } 3741ff2f6fe8SPaolo Pisati INC_ARGCV(); 3742ff2f6fe8SPaolo Pisati } else { 3743ff2f6fe8SPaolo Pisati SETLOPORT(portRange, 0); 3744ff2f6fe8SPaolo Pisati SETNUMPORTS(portRange, 1); 3745ff2f6fe8SPaolo Pisati r->raddr.s_addr = INADDR_ANY; 3746ff2f6fe8SPaolo Pisati } 3747ff2f6fe8SPaolo Pisati r->rport = GETLOPORT(portRange); 3748ff2f6fe8SPaolo Pisati r->rport_cnt = GETNUMPORTS(portRange); 3749ff2f6fe8SPaolo Pisati 3750ff2f6fe8SPaolo Pisati /* 3751ff2f6fe8SPaolo Pisati * Make sure port ranges match up, then add the redirect ports. 3752ff2f6fe8SPaolo Pisati */ 3753ff2f6fe8SPaolo Pisati if (numLocalPorts != r->pport_cnt) 3754ff2f6fe8SPaolo Pisati errx(EX_DATAERR, "redirect_port:" 3755ff2f6fe8SPaolo Pisati "port ranges must be equal in size"); 3756ff2f6fe8SPaolo Pisati 3757ff2f6fe8SPaolo Pisati /* Remote port range is allowed to be '0' which means all ports. */ 3758ff2f6fe8SPaolo Pisati if (r->rport_cnt != numLocalPorts && 3759ff2f6fe8SPaolo Pisati (r->rport_cnt != 1 || r->rport != 0)) 3760ff2f6fe8SPaolo Pisati errx(EX_DATAERR, "redirect_port: remote port must" 3761ff2f6fe8SPaolo Pisati "be 0 or equal to local port range in size"); 3762ff2f6fe8SPaolo Pisati 3763ff2f6fe8SPaolo Pisati /* 3764ff2f6fe8SPaolo Pisati * Setup LSNAT server pool. 3765ff2f6fe8SPaolo Pisati */ 3766ff2f6fe8SPaolo Pisati if (lsnat) { 3767ff2f6fe8SPaolo Pisati sep = strtok(tmp_spool_buf, ","); 3768ff2f6fe8SPaolo Pisati while (sep != NULL) { 3769ff2f6fe8SPaolo Pisati tmp = (struct cfg_spool *)spool_buf; 3770ff2f6fe8SPaolo Pisati if (len < SOF_SPOOL) 3771ff2f6fe8SPaolo Pisati goto nospace; 3772ff2f6fe8SPaolo Pisati len -= SOF_SPOOL; 3773ff2f6fe8SPaolo Pisati space += SOF_SPOOL; 3774ff2f6fe8SPaolo Pisati if (StrToAddrAndPortRange(sep, &tmp->addr, protoName, 3775ff2f6fe8SPaolo Pisati &portRange) != 0) 3776ff2f6fe8SPaolo Pisati errx(EX_DATAERR, "redirect_port:" 3777ff2f6fe8SPaolo Pisati "invalid local port range"); 3778ff2f6fe8SPaolo Pisati if (GETNUMPORTS(portRange) != 1) 3779ff2f6fe8SPaolo Pisati errx(EX_DATAERR, "redirect_port: local port" 3780ff2f6fe8SPaolo Pisati "must be single in this context"); 3781ff2f6fe8SPaolo Pisati tmp->port = GETLOPORT(portRange); 3782ff2f6fe8SPaolo Pisati r->spool_cnt++; 3783ff2f6fe8SPaolo Pisati /* Point to the next possible cfg_spool. */ 3784ff2f6fe8SPaolo Pisati spool_buf = &spool_buf[SOF_SPOOL]; 3785ff2f6fe8SPaolo Pisati sep = strtok(NULL, ","); 3786ff2f6fe8SPaolo Pisati } 3787ff2f6fe8SPaolo Pisati } 3788ff2f6fe8SPaolo Pisati return (space); 3789ff2f6fe8SPaolo Pisati nospace: 3790ff2f6fe8SPaolo Pisati errx(EX_DATAERR, "redirect_port: buf is too small\n"); 3791ff2f6fe8SPaolo Pisati } 3792ff2f6fe8SPaolo Pisati 3793ff2f6fe8SPaolo Pisati static int 3794ff2f6fe8SPaolo Pisati setup_redir_proto(char *spool_buf, int len, 3795ff2f6fe8SPaolo Pisati int *_ac, char ***_av) 3796ff2f6fe8SPaolo Pisati { 3797ff2f6fe8SPaolo Pisati char **av; 3798015002dfSRoman Kurakin int ac, space; 3799ff2f6fe8SPaolo Pisati struct protoent *protoent; 3800ff2f6fe8SPaolo Pisati struct cfg_redir *r; 3801ff2f6fe8SPaolo Pisati 3802ff2f6fe8SPaolo Pisati av = *_av; 3803ff2f6fe8SPaolo Pisati ac = *_ac; 3804ff2f6fe8SPaolo Pisati if (len >= SOF_REDIR) { 3805ff2f6fe8SPaolo Pisati r = (struct cfg_redir *)spool_buf; 3806ff2f6fe8SPaolo Pisati /* Skip cfg_redir at beginning of buf. */ 3807ff2f6fe8SPaolo Pisati spool_buf = &spool_buf[SOF_REDIR]; 3808ff2f6fe8SPaolo Pisati space = SOF_REDIR; 3809ff2f6fe8SPaolo Pisati len -= SOF_REDIR; 3810ff2f6fe8SPaolo Pisati } else 3811ff2f6fe8SPaolo Pisati goto nospace; 3812ff2f6fe8SPaolo Pisati r->mode = REDIR_PROTO; 3813ff2f6fe8SPaolo Pisati /* 3814ff2f6fe8SPaolo Pisati * Extract protocol. 3815ff2f6fe8SPaolo Pisati */ 3816ff2f6fe8SPaolo Pisati if (ac == 0) 3817ff2f6fe8SPaolo Pisati errx(EX_DATAERR, "redirect_proto: missing protocol"); 3818ff2f6fe8SPaolo Pisati 3819ff2f6fe8SPaolo Pisati protoent = getprotobyname(*av); 3820ff2f6fe8SPaolo Pisati if (protoent == NULL) 3821ff2f6fe8SPaolo Pisati errx(EX_DATAERR, "redirect_proto: unknown protocol %s", *av); 3822ff2f6fe8SPaolo Pisati else 3823ff2f6fe8SPaolo Pisati r->proto = protoent->p_proto; 3824ff2f6fe8SPaolo Pisati 3825ff2f6fe8SPaolo Pisati INC_ARGCV(); 3826ff2f6fe8SPaolo Pisati 3827ff2f6fe8SPaolo Pisati /* 3828ff2f6fe8SPaolo Pisati * Extract local address. 3829ff2f6fe8SPaolo Pisati */ 3830ff2f6fe8SPaolo Pisati if (ac == 0) 3831ff2f6fe8SPaolo Pisati errx(EX_DATAERR, "redirect_proto: missing local address"); 3832ff2f6fe8SPaolo Pisati else 3833ff2f6fe8SPaolo Pisati StrToAddr(*av, &r->laddr); 3834ff2f6fe8SPaolo Pisati 3835ff2f6fe8SPaolo Pisati INC_ARGCV(); 3836ff2f6fe8SPaolo Pisati 3837ff2f6fe8SPaolo Pisati /* 3838ff2f6fe8SPaolo Pisati * Extract optional public address. 3839ff2f6fe8SPaolo Pisati */ 3840ff2f6fe8SPaolo Pisati if (ac == 0) { 3841ff2f6fe8SPaolo Pisati r->paddr.s_addr = INADDR_ANY; 3842ff2f6fe8SPaolo Pisati r->raddr.s_addr = INADDR_ANY; 3843ff2f6fe8SPaolo Pisati } else { 3844ff2f6fe8SPaolo Pisati /* see above in setup_redir_port() */ 3845ff2f6fe8SPaolo Pisati if (!isalpha(**av)) { 3846ff2f6fe8SPaolo Pisati StrToAddr(*av, &r->paddr); 3847ff2f6fe8SPaolo Pisati INC_ARGCV(); 3848ff2f6fe8SPaolo Pisati 3849ff2f6fe8SPaolo Pisati /* 3850ff2f6fe8SPaolo Pisati * Extract optional remote address. 3851ff2f6fe8SPaolo Pisati */ 3852ff2f6fe8SPaolo Pisati /* see above in setup_redir_port() */ 3853ff2f6fe8SPaolo Pisati if (ac!=0 && !isalpha(**av)) { 3854ff2f6fe8SPaolo Pisati StrToAddr(*av, &r->raddr); 3855ff2f6fe8SPaolo Pisati INC_ARGCV(); 3856ff2f6fe8SPaolo Pisati } 3857ff2f6fe8SPaolo Pisati } 3858ff2f6fe8SPaolo Pisati } 3859ff2f6fe8SPaolo Pisati return (space); 3860ff2f6fe8SPaolo Pisati nospace: 3861ff2f6fe8SPaolo Pisati errx(EX_DATAERR, "redirect_proto: buf is too small\n"); 3862ff2f6fe8SPaolo Pisati } 3863ff2f6fe8SPaolo Pisati 3864ff2f6fe8SPaolo Pisati static void 386520e58023SMaxim Konovalov show_nat(int ac, char **av); 386620e58023SMaxim Konovalov 386720e58023SMaxim Konovalov static void 3868daa9733aSLuigi Rizzo print_nat_config(unsigned char *buf) 3869daa9733aSLuigi Rizzo { 3870ff2f6fe8SPaolo Pisati struct cfg_nat *n; 3871ff2f6fe8SPaolo Pisati int i, cnt, flag, off; 3872ff2f6fe8SPaolo Pisati struct cfg_redir *t; 3873ff2f6fe8SPaolo Pisati struct cfg_spool *s; 3874ff2f6fe8SPaolo Pisati struct protoent *p; 3875ff2f6fe8SPaolo Pisati 3876ff2f6fe8SPaolo Pisati n = (struct cfg_nat *)buf; 3877ff2f6fe8SPaolo Pisati flag = 1; 3878ff2f6fe8SPaolo Pisati off = sizeof(*n); 3879ff2f6fe8SPaolo Pisati printf("ipfw nat %u config", n->id); 3880ff2f6fe8SPaolo Pisati if (strlen(n->if_name) != 0) 3881ff2f6fe8SPaolo Pisati printf(" if %s", n->if_name); 3882ff2f6fe8SPaolo Pisati else if (n->ip.s_addr != 0) 3883ff2f6fe8SPaolo Pisati printf(" ip %s", inet_ntoa(n->ip)); 3884ff2f6fe8SPaolo Pisati while (n->mode != 0) { 3885ff2f6fe8SPaolo Pisati if (n->mode & PKT_ALIAS_LOG) { 3886ff2f6fe8SPaolo Pisati printf(" log"); 3887ff2f6fe8SPaolo Pisati n->mode &= ~PKT_ALIAS_LOG; 3888ff2f6fe8SPaolo Pisati } else if (n->mode & PKT_ALIAS_DENY_INCOMING) { 3889ff2f6fe8SPaolo Pisati printf(" deny_in"); 3890ff2f6fe8SPaolo Pisati n->mode &= ~PKT_ALIAS_DENY_INCOMING; 3891ff2f6fe8SPaolo Pisati } else if (n->mode & PKT_ALIAS_SAME_PORTS) { 3892ff2f6fe8SPaolo Pisati printf(" same_ports"); 3893ff2f6fe8SPaolo Pisati n->mode &= ~PKT_ALIAS_SAME_PORTS; 3894ff2f6fe8SPaolo Pisati } else if (n->mode & PKT_ALIAS_UNREGISTERED_ONLY) { 3895ff2f6fe8SPaolo Pisati printf(" unreg_only"); 3896ff2f6fe8SPaolo Pisati n->mode &= ~PKT_ALIAS_UNREGISTERED_ONLY; 3897ff2f6fe8SPaolo Pisati } else if (n->mode & PKT_ALIAS_RESET_ON_ADDR_CHANGE) { 3898ff2f6fe8SPaolo Pisati printf(" reset"); 3899ff2f6fe8SPaolo Pisati n->mode &= ~PKT_ALIAS_RESET_ON_ADDR_CHANGE; 3900ff2f6fe8SPaolo Pisati } else if (n->mode & PKT_ALIAS_REVERSE) { 3901ff2f6fe8SPaolo Pisati printf(" reverse"); 3902ff2f6fe8SPaolo Pisati n->mode &= ~PKT_ALIAS_REVERSE; 3903ff2f6fe8SPaolo Pisati } else if (n->mode & PKT_ALIAS_PROXY_ONLY) { 3904ff2f6fe8SPaolo Pisati printf(" proxy_only"); 3905ff2f6fe8SPaolo Pisati n->mode &= ~PKT_ALIAS_PROXY_ONLY; 3906ff2f6fe8SPaolo Pisati } 3907ff2f6fe8SPaolo Pisati } 3908ff2f6fe8SPaolo Pisati /* Print all the redirect's data configuration. */ 3909ff2f6fe8SPaolo Pisati for (cnt = 0; cnt < n->redir_cnt; cnt++) { 3910ff2f6fe8SPaolo Pisati t = (struct cfg_redir *)&buf[off]; 3911ff2f6fe8SPaolo Pisati off += SOF_REDIR; 3912ff2f6fe8SPaolo Pisati switch (t->mode) { 3913ff2f6fe8SPaolo Pisati case REDIR_ADDR: 3914ff2f6fe8SPaolo Pisati printf(" redirect_addr"); 3915ff2f6fe8SPaolo Pisati if (t->spool_cnt == 0) 3916ff2f6fe8SPaolo Pisati printf(" %s", inet_ntoa(t->laddr)); 3917ff2f6fe8SPaolo Pisati else 3918ff2f6fe8SPaolo Pisati for (i = 0; i < t->spool_cnt; i++) { 3919ff2f6fe8SPaolo Pisati s = (struct cfg_spool *)&buf[off]; 3920ff2f6fe8SPaolo Pisati if (i) 3921ff2f6fe8SPaolo Pisati printf(","); 3922ff2f6fe8SPaolo Pisati else 3923ff2f6fe8SPaolo Pisati printf(" "); 3924ff2f6fe8SPaolo Pisati printf("%s", inet_ntoa(s->addr)); 3925ff2f6fe8SPaolo Pisati off += SOF_SPOOL; 3926ff2f6fe8SPaolo Pisati } 3927ff2f6fe8SPaolo Pisati printf(" %s", inet_ntoa(t->paddr)); 3928ff2f6fe8SPaolo Pisati break; 3929ff2f6fe8SPaolo Pisati case REDIR_PORT: 3930ff2f6fe8SPaolo Pisati p = getprotobynumber(t->proto); 3931ff2f6fe8SPaolo Pisati printf(" redirect_port %s ", p->p_name); 3932ff2f6fe8SPaolo Pisati if (!t->spool_cnt) { 3933ff2f6fe8SPaolo Pisati printf("%s:%u", inet_ntoa(t->laddr), t->lport); 3934ff2f6fe8SPaolo Pisati if (t->pport_cnt > 1) 3935ff2f6fe8SPaolo Pisati printf("-%u", t->lport + 3936ff2f6fe8SPaolo Pisati t->pport_cnt - 1); 3937ff2f6fe8SPaolo Pisati } else 3938ff2f6fe8SPaolo Pisati for (i=0; i < t->spool_cnt; i++) { 3939ff2f6fe8SPaolo Pisati s = (struct cfg_spool *)&buf[off]; 3940ff2f6fe8SPaolo Pisati if (i) 3941ff2f6fe8SPaolo Pisati printf(","); 3942ff2f6fe8SPaolo Pisati printf("%s:%u", inet_ntoa(s->addr), 3943ff2f6fe8SPaolo Pisati s->port); 3944ff2f6fe8SPaolo Pisati off += SOF_SPOOL; 3945ff2f6fe8SPaolo Pisati } 3946ff2f6fe8SPaolo Pisati 3947ff2f6fe8SPaolo Pisati printf(" "); 3948ff2f6fe8SPaolo Pisati if (t->paddr.s_addr) 3949ff2f6fe8SPaolo Pisati printf("%s:", inet_ntoa(t->paddr)); 3950ff2f6fe8SPaolo Pisati printf("%u", t->pport); 3951ff2f6fe8SPaolo Pisati if (!t->spool_cnt && t->pport_cnt > 1) 3952ff2f6fe8SPaolo Pisati printf("-%u", t->pport + t->pport_cnt - 1); 3953ff2f6fe8SPaolo Pisati 3954ff2f6fe8SPaolo Pisati if (t->raddr.s_addr) { 3955ff2f6fe8SPaolo Pisati printf(" %s", inet_ntoa(t->raddr)); 3956ff2f6fe8SPaolo Pisati if (t->rport) { 3957ff2f6fe8SPaolo Pisati printf(":%u", t->rport); 3958ff2f6fe8SPaolo Pisati if (!t->spool_cnt && t->rport_cnt > 1) 3959ff2f6fe8SPaolo Pisati printf("-%u", t->rport + 3960ff2f6fe8SPaolo Pisati t->rport_cnt - 1); 3961ff2f6fe8SPaolo Pisati } 3962ff2f6fe8SPaolo Pisati } 3963ff2f6fe8SPaolo Pisati break; 3964ff2f6fe8SPaolo Pisati case REDIR_PROTO: 3965ff2f6fe8SPaolo Pisati p = getprotobynumber(t->proto); 3966ff2f6fe8SPaolo Pisati printf(" redirect_proto %s %s", p->p_name, 3967ff2f6fe8SPaolo Pisati inet_ntoa(t->laddr)); 3968ff2f6fe8SPaolo Pisati if (t->paddr.s_addr != 0) { 3969ff2f6fe8SPaolo Pisati printf(" %s", inet_ntoa(t->paddr)); 3970ff2f6fe8SPaolo Pisati if (t->raddr.s_addr) 3971ff2f6fe8SPaolo Pisati printf(" %s", inet_ntoa(t->raddr)); 3972ff2f6fe8SPaolo Pisati } 3973ff2f6fe8SPaolo Pisati break; 3974ff2f6fe8SPaolo Pisati default: 3975ff2f6fe8SPaolo Pisati errx(EX_DATAERR, "unknown redir mode"); 3976ff2f6fe8SPaolo Pisati break; 3977ff2f6fe8SPaolo Pisati } 3978ff2f6fe8SPaolo Pisati } 3979ff2f6fe8SPaolo Pisati printf("\n"); 3980ff2f6fe8SPaolo Pisati } 3981ff2f6fe8SPaolo Pisati 3982ff2f6fe8SPaolo Pisati static void 3983ff2f6fe8SPaolo Pisati config_nat(int ac, char **av) 3984ff2f6fe8SPaolo Pisati { 3985ff2f6fe8SPaolo Pisati struct cfg_nat *n; /* Nat instance configuration. */ 3986ff2f6fe8SPaolo Pisati int i, len, off, tok; 3987ff2f6fe8SPaolo Pisati char *id, buf[NAT_BUF_LEN]; /* Buffer for serialized data. */ 3988ff2f6fe8SPaolo Pisati 3989ff2f6fe8SPaolo Pisati len = NAT_BUF_LEN; 3990ff2f6fe8SPaolo Pisati /* Offset in buf: save space for n at the beginning. */ 3991ff2f6fe8SPaolo Pisati off = sizeof(*n); 3992ff2f6fe8SPaolo Pisati memset(buf, 0, sizeof(buf)); 3993ff2f6fe8SPaolo Pisati n = (struct cfg_nat *)buf; 3994ff2f6fe8SPaolo Pisati 3995ff2f6fe8SPaolo Pisati av++; ac--; 3996ff2f6fe8SPaolo Pisati /* Nat id. */ 3997ff2f6fe8SPaolo Pisati if (ac && isdigit(**av)) { 3998ff2f6fe8SPaolo Pisati id = *av; 3999ff2f6fe8SPaolo Pisati i = atoi(*av); 4000ff2f6fe8SPaolo Pisati ac--; av++; 4001ff2f6fe8SPaolo Pisati n->id = i; 4002ff2f6fe8SPaolo Pisati } else 4003ff2f6fe8SPaolo Pisati errx(EX_DATAERR, "missing nat id"); 4004ff2f6fe8SPaolo Pisati if (ac == 0) 4005ff2f6fe8SPaolo Pisati errx(EX_DATAERR, "missing option"); 4006ff2f6fe8SPaolo Pisati 4007ff2f6fe8SPaolo Pisati while (ac > 0) { 4008ff2f6fe8SPaolo Pisati tok = match_token(nat_params, *av); 4009ff2f6fe8SPaolo Pisati ac--; av++; 4010ff2f6fe8SPaolo Pisati switch (tok) { 4011ff2f6fe8SPaolo Pisati case TOK_IP: 4012ff2f6fe8SPaolo Pisati if (ac == 0) 4013ff2f6fe8SPaolo Pisati errx(EX_DATAERR, "missing option"); 4014ff2f6fe8SPaolo Pisati if (!inet_aton(av[0], &(n->ip))) 4015ff2f6fe8SPaolo Pisati errx(EX_DATAERR, "bad ip address ``%s''", 4016ff2f6fe8SPaolo Pisati av[0]); 4017ff2f6fe8SPaolo Pisati ac--; av++; 4018ff2f6fe8SPaolo Pisati break; 4019ff2f6fe8SPaolo Pisati case TOK_IF: 40208c03c6c0SMaxim Konovalov if (ac == 0) 40218c03c6c0SMaxim Konovalov errx(EX_DATAERR, "missing option"); 4022ff2f6fe8SPaolo Pisati set_addr_dynamic(av[0], n); 4023ff2f6fe8SPaolo Pisati ac--; av++; 4024ff2f6fe8SPaolo Pisati break; 4025ff2f6fe8SPaolo Pisati case TOK_ALOG: 4026ff2f6fe8SPaolo Pisati n->mode |= PKT_ALIAS_LOG; 4027ff2f6fe8SPaolo Pisati break; 4028ff2f6fe8SPaolo Pisati case TOK_DENY_INC: 4029ff2f6fe8SPaolo Pisati n->mode |= PKT_ALIAS_DENY_INCOMING; 4030ff2f6fe8SPaolo Pisati break; 4031ff2f6fe8SPaolo Pisati case TOK_SAME_PORTS: 4032ff2f6fe8SPaolo Pisati n->mode |= PKT_ALIAS_SAME_PORTS; 4033ff2f6fe8SPaolo Pisati break; 4034ff2f6fe8SPaolo Pisati case TOK_UNREG_ONLY: 4035ff2f6fe8SPaolo Pisati n->mode |= PKT_ALIAS_UNREGISTERED_ONLY; 4036ff2f6fe8SPaolo Pisati break; 4037ff2f6fe8SPaolo Pisati case TOK_RESET_ADDR: 4038ff2f6fe8SPaolo Pisati n->mode |= PKT_ALIAS_RESET_ON_ADDR_CHANGE; 4039ff2f6fe8SPaolo Pisati break; 4040ff2f6fe8SPaolo Pisati case TOK_ALIAS_REV: 4041ff2f6fe8SPaolo Pisati n->mode |= PKT_ALIAS_REVERSE; 4042ff2f6fe8SPaolo Pisati break; 4043ff2f6fe8SPaolo Pisati case TOK_PROXY_ONLY: 4044ff2f6fe8SPaolo Pisati n->mode |= PKT_ALIAS_PROXY_ONLY; 4045ff2f6fe8SPaolo Pisati break; 4046ff2f6fe8SPaolo Pisati /* 4047ff2f6fe8SPaolo Pisati * All the setup_redir_* functions work directly in the final 4048ff2f6fe8SPaolo Pisati * buffer, see above for details. 4049ff2f6fe8SPaolo Pisati */ 4050ff2f6fe8SPaolo Pisati case TOK_REDIR_ADDR: 4051ff2f6fe8SPaolo Pisati case TOK_REDIR_PORT: 4052ff2f6fe8SPaolo Pisati case TOK_REDIR_PROTO: 4053ff2f6fe8SPaolo Pisati switch (tok) { 4054ff2f6fe8SPaolo Pisati case TOK_REDIR_ADDR: 4055ff2f6fe8SPaolo Pisati i = setup_redir_addr(&buf[off], len, &ac, &av); 4056ff2f6fe8SPaolo Pisati break; 4057ff2f6fe8SPaolo Pisati case TOK_REDIR_PORT: 4058ff2f6fe8SPaolo Pisati i = setup_redir_port(&buf[off], len, &ac, &av); 4059ff2f6fe8SPaolo Pisati break; 4060ff2f6fe8SPaolo Pisati case TOK_REDIR_PROTO: 4061ff2f6fe8SPaolo Pisati i = setup_redir_proto(&buf[off], len, &ac, &av); 4062ff2f6fe8SPaolo Pisati break; 4063ff2f6fe8SPaolo Pisati } 4064ff2f6fe8SPaolo Pisati n->redir_cnt++; 4065ff2f6fe8SPaolo Pisati off += i; 4066ff2f6fe8SPaolo Pisati len -= i; 4067ff2f6fe8SPaolo Pisati break; 4068ff2f6fe8SPaolo Pisati default: 4069ff2f6fe8SPaolo Pisati errx(EX_DATAERR, "unrecognised option ``%s''", av[-1]); 4070ff2f6fe8SPaolo Pisati } 4071ff2f6fe8SPaolo Pisati } 4072ff2f6fe8SPaolo Pisati 4073ff2f6fe8SPaolo Pisati i = do_cmd(IP_FW_NAT_CFG, buf, off); 4074ff2f6fe8SPaolo Pisati if (i) 4075ff2f6fe8SPaolo Pisati err(1, "setsockopt(%s)", "IP_FW_NAT_CFG"); 407620e58023SMaxim Konovalov 40773fc7bd58SPaolo Pisati if (!do_quiet) { 407820e58023SMaxim Konovalov /* After every modification, we show the resultant rule. */ 407920e58023SMaxim Konovalov int _ac = 3; 408020e58023SMaxim Konovalov char *_av[] = {"show", "config", id}; 408120e58023SMaxim Konovalov show_nat(_ac, _av); 4082ff2f6fe8SPaolo Pisati } 40833fc7bd58SPaolo Pisati } 4084ff2f6fe8SPaolo Pisati 40859758b77fSLuigi Rizzo static void 40869758b77fSLuigi Rizzo config_pipe(int ac, char **av) 40879758b77fSLuigi Rizzo { 408862ff38aeSLuigi Rizzo struct dn_pipe p; 40899758b77fSLuigi Rizzo int i; 40909758b77fSLuigi Rizzo char *end; 40919758b77fSLuigi Rizzo void *par = NULL; 40929758b77fSLuigi Rizzo 409362ff38aeSLuigi Rizzo memset(&p, 0, sizeof p); 40949758b77fSLuigi Rizzo 40959758b77fSLuigi Rizzo av++; ac--; 40969758b77fSLuigi Rizzo /* Pipe number */ 40979758b77fSLuigi Rizzo if (ac && isdigit(**av)) { 40989758b77fSLuigi Rizzo i = atoi(*av); av++; ac--; 40999758b77fSLuigi Rizzo if (do_pipe == 1) 410062ff38aeSLuigi Rizzo p.pipe_nr = i; 41019758b77fSLuigi Rizzo else 410262ff38aeSLuigi Rizzo p.fs.fs_nr = i; 41039758b77fSLuigi Rizzo } 41045e43aef8SLuigi Rizzo while (ac > 0) { 41059758b77fSLuigi Rizzo double d; 41069758b77fSLuigi Rizzo int tok = match_token(dummynet_params, *av); 41079758b77fSLuigi Rizzo ac--; av++; 41089758b77fSLuigi Rizzo 41099758b77fSLuigi Rizzo switch(tok) { 411099e5e645SLuigi Rizzo case TOK_NOERROR: 411162ff38aeSLuigi Rizzo p.fs.flags_fs |= DN_NOERROR; 411299e5e645SLuigi Rizzo break; 411399e5e645SLuigi Rizzo 41149758b77fSLuigi Rizzo case TOK_PLR: 41159758b77fSLuigi Rizzo NEED1("plr needs argument 0..1\n"); 41169758b77fSLuigi Rizzo d = strtod(av[0], NULL); 41179758b77fSLuigi Rizzo if (d > 1) 41189758b77fSLuigi Rizzo d = 1; 41199758b77fSLuigi Rizzo else if (d < 0) 41209758b77fSLuigi Rizzo d = 0; 412162ff38aeSLuigi Rizzo p.fs.plr = (int)(d*0x7fffffff); 41229758b77fSLuigi Rizzo ac--; av++; 41239758b77fSLuigi Rizzo break; 41249758b77fSLuigi Rizzo 41259758b77fSLuigi Rizzo case TOK_QUEUE: 41269758b77fSLuigi Rizzo NEED1("queue needs queue size\n"); 41279758b77fSLuigi Rizzo end = NULL; 412862ff38aeSLuigi Rizzo p.fs.qsize = strtoul(av[0], &end, 0); 41299758b77fSLuigi Rizzo if (*end == 'K' || *end == 'k') { 413062ff38aeSLuigi Rizzo p.fs.flags_fs |= DN_QSIZE_IS_BYTES; 413162ff38aeSLuigi Rizzo p.fs.qsize *= 1024; 413201750186SBrooks Davis } else if (*end == 'B' || 413301750186SBrooks Davis _substrcmp2(end, "by", "bytes") == 0) { 413462ff38aeSLuigi Rizzo p.fs.flags_fs |= DN_QSIZE_IS_BYTES; 41359758b77fSLuigi Rizzo } 41369758b77fSLuigi Rizzo ac--; av++; 41379758b77fSLuigi Rizzo break; 41389758b77fSLuigi Rizzo 41399758b77fSLuigi Rizzo case TOK_BUCKETS: 41409758b77fSLuigi Rizzo NEED1("buckets needs argument\n"); 414162ff38aeSLuigi Rizzo p.fs.rq_size = strtoul(av[0], NULL, 0); 41429758b77fSLuigi Rizzo ac--; av++; 41439758b77fSLuigi Rizzo break; 41449758b77fSLuigi Rizzo 41459758b77fSLuigi Rizzo case TOK_MASK: 41469758b77fSLuigi Rizzo NEED1("mask needs mask specifier\n"); 41479758b77fSLuigi Rizzo /* 41489758b77fSLuigi Rizzo * per-flow queue, mask is dst_ip, dst_port, 41499758b77fSLuigi Rizzo * src_ip, src_port, proto measured in bits 41509758b77fSLuigi Rizzo */ 41519758b77fSLuigi Rizzo par = NULL; 41529758b77fSLuigi Rizzo 41538195404bSBrooks Davis bzero(&p.fs.flow_mask, sizeof(p.fs.flow_mask)); 41549758b77fSLuigi Rizzo end = NULL; 41559758b77fSLuigi Rizzo 41569758b77fSLuigi Rizzo while (ac >= 1) { 4157571f8c1bSLuigi Rizzo uint32_t *p32 = NULL; 4158571f8c1bSLuigi Rizzo uint16_t *p16 = NULL; 41598195404bSBrooks Davis uint32_t *p20 = NULL; 41608195404bSBrooks Davis struct in6_addr *pa6 = NULL; 41618195404bSBrooks Davis uint32_t a; 41629758b77fSLuigi Rizzo 41639758b77fSLuigi Rizzo tok = match_token(dummynet_params, *av); 41649758b77fSLuigi Rizzo ac--; av++; 41659758b77fSLuigi Rizzo switch(tok) { 41669758b77fSLuigi Rizzo case TOK_ALL: 41679758b77fSLuigi Rizzo /* 41689758b77fSLuigi Rizzo * special case, all bits significant 41699758b77fSLuigi Rizzo */ 417062ff38aeSLuigi Rizzo p.fs.flow_mask.dst_ip = ~0; 417162ff38aeSLuigi Rizzo p.fs.flow_mask.src_ip = ~0; 417262ff38aeSLuigi Rizzo p.fs.flow_mask.dst_port = ~0; 417362ff38aeSLuigi Rizzo p.fs.flow_mask.src_port = ~0; 417462ff38aeSLuigi Rizzo p.fs.flow_mask.proto = ~0; 41758195404bSBrooks Davis n2mask(&(p.fs.flow_mask.dst_ip6), 128); 41768195404bSBrooks Davis n2mask(&(p.fs.flow_mask.src_ip6), 128); 41778195404bSBrooks Davis p.fs.flow_mask.flow_id6 = ~0; 417862ff38aeSLuigi Rizzo p.fs.flags_fs |= DN_HAVE_FLOW_MASK; 41799758b77fSLuigi Rizzo goto end_mask; 41809758b77fSLuigi Rizzo 41819758b77fSLuigi Rizzo case TOK_DSTIP: 418262ff38aeSLuigi Rizzo p32 = &p.fs.flow_mask.dst_ip; 41839758b77fSLuigi Rizzo break; 41849758b77fSLuigi Rizzo 41859758b77fSLuigi Rizzo case TOK_SRCIP: 418662ff38aeSLuigi Rizzo p32 = &p.fs.flow_mask.src_ip; 41879758b77fSLuigi Rizzo break; 41889758b77fSLuigi Rizzo 41898195404bSBrooks Davis case TOK_DSTIP6: 41908195404bSBrooks Davis pa6 = &(p.fs.flow_mask.dst_ip6); 41918195404bSBrooks Davis break; 41928195404bSBrooks Davis 41938195404bSBrooks Davis case TOK_SRCIP6: 41948195404bSBrooks Davis pa6 = &(p.fs.flow_mask.src_ip6); 41958195404bSBrooks Davis break; 41968195404bSBrooks Davis 41978195404bSBrooks Davis case TOK_FLOWID: 41988195404bSBrooks Davis p20 = &p.fs.flow_mask.flow_id6; 41998195404bSBrooks Davis break; 42008195404bSBrooks Davis 42019758b77fSLuigi Rizzo case TOK_DSTPORT: 420262ff38aeSLuigi Rizzo p16 = &p.fs.flow_mask.dst_port; 42039758b77fSLuigi Rizzo break; 42049758b77fSLuigi Rizzo 42059758b77fSLuigi Rizzo case TOK_SRCPORT: 420662ff38aeSLuigi Rizzo p16 = &p.fs.flow_mask.src_port; 42079758b77fSLuigi Rizzo break; 42089758b77fSLuigi Rizzo 42099758b77fSLuigi Rizzo case TOK_PROTO: 42109758b77fSLuigi Rizzo break; 42119758b77fSLuigi Rizzo 42129758b77fSLuigi Rizzo default: 42139758b77fSLuigi Rizzo ac++; av--; /* backtrack */ 42149758b77fSLuigi Rizzo goto end_mask; 42159758b77fSLuigi Rizzo } 42169758b77fSLuigi Rizzo if (ac < 1) 42179758b77fSLuigi Rizzo errx(EX_USAGE, "mask: value missing"); 42189758b77fSLuigi Rizzo if (*av[0] == '/') { 42199758b77fSLuigi Rizzo a = strtoul(av[0]+1, &end, 0); 42208195404bSBrooks Davis if (pa6 == NULL) 42219758b77fSLuigi Rizzo a = (a == 32) ? ~0 : (1 << a) - 1; 42229758b77fSLuigi Rizzo } else 42230a7197a8SLuigi Rizzo a = strtoul(av[0], &end, 0); 42249758b77fSLuigi Rizzo if (p32 != NULL) 42259758b77fSLuigi Rizzo *p32 = a; 42269758b77fSLuigi Rizzo else if (p16 != NULL) { 4227610055c9SBrooks Davis if (a > 0xFFFF) 42289758b77fSLuigi Rizzo errx(EX_DATAERR, 4229776c1005SBrooks Davis "port mask must be 16 bit"); 4230571f8c1bSLuigi Rizzo *p16 = (uint16_t)a; 42318195404bSBrooks Davis } else if (p20 != NULL) { 42328195404bSBrooks Davis if (a > 0xfffff) 42338195404bSBrooks Davis errx(EX_DATAERR, 42348195404bSBrooks Davis "flow_id mask must be 20 bit"); 42358195404bSBrooks Davis *p20 = (uint32_t)a; 42368195404bSBrooks Davis } else if (pa6 != NULL) { 4237daa9733aSLuigi Rizzo if (a > 128) 42388195404bSBrooks Davis errx(EX_DATAERR, 42398195404bSBrooks Davis "in6addr invalid mask len"); 42408195404bSBrooks Davis else 42418195404bSBrooks Davis n2mask(pa6, a); 42429758b77fSLuigi Rizzo } else { 4243610055c9SBrooks Davis if (a > 0xFF) 42449758b77fSLuigi Rizzo errx(EX_DATAERR, 4245776c1005SBrooks Davis "proto mask must be 8 bit"); 424662ff38aeSLuigi Rizzo p.fs.flow_mask.proto = (uint8_t)a; 42479758b77fSLuigi Rizzo } 42489758b77fSLuigi Rizzo if (a != 0) 424962ff38aeSLuigi Rizzo p.fs.flags_fs |= DN_HAVE_FLOW_MASK; 42509758b77fSLuigi Rizzo ac--; av++; 42519758b77fSLuigi Rizzo } /* end while, config masks */ 42529758b77fSLuigi Rizzo end_mask: 42539758b77fSLuigi Rizzo break; 42549758b77fSLuigi Rizzo 42559758b77fSLuigi Rizzo case TOK_RED: 42569758b77fSLuigi Rizzo case TOK_GRED: 42579758b77fSLuigi Rizzo NEED1("red/gred needs w_q/min_th/max_th/max_p\n"); 425862ff38aeSLuigi Rizzo p.fs.flags_fs |= DN_IS_RED; 42599758b77fSLuigi Rizzo if (tok == TOK_GRED) 426062ff38aeSLuigi Rizzo p.fs.flags_fs |= DN_IS_GENTLE_RED; 42619758b77fSLuigi Rizzo /* 42629758b77fSLuigi Rizzo * the format for parameters is w_q/min_th/max_th/max_p 42639758b77fSLuigi Rizzo */ 42649758b77fSLuigi Rizzo if ((end = strsep(&av[0], "/"))) { 42659758b77fSLuigi Rizzo double w_q = strtod(end, NULL); 42669758b77fSLuigi Rizzo if (w_q > 1 || w_q <= 0) 42679758b77fSLuigi Rizzo errx(EX_DATAERR, "0 < w_q <= 1"); 426862ff38aeSLuigi Rizzo p.fs.w_q = (int) (w_q * (1 << SCALE_RED)); 42699758b77fSLuigi Rizzo } 42709758b77fSLuigi Rizzo if ((end = strsep(&av[0], "/"))) { 427162ff38aeSLuigi Rizzo p.fs.min_th = strtoul(end, &end, 0); 42729758b77fSLuigi Rizzo if (*end == 'K' || *end == 'k') 427362ff38aeSLuigi Rizzo p.fs.min_th *= 1024; 42749758b77fSLuigi Rizzo } 42759758b77fSLuigi Rizzo if ((end = strsep(&av[0], "/"))) { 427662ff38aeSLuigi Rizzo p.fs.max_th = strtoul(end, &end, 0); 42779758b77fSLuigi Rizzo if (*end == 'K' || *end == 'k') 427862ff38aeSLuigi Rizzo p.fs.max_th *= 1024; 42799758b77fSLuigi Rizzo } 42809758b77fSLuigi Rizzo if ((end = strsep(&av[0], "/"))) { 42819758b77fSLuigi Rizzo double max_p = strtod(end, NULL); 42829758b77fSLuigi Rizzo if (max_p > 1 || max_p <= 0) 42839758b77fSLuigi Rizzo errx(EX_DATAERR, "0 < max_p <= 1"); 428462ff38aeSLuigi Rizzo p.fs.max_p = (int)(max_p * (1 << SCALE_RED)); 42859758b77fSLuigi Rizzo } 42869758b77fSLuigi Rizzo ac--; av++; 42879758b77fSLuigi Rizzo break; 42889758b77fSLuigi Rizzo 42899758b77fSLuigi Rizzo case TOK_DROPTAIL: 429062ff38aeSLuigi Rizzo p.fs.flags_fs &= ~(DN_IS_RED|DN_IS_GENTLE_RED); 42919758b77fSLuigi Rizzo break; 42929758b77fSLuigi Rizzo 42939758b77fSLuigi Rizzo case TOK_BW: 42949758b77fSLuigi Rizzo NEED1("bw needs bandwidth or interface\n"); 42959758b77fSLuigi Rizzo if (do_pipe != 1) 42969758b77fSLuigi Rizzo errx(EX_DATAERR, "bandwidth only valid for pipes"); 42979758b77fSLuigi Rizzo /* 42989758b77fSLuigi Rizzo * set clocking interface or bandwidth value 42999758b77fSLuigi Rizzo */ 43009758b77fSLuigi Rizzo if (av[0][0] >= 'a' && av[0][0] <= 'z') { 430162ff38aeSLuigi Rizzo int l = sizeof(p.if_name)-1; 43029758b77fSLuigi Rizzo /* interface name */ 430362ff38aeSLuigi Rizzo strncpy(p.if_name, av[0], l); 430462ff38aeSLuigi Rizzo p.if_name[l] = '\0'; 430562ff38aeSLuigi Rizzo p.bandwidth = 0; 43069758b77fSLuigi Rizzo } else { 430762ff38aeSLuigi Rizzo p.if_name[0] = '\0'; 430862ff38aeSLuigi Rizzo p.bandwidth = strtoul(av[0], &end, 0); 43099758b77fSLuigi Rizzo if (*end == 'K' || *end == 'k') { 43109758b77fSLuigi Rizzo end++; 431162ff38aeSLuigi Rizzo p.bandwidth *= 1000; 43129758b77fSLuigi Rizzo } else if (*end == 'M') { 43139758b77fSLuigi Rizzo end++; 431462ff38aeSLuigi Rizzo p.bandwidth *= 1000000; 43159758b77fSLuigi Rizzo } 4316cb0bfd9bSDavid Malone if ((*end == 'B' && 4317cb0bfd9bSDavid Malone _substrcmp2(end, "Bi", "Bit/s") != 0) || 431801750186SBrooks Davis _substrcmp2(end, "by", "bytes") == 0) 431962ff38aeSLuigi Rizzo p.bandwidth *= 8; 432062ff38aeSLuigi Rizzo if (p.bandwidth < 0) 43219758b77fSLuigi Rizzo errx(EX_DATAERR, "bandwidth too large"); 43229758b77fSLuigi Rizzo } 43239758b77fSLuigi Rizzo ac--; av++; 43249758b77fSLuigi Rizzo break; 43259758b77fSLuigi Rizzo 43269758b77fSLuigi Rizzo case TOK_DELAY: 43279758b77fSLuigi Rizzo if (do_pipe != 1) 43289758b77fSLuigi Rizzo errx(EX_DATAERR, "delay only valid for pipes"); 43299758b77fSLuigi Rizzo NEED1("delay needs argument 0..10000ms\n"); 433062ff38aeSLuigi Rizzo p.delay = strtoul(av[0], NULL, 0); 43319758b77fSLuigi Rizzo ac--; av++; 43329758b77fSLuigi Rizzo break; 43339758b77fSLuigi Rizzo 43349758b77fSLuigi Rizzo case TOK_WEIGHT: 43359758b77fSLuigi Rizzo if (do_pipe == 1) 43369758b77fSLuigi Rizzo errx(EX_DATAERR,"weight only valid for queues"); 43379758b77fSLuigi Rizzo NEED1("weight needs argument 0..100\n"); 433862ff38aeSLuigi Rizzo p.fs.weight = strtoul(av[0], &end, 0); 43399758b77fSLuigi Rizzo ac--; av++; 43409758b77fSLuigi Rizzo break; 43419758b77fSLuigi Rizzo 43429758b77fSLuigi Rizzo case TOK_PIPE: 43439758b77fSLuigi Rizzo if (do_pipe == 1) 43449758b77fSLuigi Rizzo errx(EX_DATAERR,"pipe only valid for queues"); 43459758b77fSLuigi Rizzo NEED1("pipe needs pipe_number\n"); 434662ff38aeSLuigi Rizzo p.fs.parent_nr = strtoul(av[0], &end, 0); 43479758b77fSLuigi Rizzo ac--; av++; 43489758b77fSLuigi Rizzo break; 43499758b77fSLuigi Rizzo 43509758b77fSLuigi Rizzo default: 435166d217f8SMaxim Konovalov errx(EX_DATAERR, "unrecognised option ``%s''", av[-1]); 43529758b77fSLuigi Rizzo } 43539758b77fSLuigi Rizzo } 43549758b77fSLuigi Rizzo if (do_pipe == 1) { 435562ff38aeSLuigi Rizzo if (p.pipe_nr == 0) 43569758b77fSLuigi Rizzo errx(EX_DATAERR, "pipe_nr must be > 0"); 435762ff38aeSLuigi Rizzo if (p.delay > 10000) 43589758b77fSLuigi Rizzo errx(EX_DATAERR, "delay must be < 10000"); 43599758b77fSLuigi Rizzo } else { /* do_pipe == 2, queue */ 436062ff38aeSLuigi Rizzo if (p.fs.parent_nr == 0) 43619758b77fSLuigi Rizzo errx(EX_DATAERR, "pipe must be > 0"); 436262ff38aeSLuigi Rizzo if (p.fs.weight >100) 43639758b77fSLuigi Rizzo errx(EX_DATAERR, "weight must be <= 100"); 43649758b77fSLuigi Rizzo } 436562ff38aeSLuigi Rizzo if (p.fs.flags_fs & DN_QSIZE_IS_BYTES) { 43662b2c3b23SDavid Malone size_t len; 43672b2c3b23SDavid Malone long limit; 43682b2c3b23SDavid Malone 43692b2c3b23SDavid Malone len = sizeof(limit); 43702b2c3b23SDavid Malone if (sysctlbyname("net.inet.ip.dummynet.pipe_byte_limit", 43712b2c3b23SDavid Malone &limit, &len, NULL, 0) == -1) 43722b2c3b23SDavid Malone limit = 1024*1024; 43732b2c3b23SDavid Malone if (p.fs.qsize > limit) 43742b2c3b23SDavid Malone errx(EX_DATAERR, "queue size must be < %ldB", limit); 43759758b77fSLuigi Rizzo } else { 43762b2c3b23SDavid Malone size_t len; 43772b2c3b23SDavid Malone long limit; 43782b2c3b23SDavid Malone 43792b2c3b23SDavid Malone len = sizeof(limit); 43802b2c3b23SDavid Malone if (sysctlbyname("net.inet.ip.dummynet.pipe_slot_limit", 43812b2c3b23SDavid Malone &limit, &len, NULL, 0) == -1) 43822b2c3b23SDavid Malone limit = 100; 43832b2c3b23SDavid Malone if (p.fs.qsize > limit) 43842b2c3b23SDavid Malone errx(EX_DATAERR, "2 <= queue size <= %ld", limit); 43859758b77fSLuigi Rizzo } 438662ff38aeSLuigi Rizzo if (p.fs.flags_fs & DN_IS_RED) { 43879758b77fSLuigi Rizzo size_t len; 43889758b77fSLuigi Rizzo int lookup_depth, avg_pkt_size; 43899758b77fSLuigi Rizzo double s, idle, weight, w_q; 439062ff38aeSLuigi Rizzo struct clockinfo ck; 43919758b77fSLuigi Rizzo int t; 43929758b77fSLuigi Rizzo 439362ff38aeSLuigi Rizzo if (p.fs.min_th >= p.fs.max_th) 43949758b77fSLuigi Rizzo errx(EX_DATAERR, "min_th %d must be < than max_th %d", 439562ff38aeSLuigi Rizzo p.fs.min_th, p.fs.max_th); 439662ff38aeSLuigi Rizzo if (p.fs.max_th == 0) 43979758b77fSLuigi Rizzo errx(EX_DATAERR, "max_th must be > 0"); 43989758b77fSLuigi Rizzo 43999758b77fSLuigi Rizzo len = sizeof(int); 44009758b77fSLuigi Rizzo if (sysctlbyname("net.inet.ip.dummynet.red_lookup_depth", 44019758b77fSLuigi Rizzo &lookup_depth, &len, NULL, 0) == -1) 44029758b77fSLuigi Rizzo errx(1, "sysctlbyname(\"%s\")", 44039758b77fSLuigi Rizzo "net.inet.ip.dummynet.red_lookup_depth"); 44049758b77fSLuigi Rizzo if (lookup_depth == 0) 44059758b77fSLuigi Rizzo errx(EX_DATAERR, "net.inet.ip.dummynet.red_lookup_depth" 44069758b77fSLuigi Rizzo " must be greater than zero"); 44079758b77fSLuigi Rizzo 44089758b77fSLuigi Rizzo len = sizeof(int); 44099758b77fSLuigi Rizzo if (sysctlbyname("net.inet.ip.dummynet.red_avg_pkt_size", 44109758b77fSLuigi Rizzo &avg_pkt_size, &len, NULL, 0) == -1) 44119758b77fSLuigi Rizzo 44129758b77fSLuigi Rizzo errx(1, "sysctlbyname(\"%s\")", 44139758b77fSLuigi Rizzo "net.inet.ip.dummynet.red_avg_pkt_size"); 44149758b77fSLuigi Rizzo if (avg_pkt_size == 0) 44159758b77fSLuigi Rizzo errx(EX_DATAERR, 44169758b77fSLuigi Rizzo "net.inet.ip.dummynet.red_avg_pkt_size must" 44179758b77fSLuigi Rizzo " be greater than zero"); 44189758b77fSLuigi Rizzo 44199758b77fSLuigi Rizzo len = sizeof(struct clockinfo); 442062ff38aeSLuigi Rizzo if (sysctlbyname("kern.clockrate", &ck, &len, NULL, 0) == -1) 44219758b77fSLuigi Rizzo errx(1, "sysctlbyname(\"%s\")", "kern.clockrate"); 44229758b77fSLuigi Rizzo 44239758b77fSLuigi Rizzo /* 44249758b77fSLuigi Rizzo * Ticks needed for sending a medium-sized packet. 44259758b77fSLuigi Rizzo * Unfortunately, when we are configuring a WF2Q+ queue, we 44269758b77fSLuigi Rizzo * do not have bandwidth information, because that is stored 44279758b77fSLuigi Rizzo * in the parent pipe, and also we have multiple queues 44289758b77fSLuigi Rizzo * competing for it. So we set s=0, which is not very 44299758b77fSLuigi Rizzo * correct. But on the other hand, why do we want RED with 44309758b77fSLuigi Rizzo * WF2Q+ ? 44319758b77fSLuigi Rizzo */ 443262ff38aeSLuigi Rizzo if (p.bandwidth==0) /* this is a WF2Q+ queue */ 44339758b77fSLuigi Rizzo s = 0; 44349758b77fSLuigi Rizzo else 4435d60810f2SOleg Bulyzhin s = (double)ck.hz * avg_pkt_size * 8 / p.bandwidth; 44369758b77fSLuigi Rizzo 44379758b77fSLuigi Rizzo /* 44389758b77fSLuigi Rizzo * max idle time (in ticks) before avg queue size becomes 0. 44399758b77fSLuigi Rizzo * NOTA: (3/w_q) is approx the value x so that 44409758b77fSLuigi Rizzo * (1-w_q)^x < 10^-3. 44419758b77fSLuigi Rizzo */ 444262ff38aeSLuigi Rizzo w_q = ((double)p.fs.w_q) / (1 << SCALE_RED); 44439758b77fSLuigi Rizzo idle = s * 3. / w_q; 444462ff38aeSLuigi Rizzo p.fs.lookup_step = (int)idle / lookup_depth; 444562ff38aeSLuigi Rizzo if (!p.fs.lookup_step) 444662ff38aeSLuigi Rizzo p.fs.lookup_step = 1; 44479758b77fSLuigi Rizzo weight = 1 - w_q; 4448d60810f2SOleg Bulyzhin for (t = p.fs.lookup_step; t > 1; --t) 4449d60810f2SOleg Bulyzhin weight *= 1 - w_q; 445062ff38aeSLuigi Rizzo p.fs.lookup_weight = (int)(weight * (1 << SCALE_RED)); 44519758b77fSLuigi Rizzo } 445262ff38aeSLuigi Rizzo i = do_cmd(IP_DUMMYNET_CONFIGURE, &p, sizeof p); 44539758b77fSLuigi Rizzo if (i) 44549758b77fSLuigi Rizzo err(1, "setsockopt(%s)", "IP_DUMMYNET_CONFIGURE"); 44559758b77fSLuigi Rizzo } 44569758b77fSLuigi Rizzo 44579758b77fSLuigi Rizzo static void 4458bd1d3456SMaxim Konovalov get_mac_addr_mask(const char *p, uint8_t *addr, uint8_t *mask) 44599758b77fSLuigi Rizzo { 44609758b77fSLuigi Rizzo int i, l; 4461bd1d3456SMaxim Konovalov char *ap, *ptr, *optr; 4462bd1d3456SMaxim Konovalov struct ether_addr *mac; 4463bd1d3456SMaxim Konovalov const char *macset = "0123456789abcdefABCDEF:"; 44649758b77fSLuigi Rizzo 4465bd1d3456SMaxim Konovalov if (strcmp(p, "any") == 0) { 4466bd1d3456SMaxim Konovalov for (i = 0; i < ETHER_ADDR_LEN; i++) 44679758b77fSLuigi Rizzo addr[i] = mask[i] = 0; 44689758b77fSLuigi Rizzo return; 4469bd1d3456SMaxim Konovalov } 44709758b77fSLuigi Rizzo 4471bd1d3456SMaxim Konovalov optr = ptr = strdup(p); 4472bd1d3456SMaxim Konovalov if ((ap = strsep(&ptr, "&/")) != NULL && *ap != 0) { 4473bd1d3456SMaxim Konovalov l = strlen(ap); 4474bd1d3456SMaxim Konovalov if (strspn(ap, macset) != l || (mac = ether_aton(ap)) == NULL) 4475bd1d3456SMaxim Konovalov errx(EX_DATAERR, "Incorrect MAC address"); 4476bd1d3456SMaxim Konovalov bcopy(mac, addr, ETHER_ADDR_LEN); 4477bd1d3456SMaxim Konovalov } else 4478bd1d3456SMaxim Konovalov errx(EX_DATAERR, "Incorrect MAC address"); 4479bd1d3456SMaxim Konovalov 4480bd1d3456SMaxim Konovalov if (ptr != NULL) { /* we have mask? */ 4481bd1d3456SMaxim Konovalov if (p[ptr - optr - 1] == '/') { /* mask len */ 4482bd1d3456SMaxim Konovalov l = strtol(ptr, &ap, 10); 4483bd1d3456SMaxim Konovalov if (*ap != 0 || l > ETHER_ADDR_LEN * 8 || l < 0) 4484bd1d3456SMaxim Konovalov errx(EX_DATAERR, "Incorrect mask length"); 4485bd1d3456SMaxim Konovalov for (i = 0; l > 0 && i < ETHER_ADDR_LEN; l -= 8, i++) 44869758b77fSLuigi Rizzo mask[i] = (l >= 8) ? 0xff: (~0) << (8 - l); 4487bd1d3456SMaxim Konovalov } else { /* mask */ 4488bd1d3456SMaxim Konovalov l = strlen(ptr); 4489bd1d3456SMaxim Konovalov if (strspn(ptr, macset) != l || 4490bd1d3456SMaxim Konovalov (mac = ether_aton(ptr)) == NULL) 4491bd1d3456SMaxim Konovalov errx(EX_DATAERR, "Incorrect mask"); 4492bd1d3456SMaxim Konovalov bcopy(mac, mask, ETHER_ADDR_LEN); 44939758b77fSLuigi Rizzo } 4494bd1d3456SMaxim Konovalov } else { /* default mask: ff:ff:ff:ff:ff:ff */ 4495bd1d3456SMaxim Konovalov for (i = 0; i < ETHER_ADDR_LEN; i++) 44969758b77fSLuigi Rizzo mask[i] = 0xff; 44979758b77fSLuigi Rizzo } 4498bd1d3456SMaxim Konovalov for (i = 0; i < ETHER_ADDR_LEN; i++) 44999758b77fSLuigi Rizzo addr[i] &= mask[i]; 4500bd1d3456SMaxim Konovalov 4501bd1d3456SMaxim Konovalov free(optr); 45029758b77fSLuigi Rizzo } 45039758b77fSLuigi Rizzo 45049758b77fSLuigi Rizzo /* 45059758b77fSLuigi Rizzo * helper function, updates the pointer to cmd with the length 45069758b77fSLuigi Rizzo * of the current command, and also cleans up the first word of 45079758b77fSLuigi Rizzo * the new command in case it has been clobbered before. 45089758b77fSLuigi Rizzo */ 45099758b77fSLuigi Rizzo static ipfw_insn * 45109758b77fSLuigi Rizzo next_cmd(ipfw_insn *cmd) 45119758b77fSLuigi Rizzo { 45129758b77fSLuigi Rizzo cmd += F_LEN(cmd); 45139758b77fSLuigi Rizzo bzero(cmd, sizeof(*cmd)); 45149758b77fSLuigi Rizzo return cmd; 45159758b77fSLuigi Rizzo } 45169758b77fSLuigi Rizzo 45179758b77fSLuigi Rizzo /* 451862ff38aeSLuigi Rizzo * Takes arguments and copies them into a comment 451962ff38aeSLuigi Rizzo */ 452062ff38aeSLuigi Rizzo static void 452162ff38aeSLuigi Rizzo fill_comment(ipfw_insn *cmd, int ac, char **av) 452262ff38aeSLuigi Rizzo { 452362ff38aeSLuigi Rizzo int i, l; 452462ff38aeSLuigi Rizzo char *p = (char *)(cmd + 1); 452562ff38aeSLuigi Rizzo 452662ff38aeSLuigi Rizzo cmd->opcode = O_NOP; 452762ff38aeSLuigi Rizzo cmd->len = (cmd->len & (F_NOT | F_OR)); 452862ff38aeSLuigi Rizzo 452962ff38aeSLuigi Rizzo /* Compute length of comment string. */ 453062ff38aeSLuigi Rizzo for (i = 0, l = 0; i < ac; i++) 453162ff38aeSLuigi Rizzo l += strlen(av[i]) + 1; 453262ff38aeSLuigi Rizzo if (l == 0) 453362ff38aeSLuigi Rizzo return; 453462ff38aeSLuigi Rizzo if (l > 84) 453562ff38aeSLuigi Rizzo errx(EX_DATAERR, 453662ff38aeSLuigi Rizzo "comment too long (max 80 chars)"); 453762ff38aeSLuigi Rizzo l = 1 + (l+3)/4; 453862ff38aeSLuigi Rizzo cmd->len = (cmd->len & (F_NOT | F_OR)) | l; 453962ff38aeSLuigi Rizzo for (i = 0; i < ac; i++) { 454062ff38aeSLuigi Rizzo strcpy(p, av[i]); 454162ff38aeSLuigi Rizzo p += strlen(av[i]); 454262ff38aeSLuigi Rizzo *p++ = ' '; 454362ff38aeSLuigi Rizzo } 454462ff38aeSLuigi Rizzo *(--p) = '\0'; 454562ff38aeSLuigi Rizzo } 454662ff38aeSLuigi Rizzo 454762ff38aeSLuigi Rizzo /* 45489758b77fSLuigi Rizzo * A function to fill simple commands of size 1. 45499758b77fSLuigi Rizzo * Existing flags are preserved. 45509758b77fSLuigi Rizzo */ 45519758b77fSLuigi Rizzo static void 4552571f8c1bSLuigi Rizzo fill_cmd(ipfw_insn *cmd, enum ipfw_opcodes opcode, int flags, uint16_t arg) 45539758b77fSLuigi Rizzo { 45549758b77fSLuigi Rizzo cmd->opcode = opcode; 45559758b77fSLuigi Rizzo cmd->len = ((cmd->len | flags) & (F_NOT | F_OR)) | 1; 45569758b77fSLuigi Rizzo cmd->arg1 = arg; 45579758b77fSLuigi Rizzo } 45589758b77fSLuigi Rizzo 45599758b77fSLuigi Rizzo /* 45609758b77fSLuigi Rizzo * Fetch and add the MAC address and type, with masks. This generates one or 45619758b77fSLuigi Rizzo * two microinstructions, and returns the pointer to the last one. 45629758b77fSLuigi Rizzo */ 45639758b77fSLuigi Rizzo static ipfw_insn * 45649758b77fSLuigi Rizzo add_mac(ipfw_insn *cmd, int ac, char *av[]) 45659758b77fSLuigi Rizzo { 4566e706181bSLuigi Rizzo ipfw_insn_mac *mac; 45679758b77fSLuigi Rizzo 456899e5e645SLuigi Rizzo if (ac < 2) 45695a155b40SLuigi Rizzo errx(EX_DATAERR, "MAC dst src"); 45709758b77fSLuigi Rizzo 45719758b77fSLuigi Rizzo cmd->opcode = O_MACADDR2; 45729758b77fSLuigi Rizzo cmd->len = (cmd->len & (F_NOT | F_OR)) | F_INSN_SIZE(ipfw_insn_mac); 45739758b77fSLuigi Rizzo 45749758b77fSLuigi Rizzo mac = (ipfw_insn_mac *)cmd; 45759758b77fSLuigi Rizzo get_mac_addr_mask(av[0], mac->addr, mac->mask); /* dst */ 4576bd1d3456SMaxim Konovalov get_mac_addr_mask(av[1], &(mac->addr[ETHER_ADDR_LEN]), 4577bd1d3456SMaxim Konovalov &(mac->mask[ETHER_ADDR_LEN])); /* src */ 4578e706181bSLuigi Rizzo return cmd; 45799758b77fSLuigi Rizzo } 45809758b77fSLuigi Rizzo 4581e706181bSLuigi Rizzo static ipfw_insn * 4582e706181bSLuigi Rizzo add_mactype(ipfw_insn *cmd, int ac, char *av) 4583e706181bSLuigi Rizzo { 4584e706181bSLuigi Rizzo if (ac < 1) 4585e706181bSLuigi Rizzo errx(EX_DATAERR, "missing MAC type"); 4586e706181bSLuigi Rizzo if (strcmp(av, "any") != 0) { /* we have a non-null type */ 4587e706181bSLuigi Rizzo fill_newports((ipfw_insn_u16 *)cmd, av, IPPROTO_ETHERTYPE); 4588e706181bSLuigi Rizzo cmd->opcode = O_MAC_TYPE; 45899758b77fSLuigi Rizzo return cmd; 4590e706181bSLuigi Rizzo } else 4591e706181bSLuigi Rizzo return NULL; 4592e706181bSLuigi Rizzo } 4593e706181bSLuigi Rizzo 4594e706181bSLuigi Rizzo static ipfw_insn * 459536c263ccSHajimu UMEMOTO add_proto0(ipfw_insn *cmd, char *av, u_char *protop) 4596e706181bSLuigi Rizzo { 4597e706181bSLuigi Rizzo struct protoent *pe; 459836c263ccSHajimu UMEMOTO char *ep; 459936c263ccSHajimu UMEMOTO int proto; 46008195404bSBrooks Davis 4601c6ec0226SHajimu UMEMOTO proto = strtol(av, &ep, 10); 4602c6ec0226SHajimu UMEMOTO if (*ep != '\0' || proto <= 0) { 460336c263ccSHajimu UMEMOTO if ((pe = getprotobyname(av)) == NULL) 460436c263ccSHajimu UMEMOTO return NULL; 460536c263ccSHajimu UMEMOTO proto = pe->p_proto; 460636c263ccSHajimu UMEMOTO } 460736c263ccSHajimu UMEMOTO 460836c263ccSHajimu UMEMOTO fill_cmd(cmd, O_PROTO, 0, proto); 460936c263ccSHajimu UMEMOTO *protop = proto; 461036c263ccSHajimu UMEMOTO return cmd; 461136c263ccSHajimu UMEMOTO } 461236c263ccSHajimu UMEMOTO 461336c263ccSHajimu UMEMOTO static ipfw_insn * 461436c263ccSHajimu UMEMOTO add_proto(ipfw_insn *cmd, char *av, u_char *protop) 461536c263ccSHajimu UMEMOTO { 461636c263ccSHajimu UMEMOTO u_char proto = IPPROTO_IP; 4617e706181bSLuigi Rizzo 4618c6ec0226SHajimu UMEMOTO if (_substrcmp(av, "all") == 0 || strcmp(av, "ip") == 0) 461957cd6d26SMax Laier ; /* do not set O_IP4 nor O_IP6 */ 462036c263ccSHajimu UMEMOTO else if (strcmp(av, "ip4") == 0) 462136c263ccSHajimu UMEMOTO /* explicit "just IPv4" rule */ 462236c263ccSHajimu UMEMOTO fill_cmd(cmd, O_IP4, 0, 0); 462336c263ccSHajimu UMEMOTO else if (strcmp(av, "ip6") == 0) { 462436c263ccSHajimu UMEMOTO /* explicit "just IPv6" rule */ 462536c263ccSHajimu UMEMOTO proto = IPPROTO_IPV6; 462636c263ccSHajimu UMEMOTO fill_cmd(cmd, O_IP6, 0, 0); 462736c263ccSHajimu UMEMOTO } else 462836c263ccSHajimu UMEMOTO return add_proto0(cmd, av, protop); 462936c263ccSHajimu UMEMOTO 463036c263ccSHajimu UMEMOTO *protop = proto; 463136c263ccSHajimu UMEMOTO return cmd; 463236c263ccSHajimu UMEMOTO } 463336c263ccSHajimu UMEMOTO 463436c263ccSHajimu UMEMOTO static ipfw_insn * 463536c263ccSHajimu UMEMOTO add_proto_compat(ipfw_insn *cmd, char *av, u_char *protop) 463636c263ccSHajimu UMEMOTO { 463736c263ccSHajimu UMEMOTO u_char proto = IPPROTO_IP; 463836c263ccSHajimu UMEMOTO 463936c263ccSHajimu UMEMOTO if (_substrcmp(av, "all") == 0 || strcmp(av, "ip") == 0) 464036c263ccSHajimu UMEMOTO ; /* do not set O_IP4 nor O_IP6 */ 464157cd6d26SMax Laier else if (strcmp(av, "ipv4") == 0 || strcmp(av, "ip4") == 0) 464257cd6d26SMax Laier /* explicit "just IPv4" rule */ 464357cd6d26SMax Laier fill_cmd(cmd, O_IP4, 0, 0); 464457cd6d26SMax Laier else if (strcmp(av, "ipv6") == 0 || strcmp(av, "ip6") == 0) { 464557cd6d26SMax Laier /* explicit "just IPv6" rule */ 464636c263ccSHajimu UMEMOTO proto = IPPROTO_IPV6; 464757cd6d26SMax Laier fill_cmd(cmd, O_IP6, 0, 0); 464836c263ccSHajimu UMEMOTO } else 464936c263ccSHajimu UMEMOTO return add_proto0(cmd, av, protop); 46508195404bSBrooks Davis 465136c263ccSHajimu UMEMOTO *protop = proto; 4652e706181bSLuigi Rizzo return cmd; 4653e706181bSLuigi Rizzo } 4654e706181bSLuigi Rizzo 4655e706181bSLuigi Rizzo static ipfw_insn * 4656e706181bSLuigi Rizzo add_srcip(ipfw_insn *cmd, char *av) 4657e706181bSLuigi Rizzo { 4658e706181bSLuigi Rizzo fill_ip((ipfw_insn_ip *)cmd, av); 4659e706181bSLuigi Rizzo if (cmd->opcode == O_IP_DST_SET) /* set */ 4660e706181bSLuigi Rizzo cmd->opcode = O_IP_SRC_SET; 4661cd8b5ae0SRuslan Ermilov else if (cmd->opcode == O_IP_DST_LOOKUP) /* table */ 4662cd8b5ae0SRuslan Ermilov cmd->opcode = O_IP_SRC_LOOKUP; 4663e706181bSLuigi Rizzo else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) /* me */ 4664e706181bSLuigi Rizzo cmd->opcode = O_IP_SRC_ME; 4665e706181bSLuigi Rizzo else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn_u32)) /* one IP */ 4666e706181bSLuigi Rizzo cmd->opcode = O_IP_SRC; 4667571f8c1bSLuigi Rizzo else /* addr/mask */ 4668e706181bSLuigi Rizzo cmd->opcode = O_IP_SRC_MASK; 4669e706181bSLuigi Rizzo return cmd; 4670e706181bSLuigi Rizzo } 4671e706181bSLuigi Rizzo 4672e706181bSLuigi Rizzo static ipfw_insn * 4673e706181bSLuigi Rizzo add_dstip(ipfw_insn *cmd, char *av) 4674e706181bSLuigi Rizzo { 4675e706181bSLuigi Rizzo fill_ip((ipfw_insn_ip *)cmd, av); 4676e706181bSLuigi Rizzo if (cmd->opcode == O_IP_DST_SET) /* set */ 4677e706181bSLuigi Rizzo ; 4678cd8b5ae0SRuslan Ermilov else if (cmd->opcode == O_IP_DST_LOOKUP) /* table */ 4679cd8b5ae0SRuslan Ermilov ; 4680e706181bSLuigi Rizzo else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) /* me */ 4681e706181bSLuigi Rizzo cmd->opcode = O_IP_DST_ME; 4682e706181bSLuigi Rizzo else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn_u32)) /* one IP */ 4683e706181bSLuigi Rizzo cmd->opcode = O_IP_DST; 4684571f8c1bSLuigi Rizzo else /* addr/mask */ 4685e706181bSLuigi Rizzo cmd->opcode = O_IP_DST_MASK; 4686e706181bSLuigi Rizzo return cmd; 4687e706181bSLuigi Rizzo } 4688e706181bSLuigi Rizzo 4689e706181bSLuigi Rizzo static ipfw_insn * 4690e706181bSLuigi Rizzo add_ports(ipfw_insn *cmd, char *av, u_char proto, int opcode) 4691e706181bSLuigi Rizzo { 469201750186SBrooks Davis if (_substrcmp(av, "any") == 0) { 4693e706181bSLuigi Rizzo return NULL; 4694e706181bSLuigi Rizzo } else if (fill_newports((ipfw_insn_u16 *)cmd, av, proto)) { 4695e706181bSLuigi Rizzo /* XXX todo: check that we have a protocol with ports */ 4696e706181bSLuigi Rizzo cmd->opcode = opcode; 4697e706181bSLuigi Rizzo return cmd; 4698e706181bSLuigi Rizzo } 4699e706181bSLuigi Rizzo return NULL; 47009758b77fSLuigi Rizzo } 47019758b77fSLuigi Rizzo 47028195404bSBrooks Davis static ipfw_insn * 47038195404bSBrooks Davis add_src(ipfw_insn *cmd, char *av, u_char proto) 47048195404bSBrooks Davis { 47058195404bSBrooks Davis struct in6_addr a; 4706926bbf90SMax Laier char *host, *ch; 4707926bbf90SMax Laier ipfw_insn *ret = NULL; 4708926bbf90SMax Laier 4709926bbf90SMax Laier if ((host = strdup(av)) == NULL) 4710926bbf90SMax Laier return NULL; 4711926bbf90SMax Laier if ((ch = strrchr(host, '/')) != NULL) 4712926bbf90SMax Laier *ch = '\0'; 47138195404bSBrooks Davis 47148195404bSBrooks Davis if (proto == IPPROTO_IPV6 || strcmp(av, "me6") == 0 || 4715926bbf90SMax Laier inet_pton(AF_INET6, host, &a)) 4716926bbf90SMax Laier ret = add_srcip6(cmd, av); 47178195404bSBrooks Davis /* XXX: should check for IPv4, not !IPv6 */ 4718e28cb025SDavid Malone if (ret == NULL && (proto == IPPROTO_IP || strcmp(av, "me") == 0 || 4719e28cb025SDavid Malone !inet_pton(AF_INET6, host, &a))) 4720926bbf90SMax Laier ret = add_srcip(cmd, av); 4721e28cb025SDavid Malone if (ret == NULL && strcmp(av, "any") != 0) 4722926bbf90SMax Laier ret = cmd; 47238195404bSBrooks Davis 4724926bbf90SMax Laier free(host); 4725926bbf90SMax Laier return ret; 47268195404bSBrooks Davis } 47278195404bSBrooks Davis 47288195404bSBrooks Davis static ipfw_insn * 47298195404bSBrooks Davis add_dst(ipfw_insn *cmd, char *av, u_char proto) 47308195404bSBrooks Davis { 47318195404bSBrooks Davis struct in6_addr a; 4732926bbf90SMax Laier char *host, *ch; 4733926bbf90SMax Laier ipfw_insn *ret = NULL; 4734926bbf90SMax Laier 4735926bbf90SMax Laier if ((host = strdup(av)) == NULL) 4736926bbf90SMax Laier return NULL; 4737926bbf90SMax Laier if ((ch = strrchr(host, '/')) != NULL) 4738926bbf90SMax Laier *ch = '\0'; 47398195404bSBrooks Davis 47408195404bSBrooks Davis if (proto == IPPROTO_IPV6 || strcmp(av, "me6") == 0 || 4741926bbf90SMax Laier inet_pton(AF_INET6, host, &a)) 4742926bbf90SMax Laier ret = add_dstip6(cmd, av); 47438195404bSBrooks Davis /* XXX: should check for IPv4, not !IPv6 */ 4744e28cb025SDavid Malone if (ret == NULL && (proto == IPPROTO_IP || strcmp(av, "me") == 0 || 4745e28cb025SDavid Malone !inet_pton(AF_INET6, host, &a))) 4746926bbf90SMax Laier ret = add_dstip(cmd, av); 4747e28cb025SDavid Malone if (ret == NULL && strcmp(av, "any") != 0) 4748926bbf90SMax Laier ret = cmd; 47498195404bSBrooks Davis 4750926bbf90SMax Laier free(host); 4751926bbf90SMax Laier return ret; 47528195404bSBrooks Davis } 47538195404bSBrooks Davis 47549758b77fSLuigi Rizzo /* 47559758b77fSLuigi Rizzo * Parse arguments and assemble the microinstructions which make up a rule. 47569758b77fSLuigi Rizzo * Rules are added into the 'rulebuf' and then copied in the correct order 47579758b77fSLuigi Rizzo * into the actual rule. 47589758b77fSLuigi Rizzo * 4759974dfe30SBrian Feldman * The syntax for a rule starts with the action, followed by 4760974dfe30SBrian Feldman * optional action parameters, and the various match patterns. 47619d5abbddSJens Schweikhardt * In the assembled microcode, the first opcode must be an O_PROBE_STATE 47629758b77fSLuigi Rizzo * (generated if the rule includes a keep-state option), then the 4763974dfe30SBrian Feldman * various match patterns, log/altq actions, and the actual action. 47649758b77fSLuigi Rizzo * 47659758b77fSLuigi Rizzo */ 47669758b77fSLuigi Rizzo static void 47679758b77fSLuigi Rizzo add(int ac, char *av[]) 47689758b77fSLuigi Rizzo { 47699758b77fSLuigi Rizzo /* 47709758b77fSLuigi Rizzo * rules are added into the 'rulebuf' and then copied in 47719758b77fSLuigi Rizzo * the correct order into the actual rule. 47729758b77fSLuigi Rizzo * Some things that need to go out of order (prob, action etc.) 47739758b77fSLuigi Rizzo * go into actbuf[]. 47749758b77fSLuigi Rizzo */ 4775571f8c1bSLuigi Rizzo static uint32_t rulebuf[255], actbuf[255], cmdbuf[255]; 47769758b77fSLuigi Rizzo 477762ff38aeSLuigi Rizzo ipfw_insn *src, *dst, *cmd, *action, *prev=NULL; 4778e706181bSLuigi Rizzo ipfw_insn *first_cmd; /* first match pattern */ 47799758b77fSLuigi Rizzo 47809758b77fSLuigi Rizzo struct ip_fw *rule; 47819758b77fSLuigi Rizzo 47829758b77fSLuigi Rizzo /* 47839758b77fSLuigi Rizzo * various flags used to record that we entered some fields. 47849758b77fSLuigi Rizzo */ 478552bc23abSLuigi Rizzo ipfw_insn *have_state = NULL; /* check-state or keep-state */ 47866a7d5cb6SOleg Bulyzhin ipfw_insn *have_log = NULL, *have_altq = NULL, *have_tag = NULL; 47879ec4f2e1SMaxim Konovalov size_t len; 47889758b77fSLuigi Rizzo 47899758b77fSLuigi Rizzo int i; 47909758b77fSLuigi Rizzo 47919758b77fSLuigi Rizzo int open_par = 0; /* open parenthesis ( */ 47929758b77fSLuigi Rizzo 47939758b77fSLuigi Rizzo /* proto is here because it is used to fetch ports */ 47949758b77fSLuigi Rizzo u_char proto = IPPROTO_IP; /* default protocol */ 47959758b77fSLuigi Rizzo 479612b5dc6aSLuigi Rizzo double match_prob = 1; /* match probability, default is always match */ 479712b5dc6aSLuigi Rizzo 47989758b77fSLuigi Rizzo bzero(actbuf, sizeof(actbuf)); /* actions go here */ 47999758b77fSLuigi Rizzo bzero(cmdbuf, sizeof(cmdbuf)); 48009758b77fSLuigi Rizzo bzero(rulebuf, sizeof(rulebuf)); 48019758b77fSLuigi Rizzo 48029758b77fSLuigi Rizzo rule = (struct ip_fw *)rulebuf; 48039758b77fSLuigi Rizzo cmd = (ipfw_insn *)cmdbuf; 48049758b77fSLuigi Rizzo action = (ipfw_insn *)actbuf; 48059758b77fSLuigi Rizzo 48069758b77fSLuigi Rizzo av++; ac--; 48079758b77fSLuigi Rizzo 48089758b77fSLuigi Rizzo /* [rule N] -- Rule number optional */ 48099758b77fSLuigi Rizzo if (ac && isdigit(**av)) { 48109758b77fSLuigi Rizzo rule->rulenum = atoi(*av); 48119758b77fSLuigi Rizzo av++; 48129758b77fSLuigi Rizzo ac--; 48139758b77fSLuigi Rizzo } 48149758b77fSLuigi Rizzo 48153004afcaSLuigi Rizzo /* [set N] -- set number (0..RESVD_SET), optional */ 481601750186SBrooks Davis if (ac > 1 && _substrcmp(*av, "set") == 0) { 481743405724SLuigi Rizzo int set = strtoul(av[1], NULL, 10); 48183004afcaSLuigi Rizzo if (set < 0 || set > RESVD_SET) 481943405724SLuigi Rizzo errx(EX_DATAERR, "illegal set %s", av[1]); 482043405724SLuigi Rizzo rule->set = set; 482143405724SLuigi Rizzo av += 2; ac -= 2; 482243405724SLuigi Rizzo } 482343405724SLuigi Rizzo 48249758b77fSLuigi Rizzo /* [prob D] -- match probability, optional */ 482501750186SBrooks Davis if (ac > 1 && _substrcmp(*av, "prob") == 0) { 482612b5dc6aSLuigi Rizzo match_prob = strtod(av[1], NULL); 48279758b77fSLuigi Rizzo 482812b5dc6aSLuigi Rizzo if (match_prob <= 0 || match_prob > 1) 48299758b77fSLuigi Rizzo errx(EX_DATAERR, "illegal match prob. %s", av[1]); 48309758b77fSLuigi Rizzo av += 2; ac -= 2; 48319758b77fSLuigi Rizzo } 48329758b77fSLuigi Rizzo 48339758b77fSLuigi Rizzo /* action -- mandatory */ 48349758b77fSLuigi Rizzo NEED1("missing action"); 48359758b77fSLuigi Rizzo i = match_token(rule_actions, *av); 48369758b77fSLuigi Rizzo ac--; av++; 48379758b77fSLuigi Rizzo action->len = 1; /* default */ 48389758b77fSLuigi Rizzo switch(i) { 48399758b77fSLuigi Rizzo case TOK_CHECKSTATE: 484052bc23abSLuigi Rizzo have_state = action; 48419758b77fSLuigi Rizzo action->opcode = O_CHECK_STATE; 48429758b77fSLuigi Rizzo break; 48439758b77fSLuigi Rizzo 48449758b77fSLuigi Rizzo case TOK_ACCEPT: 48459758b77fSLuigi Rizzo action->opcode = O_ACCEPT; 48469758b77fSLuigi Rizzo break; 48479758b77fSLuigi Rizzo 48489758b77fSLuigi Rizzo case TOK_DENY: 48499758b77fSLuigi Rizzo action->opcode = O_DENY; 48505e43aef8SLuigi Rizzo action->arg1 = 0; 48515e43aef8SLuigi Rizzo break; 48525e43aef8SLuigi Rizzo 48535e43aef8SLuigi Rizzo case TOK_REJECT: 48545e43aef8SLuigi Rizzo action->opcode = O_REJECT; 48555e43aef8SLuigi Rizzo action->arg1 = ICMP_UNREACH_HOST; 48565e43aef8SLuigi Rizzo break; 48575e43aef8SLuigi Rizzo 48585e43aef8SLuigi Rizzo case TOK_RESET: 48595e43aef8SLuigi Rizzo action->opcode = O_REJECT; 48605e43aef8SLuigi Rizzo action->arg1 = ICMP_REJECT_RST; 48615e43aef8SLuigi Rizzo break; 48625e43aef8SLuigi Rizzo 48639066356bSBjoern A. Zeeb case TOK_RESET6: 48649066356bSBjoern A. Zeeb action->opcode = O_UNREACH6; 48659066356bSBjoern A. Zeeb action->arg1 = ICMP6_UNREACH_RST; 48669066356bSBjoern A. Zeeb break; 48679066356bSBjoern A. Zeeb 48685e43aef8SLuigi Rizzo case TOK_UNREACH: 48695e43aef8SLuigi Rizzo action->opcode = O_REJECT; 48705e43aef8SLuigi Rizzo NEED1("missing reject code"); 48715e43aef8SLuigi Rizzo fill_reject_code(&action->arg1, *av); 48725e43aef8SLuigi Rizzo ac--; av++; 48739758b77fSLuigi Rizzo break; 48749758b77fSLuigi Rizzo 48759066356bSBjoern A. Zeeb case TOK_UNREACH6: 48769066356bSBjoern A. Zeeb action->opcode = O_UNREACH6; 48779066356bSBjoern A. Zeeb NEED1("missing unreach code"); 48789066356bSBjoern A. Zeeb fill_unreach6_code(&action->arg1, *av); 48799066356bSBjoern A. Zeeb ac--; av++; 48809066356bSBjoern A. Zeeb break; 48819066356bSBjoern A. Zeeb 48829758b77fSLuigi Rizzo case TOK_COUNT: 48839758b77fSLuigi Rizzo action->opcode = O_COUNT; 48849758b77fSLuigi Rizzo break; 48859758b77fSLuigi Rizzo 4886f94a7fc0SPaolo Pisati case TOK_NAT: 4887f94a7fc0SPaolo Pisati action->opcode = O_NAT; 4888f94a7fc0SPaolo Pisati action->len = F_INSN_SIZE(ipfw_insn_nat); 4889f94a7fc0SPaolo Pisati goto chkarg; 48908b07e49aSJulian Elischer 48919758b77fSLuigi Rizzo case TOK_QUEUE: 48929758b77fSLuigi Rizzo action->opcode = O_QUEUE; 489340b1ae9eSGleb Smirnoff goto chkarg; 489440b1ae9eSGleb Smirnoff case TOK_PIPE: 48959758b77fSLuigi Rizzo action->opcode = O_PIPE; 489640b1ae9eSGleb Smirnoff goto chkarg; 489740b1ae9eSGleb Smirnoff case TOK_SKIPTO: 48989758b77fSLuigi Rizzo action->opcode = O_SKIPTO; 489940b1ae9eSGleb Smirnoff goto chkarg; 490040b1ae9eSGleb Smirnoff case TOK_NETGRAPH: 490140b1ae9eSGleb Smirnoff action->opcode = O_NETGRAPH; 490240b1ae9eSGleb Smirnoff goto chkarg; 490340b1ae9eSGleb Smirnoff case TOK_NGTEE: 490440b1ae9eSGleb Smirnoff action->opcode = O_NGTEE; 490540b1ae9eSGleb Smirnoff goto chkarg; 49069758b77fSLuigi Rizzo case TOK_DIVERT: 490740b1ae9eSGleb Smirnoff action->opcode = O_DIVERT; 490840b1ae9eSGleb Smirnoff goto chkarg; 49099758b77fSLuigi Rizzo case TOK_TEE: 491040b1ae9eSGleb Smirnoff action->opcode = O_TEE; 491140b1ae9eSGleb Smirnoff chkarg: 491240b1ae9eSGleb Smirnoff if (!ac) 491340b1ae9eSGleb Smirnoff errx(EX_USAGE, "missing argument for %s", *(av - 1)); 491440b1ae9eSGleb Smirnoff if (isdigit(**av)) { 491540b1ae9eSGleb Smirnoff action->arg1 = strtoul(*av, NULL, 10); 491640b1ae9eSGleb Smirnoff if (action->arg1 <= 0 || action->arg1 >= IP_FW_TABLEARG) 491740b1ae9eSGleb Smirnoff errx(EX_DATAERR, "illegal argument for %s", 491840b1ae9eSGleb Smirnoff *(av - 1)); 491940b1ae9eSGleb Smirnoff } else if (_substrcmp(*av, TABLEARG) == 0) { 492040b1ae9eSGleb Smirnoff action->arg1 = IP_FW_TABLEARG; 492140b1ae9eSGleb Smirnoff } else if (i == TOK_DIVERT || i == TOK_TEE) { 49229758b77fSLuigi Rizzo struct servent *s; 49239758b77fSLuigi Rizzo setservent(1); 49249758b77fSLuigi Rizzo s = getservbyname(av[0], "divert"); 49259758b77fSLuigi Rizzo if (s != NULL) 49269758b77fSLuigi Rizzo action->arg1 = ntohs(s->s_port); 49279758b77fSLuigi Rizzo else 49289758b77fSLuigi Rizzo errx(EX_DATAERR, "illegal divert/tee port"); 492940b1ae9eSGleb Smirnoff } else 493040b1ae9eSGleb Smirnoff errx(EX_DATAERR, "illegal argument for %s", *(av - 1)); 4931670742a1SGleb Smirnoff ac--; av++; 4932670742a1SGleb Smirnoff break; 4933670742a1SGleb Smirnoff 49349758b77fSLuigi Rizzo case TOK_FORWARD: { 49359758b77fSLuigi Rizzo ipfw_insn_sa *p = (ipfw_insn_sa *)action; 49369758b77fSLuigi Rizzo char *s, *end; 49379758b77fSLuigi Rizzo 49389758b77fSLuigi Rizzo NEED1("missing forward address[:port]"); 49399758b77fSLuigi Rizzo 49409758b77fSLuigi Rizzo action->opcode = O_FORWARD_IP; 49419758b77fSLuigi Rizzo action->len = F_INSN_SIZE(ipfw_insn_sa); 49429758b77fSLuigi Rizzo 49439758b77fSLuigi Rizzo p->sa.sin_len = sizeof(struct sockaddr_in); 49449758b77fSLuigi Rizzo p->sa.sin_family = AF_INET; 49459758b77fSLuigi Rizzo p->sa.sin_port = 0; 49469758b77fSLuigi Rizzo /* 49479758b77fSLuigi Rizzo * locate the address-port separator (':' or ',') 49489758b77fSLuigi Rizzo */ 49499758b77fSLuigi Rizzo s = strchr(*av, ':'); 49509758b77fSLuigi Rizzo if (s == NULL) 49519758b77fSLuigi Rizzo s = strchr(*av, ','); 49529758b77fSLuigi Rizzo if (s != NULL) { 49539758b77fSLuigi Rizzo *(s++) = '\0'; 49549758b77fSLuigi Rizzo i = strtoport(s, &end, 0 /* base */, 0 /* proto */); 49559758b77fSLuigi Rizzo if (s == end) 49569758b77fSLuigi Rizzo errx(EX_DATAERR, 49579758b77fSLuigi Rizzo "illegal forwarding port ``%s''", s); 49584f531a53SLuigi Rizzo p->sa.sin_port = (u_short)i; 49599758b77fSLuigi Rizzo } 4960afad78e2SJulian Elischer if (_substrcmp(*av, "tablearg") == 0) 4961afad78e2SJulian Elischer p->sa.sin_addr.s_addr = INADDR_ANY; 4962afad78e2SJulian Elischer else 49639758b77fSLuigi Rizzo lookup_host(*av, &(p->sa.sin_addr)); 49649758b77fSLuigi Rizzo ac--; av++; 49659758b77fSLuigi Rizzo break; 4966c487be96SJulian Elischer } 496762ff38aeSLuigi Rizzo case TOK_COMMENT: 496862ff38aeSLuigi Rizzo /* pretend it is a 'count' rule followed by the comment */ 496962ff38aeSLuigi Rizzo action->opcode = O_COUNT; 497062ff38aeSLuigi Rizzo ac++; av--; /* go back... */ 497162ff38aeSLuigi Rizzo break; 497262ff38aeSLuigi Rizzo 49738b07e49aSJulian Elischer case TOK_SETFIB: 49748b07e49aSJulian Elischer { 49758b07e49aSJulian Elischer int numfibs; 497605b0fdacSJulian Elischer size_t intsize = sizeof(int); 49778b07e49aSJulian Elischer 49788b07e49aSJulian Elischer action->opcode = O_SETFIB; 49798b07e49aSJulian Elischer NEED1("missing fib number"); 49808b07e49aSJulian Elischer action->arg1 = strtoul(*av, NULL, 10); 498105b0fdacSJulian Elischer if (sysctlbyname("net.fibs", &numfibs, &intsize, NULL, 0) == -1) 49828b07e49aSJulian Elischer errx(EX_DATAERR, "fibs not suported.\n"); 49838b07e49aSJulian Elischer if (action->arg1 >= numfibs) /* Temporary */ 49848b07e49aSJulian Elischer errx(EX_DATAERR, "fib too large.\n"); 49858b07e49aSJulian Elischer ac--; av++; 49868b07e49aSJulian Elischer break; 49878b07e49aSJulian Elischer } 49888b07e49aSJulian Elischer 49899758b77fSLuigi Rizzo default: 4990e706181bSLuigi Rizzo errx(EX_DATAERR, "invalid action %s\n", av[-1]); 49919758b77fSLuigi Rizzo } 49929758b77fSLuigi Rizzo action = next_cmd(action); 49939758b77fSLuigi Rizzo 49949758b77fSLuigi Rizzo /* 4995974dfe30SBrian Feldman * [altq queuename] -- altq tag, optional 49969758b77fSLuigi Rizzo * [log [logamount N]] -- log, optional 49979758b77fSLuigi Rizzo * 4998974dfe30SBrian Feldman * If they exist, it go first in the cmdbuf, but then it is 49999758b77fSLuigi Rizzo * skipped in the copy section to the end of the buffer. 50009758b77fSLuigi Rizzo */ 5001974dfe30SBrian Feldman while (ac != 0 && (i = match_token(rule_action_params, *av)) != -1) { 5002974dfe30SBrian Feldman ac--; av++; 5003974dfe30SBrian Feldman switch (i) { 5004974dfe30SBrian Feldman case TOK_LOG: 5005974dfe30SBrian Feldman { 50069758b77fSLuigi Rizzo ipfw_insn_log *c = (ipfw_insn_log *)cmd; 500762ff38aeSLuigi Rizzo int l; 50089758b77fSLuigi Rizzo 5009974dfe30SBrian Feldman if (have_log) 5010974dfe30SBrian Feldman errx(EX_DATAERR, 5011974dfe30SBrian Feldman "log cannot be specified more than once"); 5012974dfe30SBrian Feldman have_log = (ipfw_insn *)c; 50139758b77fSLuigi Rizzo cmd->len = F_INSN_SIZE(ipfw_insn_log); 50149758b77fSLuigi Rizzo cmd->opcode = O_LOG; 501501750186SBrooks Davis if (ac && _substrcmp(*av, "logamount") == 0) { 50169758b77fSLuigi Rizzo ac--; av++; 50179758b77fSLuigi Rizzo NEED1("logamount requires argument"); 501862ff38aeSLuigi Rizzo l = atoi(*av); 501962ff38aeSLuigi Rizzo if (l < 0) 5020974dfe30SBrian Feldman errx(EX_DATAERR, 5021974dfe30SBrian Feldman "logamount must be positive"); 502262ff38aeSLuigi Rizzo c->max_log = l; 50239758b77fSLuigi Rizzo ac--; av++; 50249ec4f2e1SMaxim Konovalov } else { 50259ec4f2e1SMaxim Konovalov len = sizeof(c->max_log); 50269ec4f2e1SMaxim Konovalov if (sysctlbyname("net.inet.ip.fw.verbose_limit", 50279ec4f2e1SMaxim Konovalov &c->max_log, &len, NULL, 0) == -1) 50289ec4f2e1SMaxim Konovalov errx(1, "sysctlbyname(\"%s\")", 50299ec4f2e1SMaxim Konovalov "net.inet.ip.fw.verbose_limit"); 50309758b77fSLuigi Rizzo } 5031974dfe30SBrian Feldman } 5032974dfe30SBrian Feldman break; 5033974dfe30SBrian Feldman 5034974dfe30SBrian Feldman case TOK_ALTQ: 5035974dfe30SBrian Feldman { 5036974dfe30SBrian Feldman ipfw_insn_altq *a = (ipfw_insn_altq *)cmd; 5037974dfe30SBrian Feldman 5038974dfe30SBrian Feldman NEED1("missing altq queue name"); 5039974dfe30SBrian Feldman if (have_altq) 5040974dfe30SBrian Feldman errx(EX_DATAERR, 5041974dfe30SBrian Feldman "altq cannot be specified more than once"); 5042974dfe30SBrian Feldman have_altq = (ipfw_insn *)a; 5043974dfe30SBrian Feldman cmd->len = F_INSN_SIZE(ipfw_insn_altq); 5044974dfe30SBrian Feldman cmd->opcode = O_ALTQ; 5045974dfe30SBrian Feldman fill_altq_qid(&a->qid, *av); 5046974dfe30SBrian Feldman ac--; av++; 5047974dfe30SBrian Feldman } 5048974dfe30SBrian Feldman break; 5049974dfe30SBrian Feldman 50506a7d5cb6SOleg Bulyzhin case TOK_TAG: 5051254c4725SOleg Bulyzhin case TOK_UNTAG: { 5052254c4725SOleg Bulyzhin uint16_t tag; 5053254c4725SOleg Bulyzhin 50546a7d5cb6SOleg Bulyzhin if (have_tag) 5055254c4725SOleg Bulyzhin errx(EX_USAGE, "tag and untag cannot be " 5056254c4725SOleg Bulyzhin "specified more than once"); 5057759dd6f7SRoman Kurakin GET_UINT_ARG(tag, 1, IPFW_DEFAULT_RULE - 1, i, 5058759dd6f7SRoman Kurakin rule_action_params); 50596a7d5cb6SOleg Bulyzhin have_tag = cmd; 5060254c4725SOleg Bulyzhin fill_cmd(cmd, O_TAG, (i == TOK_TAG) ? 0: F_NOT, tag); 50616a7d5cb6SOleg Bulyzhin ac--; av++; 50626a7d5cb6SOleg Bulyzhin break; 5063254c4725SOleg Bulyzhin } 50646a7d5cb6SOleg Bulyzhin 5065974dfe30SBrian Feldman default: 5066974dfe30SBrian Feldman abort(); 5067974dfe30SBrian Feldman } 50689758b77fSLuigi Rizzo cmd = next_cmd(cmd); 50699758b77fSLuigi Rizzo } 50709758b77fSLuigi Rizzo 507152bc23abSLuigi Rizzo if (have_state) /* must be a check-state, we are done */ 50729758b77fSLuigi Rizzo goto done; 50739758b77fSLuigi Rizzo 50749758b77fSLuigi Rizzo #define OR_START(target) \ 50759758b77fSLuigi Rizzo if (ac && (*av[0] == '(' || *av[0] == '{')) { \ 50769758b77fSLuigi Rizzo if (open_par) \ 50779758b77fSLuigi Rizzo errx(EX_USAGE, "nested \"(\" not allowed\n"); \ 50788ed2d749SLuigi Rizzo prev = NULL; \ 50799758b77fSLuigi Rizzo open_par = 1; \ 50809758b77fSLuigi Rizzo if ( (av[0])[1] == '\0') { \ 50819758b77fSLuigi Rizzo ac--; av++; \ 50829758b77fSLuigi Rizzo } else \ 50839758b77fSLuigi Rizzo (*av)++; \ 50849758b77fSLuigi Rizzo } \ 50859758b77fSLuigi Rizzo target: \ 50869758b77fSLuigi Rizzo 50879758b77fSLuigi Rizzo 50889758b77fSLuigi Rizzo #define CLOSE_PAR \ 50899758b77fSLuigi Rizzo if (open_par) { \ 50909758b77fSLuigi Rizzo if (ac && ( \ 509101750186SBrooks Davis strcmp(*av, ")") == 0 || \ 509201750186SBrooks Davis strcmp(*av, "}") == 0)) { \ 50938ed2d749SLuigi Rizzo prev = NULL; \ 50949758b77fSLuigi Rizzo open_par = 0; \ 50959758b77fSLuigi Rizzo ac--; av++; \ 50969758b77fSLuigi Rizzo } else \ 50979758b77fSLuigi Rizzo errx(EX_USAGE, "missing \")\"\n"); \ 50989758b77fSLuigi Rizzo } 50999758b77fSLuigi Rizzo 51009758b77fSLuigi Rizzo #define NOT_BLOCK \ 510101750186SBrooks Davis if (ac && _substrcmp(*av, "not") == 0) { \ 51029758b77fSLuigi Rizzo if (cmd->len & F_NOT) \ 51039758b77fSLuigi Rizzo errx(EX_USAGE, "double \"not\" not allowed\n"); \ 51049758b77fSLuigi Rizzo cmd->len |= F_NOT; \ 51059758b77fSLuigi Rizzo ac--; av++; \ 51069758b77fSLuigi Rizzo } 51079758b77fSLuigi Rizzo 51089758b77fSLuigi Rizzo #define OR_BLOCK(target) \ 510901750186SBrooks Davis if (ac && _substrcmp(*av, "or") == 0) { \ 51109758b77fSLuigi Rizzo if (prev == NULL || open_par == 0) \ 51119758b77fSLuigi Rizzo errx(EX_DATAERR, "invalid OR block"); \ 51129758b77fSLuigi Rizzo prev->len |= F_OR; \ 51139758b77fSLuigi Rizzo ac--; av++; \ 51149758b77fSLuigi Rizzo goto target; \ 51159758b77fSLuigi Rizzo } \ 51169758b77fSLuigi Rizzo CLOSE_PAR; 51179758b77fSLuigi Rizzo 5118e706181bSLuigi Rizzo first_cmd = cmd; 51195a155b40SLuigi Rizzo 51205a155b40SLuigi Rizzo #if 0 5121e706181bSLuigi Rizzo /* 5122e706181bSLuigi Rizzo * MAC addresses, optional. 5123e706181bSLuigi Rizzo * If we have this, we skip the part "proto from src to dst" 5124e706181bSLuigi Rizzo * and jump straight to the option parsing. 5125e706181bSLuigi Rizzo */ 5126e706181bSLuigi Rizzo NOT_BLOCK; 5127e706181bSLuigi Rizzo NEED1("missing protocol"); 512801750186SBrooks Davis if (_substrcmp(*av, "MAC") == 0 || 512901750186SBrooks Davis _substrcmp(*av, "mac") == 0) { 5130e706181bSLuigi Rizzo ac--; av++; /* the "MAC" keyword */ 5131e706181bSLuigi Rizzo add_mac(cmd, ac, av); /* exits in case of errors */ 5132e706181bSLuigi Rizzo cmd = next_cmd(cmd); 5133e706181bSLuigi Rizzo ac -= 2; av += 2; /* dst-mac and src-mac */ 5134e706181bSLuigi Rizzo NOT_BLOCK; 5135e706181bSLuigi Rizzo NEED1("missing mac type"); 5136e706181bSLuigi Rizzo if (add_mactype(cmd, ac, av[0])) 5137e706181bSLuigi Rizzo cmd = next_cmd(cmd); 5138e706181bSLuigi Rizzo ac--; av++; /* any or mac-type */ 5139e706181bSLuigi Rizzo goto read_options; 5140e706181bSLuigi Rizzo } 51415a155b40SLuigi Rizzo #endif 5142e706181bSLuigi Rizzo 51439758b77fSLuigi Rizzo /* 51449758b77fSLuigi Rizzo * protocol, mandatory 51459758b77fSLuigi Rizzo */ 51469758b77fSLuigi Rizzo OR_START(get_proto); 51479758b77fSLuigi Rizzo NOT_BLOCK; 51489758b77fSLuigi Rizzo NEED1("missing protocol"); 514936c263ccSHajimu UMEMOTO if (add_proto_compat(cmd, *av, &proto)) { 51509758b77fSLuigi Rizzo av++; ac--; 5151b730879fSMax Laier if (F_LEN(cmd) != 0) { 5152e706181bSLuigi Rizzo prev = cmd; 51539758b77fSLuigi Rizzo cmd = next_cmd(cmd); 5154e706181bSLuigi Rizzo } 51555a155b40SLuigi Rizzo } else if (first_cmd != cmd) { 5156c82b8dceSMaxim Konovalov errx(EX_DATAERR, "invalid protocol ``%s''", *av); 51575a155b40SLuigi Rizzo } else 51585a155b40SLuigi Rizzo goto read_options; 51599758b77fSLuigi Rizzo OR_BLOCK(get_proto); 51609758b77fSLuigi Rizzo 51619758b77fSLuigi Rizzo /* 5162e706181bSLuigi Rizzo * "from", mandatory 51639758b77fSLuigi Rizzo */ 516401750186SBrooks Davis if (!ac || _substrcmp(*av, "from") != 0) 51659758b77fSLuigi Rizzo errx(EX_USAGE, "missing ``from''"); 51669758b77fSLuigi Rizzo ac--; av++; 51679758b77fSLuigi Rizzo 51689758b77fSLuigi Rizzo /* 51699758b77fSLuigi Rizzo * source IP, mandatory 51709758b77fSLuigi Rizzo */ 51719758b77fSLuigi Rizzo OR_START(source_ip); 51729758b77fSLuigi Rizzo NOT_BLOCK; /* optional "not" */ 51739758b77fSLuigi Rizzo NEED1("missing source address"); 51748195404bSBrooks Davis if (add_src(cmd, *av, proto)) { 51759758b77fSLuigi Rizzo ac--; av++; 5176e706181bSLuigi Rizzo if (F_LEN(cmd) != 0) { /* ! any */ 5177e706181bSLuigi Rizzo prev = cmd; 51789758b77fSLuigi Rizzo cmd = next_cmd(cmd); 5179e706181bSLuigi Rizzo } 51808195404bSBrooks Davis } else 51818195404bSBrooks Davis errx(EX_USAGE, "bad source address %s", *av); 51829758b77fSLuigi Rizzo OR_BLOCK(source_ip); 51839758b77fSLuigi Rizzo 51849758b77fSLuigi Rizzo /* 51859758b77fSLuigi Rizzo * source ports, optional 51869758b77fSLuigi Rizzo */ 51879758b77fSLuigi Rizzo NOT_BLOCK; /* optional "not" */ 51888ed2d749SLuigi Rizzo if (ac) { 518901750186SBrooks Davis if (_substrcmp(*av, "any") == 0 || 5190e706181bSLuigi Rizzo add_ports(cmd, *av, proto, O_IP_SRCPORT)) { 5191e706181bSLuigi Rizzo ac--; av++; 5192e706181bSLuigi Rizzo if (F_LEN(cmd) != 0) 51939758b77fSLuigi Rizzo cmd = next_cmd(cmd); 51949758b77fSLuigi Rizzo } 51958ed2d749SLuigi Rizzo } 51969758b77fSLuigi Rizzo 51979758b77fSLuigi Rizzo /* 5198e706181bSLuigi Rizzo * "to", mandatory 51999758b77fSLuigi Rizzo */ 520001750186SBrooks Davis if (!ac || _substrcmp(*av, "to") != 0) 52019758b77fSLuigi Rizzo errx(EX_USAGE, "missing ``to''"); 52029758b77fSLuigi Rizzo av++; ac--; 52039758b77fSLuigi Rizzo 52049758b77fSLuigi Rizzo /* 52059758b77fSLuigi Rizzo * destination, mandatory 52069758b77fSLuigi Rizzo */ 52079758b77fSLuigi Rizzo OR_START(dest_ip); 52089758b77fSLuigi Rizzo NOT_BLOCK; /* optional "not" */ 52099758b77fSLuigi Rizzo NEED1("missing dst address"); 52108195404bSBrooks Davis if (add_dst(cmd, *av, proto)) { 5211e706181bSLuigi Rizzo ac--; av++; 5212e706181bSLuigi Rizzo if (F_LEN(cmd) != 0) { /* ! any */ 52139758b77fSLuigi Rizzo prev = cmd; 52149758b77fSLuigi Rizzo cmd = next_cmd(cmd); 5215e706181bSLuigi Rizzo } 52168195404bSBrooks Davis } else 52178195404bSBrooks Davis errx( EX_USAGE, "bad destination address %s", *av); 52189758b77fSLuigi Rizzo OR_BLOCK(dest_ip); 52199758b77fSLuigi Rizzo 52209758b77fSLuigi Rizzo /* 52219758b77fSLuigi Rizzo * dest. ports, optional 52229758b77fSLuigi Rizzo */ 52239758b77fSLuigi Rizzo NOT_BLOCK; /* optional "not" */ 52248ed2d749SLuigi Rizzo if (ac) { 522501750186SBrooks Davis if (_substrcmp(*av, "any") == 0 || 5226e706181bSLuigi Rizzo add_ports(cmd, *av, proto, O_IP_DSTPORT)) { 5227e706181bSLuigi Rizzo ac--; av++; 5228e706181bSLuigi Rizzo if (F_LEN(cmd) != 0) 5229e706181bSLuigi Rizzo cmd = next_cmd(cmd); 52309758b77fSLuigi Rizzo } 52318ed2d749SLuigi Rizzo } 52329758b77fSLuigi Rizzo 52339758b77fSLuigi Rizzo read_options: 5234e706181bSLuigi Rizzo if (ac && first_cmd == cmd) { 5235e706181bSLuigi Rizzo /* 5236e706181bSLuigi Rizzo * nothing specified so far, store in the rule to ease 5237e706181bSLuigi Rizzo * printout later. 5238e706181bSLuigi Rizzo */ 5239e706181bSLuigi Rizzo rule->_pad = 1; 5240e706181bSLuigi Rizzo } 52419758b77fSLuigi Rizzo prev = NULL; 52429758b77fSLuigi Rizzo while (ac) { 52438ed2d749SLuigi Rizzo char *s; 52448ed2d749SLuigi Rizzo ipfw_insn_u32 *cmd32; /* alias for cmd */ 52458ed2d749SLuigi Rizzo 52468ed2d749SLuigi Rizzo s = *av; 52478ed2d749SLuigi Rizzo cmd32 = (ipfw_insn_u32 *)cmd; 52489758b77fSLuigi Rizzo 52499758b77fSLuigi Rizzo if (*s == '!') { /* alternate syntax for NOT */ 52509758b77fSLuigi Rizzo if (cmd->len & F_NOT) 52519758b77fSLuigi Rizzo errx(EX_USAGE, "double \"not\" not allowed\n"); 52529758b77fSLuigi Rizzo cmd->len = F_NOT; 52539758b77fSLuigi Rizzo s++; 52549758b77fSLuigi Rizzo } 52559758b77fSLuigi Rizzo i = match_token(rule_options, s); 52569758b77fSLuigi Rizzo ac--; av++; 52579758b77fSLuigi Rizzo switch(i) { 52589758b77fSLuigi Rizzo case TOK_NOT: 52599758b77fSLuigi Rizzo if (cmd->len & F_NOT) 52609758b77fSLuigi Rizzo errx(EX_USAGE, "double \"not\" not allowed\n"); 52619758b77fSLuigi Rizzo cmd->len = F_NOT; 52629758b77fSLuigi Rizzo break; 52639758b77fSLuigi Rizzo 52649758b77fSLuigi Rizzo case TOK_OR: 52658ed2d749SLuigi Rizzo if (open_par == 0 || prev == NULL) 52669758b77fSLuigi Rizzo errx(EX_USAGE, "invalid \"or\" block\n"); 52679758b77fSLuigi Rizzo prev->len |= F_OR; 52689758b77fSLuigi Rizzo break; 52699758b77fSLuigi Rizzo 52708ed2d749SLuigi Rizzo case TOK_STARTBRACE: 52718ed2d749SLuigi Rizzo if (open_par) 52728ed2d749SLuigi Rizzo errx(EX_USAGE, "+nested \"(\" not allowed\n"); 52738ed2d749SLuigi Rizzo open_par = 1; 52748ed2d749SLuigi Rizzo break; 52758ed2d749SLuigi Rizzo 52768ed2d749SLuigi Rizzo case TOK_ENDBRACE: 52778ed2d749SLuigi Rizzo if (!open_par) 52788ed2d749SLuigi Rizzo errx(EX_USAGE, "+missing \")\"\n"); 52798ed2d749SLuigi Rizzo open_par = 0; 5280e706181bSLuigi Rizzo prev = NULL; 52818ed2d749SLuigi Rizzo break; 52828ed2d749SLuigi Rizzo 52839758b77fSLuigi Rizzo case TOK_IN: 52849758b77fSLuigi Rizzo fill_cmd(cmd, O_IN, 0, 0); 52859758b77fSLuigi Rizzo break; 52869758b77fSLuigi Rizzo 52879758b77fSLuigi Rizzo case TOK_OUT: 52889758b77fSLuigi Rizzo cmd->len ^= F_NOT; /* toggle F_NOT */ 52899758b77fSLuigi Rizzo fill_cmd(cmd, O_IN, 0, 0); 52909758b77fSLuigi Rizzo break; 52919758b77fSLuigi Rizzo 52926daf7ebdSBrian Feldman case TOK_DIVERTED: 52936daf7ebdSBrian Feldman fill_cmd(cmd, O_DIVERTED, 0, 3); 52946daf7ebdSBrian Feldman break; 52956daf7ebdSBrian Feldman 52966daf7ebdSBrian Feldman case TOK_DIVERTEDLOOPBACK: 52976daf7ebdSBrian Feldman fill_cmd(cmd, O_DIVERTED, 0, 1); 52986daf7ebdSBrian Feldman break; 52996daf7ebdSBrian Feldman 53006daf7ebdSBrian Feldman case TOK_DIVERTEDOUTPUT: 53016daf7ebdSBrian Feldman fill_cmd(cmd, O_DIVERTED, 0, 2); 53026daf7ebdSBrian Feldman break; 53036daf7ebdSBrian Feldman 53049758b77fSLuigi Rizzo case TOK_FRAG: 53059758b77fSLuigi Rizzo fill_cmd(cmd, O_FRAG, 0, 0); 53069758b77fSLuigi Rizzo break; 53079758b77fSLuigi Rizzo 53089758b77fSLuigi Rizzo case TOK_LAYER2: 53099758b77fSLuigi Rizzo fill_cmd(cmd, O_LAYER2, 0, 0); 53109758b77fSLuigi Rizzo break; 53119758b77fSLuigi Rizzo 53129758b77fSLuigi Rizzo case TOK_XMIT: 53139758b77fSLuigi Rizzo case TOK_RECV: 53149758b77fSLuigi Rizzo case TOK_VIA: 53159758b77fSLuigi Rizzo NEED1("recv, xmit, via require interface name" 53169758b77fSLuigi Rizzo " or address"); 53179758b77fSLuigi Rizzo fill_iface((ipfw_insn_if *)cmd, av[0]); 53189758b77fSLuigi Rizzo ac--; av++; 53199758b77fSLuigi Rizzo if (F_LEN(cmd) == 0) /* not a valid address */ 53209758b77fSLuigi Rizzo break; 53219758b77fSLuigi Rizzo if (i == TOK_XMIT) 53229758b77fSLuigi Rizzo cmd->opcode = O_XMIT; 53239758b77fSLuigi Rizzo else if (i == TOK_RECV) 53249758b77fSLuigi Rizzo cmd->opcode = O_RECV; 53259758b77fSLuigi Rizzo else if (i == TOK_VIA) 53269758b77fSLuigi Rizzo cmd->opcode = O_VIA; 53279758b77fSLuigi Rizzo break; 53289758b77fSLuigi Rizzo 53295e43aef8SLuigi Rizzo case TOK_ICMPTYPES: 53305e43aef8SLuigi Rizzo NEED1("icmptypes requires list of types"); 53315e43aef8SLuigi Rizzo fill_icmptypes((ipfw_insn_u32 *)cmd, *av); 53325e43aef8SLuigi Rizzo av++; ac--; 53335e43aef8SLuigi Rizzo break; 53345e43aef8SLuigi Rizzo 53358195404bSBrooks Davis case TOK_ICMP6TYPES: 53368195404bSBrooks Davis NEED1("icmptypes requires list of types"); 53378195404bSBrooks Davis fill_icmp6types((ipfw_insn_icmp6 *)cmd, *av); 53388195404bSBrooks Davis av++; ac--; 53398195404bSBrooks Davis break; 53408195404bSBrooks Davis 53419758b77fSLuigi Rizzo case TOK_IPTTL: 53429758b77fSLuigi Rizzo NEED1("ipttl requires TTL"); 534344c884e1SLuigi Rizzo if (strpbrk(*av, "-,")) { 534444c884e1SLuigi Rizzo if (!add_ports(cmd, *av, 0, O_IPTTL)) 534544c884e1SLuigi Rizzo errx(EX_DATAERR, "invalid ipttl %s", *av); 534644c884e1SLuigi Rizzo } else 53479758b77fSLuigi Rizzo fill_cmd(cmd, O_IPTTL, 0, strtoul(*av, NULL, 0)); 53489758b77fSLuigi Rizzo ac--; av++; 53499758b77fSLuigi Rizzo break; 53509758b77fSLuigi Rizzo 53519758b77fSLuigi Rizzo case TOK_IPID: 535244c884e1SLuigi Rizzo NEED1("ipid requires id"); 535344c884e1SLuigi Rizzo if (strpbrk(*av, "-,")) { 535444c884e1SLuigi Rizzo if (!add_ports(cmd, *av, 0, O_IPID)) 535544c884e1SLuigi Rizzo errx(EX_DATAERR, "invalid ipid %s", *av); 535644c884e1SLuigi Rizzo } else 53579758b77fSLuigi Rizzo fill_cmd(cmd, O_IPID, 0, strtoul(*av, NULL, 0)); 53589758b77fSLuigi Rizzo ac--; av++; 53599758b77fSLuigi Rizzo break; 53609758b77fSLuigi Rizzo 53619758b77fSLuigi Rizzo case TOK_IPLEN: 53629758b77fSLuigi Rizzo NEED1("iplen requires length"); 536344c884e1SLuigi Rizzo if (strpbrk(*av, "-,")) { 536444c884e1SLuigi Rizzo if (!add_ports(cmd, *av, 0, O_IPLEN)) 536544c884e1SLuigi Rizzo errx(EX_DATAERR, "invalid ip len %s", *av); 536644c884e1SLuigi Rizzo } else 53679758b77fSLuigi Rizzo fill_cmd(cmd, O_IPLEN, 0, strtoul(*av, NULL, 0)); 53689758b77fSLuigi Rizzo ac--; av++; 53699758b77fSLuigi Rizzo break; 53709758b77fSLuigi Rizzo 53719758b77fSLuigi Rizzo case TOK_IPVER: 53729758b77fSLuigi Rizzo NEED1("ipver requires version"); 53739758b77fSLuigi Rizzo fill_cmd(cmd, O_IPVER, 0, strtoul(*av, NULL, 0)); 53749758b77fSLuigi Rizzo ac--; av++; 53759758b77fSLuigi Rizzo break; 53769758b77fSLuigi Rizzo 53775e43aef8SLuigi Rizzo case TOK_IPPRECEDENCE: 53785e43aef8SLuigi Rizzo NEED1("ipprecedence requires value"); 53795e43aef8SLuigi Rizzo fill_cmd(cmd, O_IPPRECEDENCE, 0, 53805e43aef8SLuigi Rizzo (strtoul(*av, NULL, 0) & 7) << 5); 53815e43aef8SLuigi Rizzo ac--; av++; 53825e43aef8SLuigi Rizzo break; 53835e43aef8SLuigi Rizzo 53849758b77fSLuigi Rizzo case TOK_IPOPTS: 53859758b77fSLuigi Rizzo NEED1("missing argument for ipoptions"); 538652bc23abSLuigi Rizzo fill_flags(cmd, O_IPOPT, f_ipopts, *av); 53879758b77fSLuigi Rizzo ac--; av++; 53889758b77fSLuigi Rizzo break; 53899758b77fSLuigi Rizzo 53905e43aef8SLuigi Rizzo case TOK_IPTOS: 53915e43aef8SLuigi Rizzo NEED1("missing argument for iptos"); 539252bc23abSLuigi Rizzo fill_flags(cmd, O_IPTOS, f_iptos, *av); 53935e43aef8SLuigi Rizzo ac--; av++; 53945e43aef8SLuigi Rizzo break; 53955e43aef8SLuigi Rizzo 53969758b77fSLuigi Rizzo case TOK_UID: 53979758b77fSLuigi Rizzo NEED1("uid requires argument"); 53989758b77fSLuigi Rizzo { 53999758b77fSLuigi Rizzo char *end; 54009758b77fSLuigi Rizzo uid_t uid; 54019758b77fSLuigi Rizzo struct passwd *pwd; 54029758b77fSLuigi Rizzo 54039758b77fSLuigi Rizzo cmd->opcode = O_UID; 54049758b77fSLuigi Rizzo uid = strtoul(*av, &end, 0); 54059758b77fSLuigi Rizzo pwd = (*end == '\0') ? getpwuid(uid) : getpwnam(*av); 54069758b77fSLuigi Rizzo if (pwd == NULL) 54079758b77fSLuigi Rizzo errx(EX_DATAERR, "uid \"%s\" nonexistent", *av); 5408d6abaeebSMaxim Konovalov cmd32->d[0] = pwd->pw_uid; 54093a27af0dSChristian S.J. Peron cmd->len |= F_INSN_SIZE(ipfw_insn_u32); 54109758b77fSLuigi Rizzo ac--; av++; 54119758b77fSLuigi Rizzo } 54129758b77fSLuigi Rizzo break; 54139758b77fSLuigi Rizzo 54149758b77fSLuigi Rizzo case TOK_GID: 54159758b77fSLuigi Rizzo NEED1("gid requires argument"); 54169758b77fSLuigi Rizzo { 54179758b77fSLuigi Rizzo char *end; 54189758b77fSLuigi Rizzo gid_t gid; 54199758b77fSLuigi Rizzo struct group *grp; 54209758b77fSLuigi Rizzo 54219758b77fSLuigi Rizzo cmd->opcode = O_GID; 54229758b77fSLuigi Rizzo gid = strtoul(*av, &end, 0); 54239758b77fSLuigi Rizzo grp = (*end == '\0') ? getgrgid(gid) : getgrnam(*av); 54249758b77fSLuigi Rizzo if (grp == NULL) 54259758b77fSLuigi Rizzo errx(EX_DATAERR, "gid \"%s\" nonexistent", *av); 5426d6abaeebSMaxim Konovalov cmd32->d[0] = grp->gr_gid; 54273a27af0dSChristian S.J. Peron cmd->len |= F_INSN_SIZE(ipfw_insn_u32); 54289758b77fSLuigi Rizzo ac--; av++; 54299758b77fSLuigi Rizzo } 54309758b77fSLuigi Rizzo break; 54319758b77fSLuigi Rizzo 543231c88a30SChristian S.J. Peron case TOK_JAIL: 543331c88a30SChristian S.J. Peron NEED1("jail requires argument"); 543431c88a30SChristian S.J. Peron { 543531c88a30SChristian S.J. Peron char *end; 543631c88a30SChristian S.J. Peron int jid; 543731c88a30SChristian S.J. Peron 543831c88a30SChristian S.J. Peron cmd->opcode = O_JAIL; 543931c88a30SChristian S.J. Peron jid = (int)strtol(*av, &end, 0); 544031c88a30SChristian S.J. Peron if (jid < 0 || *end != '\0') 544131c88a30SChristian S.J. Peron errx(EX_DATAERR, "jail requires prison ID"); 5442d413c2e4SChristian S.J. Peron cmd32->d[0] = (uint32_t)jid; 54433a27af0dSChristian S.J. Peron cmd->len |= F_INSN_SIZE(ipfw_insn_u32); 544431c88a30SChristian S.J. Peron ac--; av++; 544531c88a30SChristian S.J. Peron } 544631c88a30SChristian S.J. Peron break; 544731c88a30SChristian S.J. Peron 54489758b77fSLuigi Rizzo case TOK_ESTAB: 54499758b77fSLuigi Rizzo fill_cmd(cmd, O_ESTAB, 0, 0); 54509758b77fSLuigi Rizzo break; 54519758b77fSLuigi Rizzo 54529758b77fSLuigi Rizzo case TOK_SETUP: 54539758b77fSLuigi Rizzo fill_cmd(cmd, O_TCPFLAGS, 0, 54549758b77fSLuigi Rizzo (TH_SYN) | ( (TH_ACK) & 0xff) <<8 ); 54559758b77fSLuigi Rizzo break; 54569758b77fSLuigi Rizzo 5457c99ee9e0SBrian Feldman case TOK_TCPDATALEN: 5458c99ee9e0SBrian Feldman NEED1("tcpdatalen requires length"); 5459c99ee9e0SBrian Feldman if (strpbrk(*av, "-,")) { 5460c99ee9e0SBrian Feldman if (!add_ports(cmd, *av, 0, O_TCPDATALEN)) 5461c99ee9e0SBrian Feldman errx(EX_DATAERR, "invalid tcpdata len %s", *av); 5462c99ee9e0SBrian Feldman } else 5463c99ee9e0SBrian Feldman fill_cmd(cmd, O_TCPDATALEN, 0, 5464c99ee9e0SBrian Feldman strtoul(*av, NULL, 0)); 5465c99ee9e0SBrian Feldman ac--; av++; 5466c99ee9e0SBrian Feldman break; 5467c99ee9e0SBrian Feldman 54689758b77fSLuigi Rizzo case TOK_TCPOPTS: 54699758b77fSLuigi Rizzo NEED1("missing argument for tcpoptions"); 54709758b77fSLuigi Rizzo fill_flags(cmd, O_TCPOPTS, f_tcpopts, *av); 54719758b77fSLuigi Rizzo ac--; av++; 54729758b77fSLuigi Rizzo break; 54739758b77fSLuigi Rizzo 54749758b77fSLuigi Rizzo case TOK_TCPSEQ: 54759758b77fSLuigi Rizzo case TOK_TCPACK: 54769758b77fSLuigi Rizzo NEED1("tcpseq/tcpack requires argument"); 54779758b77fSLuigi Rizzo cmd->len = F_INSN_SIZE(ipfw_insn_u32); 54789758b77fSLuigi Rizzo cmd->opcode = (i == TOK_TCPSEQ) ? O_TCPSEQ : O_TCPACK; 54799758b77fSLuigi Rizzo cmd32->d[0] = htonl(strtoul(*av, NULL, 0)); 54809758b77fSLuigi Rizzo ac--; av++; 54819758b77fSLuigi Rizzo break; 54829758b77fSLuigi Rizzo 54839758b77fSLuigi Rizzo case TOK_TCPWIN: 54849758b77fSLuigi Rizzo NEED1("tcpwin requires length"); 54859758b77fSLuigi Rizzo fill_cmd(cmd, O_TCPWIN, 0, 54869758b77fSLuigi Rizzo htons(strtoul(*av, NULL, 0))); 54879758b77fSLuigi Rizzo ac--; av++; 54889758b77fSLuigi Rizzo break; 54899758b77fSLuigi Rizzo 54909758b77fSLuigi Rizzo case TOK_TCPFLAGS: 54919758b77fSLuigi Rizzo NEED1("missing argument for tcpflags"); 54929758b77fSLuigi Rizzo cmd->opcode = O_TCPFLAGS; 54939758b77fSLuigi Rizzo fill_flags(cmd, O_TCPFLAGS, f_tcpflags, *av); 54949758b77fSLuigi Rizzo ac--; av++; 54959758b77fSLuigi Rizzo break; 54969758b77fSLuigi Rizzo 54979758b77fSLuigi Rizzo case TOK_KEEPSTATE: 54988ed2d749SLuigi Rizzo if (open_par) 54998ed2d749SLuigi Rizzo errx(EX_USAGE, "keep-state cannot be part " 55008ed2d749SLuigi Rizzo "of an or block"); 55010a7197a8SLuigi Rizzo if (have_state) 550252bc23abSLuigi Rizzo errx(EX_USAGE, "only one of keep-state " 55030a7197a8SLuigi Rizzo "and limit is allowed"); 550452bc23abSLuigi Rizzo have_state = cmd; 55059758b77fSLuigi Rizzo fill_cmd(cmd, O_KEEP_STATE, 0, 0); 55069758b77fSLuigi Rizzo break; 55079758b77fSLuigi Rizzo 5508254c4725SOleg Bulyzhin case TOK_LIMIT: { 55099758b77fSLuigi Rizzo ipfw_insn_limit *c = (ipfw_insn_limit *)cmd; 5510254c4725SOleg Bulyzhin int val; 5511254c4725SOleg Bulyzhin 5512254c4725SOleg Bulyzhin if (open_par) 5513254c4725SOleg Bulyzhin errx(EX_USAGE, 5514254c4725SOleg Bulyzhin "limit cannot be part of an or block"); 5515254c4725SOleg Bulyzhin if (have_state) 5516254c4725SOleg Bulyzhin errx(EX_USAGE, "only one of keep-state and " 5517254c4725SOleg Bulyzhin "limit is allowed"); 5518254c4725SOleg Bulyzhin have_state = cmd; 55199758b77fSLuigi Rizzo 55209758b77fSLuigi Rizzo cmd->len = F_INSN_SIZE(ipfw_insn_limit); 55219758b77fSLuigi Rizzo cmd->opcode = O_LIMIT; 5522254c4725SOleg Bulyzhin c->limit_mask = c->conn_limit = 0; 55239758b77fSLuigi Rizzo 5524254c4725SOleg Bulyzhin while (ac > 0) { 5525254c4725SOleg Bulyzhin if ((val = match_token(limit_masks, *av)) <= 0) 55269758b77fSLuigi Rizzo break; 55279758b77fSLuigi Rizzo c->limit_mask |= val; 55289758b77fSLuigi Rizzo ac--; av++; 55299758b77fSLuigi Rizzo } 5530254c4725SOleg Bulyzhin 55319758b77fSLuigi Rizzo if (c->limit_mask == 0) 5532254c4725SOleg Bulyzhin errx(EX_USAGE, "limit: missing limit mask"); 5533254c4725SOleg Bulyzhin 5534759dd6f7SRoman Kurakin GET_UINT_ARG(c->conn_limit, 1, IPFW_DEFAULT_RULE - 1, 5535759dd6f7SRoman Kurakin TOK_LIMIT, rule_options); 5536254c4725SOleg Bulyzhin 55379758b77fSLuigi Rizzo ac--; av++; 55389758b77fSLuigi Rizzo break; 5539254c4725SOleg Bulyzhin } 55409758b77fSLuigi Rizzo 5541e706181bSLuigi Rizzo case TOK_PROTO: 5542e706181bSLuigi Rizzo NEED1("missing protocol"); 55438195404bSBrooks Davis if (add_proto(cmd, *av, &proto)) { 5544e706181bSLuigi Rizzo ac--; av++; 55455a155b40SLuigi Rizzo } else 5546c82b8dceSMaxim Konovalov errx(EX_DATAERR, "invalid protocol ``%s''", 5547c82b8dceSMaxim Konovalov *av); 5548e706181bSLuigi Rizzo break; 5549e706181bSLuigi Rizzo 5550e706181bSLuigi Rizzo case TOK_SRCIP: 5551e706181bSLuigi Rizzo NEED1("missing source IP"); 5552e706181bSLuigi Rizzo if (add_srcip(cmd, *av)) { 5553e706181bSLuigi Rizzo ac--; av++; 5554e706181bSLuigi Rizzo } 5555e706181bSLuigi Rizzo break; 5556e706181bSLuigi Rizzo 5557e706181bSLuigi Rizzo case TOK_DSTIP: 5558e706181bSLuigi Rizzo NEED1("missing destination IP"); 5559e706181bSLuigi Rizzo if (add_dstip(cmd, *av)) { 5560e706181bSLuigi Rizzo ac--; av++; 5561e706181bSLuigi Rizzo } 5562e706181bSLuigi Rizzo break; 5563e706181bSLuigi Rizzo 55648195404bSBrooks Davis case TOK_SRCIP6: 55658195404bSBrooks Davis NEED1("missing source IP6"); 55668195404bSBrooks Davis if (add_srcip6(cmd, *av)) { 55678195404bSBrooks Davis ac--; av++; 55688195404bSBrooks Davis } 55698195404bSBrooks Davis break; 55708195404bSBrooks Davis 55718195404bSBrooks Davis case TOK_DSTIP6: 55728195404bSBrooks Davis NEED1("missing destination IP6"); 55738195404bSBrooks Davis if (add_dstip6(cmd, *av)) { 55748195404bSBrooks Davis ac--; av++; 55758195404bSBrooks Davis } 55768195404bSBrooks Davis break; 55778195404bSBrooks Davis 5578e706181bSLuigi Rizzo case TOK_SRCPORT: 5579e706181bSLuigi Rizzo NEED1("missing source port"); 558001750186SBrooks Davis if (_substrcmp(*av, "any") == 0 || 5581e706181bSLuigi Rizzo add_ports(cmd, *av, proto, O_IP_SRCPORT)) { 5582e706181bSLuigi Rizzo ac--; av++; 5583e706181bSLuigi Rizzo } else 5584e706181bSLuigi Rizzo errx(EX_DATAERR, "invalid source port %s", *av); 5585e706181bSLuigi Rizzo break; 5586e706181bSLuigi Rizzo 5587e706181bSLuigi Rizzo case TOK_DSTPORT: 5588e706181bSLuigi Rizzo NEED1("missing destination port"); 558901750186SBrooks Davis if (_substrcmp(*av, "any") == 0 || 5590e706181bSLuigi Rizzo add_ports(cmd, *av, proto, O_IP_DSTPORT)) { 5591e706181bSLuigi Rizzo ac--; av++; 5592e706181bSLuigi Rizzo } else 5593e706181bSLuigi Rizzo errx(EX_DATAERR, "invalid destination port %s", 5594e706181bSLuigi Rizzo *av); 5595e706181bSLuigi Rizzo break; 5596e706181bSLuigi Rizzo 5597e706181bSLuigi Rizzo case TOK_MAC: 5598e706181bSLuigi Rizzo if (add_mac(cmd, ac, av)) { 5599e706181bSLuigi Rizzo ac -= 2; av += 2; 5600e706181bSLuigi Rizzo } 5601e706181bSLuigi Rizzo break; 5602e706181bSLuigi Rizzo 5603e706181bSLuigi Rizzo case TOK_MACTYPE: 5604e706181bSLuigi Rizzo NEED1("missing mac type"); 5605e706181bSLuigi Rizzo if (!add_mactype(cmd, ac, *av)) 5606c82b8dceSMaxim Konovalov errx(EX_DATAERR, "invalid mac type %s", *av); 5607e706181bSLuigi Rizzo ac--; av++; 5608e706181bSLuigi Rizzo break; 5609e706181bSLuigi Rizzo 5610010dabb0SCrist J. Clark case TOK_VERREVPATH: 5611010dabb0SCrist J. Clark fill_cmd(cmd, O_VERREVPATH, 0, 0); 5612010dabb0SCrist J. Clark break; 5613010dabb0SCrist J. Clark 561422b5770bSAndre Oppermann case TOK_VERSRCREACH: 561522b5770bSAndre Oppermann fill_cmd(cmd, O_VERSRCREACH, 0, 0); 561622b5770bSAndre Oppermann break; 561722b5770bSAndre Oppermann 56185f9541ecSAndre Oppermann case TOK_ANTISPOOF: 56195f9541ecSAndre Oppermann fill_cmd(cmd, O_ANTISPOOF, 0, 0); 56205f9541ecSAndre Oppermann break; 56215f9541ecSAndre Oppermann 5622c3e5b9f1SLuigi Rizzo case TOK_IPSEC: 5623c3e5b9f1SLuigi Rizzo fill_cmd(cmd, O_IPSEC, 0, 0); 5624c3e5b9f1SLuigi Rizzo break; 5625c3e5b9f1SLuigi Rizzo 56268195404bSBrooks Davis case TOK_IPV6: 56278195404bSBrooks Davis fill_cmd(cmd, O_IP6, 0, 0); 56288195404bSBrooks Davis break; 56298195404bSBrooks Davis 563057cd6d26SMax Laier case TOK_IPV4: 563157cd6d26SMax Laier fill_cmd(cmd, O_IP4, 0, 0); 563257cd6d26SMax Laier break; 563357cd6d26SMax Laier 56348195404bSBrooks Davis case TOK_EXT6HDR: 56358195404bSBrooks Davis fill_ext6hdr( cmd, *av ); 56368195404bSBrooks Davis ac--; av++; 56378195404bSBrooks Davis break; 56388195404bSBrooks Davis 56398195404bSBrooks Davis case TOK_FLOWID: 56408195404bSBrooks Davis if (proto != IPPROTO_IPV6 ) 56418195404bSBrooks Davis errx( EX_USAGE, "flow-id filter is active " 56428195404bSBrooks Davis "only for ipv6 protocol\n"); 56438195404bSBrooks Davis fill_flow6( (ipfw_insn_u32 *) cmd, *av ); 56448195404bSBrooks Davis ac--; av++; 56458195404bSBrooks Davis break; 56468195404bSBrooks Davis 564762ff38aeSLuigi Rizzo case TOK_COMMENT: 564862ff38aeSLuigi Rizzo fill_comment(cmd, ac, av); 564962ff38aeSLuigi Rizzo av += ac; 565062ff38aeSLuigi Rizzo ac = 0; 565162ff38aeSLuigi Rizzo break; 565262ff38aeSLuigi Rizzo 56536a7d5cb6SOleg Bulyzhin case TOK_TAGGED: 5654254c4725SOleg Bulyzhin if (ac > 0 && strpbrk(*av, "-,")) { 56556a7d5cb6SOleg Bulyzhin if (!add_ports(cmd, *av, 0, O_TAGGED)) 5656254c4725SOleg Bulyzhin errx(EX_DATAERR, "tagged: invalid tag" 5657254c4725SOleg Bulyzhin " list: %s", *av); 5658254c4725SOleg Bulyzhin } 5659254c4725SOleg Bulyzhin else { 5660254c4725SOleg Bulyzhin uint16_t tag; 5661254c4725SOleg Bulyzhin 5662759dd6f7SRoman Kurakin GET_UINT_ARG(tag, 1, IPFW_DEFAULT_RULE - 1, 5663759dd6f7SRoman Kurakin TOK_TAGGED, rule_options); 5664254c4725SOleg Bulyzhin fill_cmd(cmd, O_TAGGED, 0, tag); 56656a7d5cb6SOleg Bulyzhin } 56666a7d5cb6SOleg Bulyzhin ac--; av++; 56676a7d5cb6SOleg Bulyzhin break; 56686a7d5cb6SOleg Bulyzhin 56698b07e49aSJulian Elischer case TOK_FIB: 56708b07e49aSJulian Elischer NEED1("fib requires fib number"); 56718b07e49aSJulian Elischer fill_cmd(cmd, O_FIB, 0, strtoul(*av, NULL, 0)); 56728b07e49aSJulian Elischer ac--; av++; 56738b07e49aSJulian Elischer break; 56748b07e49aSJulian Elischer 56759758b77fSLuigi Rizzo default: 56769758b77fSLuigi Rizzo errx(EX_USAGE, "unrecognised option [%d] %s\n", i, s); 56779758b77fSLuigi Rizzo } 56789758b77fSLuigi Rizzo if (F_LEN(cmd) > 0) { /* prepare to advance */ 56799758b77fSLuigi Rizzo prev = cmd; 56809758b77fSLuigi Rizzo cmd = next_cmd(cmd); 56819758b77fSLuigi Rizzo } 56829758b77fSLuigi Rizzo } 56839758b77fSLuigi Rizzo 56849758b77fSLuigi Rizzo done: 56859758b77fSLuigi Rizzo /* 56869758b77fSLuigi Rizzo * Now copy stuff into the rule. 56879758b77fSLuigi Rizzo * If we have a keep-state option, the first instruction 56889758b77fSLuigi Rizzo * must be a PROBE_STATE (which is generated here). 56899758b77fSLuigi Rizzo * If we have a LOG option, it was stored as the first command, 56909758b77fSLuigi Rizzo * and now must be moved to the top of the action part. 56919758b77fSLuigi Rizzo */ 56929758b77fSLuigi Rizzo dst = (ipfw_insn *)rule->cmd; 56939758b77fSLuigi Rizzo 56949758b77fSLuigi Rizzo /* 569512b5dc6aSLuigi Rizzo * First thing to write into the command stream is the match probability. 569612b5dc6aSLuigi Rizzo */ 569712b5dc6aSLuigi Rizzo if (match_prob != 1) { /* 1 means always match */ 569812b5dc6aSLuigi Rizzo dst->opcode = O_PROB; 569912b5dc6aSLuigi Rizzo dst->len = 2; 570012b5dc6aSLuigi Rizzo *((int32_t *)(dst+1)) = (int32_t)(match_prob * 0x7fffffff); 570112b5dc6aSLuigi Rizzo dst += dst->len; 570212b5dc6aSLuigi Rizzo } 570312b5dc6aSLuigi Rizzo 570412b5dc6aSLuigi Rizzo /* 57059758b77fSLuigi Rizzo * generate O_PROBE_STATE if necessary 57069758b77fSLuigi Rizzo */ 570752bc23abSLuigi Rizzo if (have_state && have_state->opcode != O_CHECK_STATE) { 57089758b77fSLuigi Rizzo fill_cmd(dst, O_PROBE_STATE, 0, 0); 57099758b77fSLuigi Rizzo dst = next_cmd(dst); 57109758b77fSLuigi Rizzo } 57116a7d5cb6SOleg Bulyzhin 57126a7d5cb6SOleg Bulyzhin /* copy all commands but O_LOG, O_KEEP_STATE, O_LIMIT, O_ALTQ, O_TAG */ 57139758b77fSLuigi Rizzo for (src = (ipfw_insn *)cmdbuf; src != cmd; src += i) { 57149758b77fSLuigi Rizzo i = F_LEN(src); 57159758b77fSLuigi Rizzo 571652bc23abSLuigi Rizzo switch (src->opcode) { 571752bc23abSLuigi Rizzo case O_LOG: 571852bc23abSLuigi Rizzo case O_KEEP_STATE: 571952bc23abSLuigi Rizzo case O_LIMIT: 5720974dfe30SBrian Feldman case O_ALTQ: 57216a7d5cb6SOleg Bulyzhin case O_TAG: 572252bc23abSLuigi Rizzo break; 572352bc23abSLuigi Rizzo default: 5724571f8c1bSLuigi Rizzo bcopy(src, dst, i * sizeof(uint32_t)); 57259758b77fSLuigi Rizzo dst += i; 57269758b77fSLuigi Rizzo } 57279758b77fSLuigi Rizzo } 57289758b77fSLuigi Rizzo 57299758b77fSLuigi Rizzo /* 573052bc23abSLuigi Rizzo * put back the have_state command as last opcode 573152bc23abSLuigi Rizzo */ 5732b985a624SLuigi Rizzo if (have_state && have_state->opcode != O_CHECK_STATE) { 573352bc23abSLuigi Rizzo i = F_LEN(have_state); 5734571f8c1bSLuigi Rizzo bcopy(have_state, dst, i * sizeof(uint32_t)); 573552bc23abSLuigi Rizzo dst += i; 573652bc23abSLuigi Rizzo } 573752bc23abSLuigi Rizzo /* 57389758b77fSLuigi Rizzo * start action section 57399758b77fSLuigi Rizzo */ 57409758b77fSLuigi Rizzo rule->act_ofs = dst - rule->cmd; 57419758b77fSLuigi Rizzo 57426a7d5cb6SOleg Bulyzhin /* put back O_LOG, O_ALTQ, O_TAG if necessary */ 5743974dfe30SBrian Feldman if (have_log) { 5744974dfe30SBrian Feldman i = F_LEN(have_log); 5745974dfe30SBrian Feldman bcopy(have_log, dst, i * sizeof(uint32_t)); 5746974dfe30SBrian Feldman dst += i; 5747974dfe30SBrian Feldman } 5748974dfe30SBrian Feldman if (have_altq) { 5749974dfe30SBrian Feldman i = F_LEN(have_altq); 5750974dfe30SBrian Feldman bcopy(have_altq, dst, i * sizeof(uint32_t)); 57519758b77fSLuigi Rizzo dst += i; 57529758b77fSLuigi Rizzo } 57536a7d5cb6SOleg Bulyzhin if (have_tag) { 57546a7d5cb6SOleg Bulyzhin i = F_LEN(have_tag); 57556a7d5cb6SOleg Bulyzhin bcopy(have_tag, dst, i * sizeof(uint32_t)); 57566a7d5cb6SOleg Bulyzhin dst += i; 57576a7d5cb6SOleg Bulyzhin } 57589758b77fSLuigi Rizzo /* 57599758b77fSLuigi Rizzo * copy all other actions 57609758b77fSLuigi Rizzo */ 57619758b77fSLuigi Rizzo for (src = (ipfw_insn *)actbuf; src != action; src += i) { 57629758b77fSLuigi Rizzo i = F_LEN(src); 5763571f8c1bSLuigi Rizzo bcopy(src, dst, i * sizeof(uint32_t)); 57649758b77fSLuigi Rizzo dst += i; 57659758b77fSLuigi Rizzo } 57669758b77fSLuigi Rizzo 5767571f8c1bSLuigi Rizzo rule->cmd_len = (uint32_t *)dst - (uint32_t *)(rule->cmd); 576862ff38aeSLuigi Rizzo i = (char *)dst - (char *)rule; 5769884be75cSThomas Moestl if (do_cmd(IP_FW_ADD, rule, (uintptr_t)&i) == -1) 57709758b77fSLuigi Rizzo err(EX_UNAVAILABLE, "getsockopt(%s)", "IP_FW_ADD"); 57719758b77fSLuigi Rizzo if (!do_quiet) 577262ff38aeSLuigi Rizzo show_ipfw(rule, 0, 0); 57739758b77fSLuigi Rizzo } 57749758b77fSLuigi Rizzo 57759758b77fSLuigi Rizzo static void 5776571f8c1bSLuigi Rizzo zero(int ac, char *av[], int optname /* IP_FW_ZERO or IP_FW_RESETLOG */) 57779758b77fSLuigi Rizzo { 5778d069a5d4SMaxim Konovalov uint32_t arg, saved_arg; 57799758b77fSLuigi Rizzo int failed = EX_OK; 578062ff38aeSLuigi Rizzo char const *name = optname == IP_FW_ZERO ? "ZERO" : "RESETLOG"; 5781d069a5d4SMaxim Konovalov char const *errstr; 57829758b77fSLuigi Rizzo 57839758b77fSLuigi Rizzo av++; ac--; 57849758b77fSLuigi Rizzo 57859758b77fSLuigi Rizzo if (!ac) { 57869758b77fSLuigi Rizzo /* clear all entries */ 5787571f8c1bSLuigi Rizzo if (do_cmd(optname, NULL, 0) < 0) 5788571f8c1bSLuigi Rizzo err(EX_UNAVAILABLE, "setsockopt(IP_FW_%s)", name); 57899758b77fSLuigi Rizzo if (!do_quiet) 5790571f8c1bSLuigi Rizzo printf("%s.\n", optname == IP_FW_ZERO ? 5791571f8c1bSLuigi Rizzo "Accounting cleared":"Logging counts reset"); 57929758b77fSLuigi Rizzo 57939758b77fSLuigi Rizzo return; 57949758b77fSLuigi Rizzo } 57959758b77fSLuigi Rizzo 57969758b77fSLuigi Rizzo while (ac) { 57979758b77fSLuigi Rizzo /* Rule number */ 57989758b77fSLuigi Rizzo if (isdigit(**av)) { 5799d069a5d4SMaxim Konovalov arg = strtonum(*av, 0, 0xffff, &errstr); 5800d069a5d4SMaxim Konovalov if (errstr) 5801d069a5d4SMaxim Konovalov errx(EX_DATAERR, 5802d069a5d4SMaxim Konovalov "invalid rule number %s\n", *av); 5803d069a5d4SMaxim Konovalov saved_arg = arg; 5804d069a5d4SMaxim Konovalov if (use_set) 5805d069a5d4SMaxim Konovalov arg |= (1 << 24) | ((use_set - 1) << 16); 58069758b77fSLuigi Rizzo av++; 58079758b77fSLuigi Rizzo ac--; 5808d069a5d4SMaxim Konovalov if (do_cmd(optname, &arg, sizeof(arg))) { 5809571f8c1bSLuigi Rizzo warn("rule %u: setsockopt(IP_FW_%s)", 5810d069a5d4SMaxim Konovalov saved_arg, name); 58119758b77fSLuigi Rizzo failed = EX_UNAVAILABLE; 58129758b77fSLuigi Rizzo } else if (!do_quiet) 5813d069a5d4SMaxim Konovalov printf("Entry %d %s.\n", saved_arg, 5814571f8c1bSLuigi Rizzo optname == IP_FW_ZERO ? 5815571f8c1bSLuigi Rizzo "cleared" : "logging count reset"); 58169758b77fSLuigi Rizzo } else { 58179758b77fSLuigi Rizzo errx(EX_USAGE, "invalid rule number ``%s''", *av); 58189758b77fSLuigi Rizzo } 58199758b77fSLuigi Rizzo } 58209758b77fSLuigi Rizzo if (failed != EX_OK) 58219758b77fSLuigi Rizzo exit(failed); 58229758b77fSLuigi Rizzo } 58239758b77fSLuigi Rizzo 58249758b77fSLuigi Rizzo static void 582526bf4d78SLuigi Rizzo flush(int force) 58269758b77fSLuigi Rizzo { 58279758b77fSLuigi Rizzo int cmd = do_pipe ? IP_DUMMYNET_FLUSH : IP_FW_FLUSH; 58289758b77fSLuigi Rizzo 582926bf4d78SLuigi Rizzo if (!force && !do_quiet) { /* need to ask user */ 58309758b77fSLuigi Rizzo int c; 58319758b77fSLuigi Rizzo 58329758b77fSLuigi Rizzo printf("Are you sure? [yn] "); 58339758b77fSLuigi Rizzo fflush(stdout); 58349758b77fSLuigi Rizzo do { 58359758b77fSLuigi Rizzo c = toupper(getc(stdin)); 58369758b77fSLuigi Rizzo while (c != '\n' && getc(stdin) != '\n') 58379758b77fSLuigi Rizzo if (feof(stdin)) 58389758b77fSLuigi Rizzo return; /* and do not flush */ 58399758b77fSLuigi Rizzo } while (c != 'Y' && c != 'N'); 58409758b77fSLuigi Rizzo printf("\n"); 58419758b77fSLuigi Rizzo if (c == 'N') /* user said no */ 58429758b77fSLuigi Rizzo return; 58439758b77fSLuigi Rizzo } 5844d069a5d4SMaxim Konovalov /* `ipfw set N flush` - is the same that `ipfw delete set N` */ 5845d069a5d4SMaxim Konovalov if (use_set) { 5846d069a5d4SMaxim Konovalov uint32_t arg = ((use_set - 1) & 0xffff) | (1 << 24); 5847d069a5d4SMaxim Konovalov if (do_cmd(IP_FW_DEL, &arg, sizeof(arg)) < 0) 5848d069a5d4SMaxim Konovalov err(EX_UNAVAILABLE, "setsockopt(IP_FW_DEL)"); 5849d069a5d4SMaxim Konovalov } else if (do_cmd(cmd, NULL, 0) < 0) 58509758b77fSLuigi Rizzo err(EX_UNAVAILABLE, "setsockopt(IP_%s_FLUSH)", 58519758b77fSLuigi Rizzo do_pipe ? "DUMMYNET" : "FW"); 58529758b77fSLuigi Rizzo if (!do_quiet) 58539758b77fSLuigi Rizzo printf("Flushed all %s.\n", do_pipe ? "pipes" : "rules"); 58549758b77fSLuigi Rizzo } 58559758b77fSLuigi Rizzo 585662ff38aeSLuigi Rizzo /* 585726bf4d78SLuigi Rizzo * Free a the (locally allocated) copy of command line arguments. 585826bf4d78SLuigi Rizzo */ 585926bf4d78SLuigi Rizzo static void 586026bf4d78SLuigi Rizzo free_args(int ac, char **av) 586126bf4d78SLuigi Rizzo { 586226bf4d78SLuigi Rizzo int i; 586326bf4d78SLuigi Rizzo 586426bf4d78SLuigi Rizzo for (i=0; i < ac; i++) 586526bf4d78SLuigi Rizzo free(av[i]); 586626bf4d78SLuigi Rizzo free(av); 586726bf4d78SLuigi Rizzo } 586826bf4d78SLuigi Rizzo 5869c15c2490SRoman Kurakin static void table_list(ipfw_table_entry ent, int need_header); 58705ec36cd6SRoman Kurakin 587126bf4d78SLuigi Rizzo /* 5872cd8b5ae0SRuslan Ermilov * This one handles all table-related commands 5873cd8b5ae0SRuslan Ermilov * ipfw table N add addr[/masklen] [value] 5874cd8b5ae0SRuslan Ermilov * ipfw table N delete addr[/masklen] 5875c15c2490SRoman Kurakin * ipfw table {N | all} flush 5876c15c2490SRoman Kurakin * ipfw table {N | all} list 5877cd8b5ae0SRuslan Ermilov */ 5878cd8b5ae0SRuslan Ermilov static void 5879cd8b5ae0SRuslan Ermilov table_handler(int ac, char *av[]) 5880cd8b5ae0SRuslan Ermilov { 5881cd8b5ae0SRuslan Ermilov ipfw_table_entry ent; 5882cd8b5ae0SRuslan Ermilov int do_add; 5883c15c2490SRoman Kurakin int is_all; 5884eba1dd21SRoman Kurakin size_t len; 5885cd8b5ae0SRuslan Ermilov char *p; 5886c15c2490SRoman Kurakin uint32_t a; 5887eba1dd21SRoman Kurakin uint32_t tables_max; 5888eba1dd21SRoman Kurakin 58897bf717b7SGiorgos Keramidas len = sizeof(tables_max); 5890eba1dd21SRoman Kurakin if (sysctlbyname("net.inet.ip.fw.tables_max", &tables_max, &len, 5891eba1dd21SRoman Kurakin NULL, 0) == -1) { 5892eba1dd21SRoman Kurakin #ifdef IPFW_TABLES_MAX 5893eba1dd21SRoman Kurakin warn("Warn: Failed to get the max tables number via sysctl. " 5894eba1dd21SRoman Kurakin "Using the compiled in defaults. \nThe reason was"); 5895eba1dd21SRoman Kurakin tables_max = IPFW_TABLES_MAX; 5896eba1dd21SRoman Kurakin #else 5897eba1dd21SRoman Kurakin errx(1, "Failed sysctlbyname(\"net.inet.ip.fw.tables_max\")"); 5898eba1dd21SRoman Kurakin #endif 5899eba1dd21SRoman Kurakin } 5900cd8b5ae0SRuslan Ermilov 5901cd8b5ae0SRuslan Ermilov ac--; av++; 5902cd8b5ae0SRuslan Ermilov if (ac && isdigit(**av)) { 5903cd8b5ae0SRuslan Ermilov ent.tbl = atoi(*av); 5904c15c2490SRoman Kurakin is_all = 0; 5905c15c2490SRoman Kurakin ac--; av++; 5906c15c2490SRoman Kurakin } else if (ac && _substrcmp(*av, "all") == 0) { 5907c15c2490SRoman Kurakin ent.tbl = 0; 5908c15c2490SRoman Kurakin is_all = 1; 5909cd8b5ae0SRuslan Ermilov ac--; av++; 5910cd8b5ae0SRuslan Ermilov } else 5911c15c2490SRoman Kurakin errx(EX_USAGE, "table number or 'all' keyword required"); 5912eba1dd21SRoman Kurakin if (ent.tbl >= tables_max) 5913eba1dd21SRoman Kurakin errx(EX_USAGE, "The table number exceeds the maximum allowed " 5914eba1dd21SRoman Kurakin "value (%d)", tables_max - 1); 5915cd8b5ae0SRuslan Ermilov NEED1("table needs command"); 5916c15c2490SRoman Kurakin if (is_all && _substrcmp(*av, "list") != 0 5917c15c2490SRoman Kurakin && _substrcmp(*av, "flush") != 0) 5918c15c2490SRoman Kurakin errx(EX_USAGE, "table number required"); 5919c15c2490SRoman Kurakin 592001750186SBrooks Davis if (_substrcmp(*av, "add") == 0 || 592101750186SBrooks Davis _substrcmp(*av, "delete") == 0) { 5922cd8b5ae0SRuslan Ermilov do_add = **av == 'a'; 5923cd8b5ae0SRuslan Ermilov ac--; av++; 5924cd8b5ae0SRuslan Ermilov if (!ac) 5925cd8b5ae0SRuslan Ermilov errx(EX_USAGE, "IP address required"); 5926cd8b5ae0SRuslan Ermilov p = strchr(*av, '/'); 5927cd8b5ae0SRuslan Ermilov if (p) { 5928cd8b5ae0SRuslan Ermilov *p++ = '\0'; 5929cd8b5ae0SRuslan Ermilov ent.masklen = atoi(p); 5930cd8b5ae0SRuslan Ermilov if (ent.masklen > 32) 5931cd8b5ae0SRuslan Ermilov errx(EX_DATAERR, "bad width ``%s''", p); 5932cd8b5ae0SRuslan Ermilov } else 5933cd8b5ae0SRuslan Ermilov ent.masklen = 32; 5934cd8b5ae0SRuslan Ermilov if (lookup_host(*av, (struct in_addr *)&ent.addr) != 0) 59351a41a8e4SRuslan Ermilov errx(EX_NOHOST, "hostname ``%s'' unknown", *av); 5936cd8b5ae0SRuslan Ermilov ac--; av++; 5937c487be96SJulian Elischer if (do_add && ac) { 5938c487be96SJulian Elischer unsigned int tval; 5939c487be96SJulian Elischer /* isdigit is a bit of a hack here.. */ 5940c487be96SJulian Elischer if (strchr(*av, (int)'.') == NULL && isdigit(**av)) { 5941cd8b5ae0SRuslan Ermilov ent.value = strtoul(*av, NULL, 0); 5942c487be96SJulian Elischer } else { 5943c487be96SJulian Elischer if (lookup_host(*av, (struct in_addr *)&tval) == 0) { 5944c487be96SJulian Elischer /* The value must be stored in host order * 5945c487be96SJulian Elischer * so that the values < 65k can be distinguished */ 5946c487be96SJulian Elischer ent.value = ntohl(tval); 5947c487be96SJulian Elischer } else { 5948c487be96SJulian Elischer errx(EX_NOHOST, "hostname ``%s'' unknown", *av); 5949c487be96SJulian Elischer } 5950c487be96SJulian Elischer } 5951c487be96SJulian Elischer } else 5952cd8b5ae0SRuslan Ermilov ent.value = 0; 5953cd8b5ae0SRuslan Ermilov if (do_cmd(do_add ? IP_FW_TABLE_ADD : IP_FW_TABLE_DEL, 5954905c41b5SJulian Elischer &ent, sizeof(ent)) < 0) { 595521899082SJulian Elischer /* If running silent, don't bomb out on these errors. */ 595621899082SJulian Elischer if (!(do_quiet && (errno == (do_add ? EEXIST : ESRCH)))) 595721899082SJulian Elischer err(EX_OSERR, "setsockopt(IP_FW_TABLE_%s)", 595821899082SJulian Elischer do_add ? "ADD" : "DEL"); 595921899082SJulian Elischer /* In silent mode, react to a failed add by deleting */ 5960dbadd6b0SJulian Elischer if (do_add) { 596121899082SJulian Elischer do_cmd(IP_FW_TABLE_DEL, &ent, sizeof(ent)); 596221899082SJulian Elischer if (do_cmd(IP_FW_TABLE_ADD, 596321899082SJulian Elischer &ent, sizeof(ent)) < 0) 596421899082SJulian Elischer err(EX_OSERR, 596521899082SJulian Elischer "setsockopt(IP_FW_TABLE_ADD)"); 5966dbadd6b0SJulian Elischer } 5967905c41b5SJulian Elischer } 596801750186SBrooks Davis } else if (_substrcmp(*av, "flush") == 0) { 5969c15c2490SRoman Kurakin a = is_all ? tables_max : (ent.tbl + 1); 5970c15c2490SRoman Kurakin do { 5971c15c2490SRoman Kurakin if (do_cmd(IP_FW_TABLE_FLUSH, &ent.tbl, 5972c15c2490SRoman Kurakin sizeof(ent.tbl)) < 0) 5973cd8b5ae0SRuslan Ermilov err(EX_OSERR, "setsockopt(IP_FW_TABLE_FLUSH)"); 5974c15c2490SRoman Kurakin } while (++ent.tbl < a); 597501750186SBrooks Davis } else if (_substrcmp(*av, "list") == 0) { 5976c15c2490SRoman Kurakin a = is_all ? tables_max : (ent.tbl + 1); 5977c15c2490SRoman Kurakin do { 5978e7ef3e94SRoman Kurakin table_list(ent, is_all); 5979c15c2490SRoman Kurakin } while (++ent.tbl < a); 59805ec36cd6SRoman Kurakin } else 59815ec36cd6SRoman Kurakin errx(EX_USAGE, "invalid table command %s", *av); 59825ec36cd6SRoman Kurakin } 59835ec36cd6SRoman Kurakin 59845ec36cd6SRoman Kurakin static void 5985c15c2490SRoman Kurakin table_list(ipfw_table_entry ent, int need_header) 59865ec36cd6SRoman Kurakin { 59875ec36cd6SRoman Kurakin ipfw_table *tbl; 59885ec36cd6SRoman Kurakin socklen_t l; 59895ec36cd6SRoman Kurakin uint32_t a; 59905ec36cd6SRoman Kurakin 5991cd8b5ae0SRuslan Ermilov a = ent.tbl; 5992cd8b5ae0SRuslan Ermilov l = sizeof(a); 5993cd8b5ae0SRuslan Ermilov if (do_cmd(IP_FW_TABLE_GETSIZE, &a, (uintptr_t)&l) < 0) 5994cd8b5ae0SRuslan Ermilov err(EX_OSERR, "getsockopt(IP_FW_TABLE_GETSIZE)"); 599503d4b38dSRoman Kurakin 599603d4b38dSRoman Kurakin /* If a is zero we have nothing to do, the table is empty. */ 599703d4b38dSRoman Kurakin if (a == 0) 599803d4b38dSRoman Kurakin return; 599903d4b38dSRoman Kurakin 6000cd8b5ae0SRuslan Ermilov l = sizeof(*tbl) + a * sizeof(ipfw_table_entry); 60015f356082SLuigi Rizzo tbl = safe_calloc(1, l); 6002cd8b5ae0SRuslan Ermilov tbl->tbl = ent.tbl; 6003cd8b5ae0SRuslan Ermilov if (do_cmd(IP_FW_TABLE_LIST, tbl, (uintptr_t)&l) < 0) 6004cd8b5ae0SRuslan Ermilov err(EX_OSERR, "getsockopt(IP_FW_TABLE_LIST)"); 6005c15c2490SRoman Kurakin if (tbl->cnt && need_header) 6006c15c2490SRoman Kurakin printf("---table(%d)---\n", tbl->tbl); 6007cd8b5ae0SRuslan Ermilov for (a = 0; a < tbl->cnt; a++) { 6008c487be96SJulian Elischer unsigned int tval; 6009c487be96SJulian Elischer tval = tbl->ent[a].value; 60100943a3b7SJulian Elischer if (do_value_as_ip) { 6011c487be96SJulian Elischer char tbuf[128]; 6012afad78e2SJulian Elischer strncpy(tbuf, inet_ntoa(*(struct in_addr *) 6013c487be96SJulian Elischer &tbl->ent[a].addr), 127); 60140943a3b7SJulian Elischer /* inet_ntoa expects network order */ 6015c487be96SJulian Elischer tval = htonl(tval); 6016afad78e2SJulian Elischer printf("%s/%u %s\n", tbuf, tbl->ent[a].masklen, 6017c487be96SJulian Elischer inet_ntoa(*(struct in_addr *)&tval)); 6018c487be96SJulian Elischer } else { 6019cd8b5ae0SRuslan Ermilov printf("%s/%u %u\n", 6020cd8b5ae0SRuslan Ermilov inet_ntoa(*(struct in_addr *)&tbl->ent[a].addr), 60210943a3b7SJulian Elischer tbl->ent[a].masklen, tval); 6022cd8b5ae0SRuslan Ermilov } 6023c487be96SJulian Elischer } 6024b0000a98SRoman Kurakin free(tbl); 6025cd8b5ae0SRuslan Ermilov } 6026cd8b5ae0SRuslan Ermilov 6027ff2f6fe8SPaolo Pisati static void 6028b88a2fe1SRoman Kurakin show_nat(int ac, char **av) 6029b88a2fe1SRoman Kurakin { 6030ff2f6fe8SPaolo Pisati struct cfg_nat *n; 6031ff2f6fe8SPaolo Pisati struct cfg_redir *e; 6032ff2f6fe8SPaolo Pisati int cmd, i, nbytes, do_cfg, do_rule, frule, lrule, nalloc, size; 6033c879f6ecSPaolo Pisati int nat_cnt, redir_cnt, r; 6034ff2f6fe8SPaolo Pisati uint8_t *data, *p; 6035015002dfSRoman Kurakin char *endptr; 6036ff2f6fe8SPaolo Pisati 6037ff2f6fe8SPaolo Pisati do_rule = 0; 6038ff2f6fe8SPaolo Pisati nalloc = 1024; 6039ff2f6fe8SPaolo Pisati size = 0; 6040ff2f6fe8SPaolo Pisati data = NULL; 6041d956bdf3SPaolo Pisati frule = 0; 6042759dd6f7SRoman Kurakin lrule = IPFW_DEFAULT_RULE; /* max ipfw rule number */ 6043ff2f6fe8SPaolo Pisati ac--; av++; 6044ff2f6fe8SPaolo Pisati 604592531c02SMaxim Konovalov if (test_only) 604692531c02SMaxim Konovalov return; 604792531c02SMaxim Konovalov 6048ff2f6fe8SPaolo Pisati /* Parse parameters. */ 6049ff2f6fe8SPaolo Pisati for (cmd = IP_FW_NAT_GET_LOG, do_cfg = 0; ac != 0; ac--, av++) { 6050ff2f6fe8SPaolo Pisati if (!strncmp(av[0], "config", strlen(av[0]))) { 6051ff2f6fe8SPaolo Pisati cmd = IP_FW_NAT_GET_CONFIG, do_cfg = 1; 6052ff2f6fe8SPaolo Pisati continue; 6053ff2f6fe8SPaolo Pisati } 6054ff2f6fe8SPaolo Pisati /* Convert command line rule #. */ 6055ff2f6fe8SPaolo Pisati frule = lrule = strtoul(av[0], &endptr, 10); 6056ff2f6fe8SPaolo Pisati if (*endptr == '-') 6057ff2f6fe8SPaolo Pisati lrule = strtoul(endptr+1, &endptr, 10); 6058ff2f6fe8SPaolo Pisati if (lrule == 0) 6059ff2f6fe8SPaolo Pisati err(EX_USAGE, "invalid rule number: %s", av[0]); 6060ff2f6fe8SPaolo Pisati do_rule = 1; 6061ff2f6fe8SPaolo Pisati } 6062ff2f6fe8SPaolo Pisati 6063ff2f6fe8SPaolo Pisati nbytes = nalloc; 6064ff2f6fe8SPaolo Pisati while (nbytes >= nalloc) { 6065ff2f6fe8SPaolo Pisati nalloc = nalloc * 2; 6066ff2f6fe8SPaolo Pisati nbytes = nalloc; 60675f356082SLuigi Rizzo data = safe_realloc(data, nbytes); 6068ff2f6fe8SPaolo Pisati if (do_cmd(cmd, data, (uintptr_t)&nbytes) < 0) 6069ff2f6fe8SPaolo Pisati err(EX_OSERR, "getsockopt(IP_FW_GET_%s)", 6070ff2f6fe8SPaolo Pisati (cmd == IP_FW_NAT_GET_LOG) ? "LOG" : "CONFIG"); 6071ff2f6fe8SPaolo Pisati } 6072ff2f6fe8SPaolo Pisati if (nbytes == 0) 6073ff2f6fe8SPaolo Pisati exit(0); 6074ff2f6fe8SPaolo Pisati if (do_cfg) { 6075ff2f6fe8SPaolo Pisati nat_cnt = *((int *)data); 6076ff2f6fe8SPaolo Pisati for (i = sizeof(nat_cnt); nat_cnt; nat_cnt--) { 6077ff2f6fe8SPaolo Pisati n = (struct cfg_nat *)&data[i]; 6078d956bdf3SPaolo Pisati if (frule <= n->id && lrule >= n->id) 6079ff2f6fe8SPaolo Pisati print_nat_config(&data[i]); 6080ff2f6fe8SPaolo Pisati i += sizeof(struct cfg_nat); 6081c879f6ecSPaolo Pisati for (redir_cnt = 0; redir_cnt < n->redir_cnt; redir_cnt++) { 6082ff2f6fe8SPaolo Pisati e = (struct cfg_redir *)&data[i]; 6083ff2f6fe8SPaolo Pisati i += sizeof(struct cfg_redir) + e->spool_cnt * 6084ff2f6fe8SPaolo Pisati sizeof(struct cfg_spool); 6085ff2f6fe8SPaolo Pisati } 6086c879f6ecSPaolo Pisati } 6087ff2f6fe8SPaolo Pisati } else { 6088ff2f6fe8SPaolo Pisati for (i = 0; 1; i += LIBALIAS_BUF_SIZE + sizeof(int)) { 6089ff2f6fe8SPaolo Pisati p = &data[i]; 6090ff2f6fe8SPaolo Pisati if (p == data + nbytes) 6091ff2f6fe8SPaolo Pisati break; 6092ff2f6fe8SPaolo Pisati bcopy(p, &r, sizeof(int)); 6093ff2f6fe8SPaolo Pisati if (do_rule) { 6094ff2f6fe8SPaolo Pisati if (!(frule <= r && lrule >= r)) 6095ff2f6fe8SPaolo Pisati continue; 6096ff2f6fe8SPaolo Pisati } 6097ff2f6fe8SPaolo Pisati printf("nat %u: %s\n", r, p+sizeof(int)); 6098ff2f6fe8SPaolo Pisati } 6099ff2f6fe8SPaolo Pisati } 6100ff2f6fe8SPaolo Pisati } 6101ff2f6fe8SPaolo Pisati 6102cd8b5ae0SRuslan Ermilov /* 6103c5620639SLuigi Rizzo * Called with the arguments, including program name because getopt 6104c5620639SLuigi Rizzo * wants it to be present. 610526bf4d78SLuigi Rizzo * Returns 0 if successful, 1 if empty command, errx() in case of errors. 610662ff38aeSLuigi Rizzo */ 61079758b77fSLuigi Rizzo static int 6108571f8c1bSLuigi Rizzo ipfw_main(int oldac, char **oldav) 61099758b77fSLuigi Rizzo { 611062ff38aeSLuigi Rizzo int ch, ac, save_ac; 6111d069a5d4SMaxim Konovalov const char *errstr; 611262ff38aeSLuigi Rizzo char **av, **save_av; 611362ff38aeSLuigi Rizzo int do_acct = 0; /* Show packet/byte count */ 6114571f8c1bSLuigi Rizzo 611562ff38aeSLuigi Rizzo #define WHITESP " \t\f\v\n\r" 6116c5620639SLuigi Rizzo if (oldac < 2) 6117c5620639SLuigi Rizzo return 1; /* need at least one argument */ 6118c5620639SLuigi Rizzo if (oldac == 2) { 6119571f8c1bSLuigi Rizzo /* 6120571f8c1bSLuigi Rizzo * If we are called with a single string, try to split it into 6121571f8c1bSLuigi Rizzo * arguments for subsequent parsing. 6122571f8c1bSLuigi Rizzo * But first, remove spaces after a ',', by copying the string 6123571f8c1bSLuigi Rizzo * in-place. 6124571f8c1bSLuigi Rizzo */ 6125c5620639SLuigi Rizzo char *arg = oldav[1]; /* The string is the first arg. */ 6126571f8c1bSLuigi Rizzo int l = strlen(arg); 6127571f8c1bSLuigi Rizzo int copy = 0; /* 1 if we need to copy, 0 otherwise */ 6128571f8c1bSLuigi Rizzo int i, j; 612962ff38aeSLuigi Rizzo for (i = j = 0; i < l; i++) { 613062ff38aeSLuigi Rizzo if (arg[i] == '#') /* comment marker */ 613162ff38aeSLuigi Rizzo break; 6132571f8c1bSLuigi Rizzo if (copy) { 6133571f8c1bSLuigi Rizzo arg[j++] = arg[i]; 613462ff38aeSLuigi Rizzo copy = !index("," WHITESP, arg[i]); 6135571f8c1bSLuigi Rizzo } else { 613662ff38aeSLuigi Rizzo copy = !index(WHITESP, arg[i]); 6137571f8c1bSLuigi Rizzo if (copy) 6138571f8c1bSLuigi Rizzo arg[j++] = arg[i]; 6139571f8c1bSLuigi Rizzo } 614062ff38aeSLuigi Rizzo } 6141571f8c1bSLuigi Rizzo if (!copy && j > 0) /* last char was a 'blank', remove it */ 6142571f8c1bSLuigi Rizzo j--; 6143571f8c1bSLuigi Rizzo l = j; /* the new argument length */ 6144571f8c1bSLuigi Rizzo arg[j++] = '\0'; 614562ff38aeSLuigi Rizzo if (l == 0) /* empty string! */ 614626bf4d78SLuigi Rizzo return 1; 6147571f8c1bSLuigi Rizzo 6148571f8c1bSLuigi Rizzo /* 6149571f8c1bSLuigi Rizzo * First, count number of arguments. Because of the previous 615062ff38aeSLuigi Rizzo * processing, this is just the number of blanks plus 1. 6151571f8c1bSLuigi Rizzo */ 6152571f8c1bSLuigi Rizzo for (i = 0, ac = 1; i < l; i++) 615362ff38aeSLuigi Rizzo if (index(WHITESP, arg[i]) != NULL) 6154571f8c1bSLuigi Rizzo ac++; 6155571f8c1bSLuigi Rizzo 6156c5620639SLuigi Rizzo /* 6157c5620639SLuigi Rizzo * Allocate the argument list, including one entry for 6158c5620639SLuigi Rizzo * the program name because getopt expects it. 6159c5620639SLuigi Rizzo */ 61605f356082SLuigi Rizzo av = safe_calloc(ac + 1, sizeof(char *)); 6161571f8c1bSLuigi Rizzo 6162571f8c1bSLuigi Rizzo /* 6163c5620639SLuigi Rizzo * Second, copy arguments from arg[] to av[]. For each one, 6164571f8c1bSLuigi Rizzo * j is the initial character, i is the one past the end. 6165571f8c1bSLuigi Rizzo */ 6166c5620639SLuigi Rizzo for (ac = 1, i = j = 0; i < l; i++) 616762ff38aeSLuigi Rizzo if (index(WHITESP, arg[i]) != NULL || i == l-1) { 6168571f8c1bSLuigi Rizzo if (i == l-1) 6169571f8c1bSLuigi Rizzo i++; 61705f356082SLuigi Rizzo av[ac] = safe_calloc(i-j+1, 1); 6171571f8c1bSLuigi Rizzo bcopy(arg+j, av[ac], i-j); 6172571f8c1bSLuigi Rizzo ac++; 6173571f8c1bSLuigi Rizzo j = i + 1; 6174571f8c1bSLuigi Rizzo } 6175571f8c1bSLuigi Rizzo } else { 6176571f8c1bSLuigi Rizzo /* 6177571f8c1bSLuigi Rizzo * If an argument ends with ',' join with the next one. 6178571f8c1bSLuigi Rizzo */ 6179571f8c1bSLuigi Rizzo int first, i, l; 6180571f8c1bSLuigi Rizzo 61815f356082SLuigi Rizzo av = safe_calloc(oldac, sizeof(char *)); 6182c5620639SLuigi Rizzo for (first = i = ac = 1, l = 0; i < oldac; i++) { 6183571f8c1bSLuigi Rizzo char *arg = oldav[i]; 6184571f8c1bSLuigi Rizzo int k = strlen(arg); 6185571f8c1bSLuigi Rizzo 6186571f8c1bSLuigi Rizzo l += k; 6187571f8c1bSLuigi Rizzo if (arg[k-1] != ',' || i == oldac-1) { 6188571f8c1bSLuigi Rizzo /* Time to copy. */ 61895f356082SLuigi Rizzo av[ac] = safe_calloc(l+1, 1); 6190571f8c1bSLuigi Rizzo for (l=0; first <= i; first++) { 6191571f8c1bSLuigi Rizzo strcat(av[ac]+l, oldav[first]); 6192571f8c1bSLuigi Rizzo l += strlen(oldav[first]); 6193571f8c1bSLuigi Rizzo } 6194571f8c1bSLuigi Rizzo ac++; 6195571f8c1bSLuigi Rizzo l = 0; 6196571f8c1bSLuigi Rizzo first = i+1; 6197571f8c1bSLuigi Rizzo } 6198571f8c1bSLuigi Rizzo } 6199571f8c1bSLuigi Rizzo } 62009758b77fSLuigi Rizzo 6201c5620639SLuigi Rizzo av[0] = strdup(oldav[0]); /* copy progname from the caller */ 62029758b77fSLuigi Rizzo /* Set the force flag for non-interactive processes */ 6203cec4ab6aSMaxim Konovalov if (!do_force) 62049758b77fSLuigi Rizzo do_force = !isatty(STDIN_FILENO); 62059758b77fSLuigi Rizzo 620662ff38aeSLuigi Rizzo /* Save arguments for final freeing of memory. */ 620762ff38aeSLuigi Rizzo save_ac = ac; 620862ff38aeSLuigi Rizzo save_av = av; 620962ff38aeSLuigi Rizzo 6210c5620639SLuigi Rizzo optind = optreset = 1; /* restart getopt() */ 62110943a3b7SJulian Elischer while ((ch = getopt(ac, av, "abcdefhinNqs:STtv")) != -1) 62129758b77fSLuigi Rizzo switch (ch) { 6213571f8c1bSLuigi Rizzo case 'a': 6214571f8c1bSLuigi Rizzo do_acct = 1; 6215571f8c1bSLuigi Rizzo break; 6216571f8c1bSLuigi Rizzo 6217ac6cec51SLuigi Rizzo case 'b': 6218ac6cec51SLuigi Rizzo comment_only = 1; 6219ac6cec51SLuigi Rizzo do_compact = 1; 6220ac6cec51SLuigi Rizzo break; 6221ac6cec51SLuigi Rizzo 6222571f8c1bSLuigi Rizzo case 'c': 6223571f8c1bSLuigi Rizzo do_compact = 1; 6224571f8c1bSLuigi Rizzo break; 6225571f8c1bSLuigi Rizzo 6226571f8c1bSLuigi Rizzo case 'd': 6227571f8c1bSLuigi Rizzo do_dynamic = 1; 6228571f8c1bSLuigi Rizzo break; 6229571f8c1bSLuigi Rizzo 6230571f8c1bSLuigi Rizzo case 'e': 6231571f8c1bSLuigi Rizzo do_expired = 1; 6232571f8c1bSLuigi Rizzo break; 6233571f8c1bSLuigi Rizzo 6234571f8c1bSLuigi Rizzo case 'f': 6235571f8c1bSLuigi Rizzo do_force = 1; 6236571f8c1bSLuigi Rizzo break; 6237571f8c1bSLuigi Rizzo 62389758b77fSLuigi Rizzo case 'h': /* help */ 623926bf4d78SLuigi Rizzo free_args(save_ac, save_av); 62409758b77fSLuigi Rizzo help(); 62419758b77fSLuigi Rizzo break; /* NOTREACHED */ 62429758b77fSLuigi Rizzo 62430943a3b7SJulian Elischer case 'i': 62440943a3b7SJulian Elischer do_value_as_ip = 1; 62450943a3b7SJulian Elischer break; 62460943a3b7SJulian Elischer 6247571f8c1bSLuigi Rizzo case 'n': 6248571f8c1bSLuigi Rizzo test_only = 1; 62499758b77fSLuigi Rizzo break; 6250571f8c1bSLuigi Rizzo 62519758b77fSLuigi Rizzo case 'N': 62529758b77fSLuigi Rizzo do_resolv = 1; 62539758b77fSLuigi Rizzo break; 6254571f8c1bSLuigi Rizzo 62559758b77fSLuigi Rizzo case 'q': 62569758b77fSLuigi Rizzo do_quiet = 1; 62579758b77fSLuigi Rizzo break; 6258571f8c1bSLuigi Rizzo 6259571f8c1bSLuigi Rizzo case 's': /* sort */ 6260571f8c1bSLuigi Rizzo do_sort = atoi(optarg); 6261571f8c1bSLuigi Rizzo break; 6262571f8c1bSLuigi Rizzo 626343405724SLuigi Rizzo case 'S': 626443405724SLuigi Rizzo show_sets = 1; 626543405724SLuigi Rizzo break; 6266571f8c1bSLuigi Rizzo 62679758b77fSLuigi Rizzo case 't': 62689758b77fSLuigi Rizzo do_time = 1; 62699758b77fSLuigi Rizzo break; 6270571f8c1bSLuigi Rizzo 62711b43a426SLuigi Rizzo case 'T': 62721b43a426SLuigi Rizzo do_time = 2; /* numeric timestamp */ 62731b43a426SLuigi Rizzo break; 62741b43a426SLuigi Rizzo 62759758b77fSLuigi Rizzo case 'v': /* verbose */ 6276571f8c1bSLuigi Rizzo verbose = 1; 62779758b77fSLuigi Rizzo break; 6278571f8c1bSLuigi Rizzo 62799758b77fSLuigi Rizzo default: 628026bf4d78SLuigi Rizzo free_args(save_ac, save_av); 628126bf4d78SLuigi Rizzo return 1; 62829758b77fSLuigi Rizzo } 62839758b77fSLuigi Rizzo 62849758b77fSLuigi Rizzo ac -= optind; 62859758b77fSLuigi Rizzo av += optind; 62869758b77fSLuigi Rizzo NEED1("bad arguments, for usage summary ``ipfw''"); 62879758b77fSLuigi Rizzo 62889758b77fSLuigi Rizzo /* 628926bf4d78SLuigi Rizzo * An undocumented behaviour of ipfw1 was to allow rule numbers first, 629026bf4d78SLuigi Rizzo * e.g. "100 add allow ..." instead of "add 100 allow ...". 629126bf4d78SLuigi Rizzo * In case, swap first and second argument to get the normal form. 629226bf4d78SLuigi Rizzo */ 629326bf4d78SLuigi Rizzo if (ac > 1 && isdigit(*av[0])) { 629426bf4d78SLuigi Rizzo char *p = av[0]; 629526bf4d78SLuigi Rizzo 629626bf4d78SLuigi Rizzo av[0] = av[1]; 629726bf4d78SLuigi Rizzo av[1] = p; 629826bf4d78SLuigi Rizzo } 629926bf4d78SLuigi Rizzo 630026bf4d78SLuigi Rizzo /* 6301ff2f6fe8SPaolo Pisati * Optional: pipe, queue or nat. 63029758b77fSLuigi Rizzo */ 6303ff2f6fe8SPaolo Pisati do_nat = 0; 63046fa74f7dSMaxim Konovalov do_pipe = 0; 6305ff2f6fe8SPaolo Pisati if (!strncmp(*av, "nat", strlen(*av))) 6306ff2f6fe8SPaolo Pisati do_nat = 1; 6307ff2f6fe8SPaolo Pisati else if (!strncmp(*av, "pipe", strlen(*av))) 63089758b77fSLuigi Rizzo do_pipe = 1; 630901750186SBrooks Davis else if (_substrcmp(*av, "queue") == 0) 63109758b77fSLuigi Rizzo do_pipe = 2; 6311d069a5d4SMaxim Konovalov else if (!strncmp(*av, "set", strlen(*av))) { 6312d069a5d4SMaxim Konovalov if (ac > 1 && isdigit(av[1][0])) { 6313d069a5d4SMaxim Konovalov use_set = strtonum(av[1], 0, RESVD_SET, &errstr); 6314d069a5d4SMaxim Konovalov if (errstr) 6315d069a5d4SMaxim Konovalov errx(EX_DATAERR, 6316d069a5d4SMaxim Konovalov "invalid set number %s\n", av[1]); 6317d069a5d4SMaxim Konovalov ac -= 2; av += 2; use_set++; 6318d069a5d4SMaxim Konovalov } 6319d069a5d4SMaxim Konovalov } 6320d069a5d4SMaxim Konovalov 6321ff2f6fe8SPaolo Pisati if (do_pipe || do_nat) { 63229758b77fSLuigi Rizzo ac--; 63239758b77fSLuigi Rizzo av++; 63249758b77fSLuigi Rizzo } 63259758b77fSLuigi Rizzo NEED1("missing command"); 63269758b77fSLuigi Rizzo 63279758b77fSLuigi Rizzo /* 6328ff2f6fe8SPaolo Pisati * For pipes, queues and nats we normally say 'nat|pipe NN config' 6329ff2f6fe8SPaolo Pisati * but the code is easier to parse as 'nat|pipe config NN' 63309758b77fSLuigi Rizzo * so we swap the two arguments. 63319758b77fSLuigi Rizzo */ 6332ff2f6fe8SPaolo Pisati if ((do_pipe || do_nat) && ac > 1 && isdigit(*av[0])) { 63339758b77fSLuigi Rizzo char *p = av[0]; 633426bf4d78SLuigi Rizzo 63359758b77fSLuigi Rizzo av[0] = av[1]; 63369758b77fSLuigi Rizzo av[1] = p; 63379758b77fSLuigi Rizzo } 6338571f8c1bSLuigi Rizzo 6339d069a5d4SMaxim Konovalov int try_next = 0; 6340d069a5d4SMaxim Konovalov if (use_set == 0) { 634101750186SBrooks Davis if (_substrcmp(*av, "add") == 0) 63429758b77fSLuigi Rizzo add(ac, av); 6343ff2f6fe8SPaolo Pisati else if (do_nat && _substrcmp(*av, "show") == 0) 6344ff2f6fe8SPaolo Pisati show_nat(ac, av); 634501750186SBrooks Davis else if (do_pipe && _substrcmp(*av, "config") == 0) 63469758b77fSLuigi Rizzo config_pipe(ac, av); 6347ff2f6fe8SPaolo Pisati else if (do_nat && _substrcmp(*av, "config") == 0) 6348ff2f6fe8SPaolo Pisati config_nat(ac, av); 6349d069a5d4SMaxim Konovalov else if (_substrcmp(*av, "set") == 0) 6350d069a5d4SMaxim Konovalov sets_handler(ac, av); 6351d069a5d4SMaxim Konovalov else if (_substrcmp(*av, "table") == 0) 6352d069a5d4SMaxim Konovalov table_handler(ac, av); 6353d069a5d4SMaxim Konovalov else if (_substrcmp(*av, "enable") == 0) 6354d069a5d4SMaxim Konovalov sysctl_handler(ac, av, 1); 6355d069a5d4SMaxim Konovalov else if (_substrcmp(*av, "disable") == 0) 6356d069a5d4SMaxim Konovalov sysctl_handler(ac, av, 0); 6357d069a5d4SMaxim Konovalov else 6358d069a5d4SMaxim Konovalov try_next = 1; 6359d069a5d4SMaxim Konovalov } 6360d069a5d4SMaxim Konovalov 6361d069a5d4SMaxim Konovalov if (use_set || try_next) { 6362d069a5d4SMaxim Konovalov if (_substrcmp(*av, "delete") == 0) 63639758b77fSLuigi Rizzo delete(ac, av); 636401750186SBrooks Davis else if (_substrcmp(*av, "flush") == 0) 636526bf4d78SLuigi Rizzo flush(do_force); 636601750186SBrooks Davis else if (_substrcmp(*av, "zero") == 0) 6367571f8c1bSLuigi Rizzo zero(ac, av, IP_FW_ZERO); 636801750186SBrooks Davis else if (_substrcmp(*av, "resetlog") == 0) 6369571f8c1bSLuigi Rizzo zero(ac, av, IP_FW_RESETLOG); 637001750186SBrooks Davis else if (_substrcmp(*av, "print") == 0 || 637101750186SBrooks Davis _substrcmp(*av, "list") == 0) 637262ff38aeSLuigi Rizzo list(ac, av, do_acct); 637301750186SBrooks Davis else if (_substrcmp(*av, "show") == 0) 637462ff38aeSLuigi Rizzo list(ac, av, 1 /* show counters */); 637562ff38aeSLuigi Rizzo else 63769758b77fSLuigi Rizzo errx(EX_USAGE, "bad command `%s'", *av); 6377d069a5d4SMaxim Konovalov } 637862ff38aeSLuigi Rizzo 637962ff38aeSLuigi Rizzo /* Free memory allocated in the argument parsing. */ 638026bf4d78SLuigi Rizzo free_args(save_ac, save_av); 63819758b77fSLuigi Rizzo return 0; 63829758b77fSLuigi Rizzo } 63839758b77fSLuigi Rizzo 63849758b77fSLuigi Rizzo 63859758b77fSLuigi Rizzo static void 63869758b77fSLuigi Rizzo ipfw_readfile(int ac, char *av[]) 63879758b77fSLuigi Rizzo { 63889758b77fSLuigi Rizzo #define MAX_ARGS 32 63899758b77fSLuigi Rizzo char buf[BUFSIZ]; 63905f356082SLuigi Rizzo char *progname = av[0]; /* original program name */ 6391c5620639SLuigi Rizzo const char *cmd = NULL; /* preprocessor name, if any */ 6392c5620639SLuigi Rizzo const char *filename = av[ac-1]; /* file to read */ 639362ff38aeSLuigi Rizzo int c, lineno=0; 63949758b77fSLuigi Rizzo FILE *f = NULL; 63959758b77fSLuigi Rizzo pid_t preproc = 0; 63969758b77fSLuigi Rizzo 6397cec4ab6aSMaxim Konovalov while ((c = getopt(ac, av, "cfNnp:qS")) != -1) { 63989758b77fSLuigi Rizzo switch(c) { 639962ff38aeSLuigi Rizzo case 'c': 640062ff38aeSLuigi Rizzo do_compact = 1; 640162ff38aeSLuigi Rizzo break; 640262ff38aeSLuigi Rizzo 6403cec4ab6aSMaxim Konovalov case 'f': 6404cec4ab6aSMaxim Konovalov do_force = 1; 6405cec4ab6aSMaxim Konovalov break; 6406cec4ab6aSMaxim Konovalov 640762ff38aeSLuigi Rizzo case 'N': 640862ff38aeSLuigi Rizzo do_resolv = 1; 640962ff38aeSLuigi Rizzo break; 641062ff38aeSLuigi Rizzo 6411571f8c1bSLuigi Rizzo case 'n': 6412571f8c1bSLuigi Rizzo test_only = 1; 6413571f8c1bSLuigi Rizzo break; 6414571f8c1bSLuigi Rizzo 64159758b77fSLuigi Rizzo case 'p': 641662ff38aeSLuigi Rizzo /* 6417c5620639SLuigi Rizzo * ipfw -p cmd [args] filename 6418c5620639SLuigi Rizzo * 6419c5620639SLuigi Rizzo * We are done with getopt(). All arguments 6420c5620639SLuigi Rizzo * except the filename go to the preprocessor, 6421c5620639SLuigi Rizzo * so we need to do the following: 6422c5620639SLuigi Rizzo * - check that a filename is actually present; 6423c5620639SLuigi Rizzo * - advance av by optind-1 to skip arguments 6424c5620639SLuigi Rizzo * already processed; 6425c5620639SLuigi Rizzo * - decrease ac by optind, to remove the args 6426c5620639SLuigi Rizzo * already processed and the final filename; 6427c5620639SLuigi Rizzo * - set the last entry in av[] to NULL so 6428c5620639SLuigi Rizzo * popen() can detect the end of the array; 6429c5620639SLuigi Rizzo * - set optind=ac to let getopt() terminate. 643062ff38aeSLuigi Rizzo */ 6431c5620639SLuigi Rizzo if (optind == ac) 6432c2438409SMaxim Konovalov errx(EX_USAGE, "no filename argument"); 6433c5620639SLuigi Rizzo cmd = optarg; 643462ff38aeSLuigi Rizzo av[ac-1] = NULL; 6435c5620639SLuigi Rizzo av += optind - 1; 6436c5620639SLuigi Rizzo ac -= optind; 6437c5620639SLuigi Rizzo optind = ac; 64389758b77fSLuigi Rizzo break; 64399758b77fSLuigi Rizzo 64409758b77fSLuigi Rizzo case 'q': 644162ff38aeSLuigi Rizzo do_quiet = 1; 644262ff38aeSLuigi Rizzo break; 644362ff38aeSLuigi Rizzo 644462ff38aeSLuigi Rizzo case 'S': 644562ff38aeSLuigi Rizzo show_sets = 1; 64469758b77fSLuigi Rizzo break; 64479758b77fSLuigi Rizzo 64489758b77fSLuigi Rizzo default: 64499758b77fSLuigi Rizzo errx(EX_USAGE, "bad arguments, for usage" 64509758b77fSLuigi Rizzo " summary ``ipfw''"); 64519758b77fSLuigi Rizzo } 64529758b77fSLuigi Rizzo 6453ca6e3cb0SKelly Yancey } 6454ca6e3cb0SKelly Yancey 645562ff38aeSLuigi Rizzo if (cmd == NULL && ac != optind + 1) { 645662ff38aeSLuigi Rizzo fprintf(stderr, "ac %d, optind %d\n", ac, optind); 64579758b77fSLuigi Rizzo errx(EX_USAGE, "extraneous filename arguments"); 645862ff38aeSLuigi Rizzo } 64599758b77fSLuigi Rizzo 646062ff38aeSLuigi Rizzo if ((f = fopen(filename, "r")) == NULL) 646162ff38aeSLuigi Rizzo err(EX_UNAVAILABLE, "fopen: %s", filename); 64629758b77fSLuigi Rizzo 646362ff38aeSLuigi Rizzo if (cmd != NULL) { /* pipe through preprocessor */ 64649758b77fSLuigi Rizzo int pipedes[2]; 64659758b77fSLuigi Rizzo 64669758b77fSLuigi Rizzo if (pipe(pipedes) == -1) 64679758b77fSLuigi Rizzo err(EX_OSERR, "cannot create pipe"); 64689758b77fSLuigi Rizzo 646962ff38aeSLuigi Rizzo preproc = fork(); 647062ff38aeSLuigi Rizzo if (preproc == -1) 64719758b77fSLuigi Rizzo err(EX_OSERR, "cannot fork"); 64729758b77fSLuigi Rizzo 647362ff38aeSLuigi Rizzo if (preproc == 0) { 647462ff38aeSLuigi Rizzo /* 647562ff38aeSLuigi Rizzo * Child, will run the preprocessor with the 647662ff38aeSLuigi Rizzo * file on stdin and the pipe on stdout. 647762ff38aeSLuigi Rizzo */ 64789758b77fSLuigi Rizzo if (dup2(fileno(f), 0) == -1 64799758b77fSLuigi Rizzo || dup2(pipedes[1], 1) == -1) 64809758b77fSLuigi Rizzo err(EX_OSERR, "dup2()"); 64819758b77fSLuigi Rizzo fclose(f); 64829758b77fSLuigi Rizzo close(pipedes[1]); 64839758b77fSLuigi Rizzo close(pipedes[0]); 648462ff38aeSLuigi Rizzo execvp(cmd, av); 64859758b77fSLuigi Rizzo err(EX_OSERR, "execvp(%s) failed", cmd); 648662ff38aeSLuigi Rizzo } else { /* parent, will reopen f as the pipe */ 64879758b77fSLuigi Rizzo fclose(f); 64889758b77fSLuigi Rizzo close(pipedes[1]); 64899758b77fSLuigi Rizzo if ((f = fdopen(pipedes[0], "r")) == NULL) { 64909758b77fSLuigi Rizzo int savederrno = errno; 64919758b77fSLuigi Rizzo 64929758b77fSLuigi Rizzo (void)kill(preproc, SIGTERM); 64939758b77fSLuigi Rizzo errno = savederrno; 64949758b77fSLuigi Rizzo err(EX_OSERR, "fdopen()"); 64959758b77fSLuigi Rizzo } 64969758b77fSLuigi Rizzo } 64979758b77fSLuigi Rizzo } 64989758b77fSLuigi Rizzo 649962ff38aeSLuigi Rizzo while (fgets(buf, BUFSIZ, f)) { /* read commands */ 650062ff38aeSLuigi Rizzo char linename[10]; 6501c5620639SLuigi Rizzo char *args[2]; 650262ff38aeSLuigi Rizzo 65039758b77fSLuigi Rizzo lineno++; 6504571f8c1bSLuigi Rizzo sprintf(linename, "Line %d", lineno); 6505571f8c1bSLuigi Rizzo setprogname(linename); /* XXX */ 65065f356082SLuigi Rizzo args[0] = progname; 6507c5620639SLuigi Rizzo args[1] = buf; 6508c5620639SLuigi Rizzo ipfw_main(2, args); 65099758b77fSLuigi Rizzo } 65109758b77fSLuigi Rizzo fclose(f); 651162ff38aeSLuigi Rizzo if (cmd != NULL) { 651262ff38aeSLuigi Rizzo int status; 651362ff38aeSLuigi Rizzo 65149758b77fSLuigi Rizzo if (waitpid(preproc, &status, 0) == -1) 65159758b77fSLuigi Rizzo errx(EX_OSERR, "waitpid()"); 65169758b77fSLuigi Rizzo if (WIFEXITED(status) && WEXITSTATUS(status) != EX_OK) 65179758b77fSLuigi Rizzo errx(EX_UNAVAILABLE, 65189758b77fSLuigi Rizzo "preprocessor exited with status %d", 65199758b77fSLuigi Rizzo WEXITSTATUS(status)); 65209758b77fSLuigi Rizzo else if (WIFSIGNALED(status)) 65219758b77fSLuigi Rizzo errx(EX_UNAVAILABLE, 65229758b77fSLuigi Rizzo "preprocessor exited with signal %d", 65239758b77fSLuigi Rizzo WTERMSIG(status)); 65249758b77fSLuigi Rizzo } 65259758b77fSLuigi Rizzo } 65269758b77fSLuigi Rizzo 65279758b77fSLuigi Rizzo int 65289758b77fSLuigi Rizzo main(int ac, char *av[]) 65299758b77fSLuigi Rizzo { 65309758b77fSLuigi Rizzo /* 65319758b77fSLuigi Rizzo * If the last argument is an absolute pathname, interpret it 65329758b77fSLuigi Rizzo * as a file to be preprocessed. 65339758b77fSLuigi Rizzo */ 65349758b77fSLuigi Rizzo 65359758b77fSLuigi Rizzo if (ac > 1 && av[ac - 1][0] == '/' && access(av[ac - 1], R_OK) == 0) 65369758b77fSLuigi Rizzo ipfw_readfile(ac, av); 653726bf4d78SLuigi Rizzo else { 6538c5620639SLuigi Rizzo if (ipfw_main(ac, av)) 653926bf4d78SLuigi Rizzo show_usage(); 654026bf4d78SLuigi Rizzo } 65419758b77fSLuigi Rizzo return EX_OK; 65429758b77fSLuigi Rizzo } 6543