Only in mtr-0.72-new: .deps
diff -ur mtr-0.72/ChangeLog mtr-0.72-new/ChangeLog
--- mtr-0.72/ChangeLog	2004-08-26 03:56:53.000000000 -0400
+++ mtr-0.72-new/ChangeLog	2008-04-14 10:33:16.000000000 -0400
@@ -1,3 +1,24 @@
+2008-04-13  Mark Kamichoff  <prox@prolixium.com>
+
+	* Changed the UDP sequence number storage to be source port -
+	UDP_PORT_MIN.  This allows us 100 packets to be in-flight at any
+	time, without losing track.  Right now we're using the classic
+	traceroute ports, but might need to increase this in the future.
+	* Added UDP checksum calculation for both IPv4 and IPv6.  Source
+	address _must_ be specified at this point, due to a problem with
+	getsockname(2) not filling in the address structure completely.
+	* Added a line in the curses output to display protocol type.
+	* Fixed IPv6 support (see first entry).
+
+2008-04-11  Mark Kamichoff  <prox@prolixium.com>
+
+	* Fixed bug displaying localaddr (always displayed ANY)
+
+2007-03-27  Mark Kamichoff  <prox@prolixium.com>
+
+	* Preliminary UDP (-P udp) support.  IPv6 doesn't work with it,
+	yet, since we're using the IP ID field for sequence numbers.
+
 2002-03-06  Cougar <cougar@random.ee>
 	+ If hop doesn't respond, draw its name in red (GTK) or bold (curses)
 
Only in mtr-0.72-new: Makefile
Only in mtr-0.72-new: config.h
Only in mtr-0.72-new: config.log
Only in mtr-0.72-new: config.status
diff -ur mtr-0.72/curses.c mtr-0.72-new/curses.c
--- mtr-0.72/curses.c	2006-09-29 15:40:09.000000000 -0400
+++ mtr-0.72-new/curses.c	2008-04-14 10:33:16.000000000 -0400
@@ -75,6 +75,7 @@
 extern int tos;
 extern float WaitTime;
 extern int af;
+extern int protocol;
 
 void pwcenter(char *str) 
 {
@@ -506,6 +507,22 @@
   time(&t);
   mvprintw(1, maxx-25, ctime(&t));
 
+  /* display protocol -- MK */
+  if(protocol == 17) {
+    mvprintw(2, 0, "Protocol: UDP\n");
+  } else {
+#ifdef ENABLE_IPV6
+    switch ( af ) {
+    case AF_INET6:
+      mvprintw(2, 0, "Protocol: ICMPv6\n");
+      break;
+#endif
+    case AF_INET:
+      mvprintw(2, 0, "Protocol: ICMP\n");
+      break;
+    }
+  }
+
   printw("Keys:  ");
   attron(A_BOLD); printw("H"); attroff(A_BOLD); printw("elp   ");
   attron(A_BOLD); printw("D"); attroff(A_BOLD); printw("isplay mode   ");
Only in mtr-0.72-new: curses.o
Only in mtr-0.72-new: display.o
Only in mtr-0.72-new: dns.o
Only in mtr-0.72-new: getopt.o
Only in mtr-0.72-new: getopt1.o
Only in mtr-0.72-new/img: Makefile
Only in mtr-0.72-new: mtr
diff -ur mtr-0.72/mtr.c mtr-0.72-new/mtr.c
--- mtr-0.72/mtr.c	2006-09-29 15:38:49.000000000 -0400
+++ mtr-0.72-new/mtr.c	2008-04-14 10:33:16.000000000 -0400
@@ -65,6 +65,7 @@
 int   bitpattern = 0;
 int   tos = 0;
 int af = DEFAULT_AF;
+int   protocol = 1;             /* protocol number: icmp or udp */
 
                                 /* begin ttl windows addByMin */
 int  fstTTL = 1;                /* default start at first hop */
@@ -145,6 +146,7 @@
     { "max-ttl", 1, 0, 'm' },
     { "inet", 0, 0, '4' },	/* IPv4 only */
     { "inet6", 0, 0, '6' },	/* IPv6 only */
+    { "protocol", 1, 0, 'P' },
     { 0, 0, 0, 0 }
   };
 
