From dae610084b4cebd0af92731dbf29f3dd9b9fd9d6 Mon Sep 17 00:00:00 2001 From: Musy Bite Date: Tue, 13 Mar 2018 22:42:05 +0300 Subject: [PATCH] Add authentication support to Net::HTTP.SOCKSProxy Inspired by #24. This version does not require thread-local variables, everything kept inside instance and local variables. Thanks @ojab! --- ChangeLog | 2 ++ doc/index.html | 8 ++++++++ lib/socksify.rb | 25 +++++++++++++++---------- lib/socksify/http.rb | 16 +++++++++++++--- 4 files changed, 38 insertions(+), 13 deletions(-) diff --git a/ChangeLog b/ChangeLog index c714caf..ed18f55 100644 --- a/ChangeLog +++ b/ChangeLog @@ -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) diff --git a/doc/index.html b/doc/index.html index 56c927a..30452b4 100644 --- a/doc/index.html +++ b/doc/index.html @@ -99,6 +99,14 @@

Use Net::HTTP explicitly via SOCKS

explicitly or use Net::HTTP directly.

+

+ Net::HTTP.SOCKSProxy also supports SOCKS authentication: +

+
+Net::HTTP.SOCKSProxy('127.0.0.1', 9050, 'username', 'p4ssw0rd')
+      
+ +

Resolve addresses via SOCKS

Socksify::resolve("spaceboyz.net")
 # => "87.106.131.203"
diff --git a/lib/socksify.rb b/lib/socksify.rb index 39adced..155ef57 100644 --- a/lib/socksify.rb +++ b/lib/socksify.rb @@ -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 @@ -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) @@ -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 @@ -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" diff --git a/lib/socksify/http.rb b/lib/socksify/http.rb index 25b63d7..2ba7ae2 100644 --- a/lib/socksify/http.rb +++ b/lib/socksify/http.rb @@ -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) @@ -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 @@ -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