]> git.saurik.com Git - apple/network_cmds.git/blobdiff - ping.tproj/ping.c
network_cmds-457.tar.gz
[apple/network_cmds.git] / ping.tproj / ping.c
index b0a8f0d877b9dddc6cdc53c933f207876dcec67b..7701b7bd3195061f832cba8627d4d9c9619af47c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008 Apple Inc. All rights reserved.
+ * Copyright (c) 1999-2013 Apple Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  *
  * SUCH DAMAGE.
  */
 
-#if 0
+#include <sys/cdefs.h>
+
 #ifndef lint
-static const char copyright[] =
+__unused static const char copyright[] =
 "@(#) Copyright (c) 1989, 1993\n\
        The Regents of the University of California.  All rights reserved.\n";
 #endif /* not lint */
 
-#ifndef lint
-static char sccsid[] = "@(#)ping.c     8.1 (Berkeley) 6/5/93";
-#endif /* not lint */
-#endif
-#include <sys/cdefs.h>
-#ifndef __APPLE__
-__FBSDID("$FreeBSD: src/sbin/ping/ping.c,v 1.112 2007/07/01 12:08:06 gnn Exp $");
-#endif
-       
 /*
  *                     P I N G . C
  *
@@ -120,6 +112,7 @@ __FBSDID("$FreeBSD: src/sbin/ping/ping.c,v 1.112 2007/07/01 12:08:06 gnn Exp $")
 #include <string.h>
 #include <sysexits.h>
 #include <unistd.h>
+#include <ifaddrs.h>
 
 #define        INADDR_LEN      ((int)sizeof(in_addr_t))
 #define        TIMEVAL_LEN     ((int)sizeof(struct tv32))
@@ -205,8 +198,10 @@ unsigned int ifscope;
 #if defined(IP_FORCE_OUT_IFP) && TARGET_OS_EMBEDDED
 char boundifname[IFNAMSIZ];
 #endif /* IP_FORCE_OUT_IFP */
+int nocell;
 int how_traffic_class = 0;
-int traffic_class = -1;
+int traffic_class = SO_TC_CTL; /* use control class, by default */
+int no_dup = 0;
 
 /* counters */
 long nmissedmax;               /* max value of ntransmitted - nreceived - 1 */
@@ -243,17 +238,16 @@ static char *pr_addr(struct in_addr);
 static char *pr_ntime(n_time);
 static void pr_icmph(struct icmp *);
 static void pr_iph(struct ip *);
-static void pr_pack(char *, int, struct sockaddr_in *, struct timeval *);
+static void pr_pack(char *, int, struct sockaddr_in *, struct timeval *, int);
 static void pr_retip(struct ip *);
 static void status(int);
 static void stopit(int);
-static void tvsub(struct timeval *, struct timeval *);
+static void tvsub(struct timeval *, const struct timeval *);
+static uint32_t str2svc(const char *);
 static void usage(void) __dead2;
 
 int
