diff options
Diffstat (limited to 'contrib/traceroute/traceroute.c')
-rw-r--r-- | contrib/traceroute/traceroute.c | 697 |
1 files changed, 554 insertions, 143 deletions
diff --git a/contrib/traceroute/traceroute.c b/contrib/traceroute/traceroute.c index 21612f80cdb1..a699f4c6f9c1 100644 --- a/contrib/traceroute/traceroute.c +++ b/contrib/traceroute/traceroute.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1988, 1989, 1991, 1994, 1995, 1996 + * Copyright (c) 1988, 1989, 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -21,10 +21,10 @@ #ifndef lint static const char copyright[] = - "@(#) Copyright (c) 1988, 1989, 1991, 1994, 1995, 1996\n\ + "@(#) Copyright (c) 1988, 1989, 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000\n\ The Regents of the University of California. All rights reserved.\n"; static const char rcsid[] = - "@(#)$Header: traceroute.c,v 1.43 96/09/27 20:08:10 leres Exp $ (LBL)"; + "@(#)$Id: traceroute.c,v 1.68 2000/12/14 08:04:33 leres Exp $ (LBL)"; #endif /* @@ -213,11 +213,13 @@ static const char rcsid[] = #include <netinet/ip_var.h> #include <netinet/ip_icmp.h> #include <netinet/udp.h> +#include <netinet/udp_var.h> #include <arpa/inet.h> #include <ctype.h> #include <errno.h> +#include <fcntl.h> #ifdef HAVE_MALLOC_H #include <malloc.h> #endif @@ -233,6 +235,21 @@ static const char rcsid[] = #include "os-proto.h" #endif +/* rfc1716 */ +#ifndef ICMP_UNREACH_FILTER_PROHIB +#define ICMP_UNREACH_FILTER_PROHIB 13 /* admin prohibited filter */ +#endif +#ifndef ICMP_UNREACH_HOST_PRECEDENCE +#define ICMP_UNREACH_HOST_PRECEDENCE 14 /* host precedence violation */ +#endif +#ifndef ICMP_UNREACH_PRECEDENCE_CUTOFF +#define ICMP_UNREACH_PRECEDENCE_CUTOFF 15 /* precedence cutoff */ +#endif + +#include "findsaddr.h" +#include "ifaddrlist.h" +#include "traceroute.h" + /* Maximum number of gateways (include room for one noop) */ #define NGATEWAYS ((int)((MAX_IPOPTLEN - IPOPT_MINOFF - 1) / sizeof(u_int32_t))) @@ -243,6 +260,13 @@ static const char rcsid[] = #define Fprintf (void)fprintf #define Printf (void)printf +/* Host name and address list */ +struct hostinfo { + char *name; + int n; + u_int32_t *addrs; +}; + /* Data section of the probe packet */ struct outdata { u_char seq; /* sequence number of this packet */ @@ -250,28 +274,45 @@ struct outdata { struct timeval tv; /* time packet left */ }; +#ifndef HAVE_ICMP_NEXTMTU +/* Path MTU Discovery (RFC1191) */ +struct my_pmtu { + u_short ipm_void; + u_short ipm_nextmtu; +}; +#endif + u_char packet[512]; /* last inbound (icmp) packet */ struct ip *outip; /* last output (udp) packet */ struct udphdr *outudp; /* last output (udp) packet */ struct outdata *outdata; /* last output (udp) packet */ +struct icmp *outicmp; /* last output (icmp) packet */ + /* loose source route gateway list (including room for final destination) */ u_int32_t gwlist[NGATEWAYS + 1]; int s; /* receive (icmp) socket file descriptor */ -int sndsock; /* send (udp) socket file descriptor */ +int sndsock; /* send (udp/icmp) socket file descriptor */ struct sockaddr whereto; /* Who to try to reach */ +struct sockaddr wherefrom; /* Who we are */ int packlen; /* total length of packet */ +int minpacket; /* min ip packet size */ int maxpacket = 32 * 1024; /* max ip packet size */ +int pmtu; /* Path MTU Discovery (RFC1191) */ +u_int pausemsecs; char *prog; char *source; char *hostname; +char *device; +static const char devnull[] = "/dev/null"; int nprobes = 3; int max_ttl = 30; +int first_ttl = 1; u_short ident; u_short port = 32768 + 666; /* start udp dest port # for probe packets */ @@ -279,6 +320,13 @@ int options; /* socket options */ int verbose; int waittime = 5; /* time to wait for response (in seconds) */ int nflag; /* print addresses numerically */ +int useicmp; /* use icmp echo instead of udp packets */ +#ifdef CANT_HACK_IPCKSUM +int doipcksum = 0; /* don't calculate ip checksums by default */ +#else +int doipcksum = 1; /* calculate ip checksums by default */ +#endif +int optlen; /* length of ip options */ extern int optind; extern int opterr; @@ -286,47 +334,68 @@ extern char *optarg; /* Forwards */ double deltaT(struct timeval *, struct timeval *); +void freehostinfo(struct hostinfo *); +void getaddr(u_int32_t *, char *); +struct hostinfo *gethostinfo(char *); +u_short in_cksum(u_short *, int); char *inetname(struct in_addr); int main(int, char **); int packet_ok(u_char *, int, struct sockaddr_in *, int); char *pr_type(u_char); void print(u_char *, int, struct sockaddr_in *); -char *getaddr(u_int32_t *, char *); -char *getsin(struct sockaddr_in *, char *); -char *savestr(const char *); void send_probe(int, int, struct timeval *); +int str2val(const char *, const char *, int, int); void tvsub(struct timeval *, struct timeval *); __dead void usage(void); -int wait_for_reply(int, struct sockaddr_in *, struct timeval *); +int wait_for_reply(int, struct sockaddr_in *, const struct timeval *); +#ifndef HAVE_USLEEP +int usleep(u_int); +#endif int main(int argc, char **argv) { - register int op, code; + register int op, code, n; register char *cp; - struct sockaddr_in from; + register const char *err; + register u_char *outp; + register u_int32_t *ap; + register struct sockaddr_in *from = (struct sockaddr_in *)&wherefrom; register struct sockaddr_in *to = (struct sockaddr_in *)&whereto; + register struct hostinfo *hi; int on = 1; register struct protoent *pe; register int ttl, probe, i; register int seq = 0; - register int tos = 0; + int tos = 0, settos = 0; register int lsrr = 0; - register int optlen = 0; + register u_short off = 0; + struct ifaddrlist *al; + char errbuf[132]; - if ((cp = strrchr(argv[0], '/')) != NULL) + if (argv[0] == NULL) + prog = "traceroute"; + else if ((cp = strrchr(argv[0], '/')) != NULL) prog = cp + 1; else prog = argv[0]; opterr = 0; - while ((op = getopt(argc, argv, "dnrvg:m:p:q:s:t:w:")) != EOF) + while ((op = getopt(argc, argv, "dFInrvxf:g:i:m:p:q:s:t:w:z:")) != EOF) switch (op) { case 'd': options |= SO_DEBUG; break; + case 'f': + first_ttl = str2val(optarg, "first ttl", 1, 255); + break; + + case 'F': + off = IP_DF; + break; + case 'g': if (lsrr >= NGATEWAYS) { Fprintf(stderr, @@ -334,17 +403,20 @@ main(int argc, char **argv) prog, NGATEWAYS); exit(1); } - (void)getaddr(gwlist + lsrr, optarg); + getaddr(gwlist + lsrr, optarg); ++lsrr; break; + case 'i': + device = optarg; + break; + + case 'I': + ++useicmp; + break; + case 'm': - max_ttl = atoi(optarg); - if (max_ttl <= 1) { - Fprintf(stderr, "%s: max ttl must be > 1\n", - prog); - exit(1); - } + max_ttl = str2val(optarg, "max ttl", 1, 255); break; case 'n': @@ -352,20 +424,12 @@ main(int argc, char **argv) break; case 'p': - port = atoi(optarg); - if (port <= 0) { - Fprintf(stderr, "%s: port must be > 0\n", prog); - exit(1); - } + port = (u_short)str2val(optarg, "port", + 1, (1 << 16) - 1); break; case 'q': - nprobes = atoi(optarg); - if (nprobes <= 0) { - Fprintf(stderr, "%s: nprobes must be > 0\n", - prog); - exit(1); - } + nprobes = str2val(optarg, "nprobes", 1, -1); break; case 'r': @@ -381,40 +445,70 @@ main(int argc, char **argv) break; case 't': - tos = atoi(optarg); - if (tos < 0 || tos > 255) { - Fprintf(stderr, "%s: tos must be 0 to 255\n", - prog); - exit(1); - } + tos = str2val(optarg, "tos", 0, 255); + ++settos; break; case 'v': ++verbose; break; + case 'x': + doipcksum = (doipcksum == 0); + break; + case 'w': - waittime = atoi(optarg); - if (waittime <= 1) { - Fprintf(stderr, "%s: wait must be > 1 sec\n", - prog); - exit(1); - } + waittime = str2val(optarg, "wait time", + 2, 24 * 60 * 60); + break; + + case 'z': + pausemsecs = str2val(optarg, "pause msecs", + 0, 60 * 60 * 1000); break; default: usage(); } + if (first_ttl > max_ttl) { + Fprintf(stderr, + "%s: first ttl (%d) may not be greater than max ttl (%d)\n", + prog, first_ttl, max_ttl); + exit(1); + } + + if (!doipcksum) + Fprintf(stderr, "%s: Warning: ip checksums disabled\n", prog); + + if (lsrr > 0) + optlen = (lsrr + 1) * sizeof(gwlist[0]); + minpacket = sizeof(*outip) + sizeof(*outdata) + optlen; + if (useicmp) + minpacket += 8; /* XXX magic number */ + else + minpacket += sizeof(*outudp); + packlen = minpacket; /* minimum sized packet */ + /* Process destination and optional packet size */ switch (argc - optind) { case 2: - packlen = atoi(argv[optind + 1]); - /* Fall thorugh */ + packlen = str2val(argv[optind + 1], + "packet length", minpacket, maxpacket); + /* Fall through */ case 1: - hostname = savestr(getsin(to, argv[optind])); + hostname = argv[optind]; + hi = gethostinfo(hostname); + setsin(to, hi->addrs[0]); + if (hi->n > 1) + Fprintf(stderr, + "%s: Warning: %s has multiple addresses; using %s\n", + prog, hostname, inet_ntoa(to->sin_addr)); + hostname = hi->name; + hi->name = NULL; + freehostinfo(hi); break; default: @@ -427,17 +521,6 @@ main(int argc, char **argv) setvbuf(stdout, NULL, _IOLBF, 0); #endif - if (lsrr > 0) - optlen = (lsrr + 1) * sizeof(gwlist[0]); - i = sizeof(*outip) + sizeof(*outudp) + sizeof(*outdata) + optlen; - if (packlen == 0) - packlen = i; /* minimum sized packet */ - else if (i > packlen || packlen > maxpacket) { - Fprintf(stderr, "%s: packet size must be %d <= s <= %d\n", - prog, i, maxpacket); - exit(1); - } - outip = (struct ip *)malloc((unsigned)packlen); if (outip == NULL) { Fprintf(stderr, "%s: malloc: %s\n", prog, strerror(errno)); @@ -446,20 +529,22 @@ main(int argc, char **argv) memset((char *)outip, 0, packlen); outip->ip_v = IPVERSION; - outip->ip_tos = tos; -#ifdef BYTESWAP_IP_LEN + if (settos) + outip->ip_tos = tos; +#ifdef BYTESWAP_IP_HDR outip->ip_len = htons(packlen); + outip->ip_off = htons(off); #else outip->ip_len = packlen; + outip->ip_off = off; #endif - outip->ip_p = IPPROTO_UDP; - outudp = (struct udphdr *)(outip + 1); + outp = (u_char *)(outip + 1); #ifdef HAVE_RAW_OPTIONS if (lsrr > 0) { register u_char *optlist; - optlist = (u_char *)outudp; - (u_char *)outudp += optlen; + optlist = outp; + outp += optlen; /* final hop */ gwlist[lsrr] = to->sin_addr.s_addr; @@ -479,19 +564,40 @@ main(int argc, char **argv) #endif outip->ip_dst = to->sin_addr; - outip->ip_hl = ((u_char *)outudp - (u_char *)outip) >> 2; - + outip->ip_hl = (outp - (u_char *)outip) >> 2; ident = (getpid() & 0xffff) | 0x8000; - outudp->uh_sport = htons(ident); - outudp->uh_ulen = htons((u_short)(packlen - (sizeof(*outip) + optlen))); - - outdata = (struct outdata *)(outudp + 1); + if (useicmp) { + outip->ip_p = IPPROTO_ICMP; + + outicmp = (struct icmp *)outp; + outicmp->icmp_type = ICMP_ECHO; + outicmp->icmp_id = htons(ident); + + outdata = (struct outdata *)(outp + 8); /* XXX magic number */ + } else { + outip->ip_p = IPPROTO_UDP; + + outudp = (struct udphdr *)outp; + outudp->uh_sport = htons(ident); + outudp->uh_ulen = + htons((u_short)(packlen - (sizeof(*outip) + optlen))); + outdata = (struct outdata *)(outudp + 1); + } cp = "icmp"; if ((pe = getprotobyname(cp)) == NULL) { Fprintf(stderr, "%s: unknown protocol %s\n", prog, cp); exit(1); } + + /* Insure the socket fds won't be 0, 1 or 2 */ + if (open(devnull, O_RDONLY) < 0 || + open(devnull, O_RDONLY) < 0 || + open(devnull, O_RDONLY) < 0) { + Fprintf(stderr, "%s: open \"%s\": %s\n", + prog, devnull, strerror(errno)); + exit(1); + } if ((s = socket(AF_INET, SOCK_RAW, pe->p_proto)) < 0) { Fprintf(stderr, "%s: icmp socket: %s\n", prog, strerror(errno)); exit(1); @@ -503,14 +609,17 @@ main(int argc, char **argv) (void)setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (char *)&on, sizeof(on)); - if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) { +#ifndef __hpux + sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); +#else + sndsock = socket(AF_INET, SOCK_RAW, + useicmp ? IPPROTO_ICMP : IPPROTO_UDP); +#endif + if (sndsock < 0) { Fprintf(stderr, "%s: raw socket: %s\n", prog, strerror(errno)); exit(1); } - /* Revert to non-privileged user after opening sockets */ - setuid(getuid()); - #if defined(IP_OPTIONS) && !defined(HAVE_RAW_OPTIONS) if (lsrr > 0) { u_char optlist[MAX_IPOPTLEN]; @@ -535,8 +644,8 @@ main(int argc, char **argv) optlist[3] = IPOPT_MINOFF; memcpy(optlist + 4, gwlist, i); - if ((setsockopt(sndsock, pe->p_proto, IP_OPTIONS, optlist, - i + sizeof(gwlist[0]))) < 0) { + if ((setsockopt(sndsock, pe->p_proto, IP_OPTIONS, + (char *)optlist, i + sizeof(gwlist[0]))) < 0) { Fprintf(stderr, "%s: IP_OPTIONS: %s\n", prog, strerror(errno)); exit(1); @@ -557,6 +666,15 @@ main(int argc, char **argv) Fprintf(stderr, "%s: IP_HDRINCL: %s\n", prog, strerror(errno)); exit(1); } +#else +#ifdef IP_TOS + if (settos && setsockopt(sndsock, IPPROTO_IP, IP_TOS, + (char *)&tos, sizeof(tos)) < 0) { + Fprintf(stderr, "%s: setsockopt tos %d: %s\n", + prog, tos, strerror(errno)); + exit(1); + } +#endif #endif if (options & SO_DEBUG) (void)setsockopt(sndsock, SOL_SOCKET, SO_DEBUG, (char *)&on, @@ -565,18 +683,87 @@ main(int argc, char **argv) (void)setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE, (char *)&on, sizeof(on)); - if (source != NULL) { - source = savestr(getsin(&from, source)); - outip->ip_src = from.sin_addr; -#ifndef IP_HDRINCL - if (bind(sndsock, (struct sockaddr *)&from, sizeof(from)) < 0) { - Fprintf(stderr, "%s: bind: %s\n", - prog, strerror(errno)); - exit (1); + /* Get the interface address list */ + n = ifaddrlist(&al, errbuf); + if (n < 0) { + Fprintf(stderr, "%s: ifaddrlist: %s\n", prog, errbuf); + exit(1); + } + if (n == 0) { + Fprintf(stderr, + "%s: Can't find any network interfaces\n", prog); + exit(1); + } + + /* Look for a specific device */ + if (device != NULL) { + for (i = n; i > 0; --i, ++al) + if (strcmp(device, al->device) == 0) + break; + if (i <= 0) { + Fprintf(stderr, "%s: Can't find interface %.32s\n", + prog, device); + exit(1); } -#endif } + /* Determine our source address */ + if (source == NULL) { + /* + * If a device was specified, use the interface address. + * Otherwise, try to determine our source address. + */ + if (device != NULL) + setsin(from, al->addr); + else if ((err = findsaddr(to, from)) != NULL) { + Fprintf(stderr, "%s: findsaddr: %s\n", + prog, err); + exit(1); + } + } else { + hi = gethostinfo(source); + source = hi->name; + hi->name = NULL; + /* + * If the device was specified make sure it + * corresponds to the source address specified. + * Otherwise, use the first address (and warn if + * there are more than one). + */ + if (device != NULL) { + for (i = hi->n, ap = hi->addrs; i > 0; --i, ++ap) + if (*ap == al->addr) + break; + if (i <= 0) { + Fprintf(stderr, + "%s: %s is not on interface %.32s\n", + prog, source, device); + exit(1); + } + setsin(from, *ap); + } else { + setsin(from, hi->addrs[0]); + if (hi->n > 1) + Fprintf(stderr, + "%s: Warning: %s has multiple addresses; using %s\n", + prog, source, inet_ntoa(from->sin_addr)); + } + freehostinfo(hi); + } + + /* Revert to non-privileged user after opening sockets */ + setgid(getgid()); + setuid(getuid()); + + outip->ip_src = from->sin_addr; +#ifndef IP_HDRINCL + if (bind(sndsock, (struct sockaddr *)from, sizeof(*from)) < 0) { + Fprintf(stderr, "%s: bind: %s\n", + prog, strerror(errno)); + exit (1); + } +#endif + Fprintf(stderr, "%s to %s (%s)", prog, hostname, inet_ntoa(to->sin_addr)); if (source) @@ -584,10 +771,12 @@ main(int argc, char **argv) Fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, packlen); (void)fflush(stderr); - for (ttl = 1; ttl <= max_ttl; ++ttl) { + for (ttl = first_ttl; ttl <= max_ttl; ++ttl) { u_int32_t lastaddr = 0; + int gotlastaddr = 0; int got_there = 0; int unreachable = 0; + int sentfirst = 0; Printf("%2d ", ttl); for (probe = 0; probe < nprobes; ++probe) { @@ -596,19 +785,33 @@ main(int argc, char **argv) struct timezone tz; register struct ip *ip; + if (sentfirst && pausemsecs > 0) + usleep(pausemsecs * 1000); (void)gettimeofday(&t1, &tz); send_probe(++seq, ttl, &t1); - while ((cc = wait_for_reply(s, &from, &t1)) != 0) { + ++sentfirst; + while ((cc = wait_for_reply(s, from, &t1)) != 0) { (void)gettimeofday(&t2, &tz); - i = packet_ok(packet, cc, &from, seq); + i = packet_ok(packet, cc, from, seq); /* Skip short packet */ if (i == 0) continue; - if (from.sin_addr.s_addr != lastaddr) { - print(packet, cc, &from); - lastaddr = from.sin_addr.s_addr; + if (!gotlastaddr || + from->sin_addr.s_addr != lastaddr) { + print(packet, cc, from); + lastaddr = from->sin_addr.s_addr; + ++gotlastaddr; } Printf(" %.3f ms", deltaT(&t1, &t2)); + if (i == -2) { +#ifndef ARCHAIC + ip = (struct ip *)packet; + if (ip->ip_ttl <= 1) + Printf(" !"); +#endif + ++got_there; + break; + } /* time exceeded in transit */ if (i == -1) break; @@ -641,7 +844,7 @@ main(int argc, char **argv) case ICMP_UNREACH_NEEDFRAG: ++unreachable; - Printf(" !F"); + Printf(" !F-%d", pmtu); break; case ICMP_UNREACH_SRCFAIL: @@ -649,15 +852,21 @@ main(int argc, char **argv) Printf(" !S"); break; -/* rfc1716 */ -#ifndef ICMP_UNREACH_FILTER_PROHIB -#define ICMP_UNREACH_FILTER_PROHIB 13 /* admin prohibited filter */ -#endif case ICMP_UNREACH_FILTER_PROHIB: ++unreachable; Printf(" !X"); break; + case ICMP_UNREACH_HOST_PRECEDENCE: + ++unreachable; + Printf(" !V"); + break; + + case ICMP_UNREACH_PRECEDENCE_CUTOFF: + ++unreachable; + Printf(" !C"); + break; + default: ++unreachable; Printf(" !<%d>", code); @@ -679,7 +888,7 @@ main(int argc, char **argv) int wait_for_reply(register int sock, register struct sockaddr_in *fromp, - register struct timeval *tp) + register const struct timeval *tp) { fd_set fds; struct timeval now, wait; @@ -695,35 +904,118 @@ wait_for_reply(register int sock, register struct sockaddr_in *fromp, (void)gettimeofday(&now, &tz); tvsub(&wait, &now); - if (select(sock + 1, &fds, (fd_set *)0, (fd_set *)0, &wait) > 0) - cc = recvfrom(s, (char *)packet, sizeof(packet), 0, + if (select(sock + 1, &fds, NULL, NULL, &wait) > 0) + cc = recvfrom(sock, (char *)packet, sizeof(packet), 0, (struct sockaddr *)fromp, &fromlen); return(cc); } void -send_probe(register int seq, register int ttl, register struct timeval *tp) +send_probe(register int seq, int ttl, register struct timeval *tp) { - register int i; + register int cc; + register struct udpiphdr *ui, *oui; + struct ip tip; outip->ip_ttl = ttl; +#ifndef __hpux outip->ip_id = htons(ident + seq); +#endif - outudp->uh_dport = htons(port + seq); + /* + * In most cases, the kernel will recalculate the ip checksum. + * But we must do it anyway so that the udp checksum comes out + * right. + */ + if (doipcksum) { + outip->ip_sum = + in_cksum((u_short *)outip, sizeof(*outip) + optlen); + if (outip->ip_sum == 0) + outip->ip_sum = 0xffff; + } + /* Payload */ outdata->seq = seq; outdata->ttl = ttl; outdata->tv = *tp; - i = sendto(sndsock, (char *)outip, packlen, 0, &whereto, - sizeof(whereto)); - if (i < 0 || i != packlen) { - if (i < 0) + if (useicmp) + outicmp->icmp_seq = htons(seq); + else + outudp->uh_dport = htons(port + seq); + + if (useicmp) { + /* Always calculate checksum for icmp packets */ + outicmp->icmp_cksum = 0; + outicmp->icmp_cksum = in_cksum((u_short *)outicmp, + packlen - (sizeof(*outip) + optlen)); + if (outicmp->icmp_cksum == 0) + outicmp->icmp_cksum = 0xffff; + } else if (doipcksum) { + /* Checksum (we must save and restore ip header) */ + tip = *outip; + ui = (struct udpiphdr *)outip; + oui = (struct udpiphdr *)&tip; + /* Easier to zero and put back things that are ok */ + memset((char *)ui, 0, sizeof(ui->ui_i)); + ui->ui_src = oui->ui_src; + ui->ui_dst = oui->ui_dst; + ui->ui_pr = oui->ui_pr; + ui->ui_len = outudp->uh_ulen; + outudp->uh_sum = 0; + outudp->uh_sum = in_cksum((u_short *)ui, packlen); + if (outudp->uh_sum == 0) + outudp->uh_sum = 0xffff; + *outip = tip; + } + + /* XXX undocumented debugging hack */ + if (verbose > 1) { + register const u_short *sp; + register int nshorts, i; + + sp = (u_short *)outip; + nshorts = (u_int)packlen / sizeof(u_short); + i = 0; + Printf("[ %d bytes", packlen); + while (--nshorts >= 0) { + if ((i++ % 8) == 0) + Printf("\n\t"); + Printf(" %04x", ntohs(*sp++)); + } + if (packlen & 1) { + if ((i % 8) == 0) + Printf("\n\t"); + Printf(" %02x", *(u_char *)sp); + } + Printf("]\n"); + } + +#if !defined(IP_HDRINCL) && defined(IP_TTL) + if (setsockopt(sndsock, IPPROTO_IP, IP_TTL, + (char *)&ttl, sizeof(ttl)) < 0) { + Fprintf(stderr, "%s: setsockopt ttl %d: %s\n", + prog, ttl, strerror(errno)); + exit(1); + } +#endif + +#ifdef __hpux + cc = sendto(sndsock, useicmp ? (char *)outicmp : (char *)outudp, + packlen - (sizeof(*outip) + optlen), 0, &whereto, sizeof(whereto)); + if (cc > 0) + cc += sizeof(*outip) + optlen; +#else + cc = sendto(sndsock, (char *)outip, + packlen, 0, &whereto, sizeof(whereto)); +#endif + if (cc < 0 || cc != packlen) { + if (cc < 0) Fprintf(stderr, "%s: sendto: %s\n", prog, strerror(errno)); Printf("%s: wrote %s %d chars, ret=%d\n", - prog, hostname, packlen, i); + prog, hostname, packlen, cc); (void)fflush(stdout); } } @@ -783,18 +1075,47 @@ packet_ok(register u_char *buf, int cc, register struct sockaddr_in *from, #endif type = icp->icmp_type; code = icp->icmp_code; + /* Path MTU Discovery (RFC1191) */ + if (code != ICMP_UNREACH_NEEDFRAG) + pmtu = 0; + else { +#ifdef HAVE_ICMP_NEXTMTU + pmtu = ntohs(icp->icmp_nextmtu); +#else + pmtu = ntohs(((struct my_pmtu *)&icp->icmp_void)->ipm_nextmtu); +#endif + } if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) || - type == ICMP_UNREACH) { - struct ip *hip; - struct udphdr *up; + type == ICMP_UNREACH || type == ICMP_ECHOREPLY) { + register struct ip *hip; + register struct udphdr *up; + register struct icmp *hicmp; hip = &icp->icmp_ip; hlen = hip->ip_hl << 2; - up = (struct udphdr *)((u_char *)hip + hlen); - if (hlen + 12 <= cc && hip->ip_p == IPPROTO_UDP && - up->uh_sport == htons(ident) && - up->uh_dport == htons(port + seq)) - return (type == ICMP_TIMXCEED ? -1 : code + 1); + if (useicmp) { + /* XXX */ + if (type == ICMP_ECHOREPLY && + icp->icmp_id == htons(ident) && + icp->icmp_seq == htons(seq)) + return (-2); + + hicmp = (struct icmp *)((u_char *)hip + hlen); + /* XXX 8 is a magic number */ + if (hlen + 8 <= cc && + hip->ip_p == IPPROTO_ICMP && + hicmp->icmp_id == htons(ident) && + hicmp->icmp_seq == htons(seq)) + return (type == ICMP_TIMXCEED ? -1 : code + 1); + } else { + up = (struct udphdr *)((u_char *)hip + hlen); + /* XXX 8 is a magic number */ + if (hlen + 12 <= cc && + hip->ip_p == IPPROTO_UDP && + up->uh_sport == htons(ident) && + up->uh_dport == htons(port + seq)) + return (type == ICMP_TIMXCEED ? -1 : code + 1); + } } #ifndef ARCHAIC if (verbose) { @@ -832,11 +1153,10 @@ print(register u_char *buf, register int cc, register struct sockaddr_in *from) Printf(" %d bytes to %s", cc, inet_ntoa (ip->ip_dst)); } - -#ifdef notyet /* * Checksum routine for Internet Protocol family headers (C Version) */ +u_short in_cksum(register u_short *addr, register int len) { register int nleft = len; @@ -867,7 +1187,6 @@ in_cksum(register u_short *addr, register int len) answer = ~sum; /* truncate to 16 bits */ return (answer); } -#endif /* * Subtract 2 timeval structs: out = out - in. @@ -899,12 +1218,23 @@ inetname(struct in_addr in) if (first && !nflag) { first = 0; - if (gethostname(domain, MAXHOSTNAMELEN) == 0 && - (cp = strchr(domain, '.')) != NULL) { - (void)strncpy(domain, cp + 1, sizeof(domain) - 1); - domain[sizeof(domain) - 1] = '\0'; - } else + if (gethostname(domain, sizeof(domain) - 1) < 0) domain[0] = '\0'; + else { + cp = strchr(domain, '.'); + if (cp == NULL) { + hp = gethostbyname(domain); + if (hp != NULL) + cp = strchr(hp->h_name, '.'); + } + if (cp == NULL) + domain[0] = '\0'; + else { + ++cp; + (void)strncpy(domain, cp, sizeof(domain) - 1); + domain[sizeof(domain) - 1] = '\0'; + } + } } if (!nflag && in.s_addr != INADDR_ANY) { hp = gethostbyaddr((char *)&in, sizeof(in), AF_INET); @@ -920,14 +1250,38 @@ inetname(struct in_addr in) return (inet_ntoa(in)); } -char * -getaddr(register u_int32_t *ap, register char *hostname) +struct hostinfo * +gethostinfo(register char *hostname) { + register int n; register struct hostent *hp; + register struct hostinfo *hi; + register char **p; + register u_int32_t addr, *ap; - *ap = inet_addr(hostname); - if ((int32_t)*ap != -1) - return (hostname); + if (strlen(hostname) > 64) { + Fprintf(stderr, "%s: hostname \"%.32s...\" is too long\n", + prog, hostname); + exit(1); + } + hi = calloc(1, sizeof(*hi)); + if (hi == NULL) { + Fprintf(stderr, "%s: calloc %s\n", prog, strerror(errno)); + exit(1); + } + addr = inet_addr(hostname); + if ((int32_t)addr != -1) { + hi->name = strdup(hostname); + hi->n = 1; + hi->addrs = calloc(1, sizeof(hi->addrs[0])); + if (hi->addrs == NULL) { + Fprintf(stderr, "%s: calloc %s\n", + prog, strerror(errno)); + exit(1); + } + hi->addrs[0] = addr; + return (hi); + } hp = gethostbyname(hostname); if (hp == NULL) { @@ -938,30 +1292,86 @@ getaddr(register u_int32_t *ap, register char *hostname) Fprintf(stderr, "%s: bad host %s\n", prog, hostname); exit(1); } - memcpy((caddr_t)ap, hp->h_addr, hp->h_length); - return (hp->h_name); + hi->name = strdup(hp->h_name); + for (n = 0, p = hp->h_addr_list; *p != NULL; ++n, ++p) + continue; + hi->n = n; + hi->addrs = calloc(n, sizeof(hi->addrs[0])); + if (hi->addrs == NULL) { + Fprintf(stderr, "%s: calloc %s\n", prog, strerror(errno)); + exit(1); + } + for (ap = hi->addrs, p = hp->h_addr_list; *p != NULL; ++ap, ++p) + memcpy(ap, *p, sizeof(*ap)); + return (hi); } -char * -getsin(register struct sockaddr_in *sin, register char *hostname) +void +freehostinfo(register struct hostinfo *hi) +{ + if (hi->name != NULL) { + free(hi->name); + hi->name = NULL; + } + free((char *)hi->addrs); + free((char *)hi); +} + +void +getaddr(register u_int32_t *ap, register char *hostname) +{ + register struct hostinfo *hi; + + hi = gethostinfo(hostname); + *ap = hi->addrs[0]; + freehostinfo(hi); +} + +void +setsin(register struct sockaddr_in *sin, register u_int32_t addr) { memset(sin, 0, sizeof(*sin)); +#ifdef HAVE_SOCKADDR_SA_LEN + sin->sin_len = sizeof(*sin); +#endif sin->sin_family = AF_INET; - return (getaddr((u_int32_t *)&sin->sin_addr.s_addr, hostname)); + sin->sin_addr.s_addr = addr; } -char * -savestr(register const char *str) +/* String to value with optional min and max. Handles decimal and hex. */ +int +str2val(register const char *str, register const char *what, + register int mi, register int ma) { - register char *cp; + register const char *cp; + register int val; + char *ep; - cp = strdup(str); - if (cp == NULL) { - Fprintf(stderr, "%s: strdup: %s\n", prog, strerror(errno)); + if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) { + cp = str + 2; + val = (int)strtol(cp, &ep, 16); + } else + val = (int)strtol(str, &ep, 10); + if (*ep != '\0') { + Fprintf(stderr, "%s: \"%s\" bad value for %s \n", + prog, str, what); + exit(1); + } + if (val < mi && mi >= 0) { + if (mi == 0) + Fprintf(stderr, "%s: %s must be >= %d\n", + prog, what, mi); + else + Fprintf(stderr, "%s: %s must be > %d\n", + prog, what, mi - 1); + exit(1); + } + if (val > ma && ma >= 0) { + Fprintf(stderr, "%s: %s must be <= %d\n", prog, what, ma); exit(1); } - return (cp); + return (val); } __dead void @@ -970,8 +1380,9 @@ usage(void) extern char version[]; Fprintf(stderr, "Version %s\n", version); - Fprintf(stderr, "Usage: %s [-dnrv] [-w wait] [-m max_ttl] [-p port#] \ -[-q nqueries]\n\t [-t tos] [-s src_addr] [-g gateway] host [data_size]\n", - prog); + Fprintf(stderr, + "Usage: %s [-dFInrvx] [-g gateway] [-i iface] [-f first_ttl]\n" + "\t[-m max_ttl] [ -p port] [-q nqueries] [-s src_addr] [-t tos]\n" + "\t[-w waittime] [-z pausemsecs] host [packetlen]\n", prog); exit(1); } |