SOCKS5 Hostname Resolution in Go's HTTP Client
Understand why socks5 and socks5h do not select different DNS modes in Go's standard HTTP transport.
In Go 1.27.3's standard HTTP transport, socks5 and socks5h do the same destination-name handling. A hostname target is sent as a hostname to the proxy. Switching those schemes does not toggle local versus remote DNS as it does in curl.
package main
import (
"fmt"
"log"
"net/http"
"net/url"
"time"
)
func main() {
proxyURL, err := url.Parse("socks5://203.0.113.10:1080")
if err != nil {
log.Fatal(err)
}
transport := http.DefaultTransport.(*http.Transport).Clone()
transport.Proxy = http.ProxyURL(proxyURL)
defer transport.CloseIdleConnections()
client := &http.Client{
Transport: transport,
Timeout: 15 * time.Second,
}
response, err := client.Get("https://example.com/")
if err != nil {
log.Fatal(err)
}
defer response.Body.Close()
fmt.Println(response.StatusCode)
}
Replace the documentation address with your SOCKS5 endpoint; candidates can be browsed in the SOCKS5 proxy list. The example uses net/http's own transport; another Go library can implement different behavior.
There are still two names to distinguish. A numeric proxy address needs no proxy-host lookup; a named proxy must be found locally before a SOCKS request can be sent. A numeric destination has no target name to resolve and cannot demonstrate hostname handling. To inspect the actual SOCKS choice, check whether the destination field carries a name or address.
The standard transport supports http, https, socks5 and socks5h proxy schemes. A generic SOCKS label does not establish SOCKS5 support at an endpoint. This example sends HTTP over TCP and tests neither other SOCKS commands nor UDP relaying.