當前位置:  首頁  >  PHP資訊  >  開源動態

新浪:反DNS劫持高效實戰&HttpDNSLib庫解析

在企業運維下,DNS劫持是一個很讓人頭疼的問題,會帶來很多問題。比如說,訪問不正常,訪問百度可能打開的不是百度網站,或者訪問了一個http的協議,通過劫持,可能訪問不到我最終要訪問的那臺服務器。





在企業運維下, DNS 劫持是一個很讓人頭疼的問題,會帶來很多問題。比如說,訪問不正常,訪問百度可能打開的不是百度網站,或者訪問了一個 http 的協議,通過劫持,可能訪問不到我最終要訪問的那臺服務器。


因為有這樣的問題,給大家也帶來很多困擾。所以,我和我的小伙伴一起研發了一個移動端的 Lib 庫,這個 Lib 庫完完全全可以解決手機移動上的 DNS 劫持的問題。


域名緩存



如果有一個電信的用戶,他查詢了 api.weibo.cn,由一個 LocalDNS 服務器訪問到新浪權威,查詢應該訪問哪一臺服務器,權威給到 Local 服務器, Local 反饋給這個用戶。問題出現在什么環節呢?如果當 LocalDNS ,也就是運營商的服務器不去訪問這樣一個權威的服務器,就不去訪問新浪了,或者以前訪問過這樣一個權威,然后現在把這個訪問解決一直緩存。


當權威將域名和 IP 發生改變之后, LocalDNS 并沒有及時的更新,這樣導致用戶訪問不到服務器,或者訪問不到資源。我想這樣的一個問題,在開發的同學們當中應該多多少少都會遇到。這是一種域名緩存,由 LocalDNS 把剛才的指向結果緩存在本地,用戶請求這樣一個指向的時候,當前的運營商直接把結果反饋給用戶。


運營商在網間結算的時候,會盡量控制它的出口帶寬,控制成本問題。比如把百度的首頁緩存到他自己的服務器上,當這樣一個園區網絡的用戶都訪問百度的時候,真正的數據并沒有訪問到百度自己的服務器,而是從當前的緩存服務器拿到了數據,丟給用戶,這樣帶來的問題是當前的頁面可能不是最新,但是這個數據是可以訪問得到的。


另外,推送廣告,很多無恥的運營商,會把運營解析指向到他們的一個緩存服務器上,并且把網頁里面的廣告替換成他們自己的,當一個網站比較大的時候,如果廣告都替換成他們自己的一些廣告 ID ,屬于坐收漁翁之利,很多網站流量大的時候,都會多多少少遇到這樣的問題,同時客戶端也會遇到這樣的問題。


如果他們做的好,沒有問題。如果他們做的不好會帶來什么問題?運營商一般對 80 端口的 http 服務做了緩存,如果域名是通過 https 的協議或者其他端口提供服務,用戶訪問就會出現失敗,比如支付服務,游戲服務,都可能會出現這一類的問題。另外,一些緩存服務器的運營水平參差不齊,發生緩存服務器故障,導致用戶沒有辦法正常訪問到網絡結果,這是最直接會影響到我們運營的產品上。


域名轉發



這是運營商玩的小貓膩。電信的用戶在查詢 api.weibo.cn 的時候,會到當前的運營商服務器查,聯通的用戶也會到當前運營商服務器查,他們兩個 LocalDNS 都會訪問我們新浪權威的服務器,由權威將指向反饋給正確的用戶。


轉發解析這個里面會出現什么樣的問題呢?比如當前的電信 LocalDNS 不訪問新浪權威的 DNS 服務器,而是直接訪問了聯通 LocalDNS 服務器,為什么有一些小的運營商這么做,他自己要控制他的流量成本,會直接將 DNS 的規則遞歸到他相關或者是同網的 DNS 服務器上做解析,由 LocalDNS 查詢了權威,在權威看到 IP 的結果,訪問的結果是一個聯通用戶訪問的,給它的指向肯定是一個聯通的結果,這個時候電信的 LocalDNS 拿到的結果實際上是聯通去請求的權威的指向結果。


大家說,對于電信的用戶訪問一個聯通的服務器是不是會很慢?我想大家以前多多少少會遇到這樣的問題,有些用戶會抱怨,比如打客服,為什么我訪問你們家這么慢?其實很多問題我們以前做過一系列監控,甚至和用戶做連調,發現了這樣一類問題,他們的 LocalDNS 是一個安全的 Local ,但是訪問上來的服務器是另外的一個安全出口。這樣一個指向是錯誤的,導致當前的電信用戶訪問的是聯通,甚至沒有辦法訪問到運營商的網絡。而部分小運營商為了節省資源,就直接將解析請求轉發到其他運營商遞歸 LocalDNS 上去了,這樣導致用戶沒有辦法正常的請求數據。


