summaryrefslogtreecommitdiffstats
path: root/contrib
diff options
context:
space:
mode:
authorfenner <fenner@FreeBSD.org>2002-07-28 02:26:31 +0000
committerfenner <fenner@FreeBSD.org>2002-07-28 02:26:31 +0000
commitee621bb64a9d8d52219e8f4fc3e97aad8332a7b4 (patch)
tree8a73173ed2899e833f93ab2671fb6366716a4bcf /contrib
parentc8bf584e69c2fc1317303e487cdb994154f354cd (diff)
downloadFreeBSD-src-ee621bb64a9d8d52219e8f4fc3e97aad8332a7b4.zip
FreeBSD-src-ee621bb64a9d8d52219e8f4fc3e97aad8332a7b4.tar.gz
Merge 1.4a12
Diffstat (limited to 'contrib')
-rw-r--r--contrib/traceroute/FREEBSD-upgrade9
-rw-r--r--contrib/traceroute/VERSION2
-rw-r--r--contrib/traceroute/traceroute.8123
-rw-r--r--contrib/traceroute/traceroute.c707
4 files changed, 613 insertions, 228 deletions
diff --git a/contrib/traceroute/FREEBSD-upgrade b/contrib/traceroute/FREEBSD-upgrade
index 749dd67..bc4918e 100644
--- a/contrib/traceroute/FREEBSD-upgrade
+++ b/contrib/traceroute/FREEBSD-upgrade
@@ -10,11 +10,13 @@ To upgrade to a newer version of traceroute, when it is available:
[Do not make ANY changes to the files.]
2. Use the command:
- cvs import -m 'Virgin import of LBL traceroute v<version>' \
+ cvs import -I linux-include \
+ -m 'Virgin import of LBL traceroute v<version>' \
src/contrib/traceroute LBL v<version>
For example, to do the import of version 1.3.2, I might have typed:
- cvs import -m 'Virgin import of LBL traceroute v1.3.2' \
+ cvs import -I linux-include \
+ -m 'Virgin import of LBL traceroute v1.3.2' \
src/contrib/traceroute LBL v1_3_2
3. Follow the instructions printed out in step 2 to resolve any
@@ -30,4 +32,7 @@ inclusion in the next vendor release of traceroute.
(The "SANE_PRECISION" patch has been submitted and rejected.)
+(The extensive modifications for TCP and GRE probes have not been
+submitted.)
+
fenner@freebsd.org - 30 Sep 1996
diff --git a/contrib/traceroute/VERSION b/contrib/traceroute/VERSION
index 1527104..26e2f76 100644
--- a/contrib/traceroute/VERSION
+++ b/contrib/traceroute/VERSION
@@ -1,2 +1,2 @@
-1.3.2+FreeBSD
+1.4a12+FreeBSD
$FreeBSD$
diff --git a/contrib/traceroute/traceroute.8 b/contrib/traceroute/traceroute.8
index 003025c..c7ad149 100644
--- a/contrib/traceroute/traceroute.8
+++ b/contrib/traceroute/traceroute.8
@@ -1,4 +1,4 @@
-.\" Copyright (c) 1989, 1995, 1996
+.\" Copyright (c) 1989, 1995, 1996, 1997, 1999, 2000
.\" The Regents of the University of California. All rights reserved.
.\"
.\" Redistribution and use in source and binary forms are permitted
@@ -13,25 +13,33 @@
.\" IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
.\" WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
.\"
-.\" $Header: traceroute.8,v 1.7 96/09/27 20:02:41 leres Exp $
+.\" $Id: traceroute.8,v 1.19 2000/09/21 08:44:19 leres Exp $
.\" $FreeBSD$
.\"
-.TH TRACEROUTE 8 "27 September 1996"
+.TH TRACEROUTE 8 "21 September 2000"
.UC 6
.SH NAME
traceroute \- print the route packets take to network host
.SH SYNOPSIS
-.. while ((op = getopt(argc, argv, "dnrvg:M:m:P:p:q:s:t:w:")) != EOF)
.na
.B traceroute
[
-.B \-Sdnrv
+.B \-dFISdnrvx
+] [
+.B \-f
+.I first_ttl
] [
.B \-g
-.I gw_host
+.I gateway
+]
+.br
+.ti +8
+[
+.B \-i
+.I iface
] [
.B \-M
-.I min_ttl
+.I first_ttl
]
.br
.ti +8
@@ -62,7 +70,12 @@ traceroute \- print the route packets take to network host
[
.B \-w
.I waittime
+] [
+.B \-z
+.I pausemsecs
]
+.br
+.ti +8
.I host
[
.I packetlen
@@ -85,12 +98,28 @@ name.
.PP
Other options are:
.TP
-.B \-S
-Print a summary of how many probes were not answered for each hop.
+.B \-f
+Set the initial time-to-live used in the first outgoing probe packet.
+.TP
+.B \-F
+Set the "don't fragment" bit.
+.TP
+.B \-d
+Enable socket level debugging.
.TP
.B \-g
Specify a loose source route gateway (8 maximum).
.TP
+.B \-i
+Specify a network interface to obtain the source IP address for
+outgoing probe packets. This is normally only useful on a multi-homed
+host. (See the
+.B \-s
+flag for another way to do this.)
+.TP
+.B \-I
+Use ICMP ECHO instead of UDP datagrams. (A synonym for "-P icmp").
+.TP
.B \-M
Set the initial time-to-live value used in outgoing probe packets.
The default is 1, i.e., start with the first hop.
@@ -141,13 +170,19 @@ that has no route through it (e.g., after the interface was dropped by
.IR routed (8C)).
.TP
.B \-s
-Use the following IP address (which must be given as an IP number, not
+Use the following IP address (which usually is given as an IP number, not
a hostname) as the source address in outgoing probe packets. On
-hosts with more than one IP address, this option can be used to
+multi-homed hosts (those with more than one IP
+address), this option can be used to
force the source address to be something other than the IP address
of the interface the probe packet is sent on. If the IP address
is not one of this machine's interface addresses, an error is
-returned and nothing is sent.
+returned and nothing is sent. (See the
+.B \-i
+flag for another way to do this.)
+.TP
+.B \-S
+Print a summary of how many probes were not answered for each hop.
.TP
.B \-t
Set the
@@ -159,7 +194,13 @@ are not running 4.4bsd, this may be academic since the normal network
services like telnet and ftp don't let you control the TOS).
Not all values of TOS are legal or
meaningful \- see the IP spec for definitions. Useful values are
-probably `-t 16' (low delay) and `-t 8' (high throughput).
+probably
+.RB ` -t
+.IR 16 '
+(low delay) and
+.RB ` -t
+.IR 8 '
+(high throughput).
.TP
.B \-v
Verbose output. Received ICMP packets other than TIME_EXCEEDED and
@@ -168,6 +209,22 @@ UNREACHABLEs are listed.
.B \-w
Set the time (in seconds) to wait for a response to a probe (default 5
sec.).
+.TP
+.B \-x
+Toggle ip checksums. Normally, this prevents traceroute from calculating
+ip checksums. In some cases, the operating system can overwrite parts of
+the outgoing packet but not recalculate the checksum (so in some cases
+the default is to not calculate checksums and using
+.B \-x
+causes them to be calcualted). Note that checksums are usually required
+for the last hop when using ICMP ECHO probes
+.RB ( \-I ).
+So they are always calculated when using ICMP.
+.TP
+.B \-z
+Set the time (in milliseconds) to pause between probes (default 0).
+Some systems such as Solaris and routers such as Ciscos rate limit
+icmp messages. A good value to use with this this is 500 (e.g. 1/2 second).
.PP
This program attempts to trace the route an IP packet would follow to some
internet host by launching UDP probe
@@ -177,19 +234,27 @@ with a ttl of one and increase by one until we get an ICMP "port
unreachable" (which means we got to "host") or hit a max (which
defaults to
.I net.inet.ip.ttl
-hops & can be changed with the \-m flag). Three
-probes (change with \-q flag) are sent at each ttl setting and a
+hops & can be changed with the
+.B \-m
+flag). Three
+probes (change with
+.B \-q
+flag) are sent at each ttl setting and a
line is printed showing the ttl, address of the gateway and
round trip time of each probe. If the probe answers come from
different gateways, the address of each responding system will
be printed. If there is no response within a 5 sec. timeout
-interval (changed with the \-w flag), a "*" is printed for that
+interval (changed with the
+.B \-w
+flag), a "*" is printed for that
probe.
.PP
We don't want the destination
host to process the UDP probe packets so the destination port is set to an
unlikely value (if some clod on the destination is using that
-value, it can be changed with the \-p flag).
+value, it can be changed with the
+.B \-p
+flag).
.PP
A sample use and output might be:
@@ -297,16 +362,20 @@ Other possible annotations after the time are
.BR !N ,
or
.B !P
-(got a host, network or protocol unreachable, respectively),
+(host, network or protocol unreachable),
.B !S
-or
-.B !F
-(source route failed or fragmentation needed \- neither of these should
-ever occur and the associated gateway is busted if you see one),
+(source route failed),
+.B !F\-<pmtu>
+(fragmentation needed \- the RFC1191 Path MTU Discovery value is displayed),
.B !X
-(communication administratively prohibited), or
-.B !<N>
-(ICMP unreachable code N).
+(communication administratively prohibited),
+.B !V
+(host precedence violation),
+.B !C
+(precedence cutoff in effect), or
+.B !<num>
+(ICMP unreachable code <num>).
+These are defined by RFC1812 (which supersedes RFC1716).
If almost all the probes result in some kind of unreachable, traceroute
will give up and exit.
.PP
@@ -317,7 +386,7 @@ Because of the load it could impose on the network, it is unwise to use
.I traceroute
during normal operations or from automated scripts.
.SH SEE ALSO
-netstat(1), ping(8)
+pathchar(8), netstat(1), ping(8)
.SH AUTHOR
Implemented by Van Jacobson from a suggestion by Steve Deering. Debugged
by a cast of thousands with particularly cogent suggestions or fixes from
@@ -326,7 +395,7 @@ C. Philip Wood, Tim Seaver and Ken Adelman.
The current version is available via anonymous ftp:
.LP
.RS
-.I ftp://ftp.ee.lbl.gov/traceroute.tar.Z
+.I ftp://ftp.ee.lbl.gov/traceroute.tar.gz
.RE
.SH BUGS
When using protocols other than UDP, functionality is reduced.
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);
}
OpenPOWER on IntegriCloud