195df0f2pfg/*- 245a5322luigi * Copyright (c) 2002-2003 Luigi Rizzo 3a9ab854luigi * Copyright (c) 1996 Alex Nash, Paul Traina, Poul-Henning Kamp 4a9ab854luigi * Copyright (c) 1994 Ugen J.S.Antsilevich 5a9ab854luigi * 6a9ab854luigi * Idea and grammar partially left from: 7a9ab854luigi * Copyright (c) 1993 Daniel Boulet 8a9ab854luigi * 9a9ab854luigi * Redistribution and use in source forms, with and without modification, 10a9ab854luigi * are permitted provided that this entire comment appears intact. 11a9ab854luigi * 12a9ab854luigi * Redistribution in binary form may occur without any restrictions. 13a9ab854luigi * Obviously, it would be nice if you gave credit where credit is due 14a9ab854luigi * but requiring it would be too onerous. 15a9ab854luigi * 16a9ab854luigi * This software is provided ``AS IS'' without any warranties of any kind. 17a9ab854luigi * 18a9ab854luigi * NEW command line interface for IP firewall facility 19a9ab854luigi * 20a9ab854luigi * $FreeBSD$ 21a9ab854luigi */ 22a9ab854luigi 236cbadf0luigi#include <sys/types.h> 242071e35benl#include <sys/param.h> 25a9ab854luigi#include <sys/socket.h> 26a9ab854luigi#include <sys/sockio.h> 27a9ab854luigi#include <sys/sysctl.h> 2880a7476luigi 2980a7476luigi#include "ipfw2.h" 30a9ab854luigi 31a9ab854luigi#include <ctype.h> 32a9ab854luigi#include <err.h> 33a9ab854luigi#include <errno.h> 34a9ab854luigi#include <grp.h> 3595deb22jamie#include <jail.h> 36a9ab854luigi#include <netdb.h> 37a9ab854luigi#include <pwd.h> 38a9ab854luigi#include <stdio.h> 395d627fdmelifaro#include <stdarg.h> 40fccd5b2ae#include <stdint.h> 41a9ab854luigi#include <stdlib.h> 42a9ab854luigi#include <string.h> 43a9ab854luigi#include <sysexits.h> 4423001c7luigi#include <time.h> /* ctime */ 456cbadf0luigi#include <timeconv.h> /* _long_to_time */ 46a1ab5f0green#include <unistd.h> 47a1ab5f0green#include <fcntl.h> 48c614ff6melifaro#include <stddef.h> /* offsetof */ 49a9ab854luigi 504941ee4maxim#include <net/ethernet.h> 5123001c7luigi#include <net/if.h> /* only IFNAMSIZ */ 52a9ab854luigi#include <netinet/in.h> 5323001c7luigi#include <netinet/in_systm.h> /* only n_short, n_long */ 54a9ab854luigi#include <netinet/ip.h> 55a9ab854luigi#include <netinet/ip_icmp.h> 56a9ab854luigi#include <netinet/ip_fw.h> 57a9ab854luigi#include <netinet/tcp.h> 58a9ab854luigi#include <arpa/inet.h> 59a9ab854luigi 60e76b8ebmarkjstruct cmdline_opts g_co; /* global options */ 61a9ab854luigi 625d627fdmelifarostruct format_opts { 635d627fdmelifaro int bcwidth; 645d627fdmelifaro int pcwidth; 655d627fdmelifaro int show_counters; 66be47553melifaro int show_time; /* show timestamp */ 673f7d90bmelifaro uint32_t set_mask; /* enabled sets mask */ 68145faf7melifaro uint32_t flags; /* request flags */ 69145faf7melifaro uint32_t first; /* first rule to request */ 70145faf7melifaro uint32_t last; /* last rule to request */ 717189aecmelifaro uint32_t dcnt; /* number of dynamic states */ 72145faf7melifaro ipfw_obj_ctlv *tstate; /* table state data */ 735d627fdmelifaro}; 745d627fdmelifaro 7580a7476luigiint resvd_set_number = RESVD_SET; 76a9ab854luigi 77e76b8ebmarkjstatic int ipfw_socket = -1; 78c614ff6melifaro 7912a0d12melifaro#define CHECK_LENGTH(v, len) do { \ 8012a0d12melifaro if ((v) < (len)) \ 8112a0d12melifaro errx(EX_DATAERR, "Rule too long"); \ 8212a0d12melifaro } while (0) 8312a0d12melifaro/* 8412a0d12melifaro * Check if we have enough space in cmd buffer. Note that since 8512a0d12melifaro * first 8? u32 words are reserved by reserved header, full cmd 8612a0d12melifaro * buffer can't be used, so we need to protect from buffer overrun 879308a28pfg * only. At the beginning, cblen is less than actual buffer size by 8812a0d12melifaro * size of ipfw_insn_u32 instruction + 1 u32 work. This eliminates need 8912a0d12melifaro * for checking small instructions fitting in given range. 9012a0d12melifaro * We also (ab)use the fact that ipfw_insn is always the first field 9112a0d12melifaro * for any custom instruction. 9212a0d12melifaro */ 9312a0d12melifaro#define CHECK_CMDLEN CHECK_LENGTH(cblen, F_LEN((ipfw_insn *)cmd)) 9412a0d12melifaro 957a65db8oleg#define GET_UINT_ARG(arg, min, max, tok, s_x) do { \ 965ceeac4luigi if (!av[0]) \ 977a65db8oleg errx(EX_USAGE, "%s: missing argument", match_value(s_x, tok)); \ 987a65db8oleg if (_substrcmp(*av, "tablearg") == 0) { \ 9920eb17amelifaro arg = IP_FW_TARG; \ 1007a65db8oleg break; \ 1017a65db8oleg } \ 1027a65db8oleg \ 1037a65db8oleg { \ 1045ceeac4luigi long _xval; \ 1057a65db8oleg char *end; \ 1067a65db8oleg \ 1075ceeac4luigi _xval = strtol(*av, &end, 10); \ 1087a65db8oleg \ 1095ceeac4luigi if (!isdigit(**av) || *end != '\0' || (_xval == 0 && errno == EINVAL)) \ 1107a65db8oleg errx(EX_DATAERR, "%s: invalid argument: %s", \ 1117a65db8oleg match_value(s_x, tok), *av); \ 1127a65db8oleg \ 1135ceeac4luigi if (errno == ERANGE || _xval < min || _xval > max) \ 1147a65db8oleg errx(EX_DATAERR, "%s: argument is out of range (%u..%u): %s", \ 1157a65db8oleg match_value(s_x, tok), min, max, *av); \ 1167a65db8oleg \ 11720eb17amelifaro if (_xval == IP_FW_TARG) \ 1187a65db8oleg errx(EX_DATAERR, "%s: illegal argument value: %s", \ 1197a65db8oleg match_value(s_x, tok), *av); \ 1205ceeac4luigi arg = _xval; \ 1217a65db8oleg } \ 1227a65db8oleg} while (0) 1237a65db8oleg 124a9ab854luigistatic struct _s_x f_tcpflags[] = { 125a9ab854luigi { "syn", TH_SYN }, 126a9ab854luigi { "fin", TH_FIN }, 127a9ab854luigi { "ack", TH_ACK }, 128a9ab854luigi { "psh", TH_PUSH }, 129a9ab854luigi { "rst", TH_RST }, 130a9ab854luigi { "urg", TH_URG }, 131a9ab854luigi { "tcp flag", 0 }, 132a9ab854luigi { NULL, 0 } 133a9ab854luigi}; 134a9ab854luigi 135a9ab854luigistatic struct _s_x f_tcpopts[] = { 136a9ab854luigi { "mss", IP_FW_TCPOPT_MSS }, 137a9ab854luigi { "maxseg", IP_FW_TCPOPT_MSS }, 138a9ab854luigi { "window", IP_FW_TCPOPT_WINDOW }, 139a9ab854luigi { "sack", IP_FW_TCPOPT_SACK }, 140a9ab854luigi { "ts", IP_FW_TCPOPT_TS }, 141a9ab854luigi { "timestamp", IP_FW_TCPOPT_TS }, 142a9ab854luigi { "cc", IP_FW_TCPOPT_CC }, 143a9ab854luigi { "tcp option", 0 }, 144a9ab854luigi { NULL, 0 } 145a9ab854luigi}; 146a9ab854luigi 147a9ab854luigi/* 148a9ab854luigi * IP options span the range 0 to 255 so we need to remap them 149a9ab854luigi * (though in fact only the low 5 bits are significant). 150a9ab854luigi */ 151a9ab854luigistatic struct _s_x f_ipopts[] = { 152a9ab854luigi { "ssrr", IP_FW_IPOPT_SSRR}, 153a9ab854luigi { "lsrr", IP_FW_IPOPT_LSRR}, 154a9ab854luigi { "rr", IP_FW_IPOPT_RR}, 155a9ab854luigi { "ts", IP_FW_IPOPT_TS}, 156a9ab854luigi { "ip option", 0 }, 157a9ab854luigi { NULL, 0 } 158a9ab854luigi}; 159a9ab854luigi 160a9ab854luigistatic struct _s_x f_iptos[] = { 161a9ab854luigi { "lowdelay", IPTOS_LOWDELAY}, 162a9ab854luigi { "throughput", IPTOS_THROUGHPUT}, 163a9ab854luigi { "reliability", IPTOS_RELIABILITY}, 164a9ab854luigi { "mincost", IPTOS_MINCOST}, 16504560c1rpaulo { "congestion", IPTOS_ECN_CE}, 16604560c1rpaulo { "ecntransport", IPTOS_ECN_ECT0}, 167a9ab854luigi { "ip tos option", 0}, 168a9ab854luigi { NULL, 0 } 169a9ab854luigi}; 170a9ab854luigi 171a90e178glebiusstatic struct _s_x f_ipoff[] = { 172a90e178glebius { "rf", IP_RF >> 8 }, 173a90e178glebius { "df", IP_DF >> 8 }, 174a90e178glebius { "mf", IP_MF >> 8 }, 175a90e178glebius { "offset", 0x1 }, 176a90e178glebius { NULL, 0} 177a90e178glebius}; 178a90e178glebius 1799902323melifarostruct _s_x f_ipdscp[] = { 18031a6358melifaro { "af11", IPTOS_DSCP_AF11 >> 2 }, /* 001010 */ 18131a6358melifaro { "af12", IPTOS_DSCP_AF12 >> 2 }, /* 001100 */ 18231a6358melifaro { "af13", IPTOS_DSCP_AF13 >> 2 }, /* 001110 */ 18331a6358melifaro { "af21", IPTOS_DSCP_AF21 >> 2 }, /* 010010 */ 18431a6358melifaro { "af22", IPTOS_DSCP_AF22 >> 2 }, /* 010100 */ 18531a6358melifaro { "af23", IPTOS_DSCP_AF23 >> 2 }, /* 010110 */ 18631a6358melifaro { "af31", IPTOS_DSCP_AF31 >> 2 }, /* 011010 */ 18731a6358melifaro { "af32", IPTOS_DSCP_AF32 >> 2 }, /* 011100 */ 18831a6358melifaro { "af33", IPTOS_DSCP_AF33 >> 2 }, /* 011110 */ 18931a6358melifaro { "af41", IPTOS_DSCP_AF41 >> 2 }, /* 100010 */ 19031a6358melifaro { "af42", IPTOS_DSCP_AF42 >> 2 }, /* 100100 */ 19131a6358melifaro { "af43", IPTOS_DSCP_AF43 >> 2 }, /* 100110 */ 19231a6358melifaro { "be", IPTOS_DSCP_CS0 >> 2 }, /* 000000 */ 19331a6358melifaro { "ef", IPTOS_DSCP_EF >> 2 }, /* 101110 */ 19431a6358melifaro { "cs0", IPTOS_DSCP_CS0 >> 2 }, /* 000000 */ 19531a6358melifaro { "cs1", IPTOS_DSCP_CS1 >> 2 }, /* 001000 */ 19631a6358melifaro { "cs2", IPTOS_DSCP_CS2 >> 2 }, /* 010000 */ 19731a6358melifaro { "cs3", IPTOS_DSCP_CS3 >> 2 }, /* 011000 */ 19831a6358melifaro { "cs4", IPTOS_DSCP_CS4 >> 2 }, /* 100000 */ 19931a6358melifaro { "cs5", IPTOS_DSCP_CS5 >> 2 }, /* 101000 */ 20031a6358melifaro { "cs6", IPTOS_DSCP_CS6 >> 2 }, /* 110000 */ 20131a6358melifaro { "cs7", IPTOS_DSCP_CS7 >> 2 }, /* 100000 */ 20231a6358melifaro { NULL, 0 } 20331a6358melifaro}; 20431a6358melifaro 205a9ab854luigistatic struct _s_x limit_masks[] = { 206a9ab854luigi {"all", DYN_SRC_ADDR|DYN_SRC_PORT|DYN_DST_ADDR|DYN_DST_PORT}, 207a9ab854luigi {"src-addr", DYN_SRC_ADDR}, 208a9ab854luigi {"src-port", DYN_SRC_PORT}, 209a9ab854luigi {"dst-addr", DYN_DST_ADDR}, 210a9ab854luigi {"dst-port", DYN_DST_PORT}, 211a9ab854luigi {NULL, 0} 212a9ab854luigi}; 213a9ab854luigi 214a9ab854luigi/* 215a9ab854luigi * we use IPPROTO_ETHERTYPE as a fake protocol id to call the print routines 216a9ab854luigi * This is only used in this code. 217a9ab854luigi */ 218a9ab854luigi#define IPPROTO_ETHERTYPE 0x1000 219a9ab854luigistatic struct _s_x ether_types[] = { 220a9ab854luigi /* 221a9ab854luigi * Note, we cannot use "-:&/" in the names because they are field 222