@@ -152,7 +154,7 @@
   while(1) {
     /* added f:m:o: byMin */
     opt = getopt_long(argc, argv,
-		      "vhrxtglpo:i:c:s:b:Q:na:f:m:46", long_options, NULL);
+		      "vhrxtglpo:i:c:s:b:Q:na:f:m:46P:", long_options, NULL);
     if(opt == -1)
       break;
 
@@ -264,6 +266,15 @@
       fprintf( stderr, "IPv6 not enabled.\n" );
       break;
 #endif
+    case 'P':
+      if (!strcasecmp("icmp", optarg)) {
+	   protocol = 1;
+	 } else if (!strcasecmp("udp", optarg)) {
+	   protocol = 17;
+	 } else {
+        fprintf (stderr, "mtr: unsupported protocol\n");
+        exit (1);
+	 }
     }
   }
 
@@ -322,8 +333,21 @@
   struct sockaddr_in6 * sa6;
 #endif
 
-  /*  Get the raw sockets first thing, so we can drop to user euid immediately  */
+  /* reset the random seed */
+  srand (getpid());
+  
+  display_detect(&argc, &argv);
+
+  /* The field options are now in a static array all together, 
+     but that requires a run-time initialization. -- REW */
+  init_fld_options ();
+
+  parse_mtr_options (getenv ("MTR_OPTIONS"));
+
+  parse_arg (argc, argv);
 
+  /* get raw sockets ASAP, so we can drop to user euid immediately *
+   * we need to do this after parsing options, to know the proto   */
   if ( ( net_preopen_result = net_preopen () ) ) {
     fprintf( stderr, "mtr: unable to get raw sockets.\n" );
     exit( EXIT_FAILURE );
@@ -341,29 +365,16 @@
     exit(1);
   }
 
-  /* reset the random seed */
-  srand (getpid());
-  
-  display_detect(&argc, &argv);
-
-  /* The field options are now in a static array all together, 
-     but that requires a run-time initialization. -- REW */
-  init_fld_options ();
-
-  parse_mtr_options (getenv ("MTR_OPTIONS"));
-
-  parse_arg (argc, argv);
-
   if (PrintVersion) {
     printf ("mtr " VERSION "\n");
     exit(0);
   }
 
   if (PrintHelp) {
-    printf("usage: %s [-hvrctglspni46] [--help] [--version] [--report]\n"
+    printf("usage: %s [-hvrctglspni46P] [--help] [--version] [--report]\n"
 	   "\t\t[--report-cycles=COUNT] [--curses] [--gtk]\n"
            "\t\t[--raw] [--split] [--no-dns] [--address interface]\n" /* BL */
-           "\t\t[--psize=bytes/-s bytes]\n"            /* ok */
+           "\t\t[--psize=bytes/-s bytes] [--protocol protocol]\n"	/* MK */
 	   "\t\t[--interval=SECONDS] HOSTNAME [PACKETSIZE]\n", argv[0]);
     exit(0);
   }
Only in mtr-0.72-new: mtr.o
diff -ur mtr-0.72/net.c mtr-0.72-new/net.c
--- mtr-0.72/net.c	2006-09-29 15:31:01.000000000 -0400
+++ mtr-0.72-new/net.c	2008-04-14 10:33:16.000000000 -0400
@@ -55,6 +55,25 @@
 };
 
 
+/*  Structure of a UDP header  */
+struct UDPHeader {
+  uint16 sport;
+  uint16 dport;
+  uint16 len;
+  uint16 checksum;
+};
+
+
+/*  UDP pseudo header for IPv4 (RFC768)  */
+struct UDPpseudo {
+  uint32 saddr;
+  uint32 daddr;
+  uint8 zeroes;
+  uint8 proto;
+  uint16 UDPLength;
+};
+
+
 /*  Structure of an IP header.  */
 struct IPHeader {
   uint8 version;
@@ -68,7 +87,11 @@
   uint32 saddr;
   uint32 daddr;
 };
