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 #include <sys/param.h>
34 #include <sys/socket.h>
35 #include <sys/socketvar.h>
36 #include <sys/sysctl.h>
41 #include <sys/unpcb.h>
43 #include <net/route.h>
45 #include <netinet/in.h>
46 #include <netinet/in_pcb.h>
47 #include <netinet/tcp.h>
48 #include <netinet/tcp_seq.h>
49 #include <netinet/tcp_var.h>
50 #include <arpa/inet.h>
64 static int opt_4
; /* Show IPv4 sockets */
65 static int opt_6
; /* Show IPv6 sockets */
66 static int opt_c
; /* Show connected sockets */
67 static int opt_l
; /* Show listening sockets */
68 static int opt_u
; /* Show Unix domain sockets */
69 static int opt_v
; /* Verbose mode */
73 #define INT_BIT (sizeof(int)*CHAR_BIT)
74 #define SET_PORT(p) do { ports[p / INT_BIT] |= 1 << (p % INT_BIT); } while (0)
75 #define CHK_PORT(p) (ports[p / INT_BIT] & (1 << (p % INT_BIT)))
83 const char *protoname
;
84 struct sockaddr_storage laddr
;
85 struct sockaddr_storage faddr
;
90 static struct sock
*sockhash
[HASHSIZE
];
92 static struct kinfo_file
*xfiles
;
93 static size_t nxfiles
;
96 xprintf(const char *fmt
, ...)
102 len
= vprintf(fmt
, ap
);
110 parse_ports(const char *portspec
)
116 if ((ports
= calloc(65536 / INT_BIT
, sizeof(int))) == NULL
)
121 errx(1, "syntax error in port range");
122 for (q
= p
; *q
!= '\0' && isdigit(*q
); ++q
)
124 for (port
= 0; p
< q
; ++p
)
125 port
= port
* 10 + (*p
- '0');
126 if (port
< 0 || port
> 65535)
127 errx(1, "invalid port number");
140 for (q
= p
; *q
!= '\0' && isdigit(*q
); ++q
)
142 for (end
= 0; p
< q
; ++p
)
143 end
= end
* 10 + (*p
- '0');
144 if (end
< port
|| end
> 65535)
145 errx(1, "invalid port number");
154 sockaddr(struct sockaddr_storage
*sa
, int af
, void *addr
, int port
)
156 struct sockaddr_in
*sin4
;
157 struct sockaddr_in6
*sin6
;
159 bzero(sa
, sizeof *sa
);
162 sin4
= (struct sockaddr_in
*)sa
;
163 sin4
->sin_len
= sizeof *sin4
;
164 sin4
->sin_family
= af
;
165 sin4
->sin_port
= port
;
166 sin4
->sin_addr
= *(struct in_addr
*)addr
;
169 sin6
= (struct sockaddr_in6
*)sa
;
170 sin6
->sin6_len
= sizeof *sin6
;
171 sin6
->sin6_family
= af
;
172 sin6
->sin6_port
= port
;
173 sin6
->sin6_addr
= *(struct in6_addr
*)addr
;
181 gather_inet(int proto
)
183 void *so_begin
, *so_end
;
189 const char *varname
, *protoname
;
202 varname
= "net.inet.tcp.pcblist";
206 varname
= "net.inet.udp.pcblist";
210 varname
= "net.inet.divert.pcblist";
220 if (sysctlbyname(varname
, NULL
, &len
, NULL
, 0)) {
223 err(1, "fetching %s", varname
);
225 if ((buf
= malloc(len
)) == NULL
)
227 if (sysctlbyname(varname
, buf
, &len
, NULL
, 0)) {
230 err(1, "fetching %s", varname
);
234 so_end
= (uint8_t *)buf
+ len
;
236 for (so_begin
= buf
, so_end
= (uint8_t *)so_begin
+ len
;
237 (uint8_t *)so_begin
+ sizeof(size_t) < (uint8_t *)so_end
&&
238 (uint8_t *)so_begin
+ *(size_t *)so_begin
<= (uint8_t *)so_end
;
239 so_begin
= (uint8_t *)so_begin
+ *(size_t *)so_begin
) {
242 xtp
= (struct xtcpcb
*)so_begin
;
243 if (xtp
->xt_len
!= sizeof *xtp
) {
244 warnx("struct xtcpcb size mismatch");
248 so
= &xtp
->xt_socket
;
252 xip
= (struct xinpcb
*)so_begin
;
253 if (xip
->xi_len
!= sizeof *xip
) {
254 warnx("struct xinpcb size mismatch");
258 so
= &xip
->xi_socket
;
263 if ((inp
->inp_vflag
& vflag
) == 0)
265 if (inp
->inp_vflag
& INP_IPV4
) {
266 if ((inp
->inp_fport
== 0 && !opt_l
) ||
267 (inp
->inp_fport
!= 0 && !opt_c
))
269 } else if (inp
->inp_vflag
& INP_IPV6
) {
270 if ((inp
->in6p_fport
== 0 && !opt_l
) ||
271 (inp
->in6p_fport
!= 0 && !opt_c
))
275 warnx("invalid vflag 0x%x", inp
->inp_vflag
);
278 if ((sock
= calloc(1, sizeof *sock
)) == NULL
)
280 sock
->socket
= so
->xso_so
;
282 if (inp
->inp_vflag
& INP_IPV4
) {
283 sock
->family
= AF_INET
;
284 sockaddr(&sock
->laddr
, sock
->family
,
285 &inp
->inp_laddr
, inp
->inp_lport
);
286 sockaddr(&sock
->faddr
, sock
->family
,
287 &inp
->inp_faddr
, inp
->inp_fport
);
288 } else if (inp
->inp_vflag
& INP_IPV6
) {
289 sock
->family
= AF_INET6
;
290 sockaddr(&sock
->laddr
, sock
->family
,
291 &inp
->in6p_laddr
, inp
->in6p_lport
);
292 sockaddr(&sock
->faddr
, sock
->family
,
293 &inp
->in6p_faddr
, inp
->in6p_fport
);
295 sock
->vflag
= inp
->inp_vflag
;
296 sock
->protoname
= protoname
;
297 hash
= (int)((uintptr_t)sock
->socket
% HASHSIZE
);
298 sock
->next
= sockhash
[hash
];
299 sockhash
[hash
] = sock
;
306 gather_unix(int proto
)
308 void *so_begin
, *so_end
;
311 const char *varname
, *protoname
;
318 varname
= "net.local.stream.pcblist";
319 protoname
= "stream";
322 varname
= "net.local.dgram.pcblist";
332 if (sysctlbyname(varname
, NULL
, &len
, NULL
, 0))
333 err(1, "fetching %s", varname
);
335 if ((buf
= malloc(len
)) == NULL
)
337 if (sysctlbyname(varname
, buf
, &len
, NULL
, 0))
338 err(1, "fetching %s", varname
);
340 for (so_begin
= buf
, so_end
= (uint8_t *)buf
+ len
;
341 (uint8_t *)so_begin
+ sizeof(size_t) < (uint8_t *)so_end
&&
342 (uint8_t *)so_begin
+ *(size_t *)so_begin
<= (uint8_t *)so_end
;
343 so_begin
= (uint8_t *)so_begin
+ *(size_t *)so_begin
) {
345 if (xup
->xu_len
!= sizeof *xup
) {
346 warnx("struct xunpcb size mismatch");
349 if ((xup
->xu_unp
.unp_conn
== NULL
&& !opt_l
) ||
350 (xup
->xu_unp
.unp_conn
!= NULL
&& !opt_c
))
352 if ((sock
= calloc(1, sizeof *sock
)) == NULL
)
354 sock
->socket
= xup
->xu_socket
.xso_so
;
355 sock
->pcb
= xup
->xu_unpp
;
357 sock
->family
= AF_UNIX
;
358 sock
->protoname
= protoname
;
359 if (xup
->xu_unp
.unp_addr
!= NULL
)
361 *(struct sockaddr_storage
*)(void *)&xup
->xu_addr
;
362 else if (xup
->xu_unp
.unp_conn
!= NULL
)
363 *(void **)&sock
->faddr
= xup
->xu_unp
.unp_conn
;
364 hash
= (int)((uintptr_t)sock
->socket
% HASHSIZE
);
365 sock
->next
= sockhash
[hash
];
366 sockhash
[hash
] = sock
;
375 if (kinfo_get_files(&xfiles
, &nxfiles
))
376 err(1, "kinfo_get_files");
380 printaddr(int af
, struct sockaddr_storage
*ss
)
382 char addrstr
[INET6_ADDRSTRLEN
] = { '\0', '\0' };
383 struct sockaddr_un
*sun
;
389 addr
= &((struct sockaddr_in
*)ss
)->sin_addr
;
390 if (inet_lnaof(*(struct in_addr
*)addr
) == INADDR_ANY
)
392 port
= ntohs(((struct sockaddr_in
*)ss
)->sin_port
);
395 addr
= &((struct sockaddr_in6
*)ss
)->sin6_addr
;
396 if (IN6_IS_ADDR_UNSPECIFIED((struct in6_addr
*)addr
))
398 port
= ntohs(((struct sockaddr_in6
*)ss
)->sin6_port
);
401 sun
= (struct sockaddr_un
*)ss
;
402 off
= (int)((char *)&sun
->sun_path
- (char *)sun
);
403 return (xprintf("%.*s", sun
->sun_len
- off
, sun
->sun_path
));
407 if (addrstr
[0] == '\0')
408 inet_ntop(af
, addr
, addrstr
, sizeof addrstr
);
410 return xprintf("%s:*", addrstr
);
412 return xprintf("%s:%d", addrstr
, port
);
416 getprocname(pid_t pid
)
418 static struct kinfo_proc proc
;
424 mib
[2] = KERN_PROC_PID
;
427 if (sysctl(mib
, 4, &proc
, &len
, NULL
, 0) == -1) {
431 return (proc
.kp_comm
);
435 check_ports(struct sock
*s
)
441 if ((s
->family
!= AF_INET
) && (s
->family
!= AF_INET6
))
443 if (s
->family
== AF_INET
)
444 port
= ntohs(((struct sockaddr_in
*)(&s
->laddr
))->sin_port
);
446 port
= ntohs(((struct sockaddr_in6
*)(&s
->laddr
))->sin6_port
);
449 if (s
->family
== AF_INET
)
450 port
= ntohs(((struct sockaddr_in
*)(&s
->faddr
))->sin_port
);
452 port
= ntohs(((struct sockaddr_in6
*)(&s
->faddr
))->sin6_port
);
462 struct kinfo_file
*xf
;
467 printf("%-8s %-10s %-5s %-2s %-6s %-21s %-21s\n",
468 "USER", "COMMAND", "PID", "FD", "PROTO",
469 "LOCAL ADDRESS", "FOREIGN ADDRESS");
471 for (xf
= xfiles
, n
= 0; n
< nxfiles
; ++n
, ++xf
) {
472 if (xf
->f_data
== NULL
)
474 hash
= (int)((uintptr_t)xf
->f_data
% HASHSIZE
);
475 for (s
= sockhash
[hash
]; s
!= NULL
; s
= s
->next
)
476 if ((void *)s
->socket
== xf
->f_data
)
483 if ((pwd
= getpwuid(xf
->f_uid
)) == NULL
)
484 pos
+= xprintf("%lu", (u_long
)xf
->f_uid
);
486 pos
+= xprintf("%s", pwd
->pw_name
);
489 pos
+= xprintf("%.10s", getprocname(xf
->f_pid
));
492 pos
+= xprintf("%lu", (u_long
)xf
->f_pid
);
495 pos
+= xprintf("%d", xf
->f_fd
);
498 pos
+= xprintf("%s", s
->protoname
);
499 if (s
->vflag
& INP_IPV4
)
501 if (s
->vflag
& INP_IPV6
)
508 pos
+= printaddr(s
->family
, &s
->laddr
);
512 pos
+= printaddr(s
->family
, &s
->faddr
);
516 if (s
->laddr
.ss_len
> 0) {
517 pos
+= printaddr(s
->family
, &s
->laddr
);
521 p
= *(void **)&s
->faddr
;
523 pos
+= xprintf("(not connected)");
526 pos
+= xprintf("-> ");
527 for (hash
= 0; hash
< HASHSIZE
; ++hash
) {
528 for (s
= sockhash
[hash
]; s
!= NULL
; s
= s
->next
)
534 if (s
== NULL
|| s
->laddr
.ss_len
== 0)
535 pos
+= xprintf("??");
537 pos
+= printaddr(s
->family
, &s
->laddr
);
549 fprintf(stderr
, "Usage: sockstat [-46clu] [-p ports]\n");
554 main(int argc
, char *argv
[])
558 while ((o
= getopt(argc
, argv
, "46clp:uv")) != -1)
591 if (!opt_4
&& !opt_6
&& !opt_u
)
592 opt_4
= opt_6
= opt_u
= 1;
593 if (!opt_c
&& !opt_l
)
596 if (opt_4
|| opt_6
) {
597 gather_inet(IPPROTO_TCP
);
598 gather_inet(IPPROTO_UDP
);
599 gather_inet(IPPROTO_DIVERT
);
602 gather_unix(SOCK_STREAM
);
603 gather_unix(SOCK_DGRAM
);