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
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Check to see if this is a valid local address.  If so, we should
 | 
			
		||||
 * end up having the same local and remote address when trying to
 | 
			
		||||
 * bind to it.
 | 
			
		||||
 * Check to see if this is a valid local address, meaning that we can
 | 
			
		||||
 * legally bind to it.
 | 
			
		||||
 */
 | 
			
		||||
static int address_is_local(const union sock_addr *addr)
 | 
			
		||||
{
 | 
			
		||||
    union sock_addr sa;
 | 
			
		||||
    union sock_addr sa1, sa2;
 | 
			
		||||
    int sockfd = -1;
 | 
			
		||||
    int e;
 | 
			
		||||
    int rv = 0;
 | 
			
		||||
    socklen_t addrlen;
 | 
			
		||||
 | 
			
		||||
    memcpy(&sa1, addr, sizeof sa1);
 | 
			
		||||
 | 
			
		||||
    /* Multicast or universal broadcast address? */
 | 
			
		||||
    if (addr->sa.sa_family == AF_INET) {
 | 
			
		||||
        if (ntohl(addr->si.sin_addr.s_addr) >= (224UL << 24))
 | 
			
		||||
    if (sa1.sa.sa_family == AF_INET) {
 | 
			
		||||
        if (ntohl(sa1.si.sin_addr.s_addr) >= (224UL << 24))
 | 
			
		||||
            return 0;
 | 
			
		||||
	sa1.si.sin_port = 0;	/* Any port */
 | 
			
		||||
    }
 | 
			
		||||
#ifdef HAVE_IPV6
 | 
			
		||||
    else if (addr->sa.sa_family == AF_INET6) {
 | 
			
		||||
        if (IN6_IS_ADDR_MULTICAST(&addr->s6.sin6_addr))
 | 
			
		||||
    else if (sa1.sa.sa_family == AF_INET6) {
 | 
			
		||||
        if (IN6_IS_ADDR_MULTICAST(&sa1.s6.sin6_addr))
 | 
			
		||||
            return 0;
 | 
			
		||||
	sa1.s6.sin6_port = 0;	/* Any port */
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
    else
 | 
			
		||||
        return 0;
 | 
			
		||||
 | 
			
		||||
    sockfd = socket(addr->sa.sa_family, SOCK_DGRAM, 0);
 | 
			
		||||
    sockfd = socket(sa1.sa.sa_family, SOCK_DGRAM, 0);
 | 
			
		||||
    if (sockfd < 0)
 | 
			
		||||
        goto err;
 | 
			
		||||
 | 
			
		||||
    if (connect(sockfd, &addr->sa, SOCKLEN(addr)))
 | 
			
		||||
    if (bind(sockfd, &sa1.sa, SOCKLEN(&sa1)))
 | 
			
		||||
        goto err;
 | 
			
		||||
 | 
			
		||||
    addrlen = SOCKLEN(addr);
 | 
			
		||||
    if (getsockname(sockfd, (struct sockaddr *)&sa, &addrlen))
 | 
			
		||||
    if (getsockname(sockfd, (struct sockaddr *)&sa2, &addrlen))
 | 
			
		||||
        goto err;
 | 
			
		||||
 | 
			
		||||
    if (addr->sa.sa_family == AF_INET)
 | 
			
		||||
        rv = sa.si.sin_addr.s_addr == addr->si.sin_addr.s_addr;
 | 
			
		||||
    if (sa1.sa.sa_family != sa2.sa.sa_family)
 | 
			
		||||
	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
 | 
			
		||||
    else if (addr->sa.sa_family == AF_INET6)
 | 
			
		||||
        rv = IN6_ARE_ADDR_EQUAL(&sa.s6.sin6_addr, &addr->s6.sin6_addr);
 | 
			
		||||
    else if (sa2.sa.sa_family == AF_INET6)
 | 
			
		||||
        rv = IN6_ARE_ADDR_EQUAL(&sa1.s6.sin6_addr, &sa2.s6.sin6_addr);
 | 
			
		||||
#endif
 | 
			
		||||
    else
 | 
			
		||||
        rv = 0;
 | 
			
		||||
  err:
 | 
			
		||||
 | 
			
		||||
err:
 | 
			
		||||
    e = errno;
 | 
			
		||||
 | 
			
		||||
    if (sockfd >= 0)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue