shadowsocks_ruby 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +9 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +5 -0
  5. data/.yardopts +5 -0
  6. data/CODE_OF_CONDUCT.md +74 -0
  7. data/Gemfile +10 -0
  8. data/LICENSE.txt +21 -0
  9. data/README.md +160 -0
  10. data/Rakefile +14 -0
  11. data/bin/aruba +17 -0
  12. data/bin/bundler +17 -0
  13. data/bin/console +14 -0
  14. data/bin/cucumber +17 -0
  15. data/bin/einhorn +17 -0
  16. data/bin/einhornsh +17 -0
  17. data/bin/htmldiff +17 -0
  18. data/bin/ldiff +17 -0
  19. data/bin/lrucache_server +16 -0
  20. data/bin/rake +17 -0
  21. data/bin/rspec +17 -0
  22. data/bin/setup +8 -0
  23. data/bin/yard +17 -0
  24. data/bin/yardoc +17 -0
  25. data/bin/yri +17 -0
  26. data/config.example.json +6 -0
  27. data/exe/sslocal-ruby +4 -0
  28. data/exe/ssserver-ruby +4 -0
  29. data/lib/shadowsocks_ruby/app.rb +236 -0
  30. data/lib/shadowsocks_ruby/cipher/cipher.rb +112 -0
  31. data/lib/shadowsocks_ruby/cipher/openssl.rb +81 -0
  32. data/lib/shadowsocks_ruby/cipher/rbnacl.rb +64 -0
  33. data/lib/shadowsocks_ruby/cipher/rc4_md5.rb +54 -0
  34. data/lib/shadowsocks_ruby/cipher/table.rb +65 -0
  35. data/lib/shadowsocks_ruby/cli/sslocal_runner.rb +125 -0
  36. data/lib/shadowsocks_ruby/cli/ssserver_runner.rb +115 -0
  37. data/lib/shadowsocks_ruby/connections/backend_connection.rb +50 -0
  38. data/lib/shadowsocks_ruby/connections/connection.rb +195 -0
  39. data/lib/shadowsocks_ruby/connections/server_connection.rb +63 -0
  40. data/lib/shadowsocks_ruby/connections/tcp/client_connection.rb +43 -0
  41. data/lib/shadowsocks_ruby/connections/tcp/destination_connection.rb +19 -0
  42. data/lib/shadowsocks_ruby/connections/tcp/localbackend_connection.rb +29 -0
  43. data/lib/shadowsocks_ruby/connections/tcp/remoteserver_connection.rb +18 -0
  44. data/lib/shadowsocks_ruby/connections/udp/client_connection.rb +43 -0
  45. data/lib/shadowsocks_ruby/connections/udp/destination_connection.rb +18 -0
  46. data/lib/shadowsocks_ruby/connections/udp/localbackend_connection.rb +29 -0
  47. data/lib/shadowsocks_ruby/connections/udp/remoteserver_connection.rb +18 -0
  48. data/lib/shadowsocks_ruby/protocols/cipher/iv_cipher.rb +99 -0
  49. data/lib/shadowsocks_ruby/protocols/cipher/no_iv_cipher.rb +53 -0
  50. data/lib/shadowsocks_ruby/protocols/cipher/verify_sha1.rb +138 -0
  51. data/lib/shadowsocks_ruby/protocols/obfs/http_simple.rb +189 -0
  52. data/lib/shadowsocks_ruby/protocols/obfs/tls_ticket.rb +342 -0
  53. data/lib/shadowsocks_ruby/protocols/packet/plain.rb +51 -0
  54. data/lib/shadowsocks_ruby/protocols/packet/shadowsocks.rb +88 -0
  55. data/lib/shadowsocks_ruby/protocols/packet/socks5.rb +162 -0
  56. data/lib/shadowsocks_ruby/protocols/protocol.rb +164 -0
  57. data/lib/shadowsocks_ruby/protocols/protocol_stack.rb +117 -0
  58. data/lib/shadowsocks_ruby/util.rb +52 -0
  59. data/lib/shadowsocks_ruby/version.rb +3 -0
  60. data/lib/shadowsocks_ruby.rb +86 -0
  61. data/shadowsocks_ruby.gemspec +48 -0
  62. metadata +290 -0
