Hi Rogier, On Wed, 16 Apr 2008 11:27:00 +0200 Rogier Wolff <[EMAIL PROTECTED]> wrote:
> On Wed, Apr 16, 2008 at 11:03:19AM +0200, Martin Pels wrote: > > > > Which patch are you looking at? > > The wrong one apparently. Ok, I'm glad that's sorted :-) > > > The one Mark attached to his message (mtr-0.72-prox5.patch) is > > moving the security stuff around, like you're saying. But the > > patches I added to my messages (mp-20080324-mtr-0.72-udp.patch and > > mp-20070724-mtr-0.72-udp.patch) do not. > > OK. So, what's the difference between the two? Why are there two > patches, and where do I find the other one? (i.e. I can now only find > one of them) > > Please send them both to me and Explain why I should apply both? which > one? what order? why? There are two patches: mp-20070724-mtr-0.72-udp.patch and mp-20080324-mtr-0.72-udp.patch. I attached both. The 2007 patch does not have the GUI "u" command. Because of this net_selectsocket() can (and does) close either the ICMP or the UDP socket after it finds out which one will be needed. The 2008 patch does have the GUI "u" command. Because of this net_selectsocket() does not close one of the sockets, because it might be needed later when the program switches from ICMP to UDP or the other way round. That's the only difference. I leave it up to you to decide which one to apply. Kind regards, Martin
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 */
diff -Naur mtr-0.72.orig/curses.c mtr-0.72/curses.c --- mtr-0.72.orig/curses.c 2006-09-29 21:40:09.000000000 +0200 +++ mtr-0.72/curses.c 2008-03-24 17:00:52.000000000 +0100 @@ -75,6 +75,7 @@ extern int tos; extern float WaitTime; extern int af; +extern int mtrtype; void pwcenter(char *str) { @@ -242,6 +243,17 @@ } return ActionNone; } + if (tolower(c) == 'u') { + switch ( mtrtype ) { + case IPPROTO_ICMP: + mtrtype = IPPROTO_UDP; + break; + case IPPROTO_UDP: + mtrtype = IPPROTO_ICMP; + break; + } + return ActionNone; + } /* reserve to display help message -Min */ if (tolower(c) == '?'|| tolower(c) == 'h') { mvprintw(2, 0, "Command:\n" ); @@ -256,7 +268,8 @@ printw(" m <n> set the max time-to-live, default n= # of hops\n" ); printw(" s <n> set the packet size to n or random(n<0)\n" ); printw(" b <c> set ping bit pattern to c(0..255) or random(c<0)\n" ); - printw(" Q <t> set ping packet's TOS to t\n\n\n" ); + printw(" Q <t> set ping packet's TOS to t\n" ); + printw(" u switch between ICMP ECHO and UDP datagrams\n\n" ); mvprintw(16, 0, " press any key to go back..." ); getch(); /* get any key */ 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 2008-03-24 17:00:52.000000000 +0100 @@ -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 2008-03-24 17:00:52.000000000 +0100 @@ -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 2008-03-24 17:05:10.000000000 +0100 @@ -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,38 @@ return 0; } - + +int net_selectsocket(void) +{ +#if !defined(IP_HDRINCL) && defined(IP_TOS) && defined(IP_TTL) + switch ( mtrtype ) { + case IPPROTO_ICMP: + sendsock4 = sendsock4_icmp; + break; + case IPPROTO_UDP: + sendsock4 = sendsock4_udp; + break; + } +#endif + if (sendsock4 < 0) + return -1; +#ifdef ENABLE_IPV6 + switch ( mtrtype ) { + case IPPROTO_ICMP: + sendsock6 = sendsock6_icmp; + break; + case IPPROTO_UDP: + sendsock6 = sendsock6_udp; + break; + } + if (sendsock6 < 0) + return -1; +#endif + + return 0; +} + + int net_open(struct hostent * host) { #ifdef ENABLE_IPV6 @@ -946,9 +1122,15 @@ void net_close(void) { - if (sendsock4 >= 0) close(sendsock4); + if (sendsock4 >= 0) { + close(sendsock4_icmp); + close(sendsock4_udp); + } if (recvsock4 >= 0) close(recvsock4); - if (sendsock6 >= 0) close(sendsock6); + if (sendsock6 >= 0) { + close(sendsock6_icmp); + close(sendsock6_udp); + } if (recvsock6 >= 0) close(recvsock6); } 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 2008-03-24 17:00:52.000000000 +0100 @@ -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 */