diff -ur mtr-0.72/ChangeLog mtr-0.72-prox3/ChangeLog
--- mtr-0.72/ChangeLog	2004-08-26 03:56:53.000000000 -0400
+++ mtr-0.72-prox3/ChangeLog	2008-03-27 00:08:52.000000000 -0400
@@ -1,3 +1,8 @@
+2007-03-27  Mark Kamichoff <prox@prolixium.com>
+
+	* Preliminary UDP (-P udp) support.  IPv6 doesn't work with it,
+	yet.
+
 2002-03-06  Cougar <cougar@random.ee>
 	+ If hop doesn't respond, draw its name in red (GTK) or bold (curses)
 
diff -ur mtr-0.72/mtr.c mtr-0.72-prox3/mtr.c
--- mtr-0.72/mtr.c	2006-09-29 15:38:49.000000000 -0400
+++ mtr-0.72-prox3/mtr.c	2008-03-26 22:38:05.000000000 -0400
@@ -61,10 +61,11 @@
 char *InterfaceAddress = NULL;
 char  LocalHostname[128];
 int   dns = 1;
-int   cpacketsize = 64;          /* default packet size */
+int   cpacketsize = 66;         /* default packet size (for ICMP only) */
 int   bitpattern = 0;
 int   tos = 0;
-int af = DEFAULT_AF;
+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);
+	 }
     }
   }
 
@@ -360,10 +371,10 @@
   }
 
   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"	/* ok */
 	   "\t\t[--interval=SECONDS] HOSTNAME [PACKETSIZE]\n", argv[0]);
     exit(0);
   }
diff -ur mtr-0.72/net.c mtr-0.72-prox3/net.c
--- mtr-0.72/net.c	2006-09-29 15:31:01.000000000 -0400
+++ mtr-0.72-prox3/net.c	2008-03-27 00:00:32.000000000 -0400
@@ -55,9 +55,18 @@
 };
 
 
+/*  Structure of a UDP header  */
+struct UDPHeader {
+  uint16 sport;
+  uint16 dport;
+  uint16 len;
+  uint16 checksum;
+};
+
+
 /*  Structure of an IP header.  */
 struct IPHeader {
-  uint8 version;
+  uint8 version;	/* actually only first 4 bits */
   uint8 tos;
   uint16 len;
   uint16 id;
@@ -68,7 +77,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 +91,8 @@
 
 #define ICMP_TIME_EXCEEDED	11
 
+#define ICMP_PORT_UNREACH	3
+
 #ifndef SOL_IP
 #define SOL_IP 0
 #endif
@@ -175,7 +190,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,13 +245,20 @@
 }
 
 
+/* 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;
+
+  /* temp for local UDP port */
+  struct sockaddr_in saNI;
+  struct sockaddr_in6 sa6NI;
+  uint16 sport = 0;
 
   /*ok  int packetsize = sizeof(struct IPHeader) + sizeof(struct ICMPHeader) + datasize;*/
   int rv;
@@ -270,16 +292,24 @@
   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->ttl = ttl;
+  if ( protocol == 1 ) {
+    ip->protocol = IPPROTO_ICMP;
+  } else if ( protocol == 17 ) {
+    ip->protocol = IPPROTO_UDP;
+  } else if ( protocol == 6 ) {	/* not implemented */
+    ip->protocol = IPPROTO_TCP;
+  }
   ip->check = 0;
 
   /* 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:
@@ -289,19 +319,70 @@
       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
   }
 
-  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);
+  /* getsockname for kernel-assigned UDP sport */
+  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
+  }
+
+  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->dport = htons(UDP_PORT_MIN);	/* default for now */
+    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 put them
+	* in the IP ID field + the getpid().  It'll overflow, but that
+	* shouldn't be a problem as the PID won't change. - MK */
+    switch ( af ) {
+    case AF_INET:
+      ip->id = getpid() + new_sequence(index);
+	 break;
+    case AF_INET6:
+      /* XXX not done for IPv6, yet */
+      break;
+    }
+
+    /* We should probably 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 (RFC768).
+	* Right now we just set it to 0 that indicates no checksum, which
+	* still seems to be valid based on the RFC! - MK */
+    udp->checksum = 0;
+  }
 
   switch ( af ) {
   case AF_INET:
@@ -309,7 +390,18 @@
     break;
   }
 
-  gettimeofday(&sequence[icmp->sequence].time, NULL);
+  if(protocol == 17) {
+    switch ( af ) {
+    case AF_INET:
+      gettimeofday(&sequence[ip->id - getpid()].time, NULL);
+	 break;
+    case AF_INET6:
+      /* XXX not done for IPv6, yet */
+      break;
+    }
+  } else {
+    gettimeofday(&sequence[icmp->sequence].time, NULL);
+  }
 
   rv = sendto(sendsock, packet, abs(packetsize), 0, 
 	      remotesockaddr, salen);
