Hi Rogier,

Thanks for the reply.

On Mon, 14 Apr 2008 21:09:56 +0200
Rogier Wolff <[EMAIL PROTECTED]> wrote:

> 
> Hi guys, 
> 
> Looks nice. One problem I have with this is that the amount of code
> that is exposed to security problems has gone up a factor of ten... 
> 
> How much work would it be to open both the new UDP port and the old
> ICMP port, and discard the one we don't need? How can the program
> switch (with the GUI "u" command) if it hasn't preopened the sockets
> anyway?

Depending on whether IP_HDRINCL is defined net_preopen() creates an
icmp and udp socket, or a single raw socket. 

If we have two sockets it is trivial to close them in
net_selectsocket(). This is actually what I did in the first version of
the patch I sent you last year (attached for completeness).
If we only have a single raw socket there is nothing we need to close.

Closing sockets will inevitably break the GUI "u" command, because
after we drop privileges we cannot open new sockets. So maybe we should
only enable this functionality when raw sockets are available.

Kind regards,
Martin

> 
> 
> 
> On Mon, Apr 14, 2008 at 11:35:03AM -0400, Mark Kamichoff wrote:
> > > I wrote a patch for Mtr 0.72 to implement UDP support. You can
> > > find it attached. UDP mode is enabled using the "-u" commandline
> > > switch, or by typing u in the GUI. The patch has been tested on
> > > Debian testing/unstable, both on IPv4 and IPv6.
> > 
> > I have written a patch (see attached) as well that adds similar UDP
> > functionality.  There are some differences in the choice of
> > destination ports used, with the original goal of emulating classic
> > traceroute(8) behavior.  The port range of 100 can cause erroneous
> > loss on some paths since it is used to store sequence numbers, but
> > 'most' of the time it is not noticable.
> > 
> > That being said, Martin's patch seems to be the best choice for
> > inclusion, as it does not suffer from this problem, and is overall
> > of cleaner design.
> > 
> > It would be great to see it included in MTR, as I believe it would
> > add considerable flexibility to the utility.
> > 
> > - Mark
> > 
> > -- 
> > Mark Kamichoff
> > [EMAIL PROTECTED]
> > http://prolixium.com/
> > Rensselaer Polytechnic Institute, Class of 2004
> 
> > 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  <[EMAIL PROTECTED]>
> > +
> > +   * 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  <[EMAIL PROTECTED]>
> > +
> > +   * Fixed bug displaying localaddr (always displayed ANY)
> > +
> > +2007-03-27  Mark Kamichoff  <[EMAIL PROTECTED]>
> > +
> > +   * 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 <[EMAIL PROTECTED]>
> >     + 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
> 
> 
> 
> 
diff -Naur mtr-0.72.orig/mtr.8 mtr-0.72/mtr.8
--- mtr-0.72.orig/mtr.8	2006-09-29 21:33:06.000000000 +0200
+++ mtr-0.72/mtr.8	2007-07-24 13:53:46.000000000 +0200
@@ -8,7 +8,7 @@
 .SH SYNOPSIS
 .B mtr 
 [\c
-.B \-hvrctglspni46\c
+.B \-hvrctglspniu46\c
 ]
 [\c
 .B \-\-help\c
@@ -208,6 +208,11 @@
 ECHO requests.  The default value for this parameter is one second.
 
 .TP
+.B \-u
+.br
+Use UDP datagrams instead of ICMP ECHO.
+
+.TP
 .B \-4
 .br
 Use IPv4 only.
diff -Naur mtr-0.72.orig/mtr.c mtr-0.72/mtr.c
--- mtr-0.72.orig/mtr.c	2006-09-29 21:38:49.000000000 +0200
+++ mtr-0.72/mtr.c	2007-07-24 13:53:43.000000000 +0200
@@ -65,6 +65,7 @@
 int   bitpattern = 0;
 int   tos = 0;
 int af = DEFAULT_AF;
+int mtrtype = IPPROTO_ICMP;     /* Use ICMP as default packet type */
 
                                 /* begin ttl windows addByMin */
 int  fstTTL = 1;                /* default start at first hop */
@@ -143,6 +144,7 @@
     { "address", 1, 0, 'a' },
     { "first-ttl", 1, 0, 'f' },	/* -f & -m are borrowed from traceroute */
     { "max-ttl", 1, 0, 'm' },
+    { "udp", 0, 0, 'u' },	/* UDP (default is ICMP) */
     { "inet", 0, 0, '4' },	/* IPv4 only */
     { "inet6", 0, 0, '6' },	/* IPv6 only */
     { 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:u46", long_options, NULL);
     if(opt == -1)
       break;
 
@@ -253,6 +255,9 @@
 	tos = 0;
       }
       break;
+    case 'u':
+      mtrtype = IPPROTO_UDP;
+      break;
     case '4':
       af = AF_INET;
       break;
@@ -354,13 +359,19 @@
 
   parse_arg (argc, argv);
 
+  /* Now that we know mtrtype we can select which socket to use */
+  if (net_selectsocket() != 0) {
+    fprintf( stderr, "mtr: Couldn't determine raw socket type.\n" );
+    exit( EXIT_FAILURE );
+  }
+
   if (PrintVersion) {
     printf ("mtr " VERSION "\n");
     exit(0);
   }
 
   if (PrintHelp) {
-    printf("usage: %s [-hvrctglspni46] [--help] [--version] [--report]\n"
+    printf("usage: %s [-hvrctglspniu46] [--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 */
diff -Naur mtr-0.72.orig/net.c mtr-0.72/net.c
--- mtr-0.72.orig/net.c	2006-09-29 21:31:01.000000000 +0200
+++ mtr-0.72/net.c	2007-07-24 13:53:35.000000000 +0200
@@ -54,6 +54,22 @@
   uint16 sequence;
 };
 
+/* Structure of an UDP header.  */
+struct UDPHeader {
+  uint16 srcport;
+  uint16 dstport;
+  uint16 length;
+  uint16 checksum;
+};
+
+/* Structure of an IPv4 UDP pseudoheader.  */
+struct UDPv4PHeader {
+  uint32 saddr;
+  uint32 daddr;
+  uint8 zero;
+  uint8 protocol;
+  uint16 len;
+};
 
 /*  Structure of an IP header.  */
 struct IPHeader {
@@ -77,6 +93,7 @@
 #define ICMP_TSTAMPREPLY	14
 
 #define ICMP_TIME_EXCEEDED	11
+#define ICMP_UNREACHABLE        3
 
 #ifndef SOL_IP
 #define SOL_IP 0
@@ -131,8 +148,12 @@
 
 int    timestamp;
 int    sendsock4;
+int    sendsock4_icmp;
+int    sendsock4_udp;
 int    recvsock4;
 int    sendsock6;
+int    sendsock6_icmp;
+int    sendsock6_udp;
 int    recvsock6;
 int    sendsock;
 int    recvsock;
@@ -175,7 +196,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 mtrtype;		/* type of query packet used */
 
 /* return the number of microseconds to wait before sending the next
    ping */
@@ -206,14 +227,40 @@
 }
 
 
+/* Prepend pseudoheader to the udp datagram and calculate checksum */
+int udp_checksum(void *pheader, void *udata, int psize, int dsize)
+{
+  unsigned int tsize = psize + dsize;
+  char csumpacket[tsize];
+  memset(csumpacket, (unsigned char) abs(bitpattern), abs(tsize));
+
+  struct UDPv4PHeader *prepend = (struct UDPv4PHeader *) csumpacket;
+  struct UDPv4PHeader *udppheader = (struct UDPv4PHeader *) pheader;
+  prepend->saddr = udppheader->saddr;
+  prepend->daddr = udppheader->daddr;
+  prepend->zero = 0;
+  prepend->protocol = udppheader->protocol;
+  prepend->len = udppheader->len;
+
+  struct UDPHeader *content = (struct UDPHeader *)(csumpacket + psize);
+  struct UDPHeader *udpdata = (struct UDPHeader *) udata;
+  content->srcport = udpdata->srcport;
+  content->dstport = udpdata->dstport;
+  content->length = udpdata->length;
+  content->checksum = udpdata->checksum;
+
+  return checksum(csumpacket,tsize);
+}
+
+
 int new_sequence(int index) 
 {
-  static int next_sequence = 0;
+  static int next_sequence = MinSequence;
   int seq;
 
   seq = next_sequence++;
   if (next_sequence >= MaxSequence)
-    next_sequence = 0;
+    next_sequence = MinSequence;
 
   sequence[seq].index = index;
   sequence[seq].transit = 1;
@@ -236,15 +283,21 @@
   /*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;
+  struct UDPv4PHeader *udpp = NULL;
+  uint16 mypid;
 
   /*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, salen = 0, udphsize = 0;
 
   ttl = index + 1;
 
+  /* offset for ipv6 checksum calculation */
+  int offset = 6;
+
   if ( packetsize < MINPACKET ) packetsize = MINPACKET;
   if ( packetsize > MAXPACKET ) packetsize = MAXPACKET;
 
@@ -271,7 +324,7 @@
   ip->id = 0;
   ip->frag = 0;    /* 1, if want to find mtu size? Min */
     ip->ttl = ttl;
-  ip->protocol = IPPROTO_ICMP;
+  ip->protocol = mtrtype;
   ip->check = 0;
 
   /* BSD needs the source address here, Linux & others do not... */
@@ -295,22 +348,71 @@
 #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);
+  switch ( mtrtype ) {
+  case IPPROTO_ICMP:
+    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);
+    
+    gettimeofday(&sequence[icmp->sequence].time, NULL);
+    break;
+
+  case IPPROTO_UDP:
+    udp = (struct UDPHeader *)(packet + iphsize);
+    udphsize = sizeof (struct UDPHeader);
+    udp->checksum  = 0;
+    mypid = (uint16)getpid();
+    if (mypid < MinPort)
+      mypid += MinPort;
+
+    udp->srcport = htons(mypid);
+    udp->length = abs(packetsize) - iphsize;
+    if(!BSDfix)
+      udp->length = htons(udp->length);
+ 
+    udp->dstport = new_sequence(index);
+    gettimeofday(&sequence[udp->dstport].time, NULL);
+    udp->dstport = htons(udp->dstport);
+    break;
+  }
 
   switch ( af ) {
   case AF_INET:
+    switch ( mtrtype ) {
+    case IPPROTO_UDP:
+      /* checksum is not mandatory. only calculate if we know ip->saddr */
+      if (ip->saddr) {
+        udpp = (struct UDPv4PHeader *)(malloc(sizeof(struct UDPv4PHeader)));
+        udpp->saddr = ip->saddr;
+        udpp->daddr = ip->daddr;
+        udpp->protocol = ip->protocol;
+        udpp->len = udp->length;
+        udp->checksum = udp_checksum(udpp, udp, sizeof(struct UDPv4PHeader), abs(packetsize) - iphsize);
+      }
+      break;
+    }
+
     ip->check = checksum(packet, abs(packetsize));
     break;
+#ifdef ENABLE_IPV6
+  case AF_INET6:
+    switch ( mtrtype ) {
+    case IPPROTO_UDP:
+      /* kernel checksum calculation */
+      if ( setsockopt(sendsock, IPPROTO_IPV6, IPV6_CHECKSUM, &offset, sizeof(offset)) ) {
+        perror( "setsockopt IPV6_CHECKSUM" );
+        exit( EXIT_FAILURE);
+      }
+      break;
+    }
+    break;
+#endif
   }
 
-  gettimeofday(&sequence[icmp->sequence].time, NULL);
-
   rv = sendto(sendsock, packet, abs(packetsize), 0, 
 	      remotesockaddr, salen);
   if (first && (rv < 0) && ((errno == EINVAL) || (errno == EMSGSIZE))) {
@@ -450,9 +552,11 @@
   socklen_t fromsockaddrsize;
   int num;
   struct ICMPHeader *header = NULL;
+  struct UDPHeader *udpheader = NULL;
   struct timeval now;
   ip_t * fromaddress = NULL;
-  int echoreplytype = 0, timeexceededtype = 0;
+  int echoreplytype = 0, timeexceededtype = 0, unreachabletype = 0;
+  int sequence = 0;
 
   gettimeofday(&now, NULL);
   switch ( af ) {
@@ -461,6 +565,7 @@
     fromaddress = (ip_t *) &(fsa4->sin_addr);
     echoreplytype = ICMP_ECHOREPLY;
     timeexceededtype = ICMP_TIME_EXCEEDED;
+    unreachabletype = ICMP_UNREACHABLE;
     break;
 #ifdef ENABLE_IPV6
   case AF_INET6:
@@ -468,6 +573,7 @@
     fromaddress = (ip_t *) &(fsa6->sin6_addr);
     echoreplytype = ICMP6_ECHO_REPLY;
     timeexceededtype = ICMP6_TIME_EXCEEDED;
+    unreachabletype = ICMP6_DST_UNREACH;
     break;
 #endif
   }
@@ -490,41 +596,78 @@
     break;
 #endif
   }
-  if (header->type == echoreplytype) {
-    if(header->id != (uint16)getpid())
-      return;
 
-    net_process_ping (header->sequence, (void *) fromaddress, now);
-  } else if (header->type == timeexceededtype) {
-    switch ( af ) {
-    case AF_INET:
-
-      if ((size_t) num < sizeof(struct IPHeader) + 
-                         sizeof(struct ICMPHeader) + 
-                         sizeof (struct IPHeader) + 
-                         sizeof (struct ICMPHeader))
+  switch ( mtrtype ) {
+  case IPPROTO_ICMP:
+    if (header->type == echoreplytype) {
+      if(header->id != (uint16)getpid())
         return;
-      header = (struct ICMPHeader *)(packet + sizeof (struct IPHeader) + 
-                                              sizeof (struct ICMPHeader) + 
-                                              sizeof (struct IPHeader));
-    break;
+
+      sequence = header->sequence;
+    } else if (header->type == timeexceededtype) {
+      switch ( af ) {
+      case AF_INET:
+
+        if ((size_t) num < sizeof(struct IPHeader) + 
+                           sizeof(struct ICMPHeader) + 
+                           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) )
+      case AF_INET6:
+        if ( num < sizeof (struct ICMPHeader) + 
+                   sizeof (struct ip6_hdr) + sizeof (struct ICMPHeader) )
+          return;
+        header = (struct ICMPHeader *) ( packet + 
+                                         sizeof (struct ICMPHeader) +
+                                         sizeof (struct ip6_hdr) );
+        break;
+#endif
+      }
+  
+      if (header->id != (uint16)getpid())
         return;
-      header = (struct ICMPHeader *) ( packet + 
-                                       sizeof (struct ICMPHeader) +
-                                       sizeof (struct ip6_hdr) );
+  
+      sequence = header->sequence;
+    }
+    break;
+  
+  case IPPROTO_UDP:
+    if (header->type == timeexceededtype || header->type == unreachabletype) {
+      switch ( af ) {
+      case AF_INET:
+
+        if ((size_t) num < sizeof(struct IPHeader) +
+                           sizeof(struct ICMPHeader) +
+                           sizeof (struct IPHeader) +
+                           sizeof (struct UDPHeader))
+          return;
+        udpheader = (struct UDPHeader *)(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 UDPHeader) )
+          return;
+        udpheader = (struct UDPHeader *) ( packet +
+                                           sizeof (struct ICMPHeader) +
+                                           sizeof (struct ip6_hdr) );
+        break;
 #endif
+      }
+      sequence = ntohs(udpheader->dstport);
     }
-
-    if (header->id != (uint16)getpid())
-      return;
-
-    net_process_ping(header->sequence, (void *)fromaddress, now);
+    break;
   }
+
+  if (sequence)
+    net_process_ping(sequence, (void *)fromaddress, now);
 }
 
 
@@ -758,14 +901,16 @@
   int trueopt = 1;
 
 #if !defined(IP_HDRINCL) && defined(IP_TOS) && defined(IP_TTL)
-  sendsock4 = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
+  sendsock4_icmp = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
+  sendsock4_udp = socket(AF_INET, SOCK_RAW, IPPROTO_UDP);
 #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);
+  sendsock6_icmp = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
+  sendsock6_udp = socket(AF_INET6, SOCK_RAW, IPPROTO_UDP);
 #endif
 
 #ifdef IP_HDRINCL
@@ -787,7 +932,42 @@
   return 0;
 }
 
- 
+
+int net_selectsocket(void)
+{
+#if !defined(IP_HDRINCL) && defined(IP_TOS) && defined(IP_TTL)
+  switch ( mtrtype ) {
+  case IPPROTO_ICMP:
+    sendsock4 = sendsock4_icmp;
+    close(sendsock4_udp);
+    break;
+  case IPPROTO_UDP:
+    sendsock4 = sendsock4_udp;
+    close(sendsock4_icmp);
+    break;
+  }
+#endif
+  if (sendsock4 < 0)
+    return -1;
+#ifdef ENABLE_IPV6
+  switch ( mtrtype ) {
+  case IPPROTO_ICMP:
+    sendsock6 = sendsock6_icmp;
+    close(sendsock6_udp);
+    break;
+  case IPPROTO_UDP:
+    sendsock6 = sendsock6_udp;
+    close(sendsock6_icmp);
+    break;
+  }
+  if (sendsock6 < 0)
+    return -1;
+#endif
+
+ return 0;
+}
+
+
 int net_open(struct hostent * host) 
 {
 #ifdef ENABLE_IPV6
diff -Naur mtr-0.72.orig/net.h mtr-0.72/net.h
--- mtr-0.72.orig/net.h	2006-03-23 06:59:27.000000000 +0100
+++ mtr-0.72/net.h	2007-07-24 13:53:38.000000000 +0200
@@ -28,6 +28,7 @@
 #endif
 
 int net_preopen(void);
+int net_selectsocket(void);
 int net_open(struct hostent *host);
 void net_reopen(struct hostent *address);
 int net_set_interfaceaddress (char *InterfaceAddress); 
@@ -80,10 +81,12 @@
 
 #define MAXPATH 8
 #define MaxHost 256
+#define MinSequence 33000
 #define MaxSequence 65536
+#define MinPort 1024
 
-#define MAXPACKET 4470		/* largest test ICMP packet size */
-#define MINPACKET 28		/* 20 bytes IP header and 8 bytes ICMP */
+#define MAXPACKET 4470		/* largest test packet size */
+#define MINPACKET 28		/* 20 bytes IP header and 8 bytes ICMP or UDP */
 
 /* stuff used by display such as report, curses... --Min */
 #define MAXFLD 20		/* max stats fields to display */

Reply via email to