2009-09-10 19 views
6

Wywołanie getaddrinfo ma wiele interesujących flag. Zastanawiam się, jaki jest cel flagi AI_V4MAPPED. W żadnym systemie nie wydaje mi się, żebym mógł uzyskać getaddrinfo, aby utworzyć :: ffff: n.n.n.n.nformować adresy tak, jak oczekiwałbym po ustawieniu tej flagi. Czy oczekuję niewłaściwej rzeczy? Czy widzę błędy?Jaki jest cel flagi AI_V4MAPPED w getaddrinfo?

W szczególności, gdy pytam o adresy rodziny AF_INET6 i określam AI_V4MAPPED, spodziewam się zobaczyć: :: ffff: n.n.n.n adresy hostów, które mają tylko rekordy DNS A (adres IPv4). I generalnie spodziewam się, że jeśli podam AI_ALL, otrzymam zarówno rekord adresu DNS AAAA (adres IPv6) hosta, jak i rekordy DNS A w formularzu :: ffff: n.n.n.n.

Ponownie, czy oczekuję tutaj wszystkich złych rzeczy?

Przetestowałem to na Fedorze 11 - glibc 2.10.1 i OS X 10.4.

Odpowiedz

6

dostać dokładnie to, czego spodziewa się dostać na Debian Lenny (glibc 2.7) - z jednym wyjątkiem - jeśli mogę określić AI_V4MAPPED bez AI_ALL i hosta Patrzę został rekordy CNAME, wskazując na rekordy A, I don” t dostań tych, którzy wrócili. Działa to dobrze, jeśli podano również AI_ALL lub jeśli nazwa hosta jest bezpośrednio powiązana z rekordami A.

Nie wiem dlaczego - może to błąd w glibc?

Oto mój program testowy:

#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

Zrobiłem o wiele więcej badań na ten temat. getaddrinfo wydaje się być nękany przez dowolną liczbę błędów, częściowo dlatego, że ma wiele dziwnych przypadków, aby poradzić sobie ze zepsutą obsługą żądań AAAA. – Omnifarious

+0

Twoja odpowiedź jest najbliższa prawdziwej odpowiedzi, więc otrzymujesz kredyt na odpowiedź. – Omnifarious

+0

AI_V4MAPPED bez AI_ALL jest błędem glibc, patrz http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=503912 – unixman83

4

Z mojego doświadczenia wynika, AI_V4MAPPED nie działa na Mac OS X 10.6. Jeśli podasz hints.ai_family = AF_INET6 i hints.ai_flags = AI_V4MAPPED, zawsze zwróci on EAI_NONAME i gai_strerror() drukuje "nodename lub servname provided, lub not known".

Działa poprawnie na OS X 10.7.

Umieszczanie tego tutaj na wypadek, gdyby pomogło komuś, nawet jeśli jesteś w Fedorze.