forked from radkesvat/ReverseTlsTunnel
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathglobals.nim
317 lines (256 loc) · 10.8 KB
/
globals.nim
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
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
import chronos
import dns_resolve, hashes, print, parseopt,strutils, random, net, osproc, strformat
import checksums/sha1
# export IpAddress
const version = "3.6"
type RunMode*{.pure.} = enum
iran, kharej
var mode*: RunMode = RunMode.iran
# [Log Options]true
const log_conn_create* = true
const log_data_len* = false
const log_conn_destory* = false
const log_conn_error* = false
# [Connection]
var trust_time*: uint = 3 #secs
var pool_size*: uint = 16
var pool_age*: uint = 10
var max_idle_time*: uint = 600 #secs (default TCP RFC is 3600)
var max_pool_unused_time*: uint = 60 #secs
const chunk_size* = 4096
var mux*: bool = false
let tls13_record_layer* = "\x17\x03\x03"
let tls13_record_layer_data_len_size*:uint = 2
let full_tls_record_len*:uint = tls13_record_layer.len().uint + tls13_record_layer_data_len_size
let mux_header_size*:uint32 = tls13_record_layer.len().uint32 + 2 + 2 + 4 + 1# followed by 2 bytes len +2 port+and 4 bytes cid and 1 byte reserve
let mux_payload_size*:uint32 = 1024
let mux_chunk_size*:uint32 = mux_payload_size + mux_header_size
let socket_buffered* = false # when using mux, it depends
var mux_capacity*:uint32 = 4
# [Routes]
var listen_addr* = "0.0.0.0"
var listen_port*: Port = 0.Port
var next_route_addr* = ""
var next_route_port*: Port = 0.Port
var iran_addr* = ""
var iran_port*: Port = 0.Port
var final_target_domain* = ""
var final_target_ip*: string
var trusted_foreign_peers*:seq[IpAddress]
const final_target_port*:Port = 443.Port # port of the sni host (443 for tls handshake)
var self_ip*: IpAddress
# [passwords and hashes]
var password* = ""
var password_hash*: string
var sh1*: uint32
var sh2*: uint32
var sh3*: uint32
var sh4*: uint32
var sh5*: uint8
var random_str* = newString(len = 2000)
# [settings]
var disable_ufw* = true
var reset_iptable* = true
var keep_system_limit* = false
var terminate_secs* = 0
var debug_info* = false
# [multiport]
var multi_port* = false
var multi_port_min: Port = 0.Port
var multi_port_max: Port = 0.Port
var multi_port_additions: seq[Port]
# [posix constants]
const SO_ORIGINAL_DST* = 80
const SOL_IP* = 0
proc isPortFree*(port:Port):bool =
execCmdEx(&"""lsof -i:{port}""").output.len < 3
proc chooseRandomLPort():Port =
result = block:
if multi_port_min == 0.Port and multi_port_max == 0.Port:
multi_port_additions[rand(multi_port_additions.high).int]
elif (multi_port_min != 0.Port and multi_port_max != 0.Port):
(multi_port_min.int + rand(multi_port_max.int - multi_port_min.int)).Port
else:
quit("multi port range may not include port 0!")
if not isPortFree(result):return chooseRandomLPort()
proc iptablesInstalled(): bool {.used.} =
execCmdEx("""dpkg-query -W --showformat='${Status}\n' iptables|grep "install ok install"""").output != ""
proc resetIptables*() =
echo "reseting iptable nat"
assert 0 == execCmdEx("iptables -t nat -F").exitCode
assert 0 == execCmdEx("iptables -t nat -X").exitCode
proc createIptablesForwardRules*() =
if reset_iptable: resetIptables()
if not (multi_port_min == 0.Port or multi_port_max == 0.Port):
assert 0 == execCmdEx(&"""iptables -t nat -A PREROUTING -p tcp --dport {multi_port_min}:{multi_port_max} -j REDIRECT --to-port {listen_port}""").exitCode
for port in multi_port_additions:
assert 0 == execCmdEx(&"""iptables -t nat -A PREROUTING -p tcp --dport {port} -j REDIRECT --to-port {listen_port}""").exitCode
proc multiportSupported(): bool =
when defined(windows) or defined(android):
echo "multi listen port unsupported for windows."
return false
else:
if not iptablesInstalled():
echo "multi listen port requires iptables to be installed."
return false
return true
proc init*() =
print version
for i in 0..<random_str.len():
random_str[i] = rand(char.low .. char.high).char
var p = initOptParser(longNoVal = @["kharej", "iran", "multiport", "keep-ufw", "keep-iptables", "keep-os-limit", "mux", "debug"])
while true:
p.next()
case p.kind
of cmdEnd: break
of cmdShortOption, cmdLongOption:
if p.val == "":
case p.key:
of "kharej":
mode = RunMode.kharej
print mode
of "iran":
mode = RunMode.iran
print mode
of "keep-ufw":
disable_ufw = false
of "keep-iptables":
reset_iptable = false
of "multiport":
multiport = true
of "keep-os-limit":
keep_system_limit = true
of "debug":
debug_info = true
of "mux":
mux = true
else:
echo "invalid option"
quit(-1)
else:
case p.key:
of "lport":
try:
listen_port = parseInt(p.val).Port
except: #multi port
if not multiportSupported(): quit(-1)
try:
let port_range_string = p.val
multi_port = true
listen_port = 0.Port # will take a random port
pool_size = max(2.uint, pool_size div 2.uint)
let port_range = port_range_string.split('-')
assert port_range.len == 2, "Invalid listen port range. !"
multi_port_min = max(1.uint16, port_range[0].parseInt.uint16).Port
multi_port_max = min(65535.uint16, port_range[1].parseInt.uint16).Port
assert multi_port_max.uint16 - multi_port_min.uint16 >= 0, "port range is invalid! use --lport:min-max"
except:
quit("could not parse lport.")
print listen_port
of "add-port":
if not multiportSupported(): quit(-1)
multi_port = true
if listen_port != 0.Port:
multi_port_additions.add listen_port.Port
listen_port = 0.Port
multi_port_additions.add p.val.parseInt().Port
of "peer":
trusted_foreign_peers.add parseIpAddress(p.val)
of "toip":
next_route_addr = (p.val)
print next_route_addr
of "toport":
try:
next_route_port = parseInt(p.val).Port
print next_route_port
except: #multi port
try:
assert(p.val == "multiport")
multi_port = true
print multi_port
except:
quit("could not parse toport.")
of "iran-ip":
iran_addr = (p.val)
print iran_addr
of "iran-port":
iran_port = parseInt(p.val).Port
print iran_port
of "sni":
final_target_domain = (p.val)
print final_target_domain
of "password":
password = (p.val)
print password
of "terminate":
terminate_secs = parseInt(p.val) * 60*60
print terminate_secs
of "pool":
pool_size = parseInt(p.val).uint
print pool_size
of "pool_age":
pool_age = parseInt(p.val).uint
print pool_age
of "trust_time":
trust_time = parseInt(p.val).uint
print trust_time
of "listen":
listen_addr = (p.val)
print listen_addr
else:
echo "Unkown argument ", p.key
quit(-1)
of cmdArgument:
# echo "Argument: ", p.key
echo "invalid argument style: ", p.key
quit(-1)
var exit = false
case mode:
of RunMode.kharej:
if iran_addr.isEmptyOrWhitespace():
echo "specify the ip address of the iran server --iran-addr:{ip}"
exit = true
if iran_port == 0.Port and not multi_port:
echo "specify the iran server prot --iran-port:{port}"
exit = true
if next_route_addr.isEmptyOrWhitespace():
echo "specify the next ip for routing --toip:{ip} (usually 127.0.0.1)"
exit = true
if next_route_port == 0.Port and not multi_port:
echo "specify the port of the next ip for routing --toport:{port} (the port of the config that panel shows you)"
exit = true
of RunMode.iran:
if listen_port == 0.Port and not multi_port:
echo "specify the listen prot --lport:{port} (usually 443)"
exit = true
if listen_port == 0.Port and multi_port:
listen_port = chooseRandomLPort()
if final_target_domain.isEmptyOrWhitespace():
echo "specify the sni for routing --sni:{domain}"
exit = true
if password.isEmptyOrWhitespace():
echo "specify the password --password:{something}"
exit = true
if exit: quit("Application did not start due to above logs.")
if terminate_secs != 0:
sleepAsync(terminate_secs*1000).addCallback(
proc(arg: pointer) =
echo "Exiting due to termination timeout. (--terminate)"
quit(0)
)
# if multi_port and listen_addr == "0.0.0.0":
# listen_addr = "127.0.0.1"
final_target_ip = resolveIPv4(final_target_domain)
print "\n"
self_ip = getPrimaryIPAddr(dest = parseIpAddress("8.8.8.8"))
password_hash = $(secureHash(password))
sh1 = hash(password_hash).uint32
sh2 = hash(sh1).uint32
sh3 = hash(sh2).uint32
sh4 = hash(sh3).uint32
# sh5 = (3 + (hash(sh2).uint32 mod 5)).uint8
sh5 = hash(sh4).uint8
while sh5 <= 2.uint32 or sh5 >= 223.uint32:
sh5 = hash(sh5).uint8
print password, password_hash, sh1, sh2, sh3, pool_size
print "\n"