mirror of
https://github.com/cwinfo/yggdrasil-go.git
synced 2024-11-22 14:10:28 +00:00
Merge pull request #68 from majestrate/tor-auto
Tor socks proxy support
This commit is contained in:
commit
76a5d69211
24
src/yggdrasil/config/config.go
Normal file
24
src/yggdrasil/config/config.go
Normal 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
|
||||||
|
}
|
8
src/yggdrasil/config/i2p.go
Normal file
8
src/yggdrasil/config/i2p.go
Normal 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
|
||||||
|
}
|
8
src/yggdrasil/config/tor.go
Normal file
8
src/yggdrasil/config/tor.go
Normal 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
|
||||||
|
}
|
@ -8,9 +8,13 @@ package yggdrasil
|
|||||||
|
|
||||||
import _ "golang.org/x/net/ipv6" // TODO put this somewhere better
|
import _ "golang.org/x/net/ipv6" // TODO put this somewhere better
|
||||||
|
|
||||||
|
import "golang.org/x/net/proxy"
|
||||||
|
|
||||||
import "fmt"
|
import "fmt"
|
||||||
import "net"
|
import "net"
|
||||||
|
import "net/url"
|
||||||
import "log"
|
import "log"
|
||||||
|
import "strings"
|
||||||
import "regexp"
|
import "regexp"
|
||||||
|
|
||||||
// Core
|
// 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) {
|
func (c *Core) DEBUG_setupAndStartGlobalTCPInterface(addrport string) {
|
||||||
iface := tcpInterface{}
|
iface := tcpInterface{}
|
||||||
|
58
src/yggdrasil/dial.go
Normal file
58
src/yggdrasil/dial.go
Normal 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
|
||||||
|
}
|
@ -19,9 +19,17 @@ import "bufio"
|
|||||||
|
|
||||||
const tcp_msgSize = 2048 + 65535 // TODO figure out what makes sense
|
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 {
|
type tcpInterface struct {
|
||||||
core *Core
|
core *Core
|
||||||
serv *net.TCPListener
|
serv net.Listener
|
||||||
mutex sync.Mutex // Protecting the below
|
mutex sync.Mutex // Protecting the below
|
||||||
calls map[string]struct{}
|
calls map[string]struct{}
|
||||||
conns map[tcpInfo](chan struct{})
|
conns map[tcpInfo](chan struct{})
|
||||||
@ -30,30 +38,27 @@ type tcpInterface struct {
|
|||||||
type tcpInfo struct {
|
type tcpInfo struct {
|
||||||
box boxPubKey
|
box boxPubKey
|
||||||
sig sigPubKey
|
sig sigPubKey
|
||||||
localAddr string // net.IPAddr.String(), not TCPAddr, don't care about port
|
localAddr string
|
||||||
remoteAddr string
|
remoteAddr string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (iface *tcpInterface) init(core *Core, addr string) {
|
func (iface *tcpInterface) init(core *Core, addr string) (err error) {
|
||||||
iface.core = core
|
iface.core = core
|
||||||
tcpAddr, err := net.ResolveTCPAddr("tcp", addr)
|
|
||||||
if err != nil {
|
iface.serv, err = net.Listen("tcp", addr)
|
||||||
panic(err)
|
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)
|
return
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
iface.calls = make(map[string]struct{})
|
|
||||||
iface.conns = make(map[tcpInfo](chan struct{}))
|
|
||||||
go iface.listener()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (iface *tcpInterface) listener() {
|
func (iface *tcpInterface) listener() {
|
||||||
defer iface.serv.Close()
|
defer iface.serv.Close()
|
||||||
iface.core.log.Println("Listening for TCP on:", iface.serv.Addr().String())
|
iface.core.log.Println("Listening for TCP on:", iface.serv.Addr().String())
|
||||||
for {
|
for {
|
||||||
sock, err := iface.serv.AcceptTCP()
|
sock, err := iface.serv.Accept()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
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) {
|
func (iface *tcpInterface) call(saddr string) {
|
||||||
go func() {
|
go func() {
|
||||||
quit := false
|
quit := false
|
||||||
@ -77,17 +102,16 @@ func (iface *tcpInterface) call(saddr string) {
|
|||||||
}
|
}
|
||||||
iface.mutex.Unlock()
|
iface.mutex.Unlock()
|
||||||
if !quit {
|
if !quit {
|
||||||
conn, err := net.DialTimeout("tcp", saddr, 6*time.Second)
|
conn, err := net.Dial("tcp", saddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
sock := conn.(*net.TCPConn)
|
iface.handler(conn)
|
||||||
iface.handler(sock)
|
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (iface *tcpInterface) handler(sock *net.TCPConn) {
|
func (iface *tcpInterface) handler(sock net.Conn) {
|
||||||
defer sock.Close()
|
defer sock.Close()
|
||||||
// Get our keys
|
// Get our keys
|
||||||
keys := []byte{}
|
keys := []byte{}
|
||||||
@ -127,18 +151,8 @@ func (iface *tcpInterface) handler(sock *net.TCPConn) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Check if we already have a connection to this node, close and block if yes
|
// Check if we already have a connection to this node, close and block if yes
|
||||||
local := sock.LocalAddr().(*net.TCPAddr)
|
info.localAddr, _, _ = net.SplitHostPort(sock.LocalAddr().String())
|
||||||
laddr := net.IPAddr{
|
info.remoteAddr, _, _ = net.SplitHostPort(sock.RemoteAddr().String())
|
||||||
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()
|
|
||||||
iface.mutex.Lock()
|
iface.mutex.Lock()
|
||||||
if blockChan, isIn := iface.conns[info]; isIn {
|
if blockChan, isIn := iface.conns[info]; isIn {
|
||||||
iface.mutex.Unlock()
|
iface.mutex.Unlock()
|
||||||
@ -224,7 +238,7 @@ func (iface *tcpInterface) handler(sock *net.TCPConn) {
|
|||||||
util_putBytes(msg)
|
util_putBytes(msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sock.SetNoDelay(true)
|
setNoDelay(sock, true)
|
||||||
go p.linkLoop(linkIn)
|
go p.linkLoop(linkIn)
|
||||||
defer func() {
|
defer func() {
|
||||||
// Put all of our cleanup here...
|
// Put all of our cleanup here...
|
||||||
@ -239,7 +253,7 @@ func (iface *tcpInterface) handler(sock *net.TCPConn) {
|
|||||||
p.core.peers.mutex.Unlock()
|
p.core.peers.mutex.Unlock()
|
||||||
close(linkIn)
|
close(linkIn)
|
||||||
}()
|
}()
|
||||||
them := sock.RemoteAddr().(*net.TCPAddr)
|
them, _, _ := net.SplitHostPort(sock.RemoteAddr().String())
|
||||||
themNodeID := getNodeID(&info.box)
|
themNodeID := getNodeID(&info.box)
|
||||||
themAddr := address_addrForNodeID(themNodeID)
|
themAddr := address_addrForNodeID(themNodeID)
|
||||||
themAddrString := net.IP(themAddr[:]).String()
|
themAddrString := net.IP(themAddr[:]).String()
|
||||||
@ -250,7 +264,7 @@ func (iface *tcpInterface) handler(sock *net.TCPConn) {
|
|||||||
return
|
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)
|
bs := make([]byte, 2*tcp_msgSize)
|
||||||
frag := bs[:0]
|
frag := bs[:0]
|
||||||
for {
|
for {
|
||||||
|
37
yggdrasil.go
37
yggdrasil.go
@ -21,31 +21,13 @@ import "runtime"
|
|||||||
|
|
||||||
import "golang.org/x/net/ipv6"
|
import "golang.org/x/net/ipv6"
|
||||||
|
|
||||||
import . "yggdrasil"
|
import "yggdrasil"
|
||||||
|
import "yggdrasil/config"
|
||||||
|
|
||||||
import "github.com/kardianos/minwinsvc"
|
import "github.com/kardianos/minwinsvc"
|
||||||
|
|
||||||
/**
|
type nodeConfig = config.NodeConfig
|
||||||
* This is a very crude wrapper around src/yggdrasil
|
type Core = yggdrasil.Core
|
||||||
* 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 node struct {
|
type node struct {
|
||||||
core Core
|
core Core
|
||||||
@ -76,6 +58,7 @@ func (n *node) init(cfg *nodeConfig, logger *log.Logger) {
|
|||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
n.core.DEBUG_setIfceExpr(ifceExpr)
|
n.core.DEBUG_setIfceExpr(ifceExpr)
|
||||||
|
|
||||||
logger.Println("Starting interface...")
|
logger.Println("Starting interface...")
|
||||||
n.core.DEBUG_setupAndStartGlobalTCPInterface(cfg.Listen) // Listen for peers on TCP
|
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
|
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 {
|
||||||
for _, p := range cfg.Peers {
|
for _, p := range cfg.Peers {
|
||||||
switch {
|
n.core.DEBUG_addPeer(p)
|
||||||
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)
|
|
||||||
}
|
|
||||||
time.Sleep(time.Second)
|
time.Sleep(time.Second)
|
||||||
}
|
}
|
||||||
time.Sleep(time.Minute)
|
time.Sleep(time.Minute)
|
||||||
@ -126,6 +102,7 @@ func generateConfig(isAutoconf bool) *nodeConfig {
|
|||||||
cfg.IfName = core.DEBUG_GetTUNDefaultIfName()
|
cfg.IfName = core.DEBUG_GetTUNDefaultIfName()
|
||||||
cfg.IfMTU = core.DEBUG_GetTUNDefaultIfMTU()
|
cfg.IfMTU = core.DEBUG_GetTUNDefaultIfMTU()
|
||||||
cfg.IfTAPMode = core.DEBUG_GetTUNDefaultIfTAPMode()
|
cfg.IfTAPMode = core.DEBUG_GetTUNDefaultIfTAPMode()
|
||||||
|
|
||||||
return &cfg
|
return &cfg
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user