-main(argc, argv)
-       int argc;
-       char *const *argv;
+main(int argc, char *const *argv)
 {
        struct sockaddr_in from, sock_in;
        struct in_addr ifaddr;
@@ -263,7 +257,7 @@ main(argc, argv)
        struct msghdr msg;
        struct sigaction si_sa;
        size_t sz;
-       u_char *datap, packet[IP_MAXPACKET];
+       u_char *datap, packet[IP_MAXPACKET] __attribute__((aligned(4)));
        char *ep, *source, *target, *payload;
        struct hostent *hp;
 #ifdef IPSEC_POLICY_IPSEC
@@ -274,7 +268,7 @@ main(argc, argv)
        u_long alarmtimeout, ultmp;
        int almost_done, ch, df, hold, i, icmp_len, mib[4], preload, sockerrno,
            tos, ttl;
-       char ctrl[CMSG_SPACE(sizeof(struct timeval))];
+       char ctrl[CMSG_SPACE(sizeof(struct timeval)) + CMSG_SPACE(sizeof(int))];
        char hnamebuf[MAXHOSTNAMELEN], snamebuf[MAXHOSTNAMELEN];
 #ifdef IP_OPTIONS
        char rspace[MAX_IPOPTLEN];      /* record route space */
@@ -297,14 +291,15 @@ main(argc, argv)
                s = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
        sockerrno = errno;
 
-       setuid(getuid());
+       if (setuid(getuid()) != 0)
+               err(EX_NOPERM, "setuid() failed");
        uid = getuid();
 
        alarmtimeout = df = preload = tos = 0;
 
        outpack = outpackhdr + sizeof(struct ip);
        while ((ch = getopt(argc, argv,
-               "Aab:c:DdfG:g:h:I:i:k:Ll:M:m:nop:QqRrS:s:T:t:vW:z:"
+               "Aab:Cc:DdfG:g:h:I:i:k:Ll:M:m:nop:QqRrS:s:T:t:vW:z:"
 #ifdef IPSEC
 #ifdef IPSEC_POLICY_IPSEC
                "P:"
@@ -331,6 +326,9 @@ main(argc, argv)
                case 'b':
                        boundif = optarg;
                        break;
+               case 'C':
+                       nocell++;
+                       break;
                case 'c':
                        ultmp = strtoul(optarg, &ep, 0);
                        if (*ep || ep == optarg || ultmp > LONG_MAX || !ultmp)
@@ -416,14 +414,17 @@ main(argc, argv)
                                    optarg);
                        options |= F_INTERVAL;
                        interval = (int)t;
-                       if (uid && interval < 1000) {
+                       if (uid && interval < 100) {
                                errno = EPERM;
                                err(EX_NOPERM, "-i interval too short");
                        }
                        break;
                case 'k':
                        how_traffic_class++;
-                       traffic_class = atoi(optarg);
+                       traffic_class = str2svc(optarg);
+                       if (traffic_class == UINT32_MAX)
+                               errx(EX_USAGE, "bad traffic class: `%s'",
+                                    optarg);
                        break;
                case 'L':
                        options |= F_NOLOOP;
@@ -641,6 +642,30 @@ main(argc, argv)
                hostname = hnamebuf;
        }
 
+       do {
+               struct ifaddrs *ifa_list, *ifa;
+               
+               if (IN_MULTICAST(ntohl(whereto.sin_addr.s_addr)) || whereto.sin_addr.s_addr == INADDR_BROADCAST) {
+                       no_dup = 1;
+                       break;
+               }
+               
+               if (getifaddrs(&ifa_list) == -1)
+                       break;
+               for (ifa = ifa_list; ifa; ifa = ifa->ifa_next) {
+                       if (ifa->ifa_addr->sa_family != AF_INET)
+                               continue;
+                       if ((ifa->ifa_flags & IFF_BROADCAST) == 0 || ifa->ifa_broadaddr == NULL)
+                               continue;
+                       if (whereto.sin_addr.s_addr != ((struct sockaddr_in*)ifa->ifa_broadaddr)->sin_addr.s_addr)
+                               continue;
+                       no_dup = 1;
+                       break;
+               }
+               
+               freeifaddrs(ifa_list);
+       } while (0);
+       
        if (options & F_FLOOD && options & F_INTERVAL)
                errx(EX_USAGE, "-f and -i: incompatible options");
 
@@ -666,6 +691,8 @@ main(argc, argv)
                err(EX_OSERR, "socket");
        }
        hold = 1;
+       (void) setsockopt(s, SOL_SOCKET, SO_RECV_ANYIF, (char *)&hold,
+           sizeof(hold));
        if (ifscope != 0) {
                if (setsockopt(s, IPPROTO_IP, IP_BOUND_IF,
                    (char *)&ifscope, sizeof (ifscope)) != 0)
@@ -678,15 +705,25 @@ main(argc, argv)
                        err(EX_OSERR, "setsockopt(IP_FORCE_OUT_IFP)");
        }
 #endif /* IP_FORCE_OUT_IFP */
+       if (nocell) {
+               if (setsockopt(s, IPPROTO_IP, IP_NO_IFT_CELLULAR,
+                   (char *)&nocell, sizeof (nocell)) != 0)
+                       err(EX_OSERR, "setsockopt(IP_NO_IFT_CELLULAR)");
+       }
        if (options & F_SO_DEBUG)
                (void)setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&hold,
                    sizeof(hold));
        if (options & F_SO_DONTROUTE)
                (void)setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (char *)&hold,
                    sizeof(hold));
