girl 0.87.0 → 0.91.0

This diff has not been reviewed by any users.
Sign up to get free protection for your applications and to get access to all the features.
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 }"