xref: /netbsd-src/usr.sbin/npf/npftest/libnpftest/npf_rule_test.c (revision 627f7eb200a4419d89b531d55fccd2ee3ffdcde0)
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(npf);
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(npf, 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 = npfk_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