OpenVPN協議解析-握手資料包分析
阿新 • • 發佈:2018-12-19
學習一種協議的最好的方式就是研究它的資料包,這樣可以加深對協議的理解。對於研究過某種協議資料包的傢伙來講,他一定知道協議頭的哪個位置對應哪個欄位,雖然這對於理解協議為什麼這麼設計可能沒有太大的幫助,然而對於排查問題和實際實施是很有幫助的。既然很多人都對Richard Stevens的《TCP/IP詳解》情有獨鍾,咱就剽竊他的風格,解析一下OpenVPN的握手是如何完成的。本文分析70餘個資料包,當然,最終我會略去重複的內容,來看看OpenVPN的握手協商過程。 |xx|xx|xx|xx|xx|xx|xx|xx|: 包id和時間戳,包括ack包的id和時間戳,在該方向每法送一個包,包id都會遞增。8位元組|xx|[...|xx|...]:如果ack buffer length長度為0,沒有ack資訊,如果不為0,則後面包含確認的包序列號,然後追加一個對端的session id,變長|xx|xx|xx|xx|:包序列號,不包括ack包,也就是說,傳送一個非P_ACK包,包序列號才會遞增,實際上如果是P_ACK包,根本就沒有這一行欄位。4位元組
1.分析前的解釋
1.1.資料包格式
本文以如下格式分析每一個握手資料包,具體OpenVPN資料包的格式,請參閱《OpenVPN協議解析-網路結構之外》:1.1.1.本文為了節省篇幅,省去了UDP以下各層的資料,直接從OpenVPN的封裝開始。
1.1.2.以下為資料包格式,xx為十六進位制位元組:
A->B:方向,分別為Server->Client和Client->Server|xx|:操作碼+key id,1位元組,xx右移5位就是操作碼|xx|xx|xx|xx|xx|xx|xx|xx|:session ID,這個ID是單方向的,8位元組|xx|xx|xx|xx|xx|xx|xx|xx|1a|de|38|06|ab|5e|55|0f|8f|ed|ea|ca|:資料包訊息MAC,本文啟用tls-auth選項,本文MAC長度20位元組(使用SHA1)1.2.TLS/SSL握手協議
關於TLS/SSL握手協議,最好的資料是RFC,然後或許看OpenSSL的原始碼上手更快些。這裡僅給出幾個圖示和幾點解釋,SSL握手協議包格式如下:不管是記錄協議還是握手協議,都會有一個record header,該record格式如下:
其中,如果是SSL握手協議的話,record header的type欄位為0x16,我們使用的TLS,因此其major和minor分別為0x03和0x01。接下來,我們看一下握手頭:
其中握手型別分別為:
Client hello:0x01Server hello:0x02Certificate:0x0bServer key exchange:0x0cCertificate request:0x0dServer hello done:0x0eCertificate verify:0x0fClient key exchange:0x10Finish:0x141.3.SSL握手協議和OpenVPN握手的關係
我們知道,OpenVPN的連線建立使用了SSL握手協議,可是卻抓不到SSL握手包,實際上SSL握手協議是作為一種載荷封裝在了OpenVPN的協議包裡面了,SSL握手協議資料實際上是寫入了一塊記憶體,然後OpenVPN從該記憶體中讀出這些資料包,然後封裝後通過reliable層發出,資料到達對端後,解封裝後寫入一塊記憶體,然後SSL從記憶體中讀出SSL握手載荷,一切都是通過BIO實現的。(如不甚理解,請參閱《OpenVPN協議解析-網路結構之外》)可以看出,SSL和OpenVPN屬於不同的層次,SSL握手協議在OpenVPN握手協議之上,然而當SSL握手結束後,OpenVPN的金鑰協議又在SSL記錄協議協議之上,更清晰的圖示如下所示:
因此,OpenVPN握手協議可以將SSL握手載荷隨意拆分和合並,它們通過BIO建立的記憶體區域建立唯一的聯絡。