girl 0.82.0 → 0.87.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a5ece81dea98cedfec3abf108fa4acf0b9ca1d465251f31aa581f3540d71b252
4
- data.tar.gz: 5d245931a0540927accdaff5d350d45b003b7433e7891e7cefc855055e358a63
3
+ metadata.gz: 590ceead2e46e0803325aff199ec4fa4610a554f873ad58e91f83e8cba7bd4a9
4
+ data.tar.gz: 3034b02ee1ddf592a67446d82a3f974f2439aef9f380f20b39c96aa943a4a7ab
5
5
  SHA512:
6
- metadata.gz: d12d73e8fc0a585697fe0c21e91f70dce42606c30e3b9cde74c6430c00ce5aa3e36773bd68cffe4e3c94746fd48d42978a003b1863372f87b11f250c4a25b3b5
7
- data.tar.gz: 1238736ccfdccf480058a353883dcedc22848f43230904c7b1419876c8d7f18fba04ff8aa8c57b67fd26b4908b50f0027021c2edfb828525a6e4248040e81ea4
6
+ metadata.gz: 27d1dd5ef6d6f4d29c1916af5c10c8eb694e7cbf11f2f8518a6d4a3ebd0d368aa92518a9c5c0f91079f9291c67b1050be16db3f0154d7fb710f55d818ca75576
7
+ data.tar.gz: ae5ab8293caf167146784342a93e059ef03a201dbd1a1a3df6bbe206321f95b13526e78713ca77903e3be44873ce02474c4d3260187fcd85c993206401fef586
@@ -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
 
@@ -108,7 +106,7 @@ module Girl
108
106
  raise "not found direct file #{ direct_path }"
109
107
  end
110
108
 
111
- directs = ( [ Addrinfo.ip( proxyd_host ).ip_address ] + RESERVED_ROUTE.split( "\n" ) + IO.binread( direct_path ).split( "\n" ) ).map { | line | IPAddr.new( line.strip ) }
109
+ directs = ( RESERVED_ROUTE.split( "\n" ) + IO.binread( direct_path ).split( "\n" ) ).map { | line | IPAddr.new( line.strip ) }
112
110
  end
113
111
 
114
112
  remotes = []
@@ -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
@@ -186,24 +197,58 @@ module Girl
186
197
  end
187
198
  end
188
199
 
189
- ##
190
- # loop send a new source
191
- #
192
- def loop_send_a_new_source( src_ext, data )
200
+ def loop_send_hello
201
+ data = @custom.hello
202
+
193
203
  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 ] }"
204
+ EXPIRE_NEW.times do | i |
205
+ if @tun.closed? || @tun_info[ :tund_addr ]
206
+ # puts "debug1 break loop send hello"
197
207
  break
198
208
  end
199
209
 
200
210
  @mutex.synchronize do
201
- # puts "debug1 send a new source #{ data.inspect }"
202
- add_tun_ctlmsg( data )
203
- next_tick
211
+ msg = i >= 1 ? "resend hello #{ i }" : "hello i'm tun"
212
+ puts "p#{ Process.pid } #{ Time.new } #{ msg }"
213
+ # puts "debug1 #{ data.inspect }"
214
+
215
+ send_data( @tun, data, @proxyd_addr )
204
216
  end
205
217
 
206
- sleep 1
218
+ sleep CHECK_STATUS_INTERVAL
219
+ end
220
+ end
221
+ end
222
+
223
+ ##
224
+ # loop send a new source
225
+ #
226
+ def loop_send_a_new_source( src )
227
+ src_info = @src_infos[ src ]
228
+
229
+ if src_info && @tun_info[ :tund_addr ]
230
+ destination_domain = src_info[ :destination_domain ]
231
+ destination_port = src_info[ :destination_port ]
232
+ domain_port = [ destination_domain, destination_port ].join( ':' )
233
+ data = [ [ 0, A_NEW_SOURCE, src_info[ :id ] ].pack( 'Q>CQ>' ), @custom.encode( domain_port ) ].join
234
+
235
+ Thread.new do
236
+ EXPIRE_NEW.times do | i |
237
+ if src.closed? || src_info[ :dst_id ]
238
+ # puts "debug1 break loop send a new source #{ src_info[ :dst_port ] }"
239
+ break
240
+ end
241
+
242
+ @mutex.synchronize do
243
+ if i >= 1
244
+ puts "p#{ Process.pid } #{ Time.new } resend a new source #{ domain_port } #{ i }"
245
+ end
246
+
247
+ send_data( @tun, data, @tun_info[ :tund_addr ] )
248
+ end
249
+
250
+ sleep CHECK_STATUS_INTERVAL
251
+ end
207
252
  end
208
253
  end
209
254
  end
@@ -264,8 +309,10 @@ module Girl
264
309
  # deal with destination ip
265
310
  #
266
311
  def deal_with_destination_ip( src, ip_info )
267
- if @directs.any? { | direct | direct.include?( ip_info.ip_address ) }
268
- # ip命中直连列表,直连
312
+ src_info = @src_infos[ src ]
313
+
314
+ if ( @directs.any? { | direct | direct.include?( ip_info.ip_address ) } ) || ( ( src_info[ :destination_domain ] == @proxyd_host ) && ![ 80, 443 ].include?( src_info[ :destination_port ] ) )
315
+ # ip命中直连列表,或者访问远端非80/443端口,直连
269
316
  # puts "debug1 #{ ip_info.inspect } hit directs"
270
317
  new_a_dst( src, ip_info )
271
318
  else
@@ -302,15 +349,12 @@ module Girl
302
349
  port = tun.local_address.ip_port
303
350
  tun_info = {
304
351
  port: port, # 端口
305
- ctlmsg_rbuffs: [], # 还没配上tund,暂存的ctlmsg
306
- ctlmsgs: [], # [ to_addr, data ]
307
- wbuffs: [], # 写前缓存 [ src_id, pack_id, data ]
308
- caches: [], # 块读出缓存 [ src_id, pack_id, data ]
309
- chunks: [], # 块队列 filename
310
- spring: 0, # 块后缀,结块时,如果块队列不为空,则自增,为空,则置为0
352
+ pending_sources: [], # 还没配上tund,暂存的src
353
+ wbuffs: [], # 写前 [ src_id, pack_id, data ]
354
+ wmems: {}, # 写后 [ src_id, pack_id ] => data
311
355
  tund_addr: nil, # tund地址
312
- src_exts: {}, # src额外信息 src_id => {}
313
- src_ids: {}, # dst_port => src_id
356
+ srcs: {}, # src_id => src
357
+ src_ids: {}, # dst_id => src_id
314
358
  paused: false, # 是否暂停写
315
359
  resendings: [], # 重传队列 [ src_id, pack_id ]
316
360
  created_at: Time.new, # 创建时间
@@ -322,10 +366,7 @@ module Girl
322
366
  @tun_info = tun_info
323
367
 
324
368
  add_read( tun, :tun )
325
- data = @custom.hello
326
- puts "p#{ Process.pid } #{ Time.new } hello i'm tun"
327
- # puts "debug1 #{ data.inspect }"
328
- add_tun_ctlmsg( data, @proxyd_addr )
369
+ loop_send_hello
329
370
  end
330
371
 
331
372
  ##
@@ -358,9 +399,6 @@ module Girl
358
399
  src: src, # 对应src
359
400
  domain: domain, # 域名
360
401
  wbuff: '', # 写前
361
- cache: '', # 块读出缓存
362
- chunks: [], # 块队列,写前达到块大小时结一个块 filename
363
- spring: 0, # 块后缀,结块时,如果块队列不为空,则自增,为空,则置为0
364
402
  last_continue_at: Time.new, # 上一次发生流量的时间
365
403
  is_closing: false # 是否准备关闭
366
404
  }
