svn commit: r187733 - user/luigi/ipfw/sbin/ipfw

Luigi Rizzo luigi at FreeBSD.org
Mon Jan 26 09:56:29 PST 2009


Author: luigi
Date: Mon Jan 26 17:56:27 2009
New Revision: 187733
URL: http://svn.freebsd.org/changeset/base/187733

Log:
  snapshot

Added:
  user/luigi/ipfw/sbin/ipfw/compile.c
  user/luigi/ipfw/sbin/ipfw/ipfw2.h
Modified:
  user/luigi/ipfw/sbin/ipfw/Makefile
  user/luigi/ipfw/sbin/ipfw/ipfw2.c

Modified: user/luigi/ipfw/sbin/ipfw/Makefile
==============================================================================
--- user/luigi/ipfw/sbin/ipfw/Makefile	Mon Jan 26 17:55:07 2009	(r187732)
+++ user/luigi/ipfw/sbin/ipfw/Makefile	Mon Jan 26 17:56:27 2009	(r187733)
@@ -1,8 +1,8 @@
 # $FreeBSD$
 
 PROG=	ipfw
-SRCS=	ipfw2.c
-WARNS?=	0
+SRCS=	ipfw2.c compile.c
+WARNS?=	2
 MAN=	ipfw.8
 
 .include <bsd.prog.mk>

