diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2007-02-07 23:20:32 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2007-02-07 23:20:32 +0000 |
commit | 0850cdabded5ee04e243e45d419d7707da78bb51 (patch) | |
tree | f3edd429d95cfa19f9ae603053751247a750e534 /networking/tftp.c | |
parent | 8c6c6e955b4a73b8a2cac8c0d277bc109b329908 (diff) | |
download | busybox-w32-0850cdabded5ee04e243e45d419d7707da78bb51.tar.gz busybox-w32-0850cdabded5ee04e243e45d419d7707da78bb51.tar.bz2 busybox-w32-0850cdabded5ee04e243e45d419d7707da78bb51.zip |
tftp: fix IPv6 fallout
Diffstat (limited to 'networking/tftp.c')
-rw-r--r-- | networking/tftp.c | 41 |
1 files changed, 22 insertions, 19 deletions
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] ); |