girl 9.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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