Golang 中通过 Tor 的 TCP 连接

TCP connection over Tor in Golang

在go中是否可以通过tor网络发起TCP连接?我环顾四周,但没有找到提及它的地方。

如果没有,是否可以使用类似于 TCP 的东西(例如 websockets)?

注意:目前还没有 post 的源代码,因为还没有。这只是事前的研究。

Tor 节点充当端口 9050 上的 SOCKS 代理。对 SOCKS5 协议的 Go 支持存在于包 golang.org/x/net/proxy:

import "golang.org/x/net/proxy"

为了通过 tor 建立连接,您首先需要创建一个通过本地 SOCKS5 代理的新 Dialer

dialer, err := proxy.SOCKS5("tcp", "127.0.0.1:9050", nil, nil)
if err != nil {
    log.Fatal(err)
}

要使用此拨号器,您只需拨打 dialer.Dial 而不是 net.Dial:

conn, err := dialer.Dial("tcp", "whosebug.com:80")
if err != nil {
    log.Fatal(err)
}
defer conn.Close()

可以通过三种方式指示客户端使用代理:

  1. 设置HTTP_PROXY环境变量:
export HTTP_PROXY="http://ProxyIP:ProxyPort"

HTTP_PROXY 环境变量将用作 HTTP 请求和 HTTPS 请求的代理 URL,除非被 HTTPS_PROXYNO_PROXY

覆盖

tor 用例中它应该是这样的(当 运行ning tor 在本地主机上时):

export HTTP_PROXY="socks5://127.0.0.1:9050"
  1. 明确指示 HTTP 客户端使用代理。这是 Golang 中的示例:
proxy, _ := url.Parse("http://ProxyIP:ProxyPort") 
httpClient := &http.Client{Transport: &http.Transport{Proxy: http.ProxyURL(proxy)}}
  1. Golang 还提供默认传输选项作为 "net/http" 包的一部分。此设置指示整个程序(包括默认的 HTTP 客户端)使用代理:
proxy, _ := url.Parse("http://ProxyIP:ProxyPort") 
http.DefaultTransport = &http.Client{Transport: &http.Transport{Proxy: http.ProxyURL(proxy)}}

您可以找到使用代理的 go HTTP 客户端示例 here

此外,您可以阅读有关如何 运行 tor 代理在 Docker 容器内,如何 运行 它作为Kubernetes 作为出口网关 here.

实现此目的最便携的方法是使用包装器 wrote by Chad Retz

它将所需的资产嵌入到您的二进制文件中。这样您就可以分发它并确保您的应用程序通过 tor。

在那种情况下,最终用户不需要安装 TBB 或除您的应用程序以外的任何其他东西。

老实说,它不包括 tor 引擎的自动更新,因此这是您端执行的操作以确保最高安全性。

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)
    }
}