-  
+
+
+/* for UDP */
+#define UDP_PORT_MIN	33434
+#define UDP_PORT_MAX	33534
 
 #define ICMP_ECHO		8
 #define ICMP_ECHOREPLY		0
@@ -78,6 +101,8 @@
 
 #define ICMP_TIME_EXCEEDED	11
 
+#define ICMP_PORT_UNREACH	3
+
 #ifndef SOL_IP
 #define SOL_IP 0
 #endif
@@ -155,6 +180,11 @@
 ip_t * sourceaddress;
 ip_t * remoteaddress;
 
+/* multiplier for UDP dport wrap */
+int    UDPmult = 0;
+int    PreWrap = 0;
+char   UDPWrapFlag = 0;
+
 /* XXX How do I code this to be IPV6 compatible??? -- REW */
 #ifdef ENABLE_IPV6
 char localaddr[INET6_ADDRSTRLEN];
@@ -175,7 +205,7 @@
 extern int bitpattern;		/* packet bit pattern used by ping */
 extern int tos;			/* type of service set in ping packet*/
 extern int af;			/* address family of remote target */
-
+extern int protocol;	/* proto number: icmp, udp, or tcp (not yet) */
 
 /* return the number of microseconds to wait before sending the next
    ping */
@@ -230,18 +260,37 @@
 }
 
 
+/* MK: done */
 /*  Attempt to find the host at a particular number of hops away  */
 void net_send_query(int index) 
 {
   /*ok  char packet[sizeof(struct IPHeader) + sizeof(struct ICMPHeader)];*/
   char packet[MAXPACKET];
   struct IPHeader *ip = (struct IPHeader *) packet;
-  struct ICMPHeader *icmp;
+  struct ICMPHeader *icmp = NULL;
+  struct UDPHeader *udp = NULL;
+  uint16 tport = 0;
+
+  /* for UDP checksumming */
+  struct UDPpseudo udpp;
+#ifdef ENABLE_IPV6
+  int UDP6ckoffset = 6;
+#endif
+  char * UDPpseudoall;
+
+  /* temp for local UDP port */
+  struct sockaddr_in saNI;
+  struct sockaddr_in6 sa6NI;
+  uint16 sport = 0;
+
+  /* temp for new_sequence for UDP only */
+  int UDPns = 0;
 
   /*ok  int packetsize = sizeof(struct IPHeader) + sizeof(struct ICMPHeader) + datasize;*/
   int rv;
   static int first=1;
-  int ttl, iphsize = 0, echotype = 0, salen = 0;
+  int ttl, iphsize = 0, echotype = 0;
+  unsigned int salen = 0;
 
   ttl = index + 1;
 
@@ -265,43 +314,135 @@
 #else
     iphsize = sizeof (struct IPHeader);
 
-  ip->version = 0x45;
-  ip->tos = tos;
-  ip->len = BSDfix ? abs(packetsize): htons (abs(packetsize));
-  ip->id = 0;
-  ip->frag = 0;    /* 1, if want to find mtu size? Min */
+    ip->version = 0x45;
+    ip->tos = tos;
+    ip->len = BSDfix ? abs(packetsize): htons (abs(packetsize));
+    ip->id = 0;
+    ip->frag = 0;    /* 1, if want to find mtu size? Min */
     ip->ttl = ttl;
-  ip->protocol = IPPROTO_ICMP;
-  ip->check = 0;
+    if ( protocol == 1 ) {
+      ip->protocol = IPPROTO_ICMP;
+    } else if ( protocol == 17 ) {
+      ip->protocol = IPPROTO_UDP;
+    }
+    ip->check = 0;
 
-  /* BSD needs the source address here, Linux & others do not... */
+    /* BSD needs the source address here, Linux & others do not... */
     addrcpy( (void *) &(ip->saddr), (void *) &(ssa4->sin_addr), AF_INET );
     addrcpy( (void *) &(ip->daddr), (void *) remoteaddress, AF_INET );
 #endif
-    echotype = ICMP_ECHO;
-    salen = sizeof (struct sockaddr_in);
+    if(protocol == 1) {
+      echotype = ICMP_ECHO;
+    }
+    salen = sizeof (saNI);
     break;
 #ifdef ENABLE_IPV6
   case AF_INET6:
     iphsize = 0;
     if ( setsockopt( sendsock, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
-                     &ttl, sizeof ttl ) ) {
+        &ttl, sizeof ttl ) ) {
       perror( "setsockopt IPV6_UNICAST_HOPS" );
       exit( EXIT_FAILURE);
     }
