Module Name: src Committed By: rmind Date: Fri Jun 22 13:43:17 UTC 2012
Modified Files: src/sys/net/npf: npf.c npf.h npf_alg.c npf_impl.h npf_inet.c npf_instr.c npf_log.c npf_nat.c npf_sendpkt.c npf_session.c npf_state.c npf_state_tcp.c npf_tableset.c src/usr.sbin/npf/npftest/libnpftest: npf_table_test.c Log Message: NPF: - Rename some functions for consistency and de-inline them. - Fix few invalid asserts (add regressoin test). - Use pserialize(9) for ALG interface. - Minor fixes, sprinkle many comments. To generate a diff of this commit: cvs rdiff -u -r1.10 -r1.11 src/sys/net/npf/npf.c src/sys/net/npf/npf_instr.c \ src/sys/net/npf/npf_sendpkt.c src/sys/net/npf/npf_tableset.c cvs rdiff -u -r1.16 -r1.17 src/sys/net/npf/npf.h cvs rdiff -u -r1.3 -r1.4 src/sys/net/npf/npf_alg.c src/sys/net/npf/npf_log.c cvs rdiff -u -r1.15 -r1.16 src/sys/net/npf/npf_impl.h cvs rdiff -u -r1.11 -r1.12 src/sys/net/npf/npf_inet.c cvs rdiff -u -r1.12 -r1.13 src/sys/net/npf/npf_nat.c \ src/sys/net/npf/npf_session.c cvs rdiff -u -r1.7 -r1.8 src/sys/net/npf/npf_state.c cvs rdiff -u -r1.6 -r1.7 src/sys/net/npf/npf_state_tcp.c cvs rdiff -u -r1.1 -r1.2 src/usr.sbin/npf/npftest/libnpftest/npf_table_test.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/net/npf/npf.c diff -u src/sys/net/npf/npf.c:1.10 src/sys/net/npf/npf.c:1.11 --- src/sys/net/npf/npf.c:1.10 Tue Mar 13 18:40:59 2012 +++ src/sys/net/npf/npf.c Fri Jun 22 13:43:17 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: npf.c,v 1.10 2012/03/13 18:40:59 elad Exp $ */ +/* $NetBSD: npf.c,v 1.11 2012/06/22 13:43:17 rmind Exp $ */ /*- * Copyright (c) 2009-2010 The NetBSD Foundation, Inc. @@ -34,7 +34,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: npf.c,v 1.10 2012/03/13 18:40:59 elad Exp $"); +__KERNEL_RCSID(0, "$NetBSD: npf.c,v 1.11 2012/06/22 13:43:17 rmind Exp $"); #include <sys/param.h> #include <sys/types.h> @@ -48,6 +48,7 @@ __KERNEL_RCSID(0, "$NetBSD: npf.c,v 1.10 #include <sys/percpu.h> #include <sys/rwlock.h> #include <sys/socketvar.h> +#include <sys/sysctl.h> #include <sys/uio.h> #include "npf_impl.h" @@ -80,6 +81,7 @@ static int npfctl_stats(void *); static krwlock_t npf_lock __cacheline_aligned; static npf_core_t * npf_core __cacheline_aligned; static percpu_t * npf_stats_percpu __read_mostly; +static struct sysctllog * npf_sysctl __read_mostly; const struct cdevsw npf_cdevsw = { npf_dev_open, npf_dev_close, npf_dev_read, nowrite, npf_dev_ioctl, @@ -99,6 +101,8 @@ npf_init(void) rw_init(&npf_lock); npf_stats_percpu = percpu_alloc(NPF_STATS_SIZE); + npf_sysctl = NULL; + npf_tableset_sysinit(); npf_session_sysinit(); npf_nat_sysinit(); @@ -144,6 +148,10 @@ npf_fini(void) npf_nat_sysfini(); npf_session_sysfini(); npf_tableset_sysfini(); + + if (npf_sysctl) { + sysctl_teardown(&npf_sysctl); + } percpu_free(npf_stats_percpu, NPF_STATS_SIZE); rw_destroy(&npf_lock); Index: src/sys/net/npf/npf_instr.c diff -u src/sys/net/npf/npf_instr.c:1.10 src/sys/net/npf/npf_instr.c:1.11 --- src/sys/net/npf/npf_instr.c:1.10 Mon Feb 20 00:18:20 2012 +++ src/sys/net/npf/npf_instr.c Fri Jun 22 13:43:17 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: npf_instr.c,v 1.10 2012/02/20 00:18:20 rmind Exp $ */ +/* $NetBSD: npf_instr.c,v 1.11 2012/06/22 13:43:17 rmind Exp $ */ /*- * Copyright (c) 2009-2010 The NetBSD Foundation, Inc. @@ -34,7 +34,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: npf_instr.c,v 1.10 2012/02/20 00:18:20 rmind Exp $"); +__KERNEL_RCSID(0, "$NetBSD: npf_instr.c,v 1.11 2012/06/22 13:43:17 rmind Exp $"); #include <sys/param.h> #include <sys/types.h> @@ -129,7 +129,7 @@ npf_match_ipmask(npf_cache_t *npc, nbuf_ } addr = sd ? npc->npc_srcip : npc->npc_dstip; if (mask != NPF_NO_NETMASK) { - npf_calculate_masked_addr(&cmpaddr, addr, mask); + npf_addr_mask(addr, mask, &cmpaddr); addr = &cmpaddr; } return memcmp(netaddr, addr, npc->npc_ipsz) ? -1 : 0; Index: src/sys/net/npf/npf_sendpkt.c diff -u src/sys/net/npf/npf_sendpkt.c:1.10 src/sys/net/npf/npf_sendpkt.c:1.11 --- src/sys/net/npf/npf_sendpkt.c:1.10 Sun May 6 02:45:25 2012 +++ src/sys/net/npf/npf_sendpkt.c Fri Jun 22 13:43:17 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: npf_sendpkt.c,v 1.10 2012/05/06 02:45:25 rmind Exp $ */ +/* $NetBSD: npf_sendpkt.c,v 1.11 2012/06/22 13:43:17 rmind Exp $ */ /*- * Copyright (c) 2010-2011 The NetBSD Foundation, Inc. @@ -34,7 +34,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: npf_sendpkt.c,v 1.10 2012/05/06 02:45:25 rmind Exp $"); +__KERNEL_RCSID(0, "$NetBSD: npf_sendpkt.c,v 1.11 2012/06/22 13:43:17 rmind Exp $"); #include <sys/param.h> #include <sys/types.h> @@ -108,7 +108,7 @@ npf_return_tcp(npf_cache_t *npc) memset(ip, 0, len); /* - * First fill of IPv4 header, for TCP checksum. + * First, partially fill IPv4 header for TCP checksum. * Note: IP length contains TCP header length. */ ip->ip_p = IPPROTO_TCP; @@ -134,7 +134,9 @@ npf_return_tcp(npf_cache_t *npc) th = (struct tcphdr *)(ip6 + 1); } - /* Construct TCP header and compute the checksum. */ + /* + * Construct TCP header and compute the checksum. + */ th->th_sport = oth->th_dport; th->th_dport = oth->th_sport; th->th_seq = htonl(ack); @@ -148,7 +150,9 @@ npf_return_tcp(npf_cache_t *npc) if (npf_iscached(npc, NPC_IP4)) { th->th_sum = in_cksum(m, len); - /* Second fill of IPv4 header, fill correct IP length. */ + /* + * Second, fill the rest of IPv4 header and correct IP length. + */ ip->ip_v = IPVERSION; ip->ip_hl = sizeof(struct ip) >> 2; ip->ip_tos = IPTOS_LOWDELAY; Index: src/sys/net/npf/npf_tableset.c diff -u src/sys/net/npf/npf_tableset.c:1.10 src/sys/net/npf/npf_tableset.c:1.11 --- src/sys/net/npf/npf_tableset.c:1.10 Mon Feb 20 00:18:20 2012 +++ src/sys/net/npf/npf_tableset.c Fri Jun 22 13:43:17 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: npf_tableset.c,v 1.10 2012/02/20 00:18:20 rmind Exp $ */ +/* $NetBSD: npf_tableset.c,v 1.11 2012/06/22 13:43:17 rmind Exp $ */ /*- * Copyright (c) 2009-2012 The NetBSD Foundation, Inc. @@ -39,7 +39,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: npf_tableset.c,v 1.10 2012/02/20 00:18:20 rmind Exp $"); +__KERNEL_RCSID(0, "$NetBSD: npf_tableset.c,v 1.11 2012/06/22 13:43:17 rmind Exp $"); #include <sys/param.h> #include <sys/types.h> @@ -164,7 +164,7 @@ table_rbtree_cmp_nodes(void *ctx, const const npf_tblent_t * const te1 = n1; const npf_tblent_t * const te2 = n2; - return npf_compare_cidr(&te1->te_addr, te1->te_mask, + return npf_addr_cmp(&te1->te_addr, te1->te_mask, &te2->te_addr, te2->te_mask); } @@ -174,7 +174,7 @@ table_rbtree_cmp_key(void *ctx, const vo const npf_tblent_t * const te = n1; const npf_addr_t *t2 = key; - return npf_compare_cidr(&te->te_addr, te->te_mask, t2, NPF_NO_NETMASK); + return npf_addr_cmp(&te->te_addr, te->te_mask, t2, NPF_NO_NETMASK); } static const rb_tree_ops_t table_rbtree_ops = { @@ -366,7 +366,7 @@ npf_table_add_cidr(npf_tableset_t *tset, switch (t->t_type) { case NPF_TABLE_HASH: /* Generate hash value from: address & mask. */ - npf_calculate_masked_addr(&val, addr, mask); + npf_addr_mask(addr, mask, &val); htbl = table_hash_bucket(t, &val, sizeof(npf_addr_t)); /* Lookup to check for duplicates. */ LIST_FOREACH(it, htbl, te_entry.hashq) { @@ -428,7 +428,7 @@ npf_table_rem_cidr(npf_tableset_t *tset, switch (t->t_type) { case NPF_TABLE_HASH: /* Generate hash value from: (address & mask). */ - npf_calculate_masked_addr(&val, addr, mask); + npf_addr_mask(addr, mask, &val); htbl = table_hash_bucket(t, &val, sizeof(npf_addr_t)); LIST_FOREACH(e, htbl, te_entry.hashq) { if (e->te_mask != mask) { @@ -446,7 +446,7 @@ npf_table_rem_cidr(npf_tableset_t *tset, break; case NPF_TABLE_TREE: /* Key: (address & mask). */ - npf_calculate_masked_addr(&val, addr, mask); + npf_addr_mask(addr, mask, &val); e = rb_tree_find_node(&t->t_rbtree, &val); if (__predict_true(e != NULL)) { rb_tree_remove_node(&t->t_rbtree, e); @@ -486,20 +486,23 @@ npf_table_match_addr(npf_tableset_t *tse case NPF_TABLE_HASH: htbl = table_hash_bucket(t, addr, sizeof(npf_addr_t)); LIST_FOREACH(e, htbl, te_entry.hashq) { - if (npf_compare_cidr(addr, e->te_mask, &e->te_addr, + if (npf_addr_cmp(addr, e->te_mask, &e->te_addr, NPF_NO_NETMASK) == 0) break; } break; case NPF_TABLE_TREE: e = rb_tree_find_node(&t->t_rbtree, addr); - KASSERT(e && npf_compare_cidr(addr, e->te_mask, &e->te_addr, - NPF_NO_NETMASK) == 0); break; default: KASSERT(false); } npf_table_put(t); - return e ? 0 : ENOENT; + if (e == NULL) { + return ENOENT; + } + KASSERT(npf_addr_cmp(addr, e->te_mask, &e->te_addr, + NPF_NO_NETMASK) == 0); + return 0; } Index: src/sys/net/npf/npf.h diff -u src/sys/net/npf/npf.h:1.16 src/sys/net/npf/npf.h:1.17 --- src/sys/net/npf/npf.h:1.16 Sat Apr 14 19:01:21 2012 +++ src/sys/net/npf/npf.h Fri Jun 22 13:43:17 2012 @@ -1,7 +1,7 @@ -/* $NetBSD: npf.h,v 1.16 2012/04/14 19:01:21 rmind Exp $ */ +/* $NetBSD: npf.h,v 1.17 2012/06/22 13:43:17 rmind Exp $ */ /*- - * Copyright (c) 2009-2011 The NetBSD Foundation, Inc. + * Copyright (c) 2009-2012 The NetBSD Foundation, Inc. * All rights reserved. * * This material is based upon work partially supported by The @@ -110,72 +110,6 @@ typedef struct { } npc_l4; } npf_cache_t; -static inline void -npf_generate_mask(npf_addr_t *dst, const npf_netmask_t omask) -{ - uint_fast8_t length = omask; - - /* Note: maximum length is 32 for IPv4 and 128 for IPv6. */ - KASSERT(length <= NPF_MAX_NETMASK); - - for (int i = 0; i < 4; i++) { - if (length >= 32) { - dst->s6_addr32[i] = htonl(0xffffffff); - length -= 32; - } else { - dst->s6_addr32[i] = htonl(0xffffffff << (32 - length)); - length = 0; - } - } -} - -static inline void -npf_calculate_masked_addr(npf_addr_t *dst, const npf_addr_t *src, - const npf_netmask_t omask) -{ - npf_addr_t mask; - - npf_generate_mask(&mask, omask); - for (int i = 0; i < 4; i++) { - dst->s6_addr32[i] = src->s6_addr32[i] & mask.s6_addr32[i]; - } -} - -/* - * npf_compare_cidr: compare two addresses, either IPv4 or IPv6. - * - * => If the mask is NULL, ignore it. - */ -static inline int -npf_compare_cidr(const npf_addr_t *addr1, const npf_netmask_t mask1, - const npf_addr_t *addr2, const npf_netmask_t mask2) -{ - npf_addr_t realmask1, realmask2; - - if (mask1 != NPF_NO_NETMASK) { - npf_generate_mask(&realmask1, mask1); - } - if (mask2 != NPF_NO_NETMASK) { - npf_generate_mask(&realmask2, mask2); - } - for (int i = 0; i < 4; i++) { - const uint32_t x = mask1 != NPF_NO_NETMASK ? - addr1->s6_addr32[i] & realmask1.s6_addr32[i] : - addr1->s6_addr32[i]; - const uint32_t y = mask2 != NPF_NO_NETMASK ? - addr2->s6_addr32[i] & realmask2.s6_addr32[i] : - addr2->s6_addr32[i]; - if (x < y) { - return -1; - } - if (x > y) { - return 1; - } - } - - return 0; -} - static inline bool npf_iscached(const npf_cache_t *npc, const int inf) { Index: src/sys/net/npf/npf_alg.c diff -u src/sys/net/npf/npf_alg.c:1.3 src/sys/net/npf/npf_alg.c:1.4 --- src/sys/net/npf/npf_alg.c:1.3 Mon Feb 20 00:18:19 2012 +++ src/sys/net/npf/npf_alg.c Fri Jun 22 13:43:17 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: npf_alg.c,v 1.3 2012/02/20 00:18:19 rmind Exp $ */ +/* $NetBSD: npf_alg.c,v 1.4 2012/06/22 13:43:17 rmind Exp $ */ /*- * Copyright (c) 2010 The NetBSD Foundation, Inc. @@ -31,16 +31,17 @@ /* * NPF interface for application level gateways (ALGs). - * - * XXX: locking */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: npf_alg.c,v 1.3 2012/02/20 00:18:19 rmind Exp $"); +__KERNEL_RCSID(0, "$NetBSD: npf_alg.c,v 1.4 2012/06/22 13:43:17 rmind Exp $"); #include <sys/param.h> +#include <sys/types.h> + #include <sys/kmem.h> -#include <sys/pool.h> +#include <sys/pserialize.h> +#include <sys/mutex.h> #include <net/pfil.h> #include "npf_impl.h" @@ -55,12 +56,16 @@ struct npf_alg { npf_algfunc_t na_seid_func; }; -static LIST_HEAD(, npf_alg) nat_alg_list __read_mostly; +static LIST_HEAD(, npf_alg) nat_alg_list __cacheline_aligned; +static kmutex_t nat_alg_lock __cacheline_aligned; +static pserialize_t nat_alg_psz __cacheline_aligned; void npf_alg_sysinit(void) { + mutex_init(&nat_alg_lock, MUTEX_DEFAULT, IPL_NONE); + nat_alg_psz = pserialize_create(); LIST_INIT(&nat_alg_list); } @@ -69,6 +74,8 @@ npf_alg_sysfini(void) { KASSERT(LIST_EMPTY(&nat_alg_list)); + pserialize_destroy(nat_alg_psz); + mutex_destroy(&nat_alg_lock); } /* @@ -88,7 +95,11 @@ npf_alg_register(npf_algfunc_t match, np alg->na_out_func = out; alg->na_in_func = in; alg->na_seid_func = seid; + + mutex_enter(&nat_alg_lock); LIST_INSERT_HEAD(&nat_alg_list, alg, na_entry); + mutex_exit(&nat_alg_lock); + return alg; } @@ -98,17 +109,15 @@ npf_alg_register(npf_algfunc_t match, np int npf_alg_unregister(npf_alg_t *alg) { - npf_alg_t *it; - LIST_FOREACH(it, &nat_alg_list, na_entry) { - if (alg == it) - break; - } - if (it != NULL) { - LIST_REMOVE(alg, na_entry); - } - /* TODO: Flush relevant sessions. */ + mutex_enter(&nat_alg_lock); + LIST_REMOVE(alg, na_entry); + pserialize_perform(nat_alg_psz); + mutex_exit(&nat_alg_lock); + + npf_nat_freealg(alg); kmem_free(alg, sizeof(npf_alg_t)); + return 0; } @@ -119,15 +128,20 @@ bool npf_alg_match(npf_cache_t *npc, nbuf_t *nbuf, npf_nat_t *nt) { npf_alg_t *alg; - npf_algfunc_t func; + bool match = false; + int s; + s = pserialize_read_enter(); LIST_FOREACH(alg, &nat_alg_list, na_entry) { - func = alg->na_match_func; + npf_algfunc_t func = alg->na_match_func; + if (func && func(npc, nbuf, nt)) { - return true; + match = true; + break; } } - return false; + pserialize_read_exit(s); + return match; } /* @@ -137,7 +151,9 @@ void npf_alg_exec(npf_cache_t *npc, nbuf_t *nbuf, npf_nat_t *nt, const int di) { npf_alg_t *alg; + int s; + s = pserialize_read_enter(); LIST_FOREACH(alg, &nat_alg_list, na_entry) { if ((di & PFIL_OUT) != 0 && alg->na_out_func != NULL) { (alg->na_out_func)(npc, nbuf, nt); @@ -148,19 +164,25 @@ npf_alg_exec(npf_cache_t *npc, nbuf_t *n continue; } } + pserialize_read_exit(s); } bool npf_alg_sessionid(npf_cache_t *npc, nbuf_t *nbuf, npf_cache_t *key) { npf_alg_t *alg; - npf_algfunc_t func; + bool nkey = false; + int s; + s = pserialize_read_enter(); LIST_FOREACH(alg, &nat_alg_list, na_entry) { - func = alg->na_seid_func; + npf_algfunc_t func = alg->na_seid_func; + if (func && func(npc, nbuf, (npf_nat_t *)key)) { - return true; + nkey = true; + break; } } - return false; + pserialize_read_exit(s); + return nkey; } Index: src/sys/net/npf/npf_log.c diff -u src/sys/net/npf/npf_log.c:1.3 src/sys/net/npf/npf_log.c:1.4 --- src/sys/net/npf/npf_log.c:1.3 Mon Feb 20 00:18:20 2012 +++ src/sys/net/npf/npf_log.c Fri Jun 22 13:43:17 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: npf_log.c,v 1.3 2012/02/20 00:18:20 rmind Exp $ */ +/* $NetBSD: npf_log.c,v 1.4 2012/06/22 13:43:17 rmind Exp $ */ /*- * Copyright (c) 2010-2011 The NetBSD Foundation, Inc. @@ -34,7 +34,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: npf_log.c,v 1.3 2012/02/20 00:18:20 rmind Exp $"); +__KERNEL_RCSID(0, "$NetBSD: npf_log.c,v 1.4 2012/06/22 13:43:17 rmind Exp $"); #include <sys/param.h> #include <sys/types.h> @@ -58,7 +58,7 @@ typedef struct npflog_softc { int sc_unit; } npflog_softc_t; -static int npflog_clone_create(struct if_clone *, int ); +static int npflog_clone_create(struct if_clone *, int); static int npflog_clone_destroy(ifnet_t *); static LIST_HEAD(, npflog_softc) npflog_if_list __cacheline_aligned; @@ -120,11 +120,13 @@ npflog_clone_create(struct if_clone *ifc ifp->if_dlt = DLT_NULL; ifp->if_ioctl = npflog_ioctl; + KERNEL_LOCK(1, NULL); if_attach(ifp); if_alloc_sadl(ifp); bpf_attach(ifp, DLT_NULL, 0); - LIST_INSERT_HEAD(&npflog_if_list, sc, sc_entry); + KERNEL_UNLOCK_ONE(NULL); + return 0; } @@ -133,9 +135,12 @@ npflog_clone_destroy(ifnet_t *ifp) { npflog_softc_t *sc = ifp->if_softc; + KERNEL_LOCK(1, NULL); LIST_REMOVE(sc, sc_entry); bpf_detach(ifp); if_detach(ifp); + KERNEL_UNLOCK_ONE(NULL); + mutex_destroy(&sc->sc_lock); kmem_free(sc, sizeof(npflog_softc_t)); return 0; @@ -148,13 +153,6 @@ npf_log_packet(npf_cache_t *npc, nbuf_t ifnet_t *ifp; int family; - /* Find a pseudo-interface to log. */ - ifp = if_byindex(if_idx); - if (ifp == NULL) { - /* No interface. */ - return; - } - /* Set the address family. */ if (npf_iscached(npc, NPC_IP4)) { family = AF_INET; @@ -164,8 +162,17 @@ npf_log_packet(npf_cache_t *npc, nbuf_t family = AF_UNSPEC; } - /* Pass through BPF. */ KERNEL_LOCK(1, NULL); + + /* Find a pseudo-interface to log. */ + ifp = if_byindex(if_idx); + if (ifp == NULL) { + /* No interface. */ + KERNEL_UNLOCK_ONE(NULL); + return; + } + + /* Pass through BPF. */ ifp->if_opackets++; ifp->if_obytes += m->m_pkthdr.len; bpf_mtap_af(ifp, family, m); Index: src/sys/net/npf/npf_impl.h diff -u src/sys/net/npf/npf_impl.h:1.15 src/sys/net/npf/npf_impl.h:1.16 --- src/sys/net/npf/npf_impl.h:1.15 Wed May 30 21:38:03 2012 +++ src/sys/net/npf/npf_impl.h Fri Jun 22 13:43:17 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: npf_impl.h,v 1.15 2012/05/30 21:38:03 rmind Exp $ */ +/* $NetBSD: npf_impl.h,v 1.16 2012/06/22 13:43:17 rmind Exp $ */ /*- * Copyright (c) 2009-2012 The NetBSD Foundation, Inc. @@ -177,7 +177,13 @@ uint16_t npf_fixup16_cksum(uint16_t, uin uint16_t npf_fixup32_cksum(uint16_t, uint32_t, uint32_t); uint16_t npf_addr_cksum(uint16_t, int, npf_addr_t *, npf_addr_t *); uint32_t npf_addr_sum(const int, const npf_addr_t *, const npf_addr_t *); -int npf_tcpsaw(npf_cache_t *, tcp_seq *, tcp_seq *, uint32_t *); +int npf_addr_cmp(const npf_addr_t *, const npf_netmask_t, + const npf_addr_t *, const npf_netmask_t); +void npf_addr_mask(const npf_addr_t *, const npf_netmask_t, + npf_addr_t *); + +int npf_tcpsaw(const npf_cache_t *, tcp_seq *, tcp_seq *, + uint32_t *); bool npf_fetch_tcpopts(const npf_cache_t *, nbuf_t *, uint16_t *, int *); bool npf_normalize(npf_cache_t *, nbuf_t *, bool, bool, u_int, u_int); @@ -291,6 +297,7 @@ void npf_nat_expire(npf_nat_t *); void npf_nat_getorig(npf_nat_t *, npf_addr_t **, in_port_t *); void npf_nat_gettrans(npf_nat_t *, npf_addr_t **, in_port_t *); void npf_nat_setalg(npf_nat_t *, npf_alg_t *, uintptr_t); +void npf_nat_freealg(npf_alg_t *); int npf_nat_save(prop_dictionary_t, prop_array_t, npf_nat_t *); npf_nat_t * npf_nat_restore(prop_dictionary_t, npf_session_t *); Index: src/sys/net/npf/npf_inet.c diff -u src/sys/net/npf/npf_inet.c:1.11 src/sys/net/npf/npf_inet.c:1.12 --- src/sys/net/npf/npf_inet.c:1.11 Mon Feb 20 00:18:19 2012 +++ src/sys/net/npf/npf_inet.c Fri Jun 22 13:43:17 2012 @@ -1,7 +1,7 @@ -/* $NetBSD: npf_inet.c,v 1.11 2012/02/20 00:18:19 rmind Exp $ */ +/* $NetBSD: npf_inet.c,v 1.12 2012/06/22 13:43:17 rmind Exp $ */ /*- - * Copyright (c) 2009-2011 The NetBSD Foundation, Inc. + * Copyright (c) 2009-2012 The NetBSD Foundation, Inc. * All rights reserved. * * This material is based upon work partially supported by The @@ -31,10 +31,15 @@ /* * Various procotol related helper routines. + * + * This layer manipulates npf_cache_t structure i.e. caches requested headers + * and stores which information was cached in the information bit field. + * It is also responsibility of this layer to update or invalidate the cache + * on rewrites (e.g. by translation routines). */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: npf_inet.c,v 1.11 2012/02/20 00:18:19 rmind Exp $"); +__KERNEL_RCSID(0, "$NetBSD: npf_inet.c,v 1.12 2012/06/22 13:43:17 rmind Exp $"); #include <sys/param.h> #include <sys/types.h> @@ -121,14 +126,86 @@ npf_addr_sum(const int sz, const npf_add return mix; } +static inline void +npf_generate_mask(npf_addr_t *out, const npf_netmask_t mask) +{ + uint_fast8_t length = mask; + + /* Note: maximum length is 32 for IPv4 and 128 for IPv6. */ + KASSERT(length <= NPF_MAX_NETMASK); + + for (int i = 0; i < 4; i++) { + if (length >= 32) { + out->s6_addr32[i] = htonl(0xffffffff); + length -= 32; + } else { + out->s6_addr32[i] = htonl(0xffffffff << (32 - length)); + length = 0; + } + } +} + +/* + * npf_addr_mask: apply the mask to a given address and store the result. + */ +void +npf_addr_mask(const npf_addr_t *addr, const npf_netmask_t mask, npf_addr_t *out) +{ + npf_addr_t realmask; + + npf_generate_mask(&realmask, mask); + + for (int i = 0; i < 4; i++) { + out->s6_addr32[i] = addr->s6_addr32[i] & realmask.s6_addr32[i]; + } +} + +/* + * npf_addr_cmp: compare two addresses, either IPv4 or IPv6. + * + * => Ignore the mask, if NPF_NO_NETMASK is specified. + * => Return 0 if equal and -1 or 1 if less or greater accordingly. + */ +int +npf_addr_cmp(const npf_addr_t *addr1, const npf_netmask_t mask1, + const npf_addr_t *addr2, const npf_netmask_t mask2) +{ + npf_addr_t realmask1, realmask2; + + if (mask1 != NPF_NO_NETMASK) { + npf_generate_mask(&realmask1, mask1); + } + if (mask2 != NPF_NO_NETMASK) { + npf_generate_mask(&realmask2, mask2); + } + + for (int i = 0; i < 4; i++) { + const uint32_t x = mask1 != NPF_NO_NETMASK ? + addr1->s6_addr32[i] & realmask1.s6_addr32[i] : + addr1->s6_addr32[i]; + const uint32_t y = mask2 != NPF_NO_NETMASK ? + addr2->s6_addr32[i] & realmask2.s6_addr32[i] : + addr2->s6_addr32[i]; + if (x < y) { + return -1; + } + if (x > y) { + return 1; + } + } + + return 0; +} + /* * npf_tcpsaw: helper to fetch SEQ, ACK, WIN and return TCP data length. - * Returns all values in host byte-order. + * + * => Returns all values in host byte-order. */ int -npf_tcpsaw(npf_cache_t *npc, tcp_seq *seq, tcp_seq *ack, uint32_t *win) +npf_tcpsaw(const npf_cache_t *npc, tcp_seq *seq, tcp_seq *ack, uint32_t *win) { - struct tcphdr *th = &npc->npc_l4.tcp; + const struct tcphdr *th = &npc->npc_l4.tcp; u_int thlen; KASSERT(npf_iscached(npc, NPC_TCP)); @@ -139,11 +216,10 @@ npf_tcpsaw(npf_cache_t *npc, tcp_seq *se thlen = th->th_off << 2; if (npf_iscached(npc, NPC_IP4)) { - struct ip *ip = &npc->npc_ip.v4; + const struct ip *ip = &npc->npc_ip.v4; return ntohs(ip->ip_len) - npf_cache_hlen(npc) - thlen; - } else { - KASSERT(npf_iscached(npc, NPC_IP6)); - struct ip6_hdr *ip6 = &npc->npc_ip.v6; + } else if (npf_iscached(npc, NPC_IP6)) { + const struct ip6_hdr *ip6 = &npc->npc_ip.v6; return ntohs(ip6->ip6_plen) - thlen; } return 0; @@ -179,6 +255,7 @@ next: if (nbuf_advfetch(&nbuf, &n_ptr, step, sizeof(val), &val)) { return false; } + switch (val) { case TCPOPT_EOL: /* Done. */ @@ -225,6 +302,7 @@ next: topts_len -= val; step = val - 1; } + /* Any options left? */ if (__predict_true(topts_len > 0)) { goto next; @@ -238,21 +316,21 @@ next: bool npf_fetch_ip(npf_cache_t *npc, nbuf_t *nbuf, void *n_ptr) { - struct ip *ip; - struct ip6_hdr *ip6; uint8_t ver; if (nbuf_fetch_datum(nbuf, n_ptr, sizeof(uint8_t), &ver)) { return false; } + switch (ver >> 4) { - case IPVERSION: - /* IPv4 */ - ip = &npc->npc_ip.v4; - /* Fetch the header. */ + case IPVERSION: { + struct ip *ip = &npc->npc_ip.v4; + + /* Fetch IPv4 header. */ if (nbuf_fetch_datum(nbuf, n_ptr, sizeof(struct ip), ip)) { return false; } + /* Check header length and fragment offset. */ if ((u_int)(ip->ip_hl << 2) < sizeof(struct ip)) { return false; @@ -261,6 +339,7 @@ npf_fetch_ip(npf_cache_t *npc, nbuf_t *n /* Note fragmentation. */ npc->npc_info |= NPC_IPFRAG; } + /* Cache: layer 3 - IPv4. */ npc->npc_ipsz = sizeof(struct in_addr); npc->npc_srcip = (npf_addr_t *)&ip->ip_src; @@ -269,31 +348,31 @@ npf_fetch_ip(npf_cache_t *npc, nbuf_t *n npc->npc_hlen = ip->ip_hl << 2; npc->npc_next_proto = npc->npc_ip.v4.ip_p; break; + } - case (IPV6_VERSION >> 4): - ip6 = &npc->npc_ip.v6; + case (IPV6_VERSION >> 4): { + struct ip6_hdr *ip6 = &npc->npc_ip.v6; + size_t toskip; + bool done; + + /* Fetch IPv6 header. */ if (nbuf_fetch_datum(nbuf, n_ptr, sizeof(struct ip6_hdr), ip6)) { return false; } - bool done = false; - uint_fast8_t next_proto; - size_t toskip; - /* Initial next-protocol value. */ - next_proto = ip6->ip6_nxt; + npc->npc_next_proto = ip6->ip6_nxt; toskip = sizeof(struct ip6_hdr); npc->npc_hlen = 0; + done = false; + /* + * Advance by the length of the previous known header and + * fetch by the lengh of next extension header. + */ do { struct ip6_ext ip6e; - npc->npc_next_proto = next_proto; - - /* - * Advance by the length of the previous known header - * and fetch the next extension header's length. - */ if (nbuf_advfetch(&nbuf, &n_ptr, toskip, sizeof(struct ip6_ext), &ip6e)) { return false; @@ -315,21 +394,28 @@ npf_fetch_ip(npf_cache_t *npc, nbuf_t *n break; } npc->npc_hlen += toskip; - next_proto = ip6e.ip6e_nxt; + npc->npc_next_proto = ip6e.ip6e_nxt; } while (!done); + /* Cache: layer 3 - IPv6. */ npc->npc_ipsz = sizeof(struct in6_addr); npc->npc_srcip = (npf_addr_t *)&ip6->ip6_src; npc->npc_dstip = (npf_addr_t *)&ip6->ip6_dst; npc->npc_info |= NPC_IP6; break; + } default: return false; } + return true; } +/* + * npf_fetch_tcp: fetch, check and cache TCP header. If necessary, + * fetch and cache layer 3 as well. + */ bool npf_fetch_tcp(npf_cache_t *npc, nbuf_t *nbuf, void *n_ptr) { @@ -355,6 +441,10 @@ npf_fetch_tcp(npf_cache_t *npc, nbuf_t * return true; } +/* + * npf_fetch_udp: fetch, check and cache UDP header. If necessary, + * fetch and cache layer 3 as well. + */ bool npf_fetch_udp(npf_cache_t *npc, nbuf_t *nbuf, void *n_ptr) { @@ -372,7 +462,7 @@ npf_fetch_udp(npf_cache_t *npc, nbuf_t * uh = &npc->npc_l4.udp; hlen = npf_cache_hlen(npc); - /* Fetch ICMP header. */ + /* Fetch UDP header. */ if (nbuf_advfetch(&nbuf, &n_ptr, hlen, sizeof(struct udphdr), uh)) { return false; } @@ -384,8 +474,6 @@ npf_fetch_udp(npf_cache_t *npc, nbuf_t * /* * npf_fetch_icmp: fetch ICMP code, type and possible query ID. - * - * => Stores both all fetched items into the cache. */ bool npf_fetch_icmp(npf_cache_t *npc, nbuf_t *nbuf, void *n_ptr) @@ -417,7 +505,7 @@ npf_fetch_icmp(npf_cache_t *npc, nbuf_t /* * npf_cache_all: general routine to cache all relevant IP (v4 or v6) - * and TCP, UDP or ICMP data. + * and TCP, UDP or ICMP headers. */ int npf_cache_all(npf_cache_t *npc, nbuf_t *nbuf) Index: src/sys/net/npf/npf_nat.c diff -u src/sys/net/npf/npf_nat.c:1.12 src/sys/net/npf/npf_nat.c:1.13 --- src/sys/net/npf/npf_nat.c:1.12 Sun Mar 11 18:27:59 2012 +++ src/sys/net/npf/npf_nat.c Fri Jun 22 13:43:17 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: npf_nat.c,v 1.12 2012/03/11 18:27:59 rmind Exp $ */ +/* $NetBSD: npf_nat.c,v 1.13 2012/06/22 13:43:17 rmind Exp $ */ /*- * Copyright (c) 2010-2011 The NetBSD Foundation, Inc. @@ -76,7 +76,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: npf_nat.c,v 1.12 2012/03/11 18:27:59 rmind Exp $"); +__KERNEL_RCSID(0, "$NetBSD: npf_nat.c,v 1.13 2012/06/22 13:43:17 rmind Exp $"); #include <sys/param.h> #include <sys/types.h> @@ -267,6 +267,12 @@ npf_nat_freepolicy(npf_natpolicy_t *np) kmem_free(np, sizeof(npf_natpolicy_t)); } +void +npf_nat_freealg(npf_alg_t *alg) +{ + (void)alg; /* TODO */ +} + /* * npf_nat_matchpolicy: compare two NAT policies. * Index: src/sys/net/npf/npf_session.c diff -u src/sys/net/npf/npf_session.c:1.12 src/sys/net/npf/npf_session.c:1.13 --- src/sys/net/npf/npf_session.c:1.12 Sun Mar 11 18:27:59 2012 +++ src/sys/net/npf/npf_session.c Fri Jun 22 13:43:17 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: npf_session.c,v 1.12 2012/03/11 18:27:59 rmind Exp $ */ +/* $NetBSD: npf_session.c,v 1.13 2012/06/22 13:43:17 rmind Exp $ */ /*- * Copyright (c) 2010-2012 The NetBSD Foundation, Inc. @@ -74,7 +74,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: npf_session.c,v 1.12 2012/03/11 18:27:59 rmind Exp $"); +__KERNEL_RCSID(0, "$NetBSD: npf_session.c,v 1.13 2012/06/22 13:43:17 rmind Exp $"); #include <sys/param.h> #include <sys/types.h> @@ -483,6 +483,7 @@ npf_session_inspect(npf_cache_t *npc, nb atomic_inc_uint(&se->s_refcnt); } else { /* Silently block invalid packets. */ + npf_stats_inc(NPF_STAT_INVALID_STATE); *error = ENETUNREACH; se = NULL; } Index: src/sys/net/npf/npf_state.c diff -u src/sys/net/npf/npf_state.c:1.7 src/sys/net/npf/npf_state.c:1.8 --- src/sys/net/npf/npf_state.c:1.7 Wed May 30 21:38:03 2012 +++ src/sys/net/npf/npf_state.c Fri Jun 22 13:43:17 2012 @@ -1,7 +1,7 @@ -/* $NetBSD: npf_state.c,v 1.7 2012/05/30 21:38:03 rmind Exp $ */ +/* $NetBSD: npf_state.c,v 1.8 2012/06/22 13:43:17 rmind Exp $ */ /*- - * Copyright (c) 2010-2011 The NetBSD Foundation, Inc. + * Copyright (c) 2010-2012 The NetBSD Foundation, Inc. * All rights reserved. * * This material is based upon work partially supported by The @@ -34,7 +34,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: npf_state.c,v 1.7 2012/05/30 21:38:03 rmind Exp $"); +__KERNEL_RCSID(0, "$NetBSD: npf_state.c,v 1.8 2012/06/22 13:43:17 rmind Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -54,7 +54,7 @@ __KERNEL_RCSID(0, "$NetBSD: npf_state.c, #define NPF_ANY_SESSION_ESTABLISHED 2 #define NPF_ANY_SESSION_NSTATES 3 -static const int npf_generic_fsm[NPF_ANY_SESSION_NSTATES][2] __read_mostly = { +static const int npf_generic_fsm[NPF_ANY_SESSION_NSTATES][2] = { [NPF_ANY_SESSION_CLOSED] = { [NPF_FLOW_FORW] = NPF_ANY_SESSION_NEW, }, @@ -68,12 +68,19 @@ static const int npf_generic_fsm[NPF_ANY }, }; -static const u_int npf_generic_timeout[] __read_mostly = { +static u_int npf_generic_timeout[] __read_mostly = { [NPF_ANY_SESSION_CLOSED] = 0, [NPF_ANY_SESSION_NEW] = 30, [NPF_ANY_SESSION_ESTABLISHED] = 60, }; +/* + * npf_state_init: initialise the state structure. + * + * Should normally be called on a first packet, which also determines the + * direction in a case of connection-orientated protocol. Returns true on + * success and false otherwise (e.g. if protocol is not supported). + */ bool npf_state_init(const npf_cache_t *npc, nbuf_t *nbuf, npf_state_t *nst) { @@ -111,6 +118,12 @@ npf_state_destroy(npf_state_t *nst) mutex_destroy(&nst->nst_lock); } +/* + * npf_state_inspect: inspect the packet according to the protocol state. + * + * Return true if packet is considered to match the state (e.g. for TCP, + * the packet belongs to the tracked connection) and false otherwise. + */ bool npf_state_inspect(const npf_cache_t *npc, nbuf_t *nbuf, npf_state_t *nst, const bool forw) @@ -137,9 +150,6 @@ npf_state_inspect(const npf_cache_t *npc NPF_TCP_STATE_SAMPLE(nst, ret); mutex_exit(&nst->nst_lock); - if (__predict_false(!ret)) { - npf_stats_inc(NPF_STAT_INVALID_STATE); - } return ret; } Index: src/sys/net/npf/npf_state_tcp.c diff -u src/sys/net/npf/npf_state_tcp.c:1.6 src/sys/net/npf/npf_state_tcp.c:1.7 --- src/sys/net/npf/npf_state_tcp.c:1.6 Tue Jun 5 22:46:54 2012 +++ src/sys/net/npf/npf_state_tcp.c Fri Jun 22 13:43:17 2012 @@ -1,7 +1,7 @@ -/* $NetBSD: npf_state_tcp.c,v 1.6 2012/06/05 22:46:54 rmind Exp $ */ +/* $NetBSD: npf_state_tcp.c,v 1.7 2012/06/22 13:43:17 rmind Exp $ */ /*- - * Copyright (c) 2010-2011 The NetBSD Foundation, Inc. + * Copyright (c) 2010-2012 The NetBSD Foundation, Inc. * All rights reserved. * * This material is based upon work partially supported by The @@ -34,7 +34,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: npf_state_tcp.c,v 1.6 2012/06/05 22:46:54 rmind Exp $"); +__KERNEL_RCSID(0, "$NetBSD: npf_state_tcp.c,v 1.7 2012/06/22 13:43:17 rmind Exp $"); #include <sys/param.h> #include <sys/types.h> @@ -440,6 +440,10 @@ npf_tcp_inwindow(const npf_cache_t *npc, return true; } +/* + * npf_state_tcp: inspect TCP segment, determine whether it belongs to + * the connection and track its state. + */ bool npf_state_tcp(const npf_cache_t *npc, nbuf_t *nbuf, npf_state_t *nst, int di) { @@ -447,7 +451,7 @@ npf_state_tcp(const npf_cache_t *npc, nb const int tcpfl = th->th_flags, state = nst->nst_state; int nstate; - KASSERT(mutex_owned(&nst->nst_lock)); + KASSERT(nst->nst_state == 0 || mutex_owned(&nst->nst_lock)); /* Look for a transition to a new state. */ if (__predict_true((tcpfl & TH_RST) == 0)) { Index: src/usr.sbin/npf/npftest/libnpftest/npf_table_test.c diff -u src/usr.sbin/npf/npftest/libnpftest/npf_table_test.c:1.1 src/usr.sbin/npf/npftest/libnpftest/npf_table_test.c:1.2 --- src/usr.sbin/npf/npftest/libnpftest/npf_table_test.c:1.1 Sat Apr 14 21:57:29 2012 +++ src/usr.sbin/npf/npftest/libnpftest/npf_table_test.c Fri Jun 22 13:43:17 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: npf_table_test.c,v 1.1 2012/04/14 21:57:29 rmind Exp $ */ +/* $NetBSD: npf_table_test.c,v 1.2 2012/06/22 13:43:17 rmind Exp $ */ /* * NPF tableset test. @@ -55,6 +55,15 @@ npf_table_test(bool verbose) error = npf_tableset_insert(tblset, t2); assert(error == 0); + /* Attempt to match non-existing entries - should fail. */ + addr->s6_addr32[0] = inet_addr(ip_list[0]); + + error = npf_table_match_addr(tblset, HASH_TID, addr); + assert(error != 0); + + error = npf_table_match_addr(tblset, TREE_TID, addr); + assert(error != 0); + /* Fill both tables with IP addresses. */ for (i = 0; i < __arraycount(ip_list); i++) { addr->s6_addr32[0] = inet_addr(ip_list[i]);