- NPF: change the group/ruleset syntax - simplify. Update npf.conf(5) manual. trunk
authorrmind <rmind@NetBSD.org>
Fri, 20 Sep 2013 03:03:52 +0000
branchtrunk
changeset 221226 ca6d01d22471
parent 221225 d7a417c8b12a
child 221227 c84ae71af25a
- NPF: change the group/ruleset syntax - simplify. Update npf.conf(5) manual. - Add support for the inline pcap-filter(7) syntax in the rule, e.g.: block out final pcap-filter "tcp and dst 10.1.1.252"
usr.sbin/npf/npfctl/npf.conf.5
usr.sbin/npf/npfctl/npf_build.c
usr.sbin/npf/npfctl/npf_parse.y
usr.sbin/npf/npfctl/npf_scan.l
usr.sbin/npf/npfctl/npf_show.c
usr.sbin/npf/npfctl/npfctl.h
--- a/usr.sbin/npf/npfctl/npf.conf.5	Thu Sep 19 23:29:25 2013 +0000
+++ b/usr.sbin/npf/npfctl/npf.conf.5	Fri Sep 20 03:03:52 2013 +0000
@@ -1,4 +1,4 @@
-.\"    $NetBSD: npf.conf.5,v 1.30 2013/09/19 12:05:11 rmind Exp $
+.\"    $NetBSD: npf.conf.5,v 1.31 2013/09/20 03:03:52 rmind Exp $
 .\"
 .\" Copyright (c) 2009-2013 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 19, 2013
+.Dd September 20, 2013
 .Dt NPF.CONF 5
 .Os
 .Sh NAME
@@ -236,19 +236,21 @@
 proc-opts	= key " " val [ "," proc-opts ]
 proc-call	= call-name ":" proc-opts new-line
 
-; Group definition and the ruleset.
+; Group definition and the rule list.
+
+group		= "group" ( "default" | group-opts ) "{" rule-list "}"
+group-opts	= name-string [ "in" | "out" ] [ "on" interface ]
+rule-list	= [ rule new-line ] rule-list
 
