ipfw2.c revision 121816
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 121816 2003-10-31 18:32:15Z brooks $ 2198943Sluigi */ 2298943Sluigi 2398943Sluigi#include <sys/param.h> 2498943Sluigi#include <sys/mbuf.h> 2598943Sluigi#include <sys/socket.h> 2698943Sluigi#include <sys/sockio.h> 2798943Sluigi#include <sys/sysctl.h> 2898943Sluigi#include <sys/time.h> 2998943Sluigi#include <sys/wait.h> 3098943Sluigi 3198943Sluigi#include <ctype.h> 3298943Sluigi#include <err.h> 3398943Sluigi#include <errno.h> 3498943Sluigi#include <grp.h> 3598943Sluigi#include <limits.h> 3698943Sluigi#include <netdb.h> 3798943Sluigi#include <pwd.h> 3898943Sluigi#include <signal.h> 3998943Sluigi#include <stdio.h> 4098943Sluigi#include <stdlib.h> 4198943Sluigi#include <stdarg.h> 4298943Sluigi#include <string.h> 43117469Sluigi#include <timeconv.h> /* XXX do we need this ? */ 4498943Sluigi#include <unistd.h> 4598943Sluigi#include <sysexits.h> 4698943Sluigi 4798943Sluigi#include <net/if.h> 4898943Sluigi#include <netinet/in.h> 4998943Sluigi#include <netinet/in_systm.h> 5098943Sluigi#include <netinet/ip.h> 5198943Sluigi#include <netinet/ip_icmp.h> 5298943Sluigi#include <netinet/ip_fw.h> 5398943Sluigi#include <netinet/ip_dummynet.h> 5498943Sluigi#include <netinet/tcp.h> 5598943Sluigi#include <arpa/inet.h> 5698943Sluigi 57117328Sluigiint 5898943Sluigi do_resolv, /* Would try to resolve all */ 5998943Sluigi do_time, /* Show time stamps */ 6098943Sluigi do_quiet, /* Be quiet in add and flush */ 6198943Sluigi do_pipe, /* this cmd refers to a pipe */ 6298943Sluigi do_sort, /* field to sort results (0 = no) */ 6398943Sluigi do_dynamic, /* display dynamic rules */ 6498943Sluigi do_expired, /* display expired dynamic rules */ 65102098Sluigi do_compact, /* show rules in compact mode */ 66101628Sluigi show_sets, /* display rule sets */ 67117328Sluigi test_only, /* only check syntax */ 6898943Sluigi verbose; 6998943Sluigi 7098943Sluigi#define IP_MASK_ALL 0xffffffff 7198943Sluigi 7298943Sluigi/* 73117328Sluigi * _s_x is a structure that stores a string <-> token pairs, used in 74117328Sluigi * various places in the parser. Entries are stored in arrays, 75117328Sluigi * with an entry with s=NULL as terminator. 76117328Sluigi * The search routines are match_token() and match_value(). 77117328Sluigi * Often, an element with x=0 contains an error string. 7898943Sluigi * 7998943Sluigi */ 8098943Sluigistruct _s_x { 81117469Sluigi char const *s; 8298943Sluigi int x; 8398943Sluigi}; 8498943Sluigi 8598943Sluigistatic struct _s_x f_tcpflags[] = { 8698943Sluigi { "syn", TH_SYN }, 8798943Sluigi { "fin", TH_FIN }, 8898943Sluigi { "ack", TH_ACK }, 8998943Sluigi { "psh", TH_PUSH }, 9098943Sluigi { "rst", TH_RST }, 9198943Sluigi { "urg", TH_URG }, 9298943Sluigi { "tcp flag", 0 }, 9398943Sluigi { NULL, 0 } 9498943Sluigi}; 9598943Sluigi 9698943Sluigistatic struct _s_x f_tcpopts[] = { 9798943Sluigi { "mss", IP_FW_TCPOPT_MSS }, 9898943Sluigi { "maxseg", IP_FW_TCPOPT_MSS }, 9998943Sluigi { "window", IP_FW_TCPOPT_WINDOW }, 10098943Sluigi { "sack", IP_FW_TCPOPT_SACK }, 10198943Sluigi { "ts", IP_FW_TCPOPT_TS }, 10298943Sluigi { "timestamp", IP_FW_TCPOPT_TS }, 10398943Sluigi { "cc", IP_FW_TCPOPT_CC }, 10498943Sluigi { "tcp option", 0 }, 10598943Sluigi { NULL, 0 } 10698943Sluigi}; 10798943Sluigi 10898943Sluigi/* 10998943Sluigi * IP options span the range 0 to 255 so we need to remap them 11098943Sluigi * (though in fact only the low 5 bits are significant). 11198943Sluigi */ 11298943Sluigistatic struct _s_x f_ipopts[] = { 11398943Sluigi { "ssrr", IP_FW_IPOPT_SSRR}, 11498943Sluigi { "lsrr", IP_FW_IPOPT_LSRR}, 11598943Sluigi { "rr", IP_FW_IPOPT_RR}, 11698943Sluigi { "ts", IP_FW_IPOPT_TS}, 11798943Sluigi { "ip option", 0 }, 11898943Sluigi { NULL, 0 } 11998943Sluigi}; 12098943Sluigi 12198943Sluigistatic struct _s_x f_iptos[] = { 12298943Sluigi { "lowdelay", IPTOS_LOWDELAY}, 12398943Sluigi { "throughput", IPTOS_THROUGHPUT}, 12498943Sluigi { "reliability", IPTOS_RELIABILITY}, 12598943Sluigi { "mincost", IPTOS_MINCOST}, 12698943Sluigi { "congestion", IPTOS_CE}, 12798943Sluigi { "ecntransport", IPTOS_ECT}, 12898943Sluigi { "ip tos option", 0}, 12998943Sluigi { NULL, 0 } 13098943Sluigi}; 13198943Sluigi 13298943Sluigistatic struct _s_x limit_masks[] = { 13398943Sluigi {"all", DYN_SRC_ADDR|DYN_SRC_PORT|DYN_DST_ADDR|DYN_DST_PORT}, 13498943Sluigi {"src-addr", DYN_SRC_ADDR}, 13598943Sluigi {"src-port", DYN_SRC_PORT}, 13698943Sluigi {"dst-addr", DYN_DST_ADDR}, 13798943Sluigi {"dst-port", DYN_DST_PORT}, 13898943Sluigi {NULL, 0} 13998943Sluigi}; 14098943Sluigi 14198943Sluigi/* 14298943Sluigi * we use IPPROTO_ETHERTYPE as a fake protocol id to call the print routines 14398943Sluigi * This is only used in this code. 14498943Sluigi */ 14598943Sluigi#define IPPROTO_ETHERTYPE 0x1000 14698943Sluigistatic struct _s_x ether_types[] = { 14798943Sluigi /* 14898943Sluigi * Note, we cannot use "-:&/" in the names because they are field 14998943Sluigi * separators in the type specifications. Also, we use s = NULL as 15098943Sluigi * end-delimiter, because a type of 0 can be legal. 15198943Sluigi */ 15298943Sluigi { "ip", 0x0800 }, 15398943Sluigi { "ipv4", 0x0800 }, 15498943Sluigi { "ipv6", 0x86dd }, 15598943Sluigi { "arp", 0x0806 }, 15698943Sluigi { "rarp", 0x8035 }, 15798943Sluigi { "vlan", 0x8100 }, 15898943Sluigi { "loop", 0x9000 }, 15998943Sluigi { "trail", 0x1000 }, 16098943Sluigi { "at", 0x809b }, 16198943Sluigi { "atalk", 0x809b }, 16298943Sluigi { "aarp", 0x80f3 }, 16398943Sluigi { "pppoe_disc", 0x8863 }, 16498943Sluigi { "pppoe_sess", 0x8864 }, 16598943Sluigi { "ipx_8022", 0x00E0 }, 16698943Sluigi { "ipx_8023", 0x0000 }, 16798943Sluigi { "ipx_ii", 0x8137 }, 16898943Sluigi { "ipx_snap", 0x8137 }, 16998943Sluigi { "ipx", 0x8137 }, 17098943Sluigi { "ns", 0x0600 }, 17198943Sluigi { NULL, 0 } 17298943Sluigi}; 17398943Sluigi 17498943Sluigistatic void show_usage(void); 17598943Sluigi 17698943Sluigienum tokens { 17798943Sluigi TOK_NULL=0, 17898943Sluigi 17998943Sluigi TOK_OR, 18098943Sluigi TOK_NOT, 181101641Sluigi TOK_STARTBRACE, 182101641Sluigi TOK_ENDBRACE, 18398943Sluigi 18498943Sluigi TOK_ACCEPT, 18598943Sluigi TOK_COUNT, 18698943Sluigi TOK_PIPE, 18798943Sluigi TOK_QUEUE, 18898943Sluigi TOK_DIVERT, 18998943Sluigi TOK_TEE, 19098943Sluigi TOK_FORWARD, 19198943Sluigi TOK_SKIPTO, 19298943Sluigi TOK_DENY, 19398943Sluigi TOK_REJECT, 19498943Sluigi TOK_RESET, 19598943Sluigi TOK_UNREACH, 19698943Sluigi TOK_CHECKSTATE, 19798943Sluigi 19898943Sluigi TOK_UID, 19998943Sluigi TOK_GID, 20098943Sluigi TOK_IN, 20198943Sluigi TOK_LIMIT, 20298943Sluigi TOK_KEEPSTATE, 20398943Sluigi TOK_LAYER2, 20498943Sluigi TOK_OUT, 20598943Sluigi TOK_XMIT, 20698943Sluigi TOK_RECV, 20798943Sluigi TOK_VIA, 20898943Sluigi TOK_FRAG, 20998943Sluigi TOK_IPOPTS, 21098943Sluigi TOK_IPLEN, 21198943Sluigi TOK_IPID, 21298943Sluigi TOK_IPPRECEDENCE, 21398943Sluigi TOK_IPTOS, 21498943Sluigi TOK_IPTTL, 21598943Sluigi TOK_IPVER, 21698943Sluigi TOK_ESTAB, 21798943Sluigi TOK_SETUP, 21898943Sluigi TOK_TCPFLAGS, 21998943Sluigi TOK_TCPOPTS, 22098943Sluigi TOK_TCPSEQ, 22198943Sluigi TOK_TCPACK, 22298943Sluigi TOK_TCPWIN, 22398943Sluigi TOK_ICMPTYPES, 224102087Sluigi TOK_MAC, 225102087Sluigi TOK_MACTYPE, 226112250Scjc TOK_VERREVPATH, 227117241Sluigi TOK_IPSEC, 228117469Sluigi TOK_COMMENT, 22998943Sluigi 23098943Sluigi TOK_PLR, 231101978Sluigi TOK_NOERROR, 23298943Sluigi TOK_BUCKETS, 23398943Sluigi TOK_DSTIP, 23498943Sluigi TOK_SRCIP, 23598943Sluigi TOK_DSTPORT, 23698943Sluigi TOK_SRCPORT, 23798943Sluigi TOK_ALL, 23898943Sluigi TOK_MASK, 23998943Sluigi TOK_BW, 24098943Sluigi TOK_DELAY, 24198943Sluigi TOK_RED, 24298943Sluigi TOK_GRED, 24398943Sluigi TOK_DROPTAIL, 24498943Sluigi TOK_PROTO, 24598943Sluigi TOK_WEIGHT, 24698943Sluigi}; 24798943Sluigi 24898943Sluigistruct _s_x dummynet_params[] = { 24998943Sluigi { "plr", TOK_PLR }, 250101978Sluigi { "noerror", TOK_NOERROR }, 25198943Sluigi { "buckets", TOK_BUCKETS }, 25298943Sluigi { "dst-ip", TOK_DSTIP }, 25398943Sluigi { "src-ip", TOK_SRCIP }, 25498943Sluigi { "dst-port", TOK_DSTPORT }, 25598943Sluigi { "src-port", TOK_SRCPORT }, 25698943Sluigi { "proto", TOK_PROTO }, 25798943Sluigi { "weight", TOK_WEIGHT }, 25898943Sluigi { "all", TOK_ALL }, 25998943Sluigi { "mask", TOK_MASK }, 26098943Sluigi { "droptail", TOK_DROPTAIL }, 26198943Sluigi { "red", TOK_RED }, 26298943Sluigi { "gred", TOK_GRED }, 26398943Sluigi { "bw", TOK_BW }, 26498943Sluigi { "bandwidth", TOK_BW }, 26598943Sluigi { "delay", TOK_DELAY }, 26699475Sluigi { "pipe", TOK_PIPE }, 26798943Sluigi { "queue", TOK_QUEUE }, 26898943Sluigi { "dummynet-params", TOK_NULL }, 269117328Sluigi { NULL, 0 } /* terminator */ 27098943Sluigi}; 27198943Sluigi 27298943Sluigistruct _s_x rule_actions[] = { 27398943Sluigi { "accept", TOK_ACCEPT }, 27498943Sluigi { "pass", TOK_ACCEPT }, 27598943Sluigi { "allow", TOK_ACCEPT }, 27698943Sluigi { "permit", TOK_ACCEPT }, 27798943Sluigi { "count", TOK_COUNT }, 27898943Sluigi { "pipe", TOK_PIPE }, 27998943Sluigi { "queue", TOK_QUEUE }, 28098943Sluigi { "divert", TOK_DIVERT }, 28198943Sluigi { "tee", TOK_TEE }, 28298943Sluigi { "fwd", TOK_FORWARD }, 28398943Sluigi { "forward", TOK_FORWARD }, 28498943Sluigi { "skipto", TOK_SKIPTO }, 28598943Sluigi { "deny", TOK_DENY }, 28698943Sluigi { "drop", TOK_DENY }, 28798943Sluigi { "reject", TOK_REJECT }, 28898943Sluigi { "reset", TOK_RESET }, 28999475Sluigi { "unreach", TOK_UNREACH }, 29098943Sluigi { "check-state", TOK_CHECKSTATE }, 291117469Sluigi { "//", TOK_COMMENT }, 292117328Sluigi { NULL, 0 } /* terminator */ 29398943Sluigi}; 29498943Sluigi 29598943Sluigistruct _s_x rule_options[] = { 29698943Sluigi { "uid", TOK_UID }, 29798943Sluigi { "gid", TOK_GID }, 29898943Sluigi { "in", TOK_IN }, 29998943Sluigi { "limit", TOK_LIMIT }, 30098943Sluigi { "keep-state", TOK_KEEPSTATE }, 30198943Sluigi { "bridged", TOK_LAYER2 }, 30298943Sluigi { "layer2", TOK_LAYER2 }, 30398943Sluigi { "out", TOK_OUT }, 30498943Sluigi { "xmit", TOK_XMIT }, 30598943Sluigi { "recv", TOK_RECV }, 30698943Sluigi { "via", TOK_VIA }, 30798943Sluigi { "fragment", TOK_FRAG }, 30898943Sluigi { "frag", TOK_FRAG }, 30998943Sluigi { "ipoptions", TOK_IPOPTS }, 31098943Sluigi { "ipopts", TOK_IPOPTS }, 31198943Sluigi { "iplen", TOK_IPLEN }, 31298943Sluigi { "ipid", TOK_IPID }, 31398943Sluigi { "ipprecedence", TOK_IPPRECEDENCE }, 31498943Sluigi { "iptos", TOK_IPTOS }, 31598943Sluigi { "ipttl", TOK_IPTTL }, 31698943Sluigi { "ipversion", TOK_IPVER }, 31798943Sluigi { "ipver", TOK_IPVER }, 31898943Sluigi { "estab", TOK_ESTAB }, 31998943Sluigi { "established", TOK_ESTAB }, 32098943Sluigi { "setup", TOK_SETUP }, 32198943Sluigi { "tcpflags", TOK_TCPFLAGS }, 32298943Sluigi { "tcpflgs", TOK_TCPFLAGS }, 32398943Sluigi { "tcpoptions", TOK_TCPOPTS }, 32498943Sluigi { "tcpopts", TOK_TCPOPTS }, 32598943Sluigi { "tcpseq", TOK_TCPSEQ }, 32698943Sluigi { "tcpack", TOK_TCPACK }, 32798943Sluigi { "tcpwin", TOK_TCPWIN }, 32899909Sluigi { "icmptype", TOK_ICMPTYPES }, 32998943Sluigi { "icmptypes", TOK_ICMPTYPES }, 330102087Sluigi { "dst-ip", TOK_DSTIP }, 331102087Sluigi { "src-ip", TOK_SRCIP }, 332102087Sluigi { "dst-port", TOK_DSTPORT }, 333102087Sluigi { "src-port", TOK_SRCPORT }, 334102087Sluigi { "proto", TOK_PROTO }, 335102087Sluigi { "MAC", TOK_MAC }, 336102087Sluigi { "mac", TOK_MAC }, 337102087Sluigi { "mac-type", TOK_MACTYPE }, 338112250Scjc { "verrevpath", TOK_VERREVPATH }, 339117241Sluigi { "ipsec", TOK_IPSEC }, 340117469Sluigi { "//", TOK_COMMENT }, 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 */ 364117469Sluigistatic int 365119740Stmmdo_cmd(int optname, void *optval, uintptr_t optlen) 366117328Sluigi{ 367117328Sluigi static int s = -1; /* the socket */ 368117328Sluigi int i; 369117577Sluigi 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; 395117469Sluigi uint 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 */ 407117469Sluigistatic char const * 408117469Sluigimatch_value(struct _s_x *p, int 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) { 424117469Sluigi char const *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; 463117469Sluigi char const *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 */ 502117577Sluigi 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++) 523117577Sluigi 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{ 627117469Sluigi char const *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 647117577Sluigicontigmask(uint8_t *p, int len) 64898943Sluigi{ 64998943Sluigi int i, n; 650117577Sluigi 65198943Sluigi for (i=0; i<len ; i++) 65298943Sluigi if ( (p[i/8] & (1 << (7 - (i%8)))) == 0) /* first bit unset */ 65398943Sluigi break; 65498943Sluigi for (n=i+1; n < len; n++) 65598943Sluigi if ( (p[n/8] & (1 << (7 - (n%8)))) != 0) 65698943Sluigi return -1; /* mask not contiguous */ 65798943Sluigi return i; 65898943Sluigi} 65998943Sluigi 66098943Sluigi/* 66198943Sluigi * print flags set/clear in the two bitmasks passed as parameters. 66298943Sluigi * There is a specialized check for f_tcpflags. 66398943Sluigi */ 66498943Sluigistatic void 665117469Sluigiprint_flags(char const *name, ipfw_insn *cmd, struct _s_x *list) 66698943Sluigi{ 667117469Sluigi char const *comma = ""; 66898943Sluigi int i; 669117577Sluigi uint8_t set = cmd->arg1 & 0xff; 670117577Sluigi uint8_t clear = (cmd->arg1 >> 8) & 0xff; 67198943Sluigi 67298943Sluigi if (list == f_tcpflags && set == TH_SYN && clear == TH_ACK) { 67398943Sluigi printf(" setup"); 67498943Sluigi return; 67598943Sluigi } 67698943Sluigi 67798943Sluigi printf(" %s ", name); 67898943Sluigi for (i=0; list[i].x != 0; i++) { 67998943Sluigi if (set & list[i].x) { 68098943Sluigi set &= ~list[i].x; 68198943Sluigi printf("%s%s", comma, list[i].s); 68298943Sluigi comma = ","; 68398943Sluigi } 68498943Sluigi if (clear & list[i].x) { 68598943Sluigi clear &= ~list[i].x; 68698943Sluigi printf("%s!%s", comma, list[i].s); 68798943Sluigi comma = ","; 68898943Sluigi } 68998943Sluigi } 69098943Sluigi} 69198943Sluigi 69298943Sluigi/* 69398943Sluigi * Print the ip address contained in a command. 69498943Sluigi */ 69598943Sluigistatic void 696117469Sluigiprint_ip(ipfw_insn_ip *cmd, char const *s) 69798943Sluigi{ 69898943Sluigi struct hostent *he = NULL; 699117328Sluigi int len = F_LEN((ipfw_insn *)cmd); 700117328Sluigi uint32_t *a = ((ipfw_insn_u32 *)cmd)->d; 70198943Sluigi 702102087Sluigi printf("%s%s ", cmd->o.len & F_NOT ? " not": "", s); 70398943Sluigi 70498943Sluigi if (cmd->o.opcode == O_IP_SRC_ME || cmd->o.opcode == O_IP_DST_ME) { 70598943Sluigi printf("me"); 70698943Sluigi return; 70798943Sluigi } 70898943Sluigi if (cmd->o.opcode == O_IP_SRC_SET || cmd->o.opcode == O_IP_DST_SET) { 709117328Sluigi uint32_t x, *map = (uint32_t *)&(cmd->mask); 710116716Sluigi int i, j; 71198943Sluigi char comma = '{'; 71298943Sluigi 71398943Sluigi x = cmd->o.arg1 - 1; 71498943Sluigi x = htonl( ~x ); 71598943Sluigi cmd->addr.s_addr = htonl(cmd->addr.s_addr); 71698943Sluigi printf("%s/%d", inet_ntoa(cmd->addr), 717117577Sluigi contigmask((uint8_t *)&x, 32)); 71898943Sluigi x = cmd->addr.s_addr = htonl(cmd->addr.s_addr); 71998943Sluigi x &= 0xff; /* base */ 720116716Sluigi /* 721116716Sluigi * Print bits and ranges. 722116716Sluigi * Locate first bit set (i), then locate first bit unset (j). 723116716Sluigi * If we have 3+ consecutive bits set, then print them as a 724116716Sluigi * range, otherwise only print the initial bit and rescan. 725116716Sluigi */ 72698943Sluigi for (i=0; i < cmd->o.arg1; i++) 727117328Sluigi if (map[i/32] & (1<<(i & 31))) { 728116716Sluigi for (j=i+1; j < cmd->o.arg1; j++) 729117328Sluigi if (!(map[ j/32] & (1<<(j & 31)))) 730116716Sluigi break; 73198943Sluigi printf("%c%d", comma, i+x); 732116716Sluigi if (j>i+2) { /* range has at least 3 elements */ 733116716Sluigi printf("-%d", j-1+x); 734116716Sluigi i = j-1; 735116716Sluigi } 73698943Sluigi comma = ','; 73798943Sluigi } 73898943Sluigi printf("}"); 73998943Sluigi return; 74098943Sluigi } 741117328Sluigi /* 742117328Sluigi * len == 2 indicates a single IP, whereas lists of 1 or more 743117328Sluigi * addr/mask pairs have len = (2n+1). We convert len to n so we 744117328Sluigi * use that to count the number of entries. 745117328Sluigi */ 746117328Sluigi for (len = len / 2; len > 0; len--, a += 2) { 747117328Sluigi int mb = /* mask length */ 748117328Sluigi (cmd->o.opcode == O_IP_SRC || cmd->o.opcode == O_IP_DST) ? 749117577Sluigi 32 : contigmask((uint8_t *)&(a[1]), 32); 75098943Sluigi if (mb == 32 && do_resolv) 751117328Sluigi he = gethostbyaddr((char *)&(a[0]), sizeof(u_long), AF_INET); 75298943Sluigi if (he != NULL) /* resolved to name */ 75398943Sluigi printf("%s", he->h_name); 75498943Sluigi else if (mb == 0) /* any */ 75598943Sluigi printf("any"); 75698943Sluigi else { /* numeric IP followed by some kind of mask */ 757117328Sluigi printf("%s", inet_ntoa( *((struct in_addr *)&a[0]) ) ); 75898943Sluigi if (mb < 0) 759117328Sluigi printf(":%s", inet_ntoa( *((struct in_addr *)&a[1]) ) ); 76098943Sluigi else if (mb < 32) 76198943Sluigi printf("/%d", mb); 76298943Sluigi } 763117328Sluigi if (len > 1) 764117328Sluigi printf(","); 765117328Sluigi } 76698943Sluigi} 76798943Sluigi 76898943Sluigi/* 76998943Sluigi * prints a MAC address/mask pair 77098943Sluigi */ 77198943Sluigistatic void 772117577Sluigiprint_mac(uint8_t *addr, uint8_t *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; 883117626Sluigi char *comment = NULL; /* ptr to comment if we have one */ 88498943Sluigi int proto = 0; /* default */ 88598943Sluigi int flags = 0; /* prerequisites */ 88698943Sluigi ipfw_insn_log *logptr = NULL; /* set if we find an O_LOG */ 88798943Sluigi int or_block = 0; /* we are in an or block */ 888117328Sluigi uint32_t set_disable; 88998943Sluigi 890115793Sticso bcopy(&rule->next_rule, &set_disable, sizeof(set_disable)); 891101628Sluigi 892101628Sluigi if (set_disable & (1 << rule->set)) { /* disabled */ 893101628Sluigi if (!show_sets) 894101628Sluigi return; 895101628Sluigi else 896101628Sluigi printf("# DISABLED "); 897101628Sluigi } 89898943Sluigi printf("%05u ", rule->rulenum); 89998943Sluigi 900117469Sluigi if (pcwidth>0 || bcwidth>0) 901115793Sticso printf("%*llu %*llu ", pcwidth, align_uint64(&rule->pcnt), 902115793Sticso bcwidth, align_uint64(&rule->bcnt)); 90398943Sluigi 904117472Sluigi if (do_time == 2) 905117472Sluigi printf("%10u ", rule->timestamp); 906117472Sluigi else if (do_time == 1) { 907107291Skeramida char timestr[30]; 908107291Skeramida time_t t = (time_t)0; 909107291Skeramida 910107291Skeramida if (twidth == 0) { 911107291Skeramida strcpy(timestr, ctime(&t)); 912107291Skeramida *strchr(timestr, '\n') = '\0'; 913107291Skeramida twidth = strlen(timestr); 914107291Skeramida } 91598943Sluigi if (rule->timestamp) { 916117469Sluigi#if _FreeBSD_version < 500000 /* XXX check */ 917117469Sluigi#define _long_to_time(x) (time_t)(x) 918117469Sluigi#endif 919107291Skeramida t = _long_to_time(rule->timestamp); 92098943Sluigi 92198943Sluigi strcpy(timestr, ctime(&t)); 92298943Sluigi *strchr(timestr, '\n') = '\0'; 92398943Sluigi printf("%s ", timestr); 92498943Sluigi } else { 925107291Skeramida printf("%*s", twidth, " "); 92698943Sluigi } 92798943Sluigi } 92898943Sluigi 929101628Sluigi if (show_sets) 930101628Sluigi printf("set %d ", rule->set); 931101628Sluigi 93298943Sluigi /* 933107289Sluigi * print the optional "match probability" 934107289Sluigi */ 935107289Sluigi if (rule->cmd_len > 0) { 936107289Sluigi cmd = rule->cmd ; 937107289Sluigi if (cmd->opcode == O_PROB) { 938107289Sluigi ipfw_insn_u32 *p = (ipfw_insn_u32 *)cmd; 939107289Sluigi double d = 1.0 * p->d[0]; 940107289Sluigi 941107289Sluigi d = (d / 0x7fffffff); 942107289Sluigi printf("prob %f ", d); 943107289Sluigi } 944107289Sluigi } 945107289Sluigi 946107289Sluigi /* 94798943Sluigi * first print actions 94898943Sluigi */ 94998943Sluigi for (l = rule->cmd_len - rule->act_ofs, cmd = ACTION_PTR(rule); 95098943Sluigi l > 0 ; l -= F_LEN(cmd), cmd += F_LEN(cmd)) { 95198943Sluigi switch(cmd->opcode) { 95298943Sluigi case O_CHECK_STATE: 95398943Sluigi printf("check-state"); 954102087Sluigi flags = HAVE_IP; /* avoid printing anything else */ 95598943Sluigi break; 95698943Sluigi 95798943Sluigi case O_ACCEPT: 95898943Sluigi printf("allow"); 95998943Sluigi break; 96098943Sluigi 96198943Sluigi case O_COUNT: 96298943Sluigi printf("count"); 96398943Sluigi break; 96498943Sluigi 96598943Sluigi case O_DENY: 96698943Sluigi printf("deny"); 96798943Sluigi break; 96898943Sluigi 96999475Sluigi case O_REJECT: 97099475Sluigi if (cmd->arg1 == ICMP_REJECT_RST) 97199475Sluigi printf("reset"); 97299475Sluigi else if (cmd->arg1 == ICMP_UNREACH_HOST) 97399475Sluigi printf("reject"); 97499475Sluigi else 97599475Sluigi print_reject_code(cmd->arg1); 97699475Sluigi break; 97799475Sluigi 97898943Sluigi case O_SKIPTO: 97998943Sluigi printf("skipto %u", cmd->arg1); 98098943Sluigi break; 98198943Sluigi 98298943Sluigi case O_PIPE: 98398943Sluigi printf("pipe %u", cmd->arg1); 98498943Sluigi break; 98598943Sluigi 98698943Sluigi case O_QUEUE: 98798943Sluigi printf("queue %u", cmd->arg1); 98898943Sluigi break; 98998943Sluigi 99098943Sluigi case O_DIVERT: 99198943Sluigi printf("divert %u", cmd->arg1); 99298943Sluigi break; 99398943Sluigi 99498943Sluigi case O_TEE: 99598943Sluigi printf("tee %u", cmd->arg1); 99698943Sluigi break; 99798943Sluigi 99898943Sluigi case O_FORWARD_IP: 99998943Sluigi { 100098943Sluigi ipfw_insn_sa *s = (ipfw_insn_sa *)cmd; 100198943Sluigi 100298943Sluigi printf("fwd %s", inet_ntoa(s->sa.sin_addr)); 100398943Sluigi if (s->sa.sin_port) 1004103241Sluigi printf(",%d", s->sa.sin_port); 100598943Sluigi } 100698943Sluigi break; 100798943Sluigi 100898943Sluigi case O_LOG: /* O_LOG is printed last */ 100998943Sluigi logptr = (ipfw_insn_log *)cmd; 101098943Sluigi break; 101198943Sluigi 101298943Sluigi default: 101398943Sluigi printf("** unrecognized action %d len %d", 101498943Sluigi cmd->opcode, cmd->len); 101598943Sluigi } 101698943Sluigi } 101798943Sluigi if (logptr) { 101898943Sluigi if (logptr->max_log > 0) 101999909Sluigi printf(" log logamount %d", logptr->max_log); 102098943Sluigi else 102199909Sluigi printf(" log"); 102298943Sluigi } 1023102087Sluigi 102498943Sluigi /* 1025102087Sluigi * then print the body. 102698943Sluigi */ 1027102087Sluigi if (rule->_pad & 1) { /* empty rules before options */ 1028102098Sluigi if (!do_compact) 1029102098Sluigi printf(" ip from any to any"); 1030102087Sluigi flags |= HAVE_IP | HAVE_OPTIONS; 1031102087Sluigi } 1032102087Sluigi 103398943Sluigi for (l = rule->act_ofs, cmd = rule->cmd ; 103498943Sluigi l > 0 ; l -= F_LEN(cmd) , cmd += F_LEN(cmd)) { 103599475Sluigi /* useful alias */ 103699475Sluigi ipfw_insn_u32 *cmd32 = (ipfw_insn_u32 *)cmd; 103798943Sluigi 1038102087Sluigi show_prerequisites(&flags, 0, cmd->opcode); 1039102087Sluigi 104098943Sluigi switch(cmd->opcode) { 1041117577Sluigi case O_PROB: 1042107289Sluigi break; /* done already */ 1043107289Sluigi 104498943Sluigi case O_PROBE_STATE: 104598943Sluigi break; /* no need to print anything here */ 104698943Sluigi 104798943Sluigi case O_MACADDR2: { 104898943Sluigi ipfw_insn_mac *m = (ipfw_insn_mac *)cmd; 1049102087Sluigi 1050102087Sluigi if ((cmd->len & F_OR) && !or_block) 1051102087Sluigi printf(" {"); 105298943Sluigi if (cmd->len & F_NOT) 105398943Sluigi printf(" not"); 1054102087Sluigi printf(" MAC"); 1055102087Sluigi flags |= HAVE_MAC; 1056117577Sluigi print_mac(m->addr, m->mask); 1057117577Sluigi print_mac(m->addr + 6, m->mask + 6); 105898943Sluigi } 105998943Sluigi break; 106098943Sluigi 106198943Sluigi case O_MAC_TYPE: 1062102087Sluigi if ((cmd->len & F_OR) && !or_block) 1063102087Sluigi printf(" {"); 1064102087Sluigi print_newports((ipfw_insn_u16 *)cmd, IPPROTO_ETHERTYPE, 1065102087Sluigi (flags & HAVE_OPTIONS) ? cmd->opcode : 0); 1066102087Sluigi flags |= HAVE_MAC | HAVE_MACTYPE | HAVE_OPTIONS; 106798943Sluigi break; 106898943Sluigi 106998943Sluigi case O_IP_SRC: 107098943Sluigi case O_IP_SRC_MASK: 107198943Sluigi case O_IP_SRC_ME: 107298943Sluigi case O_IP_SRC_SET: 1073102087Sluigi show_prerequisites(&flags, HAVE_PROTO, 0); 107498943Sluigi if (!(flags & HAVE_SRCIP)) 107598943Sluigi printf(" from"); 107698943Sluigi if ((cmd->len & F_OR) && !or_block) 107798943Sluigi printf(" {"); 1078102087Sluigi print_ip((ipfw_insn_ip *)cmd, 1079102087Sluigi (flags & HAVE_OPTIONS) ? " src-ip" : ""); 108098943Sluigi flags |= HAVE_SRCIP; 108198943Sluigi break; 108298943Sluigi 108398943Sluigi case O_IP_DST: 108498943Sluigi case O_IP_DST_MASK: 108598943Sluigi case O_IP_DST_ME: 108698943Sluigi case O_IP_DST_SET: 1087102087Sluigi show_prerequisites(&flags, HAVE_PROTO|HAVE_SRCIP, 0); 108898943Sluigi if (!(flags & HAVE_DSTIP)) 108998943Sluigi printf(" to"); 109098943Sluigi if ((cmd->len & F_OR) && !or_block) 109198943Sluigi printf(" {"); 1092102087Sluigi print_ip((ipfw_insn_ip *)cmd, 1093102087Sluigi (flags & HAVE_OPTIONS) ? " dst-ip" : ""); 109498943Sluigi flags |= HAVE_DSTIP; 109598943Sluigi break; 109698943Sluigi 109798943Sluigi case O_IP_DSTPORT: 1098102087Sluigi show_prerequisites(&flags, HAVE_IP, 0); 109998943Sluigi case O_IP_SRCPORT: 1100102087Sluigi show_prerequisites(&flags, HAVE_PROTO|HAVE_SRCIP, 0); 1101101641Sluigi if ((cmd->len & F_OR) && !or_block) 1102101641Sluigi printf(" {"); 1103102087Sluigi print_newports((ipfw_insn_u16 *)cmd, proto, 1104102087Sluigi (flags & HAVE_OPTIONS) ? cmd->opcode : 0); 110598943Sluigi break; 110698943Sluigi 110798943Sluigi case O_PROTO: { 110898943Sluigi struct protoent *pe; 110998943Sluigi 111098943Sluigi if ((cmd->len & F_OR) && !or_block) 111198943Sluigi printf(" {"); 111298943Sluigi if (cmd->len & F_NOT) 111398943Sluigi printf(" not"); 111498943Sluigi proto = cmd->arg1; 111598943Sluigi pe = getprotobynumber(cmd->arg1); 1116102087Sluigi if (flags & HAVE_OPTIONS) 1117102087Sluigi printf(" proto"); 111898943Sluigi if (pe) 111998943Sluigi printf(" %s", pe->p_name); 112098943Sluigi else 112198943Sluigi printf(" %u", cmd->arg1); 112298943Sluigi } 112398943Sluigi flags |= HAVE_PROTO; 112498943Sluigi break; 1125106505Smaxim 112698943Sluigi default: /*options ... */ 1127102087Sluigi show_prerequisites(&flags, HAVE_IP | HAVE_OPTIONS, 0); 112898943Sluigi if ((cmd->len & F_OR) && !or_block) 112998943Sluigi printf(" {"); 113098943Sluigi if (cmd->len & F_NOT && cmd->opcode != O_IN) 113198943Sluigi printf(" not"); 113298943Sluigi switch(cmd->opcode) { 113398943Sluigi case O_FRAG: 113498943Sluigi printf(" frag"); 113598943Sluigi break; 113698943Sluigi 113798943Sluigi case O_IN: 113898943Sluigi printf(cmd->len & F_NOT ? " out" : " in"); 113998943Sluigi break; 114098943Sluigi 114198943Sluigi case O_LAYER2: 114298943Sluigi printf(" layer2"); 114398943Sluigi break; 114498943Sluigi case O_XMIT: 114598943Sluigi case O_RECV: 114698943Sluigi case O_VIA: { 1147117469Sluigi char const *s; 114898943Sluigi ipfw_insn_if *cmdif = (ipfw_insn_if *)cmd; 114998943Sluigi 115098943Sluigi if (cmd->opcode == O_XMIT) 115198943Sluigi s = "xmit"; 115298943Sluigi else if (cmd->opcode == O_RECV) 115398943Sluigi s = "recv"; 1154117469Sluigi else /* if (cmd->opcode == O_VIA) */ 115598943Sluigi s = "via"; 115698943Sluigi if (cmdif->name[0] == '\0') 115799475Sluigi printf(" %s %s", s, 115899475Sluigi inet_ntoa(cmdif->p.ip)); 1159121816Sbrooks printf(" %s %s", s, cmdif->name); 116098943Sluigi } 116198943Sluigi break; 116298943Sluigi 116398943Sluigi case O_IPID: 1164116690Sluigi if (F_LEN(cmd) == 1) 1165116690Sluigi printf(" ipid %u", cmd->arg1 ); 1166116690Sluigi else 1167116690Sluigi print_newports((ipfw_insn_u16 *)cmd, 0, 1168116690Sluigi O_IPID); 116998943Sluigi break; 117098943Sluigi 117198943Sluigi case O_IPTTL: 1172116690Sluigi if (F_LEN(cmd) == 1) 1173116690Sluigi printf(" ipttl %u", cmd->arg1 ); 1174116690Sluigi else 1175116690Sluigi print_newports((ipfw_insn_u16 *)cmd, 0, 1176116690Sluigi O_IPTTL); 117798943Sluigi break; 117898943Sluigi 117998943Sluigi case O_IPVER: 118098943Sluigi printf(" ipver %u", cmd->arg1 ); 118198943Sluigi break; 118298943Sluigi 118399475Sluigi case O_IPPRECEDENCE: 118499475Sluigi printf(" ipprecedence %u", (cmd->arg1) >> 5 ); 118599475Sluigi break; 118699475Sluigi 118798943Sluigi case O_IPLEN: 1188116690Sluigi if (F_LEN(cmd) == 1) 1189116690Sluigi printf(" iplen %u", cmd->arg1 ); 1190116690Sluigi else 1191116690Sluigi print_newports((ipfw_insn_u16 *)cmd, 0, 1192116690Sluigi O_IPLEN); 119398943Sluigi break; 119498943Sluigi 1195101116Sluigi case O_IPOPT: 119698943Sluigi print_flags("ipoptions", cmd, f_ipopts); 119798943Sluigi break; 119898943Sluigi 119999475Sluigi case O_IPTOS: 120099475Sluigi print_flags("iptos", cmd, f_iptos); 120199475Sluigi break; 120299475Sluigi 120399475Sluigi case O_ICMPTYPE: 120499475Sluigi print_icmptypes((ipfw_insn_u32 *)cmd); 120599475Sluigi break; 120699475Sluigi 120798943Sluigi case O_ESTAB: 120898943Sluigi printf(" established"); 120998943Sluigi break; 121098943Sluigi 121198943Sluigi case O_TCPFLAGS: 121298943Sluigi print_flags("tcpflags", cmd, f_tcpflags); 121398943Sluigi break; 121498943Sluigi 121598943Sluigi case O_TCPOPTS: 121698943Sluigi print_flags("tcpoptions", cmd, f_tcpopts); 121798943Sluigi break; 121898943Sluigi 121998943Sluigi case O_TCPWIN: 122098943Sluigi printf(" tcpwin %d", ntohs(cmd->arg1)); 122198943Sluigi break; 122298943Sluigi 122398943Sluigi case O_TCPACK: 122498943Sluigi printf(" tcpack %d", ntohl(cmd32->d[0])); 122598943Sluigi break; 122698943Sluigi 122798943Sluigi case O_TCPSEQ: 122898943Sluigi printf(" tcpseq %d", ntohl(cmd32->d[0])); 122998943Sluigi break; 123098943Sluigi 123198943Sluigi case O_UID: 123298943Sluigi { 123398943Sluigi struct passwd *pwd = getpwuid(cmd32->d[0]); 123498943Sluigi 123598943Sluigi if (pwd) 123698943Sluigi printf(" uid %s", pwd->pw_name); 123798943Sluigi else 123898943Sluigi printf(" uid %u", cmd32->d[0]); 123998943Sluigi } 124098943Sluigi break; 124198943Sluigi 124298943Sluigi case O_GID: 124398943Sluigi { 124498943Sluigi struct group *grp = getgrgid(cmd32->d[0]); 124598943Sluigi 124698943Sluigi if (grp) 124798943Sluigi printf(" gid %s", grp->gr_name); 124898943Sluigi else 124998943Sluigi printf(" gid %u", cmd32->d[0]); 125098943Sluigi } 125198943Sluigi break; 125298943Sluigi 1253112250Scjc case O_VERREVPATH: 1254112250Scjc printf(" verrevpath"); 1255112250Scjc break; 1256116919Sluigi 1257117241Sluigi case O_IPSEC: 1258117241Sluigi printf(" ipsec"); 1259117241Sluigi break; 1260117241Sluigi 1261117469Sluigi case O_NOP: 1262117626Sluigi comment = (char *)(cmd + 1); 1263117469Sluigi break; 1264117469Sluigi 126598943Sluigi case O_KEEP_STATE: 126698943Sluigi printf(" keep-state"); 126798943Sluigi break; 126898943Sluigi 126998943Sluigi case O_LIMIT: 127098943Sluigi { 127198943Sluigi struct _s_x *p = limit_masks; 127298943Sluigi ipfw_insn_limit *c = (ipfw_insn_limit *)cmd; 1273117328Sluigi uint8_t x = c->limit_mask; 1274117469Sluigi char const *comma = " "; 127598943Sluigi 127698943Sluigi printf(" limit"); 1277117577Sluigi for (; p->x != 0 ; p++) 127899909Sluigi if ((x & p->x) == p->x) { 127998943Sluigi x &= ~p->x; 128098943Sluigi printf("%s%s", comma, p->s); 128198943Sluigi comma = ","; 128298943Sluigi } 128398943Sluigi printf(" %d", c->conn_limit); 128498943Sluigi } 128598943Sluigi break; 128698943Sluigi 128798943Sluigi default: 128898943Sluigi printf(" [opcode %d len %d]", 128998943Sluigi cmd->opcode, cmd->len); 129098943Sluigi } 129198943Sluigi } 129298943Sluigi if (cmd->len & F_OR) { 129398943Sluigi printf(" or"); 129498943Sluigi or_block = 1; 129598943Sluigi } else if (or_block) { 129698943Sluigi printf(" }"); 129798943Sluigi or_block = 0; 129898943Sluigi } 129998943Sluigi } 1300102087Sluigi show_prerequisites(&flags, HAVE_IP, 0); 1301117626Sluigi if (comment) 1302117626Sluigi printf(" // %s", comment); 130398943Sluigi printf("\n"); 130498943Sluigi} 130598943Sluigi 130698943Sluigistatic void 1307112189Smaximshow_dyn_ipfw(ipfw_dyn_rule *d, int pcwidth, int bcwidth) 130898943Sluigi{ 130998943Sluigi struct protoent *pe; 131098943Sluigi struct in_addr a; 1311115793Sticso uint16_t rulenum; 131298943Sluigi 131398943Sluigi if (!do_expired) { 131498943Sluigi if (!d->expire && !(d->dyn_type == O_LIMIT_PARENT)) 131598943Sluigi return; 131698943Sluigi } 1317115793Sticso bcopy(&d->rule, &rulenum, sizeof(rulenum)); 1318117328Sluigi printf("%05d", rulenum); 1319117469Sluigi if (pcwidth>0 || bcwidth>0) 1320117328Sluigi printf(" %*llu %*llu (%ds)", pcwidth, 1321117328Sluigi align_uint64(&d->pcnt), bcwidth, 1322117328Sluigi align_uint64(&d->bcnt), d->expire); 132398943Sluigi switch (d->dyn_type) { 132498943Sluigi case O_LIMIT_PARENT: 132598943Sluigi printf(" PARENT %d", d->count); 132698943Sluigi break; 132798943Sluigi case O_LIMIT: 132898943Sluigi printf(" LIMIT"); 132998943Sluigi break; 133098943Sluigi case O_KEEP_STATE: /* bidir, no mask */ 1331106505Smaxim printf(" STATE"); 133298943Sluigi break; 133398943Sluigi } 133498943Sluigi 133598943Sluigi if ((pe = getprotobynumber(d->id.proto)) != NULL) 133698943Sluigi printf(" %s", pe->p_name); 133798943Sluigi else 133898943Sluigi printf(" proto %u", d->id.proto); 133998943Sluigi 134098943Sluigi a.s_addr = htonl(d->id.src_ip); 134198943Sluigi printf(" %s %d", inet_ntoa(a), d->id.src_port); 134298943Sluigi 134398943Sluigi a.s_addr = htonl(d->id.dst_ip); 134498943Sluigi printf(" <-> %s %d", inet_ntoa(a), d->id.dst_port); 134598943Sluigi printf("\n"); 134698943Sluigi} 134798943Sluigi 1348117469Sluigistatic int 134998943Sluigisort_q(const void *pa, const void *pb) 135098943Sluigi{ 135198943Sluigi int rev = (do_sort < 0); 135298943Sluigi int field = rev ? -do_sort : do_sort; 135398943Sluigi long long res = 0; 135498943Sluigi const struct dn_flow_queue *a = pa; 135598943Sluigi const struct dn_flow_queue *b = pb; 135698943Sluigi 135798943Sluigi switch (field) { 135898943Sluigi case 1: /* pkts */ 135998943Sluigi res = a->len - b->len; 136098943Sluigi break; 136198943Sluigi case 2: /* bytes */ 136298943Sluigi res = a->len_bytes - b->len_bytes; 136398943Sluigi break; 136498943Sluigi 136598943Sluigi case 3: /* tot pkts */ 136698943Sluigi res = a->tot_pkts - b->tot_pkts; 136798943Sluigi break; 136898943Sluigi 136998943Sluigi case 4: /* tot bytes */ 137098943Sluigi res = a->tot_bytes - b->tot_bytes; 137198943Sluigi break; 137298943Sluigi } 137398943Sluigi if (res < 0) 137498943Sluigi res = -1; 137598943Sluigi if (res > 0) 137698943Sluigi res = 1; 137798943Sluigi return (int)(rev ? res : -res); 137898943Sluigi} 137998943Sluigi 138098943Sluigistatic void 138198943Sluigilist_queues(struct dn_flow_set *fs, struct dn_flow_queue *q) 138298943Sluigi{ 138398943Sluigi int l; 138498943Sluigi 138598943Sluigi printf(" mask: 0x%02x 0x%08x/0x%04x -> 0x%08x/0x%04x\n", 138698943Sluigi fs->flow_mask.proto, 138798943Sluigi fs->flow_mask.src_ip, fs->flow_mask.src_port, 138898943Sluigi fs->flow_mask.dst_ip, fs->flow_mask.dst_port); 138998943Sluigi if (fs->rq_elements == 0) 139098943Sluigi return; 139198943Sluigi 139298943Sluigi printf("BKT Prot ___Source IP/port____ " 139398943Sluigi "____Dest. IP/port____ Tot_pkt/bytes Pkt/Byte Drp\n"); 139498943Sluigi if (do_sort != 0) 139598943Sluigi heapsort(q, fs->rq_elements, sizeof *q, sort_q); 139698943Sluigi for (l = 0; l < fs->rq_elements; l++) { 139798943Sluigi struct in_addr ina; 139898943Sluigi struct protoent *pe; 139998943Sluigi 140098943Sluigi ina.s_addr = htonl(q[l].id.src_ip); 140198943Sluigi printf("%3d ", q[l].hash_slot); 140298943Sluigi pe = getprotobynumber(q[l].id.proto); 140398943Sluigi if (pe) 140498943Sluigi printf("%-4s ", pe->p_name); 140598943Sluigi else 140698943Sluigi printf("%4u ", q[l].id.proto); 140798943Sluigi printf("%15s/%-5d ", 140898943Sluigi inet_ntoa(ina), q[l].id.src_port); 140998943Sluigi ina.s_addr = htonl(q[l].id.dst_ip); 141098943Sluigi printf("%15s/%-5d ", 141198943Sluigi inet_ntoa(ina), q[l].id.dst_port); 141298943Sluigi printf("%4qu %8qu %2u %4u %3u\n", 141398943Sluigi q[l].tot_pkts, q[l].tot_bytes, 141498943Sluigi q[l].len, q[l].len_bytes, q[l].drops); 141598943Sluigi if (verbose) 141698943Sluigi printf(" S %20qd F %20qd\n", 141798943Sluigi q[l].S, q[l].F); 141898943Sluigi } 141998943Sluigi} 142098943Sluigi 142198943Sluigistatic void 142298943Sluigiprint_flowset_parms(struct dn_flow_set *fs, char *prefix) 142398943Sluigi{ 142498943Sluigi int l; 142598943Sluigi char qs[30]; 142698943Sluigi char plr[30]; 142798943Sluigi char red[90]; /* Display RED parameters */ 142898943Sluigi 142998943Sluigi l = fs->qsize; 143098943Sluigi if (fs->flags_fs & DN_QSIZE_IS_BYTES) { 143198943Sluigi if (l >= 8192) 143298943Sluigi sprintf(qs, "%d KB", l / 1024); 143398943Sluigi else 143498943Sluigi sprintf(qs, "%d B", l); 143598943Sluigi } else 143698943Sluigi sprintf(qs, "%3d sl.", l); 143798943Sluigi if (fs->plr) 143898943Sluigi sprintf(plr, "plr %f", 1.0 * fs->plr / (double)(0x7fffffff)); 143998943Sluigi else 144098943Sluigi plr[0] = '\0'; 144198943Sluigi if (fs->flags_fs & DN_IS_RED) /* RED parameters */ 144298943Sluigi sprintf(red, 144398943Sluigi "\n\t %cRED w_q %f min_th %d max_th %d max_p %f", 144498943Sluigi (fs->flags_fs & DN_IS_GENTLE_RED) ? 'G' : ' ', 144598943Sluigi 1.0 * fs->w_q / (double)(1 << SCALE_RED), 144698943Sluigi SCALE_VAL(fs->min_th), 144798943Sluigi SCALE_VAL(fs->max_th), 144898943Sluigi 1.0 * fs->max_p / (double)(1 << SCALE_RED)); 144998943Sluigi else 145098943Sluigi sprintf(red, "droptail"); 145198943Sluigi 145298943Sluigi printf("%s %s%s %d queues (%d buckets) %s\n", 145398943Sluigi prefix, qs, plr, fs->rq_elements, fs->rq_size, red); 145498943Sluigi} 145598943Sluigi 145698943Sluigistatic void 1457117469Sluigilist_pipes(void *data, uint nbytes, int ac, char *av[]) 145898943Sluigi{ 1459117469Sluigi int rulenum; 146098943Sluigi void *next = data; 146198943Sluigi struct dn_pipe *p = (struct dn_pipe *) data; 146298943Sluigi struct dn_flow_set *fs; 146398943Sluigi struct dn_flow_queue *q; 146498943Sluigi int l; 146598943Sluigi 146698943Sluigi if (ac > 0) 146798943Sluigi rulenum = strtoul(*av++, NULL, 10); 146898943Sluigi else 146998943Sluigi rulenum = 0; 147098943Sluigi for (; nbytes >= sizeof *p; p = (struct dn_pipe *)next) { 147198943Sluigi double b = p->bandwidth; 147298943Sluigi char buf[30]; 147398943Sluigi char prefix[80]; 147498943Sluigi 147598943Sluigi if (p->next != (struct dn_pipe *)DN_IS_PIPE) 147698943Sluigi break; /* done with pipes, now queues */ 147798943Sluigi 147898943Sluigi /* 147998943Sluigi * compute length, as pipe have variable size 148098943Sluigi */ 148198943Sluigi l = sizeof(*p) + p->fs.rq_elements * sizeof(*q); 1482117469Sluigi next = (char *)p + l; 148398943Sluigi nbytes -= l; 148498943Sluigi 148598943Sluigi if (rulenum != 0 && rulenum != p->pipe_nr) 148698943Sluigi continue; 148798943Sluigi 148898943Sluigi /* 148998943Sluigi * Print rate (or clocking interface) 149098943Sluigi */ 149198943Sluigi if (p->if_name[0] != '\0') 149298943Sluigi sprintf(buf, "%s", p->if_name); 149398943Sluigi else if (b == 0) 149498943Sluigi sprintf(buf, "unlimited"); 149598943Sluigi else if (b >= 1000000) 149698943Sluigi sprintf(buf, "%7.3f Mbit/s", b/1000000); 149798943Sluigi else if (b >= 1000) 149898943Sluigi sprintf(buf, "%7.3f Kbit/s", b/1000); 149998943Sluigi else 150098943Sluigi sprintf(buf, "%7.3f bit/s ", b); 150198943Sluigi 150298943Sluigi sprintf(prefix, "%05d: %s %4d ms ", 150398943Sluigi p->pipe_nr, buf, p->delay); 150498943Sluigi print_flowset_parms(&(p->fs), prefix); 150598943Sluigi if (verbose) 150698943Sluigi printf(" V %20qd\n", p->V >> MY_M); 1507106505Smaxim 150898943Sluigi q = (struct dn_flow_queue *)(p+1); 150998943Sluigi list_queues(&(p->fs), q); 151098943Sluigi } 151198943Sluigi for (fs = next; nbytes >= sizeof *fs; fs = next) { 151298943Sluigi char prefix[80]; 151398943Sluigi 151498943Sluigi if (fs->next != (struct dn_flow_set *)DN_IS_QUEUE) 151598943Sluigi break; 151698943Sluigi l = sizeof(*fs) + fs->rq_elements * sizeof(*q); 1517117469Sluigi next = (char *)fs + l; 151898943Sluigi nbytes -= l; 151998943Sluigi q = (struct dn_flow_queue *)(fs+1); 152098943Sluigi sprintf(prefix, "q%05d: weight %d pipe %d ", 152198943Sluigi fs->fs_nr, fs->weight, fs->parent_nr); 152298943Sluigi print_flowset_parms(fs, prefix); 152398943Sluigi list_queues(fs, q); 152498943Sluigi } 152598943Sluigi} 152698943Sluigi 1527101978Sluigi/* 1528101978Sluigi * This one handles all set-related commands 1529101978Sluigi * ipfw set { show | enable | disable } 1530101978Sluigi * ipfw set swap X Y 1531101978Sluigi * ipfw set move X to Y 1532101978Sluigi * ipfw set move rule X to Y 1533101978Sluigi */ 153498943Sluigistatic void 1535101978Sluigisets_handler(int ac, char *av[]) 1536101978Sluigi{ 1537117328Sluigi uint32_t set_disable, masks[2]; 1538101978Sluigi int i, nbytes; 1539117328Sluigi uint16_t rulenum; 1540117328Sluigi uint8_t cmd, new_set; 1541101978Sluigi 1542101978Sluigi ac--; 1543101978Sluigi av++; 1544101978Sluigi 1545101978Sluigi if (!ac) 1546101978Sluigi errx(EX_USAGE, "set needs command"); 1547101978Sluigi if (!strncmp(*av, "show", strlen(*av)) ) { 1548101978Sluigi void *data; 1549117469Sluigi char const *msg; 1550101978Sluigi 1551101978Sluigi nbytes = sizeof(struct ip_fw); 1552117328Sluigi if ((data = calloc(1, nbytes)) == NULL) 1553117328Sluigi err(EX_OSERR, "calloc"); 1554119740Stmm if (do_cmd(IP_FW_GET, data, (uintptr_t)&nbytes) < 0) 1555101978Sluigi err(EX_OSERR, "getsockopt(IP_FW_GET)"); 1556115793Sticso bcopy(&((struct ip_fw *)data)->next_rule, 1557115793Sticso &set_disable, sizeof(set_disable)); 1558101978Sluigi 1559117655Sluigi for (i = 0, msg = "disable" ; i < RESVD_SET; i++) 1560117577Sluigi if ((set_disable & (1<<i))) { 1561101978Sluigi printf("%s %d", msg, i); 1562101978Sluigi msg = ""; 1563101978Sluigi } 1564101978Sluigi msg = (set_disable) ? " enable" : "enable"; 1565117655Sluigi for (i = 0; i < RESVD_SET; i++) 1566117577Sluigi if (!(set_disable & (1<<i))) { 1567101978Sluigi printf("%s %d", msg, i); 1568101978Sluigi msg = ""; 1569101978Sluigi } 1570101978Sluigi printf("\n"); 1571101978Sluigi } else if (!strncmp(*av, "swap", strlen(*av))) { 1572101978Sluigi ac--; av++; 1573101978Sluigi if (ac != 2) 1574101978Sluigi errx(EX_USAGE, "set swap needs 2 set numbers\n"); 1575101978Sluigi rulenum = atoi(av[0]); 1576101978Sluigi new_set = atoi(av[1]); 1577117655Sluigi if (!isdigit(*(av[0])) || rulenum > RESVD_SET) 1578101978Sluigi errx(EX_DATAERR, "invalid set number %s\n", av[0]); 1579117655Sluigi if (!isdigit(*(av[1])) || new_set > RESVD_SET) 1580101978Sluigi errx(EX_DATAERR, "invalid set number %s\n", av[1]); 1581101978Sluigi masks[0] = (4 << 24) | (new_set << 16) | (rulenum); 1582117328Sluigi i = do_cmd(IP_FW_DEL, masks, sizeof(uint32_t)); 1583101978Sluigi } else if (!strncmp(*av, "move", strlen(*av))) { 1584101978Sluigi ac--; av++; 1585101978Sluigi if (ac && !strncmp(*av, "rule", strlen(*av))) { 1586101978Sluigi cmd = 2; 1587101978Sluigi ac--; av++; 1588101978Sluigi } else 1589101978Sluigi cmd = 3; 1590101978Sluigi if (ac != 3 || strncmp(av[1], "to", strlen(*av))) 1591101978Sluigi errx(EX_USAGE, "syntax: set move [rule] X to Y\n"); 1592101978Sluigi rulenum = atoi(av[0]); 1593101978Sluigi new_set = atoi(av[2]); 1594117655Sluigi if (!isdigit(*(av[0])) || (cmd == 3 && rulenum > RESVD_SET) || 1595101978Sluigi (cmd == 2 && rulenum == 65535) ) 1596101978Sluigi errx(EX_DATAERR, "invalid source number %s\n", av[0]); 1597117655Sluigi if (!isdigit(*(av[2])) || new_set > RESVD_SET) 1598101978Sluigi errx(EX_DATAERR, "invalid dest. set %s\n", av[1]); 1599101978Sluigi masks[0] = (cmd << 24) | (new_set << 16) | (rulenum); 1600117328Sluigi i = do_cmd(IP_FW_DEL, masks, sizeof(uint32_t)); 1601101978Sluigi } else if (!strncmp(*av, "disable", strlen(*av)) || 1602101978Sluigi !strncmp(*av, "enable", strlen(*av)) ) { 1603101978Sluigi int which = !strncmp(*av, "enable", strlen(*av)) ? 1 : 0; 1604101978Sluigi 1605101978Sluigi ac--; av++; 1606101978Sluigi masks[0] = masks[1] = 0; 1607101978Sluigi 1608101978Sluigi while (ac) { 1609101978Sluigi if (isdigit(**av)) { 1610101978Sluigi i = atoi(*av); 1611117655Sluigi if (i < 0 || i > RESVD_SET) 1612101978Sluigi errx(EX_DATAERR, 1613101978Sluigi "invalid set number %d\n", i); 1614101978Sluigi masks[which] |= (1<<i); 1615101978Sluigi } else if (!strncmp(*av, "disable", strlen(*av))) 1616101978Sluigi which = 0; 1617101978Sluigi else if (!strncmp(*av, "enable", strlen(*av))) 1618101978Sluigi which = 1; 1619101978Sluigi else 1620101978Sluigi errx(EX_DATAERR, 1621101978Sluigi "invalid set command %s\n", *av); 1622101978Sluigi av++; ac--; 1623101978Sluigi } 1624101978Sluigi if ( (masks[0] & masks[1]) != 0 ) 1625101978Sluigi errx(EX_DATAERR, 1626101978Sluigi "cannot enable and disable the same set\n"); 1627101978Sluigi 1628117328Sluigi i = do_cmd(IP_FW_DEL, masks, sizeof(masks)); 1629101978Sluigi if (i) 1630101978Sluigi warn("set enable/disable: setsockopt(IP_FW_DEL)"); 1631101978Sluigi } else 1632101978Sluigi errx(EX_USAGE, "invalid set command %s\n", *av); 1633101978Sluigi} 1634101978Sluigi 1635101978Sluigistatic void 1636109126Sdillonsysctl_handler(int ac, char *av[], int which) 1637109126Sdillon{ 1638109126Sdillon ac--; 1639109126Sdillon av++; 1640109126Sdillon 1641119668Smaxim if (ac == 0) { 1642109126Sdillon warnx("missing keyword to enable/disable\n"); 1643109126Sdillon } else if (strncmp(*av, "firewall", strlen(*av)) == 0) { 1644116770Sluigi sysctlbyname("net.inet.ip.fw.enable", NULL, 0, 1645116770Sluigi &which, sizeof(which)); 1646109126Sdillon } else if (strncmp(*av, "one_pass", strlen(*av)) == 0) { 1647116770Sluigi sysctlbyname("net.inet.ip.fw.one_pass", NULL, 0, 1648116770Sluigi &which, sizeof(which)); 1649109126Sdillon } else if (strncmp(*av, "debug", strlen(*av)) == 0) { 1650116770Sluigi sysctlbyname("net.inet.ip.fw.debug", NULL, 0, 1651116770Sluigi &which, sizeof(which)); 1652109126Sdillon } else if (strncmp(*av, "verbose", strlen(*av)) == 0) { 1653116770Sluigi sysctlbyname("net.inet.ip.fw.verbose", NULL, 0, 1654116770Sluigi &which, sizeof(which)); 1655109126Sdillon } else if (strncmp(*av, "dyn_keepalive", strlen(*av)) == 0) { 1656116770Sluigi sysctlbyname("net.inet.ip.fw.dyn_keepalive", NULL, 0, 1657116770Sluigi &which, sizeof(which)); 1658109126Sdillon } else { 1659109126Sdillon warnx("unrecognize enable/disable keyword: %s\n", *av); 1660109126Sdillon } 1661109126Sdillon} 1662109126Sdillon 1663109126Sdillonstatic void 1664117469Sluigilist(int ac, char *av[], int show_counters) 166598943Sluigi{ 166698943Sluigi struct ip_fw *r; 166798943Sluigi ipfw_dyn_rule *dynrules, *d; 166898943Sluigi 1669117469Sluigi#define NEXT(r) ((struct ip_fw *)((char *)r + RULESIZE(r))) 1670117469Sluigi char *lim; 1671117469Sluigi void *data = NULL; 1672112189Smaxim int bcwidth, n, nbytes, nstat, ndyn, pcwidth, width; 167398943Sluigi int exitval = EX_OK; 167498943Sluigi int lac; 167598943Sluigi char **lav; 1676117469Sluigi u_long rnum, last; 167798943Sluigi char *endptr; 167898943Sluigi int seen = 0; 167998943Sluigi 168098943Sluigi const int ocmd = do_pipe ? IP_DUMMYNET_GET : IP_FW_GET; 168198943Sluigi int nalloc = 1024; /* start somewhere... */ 168298943Sluigi 1683117328Sluigi if (test_only) { 1684117328Sluigi fprintf(stderr, "Testing only, list disabled\n"); 1685117328Sluigi return; 1686117328Sluigi } 1687117328Sluigi 168898943Sluigi ac--; 168998943Sluigi av++; 169098943Sluigi 169198943Sluigi /* get rules or pipes from kernel, resizing array as necessary */ 169298943Sluigi nbytes = nalloc; 169398943Sluigi 169498943Sluigi while (nbytes >= nalloc) { 169598943Sluigi nalloc = nalloc * 2 + 200; 169698943Sluigi nbytes = nalloc; 169798943Sluigi if ((data = realloc(data, nbytes)) == NULL) 169898943Sluigi err(EX_OSERR, "realloc"); 1699119740Stmm if (do_cmd(ocmd, data, (uintptr_t)&nbytes) < 0) 170098943Sluigi err(EX_OSERR, "getsockopt(IP_%s_GET)", 170198943Sluigi do_pipe ? "DUMMYNET" : "FW"); 170298943Sluigi } 170398943Sluigi 170498943Sluigi if (do_pipe) { 170598943Sluigi list_pipes(data, nbytes, ac, av); 170698943Sluigi goto done; 170798943Sluigi } 170898943Sluigi 170998943Sluigi /* 171098943Sluigi * Count static rules. They have variable size so we 171198943Sluigi * need to scan the list to count them. 171298943Sluigi */ 1713117469Sluigi for (nstat = 1, r = data, lim = (char *)data + nbytes; 1714117469Sluigi r->rulenum < 65535 && (char *)r < lim; 1715117469Sluigi ++nstat, r = NEXT(r) ) 171698943Sluigi ; /* nothing */ 171798943Sluigi 171898943Sluigi /* 171998943Sluigi * Count dynamic rules. This is easier as they have 172098943Sluigi * fixed size. 172198943Sluigi */ 1722117469Sluigi r = NEXT(r); 172398943Sluigi dynrules = (ipfw_dyn_rule *)r ; 1724117469Sluigi n = (char *)r - (char *)data; 172598943Sluigi ndyn = (nbytes - n) / sizeof *dynrules; 172698943Sluigi 1727112189Smaxim /* if showing stats, figure out column widths ahead of time */ 1728112189Smaxim bcwidth = pcwidth = 0; 1729117469Sluigi if (show_counters) { 1730117469Sluigi for (n = 0, r = data; n < nstat; n++, r = NEXT(r)) { 1731112189Smaxim /* packet counter */ 1732115793Sticso width = snprintf(NULL, 0, "%llu", 1733115793Sticso align_uint64(&r->pcnt)); 1734112189Smaxim if (width > pcwidth) 1735112189Smaxim pcwidth = width; 1736112189Smaxim 1737112189Smaxim /* byte counter */ 1738115793Sticso width = snprintf(NULL, 0, "%llu", 1739115793Sticso align_uint64(&r->bcnt)); 1740112189Smaxim if (width > bcwidth) 1741112189Smaxim bcwidth = width; 1742112189Smaxim } 1743112189Smaxim } 1744112189Smaxim if (do_dynamic && ndyn) { 1745112189Smaxim for (n = 0, d = dynrules; n < ndyn; n++, d++) { 1746115793Sticso width = snprintf(NULL, 0, "%llu", 1747115793Sticso align_uint64(&d->pcnt)); 1748112189Smaxim if (width > pcwidth) 1749112189Smaxim pcwidth = width; 1750112189Smaxim 1751115793Sticso width = snprintf(NULL, 0, "%llu", 1752115793Sticso align_uint64(&d->bcnt)); 1753112189Smaxim if (width > bcwidth) 1754112189Smaxim bcwidth = width; 1755112189Smaxim } 1756112189Smaxim } 175798943Sluigi /* if no rule numbers were specified, list all rules */ 175898943Sluigi if (ac == 0) { 1759117469Sluigi for (n = 0, r = data; n < nstat; n++, r = NEXT(r) ) 1760112189Smaxim show_ipfw(r, pcwidth, bcwidth); 176198943Sluigi 176298943Sluigi if (do_dynamic && ndyn) { 176398943Sluigi printf("## Dynamic rules (%d):\n", ndyn); 176498943Sluigi for (n = 0, d = dynrules; n < ndyn; n++, d++) 1765112189Smaxim show_dyn_ipfw(d, pcwidth, bcwidth); 176698943Sluigi } 176798943Sluigi goto done; 176898943Sluigi } 176998943Sluigi 177098943Sluigi /* display specific rules requested on command line */ 177198943Sluigi 177298943Sluigi for (lac = ac, lav = av; lac != 0; lac--) { 177398943Sluigi /* convert command line rule # */ 1774117469Sluigi last = rnum = strtoul(*lav++, &endptr, 10); 1775117469Sluigi if (*endptr == '-') 1776117469Sluigi last = strtoul(endptr+1, &endptr, 10); 177798943Sluigi if (*endptr) { 177898943Sluigi exitval = EX_USAGE; 177998943Sluigi warnx("invalid rule number: %s", *(lav - 1)); 178098943Sluigi continue; 178198943Sluigi } 1782117469Sluigi for (n = seen = 0, r = data; n < nstat; n++, r = NEXT(r) ) { 1783117469Sluigi if (r->rulenum > last) 178498943Sluigi break; 1785117469Sluigi if (r->rulenum >= rnum && r->rulenum <= last) { 1786112189Smaxim show_ipfw(r, pcwidth, bcwidth); 178798943Sluigi seen = 1; 178898943Sluigi } 178998943Sluigi } 179098943Sluigi if (!seen) { 179198943Sluigi /* give precedence to other error(s) */ 179298943Sluigi if (exitval == EX_OK) 179398943Sluigi exitval = EX_UNAVAILABLE; 179498943Sluigi warnx("rule %lu does not exist", rnum); 179598943Sluigi } 179698943Sluigi } 179798943Sluigi 179898943Sluigi if (do_dynamic && ndyn) { 179998943Sluigi printf("## Dynamic rules:\n"); 180098943Sluigi for (lac = ac, lav = av; lac != 0; lac--) { 180198943Sluigi rnum = strtoul(*lav++, &endptr, 10); 1802117469Sluigi if (*endptr == '-') 1803117469Sluigi last = strtoul(endptr+1, &endptr, 10); 180498943Sluigi if (*endptr) 180598943Sluigi /* already warned */ 180698943Sluigi continue; 180798943Sluigi for (n = 0, d = dynrules; n < ndyn; n++, d++) { 1808115793Sticso uint16_t rulenum; 1809115793Sticso 1810115793Sticso bcopy(&d->rule, &rulenum, sizeof(rulenum)); 1811115793Sticso if (rulenum > rnum) 181298943Sluigi break; 1813117469Sluigi if (r->rulenum >= rnum && r->rulenum <= last) 1814112189Smaxim show_dyn_ipfw(d, pcwidth, bcwidth); 181598943Sluigi } 181698943Sluigi } 181798943Sluigi } 181898943Sluigi 181998943Sluigi ac = 0; 182098943Sluigi 182198943Sluigidone: 182298943Sluigi free(data); 182398943Sluigi 182498943Sluigi if (exitval != EX_OK) 182598943Sluigi exit(exitval); 1826117469Sluigi#undef NEXT 182798943Sluigi} 182898943Sluigi 182998943Sluigistatic void 183098943Sluigishow_usage(void) 183198943Sluigi{ 183298943Sluigi fprintf(stderr, "usage: ipfw [options]\n" 183398943Sluigi"do \"ipfw -h\" or see ipfw manpage for details\n" 183498943Sluigi); 183598943Sluigi exit(EX_USAGE); 183698943Sluigi} 183798943Sluigi 183898943Sluigistatic void 183998943Sluigihelp(void) 184098943Sluigi{ 1841117328Sluigi fprintf(stderr, 1842117328Sluigi"ipfw syntax summary (but please do read the ipfw(8) manpage):\n" 1843117577Sluigi"ipfw [-acdeftTnNpqS] <command> where <command> is one of:\n" 1844117328Sluigi"add [num] [set N] [prob x] RULE-BODY\n" 1845117328Sluigi"{pipe|queue} N config PIPE-BODY\n" 1846117328Sluigi"[pipe|queue] {zero|delete|show} [N{,N}]\n" 1847117328Sluigi"set [disable N... enable N...] | move [rule] X to Y | swap X Y | show\n" 184898943Sluigi"\n" 1849117328Sluigi"RULE-BODY: check-state [LOG] | ACTION [LOG] ADDR [OPTION_LIST]\n" 185098943Sluigi"ACTION: check-state | allow | count | deny | reject | skipto N |\n" 185198943Sluigi" {divert|tee} PORT | forward ADDR | pipe N | queue N\n" 185298943Sluigi"ADDR: [ MAC dst src ether_type ] \n" 1853117544Sluigi" [ from IPADDR [ PORT ] to IPADDR [ PORTLIST ] ]\n" 1854117544Sluigi"IPADDR: [not] { any | me | ip/bits{x,y,z} | IPLIST }\n" 1855117544Sluigi"IPLIST: { ip | ip/bits | ip:mask }[,IPLIST]\n" 1856117544Sluigi"OPTION_LIST: OPTION [OPTION_LIST]\n" 1857117328Sluigi"OPTION: bridged | {dst-ip|src-ip} ADDR | {dst-port|src-port} LIST |\n" 1858117328Sluigi" estab | frag | {gid|uid} N | icmptypes LIST | in | out | ipid LIST |\n" 1859117328Sluigi" iplen LIST | ipoptions SPEC | ipprecedence | ipsec | iptos SPEC |\n" 1860117328Sluigi" ipttl LIST | ipversion VER | keep-state | layer2 | limit ... |\n" 1861117328Sluigi" mac ... | mac-type LIST | proto LIST | {recv|xmit|via} {IF|IPADDR} |\n" 1862117328Sluigi" setup | {tcpack|tcpseq|tcpwin} NN | tcpflags SPEC | tcpoptions SPEC |\n" 1863117328Sluigi" verrevpath\n" 186498943Sluigi); 186598943Sluigiexit(0); 186698943Sluigi} 186798943Sluigi 186898943Sluigi 186998943Sluigistatic int 187098943Sluigilookup_host (char *host, struct in_addr *ipaddr) 187198943Sluigi{ 187298943Sluigi struct hostent *he; 187398943Sluigi 187498943Sluigi if (!inet_aton(host, ipaddr)) { 187598943Sluigi if ((he = gethostbyname(host)) == NULL) 187698943Sluigi return(-1); 187798943Sluigi *ipaddr = *(struct in_addr *)he->h_addr_list[0]; 187898943Sluigi } 187998943Sluigi return(0); 188098943Sluigi} 188198943Sluigi 188298943Sluigi/* 188398943Sluigi * fills the addr and mask fields in the instruction as appropriate from av. 188498943Sluigi * Update length as appropriate. 188598943Sluigi * The following formats are allowed: 188698943Sluigi * any matches any IP. Actually returns an empty instruction. 188798943Sluigi * me returns O_IP_*_ME 188898943Sluigi * 1.2.3.4 single IP address 188998943Sluigi * 1.2.3.4:5.6.7.8 address:mask 189098943Sluigi * 1.2.3.4/24 address/mask 189198943Sluigi * 1.2.3.4/26{1,6,5,4,23} set of addresses in a subnet 1892117328Sluigi * We can have multiple comma-separated address/mask entries. 189398943Sluigi */ 189498943Sluigistatic void 189598943Sluigifill_ip(ipfw_insn_ip *cmd, char *av) 189698943Sluigi{ 1897117328Sluigi int len = 0; 1898117328Sluigi uint32_t *d = ((ipfw_insn_u32 *)cmd)->d; 189998943Sluigi 190098943Sluigi cmd->o.len &= ~F_LEN_MASK; /* zero len */ 190198943Sluigi 190298943Sluigi if (!strncmp(av, "any", strlen(av))) 190398943Sluigi return; 190498943Sluigi 190598943Sluigi if (!strncmp(av, "me", strlen(av))) { 190698943Sluigi cmd->o.len |= F_INSN_SIZE(ipfw_insn); 190798943Sluigi return; 190898943Sluigi } 190998943Sluigi 1910117328Sluigi while (av) { 1911117328Sluigi /* 1912117328Sluigi * After the address we can have '/' or ':' indicating a mask, 1913117328Sluigi * ',' indicating another address follows, '{' indicating a 1914117328Sluigi * set of addresses of unspecified size. 1915117328Sluigi */ 1916117328Sluigi char *p = strpbrk(av, "/:,{"); 1917117328Sluigi int masklen; 1918117328Sluigi char md; 1919117328Sluigi 192098943Sluigi if (p) { 192198943Sluigi md = *p; 192298943Sluigi *p++ = '\0'; 1923117328Sluigi } else 1924117328Sluigi md = '\0'; 192598943Sluigi 1926117328Sluigi if (lookup_host(av, (struct in_addr *)&d[0]) != 0) 192798943Sluigi errx(EX_NOHOST, "hostname ``%s'' unknown", av); 192898943Sluigi switch (md) { 192998943Sluigi case ':': 1930117328Sluigi if (!inet_aton(p, (struct in_addr *)&d[1])) 193198943Sluigi errx(EX_DATAERR, "bad netmask ``%s''", p); 193298943Sluigi break; 193398943Sluigi case '/': 1934117328Sluigi masklen = atoi(p); 1935117328Sluigi if (masklen == 0) 1936117328Sluigi d[1] = htonl(0); /* mask */ 1937117328Sluigi else if (masklen > 32) 193898943Sluigi errx(EX_DATAERR, "bad width ``%s''", p); 193998943Sluigi else 1940117328Sluigi d[1] = htonl(~0 << (32 - masklen)); 194198943Sluigi break; 1942117328Sluigi case '{': /* no mask, assume /24 and put back the '{' */ 1943117328Sluigi d[1] = htonl(~0 << (32 - 24)); 1944117328Sluigi *(--p) = md; 1945117328Sluigi break; 1946117328Sluigi 1947117328Sluigi case ',': /* single address plus continuation */ 1948117328Sluigi *(--p) = md; 1949117328Sluigi /* FALLTHROUGH */ 1950117328Sluigi case 0: /* initialization value */ 195198943Sluigi default: 1952117328Sluigi d[1] = htonl(~0); /* force /32 */ 195398943Sluigi break; 195498943Sluigi } 1955117328Sluigi d[0] &= d[1]; /* mask base address with mask */ 1956117328Sluigi /* find next separator */ 195798943Sluigi if (p) 1958117328Sluigi p = strpbrk(p, ",{"); 1959117328Sluigi if (p && *p == '{') { 1960117328Sluigi /* 1961117328Sluigi * We have a set of addresses. They are stored as follows: 1962117328Sluigi * arg1 is the set size (powers of 2, 2..256) 1963117328Sluigi * addr is the base address IN HOST FORMAT 1964117328Sluigi * mask.. is an array of arg1 bits (rounded up to 1965117328Sluigi * the next multiple of 32) with bits set 1966117328Sluigi * for each host in the map. 1967117328Sluigi */ 1968117328Sluigi uint32_t *map = (uint32_t *)&cmd->mask; 196998943Sluigi int low, high; 1970117577Sluigi int i = contigmask((uint8_t *)&(d[1]), 32); 197198943Sluigi 1972117328Sluigi if (len > 0) 1973117328Sluigi errx(EX_DATAERR, "address set cannot be in a list"); 1974117328Sluigi if (i < 24 || i > 31) 1975117328Sluigi errx(EX_DATAERR, "invalid set with mask %d\n", i); 1976117328Sluigi cmd->o.arg1 = 1<<(32-i); /* map length */ 1977117328Sluigi d[0] = ntohl(d[0]); /* base addr in host format */ 197898943Sluigi cmd->o.opcode = O_IP_DST_SET; /* default */ 197998943Sluigi cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32) + (cmd->o.arg1+31)/32; 1980101117Sluigi for (i = 0; i < (cmd->o.arg1+31)/32 ; i++) 1981117328Sluigi map[i] = 0; /* clear map */ 198298943Sluigi 1983117328Sluigi av = p + 1; 1984117328Sluigi low = d[0] & 0xff; 198598943Sluigi high = low + cmd->o.arg1 - 1; 1986117328Sluigi /* 1987117328Sluigi * Here, i stores the previous value when we specify a range 1988117328Sluigi * of addresses within a mask, e.g. 45-63. i = -1 means we 1989117328Sluigi * have no previous value. 1990117328Sluigi */ 1991116716Sluigi i = -1; /* previous value in a range */ 199298943Sluigi while (isdigit(*av)) { 199398943Sluigi char *s; 1994117328Sluigi int a = strtol(av, &s, 0); 199598943Sluigi 1996117328Sluigi if (s == av) { /* no parameter */ 1997117328Sluigi if (*av != '}') 1998117328Sluigi errx(EX_DATAERR, "set not closed\n"); 1999117328Sluigi if (i != -1) 2000117328Sluigi errx(EX_DATAERR, "incomplete range %d-", i); 2001117328Sluigi break; 2002117328Sluigi } 2003117328Sluigi if (a < low || a > high) 2004117328Sluigi errx(EX_DATAERR, "addr %d out of range [%d-%d]\n", 200598943Sluigi a, low, high); 200698943Sluigi a -= low; 2007116716Sluigi if (i == -1) /* no previous in range */ 2008116716Sluigi i = a; 2009116716Sluigi else { /* check that range is valid */ 2010116716Sluigi if (i > a) 2011116716Sluigi errx(EX_DATAERR, "invalid range %d-%d", 2012116716Sluigi i+low, a+low); 2013116716Sluigi if (*s == '-') 2014116716Sluigi errx(EX_DATAERR, "double '-' in range"); 2015116716Sluigi } 2016116716Sluigi for (; i <= a; i++) 2017117328Sluigi map[i/32] |= 1<<(i & 31); 2018116716Sluigi i = -1; 2019116716Sluigi if (*s == '-') 2020116716Sluigi i = a; 2021117328Sluigi else if (*s == '}') 2022116716Sluigi break; 202398943Sluigi av = s+1; 202498943Sluigi } 202598943Sluigi return; 202698943Sluigi } 2027117328Sluigi av = p; 2028117328Sluigi if (av) /* then *av must be a ',' */ 2029117328Sluigi av++; 203098943Sluigi 2031117328Sluigi /* Check this entry */ 2032117328Sluigi if (d[1] == 0) { /* "any", specified as x.x.x.x/0 */ 2033117328Sluigi /* 2034117328Sluigi * 'any' turns the entire list into a NOP. 2035117328Sluigi * 'not any' never matches, so it is removed from the 2036117328Sluigi * list unless it is the only item, in which case we 2037117328Sluigi * report an error. 2038117328Sluigi */ 2039117328Sluigi if (cmd->o.len & F_NOT) { /* "not any" never matches */ 2040117328Sluigi if (av == NULL && len == 0) /* only this entry */ 2041117328Sluigi errx(EX_DATAERR, "not any never matches"); 2042117328Sluigi } 2043117328Sluigi /* else do nothing and skip this entry */ 2044117328Sluigi continue; 2045117328Sluigi } 2046117328Sluigi /* A single IP can be stored in an optimized format */ 2047117328Sluigi if (d[1] == IP_MASK_ALL && av == NULL && len == 0) { 204898943Sluigi cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32); 2049117328Sluigi return; 2050117328Sluigi } 2051117328Sluigi len += 2; /* two words... */ 2052117328Sluigi d += 2; 2053117328Sluigi } /* end while */ 2054117328Sluigi cmd->o.len |= len+1; 205598943Sluigi} 205698943Sluigi 205798943Sluigi 205898943Sluigi/* 205998943Sluigi * helper function to process a set of flags and set bits in the 206098943Sluigi * appropriate masks. 206198943Sluigi */ 206298943Sluigistatic void 206398943Sluigifill_flags(ipfw_insn *cmd, enum ipfw_opcodes opcode, 206498943Sluigi struct _s_x *flags, char *p) 206598943Sluigi{ 2066117328Sluigi uint8_t set=0, clear=0; 206798943Sluigi 206898943Sluigi while (p && *p) { 206998943Sluigi char *q; /* points to the separator */ 207098943Sluigi int val; 2071117328Sluigi uint8_t *which; /* mask we are working on */ 207298943Sluigi 207398943Sluigi if (*p == '!') { 207498943Sluigi p++; 207598943Sluigi which = &clear; 207698943Sluigi } else 207798943Sluigi which = &set; 207898943Sluigi q = strchr(p, ','); 207998943Sluigi if (q) 208098943Sluigi *q++ = '\0'; 208198943Sluigi val = match_token(flags, p); 208298943Sluigi if (val <= 0) 208398943Sluigi errx(EX_DATAERR, "invalid flag %s", p); 2084117328Sluigi *which |= (uint8_t)val; 208598943Sluigi p = q; 208698943Sluigi } 208798943Sluigi cmd->opcode = opcode; 208898943Sluigi cmd->len = (cmd->len & (F_NOT | F_OR)) | 1; 208998943Sluigi cmd->arg1 = (set & 0xff) | ( (clear & 0xff) << 8); 209098943Sluigi} 209198943Sluigi 209298943Sluigi 209398943Sluigistatic void 209498943Sluigidelete(int ac, char *av[]) 209598943Sluigi{ 2096117328Sluigi uint32_t rulenum; 2097117469Sluigi struct dn_pipe p; 209898943Sluigi int i; 209998943Sluigi int exitval = EX_OK; 2100101628Sluigi int do_set = 0; 210198943Sluigi 2102117469Sluigi memset(&p, 0, sizeof p); 210398943Sluigi 210498943Sluigi av++; ac--; 2105101641Sluigi if (ac > 0 && !strncmp(*av, "set", strlen(*av))) { 2106101978Sluigi do_set = 1; /* delete set */ 2107101628Sluigi ac--; av++; 2108101978Sluigi } 210998943Sluigi 211098943Sluigi /* Rule number */ 211198943Sluigi while (ac && isdigit(**av)) { 211298943Sluigi i = atoi(*av); av++; ac--; 211398943Sluigi if (do_pipe) { 211498943Sluigi if (do_pipe == 1) 2115117469Sluigi p.pipe_nr = i; 211698943Sluigi else 2117117469Sluigi p.fs.fs_nr = i; 2118117469Sluigi i = do_cmd(IP_DUMMYNET_DEL, &p, sizeof p); 211998943Sluigi if (i) { 212098943Sluigi exitval = 1; 212198943Sluigi warn("rule %u: setsockopt(IP_DUMMYNET_DEL)", 2122117469Sluigi do_pipe == 1 ? p.pipe_nr : p.fs.fs_nr); 212398943Sluigi } 212498943Sluigi } else { 2125101978Sluigi rulenum = (i & 0xffff) | (do_set << 24); 2126117328Sluigi i = do_cmd(IP_FW_DEL, &rulenum, sizeof rulenum); 212798943Sluigi if (i) { 212898943Sluigi exitval = EX_UNAVAILABLE; 212998943Sluigi warn("rule %u: setsockopt(IP_FW_DEL)", 213098943Sluigi rulenum); 213198943Sluigi } 213298943Sluigi } 213398943Sluigi } 213498943Sluigi if (exitval != EX_OK) 213598943Sluigi exit(exitval); 213698943Sluigi} 213798943Sluigi 213898943Sluigi 213998943Sluigi/* 214098943Sluigi * fill the interface structure. We do not check the name as we can 214198943Sluigi * create interfaces dynamically, so checking them at insert time 214298943Sluigi * makes relatively little sense. 2143121816Sbrooks * Interface names containing '*', '?', or '[' are assumed to be shell 2144121816Sbrooks * patterns which match interfaces. 214598943Sluigi */ 214698943Sluigistatic void 214798943Sluigifill_iface(ipfw_insn_if *cmd, char *arg) 214898943Sluigi{ 214998943Sluigi cmd->name[0] = '\0'; 215098943Sluigi cmd->o.len |= F_INSN_SIZE(ipfw_insn_if); 215198943Sluigi 215298943Sluigi /* Parse the interface or address */ 215398943Sluigi if (!strcmp(arg, "any")) 215498943Sluigi cmd->o.len = 0; /* effectively ignore this command */ 215598943Sluigi else if (!isdigit(*arg)) { 2156121816Sbrooks strlcpy(cmd->name, arg, sizeof(cmd->name)); 2157121816Sbrooks cmd->p.glob = strpbrk(arg, "*?[") != NULL ? 1 : 0; 215898943Sluigi } else if (!inet_aton(arg, &cmd->p.ip)) 215998943Sluigi errx(EX_DATAERR, "bad ip address ``%s''", arg); 216098943Sluigi} 216198943Sluigi 216298943Sluigi/* 216398943Sluigi * the following macro returns an error message if we run out of 216498943Sluigi * arguments. 216598943Sluigi */ 216698943Sluigi#define NEED1(msg) {if (!ac) errx(EX_USAGE, msg);} 216798943Sluigi 216898943Sluigistatic void 216998943Sluigiconfig_pipe(int ac, char **av) 217098943Sluigi{ 2171117469Sluigi struct dn_pipe p; 217298943Sluigi int i; 217398943Sluigi char *end; 2174117328Sluigi uint32_t a; 217598943Sluigi void *par = NULL; 217698943Sluigi 2177117469Sluigi memset(&p, 0, sizeof p); 217898943Sluigi 217998943Sluigi av++; ac--; 218098943Sluigi /* Pipe number */ 218198943Sluigi if (ac && isdigit(**av)) { 218298943Sluigi i = atoi(*av); av++; ac--; 218398943Sluigi if (do_pipe == 1) 2184117469Sluigi p.pipe_nr = i; 218598943Sluigi else 2186117469Sluigi p.fs.fs_nr = i; 218798943Sluigi } 218899475Sluigi while (ac > 0) { 218998943Sluigi double d; 219098943Sluigi int tok = match_token(dummynet_params, *av); 219198943Sluigi ac--; av++; 219298943Sluigi 219398943Sluigi switch(tok) { 2194101978Sluigi case TOK_NOERROR: 2195117469Sluigi p.fs.flags_fs |= DN_NOERROR; 2196101978Sluigi break; 2197101978Sluigi 219898943Sluigi case TOK_PLR: 219998943Sluigi NEED1("plr needs argument 0..1\n"); 220098943Sluigi d = strtod(av[0], NULL); 220198943Sluigi if (d > 1) 220298943Sluigi d = 1; 220398943Sluigi else if (d < 0) 220498943Sluigi d = 0; 2205117469Sluigi p.fs.plr = (int)(d*0x7fffffff); 220698943Sluigi ac--; av++; 220798943Sluigi break; 220898943Sluigi 220998943Sluigi case TOK_QUEUE: 221098943Sluigi NEED1("queue needs queue size\n"); 221198943Sluigi end = NULL; 2212117469Sluigi p.fs.qsize = strtoul(av[0], &end, 0); 221398943Sluigi if (*end == 'K' || *end == 'k') { 2214117469Sluigi p.fs.flags_fs |= DN_QSIZE_IS_BYTES; 2215117469Sluigi p.fs.qsize *= 1024; 221698943Sluigi } else if (*end == 'B' || !strncmp(end, "by", 2)) { 2217117469Sluigi p.fs.flags_fs |= DN_QSIZE_IS_BYTES; 221898943Sluigi } 221998943Sluigi ac--; av++; 222098943Sluigi break; 222198943Sluigi 222298943Sluigi case TOK_BUCKETS: 222398943Sluigi NEED1("buckets needs argument\n"); 2224117469Sluigi p.fs.rq_size = strtoul(av[0], NULL, 0); 222598943Sluigi ac--; av++; 222698943Sluigi break; 222798943Sluigi 222898943Sluigi case TOK_MASK: 222998943Sluigi NEED1("mask needs mask specifier\n"); 223098943Sluigi /* 223198943Sluigi * per-flow queue, mask is dst_ip, dst_port, 223298943Sluigi * src_ip, src_port, proto measured in bits 223398943Sluigi */ 223498943Sluigi par = NULL; 223598943Sluigi 2236117469Sluigi p.fs.flow_mask.dst_ip = 0; 2237117469Sluigi p.fs.flow_mask.src_ip = 0; 2238117469Sluigi p.fs.flow_mask.dst_port = 0; 2239117469Sluigi p.fs.flow_mask.src_port = 0; 2240117469Sluigi p.fs.flow_mask.proto = 0; 224198943Sluigi end = NULL; 224298943Sluigi 224398943Sluigi while (ac >= 1) { 2244117328Sluigi uint32_t *p32 = NULL; 2245117328Sluigi uint16_t *p16 = NULL; 224698943Sluigi 224798943Sluigi tok = match_token(dummynet_params, *av); 224898943Sluigi ac--; av++; 224998943Sluigi switch(tok) { 225098943Sluigi case TOK_ALL: 225198943Sluigi /* 225298943Sluigi * special case, all bits significant 225398943Sluigi */ 2254117469Sluigi p.fs.flow_mask.dst_ip = ~0; 2255117469Sluigi p.fs.flow_mask.src_ip = ~0; 2256117469Sluigi p.fs.flow_mask.dst_port = ~0; 2257117469Sluigi p.fs.flow_mask.src_port = ~0; 2258117469Sluigi p.fs.flow_mask.proto = ~0; 2259117469Sluigi p.fs.flags_fs |= DN_HAVE_FLOW_MASK; 226098943Sluigi goto end_mask; 226198943Sluigi 226298943Sluigi case TOK_DSTIP: 2263117469Sluigi p32 = &p.fs.flow_mask.dst_ip; 226498943Sluigi break; 226598943Sluigi 226698943Sluigi case TOK_SRCIP: 2267117469Sluigi p32 = &p.fs.flow_mask.src_ip; 226898943Sluigi break; 226998943Sluigi 227098943Sluigi case TOK_DSTPORT: 2271117469Sluigi p16 = &p.fs.flow_mask.dst_port; 227298943Sluigi break; 227398943Sluigi 227498943Sluigi case TOK_SRCPORT: 2275117469Sluigi p16 = &p.fs.flow_mask.src_port; 227698943Sluigi break; 227798943Sluigi 227898943Sluigi case TOK_PROTO: 227998943Sluigi break; 228098943Sluigi 228198943Sluigi default: 228298943Sluigi ac++; av--; /* backtrack */ 228398943Sluigi goto end_mask; 228498943Sluigi } 228598943Sluigi if (ac < 1) 228698943Sluigi errx(EX_USAGE, "mask: value missing"); 228798943Sluigi if (*av[0] == '/') { 228898943Sluigi a = strtoul(av[0]+1, &end, 0); 228998943Sluigi a = (a == 32) ? ~0 : (1 << a) - 1; 2290106505Smaxim } else 229199909Sluigi a = strtoul(av[0], &end, 0); 229298943Sluigi if (p32 != NULL) 229398943Sluigi *p32 = a; 229498943Sluigi else if (p16 != NULL) { 229598943Sluigi if (a > 65535) 229698943Sluigi errx(EX_DATAERR, 229798943Sluigi "mask: must be 16 bit"); 2298117328Sluigi *p16 = (uint16_t)a; 229998943Sluigi } else { 230098943Sluigi if (a > 255) 230198943Sluigi errx(EX_DATAERR, 230298943Sluigi "mask: must be 8 bit"); 2303117469Sluigi p.fs.flow_mask.proto = (uint8_t)a; 230498943Sluigi } 230598943Sluigi if (a != 0) 2306117469Sluigi p.fs.flags_fs |= DN_HAVE_FLOW_MASK; 230798943Sluigi ac--; av++; 230898943Sluigi } /* end while, config masks */ 230998943Sluigiend_mask: 231098943Sluigi break; 231198943Sluigi 231298943Sluigi case TOK_RED: 231398943Sluigi case TOK_GRED: 231498943Sluigi NEED1("red/gred needs w_q/min_th/max_th/max_p\n"); 2315117469Sluigi p.fs.flags_fs |= DN_IS_RED; 231698943Sluigi if (tok == TOK_GRED) 2317117469Sluigi p.fs.flags_fs |= DN_IS_GENTLE_RED; 231898943Sluigi /* 231998943Sluigi * the format for parameters is w_q/min_th/max_th/max_p 232098943Sluigi */ 232198943Sluigi if ((end = strsep(&av[0], "/"))) { 232298943Sluigi double w_q = strtod(end, NULL); 232398943Sluigi if (w_q > 1 || w_q <= 0) 232498943Sluigi errx(EX_DATAERR, "0 < w_q <= 1"); 2325117469Sluigi p.fs.w_q = (int) (w_q * (1 << SCALE_RED)); 232698943Sluigi } 232798943Sluigi if ((end = strsep(&av[0], "/"))) { 2328117469Sluigi p.fs.min_th = strtoul(end, &end, 0); 232998943Sluigi if (*end == 'K' || *end == 'k') 2330117469Sluigi p.fs.min_th *= 1024; 233198943Sluigi } 233298943Sluigi if ((end = strsep(&av[0], "/"))) { 2333117469Sluigi p.fs.max_th = strtoul(end, &end, 0); 233498943Sluigi if (*end == 'K' || *end == 'k') 2335117469Sluigi p.fs.max_th *= 1024; 233698943Sluigi } 233798943Sluigi if ((end = strsep(&av[0], "/"))) { 233898943Sluigi double max_p = strtod(end, NULL); 233998943Sluigi if (max_p > 1 || max_p <= 0) 234098943Sluigi errx(EX_DATAERR, "0 < max_p <= 1"); 2341117469Sluigi p.fs.max_p = (int)(max_p * (1 << SCALE_RED)); 234298943Sluigi } 234398943Sluigi ac--; av++; 234498943Sluigi break; 234598943Sluigi 234698943Sluigi case TOK_DROPTAIL: 2347117469Sluigi p.fs.flags_fs &= ~(DN_IS_RED|DN_IS_GENTLE_RED); 234898943Sluigi break; 2349106505Smaxim 235098943Sluigi case TOK_BW: 235198943Sluigi NEED1("bw needs bandwidth or interface\n"); 235298943Sluigi if (do_pipe != 1) 235398943Sluigi errx(EX_DATAERR, "bandwidth only valid for pipes"); 235498943Sluigi /* 235598943Sluigi * set clocking interface or bandwidth value 235698943Sluigi */ 235798943Sluigi if (av[0][0] >= 'a' && av[0][0] <= 'z') { 2358117469Sluigi int l = sizeof(p.if_name)-1; 235998943Sluigi /* interface name */ 2360117469Sluigi strncpy(p.if_name, av[0], l); 2361117469Sluigi p.if_name[l] = '\0'; 2362117469Sluigi p.bandwidth = 0; 236398943Sluigi } else { 2364117469Sluigi p.if_name[0] = '\0'; 2365117469Sluigi p.bandwidth = strtoul(av[0], &end, 0); 236698943Sluigi if (*end == 'K' || *end == 'k') { 236798943Sluigi end++; 2368117469Sluigi p.bandwidth *= 1000; 236998943Sluigi } else if (*end == 'M') { 237098943Sluigi end++; 2371117469Sluigi p.bandwidth *= 1000000; 237298943Sluigi } 237398943Sluigi if (*end == 'B' || !strncmp(end, "by", 2)) 2374117469Sluigi p.bandwidth *= 8; 2375117469Sluigi if (p.bandwidth < 0) 237698943Sluigi errx(EX_DATAERR, "bandwidth too large"); 237798943Sluigi } 237898943Sluigi ac--; av++; 237998943Sluigi break; 238098943Sluigi 238198943Sluigi case TOK_DELAY: 238298943Sluigi if (do_pipe != 1) 238398943Sluigi errx(EX_DATAERR, "delay only valid for pipes"); 238498943Sluigi NEED1("delay needs argument 0..10000ms\n"); 2385117469Sluigi p.delay = strtoul(av[0], NULL, 0); 238698943Sluigi ac--; av++; 238798943Sluigi break; 238898943Sluigi 238998943Sluigi case TOK_WEIGHT: 239098943Sluigi if (do_pipe == 1) 239198943Sluigi errx(EX_DATAERR,"weight only valid for queues"); 239298943Sluigi NEED1("weight needs argument 0..100\n"); 2393117469Sluigi p.fs.weight = strtoul(av[0], &end, 0); 239498943Sluigi ac--; av++; 239598943Sluigi break; 239698943Sluigi 239798943Sluigi case TOK_PIPE: 239898943Sluigi if (do_pipe == 1) 239998943Sluigi errx(EX_DATAERR,"pipe only valid for queues"); 240098943Sluigi NEED1("pipe needs pipe_number\n"); 2401117469Sluigi p.fs.parent_nr = strtoul(av[0], &end, 0); 240298943Sluigi ac--; av++; 240398943Sluigi break; 240498943Sluigi 240598943Sluigi default: 240698943Sluigi errx(EX_DATAERR, "unrecognised option ``%s''", *av); 240798943Sluigi } 240898943Sluigi } 240998943Sluigi if (do_pipe == 1) { 2410117469Sluigi if (p.pipe_nr == 0) 241198943Sluigi errx(EX_DATAERR, "pipe_nr must be > 0"); 2412117469Sluigi if (p.delay > 10000) 241398943Sluigi errx(EX_DATAERR, "delay must be < 10000"); 241498943Sluigi } else { /* do_pipe == 2, queue */ 2415117469Sluigi if (p.fs.parent_nr == 0) 241698943Sluigi errx(EX_DATAERR, "pipe must be > 0"); 2417117469Sluigi if (p.fs.weight >100) 241898943Sluigi errx(EX_DATAERR, "weight must be <= 100"); 241998943Sluigi } 2420117469Sluigi if (p.fs.flags_fs & DN_QSIZE_IS_BYTES) { 2421117469Sluigi if (p.fs.qsize > 1024*1024) 242298943Sluigi errx(EX_DATAERR, "queue size must be < 1MB"); 242398943Sluigi } else { 2424117469Sluigi if (p.fs.qsize > 100) 242598943Sluigi errx(EX_DATAERR, "2 <= queue size <= 100"); 242698943Sluigi } 2427117469Sluigi if (p.fs.flags_fs & DN_IS_RED) { 242898943Sluigi size_t len; 242998943Sluigi int lookup_depth, avg_pkt_size; 243098943Sluigi double s, idle, weight, w_q; 2431117469Sluigi struct clockinfo ck; 243298943Sluigi int t; 243398943Sluigi 2434117469Sluigi if (p.fs.min_th >= p.fs.max_th) 243598943Sluigi errx(EX_DATAERR, "min_th %d must be < than max_th %d", 2436117469Sluigi p.fs.min_th, p.fs.max_th); 2437117469Sluigi if (p.fs.max_th == 0) 243898943Sluigi errx(EX_DATAERR, "max_th must be > 0"); 243998943Sluigi 244098943Sluigi len = sizeof(int); 244198943Sluigi if (sysctlbyname("net.inet.ip.dummynet.red_lookup_depth", 244298943Sluigi &lookup_depth, &len, NULL, 0) == -1) 244398943Sluigi 244498943Sluigi errx(1, "sysctlbyname(\"%s\")", 244598943Sluigi "net.inet.ip.dummynet.red_lookup_depth"); 244698943Sluigi if (lookup_depth == 0) 244798943Sluigi errx(EX_DATAERR, "net.inet.ip.dummynet.red_lookup_depth" 244898943Sluigi " must be greater than zero"); 244998943Sluigi 245098943Sluigi len = sizeof(int); 245198943Sluigi if (sysctlbyname("net.inet.ip.dummynet.red_avg_pkt_size", 245298943Sluigi &avg_pkt_size, &len, NULL, 0) == -1) 245398943Sluigi 245498943Sluigi errx(1, "sysctlbyname(\"%s\")", 245598943Sluigi "net.inet.ip.dummynet.red_avg_pkt_size"); 245698943Sluigi if (avg_pkt_size == 0) 245798943Sluigi errx(EX_DATAERR, 245898943Sluigi "net.inet.ip.dummynet.red_avg_pkt_size must" 245998943Sluigi " be greater than zero"); 246098943Sluigi 246198943Sluigi len = sizeof(struct clockinfo); 2462117469Sluigi if (sysctlbyname("kern.clockrate", &ck, &len, NULL, 0) == -1) 246398943Sluigi errx(1, "sysctlbyname(\"%s\")", "kern.clockrate"); 246498943Sluigi 246598943Sluigi /* 246698943Sluigi * Ticks needed for sending a medium-sized packet. 246798943Sluigi * Unfortunately, when we are configuring a WF2Q+ queue, we 246898943Sluigi * do not have bandwidth information, because that is stored 246998943Sluigi * in the parent pipe, and also we have multiple queues 247098943Sluigi * competing for it. So we set s=0, which is not very 247198943Sluigi * correct. But on the other hand, why do we want RED with 247298943Sluigi * WF2Q+ ? 247398943Sluigi */ 2474117469Sluigi if (p.bandwidth==0) /* this is a WF2Q+ queue */ 247598943Sluigi s = 0; 247698943Sluigi else 2477117469Sluigi s = ck.hz * avg_pkt_size * 8 / p.bandwidth; 247898943Sluigi 247998943Sluigi /* 248098943Sluigi * max idle time (in ticks) before avg queue size becomes 0. 248198943Sluigi * NOTA: (3/w_q) is approx the value x so that 248298943Sluigi * (1-w_q)^x < 10^-3. 248398943Sluigi */ 2484117469Sluigi w_q = ((double)p.fs.w_q) / (1 << SCALE_RED); 248598943Sluigi idle = s * 3. / w_q; 2486117469Sluigi p.fs.lookup_step = (int)idle / lookup_depth; 2487117469Sluigi if (!p.fs.lookup_step) 2488117469Sluigi p.fs.lookup_step = 1; 248998943Sluigi weight = 1 - w_q; 2490117469Sluigi for (t = p.fs.lookup_step; t > 0; --t) 249198943Sluigi weight *= weight; 2492117469Sluigi p.fs.lookup_weight = (int)(weight * (1 << SCALE_RED)); 249398943Sluigi } 2494117469Sluigi i = do_cmd(IP_DUMMYNET_CONFIGURE, &p, sizeof p); 249598943Sluigi if (i) 249698943Sluigi err(1, "setsockopt(%s)", "IP_DUMMYNET_CONFIGURE"); 249798943Sluigi} 249898943Sluigi 249998943Sluigistatic void 2500117577Sluigiget_mac_addr_mask(char *p, uint8_t *addr, uint8_t *mask) 250198943Sluigi{ 250298943Sluigi int i, l; 250398943Sluigi 250498943Sluigi for (i=0; i<6; i++) 250598943Sluigi addr[i] = mask[i] = 0; 250698943Sluigi if (!strcmp(p, "any")) 250798943Sluigi return; 250898943Sluigi 250998943Sluigi for (i=0; *p && i<6;i++, p++) { 251098943Sluigi addr[i] = strtol(p, &p, 16); 251198943Sluigi if (*p != ':') /* we start with the mask */ 251298943Sluigi break; 251398943Sluigi } 251498943Sluigi if (*p == '/') { /* mask len */ 251598943Sluigi l = strtol(p+1, &p, 0); 251698943Sluigi for (i=0; l>0; l -=8, i++) 251798943Sluigi mask[i] = (l >=8) ? 0xff : (~0) << (8-l); 251898943Sluigi } else if (*p == '&') { /* mask */ 251998943Sluigi for (i=0, p++; *p && i<6;i++, p++) { 252098943Sluigi mask[i] = strtol(p, &p, 16); 252198943Sluigi if (*p != ':') 252298943Sluigi break; 252398943Sluigi } 252498943Sluigi } else if (*p == '\0') { 252598943Sluigi for (i=0; i<6; i++) 252698943Sluigi mask[i] = 0xff; 252798943Sluigi } 252898943Sluigi for (i=0; i<6; i++) 252998943Sluigi addr[i] &= mask[i]; 253098943Sluigi} 253198943Sluigi 253298943Sluigi/* 253398943Sluigi * helper function, updates the pointer to cmd with the length 253498943Sluigi * of the current command, and also cleans up the first word of 253598943Sluigi * the new command in case it has been clobbered before. 253698943Sluigi */ 253798943Sluigistatic ipfw_insn * 253898943Sluiginext_cmd(ipfw_insn *cmd) 253998943Sluigi{ 254098943Sluigi cmd += F_LEN(cmd); 254198943Sluigi bzero(cmd, sizeof(*cmd)); 254298943Sluigi return cmd; 254398943Sluigi} 254498943Sluigi 254598943Sluigi/* 2546117469Sluigi * Takes arguments and copies them into a comment 2547117469Sluigi */ 2548117469Sluigistatic void 2549117469Sluigifill_comment(ipfw_insn *cmd, int ac, char **av) 2550117469Sluigi{ 2551117469Sluigi int i, l; 2552117469Sluigi char *p = (char *)(cmd + 1); 2553117577Sluigi 2554117469Sluigi cmd->opcode = O_NOP; 2555117469Sluigi cmd->len = (cmd->len & (F_NOT | F_OR)); 2556117469Sluigi 2557117469Sluigi /* Compute length of comment string. */ 2558117469Sluigi for (i = 0, l = 0; i < ac; i++) 2559117469Sluigi l += strlen(av[i]) + 1; 2560117469Sluigi if (l == 0) 2561117469Sluigi return; 2562117469Sluigi if (l > 84) 2563117469Sluigi errx(EX_DATAERR, 2564117469Sluigi "comment too long (max 80 chars)"); 2565117469Sluigi l = 1 + (l+3)/4; 2566117469Sluigi cmd->len = (cmd->len & (F_NOT | F_OR)) | l; 2567117469Sluigi for (i = 0; i < ac; i++) { 2568117469Sluigi strcpy(p, av[i]); 2569117469Sluigi p += strlen(av[i]); 2570117469Sluigi *p++ = ' '; 2571117469Sluigi } 2572117469Sluigi *(--p) = '\0'; 2573117469Sluigi} 2574117577Sluigi 2575117469Sluigi/* 257698943Sluigi * A function to fill simple commands of size 1. 257798943Sluigi * Existing flags are preserved. 257898943Sluigi */ 257998943Sluigistatic void 2580117328Sluigifill_cmd(ipfw_insn *cmd, enum ipfw_opcodes opcode, int flags, uint16_t arg) 258198943Sluigi{ 258298943Sluigi cmd->opcode = opcode; 258398943Sluigi cmd->len = ((cmd->len | flags) & (F_NOT | F_OR)) | 1; 258498943Sluigi cmd->arg1 = arg; 258598943Sluigi} 258698943Sluigi 258798943Sluigi/* 258898943Sluigi * Fetch and add the MAC address and type, with masks. This generates one or 258998943Sluigi * two microinstructions, and returns the pointer to the last one. 259098943Sluigi */ 259198943Sluigistatic ipfw_insn * 259298943Sluigiadd_mac(ipfw_insn *cmd, int ac, char *av[]) 259398943Sluigi{ 2594102087Sluigi ipfw_insn_mac *mac; 259598943Sluigi 2596102087Sluigi if (ac < 2) 2597102098Sluigi errx(EX_DATAERR, "MAC dst src"); 259898943Sluigi 259998943Sluigi cmd->opcode = O_MACADDR2; 260098943Sluigi cmd->len = (cmd->len & (F_NOT | F_OR)) | F_INSN_SIZE(ipfw_insn_mac); 260198943Sluigi 260298943Sluigi mac = (ipfw_insn_mac *)cmd; 2603101978Sluigi get_mac_addr_mask(av[0], mac->addr, mac->mask); /* dst */ 260498943Sluigi get_mac_addr_mask(av[1], &(mac->addr[6]), &(mac->mask[6])); /* src */ 2605102087Sluigi return cmd; 2606102087Sluigi} 260798943Sluigi 2608102087Sluigistatic ipfw_insn * 2609102087Sluigiadd_mactype(ipfw_insn *cmd, int ac, char *av) 2610102087Sluigi{ 2611102087Sluigi if (ac < 1) 2612102087Sluigi errx(EX_DATAERR, "missing MAC type"); 2613102087Sluigi if (strcmp(av, "any") != 0) { /* we have a non-null type */ 2614102087Sluigi fill_newports((ipfw_insn_u16 *)cmd, av, IPPROTO_ETHERTYPE); 261598943Sluigi cmd->opcode = O_MAC_TYPE; 2616102087Sluigi return cmd; 2617102087Sluigi } else 2618102087Sluigi return NULL; 2619102087Sluigi} 262098943Sluigi 2621102087Sluigistatic ipfw_insn * 2622102087Sluigiadd_proto(ipfw_insn *cmd, char *av) 2623102087Sluigi{ 2624102087Sluigi struct protoent *pe; 2625102087Sluigi u_char proto = 0; 2626102087Sluigi 2627102087Sluigi if (!strncmp(av, "all", strlen(av))) 2628102087Sluigi ; /* same as "ip" */ 2629102087Sluigi else if ((proto = atoi(av)) > 0) 2630102087Sluigi ; /* all done! */ 2631102087Sluigi else if ((pe = getprotobyname(av)) != NULL) 2632102087Sluigi proto = pe->p_proto; 2633102087Sluigi else 2634102098Sluigi return NULL; 2635102087Sluigi if (proto != IPPROTO_IP) 2636102087Sluigi fill_cmd(cmd, O_PROTO, 0, proto); 263798943Sluigi return cmd; 263898943Sluigi} 263998943Sluigi 2640102087Sluigistatic ipfw_insn * 2641102087Sluigiadd_srcip(ipfw_insn *cmd, char *av) 2642102087Sluigi{ 2643102087Sluigi fill_ip((ipfw_insn_ip *)cmd, av); 2644102087Sluigi if (cmd->opcode == O_IP_DST_SET) /* set */ 2645102087Sluigi cmd->opcode = O_IP_SRC_SET; 2646102087Sluigi else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) /* me */ 2647102087Sluigi cmd->opcode = O_IP_SRC_ME; 2648102087Sluigi else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn_u32)) /* one IP */ 2649102087Sluigi cmd->opcode = O_IP_SRC; 2650117328Sluigi else /* addr/mask */ 2651102087Sluigi cmd->opcode = O_IP_SRC_MASK; 2652102087Sluigi return cmd; 2653102087Sluigi} 2654102087Sluigi 2655102087Sluigistatic ipfw_insn * 2656102087Sluigiadd_dstip(ipfw_insn *cmd, char *av) 2657102087Sluigi{ 2658102087Sluigi fill_ip((ipfw_insn_ip *)cmd, av); 2659102087Sluigi if (cmd->opcode == O_IP_DST_SET) /* set */ 2660102087Sluigi ; 2661102087Sluigi else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) /* me */ 2662102087Sluigi cmd->opcode = O_IP_DST_ME; 2663102087Sluigi else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn_u32)) /* one IP */ 2664102087Sluigi cmd->opcode = O_IP_DST; 2665117328Sluigi else /* addr/mask */ 2666102087Sluigi cmd->opcode = O_IP_DST_MASK; 2667102087Sluigi return cmd; 2668102087Sluigi} 2669102087Sluigi 2670102087Sluigistatic ipfw_insn * 2671102087Sluigiadd_ports(ipfw_insn *cmd, char *av, u_char proto, int opcode) 2672102087Sluigi{ 2673102087Sluigi if (!strncmp(av, "any", strlen(av))) { 2674102087Sluigi return NULL; 2675102087Sluigi } else if (fill_newports((ipfw_insn_u16 *)cmd, av, proto)) { 2676102087Sluigi /* XXX todo: check that we have a protocol with ports */ 2677102087Sluigi cmd->opcode = opcode; 2678102087Sluigi return cmd; 2679102087Sluigi } 2680102087Sluigi return NULL; 2681102087Sluigi} 2682102087Sluigi 268398943Sluigi/* 268498943Sluigi * Parse arguments and assemble the microinstructions which make up a rule. 268598943Sluigi * Rules are added into the 'rulebuf' and then copied in the correct order 268698943Sluigi * into the actual rule. 268798943Sluigi * 268898943Sluigi * The syntax for a rule starts with the action, followed by an 268998943Sluigi * optional log action, and the various match patterns. 2690108533Sschweikh * In the assembled microcode, the first opcode must be an O_PROBE_STATE 269198943Sluigi * (generated if the rule includes a keep-state option), then the 269298943Sluigi * various match patterns, the "log" action, and the actual action. 2693106505Smaxim * 269498943Sluigi */ 269598943Sluigistatic void 269698943Sluigiadd(int ac, char *av[]) 269798943Sluigi{ 269898943Sluigi /* 269998943Sluigi * rules are added into the 'rulebuf' and then copied in 270098943Sluigi * the correct order into the actual rule. 270198943Sluigi * Some things that need to go out of order (prob, action etc.) 270298943Sluigi * go into actbuf[]. 270398943Sluigi */ 2704117328Sluigi static uint32_t rulebuf[255], actbuf[255], cmdbuf[255]; 270598943Sluigi 2706117469Sluigi ipfw_insn *src, *dst, *cmd, *action, *prev=NULL; 2707102087Sluigi ipfw_insn *first_cmd; /* first match pattern */ 270898943Sluigi 270998943Sluigi struct ip_fw *rule; 271098943Sluigi 271198943Sluigi /* 271298943Sluigi * various flags used to record that we entered some fields. 271398943Sluigi */ 2714101116Sluigi ipfw_insn *have_state = NULL; /* check-state or keep-state */ 271598943Sluigi 271698943Sluigi int i; 271798943Sluigi 271898943Sluigi int open_par = 0; /* open parenthesis ( */ 271998943Sluigi 272098943Sluigi /* proto is here because it is used to fetch ports */ 272198943Sluigi u_char proto = IPPROTO_IP; /* default protocol */ 272298943Sluigi 2723107289Sluigi double match_prob = 1; /* match probability, default is always match */ 2724107289Sluigi 272598943Sluigi bzero(actbuf, sizeof(actbuf)); /* actions go here */ 272698943Sluigi bzero(cmdbuf, sizeof(cmdbuf)); 272798943Sluigi bzero(rulebuf, sizeof(rulebuf)); 272898943Sluigi 272998943Sluigi rule = (struct ip_fw *)rulebuf; 273098943Sluigi cmd = (ipfw_insn *)cmdbuf; 273198943Sluigi action = (ipfw_insn *)actbuf; 273298943Sluigi 273398943Sluigi av++; ac--; 273498943Sluigi 273598943Sluigi /* [rule N] -- Rule number optional */ 273698943Sluigi if (ac && isdigit(**av)) { 273798943Sluigi rule->rulenum = atoi(*av); 273898943Sluigi av++; 273998943Sluigi ac--; 274098943Sluigi } 274198943Sluigi 2742117655Sluigi /* [set N] -- set number (0..RESVD_SET), optional */ 2743101628Sluigi if (ac > 1 && !strncmp(*av, "set", strlen(*av))) { 2744101628Sluigi int set = strtoul(av[1], NULL, 10); 2745117655Sluigi if (set < 0 || set > RESVD_SET) 2746101628Sluigi errx(EX_DATAERR, "illegal set %s", av[1]); 2747101628Sluigi rule->set = set; 2748101628Sluigi av += 2; ac -= 2; 2749101628Sluigi } 2750101628Sluigi 275198943Sluigi /* [prob D] -- match probability, optional */ 275298943Sluigi if (ac > 1 && !strncmp(*av, "prob", strlen(*av))) { 2753107289Sluigi match_prob = strtod(av[1], NULL); 275498943Sluigi 2755107289Sluigi if (match_prob <= 0 || match_prob > 1) 275698943Sluigi errx(EX_DATAERR, "illegal match prob. %s", av[1]); 275798943Sluigi av += 2; ac -= 2; 275898943Sluigi } 275998943Sluigi 276098943Sluigi /* action -- mandatory */ 276198943Sluigi NEED1("missing action"); 276298943Sluigi i = match_token(rule_actions, *av); 276398943Sluigi ac--; av++; 276498943Sluigi action->len = 1; /* default */ 276598943Sluigi switch(i) { 276698943Sluigi case TOK_CHECKSTATE: 2767101116Sluigi have_state = action; 276898943Sluigi action->opcode = O_CHECK_STATE; 276998943Sluigi break; 277098943Sluigi 277198943Sluigi case TOK_ACCEPT: 277298943Sluigi action->opcode = O_ACCEPT; 277398943Sluigi break; 277498943Sluigi 277598943Sluigi case TOK_DENY: 277698943Sluigi action->opcode = O_DENY; 277799475Sluigi action->arg1 = 0; 277898943Sluigi break; 277998943Sluigi 278099475Sluigi case TOK_REJECT: 278199475Sluigi action->opcode = O_REJECT; 278299475Sluigi action->arg1 = ICMP_UNREACH_HOST; 278399475Sluigi break; 278499475Sluigi 278599475Sluigi case TOK_RESET: 278699475Sluigi action->opcode = O_REJECT; 278799475Sluigi action->arg1 = ICMP_REJECT_RST; 278899475Sluigi break; 278999475Sluigi 279099475Sluigi case TOK_UNREACH: 279199475Sluigi action->opcode = O_REJECT; 279299475Sluigi NEED1("missing reject code"); 279399475Sluigi fill_reject_code(&action->arg1, *av); 279499475Sluigi ac--; av++; 279599475Sluigi break; 279699475Sluigi 279798943Sluigi case TOK_COUNT: 279898943Sluigi action->opcode = O_COUNT; 279998943Sluigi break; 280098943Sluigi 280198943Sluigi case TOK_QUEUE: 280298943Sluigi case TOK_PIPE: 280398943Sluigi action->len = F_INSN_SIZE(ipfw_insn_pipe); 280498943Sluigi case TOK_SKIPTO: 280598943Sluigi if (i == TOK_QUEUE) 280698943Sluigi action->opcode = O_QUEUE; 280798943Sluigi else if (i == TOK_PIPE) 280898943Sluigi action->opcode = O_PIPE; 280998943Sluigi else if (i == TOK_SKIPTO) 281098943Sluigi action->opcode = O_SKIPTO; 281198943Sluigi NEED1("missing skipto/pipe/queue number"); 281298943Sluigi action->arg1 = strtoul(*av, NULL, 10); 281398943Sluigi av++; ac--; 281498943Sluigi break; 281598943Sluigi 281698943Sluigi case TOK_DIVERT: 281798943Sluigi case TOK_TEE: 281898943Sluigi action->opcode = (i == TOK_DIVERT) ? O_DIVERT : O_TEE; 281998943Sluigi NEED1("missing divert/tee port"); 282098943Sluigi action->arg1 = strtoul(*av, NULL, 0); 282198943Sluigi if (action->arg1 == 0) { 282298943Sluigi struct servent *s; 282398943Sluigi setservent(1); 282498943Sluigi s = getservbyname(av[0], "divert"); 282598943Sluigi if (s != NULL) 282698943Sluigi action->arg1 = ntohs(s->s_port); 282798943Sluigi else 282898943Sluigi errx(EX_DATAERR, "illegal divert/tee port"); 282998943Sluigi } 283098943Sluigi ac--; av++; 283198943Sluigi break; 283298943Sluigi 283398943Sluigi case TOK_FORWARD: { 283498943Sluigi ipfw_insn_sa *p = (ipfw_insn_sa *)action; 283598943Sluigi char *s, *end; 283698943Sluigi 283798943Sluigi NEED1("missing forward address[:port]"); 283898943Sluigi 283998943Sluigi action->opcode = O_FORWARD_IP; 284098943Sluigi action->len = F_INSN_SIZE(ipfw_insn_sa); 284198943Sluigi 284298943Sluigi p->sa.sin_len = sizeof(struct sockaddr_in); 284398943Sluigi p->sa.sin_family = AF_INET; 284498943Sluigi p->sa.sin_port = 0; 284598943Sluigi /* 284698943Sluigi * locate the address-port separator (':' or ',') 284798943Sluigi */ 284898943Sluigi s = strchr(*av, ':'); 284998943Sluigi if (s == NULL) 285098943Sluigi s = strchr(*av, ','); 285198943Sluigi if (s != NULL) { 285298943Sluigi *(s++) = '\0'; 285398943Sluigi i = strtoport(s, &end, 0 /* base */, 0 /* proto */); 285498943Sluigi if (s == end) 285598943Sluigi errx(EX_DATAERR, 285698943Sluigi "illegal forwarding port ``%s''", s); 2857103241Sluigi p->sa.sin_port = (u_short)i; 285898943Sluigi } 285998943Sluigi lookup_host(*av, &(p->sa.sin_addr)); 286098943Sluigi } 286198943Sluigi ac--; av++; 286298943Sluigi break; 286398943Sluigi 2864117469Sluigi case TOK_COMMENT: 2865117469Sluigi /* pretend it is a 'count' rule followed by the comment */ 2866117469Sluigi action->opcode = O_COUNT; 2867117469Sluigi ac++; av--; /* go back... */ 2868117469Sluigi break; 2869117469Sluigi 287098943Sluigi default: 2871102087Sluigi errx(EX_DATAERR, "invalid action %s\n", av[-1]); 287298943Sluigi } 287398943Sluigi action = next_cmd(action); 287498943Sluigi 287598943Sluigi /* 287698943Sluigi * [log [logamount N]] -- log, optional 287798943Sluigi * 287898943Sluigi * If exists, it goes first in the cmdbuf, but then it is 287998943Sluigi * skipped in the copy section to the end of the buffer. 288098943Sluigi */ 288198943Sluigi if (ac && !strncmp(*av, "log", strlen(*av))) { 288298943Sluigi ipfw_insn_log *c = (ipfw_insn_log *)cmd; 2883117469Sluigi int l; 288498943Sluigi 288598943Sluigi cmd->len = F_INSN_SIZE(ipfw_insn_log); 288698943Sluigi cmd->opcode = O_LOG; 288798943Sluigi av++; ac--; 288898943Sluigi if (ac && !strncmp(*av, "logamount", strlen(*av))) { 288998943Sluigi ac--; av++; 289098943Sluigi NEED1("logamount requires argument"); 2891117469Sluigi l = atoi(*av); 2892117469Sluigi if (l < 0) 289398943Sluigi errx(EX_DATAERR, "logamount must be positive"); 2894117469Sluigi c->max_log = l; 289598943Sluigi ac--; av++; 289698943Sluigi } 289798943Sluigi cmd = next_cmd(cmd); 289898943Sluigi } 289998943Sluigi 2900101116Sluigi if (have_state) /* must be a check-state, we are done */ 290198943Sluigi goto done; 290298943Sluigi 290398943Sluigi#define OR_START(target) \ 290498943Sluigi if (ac && (*av[0] == '(' || *av[0] == '{')) { \ 290598943Sluigi if (open_par) \ 290698943Sluigi errx(EX_USAGE, "nested \"(\" not allowed\n"); \ 2907101641Sluigi prev = NULL; \ 290898943Sluigi open_par = 1; \ 290998943Sluigi if ( (av[0])[1] == '\0') { \ 291098943Sluigi ac--; av++; \ 291198943Sluigi } else \ 291298943Sluigi (*av)++; \ 291398943Sluigi } \ 291498943Sluigi target: \ 291598943Sluigi 291698943Sluigi 291798943Sluigi#define CLOSE_PAR \ 291898943Sluigi if (open_par) { \ 291998943Sluigi if (ac && ( \ 292098943Sluigi !strncmp(*av, ")", strlen(*av)) || \ 292198943Sluigi !strncmp(*av, "}", strlen(*av)) )) { \ 2922101641Sluigi prev = NULL; \ 292398943Sluigi open_par = 0; \ 292498943Sluigi ac--; av++; \ 292598943Sluigi } else \ 292698943Sluigi errx(EX_USAGE, "missing \")\"\n"); \ 292798943Sluigi } 2928106505Smaxim 292998943Sluigi#define NOT_BLOCK \ 293098943Sluigi if (ac && !strncmp(*av, "not", strlen(*av))) { \ 293198943Sluigi if (cmd->len & F_NOT) \ 293298943Sluigi errx(EX_USAGE, "double \"not\" not allowed\n"); \ 293398943Sluigi cmd->len |= F_NOT; \ 293498943Sluigi ac--; av++; \ 293598943Sluigi } 293698943Sluigi 293798943Sluigi#define OR_BLOCK(target) \ 293898943Sluigi if (ac && !strncmp(*av, "or", strlen(*av))) { \ 293998943Sluigi if (prev == NULL || open_par == 0) \ 294098943Sluigi errx(EX_DATAERR, "invalid OR block"); \ 294198943Sluigi prev->len |= F_OR; \ 294298943Sluigi ac--; av++; \ 294398943Sluigi goto target; \ 294498943Sluigi } \ 294598943Sluigi CLOSE_PAR; 294698943Sluigi 2947102087Sluigi first_cmd = cmd; 2948102098Sluigi 2949102098Sluigi#if 0 295098943Sluigi /* 2951102087Sluigi * MAC addresses, optional. 2952102087Sluigi * If we have this, we skip the part "proto from src to dst" 2953102087Sluigi * and jump straight to the option parsing. 2954102087Sluigi */ 2955102087Sluigi NOT_BLOCK; 2956102087Sluigi NEED1("missing protocol"); 2957102087Sluigi if (!strncmp(*av, "MAC", strlen(*av)) || 2958102087Sluigi !strncmp(*av, "mac", strlen(*av))) { 2959102087Sluigi ac--; av++; /* the "MAC" keyword */ 2960102087Sluigi add_mac(cmd, ac, av); /* exits in case of errors */ 2961102087Sluigi cmd = next_cmd(cmd); 2962102087Sluigi ac -= 2; av += 2; /* dst-mac and src-mac */ 2963102087Sluigi NOT_BLOCK; 2964102087Sluigi NEED1("missing mac type"); 2965102087Sluigi if (add_mactype(cmd, ac, av[0])) 2966102087Sluigi cmd = next_cmd(cmd); 2967102087Sluigi ac--; av++; /* any or mac-type */ 2968102087Sluigi goto read_options; 2969102087Sluigi } 2970102098Sluigi#endif 2971102087Sluigi 2972102087Sluigi /* 297398943Sluigi * protocol, mandatory 297498943Sluigi */ 297598943Sluigi OR_START(get_proto); 297698943Sluigi NOT_BLOCK; 297798943Sluigi NEED1("missing protocol"); 2978102087Sluigi if (add_proto(cmd, *av)) { 2979102087Sluigi av++; ac--; 2980102087Sluigi if (F_LEN(cmd) == 0) /* plain IP */ 2981102087Sluigi proto = 0; 2982102087Sluigi else { 2983102087Sluigi proto = cmd->arg1; 2984102087Sluigi prev = cmd; 2985102087Sluigi cmd = next_cmd(cmd); 2986102087Sluigi } 2987102098Sluigi } else if (first_cmd != cmd) { 2988116438Smaxim errx(EX_DATAERR, "invalid protocol ``%s''", *av); 2989102098Sluigi } else 2990102098Sluigi goto read_options; 299198943Sluigi OR_BLOCK(get_proto); 299298943Sluigi 299398943Sluigi /* 2994102087Sluigi * "from", mandatory 299598943Sluigi */ 2996102087Sluigi if (!ac || strncmp(*av, "from", strlen(*av))) 299798943Sluigi errx(EX_USAGE, "missing ``from''"); 299898943Sluigi ac--; av++; 299998943Sluigi 300098943Sluigi /* 300198943Sluigi * source IP, mandatory 300298943Sluigi */ 300398943Sluigi OR_START(source_ip); 300498943Sluigi NOT_BLOCK; /* optional "not" */ 300598943Sluigi NEED1("missing source address"); 3006102087Sluigi if (add_srcip(cmd, *av)) { 3007102087Sluigi ac--; av++; 3008102087Sluigi if (F_LEN(cmd) != 0) { /* ! any */ 3009102087Sluigi prev = cmd; 3010102087Sluigi cmd = next_cmd(cmd); 3011102087Sluigi } 3012102087Sluigi } 301398943Sluigi OR_BLOCK(source_ip); 301498943Sluigi 301598943Sluigi /* 301698943Sluigi * source ports, optional 301798943Sluigi */ 301898943Sluigi NOT_BLOCK; /* optional "not" */ 3019101641Sluigi if (ac) { 3020102087Sluigi if (!strncmp(*av, "any", strlen(*av)) || 3021102087Sluigi add_ports(cmd, *av, proto, O_IP_SRCPORT)) { 3022102087Sluigi ac--; av++; 3023102087Sluigi if (F_LEN(cmd) != 0) 3024102087Sluigi cmd = next_cmd(cmd); 3025101641Sluigi } 302698943Sluigi } 302798943Sluigi 302898943Sluigi /* 3029102087Sluigi * "to", mandatory 303098943Sluigi */ 3031102087Sluigi if (!ac || strncmp(*av, "to", strlen(*av))) 303298943Sluigi errx(EX_USAGE, "missing ``to''"); 303398943Sluigi av++; ac--; 303498943Sluigi 303598943Sluigi /* 303698943Sluigi * destination, mandatory 303798943Sluigi */ 303898943Sluigi OR_START(dest_ip); 303998943Sluigi NOT_BLOCK; /* optional "not" */ 304098943Sluigi NEED1("missing dst address"); 3041102087Sluigi if (add_dstip(cmd, *av)) { 3042102087Sluigi ac--; av++; 3043102087Sluigi if (F_LEN(cmd) != 0) { /* ! any */ 3044102087Sluigi prev = cmd; 3045102087Sluigi cmd = next_cmd(cmd); 3046102087Sluigi } 3047102087Sluigi } 304898943Sluigi OR_BLOCK(dest_ip); 304998943Sluigi 305098943Sluigi /* 305198943Sluigi * dest. ports, optional 305298943Sluigi */ 305398943Sluigi NOT_BLOCK; /* optional "not" */ 3054101641Sluigi if (ac) { 3055102087Sluigi if (!strncmp(*av, "any", strlen(*av)) || 3056102087Sluigi add_ports(cmd, *av, proto, O_IP_DSTPORT)) { 3057102087Sluigi ac--; av++; 3058102087Sluigi if (F_LEN(cmd) != 0) 3059102087Sluigi cmd = next_cmd(cmd); 3060101641Sluigi } 306198943Sluigi } 306298943Sluigi 306398943Sluigiread_options: 3064102087Sluigi if (ac && first_cmd == cmd) { 3065102087Sluigi /* 3066102087Sluigi * nothing specified so far, store in the rule to ease 3067102087Sluigi * printout later. 3068102087Sluigi */ 3069102087Sluigi rule->_pad = 1; 3070102087Sluigi } 307198943Sluigi prev = NULL; 307298943Sluigi while (ac) { 3073101641Sluigi char *s; 3074101641Sluigi ipfw_insn_u32 *cmd32; /* alias for cmd */ 307598943Sluigi 3076101641Sluigi s = *av; 3077101641Sluigi cmd32 = (ipfw_insn_u32 *)cmd; 3078101641Sluigi 307998943Sluigi if (*s == '!') { /* alternate syntax for NOT */ 308098943Sluigi if (cmd->len & F_NOT) 308198943Sluigi errx(EX_USAGE, "double \"not\" not allowed\n"); 308298943Sluigi cmd->len = F_NOT; 308398943Sluigi s++; 308498943Sluigi } 308598943Sluigi i = match_token(rule_options, s); 308698943Sluigi ac--; av++; 308798943Sluigi switch(i) { 308898943Sluigi case TOK_NOT: 308998943Sluigi if (cmd->len & F_NOT) 309098943Sluigi errx(EX_USAGE, "double \"not\" not allowed\n"); 309198943Sluigi cmd->len = F_NOT; 309298943Sluigi break; 309398943Sluigi 309498943Sluigi case TOK_OR: 3095101641Sluigi if (open_par == 0 || prev == NULL) 309698943Sluigi errx(EX_USAGE, "invalid \"or\" block\n"); 309798943Sluigi prev->len |= F_OR; 309898943Sluigi break; 3099101641Sluigi 3100101641Sluigi case TOK_STARTBRACE: 3101101641Sluigi if (open_par) 3102101641Sluigi errx(EX_USAGE, "+nested \"(\" not allowed\n"); 3103101641Sluigi open_par = 1; 3104101641Sluigi break; 3105101641Sluigi 3106101641Sluigi case TOK_ENDBRACE: 3107101641Sluigi if (!open_par) 3108101641Sluigi errx(EX_USAGE, "+missing \")\"\n"); 3109101641Sluigi open_par = 0; 3110102087Sluigi prev = NULL; 3111101641Sluigi break; 3112101641Sluigi 311398943Sluigi case TOK_IN: 311498943Sluigi fill_cmd(cmd, O_IN, 0, 0); 311598943Sluigi break; 311698943Sluigi 311798943Sluigi case TOK_OUT: 311898943Sluigi cmd->len ^= F_NOT; /* toggle F_NOT */ 311998943Sluigi fill_cmd(cmd, O_IN, 0, 0); 312098943Sluigi break; 312198943Sluigi 312298943Sluigi case TOK_FRAG: 312398943Sluigi fill_cmd(cmd, O_FRAG, 0, 0); 312498943Sluigi break; 312598943Sluigi 312698943Sluigi case TOK_LAYER2: 312798943Sluigi fill_cmd(cmd, O_LAYER2, 0, 0); 312898943Sluigi break; 312998943Sluigi 313098943Sluigi case TOK_XMIT: 313198943Sluigi case TOK_RECV: 313298943Sluigi case TOK_VIA: 313398943Sluigi NEED1("recv, xmit, via require interface name" 313498943Sluigi " or address"); 313598943Sluigi fill_iface((ipfw_insn_if *)cmd, av[0]); 313698943Sluigi ac--; av++; 313798943Sluigi if (F_LEN(cmd) == 0) /* not a valid address */ 313898943Sluigi break; 313998943Sluigi if (i == TOK_XMIT) 314098943Sluigi cmd->opcode = O_XMIT; 314198943Sluigi else if (i == TOK_RECV) 314298943Sluigi cmd->opcode = O_RECV; 314398943Sluigi else if (i == TOK_VIA) 314498943Sluigi cmd->opcode = O_VIA; 314598943Sluigi break; 314698943Sluigi 314799475Sluigi case TOK_ICMPTYPES: 314899475Sluigi NEED1("icmptypes requires list of types"); 314999475Sluigi fill_icmptypes((ipfw_insn_u32 *)cmd, *av); 315099475Sluigi av++; ac--; 315199475Sluigi break; 315299475Sluigi 315398943Sluigi case TOK_IPTTL: 315498943Sluigi NEED1("ipttl requires TTL"); 3155116690Sluigi if (strpbrk(*av, "-,")) { 3156116690Sluigi if (!add_ports(cmd, *av, 0, O_IPTTL)) 3157116690Sluigi errx(EX_DATAERR, "invalid ipttl %s", *av); 3158116690Sluigi } else 3159116690Sluigi fill_cmd(cmd, O_IPTTL, 0, strtoul(*av, NULL, 0)); 316098943Sluigi ac--; av++; 316198943Sluigi break; 316298943Sluigi 316398943Sluigi case TOK_IPID: 3164116690Sluigi NEED1("ipid requires id"); 3165116690Sluigi if (strpbrk(*av, "-,")) { 3166116690Sluigi if (!add_ports(cmd, *av, 0, O_IPID)) 3167116690Sluigi errx(EX_DATAERR, "invalid ipid %s", *av); 3168116690Sluigi } else 3169116690Sluigi fill_cmd(cmd, O_IPID, 0, strtoul(*av, NULL, 0)); 317098943Sluigi ac--; av++; 317198943Sluigi break; 317298943Sluigi 317398943Sluigi case TOK_IPLEN: 317498943Sluigi NEED1("iplen requires length"); 3175116690Sluigi if (strpbrk(*av, "-,")) { 3176116690Sluigi if (!add_ports(cmd, *av, 0, O_IPLEN)) 3177116690Sluigi errx(EX_DATAERR, "invalid ip len %s", *av); 3178116690Sluigi } else 3179116690Sluigi fill_cmd(cmd, O_IPLEN, 0, strtoul(*av, NULL, 0)); 318098943Sluigi ac--; av++; 318198943Sluigi break; 318298943Sluigi 318398943Sluigi case TOK_IPVER: 318498943Sluigi NEED1("ipver requires version"); 318598943Sluigi fill_cmd(cmd, O_IPVER, 0, strtoul(*av, NULL, 0)); 318698943Sluigi ac--; av++; 318798943Sluigi break; 318898943Sluigi 318999475Sluigi case TOK_IPPRECEDENCE: 319099475Sluigi NEED1("ipprecedence requires value"); 319199475Sluigi fill_cmd(cmd, O_IPPRECEDENCE, 0, 319299475Sluigi (strtoul(*av, NULL, 0) & 7) << 5); 319399475Sluigi ac--; av++; 319499475Sluigi break; 319599475Sluigi 319698943Sluigi case TOK_IPOPTS: 319798943Sluigi NEED1("missing argument for ipoptions"); 3198101116Sluigi fill_flags(cmd, O_IPOPT, f_ipopts, *av); 319998943Sluigi ac--; av++; 320098943Sluigi break; 320198943Sluigi 320299475Sluigi case TOK_IPTOS: 320399475Sluigi NEED1("missing argument for iptos"); 3204101116Sluigi fill_flags(cmd, O_IPTOS, f_iptos, *av); 320599475Sluigi ac--; av++; 320699475Sluigi break; 320799475Sluigi 320898943Sluigi case TOK_UID: 320998943Sluigi NEED1("uid requires argument"); 321098943Sluigi { 321198943Sluigi char *end; 321298943Sluigi uid_t uid; 321398943Sluigi struct passwd *pwd; 321498943Sluigi 321598943Sluigi cmd->opcode = O_UID; 321698943Sluigi uid = strtoul(*av, &end, 0); 321798943Sluigi pwd = (*end == '\0') ? getpwuid(uid) : getpwnam(*av); 321898943Sluigi if (pwd == NULL) 321998943Sluigi errx(EX_DATAERR, "uid \"%s\" nonexistent", *av); 3220106504Smaxim cmd32->d[0] = pwd->pw_uid; 322198943Sluigi cmd->len = F_INSN_SIZE(ipfw_insn_u32); 322298943Sluigi ac--; av++; 322398943Sluigi } 322498943Sluigi break; 322598943Sluigi 322698943Sluigi case TOK_GID: 322798943Sluigi NEED1("gid requires argument"); 322898943Sluigi { 322998943Sluigi char *end; 323098943Sluigi gid_t gid; 323198943Sluigi struct group *grp; 323298943Sluigi 323398943Sluigi cmd->opcode = O_GID; 323498943Sluigi gid = strtoul(*av, &end, 0); 323598943Sluigi grp = (*end == '\0') ? getgrgid(gid) : getgrnam(*av); 323698943Sluigi if (grp == NULL) 323798943Sluigi errx(EX_DATAERR, "gid \"%s\" nonexistent", *av); 3238106504Smaxim cmd32->d[0] = grp->gr_gid; 323998943Sluigi cmd->len = F_INSN_SIZE(ipfw_insn_u32); 324098943Sluigi ac--; av++; 324198943Sluigi } 324298943Sluigi break; 324398943Sluigi 324498943Sluigi case TOK_ESTAB: 324598943Sluigi fill_cmd(cmd, O_ESTAB, 0, 0); 324698943Sluigi break; 324798943Sluigi 324898943Sluigi case TOK_SETUP: 324998943Sluigi fill_cmd(cmd, O_TCPFLAGS, 0, 325098943Sluigi (TH_SYN) | ( (TH_ACK) & 0xff) <<8 ); 325198943Sluigi break; 325298943Sluigi 325398943Sluigi case TOK_TCPOPTS: 325498943Sluigi NEED1("missing argument for tcpoptions"); 325598943Sluigi fill_flags(cmd, O_TCPOPTS, f_tcpopts, *av); 325698943Sluigi ac--; av++; 325798943Sluigi break; 325898943Sluigi 325998943Sluigi case TOK_TCPSEQ: 326098943Sluigi case TOK_TCPACK: 326198943Sluigi NEED1("tcpseq/tcpack requires argument"); 326298943Sluigi cmd->len = F_INSN_SIZE(ipfw_insn_u32); 326398943Sluigi cmd->opcode = (i == TOK_TCPSEQ) ? O_TCPSEQ : O_TCPACK; 326498943Sluigi cmd32->d[0] = htonl(strtoul(*av, NULL, 0)); 326598943Sluigi ac--; av++; 326698943Sluigi break; 326798943Sluigi 326898943Sluigi case TOK_TCPWIN: 326998943Sluigi NEED1("tcpwin requires length"); 327098943Sluigi fill_cmd(cmd, O_TCPWIN, 0, 327198943Sluigi htons(strtoul(*av, NULL, 0))); 327298943Sluigi ac--; av++; 327398943Sluigi break; 327498943Sluigi 327598943Sluigi case TOK_TCPFLAGS: 327698943Sluigi NEED1("missing argument for tcpflags"); 327798943Sluigi cmd->opcode = O_TCPFLAGS; 327898943Sluigi fill_flags(cmd, O_TCPFLAGS, f_tcpflags, *av); 327998943Sluigi ac--; av++; 328098943Sluigi break; 328198943Sluigi 328298943Sluigi case TOK_KEEPSTATE: 3283101641Sluigi if (open_par) 3284101641Sluigi errx(EX_USAGE, "keep-state cannot be part " 3285101641Sluigi "of an or block"); 328699909Sluigi if (have_state) 3287101116Sluigi errx(EX_USAGE, "only one of keep-state " 328899909Sluigi "and limit is allowed"); 3289101116Sluigi have_state = cmd; 329098943Sluigi fill_cmd(cmd, O_KEEP_STATE, 0, 0); 329198943Sluigi break; 329298943Sluigi 329398943Sluigi case TOK_LIMIT: 3294101641Sluigi if (open_par) 3295101641Sluigi errx(EX_USAGE, "limit cannot be part " 3296101641Sluigi "of an or block"); 329799909Sluigi if (have_state) 3298101116Sluigi errx(EX_USAGE, "only one of keep-state " 329999909Sluigi "and limit is allowed"); 3300101641Sluigi NEED1("limit needs mask and # of connections"); 3301101116Sluigi have_state = cmd; 330298943Sluigi { 330398943Sluigi ipfw_insn_limit *c = (ipfw_insn_limit *)cmd; 330498943Sluigi 330598943Sluigi cmd->len = F_INSN_SIZE(ipfw_insn_limit); 330698943Sluigi cmd->opcode = O_LIMIT; 330798943Sluigi c->limit_mask = 0; 330898943Sluigi c->conn_limit = 0; 330998943Sluigi for (; ac >1 ;) { 331098943Sluigi int val; 331198943Sluigi 331298943Sluigi val = match_token(limit_masks, *av); 331398943Sluigi if (val <= 0) 331498943Sluigi break; 331598943Sluigi c->limit_mask |= val; 331698943Sluigi ac--; av++; 331798943Sluigi } 331898943Sluigi c->conn_limit = atoi(*av); 331998943Sluigi if (c->conn_limit == 0) 332098943Sluigi errx(EX_USAGE, "limit: limit must be >0"); 332198943Sluigi if (c->limit_mask == 0) 332298943Sluigi errx(EX_USAGE, "missing limit mask"); 332398943Sluigi ac--; av++; 332498943Sluigi } 332598943Sluigi break; 332698943Sluigi 3327102087Sluigi case TOK_PROTO: 3328102087Sluigi NEED1("missing protocol"); 3329102087Sluigi if (add_proto(cmd, *av)) { 3330102087Sluigi proto = cmd->arg1; 3331102087Sluigi ac--; av++; 3332102098Sluigi } else 3333116438Smaxim errx(EX_DATAERR, "invalid protocol ``%s''", 3334116438Smaxim *av); 3335102087Sluigi break; 3336106505Smaxim 3337102087Sluigi case TOK_SRCIP: 3338102087Sluigi NEED1("missing source IP"); 3339102087Sluigi if (add_srcip(cmd, *av)) { 3340102087Sluigi ac--; av++; 3341102087Sluigi } 3342102087Sluigi break; 3343102087Sluigi 3344102087Sluigi case TOK_DSTIP: 3345102087Sluigi NEED1("missing destination IP"); 3346102087Sluigi if (add_dstip(cmd, *av)) { 3347102087Sluigi ac--; av++; 3348102087Sluigi } 3349102087Sluigi break; 3350102087Sluigi 3351102087Sluigi case TOK_SRCPORT: 3352102087Sluigi NEED1("missing source port"); 3353102087Sluigi if (!strncmp(*av, "any", strlen(*av)) || 3354102087Sluigi add_ports(cmd, *av, proto, O_IP_SRCPORT)) { 3355102087Sluigi ac--; av++; 3356102087Sluigi } else 3357102087Sluigi errx(EX_DATAERR, "invalid source port %s", *av); 3358102087Sluigi break; 3359102087Sluigi 3360102087Sluigi case TOK_DSTPORT: 3361102087Sluigi NEED1("missing destination port"); 3362102087Sluigi if (!strncmp(*av, "any", strlen(*av)) || 3363102087Sluigi add_ports(cmd, *av, proto, O_IP_DSTPORT)) { 3364102087Sluigi ac--; av++; 3365102087Sluigi } else 3366102087Sluigi errx(EX_DATAERR, "invalid destination port %s", 3367102087Sluigi *av); 3368102087Sluigi break; 3369102087Sluigi 3370102087Sluigi case TOK_MAC: 3371102087Sluigi if (ac < 2) 3372102087Sluigi errx(EX_USAGE, "MAC dst-mac src-mac"); 3373102087Sluigi if (add_mac(cmd, ac, av)) { 3374102087Sluigi ac -= 2; av += 2; 3375102087Sluigi } 3376102087Sluigi break; 3377102087Sluigi 3378102087Sluigi case TOK_MACTYPE: 3379102087Sluigi NEED1("missing mac type"); 3380102087Sluigi if (!add_mactype(cmd, ac, *av)) 3381116438Smaxim errx(EX_DATAERR, "invalid mac type %s", *av); 3382102087Sluigi ac--; av++; 3383102087Sluigi break; 3384102087Sluigi 3385112250Scjc case TOK_VERREVPATH: 3386112250Scjc fill_cmd(cmd, O_VERREVPATH, 0, 0); 3387112250Scjc break; 3388116919Sluigi 3389117241Sluigi case TOK_IPSEC: 3390117241Sluigi fill_cmd(cmd, O_IPSEC, 0, 0); 3391117241Sluigi break; 3392117241Sluigi 3393117469Sluigi case TOK_COMMENT: 3394117469Sluigi fill_comment(cmd, ac, av); 3395117469Sluigi av += ac; 3396117469Sluigi ac = 0; 3397117469Sluigi break; 3398117469Sluigi 339998943Sluigi default: 340098943Sluigi errx(EX_USAGE, "unrecognised option [%d] %s\n", i, s); 340198943Sluigi } 340298943Sluigi if (F_LEN(cmd) > 0) { /* prepare to advance */ 340398943Sluigi prev = cmd; 340498943Sluigi cmd = next_cmd(cmd); 340598943Sluigi } 340698943Sluigi } 340798943Sluigi 340898943Sluigidone: 340998943Sluigi /* 341098943Sluigi * Now copy stuff into the rule. 341198943Sluigi * If we have a keep-state option, the first instruction 341298943Sluigi * must be a PROBE_STATE (which is generated here). 341398943Sluigi * If we have a LOG option, it was stored as the first command, 341498943Sluigi * and now must be moved to the top of the action part. 341598943Sluigi */ 341698943Sluigi dst = (ipfw_insn *)rule->cmd; 341798943Sluigi 341898943Sluigi /* 3419107289Sluigi * First thing to write into the command stream is the match probability. 3420107289Sluigi */ 3421107289Sluigi if (match_prob != 1) { /* 1 means always match */ 3422107289Sluigi dst->opcode = O_PROB; 3423107289Sluigi dst->len = 2; 3424107289Sluigi *((int32_t *)(dst+1)) = (int32_t)(match_prob * 0x7fffffff); 3425107289Sluigi dst += dst->len; 3426107289Sluigi } 3427107289Sluigi 3428107289Sluigi /* 342998943Sluigi * generate O_PROBE_STATE if necessary 343098943Sluigi */ 3431101116Sluigi if (have_state && have_state->opcode != O_CHECK_STATE) { 343298943Sluigi fill_cmd(dst, O_PROBE_STATE, 0, 0); 343398943Sluigi dst = next_cmd(dst); 343498943Sluigi } 343598943Sluigi /* 3436101116Sluigi * copy all commands but O_LOG, O_KEEP_STATE, O_LIMIT 343798943Sluigi */ 343898943Sluigi for (src = (ipfw_insn *)cmdbuf; src != cmd; src += i) { 343998943Sluigi i = F_LEN(src); 344098943Sluigi 3441101116Sluigi switch (src->opcode) { 3442101116Sluigi case O_LOG: 3443101116Sluigi case O_KEEP_STATE: 3444101116Sluigi case O_LIMIT: 3445101116Sluigi break; 3446101116Sluigi default: 3447117328Sluigi bcopy(src, dst, i * sizeof(uint32_t)); 344898943Sluigi dst += i; 344998943Sluigi } 345098943Sluigi } 345198943Sluigi 345298943Sluigi /* 3453101116Sluigi * put back the have_state command as last opcode 3454101116Sluigi */ 3455101295Sluigi if (have_state && have_state->opcode != O_CHECK_STATE) { 3456101116Sluigi i = F_LEN(have_state); 3457117328Sluigi bcopy(have_state, dst, i * sizeof(uint32_t)); 3458101116Sluigi dst += i; 3459101116Sluigi } 3460101116Sluigi /* 346198943Sluigi * start action section 346298943Sluigi */ 346398943Sluigi rule->act_ofs = dst - rule->cmd; 346498943Sluigi 346598943Sluigi /* 346698943Sluigi * put back O_LOG if necessary 346798943Sluigi */ 346898943Sluigi src = (ipfw_insn *)cmdbuf; 3469117577Sluigi if (src->opcode == O_LOG) { 347098943Sluigi i = F_LEN(src); 3471117328Sluigi bcopy(src, dst, i * sizeof(uint32_t)); 347298943Sluigi dst += i; 347398943Sluigi } 347498943Sluigi /* 347598943Sluigi * copy all other actions 347698943Sluigi */ 347798943Sluigi for (src = (ipfw_insn *)actbuf; src != action; src += i) { 347898943Sluigi i = F_LEN(src); 3479117328Sluigi bcopy(src, dst, i * sizeof(uint32_t)); 348098943Sluigi dst += i; 348198943Sluigi } 348298943Sluigi 3483117328Sluigi rule->cmd_len = (uint32_t *)dst - (uint32_t *)(rule->cmd); 3484117469Sluigi i = (char *)dst - (char *)rule; 3485119740Stmm if (do_cmd(IP_FW_ADD, rule, (uintptr_t)&i) == -1) 348698943Sluigi err(EX_UNAVAILABLE, "getsockopt(%s)", "IP_FW_ADD"); 348798943Sluigi if (!do_quiet) 3488117469Sluigi show_ipfw(rule, 0, 0); 348998943Sluigi} 349098943Sluigi 349198943Sluigistatic void 3492117328Sluigizero(int ac, char *av[], int optname /* IP_FW_ZERO or IP_FW_RESETLOG */) 349398943Sluigi{ 349498943Sluigi int rulenum; 349598943Sluigi int failed = EX_OK; 3496117469Sluigi char const *name = optname == IP_FW_ZERO ? "ZERO" : "RESETLOG"; 349798943Sluigi 349898943Sluigi av++; ac--; 349998943Sluigi 350098943Sluigi if (!ac) { 350198943Sluigi /* clear all entries */ 3502117328Sluigi if (do_cmd(optname, NULL, 0) < 0) 3503117328Sluigi err(EX_UNAVAILABLE, "setsockopt(IP_FW_%s)", name); 350498943Sluigi if (!do_quiet) 3505117328Sluigi printf("%s.\n", optname == IP_FW_ZERO ? 3506117328Sluigi "Accounting cleared":"Logging counts reset"); 350798943Sluigi 350898943Sluigi return; 350998943Sluigi } 351098943Sluigi 351198943Sluigi while (ac) { 351298943Sluigi /* Rule number */ 351398943Sluigi if (isdigit(**av)) { 351498943Sluigi rulenum = atoi(*av); 351598943Sluigi av++; 351698943Sluigi ac--; 3517117328Sluigi if (do_cmd(optname, &rulenum, sizeof rulenum)) { 3518117328Sluigi warn("rule %u: setsockopt(IP_FW_%s)", 3519117328Sluigi rulenum, name); 352098943Sluigi failed = EX_UNAVAILABLE; 352198943Sluigi } else if (!do_quiet) 3522117328Sluigi printf("Entry %d %s.\n", rulenum, 3523117328Sluigi optname == IP_FW_ZERO ? 3524117328Sluigi "cleared" : "logging count reset"); 352598943Sluigi } else { 352698943Sluigi errx(EX_USAGE, "invalid rule number ``%s''", *av); 352798943Sluigi } 352898943Sluigi } 352998943Sluigi if (failed != EX_OK) 353098943Sluigi exit(failed); 353198943Sluigi} 353298943Sluigi 353398943Sluigistatic void 3534117544Sluigiflush(int force) 353598943Sluigi{ 353698943Sluigi int cmd = do_pipe ? IP_DUMMYNET_FLUSH : IP_FW_FLUSH; 353798943Sluigi 3538117544Sluigi if (!force && !do_quiet) { /* need to ask user */ 353998943Sluigi int c; 354098943Sluigi 354198943Sluigi printf("Are you sure? [yn] "); 354298943Sluigi fflush(stdout); 354398943Sluigi do { 354498943Sluigi c = toupper(getc(stdin)); 354598943Sluigi while (c != '\n' && getc(stdin) != '\n') 354698943Sluigi if (feof(stdin)) 354798943Sluigi return; /* and do not flush */ 354898943Sluigi } while (c != 'Y' && c != 'N'); 354998943Sluigi printf("\n"); 355098943Sluigi if (c == 'N') /* user said no */ 355198943Sluigi return; 355298943Sluigi } 3553117328Sluigi if (do_cmd(cmd, NULL, 0) < 0) 355498943Sluigi err(EX_UNAVAILABLE, "setsockopt(IP_%s_FLUSH)", 355598943Sluigi do_pipe ? "DUMMYNET" : "FW"); 355698943Sluigi if (!do_quiet) 355798943Sluigi printf("Flushed all %s.\n", do_pipe ? "pipes" : "rules"); 355898943Sluigi} 355998943Sluigi 3560117469Sluigi/* 3561117544Sluigi * Free a the (locally allocated) copy of command line arguments. 3562117469Sluigi */ 3563117544Sluigistatic void 3564117544Sluigifree_args(int ac, char **av) 3565117544Sluigi{ 3566117544Sluigi int i; 3567117544Sluigi 3568117544Sluigi for (i=0; i < ac; i++) 3569117544Sluigi free(av[i]); 3570117544Sluigi free(av); 3571117544Sluigi} 3572117544Sluigi 3573117544Sluigi/* 3574117544Sluigi * Called with the arguments (excluding program name). 3575117544Sluigi * Returns 0 if successful, 1 if empty command, errx() in case of errors. 3576117544Sluigi */ 357798943Sluigistatic int 3578117328Sluigiipfw_main(int oldac, char **oldav) 357998943Sluigi{ 3580117469Sluigi int ch, ac, save_ac; 3581117469Sluigi char **av, **save_av; 3582117469Sluigi int do_acct = 0; /* Show packet/byte count */ 3583117544Sluigi int do_force = 0; /* Don't ask for confirmation */ 3584117469Sluigi 3585117469Sluigi#define WHITESP " \t\f\v\n\r" 3586117544Sluigi if (oldac == 0) 3587117544Sluigi return 1; 3588117544Sluigi else if (oldac == 1) { 3589117328Sluigi /* 3590117328Sluigi * If we are called with a single string, try to split it into 3591117328Sluigi * arguments for subsequent parsing. 3592117328Sluigi * But first, remove spaces after a ',', by copying the string 3593117328Sluigi * in-place. 3594117328Sluigi */ 3595117469Sluigi char *arg = oldav[0]; /* The string... */ 3596117328Sluigi int l = strlen(arg); 3597117328Sluigi int copy = 0; /* 1 if we need to copy, 0 otherwise */ 3598117328Sluigi int i, j; 3599117469Sluigi for (i = j = 0; i < l; i++) { 3600117469Sluigi if (arg[i] == '#') /* comment marker */ 3601117469Sluigi break; 3602117328Sluigi if (copy) { 3603117328Sluigi arg[j++] = arg[i]; 3604117469Sluigi copy = !index("," WHITESP, arg[i]); 3605117328Sluigi } else { 3606117469Sluigi copy = !index(WHITESP, arg[i]); 3607117328Sluigi if (copy) 3608117328Sluigi arg[j++] = arg[i]; 3609117328Sluigi } 3610117469Sluigi } 3611117328Sluigi if (!copy && j > 0) /* last char was a 'blank', remove it */ 3612117328Sluigi j--; 3613117328Sluigi l = j; /* the new argument length */ 3614117328Sluigi arg[j++] = '\0'; 3615117469Sluigi if (l == 0) /* empty string! */ 3616117544Sluigi return 1; 3617117328Sluigi 3618117328Sluigi /* 3619117328Sluigi * First, count number of arguments. Because of the previous 3620117469Sluigi * processing, this is just the number of blanks plus 1. 3621117328Sluigi */ 3622117469Sluigi for (i = 0, ac = 1; i < l; i++) 3623117469Sluigi if (index(WHITESP, arg[i]) != NULL) 3624117328Sluigi ac++; 3625117328Sluigi 3626117328Sluigi av = calloc(ac, sizeof(char *)); 3627117328Sluigi 3628117328Sluigi /* 3629117328Sluigi * Second, copy arguments from cmd[] to av[]. For each one, 3630117328Sluigi * j is the initial character, i is the one past the end. 3631117328Sluigi */ 3632117469Sluigi for (ac = 0, i = j = 0; i < l; i++) 3633117469Sluigi if (index(WHITESP, arg[i]) != NULL || i == l-1) { 3634117328Sluigi if (i == l-1) 3635117328Sluigi i++; 3636117328Sluigi av[ac] = calloc(i-j+1, 1); 3637117328Sluigi bcopy(arg+j, av[ac], i-j); 3638117328Sluigi ac++; 3639117328Sluigi j = i + 1; 3640117328Sluigi } 3641117328Sluigi } else { 3642117328Sluigi /* 3643117328Sluigi * If an argument ends with ',' join with the next one. 3644117328Sluigi */ 3645117328Sluigi int first, i, l; 3646117328Sluigi 3647117328Sluigi av = calloc(oldac, sizeof(char *)); 3648117328Sluigi for (first = i = ac = 0, l = 0; i < oldac; i++) { 3649117328Sluigi char *arg = oldav[i]; 3650117328Sluigi int k = strlen(arg); 3651117328Sluigi 3652117328Sluigi l += k; 3653117328Sluigi if (arg[k-1] != ',' || i == oldac-1) { 3654117328Sluigi /* Time to copy. */ 3655117328Sluigi av[ac] = calloc(l+1, 1); 3656117328Sluigi for (l=0; first <= i; first++) { 3657117328Sluigi strcat(av[ac]+l, oldav[first]); 3658117328Sluigi l += strlen(oldav[first]); 3659117328Sluigi } 3660117328Sluigi ac++; 3661117328Sluigi l = 0; 3662117328Sluigi first = i+1; 3663117328Sluigi } 3664117328Sluigi } 3665117328Sluigi } 3666117328Sluigi 366798943Sluigi /* Set the force flag for non-interactive processes */ 366898943Sluigi do_force = !isatty(STDIN_FILENO); 366998943Sluigi 3670117469Sluigi /* Save arguments for final freeing of memory. */ 3671117469Sluigi save_ac = ac; 3672117469Sluigi save_av = av; 3673117469Sluigi 3674117469Sluigi optind = optreset = 0; 3675117472Sluigi while ((ch = getopt(ac, av, "acdefhnNqs:STtv")) != -1) 367698943Sluigi switch (ch) { 367798943Sluigi case 'a': 367898943Sluigi do_acct = 1; 367998943Sluigi break; 3680117328Sluigi 3681102098Sluigi case 'c': 3682102098Sluigi do_compact = 1; 3683102098Sluigi break; 3684117328Sluigi 368598943Sluigi case 'd': 368698943Sluigi do_dynamic = 1; 368798943Sluigi break; 3688117328Sluigi 368998943Sluigi case 'e': 369098943Sluigi do_expired = 1; 369198943Sluigi break; 3692117328Sluigi 369398943Sluigi case 'f': 369498943Sluigi do_force = 1; 369598943Sluigi break; 3696117328Sluigi 3697117328Sluigi case 'h': /* help */ 3698117544Sluigi free_args(save_ac, save_av); 3699117328Sluigi help(); 3700117328Sluigi break; /* NOTREACHED */ 3701117328Sluigi 3702117328Sluigi case 'n': 3703117328Sluigi test_only = 1; 3704117328Sluigi break; 3705117328Sluigi 370698943Sluigi case 'N': 370798943Sluigi do_resolv = 1; 370898943Sluigi break; 3709117328Sluigi 371098943Sluigi case 'q': 371198943Sluigi do_quiet = 1; 371298943Sluigi break; 3713117328Sluigi 3714117328Sluigi case 's': /* sort */ 3715117328Sluigi do_sort = atoi(optarg); 3716117328Sluigi break; 3717117328Sluigi 3718101628Sluigi case 'S': 3719101628Sluigi show_sets = 1; 3720101628Sluigi break; 3721117328Sluigi 372298943Sluigi case 't': 372398943Sluigi do_time = 1; 372498943Sluigi break; 3725117328Sluigi 3726117472Sluigi case 'T': 3727117472Sluigi do_time = 2; /* numeric timestamp */ 3728117472Sluigi break; 3729117472Sluigi 373098943Sluigi case 'v': /* verbose */ 3731117328Sluigi verbose = 1; 373298943Sluigi break; 3733117328Sluigi 373498943Sluigi default: 3735117544Sluigi free_args(save_ac, save_av); 3736117544Sluigi return 1; 373798943Sluigi } 373898943Sluigi 373998943Sluigi ac -= optind; 374098943Sluigi av += optind; 374198943Sluigi NEED1("bad arguments, for usage summary ``ipfw''"); 374298943Sluigi 374398943Sluigi /* 3744117544Sluigi * An undocumented behaviour of ipfw1 was to allow rule numbers first, 3745117544Sluigi * e.g. "100 add allow ..." instead of "add 100 allow ...". 3746117544Sluigi * In case, swap first and second argument to get the normal form. 3747117544Sluigi */ 3748117544Sluigi if (ac > 1 && isdigit(*av[0])) { 3749117544Sluigi char *p = av[0]; 3750117544Sluigi 3751117544Sluigi av[0] = av[1]; 3752117544Sluigi av[1] = p; 3753117544Sluigi } 3754117544Sluigi 3755117544Sluigi /* 375698943Sluigi * optional: pipe or queue 375798943Sluigi */ 3758117821Smaxim do_pipe = 0; 3759117544Sluigi if (!strncmp(*av, "pipe", strlen(*av))) 376098943Sluigi do_pipe = 1; 3761117544Sluigi else if (!strncmp(*av, "queue", strlen(*av))) 376298943Sluigi do_pipe = 2; 3763117544Sluigi if (do_pipe) { 376498943Sluigi ac--; 376598943Sluigi av++; 376698943Sluigi } 376798943Sluigi NEED1("missing command"); 376898943Sluigi 376998943Sluigi /* 3770117328Sluigi * For pipes and queues we normally say 'pipe NN config' 377198943Sluigi * but the code is easier to parse as 'pipe config NN' 377298943Sluigi * so we swap the two arguments. 377398943Sluigi */ 3774117469Sluigi if (do_pipe > 0 && ac > 1 && isdigit(*av[0])) { 377598943Sluigi char *p = av[0]; 3776117544Sluigi 377798943Sluigi av[0] = av[1]; 377898943Sluigi av[1] = p; 377998943Sluigi } 3780117328Sluigi 378198943Sluigi if (!strncmp(*av, "add", strlen(*av))) 378298943Sluigi add(ac, av); 378398943Sluigi else if (do_pipe && !strncmp(*av, "config", strlen(*av))) 378498943Sluigi config_pipe(ac, av); 3785101978Sluigi else if (!strncmp(*av, "delete", strlen(*av))) 378698943Sluigi delete(ac, av); 378798943Sluigi else if (!strncmp(*av, "flush", strlen(*av))) 3788117544Sluigi flush(do_force); 378998943Sluigi else if (!strncmp(*av, "zero", strlen(*av))) 3790117328Sluigi zero(ac, av, IP_FW_ZERO); 379198943Sluigi else if (!strncmp(*av, "resetlog", strlen(*av))) 3792117328Sluigi zero(ac, av, IP_FW_RESETLOG); 379398943Sluigi else if (!strncmp(*av, "print", strlen(*av)) || 379498943Sluigi !strncmp(*av, "list", strlen(*av))) 3795117469Sluigi list(ac, av, do_acct); 3796101978Sluigi else if (!strncmp(*av, "set", strlen(*av))) 3797101978Sluigi sets_handler(ac, av); 3798109126Sdillon else if (!strncmp(*av, "enable", strlen(*av))) 3799109126Sdillon sysctl_handler(ac, av, 1); 3800109126Sdillon else if (!strncmp(*av, "disable", strlen(*av))) 3801109126Sdillon sysctl_handler(ac, av, 0); 3802117469Sluigi else if (!strncmp(*av, "show", strlen(*av))) 3803117469Sluigi list(ac, av, 1 /* show counters */); 3804117469Sluigi else 380598943Sluigi errx(EX_USAGE, "bad command `%s'", *av); 3806117469Sluigi 3807117469Sluigi /* Free memory allocated in the argument parsing. */ 3808117544Sluigi free_args(save_ac, save_av); 380998943Sluigi return 0; 381098943Sluigi} 381198943Sluigi 381298943Sluigi 381398943Sluigistatic void 3814106505Smaximipfw_readfile(int ac, char *av[]) 381598943Sluigi{ 381698943Sluigi#define MAX_ARGS 32 381798943Sluigi char buf[BUFSIZ]; 3818117469Sluigi char *cmd = NULL, *filename = av[ac-1]; 3819117469Sluigi int c, lineno=0; 382098943Sluigi FILE *f = NULL; 382198943Sluigi pid_t preproc = 0; 382298943Sluigi 3823117469Sluigi filename = av[ac-1]; 3824117469Sluigi 3825117469Sluigi while ((c = getopt(ac, av, "cNnp:qS")) != -1) { 382698943Sluigi switch(c) { 3827117469Sluigi case 'c': 3828117469Sluigi do_compact = 1; 3829117469Sluigi break; 3830117469Sluigi 3831117469Sluigi case 'N': 3832117469Sluigi do_resolv = 1; 3833117469Sluigi break; 3834117469Sluigi 3835117328Sluigi case 'n': 3836117328Sluigi test_only = 1; 3837117328Sluigi break; 3838117328Sluigi 383998943Sluigi case 'p': 384098943Sluigi cmd = optarg; 3841117469Sluigi /* 3842117469Sluigi * Skip previous args and delete last one, so we 3843117469Sluigi * pass all but the last argument to the preprocessor 3844117469Sluigi * via av[optind-1] 3845117469Sluigi */ 3846117469Sluigi av += optind - 1; 3847117469Sluigi ac -= optind - 1; 3848117469Sluigi av[ac-1] = NULL; 3849117469Sluigi fprintf(stderr, "command is %s\n", av[0]); 385098943Sluigi break; 385198943Sluigi 385298943Sluigi case 'q': 3853117469Sluigi do_quiet = 1; 385498943Sluigi break; 385598943Sluigi 3856117469Sluigi case 'S': 3857117469Sluigi show_sets = 1; 3858117469Sluigi break; 3859117469Sluigi 386098943Sluigi default: 386198943Sluigi errx(EX_USAGE, "bad arguments, for usage" 386298943Sluigi " summary ``ipfw''"); 386398943Sluigi } 386498943Sluigi 3865117469Sluigi if (cmd != NULL) 3866108231Skbyanc break; 3867108231Skbyanc } 3868108231Skbyanc 3869117469Sluigi if (cmd == NULL && ac != optind + 1) { 3870117469Sluigi fprintf(stderr, "ac %d, optind %d\n", ac, optind); 3871117469Sluigi errx(EX_USAGE, "extraneous filename arguments"); 3872108231Skbyanc } 3873108231Skbyanc 3874117469Sluigi if ((f = fopen(filename, "r")) == NULL) 3875117469Sluigi err(EX_UNAVAILABLE, "fopen: %s", filename); 387698943Sluigi 3877117469Sluigi if (cmd != NULL) { /* pipe through preprocessor */ 387898943Sluigi int pipedes[2]; 387998943Sluigi 388098943Sluigi if (pipe(pipedes) == -1) 388198943Sluigi err(EX_OSERR, "cannot create pipe"); 388298943Sluigi 3883117469Sluigi preproc = fork(); 3884117469Sluigi if (preproc == -1) 388598943Sluigi err(EX_OSERR, "cannot fork"); 388698943Sluigi 3887117577Sluigi if (preproc == 0) { 3888117469Sluigi /* 3889117469Sluigi * Child, will run the preprocessor with the 3890117469Sluigi * file on stdin and the pipe on stdout. 3891117469Sluigi */ 389298943Sluigi if (dup2(fileno(f), 0) == -1 389398943Sluigi || dup2(pipedes[1], 1) == -1) 389498943Sluigi err(EX_OSERR, "dup2()"); 389598943Sluigi fclose(f); 389698943Sluigi close(pipedes[1]); 389798943Sluigi close(pipedes[0]); 3898117469Sluigi execvp(cmd, av); 389998943Sluigi err(EX_OSERR, "execvp(%s) failed", cmd); 3900117469Sluigi } else { /* parent, will reopen f as the pipe */ 390198943Sluigi fclose(f); 390298943Sluigi close(pipedes[1]); 390398943Sluigi if ((f = fdopen(pipedes[0], "r")) == NULL) { 390498943Sluigi int savederrno = errno; 390598943Sluigi 390698943Sluigi (void)kill(preproc, SIGTERM); 390798943Sluigi errno = savederrno; 390898943Sluigi err(EX_OSERR, "fdopen()"); 390998943Sluigi } 391098943Sluigi } 391198943Sluigi } 391298943Sluigi 3913117469Sluigi while (fgets(buf, BUFSIZ, f)) { /* read commands */ 3914117469Sluigi char linename[10]; 3915117469Sluigi char *args[1]; 3916117469Sluigi 391798943Sluigi lineno++; 391898943Sluigi sprintf(linename, "Line %d", lineno); 3919117328Sluigi setprogname(linename); /* XXX */ 3920117469Sluigi args[0] = buf; 3921117469Sluigi ipfw_main(1, args); 392298943Sluigi } 392398943Sluigi fclose(f); 3924117469Sluigi if (cmd != NULL) { 3925117469Sluigi int status; 3926117469Sluigi 392798943Sluigi if (waitpid(preproc, &status, 0) == -1) 392898943Sluigi errx(EX_OSERR, "waitpid()"); 392998943Sluigi if (WIFEXITED(status) && WEXITSTATUS(status) != EX_OK) 393098943Sluigi errx(EX_UNAVAILABLE, 393198943Sluigi "preprocessor exited with status %d", 393298943Sluigi WEXITSTATUS(status)); 393398943Sluigi else if (WIFSIGNALED(status)) 393498943Sluigi errx(EX_UNAVAILABLE, 393598943Sluigi "preprocessor exited with signal %d", 393698943Sluigi WTERMSIG(status)); 393798943Sluigi } 393898943Sluigi} 393998943Sluigi 394098943Sluigiint 394198943Sluigimain(int ac, char *av[]) 394298943Sluigi{ 394398943Sluigi /* 394498943Sluigi * If the last argument is an absolute pathname, interpret it 394598943Sluigi * as a file to be preprocessed. 394698943Sluigi */ 394798943Sluigi 394898943Sluigi if (ac > 1 && av[ac - 1][0] == '/' && access(av[ac - 1], R_OK) == 0) 394998943Sluigi ipfw_readfile(ac, av); 3950117544Sluigi else { 3951117544Sluigi if (ipfw_main(ac-1, av+1)) 3952117544Sluigi show_usage(); 3953117544Sluigi } 395498943Sluigi return EX_OK; 395598943Sluigi} 3956