girl 0.87.0 → 0.91.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: 590ceead2e46e0803325aff199ec4fa4610a554f873ad58e91f83e8cba7bd4a9
4
- data.tar.gz: 3034b02ee1ddf592a67446d82a3f974f2439aef9f380f20b39c96aa943a4a7ab
3
+ metadata.gz: 2314c2bce1ab734d24fa40a8709c61af56cb35558652a4d25ba958c71b3a3bf3
4
+ data.tar.gz: 964ca3642b80f790b444d55db3869109fbb1c746953d2b7777d87f8eb0e17ad0
5
5
  SHA512:
6
- metadata.gz: 27d1dd5ef6d6f4d29c1916af5c10c8eb694e7cbf11f2f8518a6d4a3ebd0d368aa92518a9c5c0f91079f9291c67b1050be16db3f0154d7fb710f55d818ca75576
7
- data.tar.gz: ae5ab8293caf167146784342a93e059ef03a201dbd1a1a3df6bbe206321f95b13526e78713ca77903e3be44873ce02474c4d3260187fcd85c993206401fef586
6
+ metadata.gz: db5de1552c3841bf2f34c47c58e0f2c9789a6ed4101e3733654b1da9c557fccd97af0fb2f5c83212c3aa06ffc34630d7ab9e7798a0ebc41c6e41d32c0d742977
7
+ data.tar.gz: 3ea63129204abcadec92f7d77c7fa7222f700a819a9602c0a03e93134fbb86d3716a24dfbe387bb3e4e2b400fcb80af4c3cd92693ecec07b047c95d402a92ac2
@@ -1,33 +1,32 @@
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
- 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"
2
+ READ_SIZE = 1024 * 1024 # 一次读多少
3
+ WBUFF_LIMIT = 100 * 1024 * 1024 # 写前上限,超过上限暂停读
4
+ RESUME_BELOW = WBUFF_LIMIT / 2 # 降到多少以下恢复读
5
+ SEND_HELLO_COUNT = 10 # hello最多发几次
6
+ EXPIRE_AFTER = 300 # 多久没有新流量,过期
7
+ CHECK_EXPIRE_INTERVAL = 30 # 检查过期间隔
8
+ CHECK_RESUME_INTERVAL = 1 # 检查恢复读间隔
9
+ RESOLV_CACHE_EXPIRE = 300 # dns查询结果缓存多久过期
10
+ TUND_PORT = 1
11
+ HEARTBEAT = 2
12
+ A_NEW_SOURCE = 3
13
+ PAIRED = 4
14
+ DEST_STATUS = 5
15
+ SOURCE_STATUS = 6
16
+ MISS = 7
17
+ FIN1 = 8
18
+ GOT_FIN1 = 9
19
+ FIN2 = 10
20
+ GOT_FIN2 = 11
21
+ TUND_FIN = 12
22
+ TUN_FIN = 13
23
+ IP_CHANGED = 14
24
+ SINGLE_MISS = 15
25
+ RANGE_MISS = 16
26
+ CONTINUE = 17
27
+ IS_RESEND_READY = 18
28
+ RESEND_READY = 19
29
+ HTTP_OK = "HTTP/1.1 200 OK\r\n\r\n"
31
30
  # https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml
32
31
  RESERVED_ROUTE = <<EOF
33
32
  0.0.0.0/8
@@ -38,4 +37,14 @@ module Girl
38
37
  192.168.0.0/16
39
38
  255.255.255.255/32
40
39
  EOF
40
+ CONSTS = %w[
41
+ READ_SIZE
42
+ WBUFF_LIMIT
43
+ RESUME_BELOW
44
+ SEND_HELLO_COUNT
45
+ EXPIRE_AFTER
46
+ CHECK_EXPIRE_INTERVAL
47
+ CHECK_RESUME_INTERVAL
48
+ RESOLV_CACHE_EXPIRE
49
+ ]
41
50
  end
@@ -7,67 +7,45 @@ require 'ipaddr'
7
7
  require 'json'
8
8
  require 'socket'
9
9
 
10
- ##
10
+ =begin
11
11
  # Girl::Proxy - 代理服务,近端。
12
- #
13
- # 包结构
14
- # ======
15
- #
16
- # tun-proxyd:
17
- #
18
- # hello
19
- #
20
- # proxyd-tun:
21
- #
22
- # Q>: 0 ctlmsg -> C: 1 tund port -> n: tund port
23
- #
24
- # tun-tund:
25
- #
26
- # Q>: 0 ctlmsg -> C: 2 heartbeat -> C: random char
27
- # 3 a new source -> Q>: src id -> encoded destination address
28
- # 4 paired -> Q>: src id -> n: dst port
29
- # 5 dest status -> n: dst port -> Q>: biggest relayed dst pack id -> Q>: continue src pack id
30
- # 6 source status -> Q>: src id -> Q>: biggest relayed src pack id -> Q>: continue dst pack id
31
- # 7 miss -> Q>/n: src id / dst port -> Q>: pack id begin -> Q>: pack id end
32
- # 8 fin1 -> Q>/n: src id / dst port -> Q>: biggest src pack id / biggest dst pack id -> Q>: continue dst pack id / continue src pack id
33
- # 9 not use
34
- # 10 fin2 -> Q>/n: src id / dst port
35
- # 11 not use
36
- # 12 tund fin
37
- # 13 tun fin
38
- # 14 tun ip changed
39
- # 15 multi miss -> Q>/n: src id / dst port -> Q>: pack id begin -> Q>: pack id end -> Q>*
40
- #
41
- # Q>: 1+ pack_id -> Q>/n: src id / dst port -> traffic
42
- #
43
- # close logic
44
- # ===========
45
- #
46
- # 1-1. after close src -> dst closed ? no -> send fin1
47
- # 1-2. tun recv fin2 -> del src ext
48
- #
49
- # 2-1. tun recv fin1 -> all traffic received ? -> close src after write
50
- # 2-2. tun recv traffic -> dst closed and all traffic received ? -> close src after write
51
- # 2-3. after close src -> dst closed ? yes -> del src ext -> send fin2
52
- #
53
- # 3-1. after close dst -> src closed ? no -> send fin1
54
- # 3-2. tund recv fin2 -> del dst ext
55
- #
56
- # 4-1. tund recv fin1 -> all traffic received ? -> close dst after write
57
- # 4-2. tund recv traffic -> src closed and all traffic received ? -> close dst after write
58
- # 4-3. after close dst -> src closed ? yes -> del dst ext -> send fin2
59
- #
12
+
13
+ ## 包结构
14
+
15
+ tun-proxyd:
16
+
17
+ hello
18
+
19
+ proxyd-tun:
20
+
21
+ Q>: 0 ctlmsg -> C: 1 tund port -> n: tund port -> n: tcpd port
22
+
23
+ tun-tund:
24
+
25
+ Q>: 0 ctlmsg -> C: 2 heartbeat [not use]
26
+ 3 a new source -> Q>: src id -> encoded destination address
27
+ 4 paired -> Q>: src id -> n: dst id
28
+ 5 dest status [not use]
29
+ 6 source status [not use]
30
+ 7 miss [not use]
31
+ 8 fin1 [not use]
32
+ 9 confirm fin1 [not use]
33
+ 10 fin2 [not use]
34
+ 11 confirm fin2 [not use]
35
+ 12 tund fin
36
+ 13 tun fin
37
+ 14 tun ip changed
38
+ =end
39
+
60
40
  module Girl
61
41
  class Proxy
62
42
 
63
43
  def initialize( config_path = nil )
64
- unless config_path
44
+ unless config_path then
65
45
  config_path = File.expand_path( '../girl.conf.json', __FILE__ )
66
46
  end
67
47
 
68
- unless File.exist?( config_path )
69
- raise "missing config file #{ config_path }"
70
- end
48
+ raise "missing config file #{ config_path }" unless File.exist?( config_path )
71
49
 
72
50
  # {
73
51
  # "proxy_port": 6666, // 代理服务,近端(本地)端口
@@ -87,45 +65,37 @@ module Girl
87
65
  im = conf[ :im ]
88
66
  worker_count = conf[ :worker_count ]
89
67
 
90
- unless proxy_port
68
+ unless proxy_port then
91
69
  proxy_port = 6666
92
70
  end
93
71
 
94
- unless proxyd_host
95
- raise "missing proxyd host"
96
- end
72
+ raise "missing proxyd host" unless proxyd_host
97
73
 
98
- unless proxyd_port
74
+ unless proxyd_port then
99
75
  proxyd_port = 6060
100
76
  end
101
77
 
102
78
  directs = []
103
79
 
104
- if direct_path
105
- unless File.exist?( direct_path )
106
- raise "not found direct file #{ direct_path }"
107
- end
108
-
109
- directs = ( RESERVED_ROUTE.split( "\n" ) + IO.binread( direct_path ).split( "\n" ) ).map { | line | IPAddr.new( line.strip ) }
80
+ if direct_path then
81
+ raise "not found direct file #{ direct_path }" unless File.exist?( direct_path )
82
+ directs = ( RESERVED_ROUTE.split( "\n" ) + IO.binread( direct_path ).split( "\n" ) ).map{ | line | IPAddr.new( line.strip ) }
110
83
  end
111
84
 
112
85
  remotes = []
113
86
 
114
- if remote_path
115
- unless File.exist?( remote_path )
116
- raise "not found remote file #{ remote_path }"
117
- end
118
-
119
- remotes = IO.binread( remote_path ).split( "\n" ).map { | line | line.strip }
87
+ if remote_path then
88
+ raise "not found remote file #{ remote_path }" unless File.exist?( remote_path )
89
+ remotes = IO.binread( remote_path ).split( "\n" ).map{ | line | line.strip }
120
90
  end
121
91
 
122
- unless im
92
+ unless im then
123
93
  im = 'girl'
124
94
  end
125
95
 
126
96
  nprocessors = Etc.nprocessors
127
97
 
128
- if worker_count.nil? || worker_count <= 0 || worker_count > nprocessors
98
+ if worker_count.nil? || worker_count <= 0 || worker_count > nprocessors then
129
99
  worker_count = nprocessors
130
100
  end
131
101
 
@@ -139,29 +109,13 @@ module Girl
139
109
  puts "im #{ im }"
140
110
  puts "worker count #{ worker_count }"
141
111
 
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 |
112
+ len = CONSTS.map{ | name | name.size }.max
113
+
114
+ CONSTS.each do | name |
161
115
  puts "#{ name.gsub( '_', ' ' ).ljust( len ) } #{ Girl.const_get( name ) }"
162
116
  end
163
117
 
164
- if RUBY_PLATFORM.include?( 'linux' )
118
+ if RUBY_PLATFORM.include?( 'linux' ) then
165
119
  $0 = title
166
120
  workers = []
167
121
 
@@ -13,10 +13,10 @@ module Girl
13
13
  @mutex = Mutex.new
14
14
  @reads = []
15
15
  @writes = []
16
- @pause_srcs = []
17
- @roles = {} # sock => :dotr / :proxy / :src / :dst / :tun
16
+ @roles = {} # sock => :dotr / :proxy / :src / :dst / :tun / :stream
18
17
  @src_infos = {} # src => {}
19
18
  @dst_infos = {} # dst => {}
19
+ @stream_infos = {} # stream => {}
20
20
  @resolv_caches = {} # domain => [ ip, created_at ]
