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