天天看點

因微信支付API對IPv6支援不完整引起的一次故障

作者介紹

林偉壕,網絡安全devops新司機,先後在中國電信和網易遊戲從事資料網絡、網絡安全和遊戲運維工作。對linux運維、虛拟化和網絡安全防護等研究頗多,目前專注于網絡安全自動化檢測、防禦系統建構。

衆所周知,随着“微信紅包”等熱門應用的紅火,微信支付在我們的生活中已無處不在。今天我要分享的内容,正是關于微信支付面向商戶的api 在ipv6支援上的一個問題。關注點不僅在于問題本身,更在排查故障過程中一些思路和方法論。

故障簡述

故障詳情

發現故障,在處理的第一步經常是做故障重制,先使用shell腳本進行測試:

因微信支付API對IPv6支援不完整引起的一次故障

測試結果如下:

因微信支付API對IPv6支援不完整引起的一次故障

可以看到,第一次連接配接花費了15秒+的時間,之後都是毫秒級的傳回。是以如何定位首次連接配接耗時過長的問題是目前重點。

處理過程

節點1

由于發生這個問題之前,我們有一個内部應用也有類似問題,比如第一次通路網頁需要加載超過10s才能出來,之後通路就非常快了。當時通過抓包的方式定位到同一網絡中有其他ip劫持了流量,增加了中間建立連接配接的時間,後來去除劫持源頭後才恢複正常。于是,受過往經驗影響,我首先猜想是可能是網絡原因或者劫持。按照這個思路,先排查發起請求的用戶端所在網絡,發現是獨立的外網ip,沒有nat等相對複雜的網絡環境。同時,切換了一個網絡環境進行測試,又發現每次請求響應都很快,測試結果如下:

因微信支付API對IPv6支援不完整引起的一次故障

是以網絡問題仍無法徹底排查,于是決定在curl的同時抓包。

tcpdump -w test.pcap

抓包下來,用wireshark打開,看看是怎麼連接配接建立過程是怎樣的。

因微信支付API對IPv6支援不完整引起的一次故障

發現第一次請求有tcp重傳,于是更加懷疑是網絡問題,但從這裡又無法直覺看到是具體原因。是以開始往用戶端所在伺服器環境進行排查。

節點2

處理過程中同樣是想起,之前遇到一個iptables規則配置不合理導緻資料包梳理效率很低的問題,是以一開始在伺服器環境排查時優先檢查了iptables配置規則,發現也挺合理的,對于首次建立的連接配接沒有set tag,也沒有對new有特别設定,然後又臨時清除了所有iptables規則發現問題依舊,于是跳過iptables。

因微信支付API對IPv6支援不完整引起的一次故障

節點3

到了這裡,我開始懷疑dns解析異常也會引起首次建立連接配接耗時過長的問題。于是開始檢查/etc/resolve.conf,不管是檢查配置,還是更換dns伺服器問題都是一樣的。但是,“有心栽花花不開,無心栽柳柳成蔭”,這個過程中我還是抓了包,這麼一來,發現ipv6位址解析異常了!

因微信支付API對IPv6支援不完整引起的一次故障

可以看到,dns伺服器傳回的ipv6解析結果是”server failure aaaa”,而且耗時超過5s,這裡就有問題了。

節點4

下面開始把焦點集中到微信支付域名api.mch.weixin.qq.com的ipv6解析上,發現有servfail,而且重制率很高。

因微信支付API對IPv6支援不完整引起的一次故障

同時指定了ipv4的解析,發現a的查詢很快:

因微信支付API對IPv6支援不完整引起的一次故障

既然确定了ipv6解析有問題,ipv4解析正常,于是修改了相關代碼,确認強制域名解析ipv4的話,都是正常的。

原因分析

從dns原理看問題

1、整個dns解析過程

因微信支付API對IPv6支援不完整引起的一次故障

如上圖,當一個用戶端發起dns解析請求時,會有一個優先級的,按照本地dns緩存->/etc/hosts的dns配置->isp或本地域名解析緩存伺服器->根域名伺服器->頂級域名伺服器->...->目标站點權威伺服器的順序一路解析下來。

結合本次故障來看,問題應該是在權威伺服器這裡。究竟如何,且看下文解說。

先來看看對比的解析結果:

a.api.mch.weixin.qq.com的ipv4解析結果

因微信支付API對IPv6支援不完整引起的一次故障

b.api2.mch.weixin.qq.com的ipv4解析結果

因微信支付API對IPv6支援不完整引起的一次故障

c.api.mch.weixin.qq.com的ipv6解析結果

因微信支付API對IPv6支援不完整引起的一次故障

d.api2.mch.weixin.qq.com的ipv6解析結果

因微信支付API對IPv6支援不完整引起的一次故障

從上面的測試結果可看出,api2.mch.weixin.qq.com ipv6解析正常,api.mch.weixin.qq.com.ipv6解析失敗是因為多了一層:

api.mch.weixin.qq.com. 600       in   cname      forward.qq.com.,然後 forward.qq.com aaaa 的解析傳回是錯誤的,這裡是權威伺服器處理失敗了。

為什麼用戶端解析的是 api.mch.weixin.qq.com aaaa,而緩存回去查詢 forward.qq.com aaaa 呢? 

