Q: TCP connection over Tor in Golang Is it possible to initiate a TCP connection over the tor network in go? I've looked around but haven't found a mention of it.
If not, is there something similar to TCP - like websockets - that can be used instead?
Note: There's no source code for me to post at the moment since there isn't any yet. This is simply research beforehand.

A: A tor node acts as a SOCKS proxy on port 9050. Go support for the SOCKS5 protocol lives in package golang.org/x/net/proxy:
import "golang.org/x/net/proxy"

In order to make connections through tor, you first need to create a new Dialer that goes through the local SOCKS5 proxy:
dialer, err := proxy.SOCKS5("tcp", "127.0.0.1:9050", nil, nil)
if err != nil {
    log.Fatal(err)
}

To use this dialer, you just call dialer.Dial instead of net.Dial:
conn, err := dialer.Dial("tcp", "stackoverflow.com:80")
if err != nil {
    log.Fatal(err)
}
defer conn.Close()


A: the most portable way to achieve this is to use the wrapper wrote by Chad Retz
It will embed tor required assets into your binary. So that you can distribute it and ensure your app goes through tor.
In that scenario the end user does not need to install TBB or anything else other than your app.
Though to be honest, it does not include automatic updates of the tor engine, so this is something to perform on your end to ensure top security.
package main

import (
    "context"
    "fmt"
    "log"
    "net/http"
    "time"

    "github.com/cretz/bine/tor"
)

func main() {
    // Start tor with default config (can set start conf's DebugWriter to os.Stdout for debug logs)
    fmt.Println("Starting and registering onion service, please wait a couple of minutes...")
    t, err := tor.Start(nil, nil)
    if err != nil {
        log.Panicf("Unable to start Tor: %v", err)
    }
    defer t.Close()
    // Wait at most a few minutes to publish the service
    listenCtx, listenCancel := context.WithTimeout(context.Background(), 3*time.Minute)
    defer listenCancel()
    // Create a v3 onion service to listen on any port but show as 80
    onion, err := t.Listen(listenCtx, &tor.ListenConf{Version3: true, RemotePorts: []int{80}})
    if err != nil {
        log.Panicf("Unable to create onion service: %v", err)
    }
    defer onion.Close()
    fmt.Printf("Open Tor browser and navigate to http://%v.onion\n", onion.ID)
    fmt.Println("Press enter to exit")
    // Serve the current folder from HTTP
    errCh := make(chan error, 1)
    go func() { errCh <- http.Serve(onion, http.FileServer(http.Dir("."))) }()
    // End when enter is pressed
    go func() {
        fmt.Scanln()
        errCh <- nil
    }()
    if err = <-errCh; err != nil {
        log.Panicf("Failed serving: %v", err)
    }
}


A: There are three ways to instruct a client to use a proxy:

*

*Set the HTTP_PROXY environment variable:

export HTTP_PROXY="http://ProxyIP:ProxyPort"

HTTP_PROXY environment variable will be used as the proxy URL for HTTP requests and HTTPS requests, unless overridden by HTTPS_PROXY or NO_PROXY
In tor use case it should look like this (when running tor on localhost):
export HTTP_PROXY="socks5://127.0.0.1:9050"



*Explicitly instructing the HTTP client to use a proxy. Here's an example in Golang:

proxy, _ := url.Parse("http://ProxyIP:ProxyPort") 
httpClient := &http.Client{Transport: &http.Transport{Proxy: http.ProxyURL(proxy)}}



*Golang also offers the default transport option as part of the "net/http" package. This setting instructs the entire program (including the default HTTP client) to use the proxy:

proxy, _ := url.Parse("http://ProxyIP:ProxyPort") 
http.DefaultTransport = &http.Client{Transport: &http.Transport{Proxy: http.ProxyURL(proxy)}}

You can find example of go HTTP client using proxy here.
Also, you can read about how to run tor proxy inside a Docker container, how to run it as part of Kubernetes as an egress gateway here.