LocalDNS 遞歸出口 NAT



比如這個圖,由于是一個配置錯誤, LocalDNS 如果都是正常的指向,配置錯誤會從另外的一個網卡去查詢,聯通的用戶的指向結果是客戶端, Local 客戶端是多網絡的,由于它的配置錯誤,沒有正確的向聯通的查詢,而是訪問了電信權威的服務器,導致拿到的指向結果就是錯的,這也是很常見的一類問題。這里是由于它的網絡網卡的配置錯誤,導致沒有辦法正確的訪問,正常的 IDC 也同樣的問題,會導致用戶訪問變慢,甚至導致用戶沒有訪問通過。

現有的解決方案及存在的問題


第一、實時監控 商務推動第二、繞過自動分配的 DNS ,直接使用 114 DNS ,或者 Google 的 DNS , 114 DNS ,大家可能會把網卡的網址設成 114 的 DNS ,它不太有不準的問題,這是一個辦法。另外,完全拋棄這樣一個域名,直接自己建立這樣一個流量調度系統。比如一個用戶直接訪問是一個 IP ,大家寫接口的時候都會知道,我訪問的是一個域名,由域名做各種調度,最終分配到服務器,也可以由客戶端直接訪問持續一個 IP ,由 IP 做各種調度,最終告訴你,我該服務哪一臺服務器。如果讓一個用戶在他的電腦上設置 114 ,或者 8.8 ,這個成本是很大的。


如果我們自己的技術人員幫助用戶自己發一個 DNS 的請求包,這個事情是可以做,但是如果要去適配 N 多 Android 的版本,還要適配 iOS ,甚至各種端,我這個問題會讓大家很頭疼,它不是不能做,技術上可行,成本會很高。另外,推動用戶修改配置,這是一個很麻煩的事情。


基于前面這樣的一系列的問題,今年的時候,有了這樣一個概念,叫做 HttpDNS ,實際上很簡單,一個聯通的用戶通過一個 HttpDNS 的協議去訪問了 dns.sina.com ,這是一個域名,訪問到我們新浪 http 的服務器,這是一個 http 的 web 服務器,由 httpWeb 服務器向新浪權威的 DNS 服務器查,會查詢到當前的這個用戶,因為訪問的時候帶 IP ,當前這個用戶應該給一個記錄的指向,由 http 查出來推給用戶,這里的協議是 http 的協議,并不是傳統的 DNS 的協議。


如果當 http 的 DNS 服務器掛掉怎么辦?備選方案還是走傳統的向運營商查詢去問, httpDNS 的原理就是將 DNS 的協議,變成 http 的協議,繞過了 DNS 的協議請求,解決了劫持問題。


大家可能都聽到了, HttpDNS 的原理很簡單:第一步,客戶端直接訪問 httpDNS 的接口,獲取業務在域名配置管理系統上配置的訪問延遲最優的 IP 。同時,基于容災考慮,保留次選使用運營商 LocalDNS 解析域名的方式。第二步,客戶端使用獲取到的 IP ,直接往此 IP 發送業務協議請求,以 http 請求為例,通過在 header 中制定 host 字段,向 httpDNS 返回的 IP 發送標準的 http 請求即可。


HttpDNS 的優勢



從原理上來講, HttpDNS 只是將域名解析的協議,由 DNS 的協議換成 http 的協議,其實它一點都不復雜。這個很微小的轉換,卻帶來無數的收益。


第一、它根治了域名解析的異常,由 http 的協議直接打到 httpDNS 服務器的 IP 上,用戶在客戶端解析請求的時候,不會遭受到域名解析異常這些問題;第二,它的調度非常精準,有些包括 DNS 做的不太好,它多個網卡,甚至多個鏈路。一個電信的用戶訪問上來,可能是聯通的出口, HttpDNS 也可以面臨這樣的問題,因為它訪問服務器的時候直接走業務的 IP , http 服務器抓到的 IP 也是業務的 IP ,可以保證 IP 地址非常精準,后面的業務來說,也是可以分配到最好的一個服務器的 IP 地址。


