-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathwss-lua.lua
More file actions
162 lines (145 loc) · 3.73 KB
/
wss-lua.lua
File metadata and controls
162 lines (145 loc) · 3.73 KB
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
157
158
159
160
161
162
if not table.unpack then
table.unpack = unpack
end
function binInt(x,cap)
local ret=""
while x~=1 and x~=0 do
ret=tostring(x%2)..ret
x=math.modf(x/2)
end
ret=tostring(x)..ret
return string.rep("0",cap-#ret)..ret
end
function strBin(bin)
local str = ""
for i=1,#bin,8 do
str=str..string.char(tonumber(bin:sub(i,i+7),2))
end
return str
end
function strInt(...)
local arg = {...}
local str = ""
for k,v in pairs(arg) do
str = str..string.char(tonumber(v))
end
return str
end
function binStr(str)
local bin = ""
for i=1,#str do
bin=bin..binInt(string.byte(str:sub(i,i)),8)
end
return bin
end
local function xor(a, b)
local r, m, s = 0, 2^31
repeat
s,a,b = a+b+m, a%m, b%m
r,m = r + m*3%(s-a-b), m/2
until m < 1
return r
end
local socket = require("socket")
local sslexists, ssl = pcall(require,"ssl")
if not sslexists then
print("warning: luasec module not found")
ssl = {}
end
local ws = {}
ws.DEFAULT_PARAMS_C = {
mode = "client",
protocol = "tlsv1_2",
options = {"all", "no_sslv2", "no_sslv3", "no_tlsv1"},
verify = "none",
}
ws.client = function(newclient)
local newclient = newclient or socket.tcp()
local c = {_c = newclient}
function c:connectm(ip,port,path,host,secure)
local path = path or "/"
c._c:connect(ip,port)
if secure then
if type(secure) ~= "table" then
secure = ws.DEFAULT_PARAMS_C
end
c._c = ssl.wrap(c._c,secure)
c._c:dohandshake()
end
local host = host or ip..":"..port
local sendstr = "GET "..path.." HTTP/1.1\nconnection: Upgrade\nsec-websocket-version: 13\nhost: "..host.."\nsec-websocket-key: H+/nnW7dfSMjhYQ4j5UkTQ==\nupgrade: websocket\n\n"
print(c._c:send(sendstr))
local dat = ""
local _d,_e,_p
repeat
_d,_e,_p = c._c:receive()
if _d or (_p~="" and _p~=nil) then
dat=dat.. _d .."\n"
end
until _d == "\n" or _d == ""
end
function c:connect(host,path,port,secure)
local ip = socket.dns.toip(host)
return self:connectm(ip,port or 80,path or "/",host,secure)
end
function c:send(data,opcode)
opcode = opcode or 1
opcode = binInt(opcode,4):sub(1,4)
local MAX = math.floor(#data/125)
for i=0,MAX do
local dat = data:sub(126*i,126*i+125)
local END = (i==MAX) and "1" or "0"
local RSV = "000"
local OP = (0==i) and opcode or "0000"
local MASKED = "1"
local LEN = binInt(#dat,7)
local MASK = {
math.random(1,255),
math.random(1,255),
math.random(1,255),
math.random(1,255),
}
local sMASK = strInt(table.unpack(MASK)) --string
local SEND = strBin(END..RSV..OP..MASKED..LEN)..sMASK
local eDAT = "" --encoded
for i = 1,#dat,1 do
eDAT = eDAT..string.char( xor( string.byte(dat:sub(i,i)) , MASK[((i-1)%4)+1] ) )
end
c._c:send(SEND..eDAT)
end
end
function c:receive()
local dat = c._c:receive(2)
if dat then
local c1 = binStr(dat:sub(1,1))
local c2 = binStr(dat:sub(2,2))
local END = (c1:sub(1,1)==1) and true or false
local opcode = tonumber(c1:sub(5,8),2)
local MASKED = (c2:sub(1,1)==1) and true or false
local LEN = tonumber(c2:sub(2,8),2)
if LEN == 126 or LEN == 127 then
local extd = c._c:receive((LEN == 126) and 2 or 8 )
if extd then
LEN = tonumber(binStr(extd),2)
end
end
local MASK = {}
if MASKED then
end
local DATA
if LEN > 0 then
DATA = c._c:receive(LEN)
end
return DATA,opcode
else
return nil,"timeout"
end
end
function c:settimeout(t) return c._c:settimeout(t) end
function c:close(dat)
c:send(dat or "closed",8)
c._c:close()
end
return c
end
return ws