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?

        Roger. 



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




-- 
** [EMAIL PROTECTED] ** http://www.BitWizard.nl/ ** +31-15-2600998 **
**    Delftechpark 26 2628 XH  Delft, The Netherlands. KVK: 27239233    **
*-- BitWizard writes Linux device drivers for any device you may have! --*
Q: It doesn't work. A: Look buddy, doesn't work is an ambiguous statement. 
Does it sit on the couch all day? Is it unemployed? Please be specific! 
Define 'it' and what it isn't doing. --------- Adapted from lxrbot FAQ



-- 
To UNSUBSCRIBE, email to [EMAIL PROTECTED]
with a subject of "unsubscribe". Trouble? Contact [EMAIL PROTECTED]

Reply via email to