girl 9.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1860 @@
1
+ module Girl
2
+ class ProxyWorker
3
+ include Dns
4
+
5
+ def initialize(
6
+ redir_port,
7
+ memd_port,
8
+ tspd_port,
9
+ proxyd_host,
10
+ proxyd_port,
11
+ nameservers,
12
+ im,
13
+ directs,
14
+ remotes,
15
+ appd_host,
16
+ appd_port,
17
+ head_len,
18
+ h_a_new_source,
19
+ h_a_new_p2,
20
+ h_dst_close,
21
+ h_heartbeat,
22
+ h_p1_close,
23
+ h_p2_close,
24
+ h_p2_traffic,
25
+ h_p1_overflow,
26
+ h_p1_underhalf,
27
+ h_p2_overflow,
28
+ h_p2_underhalf,
29
+ h_query,
30
+ h_response,
31
+ h_src_close,
32
+ h_traffic,
33
+ h_src_overflow,
34
+ h_src_underhalf,
35
+ h_dst_overflow,
36
+ h_dst_underhalf,
37
+ expire_connecting,
38
+ expire_long_after,
39
+ expire_proxy_after,
40
+ expire_resolv_cache,
41
+ expire_short_after,
42
+ is_debug,
43
+ is_client_fastopen,
44
+ is_server_fastopen )
45
+
46
+ @proxyd_host = proxyd_host
47
+ @proxyd_addr = Socket.sockaddr_in( proxyd_port, proxyd_host )
48
+ @nameserver_addrs = nameservers.map{ | n | Socket.sockaddr_in( 53, n ) }
49
+ @im = im
50
+ @directs = directs
51
+ @remotes = remotes
52
+ @local_ips = Socket.ip_address_list.select{ | info | info.ipv4? }.map{ | info | info.ip_address }
53
+ @update_roles = [ :dns, :dst, :mem, :p1, :src, :rsv ] # 参与淘汰的角色
54
+ @updates_limit = 1008 # 淘汰池上限,1015(mac) - info, infod, memd, proxy, redir, rsvd, tspd
55
+ @eliminate_count = 0 # 淘汰次数
56
+ @reads = [] # 读池
57
+ @writes = [] # 写池
58
+ @roles = {} # sock => :dns / :dst / :infod / :mem / :memd / :p1 / :proxy / :redir / :rsv / :rsvd / :src / :tspd
59
+ @updates = {} # sock => updated_at
60
+ @proxy_infos = {} # proxy => { :is_syn :paused_p1s :paused_srcs :rbuff :recv_at :wbuff }
61
+ @mem_infos = {} # mem => { :wbuff }
62
+ @src_infos = {} # src => { :addrinfo :closing :destination_domain :destination_port :dst :is_connect :overflowing :proxy_proto :proxy_type :rbuff :src_id :wbuff }
63
+ @dst_infos = {} # dst => { :closing :connected :domain :ip :overflowing :port :src :wbuff }
64
+ @dns_infos = {} # dns => { :domain :src }
65
+ @rsv_infos = {} # rsv => { :addrinfo :domain :type }
66
+ @near_infos = {} # near_id => { :addrinfo :created_at :domain :id :type }
67
+ @resolv_caches = {} # domain => [ ip, created_at ]
68
+ @is_direct_caches = {} # ip => true / false
69
+ @response_caches = {} # domain => [ response, created_at, ip, is_remote ]
70
+ @response6_caches = {} # domain => [ response, created_at, ip, is_remote ]
71
+ @p1_infos = {} # p1 => { :closing :connected :overflowing :p2_id :wbuff }
72
+ @appd_addr = Socket.sockaddr_in( appd_port, appd_host )
73
+
74
+ @head_len = head_len
75
+ @h_a_new_source = h_a_new_source
76
+ @h_a_new_p2 = h_a_new_p2
77
+ @h_dst_close = h_dst_close
78
+ @h_heartbeat = h_heartbeat
79
+ @h_p1_close = h_p1_close
80
+ @h_p2_close = h_p2_close
81
+ @h_p2_traffic = h_p2_traffic
82
+ @h_p1_overflow = h_p1_overflow
83
+ @h_p1_underhalf = h_p1_underhalf
84
+ @h_p2_overflow = h_p2_overflow
85
+ @h_p2_underhalf = h_p2_underhalf
86
+ @h_query = h_query
87
+ @h_response = h_response
88
+ @h_src_close = h_src_close
89
+ @h_traffic = h_traffic
90
+ @h_src_overflow = h_src_overflow
91
+ @h_src_underhalf = h_src_underhalf
92
+ @h_dst_overflow = h_dst_overflow
93
+ @h_dst_underhalf = h_dst_underhalf
94
+ @expire_connecting = expire_connecting
95
+ @expire_long_after = expire_long_after
96
+ @expire_proxy_after = expire_proxy_after
97
+ @expire_resolv_cache = expire_resolv_cache
98
+ @expire_short_after = expire_short_after
99
+ @is_debug = is_debug
100
+ @is_client_fastopen = is_client_fastopen
101
+ @is_server_fastopen = is_server_fastopen
102
+
103
+ new_a_redir( redir_port )
104
+ new_a_infod( redir_port )
105
+ new_a_memd( memd_port )
106
+ new_a_rsvd( tspd_port )
107
+ new_a_tspd( tspd_port )
108
+ new_a_proxy
109
+ end
110
+
111
+ def looping
112
+ puts "looping"
113
+ loop_heartbeat
114
+
115
+ loop do
116
+ rs, ws = IO.select( @reads, @writes )
117
+
118
+ rs.each do | sock |
119
+ role = @roles[ sock ]
120
+
121
+ case role
122
+ when :dns then
123
+ read_dns( sock )
124
+ when :dst then
125
+ read_dst( sock )
126
+ when :infod then
127
+ read_infod( sock )
128
+ when :mem then
129
+ read_mem( sock )
130
+ when :memd then
131
+ read_memd( sock )
132
+ when :p1 then
133
+ read_p1( sock )
134
+ when :proxy then
135
+ read_proxy( sock )
136
+ when :redir then
137
+ read_redir( sock )
138
+ when :rsv then
139
+ read_rsv( sock )
140
+ when :rsvd then
141
+ read_rsvd( sock )
142
+ when :src then
143
+ read_src( sock )
144
+ when :tspd then
145
+ read_tspd( sock )
146
+ else
147
+ close_sock( sock )
148
+ end
149
+ end
150
+
151
+ ws.each do | sock |
152
+ role = @roles[ sock ]
153
+
154
+ case role
155
+ when :dst then
156
+ write_dst( sock )
157
+ when :mem then
158
+ write_mem( sock )
159
+ when :p1 then
160
+ write_p1( sock )
161
+ when :proxy then
162
+ write_proxy( sock )
163
+ when :src then
164
+ write_src( sock )
165
+ else
166
+ close_sock( sock )
167
+ end
168
+ end
169
+ end
170
+ rescue Interrupt => e
171
+ puts e.class
172
+ quit!
173
+ end
174
+
175
+ def quit!
176
+ exit
177
+ end
178
+
179
+ private
180
+
181
+ def add_dst_wbuff( dst, data )
182
+ return if dst.nil? || dst.closed? || data.nil? || data.empty?
183
+ dst_info = @dst_infos[ dst ]
184
+ dst_info[ :wbuff ] << data
185
+ bytesize = dst_info[ :wbuff ].bytesize
186
+
187
+ if !dst_info[ :overflowing ] && ( bytesize >= WBUFF_LIMIT ) then
188
+ puts "dst overflow pause src #{ dst_info[ :domain ] }"
189
+ @reads.delete( dst_info[ :src ] )
190
+ dst_info[ :overflowing ] = true
191
+ end
192
+
193
+ add_write( dst )
194
+ end
195
+
196
+ def add_mem_wbuff( mem, data )
197
+ return if mem.nil? || mem.closed? || data.nil? || data.empty?
198
+ mem_info = @mem_infos[ mem ]
199
+ mem_info[ :wbuff ] << data
200
+ add_write( mem )
201
+ end
202
+
203
+ def add_p1_wbuff( p1, data )
204
+ return if p1.nil? || p1.closed? || data.nil? || data.empty?
205
+ p1_info = @p1_infos[ p1 ]
206
+ p1_info[ :wbuff ] << data
207
+ bytesize = p1_info[ :wbuff ].bytesize
208
+ p2_id = p1_info[ :p2_id ]
209
+
210
+ if bytesize >= CLOSE_ABOVE then
211
+ puts "close overflow p1 #{ p2_id }"
212
+ close_p1( p1 )
213
+ return
214
+ end
215
+
216
+ if !p1_info[ :overflowing ] && ( bytesize >= WBUFF_LIMIT ) then
217
+ puts "add h_p1_overflow #{ p2_id }"
218
+ msg = "#{ @h_p1_overflow }#{ [ p2_id ].pack( 'Q>' ) }"
219
+ add_proxy_wbuff( pack_a_chunk( msg ) )
220
+ p1_info[ :overflowing ] = true
221
+ end
222
+
223
+ add_write( p1 )
224
+ end
225
+
226
+ def add_proxy_wbuff( data )
227
+ return if @proxy.closed? || data.nil? || data.empty?
228
+ proxy_info = @proxy_infos[ @proxy ]
229
+ proxy_info[ :wbuff ] << data
230
+ bytesize = proxy_info[ :wbuff ].bytesize
231
+
232
+ if bytesize >= CLOSE_ABOVE then
233
+ puts "close overflow proxy"
234
+ close_proxy( @proxy )
235
+ return
236
+ end
237
+
238
+ add_write( @proxy )
239
+ end
240
+
241
+ def add_read( sock, role = nil )
242
+ return if sock.nil? || sock.closed? || @reads.include?( sock )
243
+ @reads << sock
244
+
245
+ if role then
246
+ @roles[ sock ] = role
247
+ else
248
+ role = @roles[ sock ]
249
+ end
250
+
251
+ if @update_roles.include?( role ) then
252
+ set_update( sock )
253
+ end
254
+ end
255
+
256
+ def add_socks5_conn_reply( src )
257
+ # +----+-----+-------+------+----------+----------+
258
+ # |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT |
259
+ # +----+-----+-------+------+----------+----------+
260
+ # | 1 | 1 | X'00' | 1 | Variable | 2 |
261
+ # +----+-----+-------+------+----------+----------+
262
+ redir_ip, redir_port = @redir_local_address.ip_unpack
263
+ data = [ [ 5, 0, 0, 1 ].pack( 'C4' ), IPAddr.new( redir_ip ).hton, [ redir_port ].pack( 'n' ) ].join
264
+ add_src_wbuff( src, data )
265
+ end
266
+
267
+ def add_src_rbuff( src, data )
268
+ return if src.nil? || src.closed? || data.nil? || data.empty?
269
+ src_info = @src_infos[ src ]
270
+ puts "add src rbuff #{ data.bytesize }" if @is_debug
271
+ src_info[ :rbuff ] << data
272
+
273
+ if src_info[ :rbuff ].bytesize >= WBUFF_LIMIT then
274
+ puts "src rbuff full"
275
+ close_src( src )
276
+ end
277
+ end
278
+
279
+ def add_src_wbuff( src, data )
280
+ return if src.nil? || src.closed? || data.nil? || data.empty?
281
+ src_info = @src_infos[ src ]
282
+ src_info[ :wbuff ] << data
283
+ bytesize = src_info[ :wbuff ].bytesize
284
+ src_id = src_info[ :src_id ]
285
+ domain = src_info[ :destination_domain ]
286
+
287
+ if bytesize >= CLOSE_ABOVE then
288
+ puts "close overflow src #{ src_id } #{ domain }"
289
+ close_src( src )
290
+ return
291
+ end
292
+
293
+ if !src_info[ :overflowing ] && ( bytesize >= WBUFF_LIMIT ) then
294
+ if src_info[ :proxy_type ] == :direct then
295
+ puts "src overflow pause dst #{ src_id } #{ domain }"
296
+ @reads.delete( src_info[ :dst ] )
297
+ elsif src_info[ :proxy_type ] == :remote then
298
+ puts "add h_src_overflow #{ src_id } #{ domain }"
299
+ msg = "#{ @h_src_overflow }#{ [ src_id ].pack( 'Q>' ) }"
300
+ add_proxy_wbuff( pack_a_chunk( msg ) )
301
+ end
302
+
303
+ src_info[ :overflowing ] = true
304
+ end
305
+
306
+ add_write( src )
307
+ end
308
+
309
+ def add_write( sock )
310
+ return if sock.nil? || sock.closed? || @writes.include?( sock )
311
+ @writes << sock
312
+ role = @roles[ sock ]
313
+
314
+ if @update_roles.include?( role ) then
315
+ set_update( sock )
316
+ end
317
+ end
318
+
319
+ def check_expire_dnses
320
+ now = Time.new
321
+
322
+ @dns_infos.select{ | dns, _ | now.to_i - @updates[ dns ].to_i >= @expire_short_after }.each do | dns, info |
323
+ puts "expire dns #{ info[ :domain ] }" if @is_debug
324
+ close_dns( dns )
325
+ end
326
+ end
327
+
328
+ def check_expire_dsts
329
+ now = Time.new
330
+
331
+ @dst_infos.select{ | dst, info | info[ :connected ] ? ( now.to_i - @updates[ dst ].to_i >= @expire_long_after ) : ( now.to_i - @updates[ dst ].to_i >= @expire_connecting ) }.each do | dst, info |
332
+ puts "expire dst #{ info[ :domain ] }" if @is_debug
333
+ close_dst( dst )
334
+ end
335
+ end
336
+
337
+ def check_expire_mems
338
+ now = Time.new
339
+
340
+ @mem_infos.select{ | mem, _ | now.to_i - @updates[ mem ].to_i >= @expire_short_after }.each do | mem, _ |
341
+ puts "expire mem" if @is_debug
342
+ close_mem( mem )
343
+ end
344
+ end
345
+
346
+ def check_expire_nears
347
+ now = Time.new
348
+
349
+ @near_infos.select{ | _, info | now.to_i - info[ :created_at ].to_i >= @expire_short_after }.each do | near_id, info |
350
+ puts "expire near #{ info[ :domain ] }" if @is_debug
351
+ @near_infos.delete( near_id )
352
+ end
353
+ end
354
+
355
+ def check_expire_p1s
356
+ now = Time.new
357
+
358
+ @p1_infos.select{ | p1, info | info[ :connected ] ? ( now.to_i - @updates[ p1 ].to_i >= @expire_long_after ) : ( now.to_i - @updates[ p1 ].to_i >= @expire_connecting ) }.each do | p1, info |
359
+ puts "expire p1 #{ info[ :p2_id ] }" if @is_debug
360
+ close_p1( p1 )
361
+ end
362
+ end
363
+
364
+ def check_expire_rsvs
365
+ now = Time.new
366
+
367
+ @rsv_infos.select{ | rsv, _ | now.to_i - @updates[ rsv ].to_i >= @expire_short_after }.each do | rsv, info |
368
+ puts "expire rsv #{ info[ :domain ] }" if @is_debug
369
+ close_rsv( rsv )
370
+ end
371
+ end
372
+
373
+ def check_expire_srcs
374
+ now = Time.new
375
+
376
+ @src_infos.select{ | src, _ | now.to_i - @updates[ src ].to_i >= @expire_long_after }.each do | src, info |
377
+ puts "expire src #{ info[ :destination_domain ] }" if @is_debug
378
+ close_src( src )
379
+ end
380
+ end
381
+
382
+ def close_dns( dns )
383
+ return nil if dns.nil? || dns.closed?
384
+ close_sock( dns )
385
+ dns_info = @dns_infos.delete( dns )
386
+ puts "close dns #{ dns_info[ :domain ] }" if @is_debug
387
+ dns_info
388
+ end
389
+
390
+ def close_dst( dst )
391
+ return nil if dst.nil? || dst.closed?
392
+ close_sock( dst )
393
+ dst_info = @dst_infos.delete( dst )
394
+ puts "close dst #{ dst_info[ :domain ] }" if @is_debug
395
+ set_src_closing( dst_info[ :src ] ) if dst_info
396
+ dst_info
397
+ end
398
+
399
+ def close_mem( mem )
400
+ return nil if mem.nil? || mem.closed?
401
+ close_sock( mem )
402
+ @mem_infos.delete( mem )
403
+ end
404
+
405
+ def close_p1( p1 )
406
+ return nil if p1.nil? || p1.closed?
407
+ close_sock( p1 )
408
+ p1_info = @p1_infos.delete( p1 )
409
+
410
+ unless @proxy.closed? then
411
+ proxy_info = @proxy_infos[ @proxy ]
412
+ proxy_info[ :paused_p1s ].delete( p1 )
413
+ p2_id = p1_info[ :p2_id ]
414
+ puts "add h_p1_close #{ p2_id }"
415
+ msg = "#{ @h_p1_close }#{ [ p2_id ].pack( 'Q>' ) }"
416
+ add_proxy_wbuff( pack_a_chunk( msg ) )
417
+ end
418
+
419
+ p1_info
420
+ end
421
+
422
+ def close_proxy( proxy )
423
+ return if proxy.nil? || proxy.closed?
424
+ close_sock( proxy )
425
+ proxy_info = @proxy_infos.delete( proxy )
426
+ puts "close proxy"
427
+ @src_infos.each{ | src, _ | close_src( src ) }
428
+ @p1_infos.each{ | p1, _ | close_p1( p1 ) }
429
+ proxy_info
430
+ end
431
+
432
+ def close_rsv( rsv )
433
+ return nil if rsv.nil? || rsv.closed?
434
+ close_sock( rsv )
435
+ rsv_info = @rsv_infos.delete( rsv )
436
+ puts "close rsv #{ rsv_info[ :domain ] }" if @is_debug
437
+ rsv_info
438
+ end
439
+
440
+ def close_sock( sock )
441
+ return if sock.nil? || sock.closed?
442
+ sock.close
443
+ @reads.delete( sock )
444
+ @writes.delete( sock )
445
+ @updates.delete( sock )
446
+ @roles.delete( sock )
447
+ end
448
+
449
+ def close_src( src )
450
+ return nil if src.nil? || src.closed?
451
+ close_sock( src )
452
+ src_info = @src_infos.delete( src )
453
+ src_id = src_info[ :src_id ]
454
+ domain = src_info[ :destination_domain ]
455
+ puts "close src #{ domain }" if @is_debug
456
+
457
+ if src_info[ :proxy_type ] == :direct then
458
+ set_dst_closing( src_info[ :dst ] )
459
+ elsif ( src_info[ :proxy_type ] == :remote ) && !@proxy.closed? then
460
+ proxy_info = @proxy_infos[ @proxy ]
461
+ proxy_info[ :paused_srcs ].delete( src )
462
+ puts "add h_src_close #{ src_id }" if @is_debug
463
+ msg = "#{ @h_src_close }#{ [ src_id ].pack( 'Q>' ) }"
464
+ add_proxy_wbuff( pack_a_chunk( msg ) )
465
+ end
466
+
467
+ src_info
468
+ end
469
+
470
+ def deal_msg( data )
471
+ return if data.nil? || data.empty? || @proxy.closed?
472
+ proxy_info = @proxy_infos[ @proxy ]
473
+ now = Time.new
474
+ proxy_info[ :recv_at ] = now
475
+ h = data[ 0 ]
476
+
477
+ case h
478
+ when @h_a_new_p2 then
479
+ return if data.bytesize < 9
480
+ p2_id = data[ 1, 8 ].unpack( 'Q>' ).first
481
+ puts "got h_a_new_p2 #{ p2_id }"
482
+ new_a_p1( p2_id )
483
+ when @h_dst_close then
484
+ return if data.bytesize < 9
485
+ src_id = data[ 1, 8 ].unpack( 'Q>' ).first
486
+ puts "got h_dst_close #{ src_id }" if @is_debug
487
+ src, _ = @src_infos.find{ | _, info | info[ :src_id ] == src_id }
488
+ set_src_closing( src )
489
+ when @h_heartbeat then
490
+ puts "got h_heartbeat" if @is_debug
491
+ when @h_p2_close then
492
+ return if data.bytesize < 9
493
+ p2_id = data[ 1, 8 ].unpack( 'Q>' ).first
494
+ puts "got h_p2_close #{ p2_id }"
495
+ p1, _ = @p1_infos.find{ | _, info | info[ :p2_id ] == p2_id }
496
+ set_p1_closing( p1 )
497
+ when @h_p2_traffic then
498
+ return if data.bytesize < 9
499
+ p2_id = data[ 1, 8 ].unpack( 'Q>' ).first
500
+ data = data[ 9..-1 ]
501
+ # puts "got h_p2_traffic #{ p2_id } #{ data.bytesize }" if @is_debug
502
+ p1, _ = @p1_infos.find{ | _, info | info[ :p2_id ] == p2_id }
503
+ add_p1_wbuff( p1, data )
504
+ when @h_p2_overflow then
505
+ return if data.bytesize < 9
506
+ p2_id = data[ 1, 8 ].unpack( 'Q>' ).first
507
+ puts "got h_p2_overflow pause p1 #{ p2_id }"
508
+ p1, _ = @p1_infos.find{ | _, info | info[ :p2_id ] == p2_id }
509
+ @reads.delete( p1 )
510
+ proxy_info[ :paused_p1s ].delete( p1 )
511
+ when @h_p2_underhalf then
512
+ return if data.bytesize < 9
513
+ p2_id = data[ 1, 8 ].unpack( 'Q>' ).first
514
+ puts "got h_p2_underhalf #{ p2_id }"
515
+ p1, _ = @p1_infos.find{ | _, info | info[ :p2_id ] == p2_id }
516
+ add_read( p1 )
517
+ when @h_response then
518
+ return if data.bytesize < 3
519
+ near_id = data[ 1, 8 ].unpack( 'Q>' ).first
520
+ data = data[ 9..-1 ]
521
+ puts "got h_response #{ near_id } #{ data.bytesize }" if @is_debug
522
+ near_info = @near_infos.delete( near_id )
523
+
524
+ if near_info then
525
+ data[ 0, 2 ] = near_info[ :id ]
526
+ addrinfo = near_info[ :addrinfo ]
527
+ send_data( @rsvd, data, addrinfo )
528
+
529
+ begin
530
+ ip = seek_ip( data )
531
+ rescue Exception => e
532
+ puts "response seek ip #{ e.class } #{ e.message }"
533
+ end
534
+
535
+ if ip then
536
+ domain = near_info[ :domain ]
537
+ type = near_info[ :type ]
538
+
539
+ if type == 1 then
540
+ @response_caches[ domain ] = [ data, now, ip, true ]
541
+ else
542
+ @response6_caches[ domain ] = [ data, now, ip, true ]
543
+ end
544
+ end
545
+ end
546
+ when @h_traffic then
547
+ return if data.bytesize < 9
548
+ src_id = data[ 1, 8 ].unpack( 'Q>' ).first
549
+ data = data[ 9..-1 ]
550
+ # puts "got h_traffic #{ src_id } #{ data.bytesize }" if @is_debug
551
+ src, _ = @src_infos.find{ | _, info | info[ :src_id ] == src_id }
552
+ add_src_wbuff( src, data )
553
+ when @h_dst_overflow then
554
+ return if data.bytesize < 9
555
+ src_id = data[ 1, 8 ].unpack( 'Q>' ).first
556
+ puts "got h_dst_overflow pause src #{ src_id }"
557
+ src, _ = @src_infos.find{ | _, info | info[ :src_id ] == src_id }
558
+ @reads.delete( src )
559
+ proxy_info[ :paused_srcs ].delete( src )
560
+ when @h_dst_underhalf then
561
+ return if data.bytesize < 9
562
+ src_id = data[ 1, 8 ].unpack( 'Q>' ).first
563
+ puts "got h_dst_underhalf #{ src_id }"
564
+ src, _ = @src_infos.find{ | _, info | info[ :src_id ] == src_id }
565
+ add_read( src )
566
+ end
567
+ end
568
+
569
+ def decode_to_msgs( data )
570
+ msgs = []
571
+ part = ''
572
+
573
+ loop do
574
+ if data.bytesize <= 2 then
575
+ part = data
576
+ break
577
+ end
578
+
579
+ len = data[ 0, 2 ].unpack( 'n' ).first
580
+
581
+ if len == 0 then
582
+ puts "msg zero len?"
583
+ break
584
+ end
585
+
586
+ if data.bytesize < ( 2 + len ) then
587
+ part = data
588
+ break
589
+ end
590
+
591
+ msgs << data[ 2, len ]
592
+ data = data[ ( 2 + len )..-1 ]
593
+ break if data.empty?
594
+ end
595
+
596
+ [ msgs, part ]
597
+ end
598
+
599
+ def loop_heartbeat
600
+ Thread.new do
601
+ loop do
602
+ sleep HEARTBEAT_INTERVAL
603
+ msg = { message_type: 'heartbeat' }
604
+ send_data( @info, JSON.generate( msg ), @infod_addr )
605
+ end
606
+ end
607
+ end
608
+
609
+ def make_tunnel( ip, src )
610
+ return if src.nil? || src.closed?
611
+ src_info = @src_infos[ src ]
612
+ domain = src_info[ :destination_domain ]
613
+ port = src_info[ :destination_port ]
614
+
615
+ if @local_ips.include?( ip ) && [ @redir_port, @tspd_port ].include?( port ) then
616
+ puts "ignore #{ ip }:#{ port }"
617
+ close_src( src )
618
+ return
619
+ end
620
+
621
+ if [ domain, ip ].include?( @proxyd_host ) then
622
+ # 访问远端,直连
623
+ puts "direct #{ ip } #{ port }"
624
+ new_a_dst( ip, src )
625
+ return
626
+ end
627
+
628
+ if @is_direct_caches.include?( ip ) then
629
+ is_direct = @is_direct_caches[ ip ]
630
+ else
631
+ begin
632
+ is_direct = @directs.any?{ | direct | direct.include?( ip ) }
633
+ rescue IPAddr::InvalidAddressError => e
634
+ puts "make tunnel #{ e.class }"
635
+ close_src( src )
636
+ return
637
+ end
638
+
639
+ @is_direct_caches[ ip ] = is_direct
640
+ end
641
+
642
+ if is_direct then
643
+ new_a_dst( ip, src )
644
+ else
645
+ set_remote( src )
646
+ end
647
+ end
648
+
649
+ def new_a_dst( ip, src )
650
+ return if src.nil? || src.closed?
651
+ src_info = @src_infos[ src ]
652
+ domain = src_info[ :destination_domain ]
653
+ port = src_info[ :destination_port ]
654
+ check_expire_dsts
655
+
656
+ begin
657
+ destination_addr = Socket.sockaddr_in( port, ip )
658
+ dst = Socket.new( Socket::AF_INET, Socket::SOCK_STREAM, 0 )
659
+ rescue Exception => e
660
+ puts "new a dst #{ e.class } #{ domain } #{ ip }:#{ port }"
661
+ close_src( src )
662
+ return
663
+ end
664
+
665
+ dst.setsockopt( Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1 )
666
+
667
+ begin
668
+ dst.connect_nonblock( destination_addr )
669
+ rescue IO::WaitWritable
670
+ rescue Exception => e
671
+ puts "dst connect destination #{ e.class } #{ domain } #{ ip }:#{ port }"
672
+ dst.close
673
+ close_src( src )
674
+ return
675
+ end
676
+
677
+ dst_info = {
678
+ closing: false,
679
+ connected: false,
680
+ domain: domain,
681
+ ip: ip,
682
+ overflowing: false,
683
+ port: port,
684
+ src: src,
685
+ wbuff: ''
686
+ }
687
+
688
+ @dst_infos[ dst ] = dst_info
689
+ src_info[ :proxy_type ] = :direct
690
+ src_info[ :dst ] = dst
691
+
692
+ if src_info[ :proxy_proto ] == :http then
693
+ if src_info[ :is_connect ] then
694
+ puts "add HTTP_OK" if @is_debug
695
+ add_src_wbuff( src, HTTP_OK )
696
+ end
697
+ elsif src_info[ :proxy_proto ] == :socks5 then
698
+ puts "add_socks5_conn_reply" if @is_debug
699
+ add_socks5_conn_reply( src )
700
+ end
701
+
702
+ add_read( dst, :dst )
703
+ add_write( dst )
704
+ data = src_info[ :rbuff ].dup
705
+
706
+ unless data.empty? then
707
+ puts "move src rbuff to dst #{ domain } #{ data.bytesize }" if @is_debug
708
+ add_dst_wbuff( dst, data )
709
+ end
710
+ end
711
+
712
+ def new_a_infod( infod_port )
713
+ infod_ip = '127.0.0.1'
714
+ infod_addr = Socket.sockaddr_in( infod_port, infod_ip )
715
+ infod = Socket.new( Socket::AF_INET, Socket::SOCK_DGRAM, 0 )
716
+ infod.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEPORT, 1 ) if RUBY_PLATFORM.include?( 'linux' )
717
+ infod.bind( infod_addr )
718
+ puts "infod bind on #{ infod_ip } #{ infod_port }"
719
+ add_read( infod, :infod )
720
+ info = Socket.new( Socket::AF_INET, Socket::SOCK_DGRAM, 0 )
721
+ @infod_addr = infod_addr
722
+ @infod = infod
723
+ @info = info
724
+ end
725
+
726
+ def new_a_memd( memd_port )
727
+ memd_ip = '127.0.0.1'
728
+ memd = Socket.new( Socket::AF_INET, Socket::SOCK_STREAM, 0 )
729
+ memd.setsockopt( Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1 )
730
+ memd.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEPORT, 1 ) if RUBY_PLATFORM.include?( 'linux' )
731
+ memd.setsockopt( Socket::IPPROTO_TCP, Socket::TCP_FASTOPEN, 5 ) if @is_server_fastopen
732
+ memd.bind( Socket.sockaddr_in( memd_port, memd_ip ) )
733
+ memd.listen( 5 )
734
+ puts "memd listen on #{ memd_ip } #{ memd_port }"
735
+ add_read( memd, :memd )
736
+ end
737
+
738
+ def new_a_p1( p2_id )
739
+ check_expire_p1s
740
+
741
+ begin
742
+ p1 = Socket.new( Socket::AF_INET, Socket::SOCK_STREAM, 0 )
743
+ rescue Exception => e
744
+ puts "new a p1 #{ e.class } #{ p2_id }"
745
+ return
746
+ end
747
+
748
+ p1.setsockopt( Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1 )
749
+
750
+ begin
751
+ p1.connect_nonblock( @appd_addr )
752
+ rescue IO::WaitWritable
753
+ rescue Exception => e
754
+ puts "connect appd_addr #{ e.class } #{ p2_id }"
755
+ p1.close
756
+ return
757
+ end
758
+
759
+ p1_info = {
760
+ closing: false,
761
+ connected: false,
762
+ overflowing: false,
763
+ p2_id: p2_id,
764
+ wbuff: ''
765
+ }
766
+
767
+ @p1_infos[ p1 ] = p1_info
768
+ add_read( p1, :p1 )
769
+ add_write( p1 )
770
+ end
771
+
772
+ def new_a_proxy
773
+ proxy = Socket.new( Socket::AF_INET, Socket::SOCK_STREAM, 0 )
774
+ proxy.setsockopt( Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1 )
775
+
776
+ if @is_client_fastopen then
777
+ proxy.setsockopt( Socket::IPPROTO_TCP, Socket::TCP_FASTOPEN, 5 )
778
+ else
779
+ begin
780
+ proxy.connect_nonblock( @proxyd_addr )
781
+ rescue IO::WaitWritable
782
+ rescue Exception => e
783
+ puts "connect proxyd #{ e.class }"
784
+ proxy.close
785
+ return
786
+ end
787
+ end
788
+
789
+ puts "im #{ @im }"
790
+ chars = []
791
+ @head_len.times{ chars << rand( 256 ) }
792
+ head = "#{ chars.pack( 'C*' ) }#{ [ @im.bytesize ].pack( 'C' ) }#{ @im }"
793
+
794
+ proxy_info = {
795
+ is_syn: @is_client_fastopen,
796
+ paused_p1s: [],
797
+ paused_srcs: [],
798
+ rbuff: '',
799
+ recv_at: nil,
800
+ wbuff: head
801
+ }
802
+
803
+ @proxy = proxy
804
+ @proxy_infos[ proxy ] = proxy_info
805
+ add_read( proxy, :proxy )
806
+ add_write( proxy )
807
+ proxy_info
808
+ end
809
+
810
+ def new_a_redir( redir_port )
811
+ redir_ip = '0.0.0.0'
812
+ redir = Socket.new( Socket::AF_INET, Socket::SOCK_STREAM, 0 )
813
+ redir.setsockopt( Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1 )
814
+ redir.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEADDR, 1 )
815
+ redir.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEPORT, 1 ) if RUBY_PLATFORM.include?( 'linux' )
816
+ redir.setsockopt( Socket::IPPROTO_TCP, Socket::TCP_FASTOPEN, BACKLOG ) if @is_server_fastopen
817
+ redir.bind( Socket.sockaddr_in( redir_port, redir_ip ) )
818
+ redir.listen( BACKLOG )
819
+ puts "redir listen on #{ redir_ip } #{ redir_port }"
820
+ add_read( redir, :redir )
821
+ @redir_port = redir_port
822
+ @redir_local_address = redir.local_address
823
+ end
824
+
825
+ def new_a_rsv( data, addrinfo, domain, type )
826
+ check_expire_rsvs
827
+ rsv = Socket.new( Socket::AF_INET, Socket::SOCK_DGRAM, 0 )
828
+
829
+ begin
830
+ @nameserver_addrs.each{ | addr | rsv.sendmsg( data, 0, addr ) }
831
+ rescue Exception => e
832
+ puts "rsv send data #{ e.class }"
833
+ rsv.close
834
+ return
835
+ end
836
+
837
+ rsv_info = {
838
+ addrinfo: addrinfo,
839
+ domain: domain,
840
+ type: type
841
+ }
842
+
843
+ @rsv_infos[ rsv ] = rsv_info
844
+ add_read( rsv, :rsv )
845
+ end
846
+
847
+ def new_a_rsvd( rsvd_port )
848
+ rsvd_ip = '0.0.0.0'
849
+ rsvd_addr = Socket.sockaddr_in( rsvd_port, rsvd_ip )
850
+ rsvd = Socket.new( Socket::AF_INET, Socket::SOCK_DGRAM, 0 )
851
+ rsvd.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEPORT, 1 ) if RUBY_PLATFORM.include?( 'linux' )
852
+ rsvd.bind( rsvd_addr )
853
+ puts "rsvd bind on #{ rsvd_ip } #{ rsvd_port }"
854
+ add_read( rsvd, :rsvd )
855
+ @rsvd = rsvd
856
+ end
857
+
858
+ def new_a_tspd( tspd_port )
859
+ tspd_ip = '0.0.0.0'
860
+ tspd = Socket.new( Socket::AF_INET, Socket::SOCK_STREAM, 0 )
861
+ tspd.setsockopt( Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1 )
862
+ tspd.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEADDR, 1 )
863
+ tspd.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEPORT, 1 ) if RUBY_PLATFORM.include?( 'linux' )
864
+ tspd.setsockopt( Socket::IPPROTO_TCP, Socket::TCP_FASTOPEN, BACKLOG ) if @is_server_fastopen
865
+ tspd.bind( Socket.sockaddr_in( tspd_port, tspd_ip ) )
866
+ tspd.listen( BACKLOG )
867
+ puts "tspd listen on #{ tspd_ip } #{ tspd_port }"
868
+ add_read( tspd, :tspd )
869
+ @tspd_port = tspd_port
870
+ end
871
+
872
+ def pack_a_chunk( msg )
873
+ "#{ [ msg.bytesize ].pack( 'n' ) }#{ msg }"
874
+ end
875
+
876
+ def pack_p2_traffic( p2_id, data )
877
+ chunks = ''
878
+
879
+ loop do
880
+ part = data[ 0, 65526 ]
881
+ # puts "add h_p2_traffic #{ p2_id } #{ part.bytesize }" if @is_debug
882
+ msg = "#{ @h_p2_traffic }#{ [ p2_id ].pack( 'Q>' ) }#{ part }"
883
+ chunks << pack_a_chunk( msg )
884
+ data = data[ part.bytesize..-1 ]
885
+ break if data.empty?
886
+ end
887
+
888
+ chunks
889
+ end
890
+
891
+ def pack_traffic( src_id, data )
892
+ chunks = ''
893
+
894
+ loop do
895
+ part = data[ 0, 65526 ]
896
+ # puts "add h_traffic #{ src_id } #{ part.bytesize }" if @is_debug
897
+ msg = "#{ @h_traffic }#{ [ src_id ].pack( 'Q>' ) }#{ part }"
898
+ chunks << pack_a_chunk( msg )
899
+ data = data[ part.bytesize..-1 ]
900
+ break if data.empty?
901
+ end
902
+
903
+ chunks
904
+ end
905
+
906
+ def read_dns( dns )
907
+ begin
908
+ data, addrinfo, rflags, *controls = dns.recvmsg
909
+ rescue Exception => e
910
+ puts "dns recvmsg #{ e.class }"
911
+ close_dns( dns )
912
+ return
913
+ end
914
+
915
+ return if data.empty?
916
+
917
+ begin
918
+ ip = seek_ip( data )
919
+ rescue Exception => e
920
+ puts "dns seek ip #{ e.class } #{ e.message }"
921
+ close_dns( dns )
922
+ return
923
+ end
924
+
925
+ dns_info = @dns_infos[ dns ]
926
+ domain = dns_info[ :domain ]
927
+
928
+ if ip then
929
+ src = dns_info[ :src ]
930
+ make_tunnel( ip, src )
931
+ puts "set resolv cache #{ domain } #{ ip }" if @is_debug
932
+ @resolv_caches[ domain ] = [ ip, Time.new ]
933
+ else
934
+ puts "no ip in answer #{ domain }"
935
+ close_src( src )
936
+ end
937
+
938
+ close_dns( dns )
939
+ end
940
+
941
+ def read_dst( dst )
942
+ begin
943
+ data = dst.read_nonblock( READ_SIZE )
944
+ rescue Errno::ENOTCONN => e
945
+ return
946
+ rescue Exception => e
947
+ close_dst( dst )
948
+ return
949
+ end
950
+
951
+ set_update( dst )
952
+ dst_info = @dst_infos[ dst ]
953
+ # puts "read dst #{ dst_info[ :domain ] } #{ data.bytesize }" if @is_debug
954
+ src = dst_info[ :src ]
955
+ add_src_wbuff( src, data )
956
+ end
957
+
958
+ def read_infod( infod )
959
+ begin
960
+ data, addrinfo, rflags, *controls = infod.recvmsg
961
+ rescue Exception => e
962
+ puts "infod recvmsg #{ e.class }"
963
+ return
964
+ end
965
+
966
+ return if data.empty?
967
+
968
+ begin
969
+ msg = JSON.parse( data, symbolize_names: true )
970
+ rescue JSON::ParserError, EncodingError => e
971
+ puts "read infod #{ e.class }"
972
+ return
973
+ end
974
+
975
+ message_type = msg[ :message_type ]
976
+
977
+ case message_type
978
+ when 'heartbeat' then
979
+ if @proxy.closed? then
980
+ new_a_proxy
981
+ else
982
+ proxy_info = @proxy_infos[ @proxy ]
983
+
984
+ if Time.new.to_i - proxy_info[ :recv_at ].to_i >= @expire_proxy_after then
985
+ close_proxy( @proxy )
986
+ new_a_proxy
987
+ else
988
+ puts "heartbeat" if @is_debug
989
+ add_proxy_wbuff( pack_a_chunk( @h_heartbeat ) )
990
+ end
991
+ end
992
+ end
993
+ end
994
+
995
+ def read_mem( mem )
996
+ begin
997
+ mem.read_nonblock( READ_SIZE )
998
+ rescue Errno::ENOTCONN => e
999
+ return
1000
+ rescue Exception => e
1001
+ close_mem( mem )
1002
+ return
1003
+ end
1004
+
1005
+ set_update( mem )
1006
+ src_arr = []
1007
+
1008
+ @src_infos.each do | _, info |
1009
+ src_arr << {
1010
+ addrinfo: info[ :addrinfo ].ip_unpack,
1011
+ destination_domain: info[ :destination_domain ],
1012
+ destination_port: info[ :destination_port ]
1013
+ }
1014
+ end
1015
+
1016
+ msg = {
1017
+ resolv_caches: @resolv_caches.sort,
1018
+ response_caches: @response_caches.sort.map{ | a | [ a[ 0 ], a[ 1 ][ 2 ], a[ 1 ][ 3 ] ] },
1019
+ response6_caches: @response6_caches.sort.map{ | a | [ a[ 0 ], a[ 1 ][ 2 ], a[ 1 ][ 3 ] ] },
1020
+ sizes: {
1021
+ directs: @directs.size,
1022
+ remotes: @remotes.size,
1023
+ reads: @reads.size,
1024
+ writes: @writes.size,
1025
+ roles: @roles.size,
1026
+ updates: @updates.size,
1027
+ proxy_infos: @proxy_infos.size,
1028
+ mem_infos: @mem_infos.size,
1029
+ src_infos: @src_infos.size,
1030
+ dst_infos: @dst_infos.size,
1031
+ dns_infos: @dns_infos.size,
1032
+ rsv_infos: @rsv_infos.size,
1033
+ near_infos: @near_infos.size,
1034
+ resolv_caches: @resolv_caches.size,
1035
+ is_direct_caches: @is_direct_caches.size,
1036
+ response_caches: @response_caches.size,
1037
+ response6_caches: @response6_caches.size,
1038
+ p1_infos: @p1_infos.size
1039
+ },
1040
+ updates_limit: @updates_limit,
1041
+ eliminate_count: @eliminate_count,
1042
+ src_arr: src_arr
1043
+ }
1044
+
1045
+ add_mem_wbuff( mem, JSON.generate( msg ) )
1046
+ end
1047
+
1048
+ def read_memd( memd )
1049
+ check_expire_mems
1050
+
1051
+ begin
1052
+ mem, addrinfo = memd.accept_nonblock
1053
+ rescue Exception => e
1054
+ puts "memd accept #{ e.class }"
1055
+ return
1056
+ end
1057
+
1058
+ mem_info = {
1059
+ wbuff: ''
1060
+ }
1061
+
1062
+ @mem_infos[ mem ] = mem_info
1063
+ add_read( mem, :mem )
1064
+ end
1065
+
1066
+ def read_p1( p1 )
1067
+ begin
1068
+ data = p1.read_nonblock( READ_SIZE )
1069
+ rescue Errno::ENOTCONN => e
1070
+ return
1071
+ rescue Exception => e
1072
+ close_p1( p1 )
1073
+ return
1074
+ end
1075
+
1076
+ set_update( p1 )
1077
+
1078
+ if @proxy.closed? then
1079
+ close_p1( p1 )
1080
+ return
1081
+ end
1082
+
1083
+ p1_info = @p1_infos[ p1 ]
1084
+ p2_id = p1_info[ :p2_id ]
1085
+ # puts "read p1 #{ p2_id } #{ data.bytesize }" if @is_debug
1086
+ add_proxy_wbuff( pack_p2_traffic( p2_id, data ) )
1087
+
1088
+ unless @proxy.closed? then
1089
+ proxy_info = @proxy_infos[ @proxy ]
1090
+ bytesize = proxy_info[ :wbuff ].bytesize
1091
+
1092
+ if ( bytesize >= WBUFF_LIMIT ) && !proxy_info[ :paused_p1s ].include?( p1 ) then
1093
+ puts "proxy overflow pause p1 #{ p2_id }"
1094
+ @reads.delete( p1 )
1095
+ proxy_info[ :paused_p1s ] << p1
1096
+ end
1097
+ end
1098
+ end
1099
+
1100
+ def read_proxy( proxy )
1101
+ begin
1102
+ data = proxy.read_nonblock( READ_SIZE )
1103
+ rescue Errno::ENOTCONN => e
1104
+ return
1105
+ rescue Exception => e
1106
+ close_proxy( proxy )
1107
+ return
1108
+ end
1109
+
1110
+ set_update( proxy )
1111
+ proxy_info = @proxy_infos[ proxy ]
1112
+ data = "#{ proxy_info[ :rbuff ] }#{ data }"
1113
+
1114
+ msgs, part = decode_to_msgs( data )
1115
+ msgs.each{ | msg | deal_msg( msg ) }
1116
+ proxy_info[ :rbuff ] = part
1117
+ end
1118
+
1119
+ def read_redir( redir )
1120
+ check_expire_srcs
1121
+
1122
+ begin
1123
+ src, addrinfo = redir.accept_nonblock
1124
+ rescue IO::WaitReadable, Errno::EINTR => e
1125
+ puts "redir accept #{ e.class }"
1126
+ return
1127
+ end
1128
+
1129
+ puts "redir accept a src #{ addrinfo.ip_unpack.inspect }" if @is_debug
1130
+ src_id = rand( ( 2 ** 64 ) - 2 ) + 1
1131
+
1132
+ src_info = {
1133
+ addrinfo: addrinfo,
1134
+ closing: false,
1135
+ destination_domain: nil,
1136
+ destination_port: nil,
1137
+ dst: nil,
1138
+ is_connect: true,
1139
+ overflowing: false,
1140
+ proxy_proto: :uncheck, # :uncheck / :http / :socks5
1141
+ proxy_type: :uncheck, # :uncheck / :checking / :negotiation / :remote / :direct
1142
+ rbuff: '',
1143
+ src_id: src_id,
1144
+ wbuff: ''
1145
+ }
1146
+
1147
+ @src_infos[ src ] = src_info
1148
+ add_read( src, :src )
1149
+ end
1150
+
1151
+ def read_rsv( rsv )
1152
+ begin
1153
+ data, addrinfo, rflags, *controls = rsv.recvmsg
1154
+ rescue Exception => e
1155
+ puts "rsv recvmsg #{ e.class }"
1156
+ close_rsv( rsv )
1157
+ return
1158
+ end
1159
+
1160
+ return if data.empty?
1161
+
1162
+ rsv_info = @rsv_infos[ rsv ]
1163
+ addrinfo = rsv_info[ :addrinfo ]
1164
+ domain = rsv_info[ :domain ]
1165
+ type = rsv_info[ :type ]
1166
+ send_data( @rsvd, data, addrinfo )
1167
+
1168
+ begin
1169
+ ip = seek_ip( data )
1170
+ rescue Exception => e
1171
+ puts "rsv seek ip #{ e.class } #{ e.message }"
1172
+ close_rsv( rsv )
1173
+ return
1174
+ end
1175
+
1176
+ if ip then
1177
+ if type == 1 then
1178
+ puts "set response cache #{ domain } #{ ip }" if @is_debug
1179
+ @response_caches[ domain ] = [ data, Time.new, ip, false ]
1180
+ else
1181
+ puts "set response6 cache #{ domain } #{ ip }" if @is_debug
1182
+ @response6_caches[ domain ] = [ data, Time.new, ip, false ]
1183
+ end
1184
+ end
1185
+
1186
+ close_rsv( rsv )
1187
+ end
1188
+
1189
+ def read_rsvd( rsvd )
1190
+ begin
1191
+ data, addrinfo, rflags, *controls = rsvd.recvmsg
1192
+ rescue Exception => e
1193
+ puts "rsvd recvmsg #{ e.class }"
1194
+ return
1195
+ end
1196
+
1197
+ return if data.empty?
1198
+
1199
+ begin
1200
+ id, domain, type = seek_question_dn( data )
1201
+ rescue Exception => e
1202
+ puts "seek question dn #{ e.class } #{ e.message }"
1203
+ return
1204
+ end
1205
+
1206
+ return unless [ 1, 12, 28 ].include?( type )
1207
+
1208
+ if type == 12 then
1209
+ new_a_rsv( data, addrinfo, domain, type )
1210
+ return
1211
+ end
1212
+
1213
+ if type == 1 then
1214
+ response_cache = @response_caches[ domain ]
1215
+ else
1216
+ response_cache = @response6_caches[ domain ]
1217
+ end
1218
+
1219
+ if response_cache then
1220
+ response, created_at = response_cache
1221
+
1222
+ if Time.new - created_at < @expire_resolv_cache then
1223
+ response[ 0, 2 ] = id
1224
+ send_data( @rsvd, response, addrinfo )
1225
+ return
1226
+ end
1227
+
1228
+ if type == 1 then
1229
+ @response_caches.delete( domain )
1230
+ else
1231
+ @response6_caches.delete( domain )
1232
+ end
1233
+ end
1234
+
1235
+ if @remotes.any?{ | r | domain.include?( r ) } then
1236
+ check_expire_nears
1237
+ near_id = rand( ( 2 ** 64 ) - 2 ) + 1
1238
+
1239
+ near_info = {
1240
+ addrinfo: addrinfo,
1241
+ created_at: Time.new,
1242
+ domain: domain,
1243
+ id: id,
1244
+ type: type
1245
+ }
1246
+
1247
+ @near_infos[ near_id ] = near_info
1248
+ puts "add h_query #{ near_id } #{ type } #{ domain }" if @is_debug
1249
+ msg = "#{ @h_query }#{ [ near_id, type ].pack( 'Q>C' ) }#{ domain }"
1250
+ add_proxy_wbuff( pack_a_chunk( msg ) )
1251
+ return
1252
+ end
1253
+
1254
+ new_a_rsv( data, addrinfo, domain, type )
1255
+ end
1256
+
1257
+ def read_src( src )
1258
+ begin
1259
+ data = src.read_nonblock( READ_SIZE )
1260
+ rescue Errno::ENOTCONN => e
1261
+ return
1262
+ rescue Exception => e
1263
+ close_src( src )
1264
+ return
1265
+ end
1266
+
1267
+ set_update( src )
1268
+ src_info = @src_infos[ src ]
1269
+ proxy_type = src_info[ :proxy_type ]
1270
+
1271
+ case proxy_type
1272
+ when :uncheck then
1273
+ if data[ 0, 7 ] == 'CONNECT' then
1274
+ domain_port = data.split( "\r\n" )[ 0 ].split( ' ' )[ 1 ]
1275
+
1276
+ unless domain_port then
1277
+ puts "CONNECT miss domain"
1278
+ close_src( src )
1279
+ return
1280
+ end
1281
+ elsif data[ 0 ].unpack( 'C' ).first == 5 then
1282
+ # https://tools.ietf.org/html/rfc1928
1283
+ #
1284
+ # +----+----------+----------+
1285
+ # |VER | NMETHODS | METHODS |
1286
+ # +----+----------+----------+
1287
+ # | 1 | 1 | 1 to 255 |
1288
+ # +----+----------+----------+
1289
+ nmethods = data[ 1 ].unpack( 'C' ).first
1290
+ methods = data[ 2, nmethods ].unpack( 'C*' )
1291
+
1292
+ unless methods.include?( 0 ) then
1293
+ puts "miss method 00"
1294
+ close_src( src )
1295
+ return
1296
+ end
1297
+
1298
+ # +----+--------+
1299
+ # |VER | METHOD |
1300
+ # +----+--------+
1301
+ # | 1 | 1 |
1302
+ # +----+--------+
1303
+ puts "read src version 5 nmethods #{ nmethods } methods #{ methods.inspect }" if @is_debug
1304
+ data2 = [ 5, 0 ].pack( 'CC' )
1305
+ add_src_wbuff( src, data2 )
1306
+ return if src.closed?
1307
+ src_info[ :proxy_proto ] = :socks5
1308
+ src_info[ :proxy_type ] = :negotiation
1309
+ return
1310
+ else
1311
+ host_line = data.split( "\r\n" ).find{ | _line | _line[ 0, 6 ] == 'Host: ' }
1312
+
1313
+ unless host_line then
1314
+ close_src( src )
1315
+ return
1316
+ end
1317
+
1318
+ lines = data.split( "\r\n" )
1319
+
1320
+ unless lines.empty? then
1321
+ method, url, proto = lines.first.split( ' ' )
1322
+
1323
+ if proto && url && proto[ 0, 4 ] == 'HTTP' && url[ 0, 7 ] == 'http://' then
1324
+ domain_port = url.split( '/' )[ 2 ]
1325
+ end
1326
+ end
1327
+
1328
+ unless domain_port then
1329
+ domain_port = host_line.split( ' ' )[ 1 ]
1330
+
1331
+ unless domain_port then
1332
+ puts "Host line miss domain"
1333
+ close_src( src )
1334
+ return
1335
+ end
1336
+ end
1337
+
1338
+ src_info[ :is_connect ] = false
1339
+ add_src_rbuff( src, data )
1340
+ end
1341
+
1342
+ colon_idx = domain_port.rindex( ':' )
1343
+ close_idx = domain_port.rindex( ']' )
1344
+
1345
+ if colon_idx && ( close_idx.nil? || ( colon_idx > close_idx ) ) then
1346
+ domain = domain_port[ 0...colon_idx ]
1347
+ port = domain_port[ ( colon_idx + 1 )..-1 ].to_i
1348
+ else
1349
+ domain = domain_port
1350
+ port = 80
1351
+ end
1352
+
1353
+ domain = domain.gsub( /\[|\]/, '' )
1354
+ src_info[ :proxy_proto ] = :http
1355
+ src_info[ :destination_domain ] = domain
1356
+ src_info[ :destination_port ] = port
1357
+ resolve_domain( domain, src )
1358
+ when :checking then
1359
+ add_src_rbuff( src, data )
1360
+ when :negotiation then
1361
+ # +----+-----+-------+------+----------+----------+
1362
+ # |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT |
1363
+ # +----+-----+-------+------+----------+----------+
1364
+ # | 1 | 1 | X'00' | 1 | Variable | 2 |
1365
+ # +----+-----+-------+------+----------+----------+
1366
+ ver, cmd, rsv, atyp = data[ 0, 4 ].unpack( 'C4' )
1367
+
1368
+ if cmd == 1 then
1369
+ if atyp == 1 then
1370
+ destination_host, destination_port = data[ 4, 6 ].unpack( 'Nn' )
1371
+
1372
+ begin
1373
+ destination_addr = Socket.sockaddr_in( destination_port, destination_host )
1374
+ destination_addrinfo = Addrinfo.new( destination_addr )
1375
+ rescue Exception => e
1376
+ puts "new addrinfo #{ e.class }"
1377
+ close_src( src )
1378
+ return
1379
+ end
1380
+
1381
+ destination_ip = destination_addrinfo.ip_address
1382
+ puts "read src cmd #{ cmd } atyp #{ atyp } #{ destination_ip } #{ destination_port }" if @is_debug
1383
+ src_info[ :destination_domain ] = destination_ip
1384
+ src_info[ :destination_port ] = destination_port
1385
+ make_tunnel( destination_ip, src )
1386
+ elsif atyp == 3 then
1387
+ domain_len = data[ 4 ].unpack( 'C' ).first
1388
+
1389
+ if ( domain_len + 7 ) == data.bytesize then
1390
+ domain = data[ 5, domain_len ]
1391
+ port = data[ ( 5 + domain_len ), 2 ].unpack( 'n' ).first
1392
+ puts "read src cmd #{ cmd } atyp #{ atyp } #{ domain } #{ port }" if @is_debug
1393
+ src_info[ :destination_domain ] = domain
1394
+ src_info[ :destination_port ] = port
1395
+ resolve_domain( domain, src )
1396
+ end
1397
+ else
1398
+ puts "socks5 atyp #{ atyp } not implement"
1399
+ close_src( src )
1400
+ end
1401
+ else
1402
+ puts "socks5 cmd #{ cmd } not implement"
1403
+ close_src( src )
1404
+ end
1405
+ when :remote then
1406
+ src_id = src_info[ :src_id ]
1407
+ add_proxy_wbuff( pack_traffic( src_id, data ) )
1408
+
1409
+ unless @proxy.closed? then
1410
+ proxy_info = @proxy_infos[ @proxy ]
1411
+ bytesize = proxy_info[ :wbuff ].bytesize
1412
+
1413
+ if ( bytesize >= WBUFF_LIMIT ) && !proxy_info[ :paused_srcs ].include?( src ) then
1414
+ puts "proxy overflow pause src #{ src_id } #{ src_info[ :destination_domain ] }"
1415
+ @reads.delete( src )
1416
+ proxy_info[ :paused_srcs ] << src
1417
+ end
1418
+ end
1419
+ when :direct then
1420
+ dst = src_info[ :dst ]
1421
+
1422
+ if dst then
1423
+ add_dst_wbuff( dst, data )
1424
+ else
1425
+ add_src_rbuff( src, data )
1426
+ end
1427
+ end
1428
+ end
1429
+
1430
+ def read_tspd( tspd )
1431
+ check_expire_srcs
1432
+
1433
+ begin
1434
+ src, addrinfo = tspd.accept_nonblock
1435
+ rescue IO::WaitReadable, Errno::EINTR => e
1436
+ puts "tspd accept #{ e.class }"
1437
+ return
1438
+ end
1439
+
1440
+ puts "tspd accept a src #{ addrinfo.ip_unpack.inspect }" if @is_debug
1441
+
1442
+ begin
1443
+ # /usr/include/linux/netfilter_ipv4.h
1444
+ option = src.getsockopt( Socket::SOL_IP, 80 )
1445
+ rescue Exception => e
1446
+ puts "get SO_ORIGINAL_DST #{ e.class } #{ addrinfo.ip_unpack.inspect }"
1447
+ src.close
1448
+ return
1449
+ end
1450
+
1451
+ dest_family, dest_port, dest_host = option.unpack( 'nnN' )
1452
+ dest_addr = Socket.sockaddr_in( dest_port, dest_host )
1453
+ dest_addrinfo = Addrinfo.new( dest_addr )
1454
+ dest_ip = dest_addrinfo.ip_address
1455
+ src_id = rand( ( 2 ** 64 ) - 2 ) + 1
1456
+
1457
+ src_info = {
1458
+ addrinfo: addrinfo,
1459
+ closing: false,
1460
+ destination_domain: dest_ip,
1461
+ destination_port: dest_port,
1462
+ dst: nil,
1463
+ is_connect: true,
1464
+ overflowing: false,
1465
+ proxy_proto: :uncheck, # :uncheck / :http / :socks5
1466
+ proxy_type: :uncheck, # :uncheck / :checking / :negotiation / :remote / :direct
1467
+ rbuff: '',
1468
+ src_id: src_id,
1469
+ wbuff: ''
1470
+ }
1471
+
1472
+ @src_infos[ src ] = src_info
1473
+ add_read( src, :src )
1474
+ make_tunnel( dest_ip, src )
1475
+ end
1476
+
1477
+ def resolve_domain( domain, src )
1478
+ return if src.nil? || src.closed?
1479
+
1480
+ unless domain =~ /^[0-9a-zA-Z\-\.]{1,63}$/ then
1481
+ # 忽略非法域名
1482
+ puts "ignore #{ domain }"
1483
+ close_src( src )
1484
+ return
1485
+ end
1486
+
1487
+ if domain == 'localhost' then
1488
+ domain = "127.0.0.1"
1489
+ end
1490
+
1491
+ if domain =~ /^\d{1,3}\.\d{1,3}\.\d{1,3}.\d{1,3}$/ then
1492
+ # ipv4
1493
+ make_tunnel( domain, src )
1494
+ return
1495
+ end
1496
+
1497
+ if @remotes.any?{ | remote | ( domain.size >= remote.size ) && ( domain[ ( remote.size * -1 )..-1 ] == remote ) } then
1498
+ set_remote( src )
1499
+ return
1500
+ end
1501
+
1502
+ resolv_cache = @resolv_caches[ domain ]
1503
+
1504
+ if resolv_cache then
1505
+ ip, created_at = resolv_cache
1506
+
1507
+ if Time.new - created_at < @expire_resolv_cache then
1508
+ make_tunnel( ip, src )
1509
+ return
1510
+ end
1511
+
1512
+ @resolv_caches.delete( domain )
1513
+ end
1514
+
1515
+ begin
1516
+ data = pack_a_query( domain )
1517
+ rescue Exception => e
1518
+ puts "pack a query #{ e.class } #{ e.message } #{ domain }"
1519
+ close_src( src )
1520
+ return
1521
+ end
1522
+
1523
+ check_expire_dnses
1524
+ dns = Socket.new( Socket::AF_INET, Socket::SOCK_DGRAM, 0 )
1525
+
1526
+ begin
1527
+ @nameserver_addrs.each{ | addr | dns.sendmsg( data, 0, addr ) }
1528
+ rescue Exception => e
1529
+ puts "dns send data #{ e.class }"
1530
+ dns.close
1531
+ close_src( src )
1532
+ return
1533
+ end
1534
+
1535
+ dns_info = {
1536
+ domain: domain,
1537
+ src: src
1538
+ }
1539
+
1540
+ @dns_infos[ dns ] = dns_info
1541
+ add_read( dns, :dns )
1542
+ src_info = @src_infos[ src ]
1543
+ src_info[ :proxy_type ] = :checking
1544
+ end
1545
+
1546
+ def send_data( sock, data, target_addr )
1547
+ begin
1548
+ sock.sendmsg( data, 0, target_addr )
1549
+ rescue Exception => e
1550
+ puts "sendmsg #{ e.class }"
1551
+ end
1552
+ end
1553
+
1554
+ def set_dst_closing( dst )
1555
+ return if dst.nil? || dst.closed?
1556
+ dst_info = @dst_infos[ dst ]
1557
+ return if dst_info.nil? || dst_info[ :closing ]
1558
+ dst_info[ :closing ] = true
1559
+ add_write( dst )
1560
+ end
1561
+
1562
+ def set_p1_closing( p1 )
1563
+ return if p1.nil? || p1.closed?
1564
+ p1_info = @p1_infos[ p1 ]
1565
+ return if p1_info.nil? || p1_info[ :closing ]
1566
+ p1_info[ :closing ] = true
1567
+ add_write( p1 )
1568
+ end
1569
+
1570
+ def set_remote( src )
1571
+ return if src.nil? || src.closed?
1572
+
1573
+ if @proxy.closed? then
1574
+ close_src( src )
1575
+ return
1576
+ end
1577
+
1578
+ src_info = @src_infos[ src ]
1579
+ src_info[ :proxy_type ] = :remote
1580
+
1581
+ if src_info[ :proxy_proto ] == :http then
1582
+ if src_info[ :is_connect ] then
1583
+ puts "add HTTP_OK #{ src_info[ :proxy_type ] }" if @is_debug
1584
+ add_src_wbuff( src, HTTP_OK )
1585
+ end
1586
+ elsif src_info[ :proxy_proto ] == :socks5 then
1587
+ puts "add_socks5_conn_reply #{ src_info[ :proxy_type ] }" if @is_debug
1588
+ add_socks5_conn_reply( src )
1589
+ end
1590
+
1591
+ src_id = src_info[ :src_id ]
1592
+ domain = src_info[ :destination_domain ]
1593
+ port = src_info[ :destination_port ]
1594
+ domain_port = [ domain, port ].join( ':' )
1595
+ puts "add h_a_new_source #{ src_id } #{ domain_port }" if @is_debug
1596
+ msg = "#{ @h_a_new_source }#{ [ src_id ].pack( 'Q>' ) }#{ domain_port }"
1597
+ add_proxy_wbuff( pack_a_chunk( msg ) )
1598
+ data = src_info[ :rbuff ].dup
1599
+
1600
+ unless data.empty? then
1601
+ puts "move src rbuff to proxy #{ domain } #{ data.bytesize }" if @is_debug
1602
+ add_proxy_wbuff( pack_traffic( src_id, data ) )
1603
+ end
1604
+ end
1605
+
1606
+ def set_src_closing( src )
1607
+ return if src.nil? || src.closed?
1608
+ src_info = @src_infos[ src ]
1609
+ return if src_info.nil? || src_info[ :closing ]
1610
+ src_info[ :closing ] = true
1611
+ add_write( src )
1612
+ end
1613
+
1614
+ def set_update( sock )
1615
+ @updates[ sock ] = Time.new
1616
+
1617
+ if @updates_limit - @updates.size <= 20 then
1618
+ puts "updates #{ @updates.size }"
1619
+ end
1620
+
1621
+ if @updates.size >= @updates_limit then
1622
+ puts "eliminate updates"
1623
+
1624
+ @updates.keys.each do | _sock |
1625
+ case @roles[ _sock ]
1626
+ when :dns
1627
+ close_dns( _sock )
1628
+ when :dst
1629
+ close_dst( _sock )
1630
+ when :mem
1631
+ close_mem( _sock )
1632
+ when :p1
1633
+ close_p1( _sock )
1634
+ when :rsv
1635
+ close_rsv( _sock )
1636
+ when :src
1637
+ close_src( _sock )
1638
+ else
1639
+ close_sock( _sock )
1640
+ end
1641
+ end
1642
+
1643
+ @eliminate_count += 1
1644
+ end
1645
+ end
1646
+
1647
+ def write_dst( dst )
1648
+ if dst.closed? then
1649
+ puts "write closed dst?"
1650
+ return
1651
+ end
1652
+
1653
+ dst_info = @dst_infos[ dst ]
1654
+ dst_info[ :connected ] = true
1655
+ data = dst_info[ :wbuff ]
1656
+
1657
+ if data.empty? then
1658
+ if dst_info[ :closing ] then
1659
+ close_dst( dst )
1660
+ else
1661
+ @writes.delete( dst )
1662
+ end
1663
+
1664
+ return
1665
+ end
1666
+
1667
+ begin
1668
+ written = dst.write_nonblock( data )
1669
+ rescue Errno::EINPROGRESS
1670
+ return
1671
+ rescue Exception => e
1672
+ close_dst( dst )
1673
+ return
1674
+ end
1675
+
1676
+ set_update( dst )
1677
+ data = data[ written..-1 ]
1678
+ dst_info[ :wbuff ] = data
1679
+ bytesize = dst_info[ :wbuff ].bytesize
1680
+
1681
+ if dst_info[ :overflowing ] && ( bytesize < RESUME_BELOW ) then
1682
+ puts "dst underhalf #{ dst_info[ :domain ] }"
1683
+ add_read( dst_info[ :src ] )
1684
+ dst_info[ :overflowing ] = false
1685
+ end
1686
+ end
1687
+
1688
+ def write_mem( mem )
1689
+ if mem.closed? then
1690
+ puts "write closed mem?"
1691
+ return
1692
+ end
1693
+
1694
+ mem_info = @mem_infos[ mem ]
1695
+ data = mem_info[ :wbuff ]
1696
+
1697
+ if data.empty? then
1698
+ @writes.delete( mem )
1699
+ close_mem( mem )
1700
+ return
1701
+ end
1702
+
1703
+ begin
1704
+ written = mem.write_nonblock( data )
1705
+ rescue Errno::EINPROGRESS
1706
+ return
1707
+ rescue Exception => e
1708
+ close_mem( mem )
1709
+ return
1710
+ end
1711
+
1712
+ set_update( mem )
1713
+ data = data[ written..-1 ]
1714
+ mem_info[ :wbuff ] = data
1715
+ end
1716
+
1717
+ def write_p1( p1 )
1718
+ if p1.closed? then
1719
+ puts "write closed p1?"
1720
+ return
1721
+ end
1722
+
1723
+ p1_info = @p1_infos[ p1 ]
1724
+ p1_info[ :connected ] = true
1725
+ data = p1_info[ :wbuff ]
1726
+
1727
+ if data.empty? then
1728
+ if p1_info[ :closing ] then
1729
+ close_p1( p1 )
1730
+ else
1731
+ @writes.delete( p1 )
1732
+ end
1733
+
1734
+ return
1735
+ end
1736
+
1737
+ begin
1738
+ written = p1.write_nonblock( data )
1739
+ rescue Errno::EINPROGRESS
1740
+ return
1741
+ rescue Exception => e
1742
+ close_p1( p1 )
1743
+ return
1744
+ end
1745
+
1746
+ set_update( p1 )
1747
+ data = data[ written..-1 ]
1748
+ p1_info[ :wbuff ] = data
1749
+ bytesize = p1_info[ :wbuff ].bytesize
1750
+
1751
+ if p1_info[ :overflowing ] && ( bytesize < RESUME_BELOW ) then
1752
+ p2_id = p1_info[ :p2_id ]
1753
+ puts "add h_p1_underhalf #{ p2_id }"
1754
+ msg = "#{ @h_p1_underhalf }#{ [ p2_id ].pack( 'Q>' ) }"
1755
+ add_proxy_wbuff( pack_a_chunk( msg ) )
1756
+ p1_info[ :overflowing ] = false
1757
+ end
1758
+ end
1759
+
1760
+ def write_proxy( proxy )
1761
+ if proxy.closed? then
1762
+ puts "write closed proxy?"
1763
+ return
1764
+ end
1765
+
1766
+ proxy_info = @proxy_infos[ proxy ]
1767
+ data = proxy_info[ :wbuff ]
1768
+
1769
+ if data.empty? then
1770
+ @writes.delete( proxy )
1771
+ return
1772
+ end
1773
+
1774
+ begin
1775
+ if proxy_info[ :is_syn ] then
1776
+ written = proxy.sendmsg_nonblock( data, 536870912, @proxyd_addr )
1777
+ proxy_info[ :is_syn ] = false
1778
+ else
1779
+ written = proxy.write_nonblock( data )
1780
+ end
1781
+ rescue Errno::EINPROGRESS
1782
+ return
1783
+ rescue Exception => e
1784
+ puts "write proxy #{ e.class }"
1785
+ close_proxy( proxy )
1786
+ return
1787
+ end
1788
+
1789
+ set_update( proxy )
1790
+ data = data[ written..-1 ]
1791
+ proxy_info[ :wbuff ] = data
1792
+ bytesize = proxy_info[ :wbuff ].bytesize
1793
+
1794
+ if bytesize < RESUME_BELOW then
1795
+ if proxy_info[ :paused_srcs ].any? then
1796
+ puts "proxy underhalf resume srcs #{ proxy_info[ :paused_srcs ].size }"
1797
+ proxy_info[ :paused_srcs ].each{ | src | add_read( src ) }
1798
+ proxy_info[ :paused_srcs ].clear
1799
+ end
1800
+
1801
+ if proxy_info[ :paused_p1s ].any? then
1802
+ puts "proxy underhalf resume p1s #{ proxy_info[ :paused_p1s ].size }"
1803
+ proxy_info[ :paused_p1s ].each{ | p1 | add_read( p1 ) }
1804
+ proxy_info[ :paused_p1s ].clear
1805
+ end
1806
+ end
1807
+ end
1808
+
1809
+ def write_src( src )
1810
+ if src.closed? then
1811
+ puts "write closed src?"
1812
+ return
1813
+ end
1814
+
1815
+ src_info = @src_infos[ src ]
1816
+ data = src_info[ :wbuff ]
1817
+
1818
+ if data.empty? then
1819
+ if src_info[ :closing ] then
1820
+ close_src( src )
1821
+ else
1822
+ @writes.delete( src )
1823
+ end
1824
+
1825
+ return
1826
+ end
1827
+
1828
+ begin
1829
+ written = src.write_nonblock( data )
1830
+ rescue Errno::EINPROGRESS
1831
+ return
1832
+ rescue Exception => e
1833
+ close_src( src )
1834
+ return
1835
+ end
1836
+
1837
+ set_update( src )
1838
+ data = data[ written..-1 ]
1839
+ src_info[ :wbuff ] = data
1840
+ bytesize = src_info[ :wbuff ].bytesize
1841
+
1842
+ if src_info[ :overflowing ] && ( bytesize < RESUME_BELOW ) then
1843
+ src_id = src_info[ :src_id ]
1844
+ domain = src_info[ :destination_domain ]
1845
+
1846
+ if src_info[ :proxy_type ] == :direct then
1847
+ puts "src underhalf #{ src_id } #{ domain }"
1848
+ add_read( src_info[ :dst ] )
1849
+ else
1850
+ puts "add h_src_underhalf #{ src_id } #{ domain }"
1851
+ msg = "#{ @h_src_underhalf }#{ [ src_id ].pack( 'Q>' ) }"
1852
+ add_proxy_wbuff( pack_a_chunk( msg ) )
1853
+ end
1854
+
1855
+ src_info[ :overflowing ] = false
1856
+ end
1857
+ end
1858
+
1859
+ end
1860
+ end