* Copyright (c) 1980 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
static char sccsid
[] = "@(#)netstat.c 5.1 (Berkeley) %G%";
#include <sys/socketvar.h>
#include <netinet/in_systm.h>
#include <netinet/in_pcb.h>
#include <netinet/ip_icmp.h>
#include <netinet/icmp_var.h>
#include <netinet/ip_var.h>
#include <netinet/tcpip.h>
#include <netinet/tcp_seq.h>
#include <netinet/tcp_fsm.h>
#include <netinet/tcp_timer.h>
#include <netinet/tcp_var.h>
#include <netinet/tcp_debug.h>
#include <netinet/udp_var.h>
#define streq(a,b) (strcmp(a,b)==0)
#define YMAX(w) ((w)->_maxy-1)
return (subwin(stdscr
, LINES
-5-1, 0, 5, 0));
struct netinfo
*ni_forw
, *ni_prev
;
short ni_line
; /* line on screen */
short ni_seen
; /* 0 when not present in list */
#define NIF_LACHG 0x1 /* local address changed */
#define NIF_FACHG 0x2 /* foreign address changed */
short ni_state
; /* tcp state */
char *ni_proto
; /* protocol */
struct in_addr ni_laddr
; /* local address */
long ni_lport
; /* local port */
struct in_addr ni_faddr
; /* foreign address */
long ni_fport
; /* foreign port */
long ni_rcvcc
; /* rcv buffer character count */
long ni_sndcc
; /* snd buffer character count */
struct netinfo
*ni_forw
, *ni_prev
;
register struct netinfo
*p
, *q
;
while (p
!= (struct netinfo
*)&netcb
) {
static struct nlist nlst
[] = {
if (nlst
[X_TCB
].n_value
== 0) {
error("No symbols in namelist");
netcb
.ni_forw
= netcb
.ni_prev
= (struct netinfo
*)&netcb
;
register struct inpcb
*prev
, *next
;
register struct netinfo
*p
;
if (nlst
[X_TCB
].n_value
== 0)
for (p
= netcb
.ni_forw
; p
!= (struct netinfo
*)&netcb
; p
= p
->ni_forw
)
error("No protocols to display");
off
= nlst
[X_TCB
].n_value
, istcp
= 1;
off
= nlst
[X_UDB
].n_value
, istcp
= 0;
read(kmem
, &inpcb
, sizeof (struct inpcb
));
prev
= (struct inpcb
*)off
;
for (; inpcb
.inp_next
!= (struct inpcb
*)off
; prev
= next
) {
lseek(kmem
, (off_t
)next
, L_SET
);
read(kmem
, &inpcb
, sizeof (inpcb
));
if (inpcb
.inp_prev
!= prev
) {
for (; p
!= (struct netinfo
*)&netcb
; p
= p
->ni_forw
)
error("Kernel state in transition");
if (!aflag
&& inet_lnaof(inpcb
.inp_laddr
) == INADDR_ANY
)
if (nhosts
&& !checkhost(&inpcb
))
if (nports
&& !checkport(&inpcb
))
lseek(kmem
, (off_t
)inpcb
.inp_socket
, L_SET
);
read(kmem
, &sockb
, sizeof (sockb
));
lseek(kmem
, (off_t
)inpcb
.inp_ppcb
, L_SET
);
read(kmem
, &tcpcb
, sizeof (tcpcb
));
enter(&inpcb
, &sockb
, tcpcb
.t_state
, "tcp");
enter(&inpcb
, &sockb
, 0, "udp");
if (istcp
&& (protos
&UDP
)) {
off
= nlst
[X_UDB
].n_value
;
enter(inp
, so
, state
, proto
)
register struct inpcb
*inp
;
register struct socket
*so
;
register struct netinfo
*p
;
* Only take exact matches, any sockets with
* previously unbound addresses will be deleted
* below in the display routine because they
* will appear as ``not seen'' in the kernel
for (p
= netcb
.ni_forw
; p
!= (struct netinfo
*)&netcb
; p
= p
->ni_forw
) {
if (!streq(proto
, p
->ni_proto
))
if (p
->ni_lport
!= inp
->inp_lport
||
p
->ni_laddr
.s_addr
!= inp
->inp_laddr
.s_addr
)
if (p
->ni_faddr
.s_addr
== inp
->inp_faddr
.s_addr
&&
p
->ni_fport
== inp
->inp_fport
)
if (p
== (struct netinfo
*)&netcb
) {
p
= (struct netinfo
*)malloc(sizeof (*p
));
p
->ni_laddr
= inp
->inp_laddr
;
p
->ni_lport
= inp
->inp_lport
;
p
->ni_faddr
= inp
->inp_faddr
;
p
->ni_fport
= inp
->inp_fport
;
p
->ni_flags
= NIF_LACHG
|NIF_FACHG
;
p
->ni_rcvcc
= so
->so_rcv
.sb_cc
;
p
->ni_sndcc
= so
->so_snd
.sb_cc
;
if (nlst
[X_TCB
].n_type
== 0)
wmove(wnd
, 0, 0); wclrtobot(wnd
);
mvwaddstr(wnd
, 0, LADDR
, "Local Address");
mvwaddstr(wnd
, 0, FADDR
, "Foreign Address");
mvwaddstr(wnd
, 0, PROTO
, "Proto");
mvwaddstr(wnd
, 0, RCVCC
, "Recv-Q");
mvwaddstr(wnd
, 0, SNDCC
, "Send-Q");
mvwaddstr(wnd
, 0, STATE
, "(state)");
register struct netinfo
*p
, *q
;
* First, delete any connections that have gone
* away and adjust the position of connections
* below to reflect the deleted line.
while (p
!= (struct netinfo
*)&netcb
) {
if (p
->ni_line
== -1 || p
->ni_seen
) {
wmove(wnd
, p
->ni_line
, 0); wdeleteln(wnd
);
for (; q
!= (struct netinfo
*)&netcb
; q
= q
->ni_forw
)
if (q
!= p
&& q
->ni_line
> p
->ni_line
) {
/* this shouldn't be necessary */
q
->ni_flags
|= NIF_LACHG
|NIF_FACHG
;
* Update existing connections and add new ones.
for (p
= netcb
.ni_forw
; p
!= (struct netinfo
*)&netcb
; p
= p
->ni_forw
) {
* Add a new entry if possible.
p
->ni_flags
|= NIF_LACHG
|NIF_FACHG
;
if (p
->ni_flags
& NIF_LACHG
) {
wmove(wnd
, p
->ni_line
, LADDR
);
inetprint(&p
->ni_laddr
, p
->ni_lport
, p
->ni_proto
);
p
->ni_flags
&= ~NIF_LACHG
;
if (p
->ni_flags
& NIF_FACHG
) {
wmove(wnd
, p
->ni_line
, FADDR
);
inetprint(&p
->ni_faddr
, p
->ni_fport
, p
->ni_proto
);
p
->ni_flags
&= ~NIF_FACHG
;
mvwaddstr(wnd
, p
->ni_line
, PROTO
, p
->ni_proto
);
mvwprintw(wnd
, p
->ni_line
, RCVCC
, "%6d", p
->ni_rcvcc
);
mvwprintw(wnd
, p
->ni_line
, SNDCC
, "%6d", p
->ni_sndcc
);
if (streq(p
->ni_proto
, "tcp"))
if (p
->ni_state
< 0 || p
->ni_state
>= TCP_NSTATES
)
mvwprintw(wnd
, p
->ni_line
, STATE
, "%d",
mvwaddstr(wnd
, p
->ni_line
, STATE
,
if (lastrow
< YMAX(wnd
)) {
wmove(wnd
, lastrow
, 0); wclrtobot(wnd
);
wmove(wnd
, YMAX(wnd
), 0); wdeleteln(wnd
); /* XXX */
* Pretty print an Internet address (net address + port).
* If the nflag was specified, use numbers instead of names.
inetprint(in
, port
, proto
)
register struct in_addr
*in
;
char line
[80], *cp
, *index();
sprintf(line
, "%.*s.", 16, inetname(*in
));
sp
= getservbyport(port
, proto
);
sprintf(cp
, "%.8s", sp
? sp
->s_name
: "*");
sprintf(cp
, "%d", ntohs((u_short
)port
));
/* pad to full column to clear any garbage */
* Construct an Internet address representation.
* If the nflag has been supplied, give
* numeric value, otherwise try for symbolic name.
if (!nflag
&& in
.s_addr
!= INADDR_ANY
) {
int net
= inet_netof(in
);
int lna
= inet_lnaof(in
);
np
= getnetbyaddr(net
, AF_INET
);
hp
= gethostbyaddr(&in
, sizeof (in
), AF_INET
);
if (in
.s_addr
== INADDR_ANY
)
in
.s_addr
= ntohl(in
.s_addr
);
#define C(x) ((x) & 0xff)
sprintf(line
, "%u.%u.%u.%u", C(in
.s_addr
>> 24),
C(in
.s_addr
>> 16), C(in
.s_addr
>> 8), C(in
.s_addr
));
register struct netinfo
*p
;
if (prefix(cmd
, "all")) {
if (prefix(cmd
, "numbers") || prefix(cmd
, "names")) {
new = prefix(cmd
, "numbers");
for (; p
!= (struct netinfo
*)&netcb
; p
= p
->ni_forw
) {
p
->ni_flags
|= NIF_LACHG
|NIF_FACHG
;