NPF: add support for "stateful-ends". trunk
authorrmind <rmind@NetBSD.org>
Fri, 14 Mar 2014 11:29:44 +0000
branchtrunk
changeset 225536 52a1e76c99b3
parent 225535 f0fcba9d6b16
child 225537 2f1325bd6b82
NPF: add support for "stateful-ends".
sys/net/npf/npf.h
sys/net/npf/npf_handler.c
sys/net/npf/npf_impl.h
sys/net/npf/npf_nat.c
sys/net/npf/npf_session.c
usr.sbin/npf/npfctl/npf_parse.y
usr.sbin/npf/npfctl/npf_scan.l
usr.sbin/npf/npfctl/npf_show.c
--- a/sys/net/npf/npf.h	Fri Mar 14 11:27:36 2014 +0000
+++ b/sys/net/npf/npf.h	Fri Mar 14 11:29:44 2014 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf.h,v 1.37 2014/02/13 03:34:40 rmind Exp $	*/
+/*	$NetBSD: npf.h,v 1.38 2014/03/14 11:29:44 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2009-2014 The NetBSD Foundation, Inc.
@@ -210,6 +210,7 @@
 #define	NPF_RULE_RETRST			0x0010
 #define	NPF_RULE_RETICMP		0x0020
 #define	NPF_RULE_DYNAMIC		0x0040
+#define	NPF_RULE_MULTIENDS		0x0080
 
 #define	NPF_DYNAMIC_GROUP		(NPF_RULE_GROUP | NPF_RULE_DYNAMIC)
 
--- a/sys/net/npf/npf_handler.c	Fri Mar 14 11:27:36 2014 +0000
+++ b/sys/net/npf/npf_handler.c	Fri Mar 14 11:29:44 2014 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_handler.c,v 1.28 2013/11/08 00:38:26 rmind Exp $	*/
+/*	$NetBSD: npf_handler.c,v 1.29 2014/03/14 11:29:44 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2009-2013 The NetBSD Foundation, Inc.
@@ -36,7 +36,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_handler.c,v 1.28 2013/11/08 00:38:26 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_handler.c,v 1.29 2014/03/14 11:29:44 rmind Exp $");
 
 #include <sys/types.h>
 #include <sys/param.h>
@@ -229,7 +229,8 @@
 	 * if session creation fails (e.g. due to unsupported protocol).
 	 */
 	if ((retfl & NPF_RULE_STATEFUL) != 0 && !se) {
-		se = npf_session_establish(&npc, &nbuf, di);
+		se = npf_session_establish(&npc, &nbuf, di,
+		    (retfl & NPF_RULE_MULTIENDS) == 0);
 		if (se) {
 			/*
 			 * Note: the reference on the rule procedure is
--- a/sys/net/npf/npf_impl.h	Fri Mar 14 11:27:36 2014 +0000
+++ b/sys/net/npf/npf_impl.h	Fri Mar 14 11:29:44 2014 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_impl.h,v 1.49 2014/02/19 03:51:31 rmind Exp $	*/
+/*	$NetBSD: npf_impl.h,v 1.50 2014/03/14 11:29:44 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2009-2014 The NetBSD Foundation, Inc.
@@ -311,7 +311,7 @@
 npf_session_t *	npf_session_lookup(const npf_cache_t *, const nbuf_t *,
 		    const int, bool *);
 npf_session_t *	npf_session_inspect(npf_cache_t *, nbuf_t *, const int, int *);
-npf_session_t *	npf_session_establish(npf_cache_t *, nbuf_t *, const int);
+npf_session_t *	npf_session_establish(npf_cache_t *, nbuf_t *, int, bool);
 void		npf_session_release(npf_session_t *);
 void		npf_session_expire(npf_session_t *);
 bool		npf_session_pass(const npf_session_t *, npf_rproc_t **);
--- a/sys/net/npf/npf_nat.c	Fri Mar 14 11:27:36 2014 +0000
+++ b/sys/net/npf/npf_nat.c	Fri Mar 14 11:29:44 2014 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_nat.c,v 1.26 2014/02/19 03:51:31 rmind Exp $	*/
+/*	$NetBSD: npf_nat.c,v 1.27 2014/03/14 11:29:44 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2014 Mindaugas Rasiukevicius <rmind at netbsd org>
@@ -71,7 +71,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_nat.c,v 1.26 2014/02/19 03:51:31 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_nat.c,v 1.27 2014/03/14 11:29:44 rmind Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -669,7 +669,7 @@
 	 * stream depends on other, stateless filtering rules.
 	 */
 	if (se == NULL) {
-		nse = npf_session_establish(npc, nbuf, di);
+		nse = npf_session_establish(npc, nbuf, di, true);
 		if (nse == NULL) {
 			atomic_dec_uint(&np->n_refcnt);
 			return ENOMEM;
--- a/sys/net/npf/npf_session.c	Fri Mar 14 11:27:36 2014 +0000
+++ b/sys/net/npf/npf_session.c	Fri Mar 14 11:29:44 2014 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_session.c,v 1.30 2013/12/06 01:33:37 rmind Exp $	*/
+/*	$NetBSD: npf_session.c,v 1.31 2014/03/14 11:29:44 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2010-2013 The NetBSD Foundation, Inc.
@@ -92,7 +92,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_session.c,v 1.30 2013/12/06 01:33:37 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_session.c,v 1.31 2014/03/14 11:29:44 rmind Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -260,19 +260,12 @@
 	const int sz = sen1->se_alen;
 	int ret;
 
-	/*
-	 * Ports are expected to vary most, therefore they are first.
-	 */
 	if (sen1->se_src_id != sen2->se_src_id) {
 		return (sen1->se_src_id < sen2->se_src_id) ? -1 : 1;
 	}
 	if (sen1->se_dst_id != sen2->se_dst_id) {
 		return (sen1->se_dst_id < sen2->se_dst_id) ? -1 : 1;
 	}
-
-	/*
-	 * Note that hash should minimise differentiation on addresses.
-	 */
 	if (sen1->se_alen != sen2->se_alen) {
 		return (sen1->se_alen < sen2->se_alen) ? -1 : 1;
 	}
@@ -285,7 +278,19 @@
 
 	const npf_secomid_t *id1 = &sen1->se_backptr->s_common_id;
 	const npf_secomid_t *id2 = ctx ? ctx : &sen2->se_backptr->s_common_id;
-	return memcmp(id1, id2, sizeof(npf_secomid_t));
+
+	if (id1->proto != id2->proto) {
+		return (id1->proto < id2->proto) ? -1 : 1;
+	}
+
+	/*
+	 * Zero interface ID is a special case indicating a global state,
+	 * in which case we match straight away.
+	 */
+	if (id1->ifid && id1->ifid != id2->ifid) {
+		return (id1->ifid < id2->ifid) ? -1 : 1;
+	}
+	return 0;
 }
 
 static signed int
@@ -312,8 +317,7 @@
 	const int sz = sen->se_alen;
 	uint32_t hash, mix[2];
 
-	mix[0] = (scid->proto ^ scid->ifid) << 16;
-	mix[0] |= sen->se_src_id ^ sen->se_dst_id;
+	mix[0] = (scid->proto << 16) | (sen->se_src_id ^ sen->se_dst_id);
 	mix[1] = npf_addr_mix(sz, &sen->se_src_addr, &sen->se_dst_addr);
 	hash = murmurhash2(mix, sizeof(mix), sess_hash_seed);
 
@@ -486,6 +490,7 @@
     const int di, bool *forw)
 {
 	const u_int proto = npc->npc_proto;
+	const u_int ifid = nbuf->nb_ifid;
 	npf_sentry_t senkey, *sen;
 	npf_session_t *se;
 	npf_sehash_t *sh;
@@ -505,9 +510,7 @@
 	 * Note: this is a special case where we use common ID pointer
 	 * to pass the structure for the key comparator.
 	 */
-	npf_secomid_t scid;
-	memset(&scid, 0, sizeof(npf_secomid_t));
-	scid = (npf_secomid_t){ .proto = proto, .ifid = nbuf->nb_ifid };
+	npf_secomid_t scid = { .proto = proto, .ifid = ifid };
 	senkey.se_common_id = &scid;
 
 	/*
@@ -528,7 +531,7 @@
 	}
 	se = sen->se_backptr;
 	KASSERT(se->s_common_id.proto == proto);
-	KASSERT(se->s_common_id.ifid == nbuf->nb_ifid);
+	KASSERT(se->s_common_id.ifid == 0 || se->s_common_id.ifid == ifid);
 	flags = se->s_flags;
 
 	/* Check if session is active and not expired. */
@@ -597,13 +600,13 @@
 }
 
 /*
- * npf_establish_session: create a new session, insert into the global list.
+ * npf_session_establish: create a new session, insert into the global list.
  *
  * => Session is created with the reference held for the caller.
  * => Session will be activated on the first reference release.
  */
 npf_session_t *
-npf_session_establish(npf_cache_t *npc, nbuf_t *nbuf, const int di)
+npf_session_establish(npf_cache_t *npc, nbuf_t *nbuf, int di, bool per_if)
 {
 	npf_sentry_t *fw, *bk;
 	npf_sehash_t *sh;
@@ -612,6 +615,7 @@
 	bool ok;
 
 	KASSERT(!nbuf_flag_p(nbuf, NBUF_DATAREF_RESET));
+
 	if (!npf_session_trackable_p(npc)) {
 		return NULL;
 	}
@@ -644,9 +648,8 @@
 	memcpy(&fw->se_dst_addr, npc->npc_ips[NPF_DST], alen);
 
 	/* Protocol and interface. */
-	memset(&se->s_common_id, 0, sizeof(npf_secomid_t));
 	se->s_common_id.proto = npc->npc_proto;
-	se->s_common_id.ifid = nbuf->nb_ifid;
+	se->s_common_id.ifid = per_if ? nbuf->nb_ifid : 0;
 
 	/* Setup "forwards" entry. */
 	if (!npf_session_fillent(npc, fw)) {
--- a/usr.sbin/npf/npfctl/npf_parse.y	Fri Mar 14 11:27:36 2014 +0000
+++ b/usr.sbin/npf/npfctl/npf_parse.y	Fri Mar 14 11:29:44 2014 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_parse.y,v 1.33 2014/02/17 00:45:24 rmind Exp $	*/
+/*	$NetBSD: npf_parse.y,v 1.34 2014/03/14 11:29:45 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2011-2014 The NetBSD Foundation, Inc.
@@ -136,6 +136,7 @@
 %token			SEPLINE
 %token			SLASH
 %token			STATEFUL
+%token			STATEFUL_ENDS
 %token			TABLE
 %token			TCP
 %token			TO
@@ -553,6 +554,7 @@
 
 opt_stateful
 	: STATEFUL	{ $$ = NPF_RULE_STATEFUL; }
+	| STATEFUL_ENDS	{ $$ = NPF_RULE_STATEFUL | NPF_RULE_MULTIENDS; }
 	|		{ $$ = 0; }
 	;
 
--- a/usr.sbin/npf/npfctl/npf_scan.l	Fri Mar 14 11:27:36 2014 +0000
+++ b/usr.sbin/npf/npfctl/npf_scan.l	Fri Mar 14 11:29:44 2014 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_scan.l,v 1.19 2014/02/13 03:34:40 rmind Exp $	*/
+/*	$NetBSD: npf_scan.l,v 1.20 2014/03/14 11:29:45 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2011-2012 The NetBSD Foundation, Inc.
@@ -118,6 +118,7 @@
 pass			return PASS;
 pcap-filter		return PCAP_FILTER;
 stateful		return STATEFUL;
+stateful-ends		return STATEFUL_ENDS;
 apply			return APPLY;
 final			return FINAL;
 quick			return FINAL;
--- a/usr.sbin/npf/npfctl/npf_show.c	Fri Mar 14 11:27:36 2014 +0000
+++ b/usr.sbin/npf/npfctl/npf_show.c	Fri Mar 14 11:29:44 2014 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: npf_show.c,v 1.12 2014/02/19 01:43:16 rmind Exp $	*/
+/*	$NetBSD: npf_show.c,v 1.13 2014/03/14 11:29:45 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2013 The NetBSD Foundation, Inc.
@@ -36,7 +36,7 @@
  */
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: npf_show.c,v 1.12 2014/02/19 01:43:16 rmind Exp $");
+__RCSID("$NetBSD: npf_show.c,v 1.13 2014/03/14 11:29:45 rmind Exp $");
 
 #include <sys/socket.h>
 #include <netinet/in.h>
@@ -218,6 +218,7 @@
  */
 
 #define	F(name)		__CONCAT(NPF_RULE_, name)
+#define	STATEFUL_ENDS	(NPF_RULE_STATEFUL | NPF_RULE_MULTIENDS)
 #define	NAME_AT		2
 
 static const struct attr_keyword_mapent {
@@ -232,7 +233,8 @@
 	{ F(RETRST)|F(RETICMP),	F(RETRST)|F(RETICMP),	"return"	},
 	{ F(RETRST)|F(RETICMP),	F(RETRST),		"return-rst"	},
 	{ F(RETRST)|F(RETICMP),	F(RETICMP),		"return-icmp"	},
-	{ F(STATEFUL),		F(STATEFUL),		"stateful"	},
+	{ STATEFUL_ENDS,	F(STATEFUL),		"stateful"	},
+	{ STATEFUL_ENDS,	STATEFUL_ENDS,		"stateful-ends"	},
 	{ F(DIMASK),		F(IN),			"in"		},
 	{ F(DIMASK),		F(OUT),			"out"		},
 	{ F(FINAL),		F(FINAL),		"final"		},