【问题标题】:How to get scope of an IPv6 host?如何获取 IPv6 主机的范围?
【发布时间】:2026-01-08 05:30:01
【问题描述】:

我对 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 使用系统调用,然后解析输出以提取相应的地址。但问题是,我正在使用对 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 */
       };

问题是:如何从此列表中获取具有“链接”范围的地址?

【问题讨论】:

  • 为什么票数接近?解释会很好。
  • @EBGreen 因为问题是询问如何编写例程以提取接口细节。这在 * 上是最好的,因此最接近的投票是将问题迁移到可以更好地回答它的网站。
  • @Manish,您无需对此做任何事情,如果合适,迁移将自动发生,您可以继续在那里处理您的问题。
  • 为我工作。我只是认为,如果用户在接近投票的同时获得一些评论,它会帮助用户,尤其是新用户。
  • @Manish,接受正确答案(单击勾号)或评论为什么没有帮助是有礼貌的。如果您不这样做,您可能会发现将来没有人会回答您的问题!

标签: linux bash ip-address ipv6


【解决方案1】:

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

【讨论】:

    【解决方案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");
    }
    

    【讨论】:

      【解决方案3】:

      一种方法是检查地址是否在fe80::/10 范围内。 IPv6 address space 可从 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)是范围。使用 net-tools 代码中的上述常量,您可以了解它们的含义。需要进一步调查以确定此类常量的更权威来源,以及解析 /proc/net/if_inet6 是否是您的最佳选择。

      【讨论】:

      • 非常感谢杰里米,这真的帮助我理解了很多。正如你所说,我只是检查了地址是否在指定的范围内,即fe80::/10,这对我有用。
      • 不用担心。有时最简单的解决方案是最好的!
      • 谁投了反对票,请解释一下。我愿意编辑我的答案以改进它(或相应地自己编辑)。
      最近更新 更多