From: Roger Wolff Date: Fri, 2 Dec 2011 00:00:00 +0000 (+0000) Subject: mtr v0.82 X-Git-Tag: v0.82^0 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a932cb2abc85651ca6f33a06d7b64448c1d27f65;p=thirdparty%2Fmtr.git mtr v0.82 - Removed old Changelog file appended at the end as oldest changes. 2011-03-28 Mark Kamichoff - Enable decoding of ICMP extensions for MPLS for curses and report interfaces. Use the -e flag or press 'e' to enable it. source: ftp://ftp.bitwizard.nl/mtr/mtr-0.82.tar.gz --- diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..df0f762 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +autom4te.cache +.deps diff --git a/ChangeLog b/ChangeLog deleted file mode 100644 index 21df52d..0000000 --- a/ChangeLog +++ /dev/null @@ -1,13 +0,0 @@ -2002-03-06 Cougar - + If hop doesn't respond, draw its name in red (GTK) or bold (curses) - -2002-02-09 bodq - * Added --address option to bind to given IP addess - -2001-04-15 root - - * Added this file so that automake won't complain. - * Commented out the test for res_init in configure.in; - it does not work for GLIBC2 systems (e.g., RedHat 7+). - * Fixed the subordinate CHECK_LIBS on the test for res_mkquery, - so that they test for res_mkquery, not res_init. diff --git a/NEWS b/NEWS index 0e642d6..a4766b5 100644 --- a/NEWS +++ b/NEWS @@ -1,7 +1,10 @@ WHAT'S NEW? - V0.81 Fix for https://bugs.launchpad.net/mtr/+bug/776211 - don't have time right now to integrate some submitted patches. - Sorry. + V0.82 Removed old Changelog file appended at the end as oldest + changes. + 2011-03-28 Mark Kamichoff + Enable decoding of ICMP extensions for MPLS for curses and + report interfaces. Use the -e flag or press 'e' to enable it. + V0.81 Moved to git. Testing git... V0.80 Some compilation fixes for BSD by Jeremy Chadwick V0.78/0.79 some compilation fixes for BSD&others by @@ -273,3 +276,20 @@ WHAT'S NEW? Both the build process and the networking code have been cleaned up and reorganized. mtr now builds cleanly with GTK+ 0.99.8. + +--- Below is the contents of the old "Changelog file" that annoyed some +people as it didn't contain any recent changes/news. + +2002-03-06 Cougar + + If hop doesn't respond, draw its name in red (GTK) or bold (curses) + +2002-02-09 bodq + * Added --address option to bind to given IP addess + +2001-04-15 root + + * Added this file so that automake won't complain. + * Commented out the test for res_init in configure.in; + it does not work for GLIBC2 systems (e.g., RedHat 7+). + * Fixed the subordinate CHECK_LIBS on the test for res_mkquery, + so that they test for res_mkquery, not res_init. diff --git a/configure.in b/configure.in index 2a2c8a2..8474543 100644 --- a/configure.in +++ b/configure.in @@ -1,5 +1,5 @@ AC_INIT(mtr.c) -AM_INIT_AUTOMAKE(mtr, 0.81) +AM_INIT_AUTOMAKE(mtr, 0.82) AC_SUBST(GTK_OBJ) diff --git a/curses.c b/curses.c index 880d85f..3a3f8c5 100644 --- a/curses.c +++ b/curses.c @@ -111,6 +111,8 @@ int mtr_curses_keyaction(void) return ActionReset; if (tolower(c) == 'd') return ActionDisplay; + if (tolower(c) == 'e') + return ActionMPLS; if (tolower(c) == 'n') return ActionDNS; if (c == '+') @@ -263,6 +265,7 @@ int mtr_curses_keyaction(void) mvprintw(2, 0, "Command:\n" ); printw(" ?|h help\n" ); printw(" d switching display mode\n" ); + printw(" e toggle MPLS information on/off\n" ); printw(" n toggle DNS on/off\n" ); printw(" o str set the columns to display, default str='LRS N BAWV'\n" ); printw(" j toggle latency(LS NABWV)/jitter(DR AGJMXI) stats\n" ); @@ -288,11 +291,12 @@ void mtr_curses_hosts(int startstat) { int max; int at; + struct mplslen *mpls, *mplss; ip_t *addr, *addrs; int y, x; char *name; - int i, j; + int i, j, k; int hd_len; char buf[1024]; @@ -301,6 +305,7 @@ void mtr_curses_hosts(int startstat) for(at = net_min () + display_offset; at < max; at++) { printw("%2d. ", at + 1); addr = net_addr(at); + mpls = net_mpls(at); if( addrcmp( (void *) addr, (void *) &unspec_addr, af ) != 0 ) { name = dns_lookup(addr); @@ -339,9 +344,20 @@ void mtr_curses_hosts(int startstat) buf[hd_len] = 0; printw("%s", buf); + for (k=0; k < mpls->labels && enablempls; k++) { + if((k+1 < mpls->labels) || (mpls->labels == 1)) { + /* if we have more labels */ + printw("\n [MPLS: Lbl %lu Exp %u S %u TTL %u]", mpls->label[k], mpls->exp[k], mpls->s[k], mpls->ttl[k]); + } else { + /* bottom label */ + printw("\n [MPLS: Lbl %lu Exp %u S %u TTL %u]", mpls->label[k], mpls->exp[k], mpls->s[k], mpls->ttl[k]); + } + } + /* Multi path by Min */ for (i=0; i < MAXPATH; i++ ) { addrs = net_addrs(at, i); + mplss = net_mplss(at, i); if ( addrcmp( (void *) addrs, (void *) addr, af ) == 0 ) continue; if ( addrcmp( (void *) addrs, (void *) &unspec_addr, af ) == 0 ) break; @@ -352,6 +368,9 @@ void mtr_curses_hosts(int startstat) } else { printw("\n %s", strlongip( addrs ) ); } + for (k=0; k < mplss->labels && enablempls; k++) { + printw("\n [MPLS: Lbl %lu Exp %u S %u TTL %u]", mplss->label[k], mplss->exp[k], mplss->s[k], mplss->ttl[k]); + } attroff(A_BOLD); } diff --git a/display.h b/display.h index 87be8a1..91f863d 100644 --- a/display.h +++ b/display.h @@ -21,7 +21,7 @@ /* Don't put a trailing comma in enumeration lists. Some compilers (notably the one on Irix 5.2) do not like that. -- REW */ enum { ActionNone, ActionQuit, ActionReset, ActionDisplay, - ActionClear, ActionPause, ActionResume, ActionDNS, + ActionClear, ActionPause, ActionResume, ActionMPLS, ActionDNS, ActionScrollDown, ActionScrollUp }; enum { DisplayReport, DisplayCurses, DisplayGTK, DisplaySplit, DisplayRaw, DisplayXML, DisplayCSV, DisplayTXT}; diff --git a/mtr.8 b/mtr.8 index 7321bd9..694c631 100644 --- a/mtr.8 +++ b/mtr.8 @@ -8,7 +8,7 @@ mtr \- a network diagnostic tool .SH SYNOPSIS .B mtr [\c -.B \-hvrctglspniu46\c +.B \-hvrctglspeniu46\c ] [\c .B \-\-help\c @@ -35,6 +35,9 @@ mtr \- a network diagnostic tool .B \-\-raw\c ] [\c +.B \-\-mpls\c +] +[\c .B \-\-no-dns\c ] [\c @@ -161,6 +164,16 @@ Use this option to force to use the curses based terminal interface (if available). +.TP +.B \-e +.TP +.B \-\-mpls +.br +Use this option to tell +.B mtr +to display information from ICMP extensions for MPLS (RFC 4950) +that are encoded in the response packets. + .TP .B \-n .TP diff --git a/mtr.c b/mtr.c index bc988b0..5f1b651 100644 --- a/mtr.c +++ b/mtr.c @@ -60,6 +60,7 @@ char *Hostname = NULL; char *InterfaceAddress = NULL; char LocalHostname[128]; int dns = 1; +int enablempls = 0; int cpacketsize = 64; /* default packet size */ int bitpattern = 0; int tos = 0; @@ -141,6 +142,7 @@ void parse_arg (int argc, char **argv) overload psize<0, ->rand(min,max) */ { "bitpattern", 1, 0, 'b' },/* overload b>255, ->rand(0,255) */ { "tos", 1, 0, 'Q' }, /* typeof service (0,255) */ + { "mpls", 0, 0, 'e' }, { "no-dns", 0, 0, 'n' }, { "address", 1, 0, 'a' }, { "first-ttl", 1, 0, 'f' }, /* -f & -m are borrowed from traceroute */ @@ -155,7 +157,7 @@ void parse_arg (int argc, char **argv) while(1) { /* added f:m:o: byMin */ opt = getopt_long(argc, argv, - "vhrwxtglpo:i:c:s:b:Q:na:f:m:u46", long_options, NULL); + "vhrwxtglpo:i:c:s:b:Q:ena:f:m:u46", long_options, NULL); if(opt == -1) break; @@ -199,6 +201,9 @@ void parse_arg (int argc, char **argv) case 'a': InterfaceAddress = optarg; break; + case 'e': + enablempls = 1; + break; case 'n': dns = 0; break; @@ -377,7 +382,7 @@ int main(int argc, char **argv) if (PrintHelp) { printf("usage: %s [-hvrwctglspniu46] [--help] [--version] [--report]\n" "\t\t[--report-wide] [--report-cycles=COUNT] [--curses] [--gtk]\n" - "\t\t[--raw] [--split] [--no-dns] [--address interface]\n" /* BL */ + "\t\t[--raw] [--split] [--mpls] [--no-dns] [--address interface]\n" /* BL */ "\t\t[--psize=bytes/-s bytes]\n" /* ok */ "\t\t[--report-wide|-w] [-u]\n" /* rew */ "\t\t[--interval=SECONDS] HOSTNAME [PACKETSIZE]\n", argv[0]); diff --git a/mtr.h b/mtr.h index 2f5e72b..9cfee0b 100644 --- a/mtr.h +++ b/mtr.h @@ -58,6 +58,7 @@ typedef struct in6_addr ip_t; typedef struct in_addr ip_t; #endif +extern int enablempls; extern int dns; extern int use_dns; diff --git a/net.c b/net.c index 4609da8..bd7ee41 100644 --- a/net.c +++ b/net.c @@ -122,6 +122,8 @@ struct nethost { int transit; int saved[SAVED_PINGS]; int saved_seq_offset; + struct mplslen mpls; + struct mplslen mplss[MAXPATH]; }; @@ -434,7 +436,7 @@ void net_send_query(int index) /* We got a return on something we sent out. Record the address and time. */ -void net_process_ping(int seq, void * addr, struct timeval now) +void net_process_ping(int seq, struct mplslen mpls, void * addr, struct timeval now) { int index; int totusec; @@ -467,10 +469,12 @@ void net_process_ping(int seq, void * addr, struct timeval now) (void *) &unspec_addr, af ) == 0 ) { /* should be out of if as addr can change */ addrcpy( (void *) &(host[index].addr), addrcopy, af ); + host[index].mpls = mpls; display_rawhost(index, (void *) &(host[index].addr)); /* multi paths by Min */ addrcpy( (void *) &(host[index].addrs[0]), addrcopy, af ); + host[index].mplss[0] = mpls; } else { for( i=0; i 160) + decodempls(num, packet, &mpls, 156); + break; #ifdef ENABLE_IPV6 case AF_INET6: @@ -632,6 +645,10 @@ void net_process_return(void) header = (struct ICMPHeader *) ( packet + sizeof (struct ICMPHeader) + sizeof (struct ip6_hdr) ); + + if(num > 140) + decodempls(num, packet, &mpls, 136); + break; #endif } @@ -656,6 +673,10 @@ void net_process_return(void) udpheader = (struct UDPHeader *)(packet + sizeof (struct IPHeader) + sizeof (struct ICMPHeader) + sizeof (struct IPHeader)); + + if(num > 160) + decodempls(num, packet, &mpls, 156); + break; #ifdef ENABLE_IPV6 case AF_INET6: @@ -665,6 +686,10 @@ void net_process_return(void) udpheader = (struct UDPHeader *) ( packet + sizeof (struct ICMPHeader) + sizeof (struct ip6_hdr) ); + + if(num > 140) + decodempls(num, packet, &mpls, 136); + break; #endif } @@ -674,7 +699,7 @@ void net_process_return(void) } if (sequence) - net_process_ping(sequence, (void *)fromaddress, now); + net_process_ping (sequence, mpls, (void *) fromaddress, now); } @@ -689,6 +714,15 @@ ip_t *net_addrs(int at, int i) return (ip_t *)&(host[at].addrs[i]); } +void *net_mpls(int at) +{ + return (struct mplslen *)&(host[at].mplss); +} + +void *net_mplss(int at, int i) +{ + return (struct mplslen *)&(host[at].mplss[i]); +} int net_loss(int at) { @@ -1261,3 +1295,42 @@ void addrcpy( char * a, char * b, int af ) { #endif } } + +/* Decode MPLS */ +void decodempls(int num, char *packet, struct mplslen *mpls, int offset) { + + int i; + unsigned int ext_ver, ext_res, ext_chk, obj_hdr_len; + u_char obj_hdr_class, obj_hdr_type; + + /* loosely derived from the traceroute-nanog.c + * decoding by Jorge Boncompte */ + ext_ver = packet[offset]>>4; + ext_res = (packet[offset]&15)+ packet[offset+1]; + ext_chk = ((unsigned int)packet[offset+2]<<8)+packet[offset+3]; + + /* Check for ICMP extension header */ + if (ext_ver == 2 && ext_res == 0 && ext_chk != 0 && num >= (offset+6)) { + obj_hdr_len = ((int)packet[offset+4]<<8)+packet[offset+5]; + obj_hdr_class = packet[offset+6]; + obj_hdr_type = packet[offset+7]; + + /* make sure we have an MPLS extension */ + if (obj_hdr_len >= 8 && obj_hdr_class == 1 && obj_hdr_type == 1) { + /* how many labels do we have? will be at least 1 */ + mpls->labels = (obj_hdr_len-4)/4; + + /* save all label objects */ + for(i=0; (ilabels) && (i < MAXLABELS) && (num >= (offset+8)+(i*4)); i++) { + + /* piece together the 20 byte label value */ + mpls->label[i] = ((unsigned long) (packet[(offset+8)+(i*4)] << 12 & 0xff000) + + (unsigned int) (packet[(offset+9)+(i*4)] << 4 & 0xff0) + + (packet[(offset+10)+(i*4)] >> 4 & 0xf)); + mpls->exp[i] = (packet[(offset+10)+(i*4)] >> 1) & 0x7; + mpls->s[i] = (packet[(offset+10)+(i*4)] & 0x1); /* should be 1 if only one label */ + mpls->ttl[i] = packet[(offset+11)+(i*4)]; + } + } + } +} diff --git a/net.h b/net.h index 6f05c6b..6e2c172 100644 --- a/net.h +++ b/net.h @@ -40,6 +40,8 @@ int net_max(void); int net_min(void); int net_last(int at); ip_t * net_addr(int at); +void * net_mpls(int at); +void * net_mplss(int, int); int net_loss(int at); int net_drop(int at); int net_last(int at); @@ -86,6 +88,7 @@ void addrcpy( char * a, char * b, int af ); #define MAXPACKET 4470 /* largest test packet size */ #define MINPACKET 28 /* 20 bytes IP header and 8 bytes ICMP or UDP */ +#define MAXLABELS 8 /* http://kb.juniper.net/KB2190 (+ 3 just in case) */ /* stuff used by display such as report, curses... --Min */ #define MAXFLD 20 /* max stats fields to display */ @@ -119,3 +122,14 @@ extern unsigned char fld_active[]; extern char available_options[]; ip_t unspec_addr; + +/* MPLS label object */ +struct mplslen { + unsigned long label[MAXLABELS]; /* label value */ + uint8 exp[MAXLABELS]; /* experimental bits */ + uint8 ttl[MAXLABELS]; /* MPLS TTL */ + char s[MAXLABELS]; /* bottom of stack */ + char labels; /* how many labels did we get? */ +}; + +void decodempls(int, char *, struct mplslen *, int); diff --git a/report.c b/report.c index 34ea114..9834128 100644 --- a/report.c +++ b/report.c @@ -52,7 +52,8 @@ void report_open(void) void report_close(void) { - int i, j, at, max, z, w; + int i, j, k, at, max, z, w; + struct mplslen *mpls, *mplss; ip_t *addr; ip_t *addr2 = NULL; char name[81]; @@ -102,6 +103,7 @@ void report_close(void) at = net_min(); for(; at < max; at++) { addr = net_addr(at); + mpls = net_mpls(at); if( addrcmp( (void *) addr, (void *) &unspec_addr, af ) == 0 ) { sprintf(name, "???"); } else { @@ -138,24 +140,47 @@ void report_close(void) * This feature show 'loadbalances' on routes */ - /* z is starting at 1 because addrs[0] is the same that addr */ + /* z is starting at 1 because addrs[0] is the same that addr */ for (z = 1; z < MAXPATH ; z++) { - addr2 = net_addrs(at, z); - int found = 0; - if ((addrcmp ((void *) &unspec_addr, (void *) addr2, af)) == 0) - break; + addr2 = net_addrs(at, z); + mplss = net_mplss(at, z); + int found = 0; + if ((addrcmp ((void *) &unspec_addr, (void *) addr2, af)) == 0) + break; for (w = 0; w < z; w++) /* Thales -- Ok... checking if there are ips repeated on same hop */ - if ((addrcmp ((void *) addr2, (void *) net_addrs (at,w), af)) == 0) { - found = 1; - break; - } - if (!found) { - if (z == 1) + if ((addrcmp ((void *) addr2, (void *) net_addrs (at,w), af)) == 0) { + found = 1; + break; + } + + if (!found) { + + if (mpls->labels && z == 1 && enablempls) { + for (k=0; k < mpls->labels; k++) { + printf(" | |+-- [MPLS: Lbl %lu Exp %u S %u TTL %u]\n", mpls->label[k], mpls->exp[k], mpls->s[k], mpls->ttl[k]); + } + } + + if (z == 1) { printf (" | `|-- %s\n", strlongip(addr2)); - else + for (k=0; k < mplss->labels && enablempls; k++) { + printf(" | +-- [MPLS: Lbl %lu Exp %u S %u TTL %u]\n", mplss->label[k], mplss->exp[k], mplss->s[k], mplss->ttl[k]); + } + } else { printf (" | |-- %s\n", strlongip(addr2)); - } + for (k=0; k < mplss->labels && enablempls; k++) { + printf(" | +-- [MPLS: Lbl %lu Exp %u S %u TTL %u]\n", mplss->label[k], mplss->exp[k], mplss->s[k], mplss->ttl[k]); + } + } + } + } + + /* No multipath */ + if(mpls->labels && z == 1 && enablempls) { + for (k=0; k < mpls->labels; k++) { + printf(" | +-- [MPLS: Lbl %lu Exp %u S %u TTL %u]\n", mpls->label[k], mpls->exp[k], mpls->s[k], mpls->ttl[k]); + } } } } diff --git a/select.c b/select.c index 6604f49..e7a8237 100644 --- a/select.c +++ b/select.c @@ -43,8 +43,6 @@ static struct timeval intervaltime; int display_offset = 0; -#define GRACETIME (5 * 1000*1000) - void select_loop(void) { fd_set readfd; int anyset = 0; @@ -53,11 +51,8 @@ void select_loop(void) { int NumPing = 0; int paused = 0; struct timeval lasttime, thistime, selecttime; - struct timeval startgrace, stopgrace; int dt; int rv; - int graceperiod = 0; - gettimeofday(&lasttime, NULL); @@ -92,6 +87,7 @@ void select_loop(void) { selecttime.tv_usec = 0; rv = select(maxfd, (void *)&readfd, NULL, NULL, &selecttime); + } else { if(Interactive) display_redraw(); @@ -101,21 +97,10 @@ void select_loop(void) { (thistime.tv_sec == lasttime.tv_sec + intervaltime.tv_sec && thistime.tv_usec >= lasttime.tv_usec + intervaltime.tv_usec)) { lasttime = thistime; - if (!graceperiod) { - if(NumPing >= MaxPing && (!Interactive || ForceMaxPing)) { - graceperiod=1; - startgrace=thistime; - //gettimeofday (&startgrace, NULL); - } - if (net_send_batch()) - NumPing++; - } - } - if (graceperiod) { - // gettimeofday(&thistime, NULL); - dt = (thistime.tv_usec - startgrace.tv_usec) + - 1000000 * (thistime.tv_sec - startgrace.tv_sec); - if (dt > GRACETIME) return; + if(NumPing >= MaxPing && (!Interactive || ForceMaxPing)) + return; + if (net_send_batch()) + NumPing++; } selecttime.tv_usec = (thistime.tv_usec - lasttime.tv_usec); @@ -189,6 +174,10 @@ void select_loop(void) { case ActionResume: paused=0; break; + case ActionMPLS: + enablempls = !enablempls; + display_clear(); + break; case ActionDNS: if (dns) { use_dns = !use_dns;