ping.c revision 109731
1/* 2 * Copyright (c) 1989, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Mike Muuss. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 37#ifndef lint 38static const char copyright[] = 39"@(#) Copyright (c) 1989, 1993\n\ 40 The Regents of the University of California. All rights reserved.\n"; 41#endif /* not lint */ 42 43#ifndef lint 44#if 0 45static char sccsid[] = "@(#)ping.c 8.1 (Berkeley) 6/5/93"; 46#endif 47static const char rcsid[] = 48 "$FreeBSD: head/sbin/ping/ping.c 109731 2003-01-23 12:48:12Z maxim $"; 49#endif /* not lint */ 50 51/* 52 * P I N G . C 53 * 54 * Using the Internet Control Message Protocol (ICMP) "ECHO" facility, 55 * measure round-trip-delays and packet loss across network paths. 56 * 57 * Author - 58 * Mike Muuss 59 * U. S. Army Ballistic Research Laboratory 60 * December, 1983 61 * 62 * Status - 63 * Public Domain. Distribution Unlimited. 64 * Bugs - 65 * More statistics could always be gathered. 66 * This program has to run SUID to ROOT to access the ICMP socket. 67 */ 68 69#include <sys/param.h> /* NB: we rely on this for <sys/types.h> */ 70#include <sys/sysctl.h> 71 72#include <ctype.h> 73#include <err.h> 74#include <errno.h> 75#include <math.h> 76#include <netdb.h> 77#include <signal.h> 78#include <stdio.h> 79#include <stdlib.h> 80#include <string.h> 81#include <sysexits.h> 82#include <termios.h> 83#include <unistd.h> 84 85#include <sys/socket.h> 86#include <sys/time.h> 87#include <sys/uio.h> 88 89#include <netinet/in.h> 90#include <netinet/in_systm.h> 91#include <netinet/ip.h> 92#include <netinet/ip_icmp.h> 93#include <netinet/ip_var.h> 94#include <arpa/inet.h> 95 96#ifdef IPSEC 97#include <netinet6/ipsec.h> 98#endif /*IPSEC*/ 99 100#define INADDR_LEN ((int)sizeof(in_addr_t)) 101#define PHDR_LEN ((int)sizeof(struct timeval)) 102#define DEFDATALEN (64 - PHDR_LEN) /* default data length */ 103#define FLOOD_BACKOFF 20000 /* usecs to back off if F_FLOOD mode */ 104 /* runs out of buffer space */ 105#define MAXIPLEN (sizeof(struct ip) + MAX_IPOPTLEN) 106#define MAXICMPLEN (ICMP_ADVLENMIN + MAX_IPOPTLEN) 107#define MINICMPLEN ICMP_MINLEN 108#define MAXPAYLOAD (IP_MAXPACKET - MAXIPLEN - MINICMPLEN) 109#define MAXWAIT 10 /* max seconds to wait for response */ 110#define MAXALARM (60 * 60) /* max seconds for alarm timeout */ 111#define MAXTOS 255 112 113#define A(bit) rcvd_tbl[(bit)>>3] /* identify byte in array */ 114#define B(bit) (1 << ((bit) & 0x07)) /* identify bit in byte */ 115#define SET(bit) (A(bit) |= B(bit)) 116#define CLR(bit) (A(bit) &= (~B(bit))) 117#define TST(bit) (A(bit) & B(bit)) 118 119/* various options */ 120int options; 121#define F_FLOOD 0x0001 122#define F_INTERVAL 0x0002 123#define F_NUMERIC 0x0004 124#define F_PINGFILLED 0x0008 125#define F_QUIET 0x0010 126#define F_RROUTE 0x0020 127#define F_SO_DEBUG 0x0040 128#define F_SO_DONTROUTE 0x0080 129#define F_VERBOSE 0x0100 130#define F_QUIET2 0x0200 131#define F_NOLOOP 0x0400 132#define F_MTTL 0x0800 133#define F_MIF 0x1000 134#define F_AUDIBLE 0x2000 135#ifdef IPSEC 136#ifdef IPSEC_POLICY_IPSEC 137#define F_POLICY 0x4000 138#endif /*IPSEC_POLICY_IPSEC*/ 139#endif /*IPSEC*/ 140#define F_TTL 0x8000 141#define F_MISSED 0x10000 142#define F_ONCE 0x20000 143#define F_HDRINCL 0x40000 144 145/* 146 * MAX_DUP_CHK is the number of bits in received table, i.e. the maximum 147 * number of received sequence numbers we can keep track of. Change 128 148 * to 8192 for complete accuracy... 149 */ 150#define MAX_DUP_CHK (8 * 128) 151int mx_dup_ck = MAX_DUP_CHK; 152char rcvd_tbl[MAX_DUP_CHK / 8]; 153 154struct sockaddr_in whereto; /* who to ping */ 155int datalen = DEFDATALEN; 156int s; /* socket file descriptor */ 157u_char outpackhdr[IP_MAXPACKET], *outpack; 158char BSPACE = '\b'; /* characters written for flood */ 159char BBELL = '\a'; /* characters written for MISSED and AUDIBLE */ 160char DOT = '.'; 161char *hostname; 162char *shostname; 163int ident; /* process id to identify our packets */ 164int uid; /* cached uid for micro-optimization */ 165 166/* counters */ 167long npackets; /* max packets to transmit */ 168long nreceived; /* # of packets we got back */ 169long nrepeats; /* number of duplicates */ 170long ntransmitted; /* sequence # for outbound packets = #sent */ 171long nmissedmax; /* max value of ntransmitted - nreceived - 1 */ 172int interval = 1000; /* interval between packets, ms */ 173 174/* timing */ 175int timing; /* flag to do timing */ 176double tmin = 999999999.0; /* minimum round trip time */ 177double tmax = 0.0; /* maximum round trip time */ 178double tsum = 0.0; /* sum of all times, for doing average */ 179double tsumsq = 0.0; /* sum of all times squared, for std. dev. */ 180 181volatile sig_atomic_t finish_up; /* nonzero if we've been told to finish up */ 182int reset_kerninfo; 183volatile sig_atomic_t siginfo_p; 184 185static void fill(char *, char *); 186static u_short in_cksum(u_short *, int); 187static void check_status(void); 188static void finish(void) __dead2; 189static void pinger(void); 190static char *pr_addr(struct in_addr); 191static void pr_icmph(struct icmp *); 192static void pr_iph(struct ip *); 193static void pr_pack(char *, int, struct sockaddr_in *, struct timeval *); 194static void pr_retip(struct ip *); 195static void status(int); 196static void stopit(int); 197static void tvsub(struct timeval *, struct timeval *); 198static void usage(void) __dead2; 199 200int 201main(argc, argv) 202 int argc; 203 char *const *argv; 204{ 205 struct in_addr ifaddr; 206 struct iovec iov; 207 struct ip *ip; 208 struct msghdr msg; 209 struct sigaction si_sa; 210 struct sockaddr_in from, sin; 211 struct termios ts; 212 struct timeval last, intvl; 213 struct hostent *hp; 214 struct sockaddr_in *to; 215 double t; 216 size_t sz; 217 u_char *datap, packet[IP_MAXPACKET]; 218 char *ep, *source, *target; 219#ifdef IPSEC_POLICY_IPSEC 220 char *policy_in, *policy_out; 221#endif 222 u_long alarmtimeout, ultmp; 223 int ch, df, hold, i, mib[4], packlen, preload, sockerrno, 224 almost_done = 0, tos, ttl; 225 char ctrl[CMSG_SPACE(sizeof(struct timeval))]; 226 char hnamebuf[MAXHOSTNAMELEN], snamebuf[MAXHOSTNAMELEN]; 227#ifdef IP_OPTIONS 228 char rspace[MAX_IPOPTLEN]; /* record route space */ 229#endif 230 unsigned char mttl, loop; 231 232 source = NULL; 233#ifdef IPSEC_POLICY_IPSEC 234 policy_in = policy_out = NULL; 235#endif 236 237 /* 238 * Do the stuff that we need root priv's for *first*, and 239 * then drop our setuid bit. Save error reporting for 240 * after arg parsing. 241 */ 242 s = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); 243 sockerrno = errno; 244 245 setuid(getuid()); 246 uid = getuid(); 247 248 alarmtimeout = df = preload = tos = 0; 249 250 outpack = outpackhdr + sizeof(struct ip); 251 datap = &outpack[MINICMPLEN + PHDR_LEN]; 252 while ((ch = getopt(argc, argv, 253 "ADI:LQRS:T:c:adfi:l:m:nop:qrs:t:vz:" 254#ifdef IPSEC 255#ifdef IPSEC_POLICY_IPSEC 256 "P:" 257#endif /*IPSEC_POLICY_IPSEC*/ 258#endif /*IPSEC*/ 259 )) != -1) 260 { 261 switch(ch) { 262 case 'A': 263 options |= F_MISSED; 264 break; 265 case 'a': 266 options |= F_AUDIBLE; 267 break; 268 case 'c': 269 ultmp = strtoul(optarg, &ep, 0); 270 if (*ep || ep == optarg || ultmp > LONG_MAX || !ultmp) 271 errx(EX_USAGE, 272 "invalid count of packets to transmit: `%s'", 273 optarg); 274 npackets = ultmp; 275 break; 276 case 'D': 277 options |= F_HDRINCL; 278 df = 1; 279 break; 280 case 'd': 281 options |= F_SO_DEBUG; 282 break; 283 case 'f': 284 if (uid) { 285 errno = EPERM; 286 err(EX_NOPERM, "-f flag"); 287 } 288 options |= F_FLOOD; 289 setbuf(stdout, (char *)NULL); 290 break; 291 case 'i': /* wait between sending packets */ 292 t = strtod(optarg, &ep) * 1000.0; 293 if (*ep || ep == optarg || t > (double)INT_MAX) 294 errx(EX_USAGE, "invalid timing interval: `%s'", 295 optarg); 296 options |= F_INTERVAL; 297 interval = (int)t; 298 if (uid && interval < 1000) { 299 errno = EPERM; 300 err(EX_NOPERM, "-i interval too short"); 301 } 302 break; 303 case 'I': /* multicast interface */ 304 if (inet_aton(optarg, &ifaddr) == 0) 305 errx(EX_USAGE, 306 "invalid multicast interface: `%s'", 307 optarg); 308 options |= F_MIF; 309 break; 310 case 'l': 311 ultmp = strtoul(optarg, &ep, 0); 312 if (*ep || ep == optarg || ultmp > INT_MAX) 313 errx(EX_USAGE, 314 "invalid preload value: `%s'", optarg); 315 if (uid) { 316 errno = EPERM; 317 err(EX_NOPERM, "-l flag"); 318 } 319 preload = ultmp; 320 break; 321 case 'L': 322 options |= F_NOLOOP; 323 loop = 0; 324 break; 325 case 'm': /* TTL */ 326 ultmp = strtoul(optarg, &ep, 0); 327 if (*ep || ep == optarg || ultmp > 255) 328 errx(EX_USAGE, "invalid TTL: `%s'", optarg); 329 ttl = ultmp; 330 options |= F_TTL; 331 break; 332 case 'n': 333 options |= F_NUMERIC; 334 break; 335 case 'o': 336 options |= F_ONCE; 337 break; 338 case 'p': /* fill buffer with user pattern */ 339 options |= F_PINGFILLED; 340 fill((char *)datap, optarg); 341 break; 342 case 'Q': 343 options |= F_QUIET2; 344 break; 345 case 'q': 346 options |= F_QUIET; 347 break; 348 case 'R': 349 options |= F_RROUTE; 350 break; 351 case 'r': 352 options |= F_SO_DONTROUTE; 353 break; 354 case 's': /* size of packet to send */ 355 if (uid) { 356 errno = EPERM; 357 err(EX_NOPERM, "-s flag"); 358 } 359 ultmp = strtoul(optarg, &ep, 0); 360 if (ultmp > MAXPAYLOAD) 361 errx(EX_USAGE, 362 "packet size too large: %lu > %u", 363 ultmp, MAXPAYLOAD); 364 if (*ep || ep == optarg) 365 errx(EX_USAGE, "invalid packet size: `%s'", 366 optarg); 367 datalen = ultmp; 368 break; 369 case 'S': 370 source = optarg; 371 break; 372 case 't': 373 alarmtimeout = strtoul(optarg, &ep, 0); 374 if ((alarmtimeout < 1) || (alarmtimeout == ULONG_MAX)) 375 errx(EX_USAGE, "invalid timeout: `%s'", 376 optarg); 377 if (alarmtimeout > MAXALARM) 378 errx(EX_USAGE, "invalid timeout: `%s' > %d", 379 optarg, MAXALARM); 380 alarm((int)alarmtimeout); 381 break; 382 case 'T': /* multicast TTL */ 383 ultmp = strtoul(optarg, &ep, 0); 384 if (*ep || ep == optarg || ultmp > 255) 385 errx(EX_USAGE, "invalid multicast TTL: `%s'", 386 optarg); 387 mttl = ultmp; 388 options |= F_MTTL; 389 break; 390 case 'v': 391 options |= F_VERBOSE; 392 break; 393#ifdef IPSEC 394#ifdef IPSEC_POLICY_IPSEC 395 case 'P': 396 options |= F_POLICY; 397 if (!strncmp("in", optarg, 2)) 398 policy_in = strdup(optarg); 399 else if (!strncmp("out", optarg, 3)) 400 policy_out = strdup(optarg); 401 else 402 errx(1, "invalid security policy"); 403 break; 404 case 'z': 405 options |= F_HDRINCL; 406 ultmp = strtoul(optarg, &ep, 0); 407 if (*ep || ep == optarg || ultmp > MAXTOS) 408 errx(EX_USAGE, "invalid TOS: `%s'", optarg); 409 tos = ultmp; 410 break; 411#endif /*IPSEC_POLICY_IPSEC*/ 412#endif /*IPSEC*/ 413 default: 414 usage(); 415 } 416 } 417 418 if (argc - optind != 1) 419 usage(); 420 target = argv[optind]; 421 422 if (source) { 423 bzero((char *)&sin, sizeof(sin)); 424 sin.sin_family = AF_INET; 425 if (inet_aton(source, &sin.sin_addr) != 0) { 426 shostname = source; 427 } else { 428 hp = gethostbyname2(source, AF_INET); 429 if (!hp) 430 errx(EX_NOHOST, "cannot resolve %s: %s", 431 source, hstrerror(h_errno)); 432 433 sin.sin_len = sizeof sin; 434 if (hp->h_length > sizeof(sin.sin_addr) || 435 hp->h_length < 0) 436 errx(1, "gethostbyname2: illegal address"); 437 memcpy(&sin.sin_addr, hp->h_addr_list[0], 438 sizeof(sin.sin_addr)); 439 (void)strncpy(snamebuf, hp->h_name, 440 sizeof(snamebuf) - 1); 441 snamebuf[sizeof(snamebuf) - 1] = '\0'; 442 shostname = snamebuf; 443 } 444 if (bind(s, (struct sockaddr *)&sin, sizeof sin) == -1) 445 err(1, "bind"); 446 } 447 448 bzero(&whereto, sizeof(whereto)); 449 to = &whereto; 450 to->sin_family = AF_INET; 451 to->sin_len = sizeof *to; 452 if (inet_aton(target, &to->sin_addr) != 0) { 453 hostname = target; 454 } else { 455 hp = gethostbyname2(target, AF_INET); 456 if (!hp) 457 errx(EX_NOHOST, "cannot resolve %s: %s", 458 target, hstrerror(h_errno)); 459 460 if (hp->h_length > sizeof(to->sin_addr)) 461 errx(1, "gethostbyname2 returned an illegal address"); 462 memcpy(&to->sin_addr, hp->h_addr_list[0], sizeof to->sin_addr); 463 (void)strncpy(hnamebuf, hp->h_name, sizeof(hnamebuf) - 1); 464 hnamebuf[sizeof(hnamebuf) - 1] = '\0'; 465 hostname = hnamebuf; 466 } 467 468 if (options & F_FLOOD && options & F_INTERVAL) 469 errx(EX_USAGE, "-f and -i: incompatible options"); 470 471 if (options & F_FLOOD && IN_MULTICAST(ntohl(to->sin_addr.s_addr))) 472 errx(EX_USAGE, 473 "-f flag cannot be used with multicast destination"); 474 if (options & (F_MIF | F_NOLOOP | F_MTTL) 475 && !IN_MULTICAST(ntohl(to->sin_addr.s_addr))) 476 errx(EX_USAGE, 477 "-I, -L, -T flags cannot be used with unicast destination"); 478 479 if (datalen >= PHDR_LEN) /* can we time transfer */ 480 timing = 1; 481 packlen = MAXIPLEN + MAXICMPLEN + datalen; 482 packlen = packlen > IP_MAXPACKET ? IP_MAXPACKET : packlen; 483 484 if (!(options & F_PINGFILLED)) 485 for (i = PHDR_LEN; i < datalen; ++i) 486 *datap++ = i; 487 488 ident = getpid() & 0xFFFF; 489 490 if (s < 0) { 491 errno = sockerrno; 492 err(EX_OSERR, "socket"); 493 } 494 hold = 1; 495 if (options & F_SO_DEBUG) 496 (void)setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&hold, 497 sizeof(hold)); 498 if (options & F_SO_DONTROUTE) 499 (void)setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (char *)&hold, 500 sizeof(hold)); 501#ifdef IPSEC 502#ifdef IPSEC_POLICY_IPSEC 503 if (options & F_POLICY) { 504 char *buf; 505 if (policy_in != NULL) { 506 buf = ipsec_set_policy(policy_in, strlen(policy_in)); 507 if (buf == NULL) 508 errx(EX_CONFIG, "%s", ipsec_strerror()); 509 if (setsockopt(s, IPPROTO_IP, IP_IPSEC_POLICY, 510 buf, ipsec_get_policylen(buf)) < 0) 511 err(EX_CONFIG, 512 "ipsec policy cannot be configured"); 513 free(buf); 514 } 515 516 if (policy_out != NULL) { 517 buf = ipsec_set_policy(policy_out, strlen(policy_out)); 518 if (buf == NULL) 519 errx(EX_CONFIG, "%s", ipsec_strerror()); 520 if (setsockopt(s, IPPROTO_IP, IP_IPSEC_POLICY, 521 buf, ipsec_get_policylen(buf)) < 0) 522 err(EX_CONFIG, 523 "ipsec policy cannot be configured"); 524 free(buf); 525 } 526 } 527#endif /*IPSEC_POLICY_IPSEC*/ 528#endif /*IPSEC*/ 529 530 if (options & F_HDRINCL) { 531 ip = (struct ip*)outpackhdr; 532 if (!(options & (F_TTL | F_MTTL))) { 533 mib[0] = CTL_NET; 534 mib[1] = PF_INET; 535 mib[2] = IPPROTO_IP; 536 mib[3] = IPCTL_DEFTTL; 537 sz = sizeof(ttl); 538 if (sysctl(mib, 4, &ttl, &sz, NULL, 0) == -1) 539 err(1, "sysctl(net.inet.ip.ttl)"); 540 } 541 setsockopt(s, IPPROTO_IP, IP_HDRINCL, &hold, sizeof(hold)); 542 ip->ip_v = IPVERSION; 543 ip->ip_hl = sizeof(struct ip) >> 2; 544 ip->ip_tos = tos; 545 ip->ip_id = 0; 546 ip->ip_off = df ? IP_DF : 0; 547 ip->ip_ttl = ttl; 548 ip->ip_p = IPPROTO_ICMP; 549 ip->ip_src.s_addr = source ? sin.sin_addr.s_addr : INADDR_ANY; 550 ip->ip_dst = to->sin_addr; 551 } 552 /* record route option */ 553 if (options & F_RROUTE) { 554#ifdef IP_OPTIONS 555 bzero(rspace, sizeof(rspace)); 556 rspace[IPOPT_OPTVAL] = IPOPT_RR; 557 rspace[IPOPT_OLEN] = sizeof(rspace) - 1; 558 rspace[IPOPT_OFFSET] = IPOPT_MINOFF; 559 rspace[sizeof(rspace) - 1] = IPOPT_EOL; 560 if (setsockopt(s, IPPROTO_IP, IP_OPTIONS, rspace, 561 sizeof(rspace)) < 0) 562 err(EX_OSERR, "setsockopt IP_OPTIONS"); 563#else 564 errx(EX_UNAVAILABLE, 565 "record route not available in this implementation"); 566#endif /* IP_OPTIONS */ 567 } 568 569 if (options & F_TTL) { 570 if (setsockopt(s, IPPROTO_IP, IP_TTL, &ttl, 571 sizeof(ttl)) < 0) { 572 err(EX_OSERR, "setsockopt IP_TTL"); 573 } 574 } 575 if (options & F_NOLOOP) { 576 if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, 577 sizeof(loop)) < 0) { 578 err(EX_OSERR, "setsockopt IP_MULTICAST_LOOP"); 579 } 580 } 581 if (options & F_MTTL) { 582 if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, &mttl, 583 sizeof(mttl)) < 0) { 584 err(EX_OSERR, "setsockopt IP_MULTICAST_TTL"); 585 } 586 } 587 if (options & F_MIF) { 588 if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &ifaddr, 589 sizeof(ifaddr)) < 0) { 590 err(EX_OSERR, "setsockopt IP_MULTICAST_IF"); 591 } 592 } 593#ifdef SO_TIMESTAMP 594 { int on = 1; 595 if (setsockopt(s, SOL_SOCKET, SO_TIMESTAMP, &on, sizeof(on)) < 0) 596 err(EX_OSERR, "setsockopt SO_TIMESTAMP"); 597 } 598#endif 599 600 /* 601 * When pinging the broadcast address, you can get a lot of answers. 602 * Doing something so evil is useful if you are trying to stress the 603 * ethernet, or just want to fill the arp cache to get some stuff for 604 * /etc/ethers. But beware: RFC 1122 allows hosts to ignore broadcast 605 * or multicast pings if they wish. 606 */ 607 608 /* 609 * XXX receive buffer needs undetermined space for mbuf overhead 610 * as well. 611 */ 612 hold = IP_MAXPACKET + 128; 613 (void)setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&hold, 614 sizeof(hold)); 615 616 if (!uid) { 617 (void)setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&hold, 618 sizeof(hold)); 619 } 620 621 if (to->sin_family == AF_INET) { 622 (void)printf("PING %s (%s)", hostname, 623 inet_ntoa(to->sin_addr)); 624 if (source) 625 (void)printf(" from %s", shostname); 626 (void)printf(": %d data bytes\n", datalen); 627 } else 628 (void)printf("PING %s: %d data bytes\n", hostname, datalen); 629 630 /* 631 * Use sigaction() instead of signal() to get unambiguous semantics, 632 * in particular with SA_RESTART not set. 633 */ 634 635 sigemptyset(&si_sa.sa_mask); 636 si_sa.sa_flags = 0; 637 638 si_sa.sa_handler = stopit; 639 if (sigaction(SIGINT, &si_sa, 0) == -1) { 640 err(EX_OSERR, "sigaction SIGINT"); 641 } 642 643 si_sa.sa_handler = status; 644 if (sigaction(SIGINFO, &si_sa, 0) == -1) { 645 err(EX_OSERR, "sigaction"); 646 } 647 648 if (alarmtimeout > 0) { 649 si_sa.sa_handler = stopit; 650 if (sigaction(SIGALRM, &si_sa, 0) == -1) 651 err(EX_OSERR, "sigaction SIGALRM"); 652 } 653 654 bzero(&msg, sizeof(msg)); 655 msg.msg_name = (caddr_t)&from; 656 msg.msg_iov = &iov; 657 msg.msg_iovlen = 1; 658#ifdef SO_TIMESTAMP 659 msg.msg_control = (caddr_t)ctrl; 660#endif 661 iov.iov_base = packet; 662 iov.iov_len = packlen; 663 664 if (tcgetattr(STDOUT_FILENO, &ts) != -1) { 665 reset_kerninfo = !(ts.c_lflag & NOKERNINFO); 666 ts.c_lflag |= NOKERNINFO; 667 tcsetattr(STDOUT_FILENO, TCSANOW, &ts); 668 } 669 670 if (preload == 0) 671 pinger(); /* send the first ping */ 672 else { 673 if (npackets != 0 && preload > npackets) 674 preload = npackets; 675 while (preload--) /* fire off them quickies */ 676 pinger(); 677 } 678 (void)gettimeofday(&last, NULL); 679 680 if (options & F_FLOOD) { 681 intvl.tv_sec = 0; 682 intvl.tv_usec = 10000; 683 } else { 684 intvl.tv_sec = interval / 1000; 685 intvl.tv_usec = interval % 1000 * 1000; 686 } 687 688 while (!finish_up) { 689 int cc; 690 int n; 691 struct timeval timeout, now; 692 fd_set rfds; 693 694 check_status(); 695 if (s >= FD_SETSIZE) 696 errx(EX_OSERR, "descriptor too large"); 697 FD_ZERO(&rfds); 698 FD_SET(s, &rfds); 699 (void)gettimeofday(&now, NULL); 700 timeout.tv_sec = last.tv_sec + intvl.tv_sec - now.tv_sec; 701 timeout.tv_usec = last.tv_usec + intvl.tv_usec - now.tv_usec; 702 while (timeout.tv_usec < 0) { 703 timeout.tv_usec += 1000000; 704 timeout.tv_sec--; 705 } 706 while (timeout.tv_usec >= 1000000) { 707 timeout.tv_usec -= 1000000; 708 timeout.tv_sec++; 709 } 710 if (timeout.tv_sec < 0) 711 timeout.tv_sec = timeout.tv_usec = 0; 712 n = select(s + 1, &rfds, NULL, NULL, &timeout); 713 if (n < 0) 714 continue; /* Must be EINTR. */ 715 if (n == 1) { 716 struct timeval *t = NULL; 717#ifdef SO_TIMESTAMP 718 struct cmsghdr *cmsg = (struct cmsghdr *)&ctrl; 719 720 msg.msg_controllen = sizeof(ctrl); 721#endif 722 msg.msg_namelen = sizeof(from); 723 if ((cc = recvmsg(s, &msg, 0)) < 0) { 724 if (errno == EINTR) 725 continue; 726 warn("recvmsg"); 727 continue; 728 } 729#ifdef SO_TIMESTAMP 730 if (cmsg->cmsg_level == SOL_SOCKET && 731 cmsg->cmsg_type == SCM_TIMESTAMP && 732 cmsg->cmsg_len == CMSG_LEN(sizeof *t)) { 733 /* Copy to avoid alignment problems: */ 734 memcpy(&now, CMSG_DATA(cmsg), sizeof(now)); 735 t = &now; 736 } 737#endif 738 if (t == NULL) { 739 (void)gettimeofday(&now, NULL); 740 t = &now; 741 } 742 pr_pack((char *)packet, cc, &from, t); 743 if (options & F_ONCE && nreceived || 744 npackets && nreceived >= npackets) 745 break; 746 } 747 if (n == 0 || options & F_FLOOD) { 748 if (!npackets || ntransmitted < npackets) 749 pinger(); 750 else { 751 if (almost_done) 752 break; 753 almost_done = 1; 754 intvl.tv_usec = 0; 755 if (nreceived) { 756 intvl.tv_sec = 2 * tmax / 1000; 757 if (!intvl.tv_sec) 758 intvl.tv_sec = 1; 759 } else 760 intvl.tv_sec = MAXWAIT; 761 } 762 (void)gettimeofday(&last, NULL); 763 764 if (ntransmitted - nreceived - 1 > nmissedmax) { 765 nmissedmax = ntransmitted - nreceived - 1; 766 if (options & F_MISSED) 767 (void)write(STDOUT_FILENO, &BBELL, 1); 768 } 769 } 770 } 771 finish(); 772 /* NOTREACHED */ 773 exit(0); /* Make the compiler happy */ 774} 775 776/* 777 * stopit -- 778 * Set the global bit that causes the main loop to quit. 779 * Do NOT call finish() from here, since finish() does far too much 780 * to be called from a signal handler. 781 */ 782void 783stopit(sig) 784 int sig __unused; 785{ 786 787 finish_up = 1; 788} 789 790/* 791 * pinger -- 792 * Compose and transmit an ICMP ECHO REQUEST packet. The IP packet 793 * will be added on by the kernel. The ID field is our UNIX process ID, 794 * and the sequence number is an ascending integer. The first PHDR_LEN 795 * bytes of the data portion are used to hold a UNIX "timeval" struct in 796 * host byte-order, to compute the round-trip time. 797 */ 798static void 799pinger(void) 800{ 801 struct ip *ip; 802 struct icmp *icp; 803 int cc, i; 804 u_char *packet; 805 806 packet = outpack; 807 icp = (struct icmp *)outpack; 808 icp->icmp_type = ICMP_ECHO; 809 icp->icmp_code = 0; 810 icp->icmp_cksum = 0; 811 icp->icmp_seq = htons(ntransmitted); 812 icp->icmp_id = ident; /* ID */ 813 814 CLR(ntransmitted % mx_dup_ck); 815 816 if (timing) 817 (void)gettimeofday((struct timeval *)&outpack[MINICMPLEN], 818 (struct timezone *)NULL); 819 820 cc = MINICMPLEN + datalen; 821 822 /* compute ICMP checksum here */ 823 icp->icmp_cksum = in_cksum((u_short *)icp, cc); 824 825 if (options & F_HDRINCL) { 826 cc += sizeof(struct ip); 827 ip = (struct ip *)outpackhdr; 828 ip->ip_len = cc; 829 ip->ip_sum = in_cksum((u_short *)outpackhdr, cc); 830 packet = outpackhdr; 831 } 832 i = sendto(s, (char *)packet, cc, 0, (struct sockaddr *)&whereto, 833 sizeof(whereto)); 834 835 if (i < 0 || i != cc) { 836 if (i < 0) { 837 if (options & F_FLOOD && errno == ENOBUFS) { 838 usleep(FLOOD_BACKOFF); 839 return; 840 } 841 warn("sendto"); 842 } else { 843 warn("%s: partial write: %d of %d bytes", 844 hostname, i, cc); 845 } 846 } 847 ntransmitted++; 848 if (!(options & F_QUIET) && options & F_FLOOD) 849 (void)write(STDOUT_FILENO, &DOT, 1); 850} 851 852/* 853 * pr_pack -- 854 * Print out the packet, if it came from us. This logic is necessary 855 * because ALL readers of the ICMP socket get a copy of ALL ICMP packets 856 * which arrive ('tis only fair). This permits multiple copies of this 857 * program to be run without having intermingled output (or statistics!). 858 */ 859static void 860pr_pack(buf, cc, from, tv) 861 char *buf; 862 int cc; 863 struct sockaddr_in *from; 864 struct timeval *tv; 865{ 866 struct in_addr ina; 867 u_char *cp, *dp; 868 struct icmp *icp; 869 struct ip *ip; 870 const void *tp; 871 double triptime; 872 int dupflag, hlen, i, j, seq; 873 static int old_rrlen; 874 static char old_rr[MAX_IPOPTLEN]; 875 876 /* Check the IP header */ 877 ip = (struct ip *)buf; 878 hlen = ip->ip_hl << 2; 879 if (cc < hlen + ICMP_MINLEN) { 880 if (options & F_VERBOSE) 881 warn("packet too short (%d bytes) from %s", cc, 882 inet_ntoa(from->sin_addr)); 883 return; 884 } 885 886 /* Now the ICMP part */ 887 cc -= hlen; 888 icp = (struct icmp *)(buf + hlen); 889 if (icp->icmp_type == ICMP_ECHOREPLY) { 890 if (icp->icmp_id != ident) 891 return; /* 'Twas not our ECHO */ 892 ++nreceived; 893 triptime = 0.0; 894 if (timing) { 895 struct timeval tv1; 896#ifndef icmp_data 897 tp = &icp->icmp_ip; 898#else 899 tp = icp->icmp_data; 900#endif 901 /* Copy to avoid alignment problems: */ 902 memcpy(&tv1, tp, sizeof(tv1)); 903 tvsub(tv, &tv1); 904 triptime = ((double)tv->tv_sec) * 1000.0 + 905 ((double)tv->tv_usec) / 1000.0; 906 tsum += triptime; 907 tsumsq += triptime * triptime; 908 if (triptime < tmin) 909 tmin = triptime; 910 if (triptime > tmax) 911 tmax = triptime; 912 } 913 914 seq = ntohs(icp->icmp_seq); 915 916 if (TST(seq % mx_dup_ck)) { 917 ++nrepeats; 918 --nreceived; 919 dupflag = 1; 920 } else { 921 SET(seq % mx_dup_ck); 922 dupflag = 0; 923 } 924 925 if (options & F_QUIET) 926 return; 927 928 if (options & F_FLOOD) 929 (void)write(STDOUT_FILENO, &BSPACE, 1); 930 else { 931 (void)printf("%d bytes from %s: icmp_seq=%u", cc, 932 inet_ntoa(*(struct in_addr *)&from->sin_addr.s_addr), 933 seq); 934 (void)printf(" ttl=%d", ip->ip_ttl); 935 if (timing) 936 (void)printf(" time=%.3f ms", triptime); 937 if (dupflag) 938 (void)printf(" (DUP!)"); 939 if (options & F_AUDIBLE) 940 (void)write(STDOUT_FILENO, &BBELL, 1); 941 /* check the data */ 942 cp = (u_char*)&icp->icmp_data[PHDR_LEN]; 943 dp = &outpack[MINICMPLEN + PHDR_LEN]; 944 for (i = PHDR_LEN; i < datalen; ++i, ++cp, ++dp) { 945 if (*cp != *dp) { 946 (void)printf("\nwrong data byte #%d should be 0x%x but was 0x%x", 947 i, *dp, *cp); 948 (void)printf("\ncp:"); 949 cp = (u_char*)&icp->icmp_data[0]; 950 for (i = 0; i < datalen; ++i, ++cp) { 951 if ((i % 32) == 8) 952 (void)printf("\n\t"); 953 (void)printf("%x ", *cp); 954 } 955 (void)printf("\ndp:"); 956 cp = &outpack[MINICMPLEN]; 957 for (i = 0; i < datalen; ++i, ++cp) { 958 if ((i % 32) == 8) 959 (void)printf("\n\t"); 960 (void)printf("%x ", *cp); 961 } 962 break; 963 } 964 } 965 } 966 } else { 967 /* 968 * We've got something other than an ECHOREPLY. 969 * See if it's a reply to something that we sent. 970 * We can compare IP destination, protocol, 971 * and ICMP type and ID. 972 * 973 * Only print all the error messages if we are running 974 * as root to avoid leaking information not normally 975 * available to those not running as root. 976 */ 977#ifndef icmp_data 978 struct ip *oip = &icp->icmp_ip; 979#else 980 struct ip *oip = (struct ip *)icp->icmp_data; 981#endif 982 struct icmp *oicmp = (struct icmp *)(oip + 1); 983 984 if (((options & F_VERBOSE) && uid == 0) || 985 (!(options & F_QUIET2) && 986 (oip->ip_dst.s_addr == whereto.sin_addr.s_addr) && 987 (oip->ip_p == IPPROTO_ICMP) && 988 (oicmp->icmp_type == ICMP_ECHO) && 989 (oicmp->icmp_id == ident))) { 990 (void)printf("%d bytes from %s: ", cc, 991 pr_addr(from->sin_addr)); 992 pr_icmph(icp); 993 } else 994 return; 995 } 996 997 /* Display any IP options */ 998 cp = (u_char *)buf + sizeof(struct ip); 999 1000 for (; hlen > (int)sizeof(struct ip); --hlen, ++cp) 1001 switch (*cp) { 1002 case IPOPT_EOL: 1003 hlen = 0; 1004 break; 1005 case IPOPT_LSRR: 1006 case IPOPT_SSRR: 1007 (void)printf(*cp == IPOPT_LSRR ? 1008 "\nLSRR: " : "\nSSRR: "); 1009 j = cp[IPOPT_OLEN] - IPOPT_MINOFF + 1; 1010 hlen -= 2; 1011 cp += 2; 1012 if (j >= INADDR_LEN && 1013 j <= hlen - (int)sizeof(struct ip)) { 1014 for (;;) { 1015 bcopy(++cp, &ina.s_addr, INADDR_LEN); 1016 if (ina.s_addr == 0) 1017 (void)printf("\t0.0.0.0"); 1018 else 1019 (void)printf("\t%s", 1020 pr_addr(ina)); 1021 hlen -= INADDR_LEN; 1022 cp += INADDR_LEN - 1; 1023 j -= INADDR_LEN; 1024 if (j < INADDR_LEN) 1025 break; 1026 (void)putchar('\n'); 1027 } 1028 } else 1029 (void)printf("\t(truncated route)\n"); 1030 break; 1031 case IPOPT_RR: 1032 j = cp[IPOPT_OLEN]; /* get length */ 1033 i = cp[IPOPT_OFFSET]; /* and pointer */ 1034 hlen -= 2; 1035 cp += 2; 1036 if (i > j) 1037 i = j; 1038 i = i - IPOPT_MINOFF + 1; 1039 if (i < 0 || i > (hlen - (int)sizeof(struct ip))) { 1040 old_rrlen = 0; 1041 continue; 1042 } 1043 if (i == old_rrlen 1044 && !bcmp((char *)cp, old_rr, i) 1045 && !(options & F_FLOOD)) { 1046 (void)printf("\t(same route)"); 1047 hlen -= i; 1048 cp += i; 1049 break; 1050 } 1051 old_rrlen = i; 1052 bcopy((char *)cp, old_rr, i); 1053 1054 (void)printf("\nRR: "); 1055 1056 if (i >= INADDR_LEN && 1057 i <= hlen - (int)sizeof(struct ip)) { 1058 for (;;) { 1059 bcopy(++cp, &ina.s_addr, INADDR_LEN); 1060 if (ina.s_addr == 0) 1061 (void)printf("\t0.0.0.0"); 1062 else 1063 (void)printf("\t%s", 1064 pr_addr(ina)); 1065 hlen -= INADDR_LEN; 1066 cp += INADDR_LEN - 1; 1067 i -= INADDR_LEN; 1068 if (i < INADDR_LEN) 1069 break; 1070 (void)putchar('\n'); 1071 } 1072 } else 1073 (void)printf("\t(truncated route)"); 1074 break; 1075 case IPOPT_NOP: 1076 (void)printf("\nNOP"); 1077 break; 1078 default: 1079 (void)printf("\nunknown option %x", *cp); 1080 break; 1081 } 1082 if (!(options & F_FLOOD)) { 1083 (void)putchar('\n'); 1084 (void)fflush(stdout); 1085 } 1086} 1087 1088/* 1089 * in_cksum -- 1090 * Checksum routine for Internet Protocol family headers (C Version) 1091 */ 1092u_short 1093in_cksum(addr, len) 1094 u_short *addr; 1095 int len; 1096{ 1097 int nleft, sum; 1098 u_short *w; 1099 union { 1100 u_short us; 1101 u_char uc[2]; 1102 } last; 1103 u_short answer; 1104 1105 nleft = len; 1106 sum = 0; 1107 w = addr; 1108 1109 /* 1110 * Our algorithm is simple, using a 32 bit accumulator (sum), we add 1111 * sequential 16 bit words to it, and at the end, fold back all the 1112 * carry bits from the top 16 bits into the lower 16 bits. 1113 */ 1114 while (nleft > 1) { 1115 sum += *w++; 1116 nleft -= 2; 1117 } 1118 1119 /* mop up an odd byte, if necessary */ 1120 if (nleft == 1) { 1121 last.uc[0] = *(u_char *)w; 1122 last.uc[1] = 0; 1123 sum += last.us; 1124 } 1125 1126 /* add back carry outs from top 16 bits to low 16 bits */ 1127 sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ 1128 sum += (sum >> 16); /* add carry */ 1129 answer = ~sum; /* truncate to 16 bits */ 1130 return(answer); 1131} 1132 1133/* 1134 * tvsub -- 1135 * Subtract 2 timeval structs: out = out - in. Out is assumed to 1136 * be >= in. 1137 */ 1138static void 1139tvsub(out, in) 1140 struct timeval *out, *in; 1141{ 1142 1143 if ((out->tv_usec -= in->tv_usec) < 0) { 1144 --out->tv_sec; 1145 out->tv_usec += 1000000; 1146 } 1147 out->tv_sec -= in->tv_sec; 1148} 1149 1150/* 1151 * status -- 1152 * Print out statistics when SIGINFO is received. 1153 */ 1154 1155static void 1156status(sig) 1157 int sig __unused; 1158{ 1159 1160 siginfo_p = 1; 1161} 1162 1163static void 1164check_status() 1165{ 1166 1167 if (siginfo_p) { 1168 siginfo_p = 0; 1169 (void)fprintf(stderr, 1170 "\r%ld/%ld packets received (%.0f%%) %.3f min / %.3f avg / %.3f max\n", 1171 nreceived, ntransmitted, 1172 ntransmitted ? nreceived * 100.0 / ntransmitted : 0.0, 1173 nreceived ? tmin : 0.0, 1174 nreceived + nrepeats ? tsum / (nreceived + nrepeats) : tsum, 1175 tmax); 1176 } 1177} 1178 1179/* 1180 * finish -- 1181 * Print out statistics, and give up. 1182 */ 1183static void 1184finish() 1185{ 1186 1187 struct termios ts; 1188 1189 (void)signal(SIGINT, SIG_IGN); 1190 (void)signal(SIGALRM, SIG_IGN); 1191 (void)putchar('\n'); 1192 (void)fflush(stdout); 1193 (void)printf("--- %s ping statistics ---\n", hostname); 1194 (void)printf("%ld packets transmitted, ", ntransmitted); 1195 (void)printf("%ld packets received, ", nreceived); 1196 if (nrepeats) 1197 (void)printf("+%ld duplicates, ", nrepeats); 1198 if (ntransmitted) { 1199 if (nreceived > ntransmitted) 1200 (void)printf("-- somebody's printing up packets!"); 1201 else 1202 (void)printf("%d%% packet loss", 1203 (int)(((ntransmitted - nreceived) * 100) / 1204 ntransmitted)); 1205 } 1206 (void)putchar('\n'); 1207 if (nreceived && timing) { 1208 double n = nreceived + nrepeats; 1209 double avg = tsum / n; 1210 double vari = tsumsq / n - avg * avg; 1211 (void)printf( 1212 "round-trip min/avg/max/stddev = %.3f/%.3f/%.3f/%.3f ms\n", 1213 tmin, avg, tmax, sqrt(vari)); 1214 } 1215 if (reset_kerninfo && tcgetattr(STDOUT_FILENO, &ts) != -1) { 1216 ts.c_lflag &= ~NOKERNINFO; 1217 tcsetattr(STDOUT_FILENO, TCSANOW, &ts); 1218 } 1219 1220 if (nreceived) 1221 exit(0); 1222 else 1223 exit(2); 1224} 1225 1226#ifdef notdef 1227static char *ttab[] = { 1228 "Echo Reply", /* ip + seq + udata */ 1229 "Dest Unreachable", /* net, host, proto, port, frag, sr + IP */ 1230 "Source Quench", /* IP */ 1231 "Redirect", /* redirect type, gateway, + IP */ 1232 "Echo", 1233 "Time Exceeded", /* transit, frag reassem + IP */ 1234 "Parameter Problem", /* pointer + IP */ 1235 "Timestamp", /* id + seq + three timestamps */ 1236 "Timestamp Reply", /* " */ 1237 "Info Request", /* id + sq */ 1238 "Info Reply" /* " */ 1239}; 1240#endif 1241 1242/* 1243 * pr_icmph -- 1244 * Print a descriptive string about an ICMP header. 1245 */ 1246static void 1247pr_icmph(icp) 1248 struct icmp *icp; 1249{ 1250 1251 switch(icp->icmp_type) { 1252 case ICMP_ECHOREPLY: 1253 (void)printf("Echo Reply\n"); 1254 /* XXX ID + Seq + Data */ 1255 break; 1256 case ICMP_UNREACH: 1257 switch(icp->icmp_code) { 1258 case ICMP_UNREACH_NET: 1259 (void)printf("Destination Net Unreachable\n"); 1260 break; 1261 case ICMP_UNREACH_HOST: 1262 (void)printf("Destination Host Unreachable\n"); 1263 break; 1264 case ICMP_UNREACH_PROTOCOL: 1265 (void)printf("Destination Protocol Unreachable\n"); 1266 break; 1267 case ICMP_UNREACH_PORT: 1268 (void)printf("Destination Port Unreachable\n"); 1269 break; 1270 case ICMP_UNREACH_NEEDFRAG: 1271 (void)printf("frag needed and DF set (MTU %d)\n", 1272 ntohs(icp->icmp_nextmtu)); 1273 break; 1274 case ICMP_UNREACH_SRCFAIL: 1275 (void)printf("Source Route Failed\n"); 1276 break; 1277 case ICMP_UNREACH_FILTER_PROHIB: 1278 (void)printf("Communication prohibited by filter\n"); 1279 break; 1280 default: 1281 (void)printf("Dest Unreachable, Bad Code: %d\n", 1282 icp->icmp_code); 1283 break; 1284 } 1285 /* Print returned IP header information */ 1286#ifndef icmp_data 1287 pr_retip(&icp->icmp_ip); 1288#else 1289 pr_retip((struct ip *)icp->icmp_data); 1290#endif 1291 break; 1292 case ICMP_SOURCEQUENCH: 1293 (void)printf("Source Quench\n"); 1294#ifndef icmp_data 1295 pr_retip(&icp->icmp_ip); 1296#else 1297 pr_retip((struct ip *)icp->icmp_data); 1298#endif 1299 break; 1300 case ICMP_REDIRECT: 1301 switch(icp->icmp_code) { 1302 case ICMP_REDIRECT_NET: 1303 (void)printf("Redirect Network"); 1304 break; 1305 case ICMP_REDIRECT_HOST: 1306 (void)printf("Redirect Host"); 1307 break; 1308 case ICMP_REDIRECT_TOSNET: 1309 (void)printf("Redirect Type of Service and Network"); 1310 break; 1311 case ICMP_REDIRECT_TOSHOST: 1312 (void)printf("Redirect Type of Service and Host"); 1313 break; 1314 default: 1315 (void)printf("Redirect, Bad Code: %d", icp->icmp_code); 1316 break; 1317 } 1318 (void)printf("(New addr: %s)\n", inet_ntoa(icp->icmp_gwaddr)); 1319#ifndef icmp_data 1320 pr_retip(&icp->icmp_ip); 1321#else 1322 pr_retip((struct ip *)icp->icmp_data); 1323#endif 1324 break; 1325 case ICMP_ECHO: 1326 (void)printf("Echo Request\n"); 1327 /* XXX ID + Seq + Data */ 1328 break; 1329 case ICMP_TIMXCEED: 1330 switch(icp->icmp_code) { 1331 case ICMP_TIMXCEED_INTRANS: 1332 (void)printf("Time to live exceeded\n"); 1333 break; 1334 case ICMP_TIMXCEED_REASS: 1335 (void)printf("Frag reassembly time exceeded\n"); 1336 break; 1337 default: 1338 (void)printf("Time exceeded, Bad Code: %d\n", 1339 icp->icmp_code); 1340 break; 1341 } 1342#ifndef icmp_data 1343 pr_retip(&icp->icmp_ip); 1344#else 1345 pr_retip((struct ip *)icp->icmp_data); 1346#endif 1347 break; 1348 case ICMP_PARAMPROB: 1349 (void)printf("Parameter problem: pointer = 0x%02x\n", 1350 icp->icmp_hun.ih_pptr); 1351#ifndef icmp_data 1352 pr_retip(&icp->icmp_ip); 1353#else 1354 pr_retip((struct ip *)icp->icmp_data); 1355#endif 1356 break; 1357 case ICMP_TSTAMP: 1358 (void)printf("Timestamp\n"); 1359 /* XXX ID + Seq + 3 timestamps */ 1360 break; 1361 case ICMP_TSTAMPREPLY: 1362 (void)printf("Timestamp Reply\n"); 1363 /* XXX ID + Seq + 3 timestamps */ 1364 break; 1365 case ICMP_IREQ: 1366 (void)printf("Information Request\n"); 1367 /* XXX ID + Seq */ 1368 break; 1369 case ICMP_IREQREPLY: 1370 (void)printf("Information Reply\n"); 1371 /* XXX ID + Seq */ 1372 break; 1373 case ICMP_MASKREQ: 1374 (void)printf("Address Mask Request\n"); 1375 break; 1376 case ICMP_MASKREPLY: 1377 (void)printf("Address Mask Reply\n"); 1378 break; 1379 case ICMP_ROUTERADVERT: 1380 (void)printf("Router Advertisement\n"); 1381 break; 1382 case ICMP_ROUTERSOLICIT: 1383 (void)printf("Router Solicitation\n"); 1384 break; 1385 default: 1386 (void)printf("Bad ICMP type: %d\n", icp->icmp_type); 1387 } 1388} 1389 1390/* 1391 * pr_iph -- 1392 * Print an IP header with options. 1393 */ 1394static void 1395pr_iph(ip) 1396 struct ip *ip; 1397{ 1398 u_char *cp; 1399 int hlen; 1400 1401 hlen = ip->ip_hl << 2; 1402 cp = (u_char *)ip + 20; /* point to options */ 1403 1404 (void)printf("Vr HL TOS Len ID Flg off TTL Pro cks Src Dst\n"); 1405 (void)printf(" %1x %1x %02x %04x %04x", 1406 ip->ip_v, ip->ip_hl, ip->ip_tos, ntohs(ip->ip_len), 1407 ntohs(ip->ip_id)); 1408 (void)printf(" %1lx %04lx", 1409 (u_long) (ntohl(ip->ip_off) & 0xe000) >> 13, 1410 (u_long) ntohl(ip->ip_off) & 0x1fff); 1411 (void)printf(" %02x %02x %04x", ip->ip_ttl, ip->ip_p, 1412 ntohs(ip->ip_sum)); 1413 (void)printf(" %s ", inet_ntoa(*(struct in_addr *)&ip->ip_src.s_addr)); 1414 (void)printf(" %s ", inet_ntoa(*(struct in_addr *)&ip->ip_dst.s_addr)); 1415 /* dump any option bytes */ 1416 while (hlen-- > 20) { 1417 (void)printf("%02x", *cp++); 1418 } 1419 (void)putchar('\n'); 1420} 1421 1422/* 1423 * pr_addr -- 1424 * Return an ascii host address as a dotted quad and optionally with 1425 * a hostname. 1426 */ 1427static char * 1428pr_addr(ina) 1429 struct in_addr ina; 1430{ 1431 struct hostent *hp; 1432 static char buf[16 + 3 + MAXHOSTNAMELEN]; 1433 1434 if ((options & F_NUMERIC) || 1435 !(hp = gethostbyaddr((char *)&ina, 4, AF_INET))) 1436 return inet_ntoa(ina); 1437 else 1438 (void)snprintf(buf, sizeof(buf), "%s (%s)", hp->h_name, 1439 inet_ntoa(ina)); 1440 return(buf); 1441} 1442 1443/* 1444 * pr_retip -- 1445 * Dump some info on a returned (via ICMP) IP packet. 1446 */ 1447static void 1448pr_retip(ip) 1449 struct ip *ip; 1450{ 1451 u_char *cp; 1452 int hlen; 1453 1454 pr_iph(ip); 1455 hlen = ip->ip_hl << 2; 1456 cp = (u_char *)ip + hlen; 1457 1458 if (ip->ip_p == 6) 1459 (void)printf("TCP: from port %u, to port %u (decimal)\n", 1460 (*cp * 256 + *(cp + 1)), (*(cp + 2) * 256 + *(cp + 3))); 1461 else if (ip->ip_p == 17) 1462 (void)printf("UDP: from port %u, to port %u (decimal)\n", 1463 (*cp * 256 + *(cp + 1)), (*(cp + 2) * 256 + *(cp + 3))); 1464} 1465 1466static void 1467fill(bp, patp) 1468 char *bp, *patp; 1469{ 1470 char *cp; 1471 int pat[16]; 1472 u_int ii, jj, kk; 1473 1474 for (cp = patp; *cp; cp++) { 1475 if (!isxdigit(*cp)) 1476 errx(EX_USAGE, 1477 "patterns must be specified as hex digits"); 1478 1479 } 1480 ii = sscanf(patp, 1481 "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x", 1482 &pat[0], &pat[1], &pat[2], &pat[3], &pat[4], &pat[5], &pat[6], 1483 &pat[7], &pat[8], &pat[9], &pat[10], &pat[11], &pat[12], 1484 &pat[13], &pat[14], &pat[15]); 1485 1486 if (ii > 0) 1487 for (kk = 0; kk <= MAXPAYLOAD - (PHDR_LEN + ii); kk += ii) 1488 for (jj = 0; jj < ii; ++jj) 1489 bp[jj + kk] = pat[jj]; 1490 if (!(options & F_QUIET)) { 1491 (void)printf("PATTERN: 0x"); 1492 for (jj = 0; jj < ii; ++jj) 1493 (void)printf("%02x", bp[jj] & 0xFF); 1494 (void)printf("\n"); 1495 } 1496} 1497 1498static void 1499usage() 1500{ 1501 (void)fprintf(stderr, "%s\n%s\n%s\n", 1502"usage: ping [-ADQRadfnoqrv] [-c count] [-i wait] [-l preload] [-m ttl]", 1503" [-p pattern] " 1504#ifdef IPSEC 1505#ifdef IPSEC_POLICY_IPSEC 1506"[-P policy] " 1507#endif 1508#endif 1509"[-s packetsize] [-S src_addr] [-t timeout]", 1510" [-z tos ] [host | [-L] [-I iface] [-T ttl] mcast-group]"); 1511 exit(EX_USAGE); 1512} 1513