實現成本非常低廉,目前 Android 版本 SDK 已經開源了,代碼已經托管,大家可以去使用。 iOS 版本在最后測試階段,估計近期也會開源。同時,它的擴張性非常強, http 可以接入多方的 HttpDNS ,甚至可以直接訪問公共的 DNS 服務器。有的人會說,我沒有 HttpDNS 服務器怎么辦?目前已知可以使用的 DNS 服務器, DNSPod D ,目前開放了 httpDNS 接口,免費使用,大家可以直接用它。


同時, 114 也可以做,但是還沒有正式的開放。阿里內部也已經有很多項目使用了自己家的 DNS 服務器。新浪目前也是在做自己的 HttpDNS 服務器,具體是否會對外使用,還沒有收到消息。目前來說,大家可以選擇的有 DNSPod D ,同時也可以在我們這樣的 SDK 里面,可以直接發 UDP 的包,直接到 114 ,或者直接到 8.8 ,甚至一些其他的公共的 DNS 服務器上直接進行查詢,也就回答了大家說沒有 HttpDNS 服務器能不能用,是可以的。

HttpDNS Lib 庫目前的現狀,存在的問題,以及解決的問題



HttpDNS 這樣一個 Lib 庫解決了三類問題:第一、 Local DNS 的劫持。第二、平均訪問延遲下降。第三、用戶連接失敗率下降。目前已知用戶延遲訪問下降可以超過 10 % ,訪問失敗率下降超過 1/5 。當然這個也要看大家用的是什么樣的一個服務。


Local DNS 劫持,由于 HttpDNS 通過 IP 直接請求,可以直接拿到這樣的記錄。比如在 tcp/ip 層進行劫持,我們目前也會加入一些使用因子,或者數據加密的方式,保證數據的可信度,目前這一類的事情已經在做,后期我想可能很快也會開源。


為什么朋友訪問延遲可以下降,由于 IP 直接訪問省掉了一次 domain 解析過程,以前訪問一個域名,由本地系統先查詢一下,當前的這個域名應該訪問哪一臺服務器。因為去請求 A 記錄的時候和業務是一個異步的操作,不會給業務帶來任何影響。目前, SDK 去測試,獲取到一個 A 記錄平均時間會在 5 毫秒以內。


用戶連接失敗率下降,這個里面有一個智能排序的算法。比如說,我們分析一個用戶的行為,一個用戶每天可能是在家、路上、公司,很多用戶可能是這樣幾個點,同時有其他的用戶不太遵循這樣的規律。在家的時候,他所訪問的服務器正常一般是固定的,因為他的家是固定的,在公司的時候一般訪問的服務器也是固定的。我們本地在 SDK 的算法會把他訪問的歷史記錄緩存下來,同時有一系列的優化算法。比如他經常訪問這臺服務器,這臺服務器能頻繁的給它正確的返回結果,我們在算法里面排分的時候,會把這臺服務器打分打的比較高。也就是通過一些歷史的數據,個性化的定制了用戶應該去訪問哪些服務器,可以排除一部分的錯誤。

HttpDNS 本地 Lib 庫的交互流程



用戶要去訪問一個域名,到緩存查詢模塊,如果緩存里沒有,會上 HttpDNSLib 庫查,如果沒有數據,會從本地拿一個這樣的結果先給用戶,緩存再返回數據,會由緩存這個模塊把數據進行緩存,還有評估模塊,給我一個接口,查詢模塊和緩存模塊溝通,會和評估模塊溝通,用戶使用完,可以隨用戶的意愿,是否把你使用的結果反饋給評估模塊,如果你給了我一個使用的結果,我會給你一個使用更好的 IP 地址,主要有三個模塊的組成,查詢模塊、數據模塊和病故模塊。查詢模塊,檢測本地是否有相應的域名的緩存,如果沒有,當地的 LocalDNS 獲取,然后從 HttpDNS 更新 domain 記錄。


有數據檢測,過期則更新記錄返回 LocalDNS 記錄,未過期則直接返回緩存層數據。這個里面是查詢模塊簡單做的事情。數據模塊會根據當前的 sp 進行關聯的記錄。緩存域名的信息,緩存服務器的信息以及服務器的優先級記錄每個服務器的 IP 請求成功次數和錯誤次數,也會記錄 IP 最后的訪問時間和最后的測速,這些數據都是為了后面的評估模塊做智能打分的一些數據的依據。同時,還添加了內存到數據庫之間的緩存層,為了讓用戶更快速的拿到一個結果。