@@ -374,11 +412,8 @@ module Girl
374
412
  # puts "debug1 add src wbuff http ok"
375
413
  add_src_wbuff( src, HTTP_OK )
376
414
  else
377
- # puts "debug1 add src rbuffs to dst wbuff"
378
-
379
- src_info[ :rbuffs ].each do | _, data |
380
- add_dst_wbuff( dst, data )
381
- end
415
+ # puts "debug1 add src rbuff to dst wbuff"
416
+ add_dst_wbuff( dst, src_info[ :rbuff ] )
382
417
  end
383
418
  elsif src_info[ :proxy_proto ] == :socks5
384
419
  add_src_wbuff_socks5_conn_reply( src )
@@ -394,31 +429,15 @@ module Girl
394
429
  end
395
430
 
396
431
  src_info = @src_infos[ src ]
397
- src_id = src_info[ :id ]
398
- destination_port = src_info[ :destination_port ]
399
- destination_domain = src_info[ :destination_domain ]
400
-
401
- src_ext = {
402
- src: src, # src
403
- dst_port: nil, # 远端dst端口
404
- destination_domain: destination_domain, # 目的地域名
405
- wmems: {}, # 写后 pack_id => data
406
- send_ats: {}, # 上一次发出时间 pack_id => send_at
407
- relay_pack_id: 0, # 转发到几
408
- continue_dst_pack_id: 0, # 收到几
409
- pieces: {}, # 跳号包 dst_pack_id => data
410
- is_dst_closed: false, # dst是否已关闭
411
- biggest_dst_pack_id: 0, # dst最大包号码
412
- completed_pack_id: 0, # 完成到几(对面收到几)
413
- last_continue_at: Time.new # 上一次发生流量的时间
414
- }
415
-
416
- @tun_info[ :src_exts ][ src_id ] = src_ext
417
432
  src_info[ :proxy_type ] = :tunnel
433
+ src_id = src_info[ :id ]
434
+ @tun_info[ :srcs ][ src_id ] = src
418
435
 
419
- destination_domain_port = [ destination_domain, destination_port ].join( ':' )
420
- data = [ [ 0, A_NEW_SOURCE, src_id ].pack( 'Q>CQ>' ), @custom.encode( destination_domain_port ) ].join
421
- loop_send_a_new_source( src_ext, data )
436
+ if @tun_info[ :tund_addr ]
437
+ loop_send_a_new_source( src )
438
+ else
439
+ @tun_info[ :pending_sources ] << src
440
+ end
422
441
  end
423
442
 
424
443
  ##
@@ -457,75 +476,12 @@ module Girl
457
476
  [ data, domain_and_port ]
458
477
  end
459
478
 
460
- ##
461
- # add tun ctlmsg
462
- #
463
- def add_tun_ctlmsg( data, to_addr = nil )
464
- unless to_addr
465
- to_addr = @tun_info[ :tund_addr ]
466
- end
467
-
468
- if to_addr
469
- @tun_info[ :ctlmsgs ] << [ to_addr, data ]
470
- add_write( @tun )
471
- else
472
- @tun_info[ :ctlmsg_rbuffs ] << data
473
- end
474
- end
475
-
476
- ##
477
- # add tun wbuff
478
- #
479
- def add_tun_wbuff( src_id, pack_id, data )
480
- @tun_info[ :wbuffs ] << [ src_id, pack_id, data ]
481
-
482
- if @tun_info[ :wbuffs ].size >= WBUFFS_LIMIT
483
- spring = @tun_info[ :chunks ].size > 0 ? ( @tun_info[ :spring ] + 1 ) : 0
484
- filename = "#{ Process.pid }-#{ @tun_info[ :port ] }.#{ spring }"
485
- chunk_path = File.join( @tun_chunk_dir, filename )
486
- datas = @tun_info[ :wbuffs ].map{ | _src_id, _pack_id, _data | [ [ _src_id, _pack_id, _data.bytesize ].pack( 'Q>Q>n' ), _data ].join }
487
-
488
- begin
489
- IO.binwrite( chunk_path, datas.join )
490
- rescue Errno::ENOSPC => e
491
- puts "p#{ Process.pid } #{ Time.new } #{ e.class }, close tun"
492
- set_is_closing( @tun )
493
- return
494
- end
495
-
496
- @tun_info[ :chunks ] << filename
497
- @tun_info[ :spring ] = spring
498
- @tun_info[ :wbuffs ].clear
499
- end
500
-
501
- add_write( @tun )
502
- end
503
-
504
479
  ##
505
480
  # add src wbuff
506
481
  #
507
482
  def add_src_wbuff( src, data )
508
483
  src_info = @src_infos[ src ]
509
484
  src_info[ :wbuff ] << data
510
-
511
- if src_info[ :wbuff ].bytesize >= CHUNK_SIZE
512
- spring = src_info[ :chunks ].size > 0 ? ( src_info[ :spring ] + 1 ) : 0
513
- filename = "#{ Process.pid }-#{ src_info[ :id ] }.#{ spring }"
514
- chunk_path = File.join( @src_chunk_dir, filename )
515
-
516
- begin
517
- IO.binwrite( chunk_path, src_info[ :wbuff ] )
518
- rescue Errno::ENOSPC => e
519
- puts "p#{ Process.pid } #{ Time.new } #{ e.class }, close src"
520
- set_is_closing( src )
521
- return
522
- end
523
-
524
- src_info[ :chunks ] << filename
525
- src_info[ :spring ] = spring
526
- src_info[ :wbuff ].clear
527
- end
528
-
529
485
  add_write( src )
530
486
  end
531
487
 
