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,43 @@
1
+ module ShadowsocksRuby
2
+ module Connections
3
+ # Provides various functionality code of a UDP Connection.
4
+ #
5
+ # @example
6
+ # class DummyConnection < EventMachine::Connection
7
+ # include ShadowsocksRuby::Connections::UDP::ClientConnection
8
+ # end
9
+ # # some how get a DummyConnection object
10
+ # # dummy_connection = ...
11
+ # # dummy_connection.plexer_protocol.udp_process_client will be called looply
12
+ module UDP
13
+ # (see TCP::ClientConnection)
14
+ module ClientConnection
15
+ include ShadowsocksRuby::Connections::Connection
16
+ include ShadowsocksRuby::Connections::ServerConnection
17
+
18
+ # (see TCP::ClientConnection#initialize)
19
+ def initialize protocol_stack, params, backend_protocol_stack, backend_params
20
+ super
21
+ end
22
+
23
+ def process_first_packet
24
+ address_bin = packet_protocol.udp_receive_from_client(-1)
25
+ create_plexer(@params[:host], @params[:port], RemoteServerConnection)
26
+ plexer.packet_protocol.udp_send_to_remoteserver address_bin
27
+ class << self
28
+ alias process_hook process_other_packet
29
+ end
30
+ end
31
+
32
+ # This is Called by process loop
33
+ alias process_hook process_first_packet
34
+
35
+ def process_other_packet
36
+ data = packet_protocol.udp_receive_from_client(-1)
37
+ plexer.packet_protocol.udp_send_to_remoteserver(data)
38
+ end
39
+
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,18 @@
1
+ module ShadowsocksRuby
2
+ module Connections
3
+ module UDP
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
+ data = packet_protocol.udp_receive_from_destination(-1)
12
+ plexer.packet_protocol.udp_send_to_localbackend(data)
13
+ end
14
+
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,29 @@
1
+ module ShadowsocksRuby
2
+ module Connections
3
+ module UDP
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.udp_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.udp_receive_from_localbackend(-1)
23
+ plexer.packet_protocol.udp_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 UDP
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.udp_receive_from_remoteserver(-1)
12
+ plexer.packet_protocol.udp_send_to_client(data)
13
+ end
14
+
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,99 @@
1
+ module ShadowsocksRuby
2
+ module Protocols
3
+
4
+ # To be used with any cipher methods with an IV, like {Cipher::OpenSSL},
5
+ # {Cipher::RbNaCl} and {Cipher::RC4_MD5}.
6
+ class IvCipherProtocol
7
+ include DummyHelper
8
+ include BufferHelper
9
+
10
+ attr_accessor :next_protocol
11
+
12
+ # @param [Hash] configuration parameters
13
+ # @option params [Cipher::OpenSSL, Cipher::RbNaCl, Cipher::RC4_MD5] :cipher a cipher object with IV and a key, +required+
14
+ def initialize params = {}
15
+ @cipher = params[:cipher] or raise ProtocolError, "params[:cipher] is required"
16
+ @buffer =""
17
+ end
18
+
19
+ def tcp_receive_from_remoteserver_first_packet n
20
+ iv_len = @cipher.iv_len
21
+ @recv_iv = async_recv iv_len
22
+ class << self
23
+ alias tcp_receive_from_remoteserver tcp_receive_from_remoteserver_other_packet
24
+ end
25
+ tcp_receive_from_remoteserver_other_packet n
26
+ end
27
+
28
+ alias tcp_receive_from_remoteserver tcp_receive_from_remoteserver_first_packet
29
+
30
+ def tcp_receive_from_remoteserver_other_packet n
31
+ @buffer << @cipher.decrypt(async_recv(-1), @recv_iv)
32
+ tcp_receive_from_remoteserver_other_packet_helper n
33
+ end
34
+
35
+ def tcp_send_to_remoteserver_first_packet data
36
+ send_first_packet_process data
37
+ class << self
38
+ alias tcp_send_to_remoteserver send_other_packet
39
+ end
40
+ end
41
+
42
+ alias tcp_send_to_remoteserver tcp_send_to_remoteserver_first_packet
43
+
44
+ def tcp_receive_from_localbackend_first_packet n
45
+ iv_len = @cipher.iv_len
46
+ @recv_iv = async_recv iv_len
47
+ class << self
48
+ alias tcp_receive_from_localbackend tcp_receive_from_localbackend_other_packet
49
+ end
50
+ tcp_receive_from_localbackend_other_packet n
51
+ end
52
+
53
+ alias tcp_receive_from_localbackend tcp_receive_from_localbackend_first_packet
54
+
55
+ def tcp_receive_from_localbackend_other_packet n
56
+ @buffer << @cipher.decrypt(async_recv(-1), @recv_iv)
57
+ tcp_receive_from_localbackend_other_packet_helper n
58
+ end
59
+
60
+ def tcp_send_to_localbackend_first_packet data
61
+ send_first_packet_process data
62
+ class << self
63
+ alias tcp_send_to_localbackend send_other_packet
64
+ end
65
+ end
66
+
67
+ alias tcp_send_to_localbackend tcp_send_to_localbackend_first_packet
68
+
69
+
70
+ def send_first_packet_process data
71
+ @send_iv = @cipher.random_iv
72
+ send_data @send_iv + @cipher.encrypt(data, @send_iv)
73
+ end
74
+
75
+ def send_other_packet data
76
+ send_data @cipher.encrypt(data, @send_iv)
77
+ end
78
+
79
+ alias tcp_receive_from_client raise_me
80
+ alias tcp_send_to_client raise_me
81
+ #alias tcp_receive_from_remoteserver raise_me
82
+ #alias tcp_send_to_remoteserver raise_me
83
+ #alias tcp_receive_from_localbackend raise_me
84
+ #alias tcp_send_to_localbackend raise_me
85
+ alias tcp_receive_from_destination raise_me
86
+ alias tcp_send_to_destination raise_me
87
+
88
+ alias udp_receive_from_client raise_me
89
+ alias udp_send_to_client raise_me
90
+ alias udp_receive_from_remoteserver raise_me
91
+ alias udp_send_to_remoteserver raise_me
92
+ alias udp_receive_from_localbackend raise_me
93
+ alias udp_send_to_localbackend raise_me
94
+ alias udp_receive_from_destination raise_me
95
+ alias udp_send_to_destination raise_me
96
+
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,53 @@
1
+ module ShadowsocksRuby
2
+ module Protocols
3
+
4
+ # To be used with protocols without an IV, like {Cipher::Table}
5
+ class NoIvCipherProtocol
6
+ include DummyHelper
7
+
8
+ attr_accessor :next_protocol
9
+
10
+ # @param [Hash] configuration parameters
11
+ # @option params [Cipher::Table] :cipher a cipher object without IV, +required+
12
+ def initialize params = {}
13
+ @cipher = params[:cipher] or raise ProtocolError, "params[:cipher] is required"
14
+ end
15
+
16
+ def tcp_receive_from_remoteserver n
17
+ @cipher.decrypt(async_recv n)
18
+ end
19
+
20
+ def tcp_send_to_remoteserver data
21
+ send_data(@cipher.encrypt data)
22
+ end
23
+
24
+ def tcp_receive_from_localbackend n
25
+ @cipher.decrypt(async_recv n)
26
+ end
27
+
28
+ def tcp_send_to_localbackend data
29
+ send_data(@cipher.encrypt data)
30
+ end
31
+
32
+ private
33
+
34
+ alias tcp_receive_from_client raise_me
35
+ alias tcp_send_to_client raise_me
36
+ #alias tcp_receive_from_remoteserver raise_me
37
+ #alias tcp_send_to_remoteserver raise_me
38
+ #alias tcp_receive_from_localbackend raise_me
39
+ #alias tcp_send_to_localbackend raise_me
40
+ alias tcp_receive_from_destination raise_me
41
+ alias tcp_send_to_destination raise_me
42
+
43
+ alias udp_receive_from_client raise_me
44
+ alias udp_send_to_client raise_me
45
+ alias udp_receive_from_remoteserver raise_me
46
+ alias udp_send_to_remoteserver raise_me
47
+ alias udp_receive_from_localbackend raise_me
48
+ alias udp_send_to_localbackend raise_me
49
+ alias udp_receive_from_destination raise_me
50
+ alias udp_send_to_destination raise_me
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,138 @@
1
+ module ShadowsocksRuby
2
+ module Protocols
3
+ # Origin shadowsocks protocols with One Time Authenticate
4
+ #
5
+ # specification: https://shadowsocks.org/en/spec/protocol.html
6
+ class VerifySha1Protocol
7
+ include DummyHelper
8
+ include BufferHelper
9
+
10
+ attr_accessor :next_protocol
11
+
12
+ ATYP_IPV4 = 1
13
+ ATYP_DOMAIN = 3
14
+ ATYP_IPV6 = 4
15
+
16
+ # @param [Hash] configuration parameters
17
+ # @option params [Cipher::OpenSSL, Cipher::RbNaCl, Cipher::RC4_MD5] :cipher a cipher object with IV and a key, +required+
18
+ # @option params [Boolean] :compatible compatibility with origin mode, default _true_
19
+ def initialize params = {}
20
+ @params = {:compatible => true}.merge(params)
21
+ @cipher = @params[:cipher] or raise ProtocolError, "params[:cipher] is required"
22
+ raise ProtocolError, "cipher object mush have an IV and a key" if @cipher.iv_len == 0 || @cipher.key == nil
23
+ @buffer = ""
24
+ @counter = 0
25
+ end
26
+
27
+ def tcp_receive_from_remoteserver_first_packet n
28
+ @recv_iv = async_recv(@cipher.iv_len)
29
+ class << self
30
+ alias tcp_receive_from_remoteserver tcp_receive_from_remoteserver_other_packet
31
+ end
32
+ tcp_receive_from_remoteserver_other_packet n
33
+ end
34
+
35
+ alias tcp_receive_from_remoteserver tcp_receive_from_remoteserver_first_packet
36
+
37
+ def tcp_receive_from_remoteserver_other_packet n
38
+ @buffer << @cipher.decrypt(async_recv(-1), @recv_iv)
39
+ tcp_receive_from_remoteserver_other_packet_helper n
40
+ end
41
+
42
+ def tcp_send_to_remoteserver_first_packet data
43
+ data[0] = [0x10 | data.unpack("C").first].pack("C") # set ota flag
44
+ @send_iv = @cipher.random_iv
45
+ hmac = ShadowsocksRuby::Cipher.hmac_sha1_digest(@send_iv + @cipher.key, data)
46
+ send_data @send_iv + @cipher.encrypt(data + hmac, @send_iv)
47
+ class << self
48
+ alias tcp_send_to_remoteserver tcp_send_to_remoteserver_other_packet
49
+ end
50
+ end
51
+
52
+ alias tcp_send_to_remoteserver tcp_send_to_remoteserver_first_packet
53
+
54
+ def tcp_send_to_remoteserver_other_packet data
55
+ data = @cipher.encrypt(data, @send_iv)
56
+ hmac = ShadowsocksRuby::Cipher.hmac_sha1_digest(@send_iv + [@counter].pack("n"), data)
57
+ send_data [data.length].pack("n") << hmac << data
58
+ @counter += 1
59
+ end
60
+
61
+ def tcp_receive_from_localbackend_first_packet n
62
+ class << self
63
+ alias tcp_receive_from_localbackend tcp_receive_from_localbackend_other_packet
64
+ end
65
+ data = async_recv(-1) # first packet
66
+ @recv_iv = data.slice!(0, @cipher.iv_len)
67
+ data = @cipher.decrypt(data, @recv_iv)
68
+ @atyp = data.unpack("C")[0]
69
+ if @atyp & 0x10 == 0x10 # OTA mode
70
+ hmac = data[-10, 10]
71
+ raise PharseError, "hmac_sha1 is not correct" \
72
+ unless ShadowsocksRuby::Cipher.hmac_sha1_digest(@recv_iv + @cipher.key, data[0 ... -10]) == hmac
73
+ data[0] = [0x0F & @atyp].pack("C") # clear ota flag
74
+ @buffer << data[0 ... -10]
75
+ tcp_receive_from_localbackend_other_packet_helper n
76
+ else # origin mode
77
+ if @params[:compatible] == false
78
+ raise PharseError, "invalid OTA first packet in strict OTA mode"
79
+ end
80
+ @buffer << data
81
+ tcp_receive_from_localbackend_other_packet_helper n
82
+ end
83
+
84
+ end
85
+
86
+ alias tcp_receive_from_localbackend tcp_receive_from_localbackend_first_packet
87
+
88
+ def tcp_receive_from_localbackend_other_packet n
89
+ if @atyp & 0x10 == 0x10 # OTA mode
90
+ len = async_recv(2).unpack("n").first
91
+ hmac = async_recv(10)
92
+ data = async_recv(len)
93
+ raise PharseError, "hmac_sha1 is not correct" \
94
+ unless ShadowsocksRuby::Cipher.hmac_sha1_digest(@recv_iv + [@counter].pack("n"), data) == hmac
95
+ @buffer << @cipher.decrypt(data, @recv_iv)
96
+ @counter += 1
97
+ tcp_receive_from_localbackend_other_packet_helper n
98
+ else # origin mode
99
+ @buffer << @cipher.decrypt(async_recv(-1), @recv_iv)
100
+ tcp_receive_from_localbackend_other_packet_helper n
101
+ end
102
+ end
103
+
104
+ def tcp_send_to_localbackend_first_packet data
105
+ @send_iv = @cipher.random_iv
106
+ send_data @send_iv + @cipher.encrypt(data, @send_iv)
107
+ class << self
108
+ alias tcp_send_to_localbackend tcp_send_to_localbackend_other_packet
109
+ end
110
+ end
111
+
112
+ alias tcp_send_to_localbackend tcp_send_to_localbackend_first_packet
113
+
114
+ def tcp_send_to_localbackend_other_packet data
115
+ send_data @cipher.encrypt(data, @send_iv)
116
+ end
117
+
118
+ alias tcp_receive_from_client raise_me
119
+ alias tcp_send_to_client raise_me
120
+ #alias tcp_receive_from_remoteserver raise_me
121
+ #alias tcp_send_to_remoteserver raise_me
122
+ #alias tcp_receive_from_localbackend raise_me
123
+ #alias tcp_send_to_localbackend raise_me
124
+ alias tcp_receive_from_destination raise_me
125
+ alias tcp_send_to_destination raise_me
126
+
127
+ alias udp_receive_from_client raise_me
128
+ alias udp_send_to_client raise_me
129
+ alias udp_receive_from_remoteserver raise_me
130
+ alias udp_send_to_remoteserver raise_me
131
+ alias udp_receive_from_localbackend raise_me
132
+ alias udp_send_to_localbackend raise_me
133
+ alias udp_receive_from_destination raise_me
134
+ alias udp_send_to_destination raise_me
135
+
136
+ end
137
+ end
138
+ end
@@ -0,0 +1,189 @@
1
+ module ShadowsocksRuby
2
+ module Protocols
3
+ # Http Simple Obfuscation Protocol
4
+ #
5
+ # Specification:
6
+ # * https://github.com/shadowsocksr/shadowsocksr/blob/manyuser/shadowsocks/obfsplugin/http_simple.py
7
+ # * https://github.com/shadowsocksr/obfsplugin/blob/master/c/http_simple.c
8
+ class HttpSimpleProtocol
9
+ include DummyHelper
10
+ include BufferHelper
11
+
12
+ attr_accessor :next_protocol
13
+
14
+ USER_AGENTS = ["Mozilla/5.0 (Windows NT 6.3; WOW64; rv:40.0) Gecko/20100101 Firefox/40.0",
15
+ "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:40.0) Gecko/20100101 Firefox/44.0",
16
+ "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36",
17
+ "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.11 (KHTML, like Gecko) Ubuntu/11.10 Chromium/27.0.1453.93 Chrome/27.0.1453.93 Safari/537.36",
18
+ "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:35.0) Gecko/20100101 Firefox/35.0",
19
+ "Mozilla/5.0 (compatible; WOW64; MSIE 10.0; Windows NT 6.2)",
20
+ "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/533.20.25 (KHTML, like Gecko) Version/5.0.4 Safari/533.20.27",
21
+ "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.3; Trident/7.0; .NET4.0E; .NET4.0C)",
22
+ "Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko",
23
+ "Mozilla/5.0 (Linux; Android 4.4; Nexus 5 Build/BuildID) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/30.0.0.0 Mobile Safari/537.36",
24
+ "Mozilla/5.0 (iPad; CPU OS 5_0 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9A334 Safari/7534.48.3",
25
+ "Mozilla/5.0 (iPhone; CPU iPhone OS 5_0 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9A334 Safari/7534.48.3"]
26
+
27
+ # @param [Hash] configuration parameters
28
+ # @option params [String] :host shadowsocks server address, required by remoteserver protocol
29
+ # @option params [String] :port shadowsocks server port, required by remoteserver protocol
30
+ # @option params [Boolean] :compatible compatibility with origin mode, default _true_
31
+ # @option params [String] :obfs_param obfs param, optional
32
+ def initialize params = {}
33
+ @params = {:compatible => true }.merge(params)
34
+ @buffer = ''
35
+ end
36
+
37
+ def tcp_receive_from_remoteserver_first_packet n
38
+ class << self
39
+ alias tcp_receive_from_remoteserver tcp_receive_from_remoteserver_other_packet
40
+ end
41
+
42
+ async_recv_until("\r\n\r\n")
43
+ async_recv n
44
+ end
45
+
46
+ alias tcp_receive_from_remoteserver tcp_receive_from_remoteserver_first_packet
47
+
48
+ def tcp_receive_from_remoteserver_other_packet n
49
+ async_recv n
50
+ end
51
+
52
+ def tcp_send_to_remoteserver_first_packet data
53
+ if data.length > 30 + 64
54
+ headlen = 30 + Random.rand(64 + 1)
55
+ else
56
+ headlen = data.length
57
+ end
58
+ headdata = data.slice!(0, headlen)
59
+ port = ''
60
+ raise ProtocolError, "No :port params" if @params[:port] == nil
61
+ if @params[:port] != 80
62
+ port = ':' << @params[:port].to_s
63
+ end
64
+
65
+ body = nil
66
+ hosts = @params[:obfs_param] || @params[:host]
67
+ raise ProtocolError, "No :host or :obfs_param parameters" if hosts == nil
68
+ if hosts.include?('#')
69
+ hosts, body = hosts.split('#')
70
+ body = body.gsub(/\n/,"\r\n")
71
+ body = body.gsub(/\\n/,"\r\n")
72
+ end
73
+ hosts = hosts.split(",")
74
+ host = hosts[Random.rand(hosts.length)]
75
+
76
+ http_head = "GET /" << headdata.unpack("H*")[0].gsub(/../,'%\0') << " HTTP/1.1\r\n"
77
+ http_head << "Host: " << host << port << "\r\n"
78
+
79
+ if body != nil
80
+ http_head << body << "\r\n\r\n"
81
+ else
82
+ http_head << "User-Agent: " + USER_AGENTS[Random.rand(USER_AGENTS.length)] << "\r\n"
83
+ http_head << "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\nAccept-Language: en-US,en;q=0.8\r\nAccept-Encoding: gzip, deflate\r\nDNT: 1\r\nConnection: keep-alive\r\n\r\n"
84
+ end
85
+ send_data(http_head << data)
86
+ class << self
87
+ alias tcp_send_to_remoteserver tcp_send_to_remoteserver_other_packet
88
+ end
89
+
90
+ end
91
+
92
+ alias tcp_send_to_remoteserver tcp_send_to_remoteserver_first_packet
93
+
94
+ def tcp_send_to_remoteserver_other_packet data
95
+ send_data data
96
+ end
97
+
98
+
99
+ def tcp_receive_from_localbackend_first_packet n
100
+ data = async_recv 10
101
+ if (data =~ /^GET|^POST/) == nil
102
+ if @params[:compatible]
103
+ @buffer << data << async_recv(n - data.length)
104
+ else
105
+ raise PharseError, "not a valid http_simple first packet in strict mode"
106
+ end
107
+ else
108
+ buf = ""
109
+ buf << data << async_recv_until("\r\n\r\n")
110
+ host = get_host_from_http_header(buf)
111
+ if host != nil && @params[:obfs_param] != nil
112
+ hosts = @params[:obfs_param]
113
+ if hosts.include?('#')
114
+ hosts, body = hosts.split('#')
115
+ body = body.gsub(/\n/,"\r\n")
116
+ body = body.gsub(/\\n/,"\r\n")
117
+ end
118
+ hosts = hosts.split(",")
119
+ if !hosts.include?(host)
120
+ raise PharseError, "request host not in :obfs_param"
121
+ end
122
+ end
123
+ ret_buf = get_data_from_http_header(buf)
124
+ raise PharseError, "not a valid request" if ret_buf.length < 4
125
+ @buffer << ret_buf
126
+ end
127
+
128
+ class << self
129
+ alias tcp_receive_from_localbackend tcp_receive_from_localbackend_other_packet
130
+ end
131
+ tcp_receive_from_localbackend_other_packet_helper n
132
+ end
133
+
134
+ alias tcp_receive_from_localbackend tcp_receive_from_localbackend_first_packet
135
+
136
+ def tcp_receive_from_localbackend_other_packet n
137
+ async_recv(n)
138
+ end
139
+
140
+ def tcp_send_to_localbackend_first_packet data
141
+ class << self
142
+ alias tcp_send_to_localbackend tcp_send_to_localbackend_other_packet
143
+ end
144
+
145
+ header = "HTTP/1.1 200 OK\r\nConnection: keep-alive\r\nContent-Encoding: gzip\r\nContent-Type: text/html\r\nDate: "
146
+ header << Time.now.strftime('%a, %d %b %Y %H:%M:%S GMT')
147
+ header << "\r\nServer: nginx\r\nVary: Accept-Encoding\r\n\r\n"
148
+ send_data header << data
149
+ end
150
+
151
+ alias tcp_send_to_localbackend tcp_send_to_localbackend_first_packet
152
+
153
+ def tcp_send_to_localbackend_other_packet data
154
+ send_data data
155
+ end
156
+
157
+ # helpers
158
+ def get_data_from_http_header buf
159
+ [buf.split("\r\n")[0][/(%..)+/].gsub(/%/,'')].pack("H*")
160
+ end
161
+
162
+ def get_host_from_http_header buf
163
+ buf[/^Host: (.+):/,1]
164
+ end
165
+
166
+ def async_recv_until str
167
+ @next_protocol.async_recv_until str
168
+ end
169
+
170
+ alias tcp_receive_from_client raise_me
171
+ alias tcp_send_to_client raise_me
172
+ #alias tcp_receive_from_remoteserver raise_me
173
+ #alias tcp_send_to_remoteserver raise_me
174
+ #alias tcp_receive_from_localbackend raise_me
175
+ #alias tcp_send_to_localbackend raise_me
176
+ alias tcp_receive_from_destination raise_me
177
+ alias tcp_send_to_destination raise_me
178
+
179
+ alias udp_receive_from_client raise_me
180
+ alias udp_send_to_client raise_me
181
+ alias udp_receive_from_remoteserver raise_me
182
+ alias udp_send_to_remoteserver raise_me
183
+ alias udp_receive_from_localbackend raise_me
184
+ alias udp_send_to_localbackend raise_me
185
+ alias udp_receive_from_destination raise_me
186
+ alias udp_send_to_destination raise_me
187
+ end
188
+ end
189
+ end