girl 0.50.0 → 0.50.1

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.

@@ -1,169 +1,169 @@
1
- require 'girl/hex'
2
- require 'girl/version'
3
- require 'socket'
4
-
5
- ##
6
- # Girl::Resolvd - dns查询得到正确的ip。远端。
7
- #
8
- module Girl
9
- class Resolvd
10
-
11
- def initialize( port = 7070, nameservers = [] )
12
- @hex = Girl::Hex.new
13
- @mutex = Mutex.new
14
- @reads = []
15
- @writes = []
16
- @roles = {} # sock => :ctlr / :resolvd / :pub
17
- @infos = {} # resolvd => {}
18
- @socks = {} # sock => sock_id
19
- @sock_ids = {} # sock_id => sock
20
-
21
- resolvd = Socket.new( Socket::AF_INET, Socket::SOCK_DGRAM, 0 )
22
- resolvd.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEPORT, 1 )
23
- resolvd.bind( Socket.sockaddr_in( port, '0.0.0.0' ) )
24
- puts "resolvd bound on #{ port } #{ Time.new }"
25
-
26
- nameservers = nameservers.select{ | ns | Addrinfo.udp( ns, 53 ).ipv4? }
27
-
28
- resolvd_info = {
29
- resolv_addrs: {}, # resolv_addr => pub
30
- pubs: {}, # pub => src_addr
31
- last_recv_ats: {}, # pub => now
32
- pubd_addrs: nameservers.map{ | ns | Socket.sockaddr_in( 53, ns ) }
33
- }
34
-
35
- @resolvd = resolvd
36
- @resolvd_info = resolvd_info
37
- @roles[ resolvd ] = :resolvd
38
- @infos[ resolvd ] = resolvd_info
39
- @reads << resolvd
40
-
41
- ctlr, ctlw = IO.pipe
42
- @ctlw = ctlw
43
- @roles[ ctlr ] = :ctlr
44
- @reads << ctlr
45
- end
46
-
47
- def looping
48
- loop_expire
49
-
50
- loop do
51
- rs, ws = IO.select( @reads, @writes )
52
-
53
- @mutex.synchronize do
54
- rs.each do | sock |
55
- case @roles[ sock ]
56
- when :ctlr
57
- read_ctlr( sock )
58
- when :resolvd
59
- read_resolvd( sock )
60
- when :pub
61
- read_pub( sock )
62
- end
63
- end
64
-
65
- ws.each do | sock |
66
- close_sock( sock )
67
- end
68
- end
69
- end
70
- end
71
-
72
- def quit!
73
- exit
74
- end
75
-
76
- private
77
-
78
- def read_ctlr( ctlr )
79
- sock_id = ctlr.read( 8 ).unpack( 'Q>' ).first
80
- sock = @sock_ids[ sock_id ]
81
-
82
- if sock
83
- # puts "debug expire pub #{ sock_id } #{ Time.new }"
84
-
85
- unless @writes.include?( sock )
86
- @writes << sock
87
- end
88
- end
89
- end
90
-
91
- def read_resolvd( resolvd )
92
- data, addrinfo, rflags, *controls = resolvd.recvmsg
93
- return if data.size <= 12
94
-
95
- data = @hex.decode( data )
96
- info = @infos[ resolvd ]
97
- resolv_addr = addrinfo.to_sockaddr
98
- pub = info[ :resolv_addrs ][ resolv_addr ]
99
-
100
- unless pub
101
- pub = Socket.new( Socket::AF_INET, Socket::SOCK_DGRAM, 0 )
102
- pub.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEPORT, 1 )
103
- pub.bind( Socket.sockaddr_in( 0, '0.0.0.0' ) )
104
- # puts "debug a new pub bound on #{ pub.local_address.ip_unpack.last } #{ Time.new }"
105
-
106
- @roles[ pub ] = :pub
107
- pub_id = @hex.gen_random_num
108
- @socks[ pub ] = pub_id
109
- @sock_ids[ pub_id ] = pub
110
- @reads << pub
111
-
112
- info[ :resolv_addrs ][ resolv_addr ] = pub
113
- info[ :pubs ][ pub ] = resolv_addr
114
- info[ :last_recv_ats ][ pub ] = Time.new
115
- end
116
-
117
- info[ :pubd_addrs ].each do | pubd_addr |
118
- pub.sendmsg( data, 0, pubd_addr )
119
- end
120
- end
121
-
122
- def read_pub( pub )
123
- data, addrinfo, rflags, *controls = pub.recvmsg
124
- return if data.size <= 12
125
-
126
- resolv_addr = @resolvd_info[ :pubs ][ pub ]
127
- return unless resolv_addr
128
-
129
- # puts "debug pub recvmsg #{ data.inspect }"
130
- @resolvd_info[ :last_recv_ats ][ pub ] = Time.new
131
- data = @hex.encode( data )
132
- # puts "debug resolvd sendmsg #{ data.inspect }"
133
- @resolvd.sendmsg( data, 0, resolv_addr )
134
- end
135
-
136
- def close_sock( sock )
137
- sock.close
138
- @reads.delete( sock )
139
- @writes.delete( sock )
140
- @roles.delete( sock )
141
- sock_id = @socks.delete( sock )
142
- @sock_ids.delete( sock_id )
143
- @resolvd_info[ :last_recv_ats ].delete( sock )
144
- resolv_addr = @resolvd_info[ :pubs ].delete( sock )
145
- @resolvd_info[ :resolv_addrs ].delete( resolv_addr )
146
- end
147
-
148
- def loop_expire
149
- Thread.new do
150
- loop do
151
- sleep 60
152
-
153
- @mutex.synchronize do
154
- now = Time.new
155
- pubs = @resolvd_info[ :pubs ].keys
156
-
157
- pubs.each do | pub |
158
- if now - @resolvd_info[ :last_recv_ats ][ pub ] > 5
159
- pub_id = @socks[ pub ]
160
- @ctlw.write( [ pub_id ].pack( 'Q>' ) )
161
- end
162
- end
163
- end
164
- end
165
- end
166
- end
167
-
168
- end
169
- end
1
+ require 'girl/hex'
2
+ require 'girl/version'
3
+ require 'socket'
4
+
5
+ ##
6
+ # Girl::Resolvd - dns查询得到正确的ip。远端。
7
+ #
8
+ module Girl
9
+ class Resolvd
10
+
11
+ def initialize( port = 7070, nameservers = [] )
12
+ @hex = Girl::Hex.new
13
+ @mutex = Mutex.new
14
+ @reads = []
15
+ @writes = []
16
+ @roles = {} # sock => :ctlr / :resolvd / :pub
17
+ @infos = {} # resolvd => {}
18
+ @socks = {} # sock => sock_id
19
+ @sock_ids = {} # sock_id => sock
20
+
21
+ resolvd = Socket.new( Socket::AF_INET, Socket::SOCK_DGRAM, 0 )
22
+ resolvd.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEPORT, 1 )
23
+ resolvd.bind( Socket.sockaddr_in( port, '0.0.0.0' ) )
24
+ puts "resolvd bound on #{ port } #{ Time.new }"
25
+
26
+ nameservers = nameservers.select{ | ns | Addrinfo.udp( ns, 53 ).ipv4? }
27
+
28
+ resolvd_info = {
29
+ resolv_addrs: {}, # resolv_addr => pub
30
+ pubs: {}, # pub => src_addr
31
+ last_recv_ats: {}, # pub => now
32
+ pubd_addrs: nameservers.map{ | ns | Socket.sockaddr_in( 53, ns ) }
33
+ }
34
+
35
+ @resolvd = resolvd
36
+ @resolvd_info = resolvd_info
37
+ @roles[ resolvd ] = :resolvd
38
+ @infos[ resolvd ] = resolvd_info
39
+ @reads << resolvd
40
+
41
+ ctlr, ctlw = IO.pipe
42
+ @ctlw = ctlw
43
+ @roles[ ctlr ] = :ctlr
44
+ @reads << ctlr
45
+ end
46
+
47
+ def looping
48
+ loop_expire
49
+
50
+ loop do
51
+ rs, ws = IO.select( @reads, @writes )
52
+
53
+ @mutex.synchronize do
54
+ rs.each do | sock |
55
+ case @roles[ sock ]
56
+ when :ctlr
57
+ read_ctlr( sock )
58
+ when :resolvd
59
+ read_resolvd( sock )
60
+ when :pub
61
+ read_pub( sock )
62
+ end
63
+ end
64
+
65
+ ws.each do | sock |
66
+ close_sock( sock )
67
+ end
68
+ end
69
+ end
70
+ end
71
+
72
+ def quit!
73
+ exit
74
+ end
75
+
76
+ private
77
+
78
+ def read_ctlr( ctlr )
79
+ sock_id = ctlr.read( 8 ).unpack( 'Q>' ).first
80
+ sock = @sock_ids[ sock_id ]
81
+
82
+ if sock
83
+ # puts "debug expire pub #{ sock_id } #{ Time.new }"
84
+
85
+ unless @writes.include?( sock )
86
+ @writes << sock
87
+ end
88
+ end
89
+ end
90
+
91
+ def read_resolvd( resolvd )
92
+ data, addrinfo, rflags, *controls = resolvd.recvmsg
93
+ return if data.size <= 12
94
+
95
+ data = @hex.decode( data )
96
+ info = @infos[ resolvd ]
97
+ resolv_addr = addrinfo.to_sockaddr
98
+ pub = info[ :resolv_addrs ][ resolv_addr ]
99
+
100
+ unless pub
101
+ pub = Socket.new( Socket::AF_INET, Socket::SOCK_DGRAM, 0 )
102
+ pub.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEPORT, 1 )
103
+ pub.bind( Socket.sockaddr_in( 0, '0.0.0.0' ) )
104
+ # puts "debug a new pub bound on #{ pub.local_address.ip_unpack.last } #{ Time.new }"
105
+
106
+ @roles[ pub ] = :pub
107
+ pub_id = @hex.gen_random_num
108
+ @socks[ pub ] = pub_id
109
+ @sock_ids[ pub_id ] = pub
110
+ @reads << pub
111
+
112
+ info[ :resolv_addrs ][ resolv_addr ] = pub
113
+ info[ :pubs ][ pub ] = resolv_addr
114
+ info[ :last_recv_ats ][ pub ] = Time.new
115
+ end
116
+
117
+ info[ :pubd_addrs ].each do | pubd_addr |
118
+ pub.sendmsg( data, 0, pubd_addr )
119
+ end
120
+ end
121
+
122
+ def read_pub( pub )
123
+ data, addrinfo, rflags, *controls = pub.recvmsg
124
+ return if data.size <= 12
125
+
126
+ resolv_addr = @resolvd_info[ :pubs ][ pub ]
127
+ return unless resolv_addr
128
+
129
+ # puts "debug pub recvmsg #{ data.inspect }"
130
+ @resolvd_info[ :last_recv_ats ][ pub ] = Time.new
131
+ data = @hex.encode( data )
132
+ # puts "debug resolvd sendmsg #{ data.inspect }"
133
+ @resolvd.sendmsg( data, 0, resolv_addr )
134
+ end
135
+
136
+ def close_sock( sock )
137
+ sock.close
138
+ @reads.delete( sock )
139
+ @writes.delete( sock )
140
+ @roles.delete( sock )
141
+ sock_id = @socks.delete( sock )
142
+ @sock_ids.delete( sock_id )
143
+ @resolvd_info[ :last_recv_ats ].delete( sock )
144
+ resolv_addr = @resolvd_info[ :pubs ].delete( sock )
145
+ @resolvd_info[ :resolv_addrs ].delete( resolv_addr )
146
+ end
147
+
148
+ def loop_expire
149
+ Thread.new do
150
+ loop do
151
+ sleep 60
152
+
153
+ @mutex.synchronize do
154
+ now = Time.new
155
+ pubs = @resolvd_info[ :pubs ].keys
156
+
157
+ pubs.each do | pub |
158
+ if now - @resolvd_info[ :last_recv_ats ][ pub ] > 5
159
+ pub_id = @socks[ pub ]
160
+ @ctlw.write( [ pub_id ].pack( 'Q>' ) )
161
+ end
162
+ end
163
+ end
164
+ end
165
+ end
166
+ end
167
+
168
+ end
169
+ end
@@ -1,1014 +1,1014 @@
1
- require 'girl/head'
2
- require 'girl/hex'
3
- require 'girl/version'
4
- require 'socket'
5
-
6
- ##
7
- # Girl::Tun - tcp流量正常的到达目的地。近端。
8
- #
9
- # usage
10
- # =====
11
- #
12
- # Girl::Tund.new( 9090 ).looping # 远端
13
- #
14
- # Girl::Tun.new( 'your.server.ip', 9090, 1919 ).looping # 近端
15
- #
16
- # dig +short www.google.com @127.0.0.1 -p1717 # dig with girl/resolv, got 216.58.217.196
17
- #
18
- # iptables -t nat -A OUTPUT -p tcp -d 216.58.217.196 -j REDIRECT --to-ports 1919
19
- #
20
- # curl https://www.google.com/
21
- #
22
- # 包结构
23
- # ======
24
- #
25
- # 流量打包成udp,在tun-tund之间传输,包结构:
26
- #
27
- # Q>: 1+ source/dest_id -> Q>: pack_id -> traffic
28
- # 0 ctlmsg -> C: 1 tund port -> n: tund port
29
- # 2 heartbeat -> C: random char
30
- # 3 a new source -> Q>nnN: source_id dst_family dst_port dst_host
31
- # 4 paired -> Q>Q>: source_id dest_id
32
- # 5 dest status -> Q>Q>Q>: dest_id biggest_dest_pack_id continue_source_pack_id
33
- # 6 source status -> Q>Q>Q>: source_id biggest_source_pack_id continue_dest_pack_id
34
- # 7 miss -> Q>Q>Q>: source/dest_id pack_id_begin pack_id_end
35
- # 8 fin1 -> Q>: source/dest_id
36
- # 9 got fin1 -> Q>: source/dest_id
37
- # 10 fin2 -> Q>: source/dest_id
38
- # 11 got fin2 -> Q>: source/dest_id
39
- # 12 tund fin
40
- # 13 tun fin
41
- #
42
- # 两套关闭
43
- # ========
44
- #
45
- # 1-1. source.close -> ext.is_dest_closed ? no -> send fin1 loop
46
- # 1-2. recv got_fin1 -> break loop
47
- # 1-3. recv fin2 -> send got_fin2 -> del ext
48
- #
49
- # 2-1. recv fin1 -> send got_fin1 -> ext.is_dest_closed = true
50
- # 2-2. all sent && ext.biggest_dest_pack_id == ext.continue_dest_pack_id -> add closing source
51
- # 2-3. source.close -> ext.is_dest_closed ? yes -> del ext -> loop send fin2
52
- # 2-4. recv got_fin2 -> break loop
53
- #
54
- module Girl
55
- class Tun
56
- ##
57
- # tund_ip 远端ip
58
- # roomd_port roomd端口,roomd用于配对tun-tund
59
- # redir_port 本地端口,请配置iptables把流量引向这个端口
60
- # source_chunk_dir 文件缓存目录,缓存source写前
61
- # tun_chunk_dir 文件缓存目录,缓存tun写前
62
- # hex_block 外部传入自定义加解密
63
- def initialize( tund_ip, roomd_port = 9090, redir_port = 1919, source_chunk_dir = '/tmp', tun_chunk_dir = '/tmp', hex_block = nil )
64
- if hex_block
65
- Girl::Hex.class_eval( hex_block )
66
- end
67
-
68
- @tund_ip = tund_ip
69
- @roomd_addr = Socket.sockaddr_in( roomd_port, tund_ip )
70
- @redir_port = redir_port
71
- @source_chunk_dir = source_chunk_dir
72
- @tun_chunk_dir = tun_chunk_dir
73
- @hex = Girl::Hex.new
74
- @mutex = Mutex.new
75
- @reads = []
76
- @writes = []
77
- @closings = []
78
- @roles = {} # sock => :ctlr / :redir / :source / :tun
79
- @infos = {} # sock => {}
80
- @socks = {} # sock => sock_id
81
- @sock_ids = {} # sock_id => sock
82
-
83
- ctlr, ctlw = IO.pipe
84
- @ctlw = ctlw
85
- @roles[ ctlr ] = :ctlr
86
- @reads << ctlr
87
- end
88
-
89
- def looping
90
- puts 'looping'
91
-
92
- new_redir
93
- new_tun
94
-
95
- loop do
96
- rs, ws = IO.select( @reads, @writes )
97
-
98
- @mutex.synchronize do
99
- rs.each do | sock |
100
- case @roles[ sock ]
101
- when :ctlr
102
- read_ctlr( sock )
103
- when :redir
104
- read_redir( sock )
105
- when :source
106
- read_source( sock )
107
- when :tun
108
- read_tun( sock )
109
- end
110
- end
111
-
112
- ws.each do | sock |
113
- case @roles[ sock ]
114
- when :source
115
- write_source( sock )
116
- when :tun
117
- write_tun( sock )
118
- end
119
- end
120
- end
121
- end
122
- rescue Interrupt => e
123
- puts e.class
124
- quit!
125
- end
126
-
127
- def quit!
128
- if @tun && !@tun.closed? && @tun_info[ :tund_addr ]
129
- ctlmsg = [ 0, TUN_FIN ].pack( 'Q>C' )
130
- send_pack( @tun, ctlmsg, @tun_info[ :tund_addr ] )
131
- end
132
-
133
- exit
134
- end
135
-
136
- private
137
-
138
- ##
139
- # read ctlr
140
- #
141
- def read_ctlr( ctlr )
142
- case ctlr.read( 1 ).unpack( 'C' ).first
143
- when CTL_CLOSE
144
- sock_id = ctlr.read( 8 ).unpack( 'Q>' ).first
145
- sock = @sock_ids[ sock_id ]
146
-
147
- if sock
148
- add_closing( sock )
149
- end
150
- when CTL_RESUME
151
- sock_id = ctlr.read( 8 ).unpack( 'Q>' ).first
152
- sock = @sock_ids[ sock_id ]
153
-
154
- if sock
155
- add_write( sock )
156
- end
157
- end
158
- end
159
-
160
- ##
161
- # read redir
162
- #
163
- def read_redir( redir )
164
- begin
165
- source, addrinfo = redir.accept_nonblock
166
- rescue IO::WaitReadable, Errno::EINTR => e
167
- puts "accept source #{ e.class } #{ Time.new } p#{ Process.pid }"
168
- return
169
- end
170
-
171
- begin
172
- # /usr/include/linux/netfilter_ipv4.h
173
- option = source.getsockopt( Socket::SOL_IP, 80 )
174
- rescue Exception => e
175
- puts "get SO_ORIGINAL_DST #{ e.class } #{ Time.new } p#{ Process.pid }"
176
- source.close
177
- return
178
- end
179
-
180
- source_id = @hex.gen_random_num
181
- @roles[ source ] = :source
182
- @infos[ source ] = {
183
- id: source_id,
184
- tun: @tun
185
- }
186
- @socks[ source ] = source_id
187
- @sock_ids[ source_id ] = source
188
-
189
- @tun_info[ :waitings ][ source_id ] = []
190
- @tun_info[ :source_exts ][ source_id ] = {
191
- source: source,
192
- created_at: Time.new,
193
- last_recv_at: nil, # 上一次收到流量的时间
194
- wbuff: '', # 写前缓存
195
- cache: '', # 块读出缓存
196
- chunks: [], # 块队列,写前达到块大小时结一个块 filename
197
- spring: 0, # 块后缀,结块时,如果块队列不为空,则自增,为空,则置为0
198
- wmems: {}, # 写后缓存 pack_id => data
199
- send_ats: {}, # 上一次发出时间 pack_id => send_at
200
- biggest_pack_id: 0, # 发到几
201
- continue_dest_pack_id: 0, # 收到几
202
- pieces: {}, # 跳号包 dest_pack_id => data
203
- is_dest_closed: false, # 对面是否已关闭
204
- biggest_dest_pack_id: 0, # 对面发到几
205
- completed_pack_id: 0, # 完成到几(对面收到几)
206
- last_traffic_at: nil # 收到有效流量,或者发出流量的时间戳
207
- }
208
-
209
- add_read( source )
210
- loop_send_a_new_source( source, option.data )
211
- end
212
-
213
- ##
214
- # read source
215
- #
216
- def read_source( source )
217
- begin
218
- data = source.read_nonblock( PACK_SIZE )
219
- rescue IO::WaitReadable, Errno::EINTR => e
220
- return
221
- rescue Exception => e
222
- add_closing( source )
223
- return
224
- end
225
-
226
- # puts "debug read source #{ data.inspect } #{ Time.new } p#{ Process.pid }"
227
- info = @infos[ source ]
228
- tun = info[ :tun ]
229
-
230
- if tun.closed?
231
- add_closing( source )
232
- return
233
- end
234
-
235
- source_id = @socks[ source ]
236
- tun_info = @infos[ tun ]
237
- dest_id = tun_info[ :source_ids ][ source_id ]
238
-
239
- if tun_info[ :tund_addr ].nil? || dest_id.nil?
240
- tun_info[ :waitings ][ source_id ] << data
241
- return
242
- end
243
-
244
- tun_info[ :wbuffs ] << [ source_id, data ]
245
-
246
- if tun_info[ :wbuffs ].size >= WBUFFS_LIMIT
247
- tun_id = @socks[ tun ]
248
- spring = tun_info[ :chunks ].size > 0 ? ( tun_info[ :spring ] + 1 ) : 0
249
- filename = "#{ Process.pid }-#{ tun_id }.#{ spring }"
250
- chunk_path = File.join( @tun_chunk_dir, filename )
251
- IO.binwrite( chunk_path, tun_info[ :wbuffs ].map{ | source_id, data | "#{ [ source_id, data.bytesize ].pack( 'Q>n' ) }#{ data }" }.join )
252
- tun_info[ :chunks ] << filename
253
- tun_info[ :spring ] = spring
254
- tun_info[ :wbuffs ].clear
255
- end
256
-
257
- unless tun_info[ :paused ]
258
- add_write( tun )
259
- end
260
- end
261
-
262
- ##
263
- # read tun
264
- #
265
- def read_tun( tun )
266
- data, addrinfo, rflags, *controls = tun.recvmsg
267
- sockaddr = addrinfo.to_sockaddr
268
- now = Time.new
269
- info = @infos[ tun ]
270
- dest_id = data[ 0, 8 ].unpack( 'Q>' ).first
271
-
272
- if dest_id == 0
273
- case data[ 8 ].unpack( 'C' ).first
274
- when TUND_PORT
275
- return if sockaddr != @roomd_addr
276
-
277
- unless info[ :tund_addr ]
278
- tund_port = data[ 9, 2 ].unpack( 'n' ).first
279
- # puts "debug got TUND_PORT #{ tund_port } #{ Time.new } p#{ Process.pid }"
280
- info[ :tund_addr ] = Socket.sockaddr_in( tund_port, @tund_ip )
281
- info[ :last_traffic_at ] = now
282
- loop_send_heartbeat( tun )
283
- loop_check_expire( tun )
284
- loop_send_status( tun )
285
- end
286
- when PAIRED
287
- return if sockaddr != info[ :tund_addr ]
288
-
289
- source_id, dest_id = data[ 9, 16 ].unpack( 'Q>Q>' )
290
- return unless info[ :source_exts ].include?( source_id )
291
-
292
- return if info[ :source_ids ].include?( source_id )
293
-
294
- # puts "debug got PAIRED #{ source_id } #{ dest_id } #{ Time.new } p#{ Process.pid }"
295
- info[ :source_ids ][ source_id ] = dest_id
296
- info[ :dest_ids ][ dest_id ] = source_id
297
- buffs = info[ :waitings ][ source_id ]
298
-
299
- if buffs.any?
300
- # puts "debug move #{ buffs.size } waiting buffs to wbuffs #{ Time.new } p#{ Process.pid }"
301
-
302
- buffs.each do | buff |
303
- info[ :wbuffs ] << [ source_id, buff ]
304
- end
305
-
306
- buffs.clear
307
- add_write( tun )
308
- end
309
- when DEST_STATUS
310
- return if sockaddr != info[ :tund_addr ]
311
-
312
- dest_id, biggest_dest_pack_id, continue_source_pack_id = data[ 9, 24 ].unpack( 'Q>Q>Q>' )
313
- source_id = info[ :dest_ids ][ dest_id ]
314
- return unless source_id
315
-
316
- ext = info[ :source_exts ][ source_id ]
317
- return unless ext
318
-
319
- # 更新对面发到几
320
- if biggest_dest_pack_id > ext[ :biggest_dest_pack_id ]
321
- ext[ :biggest_dest_pack_id ] = biggest_dest_pack_id
322
- end
323
-
324
- # 更新对面收到几,释放写后
325
- if continue_source_pack_id > ext[ :completed_pack_id ]
326
- pack_ids = ext[ :wmems ].keys.select { | pack_id | pack_id <= continue_source_pack_id }
327
-
328
- pack_ids.each do | pack_id |
329
- ext[ :wmems ].delete( pack_id )
330
- ext[ :send_ats ].delete( pack_id )
331
- end
332
-
333
- # puts "debug completed #{ continue_source_pack_id }"
334
- ext[ :completed_pack_id ] = continue_source_pack_id
335
- end
336
-
337
- if ext[ :is_dest_closed ] && ( ext[ :biggest_dest_pack_id ] == ext[ :continue_dest_pack_id ] )
338
- add_write( ext[ :source ] )
339
- return
340
- end
341
-
342
- # 发miss
343
- if !ext[ :source ].closed? && ( ext[ :continue_dest_pack_id ] < ext[ :biggest_dest_pack_id ] )
344
- ranges = []
345
- curr_pack_id = ext[ :continue_dest_pack_id ] + 1
346
-
347
- ext[ :pieces ].keys.sort.each do | pack_id |
348
- if pack_id > curr_pack_id
349
- ranges << [ curr_pack_id, pack_id - 1 ]
350
- end
351
-
352
- curr_pack_id = pack_id + 1
353
- end
354
-
355
- if curr_pack_id <= ext[ :biggest_dest_pack_id ]
356
- ranges << [ curr_pack_id, ext[ :biggest_dest_pack_id ] ]
357
- end
358
-
359
- pack_count = 0
360
- # puts "debug #{ ext[ :continue_dest_pack_id ] }/#{ ext[ :biggest_dest_pack_id ] } send MISS #{ ranges.size }"
361
- ranges.each do | pack_id_begin, pack_id_end |
362
- if pack_count >= BREAK_SEND_MISS
363
- puts "break send miss at #{ pack_id_begin } #{ Time.new } p#{ Process.pid }"
364
- break
365
- end
366
-
367
- ctlmsg = [
368
- 0,
369
- MISS,
370
- dest_id,
371
- pack_id_begin,
372
- pack_id_end
373
- ].pack( 'Q>CQ>Q>Q>' )
374
-
375
- send_pack( tun, ctlmsg, info[ :tund_addr ] )
376
- pack_count += ( pack_id_end - pack_id_begin + 1 )
377
- end
378
- end
379
- when MISS
380
- return if sockaddr != info[ :tund_addr ]
381
-
382
- source_id, pack_id_begin, pack_id_end = data[ 9, 24 ].unpack( 'Q>Q>Q>' )
383
- ext = info[ :source_exts ][ source_id ]
384
- return unless ext
385
-
386
- ( pack_id_begin..pack_id_end ).each do | pack_id |
387
- send_at = ext[ :send_ats ][ pack_id ]
388
-
389
- if send_at
390
- break if now - send_at < STATUS_INTERVAL
391
-
392
- info[ :resendings ] << [ source_id, pack_id ]
393
- end
394
- end
395
-
396
- add_write( tun )
397
- when FIN1
398
- return if sockaddr != info[ :tund_addr ]
399
-
400
- # puts "debug 2-1. recv fin1 -> send got_fin1 -> ext.is_dest_closed = true #{ Time.new } p#{ Process.pid }"
401
- dest_id = data[ 9, 8 ].unpack( 'Q>' ).first
402
- ctlmsg = [
403
- 0,
404
- GOT_FIN1,
405
- dest_id
406
- ].pack( 'Q>CQ>' )
407
-
408
- send_pack( tun, ctlmsg, info[ :tund_addr ] )
409
-
410
- source_id = info[ :dest_ids ][ dest_id ]
411
- return unless source_id
412
-
413
- ext = info[ :source_exts ][ source_id ]
414
- return unless ext
415
-
416
- ext[ :is_dest_closed ] = true
417
- when GOT_FIN1
418
- return if sockaddr != info[ :tund_addr ]
419
-
420
- # puts "debug 1-2. recv got_fin1 -> break loop #{ Time.new } p#{ Process.pid }"
421
- source_id = data[ 9, 8 ].unpack( 'Q>' ).first
422
- info[ :fin1s ].delete( source_id )
423
- when FIN2
424
- return if sockaddr != info[ :tund_addr ]
425
-
426
- # puts "debug 1-3. recv fin2 -> send got_fin2 -> del ext #{ Time.new } p#{ Process.pid }"
427
- dest_id = data[ 9, 8 ].unpack( 'Q>' ).first
428
- ctlmsg = [
429
- 0,
430
- GOT_FIN2,
431
- dest_id
432
- ].pack( 'Q>CQ>' )
433
-
434
- send_pack( tun, ctlmsg, info[ :tund_addr ] )
435
-
436
- source_id = info[ :dest_ids ][ dest_id ]
437
- return unless source_id
438
-
439
- del_source_ext( info, source_id )
440
- when GOT_FIN2
441
- return if sockaddr != info[ :tund_addr ]
442
-
443
- # puts "debug 2-4. recv got_fin2 -> break loop #{ Time.new } p#{ Process.pid }"
444
- source_id = data[ 9, 8 ].unpack( 'Q>' ).first
445
- info[ :fin2s ].delete( source_id )
446
- when TUND_FIN
447
- return if sockaddr != info[ :tund_addr ]
448
-
449
- puts "recv tund fin #{ Time.new } p#{ Process.pid }"
450
- add_closing( tun )
451
- end
452
-
453
- return
454
- end
455
-
456
- return if sockaddr != info[ :tund_addr ]
457
-
458
- source_id = info[ :dest_ids ][ dest_id ]
459
- return unless source_id
460
-
461
- ext = info[ :source_exts ][ source_id ]
462
- return if ext.nil? || ext[ :source ].closed?
463
-
464
- pack_id = data[ 8, 8 ].unpack( 'Q>' ).first
465
- return if ( pack_id <= ext[ :continue_dest_pack_id ] ) || ext[ :pieces ].include?( pack_id )
466
-
467
- data = data[ 16..-1 ]
468
-
469
- # 解混淆
470
- if pack_id == 1
471
- data = @hex.decode( data )
472
- end
473
-
474
- # 放进source的写前缓存,跳号放碎片缓存
475
- if pack_id - ext[ :continue_dest_pack_id ] == 1
476
- while ext[ :pieces ].include?( pack_id + 1 )
477
- data << ext[ :pieces ].delete( pack_id + 1 )
478
- pack_id += 1
479
- end
480
-
481
- ext[ :continue_dest_pack_id ] = pack_id
482
- ext[ :wbuff ] << data
483
-
484
- if ext[ :wbuff ].bytesize >= CHUNK_SIZE
485
- spring = ext[ :chunks ].size > 0 ? ( ext[ :spring ] + 1 ) : 0
486
- filename = "#{ Process.pid }-#{ source_id }.#{ spring }"
487
- chunk_path = File.join( @source_chunk_dir, filename )
488
- IO.binwrite( chunk_path, ext[ :wbuff ] )
489
- ext[ :chunks ] << filename
490
- ext[ :spring ] = spring
491
- ext[ :wbuff ].clear
492
- end
493
-
494
- ext[ :last_traffic_at ] = now
495
- info[ :last_traffic_at ] = now
496
- add_write( ext[ :source ] )
497
- else
498
- ext[ :pieces ][ pack_id ] = data
499
- end
500
-
501
- ext[ :last_recv_at ] = now
502
- end
503
-
504
- ##
505
- # write source
506
- #
507
- def write_source( source )
508
- if @closings.include?( source )
509
- close_source( source )
510
- return
511
- end
512
-
513
- info = @infos[ source ]
514
- tun = info[ :tun ]
515
-
516
- if tun.closed?
517
- add_closing( source )
518
- return
519
- end
520
-
521
- tun_info = @infos[ tun ]
522
- source_id = @socks[ source ]
523
- ext = tun_info[ :source_exts ][ source_id ]
524
-
525
- # 取写前
526
- data = ext[ :cache ]
527
- from = :cache
528
-
529
- if data.empty?
530
- if ext[ :chunks ].any?
531
- path = File.join( @source_chunk_dir, ext[ :chunks ].shift )
532
-
533
- begin
534
- data = IO.binread( path )
535
- File.delete( path )
536
- rescue Errno::ENOENT
537
- add_closing( source )
538
- return
539
- end
540
- else
541
- data = ext[ :wbuff ]
542
- from = :wbuff
543
- end
544
- end
545
-
546
- if data.empty?
547
- if ext[ :is_dest_closed ] && ( ext[ :biggest_dest_pack_id ] == ext[ :continue_dest_pack_id ] )
548
- # puts "debug 2-2. all sent && ext.biggest_dest_pack_id == ext.continue_dest_pack_id -> add closing source #{ Time.new } p#{ Process.pid }"
549
- add_closing( source )
550
- return
551
- end
552
-
553
- @writes.delete( source )
554
- return
555
- end
556
-
557
- begin
558
- written = source.write_nonblock( data )
559
- rescue IO::WaitWritable, Errno::EINTR => e
560
- ext[ from ] = data
561
- return
562
- rescue Exception => e
563
- add_closing( source )
564
- return
565
- end
566
-
567
- data = data[ written..-1 ]
568
- ext[ from ] = data
569
- end
570
-
571
- ##
572
- # write tun
573
- #
574
- def write_tun( tun )
575
- if @closings.include?( tun )
576
- close_tun( tun )
577
- new_tun
578
- return
579
- end
580
-
581
- now = Time.new
582
- info = @infos[ tun ]
583
-
584
- # 重传
585
- while info[ :resendings ].any?
586
- source_id, pack_id = info[ :resendings ].shift
587
- ext = info[ :source_exts ][ source_id ]
588
-
589
- if ext
590
- pack = ext[ :wmems ][ pack_id ]
591
-
592
- if pack
593
- send_pack( tun, pack, info[ :tund_addr ] )
594
- ext[ :last_traffic_at ] = now
595
- info[ :last_traffic_at ] = now
596
- return
597
- end
598
- end
599
- end
600
-
601
- # 若写后达到上限,暂停取写前
602
- if info[ :source_exts ].map{ | _, ext | ext[ :wmems ].size }.sum >= WMEMS_LIMIT
603
- unless info[ :paused ]
604
- puts "pause #{ @socks[ tun ] } #{ Time.new } p#{ Process.pid }"
605
- info[ :paused ] = true
606
- end
607
-
608
- @writes.delete( tun )
609
- return
610
- end
611
-
612
- # 取写前
613
- if info[ :caches ].any?
614
- source_id, data = info[ :caches ].shift
615
- elsif info[ :chunks ].any?
616
- path = File.join( @tun_chunk_dir, info[ :chunks ].shift )
617
-
618
- begin
619
- data = IO.binread( path )
620
- File.delete( path )
621
- rescue Errno::ENOENT
622
- add_closing( tun )
623
- return
624
- end
625
-
626
- caches = []
627
-
628
- until data.empty?
629
- source_id, pack_size = data[ 0, 10 ].unpack( 'Q>n' )
630
- caches << [ source_id, data[ 10, pack_size ] ]
631
- data = data[ ( 10 + pack_size )..-1 ]
632
- end
633
-
634
- source_id, data = caches.shift
635
- info[ :caches ] = caches
636
- elsif info[ :wbuffs ].any?
637
- source_id, data = info[ :wbuffs ].shift
638
- else
639
- @writes.delete( tun )
640
- return
641
- end
642
-
643
- ext = info[ :source_exts ][ source_id ]
644
-
645
- if ext
646
- pack_id = ext[ :biggest_pack_id ] + 1
647
-
648
- if pack_id == 1
649
- data = @hex.encode( data )
650
- end
651
-
652
- pack = "#{ [ source_id, pack_id ].pack( 'Q>Q>' ) }#{ data }"
653
- send_pack( tun, pack, info[ :tund_addr ] )
654
- ext[ :biggest_pack_id ] = pack_id
655
- ext[ :wmems ][ pack_id ] = pack
656
- ext[ :send_ats ][ pack_id ] = now
657
- ext[ :last_traffic_at ] = now
658
- info[ :last_traffic_at ] = now
659
- end
660
- end
661
-
662
- def new_redir
663
- redir = Socket.new( Socket::AF_INET, Socket::SOCK_STREAM, 0 )
664
- redir.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEADDR, 1 )
665
- redir.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEPORT, 1 )
666
- redir.setsockopt( Socket::SOL_TCP, Socket::TCP_NODELAY, 1 )
667
- redir.bind( Socket.sockaddr_in( @redir_port, '0.0.0.0' ) )
668
- redir.listen( 511 )
669
-
670
- @roles[ redir ] = :redir
671
- @reads << redir
672
- end
673
-
674
- def new_tun
675
- tun = Socket.new( Socket::AF_INET, Socket::SOCK_DGRAM, 0 )
676
- tun.bind( Socket.sockaddr_in( 0, '0.0.0.0' ) )
677
- tun_id = @hex.gen_random_num
678
- tun_info = {
679
- id: tun_id,
680
- waitings: {}, # 还没连上tund,或者还没配上dest,暂存流量 source_id => buffs[]
681
- wbuffs: [], # 写前缓存 [ source_id, data ]
682
- caches: [], # 块读出缓存 [ source_id, data ]
683
- chunks: [], # 块队列 filename
684
- spring: 0, # 块后缀,结块时,如果块队列不为空,则自增,为空,则置为0
685
- tund_addr: nil, # 远端地址
686
- source_exts: {}, # 长命信息 source_id => {}
687
- source_ids: {}, # source_id => dest_id
688
- dest_ids: {}, # dest_id => source_id
689
- fin1s: [], # fin1: source已关闭,等待对面收完流量 source_id
690
- fin2s: [], # fin2: 流量已收完 source_id
691
- paused: false, # 是否暂停写
692
- resendings: [], # 重传队列 [ source_id, pack_id ]
693
- last_traffic_at: nil # 收到有效流量,或者发出流量的时间戳
694
- }
695
-
696
- @tun = tun
697
- @tun_info = tun_info
698
- @roles[ tun ] = :tun
699
- @infos[ tun ] = tun_info
700
- @socks[ tun ] = tun_id
701
- @sock_ids[ tun_id ] = tun
702
-
703
- send_pack( tun, @hex.hello, @roomd_addr )
704
- add_read( tun )
705
- check_expire( tun )
706
- end
707
-
708
- def check_expire( tun )
709
- Thread.new do
710
- sleep HEARTBEAT_INTERVAL
711
-
712
- unless tun.closed?
713
- tun_info = @infos[ tun ]
714
-
715
- unless tun_info[ :tund_addr ]
716
- @mutex.synchronize do
717
- tun_id = @socks[ tun ]
718
- @ctlw.write( [ CTL_CLOSE, tun_id ].pack( 'CQ>' ) )
719
- end
720
- end
721
- end
722
- end
723
- end
724
-
725
- def loop_send_heartbeat( tun )
726
- Thread.new do
727
- loop do
728
- break if tun.closed?
729
-
730
- @mutex.synchronize do
731
- send_heartbeat( tun )
732
- end
733
-
734
- sleep HEARTBEAT_INTERVAL
735
- end
736
- end
737
- end
738
-
739
- def loop_check_expire( tun )
740
- Thread.new do
741
- loop do
742
- sleep 60
743
- break if tun.closed?
744
-
745
- now = Time.new
746
- tun_info = @infos[ tun ]
747
-
748
- if now - tun_info[ :last_traffic_at ] > EXPIRE_AFTER
749
- @mutex.synchronize do
750
- tun_id = @socks[ tun ]
751
- # puts "debug ctlw close tun #{ tun_id } #{ Time.new } p#{ Process.pid }"
752
- @ctlw.write( [ CTL_CLOSE, tun_id ].pack( 'CQ>' ) )
753
- end
754
-
755
- break
756
- end
757
-
758
- exts = tun_info[ :source_exts ].select{ | _, ext | now - ext[ :created_at ] > 5 }
759
-
760
- if exts.any?
761
- @mutex.synchronize do
762
- exts.each do | source_id, ext |
763
- if ext[ :last_recv_at ].nil? || ( now - ext[ :last_recv_at ] > EXPIRE_AFTER )
764
- # puts "debug ctlw close source #{ source_id } #{ Time.new } p#{ Process.pid }"
765
- @ctlw.write( [ CTL_CLOSE, source_id ].pack( 'CQ>' ) )
766
- end
767
- end
768
- end
769
- end
770
- end
771
- end
772
- end
773
-
774
- def loop_send_status( tun )
775
- Thread.new do
776
- loop do
777
- sleep STATUS_INTERVAL
778
-
779
- if tun.closed?
780
- # puts "debug tun is closed, break send status loop #{ Time.new }"
781
- break
782
- end
783
-
784
- tun_info = @infos[ tun ]
785
-
786
- if tun_info[ :source_exts ].any?
787
- @mutex.synchronize do
788
- now = Time.new
789
-
790
- tun_info[ :source_exts ].each do | source_id, ext |
791
- if ext[ :last_traffic_at ] && ( now - ext[ :last_traffic_at ] < SEND_STATUS_UNTIL )
792
- ctlmsg = [
793
- 0,
794
- SOURCE_STATUS,
795
- source_id,
796
- ext[ :biggest_pack_id ],
797
- ext[ :continue_dest_pack_id ]
798
- ].pack( 'Q>CQ>Q>Q>' )
799
-
800
- send_pack( tun, ctlmsg, tun_info[ :tund_addr ] )
801
- end
802
- end
803
- end
804
- end
805
-
806
- if tun_info[ :paused ] && ( tun_info[ :source_exts ].map{ | _, ext | ext[ :wmems ].size }.sum < RESUME_BELOW )
807
- @mutex.synchronize do
808
- tun_id = @socks[ tun ]
809
- puts "ctlw resume #{ tun_id } #{ Time.new } p#{ Process.pid }"
810
- @ctlw.write( [ CTL_RESUME, tun_id ].pack( 'CQ>' ) )
811
- tun_info[ :paused ] = false
812
- end
813
- end
814
- end
815
- end
816
- end
817
-
818
- def loop_send_a_new_source( source, original_dst )
819
- Thread.new do
820
- 100.times do
821
- break if source.closed?
822
-
823
- source_info = @infos[ source ]
824
- tun = source_info[ :tun ]
825
- break if tun.closed?
826
-
827
- tun_info = @infos[ tun ]
828
-
829
- if tun_info[ :tund_addr ]
830
- source_id = @socks[ source ]
831
- dest_id = tun_info[ :source_ids ][ source_id ]
832
-
833
- if dest_id
834
- # puts "debug break a new source loop #{ Time.new } p#{ Process.pid }"
835
- break
836
- end
837
-
838
- @mutex.synchronize do
839
- ctlmsg = "#{ [ 0, A_NEW_SOURCE, source_id ].pack( 'Q>CQ>' ) }#{ original_dst }"
840
- # puts "debug send a new source #{ Time.new } p#{ Process.pid }"
841
- send_pack( tun, ctlmsg, tun_info[ :tund_addr ] )
842
- end
843
- end
844
-
845
- sleep 1
846
- end
847
- end
848
- end
849
-
850
- def loop_send_fin1( tun, source_id )
851
- Thread.new do
852
- 100.times do
853
- break if tun.closed?
854
-
855
- tun_info = @infos[ tun ]
856
- break unless tun_info[ :tund_addr ]
857
-
858
- unless tun_info[ :fin1s ].include?( source_id )
859
- # puts "debug break send fin1 loop #{ Time.new } p#{ Process.pid }"
860
- break
861
- end
862
-
863
- @mutex.synchronize do
864
- ctlmsg = [
865
- 0,
866
- FIN1,
867
- source_id
868
- ].pack( 'Q>CQ>' )
869
-
870
- # puts "debug send FIN1 #{ source_id } #{ Time.new } p#{ Process.pid }"
871
- send_pack( tun, ctlmsg, tun_info[ :tund_addr ] )
872
- end
873
-
874
- sleep 1
875
- end
876
- end
877
- end
878
-
879
- def loop_send_fin2( tun, source_id )
880
- Thread.new do
881
- 100.times do
882
- break if tun.closed?
883
-
884
- tun_info = @infos[ tun ]
885
- break unless tun_info[ :tund_addr ]
886
-
887
- unless tun_info[ :fin2s ].include?( source_id )
888
- # puts "debug break send fin2 loop #{ Time.new } p#{ Process.pid }"
889
- break
890
- end
891
-
892
- @mutex.synchronize do
893
- ctlmsg = [
894
- 0,
895
- FIN2,
896
- source_id
897
- ].pack( 'Q>CQ>' )
898
-
899
- # puts "debug send FIN2 #{ source_id } #{ Time.new } p#{ Process.pid }"
900
- send_pack( tun, ctlmsg, tun_info[ :tund_addr ] )
901
- end
902
-
903
- sleep 1
904
- end
905
- end
906
- end
907
-
908
- def send_heartbeat( tun )
909
- info = @infos[ tun ]
910
- ctlmsg = [ 0, HEARTBEAT, rand( 128 ) ].pack( 'Q>CC' )
911
- send_pack( tun, ctlmsg, info[ :tund_addr ] )
912
- end
913
-
914
- def send_pack( sock, data, target_sockaddr )
915
- begin
916
- sock.sendmsg( data, 0, target_sockaddr )
917
- rescue IO::WaitWritable, Errno::EINTR => e
918
- puts "sendmsg #{ e.class } #{ Time.new } p#{ Process.pid }"
919
- end
920
- end
921
-
922
- def add_read( sock )
923
- return if sock.closed? || @reads.include?( sock )
924
-
925
- @reads << sock
926
- end
927
-
928
- def add_write( sock )
929
- return if sock.closed? || @writes.include?( sock )
930
-
931
- @writes << sock
932
- end
933
-
934
- def add_closing( sock )
935
- return if sock.closed? || @closings.include?( sock )
936
-
937
- @reads.delete( sock )
938
- @closings << sock
939
- add_write( sock )
940
- end
941
-
942
- def close_tun( tun )
943
- info = close_sock( tun )
944
-
945
- info[ :chunks ].each do | filename |
946
- begin
947
- File.delete( File.join( @tun_chunk_dir, filename ) )
948
- rescue Errno::ENOENT
949
- end
950
- end
951
-
952
- info[ :source_exts ].each{ | _, ext | add_closing( ext[ :source ] ) }
953
- end
954
-
955
- def close_source( source )
956
- info = close_sock( source )
957
- tun = info[ :tun ]
958
- return if tun.closed?
959
-
960
- source_id = info[ :id ]
961
- tun_info = @infos[ tun ]
962
- ext = tun_info[ :source_exts ][ source_id ]
963
- return unless ext
964
-
965
- if ext[ :is_dest_closed ]
966
- del_source_ext( tun_info, source_id )
967
-
968
- unless tun_info[ :fin2s ].include?( source_id )
969
- # puts "debug 2-3. source.close -> ext.is_dest_closed ? yes -> del ext -> loop send fin2 #{ Time.new } p#{ Process.pid }"
970
- tun_info[ :fin2s ] << source_id
971
- loop_send_fin2( tun, source_id )
972
- end
973
- elsif !tun_info[ :fin1s ].include?( source_id )
974
- # puts "debug 1-1. source.close -> ext.is_dest_closed ? no -> send fin1 loop #{ Time.new } p#{ Process.pid }"
975
- tun_info[ :fin1s ] << source_id
976
- loop_send_fin1( tun, source_id )
977
- end
978
- end
979
-
980
- def close_sock( sock )
981
- sock.close
982
- @reads.delete( sock )
983
- @writes.delete( sock )
984
- @closings.delete( sock )
985
- @roles.delete( sock )
986
- info = @infos.delete( sock )
987
- sock_id = @socks.delete( sock )
988
- @sock_ids.delete( sock_id )
989
-
990
- info
991
- end
992
-
993
- def del_source_ext( tun_info, source_id )
994
- tun_info[ :waitings ].delete( source_id )
995
- ext = tun_info[ :source_exts ].delete( source_id )
996
-
997
- if ext
998
- ext[ :chunks ].each do | filename |
999
- begin
1000
- File.delete( File.join( @source_chunk_dir, filename ) )
1001
- rescue Errno::ENOENT
1002
- end
1003
- end
1004
- end
1005
-
1006
- dest_id = tun_info[ :source_ids ].delete( source_id )
1007
-
1008
- if dest_id
1009
- tun_info[ :dest_ids ].delete( dest_id )
1010
- end
1011
- end
1012
-
1013
- end
1014
- end
1
+ require 'girl/head'
2
+ require 'girl/hex'
3
+ require 'girl/version'
4
+ require 'socket'
5
+
6
+ ##
7
+ # Girl::Tun - tcp流量正常的到达目的地。近端。
8
+ #
9
+ # usage
10
+ # =====
11
+ #
12
+ # Girl::Tund.new( 9090 ).looping # 远端
13
+ #
14
+ # Girl::Tun.new( 'your.server.ip', 9090, 1919 ).looping # 近端
15
+ #
16
+ # dig +short www.google.com @127.0.0.1 -p1717 # dig with girl/resolv, got 216.58.217.196
17
+ #
18
+ # iptables -t nat -A OUTPUT -p tcp -d 216.58.217.196 -j REDIRECT --to-ports 1919
19
+ #
20
+ # curl https://www.google.com/
21
+ #
22
+ # 包结构
23
+ # ======
24
+ #
25
+ # 流量打包成udp,在tun-tund之间传输,包结构:
26
+ #
27
+ # Q>: 1+ source/dest_id -> Q>: pack_id -> traffic
28
+ # 0 ctlmsg -> C: 1 tund port -> n: tund port
29
+ # 2 heartbeat -> C: random char
30
+ # 3 a new source -> Q>nnN: source_id dst_family dst_port dst_host
31
+ # 4 paired -> Q>Q>: source_id dest_id
32
+ # 5 dest status -> Q>Q>Q>: dest_id biggest_dest_pack_id continue_source_pack_id
33
+ # 6 source status -> Q>Q>Q>: source_id biggest_source_pack_id continue_dest_pack_id
34
+ # 7 miss -> Q>Q>Q>: source/dest_id pack_id_begin pack_id_end
35
+ # 8 fin1 -> Q>: source/dest_id
36
+ # 9 got fin1 -> Q>: source/dest_id
37
+ # 10 fin2 -> Q>: source/dest_id
38
+ # 11 got fin2 -> Q>: source/dest_id
39
+ # 12 tund fin
40
+ # 13 tun fin
41
+ #
42
+ # 两套关闭
43
+ # ========
44
+ #
45
+ # 1-1. source.close -> ext.is_dest_closed ? no -> send fin1 loop
46
+ # 1-2. recv got_fin1 -> break loop
47
+ # 1-3. recv fin2 -> send got_fin2 -> del ext
48
+ #
49
+ # 2-1. recv fin1 -> send got_fin1 -> ext.is_dest_closed = true
50
+ # 2-2. all sent && ext.biggest_dest_pack_id == ext.continue_dest_pack_id -> add closing source
51
+ # 2-3. source.close -> ext.is_dest_closed ? yes -> del ext -> loop send fin2
52
+ # 2-4. recv got_fin2 -> break loop
53
+ #
54
+ module Girl
55
+ class Tun
56
+ ##
57
+ # tund_ip 远端ip
58
+ # roomd_port roomd端口,roomd用于配对tun-tund
59
+ # redir_port 本地端口,请配置iptables把流量引向这个端口
60
+ # source_chunk_dir 文件缓存目录,缓存source写前
61
+ # tun_chunk_dir 文件缓存目录,缓存tun写前
62
+ # hex_block 外部传入自定义加解密
63
+ def initialize( tund_ip, roomd_port = 9090, redir_port = 1919, source_chunk_dir = '/tmp', tun_chunk_dir = '/tmp', hex_block = nil )
64
+ if hex_block
65
+ Girl::Hex.class_eval( hex_block )
66
+ end
67
+
68
+ @tund_ip = tund_ip
69
+ @roomd_addr = Socket.sockaddr_in( roomd_port, tund_ip )
70
+ @redir_port = redir_port
71
+ @source_chunk_dir = source_chunk_dir
72
+ @tun_chunk_dir = tun_chunk_dir
73
+ @hex = Girl::Hex.new
74
+ @mutex = Mutex.new
75
+ @reads = []
76
+ @writes = []
77
+ @closings = []
78
+ @roles = {} # sock => :ctlr / :redir / :source / :tun
79
+ @infos = {} # sock => {}
80
+ @socks = {} # sock => sock_id
81
+ @sock_ids = {} # sock_id => sock
82
+
83
+ ctlr, ctlw = IO.pipe
84
+ @ctlw = ctlw
85
+ @roles[ ctlr ] = :ctlr
86
+ @reads << ctlr
87
+ end
88
+
89
+ def looping
90
+ puts 'looping'
91
+
92
+ new_redir
93
+ new_tun
94
+
95
+ loop do
96
+ rs, ws = IO.select( @reads, @writes )
97
+
98
+ @mutex.synchronize do
99
+ rs.each do | sock |
100
+ case @roles[ sock ]
101
+ when :ctlr
102
+ read_ctlr( sock )
103
+ when :redir
104
+ read_redir( sock )
105
+ when :source
106
+ read_source( sock )
107
+ when :tun
108
+ read_tun( sock )
109
+ end
110
+ end
111
+
112
+ ws.each do | sock |
113
+ case @roles[ sock ]
114
+ when :source
115
+ write_source( sock )
116
+ when :tun
117
+ write_tun( sock )
118
+ end
119
+ end
120
+ end
121
+ end
122
+ rescue Interrupt => e
123
+ puts e.class
124
+ quit!
125
+ end
126
+
127
+ def quit!
128
+ if @tun && !@tun.closed? && @tun_info[ :tund_addr ]
129
+ ctlmsg = [ 0, TUN_FIN ].pack( 'Q>C' )
130
+ send_pack( @tun, ctlmsg, @tun_info[ :tund_addr ] )
131
+ end
132
+
133
+ exit
134
+ end
135
+
136
+ private
137
+
138
+ ##
139
+ # read ctlr
140
+ #
141
+ def read_ctlr( ctlr )
142
+ case ctlr.read( 1 ).unpack( 'C' ).first
143
+ when CTL_CLOSE
144
+ sock_id = ctlr.read( 8 ).unpack( 'Q>' ).first
145
+ sock = @sock_ids[ sock_id ]
146
+
147
+ if sock
148
+ add_closing( sock )
149
+ end
150
+ when CTL_RESUME
151
+ sock_id = ctlr.read( 8 ).unpack( 'Q>' ).first
152
+ sock = @sock_ids[ sock_id ]
153
+
154
+ if sock
155
+ add_write( sock )
156
+ end
157
+ end
158
+ end
159
+
160
+ ##
161
+ # read redir
162
+ #
163
+ def read_redir( redir )
164
+ begin
165
+ source, addrinfo = redir.accept_nonblock
166
+ rescue IO::WaitReadable, Errno::EINTR => e
167
+ puts "accept source #{ e.class } #{ Time.new } p#{ Process.pid }"
168
+ return
169
+ end
170
+
171
+ begin
172
+ # /usr/include/linux/netfilter_ipv4.h
173
+ option = source.getsockopt( Socket::SOL_IP, 80 )
174
+ rescue Exception => e
175
+ puts "get SO_ORIGINAL_DST #{ e.class } #{ Time.new } p#{ Process.pid }"
176
+ source.close
177
+ return
178
+ end
179
+
180
+ source_id = @hex.gen_random_num
181
+ @roles[ source ] = :source
182
+ @infos[ source ] = {
183
+ id: source_id,
184
+ tun: @tun
185
+ }
186
+ @socks[ source ] = source_id
187
+ @sock_ids[ source_id ] = source
188
+
189
+ @tun_info[ :waitings ][ source_id ] = []
190
+ @tun_info[ :source_exts ][ source_id ] = {
191
+ source: source,
192
+ created_at: Time.new,
193
+ last_recv_at: nil, # 上一次收到流量的时间
194
+ wbuff: '', # 写前缓存
195
+ cache: '', # 块读出缓存
196
+ chunks: [], # 块队列,写前达到块大小时结一个块 filename
197
+ spring: 0, # 块后缀,结块时,如果块队列不为空,则自增,为空,则置为0
198
+ wmems: {}, # 写后缓存 pack_id => data
199
+ send_ats: {}, # 上一次发出时间 pack_id => send_at
200
+ biggest_pack_id: 0, # 发到几
201
+ continue_dest_pack_id: 0, # 收到几
202
+ pieces: {}, # 跳号包 dest_pack_id => data
203
+ is_dest_closed: false, # 对面是否已关闭
204
+ biggest_dest_pack_id: 0, # 对面发到几
205
+ completed_pack_id: 0, # 完成到几(对面收到几)
206
+ last_traffic_at: nil # 收到有效流量,或者发出流量的时间戳
207
+ }
208
+
209
+ add_read( source )
210
+ loop_send_a_new_source( source, option.data )
211
+ end
212
+
213
+ ##
214
+ # read source
215
+ #
216
+ def read_source( source )
217
+ begin
218
+ data = source.read_nonblock( PACK_SIZE )
219
+ rescue IO::WaitReadable, Errno::EINTR => e
220
+ return
221
+ rescue Exception => e
222
+ add_closing( source )
223
+ return
224
+ end
225
+
226
+ # puts "debug read source #{ data.inspect } #{ Time.new } p#{ Process.pid }"
227
+ info = @infos[ source ]
228
+ tun = info[ :tun ]
229
+
230
+ if tun.closed?
231
+ add_closing( source )
232
+ return
233
+ end
234
+
235
+ source_id = @socks[ source ]
236
+ tun_info = @infos[ tun ]
237
+ dest_id = tun_info[ :source_ids ][ source_id ]
238
+
239
+ if tun_info[ :tund_addr ].nil? || dest_id.nil?
240
+ tun_info[ :waitings ][ source_id ] << data
241
+ return
242
+ end
243
+
244
+ tun_info[ :wbuffs ] << [ source_id, data ]
245
+
246
+ if tun_info[ :wbuffs ].size >= WBUFFS_LIMIT
247
+ tun_id = @socks[ tun ]
248
+ spring = tun_info[ :chunks ].size > 0 ? ( tun_info[ :spring ] + 1 ) : 0
249
+ filename = "#{ Process.pid }-#{ tun_id }.#{ spring }"
250
+ chunk_path = File.join( @tun_chunk_dir, filename )
251
+ IO.binwrite( chunk_path, tun_info[ :wbuffs ].map{ | source_id, data | "#{ [ source_id, data.bytesize ].pack( 'Q>n' ) }#{ data }" }.join )
252
+ tun_info[ :chunks ] << filename
253
+ tun_info[ :spring ] = spring
254
+ tun_info[ :wbuffs ].clear
255
+ end
256
+
257
+ unless tun_info[ :paused ]
258
+ add_write( tun )
259
+ end
260
+ end
261
+
262
+ ##
263
+ # read tun
264
+ #
265
+ def read_tun( tun )
266
+ data, addrinfo, rflags, *controls = tun.recvmsg
267
+ sockaddr = addrinfo.to_sockaddr
268
+ now = Time.new
269
+ info = @infos[ tun ]
270
+ dest_id = data[ 0, 8 ].unpack( 'Q>' ).first
271
+
272
+ if dest_id == 0
273
+ case data[ 8 ].unpack( 'C' ).first
274
+ when TUND_PORT
275
+ return if sockaddr != @roomd_addr
276
+
277
+ unless info[ :tund_addr ]
278
+ tund_port = data[ 9, 2 ].unpack( 'n' ).first
279
+ # puts "debug got TUND_PORT #{ tund_port } #{ Time.new } p#{ Process.pid }"
280
+ info[ :tund_addr ] = Socket.sockaddr_in( tund_port, @tund_ip )
281
+ info[ :last_traffic_at ] = now
282
+ loop_send_heartbeat( tun )
283
+ loop_check_expire( tun )
284
+ loop_send_status( tun )
285
+ end
286
+ when PAIRED
287
+ return if sockaddr != info[ :tund_addr ]
288
+
289
+ source_id, dest_id = data[ 9, 16 ].unpack( 'Q>Q>' )
290
+ return unless info[ :source_exts ].include?( source_id )
291
+
292
+ return if info[ :source_ids ].include?( source_id )
293
+
294
+ # puts "debug got PAIRED #{ source_id } #{ dest_id } #{ Time.new } p#{ Process.pid }"
295
+ info[ :source_ids ][ source_id ] = dest_id
296
+ info[ :dest_ids ][ dest_id ] = source_id
297
+ buffs = info[ :waitings ][ source_id ]
298
+
299
+ if buffs.any?
300
+ # puts "debug move #{ buffs.size } waiting buffs to wbuffs #{ Time.new } p#{ Process.pid }"
301
+
302
+ buffs.each do | buff |
303
+ info[ :wbuffs ] << [ source_id, buff ]
304
+ end
305
+
306
+ buffs.clear
307
+ add_write( tun )
308
+ end
309
+ when DEST_STATUS
310
+ return if sockaddr != info[ :tund_addr ]
311
+
312
+ dest_id, biggest_dest_pack_id, continue_source_pack_id = data[ 9, 24 ].unpack( 'Q>Q>Q>' )
313
+ source_id = info[ :dest_ids ][ dest_id ]
314
+ return unless source_id
315
+
316
+ ext = info[ :source_exts ][ source_id ]
317
+ return unless ext
318
+
319
+ # 更新对面发到几
320
+ if biggest_dest_pack_id > ext[ :biggest_dest_pack_id ]
321
+ ext[ :biggest_dest_pack_id ] = biggest_dest_pack_id
322
+ end
323
+
324
+ # 更新对面收到几,释放写后
325
+ if continue_source_pack_id > ext[ :completed_pack_id ]
326
+ pack_ids = ext[ :wmems ].keys.select { | pack_id | pack_id <= continue_source_pack_id }
327
+
328
+ pack_ids.each do | pack_id |
329
+ ext[ :wmems ].delete( pack_id )
330
+ ext[ :send_ats ].delete( pack_id )
331
+ end
332
+
333
+ # puts "debug completed #{ continue_source_pack_id }"
334
+ ext[ :completed_pack_id ] = continue_source_pack_id
335
+ end
336
+
337
+ if ext[ :is_dest_closed ] && ( ext[ :biggest_dest_pack_id ] == ext[ :continue_dest_pack_id ] )
338
+ add_write( ext[ :source ] )
339
+ return
340
+ end
341
+
342
+ # 发miss
343
+ if !ext[ :source ].closed? && ( ext[ :continue_dest_pack_id ] < ext[ :biggest_dest_pack_id ] )
344
+ ranges = []
345
+ curr_pack_id = ext[ :continue_dest_pack_id ] + 1
346
+
347
+ ext[ :pieces ].keys.sort.each do | pack_id |
348
+ if pack_id > curr_pack_id
349
+ ranges << [ curr_pack_id, pack_id - 1 ]
350
+ end
351
+
352
+ curr_pack_id = pack_id + 1
353
+ end
354
+
355
+ if curr_pack_id <= ext[ :biggest_dest_pack_id ]
356
+ ranges << [ curr_pack_id, ext[ :biggest_dest_pack_id ] ]
357
+ end
358
+
359
+ pack_count = 0
360
+ # puts "debug #{ ext[ :continue_dest_pack_id ] }/#{ ext[ :biggest_dest_pack_id ] } send MISS #{ ranges.size }"
361
+ ranges.each do | pack_id_begin, pack_id_end |
362
+ if pack_count >= BREAK_SEND_MISS
363
+ puts "break send miss at #{ pack_id_begin } #{ Time.new } p#{ Process.pid }"
364
+ break
365
+ end
366
+
367
+ ctlmsg = [
368
+ 0,
369
+ MISS,
370
+ dest_id,
371
+ pack_id_begin,
372
+ pack_id_end
373
+ ].pack( 'Q>CQ>Q>Q>' )
374
+
375
+ send_pack( tun, ctlmsg, info[ :tund_addr ] )
376
+ pack_count += ( pack_id_end - pack_id_begin + 1 )
377
+ end
378
+ end
379
+ when MISS
380
+ return if sockaddr != info[ :tund_addr ]
381
+
382
+ source_id, pack_id_begin, pack_id_end = data[ 9, 24 ].unpack( 'Q>Q>Q>' )
383
+ ext = info[ :source_exts ][ source_id ]
384
+ return unless ext
385
+
386
+ ( pack_id_begin..pack_id_end ).each do | pack_id |
387
+ send_at = ext[ :send_ats ][ pack_id ]
388
+
389
+ if send_at
390
+ break if now - send_at < STATUS_INTERVAL
391
+
392
+ info[ :resendings ] << [ source_id, pack_id ]
393
+ end
394
+ end
395
+
396
+ add_write( tun )
397
+ when FIN1
398
+ return if sockaddr != info[ :tund_addr ]
399
+
400
+ # puts "debug 2-1. recv fin1 -> send got_fin1 -> ext.is_dest_closed = true #{ Time.new } p#{ Process.pid }"
401
+ dest_id = data[ 9, 8 ].unpack( 'Q>' ).first
402
+ ctlmsg = [
403
+ 0,
404
+ GOT_FIN1,
405
+ dest_id
406
+ ].pack( 'Q>CQ>' )
407
+
408
+ send_pack( tun, ctlmsg, info[ :tund_addr ] )
409
+
410
+ source_id = info[ :dest_ids ][ dest_id ]
411
+ return unless source_id
412
+
413
+ ext = info[ :source_exts ][ source_id ]
414
+ return unless ext
415
+
416
+ ext[ :is_dest_closed ] = true
417
+ when GOT_FIN1
418
+ return if sockaddr != info[ :tund_addr ]
419
+
420
+ # puts "debug 1-2. recv got_fin1 -> break loop #{ Time.new } p#{ Process.pid }"
421
+ source_id = data[ 9, 8 ].unpack( 'Q>' ).first
422
+ info[ :fin1s ].delete( source_id )
423
+ when FIN2
424
+ return if sockaddr != info[ :tund_addr ]
425
+
426
+ # puts "debug 1-3. recv fin2 -> send got_fin2 -> del ext #{ Time.new } p#{ Process.pid }"
427
+ dest_id = data[ 9, 8 ].unpack( 'Q>' ).first
428
+ ctlmsg = [
429
+ 0,
430
+ GOT_FIN2,
431
+ dest_id
432
+ ].pack( 'Q>CQ>' )
433
+
434
+ send_pack( tun, ctlmsg, info[ :tund_addr ] )
435
+
436
+ source_id = info[ :dest_ids ][ dest_id ]
437
+ return unless source_id
438
+
439
+ del_source_ext( info, source_id )
440
+ when GOT_FIN2
441
+ return if sockaddr != info[ :tund_addr ]
442
+
443
+ # puts "debug 2-4. recv got_fin2 -> break loop #{ Time.new } p#{ Process.pid }"
444
+ source_id = data[ 9, 8 ].unpack( 'Q>' ).first
445
+ info[ :fin2s ].delete( source_id )
446
+ when TUND_FIN
447
+ return if sockaddr != info[ :tund_addr ]
448
+
449
+ puts "recv tund fin #{ Time.new } p#{ Process.pid }"
450
+ add_closing( tun )
451
+ end
452
+
453
+ return
454
+ end
455
+
456
+ return if sockaddr != info[ :tund_addr ]
457
+
458
+ source_id = info[ :dest_ids ][ dest_id ]
459
+ return unless source_id
460
+
461
+ ext = info[ :source_exts ][ source_id ]
462
+ return if ext.nil? || ext[ :source ].closed?
463
+
464
+ pack_id = data[ 8, 8 ].unpack( 'Q>' ).first
465
+ return if ( pack_id <= ext[ :continue_dest_pack_id ] ) || ext[ :pieces ].include?( pack_id )
466
+
467
+ data = data[ 16..-1 ]
468
+
469
+ # 解混淆
470
+ if pack_id == 1
471
+ data = @hex.decode( data )
472
+ end
473
+
474
+ # 放进source的写前缓存,跳号放碎片缓存
475
+ if pack_id - ext[ :continue_dest_pack_id ] == 1
476
+ while ext[ :pieces ].include?( pack_id + 1 )
477
+ data << ext[ :pieces ].delete( pack_id + 1 )
478
+ pack_id += 1
479
+ end
480
+
481
+ ext[ :continue_dest_pack_id ] = pack_id
482
+ ext[ :wbuff ] << data
483
+
484
+ if ext[ :wbuff ].bytesize >= CHUNK_SIZE
485
+ spring = ext[ :chunks ].size > 0 ? ( ext[ :spring ] + 1 ) : 0
486
+ filename = "#{ Process.pid }-#{ source_id }.#{ spring }"
487
+ chunk_path = File.join( @source_chunk_dir, filename )
488
+ IO.binwrite( chunk_path, ext[ :wbuff ] )
489
+ ext[ :chunks ] << filename
490
+ ext[ :spring ] = spring
491
+ ext[ :wbuff ].clear
492
+ end
493
+
494
+ ext[ :last_traffic_at ] = now
495
+ info[ :last_traffic_at ] = now
496
+ add_write( ext[ :source ] )
497
+ else
498
+ ext[ :pieces ][ pack_id ] = data
499
+ end
500
+
501
+ ext[ :last_recv_at ] = now
502
+ end
503
+
504
+ ##
505
+ # write source
506
+ #
507
+ def write_source( source )
508
+ if @closings.include?( source )
509
+ close_source( source )
510
+ return
511
+ end
512
+
513
+ info = @infos[ source ]
514
+ tun = info[ :tun ]
515
+
516
+ if tun.closed?
517
+ add_closing( source )
518
+ return
519
+ end
520
+
521
+ tun_info = @infos[ tun ]
522
+ source_id = @socks[ source ]
523
+ ext = tun_info[ :source_exts ][ source_id ]
524
+
525
+ # 取写前
526
+ data = ext[ :cache ]
527
+ from = :cache
528
+
529
+ if data.empty?
530
+ if ext[ :chunks ].any?
531
+ path = File.join( @source_chunk_dir, ext[ :chunks ].shift )
532
+
533
+ begin
534
+ data = IO.binread( path )
535
+ File.delete( path )
536
+ rescue Errno::ENOENT
537
+ add_closing( source )
538
+ return
539
+ end
540
+ else
541
+ data = ext[ :wbuff ]
542
+ from = :wbuff
543
+ end
544
+ end
545
+
546
+ if data.empty?
547
+ if ext[ :is_dest_closed ] && ( ext[ :biggest_dest_pack_id ] == ext[ :continue_dest_pack_id ] )
548
+ # puts "debug 2-2. all sent && ext.biggest_dest_pack_id == ext.continue_dest_pack_id -> add closing source #{ Time.new } p#{ Process.pid }"
549
+ add_closing( source )
550
+ return
551
+ end
552
+
553
+ @writes.delete( source )
554
+ return
555
+ end
556
+
557
+ begin
558
+ written = source.write_nonblock( data )
559
+ rescue IO::WaitWritable, Errno::EINTR => e
560
+ ext[ from ] = data
561
+ return
562
+ rescue Exception => e
563
+ add_closing( source )
564
+ return
565
+ end
566
+
567
+ data = data[ written..-1 ]
568
+ ext[ from ] = data
569
+ end
570
+
571
+ ##
572
+ # write tun
573
+ #
574
+ def write_tun( tun )
575
+ if @closings.include?( tun )
576
+ close_tun( tun )
577
+ new_tun
578
+ return
579
+ end
580
+
581
+ now = Time.new
582
+ info = @infos[ tun ]
583
+
584
+ # 重传
585
+ while info[ :resendings ].any?
586
+ source_id, pack_id = info[ :resendings ].shift
587
+ ext = info[ :source_exts ][ source_id ]
588
+
589
+ if ext
590
+ pack = ext[ :wmems ][ pack_id ]
591
+
592
+ if pack
593
+ send_pack( tun, pack, info[ :tund_addr ] )
594
+ ext[ :last_traffic_at ] = now
595
+ info[ :last_traffic_at ] = now
596
+ return
597
+ end
598
+ end
599
+ end
600
+
601
+ # 若写后达到上限,暂停取写前
602
+ if info[ :source_exts ].map{ | _, ext | ext[ :wmems ].size }.sum >= WMEMS_LIMIT
603
+ unless info[ :paused ]
604
+ puts "pause #{ @socks[ tun ] } #{ Time.new } p#{ Process.pid }"
605
+ info[ :paused ] = true
606
+ end
607
+
608
+ @writes.delete( tun )
609
+ return
610
+ end
611
+
612
+ # 取写前
613
+ if info[ :caches ].any?
614
+ source_id, data = info[ :caches ].shift
615
+ elsif info[ :chunks ].any?
616
+ path = File.join( @tun_chunk_dir, info[ :chunks ].shift )
617
+
618
+ begin
619
+ data = IO.binread( path )
620
+ File.delete( path )
621
+ rescue Errno::ENOENT
622
+ add_closing( tun )
623
+ return
624
+ end
625
+
626
+ caches = []
627
+
628
+ until data.empty?
629
+ source_id, pack_size = data[ 0, 10 ].unpack( 'Q>n' )
630
+ caches << [ source_id, data[ 10, pack_size ] ]
631
+ data = data[ ( 10 + pack_size )..-1 ]
632
+ end
633
+
634
+ source_id, data = caches.shift
635
+ info[ :caches ] = caches
636
+ elsif info[ :wbuffs ].any?
637
+ source_id, data = info[ :wbuffs ].shift
638
+ else
639
+ @writes.delete( tun )
640
+ return
641
+ end
642
+
643
+ ext = info[ :source_exts ][ source_id ]
644
+
645
+ if ext
646
+ pack_id = ext[ :biggest_pack_id ] + 1
647
+
648
+ if pack_id == 1
649
+ data = @hex.encode( data )
650
+ end
651
+
652
+ pack = "#{ [ source_id, pack_id ].pack( 'Q>Q>' ) }#{ data }"
653
+ send_pack( tun, pack, info[ :tund_addr ] )
654
+ ext[ :biggest_pack_id ] = pack_id
655
+ ext[ :wmems ][ pack_id ] = pack
656
+ ext[ :send_ats ][ pack_id ] = now
657
+ ext[ :last_traffic_at ] = now
658
+ info[ :last_traffic_at ] = now
659
+ end
660
+ end
661
+
662
+ def new_redir
663
+ redir = Socket.new( Socket::AF_INET, Socket::SOCK_STREAM, 0 )
664
+ redir.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEADDR, 1 )
665
+ redir.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEPORT, 1 )
666
+ redir.setsockopt( Socket::SOL_TCP, Socket::TCP_NODELAY, 1 )
667
+ redir.bind( Socket.sockaddr_in( @redir_port, '0.0.0.0' ) )
668
+ redir.listen( 511 )
669
+
670
+ @roles[ redir ] = :redir
671
+ @reads << redir
672
+ end
673
+
674
+ def new_tun
675
+ tun = Socket.new( Socket::AF_INET, Socket::SOCK_DGRAM, 0 )
676
+ tun.bind( Socket.sockaddr_in( 0, '0.0.0.0' ) )
677
+ tun_id = @hex.gen_random_num
678
+ tun_info = {
679
+ id: tun_id,
680
+ waitings: {}, # 还没连上tund,或者还没配上dest,暂存流量 source_id => buffs[]
681
+ wbuffs: [], # 写前缓存 [ source_id, data ]
682
+ caches: [], # 块读出缓存 [ source_id, data ]
683
+ chunks: [], # 块队列 filename
684
+ spring: 0, # 块后缀,结块时,如果块队列不为空,则自增,为空,则置为0
685
+ tund_addr: nil, # 远端地址
686
+ source_exts: {}, # 长命信息 source_id => {}
687
+ source_ids: {}, # source_id => dest_id
688
+ dest_ids: {}, # dest_id => source_id
689
+ fin1s: [], # fin1: source已关闭,等待对面收完流量 source_id
690
+ fin2s: [], # fin2: 流量已收完 source_id
691
+ paused: false, # 是否暂停写
692
+ resendings: [], # 重传队列 [ source_id, pack_id ]
693
+ last_traffic_at: nil # 收到有效流量,或者发出流量的时间戳
694
+ }
695
+
696
+ @tun = tun
697
+ @tun_info = tun_info
698
+ @roles[ tun ] = :tun
699
+ @infos[ tun ] = tun_info
700
+ @socks[ tun ] = tun_id
701
+ @sock_ids[ tun_id ] = tun
702
+
703
+ send_pack( tun, @hex.hello, @roomd_addr )
704
+ add_read( tun )
705
+ check_expire( tun )
706
+ end
707
+
708
+ def check_expire( tun )
709
+ Thread.new do
710
+ sleep HEARTBEAT_INTERVAL
711
+
712
+ unless tun.closed?
713
+ tun_info = @infos[ tun ]
714
+
715
+ unless tun_info[ :tund_addr ]
716
+ @mutex.synchronize do
717
+ tun_id = @socks[ tun ]
718
+ @ctlw.write( [ CTL_CLOSE, tun_id ].pack( 'CQ>' ) )
719
+ end
720
+ end
721
+ end
722
+ end
723
+ end
724
+
725
+ def loop_send_heartbeat( tun )
726
+ Thread.new do
727
+ loop do
728
+ break if tun.closed?
729
+
730
+ @mutex.synchronize do
731
+ send_heartbeat( tun )
732
+ end
733
+
734
+ sleep HEARTBEAT_INTERVAL
735
+ end
736
+ end
737
+ end
738
+
739
+ def loop_check_expire( tun )
740
+ Thread.new do
741
+ loop do
742
+ sleep 60
743
+ break if tun.closed?
744
+
745
+ now = Time.new
746
+ tun_info = @infos[ tun ]
747
+
748
+ if now - tun_info[ :last_traffic_at ] > EXPIRE_AFTER
749
+ @mutex.synchronize do
750
+ tun_id = @socks[ tun ]
751
+ # puts "debug ctlw close tun #{ tun_id } #{ Time.new } p#{ Process.pid }"
752
+ @ctlw.write( [ CTL_CLOSE, tun_id ].pack( 'CQ>' ) )
753
+ end
754
+
755
+ break
756
+ end
757
+
758
+ exts = tun_info[ :source_exts ].select{ | _, ext | now - ext[ :created_at ] > 5 }
759
+
760
+ if exts.any?
761
+ @mutex.synchronize do
762
+ exts.each do | source_id, ext |
763
+ if ext[ :last_recv_at ].nil? || ( now - ext[ :last_recv_at ] > EXPIRE_AFTER )
764
+ # puts "debug ctlw close source #{ source_id } #{ Time.new } p#{ Process.pid }"
765
+ @ctlw.write( [ CTL_CLOSE, source_id ].pack( 'CQ>' ) )
766
+ end
767
+ end
768
+ end
769
+ end
770
+ end
771
+ end
772
+ end
773
+
774
+ def loop_send_status( tun )
775
+ Thread.new do
776
+ loop do
777
+ sleep STATUS_INTERVAL
778
+
779
+ if tun.closed?
780
+ # puts "debug tun is closed, break send status loop #{ Time.new }"
781
+ break
782
+ end
783
+
784
+ tun_info = @infos[ tun ]
785
+
786
+ if tun_info[ :source_exts ].any?
787
+ @mutex.synchronize do
788
+ now = Time.new
789
+
790
+ tun_info[ :source_exts ].each do | source_id, ext |
791
+ if ext[ :last_traffic_at ] && ( now - ext[ :last_traffic_at ] < SEND_STATUS_UNTIL )
792
+ ctlmsg = [
793
+ 0,
794
+ SOURCE_STATUS,
795
+ source_id,
796
+ ext[ :biggest_pack_id ],
797
+ ext[ :continue_dest_pack_id ]
798
+ ].pack( 'Q>CQ>Q>Q>' )
799
+
800
+ send_pack( tun, ctlmsg, tun_info[ :tund_addr ] )
801
+ end
802
+ end
803
+ end
804
+ end
805
+
806
+ if tun_info[ :paused ] && ( tun_info[ :source_exts ].map{ | _, ext | ext[ :wmems ].size }.sum < RESUME_BELOW )
807
+ @mutex.synchronize do
808
+ tun_id = @socks[ tun ]
809
+ puts "ctlw resume #{ tun_id } #{ Time.new } p#{ Process.pid }"
810
+ @ctlw.write( [ CTL_RESUME, tun_id ].pack( 'CQ>' ) )
811
+ tun_info[ :paused ] = false
812
+ end
813
+ end
814
+ end
815
+ end
816
+ end
817
+
818
+ def loop_send_a_new_source( source, original_dst )
819
+ Thread.new do
820
+ 100.times do
821
+ break if source.closed?
822
+
823
+ source_info = @infos[ source ]
824
+ tun = source_info[ :tun ]
825
+ break if tun.closed?
826
+
827
+ tun_info = @infos[ tun ]
828
+
829
+ if tun_info[ :tund_addr ]
830
+ source_id = @socks[ source ]
831
+ dest_id = tun_info[ :source_ids ][ source_id ]
832
+
833
+ if dest_id
834
+ # puts "debug break a new source loop #{ Time.new } p#{ Process.pid }"
835
+ break
836
+ end
837
+
838
+ @mutex.synchronize do
839
+ ctlmsg = "#{ [ 0, A_NEW_SOURCE, source_id ].pack( 'Q>CQ>' ) }#{ original_dst }"
840
+ # puts "debug send a new source #{ Time.new } p#{ Process.pid }"
841
+ send_pack( tun, ctlmsg, tun_info[ :tund_addr ] )
842
+ end
843
+ end
844
+
845
+ sleep 1
846
+ end
847
+ end
848
+ end
849
+
850
+ def loop_send_fin1( tun, source_id )
851
+ Thread.new do
852
+ 100.times do
853
+ break if tun.closed?
854
+
855
+ tun_info = @infos[ tun ]
856
+ break unless tun_info[ :tund_addr ]
857
+
858
+ unless tun_info[ :fin1s ].include?( source_id )
859
+ # puts "debug break send fin1 loop #{ Time.new } p#{ Process.pid }"
860
+ break
861
+ end
862
+
863
+ @mutex.synchronize do
864
+ ctlmsg = [
865
+ 0,
866
+ FIN1,
867
+ source_id
868
+ ].pack( 'Q>CQ>' )
869
+
870
+ # puts "debug send FIN1 #{ source_id } #{ Time.new } p#{ Process.pid }"
871
+ send_pack( tun, ctlmsg, tun_info[ :tund_addr ] )
872
+ end
873
+
874
+ sleep 1
875
+ end
876
+ end
877
+ end
878
+
879
+ def loop_send_fin2( tun, source_id )
880
+ Thread.new do
881
+ 100.times do
882
+ break if tun.closed?
883
+
884
+ tun_info = @infos[ tun ]
885
+ break unless tun_info[ :tund_addr ]
886
+
887
+ unless tun_info[ :fin2s ].include?( source_id )
888
+ # puts "debug break send fin2 loop #{ Time.new } p#{ Process.pid }"
889
+ break
890
+ end
891
+
892
+ @mutex.synchronize do
893
+ ctlmsg = [
894
+ 0,
895
+ FIN2,
896
+ source_id
897
+ ].pack( 'Q>CQ>' )
898
+
899
+ # puts "debug send FIN2 #{ source_id } #{ Time.new } p#{ Process.pid }"
900
+ send_pack( tun, ctlmsg, tun_info[ :tund_addr ] )
901
+ end
902
+
903
+ sleep 1
904
+ end
905
+ end
906
+ end
907
+
908
+ def send_heartbeat( tun )
909
+ info = @infos[ tun ]
910
+ ctlmsg = [ 0, HEARTBEAT, rand( 128 ) ].pack( 'Q>CC' )
911
+ send_pack( tun, ctlmsg, info[ :tund_addr ] )
912
+ end
913
+
914
+ def send_pack( sock, data, target_sockaddr )
915
+ begin
916
+ sock.sendmsg( data, 0, target_sockaddr )
917
+ rescue IO::WaitWritable, Errno::EINTR => e
918
+ puts "sendmsg #{ e.class } #{ Time.new } p#{ Process.pid }"
919
+ end
920
+ end
921
+
922
+ def add_read( sock )
923
+ return if sock.closed? || @reads.include?( sock )
924
+
925
+ @reads << sock
926
+ end
927
+
928
+ def add_write( sock )
929
+ return if sock.closed? || @writes.include?( sock )
930
+
931
+ @writes << sock
932
+ end
933
+
934
+ def add_closing( sock )
935
+ return if sock.closed? || @closings.include?( sock )
936
+
937
+ @reads.delete( sock )
938
+ @closings << sock
939
+ add_write( sock )
940
+ end
941
+
942
+ def close_tun( tun )
943
+ info = close_sock( tun )
944
+
945
+ info[ :chunks ].each do | filename |
946
+ begin
947
+ File.delete( File.join( @tun_chunk_dir, filename ) )
948
+ rescue Errno::ENOENT
949
+ end
950
+ end
951
+
952
+ info[ :source_exts ].each{ | _, ext | add_closing( ext[ :source ] ) }
953
+ end
954
+
955
+ def close_source( source )
956
+ info = close_sock( source )
957
+ tun = info[ :tun ]
958
+ return if tun.closed?
959
+
960
+ source_id = info[ :id ]
961
+ tun_info = @infos[ tun ]
962
+ ext = tun_info[ :source_exts ][ source_id ]
963
+ return unless ext
964
+
965
+ if ext[ :is_dest_closed ]
966
+ del_source_ext( tun_info, source_id )
967
+
968
+ unless tun_info[ :fin2s ].include?( source_id )
969
+ # puts "debug 2-3. source.close -> ext.is_dest_closed ? yes -> del ext -> loop send fin2 #{ Time.new } p#{ Process.pid }"
970
+ tun_info[ :fin2s ] << source_id
971
+ loop_send_fin2( tun, source_id )
972
+ end
973
+ elsif !tun_info[ :fin1s ].include?( source_id )
974
+ # puts "debug 1-1. source.close -> ext.is_dest_closed ? no -> send fin1 loop #{ Time.new } p#{ Process.pid }"
975
+ tun_info[ :fin1s ] << source_id
976
+ loop_send_fin1( tun, source_id )
977
+ end
978
+ end
979
+
980
+ def close_sock( sock )
981
+ sock.close
982
+ @reads.delete( sock )
983
+ @writes.delete( sock )
984
+ @closings.delete( sock )
985
+ @roles.delete( sock )
986
+ info = @infos.delete( sock )
987
+ sock_id = @socks.delete( sock )
988
+ @sock_ids.delete( sock_id )
989
+
990
+ info
991
+ end
992
+
993
+ def del_source_ext( tun_info, source_id )
994
+ tun_info[ :waitings ].delete( source_id )
995
+ ext = tun_info[ :source_exts ].delete( source_id )
996
+
997
+ if ext
998
+ ext[ :chunks ].each do | filename |
999
+ begin
1000
+ File.delete( File.join( @source_chunk_dir, filename ) )
1001
+ rescue Errno::ENOENT
1002
+ end
1003
+ end
1004
+ end
1005
+
1006
+ dest_id = tun_info[ :source_ids ].delete( source_id )
1007
+
1008
+ if dest_id
1009
+ tun_info[ :dest_ids ].delete( dest_id )
1010
+ end
1011
+ end
1012
+
1013
+ end
1014
+ end