@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?
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
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