Merge pull request #68 from majestrate/tor-auto

Tor socks proxy support
This commit is contained in:
Arceliar 2018-04-26 20:37:03 -05:00 committed by GitHub
commit 76a5d69211
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 204 additions and 63 deletions

View File

@ -0,0 +1,24 @@
package config
// NodeConfig defines all configuration values needed to run a signle yggdrasil node
type NodeConfig struct {
Listen string
AdminListen string
Peers []string
BoxPub string
BoxPriv string
SigPub string
SigPriv string
Multicast bool
LinkLocal string
IfName string
IfTAPMode bool
IfMTU int
Net NetConfig
}
// NetConfig defines network/proxy related configuration values
type NetConfig struct {
Tor TorConfig
I2P I2PConfig
}

View File

@ -0,0 +1,8 @@
package config
// I2PConfig is the configuration structure for i2p related configuration
type I2PConfig struct {
Keyfile string // private key file or empty string for ephemeral keys
Addr string // address of i2p api connector
Enabled bool
}

View File

@ -0,0 +1,8 @@
package config
// TorConfig is the configuration structure for Tor Proxy related values
type TorConfig struct {
OnionKeyfile string // hidden service private key for ADD_ONION (currently unimplemented)
ControlAddr string // tor control port address
Enabled bool
}

View File

@ -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{}

58
src/yggdrasil/dial.go Normal file
View File

@ -0,0 +1,58 @@
package yggdrasil
import (
"net"
"time"
)
// wrappedConn implements net.Conn
type wrappedConn struct {
c net.Conn
raddr net.Addr
}
// wrappedAddr implements net.Addr
type wrappedAddr struct {
network string
addr string
}
func (a *wrappedAddr) Network() string {
return a.network
}
func (a *wrappedAddr) String() string {
return a.addr
}
func (c *wrappedConn) Write(data []byte) (int, error) {
return c.c.Write(data)
}
func (c *wrappedConn) Read(data []byte) (int, error) {
return c.c.Read(data)
}
func (c *wrappedConn) SetDeadline(t time.Time) error {
return c.c.SetDeadline(t)
}
func (c *wrappedConn) SetReadDeadline(t time.Time) error {
return c.c.SetReadDeadline(t)
}
func (c *wrappedConn) SetWriteDeadline(t time.Time) error {
return c.c.SetWriteDeadline(t)
}
func (c *wrappedConn) Close() error {
return c.c.Close()
}
func (c *wrappedConn) LocalAddr() net.Addr {
return c.c.LocalAddr()
}
func (c *wrappedConn) RemoteAddr() net.Addr {
return c.raddr
}

View File