@@ -535,37 +491,20 @@ module Girl
535
491
  def add_dst_wbuff( dst, data )
536
492
  dst_info = @dst_infos[ dst ]
537
493
  dst_info[ :wbuff ] << data
538
-
539
- if dst_info[ :wbuff ].bytesize >= CHUNK_SIZE
540
- spring = dst_info[ :chunks ].size > 0 ? ( dst_info[ :spring ] + 1 ) : 0
541
- filename = "#{ Process.pid }-#{ dst_info[ :local_port ] }.#{ spring }"
542
- chunk_path = File.join( @dst_chunk_dir, filename )
543
-
544
- begin
545
- IO.binwrite( chunk_path, dst_info[ :wbuff ] )
546
- rescue Errno::ENOSPC => e
547
- puts "p#{ Process.pid } #{ Time.new } #{ e.class }, close dst"
548
- set_is_closing( dst )
549
- return
550
- end
551
-
552
- dst_info[ :chunks ] << filename
553
- dst_info[ :spring ] = spring
554
- dst_info[ :wbuff ].clear
555
- end
556
-
557
494
  add_write( dst )
558
495
  end
559
496
 
560
497
  ##
561
498
  # add read
562
499
  #
563
- def add_read( sock, role )
564
- unless @reads.include?( sock )
500
+ def add_read( sock, role = nil )
501
+ if sock && !sock.closed? && !@reads.include?( sock )
565
502
  @reads << sock
566
- end
567
503
 
568
- @roles[ sock ] = role
504
+ if role
505
+ @roles[ sock ] = role
506
+ end
507
+ end
569
508
  end
570
509
 
571
510
  ##
@@ -577,6 +516,17 @@ module Girl
577
516
  end
578
517
  end
579
518
 
519
+ ##
520
+ # add pause src
521
+ #
522
+ def add_pause_src( src )
523
+ @reads.delete( src )
524
+
525
+ unless @pause_srcs.include?( src )
526
+ @pause_srcs << src
527
+ end
528
+ end
529
+
580
530
  ##
581
531
  # set is closing
582
532
  #
@@ -601,10 +551,52 @@ module Girl
601
551
  end
602
552
  end
603
553
 
554
+ ##
555
+ # tunnel data
556
+ #
557
+ def tunnel_data( src, data )
558
+ src_info = @src_infos[ src ]
559
+ src_id = src_info[ :id ]
560
+ now = Time.new
561
+ pack_id = src_info[ :biggest_pack_id ]
562
+ idx = 0
563
+ len = data.bytesize
564
+
565
+ while idx < len
566
+ chunk = data[ idx, PACK_SIZE ]
567
+ pack_id += 1
568
+
569
+ if pack_id <= CONFUSE_UNTIL
570
+ chunk = @custom.encode( chunk )
571
+ # puts "debug1 encoded chunk #{ pack_id }"
572
+ end
573
+
574
+ data2 = [ [ pack_id, src_id ].pack( 'Q>Q>' ), chunk ].join
575
+ sent = send_data( @tun, data2, @tun_info[ :tund_addr ] )
576
+ # puts "debug2 written pack #{ pack_id } #{ sent }"
577
+ @tun_info[ :wmems ][ [ src_id, pack_id ] ] = data2
578
+ src_info[ :send_ats ][ pack_id ] = now
579
+ idx += PACK_SIZE
580
+ end
581
+
582
+ src_info[ :biggest_pack_id ] = pack_id
583
+ src_info[ :last_continue_at ] = now
584
+
585
+ # 写后超过上限,暂停读src
586
+ if @tun_info[ :wmems ].size >= WMEMS_LIMIT
587
+ puts "p#{ Process.pid } #{ Time.new } pause src #{ src_id } #{ src_info[ :destination_domain ] } #{ src_info[ :biggest_pack_id ] }"
588
+ add_pause_src( src )
589
+ end
590
+ end
591
+
604
592
  ##
605
593
  # send data
606
594
  #
607
595
  def send_data( tun, data, to_addr )
596
+ unless to_addr
597
+ return false
598
+ end
599
+
608
600
  begin
609
601
  tun.sendmsg( data, 0, to_addr )
610
602
  rescue IO::WaitWritable, Errno::EINTR
@@ -624,36 +616,36 @@ module Girl
624
616
  def close_src( src )
625
617
  # puts "debug1 close src"
626
618
  close_sock( src )
627
- src_info = @src_infos.delete( src )
619
+ @pause_srcs.delete( src )
620
+ src_info = @src_infos[ src ]
628
621
 
629
- src_info[ :chunks ].each do | filename |
630
- begin
631
- File.delete( File.join( @src_chunk_dir, filename ) )
632
- rescue Errno::ENOENT
622
+ if src_info[ :proxy_type ] == :direct
623
+ @src_infos.delete( src )
624
+
625
+ if src_info[ :dst ]
626
+ set_is_closing( src_info[ :dst ] )
633
627
  end
634
- end
635
628
 
636
- src_id = src_info[ :id ]
629
+ return
630
+ end
637
631
 
638
- if src_info[ :proxy_type ] == :tunnel
639
- return if @tun.closed?
632
+ if @tun.closed? || src_info[ :dst_id ].nil?
633
+ @src_infos.delete( src )
634
+ return
635
+ end
640
636
 
641
- src_ext = @tun_info[ :src_exts ][ src_id ]
642
- return if src_ext.nil? || src_ext[ :dst_port ].nil?
637
+ src_id = src_info[ :id ]
643
638
 
644
- if src_ext[ :is_dst_closed ]
645
- # puts "debug1 2-3. after close src -> dst closed ? yes -> del src ext -> send fin2"
646
- del_src_ext( src_id )
647
- data = [ 0, FIN2, src_id ].pack( 'Q>CQ>' )
648
- add_tun_ctlmsg( data )
649
- else
650
- # puts "debug1 1-1. after close src -> dst closed ? no -> send fin1"
651
- data = [ 0, FIN1, src_id, src_info[ :biggest_pack_id ], src_ext[ :continue_dst_pack_id ] ].pack( 'Q>CQ>Q>Q>' )
652
- add_tun_ctlmsg( data )
653
- end
654
- elsif src_info[ :proxy_type ] == :direct
655
- set_is_closing( src_info[ :dst ] )
639
+ if src_info[ :is_dst_closed ]
640
+ # puts "debug1 2-3. after close src -> dst closed ? yes -> del src ext -> send fin2"
641
+ del_src_ext( src_id )
642
+ data = [ 0, FIN2, src_id ].pack( 'Q>CQ>' )
643
+ else
644
+ # puts "debug1 1-1. after close src -> dst closed ? no -> send fin1"
645
+ data = [ 0, FIN1, src_id, src_info[ :biggest_pack_id ], src_info[ :continue_dst_pack_id ] ].pack( 'Q>CQ>Q>Q>' )
656
646
  end