-       if (how_traffic_class == 1) {
-               (void)setsockopt(s, SOL_SOCKET, SO_TRAFFIC_CLASS, (void *)&traffic_class,
-                                                sizeof(traffic_class));
+       if (how_traffic_class < 2 && traffic_class >= 0) {
+               (void) setsockopt(s, SOL_SOCKET, SO_TRAFFIC_CLASS,
+                   (void *)&traffic_class, sizeof (traffic_class));
+       }
+       if (how_traffic_class > 0) {
+               int on = 1;
+               (void) setsockopt(s, SOL_SOCKET, SO_RECV_TRAFFIC_CLASS,
+                   (void *)&on, sizeof (on));
        }
 #ifdef IPSEC
 #ifdef IPSEC_POLICY_IPSEC
@@ -854,17 +891,21 @@ main(argc, argv)
        if (sigaction(SIGINT, &si_sa, 0) == -1) {
                err(EX_OSERR, "sigaction SIGINT");
        }
-
+       si_sa.sa_handler = stopit;
+       if (sigaction(SIGQUIT, &si_sa, 0) == -1) {
+               err(EX_OSERR, "sigaction SIGQUIT");
+       }
+    
        si_sa.sa_handler = status;
        if (sigaction(SIGINFO, &si_sa, 0) == -1) {
-               err(EX_OSERR, "sigaction");
+               err(EX_OSERR, "sigaction SIGINFO");
        }
 
-        if (alarmtimeout > 0) {
+       if (alarmtimeout > 0) {
                si_sa.sa_handler = stopit;
                if (sigaction(SIGALRM, &si_sa, 0) == -1)
                        err(EX_OSERR, "sigaction SIGALRM");
-        }
+       }
 
        bzero(&msg, sizeof(msg));
        msg.msg_name = (caddr_t)&from;
@@ -899,6 +940,7 @@ main(argc, argv)
                struct timeval now, timeout;
                fd_set rfds;
                int cc, n;
+               int tc = -1;
 
                check_status();
                if ((unsigned)s >= FD_SETSIZE)
@@ -935,20 +977,28 @@ main(argc, argv)
                                warn("recvmsg");
                                continue;
                        }
+                       for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
 #ifdef SO_TIMESTAMP
-                       if (cmsg->cmsg_level == SOL_SOCKET &&
-                           cmsg->cmsg_type == SCM_TIMESTAMP &&
-                           cmsg->cmsg_len == CMSG_LEN(sizeof *tv)) {
-                               /* Copy to avoid alignment problems: */
-                               memcpy(&now, CMSG_DATA(cmsg), sizeof(now));
-                               tv = &now;
-                       }
+                               if (cmsg->cmsg_level == SOL_SOCKET &&
+                                       cmsg->cmsg_type == SCM_TIMESTAMP &&
+                                       cmsg->cmsg_len == CMSG_LEN(sizeof *tv)) {
+                                       /* Copy to avoid alignment problems: */
+                                       memcpy(&now, CMSG_DATA(cmsg), sizeof(now));
+                                       tv = &now;
+                               }
 #endif
+                               if (cmsg->cmsg_level == SOL_SOCKET &&
+                                       cmsg->cmsg_type == SO_TRAFFIC_CLASS &&
+                                       cmsg->cmsg_len == CMSG_LEN(sizeof(int))) {
+                                       /* Copy to avoid alignment problems: */
+                                       memcpy(&tc, CMSG_DATA(cmsg), sizeof(tc));
+                               }
+                       }
                        if (tv == NULL) {
                                (void)gettimeofday(&now, NULL);
                                tv = &now;
                        }
