girl 9.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/girl.gemspec +30 -0
- data/lib/girl/dns.rb +137 -0
- data/lib/girl/head.rb +20 -0
- data/lib/girl/proxy.rb +191 -0
- data/lib/girl/proxy_worker.rb +1860 -0
- data/lib/girl/proxyd.rb +173 -0
- data/lib/girl/proxyd_worker.rb +1409 -0
- data/lib/girl/version.rb +3 -0
- data/lib/girl.rb +2 -0
- metadata +52 -0
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
|