Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add authentication support to Net::HTTP.SOCKSProxy #24

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
101 changes: 59 additions & 42 deletions lib/socksify.rb
Expand Up @@ -92,43 +92,60 @@ def self.for_response_code(code)
end

class TCPSocket
@@socks_version ||= "5"

class << self
%w[socks_server socks_port socks_username socks_password].each do |new_method_name|
define_method new_method_name do
if Thread.current.respond_to? :thread_variable_get
Thread.current.thread_variable_get(new_method_name)
else
Thread.current[new_method_name]
end
end
end

%w[socks_server socks_port socks_username socks_password socks_ignores].each do |new_method_name|
define_method "#{new_method_name}=" do |val|
if Thread.current.respond_to? :thread_variable_set
Thread.current.thread_variable_set(new_method_name, val)
else
Thread.current[new_method_name] = val
end
end
end
end

def self.socks_version
(@@socks_version == "4a" or @@socks_version == "4") ? "\004" : "\005"
default = '5'
if Thread.current.respond_to?(:thread_variable_get)
version = Thread.current.thread_variable_get('socks_version')

version.nil? ? Thread.current.thread_variable_set('socks_version', default) : version
else
version = Thread.current['socks_version']

version.nil? ? Thread.current['socks_version'] = default : version
end
end

def self.socks_version=(version)
@@socks_version = version.to_s
end
def self.socks_server
@@socks_server ||= nil
end
def self.socks_server=(host)
@@socks_server = host
Thread.current.respond_to?(:thread_variable_get) ? Thread.current.thread_variable_set('socks_version', version.to_s) : Thread.current['socks_version']
end
def self.socks_port
@@socks_port ||= nil
end
def self.socks_port=(port)
@@socks_port = port
end
def self.socks_username
@@socks_username ||= nil
end
def self.socks_username=(username)
@@socks_username = username
end
def self.socks_password
@@socks_password ||= nil
end
def self.socks_password=(password)
@@socks_password = password

def self.encoded_socks_version
(socks_version == "4a" or socks_version == "4") ? "\004" : "\005"
end

def self.socks_ignores
@@socks_ignores ||= %w(localhost)
end
def self.socks_ignores=(ignores)
@@socks_ignores = ignores
default = %w(localhost)
if Thread.current.respond_to?(:thread_variable_get)
version = Thread.current.thread_variable_get('socks_ignores')

version.nil? ? Thread.current.thread_variable_set('socks_ignores', default) : version
else
version = Thread.current['socks_ignores']

version.nil? ? Thread.current['socks_ignores'] = default : version
end
end

class SOCKSConnectionPeerAddress < String
Expand Down Expand Up @@ -168,7 +185,7 @@ def initialize(host=nil, port=0, local_host=nil, local_port=nil)
Socksify::debug_notice "Connecting to SOCKS server #{socks_server}:#{socks_port}"
initialize_tcp socks_server, socks_port

socks_authenticate unless @@socks_version =~ /^4/
socks_authenticate unless TCPSocket::socks_version =~ /^4/

if host
socks_connect(host, port)
Expand Down Expand Up @@ -222,18 +239,18 @@ def socks_authenticate
def socks_connect(host, port)
port = Socket.getservbyname(port) if port.is_a?(String)
Socksify::debug_debug "Sending destination address"
write TCPSocket.socks_version
Socksify::debug_debug TCPSocket.socks_version.unpack "H*"
write TCPSocket::encoded_socks_version
Socksify::debug_debug TCPSocket::encoded_socks_version.unpack "H*"
write "\001"
write "\000" if @@socks_version == "5"
write [port].pack('n') if @@socks_version =~ /^4/
write "\000" if TCPSocket::socks_version == "5"
write [port].pack('n') if TCPSocket::socks_version =~ /^4/

if @@socks_version == "4"
if TCPSocket::socks_version == "4"
host = Resolv::DNS.new.getaddress(host).to_s
end
Socksify::debug_debug host
if host =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/ # to IPv4 address
write "\001" if @@socks_version == "5"
write "\001" if TCPSocket::socks_version == "5"
_ip = [$1.to_i,
$2.to_i,
$3.to_i,
Expand All @@ -244,7 +261,7 @@ def socks_connect(host, port)
raise "TCP/IPv6 over SOCKS is not yet supported (inet_pton missing in Ruby & not supported by Tor"
write "\004"
else # to hostname
if @@socks_version == "5"
if TCPSocket::socks_version == "5"
write "\003" + [host.size].pack('C') + host
else
write "\000\000\000\001"
Expand All @@ -254,7 +271,7 @@ def socks_connect(host, port)
write "\000"
end
end
write [port].pack('n') if @@socks_version == "5"
write [port].pack('n') if TCPSocket::socks_version == "5"

socks_receive_reply
Socksify::debug_notice "Connected to #{host}:#{port} over SOCKS"
Expand All @@ -263,7 +280,7 @@ def socks_connect(host, port)
# returns [bind_addr: String, bind_port: Fixnum]
def socks_receive_reply
Socksify::debug_debug "Waiting for SOCKS reply"
if @@socks_version == "5"
if TCPSocket::socks_version == "5"
connect_reply = recv(4)
if connect_reply.empty?
raise SOCKSError.new("Server doesn't reply")
Expand Down Expand Up @@ -336,7 +353,7 @@ def self.resolve(host)
s.write "\xF0\000\003" + [host.size].pack('C') + host
end
s.write [0].pack('n') # Port

addr, _port = s.socks_receive_reply
Socksify::debug_notice "Resolved #{host} as #{addr} over SOCKS"
addr
Expand Down
4 changes: 3 additions & 1 deletion lib/socksify/http.rb
Expand Up @@ -21,7 +21,7 @@

module Net
class HTTP
def self.SOCKSProxy(p_host, p_port)
def self.SOCKSProxy(p_host, p_port, p_username = nil, p_password = nil)
delta = SOCKSProxyDelta
proxyclass = Class.new(self)
proxyclass.send(:include, delta)
Expand All @@ -31,6 +31,8 @@ def self.SOCKSProxy(p_host, p_port)
@socks_server = p_host
@socks_port = p_port
}
TCPSocket.socks_username = p_username
TCPSocket.socks_password = p_password
proxyclass
end

Expand Down