647
+
648
+ send_data( @tun, data, @tun_info[ :tund_addr ] )
657
649
  end
658
650
 
659
651
  ##
@@ -663,14 +655,6 @@ module Girl
663
655
  # puts "debug1 close dst"
664
656
  close_sock( dst )
665
657
  dst_info = @dst_infos.delete( dst )
666
-
667
- dst_info[ :chunks ].each do | filename |
668
- begin
669
- File.delete( File.join( @dst_chunk_dir, filename ) )
670
- rescue Errno::ENOENT
671
- end
672
- end
673
-
674
658
  set_is_closing( dst_info[ :src ] )
675
659
  end
676
660
 
@@ -680,15 +664,7 @@ module Girl
680
664
  def close_tun( tun )
681
665
  # puts "debug1 close tun"
682
666
  close_sock( tun )
683
-
684
- @tun_info[ :chunks ].each do | filename |
685
- begin
686
- File.delete( File.join( @tun_chunk_dir, filename ) )
687
- rescue Errno::ENOENT
688
- end
689
- end
690
-
691
- @tun_info[ :src_exts ].each{ | _, src_ext | set_is_closing( src_ext[ :src ] ) }
667
+ @tun_info[ :srcs ].each{ | _, src | set_is_closing( src ) }
692
668
  end
693
669
 
694
670
  ##
@@ -705,27 +681,32 @@ module Girl
705
681
  # del src ext
706
682
  #
707
683
  def del_src_ext( src_id )
708
- src_ext = @tun_info[ :src_exts ].delete( src_id )
684
+ @tun_info[ :wmems ].delete_if { | src_id_and_pack_id, _ | src_id_and_pack_id.first == src_id }
685
+ src = @tun_info[ :srcs ].delete( src_id )
709
686
 
710
- if src_ext
711
- @tun_info[ :src_ids ].delete( src_ext[ :dst_port ] )
687
+ if src
688
+ src_info = @src_infos.delete( src )
689
+
690
+ if src_info
691
+ @tun_info[ :src_ids ].delete( src_info[ :dst_id ] )
692
+ end
712
693
  end
713
694
  end
714
695
 
715
696
  ##
716
697
  # release wmems
717
698
  #
718
- def release_wmems( src_ext, completed_pack_id )
719
- if completed_pack_id > src_ext[ :completed_pack_id ]
699
+ def release_wmems( src_info, completed_pack_id )
700
+ if completed_pack_id > src_info[ :completed_pack_id ]
720
701
  # puts "debug2 update completed pack #{ completed_pack_id }"
721
- pack_ids = src_ext[ :wmems ].keys.select { | pack_id | pack_id <= completed_pack_id }
702
+ pack_ids = src_info[ :send_ats ].keys.select { | pack_id | pack_id <= completed_pack_id }
722
703
 
723
704
  pack_ids.each do | pack_id |
724
- src_ext[ :wmems ].delete( pack_id )
725
- src_ext[ :send_ats ].delete( pack_id )
705
+ @tun_info[ :wmems ].delete( [ src_info[ :id ], pack_id ] )
706
+ src_info[ :send_ats ].delete( pack_id )
726
707
  end
727
708
 
728
- src_ext[ :completed_pack_id ] = completed_pack_id
709
+ src_info[ :completed_pack_id ] = completed_pack_id
729
710
  end
730
711
  end
731
712
 
@@ -741,32 +722,16 @@ module Girl
741
722
  #
742
723
  def write_src( src )
743
724
  src_info = @src_infos[ src ]
744
- from, data = :cache, src_info[ :cache ]
745
725
 
746
- if data.empty?
747
- if src_info[ :chunks ].any?
748
- path = File.join( @src_chunk_dir, src_info[ :chunks ].shift )
749
-
750
- begin
751
- data = src_info[ :cache ] = IO.binread( path )
752
- File.delete( path )
753
- rescue Errno::ENOENT => e
754
- puts "p#{ Process.pid } #{ Time.new } read #{ path } #{ e.class }"
755
- close_src( src )
756
- return
757
- end
758
- else
759
- from, data = :wbuff, src_info[ :wbuff ]
760
- end
726
+ if src_info[ :is_closing ]
727
+ close_src( src )
728
+ return
761
729
  end
762
730
 
763
- if data.empty?
764
- if src_info[ :is_closing ]
765
- close_src( src )
766
- else
767
- @writes.delete( src )
768
- end
731
+ data = src_info[ :wbuff ]
769
732
 
733
+ if data.empty?
734
+ @writes.delete( src )
770
735
  return
771
736
  end
772
737
 
@@ -781,7 +746,7 @@ module Girl
781
746
 
782
747
  # puts "debug2 write src #{ written }"
783
748
  data = data[ written..-1 ]
784
- src_info[ from ] = data
749
+ src_info[ :wbuff ] = data
785
750
  src_info[ :last_continue_at ] = Time.new
786
751
  end
787
752
 
@@ -790,32 +755,16 @@ module Girl
790
755
  #
791
756
  def write_dst( dst )
792
757
  dst_info = @dst_infos[ dst ]
793
- from, data = :cache, dst_info[ :cache ]
794
758
 
795
- if data.empty?
796
- if dst_info[ :chunks ].any?
797
- path = File.join( @dst_chunk_dir, dst_info[ :chunks ].shift )
798
-
799
- begin
800
- data = dst_info[ :cache ] = IO.binread( path )
801
- File.delete( path )
802
- rescue Errno::ENOENT => e
803
- puts "p#{ Process.pid } #{ Time.new } read #{ path } #{ e.class }"
804
- close_dst( dst )
805
- return
806
- end
807
- else
808
- from, data = :wbuff, dst_info[ :wbuff ]
809
- end
759
+ if dst_info[ :is_closing ]
760
+ close_dst( dst )
761
+ return
810
762
  end
811
763
 
812
- if data.empty?
813
- if dst_info[ :is_closing ]
814
- close_dst( dst )
815
- else
816
- @writes.delete( dst )
817
- end
764
+ data = dst_info[ :wbuff ]
818
765
 
766
+ if data.empty?
767
+ @writes.delete( dst )
819
768
  return
820
769
  end
821
770
 
@@ -831,7 +780,7 @@ module Girl
831
780
 
832
781
  # puts "debug2 write dst #{ written }"
833
782
  data = data[ written..-1 ]
834
- dst_info[ from ] = data
783
+ dst_info[ :wbuff ] = data
835
784
  dst_info[ :last_continue_at ] = Time.new
836
785
  end
837
786
 
