class ShadowsocksRuby::Protocols::HttpSimpleProtocol
Http Simple Obfuscation Protocol
Specification:
Constants
- USER_AGENTS
Attributes
next_protocol[RW]
Public Class Methods
new(params = {})
click to toggle source
@param [Hash] configuration parameters @option params [String] :host shadowsocks server address, required by remoteserver protocol @option params [String] :port shadowsocks server port, required by remoteserver protocol @option params [Boolean] :compatible compatibility with origin mode, default true @option params [String] :obfs_param obfs param, optional
# File lib/shadowsocks_ruby/protocols/obfs/http_simple.rb, line 32 def initialize params = {} @params = {:compatible => true }.merge(params) @buffer = '' end
Public Instance Methods
async_recv_until(str)
click to toggle source
# File lib/shadowsocks_ruby/protocols/obfs/http_simple.rb, line 166 def async_recv_until str @next_protocol.async_recv_until str end
get_data_from_http_header(buf)
click to toggle source
helpers
# File lib/shadowsocks_ruby/protocols/obfs/http_simple.rb, line 158 def get_data_from_http_header buf [buf.split("\r\n")[0][/(%..)+/].gsub(/%/,'')].pack("H*") end
get_host_from_http_header(buf)
click to toggle source
# File lib/shadowsocks_ruby/protocols/obfs/http_simple.rb, line 162 def get_host_from_http_header buf buf[/^Host: (.+):/,1] end
tcp_receive_from_localbackend_first_packet(n)
click to toggle source
# File lib/shadowsocks_ruby/protocols/obfs/http_simple.rb, line 99 def tcp_receive_from_localbackend_first_packet n data = async_recv 10 if (data =~ /^GET|^POST/) == nil if @params[:compatible] @buffer << data << async_recv(n - data.length) else raise PharseError, "not a valid http_simple first packet in strict mode" end else buf = "" buf << data << async_recv_until("\r\n\r\n") host = get_host_from_http_header(buf) if host != nil && @params[:obfs_param] != nil hosts = @params[:obfs_param] if hosts.include?('#') hosts, body = hosts.split('#') body = body.gsub(/\n/,"\r\n") body = body.gsub(/\\n/,"\r\n") end hosts = hosts.split(",") if !hosts.include?(host) raise PharseError, "request host not in :obfs_param" end end ret_buf = get_data_from_http_header(buf) raise PharseError, "not a valid request" if ret_buf.length < 4 @buffer << ret_buf end class << self alias tcp_receive_from_localbackend tcp_receive_from_localbackend_other_packet end tcp_receive_from_localbackend_other_packet_helper n end
Also aliased as: tcp_receive_from_localbackend
tcp_receive_from_localbackend_other_packet(n)
click to toggle source
# File lib/shadowsocks_ruby/protocols/obfs/http_simple.rb, line 136 def tcp_receive_from_localbackend_other_packet n async_recv(n) end
tcp_receive_from_remoteserver_first_packet(n)
click to toggle source
# File lib/shadowsocks_ruby/protocols/obfs/http_simple.rb, line 37 def tcp_receive_from_remoteserver_first_packet n class << self alias tcp_receive_from_remoteserver tcp_receive_from_remoteserver_other_packet end async_recv_until("\r\n\r\n") async_recv n end
Also aliased as: tcp_receive_from_remoteserver
tcp_receive_from_remoteserver_other_packet(n)
click to toggle source
# File lib/shadowsocks_ruby/protocols/obfs/http_simple.rb, line 48 def tcp_receive_from_remoteserver_other_packet n async_recv n end
tcp_send_to_localbackend_first_packet(data)
click to toggle source
# File lib/shadowsocks_ruby/protocols/obfs/http_simple.rb, line 140 def tcp_send_to_localbackend_first_packet data class << self alias tcp_send_to_localbackend tcp_send_to_localbackend_other_packet end header = "HTTP/1.1 200 OK\r\nConnection: keep-alive\r\nContent-Encoding: gzip\r\nContent-Type: text/html\r\nDate: " header << Time.now.strftime('%a, %d %b %Y %H:%M:%S GMT') header << "\r\nServer: nginx\r\nVary: Accept-Encoding\r\n\r\n" send_data header << data end
Also aliased as: tcp_send_to_localbackend
tcp_send_to_localbackend_other_packet(data)
click to toggle source
# File lib/shadowsocks_ruby/protocols/obfs/http_simple.rb, line 153 def tcp_send_to_localbackend_other_packet data send_data data end
tcp_send_to_remoteserver_first_packet(data)
click to toggle source
# File lib/shadowsocks_ruby/protocols/obfs/http_simple.rb, line 52 def tcp_send_to_remoteserver_first_packet data if data.length > 30 + 64 headlen = 30 + Random.rand(64 + 1) else headlen = data.length end headdata = data.slice!(0, headlen) port = '' raise ProtocolError, "No :port params" if @params[:port] == nil if @params[:port] != 80 port = ':' << @params[:port].to_s end body = nil hosts = @params[:obfs_param] || @params[:host] raise ProtocolError, "No :host or :obfs_param parameters" if hosts == nil if hosts.include?('#') hosts, body = hosts.split('#') body = body.gsub(/\n/,"\r\n") body = body.gsub(/\\n/,"\r\n") end hosts = hosts.split(",") host = hosts[Random.rand(hosts.length)] http_head = "GET /" << headdata.unpack("H*")[0].gsub(/../,'%\0') << " HTTP/1.1\r\n" http_head << "Host: " << host << port << "\r\n" if body != nil http_head << body << "\r\n\r\n" else http_head << "User-Agent: " + USER_AGENTS[Random.rand(USER_AGENTS.length)] << "\r\n" 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" end send_data(http_head << data) class << self alias tcp_send_to_remoteserver tcp_send_to_remoteserver_other_packet end end
Also aliased as: tcp_send_to_remoteserver
tcp_send_to_remoteserver_other_packet(data)
click to toggle source
# File lib/shadowsocks_ruby/protocols/obfs/http_simple.rb, line 94 def tcp_send_to_remoteserver_other_packet data send_data data end