girl 0.83.0 → 0.87.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 28c02739bfb0608617fa46ef36d80d7ba9c84753eb3c34410eb98f05cab430f1
4
- data.tar.gz: 94a70957768e52b1e40782c0df53451e1caebcac096829648009c6977219dd8b
3
+ metadata.gz: ff8fb468e18a12b716f36ad839823c2725a590cc162f896ed43b199297262c01
4
+ data.tar.gz: 657e28910c1e4303896b7f728760bedf2ba4d23dd1ed021b325cc6545b0050ac
5
5
  SHA512:
6
- metadata.gz: d0e12984275ddf891c11b75ce86d13830798d2538b9b4b15962720ac268f61dc721d1fd355f99282f6274217879e1053d698dbcdaf59de30533fe59c53596173
7
- data.tar.gz: dc98d8959fd53fc51f8e0e2851ce46afe78a7ddedf293a595148b885a8ed2055a7e1fa92e88b22826528e0a6399ff5c16700c689bf4a766a6d7ca809567e0a1d
6
+ metadata.gz: 1c29c0ee44eacc07c1deea70df4433083c45fde0f932c540831a52c0c39e539401b79cd3249190563db3dfc4f33a8b7ac336f95420038ed612abdbe5e3d8a42d
7
+ data.tar.gz: 72c4374a80e9eb93139cff701436536e99d8843c80a866494d42aee10ff64619b82e4d19b8a0660f44bd1a3b516657221e60d72227a005f96c8410a729eb919e
@@ -10,7 +10,7 @@ Gem::Specification.new do |spec|
10
10
  spec.email = ['qqtakafan@gmail.com']
11
11
 
12
12
  spec.summary = %q{妹子}
