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