npf_rule_test.c revision 1.11 1 /* $NetBSD: npf_rule_test.c,v 1.11 2014/07/20 00:37:41 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 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 struct mbuf *
59 fill_packet(const struct test_case *t)
60 {
61 struct mbuf *m;
62 struct ip *ip;
63 struct udphdr *uh;
64
65 m = mbuf_construct(IPPROTO_UDP);
66 uh = mbuf_return_hdrs(m, false, &ip);
67 ip->ip_src.s_addr = inet_addr(t->src);
68 ip->ip_dst.s_addr = inet_addr(t->dst);
69 uh->uh_sport = htons(9000);
70 uh->uh_dport = htons(9000);
71 return m;
72 }
73
74 static int
75 npf_rule_raw_test(bool verbose, struct mbuf *m, ifnet_t *ifp, int di)
76 {
77 npf_cache_t npc = { .npc_info = 0 };
78 nbuf_t nbuf;
79 npf_rule_t *rl;
80 int retfl, error;
81
82 nbuf_init(&nbuf, m, ifp);
83 npc.npc_nbuf = &nbuf;
84 npf_cache_all(&npc);
85
86 int slock = npf_config_read_enter();
87 rl = npf_ruleset_inspect(&npc, npf_config_ruleset(),
88 di, NPF_LAYER_3);
89 if (rl) {
90 error = npf_rule_conclude(rl, &retfl);
91 } else {
92 error = ENOENT;
93 }
94 npf_config_read_exit(slock);
95 return error;
96 }
97
98 static int
99 npf_test_case(u_int i, bool verbose)
100 {
101 const struct test_case *t = &test_cases[i];
102 ifnet_t *ifp = ifunit(t->ifname);
103 int error;
104
105 struct mbuf *m = fill_packet(t);
106 error = npf_rule_raw_test(verbose, m, ifp, t->di);
107 m_freem(m);
108 return error;
109 }
110
111 static npf_rule_t *
112 npf_blockall_rule(void)
113 {
114 prop_dictionary_t rldict;
115
116 rldict = prop_dictionary_create();
117 prop_dictionary_set_uint32(rldict, "attributes",
118 NPF_RULE_IN | NPF_RULE_OUT | NPF_RULE_DYNAMIC);
119 return npf_rule_alloc(rldict);
120 }
121
122 bool
123 npf_rule_test(bool verbose)
124 {
125 npf_ruleset_t *rlset;
126 npf_rule_t *rl;
127 bool fail = false;
128 uint64_t id;
129 int error;
130
131 for (unsigned i = 0; i < __arraycount(test_cases); i++) {
132 const struct test_case *t = &test_cases[i];
133 ifnet_t *ifp = ifunit(t->ifname);
134 int serror;
135
136 if (ifp == NULL) {
137 printf("Interface %s is not configured.\n", t->ifname);
138 return false;
139 }
140
141 struct mbuf *m = fill_packet(t);
142 error = npf_rule_raw_test(verbose, m, ifp, t->di);
143 serror = npf_packet_handler(NULL, &m, ifp, t->di);
144
145 if (m) {
146 m_freem(m);
147 }
148
149 if (verbose) {
150 printf("Rule test %d, expected %d (stateful) and %d \n"
151 "-> returned %d and %d.\n",
152 i + 1, t->stateful_ret, t->ret, serror, error);
153 }
154 fail |= (serror != t->stateful_ret || error != t->ret);
155 }
156
157 /*
158 * Test dynamic NPF rules.
159 */
160
161 error = npf_test_case(0, verbose);
162 assert(error == RESULT_PASS);
163
164 npf_config_enter();
165 rlset = npf_config_ruleset();
166
167 rl = npf_blockall_rule();
168 error = npf_ruleset_add(rlset, "test-rules", rl);
169 fail |= error != 0;
170
171 error = npf_test_case(0, verbose);
172 fail |= (error != RESULT_BLOCK);
173
174 id = npf_rule_getid(rl);
175 error = npf_ruleset_remove(rlset, "test-rules", id);
176 fail |= error != 0;
177
178 npf_config_exit();
179
180 error = npf_test_case(0, verbose);
181 fail |= (error != RESULT_PASS);
182
183 return !fail;
184 }
185