version 1.30, 2007/02/25 18:21:24 |
version 1.31, 2008/06/12 22:26:01 |
|
|
* SUCH DAMAGE. |
* SUCH DAMAGE. |
*/ |
*/ |
|
|
#ifndef lint |
|
#if 0 |
|
static char sccsid[] = "@(#)netstat.c 8.1 (Berkeley) 6/6/93"; |
|
#endif |
|
static char rcsid[] = "$OpenBSD$"; |
|
#endif /* not lint */ |
|
|
|
/* |
/* |
* netstat |
* netstat |
*/ |
*/ |
|
|
#include <nlist.h> |
#include <nlist.h> |
#include <paths.h> |
#include <paths.h> |
#include "systat.h" |
#include "systat.h" |
#include "extern.h" |
#include "engine.h" |
|
|
|
struct netinfo { |
|
union { |
|
struct in_addr nif_laddr; /* local address */ |
|
struct in6_addr nif_laddr6; /* local address */ |
|
} l; |
|
union { |
|
struct in_addr nif_faddr; /* foreign address */ |
|
struct in6_addr nif_faddr6; /* foreign address */ |
|
} f; |
|
char *nif_proto; /* protocol */ |
|
long nif_rcvcc; /* rcv buffer character count */ |
|
long nif_sndcc; /* snd buffer character count */ |
|
short nif_lport; /* local port */ |
|
short nif_fport; /* foreign port */ |
|
short nif_state; /* tcp state */ |
|
short nif_family; |
|
}; |
|
|
|
#define nif_laddr l.nif_laddr |
|
#define nif_laddr6 l.nif_laddr6 |
|
#define nif_faddr f.nif_faddr |
|
#define nif_faddr6 f.nif_faddr6 |
|
|
static void enter(struct inpcb *, struct socket *, int, char *); |
static void enter(struct inpcb *, struct socket *, int, char *); |
static const char *inetname(struct in_addr); |
static const char *inetname(struct in_addr); |
static void inetprint(struct in_addr *, int, char *); |
static void inetprint(struct in_addr *, int, char *, field_def *); |
static const char *inet6name(struct in6_addr *); |
static const char *inet6name(struct in6_addr *); |
static void inet6print(struct in6_addr *, int, char *); |
static void inet6print(struct in6_addr *, int, char *, field_def *); |
|
static void shownetstat(struct netinfo *p); |
|
|
|
void print_ns(void); |
|
int read_ns(void); |
|
int select_ns(void); |
|
int ns_keyboard_callback(int); |
|
|
#define streq(a,b) (strcmp(a,b)==0) |
#define streq(a,b) (strcmp(a,b)==0) |
#define YMAX(w) ((w)->_maxy-1) |
|
|
|
WINDOW * |
static int aflag = 0; |
opennetstat(void) |
|
{ |
|
sethostent(1); |
|
setnetent(1); |
|
return (subwin(stdscr, LINES-1-2, 0, 2, 0)); |
|
} |
|
|
|
struct netinfo { |
static struct nlist namelist[] = { |
struct netinfo *nif_forw, *nif_prev; |
#define X_TCBTABLE 0 /* no sysctl */ |
int nif_family; |
{ "_tcbtable" }, |
short nif_line; /* line on screen */ |
#define X_UDBTABLE 1 /* no sysctl */ |
short nif_seen; /* 0 when not present in list */ |
{ "_udbtable" }, |
short nif_flags; |
{ "" }, |
#define NIF_LACHG 0x1 /* local address changed */ |
|
#define NIF_FACHG 0x2 /* foreign address changed */ |
|
short nif_state; /* tcp state */ |
|
char *nif_proto; /* protocol */ |
|
struct in_addr nif_laddr; /* local address */ |
|
struct in6_addr nif_laddr6; /* local address */ |
|
long nif_lport; /* local port */ |
|
struct in_addr nif_faddr; /* foreign address */ |
|
struct in6_addr nif_faddr6; /* foreign address */ |
|
long nif_fport; /* foreign port */ |
|
long nif_rcvcc; /* rcv buffer character count */ |
|
long nif_sndcc; /* snd buffer character count */ |
|
}; |
}; |
|
#define ADD_ALLOC 1000 |
|
|
static struct { |
|
struct netinfo *nif_forw, *nif_prev; |
|
} netcb; |
|
|
|
static int aflag = 0; |
int protos; |
static int lastrow = 1; |
|
|
|
void |
struct netinfo *netinfos = NULL; |
closenetstat(WINDOW *w) |
size_t num_ns = 0; |
|
static size_t num_alloc = 0; |
|
|
|
|
|
field_def fields_ns[] = { |
|
{"LOCAL ADDRESS", 20, 45, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0}, |
|
{"FOREIGN ADDRESS", 20, 45, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0}, |
|
{"PROTO", 4, 9, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0}, |
|
{"RECV-Q", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, |
|
{"SEND-Q", 5, 8, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0}, |
|
{"STATE", 5, 11, 6, FLD_ALIGN_LEFT, -1, 0, 0, 0}, |
|
}; |
|
|
|
#define FIELD_ADDR(x) (&fields_ns[x]) |
|
|
|
#define FLD_NS_LOCAL FIELD_ADDR(0) |
|
#define FLD_NS_FOREIGN FIELD_ADDR(1) |
|
#define FLD_NS_PROTO FIELD_ADDR(2) |
|
#define FLD_NS_RECV_Q FIELD_ADDR(3) |
|
#define FLD_NS_SEND_Q FIELD_ADDR(4) |
|
#define FLD_NS_STATE FIELD_ADDR(5) |
|
|
|
/* Define views */ |
|
field_def *view_ns_0[] = { |
|
FLD_NS_LOCAL, FLD_NS_FOREIGN, FLD_NS_PROTO, |
|
FLD_NS_RECV_Q, FLD_NS_SEND_Q, FLD_NS_STATE, NULL |
|
}; |
|
|
|
/* Define view managers */ |
|
struct view_manager netstat_mgr = { |
|
"Netstat", select_ns, read_ns, NULL, print_header, |
|
print_ns, ns_keyboard_callback, NULL, NULL |
|
}; |
|
|
|
field_view views_ns[] = { |
|
{view_ns_0, "netstat", '0', &netstat_mgr}, |
|
{NULL, NULL, 0, NULL} |
|
}; |
|
|
|
|
|
|
|
|
|
struct netinfo * |
|
next_ns(void) |
{ |
{ |
|
if (num_alloc <= num_ns) { |
|
struct netinfo *ni; |
|
size_t a = num_alloc + ADD_ALLOC; |
|
if (a < num_alloc) |
|
return NULL; |
|
ni = realloc(netinfos, a * sizeof(*ni)); |
|
if (ni == NULL) |
|
return NULL; |
|
netinfos = ni; |
|
num_alloc = a; |
|
} |
|
|
|
return &netinfos[num_ns++]; |
|
} |
|
|
|
static void |
|
enter(struct inpcb *inp, struct socket *so, int state, char *proto) |
|
{ |
struct netinfo *p; |
struct netinfo *p; |
|
|
endhostent(); |
p = next_ns(); |
endnetent(); |
if (p == NULL) { |
p = (struct netinfo *)netcb.nif_forw; |
error("Out of Memory!"); |
while (p != (struct netinfo *)&netcb) { |
return; |
if (p->nif_line != -1) |
|
lastrow--; |
|
p->nif_line = -1; |
|
p = p->nif_forw; |
|
} |
} |
if (w != NULL) { |
|
wclear(w); |
p->nif_lport = inp->inp_lport; |
wrefresh(w); |
p->nif_fport = inp->inp_fport; |
delwin(w); |
p->nif_proto = proto; |
|
|
|
if (inp->inp_flags & INP_IPV6) { |
|
p->nif_laddr6 = inp->inp_laddr6; |
|
p->nif_faddr6 = inp->inp_faddr6; |
|
p->nif_family = AF_INET6; |
|
} else { |
|
p->nif_laddr = inp->inp_laddr; |
|
p->nif_faddr = inp->inp_faddr; |
|
p->nif_family = AF_INET; |
} |
} |
|
|
|
p->nif_rcvcc = so->so_rcv.sb_cc; |
|
p->nif_sndcc = so->so_snd.sb_cc; |
|
p->nif_state = state; |
} |
} |
|
|
static struct nlist namelist[] = { |
|
#define X_TCBTABLE 0 /* no sysctl */ |
|
{ "_tcbtable" }, |
|
#define X_UDBTABLE 1 /* no sysctl */ |
|
{ "_udbtable" }, |
|
{ "" }, |
|
}; |
|
|
|
|
/* netstat callback functions */ |
|
|
int |
int |
initnetstat(void) |
select_ns(void) |
{ |
{ |
int ret; |
static int init = 0; |
|
if (kd == NULL) { |
|
num_disp = 1; |
|
return (0); |
|
} |
|
|
if ((ret = kvm_nlist(kd, namelist)) == -1) |
if (!init) { |
errx(1, "%s", kvm_geterr(kd)); |
sethostent(1); |
else if (ret) |
setnetent(1); |
nlisterr(namelist); |
init = 1; |
if (namelist[X_TCBTABLE].n_value == 0) { |
|
error("No symbols in namelist"); |
|
return(0); |
|
} |
} |
netcb.nif_forw = netcb.nif_prev = (struct netinfo *)&netcb; |
|
protos = TCP|UDP; |
num_disp = num_ns; |
return(1); |
return (0); |
} |
} |
|
|
void |
int |
fetchnetstat(void) |
read_ns(void) |
{ |
{ |
struct inpcbtable pcbtable; |
struct inpcbtable pcbtable; |
struct inpcb *head, *prev, *next; |
struct inpcb *head, *prev, *next; |
struct netinfo *p; |
|
struct inpcb inpcb; |
struct inpcb inpcb; |
struct socket sockb; |
struct socket sockb; |
struct tcpcb tcpcb; |
struct tcpcb tcpcb; |
void *off; |
void *off; |
int istcp; |
int istcp; |
|
|
|
if (kd == NULL) { |
|
return (0); |
|
} |
|
|
|
num_ns = 0; |
|
|
if (namelist[X_TCBTABLE].n_value == 0) |
if (namelist[X_TCBTABLE].n_value == 0) |
return; |
return 0; |
for (p = netcb.nif_forw; p != (struct netinfo *)&netcb; p = p->nif_forw) |
|
p->nif_seen = 0; |
if (protos & TCP) { |
if (protos&TCP) { |
|
off = NPTR(X_TCBTABLE); |
off = NPTR(X_TCBTABLE); |
istcp = 1; |
istcp = 1; |
} else if (protos&UDP) { |
} else if (protos & UDP) { |
off = NPTR(X_UDBTABLE); |
off = NPTR(X_UDBTABLE); |
istcp = 0; |
istcp = 0; |
} else { |
} else { |
error("No protocols to display"); |
error("No protocols to display"); |
return; |
return 0; |
} |
} |
|
|
again: |
again: |
KREAD(off, &pcbtable, sizeof (struct inpcbtable)); |
KREAD(off, &pcbtable, sizeof (struct inpcbtable)); |
|
|
prev = head = (struct inpcb *)&((struct inpcbtable *)off)->inpt_queue; |
prev = head = (struct inpcb *)&((struct inpcbtable *)off)->inpt_queue; |
next = CIRCLEQ_FIRST(&pcbtable.inpt_queue); |
next = CIRCLEQ_FIRST(&pcbtable.inpt_queue); |
|
|
while (next != head) { |
while (next != head) { |
KREAD(next, &inpcb, sizeof (inpcb)); |
KREAD(next, &inpcb, sizeof (inpcb)); |
if (CIRCLEQ_PREV(&inpcb, inp_queue) != prev) { |
if (CIRCLEQ_PREV(&inpcb, inp_queue) != prev) { |
printf("prev = %p, head = %p, next = %p, inpcb...prev = %p\n", |
|
prev, head, next, CIRCLEQ_PREV(&inpcb, inp_queue)); |
|
p = netcb.nif_forw; |
|
for (; p != (struct netinfo *)&netcb; p = p->nif_forw) |
|
p->nif_seen = 1; |
|
error("Kernel state in transition"); |
error("Kernel state in transition"); |
return; |
return 0; |
} |
} |
prev = next; |
prev = next; |
next = CIRCLEQ_NEXT(&inpcb, inp_queue); |
next = CIRCLEQ_NEXT(&inpcb, inp_queue); |
|
|
IN6_IS_ADDR_UNSPECIFIED(&inpcb.inp_laddr6)) |
IN6_IS_ADDR_UNSPECIFIED(&inpcb.inp_laddr6)) |
continue; |
continue; |
} |
} |
if (nhosts && !checkhost(&inpcb)) |
|
continue; |
|
if (nports && !checkport(&inpcb)) |
|
continue; |
|
KREAD(inpcb.inp_socket, &sockb, sizeof (sockb)); |
KREAD(inpcb.inp_socket, &sockb, sizeof (sockb)); |
if (istcp) { |
if (istcp) { |
KREAD(inpcb.inp_ppcb, &tcpcb, sizeof (tcpcb)); |
KREAD(inpcb.inp_ppcb, &tcpcb, sizeof (tcpcb)); |
|
|
} else |
} else |
enter(&inpcb, &sockb, 0, "udp"); |
enter(&inpcb, &sockb, 0, "udp"); |
} |
} |
if (istcp && (protos&UDP)) { |
if (istcp && (protos & UDP)) { |
istcp = 0; |
istcp = 0; |
off = NPTR(X_UDBTABLE); |
off = NPTR(X_UDBTABLE); |
goto again; |
goto again; |
} |
} |
|
|
|
num_disp = num_ns; |
|
return 0; |
} |
} |
|
|
static void |
void |
enter(struct inpcb *inp, struct socket *so, int state, char *proto) |
print_ns(void) |
{ |
{ |
struct netinfo *p; |
int n, count = 0; |
|
|
/* |
if (kd == NULL) { |
* Only take exact matches, any sockets with |
print_fld_str(FLD_NS_LOCAL, "Failed to initialize KVM!"); |
* previously unbound addresses will be deleted |
print_fld_str(FLD_NS_FOREIGN, "Failed to initialize KVM!"); |
* below in the display routine because they |
end_line(); |
* will appear as ``not seen'' in the kernel |
return; |
* data structures. |
} |
*/ |
|
for (p = netcb.nif_forw; p != (struct netinfo *)&netcb; p = p->nif_forw) { |
|
if (p->nif_family == AF_INET && (inp->inp_flags & INP_IPV6)) |
|
continue; |
|
if (p->nif_family == AF_INET6 && !(inp->inp_flags & INP_IPV6)) |
|
continue; |
|
if (!streq(proto, p->nif_proto)) |
|
continue; |
|
if (p->nif_family == AF_INET) { |
|
if (p->nif_lport != inp->inp_lport || |
|
p->nif_laddr.s_addr != inp->inp_laddr.s_addr) |
|
continue; |
|
if (p->nif_faddr.s_addr == inp->inp_faddr.s_addr && |
|
p->nif_fport == inp->inp_fport) |
|
break; |
|
|
|
} else if (p->nif_family == AF_INET6) { |
for (n = dispstart; n < num_disp; n++) { |
if (p->nif_lport != inp->inp_lport || |
shownetstat(netinfos + n); |
!IN6_ARE_ADDR_EQUAL(&p->nif_laddr6, &inp->inp_laddr6)) |
count++; |
continue; |
if (maxprint > 0 && count >= maxprint) |
if (IN6_ARE_ADDR_EQUAL(&p->nif_faddr6, &inp->inp_faddr6) && |
break; |
p->nif_fport == inp->inp_fport) |
|
break; |
|
} else |
|
continue; |
|
} |
} |
if (p == (struct netinfo *)&netcb) { |
|
if ((p = malloc(sizeof(*p))) == NULL) { |
|
error("Out of memory"); |
|
return; |
|
} |
|
p->nif_prev = (struct netinfo *)&netcb; |
|
p->nif_forw = netcb.nif_forw; |
|
netcb.nif_forw->nif_prev = p; |
|
netcb.nif_forw = p; |
|
p->nif_line = -1; |
|
p->nif_lport = inp->inp_lport; |
|
p->nif_fport = inp->inp_fport; |
|
p->nif_proto = proto; |
|
p->nif_flags = NIF_LACHG|NIF_FACHG; |
|
if (inp->inp_flags & INP_IPV6) { |
|
p->nif_laddr6 = inp->inp_laddr6; |
|
p->nif_faddr6 = inp->inp_faddr6; |
|
p->nif_family = AF_INET6; |
|
} else { |
|
p->nif_laddr = inp->inp_laddr; |
|
p->nif_faddr = inp->inp_faddr; |
|
p->nif_family = AF_INET; |
|
} |
|
} |
|
p->nif_rcvcc = so->so_rcv.sb_cc; |
|
p->nif_sndcc = so->so_snd.sb_cc; |
|
p->nif_state = state; |
|
p->nif_seen = 1; |
|
} |
} |
|
|
/* column locations */ |
|
#define LADDR 0 |
|
#define FADDR LADDR+23 |
|
#define PROTO FADDR+23 |
|
#define RCVCC PROTO+6 |
|
#define SNDCC RCVCC+7 |
|
#define STATE SNDCC+7 |
|
|
|
|
int |
void |
initnetstat(void) |
labelnetstat(void) |
|
{ |
{ |
if (namelist[X_TCBTABLE].n_type == 0) |
field_view *v; |
return; |
int ret; |
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)"); |
|
} |
|
|
|
void |
if (kd) { |
shownetstat(void) |
if ((ret = kvm_nlist(kd, namelist)) == -1) |
{ |
errx(1, "%s", kvm_geterr(kd)); |
struct netinfo *p, *q; |
else if (ret) |
|
nlisterr(namelist); |
|
|
/* |
if (namelist[X_TCBTABLE].n_value == 0) { |
* First, delete any connections that have gone |
error("No symbols in namelist"); |
* away and adjust the position of connections |
return(0); |
* below to reflect the deleted line. |
|
*/ |
|
p = netcb.nif_forw; |
|
while (p != (struct netinfo *)&netcb) { |
|
if (p->nif_line == -1 || p->nif_seen) { |
|
p = p->nif_forw; |
|
continue; |
|
} |
} |
wmove(wnd, p->nif_line, 0); |
|
wdeleteln(wnd); |
|
q = netcb.nif_forw; |
|
for (; q != (struct netinfo *)&netcb; q = q->nif_forw) |
|
if (q != p && q->nif_line > p->nif_line) { |
|
q->nif_line--; |
|
/* this shouldn't be necessary */ |
|
q->nif_flags |= NIF_LACHG|NIF_FACHG; |
|
} |
|
lastrow--; |
|
q = p->nif_forw; |
|
p->nif_prev->nif_forw = p->nif_forw; |
|
p->nif_forw->nif_prev = p->nif_prev; |
|
free(p); |
|
p = q; |
|
} |
} |
/* |
protos = TCP|UDP; |
* Update existing connections and add new ones. |
|
*/ |
for (v = views_ns; v->name != NULL; v++) |
for (p = netcb.nif_forw; p != (struct netinfo *)&netcb; p = p->nif_forw) { |
add_view(v); |
if (p->nif_line == -1) { |
|
/* |
return(1); |
* Add a new entry if possible. |
} |
*/ |
|
if (lastrow > YMAX(wnd)) |
static void |
continue; |
shownetstat(struct netinfo *p) |
p->nif_line = lastrow++; |
{ |
p->nif_flags |= NIF_LACHG|NIF_FACHG; |
switch (p->nif_family) { |
} |
case AF_INET: |
if (p->nif_flags & NIF_LACHG) { |
inetprint(&p->nif_laddr, p->nif_lport, |
wmove(wnd, p->nif_line, LADDR); |
p->nif_proto, FLD_NS_LOCAL); |
switch (p->nif_family) { |
inetprint(&p->nif_faddr, p->nif_fport, |
case AF_INET: |
p->nif_proto, FLD_NS_FOREIGN); |
inetprint(&p->nif_laddr, p->nif_lport, |
break; |
p->nif_proto); |
case AF_INET6: |
break; |
inet6print(&p->nif_laddr6, p->nif_lport, |
case AF_INET6: |
p->nif_proto, FLD_NS_LOCAL); |
inet6print(&p->nif_laddr6, p->nif_lport, |
inet6print(&p->nif_faddr6, p->nif_fport, |
p->nif_proto); |
p->nif_proto, FLD_NS_FOREIGN); |
break; |
break; |
} |
|
p->nif_flags &= ~NIF_LACHG; |
|
} |
|
if (p->nif_flags & NIF_FACHG) { |
|
wmove(wnd, p->nif_line, FADDR); |
|
switch (p->nif_family) { |
|
case AF_INET: |
|
inetprint(&p->nif_faddr, p->nif_fport, |
|
p->nif_proto); |
|
break; |
|
case AF_INET6: |
|
inet6print(&p->nif_faddr6, p->nif_fport, |
|
p->nif_proto); |
|
break; |
|
} |
|
p->nif_flags &= ~NIF_FACHG; |
|
} |
|
mvwaddstr(wnd, p->nif_line, PROTO, p->nif_proto); |
|
if (p->nif_family == AF_INET6) |
|
waddstr(wnd, "6"); |
|
mvwprintw(wnd, p->nif_line, RCVCC, "%6d", p->nif_rcvcc); |
|
mvwprintw(wnd, p->nif_line, SNDCC, "%6d", p->nif_sndcc); |
|
if (streq(p->nif_proto, "tcp")) { |
|
if (p->nif_state < 0 || p->nif_state >= TCP_NSTATES) |
|
mvwprintw(wnd, p->nif_line, STATE, "%d", |
|
p->nif_state); |
|
else |
|
mvwaddstr(wnd, p->nif_line, STATE, |
|
tcpstates[p->nif_state]); |
|
} |
|
wclrtoeol(wnd); |
|
} |
} |
if (lastrow < YMAX(wnd)) { |
|
wmove(wnd, lastrow, 0); |
tb_start(); |
wclrtobot(wnd); |
tbprintf("%s", p->nif_proto); |
wmove(wnd, YMAX(wnd), 0); |
if (p->nif_family == AF_INET6) |
wdeleteln(wnd); /* XXX */ |
tbprintf("6"); |
|
|
|
print_fld_tb(FLD_NS_PROTO); |
|
|
|
print_fld_size(FLD_NS_RECV_Q, p->nif_rcvcc); |
|
print_fld_size(FLD_NS_SEND_Q, p->nif_sndcc); |
|
|
|
if (streq(p->nif_proto, "tcp")) { |
|
if (p->nif_state < 0 || p->nif_state >= TCP_NSTATES) |
|
print_fld_uint(FLD_NS_STATE, p->nif_state); |
|
else |
|
print_fld_str(FLD_NS_STATE, tcpstates[p->nif_state]); |
} |
} |
|
end_line(); |
} |
} |
|
|
/* |
/* |
|
|
* If the nflag was specified, use numbers instead of names. |
* If the nflag was specified, use numbers instead of names. |
*/ |
*/ |
static void |
static void |
inetprint(struct in_addr *in, int port, char *proto) |
inetprint(struct in_addr *in, int port, char *proto, field_def *fld) |
{ |
{ |
struct servent *sp = 0; |
struct servent *sp = 0; |
char line[80], *cp; |
|
|
|
snprintf(line, sizeof line, "%.*s.", 16, inetname(*in)); |
tb_start(); |
cp = strchr(line, '\0'); |
tbprintf("%s", inetname(*in)); |
|
|
if (!nflag && port) |
if (!nflag && port) |
sp = getservbyport(port, proto); |
sp = getservbyport(port, proto); |
if (sp || port == 0) |
if (sp || port == 0) |
snprintf(cp, sizeof line - strlen(cp), "%.8s", |
tbprintf(":%s", sp ? sp->s_name : "*"); |
sp ? sp->s_name : "*"); |
|
else |
else |
snprintf(cp, sizeof line - strlen(cp), "%d", |
tbprintf(":%d", ntohs((u_short)port)); |
ntohs((u_short)port)); |
|
/* pad to full column to clear any garbage */ |
print_fld_tb(fld); |
cp = strchr(line, '\0'); |
|
while (cp - line < 22 && cp - line < sizeof line-1) |
|
*cp++ = ' '; |
|
*cp = '\0'; |
|
waddstr(wnd, line); |
|
} |
} |
|
|
static void |
static void |
inet6print(struct in6_addr *in6, int port, char *proto) |
inet6print(struct in6_addr *in6, int port, char *proto, field_def *fld) |
{ |
{ |
struct servent *sp = 0; |
struct servent *sp = 0; |
char line[80], *cp; |
|
|
|
snprintf(line, sizeof line, "%.*s.", 16, inet6name(in6)); |
tb_start(); |
cp = strchr(line, '\0'); |
|
|
tbprintf("%s", inet6name(in6)); |
if (!nflag && port) |
if (!nflag && port) |
sp = getservbyport(port, proto); |
sp = getservbyport(port, proto); |
if (sp || port == 0) |
if (sp || port == 0) |
snprintf(cp, sizeof line - strlen(cp), "%.8s", |
tbprintf(":%s", sp ? sp->s_name : "*"); |
sp ? sp->s_name : "*"); |
|
else |
else |
snprintf(cp, sizeof line - strlen(cp), "%d", |
tbprintf(":%d", ntohs((u_short)port)); |
ntohs((u_short)port)); |
|
/* pad to full column to clear any garbage */ |
|
cp = strchr(line, '\0'); |
|
while (cp - line < 22 && cp - line < sizeof line-1) |
|
*cp++ = ' '; |
|
*cp = '\0'; |
|
waddstr(wnd, line); |
|
} |
|
|
|
/* |
print_fld_tb(fld); |
* Construct an Internet address representation. |
|
* If the nflag has been supplied, give |
|
* numeric value, otherwise try for symbolic name. |
|
*/ |
|
static const char * |
|
inetname(struct in_addr in) |
|
{ |
|
char *cp = 0; |
|
static char line[50]; |
|
struct hostent *hp; |
|
struct netent *np; |
|
|
|
if (!nflag && in.s_addr != INADDR_ANY) { |
|
int net = inet_netof(in); |
|
int lna = inet_lnaof(in); |
|
|
|
if (lna == INADDR_ANY) { |
|
np = getnetbyaddr(net, AF_INET); |
|
if (np) |
|
cp = np->n_name; |
|
} |
|
if (cp == 0) { |
|
hp = gethostbyaddr(&in, sizeof (in), AF_INET); |
|
if (hp) |
|
cp = hp->h_name; |
|
} |
|
} |
|
if (in.s_addr == INADDR_ANY) { |
|
strlcpy(line, "*", sizeof line); |
|
} else if (cp) { |
|
strlcpy(line, cp, sizeof line); |
|
} else { |
|
in.s_addr = ntohl(in.s_addr); |
|
#define C(x) ((x) & 0xff) |
|
snprintf(line, sizeof line, "%u.%u.%u.%u", C(in.s_addr >> 24), |
|
C(in.s_addr >> 16), C(in.s_addr >> 8), C(in.s_addr)); |
|
} |
|
return (line); |
|
} |
} |
|
|
static const char * |
static const char * |
|
|
return "?"; |
return "?"; |
} |
} |
|
|
int |
static const char * |
cmdnetstat(char *cmd, char *args) |
inetname(struct in_addr in) |
{ |
{ |
struct netinfo *p; |
static char line[NI_MAXHOST]; |
|
struct sockaddr_in sin; |
|
int flags, e; |
|
|
if (prefix(cmd, "all")) { |
flags = nflag ? NI_NUMERICHOST : 0; |
aflag = !aflag; |
if (in.s_addr == INADDR_ANY) |
goto fixup; |
return "*"; |
} |
|
if (prefix(cmd, "numbers") || prefix(cmd, "names")) { |
|
int new; |
|
|
|
new = prefix(cmd, "numbers"); |
memset(&sin, 0, sizeof(sin)); |
if (new == nflag) |
sin.sin_family = AF_INET; |
return (1); |
sin.sin_len = sizeof(struct sockaddr_in); |
p = netcb.nif_forw; |
sin.sin_addr = in; |
for (; p != (struct netinfo *)&netcb; p = p->nif_forw) { |
|
if (p->nif_line == -1) |
e = getnameinfo((struct sockaddr *)&sin, sin.sin_len, |
continue; |
line, sizeof(line), NULL, 0, flags); |
p->nif_flags |= NIF_LACHG|NIF_FACHG; |
|
} |
if (e == 0) |
nflag = new; |
return line; |
wclear(wnd); |
|
labelnetstat(); |
error("Lookup: %s", gai_strerror(e)); |
goto redisplay; |
|
} |
return "?"; |
if (!netcmd(cmd, args)) |
} |
|
|
|
int |
|
kvm_ckread(void *a, void *b, size_t l) |
|
{ |
|
if (kvm_read(kd, (u_long)a, b, l) != l) { |
|
if (verbose) |
|
error("error reading kmem at %x\n", a); |
return (0); |
return (0); |
fixup: |
} else |
fetchnetstat(); |
return (1); |
redisplay: |
|
shownetstat(); |
|
refresh(); |
|
return (1); |
|
} |
} |
|
|
|
|
|
int |
|
ns_keyboard_callback(int ch) |
|
{ |
|
switch (ch) { |
|
case 'n': |
|
nflag = !nflag; |
|
gotsig_alarm = 1; |
|
break; |
|
case 't': |
|
protos ^= TCP; |
|
gotsig_alarm = 1; |
|
break; |
|
case 'u': |
|
protos ^= UDP; |
|
gotsig_alarm = 1; |
|
break; |
|
default: |
|
return keyboard_callback(ch); |
|
}; |
|
|
|
return 1; |
|
} |
|
|