1 /* $NetBSD: npf_rule_test.c,v 1.14 2017/01/29 04:12:52 christos Exp $ */ 2 3 /* 4 * NPF ruleset test. 5 * 6 * Public Domain. 7 */ 8 9 #ifdef _KERNEL 10 #include <sys/types.h> 11 #endif 12 13 #include "npf_impl.h" 14 #include "npf_test.h" 15 16 #define RESULT_PASS 0 17 #define RESULT_BLOCK ENETUNREACH 18 19 static const struct test_case { 20 const char * src; 21 const char * dst; 22 const char * ifname; 23 int di; 24 int stateful_ret; 25 int ret; 26 } test_cases[] = { 27 28 /* Stateful pass. */ 29 { 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 .src = "10.1.1.2", .dst = "10.1.1.1", 36 .ifname = IFNAME_INT, .di = PFIL_IN, 37 .stateful_ret = RESULT_PASS, .ret = RESULT_BLOCK 38 }, 39 40 /* Pass forwards stream only. */ 41 { 42 .src = "10.1.1.1", .dst = "10.1.1.3", 43 .ifname = IFNAME_INT, .di = PFIL_OUT, 44 .stateful_ret = RESULT_PASS, .ret = RESULT_PASS 45 }, 46 { 47 .src = "10.1.1.3", .dst = "10.1.1.1", 48 .ifname = IFNAME_INT, .di = PFIL_IN, 49 .stateful_ret = RESULT_BLOCK, .ret = RESULT_BLOCK 50 }, 51 52 /* Block. */ 53 { .src = "10.1.1.1", .dst = "10.1.1.4", 54 .ifname = IFNAME_INT, .di = PFIL_OUT, 55 .stateful_ret = RESULT_BLOCK, .ret = RESULT_BLOCK 56 }, 57 58 }; 59 60 static struct mbuf * 61 fill_packet(const struct test_case *t) 62 { 63 struct mbuf *m; 64 struct ip *ip; 65 struct udphdr *uh; 66 67 m = mbuf_construct(IPPROTO_UDP); 68 uh = mbuf_return_hdrs(m, false, &ip); 69 ip->ip_src.s_addr = inet_addr(t->src); 70 ip->ip_dst.s_addr = inet_addr(t->dst); 71 uh->uh_sport = htons(9000); 72 uh->uh_dport = htons(9000); 73 return m; 74 } 75 76 static int 77 npf_rule_raw_test(bool verbose, struct mbuf *m, ifnet_t *ifp, int di) 78 { 79 npf_t *npf = npf_getkernctx(); 80 npf_cache_t npc = { .npc_info = 0, .npc_ctx = npf }; 81 nbuf_t nbuf; 82 npf_rule_t *rl; 83 npf_match_info_t mi; 84 int error; 85 86 nbuf_init(npf, &nbuf, m, ifp); 87 npc.npc_nbuf = &nbuf; 88 npf_cache_all(&npc); 89 90 int slock = npf_config_read_enter(); 91 rl = npf_ruleset_inspect(&npc, npf_config_ruleset(npf), 92 di, NPF_LAYER_3); 93 if (rl) { 94 error = npf_rule_conclude(rl, &mi); 95 } else { 96 error = ENOENT; 97 } 98 npf_config_read_exit(slock); 99 return error; 100 } 101 102 static int 103 npf_test_case(u_int i, bool verbose) 104 { 105 const struct test_case *t = &test_cases[i]; 106 ifnet_t *ifp = npf_test_getif(t->ifname); 107 int error; 108 109 struct mbuf *m = fill_packet(t); 110 error = npf_rule_raw_test(verbose, m, ifp, t->di); 111 m_freem(m); 112 return error; 113 } 114 115 static npf_rule_t * 116 npf_blockall_rule(void) 117 { 118 npf_t *npf = npf_getkernctx(); 119 prop_dictionary_t rldict; 120 121 rldict = prop_dictionary_create(); 122 prop_dictionary_set_uint32(rldict, "attr", 123 NPF_RULE_IN | NPF_RULE_OUT | NPF_RULE_DYNAMIC); 124 return npf_rule_alloc(npf, rldict); 125 } 126 127 bool 128 npf_rule_test(bool verbose) 129 { 130 npf_t *npf = npf_getkernctx(); 131 npf_ruleset_t *rlset; 132 npf_rule_t *rl; 133 bool fail = false; 134 uint64_t id; 135 int error; 136 137 for (unsigned i = 0; i < __arraycount(test_cases); i++) { 138 const struct test_case *t = &test_cases[i]; 139 ifnet_t *ifp = npf_test_getif(t->ifname); 140 int serror; 141 142 if (ifp == NULL) { 143 printf("Interface %s is not configured.\n", t->ifname); 144 return false; 145 } 146 147 struct mbuf *m = fill_packet(t); 148 error = npf_rule_raw_test(verbose, m, ifp, t->di); 149 serror = npf_packet_handler(npf, &m, ifp, t->di); 150 151 if (m) { 152 m_freem(m); 153 } 154 155 if (verbose) { 156 printf("Rule test %d, expected %d (stateful) and %d \n" 157 "-> returned %d and %d.\n", 158 i + 1, t->stateful_ret, t->ret, serror, error); 159 } 160 fail |= (serror != t->stateful_ret || error != t->ret); 161 } 162 163 /* 164 * Test dynamic NPF rules. 165 */ 166 167 error = npf_test_case(0, verbose); 168 assert(error == RESULT_PASS); 169 170 npf_config_enter(npf); 171 rlset = npf_config_ruleset(npf); 172 173 rl = npf_blockall_rule(); 174 error = npf_ruleset_add(rlset, "test-rules", rl); 175 fail |= error != 0; 176 177 error = npf_test_case(0, verbose); 178 fail |= (error != RESULT_BLOCK); 179 180 id = npf_rule_getid(rl); 181 error = npf_ruleset_remove(rlset, "test-rules", id); 182 fail |= error != 0; 183 184 npf_config_exit(npf); 185 186 error = npf_test_case(0, verbose); 187 fail |= (error != RESULT_PASS); 188 189 return !fail; 190 } 191