21
21
 
22
22
  dotr, dotw = IO.pipe
@@ -31,36 +31,40 @@ module Girl
31
31
  def looping
32
32
  puts "p#{ Process.pid } #{ Time.new } looping"
33
33
  loop_check_expire
34
- loop_check_status
34
+ loop_check_resume
35
35
 
36
36
  loop do
37
37
  rs, ws = IO.select( @reads, @writes )
38
38
 
39
39
  @mutex.synchronize do
40
- # 先写,再读
41
- ws.each do | sock |
42
- case @roles[ sock ]
43
- when :src
44
- write_src( sock )
45
- when :dst
46
- write_dst( sock )
47
- when :tun
48
- write_tun( sock )
49
- end
50
- end
51
-
40
+ # 先读,再写,避免打上关闭标记后读到
52
41
  rs.each do | sock |
53
42
  case @roles[ sock ]
54
- when :dotr
43
+ when :dotr then
55
44
  read_dotr( sock )
56
- when :proxy
45
+ when :proxy then
57
46
  read_proxy( sock )
58
- when :src
47
+ when :tun then
48
+ read_tun( sock )
49
+ when :src then
59
50
  read_src( sock )
60
- when :dst
51
+ when :dst then
61
52
  read_dst( sock )
62
- when :tun
63
- read_tun( sock )
53
+ when :stream then
54
+ read_stream( sock )
55
+ end
56
+ end
57
+
58
+ ws.each do | sock |
59
+ case @roles[ sock ]
60
+ when :tun then
61
+ write_tun( sock )
62
+ when :src then
63
+ write_src( sock )
64
+ when :dst then
65
+ write_dst( sock )
66
+ when :stream then
67
+ write_stream( sock )
64
68
  end
65
69
  end
66
70
  end
@@ -74,7 +78,7 @@ module Girl
74
78
  # quit!
75
79
  #
76
80
  def quit!
77
- if @tun && !@tun.closed? && @tun_info[ :tund_addr ]
81
+ if @tun && !@tun.closed? && @tun_info[ :tund_addr ] then
78
82
  # puts "debug1 send tun fin"
79
83
  data = [ 0, TUN_FIN ].pack( 'Q>C' )
80
84
  @tun.sendmsg( data, 0, @tun_info[ :tund_addr ] )
@@ -86,6 +90,276 @@ module Girl
86
90
 
87
91
  private
88
92
 
93
+ ##
94
+ # add ctlmsg
95
+ #
96
+ def add_ctlmsg( data, to_addr = nil )
97
+ unless to_addr then
98
+ to_addr = @tun_info[ :tund_addr ]
99
+ end
100
+
101
+ if to_addr then
102
+ @tun_info[ :ctlmsgs ] << [ data, to_addr ]
103
+ add_write( @tun )
104
+ end
105
+ end
106
+
107
+ ##
108
+ # add read
109
+ #
110
+ def add_read( sock, role = nil )
111
+ unless @reads.include?( sock ) then
112
+ @reads << sock
113
+
114
+ if role then
115
+ @roles[ sock ] = role
116
+ end
117
+ end
118
+ end
119
+
120
+ ##
121
+ # add src wbuff
122
+ #
123
+ def add_src_wbuff( src, data )
124
+ return if src.closed?
125
+ src_info = @src_infos[ src ]
126
+ src_info[ :wbuff ] << data
127
+ src_info[ :last_recv_at ] = Time.new
128
+ add_write( src )
129
+
130
+ if src_info[ :wbuff ].bytesize >= WBUFF_LIMIT then
131
+ dst = src_info[ :dst ]
132
+
133
+ if dst then
134
+ dst_info = @dst_infos[ dst ]
135
+ puts "p#{ Process.pid } #{ Time.new } pause dst #{ dst_info[ :domain ] }"
136
+ dst_info[ :paused ] = true
137
+ @reads.delete( dst )
138
+ else
139
+ stream = src_info[ :stream ]
140
+
141
+ if stream then
142
+ stream_info = @stream_infos[ stream ]
143
+ puts "p#{ Process.pid } #{ Time.new } pause stream #{ stream_info[ :domain ] }"
144
+ stream_info[ :paused ] = true
145
+ @reads.delete( stream )
146
+ end
147
+ end
148
+ end
149
+ end
150
+
151
+ ##
152
+ # add src wbuff socks5 conn reply
153
+ #
154
+ def add_src_wbuff_socks5_conn_reply( src )
155
+ # +----+-----+-------+------+----------+----------+
156
+ # |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT |
157
+ # +----+-----+-------+------+----------+----------+
158
+ # | 1 | 1 | X'00' | 1 | Variable | 2 |
159
+ # +----+-----+-------+------+----------+----------+
160
+ proxy_ip, proxy_port = @proxy_local_address.ip_unpack
161
+ data = [ [ 5, 0, 0, 1 ].pack( 'C4' ), IPAddr.new( proxy_ip ).hton, [ proxy_port ].pack( 'n' ) ].join
162
+ # puts "debug1 add src wbuff socks5 conn reply #{ data.inspect }"
163
+ add_src_wbuff( src, data )
164
+ end
165
+
166
+ ##
167
+ # add write
168
+ #
169
+ def add_write( sock )
170
+ unless @writes.include?( sock ) then
171
+ @writes << sock
172
+ end
173
+ end
174
+
175
+ ##
176
+ # close sock
177
+ #
178
+ def close_sock( sock )
179
+ sock.close
180
+ @reads.delete( sock )
181
+ @writes.delete( sock )
182
+ @roles.delete( sock )
183
+ end
184
+
185
+ ##
186
+ # close dst
187
+ #
188
+ def close_dst( dst )
189
+ # puts "debug1 close dst"
190
+ close_sock( dst )
191
+ @dst_infos.delete( dst )
192
+ end
193
+
194
+ ##
195
+ # close read src
196
+ #
197
+ def close_read_src( src )
198
+ return if src.closed?
199
+ # puts "debug1 close read src"
200
+ src.close_read
201
+ @reads.delete( src )
202
+
203
+ if src.closed? then
204
+ # puts "debug1 delete src info"
205
+ @roles.delete( src )
206
+ src_info = del_src_info( src )
207
+ else
208
+ src_info = @src_infos[ src ]
209
+ end
210
+
211
+ src_info[ :paused ] = false
212
+ src_info
213
+ end
214
+
215
+ ##
216
+ # close read dst
217
+ #
218
+ def close_read_dst( dst )
219
+ return if dst.closed?
220
+ # puts "debug1 close read dst"
221
+ dst.close_read
222
+ @reads.delete( dst )
223
+
224
+ if dst.closed? then
225
+ # puts "debug1 delete dst info"
226
+ @roles.delete( dst )
227
+ dst_info = @dst_infos.delete( dst )
228
+ else
229
+ dst_info = @dst_infos[ dst ]
230
+ end
231
+
232
+ dst_info
233
+ end
234
+
235
+ ##
236
+ # close read stream
237
+ #
238
+ def close_read_stream( stream )
239
+ return if stream.closed?
240
+ # puts "debug1 close read stream"
241
+ stream.close_read
242
+ @reads.delete( stream )
243
+
244
+ if stream.closed? then
245
+ # puts "debug1 delete stream info"
246
+ @roles.delete( stream )
247
+ stream_info = @stream_infos.delete( stream )
248
+ else
249
+ stream_info = @stream_infos[ stream ]
250
+ end
251
+
252
+ stream_info
253
+ end
254
+
255
+ ##
256
+ # close src
257
+ #
258
+ def close_src( src )
259
+ # puts "debug1 close src"
260
+ close_sock( src )
261
+ del_src_info( src )
262
+ end
263
+
264
+ ##
265
+ # close tun
266
+ #
267
+ def close_tun( tun )
268
+ # puts "debug1 close tun"
269
+ close_sock( tun )
270
+ @tun_info[ :srcs ].each{ | _, src | set_src_closing( src ) }
271
+ end
272
+
273
+ ##
274
+ # close write src
275
+ #
276
+ def close_write_src( src )
277
+ return if src.closed?
278
+ # puts "debug1 close write src"
279
+ src.close_write
280
+ @writes.delete( src )
281
+
282
+ if src.closed? then
283
+ # puts "debug1 delete src info"
284
+ @roles.delete( src )
285
+ src_info = del_src_info( src )
286
+ else
287
+ src_info = @src_infos[ src ]
288
+ end
289
+
290
+ src_info
291
+ end
292
+
293
+ ##
294
+ # close write dst
295
+ #
296
+ def close_write_dst( dst )
297
+ return if dst.closed?
298
+ # puts "debug1 close write dst"
299
+ dst.close_write
300
+ @writes.delete( dst )
301
+
302
+ if dst.closed? then
303
+ # puts "debug1 delete dst info"
304
+ @roles.delete( dst )
305
+ dst_info = @dst_infos.delete( dst )
306
+ else
307
+ dst_info = @dst_infos[ dst ]
308
+ end
309
+
310
+ dst_info
311
+ end
312
+
313
+ ##
314
+ # close write stream
315
+ #
316
+ def close_write_stream( stream )
317
+ return if stream.closed?
318
+ # puts "debug1 close write stream"
319
+ stream.close_write
320
+ @writes.delete( stream )
321
+
322
+ if stream.closed? then
323
+ # puts "debug1 delete stream info"
324
+ @roles.delete( stream )
325
+ stream_info = @stream_infos.delete( stream )
326
+ else
327
+ stream_info = @stream_infos[ stream ]
328
+ end
329
+
330
+ stream_info
331
+ end
332
+
333
+ ##
334
+ # deal with destination ip
335
+ #
336
+ def deal_with_destination_ip( src, ip_info )
337
+ src_info = @src_infos[ src ]
338
+
339
+ if ( @directs.any? { | direct | direct.include?( ip_info.ip_address ) } ) || ( ( src_info[ :destination_domain ] == @proxyd_host ) && ![ 80, 443 ].include?( src_info[ :destination_port ] ) ) then
340
+ # ip命中直连列表,或者访问远端非80/443端口,直连
341
+ # puts "debug1 #{ ip_info.inspect } hit directs"
342
+ new_a_dst( src, ip_info )
343
+ else
344
+ # 走远端
345
+ # puts "debug1 #{ ip_info.inspect } go tunnel"
346
+ set_src_proxy_type_tunnel( src )
347
+ end
348
+ end
349
+
350
+ ##
351
+ # del src info
352
+ #
353
+ def del_src_info( src )
354
+ src_info = @src_infos.delete( src )
355
+
356
+ if src_info[ :stream ] && @tun && !@tun.closed? then
357
+ @tun_info[ :srcs ].delete( src_info[ :id ] )
358
+ end
359
+
360
+ src_info
361
+ end
362
+
89
363
  ##
90
364
  # loop check expire
91
365
  #
@@ -95,127 +369,97 @@ module Girl
95
369
  sleep CHECK_EXPIRE_INTERVAL
96
370
 
97
371
  @mutex.synchronize do
98
- need_trigger = false
372
+ trigger = false
99
373
  now = Time.new
100
374
 
