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