1 /* $NetBSD: npf_rule_test.c,v 1.7 2013/02/18 23:09:20 rmind Exp $ */ 2 3 /* 4 * NPF ruleset test. 5 * 6 * Public Domain. 7 */ 8 9 #include <sys/types.h> 10 11 #include "npf_impl.h" 12 #include "npf_test.h" 13 14 #define IFNAME_EXT "npftest0" 15 #define IFNAME_INT "npftest1" 16 17 #define RESULT_PASS 0 18 #define RESULT_BLOCK ENETUNREACH 19 20 static const struct test_case { 21 const char * src; 22 const char * dst; 23 const char * ifname; 24 int di; 25 int stateful_ret; 26 int ret; 27 } test_cases[] = { 28 29 /* Stateful pass. */ 30 { 31 .src = "10.1.1.1", .dst = "10.1.1.2", 32 .ifname = IFNAME_INT, .di = PFIL_OUT, 33 .stateful_ret = RESULT_PASS, .ret = RESULT_PASS 34 }, 35 { 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 .src = "10.1.1.1", .dst = "10.1.1.3", 44 .ifname = IFNAME_INT, .di = PFIL_OUT, 45 .stateful_ret = RESULT_PASS, .ret = RESULT_PASS 46 }, 47 { 48 .src = "10.1.1.3", .dst = "10.1.1.1", 49 .ifname = IFNAME_INT, .di = PFIL_IN, 50 .stateful_ret = RESULT_BLOCK, .ret = RESULT_BLOCK 51 }, 52 53 /* Block. */ 54 { .src = "10.1.1.1", .dst = "10.1.1.4", 55 .ifname = IFNAME_INT, .di = PFIL_OUT, 56 .stateful_ret = RESULT_BLOCK, .ret = RESULT_BLOCK 57 }, 58 59 }; 60 61 static struct mbuf * 62 fill_packet(const struct test_case *t) 63 { 64 struct mbuf *m; 65 struct ip *ip; 66 struct udphdr *uh; 67 68 m = mbuf_construct(IPPROTO_UDP); 69 uh = mbuf_return_hdrs(m, false, &ip); 70 ip->ip_src.s_addr = inet_addr(t->src); 71 ip->ip_dst.s_addr = inet_addr(t->dst); 72 uh->uh_sport = htons(9000); 73 uh->uh_dport = htons(9000); 74 return m; 75 } 76 77 static int 78 npf_rule_raw_test(bool verbose, struct mbuf *m, ifnet_t *ifp, int di) 79 { 80 npf_cache_t npc = { .npc_info = 0 }; 81 nbuf_t nbuf; 82 npf_rule_t *rl; 83 int retfl, error; 84 85 nbuf_init(&nbuf, m, ifp); 86 npf_cache_all(&npc, &nbuf); 87 88 int slock = npf_config_read_enter(); 89 rl = npf_ruleset_inspect(&npc, &nbuf, npf_config_ruleset(), 90 di, NPF_LAYER_3); 91 if (rl) { 92 if (verbose) { 93 npf_rulenc_dump(rl); 94 } 95 error = npf_rule_conclude(rl, &retfl); 96 } else { 97 error = ENOENT; 98 } 99 npf_config_read_exit(slock); 100 return error; 101 } 102 103 static int 104 npf_test_first(bool verbose) 105 { 106 const struct test_case *t = &test_cases[0]; 107 ifnet_t *ifp = ifunit(t->ifname); 108 int error; 109 110 struct mbuf *m = fill_packet(t); 111 error = npf_rule_raw_test(verbose, m, ifp, t->di); 112 m_freem(m); 113 return error; 114 } 115 116 static npf_rule_t * 117 npf_blockall_rule(void) 118 { 119 prop_dictionary_t rldict; 120 121 rldict = prop_dictionary_create(); 122 prop_dictionary_set_uint32(rldict, "attributes", 123 NPF_RULE_IN | NPF_RULE_OUT | NPF_RULE_DYNAMIC); 124 return npf_rule_alloc(rldict); 125 } 126 127 bool 128 npf_rule_test(bool verbose) 129 { 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 = ifunit(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(NULL, &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 error = npf_test_first(verbose); 163 assert(error == RESULT_PASS); 164 165 npf_config_enter(); 166 rlset = npf_config_ruleset(); 167 168 rl = npf_blockall_rule(); 169 error = npf_ruleset_add(rlset, "test-rules", rl); 170 fail |= error != 0; 171 172 error = npf_test_first(verbose); 173 fail |= (error != RESULT_BLOCK); 174 175 id = npf_rule_getid(rl); 176 error = npf_ruleset_remove(rlset, "test-rules", id); 177 fail |= error != 0; 178 179 npf_config_exit(); 180 181 error = npf_test_first(verbose); 182 fail |= (error != RESULT_PASS); 183 184 return !fail; 185 } 186