域名劫持原理及實現
目錄
1.從輸入URL到頁面載入發生了什麼
總體來說分為以下幾個過程:
1.1 DNS解析
1.2 TCP連線
1.3傳送HTTP請求
它主要發生在客戶端。傳送HTTP請求的過程就是構建HTTP請求報文並通過TCP協議中傳送到伺服器指定埠(HTTP協議80/8080,HTTPS協議443)。HTTP請求報文是由三部分組成:請求行,請求報頭和請求正文。
1.4伺服器處理請求並返回HTTP報文
後端從在固定的埠接收到TCP報文開始,這一部分對應於程式語言中的socket。它會對TCP連線進行處理,對HTTP協議進行解析,並按照報文格式進一步封裝成HTTPRequest物件,供上層使用。這一部分工作一般是由
HTTP狀態碼由三個十進位制數字組成,第一個十進位制數字定義了狀態碼的型別,後兩個數字沒有分類的作用。HTTP狀態碼共分為5種類型:
1** 資訊,伺服器收到請求,需要請求者繼續執行操作
2** 成功,操作被成功接收並處理
3** 重定向,需要進一步的操作以完成請求
4** 客戶端錯誤,請求包含語法錯誤或無法完成請求
5** 伺服器錯誤,伺服器在處理請求的過程中發生了錯誤
1.5瀏覽器解析渲染頁面
瀏覽器在收到HTML,CSS,JS檔案後,它是如何把頁面呈現到螢幕上的?下圖對應的就是WebKit(一個開源的瀏覽器引擎)渲染的過程。
瀏覽器是一個邊解析邊渲染的過程。首先瀏覽器解析HTML檔案構建DOM樹,然後解析CSS檔案構建渲染樹,等到渲染樹構建完成後,瀏覽器開始佈局渲染樹並將其繪製到螢幕上。
JS的解析是由瀏覽器中的JS解析引擎完成的。JS的執行機制就可以看做是一個主執行緒加上一個任務佇列(taskqueue)。同步任務就是放在主執行緒上執行的任務,非同步任務是放在任務佇列中的任務。所有的同步任務在主執行緒上執行,形成一個執行棧;非同步任務有了執行結果就會在任務佇列中放置一個事件;指令碼執行時先依次執行執行棧,然後會從任務佇列裡提取事件,執行任務佇列中的任務,這個過程是不斷重複的,所以又叫做事件迴圈(Eventloop)。但是當文件載入過程中遇到
1.6連線結束
2. dns劫持
當用戶輸入一個URL時,想要能夠訪問我們的路由器管理介面首先就需要將改URL的DNS解析到路由器的web伺服器地址上,這時候,我們需要dns劫持。Dns劫持中主要用到一個開源的軟體-dnsmasq。
首先我們利用dnsmasq將自己的工作站配置為一個能夠解析開發域名的server,解析的ip地址設定為工作站的ip地址。利用dnsmasq建立了一個dnsmapping table,將www.baidu.com的域名解析為路由器管理介面地址192.168.2.1。這時候,通過www.baidu.com訪問時會轉跳至192.168.2.1。
3. url重定向
url重定向的實現可以在前端實現或是後端實現。這時候web伺服器需要將指定的html返回給客戶端,比如我們的快速嚮導頁面或是首頁頁面。這就需要重新定向使用者輸入的url。
3.1.前端實現
3.1.1 html頁面跳轉方式
可以使用html的meta標籤實現頁面的跳轉。
meta是html語言head區的一個輔助性標籤。meta標籤共有兩個屬性,它們分別是http-equiv屬性和name屬性,不同的屬性又有不同的引數值,這些不同的引數值就實現了不同的網頁功能。
http-equiv屬性:相當於http的檔案頭作用,它可以向瀏覽器傳回一些有用的資訊,以幫助正確和精確地顯示網頁內容,與之對應的屬性值為content,content中的內容其實就是各個引數的變數值。
<metahttp-equiv="引數"content="引數變數值">;
3.1.2 JS頁面跳轉方式
1.使用window.location.href= "newurl"
也可以用window.location= "newurl"
2. 使用window.navigate
<script>
window.navigate("http://www.csdn.net");
</script>
3.2.後端實現
後端實現主要是通過響應頭中的http響應location欄位,令客戶端重定向至指定URL。
資料互動過程
3.2.1 http訊息
HTTP是基於客戶端/服務端(C/S)的架構模型,通過一個可靠的連結來交換資訊,是一個無狀態的請求/響應協議。
一個HTTP"客戶端"是一個應用程式(Web瀏覽器或其他任何客戶端),通過連線到伺服器達到向伺服器傳送一個或多個HTTP的請求的目的。一個HTTP"伺服器"同樣也是一個應用程式(通常是一個Web服務,如ApacheWeb伺服器或IIS伺服器等),通過接收客戶端的請求並向客戶端傳送HTTP響應資料。
HTTP協議的請求和響應都是一段按一定規則組織起來的文字,其請求的頭部包括請求行(請求方式method、請求的路徑path、協議版本protocol),請求頭標(一系列key:value形式組織的文字行),空行(分隔請求頭部與資料)和請求資料。
1. 客戶端請求
客戶端傳送一個HTTP請求到伺服器的請求訊息包括以下格式:請求行(requestline)、請求頭部(header)、空行和請求資料四個部分組成。
2. 伺服器響應訊息
HTTP響應也由四個部分組成,分別是:狀態行、訊息報頭、空行和響應正文。
3.2.2 http訊息原始碼分析
1 客戶端請求解析
客服端的請求處理其實就是將請求拆解,分解各個欄位,提取出header中的資訊。
首先,uhttpd會將收到的請求存放在一個buffer中。在uhttpd中有一個狀態機來處理http請求
這三個狀態分別用來處理客服端請求中的請求行(requestline)、請求頭部(header)、請求資料。
1.CLIENT_STATE_INIT
狀態-處理請求行,在Init狀態中,呼叫staticbool client_init_cb(struct client *cl, char *buf, int len)函式來method,url, version
獲取成功後將狀態變為CLIENT_STATE_HEADER
2. CLIENT_STATE_HEADER
狀態--處理請求頭部,呼叫staticbool client_header_cb(struct client *cl, char *buf, intlen)函式來解析requestheader;
解析的方式就是staticbool client_header_cb(struct client *cl, char *buf, intlen);函式中通過/r/n作為標誌將buffer中的資料一行一行讀入。然後將每一行資料通過“:”為標誌存到結構體中傳入staticvoid client_parse_header(struct client *cl, char *data);函式中來獲取檔案頭。
這兩個函式中將buffer中的httpheader按照字串解析的方式取出有用資訊,存放到client結構體中。當buffer中全部解析完成之後狀態切換到CLIENT_STATE_DATA;
3. CLIENT_STATE_DATA
處理請求資料,呼叫函式voidclient_poll_post_data(struct client *cl)
沒看明白……大概是按照content-length取出資料。╮(╯_╰)╭
2 伺服器響應訊息處理
Uhttpd在完成CLIENT_STATE_HEADER處理的時候會呼叫uh_handle_request(cl)函式來處理客戶端的請求。
響應主要是處理url並返回狀態碼。響應的處理主要在file.c檔案中進行處理。簡單的就是講url當做是相對於www資料夾的檔案路徑來查詢檔案。比如p.to/cgi-bin,其中“/cgi-bin”就會進入file.c檔案處理。在www資料夾下尋找cgi-bin。
file.c檔案的函式入口在voiduh_handle_request(struct client *cl);
在這個函式中呼叫staticbool __handle_file_request(struct client *cl, char *url)來處理請求;
其中又呼叫了static struct path_info *uh_path_lookup(struct client*cl, const char *url)函式來尋找路徑。
其中,在uh_path_lookup()函式中,當url訪問的是一個目錄,但是url中沒有“/”的時候會轉跳到302,將url加上“/”
這裡面的path_phys[docroot_len]為根目錄,K2中就是www資料夾,預設將重定向到根資料夾中。
p.query ? "?" : "",
p.query ? p.query : "");用來提取query資訊,也就是url中的查詢資訊。
我們可以在這裡通過location欄位對url進行重定向。
附錄
1幾個重要的結構體
存放客戶端資料的結構體client.
其中,uh_addr結構體
可以用來表示一個32位的IPv4地址
得到local_addr,就是我們的lanip。
存放http請求和響應的欄位
2配置引數讀入
Uhttpd的引數位於uhttpd.config檔案中。在main.c的main函式中通過while迴圈讀入配置引數;