1 /*
2 * CDDL HEADER START
3 *
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.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 *
21 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
22 * Use is subject to license terms.
23 */
24
25 /*
26 * Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T
27 * All Rights Reserved.
28 */
29
30 /*
31 * University Copyright- Copyright (c) 1982, 1986, 1988
32 * The Regents of the University of California.
33 * All Rights Reserved.
34 *
35 * University Acknowledgment- Portions of this document are derived from
36 * software developed by the University of California, Berkeley, and its
37 * contributors.
38 */
39
40 #include <stdio.h>
41 #include <strings.h>
42 #include <errno.h>
43 #include <fcntl.h>
44 #include <unistd.h>
45 #include <signal.h>
46 #include <limits.h>
47 #include <math.h>
48
49 #include <sys/time.h>
50 #include <sys/param.h>
51 #include <sys/socket.h>
52 #include <sys/sockio.h>
53 #include <sys/stropts.h>
54 #include <sys/file.h>
55 #include <sys/sysmacros.h>
56
57 #include <arpa/inet.h>
58 #include <net/if.h>
59 #include <netinet/in_systm.h>
60 #include <netinet/in.h>
61 #include <netinet/ip.h>
62 #include <netinet/ip_icmp.h>
63 #include <netinet/ip_var.h>
64 #include <netinet/ip6.h>
65 #include <netinet/icmp6.h>
66 #include <netinet/udp.h>
67 #include <netdb.h>
68 #include <stdlib.h>
69 #include <priv_utils.h>
70
71 #include <libinetutil.h>
72 #include "ping.h"
73
74 /*
75 * This macro is used to compare 16bit, wrapping sequence numbers. Inspired by
76 * TCP's SEQ_LEQ macro.
77 */
78 #define PINGSEQ_LEQ(a, b) ((int16_t)((a)-(b)) <= 0)
79
80 #define MAX_WAIT 10 /* max sec. to wait for response */
81 #define MAX_TRAFFIC_CLASS 255 /* max traffic class for IPv6 */
82 #define MAX_FLOW_LABEL 0xFFFFF /* max flow label for IPv6 */
83 #define MAX_TOS 255 /* max type-of-service for IPv4 */
84
85 #define TIMEOUT 20 /* default timeout value */
86 #define DEFAULT_DATALEN 56
87
88 #define MULTICAST_NOLOOP 1 /* multicast options */
89 #define MULTICAST_TTL 2
90 #define MULTICAST_IF 4
91
92 #define IF_INDEX 0 /* types of -i argument */
93 #define IF_NAME 1
94 #define IF_ADDR 2
95 #define IF_ADDR6 3
96
97 #ifdef BSD
98 #define setbuf(s, b) setlinebuf((s))
99 #endif /* BSD */
100
101
102 /* interface identification */
103 union if_id {
104 int index; /* interface index (e.g., 1, 2) */
105 char *name; /* interface name (e.g., le0, hme0) */
106 union any_in_addr addr; /* interface address (e.g., 10.123.4.5) */
107 };
108
109 /* stores the interface supplied by the user */
110 struct if_entry {
111 char *str; /* unresolved, string input */
112 int id_type; /* type of ID (index, name, addr, addr6) */
113 union if_id id; /* ID */
114 };
115
116 char *progname;
117 char *targethost;
118 char *nexthop;
119
120 static int send_sock; /* send sockets */
121 static int send_sock6;
122 static struct sockaddr_in to; /* where to send */
123 static struct sockaddr_in6 to6;
124 static union any_in_addr gw_IP_list[MAX_GWS]; /* gateways */
125 static union any_in_addr gw_IP_list6[MAX_GWS6];
126 static int if_index = 0; /* outgoing interface index */
127 boolean_t is_alive = _B_FALSE; /* is target host alive */
128 struct targetaddr *current_targetaddr; /* current target IP address to probe */
129 static struct targetaddr *targetaddr_list; /* list of IP addresses to probe */
130 static int num_targetaddrs; /* no of target addresses to probe */
131 static int num_v4 = 0; /* count of IPv4 addresses */
132 static int num_v6 = 0; /* count of IPv6 addresses */
133 boolean_t verbose = _B_FALSE; /* verbose output */
134 boolean_t stats = _B_FALSE; /* display statistics */
135 static boolean_t settos = _B_FALSE; /* set type-of-service value */
136 boolean_t rr_option = _B_FALSE; /* true if using record route */
137 boolean_t send_reply = _B_FALSE; /* Send an ICMP_{ECHO|TSTAMP}REPLY */
138 /* that goes to target and comes back */
139 /* to the the sender via src routing. */
140 boolean_t strict = _B_FALSE; /* true if using strict source route */
141 boolean_t ts_option = _B_FALSE; /* true if using timestamp option */
142 boolean_t use_icmp_ts = _B_FALSE; /* Use ICMP timestamp request */
143 boolean_t use_udp = _B_FALSE; /* Use UDP instead of ICMP */
144 boolean_t probe_all = _B_FALSE; /* probe all the IP addresses */
145 boolean_t nflag = _B_FALSE; /* do not reverse lookup addresses */
146 boolean_t bypass = _B_FALSE; /* bypass IPsec policy */
147 static int family_input = AF_UNSPEC; /* address family supplied by user */
148 int datalen = DEFAULT_DATALEN; /* How much data */
149 int ts_flag; /* timestamp flag value */
150 static int num_gw; /* number of gateways */
151 static int eff_num_gw; /* effective number of gateways */
152 /* if send_reply, it's 2*num_gw+1 */
153 static int num_wraps = -1; /* no of times 64K icmp_seq wrapped */
154 static ushort_t dest_port = 32768 + 666; /* starting port for the UDP probes */
155 static char *gw_list[MAXMAX_GWS]; /* list of gateways as user enters */
156 static int interval = 1; /* interval between transmissions */
157 static int options; /* socket options */
158 static int moptions; /* multicast options */
159 int npackets; /* number of packets to send */
160 static ushort_t tos; /* type-of-service value */
161 static int hoplimit = -1; /* time-to-live value */
162 static int dontfrag; /* IP*_DONTFRAG */
163 static int timeout = TIMEOUT; /* timeout value (sec) for probes */
164 static struct if_entry out_if; /* interface argument */
165 int ident; /* ID for this ping run */
166 static hrtime_t t_last_probe_sent; /* the time we sent the last probe */
167
168 /*
169 * This buffer stores the received packets. Currently it needs to be 32 bit
170 * aligned. In the future, we'll be using 64 bit alignment, so let's use 64 bit
171 * alignment now.
172 */
173 static uint64_t in_pkt[(IP_MAXPACKET + 1)/8];
174
175 /* Used to store the ancillary data that comes with the received packets */
176 static uint64_t ancillary_data[(IP_MAXPACKET + 1)/8];
177
178 static int ntransmitted; /* number of packet sent to single IP address */
179 int nreceived; /* # of packets we got back from target host */
180 int nreceived_last_target; /* received from last target IP */
181 /*
182 * These are used for statistics. tmin is initialized to maximum longint value.
183 * The max value is also used for timeouts. All times are in microseconds.
184 */
185 long long tmin = LLONG_MAX;
186 long long tmax;
187 int64_t tsum; /* sum of all times, for doing average */
188 int64_t tsum2; /* sum of squared times, for std. dev. */
189
190 static struct targetaddr *build_targetaddr_list(struct addrinfo *,
191 union any_in_addr *);
192 extern void check_reply(struct addrinfo *, struct msghdr *, int, ushort_t);
193 extern void check_reply6(struct addrinfo *, struct msghdr *, int, ushort_t);
194 static struct targetaddr *create_targetaddr_item(int, union any_in_addr *,
195 union any_in_addr *);
196 void find_dstaddr(ushort_t, union any_in_addr *);
197 static struct ifaddrlist *find_if(struct ifaddrlist *, int);
198 static void finish();
199 static void get_gwaddrs(char *[], int, union any_in_addr *,
200 union any_in_addr *, int *, int *);
201 static void get_hostinfo(char *, int, struct addrinfo **);
202 static ushort_t in_cksum(ushort_t *, int);
203 static int int_arg(char *s, char *what);
204 boolean_t is_a_target(struct addrinfo *, union any_in_addr *);
205 static void mirror_gws(union any_in_addr *, int);
206 static void pinger(int, struct sockaddr *, struct msghdr *, int);
207 char *pr_name(char *, int);
208 char *pr_protocol(int);
209 static void print_unknown_host_msg(const char *, const char *);
210 static void recv_icmp_packet(struct addrinfo *, int, int, ushort_t, ushort_t);
211 static void resolve_nodes(struct addrinfo **, struct addrinfo **,
212 union any_in_addr **);
213 void schedule_sigalrm();
214 static void select_all_src_addrs(union any_in_addr **, struct addrinfo *,
215 union any_in_addr *, union any_in_addr *);
216 static void select_src_addr(union any_in_addr *, int, union any_in_addr *);
217 void send_scheduled_probe();
218 boolean_t seq_match(ushort_t, int, ushort_t);
219 extern void set_ancillary_data(struct msghdr *, int, union any_in_addr *, int,
220 uint_t);
221 extern void set_IPv4_options(int, union any_in_addr *, int, struct in_addr *,
222 struct in_addr *);
223 static void set_nexthop(int, struct addrinfo *, int);
224 static boolean_t setup_socket(int, int *, int *, int *, ushort_t *,
225 struct addrinfo *);
226 void sigalrm_handler();
227 void tvsub(struct timeval *, struct timeval *);
228 static void usage(char *);
229
230 /*
231 * main()
232 */
233 int
main(int argc,char * argv[])234 main(int argc, char *argv[])
235 {
236 struct addrinfo *ai_dst = NULL; /* addrinfo host list */
237 struct addrinfo *ai_nexthop = NULL; /* addrinfo nexthop */
238 union any_in_addr *src_addr_list = NULL; /* src addrs to use */
239 int recv_sock = -1; /* receive sockets */
240 int recv_sock6 = -1;
241 ushort_t udp_src_port; /* src ports for UDP probes */
242 ushort_t udp_src_port6; /* used to identify replies */
243 uint_t flowinfo = 0;
244 uint_t class = 0;
245 char abuf[INET6_ADDRSTRLEN];
246 int c;
247 int i;
248 boolean_t has_sys_ip_config;
249
250 progname = argv[0];
251
252 /*
253 * This program needs the net_icmpaccess privilege for creating
254 * raw ICMP sockets. It needs sys_ip_config for using the
255 * IP_NEXTHOP socket option (IPv4 only). We'll fail
256 * on the socket call and report the error there when we have
257 * insufficient privileges.
258 *
259 * Shared-IP zones don't have the sys_ip_config privilege, so
260 * we need to check for it in our limit set before trying
261 * to set it.
262 */
263 has_sys_ip_config = priv_ineffect(PRIV_SYS_IP_CONFIG);
264
265 (void) __init_suid_priv(PU_CLEARLIMITSET, PRIV_NET_ICMPACCESS,
266 has_sys_ip_config ? PRIV_SYS_IP_CONFIG : (char *)NULL,
267 (char *)NULL);
268
269 setbuf(stdout, (char *)0);
270
271 while ((c = getopt(argc, argv,
272 "abA:c:dDF:G:g:I:i:LlnN:P:p:rRSsTt:UvX:x:Y0123?")) != -1) {
273 switch ((char)c) {
274 case 'A':
275 if (strcmp(optarg, "inet") == 0) {
276 family_input = AF_INET;
277 } else if (strcmp(optarg, "inet6") == 0) {
278 family_input = AF_INET6;
279 } else {
280 Fprintf(stderr,
281 "%s: unknown address family %s\n",
282 progname, optarg);
283 exit(EXIT_FAILURE);
284 }
285 break;
286
287 case 'a':
288 probe_all = _B_TRUE;
289 break;
290
291 case 'c':
292 i = int_arg(optarg, "traffic class");
293 if (i > MAX_TRAFFIC_CLASS) {
294 Fprintf(stderr, "%s: traffic class %d out of "
295 "range\n", progname, i);
296 exit(EXIT_FAILURE);
297 }
298 class = (uint_t)i;
299 break;
300
301 case 'd':
302 options |= SO_DEBUG;
303 break;
304
305 case 'D':
306 dontfrag = 1;
307 break;
308
309 case 'b':
310 bypass = _B_TRUE;
311 break;
312
313 case 'F':
314 i = int_arg(optarg, "flow label");
315 if (i > MAX_FLOW_LABEL) {
316 Fprintf(stderr, "%s: flow label %d out of "
317 "range\n", progname, i);
318 exit(EXIT_FAILURE);
319 }
320 flowinfo = (uint_t)i;
321 break;
322
323 case 'I':
324 stats = _B_TRUE;
325 interval = int_arg(optarg, "interval");
326 break;
327
328 case 'i':
329 /*
330 * this can accept interface index, interface name, and
331 * address configured on the interface
332 */
333 moptions |= MULTICAST_IF;
334 out_if.str = optarg;
335
336 if (inet_pton(AF_INET6, optarg, &out_if.id.addr) > 0) {
337 out_if.id_type = IF_ADDR6;
338 } else if (inet_pton(AF_INET, optarg,
339 &out_if.id.addr) > 0) {
340 out_if.id_type = IF_ADDR;
341 } else if (strcmp(optarg, "0") == 0) {
342 out_if.id_type = IF_INDEX;
343 out_if.id.index = 0;
344 } else if ((out_if.id.index = atoi(optarg)) != 0) {
345 out_if.id_type = IF_INDEX;
346 } else {
347 out_if.id.name = optarg;
348 out_if.id_type = IF_NAME;
349 }
350 break;
351
352 case 'L':
353 moptions |= MULTICAST_NOLOOP;
354 break;
355
356 case 'l':
357 send_reply = _B_TRUE;
358 strict = _B_FALSE;
359 break;
360
361 case 'n':
362 nflag = _B_TRUE;
363 break;
364
365 case 'P':
366 settos = _B_TRUE;
367 i = int_arg(optarg, "type-of-service");
368 if (i > MAX_TOS) {
369 Fprintf(stderr, "%s: tos value %d out of "
370 "range\n", progname, i);
371 exit(EXIT_FAILURE);
372 }
373 tos = (ushort_t)i;
374 break;
375
376 case 'p':
377 i = int_arg(optarg, "port number");
378 if (i > MAX_PORT) {
379 Fprintf(stderr, "%s: port number %d out of "
380 "range\n", progname, i);
381 exit(EXIT_FAILURE);
382 }
383 dest_port = (ushort_t)i;
384 break;
385
386 case 'r':
387 options |= SO_DONTROUTE;
388 break;
389
390 case 'R':
391 rr_option = _B_TRUE;
392 break;
393
394 case 'S':
395 send_reply = _B_TRUE;
396 strict = _B_TRUE;
397 break;
398
399 case 's':
400 stats = _B_TRUE;
401 break;
402
403 case 'T':
404 ts_option = _B_TRUE;
405 break;
406
407 case 't':
408 moptions |= MULTICAST_TTL;
409 hoplimit = int_arg(optarg, "ttl");
410 if (hoplimit > MAXTTL) {
411 Fprintf(stderr, "%s: ttl %d out of range\n",
412 progname, hoplimit);
413 exit(EXIT_FAILURE);
414 }
415 break;
416
417 case 'U':
418 use_udp = _B_TRUE;
419 use_icmp_ts = _B_FALSE;
420 break;
421
422 case 'v':
423 verbose = _B_TRUE;
424 break;
425 /*
426 * 'x' and 'X' has been undocumented flags for source routing.
427 * Now we document loose source routing with the new flag 'g',
428 * which is same as in traceroute. We still keep x/X as
429 * as undocumented. 'G', which is for strict source routing is
430 * also undocumented.
431 */
432 case 'x':
433 case 'g':
434 strict = _B_FALSE;
435 if (num_gw > MAXMAX_GWS) {
436 Fprintf(stderr, "%s: too many gateways\n",
437 progname);
438 exit(EXIT_FAILURE);
439 }
440 gw_list[num_gw++] = optarg;
441 break;
442
443 case 'X':
444 case 'G':
445 strict = _B_TRUE;
446 if (num_gw > MAXMAX_GWS) {
447 Fprintf(stderr, "%s: too many gateways\n",
448 progname);
449 exit(EXIT_FAILURE);
450 }
451 gw_list[num_gw++] = optarg;
452 break;
453
454 case 'N':
455 if (nexthop != NULL) {
456 Fprintf(stderr, "%s: only one next hop gateway"
457 " allowed\n", progname);
458 exit(EXIT_FAILURE);
459 }
460 nexthop = optarg;
461 break;
462
463 case 'Y':
464 use_icmp_ts = _B_TRUE;
465 use_udp = _B_FALSE;
466 break;
467
468 case '0':
469 case '1':
470 case '2':
471 case '3':
472 ts_flag = (char)c - '0';
473 break;
474
475 case '?':
476 usage(progname);
477 exit(EXIT_FAILURE);
478 break;
479
480 default:
481 usage(progname);
482 exit(EXIT_FAILURE);
483 break;
484 }
485 }
486
487 if (optind >= argc) {
488 usage(progname);
489 exit(EXIT_FAILURE);
490 }
491
492 /*
493 * send_reply, which sends the probe packet back to itself
494 * doesn't work with UDP
495 */
496 if (use_udp)
497 send_reply = _B_FALSE;
498
499 if (getenv("MACHINE_THAT_GOES_PING") != NULL)
500 stats = _B_TRUE;
501
502 targethost = argv[optind];
503 optind++;
504 if (optind < argc) {
505 if (stats) {
506 datalen = int_arg(argv[optind], "data size");
507 optind++;
508 if (optind < argc) {
509 npackets = int_arg(argv[optind],
510 "packet count");
511 if (npackets < 1) {
512 Fprintf(stderr, "%s: packet count %d "
513 "out of range\n", progname,
514 npackets);
515 exit(EXIT_FAILURE);
516 }
517 }
518 } else {
519 timeout = int_arg(argv[optind], "timeout");
520 }
521 }
522
523 /*
524 * Let's prepare sockaddr_in* structures, cause we might need both of
525 * them.
526 */
527 bzero((char *)&to, sizeof (struct sockaddr_in));
528 to.sin_family = AF_INET;
529
530 bzero((char *)&to6, sizeof (struct sockaddr_in6));
531 to6.sin6_family = AF_INET6;
532 to6.sin6_flowinfo = htonl((class << 20) | flowinfo);
533
534 if (stats)
535 (void) sigset(SIGINT, finish);
536
537 ident = (int)getpid() & 0xFFFF;
538
539 /* resolve the hostnames */
540 resolve_nodes(&ai_dst, &ai_nexthop, &src_addr_list);
541
542 /*
543 * We should make sure datalen is reasonable.
544 * IP_MAXPACKET >= IPv4/IPv6 header length +
545 * IPv4 options/IPv6 routing header length +
546 * ICMP/ICMP6/UDP header length +
547 * datalen
548 */
549
550 if (family_input == AF_INET6 ||
551 (family_input == AF_UNSPEC && num_v6 != 0)) {
552 size_t exthdr_len = 0;
553
554 if (send_reply) {
555 exthdr_len = sizeof (struct ip6_rthdr0) +
556 2 * num_gw * sizeof (struct in6_addr);
557 } else if (num_gw > 0) {
558 exthdr_len = sizeof (struct ip6_rthdr0) +
559 num_gw * sizeof (struct in6_addr);
560 }
561
562 /*
563 * Size of ICMP6 header and UDP header are the same. Let's
564 * use ICMP6_MINLEN.
565 */
566 if (datalen > (IP_MAXPACKET - (sizeof (struct ip6_hdr) +
567 exthdr_len + ICMP6_MINLEN))) {
568 Fprintf(stderr,
569 "%s: data size too large for IPv6 packet\n",
570 progname);
571 num_v6 = 0;
572 }
573 }
574
575 if (family_input == AF_INET ||
576 (family_input == AF_UNSPEC && num_v4 != 0)) {
577 size_t opt_len = 0;
578
579 if (send_reply) {
580 /*
581 * Includes 3 bytes code+ptr+len, the intermediate
582 * gateways, the actual and the effective target.
583 */
584 opt_len = 3 +
585 (2 * num_gw + 2) * sizeof (struct in_addr);
586 } else if (num_gw > 0) {
587 opt_len = 3 + (num_gw + 1) * sizeof (struct in_addr);
588 }
589
590 if (rr_option) {
591 opt_len = MAX_IPOPTLEN;
592 } else if (ts_option) {
593 if ((ts_flag & 0x0f) <= IPOPT_TS_TSANDADDR) {
594 opt_len = MAX_IPOPTLEN;
595 } else {
596 opt_len += IPOPT_MINOFF +
597 2 * sizeof (struct ipt_ta);
598 /*
599 * Note: BSD/4.X is broken in their check so we
600 * have to bump up this number by at least one.
601 */
602 opt_len++;
603 }
604 }
605
606 /* Round up to 4 byte boundary */
607 if (opt_len & 0x3)
608 opt_len = (opt_len & ~0x3) + 4;
609
610 if (datalen > (IP_MAXPACKET - (sizeof (struct ip) + opt_len +
611 ICMP_MINLEN))) {
612 Fprintf(stderr,
613 "%s: data size too large for IPv4 packet\n",
614 progname);
615 num_v4 = 0;
616 }
617 }
618
619 if (num_v4 == 0 && num_v6 == 0) {
620 exit(EXIT_FAILURE);
621 }
622
623 /* setup the sockets */
624 if (num_v6 != 0) {
625 if (!setup_socket(AF_INET6, &send_sock6, &recv_sock6,
626 &if_index, &udp_src_port6, ai_nexthop))
627 exit(EXIT_FAILURE);
628 }
629
630 if (num_v4 != 0) {
631 if (!setup_socket(AF_INET, &send_sock, &recv_sock, &if_index,
632 &udp_src_port, ai_nexthop))
633 exit(EXIT_FAILURE);
634 }
635
636 __priv_relinquish();
637
638 /*
639 * If sending back to ourself, add the mirror image of current
640 * gateways, so that the probes travel to and from the target
641 * by visiting the same gateways in reverse order.
642 */
643 if (send_reply) {
644 if (num_v6 != 0)
645 mirror_gws(gw_IP_list6, AF_INET6);
646 if (num_v4 != 0)
647 mirror_gws(gw_IP_list, AF_INET);
648
649 /* We add 1 because we put the target as the middle gateway */
650 eff_num_gw = 2 * num_gw + 1;
651
652 } else {
653 eff_num_gw = num_gw;
654 }
655
656 targetaddr_list = build_targetaddr_list(ai_dst, src_addr_list);
657 current_targetaddr = targetaddr_list;
658
659 /*
660 * Set the starting_seq_num for the first targetaddr.
661 * If we are sending ICMP Echo Requests, the sequence number is same as
662 * ICMP sequence number, and it starts from zero. If we are sending UDP
663 * packets, the sequence number is the destination UDP port number,
664 * which starts from dest_port. At each probe, this sequence number is
665 * incremented by one.
666 * We set the starting_seq_num for first targetaddr here. The
667 * following ones will be set by looking at where we left with the last
668 * targetaddr.
669 */
670 current_targetaddr->starting_seq_num = use_udp ? dest_port : 0;
671
672 if (stats) {
673 if (probe_all || !nflag) {
674 Printf("PING %s: %d data bytes\n", targethost, datalen);
675 } else {
676 if (ai_dst->ai_family == AF_INET) {
677 (void) inet_ntop(AF_INET,
678 &((struct sockaddr_in *)(void *)
679 ai_dst->ai_addr)->sin_addr,
680 abuf, sizeof (abuf));
681 } else {
682 (void) inet_ntop(AF_INET6,
683 &((struct sockaddr_in6 *)(void *)
684 ai_dst->ai_addr)->sin6_addr,
685 abuf, sizeof (abuf));
686 }
687 Printf("PING %s (%s): %d data bytes\n",
688 targethost, abuf, datalen);
689 }
690 }
691
692 /* Let's get things going */
693 send_scheduled_probe();
694
695 /* SIGALRM is used to send the next scheduled probe */
696 (void) sigset(SIGALRM, sigalrm_handler);
697 schedule_sigalrm();
698
699 /*
700 * From now on, we'll always be listening to ICMP packets. As SIGALRM
701 * comes in, sigalrm_handler() will be invoked and send another
702 * probe.
703 */
704 recv_icmp_packet(ai_dst, recv_sock6, recv_sock, udp_src_port6,
705 udp_src_port);
706
707 return (EXIT_SUCCESS); /* should never come here */
708 }
709
710 /*
711 * Build the target IP address list. Use command line options and
712 * name lookup results returned from name server to determine which addresses
713 * to probe, how many times, in which order.
714 */
715 static struct targetaddr *
build_targetaddr_list(struct addrinfo * ai_dst,union any_in_addr * src_addr_list)716 build_targetaddr_list(struct addrinfo *ai_dst, union any_in_addr *src_addr_list)
717 {
718 struct targetaddr *head = NULL;
719 struct targetaddr *targetaddr;
720 struct targetaddr **nextp;
721 int num_dst;
722 int i;
723 struct addrinfo *aip;
724
725 aip = ai_dst;
726 if (probe_all)
727 num_dst = num_v4 + num_v6;
728 else
729 num_dst = 1;
730 num_targetaddrs = num_dst;
731 nextp = &head;
732 for (aip = ai_dst, i = 0; aip != NULL; aip = aip->ai_next, i++) {
733 if (aip->ai_family == AF_INET && num_v4 != 0) {
734 targetaddr = create_targetaddr_item(aip->ai_family,
735 (union any_in_addr *)
736 /* LINTED E_BAD_PTR_CAST_ALIGN */
737 &((struct sockaddr_in *)
738 aip->ai_addr)->sin_addr,
739 &src_addr_list[i]);
740 } else if (aip->ai_family == AF_INET6 && num_v6 != 0) {
741 targetaddr = create_targetaddr_item(aip->ai_family,
742 (union any_in_addr *)
743 /* LINTED E_BAD_PTR_CAST_ALIGN */
744 &((struct sockaddr_in6 *)
745 aip->ai_addr)->sin6_addr,
746 &src_addr_list[i]);
747 } else {
748 continue;
749 }
750 *nextp = targetaddr;
751 nextp = &targetaddr->next;
752 if (num_targetaddrs == 1)
753 break;
754 }
755 if (npackets == 0 && stats)
756 *nextp = head; /* keep going indefinitely */
757
758 return (head);
759 }
760
761 /*
762 * Given an address family, dst and src addresses, by also looking at the
763 * options provided at the command line, this function creates a targetaddr
764 * to be linked with others, forming a global targetaddr list. Each targetaddr
765 * item contains information about probes sent to a specific IP address.
766 */
767 static struct targetaddr *
create_targetaddr_item(int family,union any_in_addr * dst_addr,union any_in_addr * src_addr)768 create_targetaddr_item(int family, union any_in_addr *dst_addr,
769 union any_in_addr *src_addr)
770 {
771 struct targetaddr *targetaddr;
772
773 targetaddr = (struct targetaddr *)malloc(sizeof (struct targetaddr));
774 if (targetaddr == NULL) {
775 Fprintf(stderr, "%s: malloc %s\n", progname, strerror(errno));
776 exit(EXIT_FAILURE);
777 }
778 targetaddr->family = family;
779 targetaddr->dst_addr = *dst_addr;
780 targetaddr->src_addr = *src_addr;
781 if (stats) {
782 /*
783 * npackets is only defined if we are in stats mode.
784 * npackets determines how many probes to send to each target
785 * IP address. npackets == 0 means send only 1 and move on to
786 * next target IP.
787 */
788 if (npackets > 0)
789 targetaddr->num_probes = npackets;
790 else
791 targetaddr->num_probes = 1;
792 } else {
793 targetaddr->num_probes = timeout;
794 }
795 targetaddr->num_sent = 0;
796 targetaddr->got_reply = _B_FALSE;
797 targetaddr->probing_done = _B_FALSE;
798 targetaddr->starting_seq_num = 0; /* actual value will be set later */
799 targetaddr->next = NULL; /* actual value will be set later */
800
801 return (targetaddr);
802 }
803
804 /*
805 * print "unknown host" message
806 */
807 static void
print_unknown_host_msg(const char * protocol,const char * hostname)808 print_unknown_host_msg(const char *protocol, const char *hostname)
809 {
810 Fprintf(stderr, "%s: unknown%s host %s\n", progname, protocol,
811 hostname);
812 }
813
814 /*
815 * Resolve hostnames for the target host and gateways. Also, determine source
816 * addresses to use for each target address.
817 */
818 static void
resolve_nodes(struct addrinfo ** ai_dstp,struct addrinfo ** ai_nexthopp,union any_in_addr ** src_addr_listp)819 resolve_nodes(struct addrinfo **ai_dstp, struct addrinfo **ai_nexthopp,
820 union any_in_addr **src_addr_listp)
821 {
822 struct addrinfo *ai_dst = NULL;
823 struct addrinfo *ai_nexthop = NULL;
824 struct addrinfo *aip = NULL;
825 union any_in_addr *src_addr_list = NULL;
826 int num_resolved_gw = 0;
827 int num_resolved_gw6 = 0;
828
829 get_hostinfo(targethost, family_input, &ai_dst);
830 if (ai_dst == NULL) {
831 print_unknown_host_msg("", targethost);
832 exit(EXIT_FAILURE);
833 }
834 if (nexthop != NULL) {
835 get_hostinfo(nexthop, family_input, &ai_nexthop);
836 if (ai_nexthop == NULL) {
837 print_unknown_host_msg("", nexthop);
838 exit(EXIT_FAILURE);
839 }
840 }
841 /* Get a count of the v4 & v6 addresses */
842 for (aip = ai_dst; aip != NULL; aip = aip->ai_next) {
843 switch (aip->ai_family) {
844 case AF_INET:
845 num_v4++;
846 break;
847 case AF_INET6:
848 num_v6++;
849 break;
850 }
851 }
852
853 if (family_input == AF_UNSPEC && !probe_all) {
854 family_input = ai_dst->ai_family;
855 }
856
857 /* resolve gateways */
858 if (num_gw > 0) {
859 get_gwaddrs(gw_list, family_input, gw_IP_list, gw_IP_list6,
860 &num_resolved_gw, &num_resolved_gw6);
861
862 /* we couldn't resolve a gateway as an IPv6 host */
863 if (num_resolved_gw6 != num_gw && num_v6 != 0 &&
864 (family_input == AF_INET6 || family_input == AF_UNSPEC)) {
865 print_unknown_host_msg(" IPv6",
866 gw_list[num_resolved_gw6]);
867 num_v6 = 0;
868 }
869
870 /* we couldn't resolve a gateway as an IPv4 host */
871 if (num_resolved_gw != num_gw && num_v4 != 0 &&
872 (family_input == AF_INET || family_input == AF_UNSPEC)) {
873 print_unknown_host_msg(" IPv4",
874 gw_list[num_resolved_gw]);
875 num_v4 = 0;
876 }
877 }
878
879 if (num_v4 == 0 && num_v6 == 0)
880 exit(EXIT_FAILURE);
881
882 select_all_src_addrs(&src_addr_list, ai_dst, gw_IP_list, gw_IP_list6);
883 *ai_dstp = ai_dst;
884 *ai_nexthopp = ai_nexthop;
885 *src_addr_listp = src_addr_list;
886 }
887
888 /*
889 * Resolve the gateway names, splitting results into v4 and v6 lists.
890 * Gateway addresses are added to the appropriate passed-in array; the
891 * number of resolved gateways for each af is returned in resolved[6].
892 * Assumes that passed-in arrays are large enough for MAX_GWS[6] addrs
893 * and resolved[6] ptrs are non-null; ignores array and counter if the
894 * address family param makes them irrelevant.
895 */
896 static void
get_gwaddrs(char ** gw_list,int family,union any_in_addr * gwIPlist,union any_in_addr * gwIPlist6,int * resolved,int * resolved6)897 get_gwaddrs(char **gw_list, int family, union any_in_addr *gwIPlist,
898 union any_in_addr *gwIPlist6, int *resolved, int *resolved6)
899 {
900 int i;
901 boolean_t check_v4 = _B_TRUE, check_v6 = _B_TRUE;
902 struct addrinfo *ai = NULL;
903 struct addrinfo *aip = NULL;
904
905 *resolved = *resolved6 = 0;
906 switch (family) {
907 case AF_UNSPEC:
908 break;
909 case AF_INET:
910 check_v6 = _B_FALSE;
911 break;
912 case AF_INET6:
913 check_v4 = _B_FALSE;
914 break;
915 default:
916 return;
917 }
918
919 if (check_v4 && num_gw >= MAX_GWS) {
920 check_v4 = _B_FALSE;
921 Fprintf(stderr, "%s: too many IPv4 gateways\n", progname);
922 }
923 if (check_v6 && num_gw > MAX_GWS6) {
924 check_v6 = _B_FALSE;
925 Fprintf(stderr, "%s: too many IPv6 gateways\n", progname);
926 }
927
928 for (i = 0; i < num_gw; i++) {
929 if (!check_v4 && !check_v6)
930 return;
931 get_hostinfo(gw_list[i], family, &ai);
932 if (ai == NULL)
933 return;
934 if (check_v4 && num_v4 != 0) {
935 for (aip = ai; aip != NULL; aip = aip->ai_next) {
936 if (aip->ai_family == AF_INET) {
937 /* LINTED E_BAD_PTR_CAST_ALIGN */
938 bcopy(&((struct sockaddr_in *)
939 aip->ai_addr)->sin_addr,
940 &gwIPlist[i].addr,
941 aip->ai_addrlen);
942 (*resolved)++;
943 break;
944 }
945 }
946 } else if (check_v4) {
947 check_v4 = _B_FALSE;
948 }
949 if (check_v6 && num_v6 != 0) {
950 for (aip = ai; aip != NULL; aip = aip->ai_next) {
951 if (aip->ai_family == AF_INET6) {
952 /* LINTED E_BAD_PTR_CAST_ALIGN */
953 bcopy(&((struct sockaddr_in6 *)
954 aip->ai_addr)->sin6_addr,
955 &gwIPlist6[i].addr6,
956 aip->ai_addrlen);
957 (*resolved6)++;
958 break;
959 }
960 }
961 } else if (check_v6) {
962 check_v6 = _B_FALSE;
963 }
964 }
965 freeaddrinfo(ai);
966 }
967
968 /*
969 * Given the list of gateways, extends the list with its mirror image. This is
970 * used when -l/-S is used. The middle gateway will be the target address. We'll
971 * leave it blank for now.
972 */
973 static void
mirror_gws(union any_in_addr * gwIPlist,int family)974 mirror_gws(union any_in_addr *gwIPlist, int family)
975 {
976 int effective_num_gw;
977 int i;
978
979 /* We add 1 because we put the target as the middle gateway */
980 effective_num_gw = 2 * num_gw + 1;
981
982 if ((family == AF_INET && effective_num_gw >= MAX_GWS) ||
983 (family == AF_INET6 && effective_num_gw > MAX_GWS6)) {
984 Fprintf(stderr, "%s: too many %s gateways\n",
985 progname, (family == AF_INET) ? "IPv4" : "IPv6");
986 exit(EXIT_FAILURE);
987 }
988
989 for (i = 0; i < num_gw; i++)
990 gwIPlist[num_gw + i + 1].addr6 = gwIPlist[num_gw - i - 1].addr6;
991 }
992
993 /*
994 * Given IP address or hostname, return addrinfo list.
995 * Assumes that addrinfo ** ptr is non-null.
996 */
997 static void
get_hostinfo(char * host,int family,struct addrinfo ** aipp)998 get_hostinfo(char *host, int family, struct addrinfo **aipp)
999 {
1000 struct addrinfo hints, *ai;
1001 struct in6_addr addr6;
1002 struct in_addr addr;
1003 boolean_t broadcast; /* is this 255.255.255.255? */
1004 char tmp_buf[INET6_ADDRSTRLEN];
1005 int rc;
1006
1007 /* check if broadcast */
1008 if (strcmp(host, "255.255.255.255") == 0)
1009 broadcast = _B_TRUE;
1010 else
1011 broadcast = _B_FALSE;
1012
1013 /* check if IPv4-mapped address or broadcast */
1014 if (((inet_pton(AF_INET6, host, &addr6) > 0) &&
1015 IN6_IS_ADDR_V4MAPPED(&addr6)) || broadcast) {
1016 if (!broadcast) {
1017 /*
1018 * Peel off the "mapping" stuff, leaving 32 bit IPv4
1019 * address.
1020 */
1021 IN6_V4MAPPED_TO_INADDR(&addr6, &addr);
1022
1023 /* convert it back to a string */
1024 (void) inet_ntop(AF_INET, (void *)&addr, tmp_buf,
1025 sizeof (tmp_buf));
1026 /*
1027 * Now the host is an IPv4 address.
1028 * Since it previously was a v4 mapped v6 address
1029 * we can be sure that the size of buffer 'host'
1030 * is large enough to contain the associated v4
1031 * address and so we don't need to use a strn/lcpy
1032 * here.
1033 */
1034 (void) strcpy(host, tmp_buf);
1035 }
1036 /*
1037 * If it's a broadcast address, it cannot be an IPv6 address.
1038 * Also, if it's a mapped address, we convert it into IPv4
1039 * address because ping will send and receive IPv4 packets for
1040 * that address. Therefore, it's a failure case to ask
1041 * get_hostinfo() to treat a broadcast or a mapped address
1042 * as an IPv6 address.
1043 */
1044 if (family == AF_INET6) {
1045 return;
1046 }
1047 }
1048
1049 (void) memset(&hints, 0, sizeof (hints));
1050 hints.ai_family = family;
1051 hints.ai_flags = AI_ADDRCONFIG;
1052 rc = getaddrinfo(host, NULL, &hints, &ai);
1053 if (rc != 0) {
1054 if (rc != EAI_NONAME)
1055 Fprintf(stderr, "%s: getaddrinfo: %s\n", progname,
1056 gai_strerror(rc));
1057 return;
1058 }
1059 *aipp = ai;
1060 }
1061
1062 /*
1063 * For each IP address of the target host, determine a source address to use.
1064 */
1065 static void
select_all_src_addrs(union any_in_addr ** src_addr_list,struct addrinfo * ai,union any_in_addr * gwv4,union any_in_addr * gwv6)1066 select_all_src_addrs(union any_in_addr **src_addr_list, struct addrinfo *ai,
1067 union any_in_addr *gwv4, union any_in_addr *gwv6)
1068 {
1069 union any_in_addr *list;
1070 struct addrinfo *aip;
1071 int num_dst = 1;
1072 int i;
1073
1074 if (probe_all) {
1075 for (aip = ai; aip->ai_next != NULL; aip = aip->ai_next)
1076 num_dst++;
1077 }
1078
1079 list = calloc((size_t)num_dst, sizeof (union any_in_addr));
1080 if (list == NULL) {
1081 Fprintf(stderr, "%s: calloc: %s\n", progname, strerror(errno));
1082 exit(EXIT_FAILURE);
1083 }
1084
1085 /*
1086 * If there's a gateway, a routing header as a consequence, our kernel
1087 * picks the source address based on the first hop address, rather than
1088 * final destination address.
1089 */
1090 if (num_gw > 0) {
1091 if (ai->ai_family == AF_INET)
1092 select_src_addr(gwv4, ai->ai_family, &list[0]);
1093 else
1094 select_src_addr(gwv6, ai->ai_family, &list[0]);
1095 /*
1096 * Since the first gateway address is fixed, we'll use the same
1097 * src address for every different final destination address
1098 * we send to.
1099 */
1100 for (i = 1; i < num_dst; i++)
1101 list[i] = list[0];
1102 } else {
1103 /*
1104 * Although something like 'ping -l host' results in a routing
1105 * header, the first gateway address is the target host's
1106 * address. Therefore, as far as src address selection goes,
1107 * the result is same as having no routing header.
1108 */
1109 for (i = 0, aip = ai; i < num_dst && aip != NULL;
1110 i++, aip = aip->ai_next) {
1111 if (aip->ai_family == AF_INET) {
1112 if (num_v4 != 0) {
1113 select_src_addr((union any_in_addr *)
1114 /* LINTED E_BAD_PTR_CAST_ALIGN */
1115 &((struct sockaddr_in *)
1116 aip->ai_addr)->sin_addr,
1117 aip->ai_family,
1118 &list[i]);
1119 }
1120 } else {
1121 if (num_v6 != 0) {
1122 select_src_addr((union any_in_addr *)
1123 /* LINTED E_BAD_PTR_CAST_ALIGN */
1124 &((struct sockaddr_in6 *)
1125 aip->ai_addr)->sin6_addr,
1126 aip->ai_family,
1127 &list[i]);
1128 }
1129 }
1130 }
1131 }
1132
1133 *src_addr_list = list;
1134 }
1135
1136 /*
1137 * For a given destination address, determine a source address to use.
1138 * Returns wildcard address if it cannot determine the source address.
1139 */
1140 static void
select_src_addr(union any_in_addr * dst_addr,int family,union any_in_addr * src_addr)1141 select_src_addr(union any_in_addr *dst_addr, int family,
1142 union any_in_addr *src_addr)
1143 {
1144 struct sockaddr *sock;
1145 struct sockaddr_in *sin;
1146 struct sockaddr_in6 *sin6;
1147 int tmp_fd;
1148 size_t sock_len;
1149
1150 sock = (struct sockaddr *)malloc(sizeof (struct sockaddr_in6));
1151 if (sock == NULL) {
1152 Fprintf(stderr, "%s: malloc: %s\n", progname, strerror(errno));
1153 exit(EXIT_FAILURE);
1154 }
1155 (void) bzero(sock, sizeof (struct sockaddr_in6));
1156
1157 if (family == AF_INET) {
1158 /* LINTED E_BAD_PTR_CAST_ALIGN */
1159 sin = (struct sockaddr_in *)sock;
1160 sin->sin_family = AF_INET;
1161 sin->sin_addr = dst_addr->addr;
1162 sin->sin_port = IPPORT_ECHO; /* port shouldn't be 0 */
1163 sock_len = sizeof (struct sockaddr_in);
1164 } else {
1165 /* LINTED E_BAD_PTR_CAST_ALIGN */
1166 sin6 = (struct sockaddr_in6 *)sock;
1167 sin6->sin6_family = AF_INET6;
1168 sin6->sin6_addr = dst_addr->addr6;
1169 sin6->sin6_port = IPPORT_ECHO; /* port shouldn't be 0 */
1170 sock_len = sizeof (struct sockaddr_in6);
1171 }
1172
1173 /* open a UDP socket */
1174 if ((tmp_fd = socket(family, SOCK_DGRAM, 0)) < 0) {
1175 Fprintf(stderr, "%s: udp socket: %s\n", progname,
1176 strerror(errno));
1177 exit(EXIT_FAILURE);
1178 }
1179
1180 /* connect it */
1181 if (connect(tmp_fd, sock, sock_len) < 0) {
1182 /*
1183 * If there's no route to the destination, this connect() call
1184 * fails. We just return all-zero (wildcard) as the source
1185 * address, so that user can get to see "no route to dest"
1186 * message, as it'll try to send the probe packet out and will
1187 * receive ICMP unreachable.
1188 */
1189 if (family == AF_INET)
1190 src_addr->addr.s_addr = INADDR_ANY;
1191 else
1192 src_addr->addr6 = in6addr_any;
1193 free(sock);
1194 return;
1195 }
1196
1197 /* get the local sock info */
1198 if (getsockname(tmp_fd, sock, &sock_len) < 0) {
1199 Fprintf(stderr, "%s: getsockname: %s\n", progname,
1200 strerror(errno));
1201 exit(EXIT_FAILURE);
1202 }
1203
1204 if (family == AF_INET) {
1205 src_addr->addr = sin->sin_addr;
1206 } else {
1207 src_addr->addr6 = sin6->sin6_addr;
1208 }
1209
1210 (void) close(tmp_fd);
1211 free(sock);
1212 }
1213
1214 /*
1215 * Set the IP_NEXTHOP/IPV6_NEXTHOP socket option.
1216 * exits on failure
1217 */
1218 static void
set_nexthop(int family,struct addrinfo * ai_nexthop,int sock)1219 set_nexthop(int family, struct addrinfo *ai_nexthop, int sock)
1220 {
1221 if (family == AF_INET) {
1222 ipaddr_t nh;
1223
1224 /* LINTED E_BAD_PTR_CAST_ALIGN */
1225 nh = ((struct sockaddr_in *)ai_nexthop->
1226 ai_addr)->sin_addr.s_addr;
1227
1228 /* now we need the sys_ip_config privilege */
1229 (void) __priv_bracket(PRIV_ON);
1230 if (setsockopt(sock, IPPROTO_IP, IP_NEXTHOP,
1231 &nh, sizeof (ipaddr_t)) < 0) {
1232 if (errno == EPERM)
1233 Fprintf(stderr, "%s: Insufficient privilege "
1234 "to specify IPv4 nexthop router.\n",
1235 progname);
1236 else
1237 Fprintf(stderr, "%s: setsockopt %s\n",
1238 progname, strerror(errno));
1239 exit(EXIT_FAILURE);
1240 }
1241 (void) __priv_bracket(PRIV_OFF);
1242 /* revert to non-privileged user */
1243 } else {
1244 struct sockaddr_in6 *nh;
1245
1246 /* LINTED E_BAD_PTR_CAST_ALIGN */
1247 nh = (struct sockaddr_in6 *)ai_nexthop->
1248 ai_addr;
1249
1250 if (setsockopt(sock, IPPROTO_IPV6, IPV6_NEXTHOP,
1251 nh, sizeof (struct sockaddr_in6)) < 0) {
1252 Fprintf(stderr, "%s: setsockopt %s\n",
1253 progname, strerror(errno));
1254 exit(EXIT_FAILURE);
1255 }
1256 }
1257 }
1258
1259 /*
1260 * Setup the socket for the given address family.
1261 * Returns _B_TRUE on success, _B_FALSE on failure. Failure is the case when no
1262 * interface can be found, or the specified interface (-i) is not found. On
1263 * library call failures, it exit()s.
1264 */
1265 static boolean_t
setup_socket(int family,int * send_sockp,int * recv_sockp,int * if_index,ushort_t * udp_src_port,struct addrinfo * ai_nexthop)1266 setup_socket(int family, int *send_sockp, int *recv_sockp, int *if_index,
1267 ushort_t *udp_src_port, struct addrinfo *ai_nexthop)
1268 {
1269 int send_sock;
1270 int recv_sock;
1271 struct sockaddr_in6 sin6;
1272 struct sockaddr_in sin;
1273 struct sockaddr *sp;
1274 struct ipsec_req req;
1275 size_t slen;
1276 int on = 1;
1277 uchar_t char_op;
1278 int int_op;
1279
1280 /* now we need the net_icmpaccess privilege */
1281 (void) __priv_bracket(PRIV_ON);
1282
1283 recv_sock = socket(family, SOCK_RAW,
1284 (family == AF_INET) ? IPPROTO_ICMP : IPPROTO_ICMPV6);
1285
1286 if (recv_sock < 0) {
1287 Fprintf(stderr, "%s: socket %s\n", progname, strerror(errno));
1288 exit(EXIT_FAILURE);
1289 }
1290
1291 /* revert to non-privileged user after opening sockets */
1292 (void) __priv_bracket(PRIV_OFF);
1293
1294 if (bypass) {
1295 (void) memset(&req, 0, sizeof (req));
1296 req.ipsr_ah_req = IPSEC_PREF_NEVER;
1297 req.ipsr_esp_req = IPSEC_PREF_NEVER;
1298
1299 if (setsockopt(recv_sock, (family == AF_INET) ? IPPROTO_IP :
1300 IPPROTO_IPV6, IP_SEC_OPT, &req, sizeof (req)) < 0) {
1301 switch (errno) {
1302 case EPROTONOSUPPORT:
1303 /*
1304 * No IPsec subsystem or policy loaded.
1305 * Bypass implicitly allowed.
1306 */
1307 break;
1308 case EPERM:
1309 Fprintf(stderr, "%s: Insufficient privilege "
1310 "to bypass IPsec policy.\n", progname);
1311 exit(EXIT_FAILURE);
1312 break;
1313 default:
1314 Fprintf(stderr, "%s: setsockopt %s\n", progname,
1315 strerror(errno));
1316 exit(EXIT_FAILURE);
1317 break;
1318 }
1319 }
1320 }
1321
1322 /*
1323 * We always receive on raw icmp socket. But the sending socket can be
1324 * raw icmp or udp, depending on the use of -U flag.
1325 */
1326 if (use_udp) {
1327 send_sock = socket(family, SOCK_DGRAM, IPPROTO_UDP);
1328 if (send_sock < 0) {
1329 Fprintf(stderr, "%s: socket %s\n", progname,
1330 strerror(errno));
1331 exit(EXIT_FAILURE);
1332 }
1333
1334 if (bypass) {
1335 if (setsockopt(send_sock, (family == AF_INET) ?
1336 IPPROTO_IP : IPPROTO_IPV6, IP_SEC_OPT, &req,
1337 sizeof (req)) < 0) {
1338 switch (errno) {
1339 case EPROTONOSUPPORT:
1340 /*
1341 * No IPsec subsystem or policy loaded.
1342 * Bypass implicitly allowed.
1343 */
1344 break;
1345 case EPERM:
1346 Fprintf(stderr, "%s: Insufficient "
1347 "privilege to bypass IPsec "
1348 "policy.\n", progname);
1349 exit(EXIT_FAILURE);
1350 break;
1351 default:
1352 Fprintf(stderr, "%s: setsockopt %s\n",
1353 progname, strerror(errno));
1354 exit(EXIT_FAILURE);
1355 break;
1356 }
1357 }
1358 }
1359
1360 /*
1361 * In order to distinguish replies to our UDP probes from
1362 * other pings', we need to know our source port number.
1363 */
1364 if (family == AF_INET) {
1365 sp = (struct sockaddr *)&sin;
1366 slen = sizeof (sin);
1367 } else {
1368 sp = (struct sockaddr *)&sin6;
1369 slen = sizeof (sin6);
1370 }
1371 bzero(sp, slen);
1372 sp->sa_family = family;
1373
1374 /* Let's bind() send_sock to wildcard address and port */
1375 if (bind(send_sock, sp, slen) < 0) {
1376 Fprintf(stderr, "%s: bind %s\n", progname,
1377 strerror(errno));
1378 exit(EXIT_FAILURE);
1379 }
1380
1381 /* .... and see what port kernel picked for us */
1382 if (getsockname(send_sock, sp, &slen) < 0) {
1383 Fprintf(stderr, "%s: getsockname %s\n", progname,
1384 strerror(errno));
1385 exit(EXIT_FAILURE);
1386 }
1387 *udp_src_port = (family == AF_INET) ? sin.sin_port :
1388 sin6.sin6_port;
1389 } else {
1390 send_sock = recv_sock;
1391 }
1392
1393 if (nexthop != NULL)
1394 set_nexthop(family, ai_nexthop, send_sock);
1395
1396 int_op = 48 * 1024;
1397 if (int_op < datalen)
1398 int_op = datalen;
1399 if (setsockopt(recv_sock, SOL_SOCKET, SO_RCVBUF, (char *)&int_op,
1400 sizeof (int_op)) == -1) {
1401 Fprintf(stderr, "%s: setsockopt SO_RCVBUF %s\n", progname,
1402 strerror(errno));
1403 exit(EXIT_FAILURE);
1404 }
1405
1406 if (setsockopt(send_sock, SOL_SOCKET, SO_SNDBUF, (char *)&int_op,
1407 sizeof (int_op)) == -1) {
1408 Fprintf(stderr, "%s: setsockopt SO_SNDBUF %s\n", progname,
1409 strerror(errno));
1410 exit(EXIT_FAILURE);
1411 }
1412
1413 if (options & SO_DEBUG) {
1414 if (setsockopt(send_sock, SOL_SOCKET, SO_DEBUG, (char *)&on,
1415 sizeof (on)) == -1) {
1416 Fprintf(stderr, "%s: setsockopt SO_DEBUG %s\n",
1417 progname, strerror(errno));
1418 exit(EXIT_FAILURE);
1419 }
1420 }
1421
1422 if (options & SO_DONTROUTE) {
1423 if (setsockopt(send_sock, SOL_SOCKET, SO_DONTROUTE, (char *)&on,
1424 sizeof (on)) == -1) {
1425 Fprintf(stderr, "%s: setsockopt SO_DONTROUTE %s\n",
1426 progname, strerror(errno));
1427 exit(EXIT_FAILURE);
1428 }
1429 }
1430
1431 if (moptions & MULTICAST_NOLOOP) {
1432 if (family == AF_INET) {
1433 char_op = 0; /* used to turn off option */
1434
1435 if (setsockopt(send_sock, IPPROTO_IP, IP_MULTICAST_LOOP,
1436 (char *)&char_op, sizeof (char_op)) == -1) {
1437 Fprintf(stderr, "%s: setsockopt "
1438 "IP_MULTICAST_NOLOOP %s\n", progname,
1439 strerror(errno));
1440 exit(EXIT_FAILURE);
1441 }
1442 } else {
1443 int_op = 0; /* used to turn off option */
1444
1445 if (setsockopt(send_sock, IPPROTO_IPV6,
1446 IPV6_MULTICAST_LOOP, (char *)&int_op,
1447 sizeof (int_op)) == -1) {
1448 Fprintf(stderr, "%s: setsockopt "
1449 "IPV6_MULTICAST_NOLOOP %s\n", progname,
1450 strerror(errno));
1451 exit(EXIT_FAILURE);
1452 }
1453 }
1454 }
1455
1456 if (moptions & MULTICAST_TTL) {
1457 char_op = hoplimit;
1458
1459 /* Applies to unicast and multicast. */
1460 if (family == AF_INET) {
1461 if (setsockopt(send_sock, IPPROTO_IP, IP_MULTICAST_TTL,
1462 (char *)&char_op, sizeof (char)) == -1) {
1463 Fprintf(stderr, "%s: setsockopt "
1464 "IP_MULTICAST_TTL %s\n", progname,
1465 strerror(errno));
1466 exit(EXIT_FAILURE);
1467 }
1468 if (setsockopt(send_sock, IPPROTO_IP, IP_TTL,
1469 (char *)&hoplimit, sizeof (hoplimit)) == -1) {
1470 Fprintf(stderr, "%s: setsockopt IP_TTL %s\n",
1471 progname, strerror(errno));
1472 exit(EXIT_FAILURE);
1473 }
1474 }
1475 /*
1476 * AF_INET6 case is handled in set_ancillary_data() function.
1477 * This is because when ancillary data is used (for routing
1478 * header and outgoing interface index), the hoplimit set using
1479 * setsockopt() is ignored.
1480 */
1481 }
1482
1483 /*
1484 * did the user specify an interface?
1485 * Applies to unicast, broadcast and multicast.
1486 */
1487 if (moptions & MULTICAST_IF) {
1488 struct ifaddrlist *al = NULL; /* interface list */
1489 struct ifaddrlist *my_if;
1490 char errbuf[ERRBUFSIZE];
1491 int num_ifs;
1492 int num_src_ifs; /* exclude down and loopback */
1493 int i;
1494
1495 /* pull out the interface list */
1496 num_ifs = ifaddrlist(&al, family, LIFC_UNDER_IPMP, errbuf);
1497 if (num_ifs == -1) {
1498 Fprintf(stderr, "%s: %s\n", progname, errbuf);
1499 exit(EXIT_FAILURE);
1500 }
1501
1502 /* filter out down and loopback interfaces */
1503 num_src_ifs = 0;
1504 for (i = 0; i < num_ifs; i++) {
1505 if (!(al[i].flags & IFF_LOOPBACK) &&
1506 (al[i].flags & IFF_UP))
1507 num_src_ifs++;
1508 }
1509
1510 if (num_src_ifs == 0) {
1511 Fprintf(stderr, "%s: can't find any %s interface\n",
1512 progname, (family == AF_INET) ? "IPv4" : "IPv6");
1513
1514 return (_B_FALSE); /* failure */
1515 }
1516
1517 /* locate the specified interface */
1518 my_if = find_if(al, num_ifs);
1519 if (my_if == NULL) {
1520 Fprintf(stderr, "%s: %s is an invalid %s interface\n",
1521 progname, out_if.str,
1522 (family == AF_INET) ? "IPv4" : "IPv6");
1523
1524 return (_B_FALSE);
1525 }
1526
1527 if (family == AF_INET) {
1528 struct in_pktinfo pktinfo;
1529
1530 if (setsockopt(send_sock, IPPROTO_IP, IP_MULTICAST_IF,
1531 (char *)&my_if->addr.addr,
1532 sizeof (struct in_addr)) == -1) {
1533 Fprintf(stderr, "%s: setsockopt "
1534 "IP_MULTICAST_IF %s\n", progname,
1535 strerror(errno));
1536 exit(EXIT_FAILURE);
1537 }
1538 bzero(&pktinfo, sizeof (pktinfo));
1539 pktinfo.ipi_ifindex = my_if->index;
1540 if (setsockopt(send_sock, IPPROTO_IP, IP_PKTINFO,
1541 (char *)&pktinfo, sizeof (pktinfo)) == -1) {
1542 Fprintf(stderr, "%s: setsockopt "
1543 "IP_PKTINFO %s\n", progname,
1544 strerror(errno));
1545 exit(EXIT_FAILURE);
1546 }
1547 } else {
1548 /*
1549 * the outgoing interface is set in set_ancillary_data()
1550 * function
1551 */
1552 *if_index = my_if->index;
1553 }
1554
1555 free(al);
1556 }
1557
1558 if (settos && family == AF_INET) {
1559 int_op = tos;
1560 if (setsockopt(send_sock, IPPROTO_IP, IP_TOS, (char *)&int_op,
1561 sizeof (int_op)) == -1) {
1562 Fprintf(stderr, "%s: setsockopt IP_TOS %s\n",
1563 progname, strerror(errno));
1564 exit(EXIT_FAILURE);
1565 }
1566 }
1567
1568 /* We enable or disable to not depend on the kernel default */
1569 if (family == AF_INET) {
1570 if (setsockopt(send_sock, IPPROTO_IP, IP_DONTFRAG,
1571 (char *)&dontfrag, sizeof (dontfrag)) == -1) {
1572 Fprintf(stderr, "%s: setsockopt IP_DONTFRAG %s\n",
1573 progname, strerror(errno));
1574 exit(EXIT_FAILURE);
1575 }
1576 } else {
1577 if (setsockopt(send_sock, IPPROTO_IPV6, IPV6_DONTFRAG,
1578 (char *)&dontfrag, sizeof (dontfrag)) == -1) {
1579 Fprintf(stderr, "%s: setsockopt IPV6_DONTFRAG %s\n",
1580 progname, strerror(errno));
1581 exit(EXIT_FAILURE);
1582 }
1583 }
1584
1585 /* receiving IPv6 extension headers in verbose mode */
1586 if (verbose && family == AF_INET6) {
1587 if (setsockopt(recv_sock, IPPROTO_IPV6, IPV6_RECVHOPOPTS,
1588 (char *)&on, sizeof (on)) == -1) {
1589 Fprintf(stderr, "%s: setsockopt IPV6_RECVHOPOPTS %s\n",
1590 progname, strerror(errno));
1591 exit(EXIT_FAILURE);
1592 }
1593
1594 if (setsockopt(recv_sock, IPPROTO_IPV6, IPV6_RECVDSTOPTS,
1595 (char *)&on, sizeof (on)) == -1) {
1596 Fprintf(stderr, "%s: setsockopt IPV6_RECVDSTOPTS %s\n",
1597 progname, strerror(errno));
1598 exit(EXIT_FAILURE);
1599 }
1600
1601 if (setsockopt(recv_sock, IPPROTO_IPV6, IPV6_RECVRTHDR,
1602 (char *)&on, sizeof (on)) == -1) {
1603 Fprintf(stderr, "%s: setsockopt IPV6_RECVRTHDR %s\n",
1604 progname, strerror(errno));
1605 exit(EXIT_FAILURE);
1606 }
1607 }
1608
1609 *send_sockp = send_sock;
1610 *recv_sockp = recv_sock;
1611
1612 /* successful */
1613 return (_B_TRUE);
1614 }
1615
1616 /*
1617 * Pull out the record containing all the info about the interface specified by
1618 * `out_if'. Skips interfaces which are down or loopback.
1619 */
1620 static struct ifaddrlist *
find_if(struct ifaddrlist * al,int num_ifs)1621 find_if(struct ifaddrlist *al, int num_ifs)
1622 {
1623 static struct ifaddrlist tmp_if;
1624 boolean_t found;
1625 int i;
1626
1627 i = 0;
1628 found = _B_FALSE;
1629
1630 while (i < num_ifs && !found) {
1631 tmp_if = al[i];
1632
1633 /* skip down or loopback interfaces */
1634 if ((tmp_if.flags & IFF_LOOPBACK) || !(tmp_if.flags & IFF_UP)) {
1635 i++;
1636 continue;
1637 }
1638
1639 /* the type of interface id is variable */
1640 switch (out_if.id_type) {
1641 case IF_INDEX:
1642 if (out_if.id.index == tmp_if.index)
1643 found = _B_TRUE;
1644 break;
1645
1646 case IF_NAME:
1647 if (strcmp(out_if.id.name, tmp_if.device) == 0)
1648 found = _B_TRUE;
1649 break;
1650
1651 case IF_ADDR:
1652 if (out_if.id.addr.addr.s_addr ==
1653 tmp_if.addr.addr.s_addr) {
1654 found = _B_TRUE;
1655 }
1656 break;
1657
1658 case IF_ADDR6:
1659 if (IN6_ARE_ADDR_EQUAL(&out_if.id.addr.addr6,
1660 &tmp_if.addr.addr6)) {
1661 found = _B_TRUE;
1662 }
1663 break;
1664
1665 default:
1666 break;
1667 }
1668
1669 i++;
1670 }
1671
1672 if (found)
1673 return (&tmp_if);
1674 else
1675 return (NULL);
1676 }
1677
1678 /*
1679 * Invoked by SIGALRM, sigalrm_handler() is, responsible for calling
1680 * send_scheduled_probe() to send next probe.
1681 */
1682 void
sigalrm_handler(void)1683 sigalrm_handler(void)
1684 {
1685 /*
1686 * Guard againist denial-of-service attacks. Make sure ping doesn't
1687 * send probes for every SIGALRM it receives. Evil hacker can generate
1688 * SIGALRMs as fast as it can, but ping will ignore those which are
1689 * received too soon (earlier than 0.5 sec) after it sent the last
1690 * probe. We use gethrtime() instead of gettimeofday() because
1691 * the latter is not linear and is prone to resetting or drifting
1692 */
1693 if ((gethrtime() - t_last_probe_sent) < 500000000) {
1694 return;
1695 }
1696 send_scheduled_probe();
1697 schedule_sigalrm();
1698 }
1699
1700 /*
1701 * Schedule next SIGALRM.
1702 */
1703 void
schedule_sigalrm(void)1704 schedule_sigalrm(void)
1705 {
1706 int waittime;
1707
1708 if (npackets == 0 ||
1709 current_targetaddr->num_sent < current_targetaddr->num_probes) {
1710 (void) alarm(interval);
1711 } else {
1712 if (current_targetaddr->got_reply) {
1713 waittime = 2 * tmax / MICROSEC;
1714 if (waittime == 0)
1715 waittime = 1;
1716 } else {
1717 waittime = MAX_WAIT;
1718 }
1719 (void) alarm(waittime);
1720 }
1721 }
1722
1723 /*
1724 * Called by sigalrm_handler(), check_reply() or check_reply6(),
1725 * send_scheduled_probe() looks at the current_targetaddr and determines what
1726 * should be sent next and calls pinger().
1727 */
1728 void
send_scheduled_probe()1729 send_scheduled_probe()
1730 {
1731 static struct msghdr msg6;
1732 static boolean_t first_probe = _B_TRUE;
1733 char tmp_buf[INET6_ADDRSTRLEN];
1734
1735 /*
1736 * We are about to move to next targetaddr if it's either we sent
1737 * all the probes, or somebody set the probing_done flag to
1738 * _B_TRUE prompting us to move on.
1739 */
1740 if (current_targetaddr->num_sent == current_targetaddr->num_probes ||
1741 current_targetaddr->probing_done) {
1742 /*
1743 * is this a dead target?
1744 */
1745 if (!stats && !current_targetaddr->got_reply) {
1746 if (!probe_all) {
1747 Printf("no answer from %s\n", targethost);
1748 } else {
1749 Printf("no answer from %s(%s)\n", targethost,
1750 inet_ntop(current_targetaddr->family,
1751 ¤t_targetaddr->dst_addr,
1752 tmp_buf, sizeof (tmp_buf)));
1753 }
1754 }
1755 /*
1756 * Before we move onto next item, let's do some clean up.
1757 */
1758 current_targetaddr->got_reply = _B_FALSE;
1759 current_targetaddr->probing_done = _B_FALSE;
1760 /*
1761 * If this is probe-all without stats mode, then we need to
1762 * preserve this count. This is needed when we try to map an
1763 * icmp_seq to IP address. Otherwise, clear it.
1764 */
1765 if (stats || !probe_all)
1766 current_targetaddr->num_sent = 0;
1767 nreceived_last_target = 0;
1768
1769 current_targetaddr = current_targetaddr->next;
1770
1771 /*
1772 * Did we reach the end of road?
1773 */
1774 if (current_targetaddr == NULL) {
1775 (void) alarm(0); /* cancel alarm */
1776 if (stats)
1777 finish();
1778 if (is_alive)
1779 exit(EXIT_SUCCESS);
1780 else
1781 exit(EXIT_FAILURE);
1782 } else {
1783 /*
1784 * We use starting_seq_num for authenticating replies.
1785 * Each time we move to a new targetaddr, which has
1786 * a different target IP address, we update this field.
1787 */
1788 current_targetaddr->starting_seq_num = use_udp ?
1789 dest_port : (ntransmitted % (MAX_ICMP_SEQ + 1));
1790 }
1791 }
1792
1793 if (current_targetaddr->family == AF_INET6) {
1794 if (send_reply) {
1795 /* sending back to ourself */
1796 to6.sin6_addr = current_targetaddr->src_addr.addr6;
1797 } else {
1798 to6.sin6_addr = current_targetaddr->dst_addr.addr6;
1799 }
1800 /*
1801 * Setting the ancillary data once is enough, if we are
1802 * not using source routing through target (-l/-S). In
1803 * case -l/-S used, the middle gateway will be the
1804 * IP address of the source, which can be different
1805 * for each target IP.
1806 */
1807 if (first_probe ||
1808 (send_reply && current_targetaddr->num_sent == 0)) {
1809 if (send_reply) {
1810 /* target is the middle gateway now */
1811 gw_IP_list6[num_gw].addr6 =
1812 current_targetaddr->dst_addr.addr6;
1813 }
1814 set_ancillary_data(&msg6, hoplimit, gw_IP_list6,
1815 eff_num_gw, if_index);
1816 first_probe = _B_FALSE;
1817 }
1818 pinger(send_sock6, (struct sockaddr *)&to6, &msg6, AF_INET6);
1819 } else {
1820 to.sin_addr = current_targetaddr->dst_addr.addr;
1821 /*
1822 * Set IPv4 options when sending the first probe to a target
1823 * IP address. Some options change when the target address
1824 * changes.
1825 */
1826 if (current_targetaddr->num_sent == 0) {
1827 if (eff_num_gw > 0) {
1828 gw_IP_list[num_gw].addr =
1829 current_targetaddr->dst_addr.addr;
1830 /*
1831 * If send_reply, the target becomes the
1832 * middle gateway, sender becomes the last
1833 * gateway.
1834 */
1835 if (send_reply) {
1836 gw_IP_list[eff_num_gw].addr =
1837 current_targetaddr->src_addr.addr;
1838 }
1839 }
1840 /*
1841 * In IPv4, if source routing is used, the target
1842 * address shows up as the last gateway, hence +1.
1843 */
1844 set_IPv4_options(send_sock, gw_IP_list,
1845 (eff_num_gw > 0) ? eff_num_gw + 1 : 0,
1846 ¤t_targetaddr->src_addr.addr, &to.sin_addr);
1847 }
1848 pinger(send_sock, (struct sockaddr *)&to, NULL, AF_INET);
1849 }
1850
1851 current_targetaddr->num_sent++;
1852 }
1853
1854 /*
1855 * recv_icmp_packet()'s job is to listen to icmp packets and filter out
1856 * those ping is interested in.
1857 */
1858 static void
recv_icmp_packet(struct addrinfo * ai_dst,int recv_sock6,int recv_sock,ushort_t udp_src_port6,ushort_t udp_src_port)1859 recv_icmp_packet(struct addrinfo *ai_dst, int recv_sock6, int recv_sock,
1860 ushort_t udp_src_port6, ushort_t udp_src_port)
1861 {
1862 struct msghdr in_msg;
1863 struct iovec iov;
1864 struct sockaddr_in6 from6;
1865 fd_set fds;
1866 int result;
1867 int cc;
1868 boolean_t always_true = _B_TRUE; /* lint doesn't like while(_B_TRUE) */
1869
1870 while (always_true) {
1871 (void) FD_ZERO(&fds);
1872 if (recv_sock6 != -1)
1873 FD_SET(recv_sock6, &fds);
1874 if (recv_sock != -1)
1875 FD_SET(recv_sock, &fds);
1876
1877 result = select(MAX(recv_sock6, recv_sock) + 1, &fds,
1878 (fd_set *)NULL, (fd_set *)NULL, (struct timeval *)NULL);
1879 if (result == -1) {
1880 if (errno == EINTR) {
1881 continue;
1882 } else {
1883 Fprintf(stderr, "%s: select %s\n", progname,
1884 strerror(errno));
1885 exit(EXIT_FAILURE);
1886 }
1887 } else if (result > 0) {
1888 in_msg.msg_name = &from6;
1889 in_msg.msg_namelen = sizeof (from6);
1890 iov.iov_base = in_pkt;
1891 iov.iov_len = sizeof (in_pkt);
1892 in_msg.msg_iov = &iov;
1893 in_msg.msg_iovlen = 1;
1894 in_msg.msg_control = ancillary_data;
1895 in_msg.msg_controllen = sizeof (ancillary_data);
1896
1897 /* Do we have an ICMP6 packet waiting? */
1898 if ((recv_sock6 != -1) &&
1899 (FD_ISSET(recv_sock6, &fds))) {
1900 cc = recvmsg(recv_sock6, &in_msg, 0);
1901 if (cc < 0) {
1902 if (errno != EINTR) {
1903 Fprintf(stderr,
1904 "%s: recvmsg %s\n",
1905 progname, strerror(errno));
1906 }
1907 continue;
1908 } else if (cc > 0) {
1909 check_reply6(ai_dst, &in_msg, cc,
1910 udp_src_port6);
1911 }
1912 }
1913 /* Do we have an ICMP packet waiting? */
1914 if ((recv_sock != -1) && (FD_ISSET(recv_sock, &fds))) {
1915 cc = recvmsg(recv_sock, &in_msg, 0);
1916 if (cc < 0) {
1917 if (errno != EINTR) {
1918 Fprintf(stderr,
1919 "%s: recvmsg %s\n",
1920 progname, strerror(errno));
1921 }
1922 continue;
1923 } if (cc > 0) {
1924 check_reply(ai_dst, &in_msg, cc,
1925 udp_src_port);
1926 }
1927 }
1928 }
1929 /*
1930 * If we were probing last IP address of the target host and
1931 * received a reply for each probe sent to this address,
1932 * then we are done!
1933 */
1934 if ((npackets > 0) && (current_targetaddr->next == NULL) &&
1935 (nreceived_last_target == npackets)) {
1936 (void) alarm(0); /* cancel alarm */
1937 finish();
1938 }
1939 } /* infinite loop */
1940 }
1941
1942 /*
1943 * Given a host (with possibly multiple IP addresses) and an IP address, this
1944 * function determines if this IP address is one of the host's addresses to
1945 * which we're sending probes. Used to determine if we are interested in a
1946 * packet.
1947 */
1948 boolean_t
is_a_target(struct addrinfo * ai,union any_in_addr * addr)1949 is_a_target(struct addrinfo *ai, union any_in_addr *addr)
1950 {
1951 int num_addrs;
1952 int i;
1953 struct addrinfo *aip;
1954
1955 aip = ai;
1956 if (probe_all)
1957 num_addrs = num_v4 + num_v6;
1958 else
1959 num_addrs = 1;
1960 for (i = 0; i < num_addrs && aip != NULL; i++) {
1961 if (aip->ai_family == AF_INET6) {
1962 /* LINTED E_BAD_PTR_CAST_ALIGN */
1963 if (IN6_ARE_ADDR_EQUAL(&((struct sockaddr_in6 *)
1964 aip->ai_addr)->sin6_addr, &addr->addr6))
1965 return (_B_TRUE);
1966 } else {
1967 /* LINTED E_BAD_PTR_CAST_ALIGN */
1968 if (((struct sockaddr_in *)
1969 aip->ai_addr)->sin_addr.s_addr == addr->addr.s_addr)
1970 return (_B_TRUE);
1971 }
1972 }
1973
1974 return (_B_FALSE);
1975 }
1976
1977 /*
1978 * Compose and transmit an ICMP ECHO REQUEST packet. The IP packet
1979 * will be added on by the kernel. The ID field is our UNIX process ID,
1980 * and the sequence number is an ascending integer. The first 8 bytes
1981 * of the data portion are used to hold a UNIX "timeval" struct in network
1982 * byte-order, to compute the round-trip time.
1983 */
1984 static void
pinger(int send_sock,struct sockaddr * whereto,struct msghdr * msg6,int family)1985 pinger(int send_sock, struct sockaddr *whereto, struct msghdr *msg6,
1986 int family)
1987 {
1988 static uint64_t out_pkt_buf[(IP_MAXPACKET + 1) / 8];
1989 uchar_t *out_pkt = (uchar_t *)&out_pkt_buf;
1990 /* LINTED E_BAD_PTR_CAST_ALIGN */
1991 struct icmp *icp = (struct icmp *)out_pkt;
1992 /* LINTED E_BAD_PTR_CAST_ALIGN */
1993 struct sockaddr_in6 *to6 = (struct sockaddr_in6 *)whereto;
1994 /* LINTED E_BAD_PTR_CAST_ALIGN */
1995 struct sockaddr_in *to = (struct sockaddr_in *)whereto;
1996 struct timeval *tp;
1997 struct timeval t_snd;
1998 uchar_t *datap;
1999 struct iovec iov;
2000 int start = 0;
2001 int cc;
2002 int i;
2003
2004 /* using UDP? */
2005 if (use_udp) {
2006 cc = datalen;
2007
2008 /* LINTED E_BAD_PTR_CAST_ALIGN */
2009 tp = (struct timeval *)out_pkt;
2010 datap = &out_pkt[sizeof (struct timeval)];
2011
2012 /*
2013 * This sets the port whether we are handling a v4 or v6
2014 * sockaddr structure.
2015 */
2016 to->sin_port = htons(dest_port);
2017
2018 dest_port = (dest_port + 1) % (MAX_PORT + 1);
2019 ntransmitted++;
2020 } else { /* using ICMP */
2021 cc = datalen + ICMP_MINLEN;
2022
2023 if (family == AF_INET6) {
2024 icp->icmp_type = send_reply ?
2025 ICMP6_ECHO_REPLY : ICMP6_ECHO_REQUEST;
2026 } else if (use_icmp_ts) { /* family is AF_INET */
2027 icp->icmp_type = send_reply ?
2028 ICMP_TSTAMPREPLY : ICMP_TSTAMP;
2029 } else {
2030 icp->icmp_type = send_reply ?
2031 ICMP_ECHOREPLY : ICMP_ECHO;
2032 }
2033
2034 icp->icmp_code = 0;
2035 icp->icmp_cksum = 0;
2036 icp->icmp_seq = htons(ntransmitted++ % (MAX_ICMP_SEQ + 1));
2037 if (icp->icmp_seq == 0)
2038 num_wraps++;
2039 icp->icmp_id = htons(ident); /* ID */
2040
2041 /* LINTED E_BAD_PTR_CAST_ALIGN */
2042 tp = (struct timeval *)&out_pkt[ICMP_MINLEN];
2043 datap = &out_pkt[ICMP_MINLEN + sizeof (struct timeval)];
2044 }
2045
2046 start = sizeof (struct timeval); /* skip for time */
2047
2048 (void) gettimeofday(&t_snd, (struct timezone *)NULL);
2049
2050 /* if packet is big enough to store timeval OR ... */
2051 if ((datalen >= sizeof (struct timeval)) ||
2052 (family == AF_INET && use_icmp_ts))
2053 *tp = t_snd;
2054
2055 if (family == AF_INET && use_icmp_ts) {
2056 start = sizeof (struct id_ts); /* skip for ICMP timestamps */
2057 /* Number of milliseconds since midnight */
2058 icp->icmp_otime = htonl((tp->tv_sec % (24*60*60)) * 1000 +
2059 tp->tv_usec / 1000);
2060 }
2061
2062 for (i = start; i < datalen; i++)
2063 *datap++ = i;
2064
2065 if (family == AF_INET) {
2066 if (!use_udp)
2067 icp->icmp_cksum = in_cksum((ushort_t *)icp, cc);
2068
2069 i = sendto(send_sock, (char *)out_pkt, cc, 0, whereto,
2070 sizeof (struct sockaddr_in));
2071 } else {
2072 /*
2073 * Fill in the rest of the msghdr structure. msg_control is set
2074 * in set_ancillary_data().
2075 */
2076 msg6->msg_name = to6;
2077 msg6->msg_namelen = sizeof (struct sockaddr_in6);
2078
2079 iov.iov_base = out_pkt;
2080 iov.iov_len = cc;
2081
2082 msg6->msg_iov = &iov;
2083 msg6->msg_iovlen = 1;
2084
2085 i = sendmsg(send_sock, msg6, 0);
2086 }
2087
2088 /* This is a more precise time (right after we send the packet) */
2089 t_last_probe_sent = gethrtime();
2090
2091 if (i < 0 || i != cc) {
2092 if (i < 0) {
2093 Fprintf(stderr, "%s: sendto %s\n", progname,
2094 strerror(errno));
2095 if (!stats)
2096 exit(EXIT_FAILURE);
2097 }
2098 Printf("ping: wrote %s %d chars, ret=%d\n",
2099 targethost, cc, i);
2100 (void) fflush(stdout);
2101 }
2102 }
2103
2104 /*
2105 * Return a hostname for the given IP address.
2106 */
2107 char *
pr_name(char * addr,int family)2108 pr_name(char *addr, int family)
2109 {
2110 struct sockaddr_in sin;
2111 struct sockaddr_in6 sin6;
2112 struct sockaddr *sa;
2113 static struct in6_addr prev_addr = IN6ADDR_ANY_INIT;
2114 char *cp;
2115 char abuf[INET6_ADDRSTRLEN];
2116 static char buf[NI_MAXHOST + INET6_ADDRSTRLEN + 3];
2117 uint_t slen, alen, hlen;
2118
2119 switch (family) {
2120 case AF_INET:
2121 (void) memset(&sin, 0, sizeof (sin));
2122 slen = sizeof (struct sockaddr_in);
2123 alen = sizeof (struct in_addr);
2124 /* LINTED E_BAD_PTR_CAST_ALIGN */
2125 sin.sin_addr = *(struct in_addr *)addr;
2126 sin.sin_port = 0;
2127 sa = (struct sockaddr *)&sin;
2128 break;
2129 case AF_INET6:
2130 (void) memset(&sin6, 0, sizeof (sin6));
2131 slen = sizeof (struct sockaddr_in6);
2132 alen = sizeof (struct in6_addr);
2133 /* LINTED E_BAD_PTR_CAST_ALIGN */
2134 sin6.sin6_addr = *(struct in6_addr *)addr;
2135 sin6.sin6_port = 0;
2136 sa = (struct sockaddr *)&sin6;
2137 break;
2138 default:
2139 (void) snprintf(buf, sizeof (buf), "<invalid address family>");
2140 return (buf);
2141 }
2142 sa->sa_family = family;
2143
2144 /* compare with the buffered (previous) lookup */
2145 if (memcmp(addr, &prev_addr, alen) != 0) {
2146 int flags = (nflag) ? NI_NUMERICHOST : NI_NAMEREQD;
2147 if (getnameinfo(sa, slen, buf, sizeof (buf),
2148 NULL, 0, flags) != 0) {
2149 /* getnameinfo() failed; return just the address */
2150 if (inet_ntop(family, (const void*)addr,
2151 buf, sizeof (buf)) == NULL)
2152 buf[0] = 0;
2153 } else if (!nflag) {
2154 /* append numeric address to hostname string */
2155 hlen = strlen(buf);
2156 cp = (char *)(buf + hlen);
2157 (void) snprintf(cp, sizeof (buf) - hlen, " (%s)",
2158 inet_ntop(family, (const void *)addr, abuf,
2159 sizeof (abuf)));
2160 }
2161
2162 /* LINTED E_BAD_PTR_CAST_ALIGN */
2163 prev_addr = *(struct in6_addr *)addr;
2164 }
2165 return (buf);
2166 }
2167
2168 /*
2169 * Return the protocol string, given its protocol number.
2170 */
2171 char *
pr_protocol(int prot)2172 pr_protocol(int prot)
2173 {
2174 static char buf[20];
2175
2176 switch (prot) {
2177 case IPPROTO_ICMPV6:
2178 (void) strlcpy(buf, "icmp6", sizeof (buf));
2179 break;
2180
2181 case IPPROTO_ICMP:
2182 (void) strlcpy(buf, "icmp", sizeof (buf));
2183 break;
2184
2185 case IPPROTO_TCP:
2186 (void) strlcpy(buf, "tcp", sizeof (buf));
2187 break;
2188
2189 case IPPROTO_UDP:
2190 (void) strlcpy(buf, "udp", sizeof (buf));
2191 break;
2192
2193 default:
2194 (void) snprintf(buf, sizeof (buf), "prot %d", prot);
2195 break;
2196 }
2197
2198 return (buf);
2199 }
2200
2201 /*
2202 * Checks if value is between seq_begin and seq_begin+seq_len. Note that
2203 * sequence numbers wrap around after MAX_ICMP_SEQ (== MAX_PORT).
2204 */
2205 boolean_t
seq_match(ushort_t seq_begin,int seq_len,ushort_t value)2206 seq_match(ushort_t seq_begin, int seq_len, ushort_t value)
2207 {
2208 /*
2209 * If seq_len is too big, like some value greater than MAX_ICMP_SEQ/2,
2210 * truncate it down to MAX_ICMP_SEQ/2. We are not going to accept any
2211 * reply which come 83hr later!
2212 */
2213 if (seq_len > MAX_ICMP_SEQ / 2) {
2214 seq_begin = (seq_begin + seq_len - MAX_ICMP_SEQ / 2) %
2215 (MAX_ICMP_SEQ + 1);
2216 seq_len = MAX_ICMP_SEQ / 2;
2217 }
2218
2219 if (PINGSEQ_LEQ(seq_begin, value) &&
2220 PINGSEQ_LEQ(value, (seq_begin + seq_len - 1) % (MAX_ICMP_SEQ + 1)))
2221 return (_B_TRUE);
2222 else
2223 return (_B_FALSE);
2224 }
2225
2226 /*
2227 * For a given icmp_seq, find which destination address we must have sent this
2228 * to.
2229 */
2230 void
find_dstaddr(ushort_t icmpseq,union any_in_addr * ipaddr)2231 find_dstaddr(ushort_t icmpseq, union any_in_addr *ipaddr)
2232 {
2233 struct targetaddr *target = targetaddr_list;
2234 int real_seq;
2235 int targetaddr_index;
2236 int real_npackets;
2237 int i;
2238
2239 ipaddr->addr6 = in6addr_any;
2240
2241 /*
2242 * If this is probe_all and not stats, then the number of probes sent to
2243 * each IP address may be different (remember, we stop sending to one IP
2244 * address as soon as it replies). They are stored in target->num_sent
2245 * field. Since we don't wrap around the list (!stats), they are also
2246 * preserved.
2247 */
2248 if (probe_all && !stats) {
2249 do {
2250 if (seq_match(target->starting_seq_num,
2251 target->num_sent, icmpseq)) {
2252 ipaddr->addr6 = target->dst_addr.addr6;
2253 /*
2254 * We are not immediately return()ing here.
2255 * Because of wrapping, we might find another
2256 * match later, which is more likely to be the
2257 * real one.
2258 */
2259 }
2260 target = target->next;
2261 } while (target != NULL);
2262 } else {
2263 /*
2264 * Find the absolute (non-wrapped) seq number within the last
2265 * 64K
2266 */
2267 if (icmpseq < (ntransmitted % (MAX_ICMP_SEQ + 1))) {
2268 real_seq = num_wraps * (MAX_ICMP_SEQ + 1) + icmpseq;
2269 } else {
2270 real_seq = (num_wraps - 1) * (MAX_ICMP_SEQ + 1) +
2271 icmpseq;
2272 }
2273
2274 /* Make sure it's non-negative */
2275 if (real_seq < 0)
2276 return;
2277 real_npackets = (npackets == 0) ? 1 : npackets;
2278
2279 /*
2280 * We sent npackets many packets to each of those
2281 * num_targetaddrs many IP addresses.
2282 */
2283 targetaddr_index =
2284 (real_seq % (num_targetaddrs * real_npackets)) /
2285 real_npackets;
2286 for (i = 0; i < targetaddr_index; i++)
2287 target = target->next;
2288 ipaddr->addr6 = target->dst_addr.addr6;
2289 }
2290 }
2291
2292 /*
2293 * Checksum routine for Internet Protocol family headers (C Version)
2294 */
2295 static ushort_t
in_cksum(ushort_t * addr,int len)2296 in_cksum(ushort_t *addr, int len)
2297 {
2298 int nleft = len;
2299 ushort_t *w = addr;
2300 ushort_t answer;
2301 ushort_t odd_byte = 0;
2302 int sum = 0;
2303
2304 /*
2305 * Our algorithm is simple, using a 32 bit accumulator (sum),
2306 * we add sequential 16 bit words to it, and at the end, fold
2307 * back all the carry bits from the top 16 bits into the lower
2308 * 16 bits.
2309 */
2310 while (nleft > 1) {
2311 sum += *w++;
2312 nleft -= 2;
2313 }
2314
2315 /* mop up an odd byte, if necessary */
2316 if (nleft == 1) {
2317 *(uchar_t *)(&odd_byte) = *(uchar_t *)w;
2318 sum += odd_byte;
2319 }
2320
2321 /*
2322 * add back carry outs from top 16 bits to low 16 bits
2323 */
2324 sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
2325 sum += (sum >> 16); /* add carry */
2326 answer = ~sum; /* truncate to 16 bits */
2327 return (answer);
2328 }
2329
2330 /*
2331 * Subtract 2 timeval structs: out = out - in.
2332 * Out is assumed to be >= in.
2333 */
2334 void
tvsub(struct timeval * out,struct timeval * in)2335 tvsub(struct timeval *out, struct timeval *in)
2336 {
2337 if ((out->tv_usec -= in->tv_usec) < 0) {
2338 out->tv_sec--;
2339 out->tv_usec += 1000000;
2340 }
2341 out->tv_sec -= in->tv_sec;
2342 }
2343
2344 /*
2345 * Print out statistics, and give up.
2346 * Heavily buffered STDIO is used here, so that all the statistics
2347 * will be written with 1 sys-write call. This is nice when more
2348 * than one copy of the program is running on a terminal; it prevents
2349 * the statistics output from becoming intermingled.
2350 */
2351 static void
finish()2352 finish()
2353 {
2354 Printf("\n----%s PING Statistics----\n", targethost);
2355 Printf("%d packets transmitted, ", ntransmitted);
2356 Printf("%d packets received, ", nreceived);
2357 if (ntransmitted) {
2358 if (nreceived <= ntransmitted) {
2359 Printf("%d%% packet loss",
2360 (int)(((ntransmitted-nreceived)*100) /
2361 ntransmitted));
2362 } else {
2363 Printf("%.2f times amplification",
2364 (double)nreceived / (double)ntransmitted);
2365 }
2366 }
2367 (void) putchar('\n');
2368
2369 /* if packet is big enough to store timeval AND ... */
2370 if ((datalen >= sizeof (struct timeval)) && (nreceived > 0)) {
2371 double mean = (double)tsum / nreceived;
2372 double smean = (double)tsum2 / nreceived;
2373 double sd =
2374 sqrt(((smean - mean*mean) * nreceived) / (nreceived-1));
2375
2376 Printf("round-trip (ms) min/avg/max/stddev = "
2377 TIMEFORMAT "/" TIMEFORMAT "/"
2378 TIMEFORMAT "/" TIMEFORMAT "\n",
2379 (double)tmin / 1000, mean / 1000,
2380 (double)tmax / 1000, sd / 1000);
2381 }
2382 (void) fflush(stdout);
2383
2384 exit(is_alive ? EXIT_SUCCESS : EXIT_FAILURE);
2385 }
2386
2387 /*
2388 * print the usage line
2389 */
2390 static void
usage(char * cmdname)2391 usage(char *cmdname)
2392 {
2393 Fprintf(stderr, "usage: %s host [timeout]\n", cmdname);
2394 Fprintf(stderr,
2395 /* CSTYLED */
2396 "usage: %s -s [-l | -U] [-abdDLnRrv] [-A addr_family] [-c traffic_class]\n\t"
2397 "[-g gateway [-g gateway ...]] [-N nexthop] [-F flow_label] [-I interval]\n\t"
2398 "[-i interface] [-P tos] [-p port] [-t ttl] host [data_size] [npackets]\n",
2399 cmdname);
2400 }
2401
2402 /*
2403 * Parse integer argument; exit with an error if it's not a number.
2404 * Now it also accepts hex. values.
2405 */
2406 static int
int_arg(char * s,char * what)2407 int_arg(char *s, char *what)
2408 {
2409 char *cp;
2410 char *ep;
2411 int num;
2412
2413 errno = 0;
2414 if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) {
2415 cp = s + 2;
2416 num = (int)strtol(cp, &ep, 16);
2417 } else {
2418 num = (int)strtol(s, &ep, 10);
2419 }
2420
2421 if (errno || *ep != '\0' || num < 0) {
2422 (void) Fprintf(stderr, "%s: bad %s: %s\n",
2423 progname, what, s);
2424 exit(EXIT_FAILURE);
2425 }
2426
2427 return (num);
2428 }
2429