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