summaryrefslogtreecommitdiff
path: root/usr.bin
diff options
context:
space:
mode:
authoritojun <itojun@NetBSD.org>2000-01-05 11:59:12 +0000
committeritojun <itojun@NetBSD.org>2000-01-05 11:59:12 +0000
commit7b5dfc58ad9d917cf2b81caecadffa94de932a4d (patch)
tree2555957cd875d91291758fa3ce50ca3893da20b6 /usr.bin
parent88ac9b1712cb2fa4ba43fd3479760247da0f014e (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/Makefile4
-rw-r--r--usr.bin/systat/extern.h9
-rw-r--r--usr.bin/systat/netcmds.c139
-rw-r--r--usr.bin/systat/netstat.c226
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