Skip to content

Instantly share code, notes, and snippets.

@shannonwells
Last active May 7, 2021 20:52
Show Gist options
  • Save shannonwells/a7be8752093cd74bc590 to your computer and use it in GitHub Desktop.
Save shannonwells/a7be8752093cd74bc590 to your computer and use it in GitHub Desktop.
Faraday + SOCKS
require 'rubygems'
require 'faraday'
require 'socksify'
require 'socksify/http'
require 'awesome_print'
# This is a SOCKS monkey patch for Faraday, with example use/unit test.
# Notes:
# * It is altered to work with SOCKS5 authentication.
# * net_http_class must return a Faraday::Adapter::NetHttp instance.
# * Verified as of 2020-02-24 with:
# - SOCKS5 ss5 server
# - gem faraday, '1.0'
# - gem socksify,'1.7.1', git: 'git://github.com/pirateradio/socksify-ruby.git'
# - ruby 2.6
Socksify::debug = true
class Faraday::Adapter::NetHttp
def net_http_connection(env)
if proxy = env[:request][:proxy]
ap here: "PROXY"
if proxy.scheme == 'socks'
TCPSocket.socks_username = proxy[:user] if proxy[:user]
TCPSocket.socks_password = proxy[:password] if proxy[:password]
Net::HTTP::SOCKSProxy(proxy[:uri].host, proxy[:uri].port)
else
Net::HTTP::Proxy(proxy[:uri].host, proxy[:uri].port, proxy[:uri].user, proxy[:uri].password)
end
else
Net::HTTP
end.new(env[:url].host, env[:url].port)
end
end
# Replace with your server values, obviously
uri = URI.parse('socks://186.225.157.22:8080')
# DO NOT DO THIS IN PRODUCTION, this is just for testing
SSL_OPTS = {verify: false}
connection = Faraday.new(url: "https://www.google.com",
ssl: SSL_OPTS,
proxy: uri) do |c|
c.headers[:user_agent] = "Just Some Engineer"
c.adapter :net_http
c.response :logger
end
response = connection.get
ap body: response.body
@shannonwells
Copy link
Author

Output should be something like the following:

14:21:56 Connecting to SOCKS server 99.99.99.99:1080
14:21:56 Sending username/password authentication
14:21:56 Waiting for authentication reply
14:21:56 Sending destination address
14:21:56 ["05"]
14:21:56 www.google.com
14:21:56 Waiting for SOCKS reply
14:21:56 ["05000001"]
14:21:56 Waiting for bind_addr
14:21:56 Connected to www.google.com:443 over SOCKS
I, [2014-06-06T14:21:57.343078 #63684]  INFO -- : get https://www.google.com/
D, [2014-06-06T14:21:57.343176 #63684] DEBUG -- request: User-Agent: "Just Some Engineer"
Authorization: "Basic Og=="
I, [2014-06-06T14:21:57.343438 #63684]  INFO -- Status: 200
D, [2014-06-06T14:21:57.343516 #63684] DEBUG -- response: date: "Fri, 06 Jun 2014 21:21:58 GMT"
expires: "-1"
cache-control: "private, max-age=0"
content-type: "text/html; charset=ISO-8859-1"
set-cookie: "PREF=ID=db8a55b382449275:FF=0:TM=1402089718:LM=1402089718:S=1HBLode5SQ0YLHih; expires=Sun, 05-Jun-2016 21:21:58 GMT; path=/; domain=.google.com, NID=67=pSPBh416ST4-f4xsWapAANNwzKrp1wsOr7qz_Ty1Mv-Y3VAGJuV1hj7kkWGxde6ps-hDnK-bA1Y1P8peM-aygDrXCG9a37DL80SNX_2wMYJxJ8fo_7e4VNhoU5taVcT7;         expires=Sat, 06-Dec-2014 21:21:58 GMT; path=/; domain=.google.com; HttpOnly"
p3p: "CP=\"This is not a P3P policy! See http://www.google.com/support/accounts/bin/answer.py?hl=en&answer=151657 for more info.\""
server: "gws"
x-xss-protection: "1; mode=block"
x-frame-options: "SAMEORIGIN"
alternate-protocol: "443:quic"
connection: "close"

    {
        :body => "<!doctype html><html itemscope=\"\" itemtype=\"http://schema.org/WebPage\" lang=\"en\"><head><meta content=\"Search the world's information, including webpages, images, videos and more. Google has many special features to help you find exactly what you're looking for.\"               name=\"description\"><meta content=\"noodp\" name=\"robots\"><meta content=\"/images/google_favicon_128.png\"
        itemprop=\"image\"><title>Google</title><script>(function(){\nwindow.google={kEI:\"9jCSU46CNsqHogSgm4DYBg\",getEI:function(a){for(var c;a&&(!a.getAttribute||!(c=a.getAttribute(\"eid\")));)a=a.parentNode;return
        c||google.kEI},https:function()

    [snip...]

    google.kCSI.imc=e;google.kCSI.imn=b;google.kCSI.imp=f;void
        0!==google.stt&&(google.kCSI.stt=google.stt);google.csiReport&&google.csiReport()}};window.addEventListener?window.addEventListener(\"load\",r,!1):window.attachEvent&&window.attachEvent(\"onload\",r);google.timers.load.t.prt=g=(new Date).getTime()};})();\n</script></body></html>"
    }

@Paxa
Copy link

Paxa commented Aug 28, 2014

Thanks it's useful 👍

@shannonwells
Copy link
Author

shannonwells commented May 25, 2017

Don't set SSL_VERIFY=false except as a test! This leaves you vulnerable to Man-in-the-middle attacks.

@windy
Copy link

windy commented Feb 21, 2020

Now at faraday1.7 version, proxy[:socks] will throw an error, instead, use this code:

proxy.scheme == 'sock5'

@shannonwells
Copy link
Author

shannonwells commented Feb 21, 2020

Now at faraday1.7 version, proxy[:socks] will throw an error, instead, use this code:

proxy.scheme == 'sock5'

NB:
faraday is at 1.0, it's socksify that's 1.7. I have updated and verified the gist. That said, there is an approved PR in Faraday to support socks [Edit May 2021, which is still blocked due to a linter error??]:
lostisland/faraday#992

@a0s
Copy link

a0s commented Mar 16, 2021

if proxy.scheme == 'socks5' || proxy.scheme == 'socks4' works due https://github.com/pirateradio/socksify-ruby/blob/master/lib/socksify.rb#L97

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment