根据输入字符串查找匹配的IPv6地址

问题描述:

我需要一些帮助,根据提供的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

您的代码看起来是正确的 - 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