101
- if @tun && !@tun.closed?
102
- is_expired = @tun_info[ :last_recv_at ] ? ( now - @tun_info[ :last_recv_at ] > EXPIRE_AFTER ) : ( now - @tun_info[ :created_at ] > EXPIRE_NEW )
375
+ if @tun && !@tun.closed? then
376
+ last_recv_at = @tun_info[ :last_recv_at ] || @tun_info[ :created_at ]
377
+ last_sent_at = @tun_info[ :last_sent_at ] || @tun_info[ :created_at ]
103
378
 
104
- if is_expired
379
+ if @tun_info[ :srcs ].empty? && ( now - last_recv_at >= EXPIRE_AFTER ) && ( now - last_sent_at >= EXPIRE_AFTER ) then
105
380
  puts "p#{ Process.pid } #{ Time.new } expire tun"
106
- set_is_closing( @tun )
107
- need_trigger = true
108
- else
109
- data = [ 0, HEARTBEAT, rand( 128 ) ].pack( 'Q>CC' )
110
- # puts "debug1 #{ Time.new } heartbeat"
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
125
- end
126
- end
127
-
128
- if del_src_ids.any?
129
- @tun_info[ :srcs ].delete_if { | src_id, _ | del_src_ids.include?( src_id ) }
130
- end
381
+ set_tun_closing
382
+ trigger = true
131
383
  end
132
384
  end
133
385
 
134
386
  @src_infos.each do | src, src_info |
135
- if now - src_info[ :last_continue_at ] > EXPIRE_AFTER
136
- puts "p#{ Process.pid } #{ Time.new } expire src #{ src_info[ :destination_domain ] }"
137
- set_is_closing( src )
138
- need_trigger = true
139
- end
140
- end
387
+ last_recv_at = src_info[ :last_recv_at ] || src_info[ :created_at ]
388
+ last_sent_at = src_info[ :last_sent_at ] || src_info[ :created_at ]
141
389
 
142
- @dst_infos.each do | dst, dst_info |
143
- if now - dst_info[ :last_continue_at ] > EXPIRE_AFTER
144
- puts "p#{ Process.pid } #{ Time.new } expire dst #{ dst_info[ :domain ] }"
145
- set_is_closing( dst )
146
- need_trigger = true
390
+ if ( now - last_recv_at >= EXPIRE_AFTER ) && ( now - last_sent_at >= EXPIRE_AFTER ) then
391
+ puts "p#{ Process.pid } #{ Time.new } expire src #{ src_info[ :destination_domain ] }"
392
+ set_src_closing( src )
393
+ trigger = true
147
394
  end
148
395
  end
149
396
 
150
- if need_trigger
151
- next_tick
152
- end
397
+ next_tick if trigger
153
398
  end
154
399
  end
155
400
  end
156
401
  end
157
402
 
158
403
  ##
159
- # loop check status
404
+ # loop check resume
160
405
  #
161
- def loop_check_status
406
+ def loop_check_resume
162
407
  Thread.new do
163
408
  loop do
164
- sleep CHECK_STATUS_INTERVAL
409
+ sleep CHECK_RESUME_INTERVAL
165
410
 
166
411
  @mutex.synchronize do
167
- if @tun && !@tun.closed? && @tun_info[ :tund_addr ]
168
- if @tun_info[ :srcs ].any?
169
- now = Time.new
170
-
171
- @tun_info[ :srcs ].each do | src_id, src |
172
- src_info = @src_infos[ src ]
412
+ trigger = false
173
413
 
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 ] )
177
- end
178
- end
179
- end
414
+ @src_infos.select{ | _, src_info | src_info[ :paused ] }.each do | src, src_info |
415
+ dst = src_info[ :dst ]
180
416
 
181
- if @pause_srcs.any? && ( @tun_info[ :wmems ].size < RESUME_BELOW )
182
- @pause_srcs.each do | src |
183
- src_info = @src_infos[ src ]
417
+ if dst then
418
+ dst_info = @dst_infos[ dst ]
184
419
 
185
- if src_info
186
- puts "p#{ Process.pid } #{ Time.new } resume src #{ src_info[ :destination_domain ] }"
187
- add_read( src )
188
- end
420
+ if dst_info[ :wbuff ].size < RESUME_BELOW then
421
+ puts "p#{ Process.pid } #{ Time.new } dst.wbuff below #{ RESUME_BELOW }, resume src #{ src_info[ :destination_domain ] }"
422
+ resume_src( src )
423
+ trigger = true
189
424
  end
425
+ else
426
+ stream = src_info[ :stream ]
427
+ stream_info = @stream_infos[ stream ]
190
428
 
191
- @pause_srcs.clear
192
- next_tick
429
+ if stream_info[ :wbuff ].size < RESUME_BELOW then
430
+ puts "p#{ Process.pid } #{ Time.new } stream.wbuff below #{ RESUME_BELOW }, resume src #{ src_info[ :destination_domain ] }"
431
+ resume_src( src )
432
+ trigger = true
433
+ end
193
434
  end
194
435
  end
195
- end
196
- end
197
- end
198
- end
199
436
 
200
- def loop_send_hello
201
- data = @custom.hello
437
+ @dst_infos.select{ | _, dst_info | dst_info[ :paused ] }.each do | dst, dst_info |
438
+ src = dst_info[ :src ]
439
+ src_info = @src_infos[ src ]
202
440
 
203
- Thread.new do
204
- EXPIRE_NEW.times do | i |
205
- if @tun.closed? || @tun_info[ :tund_addr ]
206
- # puts "debug1 break loop send hello"
207
- break
208
- end
441
+ if src_info[ :wbuff ].size < RESUME_BELOW then
442
+ puts "p#{ Process.pid } #{ Time.new } src.wbuff below #{ RESUME_BELOW }, resume dst #{ dst_info[ :domain ] }"
443
+ dst_info[ :paused ] = false
444
+ add_read( dst )
445
+ trigger = true
446
+ end
447
+ end
209
448
 
210
- @mutex.synchronize do
211
- msg = i >= 1 ? "resend hello #{ i }" : "hello i'm tun"
212
- puts "p#{ Process.pid } #{ Time.new } #{ msg }"
213
- # puts "debug1 #{ data.inspect }"
449
+ @stream_infos.select{ | _, stream_info | stream_info[ :paused ] }.each do | stream, stream_info |
450
+ src = stream_info[ :src ]
451
+ src_info = @src_infos[ src ]
214
452
 
215
- send_data( @tun, data, @proxyd_addr )
216
- end
453
+ if src_info[ :wbuff ].size < RESUME_BELOW then
454
+ puts "p#{ Process.pid } #{ Time.new } src.wbuff below #{ RESUME_BELOW }, resume stream #{ stream_info[ :domain ] }"
455
+ stream_info[ :paused ] = false
456
+ add_read( stream )
457
+ trigger = true
458
+ end
459
+ end
217
460
 
218
- sleep CHECK_STATUS_INTERVAL
461
+ next_tick if trigger
462
+ end
219
463
  end
220
464
  end
221
465
  end
@@ -226,98 +470,141 @@ module Girl
226
470
  def loop_send_a_new_source( src )
227
471
  src_info = @src_infos[ src ]
228
472
 
229
- if src_info && @tun_info[ :tund_addr ]
473
+ if src_info then
230
474
  destination_domain = src_info[ :destination_domain ]
231
475
  destination_port = src_info[ :destination_port ]
232
476
  domain_port = [ destination_domain, destination_port ].join( ':' )
233
477
  data = [ [ 0, A_NEW_SOURCE, src_info[ :id ] ].pack( 'Q>CQ>' ), @custom.encode( domain_port ) ].join
234
478
 
235
479
  Thread.new do
236
- EXPIRE_NEW.times do | i |
237
- if src.closed? || src_info[ :dst_id ]
480
+ SEND_HELLO_COUNT.times do | i |
481
+ if @tun.nil? || @tun.closed? || src.closed? || src_info[ :stream ] then
238
482
  # puts "debug1 break loop send a new source #{ src_info[ :dst_port ] }"
239
483
  break
240
484
  end
241
485
 
242
486
  @mutex.synchronize do
243
- if i >= 1
487
+ if i >= 1 then
244
488
  puts "p#{ Process.pid } #{ Time.new } resend a new source #{ domain_port } #{ i }"
245
489
  end
246
490
 
247
- send_data( @tun, data, @tun_info[ :tund_addr ] )
491
+ add_ctlmsg( data )
492
+ next_tick
248
493
  end
249
494
 
250
- sleep CHECK_STATUS_INTERVAL
495
+ sleep 1
251
496
  end
252
497
  end
253
498
  end
254
499
  end
255
500
 
256
501
  ##
257
- # resolve domain
502
+ # new a dst
258
503
  #
259
- def resolve_domain( src, domain )
260
- if @remotes.any? { | remote | ( domain.size >= remote.size ) && ( domain[ ( remote.size * -1 )..-1 ] == remote ) }
261
- # puts "debug1 #{ domain } hit remotes"
262
- new_a_src_ext( src )
504
+ def new_a_dst( src, ip_info )
505
+ src_info = @src_infos[ src ]
506
+ domain = src_info[ :destination_domain ]
507
+ destination_addr = Socket.sockaddr_in( src_info[ :destination_port ], ip_info.ip_address )
508
+ dst = Socket.new( ip_info.ipv4? ? Socket::AF_INET : Socket::AF_INET6, Socket::SOCK_STREAM, 0 )
509
+ dst.setsockopt( Socket::SOL_TCP, Socket::TCP_NODELAY, 1 ) if RUBY_PLATFORM.include?( 'linux' )
510
+
511
+ begin
512
+ dst.connect_nonblock( destination_addr )
513
+ rescue IO::WaitWritable
514
+ # connect nonblock 必抛 wait writable
515
+ rescue Exception => e
516
+ puts "p#{ Process.pid } #{ Time.new } dst connect destination #{ domain } #{ src_info[ :destination_port ] } #{ ip_info.ip_address } #{ e.class }, close src"
517
+ set_src_closing( src )
263
518
  return
264
519
  end
265
520
 
266
- resolv_cache = @resolv_caches[ domain ]
521
+ # puts "debug1 a new dst #{ dst.local_address.inspect }"
522
+ local_port = dst.local_address.ip_port
523
+ dst_info = {
524
+ local_port: local_port, # 本地端口
525
+ src: src, # 对应src
526
+ domain: domain, # 目的地
527
+ wbuff: '', # 写前,从src读到的流量
528
+ paused: false, # 是否已暂停读
529
+ closing: false, # 准备关闭
530
+ closing_read: false, # 准备关闭读
531
+ closing_write: false # 准备关闭写
532
+ }
267
533
 
268
- if resolv_cache
269
- ip_info, created_at = resolv_cache
534
+ @dst_infos[ dst ] = dst_info
535
+ add_read( dst, :dst )
536
+ src_info[ :proxy_type ] = :direct
537
+ src_info[ :dst ] = dst
270
538
 
271
- if Time.new - created_at < RESOLV_CACHE_EXPIRE
272
- # puts "debug1 #{ domain } hit resolv cache #{ ip_info.inspect }"
273
- deal_with_destination_ip( src, ip_info )
274
- return
539
+ if src_info[ :proxy_proto ] == :http then
540
+ if src_info[ :is_connect ] then
541
+ # puts "debug1 add src.wbuff http ok"
542
+ add_src_wbuff( src, HTTP_OK )
543
+ elsif src_info[ :rbuff ] then
544
+ # puts "debug1 move src.rbuff to dst.wbuff"
545
+ dst_info[ :wbuff ] << src_info[ :rbuff ]
546
+ add_write( dst )
275
547
  end
