girl 4.4.0 → 4.9.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of girl might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/girl.gemspec +0 -2
- data/lib/girl/head.rb +8 -3
- data/lib/girl/proxy_worker.rb +90 -32
- data/lib/girl/proxyd_worker.rb +51 -31
- data/lib/girl/relay_worker.rb +87 -42
- data/lib/girl/resolvd_worker.rb +22 -19
- data/lib/girl/version.rb +1 -1
- metadata +3 -5
- data/lib/girl/ssl.rb +0 -79
- data/lib/girl/ssl_worker.rb +0 -851
data/lib/girl/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: girl
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.
|
4
|
+
version: 4.9.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- takafan
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-05-07 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: escape evil.
|
14
14
|
email:
|
@@ -33,8 +33,6 @@ files:
|
|
33
33
|
- lib/girl/resolv_custom.rb
|
34
34
|
- lib/girl/resolvd.rb
|
35
35
|
- lib/girl/resolvd_worker.rb
|
36
|
-
- lib/girl/ssl.rb
|
37
|
-
- lib/girl/ssl_worker.rb
|
38
36
|
- lib/girl/version.rb
|
39
37
|
homepage: https://github.com/takafan/girl
|
40
38
|
licenses:
|
@@ -55,7 +53,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
55
53
|
- !ruby/object:Gem::Version
|
56
54
|
version: '0'
|
57
55
|
requirements: []
|
58
|
-
rubygems_version: 3.2.
|
56
|
+
rubygems_version: 3.2.3
|
59
57
|
signing_key:
|
60
58
|
specification_version: 4
|
61
59
|
summary: 妹子
|
data/lib/girl/ssl.rb
DELETED
@@ -1,79 +0,0 @@
|
|
1
|
-
require 'etc'
|
2
|
-
require 'girl/concurrent_hash'
|
3
|
-
require 'girl/head'
|
4
|
-
require 'girl/ssl_worker'
|
5
|
-
require 'girl/version'
|
6
|
-
require 'json'
|
7
|
-
require 'openssl'
|
8
|
-
require 'socket'
|
9
|
-
|
10
|
-
##
|
11
|
-
# Girl::Ssl
|
12
|
-
#
|
13
|
-
module Girl
|
14
|
-
class Ssl
|
15
|
-
|
16
|
-
def initialize( config_path = nil )
|
17
|
-
unless config_path then
|
18
|
-
config_path = File.expand_path( '../girl.conf.json', __FILE__ )
|
19
|
-
end
|
20
|
-
|
21
|
-
raise "missing config file #{ config_path }" unless File.exist?( config_path )
|
22
|
-
|
23
|
-
conf = JSON.parse( IO.binread( config_path ), symbolize_names: true )
|
24
|
-
redir_port = conf[ :ssl_port ]
|
25
|
-
worker_count = conf[ :worker_count ]
|
26
|
-
|
27
|
-
unless redir_port then
|
28
|
-
redir_port = 1080
|
29
|
-
end
|
30
|
-
|
31
|
-
nprocessors = Etc.nprocessors
|
32
|
-
|
33
|
-
if worker_count.nil? || worker_count <= 0 || worker_count > nprocessors then
|
34
|
-
worker_count = nprocessors
|
35
|
-
end
|
36
|
-
|
37
|
-
len = CONSTS.map{ | name | name.size }.max
|
38
|
-
|
39
|
-
CONSTS.each do | name |
|
40
|
-
puts "#{ name.gsub( '_', ' ' ).ljust( len ) } #{ Girl.const_get( name ) }"
|
41
|
-
end
|
42
|
-
|
43
|
-
title = "girl ssl #{ Girl::VERSION }"
|
44
|
-
puts title
|
45
|
-
puts "redir port #{ redir_port } worker count #{ worker_count }"
|
46
|
-
|
47
|
-
$0 = title
|
48
|
-
workers = []
|
49
|
-
|
50
|
-
worker_count.times do | i |
|
51
|
-
workers << fork do
|
52
|
-
$0 = 'girl ssl worker'
|
53
|
-
worker = Girl::SslWorker.new( redir_port )
|
54
|
-
|
55
|
-
Signal.trap( :TERM ) do
|
56
|
-
puts "w#{ i } exit"
|
57
|
-
worker.quit!
|
58
|
-
end
|
59
|
-
|
60
|
-
worker.looping
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
Signal.trap( :TERM ) do
|
65
|
-
puts 'trap TERM'
|
66
|
-
workers.each do | pid |
|
67
|
-
begin
|
68
|
-
Process.kill( :TERM, pid )
|
69
|
-
rescue Errno::ESRCH => e
|
70
|
-
puts e.class
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
Process.waitall
|
76
|
-
end
|
77
|
-
|
78
|
-
end
|
79
|
-
end
|
data/lib/girl/ssl_worker.rb
DELETED
@@ -1,851 +0,0 @@
|
|
1
|
-
module Girl
|
2
|
-
class SslWorker
|
3
|
-
|
4
|
-
##
|
5
|
-
# initialize
|
6
|
-
#
|
7
|
-
def initialize( redir_port )
|
8
|
-
@redir_port = redir_port
|
9
|
-
@reads = []
|
10
|
-
@writes = []
|
11
|
-
@closing_srcs = []
|
12
|
-
@paused_srcs = []
|
13
|
-
@paused_dsts = []
|
14
|
-
@resume_srcs = []
|
15
|
-
@resume_dsts = []
|
16
|
-
@roles = ConcurrentHash.new # sock => :dotr / :redir / :src / :dst
|
17
|
-
@src_infos = ConcurrentHash.new # src => {}
|
18
|
-
@dst_infos = ConcurrentHash.new # dst => {}
|
19
|
-
@resolv_caches = ConcurrentHash.new # domain => [ ip, created_at ]
|
20
|
-
|
21
|
-
dotr, dotw = IO.pipe
|
22
|
-
@dotw = dotw
|
23
|
-
add_read( dotr, :dotr )
|
24
|
-
new_a_redir
|
25
|
-
end
|
26
|
-
|
27
|
-
##
|
28
|
-
# looping
|
29
|
-
#
|
30
|
-
def looping
|
31
|
-
puts "p#{ Process.pid } #{ Time.new } looping"
|
32
|
-
loop_check_expire
|
33
|
-
loop_check_resume
|
34
|
-
|
35
|
-
loop do
|
36
|
-
rs, ws = IO.select( @reads, @writes )
|
37
|
-
|
38
|
-
rs.each do | sock |
|
39
|
-
case @roles[ sock ]
|
40
|
-
when :dotr then
|
41
|
-
read_dotr( sock )
|
42
|
-
when :redir then
|
43
|
-
read_redir( sock )
|
44
|
-
when :src then
|
45
|
-
read_src( sock )
|
46
|
-
when :dst then
|
47
|
-
read_dst( sock )
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
ws.each do | sock |
|
52
|
-
case @roles[ sock ]
|
53
|
-
when :src then
|
54
|
-
write_src( sock )
|
55
|
-
when :dst then
|
56
|
-
write_dst( sock )
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
60
|
-
rescue Interrupt => e
|
61
|
-
puts e.class
|
62
|
-
quit!
|
63
|
-
end
|
64
|
-
|
65
|
-
##
|
66
|
-
# quit!
|
67
|
-
#
|
68
|
-
def quit!
|
69
|
-
# puts "debug exit"
|
70
|
-
exit
|
71
|
-
end
|
72
|
-
|
73
|
-
private
|
74
|
-
|
75
|
-
##
|
76
|
-
# add closing src
|
77
|
-
#
|
78
|
-
def add_closing_src( src )
|
79
|
-
return if src.closed? || @closing_srcs.include?( src )
|
80
|
-
@closing_srcs << src
|
81
|
-
next_tick
|
82
|
-
end
|
83
|
-
|
84
|
-
##
|
85
|
-
# add dst wbuff
|
86
|
-
#
|
87
|
-
def add_dst_wbuff( dst, data )
|
88
|
-
return if dst.closed?
|
89
|
-
dst_info = @dst_infos[ dst ]
|
90
|
-
dst_info[ :wbuff ] << data
|
91
|
-
add_write( dst )
|
92
|
-
|
93
|
-
if dst_info[ :wbuff ].bytesize >= WBUFF_LIMIT then
|
94
|
-
puts "p#{ Process.pid } #{ Time.new } pause direct src #{ dst_info[ :domain ] }"
|
95
|
-
add_paused_src( dst_info[ :src ] )
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
|
-
##
|
100
|
-
# add paused dst
|
101
|
-
#
|
102
|
-
def add_paused_dst( dst )
|
103
|
-
return if dst.closed? || @paused_dsts.include?( dst )
|
104
|
-
@reads.delete( dst )
|
105
|
-
@paused_dsts << dst
|
106
|
-
end
|
107
|
-
|
108
|
-
##
|
109
|
-
# add paused src
|
110
|
-
#
|
111
|
-
def add_paused_src( src )
|
112
|
-
return if src.closed? || @paused_srcs.include?( src )
|
113
|
-
@reads.delete( src )
|
114
|
-
@paused_srcs << src
|
115
|
-
end
|
116
|
-
|
117
|
-
##
|
118
|
-
# add read
|
119
|
-
#
|
120
|
-
def add_read( sock, role = nil )
|
121
|
-
return if sock.closed? || @reads.include?( sock )
|
122
|
-
@reads << sock
|
123
|
-
|
124
|
-
if role then
|
125
|
-
@roles[ sock ] = role
|
126
|
-
end
|
127
|
-
|
128
|
-
next_tick
|
129
|
-
end
|
130
|
-
|
131
|
-
##
|
132
|
-
# add resume dst
|
133
|
-
#
|
134
|
-
def add_resume_dst( dst )
|
135
|
-
return if @resume_dsts.include?( dst )
|
136
|
-
@resume_dsts << dst
|
137
|
-
next_tick
|
138
|
-
end
|
139
|
-
|
140
|
-
##
|
141
|
-
# add resume src
|
142
|
-
#
|
143
|
-
def add_resume_src( src )
|
144
|
-
return if @resume_srcs.include?( src )
|
145
|
-
@resume_srcs << src
|
146
|
-
next_tick
|
147
|
-
end
|
148
|
-
|
149
|
-
##
|
150
|
-
# add socks5 conn reply
|
151
|
-
#
|
152
|
-
def add_socks5_conn_reply( src )
|
153
|
-
# +----+-----+-------+------+----------+----------+
|
154
|
-
# |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT |
|
155
|
-
# +----+-----+-------+------+----------+----------+
|
156
|
-
# | 1 | 1 | X'00' | 1 | Variable | 2 |
|
157
|
-
# +----+-----+-------+------+----------+----------+
|
158
|
-
redir_ip, redir_port = @redir_local_address.ip_unpack
|
159
|
-
data = [ [ 5, 0, 0, 1 ].pack( 'C4' ), IPAddr.new( redir_ip ).hton, [ redir_port ].pack( 'n' ) ].join
|
160
|
-
# puts "debug add src.wbuff socks5 conn reply #{ data.inspect }"
|
161
|
-
add_src_wbuff( src, data )
|
162
|
-
end
|
163
|
-
|
164
|
-
##
|
165
|
-
# add src rbuff
|
166
|
-
#
|
167
|
-
def add_src_rbuff( src, data )
|
168
|
-
src_info = @src_infos[ src ]
|
169
|
-
src_info[ :rbuff ] << data
|
170
|
-
|
171
|
-
if src_info[ :rbuff ].bytesize >= WBUFF_LIMIT then
|
172
|
-
# puts "debug src.rbuff full"
|
173
|
-
add_closing_src( src )
|
174
|
-
end
|
175
|
-
end
|
176
|
-
|
177
|
-
##
|
178
|
-
# add src wbuff
|
179
|
-
#
|
180
|
-
def add_src_wbuff( src, data )
|
181
|
-
return if src.closed? || @closing_srcs.include?( src )
|
182
|
-
src_info = @src_infos[ src ]
|
183
|
-
src_info[ :wbuff ] << data
|
184
|
-
src_info[ :last_recv_at ] = Time.new
|
185
|
-
add_write( src )
|
186
|
-
|
187
|
-
if src_info[ :wbuff ].bytesize >= WBUFF_LIMIT then
|
188
|
-
dst = src_info[ :dst ]
|
189
|
-
|
190
|
-
if dst then
|
191
|
-
puts "p#{ Process.pid } #{ Time.new } pause dst #{ src_info[ :destination_domain ] }"
|
192
|
-
add_paused_dst( dst )
|
193
|
-
end
|
194
|
-
end
|
195
|
-
end
|
196
|
-
|
197
|
-
##
|
198
|
-
# add write
|
199
|
-
#
|
200
|
-
def add_write( sock )
|
201
|
-
return if sock.closed? || @writes.include?( sock )
|
202
|
-
@writes << sock
|
203
|
-
next_tick
|
204
|
-
end
|
205
|
-
|
206
|
-
##
|
207
|
-
# close read dst
|
208
|
-
#
|
209
|
-
def close_read_dst( dst )
|
210
|
-
return if dst.closed?
|
211
|
-
# puts "debug close read dst"
|
212
|
-
dst.close_read
|
213
|
-
@reads.delete( dst )
|
214
|
-
|
215
|
-
if dst.closed? then
|
216
|
-
@writes.delete( dst )
|
217
|
-
@roles.delete( dst )
|
218
|
-
del_dst_info( dst )
|
219
|
-
end
|
220
|
-
end
|
221
|
-
|
222
|
-
##
|
223
|
-
# close read src
|
224
|
-
#
|
225
|
-
def close_read_src( src )
|
226
|
-
return if src.closed?
|
227
|
-
# puts "debug close read src"
|
228
|
-
src_info = @src_infos[ src ]
|
229
|
-
src_info[ :close_read ] = true
|
230
|
-
|
231
|
-
if src_info[ :close_write ] then
|
232
|
-
close_sock( src )
|
233
|
-
del_src_info( src )
|
234
|
-
else
|
235
|
-
@reads.delete( src )
|
236
|
-
end
|
237
|
-
end
|
238
|
-
|
239
|
-
##
|
240
|
-
# close redir
|
241
|
-
#
|
242
|
-
def close_redir( redir )
|
243
|
-
return if redir.closed?
|
244
|
-
redir.close
|
245
|
-
@roles.delete( redir )
|
246
|
-
@reads.delete( redir )
|
247
|
-
@src_infos.each { | src, _ | close_src( src ) }
|
248
|
-
end
|
249
|
-
|
250
|
-
##
|
251
|
-
# close sock
|
252
|
-
#
|
253
|
-
def close_sock( sock )
|
254
|
-
sock.close
|
255
|
-
@reads.delete( sock )
|
256
|
-
@writes.delete( sock )
|
257
|
-
@roles.delete( sock )
|
258
|
-
end
|
259
|
-
|
260
|
-
##
|
261
|
-
# close src
|
262
|
-
#
|
263
|
-
def close_src( src )
|
264
|
-
return if src.closed?
|
265
|
-
# puts "debug close src"
|
266
|
-
close_sock( src )
|
267
|
-
src_info = del_src_info( src )
|
268
|
-
dst = src_info[ :dst ]
|
269
|
-
|
270
|
-
if dst then
|
271
|
-
close_sock( dst )
|
272
|
-
del_dst_info( dst )
|
273
|
-
end
|
274
|
-
end
|
275
|
-
|
276
|
-
##
|
277
|
-
# close write dst
|
278
|
-
#
|
279
|
-
def close_write_dst( dst )
|
280
|
-
return if dst.closed?
|
281
|
-
# puts "debug close write dst"
|
282
|
-
dst.close_write
|
283
|
-
@writes.delete( dst )
|
284
|
-
|
285
|
-
if dst.closed? then
|
286
|
-
@reads.delete( dst )
|
287
|
-
@roles.delete( dst )
|
288
|
-
del_dst_info( dst )
|
289
|
-
end
|
290
|
-
end
|
291
|
-
|
292
|
-
##
|
293
|
-
# close write src
|
294
|
-
#
|
295
|
-
def close_write_src( src )
|
296
|
-
return if src.closed?
|
297
|
-
# puts "debug close write src"
|
298
|
-
src_info = @src_infos[ src ]
|
299
|
-
src_info[ :close_write ] = true
|
300
|
-
|
301
|
-
if src_info[ :close_read ] then
|
302
|
-
close_sock( src )
|
303
|
-
del_src_info( src )
|
304
|
-
else
|
305
|
-
@writes.delete( src )
|
306
|
-
end
|
307
|
-
end
|
308
|
-
|
309
|
-
##
|
310
|
-
# del dst info
|
311
|
-
#
|
312
|
-
def del_dst_info( dst )
|
313
|
-
# puts "debug delete dst info"
|
314
|
-
dst_info = @dst_infos.delete( dst )
|
315
|
-
@paused_dsts.delete( dst )
|
316
|
-
@resume_dsts.delete( dst )
|
317
|
-
dst_info
|
318
|
-
end
|
319
|
-
|
320
|
-
##
|
321
|
-
# del src info
|
322
|
-
#
|
323
|
-
def del_src_info( src )
|
324
|
-
# puts "debug delete src info"
|
325
|
-
src_info = @src_infos.delete( src )
|
326
|
-
@paused_srcs.delete( src )
|
327
|
-
@resume_srcs.delete( src )
|
328
|
-
src_info
|
329
|
-
end
|
330
|
-
|
331
|
-
##
|
332
|
-
# loop check expire
|
333
|
-
#
|
334
|
-
def loop_check_expire
|
335
|
-
Thread.new do
|
336
|
-
loop do
|
337
|
-
sleep CHECK_EXPIRE_INTERVAL
|
338
|
-
now = Time.new
|
339
|
-
|
340
|
-
@src_infos.each do | src, src_info |
|
341
|
-
last_recv_at = src_info[ :last_recv_at ] || src_info[ :created_at ]
|
342
|
-
last_sent_at = src_info[ :last_sent_at ] || src_info[ :created_at ]
|
343
|
-
expire_after = src_info[ :dst ] ? EXPIRE_AFTER : EXPIRE_NEW
|
344
|
-
|
345
|
-
if ( now - last_recv_at >= expire_after ) && ( now - last_sent_at >= expire_after ) then
|
346
|
-
puts "p#{ Process.pid } #{ Time.new } expire src #{ expire_after } #{ src_info[ :id ] } #{ src_info[ :destination_domain ] }"
|
347
|
-
add_closing_src( src )
|
348
|
-
|
349
|
-
unless src_info[ :rbuff ].empty? then
|
350
|
-
puts "p#{ Process.pid } #{ Time.new } lost rbuff #{ src_info[ :rbuff ].inspect }"
|
351
|
-
end
|
352
|
-
end
|
353
|
-
end
|
354
|
-
end
|
355
|
-
end
|
356
|
-
end
|
357
|
-
|
358
|
-
##
|
359
|
-
# loop check resume
|
360
|
-
#
|
361
|
-
def loop_check_resume
|
362
|
-
Thread.new do
|
363
|
-
loop do
|
364
|
-
sleep CHECK_RESUME_INTERVAL
|
365
|
-
|
366
|
-
@paused_srcs.each do | src |
|
367
|
-
src_info = @src_infos[ src ]
|
368
|
-
dst = src_info[ :dst ]
|
369
|
-
|
370
|
-
if dst && !dst.closed? then
|
371
|
-
dst_info = @dst_infos[ dst ]
|
372
|
-
|
373
|
-
if dst_info[ :wbuff ].size < RESUME_BELOW then
|
374
|
-
puts "p#{ Process.pid } #{ Time.new } resume direct src #{ src_info[ :destination_domain ] }"
|
375
|
-
add_resume_src( src )
|
376
|
-
end
|
377
|
-
end
|
378
|
-
end
|
379
|
-
|
380
|
-
@paused_dsts.each do | dst |
|
381
|
-
dst_info = @dst_infos[ dst ]
|
382
|
-
src = dst_info[ :src ]
|
383
|
-
|
384
|
-
if src && !src.closed? then
|
385
|
-
src_info = @src_infos[ src ]
|
386
|
-
|
387
|
-
if src_info[ :wbuff ].size < RESUME_BELOW then
|
388
|
-
puts "p#{ Process.pid } #{ Time.new } resume dst #{ dst_info[ :domain ] }"
|
389
|
-
add_resume_dst( dst )
|
390
|
-
end
|
391
|
-
end
|
392
|
-
end
|
393
|
-
end
|
394
|
-
end
|
395
|
-
end
|
396
|
-
|
397
|
-
##
|
398
|
-
# new a dst
|
399
|
-
#
|
400
|
-
def new_a_dst( src, ip_info )
|
401
|
-
return if src.closed?
|
402
|
-
src_info = @src_infos[ src ]
|
403
|
-
domain = src_info[ :destination_domain ]
|
404
|
-
destination_addr = Socket.sockaddr_in( src_info[ :destination_port ], ip_info.ip_address )
|
405
|
-
dst = Socket.new( ip_info.ipv4? ? Socket::AF_INET : Socket::AF_INET6, Socket::SOCK_STREAM, 0 )
|
406
|
-
|
407
|
-
begin
|
408
|
-
dst.connect_nonblock( destination_addr )
|
409
|
-
rescue IO::WaitWritable
|
410
|
-
# connect nonblock 必抛 wait writable
|
411
|
-
rescue Exception => e
|
412
|
-
puts "p#{ Process.pid } #{ Time.new } dst connect destination #{ domain } #{ src_info[ :destination_port ] } #{ ip_info.ip_address } #{ e.class }, close src"
|
413
|
-
dst.close
|
414
|
-
add_closing_src( src )
|
415
|
-
return
|
416
|
-
end
|
417
|
-
|
418
|
-
# puts "debug a new dst #{ dst.local_address.inspect }"
|
419
|
-
dst_info = {
|
420
|
-
src: src, # 对应src
|
421
|
-
domain: domain, # 目的地
|
422
|
-
wbuff: '', # 写前
|
423
|
-
closing_write: false # 准备关闭写
|
424
|
-
}
|
425
|
-
|
426
|
-
@dst_infos[ dst ] = dst_info
|
427
|
-
add_read( dst, :dst )
|
428
|
-
src_info[ :proxy_type ] = :direct
|
429
|
-
src_info[ :dst ] = dst
|
430
|
-
add_socks5_conn_reply( src )
|
431
|
-
end
|
432
|
-
|
433
|
-
##
|
434
|
-
# new a redir
|
435
|
-
#
|
436
|
-
def new_a_redir
|
437
|
-
pre = Socket.new( Socket::AF_INET, Socket::SOCK_STREAM, 0 )
|
438
|
-
pre.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEADDR, 1 )
|
439
|
-
pre.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEPORT, 1 )
|
440
|
-
pre.bind( Socket.sockaddr_in( @redir_port, '0.0.0.0' ) )
|
441
|
-
@redir_local_address = pre.local_address
|
442
|
-
puts "p#{ Process.pid } #{ Time.new } pre bind on #{ @redir_port } local address #{ pre.local_address.inspect }"
|
443
|
-
|
444
|
-
now = Time.new
|
445
|
-
name = OpenSSL::X509::Name.new
|
446
|
-
key = OpenSSL::PKey::RSA.new 1024
|
447
|
-
cert = OpenSSL::X509::Certificate.new
|
448
|
-
cert.version = 2
|
449
|
-
cert.serial = 0
|
450
|
-
cert.not_before = now
|
451
|
-
cert.not_after = now + 365 * 24 * 60 * 60
|
452
|
-
cert.public_key = key.public_key
|
453
|
-
cert.subject = name
|
454
|
-
cert.issuer = name
|
455
|
-
cert.sign key, OpenSSL::Digest.new('SHA1')
|
456
|
-
context = OpenSSL::SSL::SSLContext.new
|
457
|
-
context.security_level = 1
|
458
|
-
context.add_certificate( cert, key )
|
459
|
-
redir = OpenSSL::SSL::SSLServer.new pre, context
|
460
|
-
redir.listen( 127 )
|
461
|
-
puts "p#{ Process.pid } #{ Time.new } redir listening"
|
462
|
-
add_read( redir, :redir )
|
463
|
-
end
|
464
|
-
|
465
|
-
##
|
466
|
-
# next tick
|
467
|
-
#
|
468
|
-
def next_tick
|
469
|
-
@dotw.write( '.' )
|
470
|
-
end
|
471
|
-
|
472
|
-
##
|
473
|
-
# resolve domain
|
474
|
-
#
|
475
|
-
def resolve_domain( src, domain )
|
476
|
-
resolv_cache = @resolv_caches[ domain ]
|
477
|
-
|
478
|
-
if resolv_cache then
|
479
|
-
ip_info, created_at = resolv_cache
|
480
|
-
|
481
|
-
if Time.new - created_at < RESOLV_CACHE_EXPIRE then
|
482
|
-
# puts "debug #{ domain } hit resolv cache #{ ip_info.inspect }"
|
483
|
-
new_a_dst( src, ip_info )
|
484
|
-
return
|
485
|
-
end
|
486
|
-
|
487
|
-
# puts "debug expire #{ domain } resolv cache"
|
488
|
-
@resolv_caches.delete( domain )
|
489
|
-
end
|
490
|
-
|
491
|
-
src_info = @src_infos[ src ]
|
492
|
-
src_info[ :proxy_type ] = :checking
|
493
|
-
|
494
|
-
Thread.new do
|
495
|
-
begin
|
496
|
-
ip_info = Addrinfo.ip( domain )
|
497
|
-
rescue Exception => e
|
498
|
-
puts "p#{ Process.pid } #{ Time.new } resolv #{ domain.inspect } #{ e.class }"
|
499
|
-
end
|
500
|
-
|
501
|
-
if ip_info then
|
502
|
-
@resolv_caches[ domain ] = [ ip_info, Time.new ]
|
503
|
-
puts "p#{ Process.pid } #{ Time.new } resolved #{ domain } #{ ip_info.ip_address }"
|
504
|
-
new_a_dst( src, ip_info )
|
505
|
-
else
|
506
|
-
add_closing_src( src )
|
507
|
-
end
|
508
|
-
end
|
509
|
-
end
|
510
|
-
|
511
|
-
##
|
512
|
-
# set dst closing write
|
513
|
-
#
|
514
|
-
def set_dst_closing_write( dst )
|
515
|
-
return if dst.closed?
|
516
|
-
dst_info = @dst_infos[ dst ]
|
517
|
-
return if dst_info[ :closing_write ]
|
518
|
-
dst_info[ :closing_write ] = true
|
519
|
-
add_write( dst )
|
520
|
-
end
|
521
|
-
|
522
|
-
##
|
523
|
-
# set src closing write
|
524
|
-
#
|
525
|
-
def set_src_closing_write( src )
|
526
|
-
return if src.closed? || @closing_srcs.include?( src )
|
527
|
-
src_info = @src_infos[ src ]
|
528
|
-
return if src_info[ :closing_write ]
|
529
|
-
src_info[ :closing_write ] = true
|
530
|
-
add_write( src )
|
531
|
-
end
|
532
|
-
|
533
|
-
##
|
534
|
-
# read dotr
|
535
|
-
#
|
536
|
-
def read_dotr( dotr )
|
537
|
-
dotr.read_nonblock( 65535 )
|
538
|
-
|
539
|
-
if @closing_srcs.any? then
|
540
|
-
@closing_srcs.each { | src | close_src( src ) }
|
541
|
-
@closing_srcs.clear
|
542
|
-
end
|
543
|
-
|
544
|
-
if @resume_srcs.any? then
|
545
|
-
@resume_srcs.each do | src |
|
546
|
-
add_read( src )
|
547
|
-
@paused_srcs.delete( src )
|
548
|
-
end
|
549
|
-
|
550
|
-
@resume_srcs.clear
|
551
|
-
end
|
552
|
-
|
553
|
-
if @resume_dsts.any? then
|
554
|
-
@resume_dsts.each do | dst |
|
555
|
-
add_read( dst )
|
556
|
-
@paused_dsts.delete( dst )
|
557
|
-
end
|
558
|
-
|
559
|
-
@resume_dsts.clear
|
560
|
-
end
|
561
|
-
end
|
562
|
-
|
563
|
-
##
|
564
|
-
# read redir
|
565
|
-
#
|
566
|
-
def read_redir( redir )
|
567
|
-
accepted = false
|
568
|
-
|
569
|
-
Thread.new do
|
570
|
-
sleep 1
|
571
|
-
|
572
|
-
unless accepted then
|
573
|
-
puts "p#{ Process.pid } #{ Time.new } accept timeout"
|
574
|
-
close_redir( redir )
|
575
|
-
new_a_redir
|
576
|
-
end
|
577
|
-
end
|
578
|
-
|
579
|
-
begin
|
580
|
-
src = redir.accept
|
581
|
-
rescue SystemExit => e
|
582
|
-
puts "p#{ Process.pid } #{ Time.new } redir accept #{ e.class }"
|
583
|
-
close_redir( redir )
|
584
|
-
return
|
585
|
-
rescue Exception => e
|
586
|
-
puts "p#{ Process.pid } #{ Time.new } redir accept #{ e.class }"
|
587
|
-
puts e.full_message
|
588
|
-
return
|
589
|
-
end
|
590
|
-
|
591
|
-
accepted = true
|
592
|
-
# puts "debug accept a src"
|
593
|
-
|
594
|
-
@src_infos[ src ] = {
|
595
|
-
proxy_proto: :uncheck, # :uncheck / :socks5
|
596
|
-
proxy_type: :uncheck, # :uncheck / :checking / :direct / :negotiation
|
597
|
-
destination_domain: nil, # 目的地域名
|
598
|
-
destination_port: nil, # 目的地端口
|
599
|
-
is_connect: true, # 代理协议是http的场合,是否是CONNECT
|
600
|
-
rbuff: '', # 读到的流量
|
601
|
-
dst: nil, # 对应的dst
|
602
|
-
wbuff: '', # 从dst读到的流量
|
603
|
-
created_at: Time.new, # 创建时间
|
604
|
-
last_recv_at: nil, # 上一次收到新流量(由dst收到)的时间
|
605
|
-
last_sent_at: nil, # 上一次发出流量(由dst发出)的时间
|
606
|
-
closing_write: false, # 准备关闭写
|
607
|
-
close_read: false, # 已经关闭读
|
608
|
-
close_write: false # 已经关闭写
|
609
|
-
}
|
610
|
-
|
611
|
-
add_read( src, :src )
|
612
|
-
end
|
613
|
-
|
614
|
-
##
|
615
|
-
# read src
|
616
|
-
#
|
617
|
-
def read_src( src )
|
618
|
-
if src.closed? then
|
619
|
-
puts "p#{ Process.pid } #{ Time.new } read src but src closed?"
|
620
|
-
return
|
621
|
-
end
|
622
|
-
|
623
|
-
src_info = @src_infos[ src ]
|
624
|
-
|
625
|
-
begin
|
626
|
-
data = src.read_nonblock( 65535 )
|
627
|
-
rescue IO::WaitReadable
|
628
|
-
return
|
629
|
-
rescue Errno::EINTR => e
|
630
|
-
puts e.class
|
631
|
-
return
|
632
|
-
rescue Exception => e
|
633
|
-
# puts "debug read src #{ e.class }"
|
634
|
-
dst = src_info[ :dst ]
|
635
|
-
close_read_src( src )
|
636
|
-
|
637
|
-
if dst then
|
638
|
-
set_dst_closing_write( dst )
|
639
|
-
end
|
640
|
-
|
641
|
-
return
|
642
|
-
end
|
643
|
-
|
644
|
-
src_info = @src_infos[ src ]
|
645
|
-
proxy_type = src_info[ :proxy_type ]
|
646
|
-
|
647
|
-
case proxy_type
|
648
|
-
when :uncheck then
|
649
|
-
if data[ 0 ].unpack( 'C' ).first != 5 then
|
650
|
-
"p#{ Process.pid } #{ Time.new } unknown data #{ data.inspect }"
|
651
|
-
end
|
652
|
-
|
653
|
-
# puts "debug socks5 #{ data.inspect }"
|
654
|
-
|
655
|
-
# https://tools.ietf.org/html/rfc1928
|
656
|
-
#
|
657
|
-
# +----+----------+----------+
|
658
|
-
# |VER | NMETHODS | METHODS |
|
659
|
-
# +----+----------+----------+
|
660
|
-
# | 1 | 1 | 1 to 255 |
|
661
|
-
# +----+----------+----------+
|
662
|
-
nmethods = data[ 1 ].unpack( 'C' ).first
|
663
|
-
methods = data[ 2, nmethods ].unpack( 'C*' )
|
664
|
-
|
665
|
-
unless methods.include?( 0 ) then
|
666
|
-
puts "p#{ Process.pid } #{ Time.new } miss method 0x00"
|
667
|
-
add_closing_src( src )
|
668
|
-
return
|
669
|
-
end
|
670
|
-
|
671
|
-
# +----+--------+
|
672
|
-
# |VER | METHOD |
|
673
|
-
# +----+--------+
|
674
|
-
# | 1 | 1 |
|
675
|
-
# +----+--------+
|
676
|
-
data2 = [ 5, 0 ].pack( 'CC' )
|
677
|
-
add_src_wbuff( src, data2 )
|
678
|
-
src_info[ :proxy_proto ] = :socks5
|
679
|
-
src_info[ :proxy_type ] = :negotiation
|
680
|
-
when :checking then
|
681
|
-
# puts "debug add src rbuff before resolved #{ data.inspect }"
|
682
|
-
src_info[ :rbuff ] << data
|
683
|
-
when :negotiation then
|
684
|
-
# +----+-----+-------+------+----------+----------+
|
685
|
-
# |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT |
|
686
|
-
# +----+-----+-------+------+----------+----------+
|
687
|
-
# | 1 | 1 | X'00' | 1 | Variable | 2 |
|
688
|
-
# +----+-----+-------+------+----------+----------+
|
689
|
-
# puts "debug negotiation #{ data.inspect }"
|
690
|
-
ver, cmd, rsv, atyp = data[ 0, 4 ].unpack( 'C4' )
|
691
|
-
|
692
|
-
if cmd == 1 then
|
693
|
-
# puts "debug socks5 CONNECT"
|
694
|
-
|
695
|
-
if atyp == 1 then
|
696
|
-
destination_host, destination_port = data[ 4, 6 ].unpack( 'Nn' )
|
697
|
-
destination_addr = Socket.sockaddr_in( destination_port, destination_host )
|
698
|
-
destination_addrinfo = Addrinfo.new( destination_addr )
|
699
|
-
destination_ip = destination_addrinfo.ip_address
|
700
|
-
src_info[ :destination_domain ] = destination_ip
|
701
|
-
src_info[ :destination_port ] = destination_port
|
702
|
-
# puts "debug IP V4 address #{ destination_addrinfo.ip_unpack.inspect }"
|
703
|
-
new_a_dst( src, destination_addrinfo )
|
704
|
-
elsif atyp == 3 then
|
705
|
-
domain_len = data[ 4 ].unpack( 'C' ).first
|
706
|
-
|
707
|
-
if ( domain_len + 7 ) == data.bytesize then
|
708
|
-
domain = data[ 5, domain_len ]
|
709
|
-
port = data[ ( 5 + domain_len ), 2 ].unpack( 'n' ).first
|
710
|
-
src_info[ :destination_domain ] = domain
|
711
|
-
src_info[ :destination_port ] = port
|
712
|
-
# puts "debug DOMAINNAME #{ domain } #{ port }"
|
713
|
-
resolve_domain( src, domain )
|
714
|
-
end
|
715
|
-
end
|
716
|
-
else
|
717
|
-
puts "p#{ Process.pid } #{ Time.new } socks5 cmd #{ cmd } not implement"
|
718
|
-
end
|
719
|
-
when :direct then
|
720
|
-
dst = src_info[ :dst ]
|
721
|
-
|
722
|
-
if dst then
|
723
|
-
add_dst_wbuff( dst, data )
|
724
|
-
else
|
725
|
-
# puts "debug add src.rbuff #{ data.bytesize }"
|
726
|
-
add_src_rbuff( src, data )
|
727
|
-
end
|
728
|
-
end
|
729
|
-
end
|
730
|
-
|
731
|
-
##
|
732
|
-
# read dst
|
733
|
-
#
|
734
|
-
def read_dst( dst )
|
735
|
-
if dst.closed? then
|
736
|
-
puts "p#{ Process.pid } #{ Time.new } read dst but dst closed?"
|
737
|
-
return
|
738
|
-
end
|
739
|
-
|
740
|
-
dst_info = @dst_infos[ dst ]
|
741
|
-
src = dst_info[ :src ]
|
742
|
-
|
743
|
-
begin
|
744
|
-
data = dst.read_nonblock( 65535 )
|
745
|
-
rescue IO::WaitReadable, Errno::EINTR
|
746
|
-
print 'r'
|
747
|
-
return
|
748
|
-
rescue Exception => e
|
749
|
-
# puts "debug read dst #{ e.class }"
|
750
|
-
close_read_dst( dst )
|
751
|
-
set_src_closing_write( src )
|
752
|
-
return
|
753
|
-
end
|
754
|
-
|
755
|
-
# puts "debug read dst #{ data.bytesize }"
|
756
|
-
add_src_wbuff( src, data )
|
757
|
-
end
|
758
|
-
|
759
|
-
##
|
760
|
-
# write src
|
761
|
-
#
|
762
|
-
def write_src( src )
|
763
|
-
if src.closed? then
|
764
|
-
puts "p#{ Process.pid } #{ Time.new } write src but src closed?"
|
765
|
-
return
|
766
|
-
end
|
767
|
-
|
768
|
-
src_info = @src_infos[ src ]
|
769
|
-
dst = src_info[ :dst ]
|
770
|
-
data = src_info[ :wbuff ]
|
771
|
-
|
772
|
-
# 写前为空,处理关闭写
|
773
|
-
if data.empty? then
|
774
|
-
if src_info[ :closing_write ] then
|
775
|
-
close_write_src( src )
|
776
|
-
else
|
777
|
-
@writes.delete( src )
|
778
|
-
end
|
779
|
-
|
780
|
-
return
|
781
|
-
end
|
782
|
-
|
783
|
-
# 写入
|
784
|
-
begin
|
785
|
-
written = src.write_nonblock( data )
|
786
|
-
rescue IO::WaitWritable, Errno::EINTR
|
787
|
-
print 'w'
|
788
|
-
return
|
789
|
-
rescue Exception => e
|
790
|
-
# puts "debug write src #{ e.class }"
|
791
|
-
close_write_src( src )
|
792
|
-
|
793
|
-
if dst then
|
794
|
-
close_read_dst( dst )
|
795
|
-
end
|
796
|
-
|
797
|
-
return
|
798
|
-
end
|
799
|
-
|
800
|
-
data = data[ written..-1 ]
|
801
|
-
src_info[ :wbuff ] = data
|
802
|
-
end
|
803
|
-
|
804
|
-
##
|
805
|
-
# write dst
|
806
|
-
#
|
807
|
-
def write_dst( dst )
|
808
|
-
if dst.closed? then
|
809
|
-
puts "p#{ Process.pid } #{ Time.new } write dst but dst closed?"
|
810
|
-
return
|
811
|
-
end
|
812
|
-
|
813
|
-
dst_info = @dst_infos[ dst ]
|
814
|
-
src = dst_info[ :src ]
|
815
|
-
data = dst_info[ :wbuff ]
|
816
|
-
|
817
|
-
# 写前为空,处理关闭写
|
818
|
-
if data.empty? then
|
819
|
-
if dst_info[ :closing_write ] then
|
820
|
-
close_write_dst( dst )
|
821
|
-
else
|
822
|
-
@writes.delete( dst )
|
823
|
-
end
|
824
|
-
|
825
|
-
return
|
826
|
-
end
|
827
|
-
|
828
|
-
# 写入
|
829
|
-
begin
|
830
|
-
written = dst.write_nonblock( data )
|
831
|
-
rescue IO::WaitWritable, Errno::EINTR
|
832
|
-
print 'w'
|
833
|
-
return
|
834
|
-
rescue Exception => e
|
835
|
-
# puts "debug write dst #{ e.class }"
|
836
|
-
close_write_dst( dst )
|
837
|
-
close_read_src( src )
|
838
|
-
return
|
839
|
-
end
|
840
|
-
|
841
|
-
data = data[ written..-1 ]
|
842
|
-
dst_info[ :wbuff ] = data
|
843
|
-
|
844
|
-
unless src.closed? then
|
845
|
-
src_info = @src_infos[ src ]
|
846
|
-
src_info[ :last_sent_at ] = Time.new
|
847
|
-
end
|
848
|
-
end
|
849
|
-
|
850
|
-
end
|
851
|
-
end
|