linux - 确定适配器的首选 IPv6 源地址

标签 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 上,您可以使用接口(interface)标志指示首选地址,并且可以通过 SIOCGLIFCONF 以编程方式使用该地址。 :
/usr/include/net/if.h:
#define   IFF_PREFERRED   0x0400000000    /* Prefer as source address */
如接口(interface)列表中所列:
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 很容易被放弃。
对于 Linux this article详细说明如何参数preferred_lft , 其中 lft是“lifetime”的缩写,可以更改为内核对选择过程的权重。此设置在 SIOCGIFCONF 的结果中似乎不方便使用或 getifaddrs()尽管。
所以我想绑定(bind)到eth0 , eri0 ,或任何可用的接口(interface)名称。选择有点明显:
  • 解析为多个接口(interface)的适配器名称失败。我采用这种方法来处理多播传输( OpenPGM ),因为协议(protocol)必须只有一个发送地址。
  • 绑定(bind)一切。这是一种逃避,对用户来说是意料之外的。
  • 使用 SO_BINDTODEVICE 绑定(bind)到适配器.这需要 CAP_NET_RAW Linux 上的系统功能,这对于管理员来说可能是相当麻烦的开销。
  • 绑定(bind)到适配器上的第一个 IPv6 接口(interface)。订购往往是完全虚假的。
  • 绑定(bind)到最后一个接口(interface)。 David Croft的文章暗示 Linux 会这样做,但也有点虚假。
  • 枚举每个接口(interface)并为每个接口(interface)显式创建一个新套接字。

  • 使用选项 #6,我希望您通常可以更聪明,并采取这种方法,如果只有链接本地范围地址可用,则绑定(bind)到该地址,否则仅绑定(bind)到可用的全局链接范围地址。
    当连接到另一台主机时 RFC 3484可以使用,但如您所见,所有选择都取决于匹配目标地址:
  • 最好是同一个地址。 (即目的地是本地机器)
  • 优先选择合适的范围。 (即与目的地共享的最小范围)
  • 避免弃用地址。
  • 首选家庭住址。喜欢外向
    界面。 (即更喜欢我们发送的接口(interface)上的地址
    出)
  • 首选匹配标签。
  • 首选公共(public)地址。
  • 使用最长匹配前缀。

  • 在某些情况下,我们可以在这里使用 #7,但在上面的接口(interface)示例中,两个全局范围接口(interface)都有 64 位前缀长度。
    RFC 3484有以下相关行:

    The IPv6 addressing architecture 5 allows multiple unicast
    addresses to be assigned to interfaces. These addresses may have
    different reachability scopes (link-local, site-local, or global).
    These addresses may also be "preferred" or "deprecated" 6.


    链接指向 RFC 2462 ,同样展开:

    preferred address - an address assigned to an interface whose use by upper layer protocols is unrestricted. Preferred addresses may be used as the source (or destination) address of packets sent from (or to) the interface.


    但是没有方法以编程方式获取此详细信息。
    公开 ioctl 的 Win32 API 的 Prop SIO_ADDRESS_LIST_SORT这使开发人员不仅可以使用 RFC 3484 排序,还可以考虑任何系统管理员覆盖。 Linux 有 /etc/gai.conf用于 getaddrinfo() 中的 RFC 3484 排序但没有用于直接访问排序的 API。 Solaris 有 ipaddrsel命令。 OSX 通过添加 ip6addrctl 来跟随 FreeBSD在 10.7。
    编辑:此附加 IETF 草案文档中列出并引用了与 RFC 3484 排序有关的一些问题:
    https://datatracker.ietf.org/doc/html/draft-axu-addr-sel-01

    Solaris, for example, creates new alias-interfaces for each new
    address assigned to a physical interface. So if_index could also be
    used to uniquely identify a source address specific routing table on
    that platform. Other operating systems do not work the same way.


    作者喜欢 Solaris 为每个额外的 IPv6 接口(interface)提供一个新别名的方法,以便 eri0将成为链接本地作用域地址,而 eri0:1eri0:2等,必须指定使用全局范围的地址。
    显然,虽然这是一个好主意,但在很长一段时间内都无法期望看到其他操作系统发生变化。

    最佳答案

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

    在 iproute 包的 ip 中闲逛linux下的代码( ip/ipaddress.c )显示ip命令挖掘接口(interface)标志,如 primarysecondary来自 struct ifaddrmsg , 成员(member) ifa_flags . ifaddmsg似乎是通过 struct nlmsghdr 获得的记录在 man 7 netlink 中,并通过 sendmsg 使用和 recvmsg与内核的交互,这总体上听起来像是一种痛苦,但至少是程序化的。主要和次要是否足够有用是一个单独的问题。

    关于linux - 确定适配器的首选 IPv6 源地址,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7202316/

    相关文章:

    python - Mac OS X : _tkinter. TclError:没有显示名称,也没有 $DISPLAY 环境变量

    objective-c - 如何收听屏幕截图

    c++ - 将应用程序从 Solaris 移植到 Linux

    android - 修改 Linux 内核配置文件

    C++ int 通过套接字 send() : differnent value in TCP package on Linux/MacOS

    macos - 如何删除 shell 可执行文件的停靠图标?

    c - 同时从多个线程调用 write() 是否安全?

    java - 类文件中的错误版本号错误

    linux - Ubuntu: "Startup Applications"中的 shell 脚本

    linux - VirtualBox 4.3 在 ubuntu 12.04 中使用 vboxmanage 创建虚拟磁盘