ping.c revision 4c10bc16d0f6bbad846a55218fb2d1bf077caf90
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T
* All Rights Reserved.
*/
/*
* University Copyright- Copyright (c) 1982, 1986, 1988
* The Regents of the University of California.
* All Rights Reserved.
*
* University Acknowledgment- Portions of this document are derived from
* software developed by the University of California, Berkeley, and its
* contributors.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <stdio.h>
#include <strings.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
#include <limits.h>
#include <math.h>
#include <sys/sysmacros.h>
#include <netinet/in_systm.h>
#include <netdb.h>
#include <stdlib.h>
#include <priv_utils.h>
#include <libinetutil.h>
#include "ping.h"
/*
* This macro is used to compare 16bit, wrapping sequence numbers. Inspired by
* TCP's SEQ_LEQ macro.
*/
#define PINGSEQ_LEQ(a, b) ((int16_t)((a)-(b)) <= 0)
#define DEFAULT_DATALEN 56
#define MULTICAST_TTL 2
#define MULTICAST_IF 4
#define IF_INDEX 0 /* types of -i argument */
#define IF_NAME 1
#define IF_ADDR 2
#define IF_ADDR6 3
#ifdef BSD
#define setbuf(s, b) setlinebuf((s))
#endif /* BSD */
/* interface identification */
union if_id {
int index; /* interface index (e.g., 1, 2) */
char *name; /* interface name (e.g., le0, hme0) */
};
/* stores the interface supplied by the user */
struct if_entry {
char *str; /* unresolved, string input */
int id_type; /* type of ID (index, name, addr, addr6) */
};
char *progname;
char *targethost;
char *nexthop;
static int send_sock; /* send sockets */
static int send_sock6;
static struct sockaddr_in6 to6;
static int if_index = 0; /* outgoing interface index */
static int num_targetaddrs; /* no of target addresses to probe */
static int num_v4 = 0; /* count of IPv4 addresses */
static int num_v6 = 0; /* count of IPv6 addresses */
/* that goes to target and comes back */
/* to the the sender via src routing. */
int ts_flag; /* timestamp flag value */
static int num_gw; /* number of gateways */
static int eff_num_gw; /* effective number of gateways */
/* if send_reply, it's 2*num_gw+1 */
static int options; /* socket options */
static int moptions; /* multicast options */
int npackets; /* number of packets to send */
int ident; /* ID for this ping run */
/*
* This buffer stores the received packets. Currently it needs to be 32 bit
* aligned. In the future, we'll be using 64 bit alignment, so let's use 64 bit
* alignment now.
*/
/* Used to store the ancillary data that comes with the received packets */
static int ntransmitted; /* number of packet sent to single IP address */
int nreceived; /* # of packets we got back from target host */
int nreceived_last_target; /* received from last target IP */
/*
* These are used for statistics. tmin is initialized to maximum longint value.
* The max value is also used for timeouts. All times are in microseconds.
*/
long long tmax;
union any_in_addr *);
union any_in_addr *);
static void finish();
static void get_gwaddrs(char *[], int, union any_in_addr *,
union any_in_addr *, int *, int *);
static void get_hostinfo(char *, int, struct addrinfo **);
static void mirror_gws(union any_in_addr *, int);
char *pr_name(char *, int);
char *pr_protocol(int);
static void print_unknown_host_msg(const char *, const char *);
union any_in_addr **);
void schedule_sigalrm();
union any_in_addr *, union any_in_addr *);
void send_scheduled_probe();
uint_t);
struct in_addr *);
static void set_nexthop(int, struct addrinfo *, int);
struct addrinfo *);
void sigalrm_handler();
static void usage(char *);
/*
* main()
*/
int
{
int recv_sock6 = -1;
char tmp_buf[INET6_ADDRSTRLEN];
int c;
int i;
/*
* This program needs the net_icmpaccess privileges. We'll fail
* on the socket call and report the error there when we have
* insufficient privileges.
*/
PRIV_SYS_NET_CONFIG, (char *)NULL);
"abA:c:dF:G:g:I:i:LlnN:P:p:rRSsTt:UvX:x:Y0123?")) != -1) {
switch ((char)c) {
case 'A':
} else {
"%s: unknown address family %s\n",
}
break;
case 'a':
break;
case 'c':
if (i > MAX_TRAFFIC_CLASS) {
"range\n", progname, i);
}
break;
case 'd':
break;
case 'b':
break;
case 'F':
if (i > MAX_FLOW_LABEL) {
"range\n", progname, i);
}
break;
case 'I':
break;
case 'i':
/*
* this can accept interface index, interface name, and
* address configured on the interface
*/
moptions |= MULTICAST_IF;
} else {
}
break;
case 'L':
break;
case 'l':
break;
case 'n':
break;
case 'P':
if (i > MAX_TOS) {
"range\n", progname, i);
}
break;
case 'p':
if (i > MAX_PORT) {
"range\n", progname, i);
}
break;
case 'r':
options |= SO_DONTROUTE;
break;
case 'R':
break;
case 'S':
break;
case 's':
break;
case 'T':
break;
case 't':
}
break;
case 'U':
break;
case 'v':
break;
/*
* 'x' and 'X' has been undocumented flags for source routing.
* Now we document loose source routing with the new flag 'g',
* which is same as in traceroute. We still keep x/X as
* as undocumented. 'G', which is for strict source routing is
* also undocumented.
*/
case 'x':
case 'g':
if (num_gw > MAXMAX_GWS) {
progname);
}
break;
case 'X':
case 'G':
if (num_gw > MAXMAX_GWS) {
progname);
}
break;
case 'N':
" allowed\n", progname);
}
break;
case 'Y':
break;
case '0':
case '1':
case '2':
case '3':
ts_flag = (char)c - '0';
break;
case '?':
break;
default:
break;
}
}
}
/*
* send_reply, which sends the probe packet back to itself
* doesn't work with UDP
*/
if (use_udp)
optind++;
if (stats) {
optind++;
"packet count");
if (npackets < 1) {
"out of range\n", progname,
npackets);
}
}
} else {
}
}
/*
* Let's prepare sockaddr_in* structures, cause we might need both of
* them.
*/
if (stats)
ident = (int)getpid() & 0xFFFF;
/* resolve the hostnames */
/*
* We should make sure datalen is reasonable.
* datalen
*/
if (family_input == AF_INET6 ||
size_t exthdr_len = 0;
if (send_reply) {
exthdr_len = sizeof (struct ip6_rthdr0) +
} else if (num_gw > 0) {
exthdr_len = sizeof (struct ip6_rthdr0) +
}
/*
* Size of ICMP6 header and UDP header are the same. Let's
* use ICMP6_MINLEN.
*/
exthdr_len + ICMP6_MINLEN))) {
"%s: data size too large for IPv6 packet\n",
progname);
num_v6 = 0;
}
}
if (family_input == AF_INET ||
if (send_reply) {
/*
* Includes 3 bytes code+ptr+len, the intermediate
* gateways, the actual and the effective target.
*/
opt_len = 3 +
} else if (num_gw > 0) {
}
if (rr_option) {
} else if (ts_option) {
} else {
opt_len += IPOPT_MINOFF +
2 * sizeof (struct ipt_ta);
/*
* Note: BSD/4.X is broken in their check so we
* have to bump up this number by at least one.
*/
opt_len++;
}
}
/* Round up to 4 byte boundary */
if (opt_len & 0x3)
ICMP_MINLEN))) {
"%s: data size too large for IPv4 packet\n",
progname);
num_v4 = 0;
}
}
}
/* setup the sockets */
if (num_v6 != 0) {
}
if (num_v4 != 0) {
}
/*
* If sending back to ourself, add the mirror image of current
* gateways, so that the probes travel to and from the target
* by visiting the same gateways in reverse order.
*/
if (send_reply) {
if (num_v6 != 0)
if (num_v4 != 0)
/* We add 1 because we put the target as the middle gateway */
} else {
eff_num_gw = num_gw;
}
/*
* Set the starting_seq_num for the first targetaddr.
* If we are sending ICMP Echo Requests, the sequence number is same as
* ICMP sequence number, and it starts from zero. If we are sending UDP
* packets, the sequence number is the destination UDP port number,
* which starts from dest_port. At each probe, this sequence number is
* incremented by one.
* We set the starting_seq_num for first targetaddr here. The
* following ones will be set by looking at where we left with the last
* targetaddr.
*/
if (stats) {
} else {
Printf("PING %s (%s): %d data bytes\n",
/* LINTED E_BAD_PTR_CAST_ALIGN */
&((struct sockaddr_in *)
datalen);
} else {
Printf("PING %s (%s): %d data bytes\n",
/* LINTED E_BAD_PTR_CAST_ALIGN */
&((struct sockaddr_in6 *)
datalen);
}
}
}
/* Let's get things going */
/* SIGALRM is used to send the next scheduled probe */
/*
* From now on, we'll always be listening to ICMP packets. As SIGALRM
* comes in, sigalrm_handler() will be invoked and send another
* probe.
*/
return (EXIT_SUCCESS); /* should never come here */
}
/*
* Build the target IP address list. Use command line options and
* name lookup results returned from name server to determine which addresses
* to probe, how many times, in which order.
*/
static struct targetaddr *
{
struct targetaddr *targetaddr;
struct targetaddr **nextp;
int num_dst;
int i;
if (probe_all)
else
num_dst = 1;
(union any_in_addr *)
/* LINTED E_BAD_PTR_CAST_ALIGN */
&((struct sockaddr_in *)
&src_addr_list[i]);
(union any_in_addr *)
/* LINTED E_BAD_PTR_CAST_ALIGN */
&((struct sockaddr_in6 *)
&src_addr_list[i]);
} else {
continue;
}
*nextp = targetaddr;
if (num_targetaddrs == 1)
break;
}
return (head);
}
/*
* Given an address family, dst and src addresses, by also looking at the
* options provided at the command line, this function creates a targetaddr
* to be linked with others, forming a global targetaddr list. Each targetaddr
* item contains information about probes sent to a specific IP address.
*/
static struct targetaddr *
union any_in_addr *src_addr)
{
struct targetaddr *targetaddr;
if (targetaddr == NULL) {
}
if (stats) {
/*
* npackets is only defined if we are in stats mode.
* npackets determines how many probes to send to each target
* IP address. npackets == 0 means send only 1 and move on to
* next target IP.
*/
if (npackets > 0)
else
} else {
}
targetaddr->num_sent = 0;
return (targetaddr);
}
/*
* print "unknown host" message
*/
static void
{
hostname);
}
/*
* Resolve hostnames for the target host and gateways. Also, determine source
* addresses to use for each target address.
*/
static void
union any_in_addr **src_addr_listp)
{
int num_resolved_gw = 0;
int num_resolved_gw6 = 0;
}
if (ai_nexthop == NULL) {
}
}
/* Get a count of the v4 & v6 addresses */
case AF_INET:
num_v4++;
break;
case AF_INET6:
num_v6++;
break;
}
}
}
/* resolve gateways */
if (num_gw > 0) {
/* we couldn't resolve a gateway as an IPv6 host */
print_unknown_host_msg(" IPv6",
num_v6 = 0;
}
/* we couldn't resolve a gateway as an IPv4 host */
print_unknown_host_msg(" IPv4",
num_v4 = 0;
}
}
}
/*
* Resolve the gateway names, splitting results into v4 and v6 lists.
* Gateway addresses are added to the appropriate passed-in array; the
* number of resolved gateways for each af is returned in resolved[6].
* Assumes that passed-in arrays are large enough for MAX_GWS[6] addrs
* and resolved[6] ptrs are non-null; ignores array and counter if the
* address family param makes them irrelevant.
*/
static void
{
int i;
switch (family) {
case AF_UNSPEC:
break;
case AF_INET:
break;
case AF_INET6:
break;
default:
return;
}
}
}
for (i = 0; i < num_gw; i++) {
return;
return;
/* LINTED E_BAD_PTR_CAST_ALIGN */
bcopy(&((struct sockaddr_in *)
aip->ai_addrlen);
(*resolved)++;
break;
}
}
} else if (check_v4) {
}
/* LINTED E_BAD_PTR_CAST_ALIGN */
bcopy(&((struct sockaddr_in6 *)
aip->ai_addrlen);
(*resolved6)++;
break;
}
}
} else if (check_v6) {
}
}
}
/*
* Given the list of gateways, extends the list with its mirror image. This is
* used when -l/-S is used. The middle gateway will be the target address. We'll
* leave it blank for now.
*/
static void
{
int effective_num_gw;
int i;
/* We add 1 because we put the target as the middle gateway */
}
for (i = 0; i < num_gw; i++)
}
/*
* Given IP address or hostname, return addrinfo list.
* Assumes that addrinfo ** ptr is non-null.
*/
static void
{
char tmp_buf[INET6_ADDRSTRLEN];
int rc;
/* check if broadcast */
else
/* check if IPv4-mapped address or broadcast */
if (!broadcast) {
/*
* Peel off the "mapping" stuff, leaving 32 bit IPv4
* address.
*/
/* convert it back to a string */
sizeof (tmp_buf));
/*
* Now the host is an IPv4 address.
* Since it previously was a v4 mapped v6 address
* we can be sure that the size of buffer 'host'
* is large enough to contain the associated v4
* here.
*/
}
/*
* If it's a broadcast address, it cannot be an IPv6 address.
* Also, if it's a mapped address, we convert it into IPv4
* address because ping will send and receive IPv4 packets for
* that address. Therefore, it's a failure case to ask
* get_hostinfo() to treat a broadcast or a mapped address
* as an IPv6 address.
*/
return;
}
}
if (rc != 0) {
if (rc != EAI_NONAME)
gai_strerror(rc));
return;
}
}
/*
* For each IP address of the target host, determine a source address to use.
*/
static void
{
union any_in_addr *list;
int num_dst = 1;
int i;
if (probe_all)
list = (union any_in_addr *)
}
/*
* If there's a gateway, a routing header as a consequence, our kernel
* picks the source address based on the first hop address, rather than
* final destination address.
*/
if (num_gw > 0) {
else
/*
* Since the first gateway address is fixed, we'll use the same
* src address for every different final destination address
* we send to.
*/
for (i = 1; i < num_dst; i++)
} else {
/*
* Although something like 'ping -l host' results in a routing
* header, the first gateway address is the target host's
* address. Therefore, as far as src address selection goes,
* the result is same as having no routing header.
*/
if (num_v4 != 0) {
select_src_addr((union any_in_addr *)
/* LINTED E_BAD_PTR_CAST_ALIGN */
&((struct sockaddr_in *)
&list[i]);
}
} else {
if (num_v6 != 0) {
select_src_addr((union any_in_addr *)
/* LINTED E_BAD_PTR_CAST_ALIGN */
&((struct sockaddr_in6 *)
&list[i]);
}
}
}
}
*src_addr_list = list;
}
/*
* For a given destination address, determine a source address to use.
* Returns wildcard address if it cannot determine the source address.
*/
static void
union any_in_addr *src_addr)
{
struct sockaddr_in *sin;
struct sockaddr_in6 *sin6;
int tmp_fd;
}
/* LINTED E_BAD_PTR_CAST_ALIGN */
sock_len = sizeof (struct sockaddr_in);
} else {
/* LINTED E_BAD_PTR_CAST_ALIGN */
sock_len = sizeof (struct sockaddr_in6);
}
/* open a UDP socket */
}
/* connect it */
/*
* If there's no route to the destination, this connect() call
* fails. We just return all-zero (wildcard) as the source
* address, so that user can get to see "no route to dest"
* message, as it'll try to send the probe packet out and will
* receive ICMP unreachable.
*/
else
return;
}
/* get the local sock info */
}
} else {
}
}
/*
* Set the IP_NEXTHOP/IPV6_NEXTHOP socket option.
* exits on failure
*/
static void
{
/* LINTED E_BAD_PTR_CAST_ALIGN */
/* now we need the sys_net_config privilege */
(void) __priv_bracket(PRIV_ON);
}
(void) __priv_bracket(PRIV_OFF);
/* revert to non-privileged user */
} else {
struct sockaddr_in6 *nh;
/* LINTED E_BAD_PTR_CAST_ALIGN */
nh, sizeof (struct sockaddr_in6)) < 0) {
}
}
}
/*
* Setup the socket for the given address family.
* Returns _B_TRUE on success, _B_FALSE on failure. Failure is the case when no
* interface can be found, or the specified interface (-i) is not found. On
* library call failures, it exit()s.
*/
static boolean_t
{
int send_sock;
int recv_sock;
struct sockaddr_in6 sin6;
struct sockaddr_in sin;
int on = 1;
int int_op;
/* now we need the net_icmpaccess privilege */
(void) __priv_bracket(PRIV_ON);
if (recv_sock < 0) {
}
/* revert to non-privileged user after opening sockets */
(void) __priv_bracket(PRIV_OFF);
if (bypass) {
"to bypass IPsec policy.\n", progname);
else
}
}
/*
* We always receive on raw icmp socket. But the sending socket can be
* raw icmp or udp, depending on the use of -U flag.
*/
if (use_udp) {
if (send_sock < 0) {
}
if (bypass) {
sizeof (req)) < 0) {
"privilege to bypass IPsec "
"policy.\n", progname);
else
}
}
/*
* In order to distinguish replies to our UDP probes from
* other pings', we need to know our source port number.
*/
} else {
}
/* Let's bind() send_sock to wildcard address and port */
}
/* .... and see what port kernel picked for us */
}
} else {
}
sizeof (int_op)) == -1) {
}
sizeof (int_op)) == -1) {
}
sizeof (on)) == -1) {
}
}
if (options & SO_DONTROUTE) {
sizeof (on)) == -1) {
}
}
if (moptions & MULTICAST_NOLOOP) {
char_op = 0; /* used to turn off option */
"IP_MULTICAST_NOLOOP %s\n", progname,
}
} else {
int_op = 0; /* used to turn off option */
IPV6_MULTICAST_LOOP, (char *)&int_op,
sizeof (int_op)) == -1) {
"IPV6_MULTICAST_NOLOOP %s\n", progname,
}
}
}
if (moptions & MULTICAST_TTL) {
(char *)&char_op, sizeof (char)) == -1) {
"IP_MULTICAST_TTL %s\n", progname,
}
}
}
/*
* AF_INET6 case is handled in set_ancillary_data() function.
* This is because when ancillary data is used (for routing
* header and outgoing interface index), the hoplimit set using
* setsockopt() is ignored.
*/
}
/* did the user specify an interface? */
if (moptions & MULTICAST_IF) {
struct ifaddrlist *my_if;
char errbuf[ERRBUFSIZE];
int num_ifs;
int num_src_ifs; /* exclude down and loopback */
int i;
/* pull out the interface list */
if (num_ifs == -1) {
}
/* filter out down and loopback interfaces */
num_src_ifs = 0;
for (i = 0; i < num_ifs; i++) {
num_src_ifs++;
}
if (num_src_ifs == 0) {
return (_B_FALSE); /* failure */
}
/* locate the specified interface */
return (_B_FALSE);
}
sizeof (struct in_addr)) == -1) {
"IP_MULTICAST_IF %s\n", progname,
}
} else {
/*
* the outgoing interface is set in set_ancillary_data()
* function
*/
}
}
sizeof (int_op)) == -1) {
}
}
/* receiving IPv6 extension headers in verbose mode */
}
}
}
}
*send_sockp = send_sock;
*recv_sockp = recv_sock;
/* successful */
return (_B_TRUE);
}
/*
* Pull out the record containing all the info about the interface specified by
* `out_if'. Skips interfaces which are down or loopback.
*/
static struct ifaddrlist *
{
static struct ifaddrlist tmp_if;
int i;
i = 0;
/* skip down or loopback interfaces */
i++;
continue;
}
/* the type of interface id is variable */
case IF_INDEX:
break;
case IF_NAME:
break;
case IF_ADDR:
}
break;
case IF_ADDR6:
}
break;
default:
break;
}
i++;
}
if (found)
return (&tmp_if);
else
return (NULL);
}
/*
* Invoked by SIGALRM, sigalrm_handler() is, responsible for calling
* send_scheduled_probe() to send next probe.
*/
void
sigalrm_handler(void)
{
/*
* Guard againist denial-of-service attacks. Make sure ping doesn't
* send probes for every SIGALRM it receives. Evil hacker can generate
* SIGALRMs as fast as it can, but ping will ignore those which are
* received too soon (earlier than 0.5 sec) after it sent the last
* probe. We use gethrtime() instead of gettimeofday() because
* the latter is not linear and is prone to resetting or drifting
*/
return;
}
}
/*
* Schedule next SIGALRM.
*/
void
schedule_sigalrm(void)
{
int waittime;
if (npackets == 0 ||
} else {
if (current_targetaddr->got_reply) {
if (waittime == 0)
waittime = 1;
} else {
}
}
}
/*
* Called by sigalrm_handler(), check_reply() or check_reply6(),
* send_scheduled_probe() looks at the current_targetaddr and determines what
* should be sent next and calls pinger().
*/
void
{
char tmp_buf[INET6_ADDRSTRLEN];
/*
* We are about to move to next targetaddr if it's either we sent
* all the probes, or somebody set the probing_done flag to
* _B_TRUE prompting us to move on.
*/
/*
* is this a dead target?
*/
if (!probe_all) {
} else {
}
}
/*
* Before we move onto next item, let's do some clean up.
*/
/*
* If this is probe-all without stats mode, then we need to
* preserve this count. This is needed when we try to map an
* icmp_seq to IP address. Otherwise, clear it.
*/
current_targetaddr->num_sent = 0;
/*
* Did we reach the end of road?
*/
if (current_targetaddr == NULL) {
(void) alarm(0); /* cancel alarm */
if (stats)
finish();
if (is_alive)
else
} else {
/*
* We use starting_seq_num for authenticating replies.
* Each time we move to a new targetaddr, which has
* a different target IP address, we update this field.
*/
}
}
if (send_reply) {
/* sending back to ourself */
} else {
}
/*
* Setting the ancillary data once is enough, if we are
* not using source routing through target (-l/-S). In
* case -l/-S used, the middle gateway will be the
* IP address of the source, which can be different
* for each target IP.
*/
if (first_probe ||
if (send_reply) {
/* target is the middle gateway now */
}
}
} else {
/*
* Set IPv4 options when sending the first probe to a target
* IP address. Some options change when the target address
* changes.
*/
if (current_targetaddr->num_sent == 0) {
if (eff_num_gw > 0) {
/*
* If send_reply, the target becomes the
* middle gateway, sender becomes the last
* gateway.
*/
if (send_reply) {
}
}
/*
* In IPv4, if source routing is used, the target
* address shows up as the last gateway, hence +1.
*/
}
}
}
/*
* recv_icmp_packet()'s job is to listen to icmp packets and filter out
* those ping is interested in.
*/
static void
{
struct sockaddr_in6 from6;
int result;
int cc;
while (always_true) {
if (recv_sock6 != -1)
if (recv_sock != -1)
if (result == -1) {
continue;
} else {
}
} else if (result > 0) {
/* Do we have an ICMP6 packet waiting? */
if ((recv_sock6 != -1) &&
if (cc < 0) {
"%s: recvmsg %s\n",
}
continue;
} else if (cc > 0) {
}
}
/* Do we have an ICMP packet waiting? */
if (cc < 0) {
"%s: recvmsg %s\n",
}
continue;
} if (cc > 0) {
}
}
}
/*
* If we were probing last IP address of the target host and
* received a reply for each probe sent to this address,
* then we are done!
*/
(nreceived_last_target == npackets)) {
(void) alarm(0); /* cancel alarm */
finish();
}
} /* infinite loop */
}
/*
* Given a host (with possibly multiple IP addresses) and an IP address, this
* function determines if this IP address is one of the host's addresses to
* which we're sending probes. Used to determine if we are interested in a
* packet.
*/
{
int num_addrs;
int i;
if (probe_all)
else
num_addrs = 1;
/* LINTED E_BAD_PTR_CAST_ALIGN */
if (IN6_ARE_ADDR_EQUAL(&((struct sockaddr_in6 *)
return (_B_TRUE);
} else {
/* LINTED E_BAD_PTR_CAST_ALIGN */
if (((struct sockaddr_in *)
return (_B_TRUE);
}
}
return (_B_FALSE);
}
/*
* Compose and transmit an ICMP ECHO REQUEST packet. The IP packet
* will be added on by the kernel. The ID field is our UNIX process ID,
* and the sequence number is an ascending integer. The first 8 bytes
* of the data portion are used to hold a UNIX "timeval" struct in network
* byte-order, to compute the round-trip time.
*/
static void
int family)
{
/* LINTED E_BAD_PTR_CAST_ALIGN */
/* LINTED E_BAD_PTR_CAST_ALIGN */
/* LINTED E_BAD_PTR_CAST_ALIGN */
int start = 0;
int cc;
int i;
/* using UDP? */
if (use_udp) {
/* LINTED E_BAD_PTR_CAST_ALIGN */
/*
* This sets the port whether we are handling a v4 or v6
* sockaddr structure.
*/
ntransmitted++;
} else { /* using ICMP */
} else if (use_icmp_ts) { /* family is AF_INET */
} else {
}
icp->icmp_cksum = 0;
num_wraps++;
/* LINTED E_BAD_PTR_CAST_ALIGN */
}
/* if packet is big enough to store timeval OR ... */
/* Number of milliseconds since midnight */
}
*datap++ = i;
if (!use_udp)
sizeof (struct sockaddr_in));
} else {
/*
* Fill in the rest of the msghdr structure. msg_control is set
* in set_ancillary_data().
*/
}
/* This is a more precise time (right after we send the packet) */
if (i < 0 || i != cc) {
if (i < 0) {
if (!stats)
}
Printf("ping: wrote %s %d chars, ret=%d\n",
targethost, cc, i);
}
}
/*
* Return a hostname for the given IP address.
*/
char *
{
struct sockaddr_in sin;
struct sockaddr_in6 sin6;
char *cp;
char abuf[INET6_ADDRSTRLEN];
switch (family) {
case AF_INET:
slen = sizeof (struct sockaddr_in);
/* LINTED E_BAD_PTR_CAST_ALIGN */
break;
case AF_INET6:
slen = sizeof (struct sockaddr_in6);
/* LINTED E_BAD_PTR_CAST_ALIGN */
break;
default:
return (buf);
}
/* compare with the buffered (previous) lookup */
/* getnameinfo() failed; return just the address */
buf[0] = 0;
} else if (!nflag) {
/* append numeric address to hostname string */
sizeof (abuf)));
}
/* LINTED E_BAD_PTR_CAST_ALIGN */
}
return (buf);
}
/*
* Return the protocol string, given its protocol number.
*/
char *
pr_protocol(int prot)
{
static char buf[20];
switch (prot) {
case IPPROTO_ICMPV6:
break;
case IPPROTO_ICMP:
break;
case IPPROTO_TCP:
break;
case IPPROTO_UDP:
break;
default:
break;
}
return (buf);
}
/*
* Checks if value is between seq_begin and seq_begin+seq_len. Note that
* sequence numbers wrap around after MAX_ICMP_SEQ (== MAX_PORT).
*/
{
/*
* If seq_len is too big, like some value greater than MAX_ICMP_SEQ/2,
* truncate it down to MAX_ICMP_SEQ/2. We are not going to accept any
* reply which come 83hr later!
*/
(MAX_ICMP_SEQ + 1);
}
return (_B_TRUE);
else
return (_B_FALSE);
}
/*
* For a given icmp_seq, find which destination address we must have sent this
* to.
*/
void
{
int real_seq;
int targetaddr_index;
int real_npackets;
int i;
/*
* If this is probe_all and not stats, then the number of probes sent to
* each IP address may be different (remember, we stop sending to one IP
* address as soon as it replies). They are stored in target->num_sent
* field. Since we don't wrap around the list (!stats), they are also
* preserved.
*/
do {
/*
* We are not immediately return()ing here.
* Because of wrapping, we might find another
* match later, which is more likely to be the
* real one.
*/
}
} else {
/*
* Find the absolute (non-wrapped) seq number within the last
* 64K
*/
} else {
}
/* Make sure it's non-negative */
if (real_seq < 0)
return;
/*
* We sent npackets many packets to each of those
* num_targetaddrs many IP addresses.
*/
for (i = 0; i < targetaddr_index; i++)
}
}
/*
* Checksum routine for Internet Protocol family headers (C Version)
*/
static ushort_t
{
int sum = 0;
/*
* Our algorithm is simple, using a 32 bit accumulator (sum),
* we add sequential 16 bit words to it, and at the end, fold
* back all the carry bits from the top 16 bits into the lower
* 16 bits.
*/
while (nleft > 1) {
sum += *w++;
nleft -= 2;
}
/* mop up an odd byte, if necessary */
if (nleft == 1) {
}
/*
* add back carry outs from top 16 bits to low 16 bits
*/
return (answer);
}
/*
* Subtract 2 timeval structs: out = out - in.
* Out is assumed to be >= in.
*/
void
{
}
}
/*
* Print out statistics, and give up.
* Heavily buffered STDIO is used here, so that all the statistics
* will be written with 1 sys-write call. This is nice when more
* than one copy of the program is running on a terminal; it prevents
* the statistics output from becoming intermingled.
*/
static void
finish()
{
if (ntransmitted) {
if (nreceived <= ntransmitted) {
Printf("%d%% packet loss",
ntransmitted));
} else {
Printf("%.2f times amplification",
(double)nreceived / (double)ntransmitted);
}
}
(void) putchar('\n');
/* if packet is big enough to store timeval AND ... */
double sd =
}
}
/*
* print the usage line
*/
static void
{
/* CSTYLED */
"usage: %s -s [-l | U] [abdLnRrv] [-A addr_family] [-c traffic_class]\n\t"
"[-g gateway [-g gateway ...]] [-N nexthop] [-F flow_label] [-I interval]\n\t"
"[-i interface] [-P tos] [-p port] [-t ttl] host [data_size] [npackets]\n",
cmdname);
}
/*
* Parse integer argument; exit with an error if it's not a number.
* Now it also accepts hex. values.
*/
static int
{
char *cp;
char *ep;
int num;
errno = 0;
if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) {
cp = s + 2;
} else {
}
}
return (num);
}