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