aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2007-02-07 23:20:32 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2007-02-07 23:20:32 +0000
commit0850cdabded5ee04e243e45d419d7707da78bb51 (patch)
treef3edd429d95cfa19f9ae603053751247a750e534
parent8c6c6e955b4a73b8a2cac8c0d277bc109b329908 (diff)
downloadbusybox-w32-0850cdabded5ee04e243e45d419d7707da78bb51.tar.gz
busybox-w32-0850cdabded5ee04e243e45d419d7707da78bb51.tar.bz2
busybox-w32-0850cdabded5ee04e243e45d419d7707da78bb51.zip
tftp: fix IPv6 fallout
-rw-r--r--include/libbb.h4
-rw-r--r--libbb/xconnect.c2
-rw-r--r--networking/tftp.c41
3 files changed, 25 insertions, 22 deletions
diff --git a/include/libbb.h b/include/libbb.h
index d5a20d365..5b2f6251f 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -289,7 +289,7 @@ int setsockopt_broadcast(int fd);
289/* NB: returns port in host byte order */ 289/* NB: returns port in host byte order */
290unsigned bb_lookup_port(const char *port, const char *protocol, unsigned default_port); 290unsigned bb_lookup_port(const char *port, const char *protocol, unsigned default_port);
291typedef struct len_and_sockaddr { 291typedef struct len_and_sockaddr {
292 int len; 292 socklen_t len;
293 union { 293 union {
294 struct sockaddr sa; 294 struct sockaddr sa;
295 struct sockaddr_in sin; 295 struct sockaddr_in sin;
@@ -335,7 +335,7 @@ len_and_sockaddr* xhost_and_af2sockaddr(const char *host, int port, sa_family_t
335 * NB: does NOT do htons() internally, just direct assignment. */ 335 * NB: does NOT do htons() internally, just direct assignment. */
336void set_nport(len_and_sockaddr *lsa, unsigned port); 336void set_nport(len_and_sockaddr *lsa, unsigned port);
337/* Retrieve sin[6]_port or return -1 for non-INET[6] lsa's */ 337/* Retrieve sin[6]_port or return -1 for non-INET[6] lsa's */
338int get_nport(len_and_sockaddr *lsa); 338int get_nport(const len_and_sockaddr *lsa);
339/* Reverse DNS. Returns NULL on failure. */ 339/* Reverse DNS. Returns NULL on failure. */
340char* xmalloc_sockaddr2host(const struct sockaddr *sa, socklen_t salen); 340char* xmalloc_sockaddr2host(const struct sockaddr *sa, socklen_t salen);
341/* This one doesn't append :PORTNUM */ 341/* This one doesn't append :PORTNUM */
diff --git a/libbb/xconnect.c b/libbb/xconnect.c
index 22f98dcf2..66b136615 100644
--- a/libbb/xconnect.c
+++ b/libbb/xconnect.c
@@ -82,7 +82,7 @@ int xconnect_tcp_v4(struct sockaddr_in *s_addr)
82/* "New" networking API */ 82/* "New" networking API */
83 83
84 84
85int get_nport(len_and_sockaddr *lsa) 85int get_nport(const len_and_sockaddr *lsa)
86{ 86{
87#if ENABLE_FEATURE_IPV6 87#if ENABLE_FEATURE_IPV6
88 if (lsa->sa.sa_family == AF_INET6) { 88 if (lsa->sa.sa_family == AF_INET6) {
diff --git a/networking/tftp.c b/networking/tftp.c
index 9083257ab..ada38bc44 100644
--- a/networking/tftp.c
+++ b/networking/tftp.c
@@ -132,7 +132,7 @@ static int tftp(
132#if ENABLE_FEATURE_TFTP_GET && ENABLE_FEATURE_TFTP_PUT 132#if ENABLE_FEATURE_TFTP_GET && ENABLE_FEATURE_TFTP_PUT
133 const int cmd, 133 const int cmd,
134#endif 134#endif
135 const len_and_sockaddr *peer_lsa, 135 len_and_sockaddr *peer_lsa,
136 const char *remotefile, const int localfd, 136 const char *remotefile, const int localfd,
137 unsigned port, int tftp_bufsize) 137 unsigned port, int tftp_bufsize)
138{ 138{
@@ -149,6 +149,9 @@ static int tftp(
149 149
150 USE_FEATURE_TFTP_BLOCKSIZE(int want_option_ack = 0;) 150 USE_FEATURE_TFTP_BLOCKSIZE(int want_option_ack = 0;)
151 151
152 unsigned org_port;
153 len_and_sockaddr *const from = alloca(offsetof(len_and_sockaddr, sa) + peer_lsa->len);
154
152 /* Can't use RESERVE_CONFIG_BUFFER here since the allocation 155 /* Can't use RESERVE_CONFIG_BUFFER here since the allocation
153 * size varies meaning BUFFERS_GO_ON_STACK would fail */ 156 * size varies meaning BUFFERS_GO_ON_STACK would fail */
154 /* We must keep the transmit and receive buffers seperate */ 157 /* We must keep the transmit and receive buffers seperate */
@@ -156,7 +159,7 @@ static int tftp(
156 char *xbuf = xmalloc(tftp_bufsize += 4); 159 char *xbuf = xmalloc(tftp_bufsize += 4);
157 char *rbuf = xmalloc(tftp_bufsize); 160 char *rbuf = xmalloc(tftp_bufsize);
158 161
159 port = htons(port); 162 port = org_port = htons(port);
160 163
161 socketfd = xsocket(peer_lsa->sa.sa_family, SOCK_DGRAM, 0); 164 socketfd = xsocket(peer_lsa->sa.sa_family, SOCK_DGRAM, 0);
162 165
@@ -167,10 +170,10 @@ static int tftp(
167 } 170 }
168 171
169 while (1) { 172 while (1) {
170
171 cp = xbuf; 173 cp = xbuf;
172 174
173 /* first create the opcode part */ 175 /* first create the opcode part */
176 /* (this 16bit store is aligned) */
174 *((uint16_t*)cp) = htons(opcode); 177 *((uint16_t*)cp) = htons(opcode);
175 cp += 2; 178 cp += 2;
176 179
@@ -222,6 +225,7 @@ static int tftp(
222 /* add ack and data */ 225 /* add ack and data */
223 226
224 if (CMD_GET(cmd) ? (opcode == TFTP_ACK) : (opcode == TFTP_DATA)) { 227 if (CMD_GET(cmd) ? (opcode == TFTP_ACK) : (opcode == TFTP_DATA)) {
228 /* TODO: unaligned access! */
225 *((uint16_t*)cp) = htons(block_nr); 229 *((uint16_t*)cp) = htons(block_nr);
226 cp += 2; 230 cp += 2;
227 block_nr++; 231 block_nr++;
@@ -273,28 +277,26 @@ static int tftp(
273 FD_SET(socketfd, &rfds); 277 FD_SET(socketfd, &rfds);
274 278
275 switch (select(socketfd + 1, &rfds, NULL, NULL, &tv)) { 279 switch (select(socketfd + 1, &rfds, NULL, NULL, &tv)) {
276 struct sockaddr *from; 280 unsigned from_port;
277 socklen_t fromlen;
278
279 case 1: 281 case 1:
280 fromlen = peer_lsa->len; 282 from->len = peer_lsa->len;
281 from = alloca(fromlen); 283 memset(from, 0, peer_lsa->len);
282 memset(from, 0, fromlen);
283
284 len = recvfrom(socketfd, rbuf, tftp_bufsize, 0, 284 len = recvfrom(socketfd, rbuf, tftp_bufsize, 0,
285 from, &fromlen); 285 &from->sa, &from->len);
286 if (len < 0) { 286 if (len < 0) {
287 bb_perror_msg("recvfrom"); 287 bb_perror_msg("recvfrom");
288 break; 288 break;
289 } 289 }
290#if ENABLE_FEATURE_IPV6 290 from_port = get_nport(from);
291 if (from->sa_family == AF_INET6) 291 if (port == org_port) {
292 if (((struct sockaddr_in6*)from)->sin6_port != port) 292 /* Our first query went to port 69
293 goto recv_again; 293 * but reply will come from different one.
294#endif 294 * Remember and use this new port */
295 if (from->sa_family == AF_INET) 295 port = from_port;
296 if (((struct sockaddr_in*)from)->sin_port != port) 296 set_nport(peer_lsa, from_port);
297 goto recv_again; 297 }
298 if (port != from_port)
299 goto recv_again;
298 timeout = 0; 300 timeout = 0;
299 break; 301 break;
300 case 0: 302 case 0:
@@ -317,6 +319,7 @@ static int tftp(
317 } 319 }
318 320
319 /* process received packet */ 321 /* process received packet */
322 /* (both accesses seems to be aligned) */
320 323
321 opcode = ntohs( ((uint16_t*)rbuf)[0] ); 324 opcode = ntohs( ((uint16_t*)rbuf)[0] );
322 tmp = ntohs( ((uint16_t*)rbuf)[1] ); 325 tmp = ntohs( ((uint16_t*)rbuf)[1] );