girl 4.1.0 → 4.6.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of girl might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 836b54e1549dfed638c775a99d128c18ce079d91bc508933635a8a8cbdfb3c2e
4
- data.tar.gz: 7c1f1bab96cab7395e49b2dd71ec5dfc1073b57ffa6611bff7abeb1a3ef8162b
3
+ metadata.gz: 8d3b294765df9759f671cd5916a4315aa5872a85e42ea9739d8e2bd409f55f49
4
+ data.tar.gz: 8405a9e93e8c038e757c3a191c40c3801ff34e9ce593be0b0187ee728cb70fa7
5
5
  SHA512:
6
- metadata.gz: 61a0a02a8a480343cd27f295d82dda48ab93e0d0c486a0d2cb82e8961477bffcc20e219238d794db8056ec00cb175955eb7c1a111b35d4fd189edec069a7390d
7
- data.tar.gz: 694ea8625f406e0e2293c20b7144398ac2a09978f510d91387e3caa76d967c72dfc712334d0d1994bf8ac2822ed0b27552d7c88924b449c1fad9ff965e4293be
6
+ metadata.gz: 8b09b4c9b12257b9fc8672eace67cd89bfac89b5032ffb6ccf2a6810342a3c09e45ba0b6658b86cafd7d671fdeaf0235de794a3f0b356c2835a3c5248de9743b
7
+ data.tar.gz: 5e16e91e812c7c53d3fbb47e4c16fc90f7f922a011d4983b6ee955306fd88496b7965e0f02c7ab78b9db80e25a4468c483dffab634d009d1f459d1a16c589a8f
data/girl.gemspec CHANGED
@@ -18,7 +18,6 @@ Gem::Specification.new do |spec|
18
18
  girl.gemspec
19
19
  lib/girl.rb
20
20
  lib/girl/concurrent_hash.rb
21
- lib/girl/custom_dns_query.rb
22
21
  lib/girl/custom.rb
23
22
  lib/girl/head.rb
24
23
  lib/girl/proxy_custom.rb
@@ -1,26 +1,26 @@
1
- class ConcurrentHash < Hash
2
- def initialize
3
- super
4
- @mutex = Mutex.new
5
- end
6
-
7
- def []( *args )
8
- @mutex.synchronize { super }
9
- end
10
-
11
- def []=( *args )
12
- @mutex.synchronize { super }
13
- end
14
-
15
- def delete( *args )
16
- @mutex.synchronize { super }
17
- end
18
-
19
- def each( *args )
20
- @mutex.synchronize { super }
21
- end
22
-
23
- def clear( *args )
24
- @mutex.synchronize { super }
25
- end
26
- end
1
+ class ConcurrentHash < Hash
2
+ def initialize
3
+ super
4
+ @mutex = Mutex.new
5
+ end
6
+
7
+ def []( *args )
8
+ @mutex.synchronize { super }
9
+ end
10
+
11
+ def []=( *args )
12
+ @mutex.synchronize { super }
13
+ end
14
+
15
+ def delete( *args )
16
+ @mutex.synchronize { super }
17
+ end
18
+
19
+ def each( *args )
20
+ @mutex.synchronize { super }
21
+ end
22
+
23
+ def clear( *args )
24
+ @mutex.synchronize { super }
25
+ end
26
+ end
data/lib/girl/head.rb CHANGED
@@ -1,13 +1,15 @@
1
1
  module Girl
2
- READ_SIZE = 1024 * 1024 # atun, btun一次读多少
2
+ READ_SIZE = 1024 * 1024 # 一次读多少
3
3
  WBUFF_LIMIT = 50 * 1024 * 1024 # 写前上限,超过上限暂停读
4
4
  RESUME_BELOW = WBUFF_LIMIT / 2 # 降到多少以下恢复读
5
+ CHUNK_SIZE = 65535 # 按块加解密,块尺寸上限,不超过65535
5
6
  EXPIRE_NEW = 5 # 多久没有建立通道,过期
