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);