From hag@linnaean.org  Thu Feb  7 01:38:31 2013
Return-Path: <hag@linnaean.org>
Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1])
	by hub.freebsd.org (Postfix) with ESMTP id 94731A4D
	for <FreeBSD-gnats-submit@freebsd.org>; Thu,  7 Feb 2013 01:38:31 +0000 (UTC)
	(envelope-from hag@linnaean.org)
Received: from perdition.linnaean.org (perdition.linnaean.org [IPv6:2001:470:8917:1::1])
	by mx1.freebsd.org (Postfix) with ESMTP id 6CAED9AC
	for <FreeBSD-gnats-submit@freebsd.org>; Thu,  7 Feb 2013 01:38:31 +0000 (UTC)
Received: by perdition.linnaean.org (Postfix, from userid 31013)
	id A2816CEC; Wed,  6 Feb 2013 20:38:24 -0500 (EST)
Message-Id: <20130207013824.A2816CEC@perdition.linnaean.org>
Date: Wed,  6 Feb 2013 20:38:24 -0500 (EST)
From: Daniel Hagerty <hag@linnaean.org>
Reply-To: Daniel Hagerty <hag@linnaean.org>
To: FreeBSD-gnats-submit@freebsd.org
Cc:
Subject: FreeBSD 9.1 ipfw lookup dst-port regression
X-Send-Pr-Version: 3.113
X-GNATS-Notify:

>Number:         175909
>Category:       kern
>Synopsis:       [ipfw] FreeBSD 9.1 ipfw lookup dst-port regression [regression]
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    melifaro
>State:          patched
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Thu Feb 07 01:40:00 UTC 2013
>Closed-Date:    
>Last-Modified:  Thu Nov 14 23:13:41 UTC 2013
>Originator:     Daniel Hagerty
>Release:        FreeBSD 9.1-RELEASE amd64
>Organization:
I misplaced my organization
>Environment:
System: FreeBSD perdition.linnaean.org 9.1-RELEASE FreeBSD 9.1-RELEASE #0 r243710+9a57fd8: Fri Jan 25 23:38:46 EST 2013 hag@yall.linnaean.org:/sys/amd64/compile/LINNAEAN64 amd64


	
>Description:

    ipfw lookup dst-port rules don't seem to work.  Didn't test
similar cases, like src-port.

>How-To-Repeat:
    Load these ipfw rules:

table 1 add 22
add 00001 permit log ip4 from any to any proto tcp lookup dst-port 1
add 00010 permit log ip from any to any proto tcp dst-port 22

    Observe how on freebsd 9.1, rule 1 will never match port 22
traffic it should, whereas the same rules on 8.3 will hit rule 1, as
expected.

>Fix:
    I worked around it for the moment by writing the rule without a
lookup table; don't have time to kernel spelunk.
>Release-Note:
>Audit-Trail:

From: Gleb Smirnoff <glebius@FreeBSD.org>
To: Daniel Hagerty <hag@linnaean.org>
Cc: FreeBSD-gnats-submit@freebsd.org, melifaro@FreeBSD.org
Subject: Re: kern/175909: FreeBSD 9.1 ipfw lookup dst-port regression
Date: Thu, 7 Feb 2013 12:38:32 +0400

   Daniel,
 
 Can you please try whether the problem can be reproduced on stable/9
 branch prior to revision r234597?
 
 To accomplish this you need:
 
 # svn co -r r234596 http://svn.freebsd.org/base/stable/9
 # cd 9
 # make buildworld buildkernel
 # make installkernel installworld
 
 reboot
 
 -- 
 Totus tuus, Glebius.
Responsible-Changed-From-To: freebsd-bugs->melifaro 
Responsible-Changed-By: melifaro 
Responsible-Changed-When: Thu Feb 7 09:11:06 UTC 2013 
Responsible-Changed-Why:  
I can reproduce this issue on my pre-9.1 desktop. There is no need for 
doing kernel recompiling.  

http://www.freebsd.org/cgi/query-pr.cgi?pr=175909 

From: Daniel Hagerty <hag@linnaean.org>
To: Gleb Smirnoff <glebius@FreeBSD.org>
Cc: FreeBSD-gnats-submit@freebsd.org,
    melifaro@FreeBSD.org