@ -19,9 +19,17 @@ import "bufio"
const tcp_msgSize = 2048 + 65535 // TODO figure out what makes sense
// wrapper function for non tcp/ip connections
func setNoDelay(c net.Conn, delay bool) {
tcp, ok := c.(*net.TCPConn)
if ok {
tcp.SetNoDelay(delay)
}
}
type tcpInterface struct {
core *Core
serv *net.TCPListener
serv net.Listener
mutex sync.Mutex // Protecting the below
calls map[string]struct{}
conns map[tcpInfo](chan struct{})
@ -30,30 +38,27 @@ type tcpInterface struct {
type tcpInfo struct {
box boxPubKey
sig sigPubKey
localAddr string // net.IPAddr.String(), not TCPAddr, don't care about port
localAddr string
remoteAddr string
}
func (iface *tcpInterface) init(core *Core, addr string) {
func (iface *tcpInterface) init(core *Core, addr string) (err error) {
iface.core = core
tcpAddr, err := net.ResolveTCPAddr("tcp", addr)
if err != nil {
panic(err)
iface.serv, err = net.Listen("tcp", addr)
if err == nil {
iface.calls = make(map[string]struct{})
iface.conns = make(map[tcpInfo](chan struct{}))
go iface.listener()
}
iface.serv, err = net.ListenTCP("tcp", tcpAddr)
if err != nil {
panic(err)
}
iface.calls = make(map[string]struct{})
iface.conns = make(map[tcpInfo](chan struct{}))
go iface.listener()
return
}
func (iface *tcpInterface) listener() {
defer iface.serv.Close()
iface.core.log.Println("Listening for TCP on:", iface.serv.Addr().String())
for {
sock, err := iface.serv.AcceptTCP()
sock, err := iface.serv.Accept()
if err != nil {
panic(err)
}
@ -61,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
@ -77,17 +102,16 @@ func (iface *tcpInterface) call(saddr string) {
}
iface.mutex.Unlock()
if !quit {
conn, err := net.DialTimeout("tcp", saddr, 6*time.Second)
conn, err := net.Dial("tcp", saddr)
if err != nil {
return
}
sock := conn.(*net.TCPConn)
iface.handler(sock)
iface.handler(conn)
}
}()
}
func (iface *tcpInterface) handler(sock *net.TCPConn) {
func (iface *tcpInterface) handler(sock net.Conn) {
defer sock.Close()
// Get our keys
keys := []byte{}
@ -127,18 +151,8 @@ func (iface *tcpInterface) handler(sock *net.TCPConn) {
return
}
// Check if we already have a connection to this node, close and block if yes
local := sock.LocalAddr().(*net.TCPAddr)
laddr := net.IPAddr{
IP: local.IP,
Zone: local.Zone,
}
info.localAddr = laddr.String()
remote := sock.RemoteAddr().(*net.TCPAddr)
raddr := net.IPAddr{
IP: remote.IP,
Zone: remote.Zone,
}
info.remoteAddr = raddr.String()
info.localAddr, _, _ = net.SplitHostPort(sock.LocalAddr().String())
info.remoteAddr, _, _ = net.SplitHostPort(sock.RemoteAddr().String())
iface.mutex.Lock()
if blockChan, isIn := iface.conns[info]; isIn {
iface.mutex.Unlock()
@ -224,7 +238,7 @@ func (iface *tcpInterface) handler(sock *net.TCPConn) {
util_putBytes(msg)
}
}
sock.SetNoDelay(true)
setNoDelay(sock, true)
go p.linkLoop(linkIn)
defer func() {
// Put all of our cleanup here...
@ -239,7 +253,7 @@ func (iface *tcpInterface) handler(sock *net.TCPConn) {
p.core.peers.mutex.Unlock()
close(linkIn)
}()
them := sock.RemoteAddr().(*net.TCPAddr)
them, _, _ := net.SplitHostPort(sock.RemoteAddr().String())
themNodeID := getNodeID(&info.box)
themAddr := address_addrForNodeID(themNodeID)
themAddrString := net.IP(themAddr[:]).String()
@ -250,7 +264,7 @@ func (iface *tcpInterface) handler(sock *net.TCPConn) {
return
}
func (iface *tcpInterface) reader(sock *net.TCPConn, in func([]byte)) {
func (iface *tcpInterface) reader(sock net.Conn, in func([]byte)) {
bs := make([]byte, 2*tcp_msgSize)
frag := bs[:0]
for {

View File

@ -21,31 +21,13 @@ import "runtime"
import "golang.org/x/net/ipv6"
import . "yggdrasil"
import "yggdrasil"
import "yggdrasil/config"
import "github.com/kardianos/minwinsvc"
/**
* This is a very crude wrapper around src/yggdrasil
* It can generate a new config (--genconf)
* It can read a config from stdin (--useconf)
* It can run with an automatic config (--autoconf)
*/
type nodeConfig struct {
Listen string
AdminListen string
Peers []string
BoxPub string
BoxPriv string
SigPub string
SigPriv string
Multicast bool
LinkLocal string
IfName string
IfTAPMode bool
IfMTU int
}
type nodeConfig = config.NodeConfig
type Core = yggdrasil.Core
type node struct {
core Core
@ -76,6 +58,7 @@ func (n *node) init(cfg *nodeConfig, logger *log.Logger) {
panic(err)
}
n.core.DEBUG_setIfceExpr(ifceExpr)
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
@ -89,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)
@ -126,6 +102,7 @@ func generateConfig(isAutoconf bool) *nodeConfig {
cfg.IfName = core.DEBUG_GetTUNDefaultIfName()
cfg.IfMTU = core.DEBUG_GetTUNDefaultIfMTU()
cfg.IfTAPMode = core.DEBUG_GetTUNDefaultIfTAPMode()
return &cfg
}