X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=ping.c;h=50c7ce6e64f98344996b7369adaee3eab9afe725;hb=5165fbed639916e0fde15a827241b21981be7934;hp=14a56cd55bdc3a9dd3f725fa10dcbc6de2454422;hpb=7ab9c7ee52db8759d457819f5480378fa3aa97cc;p=oweals%2Fbusybox.git diff --git a/ping.c b/ping.c index 14a56cd55..50c7ce6e6 100644 --- a/ping.c +++ b/ping.c @@ -1,6 +1,6 @@ /* vi: set sw=4 ts=4: */ /* - * $Id: ping.c,v 1.15 2000/05/12 19:41: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; -#define DEFDATALEN 56 -#define MAXIPLEN 60 -#define MAXICMPLEN 76 -#define MAXPACKET 65468 +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 + +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,13 +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" -#ifndef BB_FEATURE_TRIVIAL_HELP - "\nSend ICMP ECHO_REQUEST packets to network hosts\n" -#endif - ; - +#ifdef BB_FEATURE_SIMPLE_PING static char *hostname = NULL; static void noresp(int ign) @@ -104,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; @@ -112,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()); @@ -124,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)); @@ -138,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 */ @@ -156,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 */ @@ -168,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) @@ -176,26 +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" -#ifndef BB_FEATURE_TRIVIAL_HELP - "\nSend ICMP ECHO_REQUEST packets to network hosts.\n\n" - "Options:\n" - "\t-c COUNT\tSend only COUNT pings.\n" - "\t-q\t\tQuiet mode, only displays output at start\n" - "\t\t\tand when finished.\n" -#endif - ; - 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; @@ -206,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); @@ -227,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; @@ -251,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, - (int)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 */ @@ -303,7 +371,7 @@ 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; @@ -351,17 +419,16 @@ static void unpack(char *buf, int sz, struct sockaddr_in *from) printf("\n"); } else if (icmppkt->icmp_type != ICMP_ECHO) - fprintf(stderr, - "Warning: Got ICMP %d (%s)\n", + 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"); @@ -369,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 */ @@ -384,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); } @@ -412,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); @@ -429,7 +493,7 @@ static void ping(char *host) (struct sockaddr *) &from, &fromlen)) < 0) { if (errno == EINTR) continue; - perror("ping"); + perror_msg("recvfrom"); continue; } unpack(packet, c, &from); @@ -443,6 +507,8 @@ 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; @@ -455,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. @@ -489,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.