1fb07f475Srmind /*
2fb07f475Srmind * NPF initialisation and handler routines.
3fb07f475Srmind *
4fb07f475Srmind * Public Domain.
5fb07f475Srmind */
6fb07f475Srmind
7f75d79ebSchristos #ifdef _KERNEL
8fb07f475Srmind #include <sys/types.h>
9bb1fedd1Srmind #include <sys/cprng.h>
1039013e66Srmind #include <sys/kmem.h>
11fb07f475Srmind #include <net/if.h>
12fb07f475Srmind #include <net/if_types.h>
13f75d79ebSchristos #endif
14fb07f475Srmind
15fb07f475Srmind #include "npf_impl.h"
16fb07f475Srmind #include "npf_test.h"
17fb07f475Srmind
18fb07f475Srmind /* State of the current stream. */
19fb07f475Srmind static npf_state_t cstream_state;
20fb07f475Srmind static void * cstream_ptr;
21fb07f475Srmind static bool cstream_retval;
22fb07f475Srmind
23068cee29Srmind static long (*_random_func)(void);
24068cee29Srmind static int (*_pton_func)(int, const char *, void *);
25068cee29Srmind static const char * (*_ntop_func)(int, const void *, char *, socklen_t);
26068cee29Srmind
27e0cfa502Srmind static void npf_state_sample(npf_state_t *, bool);
28e0cfa502Srmind
2939013e66Srmind static void load_npf_config_ifs(nvlist_t *, bool);
3039013e66Srmind
31f75d79ebSchristos #ifndef __NetBSD__
32f75d79ebSchristos /*
33f75d79ebSchristos * Standalone NPF: we define the same struct ifnet members
34f75d79ebSchristos * to reduce the npf_ifops_t implementation differences.
35f75d79ebSchristos */
36f75d79ebSchristos struct ifnet {
37f75d79ebSchristos char if_xname[32];
38f75d79ebSchristos void * if_softc;
39f75d79ebSchristos TAILQ_ENTRY(ifnet) if_list;
40f75d79ebSchristos };
41f75d79ebSchristos #endif
42f75d79ebSchristos
43f75d79ebSchristos static TAILQ_HEAD(, ifnet) npftest_ifnet_list =
44f75d79ebSchristos TAILQ_HEAD_INITIALIZER(npftest_ifnet_list);
45f75d79ebSchristos
46b899bfd9Srmind static const char * npftest_ifop_getname(npf_t *, ifnet_t *);
47b899bfd9Srmind static ifnet_t * npftest_ifop_lookup(npf_t *, const char *);
48b899bfd9Srmind static void npftest_ifop_flush(npf_t *, void *);
49b899bfd9Srmind static void * npftest_ifop_getmeta(npf_t *, const ifnet_t *);
50b899bfd9Srmind static void npftest_ifop_setmeta(npf_t *, ifnet_t *, void *);
51f75d79ebSchristos
52dadc88e3Srmind const npf_ifops_t npftest_ifops = {
53f75d79ebSchristos .getname = npftest_ifop_getname,
54b899bfd9Srmind .lookup = npftest_ifop_lookup,
55f75d79ebSchristos .flush = npftest_ifop_flush,
56f75d79ebSchristos .getmeta = npftest_ifop_getmeta,
57f75d79ebSchristos .setmeta = npftest_ifop_setmeta,
58f75d79ebSchristos };
59f75d79ebSchristos
60e0cfa502Srmind void
npf_test_init(int (* pton_func)(int,const char *,void *),const char * (* ntop_func)(int,const void *,char *,socklen_t),long (* rndfunc)(void))61068cee29Srmind npf_test_init(int (*pton_func)(int, const char *, void *),
62068cee29Srmind const char *(*ntop_func)(int, const void *, char *, socklen_t),
63068cee29Srmind long (*rndfunc)(void))
64e0cfa502Srmind {
65f75d79ebSchristos npf_t *npf;
66f75d79ebSchristos
6723183194Srmind #ifdef __NetBSD__
6823183194Srmind // XXX: Workaround for npf_init()
6923183194Srmind if ((npf = npf_getkernctx()) != NULL) {
7023183194Srmind npf_worker_discharge(npf);
7123183194Srmind npf_worker_sysfini();
7223183194Srmind }
7323183194Srmind #endif
74b899bfd9Srmind npf = npfk_create(0, &npftest_mbufops, &npftest_ifops, NULL);
7504ad65d9Srmind npfk_thread_register(npf);
76f75d79ebSchristos npf_setkernctx(npf);
77f75d79ebSchristos
78e0cfa502Srmind npf_state_setsampler(npf_state_sample);
79068cee29Srmind _pton_func = pton_func;
80068cee29Srmind _ntop_func = ntop_func;
81068cee29Srmind _random_func = rndfunc;
82dadc88e3Srmind
83dadc88e3Srmind (void)npf_test_addif(IFNAME_DUMMY, false, false);
84e0cfa502Srmind }
85e0cfa502Srmind
86f75d79ebSchristos void
npf_test_fini(void)87f75d79ebSchristos npf_test_fini(void)
88f75d79ebSchristos {
89f75d79ebSchristos npf_t *npf = npf_getkernctx();
90*fdedb349Sriastradh
9104ad65d9Srmind npfk_thread_unregister(npf);
9204ad65d9Srmind npfk_destroy(npf);
93f75d79ebSchristos }
94f75d79ebSchristos
95fb07f475Srmind int
npf_test_load(const void * buf,size_t len,bool verbose)9639013e66Srmind npf_test_load(const void *buf, size_t len, bool verbose)
97fb07f475Srmind {
9839013e66Srmind nvlist_t *npf_dict;
9939013e66Srmind npf_error_t error;
100b899bfd9Srmind int ret;
10139013e66Srmind
10239013e66Srmind npf_dict = nvlist_unpack(buf, len, 0);
10339013e66Srmind if (!npf_dict) {
10439013e66Srmind printf("%s: could not unpack the nvlist\n", __func__);
10539013e66Srmind return EINVAL;
10639013e66Srmind }
10739013e66Srmind load_npf_config_ifs(npf_dict, verbose);
108b899bfd9Srmind ret = npfk_load(npf_getkernctx(), npf_dict, &error);
109b899bfd9Srmind nvlist_destroy(npf_dict);
110b899bfd9Srmind return ret;
111fb07f475Srmind }
112fb07f475Srmind
113a79812eaSrmind ifnet_t *
npf_test_addif(const char * ifname,bool reg,bool verbose)114a79812eaSrmind npf_test_addif(const char *ifname, bool reg, bool verbose)
11563f44833Srmind {
116f75d79ebSchristos npf_t *npf = npf_getkernctx();
11739013e66Srmind ifnet_t *ifp = kmem_zalloc(sizeof(*ifp), KM_SLEEP);
11863f44833Srmind
11963f44833Srmind /*
12063f44833Srmind * This is a "fake" interface with explicitly set index.
121a79812eaSrmind * Note: test modules may not setup pfil(9) hooks and if_attach()
122a79812eaSrmind * may not trigger npf_ifmap_attach(), so we call it manually.
12363f44833Srmind */
12463f44833Srmind strlcpy(ifp->if_xname, ifname, sizeof(ifp->if_xname));
125f75d79ebSchristos TAILQ_INSERT_TAIL(&npftest_ifnet_list, ifp, if_list);
126a79812eaSrmind
12704ad65d9Srmind npfk_ifmap_attach(npf, ifp);
128a79812eaSrmind if (reg) {
129f75d79ebSchristos npf_ifmap_register(npf, ifname);
13063f44833Srmind }
13163f44833Srmind
132a79812eaSrmind if (verbose) {
133a79812eaSrmind printf("+ Interface %s\n", ifname);
134a79812eaSrmind }
135a79812eaSrmind return ifp;
136a79812eaSrmind }
137a79812eaSrmind
138b899bfd9Srmind ifnet_t *
npf_test_getif(const char * ifname)139b899bfd9Srmind npf_test_getif(const char *ifname)
140b899bfd9Srmind {
141b899bfd9Srmind ifnet_t *ifp;
142b899bfd9Srmind
143b899bfd9Srmind TAILQ_FOREACH(ifp, &npftest_ifnet_list, if_list) {
144b899bfd9Srmind if (!strcmp(ifp->if_xname, ifname))
145b899bfd9Srmind return ifp;
146b899bfd9Srmind }
147b899bfd9Srmind return NULL;
148b899bfd9Srmind }
149b899bfd9Srmind
15039013e66Srmind static void
load_npf_config_ifs(nvlist_t * npf_dict,bool verbose)15139013e66Srmind load_npf_config_ifs(nvlist_t *npf_dict, bool verbose)
15239013e66Srmind {
15339013e66Srmind const nvlist_t * const *iflist;
15439013e66Srmind const nvlist_t *dbg_dict;
15539013e66Srmind size_t nitems;
15639013e66Srmind
15739013e66Srmind dbg_dict = dnvlist_get_nvlist(npf_dict, "debug", NULL);
15839013e66Srmind if (!dbg_dict) {
15939013e66Srmind return;
16039013e66Srmind }
16139013e66Srmind if (!nvlist_exists_nvlist_array(dbg_dict, "interfaces")) {
16239013e66Srmind return;
16339013e66Srmind }
16439013e66Srmind iflist = nvlist_get_nvlist_array(dbg_dict, "interfaces", &nitems);
16539013e66Srmind for (unsigned i = 0; i < nitems; i++) {
16639013e66Srmind const nvlist_t *ifdict = iflist[i];
16739013e66Srmind const char *ifname;
16839013e66Srmind
16939013e66Srmind if ((ifname = nvlist_get_string(ifdict, "name")) != NULL) {
17039013e66Srmind (void)npf_test_addif(ifname, true, verbose);
17139013e66Srmind }
17239013e66Srmind }
17339013e66Srmind }
17439013e66Srmind
175f75d79ebSchristos static const char *
npftest_ifop_getname(npf_t * npf __unused,ifnet_t * ifp)176b899bfd9Srmind npftest_ifop_getname(npf_t *npf __unused, ifnet_t *ifp)
177f75d79ebSchristos {
178f75d79ebSchristos return ifp->if_xname;
179f75d79ebSchristos }
180f75d79ebSchristos
181b899bfd9Srmind static ifnet_t *
npftest_ifop_lookup(npf_t * npf __unused,const char * ifname)182b899bfd9Srmind npftest_ifop_lookup(npf_t *npf __unused, const char *ifname)
18363f44833Srmind {
184b899bfd9Srmind return npf_test_getif(ifname);
185f75d79ebSchristos }
186f75d79ebSchristos
187f75d79ebSchristos static void
npftest_ifop_flush(npf_t * npf __unused,void * arg)188b899bfd9Srmind npftest_ifop_flush(npf_t *npf __unused, void *arg)
189f75d79ebSchristos {
190f75d79ebSchristos ifnet_t *ifp;
191f75d79ebSchristos
192f75d79ebSchristos TAILQ_FOREACH(ifp, &npftest_ifnet_list, if_list)
193f75d79ebSchristos ifp->if_softc = arg;
194f75d79ebSchristos }
195f75d79ebSchristos
196f75d79ebSchristos static void *
npftest_ifop_getmeta(npf_t * npf __unused,const ifnet_t * ifp)197b899bfd9Srmind npftest_ifop_getmeta(npf_t *npf __unused, const ifnet_t *ifp)
198f75d79ebSchristos {
199f75d79ebSchristos return ifp->if_softc;
200f75d79ebSchristos }
201f75d79ebSchristos
202f75d79ebSchristos static void
npftest_ifop_setmeta(npf_t * npf __unused,ifnet_t * ifp,void * arg)203b899bfd9Srmind npftest_ifop_setmeta(npf_t *npf __unused, ifnet_t *ifp, void *arg)
204f75d79ebSchristos {
205f75d79ebSchristos ifp->if_softc = arg;
20663f44833Srmind }
20763f44833Srmind
208fb07f475Srmind /*
209fb07f475Srmind * State sampler - this routine is called from inside of NPF state engine.
210fb07f475Srmind */
211e0cfa502Srmind static void
npf_state_sample(npf_state_t * nst,bool retval)212fb07f475Srmind npf_state_sample(npf_state_t *nst, bool retval)
213fb07f475Srmind {
214fb07f475Srmind /* Pointer will serve as an ID. */
215fb07f475Srmind cstream_ptr = nst;
216fb07f475Srmind memcpy(&cstream_state, nst, sizeof(npf_state_t));
217fb07f475Srmind cstream_retval = retval;
218fb07f475Srmind }
219fb07f475Srmind
220fb07f475Srmind int
npf_test_statetrack(const void * data,size_t len,ifnet_t * ifp,bool forw,int64_t * result)221a79812eaSrmind npf_test_statetrack(const void *data, size_t len, ifnet_t *ifp,
222fb07f475Srmind bool forw, int64_t *result)
223fb07f475Srmind {
224f75d79ebSchristos npf_t *npf = npf_getkernctx();
225fb07f475Srmind struct mbuf *m;
226fb07f475Srmind int i = 0, error;
227fb07f475Srmind
228fb07f475Srmind m = mbuf_getwithdata(data, len);
22904ad65d9Srmind error = npfk_packet_handler(npf, &m, ifp, forw ? PFIL_OUT : PFIL_IN);
230fb07f475Srmind if (error) {
231fb07f475Srmind assert(m == NULL);
232fb07f475Srmind return error;
233fb07f475Srmind }
234fb07f475Srmind assert(m != NULL);
235fb07f475Srmind m_freem(m);
236fb07f475Srmind
237fb07f475Srmind const int di = forw ? NPF_FLOW_FORW : NPF_FLOW_BACK;
238fb07f475Srmind npf_tcpstate_t *fstate = &cstream_state.nst_tcpst[di];
239fb07f475Srmind npf_tcpstate_t *tstate = &cstream_state.nst_tcpst[!di];
240fb07f475Srmind
241fb07f475Srmind result[i++] = (intptr_t)cstream_ptr;
242fb07f475Srmind result[i++] = cstream_retval;
243fb07f475Srmind result[i++] = cstream_state.nst_state;
244fb07f475Srmind
245fb07f475Srmind result[i++] = fstate->nst_end;
246fb07f475Srmind result[i++] = fstate->nst_maxend;
247fb07f475Srmind result[i++] = fstate->nst_maxwin;
2484ad50294Srmind result[i++] = fstate->nst_wscale;
249fb07f475Srmind
250fb07f475Srmind result[i++] = tstate->nst_end;
251fb07f475Srmind result[i++] = tstate->nst_maxend;
252fb07f475Srmind result[i++] = tstate->nst_maxwin;
2534ad50294Srmind result[i++] = tstate->nst_wscale;
254fb07f475Srmind
255fb07f475Srmind return 0;
256fb07f475Srmind }
257bb1fedd1Srmind
258068cee29Srmind int
npf_inet_pton(int af,const char * src,void * dst)259068cee29Srmind npf_inet_pton(int af, const char *src, void *dst)
260068cee29Srmind {
261068cee29Srmind return _pton_func(af, src, dst);
262068cee29Srmind }
263068cee29Srmind
264068cee29Srmind const char *
npf_inet_ntop(int af,const void * src,char * dst,socklen_t size)265068cee29Srmind npf_inet_ntop(int af, const void *src, char *dst, socklen_t size)
266068cee29Srmind {
267068cee29Srmind return _ntop_func(af, src, dst, size);
268068cee29Srmind }
269068cee29Srmind
270f75d79ebSchristos #ifdef _KERNEL
271bb1fedd1Srmind /*
272ea6af427Stls * Need to override cprng_fast32() -- we need deterministic PRNG.
273bb1fedd1Srmind */
274bb1fedd1Srmind uint32_t
cprng_fast32(void)275ea6af427Stls cprng_fast32(void)
276bb1fedd1Srmind {
277068cee29Srmind return (uint32_t)(_random_func ? _random_func() : random());
278bb1fedd1Srmind }
279f75d79ebSchristos #endif
280