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,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