/*
- * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2004-2015 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
*
- * @APPLE_LICENSE_HEADER_START@
- *
- * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
- * Reserved. This file contains Original Code and/or Modifications of
- * Original Code as defined in and that are subject to the Apple Public
- * Source License Version 1.0 (the 'License'). You may not use this file
- * except in compliance with the License. Please obtain a copy of the
- * License at http://www.apple.com/publicsource and read it before using
- * this file.
- *
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
- * License for the specific language governing rights and limitations
- * under the License."
- *
- * @APPLE_LICENSE_HEADER_END@
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
*/
-/*-
- * Copyright (c) 1990, 1993
+
+/*
+ * Copyright (c) 1988, 1989, 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000
* The Regents of the University of California. All rights reserved.
*
- * This code is derived from software contributed to Berkeley by
- * Van Jacobson.
- *
* Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
-#ifndef lint
-static char copyright[] =
-"@(#) Copyright (c) 1990, 1993\n\
- The Regents of the University of California. All rights reserved.\n";
-#endif /* not lint */
+#include <sys/cdefs.h>
#ifndef lint
-static char sccsid[] = "@(#)traceroute.c 8.1 (Berkeley) 6/6/93";
-#endif /* not lint */
+__unused static const char copyright[] =
+ "@(#) Copyright (c) 1988, 1989, 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000\n\
+The Regents of the University of California. All rights reserved.\n";
+#endif
/*
* traceroute host - trace the route ip packets follow going to "host".
* icmp "time exceeded" reply from a gateway. We start our probes
* 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 30 hops & can be changed with the -m flag). Three
- * probes (change with -q flag) are sent at each ttl setting and a
- * line is printed showing the ttl, address of the gateway and
+ * defaults to 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 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
* A sample use might be:
*
* [yak 71]% traceroute nis.nsf.net.
- * traceroute to nis.nsf.net (35.1.1.48), 30 hops max, 56 byte packet
+ * traceroute to nis.nsf.net (35.1.1.48), 64 hops max, 56 byte packet
* 1 helios.ee.lbl.gov (128.3.112.1) 19 ms 19 ms 0 ms
* 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms
* 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms
* A more interesting example is:
*
* [yak 72]% traceroute allspice.lcs.mit.edu.
- * traceroute to allspice.lcs.mit.edu (18.26.0.115), 30 hops max
+ * traceroute to allspice.lcs.mit.edu (18.26.0.115), 64 hops max
* 1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms
* 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 19 ms 19 ms
* 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 19 ms
* back to yourself. Unfortunately, SO many gateways botch source
* routing, the thing is almost worthless. Maybe one day...
*
- * -- Van Jacobson (van@helios.ee.lbl.gov)
+ * -- Van Jacobson (van@ee.lbl.gov)
* Tue Dec 20 03:50:13 PST 1988
*/
#include <sys/param.h>
-#include <sys/time.h>
-#include <sys/socket.h>
#include <sys/file.h>
#include <sys/ioctl.h>
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+#include <sys/socket.h>
+#ifdef HAVE_SYS_SYSCTL_H
+#include <sys/sysctl.h>
+#endif
+#include <sys/time.h>
#include <netinet/in_systm.h>
#include <netinet/in.h>
#include <netinet/ip.h>
+#include <netinet/ip_var.h>
#include <netinet/ip_icmp.h>
#include <netinet/udp.h>
+#include <netinet/udp_var.h>
+#include <netinet/tcp.h>
+#include <netinet/tcpip.h>
#include <arpa/inet.h>
+#ifdef IPSEC
+#include <net/route.h>
+#include <netinet6/ipsec.h> /* XXX */
+#endif /* IPSEC */
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#ifdef HAVE_MALLOC_H
+#include <malloc.h>
+#endif
+#include <memory.h>
#include <netdb.h>
#include <stdio.h>
-#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
-#define MAXPACKET 65535 /* max ip packet size */
-#ifndef MAXHOSTNAMELEN
-#define MAXHOSTNAMELEN 64
+#include "gnuc.h"
+#ifdef HAVE_OS_PROTO_H
+#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 "as.h"
+#include "traceroute.h"
-#ifndef FD_SET
-#define NFDBITS (8*sizeof(fd_set))
-#define FD_SETSIZE NFDBITS
-#define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
-#define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
-#define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
-#define FD_ZERO(p) bzero((char *)(p), sizeof(*(p)))
+/* Maximum number of gateways (include room for one noop) */
+#define NGATEWAYS ((int)((MAX_IPOPTLEN - IPOPT_MINOFF - 1) / sizeof(u_int32_t)))
+
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN 64
#endif
#define Fprintf (void)fprintf
-#define Sprintf (void)sprintf
#define Printf (void)printf
-/*
- * format of a (udp) probe packet.
- */
-struct opacket {
- struct ip ip;
- struct udphdr udp;
+/* What a GRE packet header looks like */
+struct grehdr {
+ u_int16_t flags;
+ u_int16_t proto;
+ u_int16_t length; /* PPTP version of these fields */
+ u_int16_t callId;
+};
+#ifndef IPPROTO_GRE
+#define IPPROTO_GRE 47
+#endif
+
+/* 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 */
u_char ttl; /* ttl packet left with */
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 opacket *outpacket; /* last output (udp) packet */
-int wait_for_reply __P((int, struct sockaddr_in *));
-void send_probe __P((int, int));
-double deltaT __P((struct timeval *, struct timeval *));
-int packet_ok __P((u_char *, int, struct sockaddr_in *, int));
-void print __P((u_char *, int, struct sockaddr_in *));
-void tvsub __P((struct timeval *, struct timeval *));
-char *inetname __P((struct in_addr));
-void usage __P(());
+struct ip *outip; /* last output ip packet */
+u_char *outp; /* last output inner protocol packet */
+
+struct ip *hip = NULL; /* Quoted IP header */
+int hiplen = 0;
+
+/* 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 */
-struct timezone tz; /* leftover */
struct sockaddr whereto; /* Who to try to reach */
-int datalen; /* How much data */
-
-char *source = 0;
+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 max_ttl = 30;
+int nprobes = -1;
+int max_ttl;
+int first_ttl = 1;
u_short ident;
-u_short port = 32768+666; /* start udp dest port # for probe packets */
+u_short port; /* protocol specific base "port" */
+
int options; /* socket options */
int verbose;
int waittime = 5; /* time to wait for response (in seconds) */
int nflag; /* print addresses numerically */
+int as_path; /* print as numbers for each hop */
+char *as_server = NULL;
+void *asn;
+#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 */
+int fixedPort = 0; /* Use fixed destination port for TCP and UDP */
+int printdiff = 0; /* Print the difference between sent and quoted */
+
+extern int optind;
+extern int opterr;
+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 **);
+u_short p_cksum(struct ip *, u_short *, int);
+int packet_ok(u_char *, int, struct sockaddr_in *, int);
+char *pr_type(u_char);
+void print(u_char *, int, struct sockaddr_in *);
+#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 *, const struct timeval *);
+void pkt_compare(const u_char *, int, const u_char *, int);
+#ifndef HAVE_USLEEP
+int usleep(u_int);
+#endif
+
+void udp_prep(struct outdata *);
+int udp_check(const u_char *, int);
+void tcp_prep(struct outdata *);
+int tcp_check(const u_char *, int);
+void gre_prep(struct outdata *);
+int gre_check(const u_char *, int);
+void gen_prep(struct outdata *);
+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 */
+ const char *key; /* An ascii key for the bytes of the header */
+ 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[] = {
+ {
+ "udp",
+ "spt dpt len sum",
+ IPPROTO_UDP,
+ sizeof(struct udphdr),
+ 32768 + 666,
+ udp_prep,
+ udp_check
+ },
+ {
+ "tcp",
+ "spt dpt seq ack xxflwin sum urp",
+ IPPROTO_TCP,
+ sizeof(struct tcphdr),
+ 32768 + 666,
+ tcp_prep,
+ tcp_check
+ },
+ {
+ "gre",
+ "flg pro len clid",
+ IPPROTO_GRE,
+ sizeof(struct grehdr),
+ GRE_PPTP_PROTO,
+ gre_prep,
+ gre_check
+ },
+ {
+ "icmp",
+ "typ cod sum ",
+ IPPROTO_ICMP,
+ sizeof(struct icmp),
+ 0,
+ icmp_prep,
+ icmp_check
+ },
+ {
+ NULL,
+ NULL,
+ 0,
+ 2 * sizeof(u_short),
+ 0,
+ gen_prep,
+ gen_check
+ },
+};
+struct outproto *proto = &protos[0];
+
+const char *ip_hdr_key = "vhtslen id off tlprsum srcip dstip opts";
int
-main(argc, argv)
- int argc;
- char *argv[];
+main(int argc, char **argv)
{
- extern char *optarg;
- extern int optind;
- struct hostent *hp;
- struct protoent *pe;
- struct sockaddr_in from, *to;
- int ch, i, on, probe, seq, tos, ttl;
-
- on = 1;
- seq = tos = 0;
- to = (struct sockaddr_in *)&whereto;
- while ((ch = getopt(argc, argv, "dm:np:q:rs:t:w:v")) != EOF)
- switch(ch) {
+ register int op, code, n;
+ register char *cp;
+ 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;
+ int tos = 0, settos = 0;
+ register int lsrr = 0;
+ register u_short off = 0;
+ struct ifaddrlist *al;
+ char errbuf[132];
+ int requestPort = -1;
+ int sump = 0;
+ int sockerrno = 0;
+
+ if (argv[0] == NULL)
+ prog = "traceroute";
+ else if ((cp = strrchr(argv[0], '/')) != NULL)
+ prog = cp + 1;
+ else
+ prog = argv[0];
+
+ /* 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
+ * the original code.
+ */
+ cp = "icmp";
+ pe = getprotobyname(cp);
+ if (pe) {
+ if ((s = socket(AF_INET, SOCK_RAW, pe->p_proto)) < 0)
+ sockerrno = errno;
+ else if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
+ sockerrno = errno;
+ }
+
+ setuid(getuid());
+
+#ifdef IPCTL_DEFTTL
+ {
+ 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) {
+ perror("sysctl(net.inet.ip.ttl)");
+ exit(1);
+ }
+ }
+#else
+ max_ttl = 30;
+#endif
+
+ opterr = 0;
+ while ((op = getopt(argc, argv, "aA:edDFInrSvxf:g:i:M:m:P:p:q:s:t:w:z:")) != EOF)
+ switch (op) {
+ case 'a':
+ as_path = 1;
+ break;
+
+ case 'A':
+ as_path = 1;
+ as_server = optarg;
+ break;
+
case 'd':
options |= SO_DEBUG;
break;
- case 'm':
- max_ttl = atoi(optarg);
- if (max_ttl <= 1) {
+
+ case 'D':
+ printdiff = 1;
+ break;
+
+ case 'e':
+ fixedPort = 1;
+ 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,
- "traceroute: max ttl must be >1.\n");
+ "%s: No more than %d gateways\n",
+ prog, NGATEWAYS);
exit(1);
}
+ getaddr(gwlist + lsrr, optarg);
+ ++lsrr;
+ break;
+
+ case 'i':
+ device = optarg;
break;
+
+ case 'I':
+ proto = setproto("icmp");
+ break;
+
+ case 'm':
+ max_ttl = str2val(optarg, "max ttl", 1, 255);
+ break;
+
case 'n':
- nflag++;
+ ++nflag;
break;
+
+ case 'P':
+ proto = setproto(optarg);
+ break;
+
case 'p':
- port = atoi(optarg);
- if (port < 1) {
- Fprintf(stderr,
- "traceroute: port must be >0.\n");
- exit(1);
- }
+ requestPort = (u_short)str2val(optarg, "port",
+ 1, (1 << 16) - 1);
break;
+
case 'q':
- nprobes = atoi(optarg);
- if (nprobes < 1) {
- Fprintf(stderr,
- "traceroute: nprobes must be >0.\n");
- exit(1);
- }
+ nprobes = str2val(optarg, "nprobes", 1, -1);
break;
+
case 'r':
options |= SO_DONTROUTE;
break;
+
case 's':
/*
* set the ip source address of the outbound
*/
source = optarg;
break;
+
+ case 'S':
+ sump = 1;
+ break;
+
case 't':
- tos = atoi(optarg);
- if (tos < 0 || tos > 255) {
- Fprintf(stderr,
- "traceroute: tos must be 0 to 255.\n");
- exit(1);
- }
+ tos = str2val(optarg, "tos", 0, 255);
+ ++settos;
break;
+
case 'v':
- verbose++;
+ ++verbose;
+ break;
+
+ case 'x':
+ doipcksum = (doipcksum == 0);
break;
+
case 'w':
- waittime = atoi(optarg);
- if (waittime <= 1) {
- Fprintf(stderr,
- "traceroute: wait must be >1 sec.\n");
- exit(1);
- }
+ waittime = str2val(optarg, "wait time",
+ 1, 24 * 60 * 60);
+ break;
+
+ case 'z':
+ pausemsecs = str2val(optarg, "pause msecs",
+ 0, 60 * 60 * 1000);
break;
+
default:
usage();
}
- argc -= optind;
- argv += optind;
- if (argc < 1)
- usage();
+ /* Set requested port, if any, else default for this protocol */
+ port = (requestPort != -1) ? requestPort : proto->port;
- setlinebuf (stdout);
+ if (nprobes == -1)
+ nprobes = printdiff ? 1 : 3;
- (void) bzero((char *)&whereto, sizeof(struct sockaddr));
- to->sin_family = AF_INET;
- to->sin_addr.s_addr = inet_addr(*argv);
- if (to->sin_addr.s_addr != -1)
- hostname = *argv;
- else {
- hp = gethostbyname(*argv);
- if (hp) {
- to->sin_family = hp->h_addrtype;
- bcopy(hp->h_addr, (caddr_t)&to->sin_addr, hp->h_length);
- hostname = hp->h_name;
- } else {
- (void)fprintf(stderr,
- "traceroute: unknown host %s\n", *argv);
- exit(1);
- }
- }
- if (*++argv)
- datalen = atoi(*argv);
- if (datalen < 0 || datalen >= MAXPACKET - sizeof(struct opacket)) {
+ if (first_ttl > max_ttl) {
Fprintf(stderr,
- "traceroute: packet size must be 0 <= s < %ld.\n",
- MAXPACKET - sizeof(struct opacket));
+ "%s: first ttl (%d) may not be greater than max ttl (%d)\n",
+ prog, first_ttl, max_ttl);
exit(1);
}
- datalen += sizeof(struct opacket);
- outpacket = (struct opacket *)malloc((unsigned)datalen);
- if (! outpacket) {
- perror("traceroute: malloc");
+
+ 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 = str2val(argv[optind + 1],
+ "packet length", minpacket, maxpacket);
+ /* Fall through */
+
+ case 1:
+ 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:
+ usage();
+ }
+
+#ifdef HAVE_SETLINEBUF
+ setlinebuf (stdout);
+#else
+ setvbuf(stdout, NULL, _IOLBF, 0);
+#endif
+
+ protlen = packlen - sizeof(*outip) - optlen;
+
+ outip = (struct ip *)malloc((unsigned)packlen);
+ if (outip == NULL) {
+ Fprintf(stderr, "%s: malloc: %s\n", prog, strerror(errno));
exit(1);
}
- (void) bzero((char *)outpacket, datalen);
- outpacket->ip.ip_dst = to->sin_addr;
- outpacket->ip.ip_tos = tos;
- outpacket->ip.ip_v = IPVERSION;
- outpacket->ip.ip_id = 0;
+ memset((char *)outip, 0, packlen);
+
+ outip->ip_v = IPVERSION;
+ 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;
+ outp = (u_char *)(outip + 1);
+#ifdef HAVE_RAW_OPTIONS
+ if (lsrr > 0) {
+ register u_char *optlist;
+
+ optlist = outp;
+ outp += optlen;
+
+ /* final hop */
+ gwlist[lsrr] = to->sin_addr.s_addr;
+
+ outip->ip_dst.s_addr = gwlist[0];
+
+ /* force 4 byte alignment */
+ optlist[0] = IPOPT_NOP;
+ /* loose source route option */
+ optlist[1] = IPOPT_LSRR;
+ i = lsrr * sizeof(gwlist[0]);
+ optlist[2] = i + 3;
+ /* Pointer to LSRR addresses */
+ optlist[3] = IPOPT_MINOFF;
+ memcpy(optlist + 4, gwlist + 1, i);
+ } else
+#endif
+ outip->ip_dst = to->sin_addr;
+ outip->ip_hl = (outp - (u_char *)outip) >> 2;
ident = (getpid() & 0xffff) | 0x8000;
- if ((pe = getprotobyname("icmp")) == NULL) {
- Fprintf(stderr, "icmp: unknown protocol\n");
- exit(10);
+ if (pe == NULL) {
+ Fprintf(stderr, "%s: unknown protocol %s\n", prog, cp);
+ exit(1);
}
- if ((s = socket(AF_INET, SOCK_RAW, pe->p_proto)) < 0) {
- perror("traceroute: icmp socket");
- exit(5);
+ if (s < 0) {
+ errno = sockerrno;
+ Fprintf(stderr, "%s: icmp socket: %s\n", prog, strerror(errno));
+ exit(1);
}
+ (void) setsockopt(s, SOL_SOCKET, SO_RECV_ANYIF, (char *)&on,
+ sizeof(on));
if (options & SO_DEBUG)
- (void) setsockopt(s, SOL_SOCKET, SO_DEBUG,
- (char *)&on, sizeof(on));
+ (void)setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&on,
+ sizeof(on));
if (options & SO_DONTROUTE)
- (void) setsockopt(s, SOL_SOCKET, SO_DONTROUTE,
- (char *)&on, sizeof(on));
+ (void)setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (char *)&on,
+ sizeof(on));
+
+#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
+ if (setpolicy(s, "in bypass") < 0)
+ errx(1, "%s", ipsec_strerror());
+
+ if (setpolicy(s, "out bypass") < 0)
+ errx(1, "%s", ipsec_strerror());
+#endif /* defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) */
+
+ if (sndsock < 0) {
+ errno = sockerrno;
+ Fprintf(stderr, "%s: raw socket: %s\n", prog, strerror(errno));
+ exit(1);
+ }
- if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) {
- perror("traceroute: raw socket");
- exit(5);
+#if defined(IP_OPTIONS) && !defined(HAVE_RAW_OPTIONS)
+ if (lsrr > 0) {
+ u_char optlist[MAX_IPOPTLEN];
+
+ cp = "ip";
+ if ((pe = getprotobyname(cp)) == NULL) {
+ Fprintf(stderr, "%s: unknown protocol %s\n", prog, cp);
+ exit(1);
+ }
+
+ /* final hop */
+ gwlist[lsrr] = to->sin_addr.s_addr;
+ ++lsrr;
+
+ /* force 4 byte alignment */
+ optlist[0] = IPOPT_NOP;
+ /* loose source route option */
+ optlist[1] = IPOPT_LSRR;
+ i = lsrr * sizeof(gwlist[0]);
+ optlist[2] = i + 3;
+ /* Pointer to LSRR addresses */
+ optlist[3] = IPOPT_MINOFF;
+ memcpy(optlist + 4, gwlist, i);
+
+ 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);
+ }
}
+#endif
+
#ifdef SO_SNDBUF
- if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&datalen,
- sizeof(datalen)) < 0) {
- perror("traceroute: SO_SNDBUF");
- exit(6);
+ if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&packlen,
+ sizeof(packlen)) < 0) {
+ Fprintf(stderr, "%s: SO_SNDBUF: %s\n", prog, strerror(errno));
+ exit(1);
}
-#endif SO_SNDBUF
+#endif
#ifdef IP_HDRINCL
if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
- sizeof(on)) < 0) {
- perror("traceroute: IP_HDRINCL");
- exit(6);
+ sizeof(on)) < 0) {
+ 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 IP_HDRINCL
+#endif
+#endif
if (options & SO_DEBUG)
- (void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG,
- (char *)&on, sizeof(on));
+ (void)setsockopt(sndsock, SOL_SOCKET, SO_DEBUG, (char *)&on,
+ sizeof(on));
if (options & SO_DONTROUTE)
- (void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE,
- (char *)&on, sizeof(on));
-
- if (source) {
- (void) bzero((char *)&from, sizeof(struct sockaddr));
- from.sin_family = AF_INET;
- from.sin_addr.s_addr = inet_addr(source);
- if (from.sin_addr.s_addr == -1) {
- Printf("traceroute: unknown host %s\n", source);
+ (void)setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE, (char *)&on,
+ sizeof(on));
+
+ /* Get the interface address list */
+ n = ifaddrlist(&al, errbuf, sizeof(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);
+ }
+ }
+
+ /* 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);
}
- outpacket->ip.ip_src = from.sin_addr;
-#ifndef IP_HDRINCL
- if (bind(sndsock, (struct sockaddr *)&from, sizeof(from)) < 0) {
- perror ("traceroute: bind:");
- 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;
+
+ /* Check the source address (-s), if any, is valid */
+ if (bind(sndsock, (struct sockaddr *)from, sizeof(*from)) < 0) {
+ Fprintf(stderr, "%s: bind: %s\n",
+ prog, strerror(errno));
+ exit (1);
+ }
+
+ if (as_path) {
+ asn = as_setup(as_server);
+ if (asn == NULL) {
+ Fprintf(stderr, "%s: as_setup failed, AS# lookups"
+ " disabled\n", prog);
+ (void)fflush(stderr);
+ as_path = 0;
}
-#endif IP_HDRINCL
}
+
+#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
+ if (setpolicy(sndsock, "in bypass") < 0)
+ errx(1, "%s", ipsec_strerror());
+
+ if (setpolicy(sndsock, "out bypass") < 0)
+ errx(1, "%s", ipsec_strerror());
+#endif /* defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) */
- Fprintf(stderr, "traceroute to %s (%s)", hostname,
- inet_ntoa(to->sin_addr));
+ Fprintf(stderr, "%s to %s (%s)",
+ prog, hostname, inet_ntoa(to->sin_addr));
if (source)
Fprintf(stderr, " from %s", source);
- Fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, datalen);
- (void) fflush(stderr);
+ Fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, packlen);
+ (void)fflush(stderr);
- for (ttl = 1; ttl <= max_ttl; ++ttl) {
- u_long lastaddr = 0;
+ 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);
- for (probe = 0; probe < nprobes; ++probe) {
- int cc;
+ for (probe = 0, loss = 0; probe < nprobes; ++probe) {
+ register int cc;
struct timeval t1, t2;
struct timezone tz;
- struct ip *ip;
-
- (void) gettimeofday(&t1, &tz);
- send_probe(++seq, ttl);
- while (cc = wait_for_reply(s, &from)) {
- (void) gettimeofday(&t2, &tz);
- if ((i = packet_ok(packet, cc, &from, seq))) {
- if (from.sin_addr.s_addr != lastaddr) {
- print(packet, cc, &from);
- lastaddr = from.sin_addr.s_addr;
- }
- Printf(" %g ms", deltaT(&t1, &t2));
- switch(i - 1) {
- case ICMP_UNREACH_PORT:
+ register struct ip *ip;
+ struct outdata outdata;
+
+ if (sentfirst && pausemsecs > 0)
+ usleep(pausemsecs * 1000);
+ /* Prepare outgoing data */
+ outdata.seq = ++seq;
+ outdata.ttl = ttl;
+
+ /* Avoid alignment problems by copying bytewise: */
+ (void)gettimeofday(&t1, &tz);
+ memcpy(&outdata.tv, &t1, sizeof(outdata.tv));
+
+ /* 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) {
+ double T;
+ int precis;
+
+ (void)gettimeofday(&t2, &tz);
+ i = packet_ok(packet, cc, from, seq);
+ /* Skip short packet */
+ if (i == 0)
+ continue;
+ if (!gotlastaddr ||
+ from->sin_addr.s_addr != lastaddr) {
+ if (gotlastaddr) printf("\n ");
+ print(packet, cc, from);
+ lastaddr = from->sin_addr.s_addr;
+ ++gotlastaddr;
+ }
+ T = deltaT(&t1, &t2);
+#ifdef SANE_PRECISION
+ if (T >= 1000.0)
+ precis = 0;
+ else if (T >= 100.0)
+ precis = 1;
+ else if (T >= 10.0)
+ precis = 2;
+ else
+#endif
+ precis = 3;
+ Printf(" %.*f ms", precis, T);
+ if (printdiff) {
+ Printf("\n");
+ Printf("%*.*s%s\n",
+ -(outip->ip_hl << 3),
+ outip->ip_hl << 3,
+ ip_hdr_key,
+ proto->key);
+ pkt_compare((void *)outip, packlen,
+ (void *)hip, hiplen);
+ }
+ if (i == -2) {
#ifndef ARCHAIC
- ip = (struct ip *)packet;
- if (ip->ip_ttl <= 1)
- Printf(" !");
-#endif ARCHAIC
- ++got_there;
- break;
- case ICMP_UNREACH_NET:
- ++unreachable;
- Printf(" !N");
- break;
- case ICMP_UNREACH_HOST:
- ++unreachable;
- Printf(" !H");
- break;
- case ICMP_UNREACH_PROTOCOL:
- ++got_there;
- Printf(" !P");
- break;
- case ICMP_UNREACH_NEEDFRAG:
- ++unreachable;
- Printf(" !F");
- break;
- case ICMP_UNREACH_SRCFAIL:
- ++unreachable;
- Printf(" !S");
- break;
- }
+ ip = (struct ip *)packet;
+ if (ip->ip_ttl <= 1)
+ Printf(" !");
+#endif
+ ++got_there;
break;
}
+ /* time exceeded in transit */
+ if (i == -1)
+ break;
+ code = i - 1;
+ switch (code) {
+
+ case ICMP_UNREACH_PORT:
+#ifndef ARCHAIC
+ ip = (struct ip *)packet;
+ if (ip->ip_ttl <= 1)
+ Printf(" !");
+#endif
+ ++got_there;
+ break;
+
+ case ICMP_UNREACH_NET:
+ ++unreachable;
+ Printf(" !N");
+ break;
+
+ case ICMP_UNREACH_HOST:
+ ++unreachable;
+ Printf(" !H");
+ break;
+
+ case ICMP_UNREACH_PROTOCOL:
+ ++got_there;
+ Printf(" !P");
+ break;
+
+ case ICMP_UNREACH_NEEDFRAG:
+ ++unreachable;
+ Printf(" !F-%d", pmtu);
+ break;
+
+ case ICMP_UNREACH_SRCFAIL:
+ ++unreachable;
+ Printf(" !S");
+ break;
+
+ case ICMP_UNREACH_NET_UNKNOWN:
+ ++unreachable;
+ Printf(" !U");
+ break;
+
+ case ICMP_UNREACH_HOST_UNKNOWN:
+ ++unreachable;
+ Printf(" !W");
+ break;
+
+ case ICMP_UNREACH_ISOLATED:
+ ++unreachable;
+ Printf(" !I");
+ break;
+
+ case ICMP_UNREACH_NET_PROHIB:
+ ++unreachable;
+ Printf(" !A");
+ break;
+
+ case ICMP_UNREACH_HOST_PROHIB:
+ ++unreachable;
+ Printf(" !Z");
+ break;
+
+ case ICMP_UNREACH_TOSNET:
+ ++unreachable;
+ Printf(" !Q");
+ break;
+
+ case ICMP_UNREACH_TOSHOST:
+ ++unreachable;
+ Printf(" !T");
+ break;
+
+ 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);
+ break;
+ }
+ break;
}
- if (cc == 0)
+ if (cc == 0) {
+ loss++;
Printf(" *");
- (void) fflush(stdout);
+ }
+ (void)fflush(stdout);
+ }
+ if (sump) {
+ Printf(" (%d%% loss)", (loss * 100) / nprobes);
}
putchar('\n');
- if (got_there || unreachable >= nprobes-1)
- exit(0);
+ if (got_there ||
+ (unreachable > 0 && unreachable >= nprobes - 1))
+ break;
}
+ if (as_path)
+ as_shutdown(asn);
+ exit(0);
}
int
-wait_for_reply(sock, from)
- int sock;
- struct sockaddr_in *from;
+wait_for_reply(register int sock, register struct sockaddr_in *fromp,
+ register const struct timeval *tp)
{
- fd_set fds;
- struct timeval wait;
- int cc = 0;
- int fromlen = sizeof (*from);
-
- FD_ZERO(&fds);
- FD_SET(sock, &fds);
- wait.tv_sec = waittime; wait.tv_usec = 0;
+ fd_set *fdsp;
+ size_t nfds;
+ struct timeval now, wait;
+ struct timezone tz;
+ register int cc = 0;
+ register int error;
+ socklen_t fromlen = sizeof(*fromp);
+
+ nfds = howmany(sock + 1, NFDBITS);
+ if ((fdsp = malloc(nfds * sizeof(fd_set))) == NULL)
+ err(1, "malloc");
+ memset(fdsp, 0, nfds * sizeof(fd_set));
+ FD_SET(sock, fdsp);
+
+ wait.tv_sec = tp->tv_sec + waittime;
+ wait.tv_usec = tp->tv_usec;
+ (void)gettimeofday(&now, &tz);
+ tvsub(&wait, &now);
+ if (wait.tv_sec < 0) {
+ wait.tv_sec = 0;
+ wait.tv_usec = 1;
+ }
- if (select(sock+1, &fds, (fd_set *)0, (fd_set *)0, &wait) > 0)
- cc=recvfrom(s, (char *)packet, sizeof(packet), 0,
- (struct sockaddr *)from, &fromlen);
+ error = select(sock + 1, fdsp, NULL, NULL, &wait);
+ if (error == -1 && errno == EINVAL) {
+ Fprintf(stderr, "%s: botched select() args\n", prog);
+ exit(1);
+ }
+ if (error > 0)
+ cc = recvfrom(sock, (char *)packet, sizeof(packet), 0,
+ (struct sockaddr *)fromp, &fromlen);
+ free(fdsp);
return(cc);
}
-
void
-send_probe(seq, ttl)
- int seq, ttl;
+send_probe(int seq, int ttl)
{
- struct opacket *op = outpacket;
- struct ip *ip = &op->ip;
- struct udphdr *up = &op->udp;
- int i;
+ 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
- ip->ip_off = 0;
- ip->ip_hl = sizeof(*ip) >> 2;
- ip->ip_p = IPPROTO_UDP;
- ip->ip_len = datalen;
- ip->ip_ttl = ttl;
- ip->ip_v = IPVERSION;
- ip->ip_id = htons(ident+seq);
-
- up->uh_sport = htons(ident);
- up->uh_dport = htons(port+seq);
- up->uh_ulen = htons((u_short)(datalen - sizeof(struct ip)));
- up->uh_sum = 0;
-
- op->seq = seq;
- op->ttl = ttl;
- (void) gettimeofday(&op->tv, &tz);
-
- i = sendto(sndsock, (char *)outpacket, datalen, 0, &whereto,
- sizeof(struct sockaddr));
- if (i < 0 || i != datalen) {
- if (i<0)
- perror("sendto");
- Printf("traceroute: wrote %s %d chars, ret=%d\n", hostname,
- datalen, i);
- (void) fflush(stdout);
+ 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)
+ int so;
+ char *policy;
+{
+ char *buf;
+
+ buf = ipsec_set_policy(policy, strlen(policy));
+ if (buf == NULL) {
+ warnx("%s", ipsec_strerror());
+ return -1;
+ }
+ (void)setsockopt(so, IPPROTO_IP, IP_IPSEC_POLICY,
+ buf, ipsec_get_policylen(buf));
+
+ free(buf);
+
+ return 0;
+}
+#endif
double
-deltaT(t1p, t2p)
- struct timeval *t1p, *t2p;
+deltaT(struct timeval *t1p, struct timeval *t2p)
{
register double dt;
return (dt);
}
-
/*
* Convert an ICMP "type" field to a printable string.
*/
char *
-pr_type(t)
- u_char t;
+pr_type(register u_char t)
{
static char *ttab[] = {
"Echo Reply", "ICMP 1", "ICMP 2", "Dest Unreachable",
"Info Reply"
};
- if(t > 16)
+ if (t > 16)
return("OUT-OF-RANGE");
return(ttab[t]);
}
-
int
-packet_ok(buf, cc, from, seq)
- u_char *buf;
- int cc;
- struct sockaddr_in *from;
- int seq;
+packet_ok(register u_char *buf, int cc, register struct sockaddr_in *from,
+ register int seq)
{
register struct icmp *icp;
- u_char type, code;
- int hlen;
+ register u_char type, code;
+ register int hlen;
#ifndef ARCHAIC
- struct ip *ip;
+ register struct ip *ip;
ip = (struct ip *) buf;
hlen = ip->ip_hl << 2;
icp = (struct icmp *)(buf + hlen);
#else
icp = (struct icmp *)buf;
-#endif ARCHAIC
- type = icp->icmp_type; code = icp->icmp_code;
+#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, (u_char)seq))
+ return -2;
if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) ||
type == ICMP_UNREACH) {
- struct ip *hip;
- struct udphdr *up;
+ u_char *inner;
hip = &icp->icmp_ip;
+ hiplen = ((u_char *)icp + cc) - (u_char *)hip;
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);
+ inner = (u_char *)((u_char *)hip + hlen);
+ if (hlen + 12 <= cc
+ && hip->ip_p == proto->num
+ && (*proto->check)(inner, (u_char)seq))
+ return (type == ICMP_TIMXCEED ? -1 : code + 1);
}
#ifndef ARCHAIC
if (verbose) {
- int i;
- u_long *lp = (u_long *)&icp->icmp_ip;
-
- Printf("\n%d bytes from %s to %s", cc,
- inet_ntoa(from->sin_addr), inet_ntoa(ip->ip_dst));
- Printf(": icmp type %d (%s) code %d\n", type, pr_type(type),
- icp->icmp_code);
- for (i = 4; i < cc ; i += sizeof(long))
- Printf("%2d: x%8.8lx\n", i, *lp++);
+ register int i;
+ u_int32_t *lp = (u_int32_t *)&icp->icmp_ip;
+
+ Printf("\n%d bytes from %s to ", cc, inet_ntoa(from->sin_addr));
+ Printf("%s: icmp type %d (%s) code %d\n",
+ inet_ntoa(ip->ip_dst), type, pr_type(type), icp->icmp_code);
+ for (i = 4; i < cc ; i += sizeof(*lp))
+ Printf("%2d: x%8.8x\n", i, *lp++);
}
-#endif ARCHAIC
+#endif
return(0);
}
+void
+icmp_prep(struct outdata *outdata)
+{
+ struct icmp *const icmpheader = (struct icmp *) outp;
+
+ icmpheader->icmp_type = ICMP_ECHO;
+ icmpheader->icmp_id = htons(ident);
+ icmpheader->icmp_seq = htons(outdata->seq);
+ icmpheader->icmp_cksum = 0;
+ icmpheader->icmp_cksum = in_cksum((u_short *)icmpheader, protlen);
+ if (icmpheader->icmp_cksum == 0)
+ icmpheader->icmp_cksum = 0xffff;
+}
+
+int
+icmp_check(const u_char *data, int seq)
+{
+ struct icmp *const icmpheader = (struct icmp *) data;
+
+ return (icmpheader->icmp_id == htons(ident)
+ && icmpheader->icmp_seq == htons(seq));
+}
+
+void
+udp_prep(struct outdata *outdata)
+{
+ struct udphdr *const outudp = (struct udphdr *) outp;
+
+ outudp->uh_sport = htons(ident + (fixedPort ? outdata->seq : 0));
+ outudp->uh_dport = htons(port + (fixedPort ? 0 : outdata->seq));
+ outudp->uh_ulen = htons((u_short)protlen);
+ outudp->uh_sum = 0;
+ if (doipcksum) {
+ u_short sum = p_cksum(outip, (u_short*)outudp, protlen);
+ outudp->uh_sum = (sum) ? sum : 0xffff;
+ }
+
+ return;
+}
+
+int
+udp_check(const u_char *data, int seq)
+{
+ struct udphdr *const udp = (struct udphdr *) data;
+
+ return (ntohs(udp->uh_sport) == ident + (fixedPort ? seq : 0) &&
+ ntohs(udp->uh_dport) == port + (fixedPort ? 0 : seq));
+}
+
+void
+tcp_prep(struct outdata *outdata)
+{
+ struct tcphdr *const tcp = (struct tcphdr *) outp;
+
+ tcp->th_sport = htons(ident);
+ tcp->th_dport = htons(port + (fixedPort ? 0 : outdata->seq));
+ tcp->th_seq = (tcp->th_sport << 16) | (tcp->th_dport +
+ (fixedPort ? outdata->seq : 0));
+ tcp->th_ack = 0;
+ tcp->th_off = 5;
+ tcp->th_flags = TH_SYN;
+ tcp->th_sum = 0;
+
+ if (doipcksum) {
+ u_short sum = p_cksum(outip, (u_short*)tcp, protlen);
+ tcp->th_sum = (sum) ? sum : 0xffff;
+ }
+}
+
+int
+tcp_check(const u_char *data, int seq)
+{
+ struct tcphdr *const tcp = (struct tcphdr *) data;
+
+ return (ntohs(tcp->th_sport) == ident
+ && ntohs(tcp->th_dport) == port + (fixedPort ? 0 : seq))
+ && tcp->th_seq == ((ident << 16) | (port + seq));
+}
void
-print(buf, cc, from)
- u_char *buf;
- int cc;
- struct sockaddr_in *from;
+gre_prep(struct outdata *outdata)
{
- struct ip *ip;
- int hlen;
+ struct grehdr *const gre = (struct grehdr *) outp;
+
+ gre->flags = htons(0x2001);
+ gre->proto = htons(port);
+ gre->length = 0;
+ gre->callId = htons(ident + outdata->seq);
+}
+
+int
+gre_check(const u_char *data, int seq)
+{
+ struct grehdr *const gre = (struct grehdr *) data;
+
+ return(ntohs(gre->proto) == port
+ && ntohs(gre->callId) == ident + seq);
+}
+
+void
+gen_prep(struct outdata *outdata)
+{
+ u_int16_t *const ptr = (u_int16_t *) outp;
+
+ ptr[0] = htons(ident);
+ ptr[1] = htons(port + outdata->seq);
+}
+
+int
+gen_check(const u_char *data, int seq)
+{
+ u_int16_t *const ptr = (u_int16_t *) data;
+
+ return(ntohs(ptr[0]) == ident
+ && ntohs(ptr[1]) == port + seq);
+}
+
+void
+print(register u_char *buf, register int cc, register struct sockaddr_in *from)
+{
+ register struct ip *ip;
+ register int hlen;
ip = (struct ip *) buf;
hlen = ip->ip_hl << 2;
cc -= hlen;
+ if (as_path)
+ Printf(" [AS%d]", as_lookup(asn, &from->sin_addr));
+
if (nflag)
Printf(" %s", inet_ntoa(from->sin_addr));
else
Printf(" %s (%s)", inetname(from->sin_addr),
- inet_ntoa(from->sin_addr));
+ inet_ntoa(from->sin_addr));
if (verbose)
- Printf (" %d bytes to %s", cc, inet_ntoa (ip->ip_dst));
+ Printf(" %d bytes to %s", cc, inet_ntoa (ip->ip_dst));
}
+/*
+ * Checksum routine for UDP and TCP headers.
+ */
+u_short
+p_cksum(struct ip *ip, u_short *data, int len)
+{
+ static struct ipovly ipo;
+ u_short sumh, sumd;
+ u_int32_t sumt;
+
+ ipo.ih_pr = ip->ip_p;
+ ipo.ih_len = htons(len);
+ ipo.ih_src = ip->ip_src;
+ ipo.ih_dst = ip->ip_dst;
+
+ sumh = in_cksum((u_short*)&ipo, sizeof(ipo)); /* pseudo ip hdr cksum */
+ sumd = in_cksum((u_short*)data, len); /* payload data cksum */
+ sumt = (sumh << 16) | (sumd);
+
+ return ~in_cksum((u_short*)&sumt, sizeof(sumt));
+}
-#ifdef notyet
/*
* Checksum routine for Internet Protocol family headers (C Version)
*/
u_short
-in_cksum(addr, len)
- u_short *addr;
- int len;
+in_cksum(register u_short *addr, register int len)
{
register int nleft = len;
register u_short *w = addr;
answer = ~sum; /* truncate to 16 bits */
return (answer);
}
-#endif notyet
/*
* Subtract 2 timeval structs: out = out - in.
- * Out is assumed to be >= in.
+ * Out is assumed to be within about LONG_MAX seconds of in.
*/
void
-tvsub(out, in)
- register struct timeval *out, *in;
+tvsub(register struct timeval *out, register struct timeval *in)
{
+
if ((out->tv_usec -= in->tv_usec) < 0) {
- out->tv_sec--;
+ --out->tv_sec;
out->tv_usec += 1000000;
}
out->tv_sec -= in->tv_sec;
}
-
/*
* Construct an Internet address representation.
* If the nflag has been supplied, give
* numeric value, otherwise try for symbolic name.
*/
char *
-inetname(in)
- struct in_addr in;
+inetname(struct in_addr in)
{
register char *cp;
- static char line[50];
- struct hostent *hp;
- static char domain[MAXHOSTNAMELEN + 1];
+ register struct hostent *hp;
static int first = 1;
+ static char domain[MAXHOSTNAMELEN + 1], line[MAXHOSTNAMELEN + 1];
if (first && !nflag) {
first = 0;
- if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
- (cp = index(domain, '.')))
- (void) strcpy(domain, cp + 1);
- else
- domain[0] = 0;
+ 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;
+ memmove(domain, cp, strlen(cp) + 1);
+ }
+ }
}
- cp = 0;
if (!nflag && in.s_addr != INADDR_ANY) {
- hp = gethostbyaddr((char *)&in, sizeof (in), AF_INET);
- if (hp) {
- if ((cp = index(hp->h_name, '.')) &&
- !strcmp(cp + 1, domain))
- *cp = 0;
- cp = hp->h_name;
+ hp = gethostbyaddr((char *)&in, sizeof(in), AF_INET);
+ if (hp != NULL) {
+ if ((cp = strchr(hp->h_name, '.')) != NULL &&
+ strcmp(cp + 1, domain) == 0)
+ *cp = '\0';
+ (void)strlcpy(line, hp->h_name, sizeof(line));
+ return (line);
}
}
- if (cp)
- (void) strcpy(line, cp);
- else {
- in.s_addr = ntohl(in.s_addr);
-#define C(x) ((x) & 0xff)
- Sprintf(line, "%lu.%lu.%lu.%lu", C(in.s_addr >> 24),
- C(in.s_addr >> 16), C(in.s_addr >> 8), C(in.s_addr));
+ return (inet_ntoa(in));
+}
+
+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;
+
+ 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) {
+ Fprintf(stderr, "%s: unknown host %s\n", prog, hostname);
+ exit(1);
+ }
+ if (hp->h_addrtype != AF_INET || hp->h_length != 4) {
+ Fprintf(stderr, "%s: bad host %s\n", prog, hostname);
+ exit(1);
}
- return (line);
+ 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);
+}
+
+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
-usage()
+setsin(register struct sockaddr_in *sin, register u_int32_t addr)
{
- (void)fprintf(stderr,
-"usage: traceroute [-dnrv] [-m max_ttl] [-p port#] [-q nqueries]\n\t\
-[-s src_addr] [-t tos] [-w wait] host [data size]\n");
+
+ memset(sin, 0, sizeof(*sin));
+#ifdef HAVE_SOCKADDR_SA_LEN
+ sin->sin_len = sizeof(*sin);
+#endif
+ sin->sin_family = AF_INET;
+ sin->sin_addr.s_addr = addr;
+}
+
+/* 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 const char *cp;
+ register int val;
+ char *ep;
+
+ 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 (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_int32_t 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
+pkt_compare(const u_char *a, int la, const u_char *b, int lb) {
+ int l;
+ int i;
+
+ for (i = 0; i < la; i++)
+ Printf("%02x", (unsigned int)a[i]);
+ Printf("\n");
+ l = (la <= lb) ? la : lb;
+ for (i = 0; i < l; i++)
+ if (a[i] == b[i])
+ Printf("__");
+ else
+ Printf("%02x", (unsigned int)b[i]);
+ for (; i < lb; i++)
+ Printf("%02x", (unsigned int)b[i]);
+ Printf("\n");
+}
+
+
+void
+usage(void)
+{
+ extern char version[];
+
+ Fprintf(stderr, "Version %s\n", version);
+ Fprintf(stderr,
+ "Usage: %s [-adDeFInrSvx] [-A as_server] [-f first_ttl] [-g gateway] [-i iface]\n"
+ "\t[-M first_ttl] [-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);
}