@@ -844,106 +793,7 @@ module Girl
844
793
  return
845
794
  end
846
795
 
847
- now = Time.new
848
-
849
- # 传ctlmsg
850
- while @tun_info[ :ctlmsgs ].any?
851
- to_addr, data = @tun_info[ :ctlmsgs ].first
852
-
853
- unless send_data( tun, data, to_addr )
854
- return
855
- end
856
-
857
- @tun_info[ :ctlmsgs ].shift
858
- end
859
-
860
- # 重传
861
- while @tun_info[ :resendings ].any?
862
- src_id, pack_id = @tun_info[ :resendings ].first
863
- src_ext = @tun_info[ :src_exts ][ src_id ]
864
-
865
- if src_ext
866
- data = src_ext[ :wmems ][ pack_id ]
867
-
868
- if data
869
- unless send_data( tun, data, @tun_info[ :tund_addr ] )
870
- return
871
- end
872
-
873
- src_ext[ :last_continue_at ] = now
874
- end
875
- end
876
-
877
- @tun_info[ :resendings ].shift
878
- end
879
-
880
- # 若写后达到上限,暂停取写前
881
- if @tun_info[ :src_exts ].map{ | _, src_ext | src_ext[ :wmems ].size }.sum >= WMEMS_LIMIT
882
- unless @tun_info[ :paused ]
883
- puts "p#{ Process.pid } #{ Time.new } pause tun"
884
- @tun_info[ :paused ] = true
885
- end
886
-
887
- @writes.delete( tun )
888
- return
889
- end
890
-
891
- # 取写前
892
- if @tun_info[ :caches ].any?
893
- datas = @tun_info[ :caches ]
894
- elsif @tun_info[ :chunks ].any?
895
- path = File.join( @tun_chunk_dir, @tun_info[ :chunks ].shift )
896
-
897
- begin
898
- data = IO.binread( path )
899
- File.delete( path )
900
- rescue Errno::ENOENT => e
901
- puts "p#{ Process.pid } #{ Time.new } read #{ path } #{ e.class }"
902
- close_tun( tun )
903
- return
904
- end
905
-
906
- caches = []
907
-
908
- until data.empty?
909
- _src_id, _pack_id, pack_size = data[ 0, 18 ].unpack( 'Q>Q>n' )
910
- caches << [ _src_id, _pack_id, data[ 18, pack_size ] ]
911
- data = data[ ( 18 + pack_size )..-1 ]
912
- end
913
-
914
- datas = @tun_info[ :caches ] = caches
915
- elsif @tun_info[ :wbuffs ].any?
916
- datas = @tun_info[ :wbuffs ]
917
- else
918
- @writes.delete( tun )
919
- return
920
- end
921
-
922
- while datas.any?
923
- src_id, pack_id, data = datas.first
924
- src_ext = @tun_info[ :src_exts ][ src_id ]
925
-
926
- if src_ext
927
- if pack_id <= CONFUSE_UNTIL
928
- data = @custom.encode( data )
929
- # puts "debug1 encoded pack #{ pack_id }"
930
- end
931
-
932
- data = [ [ pack_id, src_id ].pack( 'Q>Q>' ), data ].join
933
-
934
- unless send_data( tun, data, @tun_info[ :tund_addr ] )
935
- return
936
- end
937
-
938
- # puts "debug2 written pack #{ pack_id }"
939
- src_ext[ :relay_pack_id ] = pack_id
940
- src_ext[ :wmems ][ pack_id ] = data
941
- src_ext[ :send_ats ][ pack_id ] = now
942
- src_ext[ :last_continue_at ] = now
943
- end
944
-
945
- datas.shift
946
- end
796
+ @writes.delete( tun )
947
797
  end
948
798
 
949
799
  ##
@@ -963,11 +813,11 @@ module Girl
963
813
  return
964
814
  end
965
815
 
966
- id = rand( ( 2 ** 64 ) - 2 ) + 1
967
- # puts "debug1 accept a src #{ addrinfo.inspect } #{ id }"
816
+ src_id = rand( ( 2 ** 64 ) - 2 ) + 1
817
+ # puts "debug1 accept a src #{ addrinfo.inspect } #{ src_id }"
968
818
 
969
819
  @src_infos[ src ] = {
970
- id: id, # id
820
+ id: src_id, # id
971
821
  proxy_proto: :uncheck, # :uncheck / :http / :socks5
972
822
  proxy_type: :uncheck, # :uncheck / :checking / :direct / :tunnel / :negotiation
973
823
  dst: nil, # :direct的场合,对应的dst
@@ -975,11 +825,15 @@ module Girl
975
825
  destination_port: nil, # 目的地端口
976
826
  biggest_pack_id: 0, # 最大包号码
977
827
  is_connect: true, # 代理协议是http的场合,是否是CONNECT
978
- rbuffs: [], # 非CONNECT,dst或者远端dst未准备好,暂存流量 [ pack_id, data ]
828
+ rbuff: '', # 非CONNECT,dst或者远端dst未准备好,暂存流量
979
829
  wbuff: '', # 写前
980
- cache: '', # 块读出缓存
981
- chunks: [], # 块队列,写前达到块大小时结一个块 filename
982
- spring: 0, # 块后缀,结块时,如果块队列不为空,则自增,为空,则置为0
830
+ dst_id: nil, # 远端dst id
831
+ send_ats: {}, # 上一次发出时间 pack_id => send_at
832
+ continue_dst_pack_id: 0, # 收到几
833
+ pieces: {}, # 跳号包 dst_pack_id => data
834
+ is_dst_closed: false, # dst是否已关闭
835
+ biggest_dst_pack_id: 0, # dst最大包号码
836
+ completed_pack_id: 0, # 完成到几(对面收到几)
983
837
  last_continue_at: Time.new, # 上一次发生流量的时间
984
838
  is_closing: false # 是否准备关闭
985
839
  }
@@ -992,7 +846,7 @@ module Girl
992
846
  #
993
847
  def read_src( src )
994
848
  begin
995
- data = src.read_nonblock( PACK_SIZE )
849
+ data = src.read_nonblock( READ_SIZE )
996
850
  rescue IO::WaitReadable, Errno::EINTR
997
851
  return
998
852
  rescue Exception => e
@@ -1072,9 +926,7 @@ module Girl
1072
926
  end
1073
927
 
1074
928
  src_info[ :is_connect ] = false
1075
- pack_id = src_info[ :biggest_pack_id ] + 1
1076
- src_info[ :biggest_pack_id ] = pack_id
1077
- src_info[ :rbuffs ] << [ pack_id, data ]
929
+ src_info[ :rbuff ] << data
1078
930
  end
1079
931
 
1080
932
  domain, port = domain_and_port.split( ':' )
