Phil Dibowitz wrote:
>
> Attached is a new version. Thanks for the comments.

Oh crud. my *local* makefile changes got in there. Oops. New version
attached.

--
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 14:36:55 2005
@@ -86,8 +86,8 @@
 #
 # How to link the ncurses library
 #
-#STATETOP_LIB=-lncurses
-#STATETOP_LIB=-L/usr/local/lib -lncurses
+#STATETOP_LIB=-lncurses -lm
+#STATETOP_LIB=-L/usr/local/lib -lncurses -lm

 #
 # Uncomment this when building IPv6 capability.

Attachment: signature.asc
Description: OpenPGP digital signature

Reply via email to