xref: /netbsd-src/usr.sbin/npf/npftest/libnpftest/npf_test_subr.c (revision bdc22b2e01993381dcefeff2bc9b56ca75a4235c)
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