6
- EXPIRE_AFTER = 300 # 多久没有新流量,过期
7
+ EXPIRE_CONNECTING = 2 # 连接中,多久没连上过期
8
+ EXPIRE_AFTER = 86400 # 多久没有新流量,过期
7
9
  EXPIRE_CTL = 86400 # 多久没有ctlmsg来,过期
8
10
  RESET_TRAFF_DAY = 1 # 流量计数重置日,0为不重置
9
11
  CHECK_TRAFF_INTERVAL = 86400 # 检查今天是否是流量计数重置日间隔
10
- CHECK_EXPIRE_INTERVAL = 5 # 检查过期间隔
12
+ CHECK_EXPIRE_INTERVAL = 1 # 检查过期间隔
11
13
  CHECK_RESUME_INTERVAL = 1 # 检查恢复读间隔
12
14
  RESOLV_CACHE_EXPIRE = 300 # dns查询结果缓存多久过期
13
15
  RESEND_LIMIT = 5 # ctlmsg重传次数
@@ -52,7 +54,9 @@ EOF
52
54
  READ_SIZE
53
55
  WBUFF_LIMIT
54
56
  RESUME_BELOW
57
+ CHUNK_SIZE
55
58
  EXPIRE_NEW
59
+ EXPIRE_CONNECTING
56
60
  EXPIRE_AFTER
57
61
  EXPIRE_CTL
58
62
  RESET_TRAFF_DAY
data/lib/girl/proxy.rb CHANGED
@@ -14,8 +14,8 @@ require 'socket'
14
14
  #
15
15
  =begin
16
16
  C: 1 hello -> hello
17
- 2 tund port -> n: tund port
18
- 3 a new source -> Q>: src id -> encoded destination address
17
+ 2 tund port -> n: atund port -> n: btund port
18
+ 3 a new source -> Q>: src id -> destination
19
19
  4 paired -> Q>: src id -> n: dst id
20
20
  5 dest status NOT USE
21
21
  6 source status NOT USE
@@ -32,13 +32,11 @@ C: 1 hello -> hello
32
32
  17 continue NOT USE
33
33
  18 is resend ready NOT USE
34
34
  19 resend ready NOT USE
35
- 20 resolv -> Q>: src id -> encoded domain
36
- 21 resolved -> Q>: src id -> encoded ip
35
+ 20 resolv NOT USE
36
+ 21 resolved NOT USE
37
37
  22 heartbeat NOT USE
38
38
  23 unknown ctl addr
39
39
  24 ctl fin
40
- 25 source eof -> Q>: dst id
41
- 26 dest eof -> Q>: src id
42
40
  101 traff infos
43
41
  101 traff infos -> [ C: im len -> im -> Q>: traff in -> Q>: traff out ]
44
42
  =end
@@ -1,16 +1,16 @@
1
- require 'girl/custom'
2
-
3
- module Girl
4
- class ProxyCustom
5
- include Custom
6
-
7
- def initialize( im )
8
- @im = im
9
- end
10
-
11
- def hello
12
- @im
13
- end
14
-
15
- end
16
- end
1
+ require 'girl/custom'
2
+
3
+ module Girl
4
+ class ProxyCustom
5
+ include Custom
6
+
7
+ def initialize( im )
8
+ @im = im
9
+ end
10
+
11
+ def hello
12
+ @im
13
+ end
14
+
15
+ end
16
+ end
@@ -6,6 +6,7 @@ module Girl
6
6
  #
7
7
  def initialize( redir_port, proxyd_host, proxyd_port, directs, remotes, im )
8
8
  @proxyd_host = proxyd_host
9
+ @proxyd_port = proxyd_port
9
10
  @proxyd_addr = Socket.sockaddr_in( proxyd_port, proxyd_host )
10
11
  @directs = directs
11
12
  @remotes = remotes