@@ -0,0 +1,125 @@
1
+ require 'optparse'
2
+
3
+ module ShadowsocksRuby
4
+ module Cli
5
+ class SslocalRunner
6
+ def initialize(argv = ARGV, stdin = $stdin, stdout = $stdout, stderr = $stderr, kernel = Kernel)
7
+ @argv = argv
8
+ $kernel = kernel
9
+ $stdin = stdin
10
+ $stdout = stdout
11
+ $stderr = stderr
12
+ end
13
+
14
+ def execute!
15
+ # here sets default options
16
+ options = {
17
+ :port => 8388,
18
+ :local_addr => '0.0.0.0',
19
+ :local_port => 1080,
20
+ :packet_name => 'origin',
21
+ :cipher_name => 'aes-256-cfb',
22
+ :timeout => 300
23
+ }
24
+ lazy_default = {
25
+ :config => 'config.json',
26
+ :obfs_name => 'http_simple'
27
+ }
28
+
29
+ version = ShadowsocksRuby::VERSION
30
+ config_help = "path to config file (lazy default: #{lazy_default[:config]})"
31
+ server_addr_help = "server address"
32
+ server_port_help = "server port (default: #{options[:port]})"
33
+ local_addr_help = "local binding address (default: #{options[:local_addr]})"
34
+ local_port_help = "local port (default: default: #{options[:local_port]})"
35
+ password_help = "password"
36
+ packet_protocol_help = "packet protocol (default: #{options[:packet_name]})"
37
+ packet_param_help = "packet protocol parameters"
38
+ cipher_help = "cipher protocol (default: #{options[:cipher_name]})"
39
+ obfs_protocol_help = "obfuscate protocol (lazy default: #{lazy_default[:obfs_name]})"
40
+ obfs_param_help = "obfuscate protocol parameters"
41
+ timeout_help = "timeout in seconds, default: #{options[:timeout]}"
42
+ fast_open_help = "use TCP_FASTOPEN, requires Linux 3.7+"
43
+ einhorn_help = "Use Einhorn socket manager"
44
+
45
+ help_help = "display help message"
46
+ version_help = "show version information"
47
+ verbose_help = "verbose mode"
48
+ quiet_help = "quiet mode, only show warnings/errors"
49
+ get_help = "run #{File.basename($0)} -h to get help"
50
+
51
+ option_parser = OptionParser.new do |op|
52
+
53
+ op.banner = "A SOCKS like tunnel proxy that helps you bypass firewalls."
54
+ op.separator ""
55
+ op.separator "Usage: #{File.basename($0)} [options]"
56
+ op.separator ""
57
+
58
+ op.separator "Proxy options:"
59
+ op.on("-c", "--config [CONFIG]", config_help) { |value| options[:config] = value }
60
+ op.on("-s", "--server SERVER_ADDR", server_addr_help) { |value| options[:server] = value }
61
+ op.on("-p", "--port SERVER_PORT", server_port_help) { |value| options[:port] = value.to_i }
62
+ op.on("-b", "--bind_addr LOCAL_ADDR", local_addr_help) { |value| options[:local_addr] = value }
63
+ op.on("-l", "--local_port LOCAL_PORT", local_port_help) { |value| options[:local_port] = value.to_i }
64
+ op.on("-k", "--password PASSWORD", password_help) { |value| options[:password] = value }
65
+ op.on("-O", "--packet-protocol NAME", packet_protocol_help) { |value| options[:packet_name] = value }
66
+ op.on("-G", "--packet-param PARAM", packet_param_help) { |value| options[:packet_param] = value }
67
+ op.on("-m", "--cipher-protocol NAME", cipher_help) { |value| options[:cipher_name] = value }
68
+ op.on("-o", "--obfs-protocol [NAME]", obfs_protocol_help) { |value| options[:obfs_name] = value }
69
+ op.on("-g", "--obfs-param PARAM", obfs_param_help) { |value| options[:obfs_param] = value }
70
+ op.on("-t", "--timeout TIMEOUT", timeout_help) { |value| options[:timeout] = value.to_i }
71
+ op.on( "--fast-open", fast_open_help) { |value| options[:tcp_fast_open] = value }
72
+ op.on('-E', '--einhorn', einhorn_help) { |value| @options[:einhorn] = true }
73
+ op.separator ""
74
+
75
+ op.separator "Common options:"
76
+ op.on("-h", "--help", help_help) { puts op.to_s; $kernel.exit }
77
+ op.on("-v", "--vv", verbose_help) { options[:verbose] = true }
78
+ op.on("-q", "--qq", quiet_help) { options[:quiet] = true }
79
+ op.on( "--version", version_help) { puts version; $kernel.exit }
80
+ op.separator ""
81
+
82
+ end
83
+
84
+ begin
85
+ option_parser.parse!(@argv)
86
+ rescue OptionParser::MissingArgument => e
87
+ $kernel.abort("#{e.message}\n#{get_help}")
88
+ end
89
+
90
+ if options.include?(:config)
91
+ options[:config] = 'config.json' if options[:config] == nil
92
+ config_options = {}
93
+ begin
94
+ open(options[:config], 'r') do |f|
95
+ config_options = JSON.load(f, nil, {:symbolize_names => true})
96
+ end
97
+ rescue Errno::ENOENT
98
+ $kernel.abort("#{options[:config]} doesn't exists")
99
+ rescue JSON::ParserError
100
+ $kernel.abort("#{options[:config]} parse error")
101
+ end
102
+ options = config_options.merge(options)
103
+ end
104
+
105
+ if options.include?(:obfs_name)
106
+ options[:obfs_name] = lazy_default[:obfs_name] if options[:obfs_name] == nil
107
+ end
108
+
109
+ if !options.include?(:password)
110
+ $kernel.abort("--password is required\n#{get_help}")
111
+ end
112
+
113
+ if !options.include?(:server)
114
+ $kernel.abort("--server is required\n#{get_help}")
115
+ end
116
+
117
+
118
+ options[:__client] = true
119
+
120
+ App.options = options
121
+ App.instance.run!
122
+ end
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,115 @@
1
+ require 'optparse'
2
+
3
+ module ShadowsocksRuby
4
+ module Cli
5
+ class SsserverRunner
6
+ def initialize(argv = ARGV, stdin = $stdin, stdout = $stdout, stderr = $stderr, kernel = Kernel)
7
+ @argv = argv
8
+ $kernel = kernel
9
+ $stdin = stdin
10
+ $stdout = stdout
11
+ $stderr = stderr
12
+ end
13
+
14
+ def execute!
15
+ # here sets default options
16
+ options = {
17
+ :server => '0.0.0.0',
18
+ :port => 8388,
19
+ :packet_name => 'origin',
20
+ :cipher_name => 'aes-256-cfb',
21
+ :timeout => 300
22
+ }
23
+ lazy_default = {
24
+ :config => 'config.json',
25
+ :obfs_name => 'http_simple'
26
+ }
27
+
28
+ version = ShadowsocksRuby::VERSION
29
+ config_help = "path to config file (lazy default: #{lazy_default[:config]})"
30
+ server_addr_help = "server address (default: #{options[:server]})"
31
+ server_port_help = "server port (default: #{options[:port]})"
32
+ password_help = "password"
33
+ packet_protocol_help = "packet protocol (default: #{options[:packet_name]})"
34
+ packet_param_help = "packet protocol parameters"
35
+ cipher_help = "cipher protocol (default: #{options[:cipher_name]})"
36
+ obfs_protocol_help = "obfuscate protocol (lazy default: #{lazy_default[:obfs_name]})"
37
+ obfs_param_help = "obfuscate protocol parameters"
38
+ timeout_help = "timeout in seconds, default: #{options[:timeout]}"
39
+ fast_open_help = "use TCP_FASTOPEN, requires Linux 3.7+"
40
+ einhorn_help = "Use Einhorn socket manager"
41
+
42
+ help_help = "display help message"
43
+ version_help = "show version information"
44
+ verbose_help = "verbose mode"
45
+ quiet_help = "quiet mode, only show warnings/errors"
46
+ get_help = "run #{File.basename($0)} -h to get help"
47
+
48
+ option_parser = OptionParser.new do |op|
49
+
50
+ op.banner = "A SOCKS like tunnel proxy that helps you bypass firewalls."
51
+ op.separator ""
52
+ op.separator "Usage: #{File.basename($0)} [options]"
53
+ op.separator ""
54
+
55
+ op.separator "Proxy options:"
56
+ op.on("-c", "--config [CONFIG]", config_help) { |value| options[:config] = value }
57
+ op.on("-s", "--server SERVER_ADDR", server_addr_help) { |value| options[:server] = value }
58
+ op.on("-p", "--port SERVER_PORT", server_port_help) { |value| options[:port] = value.to_i }
59
+ op.on("-k", "--password PASSWORD", password_help) { |value| options[:password] = value }
60
+ op.on("-O", "--packet-protocol NAME", packet_protocol_help) { |value| options[:packet_name] = value }
61
+ op.on("-G", "--packet-param PARAM", packet_param_help) { |value| options[:packet_param] = value }
62
+ op.on("-m", "--cipher-protocol NAME", cipher_help) { |value| options[:cipher_name] = value }
63
+ op.on("-o", "--obfs-protocol [NAME]", obfs_protocol_help) { |value| options[:obfs_name] = value }
64
+ op.on("-g", "--obfs-param PARAM", obfs_param_help) { |value| options[:obfs_param] = value }
65
+ op.on("-t", "--timeout TIMEOUT", timeout_help) { |value| options[:timeout] = value.to_i }
66
+ op.on( "--fast-open", fast_open_help) { |value| options[:tcp_fast_open] = value }
67
+ op.on('-E', '--einhorn', einhorn_help) { |value| @options[:einhorn] = true }
68
+ op.separator ""
69
+
70
+ op.separator "Common options:"
71
+ op.on("-h", "--help", help_help) { puts op.to_s; $kernel.exit }
72
+ op.on("-v", "--vv", verbose_help) { options[:verbose] = true }
73
+ op.on("-q", "--qq", quiet_help) { options[:quiet] = true }
74
+ op.on( "--version", version_help) { puts version; $kernel.exit }
75
+ op.separator ""
76
+
77
+ end
78
+
79
+ begin
80
+ option_parser.parse!(@argv)
81
+ rescue OptionParser::MissingArgument => e
82
+ $kernel.abort("#{e.message}\n#{get_help}")
83
+ end
84
+
85
+ if options.include?(:config)
86
+ options[:config] = lazy_default[:config] if options[:config] == nil
87
+ config_options = {}
88
+ begin
89
+ open(options[:config], 'r') do |f|
90
+ config_options = JSON.load(f, nil, {:symbolize_names => true})
91
+ end
92
+ rescue Errno::ENOENT
93
+ $kernel.abort("#{options[:config]} doesn't exists")
94
+ rescue JSON::ParserError
95
+ $kernel.abort("#{options[:config]} parse error")
96
+ end
97
+ options = config_options.merge(options)
98
+ end
99
+
100
+ if options.include?(:obfs_name)
101
+ options[:obfs_name] = lazy_default[:obfs_name] if options[:obfs_name] == nil
102
+ end
103
+
104
+ if !options.include?(:password)
105
+ $kernel.abort("password is required\n#{get_help}")
106
+ end
107
+
108
+ options[:__server] = true
109
+
110
+ App.options = options
111
+ App.instance.run!
112
+ end
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,50 @@
1
+ module ShadowsocksRuby
2
+ module Connections
3
+ # Mixed-in code to provide functionality to a BackendConnection
4
+ # ,whose peer is a upstream peer, like a Destinatiion or a RemoteServer.
5
+ module BackendConnection
6
+
7
+ # Packet Protocol
8
+ #
9
+ # A Strategy Pattern for replacing protocol algorithm
10
+ #
11
+ # all read from {BackendConnection}'s {packet_protocol} is just data,
12
+ #
13
+ # the first send to {packet_protocol} chould be address_bin (for a {RemoteServerConnection})
14
+ # or data (for a {DestinationConnection}),
15
+ # other send to {packet_protocol} should be just data
16
+ #
17
+ # @return [ShadowsocksRuby::Protocols::SomePacketProtocol]
18
+ # @see ShadowsocksRuby::Protocols
19
+ attr_accessor :packet_protocol
20
+
21
+ # (see ServerConnection#params)
22
+ attr_reader :params
23
+
24
+ # If clild class override initialize, make sure to call super
25
+ #
26
+ # @param [Protocols::ProtocolStack] protocol_stack
27
+ # @param [Hash] params
28
+ # @return [Connection_Object]
29
+ def initialize protocol_stack, params
30
+ super()
31
+
32
+ @packet_protocol = protocol_stack.build!(self)
33
+
34
+ @params = params
35
+ @connected = EM::DefaultDeferrable.new
36
+ end
37
+
38
+
39
+ def connection_completed
40
+ @connected.succeed
41
+ end
42
+
43
+ # Buffer data until the connection to the backend server
44
+ # is established and is ready for use
45
+ def send_data data
46
+ @connected.callback { super data }
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,195 @@
1
+ require 'fiber'
2
+ require 'ipaddr'
3
+
4
+ module ShadowsocksRuby
5
+
6
+ # This module contains various functionality code to be mixed-in
7
+ # with EventMachine::Connection
8
+ # when Connection object is instantiated.
9
+ #
10
+ # There are 4 kinds of connection: client, local backend, remote server and destination. Which are demonstrated below:
11
+ #
12
+ # ------------------------------------------- -------------------------------------------------
13
+ # | | | |
14
+ # Client <---> |ClientConnection -- RemoteServerConnecton| <---> |LocalBackendConnection -- DestinationConnection| <---> Destination
15
+ # net | Shadowsocks Client | net | Shadowsocks Server | net
16
+ # ------------------------------------------- -------------------------------------------------
17
+ #
18
+ #
19
+ module Connections
20
+ # Mixed-in code to provide fiber enabled asynchronously receive
21
+ # function and pressure controled +send_data+ to EventMachine::Connection
22
+ #
23
+ # User code should define +process_hook+ which hopefully implement a state machine .
24
+ #
25
+ # *Note:* User code should not override +post_init+ and +receive_data+, it is by design.
26
+ #
27
+ # @example
28
+ # class DummyConnection < EventMachine::Connection
29
+ # include ShadowsocksRuby::Connections::Connection
30
+ # def process_hook
31
+ # @i ||= 0
32
+ # @i += 1
33
+ # puts "I'm now in a fiber enabled context: #{@fiber}"
34
+ # Fiber.yield if @i >= 3
35
+ # end
36
+ # end
37
+ #
38
+ module Connection
39
+ # 512K, used to pause plexer when plexer.get_outbound_data_size > this value
40
+ PressureLevel = 524288
41
+
42
+ # It is where to relay peer's traffic to
43
+ # For a server connection, plexer is backend connection.
44
+ # For a backend connection, plexer is server connection.
45
+ # @return [Connection]
46
+ attr_accessor :plexer
47
+
48
+ # you can set logger in test code
49
+ attr_writer :logger
50
+
51
+ # get the logger object, the defautl logger is App.instance.logger
52
+ def logger
53
+ @logger ||= App.instance.logger
54
+ end
55
+
56
+
57
+ # send_data with pressure control
58
+ # @param[String] data Data to send asynchronously
59
+ def send_data data
60
+ pressure_control
61
+ super data
62
+ end
63
+
64
+ # Call process_hook, which should be defined in user code
65
+ # @private
66
+ def process
67
+ process_hook
68
+ end
69
+
70
+ # Initialize a fiber context and enter the process loop
71
+ # normally, a child class should not override post_init, it is by design
72
+ # @private
73
+ def post_init
74
+ @buffer = String.new('', encoding: Encoding::ASCII_8BIT)
75
+ @fiber = Fiber.new do
76
+ # poor man's state machine
77
+ while true
78
+ process
79
+ end
80
+ end
81
+ @fiber.resume
82
+ end
83
+
84
+ def peer
85
+ @peer ||=
86
+ begin
87
+ port, ip = Socket.unpack_sockaddr_in(get_peername)
88
+ "#{ip}:#{port}"
89
+ end
90
+ end
91
+
92
+ # Asynchronously receive n bytes from @buffer
93
+ # @param [Integer] n Bytes to receive, if n = -1 returns all data in @buffer
94
+ # @return [String] Returned n bytes data
95
+ def async_recv n
96
+ # wait n bytes
97
+ if n == -1 && @buffer.size == 0 || @buffer.size < n
98
+ @wait_length = n
99
+ Fiber.yield
100
+ end
101
+ # read n bytes from buffer
102
+ if n == -1
103
+ s, @buffer = @buffer, String.new('', encoding: Encoding::ASCII_8BIT)
104
+ return s
105
+ else
106
+ return @buffer.slice!(0, n)
107
+ end
108
+ end
109
+
110
+ # Asynchronously receive data until str (eg: "\\r\\n\r\\n") appears.
111
+ # @param [String] str Desired endding str
112
+ # @raise BufferOversizeError raise if cannot find str in first 65536 bytes (64K bytes)of @buffer,
113
+ # enough for a HTTP request head.
114
+ # @return [String] Returned data, with str at end
115
+ def async_recv_until str
116
+ # wait for str
117
+ pos = @buffer =~ Regexp.new(str)
118
+ while pos == nil
119
+ @wait_length = -1
120
+ Fiber.yield
121
+ pos = @buffer =~ Regexp.new(str)
122
+ raise BufferOversizeError, "oversized async_recv_until read" if @buffer.size > 65536
123
+ end
124
+ # read until str from buffer
125
+ return @buffer.slice!(0, pos + str.length)
126
+ end
127
+
128
+
129
+ # Provide fiber enabled data receiving, should be always be called
130
+ # in a fiber context.
131
+ #
132
+ # Normally, client class should not call receive_data directlly,
133
+ # instead should call async_recv or async_recv_until
134
+ #
135
+ # @param [String] data
136
+ # @raise OutOfFiberConextError
137
+ #
138
+ # @private
139
+ def receive_data data
140
+ if @fiber.alive?
141
+ @buffer << data
142
+ if @wait_length == -1 || @buffer.size >= @wait_length
143
+ @fiber.resume
144
+ end
145
+ else
146
+ raise OutOfFiberContextError, "should not go here"
147
+ end
148
+ rescue MyErrorModule => e
149
+ logger.info {e.message}
150
+ close_connection
151
+ rescue Exception => e
152
+ logger.info {e.class.to_s + " " + e.message + e.backtrace.join("\n")}
153
+ close_connection
154
+ end
155
+
156
+ # if peer receving data is too slow, pause plexer sending data to me
157
+ # ,prevent memery usage to be too high
158
+ # @private
159
+ def pressure_control
160
+ @plexer ||= nil
161
+ if @plexer != nil
162
+ if get_outbound_data_size >= PressureLevel
163
+ @plexer.pause unless @plexer.paused?
164
+ EventMachine.next_tick self.method(:pressure_control)
165
+ else
166
+ @plexer.resume if @plexer.paused?
167
+ end
168
+ end
169
+ end
170
+
171
+ # Close plexer first if it exists
172
+ def unbind
173
+ @plexer ||= nil
174
+ @plexer.close_connection_after_writing if @plexer != nil
175
+ end
176
+
177
+ alias tcp_receive_from_client async_recv
178
+ alias tcp_receive_from_remoteserver async_recv
179
+ alias tcp_receive_from_localbackend async_recv
180
+ alias tcp_receive_from_destination async_recv
181
+ alias tcp_send_to_client send_data
182
+ alias tcp_send_to_remoteserver send_data
183
+ alias tcp_send_to_localbackend send_data
184
+ alias tcp_send_to_destination send_data
185
+ alias udp_receive_from_client async_recv
186
+ alias udp_receive_from_remoteserver async_recv
187
+ alias udp_receive_from_localbackend async_recv
188
+ alias udp_receive_from_destination async_recv
189
+ alias udp_send_to_client send_data
190
+ alias udp_send_to_remoteserver send_data
191
+ alias udp_send_to_localbackend send_data
192
+ alias udp_send_to_destination send_data
193
+ end
194
+ end
195
+ end
@@ -0,0 +1,63 @@
1
+ module ShadowsocksRuby
2
+ module Connections
3
+
4
+ # Mixed-in code to provide functionality to a ServerConnection
5
+ # ,whose peer is a downstream peer, like a Client or a LocalBackend.
6
+ module ServerConnection
7
+
8
+ # Packet Protocol
9
+ #
10
+ # A Strategy Pattern for replacing protocol algorithm
11
+ #
12
+ # the first read from {ServerConnection}'s {packet_protocol} is an address_bin,
13
+ # other read from {packet_protocol} is just data
14
+ #
15
+ # all send to {packet_protocol} should be just data
16
+ #
17
+ # @return [ShadowsocksRuby::Protocols::SomePacketProtocol]
18
+ # @see ShadowsocksRuby::Protocols
19
+ attr_accessor :packet_protocol
20
+
21
+ # Params
22
+ # @return [Hash]
23
+ attr_reader :params
24
+
25
+ # If clild class override initialize, make sure to call super
26
+ #
27
+ # @param [Protocols::ProtocolStack] protocol_stack
28
+ # @param [Hash] params
29
+ # @param [Protocols::ProtocolStack] backend_protocol_stack
30
+ # @param [Hash] backend_params
31
+ # @return [Connection_Object]
32
+ def initialize protocol_stack, params, backend_protocol_stack, backend_params
33
+ super()
34
+
35
+ @packet_protocol = protocol_stack.build!(self)
36
+
37
+ @params = params
38
+
39
+ @backend_protocol_stack = backend_protocol_stack
40
+ @backend_params = backend_params
41
+ end
42
+
43
+ def post_init
44
+ logger.info {"Accepted #{peer}"}
45
+ super()
46
+ end
47
+
48
+ # Create a plexer -- a backend connection
49
+ # @param [String] host
50
+ # @param [Integer] port
51
+ # @param [Class] backend_klass
52
+ # @return [Connection_Object]
53
+ def create_plexer(host, port, backend_klass)
54
+ @plexer = EventMachine.connect host, port, backend_klass, @backend_protocol_stack, @backend_params
55
+ @plexer.plexer = self
56
+ @plexer
57
+ rescue EventMachine::ConnectionError => e
58
+ raise ConnectionError, e.message + " when connect to #{host}:#{port}"
59
+ end
60
+
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,43 @@
1
+ module ShadowsocksRuby
2
+ module Connections
3
+ # Provides various functionality code of a TCP Connection.
4
+ #
5
+ # @example
6
+ # class DummyConnection < EventMachine::Connection
7
+ # include ShadowsocksRuby::Connections::TCP::ClientConnection
8
+ # end
9
+ # # some how get a DummyConnection object
10
+ # # dummy_connection = ...
11
+ # # dummy_connection.plexer_protocol.tcp_process_client will be called looply
12
+ module TCP
13
+ # Mixed-in with an EventMachine::Connection Object to use this.
14
+ module ClientConnection
15
+ include ShadowsocksRuby::Connections::Connection
16
+ include ShadowsocksRuby::Connections::ServerConnection
17
+ # (see ServerConnection#initialize)
18
+ # @option params [String] :host shadowsocks server address, required
19
+ # @option params [Integer] :port shadowsocks server port, required
20
+ def initialize protocol_stack, params, backend_protocol_stack, backend_params
21
+ super
22
+ end
23
+
24
+ def process_first_packet
25
+ address_bin = packet_protocol.tcp_receive_from_client(-1)
26
+ create_plexer(@params[:host], @params[:port], RemoteServerConnection)
27
+ plexer.packet_protocol.tcp_send_to_remoteserver address_bin
28
+ class << self
29
+ alias process_hook process_other_packet
30
+ end
31
+ end
32
+
33
+ # This is Called by process loop
34
+ alias process_hook process_first_packet
35
+
36
+ def process_other_packet
37
+ data = packet_protocol.tcp_receive_from_client(-1)
38
+ plexer.packet_protocol.tcp_send_to_remoteserver(data)
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,19 @@
1
+ module ShadowsocksRuby
2
+ module Connections
3
+ module TCP
4
+ # (see TCP::ClientConnection)
5
+ module DestinationConnection
6
+ include ShadowsocksRuby::Connections::Connection
7
+ include ShadowsocksRuby::Connections::BackendConnection
8
+
9
+ # (see TCP::ClientConnection#process_hook)
10
+ def process_hook
11
+ #plexer.packet_protocol.tcp_send_to_localbackend(packet_protocol.tcp_receive_from_destination(-1))
12
+ data = packet_protocol.tcp_receive_from_destination(-1)
13
+ plexer.packet_protocol.tcp_send_to_localbackend(data)
14
+ end
15
+
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,29 @@
1
+ module ShadowsocksRuby
2
+ module Connections
3
+ module TCP
4
+ # (see TCP::ClientConnection)
5
+ module LocalBackendConnection
6
+ include ShadowsocksRuby::Connections::Connection
7
+ include ShadowsocksRuby::Connections::ServerConnection
8
+
9
+ def process_first_packet
10
+ address_bin = packet_protocol.tcp_receive_from_localbackend(-1)
11
+ host, port = Util::parse_address_bin(address_bin)
12
+ create_plexer(host, port, DestinationConnection)
13
+ class << self
14
+ alias process_hook process_other_packet
15
+ end
16
+ end
17
+
18
+ # (see TCP::ClientConnection#process_hook)
19
+ alias process_hook process_first_packet
20
+
21
+ def process_other_packet
22
+ data = packet_protocol.tcp_receive_from_localbackend(-1)
23
+ plexer.packet_protocol.tcp_send_to_destination(data)
24
+ end
25
+
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,18 @@
1
+ module ShadowsocksRuby
2
+ module Connections
3
+ module TCP
4
+ # (see TCP::ClientConnection)
5
+ module RemoteServerConnection
6
+ include ShadowsocksRuby::Connections::Connection
7
+ include ShadowsocksRuby::Connections::BackendConnection
8
+
9
+ # (see TCP::ClientConnection#process_hook)
10
+ def process_hook
11
+ data = packet_protocol.tcp_receive_from_remoteserver(-1)
12
+ plexer.packet_protocol.tcp_send_to_client(data)
13
+ end
14
+
15
+ end
16
+ end
17
+ end
18
+ end