ipfw2.c revision 117544
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: head/sbin/ipfw/ipfw2.c 117544 2003-07-14 08:39:49Z luigi $ 2198943Sluigi */ 2298943Sluigi 2398943Sluigi#include <sys/param.h> 2498943Sluigi#include <sys/mbuf.h> 2598943Sluigi#include <sys/socket.h> 2698943Sluigi#include <sys/sockio.h> 2798943Sluigi#include <sys/sysctl.h> 2898943Sluigi#include <sys/time.h> 2998943Sluigi#include <sys/wait.h> 3098943Sluigi 3198943Sluigi#include <ctype.h> 3298943Sluigi#include <err.h> 3398943Sluigi#include <errno.h> 3498943Sluigi#include <grp.h> 3598943Sluigi#include <limits.h> 3698943Sluigi#include <netdb.h> 3798943Sluigi#include <pwd.h> 3898943Sluigi#include <signal.h> 3998943Sluigi#include <stdio.h> 4098943Sluigi#include <stdlib.h> 4198943Sluigi#include <stdarg.h> 4298943Sluigi#include <string.h> 43117469Sluigi#include <timeconv.h> /* XXX do we need this ? */ 4498943Sluigi#include <unistd.h> 4598943Sluigi#include <sysexits.h> 4698943Sluigi 4798943Sluigi#include <net/if.h> 4898943Sluigi#include <netinet/in.h> 4998943Sluigi#include <netinet/in_systm.h> 5098943Sluigi#include <netinet/ip.h> 5198943Sluigi#include <netinet/ip_icmp.h> 5298943Sluigi#include <netinet/ip_fw.h> 5398943Sluigi#include <net/route.h> /* def. of struct route */ 5498943Sluigi#include <netinet/ip_dummynet.h> 5598943Sluigi#include <netinet/tcp.h> 5698943Sluigi#include <arpa/inet.h> 5798943Sluigi 58117328Sluigiint 5998943Sluigi do_resolv, /* Would try to resolve all */ 6098943Sluigi do_time, /* Show time stamps */ 6198943Sluigi do_quiet, /* Be quiet in add and flush */ 6298943Sluigi do_pipe, /* this cmd refers to a pipe */ 6398943Sluigi do_sort, /* field to sort results (0 = no) */ 6498943Sluigi do_dynamic, /* display dynamic rules */ 6598943Sluigi do_expired, /* display expired dynamic rules */ 66102098Sluigi do_compact, /* show rules in compact mode */ 67101628Sluigi show_sets, /* display rule sets */ 68117328Sluigi test_only, /* only check syntax */ 6998943Sluigi verbose; 7098943Sluigi 7198943Sluigi#define IP_MASK_ALL 0xffffffff 7298943Sluigi 7398943Sluigi/* 74117328Sluigi * _s_x is a structure that stores a string <-> token pairs, used in 75117328Sluigi * various places in the parser. Entries are stored in arrays, 76117328Sluigi * with an entry with s=NULL as terminator. 77117328Sluigi * The search routines are match_token() and match_value(). 78117328Sluigi * Often, an element with x=0 contains an error string. 7998943Sluigi * 8098943Sluigi */ 8198943Sluigistruct _s_x { 82117469Sluigi char const *s; 8398943Sluigi int x; 8498943Sluigi}; 8598943Sluigi 8698943Sluigistatic struct _s_x f_tcpflags[] = { 8798943Sluigi { "syn", TH_SYN }, 8898943Sluigi { "fin", TH_FIN }, 8998943Sluigi { "ack", TH_ACK }, 9098943Sluigi { "psh", TH_PUSH }, 9198943Sluigi { "rst", TH_RST }, 9298943Sluigi { "urg", TH_URG }, 9398943Sluigi { "tcp flag", 0 }, 9498943Sluigi { NULL, 0 } 9598943Sluigi}; 9698943Sluigi 9798943Sluigistatic struct _s_x f_tcpopts[] = { 9898943Sluigi { "mss", IP_FW_TCPOPT_MSS }, 9998943Sluigi { "maxseg", IP_FW_TCPOPT_MSS }, 10098943Sluigi { "window", IP_FW_TCPOPT_WINDOW }, 10198943Sluigi { "sack", IP_FW_TCPOPT_SACK }, 10298943Sluigi { "ts", IP_FW_TCPOPT_TS }, 10398943Sluigi { "timestamp", IP_FW_TCPOPT_TS }, 10498943Sluigi { "cc", IP_FW_TCPOPT_CC }, 10598943Sluigi { "tcp option", 0 }, 10698943Sluigi { NULL, 0 } 10798943Sluigi}; 10898943Sluigi 10998943Sluigi/* 11098943Sluigi * IP options span the range 0 to 255 so we need to remap them 11198943Sluigi * (though in fact only the low 5 bits are significant). 11298943Sluigi */ 11398943Sluigistatic struct _s_x f_ipopts[] = { 11498943Sluigi { "ssrr", IP_FW_IPOPT_SSRR}, 11598943Sluigi { "lsrr", IP_FW_IPOPT_LSRR}, 11698943Sluigi { "rr", IP_FW_IPOPT_RR}, 11798943Sluigi { "ts", IP_FW_IPOPT_TS}, 11898943Sluigi { "ip option", 0 }, 11998943Sluigi { NULL, 0 } 12098943Sluigi}; 12198943Sluigi 12298943Sluigistatic struct _s_x f_iptos[] = { 12398943Sluigi { "lowdelay", IPTOS_LOWDELAY}, 12498943Sluigi { "throughput", IPTOS_THROUGHPUT}, 12598943Sluigi { "reliability", IPTOS_RELIABILITY}, 12698943Sluigi { "mincost", IPTOS_MINCOST}, 12798943Sluigi { "congestion", IPTOS_CE}, 12898943Sluigi { "ecntransport", IPTOS_ECT}, 12998943Sluigi { "ip tos option", 0}, 13098943Sluigi { NULL, 0 } 13198943Sluigi}; 13298943Sluigi 13398943Sluigistatic struct _s_x limit_masks[] = { 13498943Sluigi {"all", DYN_SRC_ADDR|DYN_SRC_PORT|DYN_DST_ADDR|DYN_DST_PORT}, 13598943Sluigi {"src-addr", DYN_SRC_ADDR}, 13698943Sluigi {"src-port", DYN_SRC_PORT}, 13798943Sluigi {"dst-addr", DYN_DST_ADDR}, 13898943Sluigi {"dst-port", DYN_DST_PORT}, 13998943Sluigi {NULL, 0} 14098943Sluigi}; 14198943Sluigi 14298943Sluigi/* 14398943Sluigi * we use IPPROTO_ETHERTYPE as a fake protocol id to call the print routines 14498943Sluigi * This is only used in this code. 14598943Sluigi */ 14698943Sluigi#define IPPROTO_ETHERTYPE 0x1000 14798943Sluigistatic struct _s_x ether_types[] = { 14898943Sluigi /* 14998943Sluigi * Note, we cannot use "-:&/" in the names because they are field 15098943Sluigi * separators in the type specifications. Also, we use s = NULL as 15198943Sluigi * end-delimiter, because a type of 0 can be legal. 15298943Sluigi */ 15398943Sluigi { "ip", 0x0800 }, 15498943Sluigi { "ipv4", 0x0800 }, 15598943Sluigi { "ipv6", 0x86dd }, 15698943Sluigi { "arp", 0x0806 }, 15798943Sluigi { "rarp", 0x8035 }, 15898943Sluigi { "vlan", 0x8100 }, 15998943Sluigi { "loop", 0x9000 }, 16098943Sluigi { "trail", 0x1000 }, 16198943Sluigi { "at", 0x809b }, 16298943Sluigi { "atalk", 0x809b }, 16398943Sluigi { "aarp", 0x80f3 }, 16498943Sluigi { "pppoe_disc", 0x8863 }, 16598943Sluigi { "pppoe_sess", 0x8864 }, 16698943Sluigi { "ipx_8022", 0x00E0 }, 16798943Sluigi { "ipx_8023", 0x0000 }, 16898943Sluigi { "ipx_ii", 0x8137 }, 16998943Sluigi { "ipx_snap", 0x8137 }, 17098943Sluigi { "ipx", 0x8137 }, 17198943Sluigi { "ns", 0x0600 }, 17298943Sluigi { NULL, 0 } 17398943Sluigi}; 17498943Sluigi 17598943Sluigistatic void show_usage(void); 17698943Sluigi 17798943Sluigienum tokens { 17898943Sluigi TOK_NULL=0, 17998943Sluigi 18098943Sluigi TOK_OR, 18198943Sluigi TOK_NOT, 182101641Sluigi TOK_STARTBRACE, 183101641Sluigi TOK_ENDBRACE, 18498943Sluigi 18598943Sluigi TOK_ACCEPT, 18698943Sluigi TOK_COUNT, 18798943Sluigi TOK_PIPE, 18898943Sluigi TOK_QUEUE, 18998943Sluigi TOK_DIVERT, 19098943Sluigi TOK_TEE, 19198943Sluigi TOK_FORWARD, 19298943Sluigi TOK_SKIPTO, 19398943Sluigi TOK_DENY, 19498943Sluigi TOK_REJECT, 19598943Sluigi TOK_RESET, 19698943Sluigi TOK_UNREACH, 19798943Sluigi TOK_CHECKSTATE, 19898943Sluigi 19998943Sluigi TOK_UID, 20098943Sluigi TOK_GID, 20198943Sluigi TOK_IN, 20298943Sluigi TOK_LIMIT, 20398943Sluigi TOK_KEEPSTATE, 20498943Sluigi TOK_LAYER2, 20598943Sluigi TOK_OUT, 20698943Sluigi TOK_XMIT, 20798943Sluigi TOK_RECV, 20898943Sluigi TOK_VIA, 20998943Sluigi TOK_FRAG, 21098943Sluigi TOK_IPOPTS, 21198943Sluigi TOK_IPLEN, 21298943Sluigi TOK_IPID, 21398943Sluigi TOK_IPPRECEDENCE, 21498943Sluigi TOK_IPTOS, 21598943Sluigi TOK_IPTTL, 21698943Sluigi TOK_IPVER, 21798943Sluigi TOK_ESTAB, 21898943Sluigi TOK_SETUP, 21998943Sluigi TOK_TCPFLAGS, 22098943Sluigi TOK_TCPOPTS, 22198943Sluigi TOK_TCPSEQ, 22298943Sluigi TOK_TCPACK, 22398943Sluigi TOK_TCPWIN, 22498943Sluigi TOK_ICMPTYPES, 225102087Sluigi TOK_MAC, 226102087Sluigi TOK_MACTYPE, 227112250Scjc TOK_VERREVPATH, 228117241Sluigi TOK_IPSEC, 229117469Sluigi TOK_COMMENT, 23098943Sluigi 23198943Sluigi TOK_PLR, 232101978Sluigi TOK_NOERROR, 23398943Sluigi TOK_BUCKETS, 23498943Sluigi TOK_DSTIP, 23598943Sluigi TOK_SRCIP, 23698943Sluigi TOK_DSTPORT, 23798943Sluigi TOK_SRCPORT, 23898943Sluigi TOK_ALL, 23998943Sluigi TOK_MASK, 24098943Sluigi TOK_BW, 24198943Sluigi TOK_DELAY, 24298943Sluigi TOK_RED, 24398943Sluigi TOK_GRED, 24498943Sluigi TOK_DROPTAIL, 24598943Sluigi TOK_PROTO, 24698943Sluigi TOK_WEIGHT, 24798943Sluigi}; 24898943Sluigi 24998943Sluigistruct _s_x dummynet_params[] = { 25098943Sluigi { "plr", TOK_PLR }, 251101978Sluigi { "noerror", TOK_NOERROR }, 25298943Sluigi { "buckets", TOK_BUCKETS }, 25398943Sluigi { "dst-ip", TOK_DSTIP }, 25498943Sluigi { "src-ip", TOK_SRCIP }, 25598943Sluigi { "dst-port", TOK_DSTPORT }, 25698943Sluigi { "src-port", TOK_SRCPORT }, 25798943Sluigi { "proto", TOK_PROTO }, 25898943Sluigi { "weight", TOK_WEIGHT }, 25998943Sluigi { "all", TOK_ALL }, 26098943Sluigi { "mask", TOK_MASK }, 26198943Sluigi { "droptail", TOK_DROPTAIL }, 26298943Sluigi { "red", TOK_RED }, 26398943Sluigi { "gred", TOK_GRED }, 26498943Sluigi { "bw", TOK_BW }, 26598943Sluigi { "bandwidth", TOK_BW }, 26698943Sluigi { "delay", TOK_DELAY }, 26799475Sluigi { "pipe", TOK_PIPE }, 26898943Sluigi { "queue", TOK_QUEUE }, 26998943Sluigi { "dummynet-params", TOK_NULL }, 270117328Sluigi { NULL, 0 } /* terminator */ 27198943Sluigi}; 27298943Sluigi 27398943Sluigistruct _s_x rule_actions[] = { 27498943Sluigi { "accept", TOK_ACCEPT }, 27598943Sluigi { "pass", TOK_ACCEPT }, 27698943Sluigi { "allow", TOK_ACCEPT }, 27798943Sluigi { "permit", TOK_ACCEPT }, 27898943Sluigi { "count", TOK_COUNT }, 27998943Sluigi { "pipe", TOK_PIPE }, 28098943Sluigi { "queue", TOK_QUEUE }, 28198943Sluigi { "divert", TOK_DIVERT }, 28298943Sluigi { "tee", TOK_TEE }, 28398943Sluigi { "fwd", TOK_FORWARD }, 28498943Sluigi { "forward", TOK_FORWARD }, 28598943Sluigi { "skipto", TOK_SKIPTO }, 28698943Sluigi { "deny", TOK_DENY }, 28798943Sluigi { "drop", TOK_DENY }, 28898943Sluigi { "reject", TOK_REJECT }, 28998943Sluigi { "reset", TOK_RESET }, 29099475Sluigi { "unreach", TOK_UNREACH }, 29198943Sluigi { "check-state", TOK_CHECKSTATE }, 292117469Sluigi { "//", TOK_COMMENT }, 293117328Sluigi { NULL, 0 } /* terminator */ 29498943Sluigi}; 29598943Sluigi 29698943Sluigistruct _s_x rule_options[] = { 29798943Sluigi { "uid", TOK_UID }, 29898943Sluigi { "gid", TOK_GID }, 29998943Sluigi { "in", TOK_IN }, 30098943Sluigi { "limit", TOK_LIMIT }, 30198943Sluigi { "keep-state", TOK_KEEPSTATE }, 30298943Sluigi { "bridged", TOK_LAYER2 }, 30398943Sluigi { "layer2", TOK_LAYER2 }, 30498943Sluigi { "out", TOK_OUT }, 30598943Sluigi { "xmit", TOK_XMIT }, 30698943Sluigi { "recv", TOK_RECV }, 30798943Sluigi { "via", TOK_VIA }, 30898943Sluigi { "fragment", TOK_FRAG }, 30998943Sluigi { "frag", TOK_FRAG }, 31098943Sluigi { "ipoptions", TOK_IPOPTS }, 31198943Sluigi { "ipopts", TOK_IPOPTS }, 31298943Sluigi { "iplen", TOK_IPLEN }, 31398943Sluigi { "ipid", TOK_IPID }, 31498943Sluigi { "ipprecedence", TOK_IPPRECEDENCE }, 31598943Sluigi { "iptos", TOK_IPTOS }, 31698943Sluigi { "ipttl", TOK_IPTTL }, 31798943Sluigi { "ipversion", TOK_IPVER }, 31898943Sluigi { "ipver", TOK_IPVER }, 31998943Sluigi { "estab", TOK_ESTAB }, 32098943Sluigi { "established", TOK_ESTAB }, 32198943Sluigi { "setup", TOK_SETUP }, 32298943Sluigi { "tcpflags", TOK_TCPFLAGS }, 32398943Sluigi { "tcpflgs", TOK_TCPFLAGS }, 32498943Sluigi { "tcpoptions", TOK_TCPOPTS }, 32598943Sluigi { "tcpopts", TOK_TCPOPTS }, 32698943Sluigi { "tcpseq", TOK_TCPSEQ }, 32798943Sluigi { "tcpack", TOK_TCPACK }, 32898943Sluigi { "tcpwin", TOK_TCPWIN }, 32999909Sluigi { "icmptype", TOK_ICMPTYPES }, 33098943Sluigi { "icmptypes", TOK_ICMPTYPES }, 331102087Sluigi { "dst-ip", TOK_DSTIP }, 332102087Sluigi { "src-ip", TOK_SRCIP }, 333102087Sluigi { "dst-port", TOK_DSTPORT }, 334102087Sluigi { "src-port", TOK_SRCPORT }, 335102087Sluigi { "proto", TOK_PROTO }, 336102087Sluigi { "MAC", TOK_MAC }, 337102087Sluigi { "mac", TOK_MAC }, 338102087Sluigi { "mac-type", TOK_MACTYPE }, 339112250Scjc { "verrevpath", TOK_VERREVPATH }, 340117241Sluigi { "ipsec", TOK_IPSEC }, 341117469Sluigi { "//", TOK_COMMENT }, 34298943Sluigi 34398943Sluigi { "not", TOK_NOT }, /* pseudo option */ 34498943Sluigi { "!", /* escape ? */ TOK_NOT }, /* pseudo option */ 34598943Sluigi { "or", TOK_OR }, /* pseudo option */ 34698943Sluigi { "|", /* escape */ TOK_OR }, /* pseudo option */ 347101641Sluigi { "{", TOK_STARTBRACE }, /* pseudo option */ 348101641Sluigi { "(", TOK_STARTBRACE }, /* pseudo option */ 349101641Sluigi { "}", TOK_ENDBRACE }, /* pseudo option */ 350101641Sluigi { ")", TOK_ENDBRACE }, /* pseudo option */ 351117328Sluigi { NULL, 0 } /* terminator */ 35298943Sluigi}; 35398943Sluigi 354117328Sluigistatic __inline uint64_t 355117328Sluigialign_uint64(uint64_t *pll) { 356117328Sluigi uint64_t ret; 357115793Sticso 358115793Sticso bcopy (pll, &ret, sizeof(ret)); 359115793Sticso return ret; 360115793Sticso}; 361115793Sticso 362117328Sluigi/* 363117328Sluigi * conditionally runs the command. 364117328Sluigi */ 365117469Sluigistatic int 366117328Sluigido_cmd(int optname, void *optval, socklen_t optlen) 367117328Sluigi{ 368117328Sluigi static int s = -1; /* the socket */ 369117328Sluigi int i; 370117328Sluigi 371117328Sluigi if (test_only) 372117328Sluigi return 0; 373117328Sluigi 374117328Sluigi if (s == -1) 375117328Sluigi s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); 376117328Sluigi if (s < 0) 377117328Sluigi err(EX_UNAVAILABLE, "socket"); 378117328Sluigi 379117328Sluigi if (optname == IP_FW_GET || optname == IP_DUMMYNET_GET || 380117328Sluigi optname == IP_FW_ADD) 381117328Sluigi i = getsockopt(s, IPPROTO_IP, optname, optval, 382117328Sluigi (socklen_t *)optlen); 383117328Sluigi else 384117328Sluigi i = setsockopt(s, IPPROTO_IP, optname, optval, optlen); 385117328Sluigi return i; 386117328Sluigi} 387117328Sluigi 38898943Sluigi/** 38998943Sluigi * match_token takes a table and a string, returns the value associated 390117328Sluigi * with the string (-1 in case of failure). 39198943Sluigi */ 39298943Sluigistatic int 39398943Sluigimatch_token(struct _s_x *table, char *string) 39498943Sluigi{ 39598943Sluigi struct _s_x *pt; 396117469Sluigi uint i = strlen(string); 39798943Sluigi 39898943Sluigi for (pt = table ; i && pt->s != NULL ; pt++) 39998943Sluigi if (strlen(pt->s) == i && !bcmp(string, pt->s, i)) 40098943Sluigi return pt->x; 40198943Sluigi return -1; 40298943Sluigi}; 40398943Sluigi 404117328Sluigi/** 405117328Sluigi * match_value takes a table and a value, returns the string associated 406117328Sluigi * with the value (NULL in case of failure). 407117328Sluigi */ 408117469Sluigistatic char const * 409117469Sluigimatch_value(struct _s_x *p, int value) 41098943Sluigi{ 41198943Sluigi for (; p->s != NULL; p++) 41298943Sluigi if (p->x == value) 41398943Sluigi return p->s; 41498943Sluigi return NULL; 41598943Sluigi} 41698943Sluigi 41798943Sluigi/* 41898943Sluigi * prints one port, symbolic or numeric 41998943Sluigi */ 42098943Sluigistatic void 421117328Sluigiprint_port(int proto, uint16_t port) 42298943Sluigi{ 42398943Sluigi 42498943Sluigi if (proto == IPPROTO_ETHERTYPE) { 425117469Sluigi char const *s; 42698943Sluigi 42798943Sluigi if (do_resolv && (s = match_value(ether_types, port)) ) 42898943Sluigi printf("%s", s); 42998943Sluigi else 43098943Sluigi printf("0x%04x", port); 43198943Sluigi } else { 43298943Sluigi struct servent *se = NULL; 43398943Sluigi if (do_resolv) { 43498943Sluigi struct protoent *pe = getprotobynumber(proto); 43598943Sluigi 43698943Sluigi se = getservbyport(htons(port), pe ? pe->p_name : NULL); 43798943Sluigi } 43898943Sluigi if (se) 43998943Sluigi printf("%s", se->s_name); 44098943Sluigi else 44198943Sluigi printf("%d", port); 44298943Sluigi } 44398943Sluigi} 44498943Sluigi 445117328Sluigistruct _s_x _port_name[] = { 446117328Sluigi {"dst-port", O_IP_DSTPORT}, 447117328Sluigi {"src-port", O_IP_SRCPORT}, 448117328Sluigi {"ipid", O_IPID}, 449117328Sluigi {"iplen", O_IPLEN}, 450117328Sluigi {"ipttl", O_IPTTL}, 451117328Sluigi {"mac-type", O_MAC_TYPE}, 452117328Sluigi {NULL, 0} 453117328Sluigi}; 454117328Sluigi 45598943Sluigi/* 456117328Sluigi * Print the values in a list 16-bit items of the types above. 45798943Sluigi * XXX todo: add support for mask. 45898943Sluigi */ 45998943Sluigistatic void 460102087Sluigiprint_newports(ipfw_insn_u16 *cmd, int proto, int opcode) 46198943Sluigi{ 462117328Sluigi uint16_t *p = cmd->ports; 46398943Sluigi int i; 464117469Sluigi char const *sep; 46598943Sluigi 46698943Sluigi if (cmd->o.len & F_NOT) 46798943Sluigi printf(" not"); 468116690Sluigi if (opcode != 0) { 469117328Sluigi sep = match_value(_port_name, opcode); 470117328Sluigi if (sep == NULL) 471116690Sluigi sep = "???"; 472116690Sluigi printf (" %s", sep); 473116690Sluigi } 474116690Sluigi sep = " "; 47598943Sluigi for (i = F_LEN((ipfw_insn *)cmd) - 1; i > 0; i--, p += 2) { 47698943Sluigi printf(sep); 47798943Sluigi print_port(proto, p[0]); 47898943Sluigi if (p[0] != p[1]) { 47998943Sluigi printf("-"); 48098943Sluigi print_port(proto, p[1]); 48198943Sluigi } 48298943Sluigi sep = ","; 48398943Sluigi } 48498943Sluigi} 48598943Sluigi 48698943Sluigi/* 48798943Sluigi * Like strtol, but also translates service names into port numbers 48898943Sluigi * for some protocols. 48998943Sluigi * In particular: 49098943Sluigi * proto == -1 disables the protocol check; 49198943Sluigi * proto == IPPROTO_ETHERTYPE looks up an internal table 49298943Sluigi * proto == <some value in /etc/protocols> matches the values there. 493101628Sluigi * Returns *end == s in case the parameter is not found. 49498943Sluigi */ 49598943Sluigistatic int 49698943Sluigistrtoport(char *s, char **end, int base, int proto) 49798943Sluigi{ 498101628Sluigi char *p, *buf; 499101628Sluigi char *s1; 50098943Sluigi int i; 50198943Sluigi 502101628Sluigi *end = s; /* default - not found */ 50398943Sluigi if ( *s == '\0') 504101628Sluigi return 0; /* not found */ 505106505Smaxim 50698943Sluigi if (isdigit(*s)) 50798943Sluigi return strtol(s, end, base); 50898943Sluigi 50998943Sluigi /* 510101628Sluigi * find separator. '\\' escapes the next char. 51198943Sluigi */ 512101628Sluigi for (s1 = s; *s1 && (isalnum(*s1) || *s1 == '\\') ; s1++) 513101628Sluigi if (*s1 == '\\' && s1[1] != '\0') 514101628Sluigi s1++; 51598943Sluigi 516101628Sluigi buf = malloc(s1 - s + 1); 517101628Sluigi if (buf == NULL) 518101628Sluigi return 0; 519101628Sluigi 520101628Sluigi /* 521101628Sluigi * copy into a buffer skipping backslashes 522101628Sluigi */ 523101628Sluigi for (p = s, i = 0; p != s1 ; p++) 524101628Sluigi if ( *p != '\\') 525101628Sluigi buf[i++] = *p; 526101628Sluigi buf[i++] = '\0'; 527101628Sluigi 52898943Sluigi if (proto == IPPROTO_ETHERTYPE) { 529101628Sluigi i = match_token(ether_types, buf); 530101628Sluigi free(buf); 531101628Sluigi if (i != -1) { /* found */ 53298943Sluigi *end = s1; 53398943Sluigi return i; 53498943Sluigi } 53598943Sluigi } else { 53698943Sluigi struct protoent *pe = NULL; 53798943Sluigi struct servent *se; 53898943Sluigi 53998943Sluigi if (proto != 0) 54098943Sluigi pe = getprotobynumber(proto); 54198943Sluigi setservent(1); 542101628Sluigi se = getservbyname(buf, pe ? pe->p_name : NULL); 543101628Sluigi free(buf); 54498943Sluigi if (se != NULL) { 54598943Sluigi *end = s1; 54698943Sluigi return ntohs(se->s_port); 54798943Sluigi } 54898943Sluigi } 549101628Sluigi return 0; /* not found */ 55098943Sluigi} 55198943Sluigi 55298943Sluigi/* 553117328Sluigi * Fill the body of the command with the list of port ranges. 55498943Sluigi */ 55598943Sluigistatic int 55698943Sluigifill_newports(ipfw_insn_u16 *cmd, char *av, int proto) 55798943Sluigi{ 558117328Sluigi uint16_t a, b, *p = cmd->ports; 55998943Sluigi int i = 0; 560102087Sluigi char *s = av; 56198943Sluigi 562102087Sluigi while (*s) { 56398943Sluigi a = strtoport(av, &s, 0, proto); 56498943Sluigi if (s == av) /* no parameter */ 56598943Sluigi break; 56698943Sluigi if (*s == '-') { /* a range */ 56798943Sluigi av = s+1; 56898943Sluigi b = strtoport(av, &s, 0, proto); 56998943Sluigi if (s == av) /* no parameter */ 57098943Sluigi break; 57198943Sluigi p[0] = a; 57298943Sluigi p[1] = b; 573117328Sluigi } else if (*s == ',' || *s == '\0' ) 57498943Sluigi p[0] = p[1] = a; 575117328Sluigi else /* invalid separator */ 576101978Sluigi errx(EX_DATAERR, "invalid separator <%c> in <%s>\n", 577101978Sluigi *s, av); 578102087Sluigi i++; 579102087Sluigi p += 2; 58098943Sluigi av = s+1; 58198943Sluigi } 58298943Sluigi if (i > 0) { 58398943Sluigi if (i+1 > F_LEN_MASK) 584102087Sluigi errx(EX_DATAERR, "too many ports/ranges\n"); 58598943Sluigi cmd->o.len |= i+1; /* leave F_NOT and F_OR untouched */ 58698943Sluigi } 58798943Sluigi return i; 58898943Sluigi} 58998943Sluigi 59098943Sluigistatic struct _s_x icmpcodes[] = { 59198943Sluigi { "net", ICMP_UNREACH_NET }, 59298943Sluigi { "host", ICMP_UNREACH_HOST }, 59398943Sluigi { "protocol", ICMP_UNREACH_PROTOCOL }, 59498943Sluigi { "port", ICMP_UNREACH_PORT }, 59598943Sluigi { "needfrag", ICMP_UNREACH_NEEDFRAG }, 59698943Sluigi { "srcfail", ICMP_UNREACH_SRCFAIL }, 59798943Sluigi { "net-unknown", ICMP_UNREACH_NET_UNKNOWN }, 59898943Sluigi { "host-unknown", ICMP_UNREACH_HOST_UNKNOWN }, 59998943Sluigi { "isolated", ICMP_UNREACH_ISOLATED }, 60098943Sluigi { "net-prohib", ICMP_UNREACH_NET_PROHIB }, 60198943Sluigi { "host-prohib", ICMP_UNREACH_HOST_PROHIB }, 60298943Sluigi { "tosnet", ICMP_UNREACH_TOSNET }, 60398943Sluigi { "toshost", ICMP_UNREACH_TOSHOST }, 60498943Sluigi { "filter-prohib", ICMP_UNREACH_FILTER_PROHIB }, 60598943Sluigi { "host-precedence", ICMP_UNREACH_HOST_PRECEDENCE }, 60698943Sluigi { "precedence-cutoff", ICMP_UNREACH_PRECEDENCE_CUTOFF }, 60798943Sluigi { NULL, 0 } 60898943Sluigi}; 60998943Sluigi 61098943Sluigistatic void 61198943Sluigifill_reject_code(u_short *codep, char *str) 61298943Sluigi{ 61398943Sluigi int val; 61498943Sluigi char *s; 61598943Sluigi 61698943Sluigi val = strtoul(str, &s, 0); 61798943Sluigi if (s == str || *s != '\0' || val >= 0x100) 61898943Sluigi val = match_token(icmpcodes, str); 619102087Sluigi if (val < 0) 62098943Sluigi errx(EX_DATAERR, "unknown ICMP unreachable code ``%s''", str); 62198943Sluigi *codep = val; 62298943Sluigi return; 62398943Sluigi} 62498943Sluigi 62598943Sluigistatic void 626117328Sluigiprint_reject_code(uint16_t code) 62798943Sluigi{ 628117469Sluigi char const *s = match_value(icmpcodes, code); 62998943Sluigi 63098943Sluigi if (s != NULL) 63199475Sluigi printf("unreach %s", s); 63298943Sluigi else 63399475Sluigi printf("unreach %u", code); 63498943Sluigi} 63598943Sluigi 63698943Sluigi/* 63798943Sluigi * Returns the number of bits set (from left) in a contiguous bitmask, 63898943Sluigi * or -1 if the mask is not contiguous. 63998943Sluigi * XXX this needs a proper fix. 64098943Sluigi * This effectively works on masks in big-endian (network) format. 64198943Sluigi * when compiled on little endian architectures. 64298943Sluigi * 64398943Sluigi * First bit is bit 7 of the first byte -- note, for MAC addresses, 64498943Sluigi * the first bit on the wire is bit 0 of the first byte. 64598943Sluigi * len is the max length in bits. 64698943Sluigi */ 64798943Sluigistatic int 64898943Sluigicontigmask(u_char *p, int len) 64998943Sluigi{ 65098943Sluigi int i, n; 65198943Sluigi for (i=0; i<len ; i++) 65298943Sluigi if ( (p[i/8] & (1 << (7 - (i%8)))) == 0) /* first bit unset */ 65398943Sluigi break; 65498943Sluigi for (n=i+1; n < len; n++) 65598943Sluigi if ( (p[n/8] & (1 << (7 - (n%8)))) != 0) 65698943Sluigi return -1; /* mask not contiguous */ 65798943Sluigi return i; 65898943Sluigi} 65998943Sluigi 66098943Sluigi/* 66198943Sluigi * print flags set/clear in the two bitmasks passed as parameters. 66298943Sluigi * There is a specialized check for f_tcpflags. 66398943Sluigi */ 66498943Sluigistatic void 665117469Sluigiprint_flags(char const *name, ipfw_insn *cmd, struct _s_x *list) 66698943Sluigi{ 667117469Sluigi char const *comma = ""; 66898943Sluigi int i; 66998943Sluigi u_char set = cmd->arg1 & 0xff; 67098943Sluigi u_char clear = (cmd->arg1 >> 8) & 0xff; 67198943Sluigi 67298943Sluigi if (list == f_tcpflags && set == TH_SYN && clear == TH_ACK) { 67398943Sluigi printf(" setup"); 67498943Sluigi return; 67598943Sluigi } 67698943Sluigi 67798943Sluigi printf(" %s ", name); 67898943Sluigi for (i=0; list[i].x != 0; i++) { 67998943Sluigi if (set & list[i].x) { 68098943Sluigi set &= ~list[i].x; 68198943Sluigi printf("%s%s", comma, list[i].s); 68298943Sluigi comma = ","; 68398943Sluigi } 68498943Sluigi if (clear & list[i].x) { 68598943Sluigi clear &= ~list[i].x; 68698943Sluigi printf("%s!%s", comma, list[i].s); 68798943Sluigi comma = ","; 68898943Sluigi } 68998943Sluigi } 69098943Sluigi} 69198943Sluigi 69298943Sluigi/* 69398943Sluigi * Print the ip address contained in a command. 69498943Sluigi */ 69598943Sluigistatic void 696117469Sluigiprint_ip(ipfw_insn_ip *cmd, char const *s) 69798943Sluigi{ 69898943Sluigi struct hostent *he = NULL; 699117328Sluigi int len = F_LEN((ipfw_insn *)cmd); 700117328Sluigi uint32_t *a = ((ipfw_insn_u32 *)cmd)->d; 70198943Sluigi 702102087Sluigi printf("%s%s ", cmd->o.len & F_NOT ? " not": "", s); 70398943Sluigi 70498943Sluigi if (cmd->o.opcode == O_IP_SRC_ME || cmd->o.opcode == O_IP_DST_ME) { 70598943Sluigi printf("me"); 70698943Sluigi return; 70798943Sluigi } 70898943Sluigi if (cmd->o.opcode == O_IP_SRC_SET || cmd->o.opcode == O_IP_DST_SET) { 709117328Sluigi uint32_t x, *map = (uint32_t *)&(cmd->mask); 710116716Sluigi int i, j; 71198943Sluigi char comma = '{'; 71298943Sluigi 71398943Sluigi x = cmd->o.arg1 - 1; 71498943Sluigi x = htonl( ~x ); 71598943Sluigi cmd->addr.s_addr = htonl(cmd->addr.s_addr); 71698943Sluigi printf("%s/%d", inet_ntoa(cmd->addr), 71798943Sluigi contigmask((u_char *)&x, 32)); 71898943Sluigi x = cmd->addr.s_addr = htonl(cmd->addr.s_addr); 71998943Sluigi x &= 0xff; /* base */ 720116716Sluigi /* 721116716Sluigi * Print bits and ranges. 722116716Sluigi * Locate first bit set (i), then locate first bit unset (j). 723116716Sluigi * If we have 3+ consecutive bits set, then print them as a 724116716Sluigi * range, otherwise only print the initial bit and rescan. 725116716Sluigi */ 72698943Sluigi for (i=0; i < cmd->o.arg1; i++) 727117328Sluigi if (map[i/32] & (1<<(i & 31))) { 728116716Sluigi for (j=i+1; j < cmd->o.arg1; j++) 729117328Sluigi if (!(map[ j/32] & (1<<(j & 31)))) 730116716Sluigi break; 73198943Sluigi printf("%c%d", comma, i+x); 732116716Sluigi if (j>i+2) { /* range has at least 3 elements */ 733116716Sluigi printf("-%d", j-1+x); 734116716Sluigi i = j-1; 735116716Sluigi } 73698943Sluigi comma = ','; 73798943Sluigi } 73898943Sluigi printf("}"); 73998943Sluigi return; 74098943Sluigi } 741117328Sluigi /* 742117328Sluigi * len == 2 indicates a single IP, whereas lists of 1 or more 743117328Sluigi * addr/mask pairs have len = (2n+1). We convert len to n so we 744117328Sluigi * use that to count the number of entries. 745117328Sluigi */ 746117328Sluigi for (len = len / 2; len > 0; len--, a += 2) { 747117328Sluigi int mb = /* mask length */ 748117328Sluigi (cmd->o.opcode == O_IP_SRC || cmd->o.opcode == O_IP_DST) ? 749117328Sluigi 32 : contigmask((u_char *)&(a[1]), 32); 75098943Sluigi if (mb == 32 && do_resolv) 751117328Sluigi he = gethostbyaddr((char *)&(a[0]), sizeof(u_long), AF_INET); 75298943Sluigi if (he != NULL) /* resolved to name */ 75398943Sluigi printf("%s", he->h_name); 75498943Sluigi else if (mb == 0) /* any */ 75598943Sluigi printf("any"); 75698943Sluigi else { /* numeric IP followed by some kind of mask */ 757117328Sluigi printf("%s", inet_ntoa( *((struct in_addr *)&a[0]) ) ); 75898943Sluigi if (mb < 0) 759117328Sluigi printf(":%s", inet_ntoa( *((struct in_addr *)&a[1]) ) ); 76098943Sluigi else if (mb < 32) 76198943Sluigi printf("/%d", mb); 76298943Sluigi } 763117328Sluigi if (len > 1) 764117328Sluigi printf(","); 765117328Sluigi } 766117328Sluigi 76798943Sluigi} 76898943Sluigi 76998943Sluigi/* 77098943Sluigi * prints a MAC address/mask pair 77198943Sluigi */ 77298943Sluigistatic void 77398943Sluigiprint_mac(u_char *addr, u_char *mask) 77498943Sluigi{ 77598943Sluigi int l = contigmask(mask, 48); 77698943Sluigi 77798943Sluigi if (l == 0) 77898943Sluigi printf(" any"); 77998943Sluigi else { 78098943Sluigi printf(" %02x:%02x:%02x:%02x:%02x:%02x", 78198943Sluigi addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); 78298943Sluigi if (l == -1) 78398943Sluigi printf("&%02x:%02x:%02x:%02x:%02x:%02x", 78498943Sluigi mask[0], mask[1], mask[2], 78598943Sluigi mask[3], mask[4], mask[5]); 78698943Sluigi else if (l < 48) 78798943Sluigi printf("/%d", l); 78898943Sluigi } 78998943Sluigi} 79098943Sluigi 79199475Sluigistatic void 79299475Sluigifill_icmptypes(ipfw_insn_u32 *cmd, char *av) 79399475Sluigi{ 794117328Sluigi uint8_t type; 79598943Sluigi 79699475Sluigi cmd->d[0] = 0; 79799475Sluigi while (*av) { 79899475Sluigi if (*av == ',') 79999475Sluigi av++; 80099475Sluigi 80199475Sluigi type = strtoul(av, &av, 0); 80299475Sluigi 80399475Sluigi if (*av != ',' && *av != '\0') 80499475Sluigi errx(EX_DATAERR, "invalid ICMP type"); 80599475Sluigi 80699475Sluigi if (type > 31) 80799475Sluigi errx(EX_DATAERR, "ICMP type out of range"); 80899475Sluigi 80999475Sluigi cmd->d[0] |= 1 << type; 81099475Sluigi } 81199475Sluigi cmd->o.opcode = O_ICMPTYPE; 81299475Sluigi cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32); 81399475Sluigi} 81499475Sluigi 81599475Sluigistatic void 81699475Sluigiprint_icmptypes(ipfw_insn_u32 *cmd) 81799475Sluigi{ 81899475Sluigi int i; 81999475Sluigi char sep= ' '; 82099475Sluigi 82199475Sluigi printf(" icmptypes"); 82299475Sluigi for (i = 0; i < 32; i++) { 82399475Sluigi if ( (cmd->d[0] & (1 << (i))) == 0) 82499475Sluigi continue; 82599475Sluigi printf("%c%d", sep, i); 82699475Sluigi sep = ','; 82799475Sluigi } 82899475Sluigi} 82999475Sluigi 83098943Sluigi/* 83198943Sluigi * show_ipfw() prints the body of an ipfw rule. 83298943Sluigi * Because the standard rule has at least proto src_ip dst_ip, we use 83398943Sluigi * a helper function to produce these entries if not provided explicitly. 834102087Sluigi * The first argument is the list of fields we have, the second is 835102087Sluigi * the list of fields we want to be printed. 836101978Sluigi * 837102087Sluigi * Special cases if we have provided a MAC header: 838102087Sluigi * + if the rule does not contain IP addresses/ports, do not print them; 839102087Sluigi * + if the rule does not contain an IP proto, print "all" instead of "ip"; 840102087Sluigi * 841102087Sluigi * Once we have 'have_options', IP header fields are printed as options. 84298943Sluigi */ 843101978Sluigi#define HAVE_PROTO 0x0001 844101978Sluigi#define HAVE_SRCIP 0x0002 845101978Sluigi#define HAVE_DSTIP 0x0004 846101978Sluigi#define HAVE_MAC 0x0008 847101978Sluigi#define HAVE_MACTYPE 0x0010 848102087Sluigi#define HAVE_OPTIONS 0x8000 84998943Sluigi 850101978Sluigi#define HAVE_IP (HAVE_PROTO | HAVE_SRCIP | HAVE_DSTIP) 85198943Sluigistatic void 852102087Sluigishow_prerequisites(int *flags, int want, int cmd) 85398943Sluigi{ 854102087Sluigi if ( (*flags & HAVE_IP) == HAVE_IP) 855102087Sluigi *flags |= HAVE_OPTIONS; 856102087Sluigi 857102087Sluigi if ( (*flags & (HAVE_MAC|HAVE_MACTYPE|HAVE_OPTIONS)) == HAVE_MAC && 858102087Sluigi cmd != O_MAC_TYPE) { 859102087Sluigi /* 860102087Sluigi * mac-type was optimized out by the compiler, 861102087Sluigi * restore it 862102087Sluigi */ 863102087Sluigi printf(" any"); 864102087Sluigi *flags |= HAVE_MACTYPE | HAVE_OPTIONS; 865102087Sluigi return; 866101978Sluigi } 867102087Sluigi if ( !(*flags & HAVE_OPTIONS)) { 868102087Sluigi if ( !(*flags & HAVE_PROTO) && (want & HAVE_PROTO)) 869102087Sluigi printf(" ip"); 870102087Sluigi if ( !(*flags & HAVE_SRCIP) && (want & HAVE_SRCIP)) 871102087Sluigi printf(" from any"); 872102087Sluigi if ( !(*flags & HAVE_DSTIP) && (want & HAVE_DSTIP)) 873102087Sluigi printf(" to any"); 874102087Sluigi } 87598943Sluigi *flags |= want; 87698943Sluigi} 87798943Sluigi 87898943Sluigistatic void 879112189Smaximshow_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth) 88098943Sluigi{ 881107291Skeramida static int twidth = 0; 88298943Sluigi int l; 88398943Sluigi ipfw_insn *cmd; 88498943Sluigi int proto = 0; /* default */ 88598943Sluigi int flags = 0; /* prerequisites */ 88698943Sluigi ipfw_insn_log *logptr = NULL; /* set if we find an O_LOG */ 88798943Sluigi int or_block = 0; /* we are in an or block */ 888117328Sluigi uint32_t set_disable; 88998943Sluigi 890115793Sticso bcopy(&rule->next_rule, &set_disable, sizeof(set_disable)); 891101628Sluigi 892101628Sluigi if (set_disable & (1 << rule->set)) { /* disabled */ 893101628Sluigi if (!show_sets) 894101628Sluigi return; 895101628Sluigi else 896101628Sluigi printf("# DISABLED "); 897101628Sluigi } 89898943Sluigi printf("%05u ", rule->rulenum); 89998943Sluigi 900117469Sluigi if (pcwidth>0 || bcwidth>0) 901115793Sticso printf("%*llu %*llu ", pcwidth, align_uint64(&rule->pcnt), 902115793Sticso bcwidth, align_uint64(&rule->bcnt)); 90398943Sluigi 904117472Sluigi if (do_time == 2) 905117472Sluigi printf("%10u ", rule->timestamp); 906117472Sluigi else if (do_time == 1) { 907107291Skeramida char timestr[30]; 908107291Skeramida time_t t = (time_t)0; 909107291Skeramida 910107291Skeramida if (twidth == 0) { 911107291Skeramida strcpy(timestr, ctime(&t)); 912107291Skeramida *strchr(timestr, '\n') = '\0'; 913107291Skeramida twidth = strlen(timestr); 914107291Skeramida } 91598943Sluigi if (rule->timestamp) { 916117469Sluigi#if _FreeBSD_version < 500000 /* XXX check */ 917117469Sluigi#define _long_to_time(x) (time_t)(x) 918117469Sluigi#endif 919107291Skeramida t = _long_to_time(rule->timestamp); 92098943Sluigi 92198943Sluigi strcpy(timestr, ctime(&t)); 92298943Sluigi *strchr(timestr, '\n') = '\0'; 92398943Sluigi printf("%s ", timestr); 92498943Sluigi } else { 925107291Skeramida printf("%*s", twidth, " "); 92698943Sluigi } 92798943Sluigi } 92898943Sluigi 929101628Sluigi if (show_sets) 930101628Sluigi printf("set %d ", rule->set); 931101628Sluigi 93298943Sluigi /* 933107289Sluigi * print the optional "match probability" 934107289Sluigi */ 935107289Sluigi if (rule->cmd_len > 0) { 936107289Sluigi cmd = rule->cmd ; 937107289Sluigi if (cmd->opcode == O_PROB) { 938107289Sluigi ipfw_insn_u32 *p = (ipfw_insn_u32 *)cmd; 939107289Sluigi double d = 1.0 * p->d[0]; 940107289Sluigi 941107289Sluigi d = (d / 0x7fffffff); 942107289Sluigi printf("prob %f ", d); 943107289Sluigi } 944107289Sluigi } 945107289Sluigi 946107289Sluigi /* 94798943Sluigi * first print actions 94898943Sluigi */ 94998943Sluigi for (l = rule->cmd_len - rule->act_ofs, cmd = ACTION_PTR(rule); 95098943Sluigi l > 0 ; l -= F_LEN(cmd), cmd += F_LEN(cmd)) { 95198943Sluigi switch(cmd->opcode) { 95298943Sluigi case O_CHECK_STATE: 95398943Sluigi printf("check-state"); 954102087Sluigi flags = HAVE_IP; /* avoid printing anything else */ 95598943Sluigi break; 95698943Sluigi 95798943Sluigi case O_ACCEPT: 95898943Sluigi printf("allow"); 95998943Sluigi break; 96098943Sluigi 96198943Sluigi case O_COUNT: 96298943Sluigi printf("count"); 96398943Sluigi break; 96498943Sluigi 96598943Sluigi case O_DENY: 96698943Sluigi printf("deny"); 96798943Sluigi break; 96898943Sluigi 96999475Sluigi case O_REJECT: 97099475Sluigi if (cmd->arg1 == ICMP_REJECT_RST) 97199475Sluigi printf("reset"); 97299475Sluigi else if (cmd->arg1 == ICMP_UNREACH_HOST) 97399475Sluigi printf("reject"); 97499475Sluigi else 97599475Sluigi print_reject_code(cmd->arg1); 97699475Sluigi break; 97799475Sluigi 97898943Sluigi case O_SKIPTO: 97998943Sluigi printf("skipto %u", cmd->arg1); 98098943Sluigi break; 98198943Sluigi 98298943Sluigi case O_PIPE: 98398943Sluigi printf("pipe %u", cmd->arg1); 98498943Sluigi break; 98598943Sluigi 98698943Sluigi case O_QUEUE: 98798943Sluigi printf("queue %u", cmd->arg1); 98898943Sluigi break; 98998943Sluigi 99098943Sluigi case O_DIVERT: 99198943Sluigi printf("divert %u", cmd->arg1); 99298943Sluigi break; 99398943Sluigi 99498943Sluigi case O_TEE: 99598943Sluigi printf("tee %u", cmd->arg1); 99698943Sluigi break; 99798943Sluigi 99898943Sluigi case O_FORWARD_IP: 99998943Sluigi { 100098943Sluigi ipfw_insn_sa *s = (ipfw_insn_sa *)cmd; 100198943Sluigi 100298943Sluigi printf("fwd %s", inet_ntoa(s->sa.sin_addr)); 100398943Sluigi if (s->sa.sin_port) 1004103241Sluigi printf(",%d", s->sa.sin_port); 100598943Sluigi } 100698943Sluigi break; 100798943Sluigi 100898943Sluigi case O_LOG: /* O_LOG is printed last */ 100998943Sluigi logptr = (ipfw_insn_log *)cmd; 101098943Sluigi break; 101198943Sluigi 101298943Sluigi default: 101398943Sluigi printf("** unrecognized action %d len %d", 101498943Sluigi cmd->opcode, cmd->len); 101598943Sluigi } 101698943Sluigi } 101798943Sluigi if (logptr) { 101898943Sluigi if (logptr->max_log > 0) 101999909Sluigi printf(" log logamount %d", logptr->max_log); 102098943Sluigi else 102199909Sluigi printf(" log"); 102298943Sluigi } 1023102087Sluigi 102498943Sluigi /* 1025102087Sluigi * then print the body. 102698943Sluigi */ 1027102087Sluigi if (rule->_pad & 1) { /* empty rules before options */ 1028102098Sluigi if (!do_compact) 1029102098Sluigi printf(" ip from any to any"); 1030102087Sluigi flags |= HAVE_IP | HAVE_OPTIONS; 1031102087Sluigi } 1032102087Sluigi 103398943Sluigi for (l = rule->act_ofs, cmd = rule->cmd ; 103498943Sluigi l > 0 ; l -= F_LEN(cmd) , cmd += F_LEN(cmd)) { 103599475Sluigi /* useful alias */ 103699475Sluigi ipfw_insn_u32 *cmd32 = (ipfw_insn_u32 *)cmd; 103798943Sluigi 1038102087Sluigi show_prerequisites(&flags, 0, cmd->opcode); 1039102087Sluigi 104098943Sluigi switch(cmd->opcode) { 1041107289Sluigi case O_PROB: 1042107289Sluigi break; /* done already */ 1043107289Sluigi 104498943Sluigi case O_PROBE_STATE: 104598943Sluigi break; /* no need to print anything here */ 104698943Sluigi 104798943Sluigi case O_MACADDR2: { 104898943Sluigi ipfw_insn_mac *m = (ipfw_insn_mac *)cmd; 1049102087Sluigi 1050102087Sluigi if ((cmd->len & F_OR) && !or_block) 1051102087Sluigi printf(" {"); 105298943Sluigi if (cmd->len & F_NOT) 105398943Sluigi printf(" not"); 1054102087Sluigi printf(" MAC"); 1055102087Sluigi flags |= HAVE_MAC; 105698943Sluigi print_mac( m->addr, m->mask); 105798943Sluigi print_mac( m->addr + 6, m->mask + 6); 105898943Sluigi } 105998943Sluigi break; 106098943Sluigi 106198943Sluigi case O_MAC_TYPE: 1062102087Sluigi if ((cmd->len & F_OR) && !or_block) 1063102087Sluigi printf(" {"); 1064102087Sluigi print_newports((ipfw_insn_u16 *)cmd, IPPROTO_ETHERTYPE, 1065102087Sluigi (flags & HAVE_OPTIONS) ? cmd->opcode : 0); 1066102087Sluigi flags |= HAVE_MAC | HAVE_MACTYPE | HAVE_OPTIONS; 106798943Sluigi break; 106898943Sluigi 106998943Sluigi case O_IP_SRC: 107098943Sluigi case O_IP_SRC_MASK: 107198943Sluigi case O_IP_SRC_ME: 107298943Sluigi case O_IP_SRC_SET: 1073102087Sluigi show_prerequisites(&flags, HAVE_PROTO, 0); 107498943Sluigi if (!(flags & HAVE_SRCIP)) 107598943Sluigi printf(" from"); 107698943Sluigi if ((cmd->len & F_OR) && !or_block) 107798943Sluigi printf(" {"); 1078102087Sluigi print_ip((ipfw_insn_ip *)cmd, 1079102087Sluigi (flags & HAVE_OPTIONS) ? " src-ip" : ""); 108098943Sluigi flags |= HAVE_SRCIP; 108198943Sluigi break; 108298943Sluigi 108398943Sluigi case O_IP_DST: 108498943Sluigi case O_IP_DST_MASK: 108598943Sluigi case O_IP_DST_ME: 108698943Sluigi case O_IP_DST_SET: 1087102087Sluigi show_prerequisites(&flags, HAVE_PROTO|HAVE_SRCIP, 0); 108898943Sluigi if (!(flags & HAVE_DSTIP)) 108998943Sluigi printf(" to"); 109098943Sluigi if ((cmd->len & F_OR) && !or_block) 109198943Sluigi printf(" {"); 1092102087Sluigi print_ip((ipfw_insn_ip *)cmd, 1093102087Sluigi (flags & HAVE_OPTIONS) ? " dst-ip" : ""); 109498943Sluigi flags |= HAVE_DSTIP; 109598943Sluigi break; 109698943Sluigi 109798943Sluigi case O_IP_DSTPORT: 1098102087Sluigi show_prerequisites(&flags, HAVE_IP, 0); 109998943Sluigi case O_IP_SRCPORT: 1100102087Sluigi show_prerequisites(&flags, HAVE_PROTO|HAVE_SRCIP, 0); 1101101641Sluigi if ((cmd->len & F_OR) && !or_block) 1102101641Sluigi printf(" {"); 1103102087Sluigi print_newports((ipfw_insn_u16 *)cmd, proto, 1104102087Sluigi (flags & HAVE_OPTIONS) ? cmd->opcode : 0); 110598943Sluigi break; 110698943Sluigi 110798943Sluigi case O_PROTO: { 110898943Sluigi struct protoent *pe; 110998943Sluigi 111098943Sluigi if ((cmd->len & F_OR) && !or_block) 111198943Sluigi printf(" {"); 111298943Sluigi if (cmd->len & F_NOT) 111398943Sluigi printf(" not"); 111498943Sluigi proto = cmd->arg1; 111598943Sluigi pe = getprotobynumber(cmd->arg1); 1116102087Sluigi if (flags & HAVE_OPTIONS) 1117102087Sluigi printf(" proto"); 111898943Sluigi if (pe) 111998943Sluigi printf(" %s", pe->p_name); 112098943Sluigi else 112198943Sluigi printf(" %u", cmd->arg1); 112298943Sluigi } 112398943Sluigi flags |= HAVE_PROTO; 112498943Sluigi break; 1125106505Smaxim 112698943Sluigi default: /*options ... */ 1127102087Sluigi show_prerequisites(&flags, HAVE_IP | HAVE_OPTIONS, 0); 112898943Sluigi if ((cmd->len & F_OR) && !or_block) 112998943Sluigi printf(" {"); 113098943Sluigi if (cmd->len & F_NOT && cmd->opcode != O_IN) 113198943Sluigi printf(" not"); 113298943Sluigi switch(cmd->opcode) { 113398943Sluigi case O_FRAG: 113498943Sluigi printf(" frag"); 113598943Sluigi break; 113698943Sluigi 113798943Sluigi case O_IN: 113898943Sluigi printf(cmd->len & F_NOT ? " out" : " in"); 113998943Sluigi break; 114098943Sluigi 114198943Sluigi case O_LAYER2: 114298943Sluigi printf(" layer2"); 114398943Sluigi break; 114498943Sluigi case O_XMIT: 114598943Sluigi case O_RECV: 114698943Sluigi case O_VIA: { 1147117469Sluigi char const *s; 114898943Sluigi ipfw_insn_if *cmdif = (ipfw_insn_if *)cmd; 114998943Sluigi 115098943Sluigi if (cmd->opcode == O_XMIT) 115198943Sluigi s = "xmit"; 115298943Sluigi else if (cmd->opcode == O_RECV) 115398943Sluigi s = "recv"; 1154117469Sluigi else /* if (cmd->opcode == O_VIA) */ 115598943Sluigi s = "via"; 115698943Sluigi if (cmdif->name[0] == '\0') 115799475Sluigi printf(" %s %s", s, 115899475Sluigi inet_ntoa(cmdif->p.ip)); 115998943Sluigi else if (cmdif->p.unit == -1) 116098943Sluigi printf(" %s %s*", s, cmdif->name); 116198943Sluigi else 116299475Sluigi printf(" %s %s%d", s, cmdif->name, 116399475Sluigi cmdif->p.unit); 116498943Sluigi } 116598943Sluigi break; 116698943Sluigi 116798943Sluigi case O_IPID: 1168116690Sluigi if (F_LEN(cmd) == 1) 1169116690Sluigi printf(" ipid %u", cmd->arg1 ); 1170116690Sluigi else 1171116690Sluigi print_newports((ipfw_insn_u16 *)cmd, 0, 1172116690Sluigi O_IPID); 117398943Sluigi break; 117498943Sluigi 117598943Sluigi case O_IPTTL: 1176116690Sluigi if (F_LEN(cmd) == 1) 1177116690Sluigi printf(" ipttl %u", cmd->arg1 ); 1178116690Sluigi else 1179116690Sluigi print_newports((ipfw_insn_u16 *)cmd, 0, 1180116690Sluigi O_IPTTL); 118198943Sluigi break; 118298943Sluigi 118398943Sluigi case O_IPVER: 118498943Sluigi printf(" ipver %u", cmd->arg1 ); 118598943Sluigi break; 118698943Sluigi 118799475Sluigi case O_IPPRECEDENCE: 118899475Sluigi printf(" ipprecedence %u", (cmd->arg1) >> 5 ); 118999475Sluigi break; 119099475Sluigi 119198943Sluigi case O_IPLEN: 1192116690Sluigi if (F_LEN(cmd) == 1) 1193116690Sluigi printf(" iplen %u", cmd->arg1 ); 1194116690Sluigi else 1195116690Sluigi print_newports((ipfw_insn_u16 *)cmd, 0, 1196116690Sluigi O_IPLEN); 119798943Sluigi break; 119898943Sluigi 1199101116Sluigi case O_IPOPT: 120098943Sluigi print_flags("ipoptions", cmd, f_ipopts); 120198943Sluigi break; 120298943Sluigi 120399475Sluigi case O_IPTOS: 120499475Sluigi print_flags("iptos", cmd, f_iptos); 120599475Sluigi break; 120699475Sluigi 120799475Sluigi case O_ICMPTYPE: 120899475Sluigi print_icmptypes((ipfw_insn_u32 *)cmd); 120999475Sluigi break; 121099475Sluigi 121198943Sluigi case O_ESTAB: 121298943Sluigi printf(" established"); 121398943Sluigi break; 121498943Sluigi 121598943Sluigi case O_TCPFLAGS: 121698943Sluigi print_flags("tcpflags", cmd, f_tcpflags); 121798943Sluigi break; 121898943Sluigi 121998943Sluigi case O_TCPOPTS: 122098943Sluigi print_flags("tcpoptions", cmd, f_tcpopts); 122198943Sluigi break; 122298943Sluigi 122398943Sluigi case O_TCPWIN: 122498943Sluigi printf(" tcpwin %d", ntohs(cmd->arg1)); 122598943Sluigi break; 122698943Sluigi 122798943Sluigi case O_TCPACK: 122898943Sluigi printf(" tcpack %d", ntohl(cmd32->d[0])); 122998943Sluigi break; 123098943Sluigi 123198943Sluigi case O_TCPSEQ: 123298943Sluigi printf(" tcpseq %d", ntohl(cmd32->d[0])); 123398943Sluigi break; 123498943Sluigi 123598943Sluigi case O_UID: 123698943Sluigi { 123798943Sluigi struct passwd *pwd = getpwuid(cmd32->d[0]); 123898943Sluigi 123998943Sluigi if (pwd) 124098943Sluigi printf(" uid %s", pwd->pw_name); 124198943Sluigi else 124298943Sluigi printf(" uid %u", cmd32->d[0]); 124398943Sluigi } 124498943Sluigi break; 124598943Sluigi 124698943Sluigi case O_GID: 124798943Sluigi { 124898943Sluigi struct group *grp = getgrgid(cmd32->d[0]); 124998943Sluigi 125098943Sluigi if (grp) 125198943Sluigi printf(" gid %s", grp->gr_name); 125298943Sluigi else 125398943Sluigi printf(" gid %u", cmd32->d[0]); 125498943Sluigi } 125598943Sluigi break; 125698943Sluigi 1257112250Scjc case O_VERREVPATH: 1258112250Scjc printf(" verrevpath"); 1259112250Scjc break; 1260116919Sluigi 1261117241Sluigi case O_IPSEC: 1262117241Sluigi printf(" ipsec"); 1263117241Sluigi break; 1264117241Sluigi 1265117469Sluigi case O_NOP: 1266117469Sluigi printf(" // %s", (char *)(cmd + 1)); 1267117469Sluigi break; 1268117469Sluigi 126998943Sluigi case O_KEEP_STATE: 127098943Sluigi printf(" keep-state"); 127198943Sluigi break; 127298943Sluigi 127398943Sluigi case O_LIMIT: 127498943Sluigi { 127598943Sluigi struct _s_x *p = limit_masks; 127698943Sluigi ipfw_insn_limit *c = (ipfw_insn_limit *)cmd; 1277117328Sluigi uint8_t x = c->limit_mask; 1278117469Sluigi char const *comma = " "; 127998943Sluigi 128098943Sluigi printf(" limit"); 1281106505Smaxim for ( ; p->x != 0 ; p++) 128299909Sluigi if ((x & p->x) == p->x) { 128398943Sluigi x &= ~p->x; 128498943Sluigi printf("%s%s", comma, p->s); 128598943Sluigi comma = ","; 128698943Sluigi } 128798943Sluigi printf(" %d", c->conn_limit); 128898943Sluigi } 128998943Sluigi break; 129098943Sluigi 129198943Sluigi default: 129298943Sluigi printf(" [opcode %d len %d]", 129398943Sluigi cmd->opcode, cmd->len); 129498943Sluigi } 129598943Sluigi } 129698943Sluigi if (cmd->len & F_OR) { 129798943Sluigi printf(" or"); 129898943Sluigi or_block = 1; 129998943Sluigi } else if (or_block) { 130098943Sluigi printf(" }"); 130198943Sluigi or_block = 0; 130298943Sluigi } 130398943Sluigi } 1304102087Sluigi show_prerequisites(&flags, HAVE_IP, 0); 130598943Sluigi 130698943Sluigi printf("\n"); 130798943Sluigi} 130898943Sluigi 130998943Sluigistatic void 1310112189Smaximshow_dyn_ipfw(ipfw_dyn_rule *d, int pcwidth, int bcwidth) 131198943Sluigi{ 131298943Sluigi struct protoent *pe; 131398943Sluigi struct in_addr a; 1314115793Sticso uint16_t rulenum; 131598943Sluigi 131698943Sluigi if (!do_expired) { 131798943Sluigi if (!d->expire && !(d->dyn_type == O_LIMIT_PARENT)) 131898943Sluigi return; 131998943Sluigi } 1320115793Sticso bcopy(&d->rule, &rulenum, sizeof(rulenum)); 1321117328Sluigi printf("%05d", rulenum); 1322117469Sluigi if (pcwidth>0 || bcwidth>0) 1323117328Sluigi printf(" %*llu %*llu (%ds)", pcwidth, 1324117328Sluigi align_uint64(&d->pcnt), bcwidth, 1325117328Sluigi align_uint64(&d->bcnt), d->expire); 132698943Sluigi switch (d->dyn_type) { 132798943Sluigi case O_LIMIT_PARENT: 132898943Sluigi printf(" PARENT %d", d->count); 132998943Sluigi break; 133098943Sluigi case O_LIMIT: 133198943Sluigi printf(" LIMIT"); 133298943Sluigi break; 133398943Sluigi case O_KEEP_STATE: /* bidir, no mask */ 1334106505Smaxim printf(" STATE"); 133598943Sluigi break; 133698943Sluigi } 133798943Sluigi 133898943Sluigi if ((pe = getprotobynumber(d->id.proto)) != NULL) 133998943Sluigi printf(" %s", pe->p_name); 134098943Sluigi else 134198943Sluigi printf(" proto %u", d->id.proto); 134298943Sluigi 134398943Sluigi a.s_addr = htonl(d->id.src_ip); 134498943Sluigi printf(" %s %d", inet_ntoa(a), d->id.src_port); 134598943Sluigi 134698943Sluigi a.s_addr = htonl(d->id.dst_ip); 134798943Sluigi printf(" <-> %s %d", inet_ntoa(a), d->id.dst_port); 134898943Sluigi printf("\n"); 134998943Sluigi} 135098943Sluigi 1351117469Sluigistatic int 135298943Sluigisort_q(const void *pa, const void *pb) 135398943Sluigi{ 135498943Sluigi int rev = (do_sort < 0); 135598943Sluigi int field = rev ? -do_sort : do_sort; 135698943Sluigi long long res = 0; 135798943Sluigi const struct dn_flow_queue *a = pa; 135898943Sluigi const struct dn_flow_queue *b = pb; 135998943Sluigi 136098943Sluigi switch (field) { 136198943Sluigi case 1: /* pkts */ 136298943Sluigi res = a->len - b->len; 136398943Sluigi break; 136498943Sluigi case 2: /* bytes */ 136598943Sluigi res = a->len_bytes - b->len_bytes; 136698943Sluigi break; 136798943Sluigi 136898943Sluigi case 3: /* tot pkts */ 136998943Sluigi res = a->tot_pkts - b->tot_pkts; 137098943Sluigi break; 137198943Sluigi 137298943Sluigi case 4: /* tot bytes */ 137398943Sluigi res = a->tot_bytes - b->tot_bytes; 137498943Sluigi break; 137598943Sluigi } 137698943Sluigi if (res < 0) 137798943Sluigi res = -1; 137898943Sluigi if (res > 0) 137998943Sluigi res = 1; 138098943Sluigi return (int)(rev ? res : -res); 138198943Sluigi} 138298943Sluigi 138398943Sluigistatic void 138498943Sluigilist_queues(struct dn_flow_set *fs, struct dn_flow_queue *q) 138598943Sluigi{ 138698943Sluigi int l; 138798943Sluigi 138898943Sluigi printf(" mask: 0x%02x 0x%08x/0x%04x -> 0x%08x/0x%04x\n", 138998943Sluigi fs->flow_mask.proto, 139098943Sluigi fs->flow_mask.src_ip, fs->flow_mask.src_port, 139198943Sluigi fs->flow_mask.dst_ip, fs->flow_mask.dst_port); 139298943Sluigi if (fs->rq_elements == 0) 139398943Sluigi return; 139498943Sluigi 139598943Sluigi printf("BKT Prot ___Source IP/port____ " 139698943Sluigi "____Dest. IP/port____ Tot_pkt/bytes Pkt/Byte Drp\n"); 139798943Sluigi if (do_sort != 0) 139898943Sluigi heapsort(q, fs->rq_elements, sizeof *q, sort_q); 139998943Sluigi for (l = 0; l < fs->rq_elements; l++) { 140098943Sluigi struct in_addr ina; 140198943Sluigi struct protoent *pe; 140298943Sluigi 140398943Sluigi ina.s_addr = htonl(q[l].id.src_ip); 140498943Sluigi printf("%3d ", q[l].hash_slot); 140598943Sluigi pe = getprotobynumber(q[l].id.proto); 140698943Sluigi if (pe) 140798943Sluigi printf("%-4s ", pe->p_name); 140898943Sluigi else 140998943Sluigi printf("%4u ", q[l].id.proto); 141098943Sluigi printf("%15s/%-5d ", 141198943Sluigi inet_ntoa(ina), q[l].id.src_port); 141298943Sluigi ina.s_addr = htonl(q[l].id.dst_ip); 141398943Sluigi printf("%15s/%-5d ", 141498943Sluigi inet_ntoa(ina), q[l].id.dst_port); 141598943Sluigi printf("%4qu %8qu %2u %4u %3u\n", 141698943Sluigi q[l].tot_pkts, q[l].tot_bytes, 141798943Sluigi q[l].len, q[l].len_bytes, q[l].drops); 141898943Sluigi if (verbose) 141998943Sluigi printf(" S %20qd F %20qd\n", 142098943Sluigi q[l].S, q[l].F); 142198943Sluigi } 142298943Sluigi} 142398943Sluigi 142498943Sluigistatic void 142598943Sluigiprint_flowset_parms(struct dn_flow_set *fs, char *prefix) 142698943Sluigi{ 142798943Sluigi int l; 142898943Sluigi char qs[30]; 142998943Sluigi char plr[30]; 143098943Sluigi char red[90]; /* Display RED parameters */ 143198943Sluigi 143298943Sluigi l = fs->qsize; 143398943Sluigi if (fs->flags_fs & DN_QSIZE_IS_BYTES) { 143498943Sluigi if (l >= 8192) 143598943Sluigi sprintf(qs, "%d KB", l / 1024); 143698943Sluigi else 143798943Sluigi sprintf(qs, "%d B", l); 143898943Sluigi } else 143998943Sluigi sprintf(qs, "%3d sl.", l); 144098943Sluigi if (fs->plr) 144198943Sluigi sprintf(plr, "plr %f", 1.0 * fs->plr / (double)(0x7fffffff)); 144298943Sluigi else 144398943Sluigi plr[0] = '\0'; 144498943Sluigi if (fs->flags_fs & DN_IS_RED) /* RED parameters */ 144598943Sluigi sprintf(red, 144698943Sluigi "\n\t %cRED w_q %f min_th %d max_th %d max_p %f", 144798943Sluigi (fs->flags_fs & DN_IS_GENTLE_RED) ? 'G' : ' ', 144898943Sluigi 1.0 * fs->w_q / (double)(1 << SCALE_RED), 144998943Sluigi SCALE_VAL(fs->min_th), 145098943Sluigi SCALE_VAL(fs->max_th), 145198943Sluigi 1.0 * fs->max_p / (double)(1 << SCALE_RED)); 145298943Sluigi else 145398943Sluigi sprintf(red, "droptail"); 145498943Sluigi 145598943Sluigi printf("%s %s%s %d queues (%d buckets) %s\n", 145698943Sluigi prefix, qs, plr, fs->rq_elements, fs->rq_size, red); 145798943Sluigi} 145898943Sluigi 145998943Sluigistatic void 1460117469Sluigilist_pipes(void *data, uint nbytes, int ac, char *av[]) 146198943Sluigi{ 1462117469Sluigi int rulenum; 146398943Sluigi void *next = data; 146498943Sluigi struct dn_pipe *p = (struct dn_pipe *) data; 146598943Sluigi struct dn_flow_set *fs; 146698943Sluigi struct dn_flow_queue *q; 146798943Sluigi int l; 146898943Sluigi 146998943Sluigi if (ac > 0) 147098943Sluigi rulenum = strtoul(*av++, NULL, 10); 147198943Sluigi else 147298943Sluigi rulenum = 0; 147398943Sluigi for (; nbytes >= sizeof *p; p = (struct dn_pipe *)next) { 147498943Sluigi double b = p->bandwidth; 147598943Sluigi char buf[30]; 147698943Sluigi char prefix[80]; 147798943Sluigi 147898943Sluigi if (p->next != (struct dn_pipe *)DN_IS_PIPE) 147998943Sluigi break; /* done with pipes, now queues */ 148098943Sluigi 148198943Sluigi /* 148298943Sluigi * compute length, as pipe have variable size 148398943Sluigi */ 148498943Sluigi l = sizeof(*p) + p->fs.rq_elements * sizeof(*q); 1485117469Sluigi next = (char *)p + l; 148698943Sluigi nbytes -= l; 148798943Sluigi 148898943Sluigi if (rulenum != 0 && rulenum != p->pipe_nr) 148998943Sluigi continue; 149098943Sluigi 149198943Sluigi /* 149298943Sluigi * Print rate (or clocking interface) 149398943Sluigi */ 149498943Sluigi if (p->if_name[0] != '\0') 149598943Sluigi sprintf(buf, "%s", p->if_name); 149698943Sluigi else if (b == 0) 149798943Sluigi sprintf(buf, "unlimited"); 149898943Sluigi else if (b >= 1000000) 149998943Sluigi sprintf(buf, "%7.3f Mbit/s", b/1000000); 150098943Sluigi else if (b >= 1000) 150198943Sluigi sprintf(buf, "%7.3f Kbit/s", b/1000); 150298943Sluigi else 150398943Sluigi sprintf(buf, "%7.3f bit/s ", b); 150498943Sluigi 150598943Sluigi sprintf(prefix, "%05d: %s %4d ms ", 150698943Sluigi p->pipe_nr, buf, p->delay); 150798943Sluigi print_flowset_parms(&(p->fs), prefix); 150898943Sluigi if (verbose) 150998943Sluigi printf(" V %20qd\n", p->V >> MY_M); 1510106505Smaxim 151198943Sluigi q = (struct dn_flow_queue *)(p+1); 151298943Sluigi list_queues(&(p->fs), q); 151398943Sluigi } 151498943Sluigi for (fs = next; nbytes >= sizeof *fs; fs = next) { 151598943Sluigi char prefix[80]; 151698943Sluigi 151798943Sluigi if (fs->next != (struct dn_flow_set *)DN_IS_QUEUE) 151898943Sluigi break; 151998943Sluigi l = sizeof(*fs) + fs->rq_elements * sizeof(*q); 1520117469Sluigi next = (char *)fs + l; 152198943Sluigi nbytes -= l; 152298943Sluigi q = (struct dn_flow_queue *)(fs+1); 152398943Sluigi sprintf(prefix, "q%05d: weight %d pipe %d ", 152498943Sluigi fs->fs_nr, fs->weight, fs->parent_nr); 152598943Sluigi print_flowset_parms(fs, prefix); 152698943Sluigi list_queues(fs, q); 152798943Sluigi } 152898943Sluigi} 152998943Sluigi 1530101978Sluigi/* 1531101978Sluigi * This one handles all set-related commands 1532101978Sluigi * ipfw set { show | enable | disable } 1533101978Sluigi * ipfw set swap X Y 1534101978Sluigi * ipfw set move X to Y 1535101978Sluigi * ipfw set move rule X to Y 1536101978Sluigi */ 153798943Sluigistatic void 1538101978Sluigisets_handler(int ac, char *av[]) 1539101978Sluigi{ 1540117328Sluigi uint32_t set_disable, masks[2]; 1541101978Sluigi int i, nbytes; 1542117328Sluigi uint16_t rulenum; 1543117328Sluigi uint8_t cmd, new_set; 1544101978Sluigi 1545101978Sluigi ac--; 1546101978Sluigi av++; 1547101978Sluigi 1548101978Sluigi if (!ac) 1549101978Sluigi errx(EX_USAGE, "set needs command"); 1550101978Sluigi if (!strncmp(*av, "show", strlen(*av)) ) { 1551101978Sluigi void *data; 1552117469Sluigi char const *msg; 1553101978Sluigi 1554101978Sluigi nbytes = sizeof(struct ip_fw); 1555117328Sluigi if ((data = calloc(1, nbytes)) == NULL) 1556117328Sluigi err(EX_OSERR, "calloc"); 1557117328Sluigi if (do_cmd(IP_FW_GET, data, (socklen_t)&nbytes) < 0) 1558101978Sluigi err(EX_OSERR, "getsockopt(IP_FW_GET)"); 1559115793Sticso bcopy(&((struct ip_fw *)data)->next_rule, 1560115793Sticso &set_disable, sizeof(set_disable)); 1561101978Sluigi 1562101978Sluigi for (i = 0, msg = "disable" ; i < 31; i++) 1563101978Sluigi if ( (set_disable & (1<<i))) { 1564101978Sluigi printf("%s %d", msg, i); 1565101978Sluigi msg = ""; 1566101978Sluigi } 1567101978Sluigi msg = (set_disable) ? " enable" : "enable"; 1568101978Sluigi for (i = 0; i < 31; i++) 1569101978Sluigi if ( !(set_disable & (1<<i))) { 1570101978Sluigi printf("%s %d", msg, i); 1571101978Sluigi msg = ""; 1572101978Sluigi } 1573101978Sluigi printf("\n"); 1574101978Sluigi } else if (!strncmp(*av, "swap", strlen(*av))) { 1575101978Sluigi ac--; av++; 1576101978Sluigi if (ac != 2) 1577101978Sluigi errx(EX_USAGE, "set swap needs 2 set numbers\n"); 1578101978Sluigi rulenum = atoi(av[0]); 1579101978Sluigi new_set = atoi(av[1]); 1580101978Sluigi if (!isdigit(*(av[0])) || rulenum > 30) 1581101978Sluigi errx(EX_DATAERR, "invalid set number %s\n", av[0]); 1582101978Sluigi if (!isdigit(*(av[1])) || new_set > 30) 1583101978Sluigi errx(EX_DATAERR, "invalid set number %s\n", av[1]); 1584101978Sluigi masks[0] = (4 << 24) | (new_set << 16) | (rulenum); 1585117328Sluigi i = do_cmd(IP_FW_DEL, masks, sizeof(uint32_t)); 1586101978Sluigi } else if (!strncmp(*av, "move", strlen(*av))) { 1587101978Sluigi ac--; av++; 1588101978Sluigi if (ac && !strncmp(*av, "rule", strlen(*av))) { 1589101978Sluigi cmd = 2; 1590101978Sluigi ac--; av++; 1591101978Sluigi } else 1592101978Sluigi cmd = 3; 1593101978Sluigi if (ac != 3 || strncmp(av[1], "to", strlen(*av))) 1594101978Sluigi errx(EX_USAGE, "syntax: set move [rule] X to Y\n"); 1595101978Sluigi rulenum = atoi(av[0]); 1596101978Sluigi new_set = atoi(av[2]); 1597101978Sluigi if (!isdigit(*(av[0])) || (cmd == 3 && rulenum > 30) || 1598101978Sluigi (cmd == 2 && rulenum == 65535) ) 1599101978Sluigi errx(EX_DATAERR, "invalid source number %s\n", av[0]); 1600101978Sluigi if (!isdigit(*(av[2])) || new_set > 30) 1601101978Sluigi errx(EX_DATAERR, "invalid dest. set %s\n", av[1]); 1602101978Sluigi masks[0] = (cmd << 24) | (new_set << 16) | (rulenum); 1603117328Sluigi i = do_cmd(IP_FW_DEL, masks, sizeof(uint32_t)); 1604101978Sluigi } else if (!strncmp(*av, "disable", strlen(*av)) || 1605101978Sluigi !strncmp(*av, "enable", strlen(*av)) ) { 1606101978Sluigi int which = !strncmp(*av, "enable", strlen(*av)) ? 1 : 0; 1607101978Sluigi 1608101978Sluigi ac--; av++; 1609101978Sluigi masks[0] = masks[1] = 0; 1610101978Sluigi 1611101978Sluigi while (ac) { 1612101978Sluigi if (isdigit(**av)) { 1613101978Sluigi i = atoi(*av); 1614101978Sluigi if (i < 0 || i > 30) 1615101978Sluigi errx(EX_DATAERR, 1616101978Sluigi "invalid set number %d\n", i); 1617101978Sluigi masks[which] |= (1<<i); 1618101978Sluigi } else if (!strncmp(*av, "disable", strlen(*av))) 1619101978Sluigi which = 0; 1620101978Sluigi else if (!strncmp(*av, "enable", strlen(*av))) 1621101978Sluigi which = 1; 1622101978Sluigi else 1623101978Sluigi errx(EX_DATAERR, 1624101978Sluigi "invalid set command %s\n", *av); 1625101978Sluigi av++; ac--; 1626101978Sluigi } 1627101978Sluigi if ( (masks[0] & masks[1]) != 0 ) 1628101978Sluigi errx(EX_DATAERR, 1629101978Sluigi "cannot enable and disable the same set\n"); 1630101978Sluigi 1631117328Sluigi i = do_cmd(IP_FW_DEL, masks, sizeof(masks)); 1632101978Sluigi if (i) 1633101978Sluigi warn("set enable/disable: setsockopt(IP_FW_DEL)"); 1634101978Sluigi } else 1635101978Sluigi errx(EX_USAGE, "invalid set command %s\n", *av); 1636101978Sluigi} 1637101978Sluigi 1638101978Sluigistatic void 1639109126Sdillonsysctl_handler(int ac, char *av[], int which) 1640109126Sdillon{ 1641109126Sdillon ac--; 1642109126Sdillon av++; 1643109126Sdillon 1644109126Sdillon if (*av == NULL) { 1645109126Sdillon warnx("missing keyword to enable/disable\n"); 1646109126Sdillon } else if (strncmp(*av, "firewall", strlen(*av)) == 0) { 1647116770Sluigi sysctlbyname("net.inet.ip.fw.enable", NULL, 0, 1648116770Sluigi &which, sizeof(which)); 1649109126Sdillon } else if (strncmp(*av, "one_pass", strlen(*av)) == 0) { 1650116770Sluigi sysctlbyname("net.inet.ip.fw.one_pass", NULL, 0, 1651116770Sluigi &which, sizeof(which)); 1652109126Sdillon } else if (strncmp(*av, "debug", strlen(*av)) == 0) { 1653116770Sluigi sysctlbyname("net.inet.ip.fw.debug", NULL, 0, 1654116770Sluigi &which, sizeof(which)); 1655109126Sdillon } else if (strncmp(*av, "verbose", strlen(*av)) == 0) { 1656116770Sluigi sysctlbyname("net.inet.ip.fw.verbose", NULL, 0, 1657116770Sluigi &which, sizeof(which)); 1658109126Sdillon } else if (strncmp(*av, "dyn_keepalive", strlen(*av)) == 0) { 1659116770Sluigi sysctlbyname("net.inet.ip.fw.dyn_keepalive", NULL, 0, 1660116770Sluigi &which, sizeof(which)); 1661109126Sdillon } else { 1662109126Sdillon warnx("unrecognize enable/disable keyword: %s\n", *av); 1663109126Sdillon } 1664109126Sdillon} 1665109126Sdillon 1666109126Sdillonstatic void 1667117469Sluigilist(int ac, char *av[], int show_counters) 166898943Sluigi{ 166998943Sluigi struct ip_fw *r; 167098943Sluigi ipfw_dyn_rule *dynrules, *d; 167198943Sluigi 1672117469Sluigi#define NEXT(r) ((struct ip_fw *)((char *)r + RULESIZE(r))) 1673117469Sluigi char *lim; 1674117469Sluigi void *data = NULL; 1675112189Smaxim int bcwidth, n, nbytes, nstat, ndyn, pcwidth, width; 167698943Sluigi int exitval = EX_OK; 167798943Sluigi int lac; 167898943Sluigi char **lav; 1679117469Sluigi u_long rnum, last; 168098943Sluigi char *endptr; 168198943Sluigi int seen = 0; 168298943Sluigi 168398943Sluigi const int ocmd = do_pipe ? IP_DUMMYNET_GET : IP_FW_GET; 168498943Sluigi int nalloc = 1024; /* start somewhere... */ 168598943Sluigi 1686117328Sluigi if (test_only) { 1687117328Sluigi fprintf(stderr, "Testing only, list disabled\n"); 1688117328Sluigi return; 1689117328Sluigi } 1690117328Sluigi 169198943Sluigi ac--; 169298943Sluigi av++; 169398943Sluigi 169498943Sluigi /* get rules or pipes from kernel, resizing array as necessary */ 169598943Sluigi nbytes = nalloc; 169698943Sluigi 169798943Sluigi while (nbytes >= nalloc) { 169898943Sluigi nalloc = nalloc * 2 + 200; 169998943Sluigi nbytes = nalloc; 170098943Sluigi if ((data = realloc(data, nbytes)) == NULL) 170198943Sluigi err(EX_OSERR, "realloc"); 1702117328Sluigi if (do_cmd(ocmd, data, (socklen_t)&nbytes) < 0) 170398943Sluigi err(EX_OSERR, "getsockopt(IP_%s_GET)", 170498943Sluigi do_pipe ? "DUMMYNET" : "FW"); 170598943Sluigi } 170698943Sluigi 170798943Sluigi if (do_pipe) { 170898943Sluigi list_pipes(data, nbytes, ac, av); 170998943Sluigi goto done; 171098943Sluigi } 171198943Sluigi 171298943Sluigi /* 171398943Sluigi * Count static rules. They have variable size so we 171498943Sluigi * need to scan the list to count them. 171598943Sluigi */ 1716117469Sluigi for (nstat = 1, r = data, lim = (char *)data + nbytes; 1717117469Sluigi r->rulenum < 65535 && (char *)r < lim; 1718117469Sluigi ++nstat, r = NEXT(r) ) 171998943Sluigi ; /* nothing */ 172098943Sluigi 172198943Sluigi /* 172298943Sluigi * Count dynamic rules. This is easier as they have 172398943Sluigi * fixed size. 172498943Sluigi */ 1725117469Sluigi r = NEXT(r); 172698943Sluigi dynrules = (ipfw_dyn_rule *)r ; 1727117469Sluigi n = (char *)r - (char *)data; 172898943Sluigi ndyn = (nbytes - n) / sizeof *dynrules; 172998943Sluigi 1730112189Smaxim /* if showing stats, figure out column widths ahead of time */ 1731112189Smaxim bcwidth = pcwidth = 0; 1732117469Sluigi if (show_counters) { 1733117469Sluigi for (n = 0, r = data; n < nstat; n++, r = NEXT(r)) { 1734112189Smaxim /* packet counter */ 1735115793Sticso width = snprintf(NULL, 0, "%llu", 1736115793Sticso align_uint64(&r->pcnt)); 1737112189Smaxim if (width > pcwidth) 1738112189Smaxim pcwidth = width; 1739112189Smaxim 1740112189Smaxim /* byte counter */ 1741115793Sticso width = snprintf(NULL, 0, "%llu", 1742115793Sticso align_uint64(&r->bcnt)); 1743112189Smaxim if (width > bcwidth) 1744112189Smaxim bcwidth = width; 1745112189Smaxim } 1746112189Smaxim } 1747112189Smaxim if (do_dynamic && ndyn) { 1748112189Smaxim for (n = 0, d = dynrules; n < ndyn; n++, d++) { 1749115793Sticso width = snprintf(NULL, 0, "%llu", 1750115793Sticso align_uint64(&d->pcnt)); 1751112189Smaxim if (width > pcwidth) 1752112189Smaxim pcwidth = width; 1753112189Smaxim 1754115793Sticso width = snprintf(NULL, 0, "%llu", 1755115793Sticso align_uint64(&d->bcnt)); 1756112189Smaxim if (width > bcwidth) 1757112189Smaxim bcwidth = width; 1758112189Smaxim } 1759112189Smaxim } 176098943Sluigi /* if no rule numbers were specified, list all rules */ 176198943Sluigi if (ac == 0) { 1762117469Sluigi for (n = 0, r = data; n < nstat; n++, r = NEXT(r) ) 1763112189Smaxim show_ipfw(r, pcwidth, bcwidth); 176498943Sluigi 176598943Sluigi if (do_dynamic && ndyn) { 176698943Sluigi printf("## Dynamic rules (%d):\n", ndyn); 176798943Sluigi for (n = 0, d = dynrules; n < ndyn; n++, d++) 1768112189Smaxim show_dyn_ipfw(d, pcwidth, bcwidth); 176998943Sluigi } 177098943Sluigi goto done; 177198943Sluigi } 177298943Sluigi 177398943Sluigi /* display specific rules requested on command line */ 177498943Sluigi 177598943Sluigi for (lac = ac, lav = av; lac != 0; lac--) { 177698943Sluigi /* convert command line rule # */ 1777117469Sluigi last = rnum = strtoul(*lav++, &endptr, 10); 1778117469Sluigi if (*endptr == '-') 1779117469Sluigi last = strtoul(endptr+1, &endptr, 10); 178098943Sluigi if (*endptr) { 1781117469Sluigi 178298943Sluigi exitval = EX_USAGE; 178398943Sluigi warnx("invalid rule number: %s", *(lav - 1)); 178498943Sluigi continue; 178598943Sluigi } 1786117469Sluigi for (n = seen = 0, r = data; n < nstat; n++, r = NEXT(r) ) { 1787117469Sluigi if (r->rulenum > last) 178898943Sluigi break; 1789117469Sluigi if (r->rulenum >= rnum && r->rulenum <= last) { 1790112189Smaxim show_ipfw(r, pcwidth, bcwidth); 179198943Sluigi seen = 1; 179298943Sluigi } 179398943Sluigi } 179498943Sluigi if (!seen) { 179598943Sluigi /* give precedence to other error(s) */ 179698943Sluigi if (exitval == EX_OK) 179798943Sluigi exitval = EX_UNAVAILABLE; 179898943Sluigi warnx("rule %lu does not exist", rnum); 179998943Sluigi } 180098943Sluigi } 180198943Sluigi 180298943Sluigi if (do_dynamic && ndyn) { 180398943Sluigi printf("## Dynamic rules:\n"); 180498943Sluigi for (lac = ac, lav = av; lac != 0; lac--) { 180598943Sluigi rnum = strtoul(*lav++, &endptr, 10); 1806117469Sluigi if (*endptr == '-') 1807117469Sluigi last = strtoul(endptr+1, &endptr, 10); 180898943Sluigi if (*endptr) 180998943Sluigi /* already warned */ 181098943Sluigi continue; 181198943Sluigi for (n = 0, d = dynrules; n < ndyn; n++, d++) { 1812115793Sticso uint16_t rulenum; 1813115793Sticso 1814115793Sticso bcopy(&d->rule, &rulenum, sizeof(rulenum)); 1815115793Sticso if (rulenum > rnum) 181698943Sluigi break; 1817117469Sluigi if (r->rulenum >= rnum && r->rulenum <= last) 1818112189Smaxim show_dyn_ipfw(d, pcwidth, bcwidth); 181998943Sluigi } 182098943Sluigi } 182198943Sluigi } 182298943Sluigi 182398943Sluigi ac = 0; 182498943Sluigi 182598943Sluigidone: 182698943Sluigi free(data); 182798943Sluigi 182898943Sluigi if (exitval != EX_OK) 182998943Sluigi exit(exitval); 1830117469Sluigi#undef NEXT 183198943Sluigi} 183298943Sluigi 183398943Sluigistatic void 183498943Sluigishow_usage(void) 183598943Sluigi{ 183698943Sluigi fprintf(stderr, "usage: ipfw [options]\n" 183798943Sluigi"do \"ipfw -h\" or see ipfw manpage for details\n" 183898943Sluigi); 183998943Sluigi exit(EX_USAGE); 184098943Sluigi} 184198943Sluigi 184298943Sluigistatic void 184398943Sluigihelp(void) 184498943Sluigi{ 1845117328Sluigi fprintf(stderr, 1846117328Sluigi"ipfw syntax summary (but please do read the ipfw(8) manpage):\n" 1847117544Sluigi"ipfw [-acdeftTnNpqS] <command> where <command is one of:\n" 1848117328Sluigi"add [num] [set N] [prob x] RULE-BODY\n" 1849117328Sluigi"{pipe|queue} N config PIPE-BODY\n" 1850117328Sluigi"[pipe|queue] {zero|delete|show} [N{,N}]\n" 1851117328Sluigi"set [disable N... enable N...] | move [rule] X to Y | swap X Y | show\n" 185298943Sluigi"\n" 1853117328Sluigi"RULE-BODY: check-state [LOG] | ACTION [LOG] ADDR [OPTION_LIST]\n" 185498943Sluigi"ACTION: check-state | allow | count | deny | reject | skipto N |\n" 185598943Sluigi" {divert|tee} PORT | forward ADDR | pipe N | queue N\n" 185698943Sluigi"ADDR: [ MAC dst src ether_type ] \n" 1857117544Sluigi" [ from IPADDR [ PORT ] to IPADDR [ PORTLIST ] ]\n" 1858117544Sluigi"IPADDR: [not] { any | me | ip/bits{x,y,z} | IPLIST }\n" 1859117544Sluigi"IPLIST: { ip | ip/bits | ip:mask }[,IPLIST]\n" 1860117544Sluigi"OPTION_LIST: OPTION [OPTION_LIST]\n" 1861117328Sluigi"OPTION: bridged | {dst-ip|src-ip} ADDR | {dst-port|src-port} LIST |\n" 1862117328Sluigi" estab | frag | {gid|uid} N | icmptypes LIST | in | out | ipid LIST |\n" 1863117328Sluigi" iplen LIST | ipoptions SPEC | ipprecedence | ipsec | iptos SPEC |\n" 1864117328Sluigi" ipttl LIST | ipversion VER | keep-state | layer2 | limit ... |\n" 1865117328Sluigi" mac ... | mac-type LIST | proto LIST | {recv|xmit|via} {IF|IPADDR} |\n" 1866117328Sluigi" setup | {tcpack|tcpseq|tcpwin} NN | tcpflags SPEC | tcpoptions SPEC |\n" 1867117328Sluigi" verrevpath\n" 186898943Sluigi); 186998943Sluigiexit(0); 187098943Sluigi} 187198943Sluigi 187298943Sluigi 187398943Sluigistatic int 187498943Sluigilookup_host (char *host, struct in_addr *ipaddr) 187598943Sluigi{ 187698943Sluigi struct hostent *he; 187798943Sluigi 187898943Sluigi if (!inet_aton(host, ipaddr)) { 187998943Sluigi if ((he = gethostbyname(host)) == NULL) 188098943Sluigi return(-1); 188198943Sluigi *ipaddr = *(struct in_addr *)he->h_addr_list[0]; 188298943Sluigi } 188398943Sluigi return(0); 188498943Sluigi} 188598943Sluigi 188698943Sluigi/* 188798943Sluigi * fills the addr and mask fields in the instruction as appropriate from av. 188898943Sluigi * Update length as appropriate. 188998943Sluigi * The following formats are allowed: 189098943Sluigi * any matches any IP. Actually returns an empty instruction. 189198943Sluigi * me returns O_IP_*_ME 189298943Sluigi * 1.2.3.4 single IP address 189398943Sluigi * 1.2.3.4:5.6.7.8 address:mask 189498943Sluigi * 1.2.3.4/24 address/mask 189598943Sluigi * 1.2.3.4/26{1,6,5,4,23} set of addresses in a subnet 1896117328Sluigi * We can have multiple comma-separated address/mask entries. 189798943Sluigi */ 189898943Sluigistatic void 189998943Sluigifill_ip(ipfw_insn_ip *cmd, char *av) 190098943Sluigi{ 1901117328Sluigi int len = 0; 1902117328Sluigi uint32_t *d = ((ipfw_insn_u32 *)cmd)->d; 190398943Sluigi 190498943Sluigi cmd->o.len &= ~F_LEN_MASK; /* zero len */ 190598943Sluigi 190698943Sluigi if (!strncmp(av, "any", strlen(av))) 190798943Sluigi return; 190898943Sluigi 190998943Sluigi if (!strncmp(av, "me", strlen(av))) { 191098943Sluigi cmd->o.len |= F_INSN_SIZE(ipfw_insn); 191198943Sluigi return; 191298943Sluigi } 191398943Sluigi 1914117328Sluigi while (av) { 1915117328Sluigi /* 1916117328Sluigi * After the address we can have '/' or ':' indicating a mask, 1917117328Sluigi * ',' indicating another address follows, '{' indicating a 1918117328Sluigi * set of addresses of unspecified size. 1919117328Sluigi */ 1920117328Sluigi char *p = strpbrk(av, "/:,{"); 1921117328Sluigi int masklen; 1922117328Sluigi char md; 1923117328Sluigi 192498943Sluigi if (p) { 192598943Sluigi md = *p; 192698943Sluigi *p++ = '\0'; 1927117328Sluigi } else 1928117328Sluigi md = '\0'; 192998943Sluigi 1930117328Sluigi if (lookup_host(av, (struct in_addr *)&d[0]) != 0) 193198943Sluigi errx(EX_NOHOST, "hostname ``%s'' unknown", av); 193298943Sluigi switch (md) { 193398943Sluigi case ':': 1934117328Sluigi if (!inet_aton(p, (struct in_addr *)&d[1])) 193598943Sluigi errx(EX_DATAERR, "bad netmask ``%s''", p); 193698943Sluigi break; 193798943Sluigi case '/': 1938117328Sluigi masklen = atoi(p); 1939117328Sluigi if (masklen == 0) 1940117328Sluigi d[1] = htonl(0); /* mask */ 1941117328Sluigi else if (masklen > 32) 194298943Sluigi errx(EX_DATAERR, "bad width ``%s''", p); 194398943Sluigi else 1944117328Sluigi d[1] = htonl(~0 << (32 - masklen)); 194598943Sluigi break; 1946117328Sluigi case '{': /* no mask, assume /24 and put back the '{' */ 1947117328Sluigi d[1] = htonl(~0 << (32 - 24)); 1948117328Sluigi *(--p) = md; 1949117328Sluigi break; 1950117328Sluigi 1951117328Sluigi case ',': /* single address plus continuation */ 1952117328Sluigi *(--p) = md; 1953117328Sluigi /* FALLTHROUGH */ 1954117328Sluigi case 0: /* initialization value */ 195598943Sluigi default: 1956117328Sluigi d[1] = htonl(~0); /* force /32 */ 195798943Sluigi break; 195898943Sluigi } 1959117328Sluigi d[0] &= d[1]; /* mask base address with mask */ 1960117328Sluigi /* find next separator */ 196198943Sluigi if (p) 1962117328Sluigi p = strpbrk(p, ",{"); 1963117328Sluigi if (p && *p == '{') { 1964117328Sluigi /* 1965117328Sluigi * We have a set of addresses. They are stored as follows: 1966117328Sluigi * arg1 is the set size (powers of 2, 2..256) 1967117328Sluigi * addr is the base address IN HOST FORMAT 1968117328Sluigi * mask.. is an array of arg1 bits (rounded up to 1969117328Sluigi * the next multiple of 32) with bits set 1970117328Sluigi * for each host in the map. 1971117328Sluigi */ 1972117328Sluigi uint32_t *map = (uint32_t *)&cmd->mask; 197398943Sluigi int low, high; 1974117328Sluigi int i = contigmask((u_char *)&(d[1]), 32); 197598943Sluigi 1976117328Sluigi if (len > 0) 1977117328Sluigi errx(EX_DATAERR, "address set cannot be in a list"); 1978117328Sluigi if (i < 24 || i > 31) 1979117328Sluigi errx(EX_DATAERR, "invalid set with mask %d\n", i); 1980117328Sluigi cmd->o.arg1 = 1<<(32-i); /* map length */ 1981117328Sluigi d[0] = ntohl(d[0]); /* base addr in host format */ 198298943Sluigi cmd->o.opcode = O_IP_DST_SET; /* default */ 198398943Sluigi cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32) + (cmd->o.arg1+31)/32; 1984101117Sluigi for (i = 0; i < (cmd->o.arg1+31)/32 ; i++) 1985117328Sluigi map[i] = 0; /* clear map */ 198698943Sluigi 1987117328Sluigi av = p + 1; 1988117328Sluigi low = d[0] & 0xff; 198998943Sluigi high = low + cmd->o.arg1 - 1; 1990117328Sluigi /* 1991117328Sluigi * Here, i stores the previous value when we specify a range 1992117328Sluigi * of addresses within a mask, e.g. 45-63. i = -1 means we 1993117328Sluigi * have no previous value. 1994117328Sluigi */ 1995116716Sluigi i = -1; /* previous value in a range */ 199698943Sluigi while (isdigit(*av)) { 199798943Sluigi char *s; 1998117328Sluigi int a = strtol(av, &s, 0); 199998943Sluigi 2000117328Sluigi if (s == av) { /* no parameter */ 2001117328Sluigi if (*av != '}') 2002117328Sluigi errx(EX_DATAERR, "set not closed\n"); 2003117328Sluigi if (i != -1) 2004117328Sluigi errx(EX_DATAERR, "incomplete range %d-", i); 2005117328Sluigi break; 2006117328Sluigi } 2007117328Sluigi if (a < low || a > high) 2008117328Sluigi errx(EX_DATAERR, "addr %d out of range [%d-%d]\n", 200998943Sluigi a, low, high); 201098943Sluigi a -= low; 2011116716Sluigi if (i == -1) /* no previous in range */ 2012116716Sluigi i = a; 2013116716Sluigi else { /* check that range is valid */ 2014116716Sluigi if (i > a) 2015116716Sluigi errx(EX_DATAERR, "invalid range %d-%d", 2016116716Sluigi i+low, a+low); 2017116716Sluigi if (*s == '-') 2018116716Sluigi errx(EX_DATAERR, "double '-' in range"); 2019116716Sluigi } 2020116716Sluigi for (; i <= a; i++) 2021117328Sluigi map[i/32] |= 1<<(i & 31); 2022116716Sluigi i = -1; 2023116716Sluigi if (*s == '-') 2024116716Sluigi i = a; 2025117328Sluigi else if (*s == '}') 2026116716Sluigi break; 202798943Sluigi av = s+1; 202898943Sluigi } 202998943Sluigi return; 203098943Sluigi } 2031117328Sluigi av = p; 2032117328Sluigi if (av) /* then *av must be a ',' */ 2033117328Sluigi av++; 203498943Sluigi 2035117328Sluigi /* Check this entry */ 2036117328Sluigi if (d[1] == 0) { /* "any", specified as x.x.x.x/0 */ 2037117328Sluigi /* 2038117328Sluigi * 'any' turns the entire list into a NOP. 2039117328Sluigi * 'not any' never matches, so it is removed from the 2040117328Sluigi * list unless it is the only item, in which case we 2041117328Sluigi * report an error. 2042117328Sluigi */ 2043117328Sluigi if (cmd->o.len & F_NOT) { /* "not any" never matches */ 2044117328Sluigi if (av == NULL && len == 0) /* only this entry */ 2045117328Sluigi errx(EX_DATAERR, "not any never matches"); 2046117328Sluigi } 2047117328Sluigi /* else do nothing and skip this entry */ 2048117328Sluigi continue; 2049117328Sluigi } 2050117328Sluigi /* A single IP can be stored in an optimized format */ 2051117328Sluigi if (d[1] == IP_MASK_ALL && av == NULL && len == 0) { 205298943Sluigi cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32); 2053117328Sluigi return; 2054117328Sluigi } 2055117328Sluigi len += 2; /* two words... */ 2056117328Sluigi d += 2; 2057117328Sluigi } /* end while */ 2058117328Sluigi cmd->o.len |= len+1; 205998943Sluigi} 206098943Sluigi 206198943Sluigi 206298943Sluigi/* 206398943Sluigi * helper function to process a set of flags and set bits in the 206498943Sluigi * appropriate masks. 206598943Sluigi */ 206698943Sluigistatic void 206798943Sluigifill_flags(ipfw_insn *cmd, enum ipfw_opcodes opcode, 206898943Sluigi struct _s_x *flags, char *p) 206998943Sluigi{ 2070117328Sluigi uint8_t set=0, clear=0; 207198943Sluigi 207298943Sluigi while (p && *p) { 207398943Sluigi char *q; /* points to the separator */ 207498943Sluigi int val; 2075117328Sluigi uint8_t *which; /* mask we are working on */ 207698943Sluigi 207798943Sluigi if (*p == '!') { 207898943Sluigi p++; 207998943Sluigi which = &clear; 208098943Sluigi } else 208198943Sluigi which = &set; 208298943Sluigi q = strchr(p, ','); 208398943Sluigi if (q) 208498943Sluigi *q++ = '\0'; 208598943Sluigi val = match_token(flags, p); 208698943Sluigi if (val <= 0) 208798943Sluigi errx(EX_DATAERR, "invalid flag %s", p); 2088117328Sluigi *which |= (uint8_t)val; 208998943Sluigi p = q; 209098943Sluigi } 209198943Sluigi cmd->opcode = opcode; 209298943Sluigi cmd->len = (cmd->len & (F_NOT | F_OR)) | 1; 209398943Sluigi cmd->arg1 = (set & 0xff) | ( (clear & 0xff) << 8); 209498943Sluigi} 209598943Sluigi 209698943Sluigi 209798943Sluigistatic void 209898943Sluigidelete(int ac, char *av[]) 209998943Sluigi{ 2100117328Sluigi uint32_t rulenum; 2101117469Sluigi struct dn_pipe p; 210298943Sluigi int i; 210398943Sluigi int exitval = EX_OK; 2104101628Sluigi int do_set = 0; 210598943Sluigi 2106117469Sluigi memset(&p, 0, sizeof p); 210798943Sluigi 210898943Sluigi av++; ac--; 2109101641Sluigi if (ac > 0 && !strncmp(*av, "set", strlen(*av))) { 2110101978Sluigi do_set = 1; /* delete set */ 2111101628Sluigi ac--; av++; 2112101978Sluigi } 211398943Sluigi 211498943Sluigi /* Rule number */ 211598943Sluigi while (ac && isdigit(**av)) { 211698943Sluigi i = atoi(*av); av++; ac--; 211798943Sluigi if (do_pipe) { 211898943Sluigi if (do_pipe == 1) 2119117469Sluigi p.pipe_nr = i; 212098943Sluigi else 2121117469Sluigi p.fs.fs_nr = i; 2122117469Sluigi i = do_cmd(IP_DUMMYNET_DEL, &p, sizeof p); 212398943Sluigi if (i) { 212498943Sluigi exitval = 1; 212598943Sluigi warn("rule %u: setsockopt(IP_DUMMYNET_DEL)", 2126117469Sluigi do_pipe == 1 ? p.pipe_nr : p.fs.fs_nr); 212798943Sluigi } 212898943Sluigi } else { 2129101978Sluigi rulenum = (i & 0xffff) | (do_set << 24); 2130117328Sluigi i = do_cmd(IP_FW_DEL, &rulenum, sizeof rulenum); 213198943Sluigi if (i) { 213298943Sluigi exitval = EX_UNAVAILABLE; 213398943Sluigi warn("rule %u: setsockopt(IP_FW_DEL)", 213498943Sluigi rulenum); 213598943Sluigi } 213698943Sluigi } 213798943Sluigi } 213898943Sluigi if (exitval != EX_OK) 213998943Sluigi exit(exitval); 214098943Sluigi} 214198943Sluigi 214298943Sluigi 214398943Sluigi/* 214498943Sluigi * fill the interface structure. We do not check the name as we can 214598943Sluigi * create interfaces dynamically, so checking them at insert time 214698943Sluigi * makes relatively little sense. 214798943Sluigi * A '*' following the name means any unit. 214898943Sluigi */ 214998943Sluigistatic void 215098943Sluigifill_iface(ipfw_insn_if *cmd, char *arg) 215198943Sluigi{ 215298943Sluigi cmd->name[0] = '\0'; 215398943Sluigi cmd->o.len |= F_INSN_SIZE(ipfw_insn_if); 215498943Sluigi 215598943Sluigi /* Parse the interface or address */ 215698943Sluigi if (!strcmp(arg, "any")) 215798943Sluigi cmd->o.len = 0; /* effectively ignore this command */ 215898943Sluigi else if (!isdigit(*arg)) { 215998943Sluigi char *q; 216098943Sluigi 216198943Sluigi strncpy(cmd->name, arg, sizeof(cmd->name)); 216298943Sluigi cmd->name[sizeof(cmd->name) - 1] = '\0'; 216398943Sluigi /* find first digit or wildcard */ 216498943Sluigi for (q = cmd->name; *q && !isdigit(*q) && *q != '*'; q++) 216598943Sluigi continue; 216698943Sluigi cmd->p.unit = (*q == '*') ? -1 : atoi(q); 216798943Sluigi *q = '\0'; 216898943Sluigi } else if (!inet_aton(arg, &cmd->p.ip)) 216998943Sluigi errx(EX_DATAERR, "bad ip address ``%s''", arg); 217098943Sluigi} 217198943Sluigi 217298943Sluigi/* 217398943Sluigi * the following macro returns an error message if we run out of 217498943Sluigi * arguments. 217598943Sluigi */ 217698943Sluigi#define NEED1(msg) {if (!ac) errx(EX_USAGE, msg);} 217798943Sluigi 217898943Sluigistatic void 217998943Sluigiconfig_pipe(int ac, char **av) 218098943Sluigi{ 2181117469Sluigi struct dn_pipe p; 218298943Sluigi int i; 218398943Sluigi char *end; 2184117328Sluigi uint32_t a; 218598943Sluigi void *par = NULL; 218698943Sluigi 2187117469Sluigi memset(&p, 0, sizeof p); 218898943Sluigi 218998943Sluigi av++; ac--; 219098943Sluigi /* Pipe number */ 219198943Sluigi if (ac && isdigit(**av)) { 219298943Sluigi i = atoi(*av); av++; ac--; 219398943Sluigi if (do_pipe == 1) 2194117469Sluigi p.pipe_nr = i; 219598943Sluigi else 2196117469Sluigi p.fs.fs_nr = i; 219798943Sluigi } 219899475Sluigi while (ac > 0) { 219998943Sluigi double d; 220098943Sluigi int tok = match_token(dummynet_params, *av); 220198943Sluigi ac--; av++; 220298943Sluigi 220398943Sluigi switch(tok) { 2204101978Sluigi case TOK_NOERROR: 2205117469Sluigi p.fs.flags_fs |= DN_NOERROR; 2206101978Sluigi break; 2207101978Sluigi 220898943Sluigi case TOK_PLR: 220998943Sluigi NEED1("plr needs argument 0..1\n"); 221098943Sluigi d = strtod(av[0], NULL); 221198943Sluigi if (d > 1) 221298943Sluigi d = 1; 221398943Sluigi else if (d < 0) 221498943Sluigi d = 0; 2215117469Sluigi p.fs.plr = (int)(d*0x7fffffff); 221698943Sluigi ac--; av++; 221798943Sluigi break; 221898943Sluigi 221998943Sluigi case TOK_QUEUE: 222098943Sluigi NEED1("queue needs queue size\n"); 222198943Sluigi end = NULL; 2222117469Sluigi p.fs.qsize = strtoul(av[0], &end, 0); 222398943Sluigi if (*end == 'K' || *end == 'k') { 2224117469Sluigi p.fs.flags_fs |= DN_QSIZE_IS_BYTES; 2225117469Sluigi p.fs.qsize *= 1024; 222698943Sluigi } else if (*end == 'B' || !strncmp(end, "by", 2)) { 2227117469Sluigi p.fs.flags_fs |= DN_QSIZE_IS_BYTES; 222898943Sluigi } 222998943Sluigi ac--; av++; 223098943Sluigi break; 223198943Sluigi 223298943Sluigi case TOK_BUCKETS: 223398943Sluigi NEED1("buckets needs argument\n"); 2234117469Sluigi p.fs.rq_size = strtoul(av[0], NULL, 0); 223598943Sluigi ac--; av++; 223698943Sluigi break; 223798943Sluigi 223898943Sluigi case TOK_MASK: 223998943Sluigi NEED1("mask needs mask specifier\n"); 224098943Sluigi /* 224198943Sluigi * per-flow queue, mask is dst_ip, dst_port, 224298943Sluigi * src_ip, src_port, proto measured in bits 224398943Sluigi */ 224498943Sluigi par = NULL; 224598943Sluigi 2246117469Sluigi p.fs.flow_mask.dst_ip = 0; 2247117469Sluigi p.fs.flow_mask.src_ip = 0; 2248117469Sluigi p.fs.flow_mask.dst_port = 0; 2249117469Sluigi p.fs.flow_mask.src_port = 0; 2250117469Sluigi p.fs.flow_mask.proto = 0; 225198943Sluigi end = NULL; 225298943Sluigi 225398943Sluigi while (ac >= 1) { 2254117328Sluigi uint32_t *p32 = NULL; 2255117328Sluigi uint16_t *p16 = NULL; 225698943Sluigi 225798943Sluigi tok = match_token(dummynet_params, *av); 225898943Sluigi ac--; av++; 225998943Sluigi switch(tok) { 226098943Sluigi case TOK_ALL: 226198943Sluigi /* 226298943Sluigi * special case, all bits significant 226398943Sluigi */ 2264117469Sluigi p.fs.flow_mask.dst_ip = ~0; 2265117469Sluigi p.fs.flow_mask.src_ip = ~0; 2266117469Sluigi p.fs.flow_mask.dst_port = ~0; 2267117469Sluigi p.fs.flow_mask.src_port = ~0; 2268117469Sluigi p.fs.flow_mask.proto = ~0; 2269117469Sluigi p.fs.flags_fs |= DN_HAVE_FLOW_MASK; 227098943Sluigi goto end_mask; 227198943Sluigi 227298943Sluigi case TOK_DSTIP: 2273117469Sluigi p32 = &p.fs.flow_mask.dst_ip; 227498943Sluigi break; 227598943Sluigi 227698943Sluigi case TOK_SRCIP: 2277117469Sluigi p32 = &p.fs.flow_mask.src_ip; 227898943Sluigi break; 227998943Sluigi 228098943Sluigi case TOK_DSTPORT: 2281117469Sluigi p16 = &p.fs.flow_mask.dst_port; 228298943Sluigi break; 228398943Sluigi 228498943Sluigi case TOK_SRCPORT: 2285117469Sluigi p16 = &p.fs.flow_mask.src_port; 228698943Sluigi break; 228798943Sluigi 228898943Sluigi case TOK_PROTO: 228998943Sluigi break; 229098943Sluigi 229198943Sluigi default: 229298943Sluigi ac++; av--; /* backtrack */ 229398943Sluigi goto end_mask; 229498943Sluigi } 229598943Sluigi if (ac < 1) 229698943Sluigi errx(EX_USAGE, "mask: value missing"); 229798943Sluigi if (*av[0] == '/') { 229898943Sluigi a = strtoul(av[0]+1, &end, 0); 229998943Sluigi a = (a == 32) ? ~0 : (1 << a) - 1; 2300106505Smaxim } else 230199909Sluigi a = strtoul(av[0], &end, 0); 230298943Sluigi if (p32 != NULL) 230398943Sluigi *p32 = a; 230498943Sluigi else if (p16 != NULL) { 230598943Sluigi if (a > 65535) 230698943Sluigi errx(EX_DATAERR, 230798943Sluigi "mask: must be 16 bit"); 2308117328Sluigi *p16 = (uint16_t)a; 230998943Sluigi } else { 231098943Sluigi if (a > 255) 231198943Sluigi errx(EX_DATAERR, 231298943Sluigi "mask: must be 8 bit"); 2313117469Sluigi p.fs.flow_mask.proto = (uint8_t)a; 231498943Sluigi } 231598943Sluigi if (a != 0) 2316117469Sluigi p.fs.flags_fs |= DN_HAVE_FLOW_MASK; 231798943Sluigi ac--; av++; 231898943Sluigi } /* end while, config masks */ 231998943Sluigiend_mask: 232098943Sluigi break; 232198943Sluigi 232298943Sluigi case TOK_RED: 232398943Sluigi case TOK_GRED: 232498943Sluigi NEED1("red/gred needs w_q/min_th/max_th/max_p\n"); 2325117469Sluigi p.fs.flags_fs |= DN_IS_RED; 232698943Sluigi if (tok == TOK_GRED) 2327117469Sluigi p.fs.flags_fs |= DN_IS_GENTLE_RED; 232898943Sluigi /* 232998943Sluigi * the format for parameters is w_q/min_th/max_th/max_p 233098943Sluigi */ 233198943Sluigi if ((end = strsep(&av[0], "/"))) { 233298943Sluigi double w_q = strtod(end, NULL); 233398943Sluigi if (w_q > 1 || w_q <= 0) 233498943Sluigi errx(EX_DATAERR, "0 < w_q <= 1"); 2335117469Sluigi p.fs.w_q = (int) (w_q * (1 << SCALE_RED)); 233698943Sluigi } 233798943Sluigi if ((end = strsep(&av[0], "/"))) { 2338117469Sluigi p.fs.min_th = strtoul(end, &end, 0); 233998943Sluigi if (*end == 'K' || *end == 'k') 2340117469Sluigi p.fs.min_th *= 1024; 234198943Sluigi } 234298943Sluigi if ((end = strsep(&av[0], "/"))) { 2343117469Sluigi p.fs.max_th = strtoul(end, &end, 0); 234498943Sluigi if (*end == 'K' || *end == 'k') 2345117469Sluigi p.fs.max_th *= 1024; 234698943Sluigi } 234798943Sluigi if ((end = strsep(&av[0], "/"))) { 234898943Sluigi double max_p = strtod(end, NULL); 234998943Sluigi if (max_p > 1 || max_p <= 0) 235098943Sluigi errx(EX_DATAERR, "0 < max_p <= 1"); 2351117469Sluigi p.fs.max_p = (int)(max_p * (1 << SCALE_RED)); 235298943Sluigi } 235398943Sluigi ac--; av++; 235498943Sluigi break; 235598943Sluigi 235698943Sluigi case TOK_DROPTAIL: 2357117469Sluigi p.fs.flags_fs &= ~(DN_IS_RED|DN_IS_GENTLE_RED); 235898943Sluigi break; 2359106505Smaxim 236098943Sluigi case TOK_BW: 236198943Sluigi NEED1("bw needs bandwidth or interface\n"); 236298943Sluigi if (do_pipe != 1) 236398943Sluigi errx(EX_DATAERR, "bandwidth only valid for pipes"); 236498943Sluigi /* 236598943Sluigi * set clocking interface or bandwidth value 236698943Sluigi */ 236798943Sluigi if (av[0][0] >= 'a' && av[0][0] <= 'z') { 2368117469Sluigi int l = sizeof(p.if_name)-1; 236998943Sluigi /* interface name */ 2370117469Sluigi strncpy(p.if_name, av[0], l); 2371117469Sluigi p.if_name[l] = '\0'; 2372117469Sluigi p.bandwidth = 0; 237398943Sluigi } else { 2374117469Sluigi p.if_name[0] = '\0'; 2375117469Sluigi p.bandwidth = strtoul(av[0], &end, 0); 237698943Sluigi if (*end == 'K' || *end == 'k') { 237798943Sluigi end++; 2378117469Sluigi p.bandwidth *= 1000; 237998943Sluigi } else if (*end == 'M') { 238098943Sluigi end++; 2381117469Sluigi p.bandwidth *= 1000000; 238298943Sluigi } 238398943Sluigi if (*end == 'B' || !strncmp(end, "by", 2)) 2384117469Sluigi p.bandwidth *= 8; 2385117469Sluigi if (p.bandwidth < 0) 238698943Sluigi errx(EX_DATAERR, "bandwidth too large"); 238798943Sluigi } 238898943Sluigi ac--; av++; 238998943Sluigi break; 239098943Sluigi 239198943Sluigi case TOK_DELAY: 239298943Sluigi if (do_pipe != 1) 239398943Sluigi errx(EX_DATAERR, "delay only valid for pipes"); 239498943Sluigi NEED1("delay needs argument 0..10000ms\n"); 2395117469Sluigi p.delay = strtoul(av[0], NULL, 0); 239698943Sluigi ac--; av++; 239798943Sluigi break; 239898943Sluigi 239998943Sluigi case TOK_WEIGHT: 240098943Sluigi if (do_pipe == 1) 240198943Sluigi errx(EX_DATAERR,"weight only valid for queues"); 240298943Sluigi NEED1("weight needs argument 0..100\n"); 2403117469Sluigi p.fs.weight = strtoul(av[0], &end, 0); 240498943Sluigi ac--; av++; 240598943Sluigi break; 240698943Sluigi 240798943Sluigi case TOK_PIPE: 240898943Sluigi if (do_pipe == 1) 240998943Sluigi errx(EX_DATAERR,"pipe only valid for queues"); 241098943Sluigi NEED1("pipe needs pipe_number\n"); 2411117469Sluigi p.fs.parent_nr = strtoul(av[0], &end, 0); 241298943Sluigi ac--; av++; 241398943Sluigi break; 241498943Sluigi 241598943Sluigi default: 241698943Sluigi errx(EX_DATAERR, "unrecognised option ``%s''", *av); 241798943Sluigi } 241898943Sluigi } 241998943Sluigi if (do_pipe == 1) { 2420117469Sluigi if (p.pipe_nr == 0) 242198943Sluigi errx(EX_DATAERR, "pipe_nr must be > 0"); 2422117469Sluigi if (p.delay > 10000) 242398943Sluigi errx(EX_DATAERR, "delay must be < 10000"); 242498943Sluigi } else { /* do_pipe == 2, queue */ 2425117469Sluigi if (p.fs.parent_nr == 0) 242698943Sluigi errx(EX_DATAERR, "pipe must be > 0"); 2427117469Sluigi if (p.fs.weight >100) 242898943Sluigi errx(EX_DATAERR, "weight must be <= 100"); 242998943Sluigi } 2430117469Sluigi if (p.fs.flags_fs & DN_QSIZE_IS_BYTES) { 2431117469Sluigi if (p.fs.qsize > 1024*1024) 243298943Sluigi errx(EX_DATAERR, "queue size must be < 1MB"); 243398943Sluigi } else { 2434117469Sluigi if (p.fs.qsize > 100) 243598943Sluigi errx(EX_DATAERR, "2 <= queue size <= 100"); 243698943Sluigi } 2437117469Sluigi if (p.fs.flags_fs & DN_IS_RED) { 243898943Sluigi size_t len; 243998943Sluigi int lookup_depth, avg_pkt_size; 244098943Sluigi double s, idle, weight, w_q; 2441117469Sluigi struct clockinfo ck; 244298943Sluigi int t; 244398943Sluigi 2444117469Sluigi if (p.fs.min_th >= p.fs.max_th) 244598943Sluigi errx(EX_DATAERR, "min_th %d must be < than max_th %d", 2446117469Sluigi p.fs.min_th, p.fs.max_th); 2447117469Sluigi if (p.fs.max_th == 0) 244898943Sluigi errx(EX_DATAERR, "max_th must be > 0"); 244998943Sluigi 245098943Sluigi len = sizeof(int); 245198943Sluigi if (sysctlbyname("net.inet.ip.dummynet.red_lookup_depth", 245298943Sluigi &lookup_depth, &len, NULL, 0) == -1) 245398943Sluigi 245498943Sluigi errx(1, "sysctlbyname(\"%s\")", 245598943Sluigi "net.inet.ip.dummynet.red_lookup_depth"); 245698943Sluigi if (lookup_depth == 0) 245798943Sluigi errx(EX_DATAERR, "net.inet.ip.dummynet.red_lookup_depth" 245898943Sluigi " must be greater than zero"); 245998943Sluigi 246098943Sluigi len = sizeof(int); 246198943Sluigi if (sysctlbyname("net.inet.ip.dummynet.red_avg_pkt_size", 246298943Sluigi &avg_pkt_size, &len, NULL, 0) == -1) 246398943Sluigi 246498943Sluigi errx(1, "sysctlbyname(\"%s\")", 246598943Sluigi "net.inet.ip.dummynet.red_avg_pkt_size"); 246698943Sluigi if (avg_pkt_size == 0) 246798943Sluigi errx(EX_DATAERR, 246898943Sluigi "net.inet.ip.dummynet.red_avg_pkt_size must" 246998943Sluigi " be greater than zero"); 247098943Sluigi 247198943Sluigi len = sizeof(struct clockinfo); 2472117469Sluigi if (sysctlbyname("kern.clockrate", &ck, &len, NULL, 0) == -1) 247398943Sluigi errx(1, "sysctlbyname(\"%s\")", "kern.clockrate"); 247498943Sluigi 247598943Sluigi /* 247698943Sluigi * Ticks needed for sending a medium-sized packet. 247798943Sluigi * Unfortunately, when we are configuring a WF2Q+ queue, we 247898943Sluigi * do not have bandwidth information, because that is stored 247998943Sluigi * in the parent pipe, and also we have multiple queues 248098943Sluigi * competing for it. So we set s=0, which is not very 248198943Sluigi * correct. But on the other hand, why do we want RED with 248298943Sluigi * WF2Q+ ? 248398943Sluigi */ 2484117469Sluigi if (p.bandwidth==0) /* this is a WF2Q+ queue */ 248598943Sluigi s = 0; 248698943Sluigi else 2487117469Sluigi s = ck.hz * avg_pkt_size * 8 / p.bandwidth; 248898943Sluigi 248998943Sluigi /* 249098943Sluigi * max idle time (in ticks) before avg queue size becomes 0. 249198943Sluigi * NOTA: (3/w_q) is approx the value x so that 249298943Sluigi * (1-w_q)^x < 10^-3. 249398943Sluigi */ 2494117469Sluigi w_q = ((double)p.fs.w_q) / (1 << SCALE_RED); 249598943Sluigi idle = s * 3. / w_q; 2496117469Sluigi p.fs.lookup_step = (int)idle / lookup_depth; 2497117469Sluigi if (!p.fs.lookup_step) 2498117469Sluigi p.fs.lookup_step = 1; 249998943Sluigi weight = 1 - w_q; 2500117469Sluigi for (t = p.fs.lookup_step; t > 0; --t) 250198943Sluigi weight *= weight; 2502117469Sluigi p.fs.lookup_weight = (int)(weight * (1 << SCALE_RED)); 250398943Sluigi } 2504117469Sluigi i = do_cmd(IP_DUMMYNET_CONFIGURE, &p, sizeof p); 250598943Sluigi if (i) 250698943Sluigi err(1, "setsockopt(%s)", "IP_DUMMYNET_CONFIGURE"); 250798943Sluigi} 250898943Sluigi 250998943Sluigistatic void 251098943Sluigiget_mac_addr_mask(char *p, u_char *addr, u_char *mask) 251198943Sluigi{ 251298943Sluigi int i, l; 251398943Sluigi 251498943Sluigi for (i=0; i<6; i++) 251598943Sluigi addr[i] = mask[i] = 0; 251698943Sluigi if (!strcmp(p, "any")) 251798943Sluigi return; 251898943Sluigi 251998943Sluigi for (i=0; *p && i<6;i++, p++) { 252098943Sluigi addr[i] = strtol(p, &p, 16); 252198943Sluigi if (*p != ':') /* we start with the mask */ 252298943Sluigi break; 252398943Sluigi } 252498943Sluigi if (*p == '/') { /* mask len */ 252598943Sluigi l = strtol(p+1, &p, 0); 252698943Sluigi for (i=0; l>0; l -=8, i++) 252798943Sluigi mask[i] = (l >=8) ? 0xff : (~0) << (8-l); 252898943Sluigi } else if (*p == '&') { /* mask */ 252998943Sluigi for (i=0, p++; *p && i<6;i++, p++) { 253098943Sluigi mask[i] = strtol(p, &p, 16); 253198943Sluigi if (*p != ':') 253298943Sluigi break; 253398943Sluigi } 253498943Sluigi } else if (*p == '\0') { 253598943Sluigi for (i=0; i<6; i++) 253698943Sluigi mask[i] = 0xff; 253798943Sluigi } 253898943Sluigi for (i=0; i<6; i++) 253998943Sluigi addr[i] &= mask[i]; 254098943Sluigi} 254198943Sluigi 254298943Sluigi/* 254398943Sluigi * helper function, updates the pointer to cmd with the length 254498943Sluigi * of the current command, and also cleans up the first word of 254598943Sluigi * the new command in case it has been clobbered before. 254698943Sluigi */ 254798943Sluigistatic ipfw_insn * 254898943Sluiginext_cmd(ipfw_insn *cmd) 254998943Sluigi{ 255098943Sluigi cmd += F_LEN(cmd); 255198943Sluigi bzero(cmd, sizeof(*cmd)); 255298943Sluigi return cmd; 255398943Sluigi} 255498943Sluigi 255598943Sluigi/* 2556117469Sluigi * Takes arguments and copies them into a comment 2557117469Sluigi */ 2558117469Sluigistatic void 2559117469Sluigifill_comment(ipfw_insn *cmd, int ac, char **av) 2560117469Sluigi{ 2561117469Sluigi int i, l; 2562117469Sluigi char *p = (char *)(cmd + 1); 2563117469Sluigi 2564117469Sluigi cmd->opcode = O_NOP; 2565117469Sluigi cmd->len = (cmd->len & (F_NOT | F_OR)); 2566117469Sluigi 2567117469Sluigi /* Compute length of comment string. */ 2568117469Sluigi for (i = 0, l = 0; i < ac; i++) 2569117469Sluigi l += strlen(av[i]) + 1; 2570117469Sluigi if (l == 0) 2571117469Sluigi return; 2572117469Sluigi if (l > 84) 2573117469Sluigi errx(EX_DATAERR, 2574117469Sluigi "comment too long (max 80 chars)"); 2575117469Sluigi l = 1 + (l+3)/4; 2576117469Sluigi cmd->len = (cmd->len & (F_NOT | F_OR)) | l; 2577117469Sluigi for (i = 0; i < ac; i++) { 2578117469Sluigi strcpy(p, av[i]); 2579117469Sluigi p += strlen(av[i]); 2580117469Sluigi *p++ = ' '; 2581117469Sluigi } 2582117469Sluigi *(--p) = '\0'; 2583117469Sluigi} 2584117469Sluigi 2585117469Sluigi/* 258698943Sluigi * A function to fill simple commands of size 1. 258798943Sluigi * Existing flags are preserved. 258898943Sluigi */ 258998943Sluigistatic void 2590117328Sluigifill_cmd(ipfw_insn *cmd, enum ipfw_opcodes opcode, int flags, uint16_t arg) 259198943Sluigi{ 259298943Sluigi cmd->opcode = opcode; 259398943Sluigi cmd->len = ((cmd->len | flags) & (F_NOT | F_OR)) | 1; 259498943Sluigi cmd->arg1 = arg; 259598943Sluigi} 259698943Sluigi 259798943Sluigi/* 259898943Sluigi * Fetch and add the MAC address and type, with masks. This generates one or 259998943Sluigi * two microinstructions, and returns the pointer to the last one. 260098943Sluigi */ 260198943Sluigistatic ipfw_insn * 260298943Sluigiadd_mac(ipfw_insn *cmd, int ac, char *av[]) 260398943Sluigi{ 2604102087Sluigi ipfw_insn_mac *mac; 260598943Sluigi 2606102087Sluigi if (ac < 2) 2607102098Sluigi errx(EX_DATAERR, "MAC dst src"); 260898943Sluigi 260998943Sluigi cmd->opcode = O_MACADDR2; 261098943Sluigi cmd->len = (cmd->len & (F_NOT | F_OR)) | F_INSN_SIZE(ipfw_insn_mac); 261198943Sluigi 261298943Sluigi mac = (ipfw_insn_mac *)cmd; 2613101978Sluigi get_mac_addr_mask(av[0], mac->addr, mac->mask); /* dst */ 261498943Sluigi get_mac_addr_mask(av[1], &(mac->addr[6]), &(mac->mask[6])); /* src */ 2615102087Sluigi return cmd; 2616102087Sluigi} 261798943Sluigi 2618102087Sluigistatic ipfw_insn * 2619102087Sluigiadd_mactype(ipfw_insn *cmd, int ac, char *av) 2620102087Sluigi{ 2621102087Sluigi if (ac < 1) 2622102087Sluigi errx(EX_DATAERR, "missing MAC type"); 2623102087Sluigi if (strcmp(av, "any") != 0) { /* we have a non-null type */ 2624102087Sluigi fill_newports((ipfw_insn_u16 *)cmd, av, IPPROTO_ETHERTYPE); 262598943Sluigi cmd->opcode = O_MAC_TYPE; 2626102087Sluigi return cmd; 2627102087Sluigi } else 2628102087Sluigi return NULL; 2629102087Sluigi} 263098943Sluigi 2631102087Sluigistatic ipfw_insn * 2632102087Sluigiadd_proto(ipfw_insn *cmd, char *av) 2633102087Sluigi{ 2634102087Sluigi struct protoent *pe; 2635102087Sluigi u_char proto = 0; 2636102087Sluigi 2637102087Sluigi if (!strncmp(av, "all", strlen(av))) 2638102087Sluigi ; /* same as "ip" */ 2639102087Sluigi else if ((proto = atoi(av)) > 0) 2640102087Sluigi ; /* all done! */ 2641102087Sluigi else if ((pe = getprotobyname(av)) != NULL) 2642102087Sluigi proto = pe->p_proto; 2643102087Sluigi else 2644102098Sluigi return NULL; 2645102087Sluigi if (proto != IPPROTO_IP) 2646102087Sluigi fill_cmd(cmd, O_PROTO, 0, proto); 264798943Sluigi return cmd; 264898943Sluigi} 264998943Sluigi 2650102087Sluigistatic ipfw_insn * 2651102087Sluigiadd_srcip(ipfw_insn *cmd, char *av) 2652102087Sluigi{ 2653102087Sluigi fill_ip((ipfw_insn_ip *)cmd, av); 2654102087Sluigi if (cmd->opcode == O_IP_DST_SET) /* set */ 2655102087Sluigi cmd->opcode = O_IP_SRC_SET; 2656102087Sluigi else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) /* me */ 2657102087Sluigi cmd->opcode = O_IP_SRC_ME; 2658102087Sluigi else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn_u32)) /* one IP */ 2659102087Sluigi cmd->opcode = O_IP_SRC; 2660117328Sluigi else /* addr/mask */ 2661102087Sluigi cmd->opcode = O_IP_SRC_MASK; 2662102087Sluigi return cmd; 2663102087Sluigi} 2664102087Sluigi 2665102087Sluigistatic ipfw_insn * 2666102087Sluigiadd_dstip(ipfw_insn *cmd, char *av) 2667102087Sluigi{ 2668102087Sluigi fill_ip((ipfw_insn_ip *)cmd, av); 2669102087Sluigi if (cmd->opcode == O_IP_DST_SET) /* set */ 2670102087Sluigi ; 2671102087Sluigi else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) /* me */ 2672102087Sluigi cmd->opcode = O_IP_DST_ME; 2673102087Sluigi else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn_u32)) /* one IP */ 2674102087Sluigi cmd->opcode = O_IP_DST; 2675117328Sluigi else /* addr/mask */ 2676102087Sluigi cmd->opcode = O_IP_DST_MASK; 2677102087Sluigi return cmd; 2678102087Sluigi} 2679102087Sluigi 2680102087Sluigistatic ipfw_insn * 2681102087Sluigiadd_ports(ipfw_insn *cmd, char *av, u_char proto, int opcode) 2682102087Sluigi{ 2683102087Sluigi if (!strncmp(av, "any", strlen(av))) { 2684102087Sluigi return NULL; 2685102087Sluigi } else if (fill_newports((ipfw_insn_u16 *)cmd, av, proto)) { 2686102087Sluigi /* XXX todo: check that we have a protocol with ports */ 2687102087Sluigi cmd->opcode = opcode; 2688102087Sluigi return cmd; 2689102087Sluigi } 2690102087Sluigi return NULL; 2691102087Sluigi} 2692102087Sluigi 269398943Sluigi/* 269498943Sluigi * Parse arguments and assemble the microinstructions which make up a rule. 269598943Sluigi * Rules are added into the 'rulebuf' and then copied in the correct order 269698943Sluigi * into the actual rule. 269798943Sluigi * 269898943Sluigi * The syntax for a rule starts with the action, followed by an 269998943Sluigi * optional log action, and the various match patterns. 2700108533Sschweikh * In the assembled microcode, the first opcode must be an O_PROBE_STATE 270198943Sluigi * (generated if the rule includes a keep-state option), then the 270298943Sluigi * various match patterns, the "log" action, and the actual action. 2703106505Smaxim * 270498943Sluigi */ 270598943Sluigistatic void 270698943Sluigiadd(int ac, char *av[]) 270798943Sluigi{ 270898943Sluigi /* 270998943Sluigi * rules are added into the 'rulebuf' and then copied in 271098943Sluigi * the correct order into the actual rule. 271198943Sluigi * Some things that need to go out of order (prob, action etc.) 271298943Sluigi * go into actbuf[]. 271398943Sluigi */ 2714117328Sluigi static uint32_t rulebuf[255], actbuf[255], cmdbuf[255]; 271598943Sluigi 2716117469Sluigi ipfw_insn *src, *dst, *cmd, *action, *prev=NULL; 2717102087Sluigi ipfw_insn *first_cmd; /* first match pattern */ 271898943Sluigi 271998943Sluigi struct ip_fw *rule; 272098943Sluigi 272198943Sluigi /* 272298943Sluigi * various flags used to record that we entered some fields. 272398943Sluigi */ 2724101116Sluigi ipfw_insn *have_state = NULL; /* check-state or keep-state */ 272598943Sluigi 272698943Sluigi int i; 272798943Sluigi 272898943Sluigi int open_par = 0; /* open parenthesis ( */ 272998943Sluigi 273098943Sluigi /* proto is here because it is used to fetch ports */ 273198943Sluigi u_char proto = IPPROTO_IP; /* default protocol */ 273298943Sluigi 2733107289Sluigi double match_prob = 1; /* match probability, default is always match */ 2734107289Sluigi 273598943Sluigi bzero(actbuf, sizeof(actbuf)); /* actions go here */ 273698943Sluigi bzero(cmdbuf, sizeof(cmdbuf)); 273798943Sluigi bzero(rulebuf, sizeof(rulebuf)); 273898943Sluigi 273998943Sluigi rule = (struct ip_fw *)rulebuf; 274098943Sluigi cmd = (ipfw_insn *)cmdbuf; 274198943Sluigi action = (ipfw_insn *)actbuf; 274298943Sluigi 274398943Sluigi av++; ac--; 274498943Sluigi 274598943Sluigi /* [rule N] -- Rule number optional */ 274698943Sluigi if (ac && isdigit(**av)) { 274798943Sluigi rule->rulenum = atoi(*av); 274898943Sluigi av++; 274998943Sluigi ac--; 275098943Sluigi } 275198943Sluigi 2752101628Sluigi /* [set N] -- set number (0..30), optional */ 2753101628Sluigi if (ac > 1 && !strncmp(*av, "set", strlen(*av))) { 2754101628Sluigi int set = strtoul(av[1], NULL, 10); 2755101628Sluigi if (set < 0 || set > 30) 2756101628Sluigi errx(EX_DATAERR, "illegal set %s", av[1]); 2757101628Sluigi rule->set = set; 2758101628Sluigi av += 2; ac -= 2; 2759101628Sluigi } 2760101628Sluigi 276198943Sluigi /* [prob D] -- match probability, optional */ 276298943Sluigi if (ac > 1 && !strncmp(*av, "prob", strlen(*av))) { 2763107289Sluigi match_prob = strtod(av[1], NULL); 276498943Sluigi 2765107289Sluigi if (match_prob <= 0 || match_prob > 1) 276698943Sluigi errx(EX_DATAERR, "illegal match prob. %s", av[1]); 276798943Sluigi av += 2; ac -= 2; 276898943Sluigi } 276998943Sluigi 277098943Sluigi /* action -- mandatory */ 277198943Sluigi NEED1("missing action"); 277298943Sluigi i = match_token(rule_actions, *av); 277398943Sluigi ac--; av++; 277498943Sluigi action->len = 1; /* default */ 277598943Sluigi switch(i) { 277698943Sluigi case TOK_CHECKSTATE: 2777101116Sluigi have_state = action; 277898943Sluigi action->opcode = O_CHECK_STATE; 277998943Sluigi break; 278098943Sluigi 278198943Sluigi case TOK_ACCEPT: 278298943Sluigi action->opcode = O_ACCEPT; 278398943Sluigi break; 278498943Sluigi 278598943Sluigi case TOK_DENY: 278698943Sluigi action->opcode = O_DENY; 278799475Sluigi action->arg1 = 0; 278898943Sluigi break; 278998943Sluigi 279099475Sluigi case TOK_REJECT: 279199475Sluigi action->opcode = O_REJECT; 279299475Sluigi action->arg1 = ICMP_UNREACH_HOST; 279399475Sluigi break; 279499475Sluigi 279599475Sluigi case TOK_RESET: 279699475Sluigi action->opcode = O_REJECT; 279799475Sluigi action->arg1 = ICMP_REJECT_RST; 279899475Sluigi break; 279999475Sluigi 280099475Sluigi case TOK_UNREACH: 280199475Sluigi action->opcode = O_REJECT; 280299475Sluigi NEED1("missing reject code"); 280399475Sluigi fill_reject_code(&action->arg1, *av); 280499475Sluigi ac--; av++; 280599475Sluigi break; 280699475Sluigi 280798943Sluigi case TOK_COUNT: 280898943Sluigi action->opcode = O_COUNT; 280998943Sluigi break; 281098943Sluigi 281198943Sluigi case TOK_QUEUE: 281298943Sluigi case TOK_PIPE: 281398943Sluigi action->len = F_INSN_SIZE(ipfw_insn_pipe); 281498943Sluigi case TOK_SKIPTO: 281598943Sluigi if (i == TOK_QUEUE) 281698943Sluigi action->opcode = O_QUEUE; 281798943Sluigi else if (i == TOK_PIPE) 281898943Sluigi action->opcode = O_PIPE; 281998943Sluigi else if (i == TOK_SKIPTO) 282098943Sluigi action->opcode = O_SKIPTO; 282198943Sluigi NEED1("missing skipto/pipe/queue number"); 282298943Sluigi action->arg1 = strtoul(*av, NULL, 10); 282398943Sluigi av++; ac--; 282498943Sluigi break; 282598943Sluigi 282698943Sluigi case TOK_DIVERT: 282798943Sluigi case TOK_TEE: 282898943Sluigi action->opcode = (i == TOK_DIVERT) ? O_DIVERT : O_TEE; 282998943Sluigi NEED1("missing divert/tee port"); 283098943Sluigi action->arg1 = strtoul(*av, NULL, 0); 283198943Sluigi if (action->arg1 == 0) { 283298943Sluigi struct servent *s; 283398943Sluigi setservent(1); 283498943Sluigi s = getservbyname(av[0], "divert"); 283598943Sluigi if (s != NULL) 283698943Sluigi action->arg1 = ntohs(s->s_port); 283798943Sluigi else 283898943Sluigi errx(EX_DATAERR, "illegal divert/tee port"); 283998943Sluigi } 284098943Sluigi ac--; av++; 284198943Sluigi break; 284298943Sluigi 284398943Sluigi case TOK_FORWARD: { 284498943Sluigi ipfw_insn_sa *p = (ipfw_insn_sa *)action; 284598943Sluigi char *s, *end; 284698943Sluigi 284798943Sluigi NEED1("missing forward address[:port]"); 284898943Sluigi 284998943Sluigi action->opcode = O_FORWARD_IP; 285098943Sluigi action->len = F_INSN_SIZE(ipfw_insn_sa); 285198943Sluigi 285298943Sluigi p->sa.sin_len = sizeof(struct sockaddr_in); 285398943Sluigi p->sa.sin_family = AF_INET; 285498943Sluigi p->sa.sin_port = 0; 285598943Sluigi /* 285698943Sluigi * locate the address-port separator (':' or ',') 285798943Sluigi */ 285898943Sluigi s = strchr(*av, ':'); 285998943Sluigi if (s == NULL) 286098943Sluigi s = strchr(*av, ','); 286198943Sluigi if (s != NULL) { 286298943Sluigi *(s++) = '\0'; 286398943Sluigi i = strtoport(s, &end, 0 /* base */, 0 /* proto */); 286498943Sluigi if (s == end) 286598943Sluigi errx(EX_DATAERR, 286698943Sluigi "illegal forwarding port ``%s''", s); 2867103241Sluigi p->sa.sin_port = (u_short)i; 286898943Sluigi } 286998943Sluigi lookup_host(*av, &(p->sa.sin_addr)); 287098943Sluigi } 287198943Sluigi ac--; av++; 287298943Sluigi break; 287398943Sluigi 2874117469Sluigi case TOK_COMMENT: 2875117469Sluigi /* pretend it is a 'count' rule followed by the comment */ 2876117469Sluigi action->opcode = O_COUNT; 2877117469Sluigi ac++; av--; /* go back... */ 2878117469Sluigi break; 2879117469Sluigi 288098943Sluigi default: 2881102087Sluigi errx(EX_DATAERR, "invalid action %s\n", av[-1]); 288298943Sluigi } 288398943Sluigi action = next_cmd(action); 288498943Sluigi 288598943Sluigi /* 288698943Sluigi * [log [logamount N]] -- log, optional 288798943Sluigi * 288898943Sluigi * If exists, it goes first in the cmdbuf, but then it is 288998943Sluigi * skipped in the copy section to the end of the buffer. 289098943Sluigi */ 289198943Sluigi if (ac && !strncmp(*av, "log", strlen(*av))) { 289298943Sluigi ipfw_insn_log *c = (ipfw_insn_log *)cmd; 2893117469Sluigi int l; 289498943Sluigi 289598943Sluigi cmd->len = F_INSN_SIZE(ipfw_insn_log); 289698943Sluigi cmd->opcode = O_LOG; 289798943Sluigi av++; ac--; 289898943Sluigi if (ac && !strncmp(*av, "logamount", strlen(*av))) { 289998943Sluigi ac--; av++; 290098943Sluigi NEED1("logamount requires argument"); 2901117469Sluigi l = atoi(*av); 2902117469Sluigi if (l < 0) 290398943Sluigi errx(EX_DATAERR, "logamount must be positive"); 2904117469Sluigi c->max_log = l; 290598943Sluigi ac--; av++; 290698943Sluigi } 290798943Sluigi cmd = next_cmd(cmd); 290898943Sluigi } 290998943Sluigi 2910101116Sluigi if (have_state) /* must be a check-state, we are done */ 291198943Sluigi goto done; 291298943Sluigi 291398943Sluigi#define OR_START(target) \ 291498943Sluigi if (ac && (*av[0] == '(' || *av[0] == '{')) { \ 291598943Sluigi if (open_par) \ 291698943Sluigi errx(EX_USAGE, "nested \"(\" not allowed\n"); \ 2917101641Sluigi prev = NULL; \ 291898943Sluigi open_par = 1; \ 291998943Sluigi if ( (av[0])[1] == '\0') { \ 292098943Sluigi ac--; av++; \ 292198943Sluigi } else \ 292298943Sluigi (*av)++; \ 292398943Sluigi } \ 292498943Sluigi target: \ 292598943Sluigi 292698943Sluigi 292798943Sluigi#define CLOSE_PAR \ 292898943Sluigi if (open_par) { \ 292998943Sluigi if (ac && ( \ 293098943Sluigi !strncmp(*av, ")", strlen(*av)) || \ 293198943Sluigi !strncmp(*av, "}", strlen(*av)) )) { \ 2932101641Sluigi prev = NULL; \ 293398943Sluigi open_par = 0; \ 293498943Sluigi ac--; av++; \ 293598943Sluigi } else \ 293698943Sluigi errx(EX_USAGE, "missing \")\"\n"); \ 293798943Sluigi } 2938106505Smaxim 293998943Sluigi#define NOT_BLOCK \ 294098943Sluigi if (ac && !strncmp(*av, "not", strlen(*av))) { \ 294198943Sluigi if (cmd->len & F_NOT) \ 294298943Sluigi errx(EX_USAGE, "double \"not\" not allowed\n"); \ 294398943Sluigi cmd->len |= F_NOT; \ 294498943Sluigi ac--; av++; \ 294598943Sluigi } 294698943Sluigi 294798943Sluigi#define OR_BLOCK(target) \ 294898943Sluigi if (ac && !strncmp(*av, "or", strlen(*av))) { \ 294998943Sluigi if (prev == NULL || open_par == 0) \ 295098943Sluigi errx(EX_DATAERR, "invalid OR block"); \ 295198943Sluigi prev->len |= F_OR; \ 295298943Sluigi ac--; av++; \ 295398943Sluigi goto target; \ 295498943Sluigi } \ 295598943Sluigi CLOSE_PAR; 295698943Sluigi 2957102087Sluigi first_cmd = cmd; 2958102098Sluigi 2959102098Sluigi#if 0 296098943Sluigi /* 2961102087Sluigi * MAC addresses, optional. 2962102087Sluigi * If we have this, we skip the part "proto from src to dst" 2963102087Sluigi * and jump straight to the option parsing. 2964102087Sluigi */ 2965102087Sluigi NOT_BLOCK; 2966102087Sluigi NEED1("missing protocol"); 2967102087Sluigi if (!strncmp(*av, "MAC", strlen(*av)) || 2968102087Sluigi !strncmp(*av, "mac", strlen(*av))) { 2969102087Sluigi ac--; av++; /* the "MAC" keyword */ 2970102087Sluigi add_mac(cmd, ac, av); /* exits in case of errors */ 2971102087Sluigi cmd = next_cmd(cmd); 2972102087Sluigi ac -= 2; av += 2; /* dst-mac and src-mac */ 2973102087Sluigi NOT_BLOCK; 2974102087Sluigi NEED1("missing mac type"); 2975102087Sluigi if (add_mactype(cmd, ac, av[0])) 2976102087Sluigi cmd = next_cmd(cmd); 2977102087Sluigi ac--; av++; /* any or mac-type */ 2978102087Sluigi goto read_options; 2979102087Sluigi } 2980102098Sluigi#endif 2981102087Sluigi 2982102087Sluigi /* 298398943Sluigi * protocol, mandatory 298498943Sluigi */ 298598943Sluigi OR_START(get_proto); 298698943Sluigi NOT_BLOCK; 298798943Sluigi NEED1("missing protocol"); 2988102087Sluigi if (add_proto(cmd, *av)) { 2989102087Sluigi av++; ac--; 2990102087Sluigi if (F_LEN(cmd) == 0) /* plain IP */ 2991102087Sluigi proto = 0; 2992102087Sluigi else { 2993102087Sluigi proto = cmd->arg1; 2994102087Sluigi prev = cmd; 2995102087Sluigi cmd = next_cmd(cmd); 2996102087Sluigi } 2997102098Sluigi } else if (first_cmd != cmd) { 2998116438Smaxim errx(EX_DATAERR, "invalid protocol ``%s''", *av); 2999102098Sluigi } else 3000102098Sluigi goto read_options; 300198943Sluigi OR_BLOCK(get_proto); 300298943Sluigi 300398943Sluigi /* 3004102087Sluigi * "from", mandatory 300598943Sluigi */ 3006102087Sluigi if (!ac || strncmp(*av, "from", strlen(*av))) 300798943Sluigi errx(EX_USAGE, "missing ``from''"); 300898943Sluigi ac--; av++; 300998943Sluigi 301098943Sluigi /* 301198943Sluigi * source IP, mandatory 301298943Sluigi */ 301398943Sluigi OR_START(source_ip); 301498943Sluigi NOT_BLOCK; /* optional "not" */ 301598943Sluigi NEED1("missing source address"); 3016102087Sluigi if (add_srcip(cmd, *av)) { 3017102087Sluigi ac--; av++; 3018102087Sluigi if (F_LEN(cmd) != 0) { /* ! any */ 3019102087Sluigi prev = cmd; 3020102087Sluigi cmd = next_cmd(cmd); 3021102087Sluigi } 3022102087Sluigi } 302398943Sluigi OR_BLOCK(source_ip); 302498943Sluigi 302598943Sluigi /* 302698943Sluigi * source ports, optional 302798943Sluigi */ 302898943Sluigi NOT_BLOCK; /* optional "not" */ 3029101641Sluigi if (ac) { 3030102087Sluigi if (!strncmp(*av, "any", strlen(*av)) || 3031102087Sluigi add_ports(cmd, *av, proto, O_IP_SRCPORT)) { 3032102087Sluigi ac--; av++; 3033102087Sluigi if (F_LEN(cmd) != 0) 3034102087Sluigi cmd = next_cmd(cmd); 3035101641Sluigi } 303698943Sluigi } 303798943Sluigi 303898943Sluigi /* 3039102087Sluigi * "to", mandatory 304098943Sluigi */ 3041102087Sluigi if (!ac || strncmp(*av, "to", strlen(*av))) 304298943Sluigi errx(EX_USAGE, "missing ``to''"); 304398943Sluigi av++; ac--; 304498943Sluigi 304598943Sluigi /* 304698943Sluigi * destination, mandatory 304798943Sluigi */ 304898943Sluigi OR_START(dest_ip); 304998943Sluigi NOT_BLOCK; /* optional "not" */ 305098943Sluigi NEED1("missing dst address"); 3051102087Sluigi if (add_dstip(cmd, *av)) { 3052102087Sluigi ac--; av++; 3053102087Sluigi if (F_LEN(cmd) != 0) { /* ! any */ 3054102087Sluigi prev = cmd; 3055102087Sluigi cmd = next_cmd(cmd); 3056102087Sluigi } 3057102087Sluigi } 305898943Sluigi OR_BLOCK(dest_ip); 305998943Sluigi 306098943Sluigi /* 306198943Sluigi * dest. ports, optional 306298943Sluigi */ 306398943Sluigi NOT_BLOCK; /* optional "not" */ 3064101641Sluigi if (ac) { 3065102087Sluigi if (!strncmp(*av, "any", strlen(*av)) || 3066102087Sluigi add_ports(cmd, *av, proto, O_IP_DSTPORT)) { 3067102087Sluigi ac--; av++; 3068102087Sluigi if (F_LEN(cmd) != 0) 3069102087Sluigi cmd = next_cmd(cmd); 3070101641Sluigi } 307198943Sluigi } 307298943Sluigi 307398943Sluigiread_options: 3074102087Sluigi if (ac && first_cmd == cmd) { 3075102087Sluigi /* 3076102087Sluigi * nothing specified so far, store in the rule to ease 3077102087Sluigi * printout later. 3078102087Sluigi */ 3079102087Sluigi rule->_pad = 1; 3080102087Sluigi } 308198943Sluigi prev = NULL; 308298943Sluigi while (ac) { 3083101641Sluigi char *s; 3084101641Sluigi ipfw_insn_u32 *cmd32; /* alias for cmd */ 308598943Sluigi 3086101641Sluigi s = *av; 3087101641Sluigi cmd32 = (ipfw_insn_u32 *)cmd; 3088101641Sluigi 308998943Sluigi if (*s == '!') { /* alternate syntax for NOT */ 309098943Sluigi if (cmd->len & F_NOT) 309198943Sluigi errx(EX_USAGE, "double \"not\" not allowed\n"); 309298943Sluigi cmd->len = F_NOT; 309398943Sluigi s++; 309498943Sluigi } 309598943Sluigi i = match_token(rule_options, s); 309698943Sluigi ac--; av++; 309798943Sluigi switch(i) { 309898943Sluigi case TOK_NOT: 309998943Sluigi if (cmd->len & F_NOT) 310098943Sluigi errx(EX_USAGE, "double \"not\" not allowed\n"); 310198943Sluigi cmd->len = F_NOT; 310298943Sluigi break; 310398943Sluigi 310498943Sluigi case TOK_OR: 3105101641Sluigi if (open_par == 0 || prev == NULL) 310698943Sluigi errx(EX_USAGE, "invalid \"or\" block\n"); 310798943Sluigi prev->len |= F_OR; 310898943Sluigi break; 3109101641Sluigi 3110101641Sluigi case TOK_STARTBRACE: 3111101641Sluigi if (open_par) 3112101641Sluigi errx(EX_USAGE, "+nested \"(\" not allowed\n"); 3113101641Sluigi open_par = 1; 3114101641Sluigi break; 3115101641Sluigi 3116101641Sluigi case TOK_ENDBRACE: 3117101641Sluigi if (!open_par) 3118101641Sluigi errx(EX_USAGE, "+missing \")\"\n"); 3119101641Sluigi open_par = 0; 3120102087Sluigi prev = NULL; 3121101641Sluigi break; 3122101641Sluigi 312398943Sluigi case TOK_IN: 312498943Sluigi fill_cmd(cmd, O_IN, 0, 0); 312598943Sluigi break; 312698943Sluigi 312798943Sluigi case TOK_OUT: 312898943Sluigi cmd->len ^= F_NOT; /* toggle F_NOT */ 312998943Sluigi fill_cmd(cmd, O_IN, 0, 0); 313098943Sluigi break; 313198943Sluigi 313298943Sluigi case TOK_FRAG: 313398943Sluigi fill_cmd(cmd, O_FRAG, 0, 0); 313498943Sluigi break; 313598943Sluigi 313698943Sluigi case TOK_LAYER2: 313798943Sluigi fill_cmd(cmd, O_LAYER2, 0, 0); 313898943Sluigi break; 313998943Sluigi 314098943Sluigi case TOK_XMIT: 314198943Sluigi case TOK_RECV: 314298943Sluigi case TOK_VIA: 314398943Sluigi NEED1("recv, xmit, via require interface name" 314498943Sluigi " or address"); 314598943Sluigi fill_iface((ipfw_insn_if *)cmd, av[0]); 314698943Sluigi ac--; av++; 314798943Sluigi if (F_LEN(cmd) == 0) /* not a valid address */ 314898943Sluigi break; 314998943Sluigi if (i == TOK_XMIT) 315098943Sluigi cmd->opcode = O_XMIT; 315198943Sluigi else if (i == TOK_RECV) 315298943Sluigi cmd->opcode = O_RECV; 315398943Sluigi else if (i == TOK_VIA) 315498943Sluigi cmd->opcode = O_VIA; 315598943Sluigi break; 315698943Sluigi 315799475Sluigi case TOK_ICMPTYPES: 315899475Sluigi NEED1("icmptypes requires list of types"); 315999475Sluigi fill_icmptypes((ipfw_insn_u32 *)cmd, *av); 316099475Sluigi av++; ac--; 316199475Sluigi break; 316299475Sluigi 316398943Sluigi case TOK_IPTTL: 316498943Sluigi NEED1("ipttl requires TTL"); 3165116690Sluigi if (strpbrk(*av, "-,")) { 3166116690Sluigi if (!add_ports(cmd, *av, 0, O_IPTTL)) 3167116690Sluigi errx(EX_DATAERR, "invalid ipttl %s", *av); 3168116690Sluigi } else 3169116690Sluigi fill_cmd(cmd, O_IPTTL, 0, strtoul(*av, NULL, 0)); 317098943Sluigi ac--; av++; 317198943Sluigi break; 317298943Sluigi 317398943Sluigi case TOK_IPID: 3174116690Sluigi NEED1("ipid requires id"); 3175116690Sluigi if (strpbrk(*av, "-,")) { 3176116690Sluigi if (!add_ports(cmd, *av, 0, O_IPID)) 3177116690Sluigi errx(EX_DATAERR, "invalid ipid %s", *av); 3178116690Sluigi } else 3179116690Sluigi fill_cmd(cmd, O_IPID, 0, strtoul(*av, NULL, 0)); 318098943Sluigi ac--; av++; 318198943Sluigi break; 318298943Sluigi 318398943Sluigi case TOK_IPLEN: 318498943Sluigi NEED1("iplen requires length"); 3185116690Sluigi if (strpbrk(*av, "-,")) { 3186116690Sluigi if (!add_ports(cmd, *av, 0, O_IPLEN)) 3187116690Sluigi errx(EX_DATAERR, "invalid ip len %s", *av); 3188116690Sluigi } else 3189116690Sluigi fill_cmd(cmd, O_IPLEN, 0, strtoul(*av, NULL, 0)); 319098943Sluigi ac--; av++; 319198943Sluigi break; 319298943Sluigi 319398943Sluigi case TOK_IPVER: 319498943Sluigi NEED1("ipver requires version"); 319598943Sluigi fill_cmd(cmd, O_IPVER, 0, strtoul(*av, NULL, 0)); 319698943Sluigi ac--; av++; 319798943Sluigi break; 319898943Sluigi 319999475Sluigi case TOK_IPPRECEDENCE: 320099475Sluigi NEED1("ipprecedence requires value"); 320199475Sluigi fill_cmd(cmd, O_IPPRECEDENCE, 0, 320299475Sluigi (strtoul(*av, NULL, 0) & 7) << 5); 320399475Sluigi ac--; av++; 320499475Sluigi break; 320599475Sluigi 320698943Sluigi case TOK_IPOPTS: 320798943Sluigi NEED1("missing argument for ipoptions"); 3208101116Sluigi fill_flags(cmd, O_IPOPT, f_ipopts, *av); 320998943Sluigi ac--; av++; 321098943Sluigi break; 321198943Sluigi 321299475Sluigi case TOK_IPTOS: 321399475Sluigi NEED1("missing argument for iptos"); 3214101116Sluigi fill_flags(cmd, O_IPTOS, f_iptos, *av); 321599475Sluigi ac--; av++; 321699475Sluigi break; 321799475Sluigi 321898943Sluigi case TOK_UID: 321998943Sluigi NEED1("uid requires argument"); 322098943Sluigi { 322198943Sluigi char *end; 322298943Sluigi uid_t uid; 322398943Sluigi struct passwd *pwd; 322498943Sluigi 322598943Sluigi cmd->opcode = O_UID; 322698943Sluigi uid = strtoul(*av, &end, 0); 322798943Sluigi pwd = (*end == '\0') ? getpwuid(uid) : getpwnam(*av); 322898943Sluigi if (pwd == NULL) 322998943Sluigi errx(EX_DATAERR, "uid \"%s\" nonexistent", *av); 3230106504Smaxim cmd32->d[0] = pwd->pw_uid; 323198943Sluigi cmd->len = F_INSN_SIZE(ipfw_insn_u32); 323298943Sluigi ac--; av++; 323398943Sluigi } 323498943Sluigi break; 323598943Sluigi 323698943Sluigi case TOK_GID: 323798943Sluigi NEED1("gid requires argument"); 323898943Sluigi { 323998943Sluigi char *end; 324098943Sluigi gid_t gid; 324198943Sluigi struct group *grp; 324298943Sluigi 324398943Sluigi cmd->opcode = O_GID; 324498943Sluigi gid = strtoul(*av, &end, 0); 324598943Sluigi grp = (*end == '\0') ? getgrgid(gid) : getgrnam(*av); 324698943Sluigi if (grp == NULL) 324798943Sluigi errx(EX_DATAERR, "gid \"%s\" nonexistent", *av); 3248106504Smaxim cmd32->d[0] = grp->gr_gid; 324998943Sluigi cmd->len = F_INSN_SIZE(ipfw_insn_u32); 325098943Sluigi ac--; av++; 325198943Sluigi } 325298943Sluigi break; 325398943Sluigi 325498943Sluigi case TOK_ESTAB: 325598943Sluigi fill_cmd(cmd, O_ESTAB, 0, 0); 325698943Sluigi break; 325798943Sluigi 325898943Sluigi case TOK_SETUP: 325998943Sluigi fill_cmd(cmd, O_TCPFLAGS, 0, 326098943Sluigi (TH_SYN) | ( (TH_ACK) & 0xff) <<8 ); 326198943Sluigi break; 326298943Sluigi 326398943Sluigi case TOK_TCPOPTS: 326498943Sluigi NEED1("missing argument for tcpoptions"); 326598943Sluigi fill_flags(cmd, O_TCPOPTS, f_tcpopts, *av); 326698943Sluigi ac--; av++; 326798943Sluigi break; 326898943Sluigi 326998943Sluigi case TOK_TCPSEQ: 327098943Sluigi case TOK_TCPACK: 327198943Sluigi NEED1("tcpseq/tcpack requires argument"); 327298943Sluigi cmd->len = F_INSN_SIZE(ipfw_insn_u32); 327398943Sluigi cmd->opcode = (i == TOK_TCPSEQ) ? O_TCPSEQ : O_TCPACK; 327498943Sluigi cmd32->d[0] = htonl(strtoul(*av, NULL, 0)); 327598943Sluigi ac--; av++; 327698943Sluigi break; 327798943Sluigi 327898943Sluigi case TOK_TCPWIN: 327998943Sluigi NEED1("tcpwin requires length"); 328098943Sluigi fill_cmd(cmd, O_TCPWIN, 0, 328198943Sluigi htons(strtoul(*av, NULL, 0))); 328298943Sluigi ac--; av++; 328398943Sluigi break; 328498943Sluigi 328598943Sluigi case TOK_TCPFLAGS: 328698943Sluigi NEED1("missing argument for tcpflags"); 328798943Sluigi cmd->opcode = O_TCPFLAGS; 328898943Sluigi fill_flags(cmd, O_TCPFLAGS, f_tcpflags, *av); 328998943Sluigi ac--; av++; 329098943Sluigi break; 329198943Sluigi 329298943Sluigi case TOK_KEEPSTATE: 3293101641Sluigi if (open_par) 3294101641Sluigi errx(EX_USAGE, "keep-state cannot be part " 3295101641Sluigi "of an or block"); 329699909Sluigi if (have_state) 3297101116Sluigi errx(EX_USAGE, "only one of keep-state " 329899909Sluigi "and limit is allowed"); 3299101116Sluigi have_state = cmd; 330098943Sluigi fill_cmd(cmd, O_KEEP_STATE, 0, 0); 330198943Sluigi break; 330298943Sluigi 330398943Sluigi case TOK_LIMIT: 3304101641Sluigi if (open_par) 3305101641Sluigi errx(EX_USAGE, "limit cannot be part " 3306101641Sluigi "of an or block"); 330799909Sluigi if (have_state) 3308101116Sluigi errx(EX_USAGE, "only one of keep-state " 330999909Sluigi "and limit is allowed"); 3310101641Sluigi NEED1("limit needs mask and # of connections"); 3311101116Sluigi have_state = cmd; 331298943Sluigi { 331398943Sluigi ipfw_insn_limit *c = (ipfw_insn_limit *)cmd; 331498943Sluigi 331598943Sluigi cmd->len = F_INSN_SIZE(ipfw_insn_limit); 331698943Sluigi cmd->opcode = O_LIMIT; 331798943Sluigi c->limit_mask = 0; 331898943Sluigi c->conn_limit = 0; 331998943Sluigi for (; ac >1 ;) { 332098943Sluigi int val; 332198943Sluigi 332298943Sluigi val = match_token(limit_masks, *av); 332398943Sluigi if (val <= 0) 332498943Sluigi break; 332598943Sluigi c->limit_mask |= val; 332698943Sluigi ac--; av++; 332798943Sluigi } 332898943Sluigi c->conn_limit = atoi(*av); 332998943Sluigi if (c->conn_limit == 0) 333098943Sluigi errx(EX_USAGE, "limit: limit must be >0"); 333198943Sluigi if (c->limit_mask == 0) 333298943Sluigi errx(EX_USAGE, "missing limit mask"); 333398943Sluigi ac--; av++; 333498943Sluigi } 333598943Sluigi break; 333698943Sluigi 3337102087Sluigi case TOK_PROTO: 3338102087Sluigi NEED1("missing protocol"); 3339102087Sluigi if (add_proto(cmd, *av)) { 3340102087Sluigi proto = cmd->arg1; 3341102087Sluigi ac--; av++; 3342102098Sluigi } else 3343116438Smaxim errx(EX_DATAERR, "invalid protocol ``%s''", 3344116438Smaxim *av); 3345102087Sluigi break; 3346106505Smaxim 3347102087Sluigi case TOK_SRCIP: 3348102087Sluigi NEED1("missing source IP"); 3349102087Sluigi if (add_srcip(cmd, *av)) { 3350102087Sluigi ac--; av++; 3351102087Sluigi } 3352102087Sluigi break; 3353102087Sluigi 3354102087Sluigi case TOK_DSTIP: 3355102087Sluigi NEED1("missing destination IP"); 3356102087Sluigi if (add_dstip(cmd, *av)) { 3357102087Sluigi ac--; av++; 3358102087Sluigi } 3359102087Sluigi break; 3360102087Sluigi 3361102087Sluigi case TOK_SRCPORT: 3362102087Sluigi NEED1("missing source port"); 3363102087Sluigi if (!strncmp(*av, "any", strlen(*av)) || 3364102087Sluigi add_ports(cmd, *av, proto, O_IP_SRCPORT)) { 3365102087Sluigi ac--; av++; 3366102087Sluigi } else 3367102087Sluigi errx(EX_DATAERR, "invalid source port %s", *av); 3368102087Sluigi break; 3369102087Sluigi 3370102087Sluigi case TOK_DSTPORT: 3371102087Sluigi NEED1("missing destination port"); 3372102087Sluigi if (!strncmp(*av, "any", strlen(*av)) || 3373102087Sluigi add_ports(cmd, *av, proto, O_IP_DSTPORT)) { 3374102087Sluigi ac--; av++; 3375102087Sluigi } else 3376102087Sluigi errx(EX_DATAERR, "invalid destination port %s", 3377102087Sluigi *av); 3378102087Sluigi break; 3379102087Sluigi 3380102087Sluigi case TOK_MAC: 3381102087Sluigi if (ac < 2) 3382102087Sluigi errx(EX_USAGE, "MAC dst-mac src-mac"); 3383102087Sluigi if (add_mac(cmd, ac, av)) { 3384102087Sluigi ac -= 2; av += 2; 3385102087Sluigi } 3386102087Sluigi break; 3387102087Sluigi 3388102087Sluigi case TOK_MACTYPE: 3389102087Sluigi NEED1("missing mac type"); 3390102087Sluigi if (!add_mactype(cmd, ac, *av)) 3391116438Smaxim errx(EX_DATAERR, "invalid mac type %s", *av); 3392102087Sluigi ac--; av++; 3393102087Sluigi break; 3394102087Sluigi 3395112250Scjc case TOK_VERREVPATH: 3396112250Scjc fill_cmd(cmd, O_VERREVPATH, 0, 0); 3397112250Scjc break; 3398116919Sluigi 3399117241Sluigi case TOK_IPSEC: 3400117241Sluigi fill_cmd(cmd, O_IPSEC, 0, 0); 3401117241Sluigi break; 3402117241Sluigi 3403117469Sluigi case TOK_COMMENT: 3404117469Sluigi fill_comment(cmd, ac, av); 3405117469Sluigi av += ac; 3406117469Sluigi ac = 0; 3407117469Sluigi break; 3408117469Sluigi 340998943Sluigi default: 341098943Sluigi errx(EX_USAGE, "unrecognised option [%d] %s\n", i, s); 341198943Sluigi } 341298943Sluigi if (F_LEN(cmd) > 0) { /* prepare to advance */ 341398943Sluigi prev = cmd; 341498943Sluigi cmd = next_cmd(cmd); 341598943Sluigi } 341698943Sluigi } 341798943Sluigi 341898943Sluigidone: 341998943Sluigi /* 342098943Sluigi * Now copy stuff into the rule. 342198943Sluigi * If we have a keep-state option, the first instruction 342298943Sluigi * must be a PROBE_STATE (which is generated here). 342398943Sluigi * If we have a LOG option, it was stored as the first command, 342498943Sluigi * and now must be moved to the top of the action part. 342598943Sluigi */ 342698943Sluigi dst = (ipfw_insn *)rule->cmd; 342798943Sluigi 342898943Sluigi /* 3429107289Sluigi * First thing to write into the command stream is the match probability. 3430107289Sluigi */ 3431107289Sluigi if (match_prob != 1) { /* 1 means always match */ 3432107289Sluigi dst->opcode = O_PROB; 3433107289Sluigi dst->len = 2; 3434107289Sluigi *((int32_t *)(dst+1)) = (int32_t)(match_prob * 0x7fffffff); 3435107289Sluigi dst += dst->len; 3436107289Sluigi } 3437107289Sluigi 3438107289Sluigi /* 343998943Sluigi * generate O_PROBE_STATE if necessary 344098943Sluigi */ 3441101116Sluigi if (have_state && have_state->opcode != O_CHECK_STATE) { 344298943Sluigi fill_cmd(dst, O_PROBE_STATE, 0, 0); 344398943Sluigi dst = next_cmd(dst); 344498943Sluigi } 344598943Sluigi /* 3446101116Sluigi * copy all commands but O_LOG, O_KEEP_STATE, O_LIMIT 344798943Sluigi */ 344898943Sluigi for (src = (ipfw_insn *)cmdbuf; src != cmd; src += i) { 344998943Sluigi i = F_LEN(src); 345098943Sluigi 3451101116Sluigi switch (src->opcode) { 3452101116Sluigi case O_LOG: 3453101116Sluigi case O_KEEP_STATE: 3454101116Sluigi case O_LIMIT: 3455101116Sluigi break; 3456101116Sluigi default: 3457117328Sluigi bcopy(src, dst, i * sizeof(uint32_t)); 345898943Sluigi dst += i; 345998943Sluigi } 346098943Sluigi } 346198943Sluigi 346298943Sluigi /* 3463101116Sluigi * put back the have_state command as last opcode 3464101116Sluigi */ 3465101295Sluigi if (have_state && have_state->opcode != O_CHECK_STATE) { 3466101116Sluigi i = F_LEN(have_state); 3467117328Sluigi bcopy(have_state, dst, i * sizeof(uint32_t)); 3468101116Sluigi dst += i; 3469101116Sluigi } 3470101116Sluigi /* 347198943Sluigi * start action section 347298943Sluigi */ 347398943Sluigi rule->act_ofs = dst - rule->cmd; 347498943Sluigi 347598943Sluigi /* 347698943Sluigi * put back O_LOG if necessary 347798943Sluigi */ 347898943Sluigi src = (ipfw_insn *)cmdbuf; 347998943Sluigi if ( src->opcode == O_LOG ) { 348098943Sluigi i = F_LEN(src); 3481117328Sluigi bcopy(src, dst, i * sizeof(uint32_t)); 348298943Sluigi dst += i; 348398943Sluigi } 348498943Sluigi /* 348598943Sluigi * copy all other actions 348698943Sluigi */ 348798943Sluigi for (src = (ipfw_insn *)actbuf; src != action; src += i) { 348898943Sluigi i = F_LEN(src); 3489117328Sluigi bcopy(src, dst, i * sizeof(uint32_t)); 349098943Sluigi dst += i; 349198943Sluigi } 349298943Sluigi 3493117328Sluigi rule->cmd_len = (uint32_t *)dst - (uint32_t *)(rule->cmd); 3494117469Sluigi i = (char *)dst - (char *)rule; 3495117328Sluigi if (do_cmd(IP_FW_ADD, rule, (socklen_t)&i) == -1) 349698943Sluigi err(EX_UNAVAILABLE, "getsockopt(%s)", "IP_FW_ADD"); 349798943Sluigi if (!do_quiet) 3498117469Sluigi show_ipfw(rule, 0, 0); 349998943Sluigi} 350098943Sluigi 350198943Sluigistatic void 3502117328Sluigizero(int ac, char *av[], int optname /* IP_FW_ZERO or IP_FW_RESETLOG */) 350398943Sluigi{ 350498943Sluigi int rulenum; 350598943Sluigi int failed = EX_OK; 3506117469Sluigi char const *name = optname == IP_FW_ZERO ? "ZERO" : "RESETLOG"; 350798943Sluigi 350898943Sluigi av++; ac--; 350998943Sluigi 351098943Sluigi if (!ac) { 351198943Sluigi /* clear all entries */ 3512117328Sluigi if (do_cmd(optname, NULL, 0) < 0) 3513117328Sluigi err(EX_UNAVAILABLE, "setsockopt(IP_FW_%s)", name); 351498943Sluigi if (!do_quiet) 3515117328Sluigi printf("%s.\n", optname == IP_FW_ZERO ? 3516117328Sluigi "Accounting cleared":"Logging counts reset"); 351798943Sluigi 351898943Sluigi return; 351998943Sluigi } 352098943Sluigi 352198943Sluigi while (ac) { 352298943Sluigi /* Rule number */ 352398943Sluigi if (isdigit(**av)) { 352498943Sluigi rulenum = atoi(*av); 352598943Sluigi av++; 352698943Sluigi ac--; 3527117328Sluigi if (do_cmd(optname, &rulenum, sizeof rulenum)) { 3528117328Sluigi warn("rule %u: setsockopt(IP_FW_%s)", 3529117328Sluigi rulenum, name); 353098943Sluigi failed = EX_UNAVAILABLE; 353198943Sluigi } else if (!do_quiet) 3532117328Sluigi printf("Entry %d %s.\n", rulenum, 3533117328Sluigi optname == IP_FW_ZERO ? 3534117328Sluigi "cleared" : "logging count reset"); 353598943Sluigi } else { 353698943Sluigi errx(EX_USAGE, "invalid rule number ``%s''", *av); 353798943Sluigi } 353898943Sluigi } 353998943Sluigi if (failed != EX_OK) 354098943Sluigi exit(failed); 354198943Sluigi} 354298943Sluigi 354398943Sluigistatic void 3544117544Sluigiflush(int force) 354598943Sluigi{ 354698943Sluigi int cmd = do_pipe ? IP_DUMMYNET_FLUSH : IP_FW_FLUSH; 354798943Sluigi 3548117544Sluigi if (!force && !do_quiet) { /* need to ask user */ 354998943Sluigi int c; 355098943Sluigi 355198943Sluigi printf("Are you sure? [yn] "); 355298943Sluigi fflush(stdout); 355398943Sluigi do { 355498943Sluigi c = toupper(getc(stdin)); 355598943Sluigi while (c != '\n' && getc(stdin) != '\n') 355698943Sluigi if (feof(stdin)) 355798943Sluigi return; /* and do not flush */ 355898943Sluigi } while (c != 'Y' && c != 'N'); 355998943Sluigi printf("\n"); 356098943Sluigi if (c == 'N') /* user said no */ 356198943Sluigi return; 356298943Sluigi } 3563117328Sluigi if (do_cmd(cmd, NULL, 0) < 0) 356498943Sluigi err(EX_UNAVAILABLE, "setsockopt(IP_%s_FLUSH)", 356598943Sluigi do_pipe ? "DUMMYNET" : "FW"); 356698943Sluigi if (!do_quiet) 356798943Sluigi printf("Flushed all %s.\n", do_pipe ? "pipes" : "rules"); 356898943Sluigi} 356998943Sluigi 3570117469Sluigi/* 3571117544Sluigi * Free a the (locally allocated) copy of command line arguments. 3572117469Sluigi */ 3573117544Sluigistatic void 3574117544Sluigifree_args(int ac, char **av) 3575117544Sluigi{ 3576117544Sluigi int i; 3577117544Sluigi 3578117544Sluigi for (i=0; i < ac; i++) 3579117544Sluigi free(av[i]); 3580117544Sluigi free(av); 3581117544Sluigi} 3582117544Sluigi 3583117544Sluigi/* 3584117544Sluigi * Called with the arguments (excluding program name). 3585117544Sluigi * Returns 0 if successful, 1 if empty command, errx() in case of errors. 3586117544Sluigi */ 358798943Sluigistatic int 3588117328Sluigiipfw_main(int oldac, char **oldav) 358998943Sluigi{ 3590117469Sluigi int ch, ac, save_ac; 3591117469Sluigi char **av, **save_av; 3592117469Sluigi int do_acct = 0; /* Show packet/byte count */ 3593117544Sluigi int do_force = 0; /* Don't ask for confirmation */ 3594117469Sluigi 3595117469Sluigi#define WHITESP " \t\f\v\n\r" 3596117544Sluigi if (oldac == 0) 3597117544Sluigi return 1; 3598117544Sluigi else if (oldac == 1) { 3599117328Sluigi /* 3600117328Sluigi * If we are called with a single string, try to split it into 3601117328Sluigi * arguments for subsequent parsing. 3602117328Sluigi * But first, remove spaces after a ',', by copying the string 3603117328Sluigi * in-place. 3604117328Sluigi */ 3605117469Sluigi char *arg = oldav[0]; /* The string... */ 3606117328Sluigi int l = strlen(arg); 3607117328Sluigi int copy = 0; /* 1 if we need to copy, 0 otherwise */ 3608117328Sluigi int i, j; 3609117469Sluigi for (i = j = 0; i < l; i++) { 3610117469Sluigi if (arg[i] == '#') /* comment marker */ 3611117469Sluigi break; 3612117328Sluigi if (copy) { 3613117328Sluigi arg[j++] = arg[i]; 3614117469Sluigi copy = !index("," WHITESP, arg[i]); 3615117328Sluigi } else { 3616117469Sluigi copy = !index(WHITESP, arg[i]); 3617117328Sluigi if (copy) 3618117328Sluigi arg[j++] = arg[i]; 3619117328Sluigi } 3620117469Sluigi } 3621117328Sluigi if (!copy && j > 0) /* last char was a 'blank', remove it */ 3622117328Sluigi j--; 3623117328Sluigi l = j; /* the new argument length */ 3624117328Sluigi arg[j++] = '\0'; 3625117469Sluigi if (l == 0) /* empty string! */ 3626117544Sluigi return 1; 3627117328Sluigi 3628117328Sluigi /* 3629117328Sluigi * First, count number of arguments. Because of the previous 3630117469Sluigi * processing, this is just the number of blanks plus 1. 3631117328Sluigi */ 3632117469Sluigi for (i = 0, ac = 1; i < l; i++) 3633117469Sluigi if (index(WHITESP, arg[i]) != NULL) 3634117328Sluigi ac++; 3635117328Sluigi 3636117328Sluigi av = calloc(ac, sizeof(char *)); 3637117328Sluigi 3638117328Sluigi /* 3639117328Sluigi * Second, copy arguments from cmd[] to av[]. For each one, 3640117328Sluigi * j is the initial character, i is the one past the end. 3641117328Sluigi */ 3642117469Sluigi for (ac = 0, i = j = 0; i < l; i++) 3643117469Sluigi if (index(WHITESP, arg[i]) != NULL || i == l-1) { 3644117328Sluigi if (i == l-1) 3645117328Sluigi i++; 3646117328Sluigi av[ac] = calloc(i-j+1, 1); 3647117328Sluigi bcopy(arg+j, av[ac], i-j); 3648117328Sluigi ac++; 3649117328Sluigi j = i + 1; 3650117328Sluigi } 3651117328Sluigi } else { 3652117328Sluigi /* 3653117328Sluigi * If an argument ends with ',' join with the next one. 3654117328Sluigi */ 3655117328Sluigi int first, i, l; 3656117328Sluigi 3657117328Sluigi av = calloc(oldac, sizeof(char *)); 3658117328Sluigi for (first = i = ac = 0, l = 0; i < oldac; i++) { 3659117328Sluigi char *arg = oldav[i]; 3660117328Sluigi int k = strlen(arg); 3661117328Sluigi 3662117328Sluigi l += k; 3663117328Sluigi if (arg[k-1] != ',' || i == oldac-1) { 3664117328Sluigi /* Time to copy. */ 3665117328Sluigi av[ac] = calloc(l+1, 1); 3666117328Sluigi for (l=0; first <= i; first++) { 3667117328Sluigi strcat(av[ac]+l, oldav[first]); 3668117328Sluigi l += strlen(oldav[first]); 3669117328Sluigi } 3670117328Sluigi ac++; 3671117328Sluigi l = 0; 3672117328Sluigi first = i+1; 3673117328Sluigi } 3674117328Sluigi } 3675117328Sluigi } 3676117328Sluigi 367798943Sluigi /* Set the force flag for non-interactive processes */ 367898943Sluigi do_force = !isatty(STDIN_FILENO); 367998943Sluigi 3680117469Sluigi /* Save arguments for final freeing of memory. */ 3681117469Sluigi save_ac = ac; 3682117469Sluigi save_av = av; 3683117469Sluigi 3684117469Sluigi optind = optreset = 0; 3685117472Sluigi while ((ch = getopt(ac, av, "acdefhnNqs:STtv")) != -1) 368698943Sluigi switch (ch) { 368798943Sluigi case 'a': 368898943Sluigi do_acct = 1; 368998943Sluigi break; 3690117328Sluigi 3691102098Sluigi case 'c': 3692102098Sluigi do_compact = 1; 3693102098Sluigi break; 3694117328Sluigi 369598943Sluigi case 'd': 369698943Sluigi do_dynamic = 1; 369798943Sluigi break; 3698117328Sluigi 369998943Sluigi case 'e': 370098943Sluigi do_expired = 1; 370198943Sluigi break; 3702117328Sluigi 370398943Sluigi case 'f': 370498943Sluigi do_force = 1; 370598943Sluigi break; 3706117328Sluigi 3707117328Sluigi case 'h': /* help */ 3708117544Sluigi free_args(save_ac, save_av); 3709117328Sluigi help(); 3710117328Sluigi break; /* NOTREACHED */ 3711117328Sluigi 3712117328Sluigi case 'n': 3713117328Sluigi test_only = 1; 3714117328Sluigi break; 3715117328Sluigi 371698943Sluigi case 'N': 371798943Sluigi do_resolv = 1; 371898943Sluigi break; 3719117328Sluigi 372098943Sluigi case 'q': 372198943Sluigi do_quiet = 1; 372298943Sluigi break; 3723117328Sluigi 3724117328Sluigi case 's': /* sort */ 3725117328Sluigi do_sort = atoi(optarg); 3726117328Sluigi break; 3727117328Sluigi 3728101628Sluigi case 'S': 3729101628Sluigi show_sets = 1; 3730101628Sluigi break; 3731117328Sluigi 373298943Sluigi case 't': 373398943Sluigi do_time = 1; 373498943Sluigi break; 3735117328Sluigi 3736117472Sluigi case 'T': 3737117472Sluigi do_time = 2; /* numeric timestamp */ 3738117472Sluigi break; 3739117472Sluigi 374098943Sluigi case 'v': /* verbose */ 3741117328Sluigi verbose = 1; 374298943Sluigi break; 3743117328Sluigi 374498943Sluigi default: 3745117544Sluigi free_args(save_ac, save_av); 3746117544Sluigi return 1; 374798943Sluigi } 374898943Sluigi 374998943Sluigi ac -= optind; 375098943Sluigi av += optind; 375198943Sluigi NEED1("bad arguments, for usage summary ``ipfw''"); 375298943Sluigi 375398943Sluigi /* 3754117544Sluigi * An undocumented behaviour of ipfw1 was to allow rule numbers first, 3755117544Sluigi * e.g. "100 add allow ..." instead of "add 100 allow ...". 3756117544Sluigi * In case, swap first and second argument to get the normal form. 3757117544Sluigi */ 3758117544Sluigi if (ac > 1 && isdigit(*av[0])) { 3759117544Sluigi char *p = av[0]; 3760117544Sluigi 3761117544Sluigi av[0] = av[1]; 3762117544Sluigi av[1] = p; 3763117544Sluigi } 3764117544Sluigi 3765117544Sluigi /* 376698943Sluigi * optional: pipe or queue 376798943Sluigi */ 3768117544Sluigi if (!strncmp(*av, "pipe", strlen(*av))) 376998943Sluigi do_pipe = 1; 3770117544Sluigi else if (!strncmp(*av, "queue", strlen(*av))) 377198943Sluigi do_pipe = 2; 3772117544Sluigi if (do_pipe) { 377398943Sluigi ac--; 377498943Sluigi av++; 377598943Sluigi } 377698943Sluigi NEED1("missing command"); 377798943Sluigi 377898943Sluigi /* 3779117328Sluigi * For pipes and queues we normally say 'pipe NN config' 378098943Sluigi * but the code is easier to parse as 'pipe config NN' 378198943Sluigi * so we swap the two arguments. 378298943Sluigi */ 3783117469Sluigi if (do_pipe > 0 && ac > 1 && isdigit(*av[0])) { 378498943Sluigi char *p = av[0]; 3785117544Sluigi 378698943Sluigi av[0] = av[1]; 378798943Sluigi av[1] = p; 378898943Sluigi } 3789117328Sluigi 379098943Sluigi if (!strncmp(*av, "add", strlen(*av))) 379198943Sluigi add(ac, av); 379298943Sluigi else if (do_pipe && !strncmp(*av, "config", strlen(*av))) 379398943Sluigi config_pipe(ac, av); 3794101978Sluigi else if (!strncmp(*av, "delete", strlen(*av))) 379598943Sluigi delete(ac, av); 379698943Sluigi else if (!strncmp(*av, "flush", strlen(*av))) 3797117544Sluigi flush(do_force); 379898943Sluigi else if (!strncmp(*av, "zero", strlen(*av))) 3799117328Sluigi zero(ac, av, IP_FW_ZERO); 380098943Sluigi else if (!strncmp(*av, "resetlog", strlen(*av))) 3801117328Sluigi zero(ac, av, IP_FW_RESETLOG); 380298943Sluigi else if (!strncmp(*av, "print", strlen(*av)) || 380398943Sluigi !strncmp(*av, "list", strlen(*av))) 3804117469Sluigi list(ac, av, do_acct); 3805101978Sluigi else if (!strncmp(*av, "set", strlen(*av))) 3806101978Sluigi sets_handler(ac, av); 3807109126Sdillon else if (!strncmp(*av, "enable", strlen(*av))) 3808109126Sdillon sysctl_handler(ac, av, 1); 3809109126Sdillon else if (!strncmp(*av, "disable", strlen(*av))) 3810109126Sdillon sysctl_handler(ac, av, 0); 3811117469Sluigi else if (!strncmp(*av, "show", strlen(*av))) 3812117469Sluigi list(ac, av, 1 /* show counters */); 3813117469Sluigi else 381498943Sluigi errx(EX_USAGE, "bad command `%s'", *av); 3815117469Sluigi 3816117469Sluigi /* Free memory allocated in the argument parsing. */ 3817117544Sluigi free_args(save_ac, save_av); 381898943Sluigi return 0; 381998943Sluigi} 382098943Sluigi 382198943Sluigi 382298943Sluigistatic void 3823106505Smaximipfw_readfile(int ac, char *av[]) 382498943Sluigi{ 382598943Sluigi#define MAX_ARGS 32 382698943Sluigi char buf[BUFSIZ]; 3827117469Sluigi char *cmd = NULL, *filename = av[ac-1]; 3828117469Sluigi int c, lineno=0; 382998943Sluigi FILE *f = NULL; 383098943Sluigi pid_t preproc = 0; 383198943Sluigi 3832117469Sluigi filename = av[ac-1]; 3833117469Sluigi 3834117469Sluigi while ((c = getopt(ac, av, "cNnp:qS")) != -1) { 383598943Sluigi switch(c) { 3836117469Sluigi case 'c': 3837117469Sluigi do_compact = 1; 3838117469Sluigi break; 3839117469Sluigi 3840117469Sluigi case 'N': 3841117469Sluigi do_resolv = 1; 3842117469Sluigi break; 3843117469Sluigi 3844117328Sluigi case 'n': 3845117328Sluigi test_only = 1; 3846117328Sluigi break; 3847117328Sluigi 384898943Sluigi case 'p': 384998943Sluigi cmd = optarg; 3850117469Sluigi /* 3851117469Sluigi * Skip previous args and delete last one, so we 3852117469Sluigi * pass all but the last argument to the preprocessor 3853117469Sluigi * via av[optind-1] 3854117469Sluigi */ 3855117469Sluigi av += optind - 1; 3856117469Sluigi ac -= optind - 1; 3857117469Sluigi av[ac-1] = NULL; 3858117469Sluigi fprintf(stderr, "command is %s\n", av[0]); 385998943Sluigi break; 386098943Sluigi 386198943Sluigi case 'q': 3862117469Sluigi do_quiet = 1; 386398943Sluigi break; 386498943Sluigi 3865117469Sluigi case 'S': 3866117469Sluigi show_sets = 1; 3867117469Sluigi break; 3868117469Sluigi 386998943Sluigi default: 387098943Sluigi errx(EX_USAGE, "bad arguments, for usage" 387198943Sluigi " summary ``ipfw''"); 387298943Sluigi } 387398943Sluigi 3874117469Sluigi if (cmd != NULL) 3875108231Skbyanc break; 3876108231Skbyanc } 3877108231Skbyanc 3878117469Sluigi if (cmd == NULL && ac != optind + 1) { 3879117469Sluigi fprintf(stderr, "ac %d, optind %d\n", ac, optind); 3880117469Sluigi errx(EX_USAGE, "extraneous filename arguments"); 3881108231Skbyanc } 3882108231Skbyanc 3883117469Sluigi if ((f = fopen(filename, "r")) == NULL) 3884117469Sluigi err(EX_UNAVAILABLE, "fopen: %s", filename); 388598943Sluigi 3886117469Sluigi if (cmd != NULL) { /* pipe through preprocessor */ 388798943Sluigi int pipedes[2]; 388898943Sluigi 388998943Sluigi if (pipe(pipedes) == -1) 389098943Sluigi err(EX_OSERR, "cannot create pipe"); 389198943Sluigi 3892117469Sluigi preproc = fork(); 3893117469Sluigi if (preproc == -1) 389498943Sluigi err(EX_OSERR, "cannot fork"); 389598943Sluigi 3896117469Sluigi if (preproc == 0) { 3897117469Sluigi /* 3898117469Sluigi * Child, will run the preprocessor with the 3899117469Sluigi * file on stdin and the pipe on stdout. 3900117469Sluigi */ 390198943Sluigi if (dup2(fileno(f), 0) == -1 390298943Sluigi || dup2(pipedes[1], 1) == -1) 390398943Sluigi err(EX_OSERR, "dup2()"); 390498943Sluigi fclose(f); 390598943Sluigi close(pipedes[1]); 390698943Sluigi close(pipedes[0]); 3907117469Sluigi execvp(cmd, av); 390898943Sluigi err(EX_OSERR, "execvp(%s) failed", cmd); 3909117469Sluigi } else { /* parent, will reopen f as the pipe */ 391098943Sluigi fclose(f); 391198943Sluigi close(pipedes[1]); 391298943Sluigi if ((f = fdopen(pipedes[0], "r")) == NULL) { 391398943Sluigi int savederrno = errno; 391498943Sluigi 391598943Sluigi (void)kill(preproc, SIGTERM); 391698943Sluigi errno = savederrno; 391798943Sluigi err(EX_OSERR, "fdopen()"); 391898943Sluigi } 391998943Sluigi } 392098943Sluigi } 392198943Sluigi 3922117469Sluigi while (fgets(buf, BUFSIZ, f)) { /* read commands */ 3923117469Sluigi char linename[10]; 3924117469Sluigi char *args[1]; 3925117469Sluigi 392698943Sluigi lineno++; 392798943Sluigi sprintf(linename, "Line %d", lineno); 3928117328Sluigi setprogname(linename); /* XXX */ 3929117469Sluigi args[0] = buf; 3930117469Sluigi ipfw_main(1, args); 393198943Sluigi } 393298943Sluigi fclose(f); 3933117469Sluigi if (cmd != NULL) { 3934117469Sluigi int status; 3935117469Sluigi 393698943Sluigi if (waitpid(preproc, &status, 0) == -1) 393798943Sluigi errx(EX_OSERR, "waitpid()"); 393898943Sluigi if (WIFEXITED(status) && WEXITSTATUS(status) != EX_OK) 393998943Sluigi errx(EX_UNAVAILABLE, 394098943Sluigi "preprocessor exited with status %d", 394198943Sluigi WEXITSTATUS(status)); 394298943Sluigi else if (WIFSIGNALED(status)) 394398943Sluigi errx(EX_UNAVAILABLE, 394498943Sluigi "preprocessor exited with signal %d", 394598943Sluigi WTERMSIG(status)); 394698943Sluigi } 394798943Sluigi} 394898943Sluigi 394998943Sluigiint 395098943Sluigimain(int ac, char *av[]) 395198943Sluigi{ 395298943Sluigi /* 395398943Sluigi * If the last argument is an absolute pathname, interpret it 395498943Sluigi * as a file to be preprocessed. 395598943Sluigi */ 395698943Sluigi 395798943Sluigi if (ac > 1 && av[ac - 1][0] == '/' && access(av[ac - 1], R_OK) == 0) 395898943Sluigi ipfw_readfile(ac, av); 3959117544Sluigi else { 3960117544Sluigi if (ipfw_main(ac-1, av+1)) 3961117544Sluigi show_usage(); 3962117544Sluigi } 396398943Sluigi return EX_OK; 396498943Sluigi} 3965