xref: /minix/minix/usr.bin/trace/ioctl/net.c (revision 90b80121)
1 
2 #include "inc.h"
3 
4 #include <sys/ioctl.h>
5 #include <sys/ucred.h>
6 #include <net/gen/in.h>
7 #include <net/gen/ether.h>
8 #include <net/gen/eth_io.h>
9 #include <net/gen/arp_io.h>
10 #include <net/gen/ip_io.h>
11 #include <net/gen/route.h>
12 #include <net/gen/tcp.h>
13 #include <net/gen/tcp_io.h>
14 #include <net/gen/udp.h>
15 #include <net/gen/udp_io.h>
16 #include <net/gen/udp_io_hdr.h>
17 #include <net/gen/psip_io.h>
18 #include <arpa/inet.h>
19 
20 const char *
21 net_ioctl_name(unsigned long req)
22 {
23 
24 	switch (req) {
25 	NAME(FIONREAD);
26 	NAME(NWIOSETHOPT);	/* TODO: print argument */
27 	NAME(NWIOGETHOPT);	/* TODO: print argument */
28 	NAME(NWIOGETHSTAT);	/* TODO: print argument */
29 	NAME(NWIOARPGIP);	/* TODO: print argument */
30 	NAME(NWIOARPGNEXT);	/* TODO: print argument */
31 	NAME(NWIOARPSIP);	/* TODO: print argument */
32 	NAME(NWIOARPDIP);	/* TODO: print argument */
33 	NAME(NWIOSIPCONF2);	/* TODO: print argument */
34 	NAME(NWIOSIPCONF);	/* TODO: print argument */
35 	NAME(NWIOGIPCONF2);	/* TODO: print argument */
36 	NAME(NWIOGIPCONF);	/* TODO: print argument */
37 	NAME(NWIOSIPOPT);
38 	NAME(NWIOGIPOPT);
39 	NAME(NWIOGIPOROUTE);	/* TODO: print argument */
40 	NAME(NWIOSIPOROUTE);	/* TODO: print argument */
41 	NAME(NWIODIPOROUTE);	/* TODO: print argument */
42 	NAME(NWIOGIPIROUTE);	/* TODO: print argument */
43 	NAME(NWIOSIPIROUTE);	/* TODO: print argument */
44 	NAME(NWIODIPIROUTE);	/* TODO: print argument */
45 	NAME(NWIOSTCPCONF);
46 	NAME(NWIOGTCPCONF);
47 	NAME(NWIOTCPCONN);
48 	NAME(NWIOTCPLISTEN);
49 	NAME(NWIOTCPATTACH);	/* TODO: print argument */
50 	NAME(NWIOTCPSHUTDOWN);	/* no argument */
51 	NAME(NWIOSTCPOPT);
52 	NAME(NWIOGTCPOPT);
53 	NAME(NWIOTCPPUSH);	/* no argument */
54 	NAME(NWIOTCPLISTENQ);
55 	NAME(NWIOGTCPCOOKIE);
56 	NAME(NWIOTCPACCEPTTO);
57 	NAME(NWIOTCPGERROR);
58 	NAME(NWIOSUDPOPT);
59 	NAME(NWIOGUDPOPT);
60 	NAME(NWIOUDPPEEK);	/* TODO: print argument */
61 	NAME(NWIOSPSIPOPT);	/* TODO: print argument */
62 	NAME(NWIOGPSIPOPT);	/* TODO: print argument */
63 	NAME(NWIOGUDSFADDR);
64 	NAME(NWIOSUDSTADDR);
65 	NAME(NWIOSUDSADDR);
66 	NAME(NWIOGUDSADDR);
67 	NAME(NWIOGUDSPADDR);
68 	NAME(NWIOSUDSTYPE);
69 	NAME(NWIOSUDSBLOG);
70 	NAME(NWIOSUDSCONN);
71 	NAME(NWIOSUDSSHUT);
72 	NAME(NWIOSUDSPAIR);
73 	NAME(NWIOSUDSACCEPT);
74 	NAME(NWIOSUDSCTRL);
75 	NAME(NWIOGUDSCTRL);
76 	NAME(NWIOGUDSSOTYPE);
77 	NAME(NWIOGUDSPEERCRED);
78 	NAME(NWIOGUDSSNDBUF);
79 	NAME(NWIOSUDSSNDBUF);
80 	NAME(NWIOGUDSRCVBUF);
81 	NAME(NWIOSUDSRCVBUF);
82 	}
83 
84 	return NULL;
85 }
86 
87 static const struct flags ipopt_flags[] = {
88 	FLAG_ZERO(NWIO_NOFLAGS),
89 	FLAG_MASK(NWIO_ACC_MASK, NWIO_EXCL),
90 	FLAG_MASK(NWIO_ACC_MASK, NWIO_SHARED),
91 	FLAG_MASK(NWIO_ACC_MASK, NWIO_COPY),
92 	FLAG(NWIO_EN_LOC),
93 	FLAG(NWIO_DI_LOC),
94 	FLAG(NWIO_EN_BROAD),
95 	FLAG(NWIO_DI_BROAD),
96 	FLAG(NWIO_REMSPEC),
97 	FLAG(NWIO_REMANY),
98 	FLAG(NWIO_PROTOSPEC),
99 	FLAG(NWIO_PROTOANY),
100 	FLAG(NWIO_HDR_O_SPEC),
101 	FLAG(NWIO_HDR_O_ANY),
102 	FLAG(NWIO_RWDATONLY),
103 	FLAG(NWIO_RWDATALL),
104 };
105 
106 static void
107 put_ipaddr(struct trace_proc * proc, const char * name, ipaddr_t ipaddr)
108 {
109 	struct in_addr in;
110 
111 	in.s_addr = ipaddr;
112 
113 	put_in_addr(proc, name, in);
114 }
115 
116 static void
117 put_ipproto(struct trace_proc * proc, const char * name, ipproto_t proto)
118 {
119 	const char *text = NULL;
120 
121 	if (!valuesonly) {
122 		switch (proto) {
123 		TEXT(IPPROTO_ICMP);
124 		TEXT(IPPROTO_TCP);
125 		TEXT(IPPROTO_UDP);
126 		}
127 	}
128 
129 	if (text != NULL)
130 		put_field(proc, name, text);
131 	else
132 		put_value(proc, name, "%u", proto);
133 }
134 
135 static const struct flags tcpconf_flags[] = {
136 	FLAG_ZERO(NWTC_NOFLAGS),
137 	FLAG_MASK(NWTC_ACC_MASK, NWTC_EXCL),
138 	FLAG_MASK(NWTC_ACC_MASK, NWTC_SHARED),
139 	FLAG_MASK(NWTC_ACC_MASK, NWTC_COPY),
140 	FLAG_MASK(NWTC_LOCPORT_MASK, NWTC_LP_UNSET),
141 	FLAG_MASK(NWTC_LOCPORT_MASK, NWTC_LP_SET),
142 	FLAG_MASK(NWTC_LOCPORT_MASK, NWTC_LP_SEL),
143 	FLAG(NWTC_SET_RA),
144 	FLAG(NWTC_UNSET_RA),
145 	FLAG(NWTC_SET_RP),
146 	FLAG(NWTC_UNSET_RP),
147 };
148 
149 #define put_port(proc, name, port) \
150 	put_value(proc, name, "%u", ntohs(port))
151 
152 static const struct flags tcpcl_flags[] = {
153 	FLAG_ZERO(TCF_DEFAULT),
154 	FLAG(TCF_ASYNCH),
155 };
156 
157 static const struct flags tcpopt_flags[] = {
158 	FLAG_ZERO(NWTO_NOFLAG),
159 	FLAG(NWTO_SND_URG),
160 	FLAG(NWTO_SND_NOTURG),
161 	FLAG(NWTO_RCV_URG),
162 	FLAG(NWTO_RCV_NOTURG),
163 	FLAG(NWTO_BSD_URG),
164 	FLAG(NWTO_NOTBSD_URG),
165 	FLAG(NWTO_DEL_RST),
166 	FLAG(NWTO_BULK),
167 	FLAG(NWTO_NOBULK),
168 };
169 
170 static const struct flags udpopt_flags[] = {
171 	FLAG_ZERO(NWUO_NOFLAGS),
172 	FLAG_MASK(NWUO_ACC_MASK, NWUO_EXCL),
173 	FLAG_MASK(NWUO_ACC_MASK, NWUO_SHARED),
174 	FLAG_MASK(NWUO_ACC_MASK, NWUO_COPY),
175 	FLAG_MASK(NWUO_LOCPORT_MASK, NWUO_LP_SET),
176 	FLAG_MASK(NWUO_LOCPORT_MASK, NWUO_LP_SEL),
177 	FLAG_MASK(NWUO_LOCPORT_MASK, NWUO_LP_ANY),
178 	FLAG(NWUO_EN_LOC),
179 	FLAG(NWUO_DI_LOC),
180 	FLAG(NWUO_EN_BROAD),
181 	FLAG(NWUO_DI_BROAD),
182 	FLAG(NWUO_RP_SET),
183 	FLAG(NWUO_RP_ANY),
184 	FLAG(NWUO_RA_SET),
185 	FLAG(NWUO_RA_ANY),
186 	FLAG(NWUO_RWDATONLY),
187 	FLAG(NWUO_RWDATALL),
188 	FLAG(NWUO_EN_IPOPT),
189 	FLAG(NWUO_DI_IPOPT),
190 };
191 
192 static void
193 put_struct_uucred(struct trace_proc * proc, const char * name, int flags,
194 	vir_bytes addr)
195 {
196 	struct uucred cred;
197 
198 	if (!put_open_struct(proc, name, flags, addr, &cred, sizeof(cred)))
199 		return;
200 
201 	put_value(proc, "cr_uid", "%u", cred.cr_uid);
202 	if (verbose > 0) {
203 		put_value(proc, "cr_gid", "%u", cred.cr_gid);
204 		if (verbose > 1)
205 			put_value(proc, "cr_ngroups", "%d", cred.cr_ngroups);
206 		put_groups(proc, "cr_groups", PF_LOCADDR,
207 		    (vir_bytes)&cred.cr_groups, cred.cr_ngroups);
208 	}
209 
210 	put_close_struct(proc, verbose > 0);
211 }
212 
213 static void
214 put_msg_control(struct trace_proc * proc, struct msg_control * ptr)
215 {
216 	struct msghdr msg;
217 	struct cmsghdr *cmsg;
218 	size_t len;
219 	unsigned int i;
220 
221 	if (ptr->msg_controllen > sizeof(ptr->msg_control)) {
222 		put_field(proc, NULL, "..");
223 
224 		return;
225 	}
226 
227 	put_open(proc, NULL, PF_NONAME, "[", ", ");
228 
229 	memset(&msg, 0, sizeof(msg));
230 	msg.msg_control = ptr->msg_control;
231 	msg.msg_controllen = ptr->msg_controllen;
232 
233 	/*
234 	 * TODO: decide if we need a verbosity-based limit here.  The argument
235 	 * in favor of printing everything is that upon receipt, SCM_RIGHTS
236 	 * actually creates new file descriptors, which is pretty essential in
237 	 * terms of figuring out what is happening in a process.  In addition,
238 	 * these calls should be sufficiently rare that the lengthy output is
239 	 * not really disruptive for the general output flow.
240 	 */
241 	for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
242 	    cmsg = CMSG_NXTHDR(&msg, cmsg)) {
243 		put_open(proc, NULL, 0, "{", ", ");
244 
245 		if (verbose > 0)
246 			put_value(proc, "cmsg_len", "%u", cmsg->cmsg_len);
247 		if (!valuesonly && cmsg->cmsg_level == SOL_SOCKET)
248 			put_field(proc, "cmsg_level", "SOL_SOCKET");
249 		else
250 			put_value(proc, "cmsg_level", "%d", cmsg->cmsg_level);
251 		if (cmsg->cmsg_level == SOL_SOCKET)
252 			put_cmsg_type(proc, "cmsg_type", cmsg->cmsg_type);
253 
254 		len = cmsg->cmsg_len - CMSG_LEN(0);
255 
256 		/* Print the contents of the messages that we know. */
257 		if (cmsg->cmsg_level == SOL_SOCKET &&
258 		    cmsg->cmsg_type == SCM_RIGHTS) {
259 			put_open(proc, NULL, PF_NONAME, "[", ", ");
260 			for (i = 0; i < len / sizeof(int); i++)
261 				put_fd(proc, NULL,
262 				    ((int *)CMSG_DATA(cmsg))[i]);
263 			put_close(proc, "]");
264 		} else if (cmsg->cmsg_level == SOL_SOCKET &&
265 		    cmsg->cmsg_type == SCM_CREDS) {
266 			put_struct_uucred(proc, NULL, PF_LOCADDR,
267 			    (vir_bytes)CMSG_DATA(cmsg));
268 		} else if (len > 0)
269 			put_field(proc, NULL, "..");
270 
271 		put_close(proc, "}");
272 	}
273 
274 	put_close(proc, "]");
275 }
276 
277 int
278 net_ioctl_arg(struct trace_proc * proc, unsigned long req, void * ptr, int dir)
279 {
280 	const char *text;
281 	nwio_ipopt_t *ipopt;
282 	nwio_tcpconf_t *nwtc;
283 	nwio_tcpcl_t *nwtcl;
284 	nwio_tcpopt_t *nwto;
285 	tcp_cookie_t *cookie;
286 	nwio_udpopt_t *nwuo;
287 	struct sockaddr_un *sun;
288 	int i;
289 
290 	switch (req) {
291 	case FIONREAD:
292 		/*
293 		 * Arguably this does not belong here, but as of writing, the
294 		 * network services are the only ones actually implementing
295 		 * support for this IOCTL, and we don't have a more suitable
296 		 * place to put it either.
297 		 */
298 		if (ptr == NULL)
299 			return IF_IN;
300 
301 		put_value(proc, NULL, "%d", *(int *)ptr);
302 		return IF_ALL;
303 
304 	case NWIOSIPOPT:
305 	case NWIOGIPOPT:
306 		if ((ipopt = (nwio_ipopt_t *)ptr) == NULL)
307 			return dir;
308 
309 		put_flags(proc, "nwio_flags", ipopt_flags, COUNT(ipopt_flags),
310 		    "0x%x", ipopt->nwio_flags);
311 
312 		if (ipopt->nwio_flags & NWIO_REMSPEC)
313 			put_ipaddr(proc, "nwio_rem", ipopt->nwio_rem);
314 		if (ipopt->nwio_flags & NWIO_PROTOSPEC)
315 			put_ipproto(proc, "nwio_proto", ipopt->nwio_proto);
316 
317 		return 0; /* TODO: the remaining fields */
318 
319 	case NWIOSTCPCONF:
320 	case NWIOGTCPCONF:
321 		if ((nwtc = (nwio_tcpconf_t *)ptr) == NULL)
322 			return dir;
323 
324 		put_flags(proc, "nwtc_flags", tcpconf_flags,
325 		    COUNT(tcpconf_flags), "0x%x", nwtc->nwtc_flags);
326 
327 		/* The local address cannot be set, just retrieved. */
328 		if (req == NWIOGTCPCONF)
329 			put_ipaddr(proc, "nwtc_locaddr", nwtc->nwtc_locaddr);
330 
331 		if ((nwtc->nwtc_flags & NWTC_LOCPORT_MASK) == NWTC_LP_SET)
332 			put_port(proc, "nwtc_locport", nwtc->nwtc_locport);
333 
334 		if (nwtc->nwtc_flags & NWTC_SET_RA)
335 			put_ipaddr(proc, "nwtc_remaddr", nwtc->nwtc_remaddr);
336 
337 		if (nwtc->nwtc_flags & NWTC_SET_RP)
338 			put_port(proc, "nwtc_remport", nwtc->nwtc_remport);
339 
340 		return IF_ALL;
341 
342 	case NWIOTCPCONN:
343 	case NWIOTCPLISTEN:
344 		if ((nwtcl = (nwio_tcpcl_t *)ptr) == NULL)
345 			return dir;
346 
347 		put_flags(proc, "nwtcl_flags", tcpcl_flags,
348 		    COUNT(tcpcl_flags), "0x%x", nwtcl->nwtcl_flags);
349 
350 		/* We pretend the unused nwtcl_ttl field does not exist. */
351 		return IF_ALL;
352 
353 	case NWIOSTCPOPT:
354 	case NWIOGTCPOPT:
355 		if ((nwto = (nwio_tcpopt_t *)ptr) == NULL)
356 			return dir;
357 
358 		put_flags(proc, "nwto_flags", tcpopt_flags,
359 		    COUNT(tcpopt_flags), "0x%x", nwto->nwto_flags);
360 		return IF_ALL;
361 
362 	case NWIOTCPLISTENQ:
363 	case NWIOSUDSBLOG:
364 		if (ptr == NULL)
365 			return IF_OUT;
366 
367 		put_value(proc, NULL, "%d", *(int *)ptr);
368 		return IF_ALL;
369 
370 	case NWIOGTCPCOOKIE:
371 	case NWIOTCPACCEPTTO:
372 		if ((cookie = (tcp_cookie_t *)ptr) == NULL)
373 			return dir;
374 
375 		put_value(proc, "tc_ref", "%"PRIu32, cookie->tc_ref);
376 		if (verbose > 0)
377 			put_buf(proc, "tc_secret", PF_LOCADDR,
378 			    (vir_bytes)&cookie->tc_secret,
379 			    sizeof(cookie->tc_secret));
380 		return (verbose > 0) ? IF_ALL : 0;
381 
382 	case NWIOTCPGERROR:
383 		if (ptr == NULL)
384 			return IF_IN;
385 
386 		i = *(int *)ptr;
387 		if (!valuesonly && (text = get_error_name(i)) != NULL)
388 			put_field(proc, NULL, text);
389 		else
390 			put_value(proc, NULL, "%d", i);
391 		return IF_ALL;
392 
393 	case NWIOSUDPOPT:
394 	case NWIOGUDPOPT:
395 		if ((nwuo = (nwio_udpopt_t *)ptr) == NULL)
396 			return dir;
397 
398 		put_flags(proc, "nwuo_flags", udpopt_flags,
399 		    COUNT(udpopt_flags), "0x%x", nwuo->nwuo_flags);
400 
401 		/* The local address cannot be set, just retrieved. */
402 		if (req == NWIOGUDPOPT)
403 			put_ipaddr(proc, "nwuo_locaddr", nwuo->nwuo_locaddr);
404 
405 		if ((nwuo->nwuo_flags & NWUO_LOCPORT_MASK) == NWUO_LP_SET)
406 			put_port(proc, "nwuo_locport", nwuo->nwuo_locport);
407 
408 		if (nwuo->nwuo_flags & NWUO_RA_SET)
409 			put_ipaddr(proc, "nwuo_remaddr", nwuo->nwuo_remaddr);
410 
411 		if (nwuo->nwuo_flags & NWUO_RP_SET)
412 			put_port(proc, "nwuo_remport", nwuo->nwuo_remport);
413 
414 		return IF_ALL;
415 
416 	case NWIOGUDSFADDR:
417 	case NWIOSUDSTADDR:
418 	case NWIOSUDSADDR:
419 	case NWIOGUDSADDR:
420 	case NWIOGUDSPADDR:
421 	case NWIOSUDSCONN:
422 	case NWIOSUDSACCEPT:
423 		if ((sun = (struct sockaddr_un *)ptr) == NULL)
424 			return dir;
425 
426 		put_socket_family(proc, "sun_family", sun->sun_family);
427 
428 		/* This could be extended to a generic sockaddr printer.. */
429 		if (sun->sun_family == AF_LOCAL) {
430 			put_buf(proc, "sun_path", PF_LOCADDR | PF_PATH,
431 			    (vir_bytes)&sun->sun_path, sizeof(sun->sun_path));
432 			return IF_ALL; /* skipping sun_len, it's unused */
433 		} else
434 			return 0;
435 
436 	case NWIOSUDSTYPE:
437 	case NWIOGUDSSOTYPE:
438 		if (ptr == NULL)
439 			return dir;
440 
441 		put_socket_type(proc, NULL, *(int *)ptr);
442 		return IF_ALL;
443 
444 	case NWIOSUDSSHUT:
445 		if (ptr == NULL)
446 			return IF_OUT;
447 
448 		put_shutdown_how(proc, NULL, *(int *)ptr);
449 		return IF_ALL;
450 
451 	case NWIOSUDSPAIR:
452 		if (ptr == NULL)
453 			return IF_OUT;
454 
455 		put_dev(proc, NULL, *(dev_t *)ptr);
456 		return IF_ALL;
457 
458 	case NWIOSUDSCTRL:
459 		if (ptr == NULL)
460 			return IF_OUT;
461 
462 		/* FALLTHROUGH */
463 	case NWIOGUDSCTRL:
464 		if (ptr == NULL)
465 			return IF_IN;
466 
467 		put_msg_control(proc, (struct msg_control *)ptr);
468 		return IF_ALL;
469 
470 	case NWIOGUDSPEERCRED:
471 		if (ptr == NULL)
472 			return IF_IN;
473 
474 		put_struct_uucred(proc, NULL, PF_LOCADDR, (vir_bytes)ptr);
475 		return IF_ALL;
476 
477 	case NWIOGUDSSNDBUF:
478 	case NWIOSUDSSNDBUF:
479 	case NWIOGUDSRCVBUF:
480 	case NWIOSUDSRCVBUF:
481 		if (ptr == NULL)
482 			return dir;
483 
484 		put_value(proc, NULL, "%zu", *(size_t *)ptr);
485 		return IF_ALL;
486 
487 	default:
488 		return 0;
489 	}
490 }
491