276
-
277
- # puts "debug1 expire #{ domain } resolv cache"
278
- @resolv_caches.delete( domain )
548
+ elsif src_info[ :proxy_proto ] == :socks5 then
549
+ add_src_wbuff_socks5_conn_reply( src )
279
550
  end
551
+ end
552
+
553
+ ##
554
+ # new a stream
555
+ #
556
+ def new_a_stream( src_id, dst_id )
557
+ src = @tun_info[ :srcs ][ src_id ]
558
+ return if src.nil? || src.closed?
280
559
 
281
560
  src_info = @src_infos[ src ]
282
- src_info[ :proxy_type ] = :checking
561
+ return if src_info[ :dst_id ]
283
562
 
284
- Thread.new do
285
- begin
286
- ip_info = Addrinfo.ip( domain )
287
- rescue Exception => e
288
- puts "p#{ Process.pid } #{ Time.new } resolv #{ domain } #{ e.class }"
289
- end
563
+ if dst_id == 0 then
564
+ puts "p#{ Process.pid } #{ Time.new } remote dst already closed"
565
+ set_src_closing( src )
566
+ return
567
+ end
290
568
 
291
- @mutex.synchronize do
292
- if ip_info
293
- @resolv_caches[ domain ] = [ ip_info, Time.new ]
569
+ stream = Socket.new( Socket::AF_INET, Socket::SOCK_STREAM, 0 )
570
+ stream.setsockopt( Socket::SOL_TCP, Socket::TCP_NODELAY, 1 ) if RUBY_PLATFORM.include?( 'linux' )
294
571
 
295
- unless src.closed?
296
- puts "p#{ Process.pid } #{ Time.new } resolved #{ domain } #{ ip_info.ip_address }"
297
- deal_with_destination_ip( src, ip_info )
298
- end
299
- else
300
- set_is_closing( src )
301
- end
572
+ begin
573
+ stream.connect_nonblock( @tun_info[ :tcpd_addr ] )
574
+ rescue IO::WaitWritable
575
+ rescue Exception => e
576
+ puts "p#{ Process.pid } #{ Time.new } connect tcpd #{ e.class }"
577
+ return
578
+ end
302
579
 
303
- next_tick
304
- end
580
+ # puts "debug1 set stream.wbuff #{ dst_id }"
581
+ data = [ dst_id ].pack( 'n' )
582
+
583
+ unless src_info[ :rbuff ].empty? then
584
+ # puts "debug1 encode and move src.rbuff to stream.wbuff"
585
+ data << @custom.encode( src_info[ :rbuff ] )
305
586
  end
306
- end
307
587
 
308
- ##
309
- # deal with destination ip
310
- #
311
- def deal_with_destination_ip( src, ip_info )
312
- src_info = @src_infos[ src ]
588
+ domain = src_info[ :destination_domain ]
589
+ @stream_infos[ stream ] = {
590
+ src: src, # 对应src
591
+ domain: domain, # 目的地
592
+ wbuff: data, # 写前,写往远端streamd
593
+ paused: false # 是否已暂停读
594
+ }
313
595
 
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端口,直连
316
- # puts "debug1 #{ ip_info.inspect } hit directs"
317
- new_a_dst( src, ip_info )
318
- else
319
- # 走远端
320
- new_a_src_ext( src )
596
+ src_info[ :dst_id ] = dst_id
597
+ src_info[ :stream ] = stream
598
+ add_read( stream, :stream )
599
+ add_write( stream )
600
+
601
+ if src_info[ :proxy_proto ] == :http then
602
+ if src_info[ :is_connect ] then
603
+ # puts "debug1 add src.wbuff http ok"
604
+ add_src_wbuff( src, HTTP_OK )
605
+ end
606
+ elsif src_info[ :proxy_proto ] == :socks5 then
607
+ add_src_wbuff_socks5_conn_reply( src )
321
608
  end
322
609
  end
323
610
 
@@ -328,13 +615,13 @@ module Girl
328
615
  proxy = Socket.new( Socket::AF_INET, Socket::SOCK_STREAM, 0 )
329
616
  proxy.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEADDR, 1 )
330
617
 
331
- if RUBY_PLATFORM.include?( 'linux' )
618
+ if RUBY_PLATFORM.include?( 'linux' ) then
332
619
  proxy.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEPORT, 1 )
333
620
  proxy.setsockopt( Socket::SOL_TCP, Socket::TCP_NODELAY, 1 )
334
621
  end
335
622
 
336
623
  proxy.bind( Socket.sockaddr_in( proxy_port, '0.0.0.0' ) )
337
- proxy.listen( 511 )
624
+ proxy.listen( 127 )
338
625
  puts "p#{ Process.pid } #{ Time.new } proxy listen on #{ proxy_port }"
339
626
  add_read( proxy, :proxy )
340
627
  @proxy_local_address = proxy.local_address
@@ -350,450 +637,221 @@ module Girl
350
637
  tun_info = {
351
638
  port: port, # 端口
352
639
  pending_sources: [], # 还没配上tund,暂存的src
353
- wbuffs: [], # 写前 [ src_id, pack_id, data ]
354
- wmems: {}, # 写后 [ src_id, pack_id ] => data
640
+ ctlmsgs: [], # [ ctlmsg, to_addr ]
355
641
  tund_addr: nil, # tund地址
642
+ tcpd_addr: nil, # tcpd地址
356
643
  srcs: {}, # src_id => src
357
- src_ids: {}, # dst_id => src_id
358
- paused: false, # 是否暂停写
359
- resendings: [], # 重传队列 [ src_id, pack_id ]
360
644
  created_at: Time.new, # 创建时间
361
- last_recv_at: nil, # 上一次收到流量的时间,过期关闭
362
- is_closing: false # 是否准备关闭
645
+ last_recv_at: nil, # 上一次收到流量的时间
646
+ last_sent_at: nil, # 上一次发出流量的时间
647
+ closing: false # 是否准备关闭
363
648
  }
364
649
 
365
650
  @tun = tun
366
651
  @tun_info = tun_info
367
652
 
368
653
  add_read( tun, :tun )
369
- loop_send_hello
370
- end
371
-
372
- ##
373
- # new a dst
374
- #
375
- def new_a_dst( src, ip_info )
376
- src_info = @src_infos[ src ]
377
- domain = src_info[ :destination_domain ]
378
- destination_addr = Socket.sockaddr_in( src_info[ :destination_port ], ip_info.ip_address )
379
- dst = Socket.new( ip_info.ipv4? ? Socket::AF_INET : Socket::AF_INET6, Socket::SOCK_STREAM, 0 )
380
-
381
- if RUBY_PLATFORM.include?( 'linux' )
382
- dst.setsockopt( Socket::SOL_TCP, Socket::TCP_NODELAY, 1 )
383
- end
654
+ data = @custom.hello
384
655
 
385
- begin
386
- dst.connect_nonblock( destination_addr )
387
- rescue IO::WaitWritable
388
- # connect nonblock 必抛 wait writable,这里仅仅接一下,逻辑写外面,整齐
389
- rescue Exception => e
390
- puts "p#{ Process.pid } #{ Time.new } connect destination #{ e.class }, close src"
391
- set_is_closing( src )
392
- return
393
- end
656
+ Thread.new do
657
+ SEND_HELLO_COUNT.times do | i |
658
+ if @tun.nil? || @tun.closed? || @tun_info[ :tund_addr ] then
659
+ # puts "debug1 break loop send hello"
660
+ break
661
+ end
394
662
 
395
- # puts "debug1 a new dst #{ dst.local_address.inspect }"
396
- local_port = dst.local_address.ip_port
397
- @dst_infos[ dst ] = {
398
- local_port: local_port, # 本地端口
399
- src: src, # 对应src
400
- domain: domain, # 域名
401
- wbuff: '', # 写前
402
- last_continue_at: Time.new, # 上一次发生流量的时间
403
- is_closing: false # 是否准备关闭
404
- }
663
+ @mutex.synchronize do
664
+ msg = i >= 1 ? "resend hello #{ i }" : "hello i'm tun"
665
+ puts "p#{ Process.pid } #{ Time.new } #{ msg }"
666
+ # puts "debug1 #{ data.inspect }"
405
667
 
406
- add_read( dst, :dst )
407
- src_info[ :proxy_type ] = :direct
408
- src_info[ :dst ] = dst
668
+ add_ctlmsg( data, @proxyd_addr )
669
+ next_tick
670
+ end
409
671
 
410
- if src_info[ :proxy_proto ] == :http
411
- if src_info[ :is_connect ]
412
- # puts "debug1 add src wbuff http ok"
413
- add_src_wbuff( src, HTTP_OK )
414
- else
415
- # puts "debug1 add src rbuff to dst wbuff"
416
- add_dst_wbuff( dst, src_info[ :rbuff ] )
672
+ sleep 1
417
673
  end
418
- elsif src_info[ :proxy_proto ] == :socks5
419
- add_src_wbuff_socks5_conn_reply( src )
420
674
  end
421
675
  end
422
676
 
423
677
  ##
424
- # new a src ext
425
- #
426
- def new_a_src_ext( src )
427
- if @tun.nil? || @tun.closed?
428
- new_a_tun
429
- end
430
-
431
- src_info = @src_infos[ src ]
432
- src_info[ :proxy_type ] = :tunnel
433
- src_id = src_info[ :id ]
434
- @tun_info[ :srcs ][ src_id ] = src
435
-
436
- if @tun_info[ :tund_addr ]
437
- loop_send_a_new_source( src )
438
- else
439
- @tun_info[ :pending_sources ] << src
440
- end
441
- end
442
-
443
- ##
444
- # add src wbuff socks5 conn reply
445
- #
446
- def add_src_wbuff_socks5_conn_reply( src )
447
- # +----+-----+-------+------+----------+----------+
448
- # |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT |
449
- # +----+-----+-------+------+----------+----------+
450
- # | 1 | 1 | X'00' | 1 | Variable | 2 |
451
- # +----+-----+-------+------+----------+----------+
452
- proxy_ip, proxy_port = @proxy_local_address.ip_unpack
453
- data = [ [ 5, 0, 0, 1 ].pack( 'C4' ), IPAddr.new( proxy_ip ).hton, [ proxy_port ].pack( 'n' ) ].join
454
- # puts "debug1 add src wbuff socks5 conn reply #{ data.inspect }"
455
- add_src_wbuff( src, data )
456
- end
457
-
458
- ##
459
- # sub http request
460
- #
461
- def sub_http_request( data )
462
- lines = data.split( "\r\n" )
463
-
464
- if lines.empty?
465
- return [ data, nil ]
466
- end
467
-
468
- method, url, proto = lines.first.split( ' ' )
469
-
470
- if proto && url && proto[ 0, 4 ] == 'HTTP' && url[ 0, 7 ] == 'http://'
471
- domain_and_port = url.split( '/' )[ 2 ]
472
- data = data.sub( "http://#{ domain_and_port }", '' )
473
- # puts "debug1 subed #{ data.inspect } #{ domain_and_port }"
474
- end
475
-
476
- [ data, domain_and_port ]
477
- end
478
-
479
- ##
480
- # add src wbuff
481
- #
482
- def add_src_wbuff( src, data )
483
- src_info = @src_infos[ src ]
484
- src_info[ :wbuff ] << data
485
- add_write( src )
486
- end
487
-
488
- ##
489
- # add dst wbuff
490
- #
491
- def add_dst_wbuff( dst, data )
492
- dst_info = @dst_infos[ dst ]
493
- dst_info[ :wbuff ] << data
494
- add_write( dst )
495
- end
496
-
497
- ##
498
- # add read
678
+ # next tick
499
679
  #
