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