1 /* 2 * NPF layer 2 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 const char *src; 19 const char *dst; 20 uint16_t etype; 21 const char *ifname; 22 int di; 23 int ret; 24 } test_cases[] = { 25 { 26 /* pass ether in final from $mac1 to $mac2 type $E_IPv6 */ 27 .src = "00:00:5E:00:53:00", .dst = "00:00:5E:00:53:01", 28 .ifname = IFNAME_INT, .etype = ETHERTYPE_IPV6, 29 .di = PFIL_IN, .ret = RESULT_PASS 30 }, 31 { 32 /* block ether in final from $mac2 */ 33 .src = "00:00:5E:00:53:01", .dst = "00:00:5E:00:53:02", 34 .ifname = IFNAME_INT, .etype = ETHERTYPE_IP, 35 .di = PFIL_IN, .ret = RESULT_BLOCK 36 }, 37 38 /* pass ether out final to $mac3 $Apple talk */ 39 { 40 .src = "00:00:5E:00:53:00", .dst = "00:00:5E:00:53:02", 41 .ifname = IFNAME_INT, .etype = ETHERTYPE_ATALK, 42 .di = PFIL_OUT, .ret = RESULT_PASS 43 }, 44 { 45 /* goto default: block all (since direction is not matching ) */ 46 .src = "00:00:5E:00:53:00", .dst = "00:00:5E:00:53:02", 47 .ifname = IFNAME_INT, .etype = ETHERTYPE_IP, 48 .di = PFIL_IN, .ret = RESULT_BLOCK 49 }, 50 { 51 /* pass from nested options : 03 */ 52 .src = "00:00:5E:00:53:03", .dst = "00:00:5E:00:53:5A", 53 .ifname = IFNAME_INT, .etype = ETHERTYPE_IP, 54 .di = PFIL_IN, .ret = RESULT_PASS 55 }, 56 { 57 /* pass from nested options : 04 */ 58 .src = "00:00:5E:00:53:04", .dst = "00:00:5E:00:53:5A", 59 .ifname = IFNAME_INT, .etype = ETHERTYPE_IP, 60 .di = PFIL_IN, .ret = RESULT_PASS 61 }, 62 { 63 /* pass from nested options : 04 */ 64 .src = "00:00:5E:00:53:05", .dst = "00:00:5E:00:53:5A", 65 .ifname = IFNAME_INT, .etype = ETHERTYPE_IP, 66 .di = PFIL_IN, .ret = RESULT_PASS 67 }, 68 }; 69 70 static int 71 run_raw_testcase(unsigned i) 72 { 73 const struct test_case *t = &test_cases[i]; 74 npf_t *npf = npf_getkernctx(); 75 npf_cache_t *npc; 76 struct mbuf *m; 77 npf_rule_t *rl; 78 int slock, error; 79 80 m = mbuf_get_frame(t->src, t->dst, htons(t->etype)); 81 npc = get_cached_pkt(m, t->ifname, NPF_RULE_LAYER_2); 82 83 slock = npf_config_read_enter(npf); 84 rl = npf_ruleset_inspect(npc, npf_config_ruleset(npf), t->di, NPF_RULE_LAYER_2); 85 if (rl) { 86 npf_match_info_t mi; 87 error = npf_rule_conclude(rl, &mi); 88 } else { 89 error = ENOENT; 90 } 91 npf_config_read_exit(npf, slock); 92 93 put_cached_pkt(npc); 94 return error; 95 } 96 97 /* for dynamic testing */ 98 static int 99 run_handler_testcase(unsigned i) 100 { 101 const struct test_case *t = &test_cases[i]; 102 ifnet_t *ifp = npf_test_getif(t->ifname); 103 npf_t *npf = npf_getkernctx(); 104 struct mbuf *m; 105 int error; 106 107 m = mbuf_get_frame(t->src, t->dst, htons(t->etype)); 108 error = npfk_layer2_handler(npf, &m, ifp, t->di); 109 if (m) { 110 m_freem(m); 111 } 112 return error; 113 } 114 115 static npf_rule_t * 116 npf_blockall_rule(void) 117 { 118 npf_t *npf = npf_getkernctx(); 119 nvlist_t *rule = nvlist_create(0); 120 npf_rule_t *rl; 121 122 nvlist_add_number(rule, "attr", 123 NPF_RULE_IN | NPF_RULE_OUT | NPF_RULE_DYNAMIC | NPF_RULE_LAYER_2); 124 rl = npf_rule_alloc(npf, rule); 125 nvlist_destroy(rule); 126 return rl; 127 } 128 129 static bool 130 test_static(bool verbose) 131 { 132 for (unsigned i = 0; i < __arraycount(test_cases); i++) { 133 const struct test_case *t = &test_cases[i]; 134 int error; 135 136 if (npf_test_getif(t->ifname) == NULL) { 137 printf("Interface %s is not configured.\n", t->ifname); 138 return false; 139 } 140 141 error = run_handler_testcase(i); 142 143 if (verbose) { 144 printf("rule test %d:\texpected %d\n" 145 "\t\t-> returned %d\n", 146 i + 1, t->ret, error); 147 } 148 CHECK_TRUE(error == t->ret); 149 } 150 return true; 151 } 152 153 static bool 154 test_dynamic(void) 155 { 156 npf_t *npf = npf_getkernctx(); 157 npf_ruleset_t *rlset; 158 npf_rule_t *rl; 159 uint64_t id; 160 int error; 161 162 /* 163 * Test dynamic NPF rules. 164 */ 165 166 error = run_raw_testcase(0); 167 CHECK_TRUE(error == RESULT_PASS); 168 169 npf_config_enter(npf); 170 rlset = npf_config_ruleset(npf); 171 172 rl = npf_blockall_rule(); 173 error = npf_ruleset_add(rlset, "l2-ruleset", rl); 174 CHECK_TRUE(error == 0); 175 176 error = run_raw_testcase(0); 177 CHECK_TRUE(error == RESULT_BLOCK); 178 179 id = npf_rule_getid(rl); 180 error = npf_ruleset_remove(rlset, "l2-ruleset", id); 181 CHECK_TRUE(error == 0); 182 183 npf_config_exit(npf); 184 185 error = run_raw_testcase(0); 186 CHECK_TRUE(error == RESULT_PASS); 187 188 return true; 189 } 190 191 bool 192 npf_layer2_rule_test(bool verbose) 193 { 194 bool ok; 195 196 ok = test_static(verbose); 197 CHECK_TRUE(ok); 198 199 ok = test_dynamic(); 200 CHECK_TRUE(ok); 201 202 return true; 203 } 204