The Bolg

Back to coding blogs 🧏🏾‍♂️

Recently got into proxying requests and socks5, so I started out looking at how we can do that simply with io.Copy and standard go library http server

package main

import (
	"io"
	"log"
	"maps"
	"net/http"
)

func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		// Get target URL from query parameter
		targetURL := r.URL.Query().Get("url")
		if targetURL == "" {
			http.Error(w, "url parameter required", http.StatusBadRequest)
			return
		}

		// Make the request
		resp, err := http.Get(targetURL)
		if err != nil {
			http.Error(w, err.Error(), http.StatusBadGateway)
			return
		}
		defer resp.Body.Close()

		// Copy headers
		maps.Copy(w.Header(), resp.Header)

		// Copy status code
		w.WriteHeader(resp.StatusCode)

		// Stream the body
		io.Copy(w, resp.Body)
	})

	log.Printf("Starting proxy server on :8080")
	log.Fatal(http.ListenAndServe(":8080", nil))
}

What this code essentially does is, accept incoming requests, and then do another HTTP GET to the url specified in the initial request

Now why would we want to do that? Well if our server is running in another country, and we make requests to this server, our request will look like it came from wherever the server is

To test this out, i deployed the exact same server above to Google Cloud Run, and its quite cool

curl 'https://helloworld-218563108188.asia-northeast1.run.app/?url=https://ipinfo.io/json'
{
  "ip": "34.34.226.69",
  "city": "Tokyo",
  "region": "Tokyo",
  "country": "JP",
  "loc": "35.6895,139.6917",
  "org": "AS396982 Google LLC",
  "postal": "101-8656",
  "timezone": "Asia/Tokyo",
  "readme": "https://ipinfo.io/missingauth"
}

In future posts, I will explore a more generic way of proxying TCP connections, and will eventually write on socks5 protocol. The endgoal might be implementing a simple VPN using go and socks5