@@ -1087,9 +939,7 @@ module Girl
1087
939
  resolve_domain( src, domain )
1088
940
  when :checking
1089
941
  # puts "debug1 add src rbuff while checking #{ data.inspect }"
1090
- pack_id = src_info[ :biggest_pack_id ] + 1
1091
- src_info[ :biggest_pack_id ] = pack_id
1092
- src_info[ :rbuffs ] << [ pack_id, data ]
942
+ src_info[ :rbuff ] << data
1093
943
  when :negotiation
1094
944
  # +----+-----+-------+------+----------+----------+
1095
945
  # |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT |
@@ -1127,19 +977,7 @@ module Girl
1127
977
  puts "p#{ Process.pid } #{ Time.new } socks5 cmd #{ cmd } not implement"
1128
978
  end
1129
979
  when :tunnel
1130
- src_id = src_info[ :id ]
1131
- src_ext = @tun_info[ :src_exts ][ src_id ]
1132
-
1133
- unless src_ext
1134
- # puts "debug1 not found src ext"
1135
- set_is_closing( src )
1136
- return
1137
- end
1138
-
1139
- pack_id = src_info[ :biggest_pack_id ] + 1
1140
- src_info[ :biggest_pack_id ] = pack_id
1141
-
1142
- if src_ext[ :dst_port ]
980
+ if src_info[ :dst_id ]
1143
981
  if @tun.closed?
1144
982
  # puts "debug1 tun closed, close src"
1145
983
  set_is_closing( src )
@@ -1150,10 +988,10 @@ module Girl
1150
988
  data, _ = sub_http_request( data )
1151
989
  end
1152
990
 
1153
- add_tun_wbuff( src_id, pack_id, data )
991
+ tunnel_data( src, data )
1154
992
  else
1155
993
  # puts "debug1 remote dst not ready, save data to src rbuff"
1156
- src_info[ :rbuffs ] << [ pack_id, data ]
994
+ src_info[ :rbuff ] << data
1157
995
  end
1158
996
  when :direct
1159
997
  dst = src_info[ :dst ]
@@ -1172,7 +1010,7 @@ module Girl
1172
1010
  add_dst_wbuff( dst, data )
1173
1011
  else
1174
1012
  # puts "debug1 dst not ready, save data to src rbuff"
1175
- src_info[ :rbuffs ] << [ nil, data ]
1013
+ src_info[ :rbuff ] << data
1176
1014
  end
1177
1015
  end
1178
1016
  end
@@ -1182,7 +1020,7 @@ module Girl
1182
1020
  #
1183
1021
  def read_dst( dst )
1184
1022
  begin
1185
- data = dst.read_nonblock( PACK_SIZE )
1023
+ data = dst.read_nonblock( READ_SIZE )
1186
1024
  rescue IO::WaitReadable, Errno::EINTR
1187
1025
  return
1188
1026
  rescue Exception => e
@@ -1224,143 +1062,194 @@ module Girl
1224
1062
 
1225
1063
  tund_port = data[ 9, 2 ].unpack( 'n' ).first
1226
1064
 
1227
- # puts "debug1 got tund port #{ tund_port }"
1065
+ puts "p#{ Process.pid } #{ Time.new } got tund port #{ tund_port }"
1228
1066
  tund_addr = Socket.sockaddr_in( tund_port, @proxyd_host )
1229
1067
  @tun_info[ :tund_addr ] = tund_addr
1230
1068
 
1231
- if @tun_info[ :ctlmsg_rbuffs ].any?
1232
- # puts "debug1 move #{ @tun_info[ :ctlmsg_rbuffs ].size } ctlmsg rbuffs to ctlmsgs"
1233
- @tun_info[ :ctlmsgs ] += @tun_info[ :ctlmsg_rbuffs ].map{ | _data | [ tund_addr, _data ] }
1234
- @tun_info[ :ctlmsg_rbuffs ].clear
1235
- add_write( tun )
1069
+ if @tun_info[ :pending_sources ].any?
1070
+ puts "p#{ Process.pid } #{ Time.new } send pending sources"
1071
+
1072
+ @tun_info[ :pending_sources ].each do | src |
1073
+ loop_send_a_new_source( src )
1074
+ end
1075
+
1076
+ @tun_info[ :pending_sources ].clear
1236
1077
  end
1237
1078
  when PAIRED
1238
1079
  return if from_addr != @tun_info[ :tund_addr ]
1239
1080
 
1240
- src_id, dst_port = data[ 9, 10 ].unpack( 'Q>n' )
1081
+ src_id, dst_id = data[ 9, 10 ].unpack( 'Q>n' )
1241
1082
 
1242
- src_ext = @tun_info[ :src_exts ][ src_id ]
1243
- return if src_ext.nil? || src_ext[ :dst_port ]
1244
-
1245
- src = src_ext[ :src ]
1083
+ src = @tun_info[ :srcs ][ src_id ]
1246
1084
  return if src.closed?
1247
1085
 
1248
- # puts "debug1 got paired #{ src_id } #{ dst_port }"
1086
+ src_info = @src_infos[ src ]
1087
+ return if src_info[ :dst_id ]
1088
+
1089
+ # puts "debug1 got paired #{ src_id } #{ dst_id }"
1249
1090
 
1250
- if dst_port == 0
1091
+ if dst_id == 0
1251
1092
  set_is_closing( src )
1252
1093
  return
1253
1094
  end
1254
1095
 
1255
- src_ext[ :dst_port ] = dst_port
1256
- @tun_info[ :src_ids ][ dst_port ] = src_id
1257
-
1258
- src_info = @src_infos[ src ]
1096
+ src_info[ :dst_id ] = dst_id
1097
+ @tun_info[ :src_ids ][ dst_id ] = src_id
1259
1098
 
1260
1099
  if src_info[ :proxy_proto ] == :http
1261
1100
  if src_info[ :is_connect ]
1262
1101
  # puts "debug1 add src wbuff http ok"
1263
1102
  add_src_wbuff( src, HTTP_OK )
1264
1103
  else
1265
- # puts "debug1 add src rbuffs to tun wbuffs"
1266
-
1267
- src_info[ :rbuffs ].each do | pack_id, _data |
1268
- add_tun_wbuff( src_id, pack_id, _data )
1269
- end
1104
+ # puts "debug1 send src rbuff to tund"
1105
+ tunnel_data( src, src_info[ :rbuff ] )
1270
1106
  end
1271
1107
  elsif src_info[ :proxy_proto ] == :socks5
1272
- add_src_wbuff_socks5_conn_reply( src_ext[ :src ] )
1108
+ add_src_wbuff_socks5_conn_reply( src )
1273
1109
  end
1274
1110
  when DEST_STATUS