-group		= "group" "(" ( "default" | group-opts ) ")" "{" ruleset "}"
-group-opts	= [ "name" string ] [ "interface" interface ] [ "in" | "out" ]
-ruleset		= [ rule new-line ] [ ruleset ]
-
-rule		= ( "block" [ block-opts ] | "pass" ) [ "stateful" ]
-		  [ "in" | out" ] [ "final" ] [ "on" iface ]
-		  [ "family" fam-opt ] [ "proto" protocol [ proto-opts ] ]
+static-rule	= ( "block" [ block-opts ] | "pass" ) [ "stateful" ]
+		  [ "in" | out" ] [ "final" ] [ "on" interface ]
+		  [ "family" family-opt ] [ "proto" protocol [ proto-opts ] ]
 		  ( "all" | filt-opts ) [ "apply" proc-name ]
+dynamic-ruleset	= "ruleset" group-opts
+rule		= static-rule | dynamic-ruleset
 
 block-opts	= "return-rst" | "return-icmp" | "return"
-fam-opt		= "inet" | "inet6"
+family-opt	= "inet" | "inet6"
 proto-opts	= "flags" tcp-flags [ "/" tcp-flag-mask ] |
 		  "icmp-type" type [ "code" icmp-code ]
 
@@ -291,7 +293,7 @@
 	log: npflog0
 }
 
-group (name "external", interface $ext_if) {
+group "external" on $ext_if {
 	pass stateful out final all
 
 	block in final from \*[Lt]1\*[Gt]
@@ -302,13 +304,16 @@
 	pass stateful in final proto udp to $ext_if port 33434-33600	# Traceroute
 }
 
-group (name "internal", interface $int_if) {
+group "internal" on $int_if {
 	block in all
-	pass in final from \*[Lt]2\*[Gt]
+	block in final from \*[Lt]2\*[Gt]
+
+	# Ingress filtering as per RFC 2827.
+	pass in final from $localnet
 	pass out final all
 }
 
-group (default) {
+group default {
 	pass final on lo0 all
 	block all
 }
--- a/usr.sbin/npf/npfctl/npf_build.c	Thu Sep 19 23:29:25 2013 +0000
+++ b/usr.sbin/npf/npfctl/npf_build.c	Fri Sep 20 03:03:52 2013 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_build.c,v 1.26 2013/09/19 12:05:11 rmind Exp $	*/
+/*	$NetBSD: npf_build.c,v 1.27 2013/09/20 03:03:52 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2011-2013 The NetBSD Foundation, Inc.
@@ -34,7 +34,7 @@
  */
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: npf_build.c,v 1.26 2013/09/19 12:05:11 rmind Exp $");
+__RCSID("$NetBSD: npf_build.c,v 1.27 2013/09/20 03:03:52 rmind Exp $");
 
 #include <sys/types.h>
 #include <sys/ioctl.h>
@@ -59,6 +59,8 @@
 static unsigned			rule_nesting_level = 0;
 static nl_rule_t *		defgroup = NULL;
 
+static void			npfctl_dump_bpf(struct bpf_program *);
+
 void
 npfctl_config_init(bool debug)
 {
@@ -273,7 +275,7 @@
 
 static bool
 npfctl_build_code(nl_rule_t *rl, sa_family_t family, const opt_proto_t *op,
-    const filt_opts_t *fopts, bool invert)
+    const filt_opts_t *fopts)
 {
 	const addr_port_t *apfrom = &fopts->fo_from;
 	const addr_port_t *apto = &fopts->fo_to;
@@ -306,21 +308,18 @@
 		}
 	}
 
-	const int srcflag = invert ? MATCH_DST : MATCH_SRC;
-	const int dstflag = invert ? MATCH_SRC : MATCH_DST;
-
 	bc = npfctl_bpf_create();
 
 	/* Build layer 4 protocol blocks. */
 	npfctl_build_proto(bc, family, op);
 
 	/* Build IP address blocks. */
-	npfctl_build_vars(bc, family, apfrom->ap_netaddr, srcflag);
-	npfctl_build_vars(bc, family, apto->ap_netaddr, dstflag);
+	npfctl_build_vars(bc, family, apfrom->ap_netaddr, MATCH_SRC);
+	npfctl_build_vars(bc, family, apto->ap_netaddr, MATCH_DST);
 
 	/* Build port-range blocks. */
-	npfctl_build_vars(bc, family, apfrom->ap_portrange, srcflag);
-	npfctl_build_vars(bc, family, apto->ap_portrange, dstflag);
+	npfctl_build_vars(bc, family, apfrom->ap_portrange, MATCH_SRC);
+	npfctl_build_vars(bc, family, apto->ap_portrange, MATCH_DST);
 
 	/* Set the byte-code marks, if any. */
 	const void *bmarks = npfctl_bpf_bmarks(bc, &len);
@@ -330,24 +329,38 @@
 
 	/* Complete BPF byte-code and pass to the rule. */
 	struct bpf_program *bf = npfctl_bpf_complete(bc);
-	if (npf_debug) {
-		extern char *yytext;
-		extern int yylineno;
-
-		printf("\nRULE AT LINE %d\n", yylineno - (int)(*yytext == '\n'));
-		bpf_dump(bf, 0);
-	}
 	len = bf->bf_len * sizeof(struct bpf_insn);
 
 	if (npf_rule_setcode(rl, NPF_CODE_BPF, bf->bf_insns, len) == -1) {
 		errx(EXIT_FAILURE, "npf_rule_setcode failed");
 	}
+	npfctl_dump_bpf(bf);
 	npfctl_bpf_destroy(bc);
 
 	return true;
 }
 
 static void
+npfctl_build_pcap(nl_rule_t *rl, const char *filter)
+{
+	const size_t maxsnaplen = 64 * 1024;
+	struct bpf_program bf;
+	size_t len;
+
+	if (pcap_compile_nopcap(maxsnaplen, DLT_RAW, &bf,
+	    filter, 1, PCAP_NETMASK_UNKNOWN) == -1) {
+		yyerror("invalid pcap-filter(7) syntax");
+	}
+	len = bf.bf_len * sizeof(struct bpf_insn);
+
+	if (npf_rule_setcode(rl, NPF_CODE_BPF, bf.bf_insns, len) == -1) {
+		errx(EXIT_FAILURE, "npf_rule_setcode failed");
+	}
+	npfctl_dump_bpf(&bf);
+	pcap_freecode(&bf);
+}
+
+static void
 npfctl_build_rpcall(nl_rproc_t *rp, const char *name, npfvar_t *args)
 {
 	npf_extmod_t *extmod;
@@ -468,14 +481,20 @@
  */
 void
 npfctl_build_rule(uint32_t attr, u_int if_idx, sa_family_t family,
-    const opt_proto_t *op, const filt_opts_t *fopts, const char *rproc)
+    const opt_proto_t *op, const filt_opts_t *fopts,
+    const char *pcap_filter, const char *rproc)
 {
 	nl_rule_t *rl;
 
 	attr |= (npf_conf ? 0 : NPF_RULE_DYNAMIC);
 
 	rl = npf_rule_create(NULL, attr, if_idx);
-	npfctl_build_code(rl, family, op, fopts, false);
+	if (pcap_filter) {
+		npfctl_build_pcap(rl, pcap_filter);
+	} else {
+		npfctl_build_code(rl, family, op, fopts);
+	}
+
 	if (rproc) {
 		npf_rule_setproc(rl, rproc);
 	}
@@ -547,7 +566,7 @@
 		assert(false);
 	}
 
-	npfctl_build_code(nat, family, &op, fopts, false);
+	npfctl_build_code(nat, family, &op, fopts);
 	npf_nat_insert(npf_conf, nat, NPF_PRI_LAST);
 }
 
@@ -672,3 +691,16 @@
 		errx(EXIT_FAILURE, "ALG '%s' already loaded", al_name);
 	}
 }
