* Wed Oct 4 2000 Jeff Johnson - support LSRR correctly (#16281). https://bugzilla.redhat.com/bugzilla/16281 --- traceroute-1.4a5/configure +++ traceroute-1.4a5/configure @@ -1789,11 +1789,13 @@ ;; linux*) - V_INCLS="$V_INCLS -Ilinux-include -DHAVE_IFF_LOOPBACK -DUSE_KERNEL_ROUTING_TABLE" cat >> confdefs.h <<\EOF -#define BYTESWAP_IP_HDR 1 +#define HAVE_RAW_OPTIONS 1 +#define BYTESWAP_IP_LEN 1 +#define HAVE_IFF_LOOPBACK 1 +#define USE_KERNEL_ROUTING_TABLE 1 EOF - + V_INCLS="$V_INCLS -Ilinux-include" ;; osf3*) --- traceroute-1.4a5/traceroute.c +++ traceroute-1.4a5/traceroute.c @@ -207,6 +207,7 @@ #include #include +#include #include #include #include @@ -229,6 +230,11 @@ #include #include +#ifdef __linux__ +#include +#include +#endif + #include "gnuc.h" #ifdef HAVE_OS_PROTO_H #include "os-proto.h" @@ -240,7 +246,9 @@ /* Maximum number of gateways (include room for one noop) */ #define NGATEWAYS ((int)((MAX_IPOPTLEN - IPOPT_MINOFF - 1) / sizeof(u_int32_t))) +#ifndef MAXHOSTNAMELEN #define MAXHOSTNAMELEN 256 +#endif #define Fprintf (void)fprintf #define Printf (void)printf @@ -277,7 +285,10 @@ struct sockaddr_in wherefrom; /* Who we are */ int packlen; /* total length of packet */ int minpacket; /* min ip packet size */ -int maxpacket = 32 * 1024; /* max ip packet size */ +#if !defined(IP_MAXPACKET) +#define IP_MAXPACKET 64 * 1024 +#endif +int maxpacket = IP_MAXPACKET; /* max ip packet size */ int pmtu; /* Path MTU Discovery (RFC1191) */ u_int pausemsecs; @@ -324,6 +335,13 @@ __dead void usage(void); int wait_for_reply(int, struct sockaddr_in *, struct timeval *); +#ifdef linux +struct sockaddr_in *to = (struct sockaddr_in *)&whereto; +#endif +#ifndef LAUGHTER +u_short uh_sport; +#endif + #ifdef USE_KERNEL_ROUTING_TABLE struct ifaddrlist *search_routing_table(struct sockaddr_in *to, struct ifaddrlist *al, int n); #endif @@ -337,10 +355,12 @@ register u_char *outp; register u_int32_t *ap; register struct sockaddr_in *from = (struct sockaddr_in *)&wherefrom; +#ifndef linux register struct sockaddr_in *to = (struct sockaddr_in *)&whereto; +#endif register struct hostinfo *hi; - int on = 1; register struct protoent *pe; + int on = 1; register int ttl, probe, i; register int seq = 0; int tos = 0, settos = 0; @@ -396,7 +416,7 @@ case 'g': if (strlen(optarg) >= MAXHOSTNAMELEN) { - Fprintf(stderr, "%s: Nice Try !\n", prog); + Fprintf(stderr, "%s: Gateway address too long\n", prog); exit(-1); } if (lsrr >= NGATEWAYS) { @@ -413,7 +433,7 @@ device = optarg; if (strlen(device) >= 16) { /* that is the IFNAMSIZ * from kernel headers */ - Fprintf(stderr, "%s: Nice try !\n", prog); + Fprintf(stderr, "%s: Interface name too long\n", prog); exit(-1); } break; @@ -449,7 +469,7 @@ */ source = optarg; if (strlen(source) >= MAXHOSTNAMELEN) { - Fprintf(stderr, "%s: Nice Try !\n", prog); + Fprintf(stderr, "%s: Source address too long\n", prog); exit(-1); } break; @@ -504,7 +524,7 @@ case 1: hostname = argv[optind]; if (strlen(hostname) >= MAXHOSTNAMELEN) { - Fprintf(stderr, "%s: Nice try !\n", prog); + Fprintf(stderr, "%s: Address too long\n", prog); exit(-1); } hi = gethostinfo(hostname); @@ -594,7 +614,32 @@ outip->ip_p = IPPROTO_UDP; outudp = (struct udphdr *)outp; - outudp->uh_sport = htons(ident); +#ifdef LAUGHTER + outudp->uh_sport = htons(ident); +#else + /* Avoid udp port conflicts! */ + if (!useicmp) { + struct sockaddr_in s; + int alen = sizeof(s); + int lock_fd = socket(AF_INET, SOCK_DGRAM, 0); + if (lock_fd < 0) { + perror("socket"); + exit(1); + } + memset(&s, 0, sizeof(s)); + if (bind(lock_fd, (struct sockaddr*)&s, sizeof(s)) == -1) { + perror("bind"); + exit(1); + } + if (getsockname(lock_fd, (struct sockaddr*)&s, &alen) == -1) { + perror("getsockname"); + exit(1); + } + uh_sport = s.sin_port; + outudp->uh_sport = s.sin_port; + /* DO NOT CLOSE LOCK SOCKET */ + } +#endif outudp->uh_ulen = htons((u_short)(packlen - (sizeof(*outip) + optlen))); outdata = (struct outdata *)(outudp + 1); @@ -670,6 +715,52 @@ (void)setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE, (char *)&on, sizeof(on)); +#ifndef LAUGHTER + do { + int alen; + int probe_fd = socket(AF_INET, SOCK_DGRAM, 0); + int sport; + + if (probe_fd < 0) { + perror("socket"); + exit(1); + } + if (device) { + struct ifreq ifr; + strncpy(ifr.ifr_name, device, IFNAMSIZ-1); + if (setsockopt(probe_fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)) == -1) { + close(probe_fd); + break; + } + } + sport = to->sin_port; + to->sin_port = htons(1025); + if (connect(probe_fd, (struct sockaddr*)to, sizeof(*to)) == -1) { + perror("socket"); + exit(1); + } + to->sin_port = sport; + alen = sizeof(*from); + if (getsockname(probe_fd, (struct sockaddr*)from, &alen) == -1) { + perror("getsockname"); + exit(1); + } + close(probe_fd); + if (source == NULL) + goto selected; + hi = gethostinfo(source); + source = hi->name; + hi->name = NULL; + for (i = hi->n, ap = hi->addrs; i > 0; --i, ++ap) { + if (from->sin_addr.s_addr == *ap) { + freehostinfo(hi); + goto selected; + } + } + freehostinfo(hi); + } while (0); +#endif + /* Get the interface address list */ n = ifaddrlist(&allist, errbuf); al = allist; @@ -750,6 +841,10 @@ setgid(getgid()); setuid(getuid()); + +#ifndef LAUGHTER +selected: +#endif outip->ip_src = from->sin_addr; #ifndef IP_HDRINCL if (bind(sndsock, (struct sockaddr *)from, sizeof(*from)) < 0) { @@ -759,6 +854,27 @@ } #endif +#ifdef linux + if (bind(sndsock, (struct sockaddr *)from, sizeof(*from)) < 0) { + Fprintf(stderr, "%s: bind: %s\n", + prog, strerror(errno)); + exit (1); + } + if (bind(s, (struct sockaddr *)from, sizeof(*from)) < 0) { + Fprintf(stderr, "%s: bind ICMP socket: %s\n", + prog, strerror(errno)); + exit (1); + } + if (1) { + struct icmp_filter filt; + filt.data = ~((1<sin_addr)); if (source) @@ -901,10 +1017,21 @@ struct ip tip; outip->ip_ttl = ttl; +#ifdef linux + /* Do not fiddle with ID, it must be unique + and only kernel is allowed to make it. --ANK + */ + outip->ip_id = 0; +#else #ifndef __hpux outip->ip_id = htons(ident + seq); #endif +#endif +#ifdef LAUGHTER + /* The comment below has nothing to do with reality and + udp cksum has nothing to do with ip one. --ANK + */ /* * In most cases, the kernel will recalculate the ip checksum. * But we must do it anyway so that the udp checksum comes out @@ -916,6 +1043,7 @@ if (outip->ip_sum == 0) outip->ip_sum = 0xffff; } +#endif /* Payload */ outdata->seq = seq; @@ -936,6 +1064,7 @@ if (outicmp->icmp_cksum == 0) outicmp->icmp_cksum = 0xffff; } else if (doipcksum) { +#ifdef FULL_CRAP_I_WONDER_WHY_LBNL_FOLKS_DID_IT /* Checksum (we must save and restore ip header) */ tip = *outip; ui = (struct udpiphdr *)outip; @@ -948,6 +1077,30 @@ if (outudp->uh_sum == 0) outudp->uh_sum = 0xffff; *outip = tip; +#else + struct udpmagichdr { + struct in_addr src; + struct in_addr dst; + u_char zero; + u_char proto; + u_short len; + } h, saved, *hptr; + + h.src = outip->ip_src; + h.dst = to->sin_addr; + h.zero = 0; + h.proto = IPPROTO_UDP; + h.len = outudp->uh_ulen; + hptr = ((struct udpmagichdr*)outudp) - 1; + saved = *hptr; + *hptr = h; + outudp->uh_sum = 0; + outudp->uh_sum = in_cksum((u_short *)hptr, ntohs(outudp->uh_ulen) + sizeof(*hptr)); + if (outudp->uh_sum == 0) + outudp->uh_sum = 0xffff; + *hptr = saved; +#endif + } /* XXX undocumented debugging hack */ @@ -1054,6 +1207,10 @@ #else icp = (struct icmp *)buf; #endif + + if (in_cksum((u_short *)icp, htons(ip->ip_len) - hlen) && useicmp) + fprintf(stderr, "Icmp checksum is wrong\n"); + type = icp->icmp_type; code = icp->icmp_code; if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) || @@ -1083,7 +1240,11 @@ /* XXX 8 is a magic number */ if (hlen + 12 <= cc && hip->ip_p == IPPROTO_UDP && +#ifdef LAUGHTER up->uh_sport == htons(ident) && +#else + up->uh_sport == uh_sport && +#endif up->uh_dport == htons(port + seq)) return (type == ICMP_TIMXCEED ? -1 : code + 1); } @@ -1126,6 +1287,8 @@ /* * Checksum routine for Internet Protocol family headers (C Version) + * + * Certainly, it was broken --ANK */ u_short in_cksum(register u_short *addr, register int len) @@ -1148,7 +1311,7 @@ /* mop up an odd byte, if necessary */ if (nleft == 1) - sum += *(u_char *)w; + sum += htons(*(u_char *)w<<8); /* * add back carry outs from top 16 bits to low 16 bits