1275
1111
  return if from_addr != @tun_info[ :tund_addr ]
1276
1112
 
1277
- dst_port, relay_dst_pack_id, continue_src_pack_id = data[ 9, 18 ].unpack( 'nQ>Q>' )
1113
+ dst_id, relay_dst_pack_id, continue_src_pack_id = data[ 9, 18 ].unpack( 'nQ>Q>' )
1278
1114
 
1279
- src_id = @tun_info[ :src_ids ][ dst_port ]
1115
+ src_id = @tun_info[ :src_ids ][ dst_id ]
1280
1116
  return unless src_id
1281
1117
 
1282
- src_ext = @tun_info[ :src_exts ][ src_id ]
1283
- return unless src_ext
1118
+ src = @tun_info[ :srcs ][ src_id ]
1119
+ return unless src
1120
+
1121
+ src_info = @src_infos[ src ]
1122
+ return unless src_info
1284
1123
 
1285
- # puts "debug2 got dest status"
1124
+ # puts "debug2 got dest status #{ Time.new }"
1286
1125
 
1287
- release_wmems( src_ext, continue_src_pack_id )
1126
+ # 消写后
1127
+ release_wmems( src_info, continue_src_pack_id )
1288
1128
 
1289
1129
  # 发miss
1290
- if !src_ext[ :src ].closed? && ( src_ext[ :continue_dst_pack_id ] < relay_dst_pack_id )
1130
+ if !src.closed? && ( src_info[ :continue_dst_pack_id ] < relay_dst_pack_id )
1291
1131
  ranges = []
1292
- curr_pack_id = src_ext[ :continue_dst_pack_id ] + 1
1132
+ ignored = false
1133
+ curr_pack_id = src_info[ :continue_dst_pack_id ] + 1
1293
1134
 
1294
- src_ext[ :pieces ].keys.sort.each do | pack_id |
1135
+ src_info[ :pieces ].keys.sort.each do | pack_id |
1295
1136
  if pack_id > curr_pack_id
1296
1137
  ranges << [ curr_pack_id, pack_id - 1 ]
1138
+
1139
+ if ranges.size >= MISS_RANGE_LIMIT
1140
+ puts "p#{ Process.pid } #{ Time.new } break add miss range at #{ pack_id }"
1141
+ ignored = true
1142
+ break
1143
+ end
1297
1144
  end
1298
1145
 
1299
1146
  curr_pack_id = pack_id + 1
1300
1147
  end
1301
1148
 
1302
- if curr_pack_id <= relay_dst_pack_id
1149
+ if !ignored && ( curr_pack_id <= relay_dst_pack_id )
1303
1150
  ranges << [ curr_pack_id, relay_dst_pack_id ]
1304
1151
  end
1305
1152
 
1306
- pack_count = 0
1307
- # puts "debug1 continue/relay #{ src_ext[ :continue_dst_pack_id ] }/#{ relay_dst_pack_id } send MISS #{ ranges.size }"
1153
+ # puts "debug1 continue/relay #{ src_info[ :continue_dst_pack_id ] }/#{ relay_dst_pack_id } send MISS #{ ranges.size }"
1154
+ idx = 0
1155
+ ranges = ranges.map{ | pack_id_begin, pack_id_end | [ pack_id_begin, pack_id_end ].pack( 'Q>Q>' ) }
1308
1156
 
1309
- ranges.each do | pack_id_begin, pack_id_end |
1310
- if pack_count >= BREAK_SEND_MISS
1311
- puts "p#{ Process.pid } #{ Time.new } break send miss at #{ pack_id_begin }"
1312
- break
1313
- end
1157
+ while idx < ranges.size
1158
+ chunk = ranges[ idx, MULTI_MISS_SIZE ].join
1159
+ data2 = [ [ 0, MULTI_MISS, dst_id ].pack( 'Q>Cn' ), chunk ].join
1160
+ send_data( tun, data2, @tun_info[ :tund_addr ] )
1161
+ idx += MULTI_MISS_SIZE
1162
+ end
1163
+ end
1164
+ when MULTI_MISS
1165
+ src_id, *ranges = data[ 9..-1 ].unpack( 'Q>Q>*' )
1166
+
1167
+ src = @tun_info[ :srcs ][ src_id ]
1168
+ return unless src
1169
+
1170
+ src_info = @src_infos[ src ]
1171
+ return unless src_info
1172
+
1173
+ return if ranges.empty? || ( ranges.size % 2 != 0 )
1314
1174
 
1315
- data2 = [ 0, MISS, dst_port, pack_id_begin, pack_id_end ].pack( 'Q>CnQ>Q>' )
1316
- add_tun_ctlmsg( data2 )
1317
- pack_count += ( pack_id_end - pack_id_begin + 1 )
1175
+ # puts "debug1 got multi miss #{ src_id } #{ ranges.size }"
1176
+
1177
+ idx = 0
1178
+
1179
+ while idx < ranges.size
1180
+ pack_id_begin, pack_id_end = ranges[ idx ], ranges[ idx + 1 ]
1181
+
1182
+ ( pack_id_begin..pack_id_end ).each do | pack_id |
1183
+ send_at = src_info[ :send_ats ][ pack_id ]
1184
+
1185
+ if send_at
1186
+ break if now - send_at < CHECK_STATUS_INTERVAL
1187
+ data2 = @tun_info[ :wmems ][ [ src_id, pack_id ] ]
1188
+
1189
+ if data2
1190
+ if send_data( tun, data2, @tun_info[ :tund_addr ] )
1191
+ src_info[ :last_continue_at ] = now
1192
+ end
1193
+ end
1194
+ end
1318
1195
  end
1196
+
1197
+ idx += 2
1319
1198
  end
1320
1199
  when MISS
1321
1200
  return if from_addr != @tun_info[ :tund_addr ]
1322
1201
 
1323
1202
  src_id, pack_id_begin, pack_id_end = data[ 9, 24 ].unpack( 'Q>Q>Q>' )
1324
1203
 
1325
- src_ext = @tun_info[ :src_exts ][ src_id ]
1326
- return unless src_ext
1204
+ src = @tun_info[ :srcs ][ src_id ]
1205
+ return unless src
1206
+
1207
+ src_info = @src_infos[ src ]
1208
+ return unless src_info
1327
1209
 
1328
1210
  ( pack_id_begin..pack_id_end ).each do | pack_id |
1329
- send_at = src_ext[ :send_ats ][ pack_id ]
1211
+ send_at = src_info[ :send_ats ][ pack_id ]
1330
1212
 
1331
1213
  if send_at
