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 $
32 #include <sys/param.h>
33 #include <sys/socket.h>
34 #include <sys/socketvar.h>
35 #include <sys/sysctl.h>
39 #include <sys/unpcb.h>
41 #include <net/route.h>
43 #include <netinet/in.h>
44 #include <netinet/in_pcb.h>
45 #include <netinet/tcp.h>
46 #include <netinet/tcp_seq.h>
47 #include <netinet/tcp_var.h>
48 #include <arpa/inet.h>
63 static int opt_4
; /* Show IPv4 sockets */
64 static int opt_6
; /* Show IPv6 sockets */
65 static int opt_c
; /* Show connected sockets */
66 static int opt_l
; /* Show listening sockets */
67 static int opt_u
; /* Show Unix domain sockets */
68 static int opt_v
; /* Verbose mode */
72 #define INT_BIT (sizeof(int) * CHAR_BIT)
73 #define SET_PORT(p) do { ports[p / INT_BIT] |= 1 << (p % INT_BIT); } while (0)
74 #define CHK_PORT(p) (ports[p / INT_BIT] & (1 << (p % INT_BIT)))
81 const char *protoname
;
82 struct sockaddr_storage laddr
;
83 struct sockaddr_storage faddr
;
88 static struct sock
*sockhash
[HASHSIZE
];
90 static struct kinfo_file
*xfiles
;
91 static size_t nxfiles
;
95 xprintf(const char *fmt
, ...)
101 len
= vprintf(fmt
, ap
);
109 parse_ports(const char *portspec
)
115 if ((ports
= calloc(65536 / INT_BIT
, sizeof(int))) == NULL
)
120 errx(1, "syntax error in port range");
121 for (q
= p
; *q
!= '\0' && isdigit(*q
); ++q
)
123 for (port
= 0; p
< q
; ++p
)
124 port
= port
* 10 + (*p
- '0');
125 if (port
< 0 || port
> 65535)
126 errx(1, "invalid port number");
139 for (q
= p
; *q
!= '\0' && isdigit(*q
); ++q
)
141 for (end
= 0; p
< q
; ++p
)
142 end
= end
* 10 + (*p
- '0');
143 if (end
< port
|| end
> 65535)
144 errx(1, "invalid port number");
153 sockaddr(struct sockaddr_storage
*sa
, int af
, void *addr
, int port
)
155 struct sockaddr_in
*sin4
;
156 struct sockaddr_in6
*sin6
;
158 bzero(sa
, sizeof *sa
);
161 sin4
= (struct sockaddr_in
*)sa
;
162 sin4
->sin_len
= sizeof *sin4
;
163 sin4
->sin_family
= af
;
164 sin4
->sin_port
= port
;
165 sin4
->sin_addr
= *(struct in_addr
*)addr
;
168 sin6
= (struct sockaddr_in6
*)sa
;
169 sin6
->sin6_len
= sizeof *sin6
;
170 sin6
->sin6_family
= af
;
171 sin6
->sin6_port
= port
;
172 sin6
->sin6_addr
= *(struct in6_addr
*)addr
;
180 gather_inet(int proto
)
182 uint8_t *buf
, *so_begin
, *so_end
;
188 const char *varname
, *protoname
;
194 varname
= "net.inet.tcp.pcblist";
198 varname
= "net.inet.udp.pcblist";
202 varname
= "net.inet.divert.pcblist";
212 if (sysctlbyname(varname
, NULL
, &len
, NULL
, 0)) {
215 err(1, "fetching %s", varname
);
217 if ((buf
= malloc(len
)) == NULL
)
219 if (sysctlbyname(varname
, buf
, &len
, NULL
, 0)) {
222 err(1, "fetching %s", varname
);
225 for (so_begin
= buf
, so_end
= buf
+ len
;
226 so_begin
+ sizeof(size_t) < so_end
&&
227 so_begin
+ *(size_t *)so_begin
<= so_end
;
228 so_begin
= so_begin
+ *(size_t *)so_begin
) {
231 xtp
= (struct xtcpcb
*)so_begin
;
232 if (xtp
->xt_len
!= sizeof *xtp
) {
233 warnx("struct xtcpcb size mismatch");
237 so
= &xtp
->xt_socket
;
241 xip
= (struct xinpcb
*)so_begin
;
242 if (xip
->xi_len
!= sizeof *xip
) {
243 warnx("struct xinpcb size mismatch");
247 so
= &xip
->xi_socket
;
252 if ((INP_ISIPV4(inp
) && !opt_4
) || (INP_ISIPV6(inp
) && !opt_6
))
254 if (INP_ISIPV4(inp
)) {
255 if ((inp
->inp_fport
== 0 && !opt_l
) ||
256 (inp
->inp_fport
!= 0 && !opt_c
))
258 } else if (INP_ISIPV6(inp
)) {
259 if ((inp
->in6p_fport
== 0 && !opt_l
) ||
260 (inp
->in6p_fport
!= 0 && !opt_c
))
264 warnx("invalid af 0x%x", inp
->inp_af
);
267 if ((sock
= calloc(1, sizeof *sock
)) == NULL
)
269 sock
->socket
= so
->xso_so
;
271 if (INP_ISIPV4(inp
)) {
272 sock
->family
= AF_INET
;
273 sockaddr(&sock
->laddr
, sock
->family
,
274 &inp
->inp_laddr
, inp
->inp_lport
);
275 sockaddr(&sock
->faddr
, sock
->family
,
276 &inp
->inp_faddr
, inp
->inp_fport
);
277 } else if (INP_ISIPV6(inp
)) {
278 sock
->family
= AF_INET6
;
279 sockaddr(&sock
->laddr
, sock
->family
,
280 &inp
->in6p_laddr
, inp
->in6p_lport
);
281 sockaddr(&sock
->faddr
, sock
->family
,
282 &inp
->in6p_faddr
, inp
->in6p_fport
);
284 sock
->protoname
= protoname
;
285 hash
= (int)((uintptr_t)sock
->socket
% HASHSIZE
);
286 sock
->next
= sockhash
[hash
];
287 sockhash
[hash
] = sock
;
294 gather_unix(int proto
)
296 uint8_t *buf
, *so_begin
, *so_end
;
299 const char *varname
, *protoname
;
305 varname
= "net.local.stream.pcblist";
306 protoname
= "stream";
309 varname
= "net.local.dgram.pcblist";
319 if (sysctlbyname(varname
, NULL
, &len
, NULL
, 0))
320 err(1, "fetching %s", varname
);
322 if ((buf
= malloc(len
)) == NULL
)
324 if (sysctlbyname(varname
, buf
, &len
, NULL
, 0))
325 err(1, "fetching %s", varname
);
327 for (so_begin
= buf
, so_end
= buf
+ len
;
328 so_begin
+ sizeof(size_t) < so_end
&&
329 so_begin
+ *(size_t *)so_begin
<= so_end
;
330 so_begin
= so_begin
+ *(size_t *)so_begin
) {
331 xup
= (struct xunpcb
*)so_begin
;
332 if (xup
->xu_len
!= sizeof *xup
) {
333 warnx("struct xunpcb size mismatch");
336 if ((xup
->xu_unp
.unp_conn
== NULL
&& !opt_l
) ||
337 (xup
->xu_unp
.unp_conn
!= NULL
&& !opt_c
))
339 if ((sock
= calloc(1, sizeof *sock
)) == NULL
)
341 sock
->socket
= xup
->xu_socket
.xso_so
;
342 sock
->pcb
= xup
->xu_unpp
;
344 sock
->family
= AF_UNIX
;
345 sock
->protoname
= protoname
;
346 if (xup
->xu_unp
.unp_addr
!= NULL
)
347 sock
->laddr
= *(struct sockaddr_storage
*)&xup
->xu_addr
;
348 else if (xup
->xu_unp
.unp_conn
!= NULL
)
349 *(void **)&sock
->faddr
= xup
->xu_unp
.unp_conn
;
350 hash
= (int)((uintptr_t)sock
->socket
% HASHSIZE
);
351 sock
->next
= sockhash
[hash
];
352 sockhash
[hash
] = sock
;
361 if (kinfo_get_files(&xfiles
, &nxfiles
))
362 err(1, "kinfo_get_files");
366 printproto(int width
, int af
, const char *protoname
)
373 n
= xprintf("%s%c", protoname
, af
== AF_INET
? '4' : '6');
376 n
= xprintf("%s", protoname
);
380 if (width
> 0 && width
> n
)
381 xprintf("%*s", width
- n
, "");
385 printaddr(int width
, int af
, struct sockaddr_storage
*ss
)
387 char addrstr
[INET6_ADDRSTRLEN
] = { '\0', '\0' };
388 struct sockaddr_un
*sun
;
393 sun
= (struct sockaddr_un
*)ss
;
394 n
= sun
->sun_len
- offsetof(struct sockaddr_un
, sun_path
);
395 xprintf("%.*s", n
, sun
->sun_path
);
396 if (width
> 0 && width
> n
)
397 xprintf("%*s", width
- n
, "");
403 addr
= &((struct sockaddr_in
*)ss
)->sin_addr
;
404 if (inet_lnaof(*(struct in_addr
*)addr
) == INADDR_ANY
)
406 port
= ntohs(((struct sockaddr_in
*)ss
)->sin_port
);
409 addr
= &((struct sockaddr_in6
*)ss
)->sin6_addr
;
410 if (IN6_IS_ADDR_UNSPECIFIED((struct in6_addr
*)addr
))
412 port
= ntohs(((struct sockaddr_in6
*)ss
)->sin6_port
);
418 if (addrstr
[0] == '\0')
419 inet_ntop(af
, addr
, addrstr
, sizeof addrstr
);
421 n
= xprintf("%s:*", addrstr
);
423 n
= xprintf("%s:%d", addrstr
, port
);
424 if (width
> 0 && width
> n
)
425 xprintf("%*s", width
- n
, "");
429 getprocname(pid_t pid
)
431 static struct kinfo_proc proc
;
437 mib
[2] = KERN_PROC_PID
;
440 if (sysctl(mib
, 4, &proc
, &len
, NULL
, 0) == -1) {
444 return (proc
.kp_comm
);
448 check_ports(struct sock
*s
)
454 if ((s
->family
!= AF_INET
) && (s
->family
!= AF_INET6
))
456 if (s
->family
== AF_INET
)
457 port
= ntohs(((struct sockaddr_in
*)(&s
->laddr
))->sin_port
);
459 port
= ntohs(((struct sockaddr_in6
*)(&s
->laddr
))->sin6_port
);
462 if (s
->family
== AF_INET
)
463 port
= ntohs(((struct sockaddr_in
*)(&s
->faddr
))->sin_port
);
465 port
= ntohs(((struct sockaddr_in6
*)(&s
->faddr
))->sin6_port
);
475 struct kinfo_file
*xf
;
480 printf("%-8s %-10s %6s %5s %-6s %-21s %-21s\n",
481 "USER", "COMMAND", "PID", "FD", "PROTO",
482 "LOCAL ADDRESS", "FOREIGN ADDRESS");
484 for (xf
= xfiles
, n
= 0; n
< (int)nxfiles
; ++n
, ++xf
) {
485 if (xf
->f_data
== NULL
)
487 hash
= (int)((uintptr_t)xf
->f_data
% HASHSIZE
);
488 for (s
= sockhash
[hash
]; s
!= NULL
; s
= s
->next
)
489 if ((void *)s
->socket
== xf
->f_data
)
495 if ((pwd
= getpwuid(xf
->f_uid
)) != NULL
)
496 xprintf("%-8.8s ", pwd
->pw_name
);
498 xprintf("%-8lu ", (u_long
)xf
->f_uid
);
499 xprintf("%-10.10s ", getprocname(xf
->f_pid
));
500 xprintf("%6lu ", (u_long
)xf
->f_pid
);
501 xprintf("%5d ", xf
->f_fd
);
502 printproto(6, s
->family
, s
->protoname
);
507 printaddr(21, s
->family
, &s
->laddr
);
509 printaddr(0, s
->family
, &s
->faddr
);
513 if (s
->laddr
.ss_len
> 0) {
514 printaddr(0, s
->family
, &s
->laddr
);
518 p
= *(void **)&s
->faddr
;
520 xprintf("(not connected)");
524 for (hash
= 0; hash
< HASHSIZE
; ++hash
) {
525 for (s
= sockhash
[hash
]; s
!= NULL
; s
= s
->next
)
531 if (s
== NULL
|| s
->laddr
.ss_len
== 0)
534 printaddr(0, s
->family
, &s
->laddr
);
546 fprintf(stderr
, "Usage: sockstat [-46clu] [-p ports]\n");
551 main(int argc
, char *argv
[])
555 while ((o
= getopt(argc
, argv
, "46clp:uv")) != -1)
588 if (!opt_4
&& !opt_6
&& !opt_u
)
589 opt_4
= opt_6
= opt_u
= 1;
590 if (!opt_c
&& !opt_l
)
593 if (opt_4
|| opt_6
) {
594 gather_inet(IPPROTO_TCP
);
595 gather_inet(IPPROTO_UDP
);
596 gather_inet(IPPROTO_DIVERT
);
599 gather_unix(SOCK_STREAM
);
600 gather_unix(SOCK_DGRAM
);