ipfw2.c revision 117469
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 117469 2003-07-12 06:53:16Z 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_force, /* Don't ask for confirmation */ 6398943Sluigi do_pipe, /* this cmd refers to a pipe */ 6498943Sluigi do_sort, /* field to sort results (0 = no) */ 6598943Sluigi do_dynamic, /* display dynamic rules */ 6698943Sluigi do_expired, /* display expired dynamic rules */ 67102098Sluigi do_compact, /* show rules in compact mode */ 68101628Sluigi show_sets, /* display rule sets */ 69117328Sluigi test_only, /* only check syntax */ 7098943Sluigi verbose; 7198943Sluigi 7298943Sluigi#define IP_MASK_ALL 0xffffffff 7398943Sluigi 7498943Sluigi/* 75117328Sluigi * _s_x is a structure that stores a string <-> token pairs, used in 76117328Sluigi * various places in the parser. Entries are stored in arrays, 77117328Sluigi * with an entry with s=NULL as terminator. 78117328Sluigi * The search routines are match_token() and match_value(). 79117328Sluigi * Often, an element with x=0 contains an error string. 8098943Sluigi * 8198943Sluigi */ 8298943Sluigistruct _s_x { 83117469Sluigi char const *s; 8498943Sluigi int x; 8598943Sluigi}; 8698943Sluigi 8798943Sluigistatic struct _s_x f_tcpflags[] = { 8898943Sluigi { "syn", TH_SYN }, 8998943Sluigi { "fin", TH_FIN }, 9098943Sluigi { "ack", TH_ACK }, 9198943Sluigi { "psh", TH_PUSH }, 9298943Sluigi { "rst", TH_RST }, 9398943Sluigi { "urg", TH_URG }, 9498943Sluigi { "tcp flag", 0 }, 9598943Sluigi { NULL, 0 } 9698943Sluigi}; 9798943Sluigi 9898943Sluigistatic struct _s_x f_tcpopts[] = { 9998943Sluigi { "mss", IP_FW_TCPOPT_MSS }, 10098943Sluigi { "maxseg", IP_FW_TCPOPT_MSS }, 10198943Sluigi { "window", IP_FW_TCPOPT_WINDOW }, 10298943Sluigi { "sack", IP_FW_TCPOPT_SACK }, 10398943Sluigi { "ts", IP_FW_TCPOPT_TS }, 10498943Sluigi { "timestamp", IP_FW_TCPOPT_TS }, 10598943Sluigi { "cc", IP_FW_TCPOPT_CC }, 10698943Sluigi { "tcp option", 0 }, 10798943Sluigi { NULL, 0 } 10898943Sluigi}; 10998943Sluigi 11098943Sluigi/* 11198943Sluigi * IP options span the range 0 to 255 so we need to remap them 11298943Sluigi * (though in fact only the low 5 bits are significant). 11398943Sluigi */ 11498943Sluigistatic struct _s_x f_ipopts[] = { 11598943Sluigi { "ssrr", IP_FW_IPOPT_SSRR}, 11698943Sluigi { "lsrr", IP_FW_IPOPT_LSRR}, 11798943Sluigi { "rr", IP_FW_IPOPT_RR}, 11898943Sluigi { "ts", IP_FW_IPOPT_TS}, 11998943Sluigi { "ip option", 0 }, 12098943Sluigi { NULL, 0 } 12198943Sluigi}; 12298943Sluigi 12398943Sluigistatic struct _s_x f_iptos[] = { 12498943Sluigi { "lowdelay", IPTOS_LOWDELAY}, 12598943Sluigi { "throughput", IPTOS_THROUGHPUT}, 12698943Sluigi { "reliability", IPTOS_RELIABILITY}, 12798943Sluigi { "mincost", IPTOS_MINCOST}, 12898943Sluigi { "congestion", IPTOS_CE}, 12998943Sluigi { "ecntransport", IPTOS_ECT}, 13098943Sluigi { "ip tos option", 0}, 13198943Sluigi { NULL, 0 } 13298943Sluigi}; 13398943Sluigi 13498943Sluigistatic struct _s_x limit_masks[] = { 13598943Sluigi {"all", DYN_SRC_ADDR|DYN_SRC_PORT|DYN_DST_ADDR|DYN_DST_PORT}, 13698943Sluigi {"src-addr", DYN_SRC_ADDR}, 13798943Sluigi {"src-port", DYN_SRC_PORT}, 13898943Sluigi {"dst-addr", DYN_DST_ADDR}, 13998943Sluigi {"dst-port", DYN_DST_PORT}, 14098943Sluigi {NULL, 0} 14198943Sluigi}; 14298943Sluigi 14398943Sluigi/* 14498943Sluigi * we use IPPROTO_ETHERTYPE as a fake protocol id to call the print routines 14598943Sluigi * This is only used in this code. 14698943Sluigi */ 14798943Sluigi#define IPPROTO_ETHERTYPE 0x1000 14898943Sluigistatic struct _s_x ether_types[] = { 14998943Sluigi /* 15098943Sluigi * Note, we cannot use "-:&/" in the names because they are field 15198943Sluigi * separators in the type specifications. Also, we use s = NULL as 15298943Sluigi * end-delimiter, because a type of 0 can be legal. 15398943Sluigi */ 15498943Sluigi { "ip", 0x0800 }, 15598943Sluigi { "ipv4", 0x0800 }, 15698943Sluigi { "ipv6", 0x86dd }, 15798943Sluigi { "arp", 0x0806 }, 15898943Sluigi { "rarp", 0x8035 }, 15998943Sluigi { "vlan", 0x8100 }, 16098943Sluigi { "loop", 0x9000 }, 16198943Sluigi { "trail", 0x1000 }, 16298943Sluigi { "at", 0x809b }, 16398943Sluigi { "atalk", 0x809b }, 16498943Sluigi { "aarp", 0x80f3 }, 16598943Sluigi { "pppoe_disc", 0x8863 }, 16698943Sluigi { "pppoe_sess", 0x8864 }, 16798943Sluigi { "ipx_8022", 0x00E0 }, 16898943Sluigi { "ipx_8023", 0x0000 }, 16998943Sluigi { "ipx_ii", 0x8137 }, 17098943Sluigi { "ipx_snap", 0x8137 }, 17198943Sluigi { "ipx", 0x8137 }, 17298943Sluigi { "ns", 0x0600 }, 17398943Sluigi { NULL, 0 } 17498943Sluigi}; 17598943Sluigi 17698943Sluigistatic void show_usage(void); 17798943Sluigi 17898943Sluigienum tokens { 17998943Sluigi TOK_NULL=0, 18098943Sluigi 18198943Sluigi TOK_OR, 18298943Sluigi TOK_NOT, 183101641Sluigi TOK_STARTBRACE, 184101641Sluigi TOK_ENDBRACE, 18598943Sluigi 18698943Sluigi TOK_ACCEPT, 18798943Sluigi TOK_COUNT, 18898943Sluigi TOK_PIPE, 18998943Sluigi TOK_QUEUE, 19098943Sluigi TOK_DIVERT, 19198943Sluigi TOK_TEE, 19298943Sluigi TOK_FORWARD, 19398943Sluigi TOK_SKIPTO, 19498943Sluigi TOK_DENY, 19598943Sluigi TOK_REJECT, 19698943Sluigi TOK_RESET, 19798943Sluigi TOK_UNREACH, 19898943Sluigi TOK_CHECKSTATE, 19998943Sluigi 20098943Sluigi TOK_UID, 20198943Sluigi TOK_GID, 20298943Sluigi TOK_IN, 20398943Sluigi TOK_LIMIT, 20498943Sluigi TOK_KEEPSTATE, 20598943Sluigi TOK_LAYER2, 20698943Sluigi TOK_OUT, 20798943Sluigi TOK_XMIT, 20898943Sluigi TOK_RECV, 20998943Sluigi TOK_VIA, 21098943Sluigi TOK_FRAG, 21198943Sluigi TOK_IPOPTS, 21298943Sluigi TOK_IPLEN, 21398943Sluigi TOK_IPID, 21498943Sluigi TOK_IPPRECEDENCE, 21598943Sluigi TOK_IPTOS, 21698943Sluigi TOK_IPTTL, 21798943Sluigi TOK_IPVER, 21898943Sluigi TOK_ESTAB, 21998943Sluigi TOK_SETUP, 22098943Sluigi TOK_TCPFLAGS, 22198943Sluigi TOK_TCPOPTS, 22298943Sluigi TOK_TCPSEQ, 22398943Sluigi TOK_TCPACK, 22498943Sluigi TOK_TCPWIN, 22598943Sluigi TOK_ICMPTYPES, 226102087Sluigi TOK_MAC, 227102087Sluigi TOK_MACTYPE, 228112250Scjc TOK_VERREVPATH, 229117241Sluigi TOK_IPSEC, 230117469Sluigi TOK_COMMENT, 23198943Sluigi 23298943Sluigi TOK_PLR, 233101978Sluigi TOK_NOERROR, 23498943Sluigi TOK_BUCKETS, 23598943Sluigi TOK_DSTIP, 23698943Sluigi TOK_SRCIP, 23798943Sluigi TOK_DSTPORT, 23898943Sluigi TOK_SRCPORT, 23998943Sluigi TOK_ALL, 24098943Sluigi TOK_MASK, 24198943Sluigi TOK_BW, 24298943Sluigi TOK_DELAY, 24398943Sluigi TOK_RED, 24498943Sluigi TOK_GRED, 24598943Sluigi TOK_DROPTAIL, 24698943Sluigi TOK_PROTO, 24798943Sluigi TOK_WEIGHT, 24898943Sluigi}; 24998943Sluigi 25098943Sluigistruct _s_x dummynet_params[] = { 25198943Sluigi { "plr", TOK_PLR }, 252101978Sluigi { "noerror", TOK_NOERROR }, 25398943Sluigi { "buckets", TOK_BUCKETS }, 25498943Sluigi { "dst-ip", TOK_DSTIP }, 25598943Sluigi { "src-ip", TOK_SRCIP }, 25698943Sluigi { "dst-port", TOK_DSTPORT }, 25798943Sluigi { "src-port", TOK_SRCPORT }, 25898943Sluigi { "proto", TOK_PROTO }, 25998943Sluigi { "weight", TOK_WEIGHT }, 26098943Sluigi { "all", TOK_ALL }, 26198943Sluigi { "mask", TOK_MASK }, 26298943Sluigi { "droptail", TOK_DROPTAIL }, 26398943Sluigi { "red", TOK_RED }, 26498943Sluigi { "gred", TOK_GRED }, 26598943Sluigi { "bw", TOK_BW }, 26698943Sluigi { "bandwidth", TOK_BW }, 26798943Sluigi { "delay", TOK_DELAY }, 26899475Sluigi { "pipe", TOK_PIPE }, 26998943Sluigi { "queue", TOK_QUEUE }, 27098943Sluigi { "dummynet-params", TOK_NULL }, 271117328Sluigi { NULL, 0 } /* terminator */ 27298943Sluigi}; 27398943Sluigi 27498943Sluigistruct _s_x rule_actions[] = { 27598943Sluigi { "accept", TOK_ACCEPT }, 27698943Sluigi { "pass", TOK_ACCEPT }, 27798943Sluigi { "allow", TOK_ACCEPT }, 27898943Sluigi { "permit", TOK_ACCEPT }, 27998943Sluigi { "count", TOK_COUNT }, 28098943Sluigi { "pipe", TOK_PIPE }, 28198943Sluigi { "queue", TOK_QUEUE }, 28298943Sluigi { "divert", TOK_DIVERT }, 28398943Sluigi { "tee", TOK_TEE }, 28498943Sluigi { "fwd", TOK_FORWARD }, 28598943Sluigi { "forward", TOK_FORWARD }, 28698943Sluigi { "skipto", TOK_SKIPTO }, 28798943Sluigi { "deny", TOK_DENY }, 28898943Sluigi { "drop", TOK_DENY }, 28998943Sluigi { "reject", TOK_REJECT }, 29098943Sluigi { "reset", TOK_RESET }, 29199475Sluigi { "unreach", TOK_UNREACH }, 29298943Sluigi { "check-state", TOK_CHECKSTATE }, 293117469Sluigi { "//", TOK_COMMENT }, 294117328Sluigi { NULL, 0 } /* terminator */ 29598943Sluigi}; 29698943Sluigi 29798943Sluigistruct _s_x rule_options[] = { 29898943Sluigi { "uid", TOK_UID }, 29998943Sluigi { "gid", TOK_GID }, 30098943Sluigi { "in", TOK_IN }, 30198943Sluigi { "limit", TOK_LIMIT }, 30298943Sluigi { "keep-state", TOK_KEEPSTATE }, 30398943Sluigi { "bridged", TOK_LAYER2 }, 30498943Sluigi { "layer2", TOK_LAYER2 }, 30598943Sluigi { "out", TOK_OUT }, 30698943Sluigi { "xmit", TOK_XMIT }, 30798943Sluigi { "recv", TOK_RECV }, 30898943Sluigi { "via", TOK_VIA }, 30998943Sluigi { "fragment", TOK_FRAG }, 31098943Sluigi { "frag", TOK_FRAG }, 31198943Sluigi { "ipoptions", TOK_IPOPTS }, 31298943Sluigi { "ipopts", TOK_IPOPTS }, 31398943Sluigi { "iplen", TOK_IPLEN }, 31498943Sluigi { "ipid", TOK_IPID }, 31598943Sluigi { "ipprecedence", TOK_IPPRECEDENCE }, 31698943Sluigi { "iptos", TOK_IPTOS }, 31798943Sluigi { "ipttl", TOK_IPTTL }, 31898943Sluigi { "ipversion", TOK_IPVER }, 31998943Sluigi { "ipver", TOK_IPVER }, 32098943Sluigi { "estab", TOK_ESTAB }, 32198943Sluigi { "established", TOK_ESTAB }, 32298943Sluigi { "setup", TOK_SETUP }, 32398943Sluigi { "tcpflags", TOK_TCPFLAGS }, 32498943Sluigi { "tcpflgs", TOK_TCPFLAGS }, 32598943Sluigi { "tcpoptions", TOK_TCPOPTS }, 32698943Sluigi { "tcpopts", TOK_TCPOPTS }, 32798943Sluigi { "tcpseq", TOK_TCPSEQ }, 32898943Sluigi { "tcpack", TOK_TCPACK }, 32998943Sluigi { "tcpwin", TOK_TCPWIN }, 33099909Sluigi { "icmptype", TOK_ICMPTYPES }, 33198943Sluigi { "icmptypes", TOK_ICMPTYPES }, 332102087Sluigi { "dst-ip", TOK_DSTIP }, 333102087Sluigi { "src-ip", TOK_SRCIP }, 334102087Sluigi { "dst-port", TOK_DSTPORT }, 335102087Sluigi { "src-port", TOK_SRCPORT }, 336102087Sluigi { "proto", TOK_PROTO }, 337102087Sluigi { "MAC", TOK_MAC }, 338102087Sluigi { "mac", TOK_MAC }, 339102087Sluigi { "mac-type", TOK_MACTYPE }, 340112250Scjc { "verrevpath", TOK_VERREVPATH }, 341117241Sluigi { "ipsec", TOK_IPSEC }, 342117469Sluigi { "//", TOK_COMMENT }, 34398943Sluigi 34498943Sluigi { "not", TOK_NOT }, /* pseudo option */ 34598943Sluigi { "!", /* escape ? */ TOK_NOT }, /* pseudo option */ 34698943Sluigi { "or", TOK_OR }, /* pseudo option */ 34798943Sluigi { "|", /* escape */ TOK_OR }, /* pseudo option */ 348101641Sluigi { "{", TOK_STARTBRACE }, /* pseudo option */ 349101641Sluigi { "(", TOK_STARTBRACE }, /* pseudo option */ 350101641Sluigi { "}", TOK_ENDBRACE }, /* pseudo option */ 351101641Sluigi { ")", TOK_ENDBRACE }, /* pseudo option */ 352117328Sluigi { NULL, 0 } /* terminator */ 35398943Sluigi}; 35498943Sluigi 355117328Sluigistatic __inline uint64_t 356117328Sluigialign_uint64(uint64_t *pll) { 357117328Sluigi uint64_t ret; 358115793Sticso 359115793Sticso bcopy (pll, &ret, sizeof(ret)); 360115793Sticso return ret; 361115793Sticso}; 362115793Sticso 363117328Sluigi/* 364117328Sluigi * conditionally runs the command. 365117328Sluigi */ 366117469Sluigistatic int 367117328Sluigido_cmd(int optname, void *optval, socklen_t optlen) 368117328Sluigi{ 369117328Sluigi static int s = -1; /* the socket */ 370117328Sluigi int i; 371117328Sluigi 372117328Sluigi if (test_only) 373117328Sluigi return 0; 374117328Sluigi 375117328Sluigi if (s == -1) 376117328Sluigi s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); 377117328Sluigi if (s < 0) 378117328Sluigi err(EX_UNAVAILABLE, "socket"); 379117328Sluigi 380117328Sluigi if (optname == IP_FW_GET || optname == IP_DUMMYNET_GET || 381117328Sluigi optname == IP_FW_ADD) 382117328Sluigi i = getsockopt(s, IPPROTO_IP, optname, optval, 383117328Sluigi (socklen_t *)optlen); 384117328Sluigi else 385117328Sluigi i = setsockopt(s, IPPROTO_IP, optname, optval, optlen); 386117328Sluigi return i; 387117328Sluigi} 388117328Sluigi 38998943Sluigi/** 39098943Sluigi * match_token takes a table and a string, returns the value associated 391117328Sluigi * with the string (-1 in case of failure). 39298943Sluigi */ 39398943Sluigistatic int 39498943Sluigimatch_token(struct _s_x *table, char *string) 39598943Sluigi{ 39698943Sluigi struct _s_x *pt; 397117469Sluigi uint i = strlen(string); 39898943Sluigi 39998943Sluigi for (pt = table ; i && pt->s != NULL ; pt++) 40098943Sluigi if (strlen(pt->s) == i && !bcmp(string, pt->s, i)) 40198943Sluigi return pt->x; 40298943Sluigi return -1; 40398943Sluigi}; 40498943Sluigi 405117328Sluigi/** 406117328Sluigi * match_value takes a table and a value, returns the string associated 407117328Sluigi * with the value (NULL in case of failure). 408117328Sluigi */ 409117469Sluigistatic char const * 410117469Sluigimatch_value(struct _s_x *p, int value) 41198943Sluigi{ 41298943Sluigi for (; p->s != NULL; p++) 41398943Sluigi if (p->x == value) 41498943Sluigi return p->s; 41598943Sluigi return NULL; 41698943Sluigi} 41798943Sluigi 41898943Sluigi/* 41998943Sluigi * prints one port, symbolic or numeric 42098943Sluigi */ 42198943Sluigistatic void 422117328Sluigiprint_port(int proto, uint16_t port) 42398943Sluigi{ 42498943Sluigi 42598943Sluigi if (proto == IPPROTO_ETHERTYPE) { 426117469Sluigi char const *s; 42798943Sluigi 42898943Sluigi if (do_resolv && (s = match_value(ether_types, port)) ) 42998943Sluigi printf("%s", s); 43098943Sluigi else 43198943Sluigi printf("0x%04x", port); 43298943Sluigi } else { 43398943Sluigi struct servent *se = NULL; 43498943Sluigi if (do_resolv) { 43598943Sluigi struct protoent *pe = getprotobynumber(proto); 43698943Sluigi 43798943Sluigi se = getservbyport(htons(port), pe ? pe->p_name : NULL); 43898943Sluigi } 43998943Sluigi if (se) 44098943Sluigi printf("%s", se->s_name); 44198943Sluigi else 44298943Sluigi printf("%d", port); 44398943Sluigi } 44498943Sluigi} 44598943Sluigi 446117328Sluigistruct _s_x _port_name[] = { 447117328Sluigi {"dst-port", O_IP_DSTPORT}, 448117328Sluigi {"src-port", O_IP_SRCPORT}, 449117328Sluigi {"ipid", O_IPID}, 450117328Sluigi {"iplen", O_IPLEN}, 451117328Sluigi {"ipttl", O_IPTTL}, 452117328Sluigi {"mac-type", O_MAC_TYPE}, 453117328Sluigi {NULL, 0} 454117328Sluigi}; 455117328Sluigi 45698943Sluigi/* 457117328Sluigi * Print the values in a list 16-bit items of the types above. 45898943Sluigi * XXX todo: add support for mask. 45998943Sluigi */ 46098943Sluigistatic void 461102087Sluigiprint_newports(ipfw_insn_u16 *cmd, int proto, int opcode) 46298943Sluigi{ 463117328Sluigi uint16_t *p = cmd->ports; 46498943Sluigi int i; 465117469Sluigi char const *sep; 46698943Sluigi 46798943Sluigi if (cmd->o.len & F_NOT) 46898943Sluigi printf(" not"); 469116690Sluigi if (opcode != 0) { 470117328Sluigi sep = match_value(_port_name, opcode); 471117328Sluigi if (sep == NULL) 472116690Sluigi sep = "???"; 473116690Sluigi printf (" %s", sep); 474116690Sluigi } 475116690Sluigi sep = " "; 47698943Sluigi for (i = F_LEN((ipfw_insn *)cmd) - 1; i > 0; i--, p += 2) { 47798943Sluigi printf(sep); 47898943Sluigi print_port(proto, p[0]); 47998943Sluigi if (p[0] != p[1]) { 48098943Sluigi printf("-"); 48198943Sluigi print_port(proto, p[1]); 48298943Sluigi } 48398943Sluigi sep = ","; 48498943Sluigi } 48598943Sluigi} 48698943Sluigi 48798943Sluigi/* 48898943Sluigi * Like strtol, but also translates service names into port numbers 48998943Sluigi * for some protocols. 49098943Sluigi * In particular: 49198943Sluigi * proto == -1 disables the protocol check; 49298943Sluigi * proto == IPPROTO_ETHERTYPE looks up an internal table 49398943Sluigi * proto == <some value in /etc/protocols> matches the values there. 494101628Sluigi * Returns *end == s in case the parameter is not found. 49598943Sluigi */ 49698943Sluigistatic int 49798943Sluigistrtoport(char *s, char **end, int base, int proto) 49898943Sluigi{ 499101628Sluigi char *p, *buf; 500101628Sluigi char *s1; 50198943Sluigi int i; 50298943Sluigi 503101628Sluigi *end = s; /* default - not found */ 50498943Sluigi if ( *s == '\0') 505101628Sluigi return 0; /* not found */ 506106505Smaxim 50798943Sluigi if (isdigit(*s)) 50898943Sluigi return strtol(s, end, base); 50998943Sluigi 51098943Sluigi /* 511101628Sluigi * find separator. '\\' escapes the next char. 51298943Sluigi */ 513101628Sluigi for (s1 = s; *s1 && (isalnum(*s1) || *s1 == '\\') ; s1++) 514101628Sluigi if (*s1 == '\\' && s1[1] != '\0') 515101628Sluigi s1++; 51698943Sluigi 517101628Sluigi buf = malloc(s1 - s + 1); 518101628Sluigi if (buf == NULL) 519101628Sluigi return 0; 520101628Sluigi 521101628Sluigi /* 522101628Sluigi * copy into a buffer skipping backslashes 523101628Sluigi */ 524101628Sluigi for (p = s, i = 0; p != s1 ; p++) 525101628Sluigi if ( *p != '\\') 526101628Sluigi buf[i++] = *p; 527101628Sluigi buf[i++] = '\0'; 528101628Sluigi 52998943Sluigi if (proto == IPPROTO_ETHERTYPE) { 530101628Sluigi i = match_token(ether_types, buf); 531101628Sluigi free(buf); 532101628Sluigi if (i != -1) { /* found */ 53398943Sluigi *end = s1; 53498943Sluigi return i; 53598943Sluigi } 53698943Sluigi } else { 53798943Sluigi struct protoent *pe = NULL; 53898943Sluigi struct servent *se; 53998943Sluigi 54098943Sluigi if (proto != 0) 54198943Sluigi pe = getprotobynumber(proto); 54298943Sluigi setservent(1); 543101628Sluigi se = getservbyname(buf, pe ? pe->p_name : NULL); 544101628Sluigi free(buf); 54598943Sluigi if (se != NULL) { 54698943Sluigi *end = s1; 54798943Sluigi return ntohs(se->s_port); 54898943Sluigi } 54998943Sluigi } 550101628Sluigi return 0; /* not found */ 55198943Sluigi} 55298943Sluigi 55398943Sluigi/* 554117328Sluigi * Fill the body of the command with the list of port ranges. 55598943Sluigi */ 55698943Sluigistatic int 55798943Sluigifill_newports(ipfw_insn_u16 *cmd, char *av, int proto) 55898943Sluigi{ 559117328Sluigi uint16_t a, b, *p = cmd->ports; 56098943Sluigi int i = 0; 561102087Sluigi char *s = av; 56298943Sluigi 563102087Sluigi while (*s) { 56498943Sluigi a = strtoport(av, &s, 0, proto); 56598943Sluigi if (s == av) /* no parameter */ 56698943Sluigi break; 56798943Sluigi if (*s == '-') { /* a range */ 56898943Sluigi av = s+1; 56998943Sluigi b = strtoport(av, &s, 0, proto); 57098943Sluigi if (s == av) /* no parameter */ 57198943Sluigi break; 57298943Sluigi p[0] = a; 57398943Sluigi p[1] = b; 574117328Sluigi } else if (*s == ',' || *s == '\0' ) 57598943Sluigi p[0] = p[1] = a; 576117328Sluigi else /* invalid separator */ 577101978Sluigi errx(EX_DATAERR, "invalid separator <%c> in <%s>\n", 578101978Sluigi *s, av); 579102087Sluigi i++; 580102087Sluigi p += 2; 58198943Sluigi av = s+1; 58298943Sluigi } 58398943Sluigi if (i > 0) { 58498943Sluigi if (i+1 > F_LEN_MASK) 585102087Sluigi errx(EX_DATAERR, "too many ports/ranges\n"); 58698943Sluigi cmd->o.len |= i+1; /* leave F_NOT and F_OR untouched */ 58798943Sluigi } 58898943Sluigi return i; 58998943Sluigi} 59098943Sluigi 59198943Sluigistatic struct _s_x icmpcodes[] = { 59298943Sluigi { "net", ICMP_UNREACH_NET }, 59398943Sluigi { "host", ICMP_UNREACH_HOST }, 59498943Sluigi { "protocol", ICMP_UNREACH_PROTOCOL }, 59598943Sluigi { "port", ICMP_UNREACH_PORT }, 59698943Sluigi { "needfrag", ICMP_UNREACH_NEEDFRAG }, 59798943Sluigi { "srcfail", ICMP_UNREACH_SRCFAIL }, 59898943Sluigi { "net-unknown", ICMP_UNREACH_NET_UNKNOWN }, 59998943Sluigi { "host-unknown", ICMP_UNREACH_HOST_UNKNOWN }, 60098943Sluigi { "isolated", ICMP_UNREACH_ISOLATED }, 60198943Sluigi { "net-prohib", ICMP_UNREACH_NET_PROHIB }, 60298943Sluigi { "host-prohib", ICMP_UNREACH_HOST_PROHIB }, 60398943Sluigi { "tosnet", ICMP_UNREACH_TOSNET }, 60498943Sluigi { "toshost", ICMP_UNREACH_TOSHOST }, 60598943Sluigi { "filter-prohib", ICMP_UNREACH_FILTER_PROHIB }, 60698943Sluigi { "host-precedence", ICMP_UNREACH_HOST_PRECEDENCE }, 60798943Sluigi { "precedence-cutoff", ICMP_UNREACH_PRECEDENCE_CUTOFF }, 60898943Sluigi { NULL, 0 } 60998943Sluigi}; 61098943Sluigi 61198943Sluigistatic void 61298943Sluigifill_reject_code(u_short *codep, char *str) 61398943Sluigi{ 61498943Sluigi int val; 61598943Sluigi char *s; 61698943Sluigi 61798943Sluigi val = strtoul(str, &s, 0); 61898943Sluigi if (s == str || *s != '\0' || val >= 0x100) 61998943Sluigi val = match_token(icmpcodes, str); 620102087Sluigi if (val < 0) 62198943Sluigi errx(EX_DATAERR, "unknown ICMP unreachable code ``%s''", str); 62298943Sluigi *codep = val; 62398943Sluigi return; 62498943Sluigi} 62598943Sluigi 62698943Sluigistatic void 627117328Sluigiprint_reject_code(uint16_t code) 62898943Sluigi{ 629117469Sluigi char const *s = match_value(icmpcodes, code); 63098943Sluigi 63198943Sluigi if (s != NULL) 63299475Sluigi printf("unreach %s", s); 63398943Sluigi else 63499475Sluigi printf("unreach %u", code); 63598943Sluigi} 63698943Sluigi 63798943Sluigi/* 63898943Sluigi * Returns the number of bits set (from left) in a contiguous bitmask, 63998943Sluigi * or -1 if the mask is not contiguous. 64098943Sluigi * XXX this needs a proper fix. 64198943Sluigi * This effectively works on masks in big-endian (network) format. 64298943Sluigi * when compiled on little endian architectures. 64398943Sluigi * 64498943Sluigi * First bit is bit 7 of the first byte -- note, for MAC addresses, 64598943Sluigi * the first bit on the wire is bit 0 of the first byte. 64698943Sluigi * len is the max length in bits. 64798943Sluigi */ 64898943Sluigistatic int 64998943Sluigicontigmask(u_char *p, int len) 65098943Sluigi{ 65198943Sluigi int i, n; 65298943Sluigi for (i=0; i<len ; i++) 65398943Sluigi if ( (p[i/8] & (1 << (7 - (i%8)))) == 0) /* first bit unset */ 65498943Sluigi break; 65598943Sluigi for (n=i+1; n < len; n++) 65698943Sluigi if ( (p[n/8] & (1 << (7 - (n%8)))) != 0) 65798943Sluigi return -1; /* mask not contiguous */ 65898943Sluigi return i; 65998943Sluigi} 66098943Sluigi 66198943Sluigi/* 66298943Sluigi * print flags set/clear in the two bitmasks passed as parameters. 66398943Sluigi * There is a specialized check for f_tcpflags. 66498943Sluigi */ 66598943Sluigistatic void 666117469Sluigiprint_flags(char const *name, ipfw_insn *cmd, struct _s_x *list) 66798943Sluigi{ 668117469Sluigi char const *comma = ""; 66998943Sluigi int i; 67098943Sluigi u_char set = cmd->arg1 & 0xff; 67198943Sluigi u_char clear = (cmd->arg1 >> 8) & 0xff; 67298943Sluigi 67398943Sluigi if (list == f_tcpflags && set == TH_SYN && clear == TH_ACK) { 67498943Sluigi printf(" setup"); 67598943Sluigi return; 67698943Sluigi } 67798943Sluigi 67898943Sluigi printf(" %s ", name); 67998943Sluigi for (i=0; list[i].x != 0; i++) { 68098943Sluigi if (set & list[i].x) { 68198943Sluigi set &= ~list[i].x; 68298943Sluigi printf("%s%s", comma, list[i].s); 68398943Sluigi comma = ","; 68498943Sluigi } 68598943Sluigi if (clear & list[i].x) { 68698943Sluigi clear &= ~list[i].x; 68798943Sluigi printf("%s!%s", comma, list[i].s); 68898943Sluigi comma = ","; 68998943Sluigi } 69098943Sluigi } 69198943Sluigi} 69298943Sluigi 69398943Sluigi/* 69498943Sluigi * Print the ip address contained in a command. 69598943Sluigi */ 69698943Sluigistatic void 697117469Sluigiprint_ip(ipfw_insn_ip *cmd, char const *s) 69898943Sluigi{ 69998943Sluigi struct hostent *he = NULL; 700117328Sluigi int len = F_LEN((ipfw_insn *)cmd); 701117328Sluigi uint32_t *a = ((ipfw_insn_u32 *)cmd)->d; 70298943Sluigi 703102087Sluigi printf("%s%s ", cmd->o.len & F_NOT ? " not": "", s); 70498943Sluigi 70598943Sluigi if (cmd->o.opcode == O_IP_SRC_ME || cmd->o.opcode == O_IP_DST_ME) { 70698943Sluigi printf("me"); 70798943Sluigi return; 70898943Sluigi } 70998943Sluigi if (cmd->o.opcode == O_IP_SRC_SET || cmd->o.opcode == O_IP_DST_SET) { 710117328Sluigi uint32_t x, *map = (uint32_t *)&(cmd->mask); 711116716Sluigi int i, j; 71298943Sluigi char comma = '{'; 71398943Sluigi 71498943Sluigi x = cmd->o.arg1 - 1; 71598943Sluigi x = htonl( ~x ); 71698943Sluigi cmd->addr.s_addr = htonl(cmd->addr.s_addr); 71798943Sluigi printf("%s/%d", inet_ntoa(cmd->addr), 71898943Sluigi contigmask((u_char *)&x, 32)); 71998943Sluigi x = cmd->addr.s_addr = htonl(cmd->addr.s_addr); 72098943Sluigi x &= 0xff; /* base */ 721116716Sluigi /* 722116716Sluigi * Print bits and ranges. 723116716Sluigi * Locate first bit set (i), then locate first bit unset (j). 724116716Sluigi * If we have 3+ consecutive bits set, then print them as a 725116716Sluigi * range, otherwise only print the initial bit and rescan. 726116716Sluigi */ 72798943Sluigi for (i=0; i < cmd->o.arg1; i++) 728117328Sluigi if (map[i/32] & (1<<(i & 31))) { 729116716Sluigi for (j=i+1; j < cmd->o.arg1; j++) 730117328Sluigi if (!(map[ j/32] & (1<<(j & 31)))) 731116716Sluigi break; 73298943Sluigi printf("%c%d", comma, i+x); 733116716Sluigi if (j>i+2) { /* range has at least 3 elements */ 734116716Sluigi printf("-%d", j-1+x); 735116716Sluigi i = j-1; 736116716Sluigi } 73798943Sluigi comma = ','; 73898943Sluigi } 73998943Sluigi printf("}"); 74098943Sluigi return; 74198943Sluigi } 742117328Sluigi /* 743117328Sluigi * len == 2 indicates a single IP, whereas lists of 1 or more 744117328Sluigi * addr/mask pairs have len = (2n+1). We convert len to n so we 745117328Sluigi * use that to count the number of entries. 746117328Sluigi */ 747117328Sluigi for (len = len / 2; len > 0; len--, a += 2) { 748117328Sluigi int mb = /* mask length */ 749117328Sluigi (cmd->o.opcode == O_IP_SRC || cmd->o.opcode == O_IP_DST) ? 750117328Sluigi 32 : contigmask((u_char *)&(a[1]), 32); 75198943Sluigi if (mb == 32 && do_resolv) 752117328Sluigi he = gethostbyaddr((char *)&(a[0]), sizeof(u_long), AF_INET); 75398943Sluigi if (he != NULL) /* resolved to name */ 75498943Sluigi printf("%s", he->h_name); 75598943Sluigi else if (mb == 0) /* any */ 75698943Sluigi printf("any"); 75798943Sluigi else { /* numeric IP followed by some kind of mask */ 758117328Sluigi printf("%s", inet_ntoa( *((struct in_addr *)&a[0]) ) ); 75998943Sluigi if (mb < 0) 760117328Sluigi printf(":%s", inet_ntoa( *((struct in_addr *)&a[1]) ) ); 76198943Sluigi else if (mb < 32) 76298943Sluigi printf("/%d", mb); 76398943Sluigi } 764117328Sluigi if (len > 1) 765117328Sluigi printf(","); 766117328Sluigi } 767117328Sluigi 76898943Sluigi} 76998943Sluigi 77098943Sluigi/* 77198943Sluigi * prints a MAC address/mask pair 77298943Sluigi */ 77398943Sluigistatic void 77498943Sluigiprint_mac(u_char *addr, u_char *mask) 77598943Sluigi{ 77698943Sluigi int l = contigmask(mask, 48); 77798943Sluigi 77898943Sluigi if (l == 0) 77998943Sluigi printf(" any"); 78098943Sluigi else { 78198943Sluigi printf(" %02x:%02x:%02x:%02x:%02x:%02x", 78298943Sluigi addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); 78398943Sluigi if (l == -1) 78498943Sluigi printf("&%02x:%02x:%02x:%02x:%02x:%02x", 78598943Sluigi mask[0], mask[1], mask[2], 78698943Sluigi mask[3], mask[4], mask[5]); 78798943Sluigi else if (l < 48) 78898943Sluigi printf("/%d", l); 78998943Sluigi } 79098943Sluigi} 79198943Sluigi 79299475Sluigistatic void 79399475Sluigifill_icmptypes(ipfw_insn_u32 *cmd, char *av) 79499475Sluigi{ 795117328Sluigi uint8_t type; 79698943Sluigi 79799475Sluigi cmd->d[0] = 0; 79899475Sluigi while (*av) { 79999475Sluigi if (*av == ',') 80099475Sluigi av++; 80199475Sluigi 80299475Sluigi type = strtoul(av, &av, 0); 80399475Sluigi 80499475Sluigi if (*av != ',' && *av != '\0') 80599475Sluigi errx(EX_DATAERR, "invalid ICMP type"); 80699475Sluigi 80799475Sluigi if (type > 31) 80899475Sluigi errx(EX_DATAERR, "ICMP type out of range"); 80999475Sluigi 81099475Sluigi cmd->d[0] |= 1 << type; 81199475Sluigi } 81299475Sluigi cmd->o.opcode = O_ICMPTYPE; 81399475Sluigi cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32); 81499475Sluigi} 81599475Sluigi 81699475Sluigistatic void 81799475Sluigiprint_icmptypes(ipfw_insn_u32 *cmd) 81899475Sluigi{ 81999475Sluigi int i; 82099475Sluigi char sep= ' '; 82199475Sluigi 82299475Sluigi printf(" icmptypes"); 82399475Sluigi for (i = 0; i < 32; i++) { 82499475Sluigi if ( (cmd->d[0] & (1 << (i))) == 0) 82599475Sluigi continue; 82699475Sluigi printf("%c%d", sep, i); 82799475Sluigi sep = ','; 82899475Sluigi } 82999475Sluigi} 83099475Sluigi 83198943Sluigi/* 83298943Sluigi * show_ipfw() prints the body of an ipfw rule. 83398943Sluigi * Because the standard rule has at least proto src_ip dst_ip, we use 83498943Sluigi * a helper function to produce these entries if not provided explicitly. 835102087Sluigi * The first argument is the list of fields we have, the second is 836102087Sluigi * the list of fields we want to be printed. 837101978Sluigi * 838102087Sluigi * Special cases if we have provided a MAC header: 839102087Sluigi * + if the rule does not contain IP addresses/ports, do not print them; 840102087Sluigi * + if the rule does not contain an IP proto, print "all" instead of "ip"; 841102087Sluigi * 842102087Sluigi * Once we have 'have_options', IP header fields are printed as options. 84398943Sluigi */ 844101978Sluigi#define HAVE_PROTO 0x0001 845101978Sluigi#define HAVE_SRCIP 0x0002 846101978Sluigi#define HAVE_DSTIP 0x0004 847101978Sluigi#define HAVE_MAC 0x0008 848101978Sluigi#define HAVE_MACTYPE 0x0010 849102087Sluigi#define HAVE_OPTIONS 0x8000 85098943Sluigi 851101978Sluigi#define HAVE_IP (HAVE_PROTO | HAVE_SRCIP | HAVE_DSTIP) 85298943Sluigistatic void 853102087Sluigishow_prerequisites(int *flags, int want, int cmd) 85498943Sluigi{ 855102087Sluigi if ( (*flags & HAVE_IP) == HAVE_IP) 856102087Sluigi *flags |= HAVE_OPTIONS; 857102087Sluigi 858102087Sluigi if ( (*flags & (HAVE_MAC|HAVE_MACTYPE|HAVE_OPTIONS)) == HAVE_MAC && 859102087Sluigi cmd != O_MAC_TYPE) { 860102087Sluigi /* 861102087Sluigi * mac-type was optimized out by the compiler, 862102087Sluigi * restore it 863102087Sluigi */ 864102087Sluigi printf(" any"); 865102087Sluigi *flags |= HAVE_MACTYPE | HAVE_OPTIONS; 866102087Sluigi return; 867101978Sluigi } 868102087Sluigi if ( !(*flags & HAVE_OPTIONS)) { 869102087Sluigi if ( !(*flags & HAVE_PROTO) && (want & HAVE_PROTO)) 870102087Sluigi printf(" ip"); 871102087Sluigi if ( !(*flags & HAVE_SRCIP) && (want & HAVE_SRCIP)) 872102087Sluigi printf(" from any"); 873102087Sluigi if ( !(*flags & HAVE_DSTIP) && (want & HAVE_DSTIP)) 874102087Sluigi printf(" to any"); 875102087Sluigi } 87698943Sluigi *flags |= want; 87798943Sluigi} 87898943Sluigi 87998943Sluigistatic void 880112189Smaximshow_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth) 88198943Sluigi{ 882107291Skeramida static int twidth = 0; 88398943Sluigi int l; 88498943Sluigi ipfw_insn *cmd; 88598943Sluigi int proto = 0; /* default */ 88698943Sluigi int flags = 0; /* prerequisites */ 88798943Sluigi ipfw_insn_log *logptr = NULL; /* set if we find an O_LOG */ 88898943Sluigi int or_block = 0; /* we are in an or block */ 889117328Sluigi uint32_t set_disable; 89098943Sluigi 891115793Sticso bcopy(&rule->next_rule, &set_disable, sizeof(set_disable)); 892101628Sluigi 893101628Sluigi if (set_disable & (1 << rule->set)) { /* disabled */ 894101628Sluigi if (!show_sets) 895101628Sluigi return; 896101628Sluigi else 897101628Sluigi printf("# DISABLED "); 898101628Sluigi } 89998943Sluigi printf("%05u ", rule->rulenum); 90098943Sluigi 901117469Sluigi if (pcwidth>0 || bcwidth>0) 902115793Sticso printf("%*llu %*llu ", pcwidth, align_uint64(&rule->pcnt), 903115793Sticso bcwidth, align_uint64(&rule->bcnt)); 90498943Sluigi 90598943Sluigi if (do_time) { 906107291Skeramida char timestr[30]; 907107291Skeramida time_t t = (time_t)0; 908107291Skeramida 909107291Skeramida if (twidth == 0) { 910107291Skeramida strcpy(timestr, ctime(&t)); 911107291Skeramida *strchr(timestr, '\n') = '\0'; 912107291Skeramida twidth = strlen(timestr); 913107291Skeramida } 91498943Sluigi if (rule->timestamp) { 915117469Sluigi#if _FreeBSD_version < 500000 /* XXX check */ 916117469Sluigi#define _long_to_time(x) (time_t)(x) 917117469Sluigi#endif 918107291Skeramida t = _long_to_time(rule->timestamp); 91998943Sluigi 92098943Sluigi strcpy(timestr, ctime(&t)); 92198943Sluigi *strchr(timestr, '\n') = '\0'; 92298943Sluigi printf("%s ", timestr); 92398943Sluigi } else { 924107291Skeramida printf("%*s", twidth, " "); 92598943Sluigi } 92698943Sluigi } 92798943Sluigi 928101628Sluigi if (show_sets) 929101628Sluigi printf("set %d ", rule->set); 930101628Sluigi 93198943Sluigi /* 932107289Sluigi * print the optional "match probability" 933107289Sluigi */ 934107289Sluigi if (rule->cmd_len > 0) { 935107289Sluigi cmd = rule->cmd ; 936107289Sluigi if (cmd->opcode == O_PROB) { 937107289Sluigi ipfw_insn_u32 *p = (ipfw_insn_u32 *)cmd; 938107289Sluigi double d = 1.0 * p->d[0]; 939107289Sluigi 940107289Sluigi d = (d / 0x7fffffff); 941107289Sluigi printf("prob %f ", d); 942107289Sluigi } 943107289Sluigi } 944107289Sluigi 945107289Sluigi /* 94698943Sluigi * first print actions 94798943Sluigi */ 94898943Sluigi for (l = rule->cmd_len - rule->act_ofs, cmd = ACTION_PTR(rule); 94998943Sluigi l > 0 ; l -= F_LEN(cmd), cmd += F_LEN(cmd)) { 95098943Sluigi switch(cmd->opcode) { 95198943Sluigi case O_CHECK_STATE: 95298943Sluigi printf("check-state"); 953102087Sluigi flags = HAVE_IP; /* avoid printing anything else */ 95498943Sluigi break; 95598943Sluigi 95698943Sluigi case O_ACCEPT: 95798943Sluigi printf("allow"); 95898943Sluigi break; 95998943Sluigi 96098943Sluigi case O_COUNT: 96198943Sluigi printf("count"); 96298943Sluigi break; 96398943Sluigi 96498943Sluigi case O_DENY: 96598943Sluigi printf("deny"); 96698943Sluigi break; 96798943Sluigi 96899475Sluigi case O_REJECT: 96999475Sluigi if (cmd->arg1 == ICMP_REJECT_RST) 97099475Sluigi printf("reset"); 97199475Sluigi else if (cmd->arg1 == ICMP_UNREACH_HOST) 97299475Sluigi printf("reject"); 97399475Sluigi else 97499475Sluigi print_reject_code(cmd->arg1); 97599475Sluigi break; 97699475Sluigi 97798943Sluigi case O_SKIPTO: 97898943Sluigi printf("skipto %u", cmd->arg1); 97998943Sluigi break; 98098943Sluigi 98198943Sluigi case O_PIPE: 98298943Sluigi printf("pipe %u", cmd->arg1); 98398943Sluigi break; 98498943Sluigi 98598943Sluigi case O_QUEUE: 98698943Sluigi printf("queue %u", cmd->arg1); 98798943Sluigi break; 98898943Sluigi 98998943Sluigi case O_DIVERT: 99098943Sluigi printf("divert %u", cmd->arg1); 99198943Sluigi break; 99298943Sluigi 99398943Sluigi case O_TEE: 99498943Sluigi printf("tee %u", cmd->arg1); 99598943Sluigi break; 99698943Sluigi 99798943Sluigi case O_FORWARD_IP: 99898943Sluigi { 99998943Sluigi ipfw_insn_sa *s = (ipfw_insn_sa *)cmd; 100098943Sluigi 100198943Sluigi printf("fwd %s", inet_ntoa(s->sa.sin_addr)); 100298943Sluigi if (s->sa.sin_port) 1003103241Sluigi printf(",%d", s->sa.sin_port); 100498943Sluigi } 100598943Sluigi break; 100698943Sluigi 100798943Sluigi case O_LOG: /* O_LOG is printed last */ 100898943Sluigi logptr = (ipfw_insn_log *)cmd; 100998943Sluigi break; 101098943Sluigi 101198943Sluigi default: 101298943Sluigi printf("** unrecognized action %d len %d", 101398943Sluigi cmd->opcode, cmd->len); 101498943Sluigi } 101598943Sluigi } 101698943Sluigi if (logptr) { 101798943Sluigi if (logptr->max_log > 0) 101899909Sluigi printf(" log logamount %d", logptr->max_log); 101998943Sluigi else 102099909Sluigi printf(" log"); 102198943Sluigi } 1022102087Sluigi 102398943Sluigi /* 1024102087Sluigi * then print the body. 102598943Sluigi */ 1026102087Sluigi if (rule->_pad & 1) { /* empty rules before options */ 1027102098Sluigi if (!do_compact) 1028102098Sluigi printf(" ip from any to any"); 1029102087Sluigi flags |= HAVE_IP | HAVE_OPTIONS; 1030102087Sluigi } 1031102087Sluigi 103298943Sluigi for (l = rule->act_ofs, cmd = rule->cmd ; 103398943Sluigi l > 0 ; l -= F_LEN(cmd) , cmd += F_LEN(cmd)) { 103499475Sluigi /* useful alias */ 103599475Sluigi ipfw_insn_u32 *cmd32 = (ipfw_insn_u32 *)cmd; 103698943Sluigi 1037102087Sluigi show_prerequisites(&flags, 0, cmd->opcode); 1038102087Sluigi 103998943Sluigi switch(cmd->opcode) { 1040107289Sluigi case O_PROB: 1041107289Sluigi break; /* done already */ 1042107289Sluigi 104398943Sluigi case O_PROBE_STATE: 104498943Sluigi break; /* no need to print anything here */ 104598943Sluigi 104698943Sluigi case O_MACADDR2: { 104798943Sluigi ipfw_insn_mac *m = (ipfw_insn_mac *)cmd; 1048102087Sluigi 1049102087Sluigi if ((cmd->len & F_OR) && !or_block) 1050102087Sluigi printf(" {"); 105198943Sluigi if (cmd->len & F_NOT) 105298943Sluigi printf(" not"); 1053102087Sluigi printf(" MAC"); 1054102087Sluigi flags |= HAVE_MAC; 105598943Sluigi print_mac( m->addr, m->mask); 105698943Sluigi print_mac( m->addr + 6, m->mask + 6); 105798943Sluigi } 105898943Sluigi break; 105998943Sluigi 106098943Sluigi case O_MAC_TYPE: 1061102087Sluigi if ((cmd->len & F_OR) && !or_block) 1062102087Sluigi printf(" {"); 1063102087Sluigi print_newports((ipfw_insn_u16 *)cmd, IPPROTO_ETHERTYPE, 1064102087Sluigi (flags & HAVE_OPTIONS) ? cmd->opcode : 0); 1065102087Sluigi flags |= HAVE_MAC | HAVE_MACTYPE | HAVE_OPTIONS; 106698943Sluigi break; 106798943Sluigi 106898943Sluigi case O_IP_SRC: 106998943Sluigi case O_IP_SRC_MASK: 107098943Sluigi case O_IP_SRC_ME: 107198943Sluigi case O_IP_SRC_SET: 1072102087Sluigi show_prerequisites(&flags, HAVE_PROTO, 0); 107398943Sluigi if (!(flags & HAVE_SRCIP)) 107498943Sluigi printf(" from"); 107598943Sluigi if ((cmd->len & F_OR) && !or_block) 107698943Sluigi printf(" {"); 1077102087Sluigi print_ip((ipfw_insn_ip *)cmd, 1078102087Sluigi (flags & HAVE_OPTIONS) ? " src-ip" : ""); 107998943Sluigi flags |= HAVE_SRCIP; 108098943Sluigi break; 108198943Sluigi 108298943Sluigi case O_IP_DST: 108398943Sluigi case O_IP_DST_MASK: 108498943Sluigi case O_IP_DST_ME: 108598943Sluigi case O_IP_DST_SET: 1086102087Sluigi show_prerequisites(&flags, HAVE_PROTO|HAVE_SRCIP, 0); 108798943Sluigi if (!(flags & HAVE_DSTIP)) 108898943Sluigi printf(" to"); 108998943Sluigi if ((cmd->len & F_OR) && !or_block) 109098943Sluigi printf(" {"); 1091102087Sluigi print_ip((ipfw_insn_ip *)cmd, 1092102087Sluigi (flags & HAVE_OPTIONS) ? " dst-ip" : ""); 109398943Sluigi flags |= HAVE_DSTIP; 109498943Sluigi break; 109598943Sluigi 109698943Sluigi case O_IP_DSTPORT: 1097102087Sluigi show_prerequisites(&flags, HAVE_IP, 0); 109898943Sluigi case O_IP_SRCPORT: 1099102087Sluigi show_prerequisites(&flags, HAVE_PROTO|HAVE_SRCIP, 0); 1100101641Sluigi if ((cmd->len & F_OR) && !or_block) 1101101641Sluigi printf(" {"); 1102102087Sluigi print_newports((ipfw_insn_u16 *)cmd, proto, 1103102087Sluigi (flags & HAVE_OPTIONS) ? cmd->opcode : 0); 110498943Sluigi break; 110598943Sluigi 110698943Sluigi case O_PROTO: { 110798943Sluigi struct protoent *pe; 110898943Sluigi 110998943Sluigi if ((cmd->len & F_OR) && !or_block) 111098943Sluigi printf(" {"); 111198943Sluigi if (cmd->len & F_NOT) 111298943Sluigi printf(" not"); 111398943Sluigi proto = cmd->arg1; 111498943Sluigi pe = getprotobynumber(cmd->arg1); 1115102087Sluigi if (flags & HAVE_OPTIONS) 1116102087Sluigi printf(" proto"); 111798943Sluigi if (pe) 111898943Sluigi printf(" %s", pe->p_name); 111998943Sluigi else 112098943Sluigi printf(" %u", cmd->arg1); 112198943Sluigi } 112298943Sluigi flags |= HAVE_PROTO; 112398943Sluigi break; 1124106505Smaxim 112598943Sluigi default: /*options ... */ 1126102087Sluigi show_prerequisites(&flags, HAVE_IP | HAVE_OPTIONS, 0); 112798943Sluigi if ((cmd->len & F_OR) && !or_block) 112898943Sluigi printf(" {"); 112998943Sluigi if (cmd->len & F_NOT && cmd->opcode != O_IN) 113098943Sluigi printf(" not"); 113198943Sluigi switch(cmd->opcode) { 113298943Sluigi case O_FRAG: 113398943Sluigi printf(" frag"); 113498943Sluigi break; 113598943Sluigi 113698943Sluigi case O_IN: 113798943Sluigi printf(cmd->len & F_NOT ? " out" : " in"); 113898943Sluigi break; 113998943Sluigi 114098943Sluigi case O_LAYER2: 114198943Sluigi printf(" layer2"); 114298943Sluigi break; 114398943Sluigi case O_XMIT: 114498943Sluigi case O_RECV: 114598943Sluigi case O_VIA: { 1146117469Sluigi char const *s; 114798943Sluigi ipfw_insn_if *cmdif = (ipfw_insn_if *)cmd; 114898943Sluigi 114998943Sluigi if (cmd->opcode == O_XMIT) 115098943Sluigi s = "xmit"; 115198943Sluigi else if (cmd->opcode == O_RECV) 115298943Sluigi s = "recv"; 1153117469Sluigi else /* if (cmd->opcode == O_VIA) */ 115498943Sluigi s = "via"; 115598943Sluigi if (cmdif->name[0] == '\0') 115699475Sluigi printf(" %s %s", s, 115799475Sluigi inet_ntoa(cmdif->p.ip)); 115898943Sluigi else if (cmdif->p.unit == -1) 115998943Sluigi printf(" %s %s*", s, cmdif->name); 116098943Sluigi else 116199475Sluigi printf(" %s %s%d", s, cmdif->name, 116299475Sluigi cmdif->p.unit); 116398943Sluigi } 116498943Sluigi break; 116598943Sluigi 116698943Sluigi case O_IPID: 1167116690Sluigi if (F_LEN(cmd) == 1) 1168116690Sluigi printf(" ipid %u", cmd->arg1 ); 1169116690Sluigi else 1170116690Sluigi print_newports((ipfw_insn_u16 *)cmd, 0, 1171116690Sluigi O_IPID); 117298943Sluigi break; 117398943Sluigi 117498943Sluigi case O_IPTTL: 1175116690Sluigi if (F_LEN(cmd) == 1) 1176116690Sluigi printf(" ipttl %u", cmd->arg1 ); 1177116690Sluigi else 1178116690Sluigi print_newports((ipfw_insn_u16 *)cmd, 0, 1179116690Sluigi O_IPTTL); 118098943Sluigi break; 118198943Sluigi 118298943Sluigi case O_IPVER: 118398943Sluigi printf(" ipver %u", cmd->arg1 ); 118498943Sluigi break; 118598943Sluigi 118699475Sluigi case O_IPPRECEDENCE: 118799475Sluigi printf(" ipprecedence %u", (cmd->arg1) >> 5 ); 118899475Sluigi break; 118999475Sluigi 119098943Sluigi case O_IPLEN: 1191116690Sluigi if (F_LEN(cmd) == 1) 1192116690Sluigi printf(" iplen %u", cmd->arg1 ); 1193116690Sluigi else 1194116690Sluigi print_newports((ipfw_insn_u16 *)cmd, 0, 1195116690Sluigi O_IPLEN); 119698943Sluigi break; 119798943Sluigi 1198101116Sluigi case O_IPOPT: 119998943Sluigi print_flags("ipoptions", cmd, f_ipopts); 120098943Sluigi break; 120198943Sluigi 120299475Sluigi case O_IPTOS: 120399475Sluigi print_flags("iptos", cmd, f_iptos); 120499475Sluigi break; 120599475Sluigi 120699475Sluigi case O_ICMPTYPE: 120799475Sluigi print_icmptypes((ipfw_insn_u32 *)cmd); 120899475Sluigi break; 120999475Sluigi 121098943Sluigi case O_ESTAB: 121198943Sluigi printf(" established"); 121298943Sluigi break; 121398943Sluigi 121498943Sluigi case O_TCPFLAGS: 121598943Sluigi print_flags("tcpflags", cmd, f_tcpflags); 121698943Sluigi break; 121798943Sluigi 121898943Sluigi case O_TCPOPTS: 121998943Sluigi print_flags("tcpoptions", cmd, f_tcpopts); 122098943Sluigi break; 122198943Sluigi 122298943Sluigi case O_TCPWIN: 122398943Sluigi printf(" tcpwin %d", ntohs(cmd->arg1)); 122498943Sluigi break; 122598943Sluigi 122698943Sluigi case O_TCPACK: 122798943Sluigi printf(" tcpack %d", ntohl(cmd32->d[0])); 122898943Sluigi break; 122998943Sluigi 123098943Sluigi case O_TCPSEQ: 123198943Sluigi printf(" tcpseq %d", ntohl(cmd32->d[0])); 123298943Sluigi break; 123398943Sluigi 123498943Sluigi case O_UID: 123598943Sluigi { 123698943Sluigi struct passwd *pwd = getpwuid(cmd32->d[0]); 123798943Sluigi 123898943Sluigi if (pwd) 123998943Sluigi printf(" uid %s", pwd->pw_name); 124098943Sluigi else 124198943Sluigi printf(" uid %u", cmd32->d[0]); 124298943Sluigi } 124398943Sluigi break; 124498943Sluigi 124598943Sluigi case O_GID: 124698943Sluigi { 124798943Sluigi struct group *grp = getgrgid(cmd32->d[0]); 124898943Sluigi 124998943Sluigi if (grp) 125098943Sluigi printf(" gid %s", grp->gr_name); 125198943Sluigi else 125298943Sluigi printf(" gid %u", cmd32->d[0]); 125398943Sluigi } 125498943Sluigi break; 125598943Sluigi 1256112250Scjc case O_VERREVPATH: 1257112250Scjc printf(" verrevpath"); 1258112250Scjc break; 1259116919Sluigi 1260117241Sluigi case O_IPSEC: 1261117241Sluigi printf(" ipsec"); 1262117241Sluigi break; 1263117241Sluigi 1264117469Sluigi case O_NOP: 1265117469Sluigi printf(" // %s", (char *)(cmd + 1)); 1266117469Sluigi break; 1267117469Sluigi 126898943Sluigi case O_KEEP_STATE: 126998943Sluigi printf(" keep-state"); 127098943Sluigi break; 127198943Sluigi 127298943Sluigi case O_LIMIT: 127398943Sluigi { 127498943Sluigi struct _s_x *p = limit_masks; 127598943Sluigi ipfw_insn_limit *c = (ipfw_insn_limit *)cmd; 1276117328Sluigi uint8_t x = c->limit_mask; 1277117469Sluigi char const *comma = " "; 127898943Sluigi 127998943Sluigi printf(" limit"); 1280106505Smaxim for ( ; p->x != 0 ; p++) 128199909Sluigi if ((x & p->x) == p->x) { 128298943Sluigi x &= ~p->x; 128398943Sluigi printf("%s%s", comma, p->s); 128498943Sluigi comma = ","; 128598943Sluigi } 128698943Sluigi printf(" %d", c->conn_limit); 128798943Sluigi } 128898943Sluigi break; 128998943Sluigi 129098943Sluigi default: 129198943Sluigi printf(" [opcode %d len %d]", 129298943Sluigi cmd->opcode, cmd->len); 129398943Sluigi } 129498943Sluigi } 129598943Sluigi if (cmd->len & F_OR) { 129698943Sluigi printf(" or"); 129798943Sluigi or_block = 1; 129898943Sluigi } else if (or_block) { 129998943Sluigi printf(" }"); 130098943Sluigi or_block = 0; 130198943Sluigi } 130298943Sluigi } 1303102087Sluigi show_prerequisites(&flags, HAVE_IP, 0); 130498943Sluigi 130598943Sluigi printf("\n"); 130698943Sluigi} 130798943Sluigi 130898943Sluigistatic void 1309112189Smaximshow_dyn_ipfw(ipfw_dyn_rule *d, int pcwidth, int bcwidth) 131098943Sluigi{ 131198943Sluigi struct protoent *pe; 131298943Sluigi struct in_addr a; 1313115793Sticso uint16_t rulenum; 131498943Sluigi 131598943Sluigi if (!do_expired) { 131698943Sluigi if (!d->expire && !(d->dyn_type == O_LIMIT_PARENT)) 131798943Sluigi return; 131898943Sluigi } 1319115793Sticso bcopy(&d->rule, &rulenum, sizeof(rulenum)); 1320117328Sluigi printf("%05d", rulenum); 1321117469Sluigi if (pcwidth>0 || bcwidth>0) 1322117328Sluigi printf(" %*llu %*llu (%ds)", pcwidth, 1323117328Sluigi align_uint64(&d->pcnt), bcwidth, 1324117328Sluigi align_uint64(&d->bcnt), d->expire); 132598943Sluigi switch (d->dyn_type) { 132698943Sluigi case O_LIMIT_PARENT: 132798943Sluigi printf(" PARENT %d", d->count); 132898943Sluigi break; 132998943Sluigi case O_LIMIT: 133098943Sluigi printf(" LIMIT"); 133198943Sluigi break; 133298943Sluigi case O_KEEP_STATE: /* bidir, no mask */ 1333106505Smaxim printf(" STATE"); 133498943Sluigi break; 133598943Sluigi } 133698943Sluigi 133798943Sluigi if ((pe = getprotobynumber(d->id.proto)) != NULL) 133898943Sluigi printf(" %s", pe->p_name); 133998943Sluigi else 134098943Sluigi printf(" proto %u", d->id.proto); 134198943Sluigi 134298943Sluigi a.s_addr = htonl(d->id.src_ip); 134398943Sluigi printf(" %s %d", inet_ntoa(a), d->id.src_port); 134498943Sluigi 134598943Sluigi a.s_addr = htonl(d->id.dst_ip); 134698943Sluigi printf(" <-> %s %d", inet_ntoa(a), d->id.dst_port); 134798943Sluigi printf("\n"); 134898943Sluigi} 134998943Sluigi 1350117469Sluigistatic int 135198943Sluigisort_q(const void *pa, const void *pb) 135298943Sluigi{ 135398943Sluigi int rev = (do_sort < 0); 135498943Sluigi int field = rev ? -do_sort : do_sort; 135598943Sluigi long long res = 0; 135698943Sluigi const struct dn_flow_queue *a = pa; 135798943Sluigi const struct dn_flow_queue *b = pb; 135898943Sluigi 135998943Sluigi switch (field) { 136098943Sluigi case 1: /* pkts */ 136198943Sluigi res = a->len - b->len; 136298943Sluigi break; 136398943Sluigi case 2: /* bytes */ 136498943Sluigi res = a->len_bytes - b->len_bytes; 136598943Sluigi break; 136698943Sluigi 136798943Sluigi case 3: /* tot pkts */ 136898943Sluigi res = a->tot_pkts - b->tot_pkts; 136998943Sluigi break; 137098943Sluigi 137198943Sluigi case 4: /* tot bytes */ 137298943Sluigi res = a->tot_bytes - b->tot_bytes; 137398943Sluigi break; 137498943Sluigi } 137598943Sluigi if (res < 0) 137698943Sluigi res = -1; 137798943Sluigi if (res > 0) 137898943Sluigi res = 1; 137998943Sluigi return (int)(rev ? res : -res); 138098943Sluigi} 138198943Sluigi 138298943Sluigistatic void 138398943Sluigilist_queues(struct dn_flow_set *fs, struct dn_flow_queue *q) 138498943Sluigi{ 138598943Sluigi int l; 138698943Sluigi 138798943Sluigi printf(" mask: 0x%02x 0x%08x/0x%04x -> 0x%08x/0x%04x\n", 138898943Sluigi fs->flow_mask.proto, 138998943Sluigi fs->flow_mask.src_ip, fs->flow_mask.src_port, 139098943Sluigi fs->flow_mask.dst_ip, fs->flow_mask.dst_port); 139198943Sluigi if (fs->rq_elements == 0) 139298943Sluigi return; 139398943Sluigi 139498943Sluigi printf("BKT Prot ___Source IP/port____ " 139598943Sluigi "____Dest. IP/port____ Tot_pkt/bytes Pkt/Byte Drp\n"); 139698943Sluigi if (do_sort != 0) 139798943Sluigi heapsort(q, fs->rq_elements, sizeof *q, sort_q); 139898943Sluigi for (l = 0; l < fs->rq_elements; l++) { 139998943Sluigi struct in_addr ina; 140098943Sluigi struct protoent *pe; 140198943Sluigi 140298943Sluigi ina.s_addr = htonl(q[l].id.src_ip); 140398943Sluigi printf("%3d ", q[l].hash_slot); 140498943Sluigi pe = getprotobynumber(q[l].id.proto); 140598943Sluigi if (pe) 140698943Sluigi printf("%-4s ", pe->p_name); 140798943Sluigi else 140898943Sluigi printf("%4u ", q[l].id.proto); 140998943Sluigi printf("%15s/%-5d ", 141098943Sluigi inet_ntoa(ina), q[l].id.src_port); 141198943Sluigi ina.s_addr = htonl(q[l].id.dst_ip); 141298943Sluigi printf("%15s/%-5d ", 141398943Sluigi inet_ntoa(ina), q[l].id.dst_port); 141498943Sluigi printf("%4qu %8qu %2u %4u %3u\n", 141598943Sluigi q[l].tot_pkts, q[l].tot_bytes, 141698943Sluigi q[l].len, q[l].len_bytes, q[l].drops); 141798943Sluigi if (verbose) 141898943Sluigi printf(" S %20qd F %20qd\n", 141998943Sluigi q[l].S, q[l].F); 142098943Sluigi } 142198943Sluigi} 142298943Sluigi 142398943Sluigistatic void 142498943Sluigiprint_flowset_parms(struct dn_flow_set *fs, char *prefix) 142598943Sluigi{ 142698943Sluigi int l; 142798943Sluigi char qs[30]; 142898943Sluigi char plr[30]; 142998943Sluigi char red[90]; /* Display RED parameters */ 143098943Sluigi 143198943Sluigi l = fs->qsize; 143298943Sluigi if (fs->flags_fs & DN_QSIZE_IS_BYTES) { 143398943Sluigi if (l >= 8192) 143498943Sluigi sprintf(qs, "%d KB", l / 1024); 143598943Sluigi else 143698943Sluigi sprintf(qs, "%d B", l); 143798943Sluigi } else 143898943Sluigi sprintf(qs, "%3d sl.", l); 143998943Sluigi if (fs->plr) 144098943Sluigi sprintf(plr, "plr %f", 1.0 * fs->plr / (double)(0x7fffffff)); 144198943Sluigi else 144298943Sluigi plr[0] = '\0'; 144398943Sluigi if (fs->flags_fs & DN_IS_RED) /* RED parameters */ 144498943Sluigi sprintf(red, 144598943Sluigi "\n\t %cRED w_q %f min_th %d max_th %d max_p %f", 144698943Sluigi (fs->flags_fs & DN_IS_GENTLE_RED) ? 'G' : ' ', 144798943Sluigi 1.0 * fs->w_q / (double)(1 << SCALE_RED), 144898943Sluigi SCALE_VAL(fs->min_th), 144998943Sluigi SCALE_VAL(fs->max_th), 145098943Sluigi 1.0 * fs->max_p / (double)(1 << SCALE_RED)); 145198943Sluigi else 145298943Sluigi sprintf(red, "droptail"); 145398943Sluigi 145498943Sluigi printf("%s %s%s %d queues (%d buckets) %s\n", 145598943Sluigi prefix, qs, plr, fs->rq_elements, fs->rq_size, red); 145698943Sluigi} 145798943Sluigi 145898943Sluigistatic void 1459117469Sluigilist_pipes(void *data, uint nbytes, int ac, char *av[]) 146098943Sluigi{ 1461117469Sluigi int rulenum; 146298943Sluigi void *next = data; 146398943Sluigi struct dn_pipe *p = (struct dn_pipe *) data; 146498943Sluigi struct dn_flow_set *fs; 146598943Sluigi struct dn_flow_queue *q; 146698943Sluigi int l; 146798943Sluigi 146898943Sluigi if (ac > 0) 146998943Sluigi rulenum = strtoul(*av++, NULL, 10); 147098943Sluigi else 147198943Sluigi rulenum = 0; 147298943Sluigi for (; nbytes >= sizeof *p; p = (struct dn_pipe *)next) { 147398943Sluigi double b = p->bandwidth; 147498943Sluigi char buf[30]; 147598943Sluigi char prefix[80]; 147698943Sluigi 147798943Sluigi if (p->next != (struct dn_pipe *)DN_IS_PIPE) 147898943Sluigi break; /* done with pipes, now queues */ 147998943Sluigi 148098943Sluigi /* 148198943Sluigi * compute length, as pipe have variable size 148298943Sluigi */ 148398943Sluigi l = sizeof(*p) + p->fs.rq_elements * sizeof(*q); 1484117469Sluigi next = (char *)p + l; 148598943Sluigi nbytes -= l; 148698943Sluigi 148798943Sluigi if (rulenum != 0 && rulenum != p->pipe_nr) 148898943Sluigi continue; 148998943Sluigi 149098943Sluigi /* 149198943Sluigi * Print rate (or clocking interface) 149298943Sluigi */ 149398943Sluigi if (p->if_name[0] != '\0') 149498943Sluigi sprintf(buf, "%s", p->if_name); 149598943Sluigi else if (b == 0) 149698943Sluigi sprintf(buf, "unlimited"); 149798943Sluigi else if (b >= 1000000) 149898943Sluigi sprintf(buf, "%7.3f Mbit/s", b/1000000); 149998943Sluigi else if (b >= 1000) 150098943Sluigi sprintf(buf, "%7.3f Kbit/s", b/1000); 150198943Sluigi else 150298943Sluigi sprintf(buf, "%7.3f bit/s ", b); 150398943Sluigi 150498943Sluigi sprintf(prefix, "%05d: %s %4d ms ", 150598943Sluigi p->pipe_nr, buf, p->delay); 150698943Sluigi print_flowset_parms(&(p->fs), prefix); 150798943Sluigi if (verbose) 150898943Sluigi printf(" V %20qd\n", p->V >> MY_M); 1509106505Smaxim 151098943Sluigi q = (struct dn_flow_queue *)(p+1); 151198943Sluigi list_queues(&(p->fs), q); 151298943Sluigi } 151398943Sluigi for (fs = next; nbytes >= sizeof *fs; fs = next) { 151498943Sluigi char prefix[80]; 151598943Sluigi 151698943Sluigi if (fs->next != (struct dn_flow_set *)DN_IS_QUEUE) 151798943Sluigi break; 151898943Sluigi l = sizeof(*fs) + fs->rq_elements * sizeof(*q); 1519117469Sluigi next = (char *)fs + l; 152098943Sluigi nbytes -= l; 152198943Sluigi q = (struct dn_flow_queue *)(fs+1); 152298943Sluigi sprintf(prefix, "q%05d: weight %d pipe %d ", 152398943Sluigi fs->fs_nr, fs->weight, fs->parent_nr); 152498943Sluigi print_flowset_parms(fs, prefix); 152598943Sluigi list_queues(fs, q); 152698943Sluigi } 152798943Sluigi} 152898943Sluigi 1529101978Sluigi/* 1530101978Sluigi * This one handles all set-related commands 1531101978Sluigi * ipfw set { show | enable | disable } 1532101978Sluigi * ipfw set swap X Y 1533101978Sluigi * ipfw set move X to Y 1534101978Sluigi * ipfw set move rule X to Y 1535101978Sluigi */ 153698943Sluigistatic void 1537101978Sluigisets_handler(int ac, char *av[]) 1538101978Sluigi{ 1539117328Sluigi uint32_t set_disable, masks[2]; 1540101978Sluigi int i, nbytes; 1541117328Sluigi uint16_t rulenum; 1542117328Sluigi uint8_t cmd, new_set; 1543101978Sluigi 1544101978Sluigi ac--; 1545101978Sluigi av++; 1546101978Sluigi 1547101978Sluigi if (!ac) 1548101978Sluigi errx(EX_USAGE, "set needs command"); 1549101978Sluigi if (!strncmp(*av, "show", strlen(*av)) ) { 1550101978Sluigi void *data; 1551117469Sluigi char const *msg; 1552101978Sluigi 1553101978Sluigi nbytes = sizeof(struct ip_fw); 1554117328Sluigi if ((data = calloc(1, nbytes)) == NULL) 1555117328Sluigi err(EX_OSERR, "calloc"); 1556117328Sluigi if (do_cmd(IP_FW_GET, data, (socklen_t)&nbytes) < 0) 1557101978Sluigi err(EX_OSERR, "getsockopt(IP_FW_GET)"); 1558115793Sticso bcopy(&((struct ip_fw *)data)->next_rule, 1559115793Sticso &set_disable, sizeof(set_disable)); 1560101978Sluigi 1561101978Sluigi for (i = 0, msg = "disable" ; i < 31; i++) 1562101978Sluigi if ( (set_disable & (1<<i))) { 1563101978Sluigi printf("%s %d", msg, i); 1564101978Sluigi msg = ""; 1565101978Sluigi } 1566101978Sluigi msg = (set_disable) ? " enable" : "enable"; 1567101978Sluigi for (i = 0; i < 31; i++) 1568101978Sluigi if ( !(set_disable & (1<<i))) { 1569101978Sluigi printf("%s %d", msg, i); 1570101978Sluigi msg = ""; 1571101978Sluigi } 1572101978Sluigi printf("\n"); 1573101978Sluigi } else if (!strncmp(*av, "swap", strlen(*av))) { 1574101978Sluigi ac--; av++; 1575101978Sluigi if (ac != 2) 1576101978Sluigi errx(EX_USAGE, "set swap needs 2 set numbers\n"); 1577101978Sluigi rulenum = atoi(av[0]); 1578101978Sluigi new_set = atoi(av[1]); 1579101978Sluigi if (!isdigit(*(av[0])) || rulenum > 30) 1580101978Sluigi errx(EX_DATAERR, "invalid set number %s\n", av[0]); 1581101978Sluigi if (!isdigit(*(av[1])) || new_set > 30) 1582101978Sluigi errx(EX_DATAERR, "invalid set number %s\n", av[1]); 1583101978Sluigi masks[0] = (4 << 24) | (new_set << 16) | (rulenum); 1584117328Sluigi i = do_cmd(IP_FW_DEL, masks, sizeof(uint32_t)); 1585101978Sluigi } else if (!strncmp(*av, "move", strlen(*av))) { 1586101978Sluigi ac--; av++; 1587101978Sluigi if (ac && !strncmp(*av, "rule", strlen(*av))) { 1588101978Sluigi cmd = 2; 1589101978Sluigi ac--; av++; 1590101978Sluigi } else 1591101978Sluigi cmd = 3; 1592101978Sluigi if (ac != 3 || strncmp(av[1], "to", strlen(*av))) 1593101978Sluigi errx(EX_USAGE, "syntax: set move [rule] X to Y\n"); 1594101978Sluigi rulenum = atoi(av[0]); 1595101978Sluigi new_set = atoi(av[2]); 1596101978Sluigi if (!isdigit(*(av[0])) || (cmd == 3 && rulenum > 30) || 1597101978Sluigi (cmd == 2 && rulenum == 65535) ) 1598101978Sluigi errx(EX_DATAERR, "invalid source number %s\n", av[0]); 1599101978Sluigi if (!isdigit(*(av[2])) || new_set > 30) 1600101978Sluigi errx(EX_DATAERR, "invalid dest. set %s\n", av[1]); 1601101978Sluigi masks[0] = (cmd << 24) | (new_set << 16) | (rulenum); 1602117328Sluigi i = do_cmd(IP_FW_DEL, masks, sizeof(uint32_t)); 1603101978Sluigi } else if (!strncmp(*av, "disable", strlen(*av)) || 1604101978Sluigi !strncmp(*av, "enable", strlen(*av)) ) { 1605101978Sluigi int which = !strncmp(*av, "enable", strlen(*av)) ? 1 : 0; 1606101978Sluigi 1607101978Sluigi ac--; av++; 1608101978Sluigi masks[0] = masks[1] = 0; 1609101978Sluigi 1610101978Sluigi while (ac) { 1611101978Sluigi if (isdigit(**av)) { 1612101978Sluigi i = atoi(*av); 1613101978Sluigi if (i < 0 || i > 30) 1614101978Sluigi errx(EX_DATAERR, 1615101978Sluigi "invalid set number %d\n", i); 1616101978Sluigi masks[which] |= (1<<i); 1617101978Sluigi } else if (!strncmp(*av, "disable", strlen(*av))) 1618101978Sluigi which = 0; 1619101978Sluigi else if (!strncmp(*av, "enable", strlen(*av))) 1620101978Sluigi which = 1; 1621101978Sluigi else 1622101978Sluigi errx(EX_DATAERR, 1623101978Sluigi "invalid set command %s\n", *av); 1624101978Sluigi av++; ac--; 1625101978Sluigi } 1626101978Sluigi if ( (masks[0] & masks[1]) != 0 ) 1627101978Sluigi errx(EX_DATAERR, 1628101978Sluigi "cannot enable and disable the same set\n"); 1629101978Sluigi 1630117328Sluigi i = do_cmd(IP_FW_DEL, masks, sizeof(masks)); 1631101978Sluigi if (i) 1632101978Sluigi warn("set enable/disable: setsockopt(IP_FW_DEL)"); 1633101978Sluigi } else 1634101978Sluigi errx(EX_USAGE, "invalid set command %s\n", *av); 1635101978Sluigi} 1636101978Sluigi 1637101978Sluigistatic void 1638109126Sdillonsysctl_handler(int ac, char *av[], int which) 1639109126Sdillon{ 1640109126Sdillon ac--; 1641109126Sdillon av++; 1642109126Sdillon 1643109126Sdillon if (*av == NULL) { 1644109126Sdillon warnx("missing keyword to enable/disable\n"); 1645109126Sdillon } else if (strncmp(*av, "firewall", strlen(*av)) == 0) { 1646116770Sluigi sysctlbyname("net.inet.ip.fw.enable", NULL, 0, 1647116770Sluigi &which, sizeof(which)); 1648109126Sdillon } else if (strncmp(*av, "one_pass", strlen(*av)) == 0) { 1649116770Sluigi sysctlbyname("net.inet.ip.fw.one_pass", NULL, 0, 1650116770Sluigi &which, sizeof(which)); 1651109126Sdillon } else if (strncmp(*av, "debug", strlen(*av)) == 0) { 1652116770Sluigi sysctlbyname("net.inet.ip.fw.debug", NULL, 0, 1653116770Sluigi &which, sizeof(which)); 1654109126Sdillon } else if (strncmp(*av, "verbose", strlen(*av)) == 0) { 1655116770Sluigi sysctlbyname("net.inet.ip.fw.verbose", NULL, 0, 1656116770Sluigi &which, sizeof(which)); 1657109126Sdillon } else if (strncmp(*av, "dyn_keepalive", strlen(*av)) == 0) { 1658116770Sluigi sysctlbyname("net.inet.ip.fw.dyn_keepalive", NULL, 0, 1659116770Sluigi &which, sizeof(which)); 1660109126Sdillon } else { 1661109126Sdillon warnx("unrecognize enable/disable keyword: %s\n", *av); 1662109126Sdillon } 1663109126Sdillon} 1664109126Sdillon 1665109126Sdillonstatic void 1666117469Sluigilist(int ac, char *av[], int show_counters) 166798943Sluigi{ 166898943Sluigi struct ip_fw *r; 166998943Sluigi ipfw_dyn_rule *dynrules, *d; 167098943Sluigi 1671117469Sluigi#define NEXT(r) ((struct ip_fw *)((char *)r + RULESIZE(r))) 1672117469Sluigi char *lim; 1673117469Sluigi void *data = NULL; 1674112189Smaxim int bcwidth, n, nbytes, nstat, ndyn, pcwidth, width; 167598943Sluigi int exitval = EX_OK; 167698943Sluigi int lac; 167798943Sluigi char **lav; 1678117469Sluigi u_long rnum, last; 167998943Sluigi char *endptr; 168098943Sluigi int seen = 0; 168198943Sluigi 168298943Sluigi const int ocmd = do_pipe ? IP_DUMMYNET_GET : IP_FW_GET; 168398943Sluigi int nalloc = 1024; /* start somewhere... */ 168498943Sluigi 1685117328Sluigi if (test_only) { 1686117328Sluigi fprintf(stderr, "Testing only, list disabled\n"); 1687117328Sluigi return; 1688117328Sluigi } 1689117328Sluigi 169098943Sluigi ac--; 169198943Sluigi av++; 169298943Sluigi 169398943Sluigi /* get rules or pipes from kernel, resizing array as necessary */ 169498943Sluigi nbytes = nalloc; 169598943Sluigi 169698943Sluigi while (nbytes >= nalloc) { 169798943Sluigi nalloc = nalloc * 2 + 200; 169898943Sluigi nbytes = nalloc; 169998943Sluigi if ((data = realloc(data, nbytes)) == NULL) 170098943Sluigi err(EX_OSERR, "realloc"); 1701117328Sluigi if (do_cmd(ocmd, data, (socklen_t)&nbytes) < 0) 170298943Sluigi err(EX_OSERR, "getsockopt(IP_%s_GET)", 170398943Sluigi do_pipe ? "DUMMYNET" : "FW"); 170498943Sluigi } 170598943Sluigi 170698943Sluigi if (do_pipe) { 170798943Sluigi list_pipes(data, nbytes, ac, av); 170898943Sluigi goto done; 170998943Sluigi } 171098943Sluigi 171198943Sluigi /* 171298943Sluigi * Count static rules. They have variable size so we 171398943Sluigi * need to scan the list to count them. 171498943Sluigi */ 1715117469Sluigi for (nstat = 1, r = data, lim = (char *)data + nbytes; 1716117469Sluigi r->rulenum < 65535 && (char *)r < lim; 1717117469Sluigi ++nstat, r = NEXT(r) ) 171898943Sluigi ; /* nothing */ 171998943Sluigi 172098943Sluigi /* 172198943Sluigi * Count dynamic rules. This is easier as they have 172298943Sluigi * fixed size. 172398943Sluigi */ 1724117469Sluigi r = NEXT(r); 172598943Sluigi dynrules = (ipfw_dyn_rule *)r ; 1726117469Sluigi n = (char *)r - (char *)data; 172798943Sluigi ndyn = (nbytes - n) / sizeof *dynrules; 172898943Sluigi 1729112189Smaxim /* if showing stats, figure out column widths ahead of time */ 1730112189Smaxim bcwidth = pcwidth = 0; 1731117469Sluigi if (show_counters) { 1732117469Sluigi for (n = 0, r = data; n < nstat; n++, r = NEXT(r)) { 1733112189Smaxim /* packet counter */ 1734115793Sticso width = snprintf(NULL, 0, "%llu", 1735115793Sticso align_uint64(&r->pcnt)); 1736112189Smaxim if (width > pcwidth) 1737112189Smaxim pcwidth = width; 1738112189Smaxim 1739112189Smaxim /* byte counter */ 1740115793Sticso width = snprintf(NULL, 0, "%llu", 1741115793Sticso align_uint64(&r->bcnt)); 1742112189Smaxim if (width > bcwidth) 1743112189Smaxim bcwidth = width; 1744112189Smaxim } 1745112189Smaxim } 1746112189Smaxim if (do_dynamic && ndyn) { 1747112189Smaxim for (n = 0, d = dynrules; n < ndyn; n++, d++) { 1748115793Sticso width = snprintf(NULL, 0, "%llu", 1749115793Sticso align_uint64(&d->pcnt)); 1750112189Smaxim if (width > pcwidth) 1751112189Smaxim pcwidth = width; 1752112189Smaxim 1753115793Sticso width = snprintf(NULL, 0, "%llu", 1754115793Sticso align_uint64(&d->bcnt)); 1755112189Smaxim if (width > bcwidth) 1756112189Smaxim bcwidth = width; 1757112189Smaxim } 1758112189Smaxim } 175998943Sluigi /* if no rule numbers were specified, list all rules */ 176098943Sluigi if (ac == 0) { 1761117469Sluigi for (n = 0, r = data; n < nstat; n++, r = NEXT(r) ) 1762112189Smaxim show_ipfw(r, pcwidth, bcwidth); 176398943Sluigi 176498943Sluigi if (do_dynamic && ndyn) { 176598943Sluigi printf("## Dynamic rules (%d):\n", ndyn); 176698943Sluigi for (n = 0, d = dynrules; n < ndyn; n++, d++) 1767112189Smaxim show_dyn_ipfw(d, pcwidth, bcwidth); 176898943Sluigi } 176998943Sluigi goto done; 177098943Sluigi } 177198943Sluigi 177298943Sluigi /* display specific rules requested on command line */ 177398943Sluigi 177498943Sluigi for (lac = ac, lav = av; lac != 0; lac--) { 177598943Sluigi /* convert command line rule # */ 1776117469Sluigi last = rnum = strtoul(*lav++, &endptr, 10); 1777117469Sluigi if (*endptr == '-') 1778117469Sluigi last = strtoul(endptr+1, &endptr, 10); 177998943Sluigi if (*endptr) { 1780117469Sluigi 178198943Sluigi exitval = EX_USAGE; 178298943Sluigi warnx("invalid rule number: %s", *(lav - 1)); 178398943Sluigi continue; 178498943Sluigi } 1785117469Sluigi for (n = seen = 0, r = data; n < nstat; n++, r = NEXT(r) ) { 1786117469Sluigi if (r->rulenum > last) 178798943Sluigi break; 1788117469Sluigi if (r->rulenum >= rnum && r->rulenum <= last) { 1789112189Smaxim show_ipfw(r, pcwidth, bcwidth); 179098943Sluigi seen = 1; 179198943Sluigi } 179298943Sluigi } 179398943Sluigi if (!seen) { 179498943Sluigi /* give precedence to other error(s) */ 179598943Sluigi if (exitval == EX_OK) 179698943Sluigi exitval = EX_UNAVAILABLE; 179798943Sluigi warnx("rule %lu does not exist", rnum); 179898943Sluigi } 179998943Sluigi } 180098943Sluigi 180198943Sluigi if (do_dynamic && ndyn) { 180298943Sluigi printf("## Dynamic rules:\n"); 180398943Sluigi for (lac = ac, lav = av; lac != 0; lac--) { 180498943Sluigi rnum = strtoul(*lav++, &endptr, 10); 1805117469Sluigi if (*endptr == '-') 1806117469Sluigi last = strtoul(endptr+1, &endptr, 10); 180798943Sluigi if (*endptr) 180898943Sluigi /* already warned */ 180998943Sluigi continue; 181098943Sluigi for (n = 0, d = dynrules; n < ndyn; n++, d++) { 1811115793Sticso uint16_t rulenum; 1812115793Sticso 1813115793Sticso bcopy(&d->rule, &rulenum, sizeof(rulenum)); 1814115793Sticso if (rulenum > rnum) 181598943Sluigi break; 1816117469Sluigi if (r->rulenum >= rnum && r->rulenum <= last) 1817112189Smaxim show_dyn_ipfw(d, pcwidth, bcwidth); 181898943Sluigi } 181998943Sluigi } 182098943Sluigi } 182198943Sluigi 182298943Sluigi ac = 0; 182398943Sluigi 182498943Sluigidone: 182598943Sluigi free(data); 182698943Sluigi 182798943Sluigi if (exitval != EX_OK) 182898943Sluigi exit(exitval); 1829117469Sluigi#undef NEXT 183098943Sluigi} 183198943Sluigi 183298943Sluigistatic void 183398943Sluigishow_usage(void) 183498943Sluigi{ 183598943Sluigi fprintf(stderr, "usage: ipfw [options]\n" 183698943Sluigi"do \"ipfw -h\" or see ipfw manpage for details\n" 183798943Sluigi); 183898943Sluigi exit(EX_USAGE); 183998943Sluigi} 184098943Sluigi 184198943Sluigistatic void 184298943Sluigihelp(void) 184398943Sluigi{ 1844117328Sluigi fprintf(stderr, 1845117328Sluigi"ipfw syntax summary (but please do read the ipfw(8) manpage):\n" 1846117328Sluigi"ipfw [-acdeftnNpqS] command:" 1847117328Sluigi"add [num] [set N] [prob x] RULE-BODY\n" 1848117328Sluigi"{pipe|queue} N config PIPE-BODY\n" 1849117328Sluigi"[pipe|queue] {zero|delete|show} [N{,N}]\n" 1850117328Sluigi"set [disable N... enable N...] | move [rule] X to Y | swap X Y | show\n" 185198943Sluigi"\n" 1852117328Sluigi"RULE-BODY: check-state [LOG] | ACTION [LOG] ADDR [OPTION_LIST]\n" 185398943Sluigi"ACTION: check-state | allow | count | deny | reject | skipto N |\n" 185498943Sluigi" {divert|tee} PORT | forward ADDR | pipe N | queue N\n" 185598943Sluigi"ADDR: [ MAC dst src ether_type ] \n" 185698943Sluigi" [ from IPLIST [ PORT ] to IPLIST [ PORTLIST ] ]\n" 1857117328Sluigi"IPLIST: IPADDR[,IPADDR] | { IPADDR or ... or IPADDR }\n" 185898943Sluigi"IPADDR: [not] { any | me | ip | ip/bits | ip:mask | ip/bits{x,y,z} }\n" 185998943Sluigi"OPTION_LIST: OPTION [,OPTION_LIST]\n" 1860117328Sluigi"OPTION: bridged | {dst-ip|src-ip} ADDR | {dst-port|src-port} LIST |\n" 1861117328Sluigi" estab | frag | {gid|uid} N | icmptypes LIST | in | out | ipid LIST |\n" 1862117328Sluigi" iplen LIST | ipoptions SPEC | ipprecedence | ipsec | iptos SPEC |\n" 1863117328Sluigi" ipttl LIST | ipversion VER | keep-state | layer2 | limit ... |\n" 1864117328Sluigi" mac ... | mac-type LIST | proto LIST | {recv|xmit|via} {IF|IPADDR} |\n" 1865117328Sluigi" setup | {tcpack|tcpseq|tcpwin} NN | tcpflags SPEC | tcpoptions SPEC |\n" 1866117328Sluigi" verrevpath\n" 186798943Sluigi); 186898943Sluigiexit(0); 186998943Sluigi} 187098943Sluigi 187198943Sluigi 187298943Sluigistatic int 187398943Sluigilookup_host (char *host, struct in_addr *ipaddr) 187498943Sluigi{ 187598943Sluigi struct hostent *he; 187698943Sluigi 187798943Sluigi if (!inet_aton(host, ipaddr)) { 187898943Sluigi if ((he = gethostbyname(host)) == NULL) 187998943Sluigi return(-1); 188098943Sluigi *ipaddr = *(struct in_addr *)he->h_addr_list[0]; 188198943Sluigi } 188298943Sluigi return(0); 188398943Sluigi} 188498943Sluigi 188598943Sluigi/* 188698943Sluigi * fills the addr and mask fields in the instruction as appropriate from av. 188798943Sluigi * Update length as appropriate. 188898943Sluigi * The following formats are allowed: 188998943Sluigi * any matches any IP. Actually returns an empty instruction. 189098943Sluigi * me returns O_IP_*_ME 189198943Sluigi * 1.2.3.4 single IP address 189298943Sluigi * 1.2.3.4:5.6.7.8 address:mask 189398943Sluigi * 1.2.3.4/24 address/mask 189498943Sluigi * 1.2.3.4/26{1,6,5,4,23} set of addresses in a subnet 1895117328Sluigi * We can have multiple comma-separated address/mask entries. 189698943Sluigi */ 189798943Sluigistatic void 189898943Sluigifill_ip(ipfw_insn_ip *cmd, char *av) 189998943Sluigi{ 1900117328Sluigi int len = 0; 1901117328Sluigi uint32_t *d = ((ipfw_insn_u32 *)cmd)->d; 190298943Sluigi 190398943Sluigi cmd->o.len &= ~F_LEN_MASK; /* zero len */ 190498943Sluigi 190598943Sluigi if (!strncmp(av, "any", strlen(av))) 190698943Sluigi return; 190798943Sluigi 190898943Sluigi if (!strncmp(av, "me", strlen(av))) { 190998943Sluigi cmd->o.len |= F_INSN_SIZE(ipfw_insn); 191098943Sluigi return; 191198943Sluigi } 191298943Sluigi 1913117328Sluigi while (av) { 1914117328Sluigi /* 1915117328Sluigi * After the address we can have '/' or ':' indicating a mask, 1916117328Sluigi * ',' indicating another address follows, '{' indicating a 1917117328Sluigi * set of addresses of unspecified size. 1918117328Sluigi */ 1919117328Sluigi char *p = strpbrk(av, "/:,{"); 1920117328Sluigi int masklen; 1921117328Sluigi char md; 1922117328Sluigi 192398943Sluigi if (p) { 192498943Sluigi md = *p; 192598943Sluigi *p++ = '\0'; 1926117328Sluigi } else 1927117328Sluigi md = '\0'; 192898943Sluigi 1929117328Sluigi if (lookup_host(av, (struct in_addr *)&d[0]) != 0) 193098943Sluigi errx(EX_NOHOST, "hostname ``%s'' unknown", av); 193198943Sluigi switch (md) { 193298943Sluigi case ':': 1933117328Sluigi if (!inet_aton(p, (struct in_addr *)&d[1])) 193498943Sluigi errx(EX_DATAERR, "bad netmask ``%s''", p); 193598943Sluigi break; 193698943Sluigi case '/': 1937117328Sluigi masklen = atoi(p); 1938117328Sluigi if (masklen == 0) 1939117328Sluigi d[1] = htonl(0); /* mask */ 1940117328Sluigi else if (masklen > 32) 194198943Sluigi errx(EX_DATAERR, "bad width ``%s''", p); 194298943Sluigi else 1943117328Sluigi d[1] = htonl(~0 << (32 - masklen)); 194498943Sluigi break; 1945117328Sluigi case '{': /* no mask, assume /24 and put back the '{' */ 1946117328Sluigi d[1] = htonl(~0 << (32 - 24)); 1947117328Sluigi *(--p) = md; 1948117328Sluigi break; 1949117328Sluigi 1950117328Sluigi case ',': /* single address plus continuation */ 1951117328Sluigi *(--p) = md; 1952117328Sluigi /* FALLTHROUGH */ 1953117328Sluigi case 0: /* initialization value */ 195498943Sluigi default: 1955117328Sluigi d[1] = htonl(~0); /* force /32 */ 195698943Sluigi break; 195798943Sluigi } 1958117328Sluigi d[0] &= d[1]; /* mask base address with mask */ 1959117328Sluigi /* find next separator */ 196098943Sluigi if (p) 1961117328Sluigi p = strpbrk(p, ",{"); 1962117328Sluigi if (p && *p == '{') { 1963117328Sluigi /* 1964117328Sluigi * We have a set of addresses. They are stored as follows: 1965117328Sluigi * arg1 is the set size (powers of 2, 2..256) 1966117328Sluigi * addr is the base address IN HOST FORMAT 1967117328Sluigi * mask.. is an array of arg1 bits (rounded up to 1968117328Sluigi * the next multiple of 32) with bits set 1969117328Sluigi * for each host in the map. 1970117328Sluigi */ 1971117328Sluigi uint32_t *map = (uint32_t *)&cmd->mask; 197298943Sluigi int low, high; 1973117328Sluigi int i = contigmask((u_char *)&(d[1]), 32); 197498943Sluigi 1975117328Sluigi if (len > 0) 1976117328Sluigi errx(EX_DATAERR, "address set cannot be in a list"); 1977117328Sluigi if (i < 24 || i > 31) 1978117328Sluigi errx(EX_DATAERR, "invalid set with mask %d\n", i); 1979117328Sluigi cmd->o.arg1 = 1<<(32-i); /* map length */ 1980117328Sluigi d[0] = ntohl(d[0]); /* base addr in host format */ 198198943Sluigi cmd->o.opcode = O_IP_DST_SET; /* default */ 198298943Sluigi cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32) + (cmd->o.arg1+31)/32; 1983101117Sluigi for (i = 0; i < (cmd->o.arg1+31)/32 ; i++) 1984117328Sluigi map[i] = 0; /* clear map */ 198598943Sluigi 1986117328Sluigi av = p + 1; 1987117328Sluigi low = d[0] & 0xff; 198898943Sluigi high = low + cmd->o.arg1 - 1; 1989117328Sluigi /* 1990117328Sluigi * Here, i stores the previous value when we specify a range 1991117328Sluigi * of addresses within a mask, e.g. 45-63. i = -1 means we 1992117328Sluigi * have no previous value. 1993117328Sluigi */ 1994116716Sluigi i = -1; /* previous value in a range */ 199598943Sluigi while (isdigit(*av)) { 199698943Sluigi char *s; 1997117328Sluigi int a = strtol(av, &s, 0); 199898943Sluigi 1999117328Sluigi if (s == av) { /* no parameter */ 2000117328Sluigi if (*av != '}') 2001117328Sluigi errx(EX_DATAERR, "set not closed\n"); 2002117328Sluigi if (i != -1) 2003117328Sluigi errx(EX_DATAERR, "incomplete range %d-", i); 2004117328Sluigi break; 2005117328Sluigi } 2006117328Sluigi if (a < low || a > high) 2007117328Sluigi errx(EX_DATAERR, "addr %d out of range [%d-%d]\n", 200898943Sluigi a, low, high); 200998943Sluigi a -= low; 2010116716Sluigi if (i == -1) /* no previous in range */ 2011116716Sluigi i = a; 2012116716Sluigi else { /* check that range is valid */ 2013116716Sluigi if (i > a) 2014116716Sluigi errx(EX_DATAERR, "invalid range %d-%d", 2015116716Sluigi i+low, a+low); 2016116716Sluigi if (*s == '-') 2017116716Sluigi errx(EX_DATAERR, "double '-' in range"); 2018116716Sluigi } 2019116716Sluigi for (; i <= a; i++) 2020117328Sluigi map[i/32] |= 1<<(i & 31); 2021116716Sluigi i = -1; 2022116716Sluigi if (*s == '-') 2023116716Sluigi i = a; 2024117328Sluigi else if (*s == '}') 2025116716Sluigi break; 202698943Sluigi av = s+1; 202798943Sluigi } 202898943Sluigi return; 202998943Sluigi } 2030117328Sluigi av = p; 2031117328Sluigi if (av) /* then *av must be a ',' */ 2032117328Sluigi av++; 203398943Sluigi 2034117328Sluigi /* Check this entry */ 2035117328Sluigi if (d[1] == 0) { /* "any", specified as x.x.x.x/0 */ 2036117328Sluigi /* 2037117328Sluigi * 'any' turns the entire list into a NOP. 2038117328Sluigi * 'not any' never matches, so it is removed from the 2039117328Sluigi * list unless it is the only item, in which case we 2040117328Sluigi * report an error. 2041117328Sluigi */ 2042117328Sluigi if (cmd->o.len & F_NOT) { /* "not any" never matches */ 2043117328Sluigi if (av == NULL && len == 0) /* only this entry */ 2044117328Sluigi errx(EX_DATAERR, "not any never matches"); 2045117328Sluigi } 2046117328Sluigi /* else do nothing and skip this entry */ 2047117328Sluigi continue; 2048117328Sluigi } 2049117328Sluigi /* A single IP can be stored in an optimized format */ 2050117328Sluigi if (d[1] == IP_MASK_ALL && av == NULL && len == 0) { 205198943Sluigi cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32); 2052117328Sluigi return; 2053117328Sluigi } 2054117328Sluigi len += 2; /* two words... */ 2055117328Sluigi d += 2; 2056117328Sluigi } /* end while */ 2057117328Sluigi cmd->o.len |= len+1; 205898943Sluigi} 205998943Sluigi 206098943Sluigi 206198943Sluigi/* 206298943Sluigi * helper function to process a set of flags and set bits in the 206398943Sluigi * appropriate masks. 206498943Sluigi */ 206598943Sluigistatic void 206698943Sluigifill_flags(ipfw_insn *cmd, enum ipfw_opcodes opcode, 206798943Sluigi struct _s_x *flags, char *p) 206898943Sluigi{ 2069117328Sluigi uint8_t set=0, clear=0; 207098943Sluigi 207198943Sluigi while (p && *p) { 207298943Sluigi char *q; /* points to the separator */ 207398943Sluigi int val; 2074117328Sluigi uint8_t *which; /* mask we are working on */ 207598943Sluigi 207698943Sluigi if (*p == '!') { 207798943Sluigi p++; 207898943Sluigi which = &clear; 207998943Sluigi } else 208098943Sluigi which = &set; 208198943Sluigi q = strchr(p, ','); 208298943Sluigi if (q) 208398943Sluigi *q++ = '\0'; 208498943Sluigi val = match_token(flags, p); 208598943Sluigi if (val <= 0) 208698943Sluigi errx(EX_DATAERR, "invalid flag %s", p); 2087117328Sluigi *which |= (uint8_t)val; 208898943Sluigi p = q; 208998943Sluigi } 209098943Sluigi cmd->opcode = opcode; 209198943Sluigi cmd->len = (cmd->len & (F_NOT | F_OR)) | 1; 209298943Sluigi cmd->arg1 = (set & 0xff) | ( (clear & 0xff) << 8); 209398943Sluigi} 209498943Sluigi 209598943Sluigi 209698943Sluigistatic void 209798943Sluigidelete(int ac, char *av[]) 209898943Sluigi{ 2099117328Sluigi uint32_t rulenum; 2100117469Sluigi struct dn_pipe p; 210198943Sluigi int i; 210298943Sluigi int exitval = EX_OK; 2103101628Sluigi int do_set = 0; 210498943Sluigi 2105117469Sluigi memset(&p, 0, sizeof p); 210698943Sluigi 210798943Sluigi av++; ac--; 2108101641Sluigi if (ac > 0 && !strncmp(*av, "set", strlen(*av))) { 2109101978Sluigi do_set = 1; /* delete set */ 2110101628Sluigi ac--; av++; 2111101978Sluigi } 211298943Sluigi 211398943Sluigi /* Rule number */ 211498943Sluigi while (ac && isdigit(**av)) { 211598943Sluigi i = atoi(*av); av++; ac--; 211698943Sluigi if (do_pipe) { 211798943Sluigi if (do_pipe == 1) 2118117469Sluigi p.pipe_nr = i; 211998943Sluigi else 2120117469Sluigi p.fs.fs_nr = i; 2121117469Sluigi i = do_cmd(IP_DUMMYNET_DEL, &p, sizeof p); 212298943Sluigi if (i) { 212398943Sluigi exitval = 1; 212498943Sluigi warn("rule %u: setsockopt(IP_DUMMYNET_DEL)", 2125117469Sluigi do_pipe == 1 ? p.pipe_nr : p.fs.fs_nr); 212698943Sluigi } 212798943Sluigi } else { 2128101978Sluigi rulenum = (i & 0xffff) | (do_set << 24); 2129117328Sluigi i = do_cmd(IP_FW_DEL, &rulenum, sizeof rulenum); 213098943Sluigi if (i) { 213198943Sluigi exitval = EX_UNAVAILABLE; 213298943Sluigi warn("rule %u: setsockopt(IP_FW_DEL)", 213398943Sluigi rulenum); 213498943Sluigi } 213598943Sluigi } 213698943Sluigi } 213798943Sluigi if (exitval != EX_OK) 213898943Sluigi exit(exitval); 213998943Sluigi} 214098943Sluigi 214198943Sluigi 214298943Sluigi/* 214398943Sluigi * fill the interface structure. We do not check the name as we can 214498943Sluigi * create interfaces dynamically, so checking them at insert time 214598943Sluigi * makes relatively little sense. 214698943Sluigi * A '*' following the name means any unit. 214798943Sluigi */ 214898943Sluigistatic void 214998943Sluigifill_iface(ipfw_insn_if *cmd, char *arg) 215098943Sluigi{ 215198943Sluigi cmd->name[0] = '\0'; 215298943Sluigi cmd->o.len |= F_INSN_SIZE(ipfw_insn_if); 215398943Sluigi 215498943Sluigi /* Parse the interface or address */ 215598943Sluigi if (!strcmp(arg, "any")) 215698943Sluigi cmd->o.len = 0; /* effectively ignore this command */ 215798943Sluigi else if (!isdigit(*arg)) { 215898943Sluigi char *q; 215998943Sluigi 216098943Sluigi strncpy(cmd->name, arg, sizeof(cmd->name)); 216198943Sluigi cmd->name[sizeof(cmd->name) - 1] = '\0'; 216298943Sluigi /* find first digit or wildcard */ 216398943Sluigi for (q = cmd->name; *q && !isdigit(*q) && *q != '*'; q++) 216498943Sluigi continue; 216598943Sluigi cmd->p.unit = (*q == '*') ? -1 : atoi(q); 216698943Sluigi *q = '\0'; 216798943Sluigi } else if (!inet_aton(arg, &cmd->p.ip)) 216898943Sluigi errx(EX_DATAERR, "bad ip address ``%s''", arg); 216998943Sluigi} 217098943Sluigi 217198943Sluigi/* 217298943Sluigi * the following macro returns an error message if we run out of 217398943Sluigi * arguments. 217498943Sluigi */ 217598943Sluigi#define NEED1(msg) {if (!ac) errx(EX_USAGE, msg);} 217698943Sluigi 217798943Sluigistatic void 217898943Sluigiconfig_pipe(int ac, char **av) 217998943Sluigi{ 2180117469Sluigi struct dn_pipe p; 218198943Sluigi int i; 218298943Sluigi char *end; 2183117328Sluigi uint32_t a; 218498943Sluigi void *par = NULL; 218598943Sluigi 2186117469Sluigi memset(&p, 0, sizeof p); 218798943Sluigi 218898943Sluigi av++; ac--; 218998943Sluigi /* Pipe number */ 219098943Sluigi if (ac && isdigit(**av)) { 219198943Sluigi i = atoi(*av); av++; ac--; 219298943Sluigi if (do_pipe == 1) 2193117469Sluigi p.pipe_nr = i; 219498943Sluigi else 2195117469Sluigi p.fs.fs_nr = i; 219698943Sluigi } 219799475Sluigi while (ac > 0) { 219898943Sluigi double d; 219998943Sluigi int tok = match_token(dummynet_params, *av); 220098943Sluigi ac--; av++; 220198943Sluigi 220298943Sluigi switch(tok) { 2203101978Sluigi case TOK_NOERROR: 2204117469Sluigi p.fs.flags_fs |= DN_NOERROR; 2205101978Sluigi break; 2206101978Sluigi 220798943Sluigi case TOK_PLR: 220898943Sluigi NEED1("plr needs argument 0..1\n"); 220998943Sluigi d = strtod(av[0], NULL); 221098943Sluigi if (d > 1) 221198943Sluigi d = 1; 221298943Sluigi else if (d < 0) 221398943Sluigi d = 0; 2214117469Sluigi p.fs.plr = (int)(d*0x7fffffff); 221598943Sluigi ac--; av++; 221698943Sluigi break; 221798943Sluigi 221898943Sluigi case TOK_QUEUE: 221998943Sluigi NEED1("queue needs queue size\n"); 222098943Sluigi end = NULL; 2221117469Sluigi p.fs.qsize = strtoul(av[0], &end, 0); 222298943Sluigi if (*end == 'K' || *end == 'k') { 2223117469Sluigi p.fs.flags_fs |= DN_QSIZE_IS_BYTES; 2224117469Sluigi p.fs.qsize *= 1024; 222598943Sluigi } else if (*end == 'B' || !strncmp(end, "by", 2)) { 2226117469Sluigi p.fs.flags_fs |= DN_QSIZE_IS_BYTES; 222798943Sluigi } 222898943Sluigi ac--; av++; 222998943Sluigi break; 223098943Sluigi 223198943Sluigi case TOK_BUCKETS: 223298943Sluigi NEED1("buckets needs argument\n"); 2233117469Sluigi p.fs.rq_size = strtoul(av[0], NULL, 0); 223498943Sluigi ac--; av++; 223598943Sluigi break; 223698943Sluigi 223798943Sluigi case TOK_MASK: 223898943Sluigi NEED1("mask needs mask specifier\n"); 223998943Sluigi /* 224098943Sluigi * per-flow queue, mask is dst_ip, dst_port, 224198943Sluigi * src_ip, src_port, proto measured in bits 224298943Sluigi */ 224398943Sluigi par = NULL; 224498943Sluigi 2245117469Sluigi p.fs.flow_mask.dst_ip = 0; 2246117469Sluigi p.fs.flow_mask.src_ip = 0; 2247117469Sluigi p.fs.flow_mask.dst_port = 0; 2248117469Sluigi p.fs.flow_mask.src_port = 0; 2249117469Sluigi p.fs.flow_mask.proto = 0; 225098943Sluigi end = NULL; 225198943Sluigi 225298943Sluigi while (ac >= 1) { 2253117328Sluigi uint32_t *p32 = NULL; 2254117328Sluigi uint16_t *p16 = NULL; 225598943Sluigi 225698943Sluigi tok = match_token(dummynet_params, *av); 225798943Sluigi ac--; av++; 225898943Sluigi switch(tok) { 225998943Sluigi case TOK_ALL: 226098943Sluigi /* 226198943Sluigi * special case, all bits significant 226298943Sluigi */ 2263117469Sluigi p.fs.flow_mask.dst_ip = ~0; 2264117469Sluigi p.fs.flow_mask.src_ip = ~0; 2265117469Sluigi p.fs.flow_mask.dst_port = ~0; 2266117469Sluigi p.fs.flow_mask.src_port = ~0; 2267117469Sluigi p.fs.flow_mask.proto = ~0; 2268117469Sluigi p.fs.flags_fs |= DN_HAVE_FLOW_MASK; 226998943Sluigi goto end_mask; 227098943Sluigi 227198943Sluigi case TOK_DSTIP: 2272117469Sluigi p32 = &p.fs.flow_mask.dst_ip; 227398943Sluigi break; 227498943Sluigi 227598943Sluigi case TOK_SRCIP: 2276117469Sluigi p32 = &p.fs.flow_mask.src_ip; 227798943Sluigi break; 227898943Sluigi 227998943Sluigi case TOK_DSTPORT: 2280117469Sluigi p16 = &p.fs.flow_mask.dst_port; 228198943Sluigi break; 228298943Sluigi 228398943Sluigi case TOK_SRCPORT: 2284117469Sluigi p16 = &p.fs.flow_mask.src_port; 228598943Sluigi break; 228698943Sluigi 228798943Sluigi case TOK_PROTO: 228898943Sluigi break; 228998943Sluigi 229098943Sluigi default: 229198943Sluigi ac++; av--; /* backtrack */ 229298943Sluigi goto end_mask; 229398943Sluigi } 229498943Sluigi if (ac < 1) 229598943Sluigi errx(EX_USAGE, "mask: value missing"); 229698943Sluigi if (*av[0] == '/') { 229798943Sluigi a = strtoul(av[0]+1, &end, 0); 229898943Sluigi a = (a == 32) ? ~0 : (1 << a) - 1; 2299106505Smaxim } else 230099909Sluigi a = strtoul(av[0], &end, 0); 230198943Sluigi if (p32 != NULL) 230298943Sluigi *p32 = a; 230398943Sluigi else if (p16 != NULL) { 230498943Sluigi if (a > 65535) 230598943Sluigi errx(EX_DATAERR, 230698943Sluigi "mask: must be 16 bit"); 2307117328Sluigi *p16 = (uint16_t)a; 230898943Sluigi } else { 230998943Sluigi if (a > 255) 231098943Sluigi errx(EX_DATAERR, 231198943Sluigi "mask: must be 8 bit"); 2312117469Sluigi p.fs.flow_mask.proto = (uint8_t)a; 231398943Sluigi } 231498943Sluigi if (a != 0) 2315117469Sluigi p.fs.flags_fs |= DN_HAVE_FLOW_MASK; 231698943Sluigi ac--; av++; 231798943Sluigi } /* end while, config masks */ 231898943Sluigiend_mask: 231998943Sluigi break; 232098943Sluigi 232198943Sluigi case TOK_RED: 232298943Sluigi case TOK_GRED: 232398943Sluigi NEED1("red/gred needs w_q/min_th/max_th/max_p\n"); 2324117469Sluigi p.fs.flags_fs |= DN_IS_RED; 232598943Sluigi if (tok == TOK_GRED) 2326117469Sluigi p.fs.flags_fs |= DN_IS_GENTLE_RED; 232798943Sluigi /* 232898943Sluigi * the format for parameters is w_q/min_th/max_th/max_p 232998943Sluigi */ 233098943Sluigi if ((end = strsep(&av[0], "/"))) { 233198943Sluigi double w_q = strtod(end, NULL); 233298943Sluigi if (w_q > 1 || w_q <= 0) 233398943Sluigi errx(EX_DATAERR, "0 < w_q <= 1"); 2334117469Sluigi p.fs.w_q = (int) (w_q * (1 << SCALE_RED)); 233598943Sluigi } 233698943Sluigi if ((end = strsep(&av[0], "/"))) { 2337117469Sluigi p.fs.min_th = strtoul(end, &end, 0); 233898943Sluigi if (*end == 'K' || *end == 'k') 2339117469Sluigi p.fs.min_th *= 1024; 234098943Sluigi } 234198943Sluigi if ((end = strsep(&av[0], "/"))) { 2342117469Sluigi p.fs.max_th = strtoul(end, &end, 0); 234398943Sluigi if (*end == 'K' || *end == 'k') 2344117469Sluigi p.fs.max_th *= 1024; 234598943Sluigi } 234698943Sluigi if ((end = strsep(&av[0], "/"))) { 234798943Sluigi double max_p = strtod(end, NULL); 234898943Sluigi if (max_p > 1 || max_p <= 0) 234998943Sluigi errx(EX_DATAERR, "0 < max_p <= 1"); 2350117469Sluigi p.fs.max_p = (int)(max_p * (1 << SCALE_RED)); 235198943Sluigi } 235298943Sluigi ac--; av++; 235398943Sluigi break; 235498943Sluigi 235598943Sluigi case TOK_DROPTAIL: 2356117469Sluigi p.fs.flags_fs &= ~(DN_IS_RED|DN_IS_GENTLE_RED); 235798943Sluigi break; 2358106505Smaxim 235998943Sluigi case TOK_BW: 236098943Sluigi NEED1("bw needs bandwidth or interface\n"); 236198943Sluigi if (do_pipe != 1) 236298943Sluigi errx(EX_DATAERR, "bandwidth only valid for pipes"); 236398943Sluigi /* 236498943Sluigi * set clocking interface or bandwidth value 236598943Sluigi */ 236698943Sluigi if (av[0][0] >= 'a' && av[0][0] <= 'z') { 2367117469Sluigi int l = sizeof(p.if_name)-1; 236898943Sluigi /* interface name */ 2369117469Sluigi strncpy(p.if_name, av[0], l); 2370117469Sluigi p.if_name[l] = '\0'; 2371117469Sluigi p.bandwidth = 0; 237298943Sluigi } else { 2373117469Sluigi p.if_name[0] = '\0'; 2374117469Sluigi p.bandwidth = strtoul(av[0], &end, 0); 237598943Sluigi if (*end == 'K' || *end == 'k') { 237698943Sluigi end++; 2377117469Sluigi p.bandwidth *= 1000; 237898943Sluigi } else if (*end == 'M') { 237998943Sluigi end++; 2380117469Sluigi p.bandwidth *= 1000000; 238198943Sluigi } 238298943Sluigi if (*end == 'B' || !strncmp(end, "by", 2)) 2383117469Sluigi p.bandwidth *= 8; 2384117469Sluigi if (p.bandwidth < 0) 238598943Sluigi errx(EX_DATAERR, "bandwidth too large"); 238698943Sluigi } 238798943Sluigi ac--; av++; 238898943Sluigi break; 238998943Sluigi 239098943Sluigi case TOK_DELAY: 239198943Sluigi if (do_pipe != 1) 239298943Sluigi errx(EX_DATAERR, "delay only valid for pipes"); 239398943Sluigi NEED1("delay needs argument 0..10000ms\n"); 2394117469Sluigi p.delay = strtoul(av[0], NULL, 0); 239598943Sluigi ac--; av++; 239698943Sluigi break; 239798943Sluigi 239898943Sluigi case TOK_WEIGHT: 239998943Sluigi if (do_pipe == 1) 240098943Sluigi errx(EX_DATAERR,"weight only valid for queues"); 240198943Sluigi NEED1("weight needs argument 0..100\n"); 2402117469Sluigi p.fs.weight = strtoul(av[0], &end, 0); 240398943Sluigi ac--; av++; 240498943Sluigi break; 240598943Sluigi 240698943Sluigi case TOK_PIPE: 240798943Sluigi if (do_pipe == 1) 240898943Sluigi errx(EX_DATAERR,"pipe only valid for queues"); 240998943Sluigi NEED1("pipe needs pipe_number\n"); 2410117469Sluigi p.fs.parent_nr = strtoul(av[0], &end, 0); 241198943Sluigi ac--; av++; 241298943Sluigi break; 241398943Sluigi 241498943Sluigi default: 241598943Sluigi errx(EX_DATAERR, "unrecognised option ``%s''", *av); 241698943Sluigi } 241798943Sluigi } 241898943Sluigi if (do_pipe == 1) { 2419117469Sluigi if (p.pipe_nr == 0) 242098943Sluigi errx(EX_DATAERR, "pipe_nr must be > 0"); 2421117469Sluigi if (p.delay > 10000) 242298943Sluigi errx(EX_DATAERR, "delay must be < 10000"); 242398943Sluigi } else { /* do_pipe == 2, queue */ 2424117469Sluigi if (p.fs.parent_nr == 0) 242598943Sluigi errx(EX_DATAERR, "pipe must be > 0"); 2426117469Sluigi if (p.fs.weight >100) 242798943Sluigi errx(EX_DATAERR, "weight must be <= 100"); 242898943Sluigi } 2429117469Sluigi if (p.fs.flags_fs & DN_QSIZE_IS_BYTES) { 2430117469Sluigi if (p.fs.qsize > 1024*1024) 243198943Sluigi errx(EX_DATAERR, "queue size must be < 1MB"); 243298943Sluigi } else { 2433117469Sluigi if (p.fs.qsize > 100) 243498943Sluigi errx(EX_DATAERR, "2 <= queue size <= 100"); 243598943Sluigi } 2436117469Sluigi if (p.fs.flags_fs & DN_IS_RED) { 243798943Sluigi size_t len; 243898943Sluigi int lookup_depth, avg_pkt_size; 243998943Sluigi double s, idle, weight, w_q; 2440117469Sluigi struct clockinfo ck; 244198943Sluigi int t; 244298943Sluigi 2443117469Sluigi if (p.fs.min_th >= p.fs.max_th) 244498943Sluigi errx(EX_DATAERR, "min_th %d must be < than max_th %d", 2445117469Sluigi p.fs.min_th, p.fs.max_th); 2446117469Sluigi if (p.fs.max_th == 0) 244798943Sluigi errx(EX_DATAERR, "max_th must be > 0"); 244898943Sluigi 244998943Sluigi len = sizeof(int); 245098943Sluigi if (sysctlbyname("net.inet.ip.dummynet.red_lookup_depth", 245198943Sluigi &lookup_depth, &len, NULL, 0) == -1) 245298943Sluigi 245398943Sluigi errx(1, "sysctlbyname(\"%s\")", 245498943Sluigi "net.inet.ip.dummynet.red_lookup_depth"); 245598943Sluigi if (lookup_depth == 0) 245698943Sluigi errx(EX_DATAERR, "net.inet.ip.dummynet.red_lookup_depth" 245798943Sluigi " must be greater than zero"); 245898943Sluigi 245998943Sluigi len = sizeof(int); 246098943Sluigi if (sysctlbyname("net.inet.ip.dummynet.red_avg_pkt_size", 246198943Sluigi &avg_pkt_size, &len, NULL, 0) == -1) 246298943Sluigi 246398943Sluigi errx(1, "sysctlbyname(\"%s\")", 246498943Sluigi "net.inet.ip.dummynet.red_avg_pkt_size"); 246598943Sluigi if (avg_pkt_size == 0) 246698943Sluigi errx(EX_DATAERR, 246798943Sluigi "net.inet.ip.dummynet.red_avg_pkt_size must" 246898943Sluigi " be greater than zero"); 246998943Sluigi 247098943Sluigi len = sizeof(struct clockinfo); 2471117469Sluigi if (sysctlbyname("kern.clockrate", &ck, &len, NULL, 0) == -1) 247298943Sluigi errx(1, "sysctlbyname(\"%s\")", "kern.clockrate"); 247398943Sluigi 247498943Sluigi /* 247598943Sluigi * Ticks needed for sending a medium-sized packet. 247698943Sluigi * Unfortunately, when we are configuring a WF2Q+ queue, we 247798943Sluigi * do not have bandwidth information, because that is stored 247898943Sluigi * in the parent pipe, and also we have multiple queues 247998943Sluigi * competing for it. So we set s=0, which is not very 248098943Sluigi * correct. But on the other hand, why do we want RED with 248198943Sluigi * WF2Q+ ? 248298943Sluigi */ 2483117469Sluigi if (p.bandwidth==0) /* this is a WF2Q+ queue */ 248498943Sluigi s = 0; 248598943Sluigi else 2486117469Sluigi s = ck.hz * avg_pkt_size * 8 / p.bandwidth; 248798943Sluigi 248898943Sluigi /* 248998943Sluigi * max idle time (in ticks) before avg queue size becomes 0. 249098943Sluigi * NOTA: (3/w_q) is approx the value x so that 249198943Sluigi * (1-w_q)^x < 10^-3. 249298943Sluigi */ 2493117469Sluigi w_q = ((double)p.fs.w_q) / (1 << SCALE_RED); 249498943Sluigi idle = s * 3. / w_q; 2495117469Sluigi p.fs.lookup_step = (int)idle / lookup_depth; 2496117469Sluigi if (!p.fs.lookup_step) 2497117469Sluigi p.fs.lookup_step = 1; 249898943Sluigi weight = 1 - w_q; 2499117469Sluigi for (t = p.fs.lookup_step; t > 0; --t) 250098943Sluigi weight *= weight; 2501117469Sluigi p.fs.lookup_weight = (int)(weight * (1 << SCALE_RED)); 250298943Sluigi } 2503117469Sluigi i = do_cmd(IP_DUMMYNET_CONFIGURE, &p, sizeof p); 250498943Sluigi if (i) 250598943Sluigi err(1, "setsockopt(%s)", "IP_DUMMYNET_CONFIGURE"); 250698943Sluigi} 250798943Sluigi 250898943Sluigistatic void 250998943Sluigiget_mac_addr_mask(char *p, u_char *addr, u_char *mask) 251098943Sluigi{ 251198943Sluigi int i, l; 251298943Sluigi 251398943Sluigi for (i=0; i<6; i++) 251498943Sluigi addr[i] = mask[i] = 0; 251598943Sluigi if (!strcmp(p, "any")) 251698943Sluigi return; 251798943Sluigi 251898943Sluigi for (i=0; *p && i<6;i++, p++) { 251998943Sluigi addr[i] = strtol(p, &p, 16); 252098943Sluigi if (*p != ':') /* we start with the mask */ 252198943Sluigi break; 252298943Sluigi } 252398943Sluigi if (*p == '/') { /* mask len */ 252498943Sluigi l = strtol(p+1, &p, 0); 252598943Sluigi for (i=0; l>0; l -=8, i++) 252698943Sluigi mask[i] = (l >=8) ? 0xff : (~0) << (8-l); 252798943Sluigi } else if (*p == '&') { /* mask */ 252898943Sluigi for (i=0, p++; *p && i<6;i++, p++) { 252998943Sluigi mask[i] = strtol(p, &p, 16); 253098943Sluigi if (*p != ':') 253198943Sluigi break; 253298943Sluigi } 253398943Sluigi } else if (*p == '\0') { 253498943Sluigi for (i=0; i<6; i++) 253598943Sluigi mask[i] = 0xff; 253698943Sluigi } 253798943Sluigi for (i=0; i<6; i++) 253898943Sluigi addr[i] &= mask[i]; 253998943Sluigi} 254098943Sluigi 254198943Sluigi/* 254298943Sluigi * helper function, updates the pointer to cmd with the length 254398943Sluigi * of the current command, and also cleans up the first word of 254498943Sluigi * the new command in case it has been clobbered before. 254598943Sluigi */ 254698943Sluigistatic ipfw_insn * 254798943Sluiginext_cmd(ipfw_insn *cmd) 254898943Sluigi{ 254998943Sluigi cmd += F_LEN(cmd); 255098943Sluigi bzero(cmd, sizeof(*cmd)); 255198943Sluigi return cmd; 255298943Sluigi} 255398943Sluigi 255498943Sluigi/* 2555117469Sluigi * Takes arguments and copies them into a comment 2556117469Sluigi */ 2557117469Sluigistatic void 2558117469Sluigifill_comment(ipfw_insn *cmd, int ac, char **av) 2559117469Sluigi{ 2560117469Sluigi int i, l; 2561117469Sluigi char *p = (char *)(cmd + 1); 2562117469Sluigi 2563117469Sluigi cmd->opcode = O_NOP; 2564117469Sluigi cmd->len = (cmd->len & (F_NOT | F_OR)); 2565117469Sluigi 2566117469Sluigi /* Compute length of comment string. */ 2567117469Sluigi for (i = 0, l = 0; i < ac; i++) 2568117469Sluigi l += strlen(av[i]) + 1; 2569117469Sluigi if (l == 0) 2570117469Sluigi return; 2571117469Sluigi if (l > 84) 2572117469Sluigi errx(EX_DATAERR, 2573117469Sluigi "comment too long (max 80 chars)"); 2574117469Sluigi l = 1 + (l+3)/4; 2575117469Sluigi cmd->len = (cmd->len & (F_NOT | F_OR)) | l; 2576117469Sluigi for (i = 0; i < ac; i++) { 2577117469Sluigi strcpy(p, av[i]); 2578117469Sluigi p += strlen(av[i]); 2579117469Sluigi *p++ = ' '; 2580117469Sluigi } 2581117469Sluigi *(--p) = '\0'; 2582117469Sluigi} 2583117469Sluigi 2584117469Sluigi/* 258598943Sluigi * A function to fill simple commands of size 1. 258698943Sluigi * Existing flags are preserved. 258798943Sluigi */ 258898943Sluigistatic void 2589117328Sluigifill_cmd(ipfw_insn *cmd, enum ipfw_opcodes opcode, int flags, uint16_t arg) 259098943Sluigi{ 259198943Sluigi cmd->opcode = opcode; 259298943Sluigi cmd->len = ((cmd->len | flags) & (F_NOT | F_OR)) | 1; 259398943Sluigi cmd->arg1 = arg; 259498943Sluigi} 259598943Sluigi 259698943Sluigi/* 259798943Sluigi * Fetch and add the MAC address and type, with masks. This generates one or 259898943Sluigi * two microinstructions, and returns the pointer to the last one. 259998943Sluigi */ 260098943Sluigistatic ipfw_insn * 260198943Sluigiadd_mac(ipfw_insn *cmd, int ac, char *av[]) 260298943Sluigi{ 2603102087Sluigi ipfw_insn_mac *mac; 260498943Sluigi 2605102087Sluigi if (ac < 2) 2606102098Sluigi errx(EX_DATAERR, "MAC dst src"); 260798943Sluigi 260898943Sluigi cmd->opcode = O_MACADDR2; 260998943Sluigi cmd->len = (cmd->len & (F_NOT | F_OR)) | F_INSN_SIZE(ipfw_insn_mac); 261098943Sluigi 261198943Sluigi mac = (ipfw_insn_mac *)cmd; 2612101978Sluigi get_mac_addr_mask(av[0], mac->addr, mac->mask); /* dst */ 261398943Sluigi get_mac_addr_mask(av[1], &(mac->addr[6]), &(mac->mask[6])); /* src */ 2614102087Sluigi return cmd; 2615102087Sluigi} 261698943Sluigi 2617102087Sluigistatic ipfw_insn * 2618102087Sluigiadd_mactype(ipfw_insn *cmd, int ac, char *av) 2619102087Sluigi{ 2620102087Sluigi if (ac < 1) 2621102087Sluigi errx(EX_DATAERR, "missing MAC type"); 2622102087Sluigi if (strcmp(av, "any") != 0) { /* we have a non-null type */ 2623102087Sluigi fill_newports((ipfw_insn_u16 *)cmd, av, IPPROTO_ETHERTYPE); 262498943Sluigi cmd->opcode = O_MAC_TYPE; 2625102087Sluigi return cmd; 2626102087Sluigi } else 2627102087Sluigi return NULL; 2628102087Sluigi} 262998943Sluigi 2630102087Sluigistatic ipfw_insn * 2631102087Sluigiadd_proto(ipfw_insn *cmd, char *av) 2632102087Sluigi{ 2633102087Sluigi struct protoent *pe; 2634102087Sluigi u_char proto = 0; 2635102087Sluigi 2636102087Sluigi if (!strncmp(av, "all", strlen(av))) 2637102087Sluigi ; /* same as "ip" */ 2638102087Sluigi else if ((proto = atoi(av)) > 0) 2639102087Sluigi ; /* all done! */ 2640102087Sluigi else if ((pe = getprotobyname(av)) != NULL) 2641102087Sluigi proto = pe->p_proto; 2642102087Sluigi else 2643102098Sluigi return NULL; 2644102087Sluigi if (proto != IPPROTO_IP) 2645102087Sluigi fill_cmd(cmd, O_PROTO, 0, proto); 264698943Sluigi return cmd; 264798943Sluigi} 264898943Sluigi 2649102087Sluigistatic ipfw_insn * 2650102087Sluigiadd_srcip(ipfw_insn *cmd, char *av) 2651102087Sluigi{ 2652102087Sluigi fill_ip((ipfw_insn_ip *)cmd, av); 2653102087Sluigi if (cmd->opcode == O_IP_DST_SET) /* set */ 2654102087Sluigi cmd->opcode = O_IP_SRC_SET; 2655102087Sluigi else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) /* me */ 2656102087Sluigi cmd->opcode = O_IP_SRC_ME; 2657102087Sluigi else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn_u32)) /* one IP */ 2658102087Sluigi cmd->opcode = O_IP_SRC; 2659117328Sluigi else /* addr/mask */ 2660102087Sluigi cmd->opcode = O_IP_SRC_MASK; 2661102087Sluigi return cmd; 2662102087Sluigi} 2663102087Sluigi 2664102087Sluigistatic ipfw_insn * 2665102087Sluigiadd_dstip(ipfw_insn *cmd, char *av) 2666102087Sluigi{ 2667102087Sluigi fill_ip((ipfw_insn_ip *)cmd, av); 2668102087Sluigi if (cmd->opcode == O_IP_DST_SET) /* set */ 2669102087Sluigi ; 2670102087Sluigi else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) /* me */ 2671102087Sluigi cmd->opcode = O_IP_DST_ME; 2672102087Sluigi else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn_u32)) /* one IP */ 2673102087Sluigi cmd->opcode = O_IP_DST; 2674117328Sluigi else /* addr/mask */ 2675102087Sluigi cmd->opcode = O_IP_DST_MASK; 2676102087Sluigi return cmd; 2677102087Sluigi} 2678102087Sluigi 2679102087Sluigistatic ipfw_insn * 2680102087Sluigiadd_ports(ipfw_insn *cmd, char *av, u_char proto, int opcode) 2681102087Sluigi{ 2682102087Sluigi if (!strncmp(av, "any", strlen(av))) { 2683102087Sluigi return NULL; 2684102087Sluigi } else if (fill_newports((ipfw_insn_u16 *)cmd, av, proto)) { 2685102087Sluigi /* XXX todo: check that we have a protocol with ports */ 2686102087Sluigi cmd->opcode = opcode; 2687102087Sluigi return cmd; 2688102087Sluigi } 2689102087Sluigi return NULL; 2690102087Sluigi} 2691102087Sluigi 269298943Sluigi/* 269398943Sluigi * Parse arguments and assemble the microinstructions which make up a rule. 269498943Sluigi * Rules are added into the 'rulebuf' and then copied in the correct order 269598943Sluigi * into the actual rule. 269698943Sluigi * 269798943Sluigi * The syntax for a rule starts with the action, followed by an 269898943Sluigi * optional log action, and the various match patterns. 2699108533Sschweikh * In the assembled microcode, the first opcode must be an O_PROBE_STATE 270098943Sluigi * (generated if the rule includes a keep-state option), then the 270198943Sluigi * various match patterns, the "log" action, and the actual action. 2702106505Smaxim * 270398943Sluigi */ 270498943Sluigistatic void 270598943Sluigiadd(int ac, char *av[]) 270698943Sluigi{ 270798943Sluigi /* 270898943Sluigi * rules are added into the 'rulebuf' and then copied in 270998943Sluigi * the correct order into the actual rule. 271098943Sluigi * Some things that need to go out of order (prob, action etc.) 271198943Sluigi * go into actbuf[]. 271298943Sluigi */ 2713117328Sluigi static uint32_t rulebuf[255], actbuf[255], cmdbuf[255]; 271498943Sluigi 2715117469Sluigi ipfw_insn *src, *dst, *cmd, *action, *prev=NULL; 2716102087Sluigi ipfw_insn *first_cmd; /* first match pattern */ 271798943Sluigi 271898943Sluigi struct ip_fw *rule; 271998943Sluigi 272098943Sluigi /* 272198943Sluigi * various flags used to record that we entered some fields. 272298943Sluigi */ 2723101116Sluigi ipfw_insn *have_state = NULL; /* check-state or keep-state */ 272498943Sluigi 272598943Sluigi int i; 272698943Sluigi 272798943Sluigi int open_par = 0; /* open parenthesis ( */ 272898943Sluigi 272998943Sluigi /* proto is here because it is used to fetch ports */ 273098943Sluigi u_char proto = IPPROTO_IP; /* default protocol */ 273198943Sluigi 2732107289Sluigi double match_prob = 1; /* match probability, default is always match */ 2733107289Sluigi 273498943Sluigi bzero(actbuf, sizeof(actbuf)); /* actions go here */ 273598943Sluigi bzero(cmdbuf, sizeof(cmdbuf)); 273698943Sluigi bzero(rulebuf, sizeof(rulebuf)); 273798943Sluigi 273898943Sluigi rule = (struct ip_fw *)rulebuf; 273998943Sluigi cmd = (ipfw_insn *)cmdbuf; 274098943Sluigi action = (ipfw_insn *)actbuf; 274198943Sluigi 274298943Sluigi av++; ac--; 274398943Sluigi 274498943Sluigi /* [rule N] -- Rule number optional */ 274598943Sluigi if (ac && isdigit(**av)) { 274698943Sluigi rule->rulenum = atoi(*av); 274798943Sluigi av++; 274898943Sluigi ac--; 274998943Sluigi } 275098943Sluigi 2751101628Sluigi /* [set N] -- set number (0..30), optional */ 2752101628Sluigi if (ac > 1 && !strncmp(*av, "set", strlen(*av))) { 2753101628Sluigi int set = strtoul(av[1], NULL, 10); 2754101628Sluigi if (set < 0 || set > 30) 2755101628Sluigi errx(EX_DATAERR, "illegal set %s", av[1]); 2756101628Sluigi rule->set = set; 2757101628Sluigi av += 2; ac -= 2; 2758101628Sluigi } 2759101628Sluigi 276098943Sluigi /* [prob D] -- match probability, optional */ 276198943Sluigi if (ac > 1 && !strncmp(*av, "prob", strlen(*av))) { 2762107289Sluigi match_prob = strtod(av[1], NULL); 276398943Sluigi 2764107289Sluigi if (match_prob <= 0 || match_prob > 1) 276598943Sluigi errx(EX_DATAERR, "illegal match prob. %s", av[1]); 276698943Sluigi av += 2; ac -= 2; 276798943Sluigi } 276898943Sluigi 276998943Sluigi /* action -- mandatory */ 277098943Sluigi NEED1("missing action"); 277198943Sluigi i = match_token(rule_actions, *av); 277298943Sluigi ac--; av++; 277398943Sluigi action->len = 1; /* default */ 277498943Sluigi switch(i) { 277598943Sluigi case TOK_CHECKSTATE: 2776101116Sluigi have_state = action; 277798943Sluigi action->opcode = O_CHECK_STATE; 277898943Sluigi break; 277998943Sluigi 278098943Sluigi case TOK_ACCEPT: 278198943Sluigi action->opcode = O_ACCEPT; 278298943Sluigi break; 278398943Sluigi 278498943Sluigi case TOK_DENY: 278598943Sluigi action->opcode = O_DENY; 278699475Sluigi action->arg1 = 0; 278798943Sluigi break; 278898943Sluigi 278999475Sluigi case TOK_REJECT: 279099475Sluigi action->opcode = O_REJECT; 279199475Sluigi action->arg1 = ICMP_UNREACH_HOST; 279299475Sluigi break; 279399475Sluigi 279499475Sluigi case TOK_RESET: 279599475Sluigi action->opcode = O_REJECT; 279699475Sluigi action->arg1 = ICMP_REJECT_RST; 279799475Sluigi break; 279899475Sluigi 279999475Sluigi case TOK_UNREACH: 280099475Sluigi action->opcode = O_REJECT; 280199475Sluigi NEED1("missing reject code"); 280299475Sluigi fill_reject_code(&action->arg1, *av); 280399475Sluigi ac--; av++; 280499475Sluigi break; 280599475Sluigi 280698943Sluigi case TOK_COUNT: 280798943Sluigi action->opcode = O_COUNT; 280898943Sluigi break; 280998943Sluigi 281098943Sluigi case TOK_QUEUE: 281198943Sluigi case TOK_PIPE: 281298943Sluigi action->len = F_INSN_SIZE(ipfw_insn_pipe); 281398943Sluigi case TOK_SKIPTO: 281498943Sluigi if (i == TOK_QUEUE) 281598943Sluigi action->opcode = O_QUEUE; 281698943Sluigi else if (i == TOK_PIPE) 281798943Sluigi action->opcode = O_PIPE; 281898943Sluigi else if (i == TOK_SKIPTO) 281998943Sluigi action->opcode = O_SKIPTO; 282098943Sluigi NEED1("missing skipto/pipe/queue number"); 282198943Sluigi action->arg1 = strtoul(*av, NULL, 10); 282298943Sluigi av++; ac--; 282398943Sluigi break; 282498943Sluigi 282598943Sluigi case TOK_DIVERT: 282698943Sluigi case TOK_TEE: 282798943Sluigi action->opcode = (i == TOK_DIVERT) ? O_DIVERT : O_TEE; 282898943Sluigi NEED1("missing divert/tee port"); 282998943Sluigi action->arg1 = strtoul(*av, NULL, 0); 283098943Sluigi if (action->arg1 == 0) { 283198943Sluigi struct servent *s; 283298943Sluigi setservent(1); 283398943Sluigi s = getservbyname(av[0], "divert"); 283498943Sluigi if (s != NULL) 283598943Sluigi action->arg1 = ntohs(s->s_port); 283698943Sluigi else 283798943Sluigi errx(EX_DATAERR, "illegal divert/tee port"); 283898943Sluigi } 283998943Sluigi ac--; av++; 284098943Sluigi break; 284198943Sluigi 284298943Sluigi case TOK_FORWARD: { 284398943Sluigi ipfw_insn_sa *p = (ipfw_insn_sa *)action; 284498943Sluigi char *s, *end; 284598943Sluigi 284698943Sluigi NEED1("missing forward address[:port]"); 284798943Sluigi 284898943Sluigi action->opcode = O_FORWARD_IP; 284998943Sluigi action->len = F_INSN_SIZE(ipfw_insn_sa); 285098943Sluigi 285198943Sluigi p->sa.sin_len = sizeof(struct sockaddr_in); 285298943Sluigi p->sa.sin_family = AF_INET; 285398943Sluigi p->sa.sin_port = 0; 285498943Sluigi /* 285598943Sluigi * locate the address-port separator (':' or ',') 285698943Sluigi */ 285798943Sluigi s = strchr(*av, ':'); 285898943Sluigi if (s == NULL) 285998943Sluigi s = strchr(*av, ','); 286098943Sluigi if (s != NULL) { 286198943Sluigi *(s++) = '\0'; 286298943Sluigi i = strtoport(s, &end, 0 /* base */, 0 /* proto */); 286398943Sluigi if (s == end) 286498943Sluigi errx(EX_DATAERR, 286598943Sluigi "illegal forwarding port ``%s''", s); 2866103241Sluigi p->sa.sin_port = (u_short)i; 286798943Sluigi } 286898943Sluigi lookup_host(*av, &(p->sa.sin_addr)); 286998943Sluigi } 287098943Sluigi ac--; av++; 287198943Sluigi break; 287298943Sluigi 2873117469Sluigi case TOK_COMMENT: 2874117469Sluigi /* pretend it is a 'count' rule followed by the comment */ 2875117469Sluigi action->opcode = O_COUNT; 2876117469Sluigi ac++; av--; /* go back... */ 2877117469Sluigi break; 2878117469Sluigi 287998943Sluigi default: 2880102087Sluigi errx(EX_DATAERR, "invalid action %s\n", av[-1]); 288198943Sluigi } 288298943Sluigi action = next_cmd(action); 288398943Sluigi 288498943Sluigi /* 288598943Sluigi * [log [logamount N]] -- log, optional 288698943Sluigi * 288798943Sluigi * If exists, it goes first in the cmdbuf, but then it is 288898943Sluigi * skipped in the copy section to the end of the buffer. 288998943Sluigi */ 289098943Sluigi if (ac && !strncmp(*av, "log", strlen(*av))) { 289198943Sluigi ipfw_insn_log *c = (ipfw_insn_log *)cmd; 2892117469Sluigi int l; 289398943Sluigi 289498943Sluigi cmd->len = F_INSN_SIZE(ipfw_insn_log); 289598943Sluigi cmd->opcode = O_LOG; 289698943Sluigi av++; ac--; 289798943Sluigi if (ac && !strncmp(*av, "logamount", strlen(*av))) { 289898943Sluigi ac--; av++; 289998943Sluigi NEED1("logamount requires argument"); 2900117469Sluigi l = atoi(*av); 2901117469Sluigi if (l < 0) 290298943Sluigi errx(EX_DATAERR, "logamount must be positive"); 2903117469Sluigi c->max_log = l; 290498943Sluigi ac--; av++; 290598943Sluigi } 290698943Sluigi cmd = next_cmd(cmd); 290798943Sluigi } 290898943Sluigi 2909101116Sluigi if (have_state) /* must be a check-state, we are done */ 291098943Sluigi goto done; 291198943Sluigi 291298943Sluigi#define OR_START(target) \ 291398943Sluigi if (ac && (*av[0] == '(' || *av[0] == '{')) { \ 291498943Sluigi if (open_par) \ 291598943Sluigi errx(EX_USAGE, "nested \"(\" not allowed\n"); \ 2916101641Sluigi prev = NULL; \ 291798943Sluigi open_par = 1; \ 291898943Sluigi if ( (av[0])[1] == '\0') { \ 291998943Sluigi ac--; av++; \ 292098943Sluigi } else \ 292198943Sluigi (*av)++; \ 292298943Sluigi } \ 292398943Sluigi target: \ 292498943Sluigi 292598943Sluigi 292698943Sluigi#define CLOSE_PAR \ 292798943Sluigi if (open_par) { \ 292898943Sluigi if (ac && ( \ 292998943Sluigi !strncmp(*av, ")", strlen(*av)) || \ 293098943Sluigi !strncmp(*av, "}", strlen(*av)) )) { \ 2931101641Sluigi prev = NULL; \ 293298943Sluigi open_par = 0; \ 293398943Sluigi ac--; av++; \ 293498943Sluigi } else \ 293598943Sluigi errx(EX_USAGE, "missing \")\"\n"); \ 293698943Sluigi } 2937106505Smaxim 293898943Sluigi#define NOT_BLOCK \ 293998943Sluigi if (ac && !strncmp(*av, "not", strlen(*av))) { \ 294098943Sluigi if (cmd->len & F_NOT) \ 294198943Sluigi errx(EX_USAGE, "double \"not\" not allowed\n"); \ 294298943Sluigi cmd->len |= F_NOT; \ 294398943Sluigi ac--; av++; \ 294498943Sluigi } 294598943Sluigi 294698943Sluigi#define OR_BLOCK(target) \ 294798943Sluigi if (ac && !strncmp(*av, "or", strlen(*av))) { \ 294898943Sluigi if (prev == NULL || open_par == 0) \ 294998943Sluigi errx(EX_DATAERR, "invalid OR block"); \ 295098943Sluigi prev->len |= F_OR; \ 295198943Sluigi ac--; av++; \ 295298943Sluigi goto target; \ 295398943Sluigi } \ 295498943Sluigi CLOSE_PAR; 295598943Sluigi 2956102087Sluigi first_cmd = cmd; 2957102098Sluigi 2958102098Sluigi#if 0 295998943Sluigi /* 2960102087Sluigi * MAC addresses, optional. 2961102087Sluigi * If we have this, we skip the part "proto from src to dst" 2962102087Sluigi * and jump straight to the option parsing. 2963102087Sluigi */ 2964102087Sluigi NOT_BLOCK; 2965102087Sluigi NEED1("missing protocol"); 2966102087Sluigi if (!strncmp(*av, "MAC", strlen(*av)) || 2967102087Sluigi !strncmp(*av, "mac", strlen(*av))) { 2968102087Sluigi ac--; av++; /* the "MAC" keyword */ 2969102087Sluigi add_mac(cmd, ac, av); /* exits in case of errors */ 2970102087Sluigi cmd = next_cmd(cmd); 2971102087Sluigi ac -= 2; av += 2; /* dst-mac and src-mac */ 2972102087Sluigi NOT_BLOCK; 2973102087Sluigi NEED1("missing mac type"); 2974102087Sluigi if (add_mactype(cmd, ac, av[0])) 2975102087Sluigi cmd = next_cmd(cmd); 2976102087Sluigi ac--; av++; /* any or mac-type */ 2977102087Sluigi goto read_options; 2978102087Sluigi } 2979102098Sluigi#endif 2980102087Sluigi 2981102087Sluigi /* 298298943Sluigi * protocol, mandatory 298398943Sluigi */ 298498943Sluigi OR_START(get_proto); 298598943Sluigi NOT_BLOCK; 298698943Sluigi NEED1("missing protocol"); 2987102087Sluigi if (add_proto(cmd, *av)) { 2988102087Sluigi av++; ac--; 2989102087Sluigi if (F_LEN(cmd) == 0) /* plain IP */ 2990102087Sluigi proto = 0; 2991102087Sluigi else { 2992102087Sluigi proto = cmd->arg1; 2993102087Sluigi prev = cmd; 2994102087Sluigi cmd = next_cmd(cmd); 2995102087Sluigi } 2996102098Sluigi } else if (first_cmd != cmd) { 2997116438Smaxim errx(EX_DATAERR, "invalid protocol ``%s''", *av); 2998102098Sluigi } else 2999102098Sluigi goto read_options; 300098943Sluigi OR_BLOCK(get_proto); 300198943Sluigi 300298943Sluigi /* 3003102087Sluigi * "from", mandatory 300498943Sluigi */ 3005102087Sluigi if (!ac || strncmp(*av, "from", strlen(*av))) 300698943Sluigi errx(EX_USAGE, "missing ``from''"); 300798943Sluigi ac--; av++; 300898943Sluigi 300998943Sluigi /* 301098943Sluigi * source IP, mandatory 301198943Sluigi */ 301298943Sluigi OR_START(source_ip); 301398943Sluigi NOT_BLOCK; /* optional "not" */ 301498943Sluigi NEED1("missing source address"); 3015102087Sluigi if (add_srcip(cmd, *av)) { 3016102087Sluigi ac--; av++; 3017102087Sluigi if (F_LEN(cmd) != 0) { /* ! any */ 3018102087Sluigi prev = cmd; 3019102087Sluigi cmd = next_cmd(cmd); 3020102087Sluigi } 3021102087Sluigi } 302298943Sluigi OR_BLOCK(source_ip); 302398943Sluigi 302498943Sluigi /* 302598943Sluigi * source ports, optional 302698943Sluigi */ 302798943Sluigi NOT_BLOCK; /* optional "not" */ 3028101641Sluigi if (ac) { 3029102087Sluigi if (!strncmp(*av, "any", strlen(*av)) || 3030102087Sluigi add_ports(cmd, *av, proto, O_IP_SRCPORT)) { 3031102087Sluigi ac--; av++; 3032102087Sluigi if (F_LEN(cmd) != 0) 3033102087Sluigi cmd = next_cmd(cmd); 3034101641Sluigi } 303598943Sluigi } 303698943Sluigi 303798943Sluigi /* 3038102087Sluigi * "to", mandatory 303998943Sluigi */ 3040102087Sluigi if (!ac || strncmp(*av, "to", strlen(*av))) 304198943Sluigi errx(EX_USAGE, "missing ``to''"); 304298943Sluigi av++; ac--; 304398943Sluigi 304498943Sluigi /* 304598943Sluigi * destination, mandatory 304698943Sluigi */ 304798943Sluigi OR_START(dest_ip); 304898943Sluigi NOT_BLOCK; /* optional "not" */ 304998943Sluigi NEED1("missing dst address"); 3050102087Sluigi if (add_dstip(cmd, *av)) { 3051102087Sluigi ac--; av++; 3052102087Sluigi if (F_LEN(cmd) != 0) { /* ! any */ 3053102087Sluigi prev = cmd; 3054102087Sluigi cmd = next_cmd(cmd); 3055102087Sluigi } 3056102087Sluigi } 305798943Sluigi OR_BLOCK(dest_ip); 305898943Sluigi 305998943Sluigi /* 306098943Sluigi * dest. ports, optional 306198943Sluigi */ 306298943Sluigi NOT_BLOCK; /* optional "not" */ 3063101641Sluigi if (ac) { 3064102087Sluigi if (!strncmp(*av, "any", strlen(*av)) || 3065102087Sluigi add_ports(cmd, *av, proto, O_IP_DSTPORT)) { 3066102087Sluigi ac--; av++; 3067102087Sluigi if (F_LEN(cmd) != 0) 3068102087Sluigi cmd = next_cmd(cmd); 3069101641Sluigi } 307098943Sluigi } 307198943Sluigi 307298943Sluigiread_options: 3073102087Sluigi if (ac && first_cmd == cmd) { 3074102087Sluigi /* 3075102087Sluigi * nothing specified so far, store in the rule to ease 3076102087Sluigi * printout later. 3077102087Sluigi */ 3078102087Sluigi rule->_pad = 1; 3079102087Sluigi } 308098943Sluigi prev = NULL; 308198943Sluigi while (ac) { 3082101641Sluigi char *s; 3083101641Sluigi ipfw_insn_u32 *cmd32; /* alias for cmd */ 308498943Sluigi 3085101641Sluigi s = *av; 3086101641Sluigi cmd32 = (ipfw_insn_u32 *)cmd; 3087101641Sluigi 308898943Sluigi if (*s == '!') { /* alternate syntax for NOT */ 308998943Sluigi if (cmd->len & F_NOT) 309098943Sluigi errx(EX_USAGE, "double \"not\" not allowed\n"); 309198943Sluigi cmd->len = F_NOT; 309298943Sluigi s++; 309398943Sluigi } 309498943Sluigi i = match_token(rule_options, s); 309598943Sluigi ac--; av++; 309698943Sluigi switch(i) { 309798943Sluigi case TOK_NOT: 309898943Sluigi if (cmd->len & F_NOT) 309998943Sluigi errx(EX_USAGE, "double \"not\" not allowed\n"); 310098943Sluigi cmd->len = F_NOT; 310198943Sluigi break; 310298943Sluigi 310398943Sluigi case TOK_OR: 3104101641Sluigi if (open_par == 0 || prev == NULL) 310598943Sluigi errx(EX_USAGE, "invalid \"or\" block\n"); 310698943Sluigi prev->len |= F_OR; 310798943Sluigi break; 3108101641Sluigi 3109101641Sluigi case TOK_STARTBRACE: 3110101641Sluigi if (open_par) 3111101641Sluigi errx(EX_USAGE, "+nested \"(\" not allowed\n"); 3112101641Sluigi open_par = 1; 3113101641Sluigi break; 3114101641Sluigi 3115101641Sluigi case TOK_ENDBRACE: 3116101641Sluigi if (!open_par) 3117101641Sluigi errx(EX_USAGE, "+missing \")\"\n"); 3118101641Sluigi open_par = 0; 3119102087Sluigi prev = NULL; 3120101641Sluigi break; 3121101641Sluigi 312298943Sluigi case TOK_IN: 312398943Sluigi fill_cmd(cmd, O_IN, 0, 0); 312498943Sluigi break; 312598943Sluigi 312698943Sluigi case TOK_OUT: 312798943Sluigi cmd->len ^= F_NOT; /* toggle F_NOT */ 312898943Sluigi fill_cmd(cmd, O_IN, 0, 0); 312998943Sluigi break; 313098943Sluigi 313198943Sluigi case TOK_FRAG: 313298943Sluigi fill_cmd(cmd, O_FRAG, 0, 0); 313398943Sluigi break; 313498943Sluigi 313598943Sluigi case TOK_LAYER2: 313698943Sluigi fill_cmd(cmd, O_LAYER2, 0, 0); 313798943Sluigi break; 313898943Sluigi 313998943Sluigi case TOK_XMIT: 314098943Sluigi case TOK_RECV: 314198943Sluigi case TOK_VIA: 314298943Sluigi NEED1("recv, xmit, via require interface name" 314398943Sluigi " or address"); 314498943Sluigi fill_iface((ipfw_insn_if *)cmd, av[0]); 314598943Sluigi ac--; av++; 314698943Sluigi if (F_LEN(cmd) == 0) /* not a valid address */ 314798943Sluigi break; 314898943Sluigi if (i == TOK_XMIT) 314998943Sluigi cmd->opcode = O_XMIT; 315098943Sluigi else if (i == TOK_RECV) 315198943Sluigi cmd->opcode = O_RECV; 315298943Sluigi else if (i == TOK_VIA) 315398943Sluigi cmd->opcode = O_VIA; 315498943Sluigi break; 315598943Sluigi 315699475Sluigi case TOK_ICMPTYPES: 315799475Sluigi NEED1("icmptypes requires list of types"); 315899475Sluigi fill_icmptypes((ipfw_insn_u32 *)cmd, *av); 315999475Sluigi av++; ac--; 316099475Sluigi break; 316199475Sluigi 316298943Sluigi case TOK_IPTTL: 316398943Sluigi NEED1("ipttl requires TTL"); 3164116690Sluigi if (strpbrk(*av, "-,")) { 3165116690Sluigi if (!add_ports(cmd, *av, 0, O_IPTTL)) 3166116690Sluigi errx(EX_DATAERR, "invalid ipttl %s", *av); 3167116690Sluigi } else 3168116690Sluigi fill_cmd(cmd, O_IPTTL, 0, strtoul(*av, NULL, 0)); 316998943Sluigi ac--; av++; 317098943Sluigi break; 317198943Sluigi 317298943Sluigi case TOK_IPID: 3173116690Sluigi NEED1("ipid requires id"); 3174116690Sluigi if (strpbrk(*av, "-,")) { 3175116690Sluigi if (!add_ports(cmd, *av, 0, O_IPID)) 3176116690Sluigi errx(EX_DATAERR, "invalid ipid %s", *av); 3177116690Sluigi } else 3178116690Sluigi fill_cmd(cmd, O_IPID, 0, strtoul(*av, NULL, 0)); 317998943Sluigi ac--; av++; 318098943Sluigi break; 318198943Sluigi 318298943Sluigi case TOK_IPLEN: 318398943Sluigi NEED1("iplen requires length"); 3184116690Sluigi if (strpbrk(*av, "-,")) { 3185116690Sluigi if (!add_ports(cmd, *av, 0, O_IPLEN)) 3186116690Sluigi errx(EX_DATAERR, "invalid ip len %s", *av); 3187116690Sluigi } else 3188116690Sluigi fill_cmd(cmd, O_IPLEN, 0, strtoul(*av, NULL, 0)); 318998943Sluigi ac--; av++; 319098943Sluigi break; 319198943Sluigi 319298943Sluigi case TOK_IPVER: 319398943Sluigi NEED1("ipver requires version"); 319498943Sluigi fill_cmd(cmd, O_IPVER, 0, strtoul(*av, NULL, 0)); 319598943Sluigi ac--; av++; 319698943Sluigi break; 319798943Sluigi 319899475Sluigi case TOK_IPPRECEDENCE: 319999475Sluigi NEED1("ipprecedence requires value"); 320099475Sluigi fill_cmd(cmd, O_IPPRECEDENCE, 0, 320199475Sluigi (strtoul(*av, NULL, 0) & 7) << 5); 320299475Sluigi ac--; av++; 320399475Sluigi break; 320499475Sluigi 320598943Sluigi case TOK_IPOPTS: 320698943Sluigi NEED1("missing argument for ipoptions"); 3207101116Sluigi fill_flags(cmd, O_IPOPT, f_ipopts, *av); 320898943Sluigi ac--; av++; 320998943Sluigi break; 321098943Sluigi 321199475Sluigi case TOK_IPTOS: 321299475Sluigi NEED1("missing argument for iptos"); 3213101116Sluigi fill_flags(cmd, O_IPTOS, f_iptos, *av); 321499475Sluigi ac--; av++; 321599475Sluigi break; 321699475Sluigi 321798943Sluigi case TOK_UID: 321898943Sluigi NEED1("uid requires argument"); 321998943Sluigi { 322098943Sluigi char *end; 322198943Sluigi uid_t uid; 322298943Sluigi struct passwd *pwd; 322398943Sluigi 322498943Sluigi cmd->opcode = O_UID; 322598943Sluigi uid = strtoul(*av, &end, 0); 322698943Sluigi pwd = (*end == '\0') ? getpwuid(uid) : getpwnam(*av); 322798943Sluigi if (pwd == NULL) 322898943Sluigi errx(EX_DATAERR, "uid \"%s\" nonexistent", *av); 3229106504Smaxim cmd32->d[0] = pwd->pw_uid; 323098943Sluigi cmd->len = F_INSN_SIZE(ipfw_insn_u32); 323198943Sluigi ac--; av++; 323298943Sluigi } 323398943Sluigi break; 323498943Sluigi 323598943Sluigi case TOK_GID: 323698943Sluigi NEED1("gid requires argument"); 323798943Sluigi { 323898943Sluigi char *end; 323998943Sluigi gid_t gid; 324098943Sluigi struct group *grp; 324198943Sluigi 324298943Sluigi cmd->opcode = O_GID; 324398943Sluigi gid = strtoul(*av, &end, 0); 324498943Sluigi grp = (*end == '\0') ? getgrgid(gid) : getgrnam(*av); 324598943Sluigi if (grp == NULL) 324698943Sluigi errx(EX_DATAERR, "gid \"%s\" nonexistent", *av); 3247106504Smaxim cmd32->d[0] = grp->gr_gid; 324898943Sluigi cmd->len = F_INSN_SIZE(ipfw_insn_u32); 324998943Sluigi ac--; av++; 325098943Sluigi } 325198943Sluigi break; 325298943Sluigi 325398943Sluigi case TOK_ESTAB: 325498943Sluigi fill_cmd(cmd, O_ESTAB, 0, 0); 325598943Sluigi break; 325698943Sluigi 325798943Sluigi case TOK_SETUP: 325898943Sluigi fill_cmd(cmd, O_TCPFLAGS, 0, 325998943Sluigi (TH_SYN) | ( (TH_ACK) & 0xff) <<8 ); 326098943Sluigi break; 326198943Sluigi 326298943Sluigi case TOK_TCPOPTS: 326398943Sluigi NEED1("missing argument for tcpoptions"); 326498943Sluigi fill_flags(cmd, O_TCPOPTS, f_tcpopts, *av); 326598943Sluigi ac--; av++; 326698943Sluigi break; 326798943Sluigi 326898943Sluigi case TOK_TCPSEQ: 326998943Sluigi case TOK_TCPACK: 327098943Sluigi NEED1("tcpseq/tcpack requires argument"); 327198943Sluigi cmd->len = F_INSN_SIZE(ipfw_insn_u32); 327298943Sluigi cmd->opcode = (i == TOK_TCPSEQ) ? O_TCPSEQ : O_TCPACK; 327398943Sluigi cmd32->d[0] = htonl(strtoul(*av, NULL, 0)); 327498943Sluigi ac--; av++; 327598943Sluigi break; 327698943Sluigi 327798943Sluigi case TOK_TCPWIN: 327898943Sluigi NEED1("tcpwin requires length"); 327998943Sluigi fill_cmd(cmd, O_TCPWIN, 0, 328098943Sluigi htons(strtoul(*av, NULL, 0))); 328198943Sluigi ac--; av++; 328298943Sluigi break; 328398943Sluigi 328498943Sluigi case TOK_TCPFLAGS: 328598943Sluigi NEED1("missing argument for tcpflags"); 328698943Sluigi cmd->opcode = O_TCPFLAGS; 328798943Sluigi fill_flags(cmd, O_TCPFLAGS, f_tcpflags, *av); 328898943Sluigi ac--; av++; 328998943Sluigi break; 329098943Sluigi 329198943Sluigi case TOK_KEEPSTATE: 3292101641Sluigi if (open_par) 3293101641Sluigi errx(EX_USAGE, "keep-state cannot be part " 3294101641Sluigi "of an or block"); 329599909Sluigi if (have_state) 3296101116Sluigi errx(EX_USAGE, "only one of keep-state " 329799909Sluigi "and limit is allowed"); 3298101116Sluigi have_state = cmd; 329998943Sluigi fill_cmd(cmd, O_KEEP_STATE, 0, 0); 330098943Sluigi break; 330198943Sluigi 330298943Sluigi case TOK_LIMIT: 3303101641Sluigi if (open_par) 3304101641Sluigi errx(EX_USAGE, "limit cannot be part " 3305101641Sluigi "of an or block"); 330699909Sluigi if (have_state) 3307101116Sluigi errx(EX_USAGE, "only one of keep-state " 330899909Sluigi "and limit is allowed"); 3309101641Sluigi NEED1("limit needs mask and # of connections"); 3310101116Sluigi have_state = cmd; 331198943Sluigi { 331298943Sluigi ipfw_insn_limit *c = (ipfw_insn_limit *)cmd; 331398943Sluigi 331498943Sluigi cmd->len = F_INSN_SIZE(ipfw_insn_limit); 331598943Sluigi cmd->opcode = O_LIMIT; 331698943Sluigi c->limit_mask = 0; 331798943Sluigi c->conn_limit = 0; 331898943Sluigi for (; ac >1 ;) { 331998943Sluigi int val; 332098943Sluigi 332198943Sluigi val = match_token(limit_masks, *av); 332298943Sluigi if (val <= 0) 332398943Sluigi break; 332498943Sluigi c->limit_mask |= val; 332598943Sluigi ac--; av++; 332698943Sluigi } 332798943Sluigi c->conn_limit = atoi(*av); 332898943Sluigi if (c->conn_limit == 0) 332998943Sluigi errx(EX_USAGE, "limit: limit must be >0"); 333098943Sluigi if (c->limit_mask == 0) 333198943Sluigi errx(EX_USAGE, "missing limit mask"); 333298943Sluigi ac--; av++; 333398943Sluigi } 333498943Sluigi break; 333598943Sluigi 3336102087Sluigi case TOK_PROTO: 3337102087Sluigi NEED1("missing protocol"); 3338102087Sluigi if (add_proto(cmd, *av)) { 3339102087Sluigi proto = cmd->arg1; 3340102087Sluigi ac--; av++; 3341102098Sluigi } else 3342116438Smaxim errx(EX_DATAERR, "invalid protocol ``%s''", 3343116438Smaxim *av); 3344102087Sluigi break; 3345106505Smaxim 3346102087Sluigi case TOK_SRCIP: 3347102087Sluigi NEED1("missing source IP"); 3348102087Sluigi if (add_srcip(cmd, *av)) { 3349102087Sluigi ac--; av++; 3350102087Sluigi } 3351102087Sluigi break; 3352102087Sluigi 3353102087Sluigi case TOK_DSTIP: 3354102087Sluigi NEED1("missing destination IP"); 3355102087Sluigi if (add_dstip(cmd, *av)) { 3356102087Sluigi ac--; av++; 3357102087Sluigi } 3358102087Sluigi break; 3359102087Sluigi 3360102087Sluigi case TOK_SRCPORT: 3361102087Sluigi NEED1("missing source port"); 3362102087Sluigi if (!strncmp(*av, "any", strlen(*av)) || 3363102087Sluigi add_ports(cmd, *av, proto, O_IP_SRCPORT)) { 3364102087Sluigi ac--; av++; 3365102087Sluigi } else 3366102087Sluigi errx(EX_DATAERR, "invalid source port %s", *av); 3367102087Sluigi break; 3368102087Sluigi 3369102087Sluigi case TOK_DSTPORT: 3370102087Sluigi NEED1("missing destination port"); 3371102087Sluigi if (!strncmp(*av, "any", strlen(*av)) || 3372102087Sluigi add_ports(cmd, *av, proto, O_IP_DSTPORT)) { 3373102087Sluigi ac--; av++; 3374102087Sluigi } else 3375102087Sluigi errx(EX_DATAERR, "invalid destination port %s", 3376102087Sluigi *av); 3377102087Sluigi break; 3378102087Sluigi 3379102087Sluigi case TOK_MAC: 3380102087Sluigi if (ac < 2) 3381102087Sluigi errx(EX_USAGE, "MAC dst-mac src-mac"); 3382102087Sluigi if (add_mac(cmd, ac, av)) { 3383102087Sluigi ac -= 2; av += 2; 3384102087Sluigi } 3385102087Sluigi break; 3386102087Sluigi 3387102087Sluigi case TOK_MACTYPE: 3388102087Sluigi NEED1("missing mac type"); 3389102087Sluigi if (!add_mactype(cmd, ac, *av)) 3390116438Smaxim errx(EX_DATAERR, "invalid mac type %s", *av); 3391102087Sluigi ac--; av++; 3392102087Sluigi break; 3393102087Sluigi 3394112250Scjc case TOK_VERREVPATH: 3395112250Scjc fill_cmd(cmd, O_VERREVPATH, 0, 0); 3396112250Scjc break; 3397116919Sluigi 3398117241Sluigi case TOK_IPSEC: 3399117241Sluigi fill_cmd(cmd, O_IPSEC, 0, 0); 3400117241Sluigi break; 3401117241Sluigi 3402117469Sluigi case TOK_COMMENT: 3403117469Sluigi fill_comment(cmd, ac, av); 3404117469Sluigi av += ac; 3405117469Sluigi ac = 0; 3406117469Sluigi break; 3407117469Sluigi 340898943Sluigi default: 340998943Sluigi errx(EX_USAGE, "unrecognised option [%d] %s\n", i, s); 341098943Sluigi } 341198943Sluigi if (F_LEN(cmd) > 0) { /* prepare to advance */ 341298943Sluigi prev = cmd; 341398943Sluigi cmd = next_cmd(cmd); 341498943Sluigi } 341598943Sluigi } 341698943Sluigi 341798943Sluigidone: 341898943Sluigi /* 341998943Sluigi * Now copy stuff into the rule. 342098943Sluigi * If we have a keep-state option, the first instruction 342198943Sluigi * must be a PROBE_STATE (which is generated here). 342298943Sluigi * If we have a LOG option, it was stored as the first command, 342398943Sluigi * and now must be moved to the top of the action part. 342498943Sluigi */ 342598943Sluigi dst = (ipfw_insn *)rule->cmd; 342698943Sluigi 342798943Sluigi /* 3428107289Sluigi * First thing to write into the command stream is the match probability. 3429107289Sluigi */ 3430107289Sluigi if (match_prob != 1) { /* 1 means always match */ 3431107289Sluigi dst->opcode = O_PROB; 3432107289Sluigi dst->len = 2; 3433107289Sluigi *((int32_t *)(dst+1)) = (int32_t)(match_prob * 0x7fffffff); 3434107289Sluigi dst += dst->len; 3435107289Sluigi } 3436107289Sluigi 3437107289Sluigi /* 343898943Sluigi * generate O_PROBE_STATE if necessary 343998943Sluigi */ 3440101116Sluigi if (have_state && have_state->opcode != O_CHECK_STATE) { 344198943Sluigi fill_cmd(dst, O_PROBE_STATE, 0, 0); 344298943Sluigi dst = next_cmd(dst); 344398943Sluigi } 344498943Sluigi /* 3445101116Sluigi * copy all commands but O_LOG, O_KEEP_STATE, O_LIMIT 344698943Sluigi */ 344798943Sluigi for (src = (ipfw_insn *)cmdbuf; src != cmd; src += i) { 344898943Sluigi i = F_LEN(src); 344998943Sluigi 3450101116Sluigi switch (src->opcode) { 3451101116Sluigi case O_LOG: 3452101116Sluigi case O_KEEP_STATE: 3453101116Sluigi case O_LIMIT: 3454101116Sluigi break; 3455101116Sluigi default: 3456117328Sluigi bcopy(src, dst, i * sizeof(uint32_t)); 345798943Sluigi dst += i; 345898943Sluigi } 345998943Sluigi } 346098943Sluigi 346198943Sluigi /* 3462101116Sluigi * put back the have_state command as last opcode 3463101116Sluigi */ 3464101295Sluigi if (have_state && have_state->opcode != O_CHECK_STATE) { 3465101116Sluigi i = F_LEN(have_state); 3466117328Sluigi bcopy(have_state, dst, i * sizeof(uint32_t)); 3467101116Sluigi dst += i; 3468101116Sluigi } 3469101116Sluigi /* 347098943Sluigi * start action section 347198943Sluigi */ 347298943Sluigi rule->act_ofs = dst - rule->cmd; 347398943Sluigi 347498943Sluigi /* 347598943Sluigi * put back O_LOG if necessary 347698943Sluigi */ 347798943Sluigi src = (ipfw_insn *)cmdbuf; 347898943Sluigi if ( src->opcode == O_LOG ) { 347998943Sluigi i = F_LEN(src); 3480117328Sluigi bcopy(src, dst, i * sizeof(uint32_t)); 348198943Sluigi dst += i; 348298943Sluigi } 348398943Sluigi /* 348498943Sluigi * copy all other actions 348598943Sluigi */ 348698943Sluigi for (src = (ipfw_insn *)actbuf; src != action; src += i) { 348798943Sluigi i = F_LEN(src); 3488117328Sluigi bcopy(src, dst, i * sizeof(uint32_t)); 348998943Sluigi dst += i; 349098943Sluigi } 349198943Sluigi 3492117328Sluigi rule->cmd_len = (uint32_t *)dst - (uint32_t *)(rule->cmd); 3493117469Sluigi i = (char *)dst - (char *)rule; 3494117328Sluigi if (do_cmd(IP_FW_ADD, rule, (socklen_t)&i) == -1) 349598943Sluigi err(EX_UNAVAILABLE, "getsockopt(%s)", "IP_FW_ADD"); 349698943Sluigi if (!do_quiet) 3497117469Sluigi show_ipfw(rule, 0, 0); 349898943Sluigi} 349998943Sluigi 350098943Sluigistatic void 3501117328Sluigizero(int ac, char *av[], int optname /* IP_FW_ZERO or IP_FW_RESETLOG */) 350298943Sluigi{ 350398943Sluigi int rulenum; 350498943Sluigi int failed = EX_OK; 3505117469Sluigi char const *name = optname == IP_FW_ZERO ? "ZERO" : "RESETLOG"; 350698943Sluigi 350798943Sluigi av++; ac--; 350898943Sluigi 350998943Sluigi if (!ac) { 351098943Sluigi /* clear all entries */ 3511117328Sluigi if (do_cmd(optname, NULL, 0) < 0) 3512117328Sluigi err(EX_UNAVAILABLE, "setsockopt(IP_FW_%s)", name); 351398943Sluigi if (!do_quiet) 3514117328Sluigi printf("%s.\n", optname == IP_FW_ZERO ? 3515117328Sluigi "Accounting cleared":"Logging counts reset"); 351698943Sluigi 351798943Sluigi return; 351898943Sluigi } 351998943Sluigi 352098943Sluigi while (ac) { 352198943Sluigi /* Rule number */ 352298943Sluigi if (isdigit(**av)) { 352398943Sluigi rulenum = atoi(*av); 352498943Sluigi av++; 352598943Sluigi ac--; 3526117328Sluigi if (do_cmd(optname, &rulenum, sizeof rulenum)) { 3527117328Sluigi warn("rule %u: setsockopt(IP_FW_%s)", 3528117328Sluigi rulenum, name); 352998943Sluigi failed = EX_UNAVAILABLE; 353098943Sluigi } else if (!do_quiet) 3531117328Sluigi printf("Entry %d %s.\n", rulenum, 3532117328Sluigi optname == IP_FW_ZERO ? 3533117328Sluigi "cleared" : "logging count reset"); 353498943Sluigi } else { 353598943Sluigi errx(EX_USAGE, "invalid rule number ``%s''", *av); 353698943Sluigi } 353798943Sluigi } 353898943Sluigi if (failed != EX_OK) 353998943Sluigi exit(failed); 354098943Sluigi} 354198943Sluigi 354298943Sluigistatic void 3543117328Sluigiflush(void) 354498943Sluigi{ 354598943Sluigi int cmd = do_pipe ? IP_DUMMYNET_FLUSH : IP_FW_FLUSH; 354698943Sluigi 354798943Sluigi if (!do_force && !do_quiet) { /* need to ask user */ 354898943Sluigi int c; 354998943Sluigi 355098943Sluigi printf("Are you sure? [yn] "); 355198943Sluigi fflush(stdout); 355298943Sluigi do { 355398943Sluigi c = toupper(getc(stdin)); 355498943Sluigi while (c != '\n' && getc(stdin) != '\n') 355598943Sluigi if (feof(stdin)) 355698943Sluigi return; /* and do not flush */ 355798943Sluigi } while (c != 'Y' && c != 'N'); 355898943Sluigi printf("\n"); 355998943Sluigi if (c == 'N') /* user said no */ 356098943Sluigi return; 356198943Sluigi } 3562117328Sluigi if (do_cmd(cmd, NULL, 0) < 0) 356398943Sluigi err(EX_UNAVAILABLE, "setsockopt(IP_%s_FLUSH)", 356498943Sluigi do_pipe ? "DUMMYNET" : "FW"); 356598943Sluigi if (!do_quiet) 356698943Sluigi printf("Flushed all %s.\n", do_pipe ? "pipes" : "rules"); 356798943Sluigi} 356898943Sluigi 3569117469Sluigi/* 3570117469Sluigi * called with the arguments (excluding program name). 3571117469Sluigi */ 357298943Sluigistatic int 3573117328Sluigiipfw_main(int oldac, char **oldav) 357498943Sluigi{ 3575117469Sluigi int ch, ac, save_ac; 3576117469Sluigi char **av, **save_av; 3577117469Sluigi int do_acct = 0; /* Show packet/byte count */ 3578117469Sluigi 3579117469Sluigi#define WHITESP " \t\f\v\n\r" 3580117469Sluigi if (oldac == 1) { 3581117328Sluigi /* 3582117328Sluigi * If we are called with a single string, try to split it into 3583117328Sluigi * arguments for subsequent parsing. 3584117328Sluigi * But first, remove spaces after a ',', by copying the string 3585117328Sluigi * in-place. 3586117328Sluigi */ 3587117469Sluigi char *arg = oldav[0]; /* The string... */ 3588117328Sluigi int l = strlen(arg); 3589117328Sluigi int copy = 0; /* 1 if we need to copy, 0 otherwise */ 3590117328Sluigi int i, j; 3591117469Sluigi for (i = j = 0; i < l; i++) { 3592117469Sluigi if (arg[i] == '#') /* comment marker */ 3593117469Sluigi break; 3594117328Sluigi if (copy) { 3595117328Sluigi arg[j++] = arg[i]; 3596117469Sluigi copy = !index("," WHITESP, arg[i]); 3597117328Sluigi } else { 3598117469Sluigi copy = !index(WHITESP, arg[i]); 3599117328Sluigi if (copy) 3600117328Sluigi arg[j++] = arg[i]; 3601117328Sluigi } 3602117469Sluigi } 3603117328Sluigi if (!copy && j > 0) /* last char was a 'blank', remove it */ 3604117328Sluigi j--; 3605117328Sluigi l = j; /* the new argument length */ 3606117328Sluigi arg[j++] = '\0'; 3607117469Sluigi if (l == 0) /* empty string! */ 3608117469Sluigi show_usage(); 3609117328Sluigi 3610117328Sluigi /* 3611117328Sluigi * First, count number of arguments. Because of the previous 3612117469Sluigi * processing, this is just the number of blanks plus 1. 3613117328Sluigi */ 3614117469Sluigi for (i = 0, ac = 1; i < l; i++) 3615117469Sluigi if (index(WHITESP, arg[i]) != NULL) 3616117328Sluigi ac++; 3617117328Sluigi 3618117328Sluigi av = calloc(ac, sizeof(char *)); 3619117328Sluigi 3620117328Sluigi /* 3621117328Sluigi * Second, copy arguments from cmd[] to av[]. For each one, 3622117328Sluigi * j is the initial character, i is the one past the end. 3623117328Sluigi */ 3624117469Sluigi for (ac = 0, i = j = 0; i < l; i++) 3625117469Sluigi if (index(WHITESP, arg[i]) != NULL || i == l-1) { 3626117328Sluigi if (i == l-1) 3627117328Sluigi i++; 3628117328Sluigi av[ac] = calloc(i-j+1, 1); 3629117328Sluigi bcopy(arg+j, av[ac], i-j); 3630117328Sluigi ac++; 3631117328Sluigi j = i + 1; 3632117328Sluigi } 3633117328Sluigi } else { 3634117328Sluigi /* 3635117328Sluigi * If an argument ends with ',' join with the next one. 3636117328Sluigi */ 3637117328Sluigi int first, i, l; 3638117328Sluigi 3639117328Sluigi av = calloc(oldac, sizeof(char *)); 3640117328Sluigi for (first = i = ac = 0, l = 0; i < oldac; i++) { 3641117328Sluigi char *arg = oldav[i]; 3642117328Sluigi int k = strlen(arg); 3643117328Sluigi 3644117328Sluigi l += k; 3645117328Sluigi if (arg[k-1] != ',' || i == oldac-1) { 3646117328Sluigi /* Time to copy. */ 3647117328Sluigi av[ac] = calloc(l+1, 1); 3648117328Sluigi for (l=0; first <= i; first++) { 3649117328Sluigi strcat(av[ac]+l, oldav[first]); 3650117328Sluigi l += strlen(oldav[first]); 3651117328Sluigi } 3652117328Sluigi ac++; 3653117328Sluigi l = 0; 3654117328Sluigi first = i+1; 3655117328Sluigi } 3656117328Sluigi } 3657117328Sluigi } 3658117328Sluigi 3659117469Sluigi if (ac == 0) 366098943Sluigi show_usage(); 366198943Sluigi 366298943Sluigi /* Set the force flag for non-interactive processes */ 366398943Sluigi do_force = !isatty(STDIN_FILENO); 366498943Sluigi 3665117469Sluigi /* Save arguments for final freeing of memory. */ 3666117469Sluigi save_ac = ac; 3667117469Sluigi save_av = av; 3668117469Sluigi 3669117469Sluigi optind = optreset = 0; 3670117328Sluigi while ((ch = getopt(ac, av, "acdefhnNqs:Stv")) != -1) 367198943Sluigi switch (ch) { 367298943Sluigi case 'a': 367398943Sluigi do_acct = 1; 367498943Sluigi break; 3675117328Sluigi 3676102098Sluigi case 'c': 3677102098Sluigi do_compact = 1; 3678102098Sluigi break; 3679117328Sluigi 368098943Sluigi case 'd': 368198943Sluigi do_dynamic = 1; 368298943Sluigi break; 3683117328Sluigi 368498943Sluigi case 'e': 368598943Sluigi do_expired = 1; 368698943Sluigi break; 3687117328Sluigi 368898943Sluigi case 'f': 368998943Sluigi do_force = 1; 369098943Sluigi break; 3691117328Sluigi 3692117328Sluigi case 'h': /* help */ 3693117328Sluigi help(); 3694117328Sluigi break; /* NOTREACHED */ 3695117328Sluigi 3696117328Sluigi case 'n': 3697117328Sluigi test_only = 1; 3698117328Sluigi break; 3699117328Sluigi 370098943Sluigi case 'N': 370198943Sluigi do_resolv = 1; 370298943Sluigi break; 3703117328Sluigi 370498943Sluigi case 'q': 370598943Sluigi do_quiet = 1; 370698943Sluigi break; 3707117328Sluigi 3708117328Sluigi case 's': /* sort */ 3709117328Sluigi do_sort = atoi(optarg); 3710117328Sluigi break; 3711117328Sluigi 3712101628Sluigi case 'S': 3713101628Sluigi show_sets = 1; 3714101628Sluigi break; 3715117328Sluigi 371698943Sluigi case 't': 371798943Sluigi do_time = 1; 371898943Sluigi break; 3719117328Sluigi 372098943Sluigi case 'v': /* verbose */ 3721117328Sluigi verbose = 1; 372298943Sluigi break; 3723117328Sluigi 372498943Sluigi default: 372598943Sluigi show_usage(); 372698943Sluigi } 372798943Sluigi 372898943Sluigi ac -= optind; 372998943Sluigi av += optind; 373098943Sluigi NEED1("bad arguments, for usage summary ``ipfw''"); 373198943Sluigi 373298943Sluigi /* 373398943Sluigi * optional: pipe or queue 373498943Sluigi */ 373598943Sluigi if (!strncmp(*av, "pipe", strlen(*av))) { 373698943Sluigi do_pipe = 1; 373798943Sluigi ac--; 373898943Sluigi av++; 373998943Sluigi } else if (!strncmp(*av, "queue", strlen(*av))) { 374098943Sluigi do_pipe = 2; 374198943Sluigi ac--; 374298943Sluigi av++; 374398943Sluigi } 374498943Sluigi NEED1("missing command"); 374598943Sluigi 374698943Sluigi /* 3747117328Sluigi * For pipes and queues we normally say 'pipe NN config' 374898943Sluigi * but the code is easier to parse as 'pipe config NN' 374998943Sluigi * so we swap the two arguments. 375098943Sluigi */ 3751117469Sluigi if (do_pipe > 0 && ac > 1 && isdigit(*av[0])) { 375298943Sluigi char *p = av[0]; 375398943Sluigi av[0] = av[1]; 375498943Sluigi av[1] = p; 375598943Sluigi } 3756117328Sluigi 375798943Sluigi if (!strncmp(*av, "add", strlen(*av))) 375898943Sluigi add(ac, av); 375998943Sluigi else if (do_pipe && !strncmp(*av, "config", strlen(*av))) 376098943Sluigi config_pipe(ac, av); 3761101978Sluigi else if (!strncmp(*av, "delete", strlen(*av))) 376298943Sluigi delete(ac, av); 376398943Sluigi else if (!strncmp(*av, "flush", strlen(*av))) 376498943Sluigi flush(); 376598943Sluigi else if (!strncmp(*av, "zero", strlen(*av))) 3766117328Sluigi zero(ac, av, IP_FW_ZERO); 376798943Sluigi else if (!strncmp(*av, "resetlog", strlen(*av))) 3768117328Sluigi zero(ac, av, IP_FW_RESETLOG); 376998943Sluigi else if (!strncmp(*av, "print", strlen(*av)) || 377098943Sluigi !strncmp(*av, "list", strlen(*av))) 3771117469Sluigi list(ac, av, do_acct); 3772101978Sluigi else if (!strncmp(*av, "set", strlen(*av))) 3773101978Sluigi sets_handler(ac, av); 3774109126Sdillon else if (!strncmp(*av, "enable", strlen(*av))) 3775109126Sdillon sysctl_handler(ac, av, 1); 3776109126Sdillon else if (!strncmp(*av, "disable", strlen(*av))) 3777109126Sdillon sysctl_handler(ac, av, 0); 3778117469Sluigi else if (!strncmp(*av, "show", strlen(*av))) 3779117469Sluigi list(ac, av, 1 /* show counters */); 3780117469Sluigi else 378198943Sluigi errx(EX_USAGE, "bad command `%s'", *av); 3782117469Sluigi 3783117469Sluigi /* Free memory allocated in the argument parsing. */ 3784117469Sluigi for (ch=0; ch < save_ac; ch++) 3785117469Sluigi free(save_av[ch]); 3786117469Sluigi free(save_av); 378798943Sluigi return 0; 378898943Sluigi} 378998943Sluigi 379098943Sluigi 379198943Sluigistatic void 3792106505Smaximipfw_readfile(int ac, char *av[]) 379398943Sluigi{ 379498943Sluigi#define MAX_ARGS 32 379598943Sluigi char buf[BUFSIZ]; 3796117469Sluigi char *cmd = NULL, *filename = av[ac-1]; 3797117469Sluigi int c, lineno=0; 379898943Sluigi FILE *f = NULL; 379998943Sluigi pid_t preproc = 0; 380098943Sluigi 3801117469Sluigi filename = av[ac-1]; 3802117469Sluigi 3803117469Sluigi while ((c = getopt(ac, av, "cNnp:qS")) != -1) { 380498943Sluigi switch(c) { 3805117469Sluigi case 'c': 3806117469Sluigi do_compact = 1; 3807117469Sluigi break; 3808117469Sluigi 3809117469Sluigi case 'N': 3810117469Sluigi do_resolv = 1; 3811117469Sluigi break; 3812117469Sluigi 3813117328Sluigi case 'n': 3814117328Sluigi test_only = 1; 3815117328Sluigi break; 3816117328Sluigi 381798943Sluigi case 'p': 381898943Sluigi cmd = optarg; 3819117469Sluigi /* 3820117469Sluigi * Skip previous args and delete last one, so we 3821117469Sluigi * pass all but the last argument to the preprocessor 3822117469Sluigi * via av[optind-1] 3823117469Sluigi */ 3824117469Sluigi av += optind - 1; 3825117469Sluigi ac -= optind - 1; 3826117469Sluigi av[ac-1] = NULL; 3827117469Sluigi fprintf(stderr, "command is %s\n", av[0]); 382898943Sluigi break; 382998943Sluigi 383098943Sluigi case 'q': 3831117469Sluigi do_quiet = 1; 383298943Sluigi break; 383398943Sluigi 3834117469Sluigi case 'S': 3835117469Sluigi show_sets = 1; 3836117469Sluigi break; 3837117469Sluigi 383898943Sluigi default: 383998943Sluigi errx(EX_USAGE, "bad arguments, for usage" 384098943Sluigi " summary ``ipfw''"); 384198943Sluigi } 384298943Sluigi 3843117469Sluigi if (cmd != NULL) 3844108231Skbyanc break; 3845108231Skbyanc } 3846108231Skbyanc 3847117469Sluigi if (cmd == NULL && ac != optind + 1) { 3848117469Sluigi fprintf(stderr, "ac %d, optind %d\n", ac, optind); 3849117469Sluigi errx(EX_USAGE, "extraneous filename arguments"); 3850108231Skbyanc } 3851108231Skbyanc 3852117469Sluigi if ((f = fopen(filename, "r")) == NULL) 3853117469Sluigi err(EX_UNAVAILABLE, "fopen: %s", filename); 385498943Sluigi 3855117469Sluigi if (cmd != NULL) { /* pipe through preprocessor */ 385698943Sluigi int pipedes[2]; 385798943Sluigi 385898943Sluigi if (pipe(pipedes) == -1) 385998943Sluigi err(EX_OSERR, "cannot create pipe"); 386098943Sluigi 3861117469Sluigi preproc = fork(); 3862117469Sluigi if (preproc == -1) 386398943Sluigi err(EX_OSERR, "cannot fork"); 386498943Sluigi 3865117469Sluigi if (preproc == 0) { 3866117469Sluigi /* 3867117469Sluigi * Child, will run the preprocessor with the 3868117469Sluigi * file on stdin and the pipe on stdout. 3869117469Sluigi */ 387098943Sluigi if (dup2(fileno(f), 0) == -1 387198943Sluigi || dup2(pipedes[1], 1) == -1) 387298943Sluigi err(EX_OSERR, "dup2()"); 387398943Sluigi fclose(f); 387498943Sluigi close(pipedes[1]); 387598943Sluigi close(pipedes[0]); 3876117469Sluigi execvp(cmd, av); 387798943Sluigi err(EX_OSERR, "execvp(%s) failed", cmd); 3878117469Sluigi } else { /* parent, will reopen f as the pipe */ 387998943Sluigi fclose(f); 388098943Sluigi close(pipedes[1]); 388198943Sluigi if ((f = fdopen(pipedes[0], "r")) == NULL) { 388298943Sluigi int savederrno = errno; 388398943Sluigi 388498943Sluigi (void)kill(preproc, SIGTERM); 388598943Sluigi errno = savederrno; 388698943Sluigi err(EX_OSERR, "fdopen()"); 388798943Sluigi } 388898943Sluigi } 388998943Sluigi } 389098943Sluigi 3891117469Sluigi while (fgets(buf, BUFSIZ, f)) { /* read commands */ 3892117469Sluigi char linename[10]; 3893117469Sluigi char *args[1]; 3894117469Sluigi 389598943Sluigi lineno++; 389698943Sluigi sprintf(linename, "Line %d", lineno); 3897117328Sluigi setprogname(linename); /* XXX */ 3898117469Sluigi args[0] = buf; 3899117469Sluigi ipfw_main(1, args); 390098943Sluigi } 390198943Sluigi fclose(f); 3902117469Sluigi if (cmd != NULL) { 3903117469Sluigi int status; 3904117469Sluigi 390598943Sluigi if (waitpid(preproc, &status, 0) == -1) 390698943Sluigi errx(EX_OSERR, "waitpid()"); 390798943Sluigi if (WIFEXITED(status) && WEXITSTATUS(status) != EX_OK) 390898943Sluigi errx(EX_UNAVAILABLE, 390998943Sluigi "preprocessor exited with status %d", 391098943Sluigi WEXITSTATUS(status)); 391198943Sluigi else if (WIFSIGNALED(status)) 391298943Sluigi errx(EX_UNAVAILABLE, 391398943Sluigi "preprocessor exited with signal %d", 391498943Sluigi WTERMSIG(status)); 391598943Sluigi } 391698943Sluigi} 391798943Sluigi 391898943Sluigiint 391998943Sluigimain(int ac, char *av[]) 392098943Sluigi{ 392198943Sluigi /* 392298943Sluigi * If the last argument is an absolute pathname, interpret it 392398943Sluigi * as a file to be preprocessed. 392498943Sluigi */ 392598943Sluigi 392698943Sluigi if (ac > 1 && av[ac - 1][0] == '/' && access(av[ac - 1], R_OK) == 0) 392798943Sluigi ipfw_readfile(ac, av); 392898943Sluigi else 3929117469Sluigi ipfw_main(ac-1, av+1); 393098943Sluigi return EX_OK; 393198943Sluigi} 3932