198943Sluigi/* 2117328Sluigi * Copyright (c) 2002-2003 Luigi Rizzo 398943Sluigi * Copyright (c) 1996 Alex Nash, Paul Traina, Poul-Henning Kamp 498943Sluigi * Copyright (c) 1994 Ugen J.S.Antsilevich 598943Sluigi * 698943Sluigi * Idea and grammar partially left from: 798943Sluigi * Copyright (c) 1993 Daniel Boulet 898943Sluigi * 998943Sluigi * Redistribution and use in source forms, with and without modification, 1098943Sluigi * are permitted provided that this entire comment appears intact. 1198943Sluigi * 1298943Sluigi * Redistribution in binary form may occur without any restrictions. 1398943Sluigi * Obviously, it would be nice if you gave credit where credit is due 1498943Sluigi * but requiring it would be too onerous. 1598943Sluigi * 1698943Sluigi * This software is provided ``AS IS'' without any warranties of any kind. 1798943Sluigi * 1898943Sluigi * NEW command line interface for IP firewall facility 1998943Sluigi * 2098943Sluigi * $FreeBSD$ 2198943Sluigi */ 2298943Sluigi 23187604Sluigi#include <sys/types.h> 24223262Sbenl#include <sys/param.h> 2598943Sluigi#include <sys/socket.h> 2698943Sluigi#include <sys/sockio.h> 2798943Sluigi#include <sys/sysctl.h> 2898943Sluigi 29187767Sluigi#include "ipfw2.h" 30187767Sluigi 3198943Sluigi#include <ctype.h> 3298943Sluigi#include <err.h> 3398943Sluigi#include <errno.h> 3498943Sluigi#include <grp.h> 3598943Sluigi#include <netdb.h> 3698943Sluigi#include <pwd.h> 3798943Sluigi#include <stdio.h> 3898943Sluigi#include <stdlib.h> 3998943Sluigi#include <string.h> 4098943Sluigi#include <sysexits.h> 41187983Sluigi#include <time.h> /* ctime */ 42187604Sluigi#include <timeconv.h> /* _long_to_time */ 43136071Sgreen#include <unistd.h> 44136071Sgreen#include <fcntl.h> 45234597Smelifaro#include <stddef.h> /* offsetof */ 4698943Sluigi 47169424Smaxim#include <net/ethernet.h> 48187983Sluigi#include <net/if.h> /* only IFNAMSIZ */ 4998943Sluigi#include <netinet/in.h> 50187983Sluigi#include <netinet/in_systm.h> /* only n_short, n_long */ 5198943Sluigi#include <netinet/ip.h> 5298943Sluigi#include <netinet/ip_icmp.h> 5398943Sluigi#include <netinet/ip_fw.h> 5498943Sluigi#include <netinet/tcp.h> 5598943Sluigi#include <arpa/inet.h> 5698943Sluigi 57187767Sluigistruct cmdline_opts co; /* global options */ 5898943Sluigi 59187767Sluigiint resvd_set_number = RESVD_SET; 60187764Sluigi 61234597Smelifaroint ipfw_socket = -1; 62234597Smelifaro 63265699Smelifarouint32_t ipfw_tables_max = 0; /* Number of tables supported by kernel */ 64265699Smelifaro 65234597Smelifaro#ifndef s6_addr32 66234597Smelifaro#define s6_addr32 __u6_addr.__u6_addr32 67234597Smelifaro#endif 68234597Smelifaro 69248505Smelifaro#define CHECK_LENGTH(v, len) do { \ 70248505Smelifaro if ((v) < (len)) \ 71248505Smelifaro errx(EX_DATAERR, "Rule too long"); \ 72248505Smelifaro } while (0) 73248505Smelifaro/* 74248505Smelifaro * Check if we have enough space in cmd buffer. Note that since 75248505Smelifaro * first 8? u32 words are reserved by reserved header, full cmd 76248505Smelifaro * buffer can't be used, so we need to protect from buffer overrun 77248505Smelifaro * only. At the beginnig, cblen is less than actual buffer size by 78248505Smelifaro * size of ipfw_insn_u32 instruction + 1 u32 work. This eliminates need 79248505Smelifaro * for checking small instructions fitting in given range. 80248505Smelifaro * We also (ab)use the fact that ipfw_insn is always the first field 81248505Smelifaro * for any custom instruction. 82248505Smelifaro */ 83248505Smelifaro#define CHECK_CMDLEN CHECK_LENGTH(cblen, F_LEN((ipfw_insn *)cmd)) 84248505Smelifaro 85159636Soleg#define GET_UINT_ARG(arg, min, max, tok, s_x) do { \ 86204591Sluigi if (!av[0]) \ 87159636Soleg errx(EX_USAGE, "%s: missing argument", match_value(s_x, tok)); \ 88159636Soleg if (_substrcmp(*av, "tablearg") == 0) { \ 89159636Soleg arg = IP_FW_TABLEARG; \ 90159636Soleg break; \ 91159636Soleg } \ 92159636Soleg \ 93159636Soleg { \ 94204591Sluigi long _xval; \ 95159636Soleg char *end; \ 96159636Soleg \ 97204591Sluigi _xval = strtol(*av, &end, 10); \ 98159636Soleg \ 99204591Sluigi if (!isdigit(**av) || *end != '\0' || (_xval == 0 && errno == EINVAL)) \ 100159636Soleg errx(EX_DATAERR, "%s: invalid argument: %s", \ 101159636Soleg match_value(s_x, tok), *av); \ 102159636Soleg \ 103204591Sluigi if (errno == ERANGE || _xval < min || _xval > max) \ 104159636Soleg errx(EX_DATAERR, "%s: argument is out of range (%u..%u): %s", \ 105159636Soleg match_value(s_x, tok), min, max, *av); \ 106159636Soleg \ 107204591Sluigi if (_xval == IP_FW_TABLEARG) \ 108159636Soleg errx(EX_DATAERR, "%s: illegal argument value: %s", \ 109159636Soleg match_value(s_x, tok), *av); \ 110204591Sluigi arg = _xval; \ 111159636Soleg } \ 112158879Soleg} while (0) 113158879Soleg 114187762Sluigistatic void 115187762SluigiPRINT_UINT_ARG(const char *str, uint32_t arg) 116187762Sluigi{ 117187762Sluigi if (str != NULL) 118187762Sluigi printf("%s",str); 119187762Sluigi if (arg == IP_FW_TABLEARG) 120187762Sluigi printf("tablearg"); 121187762Sluigi else 122187762Sluigi printf("%u", arg); 123187762Sluigi} 124159636Soleg 12598943Sluigistatic struct _s_x f_tcpflags[] = { 12698943Sluigi { "syn", TH_SYN }, 12798943Sluigi { "fin", TH_FIN }, 12898943Sluigi { "ack", TH_ACK }, 12998943Sluigi { "psh", TH_PUSH }, 13098943Sluigi { "rst", TH_RST }, 13198943Sluigi { "urg", TH_URG }, 13298943Sluigi { "tcp flag", 0 }, 13398943Sluigi { NULL, 0 } 13498943Sluigi}; 13598943Sluigi 13698943Sluigistatic struct _s_x f_tcpopts[] = { 13798943Sluigi { "mss", IP_FW_TCPOPT_MSS }, 13898943Sluigi { "maxseg", IP_FW_TCPOPT_MSS }, 13998943Sluigi { "window", IP_FW_TCPOPT_WINDOW }, 14098943Sluigi { "sack", IP_FW_TCPOPT_SACK }, 14198943Sluigi { "ts", IP_FW_TCPOPT_TS }, 14298943Sluigi { "timestamp", IP_FW_TCPOPT_TS }, 14398943Sluigi { "cc", IP_FW_TCPOPT_CC }, 14498943Sluigi { "tcp option", 0 }, 14598943Sluigi { NULL, 0 } 14698943Sluigi}; 14798943Sluigi 14898943Sluigi/* 14998943Sluigi * IP options span the range 0 to 255 so we need to remap them 15098943Sluigi * (though in fact only the low 5 bits are significant). 15198943Sluigi */ 15298943Sluigistatic struct _s_x f_ipopts[] = { 15398943Sluigi { "ssrr", IP_FW_IPOPT_SSRR}, 15498943Sluigi { "lsrr", IP_FW_IPOPT_LSRR}, 15598943Sluigi { "rr", IP_FW_IPOPT_RR}, 15698943Sluigi { "ts", IP_FW_IPOPT_TS}, 15798943Sluigi { "ip option", 0 }, 15898943Sluigi { NULL, 0 } 15998943Sluigi}; 16098943Sluigi 16198943Sluigistatic struct _s_x f_iptos[] = { 16298943Sluigi { "lowdelay", IPTOS_LOWDELAY}, 16398943Sluigi { "throughput", IPTOS_THROUGHPUT}, 16498943Sluigi { "reliability", IPTOS_RELIABILITY}, 16598943Sluigi { "mincost", IPTOS_MINCOST}, 166172801Srpaulo { "congestion", IPTOS_ECN_CE}, 167172801Srpaulo { "ecntransport", IPTOS_ECN_ECT0}, 16898943Sluigi { "ip tos option", 0}, 16998943Sluigi { NULL, 0 } 17098943Sluigi}; 17198943Sluigi 172250762Smelifarostatic struct _s_x f_ipdscp[] = { 173250762Smelifaro { "af11", IPTOS_DSCP_AF11 >> 2 }, /* 001010 */ 174250762Smelifaro { "af12", IPTOS_DSCP_AF12 >> 2 }, /* 001100 */ 175250762Smelifaro { "af13", IPTOS_DSCP_AF13 >> 2 }, /* 001110 */ 176250762Smelifaro { "af21", IPTOS_DSCP_AF21 >> 2 }, /* 010010 */ 177250762Smelifaro { "af22", IPTOS_DSCP_AF22 >> 2 }, /* 010100 */ 178250762Smelifaro { "af23", IPTOS_DSCP_AF23 >> 2 }, /* 010110 */ 179250762Smelifaro { "af31", IPTOS_DSCP_AF31 >> 2 }, /* 011010 */ 180250762Smelifaro { "af32", IPTOS_DSCP_AF32 >> 2 }, /* 011100 */ 181250762Smelifaro { "af33", IPTOS_DSCP_AF33 >> 2 }, /* 011110 */ 182250762Smelifaro { "af41", IPTOS_DSCP_AF41 >> 2 }, /* 100010 */ 183250762Smelifaro { "af42", IPTOS_DSCP_AF42 >> 2 }, /* 100100 */ 184250762Smelifaro { "af43", IPTOS_DSCP_AF43 >> 2 }, /* 100110 */ 185250762Smelifaro { "be", IPTOS_DSCP_CS0 >> 2 }, /* 000000 */ 186250762Smelifaro { "ef", IPTOS_DSCP_EF >> 2 }, /* 101110 */ 187250762Smelifaro { "cs0", IPTOS_DSCP_CS0 >> 2 }, /* 000000 */ 188250762Smelifaro { "cs1", IPTOS_DSCP_CS1 >> 2 }, /* 001000 */ 189250762Smelifaro { "cs2", IPTOS_DSCP_CS2 >> 2 }, /* 010000 */ 190250762Smelifaro { "cs3", IPTOS_DSCP_CS3 >> 2 }, /* 011000 */ 191250762Smelifaro { "cs4", IPTOS_DSCP_CS4 >> 2 }, /* 100000 */ 192250762Smelifaro { "cs5", IPTOS_DSCP_CS5 >> 2 }, /* 101000 */ 193250762Smelifaro { "cs6", IPTOS_DSCP_CS6 >> 2 }, /* 110000 */ 194250762Smelifaro { "cs7", IPTOS_DSCP_CS7 >> 2 }, /* 100000 */ 195250762Smelifaro { NULL, 0 } 196250762Smelifaro}; 197250762Smelifaro 19898943Sluigistatic struct _s_x limit_masks[] = { 19998943Sluigi {"all", DYN_SRC_ADDR|DYN_SRC_PORT|DYN_DST_ADDR|DYN_DST_PORT}, 20098943Sluigi {"src-addr", DYN_SRC_ADDR}, 20198943Sluigi {"src-port", DYN_SRC_PORT}, 20298943Sluigi {"dst-addr", DYN_DST_ADDR}, 20398943Sluigi {"dst-port", DYN_DST_PORT}, 20498943Sluigi {NULL, 0} 20598943Sluigi}; 20698943Sluigi 20798943Sluigi/* 20898943Sluigi * we use IPPROTO_ETHERTYPE as a fake protocol id to call the print routines 20998943Sluigi * This is only used in this code. 21098943Sluigi */ 21198943Sluigi#define IPPROTO_ETHERTYPE 0x1000 21298943Sluigistatic struct _s_x ether_types[] = { 21398943Sluigi /* 21498943Sluigi * Note, we cannot use "-:&/" in the names because they are field 21598943Sluigi * separators in the type specifications. Also, we use s = NULL as 21698943Sluigi * end-delimiter, because a type of 0 can be legal. 21798943Sluigi */ 21898943Sluigi { "ip", 0x0800 }, 21998943Sluigi { "ipv4", 0x0800 }, 22098943Sluigi { "ipv6", 0x86dd }, 22198943Sluigi { "arp", 0x0806 }, 22298943Sluigi { "rarp", 0x8035 }, 22398943Sluigi { "vlan", 0x8100 }, 22498943Sluigi { "loop", 0x9000 }, 22598943Sluigi { "trail", 0x1000 }, 22698943Sluigi { "at", 0x809b }, 22798943Sluigi { "atalk", 0x809b }, 22898943Sluigi { "aarp", 0x80f3 }, 22998943Sluigi { "pppoe_disc", 0x8863 }, 23098943Sluigi { "pppoe_sess", 0x8864 }, 23198943Sluigi { "ipx_8022", 0x00E0 }, 23298943Sluigi { "ipx_8023", 0x0000 }, 23398943Sluigi { "ipx_ii", 0x8137 }, 23498943Sluigi { "ipx_snap", 0x8137 }, 23598943Sluigi { "ipx", 0x8137 }, 23698943Sluigi { "ns", 0x0600 }, 23798943Sluigi { NULL, 0 } 23898943Sluigi}; 23998943Sluigi 24098943Sluigi 241187769Sluigistatic struct _s_x rule_actions[] = { 24298943Sluigi { "accept", TOK_ACCEPT }, 24398943Sluigi { "pass", TOK_ACCEPT }, 24498943Sluigi { "allow", TOK_ACCEPT }, 24598943Sluigi { "permit", TOK_ACCEPT }, 24698943Sluigi { "count", TOK_COUNT }, 24798943Sluigi { "pipe", TOK_PIPE }, 24898943Sluigi { "queue", TOK_QUEUE }, 24998943Sluigi { "divert", TOK_DIVERT }, 25098943Sluigi { "tee", TOK_TEE }, 251141351Sglebius { "netgraph", TOK_NETGRAPH }, 252141351Sglebius { "ngtee", TOK_NGTEE }, 25398943Sluigi { "fwd", TOK_FORWARD }, 25498943Sluigi { "forward", TOK_FORWARD }, 25598943Sluigi { "skipto", TOK_SKIPTO }, 25698943Sluigi { "deny", TOK_DENY }, 25798943Sluigi { "drop", TOK_DENY }, 25898943Sluigi { "reject", TOK_REJECT }, 259149020Sbz { "reset6", TOK_RESET6 }, 26098943Sluigi { "reset", TOK_RESET }, 261149020Sbz { "unreach6", TOK_UNREACH6 }, 26299475Sluigi { "unreach", TOK_UNREACH }, 26398943Sluigi { "check-state", TOK_CHECKSTATE }, 264117469Sluigi { "//", TOK_COMMENT }, 265220802Sglebius { "nat", TOK_NAT }, 266190633Spiso { "reass", TOK_REASS }, 267178888Sjulian { "setfib", TOK_SETFIB }, 268250762Smelifaro { "setdscp", TOK_SETDSCP }, 269223666Sae { "call", TOK_CALL }, 270223666Sae { "return", TOK_RETURN }, 271117328Sluigi { NULL, 0 } /* terminator */ 27298943Sluigi}; 27398943Sluigi 274187769Sluigistatic struct _s_x rule_action_params[] = { 275136071Sgreen { "altq", TOK_ALTQ }, 276136071Sgreen { "log", TOK_LOG }, 277158879Soleg { "tag", TOK_TAG }, 278158879Soleg { "untag", TOK_UNTAG }, 279136071Sgreen { NULL, 0 } /* terminator */ 280136071Sgreen}; 281136071Sgreen 282200567Sluigi/* 283200567Sluigi * The 'lookup' instruction accepts one of the following arguments. 284200567Sluigi * -1 is a terminator for the list. 285200567Sluigi * Arguments are passed as v[1] in O_DST_LOOKUP options. 286200567Sluigi */ 287200567Sluigistatic int lookup_key[] = { 288200567Sluigi TOK_DSTIP, TOK_SRCIP, TOK_DSTPORT, TOK_SRCPORT, 289205169Sluigi TOK_UID, TOK_JAIL, TOK_DSCP, -1 }; 290200567Sluigi 291187769Sluigistatic struct _s_x rule_options[] = { 292158879Soleg { "tagged", TOK_TAGGED }, 29398943Sluigi { "uid", TOK_UID }, 29498943Sluigi { "gid", TOK_GID }, 295133600Scsjp { "jail", TOK_JAIL }, 29698943Sluigi { "in", TOK_IN }, 29798943Sluigi { "limit", TOK_LIMIT }, 29898943Sluigi { "keep-state", TOK_KEEPSTATE }, 29998943Sluigi { "bridged", TOK_LAYER2 }, 30098943Sluigi { "layer2", TOK_LAYER2 }, 30198943Sluigi { "out", TOK_OUT }, 302136073Sgreen { "diverted", TOK_DIVERTED }, 303136073Sgreen { "diverted-loopback", TOK_DIVERTEDLOOPBACK }, 304136073Sgreen { "diverted-output", TOK_DIVERTEDOUTPUT }, 30598943Sluigi { "xmit", TOK_XMIT }, 30698943Sluigi { "recv", TOK_RECV }, 30798943Sluigi { "via", TOK_VIA }, 30898943Sluigi { "fragment", TOK_FRAG }, 30998943Sluigi { "frag", TOK_FRAG }, 310178888Sjulian { "fib", TOK_FIB }, 31198943Sluigi { "ipoptions", TOK_IPOPTS }, 31298943Sluigi { "ipopts", TOK_IPOPTS }, 31398943Sluigi { "iplen", TOK_IPLEN }, 31498943Sluigi { "ipid", TOK_IPID }, 31598943Sluigi { "ipprecedence", TOK_IPPRECEDENCE }, 316205169Sluigi { "dscp", TOK_DSCP }, 31798943Sluigi { "iptos", TOK_IPTOS }, 31898943Sluigi { "ipttl", TOK_IPTTL }, 31998943Sluigi { "ipversion", TOK_IPVER }, 32098943Sluigi { "ipver", TOK_IPVER }, 32198943Sluigi { "estab", TOK_ESTAB }, 32298943Sluigi { "established", TOK_ESTAB }, 32398943Sluigi { "setup", TOK_SETUP }, 324215179Sluigi { "sockarg", TOK_SOCKARG }, 325136075Sgreen { "tcpdatalen", TOK_TCPDATALEN }, 32698943Sluigi { "tcpflags", TOK_TCPFLAGS }, 32798943Sluigi { "tcpflgs", TOK_TCPFLAGS }, 32898943Sluigi { "tcpoptions", TOK_TCPOPTS }, 32998943Sluigi { "tcpopts", TOK_TCPOPTS }, 33098943Sluigi { "tcpseq", TOK_TCPSEQ }, 33198943Sluigi { "tcpack", TOK_TCPACK }, 33298943Sluigi { "tcpwin", TOK_TCPWIN }, 33399909Sluigi { "icmptype", TOK_ICMPTYPES }, 33498943Sluigi { "icmptypes", TOK_ICMPTYPES }, 335102087Sluigi { "dst-ip", TOK_DSTIP }, 336102087Sluigi { "src-ip", TOK_SRCIP }, 337102087Sluigi { "dst-port", TOK_DSTPORT }, 338102087Sluigi { "src-port", TOK_SRCPORT }, 339102087Sluigi { "proto", TOK_PROTO }, 340102087Sluigi { "MAC", TOK_MAC }, 341102087Sluigi { "mac", TOK_MAC }, 342102087Sluigi { "mac-type", TOK_MACTYPE }, 343112250Scjc { "verrevpath", TOK_VERREVPATH }, 344128575Sandre { "versrcreach", TOK_VERSRCREACH }, 345133387Sandre { "antispoof", TOK_ANTISPOOF }, 346117241Sluigi { "ipsec", TOK_IPSEC }, 347145246Sbrooks { "icmp6type", TOK_ICMP6TYPES }, 348145246Sbrooks { "icmp6types", TOK_ICMP6TYPES }, 349145246Sbrooks { "ext6hdr", TOK_EXT6HDR}, 350145246Sbrooks { "flow-id", TOK_FLOWID}, 351145246Sbrooks { "ipv6", TOK_IPV6}, 352145246Sbrooks { "ip6", TOK_IPV6}, 353146894Smlaier { "ipv4", TOK_IPV4}, 354146894Smlaier { "ip4", TOK_IPV4}, 355145246Sbrooks { "dst-ipv6", TOK_DSTIP6}, 356145246Sbrooks { "dst-ip6", TOK_DSTIP6}, 357145246Sbrooks { "src-ipv6", TOK_SRCIP6}, 358145246Sbrooks { "src-ip6", TOK_SRCIP6}, 359200567Sluigi { "lookup", TOK_LOOKUP}, 360117469Sluigi { "//", TOK_COMMENT }, 36198943Sluigi 36298943Sluigi { "not", TOK_NOT }, /* pseudo option */ 36398943Sluigi { "!", /* escape ? */ TOK_NOT }, /* pseudo option */ 36498943Sluigi { "or", TOK_OR }, /* pseudo option */ 36598943Sluigi { "|", /* escape */ TOK_OR }, /* pseudo option */ 366101641Sluigi { "{", TOK_STARTBRACE }, /* pseudo option */ 367101641Sluigi { "(", TOK_STARTBRACE }, /* pseudo option */ 368101641Sluigi { "}", TOK_ENDBRACE }, /* pseudo option */ 369101641Sluigi { ")", TOK_ENDBRACE }, /* pseudo option */ 370117328Sluigi { NULL, 0 } /* terminator */ 37198943Sluigi}; 37298943Sluigi 373206843Sluigi/* 374206843Sluigi * Helper routine to print a possibly unaligned uint64_t on 375206843Sluigi * various platform. If width > 0, print the value with 376206843Sluigi * the desired width, followed by a space; 377206843Sluigi * otherwise, return the required width. 378187787Sluigi */ 379206843Sluigiint 380206843Sluigipr_u64(uint64_t *pd, int width) 381187787Sluigi{ 382206843Sluigi#ifdef TCC 383206843Sluigi#define U64_FMT "I64" 384206843Sluigi#else 385206843Sluigi#define U64_FMT "llu" 386206843Sluigi#endif 387206846Sluigi uint64_t u; 388206846Sluigi unsigned long long d; 389115793Sticso 390206846Sluigi bcopy (pd, &u, sizeof(u)); 391206846Sluigi d = u; 392206843Sluigi return (width > 0) ? 393206843Sluigi printf("%*" U64_FMT " ", width, d) : 394206843Sluigi snprintf(NULL, 0, "%" U64_FMT, d) ; 395206843Sluigi#undef U64_FMT 396129389Sstefanf} 397115793Sticso 398187767Sluigivoid * 399187716Sluigisafe_calloc(size_t number, size_t size) 400187716Sluigi{ 401187716Sluigi void *ret = calloc(number, size); 402187716Sluigi 403187716Sluigi if (ret == NULL) 404187716Sluigi err(EX_OSERR, "calloc"); 405187716Sluigi return ret; 406187716Sluigi} 407187716Sluigi 408187767Sluigivoid * 409187716Sluigisafe_realloc(void *ptr, size_t size) 410187716Sluigi{ 411187716Sluigi void *ret = realloc(ptr, size); 412187716Sluigi 413187716Sluigi if (ret == NULL) 414187716Sluigi err(EX_OSERR, "realloc"); 415187716Sluigi return ret; 416187716Sluigi} 417187716Sluigi 418117328Sluigi/* 419117328Sluigi * conditionally runs the command. 420204591Sluigi * Selected options or negative -> getsockopt 421117328Sluigi */ 422187769Sluigiint 423119740Stmmdo_cmd(int optname, void *optval, uintptr_t optlen) 424117328Sluigi{ 425117328Sluigi int i; 426117577Sluigi 427187764Sluigi if (co.test_only) 428117328Sluigi return 0; 429117328Sluigi 430234597Smelifaro if (ipfw_socket == -1) 431234597Smelifaro ipfw_socket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); 432234597Smelifaro if (ipfw_socket < 0) 433117328Sluigi err(EX_UNAVAILABLE, "socket"); 434117328Sluigi 435117328Sluigi if (optname == IP_FW_GET || optname == IP_DUMMYNET_GET || 436234597Smelifaro optname == IP_FW_ADD || optname == IP_FW3 || 437220802Sglebius optname == IP_FW_NAT_GET_CONFIG || 438204591Sluigi optname < 0 || 439204591Sluigi optname == IP_FW_NAT_GET_LOG) { 440204591Sluigi if (optname < 0) 441204591Sluigi optname = -optname; 442234597Smelifaro i = getsockopt(ipfw_socket, IPPROTO_IP, optname, optval, 443117328Sluigi (socklen_t *)optlen); 444204591Sluigi } else { 445234597Smelifaro i = setsockopt(ipfw_socket, IPPROTO_IP, optname, optval, optlen); 446204591Sluigi } 447117328Sluigi return i; 448117328Sluigi} 449117328Sluigi 450234597Smelifaro/* 451234597Smelifaro * do_setcmd3 - pass ipfw control cmd to kernel 452234597Smelifaro * @optname: option name 453234597Smelifaro * @optval: pointer to option data 454234597Smelifaro * @optlen: option length 455234597Smelifaro * 456234597Smelifaro * Function encapsulates option value in IP_FW3 socket option 457234597Smelifaro * and calls setsockopt(). 458234597Smelifaro * Function returns 0 on success or -1 otherwise. 459234597Smelifaro */ 460234597Smelifaroint 461234597Smelifarodo_setcmd3(int optname, void *optval, socklen_t optlen) 462234597Smelifaro{ 463234597Smelifaro socklen_t len; 464234597Smelifaro ip_fw3_opheader *op3; 465234597Smelifaro 466234597Smelifaro if (co.test_only) 467234597Smelifaro return (0); 468234597Smelifaro 469234597Smelifaro if (ipfw_socket == -1) 470234597Smelifaro ipfw_socket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); 471234597Smelifaro if (ipfw_socket < 0) 472234597Smelifaro err(EX_UNAVAILABLE, "socket"); 473234597Smelifaro 474234597Smelifaro len = sizeof(ip_fw3_opheader) + optlen; 475234597Smelifaro op3 = alloca(len); 476234597Smelifaro /* Zero reserved fields */ 477234597Smelifaro memset(op3, 0, sizeof(ip_fw3_opheader)); 478234597Smelifaro memcpy(op3 + 1, optval, optlen); 479234597Smelifaro op3->opcode = optname; 480234597Smelifaro 481234597Smelifaro return setsockopt(ipfw_socket, IPPROTO_IP, IP_FW3, op3, len); 482234597Smelifaro} 483234597Smelifaro 48498943Sluigi/** 48598943Sluigi * match_token takes a table and a string, returns the value associated 486117328Sluigi * with the string (-1 in case of failure). 48798943Sluigi */ 488187769Sluigiint 48998943Sluigimatch_token(struct _s_x *table, char *string) 49098943Sluigi{ 49198943Sluigi struct _s_x *pt; 492117469Sluigi uint i = strlen(string); 49398943Sluigi 49498943Sluigi for (pt = table ; i && pt->s != NULL ; pt++) 49598943Sluigi if (strlen(pt->s) == i && !bcmp(string, pt->s, i)) 49698943Sluigi return pt->x; 49798943Sluigi return -1; 498129389Sstefanf} 49998943Sluigi 500117328Sluigi/** 501117328Sluigi * match_value takes a table and a value, returns the string associated 502117328Sluigi * with the value (NULL in case of failure). 503117328Sluigi */ 504187770Sluigichar const * 505117469Sluigimatch_value(struct _s_x *p, int value) 50698943Sluigi{ 50798943Sluigi for (; p->s != NULL; p++) 50898943Sluigi if (p->x == value) 50998943Sluigi return p->s; 51098943Sluigi return NULL; 51198943Sluigi} 51298943Sluigi 51398943Sluigi/* 514140271Sbrooks * _substrcmp takes two strings and returns 1 if they do not match, 515140271Sbrooks * and 0 if they match exactly or the first string is a sub-string 516140271Sbrooks * of the second. A warning is printed to stderr in the case that the 517140271Sbrooks * first string is a sub-string of the second. 518140271Sbrooks * 519140271Sbrooks * This function will be removed in the future through the usual 520140271Sbrooks * deprecation process. 521140271Sbrooks */ 522187767Sluigiint 523140271Sbrooks_substrcmp(const char *str1, const char* str2) 524140271Sbrooks{ 525220804Sglebius 526140271Sbrooks if (strncmp(str1, str2, strlen(str1)) != 0) 527140271Sbrooks return 1; 528140271Sbrooks 529140271Sbrooks if (strlen(str1) != strlen(str2)) 530140271Sbrooks warnx("DEPRECATED: '%s' matched '%s' as a sub-string", 531140271Sbrooks str1, str2); 532140271Sbrooks return 0; 533140271Sbrooks} 534140271Sbrooks 535140271Sbrooks/* 536140271Sbrooks * _substrcmp2 takes three strings and returns 1 if the first two do not match, 537140271Sbrooks * and 0 if they match exactly or the second string is a sub-string 538140271Sbrooks * of the first. A warning is printed to stderr in the case that the 539140271Sbrooks * first string does not match the third. 540140271Sbrooks * 541140271Sbrooks * This function exists to warn about the bizzare construction 542140271Sbrooks * strncmp(str, "by", 2) which is used to allow people to use a shotcut 543140271Sbrooks * for "bytes". The problem is that in addition to accepting "by", 544140271Sbrooks * "byt", "byte", and "bytes", it also excepts "by_rabid_dogs" and any 545140271Sbrooks * other string beginning with "by". 546140271Sbrooks * 547140271Sbrooks * This function will be removed in the future through the usual 548140271Sbrooks * deprecation process. 549140271Sbrooks */ 550187769Sluigiint 551140271Sbrooks_substrcmp2(const char *str1, const char* str2, const char* str3) 552140271Sbrooks{ 553220804Sglebius 554140271Sbrooks if (strncmp(str1, str2, strlen(str2)) != 0) 555140271Sbrooks return 1; 556140271Sbrooks 557140271Sbrooks if (strcmp(str1, str3) != 0) 558140271Sbrooks warnx("DEPRECATED: '%s' matched '%s'", 559140271Sbrooks str1, str3); 560140271Sbrooks return 0; 561140271Sbrooks} 562140271Sbrooks 563140271Sbrooks/* 56498943Sluigi * prints one port, symbolic or numeric 56598943Sluigi */ 56698943Sluigistatic void 567117328Sluigiprint_port(int proto, uint16_t port) 56898943Sluigi{ 56998943Sluigi 57098943Sluigi if (proto == IPPROTO_ETHERTYPE) { 571117469Sluigi char const *s; 57298943Sluigi 573187764Sluigi if (co.do_resolv && (s = match_value(ether_types, port)) ) 57498943Sluigi printf("%s", s); 57598943Sluigi else 57698943Sluigi printf("0x%04x", port); 57798943Sluigi } else { 57898943Sluigi struct servent *se = NULL; 579187764Sluigi if (co.do_resolv) { 58098943Sluigi struct protoent *pe = getprotobynumber(proto); 58198943Sluigi 58298943Sluigi se = getservbyport(htons(port), pe ? pe->p_name : NULL); 58398943Sluigi } 58498943Sluigi if (se) 58598943Sluigi printf("%s", se->s_name); 58698943Sluigi else 58798943Sluigi printf("%d", port); 58898943Sluigi } 58998943Sluigi} 59098943Sluigi 591187769Sluigistatic struct _s_x _port_name[] = { 592117328Sluigi {"dst-port", O_IP_DSTPORT}, 593117328Sluigi {"src-port", O_IP_SRCPORT}, 594117328Sluigi {"ipid", O_IPID}, 595117328Sluigi {"iplen", O_IPLEN}, 596117328Sluigi {"ipttl", O_IPTTL}, 597117328Sluigi {"mac-type", O_MAC_TYPE}, 598136075Sgreen {"tcpdatalen", O_TCPDATALEN}, 599234278Sglebius {"tcpwin", O_TCPWIN}, 600158879Soleg {"tagged", O_TAGGED}, 601117328Sluigi {NULL, 0} 602117328Sluigi}; 603117328Sluigi 60498943Sluigi/* 605117328Sluigi * Print the values in a list 16-bit items of the types above. 60698943Sluigi * XXX todo: add support for mask. 60798943Sluigi */ 60898943Sluigistatic void 609102087Sluigiprint_newports(ipfw_insn_u16 *cmd, int proto, int opcode) 61098943Sluigi{ 611117328Sluigi uint16_t *p = cmd->ports; 61298943Sluigi int i; 613117469Sluigi char const *sep; 61498943Sluigi 615116690Sluigi if (opcode != 0) { 616117328Sluigi sep = match_value(_port_name, opcode); 617117328Sluigi if (sep == NULL) 618116690Sluigi sep = "???"; 619116690Sluigi printf (" %s", sep); 620116690Sluigi } 621116690Sluigi sep = " "; 62298943Sluigi for (i = F_LEN((ipfw_insn *)cmd) - 1; i > 0; i--, p += 2) { 623193702Sluigi printf("%s", sep); 62498943Sluigi print_port(proto, p[0]); 62598943Sluigi if (p[0] != p[1]) { 62698943Sluigi printf("-"); 62798943Sluigi print_port(proto, p[1]); 62898943Sluigi } 62998943Sluigi sep = ","; 63098943Sluigi } 63198943Sluigi} 63298943Sluigi 63398943Sluigi/* 63498943Sluigi * Like strtol, but also translates service names into port numbers 63598943Sluigi * for some protocols. 63698943Sluigi * In particular: 63798943Sluigi * proto == -1 disables the protocol check; 63898943Sluigi * proto == IPPROTO_ETHERTYPE looks up an internal table 63998943Sluigi * proto == <some value in /etc/protocols> matches the values there. 640101628Sluigi * Returns *end == s in case the parameter is not found. 64198943Sluigi */ 64298943Sluigistatic int 64398943Sluigistrtoport(char *s, char **end, int base, int proto) 64498943Sluigi{ 645101628Sluigi char *p, *buf; 646101628Sluigi char *s1; 64798943Sluigi int i; 64898943Sluigi 649101628Sluigi *end = s; /* default - not found */ 650117577Sluigi if (*s == '\0') 651101628Sluigi return 0; /* not found */ 652106505Smaxim 65398943Sluigi if (isdigit(*s)) 65498943Sluigi return strtol(s, end, base); 65598943Sluigi 65698943Sluigi /* 657101628Sluigi * find separator. '\\' escapes the next char. 65898943Sluigi */ 659101628Sluigi for (s1 = s; *s1 && (isalnum(*s1) || *s1 == '\\') ; s1++) 660101628Sluigi if (*s1 == '\\' && s1[1] != '\0') 661101628Sluigi s1++; 66298943Sluigi 663187716Sluigi buf = safe_calloc(s1 - s + 1, 1); 664101628Sluigi 665101628Sluigi /* 666101628Sluigi * copy into a buffer skipping backslashes 667101628Sluigi */ 668101628Sluigi for (p = s, i = 0; p != s1 ; p++) 669117577Sluigi if (*p != '\\') 670101628Sluigi buf[i++] = *p; 671101628Sluigi buf[i++] = '\0'; 672101628Sluigi 67398943Sluigi if (proto == IPPROTO_ETHERTYPE) { 674101628Sluigi i = match_token(ether_types, buf); 675101628Sluigi free(buf); 676101628Sluigi if (i != -1) { /* found */ 67798943Sluigi *end = s1; 67898943Sluigi return i; 67998943Sluigi } 68098943Sluigi } else { 68198943Sluigi struct protoent *pe = NULL; 68298943Sluigi struct servent *se; 68398943Sluigi 68498943Sluigi if (proto != 0) 68598943Sluigi pe = getprotobynumber(proto); 68698943Sluigi setservent(1); 687101628Sluigi se = getservbyname(buf, pe ? pe->p_name : NULL); 688101628Sluigi free(buf); 68998943Sluigi if (se != NULL) { 69098943Sluigi *end = s1; 69198943Sluigi return ntohs(se->s_port); 69298943Sluigi } 69398943Sluigi } 694101628Sluigi return 0; /* not found */ 69598943Sluigi} 69698943Sluigi 69798943Sluigi/* 698117328Sluigi * Fill the body of the command with the list of port ranges. 69998943Sluigi */ 70098943Sluigistatic int 701248505Smelifarofill_newports(ipfw_insn_u16 *cmd, char *av, int proto, int cblen) 70298943Sluigi{ 703117328Sluigi uint16_t a, b, *p = cmd->ports; 70498943Sluigi int i = 0; 705102087Sluigi char *s = av; 70698943Sluigi 707102087Sluigi while (*s) { 70898943Sluigi a = strtoport(av, &s, 0, proto); 709159636Soleg if (s == av) /* empty or invalid argument */ 710159636Soleg return (0); 711159636Soleg 712248505Smelifaro CHECK_LENGTH(cblen, i + 2); 713248505Smelifaro 714159636Soleg switch (*s) { 715159636Soleg case '-': /* a range */ 716159636Soleg av = s + 1; 71798943Sluigi b = strtoport(av, &s, 0, proto); 718159636Soleg /* Reject expressions like '1-abc' or '1-2-3'. */ 719159636Soleg if (s == av || (*s != ',' && *s != '\0')) 720159636Soleg return (0); 72198943Sluigi p[0] = a; 72298943Sluigi p[1] = b; 723159636Soleg break; 724159636Soleg case ',': /* comma separated list */ 725159636Soleg case '\0': 72698943Sluigi p[0] = p[1] = a; 727159636Soleg break; 728159636Soleg default: 729159636Soleg warnx("port list: invalid separator <%c> in <%s>", 730101978Sluigi *s, av); 731159636Soleg return (0); 732159636Soleg } 733159636Soleg 734102087Sluigi i++; 735102087Sluigi p += 2; 736159636Soleg av = s + 1; 73798943Sluigi } 73898943Sluigi if (i > 0) { 739159636Soleg if (i + 1 > F_LEN_MASK) 740102087Sluigi errx(EX_DATAERR, "too many ports/ranges\n"); 741159636Soleg cmd->o.len |= i + 1; /* leave F_NOT and F_OR untouched */ 74298943Sluigi } 743159636Soleg return (i); 74498943Sluigi} 74598943Sluigi 746250762Smelifaro/* 747250762Smelifaro * Fill the body of the command with the list of DiffServ codepoints. 748250762Smelifaro */ 749250762Smelifarostatic void 750250762Smelifarofill_dscp(ipfw_insn *cmd, char *av, int cblen) 751250762Smelifaro{ 752250762Smelifaro uint32_t *low, *high; 753250762Smelifaro char *s = av, *a; 754250762Smelifaro int code; 755250762Smelifaro 756250762Smelifaro cmd->opcode = O_DSCP; 757250762Smelifaro cmd->len |= F_INSN_SIZE(ipfw_insn_u32) + 1; 758250762Smelifaro 759250762Smelifaro CHECK_CMDLEN; 760250762Smelifaro 761250762Smelifaro low = (uint32_t *)(cmd + 1); 762250762Smelifaro high = low + 1; 763250762Smelifaro 764250762Smelifaro *low = 0; 765250762Smelifaro *high = 0; 766250762Smelifaro 767250762Smelifaro while (s != NULL) { 768250762Smelifaro a = strchr(s, ','); 769250762Smelifaro 770250762Smelifaro if (a != NULL) 771250762Smelifaro *a++ = '\0'; 772250762Smelifaro 773250762Smelifaro if (isalpha(*s)) { 774250762Smelifaro if ((code = match_token(f_ipdscp, s)) == -1) 775250762Smelifaro errx(EX_DATAERR, "Unknown DSCP code"); 776250762Smelifaro } else { 777250762Smelifaro code = strtoul(s, NULL, 10); 778250762Smelifaro if (code < 0 || code > 63) 779250762Smelifaro errx(EX_DATAERR, "Invalid DSCP value"); 780250762Smelifaro } 781250762Smelifaro 782250762Smelifaro if (code > 32) 783250762Smelifaro *high |= 1 << (code - 32); 784250762Smelifaro else 785250762Smelifaro *low |= 1 << code; 786250762Smelifaro 787250762Smelifaro s = a; 788250762Smelifaro } 789250762Smelifaro} 790250762Smelifaro 79198943Sluigistatic struct _s_x icmpcodes[] = { 79298943Sluigi { "net", ICMP_UNREACH_NET }, 79398943Sluigi { "host", ICMP_UNREACH_HOST }, 79498943Sluigi { "protocol", ICMP_UNREACH_PROTOCOL }, 79598943Sluigi { "port", ICMP_UNREACH_PORT }, 79698943Sluigi { "needfrag", ICMP_UNREACH_NEEDFRAG }, 79798943Sluigi { "srcfail", ICMP_UNREACH_SRCFAIL }, 79898943Sluigi { "net-unknown", ICMP_UNREACH_NET_UNKNOWN }, 79998943Sluigi { "host-unknown", ICMP_UNREACH_HOST_UNKNOWN }, 80098943Sluigi { "isolated", ICMP_UNREACH_ISOLATED }, 80198943Sluigi { "net-prohib", ICMP_UNREACH_NET_PROHIB }, 80298943Sluigi { "host-prohib", ICMP_UNREACH_HOST_PROHIB }, 80398943Sluigi { "tosnet", ICMP_UNREACH_TOSNET }, 80498943Sluigi { "toshost", ICMP_UNREACH_TOSHOST }, 80598943Sluigi { "filter-prohib", ICMP_UNREACH_FILTER_PROHIB }, 80698943Sluigi { "host-precedence", ICMP_UNREACH_HOST_PRECEDENCE }, 80798943Sluigi { "precedence-cutoff", ICMP_UNREACH_PRECEDENCE_CUTOFF }, 80898943Sluigi { NULL, 0 } 80998943Sluigi}; 81098943Sluigi 81198943Sluigistatic void 81298943Sluigifill_reject_code(u_short *codep, char *str) 81398943Sluigi{ 81498943Sluigi int val; 81598943Sluigi char *s; 81698943Sluigi 81798943Sluigi val = strtoul(str, &s, 0); 81898943Sluigi if (s == str || *s != '\0' || val >= 0x100) 81998943Sluigi val = match_token(icmpcodes, str); 820102087Sluigi if (val < 0) 82198943Sluigi errx(EX_DATAERR, "unknown ICMP unreachable code ``%s''", str); 82298943Sluigi *codep = val; 82398943Sluigi return; 82498943Sluigi} 82598943Sluigi 82698943Sluigistatic void 827117328Sluigiprint_reject_code(uint16_t code) 82898943Sluigi{ 829117469Sluigi char const *s = match_value(icmpcodes, code); 83098943Sluigi 83198943Sluigi if (s != NULL) 83299475Sluigi printf("unreach %s", s); 83398943Sluigi else 83499475Sluigi printf("unreach %u", code); 83598943Sluigi} 83698943Sluigi 83798943Sluigi/* 83898943Sluigi * Returns the number of bits set (from left) in a contiguous bitmask, 83998943Sluigi * or -1 if the mask is not contiguous. 84098943Sluigi * XXX this needs a proper fix. 84198943Sluigi * This effectively works on masks in big-endian (network) format. 84298943Sluigi * when compiled on little endian architectures. 84398943Sluigi * 84498943Sluigi * First bit is bit 7 of the first byte -- note, for MAC addresses, 84598943Sluigi * the first bit on the wire is bit 0 of the first byte. 84698943Sluigi * len is the max length in bits. 84798943Sluigi */ 848187770Sluigiint 849117577Sluigicontigmask(uint8_t *p, int len) 85098943Sluigi{ 85198943Sluigi int i, n; 852117577Sluigi 85398943Sluigi for (i=0; i<len ; i++) 85498943Sluigi if ( (p[i/8] & (1 << (7 - (i%8)))) == 0) /* first bit unset */ 85598943Sluigi break; 85698943Sluigi for (n=i+1; n < len; n++) 85798943Sluigi if ( (p[n/8] & (1 << (7 - (n%8)))) != 0) 85898943Sluigi return -1; /* mask not contiguous */ 85998943Sluigi return i; 86098943Sluigi} 86198943Sluigi 86298943Sluigi/* 86398943Sluigi * print flags set/clear in the two bitmasks passed as parameters. 86498943Sluigi * There is a specialized check for f_tcpflags. 86598943Sluigi */ 86698943Sluigistatic void 867117469Sluigiprint_flags(char const *name, ipfw_insn *cmd, struct _s_x *list) 86898943Sluigi{ 869117469Sluigi char const *comma = ""; 87098943Sluigi int i; 871117577Sluigi uint8_t set = cmd->arg1 & 0xff; 872117577Sluigi uint8_t clear = (cmd->arg1 >> 8) & 0xff; 87398943Sluigi 87498943Sluigi if (list == f_tcpflags && set == TH_SYN && clear == TH_ACK) { 87598943Sluigi printf(" setup"); 87698943Sluigi return; 87798943Sluigi } 87898943Sluigi 87998943Sluigi printf(" %s ", name); 88098943Sluigi for (i=0; list[i].x != 0; i++) { 88198943Sluigi if (set & list[i].x) { 88298943Sluigi set &= ~list[i].x; 88398943Sluigi printf("%s%s", comma, list[i].s); 88498943Sluigi comma = ","; 88598943Sluigi } 88698943Sluigi if (clear & list[i].x) { 88798943Sluigi clear &= ~list[i].x; 88898943Sluigi printf("%s!%s", comma, list[i].s); 88998943Sluigi comma = ","; 89098943Sluigi } 89198943Sluigi } 89298943Sluigi} 89398943Sluigi 89498943Sluigi/* 89598943Sluigi * Print the ip address contained in a command. 89698943Sluigi */ 89798943Sluigistatic void 898117469Sluigiprint_ip(ipfw_insn_ip *cmd, char const *s) 89998943Sluigi{ 90098943Sluigi struct hostent *he = NULL; 901204591Sluigi uint32_t len = F_LEN((ipfw_insn *)cmd); 902117328Sluigi uint32_t *a = ((ipfw_insn_u32 *)cmd)->d; 90398943Sluigi 904200567Sluigi if (cmd->o.opcode == O_IP_DST_LOOKUP && len > F_INSN_SIZE(ipfw_insn_u32)) { 905200567Sluigi uint32_t d = a[1]; 906200567Sluigi const char *arg = "<invalid>"; 907200567Sluigi 908200567Sluigi if (d < sizeof(lookup_key)/sizeof(lookup_key[0])) 909200567Sluigi arg = match_value(rule_options, lookup_key[d]); 910200567Sluigi printf("%s lookup %s %d", cmd->o.len & F_NOT ? " not": "", 911200567Sluigi arg, cmd->o.arg1); 912200567Sluigi return; 913200567Sluigi } 914102087Sluigi printf("%s%s ", cmd->o.len & F_NOT ? " not": "", s); 91598943Sluigi 91698943Sluigi if (cmd->o.opcode == O_IP_SRC_ME || cmd->o.opcode == O_IP_DST_ME) { 91798943Sluigi printf("me"); 91898943Sluigi return; 91998943Sluigi } 920130281Sru if (cmd->o.opcode == O_IP_SRC_LOOKUP || 921130281Sru cmd->o.opcode == O_IP_DST_LOOKUP) { 922130281Sru printf("table(%u", ((ipfw_insn *)cmd)->arg1); 923130281Sru if (len == F_INSN_SIZE(ipfw_insn_u32)) 924130281Sru printf(",%u", *a); 925130281Sru printf(")"); 926130281Sru return; 927130281Sru } 92898943Sluigi if (cmd->o.opcode == O_IP_SRC_SET || cmd->o.opcode == O_IP_DST_SET) { 929117328Sluigi uint32_t x, *map = (uint32_t *)&(cmd->mask); 930116716Sluigi int i, j; 93198943Sluigi char comma = '{'; 93298943Sluigi 93398943Sluigi x = cmd->o.arg1 - 1; 93498943Sluigi x = htonl( ~x ); 93598943Sluigi cmd->addr.s_addr = htonl(cmd->addr.s_addr); 93698943Sluigi printf("%s/%d", inet_ntoa(cmd->addr), 937117577Sluigi contigmask((uint8_t *)&x, 32)); 93898943Sluigi x = cmd->addr.s_addr = htonl(cmd->addr.s_addr); 93998943Sluigi x &= 0xff; /* base */ 940116716Sluigi /* 941116716Sluigi * Print bits and ranges. 942116716Sluigi * Locate first bit set (i), then locate first bit unset (j). 943116716Sluigi * If we have 3+ consecutive bits set, then print them as a 944116716Sluigi * range, otherwise only print the initial bit and rescan. 945116716Sluigi */ 94698943Sluigi for (i=0; i < cmd->o.arg1; i++) 947117328Sluigi if (map[i/32] & (1<<(i & 31))) { 948116716Sluigi for (j=i+1; j < cmd->o.arg1; j++) 949117328Sluigi if (!(map[ j/32] & (1<<(j & 31)))) 950116716Sluigi break; 95198943Sluigi printf("%c%d", comma, i+x); 952116716Sluigi if (j>i+2) { /* range has at least 3 elements */ 953116716Sluigi printf("-%d", j-1+x); 954116716Sluigi i = j-1; 955116716Sluigi } 95698943Sluigi comma = ','; 95798943Sluigi } 95898943Sluigi printf("}"); 95998943Sluigi return; 96098943Sluigi } 961117328Sluigi /* 962117328Sluigi * len == 2 indicates a single IP, whereas lists of 1 or more 963117328Sluigi * addr/mask pairs have len = (2n+1). We convert len to n so we 964117328Sluigi * use that to count the number of entries. 965117328Sluigi */ 966117328Sluigi for (len = len / 2; len > 0; len--, a += 2) { 967117328Sluigi int mb = /* mask length */ 968117328Sluigi (cmd->o.opcode == O_IP_SRC || cmd->o.opcode == O_IP_DST) ? 969117577Sluigi 32 : contigmask((uint8_t *)&(a[1]), 32); 970187764Sluigi if (mb == 32 && co.do_resolv) 971117328Sluigi he = gethostbyaddr((char *)&(a[0]), sizeof(u_long), AF_INET); 97298943Sluigi if (he != NULL) /* resolved to name */ 97398943Sluigi printf("%s", he->h_name); 97498943Sluigi else if (mb == 0) /* any */ 97598943Sluigi printf("any"); 97698943Sluigi else { /* numeric IP followed by some kind of mask */ 977117328Sluigi printf("%s", inet_ntoa( *((struct in_addr *)&a[0]) ) ); 97898943Sluigi if (mb < 0) 979117328Sluigi printf(":%s", inet_ntoa( *((struct in_addr *)&a[1]) ) ); 98098943Sluigi else if (mb < 32) 98198943Sluigi printf("/%d", mb); 98298943Sluigi } 983117328Sluigi if (len > 1) 984117328Sluigi printf(","); 985117328Sluigi } 98698943Sluigi} 98798943Sluigi 98898943Sluigi/* 98998943Sluigi * prints a MAC address/mask pair 99098943Sluigi */ 99198943Sluigistatic void 992117577Sluigiprint_mac(uint8_t *addr, uint8_t *mask) 99398943Sluigi{ 99498943Sluigi int l = contigmask(mask, 48); 99598943Sluigi 99698943Sluigi if (l == 0) 99798943Sluigi printf(" any"); 99898943Sluigi else { 99998943Sluigi printf(" %02x:%02x:%02x:%02x:%02x:%02x", 100098943Sluigi addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); 100198943Sluigi if (l == -1) 100298943Sluigi printf("&%02x:%02x:%02x:%02x:%02x:%02x", 100398943Sluigi mask[0], mask[1], mask[2], 100498943Sluigi mask[3], mask[4], mask[5]); 100598943Sluigi else if (l < 48) 100698943Sluigi printf("/%d", l); 100798943Sluigi } 100898943Sluigi} 100998943Sluigi 101099475Sluigistatic void 101199475Sluigifill_icmptypes(ipfw_insn_u32 *cmd, char *av) 101299475Sluigi{ 1013117328Sluigi uint8_t type; 101498943Sluigi 101599475Sluigi cmd->d[0] = 0; 101699475Sluigi while (*av) { 101799475Sluigi if (*av == ',') 101899475Sluigi av++; 101999475Sluigi 102099475Sluigi type = strtoul(av, &av, 0); 102199475Sluigi 102299475Sluigi if (*av != ',' && *av != '\0') 102399475Sluigi errx(EX_DATAERR, "invalid ICMP type"); 102499475Sluigi 102599475Sluigi if (type > 31) 102699475Sluigi errx(EX_DATAERR, "ICMP type out of range"); 102799475Sluigi 102899475Sluigi cmd->d[0] |= 1 << type; 102999475Sluigi } 103099475Sluigi cmd->o.opcode = O_ICMPTYPE; 103199475Sluigi cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32); 103299475Sluigi} 103399475Sluigi 103499475Sluigistatic void 103599475Sluigiprint_icmptypes(ipfw_insn_u32 *cmd) 103699475Sluigi{ 103799475Sluigi int i; 103899475Sluigi char sep= ' '; 103999475Sluigi 104099475Sluigi printf(" icmptypes"); 104199475Sluigi for (i = 0; i < 32; i++) { 104299475Sluigi if ( (cmd->d[0] & (1 << (i))) == 0) 104399475Sluigi continue; 104499475Sluigi printf("%c%d", sep, i); 104599475Sluigi sep = ','; 104699475Sluigi } 104799475Sluigi} 104899475Sluigi 1049250762Smelifarostatic void 1050250762Smelifaroprint_dscp(ipfw_insn_u32 *cmd) 1051250762Smelifaro{ 1052250762Smelifaro int i, c; 1053250762Smelifaro uint32_t *v; 1054250762Smelifaro char sep= ' '; 1055250762Smelifaro const char *code; 1056250762Smelifaro 1057250762Smelifaro printf(" dscp"); 1058250762Smelifaro i = 0; 1059250762Smelifaro c = 0; 1060250762Smelifaro v = cmd->d; 1061250762Smelifaro while (i < 64) { 1062250762Smelifaro if (*v & (1 << i)) { 1063250762Smelifaro if ((code = match_value(f_ipdscp, i)) != NULL) 1064250762Smelifaro printf("%c%s", sep, code); 1065250762Smelifaro else 1066250762Smelifaro printf("%c%d", sep, i); 1067250762Smelifaro sep = ','; 1068250762Smelifaro } 1069250762Smelifaro 1070250762Smelifaro if ((++i % 32) == 0) 1071250762Smelifaro v++; 1072250762Smelifaro } 1073250762Smelifaro} 1074250762Smelifaro 107598943Sluigi/* 107698943Sluigi * show_ipfw() prints the body of an ipfw rule. 107798943Sluigi * Because the standard rule has at least proto src_ip dst_ip, we use 107898943Sluigi * a helper function to produce these entries if not provided explicitly. 1079102087Sluigi * The first argument is the list of fields we have, the second is 1080102087Sluigi * the list of fields we want to be printed. 1081101978Sluigi * 1082102087Sluigi * Special cases if we have provided a MAC header: 1083102087Sluigi * + if the rule does not contain IP addresses/ports, do not print them; 1084102087Sluigi * + if the rule does not contain an IP proto, print "all" instead of "ip"; 1085102087Sluigi * 1086102087Sluigi * Once we have 'have_options', IP header fields are printed as options. 108798943Sluigi */ 1088101978Sluigi#define HAVE_PROTO 0x0001 1089101978Sluigi#define HAVE_SRCIP 0x0002 1090101978Sluigi#define HAVE_DSTIP 0x0004 1091169139Smaxim#define HAVE_PROTO4 0x0008 1092169139Smaxim#define HAVE_PROTO6 0x0010 1093205179Sluigi#define HAVE_IP 0x0100 1094102087Sluigi#define HAVE_OPTIONS 0x8000 109598943Sluigi 109698943Sluigistatic void 1097187477Sluigishow_prerequisites(int *flags, int want, int cmd __unused) 109898943Sluigi{ 1099187764Sluigi if (co.comment_only) 1100123495Sluigi return; 1101102087Sluigi if ( (*flags & HAVE_IP) == HAVE_IP) 1102102087Sluigi *flags |= HAVE_OPTIONS; 1103102087Sluigi 1104102087Sluigi if ( !(*flags & HAVE_OPTIONS)) { 1105187477Sluigi if ( !(*flags & HAVE_PROTO) && (want & HAVE_PROTO)) { 1106146894Smlaier if ( (*flags & HAVE_PROTO4)) 1107146894Smlaier printf(" ip4"); 1108146894Smlaier else if ( (*flags & HAVE_PROTO6)) 1109146894Smlaier printf(" ip6"); 1110146894Smlaier else 1111146894Smlaier printf(" ip"); 1112187477Sluigi } 1113102087Sluigi if ( !(*flags & HAVE_SRCIP) && (want & HAVE_SRCIP)) 1114102087Sluigi printf(" from any"); 1115102087Sluigi if ( !(*flags & HAVE_DSTIP) && (want & HAVE_DSTIP)) 1116102087Sluigi printf(" to any"); 1117102087Sluigi } 111898943Sluigi *flags |= want; 111998943Sluigi} 112098943Sluigi 112198943Sluigistatic void 1122112189Smaximshow_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth) 112398943Sluigi{ 1124107291Skeramida static int twidth = 0; 112598943Sluigi int l; 1126158879Soleg ipfw_insn *cmd, *tagptr = NULL; 1127187477Sluigi const char *comment = NULL; /* ptr to comment if we have one */ 112898943Sluigi int proto = 0; /* default */ 112998943Sluigi int flags = 0; /* prerequisites */ 113098943Sluigi ipfw_insn_log *logptr = NULL; /* set if we find an O_LOG */ 1131136071Sgreen ipfw_insn_altq *altqptr = NULL; /* set if we find an O_ALTQ */ 113298943Sluigi int or_block = 0; /* we are in an or block */ 1133117328Sluigi uint32_t set_disable; 113498943Sluigi 1135115793Sticso bcopy(&rule->next_rule, &set_disable, sizeof(set_disable)); 1136101628Sluigi 1137101628Sluigi if (set_disable & (1 << rule->set)) { /* disabled */ 1138187764Sluigi if (!co.show_sets) 1139101628Sluigi return; 1140101628Sluigi else 1141101628Sluigi printf("# DISABLED "); 1142101628Sluigi } 114398943Sluigi printf("%05u ", rule->rulenum); 114498943Sluigi 1145206843Sluigi if (pcwidth > 0 || bcwidth > 0) { 1146206843Sluigi pr_u64(&rule->pcnt, pcwidth); 1147206843Sluigi pr_u64(&rule->bcnt, bcwidth); 1148206843Sluigi } 114998943Sluigi 1150187764Sluigi if (co.do_time == 2) 1151117472Sluigi printf("%10u ", rule->timestamp); 1152187764Sluigi else if (co.do_time == 1) { 1153107291Skeramida char timestr[30]; 1154107291Skeramida time_t t = (time_t)0; 1155107291Skeramida 1156107291Skeramida if (twidth == 0) { 1157107291Skeramida strcpy(timestr, ctime(&t)); 1158107291Skeramida *strchr(timestr, '\n') = '\0'; 1159107291Skeramida twidth = strlen(timestr); 1160107291Skeramida } 116198943Sluigi if (rule->timestamp) { 1162107291Skeramida t = _long_to_time(rule->timestamp); 116398943Sluigi 116498943Sluigi strcpy(timestr, ctime(&t)); 116598943Sluigi *strchr(timestr, '\n') = '\0'; 116698943Sluigi printf("%s ", timestr); 116798943Sluigi } else { 1168107291Skeramida printf("%*s", twidth, " "); 116998943Sluigi } 117098943Sluigi } 117198943Sluigi 1172187764Sluigi if (co.show_sets) 1173101628Sluigi printf("set %d ", rule->set); 1174101628Sluigi 117598943Sluigi /* 1176107289Sluigi * print the optional "match probability" 1177107289Sluigi */ 1178107289Sluigi if (rule->cmd_len > 0) { 1179107289Sluigi cmd = rule->cmd ; 1180107289Sluigi if (cmd->opcode == O_PROB) { 1181107289Sluigi ipfw_insn_u32 *p = (ipfw_insn_u32 *)cmd; 1182107289Sluigi double d = 1.0 * p->d[0]; 1183107289Sluigi 1184107289Sluigi d = (d / 0x7fffffff); 1185107289Sluigi printf("prob %f ", d); 1186107289Sluigi } 1187107289Sluigi } 1188107289Sluigi 1189107289Sluigi /* 119098943Sluigi * first print actions 119198943Sluigi */ 1192220802Sglebius for (l = rule->cmd_len - rule->act_ofs, cmd = ACTION_PTR(rule); 119398943Sluigi l > 0 ; l -= F_LEN(cmd), cmd += F_LEN(cmd)) { 119498943Sluigi switch(cmd->opcode) { 119598943Sluigi case O_CHECK_STATE: 119698943Sluigi printf("check-state"); 1197205179Sluigi /* avoid printing anything else */ 1198205179Sluigi flags = HAVE_PROTO | HAVE_SRCIP | 1199205179Sluigi HAVE_DSTIP | HAVE_IP; 120098943Sluigi break; 120198943Sluigi 120298943Sluigi case O_ACCEPT: 120398943Sluigi printf("allow"); 120498943Sluigi break; 120598943Sluigi 120698943Sluigi case O_COUNT: 120798943Sluigi printf("count"); 120898943Sluigi break; 120998943Sluigi 121098943Sluigi case O_DENY: 121198943Sluigi printf("deny"); 121298943Sluigi break; 121398943Sluigi 121499475Sluigi case O_REJECT: 121599475Sluigi if (cmd->arg1 == ICMP_REJECT_RST) 121699475Sluigi printf("reset"); 121799475Sluigi else if (cmd->arg1 == ICMP_UNREACH_HOST) 121899475Sluigi printf("reject"); 121999475Sluigi else 122099475Sluigi print_reject_code(cmd->arg1); 122199475Sluigi break; 122299475Sluigi 1223149020Sbz case O_UNREACH6: 1224149020Sbz if (cmd->arg1 == ICMP6_UNREACH_RST) 1225149020Sbz printf("reset6"); 1226149020Sbz else 1227149020Sbz print_unreach6_code(cmd->arg1); 1228149020Sbz break; 1229149020Sbz 1230159636Soleg case O_SKIPTO: 1231159636Soleg PRINT_UINT_ARG("skipto ", cmd->arg1); 123298943Sluigi break; 123398943Sluigi 123498943Sluigi case O_PIPE: 1235159636Soleg PRINT_UINT_ARG("pipe ", cmd->arg1); 1236159636Soleg break; 1237159636Soleg 123898943Sluigi case O_QUEUE: 1239159636Soleg PRINT_UINT_ARG("queue ", cmd->arg1); 1240159636Soleg break; 1241159636Soleg 124298943Sluigi case O_DIVERT: 1243159636Soleg PRINT_UINT_ARG("divert ", cmd->arg1); 1244159636Soleg break; 1245159636Soleg 124698943Sluigi case O_TEE: 1247159636Soleg PRINT_UINT_ARG("tee ", cmd->arg1); 1248159636Soleg break; 1249159636Soleg 1250141351Sglebius case O_NETGRAPH: 1251159636Soleg PRINT_UINT_ARG("netgraph ", cmd->arg1); 1252159636Soleg break; 1253159636Soleg 1254141351Sglebius case O_NGTEE: 1255159636Soleg PRINT_UINT_ARG("ngtee ", cmd->arg1); 1256159636Soleg break; 1257141351Sglebius 125898943Sluigi case O_FORWARD_IP: 125998943Sluigi { 126098943Sluigi ipfw_insn_sa *s = (ipfw_insn_sa *)cmd; 126198943Sluigi 1262161424Sjulian if (s->sa.sin_addr.s_addr == INADDR_ANY) { 1263161424Sjulian printf("fwd tablearg"); 1264161424Sjulian } else { 1265161424Sjulian printf("fwd %s", inet_ntoa(s->sa.sin_addr)); 1266161424Sjulian } 126798943Sluigi if (s->sa.sin_port) 1268103241Sluigi printf(",%d", s->sa.sin_port); 126998943Sluigi } 127098943Sluigi break; 127198943Sluigi 1272225044Sbz case O_FORWARD_IP6: 1273225044Sbz { 1274225044Sbz char buf[4 + INET6_ADDRSTRLEN + 1]; 1275225044Sbz ipfw_insn_sa6 *s = (ipfw_insn_sa6 *)cmd; 1276225044Sbz 1277225044Sbz printf("fwd %s", inet_ntop(AF_INET6, &s->sa.sin6_addr, 1278225044Sbz buf, sizeof(buf))); 1279225044Sbz if (s->sa.sin6_port) 1280225044Sbz printf(",%d", s->sa.sin6_port); 1281225044Sbz } 1282225044Sbz break; 1283225044Sbz 128498943Sluigi case O_LOG: /* O_LOG is printed last */ 128598943Sluigi logptr = (ipfw_insn_log *)cmd; 128698943Sluigi break; 128798943Sluigi 1288136071Sgreen case O_ALTQ: /* O_ALTQ is printed after O_LOG */ 1289136071Sgreen altqptr = (ipfw_insn_altq *)cmd; 1290136071Sgreen break; 1291136071Sgreen 1292158879Soleg case O_TAG: 1293158879Soleg tagptr = cmd; 1294158879Soleg break; 1295158879Soleg 1296165648Spiso case O_NAT: 1297223080Sae if (cmd->arg1 != 0) 1298223080Sae PRINT_UINT_ARG("nat ", cmd->arg1); 1299223080Sae else 1300223080Sae printf("nat global"); 1301223080Sae break; 1302220804Sglebius 1303178888Sjulian case O_SETFIB: 1304178888Sjulian PRINT_UINT_ARG("setfib ", cmd->arg1); 1305178888Sjulian break; 1306190633Spiso 1307250762Smelifaro case O_SETDSCP: 1308250762Smelifaro { 1309250762Smelifaro const char *code; 1310250762Smelifaro 1311250762Smelifaro if ((code = match_value(f_ipdscp, cmd->arg1)) != NULL) 1312250762Smelifaro printf("setdscp %s", code); 1313250762Smelifaro else 1314250762Smelifaro PRINT_UINT_ARG("setdscp ", cmd->arg1); 1315250762Smelifaro } 1316250762Smelifaro break; 1317250762Smelifaro 1318190633Spiso case O_REASS: 1319190633Spiso printf("reass"); 1320190633Spiso break; 1321220804Sglebius 1322223666Sae case O_CALLRETURN: 1323223666Sae if (cmd->len & F_NOT) 1324223666Sae printf("return"); 1325223666Sae else 1326223666Sae PRINT_UINT_ARG("call ", cmd->arg1); 1327223666Sae break; 1328223666Sae 132998943Sluigi default: 1330136071Sgreen printf("** unrecognized action %d len %d ", 133198943Sluigi cmd->opcode, cmd->len); 133298943Sluigi } 133398943Sluigi } 133498943Sluigi if (logptr) { 133598943Sluigi if (logptr->max_log > 0) 133699909Sluigi printf(" log logamount %d", logptr->max_log); 133798943Sluigi else 133899909Sluigi printf(" log"); 133998943Sluigi } 1340204591Sluigi#ifndef NO_ALTQ 1341136071Sgreen if (altqptr) { 1342187983Sluigi print_altq_cmd(altqptr); 1343136071Sgreen } 1344204591Sluigi#endif 1345158879Soleg if (tagptr) { 1346158879Soleg if (tagptr->len & F_NOT) 1347159636Soleg PRINT_UINT_ARG(" untag ", tagptr->arg1); 1348158879Soleg else 1349159636Soleg PRINT_UINT_ARG(" tag ", tagptr->arg1); 1350158879Soleg } 1351136071Sgreen 135298943Sluigi /* 1353102087Sluigi * then print the body. 135498943Sluigi */ 1355220802Sglebius for (l = rule->act_ofs, cmd = rule->cmd ; 1356146894Smlaier l > 0 ; l -= F_LEN(cmd) , cmd += F_LEN(cmd)) { 1357146894Smlaier if ((cmd->len & F_OR) || (cmd->len & F_NOT)) 1358146894Smlaier continue; 1359146894Smlaier if (cmd->opcode == O_IP4) { 1360146894Smlaier flags |= HAVE_PROTO4; 1361146894Smlaier break; 1362146894Smlaier } else if (cmd->opcode == O_IP6) { 1363146894Smlaier flags |= HAVE_PROTO6; 1364146894Smlaier break; 1365220804Sglebius } 1366146894Smlaier } 1367102087Sluigi if (rule->_pad & 1) { /* empty rules before options */ 1368187764Sluigi if (!co.do_compact) { 1369146894Smlaier show_prerequisites(&flags, HAVE_PROTO, 0); 1370146894Smlaier printf(" from any to any"); 1371146894Smlaier } 1372205179Sluigi flags |= HAVE_IP | HAVE_OPTIONS | HAVE_PROTO | 1373205179Sluigi HAVE_SRCIP | HAVE_DSTIP; 1374102087Sluigi } 1375102087Sluigi 1376187764Sluigi if (co.comment_only) 1377123495Sluigi comment = "..."; 1378123495Sluigi 1379220802Sglebius for (l = rule->act_ofs, cmd = rule->cmd ; 138098943Sluigi l > 0 ; l -= F_LEN(cmd) , cmd += F_LEN(cmd)) { 138199475Sluigi /* useful alias */ 138299475Sluigi ipfw_insn_u32 *cmd32 = (ipfw_insn_u32 *)cmd; 138398943Sluigi 1384187764Sluigi if (co.comment_only) { 1385123495Sluigi if (cmd->opcode != O_NOP) 1386123495Sluigi continue; 1387123495Sluigi printf(" // %s\n", (char *)(cmd + 1)); 1388123495Sluigi return; 1389123495Sluigi } 1390123495Sluigi 1391102087Sluigi show_prerequisites(&flags, 0, cmd->opcode); 1392102087Sluigi 139398943Sluigi switch(cmd->opcode) { 1394117577Sluigi case O_PROB: 1395107289Sluigi break; /* done already */ 1396107289Sluigi 139798943Sluigi case O_PROBE_STATE: 139898943Sluigi break; /* no need to print anything here */ 139998943Sluigi 140098943Sluigi case O_IP_SRC: 1401130281Sru case O_IP_SRC_LOOKUP: 140298943Sluigi case O_IP_SRC_MASK: 140398943Sluigi case O_IP_SRC_ME: 140498943Sluigi case O_IP_SRC_SET: 1405102087Sluigi show_prerequisites(&flags, HAVE_PROTO, 0); 140698943Sluigi if (!(flags & HAVE_SRCIP)) 140798943Sluigi printf(" from"); 140898943Sluigi if ((cmd->len & F_OR) && !or_block) 140998943Sluigi printf(" {"); 1410102087Sluigi print_ip((ipfw_insn_ip *)cmd, 1411102087Sluigi (flags & HAVE_OPTIONS) ? " src-ip" : ""); 141298943Sluigi flags |= HAVE_SRCIP; 141398943Sluigi break; 141498943Sluigi 141598943Sluigi case O_IP_DST: 1416130281Sru case O_IP_DST_LOOKUP: 141798943Sluigi case O_IP_DST_MASK: 141898943Sluigi case O_IP_DST_ME: 141998943Sluigi case O_IP_DST_SET: 1420102087Sluigi show_prerequisites(&flags, HAVE_PROTO|HAVE_SRCIP, 0); 142198943Sluigi if (!(flags & HAVE_DSTIP)) 142298943Sluigi printf(" to"); 142398943Sluigi if ((cmd->len & F_OR) && !or_block) 142498943Sluigi printf(" {"); 1425102087Sluigi print_ip((ipfw_insn_ip *)cmd, 1426102087Sluigi (flags & HAVE_OPTIONS) ? " dst-ip" : ""); 142798943Sluigi flags |= HAVE_DSTIP; 142898943Sluigi break; 142998943Sluigi 1430145246Sbrooks case O_IP6_SRC: 1431145246Sbrooks case O_IP6_SRC_MASK: 1432145246Sbrooks case O_IP6_SRC_ME: 1433147105Smlaier show_prerequisites(&flags, HAVE_PROTO, 0); 1434145246Sbrooks if (!(flags & HAVE_SRCIP)) 1435145246Sbrooks printf(" from"); 1436145246Sbrooks if ((cmd->len & F_OR) && !or_block) 1437145246Sbrooks printf(" {"); 1438145246Sbrooks print_ip6((ipfw_insn_ip6 *)cmd, 1439145246Sbrooks (flags & HAVE_OPTIONS) ? " src-ip6" : ""); 1440145246Sbrooks flags |= HAVE_SRCIP | HAVE_PROTO; 1441145246Sbrooks break; 1442145246Sbrooks 1443145246Sbrooks case O_IP6_DST: 1444145246Sbrooks case O_IP6_DST_MASK: 1445145246Sbrooks case O_IP6_DST_ME: 1446145246Sbrooks show_prerequisites(&flags, HAVE_PROTO|HAVE_SRCIP, 0); 1447145246Sbrooks if (!(flags & HAVE_DSTIP)) 1448145246Sbrooks printf(" to"); 1449145246Sbrooks if ((cmd->len & F_OR) && !or_block) 1450145246Sbrooks printf(" {"); 1451145246Sbrooks print_ip6((ipfw_insn_ip6 *)cmd, 1452145246Sbrooks (flags & HAVE_OPTIONS) ? " dst-ip6" : ""); 1453145246Sbrooks flags |= HAVE_DSTIP; 1454145246Sbrooks break; 1455145246Sbrooks 1456145246Sbrooks case O_FLOW6ID: 1457145246Sbrooks print_flow6id( (ipfw_insn_u32 *) cmd ); 1458145246Sbrooks flags |= HAVE_OPTIONS; 1459145246Sbrooks break; 1460145246Sbrooks 146198943Sluigi case O_IP_DSTPORT: 1462205179Sluigi show_prerequisites(&flags, 1463205179Sluigi HAVE_PROTO | HAVE_SRCIP | 1464205179Sluigi HAVE_DSTIP | HAVE_IP, 0); 146598943Sluigi case O_IP_SRCPORT: 1466224942Sjhb if (flags & HAVE_DSTIP) 1467224942Sjhb flags |= HAVE_IP; 1468205179Sluigi show_prerequisites(&flags, 1469205179Sluigi HAVE_PROTO | HAVE_SRCIP, 0); 1470101641Sluigi if ((cmd->len & F_OR) && !or_block) 1471101641Sluigi printf(" {"); 1472172306Smaxim if (cmd->len & F_NOT) 1473172306Smaxim printf(" not"); 1474102087Sluigi print_newports((ipfw_insn_u16 *)cmd, proto, 1475102087Sluigi (flags & HAVE_OPTIONS) ? cmd->opcode : 0); 147698943Sluigi break; 147798943Sluigi 147898943Sluigi case O_PROTO: { 1479145246Sbrooks struct protoent *pe = NULL; 148098943Sluigi 148198943Sluigi if ((cmd->len & F_OR) && !or_block) 148298943Sluigi printf(" {"); 148398943Sluigi if (cmd->len & F_NOT) 148498943Sluigi printf(" not"); 148598943Sluigi proto = cmd->arg1; 1486145567Sbrooks pe = getprotobynumber(cmd->arg1); 1487146894Smlaier if ((flags & (HAVE_PROTO4 | HAVE_PROTO6)) && 1488146894Smlaier !(flags & HAVE_PROTO)) 1489146894Smlaier show_prerequisites(&flags, 1490205179Sluigi HAVE_PROTO | HAVE_IP | HAVE_SRCIP | 1491205179Sluigi HAVE_DSTIP | HAVE_OPTIONS, 0); 1492102087Sluigi if (flags & HAVE_OPTIONS) 1493102087Sluigi printf(" proto"); 149498943Sluigi if (pe) 149598943Sluigi printf(" %s", pe->p_name); 149698943Sluigi else 149798943Sluigi printf(" %u", cmd->arg1); 149898943Sluigi } 149998943Sluigi flags |= HAVE_PROTO; 150098943Sluigi break; 1501106505Smaxim 150298943Sluigi default: /*options ... */ 1503146894Smlaier if (!(cmd->len & (F_OR|F_NOT))) 1504146894Smlaier if (((cmd->opcode == O_IP6) && 1505146894Smlaier (flags & HAVE_PROTO6)) || 1506146894Smlaier ((cmd->opcode == O_IP4) && 1507146894Smlaier (flags & HAVE_PROTO4))) 1508146894Smlaier break; 1509205179Sluigi show_prerequisites(&flags, HAVE_PROTO | HAVE_SRCIP | 1510205179Sluigi HAVE_DSTIP | HAVE_IP | HAVE_OPTIONS, 0); 151198943Sluigi if ((cmd->len & F_OR) && !or_block) 151298943Sluigi printf(" {"); 151398943Sluigi if (cmd->len & F_NOT && cmd->opcode != O_IN) 151498943Sluigi printf(" not"); 151598943Sluigi switch(cmd->opcode) { 1516169139Smaxim case O_MACADDR2: { 1517169139Smaxim ipfw_insn_mac *m = (ipfw_insn_mac *)cmd; 1518169139Smaxim 1519169139Smaxim printf(" MAC"); 1520169139Smaxim print_mac(m->addr, m->mask); 1521169139Smaxim print_mac(m->addr + 6, m->mask + 6); 1522169139Smaxim } 1523169139Smaxim break; 1524169139Smaxim 1525169139Smaxim case O_MAC_TYPE: 1526169139Smaxim print_newports((ipfw_insn_u16 *)cmd, 1527169139Smaxim IPPROTO_ETHERTYPE, cmd->opcode); 1528169139Smaxim break; 1529169139Smaxim 1530169139Smaxim 153198943Sluigi case O_FRAG: 153298943Sluigi printf(" frag"); 153398943Sluigi break; 153498943Sluigi 1535178888Sjulian case O_FIB: 1536178888Sjulian printf(" fib %u", cmd->arg1 ); 1537178888Sjulian break; 1538215179Sluigi case O_SOCKARG: 1539215179Sluigi printf(" sockarg"); 1540215179Sluigi break; 1541178888Sjulian 154298943Sluigi case O_IN: 154398943Sluigi printf(cmd->len & F_NOT ? " out" : " in"); 154498943Sluigi break; 154598943Sluigi 1546136073Sgreen case O_DIVERTED: 1547136073Sgreen switch (cmd->arg1) { 1548136073Sgreen case 3: 1549136073Sgreen printf(" diverted"); 1550136073Sgreen break; 1551136073Sgreen case 1: 1552136073Sgreen printf(" diverted-loopback"); 1553136073Sgreen break; 1554136073Sgreen case 2: 1555136073Sgreen printf(" diverted-output"); 1556136073Sgreen break; 1557136073Sgreen default: 1558136073Sgreen printf(" diverted-?<%u>", cmd->arg1); 1559136073Sgreen break; 1560136073Sgreen } 1561136073Sgreen break; 1562136073Sgreen 156398943Sluigi case O_LAYER2: 156498943Sluigi printf(" layer2"); 156598943Sluigi break; 156698943Sluigi case O_XMIT: 156798943Sluigi case O_RECV: 1568140423Sglebius case O_VIA: 1569140423Sglebius { 1570117469Sluigi char const *s; 157198943Sluigi ipfw_insn_if *cmdif = (ipfw_insn_if *)cmd; 157298943Sluigi 157398943Sluigi if (cmd->opcode == O_XMIT) 157498943Sluigi s = "xmit"; 157598943Sluigi else if (cmd->opcode == O_RECV) 157698943Sluigi s = "recv"; 1577117469Sluigi else /* if (cmd->opcode == O_VIA) */ 157898943Sluigi s = "via"; 157998943Sluigi if (cmdif->name[0] == '\0') 158099475Sluigi printf(" %s %s", s, 158199475Sluigi inet_ntoa(cmdif->p.ip)); 1582234597Smelifaro else if (cmdif->name[0] == '\1') /* interface table */ 1583234597Smelifaro printf(" %s table(%d)", s, cmdif->p.glob); 1584140423Sglebius else 1585140423Sglebius printf(" %s %s", s, cmdif->name); 1586140423Sglebius 158798943Sluigi break; 1588140423Sglebius } 158998943Sluigi case O_IPID: 1590116690Sluigi if (F_LEN(cmd) == 1) 1591116690Sluigi printf(" ipid %u", cmd->arg1 ); 1592116690Sluigi else 1593116690Sluigi print_newports((ipfw_insn_u16 *)cmd, 0, 1594116690Sluigi O_IPID); 159598943Sluigi break; 159698943Sluigi 159798943Sluigi case O_IPTTL: 1598116690Sluigi if (F_LEN(cmd) == 1) 1599116690Sluigi printf(" ipttl %u", cmd->arg1 ); 1600116690Sluigi else 1601116690Sluigi print_newports((ipfw_insn_u16 *)cmd, 0, 1602116690Sluigi O_IPTTL); 160398943Sluigi break; 160498943Sluigi 160598943Sluigi case O_IPVER: 160698943Sluigi printf(" ipver %u", cmd->arg1 ); 160798943Sluigi break; 160898943Sluigi 160999475Sluigi case O_IPPRECEDENCE: 161099475Sluigi printf(" ipprecedence %u", (cmd->arg1) >> 5 ); 161199475Sluigi break; 161299475Sluigi 1613250762Smelifaro case O_DSCP: 1614250762Smelifaro print_dscp((ipfw_insn_u32 *)cmd); 1615250762Smelifaro break; 1616250762Smelifaro 161798943Sluigi case O_IPLEN: 1618116690Sluigi if (F_LEN(cmd) == 1) 1619116690Sluigi printf(" iplen %u", cmd->arg1 ); 1620116690Sluigi else 1621116690Sluigi print_newports((ipfw_insn_u16 *)cmd, 0, 1622116690Sluigi O_IPLEN); 162398943Sluigi break; 162498943Sluigi 1625101116Sluigi case O_IPOPT: 162698943Sluigi print_flags("ipoptions", cmd, f_ipopts); 162798943Sluigi break; 162898943Sluigi 162999475Sluigi case O_IPTOS: 163099475Sluigi print_flags("iptos", cmd, f_iptos); 163199475Sluigi break; 163299475Sluigi 163399475Sluigi case O_ICMPTYPE: 163499475Sluigi print_icmptypes((ipfw_insn_u32 *)cmd); 163599475Sluigi break; 163699475Sluigi 163798943Sluigi case O_ESTAB: 163898943Sluigi printf(" established"); 163998943Sluigi break; 164098943Sluigi 1641136075Sgreen case O_TCPDATALEN: 1642136075Sgreen if (F_LEN(cmd) == 1) 1643136075Sgreen printf(" tcpdatalen %u", cmd->arg1 ); 1644136075Sgreen else 1645136075Sgreen print_newports((ipfw_insn_u16 *)cmd, 0, 1646136075Sgreen O_TCPDATALEN); 1647136075Sgreen break; 1648136075Sgreen 164998943Sluigi case O_TCPFLAGS: 165098943Sluigi print_flags("tcpflags", cmd, f_tcpflags); 165198943Sluigi break; 165298943Sluigi 165398943Sluigi case O_TCPOPTS: 165498943Sluigi print_flags("tcpoptions", cmd, f_tcpopts); 165598943Sluigi break; 165698943Sluigi 165798943Sluigi case O_TCPWIN: 1658234278Sglebius if (F_LEN(cmd) == 1) 1659234278Sglebius printf(" tcpwin %u", cmd->arg1); 1660234278Sglebius else 1661234278Sglebius print_newports((ipfw_insn_u16 *)cmd, 0, 1662234278Sglebius O_TCPWIN); 166398943Sluigi break; 166498943Sluigi 166598943Sluigi case O_TCPACK: 166698943Sluigi printf(" tcpack %d", ntohl(cmd32->d[0])); 166798943Sluigi break; 166898943Sluigi 166998943Sluigi case O_TCPSEQ: 167098943Sluigi printf(" tcpseq %d", ntohl(cmd32->d[0])); 167198943Sluigi break; 167298943Sluigi 167398943Sluigi case O_UID: 167498943Sluigi { 167598943Sluigi struct passwd *pwd = getpwuid(cmd32->d[0]); 167698943Sluigi 167798943Sluigi if (pwd) 167898943Sluigi printf(" uid %s", pwd->pw_name); 167998943Sluigi else 168098943Sluigi printf(" uid %u", cmd32->d[0]); 168198943Sluigi } 168298943Sluigi break; 168398943Sluigi 168498943Sluigi case O_GID: 168598943Sluigi { 168698943Sluigi struct group *grp = getgrgid(cmd32->d[0]); 168798943Sluigi 168898943Sluigi if (grp) 168998943Sluigi printf(" gid %s", grp->gr_name); 169098943Sluigi else 169198943Sluigi printf(" gid %u", cmd32->d[0]); 169298943Sluigi } 169398943Sluigi break; 169498943Sluigi 1695133600Scsjp case O_JAIL: 1696133600Scsjp printf(" jail %d", cmd32->d[0]); 1697133600Scsjp break; 1698133600Scsjp 1699112250Scjc case O_VERREVPATH: 1700112250Scjc printf(" verrevpath"); 1701112250Scjc break; 1702116919Sluigi 1703128575Sandre case O_VERSRCREACH: 1704128575Sandre printf(" versrcreach"); 1705128575Sandre break; 1706128575Sandre 1707133387Sandre case O_ANTISPOOF: 1708133387Sandre printf(" antispoof"); 1709133387Sandre break; 1710133387Sandre 1711117241Sluigi case O_IPSEC: 1712117241Sluigi printf(" ipsec"); 1713117241Sluigi break; 1714117241Sluigi 1715117469Sluigi case O_NOP: 1716117626Sluigi comment = (char *)(cmd + 1); 1717117469Sluigi break; 1718117469Sluigi 171998943Sluigi case O_KEEP_STATE: 172098943Sluigi printf(" keep-state"); 172198943Sluigi break; 172298943Sluigi 1723159636Soleg case O_LIMIT: { 172498943Sluigi struct _s_x *p = limit_masks; 172598943Sluigi ipfw_insn_limit *c = (ipfw_insn_limit *)cmd; 1726117328Sluigi uint8_t x = c->limit_mask; 1727117469Sluigi char const *comma = " "; 172898943Sluigi 172998943Sluigi printf(" limit"); 1730117577Sluigi for (; p->x != 0 ; p++) 173199909Sluigi if ((x & p->x) == p->x) { 173298943Sluigi x &= ~p->x; 173398943Sluigi printf("%s%s", comma, p->s); 173498943Sluigi comma = ","; 173598943Sluigi } 1736159636Soleg PRINT_UINT_ARG(" ", c->conn_limit); 173798943Sluigi break; 1738159636Soleg } 173998943Sluigi 1740146894Smlaier case O_IP6: 1741152923Sume printf(" ip6"); 1742145246Sbrooks break; 1743145246Sbrooks 1744146894Smlaier case O_IP4: 1745152923Sume printf(" ip4"); 1746146894Smlaier break; 1747146894Smlaier 1748145246Sbrooks case O_ICMP6TYPE: 1749145246Sbrooks print_icmp6types((ipfw_insn_u32 *)cmd); 1750145246Sbrooks break; 1751145246Sbrooks 1752145246Sbrooks case O_EXT_HDR: 1753145246Sbrooks print_ext6hdr( (ipfw_insn *) cmd ); 1754145246Sbrooks break; 1755145246Sbrooks 1756158879Soleg case O_TAGGED: 1757158879Soleg if (F_LEN(cmd) == 1) 1758159636Soleg PRINT_UINT_ARG(" tagged ", cmd->arg1); 1759158879Soleg else 1760159636Soleg print_newports((ipfw_insn_u16 *)cmd, 0, 1761159636Soleg O_TAGGED); 1762158879Soleg break; 1763158879Soleg 176498943Sluigi default: 176598943Sluigi printf(" [opcode %d len %d]", 176698943Sluigi cmd->opcode, cmd->len); 176798943Sluigi } 176898943Sluigi } 176998943Sluigi if (cmd->len & F_OR) { 177098943Sluigi printf(" or"); 177198943Sluigi or_block = 1; 177298943Sluigi } else if (or_block) { 177398943Sluigi printf(" }"); 177498943Sluigi or_block = 0; 177598943Sluigi } 177698943Sluigi } 1777205179Sluigi show_prerequisites(&flags, HAVE_PROTO | HAVE_SRCIP | HAVE_DSTIP 1778220802Sglebius | HAVE_IP, 0); 1779117626Sluigi if (comment) 1780117626Sluigi printf(" // %s", comment); 178198943Sluigi printf("\n"); 178298943Sluigi} 178398943Sluigi 178498943Sluigistatic void 1785112189Smaximshow_dyn_ipfw(ipfw_dyn_rule *d, int pcwidth, int bcwidth) 178698943Sluigi{ 178798943Sluigi struct protoent *pe; 178898943Sluigi struct in_addr a; 1789115793Sticso uint16_t rulenum; 1790159160Smlaier char buf[INET6_ADDRSTRLEN]; 179198943Sluigi 1792187764Sluigi if (!co.do_expired) { 179398943Sluigi if (!d->expire && !(d->dyn_type == O_LIMIT_PARENT)) 179498943Sluigi return; 179598943Sluigi } 1796115793Sticso bcopy(&d->rule, &rulenum, sizeof(rulenum)); 1797117328Sluigi printf("%05d", rulenum); 1798206843Sluigi if (pcwidth > 0 || bcwidth > 0) { 1799206843Sluigi printf(" "); 1800206843Sluigi pr_u64(&d->pcnt, pcwidth); 1801206843Sluigi pr_u64(&d->bcnt, bcwidth); 1802206843Sluigi printf("(%ds)", d->expire); 1803206843Sluigi } 180498943Sluigi switch (d->dyn_type) { 180598943Sluigi case O_LIMIT_PARENT: 180698943Sluigi printf(" PARENT %d", d->count); 180798943Sluigi break; 180898943Sluigi case O_LIMIT: 180998943Sluigi printf(" LIMIT"); 181098943Sluigi break; 181198943Sluigi case O_KEEP_STATE: /* bidir, no mask */ 1812106505Smaxim printf(" STATE"); 181398943Sluigi break; 181498943Sluigi } 181598943Sluigi 181698943Sluigi if ((pe = getprotobynumber(d->id.proto)) != NULL) 181798943Sluigi printf(" %s", pe->p_name); 181898943Sluigi else 181998943Sluigi printf(" proto %u", d->id.proto); 182098943Sluigi 1821159160Smlaier if (d->id.addr_type == 4) { 1822159160Smlaier a.s_addr = htonl(d->id.src_ip); 1823159160Smlaier printf(" %s %d", inet_ntoa(a), d->id.src_port); 182498943Sluigi 1825159160Smlaier a.s_addr = htonl(d->id.dst_ip); 1826159160Smlaier printf(" <-> %s %d", inet_ntoa(a), d->id.dst_port); 1827159160Smlaier } else if (d->id.addr_type == 6) { 1828159160Smlaier printf(" %s %d", inet_ntop(AF_INET6, &d->id.src_ip6, buf, 1829159160Smlaier sizeof(buf)), d->id.src_port); 1830159160Smlaier printf(" <-> %s %d", inet_ntop(AF_INET6, &d->id.dst_ip6, buf, 1831159160Smlaier sizeof(buf)), d->id.dst_port); 1832159160Smlaier } else 1833159160Smlaier printf(" UNKNOWN <-> UNKNOWN\n"); 1834220804Sglebius 183598943Sluigi printf("\n"); 183698943Sluigi} 183798943Sluigi 1838101978Sluigi/* 1839101978Sluigi * This one handles all set-related commands 1840101978Sluigi * ipfw set { show | enable | disable } 1841101978Sluigi * ipfw set swap X Y 1842101978Sluigi * ipfw set move X to Y 1843101978Sluigi * ipfw set move rule X to Y 1844101978Sluigi */ 1845187767Sluigivoid 1846204591Sluigiipfw_sets_handler(char *av[]) 1847101978Sluigi{ 1848117328Sluigi uint32_t set_disable, masks[2]; 1849101978Sluigi int i, nbytes; 1850117328Sluigi uint16_t rulenum; 1851117328Sluigi uint8_t cmd, new_set; 1852101978Sluigi 1853101978Sluigi av++; 1854101978Sluigi 1855204591Sluigi if (av[0] == NULL) 1856101978Sluigi errx(EX_USAGE, "set needs command"); 1857140271Sbrooks if (_substrcmp(*av, "show") == 0) { 1858204717Sluigi void *data = NULL; 1859117469Sluigi char const *msg; 1860204717Sluigi int nalloc; 1861101978Sluigi 1862204717Sluigi nalloc = nbytes = sizeof(struct ip_fw); 1863204717Sluigi while (nbytes >= nalloc) { 1864204717Sluigi if (data) 1865204717Sluigi free(data); 1866204717Sluigi nalloc = nalloc * 2 + 200; 1867204717Sluigi nbytes = nalloc; 1868206843Sluigi data = safe_calloc(1, nbytes); 1869206843Sluigi if (do_cmd(IP_FW_GET, data, (uintptr_t)&nbytes) < 0) 1870206843Sluigi err(EX_OSERR, "getsockopt(IP_FW_GET)"); 1871204717Sluigi } 1872204717Sluigi 1873115793Sticso bcopy(&((struct ip_fw *)data)->next_rule, 1874115793Sticso &set_disable, sizeof(set_disable)); 1875101978Sluigi 1876117655Sluigi for (i = 0, msg = "disable" ; i < RESVD_SET; i++) 1877117577Sluigi if ((set_disable & (1<<i))) { 1878101978Sluigi printf("%s %d", msg, i); 1879101978Sluigi msg = ""; 1880101978Sluigi } 1881101978Sluigi msg = (set_disable) ? " enable" : "enable"; 1882117655Sluigi for (i = 0; i < RESVD_SET; i++) 1883117577Sluigi if (!(set_disable & (1<<i))) { 1884101978Sluigi printf("%s %d", msg, i); 1885101978Sluigi msg = ""; 1886101978Sluigi } 1887101978Sluigi printf("\n"); 1888140271Sbrooks } else if (_substrcmp(*av, "swap") == 0) { 1889204591Sluigi av++; 1890204591Sluigi if ( av[0] == NULL || av[1] == NULL ) 1891101978Sluigi errx(EX_USAGE, "set swap needs 2 set numbers\n"); 1892101978Sluigi rulenum = atoi(av[0]); 1893101978Sluigi new_set = atoi(av[1]); 1894117655Sluigi if (!isdigit(*(av[0])) || rulenum > RESVD_SET) 1895101978Sluigi errx(EX_DATAERR, "invalid set number %s\n", av[0]); 1896117655Sluigi if (!isdigit(*(av[1])) || new_set > RESVD_SET) 1897101978Sluigi errx(EX_DATAERR, "invalid set number %s\n", av[1]); 1898101978Sluigi masks[0] = (4 << 24) | (new_set << 16) | (rulenum); 1899117328Sluigi i = do_cmd(IP_FW_DEL, masks, sizeof(uint32_t)); 1900140271Sbrooks } else if (_substrcmp(*av, "move") == 0) { 1901204591Sluigi av++; 1902204717Sluigi if (av[0] && _substrcmp(*av, "rule") == 0) { 1903101978Sluigi cmd = 2; 1904204591Sluigi av++; 1905101978Sluigi } else 1906101978Sluigi cmd = 3; 1907204591Sluigi if (av[0] == NULL || av[1] == NULL || av[2] == NULL || 1908204591Sluigi av[3] != NULL || _substrcmp(av[1], "to") != 0) 1909101978Sluigi errx(EX_USAGE, "syntax: set move [rule] X to Y\n"); 1910101978Sluigi rulenum = atoi(av[0]); 1911101978Sluigi new_set = atoi(av[2]); 1912117655Sluigi if (!isdigit(*(av[0])) || (cmd == 3 && rulenum > RESVD_SET) || 1913182823Srik (cmd == 2 && rulenum == IPFW_DEFAULT_RULE) ) 1914101978Sluigi errx(EX_DATAERR, "invalid source number %s\n", av[0]); 1915117655Sluigi if (!isdigit(*(av[2])) || new_set > RESVD_SET) 1916101978Sluigi errx(EX_DATAERR, "invalid dest. set %s\n", av[1]); 1917101978Sluigi masks[0] = (cmd << 24) | (new_set << 16) | (rulenum); 1918117328Sluigi i = do_cmd(IP_FW_DEL, masks, sizeof(uint32_t)); 1919140271Sbrooks } else if (_substrcmp(*av, "disable") == 0 || 1920140271Sbrooks _substrcmp(*av, "enable") == 0 ) { 1921140271Sbrooks int which = _substrcmp(*av, "enable") == 0 ? 1 : 0; 1922101978Sluigi 1923204591Sluigi av++; 1924101978Sluigi masks[0] = masks[1] = 0; 1925101978Sluigi 1926204717Sluigi while (av[0]) { 1927101978Sluigi if (isdigit(**av)) { 1928101978Sluigi i = atoi(*av); 1929117655Sluigi if (i < 0 || i > RESVD_SET) 1930101978Sluigi errx(EX_DATAERR, 1931101978Sluigi "invalid set number %d\n", i); 1932101978Sluigi masks[which] |= (1<<i); 1933140271Sbrooks } else if (_substrcmp(*av, "disable") == 0) 1934101978Sluigi which = 0; 1935140271Sbrooks else if (_substrcmp(*av, "enable") == 0) 1936101978Sluigi which = 1; 1937101978Sluigi else 1938101978Sluigi errx(EX_DATAERR, 1939101978Sluigi "invalid set command %s\n", *av); 1940204591Sluigi av++; 1941101978Sluigi } 1942101978Sluigi if ( (masks[0] & masks[1]) != 0 ) 1943101978Sluigi errx(EX_DATAERR, 1944101978Sluigi "cannot enable and disable the same set\n"); 1945101978Sluigi 1946117328Sluigi i = do_cmd(IP_FW_DEL, masks, sizeof(masks)); 1947101978Sluigi if (i) 1948101978Sluigi warn("set enable/disable: setsockopt(IP_FW_DEL)"); 1949101978Sluigi } else 1950101978Sluigi errx(EX_USAGE, "invalid set command %s\n", *av); 1951101978Sluigi} 1952101978Sluigi 1953187767Sluigivoid 1954204591Sluigiipfw_sysctl_handler(char *av[], int which) 1955109126Sdillon{ 1956109126Sdillon av++; 1957109126Sdillon 1958204591Sluigi if (av[0] == NULL) { 1959109126Sdillon warnx("missing keyword to enable/disable\n"); 1960140271Sbrooks } else if (_substrcmp(*av, "firewall") == 0) { 1961116770Sluigi sysctlbyname("net.inet.ip.fw.enable", NULL, 0, 1962116770Sluigi &which, sizeof(which)); 1963206266Sume sysctlbyname("net.inet6.ip6.fw.enable", NULL, 0, 1964206266Sume &which, sizeof(which)); 1965140271Sbrooks } else if (_substrcmp(*av, "one_pass") == 0) { 1966116770Sluigi sysctlbyname("net.inet.ip.fw.one_pass", NULL, 0, 1967116770Sluigi &which, sizeof(which)); 1968140271Sbrooks } else if (_substrcmp(*av, "debug") == 0) { 1969116770Sluigi sysctlbyname("net.inet.ip.fw.debug", NULL, 0, 1970116770Sluigi &which, sizeof(which)); 1971140271Sbrooks } else if (_substrcmp(*av, "verbose") == 0) { 1972116770Sluigi sysctlbyname("net.inet.ip.fw.verbose", NULL, 0, 1973116770Sluigi &which, sizeof(which)); 1974140271Sbrooks } else if (_substrcmp(*av, "dyn_keepalive") == 0) { 1975116770Sluigi sysctlbyname("net.inet.ip.fw.dyn_keepalive", NULL, 0, 1976116770Sluigi &which, sizeof(which)); 1977204591Sluigi#ifndef NO_ALTQ 1978140271Sbrooks } else if (_substrcmp(*av, "altq") == 0) { 1979136071Sgreen altq_set_enabled(which); 1980204591Sluigi#endif 1981109126Sdillon } else { 1982109126Sdillon warnx("unrecognize enable/disable keyword: %s\n", *av); 1983109126Sdillon } 1984109126Sdillon} 1985109126Sdillon 1986187767Sluigivoid 1987187767Sluigiipfw_list(int ac, char *av[], int show_counters) 198898943Sluigi{ 198998943Sluigi struct ip_fw *r; 199098943Sluigi ipfw_dyn_rule *dynrules, *d; 199198943Sluigi 1992117469Sluigi#define NEXT(r) ((struct ip_fw *)((char *)r + RULESIZE(r))) 1993117469Sluigi char *lim; 1994117469Sluigi void *data = NULL; 1995112189Smaxim int bcwidth, n, nbytes, nstat, ndyn, pcwidth, width; 199698943Sluigi int exitval = EX_OK; 199798943Sluigi int lac; 199898943Sluigi char **lav; 1999117469Sluigi u_long rnum, last; 200098943Sluigi char *endptr; 200198943Sluigi int seen = 0; 2002170923Smaxim uint8_t set; 200398943Sluigi 2004187764Sluigi const int ocmd = co.do_pipe ? IP_DUMMYNET_GET : IP_FW_GET; 200598943Sluigi int nalloc = 1024; /* start somewhere... */ 200698943Sluigi 2007135036Smaxim last = 0; 2008135036Smaxim 2009187764Sluigi if (co.test_only) { 2010117328Sluigi fprintf(stderr, "Testing only, list disabled\n"); 2011117328Sluigi return; 2012117328Sluigi } 2013204591Sluigi if (co.do_pipe) { 2014204591Sluigi dummynet_list(ac, av, show_counters); 2015204591Sluigi return; 2016204591Sluigi } 2017117328Sluigi 201898943Sluigi ac--; 201998943Sluigi av++; 202098943Sluigi 202198943Sluigi /* get rules or pipes from kernel, resizing array as necessary */ 202298943Sluigi nbytes = nalloc; 202398943Sluigi 202498943Sluigi while (nbytes >= nalloc) { 202598943Sluigi nalloc = nalloc * 2 + 200; 202698943Sluigi nbytes = nalloc; 2027187716Sluigi data = safe_realloc(data, nbytes); 2028119740Stmm if (do_cmd(ocmd, data, (uintptr_t)&nbytes) < 0) 202998943Sluigi err(EX_OSERR, "getsockopt(IP_%s_GET)", 2030187764Sluigi co.do_pipe ? "DUMMYNET" : "FW"); 203198943Sluigi } 203298943Sluigi 203398943Sluigi /* 203498943Sluigi * Count static rules. They have variable size so we 203598943Sluigi * need to scan the list to count them. 203698943Sluigi */ 2037117469Sluigi for (nstat = 1, r = data, lim = (char *)data + nbytes; 2038182823Srik r->rulenum < IPFW_DEFAULT_RULE && (char *)r < lim; 2039117469Sluigi ++nstat, r = NEXT(r) ) 204098943Sluigi ; /* nothing */ 204198943Sluigi 204298943Sluigi /* 204398943Sluigi * Count dynamic rules. This is easier as they have 204498943Sluigi * fixed size. 204598943Sluigi */ 2046117469Sluigi r = NEXT(r); 204798943Sluigi dynrules = (ipfw_dyn_rule *)r ; 2048117469Sluigi n = (char *)r - (char *)data; 204998943Sluigi ndyn = (nbytes - n) / sizeof *dynrules; 205098943Sluigi 2051112189Smaxim /* if showing stats, figure out column widths ahead of time */ 2052112189Smaxim bcwidth = pcwidth = 0; 2053117469Sluigi if (show_counters) { 2054117469Sluigi for (n = 0, r = data; n < nstat; n++, r = NEXT(r)) { 2055170923Smaxim /* skip rules from another set */ 2056187764Sluigi if (co.use_set && r->set != co.use_set - 1) 2057170923Smaxim continue; 2058170923Smaxim 2059112189Smaxim /* packet counter */ 2060206843Sluigi width = pr_u64(&r->pcnt, 0); 2061112189Smaxim if (width > pcwidth) 2062112189Smaxim pcwidth = width; 2063112189Smaxim 2064112189Smaxim /* byte counter */ 2065206843Sluigi width = pr_u64(&r->bcnt, 0); 2066112189Smaxim if (width > bcwidth) 2067112189Smaxim bcwidth = width; 2068112189Smaxim } 2069112189Smaxim } 2070187764Sluigi if (co.do_dynamic && ndyn) { 2071112189Smaxim for (n = 0, d = dynrules; n < ndyn; n++, d++) { 2072187764Sluigi if (co.use_set) { 2073170923Smaxim /* skip rules from another set */ 2074171989Smaxim bcopy((char *)&d->rule + sizeof(uint16_t), 2075170923Smaxim &set, sizeof(uint8_t)); 2076187764Sluigi if (set != co.use_set - 1) 2077170923Smaxim continue; 2078170923Smaxim } 2079206843Sluigi width = pr_u64(&d->pcnt, 0); 2080112189Smaxim if (width > pcwidth) 2081112189Smaxim pcwidth = width; 2082112189Smaxim 2083206843Sluigi width = pr_u64(&d->bcnt, 0); 2084112189Smaxim if (width > bcwidth) 2085112189Smaxim bcwidth = width; 2086112189Smaxim } 2087112189Smaxim } 208898943Sluigi /* if no rule numbers were specified, list all rules */ 208998943Sluigi if (ac == 0) { 2090170923Smaxim for (n = 0, r = data; n < nstat; n++, r = NEXT(r)) { 2091187764Sluigi if (co.use_set && r->set != co.use_set - 1) 2092170923Smaxim continue; 2093112189Smaxim show_ipfw(r, pcwidth, bcwidth); 2094170923Smaxim } 209598943Sluigi 2096187764Sluigi if (co.do_dynamic && ndyn) { 209798943Sluigi printf("## Dynamic rules (%d):\n", ndyn); 2098170923Smaxim for (n = 0, d = dynrules; n < ndyn; n++, d++) { 2099187764Sluigi if (co.use_set) { 2100171989Smaxim bcopy((char *)&d->rule + sizeof(uint16_t), 2101170923Smaxim &set, sizeof(uint8_t)); 2102187764Sluigi if (set != co.use_set - 1) 2103170923Smaxim continue; 2104170923Smaxim } 2105112189Smaxim show_dyn_ipfw(d, pcwidth, bcwidth); 210698943Sluigi } 2107170923Smaxim } 210898943Sluigi goto done; 210998943Sluigi } 211098943Sluigi 211198943Sluigi /* display specific rules requested on command line */ 211298943Sluigi 211398943Sluigi for (lac = ac, lav = av; lac != 0; lac--) { 211498943Sluigi /* convert command line rule # */ 2115117469Sluigi last = rnum = strtoul(*lav++, &endptr, 10); 2116117469Sluigi if (*endptr == '-') 2117117469Sluigi last = strtoul(endptr+1, &endptr, 10); 211898943Sluigi if (*endptr) { 211998943Sluigi exitval = EX_USAGE; 212098943Sluigi warnx("invalid rule number: %s", *(lav - 1)); 212198943Sluigi continue; 212298943Sluigi } 2123117469Sluigi for (n = seen = 0, r = data; n < nstat; n++, r = NEXT(r) ) { 2124117469Sluigi if (r->rulenum > last) 212598943Sluigi break; 2126187764Sluigi if (co.use_set && r->set != co.use_set - 1) 2127170923Smaxim continue; 2128117469Sluigi if (r->rulenum >= rnum && r->rulenum <= last) { 2129112189Smaxim show_ipfw(r, pcwidth, bcwidth); 213098943Sluigi seen = 1; 213198943Sluigi } 213298943Sluigi } 213398943Sluigi if (!seen) { 213498943Sluigi /* give precedence to other error(s) */ 213598943Sluigi if (exitval == EX_OK) 213698943Sluigi exitval = EX_UNAVAILABLE; 213798943Sluigi warnx("rule %lu does not exist", rnum); 213898943Sluigi } 213998943Sluigi } 214098943Sluigi 2141187764Sluigi if (co.do_dynamic && ndyn) { 214298943Sluigi printf("## Dynamic rules:\n"); 214398943Sluigi for (lac = ac, lav = av; lac != 0; lac--) { 2144145246Sbrooks last = rnum = strtoul(*lav++, &endptr, 10); 2145117469Sluigi if (*endptr == '-') 2146117469Sluigi last = strtoul(endptr+1, &endptr, 10); 214798943Sluigi if (*endptr) 214898943Sluigi /* already warned */ 214998943Sluigi continue; 215098943Sluigi for (n = 0, d = dynrules; n < ndyn; n++, d++) { 2151115793Sticso uint16_t rulenum; 2152115793Sticso 2153115793Sticso bcopy(&d->rule, &rulenum, sizeof(rulenum)); 2154115793Sticso if (rulenum > rnum) 215598943Sluigi break; 2156187764Sluigi if (co.use_set) { 2157171989Smaxim bcopy((char *)&d->rule + sizeof(uint16_t), 2158170923Smaxim &set, sizeof(uint8_t)); 2159187764Sluigi if (set != co.use_set - 1) 2160170923Smaxim continue; 2161170923Smaxim } 2162117469Sluigi if (r->rulenum >= rnum && r->rulenum <= last) 2163112189Smaxim show_dyn_ipfw(d, pcwidth, bcwidth); 216498943Sluigi } 216598943Sluigi } 216698943Sluigi } 216798943Sluigi 216898943Sluigi ac = 0; 216998943Sluigi 217098943Sluigidone: 217198943Sluigi free(data); 217298943Sluigi 217398943Sluigi if (exitval != EX_OK) 217498943Sluigi exit(exitval); 2175117469Sluigi#undef NEXT 217698943Sluigi} 217798943Sluigi 217898943Sluigistatic int 217998943Sluigilookup_host (char *host, struct in_addr *ipaddr) 218098943Sluigi{ 218198943Sluigi struct hostent *he; 218298943Sluigi 218398943Sluigi if (!inet_aton(host, ipaddr)) { 218498943Sluigi if ((he = gethostbyname(host)) == NULL) 218598943Sluigi return(-1); 218698943Sluigi *ipaddr = *(struct in_addr *)he->h_addr_list[0]; 218798943Sluigi } 218898943Sluigi return(0); 218998943Sluigi} 219098943Sluigi 219198943Sluigi/* 219298943Sluigi * fills the addr and mask fields in the instruction as appropriate from av. 219398943Sluigi * Update length as appropriate. 219498943Sluigi * The following formats are allowed: 219598943Sluigi * me returns O_IP_*_ME 219698943Sluigi * 1.2.3.4 single IP address 219798943Sluigi * 1.2.3.4:5.6.7.8 address:mask 219898943Sluigi * 1.2.3.4/24 address/mask 219998943Sluigi * 1.2.3.4/26{1,6,5,4,23} set of addresses in a subnet 2200117328Sluigi * We can have multiple comma-separated address/mask entries. 220198943Sluigi */ 220298943Sluigistatic void 2203248505Smelifarofill_ip(ipfw_insn_ip *cmd, char *av, int cblen) 220498943Sluigi{ 2205117328Sluigi int len = 0; 2206117328Sluigi uint32_t *d = ((ipfw_insn_u32 *)cmd)->d; 2207265699Smelifaro uint32_t tables_max; 220898943Sluigi 220998943Sluigi cmd->o.len &= ~F_LEN_MASK; /* zero len */ 221098943Sluigi 2211140271Sbrooks if (_substrcmp(av, "any") == 0) 221298943Sluigi return; 221398943Sluigi 2214140271Sbrooks if (_substrcmp(av, "me") == 0) { 221598943Sluigi cmd->o.len |= F_INSN_SIZE(ipfw_insn); 221698943Sluigi return; 221798943Sluigi } 221898943Sluigi 2219140271Sbrooks if (strncmp(av, "table(", 6) == 0) { 2220130281Sru char *p = strchr(av + 6, ','); 2221130281Sru 2222130281Sru if (p) 2223130281Sru *p++ = '\0'; 2224130281Sru cmd->o.opcode = O_IP_DST_LOOKUP; 2225130281Sru cmd->o.arg1 = strtoul(av + 6, NULL, 0); 2226265699Smelifaro tables_max = ipfw_get_tables_max(); 2227265699Smelifaro if (cmd->o.arg1 > tables_max) 2228265699Smelifaro errx(EX_USAGE, "The table number exceeds the maximum " 2229265699Smelifaro "allowed value (%u)", tables_max - 1); 2230130281Sru if (p) { 2231130281Sru cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32); 2232130281Sru d[0] = strtoul(p, NULL, 0); 2233130281Sru } else 2234130281Sru cmd->o.len |= F_INSN_SIZE(ipfw_insn); 2235130281Sru return; 2236130281Sru } 2237130281Sru 2238117328Sluigi while (av) { 2239117328Sluigi /* 2240117328Sluigi * After the address we can have '/' or ':' indicating a mask, 2241117328Sluigi * ',' indicating another address follows, '{' indicating a 2242117328Sluigi * set of addresses of unspecified size. 2243117328Sluigi */ 2244165851Smlaier char *t = NULL, *p = strpbrk(av, "/:,{"); 2245117328Sluigi int masklen; 2246187477Sluigi char md, nd = '\0'; 2247117328Sluigi 2248248505Smelifaro CHECK_LENGTH(cblen, F_INSN_SIZE(ipfw_insn) + 2 + len); 2249248505Smelifaro 225098943Sluigi if (p) { 225198943Sluigi md = *p; 225298943Sluigi *p++ = '\0'; 2253165851Smlaier if ((t = strpbrk(p, ",{")) != NULL) { 2254165851Smlaier nd = *t; 2255165851Smlaier *t = '\0'; 2256165851Smlaier } 2257117328Sluigi } else 2258117328Sluigi md = '\0'; 225998943Sluigi 2260117328Sluigi if (lookup_host(av, (struct in_addr *)&d[0]) != 0) 226198943Sluigi errx(EX_NOHOST, "hostname ``%s'' unknown", av); 226298943Sluigi switch (md) { 226398943Sluigi case ':': 2264117328Sluigi if (!inet_aton(p, (struct in_addr *)&d[1])) 226598943Sluigi errx(EX_DATAERR, "bad netmask ``%s''", p); 226698943Sluigi break; 226798943Sluigi case '/': 2268117328Sluigi masklen = atoi(p); 2269117328Sluigi if (masklen == 0) 2270117328Sluigi d[1] = htonl(0); /* mask */ 2271117328Sluigi else if (masklen > 32) 227298943Sluigi errx(EX_DATAERR, "bad width ``%s''", p); 227398943Sluigi else 2274117328Sluigi d[1] = htonl(~0 << (32 - masklen)); 227598943Sluigi break; 2276117328Sluigi case '{': /* no mask, assume /24 and put back the '{' */ 2277117328Sluigi d[1] = htonl(~0 << (32 - 24)); 2278117328Sluigi *(--p) = md; 2279117328Sluigi break; 2280117328Sluigi 2281117328Sluigi case ',': /* single address plus continuation */ 2282117328Sluigi *(--p) = md; 2283117328Sluigi /* FALLTHROUGH */ 2284117328Sluigi case 0: /* initialization value */ 228598943Sluigi default: 2286117328Sluigi d[1] = htonl(~0); /* force /32 */ 228798943Sluigi break; 228898943Sluigi } 2289117328Sluigi d[0] &= d[1]; /* mask base address with mask */ 2290165851Smlaier if (t) 2291165851Smlaier *t = nd; 2292117328Sluigi /* find next separator */ 229398943Sluigi if (p) 2294117328Sluigi p = strpbrk(p, ",{"); 2295117328Sluigi if (p && *p == '{') { 2296117328Sluigi /* 2297117328Sluigi * We have a set of addresses. They are stored as follows: 2298117328Sluigi * arg1 is the set size (powers of 2, 2..256) 2299117328Sluigi * addr is the base address IN HOST FORMAT 2300117328Sluigi * mask.. is an array of arg1 bits (rounded up to 2301117328Sluigi * the next multiple of 32) with bits set 2302117328Sluigi * for each host in the map. 2303117328Sluigi */ 2304117328Sluigi uint32_t *map = (uint32_t *)&cmd->mask; 230598943Sluigi int low, high; 2306117577Sluigi int i = contigmask((uint8_t *)&(d[1]), 32); 230798943Sluigi 2308117328Sluigi if (len > 0) 2309117328Sluigi errx(EX_DATAERR, "address set cannot be in a list"); 2310117328Sluigi if (i < 24 || i > 31) 2311117328Sluigi errx(EX_DATAERR, "invalid set with mask %d\n", i); 2312117328Sluigi cmd->o.arg1 = 1<<(32-i); /* map length */ 2313117328Sluigi d[0] = ntohl(d[0]); /* base addr in host format */ 231498943Sluigi cmd->o.opcode = O_IP_DST_SET; /* default */ 231598943Sluigi cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32) + (cmd->o.arg1+31)/32; 2316101117Sluigi for (i = 0; i < (cmd->o.arg1+31)/32 ; i++) 2317117328Sluigi map[i] = 0; /* clear map */ 231898943Sluigi 2319117328Sluigi av = p + 1; 2320117328Sluigi low = d[0] & 0xff; 232198943Sluigi high = low + cmd->o.arg1 - 1; 2322117328Sluigi /* 2323117328Sluigi * Here, i stores the previous value when we specify a range 2324117328Sluigi * of addresses within a mask, e.g. 45-63. i = -1 means we 2325117328Sluigi * have no previous value. 2326117328Sluigi */ 2327116716Sluigi i = -1; /* previous value in a range */ 232898943Sluigi while (isdigit(*av)) { 232998943Sluigi char *s; 2330117328Sluigi int a = strtol(av, &s, 0); 233198943Sluigi 2332117328Sluigi if (s == av) { /* no parameter */ 2333117328Sluigi if (*av != '}') 2334117328Sluigi errx(EX_DATAERR, "set not closed\n"); 2335117328Sluigi if (i != -1) 2336117328Sluigi errx(EX_DATAERR, "incomplete range %d-", i); 2337117328Sluigi break; 2338117328Sluigi } 2339117328Sluigi if (a < low || a > high) 2340117328Sluigi errx(EX_DATAERR, "addr %d out of range [%d-%d]\n", 234198943Sluigi a, low, high); 234298943Sluigi a -= low; 2343116716Sluigi if (i == -1) /* no previous in range */ 2344116716Sluigi i = a; 2345116716Sluigi else { /* check that range is valid */ 2346116716Sluigi if (i > a) 2347116716Sluigi errx(EX_DATAERR, "invalid range %d-%d", 2348116716Sluigi i+low, a+low); 2349116716Sluigi if (*s == '-') 2350116716Sluigi errx(EX_DATAERR, "double '-' in range"); 2351116716Sluigi } 2352116716Sluigi for (; i <= a; i++) 2353117328Sluigi map[i/32] |= 1<<(i & 31); 2354116716Sluigi i = -1; 2355116716Sluigi if (*s == '-') 2356116716Sluigi i = a; 2357117328Sluigi else if (*s == '}') 2358116716Sluigi break; 235998943Sluigi av = s+1; 236098943Sluigi } 236198943Sluigi return; 236298943Sluigi } 2363117328Sluigi av = p; 2364117328Sluigi if (av) /* then *av must be a ',' */ 2365117328Sluigi av++; 236698943Sluigi 2367117328Sluigi /* Check this entry */ 2368117328Sluigi if (d[1] == 0) { /* "any", specified as x.x.x.x/0 */ 2369117328Sluigi /* 2370117328Sluigi * 'any' turns the entire list into a NOP. 2371117328Sluigi * 'not any' never matches, so it is removed from the 2372117328Sluigi * list unless it is the only item, in which case we 2373117328Sluigi * report an error. 2374117328Sluigi */ 2375117328Sluigi if (cmd->o.len & F_NOT) { /* "not any" never matches */ 2376117328Sluigi if (av == NULL && len == 0) /* only this entry */ 2377117328Sluigi errx(EX_DATAERR, "not any never matches"); 2378117328Sluigi } 2379117328Sluigi /* else do nothing and skip this entry */ 2380128067Smaxim return; 2381117328Sluigi } 2382117328Sluigi /* A single IP can be stored in an optimized format */ 2383204591Sluigi if (d[1] == (uint32_t)~0 && av == NULL && len == 0) { 238498943Sluigi cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32); 2385117328Sluigi return; 2386117328Sluigi } 2387117328Sluigi len += 2; /* two words... */ 2388117328Sluigi d += 2; 2389117328Sluigi } /* end while */ 2390162363Sjhay if (len + 1 > F_LEN_MASK) 2391162363Sjhay errx(EX_DATAERR, "address list too long"); 2392117328Sluigi cmd->o.len |= len+1; 239398943Sluigi} 239498943Sluigi 239598943Sluigi 2396145246Sbrooks/* n2mask sets n bits of the mask */ 2397187769Sluigivoid 2398145246Sbrooksn2mask(struct in6_addr *mask, int n) 2399145246Sbrooks{ 2400145246Sbrooks static int minimask[9] = 2401145246Sbrooks { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff }; 2402145246Sbrooks u_char *p; 2403145246Sbrooks 2404145246Sbrooks memset(mask, 0, sizeof(struct in6_addr)); 2405145246Sbrooks p = (u_char *) mask; 2406145246Sbrooks for (; n > 0; p++, n -= 8) { 2407145246Sbrooks if (n >= 8) 2408145246Sbrooks *p = 0xff; 2409145246Sbrooks else 2410145246Sbrooks *p = minimask[n]; 2411145246Sbrooks } 2412145246Sbrooks return; 2413145246Sbrooks} 2414145246Sbrooks 241598943Sluigi/* 241698943Sluigi * helper function to process a set of flags and set bits in the 241798943Sluigi * appropriate masks. 241898943Sluigi */ 241998943Sluigistatic void 242098943Sluigifill_flags(ipfw_insn *cmd, enum ipfw_opcodes opcode, 242198943Sluigi struct _s_x *flags, char *p) 242298943Sluigi{ 2423117328Sluigi uint8_t set=0, clear=0; 242498943Sluigi 242598943Sluigi while (p && *p) { 242698943Sluigi char *q; /* points to the separator */ 242798943Sluigi int val; 2428117328Sluigi uint8_t *which; /* mask we are working on */ 242998943Sluigi 243098943Sluigi if (*p == '!') { 243198943Sluigi p++; 243298943Sluigi which = &clear; 243398943Sluigi } else 243498943Sluigi which = &set; 243598943Sluigi q = strchr(p, ','); 243698943Sluigi if (q) 243798943Sluigi *q++ = '\0'; 243898943Sluigi val = match_token(flags, p); 243998943Sluigi if (val <= 0) 244098943Sluigi errx(EX_DATAERR, "invalid flag %s", p); 2441117328Sluigi *which |= (uint8_t)val; 244298943Sluigi p = q; 244398943Sluigi } 2444220802Sglebius cmd->opcode = opcode; 2445220802Sglebius cmd->len = (cmd->len & (F_NOT | F_OR)) | 1; 2446220802Sglebius cmd->arg1 = (set & 0xff) | ( (clear & 0xff) << 8); 244798943Sluigi} 244898943Sluigi 244998943Sluigi 2450187767Sluigivoid 2451204591Sluigiipfw_delete(char *av[]) 245298943Sluigi{ 2453117328Sluigi uint32_t rulenum; 245498943Sluigi int i; 245598943Sluigi int exitval = EX_OK; 2456101628Sluigi int do_set = 0; 245798943Sluigi 2458204591Sluigi av++; 2459130013Scsjp NEED1("missing rule specification"); 2460204591Sluigi if ( *av && _substrcmp(*av, "set") == 0) { 2461170923Smaxim /* Do not allow using the following syntax: 2462170923Smaxim * ipfw set N delete set M 2463170923Smaxim */ 2464187764Sluigi if (co.use_set) 2465170923Smaxim errx(EX_DATAERR, "invalid syntax"); 2466101978Sluigi do_set = 1; /* delete set */ 2467204591Sluigi av++; 2468101978Sluigi } 246998943Sluigi 247098943Sluigi /* Rule number */ 2471204591Sluigi while (*av && isdigit(**av)) { 2472204591Sluigi i = atoi(*av); av++; 2473187764Sluigi if (co.do_nat) { 2474165648Spiso exitval = do_cmd(IP_FW_NAT_DEL, &i, sizeof i); 2475165648Spiso if (exitval) { 2476165648Spiso exitval = EX_UNAVAILABLE; 2477165648Spiso warn("rule %u not available", i); 2478165648Spiso } 2479187764Sluigi } else if (co.do_pipe) { 2480187769Sluigi exitval = ipfw_delete_pipe(co.do_pipe, i); 248198943Sluigi } else { 2482187764Sluigi if (co.use_set) 2483170923Smaxim rulenum = (i & 0xffff) | (5 << 24) | 2484187764Sluigi ((co.use_set - 1) << 16); 2485170923Smaxim else 2486101978Sluigi rulenum = (i & 0xffff) | (do_set << 24); 2487117328Sluigi i = do_cmd(IP_FW_DEL, &rulenum, sizeof rulenum); 248898943Sluigi if (i) { 248998943Sluigi exitval = EX_UNAVAILABLE; 249098943Sluigi warn("rule %u: setsockopt(IP_FW_DEL)", 249198943Sluigi rulenum); 249298943Sluigi } 249398943Sluigi } 249498943Sluigi } 249598943Sluigi if (exitval != EX_OK) 249698943Sluigi exit(exitval); 249798943Sluigi} 249898943Sluigi 249998943Sluigi 250098943Sluigi/* 250198943Sluigi * fill the interface structure. We do not check the name as we can 250298943Sluigi * create interfaces dynamically, so checking them at insert time 250398943Sluigi * makes relatively little sense. 2504220802Sglebius * Interface names containing '*', '?', or '[' are assumed to be shell 2505121816Sbrooks * patterns which match interfaces. 250698943Sluigi */ 250798943Sluigistatic void 2508248505Smelifarofill_iface(ipfw_insn_if *cmd, char *arg, int cblen) 250998943Sluigi{ 251098943Sluigi cmd->name[0] = '\0'; 251198943Sluigi cmd->o.len |= F_INSN_SIZE(ipfw_insn_if); 251298943Sluigi 2513248505Smelifaro CHECK_CMDLEN; 2514248505Smelifaro 251598943Sluigi /* Parse the interface or address */ 2516140271Sbrooks if (strcmp(arg, "any") == 0) 251798943Sluigi cmd->o.len = 0; /* effectively ignore this command */ 2518234597Smelifaro else if (strncmp(arg, "table(", 6) == 0) { 2519234597Smelifaro char *p = strchr(arg + 6, ','); 2520234597Smelifaro if (p) 2521234597Smelifaro *p++ = '\0'; 2522234597Smelifaro cmd->name[0] = '\1'; /* Special value indicating table */ 2523234597Smelifaro cmd->p.glob = strtoul(arg + 6, NULL, 0); 2524234597Smelifaro } else if (!isdigit(*arg)) { 2525121816Sbrooks strlcpy(cmd->name, arg, sizeof(cmd->name)); 2526121816Sbrooks cmd->p.glob = strpbrk(arg, "*?[") != NULL ? 1 : 0; 252798943Sluigi } else if (!inet_aton(arg, &cmd->p.ip)) 252898943Sluigi errx(EX_DATAERR, "bad ip address ``%s''", arg); 252998943Sluigi} 253098943Sluigi 253198943Sluigistatic void 2532169424Smaximget_mac_addr_mask(const char *p, uint8_t *addr, uint8_t *mask) 253398943Sluigi{ 2534204591Sluigi int i; 2535204591Sluigi size_t l; 2536169424Smaxim char *ap, *ptr, *optr; 2537169424Smaxim struct ether_addr *mac; 2538169424Smaxim const char *macset = "0123456789abcdefABCDEF:"; 253998943Sluigi 2540169424Smaxim if (strcmp(p, "any") == 0) { 2541169424Smaxim for (i = 0; i < ETHER_ADDR_LEN; i++) 2542169424Smaxim addr[i] = mask[i] = 0; 254398943Sluigi return; 2544169424Smaxim } 254598943Sluigi 2546169424Smaxim optr = ptr = strdup(p); 2547169424Smaxim if ((ap = strsep(&ptr, "&/")) != NULL && *ap != 0) { 2548169424Smaxim l = strlen(ap); 2549169424Smaxim if (strspn(ap, macset) != l || (mac = ether_aton(ap)) == NULL) 2550169424Smaxim errx(EX_DATAERR, "Incorrect MAC address"); 2551169424Smaxim bcopy(mac, addr, ETHER_ADDR_LEN); 2552169424Smaxim } else 2553169424Smaxim errx(EX_DATAERR, "Incorrect MAC address"); 2554169424Smaxim 2555169424Smaxim if (ptr != NULL) { /* we have mask? */ 2556169424Smaxim if (p[ptr - optr - 1] == '/') { /* mask len */ 2557204591Sluigi long ml = strtol(ptr, &ap, 10); 2558204591Sluigi if (*ap != 0 || ml > ETHER_ADDR_LEN * 8 || ml < 0) 2559169424Smaxim errx(EX_DATAERR, "Incorrect mask length"); 2560204591Sluigi for (i = 0; ml > 0 && i < ETHER_ADDR_LEN; ml -= 8, i++) 2561204591Sluigi mask[i] = (ml >= 8) ? 0xff: (~0) << (8 - ml); 2562169424Smaxim } else { /* mask */ 2563169424Smaxim l = strlen(ptr); 2564169424Smaxim if (strspn(ptr, macset) != l || 2565169424Smaxim (mac = ether_aton(ptr)) == NULL) 2566169424Smaxim errx(EX_DATAERR, "Incorrect mask"); 2567169424Smaxim bcopy(mac, mask, ETHER_ADDR_LEN); 256898943Sluigi } 2569169424Smaxim } else { /* default mask: ff:ff:ff:ff:ff:ff */ 2570169424Smaxim for (i = 0; i < ETHER_ADDR_LEN; i++) 257198943Sluigi mask[i] = 0xff; 257298943Sluigi } 2573169424Smaxim for (i = 0; i < ETHER_ADDR_LEN; i++) 257498943Sluigi addr[i] &= mask[i]; 2575169424Smaxim 2576169424Smaxim free(optr); 257798943Sluigi} 257898943Sluigi 257998943Sluigi/* 258098943Sluigi * helper function, updates the pointer to cmd with the length 258198943Sluigi * of the current command, and also cleans up the first word of 258298943Sluigi * the new command in case it has been clobbered before. 258398943Sluigi */ 258498943Sluigistatic ipfw_insn * 2585248505Smelifaronext_cmd(ipfw_insn *cmd, int *len) 258698943Sluigi{ 2587248505Smelifaro *len -= F_LEN(cmd); 2588248505Smelifaro CHECK_LENGTH(*len, 0); 258998943Sluigi cmd += F_LEN(cmd); 259098943Sluigi bzero(cmd, sizeof(*cmd)); 259198943Sluigi return cmd; 259298943Sluigi} 259398943Sluigi 259498943Sluigi/* 2595117469Sluigi * Takes arguments and copies them into a comment 2596117469Sluigi */ 2597117469Sluigistatic void 2598248505Smelifarofill_comment(ipfw_insn *cmd, char **av, int cblen) 2599117469Sluigi{ 2600117469Sluigi int i, l; 2601117469Sluigi char *p = (char *)(cmd + 1); 2602117577Sluigi 2603117469Sluigi cmd->opcode = O_NOP; 2604117469Sluigi cmd->len = (cmd->len & (F_NOT | F_OR)); 2605117469Sluigi 2606117469Sluigi /* Compute length of comment string. */ 2607204591Sluigi for (i = 0, l = 0; av[i] != NULL; i++) 2608117469Sluigi l += strlen(av[i]) + 1; 2609117469Sluigi if (l == 0) 2610117469Sluigi return; 2611117469Sluigi if (l > 84) 2612117469Sluigi errx(EX_DATAERR, 2613117469Sluigi "comment too long (max 80 chars)"); 2614117469Sluigi l = 1 + (l+3)/4; 2615117469Sluigi cmd->len = (cmd->len & (F_NOT | F_OR)) | l; 2616248505Smelifaro CHECK_CMDLEN; 2617248505Smelifaro 2618204591Sluigi for (i = 0; av[i] != NULL; i++) { 2619117469Sluigi strcpy(p, av[i]); 2620117469Sluigi p += strlen(av[i]); 2621117469Sluigi *p++ = ' '; 2622117469Sluigi } 2623117469Sluigi *(--p) = '\0'; 2624117469Sluigi} 2625117577Sluigi 2626117469Sluigi/* 262798943Sluigi * A function to fill simple commands of size 1. 262898943Sluigi * Existing flags are preserved. 262998943Sluigi */ 263098943Sluigistatic void 2631117328Sluigifill_cmd(ipfw_insn *cmd, enum ipfw_opcodes opcode, int flags, uint16_t arg) 263298943Sluigi{ 263398943Sluigi cmd->opcode = opcode; 263498943Sluigi cmd->len = ((cmd->len | flags) & (F_NOT | F_OR)) | 1; 263598943Sluigi cmd->arg1 = arg; 263698943Sluigi} 263798943Sluigi 263898943Sluigi/* 263998943Sluigi * Fetch and add the MAC address and type, with masks. This generates one or 264098943Sluigi * two microinstructions, and returns the pointer to the last one. 264198943Sluigi */ 264298943Sluigistatic ipfw_insn * 2643248505Smelifaroadd_mac(ipfw_insn *cmd, char *av[], int cblen) 264498943Sluigi{ 2645102087Sluigi ipfw_insn_mac *mac; 264698943Sluigi 2647204591Sluigi if ( ( av[0] == NULL ) || ( av[1] == NULL ) ) 2648102098Sluigi errx(EX_DATAERR, "MAC dst src"); 264998943Sluigi 265098943Sluigi cmd->opcode = O_MACADDR2; 265198943Sluigi cmd->len = (cmd->len & (F_NOT | F_OR)) | F_INSN_SIZE(ipfw_insn_mac); 2652248505Smelifaro CHECK_CMDLEN; 265398943Sluigi 265498943Sluigi mac = (ipfw_insn_mac *)cmd; 2655101978Sluigi get_mac_addr_mask(av[0], mac->addr, mac->mask); /* dst */ 2656169424Smaxim get_mac_addr_mask(av[1], &(mac->addr[ETHER_ADDR_LEN]), 2657169424Smaxim &(mac->mask[ETHER_ADDR_LEN])); /* src */ 2658102087Sluigi return cmd; 2659102087Sluigi} 266098943Sluigi 2661102087Sluigistatic ipfw_insn * 2662248505Smelifaroadd_mactype(ipfw_insn *cmd, char *av, int cblen) 2663102087Sluigi{ 2664204591Sluigi if (!av) 2665102087Sluigi errx(EX_DATAERR, "missing MAC type"); 2666102087Sluigi if (strcmp(av, "any") != 0) { /* we have a non-null type */ 2667248505Smelifaro fill_newports((ipfw_insn_u16 *)cmd, av, IPPROTO_ETHERTYPE, 2668248505Smelifaro cblen); 266998943Sluigi cmd->opcode = O_MAC_TYPE; 2670102087Sluigi return cmd; 2671102087Sluigi } else 2672102087Sluigi return NULL; 2673102087Sluigi} 267498943Sluigi 2675102087Sluigistatic ipfw_insn * 2676152923Sumeadd_proto0(ipfw_insn *cmd, char *av, u_char *protop) 2677102087Sluigi{ 2678102087Sluigi struct protoent *pe; 2679152923Sume char *ep; 2680152923Sume int proto; 2681102087Sluigi 2682156315Sume proto = strtol(av, &ep, 10); 2683156315Sume if (*ep != '\0' || proto <= 0) { 2684152923Sume if ((pe = getprotobyname(av)) == NULL) 2685152923Sume return NULL; 2686152923Sume proto = pe->p_proto; 2687152923Sume } 2688145246Sbrooks 2689152923Sume fill_cmd(cmd, O_PROTO, 0, proto); 2690152923Sume *protop = proto; 2691152923Sume return cmd; 2692152923Sume} 2693152923Sume 2694152923Sumestatic ipfw_insn * 2695152923Sumeadd_proto(ipfw_insn *cmd, char *av, u_char *protop) 2696152923Sume{ 2697152923Sume u_char proto = IPPROTO_IP; 2698152923Sume 2699156315Sume if (_substrcmp(av, "all") == 0 || strcmp(av, "ip") == 0) 2700146894Smlaier ; /* do not set O_IP4 nor O_IP6 */ 2701152923Sume else if (strcmp(av, "ip4") == 0) 2702152923Sume /* explicit "just IPv4" rule */ 2703152923Sume fill_cmd(cmd, O_IP4, 0, 0); 2704152923Sume else if (strcmp(av, "ip6") == 0) { 2705152923Sume /* explicit "just IPv6" rule */ 2706152923Sume proto = IPPROTO_IPV6; 2707152923Sume fill_cmd(cmd, O_IP6, 0, 0); 2708152923Sume } else 2709152923Sume return add_proto0(cmd, av, protop); 2710152923Sume 2711152923Sume *protop = proto; 2712152923Sume return cmd; 2713152923Sume} 2714152923Sume 2715152923Sumestatic ipfw_insn * 2716152923Sumeadd_proto_compat(ipfw_insn *cmd, char *av, u_char *protop) 2717152923Sume{ 2718152923Sume u_char proto = IPPROTO_IP; 2719152923Sume 2720152923Sume if (_substrcmp(av, "all") == 0 || strcmp(av, "ip") == 0) 2721152923Sume ; /* do not set O_IP4 nor O_IP6 */ 2722146894Smlaier else if (strcmp(av, "ipv4") == 0 || strcmp(av, "ip4") == 0) 2723146894Smlaier /* explicit "just IPv4" rule */ 2724146894Smlaier fill_cmd(cmd, O_IP4, 0, 0); 2725146894Smlaier else if (strcmp(av, "ipv6") == 0 || strcmp(av, "ip6") == 0) { 2726146894Smlaier /* explicit "just IPv6" rule */ 2727152923Sume proto = IPPROTO_IPV6; 2728146894Smlaier fill_cmd(cmd, O_IP6, 0, 0); 2729152923Sume } else 2730152923Sume return add_proto0(cmd, av, protop); 2731145246Sbrooks 2732152923Sume *protop = proto; 273398943Sluigi return cmd; 273498943Sluigi} 273598943Sluigi 2736102087Sluigistatic ipfw_insn * 2737248505Smelifaroadd_srcip(ipfw_insn *cmd, char *av, int cblen) 2738102087Sluigi{ 2739248505Smelifaro fill_ip((ipfw_insn_ip *)cmd, av, cblen); 2740102087Sluigi if (cmd->opcode == O_IP_DST_SET) /* set */ 2741102087Sluigi cmd->opcode = O_IP_SRC_SET; 2742130281Sru else if (cmd->opcode == O_IP_DST_LOOKUP) /* table */ 2743130281Sru cmd->opcode = O_IP_SRC_LOOKUP; 2744102087Sluigi else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) /* me */ 2745102087Sluigi cmd->opcode = O_IP_SRC_ME; 2746102087Sluigi else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn_u32)) /* one IP */ 2747102087Sluigi cmd->opcode = O_IP_SRC; 2748117328Sluigi else /* addr/mask */ 2749102087Sluigi cmd->opcode = O_IP_SRC_MASK; 2750102087Sluigi return cmd; 2751102087Sluigi} 2752102087Sluigi 2753102087Sluigistatic ipfw_insn * 2754248505Smelifaroadd_dstip(ipfw_insn *cmd, char *av, int cblen) 2755102087Sluigi{ 2756248505Smelifaro fill_ip((ipfw_insn_ip *)cmd, av, cblen); 2757102087Sluigi if (cmd->opcode == O_IP_DST_SET) /* set */ 2758102087Sluigi ; 2759130281Sru else if (cmd->opcode == O_IP_DST_LOOKUP) /* table */ 2760130281Sru ; 2761102087Sluigi else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) /* me */ 2762102087Sluigi cmd->opcode = O_IP_DST_ME; 2763102087Sluigi else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn_u32)) /* one IP */ 2764102087Sluigi cmd->opcode = O_IP_DST; 2765117328Sluigi else /* addr/mask */ 2766102087Sluigi cmd->opcode = O_IP_DST_MASK; 2767102087Sluigi return cmd; 2768102087Sluigi} 2769102087Sluigi 2770102087Sluigistatic ipfw_insn * 2771248505Smelifaroadd_ports(ipfw_insn *cmd, char *av, u_char proto, int opcode, int cblen) 2772102087Sluigi{ 2773204591Sluigi /* XXX "any" is trapped before. Perhaps "to" */ 2774140271Sbrooks if (_substrcmp(av, "any") == 0) { 2775102087Sluigi return NULL; 2776248505Smelifaro } else if (fill_newports((ipfw_insn_u16 *)cmd, av, proto, cblen)) { 2777102087Sluigi /* XXX todo: check that we have a protocol with ports */ 2778102087Sluigi cmd->opcode = opcode; 2779102087Sluigi return cmd; 2780102087Sluigi } 2781102087Sluigi return NULL; 2782102087Sluigi} 2783102087Sluigi 2784145246Sbrooksstatic ipfw_insn * 2785248505Smelifaroadd_src(ipfw_insn *cmd, char *av, u_char proto, int cblen) 2786145246Sbrooks{ 2787145246Sbrooks struct in6_addr a; 2788158553Smlaier char *host, *ch; 2789158553Smlaier ipfw_insn *ret = NULL; 2790145246Sbrooks 2791158553Smlaier if ((host = strdup(av)) == NULL) 2792158553Smlaier return NULL; 2793158553Smlaier if ((ch = strrchr(host, '/')) != NULL) 2794158553Smlaier *ch = '\0'; 2795158553Smlaier 2796145246Sbrooks if (proto == IPPROTO_IPV6 || strcmp(av, "me6") == 0 || 2797204591Sluigi inet_pton(AF_INET6, host, &a) == 1) 2798248505Smelifaro ret = add_srcip6(cmd, av, cblen); 2799145246Sbrooks /* XXX: should check for IPv4, not !IPv6 */ 2800161483Sdwmalone if (ret == NULL && (proto == IPPROTO_IP || strcmp(av, "me") == 0 || 2801204591Sluigi inet_pton(AF_INET6, host, &a) != 1)) 2802248505Smelifaro ret = add_srcip(cmd, av, cblen); 2803161483Sdwmalone if (ret == NULL && strcmp(av, "any") != 0) 2804158553Smlaier ret = cmd; 2805145246Sbrooks 2806158553Smlaier free(host); 2807158553Smlaier return ret; 2808145246Sbrooks} 2809145246Sbrooks 2810145246Sbrooksstatic ipfw_insn * 2811248505Smelifaroadd_dst(ipfw_insn *cmd, char *av, u_char proto, int cblen) 2812145246Sbrooks{ 2813145246Sbrooks struct in6_addr a; 2814158553Smlaier char *host, *ch; 2815158553Smlaier ipfw_insn *ret = NULL; 2816145246Sbrooks 2817158553Smlaier if ((host = strdup(av)) == NULL) 2818158553Smlaier return NULL; 2819158553Smlaier if ((ch = strrchr(host, '/')) != NULL) 2820158553Smlaier *ch = '\0'; 2821158553Smlaier 2822145246Sbrooks if (proto == IPPROTO_IPV6 || strcmp(av, "me6") == 0 || 2823204591Sluigi inet_pton(AF_INET6, host, &a) == 1) 2824248505Smelifaro ret = add_dstip6(cmd, av, cblen); 2825145246Sbrooks /* XXX: should check for IPv4, not !IPv6 */ 2826161483Sdwmalone if (ret == NULL && (proto == IPPROTO_IP || strcmp(av, "me") == 0 || 2827204591Sluigi inet_pton(AF_INET6, host, &a) != 1)) 2828248505Smelifaro ret = add_dstip(cmd, av, cblen); 2829161483Sdwmalone if (ret == NULL && strcmp(av, "any") != 0) 2830158553Smlaier ret = cmd; 2831145246Sbrooks 2832158553Smlaier free(host); 2833158553Smlaier return ret; 2834145246Sbrooks} 2835145246Sbrooks 283698943Sluigi/* 283798943Sluigi * Parse arguments and assemble the microinstructions which make up a rule. 283898943Sluigi * Rules are added into the 'rulebuf' and then copied in the correct order 283998943Sluigi * into the actual rule. 284098943Sluigi * 2841136071Sgreen * The syntax for a rule starts with the action, followed by 2842136071Sgreen * optional action parameters, and the various match patterns. 2843108533Sschweikh * In the assembled microcode, the first opcode must be an O_PROBE_STATE 284498943Sluigi * (generated if the rule includes a keep-state option), then the 2845136071Sgreen * various match patterns, log/altq actions, and the actual action. 2846106505Smaxim * 284798943Sluigi */ 2848187767Sluigivoid 2849204591Sluigiipfw_add(char *av[]) 285098943Sluigi{ 285198943Sluigi /* 285298943Sluigi * rules are added into the 'rulebuf' and then copied in 285398943Sluigi * the correct order into the actual rule. 285498943Sluigi * Some things that need to go out of order (prob, action etc.) 285598943Sluigi * go into actbuf[]. 285698943Sluigi */ 2857117328Sluigi static uint32_t rulebuf[255], actbuf[255], cmdbuf[255]; 2858248505Smelifaro int rblen, ablen, cblen; 285998943Sluigi 2860117469Sluigi ipfw_insn *src, *dst, *cmd, *action, *prev=NULL; 2861102087Sluigi ipfw_insn *first_cmd; /* first match pattern */ 286298943Sluigi 286398943Sluigi struct ip_fw *rule; 286498943Sluigi 286598943Sluigi /* 286698943Sluigi * various flags used to record that we entered some fields. 286798943Sluigi */ 2868101116Sluigi ipfw_insn *have_state = NULL; /* check-state or keep-state */ 2869158879Soleg ipfw_insn *have_log = NULL, *have_altq = NULL, *have_tag = NULL; 2870134475Smaxim size_t len; 287198943Sluigi 287298943Sluigi int i; 287398943Sluigi 287498943Sluigi int open_par = 0; /* open parenthesis ( */ 287598943Sluigi 287698943Sluigi /* proto is here because it is used to fetch ports */ 287798943Sluigi u_char proto = IPPROTO_IP; /* default protocol */ 287898943Sluigi 2879107289Sluigi double match_prob = 1; /* match probability, default is always match */ 2880107289Sluigi 288198943Sluigi bzero(actbuf, sizeof(actbuf)); /* actions go here */ 288298943Sluigi bzero(cmdbuf, sizeof(cmdbuf)); 288398943Sluigi bzero(rulebuf, sizeof(rulebuf)); 288498943Sluigi 288598943Sluigi rule = (struct ip_fw *)rulebuf; 288698943Sluigi cmd = (ipfw_insn *)cmdbuf; 288798943Sluigi action = (ipfw_insn *)actbuf; 288898943Sluigi 2889248505Smelifaro rblen = sizeof(rulebuf) / sizeof(rulebuf[0]); 2890248505Smelifaro rblen -= offsetof(struct ip_fw, cmd) / sizeof(rulebuf[0]); 2891248505Smelifaro ablen = sizeof(actbuf) / sizeof(actbuf[0]); 2892248505Smelifaro cblen = sizeof(cmdbuf) / sizeof(cmdbuf[0]); 2893248505Smelifaro cblen -= F_INSN_SIZE(ipfw_insn_u32) + 1; 2894248505Smelifaro 2895248505Smelifaro#define CHECK_RBUFLEN(len) { CHECK_LENGTH(rblen, len); rblen -= len; } 2896248505Smelifaro#define CHECK_ACTLEN CHECK_LENGTH(ablen, action->len) 2897248505Smelifaro 2898204591Sluigi av++; 289998943Sluigi 290098943Sluigi /* [rule N] -- Rule number optional */ 2901204591Sluigi if (av[0] && isdigit(**av)) { 290298943Sluigi rule->rulenum = atoi(*av); 290398943Sluigi av++; 290498943Sluigi } 290598943Sluigi 2906117655Sluigi /* [set N] -- set number (0..RESVD_SET), optional */ 2907205631Sluigi if (av[0] && av[1] && _substrcmp(*av, "set") == 0) { 2908101628Sluigi int set = strtoul(av[1], NULL, 10); 2909117655Sluigi if (set < 0 || set > RESVD_SET) 2910101628Sluigi errx(EX_DATAERR, "illegal set %s", av[1]); 2911101628Sluigi rule->set = set; 2912204591Sluigi av += 2; 2913101628Sluigi } 2914101628Sluigi 291598943Sluigi /* [prob D] -- match probability, optional */ 2916204591Sluigi if (av[0] && av[1] && _substrcmp(*av, "prob") == 0) { 2917107289Sluigi match_prob = strtod(av[1], NULL); 291898943Sluigi 2919107289Sluigi if (match_prob <= 0 || match_prob > 1) 292098943Sluigi errx(EX_DATAERR, "illegal match prob. %s", av[1]); 2921204591Sluigi av += 2; 292298943Sluigi } 292398943Sluigi 292498943Sluigi /* action -- mandatory */ 292598943Sluigi NEED1("missing action"); 292698943Sluigi i = match_token(rule_actions, *av); 2927204591Sluigi av++; 292898943Sluigi action->len = 1; /* default */ 2929248505Smelifaro CHECK_ACTLEN; 293098943Sluigi switch(i) { 293198943Sluigi case TOK_CHECKSTATE: 2932101116Sluigi have_state = action; 293398943Sluigi action->opcode = O_CHECK_STATE; 293498943Sluigi break; 293598943Sluigi 293698943Sluigi case TOK_ACCEPT: 293798943Sluigi action->opcode = O_ACCEPT; 293898943Sluigi break; 293998943Sluigi 294098943Sluigi case TOK_DENY: 294198943Sluigi action->opcode = O_DENY; 294299475Sluigi action->arg1 = 0; 294398943Sluigi break; 294498943Sluigi 294599475Sluigi case TOK_REJECT: 294699475Sluigi action->opcode = O_REJECT; 294799475Sluigi action->arg1 = ICMP_UNREACH_HOST; 294899475Sluigi break; 294999475Sluigi 295099475Sluigi case TOK_RESET: 295199475Sluigi action->opcode = O_REJECT; 295299475Sluigi action->arg1 = ICMP_REJECT_RST; 295399475Sluigi break; 295499475Sluigi 2955149020Sbz case TOK_RESET6: 2956149020Sbz action->opcode = O_UNREACH6; 2957149020Sbz action->arg1 = ICMP6_UNREACH_RST; 2958149020Sbz break; 2959149020Sbz 296099475Sluigi case TOK_UNREACH: 296199475Sluigi action->opcode = O_REJECT; 296299475Sluigi NEED1("missing reject code"); 296399475Sluigi fill_reject_code(&action->arg1, *av); 2964204591Sluigi av++; 296599475Sluigi break; 296699475Sluigi 2967149020Sbz case TOK_UNREACH6: 2968149020Sbz action->opcode = O_UNREACH6; 2969149020Sbz NEED1("missing unreach code"); 2970149020Sbz fill_unreach6_code(&action->arg1, *av); 2971204591Sluigi av++; 2972149020Sbz break; 2973149020Sbz 297498943Sluigi case TOK_COUNT: 297598943Sluigi action->opcode = O_COUNT; 297698943Sluigi break; 297798943Sluigi 2978176517Spiso case TOK_NAT: 2979223080Sae action->opcode = O_NAT; 2980223080Sae action->len = F_INSN_SIZE(ipfw_insn_nat); 2981248505Smelifaro CHECK_ACTLEN; 2982223080Sae if (_substrcmp(*av, "global") == 0) { 2983223080Sae action->arg1 = 0; 2984223080Sae av++; 2985223080Sae break; 2986223080Sae } else 2987223080Sae goto chkarg; 2988178888Sjulian 298998943Sluigi case TOK_QUEUE: 2990153374Sglebius action->opcode = O_QUEUE; 2991153374Sglebius goto chkarg; 299298943Sluigi case TOK_PIPE: 2993153374Sglebius action->opcode = O_PIPE; 2994153374Sglebius goto chkarg; 299598943Sluigi case TOK_SKIPTO: 2996153374Sglebius action->opcode = O_SKIPTO; 2997153374Sglebius goto chkarg; 2998153374Sglebius case TOK_NETGRAPH: 2999153374Sglebius action->opcode = O_NETGRAPH; 3000153374Sglebius goto chkarg; 3001153374Sglebius case TOK_NGTEE: 3002153374Sglebius action->opcode = O_NGTEE; 3003153374Sglebius goto chkarg; 300498943Sluigi case TOK_DIVERT: 3005153374Sglebius action->opcode = O_DIVERT; 3006153374Sglebius goto chkarg; 300798943Sluigi case TOK_TEE: 3008153374Sglebius action->opcode = O_TEE; 3009223666Sae goto chkarg; 3010223666Sae case TOK_CALL: 3011223666Sae action->opcode = O_CALLRETURN; 3012220804Sglebiuschkarg: 3013204591Sluigi if (!av[0]) 3014153374Sglebius errx(EX_USAGE, "missing argument for %s", *(av - 1)); 3015153374Sglebius if (isdigit(**av)) { 3016153374Sglebius action->arg1 = strtoul(*av, NULL, 10); 3017153374Sglebius if (action->arg1 <= 0 || action->arg1 >= IP_FW_TABLEARG) 3018153374Sglebius errx(EX_DATAERR, "illegal argument for %s", 3019153374Sglebius *(av - 1)); 3020187762Sluigi } else if (_substrcmp(*av, "tablearg") == 0) { 3021153374Sglebius action->arg1 = IP_FW_TABLEARG; 3022153374Sglebius } else if (i == TOK_DIVERT || i == TOK_TEE) { 302398943Sluigi struct servent *s; 302498943Sluigi setservent(1); 302598943Sluigi s = getservbyname(av[0], "divert"); 302698943Sluigi if (s != NULL) 302798943Sluigi action->arg1 = ntohs(s->s_port); 302898943Sluigi else 302998943Sluigi errx(EX_DATAERR, "illegal divert/tee port"); 3030153374Sglebius } else 3031153374Sglebius errx(EX_DATAERR, "illegal argument for %s", *(av - 1)); 3032204591Sluigi av++; 303398943Sluigi break; 303498943Sluigi 303598943Sluigi case TOK_FORWARD: { 3036225044Sbz /* 3037225044Sbz * Locate the address-port separator (':' or ','). 3038225044Sbz * Could be one of the following: 3039225044Sbz * hostname:port 3040225044Sbz * IPv4 a.b.c.d,port 3041225044Sbz * IPv4 a.b.c.d:port 3042225044Sbz * IPv6 w:x:y::z,port 3043225044Sbz * The ':' can only be used with hostname and IPv4 address. 3044225044Sbz * XXX-BZ Should we also support [w:x:y::z]:port? 3045225044Sbz */ 3046225044Sbz struct sockaddr_storage result; 3047225044Sbz struct addrinfo *res; 304898943Sluigi char *s, *end; 3049225044Sbz int family; 3050225044Sbz u_short port_number; 305198943Sluigi 305298943Sluigi NEED1("missing forward address[:port]"); 305398943Sluigi 3054188005Sluigi /* 305598943Sluigi * locate the address-port separator (':' or ',') 305698943Sluigi */ 3057225044Sbz s = strchr(*av, ','); 3058225044Sbz if (s == NULL) { 3059225044Sbz /* Distinguish between IPv4:port and IPv6 cases. */ 3060225044Sbz s = strchr(*av, ':'); 3061225044Sbz if (s && strchr(s+1, ':')) 3062225044Sbz s = NULL; /* no port */ 3063225044Sbz } 3064225044Sbz 3065225044Sbz port_number = 0; 306698943Sluigi if (s != NULL) { 3067225044Sbz /* Terminate host portion and set s to start of port. */ 306898943Sluigi *(s++) = '\0'; 306998943Sluigi i = strtoport(s, &end, 0 /* base */, 0 /* proto */); 307098943Sluigi if (s == end) 307198943Sluigi errx(EX_DATAERR, 307298943Sluigi "illegal forwarding port ``%s''", s); 3073225044Sbz port_number = (u_short)i; 307498943Sluigi } 3075225044Sbz 3076225044Sbz if (_substrcmp(*av, "tablearg") == 0) { 3077225044Sbz family = PF_INET; 3078225044Sbz ((struct sockaddr_in*)&result)->sin_addr.s_addr = 3079225044Sbz INADDR_ANY; 3080225044Sbz } else { 3081225044Sbz /* 3082225044Sbz * Resolve the host name or address to a family and a 3083225044Sbz * network representation of the addres. 3084225044Sbz */ 3085225044Sbz if (getaddrinfo(*av, NULL, NULL, &res)) 3086225044Sbz errx(EX_DATAERR, NULL); 3087225044Sbz /* Just use the first host in the answer. */ 3088225044Sbz family = res->ai_family; 3089225044Sbz memcpy(&result, res->ai_addr, res->ai_addrlen); 3090225044Sbz freeaddrinfo(res); 3091225044Sbz } 3092225044Sbz 3093225044Sbz if (family == PF_INET) { 3094225044Sbz ipfw_insn_sa *p = (ipfw_insn_sa *)action; 3095225044Sbz 3096225044Sbz action->opcode = O_FORWARD_IP; 3097225044Sbz action->len = F_INSN_SIZE(ipfw_insn_sa); 3098248505Smelifaro CHECK_ACTLEN; 3099225044Sbz 3100225044Sbz /* 3101225044Sbz * In the kernel we assume AF_INET and use only 3102225044Sbz * sin_port and sin_addr. Remember to set sin_len as 3103225044Sbz * the routing code seems to use it too. 3104225044Sbz */ 3105225044Sbz p->sa.sin_len = sizeof(struct sockaddr_in); 3106225044Sbz p->sa.sin_family = AF_INET; 3107225044Sbz p->sa.sin_port = port_number; 3108225044Sbz p->sa.sin_addr.s_addr = 3109225044Sbz ((struct sockaddr_in *)&result)->sin_addr.s_addr; 3110225044Sbz } else if (family == PF_INET6) { 3111225044Sbz ipfw_insn_sa6 *p = (ipfw_insn_sa6 *)action; 3112225044Sbz 3113225044Sbz action->opcode = O_FORWARD_IP6; 3114225044Sbz action->len = F_INSN_SIZE(ipfw_insn_sa6); 3115248505Smelifaro CHECK_ACTLEN; 3116225044Sbz 3117225044Sbz p->sa.sin6_len = sizeof(struct sockaddr_in6); 3118225044Sbz p->sa.sin6_family = AF_INET6; 3119225044Sbz p->sa.sin6_port = port_number; 3120225044Sbz p->sa.sin6_flowinfo = 0; 3121225044Sbz p->sa.sin6_scope_id = 0; 3122225044Sbz /* No table support for v6 yet. */ 3123225044Sbz bcopy(&((struct sockaddr_in6*)&result)->sin6_addr, 3124225044Sbz &p->sa.sin6_addr, sizeof(p->sa.sin6_addr)); 3125225044Sbz } else { 3126225044Sbz errx(EX_DATAERR, "Invalid address family in forward action"); 3127225044Sbz } 3128204591Sluigi av++; 312998943Sluigi break; 3130161424Sjulian } 3131117469Sluigi case TOK_COMMENT: 3132117469Sluigi /* pretend it is a 'count' rule followed by the comment */ 3133117469Sluigi action->opcode = O_COUNT; 3134204591Sluigi av--; /* go back... */ 3135117469Sluigi break; 3136178888Sjulian 3137178888Sjulian case TOK_SETFIB: 3138178888Sjulian { 3139178888Sjulian int numfibs; 3140178916Sjulian size_t intsize = sizeof(int); 3141178888Sjulian 3142178888Sjulian action->opcode = O_SETFIB; 3143222473Sae NEED1("missing fib number"); 3144222473Sae if (_substrcmp(*av, "tablearg") == 0) { 3145222473Sae action->arg1 = IP_FW_TABLEARG; 3146222473Sae } else { 3147222473Sae action->arg1 = strtoul(*av, NULL, 10); 3148222473Sae if (sysctlbyname("net.fibs", &numfibs, &intsize, 3149222473Sae NULL, 0) == -1) 3150222473Sae errx(EX_DATAERR, "fibs not suported.\n"); 3151222473Sae if (action->arg1 >= numfibs) /* Temporary */ 3152222473Sae errx(EX_DATAERR, "fib too large.\n"); 3153222473Sae } 3154222473Sae av++; 3155222473Sae break; 3156178888Sjulian } 3157190633Spiso 3158250762Smelifaro case TOK_SETDSCP: 3159250762Smelifaro { 3160250762Smelifaro int code; 3161250762Smelifaro 3162250762Smelifaro action->opcode = O_SETDSCP; 3163250762Smelifaro NEED1("missing DSCP code"); 3164250762Smelifaro if (_substrcmp(*av, "tablearg") == 0) { 3165250762Smelifaro action->arg1 = IP_FW_TABLEARG; 3166250762Smelifaro } else if (isalpha(*av[0])) { 3167250762Smelifaro if ((code = match_token(f_ipdscp, *av)) == -1) 3168250762Smelifaro errx(EX_DATAERR, "Unknown DSCP code"); 3169250762Smelifaro action->arg1 = code; 3170250762Smelifaro } else 3171250762Smelifaro action->arg1 = strtoul(*av, NULL, 10); 3172250762Smelifaro av++; 3173250762Smelifaro break; 3174250762Smelifaro } 3175250762Smelifaro 3176190633Spiso case TOK_REASS: 3177190633Spiso action->opcode = O_REASS; 3178190633Spiso break; 3179220804Sglebius 3180223666Sae case TOK_RETURN: 3181223666Sae fill_cmd(action, O_CALLRETURN, F_NOT, 0); 3182223666Sae break; 3183223666Sae 318498943Sluigi default: 3185102087Sluigi errx(EX_DATAERR, "invalid action %s\n", av[-1]); 318698943Sluigi } 3187248505Smelifaro action = next_cmd(action, &ablen); 318898943Sluigi 318998943Sluigi /* 3190136071Sgreen * [altq queuename] -- altq tag, optional 319198943Sluigi * [log [logamount N]] -- log, optional 319298943Sluigi * 3193136071Sgreen * If they exist, it go first in the cmdbuf, but then it is 319498943Sluigi * skipped in the copy section to the end of the buffer. 319598943Sluigi */ 3196204591Sluigi while (av[0] != NULL && (i = match_token(rule_action_params, *av)) != -1) { 3197204591Sluigi av++; 3198136071Sgreen switch (i) { 3199136071Sgreen case TOK_LOG: 3200136071Sgreen { 3201136071Sgreen ipfw_insn_log *c = (ipfw_insn_log *)cmd; 3202136071Sgreen int l; 320398943Sluigi 3204136071Sgreen if (have_log) 3205136071Sgreen errx(EX_DATAERR, 3206136071Sgreen "log cannot be specified more than once"); 3207136071Sgreen have_log = (ipfw_insn *)c; 3208136071Sgreen cmd->len = F_INSN_SIZE(ipfw_insn_log); 3209248505Smelifaro CHECK_CMDLEN; 3210136071Sgreen cmd->opcode = O_LOG; 3211204591Sluigi if (av[0] && _substrcmp(*av, "logamount") == 0) { 3212204591Sluigi av++; 3213136071Sgreen NEED1("logamount requires argument"); 3214136071Sgreen l = atoi(*av); 3215136071Sgreen if (l < 0) 3216136071Sgreen errx(EX_DATAERR, 3217136071Sgreen "logamount must be positive"); 3218136071Sgreen c->max_log = l; 3219204591Sluigi av++; 3220136071Sgreen } else { 3221136071Sgreen len = sizeof(c->max_log); 3222136071Sgreen if (sysctlbyname("net.inet.ip.fw.verbose_limit", 3223248505Smelifaro &c->max_log, &len, NULL, 0) == -1) { 3224248505Smelifaro if (co.test_only) { 3225248505Smelifaro c->max_log = 0; 3226248505Smelifaro break; 3227248505Smelifaro } 3228136071Sgreen errx(1, "sysctlbyname(\"%s\")", 3229136071Sgreen "net.inet.ip.fw.verbose_limit"); 3230248505Smelifaro } 3231136071Sgreen } 3232136071Sgreen } 3233136071Sgreen break; 3234136071Sgreen 3235204591Sluigi#ifndef NO_ALTQ 3236136071Sgreen case TOK_ALTQ: 3237136071Sgreen { 3238136071Sgreen ipfw_insn_altq *a = (ipfw_insn_altq *)cmd; 3239136071Sgreen 3240136071Sgreen NEED1("missing altq queue name"); 3241136071Sgreen if (have_altq) 3242136071Sgreen errx(EX_DATAERR, 3243136071Sgreen "altq cannot be specified more than once"); 3244136071Sgreen have_altq = (ipfw_insn *)a; 3245136071Sgreen cmd->len = F_INSN_SIZE(ipfw_insn_altq); 3246248505Smelifaro CHECK_CMDLEN; 3247136071Sgreen cmd->opcode = O_ALTQ; 3248187983Sluigi a->qid = altq_name_to_qid(*av); 3249204591Sluigi av++; 3250136071Sgreen } 3251136071Sgreen break; 3252204591Sluigi#endif 3253136071Sgreen 3254158879Soleg case TOK_TAG: 3255159636Soleg case TOK_UNTAG: { 3256159636Soleg uint16_t tag; 3257159636Soleg 3258158879Soleg if (have_tag) 3259159636Soleg errx(EX_USAGE, "tag and untag cannot be " 3260159636Soleg "specified more than once"); 3261193516Sluigi GET_UINT_ARG(tag, IPFW_ARG_MIN, IPFW_ARG_MAX, i, 3262182823Srik rule_action_params); 3263158879Soleg have_tag = cmd; 3264159636Soleg fill_cmd(cmd, O_TAG, (i == TOK_TAG) ? 0: F_NOT, tag); 3265204591Sluigi av++; 3266158879Soleg break; 3267159636Soleg } 3268158879Soleg 3269136071Sgreen default: 3270136071Sgreen abort(); 327198943Sluigi } 3272248505Smelifaro cmd = next_cmd(cmd, &cblen); 327398943Sluigi } 327498943Sluigi 3275101116Sluigi if (have_state) /* must be a check-state, we are done */ 327698943Sluigi goto done; 327798943Sluigi 327898943Sluigi#define OR_START(target) \ 3279204591Sluigi if (av[0] && (*av[0] == '(' || *av[0] == '{')) { \ 328098943Sluigi if (open_par) \ 328198943Sluigi errx(EX_USAGE, "nested \"(\" not allowed\n"); \ 3282101641Sluigi prev = NULL; \ 328398943Sluigi open_par = 1; \ 328498943Sluigi if ( (av[0])[1] == '\0') { \ 3285204591Sluigi av++; \ 328698943Sluigi } else \ 328798943Sluigi (*av)++; \ 328898943Sluigi } \ 328998943Sluigi target: \ 329098943Sluigi 329198943Sluigi 329298943Sluigi#define CLOSE_PAR \ 329398943Sluigi if (open_par) { \ 3294204591Sluigi if (av[0] && ( \ 3295140271Sbrooks strcmp(*av, ")") == 0 || \ 3296140271Sbrooks strcmp(*av, "}") == 0)) { \ 3297101641Sluigi prev = NULL; \ 329898943Sluigi open_par = 0; \ 3299204591Sluigi av++; \ 330098943Sluigi } else \ 330198943Sluigi errx(EX_USAGE, "missing \")\"\n"); \ 330298943Sluigi } 3303106505Smaxim 330498943Sluigi#define NOT_BLOCK \ 3305204591Sluigi if (av[0] && _substrcmp(*av, "not") == 0) { \ 330698943Sluigi if (cmd->len & F_NOT) \ 330798943Sluigi errx(EX_USAGE, "double \"not\" not allowed\n"); \ 330898943Sluigi cmd->len |= F_NOT; \ 3309204591Sluigi av++; \ 331098943Sluigi } 331198943Sluigi 331298943Sluigi#define OR_BLOCK(target) \ 3313204591Sluigi if (av[0] && _substrcmp(*av, "or") == 0) { \ 331498943Sluigi if (prev == NULL || open_par == 0) \ 331598943Sluigi errx(EX_DATAERR, "invalid OR block"); \ 331698943Sluigi prev->len |= F_OR; \ 3317204591Sluigi av++; \ 331898943Sluigi goto target; \ 331998943Sluigi } \ 332098943Sluigi CLOSE_PAR; 332198943Sluigi 3322102087Sluigi first_cmd = cmd; 3323102098Sluigi 3324102098Sluigi#if 0 332598943Sluigi /* 3326102087Sluigi * MAC addresses, optional. 3327102087Sluigi * If we have this, we skip the part "proto from src to dst" 3328102087Sluigi * and jump straight to the option parsing. 3329102087Sluigi */ 3330102087Sluigi NOT_BLOCK; 3331102087Sluigi NEED1("missing protocol"); 3332140271Sbrooks if (_substrcmp(*av, "MAC") == 0 || 3333140271Sbrooks _substrcmp(*av, "mac") == 0) { 3334204591Sluigi av++; /* the "MAC" keyword */ 3335204591Sluigi add_mac(cmd, av); /* exits in case of errors */ 3336102087Sluigi cmd = next_cmd(cmd); 3337204591Sluigi av += 2; /* dst-mac and src-mac */ 3338102087Sluigi NOT_BLOCK; 3339102087Sluigi NEED1("missing mac type"); 3340204591Sluigi if (add_mactype(cmd, av[0])) 3341102087Sluigi cmd = next_cmd(cmd); 3342204591Sluigi av++; /* any or mac-type */ 3343102087Sluigi goto read_options; 3344102087Sluigi } 3345102098Sluigi#endif 3346102087Sluigi 3347102087Sluigi /* 334898943Sluigi * protocol, mandatory 334998943Sluigi */ 335098943Sluigi OR_START(get_proto); 335198943Sluigi NOT_BLOCK; 335298943Sluigi NEED1("missing protocol"); 3353152923Sume if (add_proto_compat(cmd, *av, &proto)) { 3354204591Sluigi av++; 3355147105Smlaier if (F_LEN(cmd) != 0) { 3356102087Sluigi prev = cmd; 3357248505Smelifaro cmd = next_cmd(cmd, &cblen); 3358102087Sluigi } 3359102098Sluigi } else if (first_cmd != cmd) { 3360116438Smaxim errx(EX_DATAERR, "invalid protocol ``%s''", *av); 3361102098Sluigi } else 3362102098Sluigi goto read_options; 336398943Sluigi OR_BLOCK(get_proto); 336498943Sluigi 336598943Sluigi /* 3366102087Sluigi * "from", mandatory 336798943Sluigi */ 3368204591Sluigi if ((av[0] == NULL) || _substrcmp(*av, "from") != 0) 336998943Sluigi errx(EX_USAGE, "missing ``from''"); 3370204591Sluigi av++; 337198943Sluigi 337298943Sluigi /* 337398943Sluigi * source IP, mandatory 337498943Sluigi */ 337598943Sluigi OR_START(source_ip); 337698943Sluigi NOT_BLOCK; /* optional "not" */ 337798943Sluigi NEED1("missing source address"); 3378248505Smelifaro if (add_src(cmd, *av, proto, cblen)) { 3379204591Sluigi av++; 3380102087Sluigi if (F_LEN(cmd) != 0) { /* ! any */ 3381102087Sluigi prev = cmd; 3382248505Smelifaro cmd = next_cmd(cmd, &cblen); 3383102087Sluigi } 3384145246Sbrooks } else 3385145246Sbrooks errx(EX_USAGE, "bad source address %s", *av); 338698943Sluigi OR_BLOCK(source_ip); 338798943Sluigi 338898943Sluigi /* 338998943Sluigi * source ports, optional 339098943Sluigi */ 339198943Sluigi NOT_BLOCK; /* optional "not" */ 3392204591Sluigi if ( av[0] != NULL ) { 3393140271Sbrooks if (_substrcmp(*av, "any") == 0 || 3394248505Smelifaro add_ports(cmd, *av, proto, O_IP_SRCPORT, cblen)) { 3395204591Sluigi av++; 3396102087Sluigi if (F_LEN(cmd) != 0) 3397248505Smelifaro cmd = next_cmd(cmd, &cblen); 3398101641Sluigi } 339998943Sluigi } 340098943Sluigi 340198943Sluigi /* 3402102087Sluigi * "to", mandatory 340398943Sluigi */ 3404204591Sluigi if ( (av[0] == NULL) || _substrcmp(*av, "to") != 0 ) 340598943Sluigi errx(EX_USAGE, "missing ``to''"); 3406204591Sluigi av++; 340798943Sluigi 340898943Sluigi /* 340998943Sluigi * destination, mandatory 341098943Sluigi */ 341198943Sluigi OR_START(dest_ip); 341298943Sluigi NOT_BLOCK; /* optional "not" */ 341398943Sluigi NEED1("missing dst address"); 3414248505Smelifaro if (add_dst(cmd, *av, proto, cblen)) { 3415204591Sluigi av++; 3416102087Sluigi if (F_LEN(cmd) != 0) { /* ! any */ 3417102087Sluigi prev = cmd; 3418248505Smelifaro cmd = next_cmd(cmd, &cblen); 3419102087Sluigi } 3420145246Sbrooks } else 3421145246Sbrooks errx( EX_USAGE, "bad destination address %s", *av); 342298943Sluigi OR_BLOCK(dest_ip); 342398943Sluigi 342498943Sluigi /* 342598943Sluigi * dest. ports, optional 342698943Sluigi */ 342798943Sluigi NOT_BLOCK; /* optional "not" */ 3428204591Sluigi if (av[0]) { 3429140271Sbrooks if (_substrcmp(*av, "any") == 0 || 3430248505Smelifaro add_ports(cmd, *av, proto, O_IP_DSTPORT, cblen)) { 3431204591Sluigi av++; 3432102087Sluigi if (F_LEN(cmd) != 0) 3433248505Smelifaro cmd = next_cmd(cmd, &cblen); 3434101641Sluigi } 343598943Sluigi } 343698943Sluigi 343798943Sluigiread_options: 3438204591Sluigi if (av[0] && first_cmd == cmd) { 3439102087Sluigi /* 3440102087Sluigi * nothing specified so far, store in the rule to ease 3441102087Sluigi * printout later. 3442102087Sluigi */ 3443102087Sluigi rule->_pad = 1; 3444102087Sluigi } 344598943Sluigi prev = NULL; 3446204591Sluigi while ( av[0] != NULL ) { 3447101641Sluigi char *s; 3448101641Sluigi ipfw_insn_u32 *cmd32; /* alias for cmd */ 344998943Sluigi 3450101641Sluigi s = *av; 3451101641Sluigi cmd32 = (ipfw_insn_u32 *)cmd; 3452101641Sluigi 345398943Sluigi if (*s == '!') { /* alternate syntax for NOT */ 345498943Sluigi if (cmd->len & F_NOT) 345598943Sluigi errx(EX_USAGE, "double \"not\" not allowed\n"); 345698943Sluigi cmd->len = F_NOT; 345798943Sluigi s++; 345898943Sluigi } 345998943Sluigi i = match_token(rule_options, s); 3460204591Sluigi av++; 346198943Sluigi switch(i) { 346298943Sluigi case TOK_NOT: 346398943Sluigi if (cmd->len & F_NOT) 346498943Sluigi errx(EX_USAGE, "double \"not\" not allowed\n"); 346598943Sluigi cmd->len = F_NOT; 346698943Sluigi break; 346798943Sluigi 346898943Sluigi case TOK_OR: 3469101641Sluigi if (open_par == 0 || prev == NULL) 347098943Sluigi errx(EX_USAGE, "invalid \"or\" block\n"); 347198943Sluigi prev->len |= F_OR; 347298943Sluigi break; 3473101641Sluigi 3474101641Sluigi case TOK_STARTBRACE: 3475101641Sluigi if (open_par) 3476101641Sluigi errx(EX_USAGE, "+nested \"(\" not allowed\n"); 3477101641Sluigi open_par = 1; 3478101641Sluigi break; 3479101641Sluigi 3480101641Sluigi case TOK_ENDBRACE: 3481101641Sluigi if (!open_par) 3482101641Sluigi errx(EX_USAGE, "+missing \")\"\n"); 3483101641Sluigi open_par = 0; 3484102087Sluigi prev = NULL; 3485220802Sglebius break; 3486101641Sluigi 348798943Sluigi case TOK_IN: 348898943Sluigi fill_cmd(cmd, O_IN, 0, 0); 348998943Sluigi break; 349098943Sluigi 349198943Sluigi case TOK_OUT: 349298943Sluigi cmd->len ^= F_NOT; /* toggle F_NOT */ 349398943Sluigi fill_cmd(cmd, O_IN, 0, 0); 349498943Sluigi break; 349598943Sluigi 3496136073Sgreen case TOK_DIVERTED: 3497136073Sgreen fill_cmd(cmd, O_DIVERTED, 0, 3); 3498136073Sgreen break; 3499136073Sgreen 3500136073Sgreen case TOK_DIVERTEDLOOPBACK: 3501136073Sgreen fill_cmd(cmd, O_DIVERTED, 0, 1); 3502136073Sgreen break; 3503136073Sgreen 3504136073Sgreen case TOK_DIVERTEDOUTPUT: 3505136073Sgreen fill_cmd(cmd, O_DIVERTED, 0, 2); 3506136073Sgreen break; 3507136073Sgreen 350898943Sluigi case TOK_FRAG: 350998943Sluigi fill_cmd(cmd, O_FRAG, 0, 0); 351098943Sluigi break; 351198943Sluigi 351298943Sluigi case TOK_LAYER2: 351398943Sluigi fill_cmd(cmd, O_LAYER2, 0, 0); 351498943Sluigi break; 351598943Sluigi 351698943Sluigi case TOK_XMIT: 351798943Sluigi case TOK_RECV: 351898943Sluigi case TOK_VIA: 351998943Sluigi NEED1("recv, xmit, via require interface name" 352098943Sluigi " or address"); 3521248505Smelifaro fill_iface((ipfw_insn_if *)cmd, av[0], cblen); 3522204591Sluigi av++; 352398943Sluigi if (F_LEN(cmd) == 0) /* not a valid address */ 352498943Sluigi break; 352598943Sluigi if (i == TOK_XMIT) 352698943Sluigi cmd->opcode = O_XMIT; 352798943Sluigi else if (i == TOK_RECV) 352898943Sluigi cmd->opcode = O_RECV; 352998943Sluigi else if (i == TOK_VIA) 353098943Sluigi cmd->opcode = O_VIA; 353198943Sluigi break; 353298943Sluigi 353399475Sluigi case TOK_ICMPTYPES: 353499475Sluigi NEED1("icmptypes requires list of types"); 353599475Sluigi fill_icmptypes((ipfw_insn_u32 *)cmd, *av); 3536204591Sluigi av++; 353799475Sluigi break; 3538220804Sglebius 3539145246Sbrooks case TOK_ICMP6TYPES: 3540145246Sbrooks NEED1("icmptypes requires list of types"); 3541248505Smelifaro fill_icmp6types((ipfw_insn_icmp6 *)cmd, *av, cblen); 3542204591Sluigi av++; 3543145246Sbrooks break; 354499475Sluigi 354598943Sluigi case TOK_IPTTL: 354698943Sluigi NEED1("ipttl requires TTL"); 3547116690Sluigi if (strpbrk(*av, "-,")) { 3548248505Smelifaro if (!add_ports(cmd, *av, 0, O_IPTTL, cblen)) 3549116690Sluigi errx(EX_DATAERR, "invalid ipttl %s", *av); 3550116690Sluigi } else 3551116690Sluigi fill_cmd(cmd, O_IPTTL, 0, strtoul(*av, NULL, 0)); 3552204591Sluigi av++; 355398943Sluigi break; 355498943Sluigi 355598943Sluigi case TOK_IPID: 3556116690Sluigi NEED1("ipid requires id"); 3557116690Sluigi if (strpbrk(*av, "-,")) { 3558248505Smelifaro if (!add_ports(cmd, *av, 0, O_IPID, cblen)) 3559116690Sluigi errx(EX_DATAERR, "invalid ipid %s", *av); 3560116690Sluigi } else 3561116690Sluigi fill_cmd(cmd, O_IPID, 0, strtoul(*av, NULL, 0)); 3562204591Sluigi av++; 356398943Sluigi break; 356498943Sluigi 356598943Sluigi case TOK_IPLEN: 356698943Sluigi NEED1("iplen requires length"); 3567116690Sluigi if (strpbrk(*av, "-,")) { 3568248505Smelifaro if (!add_ports(cmd, *av, 0, O_IPLEN, cblen)) 3569116690Sluigi errx(EX_DATAERR, "invalid ip len %s", *av); 3570116690Sluigi } else 3571116690Sluigi fill_cmd(cmd, O_IPLEN, 0, strtoul(*av, NULL, 0)); 3572204591Sluigi av++; 357398943Sluigi break; 357498943Sluigi 357598943Sluigi case TOK_IPVER: 357698943Sluigi NEED1("ipver requires version"); 357798943Sluigi fill_cmd(cmd, O_IPVER, 0, strtoul(*av, NULL, 0)); 3578204591Sluigi av++; 357998943Sluigi break; 358098943Sluigi 358199475Sluigi case TOK_IPPRECEDENCE: 358299475Sluigi NEED1("ipprecedence requires value"); 358399475Sluigi fill_cmd(cmd, O_IPPRECEDENCE, 0, 358499475Sluigi (strtoul(*av, NULL, 0) & 7) << 5); 3585204591Sluigi av++; 358699475Sluigi break; 358799475Sluigi 3588250762Smelifaro case TOK_DSCP: 3589250762Smelifaro NEED1("missing DSCP code"); 3590250762Smelifaro fill_dscp(cmd, *av, cblen); 3591250762Smelifaro av++; 3592250762Smelifaro break; 3593250762Smelifaro 359498943Sluigi case TOK_IPOPTS: 359598943Sluigi NEED1("missing argument for ipoptions"); 3596101116Sluigi fill_flags(cmd, O_IPOPT, f_ipopts, *av); 3597204591Sluigi av++; 359898943Sluigi break; 359998943Sluigi 360099475Sluigi case TOK_IPTOS: 360199475Sluigi NEED1("missing argument for iptos"); 3602101116Sluigi fill_flags(cmd, O_IPTOS, f_iptos, *av); 3603204591Sluigi av++; 360499475Sluigi break; 360599475Sluigi 360698943Sluigi case TOK_UID: 360798943Sluigi NEED1("uid requires argument"); 360898943Sluigi { 360998943Sluigi char *end; 361098943Sluigi uid_t uid; 361198943Sluigi struct passwd *pwd; 361298943Sluigi 361398943Sluigi cmd->opcode = O_UID; 361498943Sluigi uid = strtoul(*av, &end, 0); 361598943Sluigi pwd = (*end == '\0') ? getpwuid(uid) : getpwnam(*av); 361698943Sluigi if (pwd == NULL) 361798943Sluigi errx(EX_DATAERR, "uid \"%s\" nonexistent", *av); 3618106504Smaxim cmd32->d[0] = pwd->pw_uid; 3619135089Scsjp cmd->len |= F_INSN_SIZE(ipfw_insn_u32); 3620204591Sluigi av++; 362198943Sluigi } 362298943Sluigi break; 362398943Sluigi 362498943Sluigi case TOK_GID: 362598943Sluigi NEED1("gid requires argument"); 362698943Sluigi { 362798943Sluigi char *end; 362898943Sluigi gid_t gid; 362998943Sluigi struct group *grp; 363098943Sluigi 363198943Sluigi cmd->opcode = O_GID; 363298943Sluigi gid = strtoul(*av, &end, 0); 363398943Sluigi grp = (*end == '\0') ? getgrgid(gid) : getgrnam(*av); 363498943Sluigi if (grp == NULL) 363598943Sluigi errx(EX_DATAERR, "gid \"%s\" nonexistent", *av); 3636106504Smaxim cmd32->d[0] = grp->gr_gid; 3637135089Scsjp cmd->len |= F_INSN_SIZE(ipfw_insn_u32); 3638204591Sluigi av++; 363998943Sluigi } 364098943Sluigi break; 364198943Sluigi 3642133600Scsjp case TOK_JAIL: 3643133600Scsjp NEED1("jail requires argument"); 3644133600Scsjp { 3645133600Scsjp char *end; 3646133600Scsjp int jid; 3647133600Scsjp 3648133600Scsjp cmd->opcode = O_JAIL; 3649133600Scsjp jid = (int)strtol(*av, &end, 0); 3650133600Scsjp if (jid < 0 || *end != '\0') 3651133600Scsjp errx(EX_DATAERR, "jail requires prison ID"); 3652135554Scsjp cmd32->d[0] = (uint32_t)jid; 3653135089Scsjp cmd->len |= F_INSN_SIZE(ipfw_insn_u32); 3654204591Sluigi av++; 3655133600Scsjp } 3656133600Scsjp break; 3657133600Scsjp 365898943Sluigi case TOK_ESTAB: 365998943Sluigi fill_cmd(cmd, O_ESTAB, 0, 0); 366098943Sluigi break; 366198943Sluigi 366298943Sluigi case TOK_SETUP: 366398943Sluigi fill_cmd(cmd, O_TCPFLAGS, 0, 366498943Sluigi (TH_SYN) | ( (TH_ACK) & 0xff) <<8 ); 366598943Sluigi break; 366698943Sluigi 3667136075Sgreen case TOK_TCPDATALEN: 3668136075Sgreen NEED1("tcpdatalen requires length"); 3669136075Sgreen if (strpbrk(*av, "-,")) { 3670248505Smelifaro if (!add_ports(cmd, *av, 0, O_TCPDATALEN, cblen)) 3671136075Sgreen errx(EX_DATAERR, "invalid tcpdata len %s", *av); 3672136075Sgreen } else 3673136075Sgreen fill_cmd(cmd, O_TCPDATALEN, 0, 3674136075Sgreen strtoul(*av, NULL, 0)); 3675204591Sluigi av++; 3676136075Sgreen break; 3677136075Sgreen 367898943Sluigi case TOK_TCPOPTS: 367998943Sluigi NEED1("missing argument for tcpoptions"); 368098943Sluigi fill_flags(cmd, O_TCPOPTS, f_tcpopts, *av); 3681204591Sluigi av++; 368298943Sluigi break; 368398943Sluigi 368498943Sluigi case TOK_TCPSEQ: 368598943Sluigi case TOK_TCPACK: 368698943Sluigi NEED1("tcpseq/tcpack requires argument"); 368798943Sluigi cmd->len = F_INSN_SIZE(ipfw_insn_u32); 368898943Sluigi cmd->opcode = (i == TOK_TCPSEQ) ? O_TCPSEQ : O_TCPACK; 368998943Sluigi cmd32->d[0] = htonl(strtoul(*av, NULL, 0)); 3690204591Sluigi av++; 369198943Sluigi break; 369298943Sluigi 369398943Sluigi case TOK_TCPWIN: 369498943Sluigi NEED1("tcpwin requires length"); 3695234278Sglebius if (strpbrk(*av, "-,")) { 3696248505Smelifaro if (!add_ports(cmd, *av, 0, O_TCPWIN, cblen)) 3697234278Sglebius errx(EX_DATAERR, "invalid tcpwin len %s", *av); 3698234278Sglebius } else 3699234278Sglebius fill_cmd(cmd, O_TCPWIN, 0, 3700234278Sglebius strtoul(*av, NULL, 0)); 3701204591Sluigi av++; 370298943Sluigi break; 370398943Sluigi 370498943Sluigi case TOK_TCPFLAGS: 370598943Sluigi NEED1("missing argument for tcpflags"); 370698943Sluigi cmd->opcode = O_TCPFLAGS; 370798943Sluigi fill_flags(cmd, O_TCPFLAGS, f_tcpflags, *av); 3708204591Sluigi av++; 370998943Sluigi break; 371098943Sluigi 371198943Sluigi case TOK_KEEPSTATE: 3712101641Sluigi if (open_par) 3713101641Sluigi errx(EX_USAGE, "keep-state cannot be part " 3714101641Sluigi "of an or block"); 371599909Sluigi if (have_state) 3716101116Sluigi errx(EX_USAGE, "only one of keep-state " 371799909Sluigi "and limit is allowed"); 3718101116Sluigi have_state = cmd; 371998943Sluigi fill_cmd(cmd, O_KEEP_STATE, 0, 0); 372098943Sluigi break; 372198943Sluigi 3722159636Soleg case TOK_LIMIT: { 3723159636Soleg ipfw_insn_limit *c = (ipfw_insn_limit *)cmd; 3724159636Soleg int val; 3725159636Soleg 3726101641Sluigi if (open_par) 3727159636Soleg errx(EX_USAGE, 3728159636Soleg "limit cannot be part of an or block"); 372999909Sluigi if (have_state) 3730168819Smaxim errx(EX_USAGE, "only one of keep-state and " 3731159636Soleg "limit is allowed"); 3732101116Sluigi have_state = cmd; 373398943Sluigi 373498943Sluigi cmd->len = F_INSN_SIZE(ipfw_insn_limit); 3735248505Smelifaro CHECK_CMDLEN; 373698943Sluigi cmd->opcode = O_LIMIT; 3737159636Soleg c->limit_mask = c->conn_limit = 0; 373898943Sluigi 3739204591Sluigi while ( av[0] != NULL ) { 3740159636Soleg if ((val = match_token(limit_masks, *av)) <= 0) 374198943Sluigi break; 374298943Sluigi c->limit_mask |= val; 3743204591Sluigi av++; 374498943Sluigi } 3745159636Soleg 374698943Sluigi if (c->limit_mask == 0) 3747159636Soleg errx(EX_USAGE, "limit: missing limit mask"); 3748159636Soleg 3749193516Sluigi GET_UINT_ARG(c->conn_limit, IPFW_ARG_MIN, IPFW_ARG_MAX, 3750182823Srik TOK_LIMIT, rule_options); 3751159636Soleg 3752204591Sluigi av++; 375398943Sluigi break; 3754159636Soleg } 375598943Sluigi 3756102087Sluigi case TOK_PROTO: 3757102087Sluigi NEED1("missing protocol"); 3758145246Sbrooks if (add_proto(cmd, *av, &proto)) { 3759204591Sluigi av++; 3760102098Sluigi } else 3761116438Smaxim errx(EX_DATAERR, "invalid protocol ``%s''", 3762116438Smaxim *av); 3763102087Sluigi break; 3764106505Smaxim 3765102087Sluigi case TOK_SRCIP: 3766102087Sluigi NEED1("missing source IP"); 3767248505Smelifaro if (add_srcip(cmd, *av, cblen)) { 3768204591Sluigi av++; 3769102087Sluigi } 3770102087Sluigi break; 3771102087Sluigi 3772102087Sluigi case TOK_DSTIP: 3773102087Sluigi NEED1("missing destination IP"); 3774248505Smelifaro if (add_dstip(cmd, *av, cblen)) { 3775204591Sluigi av++; 3776102087Sluigi } 3777102087Sluigi break; 3778102087Sluigi 3779145246Sbrooks case TOK_SRCIP6: 3780145246Sbrooks NEED1("missing source IP6"); 3781248505Smelifaro if (add_srcip6(cmd, *av, cblen)) { 3782204591Sluigi av++; 3783145246Sbrooks } 3784145246Sbrooks break; 3785220804Sglebius 3786145246Sbrooks case TOK_DSTIP6: 3787145246Sbrooks NEED1("missing destination IP6"); 3788248505Smelifaro if (add_dstip6(cmd, *av, cblen)) { 3789204591Sluigi av++; 3790145246Sbrooks } 3791145246Sbrooks break; 3792145246Sbrooks 3793102087Sluigi case TOK_SRCPORT: 3794102087Sluigi NEED1("missing source port"); 3795140271Sbrooks if (_substrcmp(*av, "any") == 0 || 3796248505Smelifaro add_ports(cmd, *av, proto, O_IP_SRCPORT, cblen)) { 3797204591Sluigi av++; 3798102087Sluigi } else 3799102087Sluigi errx(EX_DATAERR, "invalid source port %s", *av); 3800102087Sluigi break; 3801102087Sluigi 3802102087Sluigi case TOK_DSTPORT: 3803102087Sluigi NEED1("missing destination port"); 3804140271Sbrooks if (_substrcmp(*av, "any") == 0 || 3805248505Smelifaro add_ports(cmd, *av, proto, O_IP_DSTPORT, cblen)) { 3806204591Sluigi av++; 3807102087Sluigi } else 3808102087Sluigi errx(EX_DATAERR, "invalid destination port %s", 3809102087Sluigi *av); 3810102087Sluigi break; 3811102087Sluigi 3812102087Sluigi case TOK_MAC: 3813248505Smelifaro if (add_mac(cmd, av, cblen)) 3814204591Sluigi av += 2; 3815102087Sluigi break; 3816102087Sluigi 3817102087Sluigi case TOK_MACTYPE: 3818102087Sluigi NEED1("missing mac type"); 3819248505Smelifaro if (!add_mactype(cmd, *av, cblen)) 3820116438Smaxim errx(EX_DATAERR, "invalid mac type %s", *av); 3821204591Sluigi av++; 3822102087Sluigi break; 3823102087Sluigi 3824112250Scjc case TOK_VERREVPATH: 3825112250Scjc fill_cmd(cmd, O_VERREVPATH, 0, 0); 3826112250Scjc break; 3827116919Sluigi 3828128575Sandre case TOK_VERSRCREACH: 3829128575Sandre fill_cmd(cmd, O_VERSRCREACH, 0, 0); 3830128575Sandre break; 3831128575Sandre 3832133387Sandre case TOK_ANTISPOOF: 3833133387Sandre fill_cmd(cmd, O_ANTISPOOF, 0, 0); 3834133387Sandre break; 3835133387Sandre 3836117241Sluigi case TOK_IPSEC: 3837117241Sluigi fill_cmd(cmd, O_IPSEC, 0, 0); 3838117241Sluigi break; 3839117241Sluigi 3840145246Sbrooks case TOK_IPV6: 3841145246Sbrooks fill_cmd(cmd, O_IP6, 0, 0); 3842145246Sbrooks break; 3843145246Sbrooks 3844146894Smlaier case TOK_IPV4: 3845146894Smlaier fill_cmd(cmd, O_IP4, 0, 0); 3846146894Smlaier break; 3847146894Smlaier 3848145246Sbrooks case TOK_EXT6HDR: 3849145246Sbrooks fill_ext6hdr( cmd, *av ); 3850204591Sluigi av++; 3851145246Sbrooks break; 3852145246Sbrooks 3853145246Sbrooks case TOK_FLOWID: 3854145246Sbrooks if (proto != IPPROTO_IPV6 ) 3855145246Sbrooks errx( EX_USAGE, "flow-id filter is active " 3856145246Sbrooks "only for ipv6 protocol\n"); 3857248505Smelifaro fill_flow6( (ipfw_insn_u32 *) cmd, *av, cblen); 3858204591Sluigi av++; 3859145246Sbrooks break; 3860145246Sbrooks 3861117469Sluigi case TOK_COMMENT: 3862248505Smelifaro fill_comment(cmd, av, cblen); 3863204591Sluigi av[0]=NULL; 3864117469Sluigi break; 3865117469Sluigi 3866158879Soleg case TOK_TAGGED: 3867204591Sluigi if (av[0] && strpbrk(*av, "-,")) { 3868248505Smelifaro if (!add_ports(cmd, *av, 0, O_TAGGED, cblen)) 3869159636Soleg errx(EX_DATAERR, "tagged: invalid tag" 3870159636Soleg " list: %s", *av); 3871158879Soleg } 3872159636Soleg else { 3873159636Soleg uint16_t tag; 3874159636Soleg 3875193516Sluigi GET_UINT_ARG(tag, IPFW_ARG_MIN, IPFW_ARG_MAX, 3876182823Srik TOK_TAGGED, rule_options); 3877159636Soleg fill_cmd(cmd, O_TAGGED, 0, tag); 3878159636Soleg } 3879204591Sluigi av++; 3880158879Soleg break; 3881158879Soleg 3882178888Sjulian case TOK_FIB: 3883178888Sjulian NEED1("fib requires fib number"); 3884178888Sjulian fill_cmd(cmd, O_FIB, 0, strtoul(*av, NULL, 0)); 3885204591Sluigi av++; 3886178888Sjulian break; 3887215179Sluigi case TOK_SOCKARG: 3888215179Sluigi fill_cmd(cmd, O_SOCKARG, 0, 0); 3889215179Sluigi break; 3890178888Sjulian 3891200567Sluigi case TOK_LOOKUP: { 3892200567Sluigi ipfw_insn_u32 *c = (ipfw_insn_u32 *)cmd; 3893200567Sluigi char *p; 3894200567Sluigi int j; 3895200567Sluigi 3896205169Sluigi if (!av[0] || !av[1]) 3897200567Sluigi errx(EX_USAGE, "format: lookup argument tablenum"); 3898200567Sluigi cmd->opcode = O_IP_DST_LOOKUP; 3899200567Sluigi cmd->len |= F_INSN_SIZE(ipfw_insn) + 2; 3900200567Sluigi i = match_token(rule_options, *av); 3901200567Sluigi for (j = 0; lookup_key[j] >= 0 ; j++) { 3902200567Sluigi if (i == lookup_key[j]) 3903200567Sluigi break; 3904200567Sluigi } 3905200567Sluigi if (lookup_key[j] <= 0) 3906200567Sluigi errx(EX_USAGE, "format: cannot lookup on %s", *av); 3907223262Sbenl __PAST_END(c->d, 1) = j; // i converted to option 3908204591Sluigi av++; 3909200567Sluigi cmd->arg1 = strtoul(*av, &p, 0); 3910200567Sluigi if (p && *p) 3911200567Sluigi errx(EX_USAGE, "format: lookup argument tablenum"); 3912204591Sluigi av++; 3913200567Sluigi } 3914200567Sluigi break; 3915200567Sluigi 391698943Sluigi default: 391798943Sluigi errx(EX_USAGE, "unrecognised option [%d] %s\n", i, s); 391898943Sluigi } 391998943Sluigi if (F_LEN(cmd) > 0) { /* prepare to advance */ 392098943Sluigi prev = cmd; 3921248505Smelifaro cmd = next_cmd(cmd, &cblen); 392298943Sluigi } 392398943Sluigi } 392498943Sluigi 392598943Sluigidone: 392698943Sluigi /* 392798943Sluigi * Now copy stuff into the rule. 392898943Sluigi * If we have a keep-state option, the first instruction 392998943Sluigi * must be a PROBE_STATE (which is generated here). 393098943Sluigi * If we have a LOG option, it was stored as the first command, 393198943Sluigi * and now must be moved to the top of the action part. 393298943Sluigi */ 393398943Sluigi dst = (ipfw_insn *)rule->cmd; 393498943Sluigi 393598943Sluigi /* 3936107289Sluigi * First thing to write into the command stream is the match probability. 3937107289Sluigi */ 3938107289Sluigi if (match_prob != 1) { /* 1 means always match */ 3939107289Sluigi dst->opcode = O_PROB; 3940107289Sluigi dst->len = 2; 3941107289Sluigi *((int32_t *)(dst+1)) = (int32_t)(match_prob * 0x7fffffff); 3942107289Sluigi dst += dst->len; 3943107289Sluigi } 3944107289Sluigi 3945107289Sluigi /* 394698943Sluigi * generate O_PROBE_STATE if necessary 394798943Sluigi */ 3948101116Sluigi if (have_state && have_state->opcode != O_CHECK_STATE) { 394998943Sluigi fill_cmd(dst, O_PROBE_STATE, 0, 0); 3950248505Smelifaro dst = next_cmd(dst, &rblen); 395198943Sluigi } 3952158879Soleg 3953158879Soleg /* copy all commands but O_LOG, O_KEEP_STATE, O_LIMIT, O_ALTQ, O_TAG */ 395498943Sluigi for (src = (ipfw_insn *)cmdbuf; src != cmd; src += i) { 395598943Sluigi i = F_LEN(src); 3956248505Smelifaro CHECK_RBUFLEN(i); 395798943Sluigi 3958101116Sluigi switch (src->opcode) { 3959101116Sluigi case O_LOG: 3960101116Sluigi case O_KEEP_STATE: 3961101116Sluigi case O_LIMIT: 3962136071Sgreen case O_ALTQ: 3963158879Soleg case O_TAG: 3964101116Sluigi break; 3965101116Sluigi default: 3966117328Sluigi bcopy(src, dst, i * sizeof(uint32_t)); 396798943Sluigi dst += i; 396898943Sluigi } 396998943Sluigi } 397098943Sluigi 397198943Sluigi /* 3972101116Sluigi * put back the have_state command as last opcode 3973101116Sluigi */ 3974101295Sluigi if (have_state && have_state->opcode != O_CHECK_STATE) { 3975101116Sluigi i = F_LEN(have_state); 3976248505Smelifaro CHECK_RBUFLEN(i); 3977117328Sluigi bcopy(have_state, dst, i * sizeof(uint32_t)); 3978101116Sluigi dst += i; 3979101116Sluigi } 3980101116Sluigi /* 398198943Sluigi * start action section 398298943Sluigi */ 398398943Sluigi rule->act_ofs = dst - rule->cmd; 398498943Sluigi 3985158879Soleg /* put back O_LOG, O_ALTQ, O_TAG if necessary */ 3986136071Sgreen if (have_log) { 3987136071Sgreen i = F_LEN(have_log); 3988248505Smelifaro CHECK_RBUFLEN(i); 3989136071Sgreen bcopy(have_log, dst, i * sizeof(uint32_t)); 399098943Sluigi dst += i; 399198943Sluigi } 3992136071Sgreen if (have_altq) { 3993136071Sgreen i = F_LEN(have_altq); 3994248505Smelifaro CHECK_RBUFLEN(i); 3995136071Sgreen bcopy(have_altq, dst, i * sizeof(uint32_t)); 3996136071Sgreen dst += i; 3997136071Sgreen } 3998158879Soleg if (have_tag) { 3999158879Soleg i = F_LEN(have_tag); 4000248505Smelifaro CHECK_RBUFLEN(i); 4001158879Soleg bcopy(have_tag, dst, i * sizeof(uint32_t)); 4002158879Soleg dst += i; 4003158879Soleg } 4004248505Smelifaro 400598943Sluigi /* 400698943Sluigi * copy all other actions 400798943Sluigi */ 400898943Sluigi for (src = (ipfw_insn *)actbuf; src != action; src += i) { 400998943Sluigi i = F_LEN(src); 4010248505Smelifaro CHECK_RBUFLEN(i); 4011117328Sluigi bcopy(src, dst, i * sizeof(uint32_t)); 401298943Sluigi dst += i; 401398943Sluigi } 401498943Sluigi 4015117328Sluigi rule->cmd_len = (uint32_t *)dst - (uint32_t *)(rule->cmd); 4016117469Sluigi i = (char *)dst - (char *)rule; 4017119740Stmm if (do_cmd(IP_FW_ADD, rule, (uintptr_t)&i) == -1) 401898943Sluigi err(EX_UNAVAILABLE, "getsockopt(%s)", "IP_FW_ADD"); 4019187764Sluigi if (!co.do_quiet) 4020117469Sluigi show_ipfw(rule, 0, 0); 402198943Sluigi} 402298943Sluigi 4023187767Sluigi/* 4024187767Sluigi * clear the counters or the log counters. 4025187767Sluigi */ 4026187767Sluigivoid 4027187767Sluigiipfw_zero(int ac, char *av[], int optname /* 0 = IP_FW_ZERO, 1 = IP_FW_RESETLOG */) 402898943Sluigi{ 4029170923Smaxim uint32_t arg, saved_arg; 403098943Sluigi int failed = EX_OK; 4031170923Smaxim char const *errstr; 4032187767Sluigi char const *name = optname ? "RESETLOG" : "ZERO"; 403398943Sluigi 4034187767Sluigi optname = optname ? IP_FW_RESETLOG : IP_FW_ZERO; 4035187767Sluigi 403698943Sluigi av++; ac--; 403798943Sluigi 403898943Sluigi if (!ac) { 403998943Sluigi /* clear all entries */ 4040117328Sluigi if (do_cmd(optname, NULL, 0) < 0) 4041117328Sluigi err(EX_UNAVAILABLE, "setsockopt(IP_FW_%s)", name); 4042187764Sluigi if (!co.do_quiet) 4043117328Sluigi printf("%s.\n", optname == IP_FW_ZERO ? 4044117328Sluigi "Accounting cleared":"Logging counts reset"); 404598943Sluigi 404698943Sluigi return; 404798943Sluigi } 404898943Sluigi 404998943Sluigi while (ac) { 405098943Sluigi /* Rule number */ 405198943Sluigi if (isdigit(**av)) { 4052170923Smaxim arg = strtonum(*av, 0, 0xffff, &errstr); 4053170923Smaxim if (errstr) 4054170923Smaxim errx(EX_DATAERR, 4055170923Smaxim "invalid rule number %s\n", *av); 4056170923Smaxim saved_arg = arg; 4057187764Sluigi if (co.use_set) 4058187764Sluigi arg |= (1 << 24) | ((co.use_set - 1) << 16); 405998943Sluigi av++; 406098943Sluigi ac--; 4061170923Smaxim if (do_cmd(optname, &arg, sizeof(arg))) { 4062117328Sluigi warn("rule %u: setsockopt(IP_FW_%s)", 4063170923Smaxim saved_arg, name); 406498943Sluigi failed = EX_UNAVAILABLE; 4065187764Sluigi } else if (!co.do_quiet) 4066170923Smaxim printf("Entry %d %s.\n", saved_arg, 4067117328Sluigi optname == IP_FW_ZERO ? 4068117328Sluigi "cleared" : "logging count reset"); 406998943Sluigi } else { 407098943Sluigi errx(EX_USAGE, "invalid rule number ``%s''", *av); 407198943Sluigi } 407298943Sluigi } 407398943Sluigi if (failed != EX_OK) 407498943Sluigi exit(failed); 407598943Sluigi} 407698943Sluigi 4077187767Sluigivoid 4078187767Sluigiipfw_flush(int force) 407998943Sluigi{ 4080187764Sluigi int cmd = co.do_pipe ? IP_DUMMYNET_FLUSH : IP_FW_FLUSH; 408198943Sluigi 4082187764Sluigi if (!force && !co.do_quiet) { /* need to ask user */ 408398943Sluigi int c; 408498943Sluigi 408598943Sluigi printf("Are you sure? [yn] "); 408698943Sluigi fflush(stdout); 408798943Sluigi do { 408898943Sluigi c = toupper(getc(stdin)); 408998943Sluigi while (c != '\n' && getc(stdin) != '\n') 409098943Sluigi if (feof(stdin)) 409198943Sluigi return; /* and do not flush */ 409298943Sluigi } while (c != 'Y' && c != 'N'); 409398943Sluigi printf("\n"); 409498943Sluigi if (c == 'N') /* user said no */ 409598943Sluigi return; 409698943Sluigi } 4097204591Sluigi if (co.do_pipe) { 4098204591Sluigi dummynet_flush(); 4099204591Sluigi return; 4100204591Sluigi } 4101170923Smaxim /* `ipfw set N flush` - is the same that `ipfw delete set N` */ 4102187764Sluigi if (co.use_set) { 4103187764Sluigi uint32_t arg = ((co.use_set - 1) & 0xffff) | (1 << 24); 4104170923Smaxim if (do_cmd(IP_FW_DEL, &arg, sizeof(arg)) < 0) 4105170923Smaxim err(EX_UNAVAILABLE, "setsockopt(IP_FW_DEL)"); 4106170923Smaxim } else if (do_cmd(cmd, NULL, 0) < 0) 410798943Sluigi err(EX_UNAVAILABLE, "setsockopt(IP_%s_FLUSH)", 4108187764Sluigi co.do_pipe ? "DUMMYNET" : "FW"); 4109187764Sluigi if (!co.do_quiet) 4110187764Sluigi printf("Flushed all %s.\n", co.do_pipe ? "pipes" : "rules"); 411198943Sluigi} 411298943Sluigi 4113117544Sluigi 4114234597Smelifarostatic void table_list(uint16_t num, int need_header); 4115248505Smelifarostatic void table_fill_xentry(char *arg, ipfw_table_xentry *xent); 4116183228Srik 4117117544Sluigi/* 4118265699Smelifaro * Retrieve maximum number of tables supported by ipfw(4) module. 4119265699Smelifaro */ 4120265699Smelifarouint32_t 4121265699Smelifaroipfw_get_tables_max() 4122265699Smelifaro{ 4123265699Smelifaro size_t len; 4124265699Smelifaro uint32_t tables_max; 4125265699Smelifaro 4126265699Smelifaro if (ipfw_tables_max != 0) 4127265699Smelifaro return (ipfw_tables_max); 4128265699Smelifaro 4129265699Smelifaro len = sizeof(tables_max); 4130265699Smelifaro if (sysctlbyname("net.inet.ip.fw.tables_max", &tables_max, &len, 4131265699Smelifaro NULL, 0) == -1) { 4132265699Smelifaro if (co.test_only) 4133265699Smelifaro tables_max = 128; /* Old conservative default */ 4134265699Smelifaro else 4135265699Smelifaro errx(1, "Can't determine maximum number of ipfw tables." 4136265699Smelifaro " Perhaps you forgot to load ipfw module?"); 4137265699Smelifaro } 4138265699Smelifaro 4139265699Smelifaro ipfw_tables_max = tables_max; 4140265699Smelifaro 4141265699Smelifaro return (ipfw_tables_max); 4142265699Smelifaro} 4143265699Smelifaro 4144265699Smelifaro/* 4145130281Sru * This one handles all table-related commands 4146130281Sru * ipfw table N add addr[/masklen] [value] 4147130281Sru * ipfw table N delete addr[/masklen] 4148183407Srik * ipfw table {N | all} flush 4149183407Srik * ipfw table {N | all} list 4150130281Sru */ 4151187767Sluigivoid 4152187767Sluigiipfw_table_handler(int ac, char *av[]) 4153130281Sru{ 4154234597Smelifaro ipfw_table_xentry xent; 4155130281Sru int do_add; 4156183407Srik int is_all; 4157248505Smelifaro uint32_t a; 4158183241Srik uint32_t tables_max; 4159130281Sru 4160265699Smelifaro tables_max = ipfw_get_tables_max(); 4161183241Srik 4162234597Smelifaro memset(&xent, 0, sizeof(xent)); 4163234597Smelifaro 4164130281Sru ac--; av++; 4165130281Sru if (ac && isdigit(**av)) { 4166234597Smelifaro xent.tbl = atoi(*av); 4167183407Srik is_all = 0; 4168130281Sru ac--; av++; 4169183407Srik } else if (ac && _substrcmp(*av, "all") == 0) { 4170234597Smelifaro xent.tbl = 0; 4171183407Srik is_all = 1; 4172183407Srik ac--; av++; 4173130281Sru } else 4174183407Srik errx(EX_USAGE, "table number or 'all' keyword required"); 4175234597Smelifaro if (xent.tbl >= tables_max) 4176183241Srik errx(EX_USAGE, "The table number exceeds the maximum allowed " 4177183241Srik "value (%d)", tables_max - 1); 4178130281Sru NEED1("table needs command"); 4179183407Srik if (is_all && _substrcmp(*av, "list") != 0 4180183407Srik && _substrcmp(*av, "flush") != 0) 4181183407Srik errx(EX_USAGE, "table number required"); 4182183407Srik 4183140271Sbrooks if (_substrcmp(*av, "add") == 0 || 4184140271Sbrooks _substrcmp(*av, "delete") == 0) { 4185130281Sru do_add = **av == 'a'; 4186130281Sru ac--; av++; 4187130281Sru if (!ac) 4188234597Smelifaro errx(EX_USAGE, "address required"); 4189234597Smelifaro 4190248505Smelifaro table_fill_xentry(*av, &xent); 4191234597Smelifaro 4192130281Sru ac--; av++; 4193161424Sjulian if (do_add && ac) { 4194161424Sjulian unsigned int tval; 4195161424Sjulian /* isdigit is a bit of a hack here.. */ 4196161424Sjulian if (strchr(*av, (int)'.') == NULL && isdigit(**av)) { 4197234597Smelifaro xent.value = strtoul(*av, NULL, 0); 4198161424Sjulian } else { 4199220802Sglebius if (lookup_host(*av, (struct in_addr *)&tval) == 0) { 4200161424Sjulian /* The value must be stored in host order * 4201161424Sjulian * so that the values < 65k can be distinguished */ 4202234597Smelifaro xent.value = ntohl(tval); 4203161424Sjulian } else { 4204161424Sjulian errx(EX_NOHOST, "hostname ``%s'' unknown", *av); 4205161424Sjulian } 4206161424Sjulian } 4207161424Sjulian } else 4208234597Smelifaro xent.value = 0; 4209234597Smelifaro if (do_setcmd3(do_add ? IP_FW_TABLE_XADD : IP_FW_TABLE_XDEL, 4210234597Smelifaro &xent, xent.len) < 0) { 4211155639Sjulian /* If running silent, don't bomb out on these errors. */ 4212187764Sluigi if (!(co.do_quiet && (errno == (do_add ? EEXIST : ESRCH)))) 4213155639Sjulian err(EX_OSERR, "setsockopt(IP_FW_TABLE_%s)", 4214234597Smelifaro do_add ? "XADD" : "XDEL"); 4215155639Sjulian /* In silent mode, react to a failed add by deleting */ 4216157332Sjulian if (do_add) { 4217234597Smelifaro do_setcmd3(IP_FW_TABLE_XDEL, &xent, xent.len); 4218234597Smelifaro if (do_setcmd3(IP_FW_TABLE_XADD, &xent, xent.len) < 0) 4219155639Sjulian err(EX_OSERR, 4220234597Smelifaro "setsockopt(IP_FW_TABLE_XADD)"); 4221157332Sjulian } 4222157335Sjulian } 4223140271Sbrooks } else if (_substrcmp(*av, "flush") == 0) { 4224234597Smelifaro a = is_all ? tables_max : (uint32_t)(xent.tbl + 1); 4225183407Srik do { 4226234597Smelifaro if (do_cmd(IP_FW_TABLE_FLUSH, &xent.tbl, 4227234597Smelifaro sizeof(xent.tbl)) < 0) 4228183407Srik err(EX_OSERR, "setsockopt(IP_FW_TABLE_FLUSH)"); 4229234597Smelifaro } while (++xent.tbl < a); 4230140271Sbrooks } else if (_substrcmp(*av, "list") == 0) { 4231234597Smelifaro a = is_all ? tables_max : (uint32_t)(xent.tbl + 1); 4232183407Srik do { 4233234597Smelifaro table_list(xent.tbl, is_all); 4234234597Smelifaro } while (++xent.tbl < a); 4235183228Srik } else 4236183228Srik errx(EX_USAGE, "invalid table command %s", *av); 4237183228Srik} 4238183205Srik 4239183228Srikstatic void 4240248505Smelifarotable_fill_xentry(char *arg, ipfw_table_xentry *xent) 4241248505Smelifaro{ 4242248505Smelifaro int addrlen, mask, masklen, type; 4243248505Smelifaro struct in6_addr *paddr; 4244248505Smelifaro uint32_t *pkey; 4245248505Smelifaro char *p; 4246248505Smelifaro uint32_t key; 4247248505Smelifaro 4248248505Smelifaro mask = 0; 4249248505Smelifaro type = 0; 4250248505Smelifaro addrlen = 0; 4251248505Smelifaro masklen = 0; 4252248505Smelifaro 4253248505Smelifaro /* 4254248505Smelifaro * Let's try to guess type by agrument. 4255248505Smelifaro * Possible types: 4256248505Smelifaro * 1) IPv4[/mask] 4257248505Smelifaro * 2) IPv6[/mask] 4258248505Smelifaro * 3) interface name 4259248505Smelifaro * 4) port, uid/gid or other u32 key (base 10 format) 4260248505Smelifaro * 5) hostname 4261248505Smelifaro */ 4262248505Smelifaro paddr = &xent->k.addr6; 4263248505Smelifaro if (ishexnumber(*arg) != 0 || *arg == ':') { 4264248505Smelifaro /* Remove / if exists */ 4265248505Smelifaro if ((p = strchr(arg, '/')) != NULL) { 4266248505Smelifaro *p = '\0'; 4267248505Smelifaro mask = atoi(p + 1); 4268248505Smelifaro } 4269248505Smelifaro 4270248505Smelifaro if (inet_pton(AF_INET, arg, paddr) == 1) { 4271248505Smelifaro if (p != NULL && mask > 32) 4272248505Smelifaro errx(EX_DATAERR, "bad IPv4 mask width: %s", 4273248505Smelifaro p + 1); 4274248505Smelifaro 4275248505Smelifaro type = IPFW_TABLE_CIDR; 4276248505Smelifaro masklen = p ? mask : 32; 4277248505Smelifaro addrlen = sizeof(struct in_addr); 4278248505Smelifaro } else if (inet_pton(AF_INET6, arg, paddr) == 1) { 4279248505Smelifaro if (IN6_IS_ADDR_V4COMPAT(paddr)) 4280248505Smelifaro errx(EX_DATAERR, 4281248505Smelifaro "Use IPv4 instead of v4-compatible"); 4282248505Smelifaro if (p != NULL && mask > 128) 4283248505Smelifaro errx(EX_DATAERR, "bad IPv6 mask width: %s", 4284248505Smelifaro p + 1); 4285248505Smelifaro 4286248505Smelifaro type = IPFW_TABLE_CIDR; 4287248505Smelifaro masklen = p ? mask : 128; 4288248505Smelifaro addrlen = sizeof(struct in6_addr); 4289248505Smelifaro } else { 4290248505Smelifaro /* Port or any other key */ 4291265692Smelifaro /* Skip non-base 10 entries like 'fa1' */ 4292248505Smelifaro key = strtol(arg, &p, 10); 4293265692Smelifaro if (*p == '\0') { 4294248505Smelifaro pkey = (uint32_t *)paddr; 4295248505Smelifaro *pkey = htonl(key); 4296248505Smelifaro type = IPFW_TABLE_CIDR; 4297265692Smelifaro masklen = 32; 4298248505Smelifaro addrlen = sizeof(uint32_t); 4299265692Smelifaro } else if ((p != arg) && (*p == '.')) { 4300265692Smelifaro /* 4301265692Smelifaro * Warn on IPv4 address strings 4302265692Smelifaro * which are "valid" for inet_aton() but not 4303265692Smelifaro * in inet_pton(). 4304265692Smelifaro * 4305265692Smelifaro * Typical examples: '10.5' or '10.0.0.05' 4306265692Smelifaro */ 4307265692Smelifaro errx(EX_DATAERR, 4308265692Smelifaro "Invalid IPv4 address: %s", arg); 4309248505Smelifaro } 4310248505Smelifaro } 4311248505Smelifaro } 4312248505Smelifaro 4313248505Smelifaro if (type == 0 && strchr(arg, '.') == NULL) { 4314248505Smelifaro /* Assume interface name. Copy significant data only */ 4315248505Smelifaro mask = MIN(strlen(arg), IF_NAMESIZE - 1); 4316248505Smelifaro memcpy(xent->k.iface, arg, mask); 4317248505Smelifaro /* Set mask to exact match */ 4318248505Smelifaro masklen = 8 * IF_NAMESIZE; 4319248505Smelifaro type = IPFW_TABLE_INTERFACE; 4320248505Smelifaro addrlen = IF_NAMESIZE; 4321248505Smelifaro } 4322248505Smelifaro 4323248505Smelifaro if (type == 0) { 4324248505Smelifaro if (lookup_host(arg, (struct in_addr *)paddr) != 0) 4325248505Smelifaro errx(EX_NOHOST, "hostname ``%s'' unknown", arg); 4326248505Smelifaro 4327248505Smelifaro masklen = 32; 4328248505Smelifaro type = IPFW_TABLE_CIDR; 4329248505Smelifaro addrlen = sizeof(struct in_addr); 4330248505Smelifaro } 4331248505Smelifaro 4332248505Smelifaro xent->type = type; 4333248505Smelifaro xent->masklen = masklen; 4334248505Smelifaro xent->len = offsetof(ipfw_table_xentry, k) + addrlen; 4335248505Smelifaro} 4336248505Smelifaro 4337248505Smelifarostatic void 4338234597Smelifarotable_list(uint16_t num, int need_header) 4339183228Srik{ 4340234597Smelifaro ipfw_xtable *tbl; 4341234597Smelifaro ipfw_table_xentry *xent; 4342183228Srik socklen_t l; 4343234597Smelifaro uint32_t *a, sz, tval; 4344234597Smelifaro char tbuf[128]; 4345234597Smelifaro struct in6_addr *addr6; 4346234597Smelifaro ip_fw3_opheader *op3; 4347183205Srik 4348234597Smelifaro /* Prepend value with IP_FW3 header */ 4349234597Smelifaro l = sizeof(ip_fw3_opheader) + sizeof(uint32_t); 4350234597Smelifaro op3 = alloca(l); 4351234597Smelifaro /* Zero reserved fields */ 4352234597Smelifaro memset(op3, 0, sizeof(ip_fw3_opheader)); 4353234597Smelifaro a = (uint32_t *)(op3 + 1); 4354234597Smelifaro *a = num; 4355234597Smelifaro op3->opcode = IP_FW_TABLE_XGETSIZE; 4356234597Smelifaro if (do_cmd(IP_FW3, op3, (uintptr_t)&l) < 0) 4357234597Smelifaro err(EX_OSERR, "getsockopt(IP_FW_TABLE_XGETSIZE)"); 4358183228Srik 4359183228Srik /* If a is zero we have nothing to do, the table is empty. */ 4360234597Smelifaro if (*a == 0) 4361183228Srik return; 4362183228Srik 4363234597Smelifaro l = *a; 4364187716Sluigi tbl = safe_calloc(1, l); 4365234597Smelifaro tbl->opheader.opcode = IP_FW_TABLE_XLIST; 4366234597Smelifaro tbl->tbl = num; 4367234597Smelifaro if (do_cmd(IP_FW3, tbl, (uintptr_t)&l) < 0) 4368234597Smelifaro err(EX_OSERR, "getsockopt(IP_FW_TABLE_XLIST)"); 4369183407Srik if (tbl->cnt && need_header) 4370183407Srik printf("---table(%d)---\n", tbl->tbl); 4371234597Smelifaro sz = tbl->size - sizeof(ipfw_xtable); 4372234597Smelifaro xent = &tbl->xent[0]; 4373234597Smelifaro while (sz > 0) { 4374234597Smelifaro switch (tbl->type) { 4375234597Smelifaro case IPFW_TABLE_CIDR: 4376234597Smelifaro /* IPv4 or IPv6 prefixes */ 4377234597Smelifaro tval = xent->value; 4378234597Smelifaro addr6 = &xent->k.addr6; 4379234597Smelifaro 4380248505Smelifaro 4381248505Smelifaro if (IN6_IS_ADDR_V4COMPAT(addr6)) { 4382234597Smelifaro /* IPv4 address */ 4383234597Smelifaro inet_ntop(AF_INET, &addr6->s6_addr32[3], tbuf, sizeof(tbuf)); 4384234597Smelifaro } else { 4385234597Smelifaro /* IPv6 address */ 4386234597Smelifaro inet_ntop(AF_INET6, addr6, tbuf, sizeof(tbuf)); 4387234597Smelifaro } 4388234597Smelifaro 4389234597Smelifaro if (co.do_value_as_ip) { 4390234597Smelifaro tval = htonl(tval); 4391234597Smelifaro printf("%s/%u %s\n", tbuf, xent->masklen, 4392234597Smelifaro inet_ntoa(*(struct in_addr *)&tval)); 4393234597Smelifaro } else 4394234597Smelifaro printf("%s/%u %u\n", tbuf, xent->masklen, tval); 4395234597Smelifaro break; 4396234597Smelifaro case IPFW_TABLE_INTERFACE: 4397234597Smelifaro /* Interface names */ 4398234597Smelifaro tval = xent->value; 4399234597Smelifaro if (co.do_value_as_ip) { 4400234597Smelifaro tval = htonl(tval); 4401234597Smelifaro printf("%s %s\n", xent->k.iface, 4402234597Smelifaro inet_ntoa(*(struct in_addr *)&tval)); 4403234597Smelifaro } else 4404234597Smelifaro printf("%s %u\n", xent->k.iface, tval); 4405130281Sru } 4406234597Smelifaro 4407234597Smelifaro if (sz < xent->len) 4408234597Smelifaro break; 4409234597Smelifaro sz -= xent->len; 4410234597Smelifaro xent = (void *)xent + xent->len; 4411183228Srik } 4412234597Smelifaro 4413183228Srik free(tbl); 4414130281Sru} 4415