Module Name: src Committed By: christos Date: Sat Dec 10 05:41:10 UTC 2016
Modified Files: src/sys/net/npf: npf.c npf.h npf_conn.c npf_conn.h npf_ctl.c npf_impl.h Log Message: add functionality to lookup a nat entry from the connection list. To generate a diff of this commit: cvs rdiff -u -r1.31 -r1.32 src/sys/net/npf/npf.c cvs rdiff -u -r1.49 -r1.50 src/sys/net/npf/npf.h cvs rdiff -u -r1.17 -r1.18 src/sys/net/npf/npf_conn.c cvs rdiff -u -r1.8 -r1.9 src/sys/net/npf/npf_conn.h cvs rdiff -u -r1.43 -r1.44 src/sys/net/npf/npf_ctl.c cvs rdiff -u -r1.62 -r1.63 src/sys/net/npf/npf_impl.h 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.31 src/sys/net/npf/npf.c:1.32 --- src/sys/net/npf/npf.c:1.31 Thu Oct 29 11:19:43 2015 +++ src/sys/net/npf/npf.c Sat Dec 10 00:41:10 2016 @@ -1,4 +1,4 @@ -/* $NetBSD: npf.c,v 1.31 2015/10/29 15:19:43 christos Exp $ */ +/* $NetBSD: npf.c,v 1.32 2016/12/10 05:41:10 christos Exp $ */ /*- * Copyright (c) 2009-2013 The NetBSD Foundation, Inc. @@ -34,7 +34,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: npf.c,v 1.31 2015/10/29 15:19:43 christos Exp $"); +__KERNEL_RCSID(0, "$NetBSD: npf.c,v 1.32 2016/12/10 05:41:10 christos Exp $"); #include <sys/param.h> #include <sys/types.h> @@ -244,6 +244,9 @@ npf_dev_ioctl(dev_t dev, u_long cmd, voi case IOC_NPF_LOAD: error = npfctl_load(cmd, data); break; + case IOC_NPF_CONN_LOOKUP: + error = npfctl_conn_lookup(cmd, data); + break; case IOC_NPF_VERSION: *(int *)data = NPF_VERSION; error = 0; Index: src/sys/net/npf/npf.h diff -u src/sys/net/npf/npf.h:1.49 src/sys/net/npf/npf.h:1.50 --- src/sys/net/npf/npf.h:1.49 Thu Dec 8 21:26:36 2016 +++ src/sys/net/npf/npf.h Sat Dec 10 00:41:10 2016 @@ -1,4 +1,4 @@ -/* $NetBSD: npf.h,v 1.49 2016/12/09 02:26:36 christos Exp $ */ +/* $NetBSD: npf.h,v 1.50 2016/12/10 05:41:10 christos Exp $ */ /*- * Copyright (c) 2009-2014 The NetBSD Foundation, Inc. @@ -317,6 +317,7 @@ typedef struct npf_ioctl_table { #define IOC_NPF_STATS _IOW('N', 104, void *) #define IOC_NPF_SAVE _IOR('N', 105, struct plistref) #define IOC_NPF_RULE _IOWR('N', 107, struct plistref) +#define IOC_NPF_CONN_LOOKUP _IOWR('N', 108, struct plistref) /* * Statistics counters. Index: src/sys/net/npf/npf_conn.c diff -u src/sys/net/npf/npf_conn.c:1.17 src/sys/net/npf/npf_conn.c:1.18 --- src/sys/net/npf/npf_conn.c:1.17 Thu Dec 8 18:07:11 2016 +++ src/sys/net/npf/npf_conn.c Sat Dec 10 00:41:10 2016 @@ -1,4 +1,4 @@ -/* $NetBSD: npf_conn.c,v 1.17 2016/12/08 23:07:11 rmind Exp $ */ +/* $NetBSD: npf_conn.c,v 1.18 2016/12/10 05:41:10 christos Exp $ */ /*- * Copyright (c) 2014-2015 Mindaugas Rasiukevicius <rmind at netbsd org> @@ -99,7 +99,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: npf_conn.c,v 1.17 2016/12/08 23:07:11 rmind Exp $"); +__KERNEL_RCSID(0, "$NetBSD: npf_conn.c,v 1.18 2016/12/10 05:41:10 christos Exp $"); #include <sys/param.h> #include <sys/types.h> @@ -240,6 +240,45 @@ npf_conn_trackable_p(const npf_cache_t * return true; } +static uint32_t +connkey_setkey(npf_connkey_t *key, uint32_t proto, const void *ipv, + uint16_t *id, size_t alen, bool forw) +{ + uint32_t isrc, idst; + const npf_addr_t * const *ips = ipv; + if (__predict_true(forw)) { + isrc = NPF_SRC, idst = NPF_DST; + } else { + isrc = NPF_DST, idst = NPF_SRC; + } + + /* + * Construct a key formed out of 32-bit integers. The key layout: + * + * Field: | proto | alen | src-id | dst-id | src-addr | dst-addr | + * +--------+--------+--------+--------+----------+----------+ + * Bits: | 16 | 16 | 16 | 16 | 32-128 | 32-128 | + * + * The source and destination are inverted if they key is for the + * backwards stream (forw == false). The address length depends + * on the 'alen' field; it is a length in bytes, either 4 or 16. + */ + + key->ck_key[0] = ((uint32_t)proto << 16) | (alen & 0xffff); + key->ck_key[1] = ((uint32_t)id[isrc] << 16) | id[idst]; + + if (__predict_true(alen == sizeof(in_addr_t))) { + key->ck_key[2] = ips[isrc]->s6_addr32[0]; + key->ck_key[3] = ips[idst]->s6_addr32[0]; + return 4 * sizeof(uint32_t); + } else { + const u_int nwords = alen >> 2; + memcpy(&key->ck_key[2], ips[isrc], alen); + memcpy(&key->ck_key[2 + nwords], ips[idst], alen); + return (2 + (nwords * 2)) * sizeof(uint32_t); + } +} + /* * npf_conn_conkey: construct a key for the connection lookup. * @@ -251,7 +290,6 @@ npf_conn_conkey(const npf_cache_t *npc, const u_int alen = npc->npc_alen; const struct tcphdr *th; const struct udphdr *uh; - u_int keylen, isrc, idst; uint16_t id[2]; switch (npc->npc_proto) { @@ -288,38 +326,8 @@ npf_conn_conkey(const npf_cache_t *npc, return 0; } - if (__predict_true(forw)) { - isrc = NPF_SRC, idst = NPF_DST; - } else { - isrc = NPF_DST, idst = NPF_SRC; - } - - /* - * Construct a key formed out of 32-bit integers. The key layout: - * - * Field: | proto | alen | src-id | dst-id | src-addr | dst-addr | - * +--------+--------+--------+--------+----------+----------+ - * Bits: | 16 | 16 | 16 | 16 | 32-128 | 32-128 | - * - * The source and destination are inverted if they key is for the - * backwards stream (forw == false). The address length depends - * on the 'alen' field; it is a length in bytes, either 4 or 16. - */ - - key->ck_key[0] = ((uint32_t)npc->npc_proto << 16) | (alen & 0xffff); - key->ck_key[1] = ((uint32_t)id[isrc] << 16) | id[idst]; - - if (__predict_true(alen == sizeof(in_addr_t))) { - key->ck_key[2] = npc->npc_ips[isrc]->s6_addr32[0]; - key->ck_key[3] = npc->npc_ips[idst]->s6_addr32[0]; - keylen = 4 * sizeof(uint32_t); - } else { - const u_int nwords = alen >> 2; - memcpy(&key->ck_key[2], npc->npc_ips[isrc], alen); - memcpy(&key->ck_key[2 + nwords], npc->npc_ips[idst], alen); - keylen = (2 + (nwords * 2)) * sizeof(uint32_t); - } - return keylen; + return connkey_setkey(key, npc->npc_proto, npc->npc_ips, id, alen, + forw); } static __inline void @@ -343,6 +351,28 @@ connkey_set_id(npf_connkey_t *key, const } /* + * npf_conn_ok: check if the connection is active, and has the right direction. + */ +static bool +npf_conn_ok(npf_conn_t *con, const int di, bool forw) +{ + uint32_t flags = con->c_flags; + + /* Check if connection is active and not expired. */ + bool ok = (flags & (CONN_ACTIVE | CONN_EXPIRE)) == CONN_ACTIVE; + if (__predict_false(!ok)) { + return false; + } + + /* Check if the direction is consistent */ + bool pforw = (flags & PFIL_ALL) == di; + if (__predict_false(forw != pforw)) { + return false; + } + return true; +} + +/* * npf_conn_lookup: lookup if there is an established connection. * * => If found, we will hold a reference for the caller. @@ -353,8 +383,7 @@ npf_conn_lookup(const npf_cache_t *npc, const nbuf_t *nbuf = npc->npc_nbuf; npf_conn_t *con; npf_connkey_t key; - u_int flags, cifid; - bool ok, pforw; + u_int cifid; /* Construct a key and lookup for a connection in the store. */ if (!npf_conn_conkey(npc, &key, true)) { @@ -367,9 +396,7 @@ npf_conn_lookup(const npf_cache_t *npc, KASSERT(npc->npc_proto == con->c_proto); /* Check if connection is active and not expired. */ - flags = con->c_flags; - ok = (flags & (CONN_ACTIVE | CONN_EXPIRE)) == CONN_ACTIVE; - if (__predict_false(!ok)) { + if (!npf_conn_ok(con, di, *forw)) { atomic_dec_uint(&con->c_refcnt); return NULL; } @@ -383,11 +410,6 @@ npf_conn_lookup(const npf_cache_t *npc, atomic_dec_uint(&con->c_refcnt); return NULL; } - pforw = (flags & PFIL_ALL) == di; - if (__predict_false(*forw != pforw)) { - atomic_dec_uint(&con->c_refcnt); - return NULL; - } /* Update the last activity time. */ getnanouptime(&con->c_atime); @@ -917,6 +939,70 @@ npf_conn_export(const npf_conn_t *con) return cdict; } +static uint32_t +npf_connkey_import(prop_dictionary_t idict, npf_connkey_t *key, uint16_t *dir) +{ + uint16_t proto; + prop_object_t sobj, dobj; + uint16_t id[2]; + npf_addr_t const * ips[2]; + + prop_dictionary_get_uint16(idict, "proto", &proto); + prop_dictionary_get_uint16(idict, "direction", dir); + + prop_dictionary_get_uint16(idict, "sport", &id[NPF_SRC]); + prop_dictionary_get_uint16(idict, "dport", &id[NPF_DST]); + + sobj = prop_dictionary_get(idict, "saddr"); + if ((ips[NPF_SRC] = prop_data_data_nocopy(sobj)) == NULL) + return 0; + + dobj = prop_dictionary_get(idict, "daddr"); + if ((ips[NPF_DST] = prop_data_data_nocopy(dobj)) == NULL) + return 0; + + size_t alen = prop_data_size(sobj); + if (alen != prop_data_size(dobj)) + return 0; + *(const int *)ips[NPF_SRC], id[NPF_SRC], + *(const int *)ips[NPF_DST], id[NPF_DST], alen, proto, *dir); + + return connkey_setkey(key, proto, ips, id, alen, true); +} + +int +npf_conn_find(prop_dictionary_t idict, prop_dictionary_t *odict) +{ + npf_connkey_t key; + npf_conn_t *con; + uint16_t dir; + bool forw; + + if (!npf_connkey_import(idict, &key, &dir)) { + return EINVAL; + } + + con = npf_conndb_lookup(conn_db, &key, &forw); + if (con == NULL) { + return ESRCH; + } + + dir = dir == PFIL_IN ? PFIL_OUT : PFIL_IN; + if (!npf_conn_ok(con, dir, true)) { + atomic_dec_uint(&con->c_refcnt); + return ESRCH; + } + + *odict = npf_conn_export(con); + if (*odict == NULL) { + atomic_dec_uint(&con->c_refcnt); + return ENOSPC; + } + atomic_dec_uint(&con->c_refcnt); + + return 0; +} + /* * npf_conn_import: fully reconstruct a single connection from a * directory and insert into the given database. Index: src/sys/net/npf/npf_conn.h diff -u src/sys/net/npf/npf_conn.h:1.8 src/sys/net/npf/npf_conn.h:1.9 --- src/sys/net/npf/npf_conn.h:1.8 Sat Dec 20 11:19:43 2014 +++ src/sys/net/npf/npf_conn.h Sat Dec 10 00:41:10 2016 @@ -1,4 +1,4 @@ -/* $NetBSD: npf_conn.h,v 1.8 2014/12/20 16:19:43 rmind Exp $ */ +/* $NetBSD: npf_conn.h,v 1.9 2016/12/10 05:41:10 christos Exp $ */ /*- * Copyright (c) 2009-2014 The NetBSD Foundation, Inc. @@ -117,6 +117,7 @@ npf_nat_t * npf_conn_getnat(npf_conn_t * void npf_conn_gc(npf_conndb_t *, bool, bool); int npf_conn_import(npf_conndb_t *, prop_dictionary_t, npf_ruleset_t *); +int npf_conn_find(prop_dictionary_t, prop_dictionary_t *); prop_dictionary_t npf_conn_export(const npf_conn_t *); void npf_conn_print(const npf_conn_t *); Index: src/sys/net/npf/npf_ctl.c diff -u src/sys/net/npf/npf_ctl.c:1.43 src/sys/net/npf/npf_ctl.c:1.44 --- src/sys/net/npf/npf_ctl.c:1.43 Tue Oct 27 21:54:10 2015 +++ src/sys/net/npf/npf_ctl.c Sat Dec 10 00:41:10 2016 @@ -1,4 +1,4 @@ -/* $NetBSD: npf_ctl.c,v 1.43 2015/10/28 01:54:10 christos Exp $ */ +/* $NetBSD: npf_ctl.c,v 1.44 2016/12/10 05:41:10 christos Exp $ */ /*- * Copyright (c) 2009-2014 The NetBSD Foundation, Inc. @@ -37,7 +37,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: npf_ctl.c,v 1.43 2015/10/28 01:54:10 christos Exp $"); +__KERNEL_RCSID(0, "$NetBSD: npf_ctl.c,v 1.44 2016/12/10 05:41:10 christos Exp $"); #include <sys/param.h> #include <sys/conf.h> @@ -704,6 +704,32 @@ out: } /* + * npfctl_conn_lookup: lookup a connection in the list of connections + */ +int +npfctl_conn_lookup(u_long cmd, void *data) +{ + struct plistref *pref = data; + prop_dictionary_t conn_data, conn_result; + int error; + + error = prop_dictionary_copyin_ioctl(pref, cmd, &conn_data); + if (error) { + return error; + } + + error = npf_conn_find(conn_data, &conn_result); + if (error) { + goto out; + } + prop_dictionary_copyout_ioctl(pref, cmd, conn_result); + prop_object_release(conn_result); +out: + prop_object_release(conn_data); + return error; +} + +/* * npfctl_rule: add or remove dynamic rules in the specified ruleset. */ int Index: src/sys/net/npf/npf_impl.h diff -u src/sys/net/npf/npf_impl.h:1.62 src/sys/net/npf/npf_impl.h:1.63 --- src/sys/net/npf/npf_impl.h:1.62 Thu Dec 8 21:40:38 2016 +++ src/sys/net/npf/npf_impl.h Sat Dec 10 00:41:10 2016 @@ -1,4 +1,4 @@ -/* $NetBSD: npf_impl.h,v 1.62 2016/12/09 02:40:38 christos Exp $ */ +/* $NetBSD: npf_impl.h,v 1.63 2016/12/10 05:41:10 christos Exp $ */ /*- * Copyright (c) 2009-2014 The NetBSD Foundation, Inc. @@ -169,6 +169,7 @@ int npfctl_reload(u_long, void *); int npfctl_save(u_long, void *); int npfctl_load(u_long, void *); int npfctl_rule(u_long, void *); +int npfctl_conn_lookup(u_long, void *); int npfctl_table(void *); void npf_stats_inc(npf_stats_t);