xref: /minix3/minix/usr.bin/trace/ioctl/net.c (revision 7ecc6a9247125543940025b38b2e27c7ab19b121)
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_msg_control(struct trace_proc * proc, struct msg_control * ptr)
194 {
195 	struct msghdr msg;
196 	struct cmsghdr *cmsg;
197 	size_t len;
198 	unsigned int i;
199 
200 	if (ptr->msg_controllen > sizeof(ptr->msg_control)) {
201 		put_field(proc, NULL, "..");
202 
203 		return;
204 	}
205 
206 	put_open(proc, NULL, PF_NONAME, "[", ", ");
207 
208 	memset(&msg, 0, sizeof(msg));
209 	msg.msg_control = ptr->msg_control;
210 	msg.msg_controllen = ptr->msg_controllen;
211 
212 	/*
213 	 * TODO: decide if we need a verbosity-based limit here.  The argument
214 	 * in favor of printing everything is that upon receipt, SCM_RIGHTS
215 	 * actually creates new file descriptors, which is pretty essential in
216 	 * terms of figuring out what is happening in a process.  In addition,
217 	 * these calls should be sufficiently rare that the lengthy output is
218 	 * not really disruptive for the general output flow.
219 	 */
220 	for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
221 	    cmsg = CMSG_NXTHDR(&msg, cmsg)) {
222 		put_open(proc, NULL, 0, "{", ", ");
223 
224 		if (verbose > 0)
225 			put_value(proc, "cmsg_len", "%u", cmsg->cmsg_len);
226 		if (!valuesonly && cmsg->cmsg_level == SOL_SOCKET)
227 			put_field(proc, "cmsg_level", "SOL_SOCKET");
228 		else
229 			put_value(proc, "cmsg_level", "%d", cmsg->cmsg_level);
230 		if (cmsg->cmsg_level == SOL_SOCKET)
231 			put_cmsg_type(proc, "cmsg_type", cmsg->cmsg_type);
232 
233 		len = cmsg->cmsg_len - CMSG_LEN(0);
234 
235 		/* Print the contents of the messages that we know. */
236 		if (cmsg->cmsg_level == SOL_SOCKET &&
237 		    cmsg->cmsg_type == SCM_RIGHTS) {
238 			put_open(proc, NULL, PF_NONAME, "[", ", ");
239 			for (i = 0; i < len / sizeof(int); i++)
240 				put_fd(proc, NULL,
241 				    ((int *)CMSG_DATA(cmsg))[i]);
242 			put_close(proc, "]");
243 		} else if (cmsg->cmsg_level == SOL_SOCKET &&
244 		    cmsg->cmsg_type == SCM_CREDS) {
245 			put_struct_uucred(proc, NULL, PF_LOCADDR,
246 			    (vir_bytes)CMSG_DATA(cmsg));
247 		} else if (len > 0)
248 			put_field(proc, NULL, "..");
249 
250 		put_close(proc, "}");
251 	}
252 
253 	put_close(proc, "]");
254 }
255 
256 int
257 net_ioctl_arg(struct trace_proc * proc, unsigned long req, void * ptr, int dir)
258 {
259 	const char *text;
260 	nwio_ipopt_t *ipopt;
261 	nwio_tcpconf_t *nwtc;
262 	nwio_tcpcl_t *nwtcl;
263 	nwio_tcpopt_t *nwto;
264 	tcp_cookie_t *cookie;
265 	nwio_udpopt_t *nwuo;
266 	struct sockaddr_un *sun;
267 	int i;
268 
269 	switch (req) {
270 	case FIONREAD:
271 		/*
272 		 * Arguably this does not belong here, but as of writing, the
273 		 * network services are the only ones actually implementing
274 		 * support for this IOCTL, and we don't have a more suitable
275 		 * place to put it either.
276 		 */
277 		if (ptr == NULL)
278 			return IF_IN;
279 
280 		put_value(proc, NULL, "%d", *(int *)ptr);
281 		return IF_ALL;
282 
283 	case NWIOSIPOPT:
284 	case NWIOGIPOPT:
285 		if ((ipopt = (nwio_ipopt_t *)ptr) == NULL)
286 			return dir;
287 
288 		put_flags(proc, "nwio_flags", ipopt_flags, COUNT(ipopt_flags),
289 		    "0x%x", ipopt->nwio_flags);
290 
291 		if (ipopt->nwio_flags & NWIO_REMSPEC)
292 			put_ipaddr(proc, "nwio_rem", ipopt->nwio_rem);
293 		if (ipopt->nwio_flags & NWIO_PROTOSPEC)
294 			put_ipproto(proc, "nwio_proto", ipopt->nwio_proto);
295 
296 		return 0; /* TODO: the remaining fields */
297 
298 	case NWIOSTCPCONF:
299 	case NWIOGTCPCONF:
300 		if ((nwtc = (nwio_tcpconf_t *)ptr) == NULL)
301 			return dir;
302 
303 		put_flags(proc, "nwtc_flags", tcpconf_flags,
304 		    COUNT(tcpconf_flags), "0x%x", nwtc->nwtc_flags);
305 
306 		/* The local address cannot be set, just retrieved. */
307 		if (req == NWIOGTCPCONF)
308 			put_ipaddr(proc, "nwtc_locaddr", nwtc->nwtc_locaddr);
309 
310 		if ((nwtc->nwtc_flags & NWTC_LOCPORT_MASK) == NWTC_LP_SET)
311 			put_port(proc, "nwtc_locport", nwtc->nwtc_locport);
312 
313 		if (nwtc->nwtc_flags & NWTC_SET_RA)
314 			put_ipaddr(proc, "nwtc_remaddr", nwtc->nwtc_remaddr);
315 
316 		if (nwtc->nwtc_flags & NWTC_SET_RP)
317 			put_port(proc, "nwtc_remport", nwtc->nwtc_remport);
318 
319 		return IF_ALL;
320 
321 	case NWIOTCPCONN:
322 	case NWIOTCPLISTEN:
323 		if ((nwtcl = (nwio_tcpcl_t *)ptr) == NULL)
324 			return dir;
325 
326 		put_flags(proc, "nwtcl_flags", tcpcl_flags,
327 		    COUNT(tcpcl_flags), "0x%x", nwtcl->nwtcl_flags);
328 
329 		/* We pretend the unused nwtcl_ttl field does not exist. */
330 		return IF_ALL;
331 
332 	case NWIOSTCPOPT:
333 	case NWIOGTCPOPT:
334 		if ((nwto = (nwio_tcpopt_t *)ptr) == NULL)
335 			return dir;
336 
337 		put_flags(proc, "nwto_flags", tcpopt_flags,
338 		    COUNT(tcpopt_flags), "0x%x", nwto->nwto_flags);
339 		return IF_ALL;
340 
341 	case NWIOTCPLISTENQ:
342 	case NWIOSUDSBLOG:
343 		if (ptr == NULL)
344 			return IF_OUT;
345 
346 		put_value(proc, NULL, "%d", *(int *)ptr);
347 		return IF_ALL;
348 
349 	case NWIOGTCPCOOKIE:
350 	case NWIOTCPACCEPTTO:
351 		if ((cookie = (tcp_cookie_t *)ptr) == NULL)
352 			return dir;
353 
354 		put_value(proc, "tc_ref", "%"PRIu32, cookie->tc_ref);
355 		if (verbose > 0)
356 			put_buf(proc, "tc_secret", PF_LOCADDR,
357 			    (vir_bytes)&cookie->tc_secret,
358 			    sizeof(cookie->tc_secret));
359 		return (verbose > 0) ? IF_ALL : 0;
360 
361 	case NWIOTCPGERROR:
362 		if (ptr == NULL)
363 			return IF_IN;
364 
365 		i = *(int *)ptr;
366 		if (!valuesonly && (text = get_error_name(i)) != NULL)
367 			put_field(proc, NULL, text);
368 		else
369 			put_value(proc, NULL, "%d", i);
370 		return IF_ALL;
371 
372 	case NWIOSUDPOPT:
373 	case NWIOGUDPOPT:
374 		if ((nwuo = (nwio_udpopt_t *)ptr) == NULL)
375 			return dir;
376 
377 		put_flags(proc, "nwuo_flags", udpopt_flags,
378 		    COUNT(udpopt_flags), "0x%x", nwuo->nwuo_flags);
379 
380 		/* The local address cannot be set, just retrieved. */
381 		if (req == NWIOGUDPOPT)
382 			put_ipaddr(proc, "nwuo_locaddr", nwuo->nwuo_locaddr);
383 
384 		if ((nwuo->nwuo_flags & NWUO_LOCPORT_MASK) == NWUO_LP_SET)
385 			put_port(proc, "nwuo_locport", nwuo->nwuo_locport);
386 
387 		if (nwuo->nwuo_flags & NWUO_RA_SET)
388 			put_ipaddr(proc, "nwuo_remaddr", nwuo->nwuo_remaddr);
389 
390 		if (nwuo->nwuo_flags & NWUO_RP_SET)
391 			put_port(proc, "nwuo_remport", nwuo->nwuo_remport);
392 
393 		return IF_ALL;
394 
395 	case NWIOGUDSFADDR:
396 	case NWIOSUDSTADDR:
397 	case NWIOSUDSADDR:
398 	case NWIOGUDSADDR:
399 	case NWIOGUDSPADDR:
400 	case NWIOSUDSCONN:
401 	case NWIOSUDSACCEPT:
402 		if ((sun = (struct sockaddr_un *)ptr) == NULL)
403 			return dir;
404 
405 		put_socket_family(proc, "sun_family", sun->sun_family);
406 
407 		/* This could be extended to a generic sockaddr printer.. */
408 		if (sun->sun_family == AF_LOCAL) {
409 			put_buf(proc, "sun_path", PF_LOCADDR | PF_PATH,
410 			    (vir_bytes)&sun->sun_path, sizeof(sun->sun_path));
411 			return IF_ALL; /* skipping sun_len, it's unused */
412 		} else
413 			return 0;
414 
415 	case NWIOSUDSTYPE:
416 	case NWIOGUDSSOTYPE:
417 		if (ptr == NULL)
418 			return dir;
419 
420 		put_socket_type(proc, NULL, *(int *)ptr);
421 		return IF_ALL;
422 
423 	case NWIOSUDSSHUT:
424 		if (ptr == NULL)
425 			return IF_OUT;
426 
427 		put_shutdown_how(proc, NULL, *(int *)ptr);
428 		return IF_ALL;
429 
430 	case NWIOSUDSPAIR:
431 		if (ptr == NULL)
432 			return IF_OUT;
433 
434 		put_dev(proc, NULL, *(dev_t *)ptr);
435 		return IF_ALL;
436 
437 	case NWIOSUDSCTRL:
438 		if (ptr == NULL)
439 			return IF_OUT;
440 
441 		/* FALLTHROUGH */
442 	case NWIOGUDSCTRL:
443 		if (ptr == NULL)
444 			return IF_IN;
445 
446 		put_msg_control(proc, (struct msg_control *)ptr);
447 		return IF_ALL;
448 
449 	case NWIOGUDSPEERCRED:
450 		if (ptr == NULL)
451 			return IF_IN;
452 
453 		put_struct_uucred(proc, NULL, PF_LOCADDR, (vir_bytes)ptr);
454 		return IF_ALL;
455 
456 	case NWIOGUDSSNDBUF:
457 	case NWIOSUDSSNDBUF:
458 	case NWIOGUDSRCVBUF:
459 	case NWIOSUDSRCVBUF:
460 		if (ptr == NULL)
461 			return dir;
462 
463 		put_value(proc, NULL, "%zu", *(size_t *)ptr);
464 		return IF_ALL;
465 
466 	default:
467 		return 0;
468 	}
469 }
470