2 * Copyright (c) 2005 Joerg Sonnenberger <joerg@bec.de>. All rights reserved.
3 * Copyright (c) 2002 Dag-Erling Coïdan Smørgrav
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer
11 * in this position and unchanged.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 * $FreeBSD: src/usr.bin/sockstat/sockstat.c,v 1.12 2004/12/06 09:28:05 ru Exp $
30 * $DragonFly: src/usr.bin/sockstat/sockstat.c,v 1.7 2007/02/01 10:33:26 corecode Exp $
33 #define _KERNEL_STRUCTURES
34 #include <sys/param.h>
35 #include <sys/socket.h>
36 #include <sys/socketvar.h>
37 #include <sys/sysctl.h>
42 #include <sys/unpcb.h>
44 #include <net/route.h>
46 #include <netinet/in.h>
47 #include <netinet/in_pcb.h>
48 #include <netinet/tcp.h>
49 #include <netinet/tcp_seq.h>
50 #include <netinet/tcp_var.h>
51 #include <arpa/inet.h>
65 static int opt_4
; /* Show IPv4 sockets */
66 static int opt_6
; /* Show IPv6 sockets */
67 static int opt_c
; /* Show connected sockets */
68 static int opt_l
; /* Show listening sockets */
69 static int opt_u
; /* Show Unix domain sockets */
70 static int opt_v
; /* Verbose mode */
74 #define INT_BIT (sizeof(int)*CHAR_BIT)
75 #define SET_PORT(p) do { ports[p / INT_BIT] |= 1 << (p % INT_BIT); } while (0)
76 #define CHK_PORT(p) (ports[p / INT_BIT] & (1 << (p % INT_BIT)))
84 const char *protoname
;
85 struct sockaddr_storage laddr
;
86 struct sockaddr_storage faddr
;
91 static struct sock
*sockhash
[HASHSIZE
];
93 static struct kinfo_file
*xfiles
;
94 static size_t nxfiles
;
97 xprintf(const char *fmt
, ...)
103 len
= vprintf(fmt
, ap
);
111 parse_ports(const char *portspec
)
117 if ((ports
= calloc(65536 / INT_BIT
, sizeof(int))) == NULL
)
122 errx(1, "syntax error in port range");
123 for (q
= p
; *q
!= '\0' && isdigit(*q
); ++q
)
125 for (port
= 0; p
< q
; ++p
)
126 port
= port
* 10 + (*p
- '0');
127 if (port
< 0 || port
> 65535)
128 errx(1, "invalid port number");
141 for (q
= p
; *q
!= '\0' && isdigit(*q
); ++q
)
143 for (end
= 0; p
< q
; ++p
)
144 end
= end
* 10 + (*p
- '0');
145 if (end
< port
|| end
> 65535)
146 errx(1, "invalid port number");
155 sockaddr(struct sockaddr_storage
*sa
, int af
, void *addr
, int port
)
157 struct sockaddr_in
*sin4
;
158 struct sockaddr_in6
*sin6
;
160 bzero(sa
, sizeof *sa
);
163 sin4
= (struct sockaddr_in
*)sa
;
164 sin4
->sin_len
= sizeof *sin4
;
165 sin4
->sin_family
= af
;
166 sin4
->sin_port
= port
;
167 sin4
->sin_addr
= *(struct in_addr
*)addr
;
170 sin6
= (struct sockaddr_in6
*)sa
;
171 sin6
->sin6_len
= sizeof *sin6
;
172 sin6
->sin6_family
= af
;
173 sin6
->sin6_port
= port
;
174 sin6
->sin6_addr
= *(struct in6_addr
*)addr
;
182 gather_inet(int proto
)
184 void *so_begin
, *so_end
;
190 const char *varname
, *protoname
;
203 varname
= "net.inet.tcp.pcblist";
207 varname
= "net.inet.udp.pcblist";
211 varname
= "net.inet.divert.pcblist";
221 if (sysctlbyname(varname
, NULL
, &len
, NULL
, 0)) {
224 err(1, "fetching %s", varname
);
226 if ((buf
= malloc(len
)) == NULL
)
228 if (sysctlbyname(varname
, buf
, &len
, NULL
, 0)) {
231 err(1, "fetching %s", varname
);
235 so_end
= (uint8_t *)buf
+ len
;
237 for (so_begin
= buf
, so_end
= (uint8_t *)so_begin
+ len
;
238 (uint8_t *)so_begin
+ sizeof(size_t) < (uint8_t *)so_end
&&
239 (uint8_t *)so_begin
+ *(size_t *)so_begin
<= (uint8_t *)so_end
;
240 so_begin
= (uint8_t *)so_begin
+ *(size_t *)so_begin
) {
243 xtp
= (struct xtcpcb
*)so_begin
;
244 if (xtp
->xt_len
!= sizeof *xtp
) {
245 warnx("struct xtcpcb size mismatch");
249 so
= &xtp
->xt_socket
;
253 xip
= (struct xinpcb
*)so_begin
;
254 if (xip
->xi_len
!= sizeof *xip
) {
255 warnx("struct xinpcb size mismatch");
259 so
= &xip
->xi_socket
;
264 if ((inp
->inp_vflag
& vflag
) == 0)
266 if (inp
->inp_vflag
& INP_IPV4
) {
267 if ((inp
->inp_fport
== 0 && !opt_l
) ||
268 (inp
->inp_fport
!= 0 && !opt_c
))
270 } else if (inp
->inp_vflag
& INP_IPV6
) {
271 if ((inp
->in6p_fport
== 0 && !opt_l
) ||
272 (inp
->in6p_fport
!= 0 && !opt_c
))
276 warnx("invalid vflag 0x%x", inp
->inp_vflag
);
279 if ((sock
= calloc(1, sizeof *sock
)) == NULL
)
281 sock
->socket
= so
->xso_so
;
283 if (inp
->inp_vflag
& INP_IPV4
) {
284 sock
->family
= AF_INET
;
285 sockaddr(&sock
->laddr
, sock
->family
,
286 &inp
->inp_laddr
, inp
->inp_lport
);
287 sockaddr(&sock
->faddr
, sock
->family
,
288 &inp
->inp_faddr
, inp
->inp_fport
);
289 } else if (inp
->inp_vflag
& INP_IPV6
) {
290 sock
->family
= AF_INET6
;
291 sockaddr(&sock
->laddr
, sock
->family
,
292 &inp
->in6p_laddr
, inp
->in6p_lport
);
293 sockaddr(&sock
->faddr
, sock
->family
,
294 &inp
->in6p_faddr
, inp
->in6p_fport
);
296 sock
->vflag
= inp
->inp_vflag
;
297 sock
->protoname
= protoname
;
298 hash
= (int)((uintptr_t)sock
->socket
% HASHSIZE
);
299 sock
->next
= sockhash
[hash
];
300 sockhash
[hash
] = sock
;
307 gather_unix(int proto
)
309 void *so_begin
, *so_end
;
312 const char *varname
, *protoname
;
319 varname
= "net.local.stream.pcblist";
320 protoname
= "stream";
323 varname
= "net.local.dgram.pcblist";
333 if (sysctlbyname(varname
, NULL
, &len
, NULL
, 0))
334 err(1, "fetching %s", varname
);
336 if ((buf
= malloc(len
)) == NULL
)
338 if (sysctlbyname(varname
, buf
, &len
, NULL
, 0))
339 err(1, "fetching %s", varname
);
341 for (so_begin
= buf
, so_end
= (uint8_t *)buf
+ len
;
342 (uint8_t *)so_begin
+ sizeof(size_t) < (uint8_t *)so_end
&&
343 (uint8_t *)so_begin
+ *(size_t *)so_begin
<= (uint8_t *)so_end
;
344 so_begin
= (uint8_t *)so_begin
+ *(size_t *)so_begin
) {
346 if (xup
->xu_len
!= sizeof *xup
) {
347 warnx("struct xunpcb size mismatch");
350 if ((xup
->xu_unp
.unp_conn
== NULL
&& !opt_l
) ||
351 (xup
->xu_unp
.unp_conn
!= NULL
&& !opt_c
))
353 if ((sock
= calloc(1, sizeof *sock
)) == NULL
)
355 sock
->socket
= xup
->xu_socket
.xso_so
;
356 sock
->pcb
= xup
->xu_unpp
;
358 sock
->family
= AF_UNIX
;
359 sock
->protoname
= protoname
;
360 if (xup
->xu_unp
.unp_addr
!= NULL
)
362 *(struct sockaddr_storage
*)(void *)&xup
->xu_addr
;
363 else if (xup
->xu_unp
.unp_conn
!= NULL
)
364 *(void **)&sock
->faddr
= xup
->xu_unp
.unp_conn
;
365 hash
= (int)((uintptr_t)sock
->socket
% HASHSIZE
);
366 sock
->next
= sockhash
[hash
];
367 sockhash
[hash
] = sock
;
376 if (kinfo_get_files(&xfiles
, &nxfiles
))
377 err(1, "kinfo_get_files");
381 printaddr(int af
, struct sockaddr_storage
*ss
)
383 char addrstr
[INET6_ADDRSTRLEN
] = { '\0', '\0' };
384 struct sockaddr_un
*sun
;
390 addr
= &((struct sockaddr_in
*)ss
)->sin_addr
;
391 if (inet_lnaof(*(struct in_addr
*)addr
) == INADDR_ANY
)
393 port
= ntohs(((struct sockaddr_in
*)ss
)->sin_port
);
396 addr
= &((struct sockaddr_in6
*)ss
)->sin6_addr
;
397 if (IN6_IS_ADDR_UNSPECIFIED((struct in6_addr
*)addr
))
399 port
= ntohs(((struct sockaddr_in6
*)ss
)->sin6_port
);
402 sun
= (struct sockaddr_un
*)ss
;
403 off
= (int)((char *)&sun
->sun_path
- (char *)sun
);
404 return (xprintf("%.*s", sun
->sun_len
- off
, sun
->sun_path
));
408 if (addrstr
[0] == '\0')
409 inet_ntop(af
, addr
, addrstr
, sizeof addrstr
);
411 return xprintf("%s:*", addrstr
);
413 return xprintf("%s:%d", addrstr
, port
);
417 getprocname(pid_t pid
)
419 static struct kinfo_proc proc
;
425 mib
[2] = KERN_PROC_PID
;
428 if (sysctl(mib
, 4, &proc
, &len
, NULL
, 0) == -1) {
432 return (proc
.kp_comm
);
436 check_ports(struct sock
*s
)
442 if ((s
->family
!= AF_INET
) && (s
->family
!= AF_INET6
))
444 if (s
->family
== AF_INET
)
445 port
= ntohs(((struct sockaddr_in
*)(&s
->laddr
))->sin_port
);
447 port
= ntohs(((struct sockaddr_in6
*)(&s
->laddr
))->sin6_port
);
450 if (s
->family
== AF_INET
)
451 port
= ntohs(((struct sockaddr_in
*)(&s
->faddr
))->sin_port
);
453 port
= ntohs(((struct sockaddr_in6
*)(&s
->faddr
))->sin6_port
);
463 struct kinfo_file
*xf
;
468 printf("%-8s %-10s %-5s %-2s %-6s %-21s %-21s\n",
469 "USER", "COMMAND", "PID", "FD", "PROTO",
470 "LOCAL ADDRESS", "FOREIGN ADDRESS");
472 for (xf
= xfiles
, n
= 0; n
< nxfiles
; ++n
, ++xf
) {
473 if (xf
->f_data
== NULL
)
475 hash
= (int)((uintptr_t)xf
->f_data
% HASHSIZE
);
476 for (s
= sockhash
[hash
]; s
!= NULL
; s
= s
->next
)
477 if ((void *)s
->socket
== xf
->f_data
)
484 if ((pwd
= getpwuid(xf
->f_uid
)) == NULL
)
485 pos
+= xprintf("%lu", (u_long
)xf
->f_uid
);
487 pos
+= xprintf("%s", pwd
->pw_name
);
490 pos
+= xprintf("%.10s", getprocname(xf
->f_pid
));
493 pos
+= xprintf("%lu", (u_long
)xf
->f_pid
);
496 pos
+= xprintf("%d", xf
->f_fd
);
499 pos
+= xprintf("%s", s
->protoname
);
500 if (s
->vflag
& INP_IPV4
)
502 if (s
->vflag
& INP_IPV6
)
509 pos
+= printaddr(s
->family
, &s
->laddr
);
513 pos
+= printaddr(s
->family
, &s
->faddr
);
517 if (s
->laddr
.ss_len
> 0) {
518 pos
+= printaddr(s
->family
, &s
->laddr
);
522 p
= *(void **)&s
->faddr
;
524 pos
+= xprintf("(not connected)");
527 pos
+= xprintf("-> ");
528 for (hash
= 0; hash
< HASHSIZE
; ++hash
) {
529 for (s
= sockhash
[hash
]; s
!= NULL
; s
= s
->next
)
535 if (s
== NULL
|| s
->laddr
.ss_len
== 0)
536 pos
+= xprintf("??");
538 pos
+= printaddr(s
->family
, &s
->laddr
);
550 fprintf(stderr
, "Usage: sockstat [-46clu] [-p ports]\n");
555 main(int argc
, char *argv
[])
559 while ((o
= getopt(argc
, argv
, "46clp:uv")) != -1)
592 if (!opt_4
&& !opt_6
&& !opt_u
)
593 opt_4
= opt_6
= opt_u
= 1;
594 if (!opt_c
&& !opt_l
)
597 if (opt_4
|| opt_6
) {
598 gather_inet(IPPROTO_TCP
);
599 gather_inet(IPPROTO_UDP
);
600 gather_inet(IPPROTO_DIVERT
);
603 gather_unix(SOCK_STREAM
);
604 gather_unix(SOCK_DGRAM
);