ipfw2.c revision 117328
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 117328 2003-07-08 07:52:47Z luigi $ 2198943Sluigi */ 2298943Sluigi 2398943Sluigi#include <sys/param.h> 2498943Sluigi#include <sys/mbuf.h> 2598943Sluigi#include <sys/socket.h> 2698943Sluigi#include <sys/sockio.h> 2798943Sluigi#include <sys/sysctl.h> 2898943Sluigi#include <sys/time.h> 2998943Sluigi#include <sys/wait.h> 3098943Sluigi 3198943Sluigi#include <ctype.h> 3298943Sluigi#include <err.h> 3398943Sluigi#include <errno.h> 3498943Sluigi#include <grp.h> 3598943Sluigi#include <limits.h> 3698943Sluigi#include <netdb.h> 3798943Sluigi#include <pwd.h> 3898943Sluigi#include <signal.h> 3998943Sluigi#include <stdio.h> 4098943Sluigi#include <stdlib.h> 4198943Sluigi#include <stdarg.h> 4298943Sluigi#include <string.h> 4399603Sbde#include <timeconv.h> 4498943Sluigi#include <unistd.h> 4598943Sluigi#include <sysexits.h> 4698943Sluigi 4798943Sluigi#include <net/if.h> 4898943Sluigi#include <netinet/in.h> 4998943Sluigi#include <netinet/in_systm.h> 5098943Sluigi#include <netinet/ip.h> 5198943Sluigi#include <netinet/ip_icmp.h> 5298943Sluigi#include <netinet/ip_fw.h> 5398943Sluigi#include <net/route.h> /* def. of struct route */ 5498943Sluigi#include <netinet/ip_dummynet.h> 5598943Sluigi#include <netinet/tcp.h> 5698943Sluigi#include <arpa/inet.h> 5798943Sluigi 58117328Sluigiint 5998943Sluigi do_resolv, /* Would try to resolve all */ 6098943Sluigi do_acct, /* Show packet/byte count */ 6198943Sluigi do_time, /* Show time stamps */ 6298943Sluigi do_quiet, /* Be quiet in add and flush */ 6398943Sluigi do_force, /* Don't ask for confirmation */ 6498943Sluigi do_pipe, /* this cmd refers to a pipe */ 6598943Sluigi do_sort, /* field to sort results (0 = no) */ 6698943Sluigi do_dynamic, /* display dynamic rules */ 6798943Sluigi do_expired, /* display expired dynamic rules */ 68102098Sluigi do_compact, /* show rules in compact mode */ 69101628Sluigi show_sets, /* display rule sets */ 70117328Sluigi test_only, /* only check syntax */ 7198943Sluigi verbose; 7298943Sluigi 7398943Sluigi#define IP_MASK_ALL 0xffffffff 7498943Sluigi 7598943Sluigi/* 76117328Sluigi * _s_x is a structure that stores a string <-> token pairs, used in 77117328Sluigi * various places in the parser. Entries are stored in arrays, 78117328Sluigi * with an entry with s=NULL as terminator. 79117328Sluigi * The search routines are match_token() and match_value(). 80117328Sluigi * Often, an element with x=0 contains an error string. 8198943Sluigi * 8298943Sluigi */ 8398943Sluigistruct _s_x { 8498943Sluigi char *s; 8598943Sluigi int x; 8698943Sluigi}; 8798943Sluigi 8898943Sluigistatic struct _s_x f_tcpflags[] = { 8998943Sluigi { "syn", TH_SYN }, 9098943Sluigi { "fin", TH_FIN }, 9198943Sluigi { "ack", TH_ACK }, 9298943Sluigi { "psh", TH_PUSH }, 9398943Sluigi { "rst", TH_RST }, 9498943Sluigi { "urg", TH_URG }, 9598943Sluigi { "tcp flag", 0 }, 9698943Sluigi { NULL, 0 } 9798943Sluigi}; 9898943Sluigi 9998943Sluigistatic struct _s_x f_tcpopts[] = { 10098943Sluigi { "mss", IP_FW_TCPOPT_MSS }, 10198943Sluigi { "maxseg", IP_FW_TCPOPT_MSS }, 10298943Sluigi { "window", IP_FW_TCPOPT_WINDOW }, 10398943Sluigi { "sack", IP_FW_TCPOPT_SACK }, 10498943Sluigi { "ts", IP_FW_TCPOPT_TS }, 10598943Sluigi { "timestamp", IP_FW_TCPOPT_TS }, 10698943Sluigi { "cc", IP_FW_TCPOPT_CC }, 10798943Sluigi { "tcp option", 0 }, 10898943Sluigi { NULL, 0 } 10998943Sluigi}; 11098943Sluigi 11198943Sluigi/* 11298943Sluigi * IP options span the range 0 to 255 so we need to remap them 11398943Sluigi * (though in fact only the low 5 bits are significant). 11498943Sluigi */ 11598943Sluigistatic struct _s_x f_ipopts[] = { 11698943Sluigi { "ssrr", IP_FW_IPOPT_SSRR}, 11798943Sluigi { "lsrr", IP_FW_IPOPT_LSRR}, 11898943Sluigi { "rr", IP_FW_IPOPT_RR}, 11998943Sluigi { "ts", IP_FW_IPOPT_TS}, 12098943Sluigi { "ip option", 0 }, 12198943Sluigi { NULL, 0 } 12298943Sluigi}; 12398943Sluigi 12498943Sluigistatic struct _s_x f_iptos[] = { 12598943Sluigi { "lowdelay", IPTOS_LOWDELAY}, 12698943Sluigi { "throughput", IPTOS_THROUGHPUT}, 12798943Sluigi { "reliability", IPTOS_RELIABILITY}, 12898943Sluigi { "mincost", IPTOS_MINCOST}, 12998943Sluigi { "congestion", IPTOS_CE}, 13098943Sluigi { "ecntransport", IPTOS_ECT}, 13198943Sluigi { "ip tos option", 0}, 13298943Sluigi { NULL, 0 } 13398943Sluigi}; 13498943Sluigi 13598943Sluigistatic struct _s_x limit_masks[] = { 13698943Sluigi {"all", DYN_SRC_ADDR|DYN_SRC_PORT|DYN_DST_ADDR|DYN_DST_PORT}, 13798943Sluigi {"src-addr", DYN_SRC_ADDR}, 13898943Sluigi {"src-port", DYN_SRC_PORT}, 13998943Sluigi {"dst-addr", DYN_DST_ADDR}, 14098943Sluigi {"dst-port", DYN_DST_PORT}, 14198943Sluigi {NULL, 0} 14298943Sluigi}; 14398943Sluigi 14498943Sluigi/* 14598943Sluigi * we use IPPROTO_ETHERTYPE as a fake protocol id to call the print routines 14698943Sluigi * This is only used in this code. 14798943Sluigi */ 14898943Sluigi#define IPPROTO_ETHERTYPE 0x1000 14998943Sluigistatic struct _s_x ether_types[] = { 15098943Sluigi /* 15198943Sluigi * Note, we cannot use "-:&/" in the names because they are field 15298943Sluigi * separators in the type specifications. Also, we use s = NULL as 15398943Sluigi * end-delimiter, because a type of 0 can be legal. 15498943Sluigi */ 15598943Sluigi { "ip", 0x0800 }, 15698943Sluigi { "ipv4", 0x0800 }, 15798943Sluigi { "ipv6", 0x86dd }, 15898943Sluigi { "arp", 0x0806 }, 15998943Sluigi { "rarp", 0x8035 }, 16098943Sluigi { "vlan", 0x8100 }, 16198943Sluigi { "loop", 0x9000 }, 16298943Sluigi { "trail", 0x1000 }, 16398943Sluigi { "at", 0x809b }, 16498943Sluigi { "atalk", 0x809b }, 16598943Sluigi { "aarp", 0x80f3 }, 16698943Sluigi { "pppoe_disc", 0x8863 }, 16798943Sluigi { "pppoe_sess", 0x8864 }, 16898943Sluigi { "ipx_8022", 0x00E0 }, 16998943Sluigi { "ipx_8023", 0x0000 }, 17098943Sluigi { "ipx_ii", 0x8137 }, 17198943Sluigi { "ipx_snap", 0x8137 }, 17298943Sluigi { "ipx", 0x8137 }, 17398943Sluigi { "ns", 0x0600 }, 17498943Sluigi { NULL, 0 } 17598943Sluigi}; 17698943Sluigi 17798943Sluigistatic void show_usage(void); 17898943Sluigi 17998943Sluigienum tokens { 18098943Sluigi TOK_NULL=0, 18198943Sluigi 18298943Sluigi TOK_OR, 18398943Sluigi TOK_NOT, 184101641Sluigi TOK_STARTBRACE, 185101641Sluigi TOK_ENDBRACE, 18698943Sluigi 18798943Sluigi TOK_ACCEPT, 18898943Sluigi TOK_COUNT, 18998943Sluigi TOK_PIPE, 19098943Sluigi TOK_QUEUE, 19198943Sluigi TOK_DIVERT, 19298943Sluigi TOK_TEE, 19398943Sluigi TOK_FORWARD, 19498943Sluigi TOK_SKIPTO, 19598943Sluigi TOK_DENY, 19698943Sluigi TOK_REJECT, 19798943Sluigi TOK_RESET, 19898943Sluigi TOK_UNREACH, 19998943Sluigi TOK_CHECKSTATE, 20098943Sluigi 20198943Sluigi TOK_UID, 20298943Sluigi TOK_GID, 20398943Sluigi TOK_IN, 20498943Sluigi TOK_LIMIT, 20598943Sluigi TOK_KEEPSTATE, 20698943Sluigi TOK_LAYER2, 20798943Sluigi TOK_OUT, 20898943Sluigi TOK_XMIT, 20998943Sluigi TOK_RECV, 21098943Sluigi TOK_VIA, 21198943Sluigi TOK_FRAG, 21298943Sluigi TOK_IPOPTS, 21398943Sluigi TOK_IPLEN, 21498943Sluigi TOK_IPID, 21598943Sluigi TOK_IPPRECEDENCE, 21698943Sluigi TOK_IPTOS, 21798943Sluigi TOK_IPTTL, 21898943Sluigi TOK_IPVER, 21998943Sluigi TOK_ESTAB, 22098943Sluigi TOK_SETUP, 22198943Sluigi TOK_TCPFLAGS, 22298943Sluigi TOK_TCPOPTS, 22398943Sluigi TOK_TCPSEQ, 22498943Sluigi TOK_TCPACK, 22598943Sluigi TOK_TCPWIN, 22698943Sluigi TOK_ICMPTYPES, 227102087Sluigi TOK_MAC, 228102087Sluigi TOK_MACTYPE, 229112250Scjc TOK_VERREVPATH, 230117241Sluigi TOK_IPSEC, 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 }, 293117328Sluigi { NULL, 0 } /* terminator */ 29498943Sluigi}; 29598943Sluigi 29698943Sluigistruct _s_x rule_options[] = { 29798943Sluigi { "uid", TOK_UID }, 29898943Sluigi { "gid", TOK_GID }, 29998943Sluigi { "in", TOK_IN }, 30098943Sluigi { "limit", TOK_LIMIT }, 30198943Sluigi { "keep-state", TOK_KEEPSTATE }, 30298943Sluigi { "bridged", TOK_LAYER2 }, 30398943Sluigi { "layer2", TOK_LAYER2 }, 30498943Sluigi { "out", TOK_OUT }, 30598943Sluigi { "xmit", TOK_XMIT }, 30698943Sluigi { "recv", TOK_RECV }, 30798943Sluigi { "via", TOK_VIA }, 30898943Sluigi { "fragment", TOK_FRAG }, 30998943Sluigi { "frag", TOK_FRAG }, 31098943Sluigi { "ipoptions", TOK_IPOPTS }, 31198943Sluigi { "ipopts", TOK_IPOPTS }, 31298943Sluigi { "iplen", TOK_IPLEN }, 31398943Sluigi { "ipid", TOK_IPID }, 31498943Sluigi { "ipprecedence", TOK_IPPRECEDENCE }, 31598943Sluigi { "iptos", TOK_IPTOS }, 31698943Sluigi { "ipttl", TOK_IPTTL }, 31798943Sluigi { "ipversion", TOK_IPVER }, 31898943Sluigi { "ipver", TOK_IPVER }, 31998943Sluigi { "estab", TOK_ESTAB }, 32098943Sluigi { "established", TOK_ESTAB }, 32198943Sluigi { "setup", TOK_SETUP }, 32298943Sluigi { "tcpflags", TOK_TCPFLAGS }, 32398943Sluigi { "tcpflgs", TOK_TCPFLAGS }, 32498943Sluigi { "tcpoptions", TOK_TCPOPTS }, 32598943Sluigi { "tcpopts", TOK_TCPOPTS }, 32698943Sluigi { "tcpseq", TOK_TCPSEQ }, 32798943Sluigi { "tcpack", TOK_TCPACK }, 32898943Sluigi { "tcpwin", TOK_TCPWIN }, 32999909Sluigi { "icmptype", TOK_ICMPTYPES }, 33098943Sluigi { "icmptypes", TOK_ICMPTYPES }, 331102087Sluigi { "dst-ip", TOK_DSTIP }, 332102087Sluigi { "src-ip", TOK_SRCIP }, 333102087Sluigi { "dst-port", TOK_DSTPORT }, 334102087Sluigi { "src-port", TOK_SRCPORT }, 335102087Sluigi { "proto", TOK_PROTO }, 336102087Sluigi { "MAC", TOK_MAC }, 337102087Sluigi { "mac", TOK_MAC }, 338102087Sluigi { "mac-type", TOK_MACTYPE }, 339112250Scjc { "verrevpath", TOK_VERREVPATH }, 340117241Sluigi { "ipsec", TOK_IPSEC }, 34198943Sluigi 34298943Sluigi { "not", TOK_NOT }, /* pseudo option */ 34398943Sluigi { "!", /* escape ? */ TOK_NOT }, /* pseudo option */ 34498943Sluigi { "or", TOK_OR }, /* pseudo option */ 34598943Sluigi { "|", /* escape */ TOK_OR }, /* pseudo option */ 346101641Sluigi { "{", TOK_STARTBRACE }, /* pseudo option */ 347101641Sluigi { "(", TOK_STARTBRACE }, /* pseudo option */ 348101641Sluigi { "}", TOK_ENDBRACE }, /* pseudo option */ 349101641Sluigi { ")", TOK_ENDBRACE }, /* pseudo option */ 350117328Sluigi { NULL, 0 } /* terminator */ 35198943Sluigi}; 35298943Sluigi 353117328Sluigistatic __inline uint64_t 354117328Sluigialign_uint64(uint64_t *pll) { 355117328Sluigi uint64_t ret; 356115793Sticso 357115793Sticso bcopy (pll, &ret, sizeof(ret)); 358115793Sticso return ret; 359115793Sticso}; 360115793Sticso 361117328Sluigi/* 362117328Sluigi * conditionally runs the command. 363117328Sluigi */ 364117328Sluigiint 365117328Sluigido_cmd(int optname, void *optval, socklen_t optlen) 366117328Sluigi{ 367117328Sluigi static int s = -1; /* the socket */ 368117328Sluigi int i; 369117328Sluigi 370117328Sluigi if (test_only) 371117328Sluigi return 0; 372117328Sluigi 373117328Sluigi if (s == -1) 374117328Sluigi s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); 375117328Sluigi if (s < 0) 376117328Sluigi err(EX_UNAVAILABLE, "socket"); 377117328Sluigi 378117328Sluigi if (optname == IP_FW_GET || optname == IP_DUMMYNET_GET || 379117328Sluigi optname == IP_FW_ADD) 380117328Sluigi i = getsockopt(s, IPPROTO_IP, optname, optval, 381117328Sluigi (socklen_t *)optlen); 382117328Sluigi else 383117328Sluigi i = setsockopt(s, IPPROTO_IP, optname, optval, optlen); 384117328Sluigi return i; 385117328Sluigi} 386117328Sluigi 38798943Sluigi/** 38898943Sluigi * match_token takes a table and a string, returns the value associated 389117328Sluigi * with the string (-1 in case of failure). 39098943Sluigi */ 39198943Sluigistatic int 39298943Sluigimatch_token(struct _s_x *table, char *string) 39398943Sluigi{ 39498943Sluigi struct _s_x *pt; 39598943Sluigi int i = strlen(string); 39698943Sluigi 39798943Sluigi for (pt = table ; i && pt->s != NULL ; pt++) 39898943Sluigi if (strlen(pt->s) == i && !bcmp(string, pt->s, i)) 39998943Sluigi return pt->x; 40098943Sluigi return -1; 40198943Sluigi}; 40298943Sluigi 403117328Sluigi/** 404117328Sluigi * match_value takes a table and a value, returns the string associated 405117328Sluigi * with the value (NULL in case of failure). 406117328Sluigi */ 40798943Sluigistatic char * 408117328Sluigimatch_value(struct _s_x *p, uint32_t value) 40998943Sluigi{ 41098943Sluigi for (; p->s != NULL; p++) 41198943Sluigi if (p->x == value) 41298943Sluigi return p->s; 41398943Sluigi return NULL; 41498943Sluigi} 41598943Sluigi 41698943Sluigi/* 41798943Sluigi * prints one port, symbolic or numeric 41898943Sluigi */ 41998943Sluigistatic void 420117328Sluigiprint_port(int proto, uint16_t port) 42198943Sluigi{ 42298943Sluigi 42398943Sluigi if (proto == IPPROTO_ETHERTYPE) { 42498943Sluigi char *s; 42598943Sluigi 42698943Sluigi if (do_resolv && (s = match_value(ether_types, port)) ) 42798943Sluigi printf("%s", s); 42898943Sluigi else 42998943Sluigi printf("0x%04x", port); 43098943Sluigi } else { 43198943Sluigi struct servent *se = NULL; 43298943Sluigi if (do_resolv) { 43398943Sluigi struct protoent *pe = getprotobynumber(proto); 43498943Sluigi 43598943Sluigi se = getservbyport(htons(port), pe ? pe->p_name : NULL); 43698943Sluigi } 43798943Sluigi if (se) 43898943Sluigi printf("%s", se->s_name); 43998943Sluigi else 44098943Sluigi printf("%d", port); 44198943Sluigi } 44298943Sluigi} 44398943Sluigi 444117328Sluigistruct _s_x _port_name[] = { 445117328Sluigi {"dst-port", O_IP_DSTPORT}, 446117328Sluigi {"src-port", O_IP_SRCPORT}, 447117328Sluigi {"ipid", O_IPID}, 448117328Sluigi {"iplen", O_IPLEN}, 449117328Sluigi {"ipttl", O_IPTTL}, 450117328Sluigi {"mac-type", O_MAC_TYPE}, 451117328Sluigi {NULL, 0} 452117328Sluigi}; 453117328Sluigi 45498943Sluigi/* 455117328Sluigi * Print the values in a list 16-bit items of the types above. 45698943Sluigi * XXX todo: add support for mask. 45798943Sluigi */ 45898943Sluigistatic void 459102087Sluigiprint_newports(ipfw_insn_u16 *cmd, int proto, int opcode) 46098943Sluigi{ 461117328Sluigi uint16_t *p = cmd->ports; 46298943Sluigi int i; 463116690Sluigi char *sep; 46498943Sluigi 46598943Sluigi if (cmd->o.len & F_NOT) 46698943Sluigi printf(" not"); 467116690Sluigi if (opcode != 0) { 468117328Sluigi sep = match_value(_port_name, opcode); 469117328Sluigi if (sep == NULL) 470116690Sluigi sep = "???"; 471116690Sluigi printf (" %s", sep); 472116690Sluigi } 473116690Sluigi sep = " "; 47498943Sluigi for (i = F_LEN((ipfw_insn *)cmd) - 1; i > 0; i--, p += 2) { 47598943Sluigi printf(sep); 47698943Sluigi print_port(proto, p[0]); 47798943Sluigi if (p[0] != p[1]) { 47898943Sluigi printf("-"); 47998943Sluigi print_port(proto, p[1]); 48098943Sluigi } 48198943Sluigi sep = ","; 48298943Sluigi } 48398943Sluigi} 48498943Sluigi 48598943Sluigi/* 48698943Sluigi * Like strtol, but also translates service names into port numbers 48798943Sluigi * for some protocols. 48898943Sluigi * In particular: 48998943Sluigi * proto == -1 disables the protocol check; 49098943Sluigi * proto == IPPROTO_ETHERTYPE looks up an internal table 49198943Sluigi * proto == <some value in /etc/protocols> matches the values there. 492101628Sluigi * Returns *end == s in case the parameter is not found. 49398943Sluigi */ 49498943Sluigistatic int 49598943Sluigistrtoport(char *s, char **end, int base, int proto) 49698943Sluigi{ 497101628Sluigi char *p, *buf; 498101628Sluigi char *s1; 49998943Sluigi int i; 50098943Sluigi 501101628Sluigi *end = s; /* default - not found */ 50298943Sluigi if ( *s == '\0') 503101628Sluigi return 0; /* not found */ 504106505Smaxim 50598943Sluigi if (isdigit(*s)) 50698943Sluigi return strtol(s, end, base); 50798943Sluigi 50898943Sluigi /* 509101628Sluigi * find separator. '\\' escapes the next char. 51098943Sluigi */ 511101628Sluigi for (s1 = s; *s1 && (isalnum(*s1) || *s1 == '\\') ; s1++) 512101628Sluigi if (*s1 == '\\' && s1[1] != '\0') 513101628Sluigi s1++; 51498943Sluigi 515101628Sluigi buf = malloc(s1 - s + 1); 516101628Sluigi if (buf == NULL) 517101628Sluigi return 0; 518101628Sluigi 519101628Sluigi /* 520101628Sluigi * copy into a buffer skipping backslashes 521101628Sluigi */ 522101628Sluigi for (p = s, i = 0; p != s1 ; p++) 523101628Sluigi if ( *p != '\\') 524101628Sluigi buf[i++] = *p; 525101628Sluigi buf[i++] = '\0'; 526101628Sluigi 52798943Sluigi if (proto == IPPROTO_ETHERTYPE) { 528101628Sluigi i = match_token(ether_types, buf); 529101628Sluigi free(buf); 530101628Sluigi if (i != -1) { /* found */ 53198943Sluigi *end = s1; 53298943Sluigi return i; 53398943Sluigi } 53498943Sluigi } else { 53598943Sluigi struct protoent *pe = NULL; 53698943Sluigi struct servent *se; 53798943Sluigi 53898943Sluigi if (proto != 0) 53998943Sluigi pe = getprotobynumber(proto); 54098943Sluigi setservent(1); 541101628Sluigi se = getservbyname(buf, pe ? pe->p_name : NULL); 542101628Sluigi free(buf); 54398943Sluigi if (se != NULL) { 54498943Sluigi *end = s1; 54598943Sluigi return ntohs(se->s_port); 54698943Sluigi } 54798943Sluigi } 548101628Sluigi return 0; /* not found */ 54998943Sluigi} 55098943Sluigi 55198943Sluigi/* 552117328Sluigi * Fill the body of the command with the list of port ranges. 55398943Sluigi */ 55498943Sluigistatic int 55598943Sluigifill_newports(ipfw_insn_u16 *cmd, char *av, int proto) 55698943Sluigi{ 557117328Sluigi uint16_t a, b, *p = cmd->ports; 55898943Sluigi int i = 0; 559102087Sluigi char *s = av; 56098943Sluigi 561102087Sluigi while (*s) { 56298943Sluigi a = strtoport(av, &s, 0, proto); 56398943Sluigi if (s == av) /* no parameter */ 56498943Sluigi break; 56598943Sluigi if (*s == '-') { /* a range */ 56698943Sluigi av = s+1; 56798943Sluigi b = strtoport(av, &s, 0, proto); 56898943Sluigi if (s == av) /* no parameter */ 56998943Sluigi break; 57098943Sluigi p[0] = a; 57198943Sluigi p[1] = b; 572117328Sluigi } else if (*s == ',' || *s == '\0' ) 57398943Sluigi p[0] = p[1] = a; 574117328Sluigi else /* invalid separator */ 575101978Sluigi errx(EX_DATAERR, "invalid separator <%c> in <%s>\n", 576101978Sluigi *s, av); 577102087Sluigi i++; 578102087Sluigi p += 2; 57998943Sluigi av = s+1; 58098943Sluigi } 58198943Sluigi if (i > 0) { 58298943Sluigi if (i+1 > F_LEN_MASK) 583102087Sluigi errx(EX_DATAERR, "too many ports/ranges\n"); 58498943Sluigi cmd->o.len |= i+1; /* leave F_NOT and F_OR untouched */ 58598943Sluigi } 58698943Sluigi return i; 58798943Sluigi} 58898943Sluigi 58998943Sluigistatic struct _s_x icmpcodes[] = { 59098943Sluigi { "net", ICMP_UNREACH_NET }, 59198943Sluigi { "host", ICMP_UNREACH_HOST }, 59298943Sluigi { "protocol", ICMP_UNREACH_PROTOCOL }, 59398943Sluigi { "port", ICMP_UNREACH_PORT }, 59498943Sluigi { "needfrag", ICMP_UNREACH_NEEDFRAG }, 59598943Sluigi { "srcfail", ICMP_UNREACH_SRCFAIL }, 59698943Sluigi { "net-unknown", ICMP_UNREACH_NET_UNKNOWN }, 59798943Sluigi { "host-unknown", ICMP_UNREACH_HOST_UNKNOWN }, 59898943Sluigi { "isolated", ICMP_UNREACH_ISOLATED }, 59998943Sluigi { "net-prohib", ICMP_UNREACH_NET_PROHIB }, 60098943Sluigi { "host-prohib", ICMP_UNREACH_HOST_PROHIB }, 60198943Sluigi { "tosnet", ICMP_UNREACH_TOSNET }, 60298943Sluigi { "toshost", ICMP_UNREACH_TOSHOST }, 60398943Sluigi { "filter-prohib", ICMP_UNREACH_FILTER_PROHIB }, 60498943Sluigi { "host-precedence", ICMP_UNREACH_HOST_PRECEDENCE }, 60598943Sluigi { "precedence-cutoff", ICMP_UNREACH_PRECEDENCE_CUTOFF }, 60698943Sluigi { NULL, 0 } 60798943Sluigi}; 60898943Sluigi 60998943Sluigistatic void 61098943Sluigifill_reject_code(u_short *codep, char *str) 61198943Sluigi{ 61298943Sluigi int val; 61398943Sluigi char *s; 61498943Sluigi 61598943Sluigi val = strtoul(str, &s, 0); 61698943Sluigi if (s == str || *s != '\0' || val >= 0x100) 61798943Sluigi val = match_token(icmpcodes, str); 618102087Sluigi if (val < 0) 61998943Sluigi errx(EX_DATAERR, "unknown ICMP unreachable code ``%s''", str); 62098943Sluigi *codep = val; 62198943Sluigi return; 62298943Sluigi} 62398943Sluigi 62498943Sluigistatic void 625117328Sluigiprint_reject_code(uint16_t code) 62698943Sluigi{ 62798943Sluigi char *s = match_value(icmpcodes, code); 62898943Sluigi 62998943Sluigi if (s != NULL) 63099475Sluigi printf("unreach %s", s); 63198943Sluigi else 63299475Sluigi printf("unreach %u", code); 63398943Sluigi} 63498943Sluigi 63598943Sluigi/* 63698943Sluigi * Returns the number of bits set (from left) in a contiguous bitmask, 63798943Sluigi * or -1 if the mask is not contiguous. 63898943Sluigi * XXX this needs a proper fix. 63998943Sluigi * This effectively works on masks in big-endian (network) format. 64098943Sluigi * when compiled on little endian architectures. 64198943Sluigi * 64298943Sluigi * First bit is bit 7 of the first byte -- note, for MAC addresses, 64398943Sluigi * the first bit on the wire is bit 0 of the first byte. 64498943Sluigi * len is the max length in bits. 64598943Sluigi */ 64698943Sluigistatic int 64798943Sluigicontigmask(u_char *p, int len) 64898943Sluigi{ 64998943Sluigi int i, n; 65098943Sluigi for (i=0; i<len ; i++) 65198943Sluigi if ( (p[i/8] & (1 << (7 - (i%8)))) == 0) /* first bit unset */ 65298943Sluigi break; 65398943Sluigi for (n=i+1; n < len; n++) 65498943Sluigi if ( (p[n/8] & (1 << (7 - (n%8)))) != 0) 65598943Sluigi return -1; /* mask not contiguous */ 65698943Sluigi return i; 65798943Sluigi} 65898943Sluigi 65998943Sluigi/* 66098943Sluigi * print flags set/clear in the two bitmasks passed as parameters. 66198943Sluigi * There is a specialized check for f_tcpflags. 66298943Sluigi */ 66398943Sluigistatic void 66498943Sluigiprint_flags(char *name, ipfw_insn *cmd, struct _s_x *list) 66598943Sluigi{ 66698943Sluigi char *comma=""; 66798943Sluigi int i; 66898943Sluigi u_char set = cmd->arg1 & 0xff; 66998943Sluigi u_char clear = (cmd->arg1 >> 8) & 0xff; 67098943Sluigi 67198943Sluigi if (list == f_tcpflags && set == TH_SYN && clear == TH_ACK) { 67298943Sluigi printf(" setup"); 67398943Sluigi return; 67498943Sluigi } 67598943Sluigi 67698943Sluigi printf(" %s ", name); 67798943Sluigi for (i=0; list[i].x != 0; i++) { 67898943Sluigi if (set & list[i].x) { 67998943Sluigi set &= ~list[i].x; 68098943Sluigi printf("%s%s", comma, list[i].s); 68198943Sluigi comma = ","; 68298943Sluigi } 68398943Sluigi if (clear & list[i].x) { 68498943Sluigi clear &= ~list[i].x; 68598943Sluigi printf("%s!%s", comma, list[i].s); 68698943Sluigi comma = ","; 68798943Sluigi } 68898943Sluigi } 68998943Sluigi} 69098943Sluigi 69198943Sluigi/* 69298943Sluigi * Print the ip address contained in a command. 69398943Sluigi */ 69498943Sluigistatic void 695102087Sluigiprint_ip(ipfw_insn_ip *cmd, char *s) 69698943Sluigi{ 69798943Sluigi struct hostent *he = NULL; 698117328Sluigi int len = F_LEN((ipfw_insn *)cmd); 699117328Sluigi uint32_t *a = ((ipfw_insn_u32 *)cmd)->d; 70098943Sluigi 701102087Sluigi printf("%s%s ", cmd->o.len & F_NOT ? " not": "", s); 70298943Sluigi 70398943Sluigi if (cmd->o.opcode == O_IP_SRC_ME || cmd->o.opcode == O_IP_DST_ME) { 70498943Sluigi printf("me"); 70598943Sluigi return; 70698943Sluigi } 70798943Sluigi if (cmd->o.opcode == O_IP_SRC_SET || cmd->o.opcode == O_IP_DST_SET) { 708117328Sluigi uint32_t x, *map = (uint32_t *)&(cmd->mask); 709116716Sluigi int i, j; 71098943Sluigi char comma = '{'; 71198943Sluigi 71298943Sluigi x = cmd->o.arg1 - 1; 71398943Sluigi x = htonl( ~x ); 71498943Sluigi cmd->addr.s_addr = htonl(cmd->addr.s_addr); 71598943Sluigi printf("%s/%d", inet_ntoa(cmd->addr), 71698943Sluigi contigmask((u_char *)&x, 32)); 71798943Sluigi x = cmd->addr.s_addr = htonl(cmd->addr.s_addr); 71898943Sluigi x &= 0xff; /* base */ 719116716Sluigi /* 720116716Sluigi * Print bits and ranges. 721116716Sluigi * Locate first bit set (i), then locate first bit unset (j). 722116716Sluigi * If we have 3+ consecutive bits set, then print them as a 723116716Sluigi * range, otherwise only print the initial bit and rescan. 724116716Sluigi */ 72598943Sluigi for (i=0; i < cmd->o.arg1; i++) 726117328Sluigi if (map[i/32] & (1<<(i & 31))) { 727116716Sluigi for (j=i+1; j < cmd->o.arg1; j++) 728117328Sluigi if (!(map[ j/32] & (1<<(j & 31)))) 729116716Sluigi break; 73098943Sluigi printf("%c%d", comma, i+x); 731116716Sluigi if (j>i+2) { /* range has at least 3 elements */ 732116716Sluigi printf("-%d", j-1+x); 733116716Sluigi i = j-1; 734116716Sluigi } 73598943Sluigi comma = ','; 73698943Sluigi } 73798943Sluigi printf("}"); 73898943Sluigi return; 73998943Sluigi } 740117328Sluigi /* 741117328Sluigi * len == 2 indicates a single IP, whereas lists of 1 or more 742117328Sluigi * addr/mask pairs have len = (2n+1). We convert len to n so we 743117328Sluigi * use that to count the number of entries. 744117328Sluigi */ 745117328Sluigi for (len = len / 2; len > 0; len--, a += 2) { 746117328Sluigi int mb = /* mask length */ 747117328Sluigi (cmd->o.opcode == O_IP_SRC || cmd->o.opcode == O_IP_DST) ? 748117328Sluigi 32 : contigmask((u_char *)&(a[1]), 32); 74998943Sluigi if (mb == 32 && do_resolv) 750117328Sluigi he = gethostbyaddr((char *)&(a[0]), sizeof(u_long), AF_INET); 75198943Sluigi if (he != NULL) /* resolved to name */ 75298943Sluigi printf("%s", he->h_name); 75398943Sluigi else if (mb == 0) /* any */ 75498943Sluigi printf("any"); 75598943Sluigi else { /* numeric IP followed by some kind of mask */ 756117328Sluigi printf("%s", inet_ntoa( *((struct in_addr *)&a[0]) ) ); 75798943Sluigi if (mb < 0) 758117328Sluigi printf(":%s", inet_ntoa( *((struct in_addr *)&a[1]) ) ); 75998943Sluigi else if (mb < 32) 76098943Sluigi printf("/%d", mb); 76198943Sluigi } 762117328Sluigi if (len > 1) 763117328Sluigi printf(","); 764117328Sluigi } 765117328Sluigi 76698943Sluigi} 76798943Sluigi 76898943Sluigi/* 76998943Sluigi * prints a MAC address/mask pair 77098943Sluigi */ 77198943Sluigistatic void 77298943Sluigiprint_mac(u_char *addr, u_char *mask) 77398943Sluigi{ 77498943Sluigi int l = contigmask(mask, 48); 77598943Sluigi 77698943Sluigi if (l == 0) 77798943Sluigi printf(" any"); 77898943Sluigi else { 77998943Sluigi printf(" %02x:%02x:%02x:%02x:%02x:%02x", 78098943Sluigi addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); 78198943Sluigi if (l == -1) 78298943Sluigi printf("&%02x:%02x:%02x:%02x:%02x:%02x", 78398943Sluigi mask[0], mask[1], mask[2], 78498943Sluigi mask[3], mask[4], mask[5]); 78598943Sluigi else if (l < 48) 78698943Sluigi printf("/%d", l); 78798943Sluigi } 78898943Sluigi} 78998943Sluigi 79099475Sluigistatic void 79199475Sluigifill_icmptypes(ipfw_insn_u32 *cmd, char *av) 79299475Sluigi{ 793117328Sluigi uint8_t type; 79498943Sluigi 79599475Sluigi cmd->d[0] = 0; 79699475Sluigi while (*av) { 79799475Sluigi if (*av == ',') 79899475Sluigi av++; 79999475Sluigi 80099475Sluigi type = strtoul(av, &av, 0); 80199475Sluigi 80299475Sluigi if (*av != ',' && *av != '\0') 80399475Sluigi errx(EX_DATAERR, "invalid ICMP type"); 80499475Sluigi 80599475Sluigi if (type > 31) 80699475Sluigi errx(EX_DATAERR, "ICMP type out of range"); 80799475Sluigi 80899475Sluigi cmd->d[0] |= 1 << type; 80999475Sluigi } 81099475Sluigi cmd->o.opcode = O_ICMPTYPE; 81199475Sluigi cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32); 81299475Sluigi} 81399475Sluigi 81499475Sluigistatic void 81599475Sluigiprint_icmptypes(ipfw_insn_u32 *cmd) 81699475Sluigi{ 81799475Sluigi int i; 81899475Sluigi char sep= ' '; 81999475Sluigi 82099475Sluigi printf(" icmptypes"); 82199475Sluigi for (i = 0; i < 32; i++) { 82299475Sluigi if ( (cmd->d[0] & (1 << (i))) == 0) 82399475Sluigi continue; 82499475Sluigi printf("%c%d", sep, i); 82599475Sluigi sep = ','; 82699475Sluigi } 82799475Sluigi} 82899475Sluigi 82998943Sluigi/* 83098943Sluigi * show_ipfw() prints the body of an ipfw rule. 83198943Sluigi * Because the standard rule has at least proto src_ip dst_ip, we use 83298943Sluigi * a helper function to produce these entries if not provided explicitly. 833102087Sluigi * The first argument is the list of fields we have, the second is 834102087Sluigi * the list of fields we want to be printed. 835101978Sluigi * 836102087Sluigi * Special cases if we have provided a MAC header: 837102087Sluigi * + if the rule does not contain IP addresses/ports, do not print them; 838102087Sluigi * + if the rule does not contain an IP proto, print "all" instead of "ip"; 839102087Sluigi * 840102087Sluigi * Once we have 'have_options', IP header fields are printed as options. 84198943Sluigi */ 842101978Sluigi#define HAVE_PROTO 0x0001 843101978Sluigi#define HAVE_SRCIP 0x0002 844101978Sluigi#define HAVE_DSTIP 0x0004 845101978Sluigi#define HAVE_MAC 0x0008 846101978Sluigi#define HAVE_MACTYPE 0x0010 847102087Sluigi#define HAVE_OPTIONS 0x8000 84898943Sluigi 849101978Sluigi#define HAVE_IP (HAVE_PROTO | HAVE_SRCIP | HAVE_DSTIP) 85098943Sluigistatic void 851102087Sluigishow_prerequisites(int *flags, int want, int cmd) 85298943Sluigi{ 853102087Sluigi if ( (*flags & HAVE_IP) == HAVE_IP) 854102087Sluigi *flags |= HAVE_OPTIONS; 855102087Sluigi 856102087Sluigi if ( (*flags & (HAVE_MAC|HAVE_MACTYPE|HAVE_OPTIONS)) == HAVE_MAC && 857102087Sluigi cmd != O_MAC_TYPE) { 858102087Sluigi /* 859102087Sluigi * mac-type was optimized out by the compiler, 860102087Sluigi * restore it 861102087Sluigi */ 862102087Sluigi printf(" any"); 863102087Sluigi *flags |= HAVE_MACTYPE | HAVE_OPTIONS; 864102087Sluigi return; 865101978Sluigi } 866102087Sluigi if ( !(*flags & HAVE_OPTIONS)) { 867102087Sluigi if ( !(*flags & HAVE_PROTO) && (want & HAVE_PROTO)) 868102087Sluigi printf(" ip"); 869102087Sluigi if ( !(*flags & HAVE_SRCIP) && (want & HAVE_SRCIP)) 870102087Sluigi printf(" from any"); 871102087Sluigi if ( !(*flags & HAVE_DSTIP) && (want & HAVE_DSTIP)) 872102087Sluigi printf(" to any"); 873102087Sluigi } 87498943Sluigi *flags |= want; 87598943Sluigi} 87698943Sluigi 87798943Sluigistatic void 878112189Smaximshow_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth) 87998943Sluigi{ 880107291Skeramida static int twidth = 0; 88198943Sluigi int l; 88298943Sluigi ipfw_insn *cmd; 88398943Sluigi int proto = 0; /* default */ 88498943Sluigi int flags = 0; /* prerequisites */ 88598943Sluigi ipfw_insn_log *logptr = NULL; /* set if we find an O_LOG */ 88698943Sluigi int or_block = 0; /* we are in an or block */ 887117328Sluigi uint32_t set_disable; 88898943Sluigi 889115793Sticso bcopy(&rule->next_rule, &set_disable, sizeof(set_disable)); 890101628Sluigi 891101628Sluigi if (set_disable & (1 << rule->set)) { /* disabled */ 892101628Sluigi if (!show_sets) 893101628Sluigi return; 894101628Sluigi else 895101628Sluigi printf("# DISABLED "); 896101628Sluigi } 89798943Sluigi printf("%05u ", rule->rulenum); 89898943Sluigi 89998943Sluigi if (do_acct) 900115793Sticso printf("%*llu %*llu ", pcwidth, align_uint64(&rule->pcnt), 901115793Sticso bcwidth, align_uint64(&rule->bcnt)); 90298943Sluigi 90398943Sluigi if (do_time) { 904107291Skeramida char timestr[30]; 905107291Skeramida time_t t = (time_t)0; 906107291Skeramida 907107291Skeramida if (twidth == 0) { 908107291Skeramida strcpy(timestr, ctime(&t)); 909107291Skeramida *strchr(timestr, '\n') = '\0'; 910107291Skeramida twidth = strlen(timestr); 911107291Skeramida } 91298943Sluigi if (rule->timestamp) { 913107291Skeramida t = _long_to_time(rule->timestamp); 91498943Sluigi 91598943Sluigi strcpy(timestr, ctime(&t)); 91698943Sluigi *strchr(timestr, '\n') = '\0'; 91798943Sluigi printf("%s ", timestr); 91898943Sluigi } else { 919107291Skeramida printf("%*s", twidth, " "); 92098943Sluigi } 92198943Sluigi } 92298943Sluigi 923101628Sluigi if (show_sets) 924101628Sluigi printf("set %d ", rule->set); 925101628Sluigi 92698943Sluigi /* 927107289Sluigi * print the optional "match probability" 928107289Sluigi */ 929107289Sluigi if (rule->cmd_len > 0) { 930107289Sluigi cmd = rule->cmd ; 931107289Sluigi if (cmd->opcode == O_PROB) { 932107289Sluigi ipfw_insn_u32 *p = (ipfw_insn_u32 *)cmd; 933107289Sluigi double d = 1.0 * p->d[0]; 934107289Sluigi 935107289Sluigi d = (d / 0x7fffffff); 936107289Sluigi printf("prob %f ", d); 937107289Sluigi } 938107289Sluigi } 939107289Sluigi 940107289Sluigi /* 94198943Sluigi * first print actions 94298943Sluigi */ 94398943Sluigi for (l = rule->cmd_len - rule->act_ofs, cmd = ACTION_PTR(rule); 94498943Sluigi l > 0 ; l -= F_LEN(cmd), cmd += F_LEN(cmd)) { 94598943Sluigi switch(cmd->opcode) { 94698943Sluigi case O_CHECK_STATE: 94798943Sluigi printf("check-state"); 948102087Sluigi flags = HAVE_IP; /* avoid printing anything else */ 94998943Sluigi break; 95098943Sluigi 95198943Sluigi case O_ACCEPT: 95298943Sluigi printf("allow"); 95398943Sluigi break; 95498943Sluigi 95598943Sluigi case O_COUNT: 95698943Sluigi printf("count"); 95798943Sluigi break; 95898943Sluigi 95998943Sluigi case O_DENY: 96098943Sluigi printf("deny"); 96198943Sluigi break; 96298943Sluigi 96399475Sluigi case O_REJECT: 96499475Sluigi if (cmd->arg1 == ICMP_REJECT_RST) 96599475Sluigi printf("reset"); 96699475Sluigi else if (cmd->arg1 == ICMP_UNREACH_HOST) 96799475Sluigi printf("reject"); 96899475Sluigi else 96999475Sluigi print_reject_code(cmd->arg1); 97099475Sluigi break; 97199475Sluigi 97298943Sluigi case O_SKIPTO: 97398943Sluigi printf("skipto %u", cmd->arg1); 97498943Sluigi break; 97598943Sluigi 97698943Sluigi case O_PIPE: 97798943Sluigi printf("pipe %u", cmd->arg1); 97898943Sluigi break; 97998943Sluigi 98098943Sluigi case O_QUEUE: 98198943Sluigi printf("queue %u", cmd->arg1); 98298943Sluigi break; 98398943Sluigi 98498943Sluigi case O_DIVERT: 98598943Sluigi printf("divert %u", cmd->arg1); 98698943Sluigi break; 98798943Sluigi 98898943Sluigi case O_TEE: 98998943Sluigi printf("tee %u", cmd->arg1); 99098943Sluigi break; 99198943Sluigi 99298943Sluigi case O_FORWARD_IP: 99398943Sluigi { 99498943Sluigi ipfw_insn_sa *s = (ipfw_insn_sa *)cmd; 99598943Sluigi 99698943Sluigi printf("fwd %s", inet_ntoa(s->sa.sin_addr)); 99798943Sluigi if (s->sa.sin_port) 998103241Sluigi printf(",%d", s->sa.sin_port); 99998943Sluigi } 100098943Sluigi break; 100198943Sluigi 100298943Sluigi case O_LOG: /* O_LOG is printed last */ 100398943Sluigi logptr = (ipfw_insn_log *)cmd; 100498943Sluigi break; 100598943Sluigi 100698943Sluigi default: 100798943Sluigi printf("** unrecognized action %d len %d", 100898943Sluigi cmd->opcode, cmd->len); 100998943Sluigi } 101098943Sluigi } 101198943Sluigi if (logptr) { 101298943Sluigi if (logptr->max_log > 0) 101399909Sluigi printf(" log logamount %d", logptr->max_log); 101498943Sluigi else 101599909Sluigi printf(" log"); 101698943Sluigi } 1017102087Sluigi 101898943Sluigi /* 1019102087Sluigi * then print the body. 102098943Sluigi */ 1021102087Sluigi if (rule->_pad & 1) { /* empty rules before options */ 1022102098Sluigi if (!do_compact) 1023102098Sluigi printf(" ip from any to any"); 1024102087Sluigi flags |= HAVE_IP | HAVE_OPTIONS; 1025102087Sluigi } 1026102087Sluigi 102798943Sluigi for (l = rule->act_ofs, cmd = rule->cmd ; 102898943Sluigi l > 0 ; l -= F_LEN(cmd) , cmd += F_LEN(cmd)) { 102999475Sluigi /* useful alias */ 103099475Sluigi ipfw_insn_u32 *cmd32 = (ipfw_insn_u32 *)cmd; 103198943Sluigi 1032102087Sluigi show_prerequisites(&flags, 0, cmd->opcode); 1033102087Sluigi 103498943Sluigi switch(cmd->opcode) { 1035107289Sluigi case O_PROB: 1036107289Sluigi break; /* done already */ 1037107289Sluigi 103898943Sluigi case O_PROBE_STATE: 103998943Sluigi break; /* no need to print anything here */ 104098943Sluigi 104198943Sluigi case O_MACADDR2: { 104298943Sluigi ipfw_insn_mac *m = (ipfw_insn_mac *)cmd; 1043102087Sluigi 1044102087Sluigi if ((cmd->len & F_OR) && !or_block) 1045102087Sluigi printf(" {"); 104698943Sluigi if (cmd->len & F_NOT) 104798943Sluigi printf(" not"); 1048102087Sluigi printf(" MAC"); 1049102087Sluigi flags |= HAVE_MAC; 105098943Sluigi print_mac( m->addr, m->mask); 105198943Sluigi print_mac( m->addr + 6, m->mask + 6); 105298943Sluigi } 105398943Sluigi break; 105498943Sluigi 105598943Sluigi case O_MAC_TYPE: 1056102087Sluigi if ((cmd->len & F_OR) && !or_block) 1057102087Sluigi printf(" {"); 1058102087Sluigi print_newports((ipfw_insn_u16 *)cmd, IPPROTO_ETHERTYPE, 1059102087Sluigi (flags & HAVE_OPTIONS) ? cmd->opcode : 0); 1060102087Sluigi flags |= HAVE_MAC | HAVE_MACTYPE | HAVE_OPTIONS; 106198943Sluigi break; 106298943Sluigi 106398943Sluigi case O_IP_SRC: 106498943Sluigi case O_IP_SRC_MASK: 106598943Sluigi case O_IP_SRC_ME: 106698943Sluigi case O_IP_SRC_SET: 1067102087Sluigi show_prerequisites(&flags, HAVE_PROTO, 0); 106898943Sluigi if (!(flags & HAVE_SRCIP)) 106998943Sluigi printf(" from"); 107098943Sluigi if ((cmd->len & F_OR) && !or_block) 107198943Sluigi printf(" {"); 1072102087Sluigi print_ip((ipfw_insn_ip *)cmd, 1073102087Sluigi (flags & HAVE_OPTIONS) ? " src-ip" : ""); 107498943Sluigi flags |= HAVE_SRCIP; 107598943Sluigi break; 107698943Sluigi 107798943Sluigi case O_IP_DST: 107898943Sluigi case O_IP_DST_MASK: 107998943Sluigi case O_IP_DST_ME: 108098943Sluigi case O_IP_DST_SET: 1081102087Sluigi show_prerequisites(&flags, HAVE_PROTO|HAVE_SRCIP, 0); 108298943Sluigi if (!(flags & HAVE_DSTIP)) 108398943Sluigi printf(" to"); 108498943Sluigi if ((cmd->len & F_OR) && !or_block) 108598943Sluigi printf(" {"); 1086102087Sluigi print_ip((ipfw_insn_ip *)cmd, 1087102087Sluigi (flags & HAVE_OPTIONS) ? " dst-ip" : ""); 108898943Sluigi flags |= HAVE_DSTIP; 108998943Sluigi break; 109098943Sluigi 109198943Sluigi case O_IP_DSTPORT: 1092102087Sluigi show_prerequisites(&flags, HAVE_IP, 0); 109398943Sluigi case O_IP_SRCPORT: 1094102087Sluigi show_prerequisites(&flags, HAVE_PROTO|HAVE_SRCIP, 0); 1095101641Sluigi if ((cmd->len & F_OR) && !or_block) 1096101641Sluigi printf(" {"); 1097102087Sluigi print_newports((ipfw_insn_u16 *)cmd, proto, 1098102087Sluigi (flags & HAVE_OPTIONS) ? cmd->opcode : 0); 109998943Sluigi break; 110098943Sluigi 110198943Sluigi case O_PROTO: { 110298943Sluigi struct protoent *pe; 110398943Sluigi 110498943Sluigi if ((cmd->len & F_OR) && !or_block) 110598943Sluigi printf(" {"); 110698943Sluigi if (cmd->len & F_NOT) 110798943Sluigi printf(" not"); 110898943Sluigi proto = cmd->arg1; 110998943Sluigi pe = getprotobynumber(cmd->arg1); 1110102087Sluigi if (flags & HAVE_OPTIONS) 1111102087Sluigi printf(" proto"); 111298943Sluigi if (pe) 111398943Sluigi printf(" %s", pe->p_name); 111498943Sluigi else 111598943Sluigi printf(" %u", cmd->arg1); 111698943Sluigi } 111798943Sluigi flags |= HAVE_PROTO; 111898943Sluigi break; 1119106505Smaxim 112098943Sluigi default: /*options ... */ 1121102087Sluigi show_prerequisites(&flags, HAVE_IP | HAVE_OPTIONS, 0); 112298943Sluigi if ((cmd->len & F_OR) && !or_block) 112398943Sluigi printf(" {"); 112498943Sluigi if (cmd->len & F_NOT && cmd->opcode != O_IN) 112598943Sluigi printf(" not"); 112698943Sluigi switch(cmd->opcode) { 112798943Sluigi case O_FRAG: 112898943Sluigi printf(" frag"); 112998943Sluigi break; 113098943Sluigi 113198943Sluigi case O_IN: 113298943Sluigi printf(cmd->len & F_NOT ? " out" : " in"); 113398943Sluigi break; 113498943Sluigi 113598943Sluigi case O_LAYER2: 113698943Sluigi printf(" layer2"); 113798943Sluigi break; 113898943Sluigi case O_XMIT: 113998943Sluigi case O_RECV: 114098943Sluigi case O_VIA: { 114198943Sluigi char *s; 114298943Sluigi ipfw_insn_if *cmdif = (ipfw_insn_if *)cmd; 114398943Sluigi 114498943Sluigi if (cmd->opcode == O_XMIT) 114598943Sluigi s = "xmit"; 114698943Sluigi else if (cmd->opcode == O_RECV) 114798943Sluigi s = "recv"; 114898943Sluigi else if (cmd->opcode == O_VIA) 114998943Sluigi s = "via"; 115098943Sluigi if (cmdif->name[0] == '\0') 115199475Sluigi printf(" %s %s", s, 115299475Sluigi inet_ntoa(cmdif->p.ip)); 115398943Sluigi else if (cmdif->p.unit == -1) 115498943Sluigi printf(" %s %s*", s, cmdif->name); 115598943Sluigi else 115699475Sluigi printf(" %s %s%d", s, cmdif->name, 115799475Sluigi cmdif->p.unit); 115898943Sluigi } 115998943Sluigi break; 116098943Sluigi 116198943Sluigi case O_IPID: 1162116690Sluigi if (F_LEN(cmd) == 1) 1163116690Sluigi printf(" ipid %u", cmd->arg1 ); 1164116690Sluigi else 1165116690Sluigi print_newports((ipfw_insn_u16 *)cmd, 0, 1166116690Sluigi O_IPID); 116798943Sluigi break; 116898943Sluigi 116998943Sluigi case O_IPTTL: 1170116690Sluigi if (F_LEN(cmd) == 1) 1171116690Sluigi printf(" ipttl %u", cmd->arg1 ); 1172116690Sluigi else 1173116690Sluigi print_newports((ipfw_insn_u16 *)cmd, 0, 1174116690Sluigi O_IPTTL); 117598943Sluigi break; 117698943Sluigi 117798943Sluigi case O_IPVER: 117898943Sluigi printf(" ipver %u", cmd->arg1 ); 117998943Sluigi break; 118098943Sluigi 118199475Sluigi case O_IPPRECEDENCE: 118299475Sluigi printf(" ipprecedence %u", (cmd->arg1) >> 5 ); 118399475Sluigi break; 118499475Sluigi 118598943Sluigi case O_IPLEN: 1186116690Sluigi if (F_LEN(cmd) == 1) 1187116690Sluigi printf(" iplen %u", cmd->arg1 ); 1188116690Sluigi else 1189116690Sluigi print_newports((ipfw_insn_u16 *)cmd, 0, 1190116690Sluigi O_IPLEN); 119198943Sluigi break; 119298943Sluigi 1193101116Sluigi case O_IPOPT: 119498943Sluigi print_flags("ipoptions", cmd, f_ipopts); 119598943Sluigi break; 119698943Sluigi 119799475Sluigi case O_IPTOS: 119899475Sluigi print_flags("iptos", cmd, f_iptos); 119999475Sluigi break; 120099475Sluigi 120199475Sluigi case O_ICMPTYPE: 120299475Sluigi print_icmptypes((ipfw_insn_u32 *)cmd); 120399475Sluigi break; 120499475Sluigi 120598943Sluigi case O_ESTAB: 120698943Sluigi printf(" established"); 120798943Sluigi break; 120898943Sluigi 120998943Sluigi case O_TCPFLAGS: 121098943Sluigi print_flags("tcpflags", cmd, f_tcpflags); 121198943Sluigi break; 121298943Sluigi 121398943Sluigi case O_TCPOPTS: 121498943Sluigi print_flags("tcpoptions", cmd, f_tcpopts); 121598943Sluigi break; 121698943Sluigi 121798943Sluigi case O_TCPWIN: 121898943Sluigi printf(" tcpwin %d", ntohs(cmd->arg1)); 121998943Sluigi break; 122098943Sluigi 122198943Sluigi case O_TCPACK: 122298943Sluigi printf(" tcpack %d", ntohl(cmd32->d[0])); 122398943Sluigi break; 122498943Sluigi 122598943Sluigi case O_TCPSEQ: 122698943Sluigi printf(" tcpseq %d", ntohl(cmd32->d[0])); 122798943Sluigi break; 122898943Sluigi 122998943Sluigi case O_UID: 123098943Sluigi { 123198943Sluigi struct passwd *pwd = getpwuid(cmd32->d[0]); 123298943Sluigi 123398943Sluigi if (pwd) 123498943Sluigi printf(" uid %s", pwd->pw_name); 123598943Sluigi else 123698943Sluigi printf(" uid %u", cmd32->d[0]); 123798943Sluigi } 123898943Sluigi break; 123998943Sluigi 124098943Sluigi case O_GID: 124198943Sluigi { 124298943Sluigi struct group *grp = getgrgid(cmd32->d[0]); 124398943Sluigi 124498943Sluigi if (grp) 124598943Sluigi printf(" gid %s", grp->gr_name); 124698943Sluigi else 124798943Sluigi printf(" gid %u", cmd32->d[0]); 124898943Sluigi } 124998943Sluigi break; 125098943Sluigi 1251112250Scjc case O_VERREVPATH: 1252112250Scjc printf(" verrevpath"); 1253112250Scjc break; 1254116919Sluigi 1255117241Sluigi case O_IPSEC: 1256117241Sluigi printf(" ipsec"); 1257117241Sluigi break; 1258117241Sluigi 125998943Sluigi case O_KEEP_STATE: 126098943Sluigi printf(" keep-state"); 126198943Sluigi break; 126298943Sluigi 126398943Sluigi case O_LIMIT: 126498943Sluigi { 126598943Sluigi struct _s_x *p = limit_masks; 126698943Sluigi ipfw_insn_limit *c = (ipfw_insn_limit *)cmd; 1267117328Sluigi uint8_t x = c->limit_mask; 126898943Sluigi char *comma = " "; 126998943Sluigi 127098943Sluigi printf(" limit"); 1271106505Smaxim for ( ; p->x != 0 ; p++) 127299909Sluigi if ((x & p->x) == p->x) { 127398943Sluigi x &= ~p->x; 127498943Sluigi printf("%s%s", comma, p->s); 127598943Sluigi comma = ","; 127698943Sluigi } 127798943Sluigi printf(" %d", c->conn_limit); 127898943Sluigi } 127998943Sluigi break; 128098943Sluigi 128198943Sluigi default: 128298943Sluigi printf(" [opcode %d len %d]", 128398943Sluigi cmd->opcode, cmd->len); 128498943Sluigi } 128598943Sluigi } 128698943Sluigi if (cmd->len & F_OR) { 128798943Sluigi printf(" or"); 128898943Sluigi or_block = 1; 128998943Sluigi } else if (or_block) { 129098943Sluigi printf(" }"); 129198943Sluigi or_block = 0; 129298943Sluigi } 129398943Sluigi } 1294102087Sluigi show_prerequisites(&flags, HAVE_IP, 0); 129598943Sluigi 129698943Sluigi printf("\n"); 129798943Sluigi} 129898943Sluigi 129998943Sluigistatic void 1300112189Smaximshow_dyn_ipfw(ipfw_dyn_rule *d, int pcwidth, int bcwidth) 130198943Sluigi{ 130298943Sluigi struct protoent *pe; 130398943Sluigi struct in_addr a; 1304115793Sticso uint16_t rulenum; 130598943Sluigi 130698943Sluigi if (!do_expired) { 130798943Sluigi if (!d->expire && !(d->dyn_type == O_LIMIT_PARENT)) 130898943Sluigi return; 130998943Sluigi } 1310115793Sticso bcopy(&d->rule, &rulenum, sizeof(rulenum)); 1311117328Sluigi printf("%05d", rulenum); 1312117328Sluigi if (do_acct) 1313117328Sluigi printf(" %*llu %*llu (%ds)", pcwidth, 1314117328Sluigi align_uint64(&d->pcnt), bcwidth, 1315117328Sluigi align_uint64(&d->bcnt), d->expire); 131698943Sluigi switch (d->dyn_type) { 131798943Sluigi case O_LIMIT_PARENT: 131898943Sluigi printf(" PARENT %d", d->count); 131998943Sluigi break; 132098943Sluigi case O_LIMIT: 132198943Sluigi printf(" LIMIT"); 132298943Sluigi break; 132398943Sluigi case O_KEEP_STATE: /* bidir, no mask */ 1324106505Smaxim printf(" STATE"); 132598943Sluigi break; 132698943Sluigi } 132798943Sluigi 132898943Sluigi if ((pe = getprotobynumber(d->id.proto)) != NULL) 132998943Sluigi printf(" %s", pe->p_name); 133098943Sluigi else 133198943Sluigi printf(" proto %u", d->id.proto); 133298943Sluigi 133398943Sluigi a.s_addr = htonl(d->id.src_ip); 133498943Sluigi printf(" %s %d", inet_ntoa(a), d->id.src_port); 133598943Sluigi 133698943Sluigi a.s_addr = htonl(d->id.dst_ip); 133798943Sluigi printf(" <-> %s %d", inet_ntoa(a), d->id.dst_port); 133898943Sluigi printf("\n"); 133998943Sluigi} 134098943Sluigi 134198943Sluigiint 134298943Sluigisort_q(const void *pa, const void *pb) 134398943Sluigi{ 134498943Sluigi int rev = (do_sort < 0); 134598943Sluigi int field = rev ? -do_sort : do_sort; 134698943Sluigi long long res = 0; 134798943Sluigi const struct dn_flow_queue *a = pa; 134898943Sluigi const struct dn_flow_queue *b = pb; 134998943Sluigi 135098943Sluigi switch (field) { 135198943Sluigi case 1: /* pkts */ 135298943Sluigi res = a->len - b->len; 135398943Sluigi break; 135498943Sluigi case 2: /* bytes */ 135598943Sluigi res = a->len_bytes - b->len_bytes; 135698943Sluigi break; 135798943Sluigi 135898943Sluigi case 3: /* tot pkts */ 135998943Sluigi res = a->tot_pkts - b->tot_pkts; 136098943Sluigi break; 136198943Sluigi 136298943Sluigi case 4: /* tot bytes */ 136398943Sluigi res = a->tot_bytes - b->tot_bytes; 136498943Sluigi break; 136598943Sluigi } 136698943Sluigi if (res < 0) 136798943Sluigi res = -1; 136898943Sluigi if (res > 0) 136998943Sluigi res = 1; 137098943Sluigi return (int)(rev ? res : -res); 137198943Sluigi} 137298943Sluigi 137398943Sluigistatic void 137498943Sluigilist_queues(struct dn_flow_set *fs, struct dn_flow_queue *q) 137598943Sluigi{ 137698943Sluigi int l; 137798943Sluigi 137898943Sluigi printf(" mask: 0x%02x 0x%08x/0x%04x -> 0x%08x/0x%04x\n", 137998943Sluigi fs->flow_mask.proto, 138098943Sluigi fs->flow_mask.src_ip, fs->flow_mask.src_port, 138198943Sluigi fs->flow_mask.dst_ip, fs->flow_mask.dst_port); 138298943Sluigi if (fs->rq_elements == 0) 138398943Sluigi return; 138498943Sluigi 138598943Sluigi printf("BKT Prot ___Source IP/port____ " 138698943Sluigi "____Dest. IP/port____ Tot_pkt/bytes Pkt/Byte Drp\n"); 138798943Sluigi if (do_sort != 0) 138898943Sluigi heapsort(q, fs->rq_elements, sizeof *q, sort_q); 138998943Sluigi for (l = 0; l < fs->rq_elements; l++) { 139098943Sluigi struct in_addr ina; 139198943Sluigi struct protoent *pe; 139298943Sluigi 139398943Sluigi ina.s_addr = htonl(q[l].id.src_ip); 139498943Sluigi printf("%3d ", q[l].hash_slot); 139598943Sluigi pe = getprotobynumber(q[l].id.proto); 139698943Sluigi if (pe) 139798943Sluigi printf("%-4s ", pe->p_name); 139898943Sluigi else 139998943Sluigi printf("%4u ", q[l].id.proto); 140098943Sluigi printf("%15s/%-5d ", 140198943Sluigi inet_ntoa(ina), q[l].id.src_port); 140298943Sluigi ina.s_addr = htonl(q[l].id.dst_ip); 140398943Sluigi printf("%15s/%-5d ", 140498943Sluigi inet_ntoa(ina), q[l].id.dst_port); 140598943Sluigi printf("%4qu %8qu %2u %4u %3u\n", 140698943Sluigi q[l].tot_pkts, q[l].tot_bytes, 140798943Sluigi q[l].len, q[l].len_bytes, q[l].drops); 140898943Sluigi if (verbose) 140998943Sluigi printf(" S %20qd F %20qd\n", 141098943Sluigi q[l].S, q[l].F); 141198943Sluigi } 141298943Sluigi} 141398943Sluigi 141498943Sluigistatic void 141598943Sluigiprint_flowset_parms(struct dn_flow_set *fs, char *prefix) 141698943Sluigi{ 141798943Sluigi int l; 141898943Sluigi char qs[30]; 141998943Sluigi char plr[30]; 142098943Sluigi char red[90]; /* Display RED parameters */ 142198943Sluigi 142298943Sluigi l = fs->qsize; 142398943Sluigi if (fs->flags_fs & DN_QSIZE_IS_BYTES) { 142498943Sluigi if (l >= 8192) 142598943Sluigi sprintf(qs, "%d KB", l / 1024); 142698943Sluigi else 142798943Sluigi sprintf(qs, "%d B", l); 142898943Sluigi } else 142998943Sluigi sprintf(qs, "%3d sl.", l); 143098943Sluigi if (fs->plr) 143198943Sluigi sprintf(plr, "plr %f", 1.0 * fs->plr / (double)(0x7fffffff)); 143298943Sluigi else 143398943Sluigi plr[0] = '\0'; 143498943Sluigi if (fs->flags_fs & DN_IS_RED) /* RED parameters */ 143598943Sluigi sprintf(red, 143698943Sluigi "\n\t %cRED w_q %f min_th %d max_th %d max_p %f", 143798943Sluigi (fs->flags_fs & DN_IS_GENTLE_RED) ? 'G' : ' ', 143898943Sluigi 1.0 * fs->w_q / (double)(1 << SCALE_RED), 143998943Sluigi SCALE_VAL(fs->min_th), 144098943Sluigi SCALE_VAL(fs->max_th), 144198943Sluigi 1.0 * fs->max_p / (double)(1 << SCALE_RED)); 144298943Sluigi else 144398943Sluigi sprintf(red, "droptail"); 144498943Sluigi 144598943Sluigi printf("%s %s%s %d queues (%d buckets) %s\n", 144698943Sluigi prefix, qs, plr, fs->rq_elements, fs->rq_size, red); 144798943Sluigi} 144898943Sluigi 144998943Sluigistatic void 145098943Sluigilist_pipes(void *data, int nbytes, int ac, char *av[]) 145198943Sluigi{ 145298943Sluigi u_long rulenum; 145398943Sluigi void *next = data; 145498943Sluigi struct dn_pipe *p = (struct dn_pipe *) data; 145598943Sluigi struct dn_flow_set *fs; 145698943Sluigi struct dn_flow_queue *q; 145798943Sluigi int l; 145898943Sluigi 145998943Sluigi if (ac > 0) 146098943Sluigi rulenum = strtoul(*av++, NULL, 10); 146198943Sluigi else 146298943Sluigi rulenum = 0; 146398943Sluigi for (; nbytes >= sizeof *p; p = (struct dn_pipe *)next) { 146498943Sluigi double b = p->bandwidth; 146598943Sluigi char buf[30]; 146698943Sluigi char prefix[80]; 146798943Sluigi 146898943Sluigi if (p->next != (struct dn_pipe *)DN_IS_PIPE) 146998943Sluigi break; /* done with pipes, now queues */ 147098943Sluigi 147198943Sluigi /* 147298943Sluigi * compute length, as pipe have variable size 147398943Sluigi */ 147498943Sluigi l = sizeof(*p) + p->fs.rq_elements * sizeof(*q); 147598943Sluigi next = (void *)p + l; 147698943Sluigi nbytes -= l; 147798943Sluigi 147898943Sluigi if (rulenum != 0 && rulenum != p->pipe_nr) 147998943Sluigi continue; 148098943Sluigi 148198943Sluigi /* 148298943Sluigi * Print rate (or clocking interface) 148398943Sluigi */ 148498943Sluigi if (p->if_name[0] != '\0') 148598943Sluigi sprintf(buf, "%s", p->if_name); 148698943Sluigi else if (b == 0) 148798943Sluigi sprintf(buf, "unlimited"); 148898943Sluigi else if (b >= 1000000) 148998943Sluigi sprintf(buf, "%7.3f Mbit/s", b/1000000); 149098943Sluigi else if (b >= 1000) 149198943Sluigi sprintf(buf, "%7.3f Kbit/s", b/1000); 149298943Sluigi else 149398943Sluigi sprintf(buf, "%7.3f bit/s ", b); 149498943Sluigi 149598943Sluigi sprintf(prefix, "%05d: %s %4d ms ", 149698943Sluigi p->pipe_nr, buf, p->delay); 149798943Sluigi print_flowset_parms(&(p->fs), prefix); 149898943Sluigi if (verbose) 149998943Sluigi printf(" V %20qd\n", p->V >> MY_M); 1500106505Smaxim 150198943Sluigi q = (struct dn_flow_queue *)(p+1); 150298943Sluigi list_queues(&(p->fs), q); 150398943Sluigi } 150498943Sluigi for (fs = next; nbytes >= sizeof *fs; fs = next) { 150598943Sluigi char prefix[80]; 150698943Sluigi 150798943Sluigi if (fs->next != (struct dn_flow_set *)DN_IS_QUEUE) 150898943Sluigi break; 150998943Sluigi l = sizeof(*fs) + fs->rq_elements * sizeof(*q); 151098943Sluigi next = (void *)fs + l; 151198943Sluigi nbytes -= l; 151298943Sluigi q = (struct dn_flow_queue *)(fs+1); 151398943Sluigi sprintf(prefix, "q%05d: weight %d pipe %d ", 151498943Sluigi fs->fs_nr, fs->weight, fs->parent_nr); 151598943Sluigi print_flowset_parms(fs, prefix); 151698943Sluigi list_queues(fs, q); 151798943Sluigi } 151898943Sluigi} 151998943Sluigi 1520101978Sluigi/* 1521101978Sluigi * This one handles all set-related commands 1522101978Sluigi * ipfw set { show | enable | disable } 1523101978Sluigi * ipfw set swap X Y 1524101978Sluigi * ipfw set move X to Y 1525101978Sluigi * ipfw set move rule X to Y 1526101978Sluigi */ 152798943Sluigistatic void 1528101978Sluigisets_handler(int ac, char *av[]) 1529101978Sluigi{ 1530117328Sluigi uint32_t set_disable, masks[2]; 1531101978Sluigi int i, nbytes; 1532117328Sluigi uint16_t rulenum; 1533117328Sluigi uint8_t cmd, new_set; 1534101978Sluigi 1535101978Sluigi ac--; 1536101978Sluigi av++; 1537101978Sluigi 1538101978Sluigi if (!ac) 1539101978Sluigi errx(EX_USAGE, "set needs command"); 1540101978Sluigi if (!strncmp(*av, "show", strlen(*av)) ) { 1541101978Sluigi void *data; 1542101978Sluigi char *msg; 1543101978Sluigi 1544101978Sluigi nbytes = sizeof(struct ip_fw); 1545117328Sluigi if ((data = calloc(1, nbytes)) == NULL) 1546117328Sluigi err(EX_OSERR, "calloc"); 1547117328Sluigi if (do_cmd(IP_FW_GET, data, (socklen_t)&nbytes) < 0) 1548101978Sluigi err(EX_OSERR, "getsockopt(IP_FW_GET)"); 1549115793Sticso bcopy(&((struct ip_fw *)data)->next_rule, 1550115793Sticso &set_disable, sizeof(set_disable)); 1551101978Sluigi 1552101978Sluigi for (i = 0, msg = "disable" ; i < 31; i++) 1553101978Sluigi if ( (set_disable & (1<<i))) { 1554101978Sluigi printf("%s %d", msg, i); 1555101978Sluigi msg = ""; 1556101978Sluigi } 1557101978Sluigi msg = (set_disable) ? " enable" : "enable"; 1558101978Sluigi for (i = 0; i < 31; i++) 1559101978Sluigi if ( !(set_disable & (1<<i))) { 1560101978Sluigi printf("%s %d", msg, i); 1561101978Sluigi msg = ""; 1562101978Sluigi } 1563101978Sluigi printf("\n"); 1564101978Sluigi } else if (!strncmp(*av, "swap", strlen(*av))) { 1565101978Sluigi ac--; av++; 1566101978Sluigi if (ac != 2) 1567101978Sluigi errx(EX_USAGE, "set swap needs 2 set numbers\n"); 1568101978Sluigi rulenum = atoi(av[0]); 1569101978Sluigi new_set = atoi(av[1]); 1570101978Sluigi if (!isdigit(*(av[0])) || rulenum > 30) 1571101978Sluigi errx(EX_DATAERR, "invalid set number %s\n", av[0]); 1572101978Sluigi if (!isdigit(*(av[1])) || new_set > 30) 1573101978Sluigi errx(EX_DATAERR, "invalid set number %s\n", av[1]); 1574101978Sluigi masks[0] = (4 << 24) | (new_set << 16) | (rulenum); 1575117328Sluigi i = do_cmd(IP_FW_DEL, masks, sizeof(uint32_t)); 1576101978Sluigi } else if (!strncmp(*av, "move", strlen(*av))) { 1577101978Sluigi ac--; av++; 1578101978Sluigi if (ac && !strncmp(*av, "rule", strlen(*av))) { 1579101978Sluigi cmd = 2; 1580101978Sluigi ac--; av++; 1581101978Sluigi } else 1582101978Sluigi cmd = 3; 1583101978Sluigi if (ac != 3 || strncmp(av[1], "to", strlen(*av))) 1584101978Sluigi errx(EX_USAGE, "syntax: set move [rule] X to Y\n"); 1585101978Sluigi rulenum = atoi(av[0]); 1586101978Sluigi new_set = atoi(av[2]); 1587101978Sluigi if (!isdigit(*(av[0])) || (cmd == 3 && rulenum > 30) || 1588101978Sluigi (cmd == 2 && rulenum == 65535) ) 1589101978Sluigi errx(EX_DATAERR, "invalid source number %s\n", av[0]); 1590101978Sluigi if (!isdigit(*(av[2])) || new_set > 30) 1591101978Sluigi errx(EX_DATAERR, "invalid dest. set %s\n", av[1]); 1592101978Sluigi masks[0] = (cmd << 24) | (new_set << 16) | (rulenum); 1593117328Sluigi i = do_cmd(IP_FW_DEL, masks, sizeof(uint32_t)); 1594101978Sluigi } else if (!strncmp(*av, "disable", strlen(*av)) || 1595101978Sluigi !strncmp(*av, "enable", strlen(*av)) ) { 1596101978Sluigi int which = !strncmp(*av, "enable", strlen(*av)) ? 1 : 0; 1597101978Sluigi 1598101978Sluigi ac--; av++; 1599101978Sluigi masks[0] = masks[1] = 0; 1600101978Sluigi 1601101978Sluigi while (ac) { 1602101978Sluigi if (isdigit(**av)) { 1603101978Sluigi i = atoi(*av); 1604101978Sluigi if (i < 0 || i > 30) 1605101978Sluigi errx(EX_DATAERR, 1606101978Sluigi "invalid set number %d\n", i); 1607101978Sluigi masks[which] |= (1<<i); 1608101978Sluigi } else if (!strncmp(*av, "disable", strlen(*av))) 1609101978Sluigi which = 0; 1610101978Sluigi else if (!strncmp(*av, "enable", strlen(*av))) 1611101978Sluigi which = 1; 1612101978Sluigi else 1613101978Sluigi errx(EX_DATAERR, 1614101978Sluigi "invalid set command %s\n", *av); 1615101978Sluigi av++; ac--; 1616101978Sluigi } 1617101978Sluigi if ( (masks[0] & masks[1]) != 0 ) 1618101978Sluigi errx(EX_DATAERR, 1619101978Sluigi "cannot enable and disable the same set\n"); 1620101978Sluigi 1621117328Sluigi i = do_cmd(IP_FW_DEL, masks, sizeof(masks)); 1622101978Sluigi if (i) 1623101978Sluigi warn("set enable/disable: setsockopt(IP_FW_DEL)"); 1624101978Sluigi } else 1625101978Sluigi errx(EX_USAGE, "invalid set command %s\n", *av); 1626101978Sluigi} 1627101978Sluigi 1628101978Sluigistatic void 1629109126Sdillonsysctl_handler(int ac, char *av[], int which) 1630109126Sdillon{ 1631109126Sdillon ac--; 1632109126Sdillon av++; 1633109126Sdillon 1634109126Sdillon if (*av == NULL) { 1635109126Sdillon warnx("missing keyword to enable/disable\n"); 1636109126Sdillon } else if (strncmp(*av, "firewall", strlen(*av)) == 0) { 1637116770Sluigi sysctlbyname("net.inet.ip.fw.enable", NULL, 0, 1638116770Sluigi &which, sizeof(which)); 1639109126Sdillon } else if (strncmp(*av, "one_pass", strlen(*av)) == 0) { 1640116770Sluigi sysctlbyname("net.inet.ip.fw.one_pass", NULL, 0, 1641116770Sluigi &which, sizeof(which)); 1642109126Sdillon } else if (strncmp(*av, "debug", strlen(*av)) == 0) { 1643116770Sluigi sysctlbyname("net.inet.ip.fw.debug", NULL, 0, 1644116770Sluigi &which, sizeof(which)); 1645109126Sdillon } else if (strncmp(*av, "verbose", strlen(*av)) == 0) { 1646116770Sluigi sysctlbyname("net.inet.ip.fw.verbose", NULL, 0, 1647116770Sluigi &which, sizeof(which)); 1648109126Sdillon } else if (strncmp(*av, "dyn_keepalive", strlen(*av)) == 0) { 1649116770Sluigi sysctlbyname("net.inet.ip.fw.dyn_keepalive", NULL, 0, 1650116770Sluigi &which, sizeof(which)); 1651109126Sdillon } else { 1652109126Sdillon warnx("unrecognize enable/disable keyword: %s\n", *av); 1653109126Sdillon } 1654109126Sdillon} 1655109126Sdillon 1656109126Sdillonstatic void 165798943Sluigilist(int ac, char *av[]) 165898943Sluigi{ 165998943Sluigi struct ip_fw *r; 166098943Sluigi ipfw_dyn_rule *dynrules, *d; 166198943Sluigi 166298943Sluigi void *lim, *data = NULL; 1663112189Smaxim int bcwidth, n, nbytes, nstat, ndyn, pcwidth, width; 166498943Sluigi int exitval = EX_OK; 166598943Sluigi int lac; 166698943Sluigi char **lav; 166798943Sluigi u_long rnum; 166898943Sluigi char *endptr; 166998943Sluigi int seen = 0; 167098943Sluigi 167198943Sluigi const int ocmd = do_pipe ? IP_DUMMYNET_GET : IP_FW_GET; 167298943Sluigi int nalloc = 1024; /* start somewhere... */ 167398943Sluigi 1674117328Sluigi if (test_only) { 1675117328Sluigi fprintf(stderr, "Testing only, list disabled\n"); 1676117328Sluigi return; 1677117328Sluigi } 1678117328Sluigi 167998943Sluigi ac--; 168098943Sluigi av++; 168198943Sluigi 168298943Sluigi /* get rules or pipes from kernel, resizing array as necessary */ 168398943Sluigi nbytes = nalloc; 168498943Sluigi 168598943Sluigi while (nbytes >= nalloc) { 168698943Sluigi nalloc = nalloc * 2 + 200; 168798943Sluigi nbytes = nalloc; 168898943Sluigi if ((data = realloc(data, nbytes)) == NULL) 168998943Sluigi err(EX_OSERR, "realloc"); 1690117328Sluigi if (do_cmd(ocmd, data, (socklen_t)&nbytes) < 0) 169198943Sluigi err(EX_OSERR, "getsockopt(IP_%s_GET)", 169298943Sluigi do_pipe ? "DUMMYNET" : "FW"); 169398943Sluigi } 169498943Sluigi 169598943Sluigi if (do_pipe) { 169698943Sluigi list_pipes(data, nbytes, ac, av); 169798943Sluigi goto done; 169898943Sluigi } 169998943Sluigi 170098943Sluigi /* 170198943Sluigi * Count static rules. They have variable size so we 170298943Sluigi * need to scan the list to count them. 170398943Sluigi */ 170498943Sluigi for (nstat = 1, r = data, lim = data + nbytes; 170598943Sluigi r->rulenum < 65535 && (void *)r < lim; 170698943Sluigi ++nstat, r = (void *)r + RULESIZE(r) ) 170798943Sluigi ; /* nothing */ 170898943Sluigi 170998943Sluigi /* 171098943Sluigi * Count dynamic rules. This is easier as they have 171198943Sluigi * fixed size. 171298943Sluigi */ 171398943Sluigi r = (void *)r + RULESIZE(r); 171498943Sluigi dynrules = (ipfw_dyn_rule *)r ; 171598943Sluigi n = (void *)r - data; 171698943Sluigi ndyn = (nbytes - n) / sizeof *dynrules; 171798943Sluigi 1718112189Smaxim /* if showing stats, figure out column widths ahead of time */ 1719112189Smaxim bcwidth = pcwidth = 0; 1720112189Smaxim if (do_acct) { 1721112189Smaxim for (n = 0, r = data; n < nstat; 1722112189Smaxim n++, r = (void *)r + RULESIZE(r)) { 1723112189Smaxim /* packet counter */ 1724115793Sticso width = snprintf(NULL, 0, "%llu", 1725115793Sticso align_uint64(&r->pcnt)); 1726112189Smaxim if (width > pcwidth) 1727112189Smaxim pcwidth = width; 1728112189Smaxim 1729112189Smaxim /* byte counter */ 1730115793Sticso width = snprintf(NULL, 0, "%llu", 1731115793Sticso align_uint64(&r->bcnt)); 1732112189Smaxim if (width > bcwidth) 1733112189Smaxim bcwidth = width; 1734112189Smaxim } 1735112189Smaxim } 1736112189Smaxim if (do_dynamic && ndyn) { 1737112189Smaxim for (n = 0, d = dynrules; n < ndyn; n++, d++) { 1738115793Sticso width = snprintf(NULL, 0, "%llu", 1739115793Sticso align_uint64(&d->pcnt)); 1740112189Smaxim if (width > pcwidth) 1741112189Smaxim pcwidth = width; 1742112189Smaxim 1743115793Sticso width = snprintf(NULL, 0, "%llu", 1744115793Sticso align_uint64(&d->bcnt)); 1745112189Smaxim if (width > bcwidth) 1746112189Smaxim bcwidth = width; 1747112189Smaxim } 1748112189Smaxim } 174998943Sluigi /* if no rule numbers were specified, list all rules */ 175098943Sluigi if (ac == 0) { 175198943Sluigi for (n = 0, r = data; n < nstat; 175298943Sluigi n++, r = (void *)r + RULESIZE(r) ) 1753112189Smaxim show_ipfw(r, pcwidth, bcwidth); 175498943Sluigi 175598943Sluigi if (do_dynamic && ndyn) { 175698943Sluigi printf("## Dynamic rules (%d):\n", ndyn); 175798943Sluigi for (n = 0, d = dynrules; n < ndyn; n++, d++) 1758112189Smaxim show_dyn_ipfw(d, pcwidth, bcwidth); 175998943Sluigi } 176098943Sluigi goto done; 176198943Sluigi } 176298943Sluigi 176398943Sluigi /* display specific rules requested on command line */ 176498943Sluigi 176598943Sluigi for (lac = ac, lav = av; lac != 0; lac--) { 176698943Sluigi /* convert command line rule # */ 176798943Sluigi rnum = strtoul(*lav++, &endptr, 10); 176898943Sluigi if (*endptr) { 176998943Sluigi exitval = EX_USAGE; 177098943Sluigi warnx("invalid rule number: %s", *(lav - 1)); 177198943Sluigi continue; 177298943Sluigi } 177398943Sluigi for (n = seen = 0, r = data; n < nstat; 177498943Sluigi n++, r = (void *)r + RULESIZE(r) ) { 177598943Sluigi if (r->rulenum > rnum) 177698943Sluigi break; 177798943Sluigi if (r->rulenum == rnum) { 1778112189Smaxim show_ipfw(r, pcwidth, bcwidth); 177998943Sluigi seen = 1; 178098943Sluigi } 178198943Sluigi } 178298943Sluigi if (!seen) { 178398943Sluigi /* give precedence to other error(s) */ 178498943Sluigi if (exitval == EX_OK) 178598943Sluigi exitval = EX_UNAVAILABLE; 178698943Sluigi warnx("rule %lu does not exist", rnum); 178798943Sluigi } 178898943Sluigi } 178998943Sluigi 179098943Sluigi if (do_dynamic && ndyn) { 179198943Sluigi printf("## Dynamic rules:\n"); 179298943Sluigi for (lac = ac, lav = av; lac != 0; lac--) { 179398943Sluigi rnum = strtoul(*lav++, &endptr, 10); 179498943Sluigi if (*endptr) 179598943Sluigi /* already warned */ 179698943Sluigi continue; 179798943Sluigi for (n = 0, d = dynrules; n < ndyn; n++, d++) { 1798115793Sticso uint16_t rulenum; 1799115793Sticso 1800115793Sticso bcopy(&d->rule, &rulenum, sizeof(rulenum)); 1801115793Sticso if (rulenum > rnum) 180298943Sluigi break; 1803115793Sticso if (rulenum == rnum) 1804112189Smaxim show_dyn_ipfw(d, pcwidth, bcwidth); 180598943Sluigi } 180698943Sluigi } 180798943Sluigi } 180898943Sluigi 180998943Sluigi ac = 0; 181098943Sluigi 181198943Sluigidone: 181298943Sluigi free(data); 181398943Sluigi 181498943Sluigi if (exitval != EX_OK) 181598943Sluigi exit(exitval); 181698943Sluigi} 181798943Sluigi 181898943Sluigistatic void 181998943Sluigishow_usage(void) 182098943Sluigi{ 182198943Sluigi fprintf(stderr, "usage: ipfw [options]\n" 182298943Sluigi"do \"ipfw -h\" or see ipfw manpage for details\n" 182398943Sluigi); 182498943Sluigi exit(EX_USAGE); 182598943Sluigi} 182698943Sluigi 182798943Sluigistatic void 182898943Sluigihelp(void) 182998943Sluigi{ 1830117328Sluigi fprintf(stderr, 1831117328Sluigi"ipfw syntax summary (but please do read the ipfw(8) manpage):\n" 1832117328Sluigi"ipfw [-acdeftnNpqS] command:" 1833117328Sluigi"add [num] [set N] [prob x] RULE-BODY\n" 1834117328Sluigi"{pipe|queue} N config PIPE-BODY\n" 1835117328Sluigi"[pipe|queue] {zero|delete|show} [N{,N}]\n" 1836117328Sluigi"set [disable N... enable N...] | move [rule] X to Y | swap X Y | show\n" 183798943Sluigi"\n" 1838117328Sluigi"RULE-BODY: check-state [LOG] | ACTION [LOG] ADDR [OPTION_LIST]\n" 183998943Sluigi"ACTION: check-state | allow | count | deny | reject | skipto N |\n" 184098943Sluigi" {divert|tee} PORT | forward ADDR | pipe N | queue N\n" 184198943Sluigi"ADDR: [ MAC dst src ether_type ] \n" 184298943Sluigi" [ from IPLIST [ PORT ] to IPLIST [ PORTLIST ] ]\n" 1843117328Sluigi"IPLIST: IPADDR[,IPADDR] | { IPADDR or ... or IPADDR }\n" 184498943Sluigi"IPADDR: [not] { any | me | ip | ip/bits | ip:mask | ip/bits{x,y,z} }\n" 184598943Sluigi"OPTION_LIST: OPTION [,OPTION_LIST]\n" 1846117328Sluigi"OPTION: bridged | {dst-ip|src-ip} ADDR | {dst-port|src-port} LIST |\n" 1847117328Sluigi" estab | frag | {gid|uid} N | icmptypes LIST | in | out | ipid LIST |\n" 1848117328Sluigi" iplen LIST | ipoptions SPEC | ipprecedence | ipsec | iptos SPEC |\n" 1849117328Sluigi" ipttl LIST | ipversion VER | keep-state | layer2 | limit ... |\n" 1850117328Sluigi" mac ... | mac-type LIST | proto LIST | {recv|xmit|via} {IF|IPADDR} |\n" 1851117328Sluigi" setup | {tcpack|tcpseq|tcpwin} NN | tcpflags SPEC | tcpoptions SPEC |\n" 1852117328Sluigi" verrevpath\n" 185398943Sluigi); 185498943Sluigiexit(0); 185598943Sluigi} 185698943Sluigi 185798943Sluigi 185898943Sluigistatic int 185998943Sluigilookup_host (char *host, struct in_addr *ipaddr) 186098943Sluigi{ 186198943Sluigi struct hostent *he; 186298943Sluigi 186398943Sluigi if (!inet_aton(host, ipaddr)) { 186498943Sluigi if ((he = gethostbyname(host)) == NULL) 186598943Sluigi return(-1); 186698943Sluigi *ipaddr = *(struct in_addr *)he->h_addr_list[0]; 186798943Sluigi } 186898943Sluigi return(0); 186998943Sluigi} 187098943Sluigi 187198943Sluigi/* 187298943Sluigi * fills the addr and mask fields in the instruction as appropriate from av. 187398943Sluigi * Update length as appropriate. 187498943Sluigi * The following formats are allowed: 187598943Sluigi * any matches any IP. Actually returns an empty instruction. 187698943Sluigi * me returns O_IP_*_ME 187798943Sluigi * 1.2.3.4 single IP address 187898943Sluigi * 1.2.3.4:5.6.7.8 address:mask 187998943Sluigi * 1.2.3.4/24 address/mask 188098943Sluigi * 1.2.3.4/26{1,6,5,4,23} set of addresses in a subnet 1881117328Sluigi * We can have multiple comma-separated address/mask entries. 188298943Sluigi */ 188398943Sluigistatic void 188498943Sluigifill_ip(ipfw_insn_ip *cmd, char *av) 188598943Sluigi{ 1886117328Sluigi int len = 0; 1887117328Sluigi uint32_t *d = ((ipfw_insn_u32 *)cmd)->d; 188898943Sluigi 188998943Sluigi cmd->o.len &= ~F_LEN_MASK; /* zero len */ 189098943Sluigi 189198943Sluigi if (!strncmp(av, "any", strlen(av))) 189298943Sluigi return; 189398943Sluigi 189498943Sluigi if (!strncmp(av, "me", strlen(av))) { 189598943Sluigi cmd->o.len |= F_INSN_SIZE(ipfw_insn); 189698943Sluigi return; 189798943Sluigi } 189898943Sluigi 1899117328Sluigi while (av) { 1900117328Sluigi /* 1901117328Sluigi * After the address we can have '/' or ':' indicating a mask, 1902117328Sluigi * ',' indicating another address follows, '{' indicating a 1903117328Sluigi * set of addresses of unspecified size. 1904117328Sluigi */ 1905117328Sluigi char *p = strpbrk(av, "/:,{"); 1906117328Sluigi int masklen; 1907117328Sluigi char md; 1908117328Sluigi 190998943Sluigi if (p) { 191098943Sluigi md = *p; 191198943Sluigi *p++ = '\0'; 1912117328Sluigi } else 1913117328Sluigi md = '\0'; 191498943Sluigi 1915117328Sluigi if (lookup_host(av, (struct in_addr *)&d[0]) != 0) 191698943Sluigi errx(EX_NOHOST, "hostname ``%s'' unknown", av); 191798943Sluigi switch (md) { 191898943Sluigi case ':': 1919117328Sluigi if (!inet_aton(p, (struct in_addr *)&d[1])) 192098943Sluigi errx(EX_DATAERR, "bad netmask ``%s''", p); 192198943Sluigi break; 192298943Sluigi case '/': 1923117328Sluigi masklen = atoi(p); 1924117328Sluigi if (masklen == 0) 1925117328Sluigi d[1] = htonl(0); /* mask */ 1926117328Sluigi else if (masklen > 32) 192798943Sluigi errx(EX_DATAERR, "bad width ``%s''", p); 192898943Sluigi else 1929117328Sluigi d[1] = htonl(~0 << (32 - masklen)); 193098943Sluigi break; 1931117328Sluigi case '{': /* no mask, assume /24 and put back the '{' */ 1932117328Sluigi d[1] = htonl(~0 << (32 - 24)); 1933117328Sluigi *(--p) = md; 1934117328Sluigi break; 1935117328Sluigi 1936117328Sluigi case ',': /* single address plus continuation */ 1937117328Sluigi *(--p) = md; 1938117328Sluigi /* FALLTHROUGH */ 1939117328Sluigi case 0: /* initialization value */ 194098943Sluigi default: 1941117328Sluigi d[1] = htonl(~0); /* force /32 */ 194298943Sluigi break; 194398943Sluigi } 1944117328Sluigi d[0] &= d[1]; /* mask base address with mask */ 1945117328Sluigi /* find next separator */ 194698943Sluigi if (p) 1947117328Sluigi p = strpbrk(p, ",{"); 1948117328Sluigi if (p && *p == '{') { 1949117328Sluigi /* 1950117328Sluigi * We have a set of addresses. They are stored as follows: 1951117328Sluigi * arg1 is the set size (powers of 2, 2..256) 1952117328Sluigi * addr is the base address IN HOST FORMAT 1953117328Sluigi * mask.. is an array of arg1 bits (rounded up to 1954117328Sluigi * the next multiple of 32) with bits set 1955117328Sluigi * for each host in the map. 1956117328Sluigi */ 1957117328Sluigi uint32_t *map = (uint32_t *)&cmd->mask; 195898943Sluigi int low, high; 1959117328Sluigi int i = contigmask((u_char *)&(d[1]), 32); 196098943Sluigi 1961117328Sluigi if (len > 0) 1962117328Sluigi errx(EX_DATAERR, "address set cannot be in a list"); 1963117328Sluigi if (i < 24 || i > 31) 1964117328Sluigi errx(EX_DATAERR, "invalid set with mask %d\n", i); 1965117328Sluigi cmd->o.arg1 = 1<<(32-i); /* map length */ 1966117328Sluigi d[0] = ntohl(d[0]); /* base addr in host format */ 196798943Sluigi cmd->o.opcode = O_IP_DST_SET; /* default */ 196898943Sluigi cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32) + (cmd->o.arg1+31)/32; 1969101117Sluigi for (i = 0; i < (cmd->o.arg1+31)/32 ; i++) 1970117328Sluigi map[i] = 0; /* clear map */ 197198943Sluigi 1972117328Sluigi av = p + 1; 1973117328Sluigi low = d[0] & 0xff; 197498943Sluigi high = low + cmd->o.arg1 - 1; 1975117328Sluigi /* 1976117328Sluigi * Here, i stores the previous value when we specify a range 1977117328Sluigi * of addresses within a mask, e.g. 45-63. i = -1 means we 1978117328Sluigi * have no previous value. 1979117328Sluigi */ 1980116716Sluigi i = -1; /* previous value in a range */ 198198943Sluigi while (isdigit(*av)) { 198298943Sluigi char *s; 1983117328Sluigi int a = strtol(av, &s, 0); 198498943Sluigi 1985117328Sluigi if (s == av) { /* no parameter */ 1986117328Sluigi if (*av != '}') 1987117328Sluigi errx(EX_DATAERR, "set not closed\n"); 1988117328Sluigi if (i != -1) 1989117328Sluigi errx(EX_DATAERR, "incomplete range %d-", i); 1990117328Sluigi break; 1991117328Sluigi } 1992117328Sluigi if (a < low || a > high) 1993117328Sluigi errx(EX_DATAERR, "addr %d out of range [%d-%d]\n", 199498943Sluigi a, low, high); 199598943Sluigi a -= low; 1996116716Sluigi if (i == -1) /* no previous in range */ 1997116716Sluigi i = a; 1998116716Sluigi else { /* check that range is valid */ 1999116716Sluigi if (i > a) 2000116716Sluigi errx(EX_DATAERR, "invalid range %d-%d", 2001116716Sluigi i+low, a+low); 2002116716Sluigi if (*s == '-') 2003116716Sluigi errx(EX_DATAERR, "double '-' in range"); 2004116716Sluigi } 2005116716Sluigi for (; i <= a; i++) 2006117328Sluigi map[i/32] |= 1<<(i & 31); 2007116716Sluigi i = -1; 2008116716Sluigi if (*s == '-') 2009116716Sluigi i = a; 2010117328Sluigi else if (*s == '}') 2011116716Sluigi break; 201298943Sluigi av = s+1; 201398943Sluigi } 201498943Sluigi return; 201598943Sluigi } 2016117328Sluigi av = p; 2017117328Sluigi if (av) /* then *av must be a ',' */ 2018117328Sluigi av++; 201998943Sluigi 2020117328Sluigi /* Check this entry */ 2021117328Sluigi if (d[1] == 0) { /* "any", specified as x.x.x.x/0 */ 2022117328Sluigi /* 2023117328Sluigi * 'any' turns the entire list into a NOP. 2024117328Sluigi * 'not any' never matches, so it is removed from the 2025117328Sluigi * list unless it is the only item, in which case we 2026117328Sluigi * report an error. 2027117328Sluigi */ 2028117328Sluigi if (cmd->o.len & F_NOT) { /* "not any" never matches */ 2029117328Sluigi if (av == NULL && len == 0) /* only this entry */ 2030117328Sluigi errx(EX_DATAERR, "not any never matches"); 2031117328Sluigi } 2032117328Sluigi /* else do nothing and skip this entry */ 2033117328Sluigi continue; 2034117328Sluigi } 2035117328Sluigi /* A single IP can be stored in an optimized format */ 2036117328Sluigi if (d[1] == IP_MASK_ALL && av == NULL && len == 0) { 203798943Sluigi cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32); 2038117328Sluigi return; 2039117328Sluigi } 2040117328Sluigi len += 2; /* two words... */ 2041117328Sluigi d += 2; 2042117328Sluigi } /* end while */ 2043117328Sluigi cmd->o.len |= len+1; 204498943Sluigi} 204598943Sluigi 204698943Sluigi 204798943Sluigi/* 204898943Sluigi * helper function to process a set of flags and set bits in the 204998943Sluigi * appropriate masks. 205098943Sluigi */ 205198943Sluigistatic void 205298943Sluigifill_flags(ipfw_insn *cmd, enum ipfw_opcodes opcode, 205398943Sluigi struct _s_x *flags, char *p) 205498943Sluigi{ 2055117328Sluigi uint8_t set=0, clear=0; 205698943Sluigi 205798943Sluigi while (p && *p) { 205898943Sluigi char *q; /* points to the separator */ 205998943Sluigi int val; 2060117328Sluigi uint8_t *which; /* mask we are working on */ 206198943Sluigi 206298943Sluigi if (*p == '!') { 206398943Sluigi p++; 206498943Sluigi which = &clear; 206598943Sluigi } else 206698943Sluigi which = &set; 206798943Sluigi q = strchr(p, ','); 206898943Sluigi if (q) 206998943Sluigi *q++ = '\0'; 207098943Sluigi val = match_token(flags, p); 207198943Sluigi if (val <= 0) 207298943Sluigi errx(EX_DATAERR, "invalid flag %s", p); 2073117328Sluigi *which |= (uint8_t)val; 207498943Sluigi p = q; 207598943Sluigi } 207698943Sluigi cmd->opcode = opcode; 207798943Sluigi cmd->len = (cmd->len & (F_NOT | F_OR)) | 1; 207898943Sluigi cmd->arg1 = (set & 0xff) | ( (clear & 0xff) << 8); 207998943Sluigi} 208098943Sluigi 208198943Sluigi 208298943Sluigistatic void 208398943Sluigidelete(int ac, char *av[]) 208498943Sluigi{ 2085117328Sluigi uint32_t rulenum; 208698943Sluigi struct dn_pipe pipe; 208798943Sluigi int i; 208898943Sluigi int exitval = EX_OK; 2089101628Sluigi int do_set = 0; 209098943Sluigi 209198943Sluigi memset(&pipe, 0, sizeof pipe); 209298943Sluigi 209398943Sluigi av++; ac--; 2094101641Sluigi if (ac > 0 && !strncmp(*av, "set", strlen(*av))) { 2095101978Sluigi do_set = 1; /* delete set */ 2096101628Sluigi ac--; av++; 2097101978Sluigi } 209898943Sluigi 209998943Sluigi /* Rule number */ 210098943Sluigi while (ac && isdigit(**av)) { 210198943Sluigi i = atoi(*av); av++; ac--; 210298943Sluigi if (do_pipe) { 210398943Sluigi if (do_pipe == 1) 210498943Sluigi pipe.pipe_nr = i; 210598943Sluigi else 210698943Sluigi pipe.fs.fs_nr = i; 2107117328Sluigi i = do_cmd(IP_DUMMYNET_DEL, &pipe, sizeof pipe); 210898943Sluigi if (i) { 210998943Sluigi exitval = 1; 211098943Sluigi warn("rule %u: setsockopt(IP_DUMMYNET_DEL)", 211198943Sluigi do_pipe == 1 ? pipe.pipe_nr : 211298943Sluigi pipe.fs.fs_nr); 211398943Sluigi } 211498943Sluigi } else { 2115101978Sluigi rulenum = (i & 0xffff) | (do_set << 24); 2116117328Sluigi i = do_cmd(IP_FW_DEL, &rulenum, sizeof rulenum); 211798943Sluigi if (i) { 211898943Sluigi exitval = EX_UNAVAILABLE; 211998943Sluigi warn("rule %u: setsockopt(IP_FW_DEL)", 212098943Sluigi rulenum); 212198943Sluigi } 212298943Sluigi } 212398943Sluigi } 212498943Sluigi if (exitval != EX_OK) 212598943Sluigi exit(exitval); 212698943Sluigi} 212798943Sluigi 212898943Sluigi 212998943Sluigi/* 213098943Sluigi * fill the interface structure. We do not check the name as we can 213198943Sluigi * create interfaces dynamically, so checking them at insert time 213298943Sluigi * makes relatively little sense. 213398943Sluigi * A '*' following the name means any unit. 213498943Sluigi */ 213598943Sluigistatic void 213698943Sluigifill_iface(ipfw_insn_if *cmd, char *arg) 213798943Sluigi{ 213898943Sluigi cmd->name[0] = '\0'; 213998943Sluigi cmd->o.len |= F_INSN_SIZE(ipfw_insn_if); 214098943Sluigi 214198943Sluigi /* Parse the interface or address */ 214298943Sluigi if (!strcmp(arg, "any")) 214398943Sluigi cmd->o.len = 0; /* effectively ignore this command */ 214498943Sluigi else if (!isdigit(*arg)) { 214598943Sluigi char *q; 214698943Sluigi 214798943Sluigi strncpy(cmd->name, arg, sizeof(cmd->name)); 214898943Sluigi cmd->name[sizeof(cmd->name) - 1] = '\0'; 214998943Sluigi /* find first digit or wildcard */ 215098943Sluigi for (q = cmd->name; *q && !isdigit(*q) && *q != '*'; q++) 215198943Sluigi continue; 215298943Sluigi cmd->p.unit = (*q == '*') ? -1 : atoi(q); 215398943Sluigi *q = '\0'; 215498943Sluigi } else if (!inet_aton(arg, &cmd->p.ip)) 215598943Sluigi errx(EX_DATAERR, "bad ip address ``%s''", arg); 215698943Sluigi} 215798943Sluigi 215898943Sluigi/* 215998943Sluigi * the following macro returns an error message if we run out of 216098943Sluigi * arguments. 216198943Sluigi */ 216298943Sluigi#define NEED1(msg) {if (!ac) errx(EX_USAGE, msg);} 216398943Sluigi 216498943Sluigistatic void 216598943Sluigiconfig_pipe(int ac, char **av) 216698943Sluigi{ 216798943Sluigi struct dn_pipe pipe; 216898943Sluigi int i; 216998943Sluigi char *end; 2170117328Sluigi uint32_t a; 217198943Sluigi void *par = NULL; 217298943Sluigi 217398943Sluigi memset(&pipe, 0, sizeof pipe); 217498943Sluigi 217598943Sluigi av++; ac--; 217698943Sluigi /* Pipe number */ 217798943Sluigi if (ac && isdigit(**av)) { 217898943Sluigi i = atoi(*av); av++; ac--; 217998943Sluigi if (do_pipe == 1) 218098943Sluigi pipe.pipe_nr = i; 218198943Sluigi else 218298943Sluigi pipe.fs.fs_nr = i; 218398943Sluigi } 218499475Sluigi while (ac > 0) { 218598943Sluigi double d; 218698943Sluigi int tok = match_token(dummynet_params, *av); 218798943Sluigi ac--; av++; 218898943Sluigi 218998943Sluigi switch(tok) { 2190101978Sluigi case TOK_NOERROR: 2191101978Sluigi pipe.fs.flags_fs |= DN_NOERROR; 2192101978Sluigi break; 2193101978Sluigi 219498943Sluigi case TOK_PLR: 219598943Sluigi NEED1("plr needs argument 0..1\n"); 219698943Sluigi d = strtod(av[0], NULL); 219798943Sluigi if (d > 1) 219898943Sluigi d = 1; 219998943Sluigi else if (d < 0) 220098943Sluigi d = 0; 220198943Sluigi pipe.fs.plr = (int)(d*0x7fffffff); 220298943Sluigi ac--; av++; 220398943Sluigi break; 220498943Sluigi 220598943Sluigi case TOK_QUEUE: 220698943Sluigi NEED1("queue needs queue size\n"); 220798943Sluigi end = NULL; 220898943Sluigi pipe.fs.qsize = strtoul(av[0], &end, 0); 220998943Sluigi if (*end == 'K' || *end == 'k') { 221098943Sluigi pipe.fs.flags_fs |= DN_QSIZE_IS_BYTES; 221198943Sluigi pipe.fs.qsize *= 1024; 221298943Sluigi } else if (*end == 'B' || !strncmp(end, "by", 2)) { 221398943Sluigi pipe.fs.flags_fs |= DN_QSIZE_IS_BYTES; 221498943Sluigi } 221598943Sluigi ac--; av++; 221698943Sluigi break; 221798943Sluigi 221898943Sluigi case TOK_BUCKETS: 221998943Sluigi NEED1("buckets needs argument\n"); 222098943Sluigi pipe.fs.rq_size = strtoul(av[0], NULL, 0); 222198943Sluigi ac--; av++; 222298943Sluigi break; 222398943Sluigi 222498943Sluigi case TOK_MASK: 222598943Sluigi NEED1("mask needs mask specifier\n"); 222698943Sluigi /* 222798943Sluigi * per-flow queue, mask is dst_ip, dst_port, 222898943Sluigi * src_ip, src_port, proto measured in bits 222998943Sluigi */ 223098943Sluigi par = NULL; 223198943Sluigi 223298943Sluigi pipe.fs.flow_mask.dst_ip = 0; 223398943Sluigi pipe.fs.flow_mask.src_ip = 0; 223498943Sluigi pipe.fs.flow_mask.dst_port = 0; 223598943Sluigi pipe.fs.flow_mask.src_port = 0; 223698943Sluigi pipe.fs.flow_mask.proto = 0; 223798943Sluigi end = NULL; 223898943Sluigi 223998943Sluigi while (ac >= 1) { 2240117328Sluigi uint32_t *p32 = NULL; 2241117328Sluigi uint16_t *p16 = NULL; 224298943Sluigi 224398943Sluigi tok = match_token(dummynet_params, *av); 224498943Sluigi ac--; av++; 224598943Sluigi switch(tok) { 224698943Sluigi case TOK_ALL: 224798943Sluigi /* 224898943Sluigi * special case, all bits significant 224998943Sluigi */ 225098943Sluigi pipe.fs.flow_mask.dst_ip = ~0; 225198943Sluigi pipe.fs.flow_mask.src_ip = ~0; 225298943Sluigi pipe.fs.flow_mask.dst_port = ~0; 225398943Sluigi pipe.fs.flow_mask.src_port = ~0; 225498943Sluigi pipe.fs.flow_mask.proto = ~0; 225598943Sluigi pipe.fs.flags_fs |= DN_HAVE_FLOW_MASK; 225698943Sluigi goto end_mask; 225798943Sluigi 225898943Sluigi case TOK_DSTIP: 225998943Sluigi p32 = &pipe.fs.flow_mask.dst_ip; 226098943Sluigi break; 226198943Sluigi 226298943Sluigi case TOK_SRCIP: 226398943Sluigi p32 = &pipe.fs.flow_mask.src_ip; 226498943Sluigi break; 226598943Sluigi 226698943Sluigi case TOK_DSTPORT: 226798943Sluigi p16 = &pipe.fs.flow_mask.dst_port; 226898943Sluigi break; 226998943Sluigi 227098943Sluigi case TOK_SRCPORT: 227198943Sluigi p16 = &pipe.fs.flow_mask.src_port; 227298943Sluigi break; 227398943Sluigi 227498943Sluigi case TOK_PROTO: 227598943Sluigi break; 227698943Sluigi 227798943Sluigi default: 227898943Sluigi ac++; av--; /* backtrack */ 227998943Sluigi goto end_mask; 228098943Sluigi } 228198943Sluigi if (ac < 1) 228298943Sluigi errx(EX_USAGE, "mask: value missing"); 228398943Sluigi if (*av[0] == '/') { 228498943Sluigi a = strtoul(av[0]+1, &end, 0); 228598943Sluigi a = (a == 32) ? ~0 : (1 << a) - 1; 2286106505Smaxim } else 228799909Sluigi a = strtoul(av[0], &end, 0); 228898943Sluigi if (p32 != NULL) 228998943Sluigi *p32 = a; 229098943Sluigi else if (p16 != NULL) { 229198943Sluigi if (a > 65535) 229298943Sluigi errx(EX_DATAERR, 229398943Sluigi "mask: must be 16 bit"); 2294117328Sluigi *p16 = (uint16_t)a; 229598943Sluigi } else { 229698943Sluigi if (a > 255) 229798943Sluigi errx(EX_DATAERR, 229898943Sluigi "mask: must be 8 bit"); 2299117328Sluigi pipe.fs.flow_mask.proto = (uint8_t)a; 230098943Sluigi } 230198943Sluigi if (a != 0) 230298943Sluigi pipe.fs.flags_fs |= DN_HAVE_FLOW_MASK; 230398943Sluigi ac--; av++; 230498943Sluigi } /* end while, config masks */ 230598943Sluigiend_mask: 230698943Sluigi break; 230798943Sluigi 230898943Sluigi case TOK_RED: 230998943Sluigi case TOK_GRED: 231098943Sluigi NEED1("red/gred needs w_q/min_th/max_th/max_p\n"); 231198943Sluigi pipe.fs.flags_fs |= DN_IS_RED; 231298943Sluigi if (tok == TOK_GRED) 231398943Sluigi pipe.fs.flags_fs |= DN_IS_GENTLE_RED; 231498943Sluigi /* 231598943Sluigi * the format for parameters is w_q/min_th/max_th/max_p 231698943Sluigi */ 231798943Sluigi if ((end = strsep(&av[0], "/"))) { 231898943Sluigi double w_q = strtod(end, NULL); 231998943Sluigi if (w_q > 1 || w_q <= 0) 232098943Sluigi errx(EX_DATAERR, "0 < w_q <= 1"); 232198943Sluigi pipe.fs.w_q = (int) (w_q * (1 << SCALE_RED)); 232298943Sluigi } 232398943Sluigi if ((end = strsep(&av[0], "/"))) { 232498943Sluigi pipe.fs.min_th = strtoul(end, &end, 0); 232598943Sluigi if (*end == 'K' || *end == 'k') 232698943Sluigi pipe.fs.min_th *= 1024; 232798943Sluigi } 232898943Sluigi if ((end = strsep(&av[0], "/"))) { 232998943Sluigi pipe.fs.max_th = strtoul(end, &end, 0); 233098943Sluigi if (*end == 'K' || *end == 'k') 233198943Sluigi pipe.fs.max_th *= 1024; 233298943Sluigi } 233398943Sluigi if ((end = strsep(&av[0], "/"))) { 233498943Sluigi double max_p = strtod(end, NULL); 233598943Sluigi if (max_p > 1 || max_p <= 0) 233698943Sluigi errx(EX_DATAERR, "0 < max_p <= 1"); 233798943Sluigi pipe.fs.max_p = (int)(max_p * (1 << SCALE_RED)); 233898943Sluigi } 233998943Sluigi ac--; av++; 234098943Sluigi break; 234198943Sluigi 234298943Sluigi case TOK_DROPTAIL: 234398943Sluigi pipe.fs.flags_fs &= ~(DN_IS_RED|DN_IS_GENTLE_RED); 234498943Sluigi break; 2345106505Smaxim 234698943Sluigi case TOK_BW: 234798943Sluigi NEED1("bw needs bandwidth or interface\n"); 234898943Sluigi if (do_pipe != 1) 234998943Sluigi errx(EX_DATAERR, "bandwidth only valid for pipes"); 235098943Sluigi /* 235198943Sluigi * set clocking interface or bandwidth value 235298943Sluigi */ 235398943Sluigi if (av[0][0] >= 'a' && av[0][0] <= 'z') { 235498943Sluigi int l = sizeof(pipe.if_name)-1; 235598943Sluigi /* interface name */ 235698943Sluigi strncpy(pipe.if_name, av[0], l); 235798943Sluigi pipe.if_name[l] = '\0'; 235898943Sluigi pipe.bandwidth = 0; 235998943Sluigi } else { 236098943Sluigi pipe.if_name[0] = '\0'; 236198943Sluigi pipe.bandwidth = strtoul(av[0], &end, 0); 236298943Sluigi if (*end == 'K' || *end == 'k') { 236398943Sluigi end++; 236498943Sluigi pipe.bandwidth *= 1000; 236598943Sluigi } else if (*end == 'M') { 236698943Sluigi end++; 236798943Sluigi pipe.bandwidth *= 1000000; 236898943Sluigi } 236998943Sluigi if (*end == 'B' || !strncmp(end, "by", 2)) 237098943Sluigi pipe.bandwidth *= 8; 237198943Sluigi if (pipe.bandwidth < 0) 237298943Sluigi errx(EX_DATAERR, "bandwidth too large"); 237398943Sluigi } 237498943Sluigi ac--; av++; 237598943Sluigi break; 237698943Sluigi 237798943Sluigi case TOK_DELAY: 237898943Sluigi if (do_pipe != 1) 237998943Sluigi errx(EX_DATAERR, "delay only valid for pipes"); 238098943Sluigi NEED1("delay needs argument 0..10000ms\n"); 238198943Sluigi pipe.delay = strtoul(av[0], NULL, 0); 238298943Sluigi ac--; av++; 238398943Sluigi break; 238498943Sluigi 238598943Sluigi case TOK_WEIGHT: 238698943Sluigi if (do_pipe == 1) 238798943Sluigi errx(EX_DATAERR,"weight only valid for queues"); 238898943Sluigi NEED1("weight needs argument 0..100\n"); 238998943Sluigi pipe.fs.weight = strtoul(av[0], &end, 0); 239098943Sluigi ac--; av++; 239198943Sluigi break; 239298943Sluigi 239398943Sluigi case TOK_PIPE: 239498943Sluigi if (do_pipe == 1) 239598943Sluigi errx(EX_DATAERR,"pipe only valid for queues"); 239698943Sluigi NEED1("pipe needs pipe_number\n"); 239798943Sluigi pipe.fs.parent_nr = strtoul(av[0], &end, 0); 239898943Sluigi ac--; av++; 239998943Sluigi break; 240098943Sluigi 240198943Sluigi default: 240298943Sluigi errx(EX_DATAERR, "unrecognised option ``%s''", *av); 240398943Sluigi } 240498943Sluigi } 240598943Sluigi if (do_pipe == 1) { 240698943Sluigi if (pipe.pipe_nr == 0) 240798943Sluigi errx(EX_DATAERR, "pipe_nr must be > 0"); 240898943Sluigi if (pipe.delay > 10000) 240998943Sluigi errx(EX_DATAERR, "delay must be < 10000"); 241098943Sluigi } else { /* do_pipe == 2, queue */ 241198943Sluigi if (pipe.fs.parent_nr == 0) 241298943Sluigi errx(EX_DATAERR, "pipe must be > 0"); 241398943Sluigi if (pipe.fs.weight >100) 241498943Sluigi errx(EX_DATAERR, "weight must be <= 100"); 241598943Sluigi } 241698943Sluigi if (pipe.fs.flags_fs & DN_QSIZE_IS_BYTES) { 241798943Sluigi if (pipe.fs.qsize > 1024*1024) 241898943Sluigi errx(EX_DATAERR, "queue size must be < 1MB"); 241998943Sluigi } else { 242098943Sluigi if (pipe.fs.qsize > 100) 242198943Sluigi errx(EX_DATAERR, "2 <= queue size <= 100"); 242298943Sluigi } 242398943Sluigi if (pipe.fs.flags_fs & DN_IS_RED) { 242498943Sluigi size_t len; 242598943Sluigi int lookup_depth, avg_pkt_size; 242698943Sluigi double s, idle, weight, w_q; 242798943Sluigi struct clockinfo clock; 242898943Sluigi int t; 242998943Sluigi 243098943Sluigi if (pipe.fs.min_th >= pipe.fs.max_th) 243198943Sluigi errx(EX_DATAERR, "min_th %d must be < than max_th %d", 243298943Sluigi pipe.fs.min_th, pipe.fs.max_th); 243398943Sluigi if (pipe.fs.max_th == 0) 243498943Sluigi errx(EX_DATAERR, "max_th must be > 0"); 243598943Sluigi 243698943Sluigi len = sizeof(int); 243798943Sluigi if (sysctlbyname("net.inet.ip.dummynet.red_lookup_depth", 243898943Sluigi &lookup_depth, &len, NULL, 0) == -1) 243998943Sluigi 244098943Sluigi errx(1, "sysctlbyname(\"%s\")", 244198943Sluigi "net.inet.ip.dummynet.red_lookup_depth"); 244298943Sluigi if (lookup_depth == 0) 244398943Sluigi errx(EX_DATAERR, "net.inet.ip.dummynet.red_lookup_depth" 244498943Sluigi " must be greater than zero"); 244598943Sluigi 244698943Sluigi len = sizeof(int); 244798943Sluigi if (sysctlbyname("net.inet.ip.dummynet.red_avg_pkt_size", 244898943Sluigi &avg_pkt_size, &len, NULL, 0) == -1) 244998943Sluigi 245098943Sluigi errx(1, "sysctlbyname(\"%s\")", 245198943Sluigi "net.inet.ip.dummynet.red_avg_pkt_size"); 245298943Sluigi if (avg_pkt_size == 0) 245398943Sluigi errx(EX_DATAERR, 245498943Sluigi "net.inet.ip.dummynet.red_avg_pkt_size must" 245598943Sluigi " be greater than zero"); 245698943Sluigi 245798943Sluigi len = sizeof(struct clockinfo); 245898943Sluigi if (sysctlbyname("kern.clockrate", &clock, &len, NULL, 0) == -1) 245998943Sluigi errx(1, "sysctlbyname(\"%s\")", "kern.clockrate"); 246098943Sluigi 246198943Sluigi /* 246298943Sluigi * Ticks needed for sending a medium-sized packet. 246398943Sluigi * Unfortunately, when we are configuring a WF2Q+ queue, we 246498943Sluigi * do not have bandwidth information, because that is stored 246598943Sluigi * in the parent pipe, and also we have multiple queues 246698943Sluigi * competing for it. So we set s=0, which is not very 246798943Sluigi * correct. But on the other hand, why do we want RED with 246898943Sluigi * WF2Q+ ? 246998943Sluigi */ 247098943Sluigi if (pipe.bandwidth==0) /* this is a WF2Q+ queue */ 247198943Sluigi s = 0; 247298943Sluigi else 247398943Sluigi s = clock.hz * avg_pkt_size * 8 / pipe.bandwidth; 247498943Sluigi 247598943Sluigi /* 247698943Sluigi * max idle time (in ticks) before avg queue size becomes 0. 247798943Sluigi * NOTA: (3/w_q) is approx the value x so that 247898943Sluigi * (1-w_q)^x < 10^-3. 247998943Sluigi */ 248098943Sluigi w_q = ((double)pipe.fs.w_q) / (1 << SCALE_RED); 248198943Sluigi idle = s * 3. / w_q; 248298943Sluigi pipe.fs.lookup_step = (int)idle / lookup_depth; 248398943Sluigi if (!pipe.fs.lookup_step) 248498943Sluigi pipe.fs.lookup_step = 1; 248598943Sluigi weight = 1 - w_q; 248698943Sluigi for (t = pipe.fs.lookup_step; t > 0; --t) 248798943Sluigi weight *= weight; 248898943Sluigi pipe.fs.lookup_weight = (int)(weight * (1 << SCALE_RED)); 248998943Sluigi } 2490117328Sluigi i = do_cmd(IP_DUMMYNET_CONFIGURE, &pipe, sizeof pipe); 249198943Sluigi if (i) 249298943Sluigi err(1, "setsockopt(%s)", "IP_DUMMYNET_CONFIGURE"); 249398943Sluigi} 249498943Sluigi 249598943Sluigistatic void 249698943Sluigiget_mac_addr_mask(char *p, u_char *addr, u_char *mask) 249798943Sluigi{ 249898943Sluigi int i, l; 249998943Sluigi 250098943Sluigi for (i=0; i<6; i++) 250198943Sluigi addr[i] = mask[i] = 0; 250298943Sluigi if (!strcmp(p, "any")) 250398943Sluigi return; 250498943Sluigi 250598943Sluigi for (i=0; *p && i<6;i++, p++) { 250698943Sluigi addr[i] = strtol(p, &p, 16); 250798943Sluigi if (*p != ':') /* we start with the mask */ 250898943Sluigi break; 250998943Sluigi } 251098943Sluigi if (*p == '/') { /* mask len */ 251198943Sluigi l = strtol(p+1, &p, 0); 251298943Sluigi for (i=0; l>0; l -=8, i++) 251398943Sluigi mask[i] = (l >=8) ? 0xff : (~0) << (8-l); 251498943Sluigi } else if (*p == '&') { /* mask */ 251598943Sluigi for (i=0, p++; *p && i<6;i++, p++) { 251698943Sluigi mask[i] = strtol(p, &p, 16); 251798943Sluigi if (*p != ':') 251898943Sluigi break; 251998943Sluigi } 252098943Sluigi } else if (*p == '\0') { 252198943Sluigi for (i=0; i<6; i++) 252298943Sluigi mask[i] = 0xff; 252398943Sluigi } 252498943Sluigi for (i=0; i<6; i++) 252598943Sluigi addr[i] &= mask[i]; 252698943Sluigi} 252798943Sluigi 252898943Sluigi/* 252998943Sluigi * helper function, updates the pointer to cmd with the length 253098943Sluigi * of the current command, and also cleans up the first word of 253198943Sluigi * the new command in case it has been clobbered before. 253298943Sluigi */ 253398943Sluigistatic ipfw_insn * 253498943Sluiginext_cmd(ipfw_insn *cmd) 253598943Sluigi{ 253698943Sluigi cmd += F_LEN(cmd); 253798943Sluigi bzero(cmd, sizeof(*cmd)); 253898943Sluigi return cmd; 253998943Sluigi} 254098943Sluigi 254198943Sluigi/* 254298943Sluigi * A function to fill simple commands of size 1. 254398943Sluigi * Existing flags are preserved. 254498943Sluigi */ 254598943Sluigistatic void 2546117328Sluigifill_cmd(ipfw_insn *cmd, enum ipfw_opcodes opcode, int flags, uint16_t arg) 254798943Sluigi{ 254898943Sluigi cmd->opcode = opcode; 254998943Sluigi cmd->len = ((cmd->len | flags) & (F_NOT | F_OR)) | 1; 255098943Sluigi cmd->arg1 = arg; 255198943Sluigi} 255298943Sluigi 255398943Sluigi/* 255498943Sluigi * Fetch and add the MAC address and type, with masks. This generates one or 255598943Sluigi * two microinstructions, and returns the pointer to the last one. 255698943Sluigi */ 255798943Sluigistatic ipfw_insn * 255898943Sluigiadd_mac(ipfw_insn *cmd, int ac, char *av[]) 255998943Sluigi{ 2560102087Sluigi ipfw_insn_mac *mac; 256198943Sluigi 2562102087Sluigi if (ac < 2) 2563102098Sluigi errx(EX_DATAERR, "MAC dst src"); 256498943Sluigi 256598943Sluigi cmd->opcode = O_MACADDR2; 256698943Sluigi cmd->len = (cmd->len & (F_NOT | F_OR)) | F_INSN_SIZE(ipfw_insn_mac); 256798943Sluigi 256898943Sluigi mac = (ipfw_insn_mac *)cmd; 2569101978Sluigi get_mac_addr_mask(av[0], mac->addr, mac->mask); /* dst */ 257098943Sluigi get_mac_addr_mask(av[1], &(mac->addr[6]), &(mac->mask[6])); /* src */ 2571102087Sluigi return cmd; 2572102087Sluigi} 257398943Sluigi 2574102087Sluigistatic ipfw_insn * 2575102087Sluigiadd_mactype(ipfw_insn *cmd, int ac, char *av) 2576102087Sluigi{ 2577102087Sluigi if (ac < 1) 2578102087Sluigi errx(EX_DATAERR, "missing MAC type"); 2579102087Sluigi if (strcmp(av, "any") != 0) { /* we have a non-null type */ 2580102087Sluigi fill_newports((ipfw_insn_u16 *)cmd, av, IPPROTO_ETHERTYPE); 258198943Sluigi cmd->opcode = O_MAC_TYPE; 2582102087Sluigi return cmd; 2583102087Sluigi } else 2584102087Sluigi return NULL; 2585102087Sluigi} 258698943Sluigi 2587102087Sluigistatic ipfw_insn * 2588102087Sluigiadd_proto(ipfw_insn *cmd, char *av) 2589102087Sluigi{ 2590102087Sluigi struct protoent *pe; 2591102087Sluigi u_char proto = 0; 2592102087Sluigi 2593102087Sluigi if (!strncmp(av, "all", strlen(av))) 2594102087Sluigi ; /* same as "ip" */ 2595102087Sluigi else if ((proto = atoi(av)) > 0) 2596102087Sluigi ; /* all done! */ 2597102087Sluigi else if ((pe = getprotobyname(av)) != NULL) 2598102087Sluigi proto = pe->p_proto; 2599102087Sluigi else 2600102098Sluigi return NULL; 2601102087Sluigi if (proto != IPPROTO_IP) 2602102087Sluigi fill_cmd(cmd, O_PROTO, 0, proto); 260398943Sluigi return cmd; 260498943Sluigi} 260598943Sluigi 2606102087Sluigistatic ipfw_insn * 2607102087Sluigiadd_srcip(ipfw_insn *cmd, char *av) 2608102087Sluigi{ 2609102087Sluigi fill_ip((ipfw_insn_ip *)cmd, av); 2610102087Sluigi if (cmd->opcode == O_IP_DST_SET) /* set */ 2611102087Sluigi cmd->opcode = O_IP_SRC_SET; 2612102087Sluigi else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) /* me */ 2613102087Sluigi cmd->opcode = O_IP_SRC_ME; 2614102087Sluigi else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn_u32)) /* one IP */ 2615102087Sluigi cmd->opcode = O_IP_SRC; 2616117328Sluigi else /* addr/mask */ 2617102087Sluigi cmd->opcode = O_IP_SRC_MASK; 2618102087Sluigi return cmd; 2619102087Sluigi} 2620102087Sluigi 2621102087Sluigistatic ipfw_insn * 2622102087Sluigiadd_dstip(ipfw_insn *cmd, char *av) 2623102087Sluigi{ 2624102087Sluigi fill_ip((ipfw_insn_ip *)cmd, av); 2625102087Sluigi if (cmd->opcode == O_IP_DST_SET) /* set */ 2626102087Sluigi ; 2627102087Sluigi else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) /* me */ 2628102087Sluigi cmd->opcode = O_IP_DST_ME; 2629102087Sluigi else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn_u32)) /* one IP */ 2630102087Sluigi cmd->opcode = O_IP_DST; 2631117328Sluigi else /* addr/mask */ 2632102087Sluigi cmd->opcode = O_IP_DST_MASK; 2633102087Sluigi return cmd; 2634102087Sluigi} 2635102087Sluigi 2636102087Sluigistatic ipfw_insn * 2637102087Sluigiadd_ports(ipfw_insn *cmd, char *av, u_char proto, int opcode) 2638102087Sluigi{ 2639102087Sluigi if (!strncmp(av, "any", strlen(av))) { 2640102087Sluigi return NULL; 2641102087Sluigi } else if (fill_newports((ipfw_insn_u16 *)cmd, av, proto)) { 2642102087Sluigi /* XXX todo: check that we have a protocol with ports */ 2643102087Sluigi cmd->opcode = opcode; 2644102087Sluigi return cmd; 2645102087Sluigi } 2646102087Sluigi return NULL; 2647102087Sluigi} 2648102087Sluigi 264998943Sluigi/* 265098943Sluigi * Parse arguments and assemble the microinstructions which make up a rule. 265198943Sluigi * Rules are added into the 'rulebuf' and then copied in the correct order 265298943Sluigi * into the actual rule. 265398943Sluigi * 265498943Sluigi * The syntax for a rule starts with the action, followed by an 265598943Sluigi * optional log action, and the various match patterns. 2656108533Sschweikh * In the assembled microcode, the first opcode must be an O_PROBE_STATE 265798943Sluigi * (generated if the rule includes a keep-state option), then the 265898943Sluigi * various match patterns, the "log" action, and the actual action. 2659106505Smaxim * 266098943Sluigi */ 266198943Sluigistatic void 266298943Sluigiadd(int ac, char *av[]) 266398943Sluigi{ 266498943Sluigi /* 266598943Sluigi * rules are added into the 'rulebuf' and then copied in 266698943Sluigi * the correct order into the actual rule. 266798943Sluigi * Some things that need to go out of order (prob, action etc.) 266898943Sluigi * go into actbuf[]. 266998943Sluigi */ 2670117328Sluigi static uint32_t rulebuf[255], actbuf[255], cmdbuf[255]; 267198943Sluigi 267298943Sluigi ipfw_insn *src, *dst, *cmd, *action, *prev; 2673102087Sluigi ipfw_insn *first_cmd; /* first match pattern */ 267498943Sluigi 267598943Sluigi struct ip_fw *rule; 267698943Sluigi 267798943Sluigi /* 267898943Sluigi * various flags used to record that we entered some fields. 267998943Sluigi */ 2680101116Sluigi ipfw_insn *have_state = NULL; /* check-state or keep-state */ 268198943Sluigi 268298943Sluigi int i; 268398943Sluigi 268498943Sluigi int open_par = 0; /* open parenthesis ( */ 268598943Sluigi 268698943Sluigi /* proto is here because it is used to fetch ports */ 268798943Sluigi u_char proto = IPPROTO_IP; /* default protocol */ 268898943Sluigi 2689107289Sluigi double match_prob = 1; /* match probability, default is always match */ 2690107289Sluigi 269198943Sluigi bzero(actbuf, sizeof(actbuf)); /* actions go here */ 269298943Sluigi bzero(cmdbuf, sizeof(cmdbuf)); 269398943Sluigi bzero(rulebuf, sizeof(rulebuf)); 269498943Sluigi 269598943Sluigi rule = (struct ip_fw *)rulebuf; 269698943Sluigi cmd = (ipfw_insn *)cmdbuf; 269798943Sluigi action = (ipfw_insn *)actbuf; 269898943Sluigi 269998943Sluigi av++; ac--; 270098943Sluigi 270198943Sluigi /* [rule N] -- Rule number optional */ 270298943Sluigi if (ac && isdigit(**av)) { 270398943Sluigi rule->rulenum = atoi(*av); 270498943Sluigi av++; 270598943Sluigi ac--; 270698943Sluigi } 270798943Sluigi 2708101628Sluigi /* [set N] -- set number (0..30), optional */ 2709101628Sluigi if (ac > 1 && !strncmp(*av, "set", strlen(*av))) { 2710101628Sluigi int set = strtoul(av[1], NULL, 10); 2711101628Sluigi if (set < 0 || set > 30) 2712101628Sluigi errx(EX_DATAERR, "illegal set %s", av[1]); 2713101628Sluigi rule->set = set; 2714101628Sluigi av += 2; ac -= 2; 2715101628Sluigi } 2716101628Sluigi 271798943Sluigi /* [prob D] -- match probability, optional */ 271898943Sluigi if (ac > 1 && !strncmp(*av, "prob", strlen(*av))) { 2719107289Sluigi match_prob = strtod(av[1], NULL); 272098943Sluigi 2721107289Sluigi if (match_prob <= 0 || match_prob > 1) 272298943Sluigi errx(EX_DATAERR, "illegal match prob. %s", av[1]); 272398943Sluigi av += 2; ac -= 2; 272498943Sluigi } 272598943Sluigi 272698943Sluigi /* action -- mandatory */ 272798943Sluigi NEED1("missing action"); 272898943Sluigi i = match_token(rule_actions, *av); 272998943Sluigi ac--; av++; 273098943Sluigi action->len = 1; /* default */ 273198943Sluigi switch(i) { 273298943Sluigi case TOK_CHECKSTATE: 2733101116Sluigi have_state = action; 273498943Sluigi action->opcode = O_CHECK_STATE; 273598943Sluigi break; 273698943Sluigi 273798943Sluigi case TOK_ACCEPT: 273898943Sluigi action->opcode = O_ACCEPT; 273998943Sluigi break; 274098943Sluigi 274198943Sluigi case TOK_DENY: 274298943Sluigi action->opcode = O_DENY; 274399475Sluigi action->arg1 = 0; 274498943Sluigi break; 274598943Sluigi 274699475Sluigi case TOK_REJECT: 274799475Sluigi action->opcode = O_REJECT; 274899475Sluigi action->arg1 = ICMP_UNREACH_HOST; 274999475Sluigi break; 275099475Sluigi 275199475Sluigi case TOK_RESET: 275299475Sluigi action->opcode = O_REJECT; 275399475Sluigi action->arg1 = ICMP_REJECT_RST; 275499475Sluigi break; 275599475Sluigi 275699475Sluigi case TOK_UNREACH: 275799475Sluigi action->opcode = O_REJECT; 275899475Sluigi NEED1("missing reject code"); 275999475Sluigi fill_reject_code(&action->arg1, *av); 276099475Sluigi ac--; av++; 276199475Sluigi break; 276299475Sluigi 276398943Sluigi case TOK_COUNT: 276498943Sluigi action->opcode = O_COUNT; 276598943Sluigi break; 276698943Sluigi 276798943Sluigi case TOK_QUEUE: 276898943Sluigi case TOK_PIPE: 276998943Sluigi action->len = F_INSN_SIZE(ipfw_insn_pipe); 277098943Sluigi case TOK_SKIPTO: 277198943Sluigi if (i == TOK_QUEUE) 277298943Sluigi action->opcode = O_QUEUE; 277398943Sluigi else if (i == TOK_PIPE) 277498943Sluigi action->opcode = O_PIPE; 277598943Sluigi else if (i == TOK_SKIPTO) 277698943Sluigi action->opcode = O_SKIPTO; 277798943Sluigi NEED1("missing skipto/pipe/queue number"); 277898943Sluigi action->arg1 = strtoul(*av, NULL, 10); 277998943Sluigi av++; ac--; 278098943Sluigi break; 278198943Sluigi 278298943Sluigi case TOK_DIVERT: 278398943Sluigi case TOK_TEE: 278498943Sluigi action->opcode = (i == TOK_DIVERT) ? O_DIVERT : O_TEE; 278598943Sluigi NEED1("missing divert/tee port"); 278698943Sluigi action->arg1 = strtoul(*av, NULL, 0); 278798943Sluigi if (action->arg1 == 0) { 278898943Sluigi struct servent *s; 278998943Sluigi setservent(1); 279098943Sluigi s = getservbyname(av[0], "divert"); 279198943Sluigi if (s != NULL) 279298943Sluigi action->arg1 = ntohs(s->s_port); 279398943Sluigi else 279498943Sluigi errx(EX_DATAERR, "illegal divert/tee port"); 279598943Sluigi } 279698943Sluigi ac--; av++; 279798943Sluigi break; 279898943Sluigi 279998943Sluigi case TOK_FORWARD: { 280098943Sluigi ipfw_insn_sa *p = (ipfw_insn_sa *)action; 280198943Sluigi char *s, *end; 280298943Sluigi 280398943Sluigi NEED1("missing forward address[:port]"); 280498943Sluigi 280598943Sluigi action->opcode = O_FORWARD_IP; 280698943Sluigi action->len = F_INSN_SIZE(ipfw_insn_sa); 280798943Sluigi 280898943Sluigi p->sa.sin_len = sizeof(struct sockaddr_in); 280998943Sluigi p->sa.sin_family = AF_INET; 281098943Sluigi p->sa.sin_port = 0; 281198943Sluigi /* 281298943Sluigi * locate the address-port separator (':' or ',') 281398943Sluigi */ 281498943Sluigi s = strchr(*av, ':'); 281598943Sluigi if (s == NULL) 281698943Sluigi s = strchr(*av, ','); 281798943Sluigi if (s != NULL) { 281898943Sluigi *(s++) = '\0'; 281998943Sluigi i = strtoport(s, &end, 0 /* base */, 0 /* proto */); 282098943Sluigi if (s == end) 282198943Sluigi errx(EX_DATAERR, 282298943Sluigi "illegal forwarding port ``%s''", s); 2823103241Sluigi p->sa.sin_port = (u_short)i; 282498943Sluigi } 282598943Sluigi lookup_host(*av, &(p->sa.sin_addr)); 282698943Sluigi } 282798943Sluigi ac--; av++; 282898943Sluigi break; 282998943Sluigi 283098943Sluigi default: 2831102087Sluigi errx(EX_DATAERR, "invalid action %s\n", av[-1]); 283298943Sluigi } 283398943Sluigi action = next_cmd(action); 283498943Sluigi 283598943Sluigi /* 283698943Sluigi * [log [logamount N]] -- log, optional 283798943Sluigi * 283898943Sluigi * If exists, it goes first in the cmdbuf, but then it is 283998943Sluigi * skipped in the copy section to the end of the buffer. 284098943Sluigi */ 284198943Sluigi if (ac && !strncmp(*av, "log", strlen(*av))) { 284298943Sluigi ipfw_insn_log *c = (ipfw_insn_log *)cmd; 284398943Sluigi 284498943Sluigi cmd->len = F_INSN_SIZE(ipfw_insn_log); 284598943Sluigi cmd->opcode = O_LOG; 284698943Sluigi av++; ac--; 284798943Sluigi if (ac && !strncmp(*av, "logamount", strlen(*av))) { 284898943Sluigi ac--; av++; 284998943Sluigi NEED1("logamount requires argument"); 285098943Sluigi c->max_log = atoi(*av); 285198943Sluigi if (c->max_log < 0) 285298943Sluigi errx(EX_DATAERR, "logamount must be positive"); 285398943Sluigi ac--; av++; 285498943Sluigi } 285598943Sluigi cmd = next_cmd(cmd); 285698943Sluigi } 285798943Sluigi 2858101116Sluigi if (have_state) /* must be a check-state, we are done */ 285998943Sluigi goto done; 286098943Sluigi 286198943Sluigi#define OR_START(target) \ 286298943Sluigi if (ac && (*av[0] == '(' || *av[0] == '{')) { \ 286398943Sluigi if (open_par) \ 286498943Sluigi errx(EX_USAGE, "nested \"(\" not allowed\n"); \ 2865101641Sluigi prev = NULL; \ 286698943Sluigi open_par = 1; \ 286798943Sluigi if ( (av[0])[1] == '\0') { \ 286898943Sluigi ac--; av++; \ 286998943Sluigi } else \ 287098943Sluigi (*av)++; \ 287198943Sluigi } \ 287298943Sluigi target: \ 287398943Sluigi 287498943Sluigi 287598943Sluigi#define CLOSE_PAR \ 287698943Sluigi if (open_par) { \ 287798943Sluigi if (ac && ( \ 287898943Sluigi !strncmp(*av, ")", strlen(*av)) || \ 287998943Sluigi !strncmp(*av, "}", strlen(*av)) )) { \ 2880101641Sluigi prev = NULL; \ 288198943Sluigi open_par = 0; \ 288298943Sluigi ac--; av++; \ 288398943Sluigi } else \ 288498943Sluigi errx(EX_USAGE, "missing \")\"\n"); \ 288598943Sluigi } 2886106505Smaxim 288798943Sluigi#define NOT_BLOCK \ 288898943Sluigi if (ac && !strncmp(*av, "not", strlen(*av))) { \ 288998943Sluigi if (cmd->len & F_NOT) \ 289098943Sluigi errx(EX_USAGE, "double \"not\" not allowed\n"); \ 289198943Sluigi cmd->len |= F_NOT; \ 289298943Sluigi ac--; av++; \ 289398943Sluigi } 289498943Sluigi 289598943Sluigi#define OR_BLOCK(target) \ 289698943Sluigi if (ac && !strncmp(*av, "or", strlen(*av))) { \ 289798943Sluigi if (prev == NULL || open_par == 0) \ 289898943Sluigi errx(EX_DATAERR, "invalid OR block"); \ 289998943Sluigi prev->len |= F_OR; \ 290098943Sluigi ac--; av++; \ 290198943Sluigi goto target; \ 290298943Sluigi } \ 290398943Sluigi CLOSE_PAR; 290498943Sluigi 2905102087Sluigi first_cmd = cmd; 2906102098Sluigi 2907102098Sluigi#if 0 290898943Sluigi /* 2909102087Sluigi * MAC addresses, optional. 2910102087Sluigi * If we have this, we skip the part "proto from src to dst" 2911102087Sluigi * and jump straight to the option parsing. 2912102087Sluigi */ 2913102087Sluigi NOT_BLOCK; 2914102087Sluigi NEED1("missing protocol"); 2915102087Sluigi if (!strncmp(*av, "MAC", strlen(*av)) || 2916102087Sluigi !strncmp(*av, "mac", strlen(*av))) { 2917102087Sluigi ac--; av++; /* the "MAC" keyword */ 2918102087Sluigi add_mac(cmd, ac, av); /* exits in case of errors */ 2919102087Sluigi cmd = next_cmd(cmd); 2920102087Sluigi ac -= 2; av += 2; /* dst-mac and src-mac */ 2921102087Sluigi NOT_BLOCK; 2922102087Sluigi NEED1("missing mac type"); 2923102087Sluigi if (add_mactype(cmd, ac, av[0])) 2924102087Sluigi cmd = next_cmd(cmd); 2925102087Sluigi ac--; av++; /* any or mac-type */ 2926102087Sluigi goto read_options; 2927102087Sluigi } 2928102098Sluigi#endif 2929102087Sluigi 2930102087Sluigi /* 293198943Sluigi * protocol, mandatory 293298943Sluigi */ 293398943Sluigi OR_START(get_proto); 293498943Sluigi NOT_BLOCK; 293598943Sluigi NEED1("missing protocol"); 2936102087Sluigi if (add_proto(cmd, *av)) { 2937102087Sluigi av++; ac--; 2938102087Sluigi if (F_LEN(cmd) == 0) /* plain IP */ 2939102087Sluigi proto = 0; 2940102087Sluigi else { 2941102087Sluigi proto = cmd->arg1; 2942102087Sluigi prev = cmd; 2943102087Sluigi cmd = next_cmd(cmd); 2944102087Sluigi } 2945102098Sluigi } else if (first_cmd != cmd) { 2946116438Smaxim errx(EX_DATAERR, "invalid protocol ``%s''", *av); 2947102098Sluigi } else 2948102098Sluigi goto read_options; 294998943Sluigi OR_BLOCK(get_proto); 295098943Sluigi 295198943Sluigi /* 2952102087Sluigi * "from", mandatory 295398943Sluigi */ 2954102087Sluigi if (!ac || strncmp(*av, "from", strlen(*av))) 295598943Sluigi errx(EX_USAGE, "missing ``from''"); 295698943Sluigi ac--; av++; 295798943Sluigi 295898943Sluigi /* 295998943Sluigi * source IP, mandatory 296098943Sluigi */ 296198943Sluigi OR_START(source_ip); 296298943Sluigi NOT_BLOCK; /* optional "not" */ 296398943Sluigi NEED1("missing source address"); 2964102087Sluigi if (add_srcip(cmd, *av)) { 2965102087Sluigi ac--; av++; 2966102087Sluigi if (F_LEN(cmd) != 0) { /* ! any */ 2967102087Sluigi prev = cmd; 2968102087Sluigi cmd = next_cmd(cmd); 2969102087Sluigi } 2970102087Sluigi } 297198943Sluigi OR_BLOCK(source_ip); 297298943Sluigi 297398943Sluigi /* 297498943Sluigi * source ports, optional 297598943Sluigi */ 297698943Sluigi NOT_BLOCK; /* optional "not" */ 2977101641Sluigi if (ac) { 2978102087Sluigi if (!strncmp(*av, "any", strlen(*av)) || 2979102087Sluigi add_ports(cmd, *av, proto, O_IP_SRCPORT)) { 2980102087Sluigi ac--; av++; 2981102087Sluigi if (F_LEN(cmd) != 0) 2982102087Sluigi cmd = next_cmd(cmd); 2983101641Sluigi } 298498943Sluigi } 298598943Sluigi 298698943Sluigi /* 2987102087Sluigi * "to", mandatory 298898943Sluigi */ 2989102087Sluigi if (!ac || strncmp(*av, "to", strlen(*av))) 299098943Sluigi errx(EX_USAGE, "missing ``to''"); 299198943Sluigi av++; ac--; 299298943Sluigi 299398943Sluigi /* 299498943Sluigi * destination, mandatory 299598943Sluigi */ 299698943Sluigi OR_START(dest_ip); 299798943Sluigi NOT_BLOCK; /* optional "not" */ 299898943Sluigi NEED1("missing dst address"); 2999102087Sluigi if (add_dstip(cmd, *av)) { 3000102087Sluigi ac--; av++; 3001102087Sluigi if (F_LEN(cmd) != 0) { /* ! any */ 3002102087Sluigi prev = cmd; 3003102087Sluigi cmd = next_cmd(cmd); 3004102087Sluigi } 3005102087Sluigi } 300698943Sluigi OR_BLOCK(dest_ip); 300798943Sluigi 300898943Sluigi /* 300998943Sluigi * dest. ports, optional 301098943Sluigi */ 301198943Sluigi NOT_BLOCK; /* optional "not" */ 3012101641Sluigi if (ac) { 3013102087Sluigi if (!strncmp(*av, "any", strlen(*av)) || 3014102087Sluigi add_ports(cmd, *av, proto, O_IP_DSTPORT)) { 3015102087Sluigi ac--; av++; 3016102087Sluigi if (F_LEN(cmd) != 0) 3017102087Sluigi cmd = next_cmd(cmd); 3018101641Sluigi } 301998943Sluigi } 302098943Sluigi 302198943Sluigiread_options: 3022102087Sluigi if (ac && first_cmd == cmd) { 3023102087Sluigi /* 3024102087Sluigi * nothing specified so far, store in the rule to ease 3025102087Sluigi * printout later. 3026102087Sluigi */ 3027102087Sluigi rule->_pad = 1; 3028102087Sluigi } 302998943Sluigi prev = NULL; 303098943Sluigi while (ac) { 3031101641Sluigi char *s; 3032101641Sluigi ipfw_insn_u32 *cmd32; /* alias for cmd */ 303398943Sluigi 3034101641Sluigi s = *av; 3035101641Sluigi cmd32 = (ipfw_insn_u32 *)cmd; 3036101641Sluigi 303798943Sluigi if (*s == '!') { /* alternate syntax for NOT */ 303898943Sluigi if (cmd->len & F_NOT) 303998943Sluigi errx(EX_USAGE, "double \"not\" not allowed\n"); 304098943Sluigi cmd->len = F_NOT; 304198943Sluigi s++; 304298943Sluigi } 304398943Sluigi i = match_token(rule_options, s); 304498943Sluigi ac--; av++; 304598943Sluigi switch(i) { 304698943Sluigi case TOK_NOT: 304798943Sluigi if (cmd->len & F_NOT) 304898943Sluigi errx(EX_USAGE, "double \"not\" not allowed\n"); 304998943Sluigi cmd->len = F_NOT; 305098943Sluigi break; 305198943Sluigi 305298943Sluigi case TOK_OR: 3053101641Sluigi if (open_par == 0 || prev == NULL) 305498943Sluigi errx(EX_USAGE, "invalid \"or\" block\n"); 305598943Sluigi prev->len |= F_OR; 305698943Sluigi break; 3057101641Sluigi 3058101641Sluigi case TOK_STARTBRACE: 3059101641Sluigi if (open_par) 3060101641Sluigi errx(EX_USAGE, "+nested \"(\" not allowed\n"); 3061101641Sluigi open_par = 1; 3062101641Sluigi break; 3063101641Sluigi 3064101641Sluigi case TOK_ENDBRACE: 3065101641Sluigi if (!open_par) 3066101641Sluigi errx(EX_USAGE, "+missing \")\"\n"); 3067101641Sluigi open_par = 0; 3068102087Sluigi prev = NULL; 3069101641Sluigi break; 3070101641Sluigi 307198943Sluigi case TOK_IN: 307298943Sluigi fill_cmd(cmd, O_IN, 0, 0); 307398943Sluigi break; 307498943Sluigi 307598943Sluigi case TOK_OUT: 307698943Sluigi cmd->len ^= F_NOT; /* toggle F_NOT */ 307798943Sluigi fill_cmd(cmd, O_IN, 0, 0); 307898943Sluigi break; 307998943Sluigi 308098943Sluigi case TOK_FRAG: 308198943Sluigi fill_cmd(cmd, O_FRAG, 0, 0); 308298943Sluigi break; 308398943Sluigi 308498943Sluigi case TOK_LAYER2: 308598943Sluigi fill_cmd(cmd, O_LAYER2, 0, 0); 308698943Sluigi break; 308798943Sluigi 308898943Sluigi case TOK_XMIT: 308998943Sluigi case TOK_RECV: 309098943Sluigi case TOK_VIA: 309198943Sluigi NEED1("recv, xmit, via require interface name" 309298943Sluigi " or address"); 309398943Sluigi fill_iface((ipfw_insn_if *)cmd, av[0]); 309498943Sluigi ac--; av++; 309598943Sluigi if (F_LEN(cmd) == 0) /* not a valid address */ 309698943Sluigi break; 309798943Sluigi if (i == TOK_XMIT) 309898943Sluigi cmd->opcode = O_XMIT; 309998943Sluigi else if (i == TOK_RECV) 310098943Sluigi cmd->opcode = O_RECV; 310198943Sluigi else if (i == TOK_VIA) 310298943Sluigi cmd->opcode = O_VIA; 310398943Sluigi break; 310498943Sluigi 310599475Sluigi case TOK_ICMPTYPES: 310699475Sluigi NEED1("icmptypes requires list of types"); 310799475Sluigi fill_icmptypes((ipfw_insn_u32 *)cmd, *av); 310899475Sluigi av++; ac--; 310999475Sluigi break; 311099475Sluigi 311198943Sluigi case TOK_IPTTL: 311298943Sluigi NEED1("ipttl requires TTL"); 3113116690Sluigi if (strpbrk(*av, "-,")) { 3114116690Sluigi if (!add_ports(cmd, *av, 0, O_IPTTL)) 3115116690Sluigi errx(EX_DATAERR, "invalid ipttl %s", *av); 3116116690Sluigi } else 3117116690Sluigi fill_cmd(cmd, O_IPTTL, 0, strtoul(*av, NULL, 0)); 311898943Sluigi ac--; av++; 311998943Sluigi break; 312098943Sluigi 312198943Sluigi case TOK_IPID: 3122116690Sluigi NEED1("ipid requires id"); 3123116690Sluigi if (strpbrk(*av, "-,")) { 3124116690Sluigi if (!add_ports(cmd, *av, 0, O_IPID)) 3125116690Sluigi errx(EX_DATAERR, "invalid ipid %s", *av); 3126116690Sluigi } else 3127116690Sluigi fill_cmd(cmd, O_IPID, 0, strtoul(*av, NULL, 0)); 312898943Sluigi ac--; av++; 312998943Sluigi break; 313098943Sluigi 313198943Sluigi case TOK_IPLEN: 313298943Sluigi NEED1("iplen requires length"); 3133116690Sluigi if (strpbrk(*av, "-,")) { 3134116690Sluigi if (!add_ports(cmd, *av, 0, O_IPLEN)) 3135116690Sluigi errx(EX_DATAERR, "invalid ip len %s", *av); 3136116690Sluigi } else 3137116690Sluigi fill_cmd(cmd, O_IPLEN, 0, strtoul(*av, NULL, 0)); 313898943Sluigi ac--; av++; 313998943Sluigi break; 314098943Sluigi 314198943Sluigi case TOK_IPVER: 314298943Sluigi NEED1("ipver requires version"); 314398943Sluigi fill_cmd(cmd, O_IPVER, 0, strtoul(*av, NULL, 0)); 314498943Sluigi ac--; av++; 314598943Sluigi break; 314698943Sluigi 314799475Sluigi case TOK_IPPRECEDENCE: 314899475Sluigi NEED1("ipprecedence requires value"); 314999475Sluigi fill_cmd(cmd, O_IPPRECEDENCE, 0, 315099475Sluigi (strtoul(*av, NULL, 0) & 7) << 5); 315199475Sluigi ac--; av++; 315299475Sluigi break; 315399475Sluigi 315498943Sluigi case TOK_IPOPTS: 315598943Sluigi NEED1("missing argument for ipoptions"); 3156101116Sluigi fill_flags(cmd, O_IPOPT, f_ipopts, *av); 315798943Sluigi ac--; av++; 315898943Sluigi break; 315998943Sluigi 316099475Sluigi case TOK_IPTOS: 316199475Sluigi NEED1("missing argument for iptos"); 3162101116Sluigi fill_flags(cmd, O_IPTOS, f_iptos, *av); 316399475Sluigi ac--; av++; 316499475Sluigi break; 316599475Sluigi 316698943Sluigi case TOK_UID: 316798943Sluigi NEED1("uid requires argument"); 316898943Sluigi { 316998943Sluigi char *end; 317098943Sluigi uid_t uid; 317198943Sluigi struct passwd *pwd; 317298943Sluigi 317398943Sluigi cmd->opcode = O_UID; 317498943Sluigi uid = strtoul(*av, &end, 0); 317598943Sluigi pwd = (*end == '\0') ? getpwuid(uid) : getpwnam(*av); 317698943Sluigi if (pwd == NULL) 317798943Sluigi errx(EX_DATAERR, "uid \"%s\" nonexistent", *av); 3178106504Smaxim cmd32->d[0] = pwd->pw_uid; 317998943Sluigi cmd->len = F_INSN_SIZE(ipfw_insn_u32); 318098943Sluigi ac--; av++; 318198943Sluigi } 318298943Sluigi break; 318398943Sluigi 318498943Sluigi case TOK_GID: 318598943Sluigi NEED1("gid requires argument"); 318698943Sluigi { 318798943Sluigi char *end; 318898943Sluigi gid_t gid; 318998943Sluigi struct group *grp; 319098943Sluigi 319198943Sluigi cmd->opcode = O_GID; 319298943Sluigi gid = strtoul(*av, &end, 0); 319398943Sluigi grp = (*end == '\0') ? getgrgid(gid) : getgrnam(*av); 319498943Sluigi if (grp == NULL) 319598943Sluigi errx(EX_DATAERR, "gid \"%s\" nonexistent", *av); 3196106504Smaxim cmd32->d[0] = grp->gr_gid; 319798943Sluigi cmd->len = F_INSN_SIZE(ipfw_insn_u32); 319898943Sluigi ac--; av++; 319998943Sluigi } 320098943Sluigi break; 320198943Sluigi 320298943Sluigi case TOK_ESTAB: 320398943Sluigi fill_cmd(cmd, O_ESTAB, 0, 0); 320498943Sluigi break; 320598943Sluigi 320698943Sluigi case TOK_SETUP: 320798943Sluigi fill_cmd(cmd, O_TCPFLAGS, 0, 320898943Sluigi (TH_SYN) | ( (TH_ACK) & 0xff) <<8 ); 320998943Sluigi break; 321098943Sluigi 321198943Sluigi case TOK_TCPOPTS: 321298943Sluigi NEED1("missing argument for tcpoptions"); 321398943Sluigi fill_flags(cmd, O_TCPOPTS, f_tcpopts, *av); 321498943Sluigi ac--; av++; 321598943Sluigi break; 321698943Sluigi 321798943Sluigi case TOK_TCPSEQ: 321898943Sluigi case TOK_TCPACK: 321998943Sluigi NEED1("tcpseq/tcpack requires argument"); 322098943Sluigi cmd->len = F_INSN_SIZE(ipfw_insn_u32); 322198943Sluigi cmd->opcode = (i == TOK_TCPSEQ) ? O_TCPSEQ : O_TCPACK; 322298943Sluigi cmd32->d[0] = htonl(strtoul(*av, NULL, 0)); 322398943Sluigi ac--; av++; 322498943Sluigi break; 322598943Sluigi 322698943Sluigi case TOK_TCPWIN: 322798943Sluigi NEED1("tcpwin requires length"); 322898943Sluigi fill_cmd(cmd, O_TCPWIN, 0, 322998943Sluigi htons(strtoul(*av, NULL, 0))); 323098943Sluigi ac--; av++; 323198943Sluigi break; 323298943Sluigi 323398943Sluigi case TOK_TCPFLAGS: 323498943Sluigi NEED1("missing argument for tcpflags"); 323598943Sluigi cmd->opcode = O_TCPFLAGS; 323698943Sluigi fill_flags(cmd, O_TCPFLAGS, f_tcpflags, *av); 323798943Sluigi ac--; av++; 323898943Sluigi break; 323998943Sluigi 324098943Sluigi case TOK_KEEPSTATE: 3241101641Sluigi if (open_par) 3242101641Sluigi errx(EX_USAGE, "keep-state cannot be part " 3243101641Sluigi "of an or block"); 324499909Sluigi if (have_state) 3245101116Sluigi errx(EX_USAGE, "only one of keep-state " 324699909Sluigi "and limit is allowed"); 3247101116Sluigi have_state = cmd; 324898943Sluigi fill_cmd(cmd, O_KEEP_STATE, 0, 0); 324998943Sluigi break; 325098943Sluigi 325198943Sluigi case TOK_LIMIT: 3252101641Sluigi if (open_par) 3253101641Sluigi errx(EX_USAGE, "limit cannot be part " 3254101641Sluigi "of an or block"); 325599909Sluigi if (have_state) 3256101116Sluigi errx(EX_USAGE, "only one of keep-state " 325799909Sluigi "and limit is allowed"); 3258101641Sluigi NEED1("limit needs mask and # of connections"); 3259101116Sluigi have_state = cmd; 326098943Sluigi { 326198943Sluigi ipfw_insn_limit *c = (ipfw_insn_limit *)cmd; 326298943Sluigi 326398943Sluigi cmd->len = F_INSN_SIZE(ipfw_insn_limit); 326498943Sluigi cmd->opcode = O_LIMIT; 326598943Sluigi c->limit_mask = 0; 326698943Sluigi c->conn_limit = 0; 326798943Sluigi for (; ac >1 ;) { 326898943Sluigi int val; 326998943Sluigi 327098943Sluigi val = match_token(limit_masks, *av); 327198943Sluigi if (val <= 0) 327298943Sluigi break; 327398943Sluigi c->limit_mask |= val; 327498943Sluigi ac--; av++; 327598943Sluigi } 327698943Sluigi c->conn_limit = atoi(*av); 327798943Sluigi if (c->conn_limit == 0) 327898943Sluigi errx(EX_USAGE, "limit: limit must be >0"); 327998943Sluigi if (c->limit_mask == 0) 328098943Sluigi errx(EX_USAGE, "missing limit mask"); 328198943Sluigi ac--; av++; 328298943Sluigi } 328398943Sluigi break; 328498943Sluigi 3285102087Sluigi case TOK_PROTO: 3286102087Sluigi NEED1("missing protocol"); 3287102087Sluigi if (add_proto(cmd, *av)) { 3288102087Sluigi proto = cmd->arg1; 3289102087Sluigi ac--; av++; 3290102098Sluigi } else 3291116438Smaxim errx(EX_DATAERR, "invalid protocol ``%s''", 3292116438Smaxim *av); 3293102087Sluigi break; 3294106505Smaxim 3295102087Sluigi case TOK_SRCIP: 3296102087Sluigi NEED1("missing source IP"); 3297102087Sluigi if (add_srcip(cmd, *av)) { 3298102087Sluigi ac--; av++; 3299102087Sluigi } 3300102087Sluigi break; 3301102087Sluigi 3302102087Sluigi case TOK_DSTIP: 3303102087Sluigi NEED1("missing destination IP"); 3304102087Sluigi if (add_dstip(cmd, *av)) { 3305102087Sluigi ac--; av++; 3306102087Sluigi } 3307102087Sluigi break; 3308102087Sluigi 3309102087Sluigi case TOK_SRCPORT: 3310102087Sluigi NEED1("missing source port"); 3311102087Sluigi if (!strncmp(*av, "any", strlen(*av)) || 3312102087Sluigi add_ports(cmd, *av, proto, O_IP_SRCPORT)) { 3313102087Sluigi ac--; av++; 3314102087Sluigi } else 3315102087Sluigi errx(EX_DATAERR, "invalid source port %s", *av); 3316102087Sluigi break; 3317102087Sluigi 3318102087Sluigi case TOK_DSTPORT: 3319102087Sluigi NEED1("missing destination port"); 3320102087Sluigi if (!strncmp(*av, "any", strlen(*av)) || 3321102087Sluigi add_ports(cmd, *av, proto, O_IP_DSTPORT)) { 3322102087Sluigi ac--; av++; 3323102087Sluigi } else 3324102087Sluigi errx(EX_DATAERR, "invalid destination port %s", 3325102087Sluigi *av); 3326102087Sluigi break; 3327102087Sluigi 3328102087Sluigi case TOK_MAC: 3329102087Sluigi if (ac < 2) 3330102087Sluigi errx(EX_USAGE, "MAC dst-mac src-mac"); 3331102087Sluigi if (add_mac(cmd, ac, av)) { 3332102087Sluigi ac -= 2; av += 2; 3333102087Sluigi } 3334102087Sluigi break; 3335102087Sluigi 3336102087Sluigi case TOK_MACTYPE: 3337102087Sluigi NEED1("missing mac type"); 3338102087Sluigi if (!add_mactype(cmd, ac, *av)) 3339116438Smaxim errx(EX_DATAERR, "invalid mac type %s", *av); 3340102087Sluigi ac--; av++; 3341102087Sluigi break; 3342102087Sluigi 3343112250Scjc case TOK_VERREVPATH: 3344112250Scjc fill_cmd(cmd, O_VERREVPATH, 0, 0); 3345112250Scjc break; 3346116919Sluigi 3347117241Sluigi case TOK_IPSEC: 3348117241Sluigi fill_cmd(cmd, O_IPSEC, 0, 0); 3349117241Sluigi break; 3350117241Sluigi 335198943Sluigi default: 335298943Sluigi errx(EX_USAGE, "unrecognised option [%d] %s\n", i, s); 335398943Sluigi } 335498943Sluigi if (F_LEN(cmd) > 0) { /* prepare to advance */ 335598943Sluigi prev = cmd; 335698943Sluigi cmd = next_cmd(cmd); 335798943Sluigi } 335898943Sluigi } 335998943Sluigi 336098943Sluigidone: 336198943Sluigi /* 336298943Sluigi * Now copy stuff into the rule. 336398943Sluigi * If we have a keep-state option, the first instruction 336498943Sluigi * must be a PROBE_STATE (which is generated here). 336598943Sluigi * If we have a LOG option, it was stored as the first command, 336698943Sluigi * and now must be moved to the top of the action part. 336798943Sluigi */ 336898943Sluigi dst = (ipfw_insn *)rule->cmd; 336998943Sluigi 337098943Sluigi /* 3371107289Sluigi * First thing to write into the command stream is the match probability. 3372107289Sluigi */ 3373107289Sluigi if (match_prob != 1) { /* 1 means always match */ 3374107289Sluigi dst->opcode = O_PROB; 3375107289Sluigi dst->len = 2; 3376107289Sluigi *((int32_t *)(dst+1)) = (int32_t)(match_prob * 0x7fffffff); 3377107289Sluigi dst += dst->len; 3378107289Sluigi } 3379107289Sluigi 3380107289Sluigi /* 338198943Sluigi * generate O_PROBE_STATE if necessary 338298943Sluigi */ 3383101116Sluigi if (have_state && have_state->opcode != O_CHECK_STATE) { 338498943Sluigi fill_cmd(dst, O_PROBE_STATE, 0, 0); 338598943Sluigi dst = next_cmd(dst); 338698943Sluigi } 338798943Sluigi /* 3388101116Sluigi * copy all commands but O_LOG, O_KEEP_STATE, O_LIMIT 338998943Sluigi */ 339098943Sluigi for (src = (ipfw_insn *)cmdbuf; src != cmd; src += i) { 339198943Sluigi i = F_LEN(src); 339298943Sluigi 3393101116Sluigi switch (src->opcode) { 3394101116Sluigi case O_LOG: 3395101116Sluigi case O_KEEP_STATE: 3396101116Sluigi case O_LIMIT: 3397101116Sluigi break; 3398101116Sluigi default: 3399117328Sluigi bcopy(src, dst, i * sizeof(uint32_t)); 340098943Sluigi dst += i; 340198943Sluigi } 340298943Sluigi } 340398943Sluigi 340498943Sluigi /* 3405101116Sluigi * put back the have_state command as last opcode 3406101116Sluigi */ 3407101295Sluigi if (have_state && have_state->opcode != O_CHECK_STATE) { 3408101116Sluigi i = F_LEN(have_state); 3409117328Sluigi bcopy(have_state, dst, i * sizeof(uint32_t)); 3410101116Sluigi dst += i; 3411101116Sluigi } 3412101116Sluigi /* 341398943Sluigi * start action section 341498943Sluigi */ 341598943Sluigi rule->act_ofs = dst - rule->cmd; 341698943Sluigi 341798943Sluigi /* 341898943Sluigi * put back O_LOG if necessary 341998943Sluigi */ 342098943Sluigi src = (ipfw_insn *)cmdbuf; 342198943Sluigi if ( src->opcode == O_LOG ) { 342298943Sluigi i = F_LEN(src); 3423117328Sluigi bcopy(src, dst, i * sizeof(uint32_t)); 342498943Sluigi dst += i; 342598943Sluigi } 342698943Sluigi /* 342798943Sluigi * copy all other actions 342898943Sluigi */ 342998943Sluigi for (src = (ipfw_insn *)actbuf; src != action; src += i) { 343098943Sluigi i = F_LEN(src); 3431117328Sluigi bcopy(src, dst, i * sizeof(uint32_t)); 343298943Sluigi dst += i; 343398943Sluigi } 343498943Sluigi 3435117328Sluigi rule->cmd_len = (uint32_t *)dst - (uint32_t *)(rule->cmd); 343698943Sluigi i = (void *)dst - (void *)rule; 3437117328Sluigi if (do_cmd(IP_FW_ADD, rule, (socklen_t)&i) == -1) 343898943Sluigi err(EX_UNAVAILABLE, "getsockopt(%s)", "IP_FW_ADD"); 343998943Sluigi if (!do_quiet) 3440112189Smaxim show_ipfw(rule, 10, 10); 344198943Sluigi} 344298943Sluigi 344398943Sluigistatic void 3444117328Sluigizero(int ac, char *av[], int optname /* IP_FW_ZERO or IP_FW_RESETLOG */) 344598943Sluigi{ 344698943Sluigi int rulenum; 344798943Sluigi int failed = EX_OK; 3448117328Sluigi char *name = optname == IP_FW_ZERO ? "ZERO" : "RESETLOG"; 344998943Sluigi 345098943Sluigi av++; ac--; 345198943Sluigi 345298943Sluigi if (!ac) { 345398943Sluigi /* clear all entries */ 3454117328Sluigi if (do_cmd(optname, NULL, 0) < 0) 3455117328Sluigi err(EX_UNAVAILABLE, "setsockopt(IP_FW_%s)", name); 345698943Sluigi if (!do_quiet) 3457117328Sluigi printf("%s.\n", optname == IP_FW_ZERO ? 3458117328Sluigi "Accounting cleared":"Logging counts reset"); 345998943Sluigi 346098943Sluigi return; 346198943Sluigi } 346298943Sluigi 346398943Sluigi while (ac) { 346498943Sluigi /* Rule number */ 346598943Sluigi if (isdigit(**av)) { 346698943Sluigi rulenum = atoi(*av); 346798943Sluigi av++; 346898943Sluigi ac--; 3469117328Sluigi if (do_cmd(optname, &rulenum, sizeof rulenum)) { 3470117328Sluigi warn("rule %u: setsockopt(IP_FW_%s)", 3471117328Sluigi rulenum, name); 347298943Sluigi failed = EX_UNAVAILABLE; 347398943Sluigi } else if (!do_quiet) 3474117328Sluigi printf("Entry %d %s.\n", rulenum, 3475117328Sluigi optname == IP_FW_ZERO ? 3476117328Sluigi "cleared" : "logging count reset"); 347798943Sluigi } else { 347898943Sluigi errx(EX_USAGE, "invalid rule number ``%s''", *av); 347998943Sluigi } 348098943Sluigi } 348198943Sluigi if (failed != EX_OK) 348298943Sluigi exit(failed); 348398943Sluigi} 348498943Sluigi 348598943Sluigistatic void 3486117328Sluigiflush(void) 348798943Sluigi{ 348898943Sluigi int cmd = do_pipe ? IP_DUMMYNET_FLUSH : IP_FW_FLUSH; 348998943Sluigi 349098943Sluigi if (!do_force && !do_quiet) { /* need to ask user */ 349198943Sluigi int c; 349298943Sluigi 349398943Sluigi printf("Are you sure? [yn] "); 349498943Sluigi fflush(stdout); 349598943Sluigi do { 349698943Sluigi c = toupper(getc(stdin)); 349798943Sluigi while (c != '\n' && getc(stdin) != '\n') 349898943Sluigi if (feof(stdin)) 349998943Sluigi return; /* and do not flush */ 350098943Sluigi } while (c != 'Y' && c != 'N'); 350198943Sluigi printf("\n"); 350298943Sluigi if (c == 'N') /* user said no */ 350398943Sluigi return; 350498943Sluigi } 3505117328Sluigi if (do_cmd(cmd, NULL, 0) < 0) 350698943Sluigi err(EX_UNAVAILABLE, "setsockopt(IP_%s_FLUSH)", 350798943Sluigi do_pipe ? "DUMMYNET" : "FW"); 350898943Sluigi if (!do_quiet) 350998943Sluigi printf("Flushed all %s.\n", do_pipe ? "pipes" : "rules"); 351098943Sluigi} 351198943Sluigi 351298943Sluigistatic int 3513117328Sluigiipfw_main(int oldac, char **oldav) 351498943Sluigi{ 3515117328Sluigi int ch, ac; 3516117328Sluigi char **av; 3517117328Sluigi 3518117328Sluigi if (oldac == 2) { 3519117328Sluigi /* 3520117328Sluigi * If we are called with a single string, try to split it into 3521117328Sluigi * arguments for subsequent parsing. 3522117328Sluigi * But first, remove spaces after a ',', by copying the string 3523117328Sluigi * in-place. 3524117328Sluigi */ 352598943Sluigi 3526117328Sluigi char *arg = oldav[1]; /* The string... */ 3527117328Sluigi int l = strlen(arg); 3528117328Sluigi int copy = 0; /* 1 if we need to copy, 0 otherwise */ 3529117328Sluigi int i, j; 3530117328Sluigi for (i = j = 0; i < l; i++) 3531117328Sluigi if (copy) { 3532117328Sluigi arg[j++] = arg[i]; 3533117328Sluigi copy = !index(" \t\n,", arg[i]); 3534117328Sluigi } else { 3535117328Sluigi copy = !index(" \t\n", arg[i]); 3536117328Sluigi if (copy) 3537117328Sluigi arg[j++] = arg[i]; 3538117328Sluigi } 3539117328Sluigi if (!copy && j > 0) /* last char was a 'blank', remove it */ 3540117328Sluigi j--; 3541117328Sluigi l = j; /* the new argument length */ 3542117328Sluigi arg[j++] = '\0'; 3543117328Sluigi 3544117328Sluigi /* 3545117328Sluigi * First, count number of arguments. Because of the previous 3546117328Sluigi * processing, this is just the number of blanks plus 1 3547117328Sluigi * (and then plus 1 for the program name). 3548117328Sluigi */ 3549117328Sluigi for (i = 0, ac=1; i < l; i++) 3550117328Sluigi if (index(" \t\n", arg[i]) != NULL) 3551117328Sluigi ac++; 3552117328Sluigi ac++; /* account for program name */ 3553117328Sluigi 3554117328Sluigi if (ac <= 1) 3555117328Sluigi show_usage(); 3556117328Sluigi av = calloc(ac, sizeof(char *)); 3557117328Sluigi av[0] = calloc(1+strlen(oldav[0]), 1); 3558117328Sluigi strcpy(av[0], oldav[0]); 3559117328Sluigi ac = 1; 3560117328Sluigi 3561117328Sluigi /* 3562117328Sluigi * Second, copy arguments from cmd[] to av[]. For each one, 3563117328Sluigi * j is the initial character, i is the one past the end. 3564117328Sluigi */ 3565117328Sluigi for (i = j = 0; i < l; i++) 3566117328Sluigi if (isblank(arg[i]) || i == l-1) { 3567117328Sluigi if (i == l-1) 3568117328Sluigi i++; 3569117328Sluigi av[ac] = calloc(i-j+1, 1); 3570117328Sluigi bcopy(arg+j, av[ac], i-j); 3571117328Sluigi ac++; 3572117328Sluigi j = i + 1; 3573117328Sluigi } 3574117328Sluigi } else { 3575117328Sluigi /* 3576117328Sluigi * If an argument ends with ',' join with the next one. 3577117328Sluigi */ 3578117328Sluigi int first, i, l; 3579117328Sluigi 3580117328Sluigi av = calloc(oldac, sizeof(char *)); 3581117328Sluigi for (first = i = ac = 0, l = 0; i < oldac; i++) { 3582117328Sluigi char *arg = oldav[i]; 3583117328Sluigi int k = strlen(arg); 3584117328Sluigi 3585117328Sluigi l += k; 3586117328Sluigi if (arg[k-1] != ',' || i == oldac-1) { 3587117328Sluigi /* Time to copy. */ 3588117328Sluigi av[ac] = calloc(l+1, 1); 3589117328Sluigi for (l=0; first <= i; first++) { 3590117328Sluigi strcat(av[ac]+l, oldav[first]); 3591117328Sluigi l += strlen(oldav[first]); 3592117328Sluigi } 3593117328Sluigi ac++; 3594117328Sluigi l = 0; 3595117328Sluigi first = i+1; 3596117328Sluigi } 3597117328Sluigi } 3598117328Sluigi } 3599117328Sluigi 360098943Sluigi if (ac == 1) 360198943Sluigi show_usage(); 360298943Sluigi 360398943Sluigi /* Set the force flag for non-interactive processes */ 360498943Sluigi do_force = !isatty(STDIN_FILENO); 360598943Sluigi 360698943Sluigi optind = optreset = 1; 3607117328Sluigi while ((ch = getopt(ac, av, "acdefhnNqs:Stv")) != -1) 360898943Sluigi switch (ch) { 360998943Sluigi case 'a': 361098943Sluigi do_acct = 1; 361198943Sluigi break; 3612117328Sluigi 3613102098Sluigi case 'c': 3614102098Sluigi do_compact = 1; 3615102098Sluigi break; 3616117328Sluigi 361798943Sluigi case 'd': 361898943Sluigi do_dynamic = 1; 361998943Sluigi break; 3620117328Sluigi 362198943Sluigi case 'e': 362298943Sluigi do_expired = 1; 362398943Sluigi break; 3624117328Sluigi 362598943Sluigi case 'f': 362698943Sluigi do_force = 1; 362798943Sluigi break; 3628117328Sluigi 3629117328Sluigi case 'h': /* help */ 3630117328Sluigi help(); 3631117328Sluigi break; /* NOTREACHED */ 3632117328Sluigi 3633117328Sluigi case 'n': 3634117328Sluigi test_only = 1; 3635117328Sluigi break; 3636117328Sluigi 363798943Sluigi case 'N': 363898943Sluigi do_resolv = 1; 363998943Sluigi break; 3640117328Sluigi 364198943Sluigi case 'q': 364298943Sluigi do_quiet = 1; 364398943Sluigi break; 3644117328Sluigi 3645117328Sluigi case 's': /* sort */ 3646117328Sluigi do_sort = atoi(optarg); 3647117328Sluigi break; 3648117328Sluigi 3649101628Sluigi case 'S': 3650101628Sluigi show_sets = 1; 3651101628Sluigi break; 3652117328Sluigi 365398943Sluigi case 't': 365498943Sluigi do_time = 1; 365598943Sluigi break; 3656117328Sluigi 365798943Sluigi case 'v': /* verbose */ 3658117328Sluigi verbose = 1; 365998943Sluigi break; 3660117328Sluigi 366198943Sluigi default: 366298943Sluigi show_usage(); 366398943Sluigi } 366498943Sluigi 366598943Sluigi ac -= optind; 366698943Sluigi av += optind; 366798943Sluigi NEED1("bad arguments, for usage summary ``ipfw''"); 366898943Sluigi 366998943Sluigi /* 367098943Sluigi * optional: pipe or queue 367198943Sluigi */ 367298943Sluigi if (!strncmp(*av, "pipe", strlen(*av))) { 367398943Sluigi do_pipe = 1; 367498943Sluigi ac--; 367598943Sluigi av++; 367698943Sluigi } else if (!strncmp(*av, "queue", strlen(*av))) { 367798943Sluigi do_pipe = 2; 367898943Sluigi ac--; 367998943Sluigi av++; 368098943Sluigi } 368198943Sluigi NEED1("missing command"); 368298943Sluigi 368398943Sluigi /* 3684117328Sluigi * For pipes and queues we normally say 'pipe NN config' 368598943Sluigi * but the code is easier to parse as 'pipe config NN' 368698943Sluigi * so we swap the two arguments. 368798943Sluigi */ 368898943Sluigi if (do_pipe > 0 && ac > 1 && *av[0] >= '0' && *av[0] <= '9') { 368998943Sluigi char *p = av[0]; 369098943Sluigi av[0] = av[1]; 369198943Sluigi av[1] = p; 369298943Sluigi } 3693117328Sluigi 369498943Sluigi if (!strncmp(*av, "add", strlen(*av))) 369598943Sluigi add(ac, av); 369698943Sluigi else if (do_pipe && !strncmp(*av, "config", strlen(*av))) 369798943Sluigi config_pipe(ac, av); 3698101978Sluigi else if (!strncmp(*av, "delete", strlen(*av))) 369998943Sluigi delete(ac, av); 370098943Sluigi else if (!strncmp(*av, "flush", strlen(*av))) 370198943Sluigi flush(); 370298943Sluigi else if (!strncmp(*av, "zero", strlen(*av))) 3703117328Sluigi zero(ac, av, IP_FW_ZERO); 370498943Sluigi else if (!strncmp(*av, "resetlog", strlen(*av))) 3705117328Sluigi zero(ac, av, IP_FW_RESETLOG); 370698943Sluigi else if (!strncmp(*av, "print", strlen(*av)) || 370798943Sluigi !strncmp(*av, "list", strlen(*av))) 370898943Sluigi list(ac, av); 3709101978Sluigi else if (!strncmp(*av, "set", strlen(*av))) 3710101978Sluigi sets_handler(ac, av); 3711109126Sdillon else if (!strncmp(*av, "enable", strlen(*av))) 3712109126Sdillon sysctl_handler(ac, av, 1); 3713109126Sdillon else if (!strncmp(*av, "disable", strlen(*av))) 3714109126Sdillon sysctl_handler(ac, av, 0); 371598943Sluigi else if (!strncmp(*av, "show", strlen(*av))) { 371698943Sluigi do_acct++; 371798943Sluigi list(ac, av); 371898943Sluigi } else 371998943Sluigi errx(EX_USAGE, "bad command `%s'", *av); 372098943Sluigi return 0; 372198943Sluigi} 372298943Sluigi 372398943Sluigi 372498943Sluigistatic void 3725106505Smaximipfw_readfile(int ac, char *av[]) 372698943Sluigi{ 372798943Sluigi#define MAX_ARGS 32 372898943Sluigi#define WHITESP " \t\f\v\n\r" 372998943Sluigi char buf[BUFSIZ]; 373098943Sluigi char *a, *p, *args[MAX_ARGS], *cmd = NULL; 373198943Sluigi char linename[10]; 373298943Sluigi int i=0, lineno=0, qflag=0, pflag=0, status; 373398943Sluigi FILE *f = NULL; 373498943Sluigi pid_t preproc = 0; 373598943Sluigi int c; 373698943Sluigi 3737117328Sluigi while ((c = getopt(ac, av, "np:q")) != -1) { 373898943Sluigi switch(c) { 3739117328Sluigi case 'n': 3740117328Sluigi test_only = 1; 3741117328Sluigi break; 3742117328Sluigi 374398943Sluigi case 'p': 374498943Sluigi pflag = 1; 374598943Sluigi cmd = optarg; 374698943Sluigi args[0] = cmd; 374798943Sluigi i = 1; 374898943Sluigi break; 374998943Sluigi 375098943Sluigi case 'q': 375198943Sluigi qflag = 1; 375298943Sluigi break; 375398943Sluigi 375498943Sluigi default: 375598943Sluigi errx(EX_USAGE, "bad arguments, for usage" 375698943Sluigi " summary ``ipfw''"); 375798943Sluigi } 375898943Sluigi 3759108231Skbyanc if (pflag) 3760108231Skbyanc break; 3761108231Skbyanc } 3762108231Skbyanc 3763108231Skbyanc if (pflag) { 3764108231Skbyanc /* Pass all but the last argument to the preprocessor. */ 3765108231Skbyanc while (optind < ac - 1) { 3766108231Skbyanc if (i >= MAX_ARGS) 3767108231Skbyanc errx(EX_USAGE, "too many preprocessor options"); 3768108231Skbyanc args[i++] = av[optind++]; 3769108231Skbyanc } 3770108231Skbyanc } 3771108231Skbyanc 377298943Sluigi av += optind; 377398943Sluigi ac -= optind; 377498943Sluigi if (ac != 1) 377598943Sluigi errx(EX_USAGE, "extraneous filename arguments"); 377698943Sluigi 377798943Sluigi if ((f = fopen(av[0], "r")) == NULL) 377898943Sluigi err(EX_UNAVAILABLE, "fopen: %s", av[0]); 377998943Sluigi 378098943Sluigi if (pflag) { 378198943Sluigi /* pipe through preprocessor (cpp or m4) */ 378298943Sluigi int pipedes[2]; 378398943Sluigi 378498943Sluigi args[i] = 0; 378598943Sluigi 378698943Sluigi if (pipe(pipedes) == -1) 378798943Sluigi err(EX_OSERR, "cannot create pipe"); 378898943Sluigi 378998943Sluigi switch((preproc = fork())) { 379098943Sluigi case -1: 379198943Sluigi err(EX_OSERR, "cannot fork"); 379298943Sluigi 379398943Sluigi case 0: 379498943Sluigi /* child */ 379598943Sluigi if (dup2(fileno(f), 0) == -1 379698943Sluigi || dup2(pipedes[1], 1) == -1) 379798943Sluigi err(EX_OSERR, "dup2()"); 379898943Sluigi fclose(f); 379998943Sluigi close(pipedes[1]); 380098943Sluigi close(pipedes[0]); 380198943Sluigi execvp(cmd, args); 380298943Sluigi err(EX_OSERR, "execvp(%s) failed", cmd); 380398943Sluigi 380498943Sluigi default: 380598943Sluigi /* parent */ 380698943Sluigi fclose(f); 380798943Sluigi close(pipedes[1]); 380898943Sluigi if ((f = fdopen(pipedes[0], "r")) == NULL) { 380998943Sluigi int savederrno = errno; 381098943Sluigi 381198943Sluigi (void)kill(preproc, SIGTERM); 381298943Sluigi errno = savederrno; 381398943Sluigi err(EX_OSERR, "fdopen()"); 381498943Sluigi } 381598943Sluigi } 381698943Sluigi } 381798943Sluigi 381898943Sluigi while (fgets(buf, BUFSIZ, f)) { 381998943Sluigi lineno++; 3820117328Sluigi if (*buf == '#') 3821117328Sluigi continue; 3822117328Sluigi 382398943Sluigi sprintf(linename, "Line %d", lineno); 382498943Sluigi args[0] = linename; 3825117328Sluigi setprogname(linename); /* XXX */ 382698943Sluigi 382798943Sluigi if ((p = strchr(buf, '#')) != NULL) 382898943Sluigi *p = '\0'; 382998943Sluigi i = 1; 383098943Sluigi if (qflag) 383198943Sluigi args[i++] = "-q"; 383298943Sluigi for (a = strtok(buf, WHITESP); 383398943Sluigi a && i < MAX_ARGS; a = strtok(NULL, WHITESP), i++) 383498943Sluigi args[i] = a; 383598943Sluigi if (i == (qflag? 2: 1)) 383698943Sluigi continue; 383798943Sluigi if (i == MAX_ARGS) 383898943Sluigi errx(EX_USAGE, "%s: too many arguments", 383998943Sluigi linename); 384098943Sluigi args[i] = NULL; 384198943Sluigi 384298943Sluigi ipfw_main(i, args); 384398943Sluigi } 384498943Sluigi fclose(f); 384598943Sluigi if (pflag) { 384698943Sluigi if (waitpid(preproc, &status, 0) == -1) 384798943Sluigi errx(EX_OSERR, "waitpid()"); 384898943Sluigi if (WIFEXITED(status) && WEXITSTATUS(status) != EX_OK) 384998943Sluigi errx(EX_UNAVAILABLE, 385098943Sluigi "preprocessor exited with status %d", 385198943Sluigi WEXITSTATUS(status)); 385298943Sluigi else if (WIFSIGNALED(status)) 385398943Sluigi errx(EX_UNAVAILABLE, 385498943Sluigi "preprocessor exited with signal %d", 385598943Sluigi WTERMSIG(status)); 385698943Sluigi } 385798943Sluigi} 385898943Sluigi 385998943Sluigiint 386098943Sluigimain(int ac, char *av[]) 386198943Sluigi{ 386298943Sluigi /* 386398943Sluigi * If the last argument is an absolute pathname, interpret it 386498943Sluigi * as a file to be preprocessed. 386598943Sluigi */ 386698943Sluigi 386798943Sluigi if (ac > 1 && av[ac - 1][0] == '/' && access(av[ac - 1], R_OK) == 0) 386898943Sluigi ipfw_readfile(ac, av); 386998943Sluigi else 387098943Sluigi ipfw_main(ac, av); 387198943Sluigi return EX_OK; 387298943Sluigi} 3873