Added: user/luigi/ipfw/sbin/ipfw/compile.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ user/luigi/ipfw/sbin/ipfw/compile.c	Mon Jan 26 17:56:27 2009	(r187733)
@@ -0,0 +1,5577 @@
+/*
+ * Copyright (c) 2002-2003 Luigi Rizzo
+ * Copyright (c) 1996 Alex Nash, Paul Traina, Poul-Henning Kamp
+ * Copyright (c) 1994 Ugen J.S.Antsilevich
+ *
+ * Idea and grammar partially left from:
+ * Copyright (c) 1993 Daniel Boulet
+ *
+ * Redistribution and use in source forms, with and without modification,
+ * are permitted provided that this entire comment appears intact.
+ *
+ * Redistribution in binary form may occur without any restrictions.
+ * Obviously, it would be nice if you gave credit where credit is due
+ * but requiring it would be too onerous.
+ *
+ * This software is provided ``AS IS'' without any warranties of any kind.
+ *
+ * NEW command line interface for IP firewall facility
+ *
+ * $FreeBSD: head/sbin/ipfw/ipfw2.c 187716 2009-01-26 14:26:35Z luigi $
+ */
+
+#include "ipfw2.h"
+
+#if 0
+int
+		do_value_as_ip,		/* show table value as IP */
+		do_resolv,		/* Would try to resolve all */
+		do_time,		/* Show time stamps */
+		do_quiet,		/* Be quiet in add and flush */
+		do_pipe,		/* this cmd refers to a pipe */
+	        do_nat, 		/* Nat configuration. */
+		do_sort,		/* field to sort results (0 = no) */
+		do_dynamic,		/* display dynamic rules */
+		do_expired,		/* display expired dynamic rules */
+		do_compact,		/* show rules in compact mode */
+		do_force,		/* do not ask for confirmation */
+		use_set,		/* work with specified set number */
+		show_sets,		/* display rule sets */
+		test_only,		/* only check syntax */
+		comment_only,		/* only print action and comment */
+		verbose;
+
+static struct _s_x f_tcpflags[] = {
+	{ "syn", TH_SYN },
+	{ "fin", TH_FIN },
+	{ "ack", TH_ACK },
+	{ "psh", TH_PUSH },
+	{ "rst", TH_RST },
+	{ "urg", TH_URG },
+	{ "tcp flag", 0 },
+	{ NULL,	0 }
+};
+
+static struct _s_x f_tcpopts[] = {
+	{ "mss",	IP_FW_TCPOPT_MSS },
+	{ "maxseg",	IP_FW_TCPOPT_MSS },
+	{ "window",	IP_FW_TCPOPT_WINDOW },
+	{ "sack",	IP_FW_TCPOPT_SACK },
+	{ "ts",		IP_FW_TCPOPT_TS },
+	{ "timestamp",	IP_FW_TCPOPT_TS },
+	{ "cc",		IP_FW_TCPOPT_CC },
+	{ "tcp option",	0 },
+	{ NULL,	0 }
+};
+
+/*
+ * IP options span the range 0 to 255 so we need to remap them
+ * (though in fact only the low 5 bits are significant).
+ */
+static struct _s_x f_ipopts[] = {
+	{ "ssrr",	IP_FW_IPOPT_SSRR},
+	{ "lsrr",	IP_FW_IPOPT_LSRR},
+	{ "rr",		IP_FW_IPOPT_RR},
+	{ "ts",		IP_FW_IPOPT_TS},
+	{ "ip option",	0 },
+	{ NULL,	0 }
+};
+
+static struct _s_x f_iptos[] = {
+	{ "lowdelay",	IPTOS_LOWDELAY},
+	{ "throughput",	IPTOS_THROUGHPUT},
+	{ "reliability", IPTOS_RELIABILITY},
+	{ "mincost",	IPTOS_MINCOST},
+	{ "congestion",	IPTOS_ECN_CE},
+	{ "ecntransport", IPTOS_ECN_ECT0},
+	{ "ip tos option", 0},
+	{ NULL,	0 }
+};
+
+static struct _s_x limit_masks[] = {
+	{"all",		DYN_SRC_ADDR|DYN_SRC_PORT|DYN_DST_ADDR|DYN_DST_PORT},
+	{"src-addr",	DYN_SRC_ADDR},
+	{"src-port",	DYN_SRC_PORT},
+	{"dst-addr",	DYN_DST_ADDR},
+	{"dst-port",	DYN_DST_PORT},
+	{NULL,		0}
+};
+
+/*
+ * we use IPPROTO_ETHERTYPE as a fake protocol id to call the print routines
+ * This is only used in this code.
+ */
+static struct _s_x ether_types[] = {
+    /*
+     * Note, we cannot use "-:&/" in the names because they are field
+     * separators in the type specifications. Also, we use s = NULL as
+     * end-delimiter, because a type of 0 can be legal.
+     */
+	{ "ip",		0x0800 },
+	{ "ipv4",	0x0800 },
+	{ "ipv6",	0x86dd },
+	{ "arp",	0x0806 },
+	{ "rarp",	0x8035 },
+	{ "vlan",	0x8100 },
+	{ "loop",	0x9000 },
+	{ "trail",	0x1000 },
+	{ "at",		0x809b },
+	{ "atalk",	0x809b },
+	{ "aarp",	0x80f3 },
+	{ "pppoe_disc",	0x8863 },
+	{ "pppoe_sess",	0x8864 },
+	{ "ipx_8022",	0x00E0 },
+	{ "ipx_8023",	0x0000 },
+	{ "ipx_ii",	0x8137 },
+	{ "ipx_snap",	0x8137 },
+	{ "ipx",	0x8137 },
+	{ "ns",		0x0600 },
+	{ NULL,		0 }
+};
+
+static void show_usage(void);
+
+struct _s_x dummynet_params[] = {
+	{ "plr",		TOK_PLR },
+	{ "noerror",		TOK_NOERROR },
+	{ "buckets",		TOK_BUCKETS },
+	{ "dst-ip",		TOK_DSTIP },
+	{ "src-ip",		TOK_SRCIP },
+	{ "dst-port",		TOK_DSTPORT },
+	{ "src-port",		TOK_SRCPORT },
+	{ "proto",		TOK_PROTO },
+	{ "weight",		TOK_WEIGHT },
+	{ "all",		TOK_ALL },
+	{ "mask",		TOK_MASK },
+	{ "droptail",		TOK_DROPTAIL },
+	{ "red",		TOK_RED },
+	{ "gred",		TOK_GRED },
+	{ "bw",			TOK_BW },
+	{ "bandwidth",		TOK_BW },
+	{ "delay",		TOK_DELAY },
+	{ "pipe",		TOK_PIPE },
+	{ "queue",		TOK_QUEUE },
+	{ "flow-id",		TOK_FLOWID},
+	{ "dst-ipv6",		TOK_DSTIP6},
+	{ "dst-ip6",		TOK_DSTIP6},
+	{ "src-ipv6",		TOK_SRCIP6},
+	{ "src-ip6",		TOK_SRCIP6},
+	{ "dummynet-params",	TOK_NULL },
+	{ NULL, 0 }	/* terminator */
+};
+
+struct _s_x nat_params[] = {
+	{ "ip",	                TOK_IP },
+	{ "if",	                TOK_IF },
+ 	{ "log",                TOK_ALOG },
+ 	{ "deny_in",	        TOK_DENY_INC },
+ 	{ "same_ports",	        TOK_SAME_PORTS },
+ 	{ "unreg_only",	        TOK_UNREG_ONLY },
+ 	{ "reset",	        TOK_RESET_ADDR },
+ 	{ "reverse",	        TOK_ALIAS_REV },	
+ 	{ "proxy_only",	        TOK_PROXY_ONLY },
+	{ "redirect_addr",	TOK_REDIR_ADDR },
+	{ "redirect_port",	TOK_REDIR_PORT },
+	{ "redirect_proto",	TOK_REDIR_PROTO },
+ 	{ NULL, 0 }	/* terminator */
+};
+#endif
+
+static struct _s_x rule_actions[] = {
+	{ "accept",		TOK_ACCEPT },
+	{ "pass",		TOK_ACCEPT },
+	{ "allow",		TOK_ACCEPT },
+	{ "permit",		TOK_ACCEPT },
+	{ "count",		TOK_COUNT },
+	{ "pipe",		TOK_PIPE },
+	{ "queue",		TOK_QUEUE },
+	{ "divert",		TOK_DIVERT },
+	{ "tee",		TOK_TEE },
+	{ "netgraph",		TOK_NETGRAPH },
+	{ "ngtee",		TOK_NGTEE },
+	{ "fwd",		TOK_FORWARD },
+	{ "forward",		TOK_FORWARD },
+	{ "skipto",		TOK_SKIPTO },
+	{ "deny",		TOK_DENY },
+	{ "drop",		TOK_DENY },
+	{ "reject",		TOK_REJECT },
+	{ "reset6",		TOK_RESET6 },
+	{ "reset",		TOK_RESET },
+	{ "unreach6",		TOK_UNREACH6 },
+	{ "unreach",		TOK_UNREACH },
+	{ "check-state",	TOK_CHECKSTATE },
+	{ "//",			TOK_COMMENT },
+	{ "nat",                TOK_NAT },
+	{ "setfib",		TOK_SETFIB },
+	{ NULL, 0 }	/* terminator */
+};
+
+#if 0
+struct _s_x rule_action_params[] = {
+	{ "altq",		TOK_ALTQ },
+	{ "log",		TOK_LOG },
+	{ "tag",		TOK_TAG },
+	{ "untag",		TOK_UNTAG },
+	{ NULL, 0 }	/* terminator */
+};
+
+struct _s_x rule_options[] = {
+	{ "tagged",		TOK_TAGGED },
+	{ "uid",		TOK_UID },
+	{ "gid",		TOK_GID },
+	{ "jail",		TOK_JAIL },
+	{ "in",			TOK_IN },
+	{ "limit",		TOK_LIMIT },
+	{ "keep-state",		TOK_KEEPSTATE },
+	{ "bridged",		TOK_LAYER2 },
+	{ "layer2",		TOK_LAYER2 },
+	{ "out",		TOK_OUT },
+	{ "diverted",		TOK_DIVERTED },
+	{ "diverted-loopback",	TOK_DIVERTEDLOOPBACK },
+	{ "diverted-output",	TOK_DIVERTEDOUTPUT },
+	{ "xmit",		TOK_XMIT },
+	{ "recv",		TOK_RECV },
+	{ "via",		TOK_VIA },
+	{ "fragment",		TOK_FRAG },
+	{ "frag",		TOK_FRAG },
+	{ "fib",		TOK_FIB },
+	{ "ipoptions",		TOK_IPOPTS },
+	{ "ipopts",		TOK_IPOPTS },
+	{ "iplen",		TOK_IPLEN },
+	{ "ipid",		TOK_IPID },
+	{ "ipprecedence",	TOK_IPPRECEDENCE },
+	{ "iptos",		TOK_IPTOS },
+	{ "ipttl",		TOK_IPTTL },
+	{ "ipversion",		TOK_IPVER },
+	{ "ipver",		TOK_IPVER },
+	{ "estab",		TOK_ESTAB },
+	{ "established",	TOK_ESTAB },
+	{ "setup",		TOK_SETUP },
+	{ "tcpdatalen",		TOK_TCPDATALEN },
+	{ "tcpflags",		TOK_TCPFLAGS },
+	{ "tcpflgs",		TOK_TCPFLAGS },
+	{ "tcpoptions",		TOK_TCPOPTS },
+	{ "tcpopts",		TOK_TCPOPTS },
+	{ "tcpseq",		TOK_TCPSEQ },
+	{ "tcpack",		TOK_TCPACK },
+	{ "tcpwin",		TOK_TCPWIN },
+	{ "icmptype",		TOK_ICMPTYPES },
+	{ "icmptypes",		TOK_ICMPTYPES },
+	{ "dst-ip",		TOK_DSTIP },
+	{ "src-ip",		TOK_SRCIP },
+	{ "dst-port",		TOK_DSTPORT },
+	{ "src-port",		TOK_SRCPORT },
+	{ "proto",		TOK_PROTO },
+	{ "MAC",		TOK_MAC },
+	{ "mac",		TOK_MAC },
+	{ "mac-type",		TOK_MACTYPE },
+	{ "verrevpath",		TOK_VERREVPATH },
+	{ "versrcreach",	TOK_VERSRCREACH },
+	{ "antispoof",		TOK_ANTISPOOF },
+	{ "ipsec",		TOK_IPSEC },
+	{ "icmp6type",		TOK_ICMP6TYPES },
+	{ "icmp6types",		TOK_ICMP6TYPES },
+	{ "ext6hdr",		TOK_EXT6HDR},
+	{ "flow-id",		TOK_FLOWID},
+	{ "ipv6",		TOK_IPV6},
+	{ "ip6",		TOK_IPV6},
+	{ "ipv4",		TOK_IPV4},
+	{ "ip4",		TOK_IPV4},
+	{ "dst-ipv6",		TOK_DSTIP6},
+	{ "dst-ip6",		TOK_DSTIP6},
+	{ "src-ipv6",		TOK_SRCIP6},
+	{ "src-ip6",		TOK_SRCIP6},
+	{ "//",			TOK_COMMENT },
+
+	{ "not",		TOK_NOT },		/* pseudo option */
+	{ "!", /* escape ? */	TOK_NOT },		/* pseudo option */
+	{ "or",			TOK_OR },		/* pseudo option */
+	{ "|", /* escape */	TOK_OR },		/* pseudo option */
+	{ "{",			TOK_STARTBRACE },	/* pseudo option */
+	{ "(",			TOK_STARTBRACE },	/* pseudo option */
+	{ "}",			TOK_ENDBRACE },		/* pseudo option */
+	{ ")",			TOK_ENDBRACE },		/* pseudo option */
+	{ NULL, 0 }	/* terminator */
+};
+
+#define	TABLEARG	"tablearg"
+
+static void *
+safe_calloc(size_t number, size_t size)
+{
+	void *ret = calloc(number, size);
+
+	if (ret == NULL)
+		err(EX_OSERR, "calloc");
+	return ret;
+}
+
+static void *
+safe_realloc(void *ptr, size_t size)
+{
+	void *ret = realloc(ptr, size);
+
+	if (ret == NULL)
+		err(EX_OSERR, "realloc");
+	return ret;
+}
+
+/*
+ * conditionally runs the command.
+ */
+static int
+do_cmd(int optname, void *optval, uintptr_t optlen)
+{
+	static int s = -1;	/* the socket */
+	int i;
+
+	if (test_only)
+		return 0;
+
+	if (s == -1)
+		s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
+	if (s < 0)
+		err(EX_UNAVAILABLE, "socket");
+
+	if (optname == IP_FW_GET || optname == IP_DUMMYNET_GET ||
+	    optname == IP_FW_ADD || optname == IP_FW_TABLE_LIST ||
+	    optname == IP_FW_TABLE_GETSIZE || 
+	    optname == IP_FW_NAT_GET_CONFIG || 
+	    optname == IP_FW_NAT_GET_LOG)
+		i = getsockopt(s, IPPROTO_IP, optname, optval,
+			(socklen_t *)optlen);
+	else
+		i = setsockopt(s, IPPROTO_IP, optname, optval, optlen);
+	return i;
+}
+
+/**
+ * match_token takes a table and a string, returns the value associated
+ * with the string (-1 in case of failure).
+ */
+static int
+match_token(struct _s_x *table, char *string)
+{
+	struct _s_x *pt;
+	uint i = strlen(string);
+
+	for (pt = table ; i && pt->s != NULL ; pt++)
+		if (strlen(pt->s) == i && !bcmp(string, pt->s, i))
+			return pt->x;
+	return -1;
+}
+
+/**
+ * match_value takes a table and a value, returns the string associated
+ * with the value (NULL in case of failure).
+ */
+static char const *
+match_value(struct _s_x *p, int value)
+{
+	for (; p->s != NULL; p++)
+		if (p->x == value)
+			return p->s;
+	return NULL;
+}
+
+/*
+ * _substrcmp takes two strings and returns 1 if they do not match,
+ * and 0 if they match exactly or the first string is a sub-string
+ * of the second.  A warning is printed to stderr in the case that the
+ * first string is a sub-string of the second.
+ *
+ * This function will be removed in the future through the usual
+ * deprecation process.
+ */
+static int
+_substrcmp(const char *str1, const char* str2)
+{
+	
+	if (strncmp(str1, str2, strlen(str1)) != 0)
+		return 1;
+
+	if (strlen(str1) != strlen(str2))
+		warnx("DEPRECATED: '%s' matched '%s' as a sub-string",
+		    str1, str2);
+	return 0;
+}
+
+/*
+ * _substrcmp2 takes three strings and returns 1 if the first two do not match,
+ * and 0 if they match exactly or the second string is a sub-string
+ * of the first.  A warning is printed to stderr in the case that the
+ * first string does not match the third.
+ *
+ * This function exists to warn about the bizzare construction
+ * strncmp(str, "by", 2) which is used to allow people to use a shotcut
+ * for "bytes".  The problem is that in addition to accepting "by",
+ * "byt", "byte", and "bytes", it also excepts "by_rabid_dogs" and any
+ * other string beginning with "by".
+ *
+ * This function will be removed in the future through the usual
+ * deprecation process.
+ */
+static int
+_substrcmp2(const char *str1, const char* str2, const char* str3)
+{
+	
+	if (strncmp(str1, str2, strlen(str2)) != 0)
+		return 1;
+
+	if (strcmp(str1, str3) != 0)
+		warnx("DEPRECATED: '%s' matched '%s'",
+		    str1, str3);
+	return 0;
+}
+
+/*
+ * prints one port, symbolic or numeric
+ */
+static void
+print_port(int proto, uint16_t port)
+{
+
+	if (proto == IPPROTO_ETHERTYPE) {
+		char const *s;
+
+		if (do_resolv && (s = match_value(ether_types, port)) )
+			printf("%s", s);
+		else
+			printf("0x%04x", port);
+	} else {
+		struct servent *se = NULL;
+		if (do_resolv) {
+			struct protoent *pe = getprotobynumber(proto);
+
+			se = getservbyport(htons(port), pe ? pe->p_name : NULL);
+		}
+		if (se)
+			printf("%s", se->s_name);
+		else
+			printf("%d", port);
+	}
+}
+
+struct _s_x _port_name[] = {
+	{"dst-port",	O_IP_DSTPORT},
+	{"src-port",	O_IP_SRCPORT},
+	{"ipid",	O_IPID},
+	{"iplen",	O_IPLEN},
+	{"ipttl",	O_IPTTL},
+	{"mac-type",	O_MAC_TYPE},
+	{"tcpdatalen",	O_TCPDATALEN},
+	{"tagged",	O_TAGGED},
+	{NULL,		0}
+};
+
+/*
+ * Print the values in a list 16-bit items of the types above.
+ * XXX todo: add support for mask.
+ */
+static void
+print_newports(ipfw_insn_u16 *cmd, int proto, int opcode)
+{
+	uint16_t *p = cmd->ports;
+	int i;
+	char const *sep;
+
+	if (opcode != 0) {
+		sep = match_value(_port_name, opcode);
+		if (sep == NULL)
+			sep = "???";
+		printf (" %s", sep);
+	}
+	sep = " ";
+	for (i = F_LEN((ipfw_insn *)cmd) - 1; i > 0; i--, p += 2) {
+		printf(sep);
+		print_port(proto, p[0]);
+		if (p[0] != p[1]) {
+			printf("-");
+			print_port(proto, p[1]);
+		}
+		sep = ",";
+	}
+}
+#endif
+
+/*
+ * Like strtol, but also translates service names into port numbers
+ * for some protocols.
+ * In particular:
+ *	proto == -1 disables the protocol check;
+ *	proto == IPPROTO_ETHERTYPE looks up an internal table
+ *	proto == <some value in /etc/protocols> matches the values there.
+ * Returns *end == s in case the parameter is not found.
+ */
+static int
+strtoport(char *s, char **end, int base, int proto)
+{
+	char *p, *buf;
+	char *s1;
+	int i;
+
+	*end = s;		/* default - not found */
+	if (*s == '\0')
+		return 0;	/* not found */
+
+	if (isdigit(*s))
+		return strtol(s, end, base);
+
+	/*
+	 * find separator. '\\' escapes the next char.
+	 */
+	for (s1 = s; *s1 && (isalnum(*s1) || *s1 == '\\') ; s1++)
+		if (*s1 == '\\' && s1[1] != '\0')
+			s1++;
+
+	buf = safe_calloc(s1 - s + 1, 1);
+
+	/*
+	 * copy into a buffer skipping backslashes
+	 */
+	for (p = s, i = 0; p != s1 ; p++)
+		if (*p != '\\')
+			buf[i++] = *p;
+	buf[i++] = '\0';
+
+	if (proto == IPPROTO_ETHERTYPE) {
+		i = match_token(ether_types, buf);
+		free(buf);
+		if (i != -1) {	/* found */
+			*end = s1;
+			return i;
+		}
+	} else {
+		struct protoent *pe = NULL;
+		struct servent *se;
+
+		if (proto != 0)
+			pe = getprotobynumber(proto);
+		setservent(1);
+		se = getservbyname(buf, pe ? pe->p_name : NULL);
+		free(buf);
+		if (se != NULL) {
+			*end = s1;
+			return ntohs(se->s_port);
+		}
+	}
+	return 0;	/* not found */
+}
+
+/*
+ * Map between current altq queue id numbers and names.
+ */
+static int altq_fetched = 0;
+static TAILQ_HEAD(, pf_altq) altq_entries = 
+	TAILQ_HEAD_INITIALIZER(altq_entries);
+
+#if 0
+static void
+altq_set_enabled(int enabled)
+{
+	int pffd;
+
+	pffd = open("/dev/pf", O_RDWR);
+	if (pffd == -1)
+		err(EX_UNAVAILABLE,
+		    "altq support opening pf(4) control device");
+	if (enabled) {
+		if (ioctl(pffd, DIOCSTARTALTQ) != 0 && errno != EEXIST)
+			err(EX_UNAVAILABLE, "enabling altq");
+	} else {
+		if (ioctl(pffd, DIOCSTOPALTQ) != 0 && errno != ENOENT)
+			err(EX_UNAVAILABLE, "disabling altq");
+	}
+	close(pffd);
+}
+#endif
+
+static void
+altq_fetch(void)
+{
+	struct pfioc_altq pfioc;
+	struct pf_altq *altq;
+	int pffd;
+	unsigned int mnr;
+
+	if (altq_fetched)
+		return;
+	altq_fetched = 1;
+	pffd = open("/dev/pf", O_RDONLY);
+	if (pffd == -1) {
+		warn("altq support opening pf(4) control device");
+		return;
+	}
+	bzero(&pfioc, sizeof(pfioc));
+	if (ioctl(pffd, DIOCGETALTQS, &pfioc) != 0) {
+		warn("altq support getting queue list");
+		close(pffd);
+		return;
+	}
+	mnr = pfioc.nr;
+	for (pfioc.nr = 0; pfioc.nr < mnr; pfioc.nr++) {
+		if (ioctl(pffd, DIOCGETALTQ, &pfioc) != 0) {
+			if (errno == EBUSY)
+				break;
+			warn("altq support getting queue list");
+			close(pffd);
+			return;
+		}
+		if (pfioc.altq.qid == 0)
+			continue;
+		altq = safe_calloc(1, sizeof(*altq));
+		*altq = pfioc.altq;
+		TAILQ_INSERT_TAIL(&altq_entries, altq, entries);
+	}
+	close(pffd);
+}
+
+static u_int32_t
+altq_name_to_qid(const char *name)
+{
+	struct pf_altq *altq;
+
+	altq_fetch();
+	TAILQ_FOREACH(altq, &altq_entries, entries)
+		if (strcmp(name, altq->qname) == 0)
+			break;
+	if (altq == NULL)
+		errx(EX_DATAERR, "altq has no queue named `%s'", name);
+	return altq->qid;
+}
+
+#if 0
+static const char *
+altq_qid_to_name(u_int32_t qid)
+{
+	struct pf_altq *altq;
+
+	altq_fetch();
+	TAILQ_FOREACH(altq, &altq_entries, entries)
+		if (qid == altq->qid)
+			break;
+	if (altq == NULL)
+		return NULL;
+	return altq->qname;
+}
+#endif
+
+
+static void
+fill_altq_qid(u_int32_t *qid, const char *av)
+{
+	*qid = altq_name_to_qid(av);
+}
+
+/*
+ * Fill the body of the command with the list of port ranges.
+ */
+static int
+fill_newports(ipfw_insn_u16 *cmd, char *av, int proto)
+{
+	uint16_t a, b, *p = cmd->ports;
+	int i = 0;
+	char *s = av;
+
+	while (*s) {
+		a = strtoport(av, &s, 0, proto);
+		if (s == av) 			/* empty or invalid argument */
+			return (0);
+
+		switch (*s) {
+		case '-':			/* a range */
+			av = s + 1;
+			b = strtoport(av, &s, 0, proto);
+			/* Reject expressions like '1-abc' or '1-2-3'. */
+			if (s == av || (*s != ',' && *s != '\0'))
+				return (0);
+			p[0] = a;
+			p[1] = b;
+			break;
+		case ',':			/* comma separated list */
+		case '\0':
+			p[0] = p[1] = a;
+			break;
+		default:
+			warnx("port list: invalid separator <%c> in <%s>",
+				*s, av);
+			return (0);
+		}
+
+		i++;
+		p += 2;
+		av = s + 1;
+	}
+	if (i > 0) {
+		if (i + 1 > F_LEN_MASK)
+			errx(EX_DATAERR, "too many ports/ranges\n");
+		cmd->o.len |= i + 1;	/* leave F_NOT and F_OR untouched */
+	}
+	return (i);
+}
+
+#if 0
+static struct _s_x icmpcodes[] = {
+      { "net",			ICMP_UNREACH_NET },
+      { "host",			ICMP_UNREACH_HOST },
+      { "protocol",		ICMP_UNREACH_PROTOCOL },
+      { "port",			ICMP_UNREACH_PORT },
+      { "needfrag",		ICMP_UNREACH_NEEDFRAG },
+      { "srcfail",		ICMP_UNREACH_SRCFAIL },
+      { "net-unknown",		ICMP_UNREACH_NET_UNKNOWN },
+      { "host-unknown",		ICMP_UNREACH_HOST_UNKNOWN },
+      { "isolated",		ICMP_UNREACH_ISOLATED },
+      { "net-prohib",		ICMP_UNREACH_NET_PROHIB },
+      { "host-prohib",		ICMP_UNREACH_HOST_PROHIB },
+      { "tosnet",		ICMP_UNREACH_TOSNET },
+      { "toshost",		ICMP_UNREACH_TOSHOST },
+      { "filter-prohib",	ICMP_UNREACH_FILTER_PROHIB },
+      { "host-precedence",	ICMP_UNREACH_HOST_PRECEDENCE },
+      { "precedence-cutoff",	ICMP_UNREACH_PRECEDENCE_CUTOFF },
+      { NULL, 0 }
+};
+#endif
+
+static void
+fill_reject_code(u_short *codep, char *str)
+{
+	int val;
+	char *s;
+
+	val = strtoul(str, &s, 0);
+	if (s == str || *s != '\0' || val >= 0x100)
+		val = match_token(icmpcodes, str);
+	if (val < 0)
+		errx(EX_DATAERR, "unknown ICMP unreachable code ``%s''", str);
+	*codep = val;
+	return;
+}
+
+#if 0
+static void
+print_reject_code(uint16_t code)
+{
+	char const *s = match_value(icmpcodes, code);
+
+	if (s != NULL)
+		printf("unreach %s", s);
+	else
+		printf("unreach %u", code);
+}
+
+static struct _s_x icmp6codes[] = {
+      { "no-route",		ICMP6_DST_UNREACH_NOROUTE },
+      { "admin-prohib",		ICMP6_DST_UNREACH_ADMIN },
+      { "address",		ICMP6_DST_UNREACH_ADDR },
+      { "port",			ICMP6_DST_UNREACH_NOPORT },
+      { NULL, 0 }
+};
+#endif
+
+static void
+fill_unreach6_code(u_short *codep, char *str)
+{
+	int val;
+	char *s;
+
+	val = strtoul(str, &s, 0);
+	if (s == str || *s != '\0' || val >= 0x100)
+		val = match_token(icmp6codes, str);
+	if (val < 0)
+		errx(EX_DATAERR, "unknown ICMPv6 unreachable code ``%s''", str);
+	*codep = val;
+	return;
+}
+
+#if 0
+static void
+print_unreach6_code(uint16_t code)
+{
+	char const *s = match_value(icmp6codes, code);
+
+	if (s != NULL)
+		printf("unreach6 %s", s);
+	else
+		printf("unreach6 %u", code);
+}
+#endif
+
+/*
+ * Returns the number of bits set (from left) in a contiguous bitmask,
+ * or -1 if the mask is not contiguous.
+ * XXX this needs a proper fix.
+ * This effectively works on masks in big-endian (network) format.
+ * when compiled on little endian architectures.
+ *
+ * First bit is bit 7 of the first byte -- note, for MAC addresses,
+ * the first bit on the wire is bit 0 of the first byte.
+ * len is the max length in bits.
+ */
+static int
+contigmask(uint8_t *p, int len)
+{
+	int i, n;
+
+	for (i=0; i<len ; i++)
+		if ( (p[i/8] & (1 << (7 - (i%8)))) == 0) /* first bit unset */
+			break;
+	for (n=i+1; n < len; n++)
+		if ( (p[n/8] & (1 << (7 - (n%8)))) != 0)
+			return -1; /* mask not contiguous */
+	return i;
+}
+
+#if 0
+/*
+ * print flags set/clear in the two bitmasks passed as parameters.
+ * There is a specialized check for f_tcpflags.
+ */
+static void
+print_flags(char const *name, ipfw_insn *cmd, struct _s_x *list)
+{
+	char const *comma = "";
+	int i;
+	uint8_t set = cmd->arg1 & 0xff;
+	uint8_t clear = (cmd->arg1 >> 8) & 0xff;
+
+	if (list == f_tcpflags && set == TH_SYN && clear == TH_ACK) {
+		printf(" setup");
+		return;
+	}
+
+	printf(" %s ", name);
+	for (i=0; list[i].x != 0; i++) {
+		if (set & list[i].x) {
+			set &= ~list[i].x;
+			printf("%s%s", comma, list[i].s);
+			comma = ",";
+		}
+		if (clear & list[i].x) {
+			clear &= ~list[i].x;
+			printf("%s!%s", comma, list[i].s);
+			comma = ",";
+		}
+	}
+}
+
+/*
+ * Print the ip address contained in a command.
+ */
+static void
+print_ip(ipfw_insn_ip *cmd, char const *s)
+{
+	struct hostent *he = NULL;
+	int len = F_LEN((ipfw_insn *)cmd);
+	uint32_t *a = ((ipfw_insn_u32 *)cmd)->d;
+
+	printf("%s%s ", cmd->o.len & F_NOT ? " not": "", s);
+
+	if (cmd->o.opcode == O_IP_SRC_ME || cmd->o.opcode == O_IP_DST_ME) {
+		printf("me");
+		return;
+	}
+	if (cmd->o.opcode == O_IP_SRC_LOOKUP ||
+	    cmd->o.opcode == O_IP_DST_LOOKUP) {
+		printf("table(%u", ((ipfw_insn *)cmd)->arg1);
+		if (len == F_INSN_SIZE(ipfw_insn_u32))
+			printf(",%u", *a);
+		printf(")");
+		return;
+	}
+	if (cmd->o.opcode == O_IP_SRC_SET || cmd->o.opcode == O_IP_DST_SET) {
+		uint32_t x, *map = (uint32_t *)&(cmd->mask);
+		int i, j;
+		char comma = '{';
+
+		x = cmd->o.arg1 - 1;
+		x = htonl( ~x );
+		cmd->addr.s_addr = htonl(cmd->addr.s_addr);
+		printf("%s/%d", inet_ntoa(cmd->addr),
+			contigmask((uint8_t *)&x, 32));
+		x = cmd->addr.s_addr = htonl(cmd->addr.s_addr);
+		x &= 0xff; /* base */
+		/*
+		 * Print bits and ranges.
+		 * Locate first bit set (i), then locate first bit unset (j).
+		 * If we have 3+ consecutive bits set, then print them as a
+		 * range, otherwise only print the initial bit and rescan.
+		 */
+		for (i=0; i < cmd->o.arg1; i++)
+			if (map[i/32] & (1<<(i & 31))) {
+				for (j=i+1; j < cmd->o.arg1; j++)
+					if (!(map[ j/32] & (1<<(j & 31))))
+						break;
+				printf("%c%d", comma, i+x);
+				if (j>i+2) { /* range has at least 3 elements */
+					printf("-%d", j-1+x);
+					i = j-1;
+				}
+				comma = ',';
+			}
+		printf("}");
+		return;
+	}
+	/*
+	 * len == 2 indicates a single IP, whereas lists of 1 or more
+	 * addr/mask pairs have len = (2n+1). We convert len to n so we
+	 * use that to count the number of entries.
+	 */
+    for (len = len / 2; len > 0; len--, a += 2) {
+	int mb =	/* mask length */
+	    (cmd->o.opcode == O_IP_SRC || cmd->o.opcode == O_IP_DST) ?
+		32 : contigmask((uint8_t *)&(a[1]), 32);
+	if (mb == 32 && do_resolv)
+		he = gethostbyaddr((char *)&(a[0]), sizeof(u_long), AF_INET);
+	if (he != NULL)		/* resolved to name */
+		printf("%s", he->h_name);
+	else if (mb == 0)	/* any */
+		printf("any");
+	else {		/* numeric IP followed by some kind of mask */
+		printf("%s", inet_ntoa( *((struct in_addr *)&a[0]) ) );
+		if (mb < 0)
+			printf(":%s", inet_ntoa( *((struct in_addr *)&a[1]) ) );
+		else if (mb < 32)
+			printf("/%d", mb);
+	}
+	if (len > 1)
+		printf(",");
+    }
+}
+
+/*
+ * prints a MAC address/mask pair
+ */
+static void
+print_mac(uint8_t *addr, uint8_t *mask)
+{
+	int l = contigmask(mask, 48);
+
+	if (l == 0)
+		printf(" any");
+	else {
+		printf(" %02x:%02x:%02x:%02x:%02x:%02x",
+		    addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
+		if (l == -1)
+			printf("&%02x:%02x:%02x:%02x:%02x:%02x",
+			    mask[0], mask[1], mask[2],
+			    mask[3], mask[4], mask[5]);
+		else if (l < 48)
+			printf("/%d", l);
+	}
+}
+#endif
+
+static void
+fill_icmptypes(ipfw_insn_u32 *cmd, char *av)
+{
+	uint8_t type;
+
+	cmd->d[0] = 0;
+	while (*av) {
+		if (*av == ',')
+			av++;
+
+		type = strtoul(av, &av, 0);
+
+		if (*av != ',' && *av != '\0')
+			errx(EX_DATAERR, "invalid ICMP type");
+
+		if (type > 31)
+			errx(EX_DATAERR, "ICMP type out of range");
+
+		cmd->d[0] |= 1 << type;
+	}
+	cmd->o.opcode = O_ICMPTYPE;

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-user mailing list