Skip to content

Commit

Permalink
Add authentication support to Net::HTTP.SOCKSProxy
Browse files Browse the repository at this point in the history
Inspired by #24. This version does not require thread-local variables,
everything kept inside instance and local variables.

Thanks @ojab!
  • Loading branch information
musybite committed Mar 13, 2018
1 parent c840b8f commit dae6100
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 13 deletions.
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

0 comments on commit dae6100

Please sign in to comment.