From 77568915102c01fa69078764359421b19c7e0764 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Thu, 26 Apr 2018 10:23:21 -0400 Subject: [PATCH] support socks proxy in peer url and decouple explicit tor/i2p routing --- src/yggdrasil/core.go | 1 - src/yggdrasil/debug.go | 52 ++++++++++++++++++++++++++++++++++++++++++ src/yggdrasil/dial.go | 49 --------------------------------------- src/yggdrasil/tcp.go | 22 +++++++++++++++++- yggdrasil.go | 11 +-------- 5 files changed, 74 insertions(+), 61 deletions(-) diff --git a/src/yggdrasil/core.go b/src/yggdrasil/core.go index d68a601f..be0c6aec 100644 --- a/src/yggdrasil/core.go +++ b/src/yggdrasil/core.go @@ -19,7 +19,6 @@ type Core struct { tun tunDevice admin admin searches searches - Dialer Dialer tcp *tcpInterface udp *udpInterface log *log.Logger diff --git a/src/yggdrasil/debug.go b/src/yggdrasil/debug.go index d358bc62..dcc2581f 100644 --- a/src/yggdrasil/debug.go +++ b/src/yggdrasil/debug.go @@ -8,9 +8,13 @@ package yggdrasil import _ "golang.org/x/net/ipv6" // TODO put this somewhere better +import "golang.org/x/net/proxy" + import "fmt" import "net" +import "net/url" import "log" +import "strings" import "regexp" // Core @@ -307,6 +311,54 @@ func (c *Core) DEBUG_maybeSendUDPKeys(saddr string) { //////////////////////////////////////////////////////////////////////////////// +func (c *Core) DEBUG_addPeer(addr string) { + u, err := url.Parse(addr) + if err != nil { + panic(err) + } + if len(u.Opaque) == 0 { + switch strings.ToLower(u.Scheme) { + case "tcp": + c.DEBUG_addTCPConn(u.Host) + case "udp": + c.DEBUG_maybeSendUDPKeys(u.Host) + case "socks": + c.DEBUG_addSOCKSConn(u.Host, u.Path[1:]) + default: + panic("invalid peer: " + addr) + } + } else { + // no url scheme provided + addr = strings.ToLower(addr) + if strings.HasPrefix(addr, "udp:") { + c.DEBUG_maybeSendUDPKeys(addr[4:]) + } else { + if strings.HasPrefix(addr, "tcp:") { + addr = addr[4:] + } + c.DEBUG_addTCPConn(addr) + } + } +} + +func (c *Core) DEBUG_addSOCKSConn(socksaddr, peeraddr string) { + go func() { + dialer, err := proxy.SOCKS5("tcp", socksaddr, nil, proxy.Direct) + if err == nil { + conn, err := dialer.Dial("tcp", peeraddr) + if err == nil { + c.tcp.callWithConn(&wrappedConn{ + c: conn, + raddr: &wrappedAddr{ + network: "tcp", + addr: peeraddr, + }, + }) + } + } + }() +} + //* func (c *Core) DEBUG_setupAndStartGlobalTCPInterface(addrport string) { iface := tcpInterface{} diff --git a/src/yggdrasil/dial.go b/src/yggdrasil/dial.go index 5269c165..7aec4192 100644 --- a/src/yggdrasil/dial.go +++ b/src/yggdrasil/dial.go @@ -1,23 +1,10 @@ package yggdrasil import ( - "errors" - "golang.org/x/net/proxy" "net" - "strings" "time" - "yggdrasil/config" ) -type Dialer = proxy.Dialer - -// muxedDialer implements proxy.Dialer (aka Dialer) -type muxedDialer struct { - conf config.NetConfig - tor Dialer - direct Dialer -} - // wrappedConn implements net.Conn type wrappedConn struct { c net.Conn @@ -69,39 +56,3 @@ func (c *wrappedConn) LocalAddr() net.Addr { func (c *wrappedConn) RemoteAddr() net.Addr { return c.raddr } - -func (d *muxedDialer) Dial(network, addr string) (net.Conn, error) { - host, _, _ := net.SplitHostPort(addr) - if d.conf.Tor.UseForAll || strings.HasSuffix(host, ".onion") { - if !d.conf.Tor.Enabled { - return nil, errors.New("tor not enabled") - } - c, err := d.tor.Dial(network, addr) - if err == nil { - c = &wrappedConn{ - c: c, - raddr: &wrappedAddr{ - network: network, - addr: addr, - }, - } - } - return c, err - } else { - return d.direct.Dial(network, addr) - } -} - -// NewDialer creates a Dialer from a NetConfig -func NewDialer(c config.NetConfig) Dialer { - if c.Tor.Enabled { - tor, _ := proxy.SOCKS5("tcp", c.Tor.SocksAddr, nil, proxy.Direct) - return &muxedDialer{ - conf: c, - tor: tor, - direct: proxy.Direct, - } - } else { - return proxy.Direct - } -} diff --git a/src/yggdrasil/tcp.go b/src/yggdrasil/tcp.go index 563178f9..d84dd345 100644 --- a/src/yggdrasil/tcp.go +++ b/src/yggdrasil/tcp.go @@ -66,6 +66,26 @@ func (iface *tcpInterface) listener() { } } +func (iface *tcpInterface) callWithConn(conn net.Conn) { + go func() { + raddr := conn.RemoteAddr().String() + iface.mutex.Lock() + _, isIn := iface.calls[raddr] + iface.mutex.Unlock() + if !isIn { + iface.mutex.Lock() + iface.calls[raddr] = struct{}{} + iface.mutex.Unlock() + defer func() { + iface.mutex.Lock() + delete(iface.calls, raddr) + iface.mutex.Unlock() + }() + iface.handler(conn) + } + }() +} + func (iface *tcpInterface) call(saddr string) { go func() { quit := false @@ -82,7 +102,7 @@ func (iface *tcpInterface) call(saddr string) { } iface.mutex.Unlock() if !quit { - conn, err := iface.core.Dialer.Dial("tcp", saddr) + conn, err := net.Dial("tcp", saddr) if err != nil { return } diff --git a/yggdrasil.go b/yggdrasil.go index 85328fc0..15f60ac7 100644 --- a/yggdrasil.go +++ b/yggdrasil.go @@ -59,8 +59,6 @@ func (n *node) init(cfg *nodeConfig, logger *log.Logger) { } n.core.DEBUG_setIfceExpr(ifceExpr) - n.core.Dialer = yggdrasil.NewDialer(cfg.Net) - logger.Println("Starting interface...") n.core.DEBUG_setupAndStartGlobalTCPInterface(cfg.Listen) // Listen for peers on TCP n.core.DEBUG_setupAndStartGlobalUDPInterface(cfg.Listen) // Also listen on UDP, TODO allow separate configuration for ip/port to listen on each of these @@ -74,14 +72,7 @@ func (n *node) init(cfg *nodeConfig, logger *log.Logger) { } for { for _, p := range cfg.Peers { - switch { - case len(p) >= 4 && p[:4] == "udp:": - n.core.DEBUG_maybeSendUDPKeys(p[4:]) - case len(p) >= 4 && p[:4] == "tcp:": - n.core.DEBUG_addTCPConn(p[4:]) - default: - n.core.DEBUG_addTCPConn(p) - } + n.core.DEBUG_addPeer(p) time.Sleep(time.Second) } time.Sleep(time.Minute)