girl 0.88.0 → 0.93.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: 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