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