On Thu, Dec 05, 2002 at 09:00:46PM -0800, RuiJH wrote: > hi, > > Could u send me a copy what you have done.In my view maybe > there is wrong with your code. :) Hello, thanks for replying. I can't send you the original code, it's spread over a bunch of c++ classes anyway so you would probably have hard time debugging it. Instead, I quickly hacked a minimal example that can demonstrate the problem, see the attachment. Compile it with gcc -o rrchksumbug rrchksumbug.c and do the following: 1) launch a (bpf) sniffing tool that can look inside options (I use ethereal) with appropriate filter ("host <your_host> and icmp" should be OK) 2) launch ./rrchksumbug as root 3) launch ping -R <somewhere> rrchksumbug is very minimal so it doesn't do any filtering - it accepts whatever comes from the network and exits. If you receive a lot of ICMP's this could be annoying. Anyway, once you manage to make it accept the ping's reply with recorded route, you will see following: - checksum reported by rrchksumbug will be the same as the one reported by ethereal (or whatever you use) - the record route pointer reported by rrchksumbug will be greater by 4 than the pointer reported by ethereal - and you'll have to believe me (or check for yourself ;) that the recorded address list received by rrchksumbug is indeed augmented by IP address of the local host. So, while the IP header has changed (RR pointer a RR address list), the checksum hasn't - it's no wonder the packet fails the check. BTW, if you do the same experiment, only leaving the "-R" out of ping's options, you'll see that everything works OK. pvl
#include <stdio.h> #include <netinet/in.h> #include <arpa/inet.h> #include <sys/socket.h> #define RECV_BUFF_SIZE 2048 // paraphrased from mtr struct IPHeader { unsigned char hdrlen:4; unsigned char version:4; unsigned char tos; unsigned short len; unsigned short id; unsigned short frag; unsigned char ttl; unsigned char protocol; unsigned short check; unsigned int saddr; unsigned int daddr; }; // basically rfc1071 unsigned short checksum (unsigned char *addr, int count) { unsigned int sum = 0; while( count > 1 ) { /* This is the inner loop */ sum += * ((unsigned short *) addr)++; count -= 2; } /* Add left-over byte, if any */ if( count > 0 ) sum += * (unsigned char *) addr; /* Fold 32-bit sum to 16 bits */ while (sum>>16) sum = (sum & 0xffff) + (sum >> 16); return ~sum; } int main () { unsigned char raw_packet[RECV_BUFF_SIZE]; int recvsock = socket (PF_INET, SOCK_RAW, IPPROTO_ICMP); struct sockaddr_in dummy_src; socklen_t srcaddrsize; int len = recvfrom (recvsock, raw_packet, RECV_BUFF_SIZE, 0, (struct sockaddr *)&dummy_src, &srcaddrsize); struct IPHeader *iphdr = (struct IPHeader * )raw_packet; printf ("received %d bytes\n", len); printf ("hdrlen: %d bytes\n", 4*iphdr->hdrlen); printf ("checksum: %#x, %s\n", ntohs (iphdr->check), checksum (raw_packet, 4*iphdr->hdrlen) ? "ERR" : "OK"); printf ("rr pointer: %d\n", raw_packet[22]); return 0; }