WebRequest對DNS說:沒有你我依然可以

WebRequest對DNS說:沒有你我依然可以


前言

標題中的“沒有你我依然可以”引用自王傑一首歌的名字《沒有你我依然可以》。

WebRequest - 就是大家熟知的System.Net.WebRequest,.NET世界中代碼們用的“瀏覽器”。

DNS - Domain Name System,就是大家熟知的將域名解析爲IP地址的系統。

起因

今天園友sixserve在博問上問了一個問題 - C# socket http請求時怎麼跟上域名信息

RT,一個IP上的IIS可能綁定了多個站點,直接請求的話IIS不知道你要請求哪個站點,所以有什麼辦法可以把域名信息跟上好讓IIS知道,不要用WebClient和其他的,這個域名綁定的是內網地址,如果用WebClient、WebRequest這樣的話要改host文件了。

問題解讀:

1. 如何通過客戶端(不是瀏覽器,是一段C#代碼)訪問目標Web服務器上綁定的指定域名的站點(比如假設這裏是q.cnblogs.com),而這個域名在DNS與客戶端的hosts文件中沒有對應的IP地址解析,所以只能通過IP地址進行訪問(比如這裏假設是61.155.169.118)。但是,由於這個Web服務器綁定了多個站點,需要通過不同的主機名(域名)進行區分,僅有IP地址,Web服務器無法知道你要訪問的目標主機名。也就是你通過 http://61.155.169.118 無法訪問到 http://q.cnblogs.com(由於沒有主機名信息);通過 http://q.cnblogs.com 訪問,請求根本無法到達目標Web服務器(由於沒有DNS解析,客戶端不知道目標IP地址)。

2. 問題也就變成了:通過IP地址訪問目標Web服務器時,如何將主機名的信息傳遞給Web服務器?園友sixserve想通過Socket來實現,並強調了不要用WebClient,WebRequest這類的(可能是基於這樣的假設:用它們只能在域名與IP地址之間選一個。之前我也是這麼認爲的)。

問題解決過程

早上看到這個提問時,我立即來了興趣。因爲昨天剛剛學習了阮一峯的互聯網協議入門,正在勁頭上。

另外,提問者強調了不要用WebRequest,我偏偏要用WebRequest。有首歌叫《偏偏喜歡你》,即使對方說“我一點也不喜歡你”,你也可以繼續偏偏喜歡你,執着可以創造奇蹟。

這裏對WebRequest的執着,並不是偏執,是經過考慮的。只要解決了DNS解析問題,就能用WebRequest通過主機名訪問。那如何解決DNS解析的問題呢?不能給DNS添加記錄,不能修改hosts文件,那怎麼辦?

1. 首先,我想到的解決思路是:能不能找到一種方法向通過C#代碼向本地DNS緩存中添加一條解析記錄。因爲在DNS解析過程中,會先在本地DNS緩存中查找。。。但此路不通,未找到實現方法。

2. 後來,在stackoverflow上找到一種解決思路:hook WSOCK32.DLL中對應的API,也就是在客戶端進行DNS解析的過程中,會調用WSOCK32.DLL中的API,只要截獲這個調用請求,對於要解析的主機名返回對應的IP即可。回答者給出了C++實現代碼:

struct hostent FAR * WSAAPI MyGetHostByName(IN const char FAR * name)
{
    // Call the regular function 
    struct hostent* ret = GetHostByNameFunction(name);
    // Check if it's the hostname you want to reroute
    if ( strcmp(host, (char*)name) == 0 )
    {
        // Edit the IP returned by the regular gethostbyname
        ret->h_addr_list[0] = hostIP;
        ret->h_length = 15;
    }
    // Return the result
    return ret;
}

並提供了C#的實現思路,通過 EasyHook 進行hook。

這個方法雖然可行,但太複雜,並沒有成爲心目中的“她” —— 還是簡單點好。

這個複雜的解決方法反而影響了我繼續解決問題的興趣,幾乎準備放棄對這個問題的繼續研究。

問題解決方法

還好,我沒有輕易放棄,繼續思考可能的解決方法,並組合各種關鍵詞進行搜索。。。

很多時候,柳暗花明就在你最因難、最無助、最精疲力盡、最想放棄的前方100米。。。

通過關鍵詞“c# add to hosts”,再次來到stackoverflow,在一個提問 Host name resolution without modifying the hosts file 的最佳答案的下方有一個回答,沒有任何“推薦”:

當時就眼前一亮,心中隱約感覺到就是“她”。。。接下來只需驗證一下剛剛發現的這個“她”是不是就是一直在尋找的“她”。。。

功夫不負有心人,事實證明就是“她”,終於找到了!下面的代碼就是見證:

[Fact]
//http://q.cnblogs.com/q/38881/
public void Q38881_Test()
{
    var request = WebRequest.Create("http://61.155.169.118") as HttpWebRequest;
    request.Host = "q.cnblogs.com";
    using (var response = request.GetResponse())
    {
        using (var sr = new StreamReader(response.GetResponseStream()))
        {
            Console.WriteLine(sr.ReadToEnd());
        }
    }
}

代碼運行結果:

小結

寫了這麼多,就是爲了這一行代碼:request.Host = "q.cnblogs.com"; 等了那麼多年,就是爲了那一個人。代碼如此,生活也是如此。。。結果往往很簡單,而真正激動人心的是其中的過程。

這行代碼的意義在於可以讓WebRequest不依賴DNS,於是纔有了這樣的故事 —— WebRequest對DNS說:沒有你我依然可以。




來源:http://www.cnblogs.com/dudu/archive/2012/07/18/webrequest_dns.html


發佈了59 篇原創文章 · 獲贊 5 · 訪問量 23萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章