xref: /minix/minix/usr.bin/trace/ioctl/net.c (revision e1cdaee1)
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 	if (!valuesonly) {
112 		in.s_addr = ipaddr;
113 
114 		/* Is this an acceptable encapsulation? */
115 		put_value(proc, name, "[%s]", inet_ntoa(in));
116 	} else
117 		put_value(proc, name, "0x%08x", ntohl(ipaddr));
118 }
119 
120 static void
121 put_ipproto(struct trace_proc * proc, const char * name, ipproto_t proto)
122 {
123 	const char *text = NULL;
124 
125 	if (!valuesonly) {
126 		switch (proto) {
127 		TEXT(IPPROTO_ICMP);
128 		TEXT(IPPROTO_TCP);
129 		TEXT(IPPROTO_UDP);
130 		}
131 	}
132 
133 	if (text != NULL)
134 		put_field(proc, name, text);
135 	else
136 		put_value(proc, name, "%u", proto);
137 }
138 
139 static const struct flags tcpconf_flags[] = {
140 	FLAG_ZERO(NWTC_NOFLAGS),
141 	FLAG_MASK(NWTC_ACC_MASK, NWTC_EXCL),
142 	FLAG_MASK(NWTC_ACC_MASK, NWTC_SHARED),
143 	FLAG_MASK(NWTC_ACC_MASK, NWTC_COPY),
144 	FLAG_MASK(NWTC_LOCPORT_MASK, NWTC_LP_UNSET),
145 	FLAG_MASK(NWTC_LOCPORT_MASK, NWTC_LP_SET),
146 	FLAG_MASK(NWTC_LOCPORT_MASK, NWTC_LP_SEL),
147 	FLAG(NWTC_SET_RA),
148 	FLAG(NWTC_UNSET_RA),
149 	FLAG(NWTC_SET_RP),
150 	FLAG(NWTC_UNSET_RP),
151 };
152 
153 #define put_port(proc, name, port) \
154 	put_value(proc, name, "%u", ntohs(port))
155 
156 static const struct flags tcpcl_flags[] = {
157 	FLAG_ZERO(TCF_DEFAULT),
158 	FLAG(TCF_ASYNCH),
159 };
160 
161 static const struct flags tcpopt_flags[] = {
162 	FLAG_ZERO(NWTO_NOFLAG),
163 	FLAG(NWTO_SND_URG),
164 	FLAG(NWTO_SND_NOTURG),
165 	FLAG(NWTO_RCV_URG),
166 	FLAG(NWTO_RCV_NOTURG),
167 	FLAG(NWTO_BSD_URG),
168 	FLAG(NWTO_NOTBSD_URG),
169 	FLAG(NWTO_DEL_RST),
170 	FLAG(NWTO_BULK),
171 	FLAG(NWTO_NOBULK),
172 };
173 
174 static const struct flags udpopt_flags[] = {
175 	FLAG_ZERO(NWUO_NOFLAGS),
176 	FLAG_MASK(NWUO_ACC_MASK, NWUO_EXCL),
177 	FLAG_MASK(NWUO_ACC_MASK, NWUO_SHARED),
178 	FLAG_MASK(NWUO_ACC_MASK, NWUO_COPY),
179 	FLAG_MASK(NWUO_LOCPORT_MASK, NWUO_LP_SET),
180 	FLAG_MASK(NWUO_LOCPORT_MASK, NWUO_LP_SEL),
181 	FLAG_MASK(NWUO_LOCPORT_MASK, NWUO_LP_ANY),
182 	FLAG(NWUO_EN_LOC),
183 	FLAG(NWUO_DI_LOC),
184 	FLAG(NWUO_EN_BROAD),
185 	FLAG(NWUO_DI_BROAD),
186 	FLAG(NWUO_RP_SET),
187 	FLAG(NWUO_RP_ANY),
188 	FLAG(NWUO_RA_SET),
189 	FLAG(NWUO_RA_ANY),
190 	FLAG(NWUO_RWDATONLY),
191 	FLAG(NWUO_RWDATALL),
192 	FLAG(NWUO_EN_IPOPT),
193 	FLAG(NWUO_DI_IPOPT),
194 };
195 
196 static void
197 put_family(struct trace_proc * proc, const char * name, int family)
198 {
199 	const char *text = NULL;
200 
201 	if (!valuesonly) {
202 		/* TODO: add all the other protocols */
203 		switch (family) {
204 		TEXT(AF_UNSPEC);
205 		TEXT(AF_LOCAL);
206 		TEXT(AF_INET);
207 		TEXT(AF_INET6);
208 		}
209 	}
210 
211 	if (text != NULL)
212 		put_field(proc, name, text);
213 	else
214 		put_value(proc, name, "%d", family);
215 }
216 
217 static const struct flags sock_type[] = {
218 	FLAG_MASK(~SOCK_FLAGS_MASK, SOCK_STREAM),
219 	FLAG_MASK(~SOCK_FLAGS_MASK, SOCK_DGRAM),
220 	FLAG_MASK(~SOCK_FLAGS_MASK, SOCK_RAW),
221 	FLAG_MASK(~SOCK_FLAGS_MASK, SOCK_RDM),
222 	FLAG_MASK(~SOCK_FLAGS_MASK, SOCK_SEQPACKET),
223 	FLAG(SOCK_CLOEXEC),
224 	FLAG(SOCK_NONBLOCK),
225 	FLAG(SOCK_NOSIGPIPE),
226 };
227 
228 static void
229 put_shutdown_how(struct trace_proc * proc, const char * name, int how)
230 {
231 	const char *text = NULL;
232 
233 	if (!valuesonly) {
234 		switch (how) {
235 		TEXT(SHUT_RD);
236 		TEXT(SHUT_WR);
237 		TEXT(SHUT_RDWR);
238 		}
239 	}
240 
241 	if (text != NULL)
242 		put_field(proc, name, text);
243 	else
244 		put_value(proc, name, "%d", how);
245 }
246 
247 static void
248 put_struct_uucred(struct trace_proc * proc, const char * name, int flags,
249 	vir_bytes addr)
250 {
251 	struct uucred cred;
252 
253 	if (!put_open_struct(proc, name, flags, addr, &cred, sizeof(cred)))
254 		return;
255 
256 	put_value(proc, "cr_uid", "%u", cred.cr_uid);
257 	if (verbose > 0) {
258 		put_value(proc, "cr_gid", "%u", cred.cr_gid);
259 		if (verbose > 1)
260 			put_value(proc, "cr_ngroups", "%d", cred.cr_ngroups);
261 		put_groups(proc, "cr_groups", PF_LOCADDR,
262 		    (vir_bytes)&cred.cr_groups, cred.cr_ngroups);
263 	}
264 
265 	put_close_struct(proc, verbose > 0);
266 }
267 
268 static void
269 put_cmsg_type(struct trace_proc * proc, const char * name, int type)
270 {
271 	const char *text = NULL;
272 
273 	if (!valuesonly) {
274 		switch (type) {
275 		TEXT(SCM_RIGHTS);
276 		TEXT(SCM_CREDS);
277 		TEXT(SCM_TIMESTAMP);
278 		}
279 	}
280 
281 	if (text != NULL)
282 		put_field(proc, name, text);
283 	else
284 		put_value(proc, name, "%d", type);
285 }
286 
287 static void
288 put_msg_control(struct trace_proc * proc, struct msg_control * ptr)
289 {
290 	struct msghdr msg;
291 	struct cmsghdr *cmsg;
292 	size_t len;
293 	unsigned int i;
294 
295 	if (ptr->msg_controllen > sizeof(ptr->msg_control)) {
296 		put_field(proc, NULL, "..");
297 
298 		return;
299 	}
300 
301 	put_open(proc, NULL, PF_NONAME, "[", ", ");
302 
303 	memset(&msg, 0, sizeof(msg));
304 	msg.msg_control = ptr->msg_control;
305 	msg.msg_controllen = ptr->msg_controllen;
306 
307 	/*
308 	 * TODO: decide if we need a verbosity-based limit here.  The argument
309 	 * in favor of printing everything is that upon receipt, SCM_RIGHTS
310 	 * actually creates new file descriptors, which is pretty essential in
311 	 * terms of figuring out what is happening in a process.  In addition,
312 	 * these calls should be sufficiently rare that the lengthy output is
313 	 * not really disruptive for the general output flow.
314 	 */
315 	for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
316 	    cmsg = CMSG_NXTHDR(&msg, cmsg)) {
317 		put_open(proc, NULL, 0, "{", ", ");
318 
319 		if (verbose > 0)
320 			put_value(proc, "cmsg_len", "%u", cmsg->cmsg_len);
321 		if (!valuesonly && cmsg->cmsg_level == SOL_SOCKET)
322 			put_field(proc, "cmsg_level", "SOL_SOCKET");
323 		else
324 			put_value(proc, "cmsg_level", "%d", cmsg->cmsg_level);
325 		if (cmsg->cmsg_level == SOL_SOCKET)
326 			put_cmsg_type(proc, "cmsg_type", cmsg->cmsg_type);
327 
328 		len = cmsg->cmsg_len - CMSG_LEN(0);
329 
330 		/* Print the contents of the messages that we know. */
331 		if (cmsg->cmsg_level == SOL_SOCKET &&
332 		    cmsg->cmsg_type == SCM_RIGHTS) {
333 			put_open(proc, NULL, PF_NONAME, "[", ", ");
334 			for (i = 0; i < len / sizeof(int); i++)
335 				put_fd(proc, NULL,
336 				    ((int *)CMSG_DATA(cmsg))[i]);
337 			put_close(proc, "]");
338 		} else if (cmsg->cmsg_level == SOL_SOCKET &&
339 		    cmsg->cmsg_type == SCM_CREDS) {
340 			put_struct_uucred(proc, NULL, PF_LOCADDR,
341 			    (vir_bytes)CMSG_DATA(cmsg));
342 		} else if (len > 0)
343 			put_field(proc, NULL, "..");
344 
345 		put_close(proc, "}");
346 	}
347 
348 	put_close(proc, "]");
349 }
350 
351 int
352 net_ioctl_arg(struct trace_proc * proc, unsigned long req, void * ptr, int dir)
353 {
354 	const char *text;
355 	nwio_ipopt_t *ipopt;
356 	nwio_tcpconf_t *nwtc;
357 	nwio_tcpcl_t *nwtcl;
358 	nwio_tcpopt_t *nwto;
359 	tcp_cookie_t *cookie;
360 	nwio_udpopt_t *nwuo;
361 	struct sockaddr_un *sun;
362 	int i;
363 
364 	switch (req) {
365 	case FIONREAD:
366 		/*
367 		 * Arguably this does not belong here, but as of writing, the
368 		 * network services are the only ones actually implementing
369 		 * support for this IOCTL, and we don't have a more suitable
370 		 * place to put it either.
371 		 */
372 		if (ptr == NULL)
373 			return IF_IN;
374 
375 		put_value(proc, NULL, "%d", *(int *)ptr);
376 		return IF_ALL;
377 
378 	case NWIOSIPOPT:
379 	case NWIOGIPOPT:
380 		if ((ipopt = (nwio_ipopt_t *)ptr) == NULL)
381 			return dir;
382 
383 		put_flags(proc, "nwio_flags", ipopt_flags, COUNT(ipopt_flags),
384 		    "0x%x", ipopt->nwio_flags);
385 
386 		if (ipopt->nwio_flags & NWIO_REMSPEC)
387 			put_ipaddr(proc, "nwio_rem", ipopt->nwio_rem);
388 		if (ipopt->nwio_flags & NWIO_PROTOSPEC)
389 			put_ipproto(proc, "nwio_proto", ipopt->nwio_proto);
390 
391 		return 0; /* TODO: the remaining fields */
392 
393 	case NWIOSTCPCONF:
394 	case NWIOGTCPCONF:
395 		if ((nwtc = (nwio_tcpconf_t *)ptr) == NULL)
396 			return dir;
397 
398 		put_flags(proc, "nwtc_flags", tcpconf_flags,
399 		    COUNT(tcpconf_flags), "0x%x", nwtc->nwtc_flags);
400 
401 		/* The local address cannot be set, just retrieved. */
402 		if (req == NWIOGTCPCONF)
403 			put_ipaddr(proc, "nwtc_locaddr", nwtc->nwtc_locaddr);
404 
405 		if ((nwtc->nwtc_flags & NWTC_LOCPORT_MASK) == NWTC_LP_SET)
406 			put_port(proc, "nwtc_locport", nwtc->nwtc_locport);
407 
408 		if (nwtc->nwtc_flags & NWTC_SET_RA)
409 			put_ipaddr(proc, "nwtc_remaddr", nwtc->nwtc_remaddr);
410 
411 		if (nwtc->nwtc_flags & NWTC_SET_RP)
412 			put_port(proc, "nwtc_remport", nwtc->nwtc_remport);
413 
414 		return IF_ALL;
415 
416 	case NWIOTCPCONN:
417 	case NWIOTCPLISTEN:
418 		if ((nwtcl = (nwio_tcpcl_t *)ptr) == NULL)
419 			return dir;
420 
421 		put_flags(proc, "nwtcl_flags", tcpcl_flags,
422 		    COUNT(tcpcl_flags), "0x%x", nwtcl->nwtcl_flags);
423 
424 		/* We pretend the unused nwtcl_ttl field does not exist. */
425 		return IF_ALL;
426 
427 	case NWIOSTCPOPT:
428 	case NWIOGTCPOPT:
429 		if ((nwto = (nwio_tcpopt_t *)ptr) == NULL)
430 			return dir;
431 
432 		put_flags(proc, "nwto_flags", tcpopt_flags,
433 		    COUNT(tcpopt_flags), "0x%x", nwto->nwto_flags);
434 		return IF_ALL;
435 
436 	case NWIOTCPLISTENQ:
437 	case NWIOSUDSBLOG:
438 		if (ptr == NULL)
439 			return IF_OUT;
440 
441 		put_value(proc, NULL, "%d", *(int *)ptr);
442 		return IF_ALL;
443 
444 	case NWIOGTCPCOOKIE:
445 	case NWIOTCPACCEPTTO:
446 		if ((cookie = (tcp_cookie_t *)ptr) == NULL)
447 			return dir;
448 
449 		put_value(proc, "tc_ref", "%"PRIu32, cookie->tc_ref);
450 		if (verbose > 0)
451 			put_buf(proc, "tc_secret", PF_LOCADDR,
452 			    (vir_bytes)&cookie->tc_secret,
453 			    sizeof(cookie->tc_secret));
454 		return (verbose > 0) ? IF_ALL : 0;
455 
456 	case NWIOTCPGERROR:
457 		if (ptr == NULL)
458 			return IF_IN;
459 
460 		i = *(int *)ptr;
461 		if (!valuesonly && (text = get_error_name(i)) != NULL)
462 			put_field(proc, NULL, text);
463 		else
464 			put_value(proc, NULL, "%d", i);
465 		return IF_ALL;
466 
467 	case NWIOSUDPOPT:
468 	case NWIOGUDPOPT:
469 		if ((nwuo = (nwio_udpopt_t *)ptr) == NULL)
470 			return dir;
471 
472 		put_flags(proc, "nwuo_flags", udpopt_flags,
473 		    COUNT(udpopt_flags), "0x%x", nwuo->nwuo_flags);
474 
475 		/* The local address cannot be set, just retrieved. */
476 		if (req == NWIOGUDPOPT)
477 			put_ipaddr(proc, "nwuo_locaddr", nwuo->nwuo_locaddr);
478 
479 		if ((nwuo->nwuo_flags & NWUO_LOCPORT_MASK) == NWUO_LP_SET)
480 			put_port(proc, "nwuo_locport", nwuo->nwuo_locport);
481 
482 		if (nwuo->nwuo_flags & NWUO_RA_SET)
483 			put_ipaddr(proc, "nwuo_remaddr", nwuo->nwuo_remaddr);
484 
485 		if (nwuo->nwuo_flags & NWUO_RP_SET)
486 			put_port(proc, "nwuo_remport", nwuo->nwuo_remport);
487 
488 		return IF_ALL;
489 
490 	case NWIOGUDSFADDR:
491 	case NWIOSUDSTADDR:
492 	case NWIOSUDSADDR:
493 	case NWIOGUDSADDR:
494 	case NWIOGUDSPADDR:
495 	case NWIOSUDSCONN:
496 	case NWIOSUDSACCEPT:
497 		if ((sun = (struct sockaddr_un *)ptr) == NULL)
498 			return dir;
499 
500 		put_family(proc, "sun_family", sun->sun_family);
501 
502 		/* This could be extended to a generic sockaddr printer.. */
503 		if (sun->sun_family == AF_LOCAL) {
504 			put_buf(proc, "sun_path", PF_LOCADDR | PF_PATH,
505 			    (vir_bytes)&sun->sun_path, sizeof(sun->sun_path));
506 			return IF_ALL; /* skipping sun_len, it's unused */
507 		} else
508 			return 0;
509 
510 	case NWIOSUDSTYPE:
511 	case NWIOGUDSSOTYPE:
512 		if (ptr == NULL)
513 			return dir;
514 
515 		put_flags(proc, NULL, sock_type, COUNT(sock_type), "0x%x",
516 		    *(int *)ptr);
517 		return IF_ALL;
518 
519 	case NWIOSUDSSHUT:
520 		if (ptr == NULL)
521 			return IF_OUT;
522 
523 		put_shutdown_how(proc, NULL, *(int *)ptr);
524 		return IF_ALL;
525 
526 	case NWIOSUDSPAIR:
527 		if (ptr == NULL)
528 			return IF_OUT;
529 
530 		put_dev(proc, NULL, *(dev_t *)ptr);
531 		return IF_ALL;
532 
533 	case NWIOSUDSCTRL:
534 		if (ptr == NULL)
535 			return IF_OUT;
536 
537 		/* FALLTHROUGH */
538 	case NWIOGUDSCTRL:
539 		if (ptr == NULL)
540 			return IF_IN;
541 
542 		put_msg_control(proc, (struct msg_control *)ptr);
543 		return IF_ALL;
544 
545 	case NWIOGUDSPEERCRED:
546 		if (ptr == NULL)
547 			return IF_IN;
548 
549 		put_struct_uucred(proc, NULL, PF_LOCADDR, (vir_bytes)ptr);
550 		return IF_ALL;
551 
552 	case NWIOGUDSSNDBUF:
553 	case NWIOSUDSSNDBUF:
554 	case NWIOGUDSRCVBUF:
555 	case NWIOSUDSRCVBUF:
556 		if (ptr == NULL)
557 			return dir;
558 
559 		put_value(proc, NULL, "%zu", *(size_t *)ptr);
560 		return IF_ALL;
561 
562 	default:
563 		return 0;
564 	}
565 }
566