2016
Apr
13

最近将 OS 升级到 Red Hat Enterprise Linux 6.x,结果有一个功能就莫名的坏掉了,该功能很普通,就只是将 A 机器上的图片用 Curl (PUT) 的方式,丢到 B 机器上,但是它一执行就会收到 Error 500,於是我查看了 A 机器上的 Error log ,发现一个错误讯息: Failed to connect to 800:c:f1:806:2001:a Network is unreachable

我尝试在 A 机器上手动执行 curl "http://B/xxx/xxx" -X PUT ... ,直接用 curl 方式来上传图片,而这个方式是可以正常运做的,图片有被传到 B 机器上,但是这个结果反而让我很困扰,Curl 指令可以运作,但是 PHP 的 curl 却没办法动。

第一时间,我就先用指令 host B 来查机器 B 的 IP,看看他的 IP 是否正常,而我得到下面这个结果,该 domain 同时存在 IPv4 与 IPv6,看来这就是问题的所在,但是为什么程式会使用 IPv6 ,而不使用 IPv4 呢 ?

Example
  1. host B
  2. B has address x4.2x3.x89.106
  3. B IPv6 address 800:c:f1:806:2001:a

虽然我在 A 机器中可以取得 B 机器的 IPv6 ,但是当 A 要 connect 至 B 的时候, A 会先将 Request 丢给 Router ,而那台 Router 没办法正确的处理 IPv6 格式,造成连线中断,所以我们必须强迫程式使用 IPv4 ,而不要用 IPv6 。

我们可以使用 network 这个指令,来分辨出 Router 是否可以正确的解析出 IPv6 格式,看下面这个范例 , IP 变成很奇怪的格式,代表它不支援 IPv6。

nslookup
  1. $ nslookup 800:c:f1:806:2001:a
  2. Server: 192.168.0.20
  3. Address: 192.168.0.20#53
  4.  
  5. Non-authoritative answer:
  6. 8.6.0.0.0.0.0.0.0.0.0.0.0.0.0.0.2.0.z.0.1.0.0.4.0.0.8.6.4.0.1.2.ip6.arpa name = tx-xn-x6a.2e101.net.

Solve IPv6 Problem

PHP Curl 内建就有提供一个 option ,可以强迫系统的 Domain Name resolution 使用 IPv4,方法很简单,只要多一行语法就搞定了,加了下面这句程式后, PHP Curl 就可以正确的将 domain 转到 IPv4 ,功能也就正常了。

Force curl using IPv4
  1. curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);

ifconfig 移除 IPv6

跟同事讨论后,同事也提出另一个方法,就是将 B 机器的 IPv6 下掉,因为我们的系统还不需要使用 IPv6 ,自然也不用支援 IPv6 这种 IP。

我们先检查 B 机器上的网路设定,下指令 ifconfig 后会看到 inet6 相关设定,有这个设定就是指这台机器的 IP 支援 IPv6 。

ifconfig
  1. enp0s8: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
  2. inet 192.168.0.4 netmask 255.255.255.0 broadcast 192.168.56.255
  3. inet6 fe10::a20:27ff:fec:22ae prefixlen 64 scopeid 0x20<link>
  4. ether 01:00:17:0c:a2:0e txqueuelen 1000 (Ethernet)
  5. RX packets 7483810 bytes 849228602 (809.8 MiB)
  6. RX errors 0 dropped 0 overruns 0 frame 0
  7. TX packets 21513200 bytes 50057076506 (46.6 GiB)
  8. TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

接著用以下方式来移除 inet6 IPv6 :

  • 编辑 /etc/sysconfig/network 加入以下两个设定
    • NETWORKING_IPV6=no
    • IPV6_AUTOCONF=no
  • 编辑 /etc/sysctl.conf 加入以下设定
    • net.ipv6.conf.eth0.disable_ipv6 = 1
  • sudo reboot 重开机

重开机后,再用 ifconfig 检查 inet6 是否已经被移除。

ifconfig inet6 不见了
  1. enp0s8: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
  2. inet 192.168.0.4 netmask 255.255.255.0 broadcast 192.168.56.255
  3. ether 01:00:17:0c:a2:0e txqueuelen 1000 (Ethernet)
  4. RX packets 7483810 bytes 849228602 (809.8 MiB)
  5. RX errors 0 dropped 0 overruns 0 frame 0
  6. TX packets 21513200 bytes 50057076506 (46.6 GiB)
  7. TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

回應 (Leave a comment)