This commit is contained in:
Arceliar 2018-04-28 12:02:58 -05:00
commit 44cd1f0cda
7 changed files with 201 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/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,51 @@ func (c *Core) DEBUG_maybeSendUDPKeys(saddr string) {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
func (c *Core) DEBUG_addPeer(addr string) {
u, err := url.Parse(addr)
if err == nil {
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
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 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.serv, err = net.ListenTCP("tcp", tcpAddr)
if err != nil {
panic(err)
}
iface.calls = make(map[string]struct{}) iface.calls = make(map[string]struct{})
iface.conns = make(map[tcpInfo](chan struct{})) iface.conns = make(map[tcpInfo](chan struct{}))
go iface.listener() go iface.listener()
}
return
} }
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 {

View File

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