tftp: fix IPv6 fallout
No binary (build failed)
—
(log yok)
| @@ -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 */ | |
| @@ -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) { | |
| @@ -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] ); | |