Subject: Re: kern/175909: FreeBSD 9.1 ipfw lookup dst-port regression
Date: Fri, 8 Feb 2013 12:56:00 -0500

  > Can you please try whether the problem can be reproduced on stable/9
  > branch prior to revision r234597?
 
     Your hunch is confirmed.  234597 demonstrates the bug, 234593 (the
 preceding commit on stable/9) does not.
 
 
 234593:
 
 00001   7    388 allow log ip4 from any to any proto tcp lookup dst-port 1
 00010   0      0 allow log ip4 from any to any proto tcp dst-port 29
 
 vs 234597:
 
 00001   0     0 allow log ip4 from any to any proto tcp lookup dst-port 1
 00010   6   336 allow log ip4 from any to any proto tcp dst-port 29

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/175909: commit references a PR
Date: Sat,  2 Mar 2013 18:51:40 +0000 (UTC)

 Author: melifaro
 Date: Sat Mar  2 18:51:26 2013
 New Revision: 247666
 URL: http://svnweb.freebsd.org/changeset/base/247666
 
 Log:
   Fix ipfw table argument parsing/printing.
   Fix style.
   
   PR:		kern/175909
   Submitted by:	Daniel Hagerty <hag@linnaean.org>
   MFC after:	2 weeks
 
 Modified:
   head/sbin/ipfw/ipfw2.c
 
 Modified: head/sbin/ipfw/ipfw2.c
 ==============================================================================
 --- head/sbin/ipfw/ipfw2.c	Sat Mar  2 18:40:04 2013	(r247665)
 +++ head/sbin/ipfw/ipfw2.c	Sat Mar  2 18:51:26 2013	(r247666)
 @@ -3912,6 +3912,7 @@ ipfw_flush(int force)
  
  
  static void table_list(uint16_t num, int need_header);
 +static void table_fill_xentry(char *arg, ipfw_table_xentry *xent);
  
  /*
   * This one handles all table-related commands
 @@ -3927,8 +3928,7 @@ ipfw_table_handler(int ac, char *av[])
  	int do_add;
  	int is_all;
  	size_t len;
 -	char *p;
 -	uint32_t a, type, mask, addrlen;
 +	uint32_t a, mask;
  	uint32_t tables_max;
  
  	mask = 0;	// XXX uninitialized ?
 @@ -3965,57 +3965,8 @@ ipfw_table_handler(int ac, char *av[])
  		ac--; av++;
  		if (!ac)
  			errx(EX_USAGE, "address required");
 -		/* 
 -		 * Let's try to guess type by agrument.
 -		 * Possible types: 
 -		 * 1) IPv4[/mask]
 -		 * 2) IPv6[/mask]
 -		 * 3) interface name
 -		 * 4) port ?
 -		 */
 -		type = 0;
 -		if (ishexnumber(*av[0])) {
 -			/* Remove / if exists */
 -			if ((p = strchr(*av, '/')) != NULL) {
 -				*p = '\0';
 -				mask = atoi(p + 1);
 -			}
 -
 -			if (inet_pton(AF_INET, *av, &xent.k.addr6) == 1) {
 -				type = IPFW_TABLE_CIDR;
 -				if ((p != NULL) && (mask > 32))
 -					errx(EX_DATAERR, "bad IPv4 mask width: %s", p + 1);
 -				xent.masklen = p ? mask : 32;
 -				addrlen = sizeof(struct in_addr);
 -			} else if (inet_pton(AF_INET6, *av, &xent.k.addr6) == 1) {
 -				type = IPFW_TABLE_CIDR;
 -				if ((p != NULL) && (mask > 128))
 -					errx(EX_DATAERR, "bad IPv6 mask width: %s", p + 1);
 -				xent.masklen = p ? mask : 128;
 -				addrlen = sizeof(struct in6_addr);
 -			}
 -		}
 -
 -		if ((type == 0) && (strchr(*av, '.') == NULL)) {
 -			/* Assume interface name. Copy significant data only */
 -			mask = MIN(strlen(*av), IF_NAMESIZE - 1);
 -			memcpy(xent.k.iface, *av, mask);
 -			/* Set mask to exact match */
 -			xent.masklen = 8 * IF_NAMESIZE;
 -			type = IPFW_TABLE_INTERFACE;
 -			addrlen = IF_NAMESIZE;
 -		}
  
 -		if (type == 0) {
 -			if (lookup_host(*av, (struct in_addr *)&xent.k.addr6) != 0)
 -				errx(EX_NOHOST, "hostname ``%s'' unknown", *av);
 -			xent.masklen = 32;
 -			type = IPFW_TABLE_CIDR;
 -			addrlen = sizeof(struct in_addr);
 -		}
 -
 -		xent.type = type;
 -		xent.len = offsetof(ipfw_table_xentry, k) + addrlen;
 +		table_fill_xentry(*av, &xent);
  
  		ac--; av++;
  		if (do_add && ac) {
 @@ -4065,6 +4016,93 @@ ipfw_table_handler(int ac, char *av[])
  }
  
  static void
 +table_fill_xentry(char *arg, ipfw_table_xentry *xent)
 +{
 +	int addrlen, mask, masklen, type;
 +	struct in6_addr *paddr;
 +	uint32_t *pkey;
 +	char *p;
 +	uint32_t key;
 +
 +	mask = 0;
 +	type = 0;
 +	addrlen = 0;
 +	masklen = 0;
 +
 +	/* 
 +	 * Let's try to guess type by agrument.
 +	 * Possible types: 
 +	 * 1) IPv4[/mask]
 +	 * 2) IPv6[/mask]
 +	 * 3) interface name
 +	 * 4) port, uid/gid or other u32 key (base 10 format)
 +	 * 5) hostname
 +	 */
 +	paddr = &xent->k.addr6;
 +	if (ishexnumber(*arg) != 0 || *arg == ':') {
 +		/* Remove / if exists */
 +		if ((p = strchr(arg, '/')) != NULL) {
 +			*p = '\0';
 +			mask = atoi(p + 1);
 +		}
 +
 +		if (inet_pton(AF_INET, arg, paddr) == 1) {
 +			if (p != NULL && mask > 32)
 +				errx(EX_DATAERR, "bad IPv4 mask width: %s",
 +				    p + 1);
 +
 +			type = IPFW_TABLE_CIDR;
 +			masklen = p ? mask : 32;
 +			addrlen = sizeof(struct in_addr);
 +		} else if (inet_pton(AF_INET6, arg, paddr) == 1) {
 +			if (IN6_IS_ADDR_V4COMPAT(paddr))
 +				errx(EX_DATAERR,
 +				    "Use IPv4 instead of v4-compatible");
 +			if (p != NULL && mask > 128)
 +				errx(EX_DATAERR, "bad IPv6 mask width: %s",
 +				    p + 1);
 +
 +			type = IPFW_TABLE_CIDR;
 +			masklen = p ? mask : 128;
 +			addrlen = sizeof(struct in6_addr);
 +		} else {
 +			/* Port or any other key */
 +			key = strtol(arg, &p, 10);
 +			/* Skip non-base 10 entries like 'fa1' */
 +			if (p != arg) {
 +				pkey = (uint32_t *)paddr;
 +				*pkey = htonl(key);
 +				type = IPFW_TABLE_CIDR;
 +				addrlen = sizeof(uint32_t);
 +			}
 +		}
 +	}
 +
 +	if (type == 0 && strchr(arg, '.') == NULL) {
 +		/* Assume interface name. Copy significant data only */
 +		mask = MIN(strlen(arg), IF_NAMESIZE - 1);
 +		memcpy(xent->k.iface, arg, mask);
 +		/* Set mask to exact match */
 +		masklen = 8 * IF_NAMESIZE;
 +		type = IPFW_TABLE_INTERFACE;
 +		addrlen = IF_NAMESIZE;
 +	}
 +
 +	if (type == 0) {
 +		if (lookup_host(arg, (struct in_addr *)paddr) != 0)
 +			errx(EX_NOHOST, "hostname ``%s'' unknown", arg);
 +
 +		masklen = 32;
 +		type = IPFW_TABLE_CIDR;
 +		addrlen = sizeof(struct in_addr);
 +	}
 +
 +	xent->type = type;
 +	xent->masklen = masklen;
 +	xent->len = offsetof(ipfw_table_xentry, k) + addrlen;
 +}
 +
 +static void
  table_list(uint16_t num, int need_header)
  {
  	ipfw_xtable *tbl;
 @@ -4107,8 +4145,8 @@ table_list(uint16_t num, int need_header
  			tval = xent->value;
  			addr6 = &xent->k.addr6;
  
 -			if ((addr6->s6_addr32[0] == 0) && (addr6->s6_addr32[1] == 0) && 
 -			    (addr6->s6_addr32[2] == 0)) {
 +
 +			if (IN6_IS_ADDR_V4COMPAT(addr6)) {
  				/* IPv4 address */
  				inet_ntop(AF_INET, &addr6->s6_addr32[3], tbuf, sizeof(tbuf));
  			} else {
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 
State-Changed-From-To: open->patched 
State-Changed-By: melifaro 
State-Changed-When: Sun Mar 3 21:53:06 UTC 2013 
State-Changed-Why:  
Fixed in HEAD. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=175909 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/175909: commit references a PR
Date: Tue, 19 Mar 2013 13:29:17 +0000 (UTC)

 Author: melifaro
 Date: Tue Mar 19 13:29:01 2013
 New Revision: 248505
 URL: http://svnweb.freebsd.org/changeset/base/248505
 
 Log:
   Merge r247666, r247712, r247811.
   
   Fix ipfw table argument parsing/printing.
   Fix style.
   
   PR:		kern/175909
   Submitted by:	Daniel Hagerty <hag@linnaean.org>
   
   Implement buffer size checking in ipfw(8) add cmd.
   
   PR:		bin/65961
   Submitted by:	Eugene Grosbein <eugen@grosbein.pp.ru>
   
   Do not suddenly fail on some rulesets if -n (syntax check only) is specified
   and ipfw(4) module is not loaded.
 
 Modified:
   stable/9/sbin/ipfw/ipfw2.c
   stable/9/sbin/ipfw/ipfw2.h
   stable/9/sbin/ipfw/ipv6.c
 Directory Properties:
   stable/9/sbin/   (props changed)
   stable/9/sbin/ipfw/   (props changed)
 
 Modified: stable/9/sbin/ipfw/ipfw2.c
 ==============================================================================
 --- stable/9/sbin/ipfw/ipfw2.c	Tue Mar 19 13:21:39 2013	(r248504)
 +++ stable/9/sbin/ipfw/ipfw2.c	Tue Mar 19 13:29:01 2013	(r248505)
 @@ -64,6 +64,22 @@ int ipfw_socket = -1;
  #define s6_addr32 __u6_addr.__u6_addr32
  #endif
  
 +#define	CHECK_LENGTH(v, len) do {				\
 +	if ((v) < (len))					\
 +		errx(EX_DATAERR, "Rule too long");		\
 +	} while (0)
 +/*
 + * Check if we have enough space in cmd buffer. Note that since
 + * first 8? u32 words are reserved by reserved header, full cmd
 + * buffer can't be used, so we need to protect from buffer overrun
 + * only. At the beginnig, cblen is less than actual buffer size by
 + * size of ipfw_insn_u32 instruction + 1 u32 work. This eliminates need
 + * for checking small instructions fitting in given range.
 + * We also (ab)use the fact that ipfw_insn is always the first field
 + * for any custom instruction.
 + */
 +#define	CHECK_CMDLEN	CHECK_LENGTH(cblen, F_LEN((ipfw_insn *)cmd))
 +
  #define GET_UINT_ARG(arg, min, max, tok, s_x) do {			\
  	if (!av[0])							\
  		errx(EX_USAGE, "%s: missing argument", match_value(s_x, tok)); \
 @@ -653,7 +669,7 @@ strtoport(char *s, char **end, int base,
   * Fill the body of the command with the list of port ranges.
   */
  static int
 -fill_newports(ipfw_insn_u16 *cmd, char *av, int proto)
 +fill_newports(ipfw_insn_u16 *cmd, char *av, int proto, int cblen)
  {
  	uint16_t a, b, *p = cmd->ports;
  	int i = 0;
 @@ -664,6 +680,8 @@ fill_newports(ipfw_insn_u16 *cmd, char *
  		if (s == av) 			/* empty or invalid argument */
  			return (0);
  
 +		CHECK_LENGTH(cblen, i + 2);
 +
  		switch (*s) {
  		case '-':			/* a range */
  			av = s + 1;
 @@ -2067,7 +2085,7 @@ lookup_host (char *host, struct in_addr 
   * We can have multiple comma-separated address/mask entries.
   */
  static void
 -fill_ip(ipfw_insn_ip *cmd, char *av)
 +fill_ip(ipfw_insn_ip *cmd, char *av, int cblen)
  {
  	int len = 0;
  	uint32_t *d = ((ipfw_insn_u32 *)cmd)->d;
 @@ -2107,6 +2125,8 @@ fill_ip(ipfw_insn_ip *cmd, char *av)
  	int masklen;
  	char md, nd = '\0';
  
 +	CHECK_LENGTH(cblen, F_INSN_SIZE(ipfw_insn) + 2 + len);
 +
  	if (p) {
  		md = *p;
  		*p++ = '\0';
 @@ -2365,11 +2385,13 @@ ipfw_delete(char *av[])
   * patterns which match interfaces.
   */
  static void
 -fill_iface(ipfw_insn_if *cmd, char *arg)
 +fill_iface(ipfw_insn_if *cmd, char *arg, int cblen)
  {
  	cmd->name[0] = '\0';
  	cmd->o.len |= F_INSN_SIZE(ipfw_insn_if);
  
 +	CHECK_CMDLEN;
 +
  	/* Parse the interface or address */
  	if (strcmp(arg, "any") == 0)
  		cmd->o.len = 0;		/* effectively ignore this command */
 @@ -2440,8 +2462,10 @@ get_mac_addr_mask(const char *p, uint8_t
   * the new command in case it has been clobbered before.
   */
  static ipfw_insn *
 -next_cmd(ipfw_insn *cmd)
 +next_cmd(ipfw_insn *cmd, int *len)
  {
 +	*len -= F_LEN(cmd);
 +	CHECK_LENGTH(*len, 0);
  	cmd += F_LEN(cmd);
  	bzero(cmd, sizeof(*cmd));
  	return cmd;
 @@ -2451,7 +2475,7 @@ next_cmd(ipfw_insn *cmd)
   * Takes arguments and copies them into a comment
   */
  static void
 -fill_comment(ipfw_insn *cmd, char **av)
 +fill_comment(ipfw_insn *cmd, char **av, int cblen)
  {
  	int i, l;
  	char *p = (char *)(cmd + 1);
 @@ -2469,6 +2493,8 @@ fill_comment(ipfw_insn *cmd, char **av)
  		    "comment too long (max 80 chars)");
  	l = 1 + (l+3)/4;
  	cmd->len =  (cmd->len & (F_NOT | F_OR)) | l;
 +	CHECK_CMDLEN;
 +
  	for (i = 0; av[i] != NULL; i++) {
  		strcpy(p, av[i]);
  		p += strlen(av[i]);
 @@ -2494,7 +2520,7 @@ fill_cmd(ipfw_insn *cmd, enum ipfw_opcod
   * two microinstructions, and returns the pointer to the last one.
   */
  static ipfw_insn *
 -add_mac(ipfw_insn *cmd, char *av[])
 +add_mac(ipfw_insn *cmd, char *av[], int cblen)
  {
  	ipfw_insn_mac *mac;
  
 @@ -2503,6 +2529,7 @@ add_mac(ipfw_insn *cmd, char *av[])
  
  	cmd->opcode = O_MACADDR2;
  	cmd->len = (cmd->len & (F_NOT | F_OR)) | F_INSN_SIZE(ipfw_insn_mac);
 +	CHECK_CMDLEN;
  
  	mac = (ipfw_insn_mac *)cmd;
  	get_mac_addr_mask(av[0], mac->addr, mac->mask);	/* dst */
 @@ -2512,12 +2539,13 @@ add_mac(ipfw_insn *cmd, char *av[])
  }
  
  static ipfw_insn *
 -add_mactype(ipfw_insn *cmd, char *av)
 +add_mactype(ipfw_insn *cmd, char *av, int cblen)
  {
  	if (!av)
  		errx(EX_DATAERR, "missing MAC type");
  	if (strcmp(av, "any") != 0) { /* we have a non-null type */
 -		fill_newports((ipfw_insn_u16 *)cmd, av, IPPROTO_ETHERTYPE);
 +		fill_newports((ipfw_insn_u16 *)cmd, av, IPPROTO_ETHERTYPE,
 +		    cblen);
  		cmd->opcode = O_MAC_TYPE;
  		return cmd;
  	} else
 @@ -2586,9 +2614,9 @@ add_proto_compat(ipfw_insn *cmd, char *a
  }
  
  static ipfw_insn *
 -add_srcip(ipfw_insn *cmd, char *av)
 +add_srcip(ipfw_insn *cmd, char *av, int cblen)
  {
 -	fill_ip((ipfw_insn_ip *)cmd, av);
 +	fill_ip((ipfw_insn_ip *)cmd, av, cblen);
  	if (cmd->opcode == O_IP_DST_SET)			/* set */
  		cmd->opcode = O_IP_SRC_SET;
  	else if (cmd->opcode == O_IP_DST_LOOKUP)		/* table */
 @@ -2603,9 +2631,9 @@ add_srcip(ipfw_insn *cmd, char *av)
  }
  
  static ipfw_insn *
 -add_dstip(ipfw_insn *cmd, char *av)
 +add_dstip(ipfw_insn *cmd, char *av, int cblen)
  {
 -	fill_ip((ipfw_insn_ip *)cmd, av);
 +	fill_ip((ipfw_insn_ip *)cmd, av, cblen);
  	if (cmd->opcode == O_IP_DST_SET)			/* set */
  		;
  	else if (cmd->opcode == O_IP_DST_LOOKUP)		/* table */
 @@ -2620,12 +2648,12 @@ add_dstip(ipfw_insn *cmd, char *av)
  }
  
  static ipfw_insn *
 -add_ports(ipfw_insn *cmd, char *av, u_char proto, int opcode)
 +add_ports(ipfw_insn *cmd, char *av, u_char proto, int opcode, int cblen)
  {
  	/* XXX "any" is trapped before. Perhaps "to" */
  	if (_substrcmp(av, "any") == 0) {
  		return NULL;
 -	} else if (fill_newports((ipfw_insn_u16 *)cmd, av, proto)) {
 +	} else if (fill_newports((ipfw_insn_u16 *)cmd, av, proto, cblen)) {
  		/* XXX todo: check that we have a protocol with ports */
  		cmd->opcode = opcode;
  		return cmd;
 @@ -2634,7 +2662,7 @@ add_ports(ipfw_insn *cmd, char *av, u_ch
  }
  
  static ipfw_insn *
 -add_src(ipfw_insn *cmd, char *av, u_char proto)
 +add_src(ipfw_insn *cmd, char *av, u_char proto, int cblen)
  {
  	struct in6_addr a;
  	char *host, *ch;
 @@ -2647,11 +2675,11 @@ add_src(ipfw_insn *cmd, char *av, u_char
  
  	if (proto == IPPROTO_IPV6  || strcmp(av, "me6") == 0 ||
  	    inet_pton(AF_INET6, host, &a) == 1)
 -		ret = add_srcip6(cmd, av);
 +		ret = add_srcip6(cmd, av, cblen);
  	/* XXX: should check for IPv4, not !IPv6 */
  	if (ret == NULL && (proto == IPPROTO_IP || strcmp(av, "me") == 0 ||
  	    inet_pton(AF_INET6, host, &a) != 1))
 -		ret = add_srcip(cmd, av);
 +		ret = add_srcip(cmd, av, cblen);
  	if (ret == NULL && strcmp(av, "any") != 0)
  		ret = cmd;
  
 @@ -2660,7 +2688,7 @@ add_src(ipfw_insn *cmd, char *av, u_char
  }
  
  static ipfw_insn *
 -add_dst(ipfw_insn *cmd, char *av, u_char proto)
 +add_dst(ipfw_insn *cmd, char *av, u_char proto, int cblen)
  {
  	struct in6_addr a;
  	char *host, *ch;
 @@ -2673,11 +2701,11 @@ add_dst(ipfw_insn *cmd, char *av, u_char
  
  	if (proto == IPPROTO_IPV6  || strcmp(av, "me6") == 0 ||
  	    inet_pton(AF_INET6, host, &a) == 1)
 -		ret = add_dstip6(cmd, av);
 +		ret = add_dstip6(cmd, av, cblen);
  	/* XXX: should check for IPv4, not !IPv6 */
  	if (ret == NULL && (proto == IPPROTO_IP || strcmp(av, "me") == 0 ||
  	    inet_pton(AF_INET6, host, &a) != 1))
 -		ret = add_dstip(cmd, av);
 +		ret = add_dstip(cmd, av, cblen);
  	if (ret == NULL && strcmp(av, "any") != 0)
  		ret = cmd;
  
 @@ -2707,6 +2735,7 @@ ipfw_add(char *av[])
  	 * go into actbuf[].
  	 */
  	static uint32_t rulebuf[255], actbuf[255], cmdbuf[255];
 +	int rblen, ablen, cblen;
  
  	ipfw_insn *src, *dst, *cmd, *action, *prev=NULL;
  	ipfw_insn *first_cmd;	/* first match pattern */
 @@ -2737,6 +2766,15 @@ ipfw_add(char *av[])
  	cmd = (ipfw_insn *)cmdbuf;
  	action = (ipfw_insn *)actbuf;
  
 +	rblen = sizeof(rulebuf) / sizeof(rulebuf[0]);
 +	rblen -= offsetof(struct ip_fw, cmd) / sizeof(rulebuf[0]);
 +	ablen = sizeof(actbuf) / sizeof(actbuf[0]);
 +	cblen = sizeof(cmdbuf) / sizeof(cmdbuf[0]);
 +	cblen -= F_INSN_SIZE(ipfw_insn_u32) + 1;
 +
 +#define	CHECK_RBUFLEN(len)	{ CHECK_LENGTH(rblen, len); rblen -= len; }
 +#define	CHECK_ACTLEN		CHECK_LENGTH(ablen, action->len)
 +
  	av++;
  
  	/* [rule N]	-- Rule number optional */
 @@ -2768,6 +2806,7 @@ ipfw_add(char *av[])
  	i = match_token(rule_actions, *av);
  	av++;
  	action->len = 1;	/* default */
 +	CHECK_ACTLEN;
  	switch(i) {
  	case TOK_CHECKSTATE:
  		have_state = action;
 @@ -2819,6 +2858,7 @@ ipfw_add(char *av[])
  	case TOK_NAT:
  		action->opcode = O_NAT;
  		action->len = F_INSN_SIZE(ipfw_insn_nat);
 +		CHECK_ACTLEN;
  		if (_substrcmp(*av, "global") == 0) {
  			action->arg1 = 0;
  			av++;
 @@ -2935,6 +2975,7 @@ chkarg:
  
  			action->opcode = O_FORWARD_IP;
  			action->len = F_INSN_SIZE(ipfw_insn_sa);
 +			CHECK_ACTLEN;
  
  			/*
  			 * In the kernel we assume AF_INET and use only
 @@ -2951,6 +2992,7 @@ chkarg:
  
  			action->opcode = O_FORWARD_IP6;
  			action->len = F_INSN_SIZE(ipfw_insn_sa6);
 +			CHECK_ACTLEN;
  
  			p->sa.sin6_len = sizeof(struct sockaddr_in6);
  			p->sa.sin6_family = AF_INET6;
 @@ -3004,7 +3046,7 @@ chkarg:
  	default:
  		errx(EX_DATAERR, "invalid action %s\n", av[-1]);
  	}
 -	action = next_cmd(action);
 +	action = next_cmd(action, &ablen);
  
  	/*
  	 * [altq queuename] -- altq tag, optional
 @@ -3026,6 +3068,7 @@ chkarg:
  				    "log cannot be specified more than once");
  			have_log = (ipfw_insn *)c;
  			cmd->len = F_INSN_SIZE(ipfw_insn_log);
 +			CHECK_CMDLEN;
  			cmd->opcode = O_LOG;
  			if (av[0] && _substrcmp(*av, "logamount") == 0) {
  				av++;
 @@ -3039,9 +3082,14 @@ chkarg:
  			} else {
  				len = sizeof(c->max_log);
  				if (sysctlbyname("net.inet.ip.fw.verbose_limit",
 -				    &c->max_log, &len, NULL, 0) == -1)
 +				    &c->max_log, &len, NULL, 0) == -1) {
 +					if (co.test_only) {
 +						c->max_log = 0;
 +						break;
 +					}
  					errx(1, "sysctlbyname(\"%s\")",
  					    "net.inet.ip.fw.verbose_limit");
 +				}
  			}
  		    }
  			break;
 @@ -3057,6 +3105,7 @@ chkarg:
  				    "altq cannot be specified more than once");
  			have_altq = (ipfw_insn *)a;
  			cmd->len = F_INSN_SIZE(ipfw_insn_altq);
 +			CHECK_CMDLEN;
  			cmd->opcode = O_ALTQ;
  			a->qid = altq_name_to_qid(*av);
  			av++;
 @@ -3082,7 +3131,7 @@ chkarg:
  		default:
  			abort();
  		}
 -		cmd = next_cmd(cmd);
 +		cmd = next_cmd(cmd, &cblen);
  	}
  
  	if (have_state)	/* must be a check-state, we are done */
 @@ -3167,7 +3216,7 @@ chkarg:
  		av++;
  		if (F_LEN(cmd) != 0) {
  			prev = cmd;
 -			cmd = next_cmd(cmd);
 +			cmd = next_cmd(cmd, &cblen);
  		}
  	} else if (first_cmd != cmd) {
  		errx(EX_DATAERR, "invalid protocol ``%s''", *av);
 @@ -3188,11 +3237,11 @@ chkarg:
      OR_START(source_ip);
  	NOT_BLOCK;	/* optional "not" */
  	NEED1("missing source address");
 -	if (add_src(cmd, *av, proto)) {
 +	if (add_src(cmd, *av, proto, cblen)) {
  		av++;
  		if (F_LEN(cmd) != 0) {	/* ! any */
  			prev = cmd;
 -			cmd = next_cmd(cmd);
 +			cmd = next_cmd(cmd, &cblen);
  		}
  	} else
  		errx(EX_USAGE, "bad source address %s", *av);
 @@ -3204,10 +3253,10 @@ chkarg:
  	NOT_BLOCK;	/* optional "not" */
  	if ( av[0] != NULL ) {
  		if (_substrcmp(*av, "any") == 0 ||
 -		    add_ports(cmd, *av, proto, O_IP_SRCPORT)) {
 +		    add_ports(cmd, *av, proto, O_IP_SRCPORT, cblen)) {
  			av++;
  			if (F_LEN(cmd) != 0)
 -				cmd = next_cmd(cmd);
 +				cmd = next_cmd(cmd, &cblen);
  		}
  	}
  
 @@ -3224,11 +3273,11 @@ chkarg:
      OR_START(dest_ip);
  	NOT_BLOCK;	/* optional "not" */
  	NEED1("missing dst address");
 -	if (add_dst(cmd, *av, proto)) {
 +	if (add_dst(cmd, *av, proto, cblen)) {
  		av++;
  		if (F_LEN(cmd) != 0) {	/* ! any */
  			prev = cmd;
 -			cmd = next_cmd(cmd);
 +			cmd = next_cmd(cmd, &cblen);
  		}
  	} else
  		errx( EX_USAGE, "bad destination address %s", *av);
 @@ -3240,10 +3289,10 @@ chkarg:
  	NOT_BLOCK;	/* optional "not" */
  	if (av[0]) {
  		if (_substrcmp(*av, "any") == 0 ||
 -		    add_ports(cmd, *av, proto, O_IP_DSTPORT)) {
 +		    add_ports(cmd, *av, proto, O_IP_DSTPORT, cblen)) {
  			av++;
  			if (F_LEN(cmd) != 0)
 -				cmd = next_cmd(cmd);
 +				cmd = next_cmd(cmd, &cblen);
  		}
  	}
  
 @@ -3331,7 +3380,7 @@ read_options:
  		case TOK_VIA:
  			NEED1("recv, xmit, via require interface name"
  				" or address");
 -			fill_iface((ipfw_insn_if *)cmd, av[0]);
 +			fill_iface((ipfw_insn_if *)cmd, av[0], cblen);
  			av++;
  			if (F_LEN(cmd) == 0)	/* not a valid address */
  				break;
 @@ -3351,14 +3400,14 @@ read_options:
  
  		case TOK_ICMP6TYPES:
  			NEED1("icmptypes requires list of types");
 -			fill_icmp6types((ipfw_insn_icmp6 *)cmd, *av);
 +			fill_icmp6types((ipfw_insn_icmp6 *)cmd, *av, cblen);
  			av++;
  			break;
  
  		case TOK_IPTTL:
  			NEED1("ipttl requires TTL");
  			if (strpbrk(*av, "-,")) {
 -			    if (!add_ports(cmd, *av, 0, O_IPTTL))
 +			    if (!add_ports(cmd, *av, 0, O_IPTTL, cblen))
  				errx(EX_DATAERR, "invalid ipttl %s", *av);
  			} else
  			    fill_cmd(cmd, O_IPTTL, 0, strtoul(*av, NULL, 0));
 @@ -3368,7 +3417,7 @@ read_options:
  		case TOK_IPID:
  			NEED1("ipid requires id");
  			if (strpbrk(*av, "-,")) {
 -			    if (!add_ports(cmd, *av, 0, O_IPID))
 +			    if (!add_ports(cmd, *av, 0, O_IPID, cblen))
  				errx(EX_DATAERR, "invalid ipid %s", *av);
  			} else
  			    fill_cmd(cmd, O_IPID, 0, strtoul(*av, NULL, 0));
 @@ -3378,7 +3427,7 @@ read_options:
  		case TOK_IPLEN:
  			NEED1("iplen requires length");
  			if (strpbrk(*av, "-,")) {
 -			    if (!add_ports(cmd, *av, 0, O_IPLEN))
 +			    if (!add_ports(cmd, *av, 0, O_IPLEN, cblen))
  				errx(EX_DATAERR, "invalid ip len %s", *av);
  			} else
  			    fill_cmd(cmd, O_IPLEN, 0, strtoul(*av, NULL, 0));
 @@ -3474,7 +3523,7 @@ read_options:
  		case TOK_TCPDATALEN:
  			NEED1("tcpdatalen requires length");
  			if (strpbrk(*av, "-,")) {
 -			    if (!add_ports(cmd, *av, 0, O_TCPDATALEN))
 +			    if (!add_ports(cmd, *av, 0, O_TCPDATALEN, cblen))
  				errx(EX_DATAERR, "invalid tcpdata len %s", *av);
  			} else
  			    fill_cmd(cmd, O_TCPDATALEN, 0,
 @@ -3500,7 +3549,7 @@ read_options:
  		case TOK_TCPWIN:
  			NEED1("tcpwin requires length");
  			if (strpbrk(*av, "-,")) {
 -			    if (!add_ports(cmd, *av, 0, O_TCPWIN))
 +			    if (!add_ports(cmd, *av, 0, O_TCPWIN, cblen))
  				errx(EX_DATAERR, "invalid tcpwin len %s", *av);
  			} else
  			    fill_cmd(cmd, O_TCPWIN, 0,
 @@ -3539,6 +3588,7 @@ read_options:
  			have_state = cmd;
  
  			cmd->len = F_INSN_SIZE(ipfw_insn_limit);
 +			CHECK_CMDLEN;
  			cmd->opcode = O_LIMIT;
  			c->limit_mask = c->conn_limit = 0;
  
 @@ -3570,28 +3620,28 @@ read_options:
  
  		case TOK_SRCIP:
  			NEED1("missing source IP");
 -			if (add_srcip(cmd, *av)) {
 +			if (add_srcip(cmd, *av, cblen)) {
  				av++;
  			}
  			break;
  
  		case TOK_DSTIP:
  			NEED1("missing destination IP");
 -			if (add_dstip(cmd, *av)) {
 +			if (add_dstip(cmd, *av, cblen)) {
  				av++;
  			}
  			break;
  
  		case TOK_SRCIP6:
  			NEED1("missing source IP6");
 -			if (add_srcip6(cmd, *av)) {
 +			if (add_srcip6(cmd, *av, cblen)) {
  				av++;
  			}
  			break;
  
  		case TOK_DSTIP6:
  			NEED1("missing destination IP6");
 -			if (add_dstip6(cmd, *av)) {
 +			if (add_dstip6(cmd, *av, cblen)) {
  				av++;
  			}
  			break;
 @@ -3599,7 +3649,7 @@ read_options:
  		case TOK_SRCPORT:
  			NEED1("missing source port");
  			if (_substrcmp(*av, "any") == 0 ||
 -			    add_ports(cmd, *av, proto, O_IP_SRCPORT)) {
 +			    add_ports(cmd, *av, proto, O_IP_SRCPORT, cblen)) {
  				av++;
  			} else
  				errx(EX_DATAERR, "invalid source port %s", *av);
 @@ -3608,7 +3658,7 @@ read_options:
  		case TOK_DSTPORT:
  			NEED1("missing destination port");
  			if (_substrcmp(*av, "any") == 0 ||
 -			    add_ports(cmd, *av, proto, O_IP_DSTPORT)) {
 +			    add_ports(cmd, *av, proto, O_IP_DSTPORT, cblen)) {
  				av++;
  			} else
  				errx(EX_DATAERR, "invalid destination port %s",
 @@ -3616,13 +3666,13 @@ read_options:
  			break;
  
  		case TOK_MAC:
 -			if (add_mac(cmd, av))
 +			if (add_mac(cmd, av, cblen))
  				av += 2;
  			break;
  
  		case TOK_MACTYPE:
  			NEED1("missing mac type");
 -			if (!add_mactype(cmd, *av))
 +			if (!add_mactype(cmd, *av, cblen))
  				errx(EX_DATAERR, "invalid mac type %s", *av);
  			av++;
  			break;
 @@ -3660,18 +3710,18 @@ read_options:
  			if (proto != IPPROTO_IPV6 )
  				errx( EX_USAGE, "flow-id filter is active "
  				    "only for ipv6 protocol\n");
 -			fill_flow6( (ipfw_insn_u32 *) cmd, *av );
 +			fill_flow6( (ipfw_insn_u32 *) cmd, *av, cblen);
  			av++;
  			break;
  
  		case TOK_COMMENT:
 -			fill_comment(cmd, av);
 +			fill_comment(cmd, av, cblen);
  			av[0]=NULL;
  			break;
  
  		case TOK_TAGGED:
  			if (av[0] && strpbrk(*av, "-,")) {
 -				if (!add_ports(cmd, *av, 0, O_TAGGED))
 +				if (!add_ports(cmd, *av, 0, O_TAGGED, cblen))
  					errx(EX_DATAERR, "tagged: invalid tag"
  					    " list: %s", *av);
  			}
 @@ -3724,7 +3774,7 @@ read_options:
  		}
  		if (F_LEN(cmd) > 0) {	/* prepare to advance */
  			prev = cmd;
 -			cmd = next_cmd(cmd);
 +			cmd = next_cmd(cmd, &cblen);
  		}
  	}
  
 @@ -3753,12 +3803,13 @@ done:
  	 */
  	if (have_state && have_state->opcode != O_CHECK_STATE) {
  		fill_cmd(dst, O_PROBE_STATE, 0, 0);
 -		dst = next_cmd(dst);
 +		dst = next_cmd(dst, &rblen);
  	}
  
  	/* copy all commands but O_LOG, O_KEEP_STATE, O_LIMIT, O_ALTQ, O_TAG */
  	for (src = (ipfw_insn *)cmdbuf; src != cmd; src += i) {
  		i = F_LEN(src);
 +		CHECK_RBUFLEN(i);
  
  		switch (src->opcode) {
  		case O_LOG:
 @@ -3778,6 +3829,7 @@ done:
  	 */
  	if (have_state && have_state->opcode != O_CHECK_STATE) {
  		i = F_LEN(have_state);
 +		CHECK_RBUFLEN(i);
  		bcopy(have_state, dst, i * sizeof(uint32_t));
  		dst += i;
  	}
 @@ -3789,24 +3841,29 @@ done:
  	/* put back O_LOG, O_ALTQ, O_TAG if necessary */
  	if (have_log) {
  		i = F_LEN(have_log);
 +		CHECK_RBUFLEN(i);
  		bcopy(have_log, dst, i * sizeof(uint32_t));
  		dst += i;
  	}
  	if (have_altq) {
  		i = F_LEN(have_altq);
 +		CHECK_RBUFLEN(i);
  		bcopy(have_altq, dst, i * sizeof(uint32_t));
  		dst += i;
  	}
  	if (have_tag) {
  		i = F_LEN(have_tag);
 +		CHECK_RBUFLEN(i);
  		bcopy(have_tag, dst, i * sizeof(uint32_t));
  		dst += i;
  	}
 +
  	/*
  	 * copy all other actions
  	 */
  	for (src = (ipfw_insn *)actbuf; src != action; src += i) {
  		i = F_LEN(src);
 +		CHECK_RBUFLEN(i);
  		bcopy(src, dst, i * sizeof(uint32_t));
  		dst += i;
  	}
 @@ -3911,6 +3968,7 @@ ipfw_flush(int force)
  
  
  static void table_list(uint16_t num, int need_header);
 +static void table_fill_xentry(char *arg, ipfw_table_xentry *xent);
  
  /*
   * This one handles all table-related commands
 @@ -3926,15 +3984,18 @@ ipfw_table_handler(int ac, char *av[])
  	int do_add;
  	int is_all;
  	size_t len;
 -	char *p;
 -	uint32_t a, type, mask, addrlen;
 +	uint32_t a;
  	uint32_t tables_max;
  
  	len = sizeof(tables_max);
  	if (sysctlbyname("net.inet.ip.fw.tables_max", &tables_max, &len,
 -		NULL, 0) == -1)
 -		errx(1, "Can't determine maximum number of ipfw tables. "
 -		    "Perhaps you forgot to load ipfw module?");
 +	    NULL, 0) == -1) {
 +		if (co.test_only)
 +			tables_max = 128; /* Old conservative default */
 +		else
 +			errx(1, "Can't determine maximum number of ipfw tables."
 +			    " Perhaps you forgot to load ipfw module?");
 +	}
  
  	memset(&xent, 0, sizeof(xent));
  
 @@ -3963,57 +4024,8 @@ ipfw_table_handler(int ac, char *av[])
  		ac--; av++;
  		if (!ac)
  			errx(EX_USAGE, "address required");
 -		/* 
 -		 * Let's try to guess type by agrument.
 -		 * Possible types: 
 -		 * 1) IPv4[/mask]
 -		 * 2) IPv6[/mask]
 -		 * 3) interface name
 -		 * 4) port ?
 -		 */
 -		type = 0;
 -		if (ishexnumber(*av[0])) {
 -			/* Remove / if exists */
 -			if ((p = strchr(*av, '/')) != NULL) {
 -				*p = '\0';
 -				mask = atoi(p + 1);
 -			}
 -
 -			if (inet_pton(AF_INET, *av, &xent.k.addr6) == 1) {
 -				type = IPFW_TABLE_CIDR;
 -				if ((p != NULL) && (mask > 32))
 -					errx(EX_DATAERR, "bad IPv4 mask width: %s", p + 1);
 -				xent.masklen = p ? mask : 32;
 -				addrlen = sizeof(struct in_addr);
 -			} else if (inet_pton(AF_INET6, *av, &xent.k.addr6) == 1) {
 -				type = IPFW_TABLE_CIDR;
 -				if ((p != NULL) && (mask > 128))
 -					errx(EX_DATAERR, "bad IPv6 mask width: %s", p + 1);
 -				xent.masklen = p ? mask : 128;
 -				addrlen = sizeof(struct in6_addr);
 -			}
 -		}
  
 -		if ((type == 0) && (strchr(*av, '.') == NULL)) {
 -			/* Assume interface name. Copy significant data only */
 -			mask = MIN(strlen(*av), IF_NAMESIZE - 1);
 -			memcpy(xent.k.iface, *av, mask);
 -			/* Set mask to exact match */
 -			xent.masklen = 8 * IF_NAMESIZE;
 -			type = IPFW_TABLE_INTERFACE;
 -			addrlen = IF_NAMESIZE;
 -		}
 -
 -		if (type == 0) {
 -			if (lookup_host(*av, (struct in_addr *)&xent.k.addr6) != 0)
 -				errx(EX_NOHOST, "hostname ``%s'' unknown", *av);
 -			xent.masklen = 32;
 -			type = IPFW_TABLE_CIDR;
 -			addrlen = sizeof(struct in_addr);
 -		}
 -
 -		xent.type = type;
 -		xent.len = offsetof(ipfw_table_xentry, k) + addrlen;
 +		table_fill_xentry(*av, &xent);
  
  		ac--; av++;
  		if (do_add && ac) {
 @@ -4063,6 +4075,93 @@ ipfw_table_handler(int ac, char *av[])
  }
  
  static void
 +table_fill_xentry(char *arg, ipfw_table_xentry *xent)
 +{
 +	int addrlen, mask, masklen, type;
 +	struct in6_addr *paddr;
 +	uint32_t *pkey;
 +	char *p;
 +	uint32_t key;
 +
 +	mask = 0;
 +	type = 0;
 +	addrlen = 0;
 +	masklen = 0;
 +
 +	/* 
 +	 * Let's try to guess type by agrument.
 +	 * Possible types: 
 +	 * 1) IPv4[/mask]
 +	 * 2) IPv6[/mask]
 +	 * 3) interface name
 +	 * 4) port, uid/gid or other u32 key (base 10 format)
 +	 * 5) hostname
 +	 */
 +	paddr = &xent->k.addr6;
 +	if (ishexnumber(*arg) != 0 || *arg == ':') {
 +		/* Remove / if exists */
 +		if ((p = strchr(arg, '/')) != NULL) {
 +			*p = '\0';
 +			mask = atoi(p + 1);
 +		}
 +
 +		if (inet_pton(AF_INET, arg, paddr) == 1) {
 +			if (p != NULL && mask > 32)
 +				errx(EX_DATAERR, "bad IPv4 mask width: %s",
 +				    p + 1);
 +
 +			type = IPFW_TABLE_CIDR;
 +			masklen = p ? mask : 32;
 +			addrlen = sizeof(struct in_addr);
 +		} else if (inet_pton(AF_INET6, arg, paddr) == 1) {
 +			if (IN6_IS_ADDR_V4COMPAT(paddr))
 +				errx(EX_DATAERR,
 +				    "Use IPv4 instead of v4-compatible");
 +			if (p != NULL && mask > 128)
 +				errx(EX_DATAERR, "bad IPv6 mask width: %s",
 +				    p + 1);
 +
 +			type = IPFW_TABLE_CIDR;
 +			masklen = p ? mask : 128;
 +			addrlen = sizeof(struct in6_addr);
 +		} else {
 +			/* Port or any other key */
 +			key = strtol(arg, &p, 10);
 +			/* Skip non-base 10 entries like 'fa1' */
 +			if (p != arg) {
 +				pkey = (uint32_t *)paddr;
 +				*pkey = htonl(key);
 +				type = IPFW_TABLE_CIDR;
 +				addrlen = sizeof(uint32_t);
 +			}
 +		}
 +	}
 +
 +	if (type == 0 && strchr(arg, '.') == NULL) {
 +		/* Assume interface name. Copy significant data only */
 +		mask = MIN(strlen(arg), IF_NAMESIZE - 1);
 +		memcpy(xent->k.iface, arg, mask);
 +		/* Set mask to exact match */
 +		masklen = 8 * IF_NAMESIZE;
 +		type = IPFW_TABLE_INTERFACE;
 +		addrlen = IF_NAMESIZE;
 +	}
 +
 +	if (type == 0) {
 +		if (lookup_host(arg, (struct in_addr *)paddr) != 0)
 +			errx(EX_NOHOST, "hostname ``%s'' unknown", arg);
 +
 +		masklen = 32;
 +		type = IPFW_TABLE_CIDR;
 +		addrlen = sizeof(struct in_addr);
 +	}
 +
 +	xent->type = type;
 +	xent->masklen = masklen;
 +	xent->len = offsetof(ipfw_table_xentry, k) + addrlen;
 +}
 +
 +static void
  table_list(uint16_t num, int need_header)
  {
  	ipfw_xtable *tbl;
 @@ -4105,8 +4204,8 @@ table_list(uint16_t num, int need_header
  			tval = xent->value;
  			addr6 = &xent->k.addr6;
  
 -			if ((addr6->s6_addr32[0] == 0) && (addr6->s6_addr32[1] == 0) && 
 -			    (addr6->s6_addr32[2] == 0)) {
 +
 +			if (IN6_IS_ADDR_V4COMPAT(addr6)) {
  				/* IPv4 address */
  				inet_ntop(AF_INET, &addr6->s6_addr32[3], tbuf, sizeof(tbuf));
  			} else {
 
 Modified: stable/9/sbin/ipfw/ipfw2.h
 ==============================================================================
 --- stable/9/sbin/ipfw/ipfw2.h	Tue Mar 19 13:21:39 2013	(r248504)
 +++ stable/9/sbin/ipfw/ipfw2.h	Tue Mar 19 13:29:01 2013	(r248505)
 @@ -283,10 +283,10 @@ void print_flow6id(struct _ipfw_insn_u32
  void print_icmp6types(struct _ipfw_insn_u32 *cmd);
  void print_ext6hdr(struct _ipfw_insn *cmd );
  
 -struct _ipfw_insn *add_srcip6(struct _ipfw_insn *cmd, char *av);
 -struct _ipfw_insn *add_dstip6(struct _ipfw_insn *cmd, char *av);
 +struct _ipfw_insn *add_srcip6(struct _ipfw_insn *cmd, char *av, int cblen);
 +struct _ipfw_insn *add_dstip6(struct _ipfw_insn *cmd, char *av, int cblen);
  
 -void fill_flow6(struct _ipfw_insn_u32 *cmd, char *av );
 +void fill_flow6(struct _ipfw_insn_u32 *cmd, char *av, int cblen);
  void fill_unreach6_code(u_short *codep, char *str);
 -void fill_icmp6types(struct _ipfw_insn_icmp6 *cmd, char *av);
 +void fill_icmp6types(struct _ipfw_insn_icmp6 *cmd, char *av, int cblen);
  int fill_ext6hdr(struct _ipfw_insn *cmd, char *av);
 
 Modified: stable/9/sbin/ipfw/ipv6.c
 ==============================================================================
 --- stable/9/sbin/ipfw/ipv6.c	Tue Mar 19 13:21:39 2013	(r248504)
 +++ stable/9/sbin/ipfw/ipv6.c	Tue Mar 19 13:29:01 2013	(r248505)
 @@ -42,6 +42,11 @@
  #include <netinet/ip_fw.h>
  #include <arpa/inet.h>
  
 +#define	CHECK_LENGTH(v, len) do {			\
 +	if ((v) < (len))				\
 +		errx(EX_DATAERR, "Rule too long");	\
 +	} while (0)
 +
  static struct _s_x icmp6codes[] = {
        { "no-route",		ICMP6_DST_UNREACH_NOROUTE },
        { "admin-prohib",		ICMP6_DST_UNREACH_ADMIN },
 @@ -131,10 +136,12 @@ print_ip6(ipfw_insn_ip6 *cmd, char const
  }
  
  void
 -fill_icmp6types(ipfw_insn_icmp6 *cmd, char *av)
 +fill_icmp6types(ipfw_insn_icmp6 *cmd, char *av, int cblen)
  {
         uint8_t type;
  
 +       CHECK_LENGTH(cblen, F_INSN_SIZE(ipfw_insn_icmp6));
 +
         bzero(cmd, sizeof(*cmd));
         while (*av) {
  	   if (*av == ',')
 @@ -327,7 +334,7 @@ lookup_host6 (char *host, struct in6_add
   * Return 1 on success, 0 on failure.
   */
  static int
 -fill_ip6(ipfw_insn_ip6 *cmd, char *av)
 +fill_ip6(ipfw_insn_ip6 *cmd, char *av, int cblen)
  {
  	int len = 0;
  	struct in6_addr *d = &(cmd->addr6);
 @@ -379,6 +386,8 @@ fill_ip6(ipfw_insn_ip6 *cmd, char *av)
  		int masklen;
  		char md = '\0';
  
 +		CHECK_LENGTH(cblen, 1 + len + 2 * F_INSN_SIZE(struct in6_addr));
 +
  		if ((p = strpbrk(av, "/,")) ) {
  			md = *p;	/* save the separator */
  			*p = '\0';	/* terminate address string */
 @@ -453,7 +462,7 @@ fill_ip6(ipfw_insn_ip6 *cmd, char *av)
   * additional flow-id we want to filter, the basic is 1
   */
  void
 -fill_flow6( ipfw_insn_u32 *cmd, char *av )
 +fill_flow6( ipfw_insn_u32 *cmd, char *av, int cblen)
  {
  	u_int32_t type;	 /* Current flow number */
  	u_int16_t nflow = 0;    /* Current flow index */
 @@ -461,6 +470,8 @@ fill_flow6( ipfw_insn_u32 *cmd, char *av
  	cmd->d[0] = 0;	  /* Initializing the base number*/
  
  	while (s) {
 +		CHECK_LENGTH(cblen, F_INSN_SIZE(ipfw_insn_u32) + nflow + 1);
 +
  		av = strsep( &s, ",") ;
  		type = strtoul(av, &av, 0);
  		if (*av != ',' && *av != '\0')
 @@ -481,10 +492,10 @@ fill_flow6( ipfw_insn_u32 *cmd, char *av
  }
  
  ipfw_insn *
 -add_srcip6(ipfw_insn *cmd, char *av)
 +add_srcip6(ipfw_insn *cmd, char *av, int cblen)
  {
  
 -	fill_ip6((ipfw_insn_ip6 *)cmd, av);
 +	fill_ip6((ipfw_insn_ip6 *)cmd, av, cblen);
  	if (cmd->opcode == O_IP_DST_SET)			/* set */
  		cmd->opcode = O_IP_SRC_SET;
  	else if (cmd->opcode == O_IP_DST_LOOKUP)		/* table */
 @@ -503,10 +514,10 @@ add_srcip6(ipfw_insn *cmd, char *av)
  }
  
  ipfw_insn *
 -add_dstip6(ipfw_insn *cmd, char *av)
 +add_dstip6(ipfw_insn *cmd, char *av, int cblen)
  {
  
 -	fill_ip6((ipfw_insn_ip6 *)cmd, av);
 +	fill_ip6((ipfw_insn_ip6 *)cmd, av, cblen);
  	if (cmd->opcode == O_IP_DST_SET)			/* set */
  		;
  	else if (cmd->opcode == O_IP_DST_LOOKUP)		/* table */
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 

From: Nick Hibma <nick@anywi.com>
To: bug-followup@FreeBSD.org,
 hag@linnaean.org
Cc:  
Subject: Re: kern/175909: [ipfw] FreeBSD 9.1 ipfw lookup dst-port regression [regression]
Date: Fri, 15 Nov 2013 00:00:43 +0100

 I don't see how table_fill_xentry can ever produce an entry containing a port.

 netinet/ip_fw.h:

 #define IPFW_TABLE_CIDR 1 /* Table for holding IPv4/IPv6 prefixes */
 #define IPFW_TABLE_INTERFACE 2 /* Table for holding interface names */
 #define IPFW_TABLE_MAXTYPE 2 /* Maximum valid number */

 Up to FreeBSD 10 this seems to be the only two types allowed. I don't see how
 port lookups could ever work in this case:
 
 # ipfw table all flush
 # ipfw table 50 add 1.2.3.4/15
 # ipfw table 51 add smtp
 # ipfw table 52 add 25
 # ipfw table 53 add ue0
 # ipfw table 54 add %ue0
 # ipfw table all list
 table(50)
 1.2.0.0/15 0
 table(51)
 smtp 0 
 table(52)
 ::/0 0 
 table(53)
 ue0 0 
 table(54)
 %ue0 0
 
 I guess the strings are considered network interfaces. I would have expected
 port numbers to be converted to integers before going into the kernel.
 
 Regards,
 
 Nick Hibma
 AnyWi Technologies

>Unformatted:
