aboutsummaryrefslogtreecommitdiff
path: root/contrib/traceroute/traceroute.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/traceroute/traceroute.c')
-rw-r--r--contrib/traceroute/traceroute.c697
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);
}