1/*
2 * dsock.c - Darwin socket processing functions for /dev/kmem-based lsof
3 */
4
5/*
6 * Special Darwin socket info: Justin Walker, 000927
7 */
8
9/*
10 * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana
11 * 47907.  All rights reserved.
12 *
13 * Written by Victor A. Abell
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 Purdue University are responsible for any
23 *    consequences of the use of this software.
24 *
25 * 2. The origin of this software must not be misrepresented, either by
26 *    explicit claim or by omission.  Credit to the authors and Purdue
27 *    University must appear in documentation and sources.
28 *
29 * 3. Altered versions must be plainly marked as such, and must not be
30 *    misrepresented as being the original software.
31 *
32 * 4. This notice may not be removed or altered.
33 */
34
35#ifndef lint
36static char copyright[] =
37"@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n";
38static char *rcsid = "$Id: dsock.c,v 1.11 2005/11/01 20:24:51 abe Exp $";
39#endif
40
41
42#include "lsof.h"
43
44
45#if	defined(HASIPv6)
46/*
47 * IPv6_2_IPv4()  -- macro to define the address of an IPv4 address contained
48 *                 in an IPv6 address
49 */
50
51#define	IPv6_2_IPv4(v6)	(((uint8_t *)((struct in6_addr *)v6)->s6_addr)+12)
52#endif	/* defined(HASIPv6) */
53
54
55/*
56 * process_socket() - process socket
57 */
58
59void
60process_socket(sa)
61	KA_T sa;			/* socket address in kernel */
62{
63	struct domain d;
64	unsigned char *fa = (unsigned char *)NULL;
65	int fam, lp;
66	int fp = 0;
67	struct inpcb inp;
68	unsigned char *la = (unsigned char *)NULL;
69	struct protosw p;
70	struct socket s;
71	struct tcpcb t;
72	KA_T ta = (KA_T)NULL;
73	struct unpcb uc, unp;
74	struct sockaddr_un *ua = NULL;
75	struct sockaddr_un un;
76	int unl;
77
78#if	defined(HASIPv6)
79	struct in6pcb in6p;
80#endif	/* defined(HASIPv6) */
81
82#if	defined(AF_SYSTEM)
83	struct kern_event_pcb kev_cb;
84#endif	/* defined(AF_SYSTEM) */
85
86#if	defined(AF_NDRV)
87	char buf[IFNAMSIZ];
88	struct ndrv_cb ndrv_cb;
89	struct ifnet ifnet;
90#endif	/* defined(AF_NDRV) */
91
92	(void) snpf(Lf->type, sizeof(Lf->type), "sock");
93	Lf->inp_ty = 2;
94/*
95 * Read the socket, protocol, and domain structures.
96 */
97	if (!sa) {
98	    enter_nm("no socket address");
99	    return;
100	}
101	if (kread(sa, (char *)&s, sizeof(s))) {
102	    (void) snpf(Namech, Namechl, "can't read socket struct from %s",
103		print_kptr(sa, (char *)NULL, 0));
104	    enter_nm(Namech);
105	    return;
106	}
107	if (!s.so_type) {
108	    enter_nm("no socket type");
109	    return;
110	}
111	if (!s.so_proto
112	||  kread((KA_T)s.so_proto, (char *)&p, sizeof(p))) {
113	    (void) snpf(Namech, Namechl, "can't read protocol switch from %s",
114		print_kptr((KA_T)s.so_proto, (char *)NULL, 0));
115	    enter_nm(Namech);
116	    return;
117	}
118	if (!p.pr_domain
119	||  kread((KA_T)p.pr_domain, (char *)&d, sizeof(d))) {
120	    (void) snpf(Namech, Namechl, "can't read domain struct from %s",
121		print_kptr((KA_T)p.pr_domain, (char *)NULL, 0));
122	    enter_nm(Namech);
123	    return;
124	}
125/*
126 * Save size information.
127 */
128	if (Fsize) {
129	    if (Lf->access == 'r')
130		Lf->sz = (SZOFFTYPE)s.so_rcv.sb_cc;
131	    else if (Lf->access == 'w')
132		Lf->sz = (SZOFFTYPE)s.so_snd.sb_cc;
133	    else
134		Lf->sz = (SZOFFTYPE)(s.so_rcv.sb_cc + s.so_snd.sb_cc);
135	    Lf->sz_def = 1;
136	} else
137	    Lf->off_def = 1;
138
139#if	defined(HASTCPTPIQ)
140	Lf->lts.rq = s.so_rcv.sb_cc;
141	Lf->lts.sq = s.so_snd.sb_cc;
142	Lf->lts.rqs = Lf->lts.sqs = 1;
143#endif	/* defined(HASTCPTPIQ) */
144
145#if	defined(HASSOOPT)
146	Lf->lts.ltm = (unsigned int)(s.so_linger & 0xffff);
147	Lf->lts.opt = (unsigned int)(s.so_options & 0xffff);
148	Lf->lts.pqlen = (unsigned int)s.so_incqlen;
149	Lf->lts.qlen = (unsigned int)s.so_qlen;
150	Lf->lts.qlim = (unsigned int)s.so_qlimit;
151	Lf->lts.rbsz = (unsigned long)s.so_rcv.sb_mbmax;
152	Lf->lts.sbsz = (unsigned long)s.so_snd.sb_mbmax;
153	Lf->lts.pqlens = Lf->lts.qlens = Lf->lts.qlims = Lf->lts.rbszs
154		       = Lf->lts.sbszs = (unsigned char)1;
155#endif	/* defined(HASSOOPT) */
156
157#if	defined(HASSOSTATE)
158	Lf->lts.ss = (unsigned int)s.so_state;
159#endif	/* defined(HASSOSTATE) */
160
161/*
162 * Process socket by the associated domain family.
163 */
164	switch ((fam = d.dom_family)) {
165/*
166 * Process an Internet domain socket.
167 */
168	case AF_INET:
169
170#if	defined(HASIPv6)
171	case AF_INET6:
172#endif	/* defined(HASIPv6) */
173
174	    if (Fnet) {
175		if (!FnetTy
176		||  ((FnetTy == 4) && (fam == AF_INET))
177
178#if	defined(HASIPv6)
179		||  ((FnetTy == 6) && (fam == AF_INET6))
180#endif	/* defined(HASIPv6) */
181
182		)
183		    Lf->sf |= SELNET;
184	    }
185	    printiproto(p.pr_protocol);
186
187#if	defined(HASIPv6)
188	    (void) snpf(Lf->type, sizeof(Lf->type),
189		(fam == AF_INET) ? "IPv4" : "IPv6");
190#else	/* !defined(HASIPv6) */
191	    (void) snpf(Lf->type, sizeof(Lf->type), "inet");
192#endif	/* defined(HASIPv6) */
193
194#if	defined(HASIPv6)
195	    if (fam == AF_INET6) {
196
197	    /*
198	     * Read IPv6 protocol control block.
199	     */
200		if (!s.so_pcb
201		||  kread((KA_T)s.so_pcb, (char *)&in6p, sizeof(in6p)))
202		{
203		    (void) snpf(Namech, Namechl, "can't read in6pcb at %s",
204			print_kptr((KA_T)s.so_pcb, (char *)NULL, 0));
205		    enter_nm(Namech);
206		    return;
207	        }
208	    /*
209	     * Save IPv6 address information.
210	     */
211		enter_dev_ch(print_kptr((KA_T)(in6p.in6p_ppcb ? in6p.in6p_ppcb
212							      : s.so_pcb),
213					       (char *)NULL, 0));
214		if (p.pr_protocol == IPPROTO_TCP)
215		    ta = (KA_T)in6p.in6p_ppcb;
216		la = (unsigned char *)&in6p.in6p_laddr;
217		lp = (int)ntohs(in6p.in6p_lport);
218		if (!IN6_IS_ADDR_UNSPECIFIED(&in6p.in6p_faddr)
219		||  in6p.in6p_fport)
220		{
221		    fa = (unsigned char *)&in6p.in6p_faddr;
222		    fp = (int)ntohs(in6p.in6p_fport);
223		}
224	    } else
225#endif	/* defined(HASIPv6) */
226
227	    {
228
229	    /*
230	     * Read IPv4 protocol control block.
231	     */
232		if (!s.so_pcb
233		||  kread((KA_T)s.so_pcb, (char *)&inp, sizeof(inp))) {
234		    if (!s.so_pcb) {
235			(void) snpf(Namech, Namechl, "no PCB%s%s",
236			    (s.so_state & SS_CANTSENDMORE) ? ", CANTSENDMORE"
237						           : "",
238			    (s.so_state & SS_CANTRCVMORE) ? ", CANTRCVMORE"
239						          : "");
240		    } else {
241			(void) snpf(Namech, Namechl, "can't read inpcb at %s",
242			    print_kptr((KA_T)s.so_pcb, (char *)NULL, 0));
243		    }
244		    enter_nm(Namech);
245		    return;
246		}
247	    /*
248	     * Print Internet socket information.
249	     */
250		enter_dev_ch(print_kptr((KA_T)(inp.inp_ppcb ? inp.inp_ppcb
251							    : s.so_pcb),
252					(char *)NULL, 0));
253	    /*
254	     * Save IPv4 address information.
255	     */
256		if (p.pr_protocol == IPPROTO_TCP)
257		    ta = (KA_T)inp.inp_ppcb;
258		la = (unsigned char *)&inp.inp_laddr;
259		lp = (int)ntohs(inp.inp_lport);
260		if (inp.inp_faddr.s_addr != INADDR_ANY || inp.inp_fport) {
261		    fa = (unsigned char *)&inp.inp_faddr;
262		    fp = (int)ntohs(inp.inp_fport);
263		}
264	    }
265
266#if	defined(HASIPv6)
267	    if ((fam == AF_INET6)
268	    &&  ((la && IN6_IS_ADDR_V4MAPPED((struct in6_addr *)la))
269	    ||  ((fa && IN6_IS_ADDR_V4MAPPED((struct in6_addr *)fa))))) {
270
271	    /*
272	     * Adjust for IPv4 addresses mapped in IPv6 addresses.
273	     */
274		if (la)
275		    la = (unsigned char *)IPv6_2_IPv4(la);
276		if (fa)
277		    fa = (unsigned char *)IPv6_2_IPv4(fa);
278		fam = AF_INET;
279	    }
280#endif	/* defined(HASIPv6) */
281
282	/*
283	 * Enter local and remote addresses by address family.
284	 */
285	    if (fa || la)
286		(void) ent_inaddr(la, lp, fa, fp, fam);
287	    if (ta && !kread(ta, (char *)&t, sizeof(t))) {
288		Lf->lts.type = 0;
289		Lf->lts.state.i = (int)t.t_state;
290
291#if	defined(HASSOOPT)
292		Lf->lts.kai = (unsigned int)t.t_timer[TCPT_KEEP];
293#endif	/* defined(HASSOOPT) */
294
295#if	defined(HASTCPOPT)
296		Lf->lts.mss = (unsigned long)t.t_maxseg;
297		Lf->lts.msss = (unsigned char)1;
298		Lf->lts.topt = (unsigned int)t.t_flags;
299#endif	/* defined(HASTCPOPT) */
300
301	    }
302	    break;
303
304#if	defined(AF_NDRV)
305/*
306 * Process an NDRV domain socket.
307 */
308	case AF_NDRV:
309	{
310	    (void) snpf(Lf->type, sizeof(Lf->type), "ndrv");
311	/*
312	 * Read protocol control block.
313	 */
314	    if (!s.so_pcb
315	    ||  kread((KA_T)s.so_pcb, (char *)&ndrv_cb, sizeof(ndrv_cb))) {
316		(void) snpf(Namech, Namechl, "can't read ndrv_cb at %s",
317		    print_kptr((KA_T)s.so_pcb, (char *)NULL, 0));
318		enter_nm(Namech);
319		return;
320	    }
321	/*
322	 * Print NDRV socket information.
323	 */
324	    enter_dev_ch(print_kptr((KA_T)(s.so_pcb), (char *)NULL, 0));
325	/*
326	 * Print device name, if bound
327	 */
328	    if (!ndrv_cb.nd_if
329	    ||  kread((KA_T)ndrv_cb.nd_if, (char *)&ifnet, sizeof(ifnet))) {
330		(void) snpf(Namech, Namechl, "can't read ifnet at %s",
331			    print_kptr((KA_T)ndrv_cb.nd_if, (char *)NULL, 0));
332		enter_nm(Namech);
333		return;
334	    }
335	    if (!ifnet.if_name
336	    ||  kread((KA_T)ifnet.if_name, buf, sizeof(buf))) {
337		(void) snpf(Namech, Namechl, "can't read ifnet.if_name at %s",
338			    print_kptr((KA_T)ifnet.if_name, (char *)NULL, 0));
339		enter_nm(Namech);
340		return;
341	    }
342	    (void) snpf(Namech, Namechl, "-> %s%d", buf, ifnet.if_unit);
343	}
344	break;
345#endif	/* defined(AF_NDRV) */
346
347#if	defined(pseudo_AF_KEY)
348/*
349 * Process an [internal] key-management function socket
350 */
351	case pseudo_AF_KEY:
352	    (void) snpf(Lf->type, sizeof(Lf->type), "key");
353	    break;
354#endif	/* defined(pseudo_AF_KEY) */
355
356#if	defined(AF_SYSTEM)
357/*
358 * Process a SYSTEM domain socket
359 */
360	case AF_SYSTEM:
361	    (void) snpf(Lf->type, sizeof(Lf->type), "systm");
362	/*
363	 * Read protocol control block.
364	 */
365	    if (!s.so_pcb
366	    ||  kread((KA_T)s.so_pcb, (char *)&kev_cb, sizeof(kev_cb))) {
367		(void) snpf(Namech, Namechl, "can't read kev_cb at %s",
368		    print_kptr((KA_T)s.so_pcb, (char *)NULL, 0));
369		enter_nm(Namech);
370		return;
371	    }
372	/*
373	 * Print SYSTEM socket information.
374	 */
375	    enter_dev_ch(print_kptr((KA_T)(s.so_pcb), (char *)NULL, 0));
376	    (void) snpf(Namech, Namechl, "[%lx:%lx:%lx]",
377			kev_cb.vendor_code_filter,
378			kev_cb.class_filter, kev_cb.subclass_filter);
379	    break;
380#endif	/* defined(AF_SYSTEM) */
381
382#if	defined(AF_PPP)
383/*
384 * Process a PPP domain socket
385 */
386	case AF_PPP:
387	    (void) snpf(Lf->type, sizeof(Lf->type), "ppp");
388	    break;
389#endif	/* defined(AF_PPP) */
390
391/*
392 * Process a ROUTE domain socket.
393 */
394	case AF_ROUTE:
395	    (void) snpf(Lf->type, sizeof(Lf->type), "rte");
396	    if (s.so_pcb)
397		enter_dev_ch(print_kptr((KA_T)(s.so_pcb), (char *)NULL, 0));
398	    else
399		(void) snpf(Namech, Namechl, "no protocol control block");
400	    if (!Fsize)
401		Lf->off_def = 1;
402	    break;
403/*
404 * Process a Unix domain socket.
405 */
406	case AF_UNIX:
407	    if (Funix)
408		Lf->sf |= SELUNX;
409	    (void) snpf(Lf->type, sizeof(Lf->type), "unix");
410	/*
411	 * Read Unix protocol control block and the Unix address structure.
412	 */
413
414	    enter_dev_ch(print_kptr(sa, (char *)NULL, 0));
415	    if (!s.so_pcb
416	    ||  kread((KA_T)s.so_pcb, (char *)&unp, sizeof(unp))) {
417		(void) snpf(Namech, Namechl, "can't read unpcb at %s",
418		    print_kptr((KA_T)s.so_pcb, (char *)NULL, 0));
419		break;
420	    }
421	    if ((struct socket *)sa != unp.unp_socket) {
422		(void) snpf(Namech, Namechl, "unp_socket (%s) mismatch",
423		    print_kptr((KA_T)unp.unp_socket, (char *)NULL, 0));
424		break;
425	    }
426	    if (unp.unp_addr) {
427		if (kread((KA_T)unp.unp_addr, (char *)&un, sizeof(un))) {
428		    (void) snpf(Namech, Namechl, "can't read unp_addr at %s",
429			print_kptr((KA_T)unp.unp_addr, (char *)NULL, 0));
430		    break;
431		}
432		ua = &un;
433	    }
434	    if (!ua) {
435		ua = &un;
436		(void) bzero((char *)ua, sizeof(un));
437		ua->sun_family = AF_UNSPEC;
438	    }
439	/*
440	 * Print information on Unix socket that has no address bound
441	 * to it, although it may be connected to another Unix domain
442	 * socket as a pipe.
443	 */
444	    if (ua->sun_family != AF_UNIX) {
445		if (ua->sun_family == AF_UNSPEC) {
446		    if (unp.unp_conn) {
447			if (kread((KA_T)unp.unp_conn, (char *)&uc, sizeof(uc)))
448			    (void) snpf(Namech, Namechl,
449				"can't read unp_conn at %s",
450				print_kptr((KA_T)unp.unp_conn,(char *)NULL,0));
451			else
452			    (void) snpf(Namech, Namechl, "->%s",
453				print_kptr((KA_T)uc.unp_socket,(char *)NULL,0));
454		    } else
455			(void) snpf(Namech, Namechl, "->(none)");
456		} else
457		    (void) snpf(Namech, Namechl, "unknown sun_family (%d)",
458			ua->sun_family);
459		break;
460	    }
461	    if (ua->sun_path[0]) {
462		unl = ua->sun_len - offsetof(struct sockaddr_un, sun_path);
463		if ((unl < 0) || (unl >= sizeof(ua->sun_path)))
464		    unl = sizeof(ua->sun_path) - 1;
465		ua->sun_path[unl] = '\0';
466		if (ua->sun_path[0] && Sfile && is_file_named(ua->sun_path, 0))
467		    Lf->sf |= SELNM;
468		if (ua->sun_path[0] && !Namech[0])
469		    (void) snpf(Namech, Namechl, "%s", ua->sun_path);
470	    } else
471		(void) snpf(Namech, Namechl, "no address");
472	    break;
473	default:
474	    printunkaf(fam, 1);
475	}
476	if (Namech[0])
477	    enter_nm(Namech);
478}
479