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)