通常情况下,拥有双栈网络时,操作系统优先使用IPv6网络。但是这个特性给我带来了一些麻烦...

我的服务器支持双栈网络,但是云服务商默认禁止了邮件协议,即不能通过云服务器进行邮件发送活动。这对博客运营来说相当不友好,在我要求使用邮件功能后,服务商给我另外分配了一个IPv4地址,邮件可以通过这个地址发送而不会受到阻止。现在我的服务器共有3个IP地址,分别是两个IPv4地址,一个IPv6地址。基于IPv6优先的特性,发送邮件连接SMTP服务器时,使用了IPv6通道,毫不意外的,连接被阻止,造成的结果就是邮件无法发送出去。

这个问题我排查许久,才发现是IPv6的问题。对此需要寻找一个解决方法。

查了很多资料,有禁用IPv6协议栈的,有禁用IPv6 DNS解析的,有提高IPv4协议栈优先级的。

最终我选择提高IPv4协议栈的优先级来解决这个问题。

getaddrinfo()

“在C 编程中, 函数 getaddrinfo()getnameinfo()域名主机名IP 地址在人类可读的文本表示形式和操作系统的网络 API 的结构化二进制格式之间进行转换。这两个函数都包含在POSIX标准应用程序编程接口(API) 中。[1]

getaddrinfo 和 getnameinfo 是彼此的反函数。它们与网络协议无关,同时支持IPv4IPv6。它是在构建独立于协议的应用程序中进行名称解析以及将遗留 IPv4 代码转换为 IPv6 Internet 的推荐接口。

在内部,这些函数通过调用其他较低级别的函数(例如gethostbyname() )使用域名系统(DNS) 执行解析。”

来自:getaddrinfo - Wikipedia

gai.conf

前面提到,getaddrinfo()将域名、主机名、IP地址转化为人类可读的文本形式。在使用getaddrinfo()获取到多个IP地址时,根据 RFC 3484,就需要对获取到的IP地址进行排序,即确定优先级。RFC 提供了一种排序算法,但并不是全面的,RFC 还要求系统管理员应该有可能动态更改排序。为此在Linux系统中,gai.conf就是用来干这个事情的,配置IPv4、IPv6的优先级,需要从这个文件入手。

下面是gai.conf的配置文件中的每一行都包含一个关键字及其参数,并忽略任何空白的地方。以“#”开头的是注释,将会被忽略。

# Configuration for getaddrinfo(3).
#
# So far only configuration for the destination address sorting is needed.
# RFC 3484 governs the sorting.  But the RFC also says that system
# administrators should be able to overwrite the defaults.  This can be
# achieved here.
#
# All lines have an initial identifier specifying the option followed by
# up to two values.  Information specified in this file replaces the
# default information.  Complete absence of data of one kind causes the
# appropriate default information to be used.  The supported commands include:
#
# reload  <yes|no>
#    If set to yes, each getaddrinfo(3) call will check whether this file
#    changed and if necessary reload.  This option should not really be
#    used.  There are possible runtime problems.  The default is no.
#
# label   <mask>   <value>
#    Add another rule to the RFC 3484 label table.  See section 2.1 in
#    RFC 3484.  The default is:
#
#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
#label 2001:0::/32   7
#
#    This default differs from the tables given in RFC 3484 by handling
#    (now obsolete) site-local IPv6 addresses and Unique Local Addresses.
#    The reason for this difference is that these addresses are never
#    NATed while IPv4 site-local addresses most probably are.  Given
#    the precedence of IPv6 over IPv4 (see below) on machines having only
#    site-local IPv4 and IPv6 addresses a lookup for a global address would
#    see the IPv6 be preferred.  The result is a long delay because the
#    site-local IPv6 addresses cannot be used while the IPv4 address is
#    (at least for the foreseeable future) NATed.  We also treat Teredo
#    tunnels special.
#
# precedence  <mask>   <value>
#    Add another rule to the RFC 3484 precedence table.  See section 2.1
#    and 10.3 in RFC 3484.  The default is:
#
#precedence  ::1/128       50
#precedence  ::/0          40
#precedence  2002::/16     30
#precedence ::/96          20
#precedence ::ffff:0:0/96  10
#
#    For sites which prefer IPv4 connections change the last line to
#
#precedence ::ffff:0:0/96  100

#
# scopev4  <mask>  <value>
#    Add another rule to the RFC 6724 scope table for IPv4 addresses.
#    By default the scope IDs described in section 3.2 in RFC 6724 are
#    used.  Changing these defaults should hardly ever be necessary.
#    The defaults are equivalent to:
#
#scopev4 ::ffff:169.254.0.0/112  2
#scopev4 ::ffff:127.0.0.0/104    2
#scopev4 ::ffff:0.0.0.0/96       14

配置IPv4协议优先

根据 RFC 3484协议的第10.3条款,在IPv4/IPv6双栈协议中设置IPv4优先,只需赋予 ::ffff:0.0.0.0/96 前缀更高的优先级即可。

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)

   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)

编辑/etc/gai.conf文件,将precedence ::ffff:0:0/96 100取消注释后保存即可。

参考资料

この素晴らしい世界に祝福を!
最后更新于 2022-12-18