本文是上篇" TNSAnalysis " 的修改版。
参考文档:oracle_tns协议.doc ( http://download.csdn.net/detail/afer198215/4413480 )
建立连接时,oracle客户端先向oracle服务器 发送客户端可以使用的最高tns版本连接请求包,服务器会回应一个等于或小于客户端要求tns版本的响应包,
服务器回应包中的tns版本才是双方通信的真实tns版本。
上篇TNSAnalysis的代码分析oracle10以上TNS协议存在问题,本文做部分修改。
以下代码可以分析出 请求类型、连接请求中的TNS协议版本、连接请求字符串、sql请求字符串
支持tns v312(oracle 9)、tns v313(oracle 10)及部分tns v314(oralce 11,尚不确定sql解析是否正确)。
package org.sl.analysis.tns;
import org.sl.util.Utility;
/**
* TNS分析接口
* @author shanl
*
*/
abstract
public class TNSAnalysis {
/**TNS请求头标志长度8*/
public static final int REQUEST_HEADER_LENGTH = 8;
/**请求类型:连接*/
public static final short REQUEST_TYPE_CONNECTION = 1;
/**请求类型:SQL*/
public static final short REQUEST_TYPE_SQL = 6;
/**响应类型:接收*/
public static final short RESPONSE_TYPE_RECEIVE = 2;
/**请求类型:未知*/
public static final short REQUEST_TYPE_UNKNOW = -1;
protected byte[] requestData = null;
protected int requestOffset = 0;
protected int requestLen = 0;
/**
* 设置tns请求数据,并返回请求类型
* @param request 请求数据
* @param offset 请求数据偏移量
* @param len 请求数据长度
* @return 返回请求类型
*/
public int setRequest(byte[] request, int offset, int len){
this.requestData = request;
this.requestOffset = offset;
this.requestLen = len;
return getRequestType();
}
/**
* 返回请求类型
* @return
*/
public int getRequestType(){
return requestData[requestOffset+4];
}
/**
* 返回连接请求的tns版本<br/>
* 只有当getRequestType()返回值为REQUEST_TYPE_CONNECTION有效.
* @return 如果当前请求类型不是REQUEST_TYPE_CONNECTION,那么返回-1.
*/
public int getRequestTNSVersion(){
int ver = -1;
if(REQUEST_TYPE_CONNECTION == getRequestType()){
ver = Utility.byte2Short(requestData, requestOffset+8);
}
return ver;
}
/**
* 返回连接请注字符串<br/>
* 只有当getRequestType()返回值为REQUEST_TYPE_CONNECTION有效.
* @return
*/
abstract public String getConnectData();
/**
* 返回sql请求字符串
* 只有当getRequestType()返回值为REQUEST_TYPE_SQL有效.
* @return
*/
abstract public String getSqlData();
}
package org.sl.analysis.tns;
import org.sl.util.Utility;
/**
* TNS版本313对应oracle 9.2
* @author shanl
*
*/
public class TNSV312 extends TNSAnalysis{
@Override
public String getConnectData() {
if(0x01!=this.requestData[4]){
return "";
}
int offset = REQUEST_HEADER_LENGTH;
// int dataLen = (0xff00&(data[offset+16]<<2)) | (0x00ff&data[offset+17]);
// int dataOffset = (0xff00&(data[offset+18]<<2)) | (0x00ff&data[offset+19]);
int dataLen = Utility.byte2Short(requestData, offset+16);
int dataOffset = Utility.byte2Short(requestData, offset+18);
byte[] buffer = new byte[dataLen];
int po = 0;
if(dataLen<=0){
return "";
}
for(int i=dataOffset,end=dataOffset+dataLen; i<end; i++,po++){
if(0x00!=this.requestData[i]){
buffer[po] = this.requestData[i];
}else{
buffer[po] = ' ';
}
}
// return new String(data, dataOffset, dataLen);
return new String(buffer,0,dataLen);
}
@Override
public String getSqlData() {
String sql = "";
int offset = 8+4;
if(0x03==requestData[10] && 0x5E==requestData[11]){
sql = parse035e(8+2);
}else if(0x11==requestData[10] && 0x69==requestData[11]){
sql = parse1169(offset);
}else if(0x11==requestData[10] && 0x6b==requestData[11]){
sql = parse116b(offset);
}else if(0x03==requestData[10] && 0x3E==requestData[11]){ //如果标志为01则skip=6*8
sql = parse033e01(offset);
}else if(0x03==requestData[10] && 0x47==requestData[11]){ //如果标志为01则skip=15*8+5
sql = parse034701(offset);
}else{
// System.out.println("type:"+Integer.toHexString(data[10])+","+Integer.toHexString(data[11]));
}
return sql;
}
public String parse034701(int _offset){
String sql = "";
int offset = _offset+12;
int skip = 6*8+1;
if(0x01==requestData[_offset+5] || 0x02==requestData[_offset+5]){
sql = parse03xx01(offset, skip);
}else if(0x03==requestData[_offset+12]){
sql = parse035e(offset);
}else{
sql = "";
}
return sql;
}
public String parse033e01(int _offset){
String sql = "";
int offset = _offset+12;
int skip = 15*8+5;
if(0x01==requestData[_offset+5] || 0x02==requestData[_offset+5]){
sql = parse03xx01(offset, skip);
}else if(0x03==requestData[_offset+12]){
sql = parse035e(offset);
}else{
sql = "";
}
return sql;
}
private String parse03xx01(int offset, int skip){
String sql = "";
int c = offset;
int len = 0;
int position = 0;
byte[] buffer = new byte[this.requestLen];
// if(0x01==requestData[offset] || 0x02==requestData[offset]){
// //is sql
// }else{
// return "";
// }
c += skip;
if((byte)0xFE == requestData[c]){
do{
len = requestData[++c];
for(int i=c+1,end=i+len; i<end; i++){
if(0x00 != requestData[i]){
buffer[position++] = requestData[i];
}else{
buffer[position++] = ' ';
}
}
c += len;
}while(len!=0);
}else{//非大数量
len = requestData[c];
for(int i=c+1,end=i+len; i<end; i++){
if(0x00 != requestData[i]){
buffer[position++] = requestData[i];
}else{
buffer[position++] = ' ';
}
}
}
sql = new String(buffer, 0, position);
return sql;
}
public String parse035e(int offset){
String sql = "";
byte[] buffer = new byte[this.requestLen];
int skip = 81;
int c = offset;
int len = 0;
int position = 0;
if(0x03!=requestData[c++] || 0x5e!=requestData[c++]){
// System.out.println("非sql请求.");
return "";
}
c += skip;
if((byte)0xFE == requestData[c]){
do{
len = requestData[++c];
for(int i=c+1,end=i+len; i<end; i++){
if(0x00 != requestData[i]){
buffer[position++] = requestData[i];
}else{
buffer[position++] = ' ';
}
}
c += len;
}while(len!=0);
}else{//非大数量
len = requestData[c];
for(int i=c+1,end=i+len; i<end; i++){
if(0x00 != requestData[i]){
buffer[position++] = requestData[i];
}else{
buffer[position++] = ' ';
}
}
}
sql = new String(buffer, 0, position);
return sql;
}
public String parse116b(int offset){
int _offset = offset+1+12;
return parse035e(_offset);
}
public String parse1169(int offset){
int _offset = offset+1+12;
return parse035e(_offset);
}
}
package org.sl.analysis.tns;
import org.sl.util.Utility;
/**
* TNS版本313对应oracle 10
* @author shanl
*
*/
public class TNSV313 extends TNSAnalysis{
@Override
public String getConnectData() {
if(0x01!=this.requestData[4]){
return "";
}
int offset = REQUEST_HEADER_LENGTH;
// int dataLen = (0xff00&(data[offset+16]<<2)) | (0x00ff&data[offset+17]);
// int dataOffset = (0xff00&(data[offset+18]<<2)) | (0x00ff&data[offset+19]);
int dataLen = Utility.byte2Short(requestData, offset+16);
int dataOffset = Utility.byte2Short(requestData, offset+18);
byte[] buffer = new byte[dataLen];
int po = 0;
if(dataLen<=0){
return "";
}
for(int i=dataOffset,end=dataOffset+dataLen; i<end; i++,po++){
if(0x00!=this.requestData[i]){
buffer[po] = this.requestData[i];
}else{
buffer[po] = ' ';
}
}
// return new String(data, dataOffset, dataLen);
return new String(buffer,0,dataLen);
}
@Override
public String getSqlData() {
String sql = "";
int offset = 8+4;
if(0x03==requestData[10] && 0x5E==requestData[11]){
sql = parse035e(8+2);
}else if(0x11==requestData[10] && 0x69==requestData[11]){
sql = parse1169(offset);
}else if(0x11==requestData[10] && 0x6b==requestData[11]){
sql = parse116b(offset);
}else if(0x03==requestData[10] && 0x3E==requestData[11]){ //如果标志为02则skip=6*8
sql = parse033e01(offset);
}else if(0x03==requestData[10] && 0x47==requestData[11]){ //如果标志为02则skip=15*8+5
sql = parse034701(offset);
}else{
// System.out.println("type:"+Integer.toHexString(data[10])+","+Integer.toHexString(data[11]));
}
return sql;
}
public String parse034701(int _offset){
String sql = "";
int offset = _offset+12;
int skip = 6*8+1;
if(0x01==requestData[_offset+5] || 0x02==requestData[_offset+5]){
sql = parse03xx01(offset, skip);
}else if(0x03==requestData[_offset+12]){
sql = parse035e(offset);
}else{
sql = "";
}
return sql;
}
public String parse033e01(int _offset){
String sql = "";
int offset = _offset+12;
int skip = 15*8+5;
if(0x01==requestData[_offset+5] || 0x02==requestData[_offset+5]){
sql = parse03xx01(offset, skip);
}else if(0x03==requestData[_offset+12]){
sql = parse035e(offset);
}else{
sql = "";
}
return sql;
}
private String parse03xx01(int offset, int skip){
String sql = "";
int c = offset;
int len = 0;
int position = 0;
byte[] buffer = new byte[this.requestLen];
// if(0x01==requestData[offset] || 0x02==requestData[offset]){
// //is sql
// }else{
// return "";
// }
c += skip;
if((byte)0xFE == requestData[c]){
do{
len = requestData[++c];
for(int i=c+1,end=i+len; i<end; i++){
if(0x00 != requestData[i]){
buffer[position++] = requestData[i];
}else{
buffer[position++] = ' ';
}
}
c += len;
}while(len!=0);
}else{//非大数量
len = requestData[c];
for(int i=c+1,end=i+len; i<end; i++){
if(0x00 != requestData[i]){
buffer[position++] = requestData[i];
}else{
buffer[position++] = ' ';
}
}
}
sql = new String(buffer, 0, position);
return sql;
}
public String parse035e(int offset){
String sql = "";
byte[] buffer = new byte[1024*1024*2];
int skip = 93;
int c = offset;
int len = 0;
int position = 0;
if(0x03!=requestData[c++] || 0x5e!=requestData[c++]){
// System.out.println("非sql请求.");
return "";
}
c += skip;
if((byte)0xFE == requestData[c]){
do{
len = requestData[++c];
for(int i=c+1,end=i+len; i<end; i++){
if(0x00 != requestData[i]){
buffer[position++] = requestData[i];
}else{
buffer[position++] = ' ';
}
}
c += len;
}while(len!=0);
}else{//非大数量
len = requestData[c];
for(int i=c+1,end=i+len; i<end; i++){
if(0x00 != requestData[i]){
buffer[position++] = requestData[i];
}else{
buffer[position++] = ' ';
}
}
}
sql = new String(buffer, 0, position);
return sql;
}
public String parse116b(int offset){
int _offset = offset+1+12;
return parse035e(_offset);
}
public String parse1169(int offset){
int _offset = offset+1+12;
return parse035e(_offset);
}
}
package org.sl.analysis.tns;
import java.io.UnsupportedEncodingException;
import org.sl.util.Utility;
/**
* TNS版本314对应oracle 11
* @author shanl
*
*/
public class TNSV314 extends TNSAnalysis{
@Override
public String getConnectData() {
if(0x01!=this.requestData[4]){
return "";
}
int offset = REQUEST_HEADER_LENGTH;
int dataLen = Utility.byte2Short(requestData, offset+16);
int dataOffset = Utility.byte2Short(requestData, offset+18)+10;
byte[] buffer = new byte[dataLen];
int po = 0;
if(dataLen<=0){
return "";
}
for(int i=dataOffset,end=dataOffset+dataLen; i<end; i++,po++){
if(0x00!=this.requestData[i]){
buffer[po] = this.requestData[i];
}else{
buffer[po] = ' ';
}
}
// return new String(data, dataOffset, dataLen);
try {
return new String(buffer,0,dataLen, "ISO-8859-1");
} catch (UnsupportedEncodingException e) {
return new String(buffer,0,dataLen);
}
}
@Override
public String getSqlData(){
throw new RuntimeException("未完成.");
}
public String getSqlDataV313() {
String sql = "";
int offset = 8+4;
if(0x03==requestData[10] && 0x5E==requestData[11]){
sql = parse035e(8+2);
}else if(0x11==requestData[10] && 0x69==requestData[11]){
sql = parse1169(offset);
}else if(0x11==requestData[10] && 0x6b==requestData[11]){
sql = parse116b(offset);
}else{
// System.out.println("type:"+Integer.toHexString(data[10])+","+Integer.toHexString(data[11]));
}
return sql;
}
public String parse035e(int offset){
String sql = "";
byte[] buffer = new byte[1024*1024*2];
int skip = 93;
int c = offset;
int len = 0;
int position = 0;
if(0x03!=requestData[c++] || 0x5e!=requestData[c++]){
// System.out.println("非sql请求.");
return "";
}
c += skip;
if((byte)0xFE == requestData[c]){
do{
len = requestData[++c];
for(int i=c+1,end=i+len; i<end; i++){
if(0x00 != requestData[i]){
buffer[position++] = requestData[i];
}else{
buffer[position++] = ' ';
}
}
c += len;
}while(len!=0);
}else{//非大数量
len = requestData[c];
for(int i=c+1,end=i+len; i<end; i++){
if(0x00 != requestData[i]){
buffer[position++] = requestData[i];
}else{
buffer[position++] = ' ';
}
}
}
sql = new String(buffer, 0, position);
return sql;
}
public String parse116b(int offset){
int _offset = offset+1+12;
return parse035e(_offset);
}
public String parse1169(int offset){
int _offset = offset+1+12;
return parse035e(_offset);
}
}
package org.sl.analysis.tns;
/**
* tns V312+V313
* @author shanl
*
*/
public class TNSV312_V313 extends TNSAnalysis{
TNSAnalysis v312 = new TNSV312();
TNSAnalysis v313 = new TNSV313();
@Override
public String getConnectData() {
String sql = "";
sql = v312.getConnectData();
if("".equals(sql)){
sql = v313.getConnectData();
}
return sql;
}
@Override
public String getSqlData() {
String sql = "";
sql = v312.getSqlData();
if("".equals(sql)){
sql = v313.getSqlData();
}
return sql;
}
}
package org.sl.analysis.tns;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import org.sl.util.Utility;
/**
* TNS分析器的工厂类
* @author shanl
*
*/
public class TNSAnalyFactory{
/**TNS版本312,对应oracle 9*/
public static final short TNS_VERSION_312 = 312;
/**TNS版本313,对应oracle 10*/
public static final short TNS_VERSION_313 = 313;
/**TNS版本314,对应oracle 11*/
public static final short TNS_VERSION_314 = 314;
/**未知的tns版本*/
public static final short TNS_VERSION_UNKNOW = -1;
private static Map<Short,Class<? extends TNSAnalysis>> dict = null;
static{
dict = new HashMap<Short,Class<? extends TNSAnalysis>>(20);
dict.put(TNS_VERSION_UNKNOW, TNSV312_V313.class);
dict.put(TNS_VERSION_312, TNSV312.class);
dict.put(TNS_VERSION_313, TNSV313.class);
dict.put(TNS_VERSION_314, TNSV314.class);
}
/**
* 注册一个指定版本的tns分析类
* @param tnsVersion
* @param analyClass
*/
synchronized
public static void registerTNSAnalyClass(short tnsVersion, Class<? extends TNSAnalysis> analyClass){
if(null==analyClass){
return;
}
dict.put(tnsVersion, analyClass);
}
/**
* 移除一个指定版本的tns分析类
* @param tnsVersion
* @return
*/
synchronized
public static Class<? extends TNSAnalysis> removeTNSAnalyClass(short tnsVersion){
return dict.remove(tnsVersion);
}
/**
* 得到一个当前已注册类合集的复本
* @return 不会返回null
*/
synchronized
public static Map<Short,Class<? extends TNSAnalysis>> duplicate(){
Map<Short,Class<? extends TNSAnalysis>> nd = new HashMap<Short,Class<? extends TNSAnalysis>>(20);
Set<Short> keys = dict.keySet();
if(keys.isEmpty()){
return nd;
}
for(Short key:keys){
nd.put(key, dict.get(key));
}
return nd;
}
/**
* 返回指定版本的分析类实例
* @param tnsVersion
* @return 如果找不到则返回v312+v313;否则,返回指定tns版本分析类实例.
*/
synchronized
public static TNSAnalysis getTNSAnalyInstance(Short tnsVersion){
TNSAnalysis instance = null;
Class<? extends TNSAnalysis> cs = null;
try{
if(dict.containsKey(tnsVersion)){
cs = dict.get(tnsVersion);
instance = cs.newInstance();
}else{
instance = new TNSV312_V313();
}
}catch(Exception ex){
throw new RuntimeException(ex.getMessage());
}
return instance;
}
/**
* 从请求中得到tns版本
* @param requestData
* @param offset
* @return 返回-1表示不是含有tns版本的请求
*/
synchronized
public static short getTNSVersionFromRequest(byte[] requestData, int offset){
short ver = -1;
if(TNSAnalysis.REQUEST_TYPE_CONNECTION==requestData[offset+4]){
ver = Utility.byte2Short(requestData, offset+8);
}
return ver;
}
/**
* 从响应中得到tns版本
* @param responseData
* @param offset
* @return 返回-1表示不是含有tns版本的响应
*/
synchronized
public static short getTNSVersionFromResponse(byte[] responseData, int offset){
short ver = -1;
if(TNSAnalysis.RESPONSE_TYPE_RECEIVE==responseData[offset+4]){
ver = Utility.byte2Short(responseData, offset+8);
}
return ver;
}
}
测试类:
package test;
import org.sl.analysis.tns.TNSAnalyFactory;
import org.sl.analysis.tns.TNSAnalysis;
import org.sl.analysis.tns.TNSV314;
public class Test6 {
public static void main(String[] args){
// t3();
t2();
// t1();
}
static void t3(){
String hexStr = ""
+"00F00000010000000138012C000008007FFF860E0000010000B6003A000"
+"002006161000000000000000000000D4C0001A4D8000000000000000028"
+"4445534352495054494F4E3D28414444524553533D2850524F544F434F4"
+"C3D5443502928484F53543D3139322E3136382E322E32332928504F5254"
+"3D31353231292928434F4E4E4543545F444154413D28534552564943455"
+"F4E414D453D697032356F72636C29284349443D2850524F4752414D3D443"
+"A5C746F6F6C735C504C53514C20446576656C6F7065725C504C53514C446"
+"5762E6578652928484F53543D504336372928555345523D7368616E6C29292929";
byte[] bys = new byte[hexStr.length()/2];
int hex = 0;
int c = 0;
int len = 0;
// TDSAnalyForSybase tds = new TDSAnalyForSybase();
for(int i=0,j=0,endi=hexStr.length(); i<endi; j++){
hex = Integer.valueOf(hexStr.substring(i, i+=2), 16);
bys[j] = (byte)hex;
}
short tnsVer = TNSAnalyFactory.getTNSVersionFromRequest(bys, 0);
System.out.println(tnsVer);
TNSAnalysis sis = TNSAnalyFactory.getTNSAnalyInstance(tnsVer);
sis.setRequest(bys, 0, bys.length);
System.out.println("request:"+sis.getConnectData());
}
static void t2(){
String hexStr = ""
// +"00200000020000000139000108007FFF01000000002061410000000000000000";
+"00200000020000000138000008007FFF01000000002061410000000000000000";
byte[] bys = new byte[hexStr.length()/2];
int hex = 0;
int c = 0;
int len = 0;
// TDSAnalyForSybase tds = new TDSAnalyForSybase();
for(int i=0,j=0,endi=hexStr.length(); i<endi; j++){
hex = Integer.valueOf(hexStr.substring(i, i+=2), 16);
bys[j] = (byte)hex;
}
short tnsVer = TNSAnalyFactory.getTNSVersionFromResponse(bys, 0);
System.out.println(tnsVer);
}
static void t1(){
String hexStr = ""
+"003A000001000000013A012C004120007FFFC60E0000010000EF003A00"
+"0008006161000000000000000000000000000000000000000000000000"
+"00F90000060000000000284445534352495054494F4E3D28434F4E4E45"
+"43545F444154413D285345525645523D44454449434154454429285345"
+"52564943455F4E414D453D697032356F72636C29284349443D2850524F"
+"4752414D3D433A5C446F63756D656E74733F616E643F53657474696E67"
+"735C41646D696E6973747261746F725C3F3F3F3F5C506C53716C446576"
+"2E6578652928484F53543D4E44544B4D4B574C38455954503542292855"
+"5345523D41646D696E6973747261746F7229292928414444524553533D"
+"2850524F544F434F4C3D5443502928484F53543D3139322E3136382E32"
+"2E32332928504F52543D31353231292929";
byte[] bys = new byte[hexStr.length()/2];
int hex = 0;
int c = 0;
int len = 0;
// TDSAnalyForSybase tds = new TDSAnalyForSybase();
for(int i=0,j=0,endi=hexStr.length(); i<endi; j++){
hex = Integer.valueOf(hexStr.substring(i, i+=2), 16);
bys[j] = (byte)hex;
}
TNSAnalyFactory.registerTNSAnalyClass((short) 314, TNSV314.class);
short tnsVer = TNSAnalyFactory.getTNSVersionFromRequest(bys, 0);
System.out.println("tns version:"+tnsVer);
TNSAnalysis sis = TNSAnalyFactory.getTNSAnalyInstance(tnsVer);
sis.setRequest(bys, 0, bys.length);
System.out.println("connect:"+sis.getConnectData());
}
}