這是因為 api.mch.weixin.qq.com. 600 in cname forward.qq.com. 這條記錄被緩存了,導緻後邊後續的查詢都會變成查 forward.qq.com 對應的記錄。

下面再對比一下解析www.163.com和api.mch.weixin.qq.com看看在權威伺服器層面有何不同。

因微信支付API對IPv6支援不完整引起的一次故障

這裡api.mch.weixin.qq.com的aaaa 解析傳回有問題,是soa,按協定應該還是傳回 cname 記錄;可以對比 www.163.com 的解析結果發現後者就是傳回的soa。

從上文可以看到 forward.qq.com. 實際上是做了一層 ns,雖然沒有真正的授權出去(ns-os1.qq.com. 上沒有 forward.qq.com soa 記錄),但緩存看來,它已經授權了一層,而傳回的 soa 有誤,是以緩存伺服器無法判定該 nodata 傳回的類型,是以認為該傳回不合法,最終導緻了api.mch.weixin.qq.com和forward.qq.com 的aaaa記錄一直傳回 servfail,是以緩存伺服器會嘗試繼續解析,進而導緻首次解析時間過長。等到之後解析成功後,就使用的本地緩存,是以解析很快,等到緩存失效後,問題就會重制。

2、關于curl的dns解析順序

一般來說,如果伺服器開啟了ipv6,curl預設會優先解析 ipv6,在對應域名沒有 ipv6 的情況下,會等待 ipv6 dns解析失敗 timeout 之後才按以前的正常流程去找 ipv4。dns服務都是支援解析ipv6的,如果沒有設定ipv6解析,查詢結果就是空,不會是serverfail。

3、關于nslookup和dig的工作原理

不同作業系統nslookup和dig的原理并不同,比如win7的nslookup每發一次ipv4請求就會産生2個a記錄請求,換到win xp下nslookup沒發一次ipv4請求則隻會産生一個a記錄請求,是以在抓包分析時需要根據不同作業系統的應用特性進行區分。

微信原來已有解決方案

針對這個問題,其實微信官方文檔

商戶通路微信支付

商戶側使用api.mch.weixin.qq.com(主)和api2.mch.weixin.qq.com(備)這兩個支付api域名通路微信支付,這兩個域名功能完全一樣。

這兩個域名分别配hosts綁定專線通路微信的兩個131開頭的政策ip,具體電信ip和聯通ip那個綁定到api和api2, 商戶側可以測速後自己決定。

商戶側的通路支付接口的代碼邏輯需具備失敗換域名重試的機制,即通路api.mch.weixin.qq.com不通的話,就換成api2.mch.weixin.qq.com重試。

商戶側通路微信支付時,若兩條專線都不通,要有能切回走公網通路的能力。若無法走公網,則商戶側需要知曉這裡的風險。

可行的解決辦法

關閉伺服器ipv6功能

1、使用ifconfig驗證是否開啟ipv6:

因微信支付API對IPv6支援不完整引起的一次故障

2、檢視服務監聽的ip驗證是否開啟ipv6:

因微信支付API對IPv6支援不完整引起的一次故障

3、使用lsmod驗證是否開啟ipv6:

因微信支付API對IPv6支援不完整引起的一次故障

關閉ipv6:修改/etc/modprobe.conf加入如下的兩條,重新開機系統即可。

alias net-pf-10 off

alias ipv6 off

開啟ipv6:ipv6是預設支援的,是以隻需将/etc/modprobe.conf中的上面兩條指令注釋掉即可。

在/etc/hosts檔案中指定域名ip解析記錄

按照下面格式配置,但是如果指定的伺服器故障了,業務也會受牽連,這不是很穩妥的方法。

api.mch.weixin.qq.com 183.3.235.18

在代碼中指定域名解析使用ipv4結果

比如php:

因微信支付API對IPv6支援不完整引起的一次故障

使用微信官方方案,設定主備域名進行備援,支援域名解析失敗切換。

經驗教訓

熟讀使用者文檔

很多人學習技術知識時喜歡在搜尋引擎找别人的部落格或者問題解答來作為知識學習的入口,其實這裡有個問題,部落格或者問題答案經過别人的消化,一方面提高了易讀性,另外也引入了偏見誤解,同時無法保證完整性。反觀官方的使用者文檔,特别是外文的,易讀性相對差,不過很權威也很全面,很多細節問題都有。但很多人不願意好好看使用者文檔,而是通過網絡上很零碎的知識去學,這樣難免有遺漏。像這次我們使用微信支付api過程中使用者文檔沒有看到這一塊,繞了一圈,反而增加了學習成本。是以,學習或者使用新系統新技術,熟讀使用者文檔反而是一個很基礎的地方呢。

不能思維固化

從上面的處理過程來看,可以發現由于之前有類似問題的處理經驗,一開始我往網絡或劫持,或iptables等方向去定位問題,并沒有帶來太大作用。很多時候有相關經驗起碼能提供思路,不失為一種優勢。而有時候,太重視經驗也會導緻思維固化,沒能把基礎的資訊全面收集後再做定性,後做定位,就會事倍功半。

原文釋出時間為:2017-02-28

本文來自雲栖社群合作夥伴dbaplus

繼續閱讀