Add c.Dialer(auth) which returns a net.proxy.
A bit more involved than David S' version, since it queries the control port for an appropriate SOCKS listener. This makes it easier to use.
This commit is contained in:
parent
f6128d70b6
commit
ae6d97af37
|
@ -0,0 +1,54 @@
|
||||||
|
// dialer.go - Tor backed proxy.Dialer.
|
||||||
|
//
|
||||||
|
// To the extent possible under law, Yawning Angel waived all copyright
|
||||||
|
// and related or neighboring rights to bulb, using the creative
|
||||||
|
// commons "cc0" public domain dedication. See LICENSE or
|
||||||
|
// <http://creativecommons.org/publicdomain/zero/1.0/> for full details.
|
||||||
|
|
||||||
|
package bulb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"golang.org/x/net/proxy"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Dialer returns a proxy.Dialer for the given Tor instance.
|
||||||
|
func (c *Conn) Dialer(auth *proxy.Auth) (proxy.Dialer, error) {
|
||||||
|
const (
|
||||||
|
cmdGetInfo = "GETINFO"
|
||||||
|
socksListeners = "net/listeners/socks"
|
||||||
|
unixPrefix = "unix:"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Query for the SOCKS listeners via a GETINFO request.
|
||||||
|
resp, err := c.Request("%s %s", cmdGetInfo, socksListeners)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(resp.Data) != 1 {
|
||||||
|
return nil, newProtocolError("no SOCKS listeners configured")
|
||||||
|
}
|
||||||
|
splitResp := strings.Split(resp.Data[0], " ")
|
||||||
|
if len(splitResp) < 1 {
|
||||||
|
return nil, newProtocolError("no SOCKS listeners configured")
|
||||||
|
}
|
||||||
|
|
||||||
|
// The first listener will have a "net/listeners/socks=" prefix, and all
|
||||||
|
// entries are QuotedStrings.
|
||||||
|
laddrStr := strings.TrimPrefix(splitResp[0], socksListeners+"=")
|
||||||
|
if laddrStr == splitResp[0] {
|
||||||
|
return nil, newProtocolError("failed to parse SOCKS listener")
|
||||||
|
}
|
||||||
|
laddrStr, _ = strconv.Unquote(laddrStr)
|
||||||
|
|
||||||
|
// Construct the proxyDialer.
|
||||||
|
if strings.HasPrefix(laddrStr, unixPrefix) {
|
||||||
|
unixPath := strings.TrimPrefix(laddrStr, unixPrefix)
|
||||||
|
return proxy.SOCKS5("unix", unixPath, auth, proxy.Direct)
|
||||||
|
}
|
||||||
|
|
||||||
|
return proxy.SOCKS5("tcp", laddrStr, auth, proxy.Direct)
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
// Dialer example.
|
||||||
|
//
|
||||||
|
// To the extent possible under law, Yawning Angel waived all copyright
|
||||||
|
// and related or neighboring rights to bulb, using the creative
|
||||||
|
// commons "cc0" public domain dedication. See LICENSE or
|
||||||
|
// <http://creativecommons.org/publicdomain/zero/1.0/> for full details.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/yawning/bulb"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// Connect to a running tor instance.
|
||||||
|
// * TCP: c, err := bulb.Dial("tcp4", "127.0.0.1:9051")
|
||||||
|
c, err := bulb.Dial("unix", "/var/run/tor/control")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("failed to connect to control port: %v", err)
|
||||||
|
}
|
||||||
|
defer c.Close()
|
||||||
|
|
||||||
|
// See what's really going on under the hood.
|
||||||
|
// Do not enable in production.
|
||||||
|
c.Debug(true)
|
||||||
|
|
||||||
|
// Authenticate with the control port. The password argument
|
||||||
|
// here can be "" if no password is set (CookieAuth, no auth).
|
||||||
|
if err := c.Authenticate("ExamplePassword"); err != nil {
|
||||||
|
log.Fatalf("Authentication failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get a proxy.Dialer that will use the given Tor instance for outgoing
|
||||||
|
// connections.
|
||||||
|
dialer, err := c.Dialer(nil)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to get Dialer: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try using the Dialer for something...
|
||||||
|
orTransport := &http.Transport{Dial: dialer.Dial}
|
||||||
|
orHTTPClient := &http.Client{Transport: orTransport}
|
||||||
|
resp, err := orHTTPClient.Get("https://check.torproject.org/api/ip")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed https GET: %v", err)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
body, _ := ioutil.ReadAll(resp.Body)
|
||||||
|
log.Printf("HTTPS GET via Tor: %v", resp)
|
||||||
|
log.Printf(" Body: %s\n", body)
|
||||||
|
}
|
Reference in New Issue