X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=ping.c;h=50c7ce6e64f98344996b7369adaee3eab9afe725;hb=5165fbed639916e0fde15a827241b21981be7934;hp=c9cf5ffb4e553cde3e53065557fab340c46034e9;hpb=e49d5ecbbe51718fa925b6890a735e5937cc2aa2;p=oweals%2Fbusybox.git diff --git a/ping.c b/ping.c index c9cf5ffb4..50c7ce6e6 100644 --- a/ping.c +++ b/ping.c @@ -1,6 +1,6 @@ /* vi: set sw=4 ts=4: */ /* - * $Id: ping.c,v 1.11 2000/02/08 19:58:47 erik Exp $ + * $Id: ping.c,v 1.38 2001/02/20 06:14:08 andersen Exp $ * Mini ping implementation for busybox * * Copyright (C) 1999 by Randolph Chung @@ -31,7 +31,6 @@ * Original copyright notice is retained at the end of this file. */ -#include "internal.h" #include #include #include @@ -47,14 +46,100 @@ #include #include #include +#include +#include +#include +#include "busybox.h" + + +/* It turns out that libc5 doesn't have proper icmp support + * built into it header files, so we have to supplement it */ +#if ! defined __GLIBC__ && ! defined __UCLIBC__ +typedef unsigned int socklen_t; + +static const int ICMP_MINLEN = 8; /* abs minimum */ + +struct icmp_ra_addr +{ + u_int32_t ira_addr; + u_int32_t ira_preference; +}; + + +struct icmp +{ + u_int8_t icmp_type; /* type of message, see below */ + u_int8_t icmp_code; /* type sub code */ + u_int16_t icmp_cksum; /* ones complement checksum of struct */ + union + { + u_char ih_pptr; /* ICMP_PARAMPROB */ + struct in_addr ih_gwaddr; /* gateway address */ + struct ih_idseq /* echo datagram */ + { + u_int16_t icd_id; + u_int16_t icd_seq; + } ih_idseq; + u_int32_t ih_void; + + /* ICMP_UNREACH_NEEDFRAG -- Path MTU Discovery (RFC1191) */ + struct ih_pmtu + { + u_int16_t ipm_void; + u_int16_t ipm_nextmtu; + } ih_pmtu; + + struct ih_rtradv + { + u_int8_t irt_num_addrs; + u_int8_t irt_wpa; + u_int16_t irt_lifetime; + } ih_rtradv; + } icmp_hun; +#define icmp_pptr icmp_hun.ih_pptr +#define icmp_gwaddr icmp_hun.ih_gwaddr +#define icmp_id icmp_hun.ih_idseq.icd_id +#define icmp_seq icmp_hun.ih_idseq.icd_seq +#define icmp_void icmp_hun.ih_void +#define icmp_pmvoid icmp_hun.ih_pmtu.ipm_void +#define icmp_nextmtu icmp_hun.ih_pmtu.ipm_nextmtu +#define icmp_num_addrs icmp_hun.ih_rtradv.irt_num_addrs +#define icmp_wpa icmp_hun.ih_rtradv.irt_wpa +#define icmp_lifetime icmp_hun.ih_rtradv.irt_lifetime + union + { + struct + { + u_int32_t its_otime; + u_int32_t its_rtime; + u_int32_t its_ttime; + } id_ts; + struct + { + struct ip idi_ip; + /* options and then 64 bits of data */ + } id_ip; + struct icmp_ra_addr id_radv; + u_int32_t id_mask; + u_int8_t id_data[1]; + } icmp_dun; +#define icmp_otime icmp_dun.id_ts.its_otime +#define icmp_rtime icmp_dun.id_ts.its_rtime +#define icmp_ttime icmp_dun.id_ts.its_ttime +#define icmp_ip icmp_dun.id_ip.idi_ip +#define icmp_radv icmp_dun.id_radv +#define icmp_mask icmp_dun.id_mask +#define icmp_data icmp_dun.id_data +}; +#endif -#define DEFDATALEN 56 -#define MAXIPLEN 60 -#define MAXICMPLEN 76 -#define MAXPACKET 65468 +static const int DEFDATALEN = 56; +static const int MAXIPLEN = 60; +static const int MAXICMPLEN = 76; +static const int MAXPACKET = 65468; #define MAX_DUP_CHK (8 * 128) -#define MAXWAIT 10 -#define PINGINTERVAL 1 /* second */ +static const int MAXWAIT = 10; +static const int PINGINTERVAL = 1; /* second */ #define O_QUIET (1 << 0) @@ -64,6 +149,8 @@ #define CLR(bit) (A(bit) &= (~B(bit))) #define TST(bit) (A(bit) & B(bit)) +static void ping(const char *host); + /* common routines */ static int in_cksum(unsigned short *buf, int sz) { @@ -89,9 +176,7 @@ static int in_cksum(unsigned short *buf, int sz) } /* simple version */ -#ifdef BB_SIMPLE_PING -static const char *ping_usage = "ping host\n\n"; - +#ifdef BB_FEATURE_SIMPLE_PING static char *hostname = NULL; static void noresp(int ign) @@ -100,7 +185,7 @@ static void noresp(int ign) exit(0); } -static int ping(const char *host) +static void ping(const char *host) { struct hostent *h; struct sockaddr_in pingaddr; @@ -108,10 +193,8 @@ static int ping(const char *host) int pingsock, c; char packet[DEFDATALEN + MAXIPLEN + MAXICMPLEN]; - if ((pingsock = socket(AF_INET, SOCK_RAW, 1)) < 0) { /* 1 == ICMP */ - perror("ping"); - exit(1); - } + if ((pingsock = socket(AF_INET, SOCK_RAW, 1)) < 0) /* 1 == ICMP */ + perror_msg_and_die("creating a raw socket"); /* drop root privs if running setuid */ setuid(getuid()); @@ -120,7 +203,7 @@ static int ping(const char *host) pingaddr.sin_family = AF_INET; if (!(h = gethostbyname(host))) { - fprintf(stderr, "ping: unknown host %s\n", host); + error_msg("unknown host %s", host); exit(1); } memcpy(&pingaddr.sin_addr, h->h_addr, sizeof(pingaddr.sin_addr)); @@ -134,12 +217,8 @@ static int ping(const char *host) 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); - } + if (c < 0 || c != sizeof(packet)) + perror_msg_and_die("sendto"); signal(SIGALRM, noresp); alarm(5); /* give the host 5000ms to respond */ @@ -152,7 +231,7 @@ static int ping(const char *host) (struct sockaddr *) &from, &fromlen)) < 0) { if (errno == EINTR) continue; - perror("ping"); + perror_msg("recvfrom"); continue; } if (c >= 76) { /* ip + icmp */ @@ -164,7 +243,7 @@ static int ping(const char *host) } } printf("%s is alive!\n", hostname); - return (TRUE); + return; } extern int ping_main(int argc, char **argv) @@ -172,23 +251,17 @@ extern int ping_main(int argc, char **argv) argc--; argv++; if (argc < 1) - usage(ping_usage); + show_usage(); ping(*argv); - exit(TRUE); + return EXIT_SUCCESS; } -#else +#else /* ! BB_FEATURE_SIMPLE_PING */ /* 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 char *hostname = NULL; static struct sockaddr_in pingaddr; static int pingsock = -1; +static int datalen; /* intentionally uninitialized to work around gcc bug */ static long ntransmitted = 0, nreceived = 0, nrepeats = 0, pingcount = 0; static int myid = 0, options = 0; @@ -199,12 +272,12 @@ static void sendping(int); static void pingstats(int); static void unpack(char *, int, struct sockaddr_in *); -static void ping(char *); - /**************************************************************************/ -static void pingstats(int ign) +static void pingstats(int junk) { + int status; + signal(SIGINT, SIG_IGN); printf("\n--- %s ping statistics ---\n", hostname); @@ -220,14 +293,18 @@ static void pingstats(int ign) tmin / 10, tmin % 10, (tsum / (nreceived + nrepeats)) / 10, (tsum / (nreceived + nrepeats)) % 10, tmax / 10, tmax % 10); - exit(0); + if (nreceived != 0) + status = EXIT_SUCCESS; + else + status = EXIT_FAILURE; + exit(status); } -static void sendping(int ign) +static void sendping(int junk) { struct icmp *pkt; int i; - char packet[DEFDATALEN + 8]; + char packet[datalen + 8]; pkt = (struct icmp *) packet; @@ -244,13 +321,11 @@ static void sendping(int ign) 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); - } + if (i < 0) + perror_msg_and_die("sendto"); + else if ((size_t)i != sizeof(packet)) + error_msg_and_die("ping wrote %d chars; %d expected", i, + (int)sizeof(packet)); signal(SIGALRM, sendping); if (pingcount == 0 || ntransmitted < pingcount) { /* schedule next in 1s */ @@ -262,6 +337,26 @@ static void sendping(int ign) } } +static char *icmp_type_name (int id) +{ + switch (id) { + case ICMP_ECHOREPLY: return "Echo Reply"; + case ICMP_DEST_UNREACH: return "Destination Unreachable"; + case ICMP_SOURCE_QUENCH: return "Source Quench"; + case ICMP_REDIRECT: return "Redirect (change route)"; + case ICMP_ECHO: return "Echo Request"; + case ICMP_TIME_EXCEEDED: return "Time Exceeded"; + case ICMP_PARAMETERPROB: return "Parameter Problem"; + case ICMP_TIMESTAMP: return "Timestamp Request"; + case ICMP_TIMESTAMPREPLY: return "Timestamp Reply"; + case ICMP_INFO_REQUEST: return "Information Request"; + case ICMP_INFO_REPLY: return "Information Reply"; + case ICMP_ADDRESS: return "Address Mask Request"; + case ICMP_ADDRESSREPLY: return "Address Mask Reply"; + default: return "unknown ICMP type"; + } +} + static void unpack(char *buf, int sz, struct sockaddr_in *from) { struct icmp *icmppkt; @@ -276,16 +371,17 @@ static void unpack(char *buf, int sz, struct sockaddr_in *from) iphdr = (struct iphdr *) buf; hlen = iphdr->ihl << 2; /* discard if too short */ - if (sz < (DEFDATALEN + ICMP_MINLEN)) + if (sz < (datalen + ICMP_MINLEN)) return; sz -= hlen; icmppkt = (struct icmp *) (buf + hlen); + if (icmppkt->icmp_id != myid) + return; /* not our ping */ + if (icmppkt->icmp_type == ICMP_ECHOREPLY) { - if (icmppkt->icmp_id != myid) - return; /* not our ping */ - ++nreceived; + ++nreceived; tp = (struct timeval *) icmppkt->icmp_data; if ((tv.tv_usec -= tp->tv_usec) < 0) { @@ -321,18 +417,18 @@ static void unpack(char *buf, int sz, struct sockaddr_in *from) if (dupflag) printf(" (DUP!)"); printf("\n"); - } else { - fprintf(stderr, - "Warning: unknown ICMP packet received (not echo-reply)\n"); - } + } else + if (icmppkt->icmp_type != ICMP_ECHO) + error_msg("Warning: Got ICMP %d (%s)", + icmppkt->icmp_type, icmp_type_name (icmppkt->icmp_type)); } -static void ping(char *host) +static void ping(const char *host) { struct protoent *proto; struct hostent *h; char buf[MAXHOSTNAMELEN]; - char packet[DEFDATALEN + MAXIPLEN + MAXICMPLEN]; + char packet[datalen + MAXIPLEN + MAXICMPLEN]; int sockopt; proto = getprotobyname("icmp"); @@ -340,12 +436,10 @@ static void ping(char *host) * 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); + if (errno == EPERM) + error_msg_and_die("permission denied. (are you root?)"); + else + perror_msg_and_die("creating a raw socket"); } /* drop root privs if running setuid */ @@ -355,13 +449,12 @@ static void ping(char *host) pingaddr.sin_family = AF_INET; if (!(h = gethostbyname(host))) { - fprintf(stderr, "ping: unknown host %s\n", host); + error_msg("unknown host %s", host); exit(1); } if (h->h_addrtype != AF_INET) { - fprintf(stderr, - "ping: unknown address type; only AF_INET is currently supported.\n"); + error_msg("unknown address type; only AF_INET is currently supported."); exit(1); } @@ -383,7 +476,7 @@ static void ping(char *host) printf("PING %s (%s): %d data bytes\n", hostname, inet_ntoa(*(struct in_addr *) &pingaddr.sin_addr.s_addr), - DEFDATALEN); + datalen); signal(SIGINT, pingstats); @@ -393,14 +486,14 @@ static void ping(char *host) /* listen for replies */ while (1) { struct sockaddr_in from; - size_t fromlen = sizeof(from); + socklen_t fromlen = (socklen_t) sizeof(from); int c; if ((c = recvfrom(pingsock, packet, sizeof(packet), 0, (struct sockaddr *) &from, &fromlen)) < 0) { if (errno == EINTR) continue; - perror("ping"); + perror_msg("recvfrom"); continue; } unpack(packet, c, &from); @@ -414,13 +507,13 @@ extern int ping_main(int argc, char **argv) { char *thisarg; + datalen = DEFDATALEN; /* initialized here rather than in global scope to work around gcc bug */ + argc--; argv++; options = 0; /* Parse any options */ - while (argc > 1) { - if (**argv != '-') - usage(ping_usage); + while (argc >= 1 && **argv == '-') { thisarg = *argv; thisarg++; switch (*thisarg) { @@ -428,24 +521,31 @@ extern int ping_main(int argc, char **argv) options |= O_QUIET; break; case 'c': - argc--; + if (--argc <= 0) + show_usage(); argv++; pingcount = atoi(*argv); break; + case 's': + if (--argc <= 0) + show_usage(); + argv++; + datalen = atoi(*argv); + break; default: - usage(ping_usage); + show_usage(); } argc--; argv++; } if (argc < 1) - usage(ping_usage); + show_usage(); myid = getpid() & 0xFFFF; ping(*argv); - exit(TRUE); + return EXIT_SUCCESS; } -#endif +#endif /* ! BB_FEATURE_SIMPLE_PING */ /* * Copyright (c) 1989 The Regents of the University of California. @@ -462,10 +562,10 @@ extern int ping_main(int argc, char **argv) * 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. + * + * 3. + * * 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.