-                       pr_pack((char *)packet, cc, &from, tv);
+                       pr_pack((char *)packet, cc, &from, tv, tc);
                        if ((options & F_ONCE && nreceived) ||
                            (npackets && nreceived >= npackets))
                                break;
@@ -1001,8 +1051,7 @@ main(argc, argv)
  * to be called from a signal handler.
  */
 void
-stopit(sig)
-       int sig __unused;
+stopit(int sig __unused)
 {
 
        /*
@@ -1068,7 +1117,7 @@ pinger(void)
                ip->ip_sum = in_cksum((u_short *)outpackhdr, cc);
                packet = outpackhdr;
        }
-       if (how_traffic_class == 2) {
+       if (how_traffic_class > 1 && traffic_class >= 0) {
                struct msghdr msg;
                struct iovec iov;
                char *cmbuf[CMSG_SPACE(sizeof(int))];
@@ -1122,11 +1171,8 @@ pinger(void)
  * program to be run without having intermingled output (or statistics!).
  */
 static void
-pr_pack(buf, cc, from, tv)
-       char *buf;
-       int cc;
-       struct sockaddr_in *from;
-       struct timeval *tv;
+pr_pack(char *buf, int cc, struct sockaddr_in *from, struct timeval *tv,
+    int tc)
 {
        struct in_addr ina;
        u_char *cp, *dp;
@@ -1213,9 +1259,11 @@ pr_pack(buf, cc, from, tv)
                        (void)printf(" ttl=%d", ip->ip_ttl);
                        if (timing)
                                (void)printf(" time=%.3f ms", triptime);
-                       if (dupflag) {
-                               if (!IN_MULTICAST(ntohl(whereto.sin_addr.s_addr)))
-                                       (void)printf(" (DUP!)");
+                       if (tc != -1) {
+                               (void)printf(" tc=%d", tc);
+                       }
+                       if (dupflag && no_dup == 0) {
+                               (void)printf(" (DUP!)");
                        }
                        if (options & F_AUDIBLE)
                                (void)write(STDOUT_FILENO, &BBELL, 1);
@@ -1392,9 +1440,7 @@ pr_pack(buf, cc, from, tv)
  *     Checksum routine for Internet Protocol family headers (C Version)
  */
 u_short
-in_cksum(addr, len)
-       u_short *addr;
-       int len;
+in_cksum(u_short *addr, int len)
 {
        int nleft, sum;
        u_short *w;
@@ -1438,8 +1484,7 @@ in_cksum(addr, len)
  * be >= in.
  */
 static void
-tvsub(out, in)
-       struct timeval *out, *in;
+tvsub(struct timeval *out, const struct timeval *in)
 {
 
        if ((out->tv_usec -= in->tv_usec) < 0) {
@@ -1455,15 +1500,14 @@ tvsub(out, in)
  */
 
 static void
-status(sig)
-       int sig __unused;
+status(int sig __unused)
 {
 
        siginfo_p = 1;
 }
 
 static void
-check_status()
+check_status(void)
 {
 
        if (siginfo_p) {
@@ -1483,7 +1527,7 @@ check_status()
  *     Print out statistics, and give up.
  */
 static void
-finish()
+finish(void)
 {
 
        (void)signal(SIGINT, SIG_IGN);
@@ -1542,8 +1586,7 @@ static char *ttab[] = {
  *     Print a descriptive string about an ICMP header.
  */
 static void
-pr_icmph(icp)
-       struct icmp *icp;
+pr_icmph(struct icmp *icp)
 {
 
        switch(icp->icmp_type) {
@@ -1690,8 +1733,7 @@ pr_icmph(icp)
  *     Print an IP header with options.
  */
 static void
-pr_iph(ip)
-       struct ip *ip;
+pr_iph(struct ip *ip)
 {
        u_char *cp;
        int hlen;
@@ -1723,8 +1765,7 @@ pr_iph(ip)
  * a hostname.
  */
 static char *
-pr_addr(ina)
-       struct in_addr ina;
+pr_addr(struct in_addr ina)
 {
        struct hostent *hp;
        static char buf[16 + 3 + MAXHOSTNAMELEN];
@@ -1743,8 +1784,7 @@ pr_addr(ina)
  *     Dump some info on a returned (via ICMP) IP packet.
  */
 static void
-pr_retip(ip)
-       struct ip *ip;
+pr_retip(struct ip *ip)
 {
        u_char *cp;
        int hlen;
@@ -1762,7 +1802,7 @@ pr_retip(ip)
 }
 
 static char *
-pr_ntime (n_time timestamp)
+pr_ntime(n_time timestamp)
 {
        static char buf[10];
        int hour, min, sec;
@@ -1778,8 +1818,7 @@ pr_ntime (n_time timestamp)
 }
 
 static void
-fill(bp, patp)
-       char *bp, *patp;
+fill(char *bp, char *patp)
 {
        char *cp;
        int pat[16];
@@ -1809,22 +1848,59 @@ fill(bp, patp)
        }
 }
 
+uint32_t
+str2svc(const char *str)
+{
+       uint32_t svc;
+       char *endptr;
+       
+       if (str == NULL || *str == '\0')
+               svc = UINT32_MAX;
+       else if (strcasecmp(str, "BK_SYS") == 0)
+               return SO_TC_BK_SYS;
+       else if (strcasecmp(str, "BK") == 0)
+               return SO_TC_BK;
+       else if (strcasecmp(str, "BE") == 0)
+               return SO_TC_BE;
+       else if (strcasecmp(str, "RD") == 0)
+               return SO_TC_RD;
+       else if (strcasecmp(str, "OAM") == 0)
+               return SO_TC_OAM;
+       else if (strcasecmp(str, "AV") == 0)
+               return SO_TC_AV;
+       else if (strcasecmp(str, "RV") == 0)
+               return SO_TC_RV;
+       else if (strcasecmp(str, "VI") == 0)
+               return SO_TC_VI;
+       else if (strcasecmp(str, "VO") == 0)
+               return SO_TC_VO;
+       else if (strcasecmp(str, "CTL") == 0)
+               return SO_TC_CTL;
+       else {
+               svc = strtoul(str, &endptr, 0);
+               if (*endptr != '\0')
+                       svc = UINT32_MAX;
+       }
+       return (svc);
+}
+
 #if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
 #define        SECOPT          " [-P policy]"
 #else
 #define        SECOPT          ""
 #endif
 static void
-usage()
+usage(void)
 {
 
-       (void)fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
-"usage: ping [-AaDdfnoQqRrv] [-b boundif] [-c count] [-G sweepmaxsize] [-g sweepminsize]",
-"            [-h sweepincrsize] [-i wait] [-l preload] [-M mask | time] [-m ttl]",
-"           " SECOPT " [-p pattern] [-S src_addr] [-s packetsize] [-t timeout]",
-"            [-W waittime] [-z tos] host",
-"       ping [-AaDdfLnoQqRrv] [-c count] [-I iface] [-i wait] [-l preload]",
-"            [-M mask | time] [-m ttl]" SECOPT " [-p pattern] [-S src_addr]",
+       (void)fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
+"usage: ping [-AaDdfnoQqRrv] [-b boundif] [-c count] [-G sweepmaxsize]",
+"            [-g sweepminsize] [-h sweepincrsize] [-i wait] [−k trafficclass]",
+"            [-l preload] [-M mask | time] [-m ttl]" SECOPT " [-p pattern]",
+"            [-S src_addr] [-s packetsize] [-t timeout][-W waittime] [-z tos]",
+"            host",
+"       ping [-AaDdfLnoQqRrv] [-b boundif] [-c count] [-I iface] [-i wait]",
+"            [−k trafficclass] [-l preload] [-M mask | time] [-m ttl]" SECOPT " [-p pattern] [-S src_addr]",
 "            [-s packetsize] [-T ttl] [-t timeout] [-W waittime]",
 "            [-z tos] mcast-group");
        exit(EX_USAGE);