ping.c revision 19864
11558Srgrimes/* 21558Srgrimes * Copyright (c) 1989, 1993 31558Srgrimes * The Regents of the University of California. All rights reserved. 41558Srgrimes * 51558Srgrimes * This code is derived from software contributed to Berkeley by 61558Srgrimes * Mike Muuss. 71558Srgrimes * 81558Srgrimes * Redistribution and use in source and binary forms, with or without 91558Srgrimes * modification, are permitted provided that the following conditions 101558Srgrimes * are met: 111558Srgrimes * 1. Redistributions of source code must retain the above copyright 121558Srgrimes * notice, this list of conditions and the following disclaimer. 131558Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 141558Srgrimes * notice, this list of conditions and the following disclaimer in the 151558Srgrimes * documentation and/or other materials provided with the distribution. 161558Srgrimes * 3. All advertising materials mentioning features or use of this software 171558Srgrimes * must display the following acknowledgement: 181558Srgrimes * This product includes software developed by the University of 191558Srgrimes * California, Berkeley and its contributors. 201558Srgrimes * 4. Neither the name of the University nor the names of its contributors 211558Srgrimes * may be used to endorse or promote products derived from this software 221558Srgrimes * without specific prior written permission. 231558Srgrimes * 241558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 251558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 261558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 271558Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 281558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 291558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 301558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 311558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 321558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 331558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 341558Srgrimes * SUCH DAMAGE. 351558Srgrimes */ 361558Srgrimes 371558Srgrimes#ifndef lint 381558Srgrimesstatic char copyright[] = 391558Srgrimes"@(#) Copyright (c) 1989, 1993\n\ 401558Srgrimes The Regents of the University of California. All rights reserved.\n"; 411558Srgrimes#endif /* not lint */ 421558Srgrimes 431558Srgrimes#ifndef lint 441558Srgrimesstatic char sccsid[] = "@(#)ping.c 8.1 (Berkeley) 6/5/93"; 451558Srgrimes#endif /* not lint */ 461558Srgrimes 471558Srgrimes/* 481558Srgrimes * P I N G . C 491558Srgrimes * 501558Srgrimes * Using the InterNet Control Message Protocol (ICMP) "ECHO" facility, 511558Srgrimes * measure round-trip-delays and packet loss across network paths. 521558Srgrimes * 531558Srgrimes * Author - 541558Srgrimes * Mike Muuss 551558Srgrimes * U. S. Army Ballistic Research Laboratory 561558Srgrimes * December, 1983 571558Srgrimes * 581558Srgrimes * Status - 591558Srgrimes * Public Domain. Distribution Unlimited. 601558Srgrimes * Bugs - 611558Srgrimes * More statistics could always be gathered. 621558Srgrimes * This program has to run SUID to ROOT to access the ICMP socket. 631558Srgrimes */ 641558Srgrimes 651558Srgrimes#include <sys/param.h> 661558Srgrimes#include <sys/socket.h> 671558Srgrimes#include <sys/file.h> 681558Srgrimes#include <sys/time.h> 691558Srgrimes#include <sys/signal.h> 703792Ssef#include <termios.h> 711558Srgrimes 721558Srgrimes#include <netinet/in_systm.h> 731558Srgrimes#include <netinet/in.h> 741558Srgrimes#include <netinet/ip.h> 751558Srgrimes#include <netinet/ip_icmp.h> 761558Srgrimes#include <netinet/ip_var.h> 771558Srgrimes#include <netdb.h> 781558Srgrimes#include <unistd.h> 791558Srgrimes#include <stdio.h> 801558Srgrimes#include <ctype.h> 811558Srgrimes#include <errno.h> 821558Srgrimes#include <string.h> 831558Srgrimes 841558Srgrimes#define DEFDATALEN (64 - 8) /* default data length */ 851558Srgrimes#define MAXIPLEN 60 861558Srgrimes#define MAXICMPLEN 76 871558Srgrimes#define MAXPACKET (65536 - 60 - 8)/* max packet size */ 881558Srgrimes#define MAXWAIT 10 /* max seconds to wait for response */ 891558Srgrimes#define NROUTES 9 /* number of record route slots */ 901558Srgrimes 911558Srgrimes#define A(bit) rcvd_tbl[(bit)>>3] /* identify byte in array */ 921558Srgrimes#define B(bit) (1 << ((bit) & 0x07)) /* identify bit in byte */ 931558Srgrimes#define SET(bit) (A(bit) |= B(bit)) 941558Srgrimes#define CLR(bit) (A(bit) &= (~B(bit))) 951558Srgrimes#define TST(bit) (A(bit) & B(bit)) 961558Srgrimes 971558Srgrimes/* various options */ 981558Srgrimesint options; 991558Srgrimes#define F_FLOOD 0x001 1001558Srgrimes#define F_INTERVAL 0x002 1011558Srgrimes#define F_NUMERIC 0x004 1021558Srgrimes#define F_PINGFILLED 0x008 1031558Srgrimes#define F_QUIET 0x010 1041558Srgrimes#define F_RROUTE 0x020 1051558Srgrimes#define F_SO_DEBUG 0x040 1061558Srgrimes#define F_SO_DONTROUTE 0x080 1071558Srgrimes#define F_VERBOSE 0x100 10817724Sfenner#define F_QUIET2 0x200 1091558Srgrimes 1101558Srgrimes/* 1111558Srgrimes * MAX_DUP_CHK is the number of bits in received table, i.e. the maximum 1121558Srgrimes * number of received sequence numbers we can keep track of. Change 128 1131558Srgrimes * to 8192 for complete accuracy... 1141558Srgrimes */ 1151558Srgrimes#define MAX_DUP_CHK (8 * 128) 1161558Srgrimesint mx_dup_ck = MAX_DUP_CHK; 1171558Srgrimeschar rcvd_tbl[MAX_DUP_CHK / 8]; 1181558Srgrimes 1191558Srgrimesstruct sockaddr whereto; /* who to ping */ 1201558Srgrimesint datalen = DEFDATALEN; 1211558Srgrimesint s; /* socket file descriptor */ 1221558Srgrimesu_char outpack[MAXPACKET]; 1231558Srgrimeschar BSPACE = '\b'; /* characters written for flood */ 1241558Srgrimeschar DOT = '.'; 1251558Srgrimeschar *hostname; 1261558Srgrimesint ident; /* process id to identify our packets */ 1271558Srgrimes 1281558Srgrimes/* counters */ 1291558Srgrimeslong npackets; /* max packets to transmit */ 1301558Srgrimeslong nreceived; /* # of packets we got back */ 1311558Srgrimeslong nrepeats; /* number of duplicates */ 1321558Srgrimeslong ntransmitted; /* sequence # for outbound packets = #sent */ 1331558Srgrimesint interval = 1; /* interval between packets */ 1341558Srgrimes 1351558Srgrimes/* timing */ 1361558Srgrimesint timing; /* flag to do timing */ 1371558Srgrimesdouble tmin = 999999999.0; /* minimum round trip time */ 1381558Srgrimesdouble tmax = 0.0; /* maximum round trip time */ 1391558Srgrimesdouble tsum = 0.0; /* sum of all times, for doing average */ 1401558Srgrimes 1413792Ssefint reset_kerninfo; 1423792Ssef 1431558Srgrimeschar *pr_addr(); 1443792Ssefvoid catcher(), finish(), status(); 1451558Srgrimes 1461558Srgrimesmain(argc, argv) 1471558Srgrimes int argc; 1481558Srgrimes char **argv; 1491558Srgrimes{ 1501558Srgrimes extern int errno, optind; 1511558Srgrimes extern char *optarg; 1521558Srgrimes struct timeval timeout; 1531558Srgrimes struct hostent *hp; 1541558Srgrimes struct sockaddr_in *to; 1551558Srgrimes struct protoent *proto; 1563792Ssef struct termios ts; 1571558Srgrimes register int i; 15817474Sfenner int ch, fdmask, hold, packlen, preload, sockerrno; 1591558Srgrimes u_char *datap, *packet; 1601558Srgrimes char *target, hnamebuf[MAXHOSTNAMELEN], *malloc(); 1611558Srgrimes#ifdef IP_OPTIONS 1621558Srgrimes char rspace[3 + 4 * NROUTES + 1]; /* record route space */ 1631558Srgrimes#endif 1641558Srgrimes 16517474Sfenner /* 16617474Sfenner * Do the stuff that we need root priv's for *first*, and 16717474Sfenner * then drop our setuid bit. Save error reporting for 16817474Sfenner * after arg parsing. 16917474Sfenner */ 17017474Sfenner proto = getprotobyname("icmp"); 17117474Sfenner if (proto) { 17217474Sfenner s = socket(AF_INET, SOCK_RAW, proto->p_proto); 17317474Sfenner sockerrno = errno; 17417474Sfenner } 17517474Sfenner 17617474Sfenner setuid(getuid()); 17717474Sfenner 1781558Srgrimes preload = 0; 1793792Ssef 1801558Srgrimes datap = &outpack[8 + sizeof(struct timeval)]; 18117724Sfenner while ((ch = getopt(argc, argv, "QRc:dfh:i:l:np:qrs:v")) != EOF) 1821558Srgrimes switch(ch) { 1831558Srgrimes case 'c': 1841558Srgrimes npackets = atoi(optarg); 1851558Srgrimes if (npackets <= 0) { 1861558Srgrimes (void)fprintf(stderr, 1871558Srgrimes "ping: bad number of packets to transmit.\n"); 1881558Srgrimes exit(1); 1891558Srgrimes } 1901558Srgrimes break; 1911558Srgrimes case 'd': 1921558Srgrimes options |= F_SO_DEBUG; 1931558Srgrimes break; 1941558Srgrimes case 'f': 1951558Srgrimes if (getuid()) { 1961558Srgrimes (void)fprintf(stderr, 1971558Srgrimes "ping: %s\n", strerror(EPERM)); 1981558Srgrimes exit(1); 1991558Srgrimes } 2001558Srgrimes options |= F_FLOOD; 2011558Srgrimes setbuf(stdout, (char *)NULL); 2021558Srgrimes break; 2031558Srgrimes case 'i': /* wait between sending packets */ 2041558Srgrimes interval = atoi(optarg); 2051558Srgrimes if (interval <= 0) { 2061558Srgrimes (void)fprintf(stderr, 2071558Srgrimes "ping: bad timing interval.\n"); 2081558Srgrimes exit(1); 2091558Srgrimes } 2101558Srgrimes options |= F_INTERVAL; 2111558Srgrimes break; 2121558Srgrimes case 'l': 2131558Srgrimes preload = atoi(optarg); 2141558Srgrimes if (preload < 0) { 2151558Srgrimes (void)fprintf(stderr, 2161558Srgrimes "ping: bad preload value.\n"); 2171558Srgrimes exit(1); 2181558Srgrimes } 2191558Srgrimes break; 2201558Srgrimes case 'n': 2211558Srgrimes options |= F_NUMERIC; 2221558Srgrimes break; 2231558Srgrimes case 'p': /* fill buffer with user pattern */ 2241558Srgrimes options |= F_PINGFILLED; 2251558Srgrimes fill((char *)datap, optarg); 2261558Srgrimes break; 22717724Sfenner case 'Q': 22817724Sfenner options |= F_QUIET2; 22917724Sfenner break; 2301558Srgrimes case 'q': 2311558Srgrimes options |= F_QUIET; 2321558Srgrimes break; 2331558Srgrimes case 'R': 2341558Srgrimes options |= F_RROUTE; 2351558Srgrimes break; 2361558Srgrimes case 'r': 2371558Srgrimes options |= F_SO_DONTROUTE; 2381558Srgrimes break; 2391558Srgrimes case 's': /* size of packet to send */ 2401558Srgrimes datalen = atoi(optarg); 2411558Srgrimes if (datalen > MAXPACKET) { 2421558Srgrimes (void)fprintf(stderr, 2431558Srgrimes "ping: packet size too large.\n"); 2441558Srgrimes exit(1); 2451558Srgrimes } 2461558Srgrimes if (datalen <= 0) { 2471558Srgrimes (void)fprintf(stderr, 2481558Srgrimes "ping: illegal packet size.\n"); 2491558Srgrimes exit(1); 2501558Srgrimes } 2511558Srgrimes break; 2521558Srgrimes case 'v': 2531558Srgrimes options |= F_VERBOSE; 2541558Srgrimes break; 2551558Srgrimes default: 2561558Srgrimes usage(); 2571558Srgrimes } 2581558Srgrimes argc -= optind; 2591558Srgrimes argv += optind; 2601558Srgrimes 2611558Srgrimes if (argc != 1) 2621558Srgrimes usage(); 2631558Srgrimes target = *argv; 2641558Srgrimes 2651558Srgrimes bzero((char *)&whereto, sizeof(struct sockaddr)); 2661558Srgrimes to = (struct sockaddr_in *)&whereto; 2671558Srgrimes to->sin_family = AF_INET; 2681558Srgrimes to->sin_addr.s_addr = inet_addr(target); 2691558Srgrimes if (to->sin_addr.s_addr != (u_int)-1) 2701558Srgrimes hostname = target; 2711558Srgrimes else { 2721558Srgrimes hp = gethostbyname(target); 2731558Srgrimes if (!hp) { 2741558Srgrimes (void)fprintf(stderr, 2751558Srgrimes "ping: unknown host %s\n", target); 2761558Srgrimes exit(1); 2771558Srgrimes } 2781558Srgrimes to->sin_family = hp->h_addrtype; 2791558Srgrimes bcopy(hp->h_addr, (caddr_t)&to->sin_addr, hp->h_length); 2801558Srgrimes (void)strncpy(hnamebuf, hp->h_name, sizeof(hnamebuf) - 1); 2811558Srgrimes hostname = hnamebuf; 2821558Srgrimes } 2831558Srgrimes 2841558Srgrimes if (options & F_FLOOD && options & F_INTERVAL) { 2851558Srgrimes (void)fprintf(stderr, 2861558Srgrimes "ping: -f and -i incompatible options.\n"); 2871558Srgrimes exit(1); 2881558Srgrimes } 2891558Srgrimes 2901558Srgrimes if (datalen >= sizeof(struct timeval)) /* can we time transfer */ 2911558Srgrimes timing = 1; 2921558Srgrimes packlen = datalen + MAXIPLEN + MAXICMPLEN; 2931558Srgrimes if (!(packet = (u_char *)malloc((u_int)packlen))) { 2941558Srgrimes (void)fprintf(stderr, "ping: out of memory.\n"); 2951558Srgrimes exit(1); 2961558Srgrimes } 2971558Srgrimes if (!(options & F_PINGFILLED)) 2981558Srgrimes for (i = 8; i < datalen; ++i) 2991558Srgrimes *datap++ = i; 3001558Srgrimes 3011558Srgrimes ident = getpid() & 0xFFFF; 3021558Srgrimes 30317474Sfenner if (!proto) { 3041558Srgrimes (void)fprintf(stderr, "ping: unknown protocol icmp.\n"); 3051558Srgrimes exit(1); 3061558Srgrimes } 30717474Sfenner if (s < 0) { 30817474Sfenner errno = sockerrno; 3091558Srgrimes perror("ping: socket"); 3101558Srgrimes exit(1); 3111558Srgrimes } 3121558Srgrimes hold = 1; 3131558Srgrimes if (options & F_SO_DEBUG) 3141558Srgrimes (void)setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&hold, 3151558Srgrimes sizeof(hold)); 3161558Srgrimes if (options & F_SO_DONTROUTE) 3171558Srgrimes (void)setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (char *)&hold, 3181558Srgrimes sizeof(hold)); 3191558Srgrimes 3201558Srgrimes /* record route option */ 3211558Srgrimes if (options & F_RROUTE) { 3221558Srgrimes#ifdef IP_OPTIONS 3231558Srgrimes rspace[IPOPT_OPTVAL] = IPOPT_RR; 3241558Srgrimes rspace[IPOPT_OLEN] = sizeof(rspace)-1; 3251558Srgrimes rspace[IPOPT_OFFSET] = IPOPT_MINOFF; 3261558Srgrimes if (setsockopt(s, IPPROTO_IP, IP_OPTIONS, rspace, 3271558Srgrimes sizeof(rspace)) < 0) { 3281558Srgrimes perror("ping: record route"); 3291558Srgrimes exit(1); 3301558Srgrimes } 3311558Srgrimes#else 3321558Srgrimes (void)fprintf(stderr, 3331558Srgrimes "ping: record route not available in this implementation.\n"); 3341558Srgrimes exit(1); 3351558Srgrimes#endif /* IP_OPTIONS */ 3361558Srgrimes } 3371558Srgrimes 3381558Srgrimes /* 3391558Srgrimes * When pinging the broadcast address, you can get a lot of answers. 3401558Srgrimes * Doing something so evil is useful if you are trying to stress the 3411558Srgrimes * ethernet, or just want to fill the arp cache to get some stuff for 3421558Srgrimes * /etc/ethers. 3431558Srgrimes */ 3441558Srgrimes hold = 48 * 1024; 3451558Srgrimes (void)setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&hold, 3461558Srgrimes sizeof(hold)); 3471558Srgrimes 3481558Srgrimes if (to->sin_family == AF_INET) 3491558Srgrimes (void)printf("PING %s (%s): %d data bytes\n", hostname, 3501558Srgrimes inet_ntoa(*(struct in_addr *)&to->sin_addr.s_addr), 3511558Srgrimes datalen); 3521558Srgrimes else 3531558Srgrimes (void)printf("PING %s: %d data bytes\n", hostname, datalen); 3541558Srgrimes 3551558Srgrimes (void)signal(SIGINT, finish); 3561558Srgrimes (void)signal(SIGALRM, catcher); 3573792Ssef (void)signal(SIGINFO, status); 3581558Srgrimes 35919864Ssef if (tcgetattr(STDOUT_FILENO, &ts) != -1) { 36019864Ssef reset_kerninfo = !(ts.c_lflag & NOKERNINFO); 36119864Ssef ts.c_lflag |= NOKERNINFO; 36219864Ssef tcsetattr(STDOUT_FILENO, TCSANOW, &ts); 36319864Ssef } 36419864Ssef 3651558Srgrimes while (preload--) /* fire off them quickies */ 3661558Srgrimes pinger(); 3671558Srgrimes 3681558Srgrimes if ((options & F_FLOOD) == 0) 3691558Srgrimes catcher(); /* start things going */ 3701558Srgrimes 3711558Srgrimes for (;;) { 3721558Srgrimes struct sockaddr_in from; 3731558Srgrimes register int cc; 3741558Srgrimes int fromlen; 3751558Srgrimes 3761558Srgrimes if (options & F_FLOOD) { 3771558Srgrimes pinger(); 3781558Srgrimes timeout.tv_sec = 0; 3791558Srgrimes timeout.tv_usec = 10000; 3801558Srgrimes fdmask = 1 << s; 3811558Srgrimes if (select(s + 1, (fd_set *)&fdmask, (fd_set *)NULL, 3821558Srgrimes (fd_set *)NULL, &timeout) < 1) 3831558Srgrimes continue; 3841558Srgrimes } 3851558Srgrimes fromlen = sizeof(from); 3861558Srgrimes if ((cc = recvfrom(s, (char *)packet, packlen, 0, 3871558Srgrimes (struct sockaddr *)&from, &fromlen)) < 0) { 3881558Srgrimes if (errno == EINTR) 3891558Srgrimes continue; 3901558Srgrimes perror("ping: recvfrom"); 3911558Srgrimes continue; 3921558Srgrimes } 3931558Srgrimes pr_pack((char *)packet, cc, &from); 3941558Srgrimes if (npackets && nreceived >= npackets) 3951558Srgrimes break; 3961558Srgrimes } 3971558Srgrimes finish(); 3981558Srgrimes /* NOTREACHED */ 3991558Srgrimes} 4001558Srgrimes 4011558Srgrimes/* 4021558Srgrimes * catcher -- 4031558Srgrimes * This routine causes another PING to be transmitted, and then 4041558Srgrimes * schedules another SIGALRM for 1 second from now. 4051558Srgrimes * 4061558Srgrimes * bug -- 4071558Srgrimes * Our sense of time will slowly skew (i.e., packets will not be 4081558Srgrimes * launched exactly at 1-second intervals). This does not affect the 4091558Srgrimes * quality of the delay and loss statistics. 4101558Srgrimes */ 4111558Srgrimesvoid 4121558Srgrimescatcher() 4131558Srgrimes{ 4141558Srgrimes int waittime; 4151558Srgrimes 4161558Srgrimes pinger(); 4171558Srgrimes (void)signal(SIGALRM, catcher); 4181558Srgrimes if (!npackets || ntransmitted < npackets) 4191558Srgrimes alarm((u_int)interval); 4201558Srgrimes else { 4211558Srgrimes if (nreceived) { 4221558Srgrimes waittime = 2 * tmax / 1000; 4231558Srgrimes if (!waittime) 4241558Srgrimes waittime = 1; 4251558Srgrimes } else 4261558Srgrimes waittime = MAXWAIT; 4271558Srgrimes (void)signal(SIGALRM, finish); 4281558Srgrimes (void)alarm((u_int)waittime); 4291558Srgrimes } 4301558Srgrimes} 4311558Srgrimes 4321558Srgrimes/* 4331558Srgrimes * pinger -- 4341558Srgrimes * Compose and transmit an ICMP ECHO REQUEST packet. The IP packet 4351558Srgrimes * will be added on by the kernel. The ID field is our UNIX process ID, 4361558Srgrimes * and the sequence number is an ascending integer. The first 8 bytes 43717724Sfenner * of the data portion are used to hold a UNIX "timeval" struct in host 4381558Srgrimes * byte-order, to compute the round-trip time. 4391558Srgrimes */ 4401558Srgrimespinger() 4411558Srgrimes{ 4421558Srgrimes register struct icmp *icp; 4431558Srgrimes register int cc; 4441558Srgrimes int i; 4451558Srgrimes 4461558Srgrimes icp = (struct icmp *)outpack; 4471558Srgrimes icp->icmp_type = ICMP_ECHO; 4481558Srgrimes icp->icmp_code = 0; 4491558Srgrimes icp->icmp_cksum = 0; 4501558Srgrimes icp->icmp_seq = ntransmitted++; 4511558Srgrimes icp->icmp_id = ident; /* ID */ 4521558Srgrimes 4531558Srgrimes CLR(icp->icmp_seq % mx_dup_ck); 4541558Srgrimes 4551558Srgrimes if (timing) 4561558Srgrimes (void)gettimeofday((struct timeval *)&outpack[8], 4571558Srgrimes (struct timezone *)NULL); 4581558Srgrimes 4591558Srgrimes cc = datalen + 8; /* skips ICMP portion */ 4601558Srgrimes 4611558Srgrimes /* compute ICMP checksum here */ 4621558Srgrimes icp->icmp_cksum = in_cksum((u_short *)icp, cc); 4631558Srgrimes 4641558Srgrimes i = sendto(s, (char *)outpack, cc, 0, &whereto, 4651558Srgrimes sizeof(struct sockaddr)); 4661558Srgrimes 4671558Srgrimes if (i < 0 || i != cc) { 4681558Srgrimes if (i < 0) 4691558Srgrimes perror("ping: sendto"); 4701558Srgrimes (void)printf("ping: wrote %s %d chars, ret=%d\n", 4711558Srgrimes hostname, cc, i); 4721558Srgrimes } 4731558Srgrimes if (!(options & F_QUIET) && options & F_FLOOD) 4741558Srgrimes (void)write(STDOUT_FILENO, &DOT, 1); 4751558Srgrimes} 4761558Srgrimes 4771558Srgrimes/* 4781558Srgrimes * pr_pack -- 4791558Srgrimes * Print out the packet, if it came from us. This logic is necessary 4801558Srgrimes * because ALL readers of the ICMP socket get a copy of ALL ICMP packets 4811558Srgrimes * which arrive ('tis only fair). This permits multiple copies of this 4821558Srgrimes * program to be run without having intermingled output (or statistics!). 4831558Srgrimes */ 4841558Srgrimespr_pack(buf, cc, from) 4851558Srgrimes char *buf; 4861558Srgrimes int cc; 4871558Srgrimes struct sockaddr_in *from; 4881558Srgrimes{ 4891558Srgrimes register struct icmp *icp; 4901558Srgrimes register u_long l; 4911558Srgrimes register int i, j; 4921558Srgrimes register u_char *cp,*dp; 4931558Srgrimes static int old_rrlen; 4941558Srgrimes static char old_rr[MAX_IPOPTLEN]; 4951558Srgrimes struct ip *ip; 4961558Srgrimes struct timeval tv, *tp; 4971558Srgrimes double triptime; 4981558Srgrimes int hlen, dupflag; 4991558Srgrimes 5001558Srgrimes (void)gettimeofday(&tv, (struct timezone *)NULL); 5011558Srgrimes 5021558Srgrimes /* Check the IP header */ 5031558Srgrimes ip = (struct ip *)buf; 5041558Srgrimes hlen = ip->ip_hl << 2; 5051558Srgrimes if (cc < hlen + ICMP_MINLEN) { 5061558Srgrimes if (options & F_VERBOSE) 5071558Srgrimes (void)fprintf(stderr, 5081558Srgrimes "ping: packet too short (%d bytes) from %s\n", cc, 5091558Srgrimes inet_ntoa(*(struct in_addr *)&from->sin_addr.s_addr)); 5101558Srgrimes return; 5111558Srgrimes } 5121558Srgrimes 5131558Srgrimes /* Now the ICMP part */ 5141558Srgrimes cc -= hlen; 5151558Srgrimes icp = (struct icmp *)(buf + hlen); 5161558Srgrimes if (icp->icmp_type == ICMP_ECHOREPLY) { 5171558Srgrimes if (icp->icmp_id != ident) 5181558Srgrimes return; /* 'Twas not our ECHO */ 5191558Srgrimes ++nreceived; 5201558Srgrimes if (timing) { 5211558Srgrimes#ifndef icmp_data 5221558Srgrimes tp = (struct timeval *)&icp->icmp_ip; 5231558Srgrimes#else 5241558Srgrimes tp = (struct timeval *)icp->icmp_data; 5251558Srgrimes#endif 5261558Srgrimes tvsub(&tv, tp); 5271558Srgrimes triptime = ((double)tv.tv_sec) * 1000.0 + 5281558Srgrimes ((double)tv.tv_usec) / 1000.0; 5291558Srgrimes tsum += triptime; 5301558Srgrimes if (triptime < tmin) 5311558Srgrimes tmin = triptime; 5321558Srgrimes if (triptime > tmax) 5331558Srgrimes tmax = triptime; 5341558Srgrimes } 5351558Srgrimes 5361558Srgrimes if (TST(icp->icmp_seq % mx_dup_ck)) { 5371558Srgrimes ++nrepeats; 5381558Srgrimes --nreceived; 5391558Srgrimes dupflag = 1; 5401558Srgrimes } else { 5411558Srgrimes SET(icp->icmp_seq % mx_dup_ck); 5421558Srgrimes dupflag = 0; 5431558Srgrimes } 5441558Srgrimes 5451558Srgrimes if (options & F_QUIET) 5461558Srgrimes return; 5471558Srgrimes 5481558Srgrimes if (options & F_FLOOD) 5491558Srgrimes (void)write(STDOUT_FILENO, &BSPACE, 1); 5501558Srgrimes else { 5511558Srgrimes (void)printf("%d bytes from %s: icmp_seq=%u", cc, 5521558Srgrimes inet_ntoa(*(struct in_addr *)&from->sin_addr.s_addr), 5531558Srgrimes icp->icmp_seq); 5541558Srgrimes (void)printf(" ttl=%d", ip->ip_ttl); 5551558Srgrimes if (timing) 5561859Sdg (void)printf(" time=%.3f ms", triptime); 5571558Srgrimes if (dupflag) 5581558Srgrimes (void)printf(" (DUP!)"); 5591558Srgrimes /* check the data */ 5601558Srgrimes cp = (u_char*)&icp->icmp_data[8]; 5611558Srgrimes dp = &outpack[8 + sizeof(struct timeval)]; 5621558Srgrimes for (i = 8; i < datalen; ++i, ++cp, ++dp) { 5631558Srgrimes if (*cp != *dp) { 5641558Srgrimes (void)printf("\nwrong data byte #%d should be 0x%x but was 0x%x", 5651558Srgrimes i, *dp, *cp); 5661558Srgrimes cp = (u_char*)&icp->icmp_data[0]; 5671558Srgrimes for (i = 8; i < datalen; ++i, ++cp) { 5681558Srgrimes if ((i % 32) == 8) 5691558Srgrimes (void)printf("\n\t"); 5701558Srgrimes (void)printf("%x ", *cp); 5711558Srgrimes } 5721558Srgrimes break; 5731558Srgrimes } 5741558Srgrimes } 5751558Srgrimes } 5761558Srgrimes } else { 57717724Sfenner /* 57817724Sfenner * We've got something other than an ECHOREPLY. 57917724Sfenner * See if it's a reply to something that we sent. 58017724Sfenner * We can compare IP destination, protocol, 58117724Sfenner * and ICMP type and ID. 58217724Sfenner */ 58317724Sfenner#ifndef icmp_data 58417724Sfenner struct ip *oip = &icp->icmp_ip; 58517724Sfenner#else 58617724Sfenner struct ip *oip = (struct ip *)icp->icmp_data; 58717724Sfenner#endif 58817724Sfenner struct icmp *oicmp = (struct icmp *)(oip + 1); 58917724Sfenner 59017724Sfenner if ((options & F_VERBOSE) || 59117724Sfenner (!(options & F_QUIET2) && 59217724Sfenner (oip->ip_dst.s_addr == 59317724Sfenner ((struct sockaddr_in *)&whereto)->sin_addr.s_addr) && 59417724Sfenner (oip->ip_p == IPPROTO_ICMP) && 59517724Sfenner (oicmp->icmp_type == ICMP_ECHO) && 59617724Sfenner (oicmp->icmp_id == ident))) { 59717724Sfenner (void)printf("%d bytes from %s: ", cc, 59817724Sfenner pr_addr(from->sin_addr.s_addr)); 59917724Sfenner pr_icmph(icp); 60017724Sfenner } else 60117724Sfenner return; 6021558Srgrimes } 6031558Srgrimes 6041558Srgrimes /* Display any IP options */ 6051558Srgrimes cp = (u_char *)buf + sizeof(struct ip); 6061558Srgrimes 6071558Srgrimes for (; hlen > (int)sizeof(struct ip); --hlen, ++cp) 6081558Srgrimes switch (*cp) { 6091558Srgrimes case IPOPT_EOL: 6101558Srgrimes hlen = 0; 6111558Srgrimes break; 6121558Srgrimes case IPOPT_LSRR: 6131558Srgrimes (void)printf("\nLSRR: "); 6141558Srgrimes hlen -= 2; 6151558Srgrimes j = *++cp; 6161558Srgrimes ++cp; 6171558Srgrimes if (j > IPOPT_MINOFF) 6181558Srgrimes for (;;) { 6191558Srgrimes l = *++cp; 6201558Srgrimes l = (l<<8) + *++cp; 6211558Srgrimes l = (l<<8) + *++cp; 6221558Srgrimes l = (l<<8) + *++cp; 6231558Srgrimes if (l == 0) 6241558Srgrimes (void)printf("\t0.0.0.0"); 6251558Srgrimes else 6261558Srgrimes (void)printf("\t%s", pr_addr(ntohl(l))); 6271558Srgrimes hlen -= 4; 6281558Srgrimes j -= 4; 6291558Srgrimes if (j <= IPOPT_MINOFF) 6301558Srgrimes break; 6311558Srgrimes (void)putchar('\n'); 6321558Srgrimes } 6331558Srgrimes break; 6341558Srgrimes case IPOPT_RR: 6351558Srgrimes j = *++cp; /* get length */ 6361558Srgrimes i = *++cp; /* and pointer */ 6371558Srgrimes hlen -= 2; 6381558Srgrimes if (i > j) 6391558Srgrimes i = j; 6401558Srgrimes i -= IPOPT_MINOFF; 6411558Srgrimes if (i <= 0) 6421558Srgrimes continue; 6431558Srgrimes if (i == old_rrlen 6441558Srgrimes && cp == (u_char *)buf + sizeof(struct ip) + 2 6451558Srgrimes && !bcmp((char *)cp, old_rr, i) 6461558Srgrimes && !(options & F_FLOOD)) { 6471558Srgrimes (void)printf("\t(same route)"); 6481558Srgrimes i = ((i + 3) / 4) * 4; 6491558Srgrimes hlen -= i; 6501558Srgrimes cp += i; 6511558Srgrimes break; 6521558Srgrimes } 6531558Srgrimes old_rrlen = i; 6541558Srgrimes bcopy((char *)cp, old_rr, i); 6551558Srgrimes (void)printf("\nRR: "); 6561558Srgrimes for (;;) { 6571558Srgrimes l = *++cp; 6581558Srgrimes l = (l<<8) + *++cp; 6591558Srgrimes l = (l<<8) + *++cp; 6601558Srgrimes l = (l<<8) + *++cp; 6611558Srgrimes if (l == 0) 6621558Srgrimes (void)printf("\t0.0.0.0"); 6631558Srgrimes else 6641558Srgrimes (void)printf("\t%s", pr_addr(ntohl(l))); 6651558Srgrimes hlen -= 4; 6661558Srgrimes i -= 4; 6671558Srgrimes if (i <= 0) 6681558Srgrimes break; 6691558Srgrimes (void)putchar('\n'); 6701558Srgrimes } 6711558Srgrimes break; 6721558Srgrimes case IPOPT_NOP: 6731558Srgrimes (void)printf("\nNOP"); 6741558Srgrimes break; 6751558Srgrimes default: 6761558Srgrimes (void)printf("\nunknown option %x", *cp); 6771558Srgrimes break; 6781558Srgrimes } 6791558Srgrimes if (!(options & F_FLOOD)) { 6801558Srgrimes (void)putchar('\n'); 6811558Srgrimes (void)fflush(stdout); 6821558Srgrimes } 6831558Srgrimes} 6841558Srgrimes 6851558Srgrimes/* 6861558Srgrimes * in_cksum -- 6871558Srgrimes * Checksum routine for Internet Protocol family headers (C Version) 6881558Srgrimes */ 6891558Srgrimesin_cksum(addr, len) 6901558Srgrimes u_short *addr; 6911558Srgrimes int len; 6921558Srgrimes{ 6931558Srgrimes register int nleft = len; 6941558Srgrimes register u_short *w = addr; 6951558Srgrimes register int sum = 0; 6961558Srgrimes u_short answer = 0; 6971558Srgrimes 6981558Srgrimes /* 6991558Srgrimes * Our algorithm is simple, using a 32 bit accumulator (sum), we add 7001558Srgrimes * sequential 16 bit words to it, and at the end, fold back all the 7011558Srgrimes * carry bits from the top 16 bits into the lower 16 bits. 7021558Srgrimes */ 7031558Srgrimes while (nleft > 1) { 7041558Srgrimes sum += *w++; 7051558Srgrimes nleft -= 2; 7061558Srgrimes } 7071558Srgrimes 7081558Srgrimes /* mop up an odd byte, if necessary */ 7091558Srgrimes if (nleft == 1) { 7101558Srgrimes *(u_char *)(&answer) = *(u_char *)w ; 7111558Srgrimes sum += answer; 7121558Srgrimes } 7131558Srgrimes 7141558Srgrimes /* add back carry outs from top 16 bits to low 16 bits */ 7151558Srgrimes sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ 7161558Srgrimes sum += (sum >> 16); /* add carry */ 7171558Srgrimes answer = ~sum; /* truncate to 16 bits */ 7181558Srgrimes return(answer); 7191558Srgrimes} 7201558Srgrimes 7211558Srgrimes/* 7221558Srgrimes * tvsub -- 7231558Srgrimes * Subtract 2 timeval structs: out = out - in. Out is assumed to 7241558Srgrimes * be >= in. 7251558Srgrimes */ 7261558Srgrimestvsub(out, in) 7271558Srgrimes register struct timeval *out, *in; 7281558Srgrimes{ 7291558Srgrimes if ((out->tv_usec -= in->tv_usec) < 0) { 7301558Srgrimes --out->tv_sec; 7311558Srgrimes out->tv_usec += 1000000; 7321558Srgrimes } 7331558Srgrimes out->tv_sec -= in->tv_sec; 7341558Srgrimes} 7351558Srgrimes 7361558Srgrimes/* 7373792Ssef * status -- 7383792Ssef * Print out statistics when SIGINFO is received. 7393792Ssef */ 7403792Ssef 7413792Ssefvoid 7423792Ssefstatus() 7433792Ssef{ 7443792Ssef double temp_min = nreceived ? tmin : 0; 7453792Ssef (void)fprintf(stderr, "%ld/%ld packets received (%ld%%) " 7463792Ssef "%.3f min / %.3f avg / %.3f max\n", 7478871Srgrimes nreceived, ntransmitted, 7488871Srgrimes (ntransmitted ? 7493792Ssef 100 - (int) (((ntransmitted - nreceived) * 100) 7503792Ssef / ntransmitted) 7513792Ssef : 0), 7523792Ssef temp_min, 7533792Ssef ((nreceived + nrepeats) ? 7543792Ssef (tsum / (nreceived + nrepeats))/1000.0 7553792Ssef : tsum), 7563792Ssef tmax/ 1000.0); 7573792Ssef} 7583792Ssef 7593792Ssef/* 7601558Srgrimes * finish -- 7611558Srgrimes * Print out statistics, and give up. 7621558Srgrimes */ 7631558Srgrimesvoid 7641558Srgrimesfinish() 7651558Srgrimes{ 7661558Srgrimes register int i; 7673792Ssef struct termios ts; 7681558Srgrimes 7691558Srgrimes (void)signal(SIGINT, SIG_IGN); 7701558Srgrimes (void)putchar('\n'); 7711558Srgrimes (void)fflush(stdout); 7721558Srgrimes (void)printf("--- %s ping statistics ---\n", hostname); 7731558Srgrimes (void)printf("%ld packets transmitted, ", ntransmitted); 7741558Srgrimes (void)printf("%ld packets received, ", nreceived); 7751558Srgrimes if (nrepeats) 7761558Srgrimes (void)printf("+%ld duplicates, ", nrepeats); 7771558Srgrimes if (ntransmitted) 7781558Srgrimes if (nreceived > ntransmitted) 7791558Srgrimes (void)printf("-- somebody's printing up packets!"); 7801558Srgrimes else 7811558Srgrimes (void)printf("%d%% packet loss", 7821558Srgrimes (int) (((ntransmitted - nreceived) * 100) / 7831558Srgrimes ntransmitted)); 7841558Srgrimes (void)putchar('\n'); 7851558Srgrimes if (nreceived && timing) { 7861558Srgrimes /* Only display average to microseconds */ 7871558Srgrimes i = 1000.0 * tsum / (nreceived + nrepeats); 7881859Sdg (void)printf("round-trip min/avg/max = %.3f/%.3f/%.3f ms\n", 7891558Srgrimes tmin, ((double)i) / 1000.0, tmax); 7901558Srgrimes } 79119395Sbde if (reset_kerninfo && tcgetattr(STDOUT_FILENO, &ts) != -1) { 7923792Ssef ts.c_lflag &= ~NOKERNINFO; 79319395Sbde tcsetattr(STDOUT_FILENO, TCSANOW, &ts); 7943792Ssef } 7953792Ssef 7968871Srgrimes if (nreceived) 7974862Sdg exit(0); 7984862Sdg else 7994862Sdg exit(2); 8001558Srgrimes} 8011558Srgrimes 8021558Srgrimes#ifdef notdef 8031558Srgrimesstatic char *ttab[] = { 8041558Srgrimes "Echo Reply", /* ip + seq + udata */ 8051558Srgrimes "Dest Unreachable", /* net, host, proto, port, frag, sr + IP */ 8061558Srgrimes "Source Quench", /* IP */ 8071558Srgrimes "Redirect", /* redirect type, gateway, + IP */ 8081558Srgrimes "Echo", 8091558Srgrimes "Time Exceeded", /* transit, frag reassem + IP */ 8101558Srgrimes "Parameter Problem", /* pointer + IP */ 8111558Srgrimes "Timestamp", /* id + seq + three timestamps */ 8121558Srgrimes "Timestamp Reply", /* " */ 8131558Srgrimes "Info Request", /* id + sq */ 8141558Srgrimes "Info Reply" /* " */ 8151558Srgrimes}; 8161558Srgrimes#endif 8171558Srgrimes 8181558Srgrimes/* 8191558Srgrimes * pr_icmph -- 8201558Srgrimes * Print a descriptive string about an ICMP header. 8211558Srgrimes */ 8221558Srgrimespr_icmph(icp) 8231558Srgrimes struct icmp *icp; 8241558Srgrimes{ 8251558Srgrimes switch(icp->icmp_type) { 8261558Srgrimes case ICMP_ECHOREPLY: 8271558Srgrimes (void)printf("Echo Reply\n"); 8281558Srgrimes /* XXX ID + Seq + Data */ 8291558Srgrimes break; 8301558Srgrimes case ICMP_UNREACH: 8311558Srgrimes switch(icp->icmp_code) { 8321558Srgrimes case ICMP_UNREACH_NET: 8331558Srgrimes (void)printf("Destination Net Unreachable\n"); 8341558Srgrimes break; 8351558Srgrimes case ICMP_UNREACH_HOST: 8361558Srgrimes (void)printf("Destination Host Unreachable\n"); 8371558Srgrimes break; 8381558Srgrimes case ICMP_UNREACH_PROTOCOL: 8391558Srgrimes (void)printf("Destination Protocol Unreachable\n"); 8401558Srgrimes break; 8411558Srgrimes case ICMP_UNREACH_PORT: 8421558Srgrimes (void)printf("Destination Port Unreachable\n"); 8431558Srgrimes break; 8441558Srgrimes case ICMP_UNREACH_NEEDFRAG: 84517724Sfenner (void)printf("frag needed and DF set (MTU %d)\n", 84617724Sfenner icp->icmp_nextmtu); 8471558Srgrimes break; 8481558Srgrimes case ICMP_UNREACH_SRCFAIL: 8491558Srgrimes (void)printf("Source Route Failed\n"); 8501558Srgrimes break; 85117724Sfenner case ICMP_UNREACH_FILTER_PROHIB: 85217724Sfenner (void)printf("Communication prohibited by filter\n"); 85317724Sfenner break; 8541558Srgrimes default: 8551558Srgrimes (void)printf("Dest Unreachable, Bad Code: %d\n", 8561558Srgrimes icp->icmp_code); 8571558Srgrimes break; 8581558Srgrimes } 8591558Srgrimes /* Print returned IP header information */ 8601558Srgrimes#ifndef icmp_data 8611558Srgrimes pr_retip(&icp->icmp_ip); 8621558Srgrimes#else 8631558Srgrimes pr_retip((struct ip *)icp->icmp_data); 8641558Srgrimes#endif 8651558Srgrimes break; 8661558Srgrimes case ICMP_SOURCEQUENCH: 8671558Srgrimes (void)printf("Source Quench\n"); 8681558Srgrimes#ifndef icmp_data 8691558Srgrimes pr_retip(&icp->icmp_ip); 8701558Srgrimes#else 8711558Srgrimes pr_retip((struct ip *)icp->icmp_data); 8721558Srgrimes#endif 8731558Srgrimes break; 8741558Srgrimes case ICMP_REDIRECT: 8751558Srgrimes switch(icp->icmp_code) { 8761558Srgrimes case ICMP_REDIRECT_NET: 8771558Srgrimes (void)printf("Redirect Network"); 8781558Srgrimes break; 8791558Srgrimes case ICMP_REDIRECT_HOST: 8801558Srgrimes (void)printf("Redirect Host"); 8811558Srgrimes break; 8821558Srgrimes case ICMP_REDIRECT_TOSNET: 8831558Srgrimes (void)printf("Redirect Type of Service and Network"); 8841558Srgrimes break; 8851558Srgrimes case ICMP_REDIRECT_TOSHOST: 8861558Srgrimes (void)printf("Redirect Type of Service and Host"); 8871558Srgrimes break; 8881558Srgrimes default: 8891558Srgrimes (void)printf("Redirect, Bad Code: %d", icp->icmp_code); 8901558Srgrimes break; 8911558Srgrimes } 8921558Srgrimes (void)printf("(New addr: 0x%08lx)\n", icp->icmp_gwaddr.s_addr); 8931558Srgrimes#ifndef icmp_data 8941558Srgrimes pr_retip(&icp->icmp_ip); 8951558Srgrimes#else 8961558Srgrimes pr_retip((struct ip *)icp->icmp_data); 8971558Srgrimes#endif 8981558Srgrimes break; 8991558Srgrimes case ICMP_ECHO: 9001558Srgrimes (void)printf("Echo Request\n"); 9011558Srgrimes /* XXX ID + Seq + Data */ 9021558Srgrimes break; 9031558Srgrimes case ICMP_TIMXCEED: 9041558Srgrimes switch(icp->icmp_code) { 9051558Srgrimes case ICMP_TIMXCEED_INTRANS: 9061558Srgrimes (void)printf("Time to live exceeded\n"); 9071558Srgrimes break; 9081558Srgrimes case ICMP_TIMXCEED_REASS: 9091558Srgrimes (void)printf("Frag reassembly time exceeded\n"); 9101558Srgrimes break; 9111558Srgrimes default: 9121558Srgrimes (void)printf("Time exceeded, Bad Code: %d\n", 9131558Srgrimes icp->icmp_code); 9141558Srgrimes break; 9151558Srgrimes } 9161558Srgrimes#ifndef icmp_data 9171558Srgrimes pr_retip(&icp->icmp_ip); 9181558Srgrimes#else 9191558Srgrimes pr_retip((struct ip *)icp->icmp_data); 9201558Srgrimes#endif 9211558Srgrimes break; 9221558Srgrimes case ICMP_PARAMPROB: 9231558Srgrimes (void)printf("Parameter problem: pointer = 0x%02x\n", 9241558Srgrimes icp->icmp_hun.ih_pptr); 9251558Srgrimes#ifndef icmp_data 9261558Srgrimes pr_retip(&icp->icmp_ip); 9271558Srgrimes#else 9281558Srgrimes pr_retip((struct ip *)icp->icmp_data); 9291558Srgrimes#endif 9301558Srgrimes break; 9311558Srgrimes case ICMP_TSTAMP: 9321558Srgrimes (void)printf("Timestamp\n"); 9331558Srgrimes /* XXX ID + Seq + 3 timestamps */ 9341558Srgrimes break; 9351558Srgrimes case ICMP_TSTAMPREPLY: 9361558Srgrimes (void)printf("Timestamp Reply\n"); 9371558Srgrimes /* XXX ID + Seq + 3 timestamps */ 9381558Srgrimes break; 9391558Srgrimes case ICMP_IREQ: 9401558Srgrimes (void)printf("Information Request\n"); 9411558Srgrimes /* XXX ID + Seq */ 9421558Srgrimes break; 9431558Srgrimes case ICMP_IREQREPLY: 9441558Srgrimes (void)printf("Information Reply\n"); 9451558Srgrimes /* XXX ID + Seq */ 9461558Srgrimes break; 9471558Srgrimes case ICMP_MASKREQ: 9481558Srgrimes (void)printf("Address Mask Request\n"); 9491558Srgrimes break; 9501558Srgrimes case ICMP_MASKREPLY: 9511558Srgrimes (void)printf("Address Mask Reply\n"); 9521558Srgrimes break; 95317724Sfenner case ICMP_ROUTERADVERT: 95417724Sfenner (void)printf("Router Advertisement\n"); 95517724Sfenner break; 95617724Sfenner case ICMP_ROUTERSOLICIT: 95717724Sfenner (void)printf("Router Solicitation\n"); 95817724Sfenner break; 9591558Srgrimes default: 9601558Srgrimes (void)printf("Bad ICMP type: %d\n", icp->icmp_type); 9611558Srgrimes } 9621558Srgrimes} 9631558Srgrimes 9641558Srgrimes/* 9651558Srgrimes * pr_iph -- 9661558Srgrimes * Print an IP header with options. 9671558Srgrimes */ 9681558Srgrimespr_iph(ip) 9691558Srgrimes struct ip *ip; 9701558Srgrimes{ 9711558Srgrimes int hlen; 9721558Srgrimes u_char *cp; 9731558Srgrimes 9741558Srgrimes hlen = ip->ip_hl << 2; 9751558Srgrimes cp = (u_char *)ip + 20; /* point to options */ 9761558Srgrimes 97717724Sfenner (void)printf("Vr HL TOS Len ID Flg off TTL Pro cks Src Dst\n"); 9781558Srgrimes (void)printf(" %1x %1x %02x %04x %04x", 97917724Sfenner ip->ip_v, ip->ip_hl, ip->ip_tos, ntohs(ip->ip_len), 98017724Sfenner ntohs(ip->ip_id)); 98117724Sfenner (void)printf(" %1x %04x", (ntohl(ip->ip_off) & 0xe000) >> 13, 98217724Sfenner ntohl(ip->ip_off) & 0x1fff); 98317724Sfenner (void)printf(" %02x %02x %04x", ip->ip_ttl, ip->ip_p, 98417724Sfenner ntohs(ip->ip_sum)); 9851558Srgrimes (void)printf(" %s ", inet_ntoa(*(struct in_addr *)&ip->ip_src.s_addr)); 9861558Srgrimes (void)printf(" %s ", inet_ntoa(*(struct in_addr *)&ip->ip_dst.s_addr)); 98717724Sfenner /* dump any option bytes */ 9881558Srgrimes while (hlen-- > 20) { 9891558Srgrimes (void)printf("%02x", *cp++); 9901558Srgrimes } 9911558Srgrimes (void)putchar('\n'); 9921558Srgrimes} 9931558Srgrimes 9941558Srgrimes/* 9951558Srgrimes * pr_addr -- 9961558Srgrimes * Return an ascii host address as a dotted quad and optionally with 9971558Srgrimes * a hostname. 9981558Srgrimes */ 9991558Srgrimeschar * 10001558Srgrimespr_addr(l) 10011558Srgrimes u_long l; 10021558Srgrimes{ 10031558Srgrimes struct hostent *hp; 10041558Srgrimes static char buf[80]; 10051558Srgrimes 10061558Srgrimes if ((options & F_NUMERIC) || 10071558Srgrimes !(hp = gethostbyaddr((char *)&l, 4, AF_INET))) 100817320Speter (void)snprintf(buf, sizeof(buf), "%s", 100917320Speter inet_ntoa(*(struct in_addr *)&l)); 10101558Srgrimes else 101117320Speter (void)snprintf(buf, sizeof(buf), "%s (%s)", hp->h_name, 10121558Srgrimes inet_ntoa(*(struct in_addr *)&l)); 10131558Srgrimes return(buf); 10141558Srgrimes} 10151558Srgrimes 10161558Srgrimes/* 10171558Srgrimes * pr_retip -- 10181558Srgrimes * Dump some info on a returned (via ICMP) IP packet. 10191558Srgrimes */ 10201558Srgrimespr_retip(ip) 10211558Srgrimes struct ip *ip; 10221558Srgrimes{ 10231558Srgrimes int hlen; 10241558Srgrimes u_char *cp; 10251558Srgrimes 10261558Srgrimes pr_iph(ip); 10271558Srgrimes hlen = ip->ip_hl << 2; 10281558Srgrimes cp = (u_char *)ip + hlen; 10291558Srgrimes 10301558Srgrimes if (ip->ip_p == 6) 10311558Srgrimes (void)printf("TCP: from port %u, to port %u (decimal)\n", 10321558Srgrimes (*cp * 256 + *(cp + 1)), (*(cp + 2) * 256 + *(cp + 3))); 10331558Srgrimes else if (ip->ip_p == 17) 10341558Srgrimes (void)printf("UDP: from port %u, to port %u (decimal)\n", 10351558Srgrimes (*cp * 256 + *(cp + 1)), (*(cp + 2) * 256 + *(cp + 3))); 10361558Srgrimes} 10371558Srgrimes 10381558Srgrimesfill(bp, patp) 10391558Srgrimes char *bp, *patp; 10401558Srgrimes{ 10411558Srgrimes register int ii, jj, kk; 10421558Srgrimes int pat[16]; 10431558Srgrimes char *cp; 10441558Srgrimes 10451558Srgrimes for (cp = patp; *cp; cp++) 10461558Srgrimes if (!isxdigit(*cp)) { 10471558Srgrimes (void)fprintf(stderr, 10481558Srgrimes "ping: patterns must be specified as hex digits.\n"); 10491558Srgrimes exit(1); 10501558Srgrimes } 10511558Srgrimes ii = sscanf(patp, 10521558Srgrimes "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x", 10531558Srgrimes &pat[0], &pat[1], &pat[2], &pat[3], &pat[4], &pat[5], &pat[6], 10541558Srgrimes &pat[7], &pat[8], &pat[9], &pat[10], &pat[11], &pat[12], 10551558Srgrimes &pat[13], &pat[14], &pat[15]); 10561558Srgrimes 10571558Srgrimes if (ii > 0) 10581558Srgrimes for (kk = 0; 10591558Srgrimes kk <= MAXPACKET - (8 + sizeof(struct timeval) + ii); 10601558Srgrimes kk += ii) 10611558Srgrimes for (jj = 0; jj < ii; ++jj) 10621558Srgrimes bp[jj + kk] = pat[jj]; 10631558Srgrimes if (!(options & F_QUIET)) { 10641558Srgrimes (void)printf("PATTERN: 0x"); 10651558Srgrimes for (jj = 0; jj < ii; ++jj) 10661558Srgrimes (void)printf("%02x", bp[jj] & 0xFF); 10671558Srgrimes (void)printf("\n"); 10681558Srgrimes } 10691558Srgrimes} 10701558Srgrimes 10711558Srgrimesusage() 10721558Srgrimes{ 10731558Srgrimes (void)fprintf(stderr, 10741558Srgrimes "usage: ping [-Rdfnqrv] [-c count] [-i wait] [-l preload]\n\t[-p pattern] [-s packetsize] host\n"); 10751558Srgrimes exit(1); 10761558Srgrimes} 1077