shadowsocks_ruby 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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,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