Какова цель флага AI_V4MAPPED в getaddrinfo? - PullRequest
7 голосов
/ 11 сентября 2009

У вызова getaddrinfo много интересных флагов. Мне интересно, какова цель флага AI_V4MAPPED. Ни в одной системе я не могу заставить getaddrinfo создавать адреса формы :: ffff: n.n.n.n, как я ожидал бы, когда установил этот флаг. Я ожидаю что-то не то? Я вижу ошибки?

В частности, если я запрашиваю адреса семейства AF_INET6 и указываю AI_V4MAPPED, я ожидаю увидеть адреса :: ffff: n.n.n.n для хостов, которые имеют только записи DNS A (адрес IPv4). И я также, как правило, ожидаю, что, если я укажу AI_ALL, я получу записи DNS AAAA (IPv6-адреса) хоста и записи DNS A в форме :: ffff: n.n.n.n.

Опять же, я жду здесь всех неправильных вещей?

Я проверял это на Fedora 11 - glibc 2.10.1 и OS X 10.4.

Ответы [ 2 ]

6 голосов
/ 12 сентября 2009

Я получаю именно то, что вы ожидаете получить, в Debian Lenny (glibc 2.7) - с одним исключением - если я укажу AI_V4MAPPED без AI_ALL, а имя хоста, которое я ищу, будет иметь CNAME, указывающие на записи A Я не получаю их обратно. Работает нормально, если также указано AI_ALL или если имя хоста напрямую связано с записями А.

Я не знаю, почему - возможно, это ошибка glibc?

Вот моя тестовая программа:

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>

int main(int argc, char *argv[])
{
    struct addrinfo hints = { 0 };
    struct addrinfo *res, *res_c;
    int err;
    char name[INET6_ADDRSTRLEN];

    if (argc < 2)
    {
        return 1;
    }

    hints.ai_family = AF_INET6;
    hints.ai_flags = AI_V4MAPPED | AI_ALL;

    err = getaddrinfo(argv[1], NULL, &hints, &res);

    if (err)
    {
        printf("getaddrinfo: %s\n", gai_strerror(err));
        return 1;
    }

    for (res_c = res; res_c; res_c = res_c->ai_next)
    {
        const void *addr;
        int port;
        struct protoent *proto;

        switch (res_c->ai_family)
        {
            case AF_INET6:
                addr = &((struct sockaddr_in6 *)(res_c->ai_addr))->sin6_addr;
                port = ((struct sockaddr_in6 *)(res_c->ai_addr))->sin6_port;
                printf("AF_INET6\t");
                break;
            case AF_INET:
                addr = &((struct sockaddr_in *)(res_c->ai_addr))->sin_addr;
                port = ((struct sockaddr_in *)(res_c->ai_addr))->sin_port;
                printf("AF_INET\t");
                break;
            default:
                addr = NULL;
                printf("(%d)\t", res_c->ai_family);
        }

        proto = getprotobynumber(res_c->ai_protocol);
        if (proto)
        {
            printf("%s\t", proto->p_name);
        }
        else
        {
            printf("(%d)\t", res_c->ai_protocol);
        }

        switch (res_c->ai_socktype)
        {
            case SOCK_STREAM:
                printf("SOCK_STREAM\t");
                break;

            case SOCK_DGRAM:
                printf("SOCK_DGRAM\t");
                break;

            default:
                printf("(?socktype?)\t");
                break;
        }

        if (addr && inet_ntop(res_c->ai_family, addr, name, sizeof name))
            printf("addr = %s", name);

        if (addr)
            printf(",%d", port);

        printf("\n");
    }

    return 0;
}
4 голосов
/ 27 сентября 2011

По моему опыту, AI_V4MAPPED не работает на Mac OS X 10.6. Если вы укажете hints.ai_family = AF_INET6 и hints.ai_flags = AI_V4MAPPED, он всегда вернет EAI_NONAME, а gai_strerror() выведет «имя узла или имя предоставлено или не известно».

На OS X 10.7 работает нормально.

Размещение этого сообщения на случай, если это кому-то поможет, даже если вы используете Fedora.

...