Socks 5 support
socks 5 support,
example:
# SOCKS5 proxy details
proxy_host = "98.170.57.241"
proxy_port = 4145
begin
# Make the request through SOCKS5 proxy
response = HTTP
.via_socks5(proxy_host, proxy_port)
.get("http://ifconfig.me/ip")
puts "Response status: #{response.status}"
puts "Response body: #{response.body}"
rescue => e
puts "Error: #{e.class} - #{e.message}"
puts e.backtrace
end
hey, do u need any more changes for this to get merged?
cc @tarcieri this would be very helpful
@ixti can you take a look at this one?
@sebyx07 Thank you for the PR, can you please:
- rebase it on top of main
- remove Ruby-3.4 related fixes (like those
s/inspect/to_json/) - we will deal with them later - Use constants instead of magic numbers (e.g.
ADDR_IPV4 = 0x01instead of using value directly with comment), something like:module HTTP # SOCKS5 proxy implementation class SOCKS5Proxy ADDR_IPV4 = 0x01 ADDR_DOMAIN = 0x03 ADDR_IPV6 = 0x04 IPV4_RE = /\A\d+\.\d+\.\d+\.\d+\z/ ERR_MESAGES = { 0x01 => "general SOCKS server failure", 0x02 => "connection not allowed by ruleset", 0x03 => "Network unreachable", 0x04 => "Host unreachable", 0x05 => "Connection refused", 0x06 => "TTL expired", 0x07 => "Command not supported", 0x08 => "Address type not supported" }.freeze # ... # Handle the reply code from the SOCKS5 proxy # @param [Integer] reply The reply code # @raise [HTTP::ConnectionError] if the reply indicates an error def handle_reply_code(reply) return if reply.zero? @failed_connect = true error_message = ERR_MESAGES.fetch(reply, "Unknown error (code: #{reply})") raise ConnectionError, "SOCKS5 proxy connection failed: #{error_message}" end # Skip the bound address and port in the response # @param [Integer] atyp The address type # @return [void] def skip_bound_address(atyp) case atyp when ADDR_IPV4 @socket.readpartial(6) # 4 bytes for IPv4 + 2 bytes for port when ADDR_DOMAIN domain_len = @socket.readpartial(1).unpack1("C") @socket.readpartial(domain_len + 2) # domain length + 2 bytes for port when ADDR_IPV6 @socket.readpartial(18) # 16 bytes for IPv6 + 2 bytes for port end end end end
Also, I've noticed that skip_bound_address handles IPV6, but format_address does not, is that intentional?
i'm busy with my work right now, you can fork my code and do the required updates, i have my own fork self hosted http gem anyway, i don't like to rely on others for mergex/fixes etc
i just shared it with you in case you want to add it to the public gem
@sebyx07 thank you!