diff options
author | fenner <fenner@FreeBSD.org> | 2002-07-28 02:26:31 +0000 |
---|---|---|
committer | fenner <fenner@FreeBSD.org> | 2002-07-28 02:26:31 +0000 |
commit | ee621bb64a9d8d52219e8f4fc3e97aad8332a7b4 (patch) | |
tree | 8a73173ed2899e833f93ab2671fb6366716a4bcf /contrib/traceroute/traceroute.c | |
parent | c8bf584e69c2fc1317303e487cdb994154f354cd (diff) | |
download | FreeBSD-src-ee621bb64a9d8d52219e8f4fc3e97aad8332a7b4.zip FreeBSD-src-ee621bb64a9d8d52219e8f4fc3e97aad8332a7b4.tar.gz |
Merge 1.4a12
Diffstat (limited to 'contrib/traceroute/traceroute.c')
-rw-r--r-- | contrib/traceroute/traceroute.c | 707 |
1 files changed, 509 insertions, 198 deletions
diff --git a/contrib/traceroute/traceroute.c b/contrib/traceroute/traceroute.c index bd23af9..666d570 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,11 +21,11 @@ #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"; #if 0 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 static const char rcsid[] = "$FreeBSD$"; @@ -220,6 +220,7 @@ static const char rcsid[] = #include <netinet/ip_var.h> #include <netinet/ip_icmp.h> #include <netinet/udp.h> +#include <netinet/udp_var.h> #include <netinet/tcp.h> #include <arpa/inet.h> @@ -230,7 +231,9 @@ static const char rcsid[] = #endif /* IPSEC */ #include <ctype.h> +#include <err.h> #include <errno.h> +#include <fcntl.h> #ifdef HAVE_MALLOC_H #include <malloc.h> #endif @@ -246,6 +249,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))) @@ -270,6 +288,13 @@ struct grehdr { /* For GRE, we prepare what looks like a PPTP packet */ #define GRE_PPTP_PROTO 0x880b +/* 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 */ @@ -278,22 +303,18 @@ struct outdata { int optlen; /* length of ip options */ }; -/* Descriptor structure for each outgoing protocol we support */ -struct outproto { - char *name; /* name of protocol */ - u_char num; /* IP protocol number */ - u_short hdrlen; /* max size of protocol header */ - u_short port; /* default base protocol-specific "port" */ - void (*prepare)(struct outdata *); - /* finish preparing an outgoing packet */ - int (*check)(const u_char *, int); - /* check an incoming packet */ +#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 ip packet */ -u_char *outprot; /* last output inner protocol packet */ +u_char *outp; /* last output inner protocol packet */ /* loose source route gateway list (including room for final destination) */ u_int32_t gwlist[NGATEWAYS + 1]; @@ -302,17 +323,23 @@ int s; /* receive (icmp) socket file descriptor */ int sndsock; /* send (udp) socket file descriptor */ struct sockaddr whereto; /* Who to try to reach */ +struct sockaddr wherefrom; /* Who we are */ int packlen; /* total length of packet */ int protlen; /* length of protocol part 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 min_ttl = 1; int max_ttl; +int first_ttl = 1; u_short ident; u_short port; /* protocol specific base "port" */ @@ -320,6 +347,12 @@ int options; /* socket options */ int verbose; int waittime = 5; /* time to wait for response (in seconds) */ int nflag; /* print addresses numerically */ +#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; @@ -327,22 +360,27 @@ 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 *); #ifdef IPSEC int setpolicy __P((int so, char *policy)); #endif void send_probe(int, int); +struct outproto *setproto(char *); +int str2val(const char *, const char *, int, int); void tvsub(struct timeval *, struct timeval *); 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 void udp_prep(struct outdata *); int udp_check(const u_char *, int); @@ -355,6 +393,18 @@ int gen_check(const u_char *, int); void icmp_prep(struct outdata *); int icmp_check(const u_char *, int); +/* Descriptor structure for each outgoing protocol we support */ +struct outproto { + char *name; /* name of protocol */ + u_char num; /* IP protocol number */ + u_short hdrlen; /* max size of protocol header */ + u_short port; /* default base protocol-specific "port" */ + void (*prepare)(struct outdata *); + /* finish preparing an outgoing packet */ + int (*check)(const u_char *, int); + /* check an incoming packet */ +}; + /* List of supported protocols. The first one is the default. The last one is the handler for generic protocols not explicitly listed. */ struct outproto protos[] = { @@ -404,21 +454,35 @@ struct outproto *proto = &protos[0]; 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_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 u_short off = 0; + struct ifaddrlist *al; + char errbuf[132]; register int optlen = 0; int requestPort = -1; int sump = 0; int sockerrno; + /* 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); + } /* * Do the setuid-required stuff first, then lose priveleges ASAP. * Do error checking for these two calls where they appeared in @@ -440,29 +504,39 @@ main(int argc, char **argv) int mib[4] = { CTL_NET, PF_INET, IPPROTO_IP, IPCTL_DEFTTL }; size_t sz = sizeof(max_ttl); - if (sysctl(mib, 4, &max_ttl, &sz, NULL, 0) == -1) - err(1, "sysctl(net.inet.ip.ttl)"); + if (sysctl(mib, 4, &max_ttl, &sz, NULL, 0) == -1) { + perror("sysctl(net.inet.ip.ttl)"); + exit(1); + } } #else max_ttl = 30; #endif - 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, "Sdnrvg:M:m:P:p:q:s:t:w:")) != EOF) + while ((op = getopt(argc, argv, "dFInrSvxf:g:i:M:m:P:p:q:s:t:w:z:")) != EOF) switch (op) { - case 'S': - sump = 1; - break; case 'd': options |= SO_DEBUG; break; + case 'f': + case 'M': /* FreeBSD compat. */ + first_ttl = str2val(optarg, "first ttl", 1, 255); + break; + + case 'F': + off = IP_DF; + break; + case 'g': if (lsrr >= NGATEWAYS) { Fprintf(stderr, @@ -470,26 +544,20 @@ main(int argc, char **argv) prog, NGATEWAYS); exit(1); } - (void)getaddr(gwlist + lsrr, optarg); + getaddr(gwlist + lsrr, optarg); ++lsrr; break; - case 'M': - min_ttl = atoi(optarg); - if (min_ttl < 1 || min_ttl > 0xff) { - Fprintf(stderr, "%s: invalid ttl value %s\n", - prog, optarg); - exit(1); - } + case 'i': + device = optarg; + break; + + case 'I': + proto = setproto("icmp"); break; case 'm': - max_ttl = atoi(optarg); - if (max_ttl < 1 || max_ttl > 0xff) { - Fprintf(stderr, "%s: invalid ttl value %s\n", - prog, optarg); - exit(1); - } + max_ttl = str2val(optarg, "max ttl", 1, 255); break; case 'n': @@ -497,50 +565,16 @@ main(int argc, char **argv) break; case 'P': - for (i = 0; protos[i].name != NULL; i++) { - if (strcasecmp(protos[i].name, optarg) == 0) { - break; - } - } - proto = &protos[i]; - if (proto->name == NULL) { /* generic handler */ - struct protoent *pe; - u_long pnum; - char *eptr; - - /* Determine the IP protocol number */ - if ((pe = getprotobyname(optarg)) != NULL) - pnum = pe->p_proto; - else { - pnum = strtoul(optarg, &eptr, 10); - if (pnum > 0xff - || *optarg == '\0' - || *eptr != '\0') { - Fprintf(stderr, "%s: unknown " - "protocol \"%s\"\n", - prog, optarg); - exit(1); - } - } - proto->num = pnum; - } + proto = setproto(optarg); break; case 'p': - requestPort = atoi(optarg); - if (requestPort <= 0) { - Fprintf(stderr, "%s: port must be > 0\n", prog); - exit(1); - } + requestPort = (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': @@ -555,27 +589,31 @@ main(int argc, char **argv) source = optarg; break; + case 'S': + sump = 1; + 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 || waittime >= 24L * 60 * 60) { - Fprintf(stderr, - "%s: wait must be > 1 sec and < 1 day\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: @@ -585,21 +623,40 @@ main(int argc, char **argv) /* Set requested port, if any, else default for this protocol */ port = (requestPort != -1) ? requestPort : proto->port; - /* Check min vs. max TTL */ - if (min_ttl > max_ttl) { - Fprintf(stderr, "%s: min ttl must be <= max ttl\n", prog); + 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) + proto->hdrlen + sizeof(struct outdata) + optlen; + 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: @@ -612,16 +669,6 @@ main(int argc, char **argv) setvbuf(stdout, NULL, _IOLBF, 0); #endif - if (lsrr > 0) - optlen = (lsrr + 1) * sizeof(gwlist[0]); - i = sizeof(*outip) + proto->hdrlen + sizeof(struct 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); - } protlen = packlen - sizeof(*outip) - optlen; outip = (struct ip *)malloc((unsigned)packlen); @@ -632,20 +679,23 @@ 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 = proto->num; - outprot = (u_char *)(outip + 1); + outp = (u_char *)(outip + 1); #ifdef HAVE_RAW_OPTIONS if (lsrr > 0) { register u_char *optlist; - optlist = (u_char *)outprot; - (u_char *)outprot += optlen; + optlist = outp; + outp += optlen; /* final hop */ gwlist[lsrr] = to->sin_addr.s_addr; @@ -665,8 +715,7 @@ main(int argc, char **argv) #endif outip->ip_dst = to->sin_addr; - outip->ip_hl = ((u_char *)outprot - (u_char *)outip) >> 2; - + outip->ip_hl = (outp - (u_char *)outip) >> 2; ident = (getpid() & 0xffff) | 0x8000; if (pe == NULL) { @@ -723,8 +772,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); @@ -745,6 +794,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, @@ -753,18 +811,83 @@ 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); + } + + 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 + #if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) if (setpolicy(sndsock, "in bypass") < 0) errx(1, "%s", ipsec_strerror()); @@ -780,10 +903,12 @@ main(int argc, char **argv) Fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, packlen); (void)fflush(stderr); - for (ttl = min_ttl; 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; int loss; Printf("%2d ", ttl); @@ -794,6 +919,8 @@ main(int argc, char **argv) register struct ip *ip; struct outdata outdata; + if (sentfirst && pausemsecs > 0) + usleep(pausemsecs * 1000); /* Prepare outgoing data */ outdata.seq = ++seq; outdata.ttl = ttl; @@ -806,20 +933,23 @@ main(int argc, char **argv) /* Finalize and send packet */ (*proto->prepare)(&outdata); send_probe(seq, ttl); + ++sentfirst; /* Wait for a reply */ - while ((cc = wait_for_reply(s, &from, &t1)) != 0) { + while ((cc = wait_for_reply(s, from, &t1)) != 0) { double T; int precis; (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; } T = deltaT(&t1, &t2); #ifdef SANE_PRECISION @@ -839,15 +969,12 @@ main(int argc, char **argv) if (ip->ip_ttl <= 1) Printf(" !"); #endif - ++got_there; break; } - /* time exceeded in transit */ if (i == -1) break; - code = i - 1; switch (code) { @@ -877,7 +1004,7 @@ main(int argc, char **argv) case ICMP_UNREACH_NEEDFRAG: ++unreachable; - Printf(" !F"); + Printf(" !F-%d", pmtu); break; case ICMP_UNREACH_SRCFAIL: @@ -885,15 +1012,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); @@ -920,7 +1053,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 *fdsp; size_t nfds; @@ -951,13 +1084,64 @@ wait_for_reply(register int sock, register struct sockaddr_in *fromp, exit(1); } if (error > 0) - cc = recvfrom(s, (char *)packet, sizeof(packet), 0, + cc = recvfrom(sock, (char *)packet, sizeof(packet), 0, (struct sockaddr *)fromp, &fromlen); free(fdsp); return(cc); } +void +send_probe(int seq, int ttl) +{ + register int cc; + + outip->ip_ttl = ttl; + outip->ip_id = htons(ident + seq); + + /* 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 + + cc = sendto(sndsock, (char *)outip, + packlen, 0, &whereto, sizeof(whereto)); + 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, cc); + (void)fflush(stdout); + } +} + #if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) int setpolicy(so, policy) @@ -980,26 +1164,6 @@ setpolicy(so, policy) } #endif -void -send_probe(int seq, int ttl) -{ - register int i; - - outip->ip_ttl = ttl; - outip->ip_id = htons(ident + seq); - - i = sendto(sndsock, (char *)outip, packlen, 0, &whereto, - sizeof(whereto)); - if (i < 0 || i != packlen) { - if (i < 0) - Fprintf(stderr, "%s: sendto: %s\n", - prog, strerror(errno)); - Printf("%s: wrote %s %d chars, ret=%d\n", - prog, hostname, packlen, i); - (void)fflush(stdout); - } -} - double deltaT(struct timeval *t1p, struct timeval *t2p) { @@ -1055,6 +1219,16 @@ 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_ECHOREPLY && proto->num == IPPROTO_ICMP && (*proto->check)((u_char *)icp,seq)) @@ -1090,7 +1264,7 @@ packet_ok(register u_char *buf, int cc, register struct sockaddr_in *from, void icmp_prep(struct outdata *outdata) { - struct icmp *const icmpheader = (struct icmp *) outprot; + struct icmp *const icmpheader = (struct icmp *) outp; icmpheader->icmp_type = ICMP_ECHO; icmpheader->icmp_id = htons(ident); @@ -1116,11 +1290,30 @@ icmp_check(const u_char *data, int seq) void udp_prep(struct outdata *outdata) { - struct udphdr *const udp = (struct udphdr *) outprot; - - udp->uh_sport = htons(ident); - udp->uh_dport = htons(port + outdata->seq); - udp->uh_ulen = htons((u_short)protlen); + struct udphdr *const outudp = (struct udphdr *) outp; + struct ip tip; + struct udpiphdr *ui, *oui; + + outudp->uh_sport = htons(ident); + outudp->uh_dport = htons(port + outdata->seq); + outudp->uh_ulen = htons((u_short)protlen); + 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; + } } int @@ -1135,7 +1328,7 @@ udp_check(const u_char *data, int seq) void tcp_prep(struct outdata *outdata) { - struct tcphdr *const tcp = (struct tcphdr *) outprot; + struct tcphdr *const tcp = (struct tcphdr *) outp; tcp->th_sport = htons(ident); tcp->th_dport = htons(port + outdata->seq); @@ -1157,7 +1350,7 @@ tcp_check(const u_char *data, int seq) void gre_prep(struct outdata *outdata) { - struct grehdr *const gre = (struct grehdr *) outprot; + struct grehdr *const gre = (struct grehdr *) outp; gre->flags = htons(0x2001); gre->proto = htons(port); @@ -1177,7 +1370,7 @@ gre_check(const u_char *data, int seq) void gen_prep(struct outdata *outdata) { - u_int16_t *const ptr = (u_int16_t *) outprot; + u_int16_t *const ptr = (u_int16_t *) outp; ptr[0] = htons(ident); ptr[1] = htons(port + outdata->seq); @@ -1277,12 +1470,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); @@ -1298,14 +1502,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) { @@ -1316,30 +1544,112 @@ 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); } - return (cp); + if (val > ma && ma >= 0) { + Fprintf(stderr, "%s: %s must be <= %d\n", prog, what, ma); + exit(1); + } + return (val); +} + +struct outproto * +setproto(char *pname) +{ + struct outproto *proto; + int i; + + for (i = 0; protos[i].name != NULL; i++) { + if (strcasecmp(protos[i].name, pname) == 0) { + break; + } + } + proto = &protos[i]; + if (proto->name == NULL) { /* generic handler */ + struct protoent *pe; + u_long pnum; + + /* Determine the IP protocol number */ + if ((pe = getprotobyname(pname)) != NULL) + pnum = pe->p_proto; + else + pnum = str2val(optarg, "proto number", 1, 255); + proto->num = pnum; + } + return proto; } void @@ -1348,8 +1658,9 @@ usage(void) extern char version[]; Fprintf(stderr, "Version %s\n", version); - Fprintf(stderr, "Usage: %s [-Sdnrv] [-w wait] [-m max_ttl] [-M min_ttl] \ -[-P proto]\n\t [-p port#] [-q nqueries] [-t tos] [-s src_addr] [-g gateway] \ -\n\t host [data_size]\n", prog); + Fprintf(stderr, + "Usage: %s [-dFInrSvx] [-g gateway] [-i iface] [-f first_ttl]\n" + "\t[-m max_ttl] [-p port] [-P proto] [-q nqueries] [-s src_addr]\n" + "\t[-t tos] [-w waittime] [-z pausemsecs] host [packetlen]\n", prog); exit(1); } |