-    echotype = ICMP6_ECHO_REQUEST;
-    salen = sizeof (struct sockaddr_in6);
+    if(protocol == 1) {
+      echotype = ICMP6_ECHO_REQUEST;
+    }
+    salen = sizeof (sa6NI);
+    break;
+#endif
+  }
+
+  /* getsockname for kernel-assigned UDP sport     *
+   * also use this to get saddr for UDP cksum - MK */
+  switch ( af ) {
+  case AF_INET:
+    if (getsockname(sendsock, (struct sockaddr *) &saNI, &salen)) {
+      perror("mtr: getsockname");
+      exit( EXIT_FAILURE);
+    }
+    sport = saNI.sin_port;
+    break;
+#ifdef ENABLE_IPV6
+  case AF_INET6:
+    if (getsockname(sendsock, (struct sockaddr *) &sa6NI, &salen)) {
+      perror("mtr: getsockname");
+      exit( EXIT_FAILURE);
+    }
+    sport = sa6NI.sin6_port;
     break;
 #endif
   }
 
-  icmp = (struct ICMPHeader *)(packet + iphsize);
-  icmp->type     = echotype;
-  icmp->code     = 0;
-  icmp->checksum = 0;
-  icmp->id       = getpid();
-  icmp->sequence = new_sequence(index);
-  icmp->checksum = checksum(icmp, abs(packetsize) - iphsize);
+  if (protocol == 1) {
+    icmp = (struct ICMPHeader *)(packet + iphsize);
+    icmp->type     = echotype;
+    icmp->code     = 0;
+    icmp->checksum = 0;
+    icmp->id       = getpid();
+    icmp->sequence = new_sequence(index);
+    icmp->checksum = checksum(icmp, abs(packetsize) - iphsize);
+  } else if (protocol == 17) {
+    udp = (struct UDPHeader *)(packet + iphsize);
+    udp->sport = ntohs(sport);
+    udp->len = htons(abs(packetsize) - iphsize);
+
+    /* What do we do about sequence numbers?  The UDP header
+	* doesn't give us any room to store one, and putting it in the
+	* payload doesn't help, since the return ICMP TTL exceeded or UDP
+	* port unreachables won't return the payload.  So, we'll pull a
+	* classic traceroute and cycle between UDP_PORT_MIN and
+	* UDP_PORT_MAX and multiplex off of those.  We'll only be able to
+	* retain information about MAX-MIN in-flight packets at any time,
+	* though.  It could be a problem if there is a very long and latent
+	* path, though. - MK */
+
+    tport = (UDPns = new_sequence(index)) + UDP_PORT_MIN;
+    tport -= UDPmult * (UDP_PORT_MAX - UDP_PORT_MIN);
+    /* stay within the range */
+    while(tport > UDP_PORT_MAX) {
+      tport -= (UDP_PORT_MAX - UDP_PORT_MIN);
+      UDPmult++;
+      UDPWrapFlag = 1;
+    }
+    udp->dport = htons(tport);
+
+    /* Generate a UDP checksum, based on pseudo-header, which
+	* is a combination of the IP source + IP dest + IP proto + IP UDP len
+     * + UDP header + UDP payload -- MK */
+    switch ( af ) {
+    case AF_INET:  /* via RFC768 */
+      /* can't calculate unless we have source addr */
+      if(saNI.sin_addr.s_addr) {
+        udpp.saddr = saNI.sin_addr.s_addr;   /* from getsockname */
+        udpp.daddr = rsa4->sin_addr.s_addr;
+        udpp.zeroes = 0;
+        udpp.proto = IPPROTO_UDP;
+        udpp.UDPLength = htons(abs(packetsize) - iphsize);
+  
+        UDPpseudoall = (char *) malloc(abs(packetsize)); /* over-allocate */
+        memset(UDPpseudoall, (unsigned char) abs(bitpattern), abs(packetsize));
+        memcpy(UDPpseudoall, &udpp, sizeof(struct UDPpseudo));
+        UDPpseudoall += sizeof(struct UDPpseudo);
+        memcpy(UDPpseudoall, udp, sizeof(struct UDPHeader));
+        UDPpseudoall -= sizeof(struct UDPpseudo);
+        /* XXX what to do if len odd or if csum is 0? */
+        udp->checksum = checksum(UDPpseudoall, (abs(packetsize) - iphsize) + sizeof(struct UDPpseudo));
+      } else {
+        udp->checksum = 0;
+      }
+      break;
+#ifdef ENABLE_IPV6
+    case AF_INET6:  /* via RFC2460, kernel does it */
+      udp->checksum = 0;
+	 if(setsockopt(sendsock, IPPROTO_IPV6, IPV6_CHECKSUM,
+          &UDP6ckoffset, sizeof(UDP6ckoffset)) == -1) {
+        perror("mtr: setsockopt");
+        exit(EXIT_FAILURE);
+      }
+      break;
+#endif
+    }
+  }
 
   switch ( af ) {
   case AF_INET:
@@ -309,7 +450,11 @@
     break;
   }
 
