Agocs.org

Helluva software engineer

Proxying Go AWS requests through a SOCKS5 proxy

I’m about to install a server on a ship. The server is going to write data to AWS S3. Unfortunately, the ship’s firewall can only whitelist by IP address, and AWS has about 10,000 IP addresses it might use. The solution we came up with is to proxy the calls to S3 through a SOCKS5 proxy that’s running over an SSH tunnel.

Creating a SOCKS5 proxy

We’re terminating this proxy/SSH tunnel with an EC2 instance that’s sitting on the public Internet. Let’s say that IP address is 30.40.50.60. To create the tunnel, we run the command:

$ ssh -nNT -D 8123 user@30.40.50.60  

I’ve left out a few extra options that make life with satellite internet more bearable, but that’s about it. We’re binding localhost:8123 to this SOCKS5 proxy. Now we need to make Go send traffic through it.

Creating a custom dialer

In order to use the proxy, we can’t just start throwing HTTP traffic at it (I know… I spent a day trying that). We have to instruct Go to perform the TCP dialing through this proxy. Luckily, there’s a "golang.org/x/net/proxy" package that helps us with that.

	dialer, err := proxy.SOCKS5("tcp", "localhost:8123", nil, proxy.Direct)
	if err != nil {
		log.Println(err)
		os.Exit(1)
	}

Now we hand that Dialer to a Transport struct, and stuff that into an HTTP client. This is all in the standard net/http package.

	tr := &http.Transport{
		Dial: dialer.Dial,
	}

	client := &http.Client{Transport: tr}

We can use that client the same way as we’d use the default net/http client:

resp, err := client.Get("https://example.org")

Using this with AWS S3

We can also hand this custom client to our AWS S3 service:

	dialer, err := proxy.SOCKS5("tcp", "localhost:8123", nil, proxy.Direct)
	if err != nil {
		log.Println(err)
		os.Exit(1)
	}

	tr := &http.Transport{
		Dial: dialer.Dial,
	}

	client := &http.Client{Transport: tr}

	sess := session.Must(session.NewSession())
	sess.Config.HTTPClient = client
	s3svc := s3.New(sess)

Now, every s3svc.PutObject() or s3svc.GetObject we run will be tunneled through this SOCKS5 proxy!


Share