标识适配器的首选IPv6源地址

时间:2011-08-26 08:59:17

标签: linux macos solaris ipv6

如果您的IPv6主机具有多个全局范围的地址,那么如何以编程方式识别bind()的首选地址?

示例地址列表:

eth0      Link encap:Ethernet  HWaddr 00:14:5e:bd:6d:da  
          inet addr:10.6.28.31  Bcast:10.6.28.255  Mask:255.255.255.0
          inet6 addr: 2002:dce8:d28e:0:214:5eff:febd:6dda/64 Scope:Global
          inet6 addr: fe80::214:5eff:febd:6dda/64 Scope:Link
          inet6 addr: 2002:dce8:d28e::31/64 Scope:Global
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1

在Solaris上,您可以指定带有接口标志的首选地址,并通过SIOCGLIFCONF以编程方式提供:

/usr/include/net/if.h:
#define   IFF_PREFERRED   0x0400000000    /* Prefer as source address */

如界面列表中所列:

eri0: flags=2104841<UP,RUNNING,MULTICAST,DHCP,ROUTER,IPv6> mtu 1500 index 2
        inet6 fe80::203:baff:fe4e:6cc8/10 
eri0:1: flags=402100841<UP,RUNNING,MULTICAST,ROUTER,IPv6,PREFERRED> mtu 1500 index 2
        inet6 2002:dce8:d28e::36/64 

但这不适用于OSX,Linux,FreeBSD或Windows。从管理员的角度看,基于UUID的适配器名称(取决于Windows版本)完全没用Windows,因此Windows很容易发布。

对于Linux this article,详细说明了如何更改参数preferred_lft,其中lft是“生命周期”的缩写,可以通过内核对选择过程进行加权。尽管如此,SIOCGIFCONFgetifaddrs()的结果中也无法方便地使用此设置。

所以我想绑定到eth0eri0或任何可用的接口名称。选择有点严峻:

  1. 解析为多个接口的适配器名称失败。我采用这种方法来处理多播传输(OpenPGM),因为协议必须只有一个发送地址。
  2. 绑定一切。这是一个警察,对用户来说是意料之外的。
  3. 使用SO_BINDTODEVICE绑定到适配器。这需要Linux上的CAP_NET_RAW系统功能,这对管理员来说可能是一个非常麻烦的开销。
  4. 绑定到适配器上的第一个IPv6接口。订购往往是完全虚假的。
  5. 绑定到最后一个界面。 David Croft的文章暗示Linux会这样做,但也有点虚假。
  6. 枚举每个接口并为每个接口明确创建一个新套接字。
  7. 使用选项#6,我希望你通常可以更聪明,并采取这种方法,如果只有一个链接本地范围地址可用绑定到那个,否则只绑定到可用的全局链接范围地址。

    当连接到另一台主机时,可以使用RFC 3484,但正如您所看到的,所有选择都取决于匹配目标地址:

    1. 喜欢相同的地址。 (即目的地是本地机器)
    2. 喜欢适当的范围。 (即与目的地共享的最小范围)
    3. 避免弃用地址。
    4. 首选家庭住址。更喜欢外出 接口。 (即更喜欢我们发送的接口上的地址 出来的)
    5. 喜欢匹配标签。
    6. 首选公共地址。
    7. 使用最长匹配前缀。
    8. 在某些情况下,我们可以在这里使用#7,但在上面的接口示例中,两个全局范围接口都具有64位前缀长度。

      RFC 3484有以下相关内容:

        

      IPv6寻址架构5允许多个单播
        要分配给接口的地址。这些地址可能有   不同的可达性范围(链接本地,站点本地或全局)   这些地址也可能是“首选”或“已弃用”6

      指向RFC 2462的链接,类似地展开了:

        

      首选地址 - 分配给使用的接口的地址   通过           上层协议不受限制。优选地址可以           用作发送数据包的源(或目标)地址           从(或到)界面。

      但没有方法以编程方式获取此细节。

      Props to Win32 API,它公开了一个ioctl SIO_ADDRESS_LIST_SORT,它允许开发人员不仅使用RFC 3484排序,还要考虑任何系统管理员覆盖。 Linux有/etc/gai.conf用于getaddrinfo()中的RFC 3484排序,但没有用于直接访问排序的API。 Solaris具有ipaddrsel命令。 OSX通过在10.7中添加ip6addrctl来关注FreeBSD。

      编辑:在此额外的IETF草案文档中列出并引用了对RFC 3484排序的一些担忧:

      http://tools.ietf.org/html/draft-axu-addr-sel-01

        例如,Solaris为每个新的用户创建了新的别名接口   分配给物理接口的地址。所以if_index也可以是   用于唯一标识上的源地址特定路由表   那个平台。其他操作系统的工作方式不同。

      作者喜欢Solaris为每个额外的IPv6接口提供新别名的方法,因此eri0将成为链接本地范围地址,eri0:1eri0:2等必须被指定使用全局范围的地址。

      显然,虽然一个不错的想法,人们不能指望在相当长的一段时间内看到其他操作系统的改变。

1 个答案:

答案 0 :(得分:2)

我不确定这是你想要的方向,但是......

在linux下的iproute bundle的ip代码(ip/ipaddress.c)中查看,显示ip命令可以从primarysecondary中挖掘出struct ifaddrmsgifa_flags之类的界面标记ifaddmsg,成员struct nlmsghdrman 7 netlink似乎是通过sendmsg中获得的recvmsg获得的,并通过{{1}}和{{1}}与内核交互使用,整体听起来像皇室的痛苦,但它至少是程序化的。小学和中学是否足够有用是一个单独的问题。