ipfw2.c revision 128067
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 128067 2004-04-09 17:26:01Z maxim $ 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 <netinet/ip_dummynet.h> 5498943Sluigi#include <netinet/tcp.h> 5598943Sluigi#include <arpa/inet.h> 5698943Sluigi 57117328Sluigiint 5898943Sluigi do_resolv, /* Would try to resolve all */ 5998943Sluigi do_time, /* Show time stamps */ 6098943Sluigi do_quiet, /* Be quiet in add and flush */ 6198943Sluigi do_pipe, /* this cmd refers to a pipe */ 6298943Sluigi do_sort, /* field to sort results (0 = no) */ 6398943Sluigi do_dynamic, /* display dynamic rules */ 6498943Sluigi do_expired, /* display expired dynamic rules */ 65102098Sluigi do_compact, /* show rules in compact mode */ 66123804Smaxim do_force, /* do not ask for confirmation */ 67101628Sluigi show_sets, /* display rule sets */ 68117328Sluigi test_only, /* only check syntax */ 69123495Sluigi comment_only, /* only print action and comment */ 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 367119740Stmmdo_cmd(int optname, void *optval, uintptr_t optlen) 368117328Sluigi{ 369117328Sluigi static int s = -1; /* the socket */ 370117328Sluigi int i; 371117577Sluigi 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 */ 504117577Sluigi 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++) 525117577Sluigi 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 649117577Sluigicontigmask(uint8_t *p, int len) 65098943Sluigi{ 65198943Sluigi int i, n; 652117577Sluigi 65398943Sluigi for (i=0; i<len ; i++) 65498943Sluigi if ( (p[i/8] & (1 << (7 - (i%8)))) == 0) /* first bit unset */ 65598943Sluigi break; 65698943Sluigi for (n=i+1; n < len; n++) 65798943Sluigi if ( (p[n/8] & (1 << (7 - (n%8)))) != 0) 65898943Sluigi return -1; /* mask not contiguous */ 65998943Sluigi return i; 66098943Sluigi} 66198943Sluigi 66298943Sluigi/* 66398943Sluigi * print flags set/clear in the two bitmasks passed as parameters. 66498943Sluigi * There is a specialized check for f_tcpflags. 66598943Sluigi */ 66698943Sluigistatic void 667117469Sluigiprint_flags(char const *name, ipfw_insn *cmd, struct _s_x *list) 66898943Sluigi{ 669117469Sluigi char const *comma = ""; 67098943Sluigi int i; 671117577Sluigi uint8_t set = cmd->arg1 & 0xff; 672117577Sluigi uint8_t clear = (cmd->arg1 >> 8) & 0xff; 67398943Sluigi 67498943Sluigi if (list == f_tcpflags && set == TH_SYN && clear == TH_ACK) { 67598943Sluigi printf(" setup"); 67698943Sluigi return; 67798943Sluigi } 67898943Sluigi 67998943Sluigi printf(" %s ", name); 68098943Sluigi for (i=0; list[i].x != 0; i++) { 68198943Sluigi if (set & list[i].x) { 68298943Sluigi set &= ~list[i].x; 68398943Sluigi printf("%s%s", comma, list[i].s); 68498943Sluigi comma = ","; 68598943Sluigi } 68698943Sluigi if (clear & list[i].x) { 68798943Sluigi clear &= ~list[i].x; 68898943Sluigi printf("%s!%s", comma, list[i].s); 68998943Sluigi comma = ","; 69098943Sluigi } 69198943Sluigi } 69298943Sluigi} 69398943Sluigi 69498943Sluigi/* 69598943Sluigi * Print the ip address contained in a command. 69698943Sluigi */ 69798943Sluigistatic void 698117469Sluigiprint_ip(ipfw_insn_ip *cmd, char const *s) 69998943Sluigi{ 70098943Sluigi struct hostent *he = NULL; 701117328Sluigi int len = F_LEN((ipfw_insn *)cmd); 702117328Sluigi uint32_t *a = ((ipfw_insn_u32 *)cmd)->d; 70398943Sluigi 704102087Sluigi printf("%s%s ", cmd->o.len & F_NOT ? " not": "", s); 70598943Sluigi 70698943Sluigi if (cmd->o.opcode == O_IP_SRC_ME || cmd->o.opcode == O_IP_DST_ME) { 70798943Sluigi printf("me"); 70898943Sluigi return; 70998943Sluigi } 71098943Sluigi if (cmd->o.opcode == O_IP_SRC_SET || cmd->o.opcode == O_IP_DST_SET) { 711117328Sluigi uint32_t x, *map = (uint32_t *)&(cmd->mask); 712116716Sluigi int i, j; 71398943Sluigi char comma = '{'; 71498943Sluigi 71598943Sluigi x = cmd->o.arg1 - 1; 71698943Sluigi x = htonl( ~x ); 71798943Sluigi cmd->addr.s_addr = htonl(cmd->addr.s_addr); 71898943Sluigi printf("%s/%d", inet_ntoa(cmd->addr), 719117577Sluigi contigmask((uint8_t *)&x, 32)); 72098943Sluigi x = cmd->addr.s_addr = htonl(cmd->addr.s_addr); 72198943Sluigi x &= 0xff; /* base */ 722116716Sluigi /* 723116716Sluigi * Print bits and ranges. 724116716Sluigi * Locate first bit set (i), then locate first bit unset (j). 725116716Sluigi * If we have 3+ consecutive bits set, then print them as a 726116716Sluigi * range, otherwise only print the initial bit and rescan. 727116716Sluigi */ 72898943Sluigi for (i=0; i < cmd->o.arg1; i++) 729117328Sluigi if (map[i/32] & (1<<(i & 31))) { 730116716Sluigi for (j=i+1; j < cmd->o.arg1; j++) 731117328Sluigi if (!(map[ j/32] & (1<<(j & 31)))) 732116716Sluigi break; 73398943Sluigi printf("%c%d", comma, i+x); 734116716Sluigi if (j>i+2) { /* range has at least 3 elements */ 735116716Sluigi printf("-%d", j-1+x); 736116716Sluigi i = j-1; 737116716Sluigi } 73898943Sluigi comma = ','; 73998943Sluigi } 74098943Sluigi printf("}"); 74198943Sluigi return; 74298943Sluigi } 743117328Sluigi /* 744117328Sluigi * len == 2 indicates a single IP, whereas lists of 1 or more 745117328Sluigi * addr/mask pairs have len = (2n+1). We convert len to n so we 746117328Sluigi * use that to count the number of entries. 747117328Sluigi */ 748117328Sluigi for (len = len / 2; len > 0; len--, a += 2) { 749117328Sluigi int mb = /* mask length */ 750117328Sluigi (cmd->o.opcode == O_IP_SRC || cmd->o.opcode == O_IP_DST) ? 751117577Sluigi 32 : contigmask((uint8_t *)&(a[1]), 32); 75298943Sluigi if (mb == 32 && do_resolv) 753117328Sluigi he = gethostbyaddr((char *)&(a[0]), sizeof(u_long), AF_INET); 75498943Sluigi if (he != NULL) /* resolved to name */ 75598943Sluigi printf("%s", he->h_name); 75698943Sluigi else if (mb == 0) /* any */ 75798943Sluigi printf("any"); 75898943Sluigi else { /* numeric IP followed by some kind of mask */ 759117328Sluigi printf("%s", inet_ntoa( *((struct in_addr *)&a[0]) ) ); 76098943Sluigi if (mb < 0) 761117328Sluigi printf(":%s", inet_ntoa( *((struct in_addr *)&a[1]) ) ); 76298943Sluigi else if (mb < 32) 76398943Sluigi printf("/%d", mb); 76498943Sluigi } 765117328Sluigi if (len > 1) 766117328Sluigi printf(","); 767117328Sluigi } 76898943Sluigi} 76998943Sluigi 77098943Sluigi/* 77198943Sluigi * prints a MAC address/mask pair 77298943Sluigi */ 77398943Sluigistatic void 774117577Sluigiprint_mac(uint8_t *addr, uint8_t *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{ 855123495Sluigi if (comment_only) 856123495Sluigi return; 857102087Sluigi if ( (*flags & HAVE_IP) == HAVE_IP) 858102087Sluigi *flags |= HAVE_OPTIONS; 859102087Sluigi 860102087Sluigi if ( (*flags & (HAVE_MAC|HAVE_MACTYPE|HAVE_OPTIONS)) == HAVE_MAC && 861102087Sluigi cmd != O_MAC_TYPE) { 862102087Sluigi /* 863102087Sluigi * mac-type was optimized out by the compiler, 864102087Sluigi * restore it 865102087Sluigi */ 866102087Sluigi printf(" any"); 867102087Sluigi *flags |= HAVE_MACTYPE | HAVE_OPTIONS; 868102087Sluigi return; 869101978Sluigi } 870102087Sluigi if ( !(*flags & HAVE_OPTIONS)) { 871102087Sluigi if ( !(*flags & HAVE_PROTO) && (want & HAVE_PROTO)) 872102087Sluigi printf(" ip"); 873102087Sluigi if ( !(*flags & HAVE_SRCIP) && (want & HAVE_SRCIP)) 874102087Sluigi printf(" from any"); 875102087Sluigi if ( !(*flags & HAVE_DSTIP) && (want & HAVE_DSTIP)) 876102087Sluigi printf(" to any"); 877102087Sluigi } 87898943Sluigi *flags |= want; 87998943Sluigi} 88098943Sluigi 88198943Sluigistatic void 882112189Smaximshow_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth) 88398943Sluigi{ 884107291Skeramida static int twidth = 0; 88598943Sluigi int l; 88698943Sluigi ipfw_insn *cmd; 887117626Sluigi char *comment = NULL; /* ptr to comment if we have one */ 88898943Sluigi int proto = 0; /* default */ 88998943Sluigi int flags = 0; /* prerequisites */ 89098943Sluigi ipfw_insn_log *logptr = NULL; /* set if we find an O_LOG */ 89198943Sluigi int or_block = 0; /* we are in an or block */ 892117328Sluigi uint32_t set_disable; 89398943Sluigi 894115793Sticso bcopy(&rule->next_rule, &set_disable, sizeof(set_disable)); 895101628Sluigi 896101628Sluigi if (set_disable & (1 << rule->set)) { /* disabled */ 897101628Sluigi if (!show_sets) 898101628Sluigi return; 899101628Sluigi else 900101628Sluigi printf("# DISABLED "); 901101628Sluigi } 90298943Sluigi printf("%05u ", rule->rulenum); 90398943Sluigi 904117469Sluigi if (pcwidth>0 || bcwidth>0) 905115793Sticso printf("%*llu %*llu ", pcwidth, align_uint64(&rule->pcnt), 906115793Sticso bcwidth, align_uint64(&rule->bcnt)); 90798943Sluigi 908117472Sluigi if (do_time == 2) 909117472Sluigi printf("%10u ", rule->timestamp); 910117472Sluigi else if (do_time == 1) { 911107291Skeramida char timestr[30]; 912107291Skeramida time_t t = (time_t)0; 913107291Skeramida 914107291Skeramida if (twidth == 0) { 915107291Skeramida strcpy(timestr, ctime(&t)); 916107291Skeramida *strchr(timestr, '\n') = '\0'; 917107291Skeramida twidth = strlen(timestr); 918107291Skeramida } 91998943Sluigi if (rule->timestamp) { 920117469Sluigi#if _FreeBSD_version < 500000 /* XXX check */ 921117469Sluigi#define _long_to_time(x) (time_t)(x) 922117469Sluigi#endif 923107291Skeramida t = _long_to_time(rule->timestamp); 92498943Sluigi 92598943Sluigi strcpy(timestr, ctime(&t)); 92698943Sluigi *strchr(timestr, '\n') = '\0'; 92798943Sluigi printf("%s ", timestr); 92898943Sluigi } else { 929107291Skeramida printf("%*s", twidth, " "); 93098943Sluigi } 93198943Sluigi } 93298943Sluigi 933101628Sluigi if (show_sets) 934101628Sluigi printf("set %d ", rule->set); 935101628Sluigi 93698943Sluigi /* 937107289Sluigi * print the optional "match probability" 938107289Sluigi */ 939107289Sluigi if (rule->cmd_len > 0) { 940107289Sluigi cmd = rule->cmd ; 941107289Sluigi if (cmd->opcode == O_PROB) { 942107289Sluigi ipfw_insn_u32 *p = (ipfw_insn_u32 *)cmd; 943107289Sluigi double d = 1.0 * p->d[0]; 944107289Sluigi 945107289Sluigi d = (d / 0x7fffffff); 946107289Sluigi printf("prob %f ", d); 947107289Sluigi } 948107289Sluigi } 949107289Sluigi 950107289Sluigi /* 95198943Sluigi * first print actions 95298943Sluigi */ 95398943Sluigi for (l = rule->cmd_len - rule->act_ofs, cmd = ACTION_PTR(rule); 95498943Sluigi l > 0 ; l -= F_LEN(cmd), cmd += F_LEN(cmd)) { 95598943Sluigi switch(cmd->opcode) { 95698943Sluigi case O_CHECK_STATE: 95798943Sluigi printf("check-state"); 958102087Sluigi flags = HAVE_IP; /* avoid printing anything else */ 95998943Sluigi break; 96098943Sluigi 96198943Sluigi case O_ACCEPT: 96298943Sluigi printf("allow"); 96398943Sluigi break; 96498943Sluigi 96598943Sluigi case O_COUNT: 96698943Sluigi printf("count"); 96798943Sluigi break; 96898943Sluigi 96998943Sluigi case O_DENY: 97098943Sluigi printf("deny"); 97198943Sluigi break; 97298943Sluigi 97399475Sluigi case O_REJECT: 97499475Sluigi if (cmd->arg1 == ICMP_REJECT_RST) 97599475Sluigi printf("reset"); 97699475Sluigi else if (cmd->arg1 == ICMP_UNREACH_HOST) 97799475Sluigi printf("reject"); 97899475Sluigi else 97999475Sluigi print_reject_code(cmd->arg1); 98099475Sluigi break; 98199475Sluigi 98298943Sluigi case O_SKIPTO: 98398943Sluigi printf("skipto %u", cmd->arg1); 98498943Sluigi break; 98598943Sluigi 98698943Sluigi case O_PIPE: 98798943Sluigi printf("pipe %u", cmd->arg1); 98898943Sluigi break; 98998943Sluigi 99098943Sluigi case O_QUEUE: 99198943Sluigi printf("queue %u", cmd->arg1); 99298943Sluigi break; 99398943Sluigi 99498943Sluigi case O_DIVERT: 99598943Sluigi printf("divert %u", cmd->arg1); 99698943Sluigi break; 99798943Sluigi 99898943Sluigi case O_TEE: 99998943Sluigi printf("tee %u", cmd->arg1); 100098943Sluigi break; 100198943Sluigi 100298943Sluigi case O_FORWARD_IP: 100398943Sluigi { 100498943Sluigi ipfw_insn_sa *s = (ipfw_insn_sa *)cmd; 100598943Sluigi 100698943Sluigi printf("fwd %s", inet_ntoa(s->sa.sin_addr)); 100798943Sluigi if (s->sa.sin_port) 1008103241Sluigi printf(",%d", s->sa.sin_port); 100998943Sluigi } 101098943Sluigi break; 101198943Sluigi 101298943Sluigi case O_LOG: /* O_LOG is printed last */ 101398943Sluigi logptr = (ipfw_insn_log *)cmd; 101498943Sluigi break; 101598943Sluigi 101698943Sluigi default: 101798943Sluigi printf("** unrecognized action %d len %d", 101898943Sluigi cmd->opcode, cmd->len); 101998943Sluigi } 102098943Sluigi } 102198943Sluigi if (logptr) { 102298943Sluigi if (logptr->max_log > 0) 102399909Sluigi printf(" log logamount %d", logptr->max_log); 102498943Sluigi else 102599909Sluigi printf(" log"); 102698943Sluigi } 1027102087Sluigi 102898943Sluigi /* 1029102087Sluigi * then print the body. 103098943Sluigi */ 1031102087Sluigi if (rule->_pad & 1) { /* empty rules before options */ 1032102098Sluigi if (!do_compact) 1033102098Sluigi printf(" ip from any to any"); 1034102087Sluigi flags |= HAVE_IP | HAVE_OPTIONS; 1035102087Sluigi } 1036102087Sluigi 1037123495Sluigi if (comment_only) 1038123495Sluigi comment = "..."; 1039123495Sluigi 104098943Sluigi for (l = rule->act_ofs, cmd = rule->cmd ; 104198943Sluigi l > 0 ; l -= F_LEN(cmd) , cmd += F_LEN(cmd)) { 104299475Sluigi /* useful alias */ 104399475Sluigi ipfw_insn_u32 *cmd32 = (ipfw_insn_u32 *)cmd; 104498943Sluigi 1045123495Sluigi if (comment_only) { 1046123495Sluigi if (cmd->opcode != O_NOP) 1047123495Sluigi continue; 1048123495Sluigi printf(" // %s\n", (char *)(cmd + 1)); 1049123495Sluigi return; 1050123495Sluigi } 1051123495Sluigi 1052102087Sluigi show_prerequisites(&flags, 0, cmd->opcode); 1053102087Sluigi 105498943Sluigi switch(cmd->opcode) { 1055117577Sluigi case O_PROB: 1056107289Sluigi break; /* done already */ 1057107289Sluigi 105898943Sluigi case O_PROBE_STATE: 105998943Sluigi break; /* no need to print anything here */ 106098943Sluigi 106198943Sluigi case O_MACADDR2: { 106298943Sluigi ipfw_insn_mac *m = (ipfw_insn_mac *)cmd; 1063102087Sluigi 1064102087Sluigi if ((cmd->len & F_OR) && !or_block) 1065102087Sluigi printf(" {"); 106698943Sluigi if (cmd->len & F_NOT) 106798943Sluigi printf(" not"); 1068102087Sluigi printf(" MAC"); 1069102087Sluigi flags |= HAVE_MAC; 1070117577Sluigi print_mac(m->addr, m->mask); 1071117577Sluigi print_mac(m->addr + 6, m->mask + 6); 107298943Sluigi } 107398943Sluigi break; 107498943Sluigi 107598943Sluigi case O_MAC_TYPE: 1076102087Sluigi if ((cmd->len & F_OR) && !or_block) 1077102087Sluigi printf(" {"); 1078102087Sluigi print_newports((ipfw_insn_u16 *)cmd, IPPROTO_ETHERTYPE, 1079102087Sluigi (flags & HAVE_OPTIONS) ? cmd->opcode : 0); 1080102087Sluigi flags |= HAVE_MAC | HAVE_MACTYPE | HAVE_OPTIONS; 108198943Sluigi break; 108298943Sluigi 108398943Sluigi case O_IP_SRC: 108498943Sluigi case O_IP_SRC_MASK: 108598943Sluigi case O_IP_SRC_ME: 108698943Sluigi case O_IP_SRC_SET: 1087102087Sluigi show_prerequisites(&flags, HAVE_PROTO, 0); 108898943Sluigi if (!(flags & HAVE_SRCIP)) 108998943Sluigi printf(" from"); 109098943Sluigi if ((cmd->len & F_OR) && !or_block) 109198943Sluigi printf(" {"); 1092102087Sluigi print_ip((ipfw_insn_ip *)cmd, 1093102087Sluigi (flags & HAVE_OPTIONS) ? " src-ip" : ""); 109498943Sluigi flags |= HAVE_SRCIP; 109598943Sluigi break; 109698943Sluigi 109798943Sluigi case O_IP_DST: 109898943Sluigi case O_IP_DST_MASK: 109998943Sluigi case O_IP_DST_ME: 110098943Sluigi case O_IP_DST_SET: 1101102087Sluigi show_prerequisites(&flags, HAVE_PROTO|HAVE_SRCIP, 0); 110298943Sluigi if (!(flags & HAVE_DSTIP)) 110398943Sluigi printf(" to"); 110498943Sluigi if ((cmd->len & F_OR) && !or_block) 110598943Sluigi printf(" {"); 1106102087Sluigi print_ip((ipfw_insn_ip *)cmd, 1107102087Sluigi (flags & HAVE_OPTIONS) ? " dst-ip" : ""); 110898943Sluigi flags |= HAVE_DSTIP; 110998943Sluigi break; 111098943Sluigi 111198943Sluigi case O_IP_DSTPORT: 1112102087Sluigi show_prerequisites(&flags, HAVE_IP, 0); 111398943Sluigi case O_IP_SRCPORT: 1114102087Sluigi show_prerequisites(&flags, HAVE_PROTO|HAVE_SRCIP, 0); 1115101641Sluigi if ((cmd->len & F_OR) && !or_block) 1116101641Sluigi printf(" {"); 1117102087Sluigi print_newports((ipfw_insn_u16 *)cmd, proto, 1118102087Sluigi (flags & HAVE_OPTIONS) ? cmd->opcode : 0); 111998943Sluigi break; 112098943Sluigi 112198943Sluigi case O_PROTO: { 112298943Sluigi struct protoent *pe; 112398943Sluigi 112498943Sluigi if ((cmd->len & F_OR) && !or_block) 112598943Sluigi printf(" {"); 112698943Sluigi if (cmd->len & F_NOT) 112798943Sluigi printf(" not"); 112898943Sluigi proto = cmd->arg1; 112998943Sluigi pe = getprotobynumber(cmd->arg1); 1130102087Sluigi if (flags & HAVE_OPTIONS) 1131102087Sluigi printf(" proto"); 113298943Sluigi if (pe) 113398943Sluigi printf(" %s", pe->p_name); 113498943Sluigi else 113598943Sluigi printf(" %u", cmd->arg1); 113698943Sluigi } 113798943Sluigi flags |= HAVE_PROTO; 113898943Sluigi break; 1139106505Smaxim 114098943Sluigi default: /*options ... */ 1141102087Sluigi show_prerequisites(&flags, HAVE_IP | HAVE_OPTIONS, 0); 114298943Sluigi if ((cmd->len & F_OR) && !or_block) 114398943Sluigi printf(" {"); 114498943Sluigi if (cmd->len & F_NOT && cmd->opcode != O_IN) 114598943Sluigi printf(" not"); 114698943Sluigi switch(cmd->opcode) { 114798943Sluigi case O_FRAG: 114898943Sluigi printf(" frag"); 114998943Sluigi break; 115098943Sluigi 115198943Sluigi case O_IN: 115298943Sluigi printf(cmd->len & F_NOT ? " out" : " in"); 115398943Sluigi break; 115498943Sluigi 115598943Sluigi case O_LAYER2: 115698943Sluigi printf(" layer2"); 115798943Sluigi break; 115898943Sluigi case O_XMIT: 115998943Sluigi case O_RECV: 116098943Sluigi case O_VIA: { 1161117469Sluigi char const *s; 116298943Sluigi ipfw_insn_if *cmdif = (ipfw_insn_if *)cmd; 116398943Sluigi 116498943Sluigi if (cmd->opcode == O_XMIT) 116598943Sluigi s = "xmit"; 116698943Sluigi else if (cmd->opcode == O_RECV) 116798943Sluigi s = "recv"; 1168117469Sluigi else /* if (cmd->opcode == O_VIA) */ 116998943Sluigi s = "via"; 117098943Sluigi if (cmdif->name[0] == '\0') 117199475Sluigi printf(" %s %s", s, 117299475Sluigi inet_ntoa(cmdif->p.ip)); 1173121816Sbrooks printf(" %s %s", s, cmdif->name); 117498943Sluigi } 117598943Sluigi break; 117698943Sluigi 117798943Sluigi case O_IPID: 1178116690Sluigi if (F_LEN(cmd) == 1) 1179116690Sluigi printf(" ipid %u", cmd->arg1 ); 1180116690Sluigi else 1181116690Sluigi print_newports((ipfw_insn_u16 *)cmd, 0, 1182116690Sluigi O_IPID); 118398943Sluigi break; 118498943Sluigi 118598943Sluigi case O_IPTTL: 1186116690Sluigi if (F_LEN(cmd) == 1) 1187116690Sluigi printf(" ipttl %u", cmd->arg1 ); 1188116690Sluigi else 1189116690Sluigi print_newports((ipfw_insn_u16 *)cmd, 0, 1190116690Sluigi O_IPTTL); 119198943Sluigi break; 119298943Sluigi 119398943Sluigi case O_IPVER: 119498943Sluigi printf(" ipver %u", cmd->arg1 ); 119598943Sluigi break; 119698943Sluigi 119799475Sluigi case O_IPPRECEDENCE: 119899475Sluigi printf(" ipprecedence %u", (cmd->arg1) >> 5 ); 119999475Sluigi break; 120099475Sluigi 120198943Sluigi case O_IPLEN: 1202116690Sluigi if (F_LEN(cmd) == 1) 1203116690Sluigi printf(" iplen %u", cmd->arg1 ); 1204116690Sluigi else 1205116690Sluigi print_newports((ipfw_insn_u16 *)cmd, 0, 1206116690Sluigi O_IPLEN); 120798943Sluigi break; 120898943Sluigi 1209101116Sluigi case O_IPOPT: 121098943Sluigi print_flags("ipoptions", cmd, f_ipopts); 121198943Sluigi break; 121298943Sluigi 121399475Sluigi case O_IPTOS: 121499475Sluigi print_flags("iptos", cmd, f_iptos); 121599475Sluigi break; 121699475Sluigi 121799475Sluigi case O_ICMPTYPE: 121899475Sluigi print_icmptypes((ipfw_insn_u32 *)cmd); 121999475Sluigi break; 122099475Sluigi 122198943Sluigi case O_ESTAB: 122298943Sluigi printf(" established"); 122398943Sluigi break; 122498943Sluigi 122598943Sluigi case O_TCPFLAGS: 122698943Sluigi print_flags("tcpflags", cmd, f_tcpflags); 122798943Sluigi break; 122898943Sluigi 122998943Sluigi case O_TCPOPTS: 123098943Sluigi print_flags("tcpoptions", cmd, f_tcpopts); 123198943Sluigi break; 123298943Sluigi 123398943Sluigi case O_TCPWIN: 123498943Sluigi printf(" tcpwin %d", ntohs(cmd->arg1)); 123598943Sluigi break; 123698943Sluigi 123798943Sluigi case O_TCPACK: 123898943Sluigi printf(" tcpack %d", ntohl(cmd32->d[0])); 123998943Sluigi break; 124098943Sluigi 124198943Sluigi case O_TCPSEQ: 124298943Sluigi printf(" tcpseq %d", ntohl(cmd32->d[0])); 124398943Sluigi break; 124498943Sluigi 124598943Sluigi case O_UID: 124698943Sluigi { 124798943Sluigi struct passwd *pwd = getpwuid(cmd32->d[0]); 124898943Sluigi 124998943Sluigi if (pwd) 125098943Sluigi printf(" uid %s", pwd->pw_name); 125198943Sluigi else 125298943Sluigi printf(" uid %u", cmd32->d[0]); 125398943Sluigi } 125498943Sluigi break; 125598943Sluigi 125698943Sluigi case O_GID: 125798943Sluigi { 125898943Sluigi struct group *grp = getgrgid(cmd32->d[0]); 125998943Sluigi 126098943Sluigi if (grp) 126198943Sluigi printf(" gid %s", grp->gr_name); 126298943Sluigi else 126398943Sluigi printf(" gid %u", cmd32->d[0]); 126498943Sluigi } 126598943Sluigi break; 126698943Sluigi 1267112250Scjc case O_VERREVPATH: 1268112250Scjc printf(" verrevpath"); 1269112250Scjc break; 1270116919Sluigi 1271117241Sluigi case O_IPSEC: 1272117241Sluigi printf(" ipsec"); 1273117241Sluigi break; 1274117241Sluigi 1275117469Sluigi case O_NOP: 1276117626Sluigi comment = (char *)(cmd + 1); 1277117469Sluigi break; 1278117469Sluigi 127998943Sluigi case O_KEEP_STATE: 128098943Sluigi printf(" keep-state"); 128198943Sluigi break; 128298943Sluigi 128398943Sluigi case O_LIMIT: 128498943Sluigi { 128598943Sluigi struct _s_x *p = limit_masks; 128698943Sluigi ipfw_insn_limit *c = (ipfw_insn_limit *)cmd; 1287117328Sluigi uint8_t x = c->limit_mask; 1288117469Sluigi char const *comma = " "; 128998943Sluigi 129098943Sluigi printf(" limit"); 1291117577Sluigi for (; p->x != 0 ; p++) 129299909Sluigi if ((x & p->x) == p->x) { 129398943Sluigi x &= ~p->x; 129498943Sluigi printf("%s%s", comma, p->s); 129598943Sluigi comma = ","; 129698943Sluigi } 129798943Sluigi printf(" %d", c->conn_limit); 129898943Sluigi } 129998943Sluigi break; 130098943Sluigi 130198943Sluigi default: 130298943Sluigi printf(" [opcode %d len %d]", 130398943Sluigi cmd->opcode, cmd->len); 130498943Sluigi } 130598943Sluigi } 130698943Sluigi if (cmd->len & F_OR) { 130798943Sluigi printf(" or"); 130898943Sluigi or_block = 1; 130998943Sluigi } else if (or_block) { 131098943Sluigi printf(" }"); 131198943Sluigi or_block = 0; 131298943Sluigi } 131398943Sluigi } 1314102087Sluigi show_prerequisites(&flags, HAVE_IP, 0); 1315117626Sluigi if (comment) 1316117626Sluigi printf(" // %s", comment); 131798943Sluigi printf("\n"); 131898943Sluigi} 131998943Sluigi 132098943Sluigistatic void 1321112189Smaximshow_dyn_ipfw(ipfw_dyn_rule *d, int pcwidth, int bcwidth) 132298943Sluigi{ 132398943Sluigi struct protoent *pe; 132498943Sluigi struct in_addr a; 1325115793Sticso uint16_t rulenum; 132698943Sluigi 132798943Sluigi if (!do_expired) { 132898943Sluigi if (!d->expire && !(d->dyn_type == O_LIMIT_PARENT)) 132998943Sluigi return; 133098943Sluigi } 1331115793Sticso bcopy(&d->rule, &rulenum, sizeof(rulenum)); 1332117328Sluigi printf("%05d", rulenum); 1333117469Sluigi if (pcwidth>0 || bcwidth>0) 1334117328Sluigi printf(" %*llu %*llu (%ds)", pcwidth, 1335117328Sluigi align_uint64(&d->pcnt), bcwidth, 1336117328Sluigi align_uint64(&d->bcnt), d->expire); 133798943Sluigi switch (d->dyn_type) { 133898943Sluigi case O_LIMIT_PARENT: 133998943Sluigi printf(" PARENT %d", d->count); 134098943Sluigi break; 134198943Sluigi case O_LIMIT: 134298943Sluigi printf(" LIMIT"); 134398943Sluigi break; 134498943Sluigi case O_KEEP_STATE: /* bidir, no mask */ 1345106505Smaxim printf(" STATE"); 134698943Sluigi break; 134798943Sluigi } 134898943Sluigi 134998943Sluigi if ((pe = getprotobynumber(d->id.proto)) != NULL) 135098943Sluigi printf(" %s", pe->p_name); 135198943Sluigi else 135298943Sluigi printf(" proto %u", d->id.proto); 135398943Sluigi 135498943Sluigi a.s_addr = htonl(d->id.src_ip); 135598943Sluigi printf(" %s %d", inet_ntoa(a), d->id.src_port); 135698943Sluigi 135798943Sluigi a.s_addr = htonl(d->id.dst_ip); 135898943Sluigi printf(" <-> %s %d", inet_ntoa(a), d->id.dst_port); 135998943Sluigi printf("\n"); 136098943Sluigi} 136198943Sluigi 1362117469Sluigistatic int 136398943Sluigisort_q(const void *pa, const void *pb) 136498943Sluigi{ 136598943Sluigi int rev = (do_sort < 0); 136698943Sluigi int field = rev ? -do_sort : do_sort; 136798943Sluigi long long res = 0; 136898943Sluigi const struct dn_flow_queue *a = pa; 136998943Sluigi const struct dn_flow_queue *b = pb; 137098943Sluigi 137198943Sluigi switch (field) { 137298943Sluigi case 1: /* pkts */ 137398943Sluigi res = a->len - b->len; 137498943Sluigi break; 137598943Sluigi case 2: /* bytes */ 137698943Sluigi res = a->len_bytes - b->len_bytes; 137798943Sluigi break; 137898943Sluigi 137998943Sluigi case 3: /* tot pkts */ 138098943Sluigi res = a->tot_pkts - b->tot_pkts; 138198943Sluigi break; 138298943Sluigi 138398943Sluigi case 4: /* tot bytes */ 138498943Sluigi res = a->tot_bytes - b->tot_bytes; 138598943Sluigi break; 138698943Sluigi } 138798943Sluigi if (res < 0) 138898943Sluigi res = -1; 138998943Sluigi if (res > 0) 139098943Sluigi res = 1; 139198943Sluigi return (int)(rev ? res : -res); 139298943Sluigi} 139398943Sluigi 139498943Sluigistatic void 139598943Sluigilist_queues(struct dn_flow_set *fs, struct dn_flow_queue *q) 139698943Sluigi{ 139798943Sluigi int l; 139898943Sluigi 139998943Sluigi printf(" mask: 0x%02x 0x%08x/0x%04x -> 0x%08x/0x%04x\n", 140098943Sluigi fs->flow_mask.proto, 140198943Sluigi fs->flow_mask.src_ip, fs->flow_mask.src_port, 140298943Sluigi fs->flow_mask.dst_ip, fs->flow_mask.dst_port); 140398943Sluigi if (fs->rq_elements == 0) 140498943Sluigi return; 140598943Sluigi 140698943Sluigi printf("BKT Prot ___Source IP/port____ " 140798943Sluigi "____Dest. IP/port____ Tot_pkt/bytes Pkt/Byte Drp\n"); 140898943Sluigi if (do_sort != 0) 140998943Sluigi heapsort(q, fs->rq_elements, sizeof *q, sort_q); 141098943Sluigi for (l = 0; l < fs->rq_elements; l++) { 141198943Sluigi struct in_addr ina; 141298943Sluigi struct protoent *pe; 141398943Sluigi 141498943Sluigi ina.s_addr = htonl(q[l].id.src_ip); 141598943Sluigi printf("%3d ", q[l].hash_slot); 141698943Sluigi pe = getprotobynumber(q[l].id.proto); 141798943Sluigi if (pe) 141898943Sluigi printf("%-4s ", pe->p_name); 141998943Sluigi else 142098943Sluigi printf("%4u ", q[l].id.proto); 142198943Sluigi printf("%15s/%-5d ", 142298943Sluigi inet_ntoa(ina), q[l].id.src_port); 142398943Sluigi ina.s_addr = htonl(q[l].id.dst_ip); 142498943Sluigi printf("%15s/%-5d ", 142598943Sluigi inet_ntoa(ina), q[l].id.dst_port); 142698943Sluigi printf("%4qu %8qu %2u %4u %3u\n", 142798943Sluigi q[l].tot_pkts, q[l].tot_bytes, 142898943Sluigi q[l].len, q[l].len_bytes, q[l].drops); 142998943Sluigi if (verbose) 143098943Sluigi printf(" S %20qd F %20qd\n", 143198943Sluigi q[l].S, q[l].F); 143298943Sluigi } 143398943Sluigi} 143498943Sluigi 143598943Sluigistatic void 143698943Sluigiprint_flowset_parms(struct dn_flow_set *fs, char *prefix) 143798943Sluigi{ 143898943Sluigi int l; 143998943Sluigi char qs[30]; 144098943Sluigi char plr[30]; 144198943Sluigi char red[90]; /* Display RED parameters */ 144298943Sluigi 144398943Sluigi l = fs->qsize; 144498943Sluigi if (fs->flags_fs & DN_QSIZE_IS_BYTES) { 144598943Sluigi if (l >= 8192) 144698943Sluigi sprintf(qs, "%d KB", l / 1024); 144798943Sluigi else 144898943Sluigi sprintf(qs, "%d B", l); 144998943Sluigi } else 145098943Sluigi sprintf(qs, "%3d sl.", l); 145198943Sluigi if (fs->plr) 145298943Sluigi sprintf(plr, "plr %f", 1.0 * fs->plr / (double)(0x7fffffff)); 145398943Sluigi else 145498943Sluigi plr[0] = '\0'; 145598943Sluigi if (fs->flags_fs & DN_IS_RED) /* RED parameters */ 145698943Sluigi sprintf(red, 145798943Sluigi "\n\t %cRED w_q %f min_th %d max_th %d max_p %f", 145898943Sluigi (fs->flags_fs & DN_IS_GENTLE_RED) ? 'G' : ' ', 145998943Sluigi 1.0 * fs->w_q / (double)(1 << SCALE_RED), 146098943Sluigi SCALE_VAL(fs->min_th), 146198943Sluigi SCALE_VAL(fs->max_th), 146298943Sluigi 1.0 * fs->max_p / (double)(1 << SCALE_RED)); 146398943Sluigi else 146498943Sluigi sprintf(red, "droptail"); 146598943Sluigi 146698943Sluigi printf("%s %s%s %d queues (%d buckets) %s\n", 146798943Sluigi prefix, qs, plr, fs->rq_elements, fs->rq_size, red); 146898943Sluigi} 146998943Sluigi 147098943Sluigistatic void 1471117469Sluigilist_pipes(void *data, uint nbytes, int ac, char *av[]) 147298943Sluigi{ 1473117469Sluigi int rulenum; 147498943Sluigi void *next = data; 147598943Sluigi struct dn_pipe *p = (struct dn_pipe *) data; 147698943Sluigi struct dn_flow_set *fs; 147798943Sluigi struct dn_flow_queue *q; 147898943Sluigi int l; 147998943Sluigi 148098943Sluigi if (ac > 0) 148198943Sluigi rulenum = strtoul(*av++, NULL, 10); 148298943Sluigi else 148398943Sluigi rulenum = 0; 148498943Sluigi for (; nbytes >= sizeof *p; p = (struct dn_pipe *)next) { 148598943Sluigi double b = p->bandwidth; 148698943Sluigi char buf[30]; 148798943Sluigi char prefix[80]; 148898943Sluigi 148998943Sluigi if (p->next != (struct dn_pipe *)DN_IS_PIPE) 149098943Sluigi break; /* done with pipes, now queues */ 149198943Sluigi 149298943Sluigi /* 149398943Sluigi * compute length, as pipe have variable size 149498943Sluigi */ 149598943Sluigi l = sizeof(*p) + p->fs.rq_elements * sizeof(*q); 1496117469Sluigi next = (char *)p + l; 149798943Sluigi nbytes -= l; 149898943Sluigi 149998943Sluigi if (rulenum != 0 && rulenum != p->pipe_nr) 150098943Sluigi continue; 150198943Sluigi 150298943Sluigi /* 150398943Sluigi * Print rate (or clocking interface) 150498943Sluigi */ 150598943Sluigi if (p->if_name[0] != '\0') 150698943Sluigi sprintf(buf, "%s", p->if_name); 150798943Sluigi else if (b == 0) 150898943Sluigi sprintf(buf, "unlimited"); 150998943Sluigi else if (b >= 1000000) 151098943Sluigi sprintf(buf, "%7.3f Mbit/s", b/1000000); 151198943Sluigi else if (b >= 1000) 151298943Sluigi sprintf(buf, "%7.3f Kbit/s", b/1000); 151398943Sluigi else 151498943Sluigi sprintf(buf, "%7.3f bit/s ", b); 151598943Sluigi 151698943Sluigi sprintf(prefix, "%05d: %s %4d ms ", 151798943Sluigi p->pipe_nr, buf, p->delay); 151898943Sluigi print_flowset_parms(&(p->fs), prefix); 151998943Sluigi if (verbose) 152098943Sluigi printf(" V %20qd\n", p->V >> MY_M); 1521106505Smaxim 152298943Sluigi q = (struct dn_flow_queue *)(p+1); 152398943Sluigi list_queues(&(p->fs), q); 152498943Sluigi } 152598943Sluigi for (fs = next; nbytes >= sizeof *fs; fs = next) { 152698943Sluigi char prefix[80]; 152798943Sluigi 152898943Sluigi if (fs->next != (struct dn_flow_set *)DN_IS_QUEUE) 152998943Sluigi break; 153098943Sluigi l = sizeof(*fs) + fs->rq_elements * sizeof(*q); 1531117469Sluigi next = (char *)fs + l; 153298943Sluigi nbytes -= l; 153398943Sluigi q = (struct dn_flow_queue *)(fs+1); 153498943Sluigi sprintf(prefix, "q%05d: weight %d pipe %d ", 153598943Sluigi fs->fs_nr, fs->weight, fs->parent_nr); 153698943Sluigi print_flowset_parms(fs, prefix); 153798943Sluigi list_queues(fs, q); 153898943Sluigi } 153998943Sluigi} 154098943Sluigi 1541101978Sluigi/* 1542101978Sluigi * This one handles all set-related commands 1543101978Sluigi * ipfw set { show | enable | disable } 1544101978Sluigi * ipfw set swap X Y 1545101978Sluigi * ipfw set move X to Y 1546101978Sluigi * ipfw set move rule X to Y 1547101978Sluigi */ 154898943Sluigistatic void 1549101978Sluigisets_handler(int ac, char *av[]) 1550101978Sluigi{ 1551117328Sluigi uint32_t set_disable, masks[2]; 1552101978Sluigi int i, nbytes; 1553117328Sluigi uint16_t rulenum; 1554117328Sluigi uint8_t cmd, new_set; 1555101978Sluigi 1556101978Sluigi ac--; 1557101978Sluigi av++; 1558101978Sluigi 1559101978Sluigi if (!ac) 1560101978Sluigi errx(EX_USAGE, "set needs command"); 1561101978Sluigi if (!strncmp(*av, "show", strlen(*av)) ) { 1562101978Sluigi void *data; 1563117469Sluigi char const *msg; 1564101978Sluigi 1565101978Sluigi nbytes = sizeof(struct ip_fw); 1566117328Sluigi if ((data = calloc(1, nbytes)) == NULL) 1567117328Sluigi err(EX_OSERR, "calloc"); 1568119740Stmm if (do_cmd(IP_FW_GET, data, (uintptr_t)&nbytes) < 0) 1569101978Sluigi err(EX_OSERR, "getsockopt(IP_FW_GET)"); 1570115793Sticso bcopy(&((struct ip_fw *)data)->next_rule, 1571115793Sticso &set_disable, sizeof(set_disable)); 1572101978Sluigi 1573117655Sluigi for (i = 0, msg = "disable" ; i < RESVD_SET; i++) 1574117577Sluigi if ((set_disable & (1<<i))) { 1575101978Sluigi printf("%s %d", msg, i); 1576101978Sluigi msg = ""; 1577101978Sluigi } 1578101978Sluigi msg = (set_disable) ? " enable" : "enable"; 1579117655Sluigi for (i = 0; i < RESVD_SET; i++) 1580117577Sluigi if (!(set_disable & (1<<i))) { 1581101978Sluigi printf("%s %d", msg, i); 1582101978Sluigi msg = ""; 1583101978Sluigi } 1584101978Sluigi printf("\n"); 1585101978Sluigi } else if (!strncmp(*av, "swap", strlen(*av))) { 1586101978Sluigi ac--; av++; 1587101978Sluigi if (ac != 2) 1588101978Sluigi errx(EX_USAGE, "set swap needs 2 set numbers\n"); 1589101978Sluigi rulenum = atoi(av[0]); 1590101978Sluigi new_set = atoi(av[1]); 1591117655Sluigi if (!isdigit(*(av[0])) || rulenum > RESVD_SET) 1592101978Sluigi errx(EX_DATAERR, "invalid set number %s\n", av[0]); 1593117655Sluigi if (!isdigit(*(av[1])) || new_set > RESVD_SET) 1594101978Sluigi errx(EX_DATAERR, "invalid set number %s\n", av[1]); 1595101978Sluigi masks[0] = (4 << 24) | (new_set << 16) | (rulenum); 1596117328Sluigi i = do_cmd(IP_FW_DEL, masks, sizeof(uint32_t)); 1597101978Sluigi } else if (!strncmp(*av, "move", strlen(*av))) { 1598101978Sluigi ac--; av++; 1599101978Sluigi if (ac && !strncmp(*av, "rule", strlen(*av))) { 1600101978Sluigi cmd = 2; 1601101978Sluigi ac--; av++; 1602101978Sluigi } else 1603101978Sluigi cmd = 3; 1604101978Sluigi if (ac != 3 || strncmp(av[1], "to", strlen(*av))) 1605101978Sluigi errx(EX_USAGE, "syntax: set move [rule] X to Y\n"); 1606101978Sluigi rulenum = atoi(av[0]); 1607101978Sluigi new_set = atoi(av[2]); 1608117655Sluigi if (!isdigit(*(av[0])) || (cmd == 3 && rulenum > RESVD_SET) || 1609101978Sluigi (cmd == 2 && rulenum == 65535) ) 1610101978Sluigi errx(EX_DATAERR, "invalid source number %s\n", av[0]); 1611117655Sluigi if (!isdigit(*(av[2])) || new_set > RESVD_SET) 1612101978Sluigi errx(EX_DATAERR, "invalid dest. set %s\n", av[1]); 1613101978Sluigi masks[0] = (cmd << 24) | (new_set << 16) | (rulenum); 1614117328Sluigi i = do_cmd(IP_FW_DEL, masks, sizeof(uint32_t)); 1615101978Sluigi } else if (!strncmp(*av, "disable", strlen(*av)) || 1616101978Sluigi !strncmp(*av, "enable", strlen(*av)) ) { 1617101978Sluigi int which = !strncmp(*av, "enable", strlen(*av)) ? 1 : 0; 1618101978Sluigi 1619101978Sluigi ac--; av++; 1620101978Sluigi masks[0] = masks[1] = 0; 1621101978Sluigi 1622101978Sluigi while (ac) { 1623101978Sluigi if (isdigit(**av)) { 1624101978Sluigi i = atoi(*av); 1625117655Sluigi if (i < 0 || i > RESVD_SET) 1626101978Sluigi errx(EX_DATAERR, 1627101978Sluigi "invalid set number %d\n", i); 1628101978Sluigi masks[which] |= (1<<i); 1629101978Sluigi } else if (!strncmp(*av, "disable", strlen(*av))) 1630101978Sluigi which = 0; 1631101978Sluigi else if (!strncmp(*av, "enable", strlen(*av))) 1632101978Sluigi which = 1; 1633101978Sluigi else 1634101978Sluigi errx(EX_DATAERR, 1635101978Sluigi "invalid set command %s\n", *av); 1636101978Sluigi av++; ac--; 1637101978Sluigi } 1638101978Sluigi if ( (masks[0] & masks[1]) != 0 ) 1639101978Sluigi errx(EX_DATAERR, 1640101978Sluigi "cannot enable and disable the same set\n"); 1641101978Sluigi 1642117328Sluigi i = do_cmd(IP_FW_DEL, masks, sizeof(masks)); 1643101978Sluigi if (i) 1644101978Sluigi warn("set enable/disable: setsockopt(IP_FW_DEL)"); 1645101978Sluigi } else 1646101978Sluigi errx(EX_USAGE, "invalid set command %s\n", *av); 1647101978Sluigi} 1648101978Sluigi 1649101978Sluigistatic void 1650109126Sdillonsysctl_handler(int ac, char *av[], int which) 1651109126Sdillon{ 1652109126Sdillon ac--; 1653109126Sdillon av++; 1654109126Sdillon 1655119668Smaxim if (ac == 0) { 1656109126Sdillon warnx("missing keyword to enable/disable\n"); 1657109126Sdillon } else if (strncmp(*av, "firewall", strlen(*av)) == 0) { 1658116770Sluigi sysctlbyname("net.inet.ip.fw.enable", NULL, 0, 1659116770Sluigi &which, sizeof(which)); 1660109126Sdillon } else if (strncmp(*av, "one_pass", strlen(*av)) == 0) { 1661116770Sluigi sysctlbyname("net.inet.ip.fw.one_pass", NULL, 0, 1662116770Sluigi &which, sizeof(which)); 1663109126Sdillon } else if (strncmp(*av, "debug", strlen(*av)) == 0) { 1664116770Sluigi sysctlbyname("net.inet.ip.fw.debug", NULL, 0, 1665116770Sluigi &which, sizeof(which)); 1666109126Sdillon } else if (strncmp(*av, "verbose", strlen(*av)) == 0) { 1667116770Sluigi sysctlbyname("net.inet.ip.fw.verbose", NULL, 0, 1668116770Sluigi &which, sizeof(which)); 1669109126Sdillon } else if (strncmp(*av, "dyn_keepalive", strlen(*av)) == 0) { 1670116770Sluigi sysctlbyname("net.inet.ip.fw.dyn_keepalive", NULL, 0, 1671116770Sluigi &which, sizeof(which)); 1672109126Sdillon } else { 1673109126Sdillon warnx("unrecognize enable/disable keyword: %s\n", *av); 1674109126Sdillon } 1675109126Sdillon} 1676109126Sdillon 1677109126Sdillonstatic void 1678117469Sluigilist(int ac, char *av[], int show_counters) 167998943Sluigi{ 168098943Sluigi struct ip_fw *r; 168198943Sluigi ipfw_dyn_rule *dynrules, *d; 168298943Sluigi 1683117469Sluigi#define NEXT(r) ((struct ip_fw *)((char *)r + RULESIZE(r))) 1684117469Sluigi char *lim; 1685117469Sluigi void *data = NULL; 1686112189Smaxim int bcwidth, n, nbytes, nstat, ndyn, pcwidth, width; 168798943Sluigi int exitval = EX_OK; 168898943Sluigi int lac; 168998943Sluigi char **lav; 1690117469Sluigi u_long rnum, last; 169198943Sluigi char *endptr; 169298943Sluigi int seen = 0; 169398943Sluigi 169498943Sluigi const int ocmd = do_pipe ? IP_DUMMYNET_GET : IP_FW_GET; 169598943Sluigi int nalloc = 1024; /* start somewhere... */ 169698943Sluigi 1697117328Sluigi if (test_only) { 1698117328Sluigi fprintf(stderr, "Testing only, list disabled\n"); 1699117328Sluigi return; 1700117328Sluigi } 1701117328Sluigi 170298943Sluigi ac--; 170398943Sluigi av++; 170498943Sluigi 170598943Sluigi /* get rules or pipes from kernel, resizing array as necessary */ 170698943Sluigi nbytes = nalloc; 170798943Sluigi 170898943Sluigi while (nbytes >= nalloc) { 170998943Sluigi nalloc = nalloc * 2 + 200; 171098943Sluigi nbytes = nalloc; 171198943Sluigi if ((data = realloc(data, nbytes)) == NULL) 171298943Sluigi err(EX_OSERR, "realloc"); 1713119740Stmm if (do_cmd(ocmd, data, (uintptr_t)&nbytes) < 0) 171498943Sluigi err(EX_OSERR, "getsockopt(IP_%s_GET)", 171598943Sluigi do_pipe ? "DUMMYNET" : "FW"); 171698943Sluigi } 171798943Sluigi 171898943Sluigi if (do_pipe) { 171998943Sluigi list_pipes(data, nbytes, ac, av); 172098943Sluigi goto done; 172198943Sluigi } 172298943Sluigi 172398943Sluigi /* 172498943Sluigi * Count static rules. They have variable size so we 172598943Sluigi * need to scan the list to count them. 172698943Sluigi */ 1727117469Sluigi for (nstat = 1, r = data, lim = (char *)data + nbytes; 1728117469Sluigi r->rulenum < 65535 && (char *)r < lim; 1729117469Sluigi ++nstat, r = NEXT(r) ) 173098943Sluigi ; /* nothing */ 173198943Sluigi 173298943Sluigi /* 173398943Sluigi * Count dynamic rules. This is easier as they have 173498943Sluigi * fixed size. 173598943Sluigi */ 1736117469Sluigi r = NEXT(r); 173798943Sluigi dynrules = (ipfw_dyn_rule *)r ; 1738117469Sluigi n = (char *)r - (char *)data; 173998943Sluigi ndyn = (nbytes - n) / sizeof *dynrules; 174098943Sluigi 1741112189Smaxim /* if showing stats, figure out column widths ahead of time */ 1742112189Smaxim bcwidth = pcwidth = 0; 1743117469Sluigi if (show_counters) { 1744117469Sluigi for (n = 0, r = data; n < nstat; n++, r = NEXT(r)) { 1745112189Smaxim /* packet counter */ 1746115793Sticso width = snprintf(NULL, 0, "%llu", 1747115793Sticso align_uint64(&r->pcnt)); 1748112189Smaxim if (width > pcwidth) 1749112189Smaxim pcwidth = width; 1750112189Smaxim 1751112189Smaxim /* byte counter */ 1752115793Sticso width = snprintf(NULL, 0, "%llu", 1753115793Sticso align_uint64(&r->bcnt)); 1754112189Smaxim if (width > bcwidth) 1755112189Smaxim bcwidth = width; 1756112189Smaxim } 1757112189Smaxim } 1758112189Smaxim if (do_dynamic && ndyn) { 1759112189Smaxim for (n = 0, d = dynrules; n < ndyn; n++, d++) { 1760115793Sticso width = snprintf(NULL, 0, "%llu", 1761115793Sticso align_uint64(&d->pcnt)); 1762112189Smaxim if (width > pcwidth) 1763112189Smaxim pcwidth = width; 1764112189Smaxim 1765115793Sticso width = snprintf(NULL, 0, "%llu", 1766115793Sticso align_uint64(&d->bcnt)); 1767112189Smaxim if (width > bcwidth) 1768112189Smaxim bcwidth = width; 1769112189Smaxim } 1770112189Smaxim } 177198943Sluigi /* if no rule numbers were specified, list all rules */ 177298943Sluigi if (ac == 0) { 1773117469Sluigi for (n = 0, r = data; n < nstat; n++, r = NEXT(r) ) 1774112189Smaxim show_ipfw(r, pcwidth, bcwidth); 177598943Sluigi 177698943Sluigi if (do_dynamic && ndyn) { 177798943Sluigi printf("## Dynamic rules (%d):\n", ndyn); 177898943Sluigi for (n = 0, d = dynrules; n < ndyn; n++, d++) 1779112189Smaxim show_dyn_ipfw(d, pcwidth, bcwidth); 178098943Sluigi } 178198943Sluigi goto done; 178298943Sluigi } 178398943Sluigi 178498943Sluigi /* display specific rules requested on command line */ 178598943Sluigi 178698943Sluigi for (lac = ac, lav = av; lac != 0; lac--) { 178798943Sluigi /* convert command line rule # */ 1788117469Sluigi last = rnum = strtoul(*lav++, &endptr, 10); 1789117469Sluigi if (*endptr == '-') 1790117469Sluigi last = strtoul(endptr+1, &endptr, 10); 179198943Sluigi if (*endptr) { 179298943Sluigi exitval = EX_USAGE; 179398943Sluigi warnx("invalid rule number: %s", *(lav - 1)); 179498943Sluigi continue; 179598943Sluigi } 1796117469Sluigi for (n = seen = 0, r = data; n < nstat; n++, r = NEXT(r) ) { 1797117469Sluigi if (r->rulenum > last) 179898943Sluigi break; 1799117469Sluigi if (r->rulenum >= rnum && r->rulenum <= last) { 1800112189Smaxim show_ipfw(r, pcwidth, bcwidth); 180198943Sluigi seen = 1; 180298943Sluigi } 180398943Sluigi } 180498943Sluigi if (!seen) { 180598943Sluigi /* give precedence to other error(s) */ 180698943Sluigi if (exitval == EX_OK) 180798943Sluigi exitval = EX_UNAVAILABLE; 180898943Sluigi warnx("rule %lu does not exist", rnum); 180998943Sluigi } 181098943Sluigi } 181198943Sluigi 181298943Sluigi if (do_dynamic && ndyn) { 181398943Sluigi printf("## Dynamic rules:\n"); 181498943Sluigi for (lac = ac, lav = av; lac != 0; lac--) { 181598943Sluigi rnum = strtoul(*lav++, &endptr, 10); 1816117469Sluigi if (*endptr == '-') 1817117469Sluigi last = strtoul(endptr+1, &endptr, 10); 181898943Sluigi if (*endptr) 181998943Sluigi /* already warned */ 182098943Sluigi continue; 182198943Sluigi for (n = 0, d = dynrules; n < ndyn; n++, d++) { 1822115793Sticso uint16_t rulenum; 1823115793Sticso 1824115793Sticso bcopy(&d->rule, &rulenum, sizeof(rulenum)); 1825115793Sticso if (rulenum > rnum) 182698943Sluigi break; 1827117469Sluigi if (r->rulenum >= rnum && r->rulenum <= last) 1828112189Smaxim show_dyn_ipfw(d, pcwidth, bcwidth); 182998943Sluigi } 183098943Sluigi } 183198943Sluigi } 183298943Sluigi 183398943Sluigi ac = 0; 183498943Sluigi 183598943Sluigidone: 183698943Sluigi free(data); 183798943Sluigi 183898943Sluigi if (exitval != EX_OK) 183998943Sluigi exit(exitval); 1840117469Sluigi#undef NEXT 184198943Sluigi} 184298943Sluigi 184398943Sluigistatic void 184498943Sluigishow_usage(void) 184598943Sluigi{ 184698943Sluigi fprintf(stderr, "usage: ipfw [options]\n" 184798943Sluigi"do \"ipfw -h\" or see ipfw manpage for details\n" 184898943Sluigi); 184998943Sluigi exit(EX_USAGE); 185098943Sluigi} 185198943Sluigi 185298943Sluigistatic void 185398943Sluigihelp(void) 185498943Sluigi{ 1855117328Sluigi fprintf(stderr, 1856117328Sluigi"ipfw syntax summary (but please do read the ipfw(8) manpage):\n" 1857123495Sluigi"ipfw [-abcdefhnNqStTv] <command> where <command> is one of:\n" 1858117328Sluigi"add [num] [set N] [prob x] RULE-BODY\n" 1859117328Sluigi"{pipe|queue} N config PIPE-BODY\n" 1860117328Sluigi"[pipe|queue] {zero|delete|show} [N{,N}]\n" 1861117328Sluigi"set [disable N... enable N...] | move [rule] X to Y | swap X Y | show\n" 186298943Sluigi"\n" 1863117328Sluigi"RULE-BODY: check-state [LOG] | ACTION [LOG] ADDR [OPTION_LIST]\n" 186498943Sluigi"ACTION: check-state | allow | count | deny | reject | skipto N |\n" 186598943Sluigi" {divert|tee} PORT | forward ADDR | pipe N | queue N\n" 186698943Sluigi"ADDR: [ MAC dst src ether_type ] \n" 1867117544Sluigi" [ from IPADDR [ PORT ] to IPADDR [ PORTLIST ] ]\n" 1868117544Sluigi"IPADDR: [not] { any | me | ip/bits{x,y,z} | IPLIST }\n" 1869117544Sluigi"IPLIST: { ip | ip/bits | ip:mask }[,IPLIST]\n" 1870117544Sluigi"OPTION_LIST: OPTION [OPTION_LIST]\n" 1871117328Sluigi"OPTION: bridged | {dst-ip|src-ip} ADDR | {dst-port|src-port} LIST |\n" 1872117328Sluigi" estab | frag | {gid|uid} N | icmptypes LIST | in | out | ipid LIST |\n" 1873117328Sluigi" iplen LIST | ipoptions SPEC | ipprecedence | ipsec | iptos SPEC |\n" 1874117328Sluigi" ipttl LIST | ipversion VER | keep-state | layer2 | limit ... |\n" 1875117328Sluigi" mac ... | mac-type LIST | proto LIST | {recv|xmit|via} {IF|IPADDR} |\n" 1876117328Sluigi" setup | {tcpack|tcpseq|tcpwin} NN | tcpflags SPEC | tcpoptions SPEC |\n" 1877117328Sluigi" verrevpath\n" 187898943Sluigi); 187998943Sluigiexit(0); 188098943Sluigi} 188198943Sluigi 188298943Sluigi 188398943Sluigistatic int 188498943Sluigilookup_host (char *host, struct in_addr *ipaddr) 188598943Sluigi{ 188698943Sluigi struct hostent *he; 188798943Sluigi 188898943Sluigi if (!inet_aton(host, ipaddr)) { 188998943Sluigi if ((he = gethostbyname(host)) == NULL) 189098943Sluigi return(-1); 189198943Sluigi *ipaddr = *(struct in_addr *)he->h_addr_list[0]; 189298943Sluigi } 189398943Sluigi return(0); 189498943Sluigi} 189598943Sluigi 189698943Sluigi/* 189798943Sluigi * fills the addr and mask fields in the instruction as appropriate from av. 189898943Sluigi * Update length as appropriate. 189998943Sluigi * The following formats are allowed: 190098943Sluigi * any matches any IP. Actually returns an empty instruction. 190198943Sluigi * me returns O_IP_*_ME 190298943Sluigi * 1.2.3.4 single IP address 190398943Sluigi * 1.2.3.4:5.6.7.8 address:mask 190498943Sluigi * 1.2.3.4/24 address/mask 190598943Sluigi * 1.2.3.4/26{1,6,5,4,23} set of addresses in a subnet 1906117328Sluigi * We can have multiple comma-separated address/mask entries. 190798943Sluigi */ 190898943Sluigistatic void 190998943Sluigifill_ip(ipfw_insn_ip *cmd, char *av) 191098943Sluigi{ 1911117328Sluigi int len = 0; 1912117328Sluigi uint32_t *d = ((ipfw_insn_u32 *)cmd)->d; 191398943Sluigi 191498943Sluigi cmd->o.len &= ~F_LEN_MASK; /* zero len */ 191598943Sluigi 191698943Sluigi if (!strncmp(av, "any", strlen(av))) 191798943Sluigi return; 191898943Sluigi 191998943Sluigi if (!strncmp(av, "me", strlen(av))) { 192098943Sluigi cmd->o.len |= F_INSN_SIZE(ipfw_insn); 192198943Sluigi return; 192298943Sluigi } 192398943Sluigi 1924117328Sluigi while (av) { 1925117328Sluigi /* 1926117328Sluigi * After the address we can have '/' or ':' indicating a mask, 1927117328Sluigi * ',' indicating another address follows, '{' indicating a 1928117328Sluigi * set of addresses of unspecified size. 1929117328Sluigi */ 1930117328Sluigi char *p = strpbrk(av, "/:,{"); 1931117328Sluigi int masklen; 1932117328Sluigi char md; 1933117328Sluigi 193498943Sluigi if (p) { 193598943Sluigi md = *p; 193698943Sluigi *p++ = '\0'; 1937117328Sluigi } else 1938117328Sluigi md = '\0'; 193998943Sluigi 1940117328Sluigi if (lookup_host(av, (struct in_addr *)&d[0]) != 0) 194198943Sluigi errx(EX_NOHOST, "hostname ``%s'' unknown", av); 194298943Sluigi switch (md) { 194398943Sluigi case ':': 1944117328Sluigi if (!inet_aton(p, (struct in_addr *)&d[1])) 194598943Sluigi errx(EX_DATAERR, "bad netmask ``%s''", p); 194698943Sluigi break; 194798943Sluigi case '/': 1948117328Sluigi masklen = atoi(p); 1949117328Sluigi if (masklen == 0) 1950117328Sluigi d[1] = htonl(0); /* mask */ 1951117328Sluigi else if (masklen > 32) 195298943Sluigi errx(EX_DATAERR, "bad width ``%s''", p); 195398943Sluigi else 1954117328Sluigi d[1] = htonl(~0 << (32 - masklen)); 195598943Sluigi break; 1956117328Sluigi case '{': /* no mask, assume /24 and put back the '{' */ 1957117328Sluigi d[1] = htonl(~0 << (32 - 24)); 1958117328Sluigi *(--p) = md; 1959117328Sluigi break; 1960117328Sluigi 1961117328Sluigi case ',': /* single address plus continuation */ 1962117328Sluigi *(--p) = md; 1963117328Sluigi /* FALLTHROUGH */ 1964117328Sluigi case 0: /* initialization value */ 196598943Sluigi default: 1966117328Sluigi d[1] = htonl(~0); /* force /32 */ 196798943Sluigi break; 196898943Sluigi } 1969117328Sluigi d[0] &= d[1]; /* mask base address with mask */ 1970117328Sluigi /* find next separator */ 197198943Sluigi if (p) 1972117328Sluigi p = strpbrk(p, ",{"); 1973117328Sluigi if (p && *p == '{') { 1974117328Sluigi /* 1975117328Sluigi * We have a set of addresses. They are stored as follows: 1976117328Sluigi * arg1 is the set size (powers of 2, 2..256) 1977117328Sluigi * addr is the base address IN HOST FORMAT 1978117328Sluigi * mask.. is an array of arg1 bits (rounded up to 1979117328Sluigi * the next multiple of 32) with bits set 1980117328Sluigi * for each host in the map. 1981117328Sluigi */ 1982117328Sluigi uint32_t *map = (uint32_t *)&cmd->mask; 198398943Sluigi int low, high; 1984117577Sluigi int i = contigmask((uint8_t *)&(d[1]), 32); 198598943Sluigi 1986117328Sluigi if (len > 0) 1987117328Sluigi errx(EX_DATAERR, "address set cannot be in a list"); 1988117328Sluigi if (i < 24 || i > 31) 1989117328Sluigi errx(EX_DATAERR, "invalid set with mask %d\n", i); 1990117328Sluigi cmd->o.arg1 = 1<<(32-i); /* map length */ 1991117328Sluigi d[0] = ntohl(d[0]); /* base addr in host format */ 199298943Sluigi cmd->o.opcode = O_IP_DST_SET; /* default */ 199398943Sluigi cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32) + (cmd->o.arg1+31)/32; 1994101117Sluigi for (i = 0; i < (cmd->o.arg1+31)/32 ; i++) 1995117328Sluigi map[i] = 0; /* clear map */ 199698943Sluigi 1997117328Sluigi av = p + 1; 1998117328Sluigi low = d[0] & 0xff; 199998943Sluigi high = low + cmd->o.arg1 - 1; 2000117328Sluigi /* 2001117328Sluigi * Here, i stores the previous value when we specify a range 2002117328Sluigi * of addresses within a mask, e.g. 45-63. i = -1 means we 2003117328Sluigi * have no previous value. 2004117328Sluigi */ 2005116716Sluigi i = -1; /* previous value in a range */ 200698943Sluigi while (isdigit(*av)) { 200798943Sluigi char *s; 2008117328Sluigi int a = strtol(av, &s, 0); 200998943Sluigi 2010117328Sluigi if (s == av) { /* no parameter */ 2011117328Sluigi if (*av != '}') 2012117328Sluigi errx(EX_DATAERR, "set not closed\n"); 2013117328Sluigi if (i != -1) 2014117328Sluigi errx(EX_DATAERR, "incomplete range %d-", i); 2015117328Sluigi break; 2016117328Sluigi } 2017117328Sluigi if (a < low || a > high) 2018117328Sluigi errx(EX_DATAERR, "addr %d out of range [%d-%d]\n", 201998943Sluigi a, low, high); 202098943Sluigi a -= low; 2021116716Sluigi if (i == -1) /* no previous in range */ 2022116716Sluigi i = a; 2023116716Sluigi else { /* check that range is valid */ 2024116716Sluigi if (i > a) 2025116716Sluigi errx(EX_DATAERR, "invalid range %d-%d", 2026116716Sluigi i+low, a+low); 2027116716Sluigi if (*s == '-') 2028116716Sluigi errx(EX_DATAERR, "double '-' in range"); 2029116716Sluigi } 2030116716Sluigi for (; i <= a; i++) 2031117328Sluigi map[i/32] |= 1<<(i & 31); 2032116716Sluigi i = -1; 2033116716Sluigi if (*s == '-') 2034116716Sluigi i = a; 2035117328Sluigi else if (*s == '}') 2036116716Sluigi break; 203798943Sluigi av = s+1; 203898943Sluigi } 203998943Sluigi return; 204098943Sluigi } 2041117328Sluigi av = p; 2042117328Sluigi if (av) /* then *av must be a ',' */ 2043117328Sluigi av++; 204498943Sluigi 2045117328Sluigi /* Check this entry */ 2046117328Sluigi if (d[1] == 0) { /* "any", specified as x.x.x.x/0 */ 2047117328Sluigi /* 2048117328Sluigi * 'any' turns the entire list into a NOP. 2049117328Sluigi * 'not any' never matches, so it is removed from the 2050117328Sluigi * list unless it is the only item, in which case we 2051117328Sluigi * report an error. 2052117328Sluigi */ 2053117328Sluigi if (cmd->o.len & F_NOT) { /* "not any" never matches */ 2054117328Sluigi if (av == NULL && len == 0) /* only this entry */ 2055117328Sluigi errx(EX_DATAERR, "not any never matches"); 2056117328Sluigi } 2057117328Sluigi /* else do nothing and skip this entry */ 2058128067Smaxim return; 2059117328Sluigi } 2060117328Sluigi /* A single IP can be stored in an optimized format */ 2061117328Sluigi if (d[1] == IP_MASK_ALL && av == NULL && len == 0) { 206298943Sluigi cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32); 2063117328Sluigi return; 2064117328Sluigi } 2065117328Sluigi len += 2; /* two words... */ 2066117328Sluigi d += 2; 2067117328Sluigi } /* end while */ 2068117328Sluigi cmd->o.len |= len+1; 206998943Sluigi} 207098943Sluigi 207198943Sluigi 207298943Sluigi/* 207398943Sluigi * helper function to process a set of flags and set bits in the 207498943Sluigi * appropriate masks. 207598943Sluigi */ 207698943Sluigistatic void 207798943Sluigifill_flags(ipfw_insn *cmd, enum ipfw_opcodes opcode, 207898943Sluigi struct _s_x *flags, char *p) 207998943Sluigi{ 2080117328Sluigi uint8_t set=0, clear=0; 208198943Sluigi 208298943Sluigi while (p && *p) { 208398943Sluigi char *q; /* points to the separator */ 208498943Sluigi int val; 2085117328Sluigi uint8_t *which; /* mask we are working on */ 208698943Sluigi 208798943Sluigi if (*p == '!') { 208898943Sluigi p++; 208998943Sluigi which = &clear; 209098943Sluigi } else 209198943Sluigi which = &set; 209298943Sluigi q = strchr(p, ','); 209398943Sluigi if (q) 209498943Sluigi *q++ = '\0'; 209598943Sluigi val = match_token(flags, p); 209698943Sluigi if (val <= 0) 209798943Sluigi errx(EX_DATAERR, "invalid flag %s", p); 2098117328Sluigi *which |= (uint8_t)val; 209998943Sluigi p = q; 210098943Sluigi } 210198943Sluigi cmd->opcode = opcode; 210298943Sluigi cmd->len = (cmd->len & (F_NOT | F_OR)) | 1; 210398943Sluigi cmd->arg1 = (set & 0xff) | ( (clear & 0xff) << 8); 210498943Sluigi} 210598943Sluigi 210698943Sluigi 210798943Sluigistatic void 210898943Sluigidelete(int ac, char *av[]) 210998943Sluigi{ 2110117328Sluigi uint32_t rulenum; 2111117469Sluigi struct dn_pipe p; 211298943Sluigi int i; 211398943Sluigi int exitval = EX_OK; 2114101628Sluigi int do_set = 0; 211598943Sluigi 2116117469Sluigi memset(&p, 0, sizeof p); 211798943Sluigi 211898943Sluigi av++; ac--; 2119101641Sluigi if (ac > 0 && !strncmp(*av, "set", strlen(*av))) { 2120101978Sluigi do_set = 1; /* delete set */ 2121101628Sluigi ac--; av++; 2122101978Sluigi } 212398943Sluigi 212498943Sluigi /* Rule number */ 212598943Sluigi while (ac && isdigit(**av)) { 212698943Sluigi i = atoi(*av); av++; ac--; 212798943Sluigi if (do_pipe) { 212898943Sluigi if (do_pipe == 1) 2129117469Sluigi p.pipe_nr = i; 213098943Sluigi else 2131117469Sluigi p.fs.fs_nr = i; 2132117469Sluigi i = do_cmd(IP_DUMMYNET_DEL, &p, sizeof p); 213398943Sluigi if (i) { 213498943Sluigi exitval = 1; 213598943Sluigi warn("rule %u: setsockopt(IP_DUMMYNET_DEL)", 2136117469Sluigi do_pipe == 1 ? p.pipe_nr : p.fs.fs_nr); 213798943Sluigi } 213898943Sluigi } else { 2139101978Sluigi rulenum = (i & 0xffff) | (do_set << 24); 2140117328Sluigi i = do_cmd(IP_FW_DEL, &rulenum, sizeof rulenum); 214198943Sluigi if (i) { 214298943Sluigi exitval = EX_UNAVAILABLE; 214398943Sluigi warn("rule %u: setsockopt(IP_FW_DEL)", 214498943Sluigi rulenum); 214598943Sluigi } 214698943Sluigi } 214798943Sluigi } 214898943Sluigi if (exitval != EX_OK) 214998943Sluigi exit(exitval); 215098943Sluigi} 215198943Sluigi 215298943Sluigi 215398943Sluigi/* 215498943Sluigi * fill the interface structure. We do not check the name as we can 215598943Sluigi * create interfaces dynamically, so checking them at insert time 215698943Sluigi * makes relatively little sense. 2157121816Sbrooks * Interface names containing '*', '?', or '[' are assumed to be shell 2158121816Sbrooks * patterns which match interfaces. 215998943Sluigi */ 216098943Sluigistatic void 216198943Sluigifill_iface(ipfw_insn_if *cmd, char *arg) 216298943Sluigi{ 216398943Sluigi cmd->name[0] = '\0'; 216498943Sluigi cmd->o.len |= F_INSN_SIZE(ipfw_insn_if); 216598943Sluigi 216698943Sluigi /* Parse the interface or address */ 216798943Sluigi if (!strcmp(arg, "any")) 216898943Sluigi cmd->o.len = 0; /* effectively ignore this command */ 216998943Sluigi else if (!isdigit(*arg)) { 2170121816Sbrooks strlcpy(cmd->name, arg, sizeof(cmd->name)); 2171121816Sbrooks cmd->p.glob = strpbrk(arg, "*?[") != NULL ? 1 : 0; 217298943Sluigi } else if (!inet_aton(arg, &cmd->p.ip)) 217398943Sluigi errx(EX_DATAERR, "bad ip address ``%s''", arg); 217498943Sluigi} 217598943Sluigi 217698943Sluigi/* 217798943Sluigi * the following macro returns an error message if we run out of 217898943Sluigi * arguments. 217998943Sluigi */ 218098943Sluigi#define NEED1(msg) {if (!ac) errx(EX_USAGE, msg);} 218198943Sluigi 218298943Sluigistatic void 218398943Sluigiconfig_pipe(int ac, char **av) 218498943Sluigi{ 2185117469Sluigi struct dn_pipe p; 218698943Sluigi int i; 218798943Sluigi char *end; 2188117328Sluigi uint32_t a; 218998943Sluigi void *par = NULL; 219098943Sluigi 2191117469Sluigi memset(&p, 0, sizeof p); 219298943Sluigi 219398943Sluigi av++; ac--; 219498943Sluigi /* Pipe number */ 219598943Sluigi if (ac && isdigit(**av)) { 219698943Sluigi i = atoi(*av); av++; ac--; 219798943Sluigi if (do_pipe == 1) 2198117469Sluigi p.pipe_nr = i; 219998943Sluigi else 2200117469Sluigi p.fs.fs_nr = i; 220198943Sluigi } 220299475Sluigi while (ac > 0) { 220398943Sluigi double d; 220498943Sluigi int tok = match_token(dummynet_params, *av); 220598943Sluigi ac--; av++; 220698943Sluigi 220798943Sluigi switch(tok) { 2208101978Sluigi case TOK_NOERROR: 2209117469Sluigi p.fs.flags_fs |= DN_NOERROR; 2210101978Sluigi break; 2211101978Sluigi 221298943Sluigi case TOK_PLR: 221398943Sluigi NEED1("plr needs argument 0..1\n"); 221498943Sluigi d = strtod(av[0], NULL); 221598943Sluigi if (d > 1) 221698943Sluigi d = 1; 221798943Sluigi else if (d < 0) 221898943Sluigi d = 0; 2219117469Sluigi p.fs.plr = (int)(d*0x7fffffff); 222098943Sluigi ac--; av++; 222198943Sluigi break; 222298943Sluigi 222398943Sluigi case TOK_QUEUE: 222498943Sluigi NEED1("queue needs queue size\n"); 222598943Sluigi end = NULL; 2226117469Sluigi p.fs.qsize = strtoul(av[0], &end, 0); 222798943Sluigi if (*end == 'K' || *end == 'k') { 2228117469Sluigi p.fs.flags_fs |= DN_QSIZE_IS_BYTES; 2229117469Sluigi p.fs.qsize *= 1024; 223098943Sluigi } else if (*end == 'B' || !strncmp(end, "by", 2)) { 2231117469Sluigi p.fs.flags_fs |= DN_QSIZE_IS_BYTES; 223298943Sluigi } 223398943Sluigi ac--; av++; 223498943Sluigi break; 223598943Sluigi 223698943Sluigi case TOK_BUCKETS: 223798943Sluigi NEED1("buckets needs argument\n"); 2238117469Sluigi p.fs.rq_size = strtoul(av[0], NULL, 0); 223998943Sluigi ac--; av++; 224098943Sluigi break; 224198943Sluigi 224298943Sluigi case TOK_MASK: 224398943Sluigi NEED1("mask needs mask specifier\n"); 224498943Sluigi /* 224598943Sluigi * per-flow queue, mask is dst_ip, dst_port, 224698943Sluigi * src_ip, src_port, proto measured in bits 224798943Sluigi */ 224898943Sluigi par = NULL; 224998943Sluigi 2250117469Sluigi p.fs.flow_mask.dst_ip = 0; 2251117469Sluigi p.fs.flow_mask.src_ip = 0; 2252117469Sluigi p.fs.flow_mask.dst_port = 0; 2253117469Sluigi p.fs.flow_mask.src_port = 0; 2254117469Sluigi p.fs.flow_mask.proto = 0; 225598943Sluigi end = NULL; 225698943Sluigi 225798943Sluigi while (ac >= 1) { 2258117328Sluigi uint32_t *p32 = NULL; 2259117328Sluigi uint16_t *p16 = NULL; 226098943Sluigi 226198943Sluigi tok = match_token(dummynet_params, *av); 226298943Sluigi ac--; av++; 226398943Sluigi switch(tok) { 226498943Sluigi case TOK_ALL: 226598943Sluigi /* 226698943Sluigi * special case, all bits significant 226798943Sluigi */ 2268117469Sluigi p.fs.flow_mask.dst_ip = ~0; 2269117469Sluigi p.fs.flow_mask.src_ip = ~0; 2270117469Sluigi p.fs.flow_mask.dst_port = ~0; 2271117469Sluigi p.fs.flow_mask.src_port = ~0; 2272117469Sluigi p.fs.flow_mask.proto = ~0; 2273117469Sluigi p.fs.flags_fs |= DN_HAVE_FLOW_MASK; 227498943Sluigi goto end_mask; 227598943Sluigi 227698943Sluigi case TOK_DSTIP: 2277117469Sluigi p32 = &p.fs.flow_mask.dst_ip; 227898943Sluigi break; 227998943Sluigi 228098943Sluigi case TOK_SRCIP: 2281117469Sluigi p32 = &p.fs.flow_mask.src_ip; 228298943Sluigi break; 228398943Sluigi 228498943Sluigi case TOK_DSTPORT: 2285117469Sluigi p16 = &p.fs.flow_mask.dst_port; 228698943Sluigi break; 228798943Sluigi 228898943Sluigi case TOK_SRCPORT: 2289117469Sluigi p16 = &p.fs.flow_mask.src_port; 229098943Sluigi break; 229198943Sluigi 229298943Sluigi case TOK_PROTO: 229398943Sluigi break; 229498943Sluigi 229598943Sluigi default: 229698943Sluigi ac++; av--; /* backtrack */ 229798943Sluigi goto end_mask; 229898943Sluigi } 229998943Sluigi if (ac < 1) 230098943Sluigi errx(EX_USAGE, "mask: value missing"); 230198943Sluigi if (*av[0] == '/') { 230298943Sluigi a = strtoul(av[0]+1, &end, 0); 230398943Sluigi a = (a == 32) ? ~0 : (1 << a) - 1; 2304106505Smaxim } else 230599909Sluigi a = strtoul(av[0], &end, 0); 230698943Sluigi if (p32 != NULL) 230798943Sluigi *p32 = a; 230898943Sluigi else if (p16 != NULL) { 230998943Sluigi if (a > 65535) 231098943Sluigi errx(EX_DATAERR, 231198943Sluigi "mask: must be 16 bit"); 2312117328Sluigi *p16 = (uint16_t)a; 231398943Sluigi } else { 231498943Sluigi if (a > 255) 231598943Sluigi errx(EX_DATAERR, 231698943Sluigi "mask: must be 8 bit"); 2317117469Sluigi p.fs.flow_mask.proto = (uint8_t)a; 231898943Sluigi } 231998943Sluigi if (a != 0) 2320117469Sluigi p.fs.flags_fs |= DN_HAVE_FLOW_MASK; 232198943Sluigi ac--; av++; 232298943Sluigi } /* end while, config masks */ 232398943Sluigiend_mask: 232498943Sluigi break; 232598943Sluigi 232698943Sluigi case TOK_RED: 232798943Sluigi case TOK_GRED: 232898943Sluigi NEED1("red/gred needs w_q/min_th/max_th/max_p\n"); 2329117469Sluigi p.fs.flags_fs |= DN_IS_RED; 233098943Sluigi if (tok == TOK_GRED) 2331117469Sluigi p.fs.flags_fs |= DN_IS_GENTLE_RED; 233298943Sluigi /* 233398943Sluigi * the format for parameters is w_q/min_th/max_th/max_p 233498943Sluigi */ 233598943Sluigi if ((end = strsep(&av[0], "/"))) { 233698943Sluigi double w_q = strtod(end, NULL); 233798943Sluigi if (w_q > 1 || w_q <= 0) 233898943Sluigi errx(EX_DATAERR, "0 < w_q <= 1"); 2339117469Sluigi p.fs.w_q = (int) (w_q * (1 << SCALE_RED)); 234098943Sluigi } 234198943Sluigi if ((end = strsep(&av[0], "/"))) { 2342117469Sluigi p.fs.min_th = strtoul(end, &end, 0); 234398943Sluigi if (*end == 'K' || *end == 'k') 2344117469Sluigi p.fs.min_th *= 1024; 234598943Sluigi } 234698943Sluigi if ((end = strsep(&av[0], "/"))) { 2347117469Sluigi p.fs.max_th = strtoul(end, &end, 0); 234898943Sluigi if (*end == 'K' || *end == 'k') 2349117469Sluigi p.fs.max_th *= 1024; 235098943Sluigi } 235198943Sluigi if ((end = strsep(&av[0], "/"))) { 235298943Sluigi double max_p = strtod(end, NULL); 235398943Sluigi if (max_p > 1 || max_p <= 0) 235498943Sluigi errx(EX_DATAERR, "0 < max_p <= 1"); 2355117469Sluigi p.fs.max_p = (int)(max_p * (1 << SCALE_RED)); 235698943Sluigi } 235798943Sluigi ac--; av++; 235898943Sluigi break; 235998943Sluigi 236098943Sluigi case TOK_DROPTAIL: 2361117469Sluigi p.fs.flags_fs &= ~(DN_IS_RED|DN_IS_GENTLE_RED); 236298943Sluigi break; 2363106505Smaxim 236498943Sluigi case TOK_BW: 236598943Sluigi NEED1("bw needs bandwidth or interface\n"); 236698943Sluigi if (do_pipe != 1) 236798943Sluigi errx(EX_DATAERR, "bandwidth only valid for pipes"); 236898943Sluigi /* 236998943Sluigi * set clocking interface or bandwidth value 237098943Sluigi */ 237198943Sluigi if (av[0][0] >= 'a' && av[0][0] <= 'z') { 2372117469Sluigi int l = sizeof(p.if_name)-1; 237398943Sluigi /* interface name */ 2374117469Sluigi strncpy(p.if_name, av[0], l); 2375117469Sluigi p.if_name[l] = '\0'; 2376117469Sluigi p.bandwidth = 0; 237798943Sluigi } else { 2378117469Sluigi p.if_name[0] = '\0'; 2379117469Sluigi p.bandwidth = strtoul(av[0], &end, 0); 238098943Sluigi if (*end == 'K' || *end == 'k') { 238198943Sluigi end++; 2382117469Sluigi p.bandwidth *= 1000; 238398943Sluigi } else if (*end == 'M') { 238498943Sluigi end++; 2385117469Sluigi p.bandwidth *= 1000000; 238698943Sluigi } 238798943Sluigi if (*end == 'B' || !strncmp(end, "by", 2)) 2388117469Sluigi p.bandwidth *= 8; 2389117469Sluigi if (p.bandwidth < 0) 239098943Sluigi errx(EX_DATAERR, "bandwidth too large"); 239198943Sluigi } 239298943Sluigi ac--; av++; 239398943Sluigi break; 239498943Sluigi 239598943Sluigi case TOK_DELAY: 239698943Sluigi if (do_pipe != 1) 239798943Sluigi errx(EX_DATAERR, "delay only valid for pipes"); 239898943Sluigi NEED1("delay needs argument 0..10000ms\n"); 2399117469Sluigi p.delay = strtoul(av[0], NULL, 0); 240098943Sluigi ac--; av++; 240198943Sluigi break; 240298943Sluigi 240398943Sluigi case TOK_WEIGHT: 240498943Sluigi if (do_pipe == 1) 240598943Sluigi errx(EX_DATAERR,"weight only valid for queues"); 240698943Sluigi NEED1("weight needs argument 0..100\n"); 2407117469Sluigi p.fs.weight = strtoul(av[0], &end, 0); 240898943Sluigi ac--; av++; 240998943Sluigi break; 241098943Sluigi 241198943Sluigi case TOK_PIPE: 241298943Sluigi if (do_pipe == 1) 241398943Sluigi errx(EX_DATAERR,"pipe only valid for queues"); 241498943Sluigi NEED1("pipe needs pipe_number\n"); 2415117469Sluigi p.fs.parent_nr = strtoul(av[0], &end, 0); 241698943Sluigi ac--; av++; 241798943Sluigi break; 241898943Sluigi 241998943Sluigi default: 2420124924Smaxim errx(EX_DATAERR, "unrecognised option ``%s''", av[-1]); 242198943Sluigi } 242298943Sluigi } 242398943Sluigi if (do_pipe == 1) { 2424117469Sluigi if (p.pipe_nr == 0) 242598943Sluigi errx(EX_DATAERR, "pipe_nr must be > 0"); 2426117469Sluigi if (p.delay > 10000) 242798943Sluigi errx(EX_DATAERR, "delay must be < 10000"); 242898943Sluigi } else { /* do_pipe == 2, queue */ 2429117469Sluigi if (p.fs.parent_nr == 0) 243098943Sluigi errx(EX_DATAERR, "pipe must be > 0"); 2431117469Sluigi if (p.fs.weight >100) 243298943Sluigi errx(EX_DATAERR, "weight must be <= 100"); 243398943Sluigi } 2434117469Sluigi if (p.fs.flags_fs & DN_QSIZE_IS_BYTES) { 2435117469Sluigi if (p.fs.qsize > 1024*1024) 243698943Sluigi errx(EX_DATAERR, "queue size must be < 1MB"); 243798943Sluigi } else { 2438117469Sluigi if (p.fs.qsize > 100) 243998943Sluigi errx(EX_DATAERR, "2 <= queue size <= 100"); 244098943Sluigi } 2441117469Sluigi if (p.fs.flags_fs & DN_IS_RED) { 244298943Sluigi size_t len; 244398943Sluigi int lookup_depth, avg_pkt_size; 244498943Sluigi double s, idle, weight, w_q; 2445117469Sluigi struct clockinfo ck; 244698943Sluigi int t; 244798943Sluigi 2448117469Sluigi if (p.fs.min_th >= p.fs.max_th) 244998943Sluigi errx(EX_DATAERR, "min_th %d must be < than max_th %d", 2450117469Sluigi p.fs.min_th, p.fs.max_th); 2451117469Sluigi if (p.fs.max_th == 0) 245298943Sluigi errx(EX_DATAERR, "max_th must be > 0"); 245398943Sluigi 245498943Sluigi len = sizeof(int); 245598943Sluigi if (sysctlbyname("net.inet.ip.dummynet.red_lookup_depth", 245698943Sluigi &lookup_depth, &len, NULL, 0) == -1) 245798943Sluigi 245898943Sluigi errx(1, "sysctlbyname(\"%s\")", 245998943Sluigi "net.inet.ip.dummynet.red_lookup_depth"); 246098943Sluigi if (lookup_depth == 0) 246198943Sluigi errx(EX_DATAERR, "net.inet.ip.dummynet.red_lookup_depth" 246298943Sluigi " must be greater than zero"); 246398943Sluigi 246498943Sluigi len = sizeof(int); 246598943Sluigi if (sysctlbyname("net.inet.ip.dummynet.red_avg_pkt_size", 246698943Sluigi &avg_pkt_size, &len, NULL, 0) == -1) 246798943Sluigi 246898943Sluigi errx(1, "sysctlbyname(\"%s\")", 246998943Sluigi "net.inet.ip.dummynet.red_avg_pkt_size"); 247098943Sluigi if (avg_pkt_size == 0) 247198943Sluigi errx(EX_DATAERR, 247298943Sluigi "net.inet.ip.dummynet.red_avg_pkt_size must" 247398943Sluigi " be greater than zero"); 247498943Sluigi 247598943Sluigi len = sizeof(struct clockinfo); 2476117469Sluigi if (sysctlbyname("kern.clockrate", &ck, &len, NULL, 0) == -1) 247798943Sluigi errx(1, "sysctlbyname(\"%s\")", "kern.clockrate"); 247898943Sluigi 247998943Sluigi /* 248098943Sluigi * Ticks needed for sending a medium-sized packet. 248198943Sluigi * Unfortunately, when we are configuring a WF2Q+ queue, we 248298943Sluigi * do not have bandwidth information, because that is stored 248398943Sluigi * in the parent pipe, and also we have multiple queues 248498943Sluigi * competing for it. So we set s=0, which is not very 248598943Sluigi * correct. But on the other hand, why do we want RED with 248698943Sluigi * WF2Q+ ? 248798943Sluigi */ 2488117469Sluigi if (p.bandwidth==0) /* this is a WF2Q+ queue */ 248998943Sluigi s = 0; 249098943Sluigi else 2491117469Sluigi s = ck.hz * avg_pkt_size * 8 / p.bandwidth; 249298943Sluigi 249398943Sluigi /* 249498943Sluigi * max idle time (in ticks) before avg queue size becomes 0. 249598943Sluigi * NOTA: (3/w_q) is approx the value x so that 249698943Sluigi * (1-w_q)^x < 10^-3. 249798943Sluigi */ 2498117469Sluigi w_q = ((double)p.fs.w_q) / (1 << SCALE_RED); 249998943Sluigi idle = s * 3. / w_q; 2500117469Sluigi p.fs.lookup_step = (int)idle / lookup_depth; 2501117469Sluigi if (!p.fs.lookup_step) 2502117469Sluigi p.fs.lookup_step = 1; 250398943Sluigi weight = 1 - w_q; 2504117469Sluigi for (t = p.fs.lookup_step; t > 0; --t) 250598943Sluigi weight *= weight; 2506117469Sluigi p.fs.lookup_weight = (int)(weight * (1 << SCALE_RED)); 250798943Sluigi } 2508117469Sluigi i = do_cmd(IP_DUMMYNET_CONFIGURE, &p, sizeof p); 250998943Sluigi if (i) 251098943Sluigi err(1, "setsockopt(%s)", "IP_DUMMYNET_CONFIGURE"); 251198943Sluigi} 251298943Sluigi 251398943Sluigistatic void 2514117577Sluigiget_mac_addr_mask(char *p, uint8_t *addr, uint8_t *mask) 251598943Sluigi{ 251698943Sluigi int i, l; 251798943Sluigi 251898943Sluigi for (i=0; i<6; i++) 251998943Sluigi addr[i] = mask[i] = 0; 252098943Sluigi if (!strcmp(p, "any")) 252198943Sluigi return; 252298943Sluigi 252398943Sluigi for (i=0; *p && i<6;i++, p++) { 252498943Sluigi addr[i] = strtol(p, &p, 16); 252598943Sluigi if (*p != ':') /* we start with the mask */ 252698943Sluigi break; 252798943Sluigi } 252898943Sluigi if (*p == '/') { /* mask len */ 252998943Sluigi l = strtol(p+1, &p, 0); 253098943Sluigi for (i=0; l>0; l -=8, i++) 253198943Sluigi mask[i] = (l >=8) ? 0xff : (~0) << (8-l); 253298943Sluigi } else if (*p == '&') { /* mask */ 253398943Sluigi for (i=0, p++; *p && i<6;i++, p++) { 253498943Sluigi mask[i] = strtol(p, &p, 16); 253598943Sluigi if (*p != ':') 253698943Sluigi break; 253798943Sluigi } 253898943Sluigi } else if (*p == '\0') { 253998943Sluigi for (i=0; i<6; i++) 254098943Sluigi mask[i] = 0xff; 254198943Sluigi } 254298943Sluigi for (i=0; i<6; i++) 254398943Sluigi addr[i] &= mask[i]; 254498943Sluigi} 254598943Sluigi 254698943Sluigi/* 254798943Sluigi * helper function, updates the pointer to cmd with the length 254898943Sluigi * of the current command, and also cleans up the first word of 254998943Sluigi * the new command in case it has been clobbered before. 255098943Sluigi */ 255198943Sluigistatic ipfw_insn * 255298943Sluiginext_cmd(ipfw_insn *cmd) 255398943Sluigi{ 255498943Sluigi cmd += F_LEN(cmd); 255598943Sluigi bzero(cmd, sizeof(*cmd)); 255698943Sluigi return cmd; 255798943Sluigi} 255898943Sluigi 255998943Sluigi/* 2560117469Sluigi * Takes arguments and copies them into a comment 2561117469Sluigi */ 2562117469Sluigistatic void 2563117469Sluigifill_comment(ipfw_insn *cmd, int ac, char **av) 2564117469Sluigi{ 2565117469Sluigi int i, l; 2566117469Sluigi char *p = (char *)(cmd + 1); 2567117577Sluigi 2568117469Sluigi cmd->opcode = O_NOP; 2569117469Sluigi cmd->len = (cmd->len & (F_NOT | F_OR)); 2570117469Sluigi 2571117469Sluigi /* Compute length of comment string. */ 2572117469Sluigi for (i = 0, l = 0; i < ac; i++) 2573117469Sluigi l += strlen(av[i]) + 1; 2574117469Sluigi if (l == 0) 2575117469Sluigi return; 2576117469Sluigi if (l > 84) 2577117469Sluigi errx(EX_DATAERR, 2578117469Sluigi "comment too long (max 80 chars)"); 2579117469Sluigi l = 1 + (l+3)/4; 2580117469Sluigi cmd->len = (cmd->len & (F_NOT | F_OR)) | l; 2581117469Sluigi for (i = 0; i < ac; i++) { 2582117469Sluigi strcpy(p, av[i]); 2583117469Sluigi p += strlen(av[i]); 2584117469Sluigi *p++ = ' '; 2585117469Sluigi } 2586117469Sluigi *(--p) = '\0'; 2587117469Sluigi} 2588117577Sluigi 2589117469Sluigi/* 259098943Sluigi * A function to fill simple commands of size 1. 259198943Sluigi * Existing flags are preserved. 259298943Sluigi */ 259398943Sluigistatic void 2594117328Sluigifill_cmd(ipfw_insn *cmd, enum ipfw_opcodes opcode, int flags, uint16_t arg) 259598943Sluigi{ 259698943Sluigi cmd->opcode = opcode; 259798943Sluigi cmd->len = ((cmd->len | flags) & (F_NOT | F_OR)) | 1; 259898943Sluigi cmd->arg1 = arg; 259998943Sluigi} 260098943Sluigi 260198943Sluigi/* 260298943Sluigi * Fetch and add the MAC address and type, with masks. This generates one or 260398943Sluigi * two microinstructions, and returns the pointer to the last one. 260498943Sluigi */ 260598943Sluigistatic ipfw_insn * 260698943Sluigiadd_mac(ipfw_insn *cmd, int ac, char *av[]) 260798943Sluigi{ 2608102087Sluigi ipfw_insn_mac *mac; 260998943Sluigi 2610102087Sluigi if (ac < 2) 2611102098Sluigi errx(EX_DATAERR, "MAC dst src"); 261298943Sluigi 261398943Sluigi cmd->opcode = O_MACADDR2; 261498943Sluigi cmd->len = (cmd->len & (F_NOT | F_OR)) | F_INSN_SIZE(ipfw_insn_mac); 261598943Sluigi 261698943Sluigi mac = (ipfw_insn_mac *)cmd; 2617101978Sluigi get_mac_addr_mask(av[0], mac->addr, mac->mask); /* dst */ 261898943Sluigi get_mac_addr_mask(av[1], &(mac->addr[6]), &(mac->mask[6])); /* src */ 2619102087Sluigi return cmd; 2620102087Sluigi} 262198943Sluigi 2622102087Sluigistatic ipfw_insn * 2623102087Sluigiadd_mactype(ipfw_insn *cmd, int ac, char *av) 2624102087Sluigi{ 2625102087Sluigi if (ac < 1) 2626102087Sluigi errx(EX_DATAERR, "missing MAC type"); 2627102087Sluigi if (strcmp(av, "any") != 0) { /* we have a non-null type */ 2628102087Sluigi fill_newports((ipfw_insn_u16 *)cmd, av, IPPROTO_ETHERTYPE); 262998943Sluigi cmd->opcode = O_MAC_TYPE; 2630102087Sluigi return cmd; 2631102087Sluigi } else 2632102087Sluigi return NULL; 2633102087Sluigi} 263498943Sluigi 2635102087Sluigistatic ipfw_insn * 2636102087Sluigiadd_proto(ipfw_insn *cmd, char *av) 2637102087Sluigi{ 2638102087Sluigi struct protoent *pe; 2639102087Sluigi u_char proto = 0; 2640102087Sluigi 2641102087Sluigi if (!strncmp(av, "all", strlen(av))) 2642102087Sluigi ; /* same as "ip" */ 2643102087Sluigi else if ((proto = atoi(av)) > 0) 2644102087Sluigi ; /* all done! */ 2645102087Sluigi else if ((pe = getprotobyname(av)) != NULL) 2646102087Sluigi proto = pe->p_proto; 2647102087Sluigi else 2648102098Sluigi return NULL; 2649102087Sluigi if (proto != IPPROTO_IP) 2650102087Sluigi fill_cmd(cmd, O_PROTO, 0, proto); 265198943Sluigi return cmd; 265298943Sluigi} 265398943Sluigi 2654102087Sluigistatic ipfw_insn * 2655102087Sluigiadd_srcip(ipfw_insn *cmd, char *av) 2656102087Sluigi{ 2657102087Sluigi fill_ip((ipfw_insn_ip *)cmd, av); 2658102087Sluigi if (cmd->opcode == O_IP_DST_SET) /* set */ 2659102087Sluigi cmd->opcode = O_IP_SRC_SET; 2660102087Sluigi else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) /* me */ 2661102087Sluigi cmd->opcode = O_IP_SRC_ME; 2662102087Sluigi else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn_u32)) /* one IP */ 2663102087Sluigi cmd->opcode = O_IP_SRC; 2664117328Sluigi else /* addr/mask */ 2665102087Sluigi cmd->opcode = O_IP_SRC_MASK; 2666102087Sluigi return cmd; 2667102087Sluigi} 2668102087Sluigi 2669102087Sluigistatic ipfw_insn * 2670102087Sluigiadd_dstip(ipfw_insn *cmd, char *av) 2671102087Sluigi{ 2672102087Sluigi fill_ip((ipfw_insn_ip *)cmd, av); 2673102087Sluigi if (cmd->opcode == O_IP_DST_SET) /* set */ 2674102087Sluigi ; 2675102087Sluigi else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) /* me */ 2676102087Sluigi cmd->opcode = O_IP_DST_ME; 2677102087Sluigi else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn_u32)) /* one IP */ 2678102087Sluigi cmd->opcode = O_IP_DST; 2679117328Sluigi else /* addr/mask */ 2680102087Sluigi cmd->opcode = O_IP_DST_MASK; 2681102087Sluigi return cmd; 2682102087Sluigi} 2683102087Sluigi 2684102087Sluigistatic ipfw_insn * 2685102087Sluigiadd_ports(ipfw_insn *cmd, char *av, u_char proto, int opcode) 2686102087Sluigi{ 2687102087Sluigi if (!strncmp(av, "any", strlen(av))) { 2688102087Sluigi return NULL; 2689102087Sluigi } else if (fill_newports((ipfw_insn_u16 *)cmd, av, proto)) { 2690102087Sluigi /* XXX todo: check that we have a protocol with ports */ 2691102087Sluigi cmd->opcode = opcode; 2692102087Sluigi return cmd; 2693102087Sluigi } 2694102087Sluigi return NULL; 2695102087Sluigi} 2696102087Sluigi 269798943Sluigi/* 269898943Sluigi * Parse arguments and assemble the microinstructions which make up a rule. 269998943Sluigi * Rules are added into the 'rulebuf' and then copied in the correct order 270098943Sluigi * into the actual rule. 270198943Sluigi * 270298943Sluigi * The syntax for a rule starts with the action, followed by an 270398943Sluigi * optional log action, and the various match patterns. 2704108533Sschweikh * In the assembled microcode, the first opcode must be an O_PROBE_STATE 270598943Sluigi * (generated if the rule includes a keep-state option), then the 270698943Sluigi * various match patterns, the "log" action, and the actual action. 2707106505Smaxim * 270898943Sluigi */ 270998943Sluigistatic void 271098943Sluigiadd(int ac, char *av[]) 271198943Sluigi{ 271298943Sluigi /* 271398943Sluigi * rules are added into the 'rulebuf' and then copied in 271498943Sluigi * the correct order into the actual rule. 271598943Sluigi * Some things that need to go out of order (prob, action etc.) 271698943Sluigi * go into actbuf[]. 271798943Sluigi */ 2718117328Sluigi static uint32_t rulebuf[255], actbuf[255], cmdbuf[255]; 271998943Sluigi 2720117469Sluigi ipfw_insn *src, *dst, *cmd, *action, *prev=NULL; 2721102087Sluigi ipfw_insn *first_cmd; /* first match pattern */ 272298943Sluigi 272398943Sluigi struct ip_fw *rule; 272498943Sluigi 272598943Sluigi /* 272698943Sluigi * various flags used to record that we entered some fields. 272798943Sluigi */ 2728101116Sluigi ipfw_insn *have_state = NULL; /* check-state or keep-state */ 272998943Sluigi 273098943Sluigi int i; 273198943Sluigi 273298943Sluigi int open_par = 0; /* open parenthesis ( */ 273398943Sluigi 273498943Sluigi /* proto is here because it is used to fetch ports */ 273598943Sluigi u_char proto = IPPROTO_IP; /* default protocol */ 273698943Sluigi 2737107289Sluigi double match_prob = 1; /* match probability, default is always match */ 2738107289Sluigi 273998943Sluigi bzero(actbuf, sizeof(actbuf)); /* actions go here */ 274098943Sluigi bzero(cmdbuf, sizeof(cmdbuf)); 274198943Sluigi bzero(rulebuf, sizeof(rulebuf)); 274298943Sluigi 274398943Sluigi rule = (struct ip_fw *)rulebuf; 274498943Sluigi cmd = (ipfw_insn *)cmdbuf; 274598943Sluigi action = (ipfw_insn *)actbuf; 274698943Sluigi 274798943Sluigi av++; ac--; 274898943Sluigi 274998943Sluigi /* [rule N] -- Rule number optional */ 275098943Sluigi if (ac && isdigit(**av)) { 275198943Sluigi rule->rulenum = atoi(*av); 275298943Sluigi av++; 275398943Sluigi ac--; 275498943Sluigi } 275598943Sluigi 2756117655Sluigi /* [set N] -- set number (0..RESVD_SET), optional */ 2757101628Sluigi if (ac > 1 && !strncmp(*av, "set", strlen(*av))) { 2758101628Sluigi int set = strtoul(av[1], NULL, 10); 2759117655Sluigi if (set < 0 || set > RESVD_SET) 2760101628Sluigi errx(EX_DATAERR, "illegal set %s", av[1]); 2761101628Sluigi rule->set = set; 2762101628Sluigi av += 2; ac -= 2; 2763101628Sluigi } 2764101628Sluigi 276598943Sluigi /* [prob D] -- match probability, optional */ 276698943Sluigi if (ac > 1 && !strncmp(*av, "prob", strlen(*av))) { 2767107289Sluigi match_prob = strtod(av[1], NULL); 276898943Sluigi 2769107289Sluigi if (match_prob <= 0 || match_prob > 1) 277098943Sluigi errx(EX_DATAERR, "illegal match prob. %s", av[1]); 277198943Sluigi av += 2; ac -= 2; 277298943Sluigi } 277398943Sluigi 277498943Sluigi /* action -- mandatory */ 277598943Sluigi NEED1("missing action"); 277698943Sluigi i = match_token(rule_actions, *av); 277798943Sluigi ac--; av++; 277898943Sluigi action->len = 1; /* default */ 277998943Sluigi switch(i) { 278098943Sluigi case TOK_CHECKSTATE: 2781101116Sluigi have_state = action; 278298943Sluigi action->opcode = O_CHECK_STATE; 278398943Sluigi break; 278498943Sluigi 278598943Sluigi case TOK_ACCEPT: 278698943Sluigi action->opcode = O_ACCEPT; 278798943Sluigi break; 278898943Sluigi 278998943Sluigi case TOK_DENY: 279098943Sluigi action->opcode = O_DENY; 279199475Sluigi action->arg1 = 0; 279298943Sluigi break; 279398943Sluigi 279499475Sluigi case TOK_REJECT: 279599475Sluigi action->opcode = O_REJECT; 279699475Sluigi action->arg1 = ICMP_UNREACH_HOST; 279799475Sluigi break; 279899475Sluigi 279999475Sluigi case TOK_RESET: 280099475Sluigi action->opcode = O_REJECT; 280199475Sluigi action->arg1 = ICMP_REJECT_RST; 280299475Sluigi break; 280399475Sluigi 280499475Sluigi case TOK_UNREACH: 280599475Sluigi action->opcode = O_REJECT; 280699475Sluigi NEED1("missing reject code"); 280799475Sluigi fill_reject_code(&action->arg1, *av); 280899475Sluigi ac--; av++; 280999475Sluigi break; 281099475Sluigi 281198943Sluigi case TOK_COUNT: 281298943Sluigi action->opcode = O_COUNT; 281398943Sluigi break; 281498943Sluigi 281598943Sluigi case TOK_QUEUE: 281698943Sluigi case TOK_PIPE: 281798943Sluigi action->len = F_INSN_SIZE(ipfw_insn_pipe); 281898943Sluigi case TOK_SKIPTO: 281998943Sluigi if (i == TOK_QUEUE) 282098943Sluigi action->opcode = O_QUEUE; 282198943Sluigi else if (i == TOK_PIPE) 282298943Sluigi action->opcode = O_PIPE; 282398943Sluigi else if (i == TOK_SKIPTO) 282498943Sluigi action->opcode = O_SKIPTO; 282598943Sluigi NEED1("missing skipto/pipe/queue number"); 282698943Sluigi action->arg1 = strtoul(*av, NULL, 10); 282798943Sluigi av++; ac--; 282898943Sluigi break; 282998943Sluigi 283098943Sluigi case TOK_DIVERT: 283198943Sluigi case TOK_TEE: 283298943Sluigi action->opcode = (i == TOK_DIVERT) ? O_DIVERT : O_TEE; 283398943Sluigi NEED1("missing divert/tee port"); 283498943Sluigi action->arg1 = strtoul(*av, NULL, 0); 283598943Sluigi if (action->arg1 == 0) { 283698943Sluigi struct servent *s; 283798943Sluigi setservent(1); 283898943Sluigi s = getservbyname(av[0], "divert"); 283998943Sluigi if (s != NULL) 284098943Sluigi action->arg1 = ntohs(s->s_port); 284198943Sluigi else 284298943Sluigi errx(EX_DATAERR, "illegal divert/tee port"); 284398943Sluigi } 284498943Sluigi ac--; av++; 284598943Sluigi break; 284698943Sluigi 284798943Sluigi case TOK_FORWARD: { 284898943Sluigi ipfw_insn_sa *p = (ipfw_insn_sa *)action; 284998943Sluigi char *s, *end; 285098943Sluigi 285198943Sluigi NEED1("missing forward address[:port]"); 285298943Sluigi 285398943Sluigi action->opcode = O_FORWARD_IP; 285498943Sluigi action->len = F_INSN_SIZE(ipfw_insn_sa); 285598943Sluigi 285698943Sluigi p->sa.sin_len = sizeof(struct sockaddr_in); 285798943Sluigi p->sa.sin_family = AF_INET; 285898943Sluigi p->sa.sin_port = 0; 285998943Sluigi /* 286098943Sluigi * locate the address-port separator (':' or ',') 286198943Sluigi */ 286298943Sluigi s = strchr(*av, ':'); 286398943Sluigi if (s == NULL) 286498943Sluigi s = strchr(*av, ','); 286598943Sluigi if (s != NULL) { 286698943Sluigi *(s++) = '\0'; 286798943Sluigi i = strtoport(s, &end, 0 /* base */, 0 /* proto */); 286898943Sluigi if (s == end) 286998943Sluigi errx(EX_DATAERR, 287098943Sluigi "illegal forwarding port ``%s''", s); 2871103241Sluigi p->sa.sin_port = (u_short)i; 287298943Sluigi } 287398943Sluigi lookup_host(*av, &(p->sa.sin_addr)); 287498943Sluigi } 287598943Sluigi ac--; av++; 287698943Sluigi break; 287798943Sluigi 2878117469Sluigi case TOK_COMMENT: 2879117469Sluigi /* pretend it is a 'count' rule followed by the comment */ 2880117469Sluigi action->opcode = O_COUNT; 2881117469Sluigi ac++; av--; /* go back... */ 2882117469Sluigi break; 2883117469Sluigi 288498943Sluigi default: 2885102087Sluigi errx(EX_DATAERR, "invalid action %s\n", av[-1]); 288698943Sluigi } 288798943Sluigi action = next_cmd(action); 288898943Sluigi 288998943Sluigi /* 289098943Sluigi * [log [logamount N]] -- log, optional 289198943Sluigi * 289298943Sluigi * If exists, it goes first in the cmdbuf, but then it is 289398943Sluigi * skipped in the copy section to the end of the buffer. 289498943Sluigi */ 289598943Sluigi if (ac && !strncmp(*av, "log", strlen(*av))) { 289698943Sluigi ipfw_insn_log *c = (ipfw_insn_log *)cmd; 2897117469Sluigi int l; 289898943Sluigi 289998943Sluigi cmd->len = F_INSN_SIZE(ipfw_insn_log); 290098943Sluigi cmd->opcode = O_LOG; 290198943Sluigi av++; ac--; 290298943Sluigi if (ac && !strncmp(*av, "logamount", strlen(*av))) { 290398943Sluigi ac--; av++; 290498943Sluigi NEED1("logamount requires argument"); 2905117469Sluigi l = atoi(*av); 2906117469Sluigi if (l < 0) 290798943Sluigi errx(EX_DATAERR, "logamount must be positive"); 2908117469Sluigi c->max_log = l; 290998943Sluigi ac--; av++; 291098943Sluigi } 291198943Sluigi cmd = next_cmd(cmd); 291298943Sluigi } 291398943Sluigi 2914101116Sluigi if (have_state) /* must be a check-state, we are done */ 291598943Sluigi goto done; 291698943Sluigi 291798943Sluigi#define OR_START(target) \ 291898943Sluigi if (ac && (*av[0] == '(' || *av[0] == '{')) { \ 291998943Sluigi if (open_par) \ 292098943Sluigi errx(EX_USAGE, "nested \"(\" not allowed\n"); \ 2921101641Sluigi prev = NULL; \ 292298943Sluigi open_par = 1; \ 292398943Sluigi if ( (av[0])[1] == '\0') { \ 292498943Sluigi ac--; av++; \ 292598943Sluigi } else \ 292698943Sluigi (*av)++; \ 292798943Sluigi } \ 292898943Sluigi target: \ 292998943Sluigi 293098943Sluigi 293198943Sluigi#define CLOSE_PAR \ 293298943Sluigi if (open_par) { \ 293398943Sluigi if (ac && ( \ 293498943Sluigi !strncmp(*av, ")", strlen(*av)) || \ 293598943Sluigi !strncmp(*av, "}", strlen(*av)) )) { \ 2936101641Sluigi prev = NULL; \ 293798943Sluigi open_par = 0; \ 293898943Sluigi ac--; av++; \ 293998943Sluigi } else \ 294098943Sluigi errx(EX_USAGE, "missing \")\"\n"); \ 294198943Sluigi } 2942106505Smaxim 294398943Sluigi#define NOT_BLOCK \ 294498943Sluigi if (ac && !strncmp(*av, "not", strlen(*av))) { \ 294598943Sluigi if (cmd->len & F_NOT) \ 294698943Sluigi errx(EX_USAGE, "double \"not\" not allowed\n"); \ 294798943Sluigi cmd->len |= F_NOT; \ 294898943Sluigi ac--; av++; \ 294998943Sluigi } 295098943Sluigi 295198943Sluigi#define OR_BLOCK(target) \ 295298943Sluigi if (ac && !strncmp(*av, "or", strlen(*av))) { \ 295398943Sluigi if (prev == NULL || open_par == 0) \ 295498943Sluigi errx(EX_DATAERR, "invalid OR block"); \ 295598943Sluigi prev->len |= F_OR; \ 295698943Sluigi ac--; av++; \ 295798943Sluigi goto target; \ 295898943Sluigi } \ 295998943Sluigi CLOSE_PAR; 296098943Sluigi 2961102087Sluigi first_cmd = cmd; 2962102098Sluigi 2963102098Sluigi#if 0 296498943Sluigi /* 2965102087Sluigi * MAC addresses, optional. 2966102087Sluigi * If we have this, we skip the part "proto from src to dst" 2967102087Sluigi * and jump straight to the option parsing. 2968102087Sluigi */ 2969102087Sluigi NOT_BLOCK; 2970102087Sluigi NEED1("missing protocol"); 2971102087Sluigi if (!strncmp(*av, "MAC", strlen(*av)) || 2972102087Sluigi !strncmp(*av, "mac", strlen(*av))) { 2973102087Sluigi ac--; av++; /* the "MAC" keyword */ 2974102087Sluigi add_mac(cmd, ac, av); /* exits in case of errors */ 2975102087Sluigi cmd = next_cmd(cmd); 2976102087Sluigi ac -= 2; av += 2; /* dst-mac and src-mac */ 2977102087Sluigi NOT_BLOCK; 2978102087Sluigi NEED1("missing mac type"); 2979102087Sluigi if (add_mactype(cmd, ac, av[0])) 2980102087Sluigi cmd = next_cmd(cmd); 2981102087Sluigi ac--; av++; /* any or mac-type */ 2982102087Sluigi goto read_options; 2983102087Sluigi } 2984102098Sluigi#endif 2985102087Sluigi 2986102087Sluigi /* 298798943Sluigi * protocol, mandatory 298898943Sluigi */ 298998943Sluigi OR_START(get_proto); 299098943Sluigi NOT_BLOCK; 299198943Sluigi NEED1("missing protocol"); 2992102087Sluigi if (add_proto(cmd, *av)) { 2993102087Sluigi av++; ac--; 2994102087Sluigi if (F_LEN(cmd) == 0) /* plain IP */ 2995102087Sluigi proto = 0; 2996102087Sluigi else { 2997102087Sluigi proto = cmd->arg1; 2998102087Sluigi prev = cmd; 2999102087Sluigi cmd = next_cmd(cmd); 3000102087Sluigi } 3001102098Sluigi } else if (first_cmd != cmd) { 3002116438Smaxim errx(EX_DATAERR, "invalid protocol ``%s''", *av); 3003102098Sluigi } else 3004102098Sluigi goto read_options; 300598943Sluigi OR_BLOCK(get_proto); 300698943Sluigi 300798943Sluigi /* 3008102087Sluigi * "from", mandatory 300998943Sluigi */ 3010102087Sluigi if (!ac || strncmp(*av, "from", strlen(*av))) 301198943Sluigi errx(EX_USAGE, "missing ``from''"); 301298943Sluigi ac--; av++; 301398943Sluigi 301498943Sluigi /* 301598943Sluigi * source IP, mandatory 301698943Sluigi */ 301798943Sluigi OR_START(source_ip); 301898943Sluigi NOT_BLOCK; /* optional "not" */ 301998943Sluigi NEED1("missing source address"); 3020102087Sluigi if (add_srcip(cmd, *av)) { 3021102087Sluigi ac--; av++; 3022102087Sluigi if (F_LEN(cmd) != 0) { /* ! any */ 3023102087Sluigi prev = cmd; 3024102087Sluigi cmd = next_cmd(cmd); 3025102087Sluigi } 3026102087Sluigi } 302798943Sluigi OR_BLOCK(source_ip); 302898943Sluigi 302998943Sluigi /* 303098943Sluigi * source ports, optional 303198943Sluigi */ 303298943Sluigi NOT_BLOCK; /* optional "not" */ 3033101641Sluigi if (ac) { 3034102087Sluigi if (!strncmp(*av, "any", strlen(*av)) || 3035102087Sluigi add_ports(cmd, *av, proto, O_IP_SRCPORT)) { 3036102087Sluigi ac--; av++; 3037102087Sluigi if (F_LEN(cmd) != 0) 3038102087Sluigi cmd = next_cmd(cmd); 3039101641Sluigi } 304098943Sluigi } 304198943Sluigi 304298943Sluigi /* 3043102087Sluigi * "to", mandatory 304498943Sluigi */ 3045102087Sluigi if (!ac || strncmp(*av, "to", strlen(*av))) 304698943Sluigi errx(EX_USAGE, "missing ``to''"); 304798943Sluigi av++; ac--; 304898943Sluigi 304998943Sluigi /* 305098943Sluigi * destination, mandatory 305198943Sluigi */ 305298943Sluigi OR_START(dest_ip); 305398943Sluigi NOT_BLOCK; /* optional "not" */ 305498943Sluigi NEED1("missing dst address"); 3055102087Sluigi if (add_dstip(cmd, *av)) { 3056102087Sluigi ac--; av++; 3057102087Sluigi if (F_LEN(cmd) != 0) { /* ! any */ 3058102087Sluigi prev = cmd; 3059102087Sluigi cmd = next_cmd(cmd); 3060102087Sluigi } 3061102087Sluigi } 306298943Sluigi OR_BLOCK(dest_ip); 306398943Sluigi 306498943Sluigi /* 306598943Sluigi * dest. ports, optional 306698943Sluigi */ 306798943Sluigi NOT_BLOCK; /* optional "not" */ 3068101641Sluigi if (ac) { 3069102087Sluigi if (!strncmp(*av, "any", strlen(*av)) || 3070102087Sluigi add_ports(cmd, *av, proto, O_IP_DSTPORT)) { 3071102087Sluigi ac--; av++; 3072102087Sluigi if (F_LEN(cmd) != 0) 3073102087Sluigi cmd = next_cmd(cmd); 3074101641Sluigi } 307598943Sluigi } 307698943Sluigi 307798943Sluigiread_options: 3078102087Sluigi if (ac && first_cmd == cmd) { 3079102087Sluigi /* 3080102087Sluigi * nothing specified so far, store in the rule to ease 3081102087Sluigi * printout later. 3082102087Sluigi */ 3083102087Sluigi rule->_pad = 1; 3084102087Sluigi } 308598943Sluigi prev = NULL; 308698943Sluigi while (ac) { 3087101641Sluigi char *s; 3088101641Sluigi ipfw_insn_u32 *cmd32; /* alias for cmd */ 308998943Sluigi 3090101641Sluigi s = *av; 3091101641Sluigi cmd32 = (ipfw_insn_u32 *)cmd; 3092101641Sluigi 309398943Sluigi if (*s == '!') { /* alternate syntax for NOT */ 309498943Sluigi if (cmd->len & F_NOT) 309598943Sluigi errx(EX_USAGE, "double \"not\" not allowed\n"); 309698943Sluigi cmd->len = F_NOT; 309798943Sluigi s++; 309898943Sluigi } 309998943Sluigi i = match_token(rule_options, s); 310098943Sluigi ac--; av++; 310198943Sluigi switch(i) { 310298943Sluigi case TOK_NOT: 310398943Sluigi if (cmd->len & F_NOT) 310498943Sluigi errx(EX_USAGE, "double \"not\" not allowed\n"); 310598943Sluigi cmd->len = F_NOT; 310698943Sluigi break; 310798943Sluigi 310898943Sluigi case TOK_OR: 3109101641Sluigi if (open_par == 0 || prev == NULL) 311098943Sluigi errx(EX_USAGE, "invalid \"or\" block\n"); 311198943Sluigi prev->len |= F_OR; 311298943Sluigi break; 3113101641Sluigi 3114101641Sluigi case TOK_STARTBRACE: 3115101641Sluigi if (open_par) 3116101641Sluigi errx(EX_USAGE, "+nested \"(\" not allowed\n"); 3117101641Sluigi open_par = 1; 3118101641Sluigi break; 3119101641Sluigi 3120101641Sluigi case TOK_ENDBRACE: 3121101641Sluigi if (!open_par) 3122101641Sluigi errx(EX_USAGE, "+missing \")\"\n"); 3123101641Sluigi open_par = 0; 3124102087Sluigi prev = NULL; 3125101641Sluigi break; 3126101641Sluigi 312798943Sluigi case TOK_IN: 312898943Sluigi fill_cmd(cmd, O_IN, 0, 0); 312998943Sluigi break; 313098943Sluigi 313198943Sluigi case TOK_OUT: 313298943Sluigi cmd->len ^= F_NOT; /* toggle F_NOT */ 313398943Sluigi fill_cmd(cmd, O_IN, 0, 0); 313498943Sluigi break; 313598943Sluigi 313698943Sluigi case TOK_FRAG: 313798943Sluigi fill_cmd(cmd, O_FRAG, 0, 0); 313898943Sluigi break; 313998943Sluigi 314098943Sluigi case TOK_LAYER2: 314198943Sluigi fill_cmd(cmd, O_LAYER2, 0, 0); 314298943Sluigi break; 314398943Sluigi 314498943Sluigi case TOK_XMIT: 314598943Sluigi case TOK_RECV: 314698943Sluigi case TOK_VIA: 314798943Sluigi NEED1("recv, xmit, via require interface name" 314898943Sluigi " or address"); 314998943Sluigi fill_iface((ipfw_insn_if *)cmd, av[0]); 315098943Sluigi ac--; av++; 315198943Sluigi if (F_LEN(cmd) == 0) /* not a valid address */ 315298943Sluigi break; 315398943Sluigi if (i == TOK_XMIT) 315498943Sluigi cmd->opcode = O_XMIT; 315598943Sluigi else if (i == TOK_RECV) 315698943Sluigi cmd->opcode = O_RECV; 315798943Sluigi else if (i == TOK_VIA) 315898943Sluigi cmd->opcode = O_VIA; 315998943Sluigi break; 316098943Sluigi 316199475Sluigi case TOK_ICMPTYPES: 316299475Sluigi NEED1("icmptypes requires list of types"); 316399475Sluigi fill_icmptypes((ipfw_insn_u32 *)cmd, *av); 316499475Sluigi av++; ac--; 316599475Sluigi break; 316699475Sluigi 316798943Sluigi case TOK_IPTTL: 316898943Sluigi NEED1("ipttl requires TTL"); 3169116690Sluigi if (strpbrk(*av, "-,")) { 3170116690Sluigi if (!add_ports(cmd, *av, 0, O_IPTTL)) 3171116690Sluigi errx(EX_DATAERR, "invalid ipttl %s", *av); 3172116690Sluigi } else 3173116690Sluigi fill_cmd(cmd, O_IPTTL, 0, strtoul(*av, NULL, 0)); 317498943Sluigi ac--; av++; 317598943Sluigi break; 317698943Sluigi 317798943Sluigi case TOK_IPID: 3178116690Sluigi NEED1("ipid requires id"); 3179116690Sluigi if (strpbrk(*av, "-,")) { 3180116690Sluigi if (!add_ports(cmd, *av, 0, O_IPID)) 3181116690Sluigi errx(EX_DATAERR, "invalid ipid %s", *av); 3182116690Sluigi } else 3183116690Sluigi fill_cmd(cmd, O_IPID, 0, strtoul(*av, NULL, 0)); 318498943Sluigi ac--; av++; 318598943Sluigi break; 318698943Sluigi 318798943Sluigi case TOK_IPLEN: 318898943Sluigi NEED1("iplen requires length"); 3189116690Sluigi if (strpbrk(*av, "-,")) { 3190116690Sluigi if (!add_ports(cmd, *av, 0, O_IPLEN)) 3191116690Sluigi errx(EX_DATAERR, "invalid ip len %s", *av); 3192116690Sluigi } else 3193116690Sluigi fill_cmd(cmd, O_IPLEN, 0, strtoul(*av, NULL, 0)); 319498943Sluigi ac--; av++; 319598943Sluigi break; 319698943Sluigi 319798943Sluigi case TOK_IPVER: 319898943Sluigi NEED1("ipver requires version"); 319998943Sluigi fill_cmd(cmd, O_IPVER, 0, strtoul(*av, NULL, 0)); 320098943Sluigi ac--; av++; 320198943Sluigi break; 320298943Sluigi 320399475Sluigi case TOK_IPPRECEDENCE: 320499475Sluigi NEED1("ipprecedence requires value"); 320599475Sluigi fill_cmd(cmd, O_IPPRECEDENCE, 0, 320699475Sluigi (strtoul(*av, NULL, 0) & 7) << 5); 320799475Sluigi ac--; av++; 320899475Sluigi break; 320999475Sluigi 321098943Sluigi case TOK_IPOPTS: 321198943Sluigi NEED1("missing argument for ipoptions"); 3212101116Sluigi fill_flags(cmd, O_IPOPT, f_ipopts, *av); 321398943Sluigi ac--; av++; 321498943Sluigi break; 321598943Sluigi 321699475Sluigi case TOK_IPTOS: 321799475Sluigi NEED1("missing argument for iptos"); 3218101116Sluigi fill_flags(cmd, O_IPTOS, f_iptos, *av); 321999475Sluigi ac--; av++; 322099475Sluigi break; 322199475Sluigi 322298943Sluigi case TOK_UID: 322398943Sluigi NEED1("uid requires argument"); 322498943Sluigi { 322598943Sluigi char *end; 322698943Sluigi uid_t uid; 322798943Sluigi struct passwd *pwd; 322898943Sluigi 322998943Sluigi cmd->opcode = O_UID; 323098943Sluigi uid = strtoul(*av, &end, 0); 323198943Sluigi pwd = (*end == '\0') ? getpwuid(uid) : getpwnam(*av); 323298943Sluigi if (pwd == NULL) 323398943Sluigi errx(EX_DATAERR, "uid \"%s\" nonexistent", *av); 3234106504Smaxim cmd32->d[0] = pwd->pw_uid; 323598943Sluigi cmd->len = F_INSN_SIZE(ipfw_insn_u32); 323698943Sluigi ac--; av++; 323798943Sluigi } 323898943Sluigi break; 323998943Sluigi 324098943Sluigi case TOK_GID: 324198943Sluigi NEED1("gid requires argument"); 324298943Sluigi { 324398943Sluigi char *end; 324498943Sluigi gid_t gid; 324598943Sluigi struct group *grp; 324698943Sluigi 324798943Sluigi cmd->opcode = O_GID; 324898943Sluigi gid = strtoul(*av, &end, 0); 324998943Sluigi grp = (*end == '\0') ? getgrgid(gid) : getgrnam(*av); 325098943Sluigi if (grp == NULL) 325198943Sluigi errx(EX_DATAERR, "gid \"%s\" nonexistent", *av); 3252106504Smaxim cmd32->d[0] = grp->gr_gid; 325398943Sluigi cmd->len = F_INSN_SIZE(ipfw_insn_u32); 325498943Sluigi ac--; av++; 325598943Sluigi } 325698943Sluigi break; 325798943Sluigi 325898943Sluigi case TOK_ESTAB: 325998943Sluigi fill_cmd(cmd, O_ESTAB, 0, 0); 326098943Sluigi break; 326198943Sluigi 326298943Sluigi case TOK_SETUP: 326398943Sluigi fill_cmd(cmd, O_TCPFLAGS, 0, 326498943Sluigi (TH_SYN) | ( (TH_ACK) & 0xff) <<8 ); 326598943Sluigi break; 326698943Sluigi 326798943Sluigi case TOK_TCPOPTS: 326898943Sluigi NEED1("missing argument for tcpoptions"); 326998943Sluigi fill_flags(cmd, O_TCPOPTS, f_tcpopts, *av); 327098943Sluigi ac--; av++; 327198943Sluigi break; 327298943Sluigi 327398943Sluigi case TOK_TCPSEQ: 327498943Sluigi case TOK_TCPACK: 327598943Sluigi NEED1("tcpseq/tcpack requires argument"); 327698943Sluigi cmd->len = F_INSN_SIZE(ipfw_insn_u32); 327798943Sluigi cmd->opcode = (i == TOK_TCPSEQ) ? O_TCPSEQ : O_TCPACK; 327898943Sluigi cmd32->d[0] = htonl(strtoul(*av, NULL, 0)); 327998943Sluigi ac--; av++; 328098943Sluigi break; 328198943Sluigi 328298943Sluigi case TOK_TCPWIN: 328398943Sluigi NEED1("tcpwin requires length"); 328498943Sluigi fill_cmd(cmd, O_TCPWIN, 0, 328598943Sluigi htons(strtoul(*av, NULL, 0))); 328698943Sluigi ac--; av++; 328798943Sluigi break; 328898943Sluigi 328998943Sluigi case TOK_TCPFLAGS: 329098943Sluigi NEED1("missing argument for tcpflags"); 329198943Sluigi cmd->opcode = O_TCPFLAGS; 329298943Sluigi fill_flags(cmd, O_TCPFLAGS, f_tcpflags, *av); 329398943Sluigi ac--; av++; 329498943Sluigi break; 329598943Sluigi 329698943Sluigi case TOK_KEEPSTATE: 3297101641Sluigi if (open_par) 3298101641Sluigi errx(EX_USAGE, "keep-state cannot be part " 3299101641Sluigi "of an or block"); 330099909Sluigi if (have_state) 3301101116Sluigi errx(EX_USAGE, "only one of keep-state " 330299909Sluigi "and limit is allowed"); 3303101116Sluigi have_state = cmd; 330498943Sluigi fill_cmd(cmd, O_KEEP_STATE, 0, 0); 330598943Sluigi break; 330698943Sluigi 330798943Sluigi case TOK_LIMIT: 3308101641Sluigi if (open_par) 3309101641Sluigi errx(EX_USAGE, "limit cannot be part " 3310101641Sluigi "of an or block"); 331199909Sluigi if (have_state) 3312101116Sluigi errx(EX_USAGE, "only one of keep-state " 331399909Sluigi "and limit is allowed"); 3314101641Sluigi NEED1("limit needs mask and # of connections"); 3315101116Sluigi have_state = cmd; 331698943Sluigi { 331798943Sluigi ipfw_insn_limit *c = (ipfw_insn_limit *)cmd; 331898943Sluigi 331998943Sluigi cmd->len = F_INSN_SIZE(ipfw_insn_limit); 332098943Sluigi cmd->opcode = O_LIMIT; 332198943Sluigi c->limit_mask = 0; 332298943Sluigi c->conn_limit = 0; 332398943Sluigi for (; ac >1 ;) { 332498943Sluigi int val; 332598943Sluigi 332698943Sluigi val = match_token(limit_masks, *av); 332798943Sluigi if (val <= 0) 332898943Sluigi break; 332998943Sluigi c->limit_mask |= val; 333098943Sluigi ac--; av++; 333198943Sluigi } 333298943Sluigi c->conn_limit = atoi(*av); 333398943Sluigi if (c->conn_limit == 0) 333498943Sluigi errx(EX_USAGE, "limit: limit must be >0"); 333598943Sluigi if (c->limit_mask == 0) 333698943Sluigi errx(EX_USAGE, "missing limit mask"); 333798943Sluigi ac--; av++; 333898943Sluigi } 333998943Sluigi break; 334098943Sluigi 3341102087Sluigi case TOK_PROTO: 3342102087Sluigi NEED1("missing protocol"); 3343102087Sluigi if (add_proto(cmd, *av)) { 3344102087Sluigi proto = cmd->arg1; 3345102087Sluigi ac--; av++; 3346102098Sluigi } else 3347116438Smaxim errx(EX_DATAERR, "invalid protocol ``%s''", 3348116438Smaxim *av); 3349102087Sluigi break; 3350106505Smaxim 3351102087Sluigi case TOK_SRCIP: 3352102087Sluigi NEED1("missing source IP"); 3353102087Sluigi if (add_srcip(cmd, *av)) { 3354102087Sluigi ac--; av++; 3355102087Sluigi } 3356102087Sluigi break; 3357102087Sluigi 3358102087Sluigi case TOK_DSTIP: 3359102087Sluigi NEED1("missing destination IP"); 3360102087Sluigi if (add_dstip(cmd, *av)) { 3361102087Sluigi ac--; av++; 3362102087Sluigi } 3363102087Sluigi break; 3364102087Sluigi 3365102087Sluigi case TOK_SRCPORT: 3366102087Sluigi NEED1("missing source port"); 3367102087Sluigi if (!strncmp(*av, "any", strlen(*av)) || 3368102087Sluigi add_ports(cmd, *av, proto, O_IP_SRCPORT)) { 3369102087Sluigi ac--; av++; 3370102087Sluigi } else 3371102087Sluigi errx(EX_DATAERR, "invalid source port %s", *av); 3372102087Sluigi break; 3373102087Sluigi 3374102087Sluigi case TOK_DSTPORT: 3375102087Sluigi NEED1("missing destination port"); 3376102087Sluigi if (!strncmp(*av, "any", strlen(*av)) || 3377102087Sluigi add_ports(cmd, *av, proto, O_IP_DSTPORT)) { 3378102087Sluigi ac--; av++; 3379102087Sluigi } else 3380102087Sluigi errx(EX_DATAERR, "invalid destination port %s", 3381102087Sluigi *av); 3382102087Sluigi break; 3383102087Sluigi 3384102087Sluigi case TOK_MAC: 3385102087Sluigi if (ac < 2) 3386102087Sluigi errx(EX_USAGE, "MAC dst-mac src-mac"); 3387102087Sluigi if (add_mac(cmd, ac, av)) { 3388102087Sluigi ac -= 2; av += 2; 3389102087Sluigi } 3390102087Sluigi break; 3391102087Sluigi 3392102087Sluigi case TOK_MACTYPE: 3393102087Sluigi NEED1("missing mac type"); 3394102087Sluigi if (!add_mactype(cmd, ac, *av)) 3395116438Smaxim errx(EX_DATAERR, "invalid mac type %s", *av); 3396102087Sluigi ac--; av++; 3397102087Sluigi break; 3398102087Sluigi 3399112250Scjc case TOK_VERREVPATH: 3400112250Scjc fill_cmd(cmd, O_VERREVPATH, 0, 0); 3401112250Scjc break; 3402116919Sluigi 3403117241Sluigi case TOK_IPSEC: 3404117241Sluigi fill_cmd(cmd, O_IPSEC, 0, 0); 3405117241Sluigi break; 3406117241Sluigi 3407117469Sluigi case TOK_COMMENT: 3408117469Sluigi fill_comment(cmd, ac, av); 3409117469Sluigi av += ac; 3410117469Sluigi ac = 0; 3411117469Sluigi break; 3412117469Sluigi 341398943Sluigi default: 341498943Sluigi errx(EX_USAGE, "unrecognised option [%d] %s\n", i, s); 341598943Sluigi } 341698943Sluigi if (F_LEN(cmd) > 0) { /* prepare to advance */ 341798943Sluigi prev = cmd; 341898943Sluigi cmd = next_cmd(cmd); 341998943Sluigi } 342098943Sluigi } 342198943Sluigi 342298943Sluigidone: 342398943Sluigi /* 342498943Sluigi * Now copy stuff into the rule. 342598943Sluigi * If we have a keep-state option, the first instruction 342698943Sluigi * must be a PROBE_STATE (which is generated here). 342798943Sluigi * If we have a LOG option, it was stored as the first command, 342898943Sluigi * and now must be moved to the top of the action part. 342998943Sluigi */ 343098943Sluigi dst = (ipfw_insn *)rule->cmd; 343198943Sluigi 343298943Sluigi /* 3433107289Sluigi * First thing to write into the command stream is the match probability. 3434107289Sluigi */ 3435107289Sluigi if (match_prob != 1) { /* 1 means always match */ 3436107289Sluigi dst->opcode = O_PROB; 3437107289Sluigi dst->len = 2; 3438107289Sluigi *((int32_t *)(dst+1)) = (int32_t)(match_prob * 0x7fffffff); 3439107289Sluigi dst += dst->len; 3440107289Sluigi } 3441107289Sluigi 3442107289Sluigi /* 344398943Sluigi * generate O_PROBE_STATE if necessary 344498943Sluigi */ 3445101116Sluigi if (have_state && have_state->opcode != O_CHECK_STATE) { 344698943Sluigi fill_cmd(dst, O_PROBE_STATE, 0, 0); 344798943Sluigi dst = next_cmd(dst); 344898943Sluigi } 344998943Sluigi /* 3450101116Sluigi * copy all commands but O_LOG, O_KEEP_STATE, O_LIMIT 345198943Sluigi */ 345298943Sluigi for (src = (ipfw_insn *)cmdbuf; src != cmd; src += i) { 345398943Sluigi i = F_LEN(src); 345498943Sluigi 3455101116Sluigi switch (src->opcode) { 3456101116Sluigi case O_LOG: 3457101116Sluigi case O_KEEP_STATE: 3458101116Sluigi case O_LIMIT: 3459101116Sluigi break; 3460101116Sluigi default: 3461117328Sluigi bcopy(src, dst, i * sizeof(uint32_t)); 346298943Sluigi dst += i; 346398943Sluigi } 346498943Sluigi } 346598943Sluigi 346698943Sluigi /* 3467101116Sluigi * put back the have_state command as last opcode 3468101116Sluigi */ 3469101295Sluigi if (have_state && have_state->opcode != O_CHECK_STATE) { 3470101116Sluigi i = F_LEN(have_state); 3471117328Sluigi bcopy(have_state, dst, i * sizeof(uint32_t)); 3472101116Sluigi dst += i; 3473101116Sluigi } 3474101116Sluigi /* 347598943Sluigi * start action section 347698943Sluigi */ 347798943Sluigi rule->act_ofs = dst - rule->cmd; 347898943Sluigi 347998943Sluigi /* 348098943Sluigi * put back O_LOG if necessary 348198943Sluigi */ 348298943Sluigi src = (ipfw_insn *)cmdbuf; 3483117577Sluigi if (src->opcode == O_LOG) { 348498943Sluigi i = F_LEN(src); 3485117328Sluigi bcopy(src, dst, i * sizeof(uint32_t)); 348698943Sluigi dst += i; 348798943Sluigi } 348898943Sluigi /* 348998943Sluigi * copy all other actions 349098943Sluigi */ 349198943Sluigi for (src = (ipfw_insn *)actbuf; src != action; src += i) { 349298943Sluigi i = F_LEN(src); 3493117328Sluigi bcopy(src, dst, i * sizeof(uint32_t)); 349498943Sluigi dst += i; 349598943Sluigi } 349698943Sluigi 3497117328Sluigi rule->cmd_len = (uint32_t *)dst - (uint32_t *)(rule->cmd); 3498117469Sluigi i = (char *)dst - (char *)rule; 3499119740Stmm if (do_cmd(IP_FW_ADD, rule, (uintptr_t)&i) == -1) 350098943Sluigi err(EX_UNAVAILABLE, "getsockopt(%s)", "IP_FW_ADD"); 350198943Sluigi if (!do_quiet) 3502117469Sluigi show_ipfw(rule, 0, 0); 350398943Sluigi} 350498943Sluigi 350598943Sluigistatic void 3506117328Sluigizero(int ac, char *av[], int optname /* IP_FW_ZERO or IP_FW_RESETLOG */) 350798943Sluigi{ 350898943Sluigi int rulenum; 350998943Sluigi int failed = EX_OK; 3510117469Sluigi char const *name = optname == IP_FW_ZERO ? "ZERO" : "RESETLOG"; 351198943Sluigi 351298943Sluigi av++; ac--; 351398943Sluigi 351498943Sluigi if (!ac) { 351598943Sluigi /* clear all entries */ 3516117328Sluigi if (do_cmd(optname, NULL, 0) < 0) 3517117328Sluigi err(EX_UNAVAILABLE, "setsockopt(IP_FW_%s)", name); 351898943Sluigi if (!do_quiet) 3519117328Sluigi printf("%s.\n", optname == IP_FW_ZERO ? 3520117328Sluigi "Accounting cleared":"Logging counts reset"); 352198943Sluigi 352298943Sluigi return; 352398943Sluigi } 352498943Sluigi 352598943Sluigi while (ac) { 352698943Sluigi /* Rule number */ 352798943Sluigi if (isdigit(**av)) { 352898943Sluigi rulenum = atoi(*av); 352998943Sluigi av++; 353098943Sluigi ac--; 3531117328Sluigi if (do_cmd(optname, &rulenum, sizeof rulenum)) { 3532117328Sluigi warn("rule %u: setsockopt(IP_FW_%s)", 3533117328Sluigi rulenum, name); 353498943Sluigi failed = EX_UNAVAILABLE; 353598943Sluigi } else if (!do_quiet) 3536117328Sluigi printf("Entry %d %s.\n", rulenum, 3537117328Sluigi optname == IP_FW_ZERO ? 3538117328Sluigi "cleared" : "logging count reset"); 353998943Sluigi } else { 354098943Sluigi errx(EX_USAGE, "invalid rule number ``%s''", *av); 354198943Sluigi } 354298943Sluigi } 354398943Sluigi if (failed != EX_OK) 354498943Sluigi exit(failed); 354598943Sluigi} 354698943Sluigi 354798943Sluigistatic void 3548117544Sluigiflush(int force) 354998943Sluigi{ 355098943Sluigi int cmd = do_pipe ? IP_DUMMYNET_FLUSH : IP_FW_FLUSH; 355198943Sluigi 3552117544Sluigi if (!force && !do_quiet) { /* need to ask user */ 355398943Sluigi int c; 355498943Sluigi 355598943Sluigi printf("Are you sure? [yn] "); 355698943Sluigi fflush(stdout); 355798943Sluigi do { 355898943Sluigi c = toupper(getc(stdin)); 355998943Sluigi while (c != '\n' && getc(stdin) != '\n') 356098943Sluigi if (feof(stdin)) 356198943Sluigi return; /* and do not flush */ 356298943Sluigi } while (c != 'Y' && c != 'N'); 356398943Sluigi printf("\n"); 356498943Sluigi if (c == 'N') /* user said no */ 356598943Sluigi return; 356698943Sluigi } 3567117328Sluigi if (do_cmd(cmd, NULL, 0) < 0) 356898943Sluigi err(EX_UNAVAILABLE, "setsockopt(IP_%s_FLUSH)", 356998943Sluigi do_pipe ? "DUMMYNET" : "FW"); 357098943Sluigi if (!do_quiet) 357198943Sluigi printf("Flushed all %s.\n", do_pipe ? "pipes" : "rules"); 357298943Sluigi} 357398943Sluigi 3574117469Sluigi/* 3575117544Sluigi * Free a the (locally allocated) copy of command line arguments. 3576117469Sluigi */ 3577117544Sluigistatic void 3578117544Sluigifree_args(int ac, char **av) 3579117544Sluigi{ 3580117544Sluigi int i; 3581117544Sluigi 3582117544Sluigi for (i=0; i < ac; i++) 3583117544Sluigi free(av[i]); 3584117544Sluigi free(av); 3585117544Sluigi} 3586117544Sluigi 3587117544Sluigi/* 3588117544Sluigi * Called with the arguments (excluding program name). 3589117544Sluigi * Returns 0 if successful, 1 if empty command, errx() in case of errors. 3590117544Sluigi */ 359198943Sluigistatic int 3592117328Sluigiipfw_main(int oldac, char **oldav) 359398943Sluigi{ 3594117469Sluigi int ch, ac, save_ac; 3595117469Sluigi char **av, **save_av; 3596117469Sluigi int do_acct = 0; /* Show packet/byte count */ 3597117469Sluigi 3598117469Sluigi#define WHITESP " \t\f\v\n\r" 3599117544Sluigi if (oldac == 0) 3600117544Sluigi return 1; 3601117544Sluigi else if (oldac == 1) { 3602117328Sluigi /* 3603117328Sluigi * If we are called with a single string, try to split it into 3604117328Sluigi * arguments for subsequent parsing. 3605117328Sluigi * But first, remove spaces after a ',', by copying the string 3606117328Sluigi * in-place. 3607117328Sluigi */ 3608117469Sluigi char *arg = oldav[0]; /* The string... */ 3609117328Sluigi int l = strlen(arg); 3610117328Sluigi int copy = 0; /* 1 if we need to copy, 0 otherwise */ 3611117328Sluigi int i, j; 3612117469Sluigi for (i = j = 0; i < l; i++) { 3613117469Sluigi if (arg[i] == '#') /* comment marker */ 3614117469Sluigi break; 3615117328Sluigi if (copy) { 3616117328Sluigi arg[j++] = arg[i]; 3617117469Sluigi copy = !index("," WHITESP, arg[i]); 3618117328Sluigi } else { 3619117469Sluigi copy = !index(WHITESP, arg[i]); 3620117328Sluigi if (copy) 3621117328Sluigi arg[j++] = arg[i]; 3622117328Sluigi } 3623117469Sluigi } 3624117328Sluigi if (!copy && j > 0) /* last char was a 'blank', remove it */ 3625117328Sluigi j--; 3626117328Sluigi l = j; /* the new argument length */ 3627117328Sluigi arg[j++] = '\0'; 3628117469Sluigi if (l == 0) /* empty string! */ 3629117544Sluigi return 1; 3630117328Sluigi 3631117328Sluigi /* 3632117328Sluigi * First, count number of arguments. Because of the previous 3633117469Sluigi * processing, this is just the number of blanks plus 1. 3634117328Sluigi */ 3635117469Sluigi for (i = 0, ac = 1; i < l; i++) 3636117469Sluigi if (index(WHITESP, arg[i]) != NULL) 3637117328Sluigi ac++; 3638117328Sluigi 3639117328Sluigi av = calloc(ac, sizeof(char *)); 3640117328Sluigi 3641117328Sluigi /* 3642117328Sluigi * Second, copy arguments from cmd[] to av[]. For each one, 3643117328Sluigi * j is the initial character, i is the one past the end. 3644117328Sluigi */ 3645117469Sluigi for (ac = 0, i = j = 0; i < l; i++) 3646117469Sluigi if (index(WHITESP, arg[i]) != NULL || i == l-1) { 3647117328Sluigi if (i == l-1) 3648117328Sluigi i++; 3649117328Sluigi av[ac] = calloc(i-j+1, 1); 3650117328Sluigi bcopy(arg+j, av[ac], i-j); 3651117328Sluigi ac++; 3652117328Sluigi j = i + 1; 3653117328Sluigi } 3654117328Sluigi } else { 3655117328Sluigi /* 3656117328Sluigi * If an argument ends with ',' join with the next one. 3657117328Sluigi */ 3658117328Sluigi int first, i, l; 3659117328Sluigi 3660117328Sluigi av = calloc(oldac, sizeof(char *)); 3661117328Sluigi for (first = i = ac = 0, l = 0; i < oldac; i++) { 3662117328Sluigi char *arg = oldav[i]; 3663117328Sluigi int k = strlen(arg); 3664117328Sluigi 3665117328Sluigi l += k; 3666117328Sluigi if (arg[k-1] != ',' || i == oldac-1) { 3667117328Sluigi /* Time to copy. */ 3668117328Sluigi av[ac] = calloc(l+1, 1); 3669117328Sluigi for (l=0; first <= i; first++) { 3670117328Sluigi strcat(av[ac]+l, oldav[first]); 3671117328Sluigi l += strlen(oldav[first]); 3672117328Sluigi } 3673117328Sluigi ac++; 3674117328Sluigi l = 0; 3675117328Sluigi first = i+1; 3676117328Sluigi } 3677117328Sluigi } 3678117328Sluigi } 3679117328Sluigi 368098943Sluigi /* Set the force flag for non-interactive processes */ 3681123804Smaxim if (!do_force) 3682123804Smaxim do_force = !isatty(STDIN_FILENO); 368398943Sluigi 3684117469Sluigi /* Save arguments for final freeing of memory. */ 3685117469Sluigi save_ac = ac; 3686117469Sluigi save_av = av; 3687117469Sluigi 3688117469Sluigi optind = optreset = 0; 3689123495Sluigi while ((ch = getopt(ac, av, "abcdefhnNqs:STtv")) != -1) 369098943Sluigi switch (ch) { 369198943Sluigi case 'a': 369298943Sluigi do_acct = 1; 369398943Sluigi break; 3694117328Sluigi 3695123495Sluigi case 'b': 3696123495Sluigi comment_only = 1; 3697123495Sluigi do_compact = 1; 3698123495Sluigi break; 3699123495Sluigi 3700102098Sluigi case 'c': 3701102098Sluigi do_compact = 1; 3702102098Sluigi break; 3703117328Sluigi 370498943Sluigi case 'd': 370598943Sluigi do_dynamic = 1; 370698943Sluigi break; 3707117328Sluigi 370898943Sluigi case 'e': 370998943Sluigi do_expired = 1; 371098943Sluigi break; 3711117328Sluigi 371298943Sluigi case 'f': 371398943Sluigi do_force = 1; 371498943Sluigi break; 3715117328Sluigi 3716117328Sluigi case 'h': /* help */ 3717117544Sluigi free_args(save_ac, save_av); 3718117328Sluigi help(); 3719117328Sluigi break; /* NOTREACHED */ 3720117328Sluigi 3721117328Sluigi case 'n': 3722117328Sluigi test_only = 1; 3723117328Sluigi break; 3724117328Sluigi 372598943Sluigi case 'N': 372698943Sluigi do_resolv = 1; 372798943Sluigi break; 3728117328Sluigi 372998943Sluigi case 'q': 373098943Sluigi do_quiet = 1; 373198943Sluigi break; 3732117328Sluigi 3733117328Sluigi case 's': /* sort */ 3734117328Sluigi do_sort = atoi(optarg); 3735117328Sluigi break; 3736117328Sluigi 3737101628Sluigi case 'S': 3738101628Sluigi show_sets = 1; 3739101628Sluigi break; 3740117328Sluigi 374198943Sluigi case 't': 374298943Sluigi do_time = 1; 374398943Sluigi break; 3744117328Sluigi 3745117472Sluigi case 'T': 3746117472Sluigi do_time = 2; /* numeric timestamp */ 3747117472Sluigi break; 3748117472Sluigi 374998943Sluigi case 'v': /* verbose */ 3750117328Sluigi verbose = 1; 375198943Sluigi break; 3752117328Sluigi 375398943Sluigi default: 3754117544Sluigi free_args(save_ac, save_av); 3755117544Sluigi return 1; 375698943Sluigi } 375798943Sluigi 375898943Sluigi ac -= optind; 375998943Sluigi av += optind; 376098943Sluigi NEED1("bad arguments, for usage summary ``ipfw''"); 376198943Sluigi 376298943Sluigi /* 3763117544Sluigi * An undocumented behaviour of ipfw1 was to allow rule numbers first, 3764117544Sluigi * e.g. "100 add allow ..." instead of "add 100 allow ...". 3765117544Sluigi * In case, swap first and second argument to get the normal form. 3766117544Sluigi */ 3767117544Sluigi if (ac > 1 && isdigit(*av[0])) { 3768117544Sluigi char *p = av[0]; 3769117544Sluigi 3770117544Sluigi av[0] = av[1]; 3771117544Sluigi av[1] = p; 3772117544Sluigi } 3773117544Sluigi 3774117544Sluigi /* 377598943Sluigi * optional: pipe or queue 377698943Sluigi */ 3777117821Smaxim do_pipe = 0; 3778117544Sluigi if (!strncmp(*av, "pipe", strlen(*av))) 377998943Sluigi do_pipe = 1; 3780117544Sluigi else if (!strncmp(*av, "queue", strlen(*av))) 378198943Sluigi do_pipe = 2; 3782117544Sluigi if (do_pipe) { 378398943Sluigi ac--; 378498943Sluigi av++; 378598943Sluigi } 378698943Sluigi NEED1("missing command"); 378798943Sluigi 378898943Sluigi /* 3789117328Sluigi * For pipes and queues we normally say 'pipe NN config' 379098943Sluigi * but the code is easier to parse as 'pipe config NN' 379198943Sluigi * so we swap the two arguments. 379298943Sluigi */ 3793117469Sluigi if (do_pipe > 0 && ac > 1 && isdigit(*av[0])) { 379498943Sluigi char *p = av[0]; 3795117544Sluigi 379698943Sluigi av[0] = av[1]; 379798943Sluigi av[1] = p; 379898943Sluigi } 3799117328Sluigi 380098943Sluigi if (!strncmp(*av, "add", strlen(*av))) 380198943Sluigi add(ac, av); 380298943Sluigi else if (do_pipe && !strncmp(*av, "config", strlen(*av))) 380398943Sluigi config_pipe(ac, av); 3804101978Sluigi else if (!strncmp(*av, "delete", strlen(*av))) 380598943Sluigi delete(ac, av); 380698943Sluigi else if (!strncmp(*av, "flush", strlen(*av))) 3807117544Sluigi flush(do_force); 380898943Sluigi else if (!strncmp(*av, "zero", strlen(*av))) 3809117328Sluigi zero(ac, av, IP_FW_ZERO); 381098943Sluigi else if (!strncmp(*av, "resetlog", strlen(*av))) 3811117328Sluigi zero(ac, av, IP_FW_RESETLOG); 381298943Sluigi else if (!strncmp(*av, "print", strlen(*av)) || 381398943Sluigi !strncmp(*av, "list", strlen(*av))) 3814117469Sluigi list(ac, av, do_acct); 3815101978Sluigi else if (!strncmp(*av, "set", strlen(*av))) 3816101978Sluigi sets_handler(ac, av); 3817109126Sdillon else if (!strncmp(*av, "enable", strlen(*av))) 3818109126Sdillon sysctl_handler(ac, av, 1); 3819109126Sdillon else if (!strncmp(*av, "disable", strlen(*av))) 3820109126Sdillon sysctl_handler(ac, av, 0); 3821117469Sluigi else if (!strncmp(*av, "show", strlen(*av))) 3822117469Sluigi list(ac, av, 1 /* show counters */); 3823117469Sluigi else 382498943Sluigi errx(EX_USAGE, "bad command `%s'", *av); 3825117469Sluigi 3826117469Sluigi /* Free memory allocated in the argument parsing. */ 3827117544Sluigi free_args(save_ac, save_av); 382898943Sluigi return 0; 382998943Sluigi} 383098943Sluigi 383198943Sluigi 383298943Sluigistatic void 3833106505Smaximipfw_readfile(int ac, char *av[]) 383498943Sluigi{ 383598943Sluigi#define MAX_ARGS 32 383698943Sluigi char buf[BUFSIZ]; 3837117469Sluigi char *cmd = NULL, *filename = av[ac-1]; 3838117469Sluigi int c, lineno=0; 383998943Sluigi FILE *f = NULL; 384098943Sluigi pid_t preproc = 0; 384198943Sluigi 3842117469Sluigi filename = av[ac-1]; 3843117469Sluigi 3844123804Smaxim while ((c = getopt(ac, av, "cfNnp:qS")) != -1) { 384598943Sluigi switch(c) { 3846117469Sluigi case 'c': 3847117469Sluigi do_compact = 1; 3848117469Sluigi break; 3849117469Sluigi 3850123804Smaxim case 'f': 3851123804Smaxim do_force = 1; 3852123804Smaxim break; 3853123804Smaxim 3854117469Sluigi case 'N': 3855117469Sluigi do_resolv = 1; 3856117469Sluigi break; 3857117469Sluigi 3858117328Sluigi case 'n': 3859117328Sluigi test_only = 1; 3860117328Sluigi break; 3861117328Sluigi 386298943Sluigi case 'p': 386398943Sluigi cmd = optarg; 3864117469Sluigi /* 3865117469Sluigi * Skip previous args and delete last one, so we 3866117469Sluigi * pass all but the last argument to the preprocessor 3867117469Sluigi * via av[optind-1] 3868117469Sluigi */ 3869117469Sluigi av += optind - 1; 3870117469Sluigi ac -= optind - 1; 3871117469Sluigi av[ac-1] = NULL; 3872117469Sluigi fprintf(stderr, "command is %s\n", av[0]); 387398943Sluigi break; 387498943Sluigi 387598943Sluigi case 'q': 3876117469Sluigi do_quiet = 1; 387798943Sluigi break; 387898943Sluigi 3879117469Sluigi case 'S': 3880117469Sluigi show_sets = 1; 3881117469Sluigi break; 3882117469Sluigi 388398943Sluigi default: 388498943Sluigi errx(EX_USAGE, "bad arguments, for usage" 388598943Sluigi " summary ``ipfw''"); 388698943Sluigi } 388798943Sluigi 3888117469Sluigi if (cmd != NULL) 3889108231Skbyanc break; 3890108231Skbyanc } 3891108231Skbyanc 3892117469Sluigi if (cmd == NULL && ac != optind + 1) { 3893117469Sluigi fprintf(stderr, "ac %d, optind %d\n", ac, optind); 3894117469Sluigi errx(EX_USAGE, "extraneous filename arguments"); 3895108231Skbyanc } 3896108231Skbyanc 3897117469Sluigi if ((f = fopen(filename, "r")) == NULL) 3898117469Sluigi err(EX_UNAVAILABLE, "fopen: %s", filename); 389998943Sluigi 3900117469Sluigi if (cmd != NULL) { /* pipe through preprocessor */ 390198943Sluigi int pipedes[2]; 390298943Sluigi 390398943Sluigi if (pipe(pipedes) == -1) 390498943Sluigi err(EX_OSERR, "cannot create pipe"); 390598943Sluigi 3906117469Sluigi preproc = fork(); 3907117469Sluigi if (preproc == -1) 390898943Sluigi err(EX_OSERR, "cannot fork"); 390998943Sluigi 3910117577Sluigi if (preproc == 0) { 3911117469Sluigi /* 3912117469Sluigi * Child, will run the preprocessor with the 3913117469Sluigi * file on stdin and the pipe on stdout. 3914117469Sluigi */ 391598943Sluigi if (dup2(fileno(f), 0) == -1 391698943Sluigi || dup2(pipedes[1], 1) == -1) 391798943Sluigi err(EX_OSERR, "dup2()"); 391898943Sluigi fclose(f); 391998943Sluigi close(pipedes[1]); 392098943Sluigi close(pipedes[0]); 3921117469Sluigi execvp(cmd, av); 392298943Sluigi err(EX_OSERR, "execvp(%s) failed", cmd); 3923117469Sluigi } else { /* parent, will reopen f as the pipe */ 392498943Sluigi fclose(f); 392598943Sluigi close(pipedes[1]); 392698943Sluigi if ((f = fdopen(pipedes[0], "r")) == NULL) { 392798943Sluigi int savederrno = errno; 392898943Sluigi 392998943Sluigi (void)kill(preproc, SIGTERM); 393098943Sluigi errno = savederrno; 393198943Sluigi err(EX_OSERR, "fdopen()"); 393298943Sluigi } 393398943Sluigi } 393498943Sluigi } 393598943Sluigi 3936117469Sluigi while (fgets(buf, BUFSIZ, f)) { /* read commands */ 3937117469Sluigi char linename[10]; 3938117469Sluigi char *args[1]; 3939117469Sluigi 394098943Sluigi lineno++; 394198943Sluigi sprintf(linename, "Line %d", lineno); 3942117328Sluigi setprogname(linename); /* XXX */ 3943117469Sluigi args[0] = buf; 3944117469Sluigi ipfw_main(1, args); 394598943Sluigi } 394698943Sluigi fclose(f); 3947117469Sluigi if (cmd != NULL) { 3948117469Sluigi int status; 3949117469Sluigi 395098943Sluigi if (waitpid(preproc, &status, 0) == -1) 395198943Sluigi errx(EX_OSERR, "waitpid()"); 395298943Sluigi if (WIFEXITED(status) && WEXITSTATUS(status) != EX_OK) 395398943Sluigi errx(EX_UNAVAILABLE, 395498943Sluigi "preprocessor exited with status %d", 395598943Sluigi WEXITSTATUS(status)); 395698943Sluigi else if (WIFSIGNALED(status)) 395798943Sluigi errx(EX_UNAVAILABLE, 395898943Sluigi "preprocessor exited with signal %d", 395998943Sluigi WTERMSIG(status)); 396098943Sluigi } 396198943Sluigi} 396298943Sluigi 396398943Sluigiint 396498943Sluigimain(int ac, char *av[]) 396598943Sluigi{ 396698943Sluigi /* 396798943Sluigi * If the last argument is an absolute pathname, interpret it 396898943Sluigi * as a file to be preprocessed. 396998943Sluigi */ 397098943Sluigi 397198943Sluigi if (ac > 1 && av[ac - 1][0] == '/' && access(av[ac - 1], R_OK) == 0) 397298943Sluigi ipfw_readfile(ac, av); 3973117544Sluigi else { 3974117544Sluigi if (ipfw_main(ac-1, av+1)) 3975117544Sluigi show_usage(); 3976117544Sluigi } 397798943Sluigi return EX_OK; 397898943Sluigi} 3979