跳转到主要内容

Linux / Windows 在 IPv6+IPv4 双栈下优先使用 IPv4

最近服务器引入了 IPv6 ,但是就出现了一个问题:

如果访问的域名同时拥有 A 和 AAAA 解析,那么 Linux 系统会优先使用 AAAA 解析,也就是 IPv6 地址,同时网络出口的优先级都会比 IPv4 高。

而且 IPv6+IPv4 双栈下,DNS查询会同时发送 AAAA 和 A 解析,无论访问域名有没有 AAAA 解析都会浪费一定时间去查询。

但是现在 IPv6 网络还不理想。

举一个栗子:

# wget https://papermc.io/api/v1/paper/1.15.2/385/download
--2020-08-14 00:21:05--  https://papermc.io/api/v1/paper/1.15.2/385/download
正在解析主机 papermc.io (papermc.io)... 2606:4700:20::ac43:4580, 2606:4700:20::681a:202, 2606:4700:20::681a:302, ...
正在连接 papermc.io (papermc.io)|2606:4700:20::ac43:4580|:443... 已连接。
已发出 HTTP 请求,正在等待回应... 200 OK
长度:44783881 (43M) [application/java-archive]
正在保存至: “download”

 2% [=>                                                                             ] 1,317,487   9.59KB/s 剩余 35m 23s
# wget https://papermc.io/api/v1/paper/1.15.2/385/download
--2020-08-14 00:26:40--  https://papermc.io/api/v1/paper/1.15.2/385/download
正在解析主机 papermc.io (papermc.io)... 172.67.69.128, 104.26.3.2, 104.26.2.2, ...
正在连接 papermc.io (papermc.io)|172.67.69.128|:443... 已连接。
已发出 HTTP 请求,正在等待回应... 200 OK
长度:44783881 (43M) [application/java-archive]
正在保存至: “download”

 1% [                                                                               ] 466,050      105KB/s 剩余 6m 51s

结果很 amazing 啊 ,这 IPv4 不知道快到那里去了。


好,说正事

优先使用 IPV4 非常简单,

只需要在 /etc/gai.conf 文件里面添加一行(这个文件默认不存在,手动生成吧):

precedence  ::ffff:0:0/96  100

保存就立即生效了。


那么这行代码意味着什么呢

/etc/gai.conf 是干嘛的?   

手册的说明:系统调用 getaddrinfo(3) 函数时可能返回会多个答案。根据 RFC 6424 ,系统必须对这些答案进行排序,来让成功率最高的地址优先级最高。RFC 还要求系统管理员可以动态修改优先级,这就是修改优先级的文件。

人话:调用系统解析域名函数获取 IP 地址的时候可能会获取到多个地址,这个文件允许你修改获取到的地址的使用优先级。

 

/etc/gai.conf 这个文件默认里面写了
(我知道你的是刚创建的,但里面什么都没写也等于写了下面的内容[根据 RFC 3484 与手册描述]):

label  ::1/128       0
label  ::/0          1
label  2002::/16     2
label ::/96          3
label ::ffff:0:0/96  4
precedence  ::1/128       50
precedence  ::/0          40
precedence  2002::/16     30
precedence ::/96          20
precedence ::ffff:0:0/96  10

注:RFC 3484 已被 RFC 6424 废弃,但手册页任然提到 RFC 3484。
状态可查看 info 页面:https://www.rfc-editor.org/info/rfc6724

 

但部分发行版可能默认含有此文件,并包含注释,甚至还写了怎么优先使用 IPv4:

# This file is part of libc-bin package and the GNU C Library.
# Please see the gai.conf(5) manual page.

# This file configures the behavior of getaddrinfo(3) function.

# Entries are of the form:
# label FAMILY PATTERN
# precedence FAMILY PATTERN PRECEDENCE
# reload (no arguments)

# A PATTERN of ::/0 means any IPv6 address, and a PATTERN of 0.0.0.0/0
# means any IPv4 address.

