Move /var/svc/log to /var/log/svc
[unleashed/lotheac.git] / usr / src / cmd / cmd-inet / usr.sbin / ping / ping.c
blob436184bd142361d1c5ced02dc96e1521cce127a8
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
21 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
22 * Use is subject to license terms.
26 * Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T
27 * All Rights Reserved.
31 * University Copyright- Copyright (c) 1982, 1986, 1988
32 * The Regents of the University of California.
33 * All Rights Reserved.
35 * University Acknowledgment- Portions of this document are derived from
36 * software developed by the University of California, Berkeley, and its
37 * contributors.
41 * Copyright (c) 2017, Joyent, Inc.
44 #include <assert.h>
45 #include <stdio.h>
46 #include <strings.h>
47 #include <errno.h>
48 #include <fcntl.h>
49 #include <unistd.h>
50 #include <signal.h>
51 #include <limits.h>
52 #include <math.h>
53 #include <locale.h>
54 #include <thread.h>
55 #include <synch.h>
57 #include <sys/time.h>
58 #include <sys/param.h>
59 #include <sys/socket.h>
60 #include <sys/sockio.h>
61 #include <sys/stropts.h>
62 #include <sys/file.h>
63 #include <sys/sysmacros.h>
64 #include <sys/debug.h>
66 #include <arpa/inet.h>
67 #include <net/if.h>
68 #include <netinet/in_systm.h>
69 #include <netinet/in.h>
70 #include <netinet/ip.h>
71 #include <netinet/ip_icmp.h>
72 #include <netinet/ip_var.h>
73 #include <netinet/ip6.h>
74 #include <netinet/icmp6.h>
75 #include <netinet/udp.h>
76 #include <netdb.h>
77 #include <stdlib.h>
78 #include <priv_utils.h>
80 #include <libinetutil.h>
81 #include "ping.h"
84 * This macro is used to compare 16bit, wrapping sequence numbers. Inspired by
85 * TCP's SEQ_LEQ macro.
87 #define PINGSEQ_LEQ(a, b) ((int16_t)((a)-(b)) <= 0)
89 #define MAX_WAIT 10 /* max sec. to wait for response */
90 #define MAX_TRAFFIC_CLASS 255 /* max traffic class for IPv6 */
91 #define MAX_FLOW_LABEL 0xFFFFF /* max flow label for IPv6 */
92 #define MAX_TOS 255 /* max type-of-service for IPv4 */
94 #define TIMEOUT 20 /* default timeout value */
95 #define DEFAULT_DATALEN 56
97 #define MULTICAST_NOLOOP 1 /* multicast options */
98 #define MULTICAST_TTL 2
99 #define MULTICAST_IF 4
101 #define IF_INDEX 0 /* types of -i argument */
102 #define IF_NAME 1
103 #define IF_ADDR 2
104 #define IF_ADDR6 3
106 #ifdef BSD
107 #define setbuf(s, b) setlinebuf((s))
108 #endif /* BSD */
111 /* interface identification */
112 union if_id {
113 int index; /* interface index (e.g., 1, 2) */
114 char *name; /* interface name (e.g., le0, hme0) */
115 union any_in_addr addr; /* interface address (e.g., 10.123.4.5) */
118 /* stores the interface supplied by the user */
119 struct if_entry {
120 char *str; /* unresolved, string input */
121 int id_type; /* type of ID (index, name, addr, addr6) */
122 union if_id id; /* ID */
125 char *progname;
126 char *targethost;
127 char *nexthop;
129 static int send_sock; /* send sockets */
130 static int send_sock6;
131 static struct sockaddr_in to; /* where to send */
132 static struct sockaddr_in6 to6;
133 static union any_in_addr gw_IP_list[MAX_GWS]; /* gateways */
134 static union any_in_addr gw_IP_list6[MAX_GWS6];
135 static int if_index = 0; /* outgoing interface index */
136 boolean_t is_alive = B_FALSE; /* is target host alive */
137 struct targetaddr *current_targetaddr; /* current target IP address to probe */
138 static struct targetaddr *targetaddr_list; /* list of IP addresses to probe */
139 static int num_targetaddrs; /* no of target addresses to probe */
140 static int num_v4 = 0; /* count of IPv4 addresses */
141 static int num_v6 = 0; /* count of IPv6 addresses */
142 boolean_t verbose = B_FALSE; /* verbose output */
143 boolean_t stats = B_FALSE; /* display statistics */
144 static boolean_t settos = B_FALSE; /* set type-of-service value */
145 boolean_t rr_option = B_FALSE; /* true if using record route */
146 boolean_t send_reply = B_FALSE; /* Send an ICMP_{ECHO|TSTAMP}REPLY */
147 /* that goes to target and comes back */
148 /* to the the sender via src routing. */
149 boolean_t strict = B_FALSE; /* true if using strict source route */
150 boolean_t ts_option = B_FALSE; /* true if using timestamp option */
151 boolean_t use_icmp_ts = B_FALSE; /* Use ICMP timestamp request */
152 boolean_t use_udp = B_FALSE; /* Use UDP instead of ICMP */
153 boolean_t probe_all = B_FALSE; /* probe all the IP addresses */
154 boolean_t nflag = B_FALSE; /* do not reverse lookup addresses */
155 boolean_t bypass = B_FALSE; /* bypass IPsec policy */
156 static int family_input = AF_UNSPEC; /* address family supplied by user */
157 int datalen = DEFAULT_DATALEN; /* How much data */
158 int ts_flag; /* timestamp flag value */
159 static int num_gw; /* number of gateways */
160 static int eff_num_gw; /* effective number of gateways */
161 /* if send_reply, it's 2*num_gw+1 */
162 static int num_wraps = -1; /* no of times 64K icmp_seq wrapped */
163 static ushort_t dest_port = 32768 + 666; /* starting port for the UDP probes */
164 static char *gw_list[MAXMAX_GWS]; /* list of gateways as user enters */
165 static int options; /* socket options */
166 static int moptions; /* multicast options */
167 int npackets; /* number of packets to send */
168 static ushort_t tos; /* type-of-service value */
169 static int hoplimit = -1; /* time-to-live value */
170 static int dontfrag; /* IP*_DONTFRAG */
171 static int timeout = TIMEOUT; /* timeout value (sec) for probes */
172 static struct if_entry out_if; /* interface argument */
173 int ident; /* ID for this ping run */
174 static hrtime_t t_last_probe_sent; /* the time we sent the last probe */
175 static timer_t timer; /* timer for waiting */
176 static volatile boolean_t timer_done = B_FALSE; /* timer finished? */
177 static struct itimerspec interval = { { 0, 0 }, { 1, 0 } }; /* Interval for */
178 /* -I. The default interval is 1s. */
179 static hrtime_t mintime = NSEC2MSEC(500); /* minimum time between pings */
182 * Globals for our name services warning. See ns_warning_thr() for more on why
183 * this exists.
185 static mutex_t ns_lock = ERRORCHECKMUTEX; /* Protects the following data */
186 static boolean_t ns_active = B_FALSE; /* Lookup is going on */
187 static hrtime_t ns_starttime; /* Time the lookup started */
188 static int ns_sleeptime = 2; /* Time in seconds between checks */
189 static int ns_warntime = 2; /* Time in seconds before warning */
192 * This buffer stores the received packets. Currently it needs to be 32 bit
193 * aligned. In the future, we'll be using 64 bit alignment, so let's use 64 bit
194 * alignment now.
196 static uint64_t in_pkt[(IP_MAXPACKET + 1)/8];
198 /* Used to store the ancillary data that comes with the received packets */
199 static uint64_t ancillary_data[(IP_MAXPACKET + 1)/8];
201 static int ntransmitted; /* number of packet sent to single IP address */
202 int nreceived; /* # of packets we got back from target host */
203 int nreceived_last_target; /* received from last target IP */
205 * These are used for statistics. tmin is initialized to maximum longint value.
206 * The max value is also used for timeouts. All times are in microseconds.
208 long long tmin = LLONG_MAX;
209 long long tmax;
210 int64_t tsum; /* sum of all times, for doing average */
211 int64_t tsum2; /* sum of squared times, for std. dev. */
213 static struct targetaddr *build_targetaddr_list(struct addrinfo *,
214 union any_in_addr *);
215 extern void check_reply(struct addrinfo *, struct msghdr *, int, ushort_t);
216 extern void check_reply6(struct addrinfo *, struct msghdr *, int, ushort_t);
217 static struct targetaddr *create_targetaddr_item(int, union any_in_addr *,
218 union any_in_addr *);
219 void find_dstaddr(ushort_t, union any_in_addr *);
220 static struct ifaddrlist *find_if(struct ifaddrlist *, int);
221 static void finish();
222 static void get_gwaddrs(char *[], int, union any_in_addr *,
223 union any_in_addr *, int *, int *);
224 static void get_hostinfo(char *, int, struct addrinfo **);
225 static ushort_t in_cksum(ushort_t *, int);
226 static int int_arg(char *s, char *what);
227 boolean_t is_a_target(struct addrinfo *, union any_in_addr *);
228 static void mirror_gws(union any_in_addr *, int);
229 static void *ns_warning_thr(void *);
230 static void parse_interval(char *s);
231 static void pinger(int, struct sockaddr *, struct msghdr *, int);
232 char *pr_name(char *, int);
233 char *pr_protocol(int);
234 static void print_unknown_host_msg(const char *, const char *);
235 static void recv_icmp_packet(struct addrinfo *, int, int, ushort_t, ushort_t);
236 static void resolve_nodes(struct addrinfo **, struct addrinfo **,
237 union any_in_addr **);
238 void schedule_sigalrm();
239 static void select_all_src_addrs(union any_in_addr **, struct addrinfo *,
240 union any_in_addr *, union any_in_addr *);
241 static void select_src_addr(union any_in_addr *, int, union any_in_addr *);
242 void send_scheduled_probe();
243 boolean_t seq_match(ushort_t, int, ushort_t);
244 extern void set_ancillary_data(struct msghdr *, int, union any_in_addr *, int,
245 uint_t);
246 extern void set_IPv4_options(int, union any_in_addr *, int, struct in_addr *,
247 struct in_addr *);
248 static void set_nexthop(int, struct addrinfo *, int);
249 static boolean_t setup_socket(int, int *, int *, int *, ushort_t *,
250 struct addrinfo *);
251 void sigalrm_handler();
252 void tvsub(struct timeval *, struct timeval *);
253 static void usage(char *);
256 * main()
259 main(int argc, char *argv[])
261 struct addrinfo *ai_dst = NULL; /* addrinfo host list */
262 struct addrinfo *ai_nexthop = NULL; /* addrinfo nexthop */
263 union any_in_addr *src_addr_list = NULL; /* src addrs to use */
264 int recv_sock = -1; /* receive sockets */
265 int recv_sock6 = -1;
266 ushort_t udp_src_port; /* src ports for UDP probes */
267 ushort_t udp_src_port6; /* used to identify replies */
268 uint_t flowinfo = 0;
269 uint_t class = 0;
270 char abuf[INET6_ADDRSTRLEN];
271 int c;
272 int i;
273 boolean_t has_sys_ip_config;
275 progname = argv[0];
277 (void) setlocale(LC_ALL, "");
280 * This program needs the net_icmpaccess privilege for creating
281 * raw ICMP sockets. It needs sys_ip_config for using the
282 * IP_NEXTHOP socket option (IPv4 only). We'll fail
283 * on the socket call and report the error there when we have
284 * insufficient privileges.
286 * Shared-IP zones don't have the sys_ip_config privilege, so
287 * we need to check for it in our limit set before trying
288 * to set it.
290 has_sys_ip_config = priv_ineffect(PRIV_SYS_IP_CONFIG);
292 (void) __init_suid_priv(PU_CLEARLIMITSET, PRIV_NET_ICMPACCESS,
293 has_sys_ip_config ? PRIV_SYS_IP_CONFIG : NULL, NULL);
295 setbuf(stdout, (char *)0);
297 while ((c = getopt(argc, argv,
298 "abA:c:dDF:G:g:I:i:LlnN:P:p:rRSsTt:UvX:x:Y0123?")) != -1) {
299 switch ((char)c) {
300 case 'A':
301 if (strcmp(optarg, "inet") == 0) {
302 family_input = AF_INET;
303 } else if (strcmp(optarg, "inet6") == 0) {
304 family_input = AF_INET6;
305 } else {
306 Fprintf(stderr,
307 "%s: unknown address family %s\n",
308 progname, optarg);
309 exit(EXIT_FAILURE);
311 break;
313 case 'a':
314 probe_all = B_TRUE;
315 break;
317 case 'c':
318 i = int_arg(optarg, "traffic class");
319 if (i > MAX_TRAFFIC_CLASS) {
320 Fprintf(stderr, "%s: traffic class %d out of "
321 "range\n", progname, i);
322 exit(EXIT_FAILURE);
324 class = (uint_t)i;
325 break;
327 case 'd':
328 options |= SO_DEBUG;
329 break;
331 case 'D':
332 dontfrag = 1;
333 break;
335 case 'b':
336 bypass = B_TRUE;
337 break;
339 case 'F':
340 i = int_arg(optarg, "flow label");
341 if (i > MAX_FLOW_LABEL) {
342 Fprintf(stderr, "%s: flow label %d out of "
343 "range\n", progname, i);
344 exit(EXIT_FAILURE);
346 flowinfo = (uint_t)i;
347 break;
349 case 'I':
350 stats = B_TRUE;
351 parse_interval(optarg);
352 break;
354 case 'i':
356 * this can accept interface index, interface name, and
357 * address configured on the interface
359 moptions |= MULTICAST_IF;
360 out_if.str = optarg;
362 if (inet_pton(AF_INET6, optarg, &out_if.id.addr) > 0) {
363 out_if.id_type = IF_ADDR6;
364 } else if (inet_pton(AF_INET, optarg,
365 &out_if.id.addr) > 0) {
366 out_if.id_type = IF_ADDR;
367 } else if (strcmp(optarg, "0") == 0) {
368 out_if.id_type = IF_INDEX;
369 out_if.id.index = 0;
370 } else if ((out_if.id.index = atoi(optarg)) != 0) {
371 out_if.id_type = IF_INDEX;
372 } else {
373 out_if.id.name = optarg;
374 out_if.id_type = IF_NAME;
376 break;
378 case 'L':
379 moptions |= MULTICAST_NOLOOP;
380 break;
382 case 'l':
383 send_reply = B_TRUE;
384 strict = B_FALSE;
385 break;
387 case 'n':
388 nflag = B_TRUE;
389 break;
391 case 'P':
392 settos = B_TRUE;
393 i = int_arg(optarg, "type-of-service");
394 if (i > MAX_TOS) {
395 Fprintf(stderr, "%s: tos value %d out of "
396 "range\n", progname, i);
397 exit(EXIT_FAILURE);
399 tos = (ushort_t)i;
400 break;
402 case 'p':
403 i = int_arg(optarg, "port number");
404 if (i > MAX_PORT) {
405 Fprintf(stderr, "%s: port number %d out of "
406 "range\n", progname, i);
407 exit(EXIT_FAILURE);
409 dest_port = (ushort_t)i;
410 break;
412 case 'r':
413 options |= SO_DONTROUTE;
414 break;
416 case 'R':
417 rr_option = B_TRUE;
418 break;
420 case 'S':
421 send_reply = B_TRUE;
422 strict = B_TRUE;
423 break;
425 case 's':
426 stats = B_TRUE;
427 break;
429 case 'T':
430 ts_option = B_TRUE;
431 break;
433 case 't':
434 moptions |= MULTICAST_TTL;
435 hoplimit = int_arg(optarg, "ttl");
436 if (hoplimit > MAXTTL) {
437 Fprintf(stderr, "%s: ttl %d out of range\n",
438 progname, hoplimit);
439 exit(EXIT_FAILURE);
441 break;
443 case 'U':
444 use_udp = B_TRUE;
445 use_icmp_ts = B_FALSE;
446 break;
448 case 'v':
449 verbose = B_TRUE;
450 break;
452 * 'x' and 'X' has been undocumented flags for source routing.
453 * Now we document loose source routing with the new flag 'g',
454 * which is same as in traceroute. We still keep x/X as
455 * as undocumented. 'G', which is for strict source routing is
456 * also undocumented.
458 case 'x':
459 case 'g':
460 strict = B_FALSE;
461 if (num_gw > MAXMAX_GWS) {
462 Fprintf(stderr, "%s: too many gateways\n",
463 progname);
464 exit(EXIT_FAILURE);
466 gw_list[num_gw++] = optarg;
467 break;
469 case 'X':
470 case 'G':
471 strict = B_TRUE;
472 if (num_gw > MAXMAX_GWS) {
473 Fprintf(stderr, "%s: too many gateways\n",
474 progname);
475 exit(EXIT_FAILURE);
477 gw_list[num_gw++] = optarg;
478 break;
480 case 'N':
481 if (nexthop != NULL) {
482 Fprintf(stderr, "%s: only one next hop gateway"
483 " allowed\n", progname);
484 exit(EXIT_FAILURE);
486 nexthop = optarg;
487 break;
489 case 'Y':
490 use_icmp_ts = B_TRUE;
491 use_udp = B_FALSE;
492 break;
494 case '0':
495 case '1':
496 case '2':
497 case '3':
498 ts_flag = (char)c - '0';
499 break;
501 case '?':
502 usage(progname);
503 exit(EXIT_FAILURE);
504 break;
506 default:
507 usage(progname);
508 exit(EXIT_FAILURE);
509 break;
513 if (optind >= argc) {
514 usage(progname);
515 exit(EXIT_FAILURE);
519 * send_reply, which sends the probe packet back to itself
520 * doesn't work with UDP
522 if (use_udp)
523 send_reply = B_FALSE;
525 if (getenv("MACHINE_THAT_GOES_PING") != NULL)
526 stats = B_TRUE;
528 targethost = argv[optind];
529 optind++;
530 if (optind < argc) {
531 if (stats) {
532 datalen = int_arg(argv[optind], "data size");
533 optind++;
534 if (optind < argc) {
535 npackets = int_arg(argv[optind],
536 "packet count");
537 if (npackets < 1) {
538 Fprintf(stderr, "%s: packet count %d "
539 "out of range\n", progname,
540 npackets);
541 exit(EXIT_FAILURE);
544 } else {
545 timeout = int_arg(argv[optind], "timeout");
550 * Let's prepare sockaddr_in* structures, cause we might need both of
551 * them.
553 bzero((char *)&to, sizeof (struct sockaddr_in));
554 to.sin_family = AF_INET;
556 bzero((char *)&to6, sizeof (struct sockaddr_in6));
557 to6.sin6_family = AF_INET6;
558 to6.sin6_flowinfo = htonl((class << 20) | flowinfo);
560 if (stats)
561 (void) sigset(SIGINT, finish);
563 ident = (int)getpid() & 0xFFFF;
565 /* resolve the hostnames */
566 resolve_nodes(&ai_dst, &ai_nexthop, &src_addr_list);
569 * We should make sure datalen is reasonable.
570 * IP_MAXPACKET >= IPv4/IPv6 header length +
571 * IPv4 options/IPv6 routing header length +
572 * ICMP/ICMP6/UDP header length +
573 * datalen
576 if (family_input == AF_INET6 ||
577 (family_input == AF_UNSPEC && num_v6 != 0)) {
578 size_t exthdr_len = 0;
580 if (send_reply) {
581 exthdr_len = sizeof (struct ip6_rthdr0) +
582 2 * num_gw * sizeof (struct in6_addr);
583 } else if (num_gw > 0) {
584 exthdr_len = sizeof (struct ip6_rthdr0) +
585 num_gw * sizeof (struct in6_addr);
589 * Size of ICMP6 header and UDP header are the same. Let's
590 * use ICMP6_MINLEN.
592 if (datalen > (IP_MAXPACKET - (sizeof (struct ip6_hdr) +
593 exthdr_len + ICMP6_MINLEN))) {
594 Fprintf(stderr,
595 "%s: data size too large for IPv6 packet\n",
596 progname);
597 num_v6 = 0;
601 if (family_input == AF_INET ||
602 (family_input == AF_UNSPEC && num_v4 != 0)) {
603 size_t opt_len = 0;
605 if (send_reply) {
607 * Includes 3 bytes code+ptr+len, the intermediate
608 * gateways, the actual and the effective target.
610 opt_len = 3 +
611 (2 * num_gw + 2) * sizeof (struct in_addr);
612 } else if (num_gw > 0) {
613 opt_len = 3 + (num_gw + 1) * sizeof (struct in_addr);
616 if (rr_option) {
617 opt_len = MAX_IPOPTLEN;
618 } else if (ts_option) {
619 if ((ts_flag & 0x0f) <= IPOPT_TS_TSANDADDR) {
620 opt_len = MAX_IPOPTLEN;
621 } else {
622 opt_len += IPOPT_MINOFF +
623 2 * sizeof (struct ipt_ta);
625 * Note: BSD/4.X is broken in their check so we
626 * have to bump up this number by at least one.
628 opt_len++;
632 /* Round up to 4 byte boundary */
633 if (opt_len & 0x3)
634 opt_len = (opt_len & ~0x3) + 4;
636 if (datalen > (IP_MAXPACKET - (sizeof (struct ip) + opt_len +
637 ICMP_MINLEN))) {
638 Fprintf(stderr,
639 "%s: data size too large for IPv4 packet\n",
640 progname);
641 num_v4 = 0;
645 if (num_v4 == 0 && num_v6 == 0) {
646 exit(EXIT_FAILURE);
649 /* setup the sockets */
650 if (num_v6 != 0) {
651 if (!setup_socket(AF_INET6, &send_sock6, &recv_sock6,
652 &if_index, &udp_src_port6, ai_nexthop))
653 exit(EXIT_FAILURE);
656 if (num_v4 != 0) {
657 if (!setup_socket(AF_INET, &send_sock, &recv_sock, &if_index,
658 &udp_src_port, ai_nexthop))
659 exit(EXIT_FAILURE);
662 __priv_relinquish();
665 * If sending back to ourself, add the mirror image of current
666 * gateways, so that the probes travel to and from the target
667 * by visiting the same gateways in reverse order.
669 if (send_reply) {
670 if (num_v6 != 0)
671 mirror_gws(gw_IP_list6, AF_INET6);
672 if (num_v4 != 0)
673 mirror_gws(gw_IP_list, AF_INET);
675 /* We add 1 because we put the target as the middle gateway */
676 eff_num_gw = 2 * num_gw + 1;
678 } else {
679 eff_num_gw = num_gw;
682 targetaddr_list = build_targetaddr_list(ai_dst, src_addr_list);
683 current_targetaddr = targetaddr_list;
686 * Set the starting_seq_num for the first targetaddr.
687 * If we are sending ICMP Echo Requests, the sequence number is same as
688 * ICMP sequence number, and it starts from zero. If we are sending UDP
689 * packets, the sequence number is the destination UDP port number,
690 * which starts from dest_port. At each probe, this sequence number is
691 * incremented by one.
692 * We set the starting_seq_num for first targetaddr here. The
693 * following ones will be set by looking at where we left with the last
694 * targetaddr.
696 current_targetaddr->starting_seq_num = use_udp ? dest_port : 0;
698 if (stats) {
699 if (probe_all || !nflag) {
700 Printf("PING %s: %d data bytes\n", targethost, datalen);
701 } else {
702 if (ai_dst->ai_family == AF_INET) {
703 (void) inet_ntop(AF_INET,
704 &((struct sockaddr_in *)(void *)
705 ai_dst->ai_addr)->sin_addr,
706 abuf, sizeof (abuf));
707 } else {
708 (void) inet_ntop(AF_INET6,
709 &((struct sockaddr_in6 *)(void *)
710 ai_dst->ai_addr)->sin6_addr,
711 abuf, sizeof (abuf));
713 Printf("PING %s (%s): %d data bytes\n",
714 targethost, abuf, datalen);
718 /* Create our timer for future use */
719 if (timer_create(CLOCK_REALTIME, NULL, &timer) != 0) {
720 Fprintf(stderr, "%s: failed to create timer: %s\n",
721 progname, strerror(errno));
722 exit(EXIT_FAILURE);
726 * Finally start up the name services warning thread.
728 if (thr_create(NULL, 0, ns_warning_thr, NULL,
729 THR_DETACHED | THR_DAEMON, NULL) != 0) {
730 Fprintf(stderr, "%s: failed to create name services "
731 "thread: %s\n", progname, strerror(errno));
732 exit(EXIT_FAILURE);
735 /* Let's get things going */
736 send_scheduled_probe();
738 /* SIGALRM is used to send the next scheduled probe */
739 (void) sigset(SIGALRM, sigalrm_handler);
740 schedule_sigalrm();
743 * From now on, we'll always be listening to ICMP packets. As SIGALRM
744 * comes in, sigalrm_handler() will be invoked and send another
745 * probe.
747 recv_icmp_packet(ai_dst, recv_sock6, recv_sock, udp_src_port6,
748 udp_src_port);
750 return (EXIT_SUCCESS); /* should never come here */
754 * Build the target IP address list. Use command line options and
755 * name lookup results returned from name server to determine which addresses
756 * to probe, how many times, in which order.
758 static struct targetaddr *
759 build_targetaddr_list(struct addrinfo *ai_dst, union any_in_addr *src_addr_list)
761 struct targetaddr *head = NULL;
762 struct targetaddr *targetaddr;
763 struct targetaddr **nextp;
764 int num_dst;
765 int i;
766 struct addrinfo *aip;
768 aip = ai_dst;
769 if (probe_all)
770 num_dst = num_v4 + num_v6;
771 else
772 num_dst = 1;
773 num_targetaddrs = num_dst;
774 nextp = &head;
775 for (aip = ai_dst, i = 0; aip != NULL; aip = aip->ai_next, i++) {
776 if (aip->ai_family == AF_INET && num_v4 != 0) {
777 targetaddr = create_targetaddr_item(aip->ai_family,
778 (union any_in_addr *)
779 /* LINTED E_BAD_PTR_CAST_ALIGN */
780 &((struct sockaddr_in *)
781 aip->ai_addr)->sin_addr,
782 &src_addr_list[i]);
783 } else if (aip->ai_family == AF_INET6 && num_v6 != 0) {
784 targetaddr = create_targetaddr_item(aip->ai_family,
785 (union any_in_addr *)
786 /* LINTED E_BAD_PTR_CAST_ALIGN */
787 &((struct sockaddr_in6 *)
788 aip->ai_addr)->sin6_addr,
789 &src_addr_list[i]);
790 } else {
791 continue;
793 *nextp = targetaddr;
794 nextp = &targetaddr->next;
795 if (num_targetaddrs == 1)
796 break;
798 if (npackets == 0 && stats)
799 *nextp = head; /* keep going indefinitely */
801 return (head);
805 * Given an address family, dst and src addresses, by also looking at the
806 * options provided at the command line, this function creates a targetaddr
807 * to be linked with others, forming a global targetaddr list. Each targetaddr
808 * item contains information about probes sent to a specific IP address.
810 static struct targetaddr *
811 create_targetaddr_item(int family, union any_in_addr *dst_addr,
812 union any_in_addr *src_addr)
814 struct targetaddr *targetaddr;
816 targetaddr = (struct targetaddr *)malloc(sizeof (struct targetaddr));
817 if (targetaddr == NULL) {
818 Fprintf(stderr, "%s: malloc %s\n", progname, strerror(errno));
819 exit(EXIT_FAILURE);
821 targetaddr->family = family;
822 targetaddr->dst_addr = *dst_addr;
823 targetaddr->src_addr = *src_addr;
824 if (stats) {
826 * npackets is only defined if we are in stats mode.
827 * npackets determines how many probes to send to each target
828 * IP address. npackets == 0 means send only 1 and move on to
829 * next target IP.
831 if (npackets > 0)
832 targetaddr->num_probes = npackets;
833 else
834 targetaddr->num_probes = 1;
835 } else {
836 targetaddr->num_probes = timeout;
838 targetaddr->num_sent = 0;
839 targetaddr->got_reply = B_FALSE;
840 targetaddr->probing_done = B_FALSE;
841 targetaddr->starting_seq_num = 0; /* actual value will be set later */
842 targetaddr->next = NULL; /* actual value will be set later */
844 return (targetaddr);
848 * print "unknown host" message
850 static void
851 print_unknown_host_msg(const char *protocol, const char *hostname)
853 Fprintf(stderr, "%s: unknown%s host %s\n", progname, protocol,
854 hostname);
858 * Resolve hostnames for the target host and gateways. Also, determine source
859 * addresses to use for each target address.
861 static void
862 resolve_nodes(struct addrinfo **ai_dstp, struct addrinfo **ai_nexthopp,
863 union any_in_addr **src_addr_listp)
865 struct addrinfo *ai_dst = NULL;
866 struct addrinfo *ai_nexthop = NULL;
867 struct addrinfo *aip = NULL;
868 union any_in_addr *src_addr_list = NULL;
869 int num_resolved_gw = 0;
870 int num_resolved_gw6 = 0;
872 get_hostinfo(targethost, family_input, &ai_dst);
873 if (ai_dst == NULL) {
874 print_unknown_host_msg("", targethost);
875 exit(EXIT_FAILURE);
877 if (nexthop != NULL) {
878 get_hostinfo(nexthop, family_input, &ai_nexthop);
879 if (ai_nexthop == NULL) {
880 print_unknown_host_msg("", nexthop);
881 exit(EXIT_FAILURE);
884 /* Get a count of the v4 & v6 addresses */
885 for (aip = ai_dst; aip != NULL; aip = aip->ai_next) {
886 switch (aip->ai_family) {
887 case AF_INET:
888 num_v4++;
889 break;
890 case AF_INET6:
891 num_v6++;
892 break;
896 if (family_input == AF_UNSPEC && !probe_all) {
897 family_input = ai_dst->ai_family;
900 /* resolve gateways */
901 if (num_gw > 0) {
902 get_gwaddrs(gw_list, family_input, gw_IP_list, gw_IP_list6,
903 &num_resolved_gw, &num_resolved_gw6);
905 /* we couldn't resolve a gateway as an IPv6 host */
906 if (num_resolved_gw6 != num_gw && num_v6 != 0 &&
907 (family_input == AF_INET6 || family_input == AF_UNSPEC)) {
908 print_unknown_host_msg(" IPv6",
909 gw_list[num_resolved_gw6]);
910 num_v6 = 0;
913 /* we couldn't resolve a gateway as an IPv4 host */
914 if (num_resolved_gw != num_gw && num_v4 != 0 &&
915 (family_input == AF_INET || family_input == AF_UNSPEC)) {
916 print_unknown_host_msg(" IPv4",
917 gw_list[num_resolved_gw]);
918 num_v4 = 0;
922 if (num_v4 == 0 && num_v6 == 0)
923 exit(EXIT_FAILURE);
925 select_all_src_addrs(&src_addr_list, ai_dst, gw_IP_list, gw_IP_list6);
926 *ai_dstp = ai_dst;
927 *ai_nexthopp = ai_nexthop;
928 *src_addr_listp = src_addr_list;
932 * Resolve the gateway names, splitting results into v4 and v6 lists.
933 * Gateway addresses are added to the appropriate passed-in array; the
934 * number of resolved gateways for each af is returned in resolved[6].
935 * Assumes that passed-in arrays are large enough for MAX_GWS[6] addrs
936 * and resolved[6] ptrs are non-null; ignores array and counter if the
937 * address family param makes them irrelevant.
939 static void
940 get_gwaddrs(char **gw_list, int family, union any_in_addr *gwIPlist,
941 union any_in_addr *gwIPlist6, int *resolved, int *resolved6)
943 int i;
944 boolean_t check_v4 = B_TRUE, check_v6 = B_TRUE;
945 struct addrinfo *ai = NULL;
946 struct addrinfo *aip = NULL;
948 *resolved = *resolved6 = 0;
949 switch (family) {
950 case AF_UNSPEC:
951 break;
952 case AF_INET:
953 check_v6 = B_FALSE;
954 break;
955 case AF_INET6:
956 check_v4 = B_FALSE;
957 break;
958 default:
959 return;
962 if (check_v4 && num_gw >= MAX_GWS) {
963 check_v4 = B_FALSE;
964 Fprintf(stderr, "%s: too many IPv4 gateways\n", progname);
966 if (check_v6 && num_gw > MAX_GWS6) {
967 check_v6 = B_FALSE;
968 Fprintf(stderr, "%s: too many IPv6 gateways\n", progname);
971 for (i = 0; i < num_gw; i++) {
972 if (!check_v4 && !check_v6)
973 return;
974 get_hostinfo(gw_list[i], family, &ai);
975 if (ai == NULL)
976 return;
977 if (check_v4 && num_v4 != 0) {
978 for (aip = ai; aip != NULL; aip = aip->ai_next) {
979 if (aip->ai_family == AF_INET) {
980 /* LINTED E_BAD_PTR_CAST_ALIGN */
981 bcopy(&((struct sockaddr_in *)
982 aip->ai_addr)->sin_addr,
983 &gwIPlist[i].addr,
984 aip->ai_addrlen);
985 (*resolved)++;
986 break;
989 } else if (check_v4) {
990 check_v4 = B_FALSE;
992 if (check_v6 && num_v6 != 0) {
993 for (aip = ai; aip != NULL; aip = aip->ai_next) {
994 if (aip->ai_family == AF_INET6) {
995 /* LINTED E_BAD_PTR_CAST_ALIGN */
996 bcopy(&((struct sockaddr_in6 *)
997 aip->ai_addr)->sin6_addr,
998 &gwIPlist6[i].addr6,
999 aip->ai_addrlen);
1000 (*resolved6)++;
1001 break;
1004 } else if (check_v6) {
1005 check_v6 = B_FALSE;
1008 freeaddrinfo(ai);
1012 * Given the list of gateways, extends the list with its mirror image. This is
1013 * used when -l/-S is used. The middle gateway will be the target address. We'll
1014 * leave it blank for now.
1016 static void
1017 mirror_gws(union any_in_addr *gwIPlist, int family)
1019 int effective_num_gw;
1020 int i;
1022 /* We add 1 because we put the target as the middle gateway */
1023 effective_num_gw = 2 * num_gw + 1;
1025 if ((family == AF_INET && effective_num_gw >= MAX_GWS) ||
1026 (family == AF_INET6 && effective_num_gw > MAX_GWS6)) {
1027 Fprintf(stderr, "%s: too many %s gateways\n",
1028 progname, (family == AF_INET) ? "IPv4" : "IPv6");
1029 exit(EXIT_FAILURE);
1032 for (i = 0; i < num_gw; i++)
1033 gwIPlist[num_gw + i + 1].addr6 = gwIPlist[num_gw - i - 1].addr6;
1037 * Given IP address or hostname, return addrinfo list.
1038 * Assumes that addrinfo ** ptr is non-null.
1040 static void
1041 get_hostinfo(char *host, int family, struct addrinfo **aipp)
1043 struct addrinfo hints, *ai;
1044 struct in6_addr addr6;
1045 struct in_addr addr;
1046 boolean_t broadcast; /* is this 255.255.255.255? */
1047 char tmp_buf[INET6_ADDRSTRLEN];
1048 int rc;
1050 /* check if broadcast */
1051 if (strcmp(host, "255.255.255.255") == 0)
1052 broadcast = B_TRUE;
1053 else
1054 broadcast = B_FALSE;
1056 /* check if IPv4-mapped address or broadcast */
1057 if (((inet_pton(AF_INET6, host, &addr6) > 0) &&
1058 IN6_IS_ADDR_V4MAPPED(&addr6)) || broadcast) {
1059 if (!broadcast) {
1061 * Peel off the "mapping" stuff, leaving 32 bit IPv4
1062 * address.
1064 IN6_V4MAPPED_TO_INADDR(&addr6, &addr);
1066 /* convert it back to a string */
1067 (void) inet_ntop(AF_INET, (void *)&addr, tmp_buf,
1068 sizeof (tmp_buf));
1070 * Now the host is an IPv4 address.
1071 * Since it previously was a v4 mapped v6 address
1072 * we can be sure that the size of buffer 'host'
1073 * is large enough to contain the associated v4
1074 * address and so we don't need to use a strn/lcpy
1075 * here.
1077 (void) strcpy(host, tmp_buf);
1080 * If it's a broadcast address, it cannot be an IPv6 address.
1081 * Also, if it's a mapped address, we convert it into IPv4
1082 * address because ping will send and receive IPv4 packets for
1083 * that address. Therefore, it's a failure case to ask
1084 * get_hostinfo() to treat a broadcast or a mapped address
1085 * as an IPv6 address.
1087 if (family == AF_INET6) {
1088 return;
1092 (void) memset(&hints, 0, sizeof (hints));
1093 hints.ai_family = family;
1094 hints.ai_flags = AI_ADDRCONFIG;
1095 rc = getaddrinfo(host, NULL, &hints, &ai);
1096 if (rc != 0) {
1097 if (rc != EAI_NONAME)
1098 Fprintf(stderr, "%s: getaddrinfo: %s\n", progname,
1099 gai_strerror(rc));
1100 return;
1102 *aipp = ai;
1106 * For each IP address of the target host, determine a source address to use.
1108 static void
1109 select_all_src_addrs(union any_in_addr **src_addr_list, struct addrinfo *ai,
1110 union any_in_addr *gwv4, union any_in_addr *gwv6)
1112 union any_in_addr *list;
1113 struct addrinfo *aip;
1114 int num_dst = 1;
1115 int i;
1117 if (probe_all) {
1118 for (aip = ai; aip->ai_next != NULL; aip = aip->ai_next)
1119 num_dst++;
1122 list = calloc((size_t)num_dst, sizeof (union any_in_addr));
1123 if (list == NULL) {
1124 Fprintf(stderr, "%s: calloc: %s\n", progname, strerror(errno));
1125 exit(EXIT_FAILURE);
1129 * If there's a gateway, a routing header as a consequence, our kernel
1130 * picks the source address based on the first hop address, rather than
1131 * final destination address.
1133 if (num_gw > 0) {
1134 if (ai->ai_family == AF_INET)
1135 select_src_addr(gwv4, ai->ai_family, &list[0]);
1136 else
1137 select_src_addr(gwv6, ai->ai_family, &list[0]);
1139 * Since the first gateway address is fixed, we'll use the same
1140 * src address for every different final destination address
1141 * we send to.
1143 for (i = 1; i < num_dst; i++)
1144 list[i] = list[0];
1145 } else {
1147 * Although something like 'ping -l host' results in a routing
1148 * header, the first gateway address is the target host's
1149 * address. Therefore, as far as src address selection goes,
1150 * the result is same as having no routing header.
1152 for (i = 0, aip = ai; i < num_dst && aip != NULL;
1153 i++, aip = aip->ai_next) {
1154 if (aip->ai_family == AF_INET) {
1155 if (num_v4 != 0) {
1156 select_src_addr((union any_in_addr *)
1157 /* LINTED E_BAD_PTR_CAST_ALIGN */
1158 &((struct sockaddr_in *)
1159 aip->ai_addr)->sin_addr,
1160 aip->ai_family,
1161 &list[i]);
1163 } else {
1164 if (num_v6 != 0) {
1165 select_src_addr((union any_in_addr *)
1166 /* LINTED E_BAD_PTR_CAST_ALIGN */
1167 &((struct sockaddr_in6 *)
1168 aip->ai_addr)->sin6_addr,
1169 aip->ai_family,
1170 &list[i]);
1176 *src_addr_list = list;
1180 * For a given destination address, determine a source address to use.
1181 * Returns wildcard address if it cannot determine the source address.
1183 static void
1184 select_src_addr(union any_in_addr *dst_addr, int family,
1185 union any_in_addr *src_addr)
1187 struct sockaddr *sock;
1188 struct sockaddr_in *sin = NULL;
1189 struct sockaddr_in6 *sin6 = NULL;
1190 int tmp_fd;
1191 size_t sock_len;
1193 sock = (struct sockaddr *)malloc(sizeof (struct sockaddr_in6));
1194 if (sock == NULL) {
1195 Fprintf(stderr, "%s: malloc: %s\n", progname, strerror(errno));
1196 exit(EXIT_FAILURE);
1198 (void) bzero(sock, sizeof (struct sockaddr_in6));
1200 if (family == AF_INET) {
1201 /* LINTED E_BAD_PTR_CAST_ALIGN */
1202 sin = (struct sockaddr_in *)sock;
1203 sin->sin_family = AF_INET;
1204 sin->sin_addr = dst_addr->addr;
1205 sin->sin_port = IPPORT_ECHO; /* port shouldn't be 0 */
1206 sock_len = sizeof (struct sockaddr_in);
1207 } else {
1208 /* LINTED E_BAD_PTR_CAST_ALIGN */
1209 sin6 = (struct sockaddr_in6 *)sock;
1210 sin6->sin6_family = AF_INET6;
1211 sin6->sin6_addr = dst_addr->addr6;
1212 sin6->sin6_port = IPPORT_ECHO; /* port shouldn't be 0 */
1213 sock_len = sizeof (struct sockaddr_in6);
1216 /* open a UDP socket */
1217 if ((tmp_fd = socket(family, SOCK_DGRAM, 0)) < 0) {
1218 Fprintf(stderr, "%s: udp socket: %s\n", progname,
1219 strerror(errno));
1220 exit(EXIT_FAILURE);
1223 /* connect it */
1224 if (connect(tmp_fd, sock, sock_len) < 0) {
1226 * If there's no route to the destination, this connect() call
1227 * fails. We just return all-zero (wildcard) as the source
1228 * address, so that user can get to see "no route to dest"
1229 * message, as it'll try to send the probe packet out and will
1230 * receive ICMP unreachable.
1232 if (family == AF_INET)
1233 src_addr->addr.s_addr = INADDR_ANY;
1234 else
1235 src_addr->addr6 = in6addr_any;
1236 free(sock);
1237 return;
1240 /* get the local sock info */
1241 if (getsockname(tmp_fd, sock, &sock_len) < 0) {
1242 Fprintf(stderr, "%s: getsockname: %s\n", progname,
1243 strerror(errno));
1244 exit(EXIT_FAILURE);
1247 if (family == AF_INET) {
1248 assert(sin != NULL);
1249 src_addr->addr = sin->sin_addr;
1250 } else {
1251 assert(sin6 != NULL);
1252 src_addr->addr6 = sin6->sin6_addr;
1255 (void) close(tmp_fd);
1256 free(sock);
1260 * Set the IP_NEXTHOP/IPV6_NEXTHOP socket option.
1261 * exits on failure
1263 static void
1264 set_nexthop(int family, struct addrinfo *ai_nexthop, int sock)
1266 if (family == AF_INET) {
1267 ipaddr_t nh;
1269 /* LINTED E_BAD_PTR_CAST_ALIGN */
1270 nh = ((struct sockaddr_in *)ai_nexthop->
1271 ai_addr)->sin_addr.s_addr;
1273 /* now we need the sys_ip_config privilege */
1274 (void) __priv_bracket(PRIV_ON);
1275 if (setsockopt(sock, IPPROTO_IP, IP_NEXTHOP,
1276 &nh, sizeof (ipaddr_t)) < 0) {
1277 if (errno == EPERM)
1278 Fprintf(stderr, "%s: Insufficient privilege "
1279 "to specify IPv4 nexthop router.\n",
1280 progname);
1281 else
1282 Fprintf(stderr, "%s: setsockopt %s\n",
1283 progname, strerror(errno));
1284 exit(EXIT_FAILURE);
1286 (void) __priv_bracket(PRIV_OFF);
1287 /* revert to non-privileged user */
1288 } else {
1289 struct sockaddr_in6 *nh;
1291 /* LINTED E_BAD_PTR_CAST_ALIGN */
1292 nh = (struct sockaddr_in6 *)ai_nexthop->
1293 ai_addr;
1295 if (setsockopt(sock, IPPROTO_IPV6, IPV6_NEXTHOP,
1296 nh, sizeof (struct sockaddr_in6)) < 0) {
1297 Fprintf(stderr, "%s: setsockopt %s\n",
1298 progname, strerror(errno));
1299 exit(EXIT_FAILURE);
1305 * Setup the socket for the given address family.
1306 * Returns B_TRUE on success, B_FALSE on failure. Failure is the case when no
1307 * interface can be found, or the specified interface (-i) is not found. On
1308 * library call failures, it exit()s.
1310 static boolean_t
1311 setup_socket(int family, int *send_sockp, int *recv_sockp, int *if_index,
1312 ushort_t *udp_src_port, struct addrinfo *ai_nexthop)
1314 int send_sock;
1315 int recv_sock;
1316 struct sockaddr_in6 sin6;
1317 struct sockaddr_in sin;
1318 struct sockaddr *sp;
1319 struct ipsec_req req;
1320 size_t slen;
1321 int on = 1;
1322 uchar_t char_op;
1323 int int_op;
1325 /* now we need the net_icmpaccess privilege */
1326 (void) __priv_bracket(PRIV_ON);
1328 recv_sock = socket(family, SOCK_RAW,
1329 (family == AF_INET) ? IPPROTO_ICMP : IPPROTO_ICMPV6);
1331 if (recv_sock < 0) {
1332 Fprintf(stderr, "%s: socket %s\n", progname, strerror(errno));
1333 exit(EXIT_FAILURE);
1336 /* revert to non-privileged user after opening sockets */
1337 (void) __priv_bracket(PRIV_OFF);
1339 if (bypass) {
1340 (void) memset(&req, 0, sizeof (req));
1341 req.ipsr_ah_req = IPSEC_PREF_NEVER;
1342 req.ipsr_esp_req = IPSEC_PREF_NEVER;
1344 if (setsockopt(recv_sock, (family == AF_INET) ? IPPROTO_IP :
1345 IPPROTO_IPV6, IP_SEC_OPT, &req, sizeof (req)) < 0) {
1346 switch (errno) {
1347 case EPROTONOSUPPORT:
1349 * No IPsec subsystem or policy loaded.
1350 * Bypass implicitly allowed.
1352 break;
1353 case EPERM:
1354 Fprintf(stderr, "%s: Insufficient privilege "
1355 "to bypass IPsec policy.\n", progname);
1356 exit(EXIT_FAILURE);
1357 break;
1358 default:
1359 Fprintf(stderr, "%s: setsockopt %s\n", progname,
1360 strerror(errno));
1361 exit(EXIT_FAILURE);
1362 break;
1368 * We always receive on raw icmp socket. But the sending socket can be
1369 * raw icmp or udp, depending on the use of -U flag.
1371 if (use_udp) {
1372 send_sock = socket(family, SOCK_DGRAM, IPPROTO_UDP);
1373 if (send_sock < 0) {
1374 Fprintf(stderr, "%s: socket %s\n", progname,
1375 strerror(errno));
1376 exit(EXIT_FAILURE);
1379 if (bypass) {
1380 if (setsockopt(send_sock, (family == AF_INET) ?
1381 IPPROTO_IP : IPPROTO_IPV6, IP_SEC_OPT, &req,
1382 sizeof (req)) < 0) {
1383 switch (errno) {
1384 case EPROTONOSUPPORT:
1386 * No IPsec subsystem or policy loaded.
1387 * Bypass implicitly allowed.
1389 break;
1390 case EPERM:
1391 Fprintf(stderr, "%s: Insufficient "
1392 "privilege to bypass IPsec "
1393 "policy.\n", progname);
1394 exit(EXIT_FAILURE);
1395 break;
1396 default:
1397 Fprintf(stderr, "%s: setsockopt %s\n",
1398 progname, strerror(errno));
1399 exit(EXIT_FAILURE);
1400 break;
1406 * In order to distinguish replies to our UDP probes from
1407 * other pings', we need to know our source port number.
1409 if (family == AF_INET) {
1410 sp = (struct sockaddr *)&sin;
1411 slen = sizeof (sin);
1412 } else {
1413 sp = (struct sockaddr *)&sin6;
1414 slen = sizeof (sin6);
1416 bzero(sp, slen);
1417 sp->sa_family = family;
1419 /* Let's bind() send_sock to wildcard address and port */
1420 if (bind(send_sock, sp, slen) < 0) {
1421 Fprintf(stderr, "%s: bind %s\n", progname,
1422 strerror(errno));
1423 exit(EXIT_FAILURE);
1426 /* .... and see what port kernel picked for us */
1427 if (getsockname(send_sock, sp, &slen) < 0) {
1428 Fprintf(stderr, "%s: getsockname %s\n", progname,
1429 strerror(errno));
1430 exit(EXIT_FAILURE);
1432 *udp_src_port = (family == AF_INET) ? sin.sin_port :
1433 sin6.sin6_port;
1434 } else {
1435 send_sock = recv_sock;
1438 if (nexthop != NULL)
1439 set_nexthop(family, ai_nexthop, send_sock);
1441 int_op = 48 * 1024;
1442 if (int_op < datalen)
1443 int_op = datalen;
1444 if (setsockopt(recv_sock, SOL_SOCKET, SO_RCVBUF, (char *)&int_op,
1445 sizeof (int_op)) == -1) {
1446 Fprintf(stderr, "%s: setsockopt SO_RCVBUF %s\n", progname,
1447 strerror(errno));
1448 exit(EXIT_FAILURE);
1451 if (setsockopt(send_sock, SOL_SOCKET, SO_SNDBUF, (char *)&int_op,
1452 sizeof (int_op)) == -1) {
1453 Fprintf(stderr, "%s: setsockopt SO_SNDBUF %s\n", progname,
1454 strerror(errno));
1455 exit(EXIT_FAILURE);
1458 if (options & SO_DEBUG) {
1459 if (setsockopt(send_sock, SOL_SOCKET, SO_DEBUG, (char *)&on,
1460 sizeof (on)) == -1) {
1461 Fprintf(stderr, "%s: setsockopt SO_DEBUG %s\n",
1462 progname, strerror(errno));
1463 exit(EXIT_FAILURE);
1467 if (options & SO_DONTROUTE) {
1468 if (setsockopt(send_sock, SOL_SOCKET, SO_DONTROUTE, (char *)&on,
1469 sizeof (on)) == -1) {
1470 Fprintf(stderr, "%s: setsockopt SO_DONTROUTE %s\n",
1471 progname, strerror(errno));
1472 exit(EXIT_FAILURE);
1476 if (moptions & MULTICAST_NOLOOP) {
1477 if (family == AF_INET) {
1478 char_op = 0; /* used to turn off option */
1480 if (setsockopt(send_sock, IPPROTO_IP, IP_MULTICAST_LOOP,
1481 (char *)&char_op, sizeof (char_op)) == -1) {
1482 Fprintf(stderr, "%s: setsockopt "
1483 "IP_MULTICAST_NOLOOP %s\n", progname,
1484 strerror(errno));
1485 exit(EXIT_FAILURE);
1487 } else {
1488 int_op = 0; /* used to turn off option */
1490 if (setsockopt(send_sock, IPPROTO_IPV6,
1491 IPV6_MULTICAST_LOOP, (char *)&int_op,
1492 sizeof (int_op)) == -1) {
1493 Fprintf(stderr, "%s: setsockopt "
1494 "IPV6_MULTICAST_NOLOOP %s\n", progname,
1495 strerror(errno));
1496 exit(EXIT_FAILURE);
1501 if (moptions & MULTICAST_TTL) {
1502 char_op = hoplimit;
1504 /* Applies to unicast and multicast. */
1505 if (family == AF_INET) {
1506 if (setsockopt(send_sock, IPPROTO_IP, IP_MULTICAST_TTL,
1507 (char *)&char_op, sizeof (char)) == -1) {
1508 Fprintf(stderr, "%s: setsockopt "
1509 "IP_MULTICAST_TTL %s\n", progname,
1510 strerror(errno));
1511 exit(EXIT_FAILURE);
1513 if (setsockopt(send_sock, IPPROTO_IP, IP_TTL,
1514 (char *)&hoplimit, sizeof (hoplimit)) == -1) {
1515 Fprintf(stderr, "%s: setsockopt IP_TTL %s\n",
1516 progname, strerror(errno));
1517 exit(EXIT_FAILURE);
1521 * AF_INET6 case is handled in set_ancillary_data() function.
1522 * This is because when ancillary data is used (for routing
1523 * header and outgoing interface index), the hoplimit set using
1524 * setsockopt() is ignored.
1529 * did the user specify an interface?
1530 * Applies to unicast, broadcast and multicast.
1532 if (moptions & MULTICAST_IF) {
1533 struct ifaddrlist *al = NULL; /* interface list */
1534 struct ifaddrlist *my_if;
1535 char errbuf[ERRBUFSIZE];
1536 int num_ifs;
1537 int num_src_ifs; /* exclude down and loopback */
1538 int i;
1540 /* pull out the interface list */
1541 num_ifs = ifaddrlist(&al, family, LIFC_UNDER_IPMP, errbuf);
1542 if (num_ifs == -1) {
1543 Fprintf(stderr, "%s: %s\n", progname, errbuf);
1544 exit(EXIT_FAILURE);
1547 /* filter out down and loopback interfaces */
1548 num_src_ifs = 0;
1549 for (i = 0; i < num_ifs; i++) {
1550 if (!(al[i].flags & IFF_LOOPBACK) &&
1551 (al[i].flags & IFF_UP))
1552 num_src_ifs++;
1555 if (num_src_ifs == 0) {
1556 Fprintf(stderr, "%s: can't find any %s interface\n",
1557 progname, (family == AF_INET) ? "IPv4" : "IPv6");
1559 return (B_FALSE); /* failure */
1562 /* locate the specified interface */
1563 my_if = find_if(al, num_ifs);
1564 if (my_if == NULL) {
1565 Fprintf(stderr, "%s: %s is an invalid %s interface\n",
1566 progname, out_if.str,
1567 (family == AF_INET) ? "IPv4" : "IPv6");
1569 return (B_FALSE);
1572 if (family == AF_INET) {
1573 struct in_pktinfo pktinfo;
1575 if (setsockopt(send_sock, IPPROTO_IP, IP_MULTICAST_IF,
1576 (char *)&my_if->addr.addr,
1577 sizeof (struct in_addr)) == -1) {
1578 Fprintf(stderr, "%s: setsockopt "
1579 "IP_MULTICAST_IF %s\n", progname,
1580 strerror(errno));
1581 exit(EXIT_FAILURE);
1583 bzero(&pktinfo, sizeof (pktinfo));
1584 pktinfo.ipi_ifindex = my_if->index;
1585 if (setsockopt(send_sock, IPPROTO_IP, IP_PKTINFO,
1586 (char *)&pktinfo, sizeof (pktinfo)) == -1) {
1587 Fprintf(stderr, "%s: setsockopt "
1588 "IP_PKTINFO %s\n", progname,
1589 strerror(errno));
1590 exit(EXIT_FAILURE);
1592 } else {
1594 * the outgoing interface is set in set_ancillary_data()
1595 * function
1597 *if_index = my_if->index;
1600 free(al);
1603 if (settos && family == AF_INET) {
1604 int_op = tos;
1605 if (setsockopt(send_sock, IPPROTO_IP, IP_TOS, (char *)&int_op,
1606 sizeof (int_op)) == -1) {
1607 Fprintf(stderr, "%s: setsockopt IP_TOS %s\n",
1608 progname, strerror(errno));
1609 exit(EXIT_FAILURE);
1613 /* We enable or disable to not depend on the kernel default */
1614 if (family == AF_INET) {
1615 if (setsockopt(send_sock, IPPROTO_IP, IP_DONTFRAG,
1616 (char *)&dontfrag, sizeof (dontfrag)) == -1) {
1617 Fprintf(stderr, "%s: setsockopt IP_DONTFRAG %s\n",
1618 progname, strerror(errno));
1619 exit(EXIT_FAILURE);
1621 } else {
1622 if (setsockopt(send_sock, IPPROTO_IPV6, IPV6_DONTFRAG,
1623 (char *)&dontfrag, sizeof (dontfrag)) == -1) {
1624 Fprintf(stderr, "%s: setsockopt IPV6_DONTFRAG %s\n",
1625 progname, strerror(errno));
1626 exit(EXIT_FAILURE);
1630 /* receiving IPv6 extension headers in verbose mode */
1631 if (verbose && family == AF_INET6) {
1632 if (setsockopt(recv_sock, IPPROTO_IPV6, IPV6_RECVHOPOPTS,
1633 (char *)&on, sizeof (on)) == -1) {
1634 Fprintf(stderr, "%s: setsockopt IPV6_RECVHOPOPTS %s\n",
1635 progname, strerror(errno));
1636 exit(EXIT_FAILURE);
1639 if (setsockopt(recv_sock, IPPROTO_IPV6, IPV6_RECVDSTOPTS,
1640 (char *)&on, sizeof (on)) == -1) {
1641 Fprintf(stderr, "%s: setsockopt IPV6_RECVDSTOPTS %s\n",
1642 progname, strerror(errno));
1643 exit(EXIT_FAILURE);
1646 if (setsockopt(recv_sock, IPPROTO_IPV6, IPV6_RECVRTHDR,
1647 (char *)&on, sizeof (on)) == -1) {
1648 Fprintf(stderr, "%s: setsockopt IPV6_RECVRTHDR %s\n",
1649 progname, strerror(errno));
1650 exit(EXIT_FAILURE);
1654 /* Ensure that timestamping is requested on the receive socket */
1655 if (setsockopt(recv_sock, SOL_SOCKET, SO_TIMESTAMP,
1656 &on, sizeof (on)) == -1) {
1657 Fprintf(stderr, "%s: warning: timing accuracy diminished -- "
1658 "setsockopt SO_TIMESTAMP failed %s", progname,
1659 strerror(errno));
1662 *send_sockp = send_sock;
1663 *recv_sockp = recv_sock;
1665 /* successful */
1666 return (B_TRUE);
1670 * Pull out the record containing all the info about the interface specified by
1671 * `out_if'. Skips interfaces which are down or loopback.
1673 static struct ifaddrlist *
1674 find_if(struct ifaddrlist *al, int num_ifs)
1676 static struct ifaddrlist tmp_if;
1677 boolean_t found;
1678 int i;
1680 i = 0;
1681 found = B_FALSE;
1683 while (i < num_ifs && !found) {
1684 tmp_if = al[i];
1686 /* skip down or loopback interfaces */
1687 if ((tmp_if.flags & IFF_LOOPBACK) || !(tmp_if.flags & IFF_UP)) {
1688 i++;
1689 continue;
1692 /* the type of interface id is variable */
1693 switch (out_if.id_type) {
1694 case IF_INDEX:
1695 if (out_if.id.index == tmp_if.index)
1696 found = B_TRUE;
1697 break;
1699 case IF_NAME:
1700 if (strcmp(out_if.id.name, tmp_if.device) == 0)
1701 found = B_TRUE;
1702 break;
1704 case IF_ADDR:
1705 if (out_if.id.addr.addr.s_addr ==
1706 tmp_if.addr.addr.s_addr) {
1707 found = B_TRUE;
1709 break;
1711 case IF_ADDR6:
1712 if (IN6_ARE_ADDR_EQUAL(&out_if.id.addr.addr6,
1713 &tmp_if.addr.addr6)) {
1714 found = B_TRUE;
1716 break;
1718 default:
1719 break;
1722 i++;
1725 if (found)
1726 return (&tmp_if);
1727 else
1728 return (NULL);
1732 * Invoked by SIGALRM, sigalrm_handler() is, responsible for calling
1733 * send_scheduled_probe() to send next probe.
1735 void
1736 sigalrm_handler(void)
1739 * If we've been told that we're done, the timer should be cancelled
1740 * and not rescheduled, just return.
1742 if (timer_done == B_TRUE)
1743 return;
1746 * Guard against denial-of-service attacks. Make sure ping doesn't send
1747 * probes for every SIGALRM it receives in the case of errant SIGALRMs.
1748 * ping will ignore those which are received too soon (the smaller of
1749 * 0.5 sec and the ping interval, if in effect) after it sent the last
1750 * probe. We use gethrtime() instead of gettimeofday() because the
1751 * latter is not linear and is prone to resetting or drifting.
1753 if ((gethrtime() - t_last_probe_sent) < mintime) {
1754 return;
1756 send_scheduled_probe();
1757 schedule_sigalrm();
1761 * Schedule next SIGALRM.
1763 void
1764 schedule_sigalrm(void)
1766 int waittime;
1767 struct itimerspec it;
1769 bzero(&it, sizeof (struct itimerspec));
1770 if (npackets == 0 ||
1771 current_targetaddr->num_sent < current_targetaddr->num_probes) {
1772 it = interval;
1773 } else {
1774 if (current_targetaddr->got_reply) {
1775 waittime = 2 * tmax / MICROSEC;
1776 if (waittime == 0)
1777 waittime = 1;
1778 } else {
1779 waittime = MAX_WAIT;
1781 it.it_value.tv_sec = waittime;
1784 if (timer_settime(timer, TIMER_RELTIME, &it, NULL) != 0) {
1785 Fprintf(stderr, "%s: unexpected error updating time: %s\n",
1786 progname, strerror(errno));
1787 exit(EXIT_FAILURE);
1792 * Called by sigalrm_handler(), check_reply() or check_reply6(),
1793 * send_scheduled_probe() looks at the current_targetaddr and determines what
1794 * should be sent next and calls pinger().
1796 void
1797 send_scheduled_probe()
1799 static struct msghdr msg6;
1800 static boolean_t first_probe = B_TRUE;
1801 char tmp_buf[INET6_ADDRSTRLEN];
1804 * We are about to move to next targetaddr if it's either we sent
1805 * all the probes, or somebody set the probing_done flag to
1806 * B_TRUE prompting us to move on.
1808 if (current_targetaddr->num_sent == current_targetaddr->num_probes ||
1809 current_targetaddr->probing_done) {
1811 * is this a dead target?
1813 if (!stats && !current_targetaddr->got_reply) {
1814 if (!probe_all) {
1815 Printf("no answer from %s\n", targethost);
1816 } else {
1817 Printf("no answer from %s(%s)\n", targethost,
1818 inet_ntop(current_targetaddr->family,
1819 &current_targetaddr->dst_addr,
1820 tmp_buf, sizeof (tmp_buf)));
1824 * Before we move onto next item, let's do some clean up.
1826 current_targetaddr->got_reply = B_FALSE;
1827 current_targetaddr->probing_done = B_FALSE;
1829 * If this is probe-all without stats mode, then we need to
1830 * preserve this count. This is needed when we try to map an
1831 * icmp_seq to IP address. Otherwise, clear it.
1833 if (stats || !probe_all)
1834 current_targetaddr->num_sent = 0;
1835 nreceived_last_target = 0;
1837 current_targetaddr = current_targetaddr->next;
1840 * Did we reach the end of road?
1842 if (current_targetaddr == NULL) {
1843 timer_done = B_TRUE;
1844 if (stats)
1845 finish();
1846 if (is_alive)
1847 exit(EXIT_SUCCESS);
1848 else
1849 exit(EXIT_FAILURE);
1850 } else {
1852 * We use starting_seq_num for authenticating replies.
1853 * Each time we move to a new targetaddr, which has
1854 * a different target IP address, we update this field.
1856 current_targetaddr->starting_seq_num = use_udp ?
1857 dest_port : (ntransmitted % (MAX_ICMP_SEQ + 1));
1861 if (current_targetaddr->family == AF_INET6) {
1862 if (send_reply) {
1863 /* sending back to ourself */
1864 to6.sin6_addr = current_targetaddr->src_addr.addr6;
1865 } else {
1866 to6.sin6_addr = current_targetaddr->dst_addr.addr6;
1869 * Setting the ancillary data once is enough, if we are
1870 * not using source routing through target (-l/-S). In
1871 * case -l/-S used, the middle gateway will be the
1872 * IP address of the source, which can be different
1873 * for each target IP.
1875 if (first_probe ||
1876 (send_reply && current_targetaddr->num_sent == 0)) {
1877 if (send_reply) {
1878 /* target is the middle gateway now */
1879 gw_IP_list6[num_gw].addr6 =
1880 current_targetaddr->dst_addr.addr6;
1882 set_ancillary_data(&msg6, hoplimit, gw_IP_list6,
1883 eff_num_gw, if_index);
1884 first_probe = B_FALSE;
1886 pinger(send_sock6, (struct sockaddr *)&to6, &msg6, AF_INET6);
1887 } else {
1888 to.sin_addr = current_targetaddr->dst_addr.addr;
1890 * Set IPv4 options when sending the first probe to a target
1891 * IP address. Some options change when the target address
1892 * changes.
1894 if (current_targetaddr->num_sent == 0) {
1895 if (eff_num_gw > 0) {
1896 gw_IP_list[num_gw].addr =
1897 current_targetaddr->dst_addr.addr;
1899 * If send_reply, the target becomes the
1900 * middle gateway, sender becomes the last
1901 * gateway.
1903 if (send_reply) {
1904 gw_IP_list[eff_num_gw].addr =
1905 current_targetaddr->src_addr.addr;
1909 * In IPv4, if source routing is used, the target
1910 * address shows up as the last gateway, hence +1.
1912 set_IPv4_options(send_sock, gw_IP_list,
1913 (eff_num_gw > 0) ? eff_num_gw + 1 : 0,
1914 &current_targetaddr->src_addr.addr, &to.sin_addr);
1916 pinger(send_sock, (struct sockaddr *)&to, NULL, AF_INET);
1919 current_targetaddr->num_sent++;
1923 * recv_icmp_packet()'s job is to listen to icmp packets and filter out
1924 * those ping is interested in.
1926 static void
1927 recv_icmp_packet(struct addrinfo *ai_dst, int recv_sock6, int recv_sock,
1928 ushort_t udp_src_port6, ushort_t udp_src_port)
1930 struct msghdr in_msg;
1931 struct iovec iov;
1932 struct sockaddr_in6 from6;
1933 fd_set fds;
1934 int result;
1935 int cc;
1936 boolean_t always_true = B_TRUE; /* lint doesn't like while(B_TRUE) */
1938 while (always_true) {
1939 (void) FD_ZERO(&fds);
1940 if (recv_sock6 != -1)
1941 FD_SET(recv_sock6, &fds);
1942 if (recv_sock != -1)
1943 FD_SET(recv_sock, &fds);
1945 result = select(MAX(recv_sock6, recv_sock) + 1, &fds,
1946 (fd_set *)NULL, (fd_set *)NULL, NULL);
1947 if (result == -1) {
1948 if (errno == EINTR) {
1949 continue;
1950 } else {
1951 Fprintf(stderr, "%s: select %s\n", progname,
1952 strerror(errno));
1953 exit(EXIT_FAILURE);
1955 } else if (result > 0) {
1956 in_msg.msg_name = &from6;
1957 in_msg.msg_namelen = sizeof (from6);
1958 iov.iov_base = in_pkt;
1959 iov.iov_len = sizeof (in_pkt);
1960 in_msg.msg_iov = &iov;
1961 in_msg.msg_iovlen = 1;
1962 in_msg.msg_control = ancillary_data;
1963 in_msg.msg_controllen = sizeof (ancillary_data);
1965 /* Do we have an ICMP6 packet waiting? */
1966 if ((recv_sock6 != -1) &&
1967 (FD_ISSET(recv_sock6, &fds))) {
1968 cc = recvmsg(recv_sock6, &in_msg, 0);
1969 if (cc < 0) {
1970 if (errno != EINTR) {
1971 Fprintf(stderr,
1972 "%s: recvmsg %s\n",
1973 progname, strerror(errno));
1975 continue;
1976 } else if (cc > 0) {
1977 check_reply6(ai_dst, &in_msg, cc,
1978 udp_src_port6);
1981 /* Do we have an ICMP packet waiting? */
1982 if ((recv_sock != -1) && (FD_ISSET(recv_sock, &fds))) {
1983 cc = recvmsg(recv_sock, &in_msg, 0);
1984 if (cc < 0) {
1985 if (errno != EINTR) {
1986 Fprintf(stderr,
1987 "%s: recvmsg %s\n",
1988 progname, strerror(errno));
1990 continue;
1991 } if (cc > 0) {
1992 check_reply(ai_dst, &in_msg, cc,
1993 udp_src_port);
1998 * If we were probing last IP address of the target host and
1999 * received a reply for each probe sent to this address,
2000 * then we are done!
2002 if ((npackets > 0) && (current_targetaddr->next == NULL) &&
2003 (nreceived_last_target == npackets)) {
2004 timer_done = B_TRUE;
2005 finish();
2007 } /* infinite loop */
2011 * Given a host (with possibly multiple IP addresses) and an IP address, this
2012 * function determines if this IP address is one of the host's addresses to
2013 * which we're sending probes. Used to determine if we are interested in a
2014 * packet.
2016 boolean_t
2017 is_a_target(struct addrinfo *ai, union any_in_addr *addr)
2019 int num_addrs;
2020 int i;
2021 struct addrinfo *aip;
2023 aip = ai;
2024 if (probe_all)
2025 num_addrs = num_v4 + num_v6;
2026 else
2027 num_addrs = 1;
2028 for (i = 0; i < num_addrs && aip != NULL; i++) {
2029 if (aip->ai_family == AF_INET6) {
2030 /* LINTED E_BAD_PTR_CAST_ALIGN */
2031 if (IN6_ARE_ADDR_EQUAL(&((struct sockaddr_in6 *)
2032 aip->ai_addr)->sin6_addr, &addr->addr6))
2033 return (B_TRUE);
2034 } else {
2035 /* LINTED E_BAD_PTR_CAST_ALIGN */
2036 if (((struct sockaddr_in *)
2037 aip->ai_addr)->sin_addr.s_addr == addr->addr.s_addr)
2038 return (B_TRUE);
2042 return (B_FALSE);
2046 * Compose and transmit an ICMP ECHO REQUEST packet. The IP packet
2047 * will be added on by the kernel. The ID field is our UNIX process ID,
2048 * and the sequence number is an ascending integer. The first 8 bytes
2049 * of the data portion are used to hold a UNIX "timeval" struct in network
2050 * byte-order, to compute the round-trip time.
2052 static void
2053 pinger(int send_sock, struct sockaddr *whereto, struct msghdr *msg6,
2054 int family)
2056 static uint64_t out_pkt_buf[(IP_MAXPACKET + 1) / 8];
2057 uchar_t *out_pkt = (uchar_t *)&out_pkt_buf;
2058 /* LINTED E_BAD_PTR_CAST_ALIGN */
2059 struct icmp *icp = (struct icmp *)out_pkt;
2060 /* LINTED E_BAD_PTR_CAST_ALIGN */
2061 struct sockaddr_in6 *to6 = (struct sockaddr_in6 *)whereto;
2062 /* LINTED E_BAD_PTR_CAST_ALIGN */
2063 struct sockaddr_in *to = (struct sockaddr_in *)whereto;
2064 struct timeval *tp;
2065 struct timeval t_snd;
2066 uchar_t *datap;
2067 struct iovec iov;
2068 int start = 0;
2069 int cc;
2070 int i;
2072 /* using UDP? */
2073 if (use_udp) {
2074 cc = datalen;
2076 /* LINTED E_BAD_PTR_CAST_ALIGN */
2077 tp = (struct timeval *)out_pkt;
2078 datap = &out_pkt[sizeof (struct timeval)];
2081 * This sets the port whether we are handling a v4 or v6
2082 * sockaddr structure.
2084 to->sin_port = htons(dest_port);
2086 dest_port = (dest_port + 1) % (MAX_PORT + 1);
2087 ntransmitted++;
2088 } else { /* using ICMP */
2089 cc = datalen + ICMP_MINLEN;
2091 if (family == AF_INET6) {
2092 icp->icmp_type = send_reply ?
2093 ICMP6_ECHO_REPLY : ICMP6_ECHO_REQUEST;
2094 } else if (use_icmp_ts) { /* family is AF_INET */
2095 icp->icmp_type = send_reply ?
2096 ICMP_TSTAMPREPLY : ICMP_TSTAMP;
2097 } else {
2098 icp->icmp_type = send_reply ?
2099 ICMP_ECHOREPLY : ICMP_ECHO;
2102 icp->icmp_code = 0;
2103 icp->icmp_cksum = 0;
2104 icp->icmp_seq = htons(ntransmitted++ % (MAX_ICMP_SEQ + 1));
2105 if (icp->icmp_seq == 0)
2106 num_wraps++;
2107 icp->icmp_id = htons(ident); /* ID */
2109 /* LINTED E_BAD_PTR_CAST_ALIGN */
2110 tp = (struct timeval *)&out_pkt[ICMP_MINLEN];
2111 datap = &out_pkt[ICMP_MINLEN + sizeof (struct timeval)];
2114 start = sizeof (struct timeval); /* skip for time */
2116 (void) gettimeofday(&t_snd, NULL);
2118 /* if packet is big enough to store timeval OR ... */
2119 if ((datalen >= sizeof (struct timeval)) ||
2120 (family == AF_INET && use_icmp_ts))
2121 *tp = t_snd;
2123 if (family == AF_INET && use_icmp_ts) {
2124 start = sizeof (struct id_ts); /* skip for ICMP timestamps */
2125 /* Number of milliseconds since midnight */
2126 icp->icmp_otime = htonl((tp->tv_sec % (24*60*60)) * 1000 +
2127 tp->tv_usec / 1000);
2130 for (i = start; i < datalen; i++)
2131 *datap++ = i;
2133 if (family == AF_INET) {
2134 if (!use_udp)
2135 icp->icmp_cksum = in_cksum((ushort_t *)icp, cc);
2137 i = sendto(send_sock, (char *)out_pkt, cc, 0, whereto,
2138 sizeof (struct sockaddr_in));
2139 } else {
2141 * Fill in the rest of the msghdr structure. msg_control is set
2142 * in set_ancillary_data().
2144 msg6->msg_name = to6;
2145 msg6->msg_namelen = sizeof (struct sockaddr_in6);
2147 iov.iov_base = out_pkt;
2148 iov.iov_len = cc;
2150 msg6->msg_iov = &iov;
2151 msg6->msg_iovlen = 1;
2153 i = sendmsg(send_sock, msg6, 0);
2156 /* This is a more precise time (right after we send the packet) */
2157 t_last_probe_sent = gethrtime();
2159 if (i < 0 || i != cc) {
2160 if (i < 0) {
2161 Fprintf(stderr, "%s: sendto %s\n", progname,
2162 strerror(errno));
2163 if (!stats)
2164 exit(EXIT_FAILURE);
2166 Printf("ping: wrote %s %d chars, ret=%d\n",
2167 targethost, cc, i);
2168 (void) fflush(stdout);
2173 * Return a hostname for the given IP address.
2175 char *
2176 pr_name(char *addr, int family)
2178 struct sockaddr_in sin;
2179 struct sockaddr_in6 sin6;
2180 struct sockaddr *sa;
2181 static struct in6_addr prev_addr = IN6ADDR_ANY_INIT;
2182 char *cp;
2183 char abuf[INET6_ADDRSTRLEN];
2184 static char buf[NI_MAXHOST + INET6_ADDRSTRLEN + 3];
2185 uint_t slen, alen, hlen;
2187 switch (family) {
2188 case AF_INET:
2189 (void) memset(&sin, 0, sizeof (sin));
2190 slen = sizeof (struct sockaddr_in);
2191 alen = sizeof (struct in_addr);
2192 /* LINTED E_BAD_PTR_CAST_ALIGN */
2193 sin.sin_addr = *(struct in_addr *)addr;
2194 sin.sin_port = 0;
2195 sa = (struct sockaddr *)&sin;
2196 break;
2197 case AF_INET6:
2198 (void) memset(&sin6, 0, sizeof (sin6));
2199 slen = sizeof (struct sockaddr_in6);
2200 alen = sizeof (struct in6_addr);
2201 /* LINTED E_BAD_PTR_CAST_ALIGN */
2202 sin6.sin6_addr = *(struct in6_addr *)addr;
2203 sin6.sin6_port = 0;
2204 sa = (struct sockaddr *)&sin6;
2205 break;
2206 default:
2207 (void) snprintf(buf, sizeof (buf), "<invalid address family>");
2208 return (buf);
2210 sa->sa_family = family;
2212 /* compare with the buffered (previous) lookup */
2213 if (memcmp(addr, &prev_addr, alen) != 0) {
2214 int flags = (nflag) ? NI_NUMERICHOST : NI_NAMEREQD;
2215 mutex_enter(&ns_lock);
2216 ns_active = B_TRUE;
2217 ns_starttime = gethrtime();
2218 mutex_exit(&ns_lock);
2219 if (getnameinfo(sa, slen, buf, sizeof (buf),
2220 NULL, 0, flags) != 0) {
2221 /* getnameinfo() failed; return just the address */
2222 if (inet_ntop(family, (const void*)addr,
2223 buf, sizeof (buf)) == NULL)
2224 buf[0] = 0;
2225 } else if (!nflag) {
2226 /* append numeric address to hostname string */
2227 hlen = strlen(buf);
2228 cp = (char *)(buf + hlen);
2229 (void) snprintf(cp, sizeof (buf) - hlen, " (%s)",
2230 inet_ntop(family, (const void *)addr, abuf,
2231 sizeof (abuf)));
2233 mutex_enter(&ns_lock);
2234 ns_active = B_FALSE;
2235 mutex_exit(&ns_lock);
2237 /* LINTED E_BAD_PTR_CAST_ALIGN */
2238 prev_addr = *(struct in6_addr *)addr;
2240 return (buf);
2244 * Return the protocol string, given its protocol number.
2246 char *
2247 pr_protocol(int prot)
2249 static char buf[20];
2251 switch (prot) {
2252 case IPPROTO_ICMPV6:
2253 (void) strlcpy(buf, "icmp6", sizeof (buf));
2254 break;
2256 case IPPROTO_ICMP:
2257 (void) strlcpy(buf, "icmp", sizeof (buf));
2258 break;
2260 case IPPROTO_TCP:
2261 (void) strlcpy(buf, "tcp", sizeof (buf));
2262 break;
2264 case IPPROTO_UDP:
2265 (void) strlcpy(buf, "udp", sizeof (buf));
2266 break;
2268 default:
2269 (void) snprintf(buf, sizeof (buf), "prot %d", prot);
2270 break;
2273 return (buf);
2277 * Checks if value is between seq_begin and seq_begin+seq_len. Note that
2278 * sequence numbers wrap around after MAX_ICMP_SEQ (== MAX_PORT).
2280 boolean_t
2281 seq_match(ushort_t seq_begin, int seq_len, ushort_t value)
2284 * If seq_len is too big, like some value greater than MAX_ICMP_SEQ/2,
2285 * truncate it down to MAX_ICMP_SEQ/2. We are not going to accept any
2286 * reply which come 83hr later!
2288 if (seq_len > MAX_ICMP_SEQ / 2) {
2289 seq_begin = (seq_begin + seq_len - MAX_ICMP_SEQ / 2) %
2290 (MAX_ICMP_SEQ + 1);
2291 seq_len = MAX_ICMP_SEQ / 2;
2294 if (PINGSEQ_LEQ(seq_begin, value) &&
2295 PINGSEQ_LEQ(value, (seq_begin + seq_len - 1) % (MAX_ICMP_SEQ + 1)))
2296 return (B_TRUE);
2297 else
2298 return (B_FALSE);
2302 * For a given icmp_seq, find which destination address we must have sent this
2303 * to.
2305 void
2306 find_dstaddr(ushort_t icmpseq, union any_in_addr *ipaddr)
2308 struct targetaddr *target = targetaddr_list;
2309 int real_seq;
2310 int targetaddr_index;
2311 int real_npackets;
2312 int i;
2314 ipaddr->addr6 = in6addr_any;
2317 * If this is probe_all and not stats, then the number of probes sent to
2318 * each IP address may be different (remember, we stop sending to one IP
2319 * address as soon as it replies). They are stored in target->num_sent
2320 * field. Since we don't wrap around the list (!stats), they are also
2321 * preserved.
2323 if (probe_all && !stats) {
2324 do {
2325 if (seq_match(target->starting_seq_num,
2326 target->num_sent, icmpseq)) {
2327 ipaddr->addr6 = target->dst_addr.addr6;
2329 * We are not immediately return()ing here.
2330 * Because of wrapping, we might find another
2331 * match later, which is more likely to be the
2332 * real one.
2335 target = target->next;
2336 } while (target != NULL);
2337 } else {
2339 * Find the absolute (non-wrapped) seq number within the last
2340 * 64K
2342 if (icmpseq < (ntransmitted % (MAX_ICMP_SEQ + 1))) {
2343 real_seq = num_wraps * (MAX_ICMP_SEQ + 1) + icmpseq;
2344 } else {
2345 real_seq = (num_wraps - 1) * (MAX_ICMP_SEQ + 1) +
2346 icmpseq;
2349 /* Make sure it's non-negative */
2350 if (real_seq < 0)
2351 return;
2352 real_npackets = (npackets == 0) ? 1 : npackets;
2355 * We sent npackets many packets to each of those
2356 * num_targetaddrs many IP addresses.
2358 targetaddr_index =
2359 (real_seq % (num_targetaddrs * real_npackets)) /
2360 real_npackets;
2361 for (i = 0; i < targetaddr_index; i++)
2362 target = target->next;
2363 ipaddr->addr6 = target->dst_addr.addr6;
2368 * Checksum routine for Internet Protocol family headers (C Version)
2370 static ushort_t
2371 in_cksum(ushort_t *addr, int len)
2373 int nleft = len;
2374 ushort_t *w = addr;
2375 ushort_t answer;
2376 ushort_t odd_byte = 0;
2377 int sum = 0;
2380 * Our algorithm is simple, using a 32 bit accumulator (sum),
2381 * we add sequential 16 bit words to it, and at the end, fold
2382 * back all the carry bits from the top 16 bits into the lower
2383 * 16 bits.
2385 while (nleft > 1) {
2386 sum += *w++;
2387 nleft -= 2;
2390 /* mop up an odd byte, if necessary */
2391 if (nleft == 1) {
2392 *(uchar_t *)(&odd_byte) = *(uchar_t *)w;
2393 sum += odd_byte;
2397 * add back carry outs from top 16 bits to low 16 bits
2399 sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
2400 sum += (sum >> 16); /* add carry */
2401 answer = ~sum; /* truncate to 16 bits */
2402 return (answer);
2406 * Subtract 2 timeval structs: out = out - in.
2407 * Out is assumed to be >= in.
2409 void
2410 tvsub(struct timeval *out, struct timeval *in)
2412 if ((out->tv_usec -= in->tv_usec) < 0) {
2413 out->tv_sec--;
2414 out->tv_usec += 1000000;
2416 out->tv_sec -= in->tv_sec;
2420 * Print out statistics, and give up.
2421 * Heavily buffered STDIO is used here, so that all the statistics
2422 * will be written with 1 sys-write call. This is nice when more
2423 * than one copy of the program is running on a terminal; it prevents
2424 * the statistics output from becoming intermingled.
2426 static void
2427 finish()
2429 Printf("\n----%s PING Statistics----\n", targethost);
2430 Printf("%d packets transmitted, ", ntransmitted);
2431 Printf("%d packets received, ", nreceived);
2432 if (ntransmitted) {
2433 if (nreceived <= ntransmitted) {
2434 Printf("%d%% packet loss",
2435 (int)(((ntransmitted-nreceived)*100) /
2436 ntransmitted));
2437 } else {
2438 Printf("%.2f times amplification",
2439 (double)nreceived / (double)ntransmitted);
2442 (void) putchar('\n');
2444 /* if packet is big enough to store timeval AND ... */
2445 if ((datalen >= sizeof (struct timeval)) && (nreceived > 0)) {
2446 double mean = (double)tsum / nreceived;
2447 double smean = (double)tsum2 / nreceived;
2448 double sd =
2449 sqrt(((smean - mean*mean) * nreceived) / (nreceived-1));
2451 Printf("round-trip (ms) min/avg/max/stddev = "
2452 TIMEFORMAT "/" TIMEFORMAT "/"
2453 TIMEFORMAT "/" TIMEFORMAT "\n",
2454 (double)tmin / 1000, mean / 1000,
2455 (double)tmax / 1000, sd / 1000);
2457 (void) fflush(stdout);
2459 exit(is_alive ? EXIT_SUCCESS : EXIT_FAILURE);
2463 * print the usage line
2465 static void
2466 usage(char *cmdname)
2468 Fprintf(stderr, "usage: %s host [timeout]\n", cmdname);
2469 Fprintf(stderr,
2470 /* CSTYLED */
2471 "usage: %s -s [-l | -U] [-abdDLnRrv] [-A addr_family] [-c traffic_class]\n\t"
2472 "[-g gateway [-g gateway ...]] [-N nexthop] [-F flow_label] [-I interval]\n\t"
2473 "[-i interface] [-P tos] [-p port] [-t ttl] host [data_size] [npackets]\n",
2474 cmdname);
2478 * Parse integer argument; exit with an error if it's not a number.
2479 * Now it also accepts hex. values.
2481 static int
2482 int_arg(char *s, char *what)
2484 char *cp;
2485 char *ep;
2486 int num;
2488 errno = 0;
2489 if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) {
2490 cp = s + 2;
2491 num = (int)strtol(cp, &ep, 16);
2492 } else {
2493 num = (int)strtol(s, &ep, 10);
2496 if (errno || *ep != '\0' || num < 0) {
2497 Fprintf(stderr, "%s: bad %s: %s\n", progname, what, s);
2498 exit(EXIT_FAILURE);
2501 return (num);
2505 * Parse the interval into a itimerspec. The interval used to originally be
2506 * parsed as an integer argument. That means that one used to be able to specify
2507 * an interval in hex. The strtod() family honors that at times, with strtod
2508 * sometimes doing so depending on the compilation environment and strtof() and
2509 * srtold() always doing that. To facilitiate that and not worry about a
2510 * careless Makefile change breaking us, we instead just use strtold here, even
2511 * though we really don't need the precision.
2513 static void
2514 parse_interval(char *s)
2516 long double val;
2517 char *end;
2519 errno = 0;
2520 val = strtold(s, &end);
2521 if (errno != 0 || *end != '\0') {
2522 Fprintf(stderr, "%s: bad interval: %s\n", progname, s);
2523 exit(EXIT_FAILURE);
2527 * Check values that we know are going to be bad. Anything greater than
2528 * INT_MAX, anything less than 0, look for specific NaNs. Also, clamp
2529 * the value at 0.01 seconds.
2531 if (val == NAN || val <= 0.0 || val >= INT_MAX) {
2532 Fprintf(stderr, "%s: bad interval: %s\n", progname, s);
2533 exit(EXIT_FAILURE);
2536 if (val < 0.01) {
2537 Fprintf(stderr, "%s: interval too small: %Lf\n", progname, val);
2538 exit(EXIT_FAILURE);
2541 interval.it_value.tv_sec = (long)val;
2542 interval.it_value.tv_nsec = (long)((val - interval.it_value.tv_sec) *
2543 NANOSEC);
2545 if (interval.it_value.tv_sec == 0 &&
2546 interval.it_value.tv_nsec < mintime) {
2547 mintime = interval.it_value.tv_nsec;
2552 * We should have an SO_TIMESTAMP message for this socket to indicate
2553 * the actual time that the message took. If we don't we'll fall back to
2554 * gettimeofday(); however, that can cause any delays due to DNS
2555 * resolution and the like to end up wreaking havoc on us.
2557 void
2558 ping_gettime(struct msghdr *msg, struct timeval *tv)
2560 struct cmsghdr *cmsg;
2562 for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL;
2563 cmsg = CMSG_NXTHDR(msg, cmsg)) {
2564 if (cmsg->cmsg_level == SOL_SOCKET &&
2565 cmsg->cmsg_type == SO_TIMESTAMP &&
2566 cmsg->cmsg_len == CMSG_LEN(sizeof (*tv))) {
2567 bcopy(CMSG_DATA(cmsg), tv, sizeof (*tv));
2568 return;
2572 (void) gettimeofday(tv, NULL);
2576 * The purpose of this thread is to try and inform a user that we're blocked
2577 * doing name lookups. For various reasons, ping has to try and look up the IP
2578 * addresses it receives via name services unless the -n flag is specified. The
2579 * irony of this is that when trying to use ping to actually diagnose a broken
2580 * network, name services are unlikely to be available and that will result in a
2581 * lot of confusion as to why pings seem like they're not working. As such, we
2582 * basically wake up every 2 seconds and check whether or not we've hit such a
2583 * condition where we should inform the user via stderr.
2585 * Once they've been informed, we do not inform them again until approximately a
2586 * minute of time has passed, in case that things are working intermittently.
2588 /*ARGSUSED*/
2589 static void *
2590 ns_warning_thr(void *unused)
2592 for (;;) {
2593 hrtime_t now;
2595 (void) sleep(ns_sleeptime);
2596 now = gethrtime();
2597 mutex_enter(&ns_lock);
2598 if (ns_active == B_TRUE &&
2599 now - ns_starttime >= ns_warntime * NANOSEC) {
2600 Fprintf(stderr, "%s: warning: ICMP responses "
2601 "received, but name service lookups are "
2602 "taking a while. Use ping -n to disable "
2603 "name service lookups.\n",
2604 progname);
2605 mutex_exit(&ns_lock);
2606 return (NULL);
2608 mutex_exit(&ns_lock);
2611 /* LINTED: E_STMT_NOT_REACHED */
2612 return (NULL);