girl 0.75.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 +7 -0
- data/girl.gemspec +34 -0
- data/lib/girl.rb +2 -0
- data/lib/girl/custom.rb +12 -0
- data/lib/girl/head.rb +50 -0
- data/lib/girl/proxy.rb +208 -0
- data/lib/girl/proxy_custom.rb +15 -0
- data/lib/girl/proxy_worker.rb +1425 -0
- data/lib/girl/proxyd.rb +96 -0
- data/lib/girl/proxyd_custom.rb +12 -0
- data/lib/girl/proxyd_worker.rb +987 -0
- data/lib/girl/udp.rb +300 -0
- data/lib/girl/udpd.rb +286 -0
- data/lib/girl/version.rb +3 -0
- metadata +57 -0
data/lib/girl/proxyd.rb
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'etc'
|
2
|
+
require 'girl/head'
|
3
|
+
require 'girl/proxyd_custom'
|
4
|
+
require 'girl/proxyd_worker'
|
5
|
+
require 'girl/version'
|
6
|
+
require 'json'
|
7
|
+
require 'socket'
|
8
|
+
|
9
|
+
##
|
10
|
+
# Girl::Proxyd - 代理服务,远端。
|
11
|
+
#
|
12
|
+
module Girl
|
13
|
+
class Proxyd
|
14
|
+
|
15
|
+
def initialize( config_path = nil )
|
16
|
+
if config_path
|
17
|
+
unless File.exist?( config_path )
|
18
|
+
raise "not found config file #{ config_path }"
|
19
|
+
end
|
20
|
+
|
21
|
+
conf = JSON.parse( IO.binread( config_path ), symbolize_names: true )
|
22
|
+
proxyd_port = conf[ :proxyd_port ]
|
23
|
+
proxyd_tmp_dir = conf[ :proxyd_tmp_dir ]
|
24
|
+
worker_count = conf[ :worker_count ]
|
25
|
+
end
|
26
|
+
|
27
|
+
unless proxyd_port
|
28
|
+
proxyd_port = 6060
|
29
|
+
end
|
30
|
+
|
31
|
+
unless proxyd_tmp_dir
|
32
|
+
proxyd_tmp_dir = '/tmp/girl.proxyd'
|
33
|
+
end
|
34
|
+
|
35
|
+
unless File.exist?( proxyd_tmp_dir )
|
36
|
+
Dir.mkdir( proxyd_tmp_dir )
|
37
|
+
end
|
38
|
+
|
39
|
+
dst_chunk_dir = File.join( proxyd_tmp_dir, 'dst.chunk' )
|
40
|
+
|
41
|
+
unless Dir.exist?( dst_chunk_dir )
|
42
|
+
Dir.mkdir( dst_chunk_dir )
|
43
|
+
end
|
44
|
+
|
45
|
+
tund_chunk_dir = File.join( proxyd_tmp_dir, 'tund.chunk' )
|
46
|
+
|
47
|
+
unless Dir.exist?( tund_chunk_dir )
|
48
|
+
Dir.mkdir( tund_chunk_dir )
|
49
|
+
end
|
50
|
+
|
51
|
+
nprocessors = Etc.nprocessors
|
52
|
+
|
53
|
+
if worker_count.nil? || worker_count <= 0 || worker_count > nprocessors
|
54
|
+
worker_count = nprocessors
|
55
|
+
end
|
56
|
+
|
57
|
+
title = "girl proxyd #{ Girl::VERSION }"
|
58
|
+
puts title
|
59
|
+
puts "proxyd port #{ proxyd_port }"
|
60
|
+
puts "dst chunk dir #{ dst_chunk_dir }"
|
61
|
+
puts "tund chunk dir #{ tund_chunk_dir }"
|
62
|
+
puts "worker count #{ worker_count }"
|
63
|
+
|
64
|
+
$0 = title
|
65
|
+
workers = []
|
66
|
+
|
67
|
+
worker_count.times do | i |
|
68
|
+
workers << fork do
|
69
|
+
$0 = 'girl proxyd worker'
|
70
|
+
worker = Girl::ProxydWorker.new( proxyd_port, dst_chunk_dir, tund_chunk_dir )
|
71
|
+
|
72
|
+
Signal.trap( :TERM ) do
|
73
|
+
puts "w#{ i } exit"
|
74
|
+
worker.quit!
|
75
|
+
end
|
76
|
+
|
77
|
+
worker.looping
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
Signal.trap( :TERM ) do
|
82
|
+
puts 'trap TERM'
|
83
|
+
workers.each do | pid |
|
84
|
+
begin
|
85
|
+
Process.kill( :TERM, pid )
|
86
|
+
rescue Errno::ESRCH => e
|
87
|
+
puts e.class
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
Process.waitall
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,987 @@
|
|
1
|
+
module Girl
|
2
|
+
class ProxydWorker
|
3
|
+
|
4
|
+
##
|
5
|
+
# initialize
|
6
|
+
#
|
7
|
+
def initialize( proxyd_port, dst_chunk_dir, tund_chunk_dir )
|
8
|
+
@dst_chunk_dir = dst_chunk_dir
|
9
|
+
@tund_chunk_dir = tund_chunk_dir
|
10
|
+
@custom = Girl::ProxydCustom.new
|
11
|
+
@mutex = Mutex.new
|
12
|
+
@reads = []
|
13
|
+
@writes = []
|
14
|
+
@roles = {} # sock => :dotr / :proxyd / :dst / :tund
|
15
|
+
@dst_infos = {} # dst => {}
|
16
|
+
@tunds = {} # port => tund
|
17
|
+
@tund_infos = {} # tund => {}
|
18
|
+
@tunneling_tunds = {} # tunneling_addr => tund
|
19
|
+
@resolv_caches = {} # domain => [ ip, created_at ]
|
20
|
+
|
21
|
+
dotr, dotw = IO.pipe
|
22
|
+
@dotw = dotw
|
23
|
+
add_read( dotr, :dotr )
|
24
|
+
new_a_proxyd( proxyd_port )
|
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_status
|
34
|
+
|
35
|
+
loop do
|
36
|
+
rs, ws = IO.select( @reads, @writes )
|
37
|
+
|
38
|
+
@mutex.synchronize do
|
39
|
+
# 先写,再读
|
40
|
+
ws.each do | sock |
|
41
|
+
case @roles[ sock ]
|
42
|
+
when :proxyd
|
43
|
+
write_proxyd( sock )
|
44
|
+
when :dst
|
45
|
+
write_dst( sock )
|
46
|
+
when :tund
|
47
|
+
write_tund( sock )
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
rs.each do | sock |
|
52
|
+
case @roles[ sock ]
|
53
|
+
when :dotr
|
54
|
+
read_dotr( sock )
|
55
|
+
when :proxyd
|
56
|
+
read_proxyd( sock )
|
57
|
+
when :dst
|
58
|
+
read_dst( sock )
|
59
|
+
when :tund
|
60
|
+
read_tund( sock )
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
rescue Interrupt => e
|
66
|
+
puts e.class
|
67
|
+
quit!
|
68
|
+
end
|
69
|
+
|
70
|
+
##
|
71
|
+
# quit!
|
72
|
+
#
|
73
|
+
def quit!
|
74
|
+
data = [ 0, TUND_FIN ].pack( 'Q>C' )
|
75
|
+
|
76
|
+
@tund_infos.each do | tund, tund_info |
|
77
|
+
if !tund.closed? && tund_info[ :tun_addr ]
|
78
|
+
# puts "debug1 send tund fin"
|
79
|
+
tund.sendmsg( data, 0, tund_info[ :tun_addr ] )
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# puts "debug1 exit"
|
84
|
+
exit
|
85
|
+
end
|
86
|
+
|
87
|
+
private
|
88
|
+
|
89
|
+
##
|
90
|
+
# loop check expire
|
91
|
+
#
|
92
|
+
def loop_check_expire
|
93
|
+
Thread.new do
|
94
|
+
loop do
|
95
|
+
sleep CHECK_EXPIRE_INTERVAL
|
96
|
+
|
97
|
+
@mutex.synchronize do
|
98
|
+
need_trigger = false
|
99
|
+
now = Time.new
|
100
|
+
|
101
|
+
@tund_infos.each do | tund, tund_info |
|
102
|
+
unless tund.closed?
|
103
|
+
is_expired = tund_info[ :last_recv_at ] ? ( now - tund_info[ :last_recv_at ] > EXPIRE_AFTER ) : ( now - tund_info[ :created_at ] > EXPIRE_NEW )
|
104
|
+
|
105
|
+
if is_expired
|
106
|
+
puts "p#{ Process.pid } #{ Time.new } expire tund #{ tund_info[ :port ] }"
|
107
|
+
set_is_closing( tund )
|
108
|
+
else
|
109
|
+
data = [ 0, HEARTBEAT, rand( 128 ) ].pack( 'Q>CC' )
|
110
|
+
# puts "debug1 #{ Time.new } #{ tund_info[ :port ] } heartbeat"
|
111
|
+
add_tund_ctlmsg( tund, data )
|
112
|
+
|
113
|
+
tund_info[ :dst_exts ].each do | dst_local_port, dst_ext |
|
114
|
+
if dst_ext[ :dst ].closed? && ( now - dst_ext[ :last_continue_at ] > EXPIRE_AFTER )
|
115
|
+
puts "p#{ Process.pid } #{ Time.new } expire dst ext #{ dst_ext[ :domain_port ] }"
|
116
|
+
del_dst_ext( tund, dst_local_port )
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
need_trigger = true
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
@dst_infos.each do | dst, dst_info |
|
126
|
+
if now - dst_info[ :last_continue_at ] > EXPIRE_AFTER
|
127
|
+
puts "p#{ Process.pid } #{ Time.new } expire dst #{ dst_info[ :domain_port ] }"
|
128
|
+
set_is_closing( dst )
|
129
|
+
need_trigger = true
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
if need_trigger
|
134
|
+
next_tick
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
##
|
142
|
+
# loop check status
|
143
|
+
#
|
144
|
+
def loop_check_status
|
145
|
+
Thread.new do
|
146
|
+
loop do
|
147
|
+
sleep STATUS_INTERVAL
|
148
|
+
|
149
|
+
if @tunds.any?
|
150
|
+
@mutex.synchronize do
|
151
|
+
need_trigger = false
|
152
|
+
|
153
|
+
@tunds.each do | tund_port, tund |
|
154
|
+
tund_info = @tund_infos[ tund ]
|
155
|
+
|
156
|
+
if tund_info[ :dst_exts ].any?
|
157
|
+
now = Time.new
|
158
|
+
|
159
|
+
tund_info[ :dst_exts ].each do | dst_local_port, dst_ext |
|
160
|
+
if now - dst_ext[ :last_continue_at ] < SEND_STATUS_UNTIL
|
161
|
+
data = [ 0, DEST_STATUS, dst_local_port, dst_ext[ :relay_pack_id ], dst_ext[ :continue_src_pack_id ] ].pack( 'Q>CnQ>Q>' )
|
162
|
+
add_tund_ctlmsg( tund, data )
|
163
|
+
need_trigger = true
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
if tund_info[ :paused ] && ( tund_info[ :dst_exts ].map{ | _, dst_ext | dst_ext[ :wmems ].size }.sum < RESUME_BELOW )
|
169
|
+
puts "p#{ Process.pid } #{ Time.new } resume tund"
|
170
|
+
tund_info[ :paused ] = false
|
171
|
+
add_write( tund )
|
172
|
+
need_trigger = true
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
if need_trigger
|
177
|
+
next_tick
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
##
|
186
|
+
# resolve domain
|
187
|
+
#
|
188
|
+
def resolve_domain( tund, src_id, destination_domain_port )
|
189
|
+
resolv_cache = @resolv_caches[ destination_domain_port ]
|
190
|
+
|
191
|
+
if resolv_cache
|
192
|
+
destination_addr, created_at = resolv_cache
|
193
|
+
|
194
|
+
if Time.new - created_at < RESOLV_CACHE_EXPIRE
|
195
|
+
# puts "debug1 #{ destination_domain_port } hit resolv cache #{ Addrinfo.new( destination_addr ).inspect }"
|
196
|
+
deal_with_destination_addr( tund, src_id, destination_addr, destination_domain_port )
|
197
|
+
return
|
198
|
+
end
|
199
|
+
|
200
|
+
# puts "debug1 expire #{ destination_domain_port } resolv cache"
|
201
|
+
@resolv_caches.delete( destination_domain_port )
|
202
|
+
end
|
203
|
+
|
204
|
+
Thread.new do
|
205
|
+
colon_idx = destination_domain_port.rindex( ':' )
|
206
|
+
|
207
|
+
if colon_idx
|
208
|
+
destination_domain = destination_domain_port[ 0...colon_idx ]
|
209
|
+
destination_port = destination_domain_port[ ( colon_idx + 1 )..-1 ].to_i
|
210
|
+
|
211
|
+
begin
|
212
|
+
destination_addr = Socket.sockaddr_in( destination_port, destination_domain )
|
213
|
+
rescue Exception => e
|
214
|
+
puts "p#{ Process.pid } #{ Time.new } sockaddr in #{ destination_domain_port } #{ e.class }"
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
@mutex.synchronize do
|
219
|
+
if destination_addr
|
220
|
+
# puts "debug1 resolved #{ destination_domain_port } #{ Addrinfo.new( destination_addr ).inspect }"
|
221
|
+
@resolv_caches[ destination_domain_port ] = [ destination_addr, Time.new ]
|
222
|
+
|
223
|
+
unless tund.closed?
|
224
|
+
if deal_with_destination_addr( tund, src_id, destination_addr, destination_domain_port )
|
225
|
+
next_tick
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
##
|
234
|
+
# deal with destination addr
|
235
|
+
#
|
236
|
+
def deal_with_destination_addr( tund, src_id, destination_addr, destination_domain_port )
|
237
|
+
dst = Socket.new( Addrinfo.new( destination_addr ).ipv4? ? Socket::AF_INET : Socket::AF_INET6, Socket::SOCK_STREAM, 0 )
|
238
|
+
dst.setsockopt( Socket::SOL_TCP, Socket::TCP_NODELAY, 1 )
|
239
|
+
|
240
|
+
begin
|
241
|
+
dst.connect_nonblock( destination_addr )
|
242
|
+
rescue IO::WaitWritable
|
243
|
+
rescue Exception => e
|
244
|
+
puts "p#{ Process.pid } #{ Time.new } connect destination #{ e.class }"
|
245
|
+
return false
|
246
|
+
end
|
247
|
+
|
248
|
+
local_port = dst.local_address.ip_port
|
249
|
+
|
250
|
+
@dst_infos[ dst ] = {
|
251
|
+
local_port: local_port, # 本地端口
|
252
|
+
tund: tund, # 对应tund
|
253
|
+
domain_port: destination_domain_port, # 域名和端口
|
254
|
+
biggest_pack_id: 0, # 最大包号码
|
255
|
+
wbuff: '', # 写前
|
256
|
+
cache: '', # 块读出缓存
|
257
|
+
chunks: [], # 块队列,写前达到块大小时结一个块 filename
|
258
|
+
spring: 0, # 块后缀,结块时,如果块队列不为空,则自增,为空,则置为0
|
259
|
+
last_continue_at: Time.new, # 上一次发生流量的时间
|
260
|
+
is_closing: false # 是否准备关闭
|
261
|
+
}
|
262
|
+
add_read( dst, :dst )
|
263
|
+
|
264
|
+
tund_info = @tund_infos[ tund ]
|
265
|
+
tund_info[ :dst_local_ports ][ src_id ] = local_port
|
266
|
+
tund_info[ :dst_exts ][ local_port ] = {
|
267
|
+
dst: dst, # dst
|
268
|
+
src_id: src_id, # 近端src id
|
269
|
+
domain_port: destination_domain_port, # 域名和端口
|
270
|
+
wmems: {}, # 写后 pack_id => data
|
271
|
+
send_ats: {}, # 上一次发出时间 pack_id => send_at
|
272
|
+
relay_pack_id: 0, # 转发到几
|
273
|
+
continue_src_pack_id: 0, # 收到几
|
274
|
+
pieces: {}, # 跳号包 src_pack_id => data
|
275
|
+
is_src_closed: false, # src是否已关闭
|
276
|
+
biggest_src_pack_id: 0, # src最大包号码
|
277
|
+
completed_pack_id: 0, # 完成到几(对面收到几)
|
278
|
+
last_continue_at: Time.new # 上一次发生流量的时间
|
279
|
+
}
|
280
|
+
|
281
|
+
data = [ 0, PAIRED, src_id, local_port ].pack( 'Q>CQ>n' )
|
282
|
+
# puts "debug1 add ctlmsg paired #{ data.inspect }"
|
283
|
+
add_tund_ctlmsg( tund, data )
|
284
|
+
|
285
|
+
true
|
286
|
+
end
|
287
|
+
|
288
|
+
##
|
289
|
+
# new a proxyd
|
290
|
+
#
|
291
|
+
def new_a_proxyd( proxyd_port )
|
292
|
+
proxyd = Socket.new( Socket::AF_INET, Socket::SOCK_DGRAM, 0 )
|
293
|
+
proxyd.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEPORT, 1 )
|
294
|
+
proxyd.bind( Socket.sockaddr_in( proxyd_port, '0.0.0.0' ) )
|
295
|
+
|
296
|
+
puts "p#{ Process.pid } #{ Time.new } proxyd bind on #{ proxyd_port }"
|
297
|
+
@proxyd = proxyd
|
298
|
+
@proxyd_ctlmsgs = [] # [ to_addr, data ]
|
299
|
+
add_read( proxyd, :proxyd )
|
300
|
+
end
|
301
|
+
|
302
|
+
##
|
303
|
+
# add proxyd ctlmsg
|
304
|
+
#
|
305
|
+
def add_proxyd_ctlmsg( data, to_addr )
|
306
|
+
@proxyd_ctlmsgs << [ to_addr, data ]
|
307
|
+
add_write( @proxyd )
|
308
|
+
end
|
309
|
+
|
310
|
+
##
|
311
|
+
# add tund ctlmsg
|
312
|
+
#
|
313
|
+
def add_tund_ctlmsg( tund, data )
|
314
|
+
tund_info = @tund_infos[ tund ]
|
315
|
+
tund_info[ :ctlmsgs ] << data
|
316
|
+
add_write( tund )
|
317
|
+
end
|
318
|
+
|
319
|
+
##
|
320
|
+
# add tund wbuff
|
321
|
+
#
|
322
|
+
def add_tund_wbuff( tund, dst_local_port, pack_id, data )
|
323
|
+
tund_info = @tund_infos[ tund ]
|
324
|
+
tund_info[ :wbuffs ] << [ dst_local_port, pack_id, data ]
|
325
|
+
|
326
|
+
if tund_info[ :wbuffs ].size >= WBUFFS_LIMIT
|
327
|
+
spring = tund_info[ :chunks ].size > 0 ? ( tund_info[ :spring ] + 1 ) : 0
|
328
|
+
filename = "#{ Process.pid }-#{ tund_info[ :port ] }.#{ spring }"
|
329
|
+
chunk_path = File.join( @tund_chunk_dir, filename )
|
330
|
+
datas = tund_info[ :wbuffs ].map{ | _dst_local_port, _pack_id, _data | [ [ _dst_local_port, _pack_id, _data.bytesize ].pack( 'nQ>n' ), _data ].join }
|
331
|
+
|
332
|
+
begin
|
333
|
+
IO.binwrite( chunk_path, datas.join )
|
334
|
+
rescue Errno::ENOSPC => e
|
335
|
+
puts "p#{ Process.pid } #{ Time.new } #{ e.class }, close tund"
|
336
|
+
set_is_closing( tund )
|
337
|
+
return
|
338
|
+
end
|
339
|
+
|
340
|
+
tund_info[ :chunks ] << filename
|
341
|
+
tund_info[ :spring ] = spring
|
342
|
+
tund_info[ :wbuffs ].clear
|
343
|
+
end
|
344
|
+
|
345
|
+
add_write( tund )
|
346
|
+
end
|
347
|
+
|
348
|
+
##
|
349
|
+
# add dst wbuff
|
350
|
+
#
|
351
|
+
def add_dst_wbuff( dst, data )
|
352
|
+
dst_info = @dst_infos[ dst ]
|
353
|
+
dst_info[ :wbuff ] << data
|
354
|
+
|
355
|
+
if dst_info[ :wbuff ].bytesize >= CHUNK_SIZE
|
356
|
+
spring = dst_info[ :chunks ].size > 0 ? ( dst_info[ :spring ] + 1 ) : 0
|
357
|
+
filename = "#{ Process.pid }-#{ dst_info[ :local_port ] }.#{ spring }"
|
358
|
+
chunk_path = File.join( @dst_chunk_dir, filename )
|
359
|
+
|
360
|
+
begin
|
361
|
+
IO.binwrite( chunk_path, dst_info[ :wbuff ] )
|
362
|
+
rescue Errno::ENOSPC => e
|
363
|
+
puts "p#{ Process.pid } #{ Time.new } #{ e.class }, close dst"
|
364
|
+
set_is_closing( dst )
|
365
|
+
return
|
366
|
+
end
|
367
|
+
|
368
|
+
dst_info[ :chunks ] << filename
|
369
|
+
dst_info[ :spring ] = spring
|
370
|
+
dst_info[ :wbuff ].clear
|
371
|
+
end
|
372
|
+
|
373
|
+
add_write( dst )
|
374
|
+
end
|
375
|
+
|
376
|
+
##
|
377
|
+
# add read
|
378
|
+
#
|
379
|
+
def add_read( sock, role )
|
380
|
+
unless @reads.include?( sock )
|
381
|
+
@reads << sock
|
382
|
+
end
|
383
|
+
|
384
|
+
@roles[ sock ] = role
|
385
|
+
end
|
386
|
+
|
387
|
+
##
|
388
|
+
# add write
|
389
|
+
#
|
390
|
+
def add_write( sock )
|
391
|
+
if sock && !sock.closed? && !@writes.include?( sock )
|
392
|
+
@writes << sock
|
393
|
+
end
|
394
|
+
end
|
395
|
+
|
396
|
+
##
|
397
|
+
# set is closing
|
398
|
+
#
|
399
|
+
def set_is_closing( sock )
|
400
|
+
if sock && !sock.closed?
|
401
|
+
role = @roles[ sock ]
|
402
|
+
# puts "debug1 set #{ role.to_s } is closing"
|
403
|
+
|
404
|
+
case role
|
405
|
+
when :dst
|
406
|
+
dst_info = @dst_infos[ sock ]
|
407
|
+
dst_info[ :is_closing ] = true
|
408
|
+
when :tund
|
409
|
+
tund_info = @tund_infos[ sock ]
|
410
|
+
tund_info[ :is_closing ] = true
|
411
|
+
end
|
412
|
+
|
413
|
+
@reads.delete( sock )
|
414
|
+
add_write( sock )
|
415
|
+
end
|
416
|
+
end
|
417
|
+
|
418
|
+
##
|
419
|
+
# send data
|
420
|
+
#
|
421
|
+
def send_data( tund, data, to_addr )
|
422
|
+
begin
|
423
|
+
tund.sendmsg( data, 0, to_addr )
|
424
|
+
rescue IO::WaitWritable, Errno::EINTR
|
425
|
+
return false
|
426
|
+
rescue Errno::EHOSTUNREACH, Errno::ENETUNREACH, Errno::ENETDOWN => e
|
427
|
+
puts "#{ Time.new } #{ e.class }, close tund"
|
428
|
+
close_tund( tund )
|
429
|
+
return false
|
430
|
+
end
|
431
|
+
|
432
|
+
true
|
433
|
+
end
|
434
|
+
|
435
|
+
##
|
436
|
+
# close dst
|
437
|
+
#
|
438
|
+
def close_dst( dst )
|
439
|
+
# puts "debug1 close dst"
|
440
|
+
close_sock( dst )
|
441
|
+
dst_info = @dst_infos.delete( dst )
|
442
|
+
|
443
|
+
dst_info[ :chunks ].each do | filename |
|
444
|
+
begin
|
445
|
+
File.delete( File.join( @dst_chunk_dir, filename ) )
|
446
|
+
rescue Errno::ENOENT
|
447
|
+
end
|
448
|
+
end
|
449
|
+
|
450
|
+
tund = dst_info[ :tund ]
|
451
|
+
return if tund.closed?
|
452
|
+
|
453
|
+
tund_info = @tund_infos[ tund ]
|
454
|
+
local_port = dst_info[ :local_port ]
|
455
|
+
dst_ext = tund_info[ :dst_exts ][ local_port ]
|
456
|
+
return unless dst_ext
|
457
|
+
|
458
|
+
if dst_ext[ :is_src_closed ]
|
459
|
+
# puts "debug1 4-3. after close dst -> src closed ? yes -> del dst ext -> send fin2"
|
460
|
+
del_dst_ext( tund, local_port )
|
461
|
+
data = [ 0, FIN2, local_port ].pack( 'Q>Cn' )
|
462
|
+
add_tund_ctlmsg( tund, data )
|
463
|
+
else
|
464
|
+
# puts "debug1 3-1. after close dst -> src closed ? no -> send fin1"
|
465
|
+
data = [ 0, FIN1, local_port, dst_info[ :biggest_pack_id ], dst_ext[ :continue_src_pack_id ] ].pack( 'Q>CnQ>Q>' )
|
466
|
+
add_tund_ctlmsg( tund, data )
|
467
|
+
end
|
468
|
+
end
|
469
|
+
|
470
|
+
##
|
471
|
+
# close tun
|
472
|
+
#
|
473
|
+
def close_tund( tund )
|
474
|
+
# puts "debug1 close tund"
|
475
|
+
close_sock( tund )
|
476
|
+
|
477
|
+
tund_info = @tund_infos.delete( tund )
|
478
|
+
tund_info[ :chunks ].each do | filename |
|
479
|
+
begin
|
480
|
+
File.delete( File.join( @tund_chunk_dir, filename ) )
|
481
|
+
rescue Errno::ENOENT
|
482
|
+
end
|
483
|
+
end
|
484
|
+
|
485
|
+
tund_info[ :dst_exts ].each{ | _, dst_ext | set_is_closing( dst_ext[ :dst ] ) }
|
486
|
+
@tunneling_tunds.delete( tund_info[ :tun_addr ] )
|
487
|
+
@tunds.delete( tund_info[ :port ] )
|
488
|
+
end
|
489
|
+
|
490
|
+
##
|
491
|
+
# close sock
|
492
|
+
#
|
493
|
+
def close_sock( sock )
|
494
|
+
sock.close
|
495
|
+
@reads.delete( sock )
|
496
|
+
@writes.delete( sock )
|
497
|
+
@roles.delete( sock )
|
498
|
+
end
|
499
|
+
|
500
|
+
##
|
501
|
+
# del dst ext
|
502
|
+
#
|
503
|
+
def del_dst_ext( tund, dst_local_port )
|
504
|
+
tund_info = @tund_infos[ tund ]
|
505
|
+
dst_ext = tund_info[ :dst_exts ].delete( dst_local_port )
|
506
|
+
|
507
|
+
if dst_ext
|
508
|
+
tund_info[ :dst_local_ports ].delete( dst_ext[ :src_id ] )
|
509
|
+
end
|
510
|
+
end
|
511
|
+
|
512
|
+
##
|
513
|
+
# release wmems
|
514
|
+
#
|
515
|
+
def release_wmems( dst_ext, completed_pack_id )
|
516
|
+
if completed_pack_id > dst_ext[ :completed_pack_id ]
|
517
|
+
# puts "debug2 update completed pack #{ completed_pack_id }"
|
518
|
+
|
519
|
+
pack_ids = dst_ext[ :wmems ].keys.select { | pack_id | pack_id <= completed_pack_id }
|
520
|
+
|
521
|
+
pack_ids.each do | pack_id |
|
522
|
+
dst_ext[ :wmems ].delete( pack_id )
|
523
|
+
dst_ext[ :send_ats ].delete( pack_id )
|
524
|
+
end
|
525
|
+
|
526
|
+
dst_ext[ :completed_pack_id ] = completed_pack_id
|
527
|
+
end
|
528
|
+
end
|
529
|
+
|
530
|
+
##
|
531
|
+
# next tick
|
532
|
+
#
|
533
|
+
def next_tick
|
534
|
+
@dotw.write( '.' )
|
535
|
+
end
|
536
|
+
|
537
|
+
##
|
538
|
+
# write proxyd
|
539
|
+
#
|
540
|
+
def write_proxyd( proxyd )
|
541
|
+
while @proxyd_ctlmsgs.any?
|
542
|
+
to_addr, data = @proxyd_ctlmsgs.first
|
543
|
+
|
544
|
+
begin
|
545
|
+
proxyd.sendmsg( data, 0, to_addr )
|
546
|
+
rescue IO::WaitWritable, Errno::EINTR
|
547
|
+
return
|
548
|
+
end
|
549
|
+
|
550
|
+
@proxyd_ctlmsgs.shift
|
551
|
+
end
|
552
|
+
|
553
|
+
@writes.delete( proxyd )
|
554
|
+
end
|
555
|
+
|
556
|
+
##
|
557
|
+
# write dst
|
558
|
+
#
|
559
|
+
def write_dst( dst )
|
560
|
+
dst_info = @dst_infos[ dst ]
|
561
|
+
data = dst_info[ :cache ]
|
562
|
+
from = :cache
|
563
|
+
|
564
|
+
if data.empty?
|
565
|
+
if dst_info[ :chunks ].any?
|
566
|
+
path = File.join( @dst_chunk_dir, dst_info[ :chunks ].shift )
|
567
|
+
|
568
|
+
begin
|
569
|
+
dst_info[ :cache ] = data = IO.binread( path )
|
570
|
+
File.delete( path )
|
571
|
+
rescue Errno::ENOENT => e
|
572
|
+
puts "p#{ Process.pid } #{ Time.new } read #{ path } #{ e.class }"
|
573
|
+
close_dst( dst )
|
574
|
+
return
|
575
|
+
end
|
576
|
+
else
|
577
|
+
data = dst_info[ :wbuff ]
|
578
|
+
from = :wbuff
|
579
|
+
end
|
580
|
+
end
|
581
|
+
|
582
|
+
if data.empty?
|
583
|
+
if dst_info[ :is_closing ]
|
584
|
+
close_dst( dst )
|
585
|
+
else
|
586
|
+
@writes.delete( dst )
|
587
|
+
end
|
588
|
+
|
589
|
+
return
|
590
|
+
end
|
591
|
+
|
592
|
+
begin
|
593
|
+
written = dst.write_nonblock( data )
|
594
|
+
rescue IO::WaitWritable, Errno::EINTR
|
595
|
+
return
|
596
|
+
rescue Exception => e
|
597
|
+
# puts "debug1 write dst #{ e.class }"
|
598
|
+
close_dst( dst )
|
599
|
+
return
|
600
|
+
end
|
601
|
+
|
602
|
+
# puts "debug2 write dst #{ written }"
|
603
|
+
data = data[ written..-1 ]
|
604
|
+
dst_info[ from ] = data
|
605
|
+
dst_info[ :last_continue_at ] = Time.new
|
606
|
+
end
|
607
|
+
|
608
|
+
##
|
609
|
+
# write tund
|
610
|
+
#
|
611
|
+
def write_tund( tund )
|
612
|
+
tund_info = @tund_infos[ tund ]
|
613
|
+
|
614
|
+
if tund_info[ :is_closing ]
|
615
|
+
close_tund( tund )
|
616
|
+
return
|
617
|
+
end
|
618
|
+
|
619
|
+
# 传ctlmsg
|
620
|
+
while tund_info[ :ctlmsgs ].any?
|
621
|
+
data = tund_info[ :ctlmsgs ].first
|
622
|
+
|
623
|
+
unless send_data( tund, data, tund_info[ :tun_addr ] )
|
624
|
+
return
|
625
|
+
end
|
626
|
+
|
627
|
+
tund_info[ :ctlmsgs ].shift
|
628
|
+
end
|
629
|
+
|
630
|
+
# 重传
|
631
|
+
while tund_info[ :resendings ].any?
|
632
|
+
dst_local_port, pack_id = tund_info[ :resendings ].first
|
633
|
+
dst_ext = tund_info[ :dst_exts ][ dst_local_port ]
|
634
|
+
|
635
|
+
if dst_ext
|
636
|
+
data = dst_ext[ :wmems ][ pack_id ]
|
637
|
+
|
638
|
+
if data
|
639
|
+
unless send_data( tund, data, tund_info[ :tun_addr ] )
|
640
|
+
return
|
641
|
+
end
|
642
|
+
end
|
643
|
+
end
|
644
|
+
|
645
|
+
tund_info[ :resendings ].shift
|
646
|
+
return
|
647
|
+
end
|
648
|
+
|
649
|
+
# 若写后达到上限,暂停取写前
|
650
|
+
if tund_info[ :dst_exts ].map{ | _, dst_ext | dst_ext[ :wmems ].size }.sum >= WMEMS_LIMIT
|
651
|
+
unless tund_info[ :paused ]
|
652
|
+
puts "p#{ Process.pid } #{ Time.new } pause tund #{ tund_info[ :port ] }"
|
653
|
+
tund_info[ :paused ] = true
|
654
|
+
end
|
655
|
+
|
656
|
+
@writes.delete( tund )
|
657
|
+
return
|
658
|
+
end
|
659
|
+
|
660
|
+
# 取写前
|
661
|
+
if tund_info[ :caches ].any?
|
662
|
+
dst_local_port, pack_id, data = tund_info[ :caches ].first
|
663
|
+
from = :caches
|
664
|
+
elsif tund_info[ :chunks ].any?
|
665
|
+
path = File.join( @tund_chunk_dir, tund_info[ :chunks ].shift )
|
666
|
+
|
667
|
+
begin
|
668
|
+
data = IO.binread( path )
|
669
|
+
File.delete( path )
|
670
|
+
rescue Errno::ENOENT => e
|
671
|
+
puts "p#{ Process.pid } #{ Time.new } read #{ path } #{ e.class }"
|
672
|
+
close_tund( tund )
|
673
|
+
return
|
674
|
+
end
|
675
|
+
|
676
|
+
caches = []
|
677
|
+
|
678
|
+
until data.empty?
|
679
|
+
_dst_local_port, _pack_id, pack_size = data[ 0, 12 ].unpack( 'nQ>n' )
|
680
|
+
caches << [ _dst_local_port, _pack_id, data[ 12, pack_size ] ]
|
681
|
+
data = data[ ( 12 + pack_size )..-1 ]
|
682
|
+
end
|
683
|
+
|
684
|
+
tund_info[ :caches ] = caches
|
685
|
+
dst_local_port, pack_id, data = caches.first
|
686
|
+
from = :caches
|
687
|
+
elsif tund_info[ :wbuffs ].any?
|
688
|
+
dst_local_port, pack_id, data = tund_info[ :wbuffs ].first
|
689
|
+
from = :wbuffs
|
690
|
+
else
|
691
|
+
@writes.delete( tund )
|
692
|
+
return
|
693
|
+
end
|
694
|
+
|
695
|
+
dst_ext = tund_info[ :dst_exts ][ dst_local_port ]
|
696
|
+
|
697
|
+
if dst_ext
|
698
|
+
if pack_id <= CONFUSE_UNTIL
|
699
|
+
data = @custom.encode( data )
|
700
|
+
# puts "debug1 encoded pack #{ pack_id }"
|
701
|
+
end
|
702
|
+
|
703
|
+
data = [ [ pack_id, dst_local_port ].pack( 'Q>n' ), data ].join
|
704
|
+
|
705
|
+
unless send_data( tund, data, tund_info[ :tun_addr ] )
|
706
|
+
return
|
707
|
+
end
|
708
|
+
|
709
|
+
# puts "debug2 written pack #{ pack_id }"
|
710
|
+
now = Time.new
|
711
|
+
dst_ext[ :relay_pack_id ] = pack_id
|
712
|
+
dst_ext[ :wmems ][ pack_id ] = data
|
713
|
+
dst_ext[ :send_ats ][ pack_id ] = now
|
714
|
+
dst_ext[ :last_continue_at ] = now
|
715
|
+
end
|
716
|
+
|
717
|
+
tund_info[ from ].shift
|
718
|
+
end
|
719
|
+
|
720
|
+
##
|
721
|
+
# read dotr
|
722
|
+
#
|
723
|
+
def read_dotr( dotr )
|
724
|
+
dotr.read( 1 )
|
725
|
+
end
|
726
|
+
|
727
|
+
##
|
728
|
+
# read proxyd
|
729
|
+
#
|
730
|
+
def read_proxyd( proxyd )
|
731
|
+
data, addrinfo, rflags, *controls = proxyd.recvmsg
|
732
|
+
from_addr = addrinfo.to_sockaddr
|
733
|
+
|
734
|
+
return if @tunneling_tunds.include?( from_addr )
|
735
|
+
|
736
|
+
result = @custom.check( data, addrinfo )
|
737
|
+
|
738
|
+
if result != :success
|
739
|
+
puts "p#{ Process.pid } #{ Time.new } #{ result }"
|
740
|
+
return
|
741
|
+
end
|
742
|
+
|
743
|
+
tund = Socket.new( Socket::AF_INET, Socket::SOCK_DGRAM, 0 )
|
744
|
+
tund.bind( Socket.sockaddr_in( 0, '0.0.0.0' ) )
|
745
|
+
port = tund.local_address.ip_port
|
746
|
+
|
747
|
+
@tunneling_tunds[ from_addr ] = tund
|
748
|
+
@tunds[ port ] = tund
|
749
|
+
@tund_infos[ tund ] = {
|
750
|
+
port: port, # 端口
|
751
|
+
ctlmsgs: [], # data
|
752
|
+
wbuffs: [], # 写前缓存 [ dst_local_port, pack_id, data ]
|
753
|
+
caches: [], # 块读出缓存 [ dst_local_port, pack_id, data ]
|
754
|
+
chunks: [], # 块队列 filename
|
755
|
+
spring: 0, # 块后缀,结块时,如果块队列不为空,则自增,为空,则置为0
|
756
|
+
tun_addr: from_addr, # tun地址
|
757
|
+
dst_exts: {}, # dst额外信息 dst_local_port => {}
|
758
|
+
dst_local_ports: {}, # src_id => dst_local_port
|
759
|
+
paused: false, # 是否暂停写
|
760
|
+
resendings: [], # 重传队列 [ dst_local_port, pack_id ]
|
761
|
+
created_at: Time.new, # 创建时间
|
762
|
+
last_recv_at: nil, # 上一次收到流量的时间,过期关闭
|
763
|
+
is_closing: false # 是否准备关闭
|
764
|
+
}
|
765
|
+
|
766
|
+
add_read( tund, :tund )
|
767
|
+
|
768
|
+
data = [ 0, TUND_PORT, port ].pack( 'Q>Cn' )
|
769
|
+
puts "p#{ Process.pid } #{ Time.new } a new tunnel #{ addrinfo.ip_unpack.inspect } - #{ port }, #{ @tunds.size } tunds"
|
770
|
+
add_proxyd_ctlmsg( data, from_addr )
|
771
|
+
end
|
772
|
+
|
773
|
+
##
|
774
|
+
# read dst
|
775
|
+
#
|
776
|
+
def read_dst( dst )
|
777
|
+
begin
|
778
|
+
data = dst.read_nonblock( PACK_SIZE )
|
779
|
+
rescue IO::WaitReadable, Errno::EINTR
|
780
|
+
return
|
781
|
+
rescue Exception => e
|
782
|
+
# puts "debug1 read dst #{ e.class }"
|
783
|
+
set_is_closing( dst )
|
784
|
+
return
|
785
|
+
end
|
786
|
+
|
787
|
+
# puts "debug2 read dst #{ data.inspect }"
|
788
|
+
dst_info = @dst_infos[ dst ]
|
789
|
+
dst_info[ :last_continue_at ] = Time.new
|
790
|
+
tund = dst_info[ :tund ]
|
791
|
+
|
792
|
+
if tund.closed?
|
793
|
+
puts "p#{ Process.pid } #{ Time.new } tund closed, close dst"
|
794
|
+
set_is_closing( dst )
|
795
|
+
return
|
796
|
+
end
|
797
|
+
|
798
|
+
pack_id = dst_info[ :biggest_pack_id ] + 1
|
799
|
+
dst_info[ :biggest_pack_id ] = pack_id
|
800
|
+
add_tund_wbuff( tund, dst_info[ :local_port ], pack_id, data )
|
801
|
+
end
|
802
|
+
|
803
|
+
##
|
804
|
+
# read tund
|
805
|
+
#
|
806
|
+
def read_tund( tund )
|
807
|
+
data, addrinfo, rflags, *controls = tund.recvmsg
|
808
|
+
from_addr = addrinfo.to_sockaddr
|
809
|
+
now = Time.new
|
810
|
+
tund_info = @tund_infos[ tund ]
|
811
|
+
|
812
|
+
if from_addr != tund_info[ :tun_addr ]
|
813
|
+
if addrinfo.ip_port == Addrinfo.new( tund_info[ :tun_addr ] ).ip_port
|
814
|
+
puts "p#{ Process.pid } #{ Time.new } tun ip changed #{ addrinfo.inspect }"
|
815
|
+
tund_info[ :tun_addr ] = from_addr
|
816
|
+
else
|
817
|
+
puts "p#{ Process.pid } #{ Time.new } #{ addrinfo.inspect } not match #{ Addrinfo.new( tund_info[ :tun_addr ] ).inspect }"
|
818
|
+
return
|
819
|
+
end
|
820
|
+
end
|
821
|
+
|
822
|
+
tund_info[ :last_recv_at ] = now
|
823
|
+
pack_id = data[ 0, 8 ].unpack( 'Q>' ).first
|
824
|
+
|
825
|
+
if pack_id == 0
|
826
|
+
ctl_num = data[ 8 ].unpack( 'C' ).first
|
827
|
+
|
828
|
+
case ctl_num
|
829
|
+
when A_NEW_SOURCE
|
830
|
+
src_id = data[ 9, 8 ].unpack( 'Q>' ).first
|
831
|
+
dst_local_port = tund_info[ :dst_local_ports ][ src_id ]
|
832
|
+
|
833
|
+
if dst_local_port
|
834
|
+
dst_ext = tund_info[ :dst_exts ][ dst_local_port ]
|
835
|
+
return unless dst_ext
|
836
|
+
|
837
|
+
if dst_ext[ :dst ].closed?
|
838
|
+
dst_local_port = 0
|
839
|
+
end
|
840
|
+
|
841
|
+
# puts "debug1 readd ctlmsg paired #{ dst_local_port }"
|
842
|
+
data2 = [ 0, PAIRED, src_id, dst_local_port ].pack( 'Q>CQ>n' )
|
843
|
+
add_tund_ctlmsg( tund, data2 )
|
844
|
+
return
|
845
|
+
end
|
846
|
+
|
847
|
+
data = data[ 17..-1 ]
|
848
|
+
destination_domain_port = @custom.decode( data )
|
849
|
+
puts "p#{ Process.pid } #{ Time.new } a new source #{ src_id } #{ destination_domain_port }"
|
850
|
+
resolve_domain( tund, src_id, destination_domain_port )
|
851
|
+
when SOURCE_STATUS
|
852
|
+
src_id, relay_src_pack_id, continue_dst_pack_id = data[ 9, 24 ].unpack( 'Q>Q>Q>' )
|
853
|
+
|
854
|
+
dst_local_port = tund_info[ :dst_local_ports ][ src_id ]
|
855
|
+
return unless dst_local_port
|
856
|
+
|
857
|
+
dst_ext = tund_info[ :dst_exts ][ dst_local_port ]
|
858
|
+
return unless dst_ext
|
859
|
+
|
860
|
+
# puts "debug2 got source status"
|
861
|
+
|
862
|
+
release_wmems( dst_ext, continue_dst_pack_id )
|
863
|
+
|
864
|
+
# 发miss
|
865
|
+
if !dst_ext[ :dst ].closed? && ( dst_ext[ :continue_src_pack_id ] < relay_src_pack_id )
|
866
|
+
ranges = []
|
867
|
+
curr_pack_id = dst_ext[ :continue_src_pack_id ] + 1
|
868
|
+
|
869
|
+
dst_ext[ :pieces ].keys.sort.each do | pack_id |
|
870
|
+
if pack_id > curr_pack_id
|
871
|
+
ranges << [ curr_pack_id, pack_id - 1 ]
|
872
|
+
end
|
873
|
+
|
874
|
+
curr_pack_id = pack_id + 1
|
875
|
+
end
|
876
|
+
|
877
|
+
if curr_pack_id <= relay_src_pack_id
|
878
|
+
ranges << [ curr_pack_id, relay_src_pack_id ]
|
879
|
+
end
|
880
|
+
|
881
|
+
pack_count = 0
|
882
|
+
# puts "debug1 continue/relay #{ dst_ext[ :continue_src_pack_id ] }/#{ relay_src_pack_id } send MISS #{ ranges.size }"
|
883
|
+
|
884
|
+
ranges.each do | pack_id_begin, pack_id_end |
|
885
|
+
if pack_count >= BREAK_SEND_MISS
|
886
|
+
puts "p#{ Process.pid } #{ Time.new } break send miss at #{ pack_id_begin }"
|
887
|
+
break
|
888
|
+
end
|
889
|
+
|
890
|
+
data2 = [ 0, MISS, src_id, pack_id_begin, pack_id_end ].pack( 'Q>CQ>Q>Q>' )
|
891
|
+
add_tund_ctlmsg( tund, data2 )
|
892
|
+
pack_count += ( pack_id_end - pack_id_begin + 1 )
|
893
|
+
end
|
894
|
+
end
|
895
|
+
when MISS
|
896
|
+
dst_local_port, pack_id_begin, pack_id_end = data[ 9, 18 ].unpack( 'nQ>Q>' )
|
897
|
+
|
898
|
+
dst_ext = tund_info[ :dst_exts ][ dst_local_port ]
|
899
|
+
return unless dst_ext
|
900
|
+
|
901
|
+
( pack_id_begin..pack_id_end ).each do | pack_id |
|
902
|
+
send_at = dst_ext[ :send_ats ][ pack_id ]
|
903
|
+
|
904
|
+
if send_at
|
905
|
+
break if now - send_at < STATUS_INTERVAL
|
906
|
+
tund_info[ :resendings ] << [ dst_local_port, pack_id ]
|
907
|
+
end
|
908
|
+
end
|
909
|
+
|
910
|
+
add_write( tund )
|
911
|
+
when FIN1
|
912
|
+
src_id, biggest_src_pack_id, continue_dst_pack_id = data[ 9, 24 ].unpack( 'Q>Q>Q>' )
|
913
|
+
|
914
|
+
dst_local_port = tund_info[ :dst_local_ports ][ src_id ]
|
915
|
+
return unless dst_local_port
|
916
|
+
|
917
|
+
dst_ext = tund_info[ :dst_exts ][ dst_local_port ]
|
918
|
+
return unless dst_ext
|
919
|
+
|
920
|
+
# puts "debug1 got fin1 #{ src_id } biggest src pack #{ biggest_src_pack_id } completed dst pack #{ continue_dst_pack_id }"
|
921
|
+
dst_ext[ :is_src_closed ] = true
|
922
|
+
dst_ext[ :biggest_src_pack_id ] = biggest_src_pack_id
|
923
|
+
release_wmems( dst_ext, continue_dst_pack_id )
|
924
|
+
|
925
|
+
if biggest_src_pack_id == dst_ext[ :continue_src_pack_id ]
|
926
|
+
# puts "debug1 4-1. tund recv fin1 -> all traffic received ? -> close dst after write"
|
927
|
+
set_is_closing( dst_ext[ :dst ] )
|
928
|
+
end
|
929
|
+
when FIN2
|
930
|
+
src_id = data[ 9, 8 ].unpack( 'Q>' ).first
|
931
|
+
|
932
|
+
dst_local_port = tund_info[ :dst_local_ports ][ src_id ]
|
933
|
+
return unless dst_local_port
|
934
|
+
|
935
|
+
# puts "debug1 3-2. tund recv fin2 -> del dst ext"
|
936
|
+
del_dst_ext( tund, dst_local_port )
|
937
|
+
when TUN_FIN
|
938
|
+
puts "p#{ Process.pid } #{ Time.new } recv tun fin"
|
939
|
+
set_is_closing( tund )
|
940
|
+
end
|
941
|
+
|
942
|
+
return
|
943
|
+
end
|
944
|
+
|
945
|
+
src_id = data[ 8, 8 ].unpack( 'Q>' ).first
|
946
|
+
|
947
|
+
dst_local_port = tund_info[ :dst_local_ports ][ src_id ]
|
948
|
+
return unless dst_local_port
|
949
|
+
|
950
|
+
dst_ext = tund_info[ :dst_exts ][ dst_local_port ]
|
951
|
+
return if dst_ext.nil? || dst_ext[ :dst ].closed?
|
952
|
+
return if ( pack_id <= dst_ext[ :continue_src_pack_id ] ) || dst_ext[ :pieces ].include?( pack_id )
|
953
|
+
|
954
|
+
data = data[ 16..-1 ]
|
955
|
+
# puts "debug2 got pack #{ pack_id }"
|
956
|
+
|
957
|
+
if pack_id <= CONFUSE_UNTIL
|
958
|
+
# puts "debug2 #{ data.inspect }"
|
959
|
+
data = @custom.decode( data )
|
960
|
+
# puts "debug1 decoded pack #{ pack_id }"
|
961
|
+
end
|
962
|
+
|
963
|
+
# 放进写前,跳号放碎片缓存
|
964
|
+
if pack_id - dst_ext[ :continue_src_pack_id ] == 1
|
965
|
+
while dst_ext[ :pieces ].include?( pack_id + 1 )
|
966
|
+
data << dst_ext[ :pieces ].delete( pack_id + 1 )
|
967
|
+
pack_id += 1
|
968
|
+
end
|
969
|
+
|
970
|
+
dst_ext[ :continue_src_pack_id ] = pack_id
|
971
|
+
dst_ext[ :last_continue_at ] = now
|
972
|
+
add_dst_wbuff( dst_ext[ :dst ], data )
|
973
|
+
# puts "debug2 update continue src pack #{ pack_id }"
|
974
|
+
|
975
|
+
# 接到流量,若对面已关闭,且流量正好收全,关闭dst
|
976
|
+
if dst_ext[ :is_src_closed ] && ( pack_id == dst_ext[ :biggest_src_pack_id ] )
|
977
|
+
# puts "debug1 4-2. tund recv traffic -> src closed and all traffic received ? -> close dst after write"
|
978
|
+
set_is_closing( dst_ext[ :dst ] )
|
979
|
+
return
|
980
|
+
end
|
981
|
+
else
|
982
|
+
dst_ext[ :pieces ][ pack_id ] = data
|
983
|
+
end
|
984
|
+
end
|
985
|
+
|
986
|
+
end
|
987
|
+
end
|