# If this file is not present, the behavior is equivalent to having:
#    label ::1/128       0
#    label ::/0          1
#    label 2002::/16     2
#    label ::/96         3
#    label ::ffff:0:0/96 4
#    label fec0::/10     5
#    label fc00::/7      6
#    precedence ::1/128       50
#    precedence ::/0          40
#    precedence 2002::/16     30
#    precedence ::/96         20
#    precedence ::ffff:0:0/96 100
#    precedence fec0::/10     1
#    precedence fc00::/7      1

# Uncomment the following to prefer IPv4 connections over IPv6:
#precedence ::ffff:0:0/96  100

 

这些是什么地址?看下表:

IPv6 默认地址选择

前缀 优先级 标签 用途/描述
::1/128 50 0 本地主机 localhost
::/0 40 1 默认单播地址
::ffff:0:0/96 35 4 IPv4 映射的 IPv6 地址(用 IPv6 地址表示的所有 IPv4 地址)
2002::/16 30 2 用于 6to4 隧道的地址 (根据 RFC 7526 已废弃) 
2001::/32 5 5 Teredo 隧道地址
fc00::/7 3 13 唯一本地地址(内网地址)
::/96 1 3 兼容 IPv4 的地址(根据 RFC 4291 已废弃)
fec0::/10 1 11 站点本地地址(根据 RFC 3879 已废弃)
3ffe::/16 1 12 6bone 网络(早期测试用,已回收)

因此 precedence ::ffff:0:0/96 100 意味着把所有 IPv4 地址的优先级调为 100(数值越高优先级越高)。

这些地址可能会随着时间变化,详细请参阅:


100 优先级可不是我乱写的啊,这是 RFC 6424 说的:

10.3.  Configuring Preference for IPv6 or IPv4

   The default policy table gives IPv6 addresses higher precedence than
   IPv4 addresses.  This means that applications will use IPv6 in
   preference to IPv4 when the two are equally suitable.  An
   administrator can change the policy table to prefer IPv4 addresses by
   giving the ::ffff:0.0.0.0/96 prefix a higher precedence:

      Prefix        Precedence Label
      ::1/128               50     0
      ::/0                  40     1
      ::ffff:0:0/96        100     4
      2002::/16             30     2
      2001::/32              5     5
      fc00::/7               3    13
      ::/96                  1     3
      fec0::/10              1    11
      3ffe::/16              1    12

   This change to the default policy table produces the following
   behavior:

   Candidate Source Addresses: 2001:db8::2 or fe80::1 or 169.254.13.78
   Destination Address List: 2001:db8::1 or 198.51.100.121
   Unchanged Result: 2001:db8::1 (src 2001:db8::2) then 198.51.100.121
   (src 169.254.13.78) (prefer matching scope)

   Candidate Source Addresses: fe80::1 or 198.51.100.117
   Destination Address List: 2001:db8::1 or 198.51.100.121
   Unchanged Result: 198.51.100.121 (src 198.51.100.117) then
   2001:db8::1 (src fe80::1) (prefer matching scope)

   Candidate Source Addresses: 2001:db8::2 or fe80::1 or 10.1.2.4
   Destination Address List: 2001:db8::1 or 10.1.2.3
   New Result: 10.1.2.3 (src 10.1.2.4) then 2001:db8::1 (src
   2001:db8::2) (prefer higher precedence)

 


Windows 同理

由于是 RFC 要求的,所以 Windows 也有一样的东西。

在管理员 CMD 或 Powershell 中执行:

netsh interface ipv6 show prefixpolicies

相当于 Linux 的 cat /etc/gai.conf

netsh interface ipv6 set prefixpolicy ::ffff:0:0/96 100 4

相当于在 Linux 中添加 precedence  ::ffff:0:0/96  100

如:

C:\Windows\system32>netsh interface ipv6 set  prefixpolicy ::ffff:0:0/96 100 4
确定。


C:\Windows\System32>netsh interface ipv6 show prefixpolicies
查询活动状态...

优先顺序    标签   前缀
----------  -----  --------------------------------
       100      4  ::ffff:0:0/96
        50      0  ::1/128
        40      1  ::/0
        30      3  2002::/16
        20      7  fec0::/10
        10      8  3ffe::/16
         5      4  2001::/32
         3      5  fc00::/7
         1      6  ::/96