Hey folks, Attached is a new patch to statetop. It impliments hostname resolving, dynamic sizing, and fixes a few bugs. I've not tested this with IPv6, so I don't know how well it'll work with that, but if someone who does use IPv6 could test it, that would be great.
Darren: since there's a lot of changes here, I'd also like a few people
to test this for bugs and such before it get's applied to the official
tree, so don't apply it just yet, please. =)
This patch does not include updates to the man pages, I'll write those
in the next few days... this patch is just to try out the code.
Anyway, here's the list of changes:
- Implimented hostname lookups
* Per the behavior of the rest of ipfstat, they're
no by default, but -R or "n" during operation turns
them off
* truncation is often necessary to keep a pretty
form - src addresses truncate from the left while
dst addresses truncate from the right - you know your
own domain so it's less useful to you, but domains
people are going to are more important than say
"images.somehost.city.f"
* "t" during operation will turn on "truncation tagging"
which will mark where something was truncated
* By default if resolution is turned on, statetop will
surpess states with a dst port of 53. You can disable
this with "d" during operation or the -L flag
- Dynamic Sizing
* Static size no more - statetop will attempt to use
you're whole screen
* SIGWINCH doesn't seem to be working, so I implimented
a "w" command during operation that will properly handle
window resizing
- Fixed display filters... "any" now works without giving
an error. This was documented to work, but never did.
Sorry the hotkeys and the flags don't match, but no reasonable letter
was available in both, unfortunately.
Note that I've been working on this over the last two nights, but most
of it was tonight... and I didn't get much sleep last night, so I'm
pretty exhausted and may have missed some things - but it seems to run
well for me.
As always, comments welcome.
--
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 Thu Mar 31 18:07:00 2005
+++ tools/ipfstat.c Sat Apr 2 02:53:16 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);
@@ -1043,6 +1054,12 @@
ipfo.ipfo_ptr = (void *)ipsstp;
ipfo.ipfo_type = IPFOBJ_STATESTAT;
+ if(!(opts & OPT_NORESOLVE))
+ resolve = 1;
+
+ sname = malloc(STSTRSIZE);
+ dname = malloc(STSTRSIZE);
+
/* repeat until user aborts */
while ( 1 ) {
@@ -1062,6 +1079,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 +1121,12 @@
((dport > 0) && (htons(dport) != ips.is_dport))))
continue;
+ /* show DNS queries? */
+ if ((resolve && topdns == 0) && ((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 +1148,71 @@
}
}
- /* 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) {
+ /*
+ * 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(ips.is_src), 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");
+ exit(0);
+ }
+ 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 +1222,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 +1374,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 +1395,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 +1403,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 +1415,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 +1515,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 +1533,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 +1701,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)) {
signature.asc
Description: OpenPGP digital signature
