如果您的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
是“生命周期”的缩写,可以通过内核对选择过程进行加权。尽管如此,SIOCGIFCONF
或getifaddrs()
的结果中也无法方便地使用此设置。
所以我想绑定到eth0
,eri0
或任何可用的接口名称。选择有点严峻:
SO_BINDTODEVICE
绑定到适配器。这需要Linux上的CAP_NET_RAW
系统功能,这对管理员来说可能是一个非常麻烦的开销。使用选项#6,我希望你通常可以更聪明,并采取这种方法,如果只有一个链接本地范围地址可用绑定到那个,否则只绑定到可用的全局链接范围地址。
当连接到另一台主机时,可以使用RFC 3484,但正如您所看到的,所有选择都取决于匹配目标地址:
在某些情况下,我们可以在这里使用#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:1
或eri0:2
等必须被指定使用全局范围的地址。
显然,虽然一个不错的想法,人们不能指望在相当长的一段时间内看到其他操作系统的改变。
答案 0 :(得分:2)
我不确定这是你想要的方向,但是......
在linux下的iproute bundle的ip
代码(ip/ipaddress.c
)中查看,显示ip
命令可以从primary
和secondary
中挖掘出struct ifaddrmsg
和ifa_flags
之类的界面标记ifaddmsg
,成员struct nlmsghdr
。 man 7 netlink
似乎是通过sendmsg
中获得的recvmsg
获得的,并通过{{1}}和{{1}}与内核交互使用,整体听起来像皇室的痛苦,但它至少是程序化的。小学和中学是否足够有用是一个单独的问题。