1 1.1 rmind /* 2 1.16 rmind * NPF ruleset tests. 3 1.1 rmind * 4 1.1 rmind * Public Domain. 5 1.1 rmind */ 6 1.1 rmind 7 1.13 christos #ifdef _KERNEL 8 1.1 rmind #include <sys/types.h> 9 1.13 christos #endif 10 1.1 rmind 11 1.1 rmind #include "npf_impl.h" 12 1.1 rmind #include "npf_test.h" 13 1.1 rmind 14 1.1 rmind #define RESULT_PASS 0 15 1.1 rmind #define RESULT_BLOCK ENETUNREACH 16 1.1 rmind 17 1.1 rmind static const struct test_case { 18 1.20 riastrad int af; 19 1.1 rmind const char * src; 20 1.1 rmind const char * dst; 21 1.1 rmind const char * ifname; 22 1.1 rmind int di; 23 1.1 rmind int stateful_ret; 24 1.1 rmind int ret; 25 1.1 rmind } test_cases[] = { 26 1.1 rmind 27 1.1 rmind /* Stateful pass. */ 28 1.1 rmind { 29 1.20 riastrad .af = AF_INET, 30 1.1 rmind .src = "10.1.1.1", .dst = "10.1.1.2", 31 1.1 rmind .ifname = IFNAME_INT, .di = PFIL_OUT, 32 1.1 rmind .stateful_ret = RESULT_PASS, .ret = RESULT_PASS 33 1.1 rmind }, 34 1.1 rmind { 35 1.20 riastrad .af = AF_INET, 36 1.1 rmind .src = "10.1.1.2", .dst = "10.1.1.1", 37 1.1 rmind .ifname = IFNAME_INT, .di = PFIL_IN, 38 1.1 rmind .stateful_ret = RESULT_PASS, .ret = RESULT_BLOCK 39 1.1 rmind }, 40 1.1 rmind 41 1.1 rmind /* Pass forwards stream only. */ 42 1.1 rmind { 43 1.20 riastrad .af = AF_INET, 44 1.1 rmind .src = "10.1.1.1", .dst = "10.1.1.3", 45 1.1 rmind .ifname = IFNAME_INT, .di = PFIL_OUT, 46 1.1 rmind .stateful_ret = RESULT_PASS, .ret = RESULT_PASS 47 1.1 rmind }, 48 1.1 rmind { 49 1.20 riastrad .af = AF_INET, 50 1.1 rmind .src = "10.1.1.3", .dst = "10.1.1.1", 51 1.1 rmind .ifname = IFNAME_INT, .di = PFIL_IN, 52 1.1 rmind .stateful_ret = RESULT_BLOCK, .ret = RESULT_BLOCK 53 1.1 rmind }, 54 1.26 joe /* PR bin/59511 */ 55 1.26 joe { 56 1.26 joe .af = AF_INET, 57 1.26 joe .src = "192.168.100.5", .dst = "10.1.1.5", 58 1.26 joe .ifname = IFNAME_INT, .di = PFIL_IN, 59 1.26 joe .stateful_ret = RESULT_BLOCK, .ret = RESULT_BLOCK 60 1.26 joe }, 61 1.26 joe { 62 1.26 joe .af = AF_INET, 63 1.26 joe .src = "192.168.100.8", .dst = "10.1.1.5", 64 1.26 joe .ifname = IFNAME_INT, .di = PFIL_IN, 65 1.26 joe .stateful_ret = RESULT_BLOCK, .ret = RESULT_BLOCK 66 1.26 joe }, 67 1.26 joe { 68 1.26 joe .af = AF_INET, 69 1.26 joe .src = "192.168.64.3", .dst = "10.1.1.5", 70 1.26 joe .ifname = IFNAME_INT, .di = PFIL_IN, 71 1.26 joe .stateful_ret = RESULT_BLOCK, .ret = RESULT_BLOCK 72 1.26 joe }, 73 1.26 joe { 74 1.26 joe .af = AF_INET, 75 1.26 joe .src = "192.168.64.9", .dst = "10.1.1.5", 76 1.26 joe .ifname = IFNAME_INT, .di = PFIL_IN, 77 1.26 joe .stateful_ret = RESULT_BLOCK, .ret = RESULT_BLOCK 78 1.26 joe }, 79 1.1 rmind 80 1.21 riastrad /* 81 1.23 riastrad * Pass in from any of the { fe80::1, fe80:1000:0:0/95, 82 1.23 riastrad * fe80::2, fe80::2000:0:0/96, fe80::3, fe80::3000:0:0/97 } 83 1.23 riastrad * group. 84 1.21 riastrad */ 85 1.23 riastrad { /* fe80::1 */ 86 1.21 riastrad .af = AF_INET6, 87 1.21 riastrad .src = "fe80::1", .dst = "fe80::adec:c91c:d116:7592", 88 1.22 riastrad .ifname = IFNAME_INT, .di = PFIL_IN, 89 1.21 riastrad .stateful_ret = RESULT_PASS, .ret = RESULT_PASS 90 1.21 riastrad }, 91 1.23 riastrad { /* fe80::1000:0:0/95 */ 92 1.23 riastrad .af = AF_INET6, 93 1.23 riastrad .src = "fe80::1001:0:0", .dst = "fe80::adec:c91c:d116:7592", 94 1.23 riastrad .ifname = IFNAME_INT, .di = PFIL_IN, 95 1.23 riastrad .stateful_ret = RESULT_PASS, .ret = RESULT_PASS 96 1.23 riastrad }, 97 1.23 riastrad { /* fe80::1000:0:0/95, one bit off */ 98 1.23 riastrad .af = AF_INET6, 99 1.23 riastrad .src = "fe80::1003:0:0", .dst = "fe80::adec:c91c:d116:7592", 100 1.23 riastrad .ifname = IFNAME_INT, .di = PFIL_IN, 101 1.23 riastrad .stateful_ret = RESULT_BLOCK, .ret = RESULT_BLOCK 102 1.23 riastrad }, 103 1.23 riastrad { /* fe80::2 */ 104 1.21 riastrad .af = AF_INET6, 105 1.21 riastrad .src = "fe80::2", .dst = "fe80::adec:c91c:d116:7592", 106 1.22 riastrad .ifname = IFNAME_INT, .di = PFIL_IN, 107 1.21 riastrad .stateful_ret = RESULT_PASS, .ret = RESULT_PASS 108 1.21 riastrad }, 109 1.23 riastrad { /* fe80::2000:0:0/96 */ 110 1.23 riastrad .af = AF_INET6, 111 1.23 riastrad .src = "fe80::2000:8000:0", .dst = "fe80::adec:c91c:d116:7592", 112 1.23 riastrad .ifname = IFNAME_INT, .di = PFIL_IN, 113 1.23 riastrad .stateful_ret = RESULT_PASS, .ret = RESULT_PASS 114 1.23 riastrad }, 115 1.23 riastrad { /* fe80::2000:0:0/96, one bit off */ 116 1.23 riastrad .af = AF_INET6, 117 1.23 riastrad .src = "fe80::2001:8000:0", .dst = "fe80::adec:c91c:d116:7592", 118 1.23 riastrad .ifname = IFNAME_INT, .di = PFIL_IN, 119 1.23 riastrad .stateful_ret = RESULT_BLOCK, .ret = RESULT_BLOCK 120 1.23 riastrad }, 121 1.23 riastrad { /* fe80::3 */ 122 1.23 riastrad .af = AF_INET6, 123 1.23 riastrad .src = "fe80::3", .dst = "fe80::adec:c91c:d116:7592", 124 1.23 riastrad .ifname = IFNAME_INT, .di = PFIL_IN, 125 1.23 riastrad .stateful_ret = RESULT_PASS, .ret = RESULT_PASS 126 1.23 riastrad }, 127 1.23 riastrad { /* fe80::3000:0:0/97 */ 128 1.23 riastrad .af = AF_INET6, 129 1.23 riastrad .src = "fe80::3000:7fff:0", .dst = "fe80::adec:c91c:d116:7592", 130 1.23 riastrad .ifname = IFNAME_INT, .di = PFIL_IN, 131 1.23 riastrad .stateful_ret = RESULT_PASS, .ret = RESULT_PASS 132 1.23 riastrad }, 133 1.23 riastrad { /* fe80::3000:0:0/97, one bit off */ 134 1.23 riastrad .af = AF_INET6, 135 1.23 riastrad .src = "fe80::3000:ffff:0", .dst = "fe80::adec:c91c:d116:7592", 136 1.23 riastrad .ifname = IFNAME_INT, .di = PFIL_IN, 137 1.23 riastrad .stateful_ret = RESULT_BLOCK, .ret = RESULT_BLOCK 138 1.23 riastrad }, 139 1.21 riastrad { 140 1.21 riastrad .af = AF_INET6, 141 1.23 riastrad .src = "fe80::4", .dst = "fe80::adec:c91c:d116:7592", 142 1.22 riastrad .ifname = IFNAME_INT, .di = PFIL_IN, 143 1.22 riastrad .stateful_ret = RESULT_BLOCK, .ret = RESULT_BLOCK 144 1.22 riastrad }, 145 1.22 riastrad 146 1.22 riastrad /* 147 1.23 riastrad * Pass in from anywhere _not_ in that group, as long as it is 148 1.23 riastrad * to that group. 149 1.22 riastrad */ 150 1.23 riastrad { /* fe80::1 */ 151 1.22 riastrad .af = AF_INET6, 152 1.22 riastrad .src = "fe80::adec:c91c:d116:7592", .dst = "fe80::1", 153 1.22 riastrad .ifname = IFNAME_INT, .di = PFIL_IN, 154 1.22 riastrad .stateful_ret = RESULT_PASS, .ret = RESULT_PASS 155 1.22 riastrad }, 156 1.23 riastrad { /* fe80::1000:0:0/95 */ 157 1.23 riastrad .af = AF_INET6, 158 1.23 riastrad .src = "fe80::adec:c91c:d116:7592", .dst = "fe80::1001:0:0", 159 1.23 riastrad .ifname = IFNAME_INT, .di = PFIL_IN, 160 1.23 riastrad .stateful_ret = RESULT_PASS, .ret = RESULT_PASS 161 1.23 riastrad }, 162 1.23 riastrad { /* fe80::1000:0:0/95, one bit off */ 163 1.23 riastrad .af = AF_INET6, 164 1.23 riastrad .src = "fe80::adec:c91c:d116:7592", .dst = "fe80::1003:0:0", 165 1.23 riastrad .ifname = IFNAME_INT, .di = PFIL_IN, 166 1.23 riastrad .stateful_ret = RESULT_BLOCK, .ret = RESULT_BLOCK 167 1.23 riastrad }, 168 1.23 riastrad { /* fe80::2 */ 169 1.22 riastrad .af = AF_INET6, 170 1.22 riastrad .src = "fe80::adec:c91c:d116:7592", .dst = "fe80::2", 171 1.22 riastrad .ifname = IFNAME_INT, .di = PFIL_IN, 172 1.22 riastrad .stateful_ret = RESULT_PASS, .ret = RESULT_PASS 173 1.22 riastrad }, 174 1.23 riastrad { /* fe80::2000:0:0/96 */ 175 1.23 riastrad .af = AF_INET6, 176 1.23 riastrad .src = "fe80::adec:c91c:d116:7592", .dst = "fe80::2000:8000:0", 177 1.23 riastrad .ifname = IFNAME_INT, .di = PFIL_IN, 178 1.23 riastrad .stateful_ret = RESULT_PASS, .ret = RESULT_PASS 179 1.23 riastrad }, 180 1.23 riastrad { /* fe80::2000:0:0/96, one bit off */ 181 1.23 riastrad .af = AF_INET6, 182 1.23 riastrad .src = "fe80::adec:c91c:d116:7592", .dst = "fe80::2001:8000:0", 183 1.23 riastrad .ifname = IFNAME_INT, .di = PFIL_IN, 184 1.23 riastrad .stateful_ret = RESULT_BLOCK, .ret = RESULT_BLOCK 185 1.23 riastrad }, 186 1.23 riastrad { /* fe80::3 */ 187 1.23 riastrad .af = AF_INET6, 188 1.23 riastrad .src = "fe80::adec:c91c:d116:7592", .dst = "fe80::3", 189 1.23 riastrad .ifname = IFNAME_INT, .di = PFIL_IN, 190 1.23 riastrad .stateful_ret = RESULT_PASS, .ret = RESULT_PASS 191 1.23 riastrad }, 192 1.23 riastrad { /* fe80::3000:0:0/97 */ 193 1.23 riastrad .af = AF_INET6, 194 1.23 riastrad .src = "fe80::adec:c91c:d116:7592", .dst = "fe80::3000:7fff:0", 195 1.23 riastrad .ifname = IFNAME_INT, .di = PFIL_IN, 196 1.23 riastrad .stateful_ret = RESULT_PASS, .ret = RESULT_PASS 197 1.23 riastrad }, 198 1.23 riastrad { /* fe80::3000:0:0/97, one bit off */ 199 1.23 riastrad .af = AF_INET6, 200 1.23 riastrad .src = "fe80::adec:c91c:d116:7592", .dst = "fe80::3000:ffff:0", 201 1.23 riastrad .ifname = IFNAME_INT, .di = PFIL_IN, 202 1.23 riastrad .stateful_ret = RESULT_BLOCK, .ret = RESULT_BLOCK 203 1.23 riastrad }, 204 1.22 riastrad { 205 1.22 riastrad .af = AF_INET6, 206 1.23 riastrad .src = "fe80::adec:c91c:d116:7592", .dst = "fe80::4", 207 1.22 riastrad .ifname = IFNAME_INT, .di = PFIL_IN, 208 1.21 riastrad .stateful_ret = RESULT_BLOCK, .ret = RESULT_BLOCK 209 1.21 riastrad }, 210 1.21 riastrad 211 1.1 rmind /* Block. */ 212 1.20 riastrad { 213 1.20 riastrad .af = AF_INET, 214 1.20 riastrad .src = "10.1.1.1", .dst = "10.1.1.4", 215 1.1 rmind .ifname = IFNAME_INT, .di = PFIL_OUT, 216 1.1 rmind .stateful_ret = RESULT_BLOCK, .ret = RESULT_BLOCK 217 1.1 rmind }, 218 1.25 mlelstv { .src = "10.1.1.3", .dst = "10.1.1.1", 219 1.25 mlelstv .ifname = IFNAME_INT, .di = PFIL_IN, 220 1.25 mlelstv .stateful_ret = RESULT_BLOCK, .ret = RESULT_BLOCK 221 1.25 mlelstv }, 222 1.1 rmind 223 1.1 rmind }; 224 1.1 rmind 225 1.1 rmind static int 226 1.17 rmind run_raw_testcase(unsigned i) 227 1.1 rmind { 228 1.17 rmind const struct test_case *t = &test_cases[i]; 229 1.13 christos npf_t *npf = npf_getkernctx(); 230 1.17 rmind npf_cache_t *npc; 231 1.17 rmind struct mbuf *m; 232 1.1 rmind npf_rule_t *rl; 233 1.17 rmind int slock, error; 234 1.17 rmind 235 1.20 riastrad m = mbuf_get_pkt(t->af, IPPROTO_UDP, t->src, t->dst, 9000, 9000); 236 1.24 joe npc = get_cached_pkt(m, t->ifname, NPF_RULE_LAYER_3); 237 1.1 rmind 238 1.19 rmind slock = npf_config_read_enter(npf); 239 1.24 joe rl = npf_ruleset_inspect(npc, npf_config_ruleset(npf), t->di, NPF_RULE_LAYER_3); 240 1.1 rmind if (rl) { 241 1.17 rmind npf_match_info_t mi; 242 1.14 christos error = npf_rule_conclude(rl, &mi); 243 1.1 rmind } else { 244 1.1 rmind error = ENOENT; 245 1.1 rmind } 246 1.19 rmind npf_config_read_exit(npf, slock); 247 1.17 rmind 248 1.17 rmind put_cached_pkt(npc); 249 1.1 rmind return error; 250 1.1 rmind } 251 1.1 rmind 252 1.4 rmind static int 253 1.17 rmind run_handler_testcase(unsigned i) 254 1.4 rmind { 255 1.8 rmind const struct test_case *t = &test_cases[i]; 256 1.13 christos ifnet_t *ifp = npf_test_getif(t->ifname); 257 1.17 rmind npf_t *npf = npf_getkernctx(); 258 1.17 rmind struct mbuf *m; 259 1.4 rmind int error; 260 1.4 rmind 261 1.20 riastrad m = mbuf_get_pkt(t->af, IPPROTO_UDP, t->src, t->dst, 9000, 9000); 262 1.18 rmind error = npfk_packet_handler(npf, &m, ifp, t->di); 263 1.17 rmind if (m) { 264 1.17 rmind m_freem(m); 265 1.17 rmind } 266 1.4 rmind return error; 267 1.4 rmind } 268 1.4 rmind 269 1.4 rmind static npf_rule_t * 270 1.4 rmind npf_blockall_rule(void) 271 1.4 rmind { 272 1.13 christos npf_t *npf = npf_getkernctx(); 273 1.15 rmind nvlist_t *rule = nvlist_create(0); 274 1.17 rmind npf_rule_t *rl; 275 1.4 rmind 276 1.15 rmind nvlist_add_number(rule, "attr", 277 1.7 rmind NPF_RULE_IN | NPF_RULE_OUT | NPF_RULE_DYNAMIC); 278 1.17 rmind rl = npf_rule_alloc(npf, rule); 279 1.17 rmind nvlist_destroy(rule); 280 1.17 rmind return rl; 281 1.4 rmind } 282 1.4 rmind 283 1.17 rmind static bool 284 1.17 rmind test_static(bool verbose) 285 1.1 rmind { 286 1.1 rmind for (unsigned i = 0; i < __arraycount(test_cases); i++) { 287 1.1 rmind const struct test_case *t = &test_cases[i]; 288 1.17 rmind int error, serror; 289 1.1 rmind 290 1.17 rmind if (npf_test_getif(t->ifname) == NULL) { 291 1.1 rmind printf("Interface %s is not configured.\n", t->ifname); 292 1.1 rmind return false; 293 1.1 rmind } 294 1.1 rmind 295 1.17 rmind error = run_raw_testcase(i); 296 1.17 rmind serror = run_handler_testcase(i); 297 1.1 rmind 298 1.1 rmind if (verbose) { 299 1.16 rmind printf("rule test %d:\texpected %d (stateful) and %d\n" 300 1.16 rmind "\t\t-> returned %d and %d\n", 301 1.1 rmind i + 1, t->stateful_ret, t->ret, serror, error); 302 1.1 rmind } 303 1.17 rmind CHECK_TRUE(error == t->ret); 304 1.17 rmind CHECK_TRUE(serror == t->stateful_ret) 305 1.1 rmind } 306 1.17 rmind return true; 307 1.17 rmind } 308 1.17 rmind 309 1.17 rmind static bool 310 1.17 rmind test_dynamic(void) 311 1.17 rmind { 312 1.17 rmind npf_t *npf = npf_getkernctx(); 313 1.17 rmind npf_ruleset_t *rlset; 314 1.17 rmind npf_rule_t *rl; 315 1.17 rmind uint64_t id; 316 1.17 rmind int error; 317 1.4 rmind 318 1.8 rmind /* 319 1.8 rmind * Test dynamic NPF rules. 320 1.8 rmind */ 321 1.8 rmind 322 1.17 rmind error = run_raw_testcase(0); 323 1.16 rmind CHECK_TRUE(error == RESULT_PASS); 324 1.4 rmind 325 1.13 christos npf_config_enter(npf); 326 1.13 christos rlset = npf_config_ruleset(npf); 327 1.4 rmind 328 1.4 rmind rl = npf_blockall_rule(); 329 1.4 rmind error = npf_ruleset_add(rlset, "test-rules", rl); 330 1.16 rmind CHECK_TRUE(error == 0); 331 1.4 rmind 332 1.17 rmind error = run_raw_testcase(0); 333 1.16 rmind CHECK_TRUE(error == RESULT_BLOCK); 334 1.4 rmind 335 1.6 rmind id = npf_rule_getid(rl); 336 1.6 rmind error = npf_ruleset_remove(rlset, "test-rules", id); 337 1.16 rmind CHECK_TRUE(error == 0); 338 1.4 rmind 339 1.13 christos npf_config_exit(npf); 340 1.4 rmind 341 1.17 rmind error = run_raw_testcase(0); 342 1.16 rmind CHECK_TRUE(error == RESULT_PASS); 343 1.4 rmind 344 1.16 rmind return true; 345 1.1 rmind } 346 1.17 rmind 347 1.17 rmind bool 348 1.17 rmind npf_rule_test(bool verbose) 349 1.17 rmind { 350 1.17 rmind bool ok; 351 1.17 rmind 352 1.17 rmind ok = test_static(verbose); 353 1.17 rmind CHECK_TRUE(ok); 354 1.17 rmind 355 1.17 rmind ok = test_dynamic(); 356 1.17 rmind CHECK_TRUE(ok); 357 1.17 rmind 358 1.17 rmind return true; 359 1.17 rmind } 360