girl 9.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: ddce98f59f1102d50d58fd02775ed1305f3babb3a2b7998a4ed86f39438e2599
4
+ data.tar.gz: b51d851640addd0acb8d5367b9d6295a67036e720436c6d0bea9ed352222f9bc
5
+ SHA512:
6
+ metadata.gz: 469527cb74ea0a0aab7af6358dcd345852c8c9c25b9adbcb69f70acaa582592b696a2549d92e3970d55b0a607fe400f107c8445e075fffb6c22bc4d82837289a
7
+ data.tar.gz: 1ce78e2d003752fb847c11ec505960c82a241d4d0b8ebde1047e7ac788532bb35ad6d985cf76067e20c638a788736336a35a2381b146664d4c391a5e3441d39f
data/girl.gemspec ADDED
@@ -0,0 +1,30 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'girl/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'girl'
8
+ spec.version = Girl::VERSION
9
+ spec.authors = ['takafan']
10
+ spec.email = ['qqtakafan@gmail.com']
11
+
12
+ spec.summary = %q{妹子}
13
+ spec.description = %q{escape evil.}
14
+ spec.homepage = 'https://github.com/takafan/girl'
15
+ spec.license = 'MIT'
16
+
17
+ spec.files = %w[
18
+ girl.gemspec
19
+ lib/girl.rb
20
+ lib/girl/dns.rb
21
+ lib/girl/head.rb
22
+ lib/girl/proxy_worker.rb
23
+ lib/girl/proxy.rb
24
+ lib/girl/proxyd_worker.rb
25
+ lib/girl/proxyd.rb
26
+ lib/girl/version.rb
27
+ ]
28
+
29
+ spec.require_paths = ['lib']
30
+ end
data/lib/girl/dns.rb ADDED
@@ -0,0 +1,137 @@
1
+ module Girl
2
+ module Dns
3
+
4
+ def pack_a_query( domain, type = 1 )
5
+ # https://www.ietf.org/rfc/rfc1035.txt
6
+ # https://www.ietf.org/rfc/rfc3596.txt
7
+ raise "domain may not exceed 255 chars" if domain.bytesize > 255
8
+ raise "invalid domain" if domain =~ /[^\w\.\-]/
9
+ data = [ rand( 65_535 ), 1, 0, 1, 0, 0, 0 ].pack( 'nCCnnnn' )
10
+ data << [ pack_domain( domain ), type, 1 ].pack( 'a*nn' )
11
+ data
12
+ end
13
+
14
+ def pack_domain( domain )
15
+ data = ''
16
+
17
+ domain.split( '.' ).each do | label |
18
+ raise "label may not exceed 63 chars" if label.bytesize > 63
19
+ data << [ label.bytesize, label ].pack( 'Ca*' )
20
+ end
21
+
22
+ data << [ 0 ].pack( 'C' )
23
+ data
24
+ end
25
+
26
+ def seek_dn( data, offset )
27
+ name = ""
28
+ datalen = data.bytesize
29
+
30
+ loop do
31
+ raise "offset is greater than datalen" if datalen < ( offset + 1 )
32
+
33
+ len = data.unpack( "@#{ offset } C" ).first
34
+
35
+ if len == 0
36
+ offset += 1
37
+ break
38
+ elsif ( len & 0xC0 ) == 0xC0
39
+ raise "data ended before offset expand" if datalen < ( offset + 2 )
40
+
41
+ ptr = data.unpack( "@#{ offset } n" ).first
42
+ ptr &= 0x3FFF
43
+ name2 = seek_dn( data, ptr ).first
44
+ raise "data is malformed" if name2.nil?
45
+
46
+ name += name2
47
+ offset += 2
48
+ break
49
+ else
50
+ offset += 1
51
+ raise "no expansion found" if datalen < ( offset + len )
52
+
53
+ elem = data[ offset..offset + len - 1 ]
54
+ name += "#{ elem }."
55
+ offset += len
56
+ end
57
+ end
58
+
59
+ [ name, offset ]
60
+ end
61
+
62
+ def seek_ip( data )
63
+ ip = nil
64
+ answer_count = data.unpack( "@6 n" ).first
65
+ # puts "debug answer count #{ answer_count }"
66
+ offset = seek_question( data )
67
+ # puts "debug offset #{ offset }"
68
+
69
+ answer_count.times do
70
+ ip, offset = seek_rr_ip( data, offset )
71
+
72
+ if ip then
73
+ break
74
+ end
75
+ end
76
+
77
+ ip
78
+ end
79
+
80
+ def seek_question( data )
81
+ offset = 12
82
+
83
+ loop do
84
+ len = data.unpack( "@#{ offset } C" ).first
85
+ # puts "debug len #{ len } #{ data[ offset + 1, len ] }"
86
+ break if len == 0
87
+ offset += ( 1 + len )
88
+ end
89
+
90
+ offset += 5
91
+ offset
92
+ end
93
+
94
+ def seek_question_dn( data )
95
+ id = data[ 0, 2 ]
96
+ parts = []
97
+ offset = 12
98
+
99
+ loop do
100
+ len = data.unpack( "@#{ offset } C" ).first
101
+ # puts "debug len #{ len } #{ data[ offset + 1, len ] }"
102
+ break if len == 0
103
+ parts << data[ offset + 1, len ]
104
+ offset += ( 1 + len )
105
+ end
106
+
107
+ type = data.unpack( "@#{ offset + 1 } n" ).first
108
+ # puts "debug id #{ id.inspect } dn #{ parts.join( '.' ).inspect } type #{ type }"
109
+ [ id, parts.join( '.' ), type ]
110
+ end
111
+
112
+ def seek_rr_ip( data, offset )
113
+ ip = nil
114
+ name, offset = seek_dn( data, offset )
115
+ # puts "debug seek_dn #{ name }, #{ offset }"
116
+ type = data.unpack( "@#{ offset } n" ).first
117
+ # puts "debug type #{ type }"
118
+ offset += 8
119
+ rdlen = data.unpack( "@#{ offset } n" ).first
120
+ # puts "debug rdlen #{ rdlen }"
121
+ offset += 2
122
+
123
+ if type == 1 then
124
+ raise "rdlen not 4?" if rdlen != 4
125
+ a, b, c, d = data.unpack( "@#{ offset } CCCC" )
126
+ ip = "#{ a }.#{ b }.#{ c }.#{ d }"
127
+ elsif type == 28 then
128
+ tokens = data.unpack("@#{ offset } n8")
129
+ ip = format( "%x:%x:%x:%x:%x:%x:%x:%x", *tokens )
130
+ end
131
+
132
+ offset += rdlen
133
+ [ ip, offset ]
134
+ end
135
+
136
+ end
137
+ end
data/lib/girl/head.rb ADDED
@@ -0,0 +1,20 @@
1
+ module Girl
2
+ BACKLOG = 512 # 听队列大小,满后掉SYN包
3
+ RLIMIT = 1024 # sock数上限
4
+ READ_SIZE = 4 * 1024 * 1024 # 一次读多少
5
+ WBUFF_LIMIT = 30 * 1024 * 1024 # 写前上限,超过上限暂停读
6
+ RESUME_BELOW = WBUFF_LIMIT / 2 # 降到多少以下恢复读
7
+ CLOSE_ABOVE = WBUFF_LIMIT * 3 # 超过多少强制关闭
8
+ HEARTBEAT_INTERVAL = 10 # 心跳间隔
9
+ CHECK_TRAFF_INTERVAL = 3600 # 检查今天是否是流量计数重置日间隔
10
+ HTTP_OK = "HTTP/1.1 200 OK\r\n\r\n"
11
+ RESERVED_ROUTE = <<EOF
12
+ 0.0.0.0/8
13
+ 10.0.0.0/8
14
+ 127.0.0.0/8
15
+ 169.254.0.0/16
16
+ 172.16.0.0/12
17
+ 192.168.0.0/16
18
+ 255.255.255.255/32
19
+ EOF
20
+ end
data/lib/girl/proxy.rb ADDED
@@ -0,0 +1,191 @@
1
+ require 'fileutils'
2
+ require 'girl/dns'
3
+ require 'girl/head'
4
+ require 'girl/proxy_worker'
5
+ require 'girl/version'
6
+ require 'ipaddr'
7
+ require 'json'
8
+ require 'socket'
9
+
10
+ ##
11
+ # Girl::Proxy - 近端
12
+ #
13
+ #
14
+ module Girl
15
+ class Proxy
16
+
17
+ def initialize( config_path = nil )
18
+ unless config_path then
19
+ config_path = File.expand_path( '../girl.conf.json', __FILE__ )
20
+ end
21
+
22
+ raise "missing config file #{ config_path }" unless File.exist?( config_path )
23
+
24
+ conf = JSON.parse( IO.binread( config_path ), symbolize_names: true )
25
+ puts "load #{ config_path } #{ conf.inspect }"
26
+ redir_port = conf[ :redir_port ]
27
+ memd_port = conf[ :memd_port ]
28
+ tspd_port = conf[ :tspd_port ]
29
+ proxyd_host = conf[ :proxyd_host ]
30
+ proxyd_port = conf[ :proxyd_port ]
31
+ nameserver = conf[ :nameserver ]
32
+ im = conf[ :im ]
33
+ direct_path = conf[ :direct_path ]
34
+ remote_path = conf[ :remote_path ]
35
+ appd_host = conf[ :appd_host ]
36
+ appd_port = conf[ :appd_port ]
37
+ head_len = conf[ :head_len ] # 头长度
38
+ h_a_new_source = conf[ :h_a_new_source ] # A
39
+ h_a_new_p2 = conf[ :h_a_new_p2 ] # B
40
+ h_dst_close = conf[ :h_dst_close ] # D
41
+ h_heartbeat = conf[ :h_heartbeat ] # H
42
+ h_p1_close = conf[ :h_p1_close ] # I
43
+ h_p2_close = conf[ :h_p2_close ] # J
44
+ h_p2_traffic = conf[ :h_p2_traffic ] # K
45
+ h_p1_overflow = conf[ :h_p1_overflow ] # L
46
+ h_p1_underhalf = conf[ :h_p1_underhalf ] # M
47
+ h_p2_overflow = conf[ :h_p2_overflow ] # N
48
+ h_p2_underhalf = conf[ :h_p2_underhalf ] # O
49
+ h_query = conf[ :h_query ] # Q
50
+ h_response = conf[ :h_response ] # R
51
+ h_src_close = conf[ :h_src_close ] # S
52
+ h_traffic = conf[ :h_traffic ] # T
53
+ h_src_overflow = conf[ :h_src_overflow ] # U
54
+ h_src_underhalf = conf[ :h_src_underhalf ] # V
55
+ h_dst_overflow = conf[ :h_dst_overflow ] # W
56
+ h_dst_underhalf = conf[ :h_dst_underhalf ] # X
57
+
58
+ expire_connecting = conf[ :expire_connecting ] # 连接多久没有建成关闭(秒)
59
+ expire_long_after = conf[ :expire_long_after ] # 长连接多久没有新流量关闭(秒)
60
+ expire_proxy_after = conf[ :expire_proxy_after ] # proxy多久没有收到流量重建(秒)
61
+ expire_resolv_cache = conf[ :expire_resolv_cache ] # dns查询结果缓存多久(秒)
62
+ expire_short_after = conf[ :expire_short_after ] # 短连接创建多久后关闭(秒)
63
+ is_debug = conf[ :is_debug ]
64
+
65
+ redir_port = redir_port ? redir_port.to_i : 6666
66
+ memd_port = memd_port ? memd_port.to_i : redir_port + 1
67
+ tspd_port = tspd_port ? tspd_port.to_i : 7777
68
+ raise "missing proxyd host" unless proxyd_host
69
+ proxyd_port = proxyd_port ? proxyd_port.to_i : 6060
70
+ nameserver = '114.114.114.114' unless nameserver
71
+ nameservers = nameserver.split( ' ' )
72
+ im = 'office-pc' unless im
73
+ directs = []
74
+
75
+ if direct_path then
76
+ raise "not found direct file #{ direct_path }" unless File.exist?( direct_path )
77
+ directs = ( RESERVED_ROUTE.split( "\n" ) + IO.binread( direct_path ).split( "\n" ) ).map{ | line | IPAddr.new( line.strip ) }
78
+ end
79
+
80
+ remotes = []
81
+
82
+ if remote_path then
83
+ raise "not found remote file #{ remote_path }" unless File.exist?( remote_path )
84
+ remotes = IO.binread( remote_path ).split( "\n" ).map{ | line | line.strip }
85
+ end
86
+
87
+ appd_host = appd_host ? appd_host.to_s : '127.0.0.1'
88
+ appd_port = appd_port ? appd_port.to_i : 22
89
+ head_len = head_len ? head_len.to_i : 59
90
+ h_a_new_source = h_a_new_source ? h_a_new_source.to_s : 'A'
91
+ h_a_new_p2 = h_a_new_p2 ? h_a_new_p2.to_s : 'B'
92
+ h_dst_close = h_dst_close ? h_dst_close.to_s : 'D'
93
+ h_heartbeat = h_heartbeat ? h_heartbeat.to_s : 'H'
94
+ h_p1_close = h_p1_close ? h_p1_close.to_s : 'I'
95
+ h_p2_close = h_p2_close ? h_p2_close.to_s : 'J'
96
+ h_p2_traffic = h_p2_traffic ? h_p2_traffic.to_s : 'K'
97
+ h_p1_overflow = h_p1_overflow ? h_p1_overflow.to_s : 'L'
98
+ h_p1_underhalf = h_p1_underhalf ? h_p1_underhalf.to_s : 'M'
99
+ h_p2_overflow = h_p2_overflow ? h_p2_overflow.to_s : 'N'
100
+ h_p2_underhalf = h_p2_underhalf ? h_p2_underhalf.to_s : 'O'
101
+ h_query = h_query ? h_query.to_s : 'Q'
102
+ h_response = h_response ? h_response.to_s : 'R'
103
+ h_src_close = h_src_close ? h_src_close.to_s : 'S'
104
+ h_traffic = h_traffic ? h_traffic.to_s : 'T'
105
+ h_src_overflow = h_src_overflow ? h_src_overflow.to_s : 'U'
106
+ h_src_underhalf = h_src_underhalf ? h_src_underhalf.to_s : 'V'
107
+ h_dst_overflow = h_dst_overflow ? h_dst_overflow.to_s : 'W'
108
+ h_dst_underhalf = h_dst_underhalf ? h_dst_underhalf.to_s : 'X'
109
+ expire_connecting = expire_connecting ? expire_connecting.to_i : 5
110
+ expire_long_after = expire_long_after ? expire_long_after.to_i : 3600
111
+ expire_proxy_after = expire_proxy_after ? expire_proxy_after.to_i : 60
112
+ expire_resolv_cache = expire_resolv_cache ? expire_resolv_cache.to_i : 600
113
+ expire_short_after = expire_short_after ? expire_short_after.to_i : 5
114
+ is_client_fastopen = is_server_fastopen = false
115
+
116
+ if RUBY_PLATFORM.include?( 'linux' ) then
117
+ IO.popen( 'sysctl -n net.ipv4.tcp_fastopen' ) do | io |
118
+ output = io.read
119
+ val = output.to_i % 4
120
+
121
+ if [ 1, 3 ].include?( val ) then
122
+ is_client_fastopen = true
123
+ end
124
+
125
+ if [ 2, 3 ].include?( val ) then
126
+ is_server_fastopen = true
127
+ end
128
+ end
129
+ end
130
+
131
+ puts "girl proxy #{ Girl::VERSION } #{ im }"
132
+ puts "#{ redir_port } #{ tspd_port } #{ proxyd_host } #{ proxyd_port } #{ appd_host } #{ appd_port } #{ nameservers.inspect } #{ is_client_fastopen } #{ is_server_fastopen }"
133
+ puts "#{ direct_path } #{ directs.size } directs"
134
+ puts "#{ remote_path } #{ remotes.size } remotes"
135
+
136
+ if %w[ darwin linux ].any?{ | plat | RUBY_PLATFORM.include?( plat ) } then
137
+ Process.setrlimit( :NOFILE, RLIMIT )
138
+ puts "NOFILE #{ Process.getrlimit( :NOFILE ).inspect }"
139
+ end
140
+
141
+ worker = Girl::ProxyWorker.new(
142
+ redir_port,
143
+ memd_port,
144
+ tspd_port,
145
+ proxyd_host,
146
+ proxyd_port,
147
+ nameservers,
148
+ im,
149
+ directs,
150
+ remotes,
151
+ appd_host,
152
+ appd_port,
153
+ head_len,
154
+ h_a_new_source,
155
+ h_a_new_p2,
156
+ h_dst_close,
157
+ h_heartbeat,
158
+ h_p1_close,
159
+ h_p2_close,
160
+ h_p2_traffic,
161
+ h_p1_overflow,
162
+ h_p1_underhalf,
163
+ h_p2_overflow,
164
+ h_p2_underhalf,
165
+ h_query,
166
+ h_response,
167
+ h_src_close,
168
+ h_traffic,
169
+ h_src_overflow,
170
+ h_src_underhalf,
171
+ h_dst_overflow,
172
+ h_dst_underhalf,
173
+ expire_connecting,
174
+ expire_long_after,
175
+ expire_proxy_after,
176
+ expire_resolv_cache,
177
+ expire_short_after,
178
+ is_debug,
179
+ is_client_fastopen,
180
+ is_server_fastopen )
181
+
182
+ Signal.trap( :TERM ) do
183
+ puts 'exit'
184
+ worker.quit!
185
+ end
186
+
187
+ worker.looping
188
+ end
189
+
190
+ end
191
+ end