shadowsocks_ruby 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/.yardopts +5 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +10 -0
- data/LICENSE.txt +21 -0
- data/README.md +160 -0
- data/Rakefile +14 -0
- data/bin/aruba +17 -0
- data/bin/bundler +17 -0
- data/bin/console +14 -0
- data/bin/cucumber +17 -0
- data/bin/einhorn +17 -0
- data/bin/einhornsh +17 -0
- data/bin/htmldiff +17 -0
- data/bin/ldiff +17 -0
- data/bin/lrucache_server +16 -0
- data/bin/rake +17 -0
- data/bin/rspec +17 -0
- data/bin/setup +8 -0
- data/bin/yard +17 -0
- data/bin/yardoc +17 -0
- data/bin/yri +17 -0
- data/config.example.json +6 -0
- data/exe/sslocal-ruby +4 -0
- data/exe/ssserver-ruby +4 -0
- data/lib/shadowsocks_ruby/app.rb +236 -0
- data/lib/shadowsocks_ruby/cipher/cipher.rb +112 -0
- data/lib/shadowsocks_ruby/cipher/openssl.rb +81 -0
- data/lib/shadowsocks_ruby/cipher/rbnacl.rb +64 -0
- data/lib/shadowsocks_ruby/cipher/rc4_md5.rb +54 -0
- data/lib/shadowsocks_ruby/cipher/table.rb +65 -0
- data/lib/shadowsocks_ruby/cli/sslocal_runner.rb +125 -0
- data/lib/shadowsocks_ruby/cli/ssserver_runner.rb +115 -0
- data/lib/shadowsocks_ruby/connections/backend_connection.rb +50 -0
- data/lib/shadowsocks_ruby/connections/connection.rb +195 -0
- data/lib/shadowsocks_ruby/connections/server_connection.rb +63 -0
- data/lib/shadowsocks_ruby/connections/tcp/client_connection.rb +43 -0
- data/lib/shadowsocks_ruby/connections/tcp/destination_connection.rb +19 -0
- data/lib/shadowsocks_ruby/connections/tcp/localbackend_connection.rb +29 -0
- data/lib/shadowsocks_ruby/connections/tcp/remoteserver_connection.rb +18 -0
- data/lib/shadowsocks_ruby/connections/udp/client_connection.rb +43 -0
- data/lib/shadowsocks_ruby/connections/udp/destination_connection.rb +18 -0
- data/lib/shadowsocks_ruby/connections/udp/localbackend_connection.rb +29 -0
- data/lib/shadowsocks_ruby/connections/udp/remoteserver_connection.rb +18 -0
- data/lib/shadowsocks_ruby/protocols/cipher/iv_cipher.rb +99 -0
- data/lib/shadowsocks_ruby/protocols/cipher/no_iv_cipher.rb +53 -0
- data/lib/shadowsocks_ruby/protocols/cipher/verify_sha1.rb +138 -0
- data/lib/shadowsocks_ruby/protocols/obfs/http_simple.rb +189 -0
- data/lib/shadowsocks_ruby/protocols/obfs/tls_ticket.rb +342 -0
- data/lib/shadowsocks_ruby/protocols/packet/plain.rb +51 -0
- data/lib/shadowsocks_ruby/protocols/packet/shadowsocks.rb +88 -0
- data/lib/shadowsocks_ruby/protocols/packet/socks5.rb +162 -0
- data/lib/shadowsocks_ruby/protocols/protocol.rb +164 -0
- data/lib/shadowsocks_ruby/protocols/protocol_stack.rb +117 -0
- data/lib/shadowsocks_ruby/util.rb +52 -0
- data/lib/shadowsocks_ruby/version.rb +3 -0
- data/lib/shadowsocks_ruby.rb +86 -0
- data/shadowsocks_ruby.gemspec +48 -0
- metadata +290 -0
@@ -0,0 +1,342 @@
|
|
1
|
+
require 'lrucache'
|
2
|
+
|
3
|
+
module ShadowsocksRuby
|
4
|
+
module Protocols
|
5
|
+
# TLS 1.2 Obfuscation Protocol
|
6
|
+
#
|
7
|
+
# Specification:
|
8
|
+
# * https://github.com/shadowsocksr/shadowsocksr/blob/manyuser/shadowsocks/obfsplugin/obfs_tls.py
|
9
|
+
# * https://github.com/shadowsocksr/obfsplugin/blob/master/c/tls1.2_ticket.c
|
10
|
+
#
|
11
|
+
# TLS 1.2 Reference:
|
12
|
+
# * https://en.wikipedia.org/wiki/Transport_Layer_Security
|
13
|
+
# * https://tools.ietf.org/html/rfc5246
|
14
|
+
# * https://tools.ietf.org/html/rfc5077
|
15
|
+
# * https://tools.ietf.org/html/rfc6066
|
16
|
+
class TlsTicketProtocol
|
17
|
+
include DummyHelper
|
18
|
+
include BufferHelper
|
19
|
+
|
20
|
+
VERSION_SSL_3_0 = [3, 0]
|
21
|
+
VERSION_TLS_1_0 = [3, 1]
|
22
|
+
VERSION_TLS_1_1 = [3, 2]
|
23
|
+
VERSION_TLS_1_2 = [3, 3]
|
24
|
+
|
25
|
+
#Content types
|
26
|
+
CTYPE_ChangeCipherSpec = 0x14
|
27
|
+
CTYPE_Alert = 0x15
|
28
|
+
CTYPE_Handshake = 0x16
|
29
|
+
CTYPE_Application = 0x17
|
30
|
+
CTYPE_Heartbeat = 0x18
|
31
|
+
|
32
|
+
#Message types
|
33
|
+
MTYPE_HelloRequest = 0
|
34
|
+
MTYPE_ClientHello = 1
|
35
|
+
MTYPE_ServerHello = 2
|
36
|
+
MTYPE_NewSessionTicket = 4
|
37
|
+
MTYPE_Certificate = 11
|
38
|
+
MTYPE_ServerKeyExchange = 12
|
39
|
+
MTYPE_CertificateRequest = 13
|
40
|
+
MTYPE_ServerHelloDone = 14
|
41
|
+
MTYPE_CertificateVerify = 15
|
42
|
+
MTYPE_ClientKeyExchange = 16
|
43
|
+
MTYPE_Finished = 20
|
44
|
+
|
45
|
+
attr_accessor :next_protocol
|
46
|
+
|
47
|
+
# @param [Hash] configuration parameters
|
48
|
+
# @option params [String] :host shadowsocks server address, required by remoteserver protocol
|
49
|
+
# @option params [String] :key key, required by both remoteserver and localbackend protocol
|
50
|
+
# @option params [Boolean] :compatible compatibility with origin mode, default _true_
|
51
|
+
# @option params [String] :obfs_param obfs param, optional
|
52
|
+
# @option params [LRUCache] :lrucache lrucache, optional, it intened to be a lrucache Proxy if provided
|
53
|
+
def initialize params = {}
|
54
|
+
@params = {:compatible => true}.merge(params)
|
55
|
+
@buffer = ''
|
56
|
+
@client_id = Random.new.bytes(32)
|
57
|
+
@max_time_dif = 60 * 60 * 24 # time dif (second) setting
|
58
|
+
@startup_time = Time.now.to_i - 60 * 30
|
59
|
+
@client_data = @params[:lrucache] || LRUCache.new(:ttl => 60 * 5)
|
60
|
+
end
|
61
|
+
|
62
|
+
def tcp_send_to_remoteserver_first_packet data
|
63
|
+
send_client_change_cipherspec_and_finish data
|
64
|
+
|
65
|
+
class << self
|
66
|
+
alias tcp_send_to_remoteserver tcp_send_to_remoteserver_other_packet
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
alias tcp_send_to_remoteserver tcp_send_to_remoteserver_first_packet
|
72
|
+
|
73
|
+
# TLS 1.2 Application Pharse
|
74
|
+
def tcp_send_to_remoteserver_other_packet data
|
75
|
+
send_data_application_pharse data
|
76
|
+
end
|
77
|
+
|
78
|
+
def tcp_receive_from_remoteserver_first_packet n
|
79
|
+
send_client_hello
|
80
|
+
recv_server_hello
|
81
|
+
class << self
|
82
|
+
alias tcp_receive_from_remoteserver tcp_receive_from_remoteserver_other_packet
|
83
|
+
end
|
84
|
+
tcp_receive_from_remoteserver_other_packet n
|
85
|
+
end
|
86
|
+
|
87
|
+
alias tcp_receive_from_remoteserver tcp_receive_from_remoteserver_first_packet
|
88
|
+
|
89
|
+
# TLS 1.2 Application Pharse
|
90
|
+
def tcp_receive_from_remoteserver_other_packet n
|
91
|
+
head = async_recv 3
|
92
|
+
if head != [CTYPE_Application, *VERSION_TLS_1_2].pack("C3")
|
93
|
+
raise PharseError, "client_decode appdata error"
|
94
|
+
end
|
95
|
+
size = async_recv(2).unpack("n")[0]
|
96
|
+
@buffer << async_recv(size)
|
97
|
+
|
98
|
+
tcp_receive_from_remoteserver_other_packet_helper n
|
99
|
+
end
|
100
|
+
|
101
|
+
|
102
|
+
|
103
|
+
def tcp_receive_from_localbackend_first_packet n
|
104
|
+
class << self
|
105
|
+
alias tcp_receive_from_localbackend tcp_receive_from_localbackend_other_packet
|
106
|
+
end
|
107
|
+
recv_client_hello
|
108
|
+
@no_effect ||= nil
|
109
|
+
if !@no_effect
|
110
|
+
send_server_hello
|
111
|
+
recv_client_change_cipherspec_and_finish
|
112
|
+
tcp_receive_from_localbackend_other_packet n
|
113
|
+
else
|
114
|
+
tcp_receive_from_localbackend_other_packet_helper n
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
alias tcp_receive_from_localbackend tcp_receive_from_localbackend_first_packet
|
119
|
+
|
120
|
+
# TLS 1.2 Application Pharse
|
121
|
+
def tcp_receive_from_localbackend_other_packet n
|
122
|
+
@no_effect ||= nil
|
123
|
+
if !@no_effect
|
124
|
+
head = async_recv 3
|
125
|
+
if head != [CTYPE_Application, *VERSION_TLS_1_2].pack("C3")
|
126
|
+
raise PharseError, "server_decode appdata error"
|
127
|
+
end
|
128
|
+
size = async_recv(2).unpack("n")[0]
|
129
|
+
@buffer << async_recv(size)
|
130
|
+
end
|
131
|
+
|
132
|
+
tcp_receive_from_localbackend_other_packet_helper n
|
133
|
+
end
|
134
|
+
|
135
|
+
def tcp_send_to_localbackend data
|
136
|
+
@no_effect ||= nil
|
137
|
+
if !@no_effect
|
138
|
+
send_data_application_pharse data
|
139
|
+
else
|
140
|
+
send_data data
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
# helpers
|
145
|
+
def get_random
|
146
|
+
verifyid = [Time.now.to_i].pack("N") << Random.new.bytes(18)
|
147
|
+
hello = ""
|
148
|
+
hello << verifyid # Random part 1
|
149
|
+
hello << ShadowsocksRuby::Cipher.hmac_sha1_digest(@params[:key] + @client_id, verifyid) # Random part 2
|
150
|
+
end
|
151
|
+
|
152
|
+
def send_client_hello
|
153
|
+
client_hello = ""
|
154
|
+
|
155
|
+
client_hello << [*VERSION_TLS_1_2].pack("C2") # ProtocolVersion
|
156
|
+
client_hello << get_random # Random len 32
|
157
|
+
client_hello << [32].pack("C") << @client_id # SessionID
|
158
|
+
client_hello << Util.hex2bin("001cc02bc02fcca9cca8cc14cc13c00ac014c009c013009c0035002f000a") # CipherSuite
|
159
|
+
client_hello << Util.hex2bin("0100") # CompressionMethod
|
160
|
+
|
161
|
+
ext = Util.hex2bin("ff01000100") # Extension 1 (type ff01 + len 0001 + data 00 )
|
162
|
+
|
163
|
+
hosts = @params[:obfs_param] || @params[:host]
|
164
|
+
if (hosts == nil or hosts == "")
|
165
|
+
raise PharseError, "No :host or :obfs_param parameters"
|
166
|
+
end
|
167
|
+
if (("0".."9").include? hosts[-1])
|
168
|
+
hosts = ""
|
169
|
+
end
|
170
|
+
hosts = hosts.split(",")
|
171
|
+
if hosts.length != 0
|
172
|
+
host = hosts[Random.rand(hosts.length)]
|
173
|
+
else
|
174
|
+
host = ""
|
175
|
+
end
|
176
|
+
ext << make_ext_sni(host) # Extension 2
|
177
|
+
ext << Util.hex2bin("00170000") # Extension 3 (type 0017 + len 0000)
|
178
|
+
ext << Util.hex2bin("002300d0") << Random.new.bytes(208) # ticket, Extension 4 (type 0023 + len 00d0 + data)
|
179
|
+
ext << Util.hex2bin("000d001600140601060305010503040104030301030302010203") # Extension 5 (type 000d + len 0016 + data)
|
180
|
+
ext << Util.hex2bin("000500050100000000") # Extension 6 (type 0005 + len 0005 + data)
|
181
|
+
ext << Util.hex2bin("00120000") # Extension 7 (type 0012 + len 0000)
|
182
|
+
ext << Util.hex2bin("75500000") # Extension 8 (type 7550 + len 0000)
|
183
|
+
ext << Util.hex2bin("000b00020100") # Extension 9 (type 000b + len 0002 + data)
|
184
|
+
ext << Util.hex2bin("000a0006000400170018") # Extension 10 (type 000a + len 0006 + data)
|
185
|
+
|
186
|
+
client_hello << [ext.length].pack("n") << ext # Extension List
|
187
|
+
|
188
|
+
client_handshake_message = [MTYPE_ClientHello, 0, client_hello.length].pack("CCn") << client_hello
|
189
|
+
handshake_message = [CTYPE_Handshake,*VERSION_TLS_1_0, client_handshake_message.length].pack("C3n") << client_handshake_message
|
190
|
+
|
191
|
+
send_data(handshake_message)
|
192
|
+
end
|
193
|
+
|
194
|
+
def send_client_change_cipherspec_and_finish data
|
195
|
+
buf = ""
|
196
|
+
buf << [CTYPE_ChangeCipherSpec, *VERSION_TLS_1_2, 0, 1, 1].pack("C*")
|
197
|
+
buf << [CTYPE_Handshake, *VERSION_TLS_1_2, 32].pack("C3n") << Random.new.bytes(22)
|
198
|
+
buf << ShadowsocksRuby::Cipher::hmac_sha1_digest(@params[:key] + @client_id, buf)
|
199
|
+
buf << [CTYPE_Application, *VERSION_TLS_1_2, data.length].pack("C3n") << data
|
200
|
+
send_data buf
|
201
|
+
end
|
202
|
+
|
203
|
+
def recv_server_hello
|
204
|
+
data = async_recv(129) # ServerHello 76 + ServerChangeSipherSpec 6 + Finished 37
|
205
|
+
verify = data[11 ... 33]
|
206
|
+
if ShadowsocksRuby::Cipher.hmac_sha1_digest(@params[:key] + @client_id, verify) != data[33 ... 43]
|
207
|
+
raise PharseError, "client_decode data error"
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
def recv_client_hello
|
212
|
+
data = async_recv 3
|
213
|
+
if data != [CTYPE_Handshake, *VERSION_TLS_1_0].pack("C3")
|
214
|
+
if @params[:compatible]
|
215
|
+
@buffer = data
|
216
|
+
@no_effect = true
|
217
|
+
return
|
218
|
+
else
|
219
|
+
raise PharseError, "decode error"
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
len_client_handshake_message = async_recv(2).unpack("n")[0]
|
224
|
+
client_handshake_message = async_recv(len_client_handshake_message)
|
225
|
+
|
226
|
+
if (client_handshake_message.slice!(0, 2) != [MTYPE_ClientHello, 0].pack("C2"))
|
227
|
+
raise PharseError, "tls_auth not client hello message"
|
228
|
+
end
|
229
|
+
|
230
|
+
len_client_hello = client_handshake_message.slice!(0, 2).unpack("n")[0]
|
231
|
+
client_hello = client_handshake_message
|
232
|
+
|
233
|
+
if (len_client_hello != client_hello.length )
|
234
|
+
raise PharseError, "tls_auth wrong message size"
|
235
|
+
end
|
236
|
+
|
237
|
+
if (client_hello.slice!(0,2) != [*VERSION_TLS_1_2].pack("C2"))
|
238
|
+
raise PharseError, "tls_auth wrong tls version"
|
239
|
+
end
|
240
|
+
|
241
|
+
verifyid = client_hello.slice!(0, 32)
|
242
|
+
|
243
|
+
len_sessionid = client_hello.slice!(0,1).unpack("C")[0]
|
244
|
+
if (len_sessionid < 32)
|
245
|
+
raise PharseError, "tls_auth wrong sessionid_len"
|
246
|
+
end
|
247
|
+
|
248
|
+
sessionid = client_hello.slice!(0, len_sessionid)
|
249
|
+
@client_id = sessionid
|
250
|
+
|
251
|
+
sha1 = ShadowsocksRuby::Cipher::hmac_sha1_digest(@params[:key] + sessionid, verifyid[0, 22])
|
252
|
+
utc_time = Time.at(verifyid[0, 4].unpack("N")[0])
|
253
|
+
time_dif = Time.now.to_i - utc_time.to_i
|
254
|
+
|
255
|
+
#if @params[:obfs_param] != nil
|
256
|
+
# @max_time_dif = @params[:obfs_param].to_i
|
257
|
+
#end
|
258
|
+
if @max_time_dif > 0 && (time_dif.abs > @max_time_dif or utc_time.to_i - @startup_time < - @max_time_dif / 2)
|
259
|
+
raise PharseError, "tls_auth wrong time"
|
260
|
+
end
|
261
|
+
|
262
|
+
if sha1 != verifyid[22 .. -1]
|
263
|
+
raise PharseError, "tls_auth wrong sha1"
|
264
|
+
end
|
265
|
+
|
266
|
+
if @client_data[verifyid[0, 22]]
|
267
|
+
raise PharseError, "replay attack detect, id = #{Util.bin2hex(verifyid)}"
|
268
|
+
end
|
269
|
+
@client_data[verifyid[0, 22]] = sessionid
|
270
|
+
end
|
271
|
+
|
272
|
+
def send_server_hello
|
273
|
+
data = [*VERSION_TLS_1_2].pack("C2")
|
274
|
+
data << get_random
|
275
|
+
data << Util.hex2bin("20") # len 32 in decimal
|
276
|
+
data << @client_id
|
277
|
+
data << Util.hex2bin("c02f000005ff01000100")
|
278
|
+
data = Util.hex2bin("0200") << [data.length].pack("n") << data
|
279
|
+
data = Util.hex2bin("160303") << [data.length].pack("n") << data # ServerHello len 86 (11 + 32 + 1 + 32 + 10)
|
280
|
+
data << Util.hex2bin("14") << [*VERSION_TLS_1_2].pack("C2") << Util.hex2bin("000101") # ChangeCipherSpec len (6)
|
281
|
+
data << Util.hex2bin("16") << [*VERSION_TLS_1_2].pack("C2") << Util.hex2bin("0020") << Random.new.bytes(22)
|
282
|
+
data << ShadowsocksRuby::Cipher.hmac_sha1_digest(@params[:key] + @client_id, data) # Finished len(37)
|
283
|
+
send_data data # len 129
|
284
|
+
end
|
285
|
+
|
286
|
+
def recv_client_change_cipherspec_and_finish
|
287
|
+
data = async_recv 43
|
288
|
+
if data[0, 6] != [CTYPE_ChangeCipherSpec, *VERSION_TLS_1_2, 0, 1, 1].pack("C*") # ChangeCipherSpec
|
289
|
+
raise PharseError, "server_decode data error"
|
290
|
+
end
|
291
|
+
if data[6, 5] != [CTYPE_Handshake, *VERSION_TLS_1_2, 32].pack("C3n") # Finished
|
292
|
+
raise PharseError, "server_decode data error"
|
293
|
+
end
|
294
|
+
if ShadowsocksRuby::Cipher.hmac_sha1_digest(@params[:key] + @client_id, data[0, 33]) != data[33, 10]
|
295
|
+
raise PharseError, "server_decode data error"
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
299
|
+
def send_data_application_pharse data
|
300
|
+
buf = ""
|
301
|
+
while data.length > 2048
|
302
|
+
size = [Random.rand(65535) % 4096 + 100, data.length].min
|
303
|
+
buf << [CTYPE_Application, *VERSION_TLS_1_2, size].pack("C3n") << data.slice!(0, size)
|
304
|
+
end
|
305
|
+
if data.length > 0
|
306
|
+
buf << [CTYPE_Application, *VERSION_TLS_1_2, data.length].pack("C3n") << data
|
307
|
+
end
|
308
|
+
send_data buf
|
309
|
+
end
|
310
|
+
|
311
|
+
def make_ext_sni host
|
312
|
+
name_type = 0 #host_name
|
313
|
+
server_name = [name_type, host.length].pack("Cn") << host
|
314
|
+
server_name_list = [server_name.length].pack("n") << server_name
|
315
|
+
|
316
|
+
type = Util.hex2bin("0000")
|
317
|
+
data = [server_name_list.length].pack("n") << server_name_list
|
318
|
+
|
319
|
+
return type << data
|
320
|
+
end
|
321
|
+
|
322
|
+
alias tcp_receive_from_client raise_me
|
323
|
+
alias tcp_send_to_client raise_me
|
324
|
+
#alias tcp_receive_from_remoteserver raise_me
|
325
|
+
#alias tcp_send_to_remoteserver raise_me
|
326
|
+
#alias tcp_receive_from_localbackend raise_me
|
327
|
+
#alias tcp_send_to_localbackend raise_me
|
328
|
+
alias tcp_receive_from_destination raise_me
|
329
|
+
alias tcp_send_to_destination raise_me
|
330
|
+
|
331
|
+
alias udp_receive_from_client raise_me
|
332
|
+
alias udp_send_to_client raise_me
|
333
|
+
alias udp_receive_from_remoteserver raise_me
|
334
|
+
alias udp_send_to_remoteserver raise_me
|
335
|
+
alias udp_receive_from_localbackend raise_me
|
336
|
+
alias udp_send_to_localbackend raise_me
|
337
|
+
alias udp_receive_from_destination raise_me
|
338
|
+
alias udp_send_to_destination raise_me
|
339
|
+
end
|
340
|
+
|
341
|
+
end
|
342
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module ShadowsocksRuby
|
2
|
+
module Protocols
|
3
|
+
# Relay data from peer to plexer without any process.
|
4
|
+
# This is a packet protocol, so no need to implement @buffer
|
5
|
+
class PlainProtocol
|
6
|
+
include DummyHelper
|
7
|
+
|
8
|
+
attr_accessor :next_protocol
|
9
|
+
|
10
|
+
# @param [Hash] configuration parameters
|
11
|
+
def initialize params = {}
|
12
|
+
@params = {}.merge(params)
|
13
|
+
end
|
14
|
+
|
15
|
+
def tcp_receive_from_destination n
|
16
|
+
async_recv n
|
17
|
+
end
|
18
|
+
|
19
|
+
def tcp_send_to_destination data
|
20
|
+
send_data data
|
21
|
+
end
|
22
|
+
|
23
|
+
def udp_receive_from_destination n
|
24
|
+
async_recv n
|
25
|
+
end
|
26
|
+
|
27
|
+
def udp_send_to_destination data
|
28
|
+
send_data data
|
29
|
+
end
|
30
|
+
|
31
|
+
alias tcp_receive_from_client raise_me
|
32
|
+
alias tcp_send_to_client raise_me
|
33
|
+
alias tcp_receive_from_remoteserver raise_me
|
34
|
+
alias tcp_send_to_remoteserver raise_me
|
35
|
+
alias tcp_receive_from_localbackend raise_me
|
36
|
+
alias tcp_send_to_localbackend raise_me
|
37
|
+
#alias tcp_receive_from_destination raise_me
|
38
|
+
#alias tcp_send_to_destination raise_me
|
39
|
+
|
40
|
+
alias udp_receive_from_client raise_me
|
41
|
+
alias udp_send_to_client raise_me
|
42
|
+
alias udp_receive_from_remoteserver raise_me
|
43
|
+
alias udp_send_to_remoteserver raise_me
|
44
|
+
alias udp_receive_from_localbackend raise_me
|
45
|
+
alias udp_send_to_localbackend raise_me
|
46
|
+
#alias udp_receive_from_destination raise_me
|
47
|
+
#alias udp_send_to_destination raise_me
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
module ShadowsocksRuby
|
2
|
+
module Protocols
|
3
|
+
# Shadowsocks packet protocol for both origin shadowsocks protocol and OTA shadowsocks protocol.
|
4
|
+
#
|
5
|
+
# specification:
|
6
|
+
# * https://shadowsocks.org/en/spec/protocol.html
|
7
|
+
# * https://shadowsocks.org/en/spec/one-time-auth.html
|
8
|
+
#
|
9
|
+
# This is a packet protocol, so no need to implement @buffer
|
10
|
+
class ShadowsocksProtocol
|
11
|
+
include DummyHelper
|
12
|
+
|
13
|
+
attr_accessor :next_protocol
|
14
|
+
|
15
|
+
ATYP_IPV4 = 1
|
16
|
+
ATYP_DOMAIN = 3
|
17
|
+
ATYP_IPV6 = 4
|
18
|
+
|
19
|
+
# @param [Hash] configuration parameters
|
20
|
+
def initialize params = {}
|
21
|
+
end
|
22
|
+
|
23
|
+
def tcp_receive_from_localbackend_first_packet n
|
24
|
+
buf = ""
|
25
|
+
s = async_recv(1)
|
26
|
+
buf << s
|
27
|
+
address_type = s.unpack("C").first
|
28
|
+
case address_type
|
29
|
+
when ATYP_IPV4
|
30
|
+
buf << async_recv(4)
|
31
|
+
when ATYP_IPV6
|
32
|
+
buf << async_recv(16)
|
33
|
+
when ATYP_DOMAIN
|
34
|
+
buf << (s = async_recv(1))
|
35
|
+
domain_len = s.unpack("C").first
|
36
|
+
buf << async_recv(domain_len)
|
37
|
+
buf << async_recv(2) # port
|
38
|
+
else
|
39
|
+
raise PharseError, "unknown address_type: #{address_type}"
|
40
|
+
end
|
41
|
+
|
42
|
+
class << self
|
43
|
+
alias tcp_receive_from_localbackend tcp_receive_from_localbackend_other_packet
|
44
|
+
end
|
45
|
+
# first packet is special:
|
46
|
+
# ATYP + Destination Address + Destination Port
|
47
|
+
buf
|
48
|
+
end
|
49
|
+
|
50
|
+
alias tcp_receive_from_localbackend tcp_receive_from_localbackend_first_packet
|
51
|
+
|
52
|
+
def tcp_receive_from_localbackend_other_packet n
|
53
|
+
async_recv(n)
|
54
|
+
end
|
55
|
+
|
56
|
+
def tcp_send_to_localbackend data
|
57
|
+
send_data data
|
58
|
+
end
|
59
|
+
|
60
|
+
def tcp_receive_from_remoteserver n
|
61
|
+
async_recv(n)
|
62
|
+
end
|
63
|
+
|
64
|
+
def tcp_send_to_remoteserver data
|
65
|
+
send_data data
|
66
|
+
end
|
67
|
+
|
68
|
+
alias tcp_receive_from_client raise_me
|
69
|
+
alias tcp_send_to_client raise_me
|
70
|
+
#alias tcp_receive_from_remoteserver raise_me
|
71
|
+
#alias tcp_send_to_remoteserver raise_me
|
72
|
+
#alias tcp_receive_from_localbackend raise_me
|
73
|
+
#alias tcp_send_to_localbackend raise_me
|
74
|
+
alias tcp_receive_from_destination raise_me
|
75
|
+
alias tcp_send_to_destination raise_me
|
76
|
+
|
77
|
+
alias udp_receive_from_client raise_me
|
78
|
+
alias udp_send_to_client raise_me
|
79
|
+
alias udp_receive_from_remoteserver raise_me
|
80
|
+
alias udp_send_to_remoteserver raise_me
|
81
|
+
alias udp_receive_from_localbackend raise_me
|
82
|
+
alias udp_send_to_localbackend raise_me
|
83
|
+
alias udp_receive_from_destination raise_me
|
84
|
+
alias udp_send_to_destination raise_me
|
85
|
+
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,162 @@
|
|
1
|
+
require 'ipaddr'
|
2
|
+
|
3
|
+
module ShadowsocksRuby
|
4
|
+
module Protocols
|
5
|
+
# SOCKS 5 protocol
|
6
|
+
#
|
7
|
+
# specification :
|
8
|
+
# * http://tools.ieft.org/html/rfc1928
|
9
|
+
# * http://en.wikipedia.org/wiki/SOCKS
|
10
|
+
# @note Now only implemented the server side protocol, not the client side protocol.
|
11
|
+
class Socks5Protocol
|
12
|
+
include DummyHelper
|
13
|
+
|
14
|
+
attr_accessor :next_protocol
|
15
|
+
|
16
|
+
METHOD_NO_AUTH = 0
|
17
|
+
CMD_CONNECT = 1
|
18
|
+
REP_SUCCESS = 0
|
19
|
+
RESERVED = 0
|
20
|
+
ATYP_IPV4 = 1
|
21
|
+
ATYP_DOMAIN = 3
|
22
|
+
ATYP_IPV6 = 4
|
23
|
+
SOCKS5 = 5
|
24
|
+
|
25
|
+
# @param [Hash] configuration parameters
|
26
|
+
def initialize params = {}
|
27
|
+
@params = {}.merge(params)
|
28
|
+
end
|
29
|
+
|
30
|
+
def tcp_receive_from_client_first_packet n
|
31
|
+
# check version
|
32
|
+
version = async_recv(1).unpack("C").first
|
33
|
+
if version != SOCKS5
|
34
|
+
raise PharseError, "SOCKS version not supported: #{version.inspect}"
|
35
|
+
end
|
36
|
+
|
37
|
+
# client handshake v5
|
38
|
+
nmethods = async_recv(1).unpack("C").first
|
39
|
+
*methods = async_recv(nmethods).unpack("C*")
|
40
|
+
if methods.include?(METHOD_NO_AUTH)
|
41
|
+
packet = [SOCKS5, METHOD_NO_AUTH].pack("C*")
|
42
|
+
send_data packet
|
43
|
+
else
|
44
|
+
raise PharseError, 'Unsupported authentication method. Only "No Authentication" is supported'
|
45
|
+
end
|
46
|
+
|
47
|
+
version, command, reserved = async_recv(3).unpack("C3")
|
48
|
+
buf =''
|
49
|
+
buf << (s = async_recv(1))
|
50
|
+
address_type = s.unpack("C").first
|
51
|
+
case address_type
|
52
|
+
when ATYP_IPV4
|
53
|
+
buf << async_recv(4)
|
54
|
+
when ATYP_IPV6
|
55
|
+
buf << async_recv(16)
|
56
|
+
when ATYP_DOMAIN
|
57
|
+
buf << (s = async_recv(1))
|
58
|
+
domain_len = s.unpack("C").first
|
59
|
+
buf << async_recv(domain_len)
|
60
|
+
buf << async_recv(2) # port
|
61
|
+
else
|
62
|
+
raise PharseError, "unknown address_type: #{address_type}"
|
63
|
+
end
|
64
|
+
|
65
|
+
packet = ([SOCKS5, REP_SUCCESS, RESERVED, 1, 0, 0, 0, 0, 0]).pack("C8n")
|
66
|
+
send_data packet
|
67
|
+
class << self
|
68
|
+
alias tcp_receive_from_client tcp_receive_from_client_other_packet
|
69
|
+
end
|
70
|
+
|
71
|
+
# first packet is special:
|
72
|
+
# ATYP + Destination Address + Destination Port
|
73
|
+
buf
|
74
|
+
end
|
75
|
+
|
76
|
+
alias tcp_receive_from_client tcp_receive_from_client_first_packet
|
77
|
+
|
78
|
+
def tcp_receive_from_client_other_packet n
|
79
|
+
async_recv(n)
|
80
|
+
end
|
81
|
+
|
82
|
+
def tcp_send_to_client data
|
83
|
+
send_data data
|
84
|
+
end
|
85
|
+
|
86
|
+
def tcp_receive_from_localbackend_first_packet n
|
87
|
+
# check version
|
88
|
+
version = async_recv(1).unpack("C").first
|
89
|
+
if version != SOCKS5
|
90
|
+
raise PharseError, "SOCKS version not supported: #{version.inspect}"
|
91
|
+
end
|
92
|
+
|
93
|
+
# client handshake v5
|
94
|
+
nmethods = async_recv(1).unpack("C").first
|
95
|
+
*methods = async_recv(nmethods).unpack("C*")
|
96
|
+
if methods.include?(METHOD_NO_AUTH)
|
97
|
+
packet = [SOCKS5, METHOD_NO_AUTH].pack("C*")
|
98
|
+
send_data packet
|
99
|
+
else
|
100
|
+
raise PharseError, 'Unsupported authentication method. Only "No Authentication" is supported'
|
101
|
+
end
|
102
|
+
|
103
|
+
version, command, reserved = async_recv(3).unpack("C3")
|
104
|
+
buf =''
|
105
|
+
buf << (s = async_recv(1))
|
106
|
+
address_type = s.unpack("C").first
|
107
|
+
case address_type
|
108
|
+
when ATYP_IPV4
|
109
|
+
buf << async_recv(4)
|
110
|
+
when ATYP_IPV6
|
111
|
+
buf << async_recv(16)
|
112
|
+
when ATYP_DOMAIN
|
113
|
+
buf << (s = async_recv(1))
|
114
|
+
domain_len = s.unpack("C").first
|
115
|
+
buf << async_recv(domain_len)
|
116
|
+
buf << async_recv(2) # port
|
117
|
+
else
|
118
|
+
raise PharseError, "unknown address_type: #{address_type}"
|
119
|
+
end
|
120
|
+
|
121
|
+
packet = ([SOCKS5, REP_SUCCESS, RESERVED, 1, 0, 0, 0, 0, 0]).pack("C8n")
|
122
|
+
send_data packet
|
123
|
+
|
124
|
+
class << self
|
125
|
+
alias tcp_receive_from_localbackend tcp_receive_from_localbackend_other_packet
|
126
|
+
end
|
127
|
+
|
128
|
+
# first packet is special:
|
129
|
+
# ATYP + Destination Address + Destination Port
|
130
|
+
buf
|
131
|
+
end
|
132
|
+
|
133
|
+
alias tcp_receive_from_localbackend tcp_receive_from_localbackend_first_packet
|
134
|
+
|
135
|
+
def tcp_receive_from_localbackend_other_packet n
|
136
|
+
async_recv(n)
|
137
|
+
end
|
138
|
+
|
139
|
+
def tcp_send_to_localbackend data
|
140
|
+
send_data data
|
141
|
+
end
|
142
|
+
|
143
|
+
#alias tcp_receive_from_client raise_me
|
144
|
+
#alias tcp_send_to_client raise_me
|
145
|
+
alias tcp_receive_from_remoteserver raise_me
|
146
|
+
alias tcp_send_to_remoteserver raise_me
|
147
|
+
#alias tcp_receive_from_localbackend raise_me
|
148
|
+
#alias tcp_send_to_localbackend raise_me
|
149
|
+
alias tcp_receive_from_destination raise_me
|
150
|
+
alias tcp_send_to_destination raise_me
|
151
|
+
|
152
|
+
alias udp_receive_from_client raise_me
|
153
|
+
alias udp_send_to_client raise_me
|
154
|
+
alias udp_receive_from_remoteserver raise_me
|
155
|
+
alias udp_send_to_remoteserver raise_me
|
156
|
+
alias udp_receive_from_localbackend raise_me
|
157
|
+
alias udp_send_to_localbackend raise_me
|
158
|
+
alias udp_receive_from_destination raise_me
|
159
|
+
alias udp_send_to_destination raise_me
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|