aboutsummaryrefslogtreecommitdiff
path: root/networking/ping.c
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2010-03-03 01:10:29 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2010-03-03 01:10:29 +0100
commit9341fd2d300e97f2bcf8e4b804c918240de4fe33 (patch)
treec7387c7eda05c2fecae7f17017c719df964f5849 /networking/ping.c
parent5749328b5634918888474222732572a3e0c97f70 (diff)
downloadbusybox-w32-9341fd2d300e97f2bcf8e4b804c918240de4fe33.tar.gz
busybox-w32-9341fd2d300e97f2bcf8e4b804c918240de4fe33.tar.bz2
busybox-w32-9341fd2d300e97f2bcf8e4b804c918240de4fe33.zip
ping: do not leak data from stack; shrink
FANCY ping: function old new delta common_ping_main 386 1732 +1346 sendping6 98 83 -15 sendping4 188 158 -30 ping4 575 - -575 ping6 756 - -756 ------------------------------------------------------------------------------ (add/remove: 0/2 grow/shrink: 1/2 up/down: 1346/-1376) Total: -30 bytes !FANCY ping: function old new delta hostname 4 - -4 common_ping_main 566 499 -67 Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'networking/ping.c')
-rw-r--r--networking/ping.c104
1 files changed, 57 insertions, 47 deletions
diff --git a/networking/ping.c b/networking/ping.c
index 467b7f694..6a766a437 100644
--- a/networking/ping.c
+++ b/networking/ping.c
@@ -43,13 +43,12 @@ enum {
43 DEFDATALEN = 56, 43 DEFDATALEN = 56,
44 MAXIPLEN = 60, 44 MAXIPLEN = 60,
45 MAXICMPLEN = 76, 45 MAXICMPLEN = 76,
46 MAXPACKET = 65468,
47 MAX_DUP_CHK = (8 * 128), 46 MAX_DUP_CHK = (8 * 128),
48 MAXWAIT = 10, 47 MAXWAIT = 10,
49 PINGINTERVAL = 1, /* 1 second */ 48 PINGINTERVAL = 1, /* 1 second */
50}; 49};
51 50
52/* common routines */ 51/* Common routines */
53 52
54static int in_cksum(unsigned short *buf, int sz) 53static int in_cksum(unsigned short *buf, int sz)
55{ 54{
@@ -76,40 +75,41 @@ static int in_cksum(unsigned short *buf, int sz)
76 75
77#if !ENABLE_FEATURE_FANCY_PING 76#if !ENABLE_FEATURE_FANCY_PING
78 77
79/* simple version */ 78/* Simple version */
80 79
81static char *hostname; 80struct globals {
81 char *hostname;
82 char packet[DEFDATALEN + MAXIPLEN + MAXICMPLEN];
83} FIX_ALIASING;
84#define G (*(struct globals*)&bb_common_bufsiz1)
85#define INIT_G() do { } while (0)
82 86
83static void noresp(int ign UNUSED_PARAM) 87static void noresp(int ign UNUSED_PARAM)
84{ 88{
85 printf("No response from %s\n", hostname); 89 printf("No response from %s\n", G.hostname);
86 exit(EXIT_FAILURE); 90 exit(EXIT_FAILURE);
87} 91}
88 92
89static void ping4(len_and_sockaddr *lsa) 93static void ping4(len_and_sockaddr *lsa)
90{ 94{
91 struct sockaddr_in pingaddr;
92 struct icmp *pkt; 95 struct icmp *pkt;
93 int pingsock, c; 96 int pingsock, c;
94 char packet[DEFDATALEN + MAXIPLEN + MAXICMPLEN];
95 97
96 pingsock = create_icmp_socket(); 98 pingsock = create_icmp_socket();
97 pingaddr = lsa->u.sin;
98 99
99 pkt = (struct icmp *) packet; 100 pkt = (struct icmp *) G.packet;
100 memset(pkt, 0, sizeof(packet)); 101 memset(pkt, 0, sizeof(G.packet));
101 pkt->icmp_type = ICMP_ECHO; 102 pkt->icmp_type = ICMP_ECHO;
102 pkt->icmp_cksum = in_cksum((unsigned short *) pkt, sizeof(packet)); 103 pkt->icmp_cksum = in_cksum((unsigned short *) pkt, sizeof(G.packet));
103 104
104 c = xsendto(pingsock, packet, DEFDATALEN + ICMP_MINLEN, 105 xsendto(pingsock, G.packet, DEFDATALEN + ICMP_MINLEN, &lsa->u.sa, lsa->len);
105 (struct sockaddr *) &pingaddr, sizeof(pingaddr));
106 106
107 /* listen for replies */ 107 /* listen for replies */
108 while (1) { 108 while (1) {
109 struct sockaddr_in from; 109 struct sockaddr_in from;
110 socklen_t fromlen = sizeof(from); 110 socklen_t fromlen = sizeof(from);
111 111
112 c = recvfrom(pingsock, packet, sizeof(packet), 0, 112 c = recvfrom(pingsock, G.packet, sizeof(G.packet), 0,
113 (struct sockaddr *) &from, &fromlen); 113 (struct sockaddr *) &from, &fromlen);
114 if (c < 0) { 114 if (c < 0) {
115 if (errno != EINTR) 115 if (errno != EINTR)
@@ -117,9 +117,9 @@ static void ping4(len_and_sockaddr *lsa)
117 continue; 117 continue;
118 } 118 }
119 if (c >= 76) { /* ip + icmp */ 119 if (c >= 76) { /* ip + icmp */
120 struct iphdr *iphdr = (struct iphdr *) packet; 120 struct iphdr *iphdr = (struct iphdr *) G.packet;
121 121
122 pkt = (struct icmp *) (packet + (iphdr->ihl << 2)); /* skip ip hdr */ 122 pkt = (struct icmp *) (G.packet + (iphdr->ihl << 2)); /* skip ip hdr */
123 if (pkt->icmp_type == ICMP_ECHOREPLY) 123 if (pkt->icmp_type == ICMP_ECHOREPLY)
124 break; 124 break;
125 } 125 }
@@ -131,31 +131,27 @@ static void ping4(len_and_sockaddr *lsa)
131#if ENABLE_PING6 131#if ENABLE_PING6
132static void ping6(len_and_sockaddr *lsa) 132static void ping6(len_and_sockaddr *lsa)
133{ 133{
134 struct sockaddr_in6 pingaddr;
135 struct icmp6_hdr *pkt; 134 struct icmp6_hdr *pkt;
136 int pingsock, c; 135 int pingsock, c;
137 int sockopt; 136 int sockopt;
138 char packet[DEFDATALEN + MAXIPLEN + MAXICMPLEN];
139 137
140 pingsock = create_icmp6_socket(); 138 pingsock = create_icmp6_socket();
141 pingaddr = lsa->u.sin6;
142 139
143 pkt = (struct icmp6_hdr *) packet; 140 pkt = (struct icmp6_hdr *) G.packet;
144 memset(pkt, 0, sizeof(packet)); 141 memset(pkt, 0, sizeof(G.packet));
145 pkt->icmp6_type = ICMP6_ECHO_REQUEST; 142 pkt->icmp6_type = ICMP6_ECHO_REQUEST;
146 143
147 sockopt = offsetof(struct icmp6_hdr, icmp6_cksum); 144 sockopt = offsetof(struct icmp6_hdr, icmp6_cksum);
148 setsockopt(pingsock, SOL_RAW, IPV6_CHECKSUM, &sockopt, sizeof(sockopt)); 145 setsockopt(pingsock, SOL_RAW, IPV6_CHECKSUM, &sockopt, sizeof(sockopt));
149 146
150 c = xsendto(pingsock, packet, DEFDATALEN + sizeof (struct icmp6_hdr), 147 xsendto(pingsock, G.packet, DEFDATALEN + sizeof(struct icmp6_hdr), &lsa->u.sa, lsa->len);
151 (struct sockaddr *) &pingaddr, sizeof(pingaddr));
152 148
153 /* listen for replies */ 149 /* listen for replies */
154 while (1) { 150 while (1) {
155 struct sockaddr_in6 from; 151 struct sockaddr_in6 from;
156 socklen_t fromlen = sizeof(from); 152 socklen_t fromlen = sizeof(from);
157 153
158 c = recvfrom(pingsock, packet, sizeof(packet), 0, 154 c = recvfrom(pingsock, G.packet, sizeof(G.packet), 0,
159 (struct sockaddr *) &from, &fromlen); 155 (struct sockaddr *) &from, &fromlen);
160 if (c < 0) { 156 if (c < 0) {
161 if (errno != EINTR) 157 if (errno != EINTR)
@@ -163,7 +159,7 @@ static void ping6(len_and_sockaddr *lsa)
163 continue; 159 continue;
164 } 160 }
165 if (c >= ICMP_MINLEN) { /* icmp6_hdr */ 161 if (c >= ICMP_MINLEN) { /* icmp6_hdr */
166 pkt = (struct icmp6_hdr *) packet; 162 pkt = (struct icmp6_hdr *) G.packet;
167 if (pkt->icmp6_type == ICMP6_ECHO_REPLY) 163 if (pkt->icmp6_type == ICMP6_ECHO_REPLY)
168 break; 164 break;
169 } 165 }
@@ -180,6 +176,8 @@ static int common_ping_main(sa_family_t af, char **argv)
180{ 176{
181 len_and_sockaddr *lsa; 177 len_and_sockaddr *lsa;
182 178
179 INIT_G();
180
183#if ENABLE_PING6 181#if ENABLE_PING6
184 while ((++argv)[0] && argv[0][0] == '-') { 182 while ((++argv)[0] && argv[0][0] == '-') {
185 if (argv[0][1] == '4') { 183 if (argv[0][1] == '4') {
@@ -196,14 +194,14 @@ static int common_ping_main(sa_family_t af, char **argv)
196 argv++; 194 argv++;
197#endif 195#endif
198 196
199 hostname = *argv; 197 G.hostname = *argv;
200 if (!hostname) 198 if (!G.hostname)
201 bb_show_usage(); 199 bb_show_usage();
202 200
203#if ENABLE_PING6 201#if ENABLE_PING6
204 lsa = xhost_and_af2sockaddr(hostname, 0, af); 202 lsa = xhost_and_af2sockaddr(G.hostname, 0, af);
205#else 203#else
206 lsa = xhost_and_af2sockaddr(hostname, 0, AF_INET); 204 lsa = xhost_and_af2sockaddr(G.hostname, 0, AF_INET);
207#endif 205#endif
208 /* Set timer _after_ DNS resolution */ 206 /* Set timer _after_ DNS resolution */
209 signal(SIGALRM, noresp); 207 signal(SIGALRM, noresp);
@@ -215,7 +213,7 @@ static int common_ping_main(sa_family_t af, char **argv)
215 else 213 else
216#endif 214#endif
217 ping4(lsa); 215 ping4(lsa);
218 printf("%s is alive!\n", hostname); 216 printf("%s is alive!\n", G.hostname);
219 return EXIT_SUCCESS; 217 return EXIT_SUCCESS;
220} 218}
221 219
@@ -223,7 +221,7 @@ static int common_ping_main(sa_family_t af, char **argv)
223#else /* FEATURE_FANCY_PING */ 221#else /* FEATURE_FANCY_PING */
224 222
225 223
226/* full(er) version */ 224/* Full(er) version */
227 225
228#define OPT_STRING ("qvc:s:w:W:I:4" IF_PING6("6")) 226#define OPT_STRING ("qvc:s:w:W:I:4" IF_PING6("6"))
229enum { 227enum {
@@ -253,6 +251,9 @@ struct globals {
253 unsigned deadline; 251 unsigned deadline;
254 unsigned timeout; 252 unsigned timeout;
255 unsigned total_secs; 253 unsigned total_secs;
254 unsigned sizeof_rcv_packet;
255 char *rcv_packet; /* [datalen + MAXIPLEN + MAXICMPLEN] */
256 void *snd_packet; /* [datalen + ipv4/ipv6_const] */
256 const char *hostname; 257 const char *hostname;
257 const char *dotted; 258 const char *dotted;
258 union { 259 union {
@@ -370,19 +371,20 @@ static void sendping_tail(void (*sp)(int), const void *pkt, int size_pkt)
370 371
371static void sendping4(int junk UNUSED_PARAM) 372static void sendping4(int junk UNUSED_PARAM)
372{ 373{
373 /* +4 reserves a place for timestamp, which may end up sitting 374 struct icmp *pkt = G.snd_packet;
374 * *after* packet. Saves one if() */
375 struct icmp *pkt = alloca(datalen + ICMP_MINLEN + 4);
376 375
377 memset(pkt, 0, datalen + ICMP_MINLEN + 4); 376 //memset(pkt, 0, datalen + ICMP_MINLEN + 4); - G.snd_packet was xzalloced
378 pkt->icmp_type = ICMP_ECHO; 377 pkt->icmp_type = ICMP_ECHO;
379 /*pkt->icmp_code = 0;*/ 378 /*pkt->icmp_code = 0;*/
380 /*pkt->icmp_cksum = 0;*/ 379 pkt->icmp_cksum = 0; /* cksum is calculated with this field set to 0 */
381 pkt->icmp_seq = htons(ntransmitted); /* don't ++ here, it can be a macro */ 380 pkt->icmp_seq = htons(ntransmitted); /* don't ++ here, it can be a macro */
382 pkt->icmp_id = myid; 381 pkt->icmp_id = myid;
383 382
384 /* We don't do hton, because we will read it back on the same machine */ 383 /* If datalen < 4, we store timestamp _past_ the packet,
384 * but it's ok - we allocated 4 extra bytes in xzalloc() just in case.
385 */
385 /*if (datalen >= 4)*/ 386 /*if (datalen >= 4)*/
387 /* No hton: we'll read it back on the same machine */
386 *(uint32_t*)&pkt->icmp_dun = monotonic_us(); 388 *(uint32_t*)&pkt->icmp_dun = monotonic_us();
387 389
388 pkt->icmp_cksum = in_cksum((unsigned short *) pkt, datalen + ICMP_MINLEN); 390 pkt->icmp_cksum = in_cksum((unsigned short *) pkt, datalen + ICMP_MINLEN);
@@ -394,7 +396,7 @@ static void sendping6(int junk UNUSED_PARAM)
394{ 396{
395 struct icmp6_hdr *pkt = alloca(datalen + sizeof(struct icmp6_hdr) + 4); 397 struct icmp6_hdr *pkt = alloca(datalen + sizeof(struct icmp6_hdr) + 4);
396 398
397 memset(pkt, 0, datalen + sizeof(struct icmp6_hdr) + 4); 399 //memset(pkt, 0, datalen + sizeof(struct icmp6_hdr) + 4);
398 pkt->icmp6_type = ICMP6_ECHO_REQUEST; 400 pkt->icmp6_type = ICMP6_ECHO_REQUEST;
399 /*pkt->icmp6_code = 0;*/ 401 /*pkt->icmp6_code = 0;*/
400 /*pkt->icmp6_cksum = 0;*/ 402 /*pkt->icmp6_cksum = 0;*/
@@ -404,6 +406,8 @@ static void sendping6(int junk UNUSED_PARAM)
404 /*if (datalen >= 4)*/ 406 /*if (datalen >= 4)*/
405 *(uint32_t*)(&pkt->icmp6_data8[4]) = monotonic_us(); 407 *(uint32_t*)(&pkt->icmp6_data8[4]) = monotonic_us();
406 408
409 //TODO? pkt->icmp_cksum = in_cksum(...);
410
407 sendping_tail(sendping6, pkt, datalen + sizeof(struct icmp6_hdr)); 411 sendping_tail(sendping6, pkt, datalen + sizeof(struct icmp6_hdr));
408} 412}
409#endif 413#endif
@@ -561,7 +565,6 @@ static void unpack6(char *packet, int sz, /*struct sockaddr_in6 *from,*/ int hop
561 565
562static void ping4(len_and_sockaddr *lsa) 566static void ping4(len_and_sockaddr *lsa)
563{ 567{
564 char packet[datalen + MAXIPLEN + MAXICMPLEN];
565 int sockopt; 568 int sockopt;
566 569
567 pingsock = create_icmp_socket(); 570 pingsock = create_icmp_socket();
@@ -594,14 +597,14 @@ static void ping4(len_and_sockaddr *lsa)
594 socklen_t fromlen = (socklen_t) sizeof(from); 597 socklen_t fromlen = (socklen_t) sizeof(from);
595 int c; 598 int c;
596 599
597 c = recvfrom(pingsock, packet, sizeof(packet), 0, 600 c = recvfrom(pingsock, G.rcv_packet, G.sizeof_rcv_packet, 0,
598 (struct sockaddr *) &from, &fromlen); 601 (struct sockaddr *) &from, &fromlen);
599 if (c < 0) { 602 if (c < 0) {
600 if (errno != EINTR) 603 if (errno != EINTR)
601 bb_perror_msg("recvfrom"); 604 bb_perror_msg("recvfrom");
602 continue; 605 continue;
603 } 606 }
604 unpack4(packet, c, &from); 607 unpack4(G.rcv_packet, c, &from);
605 if (pingcount && nreceived >= pingcount) 608 if (pingcount && nreceived >= pingcount)
606 break; 609 break;
607 } 610 }
@@ -610,7 +613,6 @@ static void ping4(len_and_sockaddr *lsa)
610extern int BUG_bad_offsetof_icmp6_cksum(void); 613extern int BUG_bad_offsetof_icmp6_cksum(void);
611static void ping6(len_and_sockaddr *lsa) 614static void ping6(len_and_sockaddr *lsa)
612{ 615{
613 char packet[datalen + MAXIPLEN + MAXICMPLEN];
614 int sockopt; 616 int sockopt;
615 struct msghdr msg; 617 struct msghdr msg;
616 struct sockaddr_in6 from; 618 struct sockaddr_in6 from;
@@ -670,8 +672,8 @@ static void ping6(len_and_sockaddr *lsa)
670 msg.msg_iov = &iov; 672 msg.msg_iov = &iov;
671 msg.msg_iovlen = 1; 673 msg.msg_iovlen = 1;
672 msg.msg_control = control_buf; 674 msg.msg_control = control_buf;
673 iov.iov_base = packet; 675 iov.iov_base = G.rcv_packet;
674 iov.iov_len = sizeof(packet); 676 iov.iov_len = G.sizeof_rcv_packet;
675 while (1) { 677 while (1) {
676 int c; 678 int c;
677 struct cmsghdr *mp; 679 struct cmsghdr *mp;
@@ -694,7 +696,7 @@ static void ping6(len_and_sockaddr *lsa)
694 move_from_unaligned_int(hoplimit, CMSG_DATA(mp)); 696 move_from_unaligned_int(hoplimit, CMSG_DATA(mp));
695 } 697 }
696 } 698 }
697 unpack6(packet, c, /*&from,*/ hoplimit); 699 unpack6(G.rcv_packet, c, /*&from,*/ hoplimit);
698 if (pingcount && nreceived >= pingcount) 700 if (pingcount && nreceived >= pingcount)
699 break; 701 break;
700 } 702 }
@@ -710,12 +712,20 @@ static void ping(len_and_sockaddr *lsa)
710 } 712 }
711 printf(": %d data bytes\n", datalen); 713 printf(": %d data bytes\n", datalen);
712 714
715 G.sizeof_rcv_packet = datalen + MAXIPLEN + MAXICMPLEN;
716 G.rcv_packet = xzalloc(G.sizeof_rcv_packet);
713#if ENABLE_PING6 717#if ENABLE_PING6
714 if (lsa->u.sa.sa_family == AF_INET6) 718 if (lsa->u.sa.sa_family == AF_INET6) {
719 /* +4 reserves a place for timestamp, which may end up sitting
720 * _after_ packet. Saves one if() - see sendping4/6() */
721 G.snd_packet = xzalloc(datalen + sizeof(struct icmp6_hdr) + 4);
715 ping6(lsa); 722 ping6(lsa);
716 else 723 } else
717#endif 724#endif
725 {
726 G.snd_packet = xzalloc(datalen + ICMP_MINLEN + 4);
718 ping4(lsa); 727 ping4(lsa);
728 }
719} 729}
720 730
721static int common_ping_main(int opt, char **argv) 731static int common_ping_main(int opt, char **argv)