@@ -19,7 +20,7 @@ module Girl
19
20
  @resume_srcs = []
20
21
  @resume_dsts = []
21
22
  @resume_btuns = []
22
- @pending_srcs = [] # 还没配到tund,暂存的src
23
+ @pending_srcs = [] # 还没得到atund和btund地址,暂存的src
23
24
  @roles = ConcurrentHash.new # sock => :dotr / :redir / :ctl / :src / :dst / :atun / :btun
24
25
  @src_infos = ConcurrentHash.new # src => {}
25
26
  @dst_infos = ConcurrentHash.new # dst => {}
@@ -296,7 +297,7 @@ module Girl
296
297
  close_sock( atun )
297
298
  atun_info = @atun_infos.delete( atun )
298
299
  src = atun_info[ :src ]
299
-
300
+
300
301
  if src then
301
302
  @paused_srcs.delete( src )
302
303
  end
@@ -430,9 +431,8 @@ module Girl
430
431
  return if src.closed?
431
432
  src_info = @src_infos[ src ]
432
433
 
433
- if ip_info.ipv4_loopback? \
434
- || ip_info.ipv6_loopback? \
435
- || ( ( @ip_address_list.any? { | addrinfo | addrinfo.ip_address == ip_info.ip_address } ) && ( src_info[ :destination_port ] == @redir_port ) ) then
434
+ if ( ( @ip_address_list.any? { | addrinfo | addrinfo.ip_address == ip_info.ip_address } ) && ( src_info[ :destination_port ] == @redir_port ) ) \
435
+ || ( ( ip_info.ip_address == @proxyd_host ) && ( src_info[ :destination_port ] == @proxyd_port ) ) then
436
436
  puts "p#{ Process.pid } #{ Time.new } ignore #{ ip_info.ip_address }:#{ src_info[ :destination_port ] }"
437
437
  add_closing_src( src )
438
438
  return
@@ -449,7 +449,6 @@ module Girl
449
449
  is_direct = @is_direct_caches[ ip_info.ip_address ]
450
450
  else
451
451
  is_direct = @directs.any? { | direct | direct.include?( ip_info.ip_address ) }
452
- # 判断直连耗时较长(树莓派 0.27秒),这里可能切去主线程,回来src可能已关闭
453
452
  puts "p#{ Process.pid } #{ Time.new } cache is direct #{ ip_info.ip_address } #{ is_direct }"
454
453
  @is_direct_caches[ ip_info.ip_address ] = is_direct
455
454
  end
@@ -458,7 +457,6 @@ module Girl
458
457
  # puts "debug #{ ip_info.inspect } hit directs"
459
458
  new_a_dst( src, ip_info )
460
459
  else
461
- # 走远端
462
460
  # puts "debug #{ ip_info.inspect } go tunnel"
463
461
  set_proxy_type_tunnel( src )
464
462
  end
@@ -509,8 +507,8 @@ module Girl
509
507
  if @ctl && !@ctl.closed? then
510
508
  last_recv_at = @ctl_info[ :last_recv_at ] || @ctl_info[ :created_at ]
511
509
 
512
- if now - last_recv_at >= EXPIRE_AFTER then
513
- puts "p#{ Process.pid } #{ Time.new } expire ctl"
510
+ if now - last_recv_at >= EXPIRE_CTL then
511
+ puts "p#{ Process.pid } #{ Time.new } expire ctl #{ EXPIRE_CTL }"
514
512
  @ctl_info[ :closing ] = true
515
513
  next_tick
516
514
  end
@@ -519,9 +517,24 @@ module Girl
519
517
  @src_infos.each do | src, src_info |
520
518
  last_recv_at = src_info[ :last_recv_at ] || src_info[ :created_at ]
521
519
  last_sent_at = src_info[ :last_sent_at ] || src_info[ :created_at ]