500
- def add_read( sock, role = nil )
501
- if sock && !sock.closed? && !@reads.include?( sock )
502
- @reads << sock
503
-
504
- if role
505
- @roles[ sock ] = role
506
- end
507
- end
680
+ def next_tick
681
+ @dotw.write( '.' )
508
682
  end
509
683
 
510
684
  ##
511
- # add write
685
+ # resolve domain
512
686
  #
513
- def add_write( sock )
514
- if sock && !sock.closed? && !@writes.include?( sock )
515
- @writes << sock
687
+ def resolve_domain( src, domain )
688
+ if @remotes.any? { | remote | ( domain.size >= remote.size ) && ( domain[ ( remote.size * -1 )..-1 ] == remote ) } then
689
+ # puts "debug1 #{ domain } hit remotes"
690
+ set_src_proxy_type_tunnel( src )
691
+ return
516
692
  end
517
- end
518
693
 
519
- ##
520
- # add pause src
521
- #
522
- def add_pause_src( src )
523
- @reads.delete( src )
694
+ resolv_cache = @resolv_caches[ domain ]
524
695
 
525
- unless @pause_srcs.include?( src )
526
- @pause_srcs << src
527
- end
528
- end
696
+ if resolv_cache then
697
+ ip_info, created_at = resolv_cache
529
698
 
530
- ##
531
- # set is closing
532
- #
533
- def set_is_closing( sock )
534
- if sock && !sock.closed?
535
- role = @roles[ sock ]
536
- # puts "debug1 set #{ role.to_s } is closing"
537
-
538
- case role
539
- when :src
540
- src_info = @src_infos[ sock ]
541
- src_info[ :is_closing ] = true
542
- when :dst
543
- dst_info = @dst_infos[ sock ]
544
- dst_info[ :is_closing ] = true
545
- when :tun
546
- @tun_info[ :is_closing ] = true
699
+ if Time.new - created_at < RESOLV_CACHE_EXPIRE then
700
+ # puts "debug1 #{ domain } hit resolv cache #{ ip_info.inspect }"
701
+ deal_with_destination_ip( src, ip_info )
702
+ return
547
703
  end
548
704
 
549
- @reads.delete( sock )
550
- add_write( sock )
705
+ # puts "debug1 expire #{ domain } resolv cache"
706
+ @resolv_caches.delete( domain )
551
707
  end
552
- end
553
708
 
554
- ##
555
- # tunnel data
556
- #
557
- def tunnel_data( src, data )
558
709
  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
710
+ src_info[ :proxy_type ] = :checking
568
711
 
569
- if pack_id <= CONFUSE_UNTIL
570
- chunk = @custom.encode( chunk )
571
- # puts "debug1 encoded chunk #{ pack_id }"
712
+ Thread.new do
713
+ begin
714
+ ip_info = Addrinfo.ip( domain )
715
+ rescue Exception => e
716
+ puts "p#{ Process.pid } #{ Time.new } resolv #{ domain } #{ e.class }"
572
717
  end
573
718
 
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
-
592
- ##
593
- # send data
594
- #
595
- def send_data( tun, data, to_addr )
596
- unless to_addr
597
- return false
598
- end
599
-
600
- begin
601
- tun.sendmsg( data, 0, to_addr )
602
- rescue IO::WaitWritable, Errno::EINTR
603
- return false
604
- rescue Errno::EHOSTUNREACH, Errno::ENETUNREACH, Errno::ENETDOWN => e
605
- puts "#{ Time.new } #{ e.class }, close tun"
606
- close_tun( tun )
607
- return false
608
- end
609
-
610
- true
611
- end
612
-
613
- ##
614
- # close src
615
- #
616
- def close_src( src )
617
- # puts "debug1 close src"
618
- close_sock( src )
619
- @pause_srcs.delete( src )
620
- src_info = @src_infos[ src ]
719
+ @mutex.synchronize do
720
+ if ip_info then
721
+ @resolv_caches[ domain ] = [ ip_info, Time.new ]
621
722
 
622
- if src_info[ :proxy_type ] == :direct
623
- @src_infos.delete( src )
723
+ unless src.closed? then
724
+ puts "p#{ Process.pid } #{ Time.new } resolved #{ domain } #{ ip_info.ip_address }"
725
+ deal_with_destination_ip( src, ip_info )
726
+ end
727
+ else
728
+ set_src_closing( src )
729
+ end
624
730
 
625
- if src_info[ :dst ]
626
- set_is_closing( src_info[ :dst ] )
731
+ next_tick
627
732
  end
628
-
629
- return
630
- end
631
-
632
- if @tun.closed? || src_info[ :dst_id ].nil?
633
- @src_infos.delete( src )
634
- return
635
- end
636
-
637
- src_id = src_info[ :id ]
638
-
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>' )
646
733
  end
647
-
648
- send_data( @tun, data, @tun_info[ :tund_addr ] )
649
- end
650
-
651
- ##
652
- # close dst
653
- #
654
- def close_dst( dst )
655
- # puts "debug1 close dst"
656
- close_sock( dst )
657
- dst_info = @dst_infos.delete( dst )
658
- set_is_closing( dst_info[ :src ] )
659
734
  end
660
735
 
661
736
  ##
662
- # close tun
737
+ # resume src
663
738
  #
664
- def close_tun( tun )
665
- # puts "debug1 close tun"
666
- close_sock( tun )
667
- @tun_info[ :srcs ].each{ | _, src | set_is_closing( src ) }
668
- end
669
-
670
- ##
671
- # close sock
672
- #
673
- def close_sock( sock )
674
- sock.close
675
- @reads.delete( sock )
676
- @writes.delete( sock )
677
- @roles.delete( sock )
678
- end
679
-
680
- ##
681
- # del src ext
682
- #
683
- def del_src_ext( 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 )
686
-
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
693
- end
739
+ def resume_src( src )
740
+ src_info = @src_infos[ src ]
741
+ src_info[ :paused ] = false
742
+ add_read( src )
694
743
  end
695
744
 
696
745
  ##
697
- # release wmems
746
+ # set dst closing
698
747
  #
699
- def release_wmems( src_info, completed_pack_id )
700
- if completed_pack_id > src_info[ :completed_pack_id ]
701
- # puts "debug2 update completed pack #{ completed_pack_id }"
702
- pack_ids = src_info[ :send_ats ].keys.select { | pack_id | pack_id <= completed_pack_id }
703
-
704
- pack_ids.each do | pack_id |
705
- @tun_info[ :wmems ].delete( [ src_info[ :id ], pack_id ] )
706
- src_info[ :send_ats ].delete( pack_id )
707
- end
708
-
709
- src_info[ :completed_pack_id ] = completed_pack_id
710
- end
748
+ def set_dst_closing( dst )
749
+ return if dst.closed?
750
+ dst_info = @dst_infos[ dst ]
751
+ dst_info[ :closing ] = true
752
+ @reads.delete( dst )
753
+ add_write( dst )
711
754
  end
712
755
 
713
756
  ##
714
- # next tick
757
+ # set dst closing write
715
758
  #
716
- def next_tick
717
- @dotw.write( '.' )
759
+ def set_dst_closing_write( dst )
760
+ return if dst.closed?
761
+ dst_info = @dst_infos[ dst ]
762
+ dst_info[ :closing_write ] = true
763
+ add_write( dst )
718
764
  end
719
765
 
720
- ##
721
- # write src
722
- #
723
- def write_src( src )
724
- src_info = @src_infos[ src ]
725
-
726
- if src_info[ :is_closing ]
727
- close_src( src )
728
- return
729
- end
730
-
731
- data = src_info[ :wbuff ]
732
-
733
- if data.empty?
734
- @writes.delete( src )
735
- return
736
- end
737
-
738
- begin
739
- written = src.write_nonblock( data )
740
- rescue IO::WaitWritable, Errno::EINTR
741
- return
742
- rescue Exception => e
743
- close_src( src )
744
- return
745
- end
746
-
747
- # puts "debug2 write src #{ written }"
748
- data = data[ written..-1 ]
749
- src_info[ :wbuff ] = data
750
- src_info[ :last_continue_at ] = Time.new
766
+ ##
767
+ # set src is closing
768
+ #
769
+ def set_src_closing( src )
770
+ return if src.closed?
771
+ @reads.delete( src )
772
+ src_info = @src_infos[ src ]
773
+ src_info[ :closing ] = true
774
+ add_write( src )
751
775
  end
752
776
 
753
777
  ##
754
- # write dst
778
+ # set src closing write
755
779
  #
756
- def write_dst( dst )
757
- dst_info = @dst_infos[ dst ]
780
+ def set_src_closing_write( src )
781
+ return if src.closed?
782
+ src_info = @src_infos[ src ]
783
+ src_info[ :closing_write ] = true
784
+ add_write( src )
785
+ end
758
786
 
759
- if dst_info[ :is_closing ]
760
- close_dst( dst )
761
- return
787
+ ##
788
+ # set src proxy type tunnel
789
+ #
790
+ def set_src_proxy_type_tunnel( src )
791
+ if @tun.nil? || @tun.closed? then
792
+ new_a_tun
762
793
  end
763
794
 
764
- data = dst_info[ :wbuff ]
795
+ src_info = @src_infos[ src ]
796
+ src_info[ :proxy_type ] = :tunnel
797
+ src_id = src_info[ :id ]
798
+ @tun_info[ :srcs ][ src_id ] = src
765
799
 
766
- if data.empty?
767
- @writes.delete( dst )
768
- return
800
+ if @tun_info[ :tund_addr ] then
801
+ loop_send_a_new_source( src )
802
+ else
803
+ @tun_info[ :pending_sources ] << src
769
804
  end
805
+ end
770
806
 
771
- begin
772
- written = dst.write_nonblock( data )
773
- rescue IO::WaitWritable, Errno::EINTR
774
- return
775
- rescue Exception => e
776
- # puts "debug1 write dst #{ e.class }"
777
- close_dst( dst )
778
- return
779
- end
807
+ ##
808
+ # set stream closing
809
+ #
810
+ def set_stream_closing( stream )
811
+ return if stream.closed?
812
+ stream_info = @stream_infos[ stream ]
813
+ stream_info[ :closing ] = true
814
+ @reads.delete( stream )
815
+ add_write( stream )
816
+ end
780
817
 
781
- # puts "debug2 write dst #{ written }"
782
- data = data[ written..-1 ]
783
- dst_info[ :wbuff ] = data
784
- dst_info[ :last_continue_at ] = Time.new
818
+ ##
819
+ # set stream closing write
820
+ #
821
+ def set_stream_closing_write( stream )
822
+ return if stream.closed?
823
+ stream_info = @stream_infos[ stream ]
824
+ stream_info[ :closing_write ] = true
825
+ add_write( stream )
785
826
  end
786
827
 
787
828
  ##
788
- # write tun
829
+ # set tun is closing
789
830
  #
