root/trunk/lua/lib.proxy.lua @ 3232

Revision 3232, 14.5 kB (checked in by ghoulsblade, 8 months ago)
packet debugging utils
Line 
1-- uoproxy for debugging
2
3function UOProxyOpenListener (port)
4        local timeout = Client_GetTicks() + 5*1000
5        local listener
6        repeat
7                listener = NetListen(port)
8                if (not listener) then print("port listen bind fail, retrying...") Client_USleep(1 * 1000) end
9        until listener or Client_GetTicks() > timeout
10        assert(listener,"failed to bind to local port "..(port or 0))
11        return listener
12end
13function UOProxyMode (host,port)
14        print("starting proxy mode")
15        print("host:",host,"port:",port)
16       
17        gProxyHost = host
18        gProxyPort = port
19        gProxyPort2 = port+1
20       
21        gServerListenerTCP = UOProxyOpenListener(gProxyPort)
22        gServerListenerTCP2 = UOProxyOpenListener(gProxyPort2)
23       
24        print("listen port opened....")
25               
26        while true do
27                local listener = gServerListenerTCP
28                while true do
29                        local newcon = listener:PopAccepted()
30                        if (not newcon) then break end
31                        print("###############################")
32                        print("#### PROXY : connection started, listener=",(listener == gServerListenerTCP) and "A" or "B")
33                        print("###############################")
34                        UOProxyOneConnection(newcon)
35                        print("###############################")
36                        print("#### PROXY : connection ended")
37                        print("###############################")
38                        listener = gServerListenerTCP2
39                        --~ print("proxy end") return
40                end
41                Client_USleep(10) 
42                NetReadAndWrite()
43        end
44
45end
46
47-- compressed Gump
48-- see also function gPacketHandler.kPacket_Compressed_Gump ()  --0xDD
49function ProxyParseCompressedGumpPacket (input) 
50        local popped_start = input:GetTotalPopped()
51        local id = input:PopNetUint8()
52        local size = input:PopNetUint16()
53        local newgump = {}
54
55        newgump.playerid = input:PopNetUint32()
56        newgump.dialogId = input:PopNetUint32()
57        newgump.x = input:PopNetUint32()
58        newgump.y = input:PopNetUint32()
59
60        newgump.Length_CompressedData = input:PopNetUint32() - 4
61        newgump.Length_Data = input:PopNetUint32()
62
63        assert(28 + newgump.Length_CompressedData <= size)
64
65        --- Data Part ---
66        local decompressed = CreateFIFO()
67        -- pop and decompress data into decompress fifo
68        input:PeekDecompressIntoFifo(newgump.Length_CompressedData,newgump.Length_Data,decompressed)
69        -- skip compressed part (peeked)
70        input:PopRaw(newgump.Length_CompressedData)
71        newgump.Data = decompressed:PopFilledString(decompressed:Size())
72        -- and clear the decompress fifo for later usage
73        decompressed:Clear()
74       
75        -- WARNING  strange -4 on compression ahead (see runuo2 source)
76        --- Textlines Part ---
77        newgump.numTextLines = input:PopNetUint32()
78
79        if (newgump.numTextLines ~= 0) then
80                newgump.Length_CompressedTextLines = input:PopNetUint32() - 4
81                newgump.Length_TextLines = input:PopNetUint32()
82       
83                -- pop and decompress data into decompress fifo
84                input:PeekDecompressIntoFifo(newgump.Length_CompressedTextLines,newgump.Length_TextLines,decompressed)
85                -- skip compressed part (peeked)
86                input:PopRaw(newgump.Length_CompressedTextLines)
87               
88                -- print gumpdata
89                for k,v in pairs(newgump) do printdebug("gump",sprintf("newgump.%s = ",k),v) end
90               
91                local textlen = 0
92                newgump.textline = {}
93                newgump.textline_unicode = {}
94                --Index 0 because Serverside Gump Commands use this Index as textline references
95                for i = 0,newgump.numTextLines-1 do
96                        textlen = decompressed:PopNetUint16()
97                        printdebug("gump","reading text line ",i," with length ",textlen)
98                        newgump.textline[i],newgump.textline_unicode[i] = UniCodeDualPop(decompressed,textlen)
99                        printdebug("gump",sprintf("newgump.textline[%d](len=%d)=\n",i,textlen),newgump.textline[i])
100                end
101        end
102
103        decompressed:Destroy()
104
105        if ( (input:Size() >= 4) and (input:GetTotalPopped()-popped_start < size) ) then
106                local unknownterminator=input:PopNetUint32()
107        end
108        return newgump
109end
110
111
112
113-- returns false if packet incomplete
114function UOProxyHandlePacket    (fifo_in,fifo_out,bIsFromClient) 
115        local t_since_start = Client_GetTicks() - gProxyConStartTime
116        if (fifo_in:Size() == 0) then return end
117        local fromname = bIsFromClient and "client" or "server"
118        local bIsFromServer = not bIsFromClient
119       
120        local bInterpret = true
121        --~ if (bIsFromServer and gProxyServerHuffmanStarted) then bInterpret = false end -- huffman comp&decomp active now
122        --~ if (bIsFromClient and gProxyServerHuffmanStarted) then bInterpret = false end -- not really needed but something seems bugged
123        if (gDisableProxyInterpretation) then bInterpret = false end
124        local bScrambleTest = false
125        local bClientBlockTest = true
126       
127        if (bInterpret) then 
128                -- 4-byte-head con1
129                if (bIsFromClient and (not gProxyFirstPartHeaderStarted)) then
130                        gProxyFirstPartHeaderStarted = true
131                        local iPacketSize = 4
132                        print("recv:",fromname,"4byte header before protocol start con1") 
133                        print(FIFOHexDump(fifo_in,0,iPacketSize))
134                        fifo_out:PushFIFOPartRaw(fifo_in,0,iPacketSize) 
135                        fifo_in:PopRaw(iPacketSize)
136                        return true
137                end
138               
139                -- 4-byte-head con2
140                if (bIsFromClient and gProxyServerHuffmanStarted and (not gProxySecondPartHeaderStarted)) then
141                        gProxySecondPartHeaderStarted = true
142                        local iPacketSize = 4
143                        print("recv:",fromname,"4byte header before protocol start con2") 
144                        print(FIFOHexDump(fifo_in,0,iPacketSize))
145                        fifo_out:PushFIFOPartRaw(fifo_in,0,iPacketSize) 
146                        fifo_in:PopRaw(iPacketSize)
147                        return true
148                end
149       
150                -- scramble kPacket_Generic_SubCommand_Screensize (0xBF subcmd 0x05)  last 5 bytes (unknown)
151                --~ bf 00 0d 00 05 00 00 03 20 3f d0 11 00            |........ ?...|
152                if (bScrambleTest and bIsFromClient and fifo_in:Size() >= 13) then 
153                        if (fifo_in:PeekNetUint8(0) == 0xBF and
154                                fifo_in:PeekNetUint8(1) == 0x00 and
155                                fifo_in:PeekNetUint8(2) == 0x0d and
156                                fifo_in:PeekNetUint8(3) == 0x00 and
157                                fifo_in:PeekNetUint8(4) == 0x05) then
158                                fifo_in:PokeNetUint8(9,0xff)
159                                fifo_in:PokeNetUint8(10,0xff)
160                                fifo_in:PokeNetUint8(11,0xff)
161                                fifo_in:PokeNetUint8(12,0xff)
162                                print("+++++++++++++++++++++++++++++++++++++++++++++++")
163                                print("SCRAMBLED kPacket_Generic_SubCommand_Screensize")
164                                print("+++++++++++++++++++++++++++++++++++++++++++++++")
165                        end
166                end
167               
168               
169               
170                -- modify the unknown se packets
171                if (bIsFromClient and fifo_in:Size() >= 6) then
172                        --~ bf 00 06 00 24 5e
173                        if (fifo_in:PeekNetUint8(0) == 0xBF and
174                                fifo_in:PeekNetUint8(1) == 0x00 and
175                                fifo_in:PeekNetUint8(2) == 0x06 and
176                                fifo_in:PeekNetUint8(3) == 0x00 and
177                                fifo_in:PeekNetUint8(4) == 0x24) then
178                                --~ fifo_in:PokeNetUint8(5,math.random(0,255))
179                                print("+++++++++++++++++++++++++++++++++++++++++++++++")
180                                print("detected unknownSE")
181                                print("+++++++++++++++++++++++++++++++++++++++++++++++")
182                                if (bScrambleTest) then 
183                                        fifo_in:PokeNetUint8(5,16)
184                                        print("SCRAMBLED unknownSE")
185                                end
186                                if (bClientBlockTest) then gProxyBlockingClient = true end
187                        end
188                end
189               
190               
191                -- modify kPacket_Pre_Login 0x5D packet data
192                if (bScrambleTest and bIsFromClient and fifo_in:Size() >= 49) then
193                        if (fifo_in:PeekNetUint8(0) == 0x5D and
194                                fifo_in:PeekNetUint8(1) == 0xED and
195                                fifo_in:PeekNetUint8(2) == 0xED and
196                                fifo_in:PeekNetUint8(3) == 0xED and
197                                fifo_in:PeekNetUint8(4) == 0xED) then
198                                --~ fifo_in:PokeNetUint8(5,math.random(0,255))
199                                fifo_in:PokeNetUint8(48,0x11)
200                                print("+++++++++++++++++++++++++++++++++++++++++++++++")
201                                print("SCRAMBLED kPacket_Pre_Login")
202                                print("+++++++++++++++++++++++++++++++++++++++++++++++")
203                        end
204                end
205        end
206       
207        if (bInterpret) then 
208                local iId = fifo_in:PeekNetUint8(0)
209                local iPacketSize = gPacketSizeByID[iId]
210                print("UOProxyHandlePacket",fromname,sprintf("0x%02x",iId),gPacketTypeId2Name[iId],iPacketSize,"t="..t_since_start)
211                assert(iPacketSize)
212                if (iPacketSize == 0 and fifo_in:Size() < 3) then print("incomplete packet dynsize? <3") return end -- packet incomplete
213                if (iPacketSize == 0) then iPacketSize = fifo_in:PeekNetUint16(1) end
214                if (fifo_in:Size() < iPacketSize) then print("incomplete packet ",fifo_in:Size(),iPacketSize) return end -- packet incomplete
215               
216               
217                if (bIsFromServer and iId == kPacket_Server_List) then -- 0xA8
218                        fifo_in:PokeNetUint8(16*3-3,127)
219                        fifo_in:PokeNetUint8(16*3-4,0)
220                        fifo_in:PokeNetUint8(16*3-5,0)
221                        fifo_in:PokeNetUint8(16*3-6,1)
222                        print("adjusted kPacket_Server_List") -- TODO : more than one server ?
223                        print("+++++++++++++++++++++++++++++++++++++++++++++++")
224                        print("+++++    adjusted  kPacket_Server_List")
225                        print("+++++++++++++++++++++++++++++++++++++++++++++++")
226                end
227                -- login.uogamers.com (209=0xD1.173=0xAD.139=0x8B.110=0x6E)
228                --~ NET: server redirect: id=0x0000008c ip=209.173.139.110 port=2593 AccountNr.:0x79e01b53
229
230                --~ 8c d1 ad 8b 6e 0a 21 f9 ff 18 13                  |....n.!....|
231                --~ 8c 7f 00 00 01 0a 21 62 9a f8 3e                  |......!b..>|
232
233                -- todo : patch kPacket_Server_Redirect   8c d1 ad 8b 6e 0a 21 f9 ff 18 13
234                if (bIsFromServer and iId == kPacket_Server_Redirect) then -- 0x8C
235                        fifo_in:PokeNetUint8(1,127)
236                        fifo_in:PokeNetUint8(2,0)
237                        fifo_in:PokeNetUint8(3,0)
238                        fifo_in:PokeNetUint8(4,1)
239                        local iGameServerPort = gProxyPort2
240                        fifo_in:PokeNetUint8(5,floor(iGameServerPort/256)) -- port
241                        fifo_in:PokeNetUint8(6,math.mod(iGameServerPort,256)) -- port
242                       
243                        gProxyServerHuffmanStartedNextRound = true
244                        print("+++++++++++++++++++++++++++++++++++++++++++++++")
245                        print("+++++    adjusted kPacket_Server_Redirect")
246                        print("+++++++++++++++++++++++++++++++++++++++++++++++")
247                        gDisableProxyInterpretation = true
248                end
249               
250                -- todo : NetStartHuffman (after redirect?)
251               
252                --[[
253                if (bIsFromServer and iId == kPacket_Compressed_Gump) then      --0xDD
254                        local packetfifo = CreateFIFO()
255                        packetfifo:PushFIFOPartRaw(fifo_in,0,iPacketSize)
256                        local gumpdata = ProxyParseCompressedGumpPacket(packetfifo)
257                        packetfifo:Destroy()
258                       
259                        function MyPrintField (gumpdata,fieldname) print("gumpdata."..fieldname,SmartDump(gumpdata[fieldname])) end
260                        MyPrintField(gumpdata,"playerid")
261                        MyPrintField(gumpdata,"dialogId")
262                        MyPrintField(gumpdata,"x")
263                        MyPrintField(gumpdata,"y")
264                        MyPrintField(gumpdata,"Length_CompressedData")
265                        MyPrintField(gumpdata,"Length_Data")
266                        MyPrintField(gumpdata,"Data")
267                        MyPrintField(gumpdata,"numTextLines")
268                        MyPrintField(gumpdata,"Length_CompressedTextLines")
269                        MyPrintField(gumpdata,"Length_TextLines")
270                        MyPrintField(gumpdata,"textline")
271                        MyPrintField(gumpdata,"textline_unicode")
272                end
273               
274               
275                if (bIsFromClient and gProxyBlockingClient) then
276                        local bBlock = true
277                        if (fifo_in:PeekNetUint8(0) == 0xBF and
278                                fifo_in:PeekNetUint8(1) == 0x00 and
279                                fifo_in:PeekNetUint8(2) == 0x06 and
280                                fifo_in:PeekNetUint8(3) == 0x00 and
281                                fifo_in:PeekNetUint8(4) == 0x24) then
282                                -- UnknownSE (0xBF subcmd 0x24) : ok
283                                bBlock = false
284                        elseif (fifo_in:PeekNetUint8(0) == 0x73) then  -- kPacket_Ping : 0x73
285                                -- clientside ping : ok
286                                bBlock = false
287                        end
288                       
289                        bBlock = false
290                        if (bBlock) then
291                                print("===CLIENT:BLOCKED=== start")
292                                print(FIFOHexDump(fifo_in,0,iPacketSize))
293                                --~ print(FIFOHexDump(fifo_in,0,iPacketSize))
294                                print("===CLIENT:BLOCKED=== end")
295                                fifo_in:PopRaw(iPacketSize)
296                                return true
297                        end
298                end
299                ]]--
300               
301               
302                print("recv:",fromname,"t_since_start=",t_since_start) 
303                print(HexDumpUOPacket(fifo_in,iPacketSize,bIsFromClient," proxy"))
304                --~ print(FIFOHexDump(fifo_in,0,iPacketSize))
305                fifo_out:PushFIFOPartRaw(fifo_in,0,iPacketSize) 
306                fifo_in:PopRaw(iPacketSize)
307                return true
308        else
309                print("recv:",fromname,"(uninterpreted) t_since_start=",t_since_start,fifo_in:Size()) 
310                print(FIFOHexDump(fifo_in))
311                fifo_out:PushFIFOPartRaw(fifo_in) 
312                fifo_in:Clear()
313        end
314       
315        return false
316end
317--[[
318UOProxyOneConnection : start
319UOProxyOneConnection : servercon established
320recv:   client
321ef 7f 0c 22 38 00 00 00 06 00 00 00 00 00 00 00   |..."8...........|
32209 00 00 00 02 80 69 72 74 65 73 74 34 00 00 00   |......irtest4...|
32300 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   |................|
32400 00 00 00 fffffffffffffffffffffffffffffffffff   |....????????????|
32567 73 00 00 00 00 00 00 00 00 00 00 00 00 00 00   |gs..............|
32600 00 5d                                          |..]|
327
328recv:   server
329a8 00 2e 5d 00 01 00 00 55 4f 47 61 6d 65 72 73   |...]....UOGamers|
33000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   |................|
33100 00 00 00 00 00 00 00 00 fb 01 00 00 7f         |..............|
332
333recv:   client
334a0 00 00                                          |...|
335
336recv:   server
3378c d1 ad 8b 6e 0a 21 f9 ff 18 13                  |....n.!....|
338
339disconnected:client
340UOProxyOneConnection ended.
341]]--
342
343function UOProxyOneConnection (newcon)
344        if (gProxyServerHuffmanStartedNextRound) then gProxyServerHuffmanStarted = true end
345        gProxyConStartTime = Client_GetTicks()
346        if (gProxyServerHuffmanStarted) then gServerListenerTCP:Destroy() end
347        print("UOProxyOneConnection : start")
348        gProxyClientCon = newcon
349        gProxyServerCon = NetConnect(gProxyHost,gProxyPort)
350        assert(gProxyClientCon)
351        assert(gProxyServerCon,"failed to connect to real server")
352        print("UOProxyOneConnection : servercon established")
353       
354        gProxyClientSendFifo                    = CreateFIFO()
355        gProxyServerSendFifo                    = CreateFIFO()
356        gProxyClientRecvFifo                    = CreateFIFO()
357        gProxyServerRecvFifo                    = CreateFIFO()
358        gProxyServerRecvCompFifo                = CreateFIFO()
359        gProxyClientSendCompFifo                = CreateFIFO()
360       
361        gPacketSizeByID[0xEF] = 21 -- protocol start... dummy here
362       
363        local bAlive = true
364        while bAlive do
365                -- send
366                gProxyServerHuffmanStarted = false
367                if (gProxyServerHuffmanStarted) then
368                        HuffmanCompress(gProxyClientSendFifo,gProxyClientSendCompFifo) -- does NOT remove data from in-fifo. compression can always be completed.
369                        gProxyClientCon:Push(gProxyClientSendCompFifo)
370                        gProxyClientSendCompFifo:Clear()
371                        gProxyClientSendFifo:Clear()
372                else 
373                        gProxyClientCon:Push(gProxyClientSendFifo)
374                        gProxyClientSendFifo:Clear()
375                end
376               
377                gProxyServerCon:Push(gProxyServerSendFifo)
378                gProxyServerSendFifo:Clear()
379               
380                -- hardware-step
381                Client_USleep(10)
382                NetReadAndWrite()
383               
384                -- receive
385                gProxyClientCon:Pop(gProxyClientRecvFifo)
386               
387                if (gProxyServerHuffmanStarted) then 
388                        gProxyServerCon:Pop(gProxyServerRecvCompFifo)
389                        HuffmanDecompress(gProxyServerRecvCompFifo,gProxyServerRecvFifo) -- DOES remove data from gProxyServerRecvCompFifo, might not remove all if data for decompression is not yet complete
390                else
391                        gProxyServerCon:Pop(gProxyServerRecvFifo)
392                end
393                gProxyServerHuffmanStarted = false
394               
395                -- handle packets
396                while UOProxyHandlePacket(gProxyServerRecvFifo,gProxyClientSendFifo,false) do end
397                while UOProxyHandlePacket(gProxyClientRecvFifo,gProxyServerSendFifo,true) do end
398               
399                if (not gProxyClientCon:IsConnected()) then print("disconnected:client") bAlive = false end
400                if (not gProxyServerCon:IsConnected()) then print("disconnected:server") bAlive = false end
401        end
402        print("UOProxyOneConnection ended.")
403        gProxyClientCon:Destroy()
404        gProxyServerCon:Destroy()
405        gProxyClientSendFifo:Destroy()
406        gProxyServerSendFifo:Destroy()
407        gProxyClientRecvFifo:Destroy()
408        gProxyServerRecvFifo:Destroy()
409        gProxyServerRecvCompFifo:Destroy()
410        gProxyClientSendCompFifo:Destroy()
411end
412
Note: See TracBrowser for help on using the browser.