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 const char * src; 19 const char * dst; 20 const char * ifname; 21 int di; 22 int stateful_ret; 23 int ret; 24 } test_cases[] = { 25 26 /* Stateful pass. */ 27 { 28 .src = "10.1.1.1", .dst = "10.1.1.2", 29 .ifname = IFNAME_INT, .di = PFIL_OUT, 30 .stateful_ret = RESULT_PASS, .ret = RESULT_PASS 31 }, 32 { 33 .src = "10.1.1.2", .dst = "10.1.1.1", 34 .ifname = IFNAME_INT, .di = PFIL_IN, 35 .stateful_ret = RESULT_PASS, .ret = RESULT_BLOCK 36 }, 37 38 /* Pass forwards stream only. */ 39 { 40 .src = "10.1.1.1", .dst = "10.1.1.3", 41 .ifname = IFNAME_INT, .di = PFIL_OUT, 42 .stateful_ret = RESULT_PASS, .ret = RESULT_PASS 43 }, 44 { 45 .src = "10.1.1.3", .dst = "10.1.1.1", 46 .ifname = IFNAME_INT, .di = PFIL_IN, 47 .stateful_ret = RESULT_BLOCK, .ret = RESULT_BLOCK 48 }, 49 50 /* Block. */ 51 { .src = "10.1.1.1", .dst = "10.1.1.4", 52 .ifname = IFNAME_INT, .di = PFIL_OUT, 53 .stateful_ret = RESULT_BLOCK, .ret = RESULT_BLOCK 54 }, 55 56 }; 57 58 static int 59 run_raw_testcase(unsigned i) 60 { 61 const struct test_case *t = &test_cases[i]; 62 npf_t *npf = npf_getkernctx(); 63 npf_cache_t *npc; 64 struct mbuf *m; 65 npf_rule_t *rl; 66 int slock, error; 67 68 m = mbuf_get_pkt(AF_INET, IPPROTO_UDP, t->src, t->dst, 9000, 9000); 69 npc = get_cached_pkt(m, t->ifname); 70 71 slock = npf_config_read_enter(npf); 72 rl = npf_ruleset_inspect(npc, npf_config_ruleset(npf), t->di, NPF_LAYER_3); 73 if (rl) { 74 npf_match_info_t mi; 75 error = npf_rule_conclude(rl, &mi); 76 } else { 77 error = ENOENT; 78 } 79 npf_config_read_exit(npf, slock); 80 81 put_cached_pkt(npc); 82 return error; 83 } 84 85 static int 86 run_handler_testcase(unsigned i) 87 { 88 const struct test_case *t = &test_cases[i]; 89 ifnet_t *ifp = npf_test_getif(t->ifname); 90 npf_t *npf = npf_getkernctx(); 91 struct mbuf *m; 92 int error; 93 94 m = mbuf_get_pkt(AF_INET, IPPROTO_UDP, t->src, t->dst, 9000, 9000); 95 error = npfk_packet_handler(npf, &m, ifp, t->di); 96 if (m) { 97 m_freem(m); 98 } 99 return error; 100 } 101 102 static npf_rule_t * 103 npf_blockall_rule(void) 104 { 105 npf_t *npf = npf_getkernctx(); 106 nvlist_t *rule = nvlist_create(0); 107 npf_rule_t *rl; 108 109 nvlist_add_number(rule, "attr", 110 NPF_RULE_IN | NPF_RULE_OUT | NPF_RULE_DYNAMIC); 111 rl = npf_rule_alloc(npf, rule); 112 nvlist_destroy(rule); 113 return rl; 114 } 115 116 static bool 117 test_static(bool verbose) 118 { 119 for (unsigned i = 0; i < __arraycount(test_cases); i++) { 120 const struct test_case *t = &test_cases[i]; 121 int error, serror; 122 123 if (npf_test_getif(t->ifname) == NULL) { 124 printf("Interface %s is not configured.\n", t->ifname); 125 return false; 126 } 127 128 error = run_raw_testcase(i); 129 serror = run_handler_testcase(i); 130 131 if (verbose) { 132 printf("rule test %d:\texpected %d (stateful) and %d\n" 133 "\t\t-> returned %d and %d\n", 134 i + 1, t->stateful_ret, t->ret, serror, error); 135 } 136 CHECK_TRUE(error == t->ret); 137 CHECK_TRUE(serror == t->stateful_ret) 138 } 139 return true; 140 } 141 142 static bool 143 test_dynamic(void) 144 { 145 npf_t *npf = npf_getkernctx(); 146 npf_ruleset_t *rlset; 147 npf_rule_t *rl; 148 uint64_t id; 149 int error; 150 151 /* 152 * Test dynamic NPF rules. 153 */ 154 155 error = run_raw_testcase(0); 156 CHECK_TRUE(error == RESULT_PASS); 157 158 npf_config_enter(npf); 159 rlset = npf_config_ruleset(npf); 160 161 rl = npf_blockall_rule(); 162 error = npf_ruleset_add(rlset, "test-rules", rl); 163 CHECK_TRUE(error == 0); 164 165 error = run_raw_testcase(0); 166 CHECK_TRUE(error == RESULT_BLOCK); 167 168 id = npf_rule_getid(rl); 169 error = npf_ruleset_remove(rlset, "test-rules", id); 170 CHECK_TRUE(error == 0); 171 172 npf_config_exit(npf); 173 174 error = run_raw_testcase(0); 175 CHECK_TRUE(error == RESULT_PASS); 176 177 return true; 178 } 179 180 bool 181 npf_rule_test(bool verbose) 182 { 183 bool ok; 184 185 ok = test_static(verbose); 186 CHECK_TRUE(ok); 187 188 ok = test_dynamic(); 189 CHECK_TRUE(ok); 190 191 return true; 192 } 193