tftp: fix IPv6 fallout
This commit is contained in:
parent
8c6c6e955b
commit
0850cdabde
@ -289,7 +289,7 @@ int setsockopt_broadcast(int fd);
|
|||||||
/* NB: returns port in host byte order */
|
/* NB: returns port in host byte order */
|
||||||
unsigned bb_lookup_port(const char *port, const char *protocol, unsigned default_port);
|
unsigned bb_lookup_port(const char *port, const char *protocol, unsigned default_port);
|
||||||
typedef struct len_and_sockaddr {
|
typedef struct len_and_sockaddr {
|
||||||
int len;
|
socklen_t len;
|
||||||
union {
|
union {
|
||||||
struct sockaddr sa;
|
struct sockaddr sa;
|
||||||
struct sockaddr_in sin;
|
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. */
|
* NB: does NOT do htons() internally, just direct assignment. */
|
||||||
void set_nport(len_and_sockaddr *lsa, unsigned port);
|
void set_nport(len_and_sockaddr *lsa, unsigned port);
|
||||||
/* Retrieve sin[6]_port or return -1 for non-INET[6] lsa's */
|
/* 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. */
|
/* Reverse DNS. Returns NULL on failure. */
|
||||||
char* xmalloc_sockaddr2host(const struct sockaddr *sa, socklen_t salen);
|
char* xmalloc_sockaddr2host(const struct sockaddr *sa, socklen_t salen);
|
||||||
/* This one doesn't append :PORTNUM */
|
/* This one doesn't append :PORTNUM */
|
||||||
|
@ -82,7 +82,7 @@ int xconnect_tcp_v4(struct sockaddr_in *s_addr)
|
|||||||
/* "New" networking API */
|
/* "New" networking API */
|
||||||
|
|
||||||
|
|
||||||
int get_nport(len_and_sockaddr *lsa)
|
int get_nport(const len_and_sockaddr *lsa)
|
||||||
{
|
{
|
||||||
#if ENABLE_FEATURE_IPV6
|
#if ENABLE_FEATURE_IPV6
|
||||||
if (lsa->sa.sa_family == AF_INET6) {
|
if (lsa->sa.sa_family == AF_INET6) {
|
||||||
|
@ -132,7 +132,7 @@ static int tftp(
|
|||||||
#if ENABLE_FEATURE_TFTP_GET && ENABLE_FEATURE_TFTP_PUT
|
#if ENABLE_FEATURE_TFTP_GET && ENABLE_FEATURE_TFTP_PUT
|
||||||
const int cmd,
|
const int cmd,
|
||||||
#endif
|
#endif
|
||||||
const len_and_sockaddr *peer_lsa,
|
len_and_sockaddr *peer_lsa,
|
||||||
const char *remotefile, const int localfd,
|
const char *remotefile, const int localfd,
|
||||||
unsigned port, int tftp_bufsize)
|
unsigned port, int tftp_bufsize)
|
||||||
{
|
{
|
||||||
@ -149,6 +149,9 @@ static int tftp(
|
|||||||
|
|
||||||
USE_FEATURE_TFTP_BLOCKSIZE(int want_option_ack = 0;)
|
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
|
/* Can't use RESERVE_CONFIG_BUFFER here since the allocation
|
||||||
* size varies meaning BUFFERS_GO_ON_STACK would fail */
|
* size varies meaning BUFFERS_GO_ON_STACK would fail */
|
||||||
/* We must keep the transmit and receive buffers seperate */
|
/* We must keep the transmit and receive buffers seperate */
|
||||||
@ -156,7 +159,7 @@ static int tftp(
|
|||||||
char *xbuf = xmalloc(tftp_bufsize += 4);
|
char *xbuf = xmalloc(tftp_bufsize += 4);
|
||||||
char *rbuf = xmalloc(tftp_bufsize);
|
char *rbuf = xmalloc(tftp_bufsize);
|
||||||
|
|
||||||
port = htons(port);
|
port = org_port = htons(port);
|
||||||
|
|
||||||
socketfd = xsocket(peer_lsa->sa.sa_family, SOCK_DGRAM, 0);
|
socketfd = xsocket(peer_lsa->sa.sa_family, SOCK_DGRAM, 0);
|
||||||
|
|
||||||
@ -167,10 +170,10 @@ static int tftp(
|
|||||||
}
|
}
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
|
|
||||||
cp = xbuf;
|
cp = xbuf;
|
||||||
|
|
||||||
/* first create the opcode part */
|
/* first create the opcode part */
|
||||||
|
/* (this 16bit store is aligned) */
|
||||||
*((uint16_t*)cp) = htons(opcode);
|
*((uint16_t*)cp) = htons(opcode);
|
||||||
cp += 2;
|
cp += 2;
|
||||||
|
|
||||||
@ -222,6 +225,7 @@ static int tftp(
|
|||||||
/* add ack and data */
|
/* add ack and data */
|
||||||
|
|
||||||
if (CMD_GET(cmd) ? (opcode == TFTP_ACK) : (opcode == TFTP_DATA)) {
|
if (CMD_GET(cmd) ? (opcode == TFTP_ACK) : (opcode == TFTP_DATA)) {
|
||||||
|
/* TODO: unaligned access! */
|
||||||
*((uint16_t*)cp) = htons(block_nr);
|
*((uint16_t*)cp) = htons(block_nr);
|
||||||
cp += 2;
|
cp += 2;
|
||||||
block_nr++;
|
block_nr++;
|
||||||
@ -273,27 +277,25 @@ static int tftp(
|
|||||||
FD_SET(socketfd, &rfds);
|
FD_SET(socketfd, &rfds);
|
||||||
|
|
||||||
switch (select(socketfd + 1, &rfds, NULL, NULL, &tv)) {
|
switch (select(socketfd + 1, &rfds, NULL, NULL, &tv)) {
|
||||||
struct sockaddr *from;
|
unsigned from_port;
|
||||||
socklen_t fromlen;
|
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
fromlen = peer_lsa->len;
|
from->len = peer_lsa->len;
|
||||||
from = alloca(fromlen);
|
memset(from, 0, peer_lsa->len);
|
||||||
memset(from, 0, fromlen);
|
|
||||||
|
|
||||||
len = recvfrom(socketfd, rbuf, tftp_bufsize, 0,
|
len = recvfrom(socketfd, rbuf, tftp_bufsize, 0,
|
||||||
from, &fromlen);
|
&from->sa, &from->len);
|
||||||
if (len < 0) {
|
if (len < 0) {
|
||||||
bb_perror_msg("recvfrom");
|
bb_perror_msg("recvfrom");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#if ENABLE_FEATURE_IPV6
|
from_port = get_nport(from);
|
||||||
if (from->sa_family == AF_INET6)
|
if (port == org_port) {
|
||||||
if (((struct sockaddr_in6*)from)->sin6_port != port)
|
/* Our first query went to port 69
|
||||||
goto recv_again;
|
* but reply will come from different one.
|
||||||
#endif
|
* Remember and use this new port */
|
||||||
if (from->sa_family == AF_INET)
|
port = from_port;
|
||||||
if (((struct sockaddr_in*)from)->sin_port != port)
|
set_nport(peer_lsa, from_port);
|
||||||
|
}
|
||||||
|
if (port != from_port)
|
||||||
goto recv_again;
|
goto recv_again;
|
||||||
timeout = 0;
|
timeout = 0;
|
||||||
break;
|
break;
|
||||||
@ -317,6 +319,7 @@ static int tftp(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* process received packet */
|
/* process received packet */
|
||||||
|
/* (both accesses seems to be aligned) */
|
||||||
|
|
||||||
opcode = ntohs( ((uint16_t*)rbuf)[0] );
|
opcode = ntohs( ((uint16_t*)rbuf)[0] );
|
||||||
tmp = ntohs( ((uint16_t*)rbuf)[1] );
|
tmp = ntohs( ((uint16_t*)rbuf)[1] );
|
||||||
|
Loading…
x
Reference in New Issue
Block a user