ipfw2.c revision 101978
198943Sluigi/* 298943Sluigi * Copyright (c) 2002 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 101978 2002-08-16 10:31:47Z luigi $ 2198943Sluigi */ 2298943Sluigi 2398943Sluigi#include <sys/param.h> 2498943Sluigi#include <sys/mbuf.h> 2598943Sluigi#include <sys/socket.h> 2698943Sluigi#include <sys/sockio.h> 2798943Sluigi#include <sys/sysctl.h> 2898943Sluigi#include <sys/time.h> 2998943Sluigi#include <sys/wait.h> 3098943Sluigi 3198943Sluigi#include <ctype.h> 3298943Sluigi#include <err.h> 3398943Sluigi#include <errno.h> 3498943Sluigi#include <grp.h> 3598943Sluigi#include <limits.h> 3698943Sluigi#include <netdb.h> 3798943Sluigi#include <pwd.h> 3898943Sluigi#include <signal.h> 3998943Sluigi#include <stdio.h> 4098943Sluigi#include <stdlib.h> 4198943Sluigi#include <stdarg.h> 4298943Sluigi#include <string.h> 4399603Sbde#include <timeconv.h> 4498943Sluigi#include <unistd.h> 4598943Sluigi#include <sysexits.h> 4698943Sluigi 4798943Sluigi#include <net/if.h> 4898943Sluigi#include <netinet/in.h> 4998943Sluigi#include <netinet/in_systm.h> 5098943Sluigi#include <netinet/ip.h> 5198943Sluigi#include <netinet/ip_icmp.h> 5298943Sluigi#include <netinet/ip_fw.h> 5398943Sluigi#include <net/route.h> /* def. of struct route */ 5498943Sluigi#include <netinet/ip_dummynet.h> 5598943Sluigi#include <netinet/tcp.h> 5698943Sluigi#include <arpa/inet.h> 5798943Sluigi 5898943Sluigiint s, /* main RAW socket */ 5998943Sluigi do_resolv, /* Would try to resolve all */ 6098943Sluigi do_acct, /* Show packet/byte count */ 6198943Sluigi do_time, /* Show time stamps */ 6298943Sluigi do_quiet, /* Be quiet in add and flush */ 6398943Sluigi do_force, /* Don't ask for confirmation */ 6498943Sluigi do_pipe, /* this cmd refers to a pipe */ 6598943Sluigi do_sort, /* field to sort results (0 = no) */ 6698943Sluigi do_dynamic, /* display dynamic rules */ 6798943Sluigi do_expired, /* display expired dynamic rules */ 68101628Sluigi show_sets, /* display rule sets */ 6998943Sluigi verbose; 7098943Sluigi 7198943Sluigi#define IP_MASK_ALL 0xffffffff 7298943Sluigi 7398943Sluigi/* 7498943Sluigi * structure to hold flag names and associated values to be 7598943Sluigi * set in the appropriate masks. 7698943Sluigi * A NULL string terminates the array. 7798943Sluigi * Often, an element with 0 value contains an error string. 7898943Sluigi * 7998943Sluigi */ 8098943Sluigistruct _s_x { 8198943Sluigi char *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, 22498943Sluigi 22598943Sluigi TOK_PLR, 226101978Sluigi TOK_NOERROR, 22798943Sluigi TOK_BUCKETS, 22898943Sluigi TOK_DSTIP, 22998943Sluigi TOK_SRCIP, 23098943Sluigi TOK_DSTPORT, 23198943Sluigi TOK_SRCPORT, 23298943Sluigi TOK_ALL, 23398943Sluigi TOK_MASK, 23498943Sluigi TOK_BW, 23598943Sluigi TOK_DELAY, 23698943Sluigi TOK_RED, 23798943Sluigi TOK_GRED, 23898943Sluigi TOK_DROPTAIL, 23998943Sluigi TOK_PROTO, 24098943Sluigi TOK_WEIGHT, 24198943Sluigi}; 24298943Sluigi 24398943Sluigistruct _s_x dummynet_params[] = { 24498943Sluigi { "plr", TOK_PLR }, 245101978Sluigi { "noerror", TOK_NOERROR }, 24698943Sluigi { "buckets", TOK_BUCKETS }, 24798943Sluigi { "dst-ip", TOK_DSTIP }, 24898943Sluigi { "src-ip", TOK_SRCIP }, 24998943Sluigi { "dst-port", TOK_DSTPORT }, 25098943Sluigi { "src-port", TOK_SRCPORT }, 25198943Sluigi { "proto", TOK_PROTO }, 25298943Sluigi { "weight", TOK_WEIGHT }, 25398943Sluigi { "all", TOK_ALL }, 25498943Sluigi { "mask", TOK_MASK }, 25598943Sluigi { "droptail", TOK_DROPTAIL }, 25698943Sluigi { "red", TOK_RED }, 25798943Sluigi { "gred", TOK_GRED }, 25898943Sluigi { "bw", TOK_BW }, 25998943Sluigi { "bandwidth", TOK_BW }, 26098943Sluigi { "delay", TOK_DELAY }, 26199475Sluigi { "pipe", TOK_PIPE }, 26298943Sluigi { "queue", TOK_QUEUE }, 26398943Sluigi { "dummynet-params", TOK_NULL }, 26498943Sluigi { NULL, 0 } 26598943Sluigi}; 26698943Sluigi 26798943Sluigistruct _s_x rule_actions[] = { 26898943Sluigi { "accept", TOK_ACCEPT }, 26998943Sluigi { "pass", TOK_ACCEPT }, 27098943Sluigi { "allow", TOK_ACCEPT }, 27198943Sluigi { "permit", TOK_ACCEPT }, 27298943Sluigi { "count", TOK_COUNT }, 27398943Sluigi { "pipe", TOK_PIPE }, 27498943Sluigi { "queue", TOK_QUEUE }, 27598943Sluigi { "divert", TOK_DIVERT }, 27698943Sluigi { "tee", TOK_TEE }, 27798943Sluigi { "fwd", TOK_FORWARD }, 27898943Sluigi { "forward", TOK_FORWARD }, 27998943Sluigi { "skipto", TOK_SKIPTO }, 28098943Sluigi { "deny", TOK_DENY }, 28198943Sluigi { "drop", TOK_DENY }, 28298943Sluigi { "reject", TOK_REJECT }, 28398943Sluigi { "reset", TOK_RESET }, 28499475Sluigi { "unreach", TOK_UNREACH }, 28598943Sluigi { "check-state", TOK_CHECKSTATE }, 28698943Sluigi { NULL, TOK_NULL }, 28798943Sluigi { NULL, 0 } 28898943Sluigi}; 28998943Sluigi 29098943Sluigistruct _s_x rule_options[] = { 29198943Sluigi { "uid", TOK_UID }, 29298943Sluigi { "gid", TOK_GID }, 29398943Sluigi { "in", TOK_IN }, 29498943Sluigi { "limit", TOK_LIMIT }, 29598943Sluigi { "keep-state", TOK_KEEPSTATE }, 29698943Sluigi { "bridged", TOK_LAYER2 }, 29798943Sluigi { "layer2", TOK_LAYER2 }, 29898943Sluigi { "out", TOK_OUT }, 29998943Sluigi { "xmit", TOK_XMIT }, 30098943Sluigi { "recv", TOK_RECV }, 30198943Sluigi { "via", TOK_VIA }, 30298943Sluigi { "fragment", TOK_FRAG }, 30398943Sluigi { "frag", TOK_FRAG }, 30498943Sluigi { "ipoptions", TOK_IPOPTS }, 30598943Sluigi { "ipopts", TOK_IPOPTS }, 30698943Sluigi { "iplen", TOK_IPLEN }, 30798943Sluigi { "ipid", TOK_IPID }, 30898943Sluigi { "ipprecedence", TOK_IPPRECEDENCE }, 30998943Sluigi { "iptos", TOK_IPTOS }, 31098943Sluigi { "ipttl", TOK_IPTTL }, 31198943Sluigi { "ipversion", TOK_IPVER }, 31298943Sluigi { "ipver", TOK_IPVER }, 31398943Sluigi { "estab", TOK_ESTAB }, 31498943Sluigi { "established", TOK_ESTAB }, 31598943Sluigi { "setup", TOK_SETUP }, 31698943Sluigi { "tcpflags", TOK_TCPFLAGS }, 31798943Sluigi { "tcpflgs", TOK_TCPFLAGS }, 31898943Sluigi { "tcpoptions", TOK_TCPOPTS }, 31998943Sluigi { "tcpopts", TOK_TCPOPTS }, 32098943Sluigi { "tcpseq", TOK_TCPSEQ }, 32198943Sluigi { "tcpack", TOK_TCPACK }, 32298943Sluigi { "tcpwin", TOK_TCPWIN }, 32399909Sluigi { "icmptype", TOK_ICMPTYPES }, 32498943Sluigi { "icmptypes", TOK_ICMPTYPES }, 32598943Sluigi 32698943Sluigi { "not", TOK_NOT }, /* pseudo option */ 32798943Sluigi { "!", /* escape ? */ TOK_NOT }, /* pseudo option */ 32898943Sluigi { "or", TOK_OR }, /* pseudo option */ 32998943Sluigi { "|", /* escape */ TOK_OR }, /* pseudo option */ 330101641Sluigi { "{", TOK_STARTBRACE }, /* pseudo option */ 331101641Sluigi { "(", TOK_STARTBRACE }, /* pseudo option */ 332101641Sluigi { "}", TOK_ENDBRACE }, /* pseudo option */ 333101641Sluigi { ")", TOK_ENDBRACE }, /* pseudo option */ 33498943Sluigi { NULL, TOK_NULL }, 33598943Sluigi { NULL, 0 } 33698943Sluigi}; 33798943Sluigi 33898943Sluigi/** 33998943Sluigi * match_token takes a table and a string, returns the value associated 34098943Sluigi * with the string (0 meaning an error in most cases) 34198943Sluigi */ 34298943Sluigistatic int 34398943Sluigimatch_token(struct _s_x *table, char *string) 34498943Sluigi{ 34598943Sluigi struct _s_x *pt; 34698943Sluigi int i = strlen(string); 34798943Sluigi 34898943Sluigi for (pt = table ; i && pt->s != NULL ; pt++) 34998943Sluigi if (strlen(pt->s) == i && !bcmp(string, pt->s, i)) 35098943Sluigi return pt->x; 35198943Sluigi return -1; 35298943Sluigi}; 35398943Sluigi 35498943Sluigistatic char * 35598943Sluigimatch_value(struct _s_x *p, u_int32_t value) 35698943Sluigi{ 35798943Sluigi for (; p->s != NULL; p++) 35898943Sluigi if (p->x == value) 35998943Sluigi return p->s; 36098943Sluigi return NULL; 36198943Sluigi} 36298943Sluigi 36398943Sluigi/* 36498943Sluigi * prints one port, symbolic or numeric 36598943Sluigi */ 36698943Sluigistatic void 36798943Sluigiprint_port(int proto, u_int16_t port) 36898943Sluigi{ 36998943Sluigi 37098943Sluigi if (proto == IPPROTO_ETHERTYPE) { 37198943Sluigi char *s; 37298943Sluigi 37398943Sluigi if (do_resolv && (s = match_value(ether_types, port)) ) 37498943Sluigi printf("%s", s); 37598943Sluigi else 37698943Sluigi printf("0x%04x", port); 37798943Sluigi } else { 37898943Sluigi struct servent *se = NULL; 37998943Sluigi if (do_resolv) { 38098943Sluigi struct protoent *pe = getprotobynumber(proto); 38198943Sluigi 38298943Sluigi se = getservbyport(htons(port), pe ? pe->p_name : NULL); 38398943Sluigi } 38498943Sluigi if (se) 38598943Sluigi printf("%s", se->s_name); 38698943Sluigi else 38798943Sluigi printf("%d", port); 38898943Sluigi } 38998943Sluigi} 39098943Sluigi 39198943Sluigi/* 39298943Sluigi * print the values in a list of ports 39398943Sluigi * XXX todo: add support for mask. 39498943Sluigi */ 39598943Sluigistatic void 39698943Sluigiprint_newports(ipfw_insn_u16 *cmd, int proto) 39798943Sluigi{ 39898943Sluigi u_int16_t *p = cmd->ports; 39998943Sluigi int i; 40098943Sluigi char *sep= " "; 40198943Sluigi 40298943Sluigi if (cmd->o.len & F_NOT) 40398943Sluigi printf(" not"); 40498943Sluigi for (i = F_LEN((ipfw_insn *)cmd) - 1; i > 0; i--, p += 2) { 40598943Sluigi printf(sep); 40698943Sluigi print_port(proto, p[0]); 40798943Sluigi if (p[0] != p[1]) { 40898943Sluigi printf("-"); 40998943Sluigi print_port(proto, p[1]); 41098943Sluigi } 41198943Sluigi sep = ","; 41298943Sluigi } 41398943Sluigi} 41498943Sluigi 41598943Sluigi/* 41698943Sluigi * Like strtol, but also translates service names into port numbers 41798943Sluigi * for some protocols. 41898943Sluigi * In particular: 41998943Sluigi * proto == -1 disables the protocol check; 42098943Sluigi * proto == IPPROTO_ETHERTYPE looks up an internal table 42198943Sluigi * proto == <some value in /etc/protocols> matches the values there. 422101628Sluigi * Returns *end == s in case the parameter is not found. 42398943Sluigi */ 42498943Sluigistatic int 42598943Sluigistrtoport(char *s, char **end, int base, int proto) 42698943Sluigi{ 427101628Sluigi char *p, *buf; 428101628Sluigi char *s1; 42998943Sluigi int i; 43098943Sluigi 431101628Sluigi *end = s; /* default - not found */ 43298943Sluigi if ( *s == '\0') 433101628Sluigi return 0; /* not found */ 434101628Sluigi 43598943Sluigi if (isdigit(*s)) 43698943Sluigi return strtol(s, end, base); 43798943Sluigi 43898943Sluigi /* 439101628Sluigi * find separator. '\\' escapes the next char. 44098943Sluigi */ 441101628Sluigi for (s1 = s; *s1 && (isalnum(*s1) || *s1 == '\\') ; s1++) 442101628Sluigi if (*s1 == '\\' && s1[1] != '\0') 443101628Sluigi s1++; 44498943Sluigi 445101628Sluigi buf = malloc(s1 - s + 1); 446101628Sluigi if (buf == NULL) 447101628Sluigi return 0; 448101628Sluigi 449101628Sluigi /* 450101628Sluigi * copy into a buffer skipping backslashes 451101628Sluigi */ 452101628Sluigi for (p = s, i = 0; p != s1 ; p++) 453101628Sluigi if ( *p != '\\') 454101628Sluigi buf[i++] = *p; 455101628Sluigi buf[i++] = '\0'; 456101628Sluigi 45798943Sluigi if (proto == IPPROTO_ETHERTYPE) { 458101628Sluigi i = match_token(ether_types, buf); 459101628Sluigi free(buf); 460101628Sluigi if (i != -1) { /* found */ 46198943Sluigi *end = s1; 46298943Sluigi return i; 46398943Sluigi } 46498943Sluigi } else { 46598943Sluigi struct protoent *pe = NULL; 46698943Sluigi struct servent *se; 46798943Sluigi 46898943Sluigi if (proto != 0) 46998943Sluigi pe = getprotobynumber(proto); 47098943Sluigi setservent(1); 471101628Sluigi se = getservbyname(buf, pe ? pe->p_name : NULL); 472101628Sluigi free(buf); 47398943Sluigi if (se != NULL) { 47498943Sluigi *end = s1; 47598943Sluigi return ntohs(se->s_port); 47698943Sluigi } 47798943Sluigi } 478101628Sluigi return 0; /* not found */ 47998943Sluigi} 48098943Sluigi 48198943Sluigi/* 48298943Sluigi * fill the body of the command with the list of port ranges. 48398943Sluigi * At the moment it only understands numeric ranges. 48498943Sluigi */ 48598943Sluigistatic int 48698943Sluigifill_newports(ipfw_insn_u16 *cmd, char *av, int proto) 48798943Sluigi{ 48898943Sluigi u_int16_t *p = cmd->ports; 48998943Sluigi int i = 0; 49098943Sluigi 49198943Sluigi for (; *av ; i++, p +=2 ) { 49298943Sluigi u_int16_t a, b; 49398943Sluigi char *s; 49498943Sluigi 49598943Sluigi a = strtoport(av, &s, 0, proto); 49698943Sluigi if (s == av) /* no parameter */ 49798943Sluigi break; 49898943Sluigi if (*s == '-') { /* a range */ 49998943Sluigi av = s+1; 50098943Sluigi b = strtoport(av, &s, 0, proto); 50198943Sluigi if (s == av) /* no parameter */ 50298943Sluigi break; 50398943Sluigi p[0] = a; 50498943Sluigi p[1] = b; 50598943Sluigi } else if (*s == ',' || *s == '\0' ) { 50698943Sluigi p[0] = p[1] = a; 507101978Sluigi } else { /* invalid separator */ 508101978Sluigi errx(EX_DATAERR, "invalid separator <%c> in <%s>\n", 509101978Sluigi *s, av); 510101978Sluigi } 51198943Sluigi av = s+1; 51298943Sluigi } 51398943Sluigi if (i > 0) { 51498943Sluigi if (i+1 > F_LEN_MASK) 51598943Sluigi errx(EX_DATAERR, "too many port range\n"); 51698943Sluigi cmd->o.len |= i+1; /* leave F_NOT and F_OR untouched */ 51798943Sluigi } 51898943Sluigi return i; 51998943Sluigi} 52098943Sluigi 52198943Sluigistatic struct _s_x icmpcodes[] = { 52298943Sluigi { "net", ICMP_UNREACH_NET }, 52398943Sluigi { "host", ICMP_UNREACH_HOST }, 52498943Sluigi { "protocol", ICMP_UNREACH_PROTOCOL }, 52598943Sluigi { "port", ICMP_UNREACH_PORT }, 52698943Sluigi { "needfrag", ICMP_UNREACH_NEEDFRAG }, 52798943Sluigi { "srcfail", ICMP_UNREACH_SRCFAIL }, 52898943Sluigi { "net-unknown", ICMP_UNREACH_NET_UNKNOWN }, 52998943Sluigi { "host-unknown", ICMP_UNREACH_HOST_UNKNOWN }, 53098943Sluigi { "isolated", ICMP_UNREACH_ISOLATED }, 53198943Sluigi { "net-prohib", ICMP_UNREACH_NET_PROHIB }, 53298943Sluigi { "host-prohib", ICMP_UNREACH_HOST_PROHIB }, 53398943Sluigi { "tosnet", ICMP_UNREACH_TOSNET }, 53498943Sluigi { "toshost", ICMP_UNREACH_TOSHOST }, 53598943Sluigi { "filter-prohib", ICMP_UNREACH_FILTER_PROHIB }, 53698943Sluigi { "host-precedence", ICMP_UNREACH_HOST_PRECEDENCE }, 53798943Sluigi { "precedence-cutoff", ICMP_UNREACH_PRECEDENCE_CUTOFF }, 53898943Sluigi { NULL, 0 } 53998943Sluigi}; 54098943Sluigi 54198943Sluigistatic void 54298943Sluigifill_reject_code(u_short *codep, char *str) 54398943Sluigi{ 54498943Sluigi int val; 54598943Sluigi char *s; 54698943Sluigi 54798943Sluigi val = strtoul(str, &s, 0); 54898943Sluigi if (s == str || *s != '\0' || val >= 0x100) 54998943Sluigi val = match_token(icmpcodes, str); 55098943Sluigi if (val <= 0) 55198943Sluigi errx(EX_DATAERR, "unknown ICMP unreachable code ``%s''", str); 55298943Sluigi *codep = val; 55398943Sluigi return; 55498943Sluigi} 55598943Sluigi 55698943Sluigistatic void 55799475Sluigiprint_reject_code(u_int16_t code) 55898943Sluigi{ 55998943Sluigi char *s = match_value(icmpcodes, code); 56098943Sluigi 56198943Sluigi if (s != NULL) 56299475Sluigi printf("unreach %s", s); 56398943Sluigi else 56499475Sluigi printf("unreach %u", code); 56598943Sluigi} 56698943Sluigi 56798943Sluigi/* 56898943Sluigi * Returns the number of bits set (from left) in a contiguous bitmask, 56998943Sluigi * or -1 if the mask is not contiguous. 57098943Sluigi * XXX this needs a proper fix. 57198943Sluigi * This effectively works on masks in big-endian (network) format. 57298943Sluigi * when compiled on little endian architectures. 57398943Sluigi * 57498943Sluigi * First bit is bit 7 of the first byte -- note, for MAC addresses, 57598943Sluigi * the first bit on the wire is bit 0 of the first byte. 57698943Sluigi * len is the max length in bits. 57798943Sluigi */ 57898943Sluigistatic int 57998943Sluigicontigmask(u_char *p, int len) 58098943Sluigi{ 58198943Sluigi int i, n; 58298943Sluigi for (i=0; i<len ; i++) 58398943Sluigi if ( (p[i/8] & (1 << (7 - (i%8)))) == 0) /* first bit unset */ 58498943Sluigi break; 58598943Sluigi for (n=i+1; n < len; n++) 58698943Sluigi if ( (p[n/8] & (1 << (7 - (n%8)))) != 0) 58798943Sluigi return -1; /* mask not contiguous */ 58898943Sluigi return i; 58998943Sluigi} 59098943Sluigi 59198943Sluigi/* 59298943Sluigi * print flags set/clear in the two bitmasks passed as parameters. 59398943Sluigi * There is a specialized check for f_tcpflags. 59498943Sluigi */ 59598943Sluigistatic void 59698943Sluigiprint_flags(char *name, ipfw_insn *cmd, struct _s_x *list) 59798943Sluigi{ 59898943Sluigi char *comma=""; 59998943Sluigi int i; 60098943Sluigi u_char set = cmd->arg1 & 0xff; 60198943Sluigi u_char clear = (cmd->arg1 >> 8) & 0xff; 60298943Sluigi 60398943Sluigi if (list == f_tcpflags && set == TH_SYN && clear == TH_ACK) { 60498943Sluigi printf(" setup"); 60598943Sluigi return; 60698943Sluigi } 60798943Sluigi 60898943Sluigi printf(" %s ", name); 60998943Sluigi for (i=0; list[i].x != 0; i++) { 61098943Sluigi if (set & list[i].x) { 61198943Sluigi set &= ~list[i].x; 61298943Sluigi printf("%s%s", comma, list[i].s); 61398943Sluigi comma = ","; 61498943Sluigi } 61598943Sluigi if (clear & list[i].x) { 61698943Sluigi clear &= ~list[i].x; 61798943Sluigi printf("%s!%s", comma, list[i].s); 61898943Sluigi comma = ","; 61998943Sluigi } 62098943Sluigi } 62198943Sluigi} 62298943Sluigi 62398943Sluigi/* 62498943Sluigi * Print the ip address contained in a command. 62598943Sluigi */ 62698943Sluigistatic void 62798943Sluigiprint_ip(ipfw_insn_ip *cmd) 62898943Sluigi{ 62998943Sluigi struct hostent *he = NULL; 63098943Sluigi int mb; 63198943Sluigi 63298943Sluigi printf("%s ", cmd->o.len & F_NOT ? " not": ""); 63398943Sluigi 63498943Sluigi if (cmd->o.opcode == O_IP_SRC_ME || cmd->o.opcode == O_IP_DST_ME) { 63598943Sluigi printf("me"); 63698943Sluigi return; 63798943Sluigi } 63898943Sluigi if (cmd->o.opcode == O_IP_SRC_SET || cmd->o.opcode == O_IP_DST_SET) { 63998943Sluigi u_int32_t x, *d; 64098943Sluigi int i; 64198943Sluigi char comma = '{'; 64298943Sluigi 64398943Sluigi x = cmd->o.arg1 - 1; 64498943Sluigi x = htonl( ~x ); 64598943Sluigi cmd->addr.s_addr = htonl(cmd->addr.s_addr); 64698943Sluigi printf("%s/%d", inet_ntoa(cmd->addr), 64798943Sluigi contigmask((u_char *)&x, 32)); 64898943Sluigi x = cmd->addr.s_addr = htonl(cmd->addr.s_addr); 64998943Sluigi x &= 0xff; /* base */ 65098943Sluigi d = (u_int32_t *)&(cmd->mask); 65198943Sluigi for (i=0; i < cmd->o.arg1; i++) 65298943Sluigi if (d[ i/32] & (1<<(i & 31))) { 65398943Sluigi printf("%c%d", comma, i+x); 65498943Sluigi comma = ','; 65598943Sluigi } 65698943Sluigi printf("}"); 65798943Sluigi return; 65898943Sluigi } 65998943Sluigi if (cmd->o.opcode == O_IP_SRC || cmd->o.opcode == O_IP_DST) 66098943Sluigi mb = 32; 66198943Sluigi else 66298943Sluigi mb = contigmask((u_char *)&(cmd->mask.s_addr), 32); 66398943Sluigi if (mb == 32 && do_resolv) 66498943Sluigi he = gethostbyaddr((char *)&(cmd->addr.s_addr), 66598943Sluigi sizeof(u_long), AF_INET); 66698943Sluigi if (he != NULL) /* resolved to name */ 66798943Sluigi printf("%s", he->h_name); 66898943Sluigi else if (mb == 0) /* any */ 66998943Sluigi printf("any"); 67098943Sluigi else { /* numeric IP followed by some kind of mask */ 67198943Sluigi printf("%s", inet_ntoa(cmd->addr)); 67298943Sluigi if (mb < 0) 67398943Sluigi printf(":%s", inet_ntoa(cmd->mask)); 67498943Sluigi else if (mb < 32) 67598943Sluigi printf("/%d", mb); 67698943Sluigi } 67798943Sluigi} 67898943Sluigi 67998943Sluigi/* 68098943Sluigi * prints a MAC address/mask pair 68198943Sluigi */ 68298943Sluigistatic void 68398943Sluigiprint_mac(u_char *addr, u_char *mask) 68498943Sluigi{ 68598943Sluigi int l = contigmask(mask, 48); 68698943Sluigi 68798943Sluigi if (l == 0) 68898943Sluigi printf(" any"); 68998943Sluigi else { 69098943Sluigi printf(" %02x:%02x:%02x:%02x:%02x:%02x", 69198943Sluigi addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); 69298943Sluigi if (l == -1) 69398943Sluigi printf("&%02x:%02x:%02x:%02x:%02x:%02x", 69498943Sluigi mask[0], mask[1], mask[2], 69598943Sluigi mask[3], mask[4], mask[5]); 69698943Sluigi else if (l < 48) 69798943Sluigi printf("/%d", l); 69898943Sluigi } 69998943Sluigi} 70098943Sluigi 70199475Sluigistatic void 70299475Sluigifill_icmptypes(ipfw_insn_u32 *cmd, char *av) 70399475Sluigi{ 70499475Sluigi u_int8_t type; 70598943Sluigi 70699475Sluigi cmd->d[0] = 0; 70799475Sluigi while (*av) { 70899475Sluigi if (*av == ',') 70999475Sluigi av++; 71099475Sluigi 71199475Sluigi type = strtoul(av, &av, 0); 71299475Sluigi 71399475Sluigi if (*av != ',' && *av != '\0') 71499475Sluigi errx(EX_DATAERR, "invalid ICMP type"); 71599475Sluigi 71699475Sluigi if (type > 31) 71799475Sluigi errx(EX_DATAERR, "ICMP type out of range"); 71899475Sluigi 71999475Sluigi cmd->d[0] |= 1 << type; 72099475Sluigi } 72199475Sluigi cmd->o.opcode = O_ICMPTYPE; 72299475Sluigi cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32); 72399475Sluigi} 72499475Sluigi 72599475Sluigistatic void 72699475Sluigiprint_icmptypes(ipfw_insn_u32 *cmd) 72799475Sluigi{ 72899475Sluigi int i; 72999475Sluigi char sep= ' '; 73099475Sluigi 73199475Sluigi printf(" icmptypes"); 73299475Sluigi for (i = 0; i < 32; i++) { 73399475Sluigi if ( (cmd->d[0] & (1 << (i))) == 0) 73499475Sluigi continue; 73599475Sluigi printf("%c%d", sep, i); 73699475Sluigi sep = ','; 73799475Sluigi } 73899475Sluigi} 73999475Sluigi 74098943Sluigi/* 74198943Sluigi * show_ipfw() prints the body of an ipfw rule. 74298943Sluigi * Because the standard rule has at least proto src_ip dst_ip, we use 74398943Sluigi * a helper function to produce these entries if not provided explicitly. 744101978Sluigi * 745101978Sluigi * Special case: if we have provided a MAC header, and no IP specs, 746101978Sluigi * just leave it alone. 747101978Sluigi * Also, if we have providea a MAC header and no IP protocol, print it 748101978Sluigi * as "all" instead of "ip". 74998943Sluigi */ 750101978Sluigi#define HAVE_PROTO 0x0001 751101978Sluigi#define HAVE_SRCIP 0x0002 752101978Sluigi#define HAVE_DSTIP 0x0004 753101978Sluigi#define HAVE_MAC 0x0008 754101978Sluigi#define HAVE_MACTYPE 0x0010 75598943Sluigi 756101978Sluigi#define HAVE_IP (HAVE_PROTO | HAVE_SRCIP | HAVE_DSTIP) 75798943Sluigistatic void 75898943Sluigishow_prerequisites(int *flags, int want) 75998943Sluigi{ 760101978Sluigi if ( (*flags & (HAVE_MAC | HAVE_MACTYPE)) == HAVE_MAC) { 761101978Sluigi printf(" any"); /* MAC type */ 762101978Sluigi *flags |= HAVE_MACTYPE; 763101978Sluigi } 764101978Sluigi 76598943Sluigi if ( !(*flags & HAVE_PROTO) && (want & HAVE_PROTO)) 766101978Sluigi printf( (*flags & HAVE_MAC) ? " all" : " ip"); 76798943Sluigi if ( !(*flags & HAVE_SRCIP) && (want & HAVE_SRCIP)) 76898943Sluigi printf(" from any"); 76998943Sluigi if ( !(*flags & HAVE_DSTIP) && (want & HAVE_DSTIP)) 77098943Sluigi printf(" to any"); 77198943Sluigi *flags |= want; 77298943Sluigi} 77398943Sluigi 77498943Sluigistatic void 77598943Sluigishow_ipfw(struct ip_fw *rule) 77698943Sluigi{ 77798943Sluigi int l; 77898943Sluigi ipfw_insn *cmd; 77998943Sluigi int proto = 0; /* default */ 78098943Sluigi int flags = 0; /* prerequisites */ 78198943Sluigi ipfw_insn_log *logptr = NULL; /* set if we find an O_LOG */ 78298943Sluigi int or_block = 0; /* we are in an or block */ 78398943Sluigi 784101628Sluigi u_int32_t set_disable = (u_int32_t)(rule->next_rule); 785101628Sluigi 786101628Sluigi if (set_disable & (1 << rule->set)) { /* disabled */ 787101628Sluigi if (!show_sets) 788101628Sluigi return; 789101628Sluigi else 790101628Sluigi printf("# DISABLED "); 791101628Sluigi } 79298943Sluigi printf("%05u ", rule->rulenum); 79398943Sluigi 79498943Sluigi if (do_acct) 79598943Sluigi printf("%10qu %10qu ", rule->pcnt, rule->bcnt); 79698943Sluigi 79798943Sluigi if (do_time) { 79898943Sluigi if (rule->timestamp) { 79998943Sluigi char timestr[30]; 80098943Sluigi time_t t = _long_to_time(rule->timestamp); 80198943Sluigi 80298943Sluigi strcpy(timestr, ctime(&t)); 80398943Sluigi *strchr(timestr, '\n') = '\0'; 80498943Sluigi printf("%s ", timestr); 80598943Sluigi } else { 80698943Sluigi printf(" "); 80798943Sluigi } 80898943Sluigi } 80998943Sluigi 810101628Sluigi if (show_sets) 811101628Sluigi printf("set %d ", rule->set); 812101628Sluigi 81398943Sluigi /* 81498943Sluigi * first print actions 81598943Sluigi */ 81698943Sluigi for (l = rule->cmd_len - rule->act_ofs, cmd = ACTION_PTR(rule); 81798943Sluigi l > 0 ; l -= F_LEN(cmd), cmd += F_LEN(cmd)) { 81898943Sluigi switch(cmd->opcode) { 81998943Sluigi case O_CHECK_STATE: 82098943Sluigi printf("check-state"); 82198943Sluigi /* avoid printing anything else */ 82298943Sluigi flags = HAVE_PROTO|HAVE_SRCIP|HAVE_DSTIP; 82398943Sluigi break; 82498943Sluigi 82598943Sluigi case O_PROB: 82698943Sluigi { 82798943Sluigi ipfw_insn_u32 *p = (ipfw_insn_u32 *)cmd; 82898943Sluigi double d = 1.0 * p->d[0]; 82998943Sluigi 83098943Sluigi d = 1 - (d / 0x7fffffff); 83198943Sluigi printf("prob %f ", d); 83298943Sluigi } 83398943Sluigi break; 83498943Sluigi 83598943Sluigi case O_ACCEPT: 83698943Sluigi printf("allow"); 83798943Sluigi break; 83898943Sluigi 83998943Sluigi case O_COUNT: 84098943Sluigi printf("count"); 84198943Sluigi break; 84298943Sluigi 84398943Sluigi case O_DENY: 84498943Sluigi printf("deny"); 84598943Sluigi break; 84698943Sluigi 84799475Sluigi case O_REJECT: 84899475Sluigi if (cmd->arg1 == ICMP_REJECT_RST) 84999475Sluigi printf("reset"); 85099475Sluigi else if (cmd->arg1 == ICMP_UNREACH_HOST) 85199475Sluigi printf("reject"); 85299475Sluigi else 85399475Sluigi print_reject_code(cmd->arg1); 85499475Sluigi break; 85599475Sluigi 85698943Sluigi case O_SKIPTO: 85798943Sluigi printf("skipto %u", cmd->arg1); 85898943Sluigi break; 85998943Sluigi 86098943Sluigi case O_PIPE: 86198943Sluigi printf("pipe %u", cmd->arg1); 86298943Sluigi break; 86398943Sluigi 86498943Sluigi case O_QUEUE: 86598943Sluigi printf("queue %u", cmd->arg1); 86698943Sluigi break; 86798943Sluigi 86898943Sluigi case O_DIVERT: 86998943Sluigi printf("divert %u", cmd->arg1); 87098943Sluigi break; 87198943Sluigi 87298943Sluigi case O_TEE: 87398943Sluigi printf("tee %u", cmd->arg1); 87498943Sluigi break; 87598943Sluigi 87698943Sluigi case O_FORWARD_IP: 87798943Sluigi { 87898943Sluigi ipfw_insn_sa *s = (ipfw_insn_sa *)cmd; 87998943Sluigi 88098943Sluigi printf("fwd %s", inet_ntoa(s->sa.sin_addr)); 88198943Sluigi if (s->sa.sin_port) 88298943Sluigi printf(",%d", ntohs(s->sa.sin_port)); 88398943Sluigi } 88498943Sluigi break; 88598943Sluigi 88698943Sluigi case O_LOG: /* O_LOG is printed last */ 88798943Sluigi logptr = (ipfw_insn_log *)cmd; 88898943Sluigi break; 88998943Sluigi 89098943Sluigi default: 89198943Sluigi printf("** unrecognized action %d len %d", 89298943Sluigi cmd->opcode, cmd->len); 89398943Sluigi } 89498943Sluigi } 89598943Sluigi if (logptr) { 89698943Sluigi if (logptr->max_log > 0) 89799909Sluigi printf(" log logamount %d", logptr->max_log); 89898943Sluigi else 89999909Sluigi printf(" log"); 90098943Sluigi } 90198943Sluigi /* 90298943Sluigi * then print the body 90398943Sluigi */ 90498943Sluigi for (l = rule->act_ofs, cmd = rule->cmd ; 90598943Sluigi l > 0 ; l -= F_LEN(cmd) , cmd += F_LEN(cmd)) { 90699475Sluigi /* useful alias */ 90799475Sluigi ipfw_insn_u32 *cmd32 = (ipfw_insn_u32 *)cmd; 90898943Sluigi 90998943Sluigi switch(cmd->opcode) { 91098943Sluigi case O_PROBE_STATE: 91198943Sluigi break; /* no need to print anything here */ 91298943Sluigi 91398943Sluigi case O_MACADDR2: { 91498943Sluigi ipfw_insn_mac *m = (ipfw_insn_mac *)cmd; 91598943Sluigi if ( (flags & HAVE_MAC) == 0) 91698943Sluigi printf(" MAC"); 91798943Sluigi flags |= HAVE_MAC; 91898943Sluigi if (cmd->len & F_NOT) 91998943Sluigi printf(" not"); 92098943Sluigi print_mac( m->addr, m->mask); 92198943Sluigi print_mac( m->addr + 6, m->mask + 6); 92298943Sluigi } 92398943Sluigi break; 92498943Sluigi 92598943Sluigi case O_MAC_TYPE: 926101978Sluigi if ( (flags & HAVE_MAC) == 0) 927101978Sluigi printf(" MAC"); 928101978Sluigi flags |= (HAVE_MAC | HAVE_MACTYPE); 92998943Sluigi print_newports((ipfw_insn_u16 *)cmd, IPPROTO_ETHERTYPE); 93098943Sluigi break; 93198943Sluigi 93298943Sluigi case O_IP_SRC: 93398943Sluigi case O_IP_SRC_MASK: 93498943Sluigi case O_IP_SRC_ME: 93598943Sluigi case O_IP_SRC_SET: 93698943Sluigi show_prerequisites(&flags, HAVE_PROTO); 93798943Sluigi if (!(flags & HAVE_SRCIP)) 93898943Sluigi printf(" from"); 93998943Sluigi if ((cmd->len & F_OR) && !or_block) 94098943Sluigi printf(" {"); 94198943Sluigi print_ip((ipfw_insn_ip *)cmd); 94298943Sluigi flags |= HAVE_SRCIP; 94398943Sluigi break; 94498943Sluigi 94598943Sluigi case O_IP_DST: 94698943Sluigi case O_IP_DST_MASK: 94798943Sluigi case O_IP_DST_ME: 94898943Sluigi case O_IP_DST_SET: 94998943Sluigi show_prerequisites(&flags, HAVE_PROTO|HAVE_SRCIP); 95098943Sluigi if (!(flags & HAVE_DSTIP)) 95198943Sluigi printf(" to"); 95298943Sluigi if ((cmd->len & F_OR) && !or_block) 95398943Sluigi printf(" {"); 95498943Sluigi print_ip((ipfw_insn_ip *)cmd); 95598943Sluigi flags |= HAVE_DSTIP; 95698943Sluigi break; 95798943Sluigi 95898943Sluigi case O_IP_DSTPORT: 95998943Sluigi show_prerequisites(&flags, 96098943Sluigi HAVE_PROTO|HAVE_SRCIP|HAVE_DSTIP); 96198943Sluigi case O_IP_SRCPORT: 96298943Sluigi show_prerequisites(&flags, HAVE_PROTO|HAVE_SRCIP); 963101641Sluigi if ((cmd->len & F_OR) && !or_block) 964101641Sluigi printf(" {"); 96598943Sluigi print_newports((ipfw_insn_u16 *)cmd, proto); 96698943Sluigi break; 96798943Sluigi 96898943Sluigi case O_PROTO: { 96998943Sluigi struct protoent *pe; 97098943Sluigi 97198943Sluigi if ((cmd->len & F_OR) && !or_block) 97298943Sluigi printf(" {"); 97398943Sluigi if (cmd->len & F_NOT) 97498943Sluigi printf(" not"); 97598943Sluigi proto = cmd->arg1; 97698943Sluigi pe = getprotobynumber(cmd->arg1); 97798943Sluigi if (pe) 97898943Sluigi printf(" %s", pe->p_name); 97998943Sluigi else 98098943Sluigi printf(" %u", cmd->arg1); 98198943Sluigi } 98298943Sluigi flags |= HAVE_PROTO; 98398943Sluigi break; 98498943Sluigi 98598943Sluigi default: /*options ... */ 98698943Sluigi show_prerequisites(&flags, 98798943Sluigi HAVE_PROTO|HAVE_SRCIP|HAVE_DSTIP); 98898943Sluigi if ((cmd->len & F_OR) && !or_block) 98998943Sluigi printf(" {"); 99098943Sluigi if (cmd->len & F_NOT && cmd->opcode != O_IN) 99198943Sluigi printf(" not"); 99298943Sluigi switch(cmd->opcode) { 99398943Sluigi case O_FRAG: 99498943Sluigi printf(" frag"); 99598943Sluigi break; 99698943Sluigi 99798943Sluigi case O_IN: 99898943Sluigi printf(cmd->len & F_NOT ? " out" : " in"); 99998943Sluigi break; 100098943Sluigi 100198943Sluigi case O_LAYER2: 100298943Sluigi printf(" layer2"); 100398943Sluigi break; 100498943Sluigi case O_XMIT: 100598943Sluigi case O_RECV: 100698943Sluigi case O_VIA: { 100798943Sluigi char *s; 100898943Sluigi ipfw_insn_if *cmdif = (ipfw_insn_if *)cmd; 100998943Sluigi 101098943Sluigi if (cmd->opcode == O_XMIT) 101198943Sluigi s = "xmit"; 101298943Sluigi else if (cmd->opcode == O_RECV) 101398943Sluigi s = "recv"; 101498943Sluigi else if (cmd->opcode == O_VIA) 101598943Sluigi s = "via"; 101698943Sluigi if (cmdif->name[0] == '\0') 101799475Sluigi printf(" %s %s", s, 101899475Sluigi inet_ntoa(cmdif->p.ip)); 101998943Sluigi else if (cmdif->p.unit == -1) 102098943Sluigi printf(" %s %s*", s, cmdif->name); 102198943Sluigi else 102299475Sluigi printf(" %s %s%d", s, cmdif->name, 102399475Sluigi cmdif->p.unit); 102498943Sluigi } 102598943Sluigi break; 102698943Sluigi 102798943Sluigi case O_IPID: 102898943Sluigi printf(" ipid %u", cmd->arg1 ); 102998943Sluigi break; 103098943Sluigi 103198943Sluigi case O_IPTTL: 103298943Sluigi printf(" ipttl %u", cmd->arg1 ); 103398943Sluigi break; 103498943Sluigi 103598943Sluigi case O_IPVER: 103698943Sluigi printf(" ipver %u", cmd->arg1 ); 103798943Sluigi break; 103898943Sluigi 103999475Sluigi case O_IPPRECEDENCE: 104099475Sluigi printf(" ipprecedence %u", (cmd->arg1) >> 5 ); 104199475Sluigi break; 104299475Sluigi 104398943Sluigi case O_IPLEN: 104498943Sluigi printf(" iplen %u", cmd->arg1 ); 104598943Sluigi break; 104698943Sluigi 1047101116Sluigi case O_IPOPT: 104898943Sluigi print_flags("ipoptions", cmd, f_ipopts); 104998943Sluigi break; 105098943Sluigi 105199475Sluigi case O_IPTOS: 105299475Sluigi print_flags("iptos", cmd, f_iptos); 105399475Sluigi break; 105499475Sluigi 105599475Sluigi case O_ICMPTYPE: 105699475Sluigi print_icmptypes((ipfw_insn_u32 *)cmd); 105799475Sluigi break; 105899475Sluigi 105998943Sluigi case O_ESTAB: 106098943Sluigi printf(" established"); 106198943Sluigi break; 106298943Sluigi 106398943Sluigi case O_TCPFLAGS: 106498943Sluigi print_flags("tcpflags", cmd, f_tcpflags); 106598943Sluigi break; 106698943Sluigi 106798943Sluigi case O_TCPOPTS: 106898943Sluigi print_flags("tcpoptions", cmd, f_tcpopts); 106998943Sluigi break; 107098943Sluigi 107198943Sluigi case O_TCPWIN: 107298943Sluigi printf(" tcpwin %d", ntohs(cmd->arg1)); 107398943Sluigi break; 107498943Sluigi 107598943Sluigi case O_TCPACK: 107698943Sluigi printf(" tcpack %d", ntohl(cmd32->d[0])); 107798943Sluigi break; 107898943Sluigi 107998943Sluigi case O_TCPSEQ: 108098943Sluigi printf(" tcpseq %d", ntohl(cmd32->d[0])); 108198943Sluigi break; 108298943Sluigi 108398943Sluigi case O_UID: 108498943Sluigi { 108598943Sluigi struct passwd *pwd = getpwuid(cmd32->d[0]); 108698943Sluigi 108798943Sluigi if (pwd) 108898943Sluigi printf(" uid %s", pwd->pw_name); 108998943Sluigi else 109098943Sluigi printf(" uid %u", cmd32->d[0]); 109198943Sluigi } 109298943Sluigi break; 109398943Sluigi 109498943Sluigi case O_GID: 109598943Sluigi { 109698943Sluigi struct group *grp = getgrgid(cmd32->d[0]); 109798943Sluigi 109898943Sluigi if (grp) 109998943Sluigi printf(" gid %s", grp->gr_name); 110098943Sluigi else 110198943Sluigi printf(" gid %u", cmd32->d[0]); 110298943Sluigi } 110398943Sluigi break; 110498943Sluigi 110598943Sluigi case O_KEEP_STATE: 110698943Sluigi printf(" keep-state"); 110798943Sluigi break; 110898943Sluigi 110998943Sluigi case O_LIMIT: 111098943Sluigi { 111198943Sluigi struct _s_x *p = limit_masks; 111298943Sluigi ipfw_insn_limit *c = (ipfw_insn_limit *)cmd; 111398943Sluigi u_int8_t x = c->limit_mask; 111498943Sluigi char *comma = " "; 111598943Sluigi 111698943Sluigi printf(" limit"); 111798943Sluigi for ( ; p->x != 0 ; p++) 111899909Sluigi if ((x & p->x) == p->x) { 111998943Sluigi x &= ~p->x; 112098943Sluigi printf("%s%s", comma, p->s); 112198943Sluigi comma = ","; 112298943Sluigi } 112398943Sluigi printf(" %d", c->conn_limit); 112498943Sluigi } 112598943Sluigi break; 112698943Sluigi 112798943Sluigi default: 112898943Sluigi printf(" [opcode %d len %d]", 112998943Sluigi cmd->opcode, cmd->len); 113098943Sluigi } 113198943Sluigi } 113298943Sluigi if (cmd->len & F_OR) { 113398943Sluigi printf(" or"); 113498943Sluigi or_block = 1; 113598943Sluigi } else if (or_block) { 113698943Sluigi printf(" }"); 113798943Sluigi or_block = 0; 113898943Sluigi } 113998943Sluigi } 114098943Sluigi show_prerequisites(&flags, HAVE_PROTO|HAVE_SRCIP|HAVE_DSTIP); 114198943Sluigi 114298943Sluigi printf("\n"); 114398943Sluigi} 114498943Sluigi 114598943Sluigistatic void 114698943Sluigishow_dyn_ipfw(ipfw_dyn_rule *d) 114798943Sluigi{ 114898943Sluigi struct protoent *pe; 114998943Sluigi struct in_addr a; 115098943Sluigi 115198943Sluigi if (!do_expired) { 115298943Sluigi if (!d->expire && !(d->dyn_type == O_LIMIT_PARENT)) 115398943Sluigi return; 115498943Sluigi } 115598943Sluigi 115698943Sluigi printf("%05d %10qu %10qu (%ds)", 115798943Sluigi (int)(d->rule), d->pcnt, d->bcnt, d->expire); 115898943Sluigi switch (d->dyn_type) { 115998943Sluigi case O_LIMIT_PARENT: 116098943Sluigi printf(" PARENT %d", d->count); 116198943Sluigi break; 116298943Sluigi case O_LIMIT: 116398943Sluigi printf(" LIMIT"); 116498943Sluigi break; 116598943Sluigi case O_KEEP_STATE: /* bidir, no mask */ 116698943Sluigi printf(" STATE"); 116798943Sluigi break; 116898943Sluigi } 116998943Sluigi 117098943Sluigi if ((pe = getprotobynumber(d->id.proto)) != NULL) 117198943Sluigi printf(" %s", pe->p_name); 117298943Sluigi else 117398943Sluigi printf(" proto %u", d->id.proto); 117498943Sluigi 117598943Sluigi a.s_addr = htonl(d->id.src_ip); 117698943Sluigi printf(" %s %d", inet_ntoa(a), d->id.src_port); 117798943Sluigi 117898943Sluigi a.s_addr = htonl(d->id.dst_ip); 117998943Sluigi printf(" <-> %s %d", inet_ntoa(a), d->id.dst_port); 118098943Sluigi printf("\n"); 118198943Sluigi} 118298943Sluigi 118398943Sluigiint 118498943Sluigisort_q(const void *pa, const void *pb) 118598943Sluigi{ 118698943Sluigi int rev = (do_sort < 0); 118798943Sluigi int field = rev ? -do_sort : do_sort; 118898943Sluigi long long res = 0; 118998943Sluigi const struct dn_flow_queue *a = pa; 119098943Sluigi const struct dn_flow_queue *b = pb; 119198943Sluigi 119298943Sluigi switch (field) { 119398943Sluigi case 1: /* pkts */ 119498943Sluigi res = a->len - b->len; 119598943Sluigi break; 119698943Sluigi case 2: /* bytes */ 119798943Sluigi res = a->len_bytes - b->len_bytes; 119898943Sluigi break; 119998943Sluigi 120098943Sluigi case 3: /* tot pkts */ 120198943Sluigi res = a->tot_pkts - b->tot_pkts; 120298943Sluigi break; 120398943Sluigi 120498943Sluigi case 4: /* tot bytes */ 120598943Sluigi res = a->tot_bytes - b->tot_bytes; 120698943Sluigi break; 120798943Sluigi } 120898943Sluigi if (res < 0) 120998943Sluigi res = -1; 121098943Sluigi if (res > 0) 121198943Sluigi res = 1; 121298943Sluigi return (int)(rev ? res : -res); 121398943Sluigi} 121498943Sluigi 121598943Sluigistatic void 121698943Sluigilist_queues(struct dn_flow_set *fs, struct dn_flow_queue *q) 121798943Sluigi{ 121898943Sluigi int l; 121998943Sluigi 122098943Sluigi printf(" mask: 0x%02x 0x%08x/0x%04x -> 0x%08x/0x%04x\n", 122198943Sluigi fs->flow_mask.proto, 122298943Sluigi fs->flow_mask.src_ip, fs->flow_mask.src_port, 122398943Sluigi fs->flow_mask.dst_ip, fs->flow_mask.dst_port); 122498943Sluigi if (fs->rq_elements == 0) 122598943Sluigi return; 122698943Sluigi 122798943Sluigi printf("BKT Prot ___Source IP/port____ " 122898943Sluigi "____Dest. IP/port____ Tot_pkt/bytes Pkt/Byte Drp\n"); 122998943Sluigi if (do_sort != 0) 123098943Sluigi heapsort(q, fs->rq_elements, sizeof *q, sort_q); 123198943Sluigi for (l = 0; l < fs->rq_elements; l++) { 123298943Sluigi struct in_addr ina; 123398943Sluigi struct protoent *pe; 123498943Sluigi 123598943Sluigi ina.s_addr = htonl(q[l].id.src_ip); 123698943Sluigi printf("%3d ", q[l].hash_slot); 123798943Sluigi pe = getprotobynumber(q[l].id.proto); 123898943Sluigi if (pe) 123998943Sluigi printf("%-4s ", pe->p_name); 124098943Sluigi else 124198943Sluigi printf("%4u ", q[l].id.proto); 124298943Sluigi printf("%15s/%-5d ", 124398943Sluigi inet_ntoa(ina), q[l].id.src_port); 124498943Sluigi ina.s_addr = htonl(q[l].id.dst_ip); 124598943Sluigi printf("%15s/%-5d ", 124698943Sluigi inet_ntoa(ina), q[l].id.dst_port); 124798943Sluigi printf("%4qu %8qu %2u %4u %3u\n", 124898943Sluigi q[l].tot_pkts, q[l].tot_bytes, 124998943Sluigi q[l].len, q[l].len_bytes, q[l].drops); 125098943Sluigi if (verbose) 125198943Sluigi printf(" S %20qd F %20qd\n", 125298943Sluigi q[l].S, q[l].F); 125398943Sluigi } 125498943Sluigi} 125598943Sluigi 125698943Sluigistatic void 125798943Sluigiprint_flowset_parms(struct dn_flow_set *fs, char *prefix) 125898943Sluigi{ 125998943Sluigi int l; 126098943Sluigi char qs[30]; 126198943Sluigi char plr[30]; 126298943Sluigi char red[90]; /* Display RED parameters */ 126398943Sluigi 126498943Sluigi l = fs->qsize; 126598943Sluigi if (fs->flags_fs & DN_QSIZE_IS_BYTES) { 126698943Sluigi if (l >= 8192) 126798943Sluigi sprintf(qs, "%d KB", l / 1024); 126898943Sluigi else 126998943Sluigi sprintf(qs, "%d B", l); 127098943Sluigi } else 127198943Sluigi sprintf(qs, "%3d sl.", l); 127298943Sluigi if (fs->plr) 127398943Sluigi sprintf(plr, "plr %f", 1.0 * fs->plr / (double)(0x7fffffff)); 127498943Sluigi else 127598943Sluigi plr[0] = '\0'; 127698943Sluigi if (fs->flags_fs & DN_IS_RED) /* RED parameters */ 127798943Sluigi sprintf(red, 127898943Sluigi "\n\t %cRED w_q %f min_th %d max_th %d max_p %f", 127998943Sluigi (fs->flags_fs & DN_IS_GENTLE_RED) ? 'G' : ' ', 128098943Sluigi 1.0 * fs->w_q / (double)(1 << SCALE_RED), 128198943Sluigi SCALE_VAL(fs->min_th), 128298943Sluigi SCALE_VAL(fs->max_th), 128398943Sluigi 1.0 * fs->max_p / (double)(1 << SCALE_RED)); 128498943Sluigi else 128598943Sluigi sprintf(red, "droptail"); 128698943Sluigi 128798943Sluigi printf("%s %s%s %d queues (%d buckets) %s\n", 128898943Sluigi prefix, qs, plr, fs->rq_elements, fs->rq_size, red); 128998943Sluigi} 129098943Sluigi 129198943Sluigistatic void 129298943Sluigilist_pipes(void *data, int nbytes, int ac, char *av[]) 129398943Sluigi{ 129498943Sluigi u_long rulenum; 129598943Sluigi void *next = data; 129698943Sluigi struct dn_pipe *p = (struct dn_pipe *) data; 129798943Sluigi struct dn_flow_set *fs; 129898943Sluigi struct dn_flow_queue *q; 129998943Sluigi int l; 130098943Sluigi 130198943Sluigi if (ac > 0) 130298943Sluigi rulenum = strtoul(*av++, NULL, 10); 130398943Sluigi else 130498943Sluigi rulenum = 0; 130598943Sluigi for (; nbytes >= sizeof *p; p = (struct dn_pipe *)next) { 130698943Sluigi double b = p->bandwidth; 130798943Sluigi char buf[30]; 130898943Sluigi char prefix[80]; 130998943Sluigi 131098943Sluigi if (p->next != (struct dn_pipe *)DN_IS_PIPE) 131198943Sluigi break; /* done with pipes, now queues */ 131298943Sluigi 131398943Sluigi /* 131498943Sluigi * compute length, as pipe have variable size 131598943Sluigi */ 131698943Sluigi l = sizeof(*p) + p->fs.rq_elements * sizeof(*q); 131798943Sluigi next = (void *)p + l; 131898943Sluigi nbytes -= l; 131998943Sluigi 132098943Sluigi if (rulenum != 0 && rulenum != p->pipe_nr) 132198943Sluigi continue; 132298943Sluigi 132398943Sluigi /* 132498943Sluigi * Print rate (or clocking interface) 132598943Sluigi */ 132698943Sluigi if (p->if_name[0] != '\0') 132798943Sluigi sprintf(buf, "%s", p->if_name); 132898943Sluigi else if (b == 0) 132998943Sluigi sprintf(buf, "unlimited"); 133098943Sluigi else if (b >= 1000000) 133198943Sluigi sprintf(buf, "%7.3f Mbit/s", b/1000000); 133298943Sluigi else if (b >= 1000) 133398943Sluigi sprintf(buf, "%7.3f Kbit/s", b/1000); 133498943Sluigi else 133598943Sluigi sprintf(buf, "%7.3f bit/s ", b); 133698943Sluigi 133798943Sluigi sprintf(prefix, "%05d: %s %4d ms ", 133898943Sluigi p->pipe_nr, buf, p->delay); 133998943Sluigi print_flowset_parms(&(p->fs), prefix); 134098943Sluigi if (verbose) 134198943Sluigi printf(" V %20qd\n", p->V >> MY_M); 134298943Sluigi 134398943Sluigi q = (struct dn_flow_queue *)(p+1); 134498943Sluigi list_queues(&(p->fs), q); 134598943Sluigi } 134698943Sluigi for (fs = next; nbytes >= sizeof *fs; fs = next) { 134798943Sluigi char prefix[80]; 134898943Sluigi 134998943Sluigi if (fs->next != (struct dn_flow_set *)DN_IS_QUEUE) 135098943Sluigi break; 135198943Sluigi l = sizeof(*fs) + fs->rq_elements * sizeof(*q); 135298943Sluigi next = (void *)fs + l; 135398943Sluigi nbytes -= l; 135498943Sluigi q = (struct dn_flow_queue *)(fs+1); 135598943Sluigi sprintf(prefix, "q%05d: weight %d pipe %d ", 135698943Sluigi fs->fs_nr, fs->weight, fs->parent_nr); 135798943Sluigi print_flowset_parms(fs, prefix); 135898943Sluigi list_queues(fs, q); 135998943Sluigi } 136098943Sluigi} 136198943Sluigi 1362101978Sluigi/* 1363101978Sluigi * This one handles all set-related commands 1364101978Sluigi * ipfw set { show | enable | disable } 1365101978Sluigi * ipfw set swap X Y 1366101978Sluigi * ipfw set move X to Y 1367101978Sluigi * ipfw set move rule X to Y 1368101978Sluigi */ 136998943Sluigistatic void 1370101978Sluigisets_handler(int ac, char *av[]) 1371101978Sluigi{ 1372101978Sluigi u_int32_t set_disable, masks[2]; 1373101978Sluigi int i, nbytes; 1374101978Sluigi u_int16_t rulenum; 1375101978Sluigi u_int8_t cmd, new_set; 1376101978Sluigi 1377101978Sluigi ac--; 1378101978Sluigi av++; 1379101978Sluigi 1380101978Sluigi if (!ac) 1381101978Sluigi errx(EX_USAGE, "set needs command"); 1382101978Sluigi if (!strncmp(*av, "show", strlen(*av)) ) { 1383101978Sluigi void *data; 1384101978Sluigi char *msg; 1385101978Sluigi 1386101978Sluigi nbytes = sizeof(struct ip_fw); 1387101978Sluigi if ((data = malloc(nbytes)) == NULL) 1388101978Sluigi err(EX_OSERR, "malloc"); 1389101978Sluigi if (getsockopt(s, IPPROTO_IP, IP_FW_GET, data, &nbytes) < 0) 1390101978Sluigi err(EX_OSERR, "getsockopt(IP_FW_GET)"); 1391101978Sluigi set_disable = (u_int32_t)(((struct ip_fw *)data)->next_rule); 1392101978Sluigi 1393101978Sluigi for (i = 0, msg = "disable" ; i < 31; i++) 1394101978Sluigi if ( (set_disable & (1<<i))) { 1395101978Sluigi printf("%s %d", msg, i); 1396101978Sluigi msg = ""; 1397101978Sluigi } 1398101978Sluigi msg = (set_disable) ? " enable" : "enable"; 1399101978Sluigi for (i = 0; i < 31; i++) 1400101978Sluigi if ( !(set_disable & (1<<i))) { 1401101978Sluigi printf("%s %d", msg, i); 1402101978Sluigi msg = ""; 1403101978Sluigi } 1404101978Sluigi printf("\n"); 1405101978Sluigi } else if (!strncmp(*av, "swap", strlen(*av))) { 1406101978Sluigi ac--; av++; 1407101978Sluigi if (ac != 2) 1408101978Sluigi errx(EX_USAGE, "set swap needs 2 set numbers\n"); 1409101978Sluigi rulenum = atoi(av[0]); 1410101978Sluigi new_set = atoi(av[1]); 1411101978Sluigi if (!isdigit(*(av[0])) || rulenum > 30) 1412101978Sluigi errx(EX_DATAERR, "invalid set number %s\n", av[0]); 1413101978Sluigi if (!isdigit(*(av[1])) || new_set > 30) 1414101978Sluigi errx(EX_DATAERR, "invalid set number %s\n", av[1]); 1415101978Sluigi masks[0] = (4 << 24) | (new_set << 16) | (rulenum); 1416101978Sluigi i = setsockopt(s, IPPROTO_IP, IP_FW_DEL, 1417101978Sluigi masks, sizeof(u_int32_t)); 1418101978Sluigi } else if (!strncmp(*av, "move", strlen(*av))) { 1419101978Sluigi ac--; av++; 1420101978Sluigi if (ac && !strncmp(*av, "rule", strlen(*av))) { 1421101978Sluigi cmd = 2; 1422101978Sluigi ac--; av++; 1423101978Sluigi } else 1424101978Sluigi cmd = 3; 1425101978Sluigi if (ac != 3 || strncmp(av[1], "to", strlen(*av))) 1426101978Sluigi errx(EX_USAGE, "syntax: set move [rule] X to Y\n"); 1427101978Sluigi rulenum = atoi(av[0]); 1428101978Sluigi new_set = atoi(av[2]); 1429101978Sluigi if (!isdigit(*(av[0])) || (cmd == 3 && rulenum > 30) || 1430101978Sluigi (cmd == 2 && rulenum == 65535) ) 1431101978Sluigi errx(EX_DATAERR, "invalid source number %s\n", av[0]); 1432101978Sluigi if (!isdigit(*(av[2])) || new_set > 30) 1433101978Sluigi errx(EX_DATAERR, "invalid dest. set %s\n", av[1]); 1434101978Sluigi masks[0] = (cmd << 24) | (new_set << 16) | (rulenum); 1435101978Sluigi i = setsockopt(s, IPPROTO_IP, IP_FW_DEL, 1436101978Sluigi masks, sizeof(u_int32_t)); 1437101978Sluigi } else if (!strncmp(*av, "disable", strlen(*av)) || 1438101978Sluigi !strncmp(*av, "enable", strlen(*av)) ) { 1439101978Sluigi int which = !strncmp(*av, "enable", strlen(*av)) ? 1 : 0; 1440101978Sluigi 1441101978Sluigi ac--; av++; 1442101978Sluigi masks[0] = masks[1] = 0; 1443101978Sluigi 1444101978Sluigi while (ac) { 1445101978Sluigi if (isdigit(**av)) { 1446101978Sluigi i = atoi(*av); 1447101978Sluigi if (i < 0 || i > 30) 1448101978Sluigi errx(EX_DATAERR, 1449101978Sluigi "invalid set number %d\n", i); 1450101978Sluigi masks[which] |= (1<<i); 1451101978Sluigi } else if (!strncmp(*av, "disable", strlen(*av))) 1452101978Sluigi which = 0; 1453101978Sluigi else if (!strncmp(*av, "enable", strlen(*av))) 1454101978Sluigi which = 1; 1455101978Sluigi else 1456101978Sluigi errx(EX_DATAERR, 1457101978Sluigi "invalid set command %s\n", *av); 1458101978Sluigi av++; ac--; 1459101978Sluigi } 1460101978Sluigi if ( (masks[0] & masks[1]) != 0 ) 1461101978Sluigi errx(EX_DATAERR, 1462101978Sluigi "cannot enable and disable the same set\n"); 1463101978Sluigi 1464101978Sluigi i = setsockopt(s, IPPROTO_IP, IP_FW_DEL, masks, sizeof(masks)); 1465101978Sluigi if (i) 1466101978Sluigi warn("set enable/disable: setsockopt(IP_FW_DEL)"); 1467101978Sluigi } else 1468101978Sluigi errx(EX_USAGE, "invalid set command %s\n", *av); 1469101978Sluigi} 1470101978Sluigi 1471101978Sluigistatic void 147298943Sluigilist(int ac, char *av[]) 147398943Sluigi{ 147498943Sluigi struct ip_fw *r; 147598943Sluigi ipfw_dyn_rule *dynrules, *d; 147698943Sluigi 147798943Sluigi void *lim, *data = NULL; 147898943Sluigi int n, nbytes, nstat, ndyn; 147998943Sluigi int exitval = EX_OK; 148098943Sluigi int lac; 148198943Sluigi char **lav; 148298943Sluigi u_long rnum; 148398943Sluigi char *endptr; 148498943Sluigi int seen = 0; 148598943Sluigi 148698943Sluigi const int ocmd = do_pipe ? IP_DUMMYNET_GET : IP_FW_GET; 148798943Sluigi int nalloc = 1024; /* start somewhere... */ 148898943Sluigi 148998943Sluigi ac--; 149098943Sluigi av++; 149198943Sluigi 149298943Sluigi /* get rules or pipes from kernel, resizing array as necessary */ 149398943Sluigi nbytes = nalloc; 149498943Sluigi 149598943Sluigi while (nbytes >= nalloc) { 149698943Sluigi nalloc = nalloc * 2 + 200; 149798943Sluigi nbytes = nalloc; 149898943Sluigi if ((data = realloc(data, nbytes)) == NULL) 149998943Sluigi err(EX_OSERR, "realloc"); 150098943Sluigi if (getsockopt(s, IPPROTO_IP, ocmd, data, &nbytes) < 0) 150198943Sluigi err(EX_OSERR, "getsockopt(IP_%s_GET)", 150298943Sluigi do_pipe ? "DUMMYNET" : "FW"); 150398943Sluigi } 150498943Sluigi 150598943Sluigi if (do_pipe) { 150698943Sluigi list_pipes(data, nbytes, ac, av); 150798943Sluigi goto done; 150898943Sluigi } 150998943Sluigi 151098943Sluigi /* 151198943Sluigi * Count static rules. They have variable size so we 151298943Sluigi * need to scan the list to count them. 151398943Sluigi */ 151498943Sluigi for (nstat = 1, r = data, lim = data + nbytes; 151598943Sluigi r->rulenum < 65535 && (void *)r < lim; 151698943Sluigi ++nstat, r = (void *)r + RULESIZE(r) ) 151798943Sluigi ; /* nothing */ 151898943Sluigi 151998943Sluigi /* 152098943Sluigi * Count dynamic rules. This is easier as they have 152198943Sluigi * fixed size. 152298943Sluigi */ 152398943Sluigi r = (void *)r + RULESIZE(r); 152498943Sluigi dynrules = (ipfw_dyn_rule *)r ; 152598943Sluigi n = (void *)r - data; 152698943Sluigi ndyn = (nbytes - n) / sizeof *dynrules; 152798943Sluigi 152898943Sluigi /* if no rule numbers were specified, list all rules */ 152998943Sluigi if (ac == 0) { 153098943Sluigi for (n = 0, r = data; n < nstat; 153198943Sluigi n++, r = (void *)r + RULESIZE(r) ) 153298943Sluigi show_ipfw(r); 153398943Sluigi 153498943Sluigi if (do_dynamic && ndyn) { 153598943Sluigi printf("## Dynamic rules (%d):\n", ndyn); 153698943Sluigi for (n = 0, d = dynrules; n < ndyn; n++, d++) 153798943Sluigi show_dyn_ipfw(d); 153898943Sluigi } 153998943Sluigi goto done; 154098943Sluigi } 154198943Sluigi 154298943Sluigi /* display specific rules requested on command line */ 154398943Sluigi 154498943Sluigi for (lac = ac, lav = av; lac != 0; lac--) { 154598943Sluigi /* convert command line rule # */ 154698943Sluigi rnum = strtoul(*lav++, &endptr, 10); 154798943Sluigi if (*endptr) { 154898943Sluigi exitval = EX_USAGE; 154998943Sluigi warnx("invalid rule number: %s", *(lav - 1)); 155098943Sluigi continue; 155198943Sluigi } 155298943Sluigi for (n = seen = 0, r = data; n < nstat; 155398943Sluigi n++, r = (void *)r + RULESIZE(r) ) { 155498943Sluigi if (r->rulenum > rnum) 155598943Sluigi break; 155698943Sluigi if (r->rulenum == rnum) { 155798943Sluigi show_ipfw(r); 155898943Sluigi seen = 1; 155998943Sluigi } 156098943Sluigi } 156198943Sluigi if (!seen) { 156298943Sluigi /* give precedence to other error(s) */ 156398943Sluigi if (exitval == EX_OK) 156498943Sluigi exitval = EX_UNAVAILABLE; 156598943Sluigi warnx("rule %lu does not exist", rnum); 156698943Sluigi } 156798943Sluigi } 156898943Sluigi 156998943Sluigi if (do_dynamic && ndyn) { 157098943Sluigi printf("## Dynamic rules:\n"); 157198943Sluigi for (lac = ac, lav = av; lac != 0; lac--) { 157298943Sluigi rnum = strtoul(*lav++, &endptr, 10); 157398943Sluigi if (*endptr) 157498943Sluigi /* already warned */ 157598943Sluigi continue; 157698943Sluigi for (n = 0, d = dynrules; n < ndyn; n++, d++) { 157798943Sluigi if ((int)(d->rule) > rnum) 157898943Sluigi break; 157998943Sluigi if ((int)(d->rule) == rnum) 158098943Sluigi show_dyn_ipfw(d); 158198943Sluigi } 158298943Sluigi } 158398943Sluigi } 158498943Sluigi 158598943Sluigi ac = 0; 158698943Sluigi 158798943Sluigidone: 158898943Sluigi free(data); 158998943Sluigi 159098943Sluigi if (exitval != EX_OK) 159198943Sluigi exit(exitval); 159298943Sluigi} 159398943Sluigi 159498943Sluigistatic void 159598943Sluigishow_usage(void) 159698943Sluigi{ 159798943Sluigi fprintf(stderr, "usage: ipfw [options]\n" 159898943Sluigi" add [number] rule\n" 159998943Sluigi" pipe number config [pipeconfig]\n" 160098943Sluigi" queue number config [queueconfig]\n" 160198943Sluigi" [pipe] flush\n" 160298943Sluigi" [pipe] delete number ...\n" 160398943Sluigi" [pipe] {list|show} [number ...]\n" 160498943Sluigi" {zero|resetlog} [number ...]\n" 160598943Sluigi"do \"ipfw -h\" or see ipfw manpage for details\n" 160698943Sluigi); 160798943Sluigi 160898943Sluigi exit(EX_USAGE); 160998943Sluigi} 161098943Sluigi 161198943Sluigistatic void 161298943Sluigihelp(void) 161398943Sluigi{ 161498943Sluigi 161598943Sluigi fprintf(stderr, "ipfw syntax summary:\n" 161698943Sluigi"ipfw add [N] [prob {0..1}] ACTION [log [logamount N]] ADDR OPTIONS\n" 161798943Sluigi"ipfw {pipe|queue} N config BODY\n" 161898943Sluigi"ipfw [pipe] {zero|delete|show} [N{,N}]\n" 161998943Sluigi"\n" 162098943Sluigi"RULE: [1..] [PROB] BODY\n" 162198943Sluigi"RULENUM: INTEGER(1..65534)\n" 162298943Sluigi"PROB: prob REAL(0..1)\n" 162398943Sluigi"BODY: check-state [LOG] (no body) |\n" 162498943Sluigi" ACTION [LOG] MATCH_ADDR [OPTION_LIST]\n" 162598943Sluigi"ACTION: check-state | allow | count | deny | reject | skipto N |\n" 162698943Sluigi" {divert|tee} PORT | forward ADDR | pipe N | queue N\n" 162798943Sluigi"ADDR: [ MAC dst src ether_type ] \n" 162898943Sluigi" [ from IPLIST [ PORT ] to IPLIST [ PORTLIST ] ]\n" 162998943Sluigi"IPLIST: IPADDR | ( IPADDR or ... or IPADDR )\n" 163098943Sluigi"IPADDR: [not] { any | me | ip | ip/bits | ip:mask | ip/bits{x,y,z} }\n" 163198943Sluigi"OPTION_LIST: OPTION [,OPTION_LIST]\n" 163298943Sluigi); 163398943Sluigiexit(0); 163498943Sluigi} 163598943Sluigi 163698943Sluigi 163798943Sluigistatic int 163898943Sluigilookup_host (char *host, struct in_addr *ipaddr) 163998943Sluigi{ 164098943Sluigi struct hostent *he; 164198943Sluigi 164298943Sluigi if (!inet_aton(host, ipaddr)) { 164398943Sluigi if ((he = gethostbyname(host)) == NULL) 164498943Sluigi return(-1); 164598943Sluigi *ipaddr = *(struct in_addr *)he->h_addr_list[0]; 164698943Sluigi } 164798943Sluigi return(0); 164898943Sluigi} 164998943Sluigi 165098943Sluigi/* 165198943Sluigi * fills the addr and mask fields in the instruction as appropriate from av. 165298943Sluigi * Update length as appropriate. 165398943Sluigi * The following formats are allowed: 165498943Sluigi * any matches any IP. Actually returns an empty instruction. 165598943Sluigi * me returns O_IP_*_ME 165698943Sluigi * 1.2.3.4 single IP address 165798943Sluigi * 1.2.3.4:5.6.7.8 address:mask 165898943Sluigi * 1.2.3.4/24 address/mask 165998943Sluigi * 1.2.3.4/26{1,6,5,4,23} set of addresses in a subnet 166098943Sluigi */ 166198943Sluigistatic void 166298943Sluigifill_ip(ipfw_insn_ip *cmd, char *av) 166398943Sluigi{ 166498943Sluigi char *p = 0, md = 0; 166598943Sluigi u_int32_t i; 166698943Sluigi 166798943Sluigi cmd->o.len &= ~F_LEN_MASK; /* zero len */ 166898943Sluigi 166998943Sluigi if (!strncmp(av, "any", strlen(av))) 167098943Sluigi return; 167198943Sluigi 167298943Sluigi if (!strncmp(av, "me", strlen(av))) { 167398943Sluigi cmd->o.len |= F_INSN_SIZE(ipfw_insn); 167498943Sluigi return; 167598943Sluigi } 167698943Sluigi 167798943Sluigi p = strchr(av, '/'); 167898943Sluigi if (!p) 167998943Sluigi p = strchr(av, ':'); 168098943Sluigi if (p) { 168198943Sluigi md = *p; 168298943Sluigi *p++ = '\0'; 168398943Sluigi } 168498943Sluigi 168598943Sluigi if (lookup_host(av, &cmd->addr) != 0) 168698943Sluigi errx(EX_NOHOST, "hostname ``%s'' unknown", av); 168798943Sluigi switch (md) { 168898943Sluigi case ':': 168998943Sluigi if (!inet_aton(p, &cmd->mask)) 169098943Sluigi errx(EX_DATAERR, "bad netmask ``%s''", p); 169198943Sluigi break; 169298943Sluigi case '/': 169398943Sluigi i = atoi(p); 169498943Sluigi if (i == 0) 169598943Sluigi cmd->mask.s_addr = htonl(0); 169698943Sluigi else if (i > 32) 169798943Sluigi errx(EX_DATAERR, "bad width ``%s''", p); 169898943Sluigi else 169998943Sluigi cmd->mask.s_addr = htonl(~0 << (32 - i)); 170098943Sluigi break; 170198943Sluigi default: 170298943Sluigi cmd->mask.s_addr = htonl(~0); 170398943Sluigi break; 170498943Sluigi } 170598943Sluigi cmd->addr.s_addr &= cmd->mask.s_addr; 170698943Sluigi /* 170798943Sluigi * now look if we have a set of addresses. They are stored as follows: 170898943Sluigi * arg1 is the set size (powers of 2, 2..256) 170998943Sluigi * addr is the base address IN HOST FORMAT 171098943Sluigi * mask.. is an array of u_int32_t with bits set. 171198943Sluigi */ 171298943Sluigi if (p) 171398943Sluigi p = strchr(p, '{'); 171498943Sluigi if (p) { /* fetch addresses */ 171598943Sluigi u_int32_t *d; 171698943Sluigi int low, high; 171798943Sluigi int i = contigmask((u_char *)&(cmd->mask), 32); 171898943Sluigi 171998943Sluigi if (i < 24 || i > 31) { 172098943Sluigi fprintf(stderr, "invalid set with mask %d\n", 172198943Sluigi i); 172298943Sluigi exit(0); 172398943Sluigi } 172498943Sluigi cmd->o.arg1 = 1<<(32-i); 172598943Sluigi cmd->addr.s_addr = ntohl(cmd->addr.s_addr); 172698943Sluigi d = (u_int32_t *)&cmd->mask; 172798943Sluigi cmd->o.opcode = O_IP_DST_SET; /* default */ 172898943Sluigi cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32) + (cmd->o.arg1+31)/32; 1729101117Sluigi for (i = 0; i < (cmd->o.arg1+31)/32 ; i++) 173098943Sluigi d[i] = 0; /* clear masks */ 173198943Sluigi 173298943Sluigi av = p+1; 173398943Sluigi low = cmd->addr.s_addr & 0xff; 173498943Sluigi high = low + cmd->o.arg1 - 1; 173598943Sluigi while (isdigit(*av)) { 173698943Sluigi char *s; 173798943Sluigi u_int16_t a = strtol(av, &s, 0); 173898943Sluigi 173998943Sluigi if (s == av) /* no parameter */ 174098943Sluigi break; 174198943Sluigi if (a < low || a > high) { 174298943Sluigi fprintf(stderr, "addr %d out of range [%d-%d]\n", 174398943Sluigi a, low, high); 174498943Sluigi exit(0); 174598943Sluigi } 174698943Sluigi a -= low; 174798943Sluigi d[ a/32] |= 1<<(a & 31); 174898943Sluigi if (*s != ',') 174998943Sluigi break; 175098943Sluigi av = s+1; 175198943Sluigi } 175298943Sluigi return; 175398943Sluigi } 175498943Sluigi 175598943Sluigi if (cmd->mask.s_addr == 0) { /* any */ 175698943Sluigi if (cmd->o.len & F_NOT) 175798943Sluigi errx(EX_DATAERR, "not any never matches"); 175898943Sluigi else /* useless, nuke it */ 175998943Sluigi return; 176098943Sluigi } else if (cmd->mask.s_addr == IP_MASK_ALL) /* one IP */ 176198943Sluigi cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32); 176298943Sluigi else /* addr/mask */ 176398943Sluigi cmd->o.len |= F_INSN_SIZE(ipfw_insn_ip); 176498943Sluigi} 176598943Sluigi 176698943Sluigi 176798943Sluigi/* 176898943Sluigi * helper function to process a set of flags and set bits in the 176998943Sluigi * appropriate masks. 177098943Sluigi */ 177198943Sluigistatic void 177298943Sluigifill_flags(ipfw_insn *cmd, enum ipfw_opcodes opcode, 177398943Sluigi struct _s_x *flags, char *p) 177498943Sluigi{ 177598943Sluigi u_int8_t set=0, clear=0; 177698943Sluigi 177798943Sluigi while (p && *p) { 177898943Sluigi char *q; /* points to the separator */ 177998943Sluigi int val; 178098943Sluigi u_int8_t *which; /* mask we are working on */ 178198943Sluigi 178298943Sluigi if (*p == '!') { 178398943Sluigi p++; 178498943Sluigi which = &clear; 178598943Sluigi } else 178698943Sluigi which = &set; 178798943Sluigi q = strchr(p, ','); 178898943Sluigi if (q) 178998943Sluigi *q++ = '\0'; 179098943Sluigi val = match_token(flags, p); 179198943Sluigi if (val <= 0) 179298943Sluigi errx(EX_DATAERR, "invalid flag %s", p); 179398943Sluigi *which |= (u_int8_t)val; 179498943Sluigi p = q; 179598943Sluigi } 179698943Sluigi cmd->opcode = opcode; 179798943Sluigi cmd->len = (cmd->len & (F_NOT | F_OR)) | 1; 179898943Sluigi cmd->arg1 = (set & 0xff) | ( (clear & 0xff) << 8); 179998943Sluigi} 180098943Sluigi 180198943Sluigi 180298943Sluigistatic void 180398943Sluigidelete(int ac, char *av[]) 180498943Sluigi{ 1805101978Sluigi u_int32_t rulenum; 180698943Sluigi struct dn_pipe pipe; 180798943Sluigi int i; 180898943Sluigi int exitval = EX_OK; 1809101628Sluigi int do_set = 0; 181098943Sluigi 181198943Sluigi memset(&pipe, 0, sizeof pipe); 181298943Sluigi 181398943Sluigi av++; ac--; 1814101641Sluigi if (ac > 0 && !strncmp(*av, "set", strlen(*av))) { 1815101978Sluigi do_set = 1; /* delete set */ 1816101628Sluigi ac--; av++; 1817101978Sluigi } 181898943Sluigi 181998943Sluigi /* Rule number */ 182098943Sluigi while (ac && isdigit(**av)) { 182198943Sluigi i = atoi(*av); av++; ac--; 182298943Sluigi if (do_pipe) { 182398943Sluigi if (do_pipe == 1) 182498943Sluigi pipe.pipe_nr = i; 182598943Sluigi else 182698943Sluigi pipe.fs.fs_nr = i; 182798943Sluigi i = setsockopt(s, IPPROTO_IP, IP_DUMMYNET_DEL, 182898943Sluigi &pipe, sizeof pipe); 182998943Sluigi if (i) { 183098943Sluigi exitval = 1; 183198943Sluigi warn("rule %u: setsockopt(IP_DUMMYNET_DEL)", 183298943Sluigi do_pipe == 1 ? pipe.pipe_nr : 183398943Sluigi pipe.fs.fs_nr); 183498943Sluigi } 183598943Sluigi } else { 1836101978Sluigi rulenum = (i & 0xffff) | (do_set << 24); 183798943Sluigi i = setsockopt(s, IPPROTO_IP, IP_FW_DEL, &rulenum, 183898943Sluigi sizeof rulenum); 183998943Sluigi if (i) { 184098943Sluigi exitval = EX_UNAVAILABLE; 184198943Sluigi warn("rule %u: setsockopt(IP_FW_DEL)", 184298943Sluigi rulenum); 184398943Sluigi } 184498943Sluigi } 184598943Sluigi } 184698943Sluigi if (exitval != EX_OK) 184798943Sluigi exit(exitval); 184898943Sluigi} 184998943Sluigi 185098943Sluigi 185198943Sluigi/* 185298943Sluigi * fill the interface structure. We do not check the name as we can 185398943Sluigi * create interfaces dynamically, so checking them at insert time 185498943Sluigi * makes relatively little sense. 185598943Sluigi * A '*' following the name means any unit. 185698943Sluigi */ 185798943Sluigistatic void 185898943Sluigifill_iface(ipfw_insn_if *cmd, char *arg) 185998943Sluigi{ 186098943Sluigi cmd->name[0] = '\0'; 186198943Sluigi cmd->o.len |= F_INSN_SIZE(ipfw_insn_if); 186298943Sluigi 186398943Sluigi /* Parse the interface or address */ 186498943Sluigi if (!strcmp(arg, "any")) 186598943Sluigi cmd->o.len = 0; /* effectively ignore this command */ 186698943Sluigi else if (!isdigit(*arg)) { 186798943Sluigi char *q; 186898943Sluigi 186998943Sluigi strncpy(cmd->name, arg, sizeof(cmd->name)); 187098943Sluigi cmd->name[sizeof(cmd->name) - 1] = '\0'; 187198943Sluigi /* find first digit or wildcard */ 187298943Sluigi for (q = cmd->name; *q && !isdigit(*q) && *q != '*'; q++) 187398943Sluigi continue; 187498943Sluigi cmd->p.unit = (*q == '*') ? -1 : atoi(q); 187598943Sluigi *q = '\0'; 187698943Sluigi } else if (!inet_aton(arg, &cmd->p.ip)) 187798943Sluigi errx(EX_DATAERR, "bad ip address ``%s''", arg); 187898943Sluigi} 187998943Sluigi 188098943Sluigi/* 188198943Sluigi * the following macro returns an error message if we run out of 188298943Sluigi * arguments. 188398943Sluigi */ 188498943Sluigi#define NEED1(msg) {if (!ac) errx(EX_USAGE, msg);} 188598943Sluigi 188698943Sluigistatic void 188798943Sluigiconfig_pipe(int ac, char **av) 188898943Sluigi{ 188998943Sluigi struct dn_pipe pipe; 189098943Sluigi int i; 189198943Sluigi char *end; 189298943Sluigi u_int32_t a; 189398943Sluigi void *par = NULL; 189498943Sluigi 189598943Sluigi memset(&pipe, 0, sizeof pipe); 189698943Sluigi 189798943Sluigi av++; ac--; 189898943Sluigi /* Pipe number */ 189998943Sluigi if (ac && isdigit(**av)) { 190098943Sluigi i = atoi(*av); av++; ac--; 190198943Sluigi if (do_pipe == 1) 190298943Sluigi pipe.pipe_nr = i; 190398943Sluigi else 190498943Sluigi pipe.fs.fs_nr = i; 190598943Sluigi } 190699475Sluigi while (ac > 0) { 190798943Sluigi double d; 190898943Sluigi int tok = match_token(dummynet_params, *av); 190998943Sluigi ac--; av++; 191098943Sluigi 191198943Sluigi switch(tok) { 1912101978Sluigi case TOK_NOERROR: 1913101978Sluigi pipe.fs.flags_fs |= DN_NOERROR; 1914101978Sluigi break; 1915101978Sluigi 191698943Sluigi case TOK_PLR: 191798943Sluigi NEED1("plr needs argument 0..1\n"); 191898943Sluigi d = strtod(av[0], NULL); 191998943Sluigi if (d > 1) 192098943Sluigi d = 1; 192198943Sluigi else if (d < 0) 192298943Sluigi d = 0; 192398943Sluigi pipe.fs.plr = (int)(d*0x7fffffff); 192498943Sluigi ac--; av++; 192598943Sluigi break; 192698943Sluigi 192798943Sluigi case TOK_QUEUE: 192898943Sluigi NEED1("queue needs queue size\n"); 192998943Sluigi end = NULL; 193098943Sluigi pipe.fs.qsize = strtoul(av[0], &end, 0); 193198943Sluigi if (*end == 'K' || *end == 'k') { 193298943Sluigi pipe.fs.flags_fs |= DN_QSIZE_IS_BYTES; 193398943Sluigi pipe.fs.qsize *= 1024; 193498943Sluigi } else if (*end == 'B' || !strncmp(end, "by", 2)) { 193598943Sluigi pipe.fs.flags_fs |= DN_QSIZE_IS_BYTES; 193698943Sluigi } 193798943Sluigi ac--; av++; 193898943Sluigi break; 193998943Sluigi 194098943Sluigi case TOK_BUCKETS: 194198943Sluigi NEED1("buckets needs argument\n"); 194298943Sluigi pipe.fs.rq_size = strtoul(av[0], NULL, 0); 194398943Sluigi ac--; av++; 194498943Sluigi break; 194598943Sluigi 194698943Sluigi case TOK_MASK: 194798943Sluigi NEED1("mask needs mask specifier\n"); 194898943Sluigi /* 194998943Sluigi * per-flow queue, mask is dst_ip, dst_port, 195098943Sluigi * src_ip, src_port, proto measured in bits 195198943Sluigi */ 195298943Sluigi par = NULL; 195398943Sluigi 195498943Sluigi pipe.fs.flow_mask.dst_ip = 0; 195598943Sluigi pipe.fs.flow_mask.src_ip = 0; 195698943Sluigi pipe.fs.flow_mask.dst_port = 0; 195798943Sluigi pipe.fs.flow_mask.src_port = 0; 195898943Sluigi pipe.fs.flow_mask.proto = 0; 195998943Sluigi end = NULL; 196098943Sluigi 196198943Sluigi while (ac >= 1) { 196298943Sluigi u_int32_t *p32 = NULL; 196398943Sluigi u_int16_t *p16 = NULL; 196498943Sluigi 196598943Sluigi tok = match_token(dummynet_params, *av); 196698943Sluigi ac--; av++; 196798943Sluigi switch(tok) { 196898943Sluigi case TOK_ALL: 196998943Sluigi /* 197098943Sluigi * special case, all bits significant 197198943Sluigi */ 197298943Sluigi pipe.fs.flow_mask.dst_ip = ~0; 197398943Sluigi pipe.fs.flow_mask.src_ip = ~0; 197498943Sluigi pipe.fs.flow_mask.dst_port = ~0; 197598943Sluigi pipe.fs.flow_mask.src_port = ~0; 197698943Sluigi pipe.fs.flow_mask.proto = ~0; 197798943Sluigi pipe.fs.flags_fs |= DN_HAVE_FLOW_MASK; 197898943Sluigi goto end_mask; 197998943Sluigi 198098943Sluigi case TOK_DSTIP: 198198943Sluigi p32 = &pipe.fs.flow_mask.dst_ip; 198298943Sluigi break; 198398943Sluigi 198498943Sluigi case TOK_SRCIP: 198598943Sluigi p32 = &pipe.fs.flow_mask.src_ip; 198698943Sluigi break; 198798943Sluigi 198898943Sluigi case TOK_DSTPORT: 198998943Sluigi p16 = &pipe.fs.flow_mask.dst_port; 199098943Sluigi break; 199198943Sluigi 199298943Sluigi case TOK_SRCPORT: 199398943Sluigi p16 = &pipe.fs.flow_mask.src_port; 199498943Sluigi break; 199598943Sluigi 199698943Sluigi case TOK_PROTO: 199798943Sluigi break; 199898943Sluigi 199998943Sluigi default: 200098943Sluigi ac++; av--; /* backtrack */ 200198943Sluigi goto end_mask; 200298943Sluigi } 200398943Sluigi if (ac < 1) 200498943Sluigi errx(EX_USAGE, "mask: value missing"); 200598943Sluigi if (*av[0] == '/') { 200698943Sluigi a = strtoul(av[0]+1, &end, 0); 200798943Sluigi a = (a == 32) ? ~0 : (1 << a) - 1; 200898943Sluigi } else 200999909Sluigi a = strtoul(av[0], &end, 0); 201098943Sluigi if (p32 != NULL) 201198943Sluigi *p32 = a; 201298943Sluigi else if (p16 != NULL) { 201398943Sluigi if (a > 65535) 201498943Sluigi errx(EX_DATAERR, 201598943Sluigi "mask: must be 16 bit"); 201698943Sluigi *p16 = (u_int16_t)a; 201798943Sluigi } else { 201898943Sluigi if (a > 255) 201998943Sluigi errx(EX_DATAERR, 202098943Sluigi "mask: must be 8 bit"); 202198943Sluigi pipe.fs.flow_mask.proto = (u_int8_t)a; 202298943Sluigi } 202398943Sluigi if (a != 0) 202498943Sluigi pipe.fs.flags_fs |= DN_HAVE_FLOW_MASK; 202598943Sluigi ac--; av++; 202698943Sluigi } /* end while, config masks */ 202798943Sluigiend_mask: 202898943Sluigi break; 202998943Sluigi 203098943Sluigi case TOK_RED: 203198943Sluigi case TOK_GRED: 203298943Sluigi NEED1("red/gred needs w_q/min_th/max_th/max_p\n"); 203398943Sluigi pipe.fs.flags_fs |= DN_IS_RED; 203498943Sluigi if (tok == TOK_GRED) 203598943Sluigi pipe.fs.flags_fs |= DN_IS_GENTLE_RED; 203698943Sluigi /* 203798943Sluigi * the format for parameters is w_q/min_th/max_th/max_p 203898943Sluigi */ 203998943Sluigi if ((end = strsep(&av[0], "/"))) { 204098943Sluigi double w_q = strtod(end, NULL); 204198943Sluigi if (w_q > 1 || w_q <= 0) 204298943Sluigi errx(EX_DATAERR, "0 < w_q <= 1"); 204398943Sluigi pipe.fs.w_q = (int) (w_q * (1 << SCALE_RED)); 204498943Sluigi } 204598943Sluigi if ((end = strsep(&av[0], "/"))) { 204698943Sluigi pipe.fs.min_th = strtoul(end, &end, 0); 204798943Sluigi if (*end == 'K' || *end == 'k') 204898943Sluigi pipe.fs.min_th *= 1024; 204998943Sluigi } 205098943Sluigi if ((end = strsep(&av[0], "/"))) { 205198943Sluigi pipe.fs.max_th = strtoul(end, &end, 0); 205298943Sluigi if (*end == 'K' || *end == 'k') 205398943Sluigi pipe.fs.max_th *= 1024; 205498943Sluigi } 205598943Sluigi if ((end = strsep(&av[0], "/"))) { 205698943Sluigi double max_p = strtod(end, NULL); 205798943Sluigi if (max_p > 1 || max_p <= 0) 205898943Sluigi errx(EX_DATAERR, "0 < max_p <= 1"); 205998943Sluigi pipe.fs.max_p = (int)(max_p * (1 << SCALE_RED)); 206098943Sluigi } 206198943Sluigi ac--; av++; 206298943Sluigi break; 206398943Sluigi 206498943Sluigi case TOK_DROPTAIL: 206598943Sluigi pipe.fs.flags_fs &= ~(DN_IS_RED|DN_IS_GENTLE_RED); 206698943Sluigi break; 206798943Sluigi 206898943Sluigi case TOK_BW: 206998943Sluigi NEED1("bw needs bandwidth or interface\n"); 207098943Sluigi if (do_pipe != 1) 207198943Sluigi errx(EX_DATAERR, "bandwidth only valid for pipes"); 207298943Sluigi /* 207398943Sluigi * set clocking interface or bandwidth value 207498943Sluigi */ 207598943Sluigi if (av[0][0] >= 'a' && av[0][0] <= 'z') { 207698943Sluigi int l = sizeof(pipe.if_name)-1; 207798943Sluigi /* interface name */ 207898943Sluigi strncpy(pipe.if_name, av[0], l); 207998943Sluigi pipe.if_name[l] = '\0'; 208098943Sluigi pipe.bandwidth = 0; 208198943Sluigi } else { 208298943Sluigi pipe.if_name[0] = '\0'; 208398943Sluigi pipe.bandwidth = strtoul(av[0], &end, 0); 208498943Sluigi if (*end == 'K' || *end == 'k') { 208598943Sluigi end++; 208698943Sluigi pipe.bandwidth *= 1000; 208798943Sluigi } else if (*end == 'M') { 208898943Sluigi end++; 208998943Sluigi pipe.bandwidth *= 1000000; 209098943Sluigi } 209198943Sluigi if (*end == 'B' || !strncmp(end, "by", 2)) 209298943Sluigi pipe.bandwidth *= 8; 209398943Sluigi if (pipe.bandwidth < 0) 209498943Sluigi errx(EX_DATAERR, "bandwidth too large"); 209598943Sluigi } 209698943Sluigi ac--; av++; 209798943Sluigi break; 209898943Sluigi 209998943Sluigi case TOK_DELAY: 210098943Sluigi if (do_pipe != 1) 210198943Sluigi errx(EX_DATAERR, "delay only valid for pipes"); 210298943Sluigi NEED1("delay needs argument 0..10000ms\n"); 210398943Sluigi pipe.delay = strtoul(av[0], NULL, 0); 210498943Sluigi ac--; av++; 210598943Sluigi break; 210698943Sluigi 210798943Sluigi case TOK_WEIGHT: 210898943Sluigi if (do_pipe == 1) 210998943Sluigi errx(EX_DATAERR,"weight only valid for queues"); 211098943Sluigi NEED1("weight needs argument 0..100\n"); 211198943Sluigi pipe.fs.weight = strtoul(av[0], &end, 0); 211298943Sluigi ac--; av++; 211398943Sluigi break; 211498943Sluigi 211598943Sluigi case TOK_PIPE: 211698943Sluigi if (do_pipe == 1) 211798943Sluigi errx(EX_DATAERR,"pipe only valid for queues"); 211898943Sluigi NEED1("pipe needs pipe_number\n"); 211998943Sluigi pipe.fs.parent_nr = strtoul(av[0], &end, 0); 212098943Sluigi ac--; av++; 212198943Sluigi break; 212298943Sluigi 212398943Sluigi default: 212498943Sluigi errx(EX_DATAERR, "unrecognised option ``%s''", *av); 212598943Sluigi } 212698943Sluigi } 212798943Sluigi if (do_pipe == 1) { 212898943Sluigi if (pipe.pipe_nr == 0) 212998943Sluigi errx(EX_DATAERR, "pipe_nr must be > 0"); 213098943Sluigi if (pipe.delay > 10000) 213198943Sluigi errx(EX_DATAERR, "delay must be < 10000"); 213298943Sluigi } else { /* do_pipe == 2, queue */ 213398943Sluigi if (pipe.fs.parent_nr == 0) 213498943Sluigi errx(EX_DATAERR, "pipe must be > 0"); 213598943Sluigi if (pipe.fs.weight >100) 213698943Sluigi errx(EX_DATAERR, "weight must be <= 100"); 213798943Sluigi } 213898943Sluigi if (pipe.fs.flags_fs & DN_QSIZE_IS_BYTES) { 213998943Sluigi if (pipe.fs.qsize > 1024*1024) 214098943Sluigi errx(EX_DATAERR, "queue size must be < 1MB"); 214198943Sluigi } else { 214298943Sluigi if (pipe.fs.qsize > 100) 214398943Sluigi errx(EX_DATAERR, "2 <= queue size <= 100"); 214498943Sluigi } 214598943Sluigi if (pipe.fs.flags_fs & DN_IS_RED) { 214698943Sluigi size_t len; 214798943Sluigi int lookup_depth, avg_pkt_size; 214898943Sluigi double s, idle, weight, w_q; 214998943Sluigi struct clockinfo clock; 215098943Sluigi int t; 215198943Sluigi 215298943Sluigi if (pipe.fs.min_th >= pipe.fs.max_th) 215398943Sluigi errx(EX_DATAERR, "min_th %d must be < than max_th %d", 215498943Sluigi pipe.fs.min_th, pipe.fs.max_th); 215598943Sluigi if (pipe.fs.max_th == 0) 215698943Sluigi errx(EX_DATAERR, "max_th must be > 0"); 215798943Sluigi 215898943Sluigi len = sizeof(int); 215998943Sluigi if (sysctlbyname("net.inet.ip.dummynet.red_lookup_depth", 216098943Sluigi &lookup_depth, &len, NULL, 0) == -1) 216198943Sluigi 216298943Sluigi errx(1, "sysctlbyname(\"%s\")", 216398943Sluigi "net.inet.ip.dummynet.red_lookup_depth"); 216498943Sluigi if (lookup_depth == 0) 216598943Sluigi errx(EX_DATAERR, "net.inet.ip.dummynet.red_lookup_depth" 216698943Sluigi " must be greater than zero"); 216798943Sluigi 216898943Sluigi len = sizeof(int); 216998943Sluigi if (sysctlbyname("net.inet.ip.dummynet.red_avg_pkt_size", 217098943Sluigi &avg_pkt_size, &len, NULL, 0) == -1) 217198943Sluigi 217298943Sluigi errx(1, "sysctlbyname(\"%s\")", 217398943Sluigi "net.inet.ip.dummynet.red_avg_pkt_size"); 217498943Sluigi if (avg_pkt_size == 0) 217598943Sluigi errx(EX_DATAERR, 217698943Sluigi "net.inet.ip.dummynet.red_avg_pkt_size must" 217798943Sluigi " be greater than zero"); 217898943Sluigi 217998943Sluigi len = sizeof(struct clockinfo); 218098943Sluigi if (sysctlbyname("kern.clockrate", &clock, &len, NULL, 0) == -1) 218198943Sluigi errx(1, "sysctlbyname(\"%s\")", "kern.clockrate"); 218298943Sluigi 218398943Sluigi /* 218498943Sluigi * Ticks needed for sending a medium-sized packet. 218598943Sluigi * Unfortunately, when we are configuring a WF2Q+ queue, we 218698943Sluigi * do not have bandwidth information, because that is stored 218798943Sluigi * in the parent pipe, and also we have multiple queues 218898943Sluigi * competing for it. So we set s=0, which is not very 218998943Sluigi * correct. But on the other hand, why do we want RED with 219098943Sluigi * WF2Q+ ? 219198943Sluigi */ 219298943Sluigi if (pipe.bandwidth==0) /* this is a WF2Q+ queue */ 219398943Sluigi s = 0; 219498943Sluigi else 219598943Sluigi s = clock.hz * avg_pkt_size * 8 / pipe.bandwidth; 219698943Sluigi 219798943Sluigi /* 219898943Sluigi * max idle time (in ticks) before avg queue size becomes 0. 219998943Sluigi * NOTA: (3/w_q) is approx the value x so that 220098943Sluigi * (1-w_q)^x < 10^-3. 220198943Sluigi */ 220298943Sluigi w_q = ((double)pipe.fs.w_q) / (1 << SCALE_RED); 220398943Sluigi idle = s * 3. / w_q; 220498943Sluigi pipe.fs.lookup_step = (int)idle / lookup_depth; 220598943Sluigi if (!pipe.fs.lookup_step) 220698943Sluigi pipe.fs.lookup_step = 1; 220798943Sluigi weight = 1 - w_q; 220898943Sluigi for (t = pipe.fs.lookup_step; t > 0; --t) 220998943Sluigi weight *= weight; 221098943Sluigi pipe.fs.lookup_weight = (int)(weight * (1 << SCALE_RED)); 221198943Sluigi } 221298943Sluigi i = setsockopt(s, IPPROTO_IP, IP_DUMMYNET_CONFIGURE, &pipe, 221398943Sluigi sizeof pipe); 221498943Sluigi if (i) 221598943Sluigi err(1, "setsockopt(%s)", "IP_DUMMYNET_CONFIGURE"); 221698943Sluigi} 221798943Sluigi 221898943Sluigistatic void 221998943Sluigiget_mac_addr_mask(char *p, u_char *addr, u_char *mask) 222098943Sluigi{ 222198943Sluigi int i, l; 222298943Sluigi 222398943Sluigi for (i=0; i<6; i++) 222498943Sluigi addr[i] = mask[i] = 0; 222598943Sluigi if (!strcmp(p, "any")) 222698943Sluigi return; 222798943Sluigi 222898943Sluigi for (i=0; *p && i<6;i++, p++) { 222998943Sluigi addr[i] = strtol(p, &p, 16); 223098943Sluigi if (*p != ':') /* we start with the mask */ 223198943Sluigi break; 223298943Sluigi } 223398943Sluigi if (*p == '/') { /* mask len */ 223498943Sluigi l = strtol(p+1, &p, 0); 223598943Sluigi for (i=0; l>0; l -=8, i++) 223698943Sluigi mask[i] = (l >=8) ? 0xff : (~0) << (8-l); 223798943Sluigi } else if (*p == '&') { /* mask */ 223898943Sluigi for (i=0, p++; *p && i<6;i++, p++) { 223998943Sluigi mask[i] = strtol(p, &p, 16); 224098943Sluigi if (*p != ':') 224198943Sluigi break; 224298943Sluigi } 224398943Sluigi } else if (*p == '\0') { 224498943Sluigi for (i=0; i<6; i++) 224598943Sluigi mask[i] = 0xff; 224698943Sluigi } 224798943Sluigi for (i=0; i<6; i++) 224898943Sluigi addr[i] &= mask[i]; 224998943Sluigi} 225098943Sluigi 225198943Sluigi/* 225298943Sluigi * helper function, updates the pointer to cmd with the length 225398943Sluigi * of the current command, and also cleans up the first word of 225498943Sluigi * the new command in case it has been clobbered before. 225598943Sluigi */ 225698943Sluigistatic ipfw_insn * 225798943Sluiginext_cmd(ipfw_insn *cmd) 225898943Sluigi{ 225998943Sluigi cmd += F_LEN(cmd); 226098943Sluigi bzero(cmd, sizeof(*cmd)); 226198943Sluigi return cmd; 226298943Sluigi} 226398943Sluigi 226498943Sluigi/* 226598943Sluigi * A function to fill simple commands of size 1. 226698943Sluigi * Existing flags are preserved. 226798943Sluigi */ 226898943Sluigistatic void 226998943Sluigifill_cmd(ipfw_insn *cmd, enum ipfw_opcodes opcode, int flags, u_int16_t arg) 227098943Sluigi{ 227198943Sluigi cmd->opcode = opcode; 227298943Sluigi cmd->len = ((cmd->len | flags) & (F_NOT | F_OR)) | 1; 227398943Sluigi cmd->arg1 = arg; 227498943Sluigi} 227598943Sluigi 227698943Sluigi/* 227798943Sluigi * Fetch and add the MAC address and type, with masks. This generates one or 227898943Sluigi * two microinstructions, and returns the pointer to the last one. 227998943Sluigi */ 228098943Sluigistatic ipfw_insn * 228198943Sluigiadd_mac(ipfw_insn *cmd, int ac, char *av[]) 228298943Sluigi{ 228398943Sluigi ipfw_insn_mac *mac; /* also *src */ 228498943Sluigi 2285101978Sluigi if (ac <2) 2286101978Sluigi errx(EX_DATAERR, "MAC dst src [type]"); 228798943Sluigi 228898943Sluigi cmd->opcode = O_MACADDR2; 228998943Sluigi cmd->len = (cmd->len & (F_NOT | F_OR)) | F_INSN_SIZE(ipfw_insn_mac); 229098943Sluigi 229198943Sluigi mac = (ipfw_insn_mac *)cmd; 2292101978Sluigi get_mac_addr_mask(av[0], mac->addr, mac->mask); /* dst */ 229398943Sluigi get_mac_addr_mask(av[1], &(mac->addr[6]), &(mac->mask[6])); /* src */ 2294101978Sluigi 2295101978Sluigi if (ac>2 && strcmp(av[2], "any") != 0) { /* we have a non-null type */ 229698943Sluigi cmd += F_LEN(cmd); 229798943Sluigi 2298101978Sluigi fill_newports((ipfw_insn_u16 *)cmd, av[2], IPPROTO_ETHERTYPE); 229998943Sluigi cmd->opcode = O_MAC_TYPE; 230098943Sluigi } 230198943Sluigi 230298943Sluigi return cmd; 230398943Sluigi} 230498943Sluigi 230598943Sluigi/* 230698943Sluigi * Parse arguments and assemble the microinstructions which make up a rule. 230798943Sluigi * Rules are added into the 'rulebuf' and then copied in the correct order 230898943Sluigi * into the actual rule. 230998943Sluigi * 231098943Sluigi * The syntax for a rule starts with the action, followed by an 231198943Sluigi * optional log action, and the various match patterns. 231298943Sluigi * In the assembled microcode, the first opcode must be a O_PROBE_STATE 231398943Sluigi * (generated if the rule includes a keep-state option), then the 231498943Sluigi * various match patterns, the "log" action, and the actual action. 231598943Sluigi * 231698943Sluigi */ 231798943Sluigistatic void 231898943Sluigiadd(int ac, char *av[]) 231998943Sluigi{ 232098943Sluigi /* 232198943Sluigi * rules are added into the 'rulebuf' and then copied in 232298943Sluigi * the correct order into the actual rule. 232398943Sluigi * Some things that need to go out of order (prob, action etc.) 232498943Sluigi * go into actbuf[]. 232598943Sluigi */ 232698943Sluigi static u_int32_t rulebuf[255], actbuf[255], cmdbuf[255]; 232798943Sluigi 232898943Sluigi ipfw_insn *src, *dst, *cmd, *action, *prev; 232998943Sluigi 233098943Sluigi struct ip_fw *rule; 233198943Sluigi 233298943Sluigi /* 233398943Sluigi * various flags used to record that we entered some fields. 233498943Sluigi */ 233598943Sluigi int have_mac = 0; /* set if we have a MAC address */ 2336101116Sluigi ipfw_insn *have_state = NULL; /* check-state or keep-state */ 233798943Sluigi 233898943Sluigi int i; 233998943Sluigi 234098943Sluigi int open_par = 0; /* open parenthesis ( */ 234198943Sluigi 234298943Sluigi /* proto is here because it is used to fetch ports */ 234398943Sluigi u_char proto = IPPROTO_IP; /* default protocol */ 234498943Sluigi 234598943Sluigi bzero(actbuf, sizeof(actbuf)); /* actions go here */ 234698943Sluigi bzero(cmdbuf, sizeof(cmdbuf)); 234798943Sluigi bzero(rulebuf, sizeof(rulebuf)); 234898943Sluigi 234998943Sluigi rule = (struct ip_fw *)rulebuf; 235098943Sluigi cmd = (ipfw_insn *)cmdbuf; 235198943Sluigi action = (ipfw_insn *)actbuf; 235298943Sluigi 235398943Sluigi av++; ac--; 235498943Sluigi 235598943Sluigi /* [rule N] -- Rule number optional */ 235698943Sluigi if (ac && isdigit(**av)) { 235798943Sluigi rule->rulenum = atoi(*av); 235898943Sluigi av++; 235998943Sluigi ac--; 236098943Sluigi } 236198943Sluigi 2362101628Sluigi /* [set N] -- set number (0..30), optional */ 2363101628Sluigi if (ac > 1 && !strncmp(*av, "set", strlen(*av))) { 2364101628Sluigi int set = strtoul(av[1], NULL, 10); 2365101628Sluigi if (set < 0 || set > 30) 2366101628Sluigi errx(EX_DATAERR, "illegal set %s", av[1]); 2367101628Sluigi rule->set = set; 2368101628Sluigi av += 2; ac -= 2; 2369101628Sluigi } 2370101628Sluigi 237198943Sluigi /* [prob D] -- match probability, optional */ 237298943Sluigi if (ac > 1 && !strncmp(*av, "prob", strlen(*av))) { 237398943Sluigi double d = strtod(av[1], NULL); 237498943Sluigi 237598943Sluigi if (d <= 0 || d > 1) 237698943Sluigi errx(EX_DATAERR, "illegal match prob. %s", av[1]); 237798943Sluigi if (d != 1) { /* 1 means always match */ 237898943Sluigi action->opcode = O_PROB; 237998943Sluigi action->len = 2; 238098943Sluigi *((int32_t *)(action+1)) = 238198943Sluigi (int32_t)((1 - d) * 0x7fffffff); 238298943Sluigi action += action->len; 238398943Sluigi } 238498943Sluigi av += 2; ac -= 2; 238598943Sluigi } 238698943Sluigi 238798943Sluigi /* action -- mandatory */ 238898943Sluigi NEED1("missing action"); 238998943Sluigi i = match_token(rule_actions, *av); 239098943Sluigi ac--; av++; 239198943Sluigi action->len = 1; /* default */ 239298943Sluigi switch(i) { 239398943Sluigi case TOK_CHECKSTATE: 2394101116Sluigi have_state = action; 239598943Sluigi action->opcode = O_CHECK_STATE; 239698943Sluigi break; 239798943Sluigi 239898943Sluigi case TOK_ACCEPT: 239998943Sluigi action->opcode = O_ACCEPT; 240098943Sluigi break; 240198943Sluigi 240298943Sluigi case TOK_DENY: 240398943Sluigi action->opcode = O_DENY; 240499475Sluigi action->arg1 = 0; 240598943Sluigi break; 240698943Sluigi 240799475Sluigi case TOK_REJECT: 240899475Sluigi action->opcode = O_REJECT; 240999475Sluigi action->arg1 = ICMP_UNREACH_HOST; 241099475Sluigi break; 241199475Sluigi 241299475Sluigi case TOK_RESET: 241399475Sluigi action->opcode = O_REJECT; 241499475Sluigi action->arg1 = ICMP_REJECT_RST; 241599475Sluigi break; 241699475Sluigi 241799475Sluigi case TOK_UNREACH: 241899475Sluigi action->opcode = O_REJECT; 241999475Sluigi NEED1("missing reject code"); 242099475Sluigi fill_reject_code(&action->arg1, *av); 242199475Sluigi ac--; av++; 242299475Sluigi break; 242399475Sluigi 242498943Sluigi case TOK_COUNT: 242598943Sluigi action->opcode = O_COUNT; 242698943Sluigi break; 242798943Sluigi 242898943Sluigi case TOK_QUEUE: 242998943Sluigi case TOK_PIPE: 243098943Sluigi action->len = F_INSN_SIZE(ipfw_insn_pipe); 243198943Sluigi case TOK_SKIPTO: 243298943Sluigi if (i == TOK_QUEUE) 243398943Sluigi action->opcode = O_QUEUE; 243498943Sluigi else if (i == TOK_PIPE) 243598943Sluigi action->opcode = O_PIPE; 243698943Sluigi else if (i == TOK_SKIPTO) 243798943Sluigi action->opcode = O_SKIPTO; 243898943Sluigi NEED1("missing skipto/pipe/queue number"); 243998943Sluigi action->arg1 = strtoul(*av, NULL, 10); 244098943Sluigi av++; ac--; 244198943Sluigi break; 244298943Sluigi 244398943Sluigi case TOK_DIVERT: 244498943Sluigi case TOK_TEE: 244598943Sluigi action->opcode = (i == TOK_DIVERT) ? O_DIVERT : O_TEE; 244698943Sluigi NEED1("missing divert/tee port"); 244798943Sluigi action->arg1 = strtoul(*av, NULL, 0); 244898943Sluigi if (action->arg1 == 0) { 244998943Sluigi struct servent *s; 245098943Sluigi setservent(1); 245198943Sluigi s = getservbyname(av[0], "divert"); 245298943Sluigi if (s != NULL) 245398943Sluigi action->arg1 = ntohs(s->s_port); 245498943Sluigi else 245598943Sluigi errx(EX_DATAERR, "illegal divert/tee port"); 245698943Sluigi } 245798943Sluigi ac--; av++; 245898943Sluigi break; 245998943Sluigi 246098943Sluigi case TOK_FORWARD: { 246198943Sluigi ipfw_insn_sa *p = (ipfw_insn_sa *)action; 246298943Sluigi char *s, *end; 246398943Sluigi 246498943Sluigi NEED1("missing forward address[:port]"); 246598943Sluigi 246698943Sluigi action->opcode = O_FORWARD_IP; 246798943Sluigi action->len = F_INSN_SIZE(ipfw_insn_sa); 246898943Sluigi 246998943Sluigi p->sa.sin_len = sizeof(struct sockaddr_in); 247098943Sluigi p->sa.sin_family = AF_INET; 247198943Sluigi p->sa.sin_port = 0; 247298943Sluigi /* 247398943Sluigi * locate the address-port separator (':' or ',') 247498943Sluigi */ 247598943Sluigi s = strchr(*av, ':'); 247698943Sluigi if (s == NULL) 247798943Sluigi s = strchr(*av, ','); 247898943Sluigi if (s != NULL) { 247998943Sluigi *(s++) = '\0'; 248098943Sluigi i = strtoport(s, &end, 0 /* base */, 0 /* proto */); 248198943Sluigi if (s == end) 248298943Sluigi errx(EX_DATAERR, 248398943Sluigi "illegal forwarding port ``%s''", s); 248498943Sluigi p->sa.sin_port = htons( (u_short)i ); 248598943Sluigi } 248698943Sluigi lookup_host(*av, &(p->sa.sin_addr)); 248798943Sluigi } 248898943Sluigi ac--; av++; 248998943Sluigi break; 249098943Sluigi 249198943Sluigi default: 249298943Sluigi errx(EX_DATAERR, "invalid action %s\n", *av); 249398943Sluigi } 249498943Sluigi action = next_cmd(action); 249598943Sluigi 249698943Sluigi /* 249798943Sluigi * [log [logamount N]] -- log, optional 249898943Sluigi * 249998943Sluigi * If exists, it goes first in the cmdbuf, but then it is 250098943Sluigi * skipped in the copy section to the end of the buffer. 250198943Sluigi */ 250298943Sluigi if (ac && !strncmp(*av, "log", strlen(*av))) { 250398943Sluigi ipfw_insn_log *c = (ipfw_insn_log *)cmd; 250498943Sluigi 250598943Sluigi cmd->len = F_INSN_SIZE(ipfw_insn_log); 250698943Sluigi cmd->opcode = O_LOG; 250798943Sluigi av++; ac--; 250898943Sluigi if (ac && !strncmp(*av, "logamount", strlen(*av))) { 250998943Sluigi ac--; av++; 251098943Sluigi NEED1("logamount requires argument"); 251198943Sluigi c->max_log = atoi(*av); 251298943Sluigi if (c->max_log < 0) 251398943Sluigi errx(EX_DATAERR, "logamount must be positive"); 251498943Sluigi ac--; av++; 251598943Sluigi } 251698943Sluigi cmd = next_cmd(cmd); 251798943Sluigi } 251898943Sluigi 2519101116Sluigi if (have_state) /* must be a check-state, we are done */ 252098943Sluigi goto done; 252198943Sluigi 252298943Sluigi#define OR_START(target) \ 252398943Sluigi if (ac && (*av[0] == '(' || *av[0] == '{')) { \ 252498943Sluigi if (open_par) \ 252598943Sluigi errx(EX_USAGE, "nested \"(\" not allowed\n"); \ 2526101641Sluigi prev = NULL; \ 252798943Sluigi open_par = 1; \ 252898943Sluigi if ( (av[0])[1] == '\0') { \ 252998943Sluigi ac--; av++; \ 253098943Sluigi } else \ 253198943Sluigi (*av)++; \ 253298943Sluigi } \ 253398943Sluigi target: \ 253498943Sluigi 253598943Sluigi 253698943Sluigi#define CLOSE_PAR \ 253798943Sluigi if (open_par) { \ 253898943Sluigi if (ac && ( \ 253998943Sluigi !strncmp(*av, ")", strlen(*av)) || \ 254098943Sluigi !strncmp(*av, "}", strlen(*av)) )) { \ 2541101641Sluigi prev = NULL; \ 254298943Sluigi open_par = 0; \ 254398943Sluigi ac--; av++; \ 254498943Sluigi } else \ 254598943Sluigi errx(EX_USAGE, "missing \")\"\n"); \ 254698943Sluigi } 254798943Sluigi 254898943Sluigi#define NOT_BLOCK \ 254998943Sluigi if (ac && !strncmp(*av, "not", strlen(*av))) { \ 255098943Sluigi if (cmd->len & F_NOT) \ 255198943Sluigi errx(EX_USAGE, "double \"not\" not allowed\n"); \ 255298943Sluigi cmd->len |= F_NOT; \ 255398943Sluigi ac--; av++; \ 255498943Sluigi } 255598943Sluigi 255698943Sluigi#define OR_BLOCK(target) \ 255798943Sluigi if (ac && !strncmp(*av, "or", strlen(*av))) { \ 255898943Sluigi if (prev == NULL || open_par == 0) \ 255998943Sluigi errx(EX_DATAERR, "invalid OR block"); \ 256098943Sluigi prev->len |= F_OR; \ 256198943Sluigi ac--; av++; \ 256298943Sluigi goto target; \ 256398943Sluigi } \ 256498943Sluigi CLOSE_PAR; 256598943Sluigi 256698943Sluigi /* 256798943Sluigi * protocol, mandatory 256898943Sluigi */ 256998943Sluigi OR_START(get_proto); 257098943Sluigi NOT_BLOCK; 257198943Sluigi NEED1("missing protocol"); 257298943Sluigi { 257398943Sluigi struct protoent *pe; 257498943Sluigi 257598943Sluigi if (!strncmp(*av, "all", strlen(*av))) 257698943Sluigi ; /* same as "ip" */ 257798943Sluigi else if (!strncmp(*av, "MAC", strlen(*av))) { 2578101978Sluigi cmd = add_mac(cmd, ac-1, av+1); /* exits in case of errors */ 2579101978Sluigi av += 3; 258098943Sluigi ac -= 3; 258198943Sluigi have_mac = 1; 258298943Sluigi } else if ((proto = atoi(*av)) > 0) 258398943Sluigi ; /* all done! */ 258498943Sluigi else if ((pe = getprotobyname(*av)) != NULL) 258598943Sluigi proto = pe->p_proto; 258698943Sluigi else 258798943Sluigi errx(EX_DATAERR, "invalid protocol ``%s''", *av); 258898943Sluigi av++; ac--; 258998943Sluigi if (proto != IPPROTO_IP) 259098943Sluigi fill_cmd(cmd, O_PROTO, 0, proto); 259198943Sluigi } 259298943Sluigi cmd = next_cmd(cmd); 259398943Sluigi OR_BLOCK(get_proto); 259498943Sluigi 259598943Sluigi /* 259698943Sluigi * "from", mandatory (unless we have a MAC address) 259798943Sluigi */ 259898943Sluigi if (!ac || strncmp(*av, "from", strlen(*av))) { 259998943Sluigi if (have_mac) /* we do not need a "to" address */ 260098943Sluigi goto read_to; 260198943Sluigi errx(EX_USAGE, "missing ``from''"); 260298943Sluigi } 260398943Sluigi ac--; av++; 260498943Sluigi 260598943Sluigi /* 260698943Sluigi * source IP, mandatory 260798943Sluigi */ 260898943Sluigi OR_START(source_ip); 260998943Sluigi NOT_BLOCK; /* optional "not" */ 261098943Sluigi NEED1("missing source address"); 261198943Sluigi 261298943Sluigi /* source -- mandatory */ 261398943Sluigi fill_ip((ipfw_insn_ip *)cmd, *av); 261498943Sluigi if (cmd->opcode == O_IP_DST_SET) /* set */ 261598943Sluigi cmd->opcode = O_IP_SRC_SET; 261698943Sluigi else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) /* me */ 261798943Sluigi cmd->opcode = O_IP_SRC_ME; 261898943Sluigi else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn_u32)) /* one IP */ 261998943Sluigi cmd->opcode = O_IP_SRC; 262098943Sluigi else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn_ip)) /* addr/mask */ 262198943Sluigi cmd->opcode = O_IP_SRC_MASK; 262298943Sluigi /* otherwise len will be zero and the command skipped */ 262398943Sluigi ac--; av++; 262498943Sluigi prev = cmd; /* in case we need to backtrack */ 262598943Sluigi cmd = next_cmd(cmd); 262698943Sluigi OR_BLOCK(source_ip); 262798943Sluigi 2628101641Sluigi OR_START(source_port); 262998943Sluigi /* 263098943Sluigi * source ports, optional 263198943Sluigi */ 263298943Sluigi NOT_BLOCK; /* optional "not" */ 2633101641Sluigi if (ac) { 2634101641Sluigi if (!strncmp(*av, "any", strlen(*av))) { 2635101641Sluigi ac--; 2636101641Sluigi av++; 2637101641Sluigi } else if (fill_newports((ipfw_insn_u16 *)cmd, *av, proto)) { 2638101641Sluigi /* XXX todo: check that we have a protocol with ports */ 2639101641Sluigi cmd->opcode = O_IP_SRCPORT; 2640101641Sluigi ac--; 2641101641Sluigi av++; 2642101641Sluigi cmd = next_cmd(cmd); 2643101641Sluigi } 264498943Sluigi } 2645101641Sluigi OR_BLOCK(source_port); 264698943Sluigi 264798943Sluigiread_to: 264898943Sluigi /* 264998943Sluigi * "to", mandatory (unless we have a MAC address 265098943Sluigi */ 265198943Sluigi if (!ac || strncmp(*av, "to", strlen(*av))) { 265298943Sluigi if (have_mac) 265398943Sluigi goto read_options; 265498943Sluigi errx(EX_USAGE, "missing ``to''"); 265598943Sluigi } 265698943Sluigi av++; ac--; 265798943Sluigi 265898943Sluigi /* 265998943Sluigi * destination, mandatory 266098943Sluigi */ 266198943Sluigi OR_START(dest_ip); 266298943Sluigi NOT_BLOCK; /* optional "not" */ 266398943Sluigi NEED1("missing dst address"); 266498943Sluigi fill_ip((ipfw_insn_ip *)cmd, *av); 266598943Sluigi if (cmd->opcode == O_IP_DST_SET) /* set */ 266698943Sluigi ; 266798943Sluigi else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) /* me */ 266898943Sluigi cmd->opcode = O_IP_DST_ME; 266998943Sluigi else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn_u32)) /* one IP */ 267098943Sluigi cmd->opcode = O_IP_DST; 267198943Sluigi else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn_ip)) /* addr/mask */ 267298943Sluigi cmd->opcode = O_IP_DST_MASK; 267398943Sluigi ac--; 267498943Sluigi av++; 267598943Sluigi prev = cmd; 267698943Sluigi cmd = next_cmd(cmd); 267798943Sluigi OR_BLOCK(dest_ip); 267898943Sluigi 2679101641Sluigi OR_START(dest_port); 268098943Sluigi /* 268198943Sluigi * dest. ports, optional 268298943Sluigi */ 268398943Sluigi NOT_BLOCK; /* optional "not" */ 2684101641Sluigi if (ac) { 2685101641Sluigi if (!strncmp(*av, "any", strlen(*av))) { 2686101641Sluigi ac--; 2687101641Sluigi av++; 2688101641Sluigi } else if (fill_newports((ipfw_insn_u16 *)cmd, *av, proto)) { 2689101641Sluigi /* XXX todo: check that we have a protocol with ports */ 2690101641Sluigi cmd->opcode = O_IP_DSTPORT; 2691101641Sluigi ac--; 2692101641Sluigi av++; 2693101641Sluigi cmd += F_LEN(cmd); 2694101641Sluigi } 269598943Sluigi } 2696101641Sluigi OR_BLOCK(dest_port); 269798943Sluigi 269898943Sluigiread_options: 269998943Sluigi prev = NULL; 270098943Sluigi while (ac) { 2701101641Sluigi char *s; 2702101641Sluigi ipfw_insn_u32 *cmd32; /* alias for cmd */ 270398943Sluigi 2704101641Sluigi s = *av; 2705101641Sluigi cmd32 = (ipfw_insn_u32 *)cmd; 2706101641Sluigi 270798943Sluigi if (*s == '!') { /* alternate syntax for NOT */ 270898943Sluigi if (cmd->len & F_NOT) 270998943Sluigi errx(EX_USAGE, "double \"not\" not allowed\n"); 271098943Sluigi cmd->len = F_NOT; 271198943Sluigi s++; 271298943Sluigi } 271398943Sluigi i = match_token(rule_options, s); 271498943Sluigi ac--; av++; 271598943Sluigi switch(i) { 271698943Sluigi case TOK_NOT: 271798943Sluigi if (cmd->len & F_NOT) 271898943Sluigi errx(EX_USAGE, "double \"not\" not allowed\n"); 271998943Sluigi cmd->len = F_NOT; 272098943Sluigi break; 272198943Sluigi 272298943Sluigi case TOK_OR: 2723101641Sluigi if (open_par == 0 || prev == NULL) 272498943Sluigi errx(EX_USAGE, "invalid \"or\" block\n"); 272598943Sluigi prev->len |= F_OR; 272698943Sluigi break; 2727101641Sluigi 2728101641Sluigi case TOK_STARTBRACE: 2729101641Sluigi if (open_par) 2730101641Sluigi errx(EX_USAGE, "+nested \"(\" not allowed\n"); 2731101641Sluigi open_par = 1; 2732101641Sluigi break; 2733101641Sluigi 2734101641Sluigi case TOK_ENDBRACE: 2735101641Sluigi if (!open_par) 2736101641Sluigi errx(EX_USAGE, "+missing \")\"\n"); 2737101641Sluigi open_par = 0; 2738101641Sluigi break; 2739101641Sluigi 274098943Sluigi case TOK_IN: 274198943Sluigi fill_cmd(cmd, O_IN, 0, 0); 274298943Sluigi break; 274398943Sluigi 274498943Sluigi case TOK_OUT: 274598943Sluigi cmd->len ^= F_NOT; /* toggle F_NOT */ 274698943Sluigi fill_cmd(cmd, O_IN, 0, 0); 274798943Sluigi break; 274898943Sluigi 274998943Sluigi case TOK_FRAG: 275098943Sluigi fill_cmd(cmd, O_FRAG, 0, 0); 275198943Sluigi break; 275298943Sluigi 275398943Sluigi case TOK_LAYER2: 275498943Sluigi fill_cmd(cmd, O_LAYER2, 0, 0); 275598943Sluigi break; 275698943Sluigi 275798943Sluigi case TOK_XMIT: 275898943Sluigi case TOK_RECV: 275998943Sluigi case TOK_VIA: 276098943Sluigi NEED1("recv, xmit, via require interface name" 276198943Sluigi " or address"); 276298943Sluigi fill_iface((ipfw_insn_if *)cmd, av[0]); 276398943Sluigi ac--; av++; 276498943Sluigi if (F_LEN(cmd) == 0) /* not a valid address */ 276598943Sluigi break; 276698943Sluigi if (i == TOK_XMIT) 276798943Sluigi cmd->opcode = O_XMIT; 276898943Sluigi else if (i == TOK_RECV) 276998943Sluigi cmd->opcode = O_RECV; 277098943Sluigi else if (i == TOK_VIA) 277198943Sluigi cmd->opcode = O_VIA; 277298943Sluigi break; 277398943Sluigi 277499475Sluigi case TOK_ICMPTYPES: 277599475Sluigi NEED1("icmptypes requires list of types"); 277699475Sluigi fill_icmptypes((ipfw_insn_u32 *)cmd, *av); 277799475Sluigi av++; ac--; 277899475Sluigi break; 277999475Sluigi 278098943Sluigi case TOK_IPTTL: 278198943Sluigi NEED1("ipttl requires TTL"); 278298943Sluigi fill_cmd(cmd, O_IPTTL, 0, strtoul(*av, NULL, 0)); 278398943Sluigi ac--; av++; 278498943Sluigi break; 278598943Sluigi 278698943Sluigi case TOK_IPID: 278798943Sluigi NEED1("ipid requires length"); 278898943Sluigi fill_cmd(cmd, O_IPID, 0, strtoul(*av, NULL, 0)); 278998943Sluigi ac--; av++; 279098943Sluigi break; 279198943Sluigi 279298943Sluigi case TOK_IPLEN: 279398943Sluigi NEED1("iplen requires length"); 279498943Sluigi fill_cmd(cmd, O_IPLEN, 0, strtoul(*av, NULL, 0)); 279598943Sluigi ac--; av++; 279698943Sluigi break; 279798943Sluigi 279898943Sluigi case TOK_IPVER: 279998943Sluigi NEED1("ipver requires version"); 280098943Sluigi fill_cmd(cmd, O_IPVER, 0, strtoul(*av, NULL, 0)); 280198943Sluigi ac--; av++; 280298943Sluigi break; 280398943Sluigi 280499475Sluigi case TOK_IPPRECEDENCE: 280599475Sluigi NEED1("ipprecedence requires value"); 280699475Sluigi fill_cmd(cmd, O_IPPRECEDENCE, 0, 280799475Sluigi (strtoul(*av, NULL, 0) & 7) << 5); 280899475Sluigi ac--; av++; 280999475Sluigi break; 281099475Sluigi 281198943Sluigi case TOK_IPOPTS: 281298943Sluigi NEED1("missing argument for ipoptions"); 2813101116Sluigi fill_flags(cmd, O_IPOPT, f_ipopts, *av); 281498943Sluigi ac--; av++; 281598943Sluigi break; 281698943Sluigi 281799475Sluigi case TOK_IPTOS: 281899475Sluigi NEED1("missing argument for iptos"); 2819101116Sluigi fill_flags(cmd, O_IPTOS, f_iptos, *av); 282099475Sluigi ac--; av++; 282199475Sluigi break; 282299475Sluigi 282398943Sluigi case TOK_UID: 282498943Sluigi NEED1("uid requires argument"); 282598943Sluigi { 282698943Sluigi char *end; 282798943Sluigi uid_t uid; 282898943Sluigi struct passwd *pwd; 282998943Sluigi 283098943Sluigi cmd->opcode = O_UID; 283198943Sluigi uid = strtoul(*av, &end, 0); 283298943Sluigi pwd = (*end == '\0') ? getpwuid(uid) : getpwnam(*av); 283398943Sluigi if (pwd == NULL) 283498943Sluigi errx(EX_DATAERR, "uid \"%s\" nonexistent", *av); 283598943Sluigi cmd32->d[0] = uid; 283698943Sluigi cmd->len = F_INSN_SIZE(ipfw_insn_u32); 283798943Sluigi ac--; av++; 283898943Sluigi } 283998943Sluigi break; 284098943Sluigi 284198943Sluigi case TOK_GID: 284298943Sluigi NEED1("gid requires argument"); 284398943Sluigi { 284498943Sluigi char *end; 284598943Sluigi gid_t gid; 284698943Sluigi struct group *grp; 284798943Sluigi 284898943Sluigi cmd->opcode = O_GID; 284998943Sluigi gid = strtoul(*av, &end, 0); 285098943Sluigi grp = (*end == '\0') ? getgrgid(gid) : getgrnam(*av); 285198943Sluigi if (grp == NULL) 285298943Sluigi errx(EX_DATAERR, "gid \"%s\" nonexistent", *av); 285398943Sluigi 285498943Sluigi cmd32->d[0] = gid; 285598943Sluigi cmd->len = F_INSN_SIZE(ipfw_insn_u32); 285698943Sluigi ac--; av++; 285798943Sluigi } 285898943Sluigi break; 285998943Sluigi 286098943Sluigi case TOK_ESTAB: 286198943Sluigi fill_cmd(cmd, O_ESTAB, 0, 0); 286298943Sluigi break; 286398943Sluigi 286498943Sluigi case TOK_SETUP: 286598943Sluigi fill_cmd(cmd, O_TCPFLAGS, 0, 286698943Sluigi (TH_SYN) | ( (TH_ACK) & 0xff) <<8 ); 286798943Sluigi break; 286898943Sluigi 286998943Sluigi case TOK_TCPOPTS: 287098943Sluigi NEED1("missing argument for tcpoptions"); 287198943Sluigi fill_flags(cmd, O_TCPOPTS, f_tcpopts, *av); 287298943Sluigi ac--; av++; 287398943Sluigi break; 287498943Sluigi 287598943Sluigi case TOK_TCPSEQ: 287698943Sluigi case TOK_TCPACK: 287798943Sluigi NEED1("tcpseq/tcpack requires argument"); 287898943Sluigi cmd->len = F_INSN_SIZE(ipfw_insn_u32); 287998943Sluigi cmd->opcode = (i == TOK_TCPSEQ) ? O_TCPSEQ : O_TCPACK; 288098943Sluigi cmd32->d[0] = htonl(strtoul(*av, NULL, 0)); 288198943Sluigi ac--; av++; 288298943Sluigi break; 288398943Sluigi 288498943Sluigi case TOK_TCPWIN: 288598943Sluigi NEED1("tcpwin requires length"); 288698943Sluigi fill_cmd(cmd, O_TCPWIN, 0, 288798943Sluigi htons(strtoul(*av, NULL, 0))); 288898943Sluigi ac--; av++; 288998943Sluigi break; 289098943Sluigi 289198943Sluigi case TOK_TCPFLAGS: 289298943Sluigi NEED1("missing argument for tcpflags"); 289398943Sluigi cmd->opcode = O_TCPFLAGS; 289498943Sluigi fill_flags(cmd, O_TCPFLAGS, f_tcpflags, *av); 289598943Sluigi ac--; av++; 289698943Sluigi break; 289798943Sluigi 289898943Sluigi case TOK_KEEPSTATE: 2899101641Sluigi if (open_par) 2900101641Sluigi errx(EX_USAGE, "keep-state cannot be part " 2901101641Sluigi "of an or block"); 290299909Sluigi if (have_state) 2903101116Sluigi errx(EX_USAGE, "only one of keep-state " 290499909Sluigi "and limit is allowed"); 2905101116Sluigi have_state = cmd; 290698943Sluigi fill_cmd(cmd, O_KEEP_STATE, 0, 0); 290798943Sluigi break; 290898943Sluigi 290998943Sluigi case TOK_LIMIT: 2910101641Sluigi if (open_par) 2911101641Sluigi errx(EX_USAGE, "limit cannot be part " 2912101641Sluigi "of an or block"); 291399909Sluigi if (have_state) 2914101116Sluigi errx(EX_USAGE, "only one of keep-state " 291599909Sluigi "and limit is allowed"); 2916101641Sluigi NEED1("limit needs mask and # of connections"); 2917101116Sluigi have_state = cmd; 291898943Sluigi { 291998943Sluigi ipfw_insn_limit *c = (ipfw_insn_limit *)cmd; 292098943Sluigi 292198943Sluigi cmd->len = F_INSN_SIZE(ipfw_insn_limit); 292298943Sluigi cmd->opcode = O_LIMIT; 292398943Sluigi c->limit_mask = 0; 292498943Sluigi c->conn_limit = 0; 292598943Sluigi for (; ac >1 ;) { 292698943Sluigi int val; 292798943Sluigi 292898943Sluigi val = match_token(limit_masks, *av); 292998943Sluigi if (val <= 0) 293098943Sluigi break; 293198943Sluigi c->limit_mask |= val; 293298943Sluigi ac--; av++; 293398943Sluigi } 293498943Sluigi c->conn_limit = atoi(*av); 293598943Sluigi if (c->conn_limit == 0) 293698943Sluigi errx(EX_USAGE, "limit: limit must be >0"); 293798943Sluigi if (c->limit_mask == 0) 293898943Sluigi errx(EX_USAGE, "missing limit mask"); 293998943Sluigi ac--; av++; 294098943Sluigi } 294198943Sluigi break; 294298943Sluigi 294398943Sluigi default: 294498943Sluigi errx(EX_USAGE, "unrecognised option [%d] %s\n", i, s); 294598943Sluigi } 294698943Sluigi if (F_LEN(cmd) > 0) { /* prepare to advance */ 294798943Sluigi prev = cmd; 294898943Sluigi cmd = next_cmd(cmd); 294998943Sluigi } 295098943Sluigi } 295198943Sluigi 295298943Sluigidone: 295398943Sluigi /* 295498943Sluigi * Now copy stuff into the rule. 295598943Sluigi * If we have a keep-state option, the first instruction 295698943Sluigi * must be a PROBE_STATE (which is generated here). 295798943Sluigi * If we have a LOG option, it was stored as the first command, 295898943Sluigi * and now must be moved to the top of the action part. 295998943Sluigi */ 296098943Sluigi dst = (ipfw_insn *)rule->cmd; 296198943Sluigi 296298943Sluigi /* 296398943Sluigi * generate O_PROBE_STATE if necessary 296498943Sluigi */ 2965101116Sluigi if (have_state && have_state->opcode != O_CHECK_STATE) { 296698943Sluigi fill_cmd(dst, O_PROBE_STATE, 0, 0); 296798943Sluigi dst = next_cmd(dst); 296898943Sluigi } 296998943Sluigi /* 2970101116Sluigi * copy all commands but O_LOG, O_KEEP_STATE, O_LIMIT 297198943Sluigi */ 297298943Sluigi for (src = (ipfw_insn *)cmdbuf; src != cmd; src += i) { 297398943Sluigi i = F_LEN(src); 297498943Sluigi 2975101116Sluigi switch (src->opcode) { 2976101116Sluigi case O_LOG: 2977101116Sluigi case O_KEEP_STATE: 2978101116Sluigi case O_LIMIT: 2979101116Sluigi break; 2980101116Sluigi default: 298198943Sluigi bcopy(src, dst, i * sizeof(u_int32_t)); 298298943Sluigi dst += i; 298398943Sluigi } 298498943Sluigi } 298598943Sluigi 298698943Sluigi /* 2987101116Sluigi * put back the have_state command as last opcode 2988101116Sluigi */ 2989101295Sluigi if (have_state && have_state->opcode != O_CHECK_STATE) { 2990101116Sluigi i = F_LEN(have_state); 2991101116Sluigi bcopy(have_state, dst, i * sizeof(u_int32_t)); 2992101116Sluigi dst += i; 2993101116Sluigi } 2994101116Sluigi /* 299598943Sluigi * start action section 299698943Sluigi */ 299798943Sluigi rule->act_ofs = dst - rule->cmd; 299898943Sluigi 299998943Sluigi /* 300098943Sluigi * put back O_LOG if necessary 300198943Sluigi */ 300298943Sluigi src = (ipfw_insn *)cmdbuf; 300398943Sluigi if ( src->opcode == O_LOG ) { 300498943Sluigi i = F_LEN(src); 300598943Sluigi bcopy(src, dst, i * sizeof(u_int32_t)); 300698943Sluigi dst += i; 300798943Sluigi } 300898943Sluigi /* 300998943Sluigi * copy all other actions 301098943Sluigi */ 301198943Sluigi for (src = (ipfw_insn *)actbuf; src != action; src += i) { 301298943Sluigi i = F_LEN(src); 301398943Sluigi bcopy(src, dst, i * sizeof(u_int32_t)); 301498943Sluigi dst += i; 301598943Sluigi } 301698943Sluigi 301798943Sluigi rule->cmd_len = (u_int32_t *)dst - (u_int32_t *)(rule->cmd); 301898943Sluigi i = (void *)dst - (void *)rule; 301998943Sluigi if (getsockopt(s, IPPROTO_IP, IP_FW_ADD, rule, &i) == -1) 302098943Sluigi err(EX_UNAVAILABLE, "getsockopt(%s)", "IP_FW_ADD"); 302198943Sluigi if (!do_quiet) 302298943Sluigi show_ipfw(rule); 302398943Sluigi} 302498943Sluigi 302598943Sluigistatic void 3026101978Sluigizero(int ac, char *av[]) 302798943Sluigi{ 302898943Sluigi int rulenum; 302998943Sluigi int failed = EX_OK; 303098943Sluigi 303198943Sluigi av++; ac--; 303298943Sluigi 303398943Sluigi if (!ac) { 303498943Sluigi /* clear all entries */ 303598943Sluigi if (setsockopt(s, IPPROTO_IP, IP_FW_ZERO, NULL, 0) < 0) 303698943Sluigi err(EX_UNAVAILABLE, "setsockopt(%s)", "IP_FW_ZERO"); 303798943Sluigi if (!do_quiet) 303898943Sluigi printf("Accounting cleared.\n"); 303998943Sluigi 304098943Sluigi return; 304198943Sluigi } 304298943Sluigi 304398943Sluigi while (ac) { 304498943Sluigi /* Rule number */ 304598943Sluigi if (isdigit(**av)) { 304698943Sluigi rulenum = atoi(*av); 304798943Sluigi av++; 304898943Sluigi ac--; 304998943Sluigi if (setsockopt(s, IPPROTO_IP, 305098943Sluigi IP_FW_ZERO, &rulenum, sizeof rulenum)) { 305198943Sluigi warn("rule %u: setsockopt(IP_FW_ZERO)", 305298943Sluigi rulenum); 305398943Sluigi failed = EX_UNAVAILABLE; 305498943Sluigi } else if (!do_quiet) 305598943Sluigi printf("Entry %d cleared\n", rulenum); 305698943Sluigi } else { 305798943Sluigi errx(EX_USAGE, "invalid rule number ``%s''", *av); 305898943Sluigi } 305998943Sluigi } 306098943Sluigi if (failed != EX_OK) 306198943Sluigi exit(failed); 306298943Sluigi} 306398943Sluigi 306498943Sluigistatic void 3065101978Sluigiresetlog(int ac, char *av[]) 306698943Sluigi{ 306798943Sluigi int rulenum; 306898943Sluigi int failed = EX_OK; 306998943Sluigi 307098943Sluigi av++; ac--; 307198943Sluigi 307298943Sluigi if (!ac) { 307398943Sluigi /* clear all entries */ 307498943Sluigi if (setsockopt(s, IPPROTO_IP, IP_FW_RESETLOG, NULL, 0) < 0) 307598943Sluigi err(EX_UNAVAILABLE, "setsockopt(IP_FW_RESETLOG)"); 307698943Sluigi if (!do_quiet) 307798943Sluigi printf("Logging counts reset.\n"); 307898943Sluigi 307998943Sluigi return; 308098943Sluigi } 308198943Sluigi 308298943Sluigi while (ac) { 308398943Sluigi /* Rule number */ 308498943Sluigi if (isdigit(**av)) { 308598943Sluigi rulenum = atoi(*av); 308698943Sluigi av++; 308798943Sluigi ac--; 308898943Sluigi if (setsockopt(s, IPPROTO_IP, 308998943Sluigi IP_FW_RESETLOG, &rulenum, sizeof rulenum)) { 309098943Sluigi warn("rule %u: setsockopt(IP_FW_RESETLOG)", 309198943Sluigi rulenum); 309298943Sluigi failed = EX_UNAVAILABLE; 309398943Sluigi } else if (!do_quiet) 309498943Sluigi printf("Entry %d logging count reset\n", 309598943Sluigi rulenum); 309698943Sluigi } else { 309798943Sluigi errx(EX_DATAERR, "invalid rule number ``%s''", *av); 309898943Sluigi } 309998943Sluigi } 310098943Sluigi if (failed != EX_OK) 310198943Sluigi exit(failed); 310298943Sluigi} 310398943Sluigi 310498943Sluigistatic void 310598943Sluigiflush() 310698943Sluigi{ 310798943Sluigi int cmd = do_pipe ? IP_DUMMYNET_FLUSH : IP_FW_FLUSH; 310898943Sluigi 310998943Sluigi if (!do_force && !do_quiet) { /* need to ask user */ 311098943Sluigi int c; 311198943Sluigi 311298943Sluigi printf("Are you sure? [yn] "); 311398943Sluigi fflush(stdout); 311498943Sluigi do { 311598943Sluigi c = toupper(getc(stdin)); 311698943Sluigi while (c != '\n' && getc(stdin) != '\n') 311798943Sluigi if (feof(stdin)) 311898943Sluigi return; /* and do not flush */ 311998943Sluigi } while (c != 'Y' && c != 'N'); 312098943Sluigi printf("\n"); 312198943Sluigi if (c == 'N') /* user said no */ 312298943Sluigi return; 312398943Sluigi } 312498943Sluigi if (setsockopt(s, IPPROTO_IP, cmd, NULL, 0) < 0) 312598943Sluigi err(EX_UNAVAILABLE, "setsockopt(IP_%s_FLUSH)", 312698943Sluigi do_pipe ? "DUMMYNET" : "FW"); 312798943Sluigi if (!do_quiet) 312898943Sluigi printf("Flushed all %s.\n", do_pipe ? "pipes" : "rules"); 312998943Sluigi} 313098943Sluigi 313198943Sluigistatic int 313298943Sluigiipfw_main(int ac, char **av) 313398943Sluigi{ 313498943Sluigi int ch; 313598943Sluigi 313698943Sluigi if (ac == 1) 313798943Sluigi show_usage(); 313898943Sluigi 313998943Sluigi /* Set the force flag for non-interactive processes */ 314098943Sluigi do_force = !isatty(STDIN_FILENO); 314198943Sluigi 314298943Sluigi optind = optreset = 1; 3143101628Sluigi while ((ch = getopt(ac, av, "hs:adefNqStv")) != -1) 314498943Sluigi switch (ch) { 314598943Sluigi case 'h': /* help */ 314698943Sluigi help(); 314798943Sluigi break; /* NOTREACHED */ 314898943Sluigi 314998943Sluigi case 's': /* sort */ 315098943Sluigi do_sort = atoi(optarg); 315198943Sluigi break; 315298943Sluigi case 'a': 315398943Sluigi do_acct = 1; 315498943Sluigi break; 315598943Sluigi case 'd': 315698943Sluigi do_dynamic = 1; 315798943Sluigi break; 315898943Sluigi case 'e': 315998943Sluigi do_expired = 1; 316098943Sluigi break; 316198943Sluigi case 'f': 316298943Sluigi do_force = 1; 316398943Sluigi break; 316498943Sluigi case 'N': 316598943Sluigi do_resolv = 1; 316698943Sluigi break; 316798943Sluigi case 'q': 316898943Sluigi do_quiet = 1; 316998943Sluigi break; 3170101628Sluigi case 'S': 3171101628Sluigi show_sets = 1; 3172101628Sluigi break; 317398943Sluigi case 't': 317498943Sluigi do_time = 1; 317598943Sluigi break; 317698943Sluigi case 'v': /* verbose */ 317798943Sluigi verbose++; 317898943Sluigi break; 317998943Sluigi default: 318098943Sluigi show_usage(); 318198943Sluigi } 318298943Sluigi 318398943Sluigi ac -= optind; 318498943Sluigi av += optind; 318598943Sluigi NEED1("bad arguments, for usage summary ``ipfw''"); 318698943Sluigi 318798943Sluigi /* 318898943Sluigi * optional: pipe or queue 318998943Sluigi */ 319098943Sluigi if (!strncmp(*av, "pipe", strlen(*av))) { 319198943Sluigi do_pipe = 1; 319298943Sluigi ac--; 319398943Sluigi av++; 319498943Sluigi } else if (!strncmp(*av, "queue", strlen(*av))) { 319598943Sluigi do_pipe = 2; 319698943Sluigi ac--; 319798943Sluigi av++; 319898943Sluigi } 319998943Sluigi NEED1("missing command"); 320098943Sluigi 320198943Sluigi /* 320298943Sluigi * for pipes and queues we normally say 'pipe NN config' 320398943Sluigi * but the code is easier to parse as 'pipe config NN' 320498943Sluigi * so we swap the two arguments. 320598943Sluigi */ 320698943Sluigi if (do_pipe > 0 && ac > 1 && *av[0] >= '0' && *av[0] <= '9') { 320798943Sluigi char *p = av[0]; 320898943Sluigi av[0] = av[1]; 320998943Sluigi av[1] = p; 321098943Sluigi } 321198943Sluigi if (!strncmp(*av, "add", strlen(*av))) 321298943Sluigi add(ac, av); 321398943Sluigi else if (do_pipe && !strncmp(*av, "config", strlen(*av))) 321498943Sluigi config_pipe(ac, av); 3215101978Sluigi else if (!strncmp(*av, "delete", strlen(*av))) 321698943Sluigi delete(ac, av); 321798943Sluigi else if (!strncmp(*av, "flush", strlen(*av))) 321898943Sluigi flush(); 321998943Sluigi else if (!strncmp(*av, "zero", strlen(*av))) 322098943Sluigi zero(ac, av); 322198943Sluigi else if (!strncmp(*av, "resetlog", strlen(*av))) 322298943Sluigi resetlog(ac, av); 322398943Sluigi else if (!strncmp(*av, "print", strlen(*av)) || 322498943Sluigi !strncmp(*av, "list", strlen(*av))) 322598943Sluigi list(ac, av); 3226101978Sluigi else if (!strncmp(*av, "set", strlen(*av))) 3227101978Sluigi sets_handler(ac, av); 322898943Sluigi else if (!strncmp(*av, "show", strlen(*av))) { 322998943Sluigi do_acct++; 323098943Sluigi list(ac, av); 323198943Sluigi } else 323298943Sluigi errx(EX_USAGE, "bad command `%s'", *av); 323398943Sluigi return 0; 323498943Sluigi} 323598943Sluigi 323698943Sluigi 323798943Sluigistatic void 323898943Sluigiipfw_readfile(int ac, char *av[]) 323998943Sluigi{ 324098943Sluigi#define MAX_ARGS 32 324198943Sluigi#define WHITESP " \t\f\v\n\r" 324298943Sluigi char buf[BUFSIZ]; 324398943Sluigi char *a, *p, *args[MAX_ARGS], *cmd = NULL; 324498943Sluigi char linename[10]; 324598943Sluigi int i=0, lineno=0, qflag=0, pflag=0, status; 324698943Sluigi FILE *f = NULL; 324798943Sluigi pid_t preproc = 0; 324898943Sluigi int c; 324998943Sluigi 325098943Sluigi while ((c = getopt(ac, av, "D:U:p:q")) != -1) 325198943Sluigi switch(c) { 325298943Sluigi case 'D': 325398943Sluigi if (!pflag) 325498943Sluigi errx(EX_USAGE, "-D requires -p"); 325598943Sluigi if (i > MAX_ARGS - 2) 325698943Sluigi errx(EX_USAGE, 325798943Sluigi "too many -D or -U options"); 325898943Sluigi args[i++] = "-D"; 325998943Sluigi args[i++] = optarg; 326098943Sluigi break; 326198943Sluigi 326298943Sluigi case 'U': 326398943Sluigi if (!pflag) 326498943Sluigi errx(EX_USAGE, "-U requires -p"); 326598943Sluigi if (i > MAX_ARGS - 2) 326698943Sluigi errx(EX_USAGE, 326798943Sluigi "too many -D or -U options"); 326898943Sluigi args[i++] = "-U"; 326998943Sluigi args[i++] = optarg; 327098943Sluigi break; 327198943Sluigi 327298943Sluigi case 'p': 327398943Sluigi pflag = 1; 327498943Sluigi cmd = optarg; 327598943Sluigi args[0] = cmd; 327698943Sluigi i = 1; 327798943Sluigi break; 327898943Sluigi 327998943Sluigi case 'q': 328098943Sluigi qflag = 1; 328198943Sluigi break; 328298943Sluigi 328398943Sluigi default: 328498943Sluigi errx(EX_USAGE, "bad arguments, for usage" 328598943Sluigi " summary ``ipfw''"); 328698943Sluigi } 328798943Sluigi 328898943Sluigi av += optind; 328998943Sluigi ac -= optind; 329098943Sluigi if (ac != 1) 329198943Sluigi errx(EX_USAGE, "extraneous filename arguments"); 329298943Sluigi 329398943Sluigi if ((f = fopen(av[0], "r")) == NULL) 329498943Sluigi err(EX_UNAVAILABLE, "fopen: %s", av[0]); 329598943Sluigi 329698943Sluigi if (pflag) { 329798943Sluigi /* pipe through preprocessor (cpp or m4) */ 329898943Sluigi int pipedes[2]; 329998943Sluigi 330098943Sluigi args[i] = 0; 330198943Sluigi 330298943Sluigi if (pipe(pipedes) == -1) 330398943Sluigi err(EX_OSERR, "cannot create pipe"); 330498943Sluigi 330598943Sluigi switch((preproc = fork())) { 330698943Sluigi case -1: 330798943Sluigi err(EX_OSERR, "cannot fork"); 330898943Sluigi 330998943Sluigi case 0: 331098943Sluigi /* child */ 331198943Sluigi if (dup2(fileno(f), 0) == -1 331298943Sluigi || dup2(pipedes[1], 1) == -1) 331398943Sluigi err(EX_OSERR, "dup2()"); 331498943Sluigi fclose(f); 331598943Sluigi close(pipedes[1]); 331698943Sluigi close(pipedes[0]); 331798943Sluigi execvp(cmd, args); 331898943Sluigi err(EX_OSERR, "execvp(%s) failed", cmd); 331998943Sluigi 332098943Sluigi default: 332198943Sluigi /* parent */ 332298943Sluigi fclose(f); 332398943Sluigi close(pipedes[1]); 332498943Sluigi if ((f = fdopen(pipedes[0], "r")) == NULL) { 332598943Sluigi int savederrno = errno; 332698943Sluigi 332798943Sluigi (void)kill(preproc, SIGTERM); 332898943Sluigi errno = savederrno; 332998943Sluigi err(EX_OSERR, "fdopen()"); 333098943Sluigi } 333198943Sluigi } 333298943Sluigi } 333398943Sluigi 333498943Sluigi while (fgets(buf, BUFSIZ, f)) { 333598943Sluigi lineno++; 333698943Sluigi sprintf(linename, "Line %d", lineno); 333798943Sluigi args[0] = linename; 333898943Sluigi 333998943Sluigi if (*buf == '#') 334098943Sluigi continue; 334198943Sluigi if ((p = strchr(buf, '#')) != NULL) 334298943Sluigi *p = '\0'; 334398943Sluigi i = 1; 334498943Sluigi if (qflag) 334598943Sluigi args[i++] = "-q"; 334698943Sluigi for (a = strtok(buf, WHITESP); 334798943Sluigi a && i < MAX_ARGS; a = strtok(NULL, WHITESP), i++) 334898943Sluigi args[i] = a; 334998943Sluigi if (i == (qflag? 2: 1)) 335098943Sluigi continue; 335198943Sluigi if (i == MAX_ARGS) 335298943Sluigi errx(EX_USAGE, "%s: too many arguments", 335398943Sluigi linename); 335498943Sluigi args[i] = NULL; 335598943Sluigi 335698943Sluigi ipfw_main(i, args); 335798943Sluigi } 335898943Sluigi fclose(f); 335998943Sluigi if (pflag) { 336098943Sluigi if (waitpid(preproc, &status, 0) == -1) 336198943Sluigi errx(EX_OSERR, "waitpid()"); 336298943Sluigi if (WIFEXITED(status) && WEXITSTATUS(status) != EX_OK) 336398943Sluigi errx(EX_UNAVAILABLE, 336498943Sluigi "preprocessor exited with status %d", 336598943Sluigi WEXITSTATUS(status)); 336698943Sluigi else if (WIFSIGNALED(status)) 336798943Sluigi errx(EX_UNAVAILABLE, 336898943Sluigi "preprocessor exited with signal %d", 336998943Sluigi WTERMSIG(status)); 337098943Sluigi } 337198943Sluigi} 337298943Sluigi 337398943Sluigiint 337498943Sluigimain(int ac, char *av[]) 337598943Sluigi{ 337698943Sluigi s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); 337798943Sluigi if (s < 0) 337898943Sluigi err(EX_UNAVAILABLE, "socket"); 337998943Sluigi 338098943Sluigi /* 338198943Sluigi * If the last argument is an absolute pathname, interpret it 338298943Sluigi * as a file to be preprocessed. 338398943Sluigi */ 338498943Sluigi 338598943Sluigi if (ac > 1 && av[ac - 1][0] == '/' && access(av[ac - 1], R_OK) == 0) 338698943Sluigi ipfw_readfile(ac, av); 338798943Sluigi else 338898943Sluigi ipfw_main(ac, av); 338998943Sluigi return EX_OK; 339098943Sluigi} 3391