about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--app/lib/request.rb83
1 files changed, 48 insertions, 35 deletions
diff --git a/app/lib/request.rb b/app/lib/request.rb
index e25b9026c..5f7075a3c 100644
--- a/app/lib/request.rb
+++ b/app/lib/request.rb
@@ -30,7 +30,8 @@ class Request
     @verb        = verb
     @url         = Addressable::URI.parse(url).normalize
     @http_client = options.delete(:http_client)
-    @options     = options.merge(use_proxy? ? Rails.configuration.x.http_client_proxy : { socket_class: Socket })
+    @options     = options.merge(socket_class: use_proxy? ? ProxySocket : Socket)
+    @options     = @options.merge(Rails.configuration.x.http_client_proxy) if use_proxy?
     @headers     = {}
 
     raise Mastodon::HostValidationError, 'Instance does not support hidden service connections' if block_hidden_service?
@@ -177,47 +178,49 @@ class Request
   class Socket < TCPSocket
     class << self
       def open(host, *args)
-        return super(host, *args) if thru_hidden_service?(host)
-
         outer_e = nil
         port    = args.first
 
-        Resolv::DNS.open do |dns|
-          dns.timeouts = 5
+        addresses = []
+        begin
+          addresses = [IPAddr.new(host)]
+        rescue IPAddr::InvalidAddressError
+          Resolv::DNS.open do |dns|
+            dns.timeouts = 5
+            addresses = dns.getaddresses(host).take(2)
+          end
+        end
 
-          addresses = dns.getaddresses(host).take(2)
+        addresses.each do |address|
+          begin
+            check_private_address(address)
+
+            sock     = ::Socket.new(address.is_a?(Resolv::IPv6) ? ::Socket::AF_INET6 : ::Socket::AF_INET, ::Socket::SOCK_STREAM, 0)
+            sockaddr = ::Socket.pack_sockaddr_in(port, address.to_s)
+
+            sock.setsockopt(::Socket::IPPROTO_TCP, ::Socket::TCP_NODELAY, 1)
 
-          addresses.each do |address|
             begin
-              raise Mastodon::HostValidationError if PrivateAddressCheck.private_address?(IPAddr.new(address.to_s))
-
-              sock     = ::Socket.new(address.is_a?(Resolv::IPv6) ? ::Socket::AF_INET6 : ::Socket::AF_INET, ::Socket::SOCK_STREAM, 0)
-              sockaddr = ::Socket.pack_sockaddr_in(port, address.to_s)
-
-              sock.setsockopt(::Socket::IPPROTO_TCP, ::Socket::TCP_NODELAY, 1)
-
-              begin
-                sock.connect_nonblock(sockaddr)
-              rescue IO::WaitWritable
-                if IO.select(nil, [sock], nil, Request::TIMEOUT[:connect])
-                  begin
-                    sock.connect_nonblock(sockaddr)
-                  rescue Errno::EISCONN
-                    # Yippee!
-                  rescue
-                    sock.close
-                    raise
-                  end
-                else
+              sock.connect_nonblock(sockaddr)
+            rescue IO::WaitWritable
+              if IO.select(nil, [sock], nil, Request::TIMEOUT[:connect])
+                begin
+                  sock.connect_nonblock(sockaddr)
+                rescue Errno::EISCONN
+                  # Yippee!
+                rescue
                   sock.close
-                  raise HTTP::TimeoutError, "Connect timed out after #{Request::TIMEOUT[:connect]} seconds"
+                  raise
                 end
+              else
+                sock.close
+                raise HTTP::TimeoutError, "Connect timed out after #{Request::TIMEOUT[:connect]} seconds"
               end
-
-              return sock
-            rescue => e
-              outer_e = e
             end
+
+            return sock
+          rescue => e
+            outer_e = e
           end
         end
 
@@ -230,11 +233,21 @@ class Request
 
       alias new open
 
-      def thru_hidden_service?(host)
-        Rails.configuration.x.access_to_hidden_service && /\.(onion|i2p)$/.match(host)
+      def check_private_address(address)
+        raise Mastodon::HostValidationError if PrivateAddressCheck.private_address?(IPAddr.new(address.to_s))
+      end
+    end
+  end
+
+  class ProxySocket < Socket
+    class << self
+      def check_private_address(_address)
+        # Accept connections to private addresses as HTTP proxies will usually
+        # be on local addresses
+        nil
       end
     end
   end
 
-  private_constant :ClientLimit, :Socket
+  private_constant :ClientLimit, :Socket, :ProxySocket
 end