180cc79e1SJoerg Sonnenberger /*-
280cc79e1SJoerg Sonnenberger * Copyright (c) 2005 Joerg Sonnenberger <joerg@bec.de>. All rights reserved.
3f6e8a0a1SImre Vadasz * Copyright (c) 2002 Dag-Erling Coïdan Smørgrav
480cc79e1SJoerg Sonnenberger * All rights reserved.
580cc79e1SJoerg Sonnenberger *
680cc79e1SJoerg Sonnenberger * Redistribution and use in source and binary forms, with or without
780cc79e1SJoerg Sonnenberger * modification, are permitted provided that the following conditions
880cc79e1SJoerg Sonnenberger * are met:
980cc79e1SJoerg Sonnenberger * 1. Redistributions of source code must retain the above copyright
1080cc79e1SJoerg Sonnenberger * notice, this list of conditions and the following disclaimer
1180cc79e1SJoerg Sonnenberger * in this position and unchanged.
1280cc79e1SJoerg Sonnenberger * 2. Redistributions in binary form must reproduce the above copyright
1380cc79e1SJoerg Sonnenberger * notice, this list of conditions and the following disclaimer in the
1480cc79e1SJoerg Sonnenberger * documentation and/or other materials provided with the distribution.
1580cc79e1SJoerg Sonnenberger * 3. The name of the author may not be used to endorse or promote products
1680cc79e1SJoerg Sonnenberger * derived from this software without specific prior written permission.
1780cc79e1SJoerg Sonnenberger *
1880cc79e1SJoerg Sonnenberger * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1980cc79e1SJoerg Sonnenberger * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2080cc79e1SJoerg Sonnenberger * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2180cc79e1SJoerg Sonnenberger * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2280cc79e1SJoerg Sonnenberger * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2380cc79e1SJoerg Sonnenberger * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2480cc79e1SJoerg Sonnenberger * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2580cc79e1SJoerg Sonnenberger * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2680cc79e1SJoerg Sonnenberger * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2780cc79e1SJoerg Sonnenberger * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2880cc79e1SJoerg Sonnenberger *
2980cc79e1SJoerg Sonnenberger * $FreeBSD: src/usr.bin/sockstat/sockstat.c,v 1.12 2004/12/06 09:28:05 ru Exp $
3080cc79e1SJoerg Sonnenberger */
3180cc79e1SJoerg Sonnenberger
3280cc79e1SJoerg Sonnenberger #include <sys/param.h>
3380cc79e1SJoerg Sonnenberger #include <sys/socket.h>
3480cc79e1SJoerg Sonnenberger #include <sys/socketvar.h>
3580cc79e1SJoerg Sonnenberger #include <sys/sysctl.h>
3680cc79e1SJoerg Sonnenberger #include <sys/file.h>
3780cc79e1SJoerg Sonnenberger
3880cc79e1SJoerg Sonnenberger #include <sys/un.h>
3980cc79e1SJoerg Sonnenberger #include <sys/unpcb.h>
4080cc79e1SJoerg Sonnenberger
4180cc79e1SJoerg Sonnenberger #include <net/route.h>
4280cc79e1SJoerg Sonnenberger
4380cc79e1SJoerg Sonnenberger #include <netinet/in.h>
4480cc79e1SJoerg Sonnenberger #include <netinet/in_pcb.h>
4580cc79e1SJoerg Sonnenberger #include <netinet/tcp.h>
4680cc79e1SJoerg Sonnenberger #include <netinet/tcp_seq.h>
4780cc79e1SJoerg Sonnenberger #include <netinet/tcp_var.h>
4880cc79e1SJoerg Sonnenberger #include <arpa/inet.h>
4980cc79e1SJoerg Sonnenberger
5080cc79e1SJoerg Sonnenberger #include <ctype.h>
5180cc79e1SJoerg Sonnenberger #include <err.h>
5280cc79e1SJoerg Sonnenberger #include <errno.h>
5380cc79e1SJoerg Sonnenberger #include <kinfo.h>
5480cc79e1SJoerg Sonnenberger #include <netdb.h>
5580cc79e1SJoerg Sonnenberger #include <pwd.h>
5680cc79e1SJoerg Sonnenberger #include <stdarg.h>
57*70bb9b56SAaron LI #include <stddef.h>
5880cc79e1SJoerg Sonnenberger #include <stdio.h>
5980cc79e1SJoerg Sonnenberger #include <stdlib.h>
6080cc79e1SJoerg Sonnenberger #include <string.h>
6180cc79e1SJoerg Sonnenberger #include <unistd.h>
6280cc79e1SJoerg Sonnenberger
6380cc79e1SJoerg Sonnenberger static int opt_4; /* Show IPv4 sockets */
6480cc79e1SJoerg Sonnenberger static int opt_6; /* Show IPv6 sockets */
6580cc79e1SJoerg Sonnenberger static int opt_c; /* Show connected sockets */
6680cc79e1SJoerg Sonnenberger static int opt_l; /* Show listening sockets */
6780cc79e1SJoerg Sonnenberger static int opt_u; /* Show Unix domain sockets */
6880cc79e1SJoerg Sonnenberger static int opt_v; /* Verbose mode */
6980cc79e1SJoerg Sonnenberger
7080cc79e1SJoerg Sonnenberger static int *ports;
7180cc79e1SJoerg Sonnenberger
7280cc79e1SJoerg Sonnenberger #define INT_BIT (sizeof(int) * CHAR_BIT)
7380cc79e1SJoerg Sonnenberger #define SET_PORT(p) do { ports[p / INT_BIT] |= 1 << (p % INT_BIT); } while (0)
7480cc79e1SJoerg Sonnenberger #define CHK_PORT(p) (ports[p / INT_BIT] & (1 << (p % INT_BIT)))
7580cc79e1SJoerg Sonnenberger
7680cc79e1SJoerg Sonnenberger struct sock {
7780cc79e1SJoerg Sonnenberger void *socket;
7880cc79e1SJoerg Sonnenberger void *pcb;
7980cc79e1SJoerg Sonnenberger int family;
8080cc79e1SJoerg Sonnenberger int proto;
8180cc79e1SJoerg Sonnenberger const char *protoname;
8280cc79e1SJoerg Sonnenberger struct sockaddr_storage laddr;
8380cc79e1SJoerg Sonnenberger struct sockaddr_storage faddr;
8480cc79e1SJoerg Sonnenberger struct sock *next;
8580cc79e1SJoerg Sonnenberger };
8680cc79e1SJoerg Sonnenberger
8780cc79e1SJoerg Sonnenberger #define HASHSIZE 1009
8880cc79e1SJoerg Sonnenberger static struct sock *sockhash[HASHSIZE];
8980cc79e1SJoerg Sonnenberger
9080cc79e1SJoerg Sonnenberger static struct kinfo_file *xfiles;
91fd282d19SSascha Wildner static size_t nxfiles;
9280cc79e1SJoerg Sonnenberger
93*70bb9b56SAaron LI __printflike(1, 2)
9480cc79e1SJoerg Sonnenberger static int
xprintf(const char * fmt,...)9580cc79e1SJoerg Sonnenberger xprintf(const char *fmt, ...)
9680cc79e1SJoerg Sonnenberger {
9780cc79e1SJoerg Sonnenberger va_list ap;
9880cc79e1SJoerg Sonnenberger int len;
9980cc79e1SJoerg Sonnenberger
10080cc79e1SJoerg Sonnenberger va_start(ap, fmt);
10180cc79e1SJoerg Sonnenberger len = vprintf(fmt, ap);
10280cc79e1SJoerg Sonnenberger va_end(ap);
10380cc79e1SJoerg Sonnenberger if (len < 0)
10480cc79e1SJoerg Sonnenberger err(1, "printf()");
10580cc79e1SJoerg Sonnenberger return (len);
10680cc79e1SJoerg Sonnenberger }
10780cc79e1SJoerg Sonnenberger
10880cc79e1SJoerg Sonnenberger static void
parse_ports(const char * portspec)10980cc79e1SJoerg Sonnenberger parse_ports(const char *portspec)
11080cc79e1SJoerg Sonnenberger {
11180cc79e1SJoerg Sonnenberger const char *p, *q;
11280cc79e1SJoerg Sonnenberger int port, end;
11380cc79e1SJoerg Sonnenberger
11480cc79e1SJoerg Sonnenberger if (ports == NULL)
11580cc79e1SJoerg Sonnenberger if ((ports = calloc(65536 / INT_BIT, sizeof(int))) == NULL)
11680cc79e1SJoerg Sonnenberger err(1, "calloc()");
11780cc79e1SJoerg Sonnenberger p = portspec;
11880cc79e1SJoerg Sonnenberger while (*p != '\0') {
11980cc79e1SJoerg Sonnenberger if (!isdigit(*p))
12080cc79e1SJoerg Sonnenberger errx(1, "syntax error in port range");
12180cc79e1SJoerg Sonnenberger for (q = p; *q != '\0' && isdigit(*q); ++q)
12280cc79e1SJoerg Sonnenberger /* nothing */ ;
12380cc79e1SJoerg Sonnenberger for (port = 0; p < q; ++p)
124c4f3b183SJoerg Sonnenberger port = port * 10 + (*p - '0');
12580cc79e1SJoerg Sonnenberger if (port < 0 || port > 65535)
12680cc79e1SJoerg Sonnenberger errx(1, "invalid port number");
12780cc79e1SJoerg Sonnenberger SET_PORT(port);
12880cc79e1SJoerg Sonnenberger switch (*p) {
12980cc79e1SJoerg Sonnenberger case '-':
13080cc79e1SJoerg Sonnenberger ++p;
13180cc79e1SJoerg Sonnenberger break;
13280cc79e1SJoerg Sonnenberger case ',':
13380cc79e1SJoerg Sonnenberger ++p;
13480cc79e1SJoerg Sonnenberger /* fall through */
13580cc79e1SJoerg Sonnenberger case '\0':
13680cc79e1SJoerg Sonnenberger default:
13780cc79e1SJoerg Sonnenberger continue;
13880cc79e1SJoerg Sonnenberger }
13980cc79e1SJoerg Sonnenberger for (q = p; *q != '\0' && isdigit(*q); ++q)
14080cc79e1SJoerg Sonnenberger /* nothing */ ;
14180cc79e1SJoerg Sonnenberger for (end = 0; p < q; ++p)
142c4f3b183SJoerg Sonnenberger end = end * 10 + (*p - '0');
14380cc79e1SJoerg Sonnenberger if (end < port || end > 65535)
14480cc79e1SJoerg Sonnenberger errx(1, "invalid port number");
14580cc79e1SJoerg Sonnenberger while (port++ < end)
14680cc79e1SJoerg Sonnenberger SET_PORT(port);
14780cc79e1SJoerg Sonnenberger if (*p == ',')
14880cc79e1SJoerg Sonnenberger ++p;
14980cc79e1SJoerg Sonnenberger }
15080cc79e1SJoerg Sonnenberger }
15180cc79e1SJoerg Sonnenberger
15280cc79e1SJoerg Sonnenberger static void
sockaddr(struct sockaddr_storage * sa,int af,void * addr,int port)15380cc79e1SJoerg Sonnenberger sockaddr(struct sockaddr_storage *sa, int af, void *addr, int port)
15480cc79e1SJoerg Sonnenberger {
15580cc79e1SJoerg Sonnenberger struct sockaddr_in *sin4;
15680cc79e1SJoerg Sonnenberger struct sockaddr_in6 *sin6;
15780cc79e1SJoerg Sonnenberger
15880cc79e1SJoerg Sonnenberger bzero(sa, sizeof *sa);
15980cc79e1SJoerg Sonnenberger switch (af) {
16080cc79e1SJoerg Sonnenberger case AF_INET:
16180cc79e1SJoerg Sonnenberger sin4 = (struct sockaddr_in *)sa;
16280cc79e1SJoerg Sonnenberger sin4->sin_len = sizeof *sin4;
16380cc79e1SJoerg Sonnenberger sin4->sin_family = af;
16480cc79e1SJoerg Sonnenberger sin4->sin_port = port;
16580cc79e1SJoerg Sonnenberger sin4->sin_addr = *(struct in_addr *)addr;
16680cc79e1SJoerg Sonnenberger break;
16780cc79e1SJoerg Sonnenberger case AF_INET6:
16880cc79e1SJoerg Sonnenberger sin6 = (struct sockaddr_in6 *)sa;
16980cc79e1SJoerg Sonnenberger sin6->sin6_len = sizeof *sin6;
17080cc79e1SJoerg Sonnenberger sin6->sin6_family = af;
17180cc79e1SJoerg Sonnenberger sin6->sin6_port = port;
17280cc79e1SJoerg Sonnenberger sin6->sin6_addr = *(struct in6_addr *)addr;
17380cc79e1SJoerg Sonnenberger break;
17480cc79e1SJoerg Sonnenberger default:
17580cc79e1SJoerg Sonnenberger abort();
17680cc79e1SJoerg Sonnenberger }
17780cc79e1SJoerg Sonnenberger }
17880cc79e1SJoerg Sonnenberger
17980cc79e1SJoerg Sonnenberger static void
gather_inet(int proto)18080cc79e1SJoerg Sonnenberger gather_inet(int proto)
18180cc79e1SJoerg Sonnenberger {
182*70bb9b56SAaron LI uint8_t *buf, *so_begin, *so_end;
18380cc79e1SJoerg Sonnenberger struct xinpcb *xip;
18480cc79e1SJoerg Sonnenberger struct xtcpcb *xtp;
18580cc79e1SJoerg Sonnenberger struct inpcb *inp;
18680cc79e1SJoerg Sonnenberger struct xsocket *so;
18780cc79e1SJoerg Sonnenberger struct sock *sock;
18880cc79e1SJoerg Sonnenberger const char *varname, *protoname;
18980cc79e1SJoerg Sonnenberger size_t len;
190727ccde8SSepherosa Ziehau int hash;
19180cc79e1SJoerg Sonnenberger
19280cc79e1SJoerg Sonnenberger switch (proto) {
19380cc79e1SJoerg Sonnenberger case IPPROTO_TCP:
19480cc79e1SJoerg Sonnenberger varname = "net.inet.tcp.pcblist";
19580cc79e1SJoerg Sonnenberger protoname = "tcp";
19680cc79e1SJoerg Sonnenberger break;
19780cc79e1SJoerg Sonnenberger case IPPROTO_UDP:
19880cc79e1SJoerg Sonnenberger varname = "net.inet.udp.pcblist";
19980cc79e1SJoerg Sonnenberger protoname = "udp";
20080cc79e1SJoerg Sonnenberger break;
20180cc79e1SJoerg Sonnenberger case IPPROTO_DIVERT:
20280cc79e1SJoerg Sonnenberger varname = "net.inet.divert.pcblist";
20380cc79e1SJoerg Sonnenberger protoname = "div";
20480cc79e1SJoerg Sonnenberger break;
20580cc79e1SJoerg Sonnenberger default:
20680cc79e1SJoerg Sonnenberger abort();
20780cc79e1SJoerg Sonnenberger }
20880cc79e1SJoerg Sonnenberger
20980cc79e1SJoerg Sonnenberger buf = NULL;
21080cc79e1SJoerg Sonnenberger len = 0;
21180cc79e1SJoerg Sonnenberger
21280cc79e1SJoerg Sonnenberger if (sysctlbyname(varname, NULL, &len, NULL, 0)) {
21380cc79e1SJoerg Sonnenberger if (errno == ENOENT)
21480cc79e1SJoerg Sonnenberger goto out;
21580cc79e1SJoerg Sonnenberger err(1, "fetching %s", varname);
21680cc79e1SJoerg Sonnenberger }
21780cc79e1SJoerg Sonnenberger if ((buf = malloc(len)) == NULL)
21880cc79e1SJoerg Sonnenberger err(1, "malloc()");
21980cc79e1SJoerg Sonnenberger if (sysctlbyname(varname, buf, &len, NULL, 0)) {
22080cc79e1SJoerg Sonnenberger if (errno == ENOENT)
22180cc79e1SJoerg Sonnenberger goto out;
22280cc79e1SJoerg Sonnenberger err(1, "fetching %s", varname);
22380cc79e1SJoerg Sonnenberger }
22480cc79e1SJoerg Sonnenberger
225*70bb9b56SAaron LI for (so_begin = buf, so_end = buf + len;
226*70bb9b56SAaron LI so_begin + sizeof(size_t) < so_end &&
227*70bb9b56SAaron LI so_begin + *(size_t *)so_begin <= so_end;
228*70bb9b56SAaron LI so_begin = so_begin + *(size_t *)so_begin) {
22980cc79e1SJoerg Sonnenberger switch (proto) {
23080cc79e1SJoerg Sonnenberger case IPPROTO_TCP:
23180cc79e1SJoerg Sonnenberger xtp = (struct xtcpcb *)so_begin;
23280cc79e1SJoerg Sonnenberger if (xtp->xt_len != sizeof *xtp) {
23380cc79e1SJoerg Sonnenberger warnx("struct xtcpcb size mismatch");
23480cc79e1SJoerg Sonnenberger goto out;
23580cc79e1SJoerg Sonnenberger }
23680cc79e1SJoerg Sonnenberger inp = &xtp->xt_inp;
23780cc79e1SJoerg Sonnenberger so = &xtp->xt_socket;
23880cc79e1SJoerg Sonnenberger break;
23980cc79e1SJoerg Sonnenberger case IPPROTO_UDP:
24080cc79e1SJoerg Sonnenberger case IPPROTO_DIVERT:
24180cc79e1SJoerg Sonnenberger xip = (struct xinpcb *)so_begin;
24280cc79e1SJoerg Sonnenberger if (xip->xi_len != sizeof *xip) {
24380cc79e1SJoerg Sonnenberger warnx("struct xinpcb size mismatch");
24480cc79e1SJoerg Sonnenberger goto out;
24580cc79e1SJoerg Sonnenberger }
24680cc79e1SJoerg Sonnenberger inp = &xip->xi_inp;
24780cc79e1SJoerg Sonnenberger so = &xip->xi_socket;
24880cc79e1SJoerg Sonnenberger break;
24980cc79e1SJoerg Sonnenberger default:
25080cc79e1SJoerg Sonnenberger abort();
25180cc79e1SJoerg Sonnenberger }
252727ccde8SSepherosa Ziehau if ((INP_ISIPV4(inp) && !opt_4) || (INP_ISIPV6(inp) && !opt_6))
25380cc79e1SJoerg Sonnenberger continue;
254727ccde8SSepherosa Ziehau if (INP_ISIPV4(inp)) {
25580cc79e1SJoerg Sonnenberger if ((inp->inp_fport == 0 && !opt_l) ||
25680cc79e1SJoerg Sonnenberger (inp->inp_fport != 0 && !opt_c))
25780cc79e1SJoerg Sonnenberger continue;
258727ccde8SSepherosa Ziehau } else if (INP_ISIPV6(inp)) {
25980cc79e1SJoerg Sonnenberger if ((inp->in6p_fport == 0 && !opt_l) ||
26080cc79e1SJoerg Sonnenberger (inp->in6p_fport != 0 && !opt_c))
26180cc79e1SJoerg Sonnenberger continue;
26280cc79e1SJoerg Sonnenberger } else {
26380cc79e1SJoerg Sonnenberger if (opt_v)
264727ccde8SSepherosa Ziehau warnx("invalid af 0x%x", inp->inp_af);
26580cc79e1SJoerg Sonnenberger continue;
26680cc79e1SJoerg Sonnenberger }
26780cc79e1SJoerg Sonnenberger if ((sock = calloc(1, sizeof *sock)) == NULL)
26880cc79e1SJoerg Sonnenberger err(1, "malloc()");
26980cc79e1SJoerg Sonnenberger sock->socket = so->xso_so;
27080cc79e1SJoerg Sonnenberger sock->proto = proto;
271727ccde8SSepherosa Ziehau if (INP_ISIPV4(inp)) {
27280cc79e1SJoerg Sonnenberger sock->family = AF_INET;
27380cc79e1SJoerg Sonnenberger sockaddr(&sock->laddr, sock->family,
27480cc79e1SJoerg Sonnenberger &inp->inp_laddr, inp->inp_lport);
27580cc79e1SJoerg Sonnenberger sockaddr(&sock->faddr, sock->family,
27680cc79e1SJoerg Sonnenberger &inp->inp_faddr, inp->inp_fport);
277727ccde8SSepherosa Ziehau } else if (INP_ISIPV6(inp)) {
27880cc79e1SJoerg Sonnenberger sock->family = AF_INET6;
27980cc79e1SJoerg Sonnenberger sockaddr(&sock->laddr, sock->family,
28080cc79e1SJoerg Sonnenberger &inp->in6p_laddr, inp->in6p_lport);
28180cc79e1SJoerg Sonnenberger sockaddr(&sock->faddr, sock->family,
28280cc79e1SJoerg Sonnenberger &inp->in6p_faddr, inp->in6p_fport);
28380cc79e1SJoerg Sonnenberger }
28480cc79e1SJoerg Sonnenberger sock->protoname = protoname;
28580cc79e1SJoerg Sonnenberger hash = (int)((uintptr_t)sock->socket % HASHSIZE);
28680cc79e1SJoerg Sonnenberger sock->next = sockhash[hash];
28780cc79e1SJoerg Sonnenberger sockhash[hash] = sock;
28880cc79e1SJoerg Sonnenberger }
28980cc79e1SJoerg Sonnenberger out:
29080cc79e1SJoerg Sonnenberger free(buf);
29180cc79e1SJoerg Sonnenberger }
29280cc79e1SJoerg Sonnenberger
29380cc79e1SJoerg Sonnenberger static void
gather_unix(int proto)29480cc79e1SJoerg Sonnenberger gather_unix(int proto)
29580cc79e1SJoerg Sonnenberger {
296*70bb9b56SAaron LI uint8_t *buf, *so_begin, *so_end;
29780cc79e1SJoerg Sonnenberger struct xunpcb *xup;
29880cc79e1SJoerg Sonnenberger struct sock *sock;
29980cc79e1SJoerg Sonnenberger const char *varname, *protoname;
30080cc79e1SJoerg Sonnenberger size_t len;
30180cc79e1SJoerg Sonnenberger int hash;
30280cc79e1SJoerg Sonnenberger
30380cc79e1SJoerg Sonnenberger switch (proto) {
30480cc79e1SJoerg Sonnenberger case SOCK_STREAM:
30580cc79e1SJoerg Sonnenberger varname = "net.local.stream.pcblist";
30680cc79e1SJoerg Sonnenberger protoname = "stream";
30780cc79e1SJoerg Sonnenberger break;
30880cc79e1SJoerg Sonnenberger case SOCK_DGRAM:
30980cc79e1SJoerg Sonnenberger varname = "net.local.dgram.pcblist";
31080cc79e1SJoerg Sonnenberger protoname = "dgram";
31180cc79e1SJoerg Sonnenberger break;
31280cc79e1SJoerg Sonnenberger default:
31380cc79e1SJoerg Sonnenberger abort();
31480cc79e1SJoerg Sonnenberger }
31580cc79e1SJoerg Sonnenberger
31680cc79e1SJoerg Sonnenberger buf = NULL;
31780cc79e1SJoerg Sonnenberger len = 0;
31880cc79e1SJoerg Sonnenberger
31980cc79e1SJoerg Sonnenberger if (sysctlbyname(varname, NULL, &len, NULL, 0))
32080cc79e1SJoerg Sonnenberger err(1, "fetching %s", varname);
32180cc79e1SJoerg Sonnenberger
32280cc79e1SJoerg Sonnenberger if ((buf = malloc(len)) == NULL)
32380cc79e1SJoerg Sonnenberger err(1, "malloc()");
32480cc79e1SJoerg Sonnenberger if (sysctlbyname(varname, buf, &len, NULL, 0))
32580cc79e1SJoerg Sonnenberger err(1, "fetching %s", varname);
32680cc79e1SJoerg Sonnenberger
327*70bb9b56SAaron LI for (so_begin = buf, so_end = buf + len;
328*70bb9b56SAaron LI so_begin + sizeof(size_t) < so_end &&
329*70bb9b56SAaron LI so_begin + *(size_t *)so_begin <= so_end;
330*70bb9b56SAaron LI so_begin = so_begin + *(size_t *)so_begin) {
331*70bb9b56SAaron LI xup = (struct xunpcb *)so_begin;
33280cc79e1SJoerg Sonnenberger if (xup->xu_len != sizeof *xup) {
33380cc79e1SJoerg Sonnenberger warnx("struct xunpcb size mismatch");
33480cc79e1SJoerg Sonnenberger goto out;
33580cc79e1SJoerg Sonnenberger }
33680cc79e1SJoerg Sonnenberger if ((xup->xu_unp.unp_conn == NULL && !opt_l) ||
33780cc79e1SJoerg Sonnenberger (xup->xu_unp.unp_conn != NULL && !opt_c))
33880cc79e1SJoerg Sonnenberger continue;
33980cc79e1SJoerg Sonnenberger if ((sock = calloc(1, sizeof *sock)) == NULL)
34080cc79e1SJoerg Sonnenberger err(1, "malloc()");
34180cc79e1SJoerg Sonnenberger sock->socket = xup->xu_socket.xso_so;
34280cc79e1SJoerg Sonnenberger sock->pcb = xup->xu_unpp;
34380cc79e1SJoerg Sonnenberger sock->proto = proto;
34480cc79e1SJoerg Sonnenberger sock->family = AF_UNIX;
34580cc79e1SJoerg Sonnenberger sock->protoname = protoname;
34680cc79e1SJoerg Sonnenberger if (xup->xu_unp.unp_addr != NULL)
347*70bb9b56SAaron LI sock->laddr = *(struct sockaddr_storage *)&xup->xu_addr;
34880cc79e1SJoerg Sonnenberger else if (xup->xu_unp.unp_conn != NULL)
34980cc79e1SJoerg Sonnenberger *(void **)&sock->faddr = xup->xu_unp.unp_conn;
35080cc79e1SJoerg Sonnenberger hash = (int)((uintptr_t)sock->socket % HASHSIZE);
35180cc79e1SJoerg Sonnenberger sock->next = sockhash[hash];
35280cc79e1SJoerg Sonnenberger sockhash[hash] = sock;
35380cc79e1SJoerg Sonnenberger }
35480cc79e1SJoerg Sonnenberger out:
35580cc79e1SJoerg Sonnenberger free(buf);
35680cc79e1SJoerg Sonnenberger }
35780cc79e1SJoerg Sonnenberger
35880cc79e1SJoerg Sonnenberger static void
getfiles(void)35980cc79e1SJoerg Sonnenberger getfiles(void)
36080cc79e1SJoerg Sonnenberger {
36180cc79e1SJoerg Sonnenberger if (kinfo_get_files(&xfiles, &nxfiles))
36280cc79e1SJoerg Sonnenberger err(1, "kinfo_get_files");
36380cc79e1SJoerg Sonnenberger }
36480cc79e1SJoerg Sonnenberger
365*70bb9b56SAaron LI static void
printproto(int width,int af,const char * protoname)366*70bb9b56SAaron LI printproto(int width, int af, const char *protoname)
367*70bb9b56SAaron LI {
368*70bb9b56SAaron LI int n;
369*70bb9b56SAaron LI
370*70bb9b56SAaron LI switch (af) {
371*70bb9b56SAaron LI case AF_INET:
372*70bb9b56SAaron LI case AF_INET6:
373*70bb9b56SAaron LI n = xprintf("%s%c", protoname, af == AF_INET ? '4' : '6');
374*70bb9b56SAaron LI break;
375*70bb9b56SAaron LI default:
376*70bb9b56SAaron LI n = xprintf("%s", protoname);
377*70bb9b56SAaron LI break;
378*70bb9b56SAaron LI }
379*70bb9b56SAaron LI
380*70bb9b56SAaron LI if (width > 0 && width > n)
381*70bb9b56SAaron LI xprintf("%*s", width - n, "");
382*70bb9b56SAaron LI }
383*70bb9b56SAaron LI
384*70bb9b56SAaron LI static void
printaddr(int width,int af,struct sockaddr_storage * ss)385*70bb9b56SAaron LI printaddr(int width, int af, struct sockaddr_storage *ss)
38680cc79e1SJoerg Sonnenberger {
38780cc79e1SJoerg Sonnenberger char addrstr[INET6_ADDRSTRLEN] = { '\0', '\0' };
38880cc79e1SJoerg Sonnenberger struct sockaddr_un *sun;
38980cc79e1SJoerg Sonnenberger void *addr;
390*70bb9b56SAaron LI int port, n;
391*70bb9b56SAaron LI
392*70bb9b56SAaron LI if (af == AF_UNIX) {
393*70bb9b56SAaron LI sun = (struct sockaddr_un *)ss;
394*70bb9b56SAaron LI n = sun->sun_len - offsetof(struct sockaddr_un, sun_path);
395*70bb9b56SAaron LI xprintf("%.*s", n, sun->sun_path);
396*70bb9b56SAaron LI if (width > 0 && width > n)
397*70bb9b56SAaron LI xprintf("%*s", width - n, "");
398*70bb9b56SAaron LI return;
399*70bb9b56SAaron LI }
40080cc79e1SJoerg Sonnenberger
40180cc79e1SJoerg Sonnenberger switch (af) {
40280cc79e1SJoerg Sonnenberger case AF_INET:
40380cc79e1SJoerg Sonnenberger addr = &((struct sockaddr_in *)ss)->sin_addr;
40480cc79e1SJoerg Sonnenberger if (inet_lnaof(*(struct in_addr *)addr) == INADDR_ANY)
40580cc79e1SJoerg Sonnenberger addrstr[0] = '*';
40680cc79e1SJoerg Sonnenberger port = ntohs(((struct sockaddr_in *)ss)->sin_port);
40780cc79e1SJoerg Sonnenberger break;
40880cc79e1SJoerg Sonnenberger case AF_INET6:
40980cc79e1SJoerg Sonnenberger addr = &((struct sockaddr_in6 *)ss)->sin6_addr;
41080cc79e1SJoerg Sonnenberger if (IN6_IS_ADDR_UNSPECIFIED((struct in6_addr *)addr))
41180cc79e1SJoerg Sonnenberger addrstr[0] = '*';
41280cc79e1SJoerg Sonnenberger port = ntohs(((struct sockaddr_in6 *)ss)->sin6_port);
41380cc79e1SJoerg Sonnenberger break;
414ae1a9ca5SJoerg Sonnenberger default:
415ae1a9ca5SJoerg Sonnenberger abort();
41680cc79e1SJoerg Sonnenberger }
417*70bb9b56SAaron LI
41880cc79e1SJoerg Sonnenberger if (addrstr[0] == '\0')
41980cc79e1SJoerg Sonnenberger inet_ntop(af, addr, addrstr, sizeof addrstr);
42080cc79e1SJoerg Sonnenberger if (port == 0)
421*70bb9b56SAaron LI n = xprintf("%s:*", addrstr);
42280cc79e1SJoerg Sonnenberger else
423*70bb9b56SAaron LI n = xprintf("%s:%d", addrstr, port);
424*70bb9b56SAaron LI if (width > 0 && width > n)
425*70bb9b56SAaron LI xprintf("%*s", width - n, "");
42680cc79e1SJoerg Sonnenberger }
42780cc79e1SJoerg Sonnenberger
42880cc79e1SJoerg Sonnenberger static const char *
getprocname(pid_t pid)42980cc79e1SJoerg Sonnenberger getprocname(pid_t pid)
43080cc79e1SJoerg Sonnenberger {
43180cc79e1SJoerg Sonnenberger static struct kinfo_proc proc;
43280cc79e1SJoerg Sonnenberger size_t len;
43380cc79e1SJoerg Sonnenberger int mib[4];
43480cc79e1SJoerg Sonnenberger
43580cc79e1SJoerg Sonnenberger mib[0] = CTL_KERN;
43680cc79e1SJoerg Sonnenberger mib[1] = KERN_PROC;
43780cc79e1SJoerg Sonnenberger mib[2] = KERN_PROC_PID;
43880cc79e1SJoerg Sonnenberger mib[3] = (int)pid;
43980cc79e1SJoerg Sonnenberger len = sizeof proc;
44080cc79e1SJoerg Sonnenberger if (sysctl(mib, 4, &proc, &len, NULL, 0) == -1) {
44180cc79e1SJoerg Sonnenberger warn("sysctl()");
44280cc79e1SJoerg Sonnenberger return ("??");
44380cc79e1SJoerg Sonnenberger }
4445dfd06acSSimon Schubert return (proc.kp_comm);
44580cc79e1SJoerg Sonnenberger }
44680cc79e1SJoerg Sonnenberger
44780cc79e1SJoerg Sonnenberger static int
check_ports(struct sock * s)44880cc79e1SJoerg Sonnenberger check_ports(struct sock *s)
44980cc79e1SJoerg Sonnenberger {
45080cc79e1SJoerg Sonnenberger int port;
45180cc79e1SJoerg Sonnenberger
45280cc79e1SJoerg Sonnenberger if (ports == NULL)
45380cc79e1SJoerg Sonnenberger return (1);
45480cc79e1SJoerg Sonnenberger if ((s->family != AF_INET) && (s->family != AF_INET6))
45580cc79e1SJoerg Sonnenberger return (1);
45680cc79e1SJoerg Sonnenberger if (s->family == AF_INET)
45780cc79e1SJoerg Sonnenberger port = ntohs(((struct sockaddr_in *)(&s->laddr))->sin_port);
45880cc79e1SJoerg Sonnenberger else
45980cc79e1SJoerg Sonnenberger port = ntohs(((struct sockaddr_in6 *)(&s->laddr))->sin6_port);
46080cc79e1SJoerg Sonnenberger if (CHK_PORT(port))
46180cc79e1SJoerg Sonnenberger return (1);
46280cc79e1SJoerg Sonnenberger if (s->family == AF_INET)
46380cc79e1SJoerg Sonnenberger port = ntohs(((struct sockaddr_in *)(&s->faddr))->sin_port);
46480cc79e1SJoerg Sonnenberger else
46580cc79e1SJoerg Sonnenberger port = ntohs(((struct sockaddr_in6 *)(&s->faddr))->sin6_port);
46680cc79e1SJoerg Sonnenberger if (CHK_PORT(port))
46780cc79e1SJoerg Sonnenberger return (1);
46880cc79e1SJoerg Sonnenberger return (0);
46980cc79e1SJoerg Sonnenberger }
47080cc79e1SJoerg Sonnenberger
47180cc79e1SJoerg Sonnenberger static void
display(void)47280cc79e1SJoerg Sonnenberger display(void)
47380cc79e1SJoerg Sonnenberger {
47480cc79e1SJoerg Sonnenberger struct passwd *pwd;
47580cc79e1SJoerg Sonnenberger struct kinfo_file *xf;
47680cc79e1SJoerg Sonnenberger struct sock *s;
47780cc79e1SJoerg Sonnenberger void *p;
478*70bb9b56SAaron LI int hash, n;
47980cc79e1SJoerg Sonnenberger
480*70bb9b56SAaron LI printf("%-8s %-10s %6s %5s %-6s %-21s %-21s\n",
48180cc79e1SJoerg Sonnenberger "USER", "COMMAND", "PID", "FD", "PROTO",
48280cc79e1SJoerg Sonnenberger "LOCAL ADDRESS", "FOREIGN ADDRESS");
48380cc79e1SJoerg Sonnenberger setpassent(1);
48418c5de8bSSascha Wildner for (xf = xfiles, n = 0; n < (int)nxfiles; ++n, ++xf) {
48580cc79e1SJoerg Sonnenberger if (xf->f_data == NULL)
48680cc79e1SJoerg Sonnenberger continue;
48780cc79e1SJoerg Sonnenberger hash = (int)((uintptr_t)xf->f_data % HASHSIZE);
48880cc79e1SJoerg Sonnenberger for (s = sockhash[hash]; s != NULL; s = s->next)
48980cc79e1SJoerg Sonnenberger if ((void *)s->socket == xf->f_data)
49080cc79e1SJoerg Sonnenberger break;
49180cc79e1SJoerg Sonnenberger if (s == NULL)
49280cc79e1SJoerg Sonnenberger continue;
49380cc79e1SJoerg Sonnenberger if (!check_ports(s))
49480cc79e1SJoerg Sonnenberger continue;
495*70bb9b56SAaron LI if ((pwd = getpwuid(xf->f_uid)) != NULL)
496*70bb9b56SAaron LI xprintf("%-8.8s ", pwd->pw_name);
49780cc79e1SJoerg Sonnenberger else
498*70bb9b56SAaron LI xprintf("%-8lu ", (u_long)xf->f_uid);
499*70bb9b56SAaron LI xprintf("%-10.10s ", getprocname(xf->f_pid));
500*70bb9b56SAaron LI xprintf("%6lu ", (u_long)xf->f_pid);
501*70bb9b56SAaron LI xprintf("%5d ", xf->f_fd);
502*70bb9b56SAaron LI printproto(6, s->family, s->protoname);
503*70bb9b56SAaron LI xprintf(" ");
50480cc79e1SJoerg Sonnenberger switch (s->family) {
50580cc79e1SJoerg Sonnenberger case AF_INET:
50680cc79e1SJoerg Sonnenberger case AF_INET6:
507*70bb9b56SAaron LI printaddr(21, s->family, &s->laddr);
508*70bb9b56SAaron LI xprintf(" ");
509*70bb9b56SAaron LI printaddr(0, s->family, &s->faddr);
51080cc79e1SJoerg Sonnenberger break;
51180cc79e1SJoerg Sonnenberger case AF_UNIX:
51280cc79e1SJoerg Sonnenberger /* server */
51380cc79e1SJoerg Sonnenberger if (s->laddr.ss_len > 0) {
514*70bb9b56SAaron LI printaddr(0, s->family, &s->laddr);
51580cc79e1SJoerg Sonnenberger break;
51680cc79e1SJoerg Sonnenberger }
51780cc79e1SJoerg Sonnenberger /* client */
51880cc79e1SJoerg Sonnenberger p = *(void **)&s->faddr;
51980cc79e1SJoerg Sonnenberger if (p == NULL) {
520*70bb9b56SAaron LI xprintf("(not connected)");
52180cc79e1SJoerg Sonnenberger break;
52280cc79e1SJoerg Sonnenberger }
523*70bb9b56SAaron LI xprintf("-> ");
52480cc79e1SJoerg Sonnenberger for (hash = 0; hash < HASHSIZE; ++hash) {
52580cc79e1SJoerg Sonnenberger for (s = sockhash[hash]; s != NULL; s = s->next)
52680cc79e1SJoerg Sonnenberger if (s->pcb == p)
52780cc79e1SJoerg Sonnenberger break;
52880cc79e1SJoerg Sonnenberger if (s != NULL)
52980cc79e1SJoerg Sonnenberger break;
53080cc79e1SJoerg Sonnenberger }
53180cc79e1SJoerg Sonnenberger if (s == NULL || s->laddr.ss_len == 0)
532*70bb9b56SAaron LI xprintf("??");
53380cc79e1SJoerg Sonnenberger else
534*70bb9b56SAaron LI printaddr(0, s->family, &s->laddr);
53580cc79e1SJoerg Sonnenberger break;
53680cc79e1SJoerg Sonnenberger default:
53780cc79e1SJoerg Sonnenberger abort();
53880cc79e1SJoerg Sonnenberger }
53980cc79e1SJoerg Sonnenberger xprintf("\n");
54080cc79e1SJoerg Sonnenberger }
54180cc79e1SJoerg Sonnenberger }
54280cc79e1SJoerg Sonnenberger
54380cc79e1SJoerg Sonnenberger static void
usage(void)54480cc79e1SJoerg Sonnenberger usage(void)
54580cc79e1SJoerg Sonnenberger {
54680cc79e1SJoerg Sonnenberger fprintf(stderr, "Usage: sockstat [-46clu] [-p ports]\n");
54780cc79e1SJoerg Sonnenberger exit(1);
54880cc79e1SJoerg Sonnenberger }
54980cc79e1SJoerg Sonnenberger
55080cc79e1SJoerg Sonnenberger int
main(int argc,char * argv[])55180cc79e1SJoerg Sonnenberger main(int argc, char *argv[])
55280cc79e1SJoerg Sonnenberger {
55380cc79e1SJoerg Sonnenberger int o;
55480cc79e1SJoerg Sonnenberger
55580cc79e1SJoerg Sonnenberger while ((o = getopt(argc, argv, "46clp:uv")) != -1)
55680cc79e1SJoerg Sonnenberger switch (o) {
55780cc79e1SJoerg Sonnenberger case '4':
55880cc79e1SJoerg Sonnenberger opt_4 = 1;
55980cc79e1SJoerg Sonnenberger break;
56080cc79e1SJoerg Sonnenberger case '6':
56180cc79e1SJoerg Sonnenberger opt_6 = 1;
56280cc79e1SJoerg Sonnenberger break;
56380cc79e1SJoerg Sonnenberger case 'c':
56480cc79e1SJoerg Sonnenberger opt_c = 1;
56580cc79e1SJoerg Sonnenberger break;
56680cc79e1SJoerg Sonnenberger case 'l':
56780cc79e1SJoerg Sonnenberger opt_l = 1;
56880cc79e1SJoerg Sonnenberger break;
56980cc79e1SJoerg Sonnenberger case 'p':
57080cc79e1SJoerg Sonnenberger parse_ports(optarg);
57180cc79e1SJoerg Sonnenberger break;
57280cc79e1SJoerg Sonnenberger case 'u':
57380cc79e1SJoerg Sonnenberger opt_u = 1;
57480cc79e1SJoerg Sonnenberger break;
57580cc79e1SJoerg Sonnenberger case 'v':
57680cc79e1SJoerg Sonnenberger ++opt_v;
57780cc79e1SJoerg Sonnenberger break;
57880cc79e1SJoerg Sonnenberger default:
57980cc79e1SJoerg Sonnenberger usage();
58080cc79e1SJoerg Sonnenberger }
58180cc79e1SJoerg Sonnenberger
58280cc79e1SJoerg Sonnenberger argc -= optind;
58380cc79e1SJoerg Sonnenberger argv += optind;
58480cc79e1SJoerg Sonnenberger
58580cc79e1SJoerg Sonnenberger if (argc > 0)
58680cc79e1SJoerg Sonnenberger usage();
58780cc79e1SJoerg Sonnenberger
58880cc79e1SJoerg Sonnenberger if (!opt_4 && !opt_6 && !opt_u)
58980cc79e1SJoerg Sonnenberger opt_4 = opt_6 = opt_u = 1;
59080cc79e1SJoerg Sonnenberger if (!opt_c && !opt_l)
59180cc79e1SJoerg Sonnenberger opt_c = opt_l = 1;
59280cc79e1SJoerg Sonnenberger
59380cc79e1SJoerg Sonnenberger if (opt_4 || opt_6) {
59480cc79e1SJoerg Sonnenberger gather_inet(IPPROTO_TCP);
59580cc79e1SJoerg Sonnenberger gather_inet(IPPROTO_UDP);
59680cc79e1SJoerg Sonnenberger gather_inet(IPPROTO_DIVERT);
59780cc79e1SJoerg Sonnenberger }
59880cc79e1SJoerg Sonnenberger if (opt_u) {
59980cc79e1SJoerg Sonnenberger gather_unix(SOCK_STREAM);
60080cc79e1SJoerg Sonnenberger gather_unix(SOCK_DGRAM);
60180cc79e1SJoerg Sonnenberger }
60280cc79e1SJoerg Sonnenberger getfiles();
60380cc79e1SJoerg Sonnenberger display();
60480cc79e1SJoerg Sonnenberger
60580cc79e1SJoerg Sonnenberger exit(0);
60680cc79e1SJoerg Sonnenberger }
607