1/*
2 * dsock.c -- Darwin socket processing functions for libproc-based lsof
3 */
4
5
6/*
7 * Portions Copyright 2005 Apple Computer, Inc.  All rights reserved.
8 *
9 * Copyright 2005 Purdue Research Foundation, West Lafayette, Indiana
10 * 47907.  All rights reserved.
11 *
12 * Written by Allan Nathanson, Apple Computer, Inc., and Victor A.
13 * Abell, Purdue University.
14 *
15 * This software is not subject to any license of the American Telephone
16 * and Telegraph Company or the Regents of the University of California.
17 *
18 * Permission is granted to anyone to use this software for any purpose on
19 * any computer system, and to alter it and redistribute it freely, subject
20 * to the following restrictions:
21 *
22 * 1. Neither the authors, nor Apple Computer, Inc. nor Purdue University
23 *    are responsible for any consequences of the use of this software.
24 *
25 * 2. The origin of this software must not be misrepresented, either
26 *    by explicit claim or by omission.  Credit to the authors, Apple
27 *    Computer, Inc. and Purdue University must appear in documentation
28 *    and sources.
29 *
30 * 3. Altered versions must be plainly marked as such, and must not be
31 *    misrepresented as being the original software.
32 *
33 * 4. This notice may not be removed or altered.
34 */
35
36
37#ifndef lint
38static char copyright[] =
39"@(#) Copyright 2005 Apple Computer, Inc. and Purdue Research Foundation.\nAll rights reserved.\n";
40static char *rcsid = "$Id: dsock.c,v 1.7 2012/04/10 16:41:04 abe Exp $";
41#endif
42
43
44#include "lsof.h"
45
46
47/*
48 * IPv6_2_IPv4()  -- macro to define the address of an IPv4 address contained
49 *                 in an IPv6 address
50 */
51
52#define	IPv6_2_IPv4(v6)	(((uint8_t *)((struct in6_addr *)v6)->s6_addr)+12)
53
54
55/*
56 * process_socket() -- process socket file
57 */
58
59static void
60process_socket_common(si)
61	struct socket_fdinfo *si;
62{
63	unsigned char *fa = (unsigned char *)NULL;
64	int fam, fp, lp, unl;
65	unsigned char *la = (unsigned char *)NULL;
66
67/*
68 * Enter basic socket values.
69 */
70	(void) snpf(Lf->type, sizeof(Lf->type), "sock");
71	Lf->inp_ty = 2;
72/*
73 * Enter basic file information.
74 */
75	enter_file_info(&si->pfi);
76/*
77 * Enable size or offset display.
78 */
79	if (Fsize) {
80	    if (Lf->access == 'r')
81		Lf->sz = (SZOFFTYPE)si->psi.soi_rcv.sbi_cc;
82	    else if (Lf->access == 'w')
83		Lf->sz = (SZOFFTYPE)si->psi.soi_snd.sbi_cc;
84	    else
85		Lf->sz = (SZOFFTYPE)(si->psi.soi_rcv.sbi_cc
86		       +	     si->psi.soi_snd.sbi_cc);
87	    Lf->sz_def = 1;
88	} else
89	    Lf->off_def = 1;
90
91#if	defined(HASTCPTPIQ)
92/*
93 * Enter send and receive queue sizes.
94 */
95	Lf->lts.rq = si->psi.soi_rcv.sbi_cc;
96	Lf->lts.sq = si->psi.soi_snd.sbi_cc;
97	Lf->lts.rqs = Lf->lts.sqs = (unsigned char)1;
98#endif	/* defined(HASTCPTPIQ) */
99
100#if	defined(HASSOOPT)
101/*
102 * Enter socket options.
103 */
104	Lf->lts.ltm = (unsigned int)(si->psi.soi_linger & 0xffff);
105	Lf->lts.opt = (unsigned int)(si->psi.soi_options & 0xffff);
106	Lf->lts.pqlen = (unsigned int)si->psi.soi_incqlen;
107	Lf->lts.qlen = (unsigned int)si->psi.soi_qlen;
108	Lf->lts.qlim = (unsigned int)si->psi.soi_qlimit;
109	Lf->lts.rbsz = (unsigned long)si->psi.soi_rcv.sbi_mbmax;
110	Lf->lts.sbsz = (unsigned long)si->psi.soi_snd.sbi_mbmax;
111	Lf->lts.pqlens = Lf->lts.qlens = Lf->lts.qlims = Lf->lts.rbszs
112		       = Lf->lts.sbszs = (unsigned char)1;
113#endif	/* defined(HASSOOPT) */
114
115#if	defined(HASSOSTATE)
116/*
117 * Enter socket state.
118 */
119	Lf->lts.ss = (unsigned int)si->psi.soi_state;
120#endif	/* defined(HASSOSTATE) */
121
122/*
123 * Process socket by its associated domain family.
124 */
125	switch ((fam = si->psi.soi_family)) {
126	case AF_INET:
127	case AF_INET6:
128
129	/*
130	 * Process IPv[46] sockets.
131	 */
132	    (void) snpf(Lf->type, sizeof(Lf->type),
133			(fam == AF_INET) ? "IPv4" : "IPv6");
134	    if ((si->psi.soi_kind != SOCKINFO_IN) &&
135		(si->psi.soi_kind != SOCKINFO_TCP))
136	    {
137		break;
138	    }
139	/*
140	 * Process TCP state inclusions and exclusions, as required.
141	 */
142	    if ((si->psi.soi_kind == SOCKINFO_TCP) && (TcpStXn || TcpStIn)) {
143		int tsnx = (int)si->psi.soi_proto.pri_tcp.tcpsi_state
144			 + TcpStOff;
145
146		if ((tsnx >= 0) && (tsnx < TcpNstates)) {
147		    if (TcpStXn) {
148			if (TcpStX[tsnx]) {
149			    Lf->sf |= SELEXCLF;
150			    return;
151			}
152		    }
153		    if (TcpStIn) {
154			if (TcpStI[tsnx])
155			    TcpStI[tsnx] = 2;
156			else {
157			    Lf->sf |= SELEXCLF;
158			    return;
159			}
160		    }
161		}
162	    }
163	/*
164	 * Process an Internet domain socket.
165	 */
166	    if (Fnet) {
167		if (!FnetTy
168		||  ((FnetTy == 4) && (fam == AF_INET))
169		||  ((FnetTy == 6) && (fam == AF_INET6))
170		)
171		    Lf->sf |= SELNET;
172	    }
173	    printiproto(si->psi.soi_protocol);
174	    if ((si->psi.soi_kind == SOCKINFO_TCP)
175	    &&  si->psi.soi_proto.pri_tcp.tcpsi_tp)
176	    {
177		enter_dev_ch(print_kptr((KA_T)si->psi.soi_proto.pri_tcp.tcpsi_tp,
178					(char *)NULL, 0));
179	    } else
180		enter_dev_ch(print_kptr((KA_T)si->psi.soi_pcb, (char *)NULL, 0));
181	    if (fam == AF_INET) {
182
183	    /*
184	     * Enter IPv4 address information.
185	     */
186		if (si->psi.soi_kind == SOCKINFO_TCP) {
187
188		/*
189		 * Enter information for a TCP socket.
190		 */
191		    la = (unsigned char *)&si->psi.soi_proto.pri_tcp.tcpsi_ini.insi_laddr.ina_46.i46a_addr4;
192		    lp = (int)ntohs(si->psi.soi_proto.pri_tcp.tcpsi_ini.insi_lport);
193		    fa = (unsigned char *)&si->psi.soi_proto.pri_tcp.tcpsi_ini.insi_faddr.ina_46.i46a_addr4;
194		    fp = (int)ntohs(si->psi.soi_proto.pri_tcp.tcpsi_ini.insi_fport);
195		} else {
196
197		/*
198		 * Enter information for a non-TCP socket.
199		 */
200		    la = (unsigned char *)&si->psi.soi_proto.pri_in.insi_laddr.ina_46.i46a_addr4;
201		    lp = (int)ntohs(si->psi.soi_proto.pri_in.insi_lport);
202		    fa = (unsigned char *)&si->psi.soi_proto.pri_in.insi_faddr.ina_46.i46a_addr4;
203		    fp = (int)ntohs(si->psi.soi_proto.pri_in.insi_fport);
204		}
205		if ((fa && (*fa == INADDR_ANY)) && !fp) {
206		    fa = (unsigned char *)NULL;
207		    fp = 0;
208		}
209	    } else {
210
211	    /*
212	     * Enter IPv6 address information
213	     */
214		int v4mapped = 0;
215
216		if (si->psi.soi_kind == SOCKINFO_TCP)
217		{
218
219		/*
220		 * Enter TCP socket information.
221		 */
222		    la = (unsigned char *)&si->psi.soi_proto.pri_tcp.tcpsi_ini.insi_laddr.ina_6;
223		    lp = (int)ntohs(si->psi.soi_proto.pri_tcp.tcpsi_ini.insi_lport);
224		    fa = (unsigned char *)&si->psi.soi_proto.pri_tcp.tcpsi_ini.insi_faddr.ina_6;
225		    fp = (int)ntohs(si->psi.soi_proto.pri_tcp.tcpsi_ini.insi_fport);
226		    if ((si->psi.soi_proto.pri_tcp.tcpsi_ini.insi_vflag & INI_IPV4) != 0)
227			v4mapped = 1;
228		} else {
229
230		/*
231		 * Enter non-TCP socket information.
232		 */
233		    la = (unsigned char *)&si->psi.soi_proto.pri_in.insi_laddr.ina_6;
234		    lp = (int)ntohs(si->psi.soi_proto.pri_in.insi_lport);
235		    fa = (unsigned char *)&si->psi.soi_proto.pri_in.insi_faddr.ina_6;
236		    fp = (int)ntohs(si->psi.soi_proto.pri_in.insi_fport);
237		    if ((si->psi.soi_proto.pri_in.insi_vflag & INI_IPV4) != 0)
238			v4mapped = 1;
239		}
240		if (IN6_IS_ADDR_UNSPECIFIED((struct in6_addr *)fa) && !fp) {
241		    fa = (unsigned char *)NULL;
242		    fp = 0;
243		}
244		if (v4mapped) {
245
246		/*
247		 * Adjust IPv4 addresses mapped in IPv6 addresses.
248		 */
249		    fam = AF_INET;
250		    if (la)
251			la = (unsigned char *)IPv6_2_IPv4(la);
252		    if (fa)
253			fa = (unsigned char *)IPv6_2_IPv4(fa);
254		}
255	    }
256	/*
257	 * Enter local and remote addresses by address family.
258	 */
259	    if (fa || la)
260		(void) ent_inaddr(la, lp, fa, fp, fam);
261	    if (si->psi.soi_kind == SOCKINFO_TCP) {
262
263	    /*
264	     * Enter a TCP socket definition and its state.
265	     */
266		Lf->lts.type = 0;
267		Lf->lts.state.i = (int)si->psi.soi_proto.pri_tcp.tcpsi_state;
268	    /*
269	     * Enter TCP options.
270	     */
271
272#if	defined(HASSOOPT)
273		Lf->lts.kai = (unsigned int)si->psi.soi_proto.pri_tcp.tcpsi_timer[TCPT_KEEP];
274#endif	/* defined(HASSOOPT) */
275
276#if	defined(HASTCPOPT)
277		Lf->lts.mss = (unsigned long)si->psi.soi_proto.pri_tcp.tcpsi_mss;
278		Lf->lts.msss = (unsigned char)1;
279		Lf->lts.topt = (unsigned int)si->psi.soi_proto.pri_tcp.tcpsi_flags;
280#endif	/* defined(HASTCPOPT) */
281
282	    }
283	    break;
284	case AF_UNIX:
285
286	/*
287	 * Process a UNIX domain socket.
288	 */
289	    (void) snpf(Lf->type, sizeof(Lf->type), "unix");
290	    if (si->psi.soi_kind != SOCKINFO_UN)
291		break;
292	    if (Funix)
293		Lf->sf |= SELUNX;
294	    enter_dev_ch(print_kptr((KA_T)si->psi.soi_pcb, (char *)NULL, 0));
295	/*
296	 * Enter information on a UNIX domain socket that has no address bound
297	 * to it, although it may be connected to another UNIX domain socket
298	 * as a pipe.
299	 */
300	    if (si->psi.soi_proto.pri_un.unsi_addr.ua_sun.sun_family != AF_UNIX)
301	    {
302		if (si->psi.soi_proto.pri_un.unsi_addr.ua_sun.sun_family
303		==  AF_UNSPEC)
304		{
305		    if (si->psi.soi_proto.pri_un.unsi_conn_pcb) {
306			    (void) snpf(Namech, Namechl, "->%s",
307				print_kptr((KA_T)si->psi.soi_proto.pri_un.unsi_conn_pcb, (char *)NULL, 0));
308		    } else
309			(void) snpf(Namech, Namechl, "->(none)");
310		} else
311		    (void) snpf(Namech, Namechl, "unknown sun_family (%d)",
312			si->psi.soi_proto.pri_un.unsi_addr.ua_sun.sun_family);
313		break;
314	    }
315	    if (si->psi.soi_proto.pri_un.unsi_addr.ua_sun.sun_path[0]) {
316		unl = si->psi.soi_proto.pri_un.unsi_addr.ua_sun.sun_len - offsetof(struct sockaddr_un, sun_path);
317		if ((unl < 0) || (unl >= sizeof(si->psi.soi_proto.pri_un.unsi_addr.ua_sun.sun_path)))
318		    unl = sizeof(si->psi.soi_proto.pri_un.unsi_addr.ua_sun.sun_path) - 1;
319		si->psi.soi_proto.pri_un.unsi_addr.ua_sun.sun_path[unl] = '\0';
320		if (si->psi.soi_proto.pri_un.unsi_addr.ua_sun.sun_path[0]
321		&&  Sfile
322		&&  is_file_named(si->psi.soi_proto.pri_un.unsi_addr.ua_sun.sun_path, 0))
323		    Lf->sf |= SELNM;
324		if (si->psi.soi_proto.pri_un.unsi_addr.ua_sun.sun_path[0]
325		&&  !Namech[0])
326		    (void) snpf(Namech, Namechl, "%s", si->psi.soi_proto.pri_un.unsi_addr.ua_sun.sun_path);
327	    } else
328		(void) snpf(Namech, Namechl, "no address");
329	    break;
330	case AF_ROUTE:
331
332	/*
333	 * Process a ROUTE domain socket.
334	 */
335	    (void) snpf(Lf->type, sizeof(Lf->type), "rte");
336	    if (!Fsize)
337		Lf->off_def = 1;
338	    break;
339	case AF_NDRV:
340
341	/*
342	 * Process an NDRV domain socket.
343	 */
344	    (void) snpf(Lf->type, sizeof(Lf->type), "ndrv");
345	    if (si->psi.soi_kind != SOCKINFO_NDRV)
346		break;
347	    enter_dev_ch(print_kptr((KA_T)si->psi.soi_pcb, (char *)NULL, 0));
348	    si->psi.soi_proto.pri_ndrv.ndrvsi_if_name[sizeof(si->psi.soi_proto.pri_ndrv.ndrvsi_if_name) - 1] = '\0';
349	    (void) snpf(Namech, Namechl, "-> %s%d",
350			si->psi.soi_proto.pri_ndrv.ndrvsi_if_name,
351			si->psi.soi_proto.pri_ndrv.ndrvsi_if_unit);
352	    break;
353	case pseudo_AF_KEY:
354
355	/*
356	 * Process an [internal] key-management function socket.
357	 */
358	    (void) snpf(Lf->type, sizeof(Lf->type), "key");
359	    enter_dev_ch(print_kptr((KA_T)si->psi.soi_pcb, (char *)NULL, 0));
360	    break;
361	case AF_SYSTEM:
362
363	/*
364	 * Process a SYSTEM domain socket.
365	 */
366	    (void) snpf(Lf->type, sizeof(Lf->type), "systm");
367	    if (si->psi.soi_kind != SOCKINFO_KERN_EVENT)
368		break;
369	    enter_dev_ch(print_kptr((KA_T)si->psi.soi_pcb, (char *)NULL, 0));
370	    (void) snpf(Namech, Namechl, "[%x:%x:%x]",
371			si->psi.soi_proto.pri_kern_event.kesi_vendor_code_filter,
372			si->psi.soi_proto.pri_kern_event.kesi_class_filter,
373			si->psi.soi_proto.pri_kern_event.kesi_subclass_filter);
374	    break;
375	case AF_PPP:
376
377	/*
378	 * Process a PPP domain socket.
379	 */
380	    (void) snpf(Lf->type, sizeof(Lf->type), "ppp");
381	    enter_dev_ch(print_kptr((KA_T)si->psi.soi_pcb, (char *)NULL, 0));
382	    break;
383	default:
384	    printunkaf(fam, 1);
385	}
386/*
387 * If there are NAME column characters, enter them.
388 */
389	if (Namech[0])
390	    enter_nm(Namech);
391}
392
393
394void
395process_socket(pid, fd)
396	int pid;			/* PID */
397	int32_t fd;			/* FD */
398{
399	int nb;
400	struct socket_fdinfo si;
401/*
402 * Get socket information.
403 */
404	nb = proc_pidfdinfo(pid, fd, PROC_PIDFDSOCKETINFO, &si, sizeof(si));
405	if (nb <= 0) {
406	    (void) err2nm("socket");
407	    return;
408	} else if (nb < sizeof(si)) {
409	    (void) fprintf(stderr,
410		"%s: PID %d, FD %d: proc_pidfdinfo(PROC_PIDFDSOCKETINFO);\n",
411		Pn, pid, fd);
412	    (void) fprintf(stderr,
413		"      too few bytes; expected %ld, got %d\n",
414		sizeof(si), nb);
415	    Exit(1);
416	}
417
418	process_socket_common(&si);
419}
420
421
422#ifdef	PROC_PIDLISTFILEPORTS
423void
424process_fileport_socket(pid, fp)
425	int pid;			/* PID */
426	uint32_t fp;			/* FILEPORT */
427{
428	int nb;
429	struct socket_fdinfo si;
430/*
431 * Get socket information.
432 */
433	nb = proc_pidfileportinfo(pid, fp, PROC_PIDFILEPORTSOCKETINFO, &si, sizeof(si));
434	if (nb <= 0) {
435	    (void) err2nm("socket");
436	    return;
437	} else if (nb < sizeof(si)) {
438	    (void) fprintf(stderr,
439		"%s: PID %d, FILEPORT %u: proc_pidfileportinfo(PROC_PIDFILEPORTSOCKETINFO);\n",
440		Pn, pid, fp);
441	    (void) fprintf(stderr,
442		"      too few bytes; expected %ld, got %d\n",
443		sizeof(si), nb);
444	    Exit(1);
445	}
446
447	process_socket_common(&si);
448}
449#endif	/* PROC_PIDLISTFILEPORTS */
450