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