522
- expire_after = ( src_info[ :dst ] || src_info[ :atun ] ) ? EXPIRE_AFTER : EXPIRE_NEW
523
520
 
524
- if ( now - last_recv_at >= expire_after ) && ( now - last_sent_at >= expire_after ) then
521
+ if src_info[ :dst ] then
522
+ if src_info[ :dst_connected ] then
523
+ expire_after = EXPIRE_AFTER
524
+ is_expire = ( now - last_recv_at >= expire_after ) && ( now - last_sent_at >= expire_after )
525
+ else
526
+ expire_after = EXPIRE_CONNECTING
527
+ is_expire = ( now - src_info[ :dst_created_at ] >= expire_after )
528
+ end
529
+ elsif src_info[ :atun ] then
530
+ expire_after = EXPIRE_AFTER
531
+ is_expire = ( now - last_recv_at >= expire_after ) && ( now - last_sent_at >= expire_after )
532
+ else
533
+ expire_after = EXPIRE_NEW
534
+ is_expire = ( now - last_recv_at >= expire_after ) && ( now - last_sent_at >= expire_after )
535
+ end
536
+
537
+ if is_expire then
525
538
  puts "p#{ Process.pid } #{ Time.new } expire src #{ expire_after } #{ src_info[ :id ] } #{ src_info[ :destination_domain ] }"
526
539
  add_closing_src( src )
527
540
 
@@ -550,7 +563,7 @@ module Girl
550
563
  if !dst.closed? then
551
564
  dst_info = @dst_infos[ dst ]
552
565
 
553
- if dst_info[ :wbuff ].size < RESUME_BELOW then
566
+ if dst_info[ :wbuff ].bytesize < RESUME_BELOW then
554
567
  puts "p#{ Process.pid } #{ Time.new } resume direct src #{ src_info[ :destination_domain ] }"
555
568
  add_resume_src( src )
556
569
  end
@@ -561,7 +574,7 @@ module Girl
561
574
  if atun && !atun.closed? then
562
575
  atun_info = @atun_infos[ atun ]
563
576
 
564
- if atun_info[ :wbuff ].size < RESUME_BELOW then
577
+ if atun_info[ :wbuff ].bytesize < RESUME_BELOW then
565
578
  puts "p#{ Process.pid } #{ Time.new } resume tunnel src #{ src_info[ :destination_domain ] }"
566
579
  add_resume_src( src )
567
580
  end
@@ -576,7 +589,7 @@ module Girl
576
589
  if src && !src.closed? then
577
590
  src_info = @src_infos[ src ]
578
591
 
579
- if src_info[ :wbuff ].size < RESUME_BELOW then
592
+ if src_info[ :wbuff ].bytesize < RESUME_BELOW then
580
593
  puts "p#{ Process.pid } #{ Time.new } resume dst #{ dst_info[ :domain ] }"
581
594
  add_resume_dst( dst )
582
595
  end
@@ -590,7 +603,7 @@ module Girl
590
603
  if src && !src.closed? then
591
604
  src_info = @src_infos[ src ]
592
605
 
593
- if src_info[ :wbuff ].size < RESUME_BELOW then
606
+ if src_info[ :wbuff ].bytesize < RESUME_BELOW then
594
607
  puts "p#{ Process.pid } #{ Time.new } resume btun #{ btun_info[ :domain ] }"
595
608
  add_resume_btun( btun )
596
609
  end
@@ -634,13 +647,14 @@ module Girl
634
647
  domain = src_info[ :destination_domain ]
635
648
  destination_addr = Socket.sockaddr_in( src_info[ :destination_port ], ip_info.ip_address )
636
649
  dst = Socket.new( ip_info.ipv4? ? Socket::AF_INET : Socket::AF_INET6, Socket::SOCK_STREAM, 0 )
650
+ dst.setsockopt( Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1 )
637
651
 
638
652
  begin
639
653
  dst.connect_nonblock( destination_addr )
640
654
  rescue IO::WaitWritable
