-/* $KAME: ping6.c,v 1.169 2003/07/25 06:01:47 itojun Exp $ */
+/*
+ * Copyright (c) 2002-2016 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) 1995, 1996, 1997, and 1998 WIDE Project.
* SUCH DAMAGE.
*/
-/* BSDI ping.c,v 2.3 1996/01/21 17:56:50 jch Exp */
-
/*
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
* SUCH DAMAGE.
*/
+#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
-#if 0
-static char sccsid[] = "@(#)ping.c 8.1 (Berkeley) 6/5/93";
-#endif
-static const char rcsid[] =
- "$FreeBSD$";
-#endif /* not lint */
-
/*
* Using the InterNet Control Message Protocol (ICMP) "ECHO" facility,
* measure round-trip-delays and packet loss across network paths.
#include <fcntl.h>
#include <math.h>
#include <signal.h>
+#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef HAVE_POLL_H
#include <poll.h>
#endif
+#include <sysexits.h>
+#include <getopt.h>
#ifdef IPSEC
#include <netinet6/ah.h>
#include <netinet6/ipsec.h>
#endif
-#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
-#include <md5.h>
-#else
#include "md5.h"
-#endif
struct tv32 {
u_int32_t tv32_sec;
#define F_QUIET 0x0010
#define F_RROUTE 0x0020
#define F_SO_DEBUG 0x0040
+#define F_PRTIME 0x0080
#define F_VERBOSE 0x0100
#ifdef IPSEC
#ifdef IPSEC_POLICY_IPSEC
#define F_ONCE 0x200000
#define F_AUDIBLE 0x400000
#define F_MISSED 0x800000
+#define F_DONTFRAG 0x1000000
+#define F_SWEEP 0x2000000
+#define F_CONNECT 0x4000000
#define F_NOUSERDATA (F_NODEADDR | F_FQDN | F_FQDNOLD | F_SUPTYPES)
u_int options;
+static int longopt_flag = 0;
+
+#define LOF_CONNECT 0x01
+#define LOF_PRTIME 0x02
+
+static const struct option longopts[] = {
+ { "apple-connect", no_argument, &longopt_flag, LOF_CONNECT },
+ { "apple-time", no_argument, &longopt_flag, LOF_PRTIME },
+ { NULL, 0, NULL, 0 }
+};
+
+
#define IN6LEN sizeof(struct in6_addr)
#define SA6LEN sizeof(struct sockaddr_in6)
#define DUMMY_PORT 10101
u_int8_t nonce[8]; /* nonce field for node information */
int hoplimit = -1; /* hoplimit */
int pathmtu = 0; /* path MTU for the destination. 0 = unspec. */
+u_char *packet = NULL;
+struct cmsghdr *cm = NULL;
char *boundif;
unsigned int ifscope;
int nocell;
+#ifdef HAVE_POLL_H
+struct pollfd fdmaskp[1];
+#else
+fd_set *fdmaskp = NULL;
+int fdmasks;
+#endif
/* counters */
long nmissedmax; /* max value of ntransmitted - nreceived - 1 */
long nrepeats; /* number of duplicates */
long ntransmitted; /* sequence # for outbound packets = #sent */
struct timeval interval = {1, 0}; /* interval between packets */
+long snpackets = 0; /* max packets to transmit in one sweep */
+long sntransmitted = 0; /* # of packets we sent in this sweep */
+int sweepmax = 0; /* max value of payload in sweep */
+int sweepmin = 0; /* start value of payload in sweep */
+int sweepincr = 1; /* payload increment in sweep */
/* timing */
int timing; /* flag to do timing */
/* for ancillary data(advanced API) */
struct msghdr smsghdr;
-struct iovec smsgiov;
-char *scmsg = 0;
+struct iovec smsgiov[2];
+char *scmsg = NULL;
volatile sig_atomic_t seenalrm;
volatile sig_atomic_t seenint;
int rcvtclass = 0;
-int how_so_traffic_class = 0;
-int so_traffic_class = -1;
+int use_sendmsg = 0;
+int use_recvmsg = 0;
+int so_traffic_class = SO_TC_CTL; /* use control class, by default */
+int net_service_type = -1;
+
+int32_t thiszone; /* seconds offset from gmt to local time */
+extern int32_t gmt2local(time_t);
+static void pr_currenttime(void);
int main(int, char *[]);
void fill(char *, char *);
void tvsub(struct timeval *, struct timeval *);
int setpolicy(int, char *);
char *nigroup(char *);
+static int str2sotc(const char *, bool *);
+static int str2netservicetype(const char *, bool *);
+static u_int8_t str2tclass(const char *, bool *);
void usage(void);
int
-main(argc, argv)
- int argc;
- char *argv[];
+main(int argc, char *argv[])
{
struct itimerval itimer;
struct sockaddr_in6 from;
struct timeval timeout, *tv;
#endif
struct addrinfo hints;
-#ifdef HAVE_POLL_H
- struct pollfd fdmaskp[1];
-#else
- fd_set *fdmaskp;
- int fdmasks;
-#endif
int cc, i;
int ch, hold, packlen, preload, optval, ret_ga;
- u_char *datap, *packet;
+ u_char *datap;
char *e, *target, *ifname = NULL, *gateway = NULL;
int ip6optlen = 0;
struct cmsghdr *scmsgp = NULL;
- struct cmsghdr *cm;
#if defined(SO_SNDBUF) && defined(SO_RCVBUF)
u_long lsockbufsize;
int sockbufsize = 0;
#ifdef IPV6_USE_MIN_MTU
int mflag = 0;
#endif
- int tclass = -2; /* T_CLASS value -1 means default, so -2 means do not bother */
+ /* T_CLASS value -1 means default, so -2 means do not bother */
+ int tclass = -2;
+ bool valid;
+ struct timeval intvl;
/* just to be sure */
memset(&smsghdr, 0, sizeof(smsghdr));
#define ADDOPTS "AE"
#endif /*IPSEC_POLICY_IPSEC*/
#endif
- while ((ch = getopt(argc, argv,
- "a:b:B:Cc:dfHg:h:I:i:k:l:mnNop:qrRS:s:tvwWz:" ADDOPTS)) != -1) {
+ while ((ch = getopt_long(argc, argv,
+ "a:b:B:Cc:DdfHG:g:h:I:i:k:K:l:mnNop:qrRS:s:tvwWz:" ADDOPTS,
+ longopts, NULL)) != -1) {
#undef ADDOPTS
switch (ch) {
case 'a':
naflags |= NI_NODEADDR_FLAG_ANYCAST;
break;
#else
- errx(1,
-"-a A is not supported on the platform");
+ errx(1, "-a A is not supported on "
+ "the platform");
/*NOTREACHED*/
#endif
default:
sockbufsize != lsockbufsize)
errx(1, "invalid socket buffer size");
#else
- errx(1,
-"-b option ignored: SO_SNDBUF/SO_RCVBUF socket options not supported");
+ errx(1, "-b option ignored: SO_SNDBUF/SO_RCVBUF "
+ "socket options not supported");
#endif
break;
case 'B':
errx(1,
"illegal number of packets -- %s", optarg);
break;
+ case 'D':
+ options |= F_DONTFRAG;
+ break;
case 'd':
options |= F_SO_DEBUG;
break;
case 'g':
gateway = optarg;
break;
+ case 'G': {
+ char *ptr ;
+ char *tofree;
+ unsigned long ultmp;
+
+ tofree = strdup(optarg);
+ if (tofree == NULL)
+ errx(1, "### strdup() failed");
+ ptr = tofree;
+ do {
+ char *str;
+ char *ep;
+
+ if ((str = strsep(&ptr, ",")) == NULL)
+ errx(1, "-G requires maximum packet size");
+ ultmp = strtoul(str, &ep, 0);
+ if (*ep || ep == optarg)
+ errx(EX_USAGE, "option -G invalid maximum packet size: `%s'",
+ str);
+ options |= F_SWEEP;
+ sweepmax = ultmp;
+ if (sweepmax < 1 || sweepmax > MAXDATALEN) {
+ errx(1,
+ "-G invalid maximum packet size, needs to be between 1 and %d",
+ MAXDATALEN);
+ }
+
+ if ((str = strsep(&ptr, ",")) == NULL)
+ break;
+ if (*str != 0) {
+ ultmp = strtoul(str, &ep, 0);
+ if (*ep || ep == optarg)
+ errx(EX_USAGE, "option -G invalid minimum packet size: `%s'",
+ str);
+ sweepmin = ultmp;
+ if (sweepmin < 0 || sweepmin > MAXDATALEN) {
+ errx(1,
+ "-G invalid minimum packet size, needs to be between 0 and %d",
+ MAXDATALEN);
+ }
+ }
+
+ if ((str = strsep(&ptr, ",")) == NULL)
+ break;
+ if (*str == 0)
+ break;
+ ultmp = strtoul(str, &ep, 0);
+ if (*ep || ep == optarg)
+ errx(EX_USAGE, "option -G invalid sweep increment size: `%s'",
+ str);
+ sweepincr = ultmp;
+ if (sweepincr < 1 || sweepincr > MAXDATALEN) {
+ errx(1,
+ "-G invalid sweep increment size, needs to be between 1 and %d",
+ MAXDATALEN);
+ }
+ } while (0);
+ free(tofree);
+ break;
+ }
case 'H':
options |= F_HOSTNAME;
break;
intval = strtod(optarg, &e);
if (*optarg == '\0' || *e != '\0')
errx(1, "illegal timing interval %s", optarg);
- if (intval < 1 && getuid()) {
- errx(1, "%s: only root may use interval < 1s",
+ if (intval < 0.1 && getuid()) {
+ errx(1, "%s: only root may use interval < 0.1s",
strerror(EPERM));
}
interval.tv_sec = (long)intval;
options |= F_INTERVAL;
break;
case 'k':
- how_so_traffic_class++;
- so_traffic_class = atoi(optarg);
+ if (strcasecmp(optarg, "sendmsg") == 0) {
+ use_sendmsg++;
+ break;
+ }
+ if (strcasecmp(optarg, "recvmsg") == 0) {
+ use_recvmsg++;
+ break;
+ }
+ so_traffic_class = str2sotc(optarg, &valid);
+ if (valid == false)
+ errx(EX_USAGE, "bad traffic class: `%s'",
+ optarg);
+ break;
+ case 'K':
+ if (strcasecmp(optarg, "sendmsg") == 0) {
+ use_sendmsg++;
+ break;
+ }
+ net_service_type = str2netservicetype(optarg, &valid);
+ if (valid == false)
+ errx(EX_USAGE, "bad network service type: `%s'",
+ optarg);
+ /* suppress default traffic class (-k can still be specified after -K) */
+ so_traffic_class = -1;
break;
-
case 'l':
if (getuid()) {
errno = EPERM;
case 'p': /* fill buffer with user pattern */
options |= F_PINGFILLED;
fill((char *)datap, optarg);
- break;
+ break;
case 'q':
options |= F_QUIET;
break;
memcpy(&src, res->ai_addr, res->ai_addrlen);
srclen = res->ai_addrlen;
freeaddrinfo(res);
+ res = NULL;
options |= F_SRCADDR;
break;
case 's': /* size of packet to send */
options |= F_FQDNOLD;
break;
case 'z':
- tclass = (int)strtol(optarg, &e, 10);
- if (tclass < -1 || *optarg == '\0' || *e != '\0')
+ tclass = str2tclass(optarg, &valid);
+ if (valid == false)
errx(1, "illegal TOS value -- %s", optarg);
- if (tclass > MAXTOS)
- errx(1,
- "TOS value too large, maximum is %d",
- MAXTOS);
rcvtclass = 1;
break;
#ifdef IPSEC
break;
#endif /*IPSEC_POLICY_IPSEC*/
#endif /*IPSEC*/
+ case 0:
+ switch (longopt_flag) {
+ case LOF_CONNECT:
+ options |= F_CONNECT;
+ break;
+ case LOF_PRTIME:
+ options |= F_PRTIME;
+ thiszone = gmt2local(0);
+ break;
+ default:
+ break;
+ }
+ longopt_flag = 0;
+ break;
default:
usage();
/*NOTREACHED*/
if (boundif != NULL && (ifscope = if_nametoindex(boundif)) == 0)
errx(1, "bad interface name");
+ if ((options & F_SWEEP) && !sweepmax)
+ errx(EX_USAGE, "Maximum sweep size must be specified");
+
+ if ((options & F_SWEEP) && (options & F_NOUSERDATA))
+ errx(EX_USAGE, "Option -G incompatible with -t, -w and -W");
+
argc -= optind;
argv += optind;
}
/* revoke root privilege */
- seteuid(getuid());
- setuid(getuid());
+ if (seteuid(getuid()) != 0)
+ err(1, "seteuid() failed");
+ if (setuid(getuid()) != 0)
+ err(1, "setuid() failed");
if ((options & F_FLOOD) && (options & F_INTERVAL))
errx(1, "-f and -i incompatible options");
- if ((options & F_NOUSERDATA) == 0) {
- if (datalen >= sizeof(struct tv32)) {
- /* we can time transfer */
- timing = 1;
+ if ((options & F_CONNECT)) {
+ if (connect(s, (struct sockaddr *)&dst, sizeof(dst)) == -1)
+ err(EX_OSERR, "connect");
+ }
+
+ if (sweepmax) {
+ if (sweepmin >= sweepmax)
+ errx(EX_USAGE, "Maximum packet size must be greater than the minimum packet size");
+
+ if (datalen != DEFDATALEN)
+ errx(EX_USAGE, "Packet size and ping sweep are mutually exclusive");
+
+ if (npackets > 0) {
+ snpackets = npackets;
+ npackets = 0;
} else
- timing = 0;
+ snpackets = 1;
+ datalen = sweepmin;
+ }
+
+ if ((options & F_NOUSERDATA) == 0) {
/* in F_VERBOSE case, we may get non-echoreply packets*/
if (options & F_VERBOSE)
- packlen = 2048 + IP6LEN + ICMP6ECHOLEN + EXTRA;
+ packlen = MAX(2048, sweepmax) + IP6LEN + ICMP6ECHOLEN + EXTRA;
else
- packlen = datalen + IP6LEN + ICMP6ECHOLEN + EXTRA;
+ packlen = MAX(datalen, sweepmax) + IP6LEN + ICMP6ECHOLEN + EXTRA;
} else {
/* suppress timing for node information query */
timing = 0;
packlen = 2048 + IP6LEN + ICMP6ECHOLEN + EXTRA;
}
- if (!(packet = (u_char *)malloc((u_int)packlen)))
+ if (!(packet = (u_char *)malloc((u_int)MAX(datalen, sweepmax))))
err(1, "Unable to allocate packet");
if (!(options & F_PINGFILLED))
- for (i = ICMP6ECHOLEN; i < packlen; ++i)
+ for (i = ICMP6ECHOLEN; i < MAX(datalen, sweepmax); ++i)
*datap++ = i;
ident = getpid() & 0xFFFF;
for (i = 0; i < sizeof(nonce); i += sizeof(u_int32_t))
*((u_int32_t *)&nonce[i]) = arc4random();
#endif
-
+ optval = 1;
+ if (options & F_DONTFRAG)
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_DONTFRAG,
+ &optval, sizeof(optval)) == -1)
+ err(1, "IPV6_DONTFRAG");
hold = 1;
-
if (options & F_SO_DEBUG)
(void)setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&hold,
sizeof(hold));
+
+ hold = 1;
+ (void) setsockopt(s, SOL_SOCKET, SO_RECV_ANYIF, (char *)&hold,
+ sizeof(hold));
+
optval = IPV6_DEFHLIM;
if (IN6_IS_ADDR_MULTICAST(&dst.sin6_addr))
if (setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
if (tclass != -2) {
int on = 1;
-
- if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVTCLASS, &on, sizeof(on)))
+
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVTCLASS, &on,
+ sizeof(on)))
err(1, "setsockopt(IPV6_RECVTCLASS)");
-
- if (setsockopt(s, IPPROTO_IPV6, IPV6_TCLASS, &tclass, sizeof(tclass)))
+
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_TCLASS, &tclass,
+ sizeof(tclass)))
err(1, "setsockopt(IPV6_TCLASS)");
}
- /*
+/*
optval = 1;
if (IN6_IS_ADDR_MULTICAST(&dst.sin6_addr))
if (setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
if (hoplimit != -1)
ip6optlen += CMSG_SPACE(sizeof(int));
+#ifdef IPV6_USE_MIN_MTU
+ if (mflag != 1)
+ ip6optlen += CMSG_SPACE(sizeof(int));
+#endif /* IPV6_USE_MIN_MTU */
+
if (tclass != -2)
ip6optlen += CMSG_SPACE(sizeof(int));
- if (how_so_traffic_class == 1 && so_traffic_class > 0) {
- (void)setsockopt(s, SOL_SOCKET, SO_TRAFFIC_CLASS, (void *)&so_traffic_class,
- sizeof(so_traffic_class));
- }
- if (how_so_traffic_class > 0) {
+ if (use_sendmsg == 0) {
+ if (net_service_type != -1)
+ if (setsockopt(s, SOL_SOCKET, SO_NET_SERVICE_TYPE,
+ (void *)&net_service_type, sizeof (net_service_type)) != 0)
+ warn("setsockopt(SO_NET_SERVICE_TYPE");
+ if (so_traffic_class != -1) {
+ if (setsockopt(s, SOL_SOCKET, SO_TRAFFIC_CLASS,
+ (void *)&so_traffic_class, sizeof (so_traffic_class)) != 0)
+ warn("setsockopt(SO_TRAFFIC_CLASS");
+
+ }
+ } else {
+ if (net_service_type != -1)
+ ip6optlen += CMSG_SPACE(sizeof(int));
+ if (so_traffic_class != -1)
+ ip6optlen += CMSG_SPACE(sizeof(int));
+ }
+ if (use_recvmsg > 0) {
int on = 1;
- (void)setsockopt(s, SOL_SOCKET, SO_RECV_TRAFFIC_CLASS, (void *)&on,
- sizeof(on));
+ if (setsockopt(s, SOL_SOCKET, SO_RECV_TRAFFIC_CLASS,
+ (void *)&on, sizeof (on)) != 0)
+ warn("setsockopt(SO_RECV_TRAFFIC_CLASS");
}
- if (how_so_traffic_class > 1)
- ip6optlen += CMSG_SPACE(sizeof(int));
-
+
/* set IP6 packet options */
if (ip6optlen) {
if ((scmsg = (char *)malloc(ip6optlen)) == 0)
scmsgp = CMSG_NXTHDR(&smsghdr, scmsgp);
}
+#ifdef IPV6_USE_MIN_MTU
+ if (mflag != 1) {
+ optval = mflag > 1 ? 0 : 1;
+
+ scmsgp->cmsg_len = CMSG_LEN(sizeof(int));
+ scmsgp->cmsg_level = IPPROTO_IPV6;
+ scmsgp->cmsg_type = IPV6_USE_MIN_MTU;
+ *(int *)(CMSG_DATA(scmsgp)) = optval;
+
+ scmsgp = CMSG_NXTHDR(&smsghdr, scmsgp);
+ }
+#endif /* IPV6_USE_MIN_MTU */
+
if (argc > 1) { /* some intermediate addrs are specified */
int hops, error;
#ifdef USE_RFC2292BIS
scmsgp = CMSG_NXTHDR(&smsghdr, scmsgp);
}
- if (how_so_traffic_class > 1) {
- scmsgp->cmsg_len = CMSG_LEN(sizeof(int));
- scmsgp->cmsg_level = SOL_SOCKET;
- scmsgp->cmsg_type = SO_TRAFFIC_CLASS;
- *(int *)(CMSG_DATA(scmsgp)) = so_traffic_class;
-
- scmsgp = CMSG_NXTHDR(&smsghdr, scmsgp);
+ if (use_sendmsg != 0) {
+ if (so_traffic_class != -1) {
+ scmsgp->cmsg_len = CMSG_LEN(sizeof(int));
+ scmsgp->cmsg_level = SOL_SOCKET;
+ scmsgp->cmsg_type = SO_TRAFFIC_CLASS;
+ *(int *)(CMSG_DATA(scmsgp)) = so_traffic_class;
+
+ scmsgp = CMSG_NXTHDR(&smsghdr, scmsgp);
+ }
+ if (net_service_type != -1) {
+ scmsgp->cmsg_len = CMSG_LEN(sizeof(int));
+ scmsgp->cmsg_level = SOL_SOCKET;
+ scmsgp->cmsg_type = SO_NET_SERVICE_TYPE;
+ *(int *)(CMSG_DATA(scmsgp)) = net_service_type;
+ }
}
if (!(options & F_SRCADDR)) {
/*
#if defined(SO_SNDBUF) && defined(SO_RCVBUF)
if (sockbufsize) {
- if (datalen > sockbufsize)
+ if (MAX(datalen, sweepmax) > sockbufsize)
warnx("you need -b to increase socket buffer size");
if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &sockbufsize,
sizeof(sockbufsize)) < 0)
err(1, "setsockopt(SO_RCVBUF)");
}
else {
- if (datalen > 8 * 1024) /*XXX*/
+ if (MAX(datalen, sweepmax) > 8 * 1024) /*XXX*/
warnx("you need -b to increase socket buffer size");
/*
* When pinging the broadcast address, you can get a lot of
#else /* old adv. API */
if (setsockopt(s, IPPROTO_IPV6, IPV6_HOPLIMIT, &optval,
sizeof(optval)) < 0)
- warn("setsockopt(IPV6_HOPLIMIT, %d, %lu)", optval, sizeof(optval)); /* XXX err? */
+ warn("setsockopt(IPV6_HOPLIMIT, %d, %lu)",
+ optval, sizeof(optval)); /* XXX err? */
#endif
- printf("PING6(%lu=40+8+%lu bytes) ", (unsigned long)(40 + pingerlen()),
- (unsigned long)(pingerlen() - 8));
+ if (sweepmax)
+ printf("PING6(40+8+[%lu...%lu] bytes) ",
+ (unsigned long)(sweepmin),
+ (unsigned long)(sweepmax));
+ else
+ printf("PING6(%lu=40+8+%lu bytes) ", (unsigned long)(40 + pingerlen()),
+ (unsigned long)(pingerlen() - 8));
printf("%s --> ", pr_addr((struct sockaddr *)&src, sizeof(src)));
printf("%s\n", pr_addr((struct sockaddr *)&dst, sizeof(dst)));
while (preload--) /* Fire off them quickies. */
(void)pinger();
+ /*
+ * rdar://25829310
+ *
+ * Clear blocked signals inherited from the parent
+ */
+ sigset_t newset;
+ sigemptyset(&newset);
+ if (sigprocmask(SIG_SETMASK, &newset, NULL) != 0)
+ err(EX_OSERR, "sigprocmask(newset)");
+
+ seenalrm = seenint = 0;
+#ifdef SIGINFO
+ seeninfo = 0;
+#endif
+
(void)signal(SIGINT, onsignal);
#ifdef SIGINFO
(void)signal(SIGINFO, onsignal);
#endif
if ((options & F_FLOOD) == 0) {
- (void)signal(SIGALRM, onsignal);
+ if (signal(SIGALRM, onsignal) == SIG_ERR)
+ warn("signal(SIGALRM)");
itimer.it_interval = interval;
itimer.it_value = interval;
(void)setitimer(ITIMER_REAL, &itimer, NULL);
retransmit();
}
+ if (options & F_FLOOD) {
+ intvl.tv_sec = 0;
+ intvl.tv_usec = 10000;
+ } else {
+ intvl.tv_sec = interval.tv_sec;
+ intvl.tv_usec = interval.tv_usec;
+ }
+
#ifndef HAVE_POLL_H
fdmasks = howmany(s + 1, NFDBITS) * sizeof(fd_mask);
if ((fdmaskp = malloc(fdmasks)) == NULL)
err(1, "malloc");
#endif
- seenalrm = seenint = 0;
-#ifdef SIGINFO
- seeninfo = 0;
-#endif
-
/* For control (ancillary) data received from recvmsg() */
cm = (struct cmsghdr *)malloc(CONTROLLEN);
if (cm == NULL)
/* signal handling */
if (seenalrm) {
+ seenalrm = 0;
/* last packet sent, timeout reached? */
if (npackets && ntransmitted >= npackets)
break;
+ /* sweep done ? */
+ if (sweepmax && datalen > sweepmax)
+ break;
retransmit();
- seenalrm = 0;
continue;
}
if (seenint) {
- onint(SIGINT);
seenint = 0;
+ onint(SIGINT);
continue;
}
#ifdef SIGINFO
if (seeninfo) {
- summary();
seeninfo = 0;
+ summary();
continue;
}
#endif
if (options & F_FLOOD) {
- (void)pinger();
+ if (pinger() != 0)
+ break;
#ifdef HAVE_POLL_H
timeout = 10;
#else
sleep(1);
}
continue;
- } else if (cc == 0)
+ } else if (cc == 0) {
continue;
-
+ }
m.msg_name = (caddr_t)&from;
m.msg_namelen = sizeof(from);
memset(&iov, 0, sizeof(iov));
/*
* receive control messages only. Process the
- * exceptions (currently the only possiblity is
+ * exceptions (currently the only possibility is
* a path MTU notification.)
*/
if ((mtu = get_pathmtu(&m)) > 0) {
}
}
summary();
+
+ if (res != NULL)
+ freeaddrinfo(res);
+
+ if (packet != NULL)
+ free(packet);
+
+ if (cm != NULL)
+ free(cm);
+
+ if (scmsg != NULL)
+ free(scmsg);
+
+#ifndef HAVE_POLL_H
+ if (fdmaskp != NULL)
+ free(fdmaskp);
+#endif
+
exit(nreceived == 0 ? 2 : 0);
}
void
-onsignal(sig)
- int sig;
+onsignal(int sig)
{
-
+ fflush(stdout);
+
switch (sig) {
case SIGALRM:
seenalrm++;
* This routine transmits another ping6.
*/
void
-retransmit()
+retransmit(void)
{
struct itimerval itimer;
- if (pinger() == 0)
+ if (pinger() == 0) {
return;
-
+ }
/*
* If we're not transmitting any more packets, change the timer
* to wait two round-trip times if we've received any packets or
* byte-order, to compute the round-trip time.
*/
size_t
-pingerlen()
+pingerlen(void)
{
size_t l;
}
int
-pinger()
+pinger(void)
{
struct icmp6_hdr *icp;
- struct iovec iov[2];
int i, cc;
struct icmp6_nodeinfo *nip;
int seq;
if (npackets && ntransmitted >= npackets)
return(-1); /* no more transmission */
+ if (sweepmax && sntransmitted == snpackets) {
+ datalen += sweepincr;
+ if (datalen > sweepmax)
+ return(-1); /* no more transmission */
+ sntransmitted = 0;
+ }
+
icp = (struct icmp6_hdr *)outpack;
nip = (struct icmp6_nodeinfo *)outpack;
memset(icp, 0, sizeof(*icp));
icp->icmp6_code = 0;
icp->icmp6_id = htons(ident);
icp->icmp6_seq = ntohs(seq);
+ if (datalen >= sizeof(struct tv32)) {
+ /* we can time transfer */
+ timing = 1;
+ } else
+ timing = 0;
if (timing) {
struct timeval tv;
struct tv32 *tv32;
errx(1, "internal error; length mismatch");
#endif
+ if ((options & F_CONNECT)) {
+ smsghdr.msg_name = NULL;
+ smsghdr.msg_namelen = 0;
+ } else {
smsghdr.msg_name = (caddr_t)&dst;
smsghdr.msg_namelen = sizeof(dst);
- memset(&iov, 0, sizeof(iov));
- iov[0].iov_base = (caddr_t)outpack;
- iov[0].iov_len = cc;
- smsghdr.msg_iov = iov;
+ }
+ memset(&smsgiov, 0, sizeof(smsgiov));
+ smsgiov[0].iov_base = (caddr_t)outpack;
+ smsgiov[0].iov_len = cc;
+ smsghdr.msg_iov = smsgiov;
smsghdr.msg_iovlen = 1;
i = sendmsg(s, &smsghdr, 0);
(void)printf("ping6: wrote %s %d chars, ret=%d\n",
hostname, cc, i);
}
+ sntransmitted++;
if (!(options & F_QUIET) && options & F_FLOOD)
(void)write(STDOUT_FILENO, &DOT, 1);
}
int
-myechoreply(icp)
- const struct icmp6_hdr *icp;
+myechoreply(const struct icmp6_hdr *icp)
{
if (ntohs(icp->icmp6_id) == ident)
return 1;
}
int
-mynireply(nip)
- const struct icmp6_nodeinfo *nip;
+mynireply(const struct icmp6_nodeinfo *nip)
{
if (memcmp(nip->icmp6_ni_nonce + sizeof(u_int16_t),
nonce + sizeof(u_int16_t),
}
char *
-dnsdecode(sp, ep, base, buf, bufsiz)
- const u_char **sp;
- const u_char *ep;
- const u_char *base; /*base for compressed name*/
- char *buf;
- size_t bufsiz;
+dnsdecode(const u_char **sp, const u_char *ep, const u_char *base, char *buf,
+ size_t bufsiz)
+ /*base for compressed name*/
{
- int i;
+ int i = 0;
const u_char *cp;
char cresult[NS_MAXDNAME + 1];
const u_char *comp;
* program to be run without having intermingled output (or statistics!).
*/
void
-pr_pack(buf, cc, mhdr)
- u_char *buf;
- int cc;
- struct msghdr *mhdr;
+pr_pack(u_char *buf, int cc, struct msghdr *mhdr)
{
#define safeputc(c) printf((isprint((c)) ? "%c" : "\\%03o"), c)
struct icmp6_hdr *icp;
char dnsname[NS_MAXDNAME + 1];
int tclass = 0;
int sotc = -1;
-
+
(void)gettimeofday(&tv, NULL);
if (!mhdr || !mhdr->msg_name ||
warnx("failed to get receiving traffic class");
return;
}
-
- if (how_so_traffic_class > 0)
+
+ if (use_recvmsg > 0)
sotc = get_so_traffic_class(mhdr);
-
+
if (icp->icmp6_type == ICMP6_ECHO_REPLY && myechoreply(icp)) {
seq = ntohs(icp->icmp6_seq);
++nreceived;
else {
if (options & F_AUDIBLE)
(void)write(STDOUT_FILENO, &BBELL, 1);
+ if (options & F_PRTIME)
+ pr_currenttime();
(void)printf("%d bytes from %s, icmp_seq=%u", cc,
pr_addr(from, fromlen), seq);
(void)printf(" hlim=%d", hoplim);
dp = outpack + ICMP6ECHOLEN + ICMP6ECHOTMLEN;
for (i = 8; cp < end; ++i, ++cp, ++dp) {
if (*cp != *dp) {
- (void)printf("\nwrong data byte #%d should be 0x%x but was 0x%x", i, *dp, *cp);
+ (void)printf("\nwrong data byte #%d "
+ "should be 0x%x but was 0x%x",
+ i, *dp, *cp);
break;
}
}
if (TST(seq % mx_dup_ck)) {
++nrepeats;
--nreceived;
- dupflag = 1;
} else {
SET(seq % mx_dup_ck);
- dupflag = 0;
}
if (options & F_QUIET)
return;
+ if (options & F_PRTIME)
+ pr_currenttime();
(void)printf("%d bytes from %s: ", cc, pr_addr(from, fromlen));
switch (ntohs(ni->ni_code)) {
putchar(')');
goto fqdnend;
}
- ttl = (int32_t)ntohl(*(u_int32_t *)&buf[off+ICMP6ECHOLEN+8]);
+ ttl = (int32_t)ntohl(*(u_int32_t *)
+ &buf[off+ICMP6ECHOLEN+8]);
if (comma)
printf(",");
if (!(ni->ni_flags & NI_FQDN_FLAG_VALIDTTL)) {
/* We've got something other than an ECHOREPLY */
if (!(options & F_VERBOSE))
return;
+ if (options & F_PRTIME)
+ pr_currenttime();
(void)printf("%d bytes from %s: ", cc, pr_addr(from, fromlen));
pr_icmph(icp, end);
}
}
void
-pr_exthdrs(mhdr)
- struct msghdr *mhdr;
+pr_exthdrs(struct msghdr *mhdr)
{
ssize_t bufsize;
void *bufp;
struct cmsghdr *cm;
- bufsize = 0;
bufp = mhdr->msg_control;
for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm;
cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) {
bufsize = CONTROLLEN - ((caddr_t)CMSG_DATA(cm) - (caddr_t)bufp);
if (bufsize <= 0)
- continue;
+ continue;
switch (cm->cmsg_type) {
case IPV6_HOPOPTS:
printf(" HbH Options: ");
struct ip6_hbh *ext;
int currentlen;
u_int8_t type;
- socklen_t extlen, len, origextlen;
+ socklen_t extlen, len;
void *databuf;
size_t offset;
u_int16_t value2;
* subtract the size of a cmsg structure from the buffer size.
*/
if (bufsize < (extlen + CMSG_SPACE(0))) {
- origextlen = extlen;
extlen = bufsize - CMSG_SPACE(0);
warnx("options truncated, showing only %u (total=%u)",
(unsigned int)(extlen / 8 - 1),
*/
case IP6OPT_JUMBO:
offset = 0;
- offset = inet6_opt_get_val(databuf, offset,
+ (void) inet6_opt_get_val(databuf, offset,
&value4, sizeof(value4));
printf(" Jumbo Payload Opt: Length %u\n",
(u_int32_t)ntohl(value4));
break;
case IP6OPT_ROUTER_ALERT:
offset = 0;
- offset = inet6_opt_get_val(databuf, offset,
+ (void)inet6_opt_get_val(databuf, offset,
&value2, sizeof(value2));
printf(" Router Alert Opt: Type %u\n",
ntohs(value2));
#endif /* USE_RFC2292BIS */
int
-pr_bitrange(v, soff, ii)
- u_int32_t v;
- int soff;
- int ii;
+pr_bitrange(u_int32_t v, int soff, int ii)
{
int off;
int i;
}
void
-pr_suptypes(ni, nilen)
- struct icmp6_nodeinfo *ni; /* ni->qtype must be SUPTYPES */
- size_t nilen;
+pr_suptypes(struct icmp6_nodeinfo *ni, size_t nilen)
+ /* ni->qtype must be SUPTYPES */
{
size_t clen;
u_int32_t v;
struct cbit {
u_int16_t words; /*32bit count*/
u_int16_t skip;
- } cbit;
+ } cbit = { 0, 0 };
#define MAXQTYPES (1 << 16)
size_t off;
int b;
}
void
-pr_nodeaddr(ni, nilen)
- struct icmp6_nodeinfo *ni; /* ni->qtype must be NODEADDR */
- int nilen;
+pr_nodeaddr(struct icmp6_nodeinfo *ni, int nilen)
+ /* ni->qtype must be NODEADDR */
{
u_char *cp = (u_char *)(ni + 1);
char ntop_buf[INET6_ADDRSTRLEN];
}
int
-get_hoplim(mhdr)
- struct msghdr *mhdr;
+get_hoplim(struct msghdr *mhdr)
{
struct cmsghdr *cm;
}
struct in6_pktinfo *
-get_rcvpktinfo(mhdr)
- struct msghdr *mhdr;
+get_rcvpktinfo(struct msghdr *mhdr)
{
struct cmsghdr *cm;
}
int
-get_pathmtu(mhdr)
- struct msghdr *mhdr;
+get_pathmtu(struct msghdr *mhdr)
{
#ifdef IPV6_RECVPATHMTU
struct cmsghdr *cm;
get_so_traffic_class(struct msghdr *mhdr)
{
struct cmsghdr *cm;
-
+
for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm;
cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) {
if (cm->cmsg_len == 0)
return(-1);
-
+
if (cm->cmsg_level == SOL_SOCKET &&
cm->cmsg_type == SO_TRAFFIC_CLASS &&
cm->cmsg_len == CMSG_LEN(sizeof(int)))
return(*(int *)CMSG_DATA(cm));
}
-
+
return(-1);
-}
-
+}
/*
* tvsub --
* be >= in.
*/
void
-tvsub(out, in)
- struct timeval *out, *in;
+tvsub(struct timeval *out, struct timeval *in)
{
if ((out->tv_usec -= in->tv_usec) < 0) {
--out->tv_sec;
*/
/* ARGSUSED */
void
-onint(notused)
- int notused;
+onint(int notused __unused)
{
summary();
+ if (res != NULL)
+ freeaddrinfo(res);
+
+ if (packet != NULL)
+ free(packet);
+
+ if (cm != NULL)
+ free(cm);
+
+ if (scmsg != NULL)
+ free(scmsg);
+
+#ifndef HAVE_POLL_H
+ if (fdmaskp != NULL)
+ free(fdmaskp);
+#endif
+
(void)signal(SIGINT, SIG_DFL);
(void)kill(getpid(), SIGINT);
* Print out statistics.
*/
void
-summary()
+summary(void)
{
-
(void)printf("\n--- %s ping6 statistics ---\n", hostname);
(void)printf("%ld packets transmitted, ", ntransmitted);
(void)printf("%ld packets received, ", nreceived);
* Print a descriptive string about an ICMP header.
*/
void
-pr_icmph(icp, end)
- struct icmp6_hdr *icp;
- u_char *end;
+pr_icmph(struct icmp6_hdr *icp, u_char *end)
{
char ntop_buf[INET6_ADDRSTRLEN];
struct nd_redirect *red;
* Print an IP6 header.
*/
void
-pr_iph(ip6)
- struct ip6_hdr *ip6;
+pr_iph(struct ip6_hdr *ip6)
{
u_int32_t flow = ip6->ip6_flow & IPV6_FLOWLABEL_MASK;
u_int8_t tc;
* a hostname.
*/
const char *
-pr_addr(addr, addrlen)
- struct sockaddr *addr;
- int addrlen;
+pr_addr(struct sockaddr *addr, int addrlen)
{
static char buf[NI_MAXHOST];
int flag = 0;
* Dump some info on a returned (via ICMPv6) IPv6 packet.
*/
void
-pr_retip(ip6, end)
- struct ip6_hdr *ip6;
- u_char *end;
+pr_retip(struct ip6_hdr *ip6, u_char *end)
{
u_char *cp = (u_char *)ip6, nh;
int hlen;
}
void
-fill(bp, patp)
- char *bp, *patp;
+fill(char *bp, char *patp)
{
int ii, jj, kk;
int pat[16];
#ifdef IPSEC
#ifdef IPSEC_POLICY_IPSEC
int
-setpolicy(so, policy)
- int so;
- char *policy;
+setpolicy(int so __unused, char *policy)
{
char *buf;
#endif
char *
-nigroup(name)
- char *name;
+nigroup(char *name)
{
char *p;
char *q;
return strdup(hbuf);
}
+int
+str2sotc(const char *str, bool *valid)
+{
+ int sotc = -1;
+ char *endptr;
+
+ *valid = true;
+
+ if (str == NULL || *str == '\0')
+ *valid = false;
+ 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 {
+ sotc = (int)strtol(str, &endptr, 0);
+ if (*endptr != '\0')
+ *valid = false;
+ }
+ return (sotc);
+}
+
+int
+str2netservicetype(const char *str, bool *valid)
+{
+ int svc = -1;
+ char *endptr;
+
+ *valid = true;
+
+ if (str == NULL || *str == '\0')
+ *valid = false;
+ else if (strcasecmp(str, "BK") == 0)
+ return NET_SERVICE_TYPE_BK;
+ else if (strcasecmp(str, "BE") == 0)
+ return NET_SERVICE_TYPE_BE;
+ else if (strcasecmp(str, "VI") == 0)
+ return NET_SERVICE_TYPE_VI;
+ else if (strcasecmp(str, "SIG") == 0)
+ return NET_SERVICE_TYPE_SIG;
+ else if (strcasecmp(str, "VO") == 0)
+ return NET_SERVICE_TYPE_VO;
+ else if (strcasecmp(str, "RV") == 0)
+ return NET_SERVICE_TYPE_RV;
+ else if (strcasecmp(str, "AV") == 0)
+ return NET_SERVICE_TYPE_AV;
+ else if (strcasecmp(str, "OAM") == 0)
+ return NET_SERVICE_TYPE_OAM;
+ else if (strcasecmp(str, "RD") == 0)
+ return NET_SERVICE_TYPE_RD;
+ else {
+ svc = (int)strtol(str, &endptr, 0);
+ if (*endptr != '\0')
+ *valid = false;
+ }
+ return (svc);
+}
+
+u_int8_t
+str2tclass(const char *str, bool *valid)
+{
+ u_int8_t dscp = -1;
+ char *endptr;
+
+ *valid = true;
+
+ if (str == NULL || *str == '\0')
+ *valid = false;
+ else if (strcasecmp(str, "DF") == 0)
+ dscp = _DSCP_DF;
+ else if (strcasecmp(str, "EF") == 0)
+ dscp = _DSCP_EF;
+ else if (strcasecmp(str, "VA") == 0)
+ dscp = _DSCP_VA;
+
+ else if (strcasecmp(str, "CS0") == 0)
+ dscp = _DSCP_CS0;
+ else if (strcasecmp(str, "CS1") == 0)
+ dscp = _DSCP_CS1;
+ else if (strcasecmp(str, "CS2") == 0)
+ dscp = _DSCP_CS2;
+ else if (strcasecmp(str, "CS3") == 0)
+ dscp = _DSCP_CS3;
+ else if (strcasecmp(str, "CS4") == 0)
+ dscp = _DSCP_CS4;
+ else if (strcasecmp(str, "CS5") == 0)
+ dscp = _DSCP_CS5;
+ else if (strcasecmp(str, "CS6") == 0)
+ dscp = _DSCP_CS6;
+ else if (strcasecmp(str, "CS7") == 0)
+ dscp = _DSCP_CS7;
+
+ else if (strcasecmp(str, "AF11") == 0)
+ dscp = _DSCP_AF11;
+ else if (strcasecmp(str, "AF12") == 0)
+ dscp = _DSCP_AF12;
+ else if (strcasecmp(str, "AF13") == 0)
+ dscp = _DSCP_AF13;
+ else if (strcasecmp(str, "AF21") == 0)
+ dscp = _DSCP_AF21;
+ else if (strcasecmp(str, "AF22") == 0)
+ dscp = _DSCP_AF22;
+ else if (strcasecmp(str, "AF23") == 0)
+ dscp = _DSCP_AF23;
+ else if (strcasecmp(str, "AF31") == 0)
+ dscp = _DSCP_AF31;
+ else if (strcasecmp(str, "AF32") == 0)
+ dscp = _DSCP_AF32;
+ else if (strcasecmp(str, "AF33") == 0)
+ dscp = _DSCP_AF33;
+ else if (strcasecmp(str, "AF41") == 0)
+ dscp = _DSCP_AF41;
+ else if (strcasecmp(str, "AF42") == 0)
+ dscp = _DSCP_AF42;
+ else if (strcasecmp(str, "AF43") == 0)
+ dscp = _DSCP_AF43;
+
+ else {
+ unsigned long val = strtoul(str, &endptr, 0);
+ if (*endptr != '\0' || val > 255)
+ *valid = false;
+ else
+ return ((u_int8_t)val);
+ }
+ /* DSCP occupies the 6 upper bits of the traffic class field */
+ return (dscp << 2);
+}
+
+void
+pr_currenttime(void)
+{
+ int s;
+ struct timeval tv;
+
+ gettimeofday(&tv, NULL);
+
+ s = (tv.tv_sec + thiszone) % 86400;
+ printf("%02d:%02d:%02d.%06u ", s / 3600, (s % 3600) / 60, s % 60,
+ (u_int32_t)tv.tv_usec);
+}
+
void
-usage()
+usage(void)
{
(void)fprintf(stderr,
#if defined(IPSEC) && !defined(IPSEC_POLICY_IPSEC)
"A"
#endif
"usage: ping6 [-"
- "d"
+ "Dd"
#if defined(IPSEC) && !defined(IPSEC_POLICY_IPSEC)
"E"
#endif
"m"
#endif
"nNoqrRtvwW] "
- "[-a addrtype] [-b bufsiz] [-B boundif] [-c count]\n"
+ "[-a addrtype] [-b bufsiz] [-c count]\n"
" [-g gateway] [-h hoplimit] [-I interface] [-i wait] [-l preload]"
#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
" [-P policy]"
#endif
"\n"
" [-p pattern] [-S sourceaddr] [-s packetsize] [-z tclass] "
+ "[-k traffic_class] [-K net_service_type] "
"[hops ...] host\n");
+ (void)fprintf(stderr, "Apple specific options (to be specified before hops or host like all options)\n");
+ (void)fprintf(stderr, " -b boundif # bind the socket to the interface\n");
+ (void)fprintf(stderr, " -k traffic_class # set traffic class socket option\n");
+ (void)fprintf(stderr, " -K net_service_type # set traffic class socket options\n");
+ (void)fprintf(stderr, " -apple-connect # call connect(2) in the socket\n");
+ (void)fprintf(stderr, " -apple-time # display current time\n");
+ (void)fprintf(stderr, " -apple-progress # show progress for debugging\n");
exit(1);
}