790
- def write_tun( tun )
791
- if @tun_info[ :is_closing ]
792
- close_tun( tun )
793
- return
831
+ def set_tun_closing
832
+ return if @tun.closed?
833
+ @tun_info[ :closing ] = true
834
+ @reads.delete( @tun )
835
+ add_write( @tun )
836
+ end
837
+
838
+ ##
839
+ # sub http request
840
+ #
841
+ def sub_http_request( data )
842
+ lines = data.split( "\r\n" )
843
+
844
+ return [ data, nil ] if lines.empty?
845
+
846
+ method, url, proto = lines.first.split( ' ' )
847
+
848
+ if proto && url && proto[ 0, 4 ] == 'HTTP' && url[ 0, 7 ] == 'http://' then
849
+ domain_port = url.split( '/' )[ 2 ]
850
+ data = data.sub( "http://#{ domain_port }", '' )
851
+ # puts "debug1 subed #{ data.inspect } #{ domain_port }"
794
852
  end
795
853
 
796
- @writes.delete( tun )
854
+ [ data, domain_port ]
797
855
  end
798
856
 
799
857
  ##
@@ -810,6 +868,7 @@ module Girl
810
868
  begin
811
869
  src, addrinfo = proxy.accept_nonblock
812
870
  rescue IO::WaitReadable, Errno::EINTR
871
+ print 'r'
813
872
  return
814
873
  end
815
874
 
@@ -817,30 +876,86 @@ module Girl
817
876
  # puts "debug1 accept a src #{ addrinfo.inspect } #{ src_id }"
818
877
 
819
878
  @src_infos[ src ] = {
820
- id: src_id, # id
821
- proxy_proto: :uncheck, # :uncheck / :http / :socks5
822
- proxy_type: :uncheck, # :uncheck / :checking / :direct / :tunnel / :negotiation
823
- dst: nil, # :direct的场合,对应的dst
824
- destination_domain: nil, # 目的地域名
825
- destination_port: nil, # 目的地端口
826
- biggest_pack_id: 0, # 最大包号码
827
- is_connect: true, # 代理协议是http的场合,是否是CONNECT
828
- rbuff: '', # 非CONNECT,dst或者远端dst未准备好,暂存流量
829
- wbuff: '', # 写前
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, # 完成到几(对面收到几)
837
- last_continue_at: Time.new, # 上一次发生流量的时间
838
- is_closing: false # 是否准备关闭
879
+ id: src_id, # id
880
+ proxy_proto: :uncheck, # :uncheck / :http / :socks5
881
+ proxy_type: :uncheck, # :uncheck / :checking / :direct / :tunnel / :negotiation
882
+ destination_domain: nil, # 目的地域名
883
+ destination_port: nil, # 目的地端口
884
+ is_connect: true, # 代理协议是http的场合,是否是CONNECT
885
+ rbuff: '', # 读到的流量
886
+ dst: nil, # :direct的场合,对应的dst
887
+ stream: nil, # :tunnel的场合,对应的stream
888
+ dst_id: nil, # 远端dst id
889
+ wbuff: '', # dst/stream读到的流量
890
+ created_at: Time.new, # 创建时间
891
+ last_recv_at: nil, # 上一次收到新流量(由dst收到,或者由stream收到)的时间
892
+ last_sent_at: nil, # 上一次发出流量(由dst发出,或者由stream发出)的时间
893
+ paused: false, # 是否已暂停读
894
+ closing: false, # 准备关闭
895
+ closing_read: false, # 准备关闭读
896
+ closing_write: false # 准备关闭写
839
897
  }
840
898
 
841
899
  add_read( src, :src )
842
900
  end
843
901
 
902
+ ##
903
+ # read tun
904
+ #
905
+ def read_tun( tun )
906
+ begin
907
+ data, addrinfo, rflags, *controls = tun.recvmsg_nonblock
908
+ rescue IO::WaitReadable, Errno::EINTR
909
+ print 'r'
910
+ return
911
+ end
912
+
913
+ from_addr = addrinfo.to_sockaddr
914
+ pack_id = data[ 0, 8 ].unpack( 'Q>' ).first
915
+ return if pack_id != 0
916
+
917
+ @tun_info[ :last_recv_at ] = Time.new
918
+ ctl_num = data[ 8 ].unpack( 'C' ).first
919
+
920
+ case ctl_num
921
+ when TUND_PORT then
922
+ return if ( from_addr != @proxyd_addr ) || @tun_info[ :tund_addr ]
923
+
924
+ tund_port, tcpd_port = data[ 9, 4 ].unpack( 'nn' )
925
+
926
+ puts "p#{ Process.pid } #{ Time.new } got tund port #{ tund_port }, #{ tcpd_port }"
927
+ @tun_info[ :tund_addr ] = Socket.sockaddr_in( tund_port, @proxyd_host )
928
+ @tun_info[ :tcpd_addr ] = Socket.sockaddr_in( tcpd_port, @proxyd_host )
929
+
930
+ if @tun_info[ :pending_sources ].any? then
931
+ puts "p#{ Process.pid } #{ Time.new } send pending sources"
932
+
933
+ @tun_info[ :pending_sources ].each do | src |
934
+ loop_send_a_new_source( src )
935
+ end
936
+
937
+ @tun_info[ :pending_sources ].clear
938
+ end
939
+ when PAIRED then
940
+ return if from_addr != @tun_info[ :tund_addr ]
941
+
942
+ src_id, dst_id = data[ 9, 10 ].unpack( 'Q>n' )
943
+
944
+ # puts "debug1 got paired #{ src_id } #{ dst_id }"
945
+ new_a_stream( src_id, dst_id )
946
+ when TUND_FIN then
947
+ return if from_addr != @tun_info[ :tund_addr ]
948
+
949
+ puts "p#{ Process.pid } #{ Time.new } recv tund fin"
950
+ set_tun_closing
951
+ when IP_CHANGED then
952
+ return if from_addr != @tun_info[ :tund_addr ]
953
+
954
+ puts "p#{ Process.pid } #{ Time.new } recv ip changed"
955
+ set_tun_closing
956
+ end
957
+ end
958
+
844
959
  ##
845
960
  # read src
846
961
  #
@@ -848,30 +963,38 @@ module Girl
848
963
  begin
849
964
  data = src.read_nonblock( READ_SIZE )
850
965
  rescue IO::WaitReadable, Errno::EINTR
966
+ print 'r'
851
967
  return
852
968
  rescue Exception => e
853
969
  # puts "debug1 read src #{ e.class }"
854
- set_is_closing( src )
970
+ src_info = close_read_src( src )
971
+ dst = src_info[ :dst ]
972
+
973
+ if dst then
974
+ set_dst_closing_write( dst )
975
+ else
976
+ stream = src_info[ :stream ]
977
+ set_stream_closing_write( stream ) if stream
978
+ end
979
+
855
980
  return
856
981
  end
857
982
 
858
- # puts "debug2 read src #{ data.inspect }"
859
983
  src_info = @src_infos[ src ]
860
- src_info[ :last_continue_at ] = Time.new
861
984
  proxy_type = src_info[ :proxy_type ]
862
985
 
863
986
  case proxy_type
864
- when :uncheck
865
- if data[ 0, 7 ] == 'CONNECT'
987
+ when :uncheck then
988
+ if data[ 0, 7 ] == 'CONNECT' then
866
989
  # puts "debug1 CONNECT"
867
- domain_and_port = data.split( "\r\n" )[ 0 ].split( ' ' )[ 1 ]
990
+ domain_port = data.split( "\r\n" )[ 0 ].split( ' ' )[ 1 ]
868
991
 
869
- unless domain_and_port
992
+ unless domain_port then
870
993
  puts "p#{ Process.pid } #{ Time.new } CONNECT miss domain"
871
- set_is_closing( src )
994
+ set_src_closing( src )
872
995
  return
873
996
  end
874
- elsif data[ 0 ].unpack( 'C' ).first == 5
997
+ elsif data[ 0 ].unpack( 'C' ).first == 5 then
875
998
  # puts "debug1 socks5 #{ data.inspect }"
876
999
 
877
1000
  # https://tools.ietf.org/html/rfc1928
@@ -884,9 +1007,9 @@ module Girl
884
1007
  nmethods = data[ 1 ].unpack( 'C' ).first
885
1008
  methods = data[ 2, nmethods ].unpack( 'C*' )
886
1009
 
887
- unless methods.include?( 0 )
1010
+ unless methods.include?( 0 ) then
888
1011
  puts "p#{ Process.pid } #{ Time.new } miss method 00"
889
- set_is_closing( src )
1012
+ set_src_closing( src )
890
1013
  return
891
1014
  end
892
1015
 
@@ -897,30 +1020,28 @@ module Girl
897
1020
  # +----+--------+
898
1021
  data2 = [ 5, 0 ].pack( 'CC' )
899
1022
  add_src_wbuff( src, data2 )
900
-
901
1023
  src_info[ :proxy_proto ] = :socks5
902
1024
  src_info[ :proxy_type ] = :negotiation
903
-
904
1025
  return
905
1026
  else
906
1027
  # puts "debug1 not CONNECT #{ data.inspect }"
907
1028
  host_line = data.split( "\r\n" ).find { | _line | _line[ 0, 6 ] == 'Host: ' }
908
1029
 
909
- unless host_line
1030
+ unless host_line then
910
1031
  # puts "debug1 not found host line"
911
- set_is_closing( src )
1032
+ set_src_closing( src )
912
1033
  return
913
1034
  end
914
1035
 
915
- data, domain_and_port = sub_http_request( data )
1036
+ data, domain_port = sub_http_request( data )
916
1037
 
917
- unless domain_and_port
1038
+ unless domain_port then
918
1039
  # puts "debug1 not HTTP"
919
- domain_and_port = host_line.split( ' ' )[ 1 ]
1040
+ domain_port = host_line.split( ' ' )[ 1 ]
920
1041
 
921
- unless domain_and_port
1042
+ unless domain_port then
922
1043
  puts "p#{ Process.pid } #{ Time.new } Host line miss domain"
923
- set_is_closing( src )
1044
+ set_src_closing( src )
924
1045
  return
925
1046
  end
926
1047
  end
@@ -929,7 +1050,7 @@ module Girl
929
1050
  src_info[ :rbuff ] << data
930
1051
  end
931
1052
 
932
- domain, port = domain_and_port.split( ':' )
1053
+ domain, port = domain_port.split( ':' )
933
1054
  port = port ? port.to_i : 80
934
1055
 
935
1056
  src_info[ :proxy_proto ] = :http
@@ -937,10 +1058,10 @@ module Girl
937
1058
  src_info[ :destination_port ] = port
938
1059
 
939
1060
  resolve_domain( src, domain )
940
- when :checking
941
- # puts "debug1 add src rbuff while checking #{ data.inspect }"
1061
+ when :checking then
1062
+ # puts "debug1 add src rbuff before resolved #{ data.inspect }"
942
1063
  src_info[ :rbuff ] << data
943
- when :negotiation
1064
+ when :negotiation then
944
1065
  # +----+-----+-------+------+----------+----------+
945
1066
  # |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT |
946
1067
  # +----+-----+-------+------+----------+----------+
@@ -949,10 +1070,10 @@ module Girl
949
1070
  # puts "debug1 negotiation #{ data.inspect }"
950
1071
  ver, cmd, rsv, atyp = data[ 0, 4 ].unpack( 'C4' )