641
655
  # connect nonblock 必抛 wait writable
642
656
  rescue Exception => e
643
- puts "p#{ Process.pid } #{ Time.new } dst connect destination #{ domain } #{ src_info[ :destination_port ] } #{ ip_info.ip_address } #{ e.class }, close src"
657
+ puts "p#{ Process.pid } #{ Time.new } dst connect destination #{ domain } #{ src_info[ :destination_port ] } #{ ip_info.ip_address } #{ e.class }"
644
658
  dst.close
645
659
  add_closing_src( src )
646
660
  return
@@ -655,9 +669,9 @@ module Girl
655
669
  }
656
670
 
657
671
  @dst_infos[ dst ] = dst_info
658
- add_read( dst, :dst )
659
672
  src_info[ :proxy_type ] = :direct
660
673
  src_info[ :dst ] = dst
674
+ src_info[ :dst_created_at ] = Time.new
661
675
 
662
676
  if src_info[ :proxy_proto ] == :http then
663
677
  if src_info[ :is_connect ] then
@@ -666,11 +680,13 @@ module Girl
666
680
  elsif src_info[ :rbuff ] then
667
681
  # puts "debug move src.rbuff to dst.wbuff"
668
682
  dst_info[ :wbuff ] << src_info[ :rbuff ]
669
- add_write( dst )
670
683
  end
671
684
  elsif src_info[ :proxy_proto ] == :socks5 then
672
685
  add_socks5_conn_reply( src )
673
686
  end
687
+
688
+ add_read( dst, :dst )
689
+ add_write( dst )
674
690
  end
675
691
 
676
692
  ##
@@ -706,6 +722,7 @@ module Girl
706
722
  #
707
723
  def new_a_redir( redir_port )
708
724
  redir = Socket.new( Socket::AF_INET, Socket::SOCK_STREAM, 0 )
725
+ redir.setsockopt( Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1 )
709
726
  redir.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEADDR, 1 )
710
727
 
711
728
  if RUBY_PLATFORM.include?( 'linux' ) then
@@ -724,6 +741,7 @@ module Girl
724
741
  # new tuns
725
742
  #
726
743
  def new_tuns( src_id, dst_id )
744
+ return if @ctl_info[ :atund_addr ].nil? || @ctl_info[ :btund_addr ].nil?
727
745
  src = @srcs[ src_id ]
728
746
  return if src.nil? || src.closed?
729
747
  src_info = @src_infos[ src ]
@@ -731,23 +749,25 @@ module Girl
731
749
 
732
750
  # puts "debug new atun and btun"
733
751
  atun = Socket.new( Socket::AF_INET, Socket::SOCK_STREAM, 0 )
752
+ atun.setsockopt( Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1 )
734
753
 
735
754
  begin
736
755
  atun.connect_nonblock( @ctl_info[ :atund_addr ] )
737
756
  rescue IO::WaitWritable
738
757
  rescue Exception => e
739
- puts "p#{ Process.pid } #{ Time.new } connect atund #{ e.class }, close atun"
758
+ puts "p#{ Process.pid } #{ Time.new } connect atund #{ e.class }"
740
759
  atun.close
741
760
  return
742
761
  end
743
762
 
744
763
  btun = Socket.new( Socket::AF_INET, Socket::SOCK_STREAM, 0 )
764
+ btun.setsockopt( Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1 )
745
765
 
746
766
  begin
747
767
  btun.connect_nonblock( @ctl_info[ :btund_addr ] )
748
768
  rescue IO::WaitWritable
749
769
  rescue Exception => e
750
- puts "p#{ Process.pid } #{ Time.new } connect btund #{ e.class }, close btun"
770
+ puts "p#{ Process.pid } #{ Time.new } connect btund #{ e.class }"
751
771
  btun.close
752
772
  return
753
773
  end
@@ -756,7 +776,7 @@ module Girl
756
776
  atun_wbuff = [ dst_id ].pack( 'n' )
757
777
 
758
778
  until src_info[ :rbuff ].empty? do
759
- data = src_info[ :rbuff ][ 0, 65535 ]
779
+ data = src_info[ :rbuff ][ 0, CHUNK_SIZE ]
760
780
  data_size = data.bytesize
761
781
  # puts "debug move src.rbuff #{ data_size } to atun.wbuff"
762
782
  atun_wbuff << pack_a_chunk( data )
@@ -777,7 +797,8 @@ module Girl
777
797
  domain: domain, # 目的地
778
798
  wbuff: btun_wbuff, # 写前
779
799
  rbuff: '', # 暂存当前块没收全的流量
780
- wait_bytes: 0 # 还差多少字节收全当前块
800
+ wait_bytes: 0, # 还差多少字节收全当前块
801
+ lbuff: '' # 流量截断在长度前缀处
781
802
  }
782
803
 
783
804
  src_info[ :dst_id ] = dst_id
@@ -809,7 +830,6 @@ module Girl
809
830
  # pack a chunk
810
831
  #
811
832
  def pack_a_chunk( data )
812
- # puts "debug pack a chunk"
813
833
  data = @custom.encode( data )
814
834
  "#{ [ data.bytesize ].pack( 'n' ) }#{ data }"
815
835
  end
@@ -864,6 +884,7 @@ module Girl
864
884
  #
865
885
  def send_ctlmsg( data )
866
886
  return if @ctl.nil? || @ctl.closed?
887
+ data = @custom.encode( data )
867
888
 
868
889
  begin
869
890
  @ctl.sendmsg( data, 0, @proxyd_addr )
@@ -925,30 +946,11 @@ module Girl
925
946
  add_write( src )
926
947
  end
927
948
 
928
- ##
929
- # sub http request
930
- #
931
- def sub_http_request( data )
932
- lines = data.split( "\r\n" )
933
-
934
- return [ data, nil ] if lines.empty?
935
-
936
- method, url, proto = lines.first.split( ' ' )
937
-
938
- if proto && url && proto[ 0, 4 ] == 'HTTP' && url[ 0, 7 ] == 'http://' then
939
- domain_port = url.split( '/' )[ 2 ]
940
- data = data.sub( "http://#{ domain_port }", '' )
941
- # puts "debug subed #{ data.inspect } #{ domain_port }"
942
- end
943
-
944
- [ data, domain_port ]
945
- end
946
-
947
949
  ##
948
950
  # read dotr
949
951
  #
950
952
  def read_dotr( dotr )
951
- dotr.read_nonblock( 65535 )
953
+ dotr.read_nonblock( READ_SIZE )
952
954
 
953
955
  if @ctl_info && @ctl_info[ :closing ] then
954
956
  send_ctlmsg( [ CTL_FIN ].pack( 'C' ) )
@@ -1012,6 +1014,8 @@ module Girl
1012
1014
  is_connect: true, # 代理协议是http的场合,是否是CONNECT
1013
1015
  rbuff: '', # 读到的流量
1014
1016
  dst: nil, # :direct的场合,对应的dst
1017
+ dst_created_at: nil, # :direct的场合,对应的dst的创建时间
1018
+ dst_connected: false, # :direct的场合,对应的dst是否已连接
1015
1019
  ctl: nil, # :tunnel的场合,对应的ctl
1016
1020
  atun: nil, # :tunnel的场合,对应的atun
1017
1021
  btun: nil, # :tunnel的场合,对应的btun
@@ -1042,11 +1046,12 @@ module Girl
1042
1046
  return
1043
1047
  end
1044
1048
 
1049
+ data = @custom.decode( data )
1045
1050
  ctl_num = data[ 0 ].unpack( 'C' ).first
1046
1051
 
1047
1052
  case ctl_num
1048
1053
  when TUND_PORT then
1049
- return if @ctl_info[ :atund_addr ] || data.size != 5
1054
+ return if @ctl_info[ :atund_addr ] || data.bytesize != 5
1050
1055
  atund_port, btund_port = data[ 1, 4 ].unpack( 'nn' )
1051
1056
  puts "p#{ Process.pid } #{ Time.new } got tund port #{ atund_port } #{ btund_port }"
1052
1057
  @ctl_info[ :resends ].delete( [ HELLO ].pack( 'C' ) )
@@ -1060,14 +1065,14 @@ module Girl
1060
1065
  @pending_srcs.clear
1061
1066
  end
1062
1067
  when PAIRED then
1063
- return if @ctl_info[ :atund_addr ].nil? || @ctl_info[ :btund_addr ].nil? || data.size != 11
1068
+ return if data.bytesize != 11
1064
1069
  src_id, dst_id = data[ 1, 10 ].unpack( 'Q>n' )
1065
1070
  # puts "debug got paired #{ src_id } #{ dst_id }"
1066
1071
  @ctl_info[ :resends ].delete( [ A_NEW_SOURCE, src_id ].pack( 'CQ>' ) )
1067
1072
  @ctl_info[ :last_recv_at ] = Time.new
1068
1073
  new_tuns( src_id, dst_id )
1069
1074
  when UNKNOWN_CTL_ADDR then
1070
- puts "p#{ Process.pid } #{ Time.new } got unknown ctl addr, close ctl"
1075
+ puts "p#{ Process.pid } #{ Time.new } got unknown ctl addr"
1071
1076
  close_ctl( ctl )
1072
1077
  end
1073
1078
  end
@@ -1084,7 +1089,7 @@ module Girl
1084
1089
  src_info = @src_infos[ src ]
1085
1090
 
1086
1091
  begin
1087
- data = src.read_nonblock( 65535 )
1092
+ data = src.read_nonblock( CHUNK_SIZE )
1088
1093
  rescue IO::WaitReadable
1089
1094
  print 'r'
1090
1095
  return
@@ -1159,7 +1164,16 @@ module Girl
1159
1164
  return
1160
1165
  end
1161
1166
 
1162
- data, domain_port = sub_http_request( data )
1167
+ lines = data.split( "\r\n" )
1168
+
1169
+ unless lines.empty? then
1170
+ method, url, proto = lines.first.split( ' ' )
1171
+
1172
+ if proto && url && proto[ 0, 4 ] == 'HTTP' && url[ 0, 7 ] == 'http://' then
1173
+ domain_port = url.split( '/' )[ 2 ]
1174
+ # puts "debug domain port #{ domain_port }"
1175
+ end
1176
+ end
1163
1177
 
1164
1178
  unless domain_port then
1165
1179
  # puts "debug not HTTP"
@@ -1226,10 +1240,6 @@ module Girl
1226
1240
  when :tunnel then
1227
1241
  atun = src_info[ :atun ]
1228
1242
 
1229
- if atun && !src_info[ :is_connect ] then
1230
- data, _ = sub_http_request( data )
1231
- end
1232
-
1233
1243
  if atun then
1234
1244
  add_atun_wbuff( atun, pack_a_chunk( data ) )
1235
1245
  else
@@ -1240,10 +1250,6 @@ module Girl
1240
1250
  dst = src_info[ :dst ]
1241
1251
 
1242
1252
  if dst then
1243
- unless src_info[ :is_connect ] then
1244
- data, _ = sub_http_request( data )
1245
- end
1246
-
1247
1253
  add_dst_wbuff( dst, data )
1248
1254
  else
1249
1255
  # puts "debug add src.rbuff #{ data.bytesize }"
@@ -1265,7 +1271,7 @@ module Girl
1265
1271
  src = dst_info[ :src ]
1266
1272
 
1267
1273
  begin