13
- spec.description = %q{while internet is evil, here's a girl.}
13
+ spec.description = %q{escape evil.}
14
14
  spec.homepage = 'https://github.com/takafan/girl'
15
15
  spec.license = 'MIT'
16
16
 
@@ -1,32 +1,33 @@
1
1
  module Girl
2
- PACK_SIZE = 1328 # 包大小 1400(console MTU) - 8(PPPoE header) - 40(IPv6 header) - 8(UDP header) - 8(pack id) - 8(src id) = 1328
3
- CHUNK_SIZE = PACK_SIZE * 1000 # 块大小
4
- WBUFFS_LIMIT = 1000 # 写前上限,超过上限结一个块
5
- WMEMS_LIMIT = 100_000 # 写后上限,达到上限暂停写
6
- RESUME_BELOW = 50_000 # 降到多少以下恢复写
7
- EXPIRE_NEW = 10 # 创建之后多久没有流量进来,过期
8
- EXPIRE_AFTER = 300 # 多久没有新流量,过期
9
- CHECK_EXPIRE_INTERVAL = 30 # 检查过期间隔
10
- STATUS_INTERVAL = 0.5 # 发送状态间隔
11
- SEND_STATUS_UNTIL = 10 # 持续的告之对面状态,直到没有流量往来,持续多少秒
12
- BREAK_SEND_MISS = 10_000 # miss包个数上限,达到上限忽略要后面的段,可控碎片缓存
13
- CONFUSE_UNTIL = 5 # 混淆前几个包
14
- RESOLV_CACHE_EXPIRE = 300 # dns查询结果缓存多久过期
15
- TUND_PORT = 1
16
- HEARTBEAT = 2
17
- A_NEW_SOURCE = 3
18
- PAIRED = 4
19
- DEST_STATUS = 5
20
- SOURCE_STATUS = 6
21
- MISS = 7
22
- FIN1 = 8
23
- GOT_FIN1 = 9
24
- FIN2 = 10
25
- GOT_FIN2 = 11
26
- TUND_FIN = 12
27
- TUN_FIN = 13
28
- IP_CHANGED = 14
29
- HTTP_OK = "HTTP/1.1 200 OK\r\n\r\n"
2
+ PACK_SIZE = 1328 # 包大小 1400(console MTU) - 8(PPPoE header) - 40(IPv6 header) - 8(UDP header) - 8(pack id) - 8(src id) = 1328
3
+ READ_SIZE = PACK_SIZE * 100 # 一次读多少
4
+ WMEMS_LIMIT = 100_000 # 写后上限,超过上限暂停读src/dst
5
+ RESUME_BELOW = 50_000 # 降到多少以下恢复读
6
+ EXPIRE_NEW = 10 # 创建之后多久没有流量进来,过期
7
+ EXPIRE_AFTER = 300 # 多久没有新流量,过期
8
+ CHECK_EXPIRE_INTERVAL = 30 # 检查过期间隔
9
+ CHECK_STATUS_INTERVAL = 0.5 # 发送状态间隔
10
+ SEND_STATUS_UNTIL = 10 # 持续的告之对面状态,直到没有流量往来,持续多少秒
11
+ MULTI_MISS_SIZE = 80 # 几个miss段打一个包
12
+ MISS_RANGE_LIMIT = MULTI_MISS_SIZE * 10 # miss段上限,达到上限忽略要后面的段
13
+ CONFUSE_UNTIL = 5 # 混淆前几个包
14
+ RESOLV_CACHE_EXPIRE = 300 # dns查询结果缓存多久过期
15
+ TUND_PORT = 1
16
+ HEARTBEAT = 2
17
+ A_NEW_SOURCE = 3
18
+ PAIRED = 4
19
+ DEST_STATUS = 5
20
+ SOURCE_STATUS = 6
21
+ MISS = 7
22
+ FIN1 = 8
23
+ GOT_FIN1 = 9
24
+ FIN2 = 10
25
+ GOT_FIN2 = 11
26
+ TUND_FIN = 12
27
+ TUN_FIN = 13
28
+ IP_CHANGED = 14
29
+ MULTI_MISS = 15
30
+ HTTP_OK = "HTTP/1.1 200 OK\r\n\r\n"
30
31
  # https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml
31
32
  RESERVED_ROUTE = <<EOF
32
33
  0.0.0.0/8
@@ -36,6 +36,7 @@ require 'socket'
36
36
  # 12 tund fin
37
37
  # 13 tun fin
38
38
  # 14 tun ip changed
39
+ # 15 multi miss -> Q>/n: src id / dst port -> Q>: pack id begin -> Q>: pack id end -> Q>*
39
40
  #
40
41
  # Q>: 1+ pack_id -> Q>/n: src id / dst port -> traffic
41
42
  #
@@ -74,8 +75,6 @@ module Girl
74
75
  # "proxyd_port": 6060, // 代理服务,远端端口
75
76
  # "direct_path": "girl.direct.txt", // 直连ip段
76
77
  # "remote_path": "girl.remote.txt", // 交给远端解析的域名列表
77
- # "proxy_tmp_dir": "/tmp/girl.proxy", // 近端缓存根路径
78
- # "proxyd_tmp_dir": "/tmp/girl.proxyd", // 远端缓存根路径
79
78
  # "im": "girl", // 标识,用来识别近端
80
79
  # "worker_count": 4 // 子进程数,默认取cpu个数
81
80
  # }
@@ -85,7 +84,6 @@ module Girl
85
84
  proxyd_port = conf[ :proxyd_port ]
86
85
  direct_path = conf[ :direct_path ]
87
86
  remote_path = conf[ :remote_path ]
88
- proxy_tmp_dir = conf[ :proxy_tmp_dir ]
89
87
  im = conf[ :im ]
90
88
  worker_count = conf[ :worker_count ]
91
89
 
@@ -121,32 +119,6 @@ module Girl
121
119
  remotes = IO.binread( remote_path ).split( "\n" ).map { | line | line.strip }
122
120
  end
123
121
 
124
- unless proxy_tmp_dir
125
- proxy_tmp_dir = '/tmp/girl.proxy'
126
- end
127
-
128
- unless File.exist?( proxy_tmp_dir )
129
- Dir.mkdir( proxy_tmp_dir )
130
- end
131
-
132
- src_chunk_dir = File.join( proxy_tmp_dir, 'src.chunk' )
133
-
134
- unless Dir.exist?( src_chunk_dir )
135
- Dir.mkdir( src_chunk_dir )
136
- end
137
-
138
- dst_chunk_dir = File.join( proxy_tmp_dir, 'dst.chunk' )
139
-
140
- unless Dir.exist?( dst_chunk_dir )
141
- Dir.mkdir( dst_chunk_dir )
142
- end
143
-
144
- tun_chunk_dir = File.join( proxy_tmp_dir, 'tun.chunk' )
145
-
146
- unless Dir.exist?( tun_chunk_dir )
147
- Dir.mkdir( tun_chunk_dir )
148
- end
149
-
150
122
  unless im
151
123
  im = 'girl'
152
124
  end
@@ -164,12 +136,31 @@ module Girl
164
136
  puts "proxyd port #{ proxyd_port }"
165
137
  puts "#{ direct_path } #{ directs.size } directs"
166
138
  puts "#{ remote_path } #{ remotes.size } remotes"
167
- puts "src chunk dir #{ src_chunk_dir }"
168
- puts "dst chunk dir #{ dst_chunk_dir }"
169
- puts "tun chunk dir #{ tun_chunk_dir }"
170
139
  puts "im #{ im }"
171
140
  puts "worker count #{ worker_count }"
172
141
 
142
+ names = %w[
143
+ PACK_SIZE
144
+ READ_SIZE
145
+ WMEMS_LIMIT
146
+ RESUME_BELOW
147
+ EXPIRE_NEW
148
+ EXPIRE_AFTER
149
+ CHECK_EXPIRE_INTERVAL
150
+ CHECK_STATUS_INTERVAL
151
+ SEND_STATUS_UNTIL
152
+ MULTI_MISS_SIZE
153
+ MISS_RANGE_LIMIT
154
+ CONFUSE_UNTIL
155
+ RESOLV_CACHE_EXPIRE
156
+ ]
157
+
158
+ len = names.map{ | name | name.size }.max
159
+
160
+ names.each do | name |
161
+ puts "#{ name.gsub( '_', ' ' ).ljust( len ) } #{ Girl.const_get( name ) }"
162
+ end
163
+
173
164
  if RUBY_PLATFORM.include?( 'linux' )
174
165
  $0 = title
175
166
  workers = []
@@ -177,7 +168,7 @@ module Girl
177
168
  worker_count.times do | i |
178
169
  workers << fork do
179
170
  $0 = 'girl proxy worker'
180
- worker = Girl::ProxyWorker.new( proxy_port, proxyd_host, proxyd_port, directs, remotes, src_chunk_dir, dst_chunk_dir, tun_chunk_dir, im )
171
+ worker = Girl::ProxyWorker.new( proxy_port, proxyd_host, proxyd_port, directs, remotes, im )
181
172
 
182
173
  Signal.trap( :TERM ) do
183
174
  puts "w#{ i } exit"
@@ -201,7 +192,7 @@ module Girl
201
192
 
202
193
  Process.waitall
203
194
  else
204
- Girl::ProxyWorker.new( proxy_port, proxyd_host, proxyd_port, directs, remotes, src_chunk_dir, dst_chunk_dir, tun_chunk_dir, im ).looping
195
+ Girl::ProxyWorker.new( proxy_port, proxyd_host, proxyd_port, directs, remotes, im ).looping
205
196
  end
206
197
  end
207
198
 
@@ -4,18 +4,16 @@ module Girl
4
4
  ##
5
5
  # initialize
6
6
  #
7
- def initialize( proxy_port, proxyd_host, proxyd_port, directs, remotes, src_chunk_dir, dst_chunk_dir, tun_chunk_dir, im )
7
+ def initialize( proxy_port, proxyd_host, proxyd_port, directs, remotes, im )
8
8
  @proxyd_host = proxyd_host
9
9
  @proxyd_addr = Socket.sockaddr_in( proxyd_port, proxyd_host )
10
10
  @directs = directs
11
11
  @remotes = remotes
12
- @src_chunk_dir = src_chunk_dir
13
- @dst_chunk_dir = dst_chunk_dir
14
- @tun_chunk_dir = tun_chunk_dir
15
12
  @custom = Girl::ProxyCustom.new( im )
16
13
  @mutex = Mutex.new
17
14
  @reads = []
18
15
  @writes = []
16
+ @pause_srcs = []
19
17
  @roles = {} # sock => :dotr / :proxy / :src / :dst / :tun
20
18
  @src_infos = {} # src => {}
21
19
  @dst_infos = {} # dst => {}
@@ -106,20 +104,31 @@ module Girl
106
104
  if is_expired
107
105
  puts "p#{ Process.pid } #{ Time.new } expire tun"
108
106
  set_is_closing( @tun )
107
+ need_trigger = true
109
108
  else
110
109
  data = [ 0, HEARTBEAT, rand( 128 ) ].pack( 'Q>CC' )
111
110
  # puts "debug1 #{ Time.new } heartbeat"
112
- add_tun_ctlmsg( data )
113
-
114
- @tun_info[ :src_exts ].each do | src_id, src_ext |
115
- if src_ext[ :src ].closed? && ( now - src_ext[ :last_continue_at ] > EXPIRE_AFTER )
116
- puts "p#{ Process.pid } #{ Time.new } expire src ext #{ src_ext[ :destination_domain ] }"
117
- del_src_ext( src_id )
111
+ send_data( @tun, data, @tun_info[ :tund_addr ] )
112
+ del_src_ids = []
113
+
114
+ @tun_info[ :srcs ].each do | src_id, src |
115
+ if src.closed?
116
+ src_info = @src_infos[ src ]
117
+
118
+ if src_info && ( now - src_info[ :last_continue_at ] > EXPIRE_AFTER )
119
+ puts "p#{ Process.pid } #{ Time.new } expire src ext #{ src_info[ :destination_domain ] }"
120
+ @tun_info[ :wmems ].delete_if { | src_id_and_pack_id, _ | src_id_and_pack_id.first == src_id }
121
+ @tun_info[ :src_ids ].delete( src_info[ :dst_id ] )
122
+ @src_infos.delete( src )
123
+ del_src_ids << src_id
124
+ end
118
125
  end
119
126
  end
120
- end
121
127
 
122
- need_trigger = true
128
+ if del_src_ids.any?
129
+ @tun_info[ :srcs ].delete_if { | src_id, _ | del_src_ids.include?( src_id ) }
130
+ end
131
+ end
123
132
  end
124
133
 
125
134
  @src_infos.each do | src, src_info |
@@ -152,32 +161,34 @@ module Girl
152
161
  def loop_check_status
153
162
  Thread.new do
154
163
  loop do
155
- sleep STATUS_INTERVAL
164
+ sleep CHECK_STATUS_INTERVAL
156
165
 
157
166
  @mutex.synchronize do
158
167
  if @tun && !@tun.closed? && @tun_info[ :tund_addr ]
159
- need_trigger = false
160
-
161
- if @tun_info[ :src_exts ].any?
168
+ if @tun_info[ :srcs ].any?
162
169
  now = Time.new
163
170
 
164
- @tun_info[ :src_exts ].each do | src_id, src_ext |
165
- if src_ext[ :dst_port ] && ( now - src_ext[ :last_continue_at ] < SEND_STATUS_UNTIL )
166
- data = [ 0, SOURCE_STATUS, src_id, src_ext[ :relay_pack_id ], src_ext[ :continue_dst_pack_id ] ].pack( 'Q>CQ>Q>Q>' )
167
- add_tun_ctlmsg( data )
168
- need_trigger = true
171
+ @tun_info[ :srcs ].each do | src_id, src |
172
+ src_info = @src_infos[ src ]
173
+
174
+ if src_info && src_info[ :dst_id ] && ( now - src_info[ :last_continue_at ] < SEND_STATUS_UNTIL )
175
+ data = [ 0, SOURCE_STATUS, src_id, src_info[ :biggest_pack_id ], src_info[ :continue_dst_pack_id ] ].pack( 'Q>CQ>Q>Q>' )
176
+ send_data( @tun, data, @tun_info[ :tund_addr ] )
169
177
  end
170
178
  end
171
179
  end
172
180
 
173
- if @tun_info[ :paused ] && ( @tun_info[ :src_exts ].map{ | _, src_ext | src_ext[ :wmems ].size }.sum < RESUME_BELOW )
174
- puts "p#{ Process.pid } #{ Time.new } resume tun"
175
- @tun_info[ :paused ] = false
176
- add_write( @tun )
177
- need_trigger = true
178
- end
181
+ if @pause_srcs.any? && ( @tun_info[ :wmems ].size < RESUME_BELOW )
182
+ @pause_srcs.each do | src |
183
+ src_info = @src_infos[ src ]
184
+
185
+ if src_info
186
+ puts "p#{ Process.pid } #{ Time.new } resume src #{ src_info[ :destination_domain ] }"
187
+ add_read( src )
188
+ end
189
+ end
179
190
 
180
- if need_trigger
191
+ @pause_srcs.clear
181
192
  next_tick
182
193
  end
183
194
  end
@@ -187,23 +198,60 @@ module Girl
187
198
  end
188
199
 
189
200
  ##
190
- # loop send a new source
201
+ # loop send hello
191
202
  #
192
- def loop_send_a_new_source( src_ext, data )
203
+ def loop_send_hello
204
+ data = @custom.hello
205
+
193
206
  Thread.new do
194
- EXPIRE_NEW.times do
195
- if src_ext[ :src ].closed? || src_ext[ :dst_port ]
196
- # puts "debug1 break loop send a new source #{ src_ext[ :dst_port ] }"
207
+ EXPIRE_NEW.times do | i |
208
+ if @tun.closed? || @tun_info[ :tund_addr ]
209
+ # puts "debug1 break loop send hello"
197
210
  break
198
211
  end
199
212
 
200
213
  @mutex.synchronize do
201
- # puts "debug1 send a new source #{ data.inspect }"
202
- add_tun_ctlmsg( data )
203
- next_tick
214
+ msg = i >= 1 ? "resend hello #{ i }" : "hello i'm tun"
215
+ puts "p#{ Process.pid } #{ Time.new } #{ msg }"
216
+ # puts "debug1 #{ data.inspect }"
217
+
218
+ send_data( @tun, data, @proxyd_addr )
204
219
  end
205
220
 
206
- sleep 1
221
+ sleep CHECK_STATUS_INTERVAL
222
+ end
223
+ end
224
+ end
225
+
226
+ ##
227
+ # loop send a new source
228
+ #
229
+ def loop_send_a_new_source( src )
230
+ src_info = @src_infos[ src ]
231
+
232
+ if src_info && @tun_info[ :tund_addr ]
233
+ destination_domain = src_info[ :destination_domain ]
234
+ destination_port = src_info[ :destination_port ]
235
+ domain_port = [ destination_domain, destination_port ].join( ':' )
236
+ data = [ [ 0, A_NEW_SOURCE, src_info[ :id ] ].pack( 'Q>CQ>' ), @custom.encode( domain_port ) ].join
237
+
238
+ Thread.new do
239
+ EXPIRE_NEW.times do | i |
240
+ if src.closed? || src_info[ :dst_id ]
241
+ # puts "debug1 break loop send a new source #{ src_info[ :dst_port ] }"
242
+ break
243
+ end
244
+
245
+ @mutex.synchronize do
246
+ if i >= 1
247
+ puts "p#{ Process.pid } #{ Time.new } resend a new source #{ domain_port } #{ i }"
248
+ end
249
+
250
+ send_data( @tun, data, @tun_info[ :tund_addr ] )
251
+ end
252
+
253
+ sleep CHECK_STATUS_INTERVAL
254
+ end
207
255
  end
208
256
  end
209
257
  end
@@ -304,17 +352,12 @@ module Girl
304
352
  port = tun.local_address.ip_port
305
353
  tun_info = {
306
354
  port: port, # 端口
307
- ctlmsg_rbuffs: [], # 还没配上tund,暂存的ctlmsg
308
- ctlmsgs: [], # [ to_addr, data ]
309
- wbuffs: [], # 写前缓存 [ src_id, pack_id, data ]
310
- caches: [], # 块读出缓存 [ src_id, pack_id, data ]
311
- chunks: [], # 块队列 filename
312
- spring: 0, # 块后缀,结块时,如果块队列不为空,则自增,为空,则置为0
355
+ pending_sources: [], # 还没配上tund,暂存的src
356
+ wbuffs: [], # 写前 [ src_id, pack_id, data ]
357
+ wmems: {}, # 写后 [ src_id, pack_id ] => data
313
358
  tund_addr: nil, # tund地址
314
- src_exts: {}, # src额外信息 src_id => {}
315
- src_ids: {}, # dst_port => src_id
316
- paused: false, # 是否暂停写
317
- resendings: [], # 重传队列 [ src_id, pack_id ]
359
+ srcs: {}, # src_id => src
360
+ src_ids: {}, # dst_id => src_id
318
361
  created_at: Time.new, # 创建时间
319
362
  last_recv_at: nil, # 上一次收到流量的时间,过期关闭
320
363
  is_closing: false # 是否准备关闭
@@ -324,10 +367,7 @@ module Girl
324
367
  @tun_info = tun_info
325
368
 
326
369
  add_read( tun, :tun )
327
- data = @custom.hello
328
- puts "p#{ Process.pid } #{ Time.new } hello i'm tun"
329
- # puts "debug1 #{ data.inspect }"
330
- add_tun_ctlmsg( data, @proxyd_addr )
370
+ loop_send_hello
331
371
  end
332
372
 
333
373
  ##
@@ -360,9 +400,6 @@ module Girl
360
400
  src: src, # 对应src
361
401
  domain: domain, # 域名
362
402
  wbuff: '', # 写前
363
- cache: '', # 块读出缓存
364
- chunks: [], # 块队列,写前达到块大小时结一个块 filename
365
- spring: 0, # 块后缀,结块时,如果块队列不为空,则自增,为空,则置为0
366
403
  last_continue_at: Time.new, # 上一次发生流量的时间
367
404
  is_closing: false # 是否准备关闭
368
405
  }
@@ -376,11 +413,8 @@ module Girl
376
413
  # puts "debug1 add src wbuff http ok"
377
414
  add_src_wbuff( src, HTTP_OK )
378
415
  else
379
- # puts "debug1 add src rbuffs to dst wbuff"
380
-
381
- src_info[ :rbuffs ].each do | _, data |
382
- add_dst_wbuff( dst, data )
383
- end
416
+ # puts "debug1 add src rbuff to dst wbuff"
417
+ add_dst_wbuff( dst, src_info[ :rbuff ] )
384
418
  end
385
419
  elsif src_info[ :proxy_proto ] == :socks5
386
420
  add_src_wbuff_socks5_conn_reply( src )
@@ -396,31 +430,15 @@ module Girl
396
430
  end
397
431
 
398
432
  src_info = @src_infos[ src ]
399
- src_id = src_info[ :id ]
400
- destination_port = src_info[ :destination_port ]
401
- destination_domain = src_info[ :destination_domain ]
402
-
403
- src_ext = {
404
- src: src, # src
405
- dst_port: nil, # 远端dst端口
406
- destination_domain: destination_domain, # 目的地域名
407
- wmems: {}, # 写后 pack_id => data
408
- send_ats: {}, # 上一次发出时间 pack_id => send_at
409
- relay_pack_id: 0, # 转发到几
410
- continue_dst_pack_id: 0, # 收到几
411
- pieces: {}, # 跳号包 dst_pack_id => data
412
- is_dst_closed: false, # dst是否已关闭
413
- biggest_dst_pack_id: 0, # dst最大包号码
414
- completed_pack_id: 0, # 完成到几(对面收到几)
415
- last_continue_at: Time.new # 上一次发生流量的时间
416
- }
417
-
418
- @tun_info[ :src_exts ][ src_id ] = src_ext
419
433
  src_info[ :proxy_type ] = :tunnel
434
+ src_id = src_info[ :id ]
435
+ @tun_info[ :srcs ][ src_id ] = src
420
436
 
421
- destination_domain_port = [ destination_domain, destination_port ].join( ':' )
422
- data = [ [ 0, A_NEW_SOURCE, src_id ].pack( 'Q>CQ>' ), @custom.encode( destination_domain_port ) ].join
423
- loop_send_a_new_source( src_ext, data )
437
+ if @tun_info[ :tund_addr ]
438
+ loop_send_a_new_source( src )
439
+ else
440
+ @tun_info[ :pending_sources ] << src
441
+ end
424
442
  end
425
443
 
426
444
  ##
@@ -459,75 +477,12 @@ module Girl
459
477
  [ data, domain_and_port ]
460
478
  end
461
479
 
462
- ##
463
- # add tun ctlmsg
464
- #
465
- def add_tun_ctlmsg( data, to_addr = nil )
466
- unless to_addr
467
- to_addr = @tun_info[ :tund_addr ]
468
- end
469
-
470
- if to_addr
471
- @tun_info[ :ctlmsgs ] << [ to_addr, data ]
472
- add_write( @tun )
473
- else
474
- @tun_info[ :ctlmsg_rbuffs ] << data
475
- end
476
- end
477
-
478
- ##
479
- # add tun wbuff
480
- #
481
- def add_tun_wbuff( src_id, pack_id, data )
482
- @tun_info[ :wbuffs ] << [ src_id, pack_id, data ]
483
-
484
- if @tun_info[ :wbuffs ].size >= WBUFFS_LIMIT
485
- spring = @tun_info[ :chunks ].size > 0 ? ( @tun_info[ :spring ] + 1 ) : 0
486
- filename = "#{ Process.pid }-#{ @tun_info[ :port ] }.#{ spring }"
487
- chunk_path = File.join( @tun_chunk_dir, filename )
488
- datas = @tun_info[ :wbuffs ].map{ | _src_id, _pack_id, _data | [ [ _src_id, _pack_id, _data.bytesize ].pack( 'Q>Q>n' ), _data ].join }
489
-
490
- begin
491
- IO.binwrite( chunk_path, datas.join )
492
- rescue Errno::ENOSPC => e
493
- puts "p#{ Process.pid } #{ Time.new } #{ e.class }, close tun"
494
- set_is_closing( @tun )
495
- return
496
- end
497
-
498
- @tun_info[ :chunks ] << filename
499
- @tun_info[ :spring ] = spring
500
- @tun_info[ :wbuffs ].clear
501
- end
502
-
503
- add_write( @tun )
504
- end
505
-
506
480
  ##
507
481
  # add src wbuff
508
482
  #
509
483
  def add_src_wbuff( src, data )
510
484
  src_info = @src_infos[ src ]
511
485
  src_info[ :wbuff ] << data
512
-
513
- if src_info[ :wbuff ].bytesize >= CHUNK_SIZE
514
- spring = src_info[ :chunks ].size > 0 ? ( src_info[ :spring ] + 1 ) : 0
515
- filename = "#{ Process.pid }-#{ src_info[ :id ] }.#{ spring }"
516
- chunk_path = File.join( @src_chunk_dir, filename )
517
-
518
- begin
519
- IO.binwrite( chunk_path, src_info[ :wbuff ] )
520
- rescue Errno::ENOSPC => e
521
- puts "p#{ Process.pid } #{ Time.new } #{ e.class }, close src"
522
- set_is_closing( src )
523
- return
524
- end
525
-
526
- src_info[ :chunks ] << filename
527
- src_info[ :spring ] = spring
528
- src_info[ :wbuff ].clear
529
- end
530
-
531
486
  add_write( src )
532
487
  end
533
488
 
@@ -537,37 +492,20 @@ module Girl
537
492
  def add_dst_wbuff( dst, data )
538
493
  dst_info = @dst_infos[ dst ]
539
494
  dst_info[ :wbuff ] << data
540
-
541
- if dst_info[ :wbuff ].bytesize >= CHUNK_SIZE
542
- spring = dst_info[ :chunks ].size > 0 ? ( dst_info[ :spring ] + 1 ) : 0
543
- filename = "#{ Process.pid }-#{ dst_info[ :local_port ] }.#{ spring }"
544
- chunk_path = File.join( @dst_chunk_dir, filename )
545
-
546
- begin
547
- IO.binwrite( chunk_path, dst_info[ :wbuff ] )
548
- rescue Errno::ENOSPC => e
549
- puts "p#{ Process.pid } #{ Time.new } #{ e.class }, close dst"
550
- set_is_closing( dst )
551
- return
552
- end
553
-
554
- dst_info[ :chunks ] << filename
555
- dst_info[ :spring ] = spring
556
- dst_info[ :wbuff ].clear
557
- end
558
-
559
495
  add_write( dst )
560
496
  end
561
497
 
562
498
  ##
563
499
  # add read
564
500
  #
565
- def add_read( sock, role )
566
- unless @reads.include?( sock )
501
+ def add_read( sock, role = nil )
502
+ if sock && !sock.closed? && !@reads.include?( sock )
567
503
  @reads << sock
568
- end
569
504
 
570
- @roles[ sock ] = role
505
+ if role
506
+ @roles[ sock ] = role
507
+ end
508
+ end
571
509
  end
572
510
 
573
511
  ##
@@ -579,6 +517,17 @@ module Girl
579
517
  end
580
518
  end
581
519
 
520
+ ##
521
+ # add pause src
522
+ #
523
+ def add_pause_src( src )
524
+ @reads.delete( src )
525
+
526
+ unless @pause_srcs.include?( src )
527
+ @pause_srcs << src
528
+ end
529
+ end
530
+
582
531
  ##
583
532
  # set is closing
584
533
  #
@@ -603,10 +552,52 @@ module Girl
603
552
  end
604
553
  end
605
554
 
555
+ ##
556
+ # tunnel data
557
+ #
558
+ def tunnel_data( src, data )
559
+ src_info = @src_infos[ src ]
560
+ src_id = src_info[ :id ]
561
+ now = Time.new
562
+ pack_id = src_info[ :biggest_pack_id ]
563
+ idx = 0
564
+ len = data.bytesize
565
+
566
+ while idx < len
567
+ chunk = data[ idx, PACK_SIZE ]
568
+ pack_id += 1
569
+
570
+ if pack_id <= CONFUSE_UNTIL
571
+ chunk = @custom.encode( chunk )
572
+ # puts "debug1 encoded chunk #{ pack_id }"
573
+ end
574
+
575
+ data2 = [ [ pack_id, src_id ].pack( 'Q>Q>' ), chunk ].join
576
+ sent = send_data( @tun, data2, @tun_info[ :tund_addr ] )
577
+ # puts "debug2 written pack #{ pack_id } #{ sent }"
578
+ @tun_info[ :wmems ][ [ src_id, pack_id ] ] = data2
579
+ src_info[ :send_ats ][ pack_id ] = now
580
+ idx += PACK_SIZE
581
+ end
582
+
583
+ src_info[ :biggest_pack_id ] = pack_id
584
+ src_info[ :last_continue_at ] = now
585
+
586
+ # 写后超过上限,暂停读src
587
+ if @tun_info[ :wmems ].size >= WMEMS_LIMIT
588
+ puts "p#{ Process.pid } #{ Time.new } pause src #{ src_id } #{ src_info[ :destination_domain ] } #{ src_info[ :biggest_pack_id ] }"
589
+ add_pause_src( src )
590
+ end
591
+ end
592
+
606
593
  ##
607
594
  # send data
608
595
  #
609
596
  def send_data( tun, data, to_addr )
597
+ unless to_addr
598
+ return false
599
+ end
600
+
610
601
  begin
611
602
  tun.sendmsg( data, 0, to_addr )
612
603
  rescue IO::WaitWritable, Errno::EINTR
@@ -626,36 +617,36 @@ module Girl
626
617
  def close_src( src )
627
618
  # puts "debug1 close src"
628
619
  close_sock( src )
629
- src_info = @src_infos.delete( src )
620
+ @pause_srcs.delete( src )
621
+ src_info = @src_infos[ src ]
630
622
 
631
- src_info[ :chunks ].each do | filename |
632
- begin
633
- File.delete( File.join( @src_chunk_dir, filename ) )
634
- rescue Errno::ENOENT
623
+ if src_info[ :proxy_type ] == :direct
624
+ @src_infos.delete( src )
625
+
626
+ if src_info[ :dst ]
627
+ set_is_closing( src_info[ :dst ] )
635
628
  end
636
- end
637
629
 
638
- src_id = src_info[ :id ]
630
+ return
631
+ end
639
632
 
640
- if src_info[ :proxy_type ] == :tunnel
641
- return if @tun.closed?
633
+ if @tun.closed? || src_info[ :dst_id ].nil?
634
+ @src_infos.delete( src )
635
+ return
636
+ end
642
637
 
643
- src_ext = @tun_info[ :src_exts ][ src_id ]
644
- return if src_ext.nil? || src_ext[ :dst_port ].nil?
638
+ src_id = src_info[ :id ]
645
639
 
646
- if src_ext[ :is_dst_closed ]
647
- # puts "debug1 2-3. after close src -> dst closed ? yes -> del src ext -> send fin2"
648
- del_src_ext( src_id )
649
- data = [ 0, FIN2, src_id ].pack( 'Q>CQ>' )
650
- add_tun_ctlmsg( data )
651
- else
652
- # puts "debug1 1-1. after close src -> dst closed ? no -> send fin1"
653
- data = [ 0, FIN1, src_id, src_info[ :biggest_pack_id ], src_ext[ :continue_dst_pack_id ] ].pack( 'Q>CQ>Q>Q>' )
654
- add_tun_ctlmsg( data )
655
- end
656
- elsif src_info[ :proxy_type ] == :direct
657
- set_is_closing( src_info[ :dst ] )
640
+ if src_info[ :is_dst_closed ]
641
+ # puts "debug1 2-3. after close src -> dst closed ? yes -> del src ext -> send fin2"
642
+ del_src_ext( src_id )
643
+ data = [ 0, FIN2, src_id ].pack( 'Q>CQ>' )
644
+ else
645
+ # puts "debug1 1-1. after close src -> dst closed ? no -> send fin1"
646
+ data = [ 0, FIN1, src_id, src_info[ :biggest_pack_id ], src_info[ :continue_dst_pack_id ] ].pack( 'Q>CQ>Q>Q>' )
658
647
  end
648
+
649
+ send_data( @tun, data, @tun_info[ :tund_addr ] )
659
650
  end
660
651
 
661
652
  ##
@@ -665,14 +656,6 @@ module Girl
665
656
  # puts "debug1 close dst"
666
657
  close_sock( dst )
667
658
  dst_info = @dst_infos.delete( dst )
668
-
669
- dst_info[ :chunks ].each do | filename |
670
- begin
671
- File.delete( File.join( @dst_chunk_dir, filename ) )
672
- rescue Errno::ENOENT
673
- end
674
- end
675
-
676
659
  set_is_closing( dst_info[ :src ] )
677
660
  end
678
661
 
@@ -682,15 +665,7 @@ module Girl
682
665
  def close_tun( tun )
683
666
  # puts "debug1 close tun"
684
667
  close_sock( tun )
685
-
686
- @tun_info[ :chunks ].each do | filename |
687
- begin
688
- File.delete( File.join( @tun_chunk_dir, filename ) )
689
- rescue Errno::ENOENT
690
- end
691
- end
692
-
693
- @tun_info[ :src_exts ].each{ | _, src_ext | set_is_closing( src_ext[ :src ] ) }
668
+ @tun_info[ :srcs ].each{ | _, src | set_is_closing( src ) }
694
669
  end
695
670
 
696
671
  ##
@@ -707,27 +682,32 @@ module Girl
707
682
  # del src ext
708
683
  #
709
684
  def del_src_ext( src_id )
710
- src_ext = @tun_info[ :src_exts ].delete( src_id )
685
+ @tun_info[ :wmems ].delete_if { | src_id_and_pack_id, _ | src_id_and_pack_id.first == src_id }
686
+ src = @tun_info[ :srcs ].delete( src_id )
687
+
688
+ if src
689
+ src_info = @src_infos.delete( src )
711
690
 
712
- if src_ext
713
- @tun_info[ :src_ids ].delete( src_ext[ :dst_port ] )
691
+ if src_info
692
+ @tun_info[ :src_ids ].delete( src_info[ :dst_id ] )
693
+ end
714
694
  end
715
695
  end
716
696
 
717
697
  ##
718
698
  # release wmems
719
699
  #
720
- def release_wmems( src_ext, completed_pack_id )
721
- if completed_pack_id > src_ext[ :completed_pack_id ]
700
+ def release_wmems( src_info, completed_pack_id )
701
+ if completed_pack_id > src_info[ :completed_pack_id ]
722
702
  # puts "debug2 update completed pack #{ completed_pack_id }"
723
- pack_ids = src_ext[ :wmems ].keys.select { | pack_id | pack_id <= completed_pack_id }
703
+ pack_ids = src_info[ :send_ats ].keys.select { | pack_id | pack_id <= completed_pack_id }
724
704
 
725
705
  pack_ids.each do | pack_id |
726
- src_ext[ :wmems ].delete( pack_id )
727
- src_ext[ :send_ats ].delete( pack_id )
706
+ @tun_info[ :wmems ].delete( [ src_info[ :id ], pack_id ] )
707
+ src_info[ :send_ats ].delete( pack_id )
728
708
  end
729
709
 
730
- src_ext[ :completed_pack_id ] = completed_pack_id
710
+ src_info[ :completed_pack_id ] = completed_pack_id
731
711
  end
732
712
  end
733
713
 
@@ -743,32 +723,16 @@ module Girl
743
723
  #
744
724
  def write_src( src )
745
725
  src_info = @src_infos[ src ]
746
- from, data = :cache, src_info[ :cache ]
747
726
 
748
- if data.empty?
749
- if src_info[ :chunks ].any?
750
- path = File.join( @src_chunk_dir, src_info[ :chunks ].shift )
751
-
752
- begin
753
- data = src_info[ :cache ] = IO.binread( path )
754
- File.delete( path )
755
- rescue Errno::ENOENT => e
756
- puts "p#{ Process.pid } #{ Time.new } read #{ path } #{ e.class }"
757
- close_src( src )
758
- return
759
- end
760
- else
761
- from, data = :wbuff, src_info[ :wbuff ]
762
- end
727
+ if src_info[ :is_closing ]
728
+ close_src( src )
729
+ return
763
730
  end
764
731
 
765
- if data.empty?
766
- if src_info[ :is_closing ]
767
- close_src( src )
768
- else
769
- @writes.delete( src )
770
- end
732
+ data = src_info[ :wbuff ]
771
733
 
734
+ if data.empty?
735
+ @writes.delete( src )
772
736
  return
773
737
  end
774
738
 
@@ -783,7 +747,7 @@ module Girl
783
747
 
784
748
  # puts "debug2 write src #{ written }"
785
749
  data = data[ written..-1 ]
786
- src_info[ from ] = data
750
+ src_info[ :wbuff ] = data
787
751
  src_info[ :last_continue_at ] = Time.new
788
752
  end
789
753
 
@@ -792,32 +756,16 @@ module Girl
792
756
  #
793
757
  def write_dst( dst )
794
758
  dst_info = @dst_infos[ dst ]
795
- from, data = :cache, dst_info[ :cache ]
796
759
 
797
- if data.empty?
798
- if dst_info[ :chunks ].any?
799
- path = File.join( @dst_chunk_dir, dst_info[ :chunks ].shift )
800
-
801
- begin
802
- data = dst_info[ :cache ] = IO.binread( path )
803
- File.delete( path )
804
- rescue Errno::ENOENT => e
805
- puts "p#{ Process.pid } #{ Time.new } read #{ path } #{ e.class }"
806
- close_dst( dst )
807
- return
808
- end
809
- else
810
- from, data = :wbuff, dst_info[ :wbuff ]
811
- end
760
+ if dst_info[ :is_closing ]
761
+ close_dst( dst )
762
+ return
812
763
  end
813
764
 
814
- if data.empty?
815
- if dst_info[ :is_closing ]
816
- close_dst( dst )
817
- else
818
- @writes.delete( dst )
819
- end
765
+ data = dst_info[ :wbuff ]
820
766
 
767
+ if data.empty?
768
+ @writes.delete( dst )
821
769
  return
822
770
  end
823
771
 
@@ -833,7 +781,7 @@ module Girl
833
781
 
834
782
  # puts "debug2 write dst #{ written }"
835
783
  data = data[ written..-1 ]
836
- dst_info[ from ] = data
784
+ dst_info[ :wbuff ] = data
837
785
  dst_info[ :last_continue_at ] = Time.new
838
786
  end
839
787
 
@@ -846,106 +794,7 @@ module Girl
846
794
  return
847
795
  end
848
796
 
849
- now = Time.new
850
-
851
- # 传ctlmsg
852
- while @tun_info[ :ctlmsgs ].any?
853
- to_addr, data = @tun_info[ :ctlmsgs ].first
854
-
855
- unless send_data( tun, data, to_addr )
856
- return
857
- end
858
-
859
- @tun_info[ :ctlmsgs ].shift
860
- end
861
-
862
- # 重传
863
- while @tun_info[ :resendings ].any?
864
- src_id, pack_id = @tun_info[ :resendings ].first
865
- src_ext = @tun_info[ :src_exts ][ src_id ]
866
-
867
- if src_ext
868
- data = src_ext[ :wmems ][ pack_id ]
869
-
870
- if data
871
- unless send_data( tun, data, @tun_info[ :tund_addr ] )
872
- return
873
- end
874
-
875
- src_ext[ :last_continue_at ] = now
876
- end
877
- end
878
-
879
- @tun_info[ :resendings ].shift
880
- end
881
-
882
- # 若写后达到上限,暂停取写前
883
- if @tun_info[ :src_exts ].map{ | _, src_ext | src_ext[ :wmems ].size }.sum >= WMEMS_LIMIT
884
- unless @tun_info[ :paused ]
885
- puts "p#{ Process.pid } #{ Time.new } pause tun"
886
- @tun_info[ :paused ] = true
887
- end
888
-
889
- @writes.delete( tun )
890
- return
891
- end
892
-
893
- # 取写前
894
- if @tun_info[ :caches ].any?
895
- datas = @tun_info[ :caches ]
896
- elsif @tun_info[ :chunks ].any?
897
- path = File.join( @tun_chunk_dir, @tun_info[ :chunks ].shift )
898
-
899
- begin
900
- data = IO.binread( path )
901
- File.delete( path )
902
- rescue Errno::ENOENT => e
903
- puts "p#{ Process.pid } #{ Time.new } read #{ path } #{ e.class }"
904
- close_tun( tun )
905
- return
906
- end
907
-
908
- caches = []
909
-
910
- until data.empty?
911
- _src_id, _pack_id, pack_size = data[ 0, 18 ].unpack( 'Q>Q>n' )
912
- caches << [ _src_id, _pack_id, data[ 18, pack_size ] ]
913
- data = data[ ( 18 + pack_size )..-1 ]
914
- end
915
-
916
- datas = @tun_info[ :caches ] = caches
917
- elsif @tun_info[ :wbuffs ].any?
918
- datas = @tun_info[ :wbuffs ]
919
- else
920
- @writes.delete( tun )
921
- return
922
- end
923
-
924
- while datas.any?
925
- src_id, pack_id, data = datas.first
926
- src_ext = @tun_info[ :src_exts ][ src_id ]
927
-
928
- if src_ext
929
- if pack_id <= CONFUSE_UNTIL
930
- data = @custom.encode( data )
931
- # puts "debug1 encoded pack #{ pack_id }"
932
- end
933
-
934
- data = [ [ pack_id, src_id ].pack( 'Q>Q>' ), data ].join
935
-
936
- unless send_data( tun, data, @tun_info[ :tund_addr ] )
937
- return
938
- end
939
-
940
- # puts "debug2 written pack #{ pack_id }"
941
- src_ext[ :relay_pack_id ] = pack_id
942
- src_ext[ :wmems ][ pack_id ] = data
943
- src_ext[ :send_ats ][ pack_id ] = now
944
- src_ext[ :last_continue_at ] = now
945
- end
946
-
947
- datas.shift
948
- end
797
+ @writes.delete( tun )
949
798
  end
950
799
 
951
800
  ##
@@ -965,11 +814,11 @@ module Girl
965
814
  return
966
815
  end
967
816
 
968
- id = rand( ( 2 ** 64 ) - 2 ) + 1
969
- # puts "debug1 accept a src #{ addrinfo.inspect } #{ id }"
817
+ src_id = rand( ( 2 ** 64 ) - 2 ) + 1
818
+ # puts "debug1 accept a src #{ addrinfo.inspect } #{ src_id }"
970
819
 
971
820
  @src_infos[ src ] = {
972
- id: id, # id
821
+ id: src_id, # id
973
822
  proxy_proto: :uncheck, # :uncheck / :http / :socks5
974
823
  proxy_type: :uncheck, # :uncheck / :checking / :direct / :tunnel / :negotiation
975
824
  dst: nil, # :direct的场合,对应的dst
@@ -977,11 +826,15 @@ module Girl
977
826
  destination_port: nil, # 目的地端口
978
827
  biggest_pack_id: 0, # 最大包号码
979
828
  is_connect: true, # 代理协议是http的场合,是否是CONNECT
980
- rbuffs: [], # 非CONNECT,dst或者远端dst未准备好,暂存流量 [ pack_id, data ]
829
+ rbuff: '', # 非CONNECT,dst或者远端dst未准备好,暂存流量
981
830
  wbuff: '', # 写前
982
- cache: '', # 块读出缓存
983
- chunks: [], # 块队列,写前达到块大小时结一个块 filename
984
- spring: 0, # 块后缀,结块时,如果块队列不为空,则自增,为空,则置为0
831
+ dst_id: nil, # 远端dst id
832
+ send_ats: {}, # 上一次发出时间 pack_id => send_at
833
+ continue_dst_pack_id: 0, # 收到几
834
+ pieces: {}, # 跳号包 dst_pack_id => data
835
+ is_dst_closed: false, # dst是否已关闭
836
+ biggest_dst_pack_id: 0, # dst最大包号码
837
+ completed_pack_id: 0, # 完成到几(对面收到几)
985
838
  last_continue_at: Time.new, # 上一次发生流量的时间
986
839
  is_closing: false # 是否准备关闭
987
840
  }
@@ -994,7 +847,7 @@ module Girl
994
847
  #
995
848
  def read_src( src )
996
849
  begin
997
- data = src.read_nonblock( PACK_SIZE )
850
+ data = src.read_nonblock( READ_SIZE )
998
851
  rescue IO::WaitReadable, Errno::EINTR
999
852
  return
1000
853
  rescue Exception => e
@@ -1074,9 +927,7 @@ module Girl
1074
927
  end
1075
928
 
1076
929
  src_info[ :is_connect ] = false
1077
- pack_id = src_info[ :biggest_pack_id ] + 1
1078
- src_info[ :biggest_pack_id ] = pack_id
1079
- src_info[ :rbuffs ] << [ pack_id, data ]
930
+ src_info[ :rbuff ] << data
1080
931
  end
1081
932
 
1082
933
  domain, port = domain_and_port.split( ':' )
@@ -1089,9 +940,7 @@ module Girl
1089
940
  resolve_domain( src, domain )
1090
941
  when :checking
1091
942
  # puts "debug1 add src rbuff while checking #{ data.inspect }"
1092
- pack_id = src_info[ :biggest_pack_id ] + 1
1093
- src_info[ :biggest_pack_id ] = pack_id
1094
- src_info[ :rbuffs ] << [ pack_id, data ]
943
+ src_info[ :rbuff ] << data
1095
944
  when :negotiation
1096
945
  # +----+-----+-------+------+----------+----------+
1097
946
  # |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT |
@@ -1129,19 +978,7 @@ module Girl
1129
978
  puts "p#{ Process.pid } #{ Time.new } socks5 cmd #{ cmd } not implement"
1130
979
  end
1131
980
  when :tunnel
1132
- src_id = src_info[ :id ]
1133
- src_ext = @tun_info[ :src_exts ][ src_id ]
1134
-
1135
- unless src_ext
1136
- # puts "debug1 not found src ext"
1137
- set_is_closing( src )
1138
- return
1139
- end
1140
-
1141
- pack_id = src_info[ :biggest_pack_id ] + 1
1142
- src_info[ :biggest_pack_id ] = pack_id
1143
-
1144
- if src_ext[ :dst_port ]
981
+ if src_info[ :dst_id ]
1145
982
  if @tun.closed?
1146
983
  # puts "debug1 tun closed, close src"
1147
984
  set_is_closing( src )
@@ -1152,10 +989,10 @@ module Girl
1152
989
  data, _ = sub_http_request( data )
1153
990
  end
1154
991
 
1155
- add_tun_wbuff( src_id, pack_id, data )
992
+ tunnel_data( src, data )
1156
993
  else
1157
994
  # puts "debug1 remote dst not ready, save data to src rbuff"
1158
- src_info[ :rbuffs ] << [ pack_id, data ]
995
+ src_info[ :rbuff ] << data
1159
996
  end
1160
997
  when :direct
1161
998
  dst = src_info[ :dst ]
@@ -1174,7 +1011,7 @@ module Girl
1174
1011
  add_dst_wbuff( dst, data )
1175
1012
  else
1176
1013
  # puts "debug1 dst not ready, save data to src rbuff"
1177
- src_info[ :rbuffs ] << [ nil, data ]
1014
+ src_info[ :rbuff ] << data
1178
1015
  end
1179
1016
  end
1180
1017
  end
@@ -1184,7 +1021,7 @@ module Girl
1184
1021
  #
1185
1022
  def read_dst( dst )
1186
1023
  begin
1187
- data = dst.read_nonblock( PACK_SIZE )
1024
+ data = dst.read_nonblock( READ_SIZE )
1188
1025
  rescue IO::WaitReadable, Errno::EINTR
1189
1026
  return
1190
1027
  rescue Exception => e
@@ -1226,143 +1063,194 @@ module Girl
1226
1063
 
1227
1064
  tund_port = data[ 9, 2 ].unpack( 'n' ).first
1228
1065
 
1229
- # puts "debug1 got tund port #{ tund_port }"
1066
+ puts "p#{ Process.pid } #{ Time.new } got tund port #{ tund_port }"
1230
1067
  tund_addr = Socket.sockaddr_in( tund_port, @proxyd_host )
1231
1068
  @tun_info[ :tund_addr ] = tund_addr
1232
1069
 
1233
- if @tun_info[ :ctlmsg_rbuffs ].any?
1234
- # puts "debug1 move #{ @tun_info[ :ctlmsg_rbuffs ].size } ctlmsg rbuffs to ctlmsgs"
1235
- @tun_info[ :ctlmsgs ] += @tun_info[ :ctlmsg_rbuffs ].map{ | _data | [ tund_addr, _data ] }
1236
- @tun_info[ :ctlmsg_rbuffs ].clear
1237
- add_write( tun )
1070
+ if @tun_info[ :pending_sources ].any?
1071
+ puts "p#{ Process.pid } #{ Time.new } send pending sources"
1072
+
1073
+ @tun_info[ :pending_sources ].each do | src |
1074
+ loop_send_a_new_source( src )
1075
+ end
1076
+
1077
+ @tun_info[ :pending_sources ].clear
1238
1078
  end
1239
1079
  when PAIRED
1240
1080
  return if from_addr != @tun_info[ :tund_addr ]
1241
1081
 
1242
- src_id, dst_port = data[ 9, 10 ].unpack( 'Q>n' )
1082
+ src_id, dst_id = data[ 9, 10 ].unpack( 'Q>n' )
1243
1083
 
1244
- src_ext = @tun_info[ :src_exts ][ src_id ]
1245
- return if src_ext.nil? || src_ext[ :dst_port ]
1246
-
1247
- src = src_ext[ :src ]
1084
+ src = @tun_info[ :srcs ][ src_id ]
1248
1085
  return if src.closed?
1249
1086
 
1250
- # puts "debug1 got paired #{ src_id } #{ dst_port }"
1087
+ src_info = @src_infos[ src ]
1088
+ return if src_info[ :dst_id ]
1251
1089
 
1252
- if dst_port == 0
1090
+ # puts "debug1 got paired #{ src_id } #{ dst_id }"
1091
+
1092
+ if dst_id == 0
1253
1093
  set_is_closing( src )
1254
1094
  return
1255
1095
  end
1256
1096
 
1257
- src_ext[ :dst_port ] = dst_port
1258
- @tun_info[ :src_ids ][ dst_port ] = src_id
1259
-
1260
- src_info = @src_infos[ src ]
1097
+ src_info[ :dst_id ] = dst_id
1098
+ @tun_info[ :src_ids ][ dst_id ] = src_id
1261
1099
 
1262
1100
  if src_info[ :proxy_proto ] == :http
1263
1101
  if src_info[ :is_connect ]
1264
1102
  # puts "debug1 add src wbuff http ok"
1265
1103
  add_src_wbuff( src, HTTP_OK )
1266
1104
  else
1267
- # puts "debug1 add src rbuffs to tun wbuffs"
1268
-
1269
- src_info[ :rbuffs ].each do | pack_id, _data |
1270
- add_tun_wbuff( src_id, pack_id, _data )
1271
- end
1105
+ # puts "debug1 send src rbuff to tund"
1106
+ tunnel_data( src, src_info[ :rbuff ] )
1272
1107
  end
1273
1108
  elsif src_info[ :proxy_proto ] == :socks5
1274
- add_src_wbuff_socks5_conn_reply( src_ext[ :src ] )
1109
+ add_src_wbuff_socks5_conn_reply( src )
1275
1110
  end
1276
1111
  when DEST_STATUS
1277
1112
  return if from_addr != @tun_info[ :tund_addr ]
1278
1113
 
1279
- dst_port, relay_dst_pack_id, continue_src_pack_id = data[ 9, 18 ].unpack( 'nQ>Q>' )
1114
+ dst_id, relay_dst_pack_id, continue_src_pack_id = data[ 9, 18 ].unpack( 'nQ>Q>' )
1280
1115
 
1281
- src_id = @tun_info[ :src_ids ][ dst_port ]
1116
+ src_id = @tun_info[ :src_ids ][ dst_id ]
1282
1117
  return unless src_id
1283
1118
 
1284
- src_ext = @tun_info[ :src_exts ][ src_id ]
1285
- return unless src_ext
1119
+ src = @tun_info[ :srcs ][ src_id ]
1120
+ return unless src
1121
+
1122
+ src_info = @src_infos[ src ]
1123
+ return unless src_info
1286
1124
 
1287
- # puts "debug2 got dest status"
1125
+ # puts "debug2 got dest status #{ Time.new }"
1288
1126
 
1289
- release_wmems( src_ext, continue_src_pack_id )
1127
+ # 消写后
1128
+ release_wmems( src_info, continue_src_pack_id )
1290
1129
 
1291
1130
  # 发miss
1292
- if !src_ext[ :src ].closed? && ( src_ext[ :continue_dst_pack_id ] < relay_dst_pack_id )
1131
+ if !src.closed? && ( src_info[ :continue_dst_pack_id ] < relay_dst_pack_id )
1293
1132
  ranges = []
1294
- curr_pack_id = src_ext[ :continue_dst_pack_id ] + 1
1133
+ ignored = false
1134
+ curr_pack_id = src_info[ :continue_dst_pack_id ] + 1
1295
1135
 
1296
- src_ext[ :pieces ].keys.sort.each do | pack_id |
1136
+ src_info[ :pieces ].keys.sort.each do | pack_id |
1297
1137
  if pack_id > curr_pack_id
1298
1138
  ranges << [ curr_pack_id, pack_id - 1 ]
1139
+
1140
+ if ranges.size >= MISS_RANGE_LIMIT
1141
+ puts "p#{ Process.pid } #{ Time.new } break add miss range at #{ pack_id }"
1142
+ ignored = true
1143
+ break
1144
+ end
1299
1145
  end
1300
1146
 
1301
1147
  curr_pack_id = pack_id + 1
1302
1148
  end
1303
1149
 
1304
- if curr_pack_id <= relay_dst_pack_id
1150
+ if !ignored && ( curr_pack_id <= relay_dst_pack_id )
1305
1151
  ranges << [ curr_pack_id, relay_dst_pack_id ]
1306
1152
  end
1307
1153
 
1308
- pack_count = 0
1309
- # puts "debug1 continue/relay #{ src_ext[ :continue_dst_pack_id ] }/#{ relay_dst_pack_id } send MISS #{ ranges.size }"
1154
+ # puts "debug1 continue/relay #{ src_info[ :continue_dst_pack_id ] }/#{ relay_dst_pack_id } send MISS #{ ranges.size }"
1155
+ idx = 0
1156
+ ranges = ranges.map{ | pack_id_begin, pack_id_end | [ pack_id_begin, pack_id_end ].pack( 'Q>Q>' ) }
1310
1157
 
1311
- ranges.each do | pack_id_begin, pack_id_end |
1312
- if pack_count >= BREAK_SEND_MISS
1313
- puts "p#{ Process.pid } #{ Time.new } break send miss at #{ pack_id_begin }"
1314
- break
1315
- end
1158
+ while idx < ranges.size
1159
+ chunk = ranges[ idx, MULTI_MISS_SIZE ].join
1160
+ data2 = [ [ 0, MULTI_MISS, dst_id ].pack( 'Q>Cn' ), chunk ].join
1161
+ send_data( tun, data2, @tun_info[ :tund_addr ] )
1162
+ idx += MULTI_MISS_SIZE
1163
+ end
1164
+ end
1165
+ when MULTI_MISS
1166
+ src_id, *ranges = data[ 9..-1 ].unpack( 'Q>Q>*' )
1167
+
1168
+ src = @tun_info[ :srcs ][ src_id ]
1169
+ return unless src
1170
+
1171
+ src_info = @src_infos[ src ]
1172
+ return unless src_info
1316
1173
 
1317
- data2 = [ 0, MISS, dst_port, pack_id_begin, pack_id_end ].pack( 'Q>CnQ>Q>' )
1318
- add_tun_ctlmsg( data2 )
1319
- pack_count += ( pack_id_end - pack_id_begin + 1 )
1174
+ return if ranges.empty? || ( ranges.size % 2 != 0 )
1175
+
1176
+ # puts "debug1 got multi miss #{ src_id } #{ ranges.size }"
1177
+
1178
+ idx = 0
1179
+
1180
+ while idx < ranges.size
1181
+ pack_id_begin, pack_id_end = ranges[ idx ], ranges[ idx + 1 ]
1182
+
1183
+ ( pack_id_begin..pack_id_end ).each do | pack_id |
1184
+ send_at = src_info[ :send_ats ][ pack_id ]
1185
+
1186
+ if send_at
1187
+ break if now - send_at < CHECK_STATUS_INTERVAL
1188
+ data2 = @tun_info[ :wmems ][ [ src_id, pack_id ] ]
1189
+
1190
+ if data2
1191
+ if send_data( tun, data2, @tun_info[ :tund_addr ] )
1192
+ src_info[ :last_continue_at ] = now
1193
+ end
1194
+ end
1195
+ end
1320
1196
  end
1197
+
1198
+ idx += 2
1321
1199
  end
1322
1200
  when MISS
1323
1201
  return if from_addr != @tun_info[ :tund_addr ]
1324
1202
 
1325
1203
  src_id, pack_id_begin, pack_id_end = data[ 9, 24 ].unpack( 'Q>Q>Q>' )
1326
1204
 
1327
- src_ext = @tun_info[ :src_exts ][ src_id ]
1328
- return unless src_ext
1205
+ src = @tun_info[ :srcs ][ src_id ]
1206
+ return unless src
1207
+
1208
+ src_info = @src_infos[ src ]
1209
+ return unless src_info
1329
1210
 
1330
1211
  ( pack_id_begin..pack_id_end ).each do | pack_id |
1331
- send_at = src_ext[ :send_ats ][ pack_id ]
1212
+ send_at = src_info[ :send_ats ][ pack_id ]
1332
1213
 
1333
1214
  if send_at
1334
- break if now - send_at < STATUS_INTERVAL
1335
- @tun_info[ :resendings ] << [ src_id, pack_id ]
1215
+ break if now - send_at < CHECK_STATUS_INTERVAL
1216
+ data2 = @tun_info[ :wmems ][ [ src_id, pack_id ] ]
1217
+
1218
+ if data2
1219
+ if send_data( tun, data2, @tun_info[ :tund_addr ] )
1220
+ src_info[ :last_continue_at ] = now
1221
+ end
1222
+ end
1336
1223
  end
1337
1224
  end
1338
-
1339
- add_write( tun )
1340
1225
  when FIN1
1341
1226
  return if from_addr != @tun_info[ :tund_addr ]
1342
1227
 
1343
- dst_port, biggest_dst_pack_id, continue_src_pack_id = data[ 9, 18 ].unpack( 'nQ>Q>' )
1228
+ dst_id, biggest_dst_pack_id, continue_src_pack_id = data[ 9, 18 ].unpack( 'nQ>Q>' )
1344
1229
 
1345
- src_id = @tun_info[ :src_ids ][ dst_port ]
1230
+ src_id = @tun_info[ :src_ids ][ dst_id ]
1346
1231
  return unless src_id
1347
1232
 
1348
- src_ext = @tun_info[ :src_exts ][ src_id ]
1349
- return unless src_ext
1233
+ src = @tun_info[ :srcs ][ src_id ]
1234
+ return unless src
1350
1235
 
1351
- # puts "debug1 got fin1 #{ dst_port } biggest dst pack #{ biggest_dst_pack_id } completed src pack #{ continue_src_pack_id }"
1352
- src_ext[ :is_dst_closed ] = true
1353
- src_ext[ :biggest_dst_pack_id ] = biggest_dst_pack_id
1354
- release_wmems( src_ext, continue_src_pack_id )
1236
+ src_info = @src_infos[ src ]
1237
+ return unless src_info
1238
+
1239
+ # puts "debug1 got fin1 #{ dst_id } biggest dst pack #{ biggest_dst_pack_id } completed src pack #{ continue_src_pack_id }"
1240
+ src_info[ :is_dst_closed ] = true
1241
+ src_info[ :biggest_dst_pack_id ] = biggest_dst_pack_id
1242
+ release_wmems( src_info, continue_src_pack_id )
1355
1243
 
1356
- if ( biggest_dst_pack_id == src_ext[ :continue_dst_pack_id ] )
1244
+ if ( biggest_dst_pack_id == src_info[ :continue_dst_pack_id ] )
1357
1245
  # puts "debug1 2-1. tun recv fin1 -> all traffic received ? -> close src after write"
1358
- set_is_closing( src_ext[ :src ] )
1246
+ set_is_closing( src )
1359
1247
  end
1360
1248
  when FIN2
1361
1249
  return if from_addr != @tun_info[ :tund_addr ]
1362
1250
 
1363
- dst_port = data[ 9, 2 ].unpack( 'n' ).first
1251
+ dst_id = data[ 9, 2 ].unpack( 'n' ).first
1364
1252
 
1365
- src_id = @tun_info[ :src_ids ][ dst_port ]
1253
+ src_id = @tun_info[ :src_ids ][ dst_id ]
1366
1254
  return unless src_id
1367
1255
 
1368
1256
  # puts "debug1 1-2. tun recv fin2 -> del src ext"
@@ -1384,14 +1272,18 @@ module Girl
1384
1272
 
1385
1273
  return if from_addr != @tun_info[ :tund_addr ]
1386
1274
 
1387
- dst_port = data[ 8, 2 ].unpack( 'n' ).first
1275
+ dst_id = data[ 8, 2 ].unpack( 'n' ).first
1388
1276
 
1389
- src_id = @tun_info[ :src_ids ][ dst_port ]
1277
+ src_id = @tun_info[ :src_ids ][ dst_id ]
1390
1278
  return unless src_id
1391
1279
 
1392
- src_ext = @tun_info[ :src_exts ][ src_id ]
1393
- return if src_ext.nil? || src_ext[ :src ].closed?
1394
- return if ( pack_id <= src_ext[ :continue_dst_pack_id ] ) || src_ext[ :pieces ].include?( pack_id )
1280
+ src = @tun_info[ :srcs ][ src_id ]
1281
+ return unless src
1282
+
1283
+ src_info = @src_infos[ src ]
1284
+ return unless src_info
1285
+
1286
+ return if ( pack_id <= src_info[ :continue_dst_pack_id ] ) || src_info[ :pieces ].include?( pack_id )
1395
1287
 
1396
1288
  data = data[ 10..-1 ]
1397
1289
  # puts "debug2 got pack #{ pack_id }"
@@ -1403,24 +1295,25 @@ module Girl
1403
1295
  end
1404
1296
 
1405
1297
  # 放进写前,跳号放碎片缓存
1406
- if pack_id - src_ext[ :continue_dst_pack_id ] == 1
1407
- while src_ext[ :pieces ].include?( pack_id + 1 )
1408
- data << src_ext[ :pieces ].delete( pack_id + 1 )
1298
+ if pack_id - src_info[ :continue_dst_pack_id ] == 1
1299
+ while src_info[ :pieces ].include?( pack_id + 1 )
1300
+ data << src_info[ :pieces ].delete( pack_id + 1 )
1409
1301
  pack_id += 1
1410
1302
  end
1411
1303
 
1412
- src_ext[ :continue_dst_pack_id ] = pack_id
1413
- src_ext[ :last_continue_at ] = now
1414
- add_src_wbuff( src_ext[ :src ], data )
1304
+ src_info[ :continue_dst_pack_id ] = pack_id
1305
+ src_info[ :last_continue_at ] = now
1306
+ add_src_wbuff( src, data )
1415
1307
  # puts "debug2 update continue dst pack #{ pack_id }"
1416
1308
 
1417
- # 接到流量,若对面已关闭,且流量正好收全,关闭src
1418
- if src_ext[ :is_dst_closed ] && ( pack_id == src_ext[ :biggest_dst_pack_id ] )
1309
+ # 若对面已关闭,且流量正好收全,关闭src
1310
+ if src_info[ :is_dst_closed ] && ( pack_id == src_info[ :biggest_dst_pack_id ] )
1419
1311
  # puts "debug1 2-2. tun recv traffic -> dst closed and all traffic received ? -> close src after write"
1420
- set_is_closing( src_ext[ :src ] )
1312
+ set_is_closing( src )
1421
1313
  end
1422
1314
  else
1423
- src_ext[ :pieces ][ pack_id ] = data
1315
+ src_info[ :pieces ][ pack_id ] = data
1316
+ src_info[ :last_continue_at ] = now
1424
1317
  end
1425
1318
  end
1426
1319