npf_l2rule_test.c revision 1.3 1 /*
2 * NPF layer 2 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 uint16_t etype;
21 const char *ifname;
22 int di;
23 int ret;
24 } test_cases[] = {
25 {
26 /* pass ether in final from $mac1 to $mac2 type $E_IPv6 */
27 .src = "00:00:5E:00:53:00", .dst = "00:00:5E:00:53:01",
28 .ifname = IFNAME_INT, .etype = ETHERTYPE_IPV6,
29 .di = PFIL_IN, .ret = RESULT_PASS
30 },
31 {
32 /* block ether in final from $mac2 */
33 .src = "00:00:5E:00:53:01", .dst = "00:00:5E:00:53:02",
34 .ifname = IFNAME_INT, .etype = ETHERTYPE_IP,
35 .di = PFIL_IN, .ret = RESULT_BLOCK
36 },
37
38 /* pass ether out final to $mac3 $Apple talk */
39 {
40 .src = "00:00:5E:00:53:00", .dst = "00:00:5E:00:53:02",
41 .ifname = IFNAME_INT, .etype = ETHERTYPE_ATALK,
42 .di = PFIL_OUT, .ret = RESULT_PASS
43 },
44 {
45 /* goto default: block all (since direction is not matching ) */
46 .src = "00:00:5E:00:53:00", .dst = "00:00:5E:00:53:02",
47 .ifname = IFNAME_INT, .etype = ETHERTYPE_IP,
48 .di = PFIL_IN, .ret = RESULT_BLOCK
49 },
50 {
51 /* pass from nested options : 03 */
52 .src = "00:00:5E:00:53:03", .dst = "00:00:5E:00:53:5A",
53 .ifname = IFNAME_INT, .etype = ETHERTYPE_IP,
54 .di = PFIL_IN, .ret = RESULT_PASS
55 },
56 {
57 /* pass from nested options : 04 */
58 .src = "00:00:5E:00:53:04", .dst = "00:00:5E:00:53:5A",
59 .ifname = IFNAME_INT, .etype = ETHERTYPE_IP,
60 .di = PFIL_IN, .ret = RESULT_PASS
61 },
62 {
63 /* pass from nested options : 04 */
64 .src = "00:00:5E:00:53:05", .dst = "00:00:5E:00:53:5A",
65 .ifname = IFNAME_INT, .etype = ETHERTYPE_IP,
66 .di = PFIL_IN, .ret = RESULT_PASS
67 },
68 };
69
70 static int
71 run_raw_testcase(unsigned i)
72 {
73 const struct test_case *t = &test_cases[i];
74 npf_t *npf = npf_getkernctx();
75 npf_cache_t *npc;
76 struct mbuf *m;
77 npf_rule_t *rl;
78 int slock, error;
79
80 m = mbuf_get_frame(t->src, t->dst, htons(t->etype));
81 npc = get_cached_pkt(m, t->ifname, NPF_RULE_LAYER_2);
82
83 slock = npf_config_read_enter(npf);
84 rl = npf_ruleset_inspect(npc, npf_config_ruleset(npf), t->di, NPF_RULE_LAYER_2);
85 if (rl) {
86 npf_match_info_t mi;
87 error = npf_rule_conclude(rl, &mi);
88 } else {
89 error = ENOENT;
90 }
91 npf_config_read_exit(npf, slock);
92
93 put_cached_pkt(npc);
94 return error;
95 }
96
97 /* for dynamic testing */
98 static int
99 run_handler_testcase(unsigned i)
100 {
101 const struct test_case *t = &test_cases[i];
102 ifnet_t *ifp = npf_test_getif(t->ifname);
103 npf_t *npf = npf_getkernctx();
104 struct mbuf *m;
105 int error;
106
107 m = mbuf_get_frame(t->src, t->dst, htons(t->etype));
108 error = npfk_layer2_handler(npf, &m, ifp, t->di);
109 if (m) {
110 m_freem(m);
111 }
112 return error;
113 }
114
115 static npf_rule_t *
116 npf_blockall_rule(void)
117 {
118 npf_t *npf = npf_getkernctx();
119 nvlist_t *rule = nvlist_create(0);
120 npf_rule_t *rl;
121
122 nvlist_add_number(rule, "attr",
123 NPF_RULE_IN | NPF_RULE_OUT | NPF_RULE_DYNAMIC | NPF_RULE_LAYER_2);
124 rl = npf_rule_alloc(npf, rule);
125 nvlist_destroy(rule);
126 return rl;
127 }
128
129 static bool
130 test_static(bool verbose)
131 {
132 for (unsigned i = 0; i < __arraycount(test_cases); i++) {
133 const struct test_case *t = &test_cases[i];
134 int error;
135
136 if (npf_test_getif(t->ifname) == NULL) {
137 printf("Interface %s is not configured.\n", t->ifname);
138 return false;
139 }
140
141 error = run_handler_testcase(i);
142
143 if (verbose) {
144 printf("rule test %d:\texpected %d\n"
145 "\t\t-> returned %d\n",
146 i + 1, t->ret, error);
147 }
148 CHECK_TRUE(error == t->ret);
149 }
150 return true;
151 }
152
153 static bool
154 test_dynamic(void)
155 {
156 npf_t *npf = npf_getkernctx();
157 npf_ruleset_t *rlset;
158 npf_rule_t *rl;
159 uint64_t id;
160 int error;
161
162 /*
163 * Test dynamic NPF rules.
164 */
165
166 error = run_raw_testcase(0);
167 CHECK_TRUE(error == RESULT_PASS);
168
169 npf_config_enter(npf);
170 rlset = npf_config_ruleset(npf);
171
172 rl = npf_blockall_rule();
173 error = npf_ruleset_add(rlset, "l2-ruleset", rl);
174 CHECK_TRUE(error == 0);
175
176 error = run_raw_testcase(0);
177 CHECK_TRUE(error == RESULT_BLOCK);
178
179 id = npf_rule_getid(rl);
180 error = npf_ruleset_remove(rlset, "l2-ruleset", id);
181 CHECK_TRUE(error == 0);
182
183 npf_config_exit(npf);
184
185 error = run_raw_testcase(0);
186 CHECK_TRUE(error == RESULT_PASS);
187
188 return true;
189 }
190
191 bool
192 npf_layer2_rule_test(bool verbose)
193 {
194 bool ok;
195
196 ok = test_static(verbose);
197 CHECK_TRUE(ok);
198
199 ok = test_dynamic();
200 CHECK_TRUE(ok);
201
202 return true;
203 }
204