17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5a356273cSpwernau * Common Development and Distribution License (the "License").
63c58dfd6Sjbeck * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate *
21e11c3f44Smeem * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
227c478bd9Sstevel@tonic-gate * Use is subject to license terms.
237c478bd9Sstevel@tonic-gate */
247c478bd9Sstevel@tonic-gate
257c478bd9Sstevel@tonic-gate /*
267c478bd9Sstevel@tonic-gate * Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T
277c478bd9Sstevel@tonic-gate * All Rights Reserved.
287c478bd9Sstevel@tonic-gate */
297c478bd9Sstevel@tonic-gate
307c478bd9Sstevel@tonic-gate /*
317c478bd9Sstevel@tonic-gate * University Copyright- Copyright (c) 1982, 1986, 1988
327c478bd9Sstevel@tonic-gate * The Regents of the University of California.
337c478bd9Sstevel@tonic-gate * All Rights Reserved.
347c478bd9Sstevel@tonic-gate *
357c478bd9Sstevel@tonic-gate * University Acknowledgment- Portions of this document are derived from
367c478bd9Sstevel@tonic-gate * software developed by the University of California, Berkeley, and its
377c478bd9Sstevel@tonic-gate * contributors.
387c478bd9Sstevel@tonic-gate */
397c478bd9Sstevel@tonic-gate
407c478bd9Sstevel@tonic-gate #include <stdio.h>
417c478bd9Sstevel@tonic-gate #include <strings.h>
427c478bd9Sstevel@tonic-gate #include <errno.h>
437c478bd9Sstevel@tonic-gate #include <fcntl.h>
447c478bd9Sstevel@tonic-gate #include <unistd.h>
457c478bd9Sstevel@tonic-gate #include <signal.h>
467c478bd9Sstevel@tonic-gate #include <limits.h>
477c478bd9Sstevel@tonic-gate #include <math.h>
487c478bd9Sstevel@tonic-gate
497c478bd9Sstevel@tonic-gate #include <sys/time.h>
507c478bd9Sstevel@tonic-gate #include <sys/param.h>
517c478bd9Sstevel@tonic-gate #include <sys/socket.h>
527c478bd9Sstevel@tonic-gate #include <sys/sockio.h>
537c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
547c478bd9Sstevel@tonic-gate #include <sys/file.h>
557c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
567c478bd9Sstevel@tonic-gate
577c478bd9Sstevel@tonic-gate #include <arpa/inet.h>
587c478bd9Sstevel@tonic-gate #include <net/if.h>
597c478bd9Sstevel@tonic-gate #include <netinet/in_systm.h>
607c478bd9Sstevel@tonic-gate #include <netinet/in.h>
617c478bd9Sstevel@tonic-gate #include <netinet/ip.h>
627c478bd9Sstevel@tonic-gate #include <netinet/ip_icmp.h>
637c478bd9Sstevel@tonic-gate #include <netinet/ip_var.h>
647c478bd9Sstevel@tonic-gate #include <netinet/ip6.h>
657c478bd9Sstevel@tonic-gate #include <netinet/icmp6.h>
667c478bd9Sstevel@tonic-gate #include <netinet/udp.h>
677c478bd9Sstevel@tonic-gate #include <netdb.h>
687c478bd9Sstevel@tonic-gate #include <stdlib.h>
697c478bd9Sstevel@tonic-gate #include <priv_utils.h>
707c478bd9Sstevel@tonic-gate
710406ceaaSmeem #include <libinetutil.h>
727c478bd9Sstevel@tonic-gate #include "ping.h"
737c478bd9Sstevel@tonic-gate
747c478bd9Sstevel@tonic-gate /*
757c478bd9Sstevel@tonic-gate * This macro is used to compare 16bit, wrapping sequence numbers. Inspired by
767c478bd9Sstevel@tonic-gate * TCP's SEQ_LEQ macro.
777c478bd9Sstevel@tonic-gate */
787c478bd9Sstevel@tonic-gate #define PINGSEQ_LEQ(a, b) ((int16_t)((a)-(b)) <= 0)
797c478bd9Sstevel@tonic-gate
807c478bd9Sstevel@tonic-gate #define MAX_WAIT 10 /* max sec. to wait for response */
817c478bd9Sstevel@tonic-gate #define MAX_TRAFFIC_CLASS 255 /* max traffic class for IPv6 */
827c478bd9Sstevel@tonic-gate #define MAX_FLOW_LABEL 0xFFFFF /* max flow label for IPv6 */
837c478bd9Sstevel@tonic-gate #define MAX_TOS 255 /* max type-of-service for IPv4 */
847c478bd9Sstevel@tonic-gate
857c478bd9Sstevel@tonic-gate #define TIMEOUT 20 /* default timeout value */
867c478bd9Sstevel@tonic-gate #define DEFAULT_DATALEN 56
877c478bd9Sstevel@tonic-gate
887c478bd9Sstevel@tonic-gate #define MULTICAST_NOLOOP 1 /* multicast options */
897c478bd9Sstevel@tonic-gate #define MULTICAST_TTL 2
907c478bd9Sstevel@tonic-gate #define MULTICAST_IF 4
917c478bd9Sstevel@tonic-gate
927c478bd9Sstevel@tonic-gate #define IF_INDEX 0 /* types of -i argument */
937c478bd9Sstevel@tonic-gate #define IF_NAME 1
947c478bd9Sstevel@tonic-gate #define IF_ADDR 2
957c478bd9Sstevel@tonic-gate #define IF_ADDR6 3
967c478bd9Sstevel@tonic-gate
977c478bd9Sstevel@tonic-gate #ifdef BSD
987c478bd9Sstevel@tonic-gate #define setbuf(s, b) setlinebuf((s))
997c478bd9Sstevel@tonic-gate #endif /* BSD */
1007c478bd9Sstevel@tonic-gate
1017c478bd9Sstevel@tonic-gate
1027c478bd9Sstevel@tonic-gate /* interface identification */
1037c478bd9Sstevel@tonic-gate union if_id {
1047c478bd9Sstevel@tonic-gate int index; /* interface index (e.g., 1, 2) */
1057c478bd9Sstevel@tonic-gate char *name; /* interface name (e.g., le0, hme0) */
1067c478bd9Sstevel@tonic-gate union any_in_addr addr; /* interface address (e.g., 10.123.4.5) */
1077c478bd9Sstevel@tonic-gate };
1087c478bd9Sstevel@tonic-gate
1097c478bd9Sstevel@tonic-gate /* stores the interface supplied by the user */
1107c478bd9Sstevel@tonic-gate struct if_entry {
1117c478bd9Sstevel@tonic-gate char *str; /* unresolved, string input */
1127c478bd9Sstevel@tonic-gate int id_type; /* type of ID (index, name, addr, addr6) */
1137c478bd9Sstevel@tonic-gate union if_id id; /* ID */
1147c478bd9Sstevel@tonic-gate };
1157c478bd9Sstevel@tonic-gate
1167c478bd9Sstevel@tonic-gate char *progname;
1177c478bd9Sstevel@tonic-gate char *targethost;
1184c10bc16Spwernau char *nexthop;
1197c478bd9Sstevel@tonic-gate
1207c478bd9Sstevel@tonic-gate static int send_sock; /* send sockets */
1217c478bd9Sstevel@tonic-gate static int send_sock6;
1227c478bd9Sstevel@tonic-gate static struct sockaddr_in to; /* where to send */
1237c478bd9Sstevel@tonic-gate static struct sockaddr_in6 to6;
1247c478bd9Sstevel@tonic-gate static union any_in_addr gw_IP_list[MAX_GWS]; /* gateways */
1257c478bd9Sstevel@tonic-gate static union any_in_addr gw_IP_list6[MAX_GWS6];
1267c478bd9Sstevel@tonic-gate static int if_index = 0; /* outgoing interface index */
1277c478bd9Sstevel@tonic-gate boolean_t is_alive = _B_FALSE; /* is target host alive */
1287c478bd9Sstevel@tonic-gate struct targetaddr *current_targetaddr; /* current target IP address to probe */
1297c478bd9Sstevel@tonic-gate static struct targetaddr *targetaddr_list; /* list of IP addresses to probe */
1307c478bd9Sstevel@tonic-gate static int num_targetaddrs; /* no of target addresses to probe */
1317c478bd9Sstevel@tonic-gate static int num_v4 = 0; /* count of IPv4 addresses */
1327c478bd9Sstevel@tonic-gate static int num_v6 = 0; /* count of IPv6 addresses */
1337c478bd9Sstevel@tonic-gate boolean_t verbose = _B_FALSE; /* verbose output */
1347c478bd9Sstevel@tonic-gate boolean_t stats = _B_FALSE; /* display statistics */
1357c478bd9Sstevel@tonic-gate static boolean_t settos = _B_FALSE; /* set type-of-service value */
1367c478bd9Sstevel@tonic-gate boolean_t rr_option = _B_FALSE; /* true if using record route */
1377c478bd9Sstevel@tonic-gate boolean_t send_reply = _B_FALSE; /* Send an ICMP_{ECHO|TSTAMP}REPLY */
1387c478bd9Sstevel@tonic-gate /* that goes to target and comes back */
1397c478bd9Sstevel@tonic-gate /* to the the sender via src routing. */
1407c478bd9Sstevel@tonic-gate boolean_t strict = _B_FALSE; /* true if using strict source route */
1417c478bd9Sstevel@tonic-gate boolean_t ts_option = _B_FALSE; /* true if using timestamp option */
1427c478bd9Sstevel@tonic-gate boolean_t use_icmp_ts = _B_FALSE; /* Use ICMP timestamp request */
1437c478bd9Sstevel@tonic-gate boolean_t use_udp = _B_FALSE; /* Use UDP instead of ICMP */
1447c478bd9Sstevel@tonic-gate boolean_t probe_all = _B_FALSE; /* probe all the IP addresses */
1457c478bd9Sstevel@tonic-gate boolean_t nflag = _B_FALSE; /* do not reverse lookup addresses */
146a356273cSpwernau boolean_t bypass = _B_FALSE; /* bypass IPsec policy */
1477c478bd9Sstevel@tonic-gate static int family_input = AF_UNSPEC; /* address family supplied by user */
1487c478bd9Sstevel@tonic-gate int datalen = DEFAULT_DATALEN; /* How much data */
1497c478bd9Sstevel@tonic-gate int ts_flag; /* timestamp flag value */
1507c478bd9Sstevel@tonic-gate static int num_gw; /* number of gateways */
1517c478bd9Sstevel@tonic-gate static int eff_num_gw; /* effective number of gateways */
1527c478bd9Sstevel@tonic-gate /* if send_reply, it's 2*num_gw+1 */
1537c478bd9Sstevel@tonic-gate static int num_wraps = -1; /* no of times 64K icmp_seq wrapped */
1547c478bd9Sstevel@tonic-gate static ushort_t dest_port = 32768 + 666; /* starting port for the UDP probes */
1557c478bd9Sstevel@tonic-gate static char *gw_list[MAXMAX_GWS]; /* list of gateways as user enters */
1567c478bd9Sstevel@tonic-gate static int interval = 1; /* interval between transmissions */
1577c478bd9Sstevel@tonic-gate static int options; /* socket options */
1587c478bd9Sstevel@tonic-gate static int moptions; /* multicast options */
1597c478bd9Sstevel@tonic-gate int npackets; /* number of packets to send */
1607c478bd9Sstevel@tonic-gate static ushort_t tos; /* type-of-service value */
1617c478bd9Sstevel@tonic-gate static int hoplimit = -1; /* time-to-live value */
162bd670b35SErik Nordmark static int dontfrag; /* IP*_DONTFRAG */
1637c478bd9Sstevel@tonic-gate static int timeout = TIMEOUT; /* timeout value (sec) for probes */
1647c478bd9Sstevel@tonic-gate static struct if_entry out_if; /* interface argument */
1657c478bd9Sstevel@tonic-gate int ident; /* ID for this ping run */
1667c478bd9Sstevel@tonic-gate static hrtime_t t_last_probe_sent; /* the time we sent the last probe */
1677c478bd9Sstevel@tonic-gate
1687c478bd9Sstevel@tonic-gate /*
1697c478bd9Sstevel@tonic-gate * This buffer stores the received packets. Currently it needs to be 32 bit
1707c478bd9Sstevel@tonic-gate * aligned. In the future, we'll be using 64 bit alignment, so let's use 64 bit
1717c478bd9Sstevel@tonic-gate * alignment now.
1727c478bd9Sstevel@tonic-gate */
1737c478bd9Sstevel@tonic-gate static uint64_t in_pkt[(IP_MAXPACKET + 1)/8];
1747c478bd9Sstevel@tonic-gate
1757c478bd9Sstevel@tonic-gate /* Used to store the ancillary data that comes with the received packets */
1767c478bd9Sstevel@tonic-gate static uint64_t ancillary_data[(IP_MAXPACKET + 1)/8];
1777c478bd9Sstevel@tonic-gate
1787c478bd9Sstevel@tonic-gate static int ntransmitted; /* number of packet sent to single IP address */
1797c478bd9Sstevel@tonic-gate int nreceived; /* # of packets we got back from target host */
1807c478bd9Sstevel@tonic-gate int nreceived_last_target; /* received from last target IP */
1817c478bd9Sstevel@tonic-gate /*
1827c478bd9Sstevel@tonic-gate * These are used for statistics. tmin is initialized to maximum longint value.
1837c478bd9Sstevel@tonic-gate * The max value is also used for timeouts. All times are in microseconds.
1847c478bd9Sstevel@tonic-gate */
1857c478bd9Sstevel@tonic-gate long long tmin = LLONG_MAX;
1867c478bd9Sstevel@tonic-gate long long tmax;
1877c478bd9Sstevel@tonic-gate int64_t tsum; /* sum of all times, for doing average */
1887c478bd9Sstevel@tonic-gate int64_t tsum2; /* sum of squared times, for std. dev. */
1897c478bd9Sstevel@tonic-gate
1907c478bd9Sstevel@tonic-gate static struct targetaddr *build_targetaddr_list(struct addrinfo *,
1917c478bd9Sstevel@tonic-gate union any_in_addr *);
1927c478bd9Sstevel@tonic-gate extern void check_reply(struct addrinfo *, struct msghdr *, int, ushort_t);
1937c478bd9Sstevel@tonic-gate extern void check_reply6(struct addrinfo *, struct msghdr *, int, ushort_t);
1947c478bd9Sstevel@tonic-gate static struct targetaddr *create_targetaddr_item(int, union any_in_addr *,
1957c478bd9Sstevel@tonic-gate union any_in_addr *);
1967c478bd9Sstevel@tonic-gate void find_dstaddr(ushort_t, union any_in_addr *);
1977c478bd9Sstevel@tonic-gate static struct ifaddrlist *find_if(struct ifaddrlist *, int);
1987c478bd9Sstevel@tonic-gate static void finish();
1997c478bd9Sstevel@tonic-gate static void get_gwaddrs(char *[], int, union any_in_addr *,
2007c478bd9Sstevel@tonic-gate union any_in_addr *, int *, int *);
2017c478bd9Sstevel@tonic-gate static void get_hostinfo(char *, int, struct addrinfo **);
2027c478bd9Sstevel@tonic-gate static ushort_t in_cksum(ushort_t *, int);
2037c478bd9Sstevel@tonic-gate static int int_arg(char *s, char *what);
2047c478bd9Sstevel@tonic-gate boolean_t is_a_target(struct addrinfo *, union any_in_addr *);
2057c478bd9Sstevel@tonic-gate static void mirror_gws(union any_in_addr *, int);
2067c478bd9Sstevel@tonic-gate static void pinger(int, struct sockaddr *, struct msghdr *, int);
2077c478bd9Sstevel@tonic-gate char *pr_name(char *, int);
2087c478bd9Sstevel@tonic-gate char *pr_protocol(int);
2097c478bd9Sstevel@tonic-gate static void print_unknown_host_msg(const char *, const char *);
2107c478bd9Sstevel@tonic-gate static void recv_icmp_packet(struct addrinfo *, int, int, ushort_t, ushort_t);
2114c10bc16Spwernau static void resolve_nodes(struct addrinfo **, struct addrinfo **,
2124c10bc16Spwernau union any_in_addr **);
2137c478bd9Sstevel@tonic-gate void schedule_sigalrm();
2147c478bd9Sstevel@tonic-gate static void select_all_src_addrs(union any_in_addr **, struct addrinfo *,
2157c478bd9Sstevel@tonic-gate union any_in_addr *, union any_in_addr *);
2167c478bd9Sstevel@tonic-gate static void select_src_addr(union any_in_addr *, int, union any_in_addr *);
2177c478bd9Sstevel@tonic-gate void send_scheduled_probe();
2187c478bd9Sstevel@tonic-gate boolean_t seq_match(ushort_t, int, ushort_t);
2197c478bd9Sstevel@tonic-gate extern void set_ancillary_data(struct msghdr *, int, union any_in_addr *, int,
2207c478bd9Sstevel@tonic-gate uint_t);
2217c478bd9Sstevel@tonic-gate extern void set_IPv4_options(int, union any_in_addr *, int, struct in_addr *,
2227c478bd9Sstevel@tonic-gate struct in_addr *);
2234c10bc16Spwernau static void set_nexthop(int, struct addrinfo *, int);
2244c10bc16Spwernau static boolean_t setup_socket(int, int *, int *, int *, ushort_t *,
2254c10bc16Spwernau struct addrinfo *);
2267c478bd9Sstevel@tonic-gate void sigalrm_handler();
2277c478bd9Sstevel@tonic-gate void tvsub(struct timeval *, struct timeval *);
2287c478bd9Sstevel@tonic-gate static void usage(char *);
2297c478bd9Sstevel@tonic-gate
2307c478bd9Sstevel@tonic-gate /*
2317c478bd9Sstevel@tonic-gate * main()
2327c478bd9Sstevel@tonic-gate */
2338c332a0dSja97890 int
main(int argc,char * argv[])2347c478bd9Sstevel@tonic-gate main(int argc, char *argv[])
2357c478bd9Sstevel@tonic-gate {
2367c478bd9Sstevel@tonic-gate struct addrinfo *ai_dst = NULL; /* addrinfo host list */
2374c10bc16Spwernau struct addrinfo *ai_nexthop = NULL; /* addrinfo nexthop */
2387c478bd9Sstevel@tonic-gate union any_in_addr *src_addr_list = NULL; /* src addrs to use */
2397c478bd9Sstevel@tonic-gate int recv_sock = -1; /* receive sockets */
2407c478bd9Sstevel@tonic-gate int recv_sock6 = -1;
2417c478bd9Sstevel@tonic-gate ushort_t udp_src_port; /* src ports for UDP probes */
2427c478bd9Sstevel@tonic-gate ushort_t udp_src_port6; /* used to identify replies */
2437c478bd9Sstevel@tonic-gate uint_t flowinfo = 0;
2447c478bd9Sstevel@tonic-gate uint_t class = 0;
245e11c3f44Smeem char abuf[INET6_ADDRSTRLEN];
2467c478bd9Sstevel@tonic-gate int c;
2477c478bd9Sstevel@tonic-gate int i;
248f4b3ec61Sdh155122 boolean_t has_sys_ip_config;
2497c478bd9Sstevel@tonic-gate
2507c478bd9Sstevel@tonic-gate progname = argv[0];
2517c478bd9Sstevel@tonic-gate
2527c478bd9Sstevel@tonic-gate /*
2531da45818Spwernau * This program needs the net_icmpaccess privilege for creating
254f4b3ec61Sdh155122 * raw ICMP sockets. It needs sys_ip_config for using the
2551da45818Spwernau * IP_NEXTHOP socket option (IPv4 only). We'll fail
2567c478bd9Sstevel@tonic-gate * on the socket call and report the error there when we have
2577c478bd9Sstevel@tonic-gate * insufficient privileges.
2581da45818Spwernau *
259f4b3ec61Sdh155122 * Shared-IP zones don't have the sys_ip_config privilege, so
2601da45818Spwernau * we need to check for it in our limit set before trying
2611da45818Spwernau * to set it.
2627c478bd9Sstevel@tonic-gate */
263f4b3ec61Sdh155122 has_sys_ip_config = priv_ineffect(PRIV_SYS_IP_CONFIG);
2641da45818Spwernau
2657c478bd9Sstevel@tonic-gate (void) __init_suid_priv(PU_CLEARLIMITSET, PRIV_NET_ICMPACCESS,
266f4b3ec61Sdh155122 has_sys_ip_config ? PRIV_SYS_IP_CONFIG : (char *)NULL,
2671da45818Spwernau (char *)NULL);
2687c478bd9Sstevel@tonic-gate
2697c478bd9Sstevel@tonic-gate setbuf(stdout, (char *)0);
2707c478bd9Sstevel@tonic-gate
2717c478bd9Sstevel@tonic-gate while ((c = getopt(argc, argv,
272bd670b35SErik Nordmark "abA:c:dDF:G:g:I:i:LlnN:P:p:rRSsTt:UvX:x:Y0123?")) != -1) {
2737c478bd9Sstevel@tonic-gate switch ((char)c) {
2747c478bd9Sstevel@tonic-gate case 'A':
2757c478bd9Sstevel@tonic-gate if (strcmp(optarg, "inet") == 0) {
2767c478bd9Sstevel@tonic-gate family_input = AF_INET;
2777c478bd9Sstevel@tonic-gate } else if (strcmp(optarg, "inet6") == 0) {
2787c478bd9Sstevel@tonic-gate family_input = AF_INET6;
2797c478bd9Sstevel@tonic-gate } else {
2807c478bd9Sstevel@tonic-gate Fprintf(stderr,
2817c478bd9Sstevel@tonic-gate "%s: unknown address family %s\n",
2827c478bd9Sstevel@tonic-gate progname, optarg);
2837c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
2847c478bd9Sstevel@tonic-gate }
2857c478bd9Sstevel@tonic-gate break;
2867c478bd9Sstevel@tonic-gate
2877c478bd9Sstevel@tonic-gate case 'a':
2887c478bd9Sstevel@tonic-gate probe_all = _B_TRUE;
2897c478bd9Sstevel@tonic-gate break;
2907c478bd9Sstevel@tonic-gate
2917c478bd9Sstevel@tonic-gate case 'c':
2927c478bd9Sstevel@tonic-gate i = int_arg(optarg, "traffic class");
2937c478bd9Sstevel@tonic-gate if (i > MAX_TRAFFIC_CLASS) {
2947c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: traffic class %d out of "
2957c478bd9Sstevel@tonic-gate "range\n", progname, i);
2967c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
2977c478bd9Sstevel@tonic-gate }
2987c478bd9Sstevel@tonic-gate class = (uint_t)i;
2997c478bd9Sstevel@tonic-gate break;
3007c478bd9Sstevel@tonic-gate
3017c478bd9Sstevel@tonic-gate case 'd':
3027c478bd9Sstevel@tonic-gate options |= SO_DEBUG;
3037c478bd9Sstevel@tonic-gate break;
3047c478bd9Sstevel@tonic-gate
305bd670b35SErik Nordmark case 'D':
306bd670b35SErik Nordmark dontfrag = 1;
307bd670b35SErik Nordmark break;
308bd670b35SErik Nordmark
309a356273cSpwernau case 'b':
310a356273cSpwernau bypass = _B_TRUE;
311a356273cSpwernau break;
312a356273cSpwernau
3137c478bd9Sstevel@tonic-gate case 'F':
3147c478bd9Sstevel@tonic-gate i = int_arg(optarg, "flow label");
3157c478bd9Sstevel@tonic-gate if (i > MAX_FLOW_LABEL) {
3167c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: flow label %d out of "
3177c478bd9Sstevel@tonic-gate "range\n", progname, i);
3187c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
3197c478bd9Sstevel@tonic-gate }
3207c478bd9Sstevel@tonic-gate flowinfo = (uint_t)i;
3217c478bd9Sstevel@tonic-gate break;
3227c478bd9Sstevel@tonic-gate
3237c478bd9Sstevel@tonic-gate case 'I':
3247c478bd9Sstevel@tonic-gate stats = _B_TRUE;
3257c478bd9Sstevel@tonic-gate interval = int_arg(optarg, "interval");
3267c478bd9Sstevel@tonic-gate break;
3277c478bd9Sstevel@tonic-gate
3287c478bd9Sstevel@tonic-gate case 'i':
3297c478bd9Sstevel@tonic-gate /*
3307c478bd9Sstevel@tonic-gate * this can accept interface index, interface name, and
3317c478bd9Sstevel@tonic-gate * address configured on the interface
3327c478bd9Sstevel@tonic-gate */
3337c478bd9Sstevel@tonic-gate moptions |= MULTICAST_IF;
3347c478bd9Sstevel@tonic-gate out_if.str = optarg;
3357c478bd9Sstevel@tonic-gate
3367c478bd9Sstevel@tonic-gate if (inet_pton(AF_INET6, optarg, &out_if.id.addr) > 0) {
3377c478bd9Sstevel@tonic-gate out_if.id_type = IF_ADDR6;
3387c478bd9Sstevel@tonic-gate } else if (inet_pton(AF_INET, optarg,
3397c478bd9Sstevel@tonic-gate &out_if.id.addr) > 0) {
3407c478bd9Sstevel@tonic-gate out_if.id_type = IF_ADDR;
3417c478bd9Sstevel@tonic-gate } else if (strcmp(optarg, "0") == 0) {
3427c478bd9Sstevel@tonic-gate out_if.id_type = IF_INDEX;
3437c478bd9Sstevel@tonic-gate out_if.id.index = 0;
3447c478bd9Sstevel@tonic-gate } else if ((out_if.id.index = atoi(optarg)) != 0) {
3457c478bd9Sstevel@tonic-gate out_if.id_type = IF_INDEX;
3467c478bd9Sstevel@tonic-gate } else {
3477c478bd9Sstevel@tonic-gate out_if.id.name = optarg;
3487c478bd9Sstevel@tonic-gate out_if.id_type = IF_NAME;
3497c478bd9Sstevel@tonic-gate }
3507c478bd9Sstevel@tonic-gate break;
3517c478bd9Sstevel@tonic-gate
3527c478bd9Sstevel@tonic-gate case 'L':
3537c478bd9Sstevel@tonic-gate moptions |= MULTICAST_NOLOOP;
3547c478bd9Sstevel@tonic-gate break;
3557c478bd9Sstevel@tonic-gate
3567c478bd9Sstevel@tonic-gate case 'l':
3577c478bd9Sstevel@tonic-gate send_reply = _B_TRUE;
3587c478bd9Sstevel@tonic-gate strict = _B_FALSE;
3597c478bd9Sstevel@tonic-gate break;
3607c478bd9Sstevel@tonic-gate
3617c478bd9Sstevel@tonic-gate case 'n':
3627c478bd9Sstevel@tonic-gate nflag = _B_TRUE;
3637c478bd9Sstevel@tonic-gate break;
3647c478bd9Sstevel@tonic-gate
3657c478bd9Sstevel@tonic-gate case 'P':
3667c478bd9Sstevel@tonic-gate settos = _B_TRUE;
3677c478bd9Sstevel@tonic-gate i = int_arg(optarg, "type-of-service");
3687c478bd9Sstevel@tonic-gate if (i > MAX_TOS) {
3697c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: tos value %d out of "
3707c478bd9Sstevel@tonic-gate "range\n", progname, i);
3717c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
3727c478bd9Sstevel@tonic-gate }
3737c478bd9Sstevel@tonic-gate tos = (ushort_t)i;
3747c478bd9Sstevel@tonic-gate break;
3757c478bd9Sstevel@tonic-gate
3767c478bd9Sstevel@tonic-gate case 'p':
3777c478bd9Sstevel@tonic-gate i = int_arg(optarg, "port number");
3787c478bd9Sstevel@tonic-gate if (i > MAX_PORT) {
3797c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: port number %d out of "
3807c478bd9Sstevel@tonic-gate "range\n", progname, i);
3817c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
3827c478bd9Sstevel@tonic-gate }
3837c478bd9Sstevel@tonic-gate dest_port = (ushort_t)i;
3847c478bd9Sstevel@tonic-gate break;
3857c478bd9Sstevel@tonic-gate
3867c478bd9Sstevel@tonic-gate case 'r':
3877c478bd9Sstevel@tonic-gate options |= SO_DONTROUTE;
3887c478bd9Sstevel@tonic-gate break;
3897c478bd9Sstevel@tonic-gate
3907c478bd9Sstevel@tonic-gate case 'R':
3917c478bd9Sstevel@tonic-gate rr_option = _B_TRUE;
3927c478bd9Sstevel@tonic-gate break;
3937c478bd9Sstevel@tonic-gate
3947c478bd9Sstevel@tonic-gate case 'S':
3957c478bd9Sstevel@tonic-gate send_reply = _B_TRUE;
3967c478bd9Sstevel@tonic-gate strict = _B_TRUE;
3977c478bd9Sstevel@tonic-gate break;
3987c478bd9Sstevel@tonic-gate
3997c478bd9Sstevel@tonic-gate case 's':
4007c478bd9Sstevel@tonic-gate stats = _B_TRUE;
4017c478bd9Sstevel@tonic-gate break;
4027c478bd9Sstevel@tonic-gate
4037c478bd9Sstevel@tonic-gate case 'T':
4047c478bd9Sstevel@tonic-gate ts_option = _B_TRUE;
4057c478bd9Sstevel@tonic-gate break;
4067c478bd9Sstevel@tonic-gate
4077c478bd9Sstevel@tonic-gate case 't':
4087c478bd9Sstevel@tonic-gate moptions |= MULTICAST_TTL;
4097c478bd9Sstevel@tonic-gate hoplimit = int_arg(optarg, "ttl");
4107c478bd9Sstevel@tonic-gate if (hoplimit > MAXTTL) {
4117c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: ttl %d out of range\n",
4127c478bd9Sstevel@tonic-gate progname, hoplimit);
4137c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
4147c478bd9Sstevel@tonic-gate }
4157c478bd9Sstevel@tonic-gate break;
4167c478bd9Sstevel@tonic-gate
4177c478bd9Sstevel@tonic-gate case 'U':
4187c478bd9Sstevel@tonic-gate use_udp = _B_TRUE;
4197c478bd9Sstevel@tonic-gate use_icmp_ts = _B_FALSE;
4207c478bd9Sstevel@tonic-gate break;
4217c478bd9Sstevel@tonic-gate
4227c478bd9Sstevel@tonic-gate case 'v':
4237c478bd9Sstevel@tonic-gate verbose = _B_TRUE;
4247c478bd9Sstevel@tonic-gate break;
4257c478bd9Sstevel@tonic-gate /*
4267c478bd9Sstevel@tonic-gate * 'x' and 'X' has been undocumented flags for source routing.
4277c478bd9Sstevel@tonic-gate * Now we document loose source routing with the new flag 'g',
4287c478bd9Sstevel@tonic-gate * which is same as in traceroute. We still keep x/X as
4297c478bd9Sstevel@tonic-gate * as undocumented. 'G', which is for strict source routing is
4307c478bd9Sstevel@tonic-gate * also undocumented.
4317c478bd9Sstevel@tonic-gate */
4327c478bd9Sstevel@tonic-gate case 'x':
4337c478bd9Sstevel@tonic-gate case 'g':
4347c478bd9Sstevel@tonic-gate strict = _B_FALSE;
4357c478bd9Sstevel@tonic-gate if (num_gw > MAXMAX_GWS) {
4367c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: too many gateways\n",
4377c478bd9Sstevel@tonic-gate progname);
4387c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
4397c478bd9Sstevel@tonic-gate }
4407c478bd9Sstevel@tonic-gate gw_list[num_gw++] = optarg;
4417c478bd9Sstevel@tonic-gate break;
4427c478bd9Sstevel@tonic-gate
4437c478bd9Sstevel@tonic-gate case 'X':
4447c478bd9Sstevel@tonic-gate case 'G':
4457c478bd9Sstevel@tonic-gate strict = _B_TRUE;
4467c478bd9Sstevel@tonic-gate if (num_gw > MAXMAX_GWS) {
4477c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: too many gateways\n",
4487c478bd9Sstevel@tonic-gate progname);
4497c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
4507c478bd9Sstevel@tonic-gate }
4517c478bd9Sstevel@tonic-gate gw_list[num_gw++] = optarg;
4527c478bd9Sstevel@tonic-gate break;
4537c478bd9Sstevel@tonic-gate
4544c10bc16Spwernau case 'N':
4554c10bc16Spwernau if (nexthop != NULL) {
4564c10bc16Spwernau Fprintf(stderr, "%s: only one next hop gateway"
4574c10bc16Spwernau " allowed\n", progname);
4584c10bc16Spwernau exit(EXIT_FAILURE);
4594c10bc16Spwernau }
4604c10bc16Spwernau nexthop = optarg;
4614c10bc16Spwernau break;
4624c10bc16Spwernau
4637c478bd9Sstevel@tonic-gate case 'Y':
4647c478bd9Sstevel@tonic-gate use_icmp_ts = _B_TRUE;
4657c478bd9Sstevel@tonic-gate use_udp = _B_FALSE;
4667c478bd9Sstevel@tonic-gate break;
4677c478bd9Sstevel@tonic-gate
4687c478bd9Sstevel@tonic-gate case '0':
4697c478bd9Sstevel@tonic-gate case '1':
4707c478bd9Sstevel@tonic-gate case '2':
4717c478bd9Sstevel@tonic-gate case '3':
4727c478bd9Sstevel@tonic-gate ts_flag = (char)c - '0';
4737c478bd9Sstevel@tonic-gate break;
4747c478bd9Sstevel@tonic-gate
4757c478bd9Sstevel@tonic-gate case '?':
4767c478bd9Sstevel@tonic-gate usage(progname);
4777c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
4787c478bd9Sstevel@tonic-gate break;
4797c478bd9Sstevel@tonic-gate
4807c478bd9Sstevel@tonic-gate default:
4817c478bd9Sstevel@tonic-gate usage(progname);
4827c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
4837c478bd9Sstevel@tonic-gate break;
4847c478bd9Sstevel@tonic-gate }
4857c478bd9Sstevel@tonic-gate }
4867c478bd9Sstevel@tonic-gate
4877c478bd9Sstevel@tonic-gate if (optind >= argc) {
4887c478bd9Sstevel@tonic-gate usage(progname);
4897c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
4907c478bd9Sstevel@tonic-gate }
4917c478bd9Sstevel@tonic-gate
4927c478bd9Sstevel@tonic-gate /*
4937c478bd9Sstevel@tonic-gate * send_reply, which sends the probe packet back to itself
4947c478bd9Sstevel@tonic-gate * doesn't work with UDP
4957c478bd9Sstevel@tonic-gate */
4967c478bd9Sstevel@tonic-gate if (use_udp)
4977c478bd9Sstevel@tonic-gate send_reply = _B_FALSE;
4987c478bd9Sstevel@tonic-gate
4993c58dfd6Sjbeck if (getenv("MACHINE_THAT_GOES_PING") != NULL)
5003c58dfd6Sjbeck stats = _B_TRUE;
5013c58dfd6Sjbeck
5027c478bd9Sstevel@tonic-gate targethost = argv[optind];
5037c478bd9Sstevel@tonic-gate optind++;
5047c478bd9Sstevel@tonic-gate if (optind < argc) {
5057c478bd9Sstevel@tonic-gate if (stats) {
5067c478bd9Sstevel@tonic-gate datalen = int_arg(argv[optind], "data size");
5077c478bd9Sstevel@tonic-gate optind++;
5087c478bd9Sstevel@tonic-gate if (optind < argc) {
5097c478bd9Sstevel@tonic-gate npackets = int_arg(argv[optind],
5107c478bd9Sstevel@tonic-gate "packet count");
5117c478bd9Sstevel@tonic-gate if (npackets < 1) {
5127c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: packet count %d "
5137c478bd9Sstevel@tonic-gate "out of range\n", progname,
5147c478bd9Sstevel@tonic-gate npackets);
5157c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
5167c478bd9Sstevel@tonic-gate }
5177c478bd9Sstevel@tonic-gate }
5187c478bd9Sstevel@tonic-gate } else {
5197c478bd9Sstevel@tonic-gate timeout = int_arg(argv[optind], "timeout");
5207c478bd9Sstevel@tonic-gate }
5217c478bd9Sstevel@tonic-gate }
5227c478bd9Sstevel@tonic-gate
5237c478bd9Sstevel@tonic-gate /*
5247c478bd9Sstevel@tonic-gate * Let's prepare sockaddr_in* structures, cause we might need both of
5257c478bd9Sstevel@tonic-gate * them.
5267c478bd9Sstevel@tonic-gate */
5277c478bd9Sstevel@tonic-gate bzero((char *)&to, sizeof (struct sockaddr_in));
5287c478bd9Sstevel@tonic-gate to.sin_family = AF_INET;
5297c478bd9Sstevel@tonic-gate
5307c478bd9Sstevel@tonic-gate bzero((char *)&to6, sizeof (struct sockaddr_in6));
5317c478bd9Sstevel@tonic-gate to6.sin6_family = AF_INET6;
5327c478bd9Sstevel@tonic-gate to6.sin6_flowinfo = htonl((class << 20) | flowinfo);
5337c478bd9Sstevel@tonic-gate
5347c478bd9Sstevel@tonic-gate if (stats)
5357c478bd9Sstevel@tonic-gate (void) sigset(SIGINT, finish);
5367c478bd9Sstevel@tonic-gate
5377c478bd9Sstevel@tonic-gate ident = (int)getpid() & 0xFFFF;
5387c478bd9Sstevel@tonic-gate
5397c478bd9Sstevel@tonic-gate /* resolve the hostnames */
5404c10bc16Spwernau resolve_nodes(&ai_dst, &ai_nexthop, &src_addr_list);
5417c478bd9Sstevel@tonic-gate
5427c478bd9Sstevel@tonic-gate /*
5437c478bd9Sstevel@tonic-gate * We should make sure datalen is reasonable.
5447c478bd9Sstevel@tonic-gate * IP_MAXPACKET >= IPv4/IPv6 header length +
5457c478bd9Sstevel@tonic-gate * IPv4 options/IPv6 routing header length +
5467c478bd9Sstevel@tonic-gate * ICMP/ICMP6/UDP header length +
5477c478bd9Sstevel@tonic-gate * datalen
5487c478bd9Sstevel@tonic-gate */
5497c478bd9Sstevel@tonic-gate
5507c478bd9Sstevel@tonic-gate if (family_input == AF_INET6 ||
5517c478bd9Sstevel@tonic-gate (family_input == AF_UNSPEC && num_v6 != 0)) {
5527c478bd9Sstevel@tonic-gate size_t exthdr_len = 0;
5537c478bd9Sstevel@tonic-gate
5547c478bd9Sstevel@tonic-gate if (send_reply) {
5557c478bd9Sstevel@tonic-gate exthdr_len = sizeof (struct ip6_rthdr0) +
5567c478bd9Sstevel@tonic-gate 2 * num_gw * sizeof (struct in6_addr);
5577c478bd9Sstevel@tonic-gate } else if (num_gw > 0) {
5587c478bd9Sstevel@tonic-gate exthdr_len = sizeof (struct ip6_rthdr0) +
5597c478bd9Sstevel@tonic-gate num_gw * sizeof (struct in6_addr);
5607c478bd9Sstevel@tonic-gate }
5617c478bd9Sstevel@tonic-gate
5627c478bd9Sstevel@tonic-gate /*
5637c478bd9Sstevel@tonic-gate * Size of ICMP6 header and UDP header are the same. Let's
5647c478bd9Sstevel@tonic-gate * use ICMP6_MINLEN.
5657c478bd9Sstevel@tonic-gate */
5667c478bd9Sstevel@tonic-gate if (datalen > (IP_MAXPACKET - (sizeof (struct ip6_hdr) +
5677c478bd9Sstevel@tonic-gate exthdr_len + ICMP6_MINLEN))) {
5687c478bd9Sstevel@tonic-gate Fprintf(stderr,
5697c478bd9Sstevel@tonic-gate "%s: data size too large for IPv6 packet\n",
5707c478bd9Sstevel@tonic-gate progname);
5717c478bd9Sstevel@tonic-gate num_v6 = 0;
5727c478bd9Sstevel@tonic-gate }
5737c478bd9Sstevel@tonic-gate }
5747c478bd9Sstevel@tonic-gate
5757c478bd9Sstevel@tonic-gate if (family_input == AF_INET ||
5767c478bd9Sstevel@tonic-gate (family_input == AF_UNSPEC && num_v4 != 0)) {
5777c478bd9Sstevel@tonic-gate size_t opt_len = 0;
5787c478bd9Sstevel@tonic-gate
5797c478bd9Sstevel@tonic-gate if (send_reply) {
5807c478bd9Sstevel@tonic-gate /*
5817c478bd9Sstevel@tonic-gate * Includes 3 bytes code+ptr+len, the intermediate
5827c478bd9Sstevel@tonic-gate * gateways, the actual and the effective target.
5837c478bd9Sstevel@tonic-gate */
5847c478bd9Sstevel@tonic-gate opt_len = 3 +
5857c478bd9Sstevel@tonic-gate (2 * num_gw + 2) * sizeof (struct in_addr);
5867c478bd9Sstevel@tonic-gate } else if (num_gw > 0) {
5877c478bd9Sstevel@tonic-gate opt_len = 3 + (num_gw + 1) * sizeof (struct in_addr);
5887c478bd9Sstevel@tonic-gate }
5897c478bd9Sstevel@tonic-gate
5907c478bd9Sstevel@tonic-gate if (rr_option) {
5917c478bd9Sstevel@tonic-gate opt_len = MAX_IPOPTLEN;
5927c478bd9Sstevel@tonic-gate } else if (ts_option) {
5937c478bd9Sstevel@tonic-gate if ((ts_flag & 0x0f) <= IPOPT_TS_TSANDADDR) {
5947c478bd9Sstevel@tonic-gate opt_len = MAX_IPOPTLEN;
5957c478bd9Sstevel@tonic-gate } else {
5967c478bd9Sstevel@tonic-gate opt_len += IPOPT_MINOFF +
5977c478bd9Sstevel@tonic-gate 2 * sizeof (struct ipt_ta);
5987c478bd9Sstevel@tonic-gate /*
5997c478bd9Sstevel@tonic-gate * Note: BSD/4.X is broken in their check so we
6007c478bd9Sstevel@tonic-gate * have to bump up this number by at least one.
6017c478bd9Sstevel@tonic-gate */
6027c478bd9Sstevel@tonic-gate opt_len++;
6037c478bd9Sstevel@tonic-gate }
6047c478bd9Sstevel@tonic-gate }
6057c478bd9Sstevel@tonic-gate
6067c478bd9Sstevel@tonic-gate /* Round up to 4 byte boundary */
6077c478bd9Sstevel@tonic-gate if (opt_len & 0x3)
6087c478bd9Sstevel@tonic-gate opt_len = (opt_len & ~0x3) + 4;
6097c478bd9Sstevel@tonic-gate
6107c478bd9Sstevel@tonic-gate if (datalen > (IP_MAXPACKET - (sizeof (struct ip) + opt_len +
6117c478bd9Sstevel@tonic-gate ICMP_MINLEN))) {
6127c478bd9Sstevel@tonic-gate Fprintf(stderr,
6137c478bd9Sstevel@tonic-gate "%s: data size too large for IPv4 packet\n",
6147c478bd9Sstevel@tonic-gate progname);
6157c478bd9Sstevel@tonic-gate num_v4 = 0;
6167c478bd9Sstevel@tonic-gate }
6177c478bd9Sstevel@tonic-gate }
6187c478bd9Sstevel@tonic-gate
6197c478bd9Sstevel@tonic-gate if (num_v4 == 0 && num_v6 == 0) {
6207c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
6217c478bd9Sstevel@tonic-gate }
6227c478bd9Sstevel@tonic-gate
6237c478bd9Sstevel@tonic-gate /* setup the sockets */
6247c478bd9Sstevel@tonic-gate if (num_v6 != 0) {
6257c478bd9Sstevel@tonic-gate if (!setup_socket(AF_INET6, &send_sock6, &recv_sock6,
6264c10bc16Spwernau &if_index, &udp_src_port6, ai_nexthop))
6277c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
6287c478bd9Sstevel@tonic-gate }
6297c478bd9Sstevel@tonic-gate
6307c478bd9Sstevel@tonic-gate if (num_v4 != 0) {
6317c478bd9Sstevel@tonic-gate if (!setup_socket(AF_INET, &send_sock, &recv_sock, &if_index,
6324c10bc16Spwernau &udp_src_port, ai_nexthop))
6337c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
6347c478bd9Sstevel@tonic-gate }
6357c478bd9Sstevel@tonic-gate
6367c478bd9Sstevel@tonic-gate __priv_relinquish();
6377c478bd9Sstevel@tonic-gate
6387c478bd9Sstevel@tonic-gate /*
6397c478bd9Sstevel@tonic-gate * If sending back to ourself, add the mirror image of current
6407c478bd9Sstevel@tonic-gate * gateways, so that the probes travel to and from the target
6417c478bd9Sstevel@tonic-gate * by visiting the same gateways in reverse order.
6427c478bd9Sstevel@tonic-gate */
6437c478bd9Sstevel@tonic-gate if (send_reply) {
6447c478bd9Sstevel@tonic-gate if (num_v6 != 0)
6457c478bd9Sstevel@tonic-gate mirror_gws(gw_IP_list6, AF_INET6);
6467c478bd9Sstevel@tonic-gate if (num_v4 != 0)
6477c478bd9Sstevel@tonic-gate mirror_gws(gw_IP_list, AF_INET);
6487c478bd9Sstevel@tonic-gate
6497c478bd9Sstevel@tonic-gate /* We add 1 because we put the target as the middle gateway */
6507c478bd9Sstevel@tonic-gate eff_num_gw = 2 * num_gw + 1;
6517c478bd9Sstevel@tonic-gate
6527c478bd9Sstevel@tonic-gate } else {
6537c478bd9Sstevel@tonic-gate eff_num_gw = num_gw;
6547c478bd9Sstevel@tonic-gate }
6557c478bd9Sstevel@tonic-gate
6567c478bd9Sstevel@tonic-gate targetaddr_list = build_targetaddr_list(ai_dst, src_addr_list);
6577c478bd9Sstevel@tonic-gate current_targetaddr = targetaddr_list;
6587c478bd9Sstevel@tonic-gate
6597c478bd9Sstevel@tonic-gate /*
6607c478bd9Sstevel@tonic-gate * Set the starting_seq_num for the first targetaddr.
6617c478bd9Sstevel@tonic-gate * If we are sending ICMP Echo Requests, the sequence number is same as
6627c478bd9Sstevel@tonic-gate * ICMP sequence number, and it starts from zero. If we are sending UDP
6637c478bd9Sstevel@tonic-gate * packets, the sequence number is the destination UDP port number,
6647c478bd9Sstevel@tonic-gate * which starts from dest_port. At each probe, this sequence number is
6657c478bd9Sstevel@tonic-gate * incremented by one.
6667c478bd9Sstevel@tonic-gate * We set the starting_seq_num for first targetaddr here. The
6677c478bd9Sstevel@tonic-gate * following ones will be set by looking at where we left with the last
6687c478bd9Sstevel@tonic-gate * targetaddr.
6697c478bd9Sstevel@tonic-gate */
6707c478bd9Sstevel@tonic-gate current_targetaddr->starting_seq_num = use_udp ? dest_port : 0;
6717c478bd9Sstevel@tonic-gate
6727c478bd9Sstevel@tonic-gate if (stats) {
6737c478bd9Sstevel@tonic-gate if (probe_all || !nflag) {
6747c478bd9Sstevel@tonic-gate Printf("PING %s: %d data bytes\n", targethost, datalen);
6757c478bd9Sstevel@tonic-gate } else {
6767c478bd9Sstevel@tonic-gate if (ai_dst->ai_family == AF_INET) {
677e11c3f44Smeem (void) inet_ntop(AF_INET,
678e11c3f44Smeem &((struct sockaddr_in *)(void *)
6797c478bd9Sstevel@tonic-gate ai_dst->ai_addr)->sin_addr,
680e11c3f44Smeem abuf, sizeof (abuf));
6817c478bd9Sstevel@tonic-gate } else {
682e11c3f44Smeem (void) inet_ntop(AF_INET6,
683e11c3f44Smeem &((struct sockaddr_in6 *)(void *)
6847c478bd9Sstevel@tonic-gate ai_dst->ai_addr)->sin6_addr,
685e11c3f44Smeem abuf, sizeof (abuf));
6867c478bd9Sstevel@tonic-gate }
687e11c3f44Smeem Printf("PING %s (%s): %d data bytes\n",
688e11c3f44Smeem targethost, abuf, datalen);
6897c478bd9Sstevel@tonic-gate }
6907c478bd9Sstevel@tonic-gate }
6917c478bd9Sstevel@tonic-gate
6927c478bd9Sstevel@tonic-gate /* Let's get things going */
6937c478bd9Sstevel@tonic-gate send_scheduled_probe();
6947c478bd9Sstevel@tonic-gate
6957c478bd9Sstevel@tonic-gate /* SIGALRM is used to send the next scheduled probe */
6967c478bd9Sstevel@tonic-gate (void) sigset(SIGALRM, sigalrm_handler);
6977c478bd9Sstevel@tonic-gate schedule_sigalrm();
6987c478bd9Sstevel@tonic-gate
6997c478bd9Sstevel@tonic-gate /*
7007c478bd9Sstevel@tonic-gate * From now on, we'll always be listening to ICMP packets. As SIGALRM
7017c478bd9Sstevel@tonic-gate * comes in, sigalrm_handler() will be invoked and send another
7027c478bd9Sstevel@tonic-gate * probe.
7037c478bd9Sstevel@tonic-gate */
7047c478bd9Sstevel@tonic-gate recv_icmp_packet(ai_dst, recv_sock6, recv_sock, udp_src_port6,
7057c478bd9Sstevel@tonic-gate udp_src_port);
7067c478bd9Sstevel@tonic-gate
7078c332a0dSja97890 return (EXIT_SUCCESS); /* should never come here */
7087c478bd9Sstevel@tonic-gate }
7097c478bd9Sstevel@tonic-gate
7107c478bd9Sstevel@tonic-gate /*
7117c478bd9Sstevel@tonic-gate * Build the target IP address list. Use command line options and
7127c478bd9Sstevel@tonic-gate * name lookup results returned from name server to determine which addresses
7137c478bd9Sstevel@tonic-gate * to probe, how many times, in which order.
7147c478bd9Sstevel@tonic-gate */
7157c478bd9Sstevel@tonic-gate static struct targetaddr *
build_targetaddr_list(struct addrinfo * ai_dst,union any_in_addr * src_addr_list)7167c478bd9Sstevel@tonic-gate build_targetaddr_list(struct addrinfo *ai_dst, union any_in_addr *src_addr_list)
7177c478bd9Sstevel@tonic-gate {
7187c478bd9Sstevel@tonic-gate struct targetaddr *head = NULL;
7197c478bd9Sstevel@tonic-gate struct targetaddr *targetaddr;
7207c478bd9Sstevel@tonic-gate struct targetaddr **nextp;
7217c478bd9Sstevel@tonic-gate int num_dst;
7227c478bd9Sstevel@tonic-gate int i;
7237c478bd9Sstevel@tonic-gate struct addrinfo *aip;
7247c478bd9Sstevel@tonic-gate
7257c478bd9Sstevel@tonic-gate aip = ai_dst;
7267c478bd9Sstevel@tonic-gate if (probe_all)
7277c478bd9Sstevel@tonic-gate num_dst = num_v4 + num_v6;
7287c478bd9Sstevel@tonic-gate else
7297c478bd9Sstevel@tonic-gate num_dst = 1;
7307c478bd9Sstevel@tonic-gate num_targetaddrs = num_dst;
7317c478bd9Sstevel@tonic-gate nextp = &head;
7327c478bd9Sstevel@tonic-gate for (aip = ai_dst, i = 0; aip != NULL; aip = aip->ai_next, i++) {
7337c478bd9Sstevel@tonic-gate if (aip->ai_family == AF_INET && num_v4 != 0) {
7347c478bd9Sstevel@tonic-gate targetaddr = create_targetaddr_item(aip->ai_family,
7357c478bd9Sstevel@tonic-gate (union any_in_addr *)
7367c478bd9Sstevel@tonic-gate /* LINTED E_BAD_PTR_CAST_ALIGN */
7377c478bd9Sstevel@tonic-gate &((struct sockaddr_in *)
7387c478bd9Sstevel@tonic-gate aip->ai_addr)->sin_addr,
7397c478bd9Sstevel@tonic-gate &src_addr_list[i]);
7407c478bd9Sstevel@tonic-gate } else if (aip->ai_family == AF_INET6 && num_v6 != 0) {
7417c478bd9Sstevel@tonic-gate targetaddr = create_targetaddr_item(aip->ai_family,
7427c478bd9Sstevel@tonic-gate (union any_in_addr *)
7437c478bd9Sstevel@tonic-gate /* LINTED E_BAD_PTR_CAST_ALIGN */
7447c478bd9Sstevel@tonic-gate &((struct sockaddr_in6 *)
7457c478bd9Sstevel@tonic-gate aip->ai_addr)->sin6_addr,
7467c478bd9Sstevel@tonic-gate &src_addr_list[i]);
7477c478bd9Sstevel@tonic-gate } else {
7487c478bd9Sstevel@tonic-gate continue;
7497c478bd9Sstevel@tonic-gate }
7507c478bd9Sstevel@tonic-gate *nextp = targetaddr;
7517c478bd9Sstevel@tonic-gate nextp = &targetaddr->next;
7527c478bd9Sstevel@tonic-gate if (num_targetaddrs == 1)
7537c478bd9Sstevel@tonic-gate break;
7547c478bd9Sstevel@tonic-gate }
7557c478bd9Sstevel@tonic-gate if (npackets == 0 && stats)
7567c478bd9Sstevel@tonic-gate *nextp = head; /* keep going indefinitely */
7577c478bd9Sstevel@tonic-gate
7587c478bd9Sstevel@tonic-gate return (head);
7597c478bd9Sstevel@tonic-gate }
7607c478bd9Sstevel@tonic-gate
7617c478bd9Sstevel@tonic-gate /*
7627c478bd9Sstevel@tonic-gate * Given an address family, dst and src addresses, by also looking at the
7637c478bd9Sstevel@tonic-gate * options provided at the command line, this function creates a targetaddr
7647c478bd9Sstevel@tonic-gate * to be linked with others, forming a global targetaddr list. Each targetaddr
7657c478bd9Sstevel@tonic-gate * item contains information about probes sent to a specific IP address.
7667c478bd9Sstevel@tonic-gate */
7677c478bd9Sstevel@tonic-gate static struct targetaddr *
create_targetaddr_item(int family,union any_in_addr * dst_addr,union any_in_addr * src_addr)7687c478bd9Sstevel@tonic-gate create_targetaddr_item(int family, union any_in_addr *dst_addr,
7697c478bd9Sstevel@tonic-gate union any_in_addr *src_addr)
7707c478bd9Sstevel@tonic-gate {
7717c478bd9Sstevel@tonic-gate struct targetaddr *targetaddr;
7727c478bd9Sstevel@tonic-gate
7737c478bd9Sstevel@tonic-gate targetaddr = (struct targetaddr *)malloc(sizeof (struct targetaddr));
7747c478bd9Sstevel@tonic-gate if (targetaddr == NULL) {
7757c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: malloc %s\n", progname, strerror(errno));
7767c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
7777c478bd9Sstevel@tonic-gate }
7787c478bd9Sstevel@tonic-gate targetaddr->family = family;
7797c478bd9Sstevel@tonic-gate targetaddr->dst_addr = *dst_addr;
7807c478bd9Sstevel@tonic-gate targetaddr->src_addr = *src_addr;
7817c478bd9Sstevel@tonic-gate if (stats) {
7827c478bd9Sstevel@tonic-gate /*
7837c478bd9Sstevel@tonic-gate * npackets is only defined if we are in stats mode.
7847c478bd9Sstevel@tonic-gate * npackets determines how many probes to send to each target
7857c478bd9Sstevel@tonic-gate * IP address. npackets == 0 means send only 1 and move on to
7867c478bd9Sstevel@tonic-gate * next target IP.
7877c478bd9Sstevel@tonic-gate */
7887c478bd9Sstevel@tonic-gate if (npackets > 0)
7897c478bd9Sstevel@tonic-gate targetaddr->num_probes = npackets;
7907c478bd9Sstevel@tonic-gate else
7917c478bd9Sstevel@tonic-gate targetaddr->num_probes = 1;
7927c478bd9Sstevel@tonic-gate } else {
7937c478bd9Sstevel@tonic-gate targetaddr->num_probes = timeout;
7947c478bd9Sstevel@tonic-gate }
7957c478bd9Sstevel@tonic-gate targetaddr->num_sent = 0;
7967c478bd9Sstevel@tonic-gate targetaddr->got_reply = _B_FALSE;
7977c478bd9Sstevel@tonic-gate targetaddr->probing_done = _B_FALSE;
7987c478bd9Sstevel@tonic-gate targetaddr->starting_seq_num = 0; /* actual value will be set later */
7997c478bd9Sstevel@tonic-gate targetaddr->next = NULL; /* actual value will be set later */
8007c478bd9Sstevel@tonic-gate
8017c478bd9Sstevel@tonic-gate return (targetaddr);
8027c478bd9Sstevel@tonic-gate }
8037c478bd9Sstevel@tonic-gate
8047c478bd9Sstevel@tonic-gate /*
8057c478bd9Sstevel@tonic-gate * print "unknown host" message
8067c478bd9Sstevel@tonic-gate */
8077c478bd9Sstevel@tonic-gate static void
print_unknown_host_msg(const char * protocol,const char * hostname)8087c478bd9Sstevel@tonic-gate print_unknown_host_msg(const char *protocol, const char *hostname)
8097c478bd9Sstevel@tonic-gate {
8107c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: unknown%s host %s\n", progname, protocol,
8117c478bd9Sstevel@tonic-gate hostname);
8127c478bd9Sstevel@tonic-gate }
8137c478bd9Sstevel@tonic-gate
8147c478bd9Sstevel@tonic-gate /*
8157c478bd9Sstevel@tonic-gate * Resolve hostnames for the target host and gateways. Also, determine source
8167c478bd9Sstevel@tonic-gate * addresses to use for each target address.
8177c478bd9Sstevel@tonic-gate */
8187c478bd9Sstevel@tonic-gate static void
resolve_nodes(struct addrinfo ** ai_dstp,struct addrinfo ** ai_nexthopp,union any_in_addr ** src_addr_listp)8194c10bc16Spwernau resolve_nodes(struct addrinfo **ai_dstp, struct addrinfo **ai_nexthopp,
8204c10bc16Spwernau union any_in_addr **src_addr_listp)
8217c478bd9Sstevel@tonic-gate {
8227c478bd9Sstevel@tonic-gate struct addrinfo *ai_dst = NULL;
8234c10bc16Spwernau struct addrinfo *ai_nexthop = NULL;
8247c478bd9Sstevel@tonic-gate struct addrinfo *aip = NULL;
8257c478bd9Sstevel@tonic-gate union any_in_addr *src_addr_list = NULL;
8267c478bd9Sstevel@tonic-gate int num_resolved_gw = 0;
8277c478bd9Sstevel@tonic-gate int num_resolved_gw6 = 0;
8287c478bd9Sstevel@tonic-gate
8297c478bd9Sstevel@tonic-gate get_hostinfo(targethost, family_input, &ai_dst);
8307c478bd9Sstevel@tonic-gate if (ai_dst == NULL) {
8317c478bd9Sstevel@tonic-gate print_unknown_host_msg("", targethost);
8327c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
8337c478bd9Sstevel@tonic-gate }
8344c10bc16Spwernau if (nexthop != NULL) {
8354c10bc16Spwernau get_hostinfo(nexthop, family_input, &ai_nexthop);
8364c10bc16Spwernau if (ai_nexthop == NULL) {
8374c10bc16Spwernau print_unknown_host_msg("", nexthop);
8384c10bc16Spwernau exit(EXIT_FAILURE);
8394c10bc16Spwernau }
8404c10bc16Spwernau }
8417c478bd9Sstevel@tonic-gate /* Get a count of the v4 & v6 addresses */
8427c478bd9Sstevel@tonic-gate for (aip = ai_dst; aip != NULL; aip = aip->ai_next) {
8437c478bd9Sstevel@tonic-gate switch (aip->ai_family) {
8447c478bd9Sstevel@tonic-gate case AF_INET:
8457c478bd9Sstevel@tonic-gate num_v4++;
8467c478bd9Sstevel@tonic-gate break;
8477c478bd9Sstevel@tonic-gate case AF_INET6:
8487c478bd9Sstevel@tonic-gate num_v6++;
8497c478bd9Sstevel@tonic-gate break;
8507c478bd9Sstevel@tonic-gate }
8517c478bd9Sstevel@tonic-gate }
8527c478bd9Sstevel@tonic-gate
8537c478bd9Sstevel@tonic-gate if (family_input == AF_UNSPEC && !probe_all) {
8547c478bd9Sstevel@tonic-gate family_input = ai_dst->ai_family;
8557c478bd9Sstevel@tonic-gate }
8567c478bd9Sstevel@tonic-gate
8577c478bd9Sstevel@tonic-gate /* resolve gateways */
8587c478bd9Sstevel@tonic-gate if (num_gw > 0) {
8597c478bd9Sstevel@tonic-gate get_gwaddrs(gw_list, family_input, gw_IP_list, gw_IP_list6,
8607c478bd9Sstevel@tonic-gate &num_resolved_gw, &num_resolved_gw6);
8617c478bd9Sstevel@tonic-gate
8627c478bd9Sstevel@tonic-gate /* we couldn't resolve a gateway as an IPv6 host */
8637c478bd9Sstevel@tonic-gate if (num_resolved_gw6 != num_gw && num_v6 != 0 &&
8647c478bd9Sstevel@tonic-gate (family_input == AF_INET6 || family_input == AF_UNSPEC)) {
8657c478bd9Sstevel@tonic-gate print_unknown_host_msg(" IPv6",
8667c478bd9Sstevel@tonic-gate gw_list[num_resolved_gw6]);
8677c478bd9Sstevel@tonic-gate num_v6 = 0;
8687c478bd9Sstevel@tonic-gate }
8697c478bd9Sstevel@tonic-gate
8707c478bd9Sstevel@tonic-gate /* we couldn't resolve a gateway as an IPv4 host */
8717c478bd9Sstevel@tonic-gate if (num_resolved_gw != num_gw && num_v4 != 0 &&
8727c478bd9Sstevel@tonic-gate (family_input == AF_INET || family_input == AF_UNSPEC)) {
8737c478bd9Sstevel@tonic-gate print_unknown_host_msg(" IPv4",
8747c478bd9Sstevel@tonic-gate gw_list[num_resolved_gw]);
8757c478bd9Sstevel@tonic-gate num_v4 = 0;
8767c478bd9Sstevel@tonic-gate }
8777c478bd9Sstevel@tonic-gate }
8787c478bd9Sstevel@tonic-gate
8797c478bd9Sstevel@tonic-gate if (num_v4 == 0 && num_v6 == 0)
8807c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
8817c478bd9Sstevel@tonic-gate
8827c478bd9Sstevel@tonic-gate select_all_src_addrs(&src_addr_list, ai_dst, gw_IP_list, gw_IP_list6);
8837c478bd9Sstevel@tonic-gate *ai_dstp = ai_dst;
8844c10bc16Spwernau *ai_nexthopp = ai_nexthop;
8857c478bd9Sstevel@tonic-gate *src_addr_listp = src_addr_list;
8867c478bd9Sstevel@tonic-gate }
8877c478bd9Sstevel@tonic-gate
8887c478bd9Sstevel@tonic-gate /*
8897c478bd9Sstevel@tonic-gate * Resolve the gateway names, splitting results into v4 and v6 lists.
8907c478bd9Sstevel@tonic-gate * Gateway addresses are added to the appropriate passed-in array; the
8917c478bd9Sstevel@tonic-gate * number of resolved gateways for each af is returned in resolved[6].
8927c478bd9Sstevel@tonic-gate * Assumes that passed-in arrays are large enough for MAX_GWS[6] addrs
8937c478bd9Sstevel@tonic-gate * and resolved[6] ptrs are non-null; ignores array and counter if the
8947c478bd9Sstevel@tonic-gate * address family param makes them irrelevant.
8957c478bd9Sstevel@tonic-gate */
8967c478bd9Sstevel@tonic-gate static void
get_gwaddrs(char ** gw_list,int family,union any_in_addr * gwIPlist,union any_in_addr * gwIPlist6,int * resolved,int * resolved6)8977c478bd9Sstevel@tonic-gate get_gwaddrs(char **gw_list, int family, union any_in_addr *gwIPlist,
8987c478bd9Sstevel@tonic-gate union any_in_addr *gwIPlist6, int *resolved, int *resolved6)
8997c478bd9Sstevel@tonic-gate {
9007c478bd9Sstevel@tonic-gate int i;
9017c478bd9Sstevel@tonic-gate boolean_t check_v4 = _B_TRUE, check_v6 = _B_TRUE;
9027c478bd9Sstevel@tonic-gate struct addrinfo *ai = NULL;
9037c478bd9Sstevel@tonic-gate struct addrinfo *aip = NULL;
9047c478bd9Sstevel@tonic-gate
9057c478bd9Sstevel@tonic-gate *resolved = *resolved6 = 0;
9067c478bd9Sstevel@tonic-gate switch (family) {
9077c478bd9Sstevel@tonic-gate case AF_UNSPEC:
9087c478bd9Sstevel@tonic-gate break;
9097c478bd9Sstevel@tonic-gate case AF_INET:
9107c478bd9Sstevel@tonic-gate check_v6 = _B_FALSE;
9117c478bd9Sstevel@tonic-gate break;
9127c478bd9Sstevel@tonic-gate case AF_INET6:
9137c478bd9Sstevel@tonic-gate check_v4 = _B_FALSE;
9147c478bd9Sstevel@tonic-gate break;
9157c478bd9Sstevel@tonic-gate default:
9167c478bd9Sstevel@tonic-gate return;
9177c478bd9Sstevel@tonic-gate }
9187c478bd9Sstevel@tonic-gate
9197c478bd9Sstevel@tonic-gate if (check_v4 && num_gw >= MAX_GWS) {
9207c478bd9Sstevel@tonic-gate check_v4 = _B_FALSE;
9217c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: too many IPv4 gateways\n", progname);
9227c478bd9Sstevel@tonic-gate }
9237c478bd9Sstevel@tonic-gate if (check_v6 && num_gw > MAX_GWS6) {
9247c478bd9Sstevel@tonic-gate check_v6 = _B_FALSE;
9257c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: too many IPv6 gateways\n", progname);
9267c478bd9Sstevel@tonic-gate }
9277c478bd9Sstevel@tonic-gate
9287c478bd9Sstevel@tonic-gate for (i = 0; i < num_gw; i++) {
9297c478bd9Sstevel@tonic-gate if (!check_v4 && !check_v6)
9307c478bd9Sstevel@tonic-gate return;
9317c478bd9Sstevel@tonic-gate get_hostinfo(gw_list[i], family, &ai);
9327c478bd9Sstevel@tonic-gate if (ai == NULL)
9337c478bd9Sstevel@tonic-gate return;
9347c478bd9Sstevel@tonic-gate if (check_v4 && num_v4 != 0) {
9357c478bd9Sstevel@tonic-gate for (aip = ai; aip != NULL; aip = aip->ai_next) {
9367c478bd9Sstevel@tonic-gate if (aip->ai_family == AF_INET) {
9377c478bd9Sstevel@tonic-gate /* LINTED E_BAD_PTR_CAST_ALIGN */
9387c478bd9Sstevel@tonic-gate bcopy(&((struct sockaddr_in *)
9397c478bd9Sstevel@tonic-gate aip->ai_addr)->sin_addr,
9407c478bd9Sstevel@tonic-gate &gwIPlist[i].addr,
9417c478bd9Sstevel@tonic-gate aip->ai_addrlen);
9427c478bd9Sstevel@tonic-gate (*resolved)++;
9437c478bd9Sstevel@tonic-gate break;
9447c478bd9Sstevel@tonic-gate }
9457c478bd9Sstevel@tonic-gate }
9467c478bd9Sstevel@tonic-gate } else if (check_v4) {
9477c478bd9Sstevel@tonic-gate check_v4 = _B_FALSE;
9487c478bd9Sstevel@tonic-gate }
9497c478bd9Sstevel@tonic-gate if (check_v6 && num_v6 != 0) {
9507c478bd9Sstevel@tonic-gate for (aip = ai; aip != NULL; aip = aip->ai_next) {
9517c478bd9Sstevel@tonic-gate if (aip->ai_family == AF_INET6) {
9527c478bd9Sstevel@tonic-gate /* LINTED E_BAD_PTR_CAST_ALIGN */
9537c478bd9Sstevel@tonic-gate bcopy(&((struct sockaddr_in6 *)
9547c478bd9Sstevel@tonic-gate aip->ai_addr)->sin6_addr,
9557c478bd9Sstevel@tonic-gate &gwIPlist6[i].addr6,
9567c478bd9Sstevel@tonic-gate aip->ai_addrlen);
9577c478bd9Sstevel@tonic-gate (*resolved6)++;
9587c478bd9Sstevel@tonic-gate break;
9597c478bd9Sstevel@tonic-gate }
9607c478bd9Sstevel@tonic-gate }
9617c478bd9Sstevel@tonic-gate } else if (check_v6) {
9627c478bd9Sstevel@tonic-gate check_v6 = _B_FALSE;
9637c478bd9Sstevel@tonic-gate }
9647c478bd9Sstevel@tonic-gate }
9657c478bd9Sstevel@tonic-gate freeaddrinfo(ai);
9667c478bd9Sstevel@tonic-gate }
9677c478bd9Sstevel@tonic-gate
9687c478bd9Sstevel@tonic-gate /*
9697c478bd9Sstevel@tonic-gate * Given the list of gateways, extends the list with its mirror image. This is
9707c478bd9Sstevel@tonic-gate * used when -l/-S is used. The middle gateway will be the target address. We'll
9717c478bd9Sstevel@tonic-gate * leave it blank for now.
9727c478bd9Sstevel@tonic-gate */
9737c478bd9Sstevel@tonic-gate static void
mirror_gws(union any_in_addr * gwIPlist,int family)9747c478bd9Sstevel@tonic-gate mirror_gws(union any_in_addr *gwIPlist, int family)
9757c478bd9Sstevel@tonic-gate {
9767c478bd9Sstevel@tonic-gate int effective_num_gw;
9777c478bd9Sstevel@tonic-gate int i;
9787c478bd9Sstevel@tonic-gate
9797c478bd9Sstevel@tonic-gate /* We add 1 because we put the target as the middle gateway */
9807c478bd9Sstevel@tonic-gate effective_num_gw = 2 * num_gw + 1;
9817c478bd9Sstevel@tonic-gate
9827c478bd9Sstevel@tonic-gate if ((family == AF_INET && effective_num_gw >= MAX_GWS) ||
9837c478bd9Sstevel@tonic-gate (family == AF_INET6 && effective_num_gw > MAX_GWS6)) {
9847c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: too many %s gateways\n",
9857c478bd9Sstevel@tonic-gate progname, (family == AF_INET) ? "IPv4" : "IPv6");
9867c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
9877c478bd9Sstevel@tonic-gate }
9887c478bd9Sstevel@tonic-gate
9897c478bd9Sstevel@tonic-gate for (i = 0; i < num_gw; i++)
9907c478bd9Sstevel@tonic-gate gwIPlist[num_gw + i + 1].addr6 = gwIPlist[num_gw - i - 1].addr6;
9917c478bd9Sstevel@tonic-gate }
9927c478bd9Sstevel@tonic-gate
9937c478bd9Sstevel@tonic-gate /*
9947c478bd9Sstevel@tonic-gate * Given IP address or hostname, return addrinfo list.
9957c478bd9Sstevel@tonic-gate * Assumes that addrinfo ** ptr is non-null.
9967c478bd9Sstevel@tonic-gate */
9977c478bd9Sstevel@tonic-gate static void
get_hostinfo(char * host,int family,struct addrinfo ** aipp)9987c478bd9Sstevel@tonic-gate get_hostinfo(char *host, int family, struct addrinfo **aipp)
9997c478bd9Sstevel@tonic-gate {
10007c478bd9Sstevel@tonic-gate struct addrinfo hints, *ai;
10017c478bd9Sstevel@tonic-gate struct in6_addr addr6;
10027c478bd9Sstevel@tonic-gate struct in_addr addr;
10037c478bd9Sstevel@tonic-gate boolean_t broadcast; /* is this 255.255.255.255? */
10047c478bd9Sstevel@tonic-gate char tmp_buf[INET6_ADDRSTRLEN];
10057c478bd9Sstevel@tonic-gate int rc;
10067c478bd9Sstevel@tonic-gate
10077c478bd9Sstevel@tonic-gate /* check if broadcast */
10087c478bd9Sstevel@tonic-gate if (strcmp(host, "255.255.255.255") == 0)
10097c478bd9Sstevel@tonic-gate broadcast = _B_TRUE;
10107c478bd9Sstevel@tonic-gate else
10117c478bd9Sstevel@tonic-gate broadcast = _B_FALSE;
10127c478bd9Sstevel@tonic-gate
10137c478bd9Sstevel@tonic-gate /* check if IPv4-mapped address or broadcast */
10147c478bd9Sstevel@tonic-gate if (((inet_pton(AF_INET6, host, &addr6) > 0) &&
10157c478bd9Sstevel@tonic-gate IN6_IS_ADDR_V4MAPPED(&addr6)) || broadcast) {
10167c478bd9Sstevel@tonic-gate if (!broadcast) {
10177c478bd9Sstevel@tonic-gate /*
10187c478bd9Sstevel@tonic-gate * Peel off the "mapping" stuff, leaving 32 bit IPv4
10197c478bd9Sstevel@tonic-gate * address.
10207c478bd9Sstevel@tonic-gate */
10217c478bd9Sstevel@tonic-gate IN6_V4MAPPED_TO_INADDR(&addr6, &addr);
10227c478bd9Sstevel@tonic-gate
10237c478bd9Sstevel@tonic-gate /* convert it back to a string */
10247c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET, (void *)&addr, tmp_buf,
10257c478bd9Sstevel@tonic-gate sizeof (tmp_buf));
10267c478bd9Sstevel@tonic-gate /*
10277c478bd9Sstevel@tonic-gate * Now the host is an IPv4 address.
10287c478bd9Sstevel@tonic-gate * Since it previously was a v4 mapped v6 address
10297c478bd9Sstevel@tonic-gate * we can be sure that the size of buffer 'host'
10307c478bd9Sstevel@tonic-gate * is large enough to contain the associated v4
10317c478bd9Sstevel@tonic-gate * address and so we don't need to use a strn/lcpy
10327c478bd9Sstevel@tonic-gate * here.
10337c478bd9Sstevel@tonic-gate */
10347c478bd9Sstevel@tonic-gate (void) strcpy(host, tmp_buf);
10357c478bd9Sstevel@tonic-gate }
10367c478bd9Sstevel@tonic-gate /*
10377c478bd9Sstevel@tonic-gate * If it's a broadcast address, it cannot be an IPv6 address.
10387c478bd9Sstevel@tonic-gate * Also, if it's a mapped address, we convert it into IPv4
10397c478bd9Sstevel@tonic-gate * address because ping will send and receive IPv4 packets for
10407c478bd9Sstevel@tonic-gate * that address. Therefore, it's a failure case to ask
10417c478bd9Sstevel@tonic-gate * get_hostinfo() to treat a broadcast or a mapped address
10427c478bd9Sstevel@tonic-gate * as an IPv6 address.
10437c478bd9Sstevel@tonic-gate */
10447c478bd9Sstevel@tonic-gate if (family == AF_INET6) {
10457c478bd9Sstevel@tonic-gate return;
10467c478bd9Sstevel@tonic-gate }
10477c478bd9Sstevel@tonic-gate }
10487c478bd9Sstevel@tonic-gate
10497c478bd9Sstevel@tonic-gate (void) memset(&hints, 0, sizeof (hints));
10507c478bd9Sstevel@tonic-gate hints.ai_family = family;
10517c478bd9Sstevel@tonic-gate hints.ai_flags = AI_ADDRCONFIG;
10527c478bd9Sstevel@tonic-gate rc = getaddrinfo(host, NULL, &hints, &ai);
10537c478bd9Sstevel@tonic-gate if (rc != 0) {
10547c478bd9Sstevel@tonic-gate if (rc != EAI_NONAME)
10557c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: getaddrinfo: %s\n", progname,
10567c478bd9Sstevel@tonic-gate gai_strerror(rc));
10577c478bd9Sstevel@tonic-gate return;
10587c478bd9Sstevel@tonic-gate }
10597c478bd9Sstevel@tonic-gate *aipp = ai;
10607c478bd9Sstevel@tonic-gate }
10617c478bd9Sstevel@tonic-gate
10627c478bd9Sstevel@tonic-gate /*
10637c478bd9Sstevel@tonic-gate * For each IP address of the target host, determine a source address to use.
10647c478bd9Sstevel@tonic-gate */
10657c478bd9Sstevel@tonic-gate 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)10667c478bd9Sstevel@tonic-gate select_all_src_addrs(union any_in_addr **src_addr_list, struct addrinfo *ai,
10677c478bd9Sstevel@tonic-gate union any_in_addr *gwv4, union any_in_addr *gwv6)
10687c478bd9Sstevel@tonic-gate {
10697c478bd9Sstevel@tonic-gate union any_in_addr *list;
10707c478bd9Sstevel@tonic-gate struct addrinfo *aip;
10717c478bd9Sstevel@tonic-gate int num_dst = 1;
10727c478bd9Sstevel@tonic-gate int i;
10737c478bd9Sstevel@tonic-gate
1074e11c3f44Smeem if (probe_all) {
1075e11c3f44Smeem for (aip = ai; aip->ai_next != NULL; aip = aip->ai_next)
1076e11c3f44Smeem num_dst++;
1077e11c3f44Smeem }
10787c478bd9Sstevel@tonic-gate
1079e11c3f44Smeem list = calloc((size_t)num_dst, sizeof (union any_in_addr));
10807c478bd9Sstevel@tonic-gate if (list == NULL) {
10817c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: calloc: %s\n", progname, strerror(errno));
10827c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
10837c478bd9Sstevel@tonic-gate }
10847c478bd9Sstevel@tonic-gate
10857c478bd9Sstevel@tonic-gate /*
10867c478bd9Sstevel@tonic-gate * If there's a gateway, a routing header as a consequence, our kernel
10877c478bd9Sstevel@tonic-gate * picks the source address based on the first hop address, rather than
10887c478bd9Sstevel@tonic-gate * final destination address.
10897c478bd9Sstevel@tonic-gate */
10907c478bd9Sstevel@tonic-gate if (num_gw > 0) {
10917c478bd9Sstevel@tonic-gate if (ai->ai_family == AF_INET)
10927c478bd9Sstevel@tonic-gate select_src_addr(gwv4, ai->ai_family, &list[0]);
10937c478bd9Sstevel@tonic-gate else
10947c478bd9Sstevel@tonic-gate select_src_addr(gwv6, ai->ai_family, &list[0]);
10957c478bd9Sstevel@tonic-gate /*
10967c478bd9Sstevel@tonic-gate * Since the first gateway address is fixed, we'll use the same
10977c478bd9Sstevel@tonic-gate * src address for every different final destination address
10987c478bd9Sstevel@tonic-gate * we send to.
10997c478bd9Sstevel@tonic-gate */
11007c478bd9Sstevel@tonic-gate for (i = 1; i < num_dst; i++)
11017c478bd9Sstevel@tonic-gate list[i] = list[0];
11027c478bd9Sstevel@tonic-gate } else {
11037c478bd9Sstevel@tonic-gate /*
11047c478bd9Sstevel@tonic-gate * Although something like 'ping -l host' results in a routing
11057c478bd9Sstevel@tonic-gate * header, the first gateway address is the target host's
11067c478bd9Sstevel@tonic-gate * address. Therefore, as far as src address selection goes,
11077c478bd9Sstevel@tonic-gate * the result is same as having no routing header.
11087c478bd9Sstevel@tonic-gate */
11097c478bd9Sstevel@tonic-gate for (i = 0, aip = ai; i < num_dst && aip != NULL;
11107c478bd9Sstevel@tonic-gate i++, aip = aip->ai_next) {
11117c478bd9Sstevel@tonic-gate if (aip->ai_family == AF_INET) {
11127c478bd9Sstevel@tonic-gate if (num_v4 != 0) {
11137c478bd9Sstevel@tonic-gate select_src_addr((union any_in_addr *)
11147c478bd9Sstevel@tonic-gate /* LINTED E_BAD_PTR_CAST_ALIGN */
11157c478bd9Sstevel@tonic-gate &((struct sockaddr_in *)
11167c478bd9Sstevel@tonic-gate aip->ai_addr)->sin_addr,
11177c478bd9Sstevel@tonic-gate aip->ai_family,
11187c478bd9Sstevel@tonic-gate &list[i]);
11197c478bd9Sstevel@tonic-gate }
11207c478bd9Sstevel@tonic-gate } else {
11217c478bd9Sstevel@tonic-gate if (num_v6 != 0) {
11227c478bd9Sstevel@tonic-gate select_src_addr((union any_in_addr *)
11237c478bd9Sstevel@tonic-gate /* LINTED E_BAD_PTR_CAST_ALIGN */
11247c478bd9Sstevel@tonic-gate &((struct sockaddr_in6 *)
11257c478bd9Sstevel@tonic-gate aip->ai_addr)->sin6_addr,
11267c478bd9Sstevel@tonic-gate aip->ai_family,
11277c478bd9Sstevel@tonic-gate &list[i]);
11287c478bd9Sstevel@tonic-gate }
11297c478bd9Sstevel@tonic-gate }
11307c478bd9Sstevel@tonic-gate }
11317c478bd9Sstevel@tonic-gate }
11327c478bd9Sstevel@tonic-gate
11337c478bd9Sstevel@tonic-gate *src_addr_list = list;
11347c478bd9Sstevel@tonic-gate }
11357c478bd9Sstevel@tonic-gate
11367c478bd9Sstevel@tonic-gate /*
11377c478bd9Sstevel@tonic-gate * For a given destination address, determine a source address to use.
11387c478bd9Sstevel@tonic-gate * Returns wildcard address if it cannot determine the source address.
11397c478bd9Sstevel@tonic-gate */
11407c478bd9Sstevel@tonic-gate static void
select_src_addr(union any_in_addr * dst_addr,int family,union any_in_addr * src_addr)11417c478bd9Sstevel@tonic-gate select_src_addr(union any_in_addr *dst_addr, int family,
11427c478bd9Sstevel@tonic-gate union any_in_addr *src_addr)
11437c478bd9Sstevel@tonic-gate {
11447c478bd9Sstevel@tonic-gate struct sockaddr *sock;
11457c478bd9Sstevel@tonic-gate struct sockaddr_in *sin;
11467c478bd9Sstevel@tonic-gate struct sockaddr_in6 *sin6;
11477c478bd9Sstevel@tonic-gate int tmp_fd;
11487c478bd9Sstevel@tonic-gate size_t sock_len;
11497c478bd9Sstevel@tonic-gate
11507c478bd9Sstevel@tonic-gate sock = (struct sockaddr *)malloc(sizeof (struct sockaddr_in6));
11517c478bd9Sstevel@tonic-gate if (sock == NULL) {
11527c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: malloc: %s\n", progname, strerror(errno));
11537c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
11547c478bd9Sstevel@tonic-gate }
11557c478bd9Sstevel@tonic-gate (void) bzero(sock, sizeof (struct sockaddr_in6));
11567c478bd9Sstevel@tonic-gate
11577c478bd9Sstevel@tonic-gate if (family == AF_INET) {
11587c478bd9Sstevel@tonic-gate /* LINTED E_BAD_PTR_CAST_ALIGN */
11597c478bd9Sstevel@tonic-gate sin = (struct sockaddr_in *)sock;
11607c478bd9Sstevel@tonic-gate sin->sin_family = AF_INET;
11617c478bd9Sstevel@tonic-gate sin->sin_addr = dst_addr->addr;
11627c478bd9Sstevel@tonic-gate sin->sin_port = IPPORT_ECHO; /* port shouldn't be 0 */
11637c478bd9Sstevel@tonic-gate sock_len = sizeof (struct sockaddr_in);
11647c478bd9Sstevel@tonic-gate } else {
11657c478bd9Sstevel@tonic-gate /* LINTED E_BAD_PTR_CAST_ALIGN */
11667c478bd9Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)sock;
11677c478bd9Sstevel@tonic-gate sin6->sin6_family = AF_INET6;
11687c478bd9Sstevel@tonic-gate sin6->sin6_addr = dst_addr->addr6;
11697c478bd9Sstevel@tonic-gate sin6->sin6_port = IPPORT_ECHO; /* port shouldn't be 0 */
11707c478bd9Sstevel@tonic-gate sock_len = sizeof (struct sockaddr_in6);
11717c478bd9Sstevel@tonic-gate }
11727c478bd9Sstevel@tonic-gate
11737c478bd9Sstevel@tonic-gate /* open a UDP socket */
11747c478bd9Sstevel@tonic-gate if ((tmp_fd = socket(family, SOCK_DGRAM, 0)) < 0) {
11757c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: udp socket: %s\n", progname,
11767c478bd9Sstevel@tonic-gate strerror(errno));
11777c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
11787c478bd9Sstevel@tonic-gate }
11797c478bd9Sstevel@tonic-gate
11807c478bd9Sstevel@tonic-gate /* connect it */
11817c478bd9Sstevel@tonic-gate if (connect(tmp_fd, sock, sock_len) < 0) {
11827c478bd9Sstevel@tonic-gate /*
11837c478bd9Sstevel@tonic-gate * If there's no route to the destination, this connect() call
11847c478bd9Sstevel@tonic-gate * fails. We just return all-zero (wildcard) as the source
11857c478bd9Sstevel@tonic-gate * address, so that user can get to see "no route to dest"
11867c478bd9Sstevel@tonic-gate * message, as it'll try to send the probe packet out and will
11877c478bd9Sstevel@tonic-gate * receive ICMP unreachable.
11887c478bd9Sstevel@tonic-gate */
11897c478bd9Sstevel@tonic-gate if (family == AF_INET)
11907c478bd9Sstevel@tonic-gate src_addr->addr.s_addr = INADDR_ANY;
11917c478bd9Sstevel@tonic-gate else
11927c478bd9Sstevel@tonic-gate src_addr->addr6 = in6addr_any;
11937c478bd9Sstevel@tonic-gate free(sock);
11947c478bd9Sstevel@tonic-gate return;
11957c478bd9Sstevel@tonic-gate }
11967c478bd9Sstevel@tonic-gate
11977c478bd9Sstevel@tonic-gate /* get the local sock info */
11987c478bd9Sstevel@tonic-gate if (getsockname(tmp_fd, sock, &sock_len) < 0) {
11997c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: getsockname: %s\n", progname,
12007c478bd9Sstevel@tonic-gate strerror(errno));
12017c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
12027c478bd9Sstevel@tonic-gate }
12037c478bd9Sstevel@tonic-gate
12047c478bd9Sstevel@tonic-gate if (family == AF_INET) {
12057c478bd9Sstevel@tonic-gate src_addr->addr = sin->sin_addr;
12067c478bd9Sstevel@tonic-gate } else {
12077c478bd9Sstevel@tonic-gate src_addr->addr6 = sin6->sin6_addr;
12087c478bd9Sstevel@tonic-gate }
12097c478bd9Sstevel@tonic-gate
12107c478bd9Sstevel@tonic-gate (void) close(tmp_fd);
12117c478bd9Sstevel@tonic-gate free(sock);
12127c478bd9Sstevel@tonic-gate }
12137c478bd9Sstevel@tonic-gate
12147c478bd9Sstevel@tonic-gate /*
12154c10bc16Spwernau * Set the IP_NEXTHOP/IPV6_NEXTHOP socket option.
12164c10bc16Spwernau * exits on failure
12174c10bc16Spwernau */
12184c10bc16Spwernau static void
set_nexthop(int family,struct addrinfo * ai_nexthop,int sock)12194c10bc16Spwernau set_nexthop(int family, struct addrinfo *ai_nexthop, int sock)
12204c10bc16Spwernau {
12214c10bc16Spwernau if (family == AF_INET) {
12224c10bc16Spwernau ipaddr_t nh;
12234c10bc16Spwernau
12244c10bc16Spwernau /* LINTED E_BAD_PTR_CAST_ALIGN */
12254c10bc16Spwernau nh = ((struct sockaddr_in *)ai_nexthop->
12264c10bc16Spwernau ai_addr)->sin_addr.s_addr;
12274c10bc16Spwernau
1228f4b3ec61Sdh155122 /* now we need the sys_ip_config privilege */
12294c10bc16Spwernau (void) __priv_bracket(PRIV_ON);
12304c10bc16Spwernau if (setsockopt(sock, IPPROTO_IP, IP_NEXTHOP,
12314c10bc16Spwernau &nh, sizeof (ipaddr_t)) < 0) {
12321da45818Spwernau if (errno == EPERM)
12331da45818Spwernau Fprintf(stderr, "%s: Insufficient privilege "
12341da45818Spwernau "to specify IPv4 nexthop router.\n",
12351da45818Spwernau progname);
12361da45818Spwernau else
12374c10bc16Spwernau Fprintf(stderr, "%s: setsockopt %s\n",
12384c10bc16Spwernau progname, strerror(errno));
12394c10bc16Spwernau exit(EXIT_FAILURE);
12404c10bc16Spwernau }
12414c10bc16Spwernau (void) __priv_bracket(PRIV_OFF);
12424c10bc16Spwernau /* revert to non-privileged user */
12434c10bc16Spwernau } else {
12444c10bc16Spwernau struct sockaddr_in6 *nh;
12454c10bc16Spwernau
12464c10bc16Spwernau /* LINTED E_BAD_PTR_CAST_ALIGN */
12474c10bc16Spwernau nh = (struct sockaddr_in6 *)ai_nexthop->
12484c10bc16Spwernau ai_addr;
12494c10bc16Spwernau
12504c10bc16Spwernau if (setsockopt(sock, IPPROTO_IPV6, IPV6_NEXTHOP,
12514c10bc16Spwernau nh, sizeof (struct sockaddr_in6)) < 0) {
12524c10bc16Spwernau Fprintf(stderr, "%s: setsockopt %s\n",
12534c10bc16Spwernau progname, strerror(errno));
12544c10bc16Spwernau exit(EXIT_FAILURE);
12554c10bc16Spwernau }
12564c10bc16Spwernau }
12574c10bc16Spwernau }
12584c10bc16Spwernau
12594c10bc16Spwernau /*
12607c478bd9Sstevel@tonic-gate * Setup the socket for the given address family.
12617c478bd9Sstevel@tonic-gate * Returns _B_TRUE on success, _B_FALSE on failure. Failure is the case when no
12627c478bd9Sstevel@tonic-gate * interface can be found, or the specified interface (-i) is not found. On
12637c478bd9Sstevel@tonic-gate * library call failures, it exit()s.
12647c478bd9Sstevel@tonic-gate */
12657c478bd9Sstevel@tonic-gate 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)12667c478bd9Sstevel@tonic-gate setup_socket(int family, int *send_sockp, int *recv_sockp, int *if_index,
12674c10bc16Spwernau ushort_t *udp_src_port, struct addrinfo *ai_nexthop)
12687c478bd9Sstevel@tonic-gate {
12697c478bd9Sstevel@tonic-gate int send_sock;
12707c478bd9Sstevel@tonic-gate int recv_sock;
12717c478bd9Sstevel@tonic-gate struct sockaddr_in6 sin6;
12727c478bd9Sstevel@tonic-gate struct sockaddr_in sin;
12737c478bd9Sstevel@tonic-gate struct sockaddr *sp;
1274a356273cSpwernau struct ipsec_req req;
12757c478bd9Sstevel@tonic-gate size_t slen;
12767c478bd9Sstevel@tonic-gate int on = 1;
12777c478bd9Sstevel@tonic-gate uchar_t char_op;
12787c478bd9Sstevel@tonic-gate int int_op;
12797c478bd9Sstevel@tonic-gate
12807c478bd9Sstevel@tonic-gate /* now we need the net_icmpaccess privilege */
12817c478bd9Sstevel@tonic-gate (void) __priv_bracket(PRIV_ON);
12827c478bd9Sstevel@tonic-gate
12837c478bd9Sstevel@tonic-gate recv_sock = socket(family, SOCK_RAW,
12847c478bd9Sstevel@tonic-gate (family == AF_INET) ? IPPROTO_ICMP : IPPROTO_ICMPV6);
12857c478bd9Sstevel@tonic-gate
12867c478bd9Sstevel@tonic-gate if (recv_sock < 0) {
12877c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: socket %s\n", progname, strerror(errno));
12887c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
12897c478bd9Sstevel@tonic-gate }
12907c478bd9Sstevel@tonic-gate
12917c478bd9Sstevel@tonic-gate /* revert to non-privileged user after opening sockets */
12927c478bd9Sstevel@tonic-gate (void) __priv_bracket(PRIV_OFF);
12937c478bd9Sstevel@tonic-gate
1294a356273cSpwernau if (bypass) {
1295a356273cSpwernau (void) memset(&req, 0, sizeof (req));
1296a356273cSpwernau req.ipsr_ah_req = IPSEC_PREF_NEVER;
1297a356273cSpwernau req.ipsr_esp_req = IPSEC_PREF_NEVER;
1298a356273cSpwernau
1299a356273cSpwernau if (setsockopt(recv_sock, (family == AF_INET) ? IPPROTO_IP :
1300a356273cSpwernau IPPROTO_IPV6, IP_SEC_OPT, &req, sizeof (req)) < 0) {
13015086f56fSPaul Wernau switch (errno) {
13025086f56fSPaul Wernau case EPROTONOSUPPORT:
13035086f56fSPaul Wernau /*
13045086f56fSPaul Wernau * No IPsec subsystem or policy loaded.
13055086f56fSPaul Wernau * Bypass implicitly allowed.
13065086f56fSPaul Wernau */
13075086f56fSPaul Wernau break;
13085086f56fSPaul Wernau case EPERM:
1309a356273cSpwernau Fprintf(stderr, "%s: Insufficient privilege "
1310a356273cSpwernau "to bypass IPsec policy.\n", progname);
13115086f56fSPaul Wernau exit(EXIT_FAILURE);
13125086f56fSPaul Wernau break;
13135086f56fSPaul Wernau default:
1314a356273cSpwernau Fprintf(stderr, "%s: setsockopt %s\n", progname,
1315a356273cSpwernau strerror(errno));
1316a356273cSpwernau exit(EXIT_FAILURE);
13175086f56fSPaul Wernau break;
13185086f56fSPaul Wernau }
1319a356273cSpwernau }
1320a356273cSpwernau }
1321a356273cSpwernau
13227c478bd9Sstevel@tonic-gate /*
13237c478bd9Sstevel@tonic-gate * We always receive on raw icmp socket. But the sending socket can be
13247c478bd9Sstevel@tonic-gate * raw icmp or udp, depending on the use of -U flag.
13257c478bd9Sstevel@tonic-gate */
13267c478bd9Sstevel@tonic-gate if (use_udp) {
13277c478bd9Sstevel@tonic-gate send_sock = socket(family, SOCK_DGRAM, IPPROTO_UDP);
13287c478bd9Sstevel@tonic-gate if (send_sock < 0) {
13297c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: socket %s\n", progname,
13307c478bd9Sstevel@tonic-gate strerror(errno));
13317c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
13327c478bd9Sstevel@tonic-gate }
13337c478bd9Sstevel@tonic-gate
1334a356273cSpwernau if (bypass) {
1335a356273cSpwernau if (setsockopt(send_sock, (family == AF_INET) ?
1336a356273cSpwernau IPPROTO_IP : IPPROTO_IPV6, IP_SEC_OPT, &req,
1337a356273cSpwernau sizeof (req)) < 0) {
13385086f56fSPaul Wernau switch (errno) {
13395086f56fSPaul Wernau case EPROTONOSUPPORT:
13405086f56fSPaul Wernau /*
13415086f56fSPaul Wernau * No IPsec subsystem or policy loaded.
13425086f56fSPaul Wernau * Bypass implicitly allowed.
13435086f56fSPaul Wernau */
13445086f56fSPaul Wernau break;
13455086f56fSPaul Wernau case EPERM:
1346a356273cSpwernau Fprintf(stderr, "%s: Insufficient "
1347a356273cSpwernau "privilege to bypass IPsec "
1348a356273cSpwernau "policy.\n", progname);
13495086f56fSPaul Wernau exit(EXIT_FAILURE);
13505086f56fSPaul Wernau break;
13515086f56fSPaul Wernau default:
1352a356273cSpwernau Fprintf(stderr, "%s: setsockopt %s\n",
1353a356273cSpwernau progname, strerror(errno));
1354a356273cSpwernau exit(EXIT_FAILURE);
13555086f56fSPaul Wernau break;
13565086f56fSPaul Wernau }
1357a356273cSpwernau }
1358a356273cSpwernau }
1359a356273cSpwernau
13607c478bd9Sstevel@tonic-gate /*
13617c478bd9Sstevel@tonic-gate * In order to distinguish replies to our UDP probes from
13627c478bd9Sstevel@tonic-gate * other pings', we need to know our source port number.
13637c478bd9Sstevel@tonic-gate */
13647c478bd9Sstevel@tonic-gate if (family == AF_INET) {
13657c478bd9Sstevel@tonic-gate sp = (struct sockaddr *)&sin;
13667c478bd9Sstevel@tonic-gate slen = sizeof (sin);
13677c478bd9Sstevel@tonic-gate } else {
13687c478bd9Sstevel@tonic-gate sp = (struct sockaddr *)&sin6;
13697c478bd9Sstevel@tonic-gate slen = sizeof (sin6);
13707c478bd9Sstevel@tonic-gate }
13717c478bd9Sstevel@tonic-gate bzero(sp, slen);
13727c478bd9Sstevel@tonic-gate sp->sa_family = family;
13737c478bd9Sstevel@tonic-gate
13747c478bd9Sstevel@tonic-gate /* Let's bind() send_sock to wildcard address and port */
13757c478bd9Sstevel@tonic-gate if (bind(send_sock, sp, slen) < 0) {
13767c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: bind %s\n", progname,
13777c478bd9Sstevel@tonic-gate strerror(errno));
13787c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
13797c478bd9Sstevel@tonic-gate }
13807c478bd9Sstevel@tonic-gate
13817c478bd9Sstevel@tonic-gate /* .... and see what port kernel picked for us */
13827c478bd9Sstevel@tonic-gate if (getsockname(send_sock, sp, &slen) < 0) {
13837c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: getsockname %s\n", progname,
13847c478bd9Sstevel@tonic-gate strerror(errno));
13857c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
13867c478bd9Sstevel@tonic-gate }
13877c478bd9Sstevel@tonic-gate *udp_src_port = (family == AF_INET) ? sin.sin_port :
13887c478bd9Sstevel@tonic-gate sin6.sin6_port;
13897c478bd9Sstevel@tonic-gate } else {
13907c478bd9Sstevel@tonic-gate send_sock = recv_sock;
13917c478bd9Sstevel@tonic-gate }
13927c478bd9Sstevel@tonic-gate
1393bd670b35SErik Nordmark if (nexthop != NULL)
1394bd670b35SErik Nordmark set_nexthop(family, ai_nexthop, send_sock);
1395bd670b35SErik Nordmark
13967c478bd9Sstevel@tonic-gate int_op = 48 * 1024;
13977c478bd9Sstevel@tonic-gate if (int_op < datalen)
13987c478bd9Sstevel@tonic-gate int_op = datalen;
13997c478bd9Sstevel@tonic-gate if (setsockopt(recv_sock, SOL_SOCKET, SO_RCVBUF, (char *)&int_op,
14007c478bd9Sstevel@tonic-gate sizeof (int_op)) == -1) {
14017c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: setsockopt SO_RCVBUF %s\n", progname,
14027c478bd9Sstevel@tonic-gate strerror(errno));
14037c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
14047c478bd9Sstevel@tonic-gate }
14057c478bd9Sstevel@tonic-gate
14067c478bd9Sstevel@tonic-gate if (setsockopt(send_sock, SOL_SOCKET, SO_SNDBUF, (char *)&int_op,
14077c478bd9Sstevel@tonic-gate sizeof (int_op)) == -1) {
14087c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: setsockopt SO_SNDBUF %s\n", progname,
14097c478bd9Sstevel@tonic-gate strerror(errno));
14107c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
14117c478bd9Sstevel@tonic-gate }
14127c478bd9Sstevel@tonic-gate
14137c478bd9Sstevel@tonic-gate if (options & SO_DEBUG) {
14147c478bd9Sstevel@tonic-gate if (setsockopt(send_sock, SOL_SOCKET, SO_DEBUG, (char *)&on,
14157c478bd9Sstevel@tonic-gate sizeof (on)) == -1) {
14167c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: setsockopt SO_DEBUG %s\n",
14177c478bd9Sstevel@tonic-gate progname, strerror(errno));
14187c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
14197c478bd9Sstevel@tonic-gate }
14207c478bd9Sstevel@tonic-gate }
14217c478bd9Sstevel@tonic-gate
14227c478bd9Sstevel@tonic-gate if (options & SO_DONTROUTE) {
14237c478bd9Sstevel@tonic-gate if (setsockopt(send_sock, SOL_SOCKET, SO_DONTROUTE, (char *)&on,
14247c478bd9Sstevel@tonic-gate sizeof (on)) == -1) {
14257c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: setsockopt SO_DONTROUTE %s\n",
14267c478bd9Sstevel@tonic-gate progname, strerror(errno));
14277c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
14287c478bd9Sstevel@tonic-gate }
14297c478bd9Sstevel@tonic-gate }
14307c478bd9Sstevel@tonic-gate
14317c478bd9Sstevel@tonic-gate if (moptions & MULTICAST_NOLOOP) {
14327c478bd9Sstevel@tonic-gate if (family == AF_INET) {
14337c478bd9Sstevel@tonic-gate char_op = 0; /* used to turn off option */
14347c478bd9Sstevel@tonic-gate
14357c478bd9Sstevel@tonic-gate if (setsockopt(send_sock, IPPROTO_IP, IP_MULTICAST_LOOP,
14367c478bd9Sstevel@tonic-gate (char *)&char_op, sizeof (char_op)) == -1) {
14377c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: setsockopt "
14387c478bd9Sstevel@tonic-gate "IP_MULTICAST_NOLOOP %s\n", progname,
14397c478bd9Sstevel@tonic-gate strerror(errno));
14407c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
14417c478bd9Sstevel@tonic-gate }
14427c478bd9Sstevel@tonic-gate } else {
14437c478bd9Sstevel@tonic-gate int_op = 0; /* used to turn off option */
14447c478bd9Sstevel@tonic-gate
14457c478bd9Sstevel@tonic-gate if (setsockopt(send_sock, IPPROTO_IPV6,
14467c478bd9Sstevel@tonic-gate IPV6_MULTICAST_LOOP, (char *)&int_op,
14477c478bd9Sstevel@tonic-gate sizeof (int_op)) == -1) {
14487c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: setsockopt "
14497c478bd9Sstevel@tonic-gate "IPV6_MULTICAST_NOLOOP %s\n", progname,
14507c478bd9Sstevel@tonic-gate strerror(errno));
14517c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
14527c478bd9Sstevel@tonic-gate }
14537c478bd9Sstevel@tonic-gate }
14547c478bd9Sstevel@tonic-gate }
14557c478bd9Sstevel@tonic-gate
14567c478bd9Sstevel@tonic-gate if (moptions & MULTICAST_TTL) {
14577c478bd9Sstevel@tonic-gate char_op = hoplimit;
14587c478bd9Sstevel@tonic-gate
1459bd670b35SErik Nordmark /* Applies to unicast and multicast. */
14607c478bd9Sstevel@tonic-gate if (family == AF_INET) {
14617c478bd9Sstevel@tonic-gate if (setsockopt(send_sock, IPPROTO_IP, IP_MULTICAST_TTL,
14627c478bd9Sstevel@tonic-gate (char *)&char_op, sizeof (char)) == -1) {
14637c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: setsockopt "
14647c478bd9Sstevel@tonic-gate "IP_MULTICAST_TTL %s\n", progname,
14657c478bd9Sstevel@tonic-gate strerror(errno));
14667c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
14677c478bd9Sstevel@tonic-gate }
14687c478bd9Sstevel@tonic-gate if (setsockopt(send_sock, IPPROTO_IP, IP_TTL,
14697c478bd9Sstevel@tonic-gate (char *)&hoplimit, sizeof (hoplimit)) == -1) {
14707c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: setsockopt IP_TTL %s\n",
14717c478bd9Sstevel@tonic-gate progname, strerror(errno));
14727c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
14737c478bd9Sstevel@tonic-gate }
14747c478bd9Sstevel@tonic-gate }
14757c478bd9Sstevel@tonic-gate /*
14767c478bd9Sstevel@tonic-gate * AF_INET6 case is handled in set_ancillary_data() function.
14777c478bd9Sstevel@tonic-gate * This is because when ancillary data is used (for routing
14787c478bd9Sstevel@tonic-gate * header and outgoing interface index), the hoplimit set using
14797c478bd9Sstevel@tonic-gate * setsockopt() is ignored.
14807c478bd9Sstevel@tonic-gate */
14817c478bd9Sstevel@tonic-gate }
14827c478bd9Sstevel@tonic-gate
1483bd670b35SErik Nordmark /*
1484bd670b35SErik Nordmark * did the user specify an interface?
1485bd670b35SErik Nordmark * Applies to unicast, broadcast and multicast.
1486bd670b35SErik Nordmark */
14877c478bd9Sstevel@tonic-gate if (moptions & MULTICAST_IF) {
14887c478bd9Sstevel@tonic-gate struct ifaddrlist *al = NULL; /* interface list */
14897c478bd9Sstevel@tonic-gate struct ifaddrlist *my_if;
14907c478bd9Sstevel@tonic-gate char errbuf[ERRBUFSIZE];
14917c478bd9Sstevel@tonic-gate int num_ifs;
14927c478bd9Sstevel@tonic-gate int num_src_ifs; /* exclude down and loopback */
14937c478bd9Sstevel@tonic-gate int i;
14947c478bd9Sstevel@tonic-gate
14957c478bd9Sstevel@tonic-gate /* pull out the interface list */
1496e11c3f44Smeem num_ifs = ifaddrlist(&al, family, LIFC_UNDER_IPMP, errbuf);
14977c478bd9Sstevel@tonic-gate if (num_ifs == -1) {
14987c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: %s\n", progname, errbuf);
14997c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
15007c478bd9Sstevel@tonic-gate }
15017c478bd9Sstevel@tonic-gate
15027c478bd9Sstevel@tonic-gate /* filter out down and loopback interfaces */
15037c478bd9Sstevel@tonic-gate num_src_ifs = 0;
15047c478bd9Sstevel@tonic-gate for (i = 0; i < num_ifs; i++) {
15057c478bd9Sstevel@tonic-gate if (!(al[i].flags & IFF_LOOPBACK) &&
15067c478bd9Sstevel@tonic-gate (al[i].flags & IFF_UP))
15077c478bd9Sstevel@tonic-gate num_src_ifs++;
15087c478bd9Sstevel@tonic-gate }
15097c478bd9Sstevel@tonic-gate
15107c478bd9Sstevel@tonic-gate if (num_src_ifs == 0) {
15117c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: can't find any %s interface\n",
15127c478bd9Sstevel@tonic-gate progname, (family == AF_INET) ? "IPv4" : "IPv6");
15137c478bd9Sstevel@tonic-gate
15147c478bd9Sstevel@tonic-gate return (_B_FALSE); /* failure */
15157c478bd9Sstevel@tonic-gate }
15167c478bd9Sstevel@tonic-gate
15177c478bd9Sstevel@tonic-gate /* locate the specified interface */
15187c478bd9Sstevel@tonic-gate my_if = find_if(al, num_ifs);
15197c478bd9Sstevel@tonic-gate if (my_if == NULL) {
15207c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: %s is an invalid %s interface\n",
15217c478bd9Sstevel@tonic-gate progname, out_if.str,
15227c478bd9Sstevel@tonic-gate (family == AF_INET) ? "IPv4" : "IPv6");
15237c478bd9Sstevel@tonic-gate
15247c478bd9Sstevel@tonic-gate return (_B_FALSE);
15257c478bd9Sstevel@tonic-gate }
15267c478bd9Sstevel@tonic-gate
15277c478bd9Sstevel@tonic-gate if (family == AF_INET) {
1528bd670b35SErik Nordmark struct in_pktinfo pktinfo;
1529bd670b35SErik Nordmark
15307c478bd9Sstevel@tonic-gate if (setsockopt(send_sock, IPPROTO_IP, IP_MULTICAST_IF,
15317c478bd9Sstevel@tonic-gate (char *)&my_if->addr.addr,
15327c478bd9Sstevel@tonic-gate sizeof (struct in_addr)) == -1) {
15337c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: setsockopt "
15347c478bd9Sstevel@tonic-gate "IP_MULTICAST_IF %s\n", progname,
15357c478bd9Sstevel@tonic-gate strerror(errno));
15367c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
15377c478bd9Sstevel@tonic-gate }
1538bd670b35SErik Nordmark bzero(&pktinfo, sizeof (pktinfo));
1539bd670b35SErik Nordmark pktinfo.ipi_ifindex = my_if->index;
1540bd670b35SErik Nordmark if (setsockopt(send_sock, IPPROTO_IP, IP_PKTINFO,
1541bd670b35SErik Nordmark (char *)&pktinfo, sizeof (pktinfo)) == -1) {
1542bd670b35SErik Nordmark Fprintf(stderr, "%s: setsockopt "
1543bd670b35SErik Nordmark "IP_PKTINFO %s\n", progname,
1544bd670b35SErik Nordmark strerror(errno));
1545bd670b35SErik Nordmark exit(EXIT_FAILURE);
1546bd670b35SErik Nordmark }
15477c478bd9Sstevel@tonic-gate } else {
15487c478bd9Sstevel@tonic-gate /*
15497c478bd9Sstevel@tonic-gate * the outgoing interface is set in set_ancillary_data()
15507c478bd9Sstevel@tonic-gate * function
15517c478bd9Sstevel@tonic-gate */
15527c478bd9Sstevel@tonic-gate *if_index = my_if->index;
15537c478bd9Sstevel@tonic-gate }
15547c478bd9Sstevel@tonic-gate
15557c478bd9Sstevel@tonic-gate free(al);
15567c478bd9Sstevel@tonic-gate }
15577c478bd9Sstevel@tonic-gate
15587c478bd9Sstevel@tonic-gate if (settos && family == AF_INET) {
15597c478bd9Sstevel@tonic-gate int_op = tos;
15607c478bd9Sstevel@tonic-gate if (setsockopt(send_sock, IPPROTO_IP, IP_TOS, (char *)&int_op,
15617c478bd9Sstevel@tonic-gate sizeof (int_op)) == -1) {
15627c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: setsockopt IP_TOS %s\n",
15637c478bd9Sstevel@tonic-gate progname, strerror(errno));
15647c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
15657c478bd9Sstevel@tonic-gate }
15667c478bd9Sstevel@tonic-gate }
15677c478bd9Sstevel@tonic-gate
1568bd670b35SErik Nordmark /* We enable or disable to not depend on the kernel default */
1569bd670b35SErik Nordmark if (family == AF_INET) {
1570bd670b35SErik Nordmark if (setsockopt(send_sock, IPPROTO_IP, IP_DONTFRAG,
1571bd670b35SErik Nordmark (char *)&dontfrag, sizeof (dontfrag)) == -1) {
1572bd670b35SErik Nordmark Fprintf(stderr, "%s: setsockopt IP_DONTFRAG %s\n",
1573bd670b35SErik Nordmark progname, strerror(errno));
1574bd670b35SErik Nordmark exit(EXIT_FAILURE);
1575bd670b35SErik Nordmark }
1576bd670b35SErik Nordmark } else {
1577bd670b35SErik Nordmark if (setsockopt(send_sock, IPPROTO_IPV6, IPV6_DONTFRAG,
1578bd670b35SErik Nordmark (char *)&dontfrag, sizeof (dontfrag)) == -1) {
1579bd670b35SErik Nordmark Fprintf(stderr, "%s: setsockopt IPV6_DONTFRAG %s\n",
1580bd670b35SErik Nordmark progname, strerror(errno));
1581bd670b35SErik Nordmark exit(EXIT_FAILURE);
1582bd670b35SErik Nordmark }
1583bd670b35SErik Nordmark }
1584bd670b35SErik Nordmark
15857c478bd9Sstevel@tonic-gate /* receiving IPv6 extension headers in verbose mode */
15867c478bd9Sstevel@tonic-gate if (verbose && family == AF_INET6) {
15877c478bd9Sstevel@tonic-gate if (setsockopt(recv_sock, IPPROTO_IPV6, IPV6_RECVHOPOPTS,
15887c478bd9Sstevel@tonic-gate (char *)&on, sizeof (on)) == -1) {
15897c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: setsockopt IPV6_RECVHOPOPTS %s\n",
15907c478bd9Sstevel@tonic-gate progname, strerror(errno));
15917c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
15927c478bd9Sstevel@tonic-gate }
15937c478bd9Sstevel@tonic-gate
15947c478bd9Sstevel@tonic-gate if (setsockopt(recv_sock, IPPROTO_IPV6, IPV6_RECVDSTOPTS,
15957c478bd9Sstevel@tonic-gate (char *)&on, sizeof (on)) == -1) {
15967c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: setsockopt IPV6_RECVDSTOPTS %s\n",
15977c478bd9Sstevel@tonic-gate progname, strerror(errno));
15987c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
15997c478bd9Sstevel@tonic-gate }
16007c478bd9Sstevel@tonic-gate
16017c478bd9Sstevel@tonic-gate if (setsockopt(recv_sock, IPPROTO_IPV6, IPV6_RECVRTHDR,
16027c478bd9Sstevel@tonic-gate (char *)&on, sizeof (on)) == -1) {
16037c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: setsockopt IPV6_RECVRTHDR %s\n",
16047c478bd9Sstevel@tonic-gate progname, strerror(errno));
16057c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
16067c478bd9Sstevel@tonic-gate }
16077c478bd9Sstevel@tonic-gate }
16087c478bd9Sstevel@tonic-gate
16097c478bd9Sstevel@tonic-gate *send_sockp = send_sock;
16107c478bd9Sstevel@tonic-gate *recv_sockp = recv_sock;
16117c478bd9Sstevel@tonic-gate
16127c478bd9Sstevel@tonic-gate /* successful */
16137c478bd9Sstevel@tonic-gate return (_B_TRUE);
16147c478bd9Sstevel@tonic-gate }
16157c478bd9Sstevel@tonic-gate
16167c478bd9Sstevel@tonic-gate /*
16177c478bd9Sstevel@tonic-gate * Pull out the record containing all the info about the interface specified by
16187c478bd9Sstevel@tonic-gate * `out_if'. Skips interfaces which are down or loopback.
16197c478bd9Sstevel@tonic-gate */
16207c478bd9Sstevel@tonic-gate static struct ifaddrlist *
find_if(struct ifaddrlist * al,int num_ifs)16217c478bd9Sstevel@tonic-gate find_if(struct ifaddrlist *al, int num_ifs)
16227c478bd9Sstevel@tonic-gate {
16237c478bd9Sstevel@tonic-gate static struct ifaddrlist tmp_if;
16247c478bd9Sstevel@tonic-gate boolean_t found;
16257c478bd9Sstevel@tonic-gate int i;
16267c478bd9Sstevel@tonic-gate
16277c478bd9Sstevel@tonic-gate i = 0;
16287c478bd9Sstevel@tonic-gate found = _B_FALSE;
16297c478bd9Sstevel@tonic-gate
16307c478bd9Sstevel@tonic-gate while (i < num_ifs && !found) {
16317c478bd9Sstevel@tonic-gate tmp_if = al[i];
16327c478bd9Sstevel@tonic-gate
16337c478bd9Sstevel@tonic-gate /* skip down or loopback interfaces */
16347c478bd9Sstevel@tonic-gate if ((tmp_if.flags & IFF_LOOPBACK) || !(tmp_if.flags & IFF_UP)) {
16357c478bd9Sstevel@tonic-gate i++;
16367c478bd9Sstevel@tonic-gate continue;
16377c478bd9Sstevel@tonic-gate }
16387c478bd9Sstevel@tonic-gate
16397c478bd9Sstevel@tonic-gate /* the type of interface id is variable */
16407c478bd9Sstevel@tonic-gate switch (out_if.id_type) {
16417c478bd9Sstevel@tonic-gate case IF_INDEX:
16427c478bd9Sstevel@tonic-gate if (out_if.id.index == tmp_if.index)
16437c478bd9Sstevel@tonic-gate found = _B_TRUE;
16447c478bd9Sstevel@tonic-gate break;
16457c478bd9Sstevel@tonic-gate
16467c478bd9Sstevel@tonic-gate case IF_NAME:
16477c478bd9Sstevel@tonic-gate if (strcmp(out_if.id.name, tmp_if.device) == 0)
16487c478bd9Sstevel@tonic-gate found = _B_TRUE;
16497c478bd9Sstevel@tonic-gate break;
16507c478bd9Sstevel@tonic-gate
16517c478bd9Sstevel@tonic-gate case IF_ADDR:
16527c478bd9Sstevel@tonic-gate if (out_if.id.addr.addr.s_addr ==
16537c478bd9Sstevel@tonic-gate tmp_if.addr.addr.s_addr) {
16547c478bd9Sstevel@tonic-gate found = _B_TRUE;
16557c478bd9Sstevel@tonic-gate }
16567c478bd9Sstevel@tonic-gate break;
16577c478bd9Sstevel@tonic-gate
16587c478bd9Sstevel@tonic-gate case IF_ADDR6:
16597c478bd9Sstevel@tonic-gate if (IN6_ARE_ADDR_EQUAL(&out_if.id.addr.addr6,
16607c478bd9Sstevel@tonic-gate &tmp_if.addr.addr6)) {
16617c478bd9Sstevel@tonic-gate found = _B_TRUE;
16627c478bd9Sstevel@tonic-gate }
16637c478bd9Sstevel@tonic-gate break;
16647c478bd9Sstevel@tonic-gate
16657c478bd9Sstevel@tonic-gate default:
16667c478bd9Sstevel@tonic-gate break;
16677c478bd9Sstevel@tonic-gate }
16687c478bd9Sstevel@tonic-gate
16697c478bd9Sstevel@tonic-gate i++;
16707c478bd9Sstevel@tonic-gate }
16717c478bd9Sstevel@tonic-gate
16727c478bd9Sstevel@tonic-gate if (found)
16737c478bd9Sstevel@tonic-gate return (&tmp_if);
16747c478bd9Sstevel@tonic-gate else
16757c478bd9Sstevel@tonic-gate return (NULL);
16767c478bd9Sstevel@tonic-gate }
16777c478bd9Sstevel@tonic-gate
16787c478bd9Sstevel@tonic-gate /*
16797c478bd9Sstevel@tonic-gate * Invoked by SIGALRM, sigalrm_handler() is, responsible for calling
16807c478bd9Sstevel@tonic-gate * send_scheduled_probe() to send next probe.
16817c478bd9Sstevel@tonic-gate */
16827c478bd9Sstevel@tonic-gate void
sigalrm_handler(void)16837c478bd9Sstevel@tonic-gate sigalrm_handler(void)
16847c478bd9Sstevel@tonic-gate {
16857c478bd9Sstevel@tonic-gate /*
16867c478bd9Sstevel@tonic-gate * Guard againist denial-of-service attacks. Make sure ping doesn't
16877c478bd9Sstevel@tonic-gate * send probes for every SIGALRM it receives. Evil hacker can generate
16887c478bd9Sstevel@tonic-gate * SIGALRMs as fast as it can, but ping will ignore those which are
16897c478bd9Sstevel@tonic-gate * received too soon (earlier than 0.5 sec) after it sent the last
16907c478bd9Sstevel@tonic-gate * probe. We use gethrtime() instead of gettimeofday() because
16917c478bd9Sstevel@tonic-gate * the latter is not linear and is prone to resetting or drifting
16927c478bd9Sstevel@tonic-gate */
16937c478bd9Sstevel@tonic-gate if ((gethrtime() - t_last_probe_sent) < 500000000) {
16947c478bd9Sstevel@tonic-gate return;
16957c478bd9Sstevel@tonic-gate }
16967c478bd9Sstevel@tonic-gate send_scheduled_probe();
16977c478bd9Sstevel@tonic-gate schedule_sigalrm();
16987c478bd9Sstevel@tonic-gate }
16997c478bd9Sstevel@tonic-gate
17007c478bd9Sstevel@tonic-gate /*
17017c478bd9Sstevel@tonic-gate * Schedule next SIGALRM.
17027c478bd9Sstevel@tonic-gate */
17037c478bd9Sstevel@tonic-gate void
schedule_sigalrm(void)17047c478bd9Sstevel@tonic-gate schedule_sigalrm(void)
17057c478bd9Sstevel@tonic-gate {
17067c478bd9Sstevel@tonic-gate int waittime;
17077c478bd9Sstevel@tonic-gate
17087c478bd9Sstevel@tonic-gate if (npackets == 0 ||
17097c478bd9Sstevel@tonic-gate current_targetaddr->num_sent < current_targetaddr->num_probes) {
17107c478bd9Sstevel@tonic-gate (void) alarm(interval);
17117c478bd9Sstevel@tonic-gate } else {
17127c478bd9Sstevel@tonic-gate if (current_targetaddr->got_reply) {
17137c478bd9Sstevel@tonic-gate waittime = 2 * tmax / MICROSEC;
17147c478bd9Sstevel@tonic-gate if (waittime == 0)
17157c478bd9Sstevel@tonic-gate waittime = 1;
17167c478bd9Sstevel@tonic-gate } else {
17177c478bd9Sstevel@tonic-gate waittime = MAX_WAIT;
17187c478bd9Sstevel@tonic-gate }
17197c478bd9Sstevel@tonic-gate (void) alarm(waittime);
17207c478bd9Sstevel@tonic-gate }
17217c478bd9Sstevel@tonic-gate }
17227c478bd9Sstevel@tonic-gate
17237c478bd9Sstevel@tonic-gate /*
17247c478bd9Sstevel@tonic-gate * Called by sigalrm_handler(), check_reply() or check_reply6(),
17257c478bd9Sstevel@tonic-gate * send_scheduled_probe() looks at the current_targetaddr and determines what
17267c478bd9Sstevel@tonic-gate * should be sent next and calls pinger().
17277c478bd9Sstevel@tonic-gate */
17287c478bd9Sstevel@tonic-gate void
send_scheduled_probe()17297c478bd9Sstevel@tonic-gate send_scheduled_probe()
17307c478bd9Sstevel@tonic-gate {
17317c478bd9Sstevel@tonic-gate static struct msghdr msg6;
17327c478bd9Sstevel@tonic-gate static boolean_t first_probe = _B_TRUE;
17337c478bd9Sstevel@tonic-gate char tmp_buf[INET6_ADDRSTRLEN];
17347c478bd9Sstevel@tonic-gate
17357c478bd9Sstevel@tonic-gate /*
17367c478bd9Sstevel@tonic-gate * We are about to move to next targetaddr if it's either we sent
17377c478bd9Sstevel@tonic-gate * all the probes, or somebody set the probing_done flag to
17387c478bd9Sstevel@tonic-gate * _B_TRUE prompting us to move on.
17397c478bd9Sstevel@tonic-gate */
17407c478bd9Sstevel@tonic-gate if (current_targetaddr->num_sent == current_targetaddr->num_probes ||
17417c478bd9Sstevel@tonic-gate current_targetaddr->probing_done) {
17427c478bd9Sstevel@tonic-gate /*
17437c478bd9Sstevel@tonic-gate * is this a dead target?
17447c478bd9Sstevel@tonic-gate */
17457c478bd9Sstevel@tonic-gate if (!stats && !current_targetaddr->got_reply) {
17467c478bd9Sstevel@tonic-gate if (!probe_all) {
17477c478bd9Sstevel@tonic-gate Printf("no answer from %s\n", targethost);
17487c478bd9Sstevel@tonic-gate } else {
17497c478bd9Sstevel@tonic-gate Printf("no answer from %s(%s)\n", targethost,
17507c478bd9Sstevel@tonic-gate inet_ntop(current_targetaddr->family,
17517c478bd9Sstevel@tonic-gate ¤t_targetaddr->dst_addr,
17527c478bd9Sstevel@tonic-gate tmp_buf, sizeof (tmp_buf)));
17537c478bd9Sstevel@tonic-gate }
17547c478bd9Sstevel@tonic-gate }
17557c478bd9Sstevel@tonic-gate /*
17567c478bd9Sstevel@tonic-gate * Before we move onto next item, let's do some clean up.
17577c478bd9Sstevel@tonic-gate */
17587c478bd9Sstevel@tonic-gate current_targetaddr->got_reply = _B_FALSE;
17597c478bd9Sstevel@tonic-gate current_targetaddr->probing_done = _B_FALSE;
17607c478bd9Sstevel@tonic-gate /*
17617c478bd9Sstevel@tonic-gate * If this is probe-all without stats mode, then we need to
17627c478bd9Sstevel@tonic-gate * preserve this count. This is needed when we try to map an
17637c478bd9Sstevel@tonic-gate * icmp_seq to IP address. Otherwise, clear it.
17647c478bd9Sstevel@tonic-gate */
17657c478bd9Sstevel@tonic-gate if (stats || !probe_all)
17667c478bd9Sstevel@tonic-gate current_targetaddr->num_sent = 0;
17677c478bd9Sstevel@tonic-gate nreceived_last_target = 0;
17687c478bd9Sstevel@tonic-gate
17697c478bd9Sstevel@tonic-gate current_targetaddr = current_targetaddr->next;
17707c478bd9Sstevel@tonic-gate
17717c478bd9Sstevel@tonic-gate /*
17727c478bd9Sstevel@tonic-gate * Did we reach the end of road?
17737c478bd9Sstevel@tonic-gate */
17747c478bd9Sstevel@tonic-gate if (current_targetaddr == NULL) {
17757c478bd9Sstevel@tonic-gate (void) alarm(0); /* cancel alarm */
17767c478bd9Sstevel@tonic-gate if (stats)
17777c478bd9Sstevel@tonic-gate finish();
17787c478bd9Sstevel@tonic-gate if (is_alive)
17797c478bd9Sstevel@tonic-gate exit(EXIT_SUCCESS);
17807c478bd9Sstevel@tonic-gate else
17817c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
17827c478bd9Sstevel@tonic-gate } else {
17837c478bd9Sstevel@tonic-gate /*
17847c478bd9Sstevel@tonic-gate * We use starting_seq_num for authenticating replies.
17857c478bd9Sstevel@tonic-gate * Each time we move to a new targetaddr, which has
17867c478bd9Sstevel@tonic-gate * a different target IP address, we update this field.
17877c478bd9Sstevel@tonic-gate */
1788e11c3f44Smeem current_targetaddr->starting_seq_num = use_udp ?
1789e11c3f44Smeem dest_port : (ntransmitted % (MAX_ICMP_SEQ + 1));
17907c478bd9Sstevel@tonic-gate }
17917c478bd9Sstevel@tonic-gate }
17927c478bd9Sstevel@tonic-gate
17937c478bd9Sstevel@tonic-gate if (current_targetaddr->family == AF_INET6) {
17947c478bd9Sstevel@tonic-gate if (send_reply) {
17957c478bd9Sstevel@tonic-gate /* sending back to ourself */
17967c478bd9Sstevel@tonic-gate to6.sin6_addr = current_targetaddr->src_addr.addr6;
17977c478bd9Sstevel@tonic-gate } else {
17987c478bd9Sstevel@tonic-gate to6.sin6_addr = current_targetaddr->dst_addr.addr6;
17997c478bd9Sstevel@tonic-gate }
18007c478bd9Sstevel@tonic-gate /*
18017c478bd9Sstevel@tonic-gate * Setting the ancillary data once is enough, if we are
18027c478bd9Sstevel@tonic-gate * not using source routing through target (-l/-S). In
18037c478bd9Sstevel@tonic-gate * case -l/-S used, the middle gateway will be the
18047c478bd9Sstevel@tonic-gate * IP address of the source, which can be different
18057c478bd9Sstevel@tonic-gate * for each target IP.
18067c478bd9Sstevel@tonic-gate */
18077c478bd9Sstevel@tonic-gate if (first_probe ||
18087c478bd9Sstevel@tonic-gate (send_reply && current_targetaddr->num_sent == 0)) {
18097c478bd9Sstevel@tonic-gate if (send_reply) {
18107c478bd9Sstevel@tonic-gate /* target is the middle gateway now */
18117c478bd9Sstevel@tonic-gate gw_IP_list6[num_gw].addr6 =
18127c478bd9Sstevel@tonic-gate current_targetaddr->dst_addr.addr6;
18137c478bd9Sstevel@tonic-gate }
18147c478bd9Sstevel@tonic-gate set_ancillary_data(&msg6, hoplimit, gw_IP_list6,
18157c478bd9Sstevel@tonic-gate eff_num_gw, if_index);
18167c478bd9Sstevel@tonic-gate first_probe = _B_FALSE;
18177c478bd9Sstevel@tonic-gate }
18187c478bd9Sstevel@tonic-gate pinger(send_sock6, (struct sockaddr *)&to6, &msg6, AF_INET6);
18197c478bd9Sstevel@tonic-gate } else {
18207c478bd9Sstevel@tonic-gate to.sin_addr = current_targetaddr->dst_addr.addr;
18217c478bd9Sstevel@tonic-gate /*
18227c478bd9Sstevel@tonic-gate * Set IPv4 options when sending the first probe to a target
18237c478bd9Sstevel@tonic-gate * IP address. Some options change when the target address
18247c478bd9Sstevel@tonic-gate * changes.
18257c478bd9Sstevel@tonic-gate */
18267c478bd9Sstevel@tonic-gate if (current_targetaddr->num_sent == 0) {
18277c478bd9Sstevel@tonic-gate if (eff_num_gw > 0) {
18287c478bd9Sstevel@tonic-gate gw_IP_list[num_gw].addr =
18297c478bd9Sstevel@tonic-gate current_targetaddr->dst_addr.addr;
18307c478bd9Sstevel@tonic-gate /*
18317c478bd9Sstevel@tonic-gate * If send_reply, the target becomes the
18327c478bd9Sstevel@tonic-gate * middle gateway, sender becomes the last
18337c478bd9Sstevel@tonic-gate * gateway.
18347c478bd9Sstevel@tonic-gate */
18357c478bd9Sstevel@tonic-gate if (send_reply) {
18367c478bd9Sstevel@tonic-gate gw_IP_list[eff_num_gw].addr =
18377c478bd9Sstevel@tonic-gate current_targetaddr->src_addr.addr;
18387c478bd9Sstevel@tonic-gate }
18397c478bd9Sstevel@tonic-gate }
18407c478bd9Sstevel@tonic-gate /*
18417c478bd9Sstevel@tonic-gate * In IPv4, if source routing is used, the target
18427c478bd9Sstevel@tonic-gate * address shows up as the last gateway, hence +1.
18437c478bd9Sstevel@tonic-gate */
18447c478bd9Sstevel@tonic-gate set_IPv4_options(send_sock, gw_IP_list,
18457c478bd9Sstevel@tonic-gate (eff_num_gw > 0) ? eff_num_gw + 1 : 0,
18467c478bd9Sstevel@tonic-gate ¤t_targetaddr->src_addr.addr, &to.sin_addr);
18477c478bd9Sstevel@tonic-gate }
18487c478bd9Sstevel@tonic-gate pinger(send_sock, (struct sockaddr *)&to, NULL, AF_INET);
18497c478bd9Sstevel@tonic-gate }
18507c478bd9Sstevel@tonic-gate
18517c478bd9Sstevel@tonic-gate current_targetaddr->num_sent++;
18527c478bd9Sstevel@tonic-gate }
18537c478bd9Sstevel@tonic-gate
18547c478bd9Sstevel@tonic-gate /*
18557c478bd9Sstevel@tonic-gate * recv_icmp_packet()'s job is to listen to icmp packets and filter out
18567c478bd9Sstevel@tonic-gate * those ping is interested in.
18577c478bd9Sstevel@tonic-gate */
18587c478bd9Sstevel@tonic-gate 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)18597c478bd9Sstevel@tonic-gate recv_icmp_packet(struct addrinfo *ai_dst, int recv_sock6, int recv_sock,
18607c478bd9Sstevel@tonic-gate ushort_t udp_src_port6, ushort_t udp_src_port)
18617c478bd9Sstevel@tonic-gate {
18627c478bd9Sstevel@tonic-gate struct msghdr in_msg;
18637c478bd9Sstevel@tonic-gate struct iovec iov;
18647c478bd9Sstevel@tonic-gate struct sockaddr_in6 from6;
18657c478bd9Sstevel@tonic-gate fd_set fds;
18667c478bd9Sstevel@tonic-gate int result;
18677c478bd9Sstevel@tonic-gate int cc;
18687c478bd9Sstevel@tonic-gate boolean_t always_true = _B_TRUE; /* lint doesn't like while(_B_TRUE) */
18697c478bd9Sstevel@tonic-gate
18707c478bd9Sstevel@tonic-gate while (always_true) {
18717c478bd9Sstevel@tonic-gate (void) FD_ZERO(&fds);
18727c478bd9Sstevel@tonic-gate if (recv_sock6 != -1)
18737c478bd9Sstevel@tonic-gate FD_SET(recv_sock6, &fds);
18747c478bd9Sstevel@tonic-gate if (recv_sock != -1)
18757c478bd9Sstevel@tonic-gate FD_SET(recv_sock, &fds);
18767c478bd9Sstevel@tonic-gate
18777c478bd9Sstevel@tonic-gate result = select(MAX(recv_sock6, recv_sock) + 1, &fds,
18787c478bd9Sstevel@tonic-gate (fd_set *)NULL, (fd_set *)NULL, (struct timeval *)NULL);
18797c478bd9Sstevel@tonic-gate if (result == -1) {
18807c478bd9Sstevel@tonic-gate if (errno == EINTR) {
18817c478bd9Sstevel@tonic-gate continue;
18827c478bd9Sstevel@tonic-gate } else {
18837c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: select %s\n", progname,
18847c478bd9Sstevel@tonic-gate strerror(errno));
18857c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
18867c478bd9Sstevel@tonic-gate }
18877c478bd9Sstevel@tonic-gate } else if (result > 0) {
18887c478bd9Sstevel@tonic-gate in_msg.msg_name = &from6;
18897c478bd9Sstevel@tonic-gate in_msg.msg_namelen = sizeof (from6);
18907c478bd9Sstevel@tonic-gate iov.iov_base = in_pkt;
18917c478bd9Sstevel@tonic-gate iov.iov_len = sizeof (in_pkt);
18927c478bd9Sstevel@tonic-gate in_msg.msg_iov = &iov;
18937c478bd9Sstevel@tonic-gate in_msg.msg_iovlen = 1;
18947c478bd9Sstevel@tonic-gate in_msg.msg_control = ancillary_data;
18957c478bd9Sstevel@tonic-gate in_msg.msg_controllen = sizeof (ancillary_data);
18967c478bd9Sstevel@tonic-gate
18977c478bd9Sstevel@tonic-gate /* Do we have an ICMP6 packet waiting? */
18987c478bd9Sstevel@tonic-gate if ((recv_sock6 != -1) &&
18997c478bd9Sstevel@tonic-gate (FD_ISSET(recv_sock6, &fds))) {
19007c478bd9Sstevel@tonic-gate cc = recvmsg(recv_sock6, &in_msg, 0);
19017c478bd9Sstevel@tonic-gate if (cc < 0) {
19027c478bd9Sstevel@tonic-gate if (errno != EINTR) {
19037c478bd9Sstevel@tonic-gate Fprintf(stderr,
19047c478bd9Sstevel@tonic-gate "%s: recvmsg %s\n",
19057c478bd9Sstevel@tonic-gate progname, strerror(errno));
19067c478bd9Sstevel@tonic-gate }
19077c478bd9Sstevel@tonic-gate continue;
19087c478bd9Sstevel@tonic-gate } else if (cc > 0) {
19097c478bd9Sstevel@tonic-gate check_reply6(ai_dst, &in_msg, cc,
19107c478bd9Sstevel@tonic-gate udp_src_port6);
19117c478bd9Sstevel@tonic-gate }
19127c478bd9Sstevel@tonic-gate }
19137c478bd9Sstevel@tonic-gate /* Do we have an ICMP packet waiting? */
19147c478bd9Sstevel@tonic-gate if ((recv_sock != -1) && (FD_ISSET(recv_sock, &fds))) {
19157c478bd9Sstevel@tonic-gate cc = recvmsg(recv_sock, &in_msg, 0);
19167c478bd9Sstevel@tonic-gate if (cc < 0) {
19177c478bd9Sstevel@tonic-gate if (errno != EINTR) {
19187c478bd9Sstevel@tonic-gate Fprintf(stderr,
19197c478bd9Sstevel@tonic-gate "%s: recvmsg %s\n",
19207c478bd9Sstevel@tonic-gate progname, strerror(errno));
19217c478bd9Sstevel@tonic-gate }
19227c478bd9Sstevel@tonic-gate continue;
19237c478bd9Sstevel@tonic-gate } if (cc > 0) {
19247c478bd9Sstevel@tonic-gate check_reply(ai_dst, &in_msg, cc,
19257c478bd9Sstevel@tonic-gate udp_src_port);
19267c478bd9Sstevel@tonic-gate }
19277c478bd9Sstevel@tonic-gate }
19287c478bd9Sstevel@tonic-gate }
19297c478bd9Sstevel@tonic-gate /*
19307c478bd9Sstevel@tonic-gate * If we were probing last IP address of the target host and
19317c478bd9Sstevel@tonic-gate * received a reply for each probe sent to this address,
19327c478bd9Sstevel@tonic-gate * then we are done!
19337c478bd9Sstevel@tonic-gate */
19347c478bd9Sstevel@tonic-gate if ((npackets > 0) && (current_targetaddr->next == NULL) &&
19357c478bd9Sstevel@tonic-gate (nreceived_last_target == npackets)) {
19367c478bd9Sstevel@tonic-gate (void) alarm(0); /* cancel alarm */
19377c478bd9Sstevel@tonic-gate finish();
19387c478bd9Sstevel@tonic-gate }
19397c478bd9Sstevel@tonic-gate } /* infinite loop */
19407c478bd9Sstevel@tonic-gate }
19417c478bd9Sstevel@tonic-gate
19427c478bd9Sstevel@tonic-gate /*
19437c478bd9Sstevel@tonic-gate * Given a host (with possibly multiple IP addresses) and an IP address, this
19447c478bd9Sstevel@tonic-gate * function determines if this IP address is one of the host's addresses to
19457c478bd9Sstevel@tonic-gate * which we're sending probes. Used to determine if we are interested in a
19467c478bd9Sstevel@tonic-gate * packet.
19477c478bd9Sstevel@tonic-gate */
19487c478bd9Sstevel@tonic-gate boolean_t
is_a_target(struct addrinfo * ai,union any_in_addr * addr)19497c478bd9Sstevel@tonic-gate is_a_target(struct addrinfo *ai, union any_in_addr *addr)
19507c478bd9Sstevel@tonic-gate {
19517c478bd9Sstevel@tonic-gate int num_addrs;
19527c478bd9Sstevel@tonic-gate int i;
19537c478bd9Sstevel@tonic-gate struct addrinfo *aip;
19547c478bd9Sstevel@tonic-gate
19557c478bd9Sstevel@tonic-gate aip = ai;
19567c478bd9Sstevel@tonic-gate if (probe_all)
19577c478bd9Sstevel@tonic-gate num_addrs = num_v4 + num_v6;
19587c478bd9Sstevel@tonic-gate else
19597c478bd9Sstevel@tonic-gate num_addrs = 1;
19607c478bd9Sstevel@tonic-gate for (i = 0; i < num_addrs && aip != NULL; i++) {
19617c478bd9Sstevel@tonic-gate if (aip->ai_family == AF_INET6) {
19627c478bd9Sstevel@tonic-gate /* LINTED E_BAD_PTR_CAST_ALIGN */
19637c478bd9Sstevel@tonic-gate if (IN6_ARE_ADDR_EQUAL(&((struct sockaddr_in6 *)
19647c478bd9Sstevel@tonic-gate aip->ai_addr)->sin6_addr, &addr->addr6))
19657c478bd9Sstevel@tonic-gate return (_B_TRUE);
19667c478bd9Sstevel@tonic-gate } else {
19677c478bd9Sstevel@tonic-gate /* LINTED E_BAD_PTR_CAST_ALIGN */
19687c478bd9Sstevel@tonic-gate if (((struct sockaddr_in *)
19697c478bd9Sstevel@tonic-gate aip->ai_addr)->sin_addr.s_addr == addr->addr.s_addr)
19707c478bd9Sstevel@tonic-gate return (_B_TRUE);
19717c478bd9Sstevel@tonic-gate }
19727c478bd9Sstevel@tonic-gate }
19737c478bd9Sstevel@tonic-gate
19747c478bd9Sstevel@tonic-gate return (_B_FALSE);
19757c478bd9Sstevel@tonic-gate }
19767c478bd9Sstevel@tonic-gate
19777c478bd9Sstevel@tonic-gate /*
19787c478bd9Sstevel@tonic-gate * Compose and transmit an ICMP ECHO REQUEST packet. The IP packet
19797c478bd9Sstevel@tonic-gate * will be added on by the kernel. The ID field is our UNIX process ID,
19807c478bd9Sstevel@tonic-gate * and the sequence number is an ascending integer. The first 8 bytes
19817c478bd9Sstevel@tonic-gate * of the data portion are used to hold a UNIX "timeval" struct in network
19827c478bd9Sstevel@tonic-gate * byte-order, to compute the round-trip time.
19837c478bd9Sstevel@tonic-gate */
19847c478bd9Sstevel@tonic-gate static void
pinger(int send_sock,struct sockaddr * whereto,struct msghdr * msg6,int family)19857c478bd9Sstevel@tonic-gate pinger(int send_sock, struct sockaddr *whereto, struct msghdr *msg6,
19867c478bd9Sstevel@tonic-gate int family)
19877c478bd9Sstevel@tonic-gate {
19887c478bd9Sstevel@tonic-gate static uint64_t out_pkt_buf[(IP_MAXPACKET + 1) / 8];
19897c478bd9Sstevel@tonic-gate uchar_t *out_pkt = (uchar_t *)&out_pkt_buf;
19907c478bd9Sstevel@tonic-gate /* LINTED E_BAD_PTR_CAST_ALIGN */
19917c478bd9Sstevel@tonic-gate struct icmp *icp = (struct icmp *)out_pkt;
19927c478bd9Sstevel@tonic-gate /* LINTED E_BAD_PTR_CAST_ALIGN */
19937c478bd9Sstevel@tonic-gate struct sockaddr_in6 *to6 = (struct sockaddr_in6 *)whereto;
19947c478bd9Sstevel@tonic-gate /* LINTED E_BAD_PTR_CAST_ALIGN */
19957c478bd9Sstevel@tonic-gate struct sockaddr_in *to = (struct sockaddr_in *)whereto;
19967c478bd9Sstevel@tonic-gate struct timeval *tp;
19977c478bd9Sstevel@tonic-gate struct timeval t_snd;
19987c478bd9Sstevel@tonic-gate uchar_t *datap;
19997c478bd9Sstevel@tonic-gate struct iovec iov;
20007c478bd9Sstevel@tonic-gate int start = 0;
20017c478bd9Sstevel@tonic-gate int cc;
20027c478bd9Sstevel@tonic-gate int i;
20037c478bd9Sstevel@tonic-gate
20047c478bd9Sstevel@tonic-gate /* using UDP? */
20057c478bd9Sstevel@tonic-gate if (use_udp) {
20067c478bd9Sstevel@tonic-gate cc = datalen;
20077c478bd9Sstevel@tonic-gate
20087c478bd9Sstevel@tonic-gate /* LINTED E_BAD_PTR_CAST_ALIGN */
20097c478bd9Sstevel@tonic-gate tp = (struct timeval *)out_pkt;
20107c478bd9Sstevel@tonic-gate datap = &out_pkt[sizeof (struct timeval)];
20117c478bd9Sstevel@tonic-gate
20127c478bd9Sstevel@tonic-gate /*
20137c478bd9Sstevel@tonic-gate * This sets the port whether we are handling a v4 or v6
20147c478bd9Sstevel@tonic-gate * sockaddr structure.
20157c478bd9Sstevel@tonic-gate */
20167c478bd9Sstevel@tonic-gate to->sin_port = htons(dest_port);
20177c478bd9Sstevel@tonic-gate
20187c478bd9Sstevel@tonic-gate dest_port = (dest_port + 1) % (MAX_PORT + 1);
20197c478bd9Sstevel@tonic-gate ntransmitted++;
20207c478bd9Sstevel@tonic-gate } else { /* using ICMP */
20217c478bd9Sstevel@tonic-gate cc = datalen + ICMP_MINLEN;
20227c478bd9Sstevel@tonic-gate
20237c478bd9Sstevel@tonic-gate if (family == AF_INET6) {
20247c478bd9Sstevel@tonic-gate icp->icmp_type = send_reply ?
20257c478bd9Sstevel@tonic-gate ICMP6_ECHO_REPLY : ICMP6_ECHO_REQUEST;
20267c478bd9Sstevel@tonic-gate } else if (use_icmp_ts) { /* family is AF_INET */
20277c478bd9Sstevel@tonic-gate icp->icmp_type = send_reply ?
20287c478bd9Sstevel@tonic-gate ICMP_TSTAMPREPLY : ICMP_TSTAMP;
20297c478bd9Sstevel@tonic-gate } else {
20307c478bd9Sstevel@tonic-gate icp->icmp_type = send_reply ?
20317c478bd9Sstevel@tonic-gate ICMP_ECHOREPLY : ICMP_ECHO;
20327c478bd9Sstevel@tonic-gate }
20337c478bd9Sstevel@tonic-gate
20347c478bd9Sstevel@tonic-gate icp->icmp_code = 0;
20357c478bd9Sstevel@tonic-gate icp->icmp_cksum = 0;
20367c478bd9Sstevel@tonic-gate icp->icmp_seq = htons(ntransmitted++ % (MAX_ICMP_SEQ + 1));
20377c478bd9Sstevel@tonic-gate if (icp->icmp_seq == 0)
20387c478bd9Sstevel@tonic-gate num_wraps++;
20397c478bd9Sstevel@tonic-gate icp->icmp_id = htons(ident); /* ID */
20407c478bd9Sstevel@tonic-gate
20417c478bd9Sstevel@tonic-gate /* LINTED E_BAD_PTR_CAST_ALIGN */
20427c478bd9Sstevel@tonic-gate tp = (struct timeval *)&out_pkt[ICMP_MINLEN];
20437c478bd9Sstevel@tonic-gate datap = &out_pkt[ICMP_MINLEN + sizeof (struct timeval)];
20447c478bd9Sstevel@tonic-gate }
20457c478bd9Sstevel@tonic-gate
20467c478bd9Sstevel@tonic-gate start = sizeof (struct timeval); /* skip for time */
20477c478bd9Sstevel@tonic-gate
20487c478bd9Sstevel@tonic-gate (void) gettimeofday(&t_snd, (struct timezone *)NULL);
20497c478bd9Sstevel@tonic-gate
20507c478bd9Sstevel@tonic-gate /* if packet is big enough to store timeval OR ... */
20517c478bd9Sstevel@tonic-gate if ((datalen >= sizeof (struct timeval)) ||
20527c478bd9Sstevel@tonic-gate (family == AF_INET && use_icmp_ts))
20537c478bd9Sstevel@tonic-gate *tp = t_snd;
20547c478bd9Sstevel@tonic-gate
20557c478bd9Sstevel@tonic-gate if (family == AF_INET && use_icmp_ts) {
20567c478bd9Sstevel@tonic-gate start = sizeof (struct id_ts); /* skip for ICMP timestamps */
20577c478bd9Sstevel@tonic-gate /* Number of milliseconds since midnight */
20587c478bd9Sstevel@tonic-gate icp->icmp_otime = htonl((tp->tv_sec % (24*60*60)) * 1000 +
20597c478bd9Sstevel@tonic-gate tp->tv_usec / 1000);
20607c478bd9Sstevel@tonic-gate }
20617c478bd9Sstevel@tonic-gate
20627c478bd9Sstevel@tonic-gate for (i = start; i < datalen; i++)
20637c478bd9Sstevel@tonic-gate *datap++ = i;
20647c478bd9Sstevel@tonic-gate
20657c478bd9Sstevel@tonic-gate if (family == AF_INET) {
20667c478bd9Sstevel@tonic-gate if (!use_udp)
20677c478bd9Sstevel@tonic-gate icp->icmp_cksum = in_cksum((ushort_t *)icp, cc);
20687c478bd9Sstevel@tonic-gate
20697c478bd9Sstevel@tonic-gate i = sendto(send_sock, (char *)out_pkt, cc, 0, whereto,
20707c478bd9Sstevel@tonic-gate sizeof (struct sockaddr_in));
20717c478bd9Sstevel@tonic-gate } else {
20727c478bd9Sstevel@tonic-gate /*
20737c478bd9Sstevel@tonic-gate * Fill in the rest of the msghdr structure. msg_control is set
20747c478bd9Sstevel@tonic-gate * in set_ancillary_data().
20757c478bd9Sstevel@tonic-gate */
20767c478bd9Sstevel@tonic-gate msg6->msg_name = to6;
20777c478bd9Sstevel@tonic-gate msg6->msg_namelen = sizeof (struct sockaddr_in6);
20787c478bd9Sstevel@tonic-gate
20797c478bd9Sstevel@tonic-gate iov.iov_base = out_pkt;
20807c478bd9Sstevel@tonic-gate iov.iov_len = cc;
20817c478bd9Sstevel@tonic-gate
20827c478bd9Sstevel@tonic-gate msg6->msg_iov = &iov;
20837c478bd9Sstevel@tonic-gate msg6->msg_iovlen = 1;
20847c478bd9Sstevel@tonic-gate
20857c478bd9Sstevel@tonic-gate i = sendmsg(send_sock, msg6, 0);
20867c478bd9Sstevel@tonic-gate }
20877c478bd9Sstevel@tonic-gate
20887c478bd9Sstevel@tonic-gate /* This is a more precise time (right after we send the packet) */
20897c478bd9Sstevel@tonic-gate t_last_probe_sent = gethrtime();
20907c478bd9Sstevel@tonic-gate
20917c478bd9Sstevel@tonic-gate if (i < 0 || i != cc) {
20927c478bd9Sstevel@tonic-gate if (i < 0) {
20937c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: sendto %s\n", progname,
20947c478bd9Sstevel@tonic-gate strerror(errno));
20957c478bd9Sstevel@tonic-gate if (!stats)
20967c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
20977c478bd9Sstevel@tonic-gate }
20987c478bd9Sstevel@tonic-gate Printf("ping: wrote %s %d chars, ret=%d\n",
20997c478bd9Sstevel@tonic-gate targethost, cc, i);
21007c478bd9Sstevel@tonic-gate (void) fflush(stdout);
21017c478bd9Sstevel@tonic-gate }
21027c478bd9Sstevel@tonic-gate }
21037c478bd9Sstevel@tonic-gate
21047c478bd9Sstevel@tonic-gate /*
21057c478bd9Sstevel@tonic-gate * Return a hostname for the given IP address.
21067c478bd9Sstevel@tonic-gate */
21077c478bd9Sstevel@tonic-gate char *
pr_name(char * addr,int family)21087c478bd9Sstevel@tonic-gate pr_name(char *addr, int family)
21097c478bd9Sstevel@tonic-gate {
21107c478bd9Sstevel@tonic-gate struct sockaddr_in sin;
21117c478bd9Sstevel@tonic-gate struct sockaddr_in6 sin6;
21127c478bd9Sstevel@tonic-gate struct sockaddr *sa;
21137c478bd9Sstevel@tonic-gate static struct in6_addr prev_addr = IN6ADDR_ANY_INIT;
21147c478bd9Sstevel@tonic-gate char *cp;
21157c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN];
21167c478bd9Sstevel@tonic-gate static char buf[NI_MAXHOST + INET6_ADDRSTRLEN + 3];
21177c478bd9Sstevel@tonic-gate uint_t slen, alen, hlen;
21187c478bd9Sstevel@tonic-gate
21197c478bd9Sstevel@tonic-gate switch (family) {
21207c478bd9Sstevel@tonic-gate case AF_INET:
21217c478bd9Sstevel@tonic-gate (void) memset(&sin, 0, sizeof (sin));
21227c478bd9Sstevel@tonic-gate slen = sizeof (struct sockaddr_in);
21237c478bd9Sstevel@tonic-gate alen = sizeof (struct in_addr);
21247c478bd9Sstevel@tonic-gate /* LINTED E_BAD_PTR_CAST_ALIGN */
21257c478bd9Sstevel@tonic-gate sin.sin_addr = *(struct in_addr *)addr;
21267c478bd9Sstevel@tonic-gate sin.sin_port = 0;
21277c478bd9Sstevel@tonic-gate sa = (struct sockaddr *)&sin;
21287c478bd9Sstevel@tonic-gate break;
21297c478bd9Sstevel@tonic-gate case AF_INET6:
21307c478bd9Sstevel@tonic-gate (void) memset(&sin6, 0, sizeof (sin6));
21317c478bd9Sstevel@tonic-gate slen = sizeof (struct sockaddr_in6);
21327c478bd9Sstevel@tonic-gate alen = sizeof (struct in6_addr);
21337c478bd9Sstevel@tonic-gate /* LINTED E_BAD_PTR_CAST_ALIGN */
21347c478bd9Sstevel@tonic-gate sin6.sin6_addr = *(struct in6_addr *)addr;
21357c478bd9Sstevel@tonic-gate sin6.sin6_port = 0;
21367c478bd9Sstevel@tonic-gate sa = (struct sockaddr *)&sin6;
21377c478bd9Sstevel@tonic-gate break;
21387c478bd9Sstevel@tonic-gate default:
21397c478bd9Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), "<invalid address family>");
21407c478bd9Sstevel@tonic-gate return (buf);
21417c478bd9Sstevel@tonic-gate }
21427c478bd9Sstevel@tonic-gate sa->sa_family = family;
21437c478bd9Sstevel@tonic-gate
21447c478bd9Sstevel@tonic-gate /* compare with the buffered (previous) lookup */
21457c478bd9Sstevel@tonic-gate if (memcmp(addr, &prev_addr, alen) != 0) {
21467c478bd9Sstevel@tonic-gate int flags = (nflag) ? NI_NUMERICHOST : NI_NAMEREQD;
21477c478bd9Sstevel@tonic-gate if (getnameinfo(sa, slen, buf, sizeof (buf),
21487c478bd9Sstevel@tonic-gate NULL, 0, flags) != 0) {
21497c478bd9Sstevel@tonic-gate /* getnameinfo() failed; return just the address */
21507c478bd9Sstevel@tonic-gate if (inet_ntop(family, (const void*)addr,
21517c478bd9Sstevel@tonic-gate buf, sizeof (buf)) == NULL)
21527c478bd9Sstevel@tonic-gate buf[0] = 0;
21537c478bd9Sstevel@tonic-gate } else if (!nflag) {
21547c478bd9Sstevel@tonic-gate /* append numeric address to hostname string */
21557c478bd9Sstevel@tonic-gate hlen = strlen(buf);
21567c478bd9Sstevel@tonic-gate cp = (char *)(buf + hlen);
21577c478bd9Sstevel@tonic-gate (void) snprintf(cp, sizeof (buf) - hlen, " (%s)",
21587c478bd9Sstevel@tonic-gate inet_ntop(family, (const void *)addr, abuf,
21597c478bd9Sstevel@tonic-gate sizeof (abuf)));
21607c478bd9Sstevel@tonic-gate }
21617c478bd9Sstevel@tonic-gate
21627c478bd9Sstevel@tonic-gate /* LINTED E_BAD_PTR_CAST_ALIGN */
21637c478bd9Sstevel@tonic-gate prev_addr = *(struct in6_addr *)addr;
21647c478bd9Sstevel@tonic-gate }
21657c478bd9Sstevel@tonic-gate return (buf);
21667c478bd9Sstevel@tonic-gate }
21677c478bd9Sstevel@tonic-gate
21687c478bd9Sstevel@tonic-gate /*
21697c478bd9Sstevel@tonic-gate * Return the protocol string, given its protocol number.
21707c478bd9Sstevel@tonic-gate */
21717c478bd9Sstevel@tonic-gate char *
pr_protocol(int prot)21727c478bd9Sstevel@tonic-gate pr_protocol(int prot)
21737c478bd9Sstevel@tonic-gate {
21747c478bd9Sstevel@tonic-gate static char buf[20];
21757c478bd9Sstevel@tonic-gate
21767c478bd9Sstevel@tonic-gate switch (prot) {
21777c478bd9Sstevel@tonic-gate case IPPROTO_ICMPV6:
21787c478bd9Sstevel@tonic-gate (void) strlcpy(buf, "icmp6", sizeof (buf));
21797c478bd9Sstevel@tonic-gate break;
21807c478bd9Sstevel@tonic-gate
21817c478bd9Sstevel@tonic-gate case IPPROTO_ICMP:
21827c478bd9Sstevel@tonic-gate (void) strlcpy(buf, "icmp", sizeof (buf));
21837c478bd9Sstevel@tonic-gate break;
21847c478bd9Sstevel@tonic-gate
21857c478bd9Sstevel@tonic-gate case IPPROTO_TCP:
21867c478bd9Sstevel@tonic-gate (void) strlcpy(buf, "tcp", sizeof (buf));
21877c478bd9Sstevel@tonic-gate break;
21887c478bd9Sstevel@tonic-gate
21897c478bd9Sstevel@tonic-gate case IPPROTO_UDP:
21907c478bd9Sstevel@tonic-gate (void) strlcpy(buf, "udp", sizeof (buf));
21917c478bd9Sstevel@tonic-gate break;
21927c478bd9Sstevel@tonic-gate
21937c478bd9Sstevel@tonic-gate default:
21947c478bd9Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), "prot %d", prot);
21957c478bd9Sstevel@tonic-gate break;
21967c478bd9Sstevel@tonic-gate }
21977c478bd9Sstevel@tonic-gate
21987c478bd9Sstevel@tonic-gate return (buf);
21997c478bd9Sstevel@tonic-gate }
22007c478bd9Sstevel@tonic-gate
22017c478bd9Sstevel@tonic-gate /*
22027c478bd9Sstevel@tonic-gate * Checks if value is between seq_begin and seq_begin+seq_len. Note that
22037c478bd9Sstevel@tonic-gate * sequence numbers wrap around after MAX_ICMP_SEQ (== MAX_PORT).
22047c478bd9Sstevel@tonic-gate */
22057c478bd9Sstevel@tonic-gate boolean_t
seq_match(ushort_t seq_begin,int seq_len,ushort_t value)22067c478bd9Sstevel@tonic-gate seq_match(ushort_t seq_begin, int seq_len, ushort_t value)
22077c478bd9Sstevel@tonic-gate {
22087c478bd9Sstevel@tonic-gate /*
22097c478bd9Sstevel@tonic-gate * If seq_len is too big, like some value greater than MAX_ICMP_SEQ/2,
22107c478bd9Sstevel@tonic-gate * truncate it down to MAX_ICMP_SEQ/2. We are not going to accept any
22117c478bd9Sstevel@tonic-gate * reply which come 83hr later!
22127c478bd9Sstevel@tonic-gate */
22137c478bd9Sstevel@tonic-gate if (seq_len > MAX_ICMP_SEQ / 2) {
22147c478bd9Sstevel@tonic-gate seq_begin = (seq_begin + seq_len - MAX_ICMP_SEQ / 2) %
22157c478bd9Sstevel@tonic-gate (MAX_ICMP_SEQ + 1);
22167c478bd9Sstevel@tonic-gate seq_len = MAX_ICMP_SEQ / 2;
22177c478bd9Sstevel@tonic-gate }
22187c478bd9Sstevel@tonic-gate
22197c478bd9Sstevel@tonic-gate if (PINGSEQ_LEQ(seq_begin, value) &&
22207c478bd9Sstevel@tonic-gate PINGSEQ_LEQ(value, (seq_begin + seq_len - 1) % (MAX_ICMP_SEQ + 1)))
22217c478bd9Sstevel@tonic-gate return (_B_TRUE);
22227c478bd9Sstevel@tonic-gate else
22237c478bd9Sstevel@tonic-gate return (_B_FALSE);
22247c478bd9Sstevel@tonic-gate }
22257c478bd9Sstevel@tonic-gate
22267c478bd9Sstevel@tonic-gate /*
22277c478bd9Sstevel@tonic-gate * For a given icmp_seq, find which destination address we must have sent this
22287c478bd9Sstevel@tonic-gate * to.
22297c478bd9Sstevel@tonic-gate */
22307c478bd9Sstevel@tonic-gate void
find_dstaddr(ushort_t icmpseq,union any_in_addr * ipaddr)22317c478bd9Sstevel@tonic-gate find_dstaddr(ushort_t icmpseq, union any_in_addr *ipaddr)
22327c478bd9Sstevel@tonic-gate {
22337c478bd9Sstevel@tonic-gate struct targetaddr *target = targetaddr_list;
22347c478bd9Sstevel@tonic-gate int real_seq;
22357c478bd9Sstevel@tonic-gate int targetaddr_index;
22367c478bd9Sstevel@tonic-gate int real_npackets;
22377c478bd9Sstevel@tonic-gate int i;
22387c478bd9Sstevel@tonic-gate
22397c478bd9Sstevel@tonic-gate ipaddr->addr6 = in6addr_any;
22407c478bd9Sstevel@tonic-gate
22417c478bd9Sstevel@tonic-gate /*
22427c478bd9Sstevel@tonic-gate * If this is probe_all and not stats, then the number of probes sent to
22437c478bd9Sstevel@tonic-gate * each IP address may be different (remember, we stop sending to one IP
22447c478bd9Sstevel@tonic-gate * address as soon as it replies). They are stored in target->num_sent
22457c478bd9Sstevel@tonic-gate * field. Since we don't wrap around the list (!stats), they are also
22467c478bd9Sstevel@tonic-gate * preserved.
22477c478bd9Sstevel@tonic-gate */
22487c478bd9Sstevel@tonic-gate if (probe_all && !stats) {
22497c478bd9Sstevel@tonic-gate do {
22507c478bd9Sstevel@tonic-gate if (seq_match(target->starting_seq_num,
22517c478bd9Sstevel@tonic-gate target->num_sent, icmpseq)) {
22527c478bd9Sstevel@tonic-gate ipaddr->addr6 = target->dst_addr.addr6;
22537c478bd9Sstevel@tonic-gate /*
22547c478bd9Sstevel@tonic-gate * We are not immediately return()ing here.
22557c478bd9Sstevel@tonic-gate * Because of wrapping, we might find another
22567c478bd9Sstevel@tonic-gate * match later, which is more likely to be the
22577c478bd9Sstevel@tonic-gate * real one.
22587c478bd9Sstevel@tonic-gate */
22597c478bd9Sstevel@tonic-gate }
22607c478bd9Sstevel@tonic-gate target = target->next;
22617c478bd9Sstevel@tonic-gate } while (target != NULL);
22627c478bd9Sstevel@tonic-gate } else {
22637c478bd9Sstevel@tonic-gate /*
22647c478bd9Sstevel@tonic-gate * Find the absolute (non-wrapped) seq number within the last
22657c478bd9Sstevel@tonic-gate * 64K
22667c478bd9Sstevel@tonic-gate */
22677c478bd9Sstevel@tonic-gate if (icmpseq < (ntransmitted % (MAX_ICMP_SEQ + 1))) {
22687c478bd9Sstevel@tonic-gate real_seq = num_wraps * (MAX_ICMP_SEQ + 1) + icmpseq;
22697c478bd9Sstevel@tonic-gate } else {
22707c478bd9Sstevel@tonic-gate real_seq = (num_wraps - 1) * (MAX_ICMP_SEQ + 1) +
22717c478bd9Sstevel@tonic-gate icmpseq;
22727c478bd9Sstevel@tonic-gate }
22737c478bd9Sstevel@tonic-gate
22747c478bd9Sstevel@tonic-gate /* Make sure it's non-negative */
22757c478bd9Sstevel@tonic-gate if (real_seq < 0)
22767c478bd9Sstevel@tonic-gate return;
22777c478bd9Sstevel@tonic-gate real_npackets = (npackets == 0) ? 1 : npackets;
22787c478bd9Sstevel@tonic-gate
22797c478bd9Sstevel@tonic-gate /*
22807c478bd9Sstevel@tonic-gate * We sent npackets many packets to each of those
22817c478bd9Sstevel@tonic-gate * num_targetaddrs many IP addresses.
22827c478bd9Sstevel@tonic-gate */
22837c478bd9Sstevel@tonic-gate targetaddr_index =
22847c478bd9Sstevel@tonic-gate (real_seq % (num_targetaddrs * real_npackets)) /
22857c478bd9Sstevel@tonic-gate real_npackets;
22867c478bd9Sstevel@tonic-gate for (i = 0; i < targetaddr_index; i++)
22877c478bd9Sstevel@tonic-gate target = target->next;
22887c478bd9Sstevel@tonic-gate ipaddr->addr6 = target->dst_addr.addr6;
22897c478bd9Sstevel@tonic-gate }
22907c478bd9Sstevel@tonic-gate }
22917c478bd9Sstevel@tonic-gate
22927c478bd9Sstevel@tonic-gate /*
22937c478bd9Sstevel@tonic-gate * Checksum routine for Internet Protocol family headers (C Version)
22947c478bd9Sstevel@tonic-gate */
22957c478bd9Sstevel@tonic-gate static ushort_t
in_cksum(ushort_t * addr,int len)22967c478bd9Sstevel@tonic-gate in_cksum(ushort_t *addr, int len)
22977c478bd9Sstevel@tonic-gate {
22987c478bd9Sstevel@tonic-gate int nleft = len;
22997c478bd9Sstevel@tonic-gate ushort_t *w = addr;
23007c478bd9Sstevel@tonic-gate ushort_t answer;
23017c478bd9Sstevel@tonic-gate ushort_t odd_byte = 0;
23027c478bd9Sstevel@tonic-gate int sum = 0;
23037c478bd9Sstevel@tonic-gate
23047c478bd9Sstevel@tonic-gate /*
23057c478bd9Sstevel@tonic-gate * Our algorithm is simple, using a 32 bit accumulator (sum),
23067c478bd9Sstevel@tonic-gate * we add sequential 16 bit words to it, and at the end, fold
23077c478bd9Sstevel@tonic-gate * back all the carry bits from the top 16 bits into the lower
23087c478bd9Sstevel@tonic-gate * 16 bits.
23097c478bd9Sstevel@tonic-gate */
23107c478bd9Sstevel@tonic-gate while (nleft > 1) {
23117c478bd9Sstevel@tonic-gate sum += *w++;
23127c478bd9Sstevel@tonic-gate nleft -= 2;
23137c478bd9Sstevel@tonic-gate }
23147c478bd9Sstevel@tonic-gate
23157c478bd9Sstevel@tonic-gate /* mop up an odd byte, if necessary */
23167c478bd9Sstevel@tonic-gate if (nleft == 1) {
23177c478bd9Sstevel@tonic-gate *(uchar_t *)(&odd_byte) = *(uchar_t *)w;
23187c478bd9Sstevel@tonic-gate sum += odd_byte;
23197c478bd9Sstevel@tonic-gate }
23207c478bd9Sstevel@tonic-gate
23217c478bd9Sstevel@tonic-gate /*
23227c478bd9Sstevel@tonic-gate * add back carry outs from top 16 bits to low 16 bits
23237c478bd9Sstevel@tonic-gate */
23247c478bd9Sstevel@tonic-gate sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
23257c478bd9Sstevel@tonic-gate sum += (sum >> 16); /* add carry */
23267c478bd9Sstevel@tonic-gate answer = ~sum; /* truncate to 16 bits */
23277c478bd9Sstevel@tonic-gate return (answer);
23287c478bd9Sstevel@tonic-gate }
23297c478bd9Sstevel@tonic-gate
23307c478bd9Sstevel@tonic-gate /*
23317c478bd9Sstevel@tonic-gate * Subtract 2 timeval structs: out = out - in.
23327c478bd9Sstevel@tonic-gate * Out is assumed to be >= in.
23337c478bd9Sstevel@tonic-gate */
23347c478bd9Sstevel@tonic-gate void
tvsub(struct timeval * out,struct timeval * in)23357c478bd9Sstevel@tonic-gate tvsub(struct timeval *out, struct timeval *in)
23367c478bd9Sstevel@tonic-gate {
23377c478bd9Sstevel@tonic-gate if ((out->tv_usec -= in->tv_usec) < 0) {
23387c478bd9Sstevel@tonic-gate out->tv_sec--;
23397c478bd9Sstevel@tonic-gate out->tv_usec += 1000000;
23407c478bd9Sstevel@tonic-gate }
23417c478bd9Sstevel@tonic-gate out->tv_sec -= in->tv_sec;
23427c478bd9Sstevel@tonic-gate }
23437c478bd9Sstevel@tonic-gate
23447c478bd9Sstevel@tonic-gate /*
23457c478bd9Sstevel@tonic-gate * Print out statistics, and give up.
23467c478bd9Sstevel@tonic-gate * Heavily buffered STDIO is used here, so that all the statistics
23477c478bd9Sstevel@tonic-gate * will be written with 1 sys-write call. This is nice when more
23487c478bd9Sstevel@tonic-gate * than one copy of the program is running on a terminal; it prevents
23497c478bd9Sstevel@tonic-gate * the statistics output from becoming intermingled.
23507c478bd9Sstevel@tonic-gate */
23517c478bd9Sstevel@tonic-gate static void
finish()23527c478bd9Sstevel@tonic-gate finish()
23537c478bd9Sstevel@tonic-gate {
23547c478bd9Sstevel@tonic-gate Printf("\n----%s PING Statistics----\n", targethost);
23557c478bd9Sstevel@tonic-gate Printf("%d packets transmitted, ", ntransmitted);
23567c478bd9Sstevel@tonic-gate Printf("%d packets received, ", nreceived);
23577c478bd9Sstevel@tonic-gate if (ntransmitted) {
23587c478bd9Sstevel@tonic-gate if (nreceived <= ntransmitted) {
23597c478bd9Sstevel@tonic-gate Printf("%d%% packet loss",
23607c478bd9Sstevel@tonic-gate (int)(((ntransmitted-nreceived)*100) /
23617c478bd9Sstevel@tonic-gate ntransmitted));
23627c478bd9Sstevel@tonic-gate } else {
23637c478bd9Sstevel@tonic-gate Printf("%.2f times amplification",
23647c478bd9Sstevel@tonic-gate (double)nreceived / (double)ntransmitted);
23657c478bd9Sstevel@tonic-gate }
23667c478bd9Sstevel@tonic-gate }
23677c478bd9Sstevel@tonic-gate (void) putchar('\n');
23687c478bd9Sstevel@tonic-gate
23697c478bd9Sstevel@tonic-gate /* if packet is big enough to store timeval AND ... */
23707c478bd9Sstevel@tonic-gate if ((datalen >= sizeof (struct timeval)) && (nreceived > 0)) {
23717c478bd9Sstevel@tonic-gate double mean = (double)tsum / nreceived;
23727c478bd9Sstevel@tonic-gate double smean = (double)tsum2 / nreceived;
23737c478bd9Sstevel@tonic-gate double sd =
23747c478bd9Sstevel@tonic-gate sqrt(((smean - mean*mean) * nreceived) / (nreceived-1));
23757c478bd9Sstevel@tonic-gate
23767c478bd9Sstevel@tonic-gate Printf("round-trip (ms) min/avg/max/stddev = "
23773c58dfd6Sjbeck TIMEFORMAT "/" TIMEFORMAT "/"
23783c58dfd6Sjbeck TIMEFORMAT "/" TIMEFORMAT "\n",
23793c58dfd6Sjbeck (double)tmin / 1000, mean / 1000,
23803c58dfd6Sjbeck (double)tmax / 1000, sd / 1000);
23817c478bd9Sstevel@tonic-gate }
23827c478bd9Sstevel@tonic-gate (void) fflush(stdout);
23837c478bd9Sstevel@tonic-gate
23847c478bd9Sstevel@tonic-gate exit(is_alive ? EXIT_SUCCESS : EXIT_FAILURE);
23857c478bd9Sstevel@tonic-gate }
23867c478bd9Sstevel@tonic-gate
23877c478bd9Sstevel@tonic-gate /*
23887c478bd9Sstevel@tonic-gate * print the usage line
23897c478bd9Sstevel@tonic-gate */
23907c478bd9Sstevel@tonic-gate static void
usage(char * cmdname)23917c478bd9Sstevel@tonic-gate usage(char *cmdname)
23927c478bd9Sstevel@tonic-gate {
23937c478bd9Sstevel@tonic-gate Fprintf(stderr, "usage: %s host [timeout]\n", cmdname);
23947c478bd9Sstevel@tonic-gate Fprintf(stderr,
23957c478bd9Sstevel@tonic-gate /* CSTYLED */
2396*a252e007SChris Josephes "usage: %s -s [-l | -U] [-abdDLnRrv] [-A addr_family] [-c traffic_class]\n\t"
23974c10bc16Spwernau "[-g gateway [-g gateway ...]] [-N nexthop] [-F flow_label] [-I interval]\n\t"
23987c478bd9Sstevel@tonic-gate "[-i interface] [-P tos] [-p port] [-t ttl] host [data_size] [npackets]\n",
23997c478bd9Sstevel@tonic-gate cmdname);
24007c478bd9Sstevel@tonic-gate }
24017c478bd9Sstevel@tonic-gate
24027c478bd9Sstevel@tonic-gate /*
24037c478bd9Sstevel@tonic-gate * Parse integer argument; exit with an error if it's not a number.
24047c478bd9Sstevel@tonic-gate * Now it also accepts hex. values.
24057c478bd9Sstevel@tonic-gate */
24067c478bd9Sstevel@tonic-gate static int
int_arg(char * s,char * what)24077c478bd9Sstevel@tonic-gate int_arg(char *s, char *what)
24087c478bd9Sstevel@tonic-gate {
24097c478bd9Sstevel@tonic-gate char *cp;
24107c478bd9Sstevel@tonic-gate char *ep;
24117c478bd9Sstevel@tonic-gate int num;
24127c478bd9Sstevel@tonic-gate
24137c478bd9Sstevel@tonic-gate errno = 0;
24147c478bd9Sstevel@tonic-gate if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) {
24157c478bd9Sstevel@tonic-gate cp = s + 2;
24167c478bd9Sstevel@tonic-gate num = (int)strtol(cp, &ep, 16);
24177c478bd9Sstevel@tonic-gate } else {
24187c478bd9Sstevel@tonic-gate num = (int)strtol(s, &ep, 10);
24197c478bd9Sstevel@tonic-gate }
24207c478bd9Sstevel@tonic-gate
24217c478bd9Sstevel@tonic-gate if (errno || *ep != '\0' || num < 0) {
24227c478bd9Sstevel@tonic-gate (void) Fprintf(stderr, "%s: bad %s: %s\n",
24237c478bd9Sstevel@tonic-gate progname, what, s);
24247c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
24257c478bd9Sstevel@tonic-gate }
24267c478bd9Sstevel@tonic-gate
24277c478bd9Sstevel@tonic-gate return (num);
24287c478bd9Sstevel@tonic-gate }
2429