Oracle 客戶端與服務端採用TNS做爲其數據交換協議。TNS全稱Transparent Network Substrate,是與Oracle數據庫服務器通信的專有協議,該協議爲Oracle內部協議,不向外界公開,在此以前,已經有一些反向工程的實踐對各個版本的TNS進行解析,好比wireshark就有專門的TNS分析工具,中文的協議解析可參見《ORACLE協議分析》本系列基礎介紹中關於TNS包基礎格式,及鏈接包等均沿用wireshark提供的格式。本系列重點分析TNS 314下的客戶端與服務端之間的通信,經過抓包分析,查看在不一樣客戶端,不一樣服務端狀況下傳輸方式的不一樣,嘗試還原其協議細節,實現對協議中一些關鍵內容的解析,如登陸用戶名,協議版本,oracle版本,sql命令,同時給出示例LUA代碼。爲了分析不一樣客戶端架構,本系列使用了兩類客戶端32位與64位客戶端進行測試,同時重點使用了多個廠商的不一樣客戶端(Navicat、PLSQL、SQLPlus)同時也兼顧分析了OJDBC Thin Client的狀況。服務端採用11g和12c兩個版本。本文主要分析鏈接創建,身份驗證、命令傳輸和返回、以及錯誤信息返回的過程。html
主要採用wireshark對客戶端與Oracle間的通信進行抓包分析。linux
客戶端:sql |
服務端數據庫 |
Navicat Premium 15 64bitwindows |
Oracle 11g 64bit Linux服務器 |
Navicat Premius 12 32bit架構 |
Oracle 12c 64bit windowsoracle |
PLSQL 11.2 64bitsocket |
|
SQLPlus 11.2 64bit工具 |
|
OJDBC8(Thin Client) |
|
分析過程當中關於包類型定義等參考wireshark的tns 解析器代碼。
代碼示例用lua寫成,能夠在openresty15 64bit window或linux版本下運行
其中從socket流中解碼用到了string.unpack 和pack 方法是純lua開源實現,是對c語言 lua 擴展lpack 的純lua模擬
Transparent Network Substrate顧名思義是對傳輸層協議無關,根據Oracle的介紹:TNS底層支持TCP,SSL TP,SDP,named pipeline等協議。在OSI七層協議體系中,TNS屬於會話層協議
詳細的介紹可參考
https://docs.oracle.com/cd/B28359_01/network.111/b28316/architecture.htm#NETAG004
Oracle 版本 |
TNS版本 |
11gr2 12c |
tns314 |
10g |
313 |
9i |
312 |
X |
311 |
8i |
310 |
Oracle Client調用服務端,最終實現模式主要是 OCI和ThinDriver。
不少人反映反編譯Java代碼看到的狀況和用plsql等工具調用實現不一樣,大機率是此緣由,但不管Navicat,SQLPlus,PLSQL都走的OCI。相應JDBC有兩種
ThinDriver的實現與OCI的實現從抓包上看,在鏈接創建和認證過程差距不大,但Data包差距很大,不管Endian模式,仍是具體數據類型封裝格式都有較大差別,在ThinDriver的實現中,不多未見出現Piggy Command的狀況,全部非0或大於一位的byte或者int變量都會嚴格前序長度字段。
相同位數(都是64位或者都是32位)的不一樣客戶端的實如今抓包分析時也不太相同,大概表現有兩個方面,一個是流程上的不一樣,一個是數據上的不一樣,咱們以執行select語句爲例,PLSQL和Navicat在流程上稍有差異,下圖是Navicat Premium15 執行的流程
1 |
------- |
Data Piggyback(11) Cursor Close All(69) 注意此處也有多是 03 5e |
-----> |
具體語句 |
2 |
<----- |
Data DescribeInfo(10) 17 |
------- |
返回列 |
3 |
------- |
Data UOCIFun(03) ExecuteARow(04) |
-----> |
|
4 |
<----- |
Data ReturnStatus(04) |
------- |
|
5 |
------- |
Data UOCIFun(03) FetchARow(05) |
-----> |
獲取其餘值 |
6 |
<----- |
Data RowTransferHeader(06) 01 |
------- |
返回值 |
而PLSQL中沒有中間3和4的部分。
數據上的不一樣有的時候是一些數據長度,有的時候是一些設置位上的差別,好比對於select 的Piggycommand(pagekage type 0x6 DataId=0x11 CallID=0x69)
這個包內容在Sqlplus,plsql,navicat上不只內容,長度也就有差別
語句 |
Plsql |
Sqlplus |
Navicat |
Select |
fe ff ff ff ff ff ff ff 01 00 00 00 04 00 00 00 |
fe ff ff ff ff ff ff ff 01 00 00 00 00 00 00 00 05 00 00 00 當沒有輸入;05會變03 |
fe ff ff ff ff ff ff ff 01 00 00 00 05 00 00 00 |
32位客戶端和64位客戶端也有不一樣,好比32位客戶端中全部0xfe ff ff ff ff ff ff ff 所有以其補碼01代替。但64bit 的ThinClient也有此狀況,因此很難說這些現象是否徹底由位數形成,這會致使許多協議中許多部分的長度根據位數不一樣有必定區別。文中凡協議均會標註出不一樣客戶端位數下的長度,若未單獨標註,則說明兩者無不一樣,例如Buddle execute Command命令格式:
|
32bit |
64bit |
|
序列號 |
1 |
1 |
|
Piggy command |
9 or 13 |
16 or 20 |
|
Buddle execute command 035e |
變長 |
變長 |