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
40b08923d6SRobert Mustacchi /*
41cbf54fedSJohn Levon * Copyright (c) 2018, Joyent, Inc.
42*9c4b0eaaSRobert Mustacchi * Copyright 2023 Oxide computer Company
43b08923d6SRobert Mustacchi */
44b08923d6SRobert Mustacchi
45b08923d6SRobert Mustacchi #include <assert.h>
467c478bd9Sstevel@tonic-gate #include <stdio.h>
477c478bd9Sstevel@tonic-gate #include <strings.h>
487c478bd9Sstevel@tonic-gate #include <errno.h>
497c478bd9Sstevel@tonic-gate #include <fcntl.h>
507c478bd9Sstevel@tonic-gate #include <unistd.h>
517c478bd9Sstevel@tonic-gate #include <signal.h>
527c478bd9Sstevel@tonic-gate #include <limits.h>
537c478bd9Sstevel@tonic-gate #include <math.h>
54b08923d6SRobert Mustacchi #include <locale.h>
55b08923d6SRobert Mustacchi #include <thread.h>
56b08923d6SRobert Mustacchi #include <synch.h>
577c478bd9Sstevel@tonic-gate
587c478bd9Sstevel@tonic-gate #include <sys/time.h>
597c478bd9Sstevel@tonic-gate #include <sys/param.h>
607c478bd9Sstevel@tonic-gate #include <sys/socket.h>
617c478bd9Sstevel@tonic-gate #include <sys/sockio.h>
627c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
637c478bd9Sstevel@tonic-gate #include <sys/file.h>
647c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
65b08923d6SRobert Mustacchi #include <sys/debug.h>
667c478bd9Sstevel@tonic-gate
677c478bd9Sstevel@tonic-gate #include <arpa/inet.h>
687c478bd9Sstevel@tonic-gate #include <net/if.h>
697c478bd9Sstevel@tonic-gate #include <netinet/in_systm.h>
707c478bd9Sstevel@tonic-gate #include <netinet/in.h>
717c478bd9Sstevel@tonic-gate #include <netinet/ip.h>
727c478bd9Sstevel@tonic-gate #include <netinet/ip_icmp.h>
737c478bd9Sstevel@tonic-gate #include <netinet/ip_var.h>
747c478bd9Sstevel@tonic-gate #include <netinet/ip6.h>
757c478bd9Sstevel@tonic-gate #include <netinet/icmp6.h>
767c478bd9Sstevel@tonic-gate #include <netinet/udp.h>
777c478bd9Sstevel@tonic-gate #include <netdb.h>
787c478bd9Sstevel@tonic-gate #include <stdlib.h>
797c478bd9Sstevel@tonic-gate #include <priv_utils.h>
807c478bd9Sstevel@tonic-gate
810406ceaaSmeem #include <libinetutil.h>
827c478bd9Sstevel@tonic-gate #include "ping.h"
837c478bd9Sstevel@tonic-gate
847c478bd9Sstevel@tonic-gate /*
857c478bd9Sstevel@tonic-gate * This macro is used to compare 16bit, wrapping sequence numbers. Inspired by
867c478bd9Sstevel@tonic-gate * TCP's SEQ_LEQ macro.
877c478bd9Sstevel@tonic-gate */
887c478bd9Sstevel@tonic-gate #define PINGSEQ_LEQ(a, b) ((int16_t)((a)-(b)) <= 0)
897c478bd9Sstevel@tonic-gate
907c478bd9Sstevel@tonic-gate #define MAX_WAIT 10 /* max sec. to wait for response */
917c478bd9Sstevel@tonic-gate #define MAX_TRAFFIC_CLASS 255 /* max traffic class for IPv6 */
927c478bd9Sstevel@tonic-gate #define MAX_FLOW_LABEL 0xFFFFF /* max flow label for IPv6 */
937c478bd9Sstevel@tonic-gate #define MAX_TOS 255 /* max type-of-service for IPv4 */
947c478bd9Sstevel@tonic-gate
957c478bd9Sstevel@tonic-gate #define TIMEOUT 20 /* default timeout value */
967c478bd9Sstevel@tonic-gate #define DEFAULT_DATALEN 56
977c478bd9Sstevel@tonic-gate
987c478bd9Sstevel@tonic-gate #define MULTICAST_NOLOOP 1 /* multicast options */
997c478bd9Sstevel@tonic-gate #define MULTICAST_TTL 2
1007c478bd9Sstevel@tonic-gate #define MULTICAST_IF 4
1017c478bd9Sstevel@tonic-gate
1027c478bd9Sstevel@tonic-gate #define IF_INDEX 0 /* types of -i argument */
1037c478bd9Sstevel@tonic-gate #define IF_NAME 1
1047c478bd9Sstevel@tonic-gate #define IF_ADDR 2
1057c478bd9Sstevel@tonic-gate #define IF_ADDR6 3
1067c478bd9Sstevel@tonic-gate
1077c478bd9Sstevel@tonic-gate #ifdef BSD
1087c478bd9Sstevel@tonic-gate #define setbuf(s, b) setlinebuf((s))
1097c478bd9Sstevel@tonic-gate #endif /* BSD */
1107c478bd9Sstevel@tonic-gate
1117c478bd9Sstevel@tonic-gate
1127c478bd9Sstevel@tonic-gate /* interface identification */
1137c478bd9Sstevel@tonic-gate union if_id {
1147c478bd9Sstevel@tonic-gate int index; /* interface index (e.g., 1, 2) */
1157c478bd9Sstevel@tonic-gate char *name; /* interface name (e.g., le0, hme0) */
1167c478bd9Sstevel@tonic-gate union any_in_addr addr; /* interface address (e.g., 10.123.4.5) */
1177c478bd9Sstevel@tonic-gate };
1187c478bd9Sstevel@tonic-gate
1197c478bd9Sstevel@tonic-gate /* stores the interface supplied by the user */
1207c478bd9Sstevel@tonic-gate struct if_entry {
1217c478bd9Sstevel@tonic-gate char *str; /* unresolved, string input */
1227c478bd9Sstevel@tonic-gate int id_type; /* type of ID (index, name, addr, addr6) */
1237c478bd9Sstevel@tonic-gate union if_id id; /* ID */
1247c478bd9Sstevel@tonic-gate };
1257c478bd9Sstevel@tonic-gate
1267c478bd9Sstevel@tonic-gate char *progname;
1277c478bd9Sstevel@tonic-gate char *targethost;
1284c10bc16Spwernau char *nexthop;
1297c478bd9Sstevel@tonic-gate
1307c478bd9Sstevel@tonic-gate static int send_sock; /* send sockets */
1317c478bd9Sstevel@tonic-gate static int send_sock6;
1327c478bd9Sstevel@tonic-gate static struct sockaddr_in to; /* where to send */
1337c478bd9Sstevel@tonic-gate static struct sockaddr_in6 to6;
1347c478bd9Sstevel@tonic-gate static union any_in_addr gw_IP_list[MAX_GWS]; /* gateways */
1357c478bd9Sstevel@tonic-gate static union any_in_addr gw_IP_list6[MAX_GWS6];
1367c478bd9Sstevel@tonic-gate static int if_index = 0; /* outgoing interface index */
1377c478bd9Sstevel@tonic-gate boolean_t is_alive = _B_FALSE; /* is target host alive */
1387c478bd9Sstevel@tonic-gate struct targetaddr *current_targetaddr; /* current target IP address to probe */
1397c478bd9Sstevel@tonic-gate static struct targetaddr *targetaddr_list; /* list of IP addresses to probe */
1407c478bd9Sstevel@tonic-gate static int num_targetaddrs; /* no of target addresses to probe */
1417c478bd9Sstevel@tonic-gate static int num_v4 = 0; /* count of IPv4 addresses */
1427c478bd9Sstevel@tonic-gate static int num_v6 = 0; /* count of IPv6 addresses */
1437c478bd9Sstevel@tonic-gate boolean_t verbose = _B_FALSE; /* verbose output */
1447c478bd9Sstevel@tonic-gate boolean_t stats = _B_FALSE; /* display statistics */
1457c478bd9Sstevel@tonic-gate static boolean_t settos = _B_FALSE; /* set type-of-service value */
1467c478bd9Sstevel@tonic-gate boolean_t rr_option = _B_FALSE; /* true if using record route */
1477c478bd9Sstevel@tonic-gate boolean_t send_reply = _B_FALSE; /* Send an ICMP_{ECHO|TSTAMP}REPLY */
1487c478bd9Sstevel@tonic-gate /* that goes to target and comes back */
1497c478bd9Sstevel@tonic-gate /* to the the sender via src routing. */
1507c478bd9Sstevel@tonic-gate boolean_t strict = _B_FALSE; /* true if using strict source route */
1517c478bd9Sstevel@tonic-gate boolean_t ts_option = _B_FALSE; /* true if using timestamp option */
1527c478bd9Sstevel@tonic-gate boolean_t use_icmp_ts = _B_FALSE; /* Use ICMP timestamp request */
1537c478bd9Sstevel@tonic-gate boolean_t use_udp = _B_FALSE; /* Use UDP instead of ICMP */
1547c478bd9Sstevel@tonic-gate boolean_t probe_all = _B_FALSE; /* probe all the IP addresses */
1557c478bd9Sstevel@tonic-gate boolean_t nflag = _B_FALSE; /* do not reverse lookup addresses */
156a356273cSpwernau boolean_t bypass = _B_FALSE; /* bypass IPsec policy */
1577c478bd9Sstevel@tonic-gate static int family_input = AF_UNSPEC; /* address family supplied by user */
1587c478bd9Sstevel@tonic-gate int datalen = DEFAULT_DATALEN; /* How much data */
1597c478bd9Sstevel@tonic-gate int ts_flag; /* timestamp flag value */
1607c478bd9Sstevel@tonic-gate static int num_gw; /* number of gateways */
1617c478bd9Sstevel@tonic-gate static int eff_num_gw; /* effective number of gateways */
1627c478bd9Sstevel@tonic-gate /* if send_reply, it's 2*num_gw+1 */
1637c478bd9Sstevel@tonic-gate static int num_wraps = -1; /* no of times 64K icmp_seq wrapped */
1647c478bd9Sstevel@tonic-gate static ushort_t dest_port = 32768 + 666; /* starting port for the UDP probes */
1657c478bd9Sstevel@tonic-gate static char *gw_list[MAXMAX_GWS]; /* list of gateways as user enters */
1667c478bd9Sstevel@tonic-gate static int options; /* socket options */
1677c478bd9Sstevel@tonic-gate static int moptions; /* multicast options */
1687c478bd9Sstevel@tonic-gate int npackets; /* number of packets to send */
1697c478bd9Sstevel@tonic-gate static ushort_t tos; /* type-of-service value */
1707c478bd9Sstevel@tonic-gate static int hoplimit = -1; /* time-to-live value */
171bd670b35SErik Nordmark static int dontfrag; /* IP*_DONTFRAG */
1727c478bd9Sstevel@tonic-gate static int timeout = TIMEOUT; /* timeout value (sec) for probes */
1737c478bd9Sstevel@tonic-gate static struct if_entry out_if; /* interface argument */
1747c478bd9Sstevel@tonic-gate int ident; /* ID for this ping run */
1757c478bd9Sstevel@tonic-gate static hrtime_t t_last_probe_sent; /* the time we sent the last probe */
176b08923d6SRobert Mustacchi static timer_t timer; /* timer for waiting */
177b08923d6SRobert Mustacchi static volatile boolean_t timer_done = _B_FALSE; /* timer finished? */
178b08923d6SRobert Mustacchi static struct itimerspec interval = { { 0, 0 }, { 1, 0 } }; /* Interval for */
179b08923d6SRobert Mustacchi /* -I. The default interval is 1s. */
180b08923d6SRobert Mustacchi static hrtime_t mintime = NSEC2MSEC(500); /* minimum time between pings */
181b08923d6SRobert Mustacchi
182b08923d6SRobert Mustacchi /*
183b08923d6SRobert Mustacchi * Globals for our name services warning. See ns_warning_thr() for more on why
184b08923d6SRobert Mustacchi * this exists.
185b08923d6SRobert Mustacchi */
186b08923d6SRobert Mustacchi static mutex_t ns_lock = ERRORCHECKMUTEX; /* Protects the following data */
187b08923d6SRobert Mustacchi static boolean_t ns_active = _B_FALSE; /* Lookup is going on */
188b08923d6SRobert Mustacchi static hrtime_t ns_starttime; /* Time the lookup started */
189b08923d6SRobert Mustacchi static int ns_sleeptime = 2; /* Time in seconds between checks */
190b08923d6SRobert Mustacchi static int ns_warntime = 2; /* Time in seconds before warning */
1917c478bd9Sstevel@tonic-gate
1927c478bd9Sstevel@tonic-gate /*
1937c478bd9Sstevel@tonic-gate * This buffer stores the received packets. Currently it needs to be 32 bit
1947c478bd9Sstevel@tonic-gate * aligned. In the future, we'll be using 64 bit alignment, so let's use 64 bit
1957c478bd9Sstevel@tonic-gate * alignment now.
1967c478bd9Sstevel@tonic-gate */
1977c478bd9Sstevel@tonic-gate static uint64_t in_pkt[(IP_MAXPACKET + 1)/8];
1987c478bd9Sstevel@tonic-gate
1997c478bd9Sstevel@tonic-gate /* Used to store the ancillary data that comes with the received packets */
2007c478bd9Sstevel@tonic-gate static uint64_t ancillary_data[(IP_MAXPACKET + 1)/8];
2017c478bd9Sstevel@tonic-gate
2027c478bd9Sstevel@tonic-gate static int ntransmitted; /* number of packet sent to single IP address */
2037c478bd9Sstevel@tonic-gate int nreceived; /* # of packets we got back from target host */
2047c478bd9Sstevel@tonic-gate int nreceived_last_target; /* received from last target IP */
2057c478bd9Sstevel@tonic-gate /*
2067c478bd9Sstevel@tonic-gate * These are used for statistics. tmin is initialized to maximum longint value.
2077c478bd9Sstevel@tonic-gate * The max value is also used for timeouts. All times are in microseconds.
2087c478bd9Sstevel@tonic-gate */
2097c478bd9Sstevel@tonic-gate long long tmin = LLONG_MAX;
2107c478bd9Sstevel@tonic-gate long long tmax;
2117c478bd9Sstevel@tonic-gate int64_t tsum; /* sum of all times, for doing average */
2127c478bd9Sstevel@tonic-gate int64_t tsum2; /* sum of squared times, for std. dev. */
2137c478bd9Sstevel@tonic-gate
2147c478bd9Sstevel@tonic-gate static struct targetaddr *build_targetaddr_list(struct addrinfo *,
2157c478bd9Sstevel@tonic-gate union any_in_addr *);
2167c478bd9Sstevel@tonic-gate extern void check_reply(struct addrinfo *, struct msghdr *, int, ushort_t);
2177c478bd9Sstevel@tonic-gate extern void check_reply6(struct addrinfo *, struct msghdr *, int, ushort_t);
2187c478bd9Sstevel@tonic-gate static struct targetaddr *create_targetaddr_item(int, union any_in_addr *,
2197c478bd9Sstevel@tonic-gate union any_in_addr *);
2207c478bd9Sstevel@tonic-gate void find_dstaddr(ushort_t, union any_in_addr *);
2217c478bd9Sstevel@tonic-gate static struct ifaddrlist *find_if(struct ifaddrlist *, int);
2227c478bd9Sstevel@tonic-gate static void finish();
2237c478bd9Sstevel@tonic-gate static void get_gwaddrs(char *[], int, union any_in_addr *,
2247c478bd9Sstevel@tonic-gate union any_in_addr *, int *, int *);
2257c478bd9Sstevel@tonic-gate static void get_hostinfo(char *, int, struct addrinfo **);
2267c478bd9Sstevel@tonic-gate static ushort_t in_cksum(ushort_t *, int);
2277c478bd9Sstevel@tonic-gate static int int_arg(char *s, char *what);
2287c478bd9Sstevel@tonic-gate boolean_t is_a_target(struct addrinfo *, union any_in_addr *);
2297c478bd9Sstevel@tonic-gate static void mirror_gws(union any_in_addr *, int);
230b08923d6SRobert Mustacchi static void *ns_warning_thr(void *);
231*9c4b0eaaSRobert Mustacchi static void parse_interval(const char *s);
2327c478bd9Sstevel@tonic-gate static void pinger(int, struct sockaddr *, struct msghdr *, int);
2337c478bd9Sstevel@tonic-gate char *pr_name(char *, int);
2347c478bd9Sstevel@tonic-gate char *pr_protocol(int);
2357c478bd9Sstevel@tonic-gate static void print_unknown_host_msg(const char *, const char *);
2367c478bd9Sstevel@tonic-gate static void recv_icmp_packet(struct addrinfo *, int, int, ushort_t, ushort_t);
2374c10bc16Spwernau static void resolve_nodes(struct addrinfo **, struct addrinfo **,
2384c10bc16Spwernau union any_in_addr **);
2397c478bd9Sstevel@tonic-gate void schedule_sigalrm();
2407c478bd9Sstevel@tonic-gate static void select_all_src_addrs(union any_in_addr **, struct addrinfo *,
2417c478bd9Sstevel@tonic-gate union any_in_addr *, union any_in_addr *);
2427c478bd9Sstevel@tonic-gate static void select_src_addr(union any_in_addr *, int, union any_in_addr *);
2437c478bd9Sstevel@tonic-gate void send_scheduled_probe();
2447c478bd9Sstevel@tonic-gate boolean_t seq_match(ushort_t, int, ushort_t);
2457c478bd9Sstevel@tonic-gate extern void set_ancillary_data(struct msghdr *, int, union any_in_addr *, int,
2467c478bd9Sstevel@tonic-gate uint_t);
2477c478bd9Sstevel@tonic-gate extern void set_IPv4_options(int, union any_in_addr *, int, struct in_addr *,
2487c478bd9Sstevel@tonic-gate struct in_addr *);
2494c10bc16Spwernau static void set_nexthop(int, struct addrinfo *, int);
2504c10bc16Spwernau static boolean_t setup_socket(int, int *, int *, int *, ushort_t *,
2514c10bc16Spwernau struct addrinfo *);
2527c478bd9Sstevel@tonic-gate void sigalrm_handler();
2537c478bd9Sstevel@tonic-gate void tvsub(struct timeval *, struct timeval *);
2547c478bd9Sstevel@tonic-gate static void usage(char *);
2557c478bd9Sstevel@tonic-gate
2567c478bd9Sstevel@tonic-gate /*
2577c478bd9Sstevel@tonic-gate * main()
2587c478bd9Sstevel@tonic-gate */
2598c332a0dSja int
main(int argc,char * argv[])2607c478bd9Sstevel@tonic-gate main(int argc, char *argv[])
2617c478bd9Sstevel@tonic-gate {
2627c478bd9Sstevel@tonic-gate struct addrinfo *ai_dst = NULL; /* addrinfo host list */
2634c10bc16Spwernau struct addrinfo *ai_nexthop = NULL; /* addrinfo nexthop */
2647c478bd9Sstevel@tonic-gate union any_in_addr *src_addr_list = NULL; /* src addrs to use */
2657c478bd9Sstevel@tonic-gate int recv_sock = -1; /* receive sockets */
2667c478bd9Sstevel@tonic-gate int recv_sock6 = -1;
2677c478bd9Sstevel@tonic-gate ushort_t udp_src_port; /* src ports for UDP probes */
2687c478bd9Sstevel@tonic-gate ushort_t udp_src_port6; /* used to identify replies */
2697c478bd9Sstevel@tonic-gate uint_t flowinfo = 0;
2707c478bd9Sstevel@tonic-gate uint_t class = 0;
271e11c3f44Smeem char abuf[INET6_ADDRSTRLEN];
2727c478bd9Sstevel@tonic-gate int c;
2737c478bd9Sstevel@tonic-gate int i;
274f4b3ec61Sdh boolean_t has_sys_ip_config;
2757c478bd9Sstevel@tonic-gate
2767c478bd9Sstevel@tonic-gate progname = argv[0];
2777c478bd9Sstevel@tonic-gate
278b08923d6SRobert Mustacchi (void) setlocale(LC_ALL, "");
279b08923d6SRobert Mustacchi
2807c478bd9Sstevel@tonic-gate /*
2811da45818Spwernau * This program needs the net_icmpaccess privilege for creating
282f4b3ec61Sdh * raw ICMP sockets. It needs sys_ip_config for using the
2831da45818Spwernau * IP_NEXTHOP socket option (IPv4 only). We'll fail
2847c478bd9Sstevel@tonic-gate * on the socket call and report the error there when we have
2857c478bd9Sstevel@tonic-gate * insufficient privileges.
2861da45818Spwernau *
287f4b3ec61Sdh * Shared-IP zones don't have the sys_ip_config privilege, so
2881da45818Spwernau * we need to check for it in our limit set before trying
2891da45818Spwernau * to set it.
2907c478bd9Sstevel@tonic-gate */
291f4b3ec61Sdh has_sys_ip_config = priv_ineffect(PRIV_SYS_IP_CONFIG);
2921da45818Spwernau
2937c478bd9Sstevel@tonic-gate (void) __init_suid_priv(PU_CLEARLIMITSET, PRIV_NET_ICMPACCESS,
294f4b3ec61Sdh has_sys_ip_config ? PRIV_SYS_IP_CONFIG : (char *)NULL,
2951da45818Spwernau (char *)NULL);
2967c478bd9Sstevel@tonic-gate
2977c478bd9Sstevel@tonic-gate setbuf(stdout, (char *)0);
2987c478bd9Sstevel@tonic-gate
2997c478bd9Sstevel@tonic-gate while ((c = getopt(argc, argv,
300bd670b35SErik Nordmark "abA:c:dDF:G:g:I:i:LlnN:P:p:rRSsTt:UvX:x:Y0123?")) != -1) {
3017c478bd9Sstevel@tonic-gate switch ((char)c) {
3027c478bd9Sstevel@tonic-gate case 'A':
3037c478bd9Sstevel@tonic-gate if (strcmp(optarg, "inet") == 0) {
3047c478bd9Sstevel@tonic-gate family_input = AF_INET;
3057c478bd9Sstevel@tonic-gate } else if (strcmp(optarg, "inet6") == 0) {
3067c478bd9Sstevel@tonic-gate family_input = AF_INET6;
3077c478bd9Sstevel@tonic-gate } else {
3087c478bd9Sstevel@tonic-gate Fprintf(stderr,
3097c478bd9Sstevel@tonic-gate "%s: unknown address family %s\n",
3107c478bd9Sstevel@tonic-gate progname, optarg);
3117c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
3127c478bd9Sstevel@tonic-gate }
3137c478bd9Sstevel@tonic-gate break;
3147c478bd9Sstevel@tonic-gate
3157c478bd9Sstevel@tonic-gate case 'a':
3167c478bd9Sstevel@tonic-gate probe_all = _B_TRUE;
3177c478bd9Sstevel@tonic-gate break;
3187c478bd9Sstevel@tonic-gate
3197c478bd9Sstevel@tonic-gate case 'c':
3207c478bd9Sstevel@tonic-gate i = int_arg(optarg, "traffic class");
3217c478bd9Sstevel@tonic-gate if (i > MAX_TRAFFIC_CLASS) {
3227c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: traffic class %d out of "
3237c478bd9Sstevel@tonic-gate "range\n", progname, i);
3247c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
3257c478bd9Sstevel@tonic-gate }
3267c478bd9Sstevel@tonic-gate class = (uint_t)i;
3277c478bd9Sstevel@tonic-gate break;
3287c478bd9Sstevel@tonic-gate
3297c478bd9Sstevel@tonic-gate case 'd':
3307c478bd9Sstevel@tonic-gate options |= SO_DEBUG;
3317c478bd9Sstevel@tonic-gate break;
3327c478bd9Sstevel@tonic-gate
333bd670b35SErik Nordmark case 'D':
334bd670b35SErik Nordmark dontfrag = 1;
335bd670b35SErik Nordmark break;
336bd670b35SErik Nordmark
337a356273cSpwernau case 'b':
338a356273cSpwernau bypass = _B_TRUE;
339a356273cSpwernau break;
340a356273cSpwernau
3417c478bd9Sstevel@tonic-gate case 'F':
3427c478bd9Sstevel@tonic-gate i = int_arg(optarg, "flow label");
3437c478bd9Sstevel@tonic-gate if (i > MAX_FLOW_LABEL) {
3447c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: flow label %d out of "
3457c478bd9Sstevel@tonic-gate "range\n", progname, i);
3467c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
3477c478bd9Sstevel@tonic-gate }
3487c478bd9Sstevel@tonic-gate flowinfo = (uint_t)i;
3497c478bd9Sstevel@tonic-gate break;
3507c478bd9Sstevel@tonic-gate
3517c478bd9Sstevel@tonic-gate case 'I':
3527c478bd9Sstevel@tonic-gate stats = _B_TRUE;
353b08923d6SRobert Mustacchi parse_interval(optarg);
3547c478bd9Sstevel@tonic-gate break;
3557c478bd9Sstevel@tonic-gate
3567c478bd9Sstevel@tonic-gate case 'i':
3577c478bd9Sstevel@tonic-gate /*
3587c478bd9Sstevel@tonic-gate * this can accept interface index, interface name, and
3597c478bd9Sstevel@tonic-gate * address configured on the interface
3607c478bd9Sstevel@tonic-gate */
3617c478bd9Sstevel@tonic-gate moptions |= MULTICAST_IF;
3627c478bd9Sstevel@tonic-gate out_if.str = optarg;
3637c478bd9Sstevel@tonic-gate
3647c478bd9Sstevel@tonic-gate if (inet_pton(AF_INET6, optarg, &out_if.id.addr) > 0) {
3657c478bd9Sstevel@tonic-gate out_if.id_type = IF_ADDR6;
3667c478bd9Sstevel@tonic-gate } else if (inet_pton(AF_INET, optarg,
3677c478bd9Sstevel@tonic-gate &out_if.id.addr) > 0) {
3687c478bd9Sstevel@tonic-gate out_if.id_type = IF_ADDR;
3697c478bd9Sstevel@tonic-gate } else if (strcmp(optarg, "0") == 0) {
3707c478bd9Sstevel@tonic-gate out_if.id_type = IF_INDEX;
3717c478bd9Sstevel@tonic-gate out_if.id.index = 0;
3727c478bd9Sstevel@tonic-gate } else if ((out_if.id.index = atoi(optarg)) != 0) {
3737c478bd9Sstevel@tonic-gate out_if.id_type = IF_INDEX;
3747c478bd9Sstevel@tonic-gate } else {
3757c478bd9Sstevel@tonic-gate out_if.id.name = optarg;
3767c478bd9Sstevel@tonic-gate out_if.id_type = IF_NAME;
3777c478bd9Sstevel@tonic-gate }
3787c478bd9Sstevel@tonic-gate break;
3797c478bd9Sstevel@tonic-gate
3807c478bd9Sstevel@tonic-gate case 'L':
3817c478bd9Sstevel@tonic-gate moptions |= MULTICAST_NOLOOP;
3827c478bd9Sstevel@tonic-gate break;
3837c478bd9Sstevel@tonic-gate
3847c478bd9Sstevel@tonic-gate case 'l':
3857c478bd9Sstevel@tonic-gate send_reply = _B_TRUE;
3867c478bd9Sstevel@tonic-gate strict = _B_FALSE;
3877c478bd9Sstevel@tonic-gate break;
3887c478bd9Sstevel@tonic-gate
3897c478bd9Sstevel@tonic-gate case 'n':
3907c478bd9Sstevel@tonic-gate nflag = _B_TRUE;
3917c478bd9Sstevel@tonic-gate break;
3927c478bd9Sstevel@tonic-gate
3937c478bd9Sstevel@tonic-gate case 'P':
3947c478bd9Sstevel@tonic-gate settos = _B_TRUE;
3957c478bd9Sstevel@tonic-gate i = int_arg(optarg, "type-of-service");
3967c478bd9Sstevel@tonic-gate if (i > MAX_TOS) {
3977c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: tos value %d out of "
3987c478bd9Sstevel@tonic-gate "range\n", progname, i);
3997c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
4007c478bd9Sstevel@tonic-gate }
4017c478bd9Sstevel@tonic-gate tos = (ushort_t)i;
4027c478bd9Sstevel@tonic-gate break;
4037c478bd9Sstevel@tonic-gate
4047c478bd9Sstevel@tonic-gate case 'p':
4057c478bd9Sstevel@tonic-gate i = int_arg(optarg, "port number");
4067c478bd9Sstevel@tonic-gate if (i > MAX_PORT) {
4077c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: port number %d out of "
4087c478bd9Sstevel@tonic-gate "range\n", progname, i);
4097c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
4107c478bd9Sstevel@tonic-gate }
4117c478bd9Sstevel@tonic-gate dest_port = (ushort_t)i;
4127c478bd9Sstevel@tonic-gate break;
4137c478bd9Sstevel@tonic-gate
4147c478bd9Sstevel@tonic-gate case 'r':
4157c478bd9Sstevel@tonic-gate options |= SO_DONTROUTE;
4167c478bd9Sstevel@tonic-gate break;
4177c478bd9Sstevel@tonic-gate
4187c478bd9Sstevel@tonic-gate case 'R':
4197c478bd9Sstevel@tonic-gate rr_option = _B_TRUE;
4207c478bd9Sstevel@tonic-gate break;
4217c478bd9Sstevel@tonic-gate
4227c478bd9Sstevel@tonic-gate case 'S':
4237c478bd9Sstevel@tonic-gate send_reply = _B_TRUE;
4247c478bd9Sstevel@tonic-gate strict = _B_TRUE;
4257c478bd9Sstevel@tonic-gate break;
4267c478bd9Sstevel@tonic-gate
4277c478bd9Sstevel@tonic-gate case 's':
4287c478bd9Sstevel@tonic-gate stats = _B_TRUE;
4297c478bd9Sstevel@tonic-gate break;
4307c478bd9Sstevel@tonic-gate
4317c478bd9Sstevel@tonic-gate case 'T':
4327c478bd9Sstevel@tonic-gate ts_option = _B_TRUE;
4337c478bd9Sstevel@tonic-gate break;
4347c478bd9Sstevel@tonic-gate
4357c478bd9Sstevel@tonic-gate case 't':
4367c478bd9Sstevel@tonic-gate moptions |= MULTICAST_TTL;
4377c478bd9Sstevel@tonic-gate hoplimit = int_arg(optarg, "ttl");
4387c478bd9Sstevel@tonic-gate if (hoplimit > MAXTTL) {
4397c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: ttl %d out of range\n",
4407c478bd9Sstevel@tonic-gate progname, hoplimit);
4417c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
4427c478bd9Sstevel@tonic-gate }
4437c478bd9Sstevel@tonic-gate break;
4447c478bd9Sstevel@tonic-gate
4457c478bd9Sstevel@tonic-gate case 'U':
4467c478bd9Sstevel@tonic-gate use_udp = _B_TRUE;
4477c478bd9Sstevel@tonic-gate use_icmp_ts = _B_FALSE;
4487c478bd9Sstevel@tonic-gate break;
4497c478bd9Sstevel@tonic-gate
4507c478bd9Sstevel@tonic-gate case 'v':
4517c478bd9Sstevel@tonic-gate verbose = _B_TRUE;
4527c478bd9Sstevel@tonic-gate break;
4537c478bd9Sstevel@tonic-gate /*
4547c478bd9Sstevel@tonic-gate * 'x' and 'X' has been undocumented flags for source routing.
4557c478bd9Sstevel@tonic-gate * Now we document loose source routing with the new flag 'g',
4567c478bd9Sstevel@tonic-gate * which is same as in traceroute. We still keep x/X as
4577c478bd9Sstevel@tonic-gate * as undocumented. 'G', which is for strict source routing is
4587c478bd9Sstevel@tonic-gate * also undocumented.
4597c478bd9Sstevel@tonic-gate */
4607c478bd9Sstevel@tonic-gate case 'x':
4617c478bd9Sstevel@tonic-gate case 'g':
4627c478bd9Sstevel@tonic-gate strict = _B_FALSE;
4637c478bd9Sstevel@tonic-gate if (num_gw > MAXMAX_GWS) {
4647c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: too many gateways\n",
4657c478bd9Sstevel@tonic-gate progname);
4667c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
4677c478bd9Sstevel@tonic-gate }
4687c478bd9Sstevel@tonic-gate gw_list[num_gw++] = optarg;
4697c478bd9Sstevel@tonic-gate break;
4707c478bd9Sstevel@tonic-gate
4717c478bd9Sstevel@tonic-gate case 'X':
4727c478bd9Sstevel@tonic-gate case 'G':
4737c478bd9Sstevel@tonic-gate strict = _B_TRUE;
4747c478bd9Sstevel@tonic-gate if (num_gw > MAXMAX_GWS) {
4757c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: too many gateways\n",
4767c478bd9Sstevel@tonic-gate progname);
4777c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
4787c478bd9Sstevel@tonic-gate }
4797c478bd9Sstevel@tonic-gate gw_list[num_gw++] = optarg;
4807c478bd9Sstevel@tonic-gate break;
4817c478bd9Sstevel@tonic-gate
4824c10bc16Spwernau case 'N':
4834c10bc16Spwernau if (nexthop != NULL) {
4844c10bc16Spwernau Fprintf(stderr, "%s: only one next hop gateway"
4854c10bc16Spwernau " allowed\n", progname);
4864c10bc16Spwernau exit(EXIT_FAILURE);
4874c10bc16Spwernau }
4884c10bc16Spwernau nexthop = optarg;
4894c10bc16Spwernau break;
4904c10bc16Spwernau
4917c478bd9Sstevel@tonic-gate case 'Y':
4927c478bd9Sstevel@tonic-gate use_icmp_ts = _B_TRUE;
4937c478bd9Sstevel@tonic-gate use_udp = _B_FALSE;
4947c478bd9Sstevel@tonic-gate break;
4957c478bd9Sstevel@tonic-gate
4967c478bd9Sstevel@tonic-gate case '0':
4977c478bd9Sstevel@tonic-gate case '1':
4987c478bd9Sstevel@tonic-gate case '2':
4997c478bd9Sstevel@tonic-gate case '3':
5007c478bd9Sstevel@tonic-gate ts_flag = (char)c - '0';
5017c478bd9Sstevel@tonic-gate break;
5027c478bd9Sstevel@tonic-gate
5037c478bd9Sstevel@tonic-gate case '?':
5047c478bd9Sstevel@tonic-gate usage(progname);
5057c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
5067c478bd9Sstevel@tonic-gate break;
5077c478bd9Sstevel@tonic-gate
5087c478bd9Sstevel@tonic-gate default:
5097c478bd9Sstevel@tonic-gate usage(progname);
5107c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
5117c478bd9Sstevel@tonic-gate break;
5127c478bd9Sstevel@tonic-gate }
5137c478bd9Sstevel@tonic-gate }
5147c478bd9Sstevel@tonic-gate
5157c478bd9Sstevel@tonic-gate if (optind >= argc) {
5167c478bd9Sstevel@tonic-gate usage(progname);
5177c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
5187c478bd9Sstevel@tonic-gate }
5197c478bd9Sstevel@tonic-gate
5207c478bd9Sstevel@tonic-gate /*
5217c478bd9Sstevel@tonic-gate * send_reply, which sends the probe packet back to itself
5227c478bd9Sstevel@tonic-gate * doesn't work with UDP
5237c478bd9Sstevel@tonic-gate */
5247c478bd9Sstevel@tonic-gate if (use_udp)
5257c478bd9Sstevel@tonic-gate send_reply = _B_FALSE;
5267c478bd9Sstevel@tonic-gate
5273c58dfd6Sjbeck if (getenv("MACHINE_THAT_GOES_PING") != NULL)
5283c58dfd6Sjbeck stats = _B_TRUE;
5293c58dfd6Sjbeck
5307c478bd9Sstevel@tonic-gate targethost = argv[optind];
5317c478bd9Sstevel@tonic-gate optind++;
5327c478bd9Sstevel@tonic-gate if (optind < argc) {
5337c478bd9Sstevel@tonic-gate if (stats) {
5347c478bd9Sstevel@tonic-gate datalen = int_arg(argv[optind], "data size");
5357c478bd9Sstevel@tonic-gate optind++;
5367c478bd9Sstevel@tonic-gate if (optind < argc) {
5377c478bd9Sstevel@tonic-gate npackets = int_arg(argv[optind],
5387c478bd9Sstevel@tonic-gate "packet count");
5397c478bd9Sstevel@tonic-gate if (npackets < 1) {
5407c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: packet count %d "
5417c478bd9Sstevel@tonic-gate "out of range\n", progname,
5427c478bd9Sstevel@tonic-gate npackets);
5437c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
5447c478bd9Sstevel@tonic-gate }
5457c478bd9Sstevel@tonic-gate }
5467c478bd9Sstevel@tonic-gate } else {
5477c478bd9Sstevel@tonic-gate timeout = int_arg(argv[optind], "timeout");
5487c478bd9Sstevel@tonic-gate }
5497c478bd9Sstevel@tonic-gate }
5507c478bd9Sstevel@tonic-gate
5517c478bd9Sstevel@tonic-gate /*
5527c478bd9Sstevel@tonic-gate * Let's prepare sockaddr_in* structures, cause we might need both of
5537c478bd9Sstevel@tonic-gate * them.
5547c478bd9Sstevel@tonic-gate */
5557c478bd9Sstevel@tonic-gate bzero((char *)&to, sizeof (struct sockaddr_in));
5567c478bd9Sstevel@tonic-gate to.sin_family = AF_INET;
5577c478bd9Sstevel@tonic-gate
5587c478bd9Sstevel@tonic-gate bzero((char *)&to6, sizeof (struct sockaddr_in6));
5597c478bd9Sstevel@tonic-gate to6.sin6_family = AF_INET6;
5607c478bd9Sstevel@tonic-gate to6.sin6_flowinfo = htonl((class << 20) | flowinfo);
5617c478bd9Sstevel@tonic-gate
5627c478bd9Sstevel@tonic-gate if (stats)
5637c478bd9Sstevel@tonic-gate (void) sigset(SIGINT, finish);
5647c478bd9Sstevel@tonic-gate
5657c478bd9Sstevel@tonic-gate ident = (int)getpid() & 0xFFFF;
5667c478bd9Sstevel@tonic-gate
5677c478bd9Sstevel@tonic-gate /* resolve the hostnames */
5684c10bc16Spwernau resolve_nodes(&ai_dst, &ai_nexthop, &src_addr_list);
5697c478bd9Sstevel@tonic-gate
5707c478bd9Sstevel@tonic-gate /*
5717c478bd9Sstevel@tonic-gate * We should make sure datalen is reasonable.
572*9c4b0eaaSRobert Mustacchi * IP_MAXPACKET >= IPv4/IPv6 header length +
5737c478bd9Sstevel@tonic-gate * IPv4 options/IPv6 routing header length +
5747c478bd9Sstevel@tonic-gate * ICMP/ICMP6/UDP header length +
5757c478bd9Sstevel@tonic-gate * datalen
5767c478bd9Sstevel@tonic-gate */
5777c478bd9Sstevel@tonic-gate
5787c478bd9Sstevel@tonic-gate if (family_input == AF_INET6 ||
5797c478bd9Sstevel@tonic-gate (family_input == AF_UNSPEC && num_v6 != 0)) {
5807c478bd9Sstevel@tonic-gate size_t exthdr_len = 0;
5817c478bd9Sstevel@tonic-gate
5827c478bd9Sstevel@tonic-gate if (send_reply) {
5837c478bd9Sstevel@tonic-gate exthdr_len = sizeof (struct ip6_rthdr0) +
5847c478bd9Sstevel@tonic-gate 2 * num_gw * sizeof (struct in6_addr);
5857c478bd9Sstevel@tonic-gate } else if (num_gw > 0) {
5867c478bd9Sstevel@tonic-gate exthdr_len = sizeof (struct ip6_rthdr0) +
5877c478bd9Sstevel@tonic-gate num_gw * sizeof (struct in6_addr);
5887c478bd9Sstevel@tonic-gate }
5897c478bd9Sstevel@tonic-gate
5907c478bd9Sstevel@tonic-gate /*
5917c478bd9Sstevel@tonic-gate * Size of ICMP6 header and UDP header are the same. Let's
5927c478bd9Sstevel@tonic-gate * use ICMP6_MINLEN.
5937c478bd9Sstevel@tonic-gate */
5947c478bd9Sstevel@tonic-gate if (datalen > (IP_MAXPACKET - (sizeof (struct ip6_hdr) +
5957c478bd9Sstevel@tonic-gate exthdr_len + ICMP6_MINLEN))) {
5967c478bd9Sstevel@tonic-gate Fprintf(stderr,
5977c478bd9Sstevel@tonic-gate "%s: data size too large for IPv6 packet\n",
5987c478bd9Sstevel@tonic-gate progname);
5997c478bd9Sstevel@tonic-gate num_v6 = 0;
6007c478bd9Sstevel@tonic-gate }
6017c478bd9Sstevel@tonic-gate }
6027c478bd9Sstevel@tonic-gate
6037c478bd9Sstevel@tonic-gate if (family_input == AF_INET ||
6047c478bd9Sstevel@tonic-gate (family_input == AF_UNSPEC && num_v4 != 0)) {
6057c478bd9Sstevel@tonic-gate size_t opt_len = 0;
6067c478bd9Sstevel@tonic-gate
6077c478bd9Sstevel@tonic-gate if (send_reply) {
6087c478bd9Sstevel@tonic-gate /*
6097c478bd9Sstevel@tonic-gate * Includes 3 bytes code+ptr+len, the intermediate
6107c478bd9Sstevel@tonic-gate * gateways, the actual and the effective target.
6117c478bd9Sstevel@tonic-gate */
6127c478bd9Sstevel@tonic-gate opt_len = 3 +
6137c478bd9Sstevel@tonic-gate (2 * num_gw + 2) * sizeof (struct in_addr);
6147c478bd9Sstevel@tonic-gate } else if (num_gw > 0) {
6157c478bd9Sstevel@tonic-gate opt_len = 3 + (num_gw + 1) * sizeof (struct in_addr);
6167c478bd9Sstevel@tonic-gate }
6177c478bd9Sstevel@tonic-gate
6187c478bd9Sstevel@tonic-gate if (rr_option) {
6197c478bd9Sstevel@tonic-gate opt_len = MAX_IPOPTLEN;
6207c478bd9Sstevel@tonic-gate } else if (ts_option) {
6217c478bd9Sstevel@tonic-gate if ((ts_flag & 0x0f) <= IPOPT_TS_TSANDADDR) {
6227c478bd9Sstevel@tonic-gate opt_len = MAX_IPOPTLEN;
6237c478bd9Sstevel@tonic-gate } else {
6247c478bd9Sstevel@tonic-gate opt_len += IPOPT_MINOFF +
6257c478bd9Sstevel@tonic-gate 2 * sizeof (struct ipt_ta);
6267c478bd9Sstevel@tonic-gate /*
6277c478bd9Sstevel@tonic-gate * Note: BSD/4.X is broken in their check so we
6287c478bd9Sstevel@tonic-gate * have to bump up this number by at least one.
6297c478bd9Sstevel@tonic-gate */
6307c478bd9Sstevel@tonic-gate opt_len++;
6317c478bd9Sstevel@tonic-gate }
6327c478bd9Sstevel@tonic-gate }
6337c478bd9Sstevel@tonic-gate
6347c478bd9Sstevel@tonic-gate /* Round up to 4 byte boundary */
6357c478bd9Sstevel@tonic-gate if (opt_len & 0x3)
6367c478bd9Sstevel@tonic-gate opt_len = (opt_len & ~0x3) + 4;
6377c478bd9Sstevel@tonic-gate
6387c478bd9Sstevel@tonic-gate if (datalen > (IP_MAXPACKET - (sizeof (struct ip) + opt_len +
6397c478bd9Sstevel@tonic-gate ICMP_MINLEN))) {
6407c478bd9Sstevel@tonic-gate Fprintf(stderr,
6417c478bd9Sstevel@tonic-gate "%s: data size too large for IPv4 packet\n",
6427c478bd9Sstevel@tonic-gate progname);
6437c478bd9Sstevel@tonic-gate num_v4 = 0;
6447c478bd9Sstevel@tonic-gate }
6457c478bd9Sstevel@tonic-gate }
6467c478bd9Sstevel@tonic-gate
6477c478bd9Sstevel@tonic-gate if (num_v4 == 0 && num_v6 == 0) {
6487c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
6497c478bd9Sstevel@tonic-gate }
6507c478bd9Sstevel@tonic-gate
6517c478bd9Sstevel@tonic-gate /* setup the sockets */
6527c478bd9Sstevel@tonic-gate if (num_v6 != 0) {
6537c478bd9Sstevel@tonic-gate if (!setup_socket(AF_INET6, &send_sock6, &recv_sock6,
6544c10bc16Spwernau &if_index, &udp_src_port6, ai_nexthop))
6557c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
6567c478bd9Sstevel@tonic-gate }
6577c478bd9Sstevel@tonic-gate
6587c478bd9Sstevel@tonic-gate if (num_v4 != 0) {
6597c478bd9Sstevel@tonic-gate if (!setup_socket(AF_INET, &send_sock, &recv_sock, &if_index,
6604c10bc16Spwernau &udp_src_port, ai_nexthop))
6617c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
6627c478bd9Sstevel@tonic-gate }
6637c478bd9Sstevel@tonic-gate
6647c478bd9Sstevel@tonic-gate __priv_relinquish();
6657c478bd9Sstevel@tonic-gate
6667c478bd9Sstevel@tonic-gate /*
6677c478bd9Sstevel@tonic-gate * If sending back to ourself, add the mirror image of current
6687c478bd9Sstevel@tonic-gate * gateways, so that the probes travel to and from the target
6697c478bd9Sstevel@tonic-gate * by visiting the same gateways in reverse order.
6707c478bd9Sstevel@tonic-gate */
6717c478bd9Sstevel@tonic-gate if (send_reply) {
6727c478bd9Sstevel@tonic-gate if (num_v6 != 0)
6737c478bd9Sstevel@tonic-gate mirror_gws(gw_IP_list6, AF_INET6);
6747c478bd9Sstevel@tonic-gate if (num_v4 != 0)
6757c478bd9Sstevel@tonic-gate mirror_gws(gw_IP_list, AF_INET);
6767c478bd9Sstevel@tonic-gate
6777c478bd9Sstevel@tonic-gate /* We add 1 because we put the target as the middle gateway */
6787c478bd9Sstevel@tonic-gate eff_num_gw = 2 * num_gw + 1;
6797c478bd9Sstevel@tonic-gate
6807c478bd9Sstevel@tonic-gate } else {
6817c478bd9Sstevel@tonic-gate eff_num_gw = num_gw;
6827c478bd9Sstevel@tonic-gate }
6837c478bd9Sstevel@tonic-gate
6847c478bd9Sstevel@tonic-gate targetaddr_list = build_targetaddr_list(ai_dst, src_addr_list);
6857c478bd9Sstevel@tonic-gate current_targetaddr = targetaddr_list;
6867c478bd9Sstevel@tonic-gate
6877c478bd9Sstevel@tonic-gate /*
6887c478bd9Sstevel@tonic-gate * Set the starting_seq_num for the first targetaddr.
6897c478bd9Sstevel@tonic-gate * If we are sending ICMP Echo Requests, the sequence number is same as
6907c478bd9Sstevel@tonic-gate * ICMP sequence number, and it starts from zero. If we are sending UDP
6917c478bd9Sstevel@tonic-gate * packets, the sequence number is the destination UDP port number,
6927c478bd9Sstevel@tonic-gate * which starts from dest_port. At each probe, this sequence number is
6937c478bd9Sstevel@tonic-gate * incremented by one.
6947c478bd9Sstevel@tonic-gate * We set the starting_seq_num for first targetaddr here. The
6957c478bd9Sstevel@tonic-gate * following ones will be set by looking at where we left with the last
6967c478bd9Sstevel@tonic-gate * targetaddr.
6977c478bd9Sstevel@tonic-gate */
6987c478bd9Sstevel@tonic-gate current_targetaddr->starting_seq_num = use_udp ? dest_port : 0;
6997c478bd9Sstevel@tonic-gate
7007c478bd9Sstevel@tonic-gate if (stats) {
7017c478bd9Sstevel@tonic-gate if (probe_all || !nflag) {
7027c478bd9Sstevel@tonic-gate Printf("PING %s: %d data bytes\n", targethost, datalen);
7037c478bd9Sstevel@tonic-gate } else {
7047c478bd9Sstevel@tonic-gate if (ai_dst->ai_family == AF_INET) {
705e11c3f44Smeem (void) inet_ntop(AF_INET,
706e11c3f44Smeem &((struct sockaddr_in *)(void *)
707e11c3f44Smeem ai_dst->ai_addr)->sin_addr,
708e11c3f44Smeem abuf, sizeof (abuf));
7097c478bd9Sstevel@tonic-gate } else {
710e11c3f44Smeem (void) inet_ntop(AF_INET6,
711e11c3f44Smeem &((struct sockaddr_in6 *)(void *)
712e11c3f44Smeem ai_dst->ai_addr)->sin6_addr,
713e11c3f44Smeem abuf, sizeof (abuf));
7147c478bd9Sstevel@tonic-gate }
715e11c3f44Smeem Printf("PING %s (%s): %d data bytes\n",
716e11c3f44Smeem targethost, abuf, datalen);
7177c478bd9Sstevel@tonic-gate }
7187c478bd9Sstevel@tonic-gate }
7197c478bd9Sstevel@tonic-gate
720b08923d6SRobert Mustacchi /* Create our timer for future use */
721b08923d6SRobert Mustacchi if (timer_create(CLOCK_REALTIME, NULL, &timer) != 0) {
722b08923d6SRobert Mustacchi Fprintf(stderr, "%s: failed to create timer: %s\n",
723b08923d6SRobert Mustacchi progname, strerror(errno));
724b08923d6SRobert Mustacchi exit(EXIT_FAILURE);
725b08923d6SRobert Mustacchi }
726b08923d6SRobert Mustacchi
727b08923d6SRobert Mustacchi /*
728b08923d6SRobert Mustacchi * Finally start up the name services warning thread.
729b08923d6SRobert Mustacchi */
730b08923d6SRobert Mustacchi if (thr_create(NULL, 0, ns_warning_thr, NULL,
731b08923d6SRobert Mustacchi THR_DETACHED | THR_DAEMON, NULL) != 0) {
732b08923d6SRobert Mustacchi Fprintf(stderr, "%s: failed to create name services "
733b08923d6SRobert Mustacchi "thread: %s\n", progname, strerror(errno));
734b08923d6SRobert Mustacchi exit(EXIT_FAILURE);
735b08923d6SRobert Mustacchi }
736b08923d6SRobert Mustacchi
7377c478bd9Sstevel@tonic-gate /* Let's get things going */
7387c478bd9Sstevel@tonic-gate send_scheduled_probe();
7397c478bd9Sstevel@tonic-gate
7407c478bd9Sstevel@tonic-gate /* SIGALRM is used to send the next scheduled probe */
7417c478bd9Sstevel@tonic-gate (void) sigset(SIGALRM, sigalrm_handler);
7427c478bd9Sstevel@tonic-gate schedule_sigalrm();
7437c478bd9Sstevel@tonic-gate
7447c478bd9Sstevel@tonic-gate /*
7457c478bd9Sstevel@tonic-gate * From now on, we'll always be listening to ICMP packets. As SIGALRM
7467c478bd9Sstevel@tonic-gate * comes in, sigalrm_handler() will be invoked and send another
7477c478bd9Sstevel@tonic-gate * probe.
7487c478bd9Sstevel@tonic-gate */
7497c478bd9Sstevel@tonic-gate recv_icmp_packet(ai_dst, recv_sock6, recv_sock, udp_src_port6,
7507c478bd9Sstevel@tonic-gate udp_src_port);
7517c478bd9Sstevel@tonic-gate
7528c332a0dSja return (EXIT_SUCCESS); /* should never come here */
7537c478bd9Sstevel@tonic-gate }
7547c478bd9Sstevel@tonic-gate
7557c478bd9Sstevel@tonic-gate /*
7567c478bd9Sstevel@tonic-gate * Build the target IP address list. Use command line options and
7577c478bd9Sstevel@tonic-gate * name lookup results returned from name server to determine which addresses
7587c478bd9Sstevel@tonic-gate * to probe, how many times, in which order.
7597c478bd9Sstevel@tonic-gate */
7607c478bd9Sstevel@tonic-gate static struct targetaddr *
build_targetaddr_list(struct addrinfo * ai_dst,union any_in_addr * src_addr_list)7617c478bd9Sstevel@tonic-gate build_targetaddr_list(struct addrinfo *ai_dst, union any_in_addr *src_addr_list)
7627c478bd9Sstevel@tonic-gate {
7637c478bd9Sstevel@tonic-gate struct targetaddr *head = NULL;
7647c478bd9Sstevel@tonic-gate struct targetaddr *targetaddr;
7657c478bd9Sstevel@tonic-gate struct targetaddr **nextp;
7667c478bd9Sstevel@tonic-gate int num_dst;
7677c478bd9Sstevel@tonic-gate int i;
7687c478bd9Sstevel@tonic-gate struct addrinfo *aip;
7697c478bd9Sstevel@tonic-gate
7707c478bd9Sstevel@tonic-gate aip = ai_dst;
7717c478bd9Sstevel@tonic-gate if (probe_all)
7727c478bd9Sstevel@tonic-gate num_dst = num_v4 + num_v6;
7737c478bd9Sstevel@tonic-gate else
7747c478bd9Sstevel@tonic-gate num_dst = 1;
7757c478bd9Sstevel@tonic-gate num_targetaddrs = num_dst;
7767c478bd9Sstevel@tonic-gate nextp = &head;
7777c478bd9Sstevel@tonic-gate for (aip = ai_dst, i = 0; aip != NULL; aip = aip->ai_next, i++) {
7787c478bd9Sstevel@tonic-gate if (aip->ai_family == AF_INET && num_v4 != 0) {
7797c478bd9Sstevel@tonic-gate targetaddr = create_targetaddr_item(aip->ai_family,
7807c478bd9Sstevel@tonic-gate (union any_in_addr *)
7817c478bd9Sstevel@tonic-gate /* LINTED E_BAD_PTR_CAST_ALIGN */
7827c478bd9Sstevel@tonic-gate &((struct sockaddr_in *)
7837c478bd9Sstevel@tonic-gate aip->ai_addr)->sin_addr,
7847c478bd9Sstevel@tonic-gate &src_addr_list[i]);
7857c478bd9Sstevel@tonic-gate } else if (aip->ai_family == AF_INET6 && num_v6 != 0) {
7867c478bd9Sstevel@tonic-gate targetaddr = create_targetaddr_item(aip->ai_family,
7877c478bd9Sstevel@tonic-gate (union any_in_addr *)
7887c478bd9Sstevel@tonic-gate /* LINTED E_BAD_PTR_CAST_ALIGN */
7897c478bd9Sstevel@tonic-gate &((struct sockaddr_in6 *)
7907c478bd9Sstevel@tonic-gate aip->ai_addr)->sin6_addr,
7917c478bd9Sstevel@tonic-gate &src_addr_list[i]);
7927c478bd9Sstevel@tonic-gate } else {
7937c478bd9Sstevel@tonic-gate continue;
7947c478bd9Sstevel@tonic-gate }
7957c478bd9Sstevel@tonic-gate *nextp = targetaddr;
7967c478bd9Sstevel@tonic-gate nextp = &targetaddr->next;
7977c478bd9Sstevel@tonic-gate if (num_targetaddrs == 1)
7987c478bd9Sstevel@tonic-gate break;
7997c478bd9Sstevel@tonic-gate }
8007c478bd9Sstevel@tonic-gate if (npackets == 0 && stats)
8017c478bd9Sstevel@tonic-gate *nextp = head; /* keep going indefinitely */
8027c478bd9Sstevel@tonic-gate
8037c478bd9Sstevel@tonic-gate return (head);
8047c478bd9Sstevel@tonic-gate }
8057c478bd9Sstevel@tonic-gate
8067c478bd9Sstevel@tonic-gate /*
8077c478bd9Sstevel@tonic-gate * Given an address family, dst and src addresses, by also looking at the
8087c478bd9Sstevel@tonic-gate * options provided at the command line, this function creates a targetaddr
8097c478bd9Sstevel@tonic-gate * to be linked with others, forming a global targetaddr list. Each targetaddr
8107c478bd9Sstevel@tonic-gate * item contains information about probes sent to a specific IP address.
8117c478bd9Sstevel@tonic-gate */
8127c478bd9Sstevel@tonic-gate static struct targetaddr *
create_targetaddr_item(int family,union any_in_addr * dst_addr,union any_in_addr * src_addr)8137c478bd9Sstevel@tonic-gate create_targetaddr_item(int family, union any_in_addr *dst_addr,
8147c478bd9Sstevel@tonic-gate union any_in_addr *src_addr)
8157c478bd9Sstevel@tonic-gate {
8167c478bd9Sstevel@tonic-gate struct targetaddr *targetaddr;
8177c478bd9Sstevel@tonic-gate
8187c478bd9Sstevel@tonic-gate targetaddr = (struct targetaddr *)malloc(sizeof (struct targetaddr));
8197c478bd9Sstevel@tonic-gate if (targetaddr == NULL) {
8207c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: malloc %s\n", progname, strerror(errno));
8217c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
8227c478bd9Sstevel@tonic-gate }
8237c478bd9Sstevel@tonic-gate targetaddr->family = family;
8247c478bd9Sstevel@tonic-gate targetaddr->dst_addr = *dst_addr;
8257c478bd9Sstevel@tonic-gate targetaddr->src_addr = *src_addr;
8267c478bd9Sstevel@tonic-gate if (stats) {
8277c478bd9Sstevel@tonic-gate /*
8287c478bd9Sstevel@tonic-gate * npackets is only defined if we are in stats mode.
8297c478bd9Sstevel@tonic-gate * npackets determines how many probes to send to each target
8307c478bd9Sstevel@tonic-gate * IP address. npackets == 0 means send only 1 and move on to
8317c478bd9Sstevel@tonic-gate * next target IP.
8327c478bd9Sstevel@tonic-gate */
8337c478bd9Sstevel@tonic-gate if (npackets > 0)
8347c478bd9Sstevel@tonic-gate targetaddr->num_probes = npackets;
8357c478bd9Sstevel@tonic-gate else
8367c478bd9Sstevel@tonic-gate targetaddr->num_probes = 1;
8377c478bd9Sstevel@tonic-gate } else {
8387c478bd9Sstevel@tonic-gate targetaddr->num_probes = timeout;
8397c478bd9Sstevel@tonic-gate }
8407c478bd9Sstevel@tonic-gate targetaddr->num_sent = 0;
8417c478bd9Sstevel@tonic-gate targetaddr->got_reply = _B_FALSE;
8427c478bd9Sstevel@tonic-gate targetaddr->probing_done = _B_FALSE;
8437c478bd9Sstevel@tonic-gate targetaddr->starting_seq_num = 0; /* actual value will be set later */
8447c478bd9Sstevel@tonic-gate targetaddr->next = NULL; /* actual value will be set later */
8457c478bd9Sstevel@tonic-gate
8467c478bd9Sstevel@tonic-gate return (targetaddr);
8477c478bd9Sstevel@tonic-gate }
8487c478bd9Sstevel@tonic-gate
8497c478bd9Sstevel@tonic-gate /*
8507c478bd9Sstevel@tonic-gate * print "unknown host" message
8517c478bd9Sstevel@tonic-gate */
8527c478bd9Sstevel@tonic-gate static void
print_unknown_host_msg(const char * protocol,const char * hostname)8537c478bd9Sstevel@tonic-gate print_unknown_host_msg(const char *protocol, const char *hostname)
8547c478bd9Sstevel@tonic-gate {
8557c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: unknown%s host %s\n", progname, protocol,
8567c478bd9Sstevel@tonic-gate hostname);
8577c478bd9Sstevel@tonic-gate }
8587c478bd9Sstevel@tonic-gate
8597c478bd9Sstevel@tonic-gate /*
8607c478bd9Sstevel@tonic-gate * Resolve hostnames for the target host and gateways. Also, determine source
8617c478bd9Sstevel@tonic-gate * addresses to use for each target address.
8627c478bd9Sstevel@tonic-gate */
8637c478bd9Sstevel@tonic-gate static void
resolve_nodes(struct addrinfo ** ai_dstp,struct addrinfo ** ai_nexthopp,union any_in_addr ** src_addr_listp)8644c10bc16Spwernau resolve_nodes(struct addrinfo **ai_dstp, struct addrinfo **ai_nexthopp,
8654c10bc16Spwernau union any_in_addr **src_addr_listp)
8667c478bd9Sstevel@tonic-gate {
8677c478bd9Sstevel@tonic-gate struct addrinfo *ai_dst = NULL;
8684c10bc16Spwernau struct addrinfo *ai_nexthop = NULL;
8697c478bd9Sstevel@tonic-gate struct addrinfo *aip = NULL;
8707c478bd9Sstevel@tonic-gate union any_in_addr *src_addr_list = NULL;
8717c478bd9Sstevel@tonic-gate int num_resolved_gw = 0;
8727c478bd9Sstevel@tonic-gate int num_resolved_gw6 = 0;
8737c478bd9Sstevel@tonic-gate
8747c478bd9Sstevel@tonic-gate get_hostinfo(targethost, family_input, &ai_dst);
8757c478bd9Sstevel@tonic-gate if (ai_dst == NULL) {
8767c478bd9Sstevel@tonic-gate print_unknown_host_msg("", targethost);
8777c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
8787c478bd9Sstevel@tonic-gate }
8794c10bc16Spwernau if (nexthop != NULL) {
8804c10bc16Spwernau get_hostinfo(nexthop, family_input, &ai_nexthop);
8814c10bc16Spwernau if (ai_nexthop == NULL) {
8824c10bc16Spwernau print_unknown_host_msg("", nexthop);
8834c10bc16Spwernau exit(EXIT_FAILURE);
8844c10bc16Spwernau }
8854c10bc16Spwernau }
8867c478bd9Sstevel@tonic-gate /* Get a count of the v4 & v6 addresses */
8877c478bd9Sstevel@tonic-gate for (aip = ai_dst; aip != NULL; aip = aip->ai_next) {
8887c478bd9Sstevel@tonic-gate switch (aip->ai_family) {
8897c478bd9Sstevel@tonic-gate case AF_INET:
8907c478bd9Sstevel@tonic-gate num_v4++;
8917c478bd9Sstevel@tonic-gate break;
8927c478bd9Sstevel@tonic-gate case AF_INET6:
8937c478bd9Sstevel@tonic-gate num_v6++;
8947c478bd9Sstevel@tonic-gate break;
8957c478bd9Sstevel@tonic-gate }
8967c478bd9Sstevel@tonic-gate }
8977c478bd9Sstevel@tonic-gate
8987c478bd9Sstevel@tonic-gate if (family_input == AF_UNSPEC && !probe_all) {
8997c478bd9Sstevel@tonic-gate family_input = ai_dst->ai_family;
9007c478bd9Sstevel@tonic-gate }
9017c478bd9Sstevel@tonic-gate
9027c478bd9Sstevel@tonic-gate /* resolve gateways */
9037c478bd9Sstevel@tonic-gate if (num_gw > 0) {
9047c478bd9Sstevel@tonic-gate get_gwaddrs(gw_list, family_input, gw_IP_list, gw_IP_list6,
9057c478bd9Sstevel@tonic-gate &num_resolved_gw, &num_resolved_gw6);
9067c478bd9Sstevel@tonic-gate
9077c478bd9Sstevel@tonic-gate /* we couldn't resolve a gateway as an IPv6 host */
9087c478bd9Sstevel@tonic-gate if (num_resolved_gw6 != num_gw && num_v6 != 0 &&
9097c478bd9Sstevel@tonic-gate (family_input == AF_INET6 || family_input == AF_UNSPEC)) {
9107c478bd9Sstevel@tonic-gate print_unknown_host_msg(" IPv6",
9117c478bd9Sstevel@tonic-gate gw_list[num_resolved_gw6]);
9127c478bd9Sstevel@tonic-gate num_v6 = 0;
9137c478bd9Sstevel@tonic-gate }
9147c478bd9Sstevel@tonic-gate
9157c478bd9Sstevel@tonic-gate /* we couldn't resolve a gateway as an IPv4 host */
9167c478bd9Sstevel@tonic-gate if (num_resolved_gw != num_gw && num_v4 != 0 &&
9177c478bd9Sstevel@tonic-gate (family_input == AF_INET || family_input == AF_UNSPEC)) {
9187c478bd9Sstevel@tonic-gate print_unknown_host_msg(" IPv4",
9197c478bd9Sstevel@tonic-gate gw_list[num_resolved_gw]);
9207c478bd9Sstevel@tonic-gate num_v4 = 0;
9217c478bd9Sstevel@tonic-gate }
9227c478bd9Sstevel@tonic-gate }
9237c478bd9Sstevel@tonic-gate
9247c478bd9Sstevel@tonic-gate if (num_v4 == 0 && num_v6 == 0)
9257c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
9267c478bd9Sstevel@tonic-gate
9277c478bd9Sstevel@tonic-gate select_all_src_addrs(&src_addr_list, ai_dst, gw_IP_list, gw_IP_list6);
9287c478bd9Sstevel@tonic-gate *ai_dstp = ai_dst;
9294c10bc16Spwernau *ai_nexthopp = ai_nexthop;
9307c478bd9Sstevel@tonic-gate *src_addr_listp = src_addr_list;
9317c478bd9Sstevel@tonic-gate }
9327c478bd9Sstevel@tonic-gate
9337c478bd9Sstevel@tonic-gate /*
9347c478bd9Sstevel@tonic-gate * Resolve the gateway names, splitting results into v4 and v6 lists.
9357c478bd9Sstevel@tonic-gate * Gateway addresses are added to the appropriate passed-in array; the
9367c478bd9Sstevel@tonic-gate * number of resolved gateways for each af is returned in resolved[6].
9377c478bd9Sstevel@tonic-gate * Assumes that passed-in arrays are large enough for MAX_GWS[6] addrs
9387c478bd9Sstevel@tonic-gate * and resolved[6] ptrs are non-null; ignores array and counter if the
9397c478bd9Sstevel@tonic-gate * address family param makes them irrelevant.
9407c478bd9Sstevel@tonic-gate */
9417c478bd9Sstevel@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)9427c478bd9Sstevel@tonic-gate get_gwaddrs(char **gw_list, int family, union any_in_addr *gwIPlist,
9437c478bd9Sstevel@tonic-gate union any_in_addr *gwIPlist6, int *resolved, int *resolved6)
9447c478bd9Sstevel@tonic-gate {
9457c478bd9Sstevel@tonic-gate int i;
9467c478bd9Sstevel@tonic-gate boolean_t check_v4 = _B_TRUE, check_v6 = _B_TRUE;
9477c478bd9Sstevel@tonic-gate struct addrinfo *ai = NULL;
9487c478bd9Sstevel@tonic-gate struct addrinfo *aip = NULL;
9497c478bd9Sstevel@tonic-gate
9507c478bd9Sstevel@tonic-gate *resolved = *resolved6 = 0;
9517c478bd9Sstevel@tonic-gate switch (family) {
9527c478bd9Sstevel@tonic-gate case AF_UNSPEC:
9537c478bd9Sstevel@tonic-gate break;
9547c478bd9Sstevel@tonic-gate case AF_INET:
9557c478bd9Sstevel@tonic-gate check_v6 = _B_FALSE;
9567c478bd9Sstevel@tonic-gate break;
9577c478bd9Sstevel@tonic-gate case AF_INET6:
9587c478bd9Sstevel@tonic-gate check_v4 = _B_FALSE;
9597c478bd9Sstevel@tonic-gate break;
9607c478bd9Sstevel@tonic-gate default:
9617c478bd9Sstevel@tonic-gate return;
9627c478bd9Sstevel@tonic-gate }
9637c478bd9Sstevel@tonic-gate
9647c478bd9Sstevel@tonic-gate if (check_v4 && num_gw >= MAX_GWS) {
9657c478bd9Sstevel@tonic-gate check_v4 = _B_FALSE;
9667c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: too many IPv4 gateways\n", progname);
9677c478bd9Sstevel@tonic-gate }
9687c478bd9Sstevel@tonic-gate if (check_v6 && num_gw > MAX_GWS6) {
9697c478bd9Sstevel@tonic-gate check_v6 = _B_FALSE;
9707c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: too many IPv6 gateways\n", progname);
9717c478bd9Sstevel@tonic-gate }
9727c478bd9Sstevel@tonic-gate
9737c478bd9Sstevel@tonic-gate for (i = 0; i < num_gw; i++) {
9747c478bd9Sstevel@tonic-gate if (!check_v4 && !check_v6)
9757c478bd9Sstevel@tonic-gate return;
9767c478bd9Sstevel@tonic-gate get_hostinfo(gw_list[i], family, &ai);
9777c478bd9Sstevel@tonic-gate if (ai == NULL)
9787c478bd9Sstevel@tonic-gate return;
9797c478bd9Sstevel@tonic-gate if (check_v4 && num_v4 != 0) {
9807c478bd9Sstevel@tonic-gate for (aip = ai; aip != NULL; aip = aip->ai_next) {
9817c478bd9Sstevel@tonic-gate if (aip->ai_family == AF_INET) {
9827c478bd9Sstevel@tonic-gate /* LINTED E_BAD_PTR_CAST_ALIGN */
9837c478bd9Sstevel@tonic-gate bcopy(&((struct sockaddr_in *)
9847c478bd9Sstevel@tonic-gate aip->ai_addr)->sin_addr,
9857c478bd9Sstevel@tonic-gate &gwIPlist[i].addr,
9867c478bd9Sstevel@tonic-gate aip->ai_addrlen);
9877c478bd9Sstevel@tonic-gate (*resolved)++;
9887c478bd9Sstevel@tonic-gate break;
9897c478bd9Sstevel@tonic-gate }
9907c478bd9Sstevel@tonic-gate }
9917c478bd9Sstevel@tonic-gate } else if (check_v4) {
9927c478bd9Sstevel@tonic-gate check_v4 = _B_FALSE;
9937c478bd9Sstevel@tonic-gate }
9947c478bd9Sstevel@tonic-gate if (check_v6 && num_v6 != 0) {
9957c478bd9Sstevel@tonic-gate for (aip = ai; aip != NULL; aip = aip->ai_next) {
9967c478bd9Sstevel@tonic-gate if (aip->ai_family == AF_INET6) {
9977c478bd9Sstevel@tonic-gate /* LINTED E_BAD_PTR_CAST_ALIGN */
9987c478bd9Sstevel@tonic-gate bcopy(&((struct sockaddr_in6 *)
9997c478bd9Sstevel@tonic-gate aip->ai_addr)->sin6_addr,
10007c478bd9Sstevel@tonic-gate &gwIPlist6[i].addr6,
10017c478bd9Sstevel@tonic-gate aip->ai_addrlen);
10027c478bd9Sstevel@tonic-gate (*resolved6)++;
10037c478bd9Sstevel@tonic-gate break;
10047c478bd9Sstevel@tonic-gate }
10057c478bd9Sstevel@tonic-gate }
10067c478bd9Sstevel@tonic-gate } else if (check_v6) {
10077c478bd9Sstevel@tonic-gate check_v6 = _B_FALSE;
10087c478bd9Sstevel@tonic-gate }
10097c478bd9Sstevel@tonic-gate }
10107c478bd9Sstevel@tonic-gate freeaddrinfo(ai);
10117c478bd9Sstevel@tonic-gate }
10127c478bd9Sstevel@tonic-gate
10137c478bd9Sstevel@tonic-gate /*
10147c478bd9Sstevel@tonic-gate * Given the list of gateways, extends the list with its mirror image. This is
10157c478bd9Sstevel@tonic-gate * used when -l/-S is used. The middle gateway will be the target address. We'll
10167c478bd9Sstevel@tonic-gate * leave it blank for now.
10177c478bd9Sstevel@tonic-gate */
10187c478bd9Sstevel@tonic-gate static void
mirror_gws(union any_in_addr * gwIPlist,int family)10197c478bd9Sstevel@tonic-gate mirror_gws(union any_in_addr *gwIPlist, int family)
10207c478bd9Sstevel@tonic-gate {
10217c478bd9Sstevel@tonic-gate int effective_num_gw;
10227c478bd9Sstevel@tonic-gate int i;
10237c478bd9Sstevel@tonic-gate
10247c478bd9Sstevel@tonic-gate /* We add 1 because we put the target as the middle gateway */
10257c478bd9Sstevel@tonic-gate effective_num_gw = 2 * num_gw + 1;
10267c478bd9Sstevel@tonic-gate
10277c478bd9Sstevel@tonic-gate if ((family == AF_INET && effective_num_gw >= MAX_GWS) ||
10287c478bd9Sstevel@tonic-gate (family == AF_INET6 && effective_num_gw > MAX_GWS6)) {
10297c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: too many %s gateways\n",
10307c478bd9Sstevel@tonic-gate progname, (family == AF_INET) ? "IPv4" : "IPv6");
10317c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
10327c478bd9Sstevel@tonic-gate }
10337c478bd9Sstevel@tonic-gate
10347c478bd9Sstevel@tonic-gate for (i = 0; i < num_gw; i++)
10357c478bd9Sstevel@tonic-gate gwIPlist[num_gw + i + 1].addr6 = gwIPlist[num_gw - i - 1].addr6;
10367c478bd9Sstevel@tonic-gate }
10377c478bd9Sstevel@tonic-gate
10387c478bd9Sstevel@tonic-gate /*
10397c478bd9Sstevel@tonic-gate * Given IP address or hostname, return addrinfo list.
10407c478bd9Sstevel@tonic-gate * Assumes that addrinfo ** ptr is non-null.
10417c478bd9Sstevel@tonic-gate */
10427c478bd9Sstevel@tonic-gate static void
get_hostinfo(char * host,int family,struct addrinfo ** aipp)10437c478bd9Sstevel@tonic-gate get_hostinfo(char *host, int family, struct addrinfo **aipp)
10447c478bd9Sstevel@tonic-gate {
10457c478bd9Sstevel@tonic-gate struct addrinfo hints, *ai;
10467c478bd9Sstevel@tonic-gate struct in6_addr addr6;
10477c478bd9Sstevel@tonic-gate struct in_addr addr;
10487c478bd9Sstevel@tonic-gate boolean_t broadcast; /* is this 255.255.255.255? */
10497c478bd9Sstevel@tonic-gate char tmp_buf[INET6_ADDRSTRLEN];
10507c478bd9Sstevel@tonic-gate int rc;
10517c478bd9Sstevel@tonic-gate
10527c478bd9Sstevel@tonic-gate /* check if broadcast */
10537c478bd9Sstevel@tonic-gate if (strcmp(host, "255.255.255.255") == 0)
10547c478bd9Sstevel@tonic-gate broadcast = _B_TRUE;
10557c478bd9Sstevel@tonic-gate else
10567c478bd9Sstevel@tonic-gate broadcast = _B_FALSE;
10577c478bd9Sstevel@tonic-gate
10587c478bd9Sstevel@tonic-gate /* check if IPv4-mapped address or broadcast */
10597c478bd9Sstevel@tonic-gate if (((inet_pton(AF_INET6, host, &addr6) > 0) &&
10607c478bd9Sstevel@tonic-gate IN6_IS_ADDR_V4MAPPED(&addr6)) || broadcast) {
10617c478bd9Sstevel@tonic-gate if (!broadcast) {
10627c478bd9Sstevel@tonic-gate /*
10637c478bd9Sstevel@tonic-gate * Peel off the "mapping" stuff, leaving 32 bit IPv4
10647c478bd9Sstevel@tonic-gate * address.
10657c478bd9Sstevel@tonic-gate */
10667c478bd9Sstevel@tonic-gate IN6_V4MAPPED_TO_INADDR(&addr6, &addr);
10677c478bd9Sstevel@tonic-gate
10687c478bd9Sstevel@tonic-gate /* convert it back to a string */
10697c478bd9Sstevel@tonic-gate (void) inet_ntop(AF_INET, (void *)&addr, tmp_buf,
10707c478bd9Sstevel@tonic-gate sizeof (tmp_buf));
10717c478bd9Sstevel@tonic-gate /*
10727c478bd9Sstevel@tonic-gate * Now the host is an IPv4 address.
10737c478bd9Sstevel@tonic-gate * Since it previously was a v4 mapped v6 address
10747c478bd9Sstevel@tonic-gate * we can be sure that the size of buffer 'host'
10757c478bd9Sstevel@tonic-gate * is large enough to contain the associated v4
10767c478bd9Sstevel@tonic-gate * address and so we don't need to use a strn/lcpy
10777c478bd9Sstevel@tonic-gate * here.
10787c478bd9Sstevel@tonic-gate */
10797c478bd9Sstevel@tonic-gate (void) strcpy(host, tmp_buf);
10807c478bd9Sstevel@tonic-gate }
10817c478bd9Sstevel@tonic-gate /*
10827c478bd9Sstevel@tonic-gate * If it's a broadcast address, it cannot be an IPv6 address.
10837c478bd9Sstevel@tonic-gate * Also, if it's a mapped address, we convert it into IPv4
10847c478bd9Sstevel@tonic-gate * address because ping will send and receive IPv4 packets for
10857c478bd9Sstevel@tonic-gate * that address. Therefore, it's a failure case to ask
10867c478bd9Sstevel@tonic-gate * get_hostinfo() to treat a broadcast or a mapped address
10877c478bd9Sstevel@tonic-gate * as an IPv6 address.
10887c478bd9Sstevel@tonic-gate */
10897c478bd9Sstevel@tonic-gate if (family == AF_INET6) {
10907c478bd9Sstevel@tonic-gate return;
10917c478bd9Sstevel@tonic-gate }
10927c478bd9Sstevel@tonic-gate }
10937c478bd9Sstevel@tonic-gate
10947c478bd9Sstevel@tonic-gate (void) memset(&hints, 0, sizeof (hints));
10957c478bd9Sstevel@tonic-gate hints.ai_family = family;
10967c478bd9Sstevel@tonic-gate hints.ai_flags = AI_ADDRCONFIG;
10977c478bd9Sstevel@tonic-gate rc = getaddrinfo(host, NULL, &hints, &ai);
10987c478bd9Sstevel@tonic-gate if (rc != 0) {
10997c478bd9Sstevel@tonic-gate if (rc != EAI_NONAME)
11007c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: getaddrinfo: %s\n", progname,
11017c478bd9Sstevel@tonic-gate gai_strerror(rc));
11027c478bd9Sstevel@tonic-gate return;
11037c478bd9Sstevel@tonic-gate }
11047c478bd9Sstevel@tonic-gate *aipp = ai;
11057c478bd9Sstevel@tonic-gate }
11067c478bd9Sstevel@tonic-gate
11077c478bd9Sstevel@tonic-gate /*
11087c478bd9Sstevel@tonic-gate * For each IP address of the target host, determine a source address to use.
11097c478bd9Sstevel@tonic-gate */
11107c478bd9Sstevel@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)11117c478bd9Sstevel@tonic-gate select_all_src_addrs(union any_in_addr **src_addr_list, struct addrinfo *ai,
11127c478bd9Sstevel@tonic-gate union any_in_addr *gwv4, union any_in_addr *gwv6)
11137c478bd9Sstevel@tonic-gate {
11147c478bd9Sstevel@tonic-gate union any_in_addr *list;
11157c478bd9Sstevel@tonic-gate struct addrinfo *aip;
11167c478bd9Sstevel@tonic-gate int num_dst = 1;
11177c478bd9Sstevel@tonic-gate int i;
11187c478bd9Sstevel@tonic-gate
1119e11c3f44Smeem if (probe_all) {
1120e11c3f44Smeem for (aip = ai; aip->ai_next != NULL; aip = aip->ai_next)
1121e11c3f44Smeem num_dst++;
1122e11c3f44Smeem }
11237c478bd9Sstevel@tonic-gate
1124e11c3f44Smeem list = calloc((size_t)num_dst, sizeof (union any_in_addr));
11257c478bd9Sstevel@tonic-gate if (list == NULL) {
11267c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: calloc: %s\n", progname, strerror(errno));
11277c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
11287c478bd9Sstevel@tonic-gate }
11297c478bd9Sstevel@tonic-gate
11307c478bd9Sstevel@tonic-gate /*
11317c478bd9Sstevel@tonic-gate * If there's a gateway, a routing header as a consequence, our kernel
11327c478bd9Sstevel@tonic-gate * picks the source address based on the first hop address, rather than
11337c478bd9Sstevel@tonic-gate * final destination address.
11347c478bd9Sstevel@tonic-gate */
11357c478bd9Sstevel@tonic-gate if (num_gw > 0) {
11367c478bd9Sstevel@tonic-gate if (ai->ai_family == AF_INET)
11377c478bd9Sstevel@tonic-gate select_src_addr(gwv4, ai->ai_family, &list[0]);
11387c478bd9Sstevel@tonic-gate else
11397c478bd9Sstevel@tonic-gate select_src_addr(gwv6, ai->ai_family, &list[0]);
11407c478bd9Sstevel@tonic-gate /*
11417c478bd9Sstevel@tonic-gate * Since the first gateway address is fixed, we'll use the same
11427c478bd9Sstevel@tonic-gate * src address for every different final destination address
11437c478bd9Sstevel@tonic-gate * we send to.
11447c478bd9Sstevel@tonic-gate */
11457c478bd9Sstevel@tonic-gate for (i = 1; i < num_dst; i++)
11467c478bd9Sstevel@tonic-gate list[i] = list[0];
11477c478bd9Sstevel@tonic-gate } else {
11487c478bd9Sstevel@tonic-gate /*
11497c478bd9Sstevel@tonic-gate * Although something like 'ping -l host' results in a routing
11507c478bd9Sstevel@tonic-gate * header, the first gateway address is the target host's
11517c478bd9Sstevel@tonic-gate * address. Therefore, as far as src address selection goes,
11527c478bd9Sstevel@tonic-gate * the result is same as having no routing header.
11537c478bd9Sstevel@tonic-gate */
11547c478bd9Sstevel@tonic-gate for (i = 0, aip = ai; i < num_dst && aip != NULL;
11557c478bd9Sstevel@tonic-gate i++, aip = aip->ai_next) {
11567c478bd9Sstevel@tonic-gate if (aip->ai_family == AF_INET) {
11577c478bd9Sstevel@tonic-gate if (num_v4 != 0) {
11587c478bd9Sstevel@tonic-gate select_src_addr((union any_in_addr *)
11597c478bd9Sstevel@tonic-gate /* LINTED E_BAD_PTR_CAST_ALIGN */
11607c478bd9Sstevel@tonic-gate &((struct sockaddr_in *)
11617c478bd9Sstevel@tonic-gate aip->ai_addr)->sin_addr,
11627c478bd9Sstevel@tonic-gate aip->ai_family,
11637c478bd9Sstevel@tonic-gate &list[i]);
11647c478bd9Sstevel@tonic-gate }
11657c478bd9Sstevel@tonic-gate } else {
11667c478bd9Sstevel@tonic-gate if (num_v6 != 0) {
11677c478bd9Sstevel@tonic-gate select_src_addr((union any_in_addr *)
11687c478bd9Sstevel@tonic-gate /* LINTED E_BAD_PTR_CAST_ALIGN */
11697c478bd9Sstevel@tonic-gate &((struct sockaddr_in6 *)
11707c478bd9Sstevel@tonic-gate aip->ai_addr)->sin6_addr,
11717c478bd9Sstevel@tonic-gate aip->ai_family,
11727c478bd9Sstevel@tonic-gate &list[i]);
11737c478bd9Sstevel@tonic-gate }
11747c478bd9Sstevel@tonic-gate }
11757c478bd9Sstevel@tonic-gate }
11767c478bd9Sstevel@tonic-gate }
11777c478bd9Sstevel@tonic-gate
11787c478bd9Sstevel@tonic-gate *src_addr_list = list;
11797c478bd9Sstevel@tonic-gate }
11807c478bd9Sstevel@tonic-gate
11817c478bd9Sstevel@tonic-gate /*
11827c478bd9Sstevel@tonic-gate * For a given destination address, determine a source address to use.
11837c478bd9Sstevel@tonic-gate * Returns wildcard address if it cannot determine the source address.
11847c478bd9Sstevel@tonic-gate */
11857c478bd9Sstevel@tonic-gate static void
select_src_addr(union any_in_addr * dst_addr,int family,union any_in_addr * src_addr)11867c478bd9Sstevel@tonic-gate select_src_addr(union any_in_addr *dst_addr, int family,
11877c478bd9Sstevel@tonic-gate union any_in_addr *src_addr)
11887c478bd9Sstevel@tonic-gate {
11897c478bd9Sstevel@tonic-gate struct sockaddr *sock;
1190b08923d6SRobert Mustacchi struct sockaddr_in *sin = NULL;
1191b08923d6SRobert Mustacchi struct sockaddr_in6 *sin6 = NULL;
11927c478bd9Sstevel@tonic-gate int tmp_fd;
11937c478bd9Sstevel@tonic-gate size_t sock_len;
11947c478bd9Sstevel@tonic-gate
11957c478bd9Sstevel@tonic-gate sock = (struct sockaddr *)malloc(sizeof (struct sockaddr_in6));
11967c478bd9Sstevel@tonic-gate if (sock == NULL) {
11977c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: malloc: %s\n", progname, strerror(errno));
11987c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
11997c478bd9Sstevel@tonic-gate }
12007c478bd9Sstevel@tonic-gate (void) bzero(sock, sizeof (struct sockaddr_in6));
12017c478bd9Sstevel@tonic-gate
12027c478bd9Sstevel@tonic-gate if (family == AF_INET) {
12037c478bd9Sstevel@tonic-gate /* LINTED E_BAD_PTR_CAST_ALIGN */
12047c478bd9Sstevel@tonic-gate sin = (struct sockaddr_in *)sock;
12057c478bd9Sstevel@tonic-gate sin->sin_family = AF_INET;
12067c478bd9Sstevel@tonic-gate sin->sin_addr = dst_addr->addr;
12077c478bd9Sstevel@tonic-gate sin->sin_port = IPPORT_ECHO; /* port shouldn't be 0 */
12087c478bd9Sstevel@tonic-gate sock_len = sizeof (struct sockaddr_in);
12097c478bd9Sstevel@tonic-gate } else {
12107c478bd9Sstevel@tonic-gate /* LINTED E_BAD_PTR_CAST_ALIGN */
12117c478bd9Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)sock;
12127c478bd9Sstevel@tonic-gate sin6->sin6_family = AF_INET6;
12137c478bd9Sstevel@tonic-gate sin6->sin6_addr = dst_addr->addr6;
12147c478bd9Sstevel@tonic-gate sin6->sin6_port = IPPORT_ECHO; /* port shouldn't be 0 */
12157c478bd9Sstevel@tonic-gate sock_len = sizeof (struct sockaddr_in6);
12167c478bd9Sstevel@tonic-gate }
12177c478bd9Sstevel@tonic-gate
12187c478bd9Sstevel@tonic-gate /* open a UDP socket */
12197c478bd9Sstevel@tonic-gate if ((tmp_fd = socket(family, SOCK_DGRAM, 0)) < 0) {
12207c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: udp socket: %s\n", progname,
12217c478bd9Sstevel@tonic-gate strerror(errno));
12227c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
12237c478bd9Sstevel@tonic-gate }
12247c478bd9Sstevel@tonic-gate
12257c478bd9Sstevel@tonic-gate /* connect it */
12267c478bd9Sstevel@tonic-gate if (connect(tmp_fd, sock, sock_len) < 0) {
12277c478bd9Sstevel@tonic-gate /*
12287c478bd9Sstevel@tonic-gate * If there's no route to the destination, this connect() call
12297c478bd9Sstevel@tonic-gate * fails. We just return all-zero (wildcard) as the source
12307c478bd9Sstevel@tonic-gate * address, so that user can get to see "no route to dest"
12317c478bd9Sstevel@tonic-gate * message, as it'll try to send the probe packet out and will
12327c478bd9Sstevel@tonic-gate * receive ICMP unreachable.
12337c478bd9Sstevel@tonic-gate */
12347c478bd9Sstevel@tonic-gate if (family == AF_INET)
12357c478bd9Sstevel@tonic-gate src_addr->addr.s_addr = INADDR_ANY;
12367c478bd9Sstevel@tonic-gate else
12377c478bd9Sstevel@tonic-gate src_addr->addr6 = in6addr_any;
12387c478bd9Sstevel@tonic-gate free(sock);
12397c478bd9Sstevel@tonic-gate return;
12407c478bd9Sstevel@tonic-gate }
12417c478bd9Sstevel@tonic-gate
12427c478bd9Sstevel@tonic-gate /* get the local sock info */
12437c478bd9Sstevel@tonic-gate if (getsockname(tmp_fd, sock, &sock_len) < 0) {
12447c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: getsockname: %s\n", progname,
12457c478bd9Sstevel@tonic-gate strerror(errno));
12467c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
12477c478bd9Sstevel@tonic-gate }
12487c478bd9Sstevel@tonic-gate
12497c478bd9Sstevel@tonic-gate if (family == AF_INET) {
1250b08923d6SRobert Mustacchi assert(sin != NULL);
12517c478bd9Sstevel@tonic-gate src_addr->addr = sin->sin_addr;
12527c478bd9Sstevel@tonic-gate } else {
1253b08923d6SRobert Mustacchi assert(sin6 != NULL);
12547c478bd9Sstevel@tonic-gate src_addr->addr6 = sin6->sin6_addr;
12557c478bd9Sstevel@tonic-gate }
12567c478bd9Sstevel@tonic-gate
12577c478bd9Sstevel@tonic-gate (void) close(tmp_fd);
12587c478bd9Sstevel@tonic-gate free(sock);
12597c478bd9Sstevel@tonic-gate }
12607c478bd9Sstevel@tonic-gate
12614c10bc16Spwernau /*
12624c10bc16Spwernau * Set the IP_NEXTHOP/IPV6_NEXTHOP socket option.
12634c10bc16Spwernau * exits on failure
12644c10bc16Spwernau */
12654c10bc16Spwernau static void
set_nexthop(int family,struct addrinfo * ai_nexthop,int sock)12664c10bc16Spwernau set_nexthop(int family, struct addrinfo *ai_nexthop, int sock)
12674c10bc16Spwernau {
12684c10bc16Spwernau if (family == AF_INET) {
12694c10bc16Spwernau ipaddr_t nh;
12704c10bc16Spwernau
12714c10bc16Spwernau /* LINTED E_BAD_PTR_CAST_ALIGN */
12724c10bc16Spwernau nh = ((struct sockaddr_in *)ai_nexthop->
12734c10bc16Spwernau ai_addr)->sin_addr.s_addr;
12744c10bc16Spwernau
1275f4b3ec61Sdh /* now we need the sys_ip_config privilege */
12764c10bc16Spwernau (void) __priv_bracket(PRIV_ON);
12774c10bc16Spwernau if (setsockopt(sock, IPPROTO_IP, IP_NEXTHOP,
12784c10bc16Spwernau &nh, sizeof (ipaddr_t)) < 0) {
12791da45818Spwernau if (errno == EPERM)
12801da45818Spwernau Fprintf(stderr, "%s: Insufficient privilege "
12811da45818Spwernau "to specify IPv4 nexthop router.\n",
12821da45818Spwernau progname);
12831da45818Spwernau else
12841da45818Spwernau Fprintf(stderr, "%s: setsockopt %s\n",
12851da45818Spwernau progname, strerror(errno));
12864c10bc16Spwernau exit(EXIT_FAILURE);
12874c10bc16Spwernau }
12884c10bc16Spwernau (void) __priv_bracket(PRIV_OFF);
12894c10bc16Spwernau /* revert to non-privileged user */
12904c10bc16Spwernau } else {
12914c10bc16Spwernau struct sockaddr_in6 *nh;
12924c10bc16Spwernau
12934c10bc16Spwernau /* LINTED E_BAD_PTR_CAST_ALIGN */
12944c10bc16Spwernau nh = (struct sockaddr_in6 *)ai_nexthop->
12954c10bc16Spwernau ai_addr;
12964c10bc16Spwernau
12974c10bc16Spwernau if (setsockopt(sock, IPPROTO_IPV6, IPV6_NEXTHOP,
12984c10bc16Spwernau nh, sizeof (struct sockaddr_in6)) < 0) {
12994c10bc16Spwernau Fprintf(stderr, "%s: setsockopt %s\n",
13004c10bc16Spwernau progname, strerror(errno));
13014c10bc16Spwernau exit(EXIT_FAILURE);
13024c10bc16Spwernau }
13034c10bc16Spwernau }
13044c10bc16Spwernau }
13054c10bc16Spwernau
13067c478bd9Sstevel@tonic-gate /*
13077c478bd9Sstevel@tonic-gate * Setup the socket for the given address family.
13087c478bd9Sstevel@tonic-gate * Returns _B_TRUE on success, _B_FALSE on failure. Failure is the case when no
13097c478bd9Sstevel@tonic-gate * interface can be found, or the specified interface (-i) is not found. On
13107c478bd9Sstevel@tonic-gate * library call failures, it exit()s.
13117c478bd9Sstevel@tonic-gate */
13127c478bd9Sstevel@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)13137c478bd9Sstevel@tonic-gate setup_socket(int family, int *send_sockp, int *recv_sockp, int *if_index,
13144c10bc16Spwernau ushort_t *udp_src_port, struct addrinfo *ai_nexthop)
13157c478bd9Sstevel@tonic-gate {
13167c478bd9Sstevel@tonic-gate int send_sock;
13177c478bd9Sstevel@tonic-gate int recv_sock;
13187c478bd9Sstevel@tonic-gate struct sockaddr_in6 sin6;
13197c478bd9Sstevel@tonic-gate struct sockaddr_in sin;
13207c478bd9Sstevel@tonic-gate struct sockaddr *sp;
1321a356273cSpwernau struct ipsec_req req;
13227c478bd9Sstevel@tonic-gate size_t slen;
13237c478bd9Sstevel@tonic-gate int on = 1;
13247c478bd9Sstevel@tonic-gate uchar_t char_op;
13257c478bd9Sstevel@tonic-gate int int_op;
13267c478bd9Sstevel@tonic-gate
13277c478bd9Sstevel@tonic-gate /* now we need the net_icmpaccess privilege */
13287c478bd9Sstevel@tonic-gate (void) __priv_bracket(PRIV_ON);
13297c478bd9Sstevel@tonic-gate
13307c478bd9Sstevel@tonic-gate recv_sock = socket(family, SOCK_RAW,
13317c478bd9Sstevel@tonic-gate (family == AF_INET) ? IPPROTO_ICMP : IPPROTO_ICMPV6);
13327c478bd9Sstevel@tonic-gate
13337c478bd9Sstevel@tonic-gate if (recv_sock < 0) {
13347c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: socket %s\n", progname, strerror(errno));
13357c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
13367c478bd9Sstevel@tonic-gate }
13377c478bd9Sstevel@tonic-gate
13387c478bd9Sstevel@tonic-gate /* revert to non-privileged user after opening sockets */
13397c478bd9Sstevel@tonic-gate (void) __priv_bracket(PRIV_OFF);
13407c478bd9Sstevel@tonic-gate
1341a356273cSpwernau if (bypass) {
1342a356273cSpwernau (void) memset(&req, 0, sizeof (req));
1343a356273cSpwernau req.ipsr_ah_req = IPSEC_PREF_NEVER;
1344a356273cSpwernau req.ipsr_esp_req = IPSEC_PREF_NEVER;
1345a356273cSpwernau
1346a356273cSpwernau if (setsockopt(recv_sock, (family == AF_INET) ? IPPROTO_IP :
1347a356273cSpwernau IPPROTO_IPV6, IP_SEC_OPT, &req, sizeof (req)) < 0) {
13485086f56fSPaul Wernau switch (errno) {
13495086f56fSPaul Wernau case EPROTONOSUPPORT:
13505086f56fSPaul Wernau /*
13515086f56fSPaul Wernau * No IPsec subsystem or policy loaded.
13525086f56fSPaul Wernau * Bypass implicitly allowed.
13535086f56fSPaul Wernau */
13545086f56fSPaul Wernau break;
13555086f56fSPaul Wernau case EPERM:
1356a356273cSpwernau Fprintf(stderr, "%s: Insufficient privilege "
1357a356273cSpwernau "to bypass IPsec policy.\n", progname);
13585086f56fSPaul Wernau exit(EXIT_FAILURE);
13595086f56fSPaul Wernau break;
13605086f56fSPaul Wernau default:
1361a356273cSpwernau Fprintf(stderr, "%s: setsockopt %s\n", progname,
1362a356273cSpwernau strerror(errno));
13635086f56fSPaul Wernau exit(EXIT_FAILURE);
13645086f56fSPaul Wernau break;
13655086f56fSPaul Wernau }
1366a356273cSpwernau }
1367a356273cSpwernau }
1368a356273cSpwernau
13697c478bd9Sstevel@tonic-gate /*
13707c478bd9Sstevel@tonic-gate * We always receive on raw icmp socket. But the sending socket can be
13717c478bd9Sstevel@tonic-gate * raw icmp or udp, depending on the use of -U flag.
13727c478bd9Sstevel@tonic-gate */
13737c478bd9Sstevel@tonic-gate if (use_udp) {
13747c478bd9Sstevel@tonic-gate send_sock = socket(family, SOCK_DGRAM, IPPROTO_UDP);
13757c478bd9Sstevel@tonic-gate if (send_sock < 0) {
13767c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: socket %s\n", progname,
13777c478bd9Sstevel@tonic-gate strerror(errno));
13787c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
13797c478bd9Sstevel@tonic-gate }
13807c478bd9Sstevel@tonic-gate
1381a356273cSpwernau if (bypass) {
1382a356273cSpwernau if (setsockopt(send_sock, (family == AF_INET) ?
1383a356273cSpwernau IPPROTO_IP : IPPROTO_IPV6, IP_SEC_OPT, &req,
1384a356273cSpwernau sizeof (req)) < 0) {
13855086f56fSPaul Wernau switch (errno) {
13865086f56fSPaul Wernau case EPROTONOSUPPORT:
13875086f56fSPaul Wernau /*
13885086f56fSPaul Wernau * No IPsec subsystem or policy loaded.
13895086f56fSPaul Wernau * Bypass implicitly allowed.
13905086f56fSPaul Wernau */
13915086f56fSPaul Wernau break;
13925086f56fSPaul Wernau case EPERM:
1393a356273cSpwernau Fprintf(stderr, "%s: Insufficient "
1394a356273cSpwernau "privilege to bypass IPsec "
1395a356273cSpwernau "policy.\n", progname);
13965086f56fSPaul Wernau exit(EXIT_FAILURE);
13975086f56fSPaul Wernau break;
13985086f56fSPaul Wernau default:
1399a356273cSpwernau Fprintf(stderr, "%s: setsockopt %s\n",
1400a356273cSpwernau progname, strerror(errno));
14015086f56fSPaul Wernau exit(EXIT_FAILURE);
14025086f56fSPaul Wernau break;
14035086f56fSPaul Wernau }
1404a356273cSpwernau }
1405a356273cSpwernau }
1406a356273cSpwernau
14077c478bd9Sstevel@tonic-gate /*
14087c478bd9Sstevel@tonic-gate * In order to distinguish replies to our UDP probes from
14097c478bd9Sstevel@tonic-gate * other pings', we need to know our source port number.
14107c478bd9Sstevel@tonic-gate */
14117c478bd9Sstevel@tonic-gate if (family == AF_INET) {
14127c478bd9Sstevel@tonic-gate sp = (struct sockaddr *)&sin;
14137c478bd9Sstevel@tonic-gate slen = sizeof (sin);
14147c478bd9Sstevel@tonic-gate } else {
14157c478bd9Sstevel@tonic-gate sp = (struct sockaddr *)&sin6;
14167c478bd9Sstevel@tonic-gate slen = sizeof (sin6);
14177c478bd9Sstevel@tonic-gate }
14187c478bd9Sstevel@tonic-gate bzero(sp, slen);
14197c478bd9Sstevel@tonic-gate sp->sa_family = family;
14207c478bd9Sstevel@tonic-gate
14217c478bd9Sstevel@tonic-gate /* Let's bind() send_sock to wildcard address and port */
14227c478bd9Sstevel@tonic-gate if (bind(send_sock, sp, slen) < 0) {
14237c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: bind %s\n", progname,
14247c478bd9Sstevel@tonic-gate strerror(errno));
14257c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
14267c478bd9Sstevel@tonic-gate }
14277c478bd9Sstevel@tonic-gate
14287c478bd9Sstevel@tonic-gate /* .... and see what port kernel picked for us */
14297c478bd9Sstevel@tonic-gate if (getsockname(send_sock, sp, &slen) < 0) {
14307c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: getsockname %s\n", progname,
14317c478bd9Sstevel@tonic-gate strerror(errno));
14327c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
14337c478bd9Sstevel@tonic-gate }
14347c478bd9Sstevel@tonic-gate *udp_src_port = (family == AF_INET) ? sin.sin_port :
14357c478bd9Sstevel@tonic-gate sin6.sin6_port;
14367c478bd9Sstevel@tonic-gate } else {
14377c478bd9Sstevel@tonic-gate send_sock = recv_sock;
14387c478bd9Sstevel@tonic-gate }
14397c478bd9Sstevel@tonic-gate
1440bd670b35SErik Nordmark if (nexthop != NULL)
1441bd670b35SErik Nordmark set_nexthop(family, ai_nexthop, send_sock);
1442bd670b35SErik Nordmark
14437c478bd9Sstevel@tonic-gate int_op = 48 * 1024;
14447c478bd9Sstevel@tonic-gate if (int_op < datalen)
14457c478bd9Sstevel@tonic-gate int_op = datalen;
14467c478bd9Sstevel@tonic-gate if (setsockopt(recv_sock, SOL_SOCKET, SO_RCVBUF, (char *)&int_op,
14477c478bd9Sstevel@tonic-gate sizeof (int_op)) == -1) {
14487c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: setsockopt SO_RCVBUF %s\n", progname,
14497c478bd9Sstevel@tonic-gate strerror(errno));
14507c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
14517c478bd9Sstevel@tonic-gate }
14527c478bd9Sstevel@tonic-gate
14537c478bd9Sstevel@tonic-gate if (setsockopt(send_sock, SOL_SOCKET, SO_SNDBUF, (char *)&int_op,
14547c478bd9Sstevel@tonic-gate sizeof (int_op)) == -1) {
14557c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: setsockopt SO_SNDBUF %s\n", progname,
14567c478bd9Sstevel@tonic-gate strerror(errno));
14577c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
14587c478bd9Sstevel@tonic-gate }
14597c478bd9Sstevel@tonic-gate
14607c478bd9Sstevel@tonic-gate if (options & SO_DEBUG) {
14617c478bd9Sstevel@tonic-gate if (setsockopt(send_sock, SOL_SOCKET, SO_DEBUG, (char *)&on,
14627c478bd9Sstevel@tonic-gate sizeof (on)) == -1) {
14637c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: setsockopt SO_DEBUG %s\n",
14647c478bd9Sstevel@tonic-gate progname, strerror(errno));
14657c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
14667c478bd9Sstevel@tonic-gate }
14677c478bd9Sstevel@tonic-gate }
14687c478bd9Sstevel@tonic-gate
14697c478bd9Sstevel@tonic-gate if (options & SO_DONTROUTE) {
14707c478bd9Sstevel@tonic-gate if (setsockopt(send_sock, SOL_SOCKET, SO_DONTROUTE, (char *)&on,
14717c478bd9Sstevel@tonic-gate sizeof (on)) == -1) {
14727c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: setsockopt SO_DONTROUTE %s\n",
14737c478bd9Sstevel@tonic-gate progname, strerror(errno));
14747c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
14757c478bd9Sstevel@tonic-gate }
14767c478bd9Sstevel@tonic-gate }
14777c478bd9Sstevel@tonic-gate
14787c478bd9Sstevel@tonic-gate if (moptions & MULTICAST_NOLOOP) {
14797c478bd9Sstevel@tonic-gate if (family == AF_INET) {
14807c478bd9Sstevel@tonic-gate char_op = 0; /* used to turn off option */
14817c478bd9Sstevel@tonic-gate
14827c478bd9Sstevel@tonic-gate if (setsockopt(send_sock, IPPROTO_IP, IP_MULTICAST_LOOP,
14837c478bd9Sstevel@tonic-gate (char *)&char_op, sizeof (char_op)) == -1) {
14847c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: setsockopt "
14857c478bd9Sstevel@tonic-gate "IP_MULTICAST_NOLOOP %s\n", progname,
14867c478bd9Sstevel@tonic-gate strerror(errno));
14877c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
14887c478bd9Sstevel@tonic-gate }
14897c478bd9Sstevel@tonic-gate } else {
14907c478bd9Sstevel@tonic-gate int_op = 0; /* used to turn off option */
14917c478bd9Sstevel@tonic-gate
14927c478bd9Sstevel@tonic-gate if (setsockopt(send_sock, IPPROTO_IPV6,
14937c478bd9Sstevel@tonic-gate IPV6_MULTICAST_LOOP, (char *)&int_op,
14947c478bd9Sstevel@tonic-gate sizeof (int_op)) == -1) {
14957c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: setsockopt "
14967c478bd9Sstevel@tonic-gate "IPV6_MULTICAST_NOLOOP %s\n", progname,
14977c478bd9Sstevel@tonic-gate strerror(errno));
14987c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
14997c478bd9Sstevel@tonic-gate }
15007c478bd9Sstevel@tonic-gate }
15017c478bd9Sstevel@tonic-gate }
15027c478bd9Sstevel@tonic-gate
15037c478bd9Sstevel@tonic-gate if (moptions & MULTICAST_TTL) {
15047c478bd9Sstevel@tonic-gate char_op = hoplimit;
15057c478bd9Sstevel@tonic-gate
1506bd670b35SErik Nordmark /* Applies to unicast and multicast. */
15077c478bd9Sstevel@tonic-gate if (family == AF_INET) {
15087c478bd9Sstevel@tonic-gate if (setsockopt(send_sock, IPPROTO_IP, IP_MULTICAST_TTL,
15097c478bd9Sstevel@tonic-gate (char *)&char_op, sizeof (char)) == -1) {
15107c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: setsockopt "
15117c478bd9Sstevel@tonic-gate "IP_MULTICAST_TTL %s\n", progname,
15127c478bd9Sstevel@tonic-gate strerror(errno));
15137c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
15147c478bd9Sstevel@tonic-gate }
15157c478bd9Sstevel@tonic-gate if (setsockopt(send_sock, IPPROTO_IP, IP_TTL,
15167c478bd9Sstevel@tonic-gate (char *)&hoplimit, sizeof (hoplimit)) == -1) {
15177c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: setsockopt IP_TTL %s\n",
15187c478bd9Sstevel@tonic-gate progname, strerror(errno));
15197c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
15207c478bd9Sstevel@tonic-gate }
15217c478bd9Sstevel@tonic-gate }
15227c478bd9Sstevel@tonic-gate /*
15237c478bd9Sstevel@tonic-gate * AF_INET6 case is handled in set_ancillary_data() function.
15247c478bd9Sstevel@tonic-gate * This is because when ancillary data is used (for routing
15257c478bd9Sstevel@tonic-gate * header and outgoing interface index), the hoplimit set using
15267c478bd9Sstevel@tonic-gate * setsockopt() is ignored.
15277c478bd9Sstevel@tonic-gate */
15287c478bd9Sstevel@tonic-gate }
15297c478bd9Sstevel@tonic-gate
1530bd670b35SErik Nordmark /*
1531bd670b35SErik Nordmark * did the user specify an interface?
1532bd670b35SErik Nordmark * Applies to unicast, broadcast and multicast.
1533bd670b35SErik Nordmark */
15347c478bd9Sstevel@tonic-gate if (moptions & MULTICAST_IF) {
15357c478bd9Sstevel@tonic-gate struct ifaddrlist *al = NULL; /* interface list */
15367c478bd9Sstevel@tonic-gate struct ifaddrlist *my_if;
15377c478bd9Sstevel@tonic-gate char errbuf[ERRBUFSIZE];
15387c478bd9Sstevel@tonic-gate int num_ifs;
15397c478bd9Sstevel@tonic-gate int num_src_ifs; /* exclude down and loopback */
15407c478bd9Sstevel@tonic-gate int i;
15417c478bd9Sstevel@tonic-gate
15427c478bd9Sstevel@tonic-gate /* pull out the interface list */
1543e11c3f44Smeem num_ifs = ifaddrlist(&al, family, LIFC_UNDER_IPMP, errbuf);
15447c478bd9Sstevel@tonic-gate if (num_ifs == -1) {
15457c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: %s\n", progname, errbuf);
15467c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
15477c478bd9Sstevel@tonic-gate }
15487c478bd9Sstevel@tonic-gate
15497c478bd9Sstevel@tonic-gate /* filter out down and loopback interfaces */
15507c478bd9Sstevel@tonic-gate num_src_ifs = 0;
15517c478bd9Sstevel@tonic-gate for (i = 0; i < num_ifs; i++) {
15527c478bd9Sstevel@tonic-gate if (!(al[i].flags & IFF_LOOPBACK) &&
15537c478bd9Sstevel@tonic-gate (al[i].flags & IFF_UP))
15547c478bd9Sstevel@tonic-gate num_src_ifs++;
15557c478bd9Sstevel@tonic-gate }
15567c478bd9Sstevel@tonic-gate
15577c478bd9Sstevel@tonic-gate if (num_src_ifs == 0) {
15587c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: can't find any %s interface\n",
15597c478bd9Sstevel@tonic-gate progname, (family == AF_INET) ? "IPv4" : "IPv6");
15607c478bd9Sstevel@tonic-gate
15617c478bd9Sstevel@tonic-gate return (_B_FALSE); /* failure */
15627c478bd9Sstevel@tonic-gate }
15637c478bd9Sstevel@tonic-gate
15647c478bd9Sstevel@tonic-gate /* locate the specified interface */
15657c478bd9Sstevel@tonic-gate my_if = find_if(al, num_ifs);
15667c478bd9Sstevel@tonic-gate if (my_if == NULL) {
15677c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: %s is an invalid %s interface\n",
15687c478bd9Sstevel@tonic-gate progname, out_if.str,
15697c478bd9Sstevel@tonic-gate (family == AF_INET) ? "IPv4" : "IPv6");
15707c478bd9Sstevel@tonic-gate
15717c478bd9Sstevel@tonic-gate return (_B_FALSE);
15727c478bd9Sstevel@tonic-gate }
15737c478bd9Sstevel@tonic-gate
15747c478bd9Sstevel@tonic-gate if (family == AF_INET) {
1575bd670b35SErik Nordmark struct in_pktinfo pktinfo;
1576bd670b35SErik Nordmark
15777c478bd9Sstevel@tonic-gate if (setsockopt(send_sock, IPPROTO_IP, IP_MULTICAST_IF,
15787c478bd9Sstevel@tonic-gate (char *)&my_if->addr.addr,
15797c478bd9Sstevel@tonic-gate sizeof (struct in_addr)) == -1) {
15807c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: setsockopt "
15817c478bd9Sstevel@tonic-gate "IP_MULTICAST_IF %s\n", progname,
15827c478bd9Sstevel@tonic-gate strerror(errno));
15837c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
15847c478bd9Sstevel@tonic-gate }
1585bd670b35SErik Nordmark bzero(&pktinfo, sizeof (pktinfo));
1586bd670b35SErik Nordmark pktinfo.ipi_ifindex = my_if->index;
1587bd670b35SErik Nordmark if (setsockopt(send_sock, IPPROTO_IP, IP_PKTINFO,
1588bd670b35SErik Nordmark (char *)&pktinfo, sizeof (pktinfo)) == -1) {
1589bd670b35SErik Nordmark Fprintf(stderr, "%s: setsockopt "
1590bd670b35SErik Nordmark "IP_PKTINFO %s\n", progname,
1591bd670b35SErik Nordmark strerror(errno));
1592bd670b35SErik Nordmark exit(EXIT_FAILURE);
1593bd670b35SErik Nordmark }
15947c478bd9Sstevel@tonic-gate } else {
15957c478bd9Sstevel@tonic-gate /*
15967c478bd9Sstevel@tonic-gate * the outgoing interface is set in set_ancillary_data()
15977c478bd9Sstevel@tonic-gate * function
15987c478bd9Sstevel@tonic-gate */
15997c478bd9Sstevel@tonic-gate *if_index = my_if->index;
16007c478bd9Sstevel@tonic-gate }
16017c478bd9Sstevel@tonic-gate
16027c478bd9Sstevel@tonic-gate free(al);
16037c478bd9Sstevel@tonic-gate }
16047c478bd9Sstevel@tonic-gate
16057c478bd9Sstevel@tonic-gate if (settos && family == AF_INET) {
16067c478bd9Sstevel@tonic-gate int_op = tos;
16077c478bd9Sstevel@tonic-gate if (setsockopt(send_sock, IPPROTO_IP, IP_TOS, (char *)&int_op,
16087c478bd9Sstevel@tonic-gate sizeof (int_op)) == -1) {
16097c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: setsockopt IP_TOS %s\n",
16107c478bd9Sstevel@tonic-gate progname, strerror(errno));
16117c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
16127c478bd9Sstevel@tonic-gate }
16137c478bd9Sstevel@tonic-gate }
16147c478bd9Sstevel@tonic-gate
1615bd670b35SErik Nordmark /* We enable or disable to not depend on the kernel default */
1616bd670b35SErik Nordmark if (family == AF_INET) {
1617bd670b35SErik Nordmark if (setsockopt(send_sock, IPPROTO_IP, IP_DONTFRAG,
1618bd670b35SErik Nordmark (char *)&dontfrag, sizeof (dontfrag)) == -1) {
1619bd670b35SErik Nordmark Fprintf(stderr, "%s: setsockopt IP_DONTFRAG %s\n",
1620bd670b35SErik Nordmark progname, strerror(errno));
1621bd670b35SErik Nordmark exit(EXIT_FAILURE);
1622bd670b35SErik Nordmark }
1623bd670b35SErik Nordmark } else {
1624bd670b35SErik Nordmark if (setsockopt(send_sock, IPPROTO_IPV6, IPV6_DONTFRAG,
1625bd670b35SErik Nordmark (char *)&dontfrag, sizeof (dontfrag)) == -1) {
1626bd670b35SErik Nordmark Fprintf(stderr, "%s: setsockopt IPV6_DONTFRAG %s\n",
1627bd670b35SErik Nordmark progname, strerror(errno));
1628bd670b35SErik Nordmark exit(EXIT_FAILURE);
1629bd670b35SErik Nordmark }
1630bd670b35SErik Nordmark }
1631bd670b35SErik Nordmark
16327c478bd9Sstevel@tonic-gate /* receiving IPv6 extension headers in verbose mode */
16337c478bd9Sstevel@tonic-gate if (verbose && family == AF_INET6) {
16347c478bd9Sstevel@tonic-gate if (setsockopt(recv_sock, IPPROTO_IPV6, IPV6_RECVHOPOPTS,
16357c478bd9Sstevel@tonic-gate (char *)&on, sizeof (on)) == -1) {
16367c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: setsockopt IPV6_RECVHOPOPTS %s\n",
16377c478bd9Sstevel@tonic-gate progname, strerror(errno));
16387c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
16397c478bd9Sstevel@tonic-gate }
16407c478bd9Sstevel@tonic-gate
16417c478bd9Sstevel@tonic-gate if (setsockopt(recv_sock, IPPROTO_IPV6, IPV6_RECVDSTOPTS,
16427c478bd9Sstevel@tonic-gate (char *)&on, sizeof (on)) == -1) {
16437c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: setsockopt IPV6_RECVDSTOPTS %s\n",
16447c478bd9Sstevel@tonic-gate progname, strerror(errno));
16457c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
16467c478bd9Sstevel@tonic-gate }
16477c478bd9Sstevel@tonic-gate
16487c478bd9Sstevel@tonic-gate if (setsockopt(recv_sock, IPPROTO_IPV6, IPV6_RECVRTHDR,
16497c478bd9Sstevel@tonic-gate (char *)&on, sizeof (on)) == -1) {
16507c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: setsockopt IPV6_RECVRTHDR %s\n",
16517c478bd9Sstevel@tonic-gate progname, strerror(errno));
16527c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
16537c478bd9Sstevel@tonic-gate }
16547c478bd9Sstevel@tonic-gate }
16557c478bd9Sstevel@tonic-gate
1656b08923d6SRobert Mustacchi /* Ensure that timestamping is requested on the receive socket */
1657b08923d6SRobert Mustacchi if (setsockopt(recv_sock, SOL_SOCKET, SO_TIMESTAMP,
1658b08923d6SRobert Mustacchi &on, sizeof (on)) == -1) {
1659b08923d6SRobert Mustacchi Fprintf(stderr, "%s: warning: timing accuracy diminished -- "
1660b08923d6SRobert Mustacchi "setsockopt SO_TIMESTAMP failed %s", progname,
1661b08923d6SRobert Mustacchi strerror(errno));
1662b08923d6SRobert Mustacchi }
1663b08923d6SRobert Mustacchi
16647c478bd9Sstevel@tonic-gate *send_sockp = send_sock;
16657c478bd9Sstevel@tonic-gate *recv_sockp = recv_sock;
16667c478bd9Sstevel@tonic-gate
16677c478bd9Sstevel@tonic-gate /* successful */
16687c478bd9Sstevel@tonic-gate return (_B_TRUE);
16697c478bd9Sstevel@tonic-gate }
16707c478bd9Sstevel@tonic-gate
16717c478bd9Sstevel@tonic-gate /*
16727c478bd9Sstevel@tonic-gate * Pull out the record containing all the info about the interface specified by
16737c478bd9Sstevel@tonic-gate * `out_if'. Skips interfaces which are down or loopback.
16747c478bd9Sstevel@tonic-gate */
16757c478bd9Sstevel@tonic-gate static struct ifaddrlist *
find_if(struct ifaddrlist * al,int num_ifs)16767c478bd9Sstevel@tonic-gate find_if(struct ifaddrlist *al, int num_ifs)
16777c478bd9Sstevel@tonic-gate {
16787c478bd9Sstevel@tonic-gate static struct ifaddrlist tmp_if;
16797c478bd9Sstevel@tonic-gate boolean_t found;
16807c478bd9Sstevel@tonic-gate int i;
16817c478bd9Sstevel@tonic-gate
16827c478bd9Sstevel@tonic-gate i = 0;
16837c478bd9Sstevel@tonic-gate found = _B_FALSE;
16847c478bd9Sstevel@tonic-gate
16857c478bd9Sstevel@tonic-gate while (i < num_ifs && !found) {
16867c478bd9Sstevel@tonic-gate tmp_if = al[i];
16877c478bd9Sstevel@tonic-gate
16887c478bd9Sstevel@tonic-gate /* skip down or loopback interfaces */
16897c478bd9Sstevel@tonic-gate if ((tmp_if.flags & IFF_LOOPBACK) || !(tmp_if.flags & IFF_UP)) {
16907c478bd9Sstevel@tonic-gate i++;
16917c478bd9Sstevel@tonic-gate continue;
16927c478bd9Sstevel@tonic-gate }
16937c478bd9Sstevel@tonic-gate
16947c478bd9Sstevel@tonic-gate /* the type of interface id is variable */
16957c478bd9Sstevel@tonic-gate switch (out_if.id_type) {
16967c478bd9Sstevel@tonic-gate case IF_INDEX:
16977c478bd9Sstevel@tonic-gate if (out_if.id.index == tmp_if.index)
16987c478bd9Sstevel@tonic-gate found = _B_TRUE;
16997c478bd9Sstevel@tonic-gate break;
17007c478bd9Sstevel@tonic-gate
17017c478bd9Sstevel@tonic-gate case IF_NAME:
17027c478bd9Sstevel@tonic-gate if (strcmp(out_if.id.name, tmp_if.device) == 0)
17037c478bd9Sstevel@tonic-gate found = _B_TRUE;
17047c478bd9Sstevel@tonic-gate break;
17057c478bd9Sstevel@tonic-gate
17067c478bd9Sstevel@tonic-gate case IF_ADDR:
17077c478bd9Sstevel@tonic-gate if (out_if.id.addr.addr.s_addr ==
17087c478bd9Sstevel@tonic-gate tmp_if.addr.addr.s_addr) {
17097c478bd9Sstevel@tonic-gate found = _B_TRUE;
17107c478bd9Sstevel@tonic-gate }
17117c478bd9Sstevel@tonic-gate break;
17127c478bd9Sstevel@tonic-gate
17137c478bd9Sstevel@tonic-gate case IF_ADDR6:
17147c478bd9Sstevel@tonic-gate if (IN6_ARE_ADDR_EQUAL(&out_if.id.addr.addr6,
17157c478bd9Sstevel@tonic-gate &tmp_if.addr.addr6)) {
17167c478bd9Sstevel@tonic-gate found = _B_TRUE;
17177c478bd9Sstevel@tonic-gate }
17187c478bd9Sstevel@tonic-gate break;
17197c478bd9Sstevel@tonic-gate
17207c478bd9Sstevel@tonic-gate default:
17217c478bd9Sstevel@tonic-gate break;
17227c478bd9Sstevel@tonic-gate }
17237c478bd9Sstevel@tonic-gate
17247c478bd9Sstevel@tonic-gate i++;
17257c478bd9Sstevel@tonic-gate }
17267c478bd9Sstevel@tonic-gate
17277c478bd9Sstevel@tonic-gate if (found)
17287c478bd9Sstevel@tonic-gate return (&tmp_if);
17297c478bd9Sstevel@tonic-gate else
17307c478bd9Sstevel@tonic-gate return (NULL);
17317c478bd9Sstevel@tonic-gate }
17327c478bd9Sstevel@tonic-gate
17337c478bd9Sstevel@tonic-gate /*
17347c478bd9Sstevel@tonic-gate * Invoked by SIGALRM, sigalrm_handler() is, responsible for calling
17357c478bd9Sstevel@tonic-gate * send_scheduled_probe() to send next probe.
17367c478bd9Sstevel@tonic-gate */
17377c478bd9Sstevel@tonic-gate void
sigalrm_handler(void)17387c478bd9Sstevel@tonic-gate sigalrm_handler(void)
17397c478bd9Sstevel@tonic-gate {
17407c478bd9Sstevel@tonic-gate /*
1741b08923d6SRobert Mustacchi * If we've been told that we're done, the timer should be cancelled
1742b08923d6SRobert Mustacchi * and not rescheduled, just return.
1743b08923d6SRobert Mustacchi */
1744b08923d6SRobert Mustacchi if (timer_done == _B_TRUE)
1745b08923d6SRobert Mustacchi return;
1746b08923d6SRobert Mustacchi
1747b08923d6SRobert Mustacchi /*
1748b08923d6SRobert Mustacchi * Guard against denial-of-service attacks. Make sure ping doesn't send
1749b08923d6SRobert Mustacchi * probes for every SIGALRM it receives in the case of errant SIGALRMs.
1750b08923d6SRobert Mustacchi * ping will ignore those which are received too soon (the smaller of
1751b08923d6SRobert Mustacchi * 0.5 sec and the ping interval, if in effect) after it sent the last
1752b08923d6SRobert Mustacchi * probe. We use gethrtime() instead of gettimeofday() because the
1753b08923d6SRobert Mustacchi * latter is not linear and is prone to resetting or drifting.
17547c478bd9Sstevel@tonic-gate */
1755b08923d6SRobert Mustacchi if ((gethrtime() - t_last_probe_sent) < mintime) {
17567c478bd9Sstevel@tonic-gate return;
17577c478bd9Sstevel@tonic-gate }
17587c478bd9Sstevel@tonic-gate send_scheduled_probe();
17597c478bd9Sstevel@tonic-gate schedule_sigalrm();
17607c478bd9Sstevel@tonic-gate }
17617c478bd9Sstevel@tonic-gate
17627c478bd9Sstevel@tonic-gate /*
17637c478bd9Sstevel@tonic-gate * Schedule next SIGALRM.
17647c478bd9Sstevel@tonic-gate */
17657c478bd9Sstevel@tonic-gate void
schedule_sigalrm(void)17667c478bd9Sstevel@tonic-gate schedule_sigalrm(void)
17677c478bd9Sstevel@tonic-gate {
17687c478bd9Sstevel@tonic-gate int waittime;
1769b08923d6SRobert Mustacchi struct itimerspec it;
17707c478bd9Sstevel@tonic-gate
1771b08923d6SRobert Mustacchi bzero(&it, sizeof (struct itimerspec));
17727c478bd9Sstevel@tonic-gate if (npackets == 0 ||
17737c478bd9Sstevel@tonic-gate current_targetaddr->num_sent < current_targetaddr->num_probes) {
1774b08923d6SRobert Mustacchi it = interval;
17757c478bd9Sstevel@tonic-gate } else {
17767c478bd9Sstevel@tonic-gate if (current_targetaddr->got_reply) {
17777c478bd9Sstevel@tonic-gate waittime = 2 * tmax / MICROSEC;
17787c478bd9Sstevel@tonic-gate if (waittime == 0)
17797c478bd9Sstevel@tonic-gate waittime = 1;
17807c478bd9Sstevel@tonic-gate } else {
17817c478bd9Sstevel@tonic-gate waittime = MAX_WAIT;
17827c478bd9Sstevel@tonic-gate }
1783b08923d6SRobert Mustacchi it.it_value.tv_sec = waittime;
1784b08923d6SRobert Mustacchi }
1785b08923d6SRobert Mustacchi
1786b08923d6SRobert Mustacchi if (timer_settime(timer, TIMER_RELTIME, &it, NULL) != 0) {
1787b08923d6SRobert Mustacchi Fprintf(stderr, "%s: unexpected error updating time: %s\n",
1788b08923d6SRobert Mustacchi progname, strerror(errno));
1789b08923d6SRobert Mustacchi exit(EXIT_FAILURE);
17907c478bd9Sstevel@tonic-gate }
17917c478bd9Sstevel@tonic-gate }
17927c478bd9Sstevel@tonic-gate
17937c478bd9Sstevel@tonic-gate /*
17947c478bd9Sstevel@tonic-gate * Called by sigalrm_handler(), check_reply() or check_reply6(),
17957c478bd9Sstevel@tonic-gate * send_scheduled_probe() looks at the current_targetaddr and determines what
17967c478bd9Sstevel@tonic-gate * should be sent next and calls pinger().
17977c478bd9Sstevel@tonic-gate */
17987c478bd9Sstevel@tonic-gate void
send_scheduled_probe()17997c478bd9Sstevel@tonic-gate send_scheduled_probe()
18007c478bd9Sstevel@tonic-gate {
18017c478bd9Sstevel@tonic-gate static struct msghdr msg6;
18027c478bd9Sstevel@tonic-gate static boolean_t first_probe = _B_TRUE;
18037c478bd9Sstevel@tonic-gate char tmp_buf[INET6_ADDRSTRLEN];
18047c478bd9Sstevel@tonic-gate
18057c478bd9Sstevel@tonic-gate /*
18067c478bd9Sstevel@tonic-gate * We are about to move to next targetaddr if it's either we sent
18077c478bd9Sstevel@tonic-gate * all the probes, or somebody set the probing_done flag to
18087c478bd9Sstevel@tonic-gate * _B_TRUE prompting us to move on.
18097c478bd9Sstevel@tonic-gate */
18107c478bd9Sstevel@tonic-gate if (current_targetaddr->num_sent == current_targetaddr->num_probes ||
18117c478bd9Sstevel@tonic-gate current_targetaddr->probing_done) {
18127c478bd9Sstevel@tonic-gate /*
18137c478bd9Sstevel@tonic-gate * is this a dead target?
18147c478bd9Sstevel@tonic-gate */
18157c478bd9Sstevel@tonic-gate if (!stats && !current_targetaddr->got_reply) {
18167c478bd9Sstevel@tonic-gate if (!probe_all) {
18177c478bd9Sstevel@tonic-gate Printf("no answer from %s\n", targethost);
18187c478bd9Sstevel@tonic-gate } else {
18197c478bd9Sstevel@tonic-gate Printf("no answer from %s(%s)\n", targethost,
18207c478bd9Sstevel@tonic-gate inet_ntop(current_targetaddr->family,
1821e11c3f44Smeem ¤t_targetaddr->dst_addr,
1822e11c3f44Smeem tmp_buf, sizeof (tmp_buf)));
18237c478bd9Sstevel@tonic-gate }
18247c478bd9Sstevel@tonic-gate }
18257c478bd9Sstevel@tonic-gate /*
18267c478bd9Sstevel@tonic-gate * Before we move onto next item, let's do some clean up.
18277c478bd9Sstevel@tonic-gate */
18287c478bd9Sstevel@tonic-gate current_targetaddr->got_reply = _B_FALSE;
18297c478bd9Sstevel@tonic-gate current_targetaddr->probing_done = _B_FALSE;
18307c478bd9Sstevel@tonic-gate /*
18317c478bd9Sstevel@tonic-gate * If this is probe-all without stats mode, then we need to
18327c478bd9Sstevel@tonic-gate * preserve this count. This is needed when we try to map an
18337c478bd9Sstevel@tonic-gate * icmp_seq to IP address. Otherwise, clear it.
18347c478bd9Sstevel@tonic-gate */
18357c478bd9Sstevel@tonic-gate if (stats || !probe_all)
18367c478bd9Sstevel@tonic-gate current_targetaddr->num_sent = 0;
18377c478bd9Sstevel@tonic-gate nreceived_last_target = 0;
18387c478bd9Sstevel@tonic-gate
18397c478bd9Sstevel@tonic-gate current_targetaddr = current_targetaddr->next;
18407c478bd9Sstevel@tonic-gate
18417c478bd9Sstevel@tonic-gate /*
18427c478bd9Sstevel@tonic-gate * Did we reach the end of road?
18437c478bd9Sstevel@tonic-gate */
18447c478bd9Sstevel@tonic-gate if (current_targetaddr == NULL) {
1845b08923d6SRobert Mustacchi timer_done = _B_TRUE;
18467c478bd9Sstevel@tonic-gate if (stats)
18477c478bd9Sstevel@tonic-gate finish();
18487c478bd9Sstevel@tonic-gate if (is_alive)
18497c478bd9Sstevel@tonic-gate exit(EXIT_SUCCESS);
18507c478bd9Sstevel@tonic-gate else
18517c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
18527c478bd9Sstevel@tonic-gate } else {
18537c478bd9Sstevel@tonic-gate /*
18547c478bd9Sstevel@tonic-gate * We use starting_seq_num for authenticating replies.
18557c478bd9Sstevel@tonic-gate * Each time we move to a new targetaddr, which has
18567c478bd9Sstevel@tonic-gate * a different target IP address, we update this field.
18577c478bd9Sstevel@tonic-gate */
1858e11c3f44Smeem current_targetaddr->starting_seq_num = use_udp ?
1859e11c3f44Smeem dest_port : (ntransmitted % (MAX_ICMP_SEQ + 1));
18607c478bd9Sstevel@tonic-gate }
18617c478bd9Sstevel@tonic-gate }
18627c478bd9Sstevel@tonic-gate
18637c478bd9Sstevel@tonic-gate if (current_targetaddr->family == AF_INET6) {
18647c478bd9Sstevel@tonic-gate if (send_reply) {
18657c478bd9Sstevel@tonic-gate /* sending back to ourself */
18667c478bd9Sstevel@tonic-gate to6.sin6_addr = current_targetaddr->src_addr.addr6;
18677c478bd9Sstevel@tonic-gate } else {
18687c478bd9Sstevel@tonic-gate to6.sin6_addr = current_targetaddr->dst_addr.addr6;
18697c478bd9Sstevel@tonic-gate }
18707c478bd9Sstevel@tonic-gate /*
18717c478bd9Sstevel@tonic-gate * Setting the ancillary data once is enough, if we are
18727c478bd9Sstevel@tonic-gate * not using source routing through target (-l/-S). In
18737c478bd9Sstevel@tonic-gate * case -l/-S used, the middle gateway will be the
18747c478bd9Sstevel@tonic-gate * IP address of the source, which can be different
18757c478bd9Sstevel@tonic-gate * for each target IP.
18767c478bd9Sstevel@tonic-gate */
18777c478bd9Sstevel@tonic-gate if (first_probe ||
18787c478bd9Sstevel@tonic-gate (send_reply && current_targetaddr->num_sent == 0)) {
18797c478bd9Sstevel@tonic-gate if (send_reply) {
18807c478bd9Sstevel@tonic-gate /* target is the middle gateway now */
18817c478bd9Sstevel@tonic-gate gw_IP_list6[num_gw].addr6 =
18827c478bd9Sstevel@tonic-gate current_targetaddr->dst_addr.addr6;
18837c478bd9Sstevel@tonic-gate }
18847c478bd9Sstevel@tonic-gate set_ancillary_data(&msg6, hoplimit, gw_IP_list6,
18857c478bd9Sstevel@tonic-gate eff_num_gw, if_index);
18867c478bd9Sstevel@tonic-gate first_probe = _B_FALSE;
18877c478bd9Sstevel@tonic-gate }
18887c478bd9Sstevel@tonic-gate pinger(send_sock6, (struct sockaddr *)&to6, &msg6, AF_INET6);
18897c478bd9Sstevel@tonic-gate } else {
18907c478bd9Sstevel@tonic-gate to.sin_addr = current_targetaddr->dst_addr.addr;
18917c478bd9Sstevel@tonic-gate /*
18927c478bd9Sstevel@tonic-gate * Set IPv4 options when sending the first probe to a target
18937c478bd9Sstevel@tonic-gate * IP address. Some options change when the target address
18947c478bd9Sstevel@tonic-gate * changes.
18957c478bd9Sstevel@tonic-gate */
18967c478bd9Sstevel@tonic-gate if (current_targetaddr->num_sent == 0) {
18977c478bd9Sstevel@tonic-gate if (eff_num_gw > 0) {
18987c478bd9Sstevel@tonic-gate gw_IP_list[num_gw].addr =
18997c478bd9Sstevel@tonic-gate current_targetaddr->dst_addr.addr;
19007c478bd9Sstevel@tonic-gate /*
19017c478bd9Sstevel@tonic-gate * If send_reply, the target becomes the
19027c478bd9Sstevel@tonic-gate * middle gateway, sender becomes the last
19037c478bd9Sstevel@tonic-gate * gateway.
19047c478bd9Sstevel@tonic-gate */
19057c478bd9Sstevel@tonic-gate if (send_reply) {
19067c478bd9Sstevel@tonic-gate gw_IP_list[eff_num_gw].addr =
19077c478bd9Sstevel@tonic-gate current_targetaddr->src_addr.addr;
19087c478bd9Sstevel@tonic-gate }
19097c478bd9Sstevel@tonic-gate }
19107c478bd9Sstevel@tonic-gate /*
19117c478bd9Sstevel@tonic-gate * In IPv4, if source routing is used, the target
19127c478bd9Sstevel@tonic-gate * address shows up as the last gateway, hence +1.
19137c478bd9Sstevel@tonic-gate */
19147c478bd9Sstevel@tonic-gate set_IPv4_options(send_sock, gw_IP_list,
19157c478bd9Sstevel@tonic-gate (eff_num_gw > 0) ? eff_num_gw + 1 : 0,
19167c478bd9Sstevel@tonic-gate ¤t_targetaddr->src_addr.addr, &to.sin_addr);
19177c478bd9Sstevel@tonic-gate }
19187c478bd9Sstevel@tonic-gate pinger(send_sock, (struct sockaddr *)&to, NULL, AF_INET);
19197c478bd9Sstevel@tonic-gate }
19207c478bd9Sstevel@tonic-gate
19217c478bd9Sstevel@tonic-gate current_targetaddr->num_sent++;
19227c478bd9Sstevel@tonic-gate }
19237c478bd9Sstevel@tonic-gate
19247c478bd9Sstevel@tonic-gate /*
19257c478bd9Sstevel@tonic-gate * recv_icmp_packet()'s job is to listen to icmp packets and filter out
19267c478bd9Sstevel@tonic-gate * those ping is interested in.
19277c478bd9Sstevel@tonic-gate */
19287c478bd9Sstevel@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)19297c478bd9Sstevel@tonic-gate recv_icmp_packet(struct addrinfo *ai_dst, int recv_sock6, int recv_sock,
1930afee3dc6SRobert Mustacchi ushort_t udp_src_port6, ushort_t udp_src_port)
19317c478bd9Sstevel@tonic-gate {
19327c478bd9Sstevel@tonic-gate struct msghdr in_msg;
19337c478bd9Sstevel@tonic-gate struct iovec iov;
19347c478bd9Sstevel@tonic-gate struct sockaddr_in6 from6;
19357c478bd9Sstevel@tonic-gate fd_set fds;
19367c478bd9Sstevel@tonic-gate int result;
19377c478bd9Sstevel@tonic-gate int cc;
19387c478bd9Sstevel@tonic-gate boolean_t always_true = _B_TRUE; /* lint doesn't like while(_B_TRUE) */
19397c478bd9Sstevel@tonic-gate
19407c478bd9Sstevel@tonic-gate while (always_true) {
19417c478bd9Sstevel@tonic-gate (void) FD_ZERO(&fds);
19427c478bd9Sstevel@tonic-gate if (recv_sock6 != -1)
19437c478bd9Sstevel@tonic-gate FD_SET(recv_sock6, &fds);
19447c478bd9Sstevel@tonic-gate if (recv_sock != -1)
19457c478bd9Sstevel@tonic-gate FD_SET(recv_sock, &fds);
19467c478bd9Sstevel@tonic-gate
19477c478bd9Sstevel@tonic-gate result = select(MAX(recv_sock6, recv_sock) + 1, &fds,
19487c478bd9Sstevel@tonic-gate (fd_set *)NULL, (fd_set *)NULL, (struct timeval *)NULL);
19497c478bd9Sstevel@tonic-gate if (result == -1) {
19507c478bd9Sstevel@tonic-gate if (errno == EINTR) {
19517c478bd9Sstevel@tonic-gate continue;
19527c478bd9Sstevel@tonic-gate } else {
19537c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: select %s\n", progname,
19547c478bd9Sstevel@tonic-gate strerror(errno));
19557c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
19567c478bd9Sstevel@tonic-gate }
19577c478bd9Sstevel@tonic-gate } else if (result > 0) {
19587c478bd9Sstevel@tonic-gate in_msg.msg_name = &from6;
19597c478bd9Sstevel@tonic-gate in_msg.msg_namelen = sizeof (from6);
19607c478bd9Sstevel@tonic-gate iov.iov_base = in_pkt;
19617c478bd9Sstevel@tonic-gate iov.iov_len = sizeof (in_pkt);
19627c478bd9Sstevel@tonic-gate in_msg.msg_iov = &iov;
19637c478bd9Sstevel@tonic-gate in_msg.msg_iovlen = 1;
19647c478bd9Sstevel@tonic-gate in_msg.msg_control = ancillary_data;
19657c478bd9Sstevel@tonic-gate in_msg.msg_controllen = sizeof (ancillary_data);
19667c478bd9Sstevel@tonic-gate
19677c478bd9Sstevel@tonic-gate /* Do we have an ICMP6 packet waiting? */
19687c478bd9Sstevel@tonic-gate if ((recv_sock6 != -1) &&
19697c478bd9Sstevel@tonic-gate (FD_ISSET(recv_sock6, &fds))) {
19707c478bd9Sstevel@tonic-gate cc = recvmsg(recv_sock6, &in_msg, 0);
19717c478bd9Sstevel@tonic-gate if (cc < 0) {
19727c478bd9Sstevel@tonic-gate if (errno != EINTR) {
19737c478bd9Sstevel@tonic-gate Fprintf(stderr,
19747c478bd9Sstevel@tonic-gate "%s: recvmsg %s\n",
19757c478bd9Sstevel@tonic-gate progname, strerror(errno));
19767c478bd9Sstevel@tonic-gate }
19777c478bd9Sstevel@tonic-gate continue;
19787c478bd9Sstevel@tonic-gate } else if (cc > 0) {
19797c478bd9Sstevel@tonic-gate check_reply6(ai_dst, &in_msg, cc,
19807c478bd9Sstevel@tonic-gate udp_src_port6);
19817c478bd9Sstevel@tonic-gate }
19827c478bd9Sstevel@tonic-gate }
19837c478bd9Sstevel@tonic-gate /* Do we have an ICMP packet waiting? */
19847c478bd9Sstevel@tonic-gate if ((recv_sock != -1) && (FD_ISSET(recv_sock, &fds))) {
19857c478bd9Sstevel@tonic-gate cc = recvmsg(recv_sock, &in_msg, 0);
19867c478bd9Sstevel@tonic-gate if (cc < 0) {
19877c478bd9Sstevel@tonic-gate if (errno != EINTR) {
19887c478bd9Sstevel@tonic-gate Fprintf(stderr,
19897c478bd9Sstevel@tonic-gate "%s: recvmsg %s\n",
19907c478bd9Sstevel@tonic-gate progname, strerror(errno));
19917c478bd9Sstevel@tonic-gate }
19927c478bd9Sstevel@tonic-gate continue;
1993cbf54fedSJohn Levon } else if (cc > 0) {
19947c478bd9Sstevel@tonic-gate check_reply(ai_dst, &in_msg, cc,
19957c478bd9Sstevel@tonic-gate udp_src_port);
19967c478bd9Sstevel@tonic-gate }
19977c478bd9Sstevel@tonic-gate }
19987c478bd9Sstevel@tonic-gate }
19997c478bd9Sstevel@tonic-gate /*
20007c478bd9Sstevel@tonic-gate * If we were probing last IP address of the target host and
20017c478bd9Sstevel@tonic-gate * received a reply for each probe sent to this address,
20027c478bd9Sstevel@tonic-gate * then we are done!
20037c478bd9Sstevel@tonic-gate */
20047c478bd9Sstevel@tonic-gate if ((npackets > 0) && (current_targetaddr->next == NULL) &&
20057c478bd9Sstevel@tonic-gate (nreceived_last_target == npackets)) {
2006b08923d6SRobert Mustacchi timer_done = _B_TRUE;
20077c478bd9Sstevel@tonic-gate finish();
20087c478bd9Sstevel@tonic-gate }
20097c478bd9Sstevel@tonic-gate } /* infinite loop */
20107c478bd9Sstevel@tonic-gate }
20117c478bd9Sstevel@tonic-gate
20127c478bd9Sstevel@tonic-gate /*
20137c478bd9Sstevel@tonic-gate * Given a host (with possibly multiple IP addresses) and an IP address, this
20147c478bd9Sstevel@tonic-gate * function determines if this IP address is one of the host's addresses to
20157c478bd9Sstevel@tonic-gate * which we're sending probes. Used to determine if we are interested in a
20167c478bd9Sstevel@tonic-gate * packet.
20177c478bd9Sstevel@tonic-gate */
20187c478bd9Sstevel@tonic-gate boolean_t
is_a_target(struct addrinfo * ai,union any_in_addr * addr)20197c478bd9Sstevel@tonic-gate is_a_target(struct addrinfo *ai, union any_in_addr *addr)
20207c478bd9Sstevel@tonic-gate {
20217c478bd9Sstevel@tonic-gate int num_addrs;
20227c478bd9Sstevel@tonic-gate int i;
20237c478bd9Sstevel@tonic-gate struct addrinfo *aip;
20247c478bd9Sstevel@tonic-gate
20257c478bd9Sstevel@tonic-gate aip = ai;
20267c478bd9Sstevel@tonic-gate if (probe_all)
20277c478bd9Sstevel@tonic-gate num_addrs = num_v4 + num_v6;
20287c478bd9Sstevel@tonic-gate else
20297c478bd9Sstevel@tonic-gate num_addrs = 1;
20307c478bd9Sstevel@tonic-gate for (i = 0; i < num_addrs && aip != NULL; i++) {
20317c478bd9Sstevel@tonic-gate if (aip->ai_family == AF_INET6) {
20327c478bd9Sstevel@tonic-gate /* LINTED E_BAD_PTR_CAST_ALIGN */
20337c478bd9Sstevel@tonic-gate if (IN6_ARE_ADDR_EQUAL(&((struct sockaddr_in6 *)
20347c478bd9Sstevel@tonic-gate aip->ai_addr)->sin6_addr, &addr->addr6))
20357c478bd9Sstevel@tonic-gate return (_B_TRUE);
20367c478bd9Sstevel@tonic-gate } else {
20377c478bd9Sstevel@tonic-gate /* LINTED E_BAD_PTR_CAST_ALIGN */
20387c478bd9Sstevel@tonic-gate if (((struct sockaddr_in *)
20397c478bd9Sstevel@tonic-gate aip->ai_addr)->sin_addr.s_addr == addr->addr.s_addr)
20407c478bd9Sstevel@tonic-gate return (_B_TRUE);
20417c478bd9Sstevel@tonic-gate }
20427c478bd9Sstevel@tonic-gate }
20437c478bd9Sstevel@tonic-gate
20447c478bd9Sstevel@tonic-gate return (_B_FALSE);
20457c478bd9Sstevel@tonic-gate }
20467c478bd9Sstevel@tonic-gate
20477c478bd9Sstevel@tonic-gate /*
20487c478bd9Sstevel@tonic-gate * Compose and transmit an ICMP ECHO REQUEST packet. The IP packet
20497c478bd9Sstevel@tonic-gate * will be added on by the kernel. The ID field is our UNIX process ID,
20507c478bd9Sstevel@tonic-gate * and the sequence number is an ascending integer. The first 8 bytes
20517c478bd9Sstevel@tonic-gate * of the data portion are used to hold a UNIX "timeval" struct in network
20527c478bd9Sstevel@tonic-gate * byte-order, to compute the round-trip time.
20537c478bd9Sstevel@tonic-gate */
20547c478bd9Sstevel@tonic-gate static void
pinger(int send_sock,struct sockaddr * whereto,struct msghdr * msg6,int family)20557c478bd9Sstevel@tonic-gate pinger(int send_sock, struct sockaddr *whereto, struct msghdr *msg6,
20567c478bd9Sstevel@tonic-gate int family)
20577c478bd9Sstevel@tonic-gate {
20587c478bd9Sstevel@tonic-gate static uint64_t out_pkt_buf[(IP_MAXPACKET + 1) / 8];
20597c478bd9Sstevel@tonic-gate uchar_t *out_pkt = (uchar_t *)&out_pkt_buf;
20607c478bd9Sstevel@tonic-gate /* LINTED E_BAD_PTR_CAST_ALIGN */
20617c478bd9Sstevel@tonic-gate struct icmp *icp = (struct icmp *)out_pkt;
20627c478bd9Sstevel@tonic-gate /* LINTED E_BAD_PTR_CAST_ALIGN */
20637c478bd9Sstevel@tonic-gate struct sockaddr_in6 *to6 = (struct sockaddr_in6 *)whereto;
20647c478bd9Sstevel@tonic-gate /* LINTED E_BAD_PTR_CAST_ALIGN */
20657c478bd9Sstevel@tonic-gate struct sockaddr_in *to = (struct sockaddr_in *)whereto;
20667c478bd9Sstevel@tonic-gate struct timeval *tp;
20677c478bd9Sstevel@tonic-gate struct timeval t_snd;
20687c478bd9Sstevel@tonic-gate uchar_t *datap;
20697c478bd9Sstevel@tonic-gate struct iovec iov;
20707c478bd9Sstevel@tonic-gate int start = 0;
20717c478bd9Sstevel@tonic-gate int cc;
20727c478bd9Sstevel@tonic-gate int i;
20737c478bd9Sstevel@tonic-gate
20747c478bd9Sstevel@tonic-gate /* using UDP? */
20757c478bd9Sstevel@tonic-gate if (use_udp) {
20767c478bd9Sstevel@tonic-gate cc = datalen;
20777c478bd9Sstevel@tonic-gate
20787c478bd9Sstevel@tonic-gate /* LINTED E_BAD_PTR_CAST_ALIGN */
20797c478bd9Sstevel@tonic-gate tp = (struct timeval *)out_pkt;
20807c478bd9Sstevel@tonic-gate datap = &out_pkt[sizeof (struct timeval)];
20817c478bd9Sstevel@tonic-gate
20827c478bd9Sstevel@tonic-gate /*
20837c478bd9Sstevel@tonic-gate * This sets the port whether we are handling a v4 or v6
20847c478bd9Sstevel@tonic-gate * sockaddr structure.
20857c478bd9Sstevel@tonic-gate */
20867c478bd9Sstevel@tonic-gate to->sin_port = htons(dest_port);
20877c478bd9Sstevel@tonic-gate
20887c478bd9Sstevel@tonic-gate dest_port = (dest_port + 1) % (MAX_PORT + 1);
20897c478bd9Sstevel@tonic-gate ntransmitted++;
20907c478bd9Sstevel@tonic-gate } else { /* using ICMP */
20917c478bd9Sstevel@tonic-gate cc = datalen + ICMP_MINLEN;
20927c478bd9Sstevel@tonic-gate
20937c478bd9Sstevel@tonic-gate if (family == AF_INET6) {
20947c478bd9Sstevel@tonic-gate icp->icmp_type = send_reply ?
20957c478bd9Sstevel@tonic-gate ICMP6_ECHO_REPLY : ICMP6_ECHO_REQUEST;
20967c478bd9Sstevel@tonic-gate } else if (use_icmp_ts) { /* family is AF_INET */
20977c478bd9Sstevel@tonic-gate icp->icmp_type = send_reply ?
20987c478bd9Sstevel@tonic-gate ICMP_TSTAMPREPLY : ICMP_TSTAMP;
20997c478bd9Sstevel@tonic-gate } else {
21007c478bd9Sstevel@tonic-gate icp->icmp_type = send_reply ?
21017c478bd9Sstevel@tonic-gate ICMP_ECHOREPLY : ICMP_ECHO;
21027c478bd9Sstevel@tonic-gate }
21037c478bd9Sstevel@tonic-gate
21047c478bd9Sstevel@tonic-gate icp->icmp_code = 0;
21057c478bd9Sstevel@tonic-gate icp->icmp_cksum = 0;
21067c478bd9Sstevel@tonic-gate icp->icmp_seq = htons(ntransmitted++ % (MAX_ICMP_SEQ + 1));
21077c478bd9Sstevel@tonic-gate if (icp->icmp_seq == 0)
21087c478bd9Sstevel@tonic-gate num_wraps++;
21097c478bd9Sstevel@tonic-gate icp->icmp_id = htons(ident); /* ID */
21107c478bd9Sstevel@tonic-gate
21117c478bd9Sstevel@tonic-gate /* LINTED E_BAD_PTR_CAST_ALIGN */
21127c478bd9Sstevel@tonic-gate tp = (struct timeval *)&out_pkt[ICMP_MINLEN];
21137c478bd9Sstevel@tonic-gate datap = &out_pkt[ICMP_MINLEN + sizeof (struct timeval)];
21147c478bd9Sstevel@tonic-gate }
21157c478bd9Sstevel@tonic-gate
21167c478bd9Sstevel@tonic-gate start = sizeof (struct timeval); /* skip for time */
21177c478bd9Sstevel@tonic-gate
21187c478bd9Sstevel@tonic-gate (void) gettimeofday(&t_snd, (struct timezone *)NULL);
21197c478bd9Sstevel@tonic-gate
21207c478bd9Sstevel@tonic-gate /* if packet is big enough to store timeval OR ... */
21217c478bd9Sstevel@tonic-gate if ((datalen >= sizeof (struct timeval)) ||
21227c478bd9Sstevel@tonic-gate (family == AF_INET && use_icmp_ts))
21237c478bd9Sstevel@tonic-gate *tp = t_snd;
21247c478bd9Sstevel@tonic-gate
21257c478bd9Sstevel@tonic-gate if (family == AF_INET && use_icmp_ts) {
21267c478bd9Sstevel@tonic-gate start = sizeof (struct id_ts); /* skip for ICMP timestamps */
21277c478bd9Sstevel@tonic-gate /* Number of milliseconds since midnight */
21287c478bd9Sstevel@tonic-gate icp->icmp_otime = htonl((tp->tv_sec % (24*60*60)) * 1000 +
21297c478bd9Sstevel@tonic-gate tp->tv_usec / 1000);
21307c478bd9Sstevel@tonic-gate }
21317c478bd9Sstevel@tonic-gate
21327c478bd9Sstevel@tonic-gate for (i = start; i < datalen; i++)
21337c478bd9Sstevel@tonic-gate *datap++ = i;
21347c478bd9Sstevel@tonic-gate
21357c478bd9Sstevel@tonic-gate if (family == AF_INET) {
21367c478bd9Sstevel@tonic-gate if (!use_udp)
21377c478bd9Sstevel@tonic-gate icp->icmp_cksum = in_cksum((ushort_t *)icp, cc);
21387c478bd9Sstevel@tonic-gate
21397c478bd9Sstevel@tonic-gate i = sendto(send_sock, (char *)out_pkt, cc, 0, whereto,
21407c478bd9Sstevel@tonic-gate sizeof (struct sockaddr_in));
21417c478bd9Sstevel@tonic-gate } else {
21427c478bd9Sstevel@tonic-gate /*
21437c478bd9Sstevel@tonic-gate * Fill in the rest of the msghdr structure. msg_control is set
21447c478bd9Sstevel@tonic-gate * in set_ancillary_data().
21457c478bd9Sstevel@tonic-gate */
21467c478bd9Sstevel@tonic-gate msg6->msg_name = to6;
21477c478bd9Sstevel@tonic-gate msg6->msg_namelen = sizeof (struct sockaddr_in6);
21487c478bd9Sstevel@tonic-gate
21497c478bd9Sstevel@tonic-gate iov.iov_base = out_pkt;
21507c478bd9Sstevel@tonic-gate iov.iov_len = cc;
21517c478bd9Sstevel@tonic-gate
21527c478bd9Sstevel@tonic-gate msg6->msg_iov = &iov;
21537c478bd9Sstevel@tonic-gate msg6->msg_iovlen = 1;
21547c478bd9Sstevel@tonic-gate
21557c478bd9Sstevel@tonic-gate i = sendmsg(send_sock, msg6, 0);
21567c478bd9Sstevel@tonic-gate }
21577c478bd9Sstevel@tonic-gate
21587c478bd9Sstevel@tonic-gate /* This is a more precise time (right after we send the packet) */
21597c478bd9Sstevel@tonic-gate t_last_probe_sent = gethrtime();
21607c478bd9Sstevel@tonic-gate
21617c478bd9Sstevel@tonic-gate if (i < 0 || i != cc) {
21627c478bd9Sstevel@tonic-gate if (i < 0) {
21637c478bd9Sstevel@tonic-gate Fprintf(stderr, "%s: sendto %s\n", progname,
21647c478bd9Sstevel@tonic-gate strerror(errno));
21657c478bd9Sstevel@tonic-gate if (!stats)
21667c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
21677c478bd9Sstevel@tonic-gate }
21687c478bd9Sstevel@tonic-gate Printf("ping: wrote %s %d chars, ret=%d\n",
21697c478bd9Sstevel@tonic-gate targethost, cc, i);
21707c478bd9Sstevel@tonic-gate (void) fflush(stdout);
21717c478bd9Sstevel@tonic-gate }
21727c478bd9Sstevel@tonic-gate }
21737c478bd9Sstevel@tonic-gate
21747c478bd9Sstevel@tonic-gate /*
21757c478bd9Sstevel@tonic-gate * Return a hostname for the given IP address.
21767c478bd9Sstevel@tonic-gate */
21777c478bd9Sstevel@tonic-gate char *
pr_name(char * addr,int family)21787c478bd9Sstevel@tonic-gate pr_name(char *addr, int family)
21797c478bd9Sstevel@tonic-gate {
21807c478bd9Sstevel@tonic-gate struct sockaddr_in sin;
21817c478bd9Sstevel@tonic-gate struct sockaddr_in6 sin6;
21827c478bd9Sstevel@tonic-gate struct sockaddr *sa;
21837c478bd9Sstevel@tonic-gate static struct in6_addr prev_addr = IN6ADDR_ANY_INIT;
21847c478bd9Sstevel@tonic-gate char *cp;
21857c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN];
21867c478bd9Sstevel@tonic-gate static char buf[NI_MAXHOST + INET6_ADDRSTRLEN + 3];
21877c478bd9Sstevel@tonic-gate uint_t slen, alen, hlen;
21887c478bd9Sstevel@tonic-gate
21897c478bd9Sstevel@tonic-gate switch (family) {
21907c478bd9Sstevel@tonic-gate case AF_INET:
21917c478bd9Sstevel@tonic-gate (void) memset(&sin, 0, sizeof (sin));
21927c478bd9Sstevel@tonic-gate slen = sizeof (struct sockaddr_in);
21937c478bd9Sstevel@tonic-gate alen = sizeof (struct in_addr);
21947c478bd9Sstevel@tonic-gate /* LINTED E_BAD_PTR_CAST_ALIGN */
21957c478bd9Sstevel@tonic-gate sin.sin_addr = *(struct in_addr *)addr;
21967c478bd9Sstevel@tonic-gate sin.sin_port = 0;
21977c478bd9Sstevel@tonic-gate sa = (struct sockaddr *)&sin;
21987c478bd9Sstevel@tonic-gate break;
21997c478bd9Sstevel@tonic-gate case AF_INET6:
22007c478bd9Sstevel@tonic-gate (void) memset(&sin6, 0, sizeof (sin6));
22017c478bd9Sstevel@tonic-gate slen = sizeof (struct sockaddr_in6);
22027c478bd9Sstevel@tonic-gate alen = sizeof (struct in6_addr);
22037c478bd9Sstevel@tonic-gate /* LINTED E_BAD_PTR_CAST_ALIGN */
22047c478bd9Sstevel@tonic-gate sin6.sin6_addr = *(struct in6_addr *)addr;
22057c478bd9Sstevel@tonic-gate sin6.sin6_port = 0;
22067c478bd9Sstevel@tonic-gate sa = (struct sockaddr *)&sin6;
22077c478bd9Sstevel@tonic-gate break;
22087c478bd9Sstevel@tonic-gate default:
22097c478bd9Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), "<invalid address family>");
22107c478bd9Sstevel@tonic-gate return (buf);
22117c478bd9Sstevel@tonic-gate }
22127c478bd9Sstevel@tonic-gate sa->sa_family = family;
22137c478bd9Sstevel@tonic-gate
22147c478bd9Sstevel@tonic-gate /* compare with the buffered (previous) lookup */
22157c478bd9Sstevel@tonic-gate if (memcmp(addr, &prev_addr, alen) != 0) {
22167c478bd9Sstevel@tonic-gate int flags = (nflag) ? NI_NUMERICHOST : NI_NAMEREQD;
2217b08923d6SRobert Mustacchi mutex_enter(&ns_lock);
2218b08923d6SRobert Mustacchi ns_active = _B_TRUE;
2219b08923d6SRobert Mustacchi ns_starttime = gethrtime();
2220b08923d6SRobert Mustacchi mutex_exit(&ns_lock);
22217c478bd9Sstevel@tonic-gate if (getnameinfo(sa, slen, buf, sizeof (buf),
22227c478bd9Sstevel@tonic-gate NULL, 0, flags) != 0) {
22237c478bd9Sstevel@tonic-gate /* getnameinfo() failed; return just the address */
22247c478bd9Sstevel@tonic-gate if (inet_ntop(family, (const void*)addr,
22257c478bd9Sstevel@tonic-gate buf, sizeof (buf)) == NULL)
22267c478bd9Sstevel@tonic-gate buf[0] = 0;
22277c478bd9Sstevel@tonic-gate } else if (!nflag) {
22287c478bd9Sstevel@tonic-gate /* append numeric address to hostname string */
22297c478bd9Sstevel@tonic-gate hlen = strlen(buf);
22307c478bd9Sstevel@tonic-gate cp = (char *)(buf + hlen);
22317c478bd9Sstevel@tonic-gate (void) snprintf(cp, sizeof (buf) - hlen, " (%s)",
22327c478bd9Sstevel@tonic-gate inet_ntop(family, (const void *)addr, abuf,
22337c478bd9Sstevel@tonic-gate sizeof (abuf)));
22347c478bd9Sstevel@tonic-gate }
2235b08923d6SRobert Mustacchi mutex_enter(&ns_lock);
2236b08923d6SRobert Mustacchi ns_active = _B_FALSE;
2237b08923d6SRobert Mustacchi mutex_exit(&ns_lock);
22387c478bd9Sstevel@tonic-gate
22397c478bd9Sstevel@tonic-gate /* LINTED E_BAD_PTR_CAST_ALIGN */
22407c478bd9Sstevel@tonic-gate prev_addr = *(struct in6_addr *)addr;
22417c478bd9Sstevel@tonic-gate }
22427c478bd9Sstevel@tonic-gate return (buf);
22437c478bd9Sstevel@tonic-gate }
22447c478bd9Sstevel@tonic-gate
22457c478bd9Sstevel@tonic-gate /*
22467c478bd9Sstevel@tonic-gate * Return the protocol string, given its protocol number.
22477c478bd9Sstevel@tonic-gate */
22487c478bd9Sstevel@tonic-gate char *
pr_protocol(int prot)22497c478bd9Sstevel@tonic-gate pr_protocol(int prot)
22507c478bd9Sstevel@tonic-gate {
22517c478bd9Sstevel@tonic-gate static char buf[20];
22527c478bd9Sstevel@tonic-gate
22537c478bd9Sstevel@tonic-gate switch (prot) {
22547c478bd9Sstevel@tonic-gate case IPPROTO_ICMPV6:
22557c478bd9Sstevel@tonic-gate (void) strlcpy(buf, "icmp6", sizeof (buf));
22567c478bd9Sstevel@tonic-gate break;
22577c478bd9Sstevel@tonic-gate
22587c478bd9Sstevel@tonic-gate case IPPROTO_ICMP:
22597c478bd9Sstevel@tonic-gate (void) strlcpy(buf, "icmp", sizeof (buf));
22607c478bd9Sstevel@tonic-gate break;
22617c478bd9Sstevel@tonic-gate
22627c478bd9Sstevel@tonic-gate case IPPROTO_TCP:
22637c478bd9Sstevel@tonic-gate (void) strlcpy(buf, "tcp", sizeof (buf));
22647c478bd9Sstevel@tonic-gate break;
22657c478bd9Sstevel@tonic-gate
22667c478bd9Sstevel@tonic-gate case IPPROTO_UDP:
22677c478bd9Sstevel@tonic-gate (void) strlcpy(buf, "udp", sizeof (buf));
22687c478bd9Sstevel@tonic-gate break;
22697c478bd9Sstevel@tonic-gate
22707c478bd9Sstevel@tonic-gate default:
22717c478bd9Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), "prot %d", prot);
22727c478bd9Sstevel@tonic-gate break;
22737c478bd9Sstevel@tonic-gate }
22747c478bd9Sstevel@tonic-gate
22757c478bd9Sstevel@tonic-gate return (buf);
22767c478bd9Sstevel@tonic-gate }
22777c478bd9Sstevel@tonic-gate
22787c478bd9Sstevel@tonic-gate /*
22797c478bd9Sstevel@tonic-gate * Checks if value is between seq_begin and seq_begin+seq_len. Note that
22807c478bd9Sstevel@tonic-gate * sequence numbers wrap around after MAX_ICMP_SEQ (== MAX_PORT).
22817c478bd9Sstevel@tonic-gate */
22827c478bd9Sstevel@tonic-gate boolean_t
seq_match(ushort_t seq_begin,int seq_len,ushort_t value)22837c478bd9Sstevel@tonic-gate seq_match(ushort_t seq_begin, int seq_len, ushort_t value)
22847c478bd9Sstevel@tonic-gate {
22857c478bd9Sstevel@tonic-gate /*
22867c478bd9Sstevel@tonic-gate * If seq_len is too big, like some value greater than MAX_ICMP_SEQ/2,
22877c478bd9Sstevel@tonic-gate * truncate it down to MAX_ICMP_SEQ/2. We are not going to accept any
22887c478bd9Sstevel@tonic-gate * reply which come 83hr later!
22897c478bd9Sstevel@tonic-gate */
22907c478bd9Sstevel@tonic-gate if (seq_len > MAX_ICMP_SEQ / 2) {
22917c478bd9Sstevel@tonic-gate seq_begin = (seq_begin + seq_len - MAX_ICMP_SEQ / 2) %
22927c478bd9Sstevel@tonic-gate (MAX_ICMP_SEQ + 1);
22937c478bd9Sstevel@tonic-gate seq_len = MAX_ICMP_SEQ / 2;
22947c478bd9Sstevel@tonic-gate }
22957c478bd9Sstevel@tonic-gate
22967c478bd9Sstevel@tonic-gate if (PINGSEQ_LEQ(seq_begin, value) &&
22977c478bd9Sstevel@tonic-gate PINGSEQ_LEQ(value, (seq_begin + seq_len - 1) % (MAX_ICMP_SEQ + 1)))
22987c478bd9Sstevel@tonic-gate return (_B_TRUE);
22997c478bd9Sstevel@tonic-gate else
23007c478bd9Sstevel@tonic-gate return (_B_FALSE);
23017c478bd9Sstevel@tonic-gate }
23027c478bd9Sstevel@tonic-gate
23037c478bd9Sstevel@tonic-gate /*
23047c478bd9Sstevel@tonic-gate * For a given icmp_seq, find which destination address we must have sent this
23057c478bd9Sstevel@tonic-gate * to.
23067c478bd9Sstevel@tonic-gate */
23077c478bd9Sstevel@tonic-gate void
find_dstaddr(ushort_t icmpseq,union any_in_addr * ipaddr)23087c478bd9Sstevel@tonic-gate find_dstaddr(ushort_t icmpseq, union any_in_addr *ipaddr)
23097c478bd9Sstevel@tonic-gate {
23107c478bd9Sstevel@tonic-gate struct targetaddr *target = targetaddr_list;
23117c478bd9Sstevel@tonic-gate int real_seq;
23127c478bd9Sstevel@tonic-gate int targetaddr_index;
23137c478bd9Sstevel@tonic-gate int real_npackets;
23147c478bd9Sstevel@tonic-gate int i;
23157c478bd9Sstevel@tonic-gate
23167c478bd9Sstevel@tonic-gate ipaddr->addr6 = in6addr_any;
23177c478bd9Sstevel@tonic-gate
23187c478bd9Sstevel@tonic-gate /*
23197c478bd9Sstevel@tonic-gate * If this is probe_all and not stats, then the number of probes sent to
23207c478bd9Sstevel@tonic-gate * each IP address may be different (remember, we stop sending to one IP
23217c478bd9Sstevel@tonic-gate * address as soon as it replies). They are stored in target->num_sent
23227c478bd9Sstevel@tonic-gate * field. Since we don't wrap around the list (!stats), they are also
23237c478bd9Sstevel@tonic-gate * preserved.
23247c478bd9Sstevel@tonic-gate */
23257c478bd9Sstevel@tonic-gate if (probe_all && !stats) {
23267c478bd9Sstevel@tonic-gate do {
23277c478bd9Sstevel@tonic-gate if (seq_match(target->starting_seq_num,
23287c478bd9Sstevel@tonic-gate target->num_sent, icmpseq)) {
23297c478bd9Sstevel@tonic-gate ipaddr->addr6 = target->dst_addr.addr6;
23307c478bd9Sstevel@tonic-gate /*
23317c478bd9Sstevel@tonic-gate * We are not immediately return()ing here.
23327c478bd9Sstevel@tonic-gate * Because of wrapping, we might find another
23337c478bd9Sstevel@tonic-gate * match later, which is more likely to be the
23347c478bd9Sstevel@tonic-gate * real one.
23357c478bd9Sstevel@tonic-gate */
23367c478bd9Sstevel@tonic-gate }
23377c478bd9Sstevel@tonic-gate target = target->next;
23387c478bd9Sstevel@tonic-gate } while (target != NULL);
23397c478bd9Sstevel@tonic-gate } else {
23407c478bd9Sstevel@tonic-gate /*
23417c478bd9Sstevel@tonic-gate * Find the absolute (non-wrapped) seq number within the last
23427c478bd9Sstevel@tonic-gate * 64K
23437c478bd9Sstevel@tonic-gate */
23447c478bd9Sstevel@tonic-gate if (icmpseq < (ntransmitted % (MAX_ICMP_SEQ + 1))) {
23457c478bd9Sstevel@tonic-gate real_seq = num_wraps * (MAX_ICMP_SEQ + 1) + icmpseq;
23467c478bd9Sstevel@tonic-gate } else {
23477c478bd9Sstevel@tonic-gate real_seq = (num_wraps - 1) * (MAX_ICMP_SEQ + 1) +
23487c478bd9Sstevel@tonic-gate icmpseq;
23497c478bd9Sstevel@tonic-gate }
23507c478bd9Sstevel@tonic-gate
23517c478bd9Sstevel@tonic-gate /* Make sure it's non-negative */
23527c478bd9Sstevel@tonic-gate if (real_seq < 0)
23537c478bd9Sstevel@tonic-gate return;
23547c478bd9Sstevel@tonic-gate real_npackets = (npackets == 0) ? 1 : npackets;
23557c478bd9Sstevel@tonic-gate
23567c478bd9Sstevel@tonic-gate /*
23577c478bd9Sstevel@tonic-gate * We sent npackets many packets to each of those
23587c478bd9Sstevel@tonic-gate * num_targetaddrs many IP addresses.
23597c478bd9Sstevel@tonic-gate */
23607c478bd9Sstevel@tonic-gate targetaddr_index =
23617c478bd9Sstevel@tonic-gate (real_seq % (num_targetaddrs * real_npackets)) /
23627c478bd9Sstevel@tonic-gate real_npackets;
23637c478bd9Sstevel@tonic-gate for (i = 0; i < targetaddr_index; i++)
23647c478bd9Sstevel@tonic-gate target = target->next;
23657c478bd9Sstevel@tonic-gate ipaddr->addr6 = target->dst_addr.addr6;
23667c478bd9Sstevel@tonic-gate }
23677c478bd9Sstevel@tonic-gate }
23687c478bd9Sstevel@tonic-gate
23697c478bd9Sstevel@tonic-gate /*
23707c478bd9Sstevel@tonic-gate * Checksum routine for Internet Protocol family headers (C Version)
23717c478bd9Sstevel@tonic-gate */
23727c478bd9Sstevel@tonic-gate static ushort_t
in_cksum(ushort_t * addr,int len)23737c478bd9Sstevel@tonic-gate in_cksum(ushort_t *addr, int len)
23747c478bd9Sstevel@tonic-gate {
23757c478bd9Sstevel@tonic-gate int nleft = len;
23767c478bd9Sstevel@tonic-gate ushort_t *w = addr;
23777c478bd9Sstevel@tonic-gate ushort_t answer;
23787c478bd9Sstevel@tonic-gate ushort_t odd_byte = 0;
23797c478bd9Sstevel@tonic-gate int sum = 0;
23807c478bd9Sstevel@tonic-gate
23817c478bd9Sstevel@tonic-gate /*
23827c478bd9Sstevel@tonic-gate * Our algorithm is simple, using a 32 bit accumulator (sum),
23837c478bd9Sstevel@tonic-gate * we add sequential 16 bit words to it, and at the end, fold
23847c478bd9Sstevel@tonic-gate * back all the carry bits from the top 16 bits into the lower
23857c478bd9Sstevel@tonic-gate * 16 bits.
23867c478bd9Sstevel@tonic-gate */
23877c478bd9Sstevel@tonic-gate while (nleft > 1) {
23887c478bd9Sstevel@tonic-gate sum += *w++;
23897c478bd9Sstevel@tonic-gate nleft -= 2;
23907c478bd9Sstevel@tonic-gate }
23917c478bd9Sstevel@tonic-gate
23927c478bd9Sstevel@tonic-gate /* mop up an odd byte, if necessary */
23937c478bd9Sstevel@tonic-gate if (nleft == 1) {
23947c478bd9Sstevel@tonic-gate *(uchar_t *)(&odd_byte) = *(uchar_t *)w;
23957c478bd9Sstevel@tonic-gate sum += odd_byte;
23967c478bd9Sstevel@tonic-gate }
23977c478bd9Sstevel@tonic-gate
23987c478bd9Sstevel@tonic-gate /*
23997c478bd9Sstevel@tonic-gate * add back carry outs from top 16 bits to low 16 bits
24007c478bd9Sstevel@tonic-gate */
24017c478bd9Sstevel@tonic-gate sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
24027c478bd9Sstevel@tonic-gate sum += (sum >> 16); /* add carry */
24037c478bd9Sstevel@tonic-gate answer = ~sum; /* truncate to 16 bits */
24047c478bd9Sstevel@tonic-gate return (answer);
24057c478bd9Sstevel@tonic-gate }
24067c478bd9Sstevel@tonic-gate
24077c478bd9Sstevel@tonic-gate /*
24087c478bd9Sstevel@tonic-gate * Subtract 2 timeval structs: out = out - in.
24097c478bd9Sstevel@tonic-gate * Out is assumed to be >= in.
24107c478bd9Sstevel@tonic-gate */
24117c478bd9Sstevel@tonic-gate void
tvsub(struct timeval * out,struct timeval * in)24127c478bd9Sstevel@tonic-gate tvsub(struct timeval *out, struct timeval *in)
24137c478bd9Sstevel@tonic-gate {
24147c478bd9Sstevel@tonic-gate if ((out->tv_usec -= in->tv_usec) < 0) {
24157c478bd9Sstevel@tonic-gate out->tv_sec--;
24167c478bd9Sstevel@tonic-gate out->tv_usec += 1000000;
24177c478bd9Sstevel@tonic-gate }
24187c478bd9Sstevel@tonic-gate out->tv_sec -= in->tv_sec;
24197c478bd9Sstevel@tonic-gate }
24207c478bd9Sstevel@tonic-gate
24217c478bd9Sstevel@tonic-gate /*
24227c478bd9Sstevel@tonic-gate * Print out statistics, and give up.
24237c478bd9Sstevel@tonic-gate * Heavily buffered STDIO is used here, so that all the statistics
24247c478bd9Sstevel@tonic-gate * will be written with 1 sys-write call. This is nice when more
24257c478bd9Sstevel@tonic-gate * than one copy of the program is running on a terminal; it prevents
24267c478bd9Sstevel@tonic-gate * the statistics output from becoming intermingled.
24277c478bd9Sstevel@tonic-gate */
24287c478bd9Sstevel@tonic-gate static void
finish()24297c478bd9Sstevel@tonic-gate finish()
24307c478bd9Sstevel@tonic-gate {
24317c478bd9Sstevel@tonic-gate Printf("\n----%s PING Statistics----\n", targethost);
24327c478bd9Sstevel@tonic-gate Printf("%d packets transmitted, ", ntransmitted);
24337c478bd9Sstevel@tonic-gate Printf("%d packets received, ", nreceived);
24347c478bd9Sstevel@tonic-gate if (ntransmitted) {
24357c478bd9Sstevel@tonic-gate if (nreceived <= ntransmitted) {
24367c478bd9Sstevel@tonic-gate Printf("%d%% packet loss",
24377c478bd9Sstevel@tonic-gate (int)(((ntransmitted-nreceived)*100) /
24387c478bd9Sstevel@tonic-gate ntransmitted));
24397c478bd9Sstevel@tonic-gate } else {
24407c478bd9Sstevel@tonic-gate Printf("%.2f times amplification",
24417c478bd9Sstevel@tonic-gate (double)nreceived / (double)ntransmitted);
24427c478bd9Sstevel@tonic-gate }
24437c478bd9Sstevel@tonic-gate }
24447c478bd9Sstevel@tonic-gate (void) putchar('\n');
24457c478bd9Sstevel@tonic-gate
24467c478bd9Sstevel@tonic-gate /* if packet is big enough to store timeval AND ... */
24477c478bd9Sstevel@tonic-gate if ((datalen >= sizeof (struct timeval)) && (nreceived > 0)) {
24487c478bd9Sstevel@tonic-gate double mean = (double)tsum / nreceived;
24497c478bd9Sstevel@tonic-gate double smean = (double)tsum2 / nreceived;
24507c478bd9Sstevel@tonic-gate double sd =
24517c478bd9Sstevel@tonic-gate sqrt(((smean - mean*mean) * nreceived) / (nreceived-1));
24527c478bd9Sstevel@tonic-gate
24537c478bd9Sstevel@tonic-gate Printf("round-trip (ms) min/avg/max/stddev = "
24543c58dfd6Sjbeck TIMEFORMAT "/" TIMEFORMAT "/"
24553c58dfd6Sjbeck TIMEFORMAT "/" TIMEFORMAT "\n",
24563c58dfd6Sjbeck (double)tmin / 1000, mean / 1000,
24573c58dfd6Sjbeck (double)tmax / 1000, sd / 1000);
24587c478bd9Sstevel@tonic-gate }
24597c478bd9Sstevel@tonic-gate (void) fflush(stdout);
24607c478bd9Sstevel@tonic-gate
24617c478bd9Sstevel@tonic-gate exit(is_alive ? EXIT_SUCCESS : EXIT_FAILURE);
24627c478bd9Sstevel@tonic-gate }
24637c478bd9Sstevel@tonic-gate
24647c478bd9Sstevel@tonic-gate /*
24657c478bd9Sstevel@tonic-gate * print the usage line
24667c478bd9Sstevel@tonic-gate */
24677c478bd9Sstevel@tonic-gate static void
usage(char * cmdname)24687c478bd9Sstevel@tonic-gate usage(char *cmdname)
24697c478bd9Sstevel@tonic-gate {
24707c478bd9Sstevel@tonic-gate Fprintf(stderr, "usage: %s host [timeout]\n", cmdname);
24717c478bd9Sstevel@tonic-gate Fprintf(stderr,
24727c478bd9Sstevel@tonic-gate /* CSTYLED */
2473a252e007SChris Josephes "usage: %s -s [-l | -U] [-abdDLnRrv] [-A addr_family] [-c traffic_class]\n\t"
24744c10bc16Spwernau "[-g gateway [-g gateway ...]] [-N nexthop] [-F flow_label] [-I interval]\n\t"
24757c478bd9Sstevel@tonic-gate "[-i interface] [-P tos] [-p port] [-t ttl] host [data_size] [npackets]\n",
24767c478bd9Sstevel@tonic-gate cmdname);
24777c478bd9Sstevel@tonic-gate }
24787c478bd9Sstevel@tonic-gate
24797c478bd9Sstevel@tonic-gate /*
24807c478bd9Sstevel@tonic-gate * Parse integer argument; exit with an error if it's not a number.
24817c478bd9Sstevel@tonic-gate * Now it also accepts hex. values.
24827c478bd9Sstevel@tonic-gate */
24837c478bd9Sstevel@tonic-gate static int
int_arg(char * s,char * what)24847c478bd9Sstevel@tonic-gate int_arg(char *s, char *what)
24857c478bd9Sstevel@tonic-gate {
24867c478bd9Sstevel@tonic-gate char *cp;
24877c478bd9Sstevel@tonic-gate char *ep;
24887c478bd9Sstevel@tonic-gate int num;
24897c478bd9Sstevel@tonic-gate
24907c478bd9Sstevel@tonic-gate errno = 0;
24917c478bd9Sstevel@tonic-gate if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) {
24927c478bd9Sstevel@tonic-gate cp = s + 2;
24937c478bd9Sstevel@tonic-gate num = (int)strtol(cp, &ep, 16);
24947c478bd9Sstevel@tonic-gate } else {
24957c478bd9Sstevel@tonic-gate num = (int)strtol(s, &ep, 10);
24967c478bd9Sstevel@tonic-gate }
24977c478bd9Sstevel@tonic-gate
24987c478bd9Sstevel@tonic-gate if (errno || *ep != '\0' || num < 0) {
2499b08923d6SRobert Mustacchi Fprintf(stderr, "%s: bad %s: %s\n", progname, what, s);
25007c478bd9Sstevel@tonic-gate exit(EXIT_FAILURE);
25017c478bd9Sstevel@tonic-gate }
25027c478bd9Sstevel@tonic-gate
25037c478bd9Sstevel@tonic-gate return (num);
25047c478bd9Sstevel@tonic-gate }
2505b08923d6SRobert Mustacchi
2506b08923d6SRobert Mustacchi /*
2507b08923d6SRobert Mustacchi * Parse the interval into a itimerspec. The interval used to originally be
2508b08923d6SRobert Mustacchi * parsed as an integer argument. That means that one used to be able to specify
2509b08923d6SRobert Mustacchi * an interval in hex. The strtod() family honors that at times, with strtod
2510b08923d6SRobert Mustacchi * sometimes doing so depending on the compilation environment and strtof() and
2511b08923d6SRobert Mustacchi * srtold() always doing that. To facilitiate that and not worry about a
2512b08923d6SRobert Mustacchi * careless Makefile change breaking us, we instead just use strtold here, even
2513b08923d6SRobert Mustacchi * though we really don't need the precision.
2514b08923d6SRobert Mustacchi */
2515b08923d6SRobert Mustacchi static void
parse_interval(const char * s)2516*9c4b0eaaSRobert Mustacchi parse_interval(const char *s)
2517b08923d6SRobert Mustacchi {
2518b08923d6SRobert Mustacchi long double val;
2519b08923d6SRobert Mustacchi char *end;
2520b08923d6SRobert Mustacchi
2521b08923d6SRobert Mustacchi errno = 0;
2522b08923d6SRobert Mustacchi val = strtold(s, &end);
2523b08923d6SRobert Mustacchi if (errno != 0 || *end != '\0') {
2524b08923d6SRobert Mustacchi Fprintf(stderr, "%s: bad interval: %s\n", progname, s);
2525b08923d6SRobert Mustacchi exit(EXIT_FAILURE);
2526b08923d6SRobert Mustacchi }
2527b08923d6SRobert Mustacchi
2528b08923d6SRobert Mustacchi /*
2529b08923d6SRobert Mustacchi * Check values that we know are going to be bad. Anything greater than
2530b08923d6SRobert Mustacchi * INT_MAX, anything less than 0, look for specific NaNs. Also, clamp
2531b08923d6SRobert Mustacchi * the value at 0.01 seconds.
2532b08923d6SRobert Mustacchi */
2533b08923d6SRobert Mustacchi if (val == NAN || val <= 0.0 || val >= INT_MAX) {
2534b08923d6SRobert Mustacchi Fprintf(stderr, "%s: bad interval: %s\n", progname, s);
2535b08923d6SRobert Mustacchi exit(EXIT_FAILURE);
2536b08923d6SRobert Mustacchi }
2537b08923d6SRobert Mustacchi
2538*9c4b0eaaSRobert Mustacchi if (val < 0.01L) {
2539b08923d6SRobert Mustacchi Fprintf(stderr, "%s: interval too small: %Lf\n", progname, val);
2540b08923d6SRobert Mustacchi exit(EXIT_FAILURE);
2541b08923d6SRobert Mustacchi }
2542b08923d6SRobert Mustacchi
2543b08923d6SRobert Mustacchi interval.it_value.tv_sec = (long)val;
2544b08923d6SRobert Mustacchi interval.it_value.tv_nsec = (long)((val - interval.it_value.tv_sec) *
2545b08923d6SRobert Mustacchi NANOSEC);
2546b08923d6SRobert Mustacchi
2547b08923d6SRobert Mustacchi if (interval.it_value.tv_sec == 0 &&
2548b08923d6SRobert Mustacchi interval.it_value.tv_nsec < mintime) {
2549b08923d6SRobert Mustacchi mintime = interval.it_value.tv_nsec;
2550b08923d6SRobert Mustacchi }
2551b08923d6SRobert Mustacchi }
2552b08923d6SRobert Mustacchi
2553b08923d6SRobert Mustacchi /*
2554b08923d6SRobert Mustacchi * We should have an SO_TIMESTAMP message for this socket to indicate
2555b08923d6SRobert Mustacchi * the actual time that the message took. If we don't we'll fall back to
2556b08923d6SRobert Mustacchi * gettimeofday(); however, that can cause any delays due to DNS
2557b08923d6SRobert Mustacchi * resolution and the like to end up wreaking havoc on us.
2558b08923d6SRobert Mustacchi */
2559b08923d6SRobert Mustacchi void
ping_gettime(struct msghdr * msg,struct timeval * tv)2560b08923d6SRobert Mustacchi ping_gettime(struct msghdr *msg, struct timeval *tv)
2561b08923d6SRobert Mustacchi {
2562b08923d6SRobert Mustacchi struct cmsghdr *cmsg;
2563b08923d6SRobert Mustacchi
2564b08923d6SRobert Mustacchi for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL;
2565b08923d6SRobert Mustacchi cmsg = CMSG_NXTHDR(msg, cmsg)) {
2566b08923d6SRobert Mustacchi if (cmsg->cmsg_level == SOL_SOCKET &&
2567b08923d6SRobert Mustacchi cmsg->cmsg_type == SO_TIMESTAMP &&
2568b08923d6SRobert Mustacchi cmsg->cmsg_len == CMSG_LEN(sizeof (*tv))) {
2569b08923d6SRobert Mustacchi bcopy(CMSG_DATA(cmsg), tv, sizeof (*tv));
2570b08923d6SRobert Mustacchi return;
2571b08923d6SRobert Mustacchi }
2572b08923d6SRobert Mustacchi }
2573b08923d6SRobert Mustacchi
2574b08923d6SRobert Mustacchi (void) gettimeofday(tv, (struct timezone *)NULL);
2575b08923d6SRobert Mustacchi }
2576b08923d6SRobert Mustacchi
2577b08923d6SRobert Mustacchi /*
2578b08923d6SRobert Mustacchi * The purpose of this thread is to try and inform a user that we're blocked
2579b08923d6SRobert Mustacchi * doing name lookups. For various reasons, ping has to try and look up the IP
2580b08923d6SRobert Mustacchi * addresses it receives via name services unless the -n flag is specified. The
2581b08923d6SRobert Mustacchi * irony of this is that when trying to use ping to actually diagnose a broken
2582b08923d6SRobert Mustacchi * network, name services are unlikely to be available and that will result in a
2583b08923d6SRobert Mustacchi * lot of confusion as to why pings seem like they're not working. As such, we
2584b08923d6SRobert Mustacchi * basically wake up every 2 seconds and check whether or not we've hit such a
2585b08923d6SRobert Mustacchi * condition where we should inform the user via stderr.
2586b08923d6SRobert Mustacchi *
2587b08923d6SRobert Mustacchi * Once they've been informed, we do not inform them again until approximately a
2588b08923d6SRobert Mustacchi * minute of time has passed, in case that things are working intermittently.
2589b08923d6SRobert Mustacchi */
2590b08923d6SRobert Mustacchi /*ARGSUSED*/
2591b08923d6SRobert Mustacchi static void *
ns_warning_thr(void * unused)2592b08923d6SRobert Mustacchi ns_warning_thr(void *unused)
2593b08923d6SRobert Mustacchi {
2594b08923d6SRobert Mustacchi for (;;) {
2595b08923d6SRobert Mustacchi hrtime_t now;
2596b08923d6SRobert Mustacchi
2597b08923d6SRobert Mustacchi (void) sleep(ns_sleeptime);
2598b08923d6SRobert Mustacchi now = gethrtime();
2599b08923d6SRobert Mustacchi mutex_enter(&ns_lock);
2600b08923d6SRobert Mustacchi if (ns_active == _B_TRUE &&
2601b08923d6SRobert Mustacchi now - ns_starttime >= ns_warntime * NANOSEC) {
2602afee3dc6SRobert Mustacchi Fprintf(stderr, "%s: warning: ICMP responses "
2603afee3dc6SRobert Mustacchi "received, but name service lookups are "
2604afee3dc6SRobert Mustacchi "taking a while. Use ping -n to disable "
2605afee3dc6SRobert Mustacchi "name service lookups.\n",
2606afee3dc6SRobert Mustacchi progname);
2607afee3dc6SRobert Mustacchi mutex_exit(&ns_lock);
2608afee3dc6SRobert Mustacchi return (NULL);
2609b08923d6SRobert Mustacchi }
2610b08923d6SRobert Mustacchi mutex_exit(&ns_lock);
2611b08923d6SRobert Mustacchi }
2612b08923d6SRobert Mustacchi
2613b08923d6SRobert Mustacchi /* LINTED: E_STMT_NOT_REACHED */
2614b08923d6SRobert Mustacchi return (NULL);
2615b08923d6SRobert Mustacchi }
2616