shadowsocks 0.3 → 0.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 210530027df71869738df356d97c6d3155592ab9
4
- data.tar.gz: 8a45ea79d7cfe255af4f1926dd26eb9b7c4f3328
3
+ metadata.gz: 1e13759da84263a5a81769afcb8e2d99b511766b
4
+ data.tar.gz: 9f0049ec6920bc351fc0c04017f22dbfd2cf8104
5
5
  SHA512:
6
- metadata.gz: 78fe95f2a08447581d78d6b2f6e31cf5ef9ca60fd5d27e722949b0f3a50070166cf6ac316a092e4c21f655168a2168e091c5b9ba365e807afa19b12ee99a8ce7
7
- data.tar.gz: 73b565053f9dbee59d094485e68797e0e740475e4ccd56739f8df62f15b12f7c096e484b6b33aa11ae11e0709762f31f03a73980d6b15240c2172b732e80800c
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.2
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":600
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
@@ -3,5 +3,6 @@
3
3
  "server_port":8388,
4
4
  "local_port":1080,
5
5
  "password":"barfoo!",
6
- "timeout":60
6
+ "timeout":60,
7
+ "method":"aes-256-cfb"
7
8
  }
data/lib/shadowsocks.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require 'eventmachine'
2
2
 
3
3
  module Shadowsocks
4
+ autoload :Crypto, 'shadowsocks/crypto'
4
5
  autoload :Connection, 'shadowsocks/connection'
5
6
  autoload :Server, 'shadowsocks/server'
6
7
  autoload :Local, 'shadowsocks/local'
@@ -7,12 +7,24 @@ module Shadowsocks
7
7
  class Cli
8
8
  include ::Shadowsocks::Table
9
9
 
10
- attr_accessor :side, :args, :config, :table
10
+ attr_accessor :side, :args, :config
11
11
 
12
12
  def initialize(options)
13
13
  @side = options[:side]
14
14
  @config = options[:config]
15
- @table = get_table(config.password)
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.table = @table
58
+ connection.crypto = Shadowsocks::Crypto.new @method_options
47
59
  connection.pending_connect_timeout = @config.timeout
48
60
  end
49
61
 
@@ -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") { |c| @local_port = c }
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
@@ -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, :table
4
+ :header_length, :connector, :config
7
5
 
8
6
  def receive_data data
9
7
  data_handler data
@@ -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(table[:encrypt_table], addr_to_send)
9
- server.cached_pieces.each { |piece| send_data encrypt(table[:encrypt_table], piece) }
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 encrypt(table[:decrypt_table], 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(table[:encrypt_table], data)) and return
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, @table
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]
@@ -11,7 +11,7 @@ module Shadowsocks
11
11
  end
12
12
 
13
13
  def receive_data data
14
- server.send_data encrypt(table[:encrypt_table], data)
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 = encrypt table[:decrypt_table], 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, table
44
+ @connector = EventMachine.connect @remote_addr, @remote_port, RequestConnector, self, crypto
45
45
  rescue Exception => e
46
46
  warn e
47
47
  connection_cleanup
@@ -45,10 +45,10 @@ module Shadowsocks
45
45
  decrypt_table[table[i]] = i
46
46
  i += 1
47
47
  end
48
- { encrypt_table: table, decrypt_table: decrypt_table }
48
+ { encrypt: table, decrypt: decrypt_table }
49
49
  end
50
50
 
51
- def encrypt (table, buf)
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
 
@@ -1,10 +1,10 @@
1
1
  module Shadowsocks
2
2
  class Tunnel < ::Shadowsocks::Connection
3
- attr_accessor :server, :table
3
+ attr_accessor :server
4
4
 
5
- def initialize server, table
5
+ def initialize server, crypto
6
6
  @server = server
7
- @table = table
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
@@ -1,3 +1,3 @@
1
1
  module Shadowsocks
2
- VERSION = '0.3'
2
+ VERSION = '0.4'
3
3
  end
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.3'
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