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 55 /* 56 * Pass in from any of the { fe80::1, fe80:1000:0:0/95, 57 * fe80::2, fe80::2000:0:0/96, fe80::3, fe80::3000:0:0/97 } 58 * group. 59 */ 60 { /* fe80::1 */ 61 .af = AF_INET6, 62 .src = "fe80::1", .dst = "fe80::adec:c91c:d116:7592", 63 .ifname = IFNAME_INT, .di = PFIL_IN, 64 .stateful_ret = RESULT_PASS, .ret = RESULT_PASS 65 }, 66 { /* fe80::1000:0:0/95 */ 67 .af = AF_INET6, 68 .src = "fe80::1001:0:0", .dst = "fe80::adec:c91c:d116:7592", 69 .ifname = IFNAME_INT, .di = PFIL_IN, 70 .stateful_ret = RESULT_PASS, .ret = RESULT_PASS 71 }, 72 { /* fe80::1000:0:0/95, one bit off */ 73 .af = AF_INET6, 74 .src = "fe80::1003:0:0", .dst = "fe80::adec:c91c:d116:7592", 75 .ifname = IFNAME_INT, .di = PFIL_IN, 76 .stateful_ret = RESULT_BLOCK, .ret = RESULT_BLOCK 77 }, 78 { /* fe80::2 */ 79 .af = AF_INET6, 80 .src = "fe80::2", .dst = "fe80::adec:c91c:d116:7592", 81 .ifname = IFNAME_INT, .di = PFIL_IN, 82 .stateful_ret = RESULT_PASS, .ret = RESULT_PASS 83 }, 84 { /* fe80::2000:0:0/96 */ 85 .af = AF_INET6, 86 .src = "fe80::2000:8000:0", .dst = "fe80::adec:c91c:d116:7592", 87 .ifname = IFNAME_INT, .di = PFIL_IN, 88 .stateful_ret = RESULT_PASS, .ret = RESULT_PASS 89 }, 90 { /* fe80::2000:0:0/96, one bit off */ 91 .af = AF_INET6, 92 .src = "fe80::2001:8000:0", .dst = "fe80::adec:c91c:d116:7592", 93 .ifname = IFNAME_INT, .di = PFIL_IN, 94 .stateful_ret = RESULT_BLOCK, .ret = RESULT_BLOCK 95 }, 96 { /* fe80::3 */ 97 .af = AF_INET6, 98 .src = "fe80::3", .dst = "fe80::adec:c91c:d116:7592", 99 .ifname = IFNAME_INT, .di = PFIL_IN, 100 .stateful_ret = RESULT_PASS, .ret = RESULT_PASS 101 }, 102 { /* fe80::3000:0:0/97 */ 103 .af = AF_INET6, 104 .src = "fe80::3000:7fff:0", .dst = "fe80::adec:c91c:d116:7592", 105 .ifname = IFNAME_INT, .di = PFIL_IN, 106 .stateful_ret = RESULT_PASS, .ret = RESULT_PASS 107 }, 108 { /* fe80::3000:0:0/97, one bit off */ 109 .af = AF_INET6, 110 .src = "fe80::3000:ffff:0", .dst = "fe80::adec:c91c:d116:7592", 111 .ifname = IFNAME_INT, .di = PFIL_IN, 112 .stateful_ret = RESULT_BLOCK, .ret = RESULT_BLOCK 113 }, 114 { 115 .af = AF_INET6, 116 .src = "fe80::4", .dst = "fe80::adec:c91c:d116:7592", 117 .ifname = IFNAME_INT, .di = PFIL_IN, 118 .stateful_ret = RESULT_BLOCK, .ret = RESULT_BLOCK 119 }, 120 121 /* 122 * Pass in from anywhere _not_ in that group, as long as it is 123 * to that group. 124 */ 125 { /* fe80::1 */ 126 .af = AF_INET6, 127 .src = "fe80::adec:c91c:d116:7592", .dst = "fe80::1", 128 .ifname = IFNAME_INT, .di = PFIL_IN, 129 .stateful_ret = RESULT_PASS, .ret = RESULT_PASS 130 }, 131 { /* fe80::1000:0:0/95 */ 132 .af = AF_INET6, 133 .src = "fe80::adec:c91c:d116:7592", .dst = "fe80::1001:0:0", 134 .ifname = IFNAME_INT, .di = PFIL_IN, 135 .stateful_ret = RESULT_PASS, .ret = RESULT_PASS 136 }, 137 { /* fe80::1000:0:0/95, one bit off */ 138 .af = AF_INET6, 139 .src = "fe80::adec:c91c:d116:7592", .dst = "fe80::1003:0:0", 140 .ifname = IFNAME_INT, .di = PFIL_IN, 141 .stateful_ret = RESULT_BLOCK, .ret = RESULT_BLOCK 142 }, 143 { /* fe80::2 */ 144 .af = AF_INET6, 145 .src = "fe80::adec:c91c:d116:7592", .dst = "fe80::2", 146 .ifname = IFNAME_INT, .di = PFIL_IN, 147 .stateful_ret = RESULT_PASS, .ret = RESULT_PASS 148 }, 149 { /* fe80::2000:0:0/96 */ 150 .af = AF_INET6, 151 .src = "fe80::adec:c91c:d116:7592", .dst = "fe80::2000:8000:0", 152 .ifname = IFNAME_INT, .di = PFIL_IN, 153 .stateful_ret = RESULT_PASS, .ret = RESULT_PASS 154 }, 155 { /* fe80::2000:0:0/96, one bit off */ 156 .af = AF_INET6, 157 .src = "fe80::adec:c91c:d116:7592", .dst = "fe80::2001:8000:0", 158 .ifname = IFNAME_INT, .di = PFIL_IN, 159 .stateful_ret = RESULT_BLOCK, .ret = RESULT_BLOCK 160 }, 161 { /* fe80::3 */ 162 .af = AF_INET6, 163 .src = "fe80::adec:c91c:d116:7592", .dst = "fe80::3", 164 .ifname = IFNAME_INT, .di = PFIL_IN, 165 .stateful_ret = RESULT_PASS, .ret = RESULT_PASS 166 }, 167 { /* fe80::3000:0:0/97 */ 168 .af = AF_INET6, 169 .src = "fe80::adec:c91c:d116:7592", .dst = "fe80::3000:7fff:0", 170 .ifname = IFNAME_INT, .di = PFIL_IN, 171 .stateful_ret = RESULT_PASS, .ret = RESULT_PASS 172 }, 173 { /* fe80::3000:0:0/97, one bit off */ 174 .af = AF_INET6, 175 .src = "fe80::adec:c91c:d116:7592", .dst = "fe80::3000:ffff:0", 176 .ifname = IFNAME_INT, .di = PFIL_IN, 177 .stateful_ret = RESULT_BLOCK, .ret = RESULT_BLOCK 178 }, 179 { 180 .af = AF_INET6, 181 .src = "fe80::adec:c91c:d116:7592", .dst = "fe80::4", 182 .ifname = IFNAME_INT, .di = PFIL_IN, 183 .stateful_ret = RESULT_BLOCK, .ret = RESULT_BLOCK 184 }, 185 186 /* Block. */ 187 { 188 .af = AF_INET, 189 .src = "10.1.1.1", .dst = "10.1.1.4", 190 .ifname = IFNAME_INT, .di = PFIL_OUT, 191 .stateful_ret = RESULT_BLOCK, .ret = RESULT_BLOCK 192 }, 193 194 }; 195 196 static int 197 run_raw_testcase(unsigned i) 198 { 199 const struct test_case *t = &test_cases[i]; 200 npf_t *npf = npf_getkernctx(); 201 npf_cache_t *npc; 202 struct mbuf *m; 203 npf_rule_t *rl; 204 int slock, error; 205 206 m = mbuf_get_pkt(t->af, IPPROTO_UDP, t->src, t->dst, 9000, 9000); 207 npc = get_cached_pkt(m, t->ifname); 208 209 slock = npf_config_read_enter(npf); 210 rl = npf_ruleset_inspect(npc, npf_config_ruleset(npf), t->di, NPF_LAYER_3); 211 if (rl) { 212 npf_match_info_t mi; 213 error = npf_rule_conclude(rl, &mi); 214 } else { 215 error = ENOENT; 216 } 217 npf_config_read_exit(npf, slock); 218 219 put_cached_pkt(npc); 220 return error; 221 } 222 223 static int 224 run_handler_testcase(unsigned i) 225 { 226 const struct test_case *t = &test_cases[i]; 227 ifnet_t *ifp = npf_test_getif(t->ifname); 228 npf_t *npf = npf_getkernctx(); 229 struct mbuf *m; 230 int error; 231 232 m = mbuf_get_pkt(t->af, IPPROTO_UDP, t->src, t->dst, 9000, 9000); 233 error = npfk_packet_handler(npf, &m, ifp, t->di); 234 if (m) { 235 m_freem(m); 236 } 237 return error; 238 } 239 240 static npf_rule_t * 241 npf_blockall_rule(void) 242 { 243 npf_t *npf = npf_getkernctx(); 244 nvlist_t *rule = nvlist_create(0); 245 npf_rule_t *rl; 246 247 nvlist_add_number(rule, "attr", 248 NPF_RULE_IN | NPF_RULE_OUT | NPF_RULE_DYNAMIC); 249 rl = npf_rule_alloc(npf, rule); 250 nvlist_destroy(rule); 251 return rl; 252 } 253 254 static bool 255 test_static(bool verbose) 256 { 257 for (unsigned i = 0; i < __arraycount(test_cases); i++) { 258 const struct test_case *t = &test_cases[i]; 259 int error, serror; 260 261 if (npf_test_getif(t->ifname) == NULL) { 262 printf("Interface %s is not configured.\n", t->ifname); 263 return false; 264 } 265 266 error = run_raw_testcase(i); 267 serror = run_handler_testcase(i); 268 269 if (verbose) { 270 printf("rule test %d:\texpected %d (stateful) and %d\n" 271 "\t\t-> returned %d and %d\n", 272 i + 1, t->stateful_ret, t->ret, serror, error); 273 } 274 CHECK_TRUE(error == t->ret); 275 CHECK_TRUE(serror == t->stateful_ret) 276 } 277 return true; 278 } 279 280 static bool 281 test_dynamic(void) 282 { 283 npf_t *npf = npf_getkernctx(); 284 npf_ruleset_t *rlset; 285 npf_rule_t *rl; 286 uint64_t id; 287 int error; 288 289 /* 290 * Test dynamic NPF rules. 291 */ 292 293 error = run_raw_testcase(0); 294 CHECK_TRUE(error == RESULT_PASS); 295 296 npf_config_enter(npf); 297 rlset = npf_config_ruleset(npf); 298 299 rl = npf_blockall_rule(); 300 error = npf_ruleset_add(rlset, "test-rules", rl); 301 CHECK_TRUE(error == 0); 302 303 error = run_raw_testcase(0); 304 CHECK_TRUE(error == RESULT_BLOCK); 305 306 id = npf_rule_getid(rl); 307 error = npf_ruleset_remove(rlset, "test-rules", id); 308 CHECK_TRUE(error == 0); 309 310 npf_config_exit(npf); 311 312 error = run_raw_testcase(0); 313 CHECK_TRUE(error == RESULT_PASS); 314 315 return true; 316 } 317 318 bool 319 npf_rule_test(bool verbose) 320 { 321 bool ok; 322 323 ok = test_static(verbose); 324 CHECK_TRUE(ok); 325 326 ok = test_dynamic(); 327 CHECK_TRUE(ok); 328 329 return true; 330 } 331