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

Ste*_*e-o 16 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
Run Code Online (Sandbox Code Playgroud)

在Solaris上,您可以使用接口标志指示首选地址,并通过SIOCGLIFCONF以下方式以编程方式提供:

/usr/include/net/if.h:
#define   IFF_PREFERRED   0x0400000000    /* Prefer as source address */
Run Code Online (Sandbox Code Playgroud)

如界面列表中所列:

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 
Run Code Online (Sandbox Code Playgroud)

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

对于Linux,本文详细介绍了如何更改"生命周期" 的参数preferred_lft,以便lft内核对选择过程进行加权.此设置不会出现在结果方便可行的SIOCGIFCONF或者getifaddrs()虽然.

所以我想结合eth0,eri0或任何可用的接口名称.选择有点严峻:

  1. 适配器名称解析为多个接口失败.我采用这种方法来处理多播传输(OpenPGM),因为协议必须只有一个发送地址.
  2. 绑定一切.这是一个警察,对用户来说是意想不到的.
  3. 用适配器绑定到适配器SO_BINDTODEVICE.这需要CAP_NET_RAWLinux上的系统功能,这对管理员来说可能是一个相当麻烦的开销.
  4. 绑定到适配器上的第一个IPv6接口.订购往往是完全虚假的.
  5. 绑定到最后一个界面. David Croft的文章暗示Linux会这样做,但也有点虚伪.
  6. 枚举每个接口并为每个接口明确创建一个新套接字.

使用选项#6,我希望你通常可以更聪明,并采取如果只有链接本地范围地址可用的方法绑定到该方法,否则绑定到可用的全局链接范围地址.

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

  1. 喜欢相同的地址.(即目的地是本地机器)
  2. 喜欢适当的范围.(即与目的地共享的最小范围)
  3. 避免弃用地址.
  4. 喜欢家庭住址.首选外向接口.(即更喜欢我们发送的接口上的地址)
  5. 喜欢匹配的标签.
  6. 喜欢公共地址.
  7. 使用最长匹配前缀.

在某些情况下,我们可以在这里使用#7,但在上面的接口示例中,两个全局范围接口都具有64位前缀长度.

RFC 3484具有以下相关的行:

IPv6寻址体系结构5允许将多个单播
地址分配给接口.这些地址可能具有
不同的可访问性范围(链接本地,站点本地或全局).
这些地址也可能是"首选"或"不赞成" 6.

链接到RFC 2462,类似地扩展:

首选地址 - 分配给接口的地址,上层协议的使用不受限制.优选地址可以用作从(或)接口发送的分组的源(或目的地)地址.

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

转发到Win32 API,公开ioctl SIO_ADDRESS_LIST_SORT,允许开发人员不仅使用RFC 3484排序,还要考虑任何系统管理员覆盖.Linux /etc/gai.conf用于RFC 3484排序,getaddrinfo()但没有用于直接访问排序的API.Solaris有ipaddrsel命令.OSX通过添加ip6addrctl10.7 来跟随FreeBSD .

编辑: 在此额外的IETF草案文档中列出并引用了一些关于RFC 3484排序的问题:

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

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

作者喜欢Solaris的方法,即为每个额外的IPv6接口提供一个新的别名,这样就eri0可以成为链接本地范围地址,eri0:1或者eri0:2必须指定使用全局范围地址等.

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

Ale*_*eys 2

我不确定这是否符合您正在寻找的方向,但是......

在 Linux 下查看 iproute 捆绑包的ip代码 ( ip/ipaddress.c) 显示该命令从, member中ip挖掘接口标志,例如primary和。似乎是通过中记录的获得的,并通过与内核的交互来使用,这总体听起来像是一种巨大的痛苦,但它至少是程序化的。主要和次要是否足以有用是一个单独的问题。secondarystruct ifaddrmsgifa_flagsifaddmsgstruct nlmsghdrman 7 netlinksendmsgrecvmsg