+
+static void
+npfctl_dump_bpf(struct bpf_program *bf)
+{
+	if (npf_debug) {
+		extern char *yytext;
+		extern int yylineno;
+
+		int rule_line = yylineno - (int)(*yytext == '\n');
+		printf("\nRULE AT LINE %d\n", rule_line);
+		bpf_dump(bf, 0);
+	}
+}
--- a/usr.sbin/npf/npfctl/npf_parse.y	Thu Sep 19 23:29:25 2013 +0000
+++ b/usr.sbin/npf/npfctl/npf_parse.y	Fri Sep 20 03:03:52 2013 +0000
@@ -1,11 +1,11 @@
-/*	$NetBSD: npf_parse.y,v 1.25 2013/09/19 01:04:45 rmind Exp $	*/
+/*	$NetBSD: npf_parse.y,v 1.26 2013/09/20 03:03:52 rmind Exp $	*/
 
 /*-
- * Copyright (c) 2011-2012 The NetBSD Foundation, Inc.
+ * Copyright (c) 2011-2013 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
  * This code is derived from software contributed to The NetBSD Foundation
- * by Martin Husemann and Christos Zoulas.
+ * by Martin Husemann, Christos Zoulas and Mindaugas Rasiukevicius.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -123,6 +123,7 @@
 %token			PAR_CLOSE
 %token			PAR_OPEN
 %token			PASS
+%token			PCAP_FILTER
 %token			PORT
 %token			PROCEDURE
 %token			PROTO
@@ -158,7 +159,7 @@
 %type	<str>		proc_param_val, opt_apply
 %type	<num>		ifindex, port, opt_final, on_ifindex, number
 %type	<num>		afamily, opt_family
-%type	<num>		block_or_pass, rule_dir, block_opts
+%type	<num>		block_or_pass, rule_dir, group_dir, block_opts
 %type	<num>		opt_stateful, icmp_type, table_type, map_sd, map_type
 %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
@@ -166,7 +167,7 @@
 %type	<addrport>	mapseg
 %type	<filtopts>	filt_opts, all_or_filt_opts
 %type	<optproto>	opt_proto
-%type	<rulegroup>	group_attr, group_opt
+%type	<rulegroup>	group_opts
 
 %union {
 	char *		str;
@@ -313,9 +314,9 @@
 	{
 		npfctl_build_natseg($3, $5, $2, &$4, &$6, NULL);
 	}
-	| MAP RULESET PAR_OPEN group_attr PAR_CLOSE
+	| MAP RULESET group_opts
 	{
-		npfctl_build_maprset($4.rg_name, $4.rg_attr, $4.rg_ifnum);
+		npfctl_build_maprset($3.rg_name, $3.rg_attr, $3.rg_ifnum);
 	}
 	;
 
@@ -384,11 +385,11 @@
 	;
 
 group
-	: GROUP PAR_OPEN group_attr PAR_CLOSE
+	: GROUP group_opts
 	{
 		/* Build a group.  Increases the nesting level. */
