shadowsocks 0.3 → 0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +4 -2
- data/config.json +2 -1
- data/lib/shadowsocks.rb +1 -0
- data/lib/shadowsocks/cli.rb +15 -3
- data/lib/shadowsocks/config.rb +4 -2
- data/lib/shadowsocks/connection.rb +10 -0
- data/lib/shadowsocks/crypto.rb +133 -0
- data/lib/shadowsocks/listener.rb +1 -3
- data/lib/shadowsocks/local.rb +5 -5
- data/lib/shadowsocks/server.rb +3 -3
- data/lib/shadowsocks/table.rb +2 -2
- data/lib/shadowsocks/tunnel.rb +3 -7
- data/lib/shadowsocks/version.rb +1 -1
- metadata +2 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1e13759da84263a5a81769afcb8e2d99b511766b
|
4
|
+
data.tar.gz: 9f0049ec6920bc351fc0c04017f22dbfd2cf8104
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 44a5fb86332bcbdadc27978a6dcebc2f8f215b8cb7daed472d4b84763d63dfdf1b2740136490bda9fa2c5be6385cf1f1c3c736c187d820eb620869b139e44606
|
7
|
+
data.tar.gz: 9d8ae8792552c49c434b2ee6abf4ca323e81e09c4d6bae01464a0afcb28dd254f5be834915d4695cba575350d6d3d0cb961bb4e3cd3cb6eec699ee5bddd1b0f8
|
data/README.md
CHANGED
@@ -3,7 +3,7 @@ shadowsocks-ruby
|
|
3
3
|
|
4
4
|
[![Code Climate](https://codeclimate.com/repos/524baea6c7f3a37df208dd4c/badges/9dd6c11b6a17c3a55631/gpa.png)](https://codeclimate.com/repos/524baea6c7f3a37df208dd4c/feed)
|
5
5
|
|
6
|
-
Current version: 0.
|
6
|
+
Current version: 0.4
|
7
7
|
|
8
8
|
shadowsocks-ruby is a lightweight tunnel proxy which can help you get through firewalls. It is a port of [shadowsocks](https://github.com/clowwindy/shadowsocks).
|
9
9
|
|
@@ -26,7 +26,8 @@ Create a file named `config.json`, with the following content.
|
|
26
26
|
"server_port":8388,
|
27
27
|
"local_port":1080,
|
28
28
|
"password":"barfoo!",
|
29
|
-
"timeout":
|
29
|
+
"timeout":60,
|
30
|
+
"method":"aes-256-cfb"
|
30
31
|
}
|
31
32
|
|
32
33
|
Explanation of the fields:
|
@@ -36,6 +37,7 @@ Explanation of the fields:
|
|
36
37
|
local_port local port
|
37
38
|
password a password used to encrypt transfer
|
38
39
|
timeout in seconds
|
40
|
+
method encryption method, "bf-cfb", "aes-256-cfb", "des-cfb", "rc4", etc. Default is aes-256-cfb
|
39
41
|
|
40
42
|
`cd` into the directory of `config.json`. Run `ss-server` on your server. To run it in the background, run
|
41
43
|
`nohup ss-server -c ./config.json > log &`.
|
data/config.json
CHANGED
data/lib/shadowsocks.rb
CHANGED
data/lib/shadowsocks/cli.rb
CHANGED
@@ -7,12 +7,24 @@ module Shadowsocks
|
|
7
7
|
class Cli
|
8
8
|
include ::Shadowsocks::Table
|
9
9
|
|
10
|
-
attr_accessor :side, :args, :config
|
10
|
+
attr_accessor :side, :args, :config
|
11
11
|
|
12
12
|
def initialize(options)
|
13
13
|
@side = options[:side]
|
14
14
|
@config = options[:config]
|
15
|
-
|
15
|
+
|
16
|
+
@method_options = {
|
17
|
+
method: config.method,
|
18
|
+
password: config.password
|
19
|
+
}
|
20
|
+
|
21
|
+
if @config.method == 'table'
|
22
|
+
table = get_table(config.password)
|
23
|
+
@method_options.merge!(
|
24
|
+
encrypt_table: table[:encrypt],
|
25
|
+
decrypt_table: table[:decrypt]
|
26
|
+
)
|
27
|
+
end
|
16
28
|
end
|
17
29
|
|
18
30
|
def run
|
@@ -43,7 +55,7 @@ module Shadowsocks
|
|
43
55
|
|
44
56
|
def initialize_connection connection
|
45
57
|
connection.config = @config
|
46
|
-
connection.
|
58
|
+
connection.crypto = Shadowsocks::Crypto.new @method_options
|
47
59
|
connection.pending_connect_timeout = @config.timeout
|
48
60
|
end
|
49
61
|
|
data/lib/shadowsocks/config.rb
CHANGED
@@ -2,7 +2,7 @@ require 'json'
|
|
2
2
|
|
3
3
|
module Shadowsocks
|
4
4
|
class Config
|
5
|
-
attr_reader :args, :server, :server_port, :local_port, :password, :timeout, :config_path
|
5
|
+
attr_reader :args, :server, :server_port, :local_port, :password, :timeout, :method, :config_path
|
6
6
|
|
7
7
|
def initialize(_args)
|
8
8
|
@args = _args || []
|
@@ -22,6 +22,7 @@ module Shadowsocks
|
|
22
22
|
@server_port = json["server_port"].to_i if @server_port.nil?
|
23
23
|
@local_port = json["local_port"].to_i if @local_port.nil?
|
24
24
|
@timeout = json["timeout"].to_i if @timeout.nil?
|
25
|
+
@method = json["method"] if @method.nil?
|
25
26
|
end
|
26
27
|
|
27
28
|
private
|
@@ -37,7 +38,8 @@ module Shadowsocks
|
|
37
38
|
opts.on("-k", "--password PASSWORD", "Password, should be same in client and server sides") { |c| @password = c }
|
38
39
|
opts.on("-c", "--config PATH", "config.json path") { |c| @config_path = c }
|
39
40
|
opts.on("-p", "--port PORT", Integer, "Remote server port") { |c| @server_port = c }
|
40
|
-
opts.on("-l", "--local_port PORT", Integer,"Local client port")
|
41
|
+
opts.on("-l", "--local_port PORT", Integer, "Local client port") { |c| @local_port = c }
|
42
|
+
opts.on("-m", "--method METHOD", Integer, "Encryption method") { |c| @method = c }
|
41
43
|
opts.on("-t", "--timeout NUMBER", Integer, "connection timeout") { |c| @timeout = c }
|
42
44
|
|
43
45
|
opts.on_tail("-v", "--version", "Show shadowsocks gem version") { puts Shadowsocks::VERSION; exit }
|
@@ -2,8 +2,18 @@ module Shadowsocks
|
|
2
2
|
class Connection < EventMachine::Connection
|
3
3
|
BackpressureLevel = 2097152 # 2m
|
4
4
|
|
5
|
+
attr_accessor :crypto
|
6
|
+
|
5
7
|
private
|
6
8
|
|
9
|
+
def encrypt(buf)
|
10
|
+
crypto.encrypt(buf)
|
11
|
+
end
|
12
|
+
|
13
|
+
def decrypt(buf)
|
14
|
+
crypto.decrypt(buf)
|
15
|
+
end
|
16
|
+
|
7
17
|
def over_pressure?
|
8
18
|
remote.get_outbound_data_size > BackpressureLevel
|
9
19
|
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
require 'openssl'
|
3
|
+
require 'digest/md5'
|
4
|
+
|
5
|
+
module Shadowsocks
|
6
|
+
class Crypto
|
7
|
+
include ::Shadowsocks::Table
|
8
|
+
|
9
|
+
attr_accessor :encrypt_table, :decrypt_table, :password, :method,
|
10
|
+
:cipher, :bytes_to_key_results, :iv_sent
|
11
|
+
|
12
|
+
def method_supported
|
13
|
+
case method
|
14
|
+
when 'aes-128-cfb' then [16, 16]
|
15
|
+
when 'aes-192-cfb' then [24, 16]
|
16
|
+
when 'aes-256-cfb' then [32, 16]
|
17
|
+
when 'bf-cfb' then [16, 8 ]
|
18
|
+
when 'camellia-128-cfb' then [16, 16]
|
19
|
+
when 'camellia-192-cfb' then [24, 16]
|
20
|
+
when 'camellia-256-cfb' then [32, 16]
|
21
|
+
when 'cast5-cfb' then [16, 8 ]
|
22
|
+
when 'des-cfb' then [8, 8 ]
|
23
|
+
when 'idea-cfb' then [16, 8 ]
|
24
|
+
when 'rc2-cfb' then [16, 8 ]
|
25
|
+
when 'rc4' then [16, 0 ]
|
26
|
+
when 'seed-cfb' then [16, 16]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
alias_method :get_cipher_len, :method_supported
|
30
|
+
|
31
|
+
def initialize(options = {})
|
32
|
+
@password = options[:password]
|
33
|
+
@method = options[:method].downcase
|
34
|
+
@iv_sent = false
|
35
|
+
if method == 'table'
|
36
|
+
@encrypt_table = options[:encrypt_table]
|
37
|
+
@decrypt_table = options[:decrypt_table]
|
38
|
+
else
|
39
|
+
if method_supported.nil?
|
40
|
+
raise "Encrypt method not support"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
if method != 'table'
|
45
|
+
@cipher = get_cipher(1, SecureRandom.hex(32))
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def encrypt buf
|
50
|
+
return buf if buf.length == 0
|
51
|
+
if method == 'table'
|
52
|
+
translate @encrypt_table, buf
|
53
|
+
else
|
54
|
+
if iv_sent
|
55
|
+
@cipher.update(buf)
|
56
|
+
else
|
57
|
+
@iv_sent = true
|
58
|
+
@cipher_iv + @cipher.update(buf)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def decrypt buf
|
64
|
+
return buf if buf.length == 0
|
65
|
+
if method == 'table'
|
66
|
+
translate @decrypt_table, buf
|
67
|
+
else
|
68
|
+
if @decipher.nil?
|
69
|
+
decipher_iv_len = get_cipher_len[1]
|
70
|
+
decipher_iv = buf[0..decipher_iv_len ]
|
71
|
+
@iv = decipher_iv
|
72
|
+
@decipher = get_cipher(0, @iv)
|
73
|
+
buf = buf[decipher_iv_len..-1]
|
74
|
+
return buf if buf.length == 0
|
75
|
+
end
|
76
|
+
@decipher.update(buf)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
def iv_len
|
83
|
+
@cipher_iv.length
|
84
|
+
end
|
85
|
+
|
86
|
+
def get_cipher(op, iv)
|
87
|
+
m = get_cipher_len
|
88
|
+
unless m.nil?
|
89
|
+
key, _iv = EVP_BytesToKey(m[0], m[1])
|
90
|
+
|
91
|
+
iv = _iv[0..m[1] - 1]
|
92
|
+
@iv = iv unless @iv
|
93
|
+
@cipher_iv = iv if op == 1
|
94
|
+
|
95
|
+
cipher = OpenSSL::Cipher.new method
|
96
|
+
|
97
|
+
op == 1 ? cipher.encrypt : cipher.decrypt
|
98
|
+
|
99
|
+
cipher.key = key
|
100
|
+
cipher.iv = @iv
|
101
|
+
cipher
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def EVP_BytesToKey key_len, iv_len
|
106
|
+
if bytes_to_key_results
|
107
|
+
return bytes_to_key_results
|
108
|
+
end
|
109
|
+
|
110
|
+
m = []
|
111
|
+
i = 0
|
112
|
+
|
113
|
+
len = key_len + iv_len
|
114
|
+
|
115
|
+
code = password.unpack('H*').first
|
116
|
+
|
117
|
+
while m.join.length < len do
|
118
|
+
data = if i > 0
|
119
|
+
m[i - 1] + password
|
120
|
+
else
|
121
|
+
password
|
122
|
+
end
|
123
|
+
m.push Digest::MD5.digest data
|
124
|
+
i += 1
|
125
|
+
end
|
126
|
+
ms = m.join
|
127
|
+
key = ms[0, key_len]
|
128
|
+
iv = ms[key_len, key_len + iv_len]
|
129
|
+
bytes_to_key_results = [key, iv]
|
130
|
+
bytes_to_key_results
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
data/lib/shadowsocks/listener.rb
CHANGED
@@ -1,9 +1,7 @@
|
|
1
1
|
module Shadowsocks
|
2
2
|
class Listener < ::Shadowsocks::Connection
|
3
|
-
include ::Shadowsocks::Table
|
4
|
-
|
5
3
|
attr_accessor :stage, :remote_addr, :remote_port, :addr_to_send, :cached_pieces,
|
6
|
-
:header_length, :connector, :config
|
4
|
+
:header_length, :connector, :config
|
7
5
|
|
8
6
|
def receive_data data
|
9
7
|
data_handler data
|
data/lib/shadowsocks/local.rb
CHANGED
@@ -5,15 +5,15 @@ module Shadowsocks
|
|
5
5
|
p "connecting #{server.remote_addr[3..-1]} via #{server.config.server}"
|
6
6
|
addr_to_send = server.addr_to_send.clone
|
7
7
|
|
8
|
-
send_data encrypt(
|
9
|
-
server.cached_pieces.each { |piece| send_data encrypt(
|
8
|
+
send_data encrypt(addr_to_send)
|
9
|
+
server.cached_pieces.each { |piece| send_data encrypt(piece) }
|
10
10
|
server.cached_pieces = []
|
11
11
|
|
12
12
|
server.stage = 5
|
13
13
|
end
|
14
14
|
|
15
15
|
def receive_data data
|
16
|
-
server.send_data
|
16
|
+
server.send_data decrypt(data)
|
17
17
|
outbound_checker
|
18
18
|
end
|
19
19
|
end
|
@@ -31,7 +31,7 @@ module Shadowsocks
|
|
31
31
|
when 4
|
32
32
|
cached_pieces.push data
|
33
33
|
when 5
|
34
|
-
connector.send_data(encrypt(
|
34
|
+
connector.send_data(encrypt(data)) and return
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
@@ -49,7 +49,7 @@ module Shadowsocks
|
|
49
49
|
send_data "\x05\x00\x00\x01\x00\x00\x00\x00" + [config.server_port].pack('s>')
|
50
50
|
|
51
51
|
@stage = 4
|
52
|
-
@connector = EventMachine.connect config.server, config.server_port, ServerConnector, self,
|
52
|
+
@connector = EventMachine.connect config.server, config.server_port, ServerConnector, self, crypto
|
53
53
|
|
54
54
|
if data.size > header_length
|
55
55
|
cached_pieces.push data[header_length, data.size]
|
data/lib/shadowsocks/server.rb
CHANGED
@@ -11,7 +11,7 @@ module Shadowsocks
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def receive_data data
|
14
|
-
server.send_data encrypt(
|
14
|
+
server.send_data encrypt(data)
|
15
15
|
outbound_checker
|
16
16
|
end
|
17
17
|
end
|
@@ -20,7 +20,7 @@ module Shadowsocks
|
|
20
20
|
private
|
21
21
|
|
22
22
|
def data_handler data
|
23
|
-
data =
|
23
|
+
data = decrypt data
|
24
24
|
case stage
|
25
25
|
when 0
|
26
26
|
fireup_tunnel data
|
@@ -41,7 +41,7 @@ module Shadowsocks
|
|
41
41
|
cached_pieces.push data[header_length, data.size]
|
42
42
|
end
|
43
43
|
|
44
|
-
@connector = EventMachine.connect @remote_addr, @remote_port, RequestConnector, self,
|
44
|
+
@connector = EventMachine.connect @remote_addr, @remote_port, RequestConnector, self, crypto
|
45
45
|
rescue Exception => e
|
46
46
|
warn e
|
47
47
|
connection_cleanup
|
data/lib/shadowsocks/table.rb
CHANGED
@@ -45,10 +45,10 @@ module Shadowsocks
|
|
45
45
|
decrypt_table[table[i]] = i
|
46
46
|
i += 1
|
47
47
|
end
|
48
|
-
{
|
48
|
+
{ encrypt: table, decrypt: decrypt_table }
|
49
49
|
end
|
50
50
|
|
51
|
-
def
|
51
|
+
def translate(table, buf)
|
52
52
|
table_ptr = FFI::MemoryPointer.new(:int, table.length)
|
53
53
|
table_ptr.put_array_of_int32(0, table)
|
54
54
|
|
data/lib/shadowsocks/tunnel.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
module Shadowsocks
|
2
2
|
class Tunnel < ::Shadowsocks::Connection
|
3
|
-
attr_accessor :server
|
3
|
+
attr_accessor :server
|
4
4
|
|
5
|
-
def initialize server,
|
5
|
+
def initialize server, crypto
|
6
6
|
@server = server
|
7
|
-
@
|
7
|
+
@crypto = crypto
|
8
8
|
super
|
9
9
|
end
|
10
10
|
|
@@ -15,9 +15,5 @@ module Shadowsocks
|
|
15
15
|
def remote
|
16
16
|
server
|
17
17
|
end
|
18
|
-
|
19
|
-
def encrypt table, data
|
20
|
-
server.encrypt table, data
|
21
|
-
end
|
22
18
|
end
|
23
19
|
end
|
data/lib/shadowsocks/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: shadowsocks
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '0.
|
4
|
+
version: '0.4'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sen
|
@@ -118,6 +118,7 @@ files:
|
|
118
118
|
- lib/shadowsocks/cli.rb
|
119
119
|
- lib/shadowsocks/config.rb
|
120
120
|
- lib/shadowsocks/connection.rb
|
121
|
+
- lib/shadowsocks/crypto.rb
|
121
122
|
- lib/shadowsocks/listener.rb
|
122
123
|
- lib/shadowsocks/local.rb
|
123
124
|
- lib/shadowsocks/server.rb
|