1 /* $NetBSD: npf_rule_test.c,v 1.13 2016/12/26 23:05:05 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 int retfl, error; 84 85 nbuf_init(npf, &nbuf, m, ifp); 86 npc.npc_nbuf = &nbuf; 87 npf_cache_all(&npc); 88 89 int slock = npf_config_read_enter(); 90 rl = npf_ruleset_inspect(&npc, npf_config_ruleset(npf), 91 di, NPF_LAYER_3); 92 if (rl) { 93 error = npf_rule_conclude(rl, &retfl); 94 } else { 95 error = ENOENT; 96 } 97 npf_config_read_exit(slock); 98 return error; 99 } 100 101 static int 102 npf_test_case(u_int i, bool verbose) 103 { 104 const struct test_case *t = &test_cases[i]; 105 ifnet_t *ifp = npf_test_getif(t->ifname); 106 int error; 107 108 struct mbuf *m = fill_packet(t); 109 error = npf_rule_raw_test(verbose, m, ifp, t->di); 110 m_freem(m); 111 return error; 112 } 113 114 static npf_rule_t * 115 npf_blockall_rule(void) 116 { 117 npf_t *npf = npf_getkernctx(); 118 prop_dictionary_t rldict; 119 120 rldict = prop_dictionary_create(); 121 prop_dictionary_set_uint32(rldict, "attr", 122 NPF_RULE_IN | NPF_RULE_OUT | NPF_RULE_DYNAMIC); 123 return npf_rule_alloc(npf, rldict); 124 } 125 126 bool 127 npf_rule_test(bool verbose) 128 { 129 npf_t *npf = npf_getkernctx(); 130 npf_ruleset_t *rlset; 131 npf_rule_t *rl; 132 bool fail = false; 133 uint64_t id; 134 int error; 135 136 for (unsigned i = 0; i < __arraycount(test_cases); i++) { 137 const struct test_case *t = &test_cases[i]; 138 ifnet_t *ifp = npf_test_getif(t->ifname); 139 int serror; 140 141 if (ifp == NULL) { 142 printf("Interface %s is not configured.\n", t->ifname); 143 return false; 144 } 145 146 struct mbuf *m = fill_packet(t); 147 error = npf_rule_raw_test(verbose, m, ifp, t->di); 148 serror = npf_packet_handler(npf, &m, ifp, t->di); 149 150 if (m) { 151 m_freem(m); 152 } 153 154 if (verbose) { 155 printf("Rule test %d, expected %d (stateful) and %d \n" 156 "-> returned %d and %d.\n", 157 i + 1, t->stateful_ret, t->ret, serror, error); 158 } 159 fail |= (serror != t->stateful_ret || error != t->ret); 160 } 161 162 /* 163 * Test dynamic NPF rules. 164 */ 165 166 error = npf_test_case(0, verbose); 167 assert(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, "test-rules", rl); 174 fail |= error != 0; 175 176 error = npf_test_case(0, verbose); 177 fail |= (error != RESULT_BLOCK); 178 179 id = npf_rule_getid(rl); 180 error = npf_ruleset_remove(rlset, "test-rules", id); 181 fail |= error != 0; 182 183 npf_config_exit(npf); 184 185 error = npf_test_case(0, verbose); 186 fail |= (error != RESULT_PASS); 187 188 return !fail; 189 } 190