-		npfctl_build_group($3.rg_name, $3.rg_attr,
-		    $3.rg_ifnum, $3.rg_default);
+		npfctl_build_group($2.rg_name, $2.rg_attr,
+		    $2.rg_ifnum, $2.rg_default);
 	}
 	  ruleset_block
 	{
@@ -398,70 +399,32 @@
 	;
 
 ruleset
-	: RULESET PAR_OPEN group_attr PAR_CLOSE
+	: RULESET group_opts
 	{
 		/* Ruleset is a dynamic group. */
-		npfctl_build_group($3.rg_name, $3.rg_attr | NPF_RULE_DYNAMIC,
-		    $3.rg_ifnum, $3.rg_default);
+		npfctl_build_group($2.rg_name, $2.rg_attr | NPF_RULE_DYNAMIC,
+		    $2.rg_ifnum, $2.rg_default);
 		npfctl_build_group_end();
 	}
-
-group_attr
-	: group_opt COMMA group_attr
-	{
-		$$ = $3;
-
-		if (($1.rg_name && $$.rg_name) ||
-		    ($1.rg_ifnum && $$.rg_ifnum) ||
-		    ($1.rg_attr & $$.rg_attr) != 0)
-			yyerror("duplicate group option");
-
-		if ($1.rg_name) {
-			$$.rg_name = $1.rg_name;
-		}
-		if ($1.rg_attr) {
-			$$.rg_attr |= $1.rg_attr;
-		}
-		if ($1.rg_ifnum) {
-			$$.rg_ifnum = $1.rg_ifnum;
-		}
-		if ($1.rg_default) {
-			$$.rg_default = $1.rg_default;
-		}
-	}
-	| group_opt		{ $$ = $1; }
 	;
 
-group_opt
+group_dir
+	: FORW		{ $$ = NPF_RULE_FORW; }
+	| rule_dir
+	;
+
+group_opts
 	: DEFAULT
 	{
 		memset(&$$, 0, sizeof(rule_group_t));
 		$$.rg_default = true;
 	}
-	| NAME STRING
-	{
-		memset(&$$, 0, sizeof(rule_group_t));
-		$$.rg_name = $2;
-	}
-	| INTERFACE ifindex
+	| STRING group_dir on_ifindex
 	{
 		memset(&$$, 0, sizeof(rule_group_t));
-		$$.rg_ifnum = $2;
-	}
-	| TDYNAMIC
-	{
-		memset(&$$, 0, sizeof(rule_group_t));
-		$$.rg_attr = NPF_RULE_DYNAMIC;
-	}
-	| FORW
-	{
-		memset(&$$, 0, sizeof(rule_group_t));
-		$$.rg_attr = NPF_RULE_FORW;
-	}
-	| rule_dir
-	{
-		memset(&$$, 0, sizeof(rule_group_t));
-		$$.rg_attr = $1;
+		$$.rg_name = $1;
+		$$.rg_attr = $2;
+		$$.rg_ifnum = $3;
 	}
 	;
 
@@ -486,7 +449,13 @@
 	  opt_family opt_proto all_or_filt_opts opt_apply
 	{
 		npfctl_build_rule($1 | $2 | $3 | $4, $5,
-		    $6, &$7, &$8, $9);
+		    $6, &$7, &$8, NULL, $9);
+	}
+	| block_or_pass opt_stateful rule_dir opt_final on_ifindex
+	  PCAP_FILTER STRING opt_apply
+	{
+		npfctl_build_rule($1 | $2 | $3 | $4, $5,
+		    AF_UNSPEC, NULL, NULL, $7, $8);
 	}
 	;
 
