/*
- * 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
*
#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))
#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 */
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;
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
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 */
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:"
case 'b':
boundif = optarg;
break;
+ case 'C':
+ nocell++;
+ break;
case 'c':
ultmp = strtoul(optarg, &ep, 0);
if (*ep || ep == optarg || ultmp > LONG_MAX || !ultmp)
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;
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");
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)
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
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;
struct timeval now, timeout;
fd_set rfds;
int cc, n;
+ int tc = -1;
check_status();
if ((unsigned)s >= FD_SETSIZE)
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;
* to be called from a signal handler.
*/
void
-stopit(sig)
- int sig __unused;
+stopit(int sig __unused)
{
/*
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))];
* 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;
(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);
* 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;
* 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) {
*/
static void
-status(sig)
- int sig __unused;
+status(int sig __unused)
{
siginfo_p = 1;
}
static void
-check_status()
+check_status(void)
{
if (siginfo_p) {
* Print out statistics, and give up.
*/
static void
-finish()
+finish(void)
{
(void)signal(SIGINT, SIG_IGN);
* 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) {
* Print an IP header with options.
*/
static void
-pr_iph(ip)
- struct ip *ip;
+pr_iph(struct ip *ip)
{
u_char *cp;
int hlen;
* 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];
* 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;
}
static char *
-pr_ntime (n_time timestamp)
+pr_ntime(n_time timestamp)
{
static char buf[10];
int hour, min, sec;
}
static void
-fill(bp, patp)
- char *bp, *patp;
+fill(char *bp, char *patp)
{
char *cp;
int pat[16];
}
}
+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);