forked from mirrors/tftp-hpa-google
tftpd: the "is this address local" algorithm no longer works on Linux
Linux no longer tries to match the local address with the remote one, so address_is_local() fails. Try instead to simply see if we can bind to the explicit address. Signed-off-by: H. Peter Anvin <hpa@zytor.com>
This commit is contained in:
parent
badf05140d
commit
c6d2c36b1a
1 changed files with 23 additions and 16 deletions
|
@ -51,52 +51,59 @@ struct in_pktinfo {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check to see if this is a valid local address. If so, we should
|
* Check to see if this is a valid local address, meaning that we can
|
||||||
* end up having the same local and remote address when trying to
|
* legally bind to it.
|
||||||
* bind to it.
|
|
||||||
*/
|
*/
|
||||||
static int address_is_local(const union sock_addr *addr)
|
static int address_is_local(const union sock_addr *addr)
|
||||||
{
|
{
|
||||||
union sock_addr sa;
|
union sock_addr sa1, sa2;
|
||||||
int sockfd = -1;
|
int sockfd = -1;
|
||||||
int e;
|
int e;
|
||||||
int rv = 0;
|
int rv = 0;
|
||||||
socklen_t addrlen;
|
socklen_t addrlen;
|
||||||
|
|
||||||
|
memcpy(&sa1, addr, sizeof sa1);
|
||||||
|
|
||||||
/* Multicast or universal broadcast address? */
|
/* Multicast or universal broadcast address? */
|
||||||
if (addr->sa.sa_family == AF_INET) {
|
if (sa1.sa.sa_family == AF_INET) {
|
||||||
if (ntohl(addr->si.sin_addr.s_addr) >= (224UL << 24))
|
if (ntohl(sa1.si.sin_addr.s_addr) >= (224UL << 24))
|
||||||
return 0;
|
return 0;
|
||||||
|
sa1.si.sin_port = 0; /* Any port */
|
||||||
}
|
}
|
||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
else if (addr->sa.sa_family == AF_INET6) {
|
else if (sa1.sa.sa_family == AF_INET6) {
|
||||||
if (IN6_IS_ADDR_MULTICAST(&addr->s6.sin6_addr))
|
if (IN6_IS_ADDR_MULTICAST(&sa1.s6.sin6_addr))
|
||||||
return 0;
|
return 0;
|
||||||
|
sa1.s6.sin6_port = 0; /* Any port */
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
else
|
else
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
sockfd = socket(addr->sa.sa_family, SOCK_DGRAM, 0);
|
sockfd = socket(sa1.sa.sa_family, SOCK_DGRAM, 0);
|
||||||
if (sockfd < 0)
|
if (sockfd < 0)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
if (connect(sockfd, &addr->sa, SOCKLEN(addr)))
|
if (bind(sockfd, &sa1.sa, SOCKLEN(&sa1)))
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
addrlen = SOCKLEN(addr);
|
addrlen = SOCKLEN(addr);
|
||||||
if (getsockname(sockfd, (struct sockaddr *)&sa, &addrlen))
|
if (getsockname(sockfd, (struct sockaddr *)&sa2, &addrlen))
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
if (addr->sa.sa_family == AF_INET)
|
if (sa1.sa.sa_family != sa2.sa.sa_family)
|
||||||
rv = sa.si.sin_addr.s_addr == addr->si.sin_addr.s_addr;
|
goto err;
|
||||||
|
|
||||||
|
if (sa2.sa.sa_family == AF_INET)
|
||||||
|
rv = sa1.si.sin_addr.s_addr == sa2.si.sin_addr.s_addr;
|
||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
else if (addr->sa.sa_family == AF_INET6)
|
else if (sa2.sa.sa_family == AF_INET6)
|
||||||
rv = IN6_ARE_ADDR_EQUAL(&sa.s6.sin6_addr, &addr->s6.sin6_addr);
|
rv = IN6_ARE_ADDR_EQUAL(&sa1.s6.sin6_addr, &sa2.s6.sin6_addr);
|
||||||
#endif
|
#endif
|
||||||
else
|
else
|
||||||
rv = 0;
|
rv = 0;
|
||||||
err:
|
|
||||||
|
err:
|
||||||
e = errno;
|
e = errno;
|
||||||
|
|
||||||
if (sockfd >= 0)
|
if (sockfd >= 0)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue