xref: /netbsd-src/usr.sbin/npf/npftest/libnpftest/npf_rule_test.c (revision ba65fde2d7fefa7d39838fa5fa855e62bd606b5e)
1 /*	$NetBSD: npf_rule_test.c,v 1.7 2013/02/18 23:09:20 rmind Exp $	*/
2 
3 /*
4  * NPF ruleset test.
5  *
6  * Public Domain.
7  */
8 
9 #include <sys/types.h>
10 
11 #include "npf_impl.h"
12 #include "npf_test.h"
13 
14 #define	IFNAME_EXT	"npftest0"
15 #define	IFNAME_INT	"npftest1"
16 
17 #define	RESULT_PASS	0
18 #define	RESULT_BLOCK	ENETUNREACH
19 
20 static const struct test_case {
21 	const char *	src;
22 	const char *	dst;
23 	const char *	ifname;
24 	int		di;
25 	int		stateful_ret;
26 	int		ret;
27 } test_cases[] = {
28 
29 	/* Stateful pass. */
30 	{
31 		.src = "10.1.1.1",		.dst = "10.1.1.2",
32 		.ifname = IFNAME_INT,		.di = PFIL_OUT,
33 		.stateful_ret = RESULT_PASS,	.ret = RESULT_PASS
34 	},
35 	{
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 		.src = "10.1.1.1",		.dst = "10.1.1.3",
44 		.ifname = IFNAME_INT,		.di = PFIL_OUT,
45 		.stateful_ret = RESULT_PASS,	.ret = RESULT_PASS
46 	},
47 	{
48 		.src = "10.1.1.3",		.dst = "10.1.1.1",
49 		.ifname = IFNAME_INT,		.di = PFIL_IN,
50 		.stateful_ret = RESULT_BLOCK,	.ret = RESULT_BLOCK
51 	},
52 
53 	/* Block. */
54 	{	.src = "10.1.1.1",		.dst = "10.1.1.4",
55 		.ifname = IFNAME_INT,		.di = PFIL_OUT,
56 		.stateful_ret = RESULT_BLOCK,	.ret = RESULT_BLOCK
57 	},
58 
59 };
60 
61 static struct mbuf *
62 fill_packet(const struct test_case *t)
63 {
64 	struct mbuf *m;
65 	struct ip *ip;
66 	struct udphdr *uh;
67 
68 	m = mbuf_construct(IPPROTO_UDP);
69 	uh = mbuf_return_hdrs(m, false, &ip);
70 	ip->ip_src.s_addr = inet_addr(t->src);
71 	ip->ip_dst.s_addr = inet_addr(t->dst);
72 	uh->uh_sport = htons(9000);
73 	uh->uh_dport = htons(9000);
74 	return m;
75 }
76 
77 static int
78 npf_rule_raw_test(bool verbose, struct mbuf *m, ifnet_t *ifp, int di)
79 {
80 	npf_cache_t npc = { .npc_info = 0 };
81 	nbuf_t nbuf;
82 	npf_rule_t *rl;
83 	int retfl, error;
84 
85 	nbuf_init(&nbuf, m, ifp);
86 	npf_cache_all(&npc, &nbuf);
87 
88 	int slock = npf_config_read_enter();
89 	rl = npf_ruleset_inspect(&npc, &nbuf, npf_config_ruleset(),
90 	    di, NPF_LAYER_3);
91 	if (rl) {
92 		if (verbose) {
93 			npf_rulenc_dump(rl);
94 		}
95 		error = npf_rule_conclude(rl, &retfl);
96 	} else {
97 		error = ENOENT;
98 	}
99 	npf_config_read_exit(slock);
100 	return error;
101 }
102 
103 static int
104 npf_test_first(bool verbose)
105 {
106 	const struct test_case *t = &test_cases[0];
107 	ifnet_t *ifp = ifunit(t->ifname);
108 	int error;
109 
110 	struct mbuf *m = fill_packet(t);
111 	error = npf_rule_raw_test(verbose, m, ifp, t->di);
112 	m_freem(m);
113 	return error;
114 }
115 
116 static npf_rule_t *
117 npf_blockall_rule(void)
118 {
119 	prop_dictionary_t rldict;
120 
121 	rldict = prop_dictionary_create();
122 	prop_dictionary_set_uint32(rldict, "attributes",
123 	    NPF_RULE_IN | NPF_RULE_OUT | NPF_RULE_DYNAMIC);
124 	return npf_rule_alloc(rldict);
125 }
126 
127 bool
128 npf_rule_test(bool verbose)
129 {
130 	npf_ruleset_t *rlset;
131 	npf_rule_t *rl;
132 	bool fail = false;
133 	uint64_t id;
134 	int error;
135 
136 	for (unsigned i = 0; i < __arraycount(test_cases); i++) {
137 		const struct test_case *t = &test_cases[i];
138 		ifnet_t *ifp = ifunit(t->ifname);
139 		int serror;
140 
141 		if (ifp == NULL) {
142 			printf("Interface %s is not configured.\n", t->ifname);
143 			return false;
144 		}
145 
146 		struct mbuf *m = fill_packet(t);
147 		error = npf_rule_raw_test(verbose, m, ifp, t->di);
148 		serror = npf_packet_handler(NULL, &m, ifp, t->di);
149 
150 		if (m) {
151 			m_freem(m);
152 		}
153 
154 		if (verbose) {
155 			printf("Rule test %d, expected %d (stateful) and %d \n"
156 			    "-> returned %d and %d.\n",
157 			    i + 1, t->stateful_ret, t->ret, serror, error);
158 		}
159 		fail |= (serror != t->stateful_ret || error != t->ret);
160 	}
161 
162 	error = npf_test_first(verbose);
163 	assert(error == RESULT_PASS);
164 
165 	npf_config_enter();
166 	rlset = npf_config_ruleset();
167 
168 	rl = npf_blockall_rule();
169 	error = npf_ruleset_add(rlset, "test-rules", rl);
170 	fail |= error != 0;
171 
172 	error = npf_test_first(verbose);
173 	fail |= (error != RESULT_BLOCK);
174 
175 	id = npf_rule_getid(rl);
176 	error = npf_ruleset_remove(rlset, "test-rules", id);
177 	fail |= error != 0;
178 
179 	npf_config_exit();
180 
181 	error = npf_test_first(verbose);
182 	fail |= (error != RESULT_PASS);
183 
184 	return !fail;
185 }
186