ping.c revision 17724
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 if (tcgetattr (0, &ts) != -1) { 1803792Ssef reset_kerninfo = !(ts.c_lflag & NOKERNINFO); 1813792Ssef ts.c_lflag |= NOKERNINFO; 1823792Ssef tcsetattr (0, TCSANOW, &ts); 1833792Ssef } 1843792Ssef 1851558Srgrimes datap = &outpack[8 + sizeof(struct timeval)]; 18617724Sfenner while ((ch = getopt(argc, argv, "QRc:dfh:i:l:np:qrs:v")) != EOF) 1871558Srgrimes switch(ch) { 1881558Srgrimes case 'c': 1891558Srgrimes npackets = atoi(optarg); 1901558Srgrimes if (npackets <= 0) { 1911558Srgrimes (void)fprintf(stderr, 1921558Srgrimes "ping: bad number of packets to transmit.\n"); 1931558Srgrimes exit(1); 1941558Srgrimes } 1951558Srgrimes break; 1961558Srgrimes case 'd': 1971558Srgrimes options |= F_SO_DEBUG; 1981558Srgrimes break; 1991558Srgrimes case 'f': 2001558Srgrimes if (getuid()) { 2011558Srgrimes (void)fprintf(stderr, 2021558Srgrimes "ping: %s\n", strerror(EPERM)); 2031558Srgrimes exit(1); 2041558Srgrimes } 2051558Srgrimes options |= F_FLOOD; 2061558Srgrimes setbuf(stdout, (char *)NULL); 2071558Srgrimes break; 2081558Srgrimes case 'i': /* wait between sending packets */ 2091558Srgrimes interval = atoi(optarg); 2101558Srgrimes if (interval <= 0) { 2111558Srgrimes (void)fprintf(stderr, 2121558Srgrimes "ping: bad timing interval.\n"); 2131558Srgrimes exit(1); 2141558Srgrimes } 2151558Srgrimes options |= F_INTERVAL; 2161558Srgrimes break; 2171558Srgrimes case 'l': 2181558Srgrimes preload = atoi(optarg); 2191558Srgrimes if (preload < 0) { 2201558Srgrimes (void)fprintf(stderr, 2211558Srgrimes "ping: bad preload value.\n"); 2221558Srgrimes exit(1); 2231558Srgrimes } 2241558Srgrimes break; 2251558Srgrimes case 'n': 2261558Srgrimes options |= F_NUMERIC; 2271558Srgrimes break; 2281558Srgrimes case 'p': /* fill buffer with user pattern */ 2291558Srgrimes options |= F_PINGFILLED; 2301558Srgrimes fill((char *)datap, optarg); 2311558Srgrimes break; 23217724Sfenner case 'Q': 23317724Sfenner options |= F_QUIET2; 23417724Sfenner break; 2351558Srgrimes case 'q': 2361558Srgrimes options |= F_QUIET; 2371558Srgrimes break; 2381558Srgrimes case 'R': 2391558Srgrimes options |= F_RROUTE; 2401558Srgrimes break; 2411558Srgrimes case 'r': 2421558Srgrimes options |= F_SO_DONTROUTE; 2431558Srgrimes break; 2441558Srgrimes case 's': /* size of packet to send */ 2451558Srgrimes datalen = atoi(optarg); 2461558Srgrimes if (datalen > MAXPACKET) { 2471558Srgrimes (void)fprintf(stderr, 2481558Srgrimes "ping: packet size too large.\n"); 2491558Srgrimes exit(1); 2501558Srgrimes } 2511558Srgrimes if (datalen <= 0) { 2521558Srgrimes (void)fprintf(stderr, 2531558Srgrimes "ping: illegal packet size.\n"); 2541558Srgrimes exit(1); 2551558Srgrimes } 2561558Srgrimes break; 2571558Srgrimes case 'v': 2581558Srgrimes options |= F_VERBOSE; 2591558Srgrimes break; 2601558Srgrimes default: 2611558Srgrimes usage(); 2621558Srgrimes } 2631558Srgrimes argc -= optind; 2641558Srgrimes argv += optind; 2651558Srgrimes 2661558Srgrimes if (argc != 1) 2671558Srgrimes usage(); 2681558Srgrimes target = *argv; 2691558Srgrimes 2701558Srgrimes bzero((char *)&whereto, sizeof(struct sockaddr)); 2711558Srgrimes to = (struct sockaddr_in *)&whereto; 2721558Srgrimes to->sin_family = AF_INET; 2731558Srgrimes to->sin_addr.s_addr = inet_addr(target); 2741558Srgrimes if (to->sin_addr.s_addr != (u_int)-1) 2751558Srgrimes hostname = target; 2761558Srgrimes else { 2771558Srgrimes hp = gethostbyname(target); 2781558Srgrimes if (!hp) { 2791558Srgrimes (void)fprintf(stderr, 2801558Srgrimes "ping: unknown host %s\n", target); 2811558Srgrimes exit(1); 2821558Srgrimes } 2831558Srgrimes to->sin_family = hp->h_addrtype; 2841558Srgrimes bcopy(hp->h_addr, (caddr_t)&to->sin_addr, hp->h_length); 2851558Srgrimes (void)strncpy(hnamebuf, hp->h_name, sizeof(hnamebuf) - 1); 2861558Srgrimes hostname = hnamebuf; 2871558Srgrimes } 2881558Srgrimes 2891558Srgrimes if (options & F_FLOOD && options & F_INTERVAL) { 2901558Srgrimes (void)fprintf(stderr, 2911558Srgrimes "ping: -f and -i incompatible options.\n"); 2921558Srgrimes exit(1); 2931558Srgrimes } 2941558Srgrimes 2951558Srgrimes if (datalen >= sizeof(struct timeval)) /* can we time transfer */ 2961558Srgrimes timing = 1; 2971558Srgrimes packlen = datalen + MAXIPLEN + MAXICMPLEN; 2981558Srgrimes if (!(packet = (u_char *)malloc((u_int)packlen))) { 2991558Srgrimes (void)fprintf(stderr, "ping: out of memory.\n"); 3001558Srgrimes exit(1); 3011558Srgrimes } 3021558Srgrimes if (!(options & F_PINGFILLED)) 3031558Srgrimes for (i = 8; i < datalen; ++i) 3041558Srgrimes *datap++ = i; 3051558Srgrimes 3061558Srgrimes ident = getpid() & 0xFFFF; 3071558Srgrimes 30817474Sfenner if (!proto) { 3091558Srgrimes (void)fprintf(stderr, "ping: unknown protocol icmp.\n"); 3101558Srgrimes exit(1); 3111558Srgrimes } 31217474Sfenner if (s < 0) { 31317474Sfenner errno = sockerrno; 3141558Srgrimes perror("ping: socket"); 3151558Srgrimes exit(1); 3161558Srgrimes } 3171558Srgrimes hold = 1; 3181558Srgrimes if (options & F_SO_DEBUG) 3191558Srgrimes (void)setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&hold, 3201558Srgrimes sizeof(hold)); 3211558Srgrimes if (options & F_SO_DONTROUTE) 3221558Srgrimes (void)setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (char *)&hold, 3231558Srgrimes sizeof(hold)); 3241558Srgrimes 3251558Srgrimes /* record route option */ 3261558Srgrimes if (options & F_RROUTE) { 3271558Srgrimes#ifdef IP_OPTIONS 3281558Srgrimes rspace[IPOPT_OPTVAL] = IPOPT_RR; 3291558Srgrimes rspace[IPOPT_OLEN] = sizeof(rspace)-1; 3301558Srgrimes rspace[IPOPT_OFFSET] = IPOPT_MINOFF; 3311558Srgrimes if (setsockopt(s, IPPROTO_IP, IP_OPTIONS, rspace, 3321558Srgrimes sizeof(rspace)) < 0) { 3331558Srgrimes perror("ping: record route"); 3341558Srgrimes exit(1); 3351558Srgrimes } 3361558Srgrimes#else 3371558Srgrimes (void)fprintf(stderr, 3381558Srgrimes "ping: record route not available in this implementation.\n"); 3391558Srgrimes exit(1); 3401558Srgrimes#endif /* IP_OPTIONS */ 3411558Srgrimes } 3421558Srgrimes 3431558Srgrimes /* 3441558Srgrimes * When pinging the broadcast address, you can get a lot of answers. 3451558Srgrimes * Doing something so evil is useful if you are trying to stress the 3461558Srgrimes * ethernet, or just want to fill the arp cache to get some stuff for 3471558Srgrimes * /etc/ethers. 3481558Srgrimes */ 3491558Srgrimes hold = 48 * 1024; 3501558Srgrimes (void)setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&hold, 3511558Srgrimes sizeof(hold)); 3521558Srgrimes 3531558Srgrimes if (to->sin_family == AF_INET) 3541558Srgrimes (void)printf("PING %s (%s): %d data bytes\n", hostname, 3551558Srgrimes inet_ntoa(*(struct in_addr *)&to->sin_addr.s_addr), 3561558Srgrimes datalen); 3571558Srgrimes else 3581558Srgrimes (void)printf("PING %s: %d data bytes\n", hostname, datalen); 3591558Srgrimes 3601558Srgrimes (void)signal(SIGINT, finish); 3611558Srgrimes (void)signal(SIGALRM, catcher); 3623792Ssef (void)signal(SIGINFO, status); 3631558Srgrimes 3641558Srgrimes while (preload--) /* fire off them quickies */ 3651558Srgrimes pinger(); 3661558Srgrimes 3671558Srgrimes if ((options & F_FLOOD) == 0) 3681558Srgrimes catcher(); /* start things going */ 3691558Srgrimes 3701558Srgrimes for (;;) { 3711558Srgrimes struct sockaddr_in from; 3721558Srgrimes register int cc; 3731558Srgrimes int fromlen; 3741558Srgrimes 3751558Srgrimes if (options & F_FLOOD) { 3761558Srgrimes pinger(); 3771558Srgrimes timeout.tv_sec = 0; 3781558Srgrimes timeout.tv_usec = 10000; 3791558Srgrimes fdmask = 1 << s; 3801558Srgrimes if (select(s + 1, (fd_set *)&fdmask, (fd_set *)NULL, 3811558Srgrimes (fd_set *)NULL, &timeout) < 1) 3821558Srgrimes continue; 3831558Srgrimes } 3841558Srgrimes fromlen = sizeof(from); 3851558Srgrimes if ((cc = recvfrom(s, (char *)packet, packlen, 0, 3861558Srgrimes (struct sockaddr *)&from, &fromlen)) < 0) { 3871558Srgrimes if (errno == EINTR) 3881558Srgrimes continue; 3891558Srgrimes perror("ping: recvfrom"); 3901558Srgrimes continue; 3911558Srgrimes } 3921558Srgrimes pr_pack((char *)packet, cc, &from); 3931558Srgrimes if (npackets && nreceived >= npackets) 3941558Srgrimes break; 3951558Srgrimes } 3961558Srgrimes finish(); 3971558Srgrimes /* NOTREACHED */ 3981558Srgrimes} 3991558Srgrimes 4001558Srgrimes/* 4011558Srgrimes * catcher -- 4021558Srgrimes * This routine causes another PING to be transmitted, and then 4031558Srgrimes * schedules another SIGALRM for 1 second from now. 4041558Srgrimes * 4051558Srgrimes * bug -- 4061558Srgrimes * Our sense of time will slowly skew (i.e., packets will not be 4071558Srgrimes * launched exactly at 1-second intervals). This does not affect the 4081558Srgrimes * quality of the delay and loss statistics. 4091558Srgrimes */ 4101558Srgrimesvoid 4111558Srgrimescatcher() 4121558Srgrimes{ 4131558Srgrimes int waittime; 4141558Srgrimes 4151558Srgrimes pinger(); 4161558Srgrimes (void)signal(SIGALRM, catcher); 4171558Srgrimes if (!npackets || ntransmitted < npackets) 4181558Srgrimes alarm((u_int)interval); 4191558Srgrimes else { 4201558Srgrimes if (nreceived) { 4211558Srgrimes waittime = 2 * tmax / 1000; 4221558Srgrimes if (!waittime) 4231558Srgrimes waittime = 1; 4241558Srgrimes } else 4251558Srgrimes waittime = MAXWAIT; 4261558Srgrimes (void)signal(SIGALRM, finish); 4271558Srgrimes (void)alarm((u_int)waittime); 4281558Srgrimes } 4291558Srgrimes} 4301558Srgrimes 4311558Srgrimes/* 4321558Srgrimes * pinger -- 4331558Srgrimes * Compose and transmit an ICMP ECHO REQUEST packet. The IP packet 4341558Srgrimes * will be added on by the kernel. The ID field is our UNIX process ID, 4351558Srgrimes * and the sequence number is an ascending integer. The first 8 bytes 43617724Sfenner * of the data portion are used to hold a UNIX "timeval" struct in host 4371558Srgrimes * byte-order, to compute the round-trip time. 4381558Srgrimes */ 4391558Srgrimespinger() 4401558Srgrimes{ 4411558Srgrimes register struct icmp *icp; 4421558Srgrimes register int cc; 4431558Srgrimes int i; 4441558Srgrimes 4451558Srgrimes icp = (struct icmp *)outpack; 4461558Srgrimes icp->icmp_type = ICMP_ECHO; 4471558Srgrimes icp->icmp_code = 0; 4481558Srgrimes icp->icmp_cksum = 0; 4491558Srgrimes icp->icmp_seq = ntransmitted++; 4501558Srgrimes icp->icmp_id = ident; /* ID */ 4511558Srgrimes 4521558Srgrimes CLR(icp->icmp_seq % mx_dup_ck); 4531558Srgrimes 4541558Srgrimes if (timing) 4551558Srgrimes (void)gettimeofday((struct timeval *)&outpack[8], 4561558Srgrimes (struct timezone *)NULL); 4571558Srgrimes 4581558Srgrimes cc = datalen + 8; /* skips ICMP portion */ 4591558Srgrimes 4601558Srgrimes /* compute ICMP checksum here */ 4611558Srgrimes icp->icmp_cksum = in_cksum((u_short *)icp, cc); 4621558Srgrimes 4631558Srgrimes i = sendto(s, (char *)outpack, cc, 0, &whereto, 4641558Srgrimes sizeof(struct sockaddr)); 4651558Srgrimes 4661558Srgrimes if (i < 0 || i != cc) { 4671558Srgrimes if (i < 0) 4681558Srgrimes perror("ping: sendto"); 4691558Srgrimes (void)printf("ping: wrote %s %d chars, ret=%d\n", 4701558Srgrimes hostname, cc, i); 4711558Srgrimes } 4721558Srgrimes if (!(options & F_QUIET) && options & F_FLOOD) 4731558Srgrimes (void)write(STDOUT_FILENO, &DOT, 1); 4741558Srgrimes} 4751558Srgrimes 4761558Srgrimes/* 4771558Srgrimes * pr_pack -- 4781558Srgrimes * Print out the packet, if it came from us. This logic is necessary 4791558Srgrimes * because ALL readers of the ICMP socket get a copy of ALL ICMP packets 4801558Srgrimes * which arrive ('tis only fair). This permits multiple copies of this 4811558Srgrimes * program to be run without having intermingled output (or statistics!). 4821558Srgrimes */ 4831558Srgrimespr_pack(buf, cc, from) 4841558Srgrimes char *buf; 4851558Srgrimes int cc; 4861558Srgrimes struct sockaddr_in *from; 4871558Srgrimes{ 4881558Srgrimes register struct icmp *icp; 4891558Srgrimes register u_long l; 4901558Srgrimes register int i, j; 4911558Srgrimes register u_char *cp,*dp; 4921558Srgrimes static int old_rrlen; 4931558Srgrimes static char old_rr[MAX_IPOPTLEN]; 4941558Srgrimes struct ip *ip; 4951558Srgrimes struct timeval tv, *tp; 4961558Srgrimes double triptime; 4971558Srgrimes int hlen, dupflag; 4981558Srgrimes 4991558Srgrimes (void)gettimeofday(&tv, (struct timezone *)NULL); 5001558Srgrimes 5011558Srgrimes /* Check the IP header */ 5021558Srgrimes ip = (struct ip *)buf; 5031558Srgrimes hlen = ip->ip_hl << 2; 5041558Srgrimes if (cc < hlen + ICMP_MINLEN) { 5051558Srgrimes if (options & F_VERBOSE) 5061558Srgrimes (void)fprintf(stderr, 5071558Srgrimes "ping: packet too short (%d bytes) from %s\n", cc, 5081558Srgrimes inet_ntoa(*(struct in_addr *)&from->sin_addr.s_addr)); 5091558Srgrimes return; 5101558Srgrimes } 5111558Srgrimes 5121558Srgrimes /* Now the ICMP part */ 5131558Srgrimes cc -= hlen; 5141558Srgrimes icp = (struct icmp *)(buf + hlen); 5151558Srgrimes if (icp->icmp_type == ICMP_ECHOREPLY) { 5161558Srgrimes if (icp->icmp_id != ident) 5171558Srgrimes return; /* 'Twas not our ECHO */ 5181558Srgrimes ++nreceived; 5191558Srgrimes if (timing) { 5201558Srgrimes#ifndef icmp_data 5211558Srgrimes tp = (struct timeval *)&icp->icmp_ip; 5221558Srgrimes#else 5231558Srgrimes tp = (struct timeval *)icp->icmp_data; 5241558Srgrimes#endif 5251558Srgrimes tvsub(&tv, tp); 5261558Srgrimes triptime = ((double)tv.tv_sec) * 1000.0 + 5271558Srgrimes ((double)tv.tv_usec) / 1000.0; 5281558Srgrimes tsum += triptime; 5291558Srgrimes if (triptime < tmin) 5301558Srgrimes tmin = triptime; 5311558Srgrimes if (triptime > tmax) 5321558Srgrimes tmax = triptime; 5331558Srgrimes } 5341558Srgrimes 5351558Srgrimes if (TST(icp->icmp_seq % mx_dup_ck)) { 5361558Srgrimes ++nrepeats; 5371558Srgrimes --nreceived; 5381558Srgrimes dupflag = 1; 5391558Srgrimes } else { 5401558Srgrimes SET(icp->icmp_seq % mx_dup_ck); 5411558Srgrimes dupflag = 0; 5421558Srgrimes } 5431558Srgrimes 5441558Srgrimes if (options & F_QUIET) 5451558Srgrimes return; 5461558Srgrimes 5471558Srgrimes if (options & F_FLOOD) 5481558Srgrimes (void)write(STDOUT_FILENO, &BSPACE, 1); 5491558Srgrimes else { 5501558Srgrimes (void)printf("%d bytes from %s: icmp_seq=%u", cc, 5511558Srgrimes inet_ntoa(*(struct in_addr *)&from->sin_addr.s_addr), 5521558Srgrimes icp->icmp_seq); 5531558Srgrimes (void)printf(" ttl=%d", ip->ip_ttl); 5541558Srgrimes if (timing) 5551859Sdg (void)printf(" time=%.3f ms", triptime); 5561558Srgrimes if (dupflag) 5571558Srgrimes (void)printf(" (DUP!)"); 5581558Srgrimes /* check the data */ 5591558Srgrimes cp = (u_char*)&icp->icmp_data[8]; 5601558Srgrimes dp = &outpack[8 + sizeof(struct timeval)]; 5611558Srgrimes for (i = 8; i < datalen; ++i, ++cp, ++dp) { 5621558Srgrimes if (*cp != *dp) { 5631558Srgrimes (void)printf("\nwrong data byte #%d should be 0x%x but was 0x%x", 5641558Srgrimes i, *dp, *cp); 5651558Srgrimes cp = (u_char*)&icp->icmp_data[0]; 5661558Srgrimes for (i = 8; i < datalen; ++i, ++cp) { 5671558Srgrimes if ((i % 32) == 8) 5681558Srgrimes (void)printf("\n\t"); 5691558Srgrimes (void)printf("%x ", *cp); 5701558Srgrimes } 5711558Srgrimes break; 5721558Srgrimes } 5731558Srgrimes } 5741558Srgrimes } 5751558Srgrimes } else { 57617724Sfenner /* 57717724Sfenner * We've got something other than an ECHOREPLY. 57817724Sfenner * See if it's a reply to something that we sent. 57917724Sfenner * We can compare IP destination, protocol, 58017724Sfenner * and ICMP type and ID. 58117724Sfenner */ 58217724Sfenner#ifndef icmp_data 58317724Sfenner struct ip *oip = &icp->icmp_ip; 58417724Sfenner#else 58517724Sfenner struct ip *oip = (struct ip *)icp->icmp_data; 58617724Sfenner#endif 58717724Sfenner struct icmp *oicmp = (struct icmp *)(oip + 1); 58817724Sfenner 58917724Sfenner if ((options & F_VERBOSE) || 59017724Sfenner (!(options & F_QUIET2) && 59117724Sfenner (oip->ip_dst.s_addr == 59217724Sfenner ((struct sockaddr_in *)&whereto)->sin_addr.s_addr) && 59317724Sfenner (oip->ip_p == IPPROTO_ICMP) && 59417724Sfenner (oicmp->icmp_type == ICMP_ECHO) && 59517724Sfenner (oicmp->icmp_id == ident))) { 59617724Sfenner (void)printf("%d bytes from %s: ", cc, 59717724Sfenner pr_addr(from->sin_addr.s_addr)); 59817724Sfenner pr_icmph(icp); 59917724Sfenner } else 60017724Sfenner return; 6011558Srgrimes } 6021558Srgrimes 6031558Srgrimes /* Display any IP options */ 6041558Srgrimes cp = (u_char *)buf + sizeof(struct ip); 6051558Srgrimes 6061558Srgrimes for (; hlen > (int)sizeof(struct ip); --hlen, ++cp) 6071558Srgrimes switch (*cp) { 6081558Srgrimes case IPOPT_EOL: 6091558Srgrimes hlen = 0; 6101558Srgrimes break; 6111558Srgrimes case IPOPT_LSRR: 6121558Srgrimes (void)printf("\nLSRR: "); 6131558Srgrimes hlen -= 2; 6141558Srgrimes j = *++cp; 6151558Srgrimes ++cp; 6161558Srgrimes if (j > IPOPT_MINOFF) 6171558Srgrimes for (;;) { 6181558Srgrimes l = *++cp; 6191558Srgrimes l = (l<<8) + *++cp; 6201558Srgrimes l = (l<<8) + *++cp; 6211558Srgrimes l = (l<<8) + *++cp; 6221558Srgrimes if (l == 0) 6231558Srgrimes (void)printf("\t0.0.0.0"); 6241558Srgrimes else 6251558Srgrimes (void)printf("\t%s", pr_addr(ntohl(l))); 6261558Srgrimes hlen -= 4; 6271558Srgrimes j -= 4; 6281558Srgrimes if (j <= IPOPT_MINOFF) 6291558Srgrimes break; 6301558Srgrimes (void)putchar('\n'); 6311558Srgrimes } 6321558Srgrimes break; 6331558Srgrimes case IPOPT_RR: 6341558Srgrimes j = *++cp; /* get length */ 6351558Srgrimes i = *++cp; /* and pointer */ 6361558Srgrimes hlen -= 2; 6371558Srgrimes if (i > j) 6381558Srgrimes i = j; 6391558Srgrimes i -= IPOPT_MINOFF; 6401558Srgrimes if (i <= 0) 6411558Srgrimes continue; 6421558Srgrimes if (i == old_rrlen 6431558Srgrimes && cp == (u_char *)buf + sizeof(struct ip) + 2 6441558Srgrimes && !bcmp((char *)cp, old_rr, i) 6451558Srgrimes && !(options & F_FLOOD)) { 6461558Srgrimes (void)printf("\t(same route)"); 6471558Srgrimes i = ((i + 3) / 4) * 4; 6481558Srgrimes hlen -= i; 6491558Srgrimes cp += i; 6501558Srgrimes break; 6511558Srgrimes } 6521558Srgrimes old_rrlen = i; 6531558Srgrimes bcopy((char *)cp, old_rr, i); 6541558Srgrimes (void)printf("\nRR: "); 6551558Srgrimes for (;;) { 6561558Srgrimes l = *++cp; 6571558Srgrimes l = (l<<8) + *++cp; 6581558Srgrimes l = (l<<8) + *++cp; 6591558Srgrimes l = (l<<8) + *++cp; 6601558Srgrimes if (l == 0) 6611558Srgrimes (void)printf("\t0.0.0.0"); 6621558Srgrimes else 6631558Srgrimes (void)printf("\t%s", pr_addr(ntohl(l))); 6641558Srgrimes hlen -= 4; 6651558Srgrimes i -= 4; 6661558Srgrimes if (i <= 0) 6671558Srgrimes break; 6681558Srgrimes (void)putchar('\n'); 6691558Srgrimes } 6701558Srgrimes break; 6711558Srgrimes case IPOPT_NOP: 6721558Srgrimes (void)printf("\nNOP"); 6731558Srgrimes break; 6741558Srgrimes default: 6751558Srgrimes (void)printf("\nunknown option %x", *cp); 6761558Srgrimes break; 6771558Srgrimes } 6781558Srgrimes if (!(options & F_FLOOD)) { 6791558Srgrimes (void)putchar('\n'); 6801558Srgrimes (void)fflush(stdout); 6811558Srgrimes } 6821558Srgrimes} 6831558Srgrimes 6841558Srgrimes/* 6851558Srgrimes * in_cksum -- 6861558Srgrimes * Checksum routine for Internet Protocol family headers (C Version) 6871558Srgrimes */ 6881558Srgrimesin_cksum(addr, len) 6891558Srgrimes u_short *addr; 6901558Srgrimes int len; 6911558Srgrimes{ 6921558Srgrimes register int nleft = len; 6931558Srgrimes register u_short *w = addr; 6941558Srgrimes register int sum = 0; 6951558Srgrimes u_short answer = 0; 6961558Srgrimes 6971558Srgrimes /* 6981558Srgrimes * Our algorithm is simple, using a 32 bit accumulator (sum), we add 6991558Srgrimes * sequential 16 bit words to it, and at the end, fold back all the 7001558Srgrimes * carry bits from the top 16 bits into the lower 16 bits. 7011558Srgrimes */ 7021558Srgrimes while (nleft > 1) { 7031558Srgrimes sum += *w++; 7041558Srgrimes nleft -= 2; 7051558Srgrimes } 7061558Srgrimes 7071558Srgrimes /* mop up an odd byte, if necessary */ 7081558Srgrimes if (nleft == 1) { 7091558Srgrimes *(u_char *)(&answer) = *(u_char *)w ; 7101558Srgrimes sum += answer; 7111558Srgrimes } 7121558Srgrimes 7131558Srgrimes /* add back carry outs from top 16 bits to low 16 bits */ 7141558Srgrimes sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ 7151558Srgrimes sum += (sum >> 16); /* add carry */ 7161558Srgrimes answer = ~sum; /* truncate to 16 bits */ 7171558Srgrimes return(answer); 7181558Srgrimes} 7191558Srgrimes 7201558Srgrimes/* 7211558Srgrimes * tvsub -- 7221558Srgrimes * Subtract 2 timeval structs: out = out - in. Out is assumed to 7231558Srgrimes * be >= in. 7241558Srgrimes */ 7251558Srgrimestvsub(out, in) 7261558Srgrimes register struct timeval *out, *in; 7271558Srgrimes{ 7281558Srgrimes if ((out->tv_usec -= in->tv_usec) < 0) { 7291558Srgrimes --out->tv_sec; 7301558Srgrimes out->tv_usec += 1000000; 7311558Srgrimes } 7321558Srgrimes out->tv_sec -= in->tv_sec; 7331558Srgrimes} 7341558Srgrimes 7351558Srgrimes/* 7363792Ssef * status -- 7373792Ssef * Print out statistics when SIGINFO is received. 7383792Ssef */ 7393792Ssef 7403792Ssefvoid 7413792Ssefstatus() 7423792Ssef{ 7433792Ssef double temp_min = nreceived ? tmin : 0; 7443792Ssef (void)fprintf(stderr, "%ld/%ld packets received (%ld%%) " 7453792Ssef "%.3f min / %.3f avg / %.3f max\n", 7468871Srgrimes nreceived, ntransmitted, 7478871Srgrimes (ntransmitted ? 7483792Ssef 100 - (int) (((ntransmitted - nreceived) * 100) 7493792Ssef / ntransmitted) 7503792Ssef : 0), 7513792Ssef temp_min, 7523792Ssef ((nreceived + nrepeats) ? 7533792Ssef (tsum / (nreceived + nrepeats))/1000.0 7543792Ssef : tsum), 7553792Ssef tmax/ 1000.0); 7563792Ssef} 7573792Ssef 7583792Ssef/* 7591558Srgrimes * finish -- 7601558Srgrimes * Print out statistics, and give up. 7611558Srgrimes */ 7621558Srgrimesvoid 7631558Srgrimesfinish() 7641558Srgrimes{ 7651558Srgrimes register int i; 7663792Ssef struct termios ts; 7671558Srgrimes 7681558Srgrimes (void)signal(SIGINT, SIG_IGN); 7691558Srgrimes (void)putchar('\n'); 7701558Srgrimes (void)fflush(stdout); 7711558Srgrimes (void)printf("--- %s ping statistics ---\n", hostname); 7721558Srgrimes (void)printf("%ld packets transmitted, ", ntransmitted); 7731558Srgrimes (void)printf("%ld packets received, ", nreceived); 7741558Srgrimes if (nrepeats) 7751558Srgrimes (void)printf("+%ld duplicates, ", nrepeats); 7761558Srgrimes if (ntransmitted) 7771558Srgrimes if (nreceived > ntransmitted) 7781558Srgrimes (void)printf("-- somebody's printing up packets!"); 7791558Srgrimes else 7801558Srgrimes (void)printf("%d%% packet loss", 7811558Srgrimes (int) (((ntransmitted - nreceived) * 100) / 7821558Srgrimes ntransmitted)); 7831558Srgrimes (void)putchar('\n'); 7841558Srgrimes if (nreceived && timing) { 7851558Srgrimes /* Only display average to microseconds */ 7861558Srgrimes i = 1000.0 * tsum / (nreceived + nrepeats); 7871859Sdg (void)printf("round-trip min/avg/max = %.3f/%.3f/%.3f ms\n", 7881558Srgrimes tmin, ((double)i) / 1000.0, tmax); 7891558Srgrimes } 7903792Ssef if (reset_kerninfo && tcgetattr (0, &ts) != -1) { 7913792Ssef ts.c_lflag &= ~NOKERNINFO; 7923792Ssef tcsetattr (0, TCSANOW, &ts); 7933792Ssef } 7943792Ssef 7958871Srgrimes if (nreceived) 7964862Sdg exit(0); 7974862Sdg else 7984862Sdg exit(2); 7991558Srgrimes} 8001558Srgrimes 8011558Srgrimes#ifdef notdef 8021558Srgrimesstatic char *ttab[] = { 8031558Srgrimes "Echo Reply", /* ip + seq + udata */ 8041558Srgrimes "Dest Unreachable", /* net, host, proto, port, frag, sr + IP */ 8051558Srgrimes "Source Quench", /* IP */ 8061558Srgrimes "Redirect", /* redirect type, gateway, + IP */ 8071558Srgrimes "Echo", 8081558Srgrimes "Time Exceeded", /* transit, frag reassem + IP */ 8091558Srgrimes "Parameter Problem", /* pointer + IP */ 8101558Srgrimes "Timestamp", /* id + seq + three timestamps */ 8111558Srgrimes "Timestamp Reply", /* " */ 8121558Srgrimes "Info Request", /* id + sq */ 8131558Srgrimes "Info Reply" /* " */ 8141558Srgrimes}; 8151558Srgrimes#endif 8161558Srgrimes 8171558Srgrimes/* 8181558Srgrimes * pr_icmph -- 8191558Srgrimes * Print a descriptive string about an ICMP header. 8201558Srgrimes */ 8211558Srgrimespr_icmph(icp) 8221558Srgrimes struct icmp *icp; 8231558Srgrimes{ 8241558Srgrimes switch(icp->icmp_type) { 8251558Srgrimes case ICMP_ECHOREPLY: 8261558Srgrimes (void)printf("Echo Reply\n"); 8271558Srgrimes /* XXX ID + Seq + Data */ 8281558Srgrimes break; 8291558Srgrimes case ICMP_UNREACH: 8301558Srgrimes switch(icp->icmp_code) { 8311558Srgrimes case ICMP_UNREACH_NET: 8321558Srgrimes (void)printf("Destination Net Unreachable\n"); 8331558Srgrimes break; 8341558Srgrimes case ICMP_UNREACH_HOST: 8351558Srgrimes (void)printf("Destination Host Unreachable\n"); 8361558Srgrimes break; 8371558Srgrimes case ICMP_UNREACH_PROTOCOL: 8381558Srgrimes (void)printf("Destination Protocol Unreachable\n"); 8391558Srgrimes break; 8401558Srgrimes case ICMP_UNREACH_PORT: 8411558Srgrimes (void)printf("Destination Port Unreachable\n"); 8421558Srgrimes break; 8431558Srgrimes case ICMP_UNREACH_NEEDFRAG: 84417724Sfenner (void)printf("frag needed and DF set (MTU %d)\n", 84517724Sfenner icp->icmp_nextmtu); 8461558Srgrimes break; 8471558Srgrimes case ICMP_UNREACH_SRCFAIL: 8481558Srgrimes (void)printf("Source Route Failed\n"); 8491558Srgrimes break; 85017724Sfenner case ICMP_UNREACH_FILTER_PROHIB: 85117724Sfenner (void)printf("Communication prohibited by filter\n"); 85217724Sfenner break; 8531558Srgrimes default: 8541558Srgrimes (void)printf("Dest Unreachable, Bad Code: %d\n", 8551558Srgrimes icp->icmp_code); 8561558Srgrimes break; 8571558Srgrimes } 8581558Srgrimes /* Print returned IP header information */ 8591558Srgrimes#ifndef icmp_data 8601558Srgrimes pr_retip(&icp->icmp_ip); 8611558Srgrimes#else 8621558Srgrimes pr_retip((struct ip *)icp->icmp_data); 8631558Srgrimes#endif 8641558Srgrimes break; 8651558Srgrimes case ICMP_SOURCEQUENCH: 8661558Srgrimes (void)printf("Source Quench\n"); 8671558Srgrimes#ifndef icmp_data 8681558Srgrimes pr_retip(&icp->icmp_ip); 8691558Srgrimes#else 8701558Srgrimes pr_retip((struct ip *)icp->icmp_data); 8711558Srgrimes#endif 8721558Srgrimes break; 8731558Srgrimes case ICMP_REDIRECT: 8741558Srgrimes switch(icp->icmp_code) { 8751558Srgrimes case ICMP_REDIRECT_NET: 8761558Srgrimes (void)printf("Redirect Network"); 8771558Srgrimes break; 8781558Srgrimes case ICMP_REDIRECT_HOST: 8791558Srgrimes (void)printf("Redirect Host"); 8801558Srgrimes break; 8811558Srgrimes case ICMP_REDIRECT_TOSNET: 8821558Srgrimes (void)printf("Redirect Type of Service and Network"); 8831558Srgrimes break; 8841558Srgrimes case ICMP_REDIRECT_TOSHOST: 8851558Srgrimes (void)printf("Redirect Type of Service and Host"); 8861558Srgrimes break; 8871558Srgrimes default: 8881558Srgrimes (void)printf("Redirect, Bad Code: %d", icp->icmp_code); 8891558Srgrimes break; 8901558Srgrimes } 8911558Srgrimes (void)printf("(New addr: 0x%08lx)\n", icp->icmp_gwaddr.s_addr); 8921558Srgrimes#ifndef icmp_data 8931558Srgrimes pr_retip(&icp->icmp_ip); 8941558Srgrimes#else 8951558Srgrimes pr_retip((struct ip *)icp->icmp_data); 8961558Srgrimes#endif 8971558Srgrimes break; 8981558Srgrimes case ICMP_ECHO: 8991558Srgrimes (void)printf("Echo Request\n"); 9001558Srgrimes /* XXX ID + Seq + Data */ 9011558Srgrimes break; 9021558Srgrimes case ICMP_TIMXCEED: 9031558Srgrimes switch(icp->icmp_code) { 9041558Srgrimes case ICMP_TIMXCEED_INTRANS: 9051558Srgrimes (void)printf("Time to live exceeded\n"); 9061558Srgrimes break; 9071558Srgrimes case ICMP_TIMXCEED_REASS: 9081558Srgrimes (void)printf("Frag reassembly time exceeded\n"); 9091558Srgrimes break; 9101558Srgrimes default: 9111558Srgrimes (void)printf("Time exceeded, Bad Code: %d\n", 9121558Srgrimes icp->icmp_code); 9131558Srgrimes break; 9141558Srgrimes } 9151558Srgrimes#ifndef icmp_data 9161558Srgrimes pr_retip(&icp->icmp_ip); 9171558Srgrimes#else 9181558Srgrimes pr_retip((struct ip *)icp->icmp_data); 9191558Srgrimes#endif 9201558Srgrimes break; 9211558Srgrimes case ICMP_PARAMPROB: 9221558Srgrimes (void)printf("Parameter problem: pointer = 0x%02x\n", 9231558Srgrimes icp->icmp_hun.ih_pptr); 9241558Srgrimes#ifndef icmp_data 9251558Srgrimes pr_retip(&icp->icmp_ip); 9261558Srgrimes#else 9271558Srgrimes pr_retip((struct ip *)icp->icmp_data); 9281558Srgrimes#endif 9291558Srgrimes break; 9301558Srgrimes case ICMP_TSTAMP: 9311558Srgrimes (void)printf("Timestamp\n"); 9321558Srgrimes /* XXX ID + Seq + 3 timestamps */ 9331558Srgrimes break; 9341558Srgrimes case ICMP_TSTAMPREPLY: 9351558Srgrimes (void)printf("Timestamp Reply\n"); 9361558Srgrimes /* XXX ID + Seq + 3 timestamps */ 9371558Srgrimes break; 9381558Srgrimes case ICMP_IREQ: 9391558Srgrimes (void)printf("Information Request\n"); 9401558Srgrimes /* XXX ID + Seq */ 9411558Srgrimes break; 9421558Srgrimes case ICMP_IREQREPLY: 9431558Srgrimes (void)printf("Information Reply\n"); 9441558Srgrimes /* XXX ID + Seq */ 9451558Srgrimes break; 9461558Srgrimes case ICMP_MASKREQ: 9471558Srgrimes (void)printf("Address Mask Request\n"); 9481558Srgrimes break; 9491558Srgrimes case ICMP_MASKREPLY: 9501558Srgrimes (void)printf("Address Mask Reply\n"); 9511558Srgrimes break; 95217724Sfenner case ICMP_ROUTERADVERT: 95317724Sfenner (void)printf("Router Advertisement\n"); 95417724Sfenner break; 95517724Sfenner case ICMP_ROUTERSOLICIT: 95617724Sfenner (void)printf("Router Solicitation\n"); 95717724Sfenner break; 9581558Srgrimes default: 9591558Srgrimes (void)printf("Bad ICMP type: %d\n", icp->icmp_type); 9601558Srgrimes } 9611558Srgrimes} 9621558Srgrimes 9631558Srgrimes/* 9641558Srgrimes * pr_iph -- 9651558Srgrimes * Print an IP header with options. 9661558Srgrimes */ 9671558Srgrimespr_iph(ip) 9681558Srgrimes struct ip *ip; 9691558Srgrimes{ 9701558Srgrimes int hlen; 9711558Srgrimes u_char *cp; 9721558Srgrimes 9731558Srgrimes hlen = ip->ip_hl << 2; 9741558Srgrimes cp = (u_char *)ip + 20; /* point to options */ 9751558Srgrimes 97617724Sfenner (void)printf("Vr HL TOS Len ID Flg off TTL Pro cks Src Dst\n"); 9771558Srgrimes (void)printf(" %1x %1x %02x %04x %04x", 97817724Sfenner ip->ip_v, ip->ip_hl, ip->ip_tos, ntohs(ip->ip_len), 97917724Sfenner ntohs(ip->ip_id)); 98017724Sfenner (void)printf(" %1x %04x", (ntohl(ip->ip_off) & 0xe000) >> 13, 98117724Sfenner ntohl(ip->ip_off) & 0x1fff); 98217724Sfenner (void)printf(" %02x %02x %04x", ip->ip_ttl, ip->ip_p, 98317724Sfenner ntohs(ip->ip_sum)); 9841558Srgrimes (void)printf(" %s ", inet_ntoa(*(struct in_addr *)&ip->ip_src.s_addr)); 9851558Srgrimes (void)printf(" %s ", inet_ntoa(*(struct in_addr *)&ip->ip_dst.s_addr)); 98617724Sfenner /* dump any option bytes */ 9871558Srgrimes while (hlen-- > 20) { 9881558Srgrimes (void)printf("%02x", *cp++); 9891558Srgrimes } 9901558Srgrimes (void)putchar('\n'); 9911558Srgrimes} 9921558Srgrimes 9931558Srgrimes/* 9941558Srgrimes * pr_addr -- 9951558Srgrimes * Return an ascii host address as a dotted quad and optionally with 9961558Srgrimes * a hostname. 9971558Srgrimes */ 9981558Srgrimeschar * 9991558Srgrimespr_addr(l) 10001558Srgrimes u_long l; 10011558Srgrimes{ 10021558Srgrimes struct hostent *hp; 10031558Srgrimes static char buf[80]; 10041558Srgrimes 10051558Srgrimes if ((options & F_NUMERIC) || 10061558Srgrimes !(hp = gethostbyaddr((char *)&l, 4, AF_INET))) 100717320Speter (void)snprintf(buf, sizeof(buf), "%s", 100817320Speter inet_ntoa(*(struct in_addr *)&l)); 10091558Srgrimes else 101017320Speter (void)snprintf(buf, sizeof(buf), "%s (%s)", hp->h_name, 10111558Srgrimes inet_ntoa(*(struct in_addr *)&l)); 10121558Srgrimes return(buf); 10131558Srgrimes} 10141558Srgrimes 10151558Srgrimes/* 10161558Srgrimes * pr_retip -- 10171558Srgrimes * Dump some info on a returned (via ICMP) IP packet. 10181558Srgrimes */ 10191558Srgrimespr_retip(ip) 10201558Srgrimes struct ip *ip; 10211558Srgrimes{ 10221558Srgrimes int hlen; 10231558Srgrimes u_char *cp; 10241558Srgrimes 10251558Srgrimes pr_iph(ip); 10261558Srgrimes hlen = ip->ip_hl << 2; 10271558Srgrimes cp = (u_char *)ip + hlen; 10281558Srgrimes 10291558Srgrimes if (ip->ip_p == 6) 10301558Srgrimes (void)printf("TCP: from port %u, to port %u (decimal)\n", 10311558Srgrimes (*cp * 256 + *(cp + 1)), (*(cp + 2) * 256 + *(cp + 3))); 10321558Srgrimes else if (ip->ip_p == 17) 10331558Srgrimes (void)printf("UDP: from port %u, to port %u (decimal)\n", 10341558Srgrimes (*cp * 256 + *(cp + 1)), (*(cp + 2) * 256 + *(cp + 3))); 10351558Srgrimes} 10361558Srgrimes 10371558Srgrimesfill(bp, patp) 10381558Srgrimes char *bp, *patp; 10391558Srgrimes{ 10401558Srgrimes register int ii, jj, kk; 10411558Srgrimes int pat[16]; 10421558Srgrimes char *cp; 10431558Srgrimes 10441558Srgrimes for (cp = patp; *cp; cp++) 10451558Srgrimes if (!isxdigit(*cp)) { 10461558Srgrimes (void)fprintf(stderr, 10471558Srgrimes "ping: patterns must be specified as hex digits.\n"); 10481558Srgrimes exit(1); 10491558Srgrimes } 10501558Srgrimes ii = sscanf(patp, 10511558Srgrimes "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x", 10521558Srgrimes &pat[0], &pat[1], &pat[2], &pat[3], &pat[4], &pat[5], &pat[6], 10531558Srgrimes &pat[7], &pat[8], &pat[9], &pat[10], &pat[11], &pat[12], 10541558Srgrimes &pat[13], &pat[14], &pat[15]); 10551558Srgrimes 10561558Srgrimes if (ii > 0) 10571558Srgrimes for (kk = 0; 10581558Srgrimes kk <= MAXPACKET - (8 + sizeof(struct timeval) + ii); 10591558Srgrimes kk += ii) 10601558Srgrimes for (jj = 0; jj < ii; ++jj) 10611558Srgrimes bp[jj + kk] = pat[jj]; 10621558Srgrimes if (!(options & F_QUIET)) { 10631558Srgrimes (void)printf("PATTERN: 0x"); 10641558Srgrimes for (jj = 0; jj < ii; ++jj) 10651558Srgrimes (void)printf("%02x", bp[jj] & 0xFF); 10661558Srgrimes (void)printf("\n"); 10671558Srgrimes } 10681558Srgrimes} 10691558Srgrimes 10701558Srgrimesusage() 10711558Srgrimes{ 10721558Srgrimes (void)fprintf(stderr, 10731558Srgrimes "usage: ping [-Rdfnqrv] [-c count] [-i wait] [-l preload]\n\t[-p pattern] [-s packetsize] host\n"); 10741558Srgrimes exit(1); 10751558Srgrimes} 1076