951
1072
 
952
- if cmd == 1
1073
+ if cmd == 1 then
953
1074
  # puts "debug1 socks5 CONNECT"
954
1075
 
955
- if atyp == 1
1076
+ if atyp == 1 then
956
1077
  destination_host, destination_port = data[ 4, 6 ].unpack( 'Nn' )
957
1078
  destination_addr = Socket.sockaddr_in( destination_port, destination_host )
958
1079
  destination_addrinfo = Addrinfo.new( destination_addr )
@@ -961,10 +1082,10 @@ module Girl
961
1082
  src_info[ :destination_port ] = destination_port
962
1083
  # puts "debug1 IP V4 address #{ destination_addrinfo.inspect }"
963
1084
  deal_with_destination_ip( src, destination_addrinfo )
964
- elsif atyp == 3
1085
+ elsif atyp == 3 then
965
1086
  domain_len = data[ 4 ].unpack( 'C' ).first
966
1087
 
967
- if ( domain_len + 7 ) == data.bytesize
1088
+ if ( domain_len + 7 ) == data.bytesize then
968
1089
  domain = data[ 5, domain_len ]
969
1090
  port = data[ ( 5 + domain_len ), 2 ].unpack( 'n' ).first
970
1091
  src_info[ :destination_domain ] = domain
@@ -976,41 +1097,64 @@ module Girl
976
1097
  else
977
1098
  puts "p#{ Process.pid } #{ Time.new } socks5 cmd #{ cmd } not implement"
978
1099
  end
979
- when :tunnel
980
- if src_info[ :dst_id ]
981
- if @tun.closed?
982
- # puts "debug1 tun closed, close src"
983
- set_is_closing( src )
984
- return
985
- end
1100
+ when :tunnel then
1101
+ stream = src_info[ :stream ]
986
1102
 
987
- unless src_info[ :is_connect ]
988
- data, _ = sub_http_request( data )
989
- end
1103
+ if stream then
1104
+ unless stream.closed? then
1105
+ unless src_info[ :is_connect ] then
1106
+ data, _ = sub_http_request( data )
1107
+ end
990
1108
 
991
- tunnel_data( src, data )
1109
+ stream_info = @stream_infos[ stream ]
1110
+ data = @custom.encode( data )
1111
+ # puts "debug2 add stream.wbuff encoded #{ data.bytesize }"
1112
+ stream_info[ :wbuff ] << data
1113
+ add_write( stream )
1114
+
1115
+ if stream_info[ :wbuff ].bytesize >= WBUFF_LIMIT then
1116
+ puts "p#{ Process.pid } #{ Time.new } pause tunnel src #{ src_info[ :destination_domain ] }"
1117
+ src_info[ :paused ] = true
1118
+ @reads.delete( src )
1119
+ end
1120
+ end
992
1121
  else
993
- # puts "debug1 remote dst not ready, save data to src rbuff"
1122
+ # puts "debug1 stream not ready, save data to src.rbuff"
994
1123
  src_info[ :rbuff ] << data
1124
+
1125
+ if src_info[ :rbuff ].bytesize >= WBUFF_LIMIT then
1126
+ # puts "debug1 tunnel src.rbuff full"
1127
+ set_src_closing( src )
1128
+ end
995
1129
  end
996
- when :direct
1130
+ when :direct then
997
1131
  dst = src_info[ :dst ]
998
1132
 
999
- if dst
1000
- if dst.closed?
1001
- # puts "debug1 dst closed, close src"
1002
- set_is_closing( src )
1003
- return
1004
- end
1133
+ if dst then
1134
+ unless dst.closed? then
1135
+ unless src_info[ :is_connect ] then
1136
+ data, _ = sub_http_request( data )
1137
+ end
1005
1138
 
1006
- unless src_info[ :is_connect ]
1007
- data, _ = sub_http_request( data )
1008
- end
1139
+ dst_info = @dst_infos[ dst ]
1140
+ # puts "debug2 add dst.wbuff #{ data.bytesize }"
1141
+ dst_info[ :wbuff ] << data
1142
+ add_write( dst )
1009
1143
 
1010
- add_dst_wbuff( dst, data )
1144
+ if dst_info[ :wbuff ].bytesize >= WBUFF_LIMIT then
1145
+ puts "p#{ Process.pid } #{ Time.new } pause direct src #{ src_info[ :destination_domain ] }"
1146
+ src_info[ :paused ] = true
1147
+ @reads.delete( src )
1148
+ end
1149
+ end
1011
1150
  else
1012
- # puts "debug1 dst not ready, save data to src rbuff"
1151
+ # puts "debug1 dst not ready, save data to src.rbuff"
1013
1152
  src_info[ :rbuff ] << data
1153
+
1154
+ if src_info[ :rbuff ].bytesize >= WBUFF_LIMIT then
1155
+ # puts "debug1 direct src.rbuff full"
1156
+ set_src_closing( src )
1157
+ end
1014
1158
  end
1015
1159
  end
1016
1160
  end
@@ -1022,297 +1166,250 @@ module Girl
1022
1166
  begin
1023
1167
  data = dst.read_nonblock( READ_SIZE )
1024
1168
  rescue IO::WaitReadable, Errno::EINTR
1169
+ print 'r'
1025
1170
  return
1026
1171
  rescue Exception => e
1027
1172
  # puts "debug1 read dst #{ e.class }"
1028
- set_is_closing( dst )
1173
+ dst_info = close_read_dst( dst )
1174
+ src = dst_info[ :src ]
1175
+ set_src_closing_write( src )
1029
1176
  return
1030
1177
  end
1031
1178
 
1032
- # puts "debug2 read dst #{ data.inspect }"
1033
1179
  dst_info = @dst_infos[ dst ]
1034
- dst_info[ :last_continue_at ] = Time.new
1035
1180
  src = dst_info[ :src ]
1181
+ add_src_wbuff( src, data )
1182
+ end
1036
1183
 
1037
- if src.closed?
1038
- puts "p#{ Process.pid } #{ Time.new } src closed, close dst"
1039
- set_is_closing( dst )
1184
+ ##
1185
+ # read stream
1186
+ #
1187
+ def read_stream( stream )
1188
+ begin
1189
+ data = stream.read_nonblock( READ_SIZE )
1190
+ rescue IO::WaitReadable, Errno::EINTR
1191
+ print 'r'
1192
+ return
1193
+ rescue Exception => e
1194
+ # puts "debug1 read stream #{ e.class }"
1195
+ stream_info = close_read_stream( stream )
1196
+ src = stream_info[ :src ]
1197
+ set_src_closing_write( src )
1040
1198
  return
1041
1199
  end
1042
1200
 
1201
+ stream_info = @stream_infos[ stream ]
1202
+ src = stream_info[ :src ]
1203
+ data = @custom.decode( data )
1204
+ # puts "debug2 add src.wbuff decoded #{ data.bytesize }"
1043
1205
  add_src_wbuff( src, data )
1044
1206
  end
1045
1207
 
1046
1208
  ##
1047
- # read tun
1209
+ # write tun
1048
1210
  #
1049
- def read_tun( tun )
1050
- data, addrinfo, rflags, *controls = tun.recvmsg
1051
- from_addr = addrinfo.to_sockaddr
1052
- now = Time.new
1053
- @tun_info[ :last_recv_at ] = now
1054
- pack_id = data[ 0, 8 ].unpack( 'Q>' ).first
1055
-
1056
- if pack_id == 0
1057
- ctl_num = data[ 8 ].unpack( 'C' ).first
1058
-
1059
- case ctl_num
1060
- when TUND_PORT
1061
- return if ( from_addr != @proxyd_addr ) || @tun_info[ :tund_addr ]
1062
-
1063
- tund_port = data[ 9, 2 ].unpack( 'n' ).first
1064
-
1065
- puts "p#{ Process.pid } #{ Time.new } got tund port #{ tund_port }"
1066
- tund_addr = Socket.sockaddr_in( tund_port, @proxyd_host )
1067
- @tun_info[ :tund_addr ] = tund_addr
1068
-
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
1077
- end
1078
- when PAIRED
1079
- return if from_addr != @tun_info[ :tund_addr ]
1080
-
1081
- src_id, dst_id = data[ 9, 10 ].unpack( 'Q>n' )
1082
-
1083
- src = @tun_info[ :srcs ][ src_id ]
1084
- return if src.closed?
1085
-
1086
- src_info = @src_infos[ src ]
1087
- return if src_info[ :dst_id ]
1088
-
1089
- # puts "debug1 got paired #{ src_id } #{ dst_id }"
1090
-
1091
- if dst_id == 0
1092
- set_is_closing( src )
1093
- return
1094
- end
1095
-
1096
- src_info[ :dst_id ] = dst_id
1097
- @tun_info[ :src_ids ][ dst_id ] = src_id
1098
-
1099
- if src_info[ :proxy_proto ] == :http
1100
- if src_info[ :is_connect ]
1101
- # puts "debug1 add src wbuff http ok"
1102
- add_src_wbuff( src, HTTP_OK )
1103
- else
1104
- # puts "debug1 send src rbuff to tund"
1105
- tunnel_data( src, src_info[ :rbuff ] )
1106
- end
1107
- elsif src_info[ :proxy_proto ] == :socks5
1108
- add_src_wbuff_socks5_conn_reply( src )
1109
- end
1110
- when DEST_STATUS
1111
- return if from_addr != @tun_info[ :tund_addr ]
1112
-
1113
- dst_id, relay_dst_pack_id, continue_src_pack_id = data[ 9, 18 ].unpack( 'nQ>Q>' )
1114
-
1115
- src_id = @tun_info[ :src_ids ][ dst_id ]
1116
- return unless src_id
1117
-
1118
- src = @tun_info[ :srcs ][ src_id ]
1119
- return unless src
1120
-
1121
- src_info = @src_infos[ src ]
1122
- return unless src_info
1123
-
1124
- # puts "debug2 got dest status #{ Time.new }"
1125
-
1126
- # 消写后
1127
- release_wmems( src_info, continue_src_pack_id )
1128
-
1129
- # 发miss
1130
- if !src.closed? && ( src_info[ :continue_dst_pack_id ] < relay_dst_pack_id )
1131
- ranges = []
1132
- ignored = false
1133
- curr_pack_id = src_info[ :continue_dst_pack_id ] + 1
1134
-
1135
- src_info[ :pieces ].keys.sort.each do | pack_id |
1136
- if pack_id > curr_pack_id
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
1144
- end
1145
-
1146
- curr_pack_id = pack_id + 1
1147
- end
1148
-
1149
- if !ignored && ( curr_pack_id <= relay_dst_pack_id )
1150
- ranges << [ curr_pack_id, relay_dst_pack_id ]
1151
- end
1152
-
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>' ) }
1156
-
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
1211
+ def write_tun( tun )
1212
+ # 处理关闭
1213
+ if @tun_info[ :closing ] then
1214
+ close_tun( tun )
1215
+ return
1216
+ end
1169
1217
 
1170
- src_info = @src_infos[ src ]
1171
- return unless src_info
1218
+ now = Time.new
1172
1219
 
1173
- return if ranges.empty? || ( ranges.size % 2 != 0 )
1220
+ # 发ctlmsg
1221
+ while @tun_info[ :ctlmsgs ].any? do
1222
+ data, to_addr = @tun_info[ :ctlmsgs ].first
1174
1223
 
