2013-11-27 1 views
4

resolveip 유틸리티의 기본 기능 모방 다음 코드, 가정 주소 :한다 getaddrinfo (3) 지정 hints->의 IPv6를 반환하지 않습니다 ai_socktype를이

#define _POSIX_SOURCE  /* getaddrinfo() */ 
#include <sys/types.h> /* getaddrinfo(), struct addrinfo, struct sockaddr */ 
#include <sys/socket.h> /* getaddrinfo(), struct addrinfo, struct sockaddr, AF_* */ 
#include <netdb.h>  /* getaddrinfo(), struct addrinfo, struct sockaddr */ 
#include <arpa/inet.h> /* inet_ntop() */ 
#include <stdio.h>  /* fprintf(), printf(), perror(), stderr */ 
#include <stdlib.h>  /* EXIT_SUCCESS */ 

int main(int argc, char** argv) { 
    for(int i = 1; i < argc; ++i) { /* For each hostname */ 

    char* hostname = argv[i];  
    struct addrinfo* res; /* We retrieve the addresses */ 
    if(getaddrinfo(hostname, NULL, NULL, &res) == -1) { 
     perror("getaddrinfo"); 
     continue; 
    } 

    for(; res->ai_next; res = res->ai_next) { /* We print the addresses */ 
     switch(res->ai_addr->sa_family) { 
     case AF_INET: { 
      struct in_addr addr = ((struct sockaddr_in*)(res->ai_addr))->sin_addr; 
      char buffer[17]; printf("%s: %s\n", hostname, inet_ntop(AF_INET, &addr, buffer, 17)); break; 
     } case AF_INET6: { 
      struct in6_addr addr = ((struct sockaddr_in6*)(res->ai_addr))->sin6_addr; 
      char buffer[40]; printf("%s: %s\n", hostname, inet_ntop(AF_INET6, &addr, buffer, 40)); break; 
     } default: { 
      fprintf(stderr, "%s: Unknown address family\n", hostname); 
     } 
     } 
    } 

    freeaddrinfo(res); /* We release the allocated resources */ 

    } return EXIT_SUCCESS; 
} 

위의 코드를 첫 번째로 google.com 호출을 인수 만이 다음과 비슷한 것을 출력합니다 :

google.com: 173.194.35.87 
google.com: 173.194.35.87 
google.com: 173.194.35.87 
google.com: 173.194.35.95 
google.com: 173.194.35.95 
google.com: 173.194.35.95 
google.com: 173.194.35.88 
google.com: 173.194.35.88 
google.com: 173.194.35.88 
google.com: 2a00:1450:4008:800::101f 
google.com: 2a00:1450:4008:800::101f 

중복 항목을 제거하려고한다고 가정합니다. 따라서 우리가 검색하고자하는 결과의 종류에 대한 힌트가 포함 된 구조를 만들자.

struct addrinfo hints = { 
    .ai_family = AF_UNSPEC, 
    .ai_socktype = 0, 
    .ai_protocol = 0, 
    .ai_flags = (AI_V4MAPPED | AI_ADDRCONFIG) 
}; if(getaddrinfo(hostname, NULL, &hints, &res) == -1) { 
    perror("getaddrinfo"); 
    continue; 
} 

것은 지금 우리를 보자 임의에 ai_socktype 필드를 지정하여 중복 항목을 필터링 : 구조가 getaddrinfo(3) 맨에 의해 명령으로 기본값으로 초기화되기 때문에 다음 수정, 어떤 방법으로 출력에 영향을주지 않습니다 값 :

google.com: 173.194.35.87 
google.com: 173.194.35.95 
google.com: 173.194.35.88 

이제 브 우리를 보자

struct addrinfo hints = { 
    .ai_family = AF_UNSPEC, 
    .ai_socktype = SOCK_DGRAM, 
    .ai_protocol = 0, 
    .ai_flags = (AI_V4MAPPED | AI_ADDRCONFIG) 
}; 

아아, 우리는 이제 IPv6 주소를 잃었다 원래의 힌트가없는 버전으로 RT :

if(getaddrinfo(hostname, NULL, NULL, &res) == -1) { 
    perror("getaddrinfo"); 
    continue; 
} 

그리고 우리가 지금하는 대신 수동 필터링을 사용하자가 :

google.com: 173.194.35.87 
google.com: 173.194.35.95 
google.com: 173.194.35.88 
google.com: 2a00:1450:4008:801::101f 
:

for(; res->ai_next; res = res->ai_next) { 
    if(res->ai_socktype != SOCK_DGRAM) continue; 
    ... 
} 

이제 모든 방식으로 작동 그것은 가정된다

getaddrinfo(3) 함수에 대한 힌트와 반환 된 레코드의 수동 필터링 사이의 불일치가 어디에서 발생하는지 궁금합니다. glibc 2.17을 사용하여 Linux 커널 3.8.0-32에서 테스트되었습니다.

+0

당신이 컴퓨터에 구성된 IPv6 주소를 가지고 있습니까 할 필요가? | AI_ADDRCONFIG에서 IPv6를 반환하지 않습니다 사용 .ai_socktype = 0 , .ai_protocol = 0, .ai_flags = (AI_V4MAPPED { .ai_family = AF_UNSPEC'에 대한 힌트를 설정하기 때문에 당신은 내가, 할 생각하지 – nos

+0

할 경우 주소 AI_ADDRCONFIG) }'IPv6 주소를 반환합니다. 'ai_socktype'을'0' 이외의 값으로 설정하면 결과에서 사라집니다. – Witiko

답변

4

for 루프 검사가 잘못되었으므로 항상 마지막 항목을 건너 뛰고 있습니다. 귀하의 경우에는 IPv6 주소가됩니다.

for(; res->ai_next; res = res->ai_next) { 

for(; res; res = res->ai_next) { 
+0

+ 탈출을위한 +1, IPv6에 대한 확실하지. –

+0

+1입니다. 원래의 결과에서 주소 당 3 개의 결과가 있음을 주목하십시오 (끝에 'SOCK_STREAM','SOCK_DGRAM', 그리고 일부 세번째 프로토콜, 아마도'SOCK_RAW'). 그곳에 2 개의 결과가 있습니다. –

+0

+1 진정으로 간과하기 쉬운 것들 중 가장 간단한 것입니다. 나는 지금 질문을 게시하는 것에 거의 바보가된다. – Witiko