如何获得IPv6主机的范围?

我对IPv6协议没有多less了解,所以如果这个问题听起来很愚蠢,那么很抱歉。 当我检索我的networking中的所有IPv6地址列表时,我会得到一个名为scope的字段,如下所示:

inet6 addr: 2001:470:1:82::11/64 Scope:Global inet6 addr: 2001:470:1:82::10/64 Scope:Global inet6 addr: 2001:470:1:82::13/64 Scope:Global inet6 addr: fe80::21d:9ff:fe69:2c50/64 Scope:Link inet6 addr: 2001:470:1:82::12/64 Scope:Global inet6 addr: 2001:470:1:82::15/64 Scope:Global inet6 addr: 2001:470:1:82::14/64 Scope:Global inet6 addr: 2001:470:1:82::5/64 Scope:Global inet6 addr: 2001:470:1:82::17/64 Scope:Global inet6 addr: 2001:470:1:82::6/64 Scope:Global inet6 addr: 2001:470:1:82::16/64 Scope:Global inet6 addr: 2001:470:1:82::7/64 Scope:Global inet6 addr: 2001:470:1:82::19/64 Scope:Global inet6 addr: 2001:470:1:82::8/64 Scope:Global inet6 addr: 2001:470:1:82::18/64 Scope:Global inet6 addr: 2001:470:1:82::9/64 Scope:Global inet6 addr: 2001:470:1:82::1b/64 Scope:Global inet6 addr: 2001:470:1:82::a/64 Scope:Global inet6 addr: 2001:470:1:82::1a/64 Scope:Global inet6 addr: 2001:470:1:82::b/64 Scope:Global inet6 addr: 2001:470:1:82::1d/64 Scope:Global inet6 addr: 2001:470:1:82::c/64 Scope:Global inet6 addr: 2001:470:1:82::1c/64 Scope:Global inet6 addr: 2001:470:1:82::d/64 Scope:Global inet6 addr: 2001:470:1:82::1f/64 Scope:Global inet6 addr: 2001:470:1:82::e/64 Scope:Global inet6 addr: 2001:470:1:82::1e/64 Scope:Global inet6 addr: 2001:470:1:82::f/64 Scope:Global inet6 addr: ::1/128 Scope:Host 

在我的应用程序中,我需要获取范围为“链接”的地址。 我可以使用系统调用ifconfig,然后parsing输出提取相应的地址。 但问题是,我正在使用对getifaddrs()的调用,它返回一个结构ifaddr的链表,如下所示:

  struct ifaddrs { struct ifaddrs *ifa_next; /* Next item in list */ char *ifa_name; /* Name of interface */ unsigned int ifa_flags; /* Flags from SIOCGIFFLAGS */ struct sockaddr *ifa_addr; /* Address of interface */ struct sockaddr *ifa_netmask; /* Netmask of interface */ union { struct sockaddr *ifu_broadaddr; /* Broadcast address of interface */ struct sockaddr *ifu_dstaddr; /* Point-to-point destination address */ } ifa_ifu; #define ifa_broadaddr ifa_ifu.ifu_broadaddr #define ifa_dstaddr ifa_ifu.ifu_dstaddr void *ifa_data; /* Address-specific data */ }; 

问题是:如何从这个列表中获得“链接”范围的地址?

Solutions Collecting From Web of "如何获得IPv6主机的范围?"

其中一种方法就是检查地址是否在fe80::/10 。 IPv6地址空间可从IANA获得,详细说明可能的范围。

我将源代码下载到了net-tools (ifconfig的源码包),看起来他们解析/proc/net/if_inet6 。 (在下面的代码中,注释是我自己的补充 – 下面的代码也是非常简洁的,绝对不会编译)。

 /* some defines collected around the place: */ #define _PATH_PROCNET_IFINET6 "/proc/net/if_inet6" #define IPV6_ADDR_LOOPBACK 0x0010U #define IPV6_ADDR_LINKLOCAL 0x0020U #define IPV6_ADDR_SITELOCAL 0x0040U #define IPV6_ADDR_COMPATv4 0x0080U int scope; /* among other stuff */ /* looks like here we parse the contents of /proc/net/if_inet6: */ if ((f = fopen(_PATH_PROCNET_IFINET6, "r")) != NULL) { while (fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n", addr6p[0], addr6p[1], addr6p[2], addr6p[3], addr6p[4], addr6p[5], addr6p[6], addr6p[7], &if_idx, &plen, &scope, &dad_status, devname) != EOF) { /* slightly later: */ printf(_(" Scope:")); switch (scope) { case 0: printf(_("Global")); break; case IPV6_ADDR_LINKLOCAL: printf(_("Link")); break; case IPV6_ADDR_SITELOCAL: printf(_("Site")); break; case IPV6_ADDR_COMPATv4: printf(_("Compat")); break; case IPV6_ADDR_LOOPBACK: printf(_("Host")); break; default: printf(_("Unknown")); } 

那么让我们来看看上面的解析:

 $ cat /proc/net/if_inet6 20010db8000008000000000000000001 03 40 00 00 eth0 fe800000000000000000000000004321 03 40 20 80 eth0 00000000000000000000000000000001 01 80 10 80 lo 

所以你可以看到左边第三列( 0x00 Global, 0x20 Link-Local和0x10 Loopback)是范围。 使用网络工具代码中的上述常量,可以计算出它们的含义。 进一步的调查将需要确定一个更权威的来源这样的常量,也是否解析/proc/net/if_inet6是你最好的选择。

有帮助宏来协助:

 struct sockaddr_in6 s6; if (IN6_IS_ADDR_LINKLOCAL(&s6.sin6_addr)) { puts ("link-local"); } else if (IN6_IS_ADDR_SITELOCAL(&s6.sin6_addr)) { puts ("site-local"); } else if (IN6_IS_ADDR_V4MAPPED(&s6.sin6_addr)) { puts ("v4mapped"); } else if (IN6_IS_ADDR_V4COMPAT(&s6.sin6_addr)) { puts ("v4compat"); } else if (IN6_IS_ADDR_LOOPBACK(&s6.sin6_addr)) { puts ("host"); } else if (IN6_IS_ADDR_UNSPECIFIED(&s6.sin6_addr)) { puts ("unspecified"); } else { puts ("global"); } 

我不认为范围被明确地存储在那个数据结构中。 但是,您可以从IP地址本身推断范围。 请参阅http://en.wikipedia.org/wiki/IPv6_address#Address_scopes