From f4b205deba6ab4a49bce3d82f31cfc8d3b432c50 Mon Sep 17 00:00:00 2001 From: Roger Wolff Date: Wed, 3 Mar 1999 00:00:00 +0000 Subject: [PATCH] mtr v0.29 - Lots of stuff. - Neato overview display by David Sward. - FreeBSD does wrong in the kernel the same that Solaris/x86 (see note for 0.27 does right. It forces mtr to send bad packets.... - Adjusted "not too much at once" algorithm. Now probing continues as long as not more than 5 hosts are unknown. Returning packets usually allow us to do the first sweep in one go. source: ftp://ftp.bitwizard.nl/mtr/mtr-0.29.tar.gz --- AUTHORS | 25 ++++++-- NEWS | 12 ++++ README | 18 +++++- TODO | 21 ++++++- configure.in | 5 +- curses.c | 158 +++++++++++++++++++++++++++++++++++++++++++++++---- display.c | 15 +++++ display.h | 5 +- gtk.c | 8 ++- mtr-curses.h | 1 + mtr.c | 1 + net.c | 108 +++++++++++++++++++++++++++++++---- net.h | 5 ++ select.c | 6 ++ split.c | 13 +++++ 15 files changed, 368 insertions(+), 33 deletions(-) diff --git a/AUTHORS b/AUTHORS index d8dd1ea..531be36 100644 --- a/AUTHORS +++ b/AUTHORS @@ -10,9 +10,26 @@ Thanks to everyone who has provided feedback on mtr. Thanks especially to those of you who have sent code: + (Reverse alphabetical order) + + Juha Takala, + David Sward (sward@clark.net), + Andrew Stesin, + Aaron Scarisbrick, + Russell Nelson, + Alexander V. Lukyanov, + Charles Levert, + Bertrand Leconte, + Anand Kumria, + Adam Kramer (l3zqc@qcunix1.acc.qc.edu), + Simon Kirby, + Christophe Kalt, + Mircea Damian, + Brian Casey, - Brian Casey, Mircea Damian, Christophe Kalt, Simon Kirby, - Anand Kumria, Bertrand Leconte, Charles Levert, Alexander - V. Lukyanov, Russell Nelson, Aaron Scarisbrick, Andrew - Stesin, Juha Takala. and anyone who has slipped through the cracks of my mail file. + +Authors: If you want your Email mentioned here, send it to me. + If you don't want your Email mentioned here, tell me. + + -- REW diff --git a/NEWS b/NEWS index 60aa2ab..3ed50aa 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,17 @@ WHAT'S NEW? + v0.29 Lots of stuff. + Neato overview display by David Sward. + FreeBSD does wrong in the kernel the same that Solaris/x86 (see + note for 0.27 does right. It forces mtr to send bad packets.... + Adjusted "not too much at once" algorithm. Now probing + continues as long as not more than 5 hosts are unknown. + Returning packets usually allow us to do the first sweep + in one go. + + + v0.28 DNS lookups are now suppressed if you don't want them. + v0.27 Fixed bug that showed up on Solaris/x86. Gimp mainloop now runs as it's supposed to. diff --git a/README b/README index 2cae3f6..1f68dad 100644 --- a/README +++ b/README @@ -15,7 +15,10 @@ WHAT IS MTR? INSTALLING - To begin mtr, first use the included configure script: + Slightly more hints are in the file INSTALL. If this doesn't work + you could try reading that too.... + + To begin compiling mtr, first use the included configure script: ./configure @@ -30,6 +33,18 @@ INSTALLING Note that mtr must be suid-root because it requires access to raw IP sockets. See SECURITY for security information. + If you want to build a version that doesn't use GTK, but if you + DO have GTK installed, you can use + + ./configure --with-gtk-prefix=/we_dont_want_gtk_so_we_use_a_name_that_certainly_doesnt_exist + + It seems the --no_gtk (whatever) doesn't work. Feel free to submit + a patch for this, I'm not that familiar with autoconf (it works for + me :-). + + + + WHERE CAN I GET THE LATEST VERSION OR MORE INFORMATION? See the mtr web page at @@ -43,4 +58,3 @@ WHERE CAN I GET THE LATEST VERSION OR MORE INFORMATION? Bug reports and feature requests should be sent to the mtr mailing list. - diff --git a/TODO b/TODO index 0d40681..5ceb3cd 100644 --- a/TODO +++ b/TODO @@ -30,5 +30,24 @@ - Bugs to fix? - - ? + + - Do something useful if host couldn't be resolved. + +- Nice to have: + + - stop sending packets when a new host is getting entered. + + - Show state ("looking up host") while doing the DNS lookup for a new + host. + + - Check why it still tries to go for X11 display if DISPLAY is unset. + (I saw code to handle this) + + - Revert to curses mode even if DISPLAY is set, but a problem + prevents us from running in X11 mode. + --> The problem is that gtk_init simply calls exit for us if + it finds a problem. Tricky! + + - Read environment variable "MTR_DEFAULTS" as a commandline before + parsing the commandline. diff --git a/configure.in b/configure.in index d9f5c57..1dc26cb 100644 --- a/configure.in +++ b/configure.in @@ -1,5 +1,5 @@ AC_INIT(mtr.c) -AM_INIT_AUTOMAKE(mtr, 0.28) +AM_INIT_AUTOMAKE(mtr, 0.29) AC_SUBST(GTK_OBJ) AC_SUBST(CURSES_OBJ) @@ -37,6 +37,9 @@ AC_CHECK_FUNC(socket, , AC_CHECK_FUNC(gethostbyname, , AC_CHECK_LIB(nsl, gethostbyname, , AC_MSG_ERROR(No nameservice library found))) +AC_CHECK_FUNC(res_init, , + AC_CHECK_LIB(bind, res_init, , AC_MSG_ERROR(No resolver library found))) + AC_CHECK_FUNC(res_mkquery, , AC_CHECK_LIB(resolv, res_mkquery, , AC_MSG_ERROR(No resolver library found))) diff --git a/curses.c b/curses.c index 4932e6f..930c66a 100644 --- a/curses.c +++ b/curses.c @@ -61,8 +61,12 @@ int mtr_curses_keyaction() { return ActionQuit; if(c==3) return ActionQuit; + if (c==12) + return ActionClear; if(tolower(c) == 'r') return ActionReset; + if (tolower(c) == 'd') + return ActionDisplay; return 0; } @@ -92,7 +96,7 @@ void mtr_curses_hosts(int startstat) { getyx(stdscr, y, x); move(y, startstat); - printw(" %3d%% %3d %3d %4d %4d %6d", + printw(" %3d%% %4d %4d %4d %4d %6d", net_percent(at), net_returned(at), net_xmit(at), net_best(at), net_avg(at), net_worst(at)); @@ -106,17 +110,120 @@ void mtr_curses_hosts(int startstat) { } } +static double factors[] = { 0.02, 0.05, 0.08, 0.15, 0.33, 0.50, 0.80, 1.00 }; +static int scale[8]; +static int low_ms, high_ms; + +void mtr_gen_scale(void) { + int *saved, i, max, at; + int range; + + low_ms = 1000000; + high_ms = -1; + + for (i = 0; i < 8; i++) { + scale[i] = 0; + } + max = net_max(); + for (at = 0; at < max; at++) { + saved = net_saved_pings(at); + for (i = 0; i < SAVED_PINGS; i++) { + if (saved[i] < 0) continue; + if (saved[i] < low_ms) { + low_ms = saved[i]; + } + if (saved[i] > high_ms) { + high_ms = saved[i]; + } + } + } + range = high_ms - low_ms; + for (i = 0; i < 8; i++) { + scale[i] = low_ms + ((double)range * factors[i]); + } +} + +static const char* block_map = ".123abc>"; + +void mtr_print_scaled(int ms) { + int i; + + for (i = 0; i < 8; i++) { + if (ms <= scale[i]) { + printw("%c", block_map[i]); + return; + } + } + printw(">"); +} + +void mtr_fill_graph(int at) { + int* saved; + int i; + int val; + + saved = net_saved_pings(at); + for (i = 0; i < SAVED_PINGS; i++) { + if (saved[i] == -2) { + printw(" "); + } else if (saved[i] == -1) { + attron(A_BOLD); + printw("?"); + attroff(A_BOLD); + } else { + if (display_mode == 1) { + if (saved[i] > scale[6]) { + printw("%c", block_map[7]); + } else { + printw("."); + } + } else { + mtr_print_scaled(saved[i]); + } + } + } +} + +void mtr_curses_graph(int startstat) { + int max, at, addr, y, x; + char* name; + char blocks[50]; + + max = net_max(); + for (at = 0; at < max; at++) { + printw("%2d. ", at+1); + + addr = net_addr(at); + if (!addr) { + printw("???\n"); + continue; + } + + name = dns_lookup(addr); + if (name) { + printw("%s", name); + } else { + printw("%d.%d.%d.%d", (addr >> 24) & 0xff, (addr >> 16) && 0xff, (addr >> 8) & 0xff, addr & 0xff); + } + + getyx(stdscr, y, x); + move(y, startstat); + + printw(" "); + mtr_fill_graph(at); + printw("\n"); + } +} + void mtr_curses_redraw() { int maxx, maxy; int startstat; int rowstat; + int i; erase(); getmaxyx(stdscr, maxy, maxx); - /* Modified by Brian Casey December 1997 bcasey@imagiware.com */ - startstat = maxx - 40; - rowstat = 5; attron(A_BOLD); @@ -126,6 +233,8 @@ void mtr_curses_redraw() { attroff(A_BOLD); printw("Keys: "); + attron(A_BOLD); printw("D"); attroff(A_BOLD); + printw(" - Display mode "); attron(A_BOLD); printw("R"); attroff(A_BOLD); printw(" - Restart statistics "); attron(A_BOLD); printw("Q"); attroff(A_BOLD); @@ -134,14 +243,38 @@ void mtr_curses_redraw() { attron(A_BOLD); mvprintw(rowstat - 1, 0, "Hostname"); - /* Modified by Brian Casey December 1997 bcasey@imagiware.com */ - mvprintw(rowstat - 2, startstat, " Packets Pings"); - mvprintw(rowstat - 1, startstat, " %%Loss Rcv Snt Best Avg Worst"); + if (display_mode == 0) { + startstat = maxx - 40; - attroff(A_BOLD); - move(rowstat, 0); + /* Modified by Brian Casey December 1997 bcasey@imagiware.com */ + mvprintw(rowstat - 2, startstat, " Packets Pings"); + mvprintw(rowstat - 1, startstat, " %%Loss Rcv Snt Best Avg Worst"); + + attroff(A_BOLD); + move(rowstat, 0); + + mtr_curses_hosts(startstat); + } else { + /* David Sward, Jan 1999 */ + startstat = maxx - 52; - mtr_curses_hosts(startstat); + mvprintw(rowstat - 1, startstat, " Last 50 pings"); + + attroff(A_BOLD); + move(rowstat, 0); + + mtr_gen_scale(); + mtr_curses_graph(startstat); + + printw("\n"); + attron(A_BOLD); + printw("Scale:"); + attroff(A_BOLD); + + for (i = 0; i < 7; i++) { + printw(" %c:%d ms", block_map[i], scale[i]); + } + } refresh(); } @@ -158,3 +291,8 @@ void mtr_curses_close() { printw("\n"); endwin(); } + +void mtr_curses_clear() { + mtr_curses_close(); + mtr_curses_open(); +} diff --git a/display.c b/display.c index 2200663..9f18b4e 100644 --- a/display.c +++ b/display.c @@ -170,3 +170,18 @@ void display_loop() { } } + +void display_clear() { + switch(DisplayMode) { + case DisplayCurses: + mtr_curses_clear(); + break; + case DisplayReport: + case DisplaySplit: /* BL */ + case DisplayRaw: + break; + + case DisplayGTK: + break; + } +} diff --git a/display.h b/display.h index 7919bbf..3bd27f2 100644 --- a/display.h +++ b/display.h @@ -17,7 +17,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -enum { ActionNone, ActionQuit, ActionReset }; +enum { ActionNone, ActionQuit, ActionReset, ActionDisplay, ActionClear }; enum { DisplayReport, DisplayCurses, DisplayGTK, DisplaySplit, DisplayRaw }; /* Prototypes for display.c */ @@ -29,3 +29,6 @@ void display_rawping(int hostnum, int msec); void display_rawhost(int hostnum, int ip_addr); int display_keyaction(); void display_loop(); +void display_clear(); + +int display_mode; diff --git a/gtk.c b/gtk.c index 8f0d88d..20c5520 100644 --- a/gtk.c +++ b/gtk.c @@ -147,12 +147,14 @@ GtkWidget *GetRow(int index) { GtkWidget *Scrollarea_create() { GtkWidget *List; + GtkWidget *scroll; int count; for(count = 0; Report_Positions[count]; count++); List = GTK_WIDGET(gtk_clist_new_with_titles(count, Report_Text)); - gtk_clist_set_policy(GTK_CLIST(List), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + scroll = gtk_scrolled_window_new(NULL, NULL); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); for(count = 0; Report_Positions[count + 1]; count++) { gtk_clist_set_column_width(GTK_CLIST(List), count, Report_Positions[count + 1] - @@ -162,9 +164,11 @@ GtkWidget *Scrollarea_create() { for(count = 1; Report_Positions[count]; count++) { gtk_clist_set_column_justification(GTK_CLIST(List), count, GTK_JUSTIFY_RIGHT); } + gtk_container_add(GTK_CONTAINER(scroll), List); + gtk_widget_show(List); ReportBody = List; - return List; + return scroll; } void gtk_add_row(GtkWidget *List) { diff --git a/mtr-curses.h b/mtr-curses.h index c94880f..d12d878 100644 --- a/mtr-curses.h +++ b/mtr-curses.h @@ -22,3 +22,4 @@ void mtr_curses_open(); void mtr_curses_close(); void mtr_curses_redraw(); int mtr_curses_keyaction(); +void mtr_curses_clear(); diff --git a/mtr.c b/mtr.c index 8c1bb9f..e80a8f9 100644 --- a/mtr.c +++ b/mtr.c @@ -173,6 +173,7 @@ int main(int argc, char **argv) { display_open(); dns_open(); + display_mode = 0; display_loop(); net_end_transit(); diff --git a/net.c b/net.c index e1797f6..994fa48 100644 --- a/net.c +++ b/net.c @@ -31,11 +31,13 @@ #include #include #include +#include #include "net.h" extern float WaitTime, DeltaTime; +int timestamp; #define MaxTransit 4 @@ -66,8 +68,12 @@ struct IPHeader { #define ICMP_ECHO 8 #define ICMP_ECHOREPLY 0 + +#define ICMP_TSTAMP 13 +#define ICMP_TSTAMPREPLY 14 + #define ICMP_TIME_EXCEEDED 11 - + #ifndef SOL_IP #define SOL_IP 0 #endif @@ -77,6 +83,7 @@ struct packetdata { int ttl; int sec; int msec; + int seq; }; struct nethost { @@ -87,6 +94,7 @@ struct nethost { int best; int worst; int transit; + int saved[SAVED_PINGS]; }; static struct nethost host[MaxHost]; @@ -112,6 +120,9 @@ int checksum(void *data, int sz) { return (~sum & 0xffff); } + +static int BSDfix = 0; + void net_send_ping(int index) { char packet[sizeof(struct IPHeader) + sizeof(struct ICMPHeader) + sizeof(struct packetdata)]; @@ -127,6 +138,7 @@ void net_send_ping(int index) { addr.sin_addr.s_addr = host[index].addr; host[index].xmit++; host[index].transit = 1; + net_save_xmit(index); memset(packet, 0, packetsize); @@ -136,7 +148,7 @@ void net_send_ping(int index) { ip->version = 0x45; ip->tos = 0; - ip->len = htons (packetsize); + ip->len = BSDfix? packetsize: htons (packetsize); ip->id = 0; ip->frag = 0; ip->ttl = 127; @@ -144,12 +156,13 @@ void net_send_ping(int index) { ip->saddr = 0; ip->daddr = host[index].addr; - icmp->type = ICMP_ECHO; + icmp->type = timestamp?ICMP_TSTAMP:ICMP_ECHO; icmp->id = getpid(); icmp->sequence = 0; data->ttl = 0; data->index = index; + data->seq = host[index].xmit; gettimeofday(&now, NULL); data->sec = now.tv_sec; @@ -169,6 +182,8 @@ void net_send_query(int hops) { struct ICMPHeader *icmp; struct packetdata *data; int packetsize = sizeof(struct IPHeader) + sizeof(struct ICMPHeader) + sizeof(struct packetdata); + int rv; + static int first=1; memset(packet, 0, packetsize); @@ -178,7 +193,7 @@ void net_send_query(int hops) { ip->version = 0x45; ip->tos = 0; - ip->len = htons (packetsize); + ip->len = BSDfix ? packetsize: htons (packetsize); ip->id = 0; ip->frag = 0; ip->ttl = hops; @@ -196,8 +211,19 @@ void net_send_query(int hops) { icmp->checksum = checksum(icmp, packetsize - sizeof(struct IPHeader)); ip->check = checksum(ip, packetsize); - sendto(sendsock, packet, packetsize, 0, + + rv = sendto(sendsock, packet, packetsize, 0, (struct sockaddr *)&remoteaddress, sizeof(remoteaddress)); + if (first && (rv == EINVAL)) { + first = 0; + ip->len = packetsize; + rv = sendto(sendsock, packet, packetsize, 0, + (struct sockaddr *)&remoteaddress, sizeof(remoteaddress)); + if (rv >= 0) { + fprintf (stderr, "You've got a broken (FreeBSD?) system\n"); + BSDfix = 1; + } + } } void net_process_ping(struct packetdata *data, struct sockaddr_in *addr) { @@ -212,6 +238,10 @@ void net_process_ping(struct packetdata *data, struct sockaddr_in *addr) { || (data->sec == reset.tv_sec && (1000*data->msec) < reset.tv_usec)) /* discard this data point, stats were reset after it was generated */ return; + + if (net_duplicate(data->index, data->seq)) { + return; + } totmsec = (now.tv_sec - data->sec) * 1000 + ((now.tv_usec/1000) - data->msec); @@ -231,6 +261,7 @@ void net_process_ping(struct packetdata *data, struct sockaddr_in *addr) { host[data->index].total += totmsec; host[data->index].returned++; host[data->index].transit = 0; + net_save_return(data->index, data->seq, totmsec); } else { at = data->ttl - 1; if(at < 0 || at > MaxHost) @@ -288,10 +319,10 @@ int net_addr(int at) { } int net_percent(int at) { - if(host[at].xmit == 0) + if((host[at].xmit - host[at].transit) == 0) return 0; - return 100 - (100 * (host[at].returned + host[at].transit) / host[at].xmit); + return 100 - (100 * host[at].returned / (host[at].xmit - host[at].transit)); } int net_best(int at) { @@ -348,21 +379,28 @@ void net_end_transit() { int net_send_batch() { - static int n_unknown = 10; static int at; + int n_unknown, i; if(host[at].addr == 0) { net_send_query(at + 1); - n_unknown--; } else { net_send_ping(at); } - + + n_unknown = 0; + + for (i=0;i 5)) { DeltaTime = WaitTime / (float) (at+1); at = 0; - n_unknown = 10; return 1; } @@ -396,6 +434,8 @@ int net_preopen() { } int net_open(int addr) { + net_reset(); + remoteaddress.sin_family = AF_INET; remoteaddress.sin_addr.s_addr = addr; @@ -420,6 +460,7 @@ void net_reopen(int addr) { void net_reset() { int at; + int i; for(at = 0; at < MaxHost; at++) { host[at].xmit = host[at].transit; @@ -427,6 +468,9 @@ void net_reset() { host[at].total = 0; host[at].best = 0; host[at].worst = 0; + for (i=0; i= SAVED_PINGS) { + /* ehhhh - back to the future? */ + return 3; + } + if (host[at].saved[idx] == -2) { + /* say what? must be an old ping */ + return 4; + } + if (host[at].saved[idx] != -1) { + /* it's a dup */ + return 5; + } + return 0; +} + +void net_save_return(int at, int seq, int ms) { + int idx; + idx = SAVED_PINGS - (host[at].xmit - seq) - 1; + if (idx < 0) { + return; + } + host[at].saved[idx] = ms; +} diff --git a/net.h b/net.h index fd78670..a9fdecc 100644 --- a/net.h +++ b/net.h @@ -40,5 +40,10 @@ int net_returned(int at); int net_xmit(int at); int net_transit(int at); +#define SAVED_PINGS 50 +int* net_saved_pings(int at); +void net_save_xmit(int at); +void net_save_return(int at, int seq, int ms); +int net_duplicate(int at, int seq); #define MaxHost 256 diff --git a/select.c b/select.c index 193ecd6..2f184a8 100644 --- a/select.c +++ b/select.c @@ -134,6 +134,12 @@ void select_loop() { if(action == ActionReset) net_reset(); + if (action == ActionDisplay) + display_mode = (display_mode+1) % 3; + + if (action == ActionClear) + display_clear(); + anyset = 1; } diff --git a/split.c b/split.c index a9bc2ff..5f685f9 100644 --- a/split.c +++ b/split.c @@ -32,6 +32,19 @@ #include "split.h" */ +#include + +#if defined(HAVE_NCURSES_H) +# include +#elif defined(HAVE_NCURSES_CURSES_H) +# include +#elif defined(HAVE_CURSES_H) +# include +#else +# error No curses header file available +#endif + + extern char *Hostname; extern int WaitTime; -- 2.47.2