-  gettimeofday(&sequence[icmp->sequence].time, NULL);
+  if(protocol == 17) {
+    gettimeofday(&sequence[UDPns].time, NULL);
+  } else {
+    gettimeofday(&sequence[icmp->sequence].time, NULL);
+  }
 
   rv = sendto(sendsock, packet, abs(packetsize), 0, 
 	      remotesockaddr, salen);
@@ -433,6 +578,7 @@
 }
 
 
+/* MK: done */
 /*  We know a packet has come in, because the main select loop has called us,
     now we just need to read it, see if it is for us, and if it is a reply 
     to something we sent, then call net_process_ping()  */
@@ -449,10 +595,12 @@
   struct sockaddr_in * fsa4 = (struct sockaddr_in *) &fromsockaddr_struct;
   socklen_t fromsockaddrsize;
   int num;
-  struct ICMPHeader *header = NULL;
+  struct ICMPHeader *InnerICMP = NULL;
+  struct ICMPHeader *OuterICMP = NULL;
+  struct UDPHeader *UDP = NULL;
   struct timeval now;
   ip_t * fromaddress = NULL;
-  int echoreplytype = 0, timeexceededtype = 0;
+  int echoreplytype = 0, timeexceededtype = 0, portunreachabletype = 0;
 
   gettimeofday(&now, NULL);
   switch ( af ) {
@@ -461,6 +609,7 @@
     fromaddress = (ip_t *) &(fsa4->sin_addr);
     echoreplytype = ICMP_ECHOREPLY;
     timeexceededtype = ICMP_TIME_EXCEEDED;
+    portunreachabletype = ICMP_PORT_UNREACH;
     break;
 #ifdef ENABLE_IPV6
   case AF_INET6:
@@ -468,62 +617,148 @@
     fromaddress = (ip_t *) &(fsa6->sin6_addr);
     echoreplytype = ICMP6_ECHO_REPLY;
     timeexceededtype = ICMP6_TIME_EXCEEDED;
+    portunreachabletype = ICMP6_DST_UNREACH_ADMIN;
     break;
 #endif
   }
 
   num = recvfrom(recvsock, packet, MAXPACKET, 0, 
-		 fromsockaddr, &fromsockaddrsize);
+      fromsockaddr, &fromsockaddrsize);
 
   switch ( af ) {
   case AF_INET:
-    if((size_t) num < sizeof(struct IPHeader) + sizeof(struct ICMPHeader))
-      return;
-    header = (struct ICMPHeader *)(packet + sizeof(struct IPHeader));
-    break;
-#ifdef ENABLE_IPV6
-  case AF_INET6:
-    if(num < sizeof(struct ICMPHeader))
-      return;
+    if(protocol == 17) {
 
-    header = (struct ICMPHeader *) packet;
-    break;
-#endif
-  }
-  if (header->type == echoreplytype) {
-    if(header->id != (uint16)getpid())
-      return;
+      /* make sure we have a ICMP packet with an embedded UDP header */
+      if((size_t) num < sizeof(struct IPHeader) + 
+                        sizeof(struct ICMPHeader) + 
+                        sizeof(struct IPHeader) + 
+                        sizeof(struct UDPHeader))
+        return;
 
-    net_process_ping (header->sequence, (void *) fromaddress, now);
-  } else if (header->type == timeexceededtype) {
-    switch ( af ) {
-    case AF_INET:
+      /* extract the ICMP header */
+      OuterICMP = (struct ICMPHeader *)(packet + sizeof(struct IPHeader));
+      /* extract the inner UDP header */
+      UDP = (struct UDPHeader *)(packet + sizeof(struct IPHeader) + 
+                                          sizeof(struct ICMPHeader) +
+                                          sizeof(struct IPHeader));
+
+      if(OuterICMP->type == portunreachabletype ||
+         OuterICMP->type == timeexceededtype) {
+        /* check ports for a minimal sanity check *
+         * still need to really do good check XXX */
+        if(ntohs(UDP->dport) <= UDP_PORT_MAX &&
+           ntohs(UDP->dport) >= UDP_PORT_MIN) {
+          if(UDPWrapFlag) {
+            /* we wrapped */
+            PreWrap += (UDP_PORT_MAX - UDP_PORT_MIN);
+            UDPWrapFlag = 0;
+          }
+
+          net_process_ping (PreWrap + (ntohs(UDP->dport) - UDP_PORT_MIN), (void *) fromaddress, now);
+        } else {
+          return;
+        }
+      } else {
+        /* returned unknown ICMP type */
+        return;
+      }
+      
+    } else {
+
+      /* make sure we have any kind of ICMP packet */
+      if((size_t) num < sizeof(struct IPHeader) + sizeof(struct ICMPHeader))
+        return;
+      OuterICMP = (struct ICMPHeader *)(packet + sizeof(struct IPHeader));
 
-      if ((size_t) num < sizeof(struct IPHeader) + 
-                         sizeof(struct ICMPHeader) + 
-                         sizeof (struct IPHeader) + 
-                         sizeof (struct ICMPHeader))
+      if(OuterICMP->type == echoreplytype) {
+          if(OuterICMP->id != (uint16)getpid())
+            return;
+
+          net_process_ping (OuterICMP->sequence, (void *) fromaddress, now);
+      } else if(OuterICMP->type == timeexceededtype) {
+        if((size_t) num < sizeof(struct IPHeader) +
+                          sizeof(struct ICMPHeader) + 
+                          sizeof(struct IPHeader) +
+                          sizeof(struct ICMPHeader))
+          return;
+        InnerICMP = (struct ICMPHeader *)(packet + sizeof(struct IPHeader) +
+                                                   sizeof(struct ICMPHeader) +
+                                                   sizeof(struct IPHeader));
+        if(InnerICMP->id != (uint16)getpid())
+          return;
+
+        net_process_ping (InnerICMP->sequence, (void *) fromaddress, now);
+      } else {
+        /* some other type, ignore */
         return;
-      header = (struct ICMPHeader *)(packet + sizeof (struct IPHeader) + 
-                                              sizeof (struct ICMPHeader) + 
-                                              sizeof (struct IPHeader));
+      }
+    }
     break;
+
 #ifdef ENABLE_IPV6
-    case AF_INET6:
-      if ( num < sizeof (struct ICMPHeader) + 
-                 sizeof (struct ip6_hdr) + sizeof (struct ICMPHeader) )
+  /* IPv6 does not return us the real header, so first bytes belongs to ICMP - MK */
+  case AF_INET6:
+    if(protocol == 17) {
+
+      if((size_t) num < sizeof(struct ICMPHeader) + 
+                        sizeof(struct ip6_hdr) + 
+                        sizeof(struct UDPHeader))
         return;
-      header = (struct ICMPHeader *) ( packet + 
-                                       sizeof (struct ICMPHeader) +
-                                       sizeof (struct ip6_hdr) );
-      break;
-#endif
-    }
 
-    if (header->id != (uint16)getpid())
-      return;
+      OuterICMP = (struct ICMPHeader *) packet;
+      UDP = (struct UDPHeader *)(packet + sizeof(struct ICMPHeader) +
+                                          sizeof(struct ip6_hdr));
+
+      if(OuterICMP->type == portunreachabletype ||
+	    OuterICMP->type == timeexceededtype) {
+        if(ntohs(UDP->dport) <= UDP_PORT_MAX &&
+           ntohs(UDP->dport) >= UDP_PORT_MIN) {
+          if(UDPWrapFlag) {
+            /* we wrapped */
+            PreWrap += (UDP_PORT_MAX - UDP_PORT_MIN);
+            UDPWrapFlag = 0;
+          }
+
+          net_process_ping (PreWrap + (ntohs(UDP->dport) - UDP_PORT_MIN), (void *) fromaddress, now);
+        } else {
+          return;
+        }
+      } else {
+        return;
+	 }
+      
+    } else {
+
+      /* make sure we have any kind of ICMP packet */
+      if((size_t) num < sizeof(struct ICMPHeader))
+        return;
+      OuterICMP = (struct ICMPHeader *) packet;
 
-    net_process_ping(header->sequence, (void *)fromaddress, now);
+      if(OuterICMP->type == echoreplytype) {
+          if(OuterICMP->id != (uint16)getpid())
+            return;
+
+          net_process_ping (OuterICMP->sequence, (void *) fromaddress, now);
+      } else if(OuterICMP->type == timeexceededtype) {
+        if((size_t) num < sizeof(struct ICMPHeader) + 
+                          sizeof(struct ip6_hdr) +
+                          sizeof(struct ICMPHeader))
+          return;
+        InnerICMP = (struct ICMPHeader *)(packet + sizeof(struct ICMPHeader) +
+                                                   sizeof(struct ip6_hdr));
+
+        if(InnerICMP->id != (uint16)getpid())
+          return;
+
+        net_process_ping (InnerICMP->sequence, (void *) fromaddress, now);
+      } else {
+        /* some other type, ignore */
+        return;
+      }
+    }
+    break;
+#endif
   }
 }
 
