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