/
githubmirror
/
lsof
Обзор
Документация
Войти
/
githubmirror
/
lsof
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
lib/dialects/freebsd/dsock.c
643 строки
20 KB
Gleb Smirnoff
[freebsd] don't use kf_sock_inpcb on modern versions
23 мар 2024, 22:05
23 мар 2024, 22:05
003c846
Код
Авторство
О чём код?
/* * dsock.c - FreeBSD socket processing functions for lsof */ /* * Copyright 1994 Purdue Research Foundation, West Lafayette, Indiana * 47907. All rights reserved. * * Written by Victor A. Abell * * This software is not subject to any license of the American Telephone * and Telegraph Company or the Regents of the University of California. * * Permission is granted to anyone to use this software for any purpose on * any computer system, and to alter it and redistribute it freely, subject * to the following restrictions: * * 1. Neither the authors nor Purdue University are responsible for any * consequences of the use of this software. * * 2. The origin of this software must not be misrepresented, either by * explicit claim or by omission. Credit to the authors and Purdue * University must appear in documentation and sources. * * 3. Altered versions must be plainly marked as such, and must not be * misrepresented as being the original software. * * 4. This notice may not be removed or altered. */ #include <sys/socket.h> #ifndef lint static char copyright[] = "@(#) Copyright 1994 Purdue Research Foundation.\nAll rights reserved.\n"; #endif #include "common.h" #if defined(HASIPv6) /* * IPv6_2_IPv4() -- macro to define the address of an IPv4 address contained * in an IPv6 address */ # define IPv6_2_IPv4(v6) (((uint8_t *)((struct in6_addr *)v6)->s6_addr) + 12) # if defined(HAS_NO_6PORT) /* * If the in_pcb structure no longer has the KAME accommodations of * in6p_[fl]port, redefine them to inp_[fl]port. */ # define in6p_fport inp_fport # define in6p_lport inp_lport # endif /* defined(HAS_NO_6PORT) */ # if defined(HAS_NO_6PPCB) /* * If the in_pcb structure no longer has the KAME accommodation of in6p_pcb, * redefine it to inp_ppcb. */ # define in6p_ppcb inp_ppcb # endif /* defined(HAS_NO_6PPCB) */ #endif /* defined(HASIPv6) */ #if defined(HAS_SB_CCC) # define SOCK_CC sb_ccc #else /* !defined(HAS_SB_CCC) */ # define SOCK_CC sb_cc #endif /* defined(HAS_SB_CCC) */ #if __FreeBSD_version >= 1200026 # define XTCPCB_SO xt_inp.xi_socket # define XTCPCB_SO_PCB xt_inp.xi_socket.so_pcb #else /* __FreeBSD_version < 1200026 */ # define XTCPCB_SO xt_socket # define XTCPCB_SO_PCB xt_socket.so_pcb #endif /* __FreeBSD_version >= 1200026 */ /* * Local function prototypes */ static int ckstate(struct lsof_context *ctx, struct xtcpcb *pcb, int fam); static int cmp_xunpcb_sock_pcb(const void *a, const void *b) { const struct xunpcb *pcb1 = (const struct xunpcb *)a; const struct xunpcb *pcb2 = (const struct xunpcb *)b; if (pcb1->xu_socket.so_pcb < pcb2->xu_socket.so_pcb) return -1; else if (pcb1->xu_socket.so_pcb > pcb2->xu_socket.so_pcb) return 1; else return 0; } static int cmp_xtcpcb_sock_pcb(const void *a, const void *b) { const struct xtcpcb *pcb1 = (const struct xtcpcb *)a; const struct xtcpcb *pcb2 = (const struct xtcpcb *)b; if (pcb1->XTCPCB_SO_PCB < pcb2->XTCPCB_SO_PCB) return -1; else if (pcb1->XTCPCB_SO_PCB > pcb2->XTCPCB_SO_PCB) return 1; else return 0; } static int cmp_xinpcb_sock_pcb(const void *a, const void *b) { const struct xinpcb *pcb1 = (const struct xinpcb *)a; const struct xinpcb *pcb2 = (const struct xinpcb *)b; if (pcb1->xi_socket.so_pcb < pcb2->xi_socket.so_pcb) return -1; else if (pcb1->xi_socket.so_pcb > pcb2->xi_socket.so_pcb) return 1; else return 0; } static int get_unix_pcbs(const char *name, struct xunpcb **pcbs, size_t *n_pcbs) { size_t len; char *buffer = NULL; struct xunpgen *ug = (struct xunpgen *)buffer; int count = 0; int ret = 1; if (sysctlbyname(name, NULL, &len, NULL, 0)) goto end; if ((buffer = malloc(len)) == NULL) goto end; if (sysctlbyname(name, buffer, &len, NULL, 0)) goto end; ug = (struct xunpgen *)buffer; for (ug = (struct xunpgen *)((char *)ug + ug->xug_len); ug->xug_len == sizeof(struct xunpcb); ug = (struct xunpgen *)((char *)ug + ug->xug_len)) { ++count; } memmove(buffer, buffer + ((struct xunpgen *)buffer)->xug_len, count * sizeof(struct xunpcb)); qsort(buffer, count, sizeof(struct xunpcb), cmp_xunpcb_sock_pcb); ret = 0; end: *pcbs = (struct xunpcb *)buffer; *n_pcbs = count; if (ret) free(buffer); return ret; } static int get_tcp_pcbs(struct xtcpcb **pcbs, size_t *n_pcbs) { size_t len; char *buffer = NULL; struct xinpgen *ig = (struct xinpgen *)buffer; int count = 0; int ret = 1; if (sysctlbyname("net.inet.tcp.pcblist", NULL, &len, NULL, 0)) goto end; if ((buffer = malloc(len)) == NULL) goto end; if (sysctlbyname("net.inet.tcp.pcblist", buffer, &len, NULL, 0)) goto end; ig = (struct xinpgen *)buffer; for (ig = (struct xinpgen *)((char *)ig + ig->xig_len); ig->xig_len == sizeof(struct xtcpcb); ig = (struct xinpgen *)((char *)ig + ig->xig_len)) { ++count; } memmove(buffer, buffer + ((struct xinpgen *)buffer)->xig_len, count * sizeof(struct xtcpcb)); qsort(buffer, count, sizeof(struct xtcpcb), cmp_xtcpcb_sock_pcb); ret = 0; end: *pcbs = (struct xtcpcb *)buffer; *n_pcbs = count; if (ret) free(buffer); return ret; } static int get_udp_pcbs(struct xinpcb **pcbs, size_t *n_pcbs) { size_t len; char *buffer = NULL; struct xinpgen *ig = (struct xinpgen *)buffer; int count = 0; int ret = 1; if (sysctlbyname("net.inet.udp.pcblist", NULL, &len, NULL, 0)) goto end; if ((buffer = malloc(len)) == NULL) goto end; if (sysctlbyname("net.inet.udp.pcblist", buffer, &len, NULL, 0)) goto end; ig = (struct xinpgen *)buffer; for (ig = (struct xinpgen *)((char *)ig + ig->xig_len); ig->xig_len == sizeof(struct xinpcb); ig = (struct xinpgen *)((char *)ig + ig->xig_len)) { ++count; } memmove(buffer, buffer + ((struct xinpgen *)buffer)->xig_len, count * sizeof(struct xinpcb)); qsort(buffer, count, sizeof(struct xinpcb), cmp_xinpcb_sock_pcb); ret = 0; end: *pcbs = (struct xinpcb *)buffer; *n_pcbs = count; if (ret) free(buffer); return 0; } struct pcb_lists *read_pcb_lists(void) { struct pcb_lists *pcbs; int succeeded = 0; pcbs = calloc(1, sizeof(struct pcb_lists)); if (!pcbs) goto end; if (get_unix_pcbs("net.local.stream.pcblist", &pcbs->un_stream_pcbs, &pcbs->n_un_stream_pcbs)) goto end; if (get_unix_pcbs("net.local.dgram.pcblist", &pcbs->un_dgram_pcbs, &pcbs->n_un_dgram_pcbs)) goto end; if (get_unix_pcbs("net.local.seqpacket.pcblist", &pcbs->un_seqpacket_pcbs, &pcbs->n_un_seqpacket_pcbs)) goto end; if (get_tcp_pcbs(&pcbs->tcp_pcbs, &pcbs->n_tcp_pcbs)) goto end; if (get_udp_pcbs(&pcbs->udp_pcbs, &pcbs->n_udp_pcbs)) goto end; succeeded = 1; end: if (!succeeded) { free_pcb_lists(pcbs); return NULL; } return pcbs; } void free_pcb_lists(struct pcb_lists *pcbs) { if (pcbs) { free(pcbs->un_stream_pcbs); free(pcbs->un_dgram_pcbs); free(pcbs->un_seqpacket_pcbs); free(pcbs->tcp_pcbs); free(pcbs->udp_pcbs); } free(pcbs); } /* * ckstate() -- read TCP control block and check TCP state for inclusion * or exclusion * return: -1 == no TCP CB available * 0 == TCP DB available; continue processing file * 1 == stop processing file */ static int ckstate(struct lsof_context *ctx, struct xtcpcb *pcb, int fam) { #if __FreeBSD_version >= 1200026 int tsnx; if (TcpStXn || TcpStIn) { /* * If there are TCP state inclusions or exclusions, check them. */ if ((tsnx = (int)pcb->t_state + TcpStOff) >= TcpNstates) return (0); if (TcpStXn) { if (TcpStX[tsnx]) { Lf->sf &= ~SELNET; Lf->sf |= SELEXCLF; return (1); } } if (TcpStIn) { if (TcpStI[tsnx]) { TcpStI[tsnx] = 2; Lf->sf |= SELNET; } else { Lf->sf &= ~SELNET; Lf->sf |= SELEXCLF; return (1); } } } if (!(Lf->sf & SELNET) && !TcpStIn) { /* * See if this TCP file should be selected. */ if (Fnet) { if (!FnetTy || ((FnetTy == 4) && (fam == AF_INET)) || ((FnetTy == 6) && (fam == AF_INET6)) ) { Lf->sf |= SELNET; } } } return (0); #else /* __FreeBSD_version < 1200026 */ return (-1); #endif /* __FreeBSD_version >= 1200026 */ } static void find_pcb_and_xsocket(struct pcb_lists *pcbs, int domain, int type, uint64_t pcb_addr, void **pcb, struct xsocket **xsocket) { if (!pcbs) return; if (domain == PF_INET || domain == PF_INET6) { if (type == SOCK_STREAM) { struct xtcpcb key, *result; key.XTCPCB_SO_PCB = pcb_addr; result = bsearch(&key, pcbs->tcp_pcbs, pcbs->n_tcp_pcbs, sizeof(*pcbs->tcp_pcbs), cmp_xtcpcb_sock_pcb); if (result) { *xsocket = &result->XTCPCB_SO; *pcb = result; } } else if (type == SOCK_DGRAM) { struct xinpcb key, *result; key.xi_socket.so_pcb = pcb_addr; result = bsearch(&key, pcbs->udp_pcbs, pcbs->n_udp_pcbs, sizeof(*pcbs->udp_pcbs), cmp_xinpcb_sock_pcb); if (result) { *xsocket = &result->xi_socket; *pcb = result; } } } else if (domain == PF_UNIX) { struct xunpcb key, *result = NULL; key.xu_socket.so_pcb = pcb_addr; if (type == SOCK_STREAM) { result = bsearch(&key, pcbs->un_stream_pcbs, pcbs->n_un_stream_pcbs, sizeof(*pcbs->un_stream_pcbs), cmp_xunpcb_sock_pcb); } else if (type == SOCK_DGRAM) { result = bsearch(&key, pcbs->un_dgram_pcbs, pcbs->n_un_dgram_pcbs, sizeof(*pcbs->un_dgram_pcbs), cmp_xunpcb_sock_pcb); } else if (type == SOCK_SEQPACKET) { result = bsearch( &key, pcbs->un_seqpacket_pcbs, pcbs->n_un_seqpacket_pcbs, sizeof(*pcbs->un_seqpacket_pcbs), cmp_xunpcb_sock_pcb); } if (result) { *xsocket = &result->xu_socket; *pcb = result; } } } /* * process_socket() - process socket */ void process_socket(struct lsof_context *ctx, struct kinfo_file *kf, struct pcb_lists *pcbs) { unsigned char *fa = (unsigned char *)NULL; int fam; int fp, lp; unsigned char *la = (unsigned char *)NULL; void *pcb = NULL; struct xsocket *s = NULL; int ts = -1; struct sockaddr_un *ua = NULL; int unl; Lf->type = LSOF_FILE_SOCKET; Lf->inp_ty = 2; /* * Read the socket, protocol, and domain structures. */ find_pcb_and_xsocket(pcbs, kf->kf_sock_domain, kf->kf_sock_type, kf->kf_un.kf_sock.kf_sock_pcb, &pcb, &s); /* * Save size information. */ #if defined(HAS_KF_SOCK_SENDQ) if (Lf->access == LSOF_FILE_ACCESS_READ) Lf->sz = (SZOFFTYPE)kf->kf_un.kf_sock.kf_sock_recvq; else if (Lf->access == LSOF_FILE_ACCESS_WRITE) Lf->sz = (SZOFFTYPE)kf->kf_un.kf_sock.kf_sock_sendq; else Lf->sz = (SZOFFTYPE)kf->kf_un.kf_sock.kf_sock_recvq + (SZOFFTYPE)kf->kf_un.kf_sock.kf_sock_sendq; Lf->sz_def = 1; # if defined(HASTCPTPIQ) Lf->lts.rq = kf->kf_un.kf_sock.kf_sock_recvq; Lf->lts.sq = kf->kf_un.kf_sock.kf_sock_sendq; Lf->lts.rqs = Lf->lts.sqs = 1; # endif /* defined(HASTCPTPIQ) */ #endif /* defined(HAS_KF_SOCK_SENDQ) */ if (s) { Lf->lts.ltm = (unsigned int)s->so_linger; Lf->lts.opt = (unsigned int)s->so_options; if (s->so_options & SO_ACCEPTCONN) { Lf->lts.pqlen = (unsigned int)s->so_incqlen; Lf->lts.qlen = (unsigned int)s->so_qlen; Lf->lts.qlim = (unsigned int)s->so_qlimit; } else { Lf->lts.rbsz = (unsigned long)s->so_rcv.sb_mbmax; Lf->lts.sbsz = (unsigned long)s->so_snd.sb_mbmax; } Lf->lts.pqlens = Lf->lts.qlens = Lf->lts.qlims = Lf->lts.rbszs = Lf->lts.sbszs = (unsigned char)1; Lf->lts.ss = (unsigned int)s->so_state; } Lf->lts.sbs_rcv = kf->kf_un.kf_sock.kf_sock_rcv_sb_state; Lf->lts.sbs_snd = kf->kf_un.kf_sock.kf_sock_snd_sb_state; /* * Process socket by the associated domain family. */ switch ((fam = kf->kf_sock_domain)) { /* * Process an Internet domain socket. */ case AF_INET: case AF_INET6: if (Fnet) { if (!FnetTy || ((FnetTy == 4) && (fam == AF_INET)) || ((FnetTy == 6) && (fam == AF_INET6))) { if (!TcpStIn && !UdpStIn) Lf->sf |= SELNET; } } printiproto(ctx, kf->kf_sock_protocol); Lf->type = (fam == AF_INET) ? LSOF_FILE_IPV4 : LSOF_FILE_IPV6; if (fam == AF_INET6) { struct sockaddr_in6 *local_addr6, *foreign_addr6; local_addr6 = (struct sockaddr_in6 *)&kf->kf_sa_local; foreign_addr6 = (struct sockaddr_in6 *)&kf->kf_sa_peer; /* * Read IPv6 protocol control block. */ if (!pcb) { (void)snpf(Namech, Namechl, "can't read in6pcb at %s", print_kptr((KA_T)kf->kf_un.kf_sock.kf_sock_pcb, (char *)NULL, 0)); enter_nm(ctx, Namech); return; } /* * Save IPv6 address information. */ if (kf->kf_sock_protocol == IPPROTO_TCP) { if ((ts = ckstate(ctx, (struct xtcpcb *)pcb, fam)) == 1) { return; } } enter_dev_ch(ctx, print_kptr((KA_T)( #if __FreeBSD_version >= 1400074 kf->kf_un.kf_sock.kf_sock_pcb), #else kf->kf_un.kf_sock.kf_sock_inpcb ? kf->kf_un.kf_sock.kf_sock_inpcb : kf->kf_un.kf_sock.kf_sock_pcb), #endif (char *)NULL, 0)); la = (unsigned char *)&local_addr6->sin6_addr; lp = (int)ntohs(local_addr6->sin6_port); if (!IN6_IS_ADDR_UNSPECIFIED(&foreign_addr6->sin6_addr) || foreign_addr6->sin6_port) { fa = (unsigned char *)&foreign_addr6->sin6_addr; fp = (int)ntohs(foreign_addr6->sin6_port); } } else { /* * Read Ipv4 protocol control block. */ struct sockaddr_in *local_addr = (struct sockaddr_in *)&kf->kf_sa_local; struct sockaddr_in *foreign_addr = (struct sockaddr_in *)&kf->kf_sa_peer; if (!pcb) { (void)snpf( Namech, Namechl, "no PCB%s%s", (kf->kf_un.kf_sock.kf_sock_snd_sb_state & SBS_CANTSENDMORE) ? ", CANTSENDMORE" : "", (kf->kf_un.kf_sock.kf_sock_rcv_sb_state & SBS_CANTRCVMORE) ? ", CANTRCVMORE" : ""); enter_nm(ctx, Namech); return; } if (kf->kf_sock_protocol == IPPROTO_TCP) { if ((ts = ckstate(ctx, (struct xtcpcb *)pcb, fam)) == 1) return; } enter_dev_ch(ctx, print_kptr((KA_T)( #if __FreeBSD_version >= 1400074 kf->kf_un.kf_sock.kf_sock_pcb), #else kf->kf_un.kf_sock.kf_sock_inpcb ? kf->kf_un.kf_sock.kf_sock_inpcb : kf->kf_un.kf_sock.kf_sock_pcb), #endif (char *)NULL, 0)); lp = (int)ntohs(local_addr->sin_port); la = (unsigned char *)&local_addr->sin_addr; /* * Save IPv4 address information. */ if (foreign_addr->sin_addr.s_addr != INADDR_ANY || foreign_addr->sin_port) { fp = (int)ntohs(foreign_addr->sin_port); fa = (unsigned char *)&foreign_addr->sin_addr; } } if ((fam == AF_INET6) && ((la && IN6_IS_ADDR_V4MAPPED((struct in6_addr *)la)) || ((fa && IN6_IS_ADDR_V4MAPPED((struct in6_addr *)fa))))) { /* * Adjust for IPv4 addresses mapped in IPv6 addresses. */ if (la) la = (unsigned char *)IPv6_2_IPv4(la); if (fa) fa = (unsigned char *)IPv6_2_IPv4(fa); fam = AF_INET; } /* * Enter local and remote addresses by address family. */ if (fa || la) (void)ent_inaddr(ctx, la, lp, fa, fp, fam); if (ts == 0) { struct xtcpcb *tcp_pcb = (struct xtcpcb *)pcb; Lf->lts.type = 0; #if __FreeBSD_version >= 1200026 Lf->lts.state.i = (int)tcp_pcb->t_state; #endif #if defined(HASTCPOPT) # if defined(HAS_XTCPCB_TMAXSEG) Lf->lts.mss = (unsigned long)tcp_pcb->t_maxseg; Lf->lts.msss = (unsigned char)1; # endif /* defined(HAS_XTCPCB_TMAXSEG) */ # if __FreeBSD_version >= 1200026 Lf->lts.topt = (unsigned int)tcp_pcb->t_flags; # endif #endif /* defined(HASTCPOPT) */ } break; /* * Process a ROUTE domain socket. */ case AF_ROUTE: Lf->type = LSOF_FILE_ROUTE; if (s && s->so_pcb) enter_dev_ch(ctx, print_kptr((KA_T)(s->so_pcb), (char *)NULL, 0)); else (void)snpf(Namech, Namechl, "no protocol control block"); break; /* * Process a Unix domain socket. */ case AF_UNIX: { struct xunpcb *unix_pcb = (struct xunpcb *)pcb; if (Funix) Lf->sf |= SELUNX; Lf->type = LSOF_FILE_UNIX; /* * Read Unix protocol control block and the Unix address structure. */ if (unix_pcb) enter_dev_ch( ctx, print_kptr(unix_pcb->xu_socket.xso_so, (char *)NULL, 0)); else { (void)snpf( Namech, Namechl, "can't read unpcb at %s", print_kptr(kf->kf_un.kf_sock.kf_sock_pcb, (char *)NULL, 0)); break; } ua = (struct sockaddr_un *)&kf->kf_sa_local; if (ua->sun_path[0]) { unl = ua->sun_len - offsetof(struct sockaddr_un, sun_path); if ((unl < 0) || (unl >= sizeof(ua->sun_path))) unl = sizeof(ua->sun_path) - 1; ua->sun_path[unl] = '\0'; if (ua->sun_path[0] && Sfile && is_file_named(ctx, ua->sun_path, 0)) Lf->sf |= SELNM; if (ua->sun_path[0] && !Namech[0]) (void)snpf(Namech, Namechl, "%s", ua->sun_path); } else if (kf->kf_un.kf_sock.kf_sock_unpconn) { struct xsocket *peer_socket = NULL; void *peer_pcb; find_pcb_and_xsocket(pcbs, kf->kf_sock_domain, kf->kf_sock_type, kf->kf_un.kf_sock.kf_sock_unpconn, &peer_pcb, &peer_socket); if (!peer_socket) (void)snpf(Namech, Namechl, "can't read unp_conn at %s", print_kptr((KA_T)kf->kf_un.kf_sock.kf_sock_unpconn, (char *)NULL, 0)); else (void)snpf( Namech, Namechl, "->%s", print_kptr((KA_T)peer_socket->xso_so, (char *)NULL, 0)); } else (void)snpf(Namech, Namechl, "->(none)"); break; } default: printunkaf(ctx, fam, 1); } if (Namech[0]) enter_nm(ctx, Namech); }