diff options
author | Denis Vlasenko | 2007-02-07 23:20:32 +0000 |
---|---|---|
committer | Denis Vlasenko | 2007-02-07 23:20:32 +0000 |
commit | 0850cdabded5ee04e243e45d419d7707da78bb51 (patch) | |
tree | f3edd429d95cfa19f9ae603053751247a750e534 | |
parent | 8c6c6e955b4a73b8a2cac8c0d277bc109b329908 (diff) | |
download | busybox-0850cdabded5ee04e243e45d419d7707da78bb51.zip busybox-0850cdabded5ee04e243e45d419d7707da78bb51.tar.gz |
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 d5a20d3..5b2f625 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -289,7 +289,7 @@ int setsockopt_broadcast(int fd); /* NB: returns port in host byte order */ unsigned bb_lookup_port(const char *port, const char *protocol, unsigned default_port); typedef struct len_and_sockaddr { - int len; + socklen_t len; union { struct sockaddr sa; struct sockaddr_in sin; @@ -335,7 +335,7 @@ len_and_sockaddr* xhost_and_af2sockaddr(const char *host, int port, sa_family_t * NB: does NOT do htons() internally, just direct assignment. */ void set_nport(len_and_sockaddr *lsa, unsigned port); /* Retrieve sin[6]_port or return -1 for non-INET[6] lsa's */ -int get_nport(len_and_sockaddr *lsa); +int get_nport(const len_and_sockaddr *lsa); /* Reverse DNS. Returns NULL on failure. */ char* xmalloc_sockaddr2host(const struct sockaddr *sa, socklen_t salen); /* This one doesn't append :PORTNUM */ diff --git a/libbb/xconnect.c b/libbb/xconnect.c index 22f98dc..66b1366 100644 --- a/libbb/xconnect.c +++ b/libbb/xconnect.c @@ -82,7 +82,7 @@ int xconnect_tcp_v4(struct sockaddr_in *s_addr) /* "New" networking API */ -int get_nport(len_and_sockaddr *lsa) +int get_nport(const len_and_sockaddr *lsa) { #if ENABLE_FEATURE_IPV6 if (lsa->sa.sa_family == AF_INET6) { diff --git a/networking/tftp.c b/networking/tftp.c index 9083257..ada38bc 100644 --- a/networking/tftp.c +++ b/networking/tftp.c @@ -132,7 +132,7 @@ static int tftp( #if ENABLE_FEATURE_TFTP_GET && ENABLE_FEATURE_TFTP_PUT const int cmd, #endif - const len_and_sockaddr *peer_lsa, + len_and_sockaddr *peer_lsa, const char *remotefile, const int localfd, unsigned port, int tftp_bufsize) { @@ -149,6 +149,9 @@ static int tftp( USE_FEATURE_TFTP_BLOCKSIZE(int want_option_ack = 0;) + unsigned org_port; + len_and_sockaddr *const from = alloca(offsetof(len_and_sockaddr, sa) + peer_lsa->len); + /* Can't use RESERVE_CONFIG_BUFFER here since the allocation * size varies meaning BUFFERS_GO_ON_STACK would fail */ /* We must keep the transmit and receive buffers seperate */ @@ -156,7 +159,7 @@ static int tftp( char *xbuf = xmalloc(tftp_bufsize += 4); char *rbuf = xmalloc(tftp_bufsize); - port = htons(port); + port = org_port = htons(port); socketfd = xsocket(peer_lsa->sa.sa_family, SOCK_DGRAM, 0); @@ -167,10 +170,10 @@ static int tftp( } while (1) { - cp = xbuf; /* first create the opcode part */ + /* (this 16bit store is aligned) */ *((uint16_t*)cp) = htons(opcode); cp += 2; @@ -222,6 +225,7 @@ static int tftp( /* add ack and data */ if (CMD_GET(cmd) ? (opcode == TFTP_ACK) : (opcode == TFTP_DATA)) { + /* TODO: unaligned access! */ *((uint16_t*)cp) = htons(block_nr); cp += 2; block_nr++; @@ -273,28 +277,26 @@ static int tftp( FD_SET(socketfd, &rfds); switch (select(socketfd + 1, &rfds, NULL, NULL, &tv)) { - struct sockaddr *from; - socklen_t fromlen; - + unsigned from_port; case 1: - fromlen = peer_lsa->len; - from = alloca(fromlen); - memset(from, 0, fromlen); - + from->len = peer_lsa->len; + memset(from, 0, peer_lsa->len); len = recvfrom(socketfd, rbuf, tftp_bufsize, 0, - from, &fromlen); + &from->sa, &from->len); if (len < 0) { bb_perror_msg("recvfrom"); break; } -#if ENABLE_FEATURE_IPV6 - if (from->sa_family == AF_INET6) - if (((struct sockaddr_in6*)from)->sin6_port != port) - goto recv_again; -#endif - if (from->sa_family == AF_INET) - if (((struct sockaddr_in*)from)->sin_port != port) - goto recv_again; + from_port = get_nport(from); + if (port == org_port) { + /* Our first query went to port 69 + * but reply will come from different one. + * Remember and use this new port */ + port = from_port; + set_nport(peer_lsa, from_port); + } + if (port != from_port) + goto recv_again; timeout = 0; break; case 0: @@ -317,6 +319,7 @@ static int tftp( } /* process received packet */ + /* (both accesses seems to be aligned) */ opcode = ntohs( ((uint16_t*)rbuf)[0] ); tmp = ntohs( ((uint16_t*)rbuf)[1] ); |