npf_test_subr.c revision 1.16 1 /*
2 * NPF initialisation and handler routines.
3 *
4 * Public Domain.
5 */
6
7 #ifdef _KERNEL
8 #include <sys/types.h>
9 #include <sys/cprng.h>
10 #include <sys/kmem.h>
11 #include <net/if.h>
12 #include <net/if_types.h>
13 #endif
14
15 #include "npf_impl.h"
16 #include "npf_test.h"
17
18 /* State of the current stream. */
19 static npf_state_t cstream_state;
20 static void * cstream_ptr;
21 static bool cstream_retval;
22
23 static long (*_random_func)(void);
24 static int (*_pton_func)(int, const char *, void *);
25 static const char * (*_ntop_func)(int, const void *, char *, socklen_t);
26
27 static void npf_state_sample(npf_state_t *, bool);
28
29 static void load_npf_config_ifs(nvlist_t *, bool);
30
31 #ifndef __NetBSD__
32 /*
33 * Standalone NPF: we define the same struct ifnet members
34 * to reduce the npf_ifops_t implementation differences.
35 */
36 struct ifnet {
37 char if_xname[32];
38 void * if_softc;
39 TAILQ_ENTRY(ifnet) if_list;
40 };
41 #endif
42
43 static TAILQ_HEAD(, ifnet) npftest_ifnet_list =
44 TAILQ_HEAD_INITIALIZER(npftest_ifnet_list);
45
46 static const char * npftest_ifop_getname(ifnet_t *);
47 static void npftest_ifop_flush(void *);
48 static void * npftest_ifop_getmeta(const ifnet_t *);
49 static void npftest_ifop_setmeta(ifnet_t *, void *);
50
51 const npf_ifops_t npftest_ifops = {
52 .getname = npftest_ifop_getname,
53 .lookup = npf_test_getif,
54 .flush = npftest_ifop_flush,
55 .getmeta = npftest_ifop_getmeta,
56 .setmeta = npftest_ifop_setmeta,
57 };
58
59 void
60 npf_test_init(int (*pton_func)(int, const char *, void *),
61 const char *(*ntop_func)(int, const void *, char *, socklen_t),
62 long (*rndfunc)(void))
63 {
64 npf_t *npf;
65
66 npfk_sysinit(0);
67 npf = npfk_create(0, &npftest_mbufops, &npftest_ifops);
68 npfk_thread_register(npf);
69 npf_setkernctx(npf);
70
71 npf_state_setsampler(npf_state_sample);
72 _pton_func = pton_func;
73 _ntop_func = ntop_func;
74 _random_func = rndfunc;
75
76 (void)npf_test_addif(IFNAME_DUMMY, false, false);
77 }
78
79 void
80 npf_test_fini(void)
81 {
82 npf_t *npf = npf_getkernctx();
83 npfk_thread_unregister(npf);
84 npfk_destroy(npf);
85 npfk_sysfini();
86 }
87
88 int
89 npf_test_load(const void *buf, size_t len, bool verbose)
90 {
91 nvlist_t *npf_dict;
92 npf_error_t error;
93
94 npf_dict = nvlist_unpack(buf, len, 0);
95 if (!npf_dict) {
96 printf("%s: could not unpack the nvlist\n", __func__);
97 return EINVAL;
98 }
99 load_npf_config_ifs(npf_dict, verbose);
100
101 // Note: npf_dict will be consumed by npf_load().
102 return npfk_load(npf_getkernctx(), npf_dict, &error);
103 }
104
105 ifnet_t *
106 npf_test_addif(const char *ifname, bool reg, bool verbose)
107 {
108 npf_t *npf = npf_getkernctx();
109 ifnet_t *ifp = kmem_zalloc(sizeof(*ifp), KM_SLEEP);
110
111 /*
112 * This is a "fake" interface with explicitly set index.
113 * Note: test modules may not setup pfil(9) hooks and if_attach()
114 * may not trigger npf_ifmap_attach(), so we call it manually.
115 */
116 strlcpy(ifp->if_xname, ifname, sizeof(ifp->if_xname));
117 TAILQ_INSERT_TAIL(&npftest_ifnet_list, ifp, if_list);
118
119 npfk_ifmap_attach(npf, ifp);
120 if (reg) {
121 npf_ifmap_register(npf, ifname);
122 }
123
124 if (verbose) {
125 printf("+ Interface %s\n", ifname);
126 }
127 return ifp;
128 }
129
130 static void
131 load_npf_config_ifs(nvlist_t *npf_dict, bool verbose)
132 {
133 const nvlist_t * const *iflist;
134 const nvlist_t *dbg_dict;
135 size_t nitems;
136
137 dbg_dict = dnvlist_get_nvlist(npf_dict, "debug", NULL);
138 if (!dbg_dict) {
139 return;
140 }
141 if (!nvlist_exists_nvlist_array(dbg_dict, "interfaces")) {
142 return;
143 }
144 iflist = nvlist_get_nvlist_array(dbg_dict, "interfaces", &nitems);
145 for (unsigned i = 0; i < nitems; i++) {
146 const nvlist_t *ifdict = iflist[i];
147 const char *ifname;
148
149 if ((ifname = nvlist_get_string(ifdict, "name")) != NULL) {
150 (void)npf_test_addif(ifname, true, verbose);
151 }
152 }
153 }
154
155 static const char *
156 npftest_ifop_getname(ifnet_t *ifp)
157 {
158 return ifp->if_xname;
159 }
160
161 ifnet_t *
162 npf_test_getif(const char *ifname)
163 {
164 ifnet_t *ifp;
165
166 TAILQ_FOREACH(ifp, &npftest_ifnet_list, if_list) {
167 if (!strcmp(ifp->if_xname, ifname))
168 return ifp;
169 }
170 return NULL;
171 }
172
173 static void
174 npftest_ifop_flush(void *arg)
175 {
176 ifnet_t *ifp;
177
178 TAILQ_FOREACH(ifp, &npftest_ifnet_list, if_list)
179 ifp->if_softc = arg;
180 }
181
182 static void *
183 npftest_ifop_getmeta(const ifnet_t *ifp)
184 {
185 return ifp->if_softc;
186 }
187
188 static void
189 npftest_ifop_setmeta(ifnet_t *ifp, void *arg)
190 {
191 ifp->if_softc = arg;
192 }
193
194 /*
195 * State sampler - this routine is called from inside of NPF state engine.
196 */
197 static void
198 npf_state_sample(npf_state_t *nst, bool retval)
199 {
200 /* Pointer will serve as an ID. */
201 cstream_ptr = nst;
202 memcpy(&cstream_state, nst, sizeof(npf_state_t));
203 cstream_retval = retval;
204 }
205
206 int
207 npf_test_statetrack(const void *data, size_t len, ifnet_t *ifp,
208 bool forw, int64_t *result)
209 {
210 npf_t *npf = npf_getkernctx();
211 struct mbuf *m;
212 int i = 0, error;
213
214 m = mbuf_getwithdata(data, len);
215 error = npfk_packet_handler(npf, &m, ifp, forw ? PFIL_OUT : PFIL_IN);
216 if (error) {
217 assert(m == NULL);
218 return error;
219 }
220 assert(m != NULL);
221 m_freem(m);
222
223 const int di = forw ? NPF_FLOW_FORW : NPF_FLOW_BACK;
224 npf_tcpstate_t *fstate = &cstream_state.nst_tcpst[di];
225 npf_tcpstate_t *tstate = &cstream_state.nst_tcpst[!di];
226
227 result[i++] = (intptr_t)cstream_ptr;
228 result[i++] = cstream_retval;
229 result[i++] = cstream_state.nst_state;
230
231 result[i++] = fstate->nst_end;
232 result[i++] = fstate->nst_maxend;
233 result[i++] = fstate->nst_maxwin;
234 result[i++] = fstate->nst_wscale;
235
236 result[i++] = tstate->nst_end;
237 result[i++] = tstate->nst_maxend;
238 result[i++] = tstate->nst_maxwin;
239 result[i++] = tstate->nst_wscale;
240
241 return 0;
242 }
243
244 int
245 npf_inet_pton(int af, const char *src, void *dst)
246 {
247 return _pton_func(af, src, dst);
248 }
249
250 const char *
251 npf_inet_ntop(int af, const void *src, char *dst, socklen_t size)
252 {
253 return _ntop_func(af, src, dst, size);
254 }
255
256 #ifdef _KERNEL
257 /*
258 * Need to override cprng_fast32() -- we need deterministic PRNG.
259 */
260 uint32_t
261 cprng_fast32(void)
262 {
263 return (uint32_t)(_random_func ? _random_func() : random());
264 }
265 #endif
266