Peter Postma wrote: > Looks useful. I've some comments on the source, see below. > > IPv6 statetop still works fine for me, but resolving of IPv6 > addresses does not.
OK, cool. I'll see if I can write in some IPv6 resolution at some point.
> One suggestion: maybe implement port lookups as well (by using portname()
> from lib/portname.c) ?
I would rather not - this tends to give you even less space for your
hostname display and we truncate as it is... but I can do it if people
want it.
>>+ sname = malloc(STSTRSIZE);
>>+ dname = malloc(STSTRSIZE);
>>+
>
> malloc() can fail, better check for NULL, or use static allocation.
Good gall. Fixed. Malloc's failing are very bad - I chose to exit in
this case.
>>+ hostinfo = gethostbyaddr((char
>>*)&ips.is_src,sizeof(ips.is_src), AF_INET);
>
>
> I've two problems with this, the sizeof is wrong because is_src is actually
> much bigger than you want. Better replace this with sizeof(struct in_addr).
> Or use hostname() from lib/hostname.c. On NetBSD/sparc64, the resolving
> doesn't works unless you do one of the above. And secondly, this only
> works for AF_INET since you've hardcoded that.
Good call. I also did a check for IPv4 in the loop as well.
>>+ if (length < 2) {
>>+ fprintf(stderr,"Error, screen
>>too small\n");
>>+ exit(0);
>>+ }
>
>
> This doesn't restore the terminal.
Good call. But there are LOTS of them that do this:
tsentry++;
if (!maxtsentries || tsentry == maxtsentries) {
maxtsentries += STGROWSIZE;
tstable = realloc(tstable,
maxtsentries * sizeof(statetop_t));
if (tstable == NULL) {
perror("realloc");
exit(-1);
}
}
But I cleaned up mine for you. =)
> Resizing works for me (NetBSD-3.99.2/sparc64).
>
> Does handle_resize ever get set to 1 when you resize?
Nope.
Attached is a new version. Thanks for the comments.
--
Phil Dibowitz [EMAIL PROTECTED]
Freeware and Technical Pages Insanity Palace of Metallica
http://www.phildev.net/ http://www.ipom.com/
"They that can give up essential liberty to obtain a little temporary
safety deserve neither liberty nor safety."
- Benjamin Franklin, 1759
--- tools/ipfstat.c.4.1.8 Sun Apr 3 13:50:47 2005
+++ tools/ipfstat.c Sun Apr 3 13:49:55 2005
@@ -123,6 +123,8 @@
U_QUAD_T st_pkts;
U_QUAD_T st_bytes;
u_long st_age;
+ char st_sname[STSTRSIZE];
+ char st_dname[STSTRSIZE];
} statetop_t;
#endif
@@ -143,7 +145,7 @@
ipfrstat_t **, fr_authstat_t **, u_32_t *));
#ifdef STATETOP
static void topipstates __P((i6addr_t, i6addr_t, int, int, int,
- int, int, int));
+ int, int, int, int));
static void sig_break __P((int));
static void sig_resize __P((int));
static char *getip __P((int, i6addr_t *));
@@ -156,6 +158,7 @@
static int sort_srcpt __P((const void *, const void *));
static int sort_dstip __P((const void *, const void *));
static int sort_dstpt __P((const void *, const void *));
+static unsigned digits __P((int x));
#endif
@@ -199,6 +202,7 @@
int sport = -1; /* -1 = wild card for any source port */
int dport = -1; /* -1 = wild card for any dest port */
int topclosed = 0; /* do not show closed tcp sessions */
+ int topdns = 0; /* do not show closed dns sessions */
i6addr_t saddr, daddr;
u_32_t frf;
@@ -307,6 +311,9 @@
case 'l' :
opts |= OPT_SHOWLIST;
break;
+ case 'L':
+ topdns = 1;
+ break;
case 'M' :
break;
case 'N' :
@@ -385,7 +392,7 @@
#ifdef STATETOP
else if (opts & OPT_STATETOP)
topipstates(saddr, daddr, sport, dport, protocol,
- use_inet6 ? 6 : 4, refreshtime, topclosed);
+ use_inet6 ? 6 : 4, refreshtime, topclosed, topdns);
#endif
else if (opts & OPT_AUTHSTATS)
showauthstates(frauthstp);
@@ -994,7 +1001,7 @@
static int handle_resize = 0, handle_break = 0;
static void topipstates(saddr, daddr, sport, dport, protocol, ver,
- refreshtime, topclosed)
+ refreshtime, topclosed, topdns)
i6addr_t saddr;
i6addr_t daddr;
int sport;
@@ -1003,11 +1010,14 @@
int ver;
int refreshtime;
int topclosed;
+int topdns;
{
char str1[STSTRSIZE], str2[STSTRSIZE], str3[STSTRSIZE], str4[STSTRSIZE];
- int maxtsentries = 0, reverse = 0, sorting = STSORT_DEFAULT;
+ char *sname, *dname;
+ int maxtsentries = 0, reverse = 0, sorting = STSORT_DEFAULT, resolve = 0;
int i, j, winy, tsentry, maxx, maxy, redraw = 0;
- int len, srclen, dstlen, forward = 1, c = 0;
+ int len, srclen = 0, dstlen = 0, forward = 1, c = 0, length = 0;
+ int tag_truncate = 0, templength = 0;
ips_stat_t ipsst, *ipsstp = &ipsst;
statetop_t *tstable = NULL, *tp;
ipstate_t ips;
@@ -1017,6 +1027,7 @@
struct protoent *proto;
fd_set readfd;
time_t t;
+ struct hostent* hostinfo = NULL;
/* install signal handlers */
signal(SIGINT, sig_break);
@@ -1024,6 +1035,15 @@
signal(SIGTERM, sig_break);
signal(SIGWINCH, sig_resize);
+ /* attempt this before we start curses stuff */
+ sname = malloc(STSTRSIZE);
+ dname = malloc(STSTRSIZE);
+
+ if (sname == NULL || dname == NULL) {
+ fprintf(stderr,"ERROR: allocating space failed\n");
+ exit(-1);
+ }
+
/* init ncurses stuff */
initscr();
cbreak();
@@ -1062,6 +1082,12 @@
/* read the state table and store in tstable */
for (; ipsstp->iss_list; ipsstp->iss_list = ips.is_next) {
+ /* reset names */
+ sname[0]='\0';
+ dname[0]='\0';
+ templength=0;
+ length=0;
+
if (kmemcpy((char *)&ips, (u_long)ipsstp->iss_list,
sizeof(ips)))
break;
@@ -1098,6 +1124,12 @@
((dport > 0) && (htons(dport) != ips.is_dport))))
continue;
+ /* show DNS queries? */
+ if ((resolve && topdns) && ((ips.is_p == IPPROTO_TCP) ||
+ (ips.is_p == IPPROTO_UDP)) &&
+ (ntohs(ips.is_dport) == 53))
+ continue;
+
/* show closed TCP sessions ? */
if ((topclosed == 0) && (ips.is_p == IPPROTO_TCP) &&
(ips.is_state[0] >= IPF_TCPS_LAST_ACK) &&
@@ -1119,13 +1151,79 @@
}
}
- /* get max src/dest address string length */
- len = strlen(getip(ips.is_v, &ips.is_src));
- if (srclen < len)
- srclen = len;
- len = strlen(getip(ips.is_v, &ips.is_dst));
- if (dstlen < len)
- dstlen = len;
+ srclen = dstlen = (maxx-38)/2;
+ if (resolve && ips.is_v == 4) {
+ /*
+ * We want to resolve as many hostnames
+ * as possible unless told not to. But we
+ * have limited space, so we'll truncate
+ * source address from the left (we know
+ * our own domain name), and destination
+ * addresses from the right (domain is more
+ * useful than hostname usually when outside
+ * your own domain).
+ *
+ * A note on the math:
+ * All rows other than src and dst take a total
+ * of 36 characters all together. So maxx-36
+ * is the rest of the screen, plus a space after
+ * each side is 38. So each addy gets
+ * (maxx-38)/2. If it's TCP or UDP, we also need
+ * to allow room for the port and a comma.
+ *
+ * The other trick is that for terminals with an
+ * odd number of lines we this math doesn't work
+ * so we arbitrarily cut an extra character off of
+ * the src side.
+ */
+ hostinfo = gethostbyaddr((char *)&ips.is_src,sizeof(struct in_addr), AF_INET);
+ if (hostinfo != NULL) {
+ strncpy(sname,hostinfo->h_name,STSTRSIZE);
+ templength = strlen(sname);
+ if ((ips.is_p == IPPROTO_TCP) ||
+ (ips.is_p == IPPROTO_UDP)) {
+ length = (maxx-38)/2 - (1 + digits(ntohs(ips.is_sport)));
+ } else {
+ length = (maxx-38)/2;
+ }
+ if (length < 2) {
+ fprintf(stderr,"Error, screen too small\n");
+ printw("\n");
+ curs_set(1);
+ nocbreak();
+ endwin();
+
+ free(tstable);
+ free(sname);
+ free(dname);
+ exit(-1);
+ }
+ if (templength > length) {
+ sname[length]='\0';
+ if (tag_truncate)
+ sname[length-1]='+';
+ }
+ }
+
+ hostinfo = gethostbyaddr((char *)&ips.is_dst,sizeof(ips.is_dst), AF_INET);
+ if (hostinfo != NULL) {
+ strncpy(dname,hostinfo->h_name,STSTRSIZE);
+ templength = strlen(dname);
+ if ((ips.is_p == IPPROTO_TCP) ||
+ (ips.is_p == IPPROTO_UDP)) {
+ length = (maxx-38)/2 - (1 + digits(ntohs(ips.is_dport)));
+ } else {
+ length = (maxx-38)/2;
+ }
+ if (templength > length) {
+ memmove(dname,dname+(templength-length),templength-(templength-length-1));
+ if (tag_truncate)
+ dname[0]='+';
+ }
+
+ }
+ }
+
/* fill structure */
tp = tstable + tsentry;
@@ -1135,6 +1233,11 @@
tp->st_v = ips.is_v;
tp->st_state[0] = ips.is_state[0];
tp->st_state[1] = ips.is_state[1];
+ if (resolve) {
+ strncpy(tp->st_sname,sname,STSTRSIZE);
+ strncpy(tp->st_dname,dname,STSTRSIZE);
+ }
+
if (forward) {
tp->st_pkts = ips.is_pkts[0]+ips.is_pkts[1];
tp->st_bytes = ips.is_bytes[0]+ips.is_bytes[1];
@@ -1282,6 +1385,12 @@
if (reverse)
strcat(str4, " (reverse)");
+ if (resolve)
+ strcat(str4, ", Resolve");
+
+ if (tag_truncate)
+ strcat(str4, ", tag");
+
winy += 2;
move(winy,0);
printw("Src: %s, Dest: %s, Proto: %s, Sorted by: %s\n\n",
@@ -1297,10 +1406,8 @@
* can be longer that 15 characters), so we do not enforce
* a maximum on the IP field size.
*/
- if (srclen < 15)
- srclen = 15;
- if (dstlen < 15)
- dstlen = 15;
+ /*
+ srclen = dstlen = (maxx-38)/2;
/* print column description */
winy += 2;
@@ -1307,7 +1414,7 @@
move(winy,0);
attron(A_BOLD);
printw("%-*s %-*s %3s %4s %7s %9s %9s\n",
- srclen + 6, "Source IP", dstlen + 6, "Destination IP",
+ srclen, "Source IP", dstlen, "Destination IP",
"ST", "PR", "#pkts", "#bytes", "ttl");
attroff(A_BOLD);
@@ -1319,24 +1426,33 @@
if (tsentry > maxy - 6)
tsentry = maxy - 6;
for (i = 0; i <= tsentry; i++) {
- /* print src/dest and port */
+
+ /*
+ * Print the hostname or IP - for all protos
+ */
+ if (resolve && tp->st_sname[0] != '\0') {
+ sprintf(str1, "%s", tp->st_sname);
+ } else {
+ sprintf(str1, "%s", getip(tp->st_v,&tp->st_src));
+ }
+ if (resolve && tp->st_dname[0] != '\0') {
+ sprintf(str2, "%s", tp->st_dname);
+ } else {
+ sprintf(str2, "%s", getip(tp->st_v,&tp->st_dst));
+ }
+
+ /*
+ * If we're TCP or UDP, append a portnumber
+ */
if ((tp->st_p == IPPROTO_TCP) ||
(tp->st_p == IPPROTO_UDP)) {
- sprintf(str1, "%s,%hu",
- getip(tp->st_v, &tp->st_src),
- ntohs(tp->st_sport));
- sprintf(str2, "%s,%hu",
- getip(tp->st_v, &tp->st_dst),
- ntohs(tp->st_dport));
- } else {
- sprintf(str1, "%s", getip(tp->st_v,
- &tp->st_src));
- sprintf(str2, "%s", getip(tp->st_v,
- &tp->st_dst));
+ sprintf(str1, "%s,%hu",str1,ntohs(tp->st_sport));
+ sprintf(str2, "%s,%hu",str2,ntohs(tp->st_dport));
}
+
winy++;
move(winy, 0);
- printw("%-*s %-*s", srclen + 6, str1, dstlen + 6, str2);
+ printw("%-*s %-*s", srclen, str1, dstlen, str2);
/* print state */
sprintf(str1, "%X/%X", tp->st_state[0],
@@ -1410,6 +1526,14 @@
} else if (c == 's') {
if (++sorting > STSORT_MAX)
sorting = 0;
+ } else if (c == 'n') {
+ resolve = !resolve;
+ } else if (c == 'w') {
+ handle_resize=1;
+ } else if (c == 'd') {
+ topdns = !topdns;
+ } else if (c == 't') {
+ tag_truncate = !tag_truncate;
}
}
} /* while */
@@ -1420,7 +1544,21 @@
endwin();
free(tstable);
+ free(sname);
+ free(dname);
}
+
+// This determines the length of an integer (i.e. number of digits)
+static unsigned digits(x)
+int x;
+{
+ unsigned length = 1;
+ while(x/10 > 0) {
+ x = x/10;
+ length++;
+ }
+ return length;
+}
#endif
@@ -1574,6 +1712,7 @@
/* get ip address */
if (!strcasecmp(s, "any")) {
ip->in4.s_addr = INADDR_ANY;
+ ok = 1;
#ifdef USE_INET6
ip->in6 = in6addr_any;
} else if (use_inet6 && inet_pton(AF_INET6, s, &ip->in6)) {
--- man/ipfstat.8.orig Sun Apr 3 13:51:39 2005
+++ man/ipfstat.8 Sun Apr 3 04:02:04 2005
@@ -78,6 +78,10 @@
Swap between retrieving "inactive"/"active" filter list details. For use
in combination with \fB\-i\fP.
.TP
+.B \-L
+This option is only valid in combination with \fB\-t\fP. When resolving
+hostnames, do not show DNS-related states.
+.TP
.B \-n
Show the "rule number" for each rule as it is printed.
.TP
@@ -93,7 +97,8 @@
.TP
.BR \-R
Don't try to resolve addresses to hostnames and ports to services while
-printing statistics.
+printing statistics. This doesn't have any affect on statetop which defaults
+to not resolving addresses.
.TP
.B \-s
Show packet/flow state information (statistics only).
@@ -149,28 +154,38 @@
.TP
\fBb\fP show packets/bytes from backward direction.
.TP
+\fBd\fP when resolving hostnames, hide DNS related states.
+.TP
\fBf\fP show packets/bytes from forward direction. (default)
.TP
\fBl\fP redraw the screen.
.TP
+\fBn\fP resolve IP addresses to names.
+.TP
\fBq\fP quit the program.
.TP
+\fBr\fP reverse the sorting criterion.
+.TP
\fBs\fP switch between different sorting criterion.
.TP
-\fBr\fP reverse the sorting criterion.
+\fBt\fP when resolving hostnames, tag ones that were truncated
+(with a +).
+.TP
+\fBw\fP re-adjust for screen resize (same as SIGWINCH).
.PP
-States can be sorted by protocol number, by number of IP packets, by number
-of bytes and by time-to-live of the state entry. The default is to sort by
-the number of bytes. States are sorted in descending order, but you can use
-the \fBr\fP key to sort them in ascending order.
+States can be sorted by source IP, source port, destination IP, destination
+port, protocol number, by number of IP packets, by number of bytes and by
+time-to-live of the state entry. The default is to sort by the number of bytes.
+States are sorted in descending order, but you can use the \fBr\fP key to sort
+them in ascending order.
.SH STATE TOP LIMITATIONS
It is currently not possible to interactively change the source, destination
and protocol filters or the refresh frequency. This must be done from the
command line.
.PP
-The screen must have at least 80 columns. This is however not checked.
-When running state top in IPv6 mode, the screen must be much wider to display
-the very long IPv6 addresses.
+The screen should have at least 80 columns to look right. This is however not
+checked. When running state top in IPv6 mode, the screen must be much wider to
+display the very long IPv6 addresses.
.PP
Only the first X-5 entries that match the sort and filter criteria are
displayed (where X is the number of rows on the display. The only way to see
@@ -186,4 +201,4 @@
.SH SEE ALSO
ipf(8)
.SH BUGS
-none known.
+SIGWINCH doesn't seem to get through to STATETOP.
--- Makefile.orig Sun Apr 3 04:14:23 2005
+++ Makefile Sun Apr 3 04:02:06 2005
@@ -14,9 +14,10 @@
#To test prototyping
#CC=gcc -Wstrict-prototypes -Wmissing-prototypes
# -Wunused -Wuninitialized
-#CC=gcc
+CC=gcc
#CC=cc -Dconst=
-DEBUG=-g
+#DEBUG=-g
+DEBUG=-O
# -O
CFLAGS=-I$$(TOP) -D_BSD_SOURCE
CPU=`uname -m`
@@ -77,16 +78,16 @@
#
# Uncomment the next 3 lines if you want to view the state table a la top(1)
# (requires that you have installed ncurses).
-#STATETOP_CFLAGS=-DSTATETOP
+STATETOP_CFLAGS=-DSTATETOP
#
# Where to find the ncurses include files (if not in default path),
#
-#STATETOP_INC=
+STATETOP_INC=-I/opt/csw/include -I/opt/csw/include/ncurses
#STATETOP_INC=-I/usr/local/include
#
# How to link the ncurses library
#
-#STATETOP_LIB=-lncurses
+STATETOP_LIB=-L/opt/csw/lib -R/opt/csw/lib -lncurses -lm
#STATETOP_LIB=-L/usr/local/lib -lncurses
#
signature.asc
Description: OpenPGP digital signature
