autofs-5.0.7 - fix ipv6 proximity calculation From: Ian Kent The socket based ioctl used to get interface information only return IPv4 information. Change get_proximity() function to use getifaddrs(3) instead. --- CHANGELOG | 1 modules/replicated.c | 149 ++++++++++++++------------------------------------ 2 files changed, 42 insertions(+), 108 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index dc38580..34c70fa 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,7 @@ ======================= - fix nobind sun escaped map entries. - fix use cache entry after free in lookup_prune_one_cache(). +- fix ipv6 proximity calculation. 25/07/2012 autofs-5.0.7 ======================= diff --git a/modules/replicated.c b/modules/replicated.c index 78046c6..bd6003b 100644 --- a/modules/replicated.c +++ b/modules/replicated.c @@ -52,6 +52,7 @@ #include #include #include +#include #include "rpc_subs.h" #include "replicated.h" @@ -110,58 +111,18 @@ void seed_random(void) return; } -static int alloc_ifreq(struct ifconf *ifc, int sock) -{ - int ret, lastlen = ifc_last_len, len = ifc_buf_len; - char err_buf[MAX_ERR_BUF], *buf; - - while (1) { - buf = malloc(len); - if (!buf) { - char *estr = strerror_r(errno, err_buf, MAX_ERR_BUF); - logerr("malloc: %s", estr); - return 0; - } - - ifc->ifc_len = len; - ifc->ifc_req = (struct ifreq *) buf; - - ret = ioctl(sock, SIOCGIFCONF, ifc); - if (ret == -1) { - char *estr = strerror_r(errno, err_buf, MAX_ERR_BUF); - logerr("ioctl: %s", estr); - free(buf); - return 0; - } - - if (ifc->ifc_len <= lastlen) - break; - - lastlen = ifc->ifc_len; - len += MAX_IFC_BUF; - free(buf); - } - - if (lastlen != ifc_last_len) { - ifc_last_len = lastlen; - ifc_buf_len = len; - } - - return 1; -} - static unsigned int get_proximity(struct sockaddr *host_addr) { + struct ifaddrs *ifa = NULL; + struct ifaddrs *this; struct sockaddr_in *addr, *msk_addr, *if_addr; struct sockaddr_in6 *addr6, *msk6_addr, *if6_addr; struct in_addr *hst_addr; struct in6_addr *hst6_addr; int addr_len; - char buf[MAX_ERR_BUF], *ptr; - struct ifconf ifc; - struct ifreq *ifr, nmptr; - int sock, ret, i; + char buf[MAX_ERR_BUF]; uint32_t mask, ha, ia, *mask6, *ha6, *ia6; + int ret; addr = NULL; addr6 = NULL; @@ -170,13 +131,14 @@ static unsigned int get_proximity(struct sockaddr *host_addr) mask6 = NULL; ha6 = NULL; ia6 = NULL; + ha = 0; switch (host_addr->sa_family) { case AF_INET: addr = (struct sockaddr_in *) host_addr; hst_addr = (struct in_addr *) &addr->sin_addr; ha = ntohl((uint32_t) hst_addr->s_addr); - addr_len = sizeof(hst_addr); + addr_len = sizeof(*hst_addr); break; case AF_INET6: @@ -186,7 +148,7 @@ static unsigned int get_proximity(struct sockaddr *host_addr) addr6 = (struct sockaddr_in6 *) host_addr; hst6_addr = (struct in6_addr *) &addr6->sin6_addr; ha6 = &hst6_addr->s6_addr32[0]; - addr_len = sizeof(hst6_addr); + addr_len = sizeof(*hst6_addr); break; #endif @@ -194,36 +156,29 @@ static unsigned int get_proximity(struct sockaddr *host_addr) return PROXIMITY_ERROR; } - sock = open_sock(AF_INET, SOCK_DGRAM, 0); - if (sock < 0) { + ret = getifaddrs(&ifa); + if (ret) { char *estr = strerror_r(errno, buf, MAX_ERR_BUF); - logerr("socket creation failed: %s", estr); + logerr("getifaddrs: %s", estr); return PROXIMITY_ERROR; } - if (!alloc_ifreq(&ifc, sock)) { - close(sock); - return PROXIMITY_ERROR; - } - - /* For each interface */ - - /* Is the address a local interface */ - i = 0; - ptr = (char *) &ifc.ifc_buf[0]; - - while (ptr < (char *) ifc.ifc_req + ifc.ifc_len) { - ifr = (struct ifreq *) ptr; + this = ifa; + while (this) { + if (this->ifa_flags & IFF_POINTOPOINT || + this->ifa_addr->sa_data == NULL) { + this = this->ifa_next; + continue; + } - switch (ifr->ifr_addr.sa_family) { + switch (this->ifa_addr->sa_family) { case AF_INET: if (host_addr->sa_family == AF_INET6) break; - if_addr = (struct sockaddr_in *) &ifr->ifr_addr; + if_addr = (struct sockaddr_in *) this->ifa_addr; ret = memcmp(&if_addr->sin_addr, hst_addr, addr_len); if (!ret) { - close(sock); - free(ifc.ifc_req); + freeifaddrs(ifa); return PROXIMITY_LOCAL; } break; @@ -234,55 +189,41 @@ static unsigned int get_proximity(struct sockaddr *host_addr) #else if (host_addr->sa_family == AF_INET) break; - - if6_addr = (struct sockaddr_in6 *) &ifr->ifr_addr; + if6_addr = (struct sockaddr_in6 *) this->ifa_addr; ret = memcmp(&if6_addr->sin6_addr, hst6_addr, addr_len); if (!ret) { - close(sock); - free(ifc.ifc_req); + freeifaddrs(ifa); return PROXIMITY_LOCAL; } #endif - default: break; } - - i++; - ptr = (char *) &ifc.ifc_req[i]; + this = this->ifa_next; } - i = 0; - ptr = (char *) &ifc.ifc_buf[0]; - - while (ptr < (char *) ifc.ifc_req + ifc.ifc_len) { - ifr = (struct ifreq *) ptr; - - nmptr = *ifr; - ret = ioctl(sock, SIOCGIFNETMASK, &nmptr); - if (ret == -1) { - char *estr = strerror_r(errno, buf, MAX_ERR_BUF); - logerr("ioctl: %s", estr); - close(sock); - free(ifc.ifc_req); - return PROXIMITY_ERROR; + this = ifa; + while (this) { + if (this->ifa_flags & IFF_POINTOPOINT || + this->ifa_addr->sa_data == NULL) { + this = this->ifa_next; + continue; } - switch (ifr->ifr_addr.sa_family) { + switch (this->ifa_addr->sa_family) { case AF_INET: if (host_addr->sa_family == AF_INET6) break; - if_addr = (struct sockaddr_in *) &ifr->ifr_addr; + if_addr = (struct sockaddr_in *) this->ifa_addr; ia = ntohl((uint32_t) if_addr->sin_addr.s_addr); - /* Is the address within a localiy attached subnet */ + /* Is the address within a localy attached subnet */ - msk_addr = (struct sockaddr_in *) &nmptr.ifr_netmask; + msk_addr = (struct sockaddr_in *) this->ifa_netmask; mask = ntohl((uint32_t) msk_addr->sin_addr.s_addr); if ((ia & mask) == (ha & mask)) { - close(sock); - free(ifc.ifc_req); + freeifaddrs(ifa); return PROXIMITY_SUBNET; } @@ -304,8 +245,7 @@ static unsigned int get_proximity(struct sockaddr *host_addr) break; if ((ia & mask) == (ha & mask)) { - close(sock); - free(ifc.ifc_req); + freeifaddrs(ifa); return PROXIMITY_NET; } break; @@ -316,35 +256,28 @@ static unsigned int get_proximity(struct sockaddr *host_addr) #else if (host_addr->sa_family == AF_INET) break; - - if6_addr = (struct sockaddr_in6 *) &ifr->ifr_addr; + if6_addr = (struct sockaddr_in6 *) this->ifa_addr; ia6 = &if6_addr->sin6_addr.s6_addr32[0]; /* Is the address within the network of the interface */ - msk6_addr = (struct sockaddr_in6 *) &nmptr.ifr_netmask; + msk6_addr = (struct sockaddr_in6 *) this->ifa_netmask; mask6 = &msk6_addr->sin6_addr.s6_addr32[0]; if (ipv6_mask_cmp(ha6, ia6, mask6)) { - close(sock); - free(ifc.ifc_req); + freeifaddrs(ifa); return PROXIMITY_SUBNET; } /* How do we define "local network" in ipv6? */ #endif - break; - default: break; } - - i++; - ptr = (char *) &ifc.ifc_req[i]; + this = this->ifa_next; } - close(sock); - free(ifc.ifc_req); + freeifaddrs(ifa); return PROXIMITY_OTHER; }