如何获得IPv6主机的范围是什么?(How to get scope of an IPv6 host

2019-06-26 12:08发布

我没有关于IPv6协议的很多知识,很抱歉,如果这个问题听起来很愚蠢。 当我找回我的网络中的所有IPv6地址的列表中,我得到一个字段中指定范围,如下图所示:

      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和再分析的输出来提取相应的地址。 但问题是,我使用给出调用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 */
       };

现在的问题是:如何从这份名单得到与“链接”范围的地址?

Answer 1:

这样做的一个方法是简单地检查该地址是否落入fe80::/10 。 在IPv6的地址空间可从IANA,其中详细介绍了可以在可能范围。

我下载的源代码,以净工具 (源包的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全球, 0x20链路本地和0x10环回)为范围。 从网上的工具代码中使用上述参数,你可以锻炼他们的意思。 进一步的调查将需要确定一个更权威的来源,这样的常量和解析也不管/proc/net/if_inet6是您最佳的选择。



Answer 2:

有辅助宏来帮助:

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");
}


Answer 3:

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



文章来源: How to get scope of an IPv6 host?