diff options
-rw-r--r-- | utils/ping.c | 1156 |
1 files changed, 0 insertions, 1156 deletions
diff --git a/utils/ping.c b/utils/ping.c deleted file mode 100644 index 2234f44c..00000000 --- a/utils/ping.c +++ /dev/null @@ -1,1156 +0,0 @@ -/* - * Copyright (c) 1989 The Regents of the University of California. - * All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Mike Muuss. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -char copyright[] = - "@(#) Copyright (c) 1989 The Regents of the University of California.\n" - "All rights reserved.\n"; -/* - * From: @(#)ping.c 5.9 (Berkeley) 5/12/91 - */ -char rcsid[] = "$Id: ping.c,v 1.4 2002/05/28 23:56:34 roland Exp $"; -char pkg[] = "netkit-base-0.10"; - -/* - * P I N G . C - * - * Using the InterNet Control Message Protocol (ICMP) "ECHO" facility, - * measure round-trip-delays and packet loss across network paths. - * - * Author - - * Mike Muuss - * U. S. Army Ballistic Research Laboratory - * December, 1983 - * - * Status - - * Public Domain. Distribution Unlimited. - * Bugs - - * More statistics could always be gathered. - * This program has to run SUID to ROOT to access the ICMP socket. - */ - -#include <sys/param.h> -#include <sys/socket.h> -#include <sys/file.h> -#include <sys/time.h> -#include <sys/signal.h> - -#include <netinet/in.h> -#include <netinet/ip.h> -#include <netinet/ip_icmp.h> -#include <arpa/inet.h> -#include <netdb.h> -#include <unistd.h> -#include <stdlib.h> -#include <string.h> -#include <stdio.h> -#include <ctype.h> -#include <errno.h> - -#include <cthreads.h> -/* - * Note: on some systems dropping root makes the process dumpable or - * traceable. In that case if you enable dropping root and someone - * traces ping, they get control of a raw socket and can start - * spoofing whatever packets they like. SO BE CAREFUL. - */ -#ifdef __linux__ -#define SAFE_TO_DROP_ROOT -#endif - -#define DEFDATALEN (64 - 8) /* default data length */ -#define MAXIPLEN 60 -#define MAXICMPLEN 76 -#define MAXPACKET (65536 - 60 - 8)/* max packet size */ -#define MAXWAIT 10 /* max seconds to wait for response */ -#define NROUTES 9 /* number of record route slots */ - -#define A(bit) rcvd_tbl[(bit)>>3] /* identify byte in array */ -#define B(bit) (1 << ((bit) & 0x07)) /* identify bit in byte */ -#define SET(bit) (A(bit) |= B(bit)) -#define CLR(bit) (A(bit) &= (~B(bit))) -#define TST(bit) (A(bit) & B(bit)) - -/* various options */ -int options; -#define F_FLOOD 0x001 -#define F_INTERVAL 0x002 -#define F_NUMERIC 0x004 -#define F_PINGFILLED 0x008 -#define F_QUIET 0x010 -#define F_RROUTE 0x020 -#define F_SO_DEBUG 0x040 -#define F_SO_DONTROUTE 0x080 -#define F_VERBOSE 0x100 - -/* multicast options */ -int moptions; -#define MULTICAST_NOLOOP 0x001 -#define MULTICAST_TTL 0x002 -#define MULTICAST_IF 0x004 - -/* - * MAX_DUP_CHK is the number of bits in received table, i.e. the maximum - * number of received sequence numbers we can keep track of. Change 128 - * to 8192 for complete accuracy... - */ -#define MAX_DUP_CHK (8 * 128) -int mx_dup_ck = MAX_DUP_CHK; -char rcvd_tbl[MAX_DUP_CHK / 8]; - -struct sockaddr whereto; /* who to ping */ -int datalen = DEFDATALEN; -int s; /* socket file descriptor */ -u_char outpack[MAXPACKET]; -char BSPACE = '\b'; /* characters written for flood */ -char DOT = '.'; -static char *hostname; -static int ident; /* process id to identify our packets */ - -/* counters */ -static long npackets; /* max packets to transmit */ -static long nreceived; /* # of packets we got back */ -static long nrepeats; /* number of duplicates */ -static long ntransmitted; /* sequence # for outbound packets = #sent */ -static int interval = 1; /* interval between packets */ - -/* timing */ -static int timing; /* flag to do timing */ -static long tmin = LONG_MAX; /* minimum round trip time */ -static long tmax = 0; /* maximum round trip time */ -static u_long tsum; /* sum of all times, for doing average */ - -/* protos */ -static char *pr_addr(u_long); -static int in_cksum(u_short *addr, int len); -static void catcher(int); -static void finish(int ignore); -static void pinger(void); -static void fill(void *bp, char *patp); -static void usage(void); -static void pr_pack(char *buf, int cc, struct sockaddr_in *from); -static void tvsub(struct timeval *out, struct timeval *in); -static void pr_icmph(struct icmp *icp); -static void pr_retip(struct ip *ip); - -/* Only wrapper to call pinger (). */ -void * -pinger_wrapper (void *ignored) -{ - for (;;) - { - pinger (); - sleep (interval); - } - return 0; -} - -int -main(int argc, char *argv[]) -{ - struct timeval timeout; - struct hostent *hp; - struct sockaddr_in *to; - struct protoent *proto; - struct in_addr ifaddr; - int i; - int ch, fdmask, hold, packlen, preload; - u_char *datap, *packet; - char *target; - u_char ttl, loop; - int am_i_root; -#ifdef IP_OPTIONS - char rspace[3 + 4 * NROUTES + 1]; /* record route space */ -#endif - - static char *null = NULL; - __environ = &null; - am_i_root = (getuid()==0); - - cthread_init (); - - /* - * Pull this stuff up front so we can drop root if desired. - */ - if (!(proto = getprotobyname("icmp"))) { - (void)fprintf(stderr, "ping: unknown protocol icmp.\n"); - exit(2); - } - if ((s = socket(AF_INET, SOCK_RAW, proto->p_proto)) < 0) { - if (errno==EPERM) { - fprintf(stderr, "ping: ping must run as root\n"); - } - else perror("ping: socket"); - exit(2); - } - -#ifdef SAFE_TO_DROP_ROOT - setuid(getuid()); -#endif - - preload = 0; - datap = &outpack[8 + sizeof(struct timeval)]; - while ((ch = getopt(argc, argv, "I:LRc:dfh:i:l:np:qrs:t:v")) != EOF) - switch(ch) { - case 'c': - npackets = atoi(optarg); - if (npackets <= 0) { - (void)fprintf(stderr, - "ping: bad number of packets to transmit.\n"); - exit(2); - } - break; - case 'd': - options |= F_SO_DEBUG; - break; - case 'f': - if (!am_i_root) { - (void)fprintf(stderr, - "ping: %s\n", strerror(EPERM)); - exit(2); - } - options |= F_FLOOD; - setbuf(stdout, NULL); - break; - case 'i': /* wait between sending packets */ - interval = atoi(optarg); - if (interval <= 0) { - (void)fprintf(stderr, - "ping: bad timing interval.\n"); - exit(2); - } - options |= F_INTERVAL; - break; - case 'l': - if (!am_i_root) { - (void)fprintf(stderr, - "ping: %s\n", strerror(EPERM)); - exit(2); - } - preload = atoi(optarg); - if (preload < 0) { - (void)fprintf(stderr, - "ping: bad preload value.\n"); - exit(2); - } - break; - case 'n': - options |= F_NUMERIC; - break; - case 'p': /* fill buffer with user pattern */ - options |= F_PINGFILLED; - fill(datap, optarg); - break; - case 'q': - options |= F_QUIET; - break; - case 'R': - options |= F_RROUTE; - break; - case 'r': - options |= F_SO_DONTROUTE; - break; - case 's': /* size of packet to send */ - datalen = atoi(optarg); - if (datalen > MAXPACKET) { - (void)fprintf(stderr, - "ping: packet size too large.\n"); - exit(2); - } - if (datalen <= 0) { - (void)fprintf(stderr, - "ping: illegal packet size.\n"); - exit(2); - } - break; - case 'v': - options |= F_VERBOSE; - break; - case 'L': - moptions |= MULTICAST_NOLOOP; - loop = 0; - break; - case 't': - moptions |= MULTICAST_TTL; - i = atoi(optarg); - if (i < 0 || i > 255) { - printf("ttl %u out of range\n", i); - exit(2); - } - ttl = i; - break; - case 'I': - moptions |= MULTICAST_IF; - { - int i1, i2, i3, i4; - char junk; - - if (sscanf(optarg, "%u.%u.%u.%u%c", - &i1, &i2, &i3, &i4, &junk) != 4) { - printf("bad interface address '%s'\n", - optarg); - exit(2); - } - ifaddr.s_addr = (i1<<24)|(i2<<16)|(i3<<8)|i4; - ifaddr.s_addr = htonl(ifaddr.s_addr); - } - break; - default: - usage(); - } - argc -= optind; - argv += optind; - - if (argc != 1) - usage(); - target = *argv; - - memset(&whereto, 0, sizeof(struct sockaddr)); - to = (struct sockaddr_in *)&whereto; - to->sin_family = AF_INET; - if (inet_aton(target, &to->sin_addr)) { - hostname = target; - } - else { - hp = gethostbyname(target); - if (!hp) { - (void)fprintf(stderr, - "ping: unknown host %s\n", target); - exit(2); - } - to->sin_family = hp->h_addrtype; - if (hp->h_length > (int)sizeof(to->sin_addr)) { - hp->h_length = sizeof(to->sin_addr); - } - memcpy(&to->sin_addr, hp->h_addr, hp->h_length); - hostname = malloc (strlen (hp->h_name) + 1); - strcpy (hostname, hp->h_name); - } - - if (options & F_FLOOD && options & F_INTERVAL) { - (void)fprintf(stderr, - "ping: -f and -i incompatible options.\n"); - exit(2); - } - - if (datalen >= (int)sizeof(struct timeval)) /* can we time transfer */ - timing = 1; - packlen = datalen + MAXIPLEN + MAXICMPLEN; - packet = malloc((u_int)packlen); - if (!packet) { - (void)fprintf(stderr, "ping: out of memory.\n"); - exit(2); - } - if (!(options & F_PINGFILLED)) - for (i = 8; i < datalen; ++i) - *datap++ = i; - - ident = getpid() & 0xFFFF; - hold = 1; - - if (options & F_SO_DEBUG) - (void)setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&hold, - sizeof(hold)); - - if (options & F_SO_DONTROUTE) - (void)setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (char *)&hold, - sizeof(hold)); - - /* this is necessary for broadcast pings to work */ - setsockopt(s, SOL_SOCKET, SO_BROADCAST, (char *)&hold, sizeof(hold)); - - /* record route option */ - if (options & F_RROUTE) { -#ifdef IP_OPTIONS - memset(rspace, 0, sizeof(rspace)); - rspace[IPOPT_OPTVAL] = IPOPT_RR; - rspace[IPOPT_OLEN] = sizeof(rspace)-1; - rspace[IPOPT_OFFSET] = IPOPT_MINOFF; - if (setsockopt(s, IPPROTO_IP, IP_OPTIONS, rspace, - sizeof(rspace)) < 0) { - perror("ping: record route"); - exit(2); - } -#else - (void)fprintf(stderr, - "ping: record route not available in this implementation.\n"); - exit(2); -#endif /* IP_OPTIONS */ - } - - /* - * When pinging the broadcast address, you can get a lot of answers. - * Doing something so evil is useful if you are trying to stress the - * ethernet, or just want to fill the arp cache to get some stuff for - * /etc/ethers. - */ - hold = 48 * 1024; - (void)setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&hold, - sizeof(hold)); - -/*#if 0*/ - if (moptions & MULTICAST_NOLOOP) { - if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_LOOP, - &loop, 1) == -1) { - perror ("can't disable multicast loopback"); - exit(92); - } - } - if (moptions & MULTICAST_TTL) { - if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, - &ttl, 1) == -1) { - perror ("can't set multicast time-to-live"); - exit(93); - } - } - if (moptions & MULTICAST_IF) { - if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, - &ifaddr, sizeof(ifaddr)) == -1) { - perror ("can't set multicast source interface"); - exit(94); - } - } -/*#endif*/ - - if (to->sin_family == AF_INET) - (void)printf("PING %s (%s): %d data bytes\n", hostname, - inet_ntoa(*(struct in_addr *)&to->sin_addr.s_addr), - datalen); - else - (void)printf("PING %s: %d data bytes\n", hostname, datalen); - - (void)signal(SIGINT, finish); - - /* I replace this with thread -- Kunihiro - (void)signal(SIGALRM, catcher); - */ - - - while (preload--) /* fire off them quickies */ - pinger(); - - if ((options & F_FLOOD) == 0) - cthread_detach (cthread_fork (pinger_wrapper, NULL)); - - - for (;;) { - struct sockaddr_in from; - register int cc; - socklen_t fromlen; - - if (options & F_FLOOD) { - pinger(); - timeout.tv_sec = 0; - timeout.tv_usec = 10000; - fdmask = 1 << s; - if (select(s + 1, (fd_set *)&fdmask, (fd_set *)NULL, - (fd_set *)NULL, &timeout) < 1) - continue; - } - fromlen = sizeof(from); - if ((cc = recvfrom(s, (char *)packet, packlen, 0, - (struct sockaddr *)&from, &fromlen)) < 0) { - if (errno == EINTR) - continue; - perror("ping: recvfrom"); - continue; - } - pr_pack((char *)packet, cc, &from); - if (npackets && nreceived >= npackets) - break; - } - finish(0); - /* NOTREACHED */ - return 0; -} - -/* - * catcher -- - * This routine causes another PING to be transmitted, and then - * schedules another SIGALRM for 1 second from now. - * - * bug -- - * Our sense of time will slowly skew (i.e., packets will not be - * launched exactly at 1-second intervals). This does not affect the - * quality of the delay and loss statistics. - */ -static void -catcher(int ignore) -{ - int waittime; - - (void)ignore; - pinger(); - (void)signal(SIGALRM, catcher); - if (!npackets || ntransmitted < npackets) - alarm((u_int)interval); - else { - if (nreceived) { - waittime = 2 * tmax / 1000; - if (!waittime) - waittime = 1; - if (waittime > MAXWAIT) - waittime = MAXWAIT; - } else - waittime = MAXWAIT; - (void)signal(SIGALRM, finish); - (void)alarm((u_int)waittime); - } -} - -/* - * pinger -- - * Compose and transmit an ICMP ECHO REQUEST packet. The IP packet - * will be added on by the kernel. The ID field is our UNIX process ID, - * and the sequence number is an ascending integer. The first 8 bytes - * of the data portion are used to hold a UNIX "timeval" struct in VAX - * byte-order, to compute the round-trip time. - */ -static void -pinger(void) -{ - register struct icmp *icp; - register int cc; - int i; - - icp = (struct icmp *)outpack; - icp->icmp_type = ICMP_ECHO; - icp->icmp_code = 0; - icp->icmp_cksum = 0; - icp->icmp_seq = ntransmitted++; - icp->icmp_id = ident; /* ID */ - - CLR(icp->icmp_seq % mx_dup_ck); - - if (timing) - (void)gettimeofday((struct timeval *)&outpack[8], - (struct timezone *)NULL); - - cc = datalen + 8; /* skips ICMP portion */ - - /* compute ICMP checksum here */ - icp->icmp_cksum = in_cksum((u_short *)icp, cc); - - i = sendto(s, (char *)outpack, cc, 0, &whereto, - sizeof(struct sockaddr)); - - if (i < 0 || i != cc) { - if (i < 0) - perror("ping: sendto"); - (void)printf("ping: wrote %s %d chars, ret=%d\n", - hostname, cc, i); - } - if (!(options & F_QUIET) && options & F_FLOOD) - (void)write(STDOUT_FILENO, &DOT, 1); -} - -/* - * pr_pack -- - * Print out the packet, if it came from us. This logic is necessary - * because ALL readers of the ICMP socket get a copy of ALL ICMP packets - * which arrive ('tis only fair). This permits multiple copies of this - * program to be run without having intermingled output (or statistics!). - */ -void -pr_pack(char *buf, int cc, struct sockaddr_in *from) -{ - register struct icmp *icp; - register int i; - register u_char *cp,*dp; -/*#if 0*/ - register u_long l; - register int j; - static int old_rrlen; - static char old_rr[MAX_IPOPTLEN]; -/*#endif*/ - struct ip *ip; - struct timeval tv, *tp; - long triptime = 0; - int hlen, dupflag; - - (void)gettimeofday(&tv, (struct timezone *)NULL); - - /* Check the IP header */ - ip = (struct ip *)buf; - hlen = ip->ip_hl << 2; - if (cc < datalen + ICMP_MINLEN) { - if (options & F_VERBOSE) - (void)fprintf(stderr, - "ping: packet too short (%d bytes) from %s\n", cc, - inet_ntoa(*(struct in_addr *)&from->sin_addr.s_addr)); - return; - } - - /* Now the ICMP part */ - cc -= hlen; - icp = (struct icmp *)(buf + hlen); - if (icp->icmp_type == ICMP_ECHOREPLY) { - if (icp->icmp_id != ident) - return; /* 'Twas not our ECHO */ - ++nreceived; - if (timing) { -#ifndef icmp_data - tp = (struct timeval *)(icp + 1); -#else - tp = (struct timeval *)icp->icmp_data; -#endif - tvsub(&tv, tp); - triptime = tv.tv_sec * 10000 + (tv.tv_usec / 100); - tsum += triptime; - if (triptime < tmin) - tmin = triptime; - if (triptime > tmax) - tmax = triptime; - } - - if (TST(icp->icmp_seq % mx_dup_ck)) { - ++nrepeats; - --nreceived; - dupflag = 1; - } else { - SET(icp->icmp_seq % mx_dup_ck); - dupflag = 0; - } - - if (options & F_QUIET) - return; - - if (options & F_FLOOD) - (void)write(STDOUT_FILENO, &BSPACE, 1); - else { - (void)printf("%d bytes from %s: icmp_seq=%u", cc, - inet_ntoa(*(struct in_addr *)&from->sin_addr.s_addr), - icp->icmp_seq); - (void)printf(" ttl=%d", ip->ip_ttl); - if (timing) - (void)printf(" time=%ld.%ld ms", triptime/10, - triptime%10); - if (dupflag) - (void)printf(" (DUP!)"); - /* check the data */ -#ifndef icmp_data - cp = ((u_char*)(icp + 1) + 8); -#else - cp = (u_char*)icp->icmp_data + 8; -#endif - dp = &outpack[8 + sizeof(struct timeval)]; - for (i = 8; i < datalen; ++i, ++cp, ++dp) { - if (*cp != *dp) { - (void)printf("\nwrong data byte #%d should be 0x%x but was 0x%x", - i, *dp, *cp); - cp = (u_char*)(icp + 1); - for (i = 8; i < datalen; ++i, ++cp) { - if ((i % 32) == 8) - (void)printf("\n\t"); - (void)printf("%x ", *cp); - } - break; - } - } - } - } else { - /* We've got something other than an ECHOREPLY */ - if (!(options & F_VERBOSE)) - return; - (void)printf("%d bytes from %s: ", cc, - pr_addr(from->sin_addr.s_addr)); - pr_icmph(icp); - } - -/*#if 0*/ - /* Display any IP options */ - cp = (u_char *)buf + sizeof(struct ip); - - for (; hlen > (int)sizeof(struct ip); --hlen, ++cp) - switch (*cp) { - case IPOPT_EOL: - hlen = 0; - break; - case IPOPT_LSRR: - (void)printf("\nLSRR: "); - hlen -= 2; - j = *++cp; - ++cp; - if (j > IPOPT_MINOFF) - for (;;) { - l = *++cp; - l = (l<<8) + *++cp; - l = (l<<8) + *++cp; - l = (l<<8) + *++cp; - if (l == 0) - (void)printf("\t0.0.0.0"); - else - (void)printf("\t%s", pr_addr(ntohl(l))); - hlen -= 4; - j -= 4; - if (j <= IPOPT_MINOFF) - break; - (void)putchar('\n'); - } - break; - case IPOPT_RR: - j = *++cp; /* get length */ - i = *++cp; /* and pointer */ - hlen -= 2; - if (i > j) - i = j; - i -= IPOPT_MINOFF; - if (i <= 0) - continue; - if (i == old_rrlen - && cp == (u_char *)buf + sizeof(struct ip) + 2 - && !memcmp((char *)cp, old_rr, i) - && !(options & F_FLOOD)) { - (void)printf("\t(same route)"); - i = ((i + 3) / 4) * 4; - hlen -= i; - cp += i; - break; - } - old_rrlen = i; - memcpy(old_rr, cp, i); - (void)printf("\nRR: "); - for (;;) { - l = *++cp; - l = (l<<8) + *++cp; - l = (l<<8) + *++cp; - l = (l<<8) + *++cp; - if (l == 0) - (void)printf("\t0.0.0.0"); - else - (void)printf("\t%s", pr_addr(ntohl(l))); - hlen -= 4; - i -= 4; - if (i <= 0) - break; - (void)putchar('\n'); - } - break; - case IPOPT_NOP: - (void)printf("\nNOP"); - break; - default: - (void)printf("\nunknown option %x", *cp); - break; - } -/*#endif*/ - if (!(options & F_FLOOD)) { - (void)putchar('\n'); - (void)fflush(stdout); - } -} - -/* - * in_cksum -- - * Checksum routine for Internet Protocol family headers (C Version) - */ -static int -in_cksum(u_short *addr, int len) -{ - register int nleft = len; - register u_short *w = addr; - register int sum = 0; - u_short answer = 0; - - /* - * Our algorithm is simple, using a 32 bit accumulator (sum), we add - * sequential 16 bit words to it, and at the end, fold back all the - * carry bits from the top 16 bits into the lower 16 bits. - */ - while (nleft > 1) { - sum += *w++; - nleft -= 2; - } - - /* mop up an odd byte, if necessary */ - if (nleft == 1) { - *(u_char *)(&answer) = *(u_char *)w ; - sum += answer; - } - - /* add back carry outs from top 16 bits to low 16 bits */ - sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ - sum += (sum >> 16); /* add carry */ - answer = ~sum; /* truncate to 16 bits */ - return(answer); -} - -/* - * tvsub -- - * Subtract 2 timeval structs: out = out - in. Out is assumed to - * be >= in. - */ -static void -tvsub(register struct timeval *out, register struct timeval *in) -{ - if ((out->tv_usec -= in->tv_usec) < 0) { - --out->tv_sec; - out->tv_usec += 1000000; - } - out->tv_sec -= in->tv_sec; -} - -/* - * finish -- - * Print out statistics, and give up. - */ -static void -finish(int ignore) -{ - (void)ignore; - - (void)signal(SIGINT, SIG_IGN); - (void)putchar('\n'); - (void)fflush(stdout); - (void)printf("--- %s ping statistics ---\n", hostname); - (void)printf("%ld packets transmitted, ", ntransmitted); - (void)printf("%ld packets received, ", nreceived); - if (nrepeats) - (void)printf("+%ld duplicates, ", nrepeats); - if (ntransmitted) - if (nreceived > ntransmitted) - (void)printf("-- somebody's printing up packets!"); - else - (void)printf("%d%% packet loss", - (int) (((ntransmitted - nreceived) * 100) / - ntransmitted)); - (void)putchar('\n'); - if (nreceived && timing) - (void)printf("round-trip min/avg/max = %ld.%ld/%lu.%ld/%ld.%ld ms\n", - tmin/10, tmin%10, - (tsum / (nreceived + nrepeats))/10, - (tsum / (nreceived + nrepeats))%10, - tmax/10, tmax%10); - - if (nreceived==0) exit(1); - exit(0); -} - -#ifdef notdef -static char *ttab[] = { - "Echo Reply", /* ip + seq + udata */ - "Dest Unreachable", /* net, host, proto, port, frag, sr + IP */ - "Source Quench", /* IP */ - "Redirect", /* redirect type, gateway, + IP */ - "Echo", - "Time Exceeded", /* transit, frag reassem + IP */ - "Parameter Problem", /* pointer + IP */ - "Timestamp", /* id + seq + three timestamps */ - "Timestamp Reply", /* " */ - "Info Request", /* id + sq */ - "Info Reply" /* " */ -}; -#endif - -/* - * pr_icmph -- - * Print a descriptive string about an ICMP header. - */ -static void -pr_icmph(struct icmp *icp) -{ - switch(icp->icmp_type) { - case ICMP_ECHOREPLY: - (void)printf("Echo Reply\n"); - /* XXX ID + Seq + Data */ - break; - case ICMP_DEST_UNREACH: - switch(icp->icmp_code) { - case ICMP_NET_UNREACH: - (void)printf("Destination Net Unreachable\n"); - break; - case ICMP_HOST_UNREACH: - (void)printf("Destination Host Unreachable\n"); - break; - case ICMP_PROT_UNREACH: - (void)printf("Destination Protocol Unreachable\n"); - break; - case ICMP_PORT_UNREACH: - (void)printf("Destination Port Unreachable\n"); - break; - case ICMP_FRAG_NEEDED: - (void)printf("frag needed and DF set\n"); - break; - case ICMP_SR_FAILED: - (void)printf("Source Route Failed\n"); - break; - case ICMP_NET_UNKNOWN: - (void)printf("Network Unknown\n"); - break; - case ICMP_HOST_UNKNOWN: - (void)printf("Host Unknown\n"); - break; - case ICMP_HOST_ISOLATED: - (void)printf("Host Isolated\n"); - break; - case ICMP_NET_UNR_TOS: - printf("Destination Network Unreachable At This TOS\n"); - break; - case ICMP_HOST_UNR_TOS: - printf("Destination Host Unreachable At This TOS\n"); - break; -#ifdef ICMP_PKT_FILTERED - case ICMP_PKT_FILTERED: - (void)printf("Packet Filtered\n"); - break; -#endif -#ifdef ICMP_PREC_VIOLATION - case ICMP_PREC_VIOLATION: - (void)printf("Precedence Violation\n"); - break; -#endif -#ifdef ICMP_PREC_CUTOFF - case ICMP_PREC_CUTOFF: - (void)printf("Precedence Cutoff\n"); - break; -#endif - default: - (void)printf("Dest Unreachable, Unknown Code: %d\n", - icp->icmp_code); - break; - } - /* Print returned IP header information */ -#ifndef icmp_data - pr_retip((struct ip *)(icp + 1)); -#else - pr_retip((struct ip *)icp->icmp_data); -#endif - break; - case ICMP_SOURCE_QUENCH: - (void)printf("Source Quench\n"); -#ifndef icmp_data - pr_retip((struct ip *)(icp + 1)); -#else - pr_retip((struct ip *)icp->icmp_data); -#endif - break; - case ICMP_REDIRECT: - switch(icp->icmp_code) { - case ICMP_REDIR_NET: - (void)printf("Redirect Network"); - break; - case ICMP_REDIR_HOST: - (void)printf("Redirect Host"); - break; - case ICMP_REDIR_NETTOS: - (void)printf("Redirect Type of Service and Network"); - break; - case ICMP_REDIR_HOSTTOS: - (void)printf("Redirect Type of Service and Host"); - break; - default: - (void)printf("Redirect, Bad Code: %d", icp->icmp_code); - break; - } - (void)printf("(New addr: %s)\n", - inet_ntoa(icp->icmp_gwaddr)); -#ifndef icmp_data - pr_retip((struct ip *)(icp + 1)); -#else - pr_retip((struct ip *)icp->icmp_data); -#endif - break; - case ICMP_ECHO: - (void)printf("Echo Request\n"); - /* XXX ID + Seq + Data */ - break; - case ICMP_TIME_EXCEEDED: - switch(icp->icmp_code) { - case ICMP_EXC_TTL: - (void)printf("Time to live exceeded\n"); - break; - case ICMP_EXC_FRAGTIME: - (void)printf("Frag reassembly time exceeded\n"); - break; - default: - (void)printf("Time exceeded, Bad Code: %d\n", - icp->icmp_code); - break; - } -#ifndef icmp_data - pr_retip((struct ip *)(icp + 1)); -#else - pr_retip((struct ip *)icp->icmp_data); -#endif - break; - case ICMP_PARAMETERPROB: - (void)printf("Parameter problem: IP address = %s\n", - inet_ntoa (icp->icmp_gwaddr)); -#ifndef icmp_data - pr_retip((struct ip *)(icp + 1)); -#else - pr_retip((struct ip *)icp->icmp_data); -#endif - break; - case ICMP_TIMESTAMP: - (void)printf("Timestamp\n"); - /* XXX ID + Seq + 3 timestamps */ - break; - case ICMP_TIMESTAMPREPLY: - (void)printf("Timestamp Reply\n"); - /* XXX ID + Seq + 3 timestamps */ - break; - case ICMP_INFO_REQUEST: - (void)printf("Information Request\n"); - /* XXX ID + Seq */ - break; - case ICMP_INFO_REPLY: - (void)printf("Information Reply\n"); - /* XXX ID + Seq */ - break; -#ifdef ICMP_MASKREQ - case ICMP_MASKREQ: - (void)printf("Address Mask Request\n"); - break; -#endif -#ifdef ICMP_MASKREPLY - case ICMP_MASKREPLY: - (void)printf("Address Mask Reply\n"); - break; -#endif - default: - (void)printf("Bad ICMP type: %d\n", icp->icmp_type); - } -} - -/* - * pr_iph -- - * Print an IP header with options. - */ -static void -pr_iph(struct ip *ip) -{ - int hlen; - u_char *cp; - - hlen = ip->ip_hl << 2; - cp = (u_char *)ip + 20; /* point to options */ - - (void)printf("Vr HL TOS Len ID Flg off TTL Pro cks Src Dst Data\n"); - (void)printf(" %1x %1x %02x %04x %04x", - ip->ip_v, ip->ip_hl, ip->ip_tos, ip->ip_len, ip->ip_id); - (void)printf(" %1x %04x", ((ip->ip_off) & 0xe000) >> 13, - (ip->ip_off) & 0x1fff); - (void)printf(" %02x %02x %04x", ip->ip_ttl, ip->ip_p, ip->ip_sum); - (void)printf(" %s ", inet_ntoa(*((struct in_addr *) &ip->ip_src))); - (void)printf(" %s ", inet_ntoa(*((struct in_addr *) &ip->ip_dst))); - /* dump and option bytes */ - while (hlen-- > 20) { - (void)printf("%02x", *cp++); - } - (void)putchar('\n'); -} - -/* - * pr_addr -- - * Return an ascii host address as a dotted quad and optionally with - * a hostname. - */ -static char * -pr_addr(u_long l) -{ - struct hostent *hp; - static char buf[256]; - - if ((options & F_NUMERIC) || - !(hp = gethostbyaddr((char *)&l, 4, AF_INET))) - (void)snprintf(buf, sizeof(buf), "%s", - inet_ntoa(*(struct in_addr *)&l)); - else - (void)snprintf(buf, sizeof(buf), "%s (%s)", hp->h_name, - inet_ntoa(*(struct in_addr *)&l)); - return(buf); -} - -/* - * pr_retip -- - * Dump some info on a returned (via ICMP) IP packet. - */ -static void -pr_retip(struct ip *ip) -{ - int hlen; - u_char *cp; - - pr_iph(ip); - hlen = ip->ip_hl << 2; - cp = (u_char *)ip + hlen; - - if (ip->ip_p == 6) - (void)printf("TCP: from port %u, to port %u (decimal)\n", - (*cp * 256 + *(cp + 1)), (*(cp + 2) * 256 + *(cp + 3))); - else if (ip->ip_p == 17) - (void)printf("UDP: from port %u, to port %u (decimal)\n", - (*cp * 256 + *(cp + 1)), (*(cp + 2) * 256 + *(cp + 3))); -} - -static void -fill(void *bp1, char *patp) -{ - register int ii, jj, kk; - int pat[16]; - char *cp, *bp = (char *)bp1; - - for (cp = patp; *cp; cp++) - if (!isxdigit(*cp)) { - (void)fprintf(stderr, - "ping: patterns must be specified as hex digits.\n"); - exit(2); - } - ii = sscanf(patp, - "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x", - &pat[0], &pat[1], &pat[2], &pat[3], &pat[4], &pat[5], &pat[6], - &pat[7], &pat[8], &pat[9], &pat[10], &pat[11], &pat[12], - &pat[13], &pat[14], &pat[15]); - - if (ii > 0) - for (kk = 0; kk <= MAXPACKET - (8 + ii); kk += ii) - for (jj = 0; jj < ii; ++jj) - bp[jj + kk] = pat[jj]; - if (!(options & F_QUIET)) { - (void)printf("PATTERN: 0x"); - for (jj = 0; jj < ii; ++jj) - (void)printf("%02x", bp[jj] & 0xFF); - (void)printf("\n"); - } -} - -static void -usage(void) -{ - (void)fprintf(stderr, - "usage: ping [-LRdfnqrv] [-c count] [-i wait] [-l preload]\n\t[-p pattern] [-s packetsize] [-t ttl] [-I interface address] host\n"); - exit(2); -} |