我对IPv6协议不太了解,如果这个问题听起来很愚蠢,我很抱歉。当我检索网络中所有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的系统调用,然后解析输出以提取相应的地址。但问题是,我正在使用对getifadrs()的调用,它返回一个结构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 */
};
问题是:如何从这个列表中获取具有"链接"范围的地址?
有一些辅助宏可以提供帮助:
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");
}
执行此操作的一种方法是简单地检查地址是否位于fe80::/10
内。IPv6地址空间可从IANA获得,IANA详细说明了可用的可能作用域。
我将源代码下载到nettools(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 %20sn",
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
全局、0x20
链接本地和0x10
环回)是作用域。使用网络工具代码中的上述常量,您可以计算出它们的含义。需要进行进一步的调查,以确定此类常量的更权威的来源,以及解析/proc/net/if_inet6
是否是您的最佳选择。
我不认为作用域显式存储在该数据结构中。但是,您可以从IP地址本身推断作用域。看见http://en.wikipedia.org/wiki/IPv6_address#Address_scopes