@@ -753,19 +988,28 @@
 }
 
 
+/* MK: done */
 int net_preopen(void) 
 {
   int trueopt = 1;
 
 #if !defined(IP_HDRINCL) && defined(IP_TOS) && defined(IP_TTL)
-  sendsock4 = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
+  if (protocol == 17) {
+    sendsock4 = socket(AF_INET, SOCK_RAW, IPPROTO_UDP);
+  } else {
+    sendsock4 = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
+  }
 #else
   sendsock4 = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
 #endif
   if (sendsock4 < 0) 
     return -1;
 #ifdef ENABLE_IPV6
-  sendsock6 = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
+  if (protocol == 17) {
+    sendsock6 = socket(AF_INET6, SOCK_RAW, IPPROTO_UDP);
+  } else {
+    sendsock6 = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
+  }
 #endif
 
 #ifdef IP_HDRINCL
@@ -787,16 +1031,8 @@
   return 0;
 }
 
- 
 int net_open(struct hostent * host) 
 {
-#ifdef ENABLE_IPV6
-  struct sockaddr_storage name_struct;
-#else
-  struct sockaddr_in name_struct; 
-#endif
-  struct sockaddr * name = (struct sockaddr *) &name_struct;
-  socklen_t len; 
 
   net_reset();
 
@@ -807,8 +1043,8 @@
     sendsock = sendsock4;
     recvsock = recvsock4;
     addrcpy( (void *) &(rsa4->sin_addr), host->h_addr, AF_INET );
-    sourceaddress = (ip_t *) &(ssa4->sin_addr);
     remoteaddress = (ip_t *) &(rsa4->sin_addr);
+    sourceaddress = (ip_t *) &(ssa4->sin_addr);
     break;
 #ifdef ENABLE_IPV6
   case AF_INET6:
@@ -819,8 +1055,8 @@
     sendsock = sendsock6;
     recvsock = recvsock6;
     addrcpy( (void *) &(rsa6->sin6_addr), host->h_addr, AF_INET6 );
-    sourceaddress = (ip_t *) &(ssa6->sin6_addr);
     remoteaddress = (ip_t *) &(rsa6->sin6_addr);
+    sourceaddress = (ip_t *) &(ssa6->sin6_addr);
     break;
 #endif
   default:
@@ -828,13 +1064,6 @@
     exit( EXIT_FAILURE );
   }
 