1268
- data = dst.read_nonblock( 65535 )
1274
+ data = dst.read_nonblock( CHUNK_SIZE )
1269
1275
  rescue IO::WaitReadable
1270
1276
  print 'r'
1271
1277
  return
@@ -1306,22 +1312,44 @@ module Girl
1306
1312
  end
1307
1313
 
1308
1314
  until data.empty? do
1309
- rbuff = btun_info[ :rbuff ]
1310
1315
  wait_bytes = btun_info[ :wait_bytes ]
1311
1316
 
1312
1317
  if wait_bytes > 0 then
1313
1318
  len = wait_bytes
1314
1319
  # puts "debug wait bytes #{ len }"
1315
1320
  else
1316
- if data.bytesize <= 2 then
1317
- # puts "debug unexpect data length #{ data.bytesize }"
1318
- close_btun( btun )
1319
- return
1320
- end
1321
+ lbuff = btun_info[ :lbuff ]
1322
+
1323
+ if lbuff.empty? then
1324
+ # 长度缓存为空,从读到的流量里取长度
1325
+ # 两个字节以下,记进长度缓存
1326
+ if data.bytesize <= 2 then
1327
+ # puts "debug set btun.lbuff #{ data.inspect }"
1328
+ btun_info[ :lbuff ] = data
1329
+ return
1330
+ end
1331
+
1332
+ len = data[ 0, 2 ].unpack( 'n' ).first
1333
+ data = data[ 2..-1 ]
1334
+ elsif lbuff.bytesize == 1 then
1335
+ # 长度缓存记有一个字节,补一个字节
1336
+ lbuff = "#{ lbuff }#{ data[ 0 ] }"
1321
1337
 
1322
- len = data[ 0, 2 ].unpack( 'n' ).first
1323
- # puts "debug read len #{ len }"
1324
- data = data[ 2..-1 ]
1338
+ if data.bytesize == 1 then
1339
+ # puts "debug add btun.lbuff a byte #{ data.inspect }"
1340
+ btun_info[ :lbuff ] = lbuff
1341
+ return
1342
+ end
1343
+
1344
+ # 使用长度缓存
1345
+ len = lbuff.unpack( 'n' ).first
1346
+ btun_info[ :lbuff ].clear
1347
+ data = data[ 1..-1 ]
1348
+ else
1349
+ # 使用长度缓存
1350
+ len = lbuff.unpack( 'n' ).first
1351
+ btun_info[ :lbuff ].clear
1352
+ end
1325
1353
  end
1326
1354
 
1327
1355
  chunk = data[ 0, len ]
@@ -1329,7 +1357,7 @@ module Girl
1329
1357
 
1330
1358
  if chunk_size == len then
1331
1359
  # 取完整了
1332
- chunk = @custom.decode( "#{ rbuff }#{ chunk }" )
1360
+ chunk = @custom.decode( "#{ btun_info[ :rbuff ] }#{ chunk }" )
1333
1361
  # puts "debug decode and add src.wbuff #{ chunk.bytesize }"
1334
1362
  add_src_wbuff( src, chunk )
1335
1363
  btun_info[ :rbuff ].clear
@@ -1408,6 +1436,12 @@ module Girl
1408
1436
 
1409
1437
  dst_info = @dst_infos[ dst ]
1410
1438
  src = dst_info[ :src ]
1439
+ src_info = @src_infos[ src ]
1440
+
1441
+ unless src.closed? then
1442
+ src_info[ :dst_connected ] = true
1443
+ end
1444
+
1411
1445
  data = dst_info[ :wbuff ]
1412
1446
 
1413
1447
  # 写前为空,处理关闭写
@@ -1438,7 +1472,6 @@ module Girl
1438
1472
  dst_info[ :wbuff ] = data
1439
1473
 
1440
1474
  unless src.closed? then
1441
- src_info = @src_infos[ src ]
1442
1475
  src_info[ :last_sent_at ] = Time.new
1443
1476
  end
1444
1477
  end