[Gluster-devel] Reintroduce IPv6 support
Anders Blomdell
anders.blomdell at control.lth.se
Tue Sep 2 15:22:59 UTC 2014
Back from vacation, and would like to make a new version of http://review.gluster.org/#/c/8292/.
If I understand Emmanuel Dreyfus and some scattered mails on the internet, the reason for
IPv6 to be removed was that the code using getaddrinfo is written in such a way that it
(often incorrectly) assumes that the first address returned by getaddrinfo is the one we
are interested in. As I said in private to Emmanuel:
On 2014-07-31 19:55, Anders Blomdell wrote:
> On 2014-07-31 14:49, Emmanuel Dreyfus wrote:
>> Hi
>>
>> Here is a test case that shows the problem: AF_UNSPEC really means either
>> AF_INET or AF_INET6, you have to choose for a given socket. I wonder
>> what is Linux output.
>
> It actually means all:
>
>
> #include <stdio.h>
> #include <unistd.h>
> #include <err.h>
> #include <netdb.h>
> #include <sysexits.h>
> #include <sys/socket.h>
> #include <string.h>
> #include <arpa/inet.h>
>
> int
> main(void)
> {
> struct addrinfo hints, *res, *res0;
> int error;
> char buf[128];
>
> memset(&hints, 0, sizeof(hints));
> hints.ai_family = AF_UNSPEC;
> hints.ai_socktype = SOCK_STREAM;
> error = getaddrinfo("google.com", "http", &hints, &res0);
> if (error) {
> errx(1, "%s", gai_strerror(error));
> /*NOTREACHED*/
> }
> for (res = res0; res; res = res->ai_next) {
> void *p;
>
> if (res->ai_family == AF_INET) {
> p = &((struct sockaddr_in *)(res->ai_addr))->sin_addr;
> } else if (res->ai_family == AF_INET6) {
> p = &((struct sockaddr_in6 *)(res->ai_addr))->sin6_addr;
> }
> printf("family = %d, addr = %s\n",
> res->ai_family,
> inet_ntop(res->ai_family, p, buf, 128));
> }
> return 0;
> }
>
> Which returns:
>
> family = 10, addr = 2a00:1450:400f:805::1005
> family = 2, addr = 74.125.232.227
> family = 2, addr = 74.125.232.228
> family = 2, addr = 74.125.232.229
> family = 2, addr = 74.125.232.230
> family = 2, addr = 74.125.232.231
> family = 2, addr = 74.125.232.232
> family = 2, addr = 74.125.232.233
> family = 2, addr = 74.125.232.238
> family = 2, addr = 74.125.232.224
> family = 2, addr = 74.125.232.225
> family = 2, addr = 74.125.232.226
>
> Which means that the logic has to be something like (at least on Linux):
>
> * Listen:
> if wildcard
> bind/listen IPv6
> else
> bind/listen to all returned addresses,
> it's OK if some of them fails (then we
> probably don't have that address on any of
> our interfaces)
> * Connect:
> connect to any of the given addresses (to speed
> things up we could try all in parallell and take the
> first that responds).
>
AFAICT this means that all code where only the first result from getaddrinfo is used,
the code should be re-factored along these lines:
int f(char *host,
int (*cb_start)(void *cb_context),
int (*cb_each)(struct addrinfo *a, void *cb_context),
int (*cb_end)(void *cb_context),
void *cb_context)
{
struct addrinfo *addr, *p;
...
ret = getaddrinfo (..., &addr);
if (ret == 0) {
cb_start(context);
for (p = addr; p != NULL; p = p->ai_next) {
cb_each(p, context);
}
cb_end(context);
freeaddrinfo (addr);
}
...
}
Any thoughts?
--
Anders Blomdell Email: anders.blomdell at control.lth.se
Department of Automatic Control
Lund University Phone: +46 46 222 4625
P.O. Box 118 Fax: +46 46 138118
SE-221 00 Lund, Sweden
More information about the Gluster-devel
mailing list