欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Oracle TNS 协议分析:方法论及基础知识入门

程序员文章站 2022-04-14 14:06:55
本系列重点分析TNS 314下的客户端与服务端之间的通讯,通过抓包分析,查看在不同客户端,不同服务端情况下传输方式的不同,尝试还原其协议细节,实现对协议中一些关键内容的解析,如登录用户名,协议版本,oracle版本,sql命令,同时给出示例LUA代码。为了分析不同客户端架构,本系列使用了两类客户端3... ......

前言

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两个版本。本文主要分析连接建立,身份验证、命令传输和返回、以及错误信息返回的过程。

方法及工具

主要采用wireshark对客户端与oracle间的通讯进行抓包分析。

客户端:

服务端

navicat premium 15 64bit

oracle 11g 64bit linux

navicat premius 12 32bit

oracle 12c 64bit windows

plsql 11.2 64bit


sqlplus 11.2 64bit


ojdbc8(thin client)


分析过程中关于包类型定义等参考wireshark的tns 解析器代码。

代码示例说明

代码示例用lua写成,可以在openresty15 64bit window或linux版本下运行

其中从socket流中解码用到了string.unpack 和pack 方法是纯lua开源实现,是对c语言 lua 扩展lpack 的纯lua模拟

系列目录

四、sql执行流程与包分析

协议介绍

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协议版本对应关系

oracle 版本

tns版本

11gr2 12c

tns314

10g

313

9i

312

x

311

8i

310

 

不同driver的差异

oracle client调用服务端,最终实现模式主要是 oci和thindriver。

  1. oci是c 语言的lib,和平台相关,有linux和windows 版本;
  2. thindriver是纯java的包,与平台无关;

很多人反映反编译java代码看到的情况和用plsql等工具调用实现不同,大概率是此原因,但无论navicat,sqlplus,plsql都走的oci。相应jdbc有两种

  1. jdbc oci driver 走oci调用,
  2. jdbc thin driver走 纯java实现

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

变长

变长

 

原文来自:https://www.cnblogs.com/yizhu2000/p/12866520.html