ipfw2.c revision 205179
1212420Sken/* 2212420Sken * Copyright (c) 2002-2003 Luigi Rizzo 3237683Sken * Copyright (c) 1996 Alex Nash, Paul Traina, Poul-Henning Kamp 4212420Sken * Copyright (c) 1994 Ugen J.S.Antsilevich 5212420Sken * 6212420Sken * Idea and grammar partially left from: 7212420Sken * Copyright (c) 1993 Daniel Boulet 8212420Sken * 9212420Sken * Redistribution and use in source forms, with and without modification, 10212420Sken * are permitted provided that this entire comment appears intact. 11212420Sken * 12212420Sken * Redistribution in binary form may occur without any restrictions. 13212420Sken * Obviously, it would be nice if you gave credit where credit is due 14212420Sken * but requiring it would be too onerous. 15212420Sken * 16212420Sken * This software is provided ``AS IS'' without any warranties of any kind. 17212420Sken * 18212420Sken * NEW command line interface for IP firewall facility 19212420Sken * 20212420Sken * $FreeBSD: head/sbin/ipfw/ipfw2.c 205179 2010-03-15 18:20:51Z luigi $ 21212420Sken */ 22212420Sken 23212420Sken#include <sys/types.h> 24212420Sken#include <sys/socket.h> 25212420Sken#include <sys/sockio.h> 26230592Sken#include <sys/sysctl.h> 27230592Sken 28230592Sken#include "ipfw2.h" 29230592Sken 30230592Sken#include <ctype.h> 31212420Sken#include <err.h> 32212420Sken#include <errno.h> 33212420Sken#include <grp.h> 34212420Sken#include <netdb.h> 35212420Sken#include <pwd.h> 36212420Sken#include <stdio.h> 37230592Sken#include <stdlib.h> 38212420Sken#include <string.h> 39212420Sken#include <sysexits.h> 40212420Sken#include <time.h> /* ctime */ 41212420Sken#include <timeconv.h> /* _long_to_time */ 42212420Sken#include <unistd.h> 43212420Sken#include <fcntl.h> 44212420Sken 45212420Sken#include <net/ethernet.h> 46212420Sken#include <net/if.h> /* only IFNAMSIZ */ 47212420Sken#include <netinet/in.h> 48212420Sken#include <netinet/in_systm.h> /* only n_short, n_long */ 49212420Sken#include <netinet/ip.h> 50216088Sken#include <netinet/ip_icmp.h> 51230592Sken#include <netinet/ip_fw.h> 52230592Sken#include <netinet/tcp.h> 53230592Sken#include <arpa/inet.h> 54230592Sken 55212420Skenstruct cmdline_opts co; /* global options */ 56212420Sken 57212420Skenint resvd_set_number = RESVD_SET; 58212420Sken 59212420Sken#define GET_UINT_ARG(arg, min, max, tok, s_x) do { \ 60230592Sken if (!av[0]) \ 61230592Sken errx(EX_USAGE, "%s: missing argument", match_value(s_x, tok)); \ 62212420Sken if (_substrcmp(*av, "tablearg") == 0) { \ 63212420Sken arg = IP_FW_TABLEARG; \ 64230592Sken break; \ 65212420Sken } \ 66212420Sken \ 67212420Sken { \ 68212420Sken long _xval; \ 69212420Sken char *end; \ 70212420Sken \ 71212420Sken _xval = strtol(*av, &end, 10); \ 72216088Sken \ 73216088Sken if (!isdigit(**av) || *end != '\0' || (_xval == 0 && errno == EINVAL)) \ 74216088Sken errx(EX_DATAERR, "%s: invalid argument: %s", \ 75212420Sken match_value(s_x, tok), *av); \ 76212420Sken \ 77212420Sken if (errno == ERANGE || _xval < min || _xval > max) \ 78212420Sken errx(EX_DATAERR, "%s: argument is out of range (%u..%u): %s", \ 79212420Sken match_value(s_x, tok), min, max, *av); \ 80212420Sken \ 81212420Sken if (_xval == IP_FW_TABLEARG) \ 82230592Sken errx(EX_DATAERR, "%s: illegal argument value: %s", \ 83230592Sken match_value(s_x, tok), *av); \ 84212420Sken arg = _xval; \ 85212420Sken } \ 86230592Sken} while (0) 87212420Sken 88230592Skenstatic void 89230592SkenPRINT_UINT_ARG(const char *str, uint32_t arg) 90212420Sken{ 91230592Sken if (str != NULL) 92230592Sken printf("%s",str); 93230592Sken if (arg == IP_FW_TABLEARG) 94230592Sken printf("tablearg"); 95230592Sken else 96230592Sken printf("%u", arg); 97230592Sken} 98230592Sken 99230592Skenstatic struct _s_x f_tcpflags[] = { 100230592Sken { "syn", TH_SYN }, 101230592Sken { "fin", TH_FIN }, 102230592Sken { "ack", TH_ACK }, 103230592Sken { "psh", TH_PUSH }, 104230592Sken { "rst", TH_RST }, 105230592Sken { "urg", TH_URG }, 106230592Sken { "tcp flag", 0 }, 107230592Sken { NULL, 0 } 108230592Sken}; 109230592Sken 110230592Skenstatic struct _s_x f_tcpopts[] = { 111230592Sken { "mss", IP_FW_TCPOPT_MSS }, 112230592Sken { "maxseg", IP_FW_TCPOPT_MSS }, 113230592Sken { "window", IP_FW_TCPOPT_WINDOW }, 114212420Sken { "sack", IP_FW_TCPOPT_SACK }, 115212420Sken { "ts", IP_FW_TCPOPT_TS }, 116230592Sken { "timestamp", IP_FW_TCPOPT_TS }, 117212420Sken { "cc", IP_FW_TCPOPT_CC }, 118212420Sken { "tcp option", 0 }, 119212420Sken { NULL, 0 } 120212420Sken}; 121212420Sken 122212420Sken/* 123212420Sken * IP options span the range 0 to 255 so we need to remap them 124230592Sken * (though in fact only the low 5 bits are significant). 125230592Sken */ 126212420Skenstatic struct _s_x f_ipopts[] = { 127212420Sken { "ssrr", IP_FW_IPOPT_SSRR}, 128230592Sken { "lsrr", IP_FW_IPOPT_LSRR}, 129216088Sken { "rr", IP_FW_IPOPT_RR}, 130216088Sken { "ts", IP_FW_IPOPT_TS}, 131216088Sken { "ip option", 0 }, 132216088Sken { NULL, 0 } 133216088Sken}; 134230592Sken 135212420Skenstatic struct _s_x f_iptos[] = { 136230592Sken { "lowdelay", IPTOS_LOWDELAY}, 137230592Sken { "throughput", IPTOS_THROUGHPUT}, 138230592Sken { "reliability", IPTOS_RELIABILITY}, 139230592Sken { "mincost", IPTOS_MINCOST}, 140253549Sken { "congestion", IPTOS_ECN_CE}, 141253549Sken { "ecntransport", IPTOS_ECN_ECT0}, 142253549Sken { "ip tos option", 0}, 143253549Sken { NULL, 0 } 144230592Sken}; 145230592Sken 146230592Skenstatic struct _s_x limit_masks[] = { 147230592Sken {"all", DYN_SRC_ADDR|DYN_SRC_PORT|DYN_DST_ADDR|DYN_DST_PORT}, 148230592Sken {"src-addr", DYN_SRC_ADDR}, 149212420Sken {"src-port", DYN_SRC_PORT}, 150231240Sken {"dst-addr", DYN_DST_ADDR}, 151230592Sken {"dst-port", DYN_DST_PORT}, 152216368Sken {NULL, 0} 153230592Sken}; 154230592Sken 155216368Sken/* 156264492Sscottl * we use IPPROTO_ETHERTYPE as a fake protocol id to call the print routines 157230592Sken * This is only used in this code. 158230592Sken */ 159230592Sken#define IPPROTO_ETHERTYPE 0x1000 160216368Skenstatic struct _s_x ether_types[] = { 161216368Sken /* 162230592Sken * Note, we cannot use "-:&/" in the names because they are field 163216368Sken * separators in the type specifications. Also, we use s = NULL as 164216368Sken * end-delimiter, because a type of 0 can be legal. 165230592Sken */ 166230592Sken { "ip", 0x0800 }, 167230592Sken { "ipv4", 0x0800 }, 168230592Sken { "ipv6", 0x86dd }, 169230592Sken { "arp", 0x0806 }, 170230592Sken { "rarp", 0x8035 }, 171230592Sken { "vlan", 0x8100 }, 172230592Sken { "loop", 0x9000 }, 173230592Sken { "trail", 0x1000 }, 174212420Sken { "at", 0x809b }, 175253460Sscottl { "atalk", 0x809b }, 176253460Sscottl { "aarp", 0x80f3 }, 177230592Sken { "pppoe_disc", 0x8863 }, 178230592Sken { "pppoe_sess", 0x8864 }, 179230592Sken { "ipx_8022", 0x00E0 }, 180253460Sscottl { "ipx_8023", 0x0000 }, 181230592Sken { "ipx_ii", 0x8137 }, 182262853Smav { "ipx_snap", 0x8137 }, 183262853Smav { "ipx", 0x8137 }, 184262853Smav { "ns", 0x0600 }, 185230592Sken { NULL, 0 } 186230592Sken}; 187253460Sscottl 188230592Sken 189230592Skenstatic struct _s_x rule_actions[] = { 190230592Sken { "accept", TOK_ACCEPT }, 191212420Sken { "pass", TOK_ACCEPT }, 192230592Sken { "allow", TOK_ACCEPT }, 193270250Sslm { "permit", TOK_ACCEPT }, 194270250Sslm { "count", TOK_COUNT }, 195270250Sslm { "pipe", TOK_PIPE }, 196270250Sslm { "queue", TOK_QUEUE }, 197270250Sslm { "divert", TOK_DIVERT }, 198270250Sslm { "tee", TOK_TEE }, 199270250Sslm { "netgraph", TOK_NETGRAPH }, 200270250Sslm { "ngtee", TOK_NGTEE }, 201270250Sslm { "fwd", TOK_FORWARD }, 202270250Sslm { "forward", TOK_FORWARD }, 203230592Sken { "skipto", TOK_SKIPTO }, 204230592Sken { "deny", TOK_DENY }, 205253460Sscottl { "drop", TOK_DENY }, 206253460Sscottl { "reject", TOK_REJECT }, 207230592Sken { "reset6", TOK_RESET6 }, 208230592Sken { "reset", TOK_RESET }, 209230592Sken { "unreach6", TOK_UNREACH6 }, 210230592Sken { "unreach", TOK_UNREACH }, 211230592Sken { "check-state", TOK_CHECKSTATE }, 212253460Sscottl { "//", TOK_COMMENT }, 213230592Sken { "nat", TOK_NAT }, 214230592Sken { "reass", TOK_REASS }, 215262853Smav { "setfib", TOK_SETFIB }, 216253549Sken { NULL, 0 } /* terminator */ 217253549Sken}; 218253549Sken 219230592Skenstatic struct _s_x rule_action_params[] = { 220253549Sken { "altq", TOK_ALTQ }, 221230592Sken { "log", TOK_LOG }, 222253460Sscottl { "tag", TOK_TAG }, 223230592Sken { "untag", TOK_UNTAG }, 224212420Sken { NULL, 0 } /* terminator */ 225230592Sken}; 226212420Sken 227230592Sken/* 228230592Sken * The 'lookup' instruction accepts one of the following arguments. 229230592Sken * -1 is a terminator for the list. 230230592Sken * Arguments are passed as v[1] in O_DST_LOOKUP options. 231230592Sken */ 232230592Skenstatic int lookup_key[] = { 233230592Sken TOK_DSTIP, TOK_SRCIP, TOK_DSTPORT, TOK_SRCPORT, 234230592Sken TOK_UID, TOK_JAIL, TOK_DSCP, -1 }; 235212420Sken 236253460Sscottlstatic struct _s_x rule_options[] = { 237230592Sken { "tagged", TOK_TAGGED }, 238230592Sken { "uid", TOK_UID }, 239230592Sken { "gid", TOK_GID }, 240253460Sscottl { "jail", TOK_JAIL }, 241253460Sscottl { "in", TOK_IN }, 242230592Sken { "limit", TOK_LIMIT }, 243230592Sken { "keep-state", TOK_KEEPSTATE }, 244253460Sscottl { "bridged", TOK_LAYER2 }, 245230592Sken { "layer2", TOK_LAYER2 }, 246230592Sken { "out", TOK_OUT }, 247230592Sken { "diverted", TOK_DIVERTED }, 248212420Sken { "diverted-loopback", TOK_DIVERTEDLOOPBACK }, 249212420Sken { "diverted-output", TOK_DIVERTEDOUTPUT }, 250230592Sken { "xmit", TOK_XMIT }, 251230592Sken { "recv", TOK_RECV }, 252212420Sken { "via", TOK_VIA }, 253253460Sscottl { "fragment", TOK_FRAG }, 254230592Sken { "frag", TOK_FRAG }, 255230592Sken { "fib", TOK_FIB }, 256212420Sken { "ipoptions", TOK_IPOPTS }, 257230592Sken { "ipopts", TOK_IPOPTS }, 258230592Sken { "iplen", TOK_IPLEN }, 259230592Sken { "ipid", TOK_IPID }, 260230592Sken { "ipprecedence", TOK_IPPRECEDENCE }, 261230592Sken { "dscp", TOK_DSCP }, 262253460Sscottl { "iptos", TOK_IPTOS }, 263230592Sken { "ipttl", TOK_IPTTL }, 264212420Sken { "ipversion", TOK_IPVER }, 265253460Sscottl { "ipver", TOK_IPVER }, 266230592Sken { "estab", TOK_ESTAB }, 267212420Sken { "established", TOK_ESTAB }, 268230592Sken { "setup", TOK_SETUP }, 269212420Sken { "tcpdatalen", TOK_TCPDATALEN }, 270212420Sken { "tcpflags", TOK_TCPFLAGS }, 271230592Sken { "tcpflgs", TOK_TCPFLAGS }, 272230592Sken { "tcpoptions", TOK_TCPOPTS }, 273212420Sken { "tcpopts", TOK_TCPOPTS }, 274230592Sken { "tcpseq", TOK_TCPSEQ }, 275230592Sken { "tcpack", TOK_TCPACK }, 276230592Sken { "tcpwin", TOK_TCPWIN }, 277230592Sken { "icmptype", TOK_ICMPTYPES }, 278212420Sken { "icmptypes", TOK_ICMPTYPES }, 279253460Sscottl { "dst-ip", TOK_DSTIP }, 280230592Sken { "src-ip", TOK_SRCIP }, 281230592Sken { "dst-port", TOK_DSTPORT }, 282230592Sken { "src-port", TOK_SRCPORT }, 283230592Sken { "proto", TOK_PROTO }, 284230592Sken { "MAC", TOK_MAC }, 285212420Sken { "mac", TOK_MAC }, 286230592Sken { "mac-type", TOK_MACTYPE }, 287230592Sken { "verrevpath", TOK_VERREVPATH }, 288230592Sken { "versrcreach", TOK_VERSRCREACH }, 289230592Sken { "antispoof", TOK_ANTISPOOF }, 290230592Sken { "ipsec", TOK_IPSEC }, 291253460Sscottl { "icmp6type", TOK_ICMP6TYPES }, 292212420Sken { "icmp6types", TOK_ICMP6TYPES }, 293212420Sken { "ext6hdr", TOK_EXT6HDR}, 294212420Sken { "flow-id", TOK_FLOWID}, 295249468Smav { "ipv6", TOK_IPV6}, 296253550Sken { "ip6", TOK_IPV6}, 297253460Sscottl { "ipv4", TOK_IPV4}, 298230592Sken { "ip4", TOK_IPV4}, 299212420Sken { "dst-ipv6", TOK_DSTIP6}, 300212420Sken { "dst-ip6", TOK_DSTIP6}, 301230592Sken { "src-ipv6", TOK_SRCIP6}, 302237800Sken { "src-ip6", TOK_SRCIP6}, 303237800Sken { "lookup", TOK_LOOKUP}, 304237800Sken { "//", TOK_COMMENT }, 305237800Sken 306237800Sken { "not", TOK_NOT }, /* pseudo option */ 307230592Sken { "!", /* escape ? */ TOK_NOT }, /* pseudo option */ 308253549Sken { "or", TOK_OR }, /* pseudo option */ 309212420Sken { "|", /* escape */ TOK_OR }, /* pseudo option */ 310212420Sken { "{", TOK_STARTBRACE }, /* pseudo option */ 311212420Sken { "(", TOK_STARTBRACE }, /* pseudo option */ 312253460Sscottl { "}", TOK_ENDBRACE }, /* pseudo option */ 313212420Sken { ")", TOK_ENDBRACE }, /* pseudo option */ 314230592Sken { NULL, 0 } /* terminator */ 315230592Sken}; 316230592Sken 317230592Sken/* 318212420Sken * The following is used to generate a printable argument for 319230592Sken * 64-bit numbers, irrespective of platform alignment and bit size. 320230592Sken * Because all the printf in this program use %llu as a format, 321212420Sken * we just return an unsigned long long, which is larger than 322254253Sscottl * we need in certain cases, but saves the hassle of using 323254257Smav * PRIu64 as a format specifier. 324254253Sscottl * We don't care about inlining, this is not performance critical code. 325254253Sscottl */ 326230592Skenunsigned long long 327212420Skenalign_uint64(const uint64_t *pll) 328230592Sken{ 329212420Sken uint64_t ret; 330230592Sken 331230592Sken bcopy (pll, &ret, sizeof(ret)); 332230592Sken return ret; 333230592Sken} 334230592Sken 335230592Skenvoid * 336230592Skensafe_calloc(size_t number, size_t size) 337230592Sken{ 338212420Sken void *ret = calloc(number, size); 339212420Sken 340230592Sken if (ret == NULL) 341230592Sken err(EX_OSERR, "calloc"); 342230592Sken return ret; 343230592Sken} 344230592Sken 345230592Skenvoid * 346230592Skensafe_realloc(void *ptr, size_t size) 347230592Sken{ 348212420Sken void *ret = realloc(ptr, size); 349230592Sken 350230592Sken if (ret == NULL) 351230592Sken err(EX_OSERR, "realloc"); 352253460Sscottl return ret; 353212420Sken} 354230592Sken 355230592Sken/* 356212420Sken * conditionally runs the command. 357231240Sken * Selected options or negative -> getsockopt 358230592Sken */ 359231240Skenint 360230592Skendo_cmd(int optname, void *optval, uintptr_t optlen) 361231240Sken{ 362231240Sken static int s = -1; /* the socket */ 363231240Sken int i; 364212420Sken 365253460Sscottl if (co.test_only) 366231240Sken return 0; 367231240Sken 368231240Sken if (s == -1) 369231240Sken s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); 370231240Sken if (s < 0) 371231240Sken err(EX_UNAVAILABLE, "socket"); 372231240Sken 373253460Sscottl if (optname == IP_FW_GET || optname == IP_DUMMYNET_GET || 374253460Sscottl optname == IP_FW_ADD || optname == IP_FW_TABLE_LIST || 375231240Sken optname == IP_FW_TABLE_GETSIZE || 376230592Sken optname == IP_FW_NAT_GET_CONFIG || 377230592Sken optname < 0 || 378212420Sken optname == IP_FW_NAT_GET_LOG) { 379231240Sken if (optname < 0) 380253460Sscottl optname = -optname; 381253460Sscottl i = getsockopt(s, IPPROTO_IP, optname, optval, 382231240Sken (socklen_t *)optlen); 383231240Sken } else { 384231240Sken i = setsockopt(s, IPPROTO_IP, optname, optval, optlen); 385231240Sken } 386231240Sken return i; 387253460Sscottl} 388253460Sscottl 389231240Sken/** 390240518Seadler * match_token takes a table and a string, returns the value associated 391231240Sken * with the string (-1 in case of failure). 392253460Sscottl */ 393253460Sscottlint 394231240Skenmatch_token(struct _s_x *table, char *string) 395231240Sken{ 396231240Sken struct _s_x *pt; 397231240Sken uint i = strlen(string); 398231240Sken 399231240Sken for (pt = table ; i && pt->s != NULL ; pt++) 400231240Sken if (strlen(pt->s) == i && !bcmp(string, pt->s, i)) 401231240Sken return pt->x; 402231240Sken return -1; 403231240Sken} 404231240Sken 405231240Sken/** 406231240Sken * match_value takes a table and a value, returns the string associated 407231240Sken * with the value (NULL in case of failure). 408231240Sken */ 409231240Skenchar const * 410231240Skenmatch_value(struct _s_x *p, int value) 411231240Sken{ 412231240Sken for (; p->s != NULL; p++) 413231240Sken if (p->x == value) 414212420Sken return p->s; 415212420Sken return NULL; 416231240Sken} 417212420Sken 418231240Sken/* 419231240Sken * _substrcmp takes two strings and returns 1 if they do not match, 420231240Sken * and 0 if they match exactly or the first string is a sub-string 421231240Sken * of the second. A warning is printed to stderr in the case that the 422231240Sken * first string is a sub-string of the second. 423231240Sken * 424231240Sken * This function will be removed in the future through the usual 425231240Sken * deprecation process. 426231240Sken */ 427231240Skenint 428231240Sken_substrcmp(const char *str1, const char* str2) 429253460Sscottl{ 430231240Sken 431231240Sken if (strncmp(str1, str2, strlen(str1)) != 0) 432231240Sken return 1; 433231240Sken 434231240Sken if (strlen(str1) != strlen(str2)) 435231240Sken warnx("DEPRECATED: '%s' matched '%s' as a sub-string", 436231240Sken str1, str2); 437231240Sken return 0; 438231240Sken} 439231240Sken 440231240Sken/* 441231240Sken * _substrcmp2 takes three strings and returns 1 if the first two do not match, 442231240Sken * and 0 if they match exactly or the second string is a sub-string 443231240Sken * of the first. A warning is printed to stderr in the case that the 444231240Sken * first string does not match the third. 445231240Sken * 446231240Sken * This function exists to warn about the bizzare construction 447231240Sken * strncmp(str, "by", 2) which is used to allow people to use a shotcut 448253460Sscottl * for "bytes". The problem is that in addition to accepting "by", 449253460Sscottl * "byt", "byte", and "bytes", it also excepts "by_rabid_dogs" and any 450231240Sken * other string beginning with "by". 451231240Sken * 452231240Sken * This function will be removed in the future through the usual 453231240Sken * deprecation process. 454231240Sken */ 455231240Skenint 456231240Sken_substrcmp2(const char *str1, const char* str2, const char* str3) 457253460Sscottl{ 458253460Sscottl 459231240Sken if (strncmp(str1, str2, strlen(str2)) != 0) 460231240Sken return 1; 461231240Sken 462231240Sken if (strcmp(str1, str3) != 0) 463231240Sken warnx("DEPRECATED: '%s' matched '%s'", 464231240Sken str1, str3); 465231240Sken return 0; 466231240Sken} 467231240Sken 468231240Sken/* 469231240Sken * prints one port, symbolic or numeric 470231240Sken */ 471231240Skenstatic void 472231240Skenprint_port(int proto, uint16_t port) 473231240Sken{ 474231240Sken 475231240Sken if (proto == IPPROTO_ETHERTYPE) { 476231240Sken char const *s; 477231240Sken 478231240Sken if (co.do_resolv && (s = match_value(ether_types, port)) ) 479231240Sken printf("%s", s); 480231240Sken else 481231240Sken printf("0x%04x", port); 482230592Sken } else { 483230592Sken struct servent *se = NULL; 484230592Sken if (co.do_resolv) { 485230592Sken struct protoent *pe = getprotobynumber(proto); 486230592Sken 487230592Sken se = getservbyport(htons(port), pe ? pe->p_name : NULL); 488230592Sken } 489212420Sken if (se) 490230592Sken printf("%s", se->s_name); 491230592Sken else 492212420Sken printf("%d", port); 493212420Sken } 494212420Sken} 495212420Sken 496212420Skenstatic struct _s_x _port_name[] = { 497212420Sken {"dst-port", O_IP_DSTPORT}, 498253460Sscottl {"src-port", O_IP_SRCPORT}, 499212420Sken {"ipid", O_IPID}, 500230592Sken {"iplen", O_IPLEN}, 501230592Sken {"ipttl", O_IPTTL}, 502230592Sken {"mac-type", O_MAC_TYPE}, 503230592Sken {"tcpdatalen", O_TCPDATALEN}, 504230592Sken {"tagged", O_TAGGED}, 505212420Sken {NULL, 0} 506253460Sscottl}; 507253460Sscottl 508212420Sken/* 509230592Sken * Print the values in a list 16-bit items of the types above. 510212420Sken * XXX todo: add support for mask. 511230592Sken */ 512230592Skenstatic void 513230592Skenprint_newports(ipfw_insn_u16 *cmd, int proto, int opcode) 514212420Sken{ 515253460Sscottl uint16_t *p = cmd->ports; 516253460Sscottl int i; 517212420Sken char const *sep; 518212420Sken 519212420Sken if (opcode != 0) { 520231240Sken sep = match_value(_port_name, opcode); 521218811Sken if (sep == NULL) 522212420Sken sep = "???"; 523218811Sken printf (" %s", sep); 524237683Sken } 525212420Sken sep = " "; 526212420Sken for (i = F_LEN((ipfw_insn *)cmd) - 1; i > 0; i--, p += 2) { 527212420Sken printf("%s", sep); 528212420Sken print_port(proto, p[0]); 529212420Sken if (p[0] != p[1]) { 530212420Sken printf("-"); 531230592Sken print_port(proto, p[1]); 532212420Sken } 533230592Sken sep = ","; 534212420Sken } 535230592Sken} 536230592Sken 537212420Sken/* 538212420Sken * Like strtol, but also translates service names into port numbers 539212420Sken * for some protocols. 540230592Sken * In particular: 541212420Sken * proto == -1 disables the protocol check; 542212420Sken * proto == IPPROTO_ETHERTYPE looks up an internal table 543212420Sken * proto == <some value in /etc/protocols> matches the values there. 544212420Sken * Returns *end == s in case the parameter is not found. 545218811Sken */ 546212420Skenstatic int 547212420Skenstrtoport(char *s, char **end, int base, int proto) 548253460Sscottl{ 549212420Sken char *p, *buf; 550230592Sken char *s1; 551230592Sken int i; 552230592Sken 553213535Sken *end = s; /* default - not found */ 554218812Sken if (*s == '\0') 555218812Sken return 0; /* not found */ 556218812Sken 557218812Sken if (isdigit(*s)) 558218812Sken return strtol(s, end, base); 559230592Sken 560253460Sscottl /* 561253460Sscottl * find separator. '\\' escapes the next char. 562253460Sscottl */ 563253460Sscottl for (s1 = s; *s1 && (isalnum(*s1) || *s1 == '\\') ; s1++) 564230592Sken if (*s1 == '\\' && s1[1] != '\0') 565218812Sken s1++; 566218812Sken 567218812Sken buf = safe_calloc(s1 - s + 1, 1); 568230592Sken 569230592Sken /* 570253460Sscottl * copy into a buffer skipping backslashes 571253460Sscottl */ 572230592Sken for (p = s, i = 0; p != s1 ; p++) 573230592Sken if (*p != '\\') 574230592Sken buf[i++] = *p; 575230592Sken buf[i++] = '\0'; 576237683Sken 577253460Sscottl if (proto == IPPROTO_ETHERTYPE) { 578253460Sscottl i = match_token(ether_types, buf); 579237683Sken free(buf); 580230592Sken if (i != -1) { /* found */ 581212420Sken *end = s1; 582212420Sken return i; 583212420Sken } 584253460Sscottl } else { 585237683Sken struct protoent *pe = NULL; 586230592Sken struct servent *se; 587240518Seadler 588212420Sken if (proto != 0) 589212420Sken pe = getprotobynumber(proto); 590230592Sken setservent(1); 591218811Sken se = getservbyname(buf, pe ? pe->p_name : NULL); 592212420Sken free(buf); 593212420Sken if (se != NULL) { 594237683Sken *end = s1; 595230592Sken return ntohs(se->s_port); 596230592Sken } 597230592Sken } 598230592Sken return 0; /* not found */ 599212420Sken} 600230592Sken 601212420Sken/* 602253460Sscottl * Fill the body of the command with the list of port ranges. 603230592Sken */ 604230592Skenstatic int 605218811Skenfill_newports(ipfw_insn_u16 *cmd, char *av, int proto) 606218811Sken{ 607253460Sscottl uint16_t a, b, *p = cmd->ports; 608230592Sken int i = 0; 609268197Sscottl char *s = av; 610230592Sken 611218811Sken while (*s) { 612212420Sken a = strtoport(av, &s, 0, proto); 613212420Sken if (s == av) /* empty or invalid argument */ 614212420Sken return (0); 615230592Sken 616212420Sken switch (*s) { 617212420Sken case '-': /* a range */ 618230592Sken av = s + 1; 619230592Sken b = strtoport(av, &s, 0, proto); 620237683Sken /* Reject expressions like '1-abc' or '1-2-3'. */ 621212420Sken if (s == av || (*s != ',' && *s != '\0')) 622253460Sscottl return (0); 623212420Sken p[0] = a; 624230592Sken p[1] = b; 625230592Sken break; 626212420Sken case ',': /* comma separated list */ 627230592Sken case '\0': 628230592Sken p[0] = p[1] = a; 629230592Sken break; 630230592Sken default: 631230592Sken warnx("port list: invalid separator <%c> in <%s>", 632230592Sken *s, av); 633253460Sscottl return (0); 634253460Sscottl } 635230592Sken 636230592Sken i++; 637230592Sken p += 2; 638230592Sken av = s + 1; 639230592Sken } 640212420Sken if (i > 0) { 641230592Sken if (i + 1 > F_LEN_MASK) 642230592Sken errx(EX_DATAERR, "too many ports/ranges\n"); 643253460Sscottl cmd->o.len |= i + 1; /* leave F_NOT and F_OR untouched */ 644253460Sscottl } 645230592Sken return (i); 646230592Sken} 647212420Sken 648212420Skenstatic struct _s_x icmpcodes[] = { 649253460Sscottl { "net", ICMP_UNREACH_NET }, 650253460Sscottl { "host", ICMP_UNREACH_HOST }, 651237683Sken { "protocol", ICMP_UNREACH_PROTOCOL }, 652212420Sken { "port", ICMP_UNREACH_PORT }, 653230592Sken { "needfrag", ICMP_UNREACH_NEEDFRAG }, 654230592Sken { "srcfail", ICMP_UNREACH_SRCFAIL }, 655230592Sken { "net-unknown", ICMP_UNREACH_NET_UNKNOWN }, 656230592Sken { "host-unknown", ICMP_UNREACH_HOST_UNKNOWN }, 657230592Sken { "isolated", ICMP_UNREACH_ISOLATED }, 658230592Sken { "net-prohib", ICMP_UNREACH_NET_PROHIB }, 659237683Sken { "host-prohib", ICMP_UNREACH_HOST_PROHIB }, 660230592Sken { "tosnet", ICMP_UNREACH_TOSNET }, 661230592Sken { "toshost", ICMP_UNREACH_TOSHOST }, 662230592Sken { "filter-prohib", ICMP_UNREACH_FILTER_PROHIB }, 663230592Sken { "host-precedence", ICMP_UNREACH_HOST_PRECEDENCE }, 664230592Sken { "precedence-cutoff", ICMP_UNREACH_PRECEDENCE_CUTOFF }, 665230592Sken { NULL, 0 } 666230592Sken}; 667230592Sken 668231240Skenstatic void 669237683Skenfill_reject_code(u_short *codep, char *str) 670237683Sken{ 671237683Sken int val; 672237683Sken char *s; 673237683Sken 674237683Sken val = strtoul(str, &s, 0); 675212420Sken if (s == str || *s != '\0' || val >= 0x100) 676237683Sken val = match_token(icmpcodes, str); 677212420Sken if (val < 0) 678230592Sken errx(EX_DATAERR, "unknown ICMP unreachable code ``%s''", str); 679212420Sken *codep = val; 680212420Sken return; 681212420Sken} 682212420Sken 683212420Skenstatic void 684237683Skenprint_reject_code(uint16_t code) 685212420Sken{ 686212420Sken char const *s = match_value(icmpcodes, code); 687212420Sken 688212420Sken if (s != NULL) 689212420Sken printf("unreach %s", s); 690212420Sken else 691212420Sken printf("unreach %u", code); 692212420Sken} 693212420Sken 694230592Sken/* 695230592Sken * Returns the number of bits set (from left) in a contiguous bitmask, 696230592Sken * or -1 if the mask is not contiguous. 697230592Sken * XXX this needs a proper fix. 698230592Sken * This effectively works on masks in big-endian (network) format. 699212420Sken * when compiled on little endian architectures. 700212420Sken * 701212420Sken * First bit is bit 7 of the first byte -- note, for MAC addresses, 702212420Sken * the first bit on the wire is bit 0 of the first byte. 703212420Sken * len is the max length in bits. 704212420Sken */ 705212420Skenint 706212420Skencontigmask(uint8_t *p, int len) 707212420Sken{ 708212420Sken int i, n; 709212420Sken 710230592Sken for (i=0; i<len ; i++) 711230592Sken if ( (p[i/8] & (1 << (7 - (i%8)))) == 0) /* first bit unset */ 712212420Sken break; 713253460Sscottl for (n=i+1; n < len; n++) 714212420Sken if ( (p[n/8] & (1 << (7 - (n%8)))) != 0) 715212420Sken return -1; /* mask not contiguous */ 716237683Sken return i; 717237683Sken} 718237683Sken 719237683Sken/* 720237683Sken * print flags set/clear in the two bitmasks passed as parameters. 721264492Sscottl * There is a specialized check for f_tcpflags. 722264492Sscottl */ 723264492Sscottlstatic void 724264492Sscottlprint_flags(char const *name, ipfw_insn *cmd, struct _s_x *list) 725264492Sscottl{ 726264492Sscottl char const *comma = ""; 727264492Sscottl int i; 728264492Sscottl uint8_t set = cmd->arg1 & 0xff; 729212420Sken uint8_t clear = (cmd->arg1 >> 8) & 0xff; 730264492Sscottl 731237683Sken if (list == f_tcpflags && set == TH_SYN && clear == TH_ACK) { 732237683Sken printf(" setup"); 733237683Sken return; 734237683Sken } 735237683Sken 736237683Sken printf(" %s ", name); 737212420Sken for (i=0; list[i].x != 0; i++) { 738212420Sken if (set & list[i].x) { 739212420Sken set &= ~list[i].x; 740230592Sken printf("%s%s", comma, list[i].s); 741253460Sscottl comma = ","; 742212420Sken } 743212420Sken if (clear & list[i].x) { 744212420Sken clear &= ~list[i].x; 745212420Sken printf("%s!%s", comma, list[i].s); 746230592Sken comma = ","; 747212420Sken } 748230592Sken } 749212420Sken} 750253460Sscottl 751212420Sken/* 752212420Sken * Print the ip address contained in a command. 753212420Sken */ 754212420Skenstatic void 755230592Skenprint_ip(ipfw_insn_ip *cmd, char const *s) 756230592Sken{ 757230592Sken struct hostent *he = NULL; 758230592Sken uint32_t len = F_LEN((ipfw_insn *)cmd); 759230592Sken uint32_t *a = ((ipfw_insn_u32 *)cmd)->d; 760230592Sken 761230592Sken if (cmd->o.opcode == O_IP_DST_LOOKUP && len > F_INSN_SIZE(ipfw_insn_u32)) { 762230592Sken uint32_t d = a[1]; 763230592Sken const char *arg = "<invalid>"; 764230592Sken 765230592Sken if (d < sizeof(lookup_key)/sizeof(lookup_key[0])) 766230592Sken arg = match_value(rule_options, lookup_key[d]); 767230592Sken printf("%s lookup %s %d", cmd->o.len & F_NOT ? " not": "", 768212420Sken arg, cmd->o.arg1); 769212420Sken return; 770212420Sken } 771212420Sken printf("%s%s ", cmd->o.len & F_NOT ? " not": "", s); 772212420Sken 773212420Sken if (cmd->o.opcode == O_IP_SRC_ME || cmd->o.opcode == O_IP_DST_ME) { 774253460Sscottl printf("me"); 775212420Sken return; 776212420Sken } 777212420Sken if (cmd->o.opcode == O_IP_SRC_LOOKUP || 778212420Sken cmd->o.opcode == O_IP_DST_LOOKUP) { 779212420Sken printf("table(%u", ((ipfw_insn *)cmd)->arg1); 780212420Sken if (len == F_INSN_SIZE(ipfw_insn_u32)) 781253549Sken printf(",%u", *a); 782253549Sken printf(")"); 783253549Sken return; 784212420Sken } 785230592Sken if (cmd->o.opcode == O_IP_SRC_SET || cmd->o.opcode == O_IP_DST_SET) { 786230592Sken uint32_t x, *map = (uint32_t *)&(cmd->mask); 787262853Smav int i, j; 788212420Sken char comma = '{'; 789212420Sken 790212420Sken x = cmd->o.arg1 - 1; 791212420Sken x = htonl( ~x ); 792230592Sken cmd->addr.s_addr = htonl(cmd->addr.s_addr); 793230592Sken printf("%s/%d", inet_ntoa(cmd->addr), 794253549Sken contigmask((uint8_t *)&x, 32)); 795253549Sken x = cmd->addr.s_addr = htonl(cmd->addr.s_addr); 796253549Sken x &= 0xff; /* base */ 797253549Sken /* 798253549Sken * Print bits and ranges. 799253549Sken * Locate first bit set (i), then locate first bit unset (j). 800253549Sken * If we have 3+ consecutive bits set, then print them as a 801230592Sken * range, otherwise only print the initial bit and rescan. 802253549Sken */ 803253549Sken for (i=0; i < cmd->o.arg1; i++) 804253549Sken if (map[i/32] & (1<<(i & 31))) { 805253549Sken for (j=i+1; j < cmd->o.arg1; j++) 806253549Sken if (!(map[ j/32] & (1<<(j & 31)))) 807253549Sken break; 808253549Sken printf("%c%d", comma, i+x); 809253549Sken if (j>i+2) { /* range has at least 3 elements */ 810253549Sken printf("-%d", j-1+x); 811253549Sken i = j-1; 812253549Sken } 813253549Sken comma = ','; 814253549Sken } 815253549Sken printf("}"); 816253549Sken return; 817253549Sken } 818253549Sken /* 819253549Sken * len == 2 indicates a single IP, whereas lists of 1 or more 820253549Sken * addr/mask pairs have len = (2n+1). We convert len to n so we 821253549Sken * use that to count the number of entries. 822230592Sken */ 823253549Sken for (len = len / 2; len > 0; len--, a += 2) { 824253549Sken int mb = /* mask length */ 825253549Sken (cmd->o.opcode == O_IP_SRC || cmd->o.opcode == O_IP_DST) ? 826253549Sken 32 : contigmask((uint8_t *)&(a[1]), 32); 827253549Sken if (mb == 32 && co.do_resolv) 828253549Sken he = gethostbyaddr((char *)&(a[0]), sizeof(u_long), AF_INET); 829253549Sken if (he != NULL) /* resolved to name */ 830230592Sken printf("%s", he->h_name); 831230592Sken else if (mb == 0) /* any */ 832230592Sken printf("any"); 833212420Sken else { /* numeric IP followed by some kind of mask */ 834212420Sken printf("%s", inet_ntoa( *((struct in_addr *)&a[0]) ) ); 835212420Sken if (mb < 0) 836212420Sken printf(":%s", inet_ntoa( *((struct in_addr *)&a[1]) ) ); 837212420Sken else if (mb < 32) 838212420Sken printf("/%d", mb); 839212420Sken } 840212420Sken if (len > 1) 841212420Sken printf(","); 842212420Sken } 843212420Sken} 844237683Sken 845237683Sken/* 846237683Sken * prints a MAC address/mask pair 847212420Sken */ 848253460Sscottlstatic void 849212420Skenprint_mac(uint8_t *addr, uint8_t *mask) 850212420Sken{ 851212420Sken int l = contigmask(mask, 48); 852212420Sken 853212420Sken if (l == 0) 854230592Sken printf(" any"); 855212420Sken else { 856230592Sken printf(" %02x:%02x:%02x:%02x:%02x:%02x", 857230592Sken addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); 858230592Sken if (l == -1) 859230592Sken printf("&%02x:%02x:%02x:%02x:%02x:%02x", 860230592Sken mask[0], mask[1], mask[2], 861230592Sken mask[3], mask[4], mask[5]); 862230592Sken else if (l < 48) 863230592Sken printf("/%d", l); 864212420Sken } 865212420Sken} 866230592Sken 867230592Skenstatic void 868253549Skenfill_icmptypes(ipfw_insn_u32 *cmd, char *av) 869253549Sken{ 870253549Sken uint8_t type; 871253549Sken 872253549Sken cmd->d[0] = 0; 873230592Sken while (*av) { 874212420Sken if (*av == ',') 875212420Sken av++; 876212420Sken 877212420Sken type = strtoul(av, &av, 0); 878212420Sken 879212420Sken if (*av != ',' && *av != '\0') 880212420Sken errx(EX_DATAERR, "invalid ICMP type"); 881230592Sken 882253549Sken if (type > 31) 883212420Sken errx(EX_DATAERR, "ICMP type out of range"); 884212420Sken 885212420Sken cmd->d[0] |= 1 << type; 886212420Sken } 887212420Sken cmd->o.opcode = O_ICMPTYPE; 888264492Sscottl cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32); 889237683Sken} 890237683Sken 891237683Skenstatic void 892237683Skenprint_icmptypes(ipfw_insn_u32 *cmd) 893237683Sken{ 894212420Sken int i; 895212420Sken char sep= ' '; 896212420Sken 897212420Sken printf(" icmptypes"); 898212420Sken for (i = 0; i < 32; i++) { 899212420Sken if ( (cmd->d[0] & (1 << (i))) == 0) 900212420Sken continue; 901230592Sken printf("%c%d", sep, i); 902212420Sken sep = ','; 903212420Sken } 904212420Sken} 905212420Sken 906253460Sscottl/* 907212420Sken * show_ipfw() prints the body of an ipfw rule. 908212420Sken * Because the standard rule has at least proto src_ip dst_ip, we use 909212420Sken * a helper function to produce these entries if not provided explicitly. 910212420Sken * The first argument is the list of fields we have, the second is 911212420Sken * the list of fields we want to be printed. 912212420Sken * 913212420Sken * Special cases if we have provided a MAC header: 914212420Sken * + if the rule does not contain IP addresses/ports, do not print them; 915212420Sken * + if the rule does not contain an IP proto, print "all" instead of "ip"; 916212420Sken * 917212420Sken * Once we have 'have_options', IP header fields are printed as options. 918212420Sken */ 919212420Sken#define HAVE_PROTO 0x0001 920253460Sscottl#define HAVE_SRCIP 0x0002 921253460Sscottl#define HAVE_DSTIP 0x0004 922212420Sken#define HAVE_PROTO4 0x0008 923230592Sken#define HAVE_PROTO6 0x0010 924212420Sken#define HAVE_IP 0x0100 925212420Sken#define HAVE_OPTIONS 0x8000 926212420Sken 927212420Skenstatic void 928212420Skenshow_prerequisites(int *flags, int want, int cmd __unused) 929212420Sken{ 930212420Sken if (co.comment_only) 931212420Sken return; 932212420Sken if ( (*flags & HAVE_IP) == HAVE_IP) 933253549Sken *flags |= HAVE_OPTIONS; 934253549Sken 935253549Sken if ( !(*flags & HAVE_OPTIONS)) { 936248825Smav if ( !(*flags & HAVE_PROTO) && (want & HAVE_PROTO)) { 937253549Sken if ( (*flags & HAVE_PROTO4)) 938212420Sken printf(" ip4"); 939264492Sscottl else if ( (*flags & HAVE_PROTO6)) 940237683Sken printf(" ip6"); 941264492Sscottl else 942212420Sken printf(" ip"); 943212420Sken } 944212420Sken if ( !(*flags & HAVE_SRCIP) && (want & HAVE_SRCIP)) 945212420Sken printf(" from any"); 946212420Sken if ( !(*flags & HAVE_DSTIP) && (want & HAVE_DSTIP)) 947212420Sken printf(" to any"); 948212420Sken } 949212420Sken *flags |= want; 950212420Sken} 951212420Sken 952230592Skenstatic void 953230592Skenshow_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth) 954230592Sken{ 955230592Sken static int twidth = 0; 956230592Sken int l; 957230592Sken ipfw_insn *cmd, *tagptr = NULL; 958268197Sscottl const char *comment = NULL; /* ptr to comment if we have one */ 959212420Sken int proto = 0; /* default */ 960212420Sken int flags = 0; /* prerequisites */ 961212420Sken ipfw_insn_log *logptr = NULL; /* set if we find an O_LOG */ 962212420Sken ipfw_insn_altq *altqptr = NULL; /* set if we find an O_ALTQ */ 963212420Sken int or_block = 0; /* we are in an or block */ 964212420Sken uint32_t set_disable; 965212420Sken 966212420Sken bcopy(&rule->next_rule, &set_disable, sizeof(set_disable)); 967212420Sken 968212420Sken if (set_disable & (1 << rule->set)) { /* disabled */ 969212420Sken if (!co.show_sets) 970212420Sken return; 971212420Sken else 972264492Sscottl printf("# DISABLED "); 973264492Sscottl } 974264492Sscottl printf("%05u ", rule->rulenum); 975212420Sken 976212420Sken if (pcwidth>0 || bcwidth>0) 977270250Sslm printf("%*llu %*llu ", pcwidth, align_uint64(&rule->pcnt), 978212420Sken bcwidth, align_uint64(&rule->bcnt)); 979212420Sken 980212420Sken if (co.do_time == 2) 981212420Sken printf("%10u ", rule->timestamp); 982212420Sken else if (co.do_time == 1) { 983212420Sken char timestr[30]; 984212420Sken time_t t = (time_t)0; 985212420Sken 986212420Sken if (twidth == 0) { 987212420Sken strcpy(timestr, ctime(&t)); 988212420Sken *strchr(timestr, '\n') = '\0'; 989212420Sken twidth = strlen(timestr); 990212420Sken } 991212420Sken if (rule->timestamp) { 992212420Sken t = _long_to_time(rule->timestamp); 993212420Sken 994212420Sken strcpy(timestr, ctime(&t)); 995212420Sken *strchr(timestr, '\n') = '\0'; 996212420Sken printf("%s ", timestr); 997212420Sken } else { 998212420Sken printf("%*s", twidth, " "); 999212420Sken } 1000212420Sken } 1001212420Sken 1002212420Sken if (co.show_sets) 1003212420Sken printf("set %d ", rule->set); 1004268197Sscottl 1005212420Sken /* 1006212420Sken * print the optional "match probability" 1007212420Sken */ 1008212420Sken if (rule->cmd_len > 0) { 1009268197Sscottl cmd = rule->cmd ; 1010212420Sken if (cmd->opcode == O_PROB) { 1011212420Sken ipfw_insn_u32 *p = (ipfw_insn_u32 *)cmd; 1012253460Sscottl double d = 1.0 * p->d[0]; 1013212420Sken 1014212420Sken d = (d / 0x7fffffff); 1015212420Sken printf("prob %f ", d); 1016212420Sken } 1017212420Sken } 1018253460Sscottl 1019253460Sscottl /* 1020268197Sscottl * first print actions 1021212420Sken */ 1022212420Sken for (l = rule->cmd_len - rule->act_ofs, cmd = ACTION_PTR(rule); 1023212420Sken l > 0 ; l -= F_LEN(cmd), cmd += F_LEN(cmd)) { 1024212420Sken switch(cmd->opcode) { 1025216088Sken case O_CHECK_STATE: 1026216088Sken printf("check-state"); 1027216088Sken /* avoid printing anything else */ 1028216088Sken flags = HAVE_PROTO | HAVE_SRCIP | 1029230592Sken HAVE_DSTIP | HAVE_IP; 1030212420Sken break; 1031268197Sscottl 1032212420Sken case O_ACCEPT: 1033212420Sken printf("allow"); 1034212420Sken break; 1035212420Sken 1036212420Sken case O_COUNT: 1037212420Sken printf("count"); 1038212420Sken break; 1039230592Sken 1040230592Sken case O_DENY: 1041212420Sken printf("deny"); 1042230592Sken break; 1043230592Sken 1044212420Sken case O_REJECT: 1045253460Sscottl if (cmd->arg1 == ICMP_REJECT_RST) 1046230592Sken printf("reset"); 1047212420Sken else if (cmd->arg1 == ICMP_UNREACH_HOST) 1048230592Sken printf("reject"); 1049230592Sken else 1050253460Sscottl print_reject_code(cmd->arg1); 1051230592Sken break; 1052230592Sken 1053212420Sken case O_UNREACH6: 1054212420Sken if (cmd->arg1 == ICMP6_UNREACH_RST) 1055230592Sken printf("reset6"); 1056230592Sken else 1057212420Sken print_unreach6_code(cmd->arg1); 1058212420Sken break; 1059230592Sken 1060230592Sken case O_SKIPTO: 1061212420Sken PRINT_UINT_ARG("skipto ", cmd->arg1); 1062212420Sken break; 1063230592Sken 1064230592Sken case O_PIPE: 1065212420Sken PRINT_UINT_ARG("pipe ", cmd->arg1); 1066253460Sscottl break; 1067230592Sken 1068212420Sken case O_QUEUE: 1069230592Sken PRINT_UINT_ARG("queue ", cmd->arg1); 1070230592Sken break; 1071230592Sken 1072230592Sken case O_DIVERT: 1073230592Sken PRINT_UINT_ARG("divert ", cmd->arg1); 1074230592Sken break; 1075230592Sken 1076230592Sken case O_TEE: 1077230592Sken PRINT_UINT_ARG("tee ", cmd->arg1); 1078230592Sken break; 1079253460Sscottl 1080230592Sken case O_NETGRAPH: 1081230592Sken PRINT_UINT_ARG("netgraph ", cmd->arg1); 1082230592Sken break; 1083230592Sken 1084230592Sken case O_NGTEE: 1085230592Sken PRINT_UINT_ARG("ngtee ", cmd->arg1); 1086230592Sken break; 1087230592Sken 1088253460Sscottl case O_FORWARD_IP: 1089230592Sken { 1090230592Sken ipfw_insn_sa *s = (ipfw_insn_sa *)cmd; 1091230592Sken 1092230592Sken if (s->sa.sin_addr.s_addr == INADDR_ANY) { 1093230592Sken printf("fwd tablearg"); 1094270250Sslm } else { 1095270250Sslm printf("fwd %s", inet_ntoa(s->sa.sin_addr)); 1096270250Sslm } 1097270250Sslm if (s->sa.sin_port) 1098270250Sslm printf(",%d", s->sa.sin_port); 1099270250Sslm } 1100270250Sslm break; 1101270250Sslm 1102230592Sken case O_LOG: /* O_LOG is printed last */ 1103230592Sken logptr = (ipfw_insn_log *)cmd; 1104230592Sken break; 1105253460Sscottl 1106230592Sken case O_ALTQ: /* O_ALTQ is printed after O_LOG */ 1107230592Sken altqptr = (ipfw_insn_altq *)cmd; 1108230592Sken break; 1109230592Sken 1110212420Sken case O_TAG: 1111230592Sken tagptr = cmd; 1112212420Sken break; 1113230592Sken 1114230592Sken case O_NAT: 1115230592Sken PRINT_UINT_ARG("nat ", cmd->arg1); 1116230592Sken break; 1117212420Sken 1118230592Sken case O_SETFIB: 1119230592Sken PRINT_UINT_ARG("setfib ", cmd->arg1); 1120230592Sken break; 1121230592Sken 1122230592Sken case O_REASS: 1123230592Sken printf("reass"); 1124230592Sken break; 1125212802Sken 1126253460Sscottl default: 1127230592Sken printf("** unrecognized action %d len %d ", 1128230592Sken cmd->opcode, cmd->len); 1129262853Smav } 1130212420Sken } 1131230592Sken if (logptr) { 1132230592Sken if (logptr->max_log > 0) 1133230592Sken printf(" log logamount %d", logptr->max_log); 1134212420Sken else 1135230592Sken printf(" log"); 1136230592Sken } 1137230592Sken#ifndef NO_ALTQ 1138253460Sscottl if (altqptr) { 1139253460Sscottl print_altq_cmd(altqptr); 1140230592Sken } 1141230592Sken#endif 1142230592Sken if (tagptr) { 1143230592Sken if (tagptr->len & F_NOT) 1144230592Sken PRINT_UINT_ARG(" untag ", tagptr->arg1); 1145230592Sken else 1146264492Sscottl PRINT_UINT_ARG(" tag ", tagptr->arg1); 1147230592Sken } 1148253460Sscottl 1149230592Sken /* 1150230592Sken * then print the body. 1151230592Sken */ 1152230592Sken for (l = rule->act_ofs, cmd = rule->cmd ; 1153230592Sken l > 0 ; l -= F_LEN(cmd) , cmd += F_LEN(cmd)) { 1154230592Sken if ((cmd->len & F_OR) || (cmd->len & F_NOT)) 1155212420Sken continue; 1156253460Sscottl if (cmd->opcode == O_IP4) { 1157230592Sken flags |= HAVE_PROTO4; 1158230592Sken break; 1159230592Sken } else if (cmd->opcode == O_IP6) { 1160230592Sken flags |= HAVE_PROTO6; 1161230592Sken break; 1162212420Sken } 1163230592Sken } 1164230592Sken if (rule->_pad & 1) { /* empty rules before options */ 1165253460Sscottl if (!co.do_compact) { 1166253460Sscottl show_prerequisites(&flags, HAVE_PROTO, 0); 1167230592Sken printf(" from any to any"); 1168230592Sken } 1169230592Sken flags |= HAVE_IP | HAVE_OPTIONS | HAVE_PROTO | 1170212420Sken HAVE_SRCIP | HAVE_DSTIP; 1171230592Sken } 1172212420Sken 1173230592Sken if (co.comment_only) 1174212420Sken comment = "..."; 1175230592Sken 1176230592Sken for (l = rule->act_ofs, cmd = rule->cmd ; 1177230592Sken l > 0 ; l -= F_LEN(cmd) , cmd += F_LEN(cmd)) { 1178212420Sken /* useful alias */ 1179230592Sken ipfw_insn_u32 *cmd32 = (ipfw_insn_u32 *)cmd; 1180212420Sken 1181230592Sken if (co.comment_only) { 1182230592Sken if (cmd->opcode != O_NOP) 1183230592Sken continue; 1184230592Sken printf(" // %s\n", (char *)(cmd + 1)); 1185218812Sken return; 1186218812Sken } 1187218812Sken 1188218812Sken show_prerequisites(&flags, 0, cmd->opcode); 1189253460Sscottl 1190218812Sken switch(cmd->opcode) { 1191230592Sken case O_PROB: 1192253460Sscottl break; /* done already */ 1193230592Sken 1194230592Sken case O_PROBE_STATE: 1195230592Sken break; /* no need to print anything here */ 1196218812Sken 1197218812Sken case O_IP_SRC: 1198230592Sken case O_IP_SRC_LOOKUP: 1199253460Sscottl case O_IP_SRC_MASK: 1200253460Sscottl case O_IP_SRC_ME: 1201230592Sken case O_IP_SRC_SET: 1202230592Sken show_prerequisites(&flags, HAVE_PROTO, 0); 1203230592Sken if (!(flags & HAVE_SRCIP)) 1204230592Sken printf(" from"); 1205230592Sken if ((cmd->len & F_OR) && !or_block) 1206230592Sken printf(" {"); 1207230592Sken print_ip((ipfw_insn_ip *)cmd, 1208230592Sken (flags & HAVE_OPTIONS) ? " src-ip" : ""); 1209230592Sken flags |= HAVE_SRCIP; 1210230592Sken break; 1211230592Sken 1212230592Sken case O_IP_DST: 1213212420Sken case O_IP_DST_LOOKUP: 1214253460Sscottl case O_IP_DST_MASK: 1215230592Sken case O_IP_DST_ME: 1216237683Sken case O_IP_DST_SET: 1217237683Sken show_prerequisites(&flags, HAVE_PROTO|HAVE_SRCIP, 0); 1218230592Sken if (!(flags & HAVE_DSTIP)) 1219230592Sken printf(" to"); 1220230592Sken if ((cmd->len & F_OR) && !or_block) 1221230592Sken printf(" {"); 1222230592Sken print_ip((ipfw_insn_ip *)cmd, 1223230592Sken (flags & HAVE_OPTIONS) ? " dst-ip" : ""); 1224230592Sken flags |= HAVE_DSTIP; 1225230592Sken break; 1226230592Sken 1227230592Sken case O_IP6_SRC: 1228230592Sken case O_IP6_SRC_MASK: 1229253460Sscottl case O_IP6_SRC_ME: 1230230592Sken show_prerequisites(&flags, HAVE_PROTO, 0); 1231230592Sken if (!(flags & HAVE_SRCIP)) 1232230592Sken printf(" from"); 1233230592Sken if ((cmd->len & F_OR) && !or_block) 1234230592Sken printf(" {"); 1235230592Sken print_ip6((ipfw_insn_ip6 *)cmd, 1236230592Sken (flags & HAVE_OPTIONS) ? " src-ip6" : ""); 1237230592Sken flags |= HAVE_SRCIP | HAVE_PROTO; 1238230592Sken break; 1239230592Sken 1240230592Sken case O_IP6_DST: 1241230592Sken case O_IP6_DST_MASK: 1242230592Sken case O_IP6_DST_ME: 1243230592Sken show_prerequisites(&flags, HAVE_PROTO|HAVE_SRCIP, 0); 1244230592Sken if (!(flags & HAVE_DSTIP)) 1245230592Sken printf(" to"); 1246230592Sken if ((cmd->len & F_OR) && !or_block) 1247230592Sken printf(" {"); 1248230592Sken print_ip6((ipfw_insn_ip6 *)cmd, 1249230592Sken (flags & HAVE_OPTIONS) ? " dst-ip6" : ""); 1250230592Sken flags |= HAVE_DSTIP; 1251230592Sken break; 1252230592Sken 1253230592Sken case O_FLOW6ID: 1254253460Sscottl print_flow6id( (ipfw_insn_u32 *) cmd ); 1255230592Sken flags |= HAVE_OPTIONS; 1256230592Sken break; 1257230592Sken 1258230592Sken case O_IP_DSTPORT: 1259230592Sken show_prerequisites(&flags, 1260212420Sken HAVE_PROTO | HAVE_SRCIP | 1261212420Sken HAVE_DSTIP | HAVE_IP, 0); 1262212420Sken case O_IP_SRCPORT: 1263230592Sken show_prerequisites(&flags, 1264212420Sken HAVE_PROTO | HAVE_SRCIP, 0); 1265230592Sken if ((cmd->len & F_OR) && !or_block) 1266230592Sken printf(" {"); 1267230592Sken if (cmd->len & F_NOT) 1268212420Sken printf(" not"); 1269230592Sken print_newports((ipfw_insn_u16 *)cmd, proto, 1270230592Sken (flags & HAVE_OPTIONS) ? cmd->opcode : 0); 1271230592Sken break; 1272230592Sken 1273230592Sken case O_PROTO: { 1274230592Sken struct protoent *pe = NULL; 1275230592Sken 1276230592Sken if ((cmd->len & F_OR) && !or_block) 1277230592Sken printf(" {"); 1278230592Sken if (cmd->len & F_NOT) 1279230592Sken printf(" not"); 1280230592Sken proto = cmd->arg1; 1281253460Sscottl pe = getprotobynumber(cmd->arg1); 1282230592Sken if ((flags & (HAVE_PROTO4 | HAVE_PROTO6)) && 1283230592Sken !(flags & HAVE_PROTO)) 1284212420Sken show_prerequisites(&flags, 1285212420Sken HAVE_PROTO | HAVE_IP | HAVE_SRCIP | 1286212420Sken HAVE_DSTIP | HAVE_OPTIONS, 0); 1287230592Sken if (flags & HAVE_OPTIONS) 1288253460Sscottl printf(" proto"); 1289253460Sscottl if (pe) 1290230592Sken printf(" %s", pe->p_name); 1291230592Sken else 1292230592Sken printf(" %u", cmd->arg1); 1293230592Sken } 1294230592Sken flags |= HAVE_PROTO; 1295230592Sken break; 1296230592Sken 1297230592Sken default: /*options ... */ 1298230592Sken if (!(cmd->len & (F_OR|F_NOT))) 1299230592Sken if (((cmd->opcode == O_IP6) && 1300230592Sken (flags & HAVE_PROTO6)) || 1301230592Sken ((cmd->opcode == O_IP4) && 1302212420Sken (flags & HAVE_PROTO4))) 1303253460Sscottl break; 1304230592Sken show_prerequisites(&flags, HAVE_PROTO | HAVE_SRCIP | 1305237683Sken HAVE_DSTIP | HAVE_IP | HAVE_OPTIONS, 0); 1306237683Sken if ((cmd->len & F_OR) && !or_block) 1307212420Sken printf(" {"); 1308230592Sken if (cmd->len & F_NOT && cmd->opcode != O_IN) 1309212420Sken printf(" not"); 1310230592Sken switch(cmd->opcode) { 1311230592Sken case O_MACADDR2: { 1312230592Sken ipfw_insn_mac *m = (ipfw_insn_mac *)cmd; 1313230592Sken 1314253460Sscottl printf(" MAC"); 1315230592Sken print_mac(m->addr, m->mask); 1316213535Sken print_mac(m->addr + 6, m->mask + 6); 1317230592Sken } 1318230592Sken break; 1319230592Sken 1320230592Sken case O_MAC_TYPE: 1321230592Sken print_newports((ipfw_insn_u16 *)cmd, 1322230592Sken IPPROTO_ETHERTYPE, cmd->opcode); 1323230592Sken break; 1324230592Sken 1325230592Sken 1326230592Sken case O_FRAG: 1327230592Sken printf(" frag"); 1328253460Sscottl break; 1329230592Sken 1330230592Sken case O_FIB: 1331230592Sken printf(" fib %u", cmd->arg1 ); 1332230592Sken break; 1333213535Sken 1334213535Sken case O_IN: 1335230592Sken printf(cmd->len & F_NOT ? " out" : " in"); 1336230592Sken break; 1337213535Sken 1338230592Sken case O_DIVERTED: 1339213535Sken switch (cmd->arg1) { 1340230592Sken case 3: 1341230592Sken printf(" diverted"); 1342230592Sken break; 1343213535Sken case 1: 1344230592Sken printf(" diverted-loopback"); 1345230592Sken break; 1346253460Sscottl case 2: 1347230592Sken printf(" diverted-output"); 1348230592Sken break; 1349230592Sken default: 1350213535Sken printf(" diverted-?<%u>", cmd->arg1); 1351230592Sken break; 1352237683Sken } 1353230592Sken break; 1354230592Sken 1355213535Sken case O_LAYER2: 1356230592Sken printf(" layer2"); 1357230592Sken break; 1358230592Sken case O_XMIT: 1359230592Sken case O_RECV: 1360253460Sscottl case O_VIA: 1361253460Sscottl { 1362230592Sken char const *s; 1363230592Sken ipfw_insn_if *cmdif = (ipfw_insn_if *)cmd; 1364230592Sken 1365230592Sken if (cmd->opcode == O_XMIT) 1366230592Sken s = "xmit"; 1367230592Sken else if (cmd->opcode == O_RECV) 1368230592Sken s = "recv"; 1369253460Sscottl else /* if (cmd->opcode == O_VIA) */ 1370253460Sscottl s = "via"; 1371230592Sken if (cmdif->name[0] == '\0') 1372230592Sken printf(" %s %s", s, 1373230592Sken inet_ntoa(cmdif->p.ip)); 1374253460Sscottl else 1375230592Sken printf(" %s %s", s, cmdif->name); 1376230592Sken 1377230592Sken break; 1378230592Sken } 1379230592Sken case O_IPID: 1380230592Sken if (F_LEN(cmd) == 1) 1381230592Sken printf(" ipid %u", cmd->arg1 ); 1382230592Sken else 1383230592Sken print_newports((ipfw_insn_u16 *)cmd, 0, 1384230592Sken O_IPID); 1385230592Sken break; 1386230592Sken 1387253460Sscottl case O_IPTTL: 1388230592Sken if (F_LEN(cmd) == 1) 1389230592Sken printf(" ipttl %u", cmd->arg1 ); 1390230592Sken else 1391230592Sken print_newports((ipfw_insn_u16 *)cmd, 0, 1392213535Sken O_IPTTL); 1393213535Sken break; 1394230592Sken 1395213535Sken case O_IPVER: 1396230592Sken printf(" ipver %u", cmd->arg1 ); 1397213535Sken break; 1398230592Sken 1399230592Sken case O_IPPRECEDENCE: 1400230592Sken printf(" ipprecedence %u", (cmd->arg1) >> 5 ); 1401230592Sken break; 1402213535Sken 1403230592Sken case O_IPLEN: 1404213535Sken if (F_LEN(cmd) == 1) 1405230592Sken printf(" iplen %u", cmd->arg1 ); 1406230592Sken else 1407230592Sken print_newports((ipfw_insn_u16 *)cmd, 0, 1408213535Sken O_IPLEN); 1409212772Sken break; 1410230592Sken 1411230592Sken case O_IPOPT: 1412230592Sken print_flags("ipoptions", cmd, f_ipopts); 1413212772Sken break; 1414230592Sken 1415253460Sscottl case O_IPTOS: 1416230592Sken print_flags("iptos", cmd, f_iptos); 1417237683Sken break; 1418230592Sken 1419230592Sken case O_ICMPTYPE: 1420230592Sken print_icmptypes((ipfw_insn_u32 *)cmd); 1421212772Sken break; 1422230592Sken 1423253460Sscottl case O_ESTAB: 1424230592Sken printf(" established"); 1425237683Sken break; 1426230592Sken 1427230592Sken case O_TCPDATALEN: 1428230592Sken if (F_LEN(cmd) == 1) 1429230592Sken printf(" tcpdatalen %u", cmd->arg1 ); 1430230592Sken else 1431230592Sken print_newports((ipfw_insn_u16 *)cmd, 0, 1432230592Sken O_TCPDATALEN); 1433230592Sken break; 1434230592Sken 1435230592Sken case O_TCPFLAGS: 1436230592Sken print_flags("tcpflags", cmd, f_tcpflags); 1437212420Sken break; 1438253460Sscottl 1439230592Sken case O_TCPOPTS: 1440237683Sken print_flags("tcpoptions", cmd, f_tcpopts); 1441237683Sken break; 1442237683Sken 1443213535Sken case O_TCPWIN: 1444230592Sken printf(" tcpwin %d", ntohs(cmd->arg1)); 1445230592Sken break; 1446230592Sken 1447230592Sken case O_TCPACK: 1448213535Sken printf(" tcpack %d", ntohl(cmd32->d[0])); 1449253460Sscottl break; 1450230592Sken 1451237683Sken case O_TCPSEQ: 1452230592Sken printf(" tcpseq %d", ntohl(cmd32->d[0])); 1453230592Sken break; 1454230592Sken 1455212420Sken case O_UID: 1456237683Sken { 1457230592Sken struct passwd *pwd = getpwuid(cmd32->d[0]); 1458253460Sscottl 1459230592Sken if (pwd) 1460237683Sken printf(" uid %s", pwd->pw_name); 1461230592Sken else 1462230592Sken printf(" uid %u", cmd32->d[0]); 1463230592Sken } 1464230592Sken break; 1465230592Sken 1466230592Sken case O_GID: 1467230592Sken { 1468253460Sscottl struct group *grp = getgrgid(cmd32->d[0]); 1469230592Sken 1470237683Sken if (grp) 1471230592Sken printf(" gid %s", grp->gr_name); 1472230592Sken else 1473230592Sken printf(" gid %u", cmd32->d[0]); 1474230592Sken } 1475213535Sken break; 1476212420Sken 1477230592Sken case O_JAIL: 1478230592Sken printf(" jail %d", cmd32->d[0]); 1479230592Sken break; 1480230592Sken 1481213535Sken case O_VERREVPATH: 1482230592Sken printf(" verrevpath"); 1483230592Sken break; 1484230592Sken 1485212420Sken case O_VERSRCREACH: 1486230592Sken printf(" versrcreach"); 1487230592Sken break; 1488253460Sscottl 1489230592Sken case O_ANTISPOOF: 1490230592Sken printf(" antispoof"); 1491230592Sken break; 1492213535Sken 1493253460Sscottl case O_IPSEC: 1494253460Sscottl printf(" ipsec"); 1495253460Sscottl break; 1496230592Sken 1497237683Sken case O_NOP: 1498230592Sken comment = (char *)(cmd + 1); 1499230592Sken break; 1500213535Sken 1501230592Sken case O_KEEP_STATE: 1502230592Sken printf(" keep-state"); 1503212420Sken break; 1504237683Sken 1505213535Sken case O_LIMIT: { 1506230592Sken struct _s_x *p = limit_masks; 1507230592Sken ipfw_insn_limit *c = (ipfw_insn_limit *)cmd; 1508230592Sken uint8_t x = c->limit_mask; 1509230592Sken char const *comma = " "; 1510230592Sken 1511230592Sken printf(" limit"); 1512213535Sken for (; p->x != 0 ; p++) 1513230592Sken if ((x & p->x) == p->x) { 1514230592Sken x &= ~p->x; 1515213535Sken printf("%s%s", comma, p->s); 1516230592Sken comma = ","; 1517213535Sken } 1518230592Sken PRINT_UINT_ARG(" ", c->conn_limit); 1519230592Sken break; 1520253460Sscottl } 1521230592Sken 1522230592Sken case O_IP6: 1523230592Sken printf(" ip6"); 1524230592Sken break; 1525213535Sken 1526213535Sken case O_IP4: 1527230592Sken printf(" ip4"); 1528230592Sken break; 1529230592Sken 1530230592Sken case O_ICMP6TYPE: 1531230592Sken print_icmp6types((ipfw_insn_u32 *)cmd); 1532230592Sken break; 1533213535Sken 1534230592Sken case O_EXT_HDR: 1535230592Sken print_ext6hdr( (ipfw_insn *) cmd ); 1536213535Sken break; 1537253460Sscottl 1538230592Sken case O_TAGGED: 1539213535Sken if (F_LEN(cmd) == 1) 1540253460Sscottl PRINT_UINT_ARG(" tagged ", cmd->arg1); 1541213535Sken else 1542230592Sken print_newports((ipfw_insn_u16 *)cmd, 0, 1543230592Sken O_TAGGED); 1544230592Sken break; 1545230592Sken 1546230592Sken default: 1547230592Sken printf(" [opcode %d len %d]", 1548230592Sken cmd->opcode, cmd->len); 1549253460Sscottl } 1550253460Sscottl } 1551230592Sken if (cmd->len & F_OR) { 1552230592Sken printf(" or"); 1553213535Sken or_block = 1; 1554230592Sken } else if (or_block) { 1555253460Sscottl printf(" }"); 1556230592Sken or_block = 0; 1557230592Sken } 1558213535Sken } 1559253460Sscottl show_prerequisites(&flags, HAVE_PROTO | HAVE_SRCIP | HAVE_DSTIP 1560230592Sken | HAVE_IP, 0); 1561213535Sken if (comment) 1562230592Sken printf(" // %s", comment); 1563230592Sken printf("\n"); 1564213535Sken} 1565230592Sken 1566230592Skenstatic void 1567230592Skenshow_dyn_ipfw(ipfw_dyn_rule *d, int pcwidth, int bcwidth) 1568268197Sscottl{ 1569230592Sken struct protoent *pe; 1570230592Sken struct in_addr a; 1571230592Sken uint16_t rulenum; 1572230592Sken char buf[INET6_ADDRSTRLEN]; 1573230592Sken 1574230592Sken if (!co.do_expired) { 1575230592Sken if (!d->expire && !(d->dyn_type == O_LIMIT_PARENT)) 1576253460Sscottl return; 1577253460Sscottl } 1578230592Sken bcopy(&d->rule, &rulenum, sizeof(rulenum)); 1579213535Sken printf("%05d", rulenum); 1580230592Sken if (pcwidth>0 || bcwidth>0) 1581253460Sscottl printf(" %*llu %*llu (%ds)", pcwidth, 1582230592Sken align_uint64(&d->pcnt), bcwidth, 1583213535Sken align_uint64(&d->bcnt), d->expire); 1584230592Sken switch (d->dyn_type) { 1585230592Sken case O_LIMIT_PARENT: 1586230592Sken printf(" PARENT %d", d->count); 1587230592Sken break; 1588230592Sken case O_LIMIT: 1589230592Sken printf(" LIMIT"); 1590230592Sken break; 1591230592Sken case O_KEEP_STATE: /* bidir, no mask */ 1592230592Sken printf(" STATE"); 1593230592Sken break; 1594230592Sken } 1595230592Sken 1596230592Sken if ((pe = getprotobynumber(d->id.proto)) != NULL) 1597253460Sscottl printf(" %s", pe->p_name); 1598253460Sscottl else 1599230592Sken printf(" proto %u", d->id.proto); 1600230592Sken 1601213535Sken if (d->id.addr_type == 4) { 1602213535Sken a.s_addr = htonl(d->id.src_ip); 1603212420Sken printf(" %s %d", inet_ntoa(a), d->id.src_port); 1604212420Sken 1605212420Sken a.s_addr = htonl(d->id.dst_ip); 1606212420Sken printf(" <-> %s %d", inet_ntoa(a), d->id.dst_port); 1607212420Sken } else if (d->id.addr_type == 6) { 1608212420Sken printf(" %s %d", inet_ntop(AF_INET6, &d->id.src_ip6, buf, 1609212420Sken sizeof(buf)), d->id.src_port); 1610230592Sken printf(" <-> %s %d", inet_ntop(AF_INET6, &d->id.dst_ip6, buf, 1611212420Sken sizeof(buf)), d->id.dst_port); 1612230592Sken } else 1613230592Sken printf(" UNKNOWN <-> UNKNOWN\n"); 1614237683Sken 1615212420Sken printf("\n"); 1616212420Sken} 1617253460Sscottl 1618230592Sken/* 1619212420Sken * This one handles all set-related commands 1620212420Sken * ipfw set { show | enable | disable } 1621264492Sscottl * ipfw set swap X Y 1622264492Sscottl * ipfw set move X to Y 1623264492Sscottl * ipfw set move rule X to Y 1624212420Sken */ 1625253460Sscottlvoid 1626212420Skenipfw_sets_handler(char *av[]) 1627253460Sscottl{ 1628230592Sken uint32_t set_disable, masks[2]; 1629270250Sslm int i, nbytes; 1630212420Sken uint16_t rulenum; 1631212420Sken uint8_t cmd, new_set; 1632212420Sken 1633231240Sken av++; 1634253550Sken 1635253550Sken if (av[0] == NULL) 1636270250Sslm errx(EX_USAGE, "set needs command"); 1637231240Sken if (_substrcmp(*av, "show") == 0) { 1638231240Sken void *data = NULL; 1639231240Sken char const *msg; 1640230592Sken int nalloc; 1641253550Sken 1642253550Sken nalloc = nbytes = sizeof(struct ip_fw); 1643253550Sken while (nbytes >= nalloc) { 1644253550Sken if (data) 1645268197Sscottl free(data); 1646253550Sken nalloc = nalloc * 2 + 200; 1647253550Sken nbytes = nalloc; 1648253550Sken data = safe_calloc(1, nbytes); 1649253550Sken if (do_cmd(IP_FW_GET, data, (uintptr_t)&nbytes) < 0) 1650253550Sken err(EX_OSERR, "getsockopt(IP_FW_GET)"); 1651253550Sken } 1652230592Sken 1653230592Sken bcopy(&((struct ip_fw *)data)->next_rule, 1654230592Sken &set_disable, sizeof(set_disable)); 1655230592Sken 1656230592Sken for (i = 0, msg = "disable" ; i < RESVD_SET; i++) 1657230592Sken if ((set_disable & (1<<i))) { 1658268197Sscottl printf("%s %d", msg, i); 1659230592Sken msg = ""; 1660268197Sscottl } 1661230592Sken msg = (set_disable) ? " enable" : "enable"; 1662230592Sken for (i = 0; i < RESVD_SET; i++) 1663230592Sken if (!(set_disable & (1<<i))) { 1664212420Sken printf("%s %d", msg, i); 1665230592Sken msg = ""; 1666253460Sscottl } 1667270250Sslm printf("\n"); 1668230592Sken } else if (_substrcmp(*av, "swap") == 0) { 1669230592Sken av++; 1670230592Sken if ( av[0] == NULL || av[1] == NULL ) 1671230592Sken errx(EX_USAGE, "set swap needs 2 set numbers\n"); 1672212420Sken rulenum = atoi(av[0]); 1673270250Sslm new_set = atoi(av[1]); 1674270250Sslm if (!isdigit(*(av[0])) || rulenum > RESVD_SET) 1675270250Sslm errx(EX_DATAERR, "invalid set number %s\n", av[0]); 1676270250Sslm if (!isdigit(*(av[1])) || new_set > RESVD_SET) 1677212420Sken errx(EX_DATAERR, "invalid set number %s\n", av[1]); 1678212420Sken masks[0] = (4 << 24) | (new_set << 16) | (rulenum); 1679212420Sken i = do_cmd(IP_FW_DEL, masks, sizeof(uint32_t)); 1680212420Sken } else if (_substrcmp(*av, "move") == 0) { 1681212420Sken av++; 1682212420Sken if (av[0] && _substrcmp(*av, "rule") == 0) { 1683212420Sken cmd = 2; 1684212420Sken av++; 1685212420Sken } else 1686212420Sken cmd = 3; 1687212420Sken if (av[0] == NULL || av[1] == NULL || av[2] == NULL || 1688218812Sken av[3] != NULL || _substrcmp(av[1], "to") != 0) 1689237683Sken errx(EX_USAGE, "syntax: set move [rule] X to Y\n"); 1690212420Sken rulenum = atoi(av[0]); 1691212420Sken new_set = atoi(av[2]); 1692237683Sken if (!isdigit(*(av[0])) || (cmd == 3 && rulenum > RESVD_SET) || 1693212420Sken (cmd == 2 && rulenum == IPFW_DEFAULT_RULE) ) 1694212420Sken errx(EX_DATAERR, "invalid source number %s\n", av[0]); 1695212420Sken if (!isdigit(*(av[2])) || new_set > RESVD_SET) 1696212420Sken errx(EX_DATAERR, "invalid dest. set %s\n", av[1]); 1697212420Sken masks[0] = (cmd << 24) | (new_set << 16) | (rulenum); 1698212420Sken i = do_cmd(IP_FW_DEL, masks, sizeof(uint32_t)); 1699212420Sken } else if (_substrcmp(*av, "disable") == 0 || 1700212420Sken _substrcmp(*av, "enable") == 0 ) { 1701237683Sken int which = _substrcmp(*av, "enable") == 0 ? 1 : 0; 1702212420Sken 1703237683Sken av++; 1704212420Sken masks[0] = masks[1] = 0; 1705212420Sken 1706212420Sken while (av[0]) { 1707212420Sken if (isdigit(**av)) { 1708212420Sken i = atoi(*av); 1709237683Sken if (i < 0 || i > RESVD_SET) 1710212420Sken errx(EX_DATAERR, 1711212420Sken "invalid set number %d\n", i); 1712212420Sken masks[which] |= (1<<i); 1713237683Sken } else if (_substrcmp(*av, "disable") == 0) 1714212420Sken which = 0; 1715212420Sken else if (_substrcmp(*av, "enable") == 0) 1716212420Sken which = 1; 1717212420Sken else 1718237683Sken errx(EX_DATAERR, 1719212420Sken "invalid set command %s\n", *av); 1720212420Sken av++; 1721237683Sken } 1722253550Sken if ( (masks[0] & masks[1]) != 0 ) 1723237683Sken errx(EX_DATAERR, 1724212420Sken "cannot enable and disable the same set\n"); 1725212420Sken 1726212420Sken i = do_cmd(IP_FW_DEL, masks, sizeof(masks)); 1727212420Sken if (i) 1728212420Sken warn("set enable/disable: setsockopt(IP_FW_DEL)"); 1729212420Sken } else 1730212420Sken errx(EX_USAGE, "invalid set command %s\n", *av); 1731237683Sken} 1732212420Sken 1733212420Skenvoid 1734237683Skenipfw_sysctl_handler(char *av[], int which) 1735212420Sken{ 1736212420Sken av++; 1737237683Sken 1738212420Sken if (av[0] == NULL) { 1739212420Sken warnx("missing keyword to enable/disable\n"); 1740212420Sken } else if (_substrcmp(*av, "firewall") == 0) { 1741212420Sken sysctlbyname("net.inet.ip.fw.enable", NULL, 0, 1742237683Sken &which, sizeof(which)); 1743212420Sken } else if (_substrcmp(*av, "one_pass") == 0) { 1744212420Sken sysctlbyname("net.inet.ip.fw.one_pass", NULL, 0, 1745237683Sken &which, sizeof(which)); 1746237683Sken } else if (_substrcmp(*av, "debug") == 0) { 1747216368Sken sysctlbyname("net.inet.ip.fw.debug", NULL, 0, 1748212420Sken &which, sizeof(which)); 1749268197Sscottl } else if (_substrcmp(*av, "verbose") == 0) { 1750212420Sken sysctlbyname("net.inet.ip.fw.verbose", NULL, 0, 1751212420Sken &which, sizeof(which)); 1752212420Sken } else if (_substrcmp(*av, "dyn_keepalive") == 0) { 1753212420Sken sysctlbyname("net.inet.ip.fw.dyn_keepalive", NULL, 0, 1754212420Sken &which, sizeof(which)); 1755212420Sken#ifndef NO_ALTQ 1756212420Sken } else if (_substrcmp(*av, "altq") == 0) { 1757212420Sken altq_set_enabled(which); 1758237683Sken#endif 1759212420Sken } else { 1760216088Sken warnx("unrecognize enable/disable keyword: %s\n", *av); 1761230592Sken } 1762230592Sken} 1763230592Sken 1764230592Skenvoid 1765216088Skenipfw_list(int ac, char *av[], int show_counters) 1766230592Sken{ 1767230592Sken struct ip_fw *r; 1768230592Sken ipfw_dyn_rule *dynrules, *d; 1769230592Sken 1770230592Sken#define NEXT(r) ((struct ip_fw *)((char *)r + RULESIZE(r))) 1771230592Sken char *lim; 1772230592Sken void *data = NULL; 1773230592Sken int bcwidth, n, nbytes, nstat, ndyn, pcwidth, width; 1774230592Sken int exitval = EX_OK; 1775237683Sken int lac; 1776230592Sken char **lav; 1777230592Sken u_long rnum, last; 1778230592Sken char *endptr; 1779237683Sken int seen = 0; 1780230592Sken uint8_t set; 1781230592Sken 1782230592Sken const int ocmd = co.do_pipe ? IP_DUMMYNET_GET : IP_FW_GET; 1783230592Sken int nalloc = 1024; /* start somewhere... */ 1784230592Sken 1785230592Sken last = 0; 1786230592Sken 1787230592Sken if (co.test_only) { 1788230592Sken fprintf(stderr, "Testing only, list disabled\n"); 1789230592Sken return; 1790230592Sken } 1791230592Sken if (co.do_pipe) { 1792230592Sken dummynet_list(ac, av, show_counters); 1793230592Sken return; 1794230592Sken } 1795230592Sken 1796230592Sken ac--; 1797230592Sken av++; 1798237683Sken 1799237683Sken /* get rules or pipes from kernel, resizing array as necessary */ 1800230592Sken nbytes = nalloc; 1801230592Sken 1802230592Sken while (nbytes >= nalloc) { 1803230592Sken nalloc = nalloc * 2 + 200; 1804230592Sken nbytes = nalloc; 1805230592Sken data = safe_realloc(data, nbytes); 1806230592Sken if (do_cmd(ocmd, data, (uintptr_t)&nbytes) < 0) 1807237683Sken err(EX_OSERR, "getsockopt(IP_%s_GET)", 1808230592Sken co.do_pipe ? "DUMMYNET" : "FW"); 1809230592Sken } 1810230592Sken 1811230592Sken /* 1812230592Sken * Count static rules. They have variable size so we 1813230592Sken * need to scan the list to count them. 1814212420Sken */ 1815246713Skib for (nstat = 1, r = data, lim = (char *)data + nbytes; 1816246713Skib r->rulenum < IPFW_DEFAULT_RULE && (char *)r < lim; 1817246713Skib ++nstat, r = NEXT(r) ) 1818246713Skib ; /* nothing */ 1819246713Skib 1820246713Skib /* 1821212420Sken * Count dynamic rules. This is easier as they have 1822212420Sken * fixed size. 1823212420Sken */ 1824237683Sken r = NEXT(r); 1825212420Sken dynrules = (ipfw_dyn_rule *)r ; 1826212420Sken n = (char *)r - (char *)data; 1827212420Sken ndyn = (nbytes - n) / sizeof *dynrules; 1828230592Sken 1829230592Sken /* if showing stats, figure out column widths ahead of time */ 1830212420Sken bcwidth = pcwidth = 0; 1831230592Sken if (show_counters) { 1832230592Sken for (n = 0, r = data; n < nstat; n++, r = NEXT(r)) { 1833230592Sken /* skip rules from another set */ 1834230592Sken if (co.use_set && r->set != co.use_set - 1) 1835230592Sken continue; 1836230592Sken 1837268197Sscottl /* packet counter */ 1838230592Sken width = snprintf(NULL, 0, "%llu", 1839230592Sken align_uint64(&r->pcnt)); 1840268197Sscottl if (width > pcwidth) 1841230592Sken pcwidth = width; 1842230592Sken 1843218812Sken /* byte counter */ 1844212420Sken width = snprintf(NULL, 0, "%llu", 1845212420Sken align_uint64(&r->bcnt)); 1846212420Sken if (width > bcwidth) 1847230592Sken bcwidth = width; 1848230592Sken } 1849230592Sken } 1850253550Sken if (co.do_dynamic && ndyn) { 1851230592Sken for (n = 0, d = dynrules; n < ndyn; n++, d++) { 1852253460Sscottl if (co.use_set) { 1853253460Sscottl /* skip rules from another set */ 1854230592Sken bcopy((char *)&d->rule + sizeof(uint16_t), 1855212420Sken &set, sizeof(uint8_t)); 1856212420Sken if (set != co.use_set - 1) 1857212420Sken continue; 1858212420Sken } 1859212420Sken width = snprintf(NULL, 0, "%llu", 1860231240Sken align_uint64(&d->pcnt)); 1861231240Sken if (width > pcwidth) 1862231240Sken pcwidth = width; 1863231240Sken 1864231240Sken width = snprintf(NULL, 0, "%llu", 1865231240Sken align_uint64(&d->bcnt)); 1866231240Sken if (width > bcwidth) 1867231240Sken bcwidth = width; 1868231240Sken } 1869231240Sken } 1870231240Sken /* if no rule numbers were specified, list all rules */ 1871231240Sken if (ac == 0) { 1872231240Sken for (n = 0, r = data; n < nstat; n++, r = NEXT(r)) { 1873231240Sken if (co.use_set && r->set != co.use_set - 1) 1874231240Sken continue; 1875231240Sken show_ipfw(r, pcwidth, bcwidth); 1876231240Sken } 1877231240Sken 1878231240Sken if (co.do_dynamic && ndyn) { 1879231240Sken printf("## Dynamic rules (%d):\n", ndyn); 1880231240Sken for (n = 0, d = dynrules; n < ndyn; n++, d++) { 1881231240Sken if (co.use_set) { 1882231240Sken bcopy((char *)&d->rule + sizeof(uint16_t), 1883231240Sken &set, sizeof(uint8_t)); 1884231240Sken if (set != co.use_set - 1) 1885231240Sken continue; 1886231240Sken } 1887231240Sken show_dyn_ipfw(d, pcwidth, bcwidth); 1888231240Sken } 1889231240Sken } 1890231240Sken goto done; 1891231240Sken } 1892231240Sken 1893253460Sscottl /* display specific rules requested on command line */ 1894231240Sken 1895231240Sken for (lac = ac, lav = av; lac != 0; lac--) { 1896231240Sken /* convert command line rule # */ 1897231240Sken last = rnum = strtoul(*lav++, &endptr, 10); 1898231240Sken if (*endptr == '-') 1899231240Sken last = strtoul(endptr+1, &endptr, 10); 1900231240Sken if (*endptr) { 1901231240Sken exitval = EX_USAGE; 1902231240Sken warnx("invalid rule number: %s", *(lav - 1)); 1903231240Sken continue; 1904231240Sken } 1905231240Sken for (n = seen = 0, r = data; n < nstat; n++, r = NEXT(r) ) { 1906231240Sken if (r->rulenum > last) 1907231240Sken break; 1908231240Sken if (co.use_set && r->set != co.use_set - 1) 1909231240Sken continue; 1910231240Sken if (r->rulenum >= rnum && r->rulenum <= last) { 1911231240Sken show_ipfw(r, pcwidth, bcwidth); 1912231240Sken seen = 1; 1913231240Sken } 1914231240Sken } 1915231240Sken if (!seen) { 1916231240Sken /* give precedence to other error(s) */ 1917231240Sken if (exitval == EX_OK) 1918231240Sken exitval = EX_UNAVAILABLE; 1919231240Sken warnx("rule %lu does not exist", rnum); 1920231240Sken } 1921231240Sken } 1922231240Sken 1923231240Sken if (co.do_dynamic && ndyn) { 1924231240Sken printf("## Dynamic rules:\n"); 1925231240Sken for (lac = ac, lav = av; lac != 0; lac--) { 1926231240Sken last = rnum = strtoul(*lav++, &endptr, 10); 1927231240Sken if (*endptr == '-') 1928231240Sken last = strtoul(endptr+1, &endptr, 10); 1929231240Sken if (*endptr) 1930231240Sken /* already warned */ 1931231240Sken continue; 1932231240Sken for (n = 0, d = dynrules; n < ndyn; n++, d++) { 1933231240Sken uint16_t rulenum; 1934231240Sken 1935231240Sken bcopy(&d->rule, &rulenum, sizeof(rulenum)); 1936231240Sken if (rulenum > rnum) 1937231240Sken break; 1938231240Sken if (co.use_set) { 1939231240Sken bcopy((char *)&d->rule + sizeof(uint16_t), 1940231240Sken &set, sizeof(uint8_t)); 1941231240Sken if (set != co.use_set - 1) 1942231240Sken continue; 1943231240Sken } 1944231240Sken if (r->rulenum >= rnum && r->rulenum <= last) 1945231240Sken show_dyn_ipfw(d, pcwidth, bcwidth); 1946231240Sken } 1947231240Sken } 1948231240Sken } 1949231240Sken 1950231240Sken ac = 0; 1951231240Sken 1952231240Skendone: 1953231240Sken free(data); 1954231240Sken 1955231240Sken if (exitval != EX_OK) 1956231240Sken exit(exitval); 1957231240Sken#undef NEXT 1958231240Sken} 1959231240Sken 1960231240Skenstatic int 1961231240Skenlookup_host (char *host, struct in_addr *ipaddr) 1962231240Sken{ 1963231240Sken struct hostent *he; 1964231240Sken 1965231240Sken if (!inet_aton(host, ipaddr)) { 1966231240Sken if ((he = gethostbyname(host)) == NULL) 1967231240Sken return(-1); 1968231240Sken *ipaddr = *(struct in_addr *)he->h_addr_list[0]; 1969231240Sken } 1970231240Sken return(0); 1971231240Sken} 1972231240Sken 1973231240Sken/* 1974231240Sken * fills the addr and mask fields in the instruction as appropriate from av. 1975231240Sken * Update length as appropriate. 1976231240Sken * The following formats are allowed: 1977231240Sken * me returns O_IP_*_ME 1978231240Sken * 1.2.3.4 single IP address 1979231240Sken * 1.2.3.4:5.6.7.8 address:mask 1980231240Sken * 1.2.3.4/24 address/mask 1981231240Sken * 1.2.3.4/26{1,6,5,4,23} set of addresses in a subnet 1982231240Sken * We can have multiple comma-separated address/mask entries. 1983231240Sken */ 1984231240Skenstatic void 1985231240Skenfill_ip(ipfw_insn_ip *cmd, char *av) 1986231240Sken{ 1987231240Sken int len = 0; 1988231240Sken uint32_t *d = ((ipfw_insn_u32 *)cmd)->d; 1989231240Sken 1990231240Sken cmd->o.len &= ~F_LEN_MASK; /* zero len */ 1991231240Sken 1992231240Sken if (_substrcmp(av, "any") == 0) 1993231240Sken return; 1994231240Sken 1995231240Sken if (_substrcmp(av, "me") == 0) { 1996231240Sken cmd->o.len |= F_INSN_SIZE(ipfw_insn); 1997231240Sken return; 1998231240Sken } 1999231240Sken 2000231240Sken if (strncmp(av, "table(", 6) == 0) { 2001231240Sken char *p = strchr(av + 6, ','); 2002231240Sken 2003231240Sken if (p) 2004231240Sken *p++ = '\0'; 2005231240Sken cmd->o.opcode = O_IP_DST_LOOKUP; 2006231240Sken cmd->o.arg1 = strtoul(av + 6, NULL, 0); 2007231240Sken if (p) { 2008231240Sken cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32); 2009231240Sken d[0] = strtoul(p, NULL, 0); 2010231240Sken } else 2011231240Sken cmd->o.len |= F_INSN_SIZE(ipfw_insn); 2012231240Sken return; 2013231240Sken } 2014231240Sken 2015231240Sken while (av) { 2016231240Sken /* 2017231240Sken * After the address we can have '/' or ':' indicating a mask, 2018231240Sken * ',' indicating another address follows, '{' indicating a 2019231240Sken * set of addresses of unspecified size. 2020231240Sken */ 2021231240Sken char *t = NULL, *p = strpbrk(av, "/:,{"); 2022231240Sken int masklen; 2023231240Sken char md, nd = '\0'; 2024231240Sken 2025231240Sken if (p) { 2026231240Sken md = *p; 2027253460Sscottl *p++ = '\0'; 2028253460Sscottl if ((t = strpbrk(p, ",{")) != NULL) { 2029231240Sken nd = *t; 2030231240Sken *t = '\0'; 2031231240Sken } 2032253460Sscottl } else 2033253550Sken md = '\0'; 2034253550Sken 2035231240Sken if (lookup_host(av, (struct in_addr *)&d[0]) != 0) 2036253460Sscottl errx(EX_NOHOST, "hostname ``%s'' unknown", av); 2037231240Sken switch (md) { 2038253460Sscottl case ':': 2039231240Sken if (!inet_aton(p, (struct in_addr *)&d[1])) 2040253460Sscottl errx(EX_DATAERR, "bad netmask ``%s''", p); 2041231240Sken break; 2042231240Sken case '/': 2043231240Sken masklen = atoi(p); 2044231240Sken if (masklen == 0) 2045231240Sken d[1] = htonl(0); /* mask */ 2046231240Sken else if (masklen > 32) 2047231240Sken errx(EX_DATAERR, "bad width ``%s''", p); 2048231240Sken else 2049231240Sken d[1] = htonl(~0 << (32 - masklen)); 2050231240Sken break; 2051212420Sken case '{': /* no mask, assume /24 and put back the '{' */ 2052212420Sken d[1] = htonl(~0 << (32 - 24)); 2053212420Sken *(--p) = md; 2054212420Sken break; 2055230592Sken 2056212420Sken case ',': /* single address plus continuation */ 2057230592Sken *(--p) = md; 2058230592Sken /* FALLTHROUGH */ 2059230592Sken case 0: /* initialization value */ 2060230592Sken default: 2061212420Sken d[1] = htonl(~0); /* force /32 */ 2062253460Sscottl break; 2063230592Sken } 2064253460Sscottl d[0] &= d[1]; /* mask base address with mask */ 2065253460Sscottl if (t) 2066230592Sken *t = nd; 2067212420Sken /* find next separator */ 2068212420Sken if (p) 2069230592Sken p = strpbrk(p, ",{"); 2070212420Sken if (p && *p == '{') { 2071212420Sken /* 2072212420Sken * We have a set of addresses. They are stored as follows: 2073230592Sken * arg1 is the set size (powers of 2, 2..256) 2074212420Sken * addr is the base address IN HOST FORMAT 2075218812Sken * mask.. is an array of arg1 bits (rounded up to 2076218812Sken * the next multiple of 32) with bits set 2077218812Sken * for each host in the map. 2078218812Sken */ 2079218812Sken uint32_t *map = (uint32_t *)&cmd->mask; 2080212420Sken int low, high; 2081212420Sken int i = contigmask((uint8_t *)&(d[1]), 32); 2082212420Sken 2083212420Sken if (len > 0) 2084241844Seadler errx(EX_DATAERR, "address set cannot be in a list"); 2085212420Sken if (i < 24 || i > 31) 2086212420Sken errx(EX_DATAERR, "invalid set with mask %d\n", i); 2087212420Sken cmd->o.arg1 = 1<<(32-i); /* map length */ 2088212420Sken d[0] = ntohl(d[0]); /* base addr in host format */ 2089230592Sken cmd->o.opcode = O_IP_DST_SET; /* default */ 2090230592Sken cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32) + (cmd->o.arg1+31)/32; 2091230592Sken for (i = 0; i < (cmd->o.arg1+31)/32 ; i++) 2092254615Sken map[i] = 0; /* clear map */ 2093230592Sken 2094230592Sken av = p + 1; 2095230592Sken low = d[0] & 0xff; 2096230592Sken high = low + cmd->o.arg1 - 1; 2097253460Sscottl /* 2098230592Sken * Here, i stores the previous value when we specify a range 2099230592Sken * of addresses within a mask, e.g. 45-63. i = -1 means we 2100230592Sken * have no previous value. 2101237683Sken */ 2102237683Sken i = -1; /* previous value in a range */ 2103230592Sken while (isdigit(*av)) { 2104253460Sscottl char *s; 2105230592Sken int a = strtol(av, &s, 0); 2106230592Sken 2107230592Sken if (s == av) { /* no parameter */ 2108230592Sken if (*av != '}') 2109253460Sscottl errx(EX_DATAERR, "set not closed\n"); 2110230592Sken if (i != -1) 2111230592Sken errx(EX_DATAERR, "incomplete range %d-", i); 2112230592Sken break; 2113237683Sken } 2114237683Sken if (a < low || a > high) 2115230592Sken errx(EX_DATAERR, "addr %d out of range [%d-%d]\n", 2116253460Sscottl a, low, high); 2117230592Sken a -= low; 2118230592Sken if (i == -1) /* no previous in range */ 2119230592Sken i = a; 2120253460Sscottl else { /* check that range is valid */ 2121230592Sken if (i > a) 2122230592Sken errx(EX_DATAERR, "invalid range %d-%d", 2123230592Sken i+low, a+low); 2124230592Sken if (*s == '-') 2125218812Sken errx(EX_DATAERR, "double '-' in range"); 2126218812Sken } 2127218812Sken for (; i <= a; i++) 2128218812Sken map[i/32] |= 1<<(i & 31); 2129218812Sken i = -1; 2130218812Sken if (*s == '-') 2131218812Sken i = a; 2132218812Sken else if (*s == '}') 2133218812Sken break; 2134268197Sscottl av = s+1; 2135218812Sken } 2136218812Sken return; 2137218812Sken } 2138218812Sken av = p; 2139218812Sken if (av) /* then *av must be a ',' */ 2140218812Sken av++; 2141218812Sken 2142218812Sken /* Check this entry */ 2143218812Sken if (d[1] == 0) { /* "any", specified as x.x.x.x/0 */ 2144218812Sken /* 2145218812Sken * 'any' turns the entire list into a NOP. 2146218812Sken * 'not any' never matches, so it is removed from the 2147218812Sken * list unless it is the only item, in which case we 2148218812Sken * report an error. 2149218812Sken */ 2150253460Sscottl if (cmd->o.len & F_NOT) { /* "not any" never matches */ 2151219036Sken if (av == NULL && len == 0) /* only this entry */ 2152218812Sken errx(EX_DATAERR, "not any never matches"); 2153212420Sken } 2154212420Sken /* else do nothing and skip this entry */ 2155270250Sslm return; 2156270250Sslm } 2157270250Sslm /* A single IP can be stored in an optimized format */ 2158270250Sslm if (d[1] == (uint32_t)~0 && av == NULL && len == 0) { 2159270250Sslm cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32); 2160270250Sslm return; 2161270250Sslm } 2162270250Sslm len += 2; /* two words... */ 2163270250Sslm d += 2; 2164270250Sslm } /* end while */ 2165270250Sslm if (len + 1 > F_LEN_MASK) 2166270250Sslm errx(EX_DATAERR, "address list too long"); 2167212420Sken cmd->o.len |= len+1; 2168212420Sken} 2169268197Sscottl 2170230592Sken 2171268197Sscottl/* n2mask sets n bits of the mask */ 2172230592Skenvoid 2173268197Sscottln2mask(struct in6_addr *mask, int n) 2174230592Sken{ 2175230592Sken static int minimask[9] = 2176218812Sken { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff }; 2177218812Sken u_char *p; 2178218812Sken 2179253460Sscottl memset(mask, 0, sizeof(struct in6_addr)); 2180253550Sken p = (u_char *) mask; 2181218812Sken for (; n > 0; p++, n -= 8) { 2182230592Sken if (n >= 8) 2183230592Sken *p = 0xff; 2184230592Sken else 2185230592Sken *p = minimask[n]; 2186230592Sken } 2187230592Sken return; 2188230592Sken} 2189268197Sscottl 2190230592Sken 2191230592Sken/* 2192268197Sscottl * helper function to process a set of flags and set bits in the 2193230592Sken * appropriate masks. 2194230592Sken */ 2195218812Skenstatic void 2196218812Skenfill_flags(ipfw_insn *cmd, enum ipfw_opcodes opcode, 2197218811Sken struct _s_x *flags, char *p) 2198212420Sken{ 2199212420Sken uint8_t set=0, clear=0; 2200212420Sken 2201212420Sken while (p && *p) { 2202212420Sken char *q; /* points to the separator */ 2203253460Sscottl int val; 2204253460Sscottl uint8_t *which; /* mask we are working on */ 2205253460Sscottl 2206253460Sscottl if (*p == '!') { 2207212420Sken p++; 2208230592Sken which = &clear; 2209230592Sken } else 2210230592Sken which = &set; 2211230592Sken q = strchr(p, ','); 2212230592Sken if (q) 2213230592Sken *q++ = '\0'; 2214230592Sken val = match_token(flags, p); 2215230592Sken if (val <= 0) 2216268197Sscottl errx(EX_DATAERR, "invalid flag %s", p); 2217230592Sken *which |= (uint8_t)val; 2218230592Sken p = q; 2219268197Sscottl } 2220268197Sscottl cmd->opcode = opcode; 2221230592Sken cmd->len = (cmd->len & (F_NOT | F_OR)) | 1; 2222237683Sken cmd->arg1 = (set & 0xff) | ( (clear & 0xff) << 8); 2223212420Sken} 2224237683Sken 2225212420Sken 2226212420Skenvoid 2227212420Skenipfw_delete(char *av[]) 2228230592Sken{ 2229237683Sken uint32_t rulenum; 2230230592Sken int i; 2231253460Sscottl int exitval = EX_OK; 2232230592Sken int do_set = 0; 2233230592Sken 2234230592Sken av++; 2235230592Sken NEED1("missing rule specification"); 2236268197Sscottl if ( *av && _substrcmp(*av, "set") == 0) { 2237230592Sken /* Do not allow using the following syntax: 2238230592Sken * ipfw set N delete set M 2239230592Sken */ 2240230592Sken if (co.use_set) 2241230592Sken errx(EX_DATAERR, "invalid syntax"); 2242230592Sken do_set = 1; /* delete set */ 2243230592Sken av++; 2244230592Sken } 2245268197Sscottl 2246230592Sken /* Rule number */ 2247230592Sken while (*av && isdigit(**av)) { 2248230592Sken i = atoi(*av); av++; 2249230592Sken if (co.do_nat) { 2250230592Sken exitval = do_cmd(IP_FW_NAT_DEL, &i, sizeof i); 2251230592Sken if (exitval) { 2252230592Sken exitval = EX_UNAVAILABLE; 2253230592Sken warn("rule %u not available", i); 2254230592Sken } 2255237683Sken } else if (co.do_pipe) { 2256230592Sken exitval = ipfw_delete_pipe(co.do_pipe, i); 2257230592Sken } else { 2258230592Sken if (co.use_set) 2259230592Sken rulenum = (i & 0xffff) | (5 << 24) | 2260230592Sken ((co.use_set - 1) << 16); 2261230592Sken else 2262230592Sken rulenum = (i & 0xffff) | (do_set << 24); 2263230592Sken i = do_cmd(IP_FW_DEL, &rulenum, sizeof rulenum); 2264230592Sken if (i) { 2265230592Sken exitval = EX_UNAVAILABLE; 2266230592Sken warn("rule %u: setsockopt(IP_FW_DEL)", 2267230592Sken rulenum); 2268230592Sken } 2269268197Sscottl } 2270230592Sken } 2271230592Sken if (exitval != EX_OK) 2272230592Sken exit(exitval); 2273230592Sken} 2274230592Sken 2275230592Sken 2276268197Sscottl/* 2277230592Sken * fill the interface structure. We do not check the name as we can 2278268197Sscottl * create interfaces dynamically, so checking them at insert time 2279230592Sken * makes relatively little sense. 2280230592Sken * Interface names containing '*', '?', or '[' are assumed to be shell 2281230592Sken * patterns which match interfaces. 2282230592Sken */ 2283237683Skenstatic void 2284230592Skenfill_iface(ipfw_insn_if *cmd, char *arg) 2285230592Sken{ 2286230592Sken cmd->name[0] = '\0'; 2287230592Sken cmd->o.len |= F_INSN_SIZE(ipfw_insn_if); 2288230592Sken 2289230592Sken /* Parse the interface or address */ 2290230592Sken if (strcmp(arg, "any") == 0) 2291230592Sken cmd->o.len = 0; /* effectively ignore this command */ 2292230592Sken else if (!isdigit(*arg)) { 2293230592Sken strlcpy(cmd->name, arg, sizeof(cmd->name)); 2294237546Skevlo cmd->p.glob = strpbrk(arg, "*?[") != NULL ? 1 : 0; 2295230592Sken } else if (!inet_aton(arg, &cmd->p.ip)) 2296230592Sken errx(EX_DATAERR, "bad ip address ``%s''", arg); 2297230592Sken} 2298230592Sken 2299230592Skenstatic void 2300230592Skenget_mac_addr_mask(const char *p, uint8_t *addr, uint8_t *mask) 2301230592Sken{ 2302230592Sken int i; 2303230592Sken size_t l; 2304230592Sken char *ap, *ptr, *optr; 2305230592Sken struct ether_addr *mac; 2306230592Sken const char *macset = "0123456789abcdefABCDEF:"; 2307230592Sken 2308230592Sken if (strcmp(p, "any") == 0) { 2309230592Sken for (i = 0; i < ETHER_ADDR_LEN; i++) 2310248825Smav addr[i] = mask[i] = 0; 2311266548Sken return; 2312266548Sken } 2313266548Sken 2314230592Sken optr = ptr = strdup(p); 2315230592Sken if ((ap = strsep(&ptr, "&/")) != NULL && *ap != 0) { 2316230592Sken l = strlen(ap); 2317230592Sken if (strspn(ap, macset) != l || (mac = ether_aton(ap)) == NULL) 2318230592Sken errx(EX_DATAERR, "Incorrect MAC address"); 2319230592Sken bcopy(mac, addr, ETHER_ADDR_LEN); 2320230592Sken } else 2321230592Sken errx(EX_DATAERR, "Incorrect MAC address"); 2322230592Sken 2323230592Sken if (ptr != NULL) { /* we have mask? */ 2324266548Sken if (p[ptr - optr - 1] == '/') { /* mask len */ 2325230592Sken long ml = strtol(ptr, &ap, 10); 2326230592Sken if (*ap != 0 || ml > ETHER_ADDR_LEN * 8 || ml < 0) 2327230592Sken errx(EX_DATAERR, "Incorrect mask length"); 2328230592Sken for (i = 0; ml > 0 && i < ETHER_ADDR_LEN; ml -= 8, i++) 2329230592Sken mask[i] = (ml >= 8) ? 0xff: (~0) << (8 - ml); 2330230592Sken } else { /* mask */ 2331230592Sken l = strlen(ptr); 2332212420Sken if (strspn(ptr, macset) != l || 2333212420Sken (mac = ether_aton(ptr)) == NULL) 2334212420Sken errx(EX_DATAERR, "Incorrect mask"); 2335230592Sken bcopy(mac, mask, ETHER_ADDR_LEN); 2336230592Sken } 2337230592Sken } else { /* default mask: ff:ff:ff:ff:ff:ff */ 2338230592Sken for (i = 0; i < ETHER_ADDR_LEN; i++) 2339230592Sken mask[i] = 0xff; 2340230592Sken } 2341230592Sken for (i = 0; i < ETHER_ADDR_LEN; i++) 2342268197Sscottl addr[i] &= mask[i]; 2343230592Sken 2344268197Sscottl free(optr); 2345212420Sken} 2346230592Sken 2347230592Sken/* 2348268197Sscottl * helper function, updates the pointer to cmd with the length 2349230592Sken * of the current command, and also cleans up the first word of 2350212420Sken * the new command in case it has been clobbered before. 2351212420Sken */ 2352212420Skenstatic ipfw_insn * 2353212420Skennext_cmd(ipfw_insn *cmd) 2354212420Sken{ 2355212420Sken cmd += F_LEN(cmd); 2356212420Sken bzero(cmd, sizeof(*cmd)); 2357212420Sken return cmd; 2358212420Sken} 2359212420Sken 2360212420Sken/* 2361268197Sscottl * Takes arguments and copies them into a comment 2362212420Sken */ 2363268197Sscottlstatic void 2364212420Skenfill_comment(ipfw_insn *cmd, char **av) 2365230592Sken{ 2366230592Sken int i, l; 2367230592Sken char *p = (char *)(cmd + 1); 2368268197Sscottl 2369230592Sken cmd->opcode = O_NOP; 2370212420Sken cmd->len = (cmd->len & (F_NOT | F_OR)); 2371212420Sken 2372230592Sken /* Compute length of comment string. */ 2373230592Sken for (i = 0, l = 0; av[i] != NULL; i++) 2374230592Sken l += strlen(av[i]) + 1; 2375230592Sken if (l == 0) 2376230592Sken return; 2377268197Sscottl if (l > 84) 2378253460Sscottl errx(EX_DATAERR, 2379230592Sken "comment too long (max 80 chars)"); 2380253460Sscottl l = 1 + (l+3)/4; 2381253460Sscottl cmd->len = (cmd->len & (F_NOT | F_OR)) | l; 2382212420Sken for (i = 0; av[i] != NULL; i++) { 2383212420Sken strcpy(p, av[i]); 2384212420Sken p += strlen(av[i]); 2385212420Sken *p++ = ' '; 2386212420Sken } 2387212420Sken *(--p) = '\0'; 2388212420Sken} 2389212420Sken 2390212420Sken/* 2391212420Sken * A function to fill simple commands of size 1. 2392212420Sken * Existing flags are preserved. 2393212420Sken */ 2394253460Sscottlstatic void 2395230592Skenfill_cmd(ipfw_insn *cmd, enum ipfw_opcodes opcode, int flags, uint16_t arg) 2396253460Sscottl{ 2397253460Sscottl cmd->opcode = opcode; 2398230592Sken cmd->len = ((cmd->len | flags) & (F_NOT | F_OR)) | 1; 2399268197Sscottl cmd->arg1 = arg; 2400230592Sken} 2401212420Sken 2402231240Sken/* 2403231240Sken * Fetch and add the MAC address and type, with masks. This generates one or 2404212420Sken * two microinstructions, and returns the pointer to the last one. 2405230592Sken */ 2406230592Skenstatic ipfw_insn * 2407230592Skenadd_mac(ipfw_insn *cmd, char *av[]) 2408253460Sscottl{ 2409253550Sken ipfw_insn_mac *mac; 2410230592Sken 2411212420Sken if ( ( av[0] == NULL ) || ( av[1] == NULL ) ) 2412268197Sscottl errx(EX_DATAERR, "MAC dst src"); 2413230592Sken 2414230592Sken cmd->opcode = O_MACADDR2; 2415230592Sken cmd->len = (cmd->len & (F_NOT | F_OR)) | F_INSN_SIZE(ipfw_insn_mac); 2416212420Sken 2417230592Sken mac = (ipfw_insn_mac *)cmd; 2418230592Sken get_mac_addr_mask(av[0], mac->addr, mac->mask); /* dst */ 2419230592Sken get_mac_addr_mask(av[1], &(mac->addr[ETHER_ADDR_LEN]), 2420230592Sken &(mac->mask[ETHER_ADDR_LEN])); /* src */ 2421237683Sken return cmd; 2422230592Sken} 2423230592Sken 2424230592Skenstatic ipfw_insn * 2425230592Skenadd_mactype(ipfw_insn *cmd, char *av) 2426230592Sken{ 2427230592Sken if (!av) 2428230592Sken errx(EX_DATAERR, "missing MAC type"); 2429230592Sken if (strcmp(av, "any") != 0) { /* we have a non-null type */ 2430230592Sken fill_newports((ipfw_insn_u16 *)cmd, av, IPPROTO_ETHERTYPE); 2431230592Sken cmd->opcode = O_MAC_TYPE; 2432230592Sken return cmd; 2433230592Sken } else 2434230592Sken return NULL; 2435230592Sken} 2436230592Sken 2437230592Skenstatic ipfw_insn * 2438230592Skenadd_proto0(ipfw_insn *cmd, char *av, u_char *protop) 2439230592Sken{ 2440230592Sken struct protoent *pe; 2441230592Sken char *ep; 2442230592Sken int proto; 2443230592Sken 2444230592Sken proto = strtol(av, &ep, 10); 2445230592Sken if (*ep != '\0' || proto <= 0) { 2446230592Sken if ((pe = getprotobyname(av)) == NULL) 2447230592Sken return NULL; 2448230592Sken proto = pe->p_proto; 2449230592Sken } 2450230592Sken 2451230592Sken fill_cmd(cmd, O_PROTO, 0, proto); 2452230592Sken *protop = proto; 2453230592Sken return cmd; 2454230592Sken} 2455230592Sken 2456230592Skenstatic ipfw_insn * 2457230592Skenadd_proto(ipfw_insn *cmd, char *av, u_char *protop) 2458230592Sken{ 2459230592Sken u_char proto = IPPROTO_IP; 2460230592Sken 2461230592Sken if (_substrcmp(av, "all") == 0 || strcmp(av, "ip") == 0) 2462230592Sken ; /* do not set O_IP4 nor O_IP6 */ 2463230592Sken else if (strcmp(av, "ip4") == 0) 2464230592Sken /* explicit "just IPv4" rule */ 2465230592Sken fill_cmd(cmd, O_IP4, 0, 0); 2466230592Sken else if (strcmp(av, "ip6") == 0) { 2467230592Sken /* explicit "just IPv6" rule */ 2468230592Sken proto = IPPROTO_IPV6; 2469230592Sken fill_cmd(cmd, O_IP6, 0, 0); 2470230592Sken } else 2471230592Sken return add_proto0(cmd, av, protop); 2472230592Sken 2473230592Sken *protop = proto; 2474230592Sken return cmd; 2475230592Sken} 2476230592Sken 2477230592Skenstatic ipfw_insn * 2478230592Skenadd_proto_compat(ipfw_insn *cmd, char *av, u_char *protop) 2479230592Sken{ 2480237683Sken u_char proto = IPPROTO_IP; 2481237683Sken 2482230592Sken if (_substrcmp(av, "all") == 0 || strcmp(av, "ip") == 0) 2483230592Sken ; /* do not set O_IP4 nor O_IP6 */ 2484230592Sken else if (strcmp(av, "ipv4") == 0 || strcmp(av, "ip4") == 0) 2485230592Sken /* explicit "just IPv4" rule */ 2486230592Sken fill_cmd(cmd, O_IP4, 0, 0); 2487230592Sken else if (strcmp(av, "ipv6") == 0 || strcmp(av, "ip6") == 0) { 2488230592Sken /* explicit "just IPv6" rule */ 2489230592Sken proto = IPPROTO_IPV6; 2490230592Sken fill_cmd(cmd, O_IP6, 0, 0); 2491230592Sken } else 2492230592Sken return add_proto0(cmd, av, protop); 2493230592Sken 2494230592Sken *protop = proto; 2495230592Sken return cmd; 2496230592Sken} 2497230592Sken 2498230592Skenstatic ipfw_insn * 2499230592Skenadd_srcip(ipfw_insn *cmd, char *av) 2500230592Sken{ 2501230592Sken fill_ip((ipfw_insn_ip *)cmd, av); 2502230592Sken if (cmd->opcode == O_IP_DST_SET) /* set */ 2503212420Sken cmd->opcode = O_IP_SRC_SET; 2504230592Sken else if (cmd->opcode == O_IP_DST_LOOKUP) /* table */ 2505212420Sken cmd->opcode = O_IP_SRC_LOOKUP; 2506212420Sken else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) /* me */ 2507230592Sken cmd->opcode = O_IP_SRC_ME; 2508237683Sken else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn_u32)) /* one IP */ 2509230592Sken cmd->opcode = O_IP_SRC; 2510230592Sken else /* addr/mask */ 2511230592Sken cmd->opcode = O_IP_SRC_MASK; 2512237683Sken return cmd; 2513237683Sken} 2514230592Sken 2515230592Skenstatic ipfw_insn * 2516230592Skenadd_dstip(ipfw_insn *cmd, char *av) 2517237683Sken{ 2518237683Sken fill_ip((ipfw_insn_ip *)cmd, av); 2519237683Sken if (cmd->opcode == O_IP_DST_SET) /* set */ 2520230592Sken ; 2521237683Sken else if (cmd->opcode == O_IP_DST_LOOKUP) /* table */ 2522237683Sken ; 2523230592Sken else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) /* me */ 2524230592Sken cmd->opcode = O_IP_DST_ME; 2525230592Sken else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn_u32)) /* one IP */ 2526230592Sken cmd->opcode = O_IP_DST; 2527230592Sken else /* addr/mask */ 2528225950Sken cmd->opcode = O_IP_DST_MASK; 2529230592Sken return cmd; 2530230592Sken} 2531230592Sken 2532230592Skenstatic ipfw_insn * 2533237683Skenadd_ports(ipfw_insn *cmd, char *av, u_char proto, int opcode) 2534237683Sken{ 2535237683Sken /* XXX "any" is trapped before. Perhaps "to" */ 2536237683Sken if (_substrcmp(av, "any") == 0) { 2537230592Sken return NULL; 2538230592Sken } else if (fill_newports((ipfw_insn_u16 *)cmd, av, proto)) { 2539230592Sken /* XXX todo: check that we have a protocol with ports */ 2540230592Sken cmd->opcode = opcode; 2541225950Sken return cmd; 2542230592Sken } 2543230592Sken return NULL; 2544230592Sken} 2545230592Sken 2546230592Skenstatic ipfw_insn * 2547230592Skenadd_src(ipfw_insn *cmd, char *av, u_char proto) 2548230592Sken{ 2549230592Sken struct in6_addr a; 2550230592Sken char *host, *ch; 2551230592Sken ipfw_insn *ret = NULL; 2552230592Sken 2553230592Sken if ((host = strdup(av)) == NULL) 2554230592Sken return NULL; 2555230592Sken if ((ch = strrchr(host, '/')) != NULL) 2556230592Sken *ch = '\0'; 2557230592Sken 2558230592Sken if (proto == IPPROTO_IPV6 || strcmp(av, "me6") == 0 || 2559230592Sken inet_pton(AF_INET6, host, &a) == 1) 2560230592Sken ret = add_srcip6(cmd, av); 2561230592Sken /* XXX: should check for IPv4, not !IPv6 */ 2562230592Sken if (ret == NULL && (proto == IPPROTO_IP || strcmp(av, "me") == 0 || 2563230592Sken inet_pton(AF_INET6, host, &a) != 1)) 2564230592Sken ret = add_srcip(cmd, av); 2565230592Sken if (ret == NULL && strcmp(av, "any") != 0) 2566230592Sken ret = cmd; 2567230592Sken 2568230592Sken free(host); 2569237683Sken return ret; 2570237683Sken} 2571230592Sken 2572230592Skenstatic ipfw_insn * 2573212420Skenadd_dst(ipfw_insn *cmd, char *av, u_char proto) 2574230592Sken{ 2575230592Sken struct in6_addr a; 2576230592Sken char *host, *ch; 2577230592Sken ipfw_insn *ret = NULL; 2578230592Sken 2579230592Sken if ((host = strdup(av)) == NULL) 2580230592Sken return NULL; 2581230592Sken if ((ch = strrchr(host, '/')) != NULL) 2582230592Sken *ch = '\0'; 2583230592Sken 2584230592Sken if (proto == IPPROTO_IPV6 || strcmp(av, "me6") == 0 || 2585230592Sken inet_pton(AF_INET6, host, &a) == 1) 2586230592Sken ret = add_dstip6(cmd, av); 2587230592Sken /* XXX: should check for IPv4, not !IPv6 */ 2588230592Sken if (ret == NULL && (proto == IPPROTO_IP || strcmp(av, "me") == 0 || 2589230592Sken inet_pton(AF_INET6, host, &a) != 1)) 2590230592Sken ret = add_dstip(cmd, av); 2591230592Sken if (ret == NULL && strcmp(av, "any") != 0) 2592230592Sken ret = cmd; 2593212420Sken 2594230592Sken free(host); 2595230592Sken return ret; 2596230592Sken} 2597230592Sken 2598230592Sken/* 2599230592Sken * Parse arguments and assemble the microinstructions which make up a rule. 2600230592Sken * Rules are added into the 'rulebuf' and then copied in the correct order 2601230592Sken * into the actual rule. 2602230592Sken * 2603230592Sken * The syntax for a rule starts with the action, followed by 2604230592Sken * optional action parameters, and the various match patterns. 2605230592Sken * In the assembled microcode, the first opcode must be an O_PROBE_STATE 2606230592Sken * (generated if the rule includes a keep-state option), then the 2607212420Sken * various match patterns, log/altq actions, and the actual action. 2608230592Sken * 2609230592Sken */ 2610230592Skenvoid 2611230592Skenipfw_add(char *av[]) 2612230592Sken{ 2613230592Sken /* 2614230592Sken * rules are added into the 'rulebuf' and then copied in 2615230592Sken * the correct order into the actual rule. 2616230592Sken * Some things that need to go out of order (prob, action etc.) 2617230592Sken * go into actbuf[]. 2618230592Sken */ 2619230592Sken static uint32_t rulebuf[255], actbuf[255], cmdbuf[255]; 2620230592Sken 2621230592Sken ipfw_insn *src, *dst, *cmd, *action, *prev=NULL; 2622230592Sken ipfw_insn *first_cmd; /* first match pattern */ 2623230592Sken 2624230592Sken struct ip_fw *rule; 2625230592Sken 2626230592Sken /* 2627230592Sken * various flags used to record that we entered some fields. 2628230592Sken */ 2629230592Sken ipfw_insn *have_state = NULL; /* check-state or keep-state */ 2630230592Sken ipfw_insn *have_log = NULL, *have_altq = NULL, *have_tag = NULL; 2631230592Sken size_t len; 2632230592Sken 2633230592Sken int i; 2634230592Sken 2635230592Sken int open_par = 0; /* open parenthesis ( */ 2636230592Sken 2637230592Sken /* proto is here because it is used to fetch ports */ 2638230592Sken u_char proto = IPPROTO_IP; /* default protocol */ 2639230592Sken 2640230592Sken double match_prob = 1; /* match probability, default is always match */ 2641230592Sken 2642230592Sken bzero(actbuf, sizeof(actbuf)); /* actions go here */ 2643230592Sken bzero(cmdbuf, sizeof(cmdbuf)); 2644230592Sken bzero(rulebuf, sizeof(rulebuf)); 2645230592Sken 2646230592Sken rule = (struct ip_fw *)rulebuf; 2647237683Sken cmd = (ipfw_insn *)cmdbuf; 2648237683Sken action = (ipfw_insn *)actbuf; 2649230592Sken 2650230592Sken av++; 2651230592Sken 2652230592Sken /* [rule N] -- Rule number optional */ 2653230592Sken if (av[0] && isdigit(**av)) { 2654230592Sken rule->rulenum = atoi(*av); 2655230592Sken av++; 2656230592Sken } 2657230592Sken 2658230592Sken /* [set N] -- set number (0..RESVD_SET), optional */ 2659230592Sken if (av[0] && !av[1] && _substrcmp(*av, "set") == 0) { 2660230592Sken int set = strtoul(av[1], NULL, 10); 2661230592Sken if (set < 0 || set > RESVD_SET) 2662230592Sken errx(EX_DATAERR, "illegal set %s", av[1]); 2663230592Sken rule->set = set; 2664230592Sken av += 2; 2665230592Sken } 2666230592Sken 2667230592Sken /* [prob D] -- match probability, optional */ 2668230592Sken if (av[0] && av[1] && _substrcmp(*av, "prob") == 0) { 2669230592Sken match_prob = strtod(av[1], NULL); 2670230592Sken 2671230592Sken if (match_prob <= 0 || match_prob > 1) 2672230592Sken errx(EX_DATAERR, "illegal match prob. %s", av[1]); 2673230592Sken av += 2; 2674230592Sken } 2675230592Sken 2676230592Sken /* action -- mandatory */ 2677230592Sken NEED1("missing action"); 2678230592Sken i = match_token(rule_actions, *av); 2679230592Sken av++; 2680230592Sken action->len = 1; /* default */ 2681230592Sken switch(i) { 2682230592Sken case TOK_CHECKSTATE: 2683230592Sken have_state = action; 2684230592Sken action->opcode = O_CHECK_STATE; 2685230592Sken break; 2686230592Sken 2687218812Sken case TOK_ACCEPT: 2688212420Sken action->opcode = O_ACCEPT; 2689212420Sken break; 2690216088Sken 2691212420Sken case TOK_DENY: 2692216088Sken action->opcode = O_DENY; 2693216088Sken action->arg1 = 0; 2694216088Sken break; 2695216088Sken 2696216088Sken case TOK_REJECT: 2697216088Sken action->opcode = O_REJECT; 2698216088Sken action->arg1 = ICMP_UNREACH_HOST; 2699216088Sken break; 2700218812Sken 2701218812Sken case TOK_RESET: 2702218812Sken action->opcode = O_REJECT; 2703218812Sken action->arg1 = ICMP_REJECT_RST; 2704218812Sken break; 2705218812Sken 2706218812Sken case TOK_RESET6: 2707218812Sken action->opcode = O_UNREACH6; 2708253460Sscottl action->arg1 = ICMP6_UNREACH_RST; 2709218812Sken break; 2710268197Sscottl 2711218812Sken case TOK_UNREACH: 2712230592Sken action->opcode = O_REJECT; 2713218812Sken NEED1("missing reject code"); 2714216088Sken fill_reject_code(&action->arg1, *av); 2715216088Sken av++; 2716253460Sscottl break; 2717268197Sscottl 2718216088Sken case TOK_UNREACH6: 2719216088Sken action->opcode = O_UNREACH6; 2720216088Sken NEED1("missing unreach code"); 2721216088Sken fill_unreach6_code(&action->arg1, *av); 2722216088Sken av++; 2723216088Sken break; 2724216088Sken 2725253550Sken case TOK_COUNT: 2726253550Sken action->opcode = O_COUNT; 2727216088Sken break; 2728253460Sscottl 2729237683Sken case TOK_NAT: 2730268197Sscottl action->opcode = O_NAT; 2731216088Sken action->len = F_INSN_SIZE(ipfw_insn_nat); 2732216088Sken goto chkarg; 2733216088Sken 2734253460Sscottl case TOK_QUEUE: 2735216088Sken action->opcode = O_QUEUE; 2736216088Sken goto chkarg; 2737216088Sken case TOK_PIPE: 2738216088Sken action->opcode = O_PIPE; 2739268197Sscottl goto chkarg; 2740216088Sken case TOK_SKIPTO: 2741268197Sscottl action->opcode = O_SKIPTO; 2742216088Sken goto chkarg; 2743216088Sken case TOK_NETGRAPH: 2744216088Sken action->opcode = O_NETGRAPH; 2745216088Sken goto chkarg; 2746216088Sken case TOK_NGTEE: 2747216088Sken action->opcode = O_NGTEE; 2748216088Sken goto chkarg; 2749216088Sken case TOK_DIVERT: 2750216088Sken action->opcode = O_DIVERT; 2751216088Sken goto chkarg; 2752216088Sken case TOK_TEE: 2753216088Sken action->opcode = O_TEE; 2754216088Skenchkarg: 2755216088Sken if (!av[0]) 2756216088Sken errx(EX_USAGE, "missing argument for %s", *(av - 1)); 2757216088Sken if (isdigit(**av)) { 2758216088Sken action->arg1 = strtoul(*av, NULL, 10); 2759216088Sken if (action->arg1 <= 0 || action->arg1 >= IP_FW_TABLEARG) 2760216088Sken errx(EX_DATAERR, "illegal argument for %s", 2761216088Sken *(av - 1)); 2762216088Sken } else if (_substrcmp(*av, "tablearg") == 0) { 2763216088Sken action->arg1 = IP_FW_TABLEARG; 2764216088Sken } else if (i == TOK_DIVERT || i == TOK_TEE) { 2765216088Sken struct servent *s; 2766216088Sken setservent(1); 2767216088Sken s = getservbyname(av[0], "divert"); 2768216088Sken if (s != NULL) 2769216088Sken action->arg1 = ntohs(s->s_port); 2770216088Sken else 2771216088Sken errx(EX_DATAERR, "illegal divert/tee port"); 2772246713Skib } else 2773246713Skib errx(EX_DATAERR, "illegal argument for %s", *(av - 1)); 2774246713Skib av++; 2775253460Sscottl break; 2776253460Sscottl 2777268197Sscottl case TOK_FORWARD: { 2778216088Sken ipfw_insn_sa *p = (ipfw_insn_sa *)action; 2779216088Sken char *s, *end; 2780246713Skib 2781216088Sken NEED1("missing forward address[:port]"); 2782216088Sken 2783216088Sken action->opcode = O_FORWARD_IP; 2784216088Sken action->len = F_INSN_SIZE(ipfw_insn_sa); 2785216088Sken 2786216088Sken /* 2787253460Sscottl * In the kernel we assume AF_INET and use only 2788253460Sscottl * sin_port and sin_addr. Remember to set sin_len as 2789216088Sken * the routing code seems to use it too. 2790216088Sken */ 2791268197Sscottl p->sa.sin_family = AF_INET; 2792216088Sken p->sa.sin_len = sizeof(struct sockaddr_in); 2793216088Sken p->sa.sin_port = 0; 2794216088Sken /* 2795216088Sken * locate the address-port separator (':' or ',') 2796216088Sken */ 2797216088Sken s = strchr(*av, ':'); 2798216088Sken if (s == NULL) 2799216088Sken s = strchr(*av, ','); 2800216088Sken if (s != NULL) { 2801216088Sken *(s++) = '\0'; 2802216088Sken i = strtoport(s, &end, 0 /* base */, 0 /* proto */); 2803216088Sken if (s == end) 2804216088Sken errx(EX_DATAERR, 2805216088Sken "illegal forwarding port ``%s''", s); 2806216088Sken p->sa.sin_port = (u_short)i; 2807216088Sken } 2808241145Sken if (_substrcmp(*av, "tablearg") == 0) 2809216088Sken p->sa.sin_addr.s_addr = INADDR_ANY; 2810216088Sken else 2811216088Sken lookup_host(*av, &(p->sa.sin_addr)); 2812216088Sken av++; 2813216088Sken break; 2814216088Sken } 2815216088Sken case TOK_COMMENT: 2816241145Sken /* pretend it is a 'count' rule followed by the comment */ 2817216088Sken action->opcode = O_COUNT; 2818216088Sken av--; /* go back... */ 2819246713Skib break; 2820246713Skib 2821216088Sken case TOK_SETFIB: 2822216088Sken { 2823246713Skib int numfibs; 2824246713Skib size_t intsize = sizeof(int); 2825268197Sscottl 2826246713Skib action->opcode = O_SETFIB; 2827246713Skib NEED1("missing fib number"); 2828216088Sken action->arg1 = strtoul(*av, NULL, 10); 2829216088Sken if (sysctlbyname("net.fibs", &numfibs, &intsize, NULL, 0) == -1) 2830216088Sken errx(EX_DATAERR, "fibs not suported.\n"); 2831216088Sken if (action->arg1 >= numfibs) /* Temporary */ 2832253460Sscottl errx(EX_DATAERR, "fib too large.\n"); 2833253460Sscottl av++; 2834268197Sscottl break; 2835216088Sken } 2836216088Sken 2837216088Sken case TOK_REASS: 2838216088Sken action->opcode = O_REASS; 2839216088Sken break; 2840216088Sken 2841216088Sken default: 2842216088Sken errx(EX_DATAERR, "invalid action %s\n", av[-1]); 2843216088Sken } 2844216088Sken action = next_cmd(action); 2845216088Sken 2846237683Sken /* 2847216088Sken * [altq queuename] -- altq tag, optional 2848216088Sken * [log [logamount N]] -- log, optional 2849216088Sken * 2850253460Sscottl * If they exist, it go first in the cmdbuf, but then it is 2851253550Sken * skipped in the copy section to the end of the buffer. 2852216088Sken */ 2853216088Sken while (av[0] != NULL && (i = match_token(rule_action_params, *av)) != -1) { 2854216088Sken av++; 2855216088Sken switch (i) { 2856216088Sken case TOK_LOG: 2857216088Sken { 2858216088Sken ipfw_insn_log *c = (ipfw_insn_log *)cmd; 2859216088Sken int l; 2860216088Sken 2861216088Sken if (have_log) 2862216088Sken errx(EX_DATAERR, 2863216088Sken "log cannot be specified more than once"); 2864216088Sken have_log = (ipfw_insn *)c; 2865216088Sken cmd->len = F_INSN_SIZE(ipfw_insn_log); 2866216088Sken cmd->opcode = O_LOG; 2867216088Sken if (av[0] && _substrcmp(*av, "logamount") == 0) { 2868216088Sken av++; 2869216088Sken NEED1("logamount requires argument"); 2870216088Sken l = atoi(*av); 2871237683Sken if (l < 0) 2872216088Sken errx(EX_DATAERR, 2873216088Sken "logamount must be positive"); 2874216088Sken c->max_log = l; 2875216088Sken av++; 2876216088Sken } else { 2877216088Sken len = sizeof(c->max_log); 2878216088Sken if (sysctlbyname("net.inet.ip.fw.verbose_limit", 2879216088Sken &c->max_log, &len, NULL, 0) == -1) 2880216088Sken errx(1, "sysctlbyname(\"%s\")", 2881216088Sken "net.inet.ip.fw.verbose_limit"); 2882216088Sken } 2883216088Sken } 2884216088Sken break; 2885216088Sken 2886216088Sken#ifndef NO_ALTQ 2887216088Sken case TOK_ALTQ: 2888216088Sken { 2889216088Sken ipfw_insn_altq *a = (ipfw_insn_altq *)cmd; 2890216088Sken 2891216088Sken NEED1("missing altq queue name"); 2892216088Sken if (have_altq) 2893216088Sken errx(EX_DATAERR, 2894216088Sken "altq cannot be specified more than once"); 2895216088Sken have_altq = (ipfw_insn *)a; 2896216088Sken cmd->len = F_INSN_SIZE(ipfw_insn_altq); 2897216088Sken cmd->opcode = O_ALTQ; 2898216088Sken a->qid = altq_name_to_qid(*av); 2899216088Sken av++; 2900216088Sken } 2901216088Sken break; 2902216088Sken#endif 2903216088Sken 2904216088Sken case TOK_TAG: 2905216088Sken case TOK_UNTAG: { 2906216088Sken uint16_t tag; 2907216088Sken 2908216088Sken if (have_tag) 2909216088Sken errx(EX_USAGE, "tag and untag cannot be " 2910216088Sken "specified more than once"); 2911216088Sken GET_UINT_ARG(tag, IPFW_ARG_MIN, IPFW_ARG_MAX, i, 2912253460Sscottl rule_action_params); 2913253460Sscottl have_tag = cmd; 2914216088Sken fill_cmd(cmd, O_TAG, (i == TOK_TAG) ? 0: F_NOT, tag); 2915216088Sken av++; 2916216088Sken break; 2917216088Sken } 2918216088Sken 2919216088Sken default: 2920216088Sken abort(); 2921216088Sken } 2922268197Sscottl cmd = next_cmd(cmd); 2923216088Sken } 2924216088Sken 2925216088Sken if (have_state) /* must be a check-state, we are done */ 2926216088Sken goto done; 2927216088Sken 2928216088Sken#define OR_START(target) \ 2929216088Sken if (av[0] && (*av[0] == '(' || *av[0] == '{')) { \ 2930216088Sken if (open_par) \ 2931216088Sken errx(EX_USAGE, "nested \"(\" not allowed\n"); \ 2932216088Sken prev = NULL; \ 2933216088Sken open_par = 1; \ 2934216088Sken if ( (av[0])[1] == '\0') { \ 2935216088Sken av++; \ 2936216088Sken } else \ 2937216088Sken (*av)++; \ 2938216088Sken } \ 2939216088Sken target: \ 2940264492Sscottl 2941264492Sscottl 2942216088Sken#define CLOSE_PAR \ 2943216088Sken if (open_par) { \ 2944253460Sscottl if (av[0] && ( \ 2945253460Sscottl strcmp(*av, ")") == 0 || \ 2946216088Sken strcmp(*av, "}") == 0)) { \ 2947268197Sscottl prev = NULL; \ 2948216088Sken open_par = 0; \ 2949216088Sken av++; \ 2950216088Sken } else \ 2951216088Sken errx(EX_USAGE, "missing \")\"\n"); \ 2952216088Sken } 2953216088Sken 2954216088Sken#define NOT_BLOCK \ 2955216088Sken if (av[0] && _substrcmp(*av, "not") == 0) { \ 2956216088Sken if (cmd->len & F_NOT) \ 2957216088Sken errx(EX_USAGE, "double \"not\" not allowed\n"); \ 2958216088Sken cmd->len |= F_NOT; \ 2959216088Sken av++; \ 2960216088Sken } 2961216088Sken 2962216088Sken#define OR_BLOCK(target) \ 2963216088Sken if (av[0] && _substrcmp(*av, "or") == 0) { \ 2964216088Sken if (prev == NULL || open_par == 0) \ 2965216088Sken errx(EX_DATAERR, "invalid OR block"); \ 2966216088Sken prev->len |= F_OR; \ 2967216088Sken av++; \ 2968216088Sken goto target; \ 2969216088Sken } \ 2970216088Sken CLOSE_PAR; 2971216088Sken 2972216088Sken first_cmd = cmd; 2973216088Sken 2974216088Sken#if 0 2975216088Sken /* 2976216088Sken * MAC addresses, optional. 2977216088Sken * If we have this, we skip the part "proto from src to dst" 2978216088Sken * and jump straight to the option parsing. 2979216088Sken */ 2980216088Sken NOT_BLOCK; 2981216088Sken NEED1("missing protocol"); 2982216088Sken if (_substrcmp(*av, "MAC") == 0 || 2983216088Sken _substrcmp(*av, "mac") == 0) { 2984216088Sken av++; /* the "MAC" keyword */ 2985216088Sken add_mac(cmd, av); /* exits in case of errors */ 2986216088Sken cmd = next_cmd(cmd); 2987216088Sken av += 2; /* dst-mac and src-mac */ 2988230592Sken NOT_BLOCK; 2989216088Sken NEED1("missing mac type"); 2990230592Sken if (add_mactype(cmd, av[0])) 2991216088Sken cmd = next_cmd(cmd); 2992216088Sken av++; /* any or mac-type */ 2993253460Sscottl goto read_options; 2994253460Sscottl } 2995216088Sken#endif 2996270250Sslm 2997216088Sken /* 2998216088Sken * protocol, mandatory 2999230592Sken */ 3000230592Sken OR_START(get_proto); 3001230592Sken NOT_BLOCK; 3002216088Sken NEED1("missing protocol"); 3003216088Sken if (add_proto_compat(cmd, *av, &proto)) { 3004253460Sscottl av++; 3005253460Sscottl if (F_LEN(cmd) != 0) { 3006216088Sken prev = cmd; 3007270250Sslm cmd = next_cmd(cmd); 3008216088Sken } 3009216088Sken } else if (first_cmd != cmd) { 3010216088Sken errx(EX_DATAERR, "invalid protocol ``%s''", *av); 3011216088Sken } else 3012216088Sken goto read_options; 3013253460Sscottl OR_BLOCK(get_proto); 3014253460Sscottl 3015216088Sken /* 3016216088Sken * "from", mandatory 3017270250Sslm */ 3018216088Sken if ((av[0] == NULL) || _substrcmp(*av, "from") != 0) 3019216088Sken errx(EX_USAGE, "missing ``from''"); 3020216088Sken av++; 3021216088Sken 3022216088Sken /* 3023230592Sken * source IP, mandatory 3024230592Sken */ 3025230592Sken OR_START(source_ip); 3026253460Sscottl NOT_BLOCK; /* optional "not" */ 3027253460Sscottl NEED1("missing source address"); 3028230592Sken if (add_src(cmd, *av, proto)) { 3029230592Sken av++; 3030270250Sslm if (F_LEN(cmd) != 0) { /* ! any */ 3031230592Sken prev = cmd; 3032230592Sken cmd = next_cmd(cmd); 3033230592Sken } 3034230592Sken } else 3035253460Sscottl errx(EX_USAGE, "bad source address %s", *av); 3036253460Sscottl OR_BLOCK(source_ip); 3037230592Sken 3038230592Sken /* 3039270250Sslm * source ports, optional 3040230592Sken */ 3041230592Sken NOT_BLOCK; /* optional "not" */ 3042230592Sken if ( av[0] != NULL ) { 3043230592Sken if (_substrcmp(*av, "any") == 0 || 3044230592Sken add_ports(cmd, *av, proto, O_IP_SRCPORT)) { 3045230592Sken av++; 3046216088Sken if (F_LEN(cmd) != 0) 3047216088Sken cmd = next_cmd(cmd); 3048216088Sken } 3049253460Sscottl } 3050253460Sscottl 3051216088Sken /* 3052270250Sslm * "to", mandatory 3053216088Sken */ 3054216088Sken if ( (av[0] == NULL) || _substrcmp(*av, "to") != 0 ) 3055216088Sken errx(EX_USAGE, "missing ``to''"); 3056216088Sken av++; 3057216088Sken 3058216088Sken /* 3059216088Sken * destination, mandatory 3060216088Sken */ 3061216088Sken OR_START(dest_ip); 3062216088Sken NOT_BLOCK; /* optional "not" */ 3063230592Sken NEED1("missing dst address"); 3064216088Sken if (add_dst(cmd, *av, proto)) { 3065216088Sken av++; 3066212420Sken if (F_LEN(cmd) != 0) { /* ! any */ 3067212420Sken prev = cmd; 3068230592Sken cmd = next_cmd(cmd); 3069212420Sken } 3070230592Sken } else 3071212420Sken errx( EX_USAGE, "bad destination address %s", *av); 3072212420Sken OR_BLOCK(dest_ip); 3073253460Sscottl 3074230592Sken /* 3075230592Sken * dest. ports, optional 3076264492Sscottl */ 3077264492Sscottl NOT_BLOCK; /* optional "not" */ 3078264492Sscottl if (av[0]) { 3079212420Sken if (_substrcmp(*av, "any") == 0 || 3080230592Sken add_ports(cmd, *av, proto, O_IP_DSTPORT)) { 3081230592Sken av++; 3082253460Sscottl if (F_LEN(cmd) != 0) 3083253809Sscottl cmd = next_cmd(cmd); 3084268197Sscottl } 3085212420Sken } 3086212420Sken 3087212420Skenread_options: 3088212420Sken if (av[0] && first_cmd == cmd) { 3089230592Sken /* 3090230592Sken * nothing specified so far, store in the rule to ease 3091237683Sken * printout later. 3092212420Sken */ 3093212420Sken rule->_pad = 1; 3094212420Sken } 3095212420Sken prev = NULL; 3096212420Sken while ( av[0] != NULL ) { 3097212420Sken char *s; 3098230592Sken ipfw_insn_u32 *cmd32; /* alias for cmd */ 3099230592Sken 3100230592Sken s = *av; 3101230592Sken cmd32 = (ipfw_insn_u32 *)cmd; 3102238969Smav 3103230592Sken if (*s == '!') { /* alternate syntax for NOT */ 3104212420Sken if (cmd->len & F_NOT) 3105212420Sken errx(EX_USAGE, "double \"not\" not allowed\n"); 3106212420Sken cmd->len = F_NOT; 3107230592Sken s++; 3108212420Sken } 3109212420Sken i = match_token(rule_options, s); 3110212420Sken av++; 3111212420Sken switch(i) { 3112253460Sscottl case TOK_NOT: 3113230592Sken if (cmd->len & F_NOT) 3114212420Sken errx(EX_USAGE, "double \"not\" not allowed\n"); 3115230592Sken cmd->len = F_NOT; 3116230592Sken break; 3117212420Sken 3118230592Sken case TOK_OR: 3119230592Sken if (open_par == 0 || prev == NULL) 3120230592Sken errx(EX_USAGE, "invalid \"or\" block\n"); 3121230592Sken prev->len |= F_OR; 3122230592Sken break; 3123230592Sken 3124218812Sken case TOK_STARTBRACE: 3125218812Sken if (open_par) 3126230592Sken errx(EX_USAGE, "+nested \"(\" not allowed\n"); 3127218812Sken open_par = 1; 3128253460Sscottl break; 3129253460Sscottl 3130230592Sken case TOK_ENDBRACE: 3131218812Sken if (!open_par) 3132268197Sscottl errx(EX_USAGE, "+missing \")\"\n"); 3133218812Sken open_par = 0; 3134218812Sken prev = NULL; 3135218812Sken break; 3136253460Sscottl 3137253460Sscottl case TOK_IN: 3138237683Sken fill_cmd(cmd, O_IN, 0, 0); 3139212420Sken break; 3140237683Sken 3141268197Sscottl case TOK_OUT: 3142230592Sken cmd->len ^= F_NOT; /* toggle F_NOT */ 3143230592Sken fill_cmd(cmd, O_IN, 0, 0); 3144230592Sken break; 3145212420Sken 3146268197Sscottl case TOK_DIVERTED: 3147212420Sken fill_cmd(cmd, O_DIVERTED, 0, 3); 3148218812Sken break; 3149212772Sken 3150230592Sken case TOK_DIVERTEDLOOPBACK: 3151212420Sken fill_cmd(cmd, O_DIVERTED, 0, 1); 3152212420Sken break; 3153212420Sken 3154212420Sken case TOK_DIVERTEDOUTPUT: 3155212420Sken fill_cmd(cmd, O_DIVERTED, 0, 2); 3156212420Sken break; 3157212420Sken 3158212420Sken case TOK_FRAG: 3159212420Sken fill_cmd(cmd, O_FRAG, 0, 0); 3160230592Sken break; 3161230592Sken 3162230592Sken case TOK_LAYER2: 3163230592Sken fill_cmd(cmd, O_LAYER2, 0, 0); 3164230592Sken break; 3165230592Sken 3166230592Sken case TOK_XMIT: 3167230592Sken case TOK_RECV: 3168230592Sken case TOK_VIA: 3169212420Sken NEED1("recv, xmit, via require interface name" 3170212420Sken " or address"); 3171212420Sken fill_iface((ipfw_insn_if *)cmd, av[0]); 3172212420Sken av++; 3173230592Sken if (F_LEN(cmd) == 0) /* not a valid address */ 3174230592Sken break; 3175230592Sken if (i == TOK_XMIT) 3176230592Sken cmd->opcode = O_XMIT; 3177230592Sken else if (i == TOK_RECV) 3178230592Sken cmd->opcode = O_RECV; 3179230592Sken else if (i == TOK_VIA) 3180230592Sken cmd->opcode = O_VIA; 3181253549Sken break; 3182253549Sken 3183230592Sken case TOK_ICMPTYPES: 3184230592Sken NEED1("icmptypes requires list of types"); 3185230592Sken fill_icmptypes((ipfw_insn_u32 *)cmd, *av); 3186230592Sken av++; 3187230592Sken break; 3188230592Sken 3189230592Sken case TOK_ICMP6TYPES: 3190230592Sken NEED1("icmptypes requires list of types"); 3191230592Sken fill_icmp6types((ipfw_insn_icmp6 *)cmd, *av); 3192230592Sken av++; 3193230592Sken break; 3194230592Sken 3195230592Sken case TOK_IPTTL: 3196230592Sken NEED1("ipttl requires TTL"); 3197230592Sken if (strpbrk(*av, "-,")) { 3198230592Sken if (!add_ports(cmd, *av, 0, O_IPTTL)) 3199230592Sken errx(EX_DATAERR, "invalid ipttl %s", *av); 3200230592Sken } else 3201230592Sken fill_cmd(cmd, O_IPTTL, 0, strtoul(*av, NULL, 0)); 3202230592Sken av++; 3203230592Sken break; 3204230592Sken 3205230592Sken case TOK_IPID: 3206230592Sken NEED1("ipid requires id"); 3207264492Sscottl if (strpbrk(*av, "-,")) { 3208264492Sscottl if (!add_ports(cmd, *av, 0, O_IPID)) 3209264492Sscottl errx(EX_DATAERR, "invalid ipid %s", *av); 3210230592Sken } else 3211230592Sken fill_cmd(cmd, O_IPID, 0, strtoul(*av, NULL, 0)); 3212230592Sken av++; 3213230592Sken break; 3214230592Sken 3215230592Sken case TOK_IPLEN: 3216230592Sken NEED1("iplen requires length"); 3217230592Sken if (strpbrk(*av, "-,")) { 3218230592Sken if (!add_ports(cmd, *av, 0, O_IPLEN)) 3219230592Sken errx(EX_DATAERR, "invalid ip len %s", *av); 3220230592Sken } else 3221230592Sken fill_cmd(cmd, O_IPLEN, 0, strtoul(*av, NULL, 0)); 3222230592Sken av++; 3223230592Sken break; 3224230592Sken 3225230592Sken case TOK_IPVER: 3226230592Sken NEED1("ipver requires version"); 3227253460Sscottl fill_cmd(cmd, O_IPVER, 0, strtoul(*av, NULL, 0)); 3228230592Sken av++; 3229230592Sken break; 3230230592Sken 3231230592Sken case TOK_IPPRECEDENCE: 3232230592Sken NEED1("ipprecedence requires value"); 3233230592Sken fill_cmd(cmd, O_IPPRECEDENCE, 0, 3234230592Sken (strtoul(*av, NULL, 0) & 7) << 5); 3235230592Sken av++; 3236230592Sken break; 3237230592Sken 3238230592Sken case TOK_IPOPTS: 3239230592Sken NEED1("missing argument for ipoptions"); 3240230592Sken fill_flags(cmd, O_IPOPT, f_ipopts, *av); 3241230592Sken av++; 3242230592Sken break; 3243230592Sken 3244230592Sken case TOK_IPTOS: 3245230592Sken NEED1("missing argument for iptos"); 3246230592Sken fill_flags(cmd, O_IPTOS, f_iptos, *av); 3247230592Sken av++; 3248268197Sscottl break; 3249230592Sken 3250230592Sken case TOK_UID: 3251230592Sken NEED1("uid requires argument"); 3252230592Sken { 3253230592Sken char *end; 3254230592Sken uid_t uid; 3255230592Sken struct passwd *pwd; 3256230592Sken 3257230592Sken cmd->opcode = O_UID; 3258253549Sken uid = strtoul(*av, &end, 0); 3259253549Sken pwd = (*end == '\0') ? getpwuid(uid) : getpwnam(*av); 3260253549Sken if (pwd == NULL) 3261253549Sken errx(EX_DATAERR, "uid \"%s\" nonexistent", *av); 3262253549Sken cmd32->d[0] = pwd->pw_uid; 3263253549Sken cmd->len |= F_INSN_SIZE(ipfw_insn_u32); 3264253549Sken av++; 3265253549Sken } 3266253549Sken break; 3267230592Sken 3268230592Sken case TOK_GID: 3269230592Sken NEED1("gid requires argument"); 3270230592Sken { 3271230592Sken char *end; 3272253549Sken gid_t gid; 3273253549Sken struct group *grp; 3274230592Sken 3275253549Sken cmd->opcode = O_GID; 3276253549Sken gid = strtoul(*av, &end, 0); 3277230592Sken grp = (*end == '\0') ? getgrgid(gid) : getgrnam(*av); 3278253549Sken if (grp == NULL) 3279230592Sken errx(EX_DATAERR, "gid \"%s\" nonexistent", *av); 3280230592Sken cmd32->d[0] = grp->gr_gid; 3281230592Sken cmd->len |= F_INSN_SIZE(ipfw_insn_u32); 3282253549Sken av++; 3283230592Sken } 3284230592Sken break; 3285253549Sken 3286253549Sken case TOK_JAIL: 3287230592Sken NEED1("jail requires argument"); 3288230592Sken { 3289230592Sken char *end; 3290237683Sken int jid; 3291230592Sken 3292253549Sken cmd->opcode = O_JAIL; 3293253549Sken jid = (int)strtol(*av, &end, 0); 3294253549Sken if (jid < 0 || *end != '\0') 3295253549Sken errx(EX_DATAERR, "jail requires prison ID"); 3296253549Sken cmd32->d[0] = (uint32_t)jid; 3297264492Sscottl cmd->len |= F_INSN_SIZE(ipfw_insn_u32); 3298264492Sscottl av++; 3299264492Sscottl } 3300253549Sken break; 3301253549Sken 3302253549Sken case TOK_ESTAB: 3303253549Sken fill_cmd(cmd, O_ESTAB, 0, 0); 3304230592Sken break; 3305253549Sken 3306253549Sken case TOK_SETUP: 3307253549Sken fill_cmd(cmd, O_TCPFLAGS, 0, 3308253549Sken (TH_SYN) | ( (TH_ACK) & 0xff) <<8 ); 3309253549Sken break; 3310253549Sken 3311253549Sken case TOK_TCPDATALEN: 3312230592Sken NEED1("tcpdatalen requires length"); 3313253549Sken if (strpbrk(*av, "-,")) { 3314253549Sken if (!add_ports(cmd, *av, 0, O_TCPDATALEN)) 3315230592Sken errx(EX_DATAERR, "invalid tcpdata len %s", *av); 3316253549Sken } else 3317253549Sken fill_cmd(cmd, O_TCPDATALEN, 0, 3318253549Sken strtoul(*av, NULL, 0)); 3319253549Sken av++; 3320253549Sken break; 3321253549Sken 3322253549Sken case TOK_TCPOPTS: 3323253549Sken NEED1("missing argument for tcpoptions"); 3324253549Sken fill_flags(cmd, O_TCPOPTS, f_tcpopts, *av); 3325253549Sken av++; 3326253549Sken break; 3327230592Sken 3328253549Sken case TOK_TCPSEQ: 3329253549Sken case TOK_TCPACK: 3330253549Sken NEED1("tcpseq/tcpack requires argument"); 3331253549Sken cmd->len = F_INSN_SIZE(ipfw_insn_u32); 3332253549Sken cmd->opcode = (i == TOK_TCPSEQ) ? O_TCPSEQ : O_TCPACK; 3333253549Sken cmd32->d[0] = htonl(strtoul(*av, NULL, 0)); 3334253549Sken av++; 3335230592Sken break; 3336253549Sken 3337253549Sken case TOK_TCPWIN: 3338253549Sken NEED1("tcpwin requires length"); 3339253549Sken fill_cmd(cmd, O_TCPWIN, 0, 3340253549Sken htons(strtoul(*av, NULL, 0))); 3341253549Sken av++; 3342253549Sken break; 3343253549Sken 3344253549Sken case TOK_TCPFLAGS: 3345253549Sken NEED1("missing argument for tcpflags"); 3346253549Sken cmd->opcode = O_TCPFLAGS; 3347253549Sken fill_flags(cmd, O_TCPFLAGS, f_tcpflags, *av); 3348253549Sken av++; 3349253549Sken break; 3350253549Sken 3351253549Sken case TOK_KEEPSTATE: 3352253549Sken if (open_par) 3353253549Sken errx(EX_USAGE, "keep-state cannot be part " 3354253549Sken "of an or block"); 3355253549Sken if (have_state) 3356253549Sken errx(EX_USAGE, "only one of keep-state " 3357253549Sken "and limit is allowed"); 3358253549Sken have_state = cmd; 3359253549Sken fill_cmd(cmd, O_KEEP_STATE, 0, 0); 3360253549Sken break; 3361230592Sken 3362253549Sken case TOK_LIMIT: { 3363270250Sslm ipfw_insn_limit *c = (ipfw_insn_limit *)cmd; 3364270250Sslm int val; 3365270250Sslm 3366270250Sslm if (open_par) 3367270250Sslm errx(EX_USAGE, 3368270250Sslm "limit cannot be part of an or block"); 3369270250Sslm if (have_state) 3370270250Sslm errx(EX_USAGE, "only one of keep-state and " 3371270250Sslm "limit is allowed"); 3372270250Sslm have_state = cmd; 3373270250Sslm 3374270250Sslm cmd->len = F_INSN_SIZE(ipfw_insn_limit); 3375270250Sslm cmd->opcode = O_LIMIT; 3376270250Sslm c->limit_mask = c->conn_limit = 0; 3377253549Sken 3378253549Sken while ( av[0] != NULL ) { 3379237683Sken if ((val = match_token(limit_masks, *av)) <= 0) 3380253549Sken break; 3381253549Sken c->limit_mask |= val; 3382253549Sken av++; 3383253549Sken } 3384253549Sken 3385253549Sken if (c->limit_mask == 0) 3386253549Sken errx(EX_USAGE, "limit: missing limit mask"); 3387253549Sken 3388253549Sken GET_UINT_ARG(c->conn_limit, IPFW_ARG_MIN, IPFW_ARG_MAX, 3389253549Sken TOK_LIMIT, rule_options); 3390253549Sken 3391253549Sken av++; 3392253549Sken break; 3393253549Sken } 3394253549Sken 3395253549Sken case TOK_PROTO: 3396253549Sken NEED1("missing protocol"); 3397253549Sken if (add_proto(cmd, *av, &proto)) { 3398253549Sken av++; 3399253549Sken } else 3400253549Sken errx(EX_DATAERR, "invalid protocol ``%s''", 3401253549Sken *av); 3402253549Sken break; 3403253549Sken 3404253549Sken case TOK_SRCIP: 3405253549Sken NEED1("missing source IP"); 3406237683Sken if (add_srcip(cmd, *av)) { 3407253549Sken av++; 3408253549Sken } 3409253549Sken break; 3410253549Sken 3411253549Sken case TOK_DSTIP: 3412230592Sken NEED1("missing destination IP"); 3413253549Sken if (add_dstip(cmd, *av)) { 3414253549Sken av++; 3415230592Sken } 3416230592Sken break; 3417230592Sken 3418230592Sken case TOK_SRCIP6: 3419230592Sken NEED1("missing source IP6"); 3420230592Sken if (add_srcip6(cmd, *av)) { 3421230592Sken av++; 3422230592Sken } 3423230592Sken break; 3424230592Sken 3425230592Sken case TOK_DSTIP6: 3426230592Sken NEED1("missing destination IP6"); 3427231240Sken if (add_dstip6(cmd, *av)) { 3428231240Sken av++; 3429231240Sken } 3430231240Sken break; 3431231240Sken 3432231240Sken case TOK_SRCPORT: 3433231240Sken NEED1("missing source port"); 3434231240Sken if (_substrcmp(*av, "any") == 0 || 3435231240Sken add_ports(cmd, *av, proto, O_IP_SRCPORT)) { 3436231240Sken av++; 3437231240Sken } else 3438231240Sken errx(EX_DATAERR, "invalid source port %s", *av); 3439231240Sken break; 3440231240Sken 3441230592Sken case TOK_DSTPORT: 3442230592Sken NEED1("missing destination port"); 3443230592Sken if (_substrcmp(*av, "any") == 0 || 3444230592Sken add_ports(cmd, *av, proto, O_IP_DSTPORT)) { 3445230592Sken av++; 3446230592Sken } else 3447230592Sken errx(EX_DATAERR, "invalid destination port %s", 3448230592Sken *av); 3449264492Sscottl break; 3450264492Sscottl 3451264492Sscottl case TOK_MAC: 3452230592Sken if (add_mac(cmd, av)) 3453230592Sken av += 2; 3454230592Sken break; 3455230592Sken 3456230592Sken case TOK_MACTYPE: 3457230592Sken NEED1("missing mac type"); 3458230592Sken if (!add_mactype(cmd, *av)) 3459230592Sken errx(EX_DATAERR, "invalid mac type %s", *av); 3460230592Sken av++; 3461230592Sken break; 3462230592Sken 3463230592Sken case TOK_VERREVPATH: 3464268197Sscottl fill_cmd(cmd, O_VERREVPATH, 0, 0); 3465230592Sken break; 3466230592Sken 3467230592Sken case TOK_VERSRCREACH: 3468230592Sken fill_cmd(cmd, O_VERSRCREACH, 0, 0); 3469230592Sken break; 3470230592Sken 3471230592Sken case TOK_ANTISPOOF: 3472253550Sken fill_cmd(cmd, O_ANTISPOOF, 0, 0); 3473253550Sken break; 3474253550Sken 3475253550Sken case TOK_IPSEC: 3476230592Sken fill_cmd(cmd, O_IPSEC, 0, 0); 3477230592Sken break; 3478230592Sken 3479230592Sken case TOK_IPV6: 3480230592Sken fill_cmd(cmd, O_IP6, 0, 0); 3481230592Sken break; 3482230592Sken 3483230592Sken case TOK_IPV4: 3484230592Sken fill_cmd(cmd, O_IP4, 0, 0); 3485230592Sken break; 3486230592Sken 3487253549Sken case TOK_EXT6HDR: 3488253549Sken fill_ext6hdr( cmd, *av ); 3489230592Sken av++; 3490230592Sken break; 3491230592Sken 3492230592Sken case TOK_FLOWID: 3493230592Sken if (proto != IPPROTO_IPV6 ) 3494230592Sken errx( EX_USAGE, "flow-id filter is active " 3495230592Sken "only for ipv6 protocol\n"); 3496230592Sken fill_flow6( (ipfw_insn_u32 *) cmd, *av ); 3497230592Sken av++; 3498230592Sken break; 3499230592Sken 3500230592Sken case TOK_COMMENT: 3501230592Sken fill_comment(cmd, av); 3502230592Sken av[0]=NULL; 3503230592Sken break; 3504230592Sken 3505230592Sken case TOK_TAGGED: 3506230592Sken if (av[0] && strpbrk(*av, "-,")) { 3507230592Sken if (!add_ports(cmd, *av, 0, O_TAGGED)) 3508230592Sken errx(EX_DATAERR, "tagged: invalid tag" 3509230592Sken " list: %s", *av); 3510253460Sscottl } 3511230592Sken else { 3512230592Sken uint16_t tag; 3513230592Sken 3514230592Sken GET_UINT_ARG(tag, IPFW_ARG_MIN, IPFW_ARG_MAX, 3515230592Sken TOK_TAGGED, rule_options); 3516230592Sken fill_cmd(cmd, O_TAGGED, 0, tag); 3517230592Sken } 3518230592Sken av++; 3519230592Sken break; 3520230592Sken 3521230592Sken case TOK_FIB: 3522230592Sken NEED1("fib requires fib number"); 3523230592Sken fill_cmd(cmd, O_FIB, 0, strtoul(*av, NULL, 0)); 3524253460Sscottl av++; 3525230592Sken break; 3526230592Sken 3527230592Sken case TOK_LOOKUP: { 3528230592Sken ipfw_insn_u32 *c = (ipfw_insn_u32 *)cmd; 3529230592Sken char *p; 3530230592Sken int j; 3531230592Sken 3532230592Sken if (!av[0] || !av[1]) 3533230592Sken errx(EX_USAGE, "format: lookup argument tablenum"); 3534230592Sken cmd->opcode = O_IP_DST_LOOKUP; 3535230592Sken cmd->len |= F_INSN_SIZE(ipfw_insn) + 2; 3536253460Sscottl i = match_token(rule_options, *av); 3537230592Sken for (j = 0; lookup_key[j] >= 0 ; j++) { 3538230592Sken if (i == lookup_key[j]) 3539230592Sken break; 3540230592Sken } 3541230592Sken if (lookup_key[j] <= 0) 3542230592Sken errx(EX_USAGE, "format: cannot lookup on %s", *av); 3543230592Sken c->d[1] = j; // i converted to option 3544230592Sken av++; 3545253460Sscottl cmd->arg1 = strtoul(*av, &p, 0); 3546230592Sken if (p && *p) 3547230592Sken errx(EX_USAGE, "format: lookup argument tablenum"); 3548230592Sken av++; 3549230592Sken } 3550230592Sken break; 3551230592Sken 3552237683Sken default: 3553230592Sken errx(EX_USAGE, "unrecognised option [%d] %s\n", i, s); 3554230592Sken } 3555230592Sken if (F_LEN(cmd) > 0) { /* prepare to advance */ 3556230592Sken prev = cmd; 3557230592Sken cmd = next_cmd(cmd); 3558253460Sscottl } 3559230592Sken } 3560230592Sken 3561230592Skendone: 3562230592Sken /* 3563230592Sken * Now copy stuff into the rule. 3564230592Sken * If we have a keep-state option, the first instruction 3565230592Sken * must be a PROBE_STATE (which is generated here). 3566230592Sken * If we have a LOG option, it was stored as the first command, 3567230592Sken * and now must be moved to the top of the action part. 3568230592Sken */ 3569230592Sken dst = (ipfw_insn *)rule->cmd; 3570230592Sken 3571230592Sken /* 3572230592Sken * First thing to write into the command stream is the match probability. 3573230592Sken */ 3574230592Sken if (match_prob != 1) { /* 1 means always match */ 3575230592Sken dst->opcode = O_PROB; 3576230592Sken dst->len = 2; 3577230592Sken *((int32_t *)(dst+1)) = (int32_t)(match_prob * 0x7fffffff); 3578230592Sken dst += dst->len; 3579230592Sken } 3580230592Sken 3581237683Sken /* 3582230592Sken * generate O_PROBE_STATE if necessary 3583230592Sken */ 3584230592Sken if (have_state && have_state->opcode != O_CHECK_STATE) { 3585254116Sscottl fill_cmd(dst, O_PROBE_STATE, 0, 0); 3586254116Sscottl dst = next_cmd(dst); 3587254116Sscottl } 3588254116Sscottl 3589254116Sscottl /* copy all commands but O_LOG, O_KEEP_STATE, O_LIMIT, O_ALTQ, O_TAG */ 3590254116Sscottl for (src = (ipfw_insn *)cmdbuf; src != cmd; src += i) { 3591254116Sscottl i = F_LEN(src); 3592254116Sscottl 3593254116Sscottl switch (src->opcode) { 3594254116Sscottl case O_LOG: 3595254116Sscottl case O_KEEP_STATE: 3596254116Sscottl case O_LIMIT: 3597254116Sscottl case O_ALTQ: 3598254116Sscottl case O_TAG: 3599254116Sscottl break; 3600254116Sscottl default: 3601254116Sscottl bcopy(src, dst, i * sizeof(uint32_t)); 3602268197Sscottl dst += i; 3603268197Sscottl } 3604268197Sscottl } 3605268197Sscottl 3606268197Sscottl /* 3607268197Sscottl * put back the have_state command as last opcode 3608268197Sscottl */ 3609268197Sscottl if (have_state && have_state->opcode != O_CHECK_STATE) { 3610268197Sscottl i = F_LEN(have_state); 3611268197Sscottl bcopy(have_state, dst, i * sizeof(uint32_t)); 3612268197Sscottl dst += i; 3613268197Sscottl } 3614268197Sscottl /* 3615268197Sscottl * start action section 3616268197Sscottl */ 3617268197Sscottl rule->act_ofs = dst - rule->cmd; 3618268197Sscottl 3619268197Sscottl /* put back O_LOG, O_ALTQ, O_TAG if necessary */ 3620268197Sscottl if (have_log) { 3621268197Sscottl i = F_LEN(have_log); 3622268197Sscottl bcopy(have_log, dst, i * sizeof(uint32_t)); 3623268197Sscottl dst += i; 3624268197Sscottl } 3625268197Sscottl if (have_altq) { 3626268197Sscottl i = F_LEN(have_altq); 3627268197Sscottl bcopy(have_altq, dst, i * sizeof(uint32_t)); 3628268197Sscottl dst += i; 3629268197Sscottl } 3630268197Sscottl if (have_tag) { 3631268197Sscottl i = F_LEN(have_tag); 3632 bcopy(have_tag, dst, i * sizeof(uint32_t)); 3633 dst += i; 3634 } 3635 /* 3636 * copy all other actions 3637 */ 3638 for (src = (ipfw_insn *)actbuf; src != action; src += i) { 3639 i = F_LEN(src); 3640 bcopy(src, dst, i * sizeof(uint32_t)); 3641 dst += i; 3642 } 3643 3644 rule->cmd_len = (uint32_t *)dst - (uint32_t *)(rule->cmd); 3645 i = (char *)dst - (char *)rule; 3646 if (do_cmd(IP_FW_ADD, rule, (uintptr_t)&i) == -1) 3647 err(EX_UNAVAILABLE, "getsockopt(%s)", "IP_FW_ADD"); 3648 if (!co.do_quiet) 3649 show_ipfw(rule, 0, 0); 3650} 3651 3652/* 3653 * clear the counters or the log counters. 3654 */ 3655void 3656ipfw_zero(int ac, char *av[], int optname /* 0 = IP_FW_ZERO, 1 = IP_FW_RESETLOG */) 3657{ 3658 uint32_t arg, saved_arg; 3659 int failed = EX_OK; 3660 char const *errstr; 3661 char const *name = optname ? "RESETLOG" : "ZERO"; 3662 3663 optname = optname ? IP_FW_RESETLOG : IP_FW_ZERO; 3664 3665 av++; ac--; 3666 3667 if (!ac) { 3668 /* clear all entries */ 3669 if (do_cmd(optname, NULL, 0) < 0) 3670 err(EX_UNAVAILABLE, "setsockopt(IP_FW_%s)", name); 3671 if (!co.do_quiet) 3672 printf("%s.\n", optname == IP_FW_ZERO ? 3673 "Accounting cleared":"Logging counts reset"); 3674 3675 return; 3676 } 3677 3678 while (ac) { 3679 /* Rule number */ 3680 if (isdigit(**av)) { 3681 arg = strtonum(*av, 0, 0xffff, &errstr); 3682 if (errstr) 3683 errx(EX_DATAERR, 3684 "invalid rule number %s\n", *av); 3685 saved_arg = arg; 3686 if (co.use_set) 3687 arg |= (1 << 24) | ((co.use_set - 1) << 16); 3688 av++; 3689 ac--; 3690 if (do_cmd(optname, &arg, sizeof(arg))) { 3691 warn("rule %u: setsockopt(IP_FW_%s)", 3692 saved_arg, name); 3693 failed = EX_UNAVAILABLE; 3694 } else if (!co.do_quiet) 3695 printf("Entry %d %s.\n", saved_arg, 3696 optname == IP_FW_ZERO ? 3697 "cleared" : "logging count reset"); 3698 } else { 3699 errx(EX_USAGE, "invalid rule number ``%s''", *av); 3700 } 3701 } 3702 if (failed != EX_OK) 3703 exit(failed); 3704} 3705 3706void 3707ipfw_flush(int force) 3708{ 3709 int cmd = co.do_pipe ? IP_DUMMYNET_FLUSH : IP_FW_FLUSH; 3710 3711 if (!force && !co.do_quiet) { /* need to ask user */ 3712 int c; 3713 3714 printf("Are you sure? [yn] "); 3715 fflush(stdout); 3716 do { 3717 c = toupper(getc(stdin)); 3718 while (c != '\n' && getc(stdin) != '\n') 3719 if (feof(stdin)) 3720 return; /* and do not flush */ 3721 } while (c != 'Y' && c != 'N'); 3722 printf("\n"); 3723 if (c == 'N') /* user said no */ 3724 return; 3725 } 3726 if (co.do_pipe) { 3727 dummynet_flush(); 3728 return; 3729 } 3730 /* `ipfw set N flush` - is the same that `ipfw delete set N` */ 3731 if (co.use_set) { 3732 uint32_t arg = ((co.use_set - 1) & 0xffff) | (1 << 24); 3733 if (do_cmd(IP_FW_DEL, &arg, sizeof(arg)) < 0) 3734 err(EX_UNAVAILABLE, "setsockopt(IP_FW_DEL)"); 3735 } else if (do_cmd(cmd, NULL, 0) < 0) 3736 err(EX_UNAVAILABLE, "setsockopt(IP_%s_FLUSH)", 3737 co.do_pipe ? "DUMMYNET" : "FW"); 3738 if (!co.do_quiet) 3739 printf("Flushed all %s.\n", co.do_pipe ? "pipes" : "rules"); 3740} 3741 3742 3743static void table_list(ipfw_table_entry ent, int need_header); 3744 3745/* 3746 * This one handles all table-related commands 3747 * ipfw table N add addr[/masklen] [value] 3748 * ipfw table N delete addr[/masklen] 3749 * ipfw table {N | all} flush 3750 * ipfw table {N | all} list 3751 */ 3752void 3753ipfw_table_handler(int ac, char *av[]) 3754{ 3755 ipfw_table_entry ent; 3756 int do_add; 3757 int is_all; 3758 size_t len; 3759 char *p; 3760 uint32_t a; 3761 uint32_t tables_max; 3762 3763 len = sizeof(tables_max); 3764 if (sysctlbyname("net.inet.ip.fw.tables_max", &tables_max, &len, 3765 NULL, 0) == -1) { 3766#ifdef IPFW_TABLES_MAX 3767 warn("Warn: Failed to get the max tables number via sysctl. " 3768 "Using the compiled in defaults. \nThe reason was"); 3769 tables_max = IPFW_TABLES_MAX; 3770#else 3771 errx(1, "Failed sysctlbyname(\"net.inet.ip.fw.tables_max\")"); 3772#endif 3773 } 3774 3775 ac--; av++; 3776 if (ac && isdigit(**av)) { 3777 ent.tbl = atoi(*av); 3778 is_all = 0; 3779 ac--; av++; 3780 } else if (ac && _substrcmp(*av, "all") == 0) { 3781 ent.tbl = 0; 3782 is_all = 1; 3783 ac--; av++; 3784 } else 3785 errx(EX_USAGE, "table number or 'all' keyword required"); 3786 if (ent.tbl >= tables_max) 3787 errx(EX_USAGE, "The table number exceeds the maximum allowed " 3788 "value (%d)", tables_max - 1); 3789 NEED1("table needs command"); 3790 if (is_all && _substrcmp(*av, "list") != 0 3791 && _substrcmp(*av, "flush") != 0) 3792 errx(EX_USAGE, "table number required"); 3793 3794 if (_substrcmp(*av, "add") == 0 || 3795 _substrcmp(*av, "delete") == 0) { 3796 do_add = **av == 'a'; 3797 ac--; av++; 3798 if (!ac) 3799 errx(EX_USAGE, "IP address required"); 3800 p = strchr(*av, '/'); 3801 if (p) { 3802 *p++ = '\0'; 3803 ent.masklen = atoi(p); 3804 if (ent.masklen > 32) 3805 errx(EX_DATAERR, "bad width ``%s''", p); 3806 } else 3807 ent.masklen = 32; 3808 if (lookup_host(*av, (struct in_addr *)&ent.addr) != 0) 3809 errx(EX_NOHOST, "hostname ``%s'' unknown", *av); 3810 ac--; av++; 3811 if (do_add && ac) { 3812 unsigned int tval; 3813 /* isdigit is a bit of a hack here.. */ 3814 if (strchr(*av, (int)'.') == NULL && isdigit(**av)) { 3815 ent.value = strtoul(*av, NULL, 0); 3816 } else { 3817 if (lookup_host(*av, (struct in_addr *)&tval) == 0) { 3818 /* The value must be stored in host order * 3819 * so that the values < 65k can be distinguished */ 3820 ent.value = ntohl(tval); 3821 } else { 3822 errx(EX_NOHOST, "hostname ``%s'' unknown", *av); 3823 } 3824 } 3825 } else 3826 ent.value = 0; 3827 if (do_cmd(do_add ? IP_FW_TABLE_ADD : IP_FW_TABLE_DEL, 3828 &ent, sizeof(ent)) < 0) { 3829 /* If running silent, don't bomb out on these errors. */ 3830 if (!(co.do_quiet && (errno == (do_add ? EEXIST : ESRCH)))) 3831 err(EX_OSERR, "setsockopt(IP_FW_TABLE_%s)", 3832 do_add ? "ADD" : "DEL"); 3833 /* In silent mode, react to a failed add by deleting */ 3834 if (do_add) { 3835 do_cmd(IP_FW_TABLE_DEL, &ent, sizeof(ent)); 3836 if (do_cmd(IP_FW_TABLE_ADD, 3837 &ent, sizeof(ent)) < 0) 3838 err(EX_OSERR, 3839 "setsockopt(IP_FW_TABLE_ADD)"); 3840 } 3841 } 3842 } else if (_substrcmp(*av, "flush") == 0) { 3843 a = is_all ? tables_max : (uint32_t)(ent.tbl + 1); 3844 do { 3845 if (do_cmd(IP_FW_TABLE_FLUSH, &ent.tbl, 3846 sizeof(ent.tbl)) < 0) 3847 err(EX_OSERR, "setsockopt(IP_FW_TABLE_FLUSH)"); 3848 } while (++ent.tbl < a); 3849 } else if (_substrcmp(*av, "list") == 0) { 3850 a = is_all ? tables_max : (uint32_t)(ent.tbl + 1); 3851 do { 3852 table_list(ent, is_all); 3853 } while (++ent.tbl < a); 3854 } else 3855 errx(EX_USAGE, "invalid table command %s", *av); 3856} 3857 3858static void 3859table_list(ipfw_table_entry ent, int need_header) 3860{ 3861 ipfw_table *tbl; 3862 socklen_t l; 3863 uint32_t a; 3864 3865 a = ent.tbl; 3866 l = sizeof(a); 3867 if (do_cmd(IP_FW_TABLE_GETSIZE, &a, (uintptr_t)&l) < 0) 3868 err(EX_OSERR, "getsockopt(IP_FW_TABLE_GETSIZE)"); 3869 3870 /* If a is zero we have nothing to do, the table is empty. */ 3871 if (a == 0) 3872 return; 3873 3874 l = sizeof(*tbl) + a * sizeof(ipfw_table_entry); 3875 tbl = safe_calloc(1, l); 3876 tbl->tbl = ent.tbl; 3877 if (do_cmd(IP_FW_TABLE_LIST, tbl, (uintptr_t)&l) < 0) 3878 err(EX_OSERR, "getsockopt(IP_FW_TABLE_LIST)"); 3879 if (tbl->cnt && need_header) 3880 printf("---table(%d)---\n", tbl->tbl); 3881 for (a = 0; a < tbl->cnt; a++) { 3882 unsigned int tval; 3883 tval = tbl->ent[a].value; 3884 if (co.do_value_as_ip) { 3885 char tbuf[128]; 3886 strncpy(tbuf, inet_ntoa(*(struct in_addr *) 3887 &tbl->ent[a].addr), 127); 3888 /* inet_ntoa expects network order */ 3889 tval = htonl(tval); 3890 printf("%s/%u %s\n", tbuf, tbl->ent[a].masklen, 3891 inet_ntoa(*(struct in_addr *)&tval)); 3892 } else { 3893 printf("%s/%u %u\n", 3894 inet_ntoa(*(struct in_addr *)&tbl->ent[a].addr), 3895 tbl->ent[a].masklen, tval); 3896 } 3897 } 3898 free(tbl); 3899} 3900