diff options
| author | itojun <itojun@NetBSD.org> | 2000-01-05 11:59:12 +0000 |
|---|---|---|
| committer | itojun <itojun@NetBSD.org> | 2000-01-05 11:59:12 +0000 |
| commit | 7b5dfc58ad9d917cf2b81caecadffa94de932a4d (patch) | |
| tree | 2555957cd875d91291758fa3ce50ca3893da20b6 /usr.bin | |
| parent | 88ac9b1712cb2fa4ba43fd3479760247da0f014e (diff) | |
support IPv6. commands under "netstat" are IPv6 ready.
IPv6 is supported by filters (":ignore ssh") as well.
TODO: do something about line truncation?
TODO: inet6.icmp6? ":help" will not fit into single line...
Diffstat (limited to 'usr.bin')
| -rw-r--r-- | usr.bin/systat/Makefile | 4 | ||||
| -rw-r--r-- | usr.bin/systat/extern.h | 9 | ||||
| -rw-r--r-- | usr.bin/systat/netcmds.c | 139 | ||||
| -rw-r--r-- | usr.bin/systat/netstat.c | 226 |
4 files changed, 345 insertions, 33 deletions
diff --git a/usr.bin/systat/Makefile b/usr.bin/systat/Makefile index a9346d4a364..37115c62ca4 100644 --- a/usr.bin/systat/Makefile +++ b/usr.bin/systat/Makefile @@ -1,4 +1,4 @@ -# $NetBSD: Makefile,v 1.20 1999/12/16 04:02:22 jwise Exp $ +# $NetBSD: Makefile,v 1.21 2000/01/05 11:59:12 itojun Exp $ # @(#)Makefile 8.1 (Berkeley) 6/6/93 PROG= systat @@ -17,4 +17,6 @@ BINMODE=2555 LINKS= ${BINDIR}/systat ${BINDIR}/sysstat MLINKS+=systat.1 sysstat.1 +CPPFLAGS+=-DINET6 + .include <bsd.prog.mk> diff --git a/usr.bin/systat/extern.h b/usr.bin/systat/extern.h index e699499f73b..2325dd0e71d 100644 --- a/usr.bin/systat/extern.h +++ b/usr.bin/systat/extern.h @@ -1,4 +1,4 @@ -/* $NetBSD: extern.h,v 1.18 1999/12/25 01:49:25 jwise Exp $ */ +/* $NetBSD: extern.h,v 1.19 2000/01/05 11:59:12 itojun Exp $ */ /*- * Copyright (c) 1991, 1993 @@ -61,9 +61,16 @@ extern int protos; extern int verbose; struct inpcb; +#ifdef INET6 +struct in6pcb; +#endif int checkhost __P((struct inpcb *)); int checkport __P((struct inpcb *)); +#ifdef INET6 +int checkhost6 __P((struct in6pcb *)); +int checkport6 __P((struct in6pcb *)); +#endif void closebufcache __P((WINDOW *)); void closeicmp __P ((WINDOW *)); void closeiostat __P((WINDOW *)); diff --git a/usr.bin/systat/netcmds.c b/usr.bin/systat/netcmds.c index e90dbf05e03..b7e7d9bb36b 100644 --- a/usr.bin/systat/netcmds.c +++ b/usr.bin/systat/netcmds.c @@ -1,4 +1,4 @@ -/* $NetBSD: netcmds.c,v 1.13 2000/01/05 11:48:21 itojun Exp $ */ +/* $NetBSD: netcmds.c,v 1.14 2000/01/05 11:59:12 itojun Exp $ */ /*- * Copyright (c) 1980, 1992, 1993 @@ -38,7 +38,7 @@ #if 0 static char sccsid[] = "@(#)netcmds.c 8.1 (Berkeley) 6/6/93"; #endif -__RCSID("$NetBSD: netcmds.c,v 1.13 2000/01/05 11:48:21 itojun Exp $"); +__RCSID("$NetBSD: netcmds.c,v 1.14 2000/01/05 11:59:12 itojun Exp $"); #endif /* not lint */ /* @@ -54,6 +54,10 @@ __RCSID("$NetBSD: netcmds.c,v 1.13 2000/01/05 11:48:21 itojun Exp $"); #include <netinet/in_systm.h> #include <netinet/ip.h> #include <netinet/in_pcb.h> +#ifdef INET6 +#include <netinet/ip6.h> +#include <netinet6/in6_pcb.h> +#endif #include <arpa/inet.h> @@ -67,7 +71,7 @@ __RCSID("$NetBSD: netcmds.c,v 1.13 2000/01/05 11:48:21 itojun Exp $"); #define streq(a,b) (strcmp(a,b)==0) static struct hitem { - struct in_addr addr; + struct sockaddr_storage addr; int onoff; } *hosts = NULL; @@ -78,7 +82,8 @@ static void selectproto __P((char *)); static void showprotos __P((void)); static int selectport __P((long, int)); static void showports __P((void)); -static int selecthost __P((struct in_addr *, int)); +static int addrcmp __P((struct sockaddr *, struct sockaddr *)); +static int selecthost __P((struct sockaddr *, int)); static void showhosts __P((void)); /* please note: there are also some netstat commands in netstat.c */ @@ -148,8 +153,7 @@ changeitems(args, onoff) { char *cp; struct servent *sp; - struct hostent *hp; - struct in_addr in; + struct addrinfo hints, *res, *res0; cp = strchr(args, '\n'); if (cp) @@ -170,15 +174,17 @@ changeitems(args, onoff) selectport(sp->s_port, onoff); continue; } - if (inet_aton(args, &in) == 0) { - hp = gethostbyname(args); - if (hp == 0) { - error("%s: unknown host or port", args); - continue; - } - memcpy(&in, hp->h_addr, hp->h_length); + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + if (getaddrinfo(args, "0", &hints, &res0) != 0) { + error("%s: unknown host or port", args); + continue; } - selecthost(&in, onoff); + for (res = res0; res; res = res->ai_next) + selecthost(res->ai_addr, onoff); + freeaddrinfo(res0); } } @@ -257,6 +263,21 @@ checkport(inp) return (1); } +#ifdef INET6 +int +checkport6(in6p) + struct in6pcb *in6p; +{ + struct pitem *p; + + if (ports) + for (p = ports; p < ports+nports; p++) + if (p->port == in6p->in6p_lport || p->port == in6p->in6p_fport) + return (p->onoff); + return (1); +} +#endif + static void showports() { @@ -276,13 +297,43 @@ showports() } static int -selecthost(in, onoff) - struct in_addr *in; +addrcmp(sa1, sa2) + struct sockaddr *sa1; + struct sockaddr *sa2; +{ + if (sa1->sa_family != sa2->sa_family) + return 0; + if (sa1->sa_len != sa2->sa_len) + return 0; + switch (sa1->sa_family) { + case AF_INET: + if (((struct sockaddr_in *)sa1)->sin_addr.s_addr == + ((struct sockaddr_in *)sa2)->sin_addr.s_addr) + return 1; + break; +#ifdef INET6 + case AF_INET6: + if (IN6_ARE_ADDR_EQUAL(&((struct sockaddr_in6 *)sa1)->sin6_addr, + &((struct sockaddr_in6 *)sa2)->sin6_addr)) + return 1; + break; +#endif + default: + if (memcmp(sa1, sa2, sa1->sa_len) == 0) + return 1; + break; + } + return 0; +} + +static int +selecthost(sa, onoff) + struct sockaddr *sa; int onoff; { struct hitem *p; - if (in == 0) { + if (sa == 0) { if (hosts == 0) return (0); free((char *)hosts), hosts = 0; @@ -290,10 +341,12 @@ selecthost(in, onoff) return (1); } for (p = hosts; p < hosts+nhosts; p++) - if (p->addr.s_addr == in->s_addr) { + if (addrcmp((struct sockaddr *)&p->addr, sa)) { p->onoff = onoff; return (0); } + if (sa->sa_len > sizeof(struct sockaddr_storage)) + return (-1); /*XXX*/ p = (struct hitem *)realloc(hosts, (nhosts+1)*sizeof (*p)); if (p == NULL) { error("malloc failed"); @@ -301,7 +354,7 @@ selecthost(in, onoff) } hosts = p; p = &hosts[nhosts++]; - p->addr = *in; + memcpy(&p->addr, sa, sa->sa_len); p->onoff = onoff; return (1); } @@ -311,25 +364,61 @@ checkhost(inp) struct inpcb *inp; { struct hitem *p; + struct sockaddr_in *sin; + + if (hosts) + for (p = hosts; p < hosts+nhosts; p++) { + if (((struct sockaddr *)&p->addr)->sa_family != AF_INET) + continue; + sin = (struct sockaddr_in *)&p->addr; + if (sin->sin_addr.s_addr == inp->inp_laddr.s_addr || + sin->sin_addr.s_addr == inp->inp_faddr.s_addr) + return (p->onoff); + } + return (1); +} + +#ifdef INET6 +int +checkhost6(in6p) + struct in6pcb *in6p; +{ + struct hitem *p; + struct sockaddr_in6 *sin6; if (hosts) - for (p = hosts; p < hosts+nhosts; p++) - if (p->addr.s_addr == inp->inp_laddr.s_addr || - p->addr.s_addr == inp->inp_faddr.s_addr) + for (p = hosts; p < hosts+nhosts; p++) { + if (((struct sockaddr *)&p->addr)->sa_family != AF_INET6) + continue; + sin6 = (struct sockaddr_in6 *)&p->addr; + if (IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, &in6p->in6p_laddr) || + IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, &in6p->in6p_faddr)) return (p->onoff); + } return (1); } +#endif static void showhosts() { struct hitem *p; - struct hostent *hp; + char hbuf[NI_MAXHOST]; + struct sockaddr *sa; + int flags; +#if 0 + flags = nflag ? NI_NUMERICHOST : 0; +#else + flags = 0; +#endif for (p = hosts; p < hosts+nhosts; p++) { - hp = gethostbyaddr((char *)&p->addr, sizeof (p->addr), AF_INET); + sa = (struct sockaddr *)&p->addr; + if (getnameinfo(sa, sa->sa_len, hbuf, sizeof(hbuf), NULL, 0, + flags) != 0) + strcpy(hbuf, "(invalid)"); if (!p->onoff) addch('!'); - printw("%s ", hp ? hp->h_name : inet_ntoa(p->addr)); + printw("%s ", hbuf); } } diff --git a/usr.bin/systat/netstat.c b/usr.bin/systat/netstat.c index cd40e962ee0..215dd26887c 100644 --- a/usr.bin/systat/netstat.c +++ b/usr.bin/systat/netstat.c @@ -1,4 +1,4 @@ -/* $NetBSD: netstat.c,v 1.14 2000/01/05 11:50:21 itojun Exp $ */ +/* $NetBSD: netstat.c,v 1.15 2000/01/05 11:59:12 itojun Exp $ */ /*- * Copyright (c) 1980, 1992, 1993 @@ -38,7 +38,7 @@ #if 0 static char sccsid[] = "@(#)netstat.c 8.1 (Berkeley) 6/6/93"; #endif -__RCSID("$NetBSD: netstat.c,v 1.14 2000/01/05 11:50:21 itojun Exp $"); +__RCSID("$NetBSD: netstat.c,v 1.15 2000/01/05 11:59:12 itojun Exp $"); #endif /* not lint */ /* @@ -61,6 +61,10 @@ __RCSID("$NetBSD: netstat.c,v 1.14 2000/01/05 11:50:21 itojun Exp $"); #include <netinet/ip_icmp.h> #include <netinet/icmp_var.h> #include <netinet/ip_var.h> +#ifdef INET6 +#include <netinet/ip6.h> +#include <netinet6/in6_pcb.h> +#endif #include <netinet/tcp.h> #include <netinet/tcpip.h> #include <netinet/tcp_seq.h> @@ -81,13 +85,19 @@ __RCSID("$NetBSD: netstat.c,v 1.14 2000/01/05 11:50:21 itojun Exp $"); #include "extern.h" static void enter __P((struct inpcb *, struct socket *, int, char *)); -static char *inetname __P((struct in_addr)); +static const char *inetname __P((struct in_addr)); static void inetprint __P((struct in_addr *, int, char *)); +#ifdef INET6 +static void enter6 __P((struct in6pcb *, struct socket *, int, char *)); +static const char *inet6name __P((struct in6_addr *)); +static void inet6print __P((struct in6_addr *, int, char *)); +#endif #define streq(a,b) (strcmp(a,b)==0) struct netinfo { struct netinfo *ni_forw, *ni_prev; + int ni_family; short ni_line; /* line on screen */ short ni_seen; /* 0 when not present in list */ short ni_flags; @@ -96,8 +106,14 @@ struct netinfo { short ni_state; /* tcp state */ char *ni_proto; /* protocol */ struct in_addr ni_laddr; /* local address */ +#ifdef INET6 + struct in6_addr ni_laddr6; /* local address */ +#endif long ni_lport; /* local port */ struct in_addr ni_faddr; /* foreign address */ +#ifdef INET6 + struct in6_addr ni_faddr6; /* foreign address */ +#endif long ni_fport; /* foreign port */ long ni_rcvcc; /* rcv buffer character count */ long ni_sndcc; /* snd buffer character count */ @@ -147,6 +163,12 @@ static struct nlist namelist[] = { { "_tcbtable" }, #define X_UDBTABLE 1 { "_udbtable" }, +#ifdef INET6 +#define X_TCB6 2 + { "_tcb6" }, +#define X_UDB6 3 + { "_udb6" }, +#endif { "" }, }; @@ -175,6 +197,10 @@ fetchnetstat() struct inpcb inpcb; struct socket sockb; struct tcpcb tcpcb; +#ifdef INET6 + struct in6pcb in6pcb; + struct in6pcb *head6, *prev6, *next6; +#endif void *off; int istcp; @@ -229,6 +255,56 @@ printf("prev = %p, head = %p, next = %p, inpcb...prev = %p\n", prev, head, next, off = NPTR(X_UDBTABLE); goto again; } + +#ifdef INET6 + if (protos&TCP) { + off = NPTR(X_TCB6); + istcp = 1; + } + else if (protos&UDP) { + off = NPTR(X_UDB6); + istcp = 0; + } + else { + error("No protocols to display"); + return; + } +again6: + KREAD(off, &in6pcb, sizeof (struct in6pcb)); + prev6 = head6 = (struct in6pcb *)off; + next6 = in6pcb.in6p_next; + while (next6 != head6) { + KREAD(next6, &in6pcb, sizeof (in6pcb)); + if (in6pcb.in6p_prev != prev6) { +printf("prev = %p, head = %p, next = %p, inpcb...prev = %p\n", prev6, head6, next6, in6pcb.in6p_prev); + p = netcb.ni_forw; + for (; p != (struct netinfo *)&netcb; p = p->ni_forw) + p->ni_seen = 1; + error("Kernel state in transition"); + return; + } + prev6 = next6; + next6 = in6pcb.in6p_next; + + if (!aflag && IN6_IS_ADDR_UNSPECIFIED(&in6pcb.in6p_laddr)) + continue; + if (nhosts && !checkhost6(&in6pcb)) + continue; + if (nports && !checkport6(&in6pcb)) + continue; + KREAD(in6pcb.in6p_socket, &sockb, sizeof (sockb)); + if (istcp) { + KREAD(in6pcb.in6p_ppcb, &tcpcb, sizeof (tcpcb)); + enter6(&in6pcb, &sockb, tcpcb.t_state, "tcp"); + } else + enter6(&in6pcb, &sockb, 0, "udp"); + } + if (istcp && (protos&UDP)) { + istcp = 0; + off = NPTR(X_UDB6); + goto again6; + } +#endif /*INET6*/ } static void @@ -248,6 +324,8 @@ enter(inp, so, state, proto) * data structures. */ for (p = netcb.ni_forw; p != (struct netinfo *)&netcb; p = p->ni_forw) { + if (p->ni_family != AF_INET) + continue; if (!streq(proto, p->ni_proto)) continue; if (p->ni_lport != inp->inp_lport || @@ -273,6 +351,7 @@ enter(inp, so, state, proto) p->ni_fport = inp->inp_fport; p->ni_proto = proto; p->ni_flags = NIF_LACHG|NIF_FACHG; + p->ni_family = AF_INET; } p->ni_rcvcc = so->so_rcv.sb_cc; p->ni_sndcc = so->so_snd.sb_cc; @@ -280,6 +359,60 @@ enter(inp, so, state, proto) p->ni_seen = 1; } +#ifdef INET6 +static void +enter6(in6p, so, state, proto) + struct in6pcb *in6p; + struct socket *so; + int state; + char *proto; +{ + 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 + * data structures. + */ + for (p = netcb.ni_forw; p != (struct netinfo *)&netcb; p = p->ni_forw) { + if (p->ni_family != AF_INET6) + continue; + if (!streq(proto, p->ni_proto)) + continue; + if (p->ni_lport != in6p->in6p_lport || + !IN6_ARE_ADDR_EQUAL(&p->ni_laddr6, &in6p->in6p_laddr)) + continue; + if (IN6_ARE_ADDR_EQUAL(&p->ni_faddr6, &in6p->in6p_faddr) && + p->ni_fport == in6p->in6p_fport) + break; + } + if (p == (struct netinfo *)&netcb) { + if ((p = malloc(sizeof(*p))) == NULL) { + error("Out of memory"); + return; + } + p->ni_prev = (struct netinfo *)&netcb; + p->ni_forw = netcb.ni_forw; + netcb.ni_forw->ni_prev = p; + netcb.ni_forw = p; + p->ni_line = -1; + p->ni_laddr6 = in6p->in6p_laddr; + p->ni_lport = in6p->in6p_lport; + p->ni_faddr6 = in6p->in6p_faddr; + p->ni_fport = in6p->in6p_fport; + p->ni_proto = proto; + p->ni_flags = NIF_LACHG|NIF_FACHG; + p->ni_family = AF_INET6; + } + p->ni_rcvcc = so->so_rcv.sb_cc; + p->ni_sndcc = so->so_snd.sb_cc; + p->ni_state = state; + p->ni_seen = 1; +} +#endif + /* column locations */ #define LADDR 0 #define FADDR LADDR+23 @@ -349,15 +482,41 @@ shownetstat() } if (p->ni_flags & NIF_LACHG) { wmove(wnd, p->ni_line, LADDR); - inetprint(&p->ni_laddr, p->ni_lport, p->ni_proto); + switch (p->ni_family) { + case AF_INET: + inetprint(&p->ni_laddr, p->ni_lport, + p->ni_proto); + break; +#ifdef INET6 + case AF_INET6: + inet6print(&p->ni_laddr6, p->ni_lport, + p->ni_proto); + break; +#endif + } 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); + switch (p->ni_family) { + case AF_INET: + inetprint(&p->ni_faddr, p->ni_fport, + p->ni_proto); + break; +#ifdef INET6 + case AF_INET6: + inet6print(&p->ni_faddr6, p->ni_fport, + p->ni_proto); + break; +#endif + } p->ni_flags &= ~NIF_FACHG; } mvwaddstr(wnd, p->ni_line, PROTO, p->ni_proto); +#ifdef INET6 + if (p->ni_family == AF_INET6) + waddstr(wnd, "6"); +#endif 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")) { @@ -407,12 +566,41 @@ inetprint(in, port, proto) waddstr(wnd, line); } +#ifdef INET6 +static void +inet6print(in6, port, proto) + struct in6_addr *in6; + int port; + char *proto; +{ + struct servent *sp = 0; + char line[80], *cp; + + (void)snprintf(line, sizeof line, "%.*s.", 16, inet6name(in6)); + cp = strchr(line, '\0'); + if (!nflag && port) + sp = getservbyport(port, proto); + if (sp || port == 0) + (void)snprintf(cp, line + sizeof line - cp, "%.8s", + sp ? sp->s_name : "*"); + else + (void)snprintf(cp, line + sizeof line - cp, "%d", + ntohs((u_short)port)); + /* pad to full column to clear any garbage */ + cp = strchr(line, '\0'); + while (cp - line < 22) + *cp++ = ' '; + *cp = '\0'; + waddstr(wnd, line); +} +#endif + /* * Construct an Internet address representation. * If the nflag has been supplied, give * numeric value, otherwise try for symbolic name. */ -static char * +static const char * inetname(in) struct in_addr in; { @@ -452,6 +640,32 @@ inetname(in) return (line); } +#ifdef INET6 +static const char * +inet6name(in6) + struct in6_addr *in6; +{ + static char line[NI_MAXHOST]; + struct sockaddr_in6 sin6; + int flags; + + if (nflag) + flags = NI_NUMERICHOST; + else + flags = 0; + if (IN6_IS_ADDR_UNSPECIFIED(in6)) + return "*"; + memset(&sin6, 0, sizeof(sin6)); + sin6.sin6_family = AF_INET6; + sin6.sin6_len = sizeof(struct sockaddr_in6); + sin6.sin6_addr = *in6; + if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, + line, sizeof(line), NULL, 0, flags) == 0) + return line; + return "?"; +} +#endif + /* please note: there are also some netstat commands in netcmds.c */ void |