@@ -433,6 +525,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 +542,14 @@
   struct sockaddr_in * fsa4 = (struct sockaddr_in *) &fromsockaddr_struct;
   socklen_t fromsockaddrsize;
   int num;
-  struct ICMPHeader *header = NULL;
+  struct ip6_hdr *IPv6 = NULL;
+  struct ICMPHeader *InnerICMP = NULL;
+  struct ICMPHeader *OuterICMP = NULL;
+  struct ICMPHeader *UDP = NULL;
+  struct IPHeader *IP = 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 +558,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 +566,81 @@
     fromaddress = (ip_t *) &(fsa6->sin6_addr);
     echoreplytype = ICMP6_ECHO_REPLY;
     timeexceededtype = ICMP6_TIME_EXCEEDED;
+    portunreachabletype = ICMP6_DST_UNREACH_NOPORT;
     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:
+      /* get the IP header, for ID */
+      IP = (struct IPHeader *)(packet + sizeof(struct IPHeader) +
+	                                   sizeof(struct ICMPHeader));
+      /* 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 ICMPHeader));
+
+      if(OuterICMP->type == portunreachabletype ||
+	    OuterICMP->type == timeexceededtype) {
+        /* XXX now how do we do sanity check? ;( */
+        net_process_ping (IP->id - (uint16)getpid(), (void *) fromaddress, now);
+      } else {
+	   /* some other ICMP type, process anyway! */
+        net_process_ping (IP->id - (uint16)getpid(), (void *) fromaddress, now);
+	 }
+      
+    } else {
 
-      if ((size_t) num < sizeof(struct IPHeader) + 
-                         sizeof(struct ICMPHeader) + 
-                         sizeof (struct IPHeader) + 
-                         sizeof (struct ICMPHeader))
+      /* make sure we have any kind of ICMP packet */
+      if((size_t) num < sizeof(struct IPHeader) + sizeof(struct ICMPHeader))
         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) )
+      OuterICMP = (struct ICMPHeader *)(packet + sizeof(struct IPHeader));
+
+      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 ICMPHeader) +
-                                       sizeof (struct ip6_hdr) );
-      break;
-#endif
+      }
     }
+    break;
 
-    if (header->id != (uint16)getpid())
-      return;
-
-    net_process_ping(header->sequence, (void *)fromaddress, now);
+#ifdef ENABLE_IPV6
+  case AF_INET6:
+    /* XXX broken, not done for IPv6, yet */
+    break;
+#endif
   }
 }
 
@@ -753,14 +870,24 @@
 }
 
 
+/* 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);
+  /* need different sock for sending, if we do UDP TCP */
+  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);
+  if (protocol == 17) {
+    sendsock4 = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
+  } else {
+    sendsock4 = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
+  }
 #endif
   if (sendsock4 < 0) 
     return -1;
@@ -787,7 +914,6 @@
   return 0;
 }
 
- 
 int net_open(struct hostent * host) 
 {
 #ifdef ENABLE_IPV6
@@ -807,8 +933,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 +945,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:
@@ -831,9 +957,12 @@
   len = sizeof name_struct; 
   getsockname (recvsock, name, &len);
   sockaddrtop( name, localaddr, sizeof localaddr );
-#if 0
+
+/*
+#ifdef 1
   printf ("got localaddr: %s\n", localaddr); 
 #endif
+*/
 
   return 0;
 }
@@ -906,13 +1035,43 @@
   gettimeofday(&reset, NULL);
 }
 
-
+/* 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; 
+  /* if NO source addr was specified */
+  if (!InterfaceAddress && (protocol == 1)) return 0; 
+  else if (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:
@@ -937,18 +1096,17 @@
 
   if ( bind( sendsock, sourcesockaddr, len ) == -1 ) {
     perror("mtr: failed to bind to interface");
-      return( 1 );
+    return( 1 );
   }
   return 0; 
 }
 
 
-
 void net_close(void)
 {
   if (sendsock4 >= 0) close(sendsock4);
-  if (recvsock4 >= 0) close(recvsock4);
   if (sendsock6 >= 0) close(sendsock6);
+  if (recvsock4 >= 0) close(recvsock4);
   if (recvsock6 >= 0) close(recvsock6);
 }
 
diff -ur mtr-0.72/net.h mtr-0.72-prox3/net.h
--- mtr-0.72/net.h	2006-03-23 00:59:27.000000000 -0500
+++ mtr-0.72-prox3/net.h	2008-03-26 22:38:05.000000000 -0400
@@ -82,8 +82,8 @@
 #define MaxHost 256
 #define MaxSequence 65536
 
-#define MAXPACKET 4470		/* largest test ICMP packet size */
-#define MINPACKET 28		/* 20 bytes IP header and 8 bytes ICMP */
+#define MAXPACKET 4470		/* largest test ICMP/UDP packet size */
+#define MINPACKET 28		/* 20 bytes IP header and 8 bytes ICMP/UDP */
 
 /* stuff used by display such as report, curses... --Min */
 #define MAXFLD 20		/* max stats fields to display */
