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