1/* 2 * Copyright (c) 1989 The Regents of the University of California. 3 * 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 38char copyright[] = 39"@(#) Copyright (c) 1989 The Regents of the University of California.\n\ 40 All rights reserved.\n"; 41#endif /* not lint */ 42 43/* 44 * P I N G . C 45 * 46 * Using the InterNet Control Message Protocol (ICMP) "ECHO" facility, 47 * measure round-trip-delays and packet loss across network paths. 48 * 49 * Author - 50 * Mike Muuss 51 * U. S. Army Ballistic Research Laboratory 52 * December, 1983 53 * 54 * Status - 55 * Public Domain. Distribution Unlimited. 56 * Bugs - 57 * More statistics could always be gathered. 58 * This program has to run SUID to ROOT to access the ICMP socket. 59 */ 60 61#include "ping_common.h" 62 63#include <netinet/ip.h> 64#include <netinet/ip_icmp.h> 65#ifdef DO_IPSEC 66#include <libipsec.h> 67#endif 68 69 70#define MAXIPLEN 60 71#define MAXICMPLEN 76 72#define NROUTES 9 /* number of record route slots */ 73#define TOS_MAX 255 /* 8-bit TOS field */ 74 75 76static int ts_type; 77static int nroute = 0; 78static __u32 route[10]; 79 80 81 82struct sockaddr_in whereto; /* who to ping */ 83int optlen = 0; 84int settos = 0; /* Set TOS, Precendence or other QOS options */ 85int icmp_sock; /* socket file descriptor */ 86u_char outpack[0x10000]; 87int maxpacket = sizeof(outpack); 88 89static int broadcast_pings = 0; 90 91static char *pr_addr(__u32); 92static void pr_options(unsigned char * cp, int hlen); 93static void pr_iph(struct iphdr *ip); 94static void usage(void) __attribute__((noreturn)); 95static u_short in_cksum(const u_short *addr, int len, u_short salt); 96static void pr_icmph(__u8 type, __u8 code, __u32 info, struct icmphdr *icp); 97static int parsetos(char *str); 98 99static struct { 100 struct cmsghdr cm; 101 struct in_pktinfo ipi; 102} cmsg = { {sizeof(struct cmsghdr) + sizeof(struct in_pktinfo), SOL_IP, IP_PKTINFO}, 103 {0, }}; 104int cmsg_len; 105 106struct sockaddr_in source; 107char *device; 108int pmtudisc = -1; 109 110 111int 112main(int argc, char **argv) 113{ 114 struct hostent *hp; 115 int ch, hold, packlen; 116 int socket_errno; 117 u_char *packet; 118 char *target, hnamebuf[MAXHOSTNAMELEN]; 119 char rspace[3 + 4 * NROUTES + 1]; /* record route space */ 120#ifdef DO_IPSEC 121 char *policy_string = NULL; 122#endif 123 124 icmp_sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); 125 socket_errno = errno; 126 127 uid = getuid(); 128 setuid(uid); 129 130 source.sin_family = AF_INET; 131 132 preload = 1; 133 while ((ch = getopt(argc, argv, COMMON_OPTSTR "bRT:P:")) != EOF) { 134 switch(ch) { 135 case 'b': 136 broadcast_pings = 1; 137 break; 138 case 'Q': 139 settos = parsetos(optarg); 140 if (settos && 141 (setsockopt(icmp_sock, IPPROTO_IP, IP_TOS, 142 (char *)&settos, sizeof(int)) < 0)) { 143 perror("ping: error setting QOS sockopts"); 144 exit(2); 145 } 146 break; 147 case 'R': 148 if (options & F_TIMESTAMP) { 149 fprintf(stderr, "Only one of -T or -R may be used\n"); 150 exit(2); 151 } 152 options |= F_RROUTE; 153 break; 154 case 'T': 155 if (options & F_RROUTE) { 156 fprintf(stderr, "Only one of -T or -R may be used\n"); 157 exit(2); 158 } 159 options |= F_TIMESTAMP; 160 if (strcmp(optarg, "tsonly") == 0) 161 ts_type = IPOPT_TS_TSONLY; 162 else if (strcmp(optarg, "tsandaddr") == 0) 163 ts_type = IPOPT_TS_TSANDADDR; 164 else if (strcmp(optarg, "tsprespec") == 0) 165 ts_type = IPOPT_TS_PRESPEC; 166 else { 167 fprintf(stderr, "Invalid timestamp type\n"); 168 exit(2); 169 } 170 break; 171 case 'I': 172 { 173 char dummy; 174 int i1, i2, i3, i4; 175 176 if (sscanf(optarg, "%u.%u.%u.%u%c", 177 &i1, &i2, &i3, &i4, &dummy) == 4) { 178 __u8 *ptr; 179 ptr = (__u8*)&source.sin_addr; 180 ptr[0] = i1; 181 ptr[1] = i2; 182 ptr[2] = i3; 183 ptr[3] = i4; 184 options |= F_STRICTSOURCE; 185 } else { 186 device = optarg; 187 } 188 break; 189 } 190 case 'M': 191 if (strcmp(optarg, "do") == 0) 192 pmtudisc = IP_PMTUDISC_DO; 193 else if (strcmp(optarg, "dont") == 0) 194 pmtudisc = IP_PMTUDISC_DONT; 195 else if (strcmp(optarg, "want") == 0) 196 pmtudisc = IP_PMTUDISC_WANT; 197 else { 198 fprintf(stderr, "ping: wrong value for -M: do, dont, want are valid ones.\n"); 199 exit(2); 200 } 201 break; 202 case 'V': 203 printf("ping utility, iputils-ss%s\n", SNAPSHOT); 204 exit(0); 205 COMMON_OPTIONS 206 common_options(ch); 207 break; 208 case 'P': 209#ifdef DO_IPSEC 210 policy_string = optarg; 211 break; 212#endif 213 default: 214 usage(); 215 } 216 } 217 argc -= optind; 218 argv += optind; 219 220 if (argc == 0) 221 usage(); 222 if (argc > 1) { 223 if (options & F_RROUTE) 224 usage(); 225 else if (options & F_TIMESTAMP) { 226 if (ts_type != IPOPT_TS_PRESPEC) 227 usage(); 228 if (argc > 5) 229 usage(); 230 } else { 231 if (argc > 10) 232 usage(); 233 options |= F_SOURCEROUTE; 234 } 235 } 236 while (argc > 0) { 237 target = *argv; 238 239 bzero((char *)&whereto, sizeof(whereto)); 240 whereto.sin_family = AF_INET; 241 if (inet_aton(target, &whereto.sin_addr) == 1) { 242 hostname = target; 243 if (argc == 1) 244 options |= F_NUMERIC; 245 } else { 246 hp = gethostbyname(target); 247 if (!hp) { 248 fprintf(stderr, "ping: unknown host %s\n", target); 249 exit(2); 250 } 251 memcpy(&whereto.sin_addr, hp->h_addr, 4); 252 strncpy(hnamebuf, hp->h_name, sizeof(hnamebuf) - 1); 253 hnamebuf[sizeof(hnamebuf) - 1] = 0; 254 hostname = hnamebuf; 255 } 256 if (argc > 1) 257 route[nroute++] = whereto.sin_addr.s_addr; 258 argc--; 259 argv++; 260 } 261 262 if (source.sin_addr.s_addr == 0) { 263 int alen; 264 struct sockaddr_in dst = whereto; 265 int probe_fd = socket(AF_INET, SOCK_DGRAM, 0); 266 267 if (probe_fd < 0) { 268 perror("socket"); 269 exit(2); 270 } 271 if (device) { 272 struct ifreq ifr; 273 memset(&ifr, 0, sizeof(ifr)); 274 strncpy(ifr.ifr_name, device, IFNAMSIZ-1); 275 if (setsockopt(probe_fd, SOL_SOCKET, SO_BINDTODEVICE, device, strlen(device)+1) == -1) { 276 if (IN_MULTICAST(ntohl(dst.sin_addr.s_addr))) { 277 struct ip_mreqn imr; 278 if (ioctl(probe_fd, SIOCGIFINDEX, &ifr) < 0) { 279 fprintf(stderr, "ping: unknown iface %s\n", device); 280 exit(2); 281 } 282 memset(&imr, 0, sizeof(imr)); 283 imr.imr_ifindex = ifr.ifr_ifindex; 284 if (setsockopt(probe_fd, SOL_IP, IP_MULTICAST_IF, &imr, sizeof(imr)) == -1) { 285 perror("ping: IP_MULTICAST_IF"); 286 exit(2); 287 } 288 } 289 } 290 } 291 292 if (settos && 293 setsockopt(probe_fd, IPPROTO_IP, IP_TOS, (char *)&settos, sizeof(int)) < 0) 294 perror("Warning: error setting QOS sockopts"); 295 296 dst.sin_port = htons(1025); 297 if (nroute) 298 dst.sin_addr.s_addr = route[0]; 299 if (connect(probe_fd, (struct sockaddr*)&dst, sizeof(dst)) == -1) { 300 if (errno == EACCES) { 301 if (broadcast_pings == 0) { 302 fprintf(stderr, "Do you want to ping broadcast? Then -b\n"); 303 exit(2); 304 } 305 fprintf(stderr, "WARNING: pinging broadcast address\n"); 306 if (setsockopt(probe_fd, SOL_SOCKET, SO_BROADCAST, 307 &broadcast_pings, sizeof(broadcast_pings)) < 0) { 308 perror ("can't set broadcasting"); 309 exit(2); 310 } 311 if (connect(probe_fd, (struct sockaddr*)&dst, sizeof(dst)) == -1) { 312 perror("connect"); 313 exit(2); 314 } 315 } else { 316 perror("connect"); 317 exit(2); 318 } 319 } 320 alen = sizeof(source); 321 if (getsockname(probe_fd, (struct sockaddr*)&source, &alen) == -1) { 322 perror("getsockname"); 323 exit(2); 324 } 325 source.sin_port = 0; 326 close(probe_fd); 327 } while (0); 328 329 if (whereto.sin_addr.s_addr == 0) 330 whereto.sin_addr.s_addr = source.sin_addr.s_addr; 331 332 if (icmp_sock < 0) { 333 errno = socket_errno; 334 perror("ping: icmp open socket"); 335 exit(2); 336 } 337 338 if (device) { 339 struct ifreq ifr; 340 341 memset(&ifr, 0, sizeof(ifr)); 342 strncpy(ifr.ifr_name, device, IFNAMSIZ-1); 343 if (ioctl(icmp_sock, SIOCGIFINDEX, &ifr) < 0) { 344 fprintf(stderr, "ping: unknown iface %s\n", device); 345 exit(2); 346 } 347 cmsg.ipi.ipi_ifindex = ifr.ifr_ifindex; 348 cmsg_len = sizeof(cmsg); 349 } 350 351 if (broadcast_pings || IN_MULTICAST(ntohl(whereto.sin_addr.s_addr))) { 352 if (uid) { 353 if (interval < 1000) { 354 fprintf(stderr, "ping: broadcast ping with too short interval.\n"); 355 exit(2); 356 } 357 if (pmtudisc >= 0 && pmtudisc != IP_PMTUDISC_DO) { 358 fprintf(stderr, "ping: broadcast ping does not fragment.\n"); 359 exit(2); 360 } 361 } 362 if (pmtudisc < 0) 363 pmtudisc = IP_PMTUDISC_DO; 364 } 365 366 if (pmtudisc >= 0) { 367 if (setsockopt(icmp_sock, SOL_IP, IP_MTU_DISCOVER, &pmtudisc, sizeof(pmtudisc)) == -1) { 368 perror("ping: IP_MTU_DISCOVER"); 369 exit(2); 370 } 371 } 372 373 if ((options&F_STRICTSOURCE) && 374 bind(icmp_sock, (struct sockaddr*)&source, sizeof(source)) == -1) { 375 perror("bind"); 376 exit(2); 377 } 378 379 if (1) { 380 struct icmp_filter filt; 381 filt.data = ~((1<<ICMP_SOURCE_QUENCH)| 382 (1<<ICMP_DEST_UNREACH)| 383 (1<<ICMP_TIME_EXCEEDED)| 384 (1<<ICMP_PARAMETERPROB)| 385 (1<<ICMP_REDIRECT)| 386 (1<<ICMP_ECHOREPLY)); 387 if (setsockopt(icmp_sock, SOL_RAW, ICMP_FILTER, (char*)&filt, sizeof(filt)) == -1) 388 perror("WARNING: setsockopt(ICMP_FILTER)"); 389 } 390 391 hold = 1; 392 if (setsockopt(icmp_sock, SOL_IP, IP_RECVERR, (char *)&hold, sizeof(hold))) 393 fprintf(stderr, "WARNING: your kernel is veeery old. No problems.\n"); 394 395 /* record route option */ 396 if (options & F_RROUTE) { 397 bzero(rspace, sizeof(rspace)); 398 rspace[0] = IPOPT_NOP; 399 rspace[1+IPOPT_OPTVAL] = IPOPT_RR; 400 rspace[1+IPOPT_OLEN] = sizeof(rspace)-1; 401 rspace[1+IPOPT_OFFSET] = IPOPT_MINOFF; 402 optlen = 40; 403 if (setsockopt(icmp_sock, IPPROTO_IP, IP_OPTIONS, rspace, sizeof(rspace)) < 0) { 404 perror("ping: record route"); 405 exit(2); 406 } 407 } 408 if (options & F_TIMESTAMP) { 409 bzero(rspace, sizeof(rspace)); 410 rspace[0] = IPOPT_TIMESTAMP; 411 rspace[1] = (ts_type==IPOPT_TS_TSONLY ? 40 : 36); 412 rspace[2] = 5; 413 rspace[3] = ts_type; 414 if (ts_type == IPOPT_TS_PRESPEC) { 415 int i; 416 rspace[1] = 4+nroute*8; 417 for (i=0; i<nroute; i++) 418 *(__u32*)&rspace[4+i*8] = route[i]; 419 } 420 if (setsockopt(icmp_sock, IPPROTO_IP, IP_OPTIONS, rspace, rspace[1]) < 0) { 421 rspace[3] = 2; 422 if (setsockopt(icmp_sock, IPPROTO_IP, IP_OPTIONS, rspace, rspace[1]) < 0) { 423 perror("ping: ts option"); 424 exit(2); 425 } 426 } 427 optlen = 40; 428 } 429 if (options & F_SOURCEROUTE) { 430 int i; 431 bzero(rspace, sizeof(rspace)); 432 rspace[0] = IPOPT_NOOP; 433 rspace[1+IPOPT_OPTVAL] = (options & F_SO_DONTROUTE) ? IPOPT_SSRR 434 : IPOPT_LSRR; 435 rspace[1+IPOPT_OLEN] = 3 + nroute*4; 436 rspace[1+IPOPT_OFFSET] = IPOPT_MINOFF; 437 for (i=0; i<nroute; i++) 438 *(__u32*)&rspace[4+i*4] = route[i]; 439 440 if (setsockopt(icmp_sock, IPPROTO_IP, IP_OPTIONS, rspace, 4 + nroute*4) < 0) { 441 perror("ping: record route"); 442 exit(2); 443 } 444 optlen = 40; 445 } 446 447 /* Estimate memory eaten by single packet. It is rough estimate. 448 * Actually, for small datalen's it depends on kernel side a lot. */ 449 hold = datalen + 8; 450 hold += ((hold+511)/512)*(optlen + 20 + 16 + 64 + 160); 451 sock_setbufs(icmp_sock, hold); 452 453 if (broadcast_pings) { 454 if (setsockopt(icmp_sock, SOL_SOCKET, SO_BROADCAST, 455 &broadcast_pings, sizeof(broadcast_pings)) < 0) { 456 perror ("ping: can't set broadcasting"); 457 exit(2); 458 } 459 } 460 461 if (options & F_NOLOOP) { 462 int loop = 0; 463 if (setsockopt(icmp_sock, IPPROTO_IP, IP_MULTICAST_LOOP, 464 &loop, 1) == -1) { 465 perror ("ping: can't disable multicast loopback"); 466 exit(2); 467 } 468 } 469 if (options & F_TTL) { 470 int ittl = ttl; 471 if (setsockopt(icmp_sock, IPPROTO_IP, IP_MULTICAST_TTL, 472 &ttl, 1) == -1) { 473 perror ("ping: can't set multicast time-to-live"); 474 exit(2); 475 } 476 if (setsockopt(icmp_sock, IPPROTO_IP, IP_TTL, 477 &ittl, sizeof(ittl)) == -1) { 478 perror ("ping: can't set unicast time-to-live"); 479 exit(2); 480 } 481 } 482 483#ifdef DO_IPSEC 484 if (policy_string) { 485 char *buf = ipsec_set_policy(policy_string, strlen(policy_string)); 486 if (buf == NULL) { 487 perror ("ping: can't parse policy string"); 488 exit(2); 489 } 490 if (setsockopt(icmp_sock, SOL_IP, IP_IPSEC_POLICY, 491 buf, ipsec_get_policylen(buf)) < 0) { 492 perror ("ping: can't setup policy"); 493 exit(2); 494 } 495 } 496#endif 497 498 if (datalen > 0xFFFF - 8 - optlen - 20) { 499 if (uid || datalen > sizeof(outpack)-8) { 500 fprintf(stderr, "Error: packet size %d is too large. Maximum is %d\n", datalen, 0xFFFF-8-20-optlen); 501 exit(2); 502 } 503 /* Allow small oversize to root yet. It will cause EMSGSIZE. */ 504 fprintf(stderr, "WARNING: packet size %d is too large. Maximum is %d\n", datalen, 0xFFFF-8-20-optlen); 505 } 506 507 if (datalen >= sizeof(struct timeval)) /* can we time transfer */ 508 timing = 1; 509 packlen = datalen + MAXIPLEN + MAXICMPLEN; 510 if (!(packet = (u_char *)malloc((u_int)packlen))) { 511 fprintf(stderr, "ping: out of memory.\n"); 512 exit(2); 513 } 514 515 printf("PING %s (%s) ", hostname, inet_ntoa(whereto.sin_addr)); 516 if (device || (options&F_STRICTSOURCE)) 517 printf("from %s %s: ", inet_ntoa(source.sin_addr), device ?: ""); 518 printf("%d(%d) bytes of data.\n", datalen, datalen+8+optlen+20); 519 520 setup(icmp_sock); 521 522 main_loop(icmp_sock, packet, packlen); 523} 524 525 526int receive_error_msg() 527{ 528 int res; 529 char cbuf[512]; 530 struct iovec iov; 531 struct msghdr msg; 532 struct cmsghdr *cmsg; 533 struct sock_extended_err *e; 534 struct icmphdr icmph; 535 struct sockaddr_in target; 536 int net_errors = 0; 537 int local_errors = 0; 538 int saved_errno = errno; 539 540 iov.iov_base = &icmph; 541 iov.iov_len = sizeof(icmph); 542 msg.msg_name = (void*)⌖ 543 msg.msg_namelen = sizeof(target); 544 msg.msg_iov = &iov; 545 msg.msg_iovlen = 1; 546 msg.msg_flags = 0; 547 msg.msg_control = cbuf; 548 msg.msg_controllen = sizeof(cbuf); 549 550 res = recvmsg(icmp_sock, &msg, MSG_ERRQUEUE|MSG_DONTWAIT); 551 if (res < 0) 552 goto out; 553 554 e = NULL; 555 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { 556 if (cmsg->cmsg_level == SOL_IP) { 557 if (cmsg->cmsg_type == IP_RECVERR) 558 e = (struct sock_extended_err *)CMSG_DATA(cmsg); 559 } 560 } 561 if (e == NULL) 562 abort(); 563 564 if (e->ee_origin == SO_EE_ORIGIN_LOCAL) { 565 local_errors++; 566 if (options & F_QUIET) 567 goto out; 568 if (options & F_FLOOD) 569 write(STDOUT_FILENO, "E", 1); 570 else if (e->ee_errno != EMSGSIZE) 571 fprintf(stderr, "ping: local error: %s\n", strerror(e->ee_errno)); 572 else 573 fprintf(stderr, "ping: local error: Message too long, mtu=%u\n", e->ee_info); 574 nerrors++; 575 } else if (e->ee_origin == SO_EE_ORIGIN_ICMP) { 576 struct sockaddr_in *sin = (struct sockaddr_in*)(e+1); 577 578 if (res < sizeof(icmph) || 579 target.sin_addr.s_addr != whereto.sin_addr.s_addr || 580 icmph.type != ICMP_ECHO || 581 icmph.un.echo.id != ident) { 582 /* Not our error, not an error at all. Clear. */ 583 saved_errno = 0; 584 goto out; 585 } 586 587 acknowledge(ntohs(icmph.un.echo.sequence)); 588 589 if (!working_recverr) { 590 struct icmp_filter filt; 591 working_recverr = 1; 592 /* OK, it works. Add stronger filter. */ 593 filt.data = ~((1<<ICMP_SOURCE_QUENCH)| 594 (1<<ICMP_REDIRECT)| 595 (1<<ICMP_ECHOREPLY)); 596 if (setsockopt(icmp_sock, SOL_RAW, ICMP_FILTER, (char*)&filt, sizeof(filt)) == -1) 597 perror("\rWARNING: setsockopt(ICMP_FILTER)"); 598 } 599 600 net_errors++; 601 nerrors++; 602 if (options & F_QUIET) 603 goto out; 604 if (options & F_FLOOD) { 605 write(STDOUT_FILENO, "\bE", 2); 606 } else { 607 printf("From %s icmp_seq=%u ", pr_addr(sin->sin_addr.s_addr), ntohs(icmph.un.echo.sequence)); 608 pr_icmph(e->ee_type, e->ee_code, e->ee_info, NULL); 609 fflush(stdout); 610 } 611 } 612 613out: 614 errno = saved_errno; 615 return net_errors ? : -local_errors; 616} 617 618/* 619 * pinger -- 620 * Compose and transmit an ICMP ECHO REQUEST packet. The IP packet 621 * will be added on by the kernel. The ID field is our UNIX process ID, 622 * and the sequence number is an ascending integer. The first 8 bytes 623 * of the data portion are used to hold a UNIX "timeval" struct in VAX 624 * byte-order, to compute the round-trip time. 625 */ 626int send_probe() 627{ 628 struct icmphdr *icp; 629 int cc; 630 int i; 631 632 icp = (struct icmphdr *)outpack; 633 icp->type = ICMP_ECHO; 634 icp->code = 0; 635 icp->checksum = 0; 636 icp->un.echo.sequence = htons(ntransmitted+1); 637 icp->un.echo.id = ident; /* ID */ 638 639 CLR((ntransmitted+1) % mx_dup_ck); 640 641 if (timing) { 642 if (options&F_LATENCY) { 643 static volatile int fake_fucked_egcs = sizeof(struct timeval); 644 struct timeval tmp_tv; 645 gettimeofday(&tmp_tv, NULL); 646 /* egcs is crap or glibc is crap, but memcpy 647 does not copy anything, if len is constant! */ 648 memcpy(icp+1, &tmp_tv, fake_fucked_egcs); 649 } else { 650 memset(icp+1, 0, sizeof(struct timeval)); 651 } 652 } 653 654 cc = datalen + 8; /* skips ICMP portion */ 655 656 /* compute ICMP checksum here */ 657 icp->checksum = in_cksum((u_short *)icp, cc, 0); 658 659 if (timing && !(options&F_LATENCY)) { 660 static volatile int fake_fucked_egcs = sizeof(struct timeval); 661 struct timeval tmp_tv; 662 gettimeofday(&tmp_tv, NULL); 663 /* egcs is crap or glibc is crap, but memcpy 664 does not copy anything, if len is constant! */ 665 memcpy(icp+1, &tmp_tv, fake_fucked_egcs); 666 icp->checksum = in_cksum((u_short *)(icp+1), fake_fucked_egcs, ~icp->checksum); 667 } 668 669 do { 670 static struct iovec iov = {outpack, 0}; 671 static struct msghdr m = { &whereto, sizeof(whereto), 672 &iov, 1, &cmsg, 0, 0 }; 673 m.msg_controllen = cmsg_len; 674 iov.iov_len = cc; 675 676 i = sendmsg(icmp_sock, &m, confirm); 677 confirm = 0; 678 } while (0); 679 680 return (cc == i ? 0 : i); 681} 682 683/* 684 * parse_reply -- 685 * Print out the packet, if it came from us. This logic is necessary 686 * because ALL readers of the ICMP socket get a copy of ALL ICMP packets 687 * which arrive ('tis only fair). This permits multiple copies of this 688 * program to be run without having intermingled output (or statistics!). 689 */ 690int 691parse_reply(struct msghdr *msg, int cc, void *addr, struct timeval *tv) 692{ 693 struct sockaddr_in *from = addr; 694 __u8 *buf = msg->msg_iov->iov_base; 695 struct icmphdr *icp; 696 struct iphdr *ip; 697 int hlen; 698 int csfailed; 699 700 /* Check the IP header */ 701 ip = (struct iphdr *)buf; 702 hlen = ip->ihl*4; 703 if (cc < hlen + 8 || ip->ihl < 5) { 704 if (options & F_VERBOSE) 705 fprintf(stderr, "ping: packet too short (%d bytes) from %s\n", cc, 706 pr_addr(from->sin_addr.s_addr)); 707 return 1; 708 } 709 710 /* Now the ICMP part */ 711 cc -= hlen; 712 icp = (struct icmphdr *)(buf + hlen); 713 csfailed = in_cksum((u_short *)icp, cc, 0); 714 715 if (icp->type == ICMP_ECHOREPLY) { 716 if (icp->un.echo.id != ident) 717 return 1; /* 'Twas not our ECHO */ 718 if (gather_statistics((__u8*)(icp+1), cc, 719 ntohs(icp->un.echo.sequence), 720 ip->ttl, 0, tv, pr_addr(from->sin_addr.s_addr))) 721 return 0; 722 } else { 723 /* We fall here when a redirect or source quench arrived. 724 * Also this branch processes icmp errors, when IP_RECVERR 725 * is broken. */ 726 727 switch (icp->type) { 728 case ICMP_ECHO: 729 /* MUST NOT */ 730 return 1; 731 case ICMP_SOURCE_QUENCH: 732 case ICMP_REDIRECT: 733 case ICMP_DEST_UNREACH: 734 case ICMP_TIME_EXCEEDED: 735 case ICMP_PARAMETERPROB: 736 { 737 struct iphdr * iph = (struct iphdr *)(&icp[1]); 738 struct icmphdr *icp1 = (struct icmphdr*)((unsigned char *)iph + iph->ihl*4); 739 int error_pkt; 740 if (cc < 8+sizeof(struct iphdr)+8 || 741 cc < 8+iph->ihl*4+8) 742 return 1; 743 if (icp1->type != ICMP_ECHO || 744 iph->daddr != whereto.sin_addr.s_addr || 745 icp1->un.echo.id != ident) 746 return 1; 747 error_pkt = (icp->type != ICMP_REDIRECT && 748 icp->type != ICMP_SOURCE_QUENCH); 749 if (error_pkt) { 750 acknowledge(ntohs(icp1->un.echo.sequence)); 751 if (working_recverr) { 752 return 0; 753 } else { 754 static int once; 755 /* Sigh, IP_RECVERR for raw socket 756 * was broken until 2.4.9. So, we ignore 757 * the first error and warn on the second. 758 */ 759 if (once++ == 1) 760 fprintf(stderr, "\rWARNING: kernel is not very fresh, upgrade is recommended.\n"); 761 if (once == 1) 762 return 0; 763 } 764 } 765 nerrors+=error_pkt; 766 if (options&F_QUIET) 767 return !error_pkt; 768 if (options & F_FLOOD) { 769 if (error_pkt) 770 write(STDOUT_FILENO, "\bE", 2); 771 return !error_pkt; 772 } 773 printf("From %s: icmp_seq=%u ", 774 pr_addr(from->sin_addr.s_addr), 775 ntohs(icp1->un.echo.sequence)); 776 if (csfailed) 777 printf("(BAD CHECKSUM)"); 778 pr_icmph(icp->type, icp->code, ntohl(icp->un.gateway), icp); 779 return !error_pkt; 780 } 781 default: 782 /* MUST NOT */ 783 break; 784 } 785 if ((options & F_FLOOD) && !(options & (F_VERBOSE|F_QUIET))) { 786 if (!csfailed) 787 write(STDOUT_FILENO, "!E", 2); 788 else 789 write(STDOUT_FILENO, "!EC", 3); 790 return 0; 791 } 792 if (!(options & F_VERBOSE) || uid) 793 return 0; 794 printf("From %s: ", pr_addr(from->sin_addr.s_addr)); 795 if (csfailed) { 796 printf("(BAD CHECKSUM)\n"); 797 return 0; 798 } 799 pr_icmph(icp->type, icp->code, ntohl(icp->un.gateway), icp); 800 return 0; 801 } 802 803 if (!(options & F_FLOOD)) { 804 pr_options(buf + sizeof(struct iphdr), hlen); 805 806 if (options & F_AUDIBLE) 807 putchar('\a'); 808 putchar('\n'); 809 fflush(stdout); 810 } 811 return 0; 812} 813 814u_short 815in_cksum(const u_short *addr, register int len, u_short csum) 816{ 817 register int nleft = len; 818 const u_short *w = addr; 819 register u_short answer; 820 register int sum = csum; 821 822 /* 823 * Our algorithm is simple, using a 32 bit accumulator (sum), 824 * we add sequential 16 bit words to it, and at the end, fold 825 * back all the carry bits from the top 16 bits into the lower 826 * 16 bits. 827 */ 828 while (nleft > 1) { 829 sum += *w++; 830 nleft -= 2; 831 } 832 833 /* mop up an odd byte, if necessary */ 834 if (nleft == 1) 835 sum += htons(*(u_char *)w << 8); 836 837 /* 838 * add back carry outs from top 16 bits to low 16 bits 839 */ 840 sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ 841 sum += (sum >> 16); /* add carry */ 842 answer = ~sum; /* truncate to 16 bits */ 843 return (answer); 844} 845 846/* 847 * pr_icmph -- 848 * Print a descriptive string about an ICMP header. 849 */ 850void pr_icmph(__u8 type, __u8 code, __u32 info, struct icmphdr *icp) 851{ 852 switch(type) { 853 case ICMP_ECHOREPLY: 854 printf("Echo Reply\n"); 855 break; 856 case ICMP_DEST_UNREACH: 857 switch(code) { 858 case ICMP_NET_UNREACH: 859 printf("Destination Net Unreachable\n"); 860 break; 861 case ICMP_HOST_UNREACH: 862 printf("Destination Host Unreachable\n"); 863 break; 864 case ICMP_PROT_UNREACH: 865 printf("Destination Protocol Unreachable\n"); 866 break; 867 case ICMP_PORT_UNREACH: 868 printf("Destination Port Unreachable\n"); 869 break; 870 case ICMP_FRAG_NEEDED: 871 printf("Frag needed and DF set (mtu = %u)\n", info); 872 break; 873 case ICMP_SR_FAILED: 874 printf("Source Route Failed\n"); 875 break; 876 case ICMP_PKT_FILTERED: 877 printf("Packet filtered\n"); 878 break; 879 default: 880 printf("Dest Unreachable, Bad Code: %d\n", code); 881 break; 882 } 883 if (icp && (options & F_VERBOSE)) 884 pr_iph((struct iphdr*)(icp + 1)); 885 break; 886 case ICMP_SOURCE_QUENCH: 887 printf("Source Quench\n"); 888 if (icp && (options & F_VERBOSE)) 889 pr_iph((struct iphdr*)(icp + 1)); 890 break; 891 case ICMP_REDIRECT: 892 switch(code) { 893 case ICMP_REDIR_NET: 894 printf("Redirect Network"); 895 break; 896 case ICMP_REDIR_HOST: 897 printf("Redirect Host"); 898 break; 899 case ICMP_REDIR_NETTOS: 900 printf("Redirect Type of Service and Network"); 901 break; 902 case ICMP_REDIR_HOSTTOS: 903 printf("Redirect Type of Service and Host"); 904 break; 905 default: 906 printf("Redirect, Bad Code: %d", code); 907 break; 908 } 909 if (icp) 910 printf("(New nexthop: %s)\n", pr_addr(icp->un.gateway)); 911 if (icp && (options & F_VERBOSE)) 912 pr_iph((struct iphdr*)(icp + 1)); 913 break; 914 case ICMP_ECHO: 915 printf("Echo Request\n"); 916 break; 917 case ICMP_TIME_EXCEEDED: 918 switch(code) { 919 case ICMP_EXC_TTL: 920 printf("Time to live exceeded\n"); 921 break; 922 case ICMP_EXC_FRAGTIME: 923 printf("Frag reassembly time exceeded\n"); 924 break; 925 default: 926 printf("Time exceeded, Bad Code: %d\n", code); 927 break; 928 } 929 if (icp && (options & F_VERBOSE)) 930 pr_iph((struct iphdr*)(icp + 1)); 931 break; 932 case ICMP_PARAMETERPROB: 933 printf("Parameter problem: pointer = %u\n", icp ? (ntohl(icp->un.gateway)>>24) : info); 934 if (icp && (options & F_VERBOSE)) 935 pr_iph((struct iphdr*)(icp + 1)); 936 break; 937 case ICMP_TIMESTAMP: 938 printf("Timestamp\n"); 939 break; 940 case ICMP_TIMESTAMPREPLY: 941 printf("Timestamp Reply\n"); 942 break; 943 case ICMP_INFO_REQUEST: 944 printf("Information Request\n"); 945 break; 946 case ICMP_INFO_REPLY: 947 printf("Information Reply\n"); 948 break; 949#ifdef ICMP_MASKREQ 950 case ICMP_MASKREQ: 951 printf("Address Mask Request\n"); 952 break; 953#endif 954#ifdef ICMP_MASKREPLY 955 case ICMP_MASKREPLY: 956 printf("Address Mask Reply\n"); 957 break; 958#endif 959 default: 960 printf("Bad ICMP type: %d\n", type); 961 } 962} 963 964void pr_options(unsigned char * cp, int hlen) 965{ 966 int i, j; 967 int optlen, totlen; 968 unsigned char * optptr; 969 static int old_rrlen; 970 static char old_rr[MAX_IPOPTLEN]; 971 972 totlen = hlen-sizeof(struct iphdr); 973 optptr = cp; 974 975 while (totlen > 0) { 976 if (*optptr == IPOPT_EOL) 977 break; 978 if (*optptr == IPOPT_NOP) { 979 totlen--; 980 optptr++; 981 printf("\nNOP"); 982 continue; 983 } 984 cp = optptr; 985 optlen = optptr[1]; 986 if (optlen < 2 || optlen > totlen) 987 break; 988 989 switch (*cp) { 990 case IPOPT_SSRR: 991 case IPOPT_LSRR: 992 printf("\n%cSRR: ", *cp==IPOPT_SSRR ? 'S' : 'L'); 993 j = *++cp; 994 i = *++cp; 995 i -= 4; 996 cp++; 997 if (j > IPOPT_MINOFF) { 998 for (;;) { 999 __u32 address; 1000 memcpy(&address, cp, 4); 1001 cp += 4; 1002 if (address == 0) 1003 printf("\t0.0.0.0"); 1004 else 1005 printf("\t%s", pr_addr(address)); 1006 j -= 4; 1007 putchar('\n'); 1008 if (j <= IPOPT_MINOFF) 1009 break; 1010 } 1011 } 1012 break; 1013 case IPOPT_RR: 1014 j = *++cp; /* get length */ 1015 i = *++cp; /* and pointer */ 1016 if (i > j) 1017 i = j; 1018 i -= IPOPT_MINOFF; 1019 if (i <= 0) 1020 continue; 1021 if (i == old_rrlen 1022 && !bcmp((char *)cp, old_rr, i) 1023 && !(options & F_FLOOD)) { 1024 printf("\t(same route)"); 1025 i = ((i + 3) / 4) * 4; 1026 cp += i; 1027 break; 1028 } 1029 old_rrlen = i; 1030 bcopy((char *)cp, old_rr, i); 1031 printf("\nRR: "); 1032 cp++; 1033 for (;;) { 1034 __u32 address; 1035 memcpy(&address, cp, 4); 1036 cp += 4; 1037 if (address == 0) 1038 printf("\t0.0.0.0"); 1039 else 1040 printf("\t%s", pr_addr(address)); 1041 i -= 4; 1042 putchar('\n'); 1043 if (i <= 0) 1044 break; 1045 } 1046 break; 1047 case IPOPT_TS: 1048 { 1049 int stdtime = 0, nonstdtime = 0; 1050 __u8 flags; 1051 j = *++cp; /* get length */ 1052 i = *++cp; /* and pointer */ 1053 if (i > j) 1054 i = j; 1055 i -= 5; 1056 if (i <= 0) 1057 continue; 1058 flags = *++cp; 1059 printf("\nTS: "); 1060 cp++; 1061 for (;;) { 1062 long l; 1063 1064 if ((flags&0xF) != IPOPT_TS_TSONLY) { 1065 __u32 address; 1066 memcpy(&address, cp, 4); 1067 cp += 4; 1068 if (address == 0) 1069 printf("\t0.0.0.0"); 1070 else 1071 printf("\t%s", pr_addr(address)); 1072 i -= 4; 1073 if (i <= 0) 1074 break; 1075 } 1076 l = *cp++; 1077 l = (l<<8) + *cp++; 1078 l = (l<<8) + *cp++; 1079 l = (l<<8) + *cp++; 1080 1081 if (l & 0x80000000) { 1082 if (nonstdtime==0) 1083 printf("\t%ld absolute not-standard", l&0x7fffffff); 1084 else 1085 printf("\t%ld not-standard", (l&0x7fffffff) - nonstdtime); 1086 nonstdtime = l&0x7fffffff; 1087 } else { 1088 if (stdtime==0) 1089 printf("\t%ld absolute", l); 1090 else 1091 printf("\t%ld", l - stdtime); 1092 stdtime = l; 1093 } 1094 i -= 4; 1095 putchar('\n'); 1096 if (i <= 0) 1097 break; 1098 } 1099 if (flags>>4) 1100 printf("Unrecorded hops: %d\n", flags>>4); 1101 break; 1102 } 1103 default: 1104 printf("\nunknown option %x", *cp); 1105 break; 1106 } 1107 totlen -= optlen; 1108 optptr += optlen; 1109 } 1110} 1111 1112 1113/* 1114 * pr_iph -- 1115 * Print an IP header with options. 1116 */ 1117void pr_iph(struct iphdr *ip) 1118{ 1119 int hlen; 1120 u_char *cp; 1121 1122 hlen = ip->ihl << 2; 1123 cp = (u_char *)ip + 20; /* point to options */ 1124 1125 printf("Vr HL TOS Len ID Flg off TTL Pro cks Src Dst Data\n"); 1126 printf(" %1x %1x %02x %04x %04x", 1127 ip->version, ip->ihl, ip->tos, ip->tot_len, ip->id); 1128 printf(" %1x %04x", ((ip->frag_off) & 0xe000) >> 13, 1129 (ip->frag_off) & 0x1fff); 1130 printf(" %02x %02x %04x", ip->ttl, ip->protocol, ip->check); 1131 printf(" %s ", inet_ntoa(*(struct in_addr *)&ip->saddr)); 1132 printf(" %s ", inet_ntoa(*(struct in_addr *)&ip->daddr)); 1133 printf("\n"); 1134 pr_options(cp, hlen); 1135} 1136 1137/* 1138 * pr_addr -- 1139 * Return an ascii host address as a dotted quad and optionally with 1140 * a hostname. 1141 */ 1142char * 1143pr_addr(__u32 addr) 1144{ 1145 struct hostent *hp; 1146 static char buf[4096]; 1147 1148 if ((options & F_NUMERIC) || 1149 !(hp = gethostbyaddr((char *)&addr, 4, AF_INET))) 1150 sprintf(buf, "%s", inet_ntoa(*(struct in_addr *)&addr)); 1151 else 1152 snprintf(buf, sizeof(buf), "%s (%s)", hp->h_name, 1153 inet_ntoa(*(struct in_addr *)&addr)); 1154 return(buf); 1155} 1156 1157 1158/* Set Type of Service (TOS) and other Quality of Service relating bits */ 1159int parsetos(char *str) 1160{ 1161 const char *cp; 1162 int tos; 1163 char *ep; 1164 1165 /* handle both hex and decimal values */ 1166 if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) { 1167 cp = str + 2; 1168 tos = (int)strtol(cp, &ep, 16); 1169 } else 1170 tos = (int)strtol(str, &ep, 10); 1171 1172 /* doesn't look like decimal or hex, eh? */ 1173 if (*ep != '\0') { 1174 fprintf(stderr, "ping: \"%s\" bad value for TOS\n", str); 1175 exit(2); 1176 } 1177 1178 if (tos > TOS_MAX) { 1179 fprintf(stderr, "ping: the decimal value of TOS bits must be 0-254 (or zero)\n"); 1180 exit(2); 1181 } 1182 return(tos); 1183} 1184 1185#include <linux/filter.h> 1186 1187void install_filter(void) 1188{ 1189 static int once; 1190 static struct sock_filter insns[] = { 1191 BPF_STMT(BPF_LDX|BPF_B|BPF_MSH, 0), /* Skip IP header. F..g BSD... Look into ping6. */ 1192 BPF_STMT(BPF_LD|BPF_H|BPF_IND, 4), /* Load icmp echo ident */ 1193 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 0xAAAA, 0, 1), /* Ours? */ 1194 BPF_STMT(BPF_RET|BPF_K, ~0U), /* Yes, it passes. */ 1195 BPF_STMT(BPF_LD|BPF_B|BPF_IND, 0), /* Load icmp type */ 1196 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, ICMP_ECHOREPLY, 1, 0), /* Echo? */ 1197 BPF_STMT(BPF_RET|BPF_K, 0xFFFFFFF), /* No. It passes. */ 1198 BPF_STMT(BPF_RET|BPF_K, 0) /* Echo with wrong ident. Reject. */ 1199 }; 1200 static struct sock_fprog filter = { 1201 sizeof insns / sizeof(insns[0]), 1202 insns 1203 }; 1204 1205 if (once) 1206 return; 1207 once = 1; 1208 1209 /* Patch bpflet for current identifier. */ 1210 insns[2] = (struct sock_filter)BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __constant_htons(ident), 0, 1); 1211 1212 if (setsockopt(icmp_sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter))) 1213 perror("WARNING: failed to install socket filter\n"); 1214} 1215 1216 1217void usage(void) 1218{ 1219 fprintf(stderr, 1220"Usage: ping [-LRUbdfnqrvVaA] [-c count] [-i interval] [-w deadline]\n" 1221" [-p pattern] [-s packetsize] [-t ttl] [-I interface or address]\n" 1222" [-M mtu discovery hint] [-S sndbuf]\n" 1223" [ -T timestamp option ] [ -Q tos ] [hop1 ...] destination\n"); 1224 exit(2); 1225} 1226