2010-10-02 69 views
1

我需要一些幫助,根據提供的IP地址找到網絡接口。我需要一種跨平臺的方式來可靠地查找具有IPv4和IPv6格式的給定地址的本地接口 。我在 創建了附加的程序以IP地址作爲字符串,並且 搜索​​的結果。根據輸入字符串查找匹配的IPv6地址

的原因是,我最終想通過本in_addrin6_addr結構到IP_MULTICAST_IF IOCTL爲 指定哪些接口應該被用來發送多播消息的插座上。 我想在繼續之前檢查它是否是已知的IP。

雖然它似乎可以在我的Linux機器和MacBook上正常工作,但是我的實驗室服務器上的 失敗。 (噢,我的,這最終有對 Windows上工作過。)下面是在Linux上運行的例子:

$ ifconfig wlan0 | grep inet6 
      inet6 addr: fe80::1e4b:d6ff:fe6e:f846/64 Scope:Link 

$ ifconfig wlan0 | grep inet 
      inet addr:192.168.0.13 Bcast:192.168.0.255 Mask:255.255.255.0 
      inet6 addr: fe80::1e4b:d6ff:fe6e:f846/64 Scope:Link 

$ ./findif 192.168.0.13 

found: wlan0 

$ ./findif fe80::1e4b:d6ff:fe6e:f846 

name: lo 
ifa:  00000000000000000000000000000001 
provided: fe800000000000001e4bd6fffe6ef846 

name: wlan0 
ifa:  fe800000000000001e4bd6fffe6ef846 
provided: fe800000000000001e4bd6fffe6ef846 

found: wlan0 

到目前爲止好。在運行OS X 10.6的MacBook上,我得到了類似的結果。 然而,當我做同樣的事情在我們的服務器,這是一個老 基於PPC-OS X 10.4.11運行的機器上,我得到如下:

$ ifconfig en0 | grep inet 
    inet6 fe80::20d:XXXX:XXXX:XXXX%en0 prefixlen 64 scopeid 0x4 
    inet 132.XXX.XX.XX netmask 0xffffff00 broadcast 132.XXX.XX.255 

$ ./findif 132.XXX.XX.XX 

found: en0 

$ ./findif fe80::XXX:XXXX:XXXX:XXXX 

name: lo0 
ifa:  00000000000000000000000000000001 
provided: fe800000000000000XXXXXXXXXXXXXXX 

name: lo0 
ifa:  fe800001000000000000000000000001 
provided: fe800000000000000XXXXXXXXXXXXXXX 

name: en0 
ifa:  fe800004000000000XXXXXXXXXXXXXXX 
provided: fe800000000000000XXXXXXXXXXXXXXX 

name: en1 
ifa:  fe800005000000000YYYYYYYYYYYYYYY 
provided: fe800000000000000YYYYYYYYYYYYYYY 

道歉X'ing一些地址數字,我認爲這是最好的 不暴露真實的IP在這裏的活服務器。請放心, 無論你在哪裏看到XY這是一個匹配的十六進制數字。

無論如何,請注意,針對en0返回的IPv6恰好有1位, 與ifconfig報告的位不同。任何人都可以告訴我爲什麼這個 是,以及我應該如何調整我的代碼?是簡單的memcmp而不是 正確的方式來比較IPv6地址?

感謝您的任何建議。

這裏是findif.c代碼:

#include <stdio.h> 
#include <stdlib.h> 
#include <arpa/inet.h> 
#include <ifaddrs.h> 
#include <netdb.h> 
#include <string.h> 

void printipv6(const void* ipv6) 
{ 
    int i; 
    for (i=0; i<16; i++) 
     printf("%02x", ((unsigned char*)ipv6)[i]); 
} 

int find_iface(const char *ip) 
{ 
    union { 
     struct in_addr addr; 
     struct in6_addr addr6; 
    } a; 

    int rc = inet_pton(AF_INET6, ip, &a.addr6); 
int fam = AF_INET6; 
    if (rc==0) { 
     rc = inet_pton(AF_INET, ip, &a.addr); 
    fam = AF_INET; 
} 
    if (rc < 0) { 
     perror("inet_pton"); 
     return 1; 
    } 

    struct ifaddrs *ifa, *ifa_list; 
    if (getifaddrs(&ifa_list)==-1) { 
     perror("getifaddrs"); 
     return 1; 
    } 
    ifa = ifa_list; 

    int i=0; 
    while (ifa) { 
     if (ifa->ifa_addr) { 
      if (ifa->ifa_addr->sa_family == AF_INET && fam == AF_INET) 
      { 
       if (memcmp(&((struct sockaddr_in*)ifa->ifa_addr)->sin_addr, 
          &a.addr, sizeof(struct in_addr))==0) { 
        printf("\nfound: %s\n", ifa->ifa_name); 
        break; 
       } 
      } 
      else if (ifa->ifa_addr->sa_family == AF_INET6 && fam == AF_INET6) 
      { 
       struct in6_addr *p = &((struct sockaddr_in6*)ifa->ifa_addr)->sin6_addr; 
       printf("\nname: %s\n", ifa->ifa_name); 
       printf("ifa:  "); printipv6(p);  printf("\n"); 
       printf("provided: "); printipv6(&a.addr6); printf("\n"); 
       if (memcmp(p, &a.addr6, sizeof(struct in6_addr))==0) { 
        printf("\nfound: %s\n", ifa->ifa_name); 
        break; 
       } 
      } 
     } 
     ifa = ifa->ifa_next; 
     i++; 
    } 
    freeifaddrs(ifa_list); 
    return 0; 
} 

int main(int argc, char *argv[]) 
{ 
    if (argc > 1) 
     return find_iface(argv[1]); 
    return 0; 
} 
+1

哈哈哈 - 你掩蓋了*鏈接本地*地址,無論如何都不能從互聯網公開尋址。 – 2010-10-03 02:48:37

+0

哎呀,謝謝你指出。顯然還在學習IPv6。 – Steve 2010-10-03 17:18:55

+0

那麼,鏈接本地地址包括MAC,所以它是一個唯一的標識符,如果你擔心這種事情。 – caf 2010-10-04 01:44:54

回答

1

您的代碼看起來是正確的 - IPv6鏈路本地地址都應該有以下前10位的54個零位,所以通過getifaddrs()返回的地址只是似乎錯誤。看起來這個版本的OS X可能會錯誤地將作用域ID轉移到地址中。

+0

您是否認爲特意不比較那些54個零位是正確的呢?還是說離開它並說操作系統被破壞會更好? (我會嘗試在更新版本的OS X上進行更多的測試,以驗證它至少是可靠的。) – Steve 2010-10-03 17:19:57

+0

@Steve:如果你這樣做,我只會在特定版本的OS X上做這個工作, 。或者,您可以指定OS X的最低支持版本。 – caf 2010-10-04 01:45:41

相關問題