評估模塊根據本地的數據,會對整個 IP 排序,這是一個智能排序。然后,會給 HttpDNS 的服務器智能分配 A 記錄提供數據依據。比如大家自己的 HttpDNS 服務器,當那些服務器掛掉的時候, HttpDNS 服務器會自動、智能把掛掉的服務器繞掉。同時也會給服務器進行一系列的反饋,如果不同會有相應的作用,下一批不會給用戶反饋不通的 IP 了。處理用戶反饋回來的明細請求,也是為了更好的智能化。針對用戶反饋失敗請求,進行預警監控,這也是一種機制。


智能排序會根據五個因子:第一、本次測速,速度最快的 IP 會打分,打的分也是最高。第二、反饋結果有一個官方推薦,比如這些服務器的一個壓力,很大的服務器可能打分打的偏低一點,讓用戶盡量不要選擇這些壓力大的服務器,然后給一些分數高的,壓力比較小的,讓負載均衡去攤開,也是一種做法。第三、歷史成功的次數,該 ip 歷史訪問成功次數,比如找一個朋友辦一件事情,這個朋友找他辦了 100 次事情,都是很漂亮的幫我辦了,另外一個朋友,我也找他幫我辦了 100 次,但是他只辦成 1 次,大家也可能很清楚,我肯定找靠譜的人幫助我辦事。第四、歷史錯誤次數,該 ip 歷史訪問錯誤次數。第五、最后的成功時間,這臺服務器,剛剛夠訪問它通過了,請求了它的一次這樣的數據,它就給了我結果。我現在再去找他問數據的時候,其實他還是同樣能夠給我結果的,因為他剛剛是正常的,現在我也認為他是正常的,這里面會有一個閥值, 24 小時,如果超過 24 小打分就是 0 分了,如果 24 小時之內,這一組 IP 哪一個最接近我的峰值使用,就會排序最高。智能排序是基于一系列歷史的插件,歷史數據做的一系列的插件。同時,這些插件大家可以自己進行擴展,如果想要深度的去使用這樣一個庫,里面都是接口化的,插件化的,大家可以直接進行擴展,自己需要一系列的插件。

Lib 庫主要的交互流程



首先,用 SDK 肯定要獲取 A 記錄,調用 SDK 進入一個白名單的過濾流程,如果你訪問的 IP ,這個域名存在這個端,我們會接著走下去,如果沒有配置這個域名,我們這個庫對于你發的域名是不支持的。白名單如果配置是空的,意味著全域名的支持。白名單之后,我們會查詢對應的導列,先從內存槽進行查詢,如果沒有,可能是因為剛剛退出了,所以接著查 DB , DB 有,再同步回內槽,返回給查詢的導列。就是訪問 HttpDNS Server 。


拿到數據做數據校驗,如果 IP 并非是最新的,我們會把它添加到更新隊列,以保證下次過來的時候,一定會反饋給你最新的。接下來就是記錄一些 Log ,最后經過一個過濾器,轉換成應用層,應用層對應的一個數據模型,返回給業務層,這是獲取 A 記錄的一個交互流程。



怎么保證數據是最新的呢?我們有一個定時器的邏輯。定時器做了三件事情:第一、更新國企的 DoMain 數據,第二、對這一組返回的 A 記錄做一個測速的邏輯。第三、日志管理,每個環節進行一些日志的記錄,會在定時器進行輪回。



A 記錄的更新策略。拿著 DoMain 去 HttpDNS Server 請求回來 A 記錄,請求回來 A 記錄,首先會同步到數據層,更新成功之后,同步到內存緩存,業務方再去調用 SDK 的時候,就會從業務層取 DoMain 對應的 A 記錄。


網絡發生變化怎么辦?首先, SDK 里面有一個監聽的模塊,會監聽網絡的變化,判斷當前網絡發生的變化,比如從 WIFI 變到 3G ,從 3G 變到 WIFI ,這個時候會清除內存的緩存,保證下次取的時候不會取錯。 WIFI 下,我們走的可能是聯通的運營商,如果我們手機是移動的,跟 SDK 是不一樣的,如果你是聯通的,給你返回一個電信的 IP ,可能就會比較慢,這是網絡變化的一個策略。


Lib 庫的主要功能點。首先,初始化。初始化 SDK 配置,然后初始網絡狀態信息,注冊網絡的監聽變化。同時, SDK 會支持你的一些預加載的行為。比如你已經很明確,你一定會解析這個域名,我們在初始化之后,就會緊跟著去調用一下預加載的這個函數,它會找預加載的策略,在后臺幫你把對應的域名的一些記錄在后臺都做完了,當你之后再去獲取 A 記錄的時候,它在數據層就已經有了,這是預加載。



