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