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 | |
| parent | 8c6c6e955b4a73b8a2cac8c0d277bc109b329908 (diff) | |
| download | busybox-w32-0850cdabded5ee04e243e45d419d7707da78bb51.tar.gz busybox-w32-0850cdabded5ee04e243e45d419d7707da78bb51.tar.bz2 busybox-w32-0850cdabded5ee04e243e45d419d7707da78bb51.zip | |
tftp: fix IPv6 fallout
| -rw-r--r-- | include/libbb.h | 4 | ||||
| -rw-r--r-- | libbb/xconnect.c | 2 | ||||
| -rw-r--r-- | networking/tftp.c | 41 |
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 */ |
| 290 | unsigned bb_lookup_port(const char *port, const char *protocol, unsigned default_port); | 290 | unsigned bb_lookup_port(const char *port, const char *protocol, unsigned default_port); |
| 291 | typedef struct len_and_sockaddr { | 291 | typedef 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. */ |
| 336 | void set_nport(len_and_sockaddr *lsa, unsigned port); | 336 | void 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 */ |
| 338 | int get_nport(len_and_sockaddr *lsa); | 338 | int get_nport(const len_and_sockaddr *lsa); |
| 339 | /* Reverse DNS. Returns NULL on failure. */ | 339 | /* Reverse DNS. Returns NULL on failure. */ |
| 340 | char* xmalloc_sockaddr2host(const struct sockaddr *sa, socklen_t salen); | 340 | char* 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 | ||
| 85 | int get_nport(len_and_sockaddr *lsa) | 85 | int 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] ); |