其次,更新 A 記錄,我們用一個插件化的思想,我們認為提供給我們的數據源,不僅僅有自己的 HttpDNS Server ,同時還可以用 DNSPOD 。備選方案也跟其他并列, LocalDNS ,這些都可以進行熱插拔和優先級排序。



最后,要進行測速,其實我們可以理解成為是一個最優鏈路。測速的目的是為了找到一個高可用的 IP ,如果 HttpDNS Server 返回給咱們一組 A 記錄有三個,我們怎么判斷這三個可用呢?有兩種方式:第一、用 Socket 連接你的 80 端口,這樣直接對應到你的業務接口,如果他們連得通,說明這個業務肯定是通的。我們取建立連接的時間作為它的一個 RTT ,對于三個 A 記錄來說,哪個時間最短,我們認為這個鏈路不僅通而且更快。除了這個方式,我們可以可以采用 Ping 的方式。



排序模塊,也是基于插件化的一個實現。插件有五個因子,分別是:第一、速度,基于 ping 或者 socket 得出的 RTT 。第二、優先級,根據監控系統、鏈路反饋、負載均衡得出的優先級。第三、成功次數。第四、錯誤次數,如果我們使用的時候一直沒有失敗,我們就認為這個 IP 是非常可靠的 IP ,權重越高,得分越高。第四、失敗次數,同上。第五、最后成功時間,上一秒鐘有三個 A 記錄, A 記錄是成功的,這一秒鐘也認為它是成功的,占一個模塊。最終會根據五個插件和不同的權重計算出一個最終的得分,如果哪個得分最高,我們認為這個 IP 是真正一個高可用的 IP 。




查詢模塊,其實是內存層和 DB 。先去內存層查,如果沒有去 DB 查,如果 DB 沒有,返回默認的 Local ,如果 DB 有,返回回來,同步內存再回去,這是查詢模塊。




配置模塊。使用 SDK 的時候,支持進行一個分布的自定義。首先,開關的類別,我們支持 HttpDNSLib 庫的總開關的方式,開了就能用,關了你去調用,我們還是給你打了一個 Local ,相當于是沒有開的。第二、智能排序算法,五個插件歸屬在智能排序這塊,如果開了這個開關,它才會進行排序,進行一個得分和機損,如果沒有開,默認是 Http Server 返回給默認。如果沒有太多時間做 Http Server ,可以直接用 DNSPod ,還有 UDP ,有些人可能會問為什么沒有 LocalDNS ?如果把這三個都關了,好像就沒有用了。所以我們默認 LocalDNS 是一個兜底的服務。



配置模塊的參數比較多。首先,自定義 HttpDNS API 接口地址,我們得有自己的一個地址,同樣用到 DNS Pod ,也需要配置它的 API ,如果是企業級的配置方式,需要配置企業的 KEY 和企業 ID 。 UDP 請求 DNS 服務器 IP 地址,比如 8.8 , 114 ,剛才提到域名的白名單,如果不配,默認是全域名支持,如果配了,就只支持你已經配了得域名。包括日志的采樣率,日志的上傳時間,定期是輪詢間隔時間, IP 測速間隔時間,都是可以自定義, A 記錄 TTL 差值時間,排序算法的插件權重值。

HttpDNSLib 庫的未來


主要圍繞這么幾點:第一、智能動態節點加速。第二、和監控系統進行整合,可以進行動態節點的切換。第三、故障之后的負載均衡切換。比如現在的 HTTP2 整合。


一路走來,掉進去的坑還是不少的,最早的時候,更新 A 記錄的時候會有并發,比如說,我們在業務方,不同的線程并發的調用函數,會產生并發的問題。當 SDK 這個庫還沒有緩存域名的時候,我們后臺并發調用了很多解析過程,后來發現有這個問題,就把它解決了。其實我們的目的是要得到一個高可用的 IP ,但是當時定的名字叫做測速,后來發現這好像是一個偷換概念的方式。首先,流量的方式,大家知道下載郵件,首先窗口出現這種問題,后來發現無線電不直接取 RTT ,最終我們采用了測速機制變革以及插件化的改革。我們做的時候,配置不同 Server 的時候都插件化了,允許自由更換。


The End


吐了個 "CAO" !
掃碼關注 PHP1 官方微信號
PHP1.CN | 中國最專業的PHP中文社區 | PHP資訊 | PHP教程 | 數據庫技術 | 服務器技術 | 前端開發技術 | PHP框架 | 開發工具 | PHP問答
Copyright ? 1998 - 2020 PHP1.CN. All Rights Reserved PHP1.CN 第一PHP社區 版權所有
     
28玩法