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
6080a7476luigistruct cmdline_opts 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
77c614ff6melifaroint 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
1719902323melifarostruct _s_x f_ipdscp[] = {
17231a6358melifaro	{ "af11", IPTOS_DSCP_AF11 >> 2 },	/* 001010 */
17331a6358melifaro	{ "af12", IPTOS_DSCP_AF12 >> 2 },	/* 001100 */
17431a6358melifaro	{ "af13", IPTOS_DSCP_AF13 >> 2 },	/* 001110 */
17531a6358melifaro	{ "af21", IPTOS_DSCP_AF21 >> 2 },	/* 010010 */
17631a6358melifaro	{ "af22", IPTOS_DSCP_AF22 >> 2 },	/* 010100 */
17731a6358melifaro	{ "af23", IPTOS_DSCP_AF23 >> 2 },	/* 010110 */
17831a6358melifaro	{ "af31", IPTOS_DSCP_AF31 >> 2 },	/* 011010 */
17931a6358melifaro	{ "af32", IPTOS_DSCP_AF32 >> 2 },	/* 011100 */
18031a6358melifaro	{ "af33", IPTOS_DSCP_AF33 >> 2 },	/* 011110 */
18131a6358melifaro	{ "af41", IPTOS_DSCP_AF41 >> 2 },	/* 100010 */
18231a6358melifaro	{ "af42", IPTOS_DSCP_AF42 >> 2 },	/* 100100 */
18331a6358melifaro	{ "af43", IPTOS_DSCP_AF43 >> 2 },	/* 100110 */
18431a6358melifaro	{ "be", IPTOS_DSCP_CS0 >> 2 }, 	/* 000000 */
18531a6358melifaro	{ "ef", IPTOS_DSCP_EF >> 2 },	/* 101110 */
18631a6358melifaro	{ "cs0", IPTOS_DSCP_CS0 >> 2 },	/* 000000 */
18731a6358melifaro	{ "cs1", IPTOS_DSCP_CS1 >> 2 },	/* 001000 */
18831a6358melifaro	{ "cs2", IPTOS_DSCP_CS2 >> 2 },	/* 010000 */
18931a6358melifaro	{ "cs3", IPTOS_DSCP_CS3 >> 2 },	/* 011000 */
19031a6358melifaro	{ "cs4", IPTOS_DSCP_CS4 >> 2 },	/* 100000 */
19131a6358melifaro	{ "cs5", IPTOS_DSCP_CS5 >> 2 },	/* 101000 */
19231a6358melifaro	{ "cs6", IPTOS_DSCP_CS6 >> 2 },	/* 110000 */
19331a6358melifaro	{ "cs7", IPTOS_DSCP_CS7 >> 2 },	/* 100000 */
19431a6358melifaro	{ NULL, 0 }
19531a6358melifaro};
19631a6358melifaro
197a9ab854luigistatic struct _s_x limit_masks[] = {
198a9ab854luigi	{"all",		DYN_SRC_ADDR|DYN_SRC_PORT|DYN_DST_ADDR|DYN_DST_PORT},
199a9ab854luigi	{"src-addr",	DYN_SRC_ADDR},
200a9ab854luigi	{"src-port",	DYN_SRC_PORT},
201a9ab854luigi	{"dst-addr",	DYN_DST_ADDR},
202a9ab854luigi	{"dst-port",	DYN_DST_PORT},
203a9ab854luigi	{NULL,		0}
204a9ab854luigi};
205a9ab854luigi
206a9ab854luigi/*
207a9ab854luigi * we use IPPROTO_ETHERTYPE as a fake protocol id to call the print routines
208a9ab854luigi * This is only used in this code.
209a9ab854luigi */
210a9ab854luigi#define IPPROTO_ETHERTYPE	0x1000
211a9ab854luigistatic struct _s_x ether_types[] = {
212a9ab854luigi    /*
213a9ab854luigi     * Note, we cannot use "-:&/" in the names because they are field
214a9ab854luigi     * separators in the type specifications. Also, we use s = NULL as
215