1332
- break if now - send_at < STATUS_INTERVAL
1333
- @tun_info[ :resendings ] << [ src_id, pack_id ]
1214
+ break if now - send_at < CHECK_STATUS_INTERVAL
1215
+ data2 = @tun_info[ :wmems ][ [ src_id, pack_id ] ]
1216
+
1217
+ if data2
1218
+ if send_data( tun, data2, @tun_info[ :tund_addr ] )
1219
+ src_info[ :last_continue_at ] = now
1220
+ end
1221
+ end
1334
1222
  end
1335
1223
  end
1336
-
1337
- add_write( tun )
1338
1224
  when FIN1
1339
1225
  return if from_addr != @tun_info[ :tund_addr ]
1340
1226
 
1341
- dst_port, biggest_dst_pack_id, continue_src_pack_id = data[ 9, 18 ].unpack( 'nQ>Q>' )
1227
+ dst_id, biggest_dst_pack_id, continue_src_pack_id = data[ 9, 18 ].unpack( 'nQ>Q>' )
1342
1228
 
1343
- src_id = @tun_info[ :src_ids ][ dst_port ]
1229
+ src_id = @tun_info[ :src_ids ][ dst_id ]
1344
1230
  return unless src_id
1345
1231
 
1346
- src_ext = @tun_info[ :src_exts ][ src_id ]
1347
- return unless src_ext
1232
+ src = @tun_info[ :srcs ][ src_id ]
1233
+ return unless src
1348
1234
 
1349
- # puts "debug1 got fin1 #{ dst_port } biggest dst pack #{ biggest_dst_pack_id } completed src pack #{ continue_src_pack_id }"
1350
- src_ext[ :is_dst_closed ] = true
1351
- src_ext[ :biggest_dst_pack_id ] = biggest_dst_pack_id
1352
- release_wmems( src_ext, continue_src_pack_id )
1235
+ src_info = @src_infos[ src ]
1236
+ return unless src_info
1353
1237
 
1354
- if ( biggest_dst_pack_id == src_ext[ :continue_dst_pack_id ] )
1238
+ # puts "debug1 got fin1 #{ dst_id } biggest dst pack #{ biggest_dst_pack_id } completed src pack #{ continue_src_pack_id }"
1239
+ src_info[ :is_dst_closed ] = true
1240
+ src_info[ :biggest_dst_pack_id ] = biggest_dst_pack_id
1241
+ release_wmems( src_info, continue_src_pack_id )
1242
+
1243
+ if ( biggest_dst_pack_id == src_info[ :continue_dst_pack_id ] )
1355
1244
  # puts "debug1 2-1. tun recv fin1 -> all traffic received ? -> close src after write"
1356
- set_is_closing( src_ext[ :src ] )
1245
+ set_is_closing( src )
1357
1246
  end
1358
1247
  when FIN2
1359
1248
  return if from_addr != @tun_info[ :tund_addr ]
1360
1249
 
1361
- dst_port = data[ 9, 2 ].unpack( 'n' ).first
1250
+ dst_id = data[ 9, 2 ].unpack( 'n' ).first
1362
1251
 
1363
- src_id = @tun_info[ :src_ids ][ dst_port ]
1252
+ src_id = @tun_info[ :src_ids ][ dst_id ]
1364
1253
  return unless src_id
1365
1254
 
1366
1255
  # puts "debug1 1-2. tun recv fin2 -> del src ext"
@@ -1382,14 +1271,18 @@ module Girl
1382
1271
 
1383
1272
  return if from_addr != @tun_info[ :tund_addr ]
1384
1273
 
1385
- dst_port = data[ 8, 2 ].unpack( 'n' ).first
1274
+ dst_id = data[ 8, 2 ].unpack( 'n' ).first
1386
1275
 
1387
- src_id = @tun_info[ :src_ids ][ dst_port ]
1276
+ src_id = @tun_info[ :src_ids ][ dst_id ]
1388
1277
  return unless src_id
1389
1278
 
1390
- src_ext = @tun_info[ :src_exts ][ src_id ]
1391
- return if src_ext.nil? || src_ext[ :src ].closed?
1392
- return if ( pack_id <= src_ext[ :continue_dst_pack_id ] ) || src_ext[ :pieces ].include?( pack_id )
1279
+ src = @tun_info[ :srcs ][ src_id ]
1280
+ return unless src
1281
+
1282
+ src_info = @src_infos[ src ]
1283
+ return unless src_info
1284
+
1285
+ return if ( pack_id <= src_info[ :continue_dst_pack_id ] ) || src_info[ :pieces ].include?( pack_id )
1393
1286
 
1394
1287
  data = data[ 10..-1 ]
1395
1288
  # puts "debug2 got pack #{ pack_id }"
@@ -1401,24 +1294,25 @@ module Girl
1401
1294
  end
1402
1295
 
1403
1296
  # 放进写前,跳号放碎片缓存
1404
- if pack_id - src_ext[ :continue_dst_pack_id ] == 1
1405
- while src_ext[ :pieces ].include?( pack_id + 1 )
1406
- data << src_ext[ :pieces ].delete( pack_id + 1 )
1297
+ if pack_id - src_info[ :continue_dst_pack_id ] == 1
1298
+ while src_info[ :pieces ].include?( pack_id + 1 )
1299
+ data << src_info[ :pieces ].delete( pack_id + 1 )
1407
1300
  pack_id += 1
1408
1301
  end
1409
1302
 
1410
- src_ext[ :continue_dst_pack_id ] = pack_id
1411
- src_ext[ :last_continue_at ] = now
1412
- add_src_wbuff( src_ext[ :src ], data )
1303
+ src_info[ :continue_dst_pack_id ] = pack_id
1304
+ src_info[ :last_continue_at ] = now
1305
+ add_src_wbuff( src, data )
1413
1306
  # puts "debug2 update continue dst pack #{ pack_id }"
1414
1307
 
1415
- # 接到流量,若对面已关闭,且流量正好收全,关闭src
1416
- if src_ext[ :is_dst_closed ] && ( pack_id == src_ext[ :biggest_dst_pack_id ] )
1308
+ # 若对面已关闭,且流量正好收全,关闭src
1309
+ if src_info[ :is_dst_closed ] && ( pack_id == src_info[ :biggest_dst_pack_id ] )
1417
1310
  # puts "debug1 2-2. tun recv traffic -> dst closed and all traffic received ? -> close src after write"
1418
- set_is_closing( src_ext[ :src ] )
1311
+ set_is_closing( src )
1419
1312
  end
1420
- else
1421
- src_ext[ :pieces ][ pack_id ] = data
1313
+ elsif !src_info[ :pieces ].include?( pack_id )
1314
+ src_info[ :pieces ][ pack_id ] = data
1315
+ src_info[ :last_continue_at ] = now
1422
1316
  end
1423
1317
  end
1424
1318