Pull up following revision(s) (requested by rmind in ticket #736): netbsd-6
authorriz <riz@NetBSD.org>
Tue, 11 Dec 2012 04:31:52 +0000
branchnetbsd-6
changeset 256437 f14ef2080bb5
parent 256436 7af01dc581e7
child 256438 0c31ed7eb88e
Pull up following revision(s) (requested by rmind in ticket #736): usr.sbin/npf/npfctl/npf_parse.y: revision 1.17 sys/net/npf/npf_tableset.c: revision 1.16 usr.sbin/npf/npfctl/npfctl.h: revision 1.23 usr.sbin/npf/npfctl/npf_data.c: revision 1.19 usr.sbin/npf/npfctl/npf_build.c: revision 1.15 share/examples/npf/host-npf.conf: revision 1.3 usr.sbin/npf/npfctl/npf_scan.l: revision 1.9 share/examples/npf/soho_gw-npf.conf: revision 1.3 usr.sbin/npf/npfctl/npf_var.h: revision 1.6 usr.sbin/npf/npfctl/npf.conf.5: revision 1.24 npfctl: extend syntax for extracting interface IP address(es) by the family. adjust to current npf.conf syntax npf_table_list: avoid triggering assert on diagnostic.
share/examples/npf/host-npf.conf
share/examples/npf/soho_gw-npf.conf
sys/net/npf/npf_tableset.c
usr.sbin/npf/npfctl/npf.conf.5
usr.sbin/npf/npfctl/npf_build.c
usr.sbin/npf/npfctl/npf_data.c
usr.sbin/npf/npfctl/npf_parse.y
usr.sbin/npf/npfctl/npf_scan.l
usr.sbin/npf/npfctl/npf_var.h
usr.sbin/npf/npfctl/npfctl.h
--- a/share/examples/npf/host-npf.conf	Tue Dec 11 04:26:26 2012 +0000
+++ b/share/examples/npf/host-npf.conf	Tue Dec 11 04:31:52 2012 +0000
@@ -1,4 +1,4 @@
-# $NetBSD: host-npf.conf,v 1.2.4.2 2012/10/01 20:15:34 riz Exp $
+# $NetBSD: host-npf.conf,v 1.2.4.3 2012/12/11 04:31:53 riz Exp $
 #
 # this is an example of NPF rules for a host (i.e., not routing) with
 # two network interfaces, wired and wifi
@@ -7,7 +7,12 @@
 # it also does IPSEC on the wifi
 #
 $wired_if = "wm0"
+$wired_v4 = { inet4(wm0) }
+$wired_v6 = { inet6(wm0) }
+
 $wifi_if = "iwn0"
+$wifi_v4 = { inet4(iwn0) }
+$wifi_v6 = { inet6(iwn0) }
 
 $dhcpserver = { 198.51.100.1 }
 
@@ -37,38 +42,38 @@
 	pass in  final family inet  proto icmp      all
 
 	pass in  final family inet proto tcp \
-		from $dhcpserver port bootps to $wired_if port bootpc
+		from $dhcpserver port bootps to $wired_v4 port bootpc
 	pass in  final family inet proto udp \
-		from $dhcpserver port bootps to $wired_if port bootpc
+		from $dhcpserver port bootps to $wired_v4 port bootpc
 
-	pass in final family inet6 proto tcp to $wired_if port ssh
+	pass in final family inet6 proto tcp to $wired_v6 port ssh
 
 	pass in final family inet  proto tcp flags S/SA \
-		from $backupsrv_v4 to $wired_if port $backup_port 
+		from $backupsrv_v4 to $wired_v4 port $backup_port 
 	pass in final family inet  proto udp \
-		from $backupsrv_v4 to $wired_if port $backup_port
+		from $backupsrv_v4 to $wired_v4 port $backup_port
 	pass in final family inet6 proto tcp flags S/SA \
-		from $backupsrv_v6 to $wired_if port $backup_port 
+		from $backupsrv_v6 to $wired_v6 port $backup_port 
 	pass in final family inet6 proto udp \
-		from $backupsrv_v6 to $wired_if port $backup_port
+		from $backupsrv_v6 to $wired_v6 port $backup_port
 
-	pass stateful in final family inet6 proto udp to $wired_if \
+	pass stateful in final family inet6 proto udp to $wired_v6 \
 		port $services_udp
-	pass stateful in final family inet  proto udp to $wired_if \
+	pass stateful in final family inet  proto udp to $wired_v6 \
 		port $services_udp
 
 	# only SYN packets need to generate state
 	pass stateful out final family inet6 proto tcp flags S/SA \
-		from $wired_if apply "rid" 
+		from $wired_v6 apply "rid" 
 	pass stateful out final family inet  proto tcp flags S/SA \
-		from $wired_if apply "rid" 
+		from $wired_v4 apply "rid" 
 	# pass the other tcp packets without generating extra state
-	pass out final family inet6 proto tcp from $wired_if apply "rid" 
-	pass out final family inet  proto tcp from $wired_if apply "rid" 
+	pass out final family inet6 proto tcp from $wired_v6 apply "rid" 
+	pass out final family inet  proto tcp from $wired_v4 apply "rid" 
 
 	# all other types of traffic, generate state per packet
-	pass stateful out final family inet6 from $wired_if apply "rid" 
-	pass stateful out final family inet  from $wired_if apply "rid" 
+	pass stateful out final family inet6 from $wired_v6 apply "rid" 
+	pass stateful out final family inet  from $wired_v4 apply "rid" 
 
 }
 
@@ -81,37 +86,37 @@
 	pass in  final family inet6 proto ipv6-icmp  to ff00::/10
 	pass out final family inet6 proto ipv6-icmp from ff00::/10
 
-	pass in  final family inet6 proto ipv6-icmp to $wifi_if
-	pass in  final family inet  proto icmp      to $wifi_if
+	pass in  final family inet6 proto ipv6-icmp to $wifi_v6
+	pass in  final family inet  proto icmp      to $wifi_v6
 
 	pass in  final family inet proto tcp \
-		from any port bootps to $wifi_if port bootpc
+		from any port bootps to $wifi_v4 port bootpc
 	pass in  final family inet proto udp \
-		from any port bootps to $wifi_if port bootpc
+		from any port bootps to $wifi_v4 port bootpc
 
-        pass in final family inet6 proto tcp flags S/SA to $wifi_if port ssh 
+        pass in final family inet6 proto tcp flags S/SA to $wifi_v6 port ssh 
 
-        pass in final family inet6 proto udp to $wifi_if port $services_udp
-        pass in final family inet  proto udp to $wifi_if port $services_udp
+        pass in final family inet6 proto udp to $wifi_v6 port $services_udp
+        pass in final family inet  proto udp to $wifi_v4 port $services_udp
 
 	# IPSEC
-	pass in final family inet6 proto udp to $wifi_if port isakmp
-	pass in final family inet  proto udp to $wifi_if port isakmp
+	pass in final family inet6 proto udp to $wifi_v6 port isakmp
+	pass in final family inet  proto udp to $wifi_v4 port isakmp
 	pass in family inet6 proto esp all
 	pass in family inet  proto esp all
 
 	# only SYN packets need to generate state
         pass stateful out final family inet6 proto tcp flags S/SA \
-		from $wifi_if apply "rid" 
+		from $wifi_v6 apply "rid" 
         pass stateful out final family inet  proto tcp flags S/SA \
-		from $wifi_if apply "rid" 
+		from $wifi_v4 apply "rid" 
 	# pass the other tcp packets without generating extra state
-        pass out final family inet6 proto tcp from $wifi_if apply "rid" 
-        pass out final family inet  proto tcp from $wifi_if apply "rid" 
+        pass out final family inet6 proto tcp from $wifi_v6 apply "rid" 
+        pass out final family inet  proto tcp from $wifi_v4 apply "rid" 
 
 	# all other types of traffic, generate state per packet
-        pass stateful out final family inet6 from $wifi_if apply "rid" 
-        pass stateful out final family inet  from $wifi_if apply "rid" 
+        pass stateful out final family inet6 from $wifi_v6 apply "rid" 
+        pass stateful out final family inet  from $wifi_v4 apply "rid" 
 }
 
 group (default) {
--- a/share/examples/npf/soho_gw-npf.conf	Tue Dec 11 04:26:26 2012 +0000
+++ b/share/examples/npf/soho_gw-npf.conf	Tue Dec 11 04:31:52 2012 +0000
@@ -1,4 +1,4 @@
-# $NetBSD: soho_gw-npf.conf,v 1.2.4.2 2012/10/01 20:15:34 riz Exp $
+# $NetBSD: soho_gw-npf.conf,v 1.2.4.3 2012/12/11 04:31:53 riz Exp $
 #
 # SOHO border
 #
@@ -6,6 +6,9 @@
 # IPv4 only
 #
 $ext_if = "wm0"
+$ext_v4 = inet4(wm0)
+$ext_addrs = { ifnet(wm0) }
+
 $int_if = "wm1"
 
 # a table to house e.g. block candidates in
@@ -20,11 +23,11 @@
 # NAT outgoing to the address of the external interface
 # Note: if $ext_if has multiple IP addresses (e.g. IPv6 as well),
 # then the translation address has to be specified explicitly.
-map $ext_if dynamic 198.51.100.0/24 -> $ext_if
+map $ext_if dynamic 198.51.100.0/24 -> $ext_v4
 
 # NAT traffic arriving on port 9022 of the external interface address
 # to host 198.51.100.2 port 22
-map $ext_if dynamic 198.51.100.2 port 22 <- $ext_if 9022
+map $ext_if dynamic 198.51.100.2 port 22 <- $ext_v4 9022
 
 procedure "log" {
 	log: npflog0
@@ -35,18 +38,18 @@
 }
 
 group (name "external", interface $ext_if) {
-	pass stateful out final from $ext_if apply "rid"
+	pass stateful out final from $ext_addrs apply "rid"
 
 	block in final from <1>
-	pass stateful in final family inet proto tcp to $ext_if port ssh \
+	pass stateful in final family inet proto tcp to $ext_v4 port ssh \
 		apply "log"
-	pass stateful in final proto tcp to $ext_if port $services_tcp
-	pass stateful in final proto udp to $ext_if port $services_udp
+	pass stateful in final proto tcp to $ext_addrs port $services_tcp
+	pass stateful in final proto udp to $ext_addrs port $services_udp
 
 	# Passive FTP
-	pass stateful in final proto tcp to $ext_if port 49151-65535
+	pass stateful in final proto tcp to $ext_addrs port 49151-65535
 	# Traceroute
-	pass stateful in final proto udp to $ext_if port 33434-33600
+	pass stateful in final proto udp to $ext_addrs port 33434-33600
 }
 
 group (name "internal", interface $int_if) {
--- a/sys/net/npf/npf_tableset.c	Tue Dec 11 04:26:26 2012 +0000
+++ b/sys/net/npf/npf_tableset.c	Tue Dec 11 04:31:52 2012 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_tableset.c,v 1.9.2.6 2012/11/24 04:34:41 riz Exp $	*/
+/*	$NetBSD: npf_tableset.c,v 1.9.2.7 2012/12/11 04:31:53 riz Exp $	*/
 
 /*-
  * Copyright (c) 2009-2012 The NetBSD Foundation, Inc.
@@ -41,7 +41,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_tableset.c,v 1.9.2.6 2012/11/24 04:34:41 riz Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_tableset.c,v 1.9.2.7 2012/12/11 04:31:53 riz Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -575,8 +575,7 @@
 		if (error)
 			break;
 		error = table_tree_list(&t->t_tree[1], 128, ubuf, len, &off);
-		if (error)
-			break;
+		break;
 	default:
 		KASSERT(false);
 	}
--- a/usr.sbin/npf/npfctl/npf.conf.5	Tue Dec 11 04:26:26 2012 +0000
+++ b/usr.sbin/npf/npfctl/npf.conf.5	Tue Dec 11 04:31:52 2012 +0000
@@ -1,4 +1,4 @@
-.\"    $NetBSD: npf.conf.5,v 1.9.2.4 2012/10/01 20:05:56 riz Exp $
+.\"    $NetBSD: npf.conf.5,v 1.9.2.5 2012/12/11 04:31:53 riz Exp $
 .\"
 .\" Copyright (c) 2009-2012 The NetBSD Foundation, Inc.
 .\" All rights reserved.
@@ -27,7 +27,7 @@
 .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 .\" POSSIBILITY OF SUCH DAMAGE.
 .\"
-.Dd September 30, 2012
+.Dd November 26, 2012
 .Dt NPF.CONF 5
 .Os
 .Sh NAME
@@ -96,6 +96,18 @@
 .Ed
 .Pp
 Tables of type "hash" can only contain IP addresses.
+.Ss Interfaces
+Interfaces can be specified as the values of the variables:
+.Bd -literal
+$pub_if_list = { ifnet(wm0), ifnet(wm1) }
+.Ed
+In the context of filtering, an interface provides a list of its
+all IP addresses, including IPv4 and IPv6.
+Specific interface addresses can be selected by the family, e.g.:
+.Bd -literal
+$pub_if4 = inet4(wm0)
+$pub_if6 = { inet6(wm0) }
+.Ed
 .Ss Groups
 Groups may have the following options: name, interface, and direction.
 They are defined in the following form:
@@ -151,7 +163,7 @@
 The following would translate the source to the IP address specified
 by the $pub_ip for the packets on the interface $ext_if.
 .Bd -literal
-map $ext_if dynamic 10.1.1.0/24 -> $pub_if
+map $ext_if dynamic 10.1.1.0/24 -> $pub_ip
 .Ed
 .Pp
 Translations are implicitly filtered by limiting the operation to the
@@ -256,8 +268,8 @@
 .\" -----
 .Sh EXAMPLES
 .Bd -literal
-$ext_if = "wm0"
-$int_if = "wm1"
+$ext_if = ifnet(wm0)
+$int_if = ifnet(wm1)
 
 table <1> type hash file "/etc/npf_blacklist"
 table <2> type tree dynamic
--- a/usr.sbin/npf/npfctl/npf_build.c	Tue Dec 11 04:26:26 2012 +0000
+++ b/usr.sbin/npf/npfctl/npf_build.c	Tue Dec 11 04:31:52 2012 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_build.c,v 1.4.2.7 2012/11/18 22:38:28 riz Exp $	*/
+/*	$NetBSD: npf_build.c,v 1.4.2.8 2012/12/11 04:31:52 riz Exp $	*/
 
 /*-
  * Copyright (c) 2011-2012 The NetBSD Foundation, Inc.
@@ -34,7 +34,7 @@
  */
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: npf_build.c,v 1.4.2.7 2012/11/18 22:38:28 riz Exp $");
+__RCSID("$NetBSD: npf_build.c,v 1.4.2.8 2012/12/11 04:31:52 riz Exp $");
 
 #include <sys/types.h>
 #include <sys/ioctl.h>
@@ -145,7 +145,7 @@
 	 * Otherwise, address of invalid family was passed manually.
 	 */
 	if (family != AF_UNSPEC && family != fam->fam_family) {
-		if (!fam->fam_interface) {
+		if (!fam->fam_ifindex) {
 			yyerror("specified address is not of the required "
 			    "family %d", family);
 		}
--- a/usr.sbin/npf/npfctl/npf_data.c	Tue Dec 11 04:26:26 2012 +0000
+++ b/usr.sbin/npf/npfctl/npf_data.c	Tue Dec 11 04:31:52 2012 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_data.c,v 1.10.2.5 2012/08/13 17:49:52 riz Exp $	*/
+/*	$NetBSD: npf_data.c,v 1.10.2.6 2012/12/11 04:31:52 riz Exp $	*/
 
 /*-
  * Copyright (c) 2009-2012 The NetBSD Foundation, Inc.
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: npf_data.c,v 1.10.2.5 2012/08/13 17:49:52 riz Exp $");
+__RCSID("$NetBSD: npf_data.c,v 1.10.2.6 2012/12/11 04:31:52 riz Exp $");
 
 #include <sys/types.h>
 #include <sys/null.h>
@@ -273,63 +273,60 @@
 }
 
 npfvar_t *
-npfctl_parse_iface(const char *ifname)
+npfctl_parse_ifnet(const char *ifname, const int family)
 {
-	npfvar_t *vp = npfvar_create(".iface");
+	npfvar_t *vpa, *vp;
 	struct ifaddrs *ifa;
-	fam_addr_mask_t fam;
-	bool gotif = false;
+	ifnet_addr_t ifna;
 
 	if (ifs_list == NULL && getifaddrs(&ifs_list) == -1) {
 		err(EXIT_FAILURE, "getifaddrs");
 	}
-	memset(&fam, 0, sizeof(fam));
 
-	npfvar_t *ip = npfvar_create(".ifname");
-	if (!npfvar_add_element(ip, NPFVAR_STRING, ifname, strlen(ifname) + 1))
-		goto out;
+	vpa = npfvar_create(".ifaddrs");
+	ifna.ifna_addrs = vpa;
+	ifna.ifna_index = npfctl_find_ifindex(ifname);
+	assert(ifna.ifna_index != 0);
 
 	for (ifa = ifs_list; ifa != NULL; ifa = ifa->ifa_next) {
+		fam_addr_mask_t fam;
 		struct sockaddr *sa;
-		sa_family_t family;
 
 		if (strcmp(ifa->ifa_name, ifname) != 0)
 			continue;
 
-		gotif = true;
 		if ((ifa->ifa_flags & IFF_UP) == 0)
 			warnx("interface '%s' is down", ifname);
 
 		sa = ifa->ifa_addr;
-		family = sa->sa_family;
-		if (family != AF_INET && family != AF_INET6)
+		if (sa->sa_family != AF_INET && sa->sa_family != AF_INET6)
+			continue;
+		if (family != AF_UNSPEC && sa->sa_family != family)
 			continue;
 
-		fam.fam_family = family;
-		fam.fam_interface = ip;
+		memset(&fam, 0, sizeof(fam));
+		fam.fam_family = sa->sa_family;
+		fam.fam_ifindex = ifna.ifna_index;
 
-		if (!npfctl_copy_address(family, &fam.fam_addr, sa))
+		if (!npfctl_copy_address(sa->sa_family, &fam.fam_addr, sa))
 			goto out;
 
 		if (!npfctl_parse_mask(NULL, fam.fam_family, &fam.fam_mask))
 			goto out;
 
-		if (!npfvar_add_element(vp, NPFVAR_FAM, &fam, sizeof(fam)))
+		if (!npfvar_add_element(vpa, NPFVAR_FAM, &fam, sizeof(fam)))
 			goto out;
-
 	}
-	if (!gotif) {
-		yyerror("interface '%s' not found", ifname);
-		goto out;
-	}
-	if (npfvar_get_count(vp) == 0) {
+	if (npfvar_get_count(vpa) == 0) {
 		yyerror("no addresses matched for interface '%s'", ifname);
 		goto out;
 	}
+
+	vp = npfvar_create(".interface");
+	npfvar_add_element(vp, NPFVAR_INTERFACE, &ifna, sizeof(ifna));
 	return vp;
 out:
-	npfvar_destroy(vp);
-	npfvar_destroy(ip);
+	npfvar_destroy(ifna.ifna_addrs);
 	return NULL;
 }
 
--- a/usr.sbin/npf/npfctl/npf_parse.y	Tue Dec 11 04:26:26 2012 +0000
+++ b/usr.sbin/npf/npfctl/npf_parse.y	Tue Dec 11 04:31:52 2012 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_parse.y,v 1.3.2.9 2012/11/26 17:39:29 riz Exp $	*/
+/*	$NetBSD: npf_parse.y,v 1.3.2.10 2012/12/11 04:31:52 riz Exp $	*/
 
 /*-
  * Copyright (c) 2011-2012 The NetBSD Foundation, Inc.
@@ -100,6 +100,7 @@
 %token			HASH
 %token			ICMPTYPE
 %token			ID
+%token			IFNET
 %token			IN
 %token			INET
 %token			INET6
@@ -143,10 +144,11 @@
 
 %type	<str>		addr, some_name, list_elem, table_store
 %type	<str>		proc_param_val, opt_apply
-%type	<num>		ifindex, port, opt_final, on_iface
-%type	<num>		block_or_pass, rule_dir, block_opts, opt_family
+%type	<num>		ifindex, port, opt_final, on_ifindex
+%type	<num>		afamily, opt_family
+%type	<num>		block_or_pass, rule_dir, block_opts
 %type	<num>		opt_stateful, icmp_type, table_type, map_sd, map_type
-%type	<var>		addr_or_iface, port_range, icmp_type_and_code
+%type	<var>		ifnet, addr_or_ifnet, port_range, icmp_type_and_code
 %type	<var>		filt_addr, addr_and_mask, tcp_flags, tcp_flags_and_mask
 %type	<var>		procs, proc_call, proc_param_list, proc_param
 %type	<addrport>	mapseg
@@ -158,9 +160,9 @@
 	char *		str;
 	unsigned long	num;
 	double		fpnum;
+	npfvar_t *	var;
 	addr_port_t	addrport;
 	filt_opts_t	filtopts;
-	npfvar_t *	var;
 	opt_proto_t	optproto;
 	rule_group_t	rulegroup;
 }
@@ -241,6 +243,10 @@
 		npfvar_add_element(vp, NPFVAR_VAR_ID, $1, strlen($1) + 1);
 		npfvar_add_elements(cvar, vp);
 	}
+	| ifnet
+	{
+		npfvar_add_elements(cvar, $1);
+	}
 	| addr_and_mask
 	{
 		npfvar_add_elements(cvar, $1);
@@ -277,7 +283,7 @@
 	;
 
 mapseg
-	: addr_or_iface port_range
+	: addr_or_ifnet port_range
 	{
 		$$.ap_netaddr = $1;
 		$$.ap_portrange = $2;
@@ -420,8 +426,8 @@
 	;
 
 rule
-	: block_or_pass opt_stateful rule_dir opt_final on_iface opt_family
-	  opt_proto all_or_filt_opts opt_apply
+	: block_or_pass opt_stateful rule_dir opt_final on_ifindex
+	  opt_family opt_proto all_or_filt_opts opt_apply
 	{
 		/*
 		 * Arguments: attributes, interface index, address
@@ -449,14 +455,18 @@
 	|			{ $$ = 0; }
 	;
 
-on_iface
+on_ifindex
 	: ON ifindex		{ $$ = $2; }
 	|			{ $$ = 0; }
 	;
 
+afamily
+	: INET			{ $$ = AF_INET; }
+	| INET6			{ $$ = AF_INET6; }
+	;
+
 opt_family
-	: FAMILY INET		{ $$ = AF_INET; }
-	| FAMILY INET6		{ $$ = AF_INET6; }
+	: FAMILY afamily	{ $$ = $2; }
 	|			{ $$ = AF_UNSPEC; }
 	;
 
@@ -546,7 +556,7 @@
 	;
 
 filt_addr
-	: addr_or_iface		{ $$ = $1; }
+	: addr_or_ifnet		{ $$ = $1; }
 	| TABLE_ID		{ $$ = npfctl_parse_table_id($1); }
 	| ANY			{ $$ = NULL; }
 	;
@@ -570,36 +580,37 @@
 	}
 	;
 
-addr_or_iface
+addr_or_ifnet
 	: addr_and_mask
 	{
 		assert($1 != NULL);
 		$$ = $1;
 	}
-	| some_name
+	| ifnet
 	{
-		$$ = npfctl_parse_iface($1);
+		ifnet_addr_t *ifna = npfvar_get_data($1, NPFVAR_INTERFACE, 0);
+		$$ = ifna->ifna_addrs;
 	}
 	| VAR_ID
 	{
 		npfvar_t *vp = npfvar_lookup($1);
 		const int type = npfvar_get_type(vp, 0);
+		ifnet_addr_t *ifna;
 
 		switch (type) {
-		case NPFVAR_VAR_ID:
-		case NPFVAR_STRING:
-			$$ = npfctl_parse_iface(npfvar_expand_string(vp));
-			break;
 		case NPFVAR_FAM:
 			$$ = vp;
 			break;
+		case NPFVAR_INTERFACE:
+			ifna = npfvar_get_data(vp, type, 0);
+			$$ = ifna->ifna_addrs;
+			break;
 		case -1:
-			yyerror("undefined variable '%s' for interface", $1);
+			yyerror("undefined variable '%s'", $1);
 			break;
 		default:
-			yyerror("wrong variable '%s' type '%s' or interface",
-			    $1, npfvar_type(type));
-			$$ = NULL;
+			yyerror("wrong variable '%s' type '%s' for address "
+			    "or interface", $1, npfvar_type(type));
 			break;
 		}
 	}
@@ -645,12 +656,14 @@
 	}
 	| ICMPTYPE icmp_type CODE IDENTIFIER
 	{
-		$$ = npfctl_parse_icmp($<num>0, $2, npfctl_icmpcode($<num>0, $2, $4));
+		$$ = npfctl_parse_icmp($<num>0, $2,
+		    npfctl_icmpcode($<num>0, $2, $4));
 	}
 	| ICMPTYPE icmp_type CODE VAR_ID
 	{
 		char *s = npfvar_expand_string(npfvar_lookup($4));
-		$$ = npfctl_parse_icmp($<num>0, $2, npfctl_icmpcode($<num>0, $2, s));
+		$$ = npfctl_parse_icmp($<num>0, $2,
+		    npfctl_icmpcode($<num>0, $2, s));
 	}
 	|
 	{
@@ -687,28 +700,47 @@
 	}
 	;
 
+ifnet
+	: IFNET PAR_OPEN IDENTIFIER PAR_CLOSE
+	{
+		$$ = npfctl_parse_ifnet($3, AF_UNSPEC);
+	}
+	| afamily PAR_OPEN IDENTIFIER PAR_CLOSE
+	{
+		$$ = npfctl_parse_ifnet($3, $1);
+	}
+
 ifindex
 	: some_name
 	{
 		$$ = npfctl_find_ifindex($1);
 	}
+	| ifnet
+	{
+		ifnet_addr_t *ifna = npfvar_get_data($1, NPFVAR_INTERFACE, 0);
+		$$ = ifna->ifna_index;
+	}
 	| VAR_ID
 	{
 		npfvar_t *vp = npfvar_lookup($1);
 		const int type = npfvar_get_type(vp, 0);
+		ifnet_addr_t *ifna;
 
 		switch (type) {
-		case NPFVAR_VAR_ID:
 		case NPFVAR_STRING:
+		case NPFVAR_IDENTIFIER:
 			$$ = npfctl_find_ifindex(npfvar_expand_string(vp));
 			break;
+		case NPFVAR_INTERFACE:
+			ifna = npfvar_get_data(vp, type, 0);
+			$$ = ifna->ifna_index;
+			break;
 		case -1:
 			yyerror("undefined variable '%s' for interface", $1);
 			break;
 		default:
 			yyerror("wrong variable '%s' type '%s' for interface",
 			    $1, npfvar_type(type));
-			$$ = -1;
 			break;
 		}
 	}
--- a/usr.sbin/npf/npfctl/npf_scan.l	Tue Dec 11 04:26:26 2012 +0000
+++ b/usr.sbin/npf/npfctl/npf_scan.l	Tue Dec 11 04:31:52 2012 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_scan.l,v 1.1.2.5 2012/11/26 17:39:29 riz Exp $	*/
+/*	$NetBSD: npf_scan.l,v 1.1.2.6 2012/12/11 04:31:52 riz Exp $	*/
 
 /*-
  * Copyright (c) 2011-2012 The NetBSD Foundation, Inc.
@@ -80,6 +80,7 @@
 final			return FINAL;
 quick			return FINAL;
 on			return ON;
+ifnet			return IFNET;
 inet6			return INET6;
 inet4			return INET;
 inet			return INET;
--- a/usr.sbin/npf/npfctl/npf_var.h	Tue Dec 11 04:26:26 2012 +0000
+++ b/usr.sbin/npf/npfctl/npf_var.h	Tue Dec 11 04:31:52 2012 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_var.h,v 1.1.2.4 2012/11/19 18:16:18 riz Exp $	*/
+/*	$NetBSD: npf_var.h,v 1.1.2.5 2012/12/11 04:31:52 riz Exp $	*/
 
 /*-
  * Copyright (c) 2011-2012 The NetBSD Foundation, Inc.
@@ -49,6 +49,7 @@
 #define	NPFVAR_TCPFLAG		9
 #define	NPFVAR_ICMP		10
 #define	NPFVAR_ICMP6		11
+#define	NPFVAR_INTERFACE	12
 
 #ifdef _NPFVAR_PRIVATE
 static const char *npfvar_types[ ] = {
@@ -63,7 +64,8 @@
 	[NPFVAR_PROC_PARAM]	= "procedure-parameter",
 	[NPFVAR_TCPFLAG]	= "tcp-flag",
 	[NPFVAR_ICMP]		= "icmp",
-	[NPFVAR_ICMP6]		= "icmp6"
+	[NPFVAR_ICMP6]		= "icmp6",
+	[NPFVAR_INTERFACE]	= "interface"
 };
 #endif
 
--- a/usr.sbin/npf/npfctl/npfctl.h	Tue Dec 11 04:26:26 2012 +0000
+++ b/usr.sbin/npf/npfctl/npfctl.h	Tue Dec 11 04:31:52 2012 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npfctl.h,v 1.11.2.9 2012/11/26 17:39:29 riz Exp $	*/
+/*	$NetBSD: npfctl.h,v 1.11.2.10 2012/12/11 04:31:52 riz Exp $	*/
 
 /*-
  * Copyright (c) 2009-2012 The NetBSD Foundation, Inc.
@@ -52,9 +52,16 @@
 	sa_family_t	fam_family;
 	npf_addr_t	fam_addr;
 	npf_netmask_t	fam_mask;
-	npfvar_t *	fam_interface;
+	unsigned long	fam_ifindex;
 } fam_addr_mask_t;
 
+typedef struct ifnet_addr {
+	unsigned long	ifna_index;
+	sa_family_t	ifna_family;
+	npfvar_t *	ifna_filter;
+	npfvar_t *	ifna_addrs;
+} ifnet_addr_t;
+
 typedef struct port_range {
 	in_port_t	pr_start;
 	in_port_t	pr_end;
@@ -101,10 +108,10 @@
 uint8_t		npfctl_icmpcode(int, uint8_t, const char *);
 uint8_t		npfctl_icmptype(int, const char *);
 unsigned long   npfctl_find_ifindex(const char *);
+npfvar_t *	npfctl_parse_ifnet(const char *, const int);
 npfvar_t *	npfctl_parse_tcpflag(const char *);
 npfvar_t *	npfctl_parse_table_id(const char *);
 npfvar_t * 	npfctl_parse_icmp(int, int, int);
-npfvar_t *	npfctl_parse_iface(const char *);
 npfvar_t *	npfctl_parse_port_range(in_port_t, in_port_t);
 npfvar_t *	npfctl_parse_port_range_variable(const char *);
 npfvar_t *	npfctl_parse_fam_addr_mask(const char *, const char *,