在編寫TCP程式的時候,對于服務端,accept成功傳回的時候,就一定意味着某個用戶端已經成功建立了TCP連接配接嗎?對于用戶端,connect成功傳回就一定意味着自己成功連接配接上服務端了麼?遠遠不是!
accept/connect這兩個socket調用完全是基于TCP三向交握狀态機的,即隻要本地TCP狀态機進入ESTABLISH狀态,就會成功返 回。而我們知道,TCP的三次握手本身就是一次權衡的結果。為什麼不是四次握手呢?為什麼不是五次呢?...問題可以一直這麼問下去。
事實上,用戶端完全可以在收到syn-ack之後,發送最後一個ack之後不辭而别,服務端也可以在收到syn之後,發送syn-ack之後不辭而别,從 此再也不問世事,對于對端而言,accept/connect顯然會成功傳回,因為對端的狀态機已經轉換到了ESTABLISH,它們無法意識到自己被耍 弄了。對于TCP而言,它作為一個基于連接配接的端到端協定,和我們的工作很類似,入職的時候,要簽訂合同,離職的時候,要辦理離職手續,對于不辭而别者,你 能做的大多數隻能是嘲諷。可是對于TCP而言,卻可以用上述這種不辭而别手段來提高自己的“每秒建立連接配接數”用來欺騙比較低級的測試工具,或者嘲弄那些知 其然不知其是以然的應聘者(作為一塊有效的試金石,有時真的要問那些應聘者一些這類問題,它們要比讓應聘者寫個握手過程,寫個socket程式,解釋一下 socket函數的參數要有效的多)。
對于上述的不辭而别,欺騙用戶端要比欺騙服務端更加容易,因為對于服務端而言,存在一個socket option,叫做TCP_DEFER_ACCEPT,它在收到用戶端的第一筆資料之前,抑制accept的傳回,當然,它僅僅針對用戶端首先發送第一筆 資料的應用層協定(比如HTTP協定)有效。
如果是我在考察應聘者對TCP程式設計的了解,我會讓他們寫一個或者了解一個全程的欺騙程式,将TCP的連接配接ack機制轉換為挑戰/應答模式:
欺 騙用戶端:編寫一個欺騙服務端,持續執行且僅僅執行下面的邏輯:1.隻要收到syn,就計算一個初始序列号,構造并回複syn-ack;2.隻要收到數 據,就基于這段資料的TCP頭資訊構造純ack包回應之;3.隻要收到fin,自己就ack掉它,然後也發一個fin;4.自己決不主動發起任何資料。
欺騙服務端:這個也不難...
至 于如何拿到TCP資料而不是讓其進入協定棧,這在實作上是重要的,可以考察應聘者對系統的熟悉程度。為何不能進入協定棧呢?因為進入協定棧就将進入标準的 正确的處理流程,一般會被RST...那麼如何拿到資料呢?辦法太多了,包括但不限于:1.使用PACKET套接字;2.使用PF_RING;3.使用 TUN/TAP網卡;4.使用Netfilter queue機制;5.直接改核心...
以上的那些工作真的有意義嗎?正常地講,沒有任何意義,即便你通過這種方式使自己的伺服器達到了超極高的并發,一旦被發現,估計就不僅僅是技術範疇的問題 的。事實上,做上面的事的意義在于,至此你将明白什麼是“一個TCP連接配接”,确切地說,一個TCP連接配接包括兩個無誤的狀态機,而不僅僅是一個,一個TCP 連接配接在概念上和網絡沒有任何關系,是以為“端到端協定”,對于上述的行為,顯然在不辭而别或者挑戰應答的那一端沒有維護一個無誤的狀态機,是以就不是一個 完整無誤的TCP連接配接,基于TCP連接配接的性能測試比如建立TCP連接配接數測試就必須可以檢測到這種情況。是以說,這種測試必須包含業務範疇的挑戰/應答資料 的傳輸,即,再次重申:你可以telnet成功某個IP的某個端口,并不意味着一定有某個服務在為你開啟。換句話說,隻要能拿到資料包,怎麼處理就是自己 的事了,如果在對端看來你看起來像個正常的協定棧,你就可以欺騙他們了,處在兩地的兩個端作為一個整體缺乏一種集體自省機制...
缺乏自省機制是必然的,因為一旦有了自省機制,那麼網絡就真的變成了智能生物...計算機擁有處理任意複雜資料的能力,遺憾的是,它自己并不知道自己有這 種能力。深入思考這個問題是有意思的,我知道我姓趙,但是我自己知道“我我知道我姓趙”這件事嗎?“我最害怕天黑”和“我承認我最害怕天黑”是完全不同 的。
本文轉自 dog250 51CTO部落格,原文連結:http://blog.51cto.com/dog250/1605093