跳转到主要内容

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 3484 ,系统必须对这些答案进行排序,来让成功率最高的地址优先级最高。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

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

IPv6 默认地址选择

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

因此 precedence ::ffff:0:0/96 100 意味着把所有 IPv4 地址的优先级调为 100


100 优先级可不是我乱写的啊,这是 RFC 3484 说的:https://www.ietf.org/rfc/rfc3484.txt

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
      2002::/16             30     2
      ::/96                 20     3
      ::ffff:0:0/96        100     4

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

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

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


Draves                      Standards Track                    [Page 18]

RFC 3484           Default Address Selection for IPv6      February 2003


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


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