npf_rid_test.c revision 1.1 1 1.1 joe /*
2 1.1 joe * NPF socket User/group id tests.
3 1.1 joe *
4 1.1 joe * Public Domain.
5 1.1 joe */
6 1.1 joe
7 1.1 joe #ifdef _KERNEL
8 1.1 joe #include <sys/types.h>
9 1.1 joe #include <sys/cdefs.h>
10 1.1 joe __KERNEL_RCSID(0, "$NetBSD: npf_rid_test.c,v 1.1 2025/06/01 01:07:26 joe Exp $");
11 1.1 joe #endif
12 1.1 joe
13 1.1 joe #include "npf_impl.h"
14 1.1 joe #include "npf_test.h"
15 1.1 joe
16 1.1 joe #include <netinet/in.h>
17 1.1 joe #include <sys/socket.h>
18 1.1 joe #include <sys/kauth.h>
19 1.1 joe #include <sys/socketvar.h>
20 1.1 joe #include <sys/lwp.h>
21 1.1 joe #include <sys/cpu.h>
22 1.1 joe
23 1.1 joe #define RESULT_PASS 0
24 1.1 joe #define RESULT_BLOCK ENETUNREACH
25 1.1 joe
26 1.1 joe /* this port number suitable for testing */
27 1.1 joe #define REMOTE_PORT 65500
28 1.1 joe #define LOCAL_PORT 65000
29 1.1 joe #define LOCAL_IP "127.0.0.1"
30 1.1 joe #define REMOTE_IP LOCAL_IP
31 1.1 joe
32 1.1 joe static const struct test_case {
33 1.1 joe int af;
34 1.1 joe const char * src;
35 1.1 joe uint16_t sport;
36 1.1 joe const char * dst;
37 1.1 joe uint16_t dport;
38 1.1 joe uint32_t uid;
39 1.1 joe uint32_t gid;
40 1.1 joe const char * ifname;
41 1.1 joe int di;
42 1.1 joe int ret;
43 1.1 joe int stateful_ret;
44 1.1 joe } test_cases[] = {
45 1.1 joe {
46 1.1 joe /* pass in final from $local_ip4 user $Kojo = 1001 group $wheel = 20 */
47 1.1 joe .af = AF_INET,
48 1.1 joe .src = "10.1.1.4", .sport = 9000,
49 1.1 joe .dst = LOCAL_IP, .dport = LOCAL_PORT,
50 1.1 joe .ifname = IFNAME_EXT, .di = PFIL_IN,
51 1.1 joe .uid = 1001, .gid = 20, /* matches so pass it */
52 1.1 joe .ret = RESULT_PASS, .stateful_ret = RESULT_PASS
53 1.1 joe },
54 1.1 joe {
55 1.1 joe /* connect on different UID and block */
56 1.1 joe .af = AF_INET,
57 1.1 joe .src = "10.1.1.4", .sport = 9000,
58 1.1 joe .dst = LOCAL_IP, .dport = LOCAL_PORT,
59 1.1 joe .ifname = IFNAME_EXT, .di = PFIL_IN,
60 1.1 joe .uid = 1001, .gid = 10, /* mismatch gid so block it */
61 1.1 joe .ret = RESULT_BLOCK, .stateful_ret = RESULT_BLOCK
62 1.1 joe },
63 1.1 joe {
64 1.1 joe .af = AF_INET,
65 1.1 joe .src = "10.1.1.4", .sport = 9000,
66 1.1 joe .dst = LOCAL_IP, .dport = LOCAL_PORT,
67 1.1 joe .ifname = IFNAME_EXT, .di = PFIL_IN,
68 1.1 joe .uid = 100, .gid = 20, /* mismatch uid so block it */
69 1.1 joe .ret = RESULT_BLOCK, .stateful_ret = RESULT_BLOCK
70 1.1 joe },
71 1.1 joe
72 1.1 joe
73 1.1 joe /* block out final to 127.0.0.1 user > $Kojo( > 1001) group 1 >< $wheel( IRG 1 >< 20) */
74 1.1 joe {
75 1.1 joe .af = AF_INET,
76 1.1 joe .src = LOCAL_IP, .sport = LOCAL_PORT,
77 1.1 joe .dst = REMOTE_IP, .dport = REMOTE_PORT,
78 1.1 joe .ifname = IFNAME_EXT, .di = PFIL_OUT,
79 1.1 joe .uid = 1005, .gid = 14, /* matches so blocks it */
80 1.1 joe .ret = RESULT_BLOCK, .stateful_ret = RESULT_BLOCK
81 1.1 joe },
82 1.1 joe {
83 1.1 joe .af = AF_INET,
84 1.1 joe .src = LOCAL_IP, .sport = LOCAL_PORT,
85 1.1 joe .dst = REMOTE_IP, .dport = REMOTE_PORT,
86 1.1 joe .ifname = IFNAME_EXT, .di = PFIL_OUT,
87 1.1 joe .uid = 1005, .gid = 30, /* mismatch gid so pass it */
88 1.1 joe .ret = RESULT_PASS, .stateful_ret = RESULT_PASS
89 1.1 joe },
90 1.1 joe {
91 1.1 joe .af = AF_INET,
92 1.1 joe .src = LOCAL_IP, .sport = LOCAL_PORT,
93 1.1 joe .dst = REMOTE_IP, .dport = REMOTE_PORT,
94 1.1 joe .ifname = IFNAME_EXT, .di = PFIL_OUT,
95 1.1 joe .uid = 100, .gid = 15, /* mismatch uid so pass it */
96 1.1 joe .ret = RESULT_PASS, .stateful_ret = RESULT_PASS
97 1.1 joe },
98 1.1 joe {
99 1.1 joe .af = AF_INET,
100 1.1 joe .src = LOCAL_IP, .sport = LOCAL_PORT,
101 1.1 joe .dst = REMOTE_IP, .dport = REMOTE_PORT,
102 1.1 joe .ifname = IFNAME_EXT, .di = PFIL_OUT,
103 1.1 joe .uid = 1010, .gid = 11, /* matches so blocks it */
104 1.1 joe .ret = RESULT_BLOCK, .stateful_ret = RESULT_BLOCK
105 1.1 joe },
106 1.1 joe };
107 1.1 joe
108 1.1 joe static int
109 1.1 joe run_raw_testcase(unsigned i, bool verbose)
110 1.1 joe {
111 1.1 joe const struct test_case *t = &test_cases[i];
112 1.1 joe npf_t *npf = npf_getkernctx();
113 1.1 joe npf_cache_t *npc;
114 1.1 joe struct mbuf *m;
115 1.1 joe npf_rule_t *rl;
116 1.1 joe int slock, error;
117 1.1 joe
118 1.1 joe m = mbuf_get_pkt(t->af, IPPROTO_UDP, t->src, t->dst, t->sport, t->dport);
119 1.1 joe npc = get_cached_pkt(m, t->ifname);
120 1.1 joe
121 1.1 joe slock = npf_config_read_enter(npf);
122 1.1 joe rl = npf_ruleset_inspect(npc, npf_config_ruleset(npf), t->di, NPF_LAYER_3);
123 1.1 joe if (rl) {
124 1.1 joe npf_match_info_t mi;
125 1.1 joe int id_match;
126 1.1 joe
127 1.1 joe id_match = npf_rule_match_rid(rl, npc, t->di);
128 1.1 joe error = npf_rule_conclude(rl, &mi);
129 1.1 joe if (verbose)
130 1.1 joe printf("id match is ...%d\n", id_match);
131 1.1 joe if (id_match != -1 && !id_match) {
132 1.1 joe error = npf_rule_reverse(npc, &mi, error);
133 1.1 joe }
134 1.1 joe
135 1.1 joe } else {
136 1.1 joe error = ENOENT;
137 1.1 joe }
138 1.1 joe npf_config_read_exit(npf, slock);
139 1.1 joe
140 1.1 joe put_cached_pkt(npc);
141 1.1 joe return error;
142 1.1 joe }
143 1.1 joe
144 1.1 joe static int
145 1.1 joe run_handler_testcase(unsigned i)
146 1.1 joe {
147 1.1 joe const struct test_case *t = &test_cases[i];
148 1.1 joe ifnet_t *ifp = npf_test_getif(t->ifname);
149 1.1 joe npf_t *npf = npf_getkernctx();
150 1.1 joe struct mbuf *m;
151 1.1 joe int error;
152 1.1 joe
153 1.1 joe m = mbuf_get_pkt(t->af, IPPROTO_UDP, t->src, t->dst, t->sport, t->dport);
154 1.1 joe error = npfk_packet_handler(npf, &m, ifp, t->di);
155 1.1 joe if (m) {
156 1.1 joe m_freem(m);
157 1.1 joe }
158 1.1 joe return error;
159 1.1 joe }
160 1.1 joe
161 1.1 joe /*
162 1.1 joe * we create our specific server socket here which listens on
163 1.1 joe * loopback address and port 65000. easier to test pcb lookup here since
164 1.1 joe * it will be loaded into the protocol table.
165 1.1 joe */
166 1.1 joe static struct socket *
167 1.1 joe test_socket(int dir, uid_t uid, gid_t gid)
168 1.1 joe {
169 1.1 joe struct sockaddr_in server;
170 1.1 joe struct lwp *cur = curlwp;
171 1.1 joe void *p, *rp;
172 1.1 joe
173 1.1 joe memset(&Server, 0, sizeof(server));
174 1.1 joe
175 1.1 joe server.sin_len = sizeof(server);
176 1.1 joe server.sin_family = AF_INET;
177 1.1 joe p = &server.sin_addr.s_addr;
178 1.1 joe npf_inet_pton(AF_INET, LOCAL_IP, p); /* we bind to 127.0.0.1 */
179 1.1 joe server.sin_port = htons(LOCAL_PORT);
180 1.1 joe
181 1.1 joe struct socket *so;
182 1.1 joe int error = socreate(AF_INET, &so, SOCK_DGRAM, 0, cur, NULL);
183 1.1 joe if (error) {
184 1.1 joe printf("socket creation failed: error is %d\n", error);
185 1.1 joe return NULL;
186 1.1 joe }
187 1.1 joe
188 1.1 joe solock(so);
189 1.1 joe
190 1.1 joe kauth_cred_t cred = kauth_cred_alloc();
191 1.1 joe kauth_cred_seteuid(cred, uid);
192 1.1 joe kauth_cred_setegid(cred, gid);
193 1.1 joe
194 1.1 joe kauth_cred_t old = so->so_cred;
195 1.1 joe so->so_cred = kauth_cred_dup(cred);
196 1.1 joe kauth_cred_free(old);
197 1.1 joe
198 1.1 joe sounlock(so);
199 1.1 joe
200 1.1 joe if ((error = sobind(so, (struct sockaddr *)&server, cur)) != 0) {
201 1.1 joe printf("bind failed %d\n", error);
202 1.1 joe return NULL;
203 1.1 joe }
204 1.1 joe
205 1.1 joe if (dir == PFIL_OUT) {
206 1.1 joe /* connect to an additional remote address to set the 4 tuple addr-port state */
207 1.1 joe struct sockaddr_in remote;
208 1.1 joe memset(&Remote, 0, sizeof(remote));
209 1.1 joe
210 1.1 joe remote.sin_len = sizeof(remote);
211 1.1 joe remote.sin_family = AF_INET;
212 1.1 joe rp = &remote.sin_addr.s_addr;
213 1.1 joe npf_inet_pton(AF_INET, REMOTE_IP, rp); /* we connect to 127.0.0.1 */
214 1.1 joe remote.sin_port = htons(REMOTE_PORT);
215 1.1 joe
216 1.1 joe solock(so);
217 1.1 joe if ((error = soconnect(so, (struct sockaddr *)&remote, cur)) != 0) {
218 1.1 joe printf("connect failed :%d\n", error);
219 1.1 joe return NULL;
220 1.1 joe }
221 1.1 joe sounlock(so);
222 1.1 joe }
223 1.1 joe
224 1.1 joe return so;
225 1.1 joe }
226 1.1 joe
227 1.1 joe static bool
228 1.1 joe test_static(bool verbose)
229 1.1 joe {
230 1.1 joe for (size_t i = 0; i < __arraycount(test_cases); i++) {
231 1.1 joe const struct test_case *t = &test_cases[i];
232 1.1 joe int error, serror;
233 1.1 joe struct socket *so;
234 1.1 joe
235 1.1 joe so = test_socket(t->di, t->uid, t->gid);
236 1.1 joe if (so == NULL) {
237 1.1 joe printf("socket:\n");
238 1.1 joe return false;
239 1.1 joe }
240 1.1 joe
241 1.1 joe if (npf_test_getif(t->ifname) == NULL) {
242 1.1 joe printf("Interface %s is not configured.\n", t->ifname);
243 1.1 joe return false;
244 1.1 joe }
245 1.1 joe
246 1.1 joe error = run_raw_testcase(i, verbose);
247 1.1 joe serror = run_handler_testcase(i);
248 1.1 joe
249 1.1 joe if (verbose) {
250 1.1 joe printf("rule test %d:\texpected %d (stateful) and %d\n"
251 1.1 joe "\t\t-> returned %d and %d\n",
252 1.1 joe i + 1, t->stateful_ret, t->ret, serror, error);
253 1.1 joe }
254 1.1 joe CHECK_TRUE(error == t->ret);
255 1.1 joe CHECK_TRUE(serror == t->stateful_ret)
256 1.1 joe
257 1.1 joe soclose(so);
258 1.1 joe }
259 1.1 joe return true;
260 1.1 joe }
261 1.1 joe
262 1.1 joe bool
263 1.1 joe npf_guid_test(bool verbose)
264 1.1 joe {
265 1.1 joe soinit1();
266 1.1 joe
267 1.1 joe bool ok;
268 1.1 joe
269 1.1 joe ok = test_static(verbose);
270 1.1 joe CHECK_TRUE(ok);
271 1.1 joe
272 1.1 joe return true;
273 1.1 joe }