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

Net::HTTP.SOCKSProxy auth support, take 2 #33

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
2 changes: 2 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,5 @@ SOCKSify Ruby 1.7.2
* Fix Socksify::debug = false
Previously, debug was enabled if any value was assigned to Socksify::debug
(thanks to Dennis Blommesteijn)
* Authentication support added to Net::HTTP.SOCKSProxy
(thanks to @ojab)
8 changes: 8 additions & 0 deletions doc/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,14 @@ <h3>Use Net::HTTP explicitly via SOCKS</h3>
explicitly or use <code>Net::HTTP</code> directly.
</p>

<p>
<code>Net::HTTP.SOCKSProxy</code> also supports SOCKS authentication:
</p>
<pre>
Net::HTTP.SOCKSProxy('127.0.0.1', 9050, 'username', 'p4ssw0rd')
</pre>


<h3>Resolve addresses via SOCKS</h3>
<pre>Socksify::resolve("spaceboyz.net")
# => "87.106.131.203"</pre>
Expand Down
25 changes: 15 additions & 10 deletions lib/socksify.rb
Original file line number Diff line number Diff line change
Expand Up @@ -132,10 +132,11 @@ def self.socks_ignores=(ignores)
end

class SOCKSConnectionPeerAddress < String
attr_reader :socks_server, :socks_port
attr_reader :socks_server, :socks_port, :socks_username, :socks_password

def initialize(socks_server, socks_port, peer_host)
def initialize(socks_server, socks_port, peer_host, socks_username = nil, socks_password = nil)
@socks_server, @socks_port = socks_server, socks_port
@socks_username, @socks_password = socks_username, socks_password
super peer_host
end

Expand All @@ -158,17 +159,21 @@ def initialize(host=nil, port=0, local_host=nil, local_port=nil)
socks_port = socks_peer.socks_port
socks_ignores = []
host = socks_peer.peer_host
socks_username = socks_peer.socks_username
socks_password = socks_peer.socks_password
else
socks_server = self.class.socks_server
socks_port = self.class.socks_port
socks_ignores = self.class.socks_ignores
socks_username = self.class.socks_username
socks_password = self.class.socks_password
end

if socks_server and socks_port and not socks_ignores.include?(host)
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(socks_username, socks_password) unless @@socks_version =~ /^4/

if host
socks_connect(host, port)
Expand All @@ -181,8 +186,8 @@ def initialize(host=nil, port=0, local_host=nil, local_port=nil)
end

# Authentication
def socks_authenticate
if self.class.socks_username || self.class.socks_password
def socks_authenticate(socks_username, socks_password)
if socks_username || socks_password
Socksify::debug_debug "Sending username/password authentication"
write "\005\001\002"
else
Expand All @@ -197,15 +202,15 @@ def socks_authenticate
if auth_reply[0..0] != "\004" and auth_reply[0..0] != "\005"
raise SOCKSError.new("SOCKS version #{auth_reply[0..0]} not supported")
end
if self.class.socks_username || self.class.socks_password
if socks_username || socks_password
if auth_reply[1..1] != "\002"
raise SOCKSError.new("SOCKS authentication method #{auth_reply[1..1]} neither requested nor supported")
end
auth = "\001"
auth += self.class.socks_username.to_s.length.chr
auth += self.class.socks_username.to_s
auth += self.class.socks_password.to_s.length.chr
auth += self.class.socks_password.to_s
auth += socks_username.to_s.length.chr
auth += socks_username.to_s
auth += socks_password.to_s.length.chr
auth += socks_password.to_s
write auth
auth_reply = recv(2)
if auth_reply[1..1] != "\000"
Expand Down
16 changes: 13 additions & 3 deletions lib/socksify/http.rb
Original file line number Diff line number Diff line change
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 @@ -30,6 +30,8 @@ def self.SOCKSProxy(p_host, p_port)
extend delta::ClassMethods
@socks_server = p_host
@socks_port = p_port
@socks_username = p_username
@socks_password = p_password
}
proxyclass
end
Expand All @@ -43,16 +45,24 @@ def socks_server
def socks_port
@socks_port
end

def socks_username
@socks_username
end

def socks_password
@socks_password
end
end

module InstanceMethods
if RUBY_VERSION[0..0] >= '2'
def address
TCPSocket::SOCKSConnectionPeerAddress.new(self.class.socks_server, self.class.socks_port, @address)
TCPSocket::SOCKSConnectionPeerAddress.new(self.class.socks_server, self.class.socks_port, @address, self.class.socks_username, self.class.socks_password)
end
else
def conn_address
TCPSocket::SOCKSConnectionPeerAddress.new(self.class.socks_server, self.class.socks_port, address())
TCPSocket::SOCKSConnectionPeerAddress.new(self.class.socks_server, self.class.socks_port, address(), self.class.socks_username, self.class.socks_password)
end
end
end
Expand Down
4 changes: 2 additions & 2 deletions test/tc_socksify.rb
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ def check_tor_with_service_as_string(http_klass = Net::HTTP)
end

def internet_yandex_com_ip(http_klass = Net::HTTP)
parse_internet_yandex_com_response get_http(http_klass, 'https://213.180.204.62/internet', 'yandex.com') # "http://yandex.com/internet"
parse_internet_yandex_com_response get_http(http_klass, 'https://213.180.204.62/internet/', 'yandex.com') # "http://yandex.com/internet"
end

def parse_check_response(body)
Expand All @@ -151,7 +151,7 @@ def parse_check_response(body)
end

def parse_internet_yandex_com_response(body)
if body =~ /<strong>IP-[^<]*<\/strong>: (\d+\.\d+\.\d+\.\d+)/
if body =~ /<strong>IPv4 address<\/strong>: <span[^>]*>(\d+\.\d+\.\d+\.\d+)/
ip = $1
else
raise 'Bogus response, no IP'+"\n"+body.inspect
Expand Down