1175
- # puts "debug1 got multi miss #{ src_id } #{ ranges.size }"
1224
+ begin
1225
+ @tun.sendmsg_nonblock( data, 0, to_addr )
1226
+ rescue IO::WaitWritable, Errno::EINTR
1227
+ puts "p#{ Process.pid } #{ Time.new } wait send ctlmsg, left #{ @tun_info[ :ctlmsgs ].size }"
1228
+ @tun_info[ :last_sent_at ] = now
1229
+ return
1230
+ rescue Errno::EHOSTUNREACH, Errno::ENETUNREACH, Errno::ENETDOWN => e
1231
+ puts "p#{ Process.pid } #{ Time.new } sendmsg #{ e.class }, close tun"
1232
+ close_tun( tun )
1233
+ return
1234
+ end
1176
1235
 
1177
- idx = 0
1236
+ @tun_info[ :ctlmsgs ].shift
1237
+ end
1178
1238
 
1179
- while idx < ranges.size
1180
- pack_id_begin, pack_id_end = ranges[ idx ], ranges[ idx + 1 ]
1239
+ @tun_info[ :last_sent_at ] = now
1240
+ @writes.delete( tun )
1241
+ end
1181
1242
 
1182
- ( pack_id_begin..pack_id_end ).each do | pack_id |
1183
- send_at = src_info[ :send_ats ][ pack_id ]
1243
+ ##
1244
+ # write src
1245
+ #
1246
+ def write_src( src )
1247
+ return if src.closed?
1248
+ src_info = @src_infos[ src ]
1249
+ dst = src_info[ :dst ]
1184
1250
 
1185
- if send_at
1186
- break if now - send_at < CHECK_STATUS_INTERVAL
1187
- data2 = @tun_info[ :wmems ][ [ src_id, pack_id ] ]
1251
+ # 处理关闭
1252
+ if src_info[ :closing ] then
1253
+ close_src( src )
1188
1254
 
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
1195
- end
1255
+ if dst then
1256
+ close_read_dst( dst )
1257
+ set_dst_closing_write( dst )
1258
+ else
1259
+ stream = src_info[ :stream ]
1196
1260
 
1197
- idx += 2
1261
+ if stream then
1262
+ close_read_stream( stream )
1263
+ set_stream_closing_write( stream )
1198
1264
  end
1199
- when MISS
1200
- return if from_addr != @tun_info[ :tund_addr ]
1201
-
1202
- src_id, pack_id_begin, pack_id_end = data[ 9, 24 ].unpack( 'Q>Q>Q>' )
1203
-
1204
- src = @tun_info[ :srcs ][ src_id ]
1205
- return unless src
1206
-
1207
- src_info = @src_infos[ src ]
1208
- return unless src_info
1265
+ end
1209
1266
 
1210
- ( pack_id_begin..pack_id_end ).each do | pack_id |
1211
- send_at = src_info[ :send_ats ][ pack_id ]
1267
+ return
1268
+ end
1212
1269
 
1213
- if send_at
1214
- break if now - send_at < CHECK_STATUS_INTERVAL
1215
- data2 = @tun_info[ :wmems ][ [ src_id, pack_id ] ]
1270
+ # 处理wbuff
1271
+ data = src_info[ :wbuff ]
1216
1272
 
1217
- if data2
1218
- if send_data( tun, data2, @tun_info[ :tund_addr ] )
1219
- src_info[ :last_continue_at ] = now
1220
- end
1221
- end
1222
- end
1223
- end
1224
- when FIN1
1225
- return if from_addr != @tun_info[ :tund_addr ]
1273
+ # 写前为空,处理关闭写
1274
+ if data.empty? then
1275
+ if src_info[ :closing_write ] then
1276
+ close_write_src( src )
1277
+ else
1278
+ @writes.delete( src )
1279
+ end
1226
1280
 
1227
- dst_id, biggest_dst_pack_id, continue_src_pack_id = data[ 9, 18 ].unpack( 'nQ>Q>' )
1281
+ return
1282
+ end
1228
1283
 
1229
- src_id = @tun_info[ :src_ids ][ dst_id ]
1230
- return unless src_id
1284
+ # 写入
1285
+ begin
1286
+ written = src.write_nonblock( data )
1287
+ rescue IO::WaitWritable, Errno::EINTR
1288
+ print 'w'
1289
+ return
1290
+ rescue Exception => e
1291
+ # puts "debug1 write src #{ e.class }"
1292
+ close_write_src( src )
1231
1293
 
1232
- src = @tun_info[ :srcs ][ src_id ]
1233
- return unless src
1294
+ if dst then
1295
+ close_read_dst( dst )
1296
+ else
1297
+ stream = src_info[ :stream ]
1298
+ close_read_stream( stream ) if stream
1299
+ end
1234
1300
 
1235
- src_info = @src_infos[ src ]
1236
- return unless src_info
1301
+ return
1302
+ end
1237
1303
 
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 )
1304
+ # puts "debug2 written src #{ written }"
1305
+ data = data[ written..-1 ]
1306
+ src_info[ :wbuff ] = data
1307
+ end
1242
1308
 
1243
- if ( biggest_dst_pack_id == src_info[ :continue_dst_pack_id ] )
1244
- # puts "debug1 2-1. tun recv fin1 -> all traffic received ? -> close src after write"
1245
- set_is_closing( src )
1246
- end
1247
- when FIN2
1248
- return if from_addr != @tun_info[ :tund_addr ]
1309
+ ##
1310
+ # write dst
1311
+ #
1312
+ def write_dst( dst )
1313
+ return if dst.closed?
1314
+ dst_info = @dst_infos[ dst ]
1315
+ src = dst_info[ :src ]
1249
1316
 
1250
- dst_id = data[ 9, 2 ].unpack( 'n' ).first
1317
+ # 处理关闭
1318
+ if dst_info[ :closing ] then
1319
+ close_dst( dst )
1251
1320
 
1252
- src_id = @tun_info[ :src_ids ][ dst_id ]
1253
- return unless src_id
1321
+ if src then
1322
+ close_read_src( src )
1323
+ set_src_closing_write( src )
1324
+ end
1254
1325
 
1255
- # puts "debug1 1-2. tun recv fin2 -> del src ext"
1256
- del_src_ext( src_id )
1257
- when TUND_FIN
1258
- return if from_addr != @tun_info[ :tund_addr ]
1326
+ return
1327
+ end
1259
1328
 
1260
- puts "p#{ Process.pid } #{ Time.new } recv tund fin"
1261
- set_is_closing( tun )
1262
- when IP_CHANGED
1263
- return if from_addr != @tun_info[ :tund_addr ]
1329
+ data = dst_info[ :wbuff ]
1264
1330
 
1265
- puts "p#{ Process.pid } #{ Time.new } recv ip changed"
1266
- set_is_closing( tun )
1331
+ # 写前为空,处理关闭写
1332
+ if data.empty? then
1333
+ if dst_info[ :closing_write ] then
1334
+ close_write_dst( dst )
1335
+ else
1336
+ @writes.delete( dst )
1267
1337
  end
1268
1338
 
1269
1339
  return
1270
1340
  end
1271
1341
 
1272
- return if from_addr != @tun_info[ :tund_addr ]
1273
-
1274
- dst_id = data[ 8, 2 ].unpack( 'n' ).first
1342
+ # 写入
1343
+ begin
1344
+ written = dst.write_nonblock( data )
1345
+ rescue IO::WaitWritable, Errno::EINTR
1346
+ print 'w'
1347
+ return
1348
+ rescue Exception => e
1349
+ # puts "debug1 write dst #{ e.class }"
1350
+ close_write_dst( dst )
1351
+ close_read_src( src )
1352
+ return
1353
+ end
1275
1354
 
1276
- src_id = @tun_info[ :src_ids ][ dst_id ]
1277
- return unless src_id
1355
+ data = data[ written..-1 ]
1356
+ dst_info[ :wbuff ] = data
1278
1357
 
1279
- src = @tun_info[ :srcs ][ src_id ]
1280
- return unless src
1358
+ unless src.closed? then
1359
+ src_info = @src_infos[ src ]
1360
+ src_info[ :last_sent_at ] = Time.new
1361
+ end
1362
+ end
1281
1363
 
1282
- src_info = @src_infos[ src ]
1283
- return unless src_info
1364
+ ##
1365
+ # write stream
1366
+ #
1367
+ def write_stream( stream )
1368
+ return if stream.closed?
1369
+ stream_info = @stream_infos[ stream ]
1370
+ src = stream_info[ :src ]
1371
+
1372
+ # 处理关闭
1373
+ if stream_info[ :closing ] then
1374
+ close_stream( stream )
1375
+ close_read_src( src )
1376
+ set_src_closing_write( src )
1377
+ return
1378
+ end
1284
1379
 
1285
- return if ( pack_id <= src_info[ :continue_dst_pack_id ] ) || src_info[ :pieces ].include?( pack_id )
1380
+ data = stream_info[ :wbuff ]
1286
1381
 
1287
- data = data[ 10..-1 ]
1288
- # puts "debug2 got pack #{ pack_id }"
1382
+ # 写前为空,处理关闭写
1383
+ if data.empty? then
1384
+ if stream_info[ :closing_write ] then
1385
+ close_write_stream( stream )
1386
+ else
1387
+ @writes.delete( stream )
1388
+ end
1289
1389
 
1290
- if pack_id <= CONFUSE_UNTIL
1291
- # puts "debug2 #{ data.inspect }"
1292
- data = @custom.decode( data )
1293
- # puts "debug1 decoded pack #{ pack_id }"
1390
+ return
1294
1391
  end
1295
1392
 
1296
- # 放进写前,跳号放碎片缓存
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 )
1300
- pack_id += 1
1301
- end
1393
+ # 写入
1394
+ begin
1395
+ written = stream.write_nonblock( data )
1396
+ rescue IO::WaitWritable, Errno::EINTR
1397
+ print 'w'
1398
+ return
1399
+ rescue Exception => e
1400
+ # puts "debug1 write stream #{ e.class }"
1401
+ close_write_stream( stream )
1402
+ close_read_src( src )
1403
+ return
1404
+ end
1302
1405
 
1303
- src_info[ :continue_dst_pack_id ] = pack_id
1304
- src_info[ :last_continue_at ] = now
1305
- add_src_wbuff( src, data )
1306
- # puts "debug2 update continue dst pack #{ pack_id }"
1406
+ # puts "debug2 written stream #{ written }"
1407
+ data = data[ written..-1 ]
1408
+ stream_info[ :wbuff ] = data
1307
1409
 
1308
- # 若对面已关闭,且流量正好收全,关闭src
1309
- if src_info[ :is_dst_closed ] && ( pack_id == src_info[ :biggest_dst_pack_id ] )
1310
- # puts "debug1 2-2. tun recv traffic -> dst closed and all traffic received ? -> close src after write"
1311
- set_is_closing( src )
1312
- end
1313
- elsif !src_info[ :pieces ].include?( pack_id )
1314
- src_info[ :pieces ][ pack_id ] = data
1315
- src_info[ :last_continue_at ] = now
1410
+ unless src.closed? then
1411
+ src_info = @src_infos[ src ]
1412
+ src_info[ :last_sent_at ] = Time.new
1316
1413
  end
1317
1414
  end
1318
1415