2009-09-10 4 views
6

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

В частности, если я запрашиваю адреса семейства 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.

ответ

6

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

Я не знаю, почему - возможно, это ошибка 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; 
} 
+1

Я делал гораздо больше исследований по этому вопросу. Кажется, что getaddrinfo страдает от какого-либо количества ошибок, отчасти потому, что у него много странных случаев, чтобы обойти отмененную обработку запросов AAAA. – Omnifarious

+0

Вы отвечаете, ближайший к реальному ответу, так что вы получаете ответ на кредит. – Omnifarious

+0

AI_V4MAPPED без AI_ALL - ошибка glibc, см. Http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=503912 – unixman83

4

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

Хорошо работает на OS X 10.7.

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