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