+/*
+ * 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.
+ *
+ * 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, 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) 1988, 1989, 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000
* The Regents of the University of California. All rights reserved.
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
+#include <sys/cdefs.h>
+
#ifndef lint
-static const char copyright[] =
+__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";
-#if 0
-static const char rcsid[] =
- "@(#)$Id: traceroute.c,v 1.4 2006/02/07 06:22:57 lindak Exp $ (LBL)";
-#endif
-static const char rcsid[] =
- "$FreeBSD: src/contrib/traceroute/traceroute.c,v 1.26 2004/04/17 18:44:23 pb Exp $";
#endif
/*
#include "findsaddr.h"
#include "ifaddrlist.h"
+#include "as.h"
#include "traceroute.h"
/* Maximum number of gateways (include room for one noop) */
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];
char *device;
static const char devnull[] = "/dev/null";
-int nprobes = 3;
+int nprobes = -1;
int max_ttl;
int first_ttl = 1;
u_short ident;
int verbose;
int waittime = 5; /* time to wait for response (in seconds) */
int nflag; /* print addresses numerically */
-int disable_seq = 0;
+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;
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
/* 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" */
struct outproto protos[] = {
{
"udp",
+ "spt dpt len sum",
IPPROTO_UDP,
sizeof(struct udphdr),
32768 + 666,
},
{
"tcp",
+ "spt dpt seq ack xxflwin sum urp",
IPPROTO_TCP,
sizeof(struct tcphdr),
32768 + 666,
},
{
"gre",
+ "flg pro len clid",
IPPROTO_GRE,
sizeof(struct grehdr),
GRE_PPTP_PROTO,
},
{
"icmp",
+ "typ cod sum ",
IPPROTO_ICMP,
sizeof(struct icmp),
0,
icmp_check
},
{
+ NULL,
NULL,
0,
2 * sizeof(u_short),
};
struct outproto *proto = &protos[0];
+const char *ip_hdr_key = "vhtslen id off tlprsum srcip dstip opts";
+
int
main(int argc, char **argv)
{
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 ||
max_ttl = 30;
#endif
- 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, "dFInrSvxf:g:i:M:m:P:p:q:s:t:w:z:")) != EOF)
+ 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 'D':
+ printdiff = 1;
+ break;
+
+ case 'e':
+ fixedPort = 1;
+ break;
+
case 'f':
case 'M': /* FreeBSD compat. */
first_ttl = str2val(optarg, "first ttl", 1, 255);
max_ttl = str2val(optarg, "max ttl", 1, 255);
break;
- case 'N':
- ++disable_seq;
- break;
-
case 'n':
++nflag;
break;
case 'w':
waittime = str2val(optarg, "wait time",
- 2, 24 * 60 * 60);
+ 1, 24 * 60 * 60);
break;
case 'z':
/* Set requested port, if any, else default for this protocol */
port = (requestPort != -1) ? requestPort : proto->port;
+ if (nprobes == -1)
+ nprobes = printdiff ? 1 : 3;
+
if (first_ttl > max_ttl) {
Fprintf(stderr,
"%s: first ttl (%d) may not be greater than max ttl (%d)\n",
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));
sizeof(on));
/* Get the interface address list */
- n = ifaddrlist(&al, errbuf);
+ n = ifaddrlist(&al, errbuf, sizeof(errbuf));
if (n < 0) {
Fprintf(stderr, "%s: ifaddrlist: %s\n", prog, errbuf);
exit(1);
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;
+ }
+ }
+
#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
if (setpolicy(sndsock, "in bypass") < 0)
errx(1, "%s", ipsec_strerror());
if (sentfirst && pausemsecs > 0)
usleep(pausemsecs * 1000);
/* Prepare outgoing data */
- if (disable_seq) {
- outdata.seq = seq;
- } else {
- outdata.seq = ++seq;
- }
+ outdata.seq = ++seq;
outdata.ttl = ttl;
/* Avoid alignment problems by copying bytewise: */
continue;
if (!gotlastaddr ||
from->sin_addr.s_addr != lastaddr) {
+ if (gotlastaddr) printf("\n ");
print(packet, cc, from);
lastaddr = from->sin_addr.s_addr;
++gotlastaddr;
#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;
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");
(unreachable > 0 && unreachable >= nprobes - 1))
break;
}
+ if (as_path)
+ as_shutdown(asn);
exit(0);
}
socklen_t fromlen = sizeof(*fromp);
nfds = howmany(sock + 1, NFDBITS);
- if ((fdsp = malloc(nfds * sizeof(fd_mask))) == NULL)
+ if ((fdsp = malloc(nfds * sizeof(fd_set))) == NULL)
err(1, "malloc");
- memset(fdsp, 0, nfds * sizeof(fd_mask));
+ memset(fdsp, 0, nfds * sizeof(fd_set));
FD_SET(sock, fdsp);
wait.tv_sec = tp->tv_sec + waittime;
return -2;
if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) ||
type == ICMP_UNREACH) {
- struct ip *hip;
u_char *inner;
hip = &icp->icmp_ip;
+ hiplen = ((u_char *)icp + cc) - (u_char *)hip;
hlen = hip->ip_hl << 2;
inner = (u_char *)((u_char *)hip + hlen);
if (hlen + 12 <= cc
{
struct udphdr *const outudp = (struct udphdr *) outp;
- outudp->uh_sport = htons(ident);
- outudp->uh_dport = htons(port + outdata->seq);
+ 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) {
{
struct udphdr *const udp = (struct udphdr *) data;
- return (ntohs(udp->uh_sport) == ident
- && ntohs(udp->uh_dport) == port + seq);
+ return (ntohs(udp->uh_sport) == ident + (fixedPort ? seq : 0) &&
+ ntohs(udp->uh_dport) == port + (fixedPort ? 0 : seq));
}
void
struct tcphdr *const tcp = (struct tcphdr *) outp;
tcp->th_sport = htons(ident);
- tcp->th_dport = htons(port + outdata->seq);
- tcp->th_seq = (tcp->th_sport << 16) | tcp->th_dport;
+ 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;
struct tcphdr *const tcp = (struct tcphdr *) data;
return (ntohs(tcp->th_sport) == ident
- && ntohs(tcp->th_dport) == port + seq);
+ && ntohs(tcp->th_dport) == port + (fixedPort ? 0 : seq))
+ && tcp->th_seq == ((ident << 16) | (port + seq));
}
void
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
{
static struct ipovly ipo;
u_short sumh, sumd;
- u_long sumt;
+ u_int32_t sumt;
ipo.ih_pr = ip->ip_p;
ipo.ih_len = htons(len);
domain[0] = '\0';
else {
++cp;
- (void)strncpy(domain, cp, sizeof(domain) - 1);
- domain[sizeof(domain) - 1] = '\0';
+ memmove(domain, cp, strlen(cp) + 1);
}
}
}
if ((cp = strchr(hp->h_name, '.')) != NULL &&
strcmp(cp + 1, domain) == 0)
*cp = '\0';
- (void)strncpy(line, hp->h_name, sizeof(line) - 1);
- line[sizeof(line) - 1] = '\0';
+ (void)strlcpy(line, hp->h_name, sizeof(line));
return (line);
}
}
proto = &protos[i];
if (proto->name == NULL) { /* generic handler */
struct protoent *pe;
- u_long pnum;
+ u_int32_t pnum;
/* Determine the IP protocol number */
if ((pe = getprotobyname(pname)) != NULL)
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)
{
Fprintf(stderr, "Version %s\n", version);
Fprintf(stderr,
- "Usage: %s [-dFINnrSvx] [-g gateway] [-i iface] [-f first_ttl]\n"
- "\t[-m max_ttl] [-p port] [-P proto] [-q nqueries] [-s src_addr]\n"
+ "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);
}