-
Notifications
You must be signed in to change notification settings - Fork 15
/
Copy pathtds.lua
157 lines (147 loc) · 5.59 KB
/
tds.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
require "suproxy.utils.stringUtils"
require "suproxy.utils.pureluapack"
local event=require "suproxy.utils.event"
local ok,cjson=pcall(require,"cjson")
if not ok then cjson = require("suproxy.utils.json") end
local logger=require "suproxy.utils.compatibleLog"
local tdsPacket=require "suproxy.tds.tdsPackets"
local tableUtils=require "suproxy.utils.tableUtils"local _M = {}
_M._PROTOCAL ='tds'
function _M.new(self,options)
local o= setmetatable({},{__index=self})
options=options or {}
o.disableSSL=true
if options.disableSSL~=nil then o.disableSSL=options.disableSSL end
o.catchReply=false
if options.catchReply~=nil then o.catchReply=options.catchReply end
o.BeforeAuthEvent=event:newReturnEvent(o,"BeforeAuthEvent")
o.OnAuthEvent=event:newReturnEvent(o,"OnAuthEvent")
o.AuthSuccessEvent=event:new(o,"AuthSuccessEvent")
o.AuthFailEvent=event:new(o,"AuthFailEvent")
o.CommandEnteredEvent=event:newReturnEvent(o,"CommandEnteredEvent")
o.CommandFinishedEvent=event:new(o,"CommandFinishedEvent")
o.ContextUpdateEvent=event:new(o,"ContextUpdateEvent")
o.ctx={}
local tdsParser=require ("suproxy.tds.parser"):new(o.catchReply)
o.C2PParser=tdsParser.C2PParser
o.S2PParser=tdsParser.S2PParser
o.C2PParser.events.SQLBatch:addHandler(o,_M.SQLBatchHandler)
o.C2PParser.events.Prelogin:addHandler(o,_M.PreloginHandler)
o.C2PParser.events.Login7:addHandler(o,_M.Login7Handler)
o.S2PParser.events.LoginResponse:addHandler(o,_M.LoginResponseHandler)
o.S2PParser.events.SSLLoginResponse:addHandler(o,_M.LoginResponseHandler)
o.S2PParser.events.SQLResponse:addHandler(o,_M.SQLResponseHandler)
return o
end
----------------parser event handlers----------------------
function _M:SQLBatchHandler(src,p)
if self.CommandEnteredEvent:hasHandler() then
local cmd,err=self.CommandEnteredEvent:trigger(p.sql,self.ctx)
if err then
self.channel:c2pSend(tdsPacket.packErrorResponse(err.message,err.code))
p.allBytes=nil
return
end
end
ngx.ctx.sql=p.sql
end
function _M:PreloginHandler(src,p)
if p.options.Encryption and self.disableSSL then
p.options.Encryption=2
--self.ctx.serverVer=p.options.Version.versionNumber
p:pack()
end
end
function _M:Login7Handler(src,p)
local cred
if self.BeforeAuthEvent:hasHandler() then
cred=self.BeforeAuthEvent:trigger({username=p.username,password=p.password},self.ctx)
end
if self.OnAuthEvent:hasHandler() then
local ok,message,cred=self.OnAuthEvent:trigger({username=p.username,password=p.password},self.ctx)
if not ok then
self.channel:c2pSend(tdsPacket.packErrorResponse(message or "login with "..p.username.." failed",18456))
p.allBytes=nil
return
end
end
if cred and (p.username~=cred.username or p.password~=cred.password) then
print(p.username,cred.username,p.password,cred.password)
p.username=cred.username
p.password=cred.password
p:pack()
end
self.ctx.username=p.username
self.ctx.client=p.appName
self.ctx.clientVer=p.ClientProgVer:hex()
self.ctx.libName=p.libName
self.ctx.tdsVer=p.TDSVersion:hex()
if self.ContextUpdateEvent:hasHandler() then
self.ContextUpdateEvent:trigger(self.ctx)
end
end
function _M:LoginResponseHandler(src,p)
if p.success then
if self.AuthSuccessEvent:hasHandler() then
self.AuthSuccessEvent:trigger(self.ctx.username,self.ctx)
end
self.ctx.serverVer=p.serverVersion.versionNumber
self.ctx.tdsVer=p.TDSVersion:hex()
if self.ContextUpdateEvent:hasHandler() then
self.ContextUpdateEvent:trigger(self.ctx)
end
else
if self.AuthFailEvent:hasHandler() then
self.AuthFailEvent:trigger({username=self.ctx.username,message="["..p.errNo.."]"..p.message},self.ctx)
end
end
end
function _M:SQLResponseHandler(src,p)
if self.CommandFinishedEvent:hasHandler() then
local reply=p.tostring and p:tostring() or ""
reply=reply
self.CommandFinishedEvent:trigger(ngx.ctx.sql,reply,self.ctx)
end
end
----------------implement processor methods---------------------
local function recv(self,readMethod)
local headerBytes,err,partial=readMethod(self.channel,8)
if(err) then
logger.log(logger.ERR,"err when reading header",err)
return partial,err
end
local packet=tdsPacket.Packet:new()
local pos=packet:parseHeader(headerBytes)
local payloadBytes,err,allBytes
if(packet.code==0x17) then
local _,_,_,dataLength=string.unpack(">BBBI2",headerBytes)
payloadBytes,err=readMethod(self.channel,dataLength-3)
allBytes=headerBytes..payloadBytes
else
local dataLength=packet.dataLength
payloadBytes,err=readMethod(self.channel,dataLength-8)
allBytes=headerBytes..payloadBytes
end
return allBytes
end
function _M.processUpRequest(self)
local readMethod=self.channel.c2pRead
local allBytes,err=recv(self,readMethod)
if err then return nil,err end
local p=self.C2PParser:parse(allBytes)
ngx.ctx.upPacket=p.code
return p.allBytes
end
function _M.processDownRequest(self)
local readMethod=self.channel.p2sRead
local allBytes,err=recv(self,readMethod)
if err then return nil,err end
local p =self.S2PParser:parse(allBytes,nil,ngx.ctx.upPacket)
return p.allBytes
end
function _M:sessionInvalid(session)
self.channel:c2pSend(tdsPacket.packErrorResponse("you are not allowed to connect, please contact the admin"))
ngx.exit(0)
end
return _M