--- a/usr.sbin/npf/npfctl/npf_scan.l	Thu Sep 19 23:29:25 2013 +0000
+++ b/usr.sbin/npf/npfctl/npf_scan.l	Fri Sep 20 03:03:52 2013 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_scan.l,v 1.12 2013/03/20 00:29:47 christos Exp $	*/
+/*	$NetBSD: npf_scan.l,v 1.13 2013/09/20 03:03:52 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2011-2012 The NetBSD Foundation, Inc.
@@ -113,6 +113,7 @@
 all			return ALL;
 block			return BLOCK;
 pass			return PASS;
+pcap-filter		return PCAP_FILTER;
 stateful		return STATEFUL;
 apply			return APPLY;
 final			return FINAL;
--- a/usr.sbin/npf/npfctl/npf_show.c	Thu Sep 19 23:29:25 2013 +0000
+++ b/usr.sbin/npf/npfctl/npf_show.c	Fri Sep 20 03:03:52 2013 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_show.c,v 1.1 2013/09/19 01:04:45 rmind Exp $	*/
+/*	$NetBSD: npf_show.c,v 1.2 2013/09/20 03:03:52 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2013 The NetBSD Foundation, Inc.
@@ -36,7 +36,7 @@
  */
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: npf_show.c,v 1.1 2013/09/19 01:04:45 rmind Exp $");
+__RCSID("$NetBSD: npf_show.c,v 1.2 2013/09/20 03:03:52 rmind Exp $");
 
 #include <sys/socket.h>
 #include <netinet/in.h>
@@ -482,7 +482,6 @@
 		return error;
 	}
 	while ((rl = npf_rule_iterate(ncf, &level)) != NULL) {
-		print_indent(ctx, level);
 		npfctl_print_rule(ctx, rl);
 	}
 	npf_config_destroy(ncf);
--- a/usr.sbin/npf/npfctl/npfctl.h	Thu Sep 19 23:29:25 2013 +0000
+++ b/usr.sbin/npf/npfctl/npfctl.h	Fri Sep 20 03:03:52 2013 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npfctl.h,v 1.32 2013/09/19 12:05:11 rmind Exp $	*/
+/*	$NetBSD: npfctl.h,v 1.33 2013/09/20 03:03:52 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2009-2013 The NetBSD Foundation, Inc.
@@ -188,7 +188,8 @@
 void		npfctl_build_group(const char *, int, u_int, bool);
 void		npfctl_build_group_end(void);
 void		npfctl_build_rule(uint32_t, u_int, sa_family_t,
-		    const opt_proto_t *, const filt_opts_t *, const char *);
+		    const opt_proto_t *, const filt_opts_t *,
+		    const char *, const char *);
 void		npfctl_build_natseg(int, int, u_int, const addr_port_t *,
 		    const addr_port_t *, const filt_opts_t *);
 void		npfctl_build_maprset(const char *, int, u_int);