diff options
Diffstat (limited to 'ping.c')
-rw-r--r-- | ping.c | 618 |
1 files changed, 324 insertions, 294 deletions
@@ -1,5 +1,6 @@ +/* vi: set sw=4 ts=4: */ /* - * $Id: ping.c,v 1.10 2000/02/07 05:29:42 erik Exp $ + * $Id: ping.c,v 1.11 2000/02/08 19:58:47 erik Exp $ * Mini ping implementation for busybox * * Copyright (C) 1999 by Randolph Chung <tausq@debian.org> @@ -53,7 +54,7 @@ #define MAXPACKET 65468 #define MAX_DUP_CHK (8 * 128) #define MAXWAIT 10 -#define PINGINTERVAL 1 /* second */ +#define PINGINTERVAL 1 /* second */ #define O_QUIET (1 << 0) @@ -66,118 +67,124 @@ /* common routines */ static int in_cksum(unsigned short *buf, int sz) { - int nleft = sz; - int sum = 0; - unsigned short *w = buf; - unsigned short ans = 0; - - while (nleft > 1) { - sum += *w++; - nleft -= 2; - } - - if (nleft == 1) { - *(unsigned char *)(&ans) = *(unsigned char *)w; - sum += ans; - } - - sum = (sum >> 16) + (sum & 0xFFFF); - sum += (sum >> 16); - ans = ~sum; - return(ans); -} + int nleft = sz; + int sum = 0; + unsigned short *w = buf; + unsigned short ans = 0; + + while (nleft > 1) { + sum += *w++; + nleft -= 2; + } + + if (nleft == 1) { + *(unsigned char *) (&ans) = *(unsigned char *) w; + sum += ans; + } + + sum = (sum >> 16) + (sum & 0xFFFF); + sum += (sum >> 16); + ans = ~sum; + return (ans); +} /* simple version */ #ifdef BB_SIMPLE_PING -static const char* ping_usage = "ping host\n\n"; +static const char *ping_usage = "ping host\n\n"; -static char* hostname = NULL; +static char *hostname = NULL; static void noresp(int ign) { - printf("No response from %s\n", hostname); - exit(0); + printf("No response from %s\n", hostname); + exit(0); } static int ping(const char *host) { - struct hostent *h; - struct sockaddr_in pingaddr; - struct icmp *pkt; - int pingsock, c; - char packet[DEFDATALEN + MAXIPLEN + MAXICMPLEN]; - - if ((pingsock = socket(AF_INET, SOCK_RAW, 1)) < 0) { /* 1 == ICMP */ - perror("ping"); - exit(1); - } - - /* drop root privs if running setuid */ - setuid(getuid()); - - memset(&pingaddr, 0, sizeof(struct sockaddr_in)); - pingaddr.sin_family = AF_INET; - if (!(h = gethostbyname(host))) { - fprintf(stderr, "ping: unknown host %s\n", host); - exit(1); - } - memcpy(&pingaddr.sin_addr, h->h_addr, sizeof(pingaddr.sin_addr)); - hostname = h->h_name; - - pkt = (struct icmp *)packet; - memset(pkt, 0, sizeof(packet)); - pkt->icmp_type = ICMP_ECHO; - pkt->icmp_cksum = in_cksum((unsigned short *)pkt, sizeof(packet)); - - c = sendto(pingsock, packet, sizeof(packet), 0, - (struct sockaddr *)&pingaddr, sizeof(struct sockaddr_in)); - - if (c < 0 || c != sizeof(packet)) { - if (c < 0) perror("ping"); - fprintf(stderr, "ping: write incomplete\n"); - exit(1); - } - - signal(SIGALRM, noresp); - alarm(5); /* give the host 5000ms to respond */ - /* listen for replies */ - while (1) { - struct sockaddr_in from; - size_t fromlen = sizeof(from); - - if ((c = recvfrom(pingsock, packet, sizeof(packet), 0, - (struct sockaddr *)&from, &fromlen)) < 0) { - if (errno == EINTR) continue; - perror("ping"); - continue; + struct hostent *h; + struct sockaddr_in pingaddr; + struct icmp *pkt; + int pingsock, c; + char packet[DEFDATALEN + MAXIPLEN + MAXICMPLEN]; + + if ((pingsock = socket(AF_INET, SOCK_RAW, 1)) < 0) { /* 1 == ICMP */ + perror("ping"); + exit(1); + } + + /* drop root privs if running setuid */ + setuid(getuid()); + + memset(&pingaddr, 0, sizeof(struct sockaddr_in)); + + pingaddr.sin_family = AF_INET; + if (!(h = gethostbyname(host))) { + fprintf(stderr, "ping: unknown host %s\n", host); + exit(1); + } + memcpy(&pingaddr.sin_addr, h->h_addr, sizeof(pingaddr.sin_addr)); + hostname = h->h_name; + + pkt = (struct icmp *) packet; + memset(pkt, 0, sizeof(packet)); + pkt->icmp_type = ICMP_ECHO; + pkt->icmp_cksum = in_cksum((unsigned short *) pkt, sizeof(packet)); + + c = sendto(pingsock, packet, sizeof(packet), 0, + (struct sockaddr *) &pingaddr, sizeof(struct sockaddr_in)); + + if (c < 0 || c != sizeof(packet)) { + if (c < 0) + perror("ping"); + fprintf(stderr, "ping: write incomplete\n"); + exit(1); + } + + signal(SIGALRM, noresp); + alarm(5); /* give the host 5000ms to respond */ + /* listen for replies */ + while (1) { + struct sockaddr_in from; + size_t fromlen = sizeof(from); + + if ((c = recvfrom(pingsock, packet, sizeof(packet), 0, + (struct sockaddr *) &from, &fromlen)) < 0) { + if (errno == EINTR) + continue; + perror("ping"); + continue; + } + if (c >= 76) { /* ip + icmp */ + struct iphdr *iphdr = (struct iphdr *) packet; + + pkt = (struct icmp *) (packet + (iphdr->ihl << 2)); /* skip ip hdr */ + if (pkt->icmp_type == ICMP_ECHOREPLY) + break; + } } - if (c >= 76) { /* ip + icmp */ - struct iphdr *iphdr = (struct iphdr *)packet; - pkt = (struct icmp *)(packet + (iphdr->ihl << 2)); /* skip ip hdr */ - if (pkt->icmp_type == ICMP_ECHOREPLY) break; - } - } - printf("%s is alive!\n", hostname); - return(TRUE); + printf("%s is alive!\n", hostname); + return (TRUE); } extern int ping_main(int argc, char **argv) { - argc--; - argv++; - if (argc < 1) usage(ping_usage); - ping(*argv); - exit(TRUE); + argc--; + argv++; + if (argc < 1) + usage(ping_usage); + ping(*argv); + exit(TRUE); } -#else +#else /* full(er) version */ -static const char* ping_usage = "ping [OPTION]... host\n\n" -"Send ICMP ECHO_REQUEST packets to network hosts.\n\n" -"Options:\n" -"\t-q\t\tQuiet mode, only displays output at start" -"\t\t\tand when finished.\n" -"\t-c COUNT\tSend only COUNT pings.\n"; +static const char *ping_usage = "ping [OPTION]... host\n\n" + "Send ICMP ECHO_REQUEST packets to network hosts.\n\n" + "Options:\n" + "\t-q\t\tQuiet mode, only displays output at start" + + "\t\t\tand when finished.\n" "\t-c COUNT\tSend only COUNT pings.\n"; static char *hostname = NULL; static struct sockaddr_in pingaddr; @@ -196,224 +203,247 @@ static void ping(char *); /**************************************************************************/ -static void pingstats(int ign) { - signal(SIGINT, SIG_IGN); - - printf("\n--- %s ping statistics ---\n", hostname); - printf("%ld packets transmitted, ", ntransmitted); - printf("%ld packets received, ", nreceived); - if (nrepeats) - printf("%ld duplicates, ", nrepeats); - if (ntransmitted) - printf("%ld%% packet loss\n", - (ntransmitted - nreceived)*100/ntransmitted); - if (nreceived) - printf("round-trip min/avg/max = %lu.%lu/%lu.%lu/%lu.%lu ms\n", - tmin/10, tmin%10, - (tsum/(nreceived+nrepeats))/10, - (tsum/(nreceived+nrepeats))%10, - tmax/10, tmax%10); - exit(0); +static void pingstats(int ign) +{ + signal(SIGINT, SIG_IGN); + + printf("\n--- %s ping statistics ---\n", hostname); + printf("%ld packets transmitted, ", ntransmitted); + printf("%ld packets received, ", nreceived); + if (nrepeats) + printf("%ld duplicates, ", nrepeats); + if (ntransmitted) + printf("%ld%% packet loss\n", + (ntransmitted - nreceived) * 100 / ntransmitted); + if (nreceived) + printf("round-trip min/avg/max = %lu.%lu/%lu.%lu/%lu.%lu ms\n", + tmin / 10, tmin % 10, + (tsum / (nreceived + nrepeats)) / 10, + (tsum / (nreceived + nrepeats)) % 10, tmax / 10, tmax % 10); + exit(0); } static void sendping(int ign) { - struct icmp *pkt; - int i; - char packet[DEFDATALEN + 8]; - - pkt = (struct icmp *)packet; - - pkt->icmp_type = ICMP_ECHO; - pkt->icmp_code = 0; - pkt->icmp_cksum = 0; - pkt->icmp_seq = ntransmitted++; - pkt->icmp_id = myid; - CLR(pkt->icmp_seq % MAX_DUP_CHK); - - gettimeofday((struct timeval *)&packet[8], NULL); - pkt->icmp_cksum = in_cksum((unsigned short *)pkt, sizeof(packet)); - - i = sendto(pingsock, packet, sizeof(packet), 0, - (struct sockaddr *)&pingaddr, sizeof(struct sockaddr_in)); - - if (i < 0 || i != sizeof(packet)) { - if (i < 0) perror("ping"); - fprintf(stderr, "ping wrote %d chars; %d expected\n", i, sizeof(packet)); - exit(1); - } - - signal(SIGALRM, sendping); - if (pingcount == 0 || ntransmitted < pingcount) { /* schedule next in 1s */ - alarm(PINGINTERVAL); - } else { /* done, wait for the last ping to come back */ - /* todo, don't necessarily need to wait so long... */ - signal(SIGALRM, pingstats); - alarm(MAXWAIT); - } + struct icmp *pkt; + int i; + char packet[DEFDATALEN + 8]; + + pkt = (struct icmp *) packet; + + pkt->icmp_type = ICMP_ECHO; + pkt->icmp_code = 0; + pkt->icmp_cksum = 0; + pkt->icmp_seq = ntransmitted++; + pkt->icmp_id = myid; + CLR(pkt->icmp_seq % MAX_DUP_CHK); + + gettimeofday((struct timeval *) &packet[8], NULL); + pkt->icmp_cksum = in_cksum((unsigned short *) pkt, sizeof(packet)); + + i = sendto(pingsock, packet, sizeof(packet), 0, + (struct sockaddr *) &pingaddr, sizeof(struct sockaddr_in)); + + if (i < 0 || i != sizeof(packet)) { + if (i < 0) + perror("ping"); + fprintf(stderr, "ping wrote %d chars; %d expected\n", i, + sizeof(packet)); + exit(1); + } + + signal(SIGALRM, sendping); + if (pingcount == 0 || ntransmitted < pingcount) { /* schedule next in 1s */ + alarm(PINGINTERVAL); + } else { /* done, wait for the last ping to come back */ + /* todo, don't necessarily need to wait so long... */ + signal(SIGALRM, pingstats); + alarm(MAXWAIT); + } } - + static void unpack(char *buf, int sz, struct sockaddr_in *from) { - struct icmp *icmppkt; - struct iphdr *iphdr; - struct timeval tv, *tp; - int hlen, dupflag; - unsigned long triptime; - - gettimeofday(&tv, NULL); - - /* check IP header */ - iphdr = (struct iphdr *)buf; - hlen = iphdr->ihl << 2; - /* discard if too short */ - if (sz < (DEFDATALEN + ICMP_MINLEN)) return; - - sz -= hlen; - icmppkt = (struct icmp *)(buf + hlen); - - if (icmppkt->icmp_type == ICMP_ECHOREPLY) { - if (icmppkt->icmp_id != myid) return; /* not our ping */ - ++nreceived; - tp = (struct timeval *)icmppkt->icmp_data; - - if ((tv.tv_usec -= tp->tv_usec) < 0) { - --tv.tv_sec; - tv.tv_usec += 1000000; - } - tv.tv_sec -= tp->tv_sec; - - triptime = tv.tv_sec * 10000 + (tv.tv_usec / 100); - tsum += triptime; - if (triptime < tmin) tmin = triptime; - if (triptime > tmax) tmax = triptime; - - if (TST(icmppkt->icmp_seq % MAX_DUP_CHK)) { - ++nrepeats; - --nreceived; - dupflag = 1; + struct icmp *icmppkt; + struct iphdr *iphdr; + struct timeval tv, *tp; + int hlen, dupflag; + unsigned long triptime; + + gettimeofday(&tv, NULL); + + /* check IP header */ + iphdr = (struct iphdr *) buf; + hlen = iphdr->ihl << 2; + /* discard if too short */ + if (sz < (DEFDATALEN + ICMP_MINLEN)) + return; + + sz -= hlen; + icmppkt = (struct icmp *) (buf + hlen); + + if (icmppkt->icmp_type == ICMP_ECHOREPLY) { + if (icmppkt->icmp_id != myid) + return; /* not our ping */ + ++nreceived; + tp = (struct timeval *) icmppkt->icmp_data; + + if ((tv.tv_usec -= tp->tv_usec) < 0) { + --tv.tv_sec; + tv.tv_usec += 1000000; + } + tv.tv_sec -= tp->tv_sec; + + triptime = tv.tv_sec * 10000 + (tv.tv_usec / 100); + tsum += triptime; + if (triptime < tmin) + tmin = triptime; + if (triptime > tmax) + tmax = triptime; + + if (TST(icmppkt->icmp_seq % MAX_DUP_CHK)) { + ++nrepeats; + --nreceived; + dupflag = 1; + } else { + SET(icmppkt->icmp_seq % MAX_DUP_CHK); + dupflag = 0; + } + + if (options & O_QUIET) + return; + + printf("%d bytes from %s: icmp_seq=%u", sz, + inet_ntoa(*(struct in_addr *) &from->sin_addr.s_addr), + icmppkt->icmp_seq); + printf(" ttl=%d", iphdr->ttl); + printf(" time=%lu.%lu ms", triptime / 10, triptime % 10); + if (dupflag) + printf(" (DUP!)"); + printf("\n"); } else { - SET(icmppkt->icmp_seq % MAX_DUP_CHK); - dupflag = 0; + fprintf(stderr, + "Warning: unknown ICMP packet received (not echo-reply)\n"); } - - if (options & O_QUIET) return; - - printf("%d bytes from %s: icmp_seq=%u", sz, - inet_ntoa(*(struct in_addr *)&from->sin_addr.s_addr), - icmppkt->icmp_seq); - printf(" ttl=%d", iphdr->ttl); - printf(" time=%lu.%lu ms", triptime/10, triptime%10); - if (dupflag) printf(" (DUP!)"); - printf("\n"); - } else { - fprintf(stderr, "Warning: unknown ICMP packet received (not echo-reply)\n"); - } } static void ping(char *host) { - struct protoent *proto; - struct hostent *h; - char buf[MAXHOSTNAMELEN]; - char packet[DEFDATALEN + MAXIPLEN + MAXICMPLEN]; - int sockopt; - - proto = getprotobyname("icmp"); - /* if getprotobyname failed, just silently force - * proto->p_proto to have the correct value for "icmp" */ - if ((pingsock = socket(AF_INET, SOCK_RAW, - (proto ? proto->p_proto : 1))) < 0) { /* 1 == ICMP */ - if (errno == EPERM) { - fprintf(stderr, "ping: permission denied. (are you root?)\n"); - } else { - perror("ping"); + struct protoent *proto; + struct hostent *h; + char buf[MAXHOSTNAMELEN]; + char packet[DEFDATALEN + MAXIPLEN + MAXICMPLEN]; + int sockopt; + + proto = getprotobyname("icmp"); + /* if getprotobyname failed, just silently force + * proto->p_proto to have the correct value for "icmp" */ + if ((pingsock = socket(AF_INET, SOCK_RAW, + (proto ? proto->p_proto : 1))) < 0) { /* 1 == ICMP */ + if (errno == EPERM) { + fprintf(stderr, "ping: permission denied. (are you root?)\n"); + } else { + perror("ping"); + } + exit(1); } - exit(1); - } - - /* drop root privs if running setuid */ - setuid(getuid()); - - memset(&pingaddr, 0, sizeof(struct sockaddr_in)); - pingaddr.sin_family = AF_INET; - if (!(h = gethostbyname(host))) { - fprintf(stderr, "ping: unknown host %s\n", host); - exit(1); - } - - if (h->h_addrtype != AF_INET) { - fprintf(stderr, "ping: unknown address type; only AF_INET is currently supported.\n"); - exit(1); - } - - pingaddr.sin_family = AF_INET; /* h->h_addrtype */ - memcpy(&pingaddr.sin_addr, h->h_addr, sizeof(pingaddr.sin_addr)); - strncpy(buf, h->h_name, sizeof(buf)-1); - hostname = buf; - - /* enable broadcast pings */ - sockopt = 1; - setsockopt(pingsock, SOL_SOCKET, SO_BROADCAST, (char *)&sockopt, sizeof(sockopt)); - - /* set recv buf for broadcast pings */ - sockopt = 48 * 1024; - setsockopt(pingsock, SOL_SOCKET, SO_RCVBUF, (char *)&sockopt, sizeof(sockopt)); - - printf("PING %s (%s): %d data bytes\n", - hostname, inet_ntoa(*(struct in_addr *)&pingaddr.sin_addr.s_addr), - DEFDATALEN); - - signal(SIGINT, pingstats); - - /* start the ping's going ... */ - sendping(0); - - /* listen for replies */ - while (1) { - struct sockaddr_in from; - size_t fromlen = sizeof(from); - int c; - - if ((c = recvfrom(pingsock, packet, sizeof(packet), 0, - (struct sockaddr *)&from, &fromlen)) < 0) { - if (errno == EINTR) continue; - perror("ping"); - continue; + + /* drop root privs if running setuid */ + setuid(getuid()); + + memset(&pingaddr, 0, sizeof(struct sockaddr_in)); + + pingaddr.sin_family = AF_INET; + if (!(h = gethostbyname(host))) { + fprintf(stderr, "ping: unknown host %s\n", host); + exit(1); + } + + if (h->h_addrtype != AF_INET) { + fprintf(stderr, + "ping: unknown address type; only AF_INET is currently supported.\n"); + exit(1); } - unpack(packet, c, &from); - if (pingcount > 0 && nreceived >= pingcount) break; - } - pingstats(0); + + pingaddr.sin_family = AF_INET; /* h->h_addrtype */ + memcpy(&pingaddr.sin_addr, h->h_addr, sizeof(pingaddr.sin_addr)); + strncpy(buf, h->h_name, sizeof(buf) - 1); + hostname = buf; + + /* enable broadcast pings */ + sockopt = 1; + setsockopt(pingsock, SOL_SOCKET, SO_BROADCAST, (char *) &sockopt, + sizeof(sockopt)); + + /* set recv buf for broadcast pings */ + sockopt = 48 * 1024; + setsockopt(pingsock, SOL_SOCKET, SO_RCVBUF, (char *) &sockopt, + sizeof(sockopt)); + + printf("PING %s (%s): %d data bytes\n", + hostname, + inet_ntoa(*(struct in_addr *) &pingaddr.sin_addr.s_addr), + DEFDATALEN); + + signal(SIGINT, pingstats); + + /* start the ping's going ... */ + sendping(0); + + /* listen for replies */ + while (1) { + struct sockaddr_in from; + size_t fromlen = sizeof(from); + int c; + + if ((c = recvfrom(pingsock, packet, sizeof(packet), 0, + (struct sockaddr *) &from, &fromlen)) < 0) { + if (errno == EINTR) + continue; + perror("ping"); + continue; + } + unpack(packet, c, &from); + if (pingcount > 0 && nreceived >= pingcount) + break; + } + pingstats(0); } extern int ping_main(int argc, char **argv) { - char *thisarg; - - argc--; - argv++; - options = 0; - /* Parse any options */ - while (argc > 1) { - if (**argv != '-') usage(ping_usage); - thisarg = *argv; thisarg++; - switch (*thisarg) { - case 'q': options |= O_QUIET; break; - case 'c': - argc--; argv++; - pingcount = atoi(*argv); - break; - default: - usage(ping_usage); - } - argc--; argv++; - } - if (argc < 1) usage(ping_usage); - - myid = getpid() & 0xFFFF; - ping(*argv); - exit(TRUE); + char *thisarg; + + argc--; + argv++; + options = 0; + /* Parse any options */ + while (argc > 1) { + if (**argv != '-') + usage(ping_usage); + thisarg = *argv; + thisarg++; + switch (*thisarg) { + case 'q': + options |= O_QUIET; + break; + case 'c': + argc--; + argv++; + pingcount = atoi(*argv); + break; + default: + usage(ping_usage); + } + argc--; + argv++; + } + if (argc < 1) + usage(ping_usage); + + myid = getpid() & 0xFFFF; + ping(*argv); + exit(TRUE); } #endif |