-  len = sizeof name_struct; 
-  getsockname (recvsock, name, &len);
-  sockaddrtop( name, localaddr, sizeof localaddr );
-#if 0
-  printf ("got localaddr: %s\n", localaddr); 
-#endif
-
   return 0;
 }
 
@@ -907,12 +1136,58 @@
 }
 
 
+/* MK: done */
 int net_set_interfaceaddress (char *InterfaceAddress)
 {
+#ifdef ENABLE_IPV6
+  const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
+#endif
   int len = 0;
 
-  if (!InterfaceAddress) return 0; 
+  /* hardcode for ANY */
+  if(!InterfaceAddress) {
+    switch ( af ) {
+    case AF_INET:
+      strcpy(localaddr, "0.0.0.0");
+      break;
+#ifdef ENABLE_IPV6
+    case AF_INET6:
+      strcpy(localaddr, "::");
+      break;
+#endif
+    }
+  }
+
+  /* if NO source addr was specified */
+  if (!InterfaceAddress && (protocol == 1)) return 0;
+
+  if (!InterfaceAddress && protocol == 17) {
+    /* we need to always bind the receiving UDP sock *
+	* here we just bind to anything                 */
+    sourcesockaddr->sa_family = af;
+    switch ( af ) {
+    case AF_INET:
+      ssa4->sin_port = htons(0);
+      ssa4->sin_addr.s_addr = htonl(INADDR_ANY);
+      len = sizeof (struct sockaddr);
+      break;
+#ifdef ENABLE_IPV6
+    case AF_INET6:
+      ssa6->sin6_port = htons(0);
+      ssa6->sin6_addr = in6addr_any;	/* defined above */
+      len = sizeof (struct sockaddr_in6);
+      break;
+#endif
+    }
+
+    if ( bind( sendsock, sourcesockaddr, len ) == -1 ) {
+      perror("mtr: failed to bind to interface");
+      return( 1 );
+    }
+    return 0; 
+  }
 
+  /* bind to specific addr */
   sourcesockaddr->sa_family = af;
   switch ( af ) {
   case AF_INET:
@@ -939,6 +1214,7 @@
     perror("mtr: failed to bind to interface");
       return( 1 );
   }
+  strcpy(localaddr, InterfaceAddress);
   return 0; 
 }
 
Only in mtr-0.72-new: net.o
Only in mtr-0.72-new: raw.o
Only in mtr-0.72-new: report.o
Only in mtr-0.72-new: select.o
Only in mtr-0.72-new: split.o
Only in mtr-0.72-new: stamp-h1
