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