]> git.saurik.com Git - apple/network_cmds.git/blobdiff - traceroute.tproj/traceroute.c
network_cmds-606.100.3.tar.gz
[apple/network_cmds.git] / traceroute.tproj / traceroute.c
index 7471b8f9a8b290f8f1d77675f0492ca24253312d..a411d0a4a9edf90ff9ade89cd9977440ed897a50 100644 (file)
@@ -1,3 +1,31 @@
+/*
+ * 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
 
 /*
@@ -263,6 +287,7 @@ static const char rcsid[] =
 
 #include "findsaddr.h"
 #include "ifaddrlist.h"
+#include "as.h"
 #include "traceroute.h"
 
 /* Maximum number of gateways (include room for one noop) */
@@ -316,6 +341,9 @@ u_char      packet[512];            /* last inbound (icmp) packet */
 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];
 
@@ -337,7 +365,7 @@ char *hostname;
 char *device;
 static const char devnull[] = "/dev/null";
 
-int nprobes = 3;
+int nprobes = -1;
 int max_ttl;
 int first_ttl = 1;
 u_short ident;
@@ -347,13 +375,17 @@ int options;                      /* socket options */
 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;
@@ -380,6 +412,7 @@ 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
@@ -398,6 +431,7 @@ 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" */
@@ -412,6 +446,7 @@ struct outproto {
 struct outproto protos[] = {
        {
                "udp",
+               "spt dpt len sum",
                IPPROTO_UDP,
                sizeof(struct udphdr),
                32768 + 666,
@@ -420,6 +455,7 @@ struct      outproto protos[] = {
        },
        {
                "tcp",
+               "spt dpt seq     ack     xxflwin sum urp",
                IPPROTO_TCP,
                sizeof(struct tcphdr),
                32768 + 666,
@@ -428,6 +464,7 @@ struct      outproto protos[] = {
        },
        {
                "gre",
+               "flg pro len clid",
                IPPROTO_GRE,
                sizeof(struct grehdr),
                GRE_PPTP_PROTO,
@@ -436,6 +473,7 @@ struct      outproto protos[] = {
        },
        {
                "icmp",
+               "typ cod sum ",
                IPPROTO_ICMP,
                sizeof(struct icmp),
                0,
@@ -443,6 +481,7 @@ struct      outproto protos[] = {
                icmp_check
        },
        {
+               NULL,
                NULL,
                0,
                2 * sizeof(u_short),
@@ -453,6 +492,8 @@ struct      outproto protos[] = {
 };
 struct outproto *proto = &protos[0];
 
+const char *ip_hdr_key = "vhtslen id  off tlprsum srcip   dstip   opts";
+
 int
 main(int argc, char **argv)
 {
@@ -476,6 +517,13 @@ 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 ||
@@ -514,21 +562,30 @@ main(int argc, char **argv)
        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);
@@ -561,10 +618,6 @@ main(int argc, char **argv)
                        max_ttl = str2val(optarg, "max ttl", 1, 255);
                        break;
 
-               case 'N':
-                       ++disable_seq;
-                       break;
-
                case 'n':
                        ++nflag;
                        break;
@@ -613,7 +666,7 @@ main(int argc, char **argv)
 
                case 'w':
                        waittime = str2val(optarg, "wait time",
-                           2, 24 * 60 * 60);
+                           1, 24 * 60 * 60);
                        break;
 
                case 'z':
@@ -628,6 +681,9 @@ main(int argc, char **argv)
        /* 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",
@@ -732,6 +788,8 @@ main(int argc, char **argv)
                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));
@@ -817,7 +875,7 @@ main(int argc, char **argv)
                    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);
@@ -893,6 +951,16 @@ main(int argc, char **argv)
                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());
@@ -927,11 +995,7 @@ main(int argc, char **argv)
                        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: */
@@ -955,6 +1019,7 @@ main(int argc, char **argv)
                                        continue;
                                if (!gotlastaddr ||
                                    from->sin_addr.s_addr != lastaddr) {
+                                       if (gotlastaddr) printf("\n   ");
                                        print(packet, cc, from);
                                        lastaddr = from->sin_addr.s_addr;
                                        ++gotlastaddr;
@@ -971,6 +1036,16 @@ main(int argc, char **argv)
 #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;
@@ -1020,6 +1095,41 @@ main(int argc, char **argv)
                                        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");
@@ -1056,6 +1166,8 @@ main(int argc, char **argv)
                    (unreachable > 0 && unreachable >= nprobes - 1))
                        break;
        }
+       if (as_path)
+               as_shutdown(asn);
        exit(0);
 }
 
@@ -1072,9 +1184,9 @@ wait_for_reply(register int sock, register struct sockaddr_in *fromp,
        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;
@@ -1243,10 +1355,10 @@ packet_ok(register u_char *buf, int cc, register struct sockaddr_in *from,
                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
@@ -1297,8 +1409,8 @@ udp_prep(struct outdata *outdata)
 {
        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) {
@@ -1314,8 +1426,8 @@ udp_check(const u_char *data, int seq)
 {
        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
@@ -1324,8 +1436,9 @@ tcp_prep(struct outdata *outdata)
        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;
@@ -1343,7 +1456,8 @@ 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 + seq);
+           && ntohs(tcp->th_dport) == port + (fixedPort ? 0 : seq))
+           && tcp->th_seq == ((ident << 16) | (port + seq));
 }
 
 void
@@ -1394,6 +1508,9 @@ print(register u_char *buf, register int cc, register struct sockaddr_in *from)
        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
@@ -1412,7 +1529,7 @@ p_cksum(struct ip *ip, u_short *data, int len)
 {
        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);
@@ -1504,8 +1621,7 @@ inetname(struct in_addr in)
                                domain[0] = '\0';
                        else {
                                ++cp;
-                               (void)strncpy(domain, cp, sizeof(domain) - 1);
-                               domain[sizeof(domain) - 1] = '\0';
+                               memmove(domain, cp, strlen(cp) + 1);
                        }
                }
        }
@@ -1515,8 +1631,7 @@ inetname(struct in_addr in)
                        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);
                }
        }
@@ -1661,7 +1776,7 @@ setproto(char *pname)
        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)
@@ -1673,6 +1788,26 @@ setproto(char *pname)
        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)
 {
@@ -1680,8 +1815,8 @@ 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);
 }