npf_rule_test.c revision 1.20 1 1.1 rmind /*
2 1.16 rmind * NPF ruleset tests.
3 1.1 rmind *
4 1.1 rmind * Public Domain.
5 1.1 rmind */
6 1.1 rmind
7 1.13 christos #ifdef _KERNEL
8 1.1 rmind #include <sys/types.h>
9 1.13 christos #endif
10 1.1 rmind
11 1.1 rmind #include "npf_impl.h"
12 1.1 rmind #include "npf_test.h"
13 1.1 rmind
14 1.1 rmind #define RESULT_PASS 0
15 1.1 rmind #define RESULT_BLOCK ENETUNREACH
16 1.1 rmind
17 1.1 rmind static const struct test_case {
18 1.20 riastrad int af;
19 1.1 rmind const char * src;
20 1.1 rmind const char * dst;
21 1.1 rmind const char * ifname;
22 1.1 rmind int di;
23 1.1 rmind int stateful_ret;
24 1.1 rmind int ret;
25 1.1 rmind } test_cases[] = {
26 1.1 rmind
27 1.1 rmind /* Stateful pass. */
28 1.1 rmind {
29 1.20 riastrad .af = AF_INET,
30 1.1 rmind .src = "10.1.1.1", .dst = "10.1.1.2",
31 1.1 rmind .ifname = IFNAME_INT, .di = PFIL_OUT,
32 1.1 rmind .stateful_ret = RESULT_PASS, .ret = RESULT_PASS
33 1.1 rmind },
34 1.1 rmind {
35 1.20 riastrad .af = AF_INET,
36 1.1 rmind .src = "10.1.1.2", .dst = "10.1.1.1",
37 1.1 rmind .ifname = IFNAME_INT, .di = PFIL_IN,
38 1.1 rmind .stateful_ret = RESULT_PASS, .ret = RESULT_BLOCK
39 1.1 rmind },
40 1.1 rmind
41 1.1 rmind /* Pass forwards stream only. */
42 1.1 rmind {
43 1.20 riastrad .af = AF_INET,
44 1.1 rmind .src = "10.1.1.1", .dst = "10.1.1.3",
45 1.1 rmind .ifname = IFNAME_INT, .di = PFIL_OUT,
46 1.1 rmind .stateful_ret = RESULT_PASS, .ret = RESULT_PASS
47 1.1 rmind },
48 1.1 rmind {
49 1.20 riastrad .af = AF_INET,
50 1.1 rmind .src = "10.1.1.3", .dst = "10.1.1.1",
51 1.1 rmind .ifname = IFNAME_INT, .di = PFIL_IN,
52 1.1 rmind .stateful_ret = RESULT_BLOCK, .ret = RESULT_BLOCK
53 1.1 rmind },
54 1.1 rmind
55 1.1 rmind /* Block. */
56 1.20 riastrad {
57 1.20 riastrad .af = AF_INET,
58 1.20 riastrad .src = "10.1.1.1", .dst = "10.1.1.4",
59 1.1 rmind .ifname = IFNAME_INT, .di = PFIL_OUT,
60 1.1 rmind .stateful_ret = RESULT_BLOCK, .ret = RESULT_BLOCK
61 1.1 rmind },
62 1.1 rmind
63 1.1 rmind };
64 1.1 rmind
65 1.1 rmind static int
66 1.17 rmind run_raw_testcase(unsigned i)
67 1.1 rmind {
68 1.17 rmind const struct test_case *t = &test_cases[i];
69 1.13 christos npf_t *npf = npf_getkernctx();
70 1.17 rmind npf_cache_t *npc;
71 1.17 rmind struct mbuf *m;
72 1.1 rmind npf_rule_t *rl;
73 1.17 rmind int slock, error;
74 1.17 rmind
75 1.20 riastrad m = mbuf_get_pkt(t->af, IPPROTO_UDP, t->src, t->dst, 9000, 9000);
76 1.17 rmind npc = get_cached_pkt(m, t->ifname);
77 1.1 rmind
78 1.19 rmind slock = npf_config_read_enter(npf);
79 1.17 rmind rl = npf_ruleset_inspect(npc, npf_config_ruleset(npf), t->di, NPF_LAYER_3);
80 1.1 rmind if (rl) {
81 1.17 rmind npf_match_info_t mi;
82 1.14 christos error = npf_rule_conclude(rl, &mi);
83 1.1 rmind } else {
84 1.1 rmind error = ENOENT;
85 1.1 rmind }
86 1.19 rmind npf_config_read_exit(npf, slock);
87 1.17 rmind
88 1.17 rmind put_cached_pkt(npc);
89 1.1 rmind return error;
90 1.1 rmind }
91 1.1 rmind
92 1.4 rmind static int
93 1.17 rmind run_handler_testcase(unsigned i)
94 1.4 rmind {
95 1.8 rmind const struct test_case *t = &test_cases[i];
96 1.13 christos ifnet_t *ifp = npf_test_getif(t->ifname);
97 1.17 rmind npf_t *npf = npf_getkernctx();
98 1.17 rmind struct mbuf *m;
99 1.4 rmind int error;
100 1.4 rmind
101 1.20 riastrad m = mbuf_get_pkt(t->af, IPPROTO_UDP, t->src, t->dst, 9000, 9000);
102 1.18 rmind error = npfk_packet_handler(npf, &m, ifp, t->di);
103 1.17 rmind if (m) {
104 1.17 rmind m_freem(m);
105 1.17 rmind }
106 1.4 rmind return error;
107 1.4 rmind }
108 1.4 rmind
109 1.4 rmind static npf_rule_t *
110 1.4 rmind npf_blockall_rule(void)
111 1.4 rmind {
112 1.13 christos npf_t *npf = npf_getkernctx();
113 1.15 rmind nvlist_t *rule = nvlist_create(0);
114 1.17 rmind npf_rule_t *rl;
115 1.4 rmind
116 1.15 rmind nvlist_add_number(rule, "attr",
117 1.7 rmind NPF_RULE_IN | NPF_RULE_OUT | NPF_RULE_DYNAMIC);
118 1.17 rmind rl = npf_rule_alloc(npf, rule);
119 1.17 rmind nvlist_destroy(rule);
120 1.17 rmind return rl;
121 1.4 rmind }
122 1.4 rmind
123 1.17 rmind static bool
124 1.17 rmind test_static(bool verbose)
125 1.1 rmind {
126 1.1 rmind for (unsigned i = 0; i < __arraycount(test_cases); i++) {
127 1.1 rmind const struct test_case *t = &test_cases[i];
128 1.17 rmind int error, serror;
129 1.1 rmind
130 1.17 rmind if (npf_test_getif(t->ifname) == NULL) {
131 1.1 rmind printf("Interface %s is not configured.\n", t->ifname);
132 1.1 rmind return false;
133 1.1 rmind }
134 1.1 rmind
135 1.17 rmind error = run_raw_testcase(i);
136 1.17 rmind serror = run_handler_testcase(i);
137 1.1 rmind
138 1.1 rmind if (verbose) {
139 1.16 rmind printf("rule test %d:\texpected %d (stateful) and %d\n"
140 1.16 rmind "\t\t-> returned %d and %d\n",
141 1.1 rmind i + 1, t->stateful_ret, t->ret, serror, error);
142 1.1 rmind }
143 1.17 rmind CHECK_TRUE(error == t->ret);
144 1.17 rmind CHECK_TRUE(serror == t->stateful_ret)
145 1.1 rmind }
146 1.17 rmind return true;
147 1.17 rmind }
148 1.17 rmind
149 1.17 rmind static bool
150 1.17 rmind test_dynamic(void)
151 1.17 rmind {
152 1.17 rmind npf_t *npf = npf_getkernctx();
153 1.17 rmind npf_ruleset_t *rlset;
154 1.17 rmind npf_rule_t *rl;
155 1.17 rmind uint64_t id;
156 1.17 rmind int error;
157 1.4 rmind
158 1.8 rmind /*
159 1.8 rmind * Test dynamic NPF rules.
160 1.8 rmind */
161 1.8 rmind
162 1.17 rmind error = run_raw_testcase(0);
163 1.16 rmind CHECK_TRUE(error == RESULT_PASS);
164 1.4 rmind
165 1.13 christos npf_config_enter(npf);
166 1.13 christos rlset = npf_config_ruleset(npf);
167 1.4 rmind
168 1.4 rmind rl = npf_blockall_rule();
169 1.4 rmind error = npf_ruleset_add(rlset, "test-rules", rl);
170 1.16 rmind CHECK_TRUE(error == 0);
171 1.4 rmind
172 1.17 rmind error = run_raw_testcase(0);
173 1.16 rmind CHECK_TRUE(error == RESULT_BLOCK);
174 1.4 rmind
175 1.6 rmind id = npf_rule_getid(rl);
176 1.6 rmind error = npf_ruleset_remove(rlset, "test-rules", id);
177 1.16 rmind CHECK_TRUE(error == 0);
178 1.4 rmind
179 1.13 christos npf_config_exit(npf);
180 1.4 rmind
181 1.17 rmind error = run_raw_testcase(0);
182 1.16 rmind CHECK_TRUE(error == RESULT_PASS);
183 1.4 rmind
184 1.16 rmind return true;
185 1.1 rmind }
186 1.17 rmind
187 1.17 rmind bool
188 1.17 rmind npf_rule_test(bool verbose)
189 1.17 rmind {
190 1.17 rmind bool ok;
191 1.17 rmind
192 1.17 rmind ok = test_static(verbose);
193 1.17 rmind CHECK_TRUE(ok);
194 1.17 rmind
195 1.17 rmind ok = test_dynamic();
196 1.17 rmind CHECK_TRUE(ok);
197 1.17 rmind
198 1.17 rmind return true;
199 1.17 rmind }
200