Fixes a long-standing issue where host_to_ip6addr would only ever examine/return the only the first item of the address chain returned by getaddrinfo, instead of traversing the chain and copying each of them. This has always been how host_to_ipaddr behaves, and all of the other related ipv6 code is already written to handle multiple possible addresses. Signed-off-by: Wes Campaigne <westacular@xxxxxxxxx> --- xtables.c | 29 +++++++++++------------------ 1 files changed, 11 insertions(+), 18 deletions(-) diff --git a/xtables.c b/xtables.c index 57d5d13..aea32ca 100644 --- a/xtables.c +++ b/xtables.c @@ -1415,17 +1415,17 @@ struct in6_addr *xtables_numeric_to_ip6addr(const char *num) static struct in6_addr * host_to_ip6addr(const char *name, unsigned int *naddr) { - static struct in6_addr *addr; + struct in6_addr *addr; struct addrinfo hints; struct addrinfo *res; + struct addrinfo *p; int err; + unsigned int i; memset(&hints, 0, sizeof(hints)); hints.ai_flags = AI_CANONNAME; hints.ai_family = AF_INET6; hints.ai_socktype = SOCK_RAW; - hints.ai_protocol = IPPROTO_IPV6; - hints.ai_next = NULL; *naddr = 0; if ((err = getaddrinfo(name, NULL, &hints, &res)) != 0) { @@ -1434,20 +1434,19 @@ host_to_ip6addr(const char *name, unsigned int *naddr) #endif return NULL; } else { - if (res->ai_family != AF_INET6 || - res->ai_addrlen != sizeof(struct sockaddr_in6)) - return NULL; - + /* Find length of address-chain */ + for(p = res; p != NULL; p = p->ai_next) + (*naddr)++; #ifdef DEBUG fprintf(stderr, "resolved: len=%d %s ", res->ai_addrlen, xtables_ip6addr_to_numeric(&((struct sockaddr_in6 *)res->ai_addr)->sin6_addr)); #endif - /* Get the first element of the address-chain */ - addr = xtables_malloc(sizeof(struct in6_addr)); - memcpy(addr, &((const struct sockaddr_in6 *)res->ai_addr)->sin6_addr, - sizeof(struct in6_addr)); + /* Copy each element of the address-chain */ + addr = xtables_calloc(*naddr, sizeof(struct in6_addr)); + for(p = res, i = 0; p != NULL && i < *naddr; p = p->ai_next, i++) + memcpy(&addr[i], &((const struct sockaddr_in6 *)p->ai_addr)->sin6_addr, + sizeof(struct in6_addr)); freeaddrinfo(res); - *naddr = 1; return addr; } @@ -1559,12 +1558,6 @@ xtables_ip6parse_multiple(const char *name, struct in6_addr **addrpp, strcpy(buf, "::"); addrp = ip6parse_hostnetwork(buf, &n); - /* ip6parse_hostnetwork only ever returns one IP - address (it exits if the resolution fails). - Therefore, n will always be 1 here. Leaving the - code below in anyway in case ip6parse_hostnetwork - is improved some day to behave like - ipparse_hostnetwork: */ if (n > 1) { count += n - 1; *addrpp = xtables_realloc(*addrpp, -- 1.7.1 -- To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html