This commit is contained in:
Neil Alexander 2018-05-27 22:13:37 +01:00
parent 707e23d392
commit 4c115de633
No known key found for this signature in database
GPG key ID: A02A2019A2BB0944
9 changed files with 363 additions and 108 deletions

View file

@ -213,7 +213,11 @@ func (a *admin) init(c *Core, listenaddr string) {
}, errors.New("Failed to remove allowed box pub key")
}
})
}
func (a *admin) start() error {
go a.listen()
return nil
}
func (a *admin) listen() {
@ -356,11 +360,11 @@ func (a *admin) addPeer(addr string) error {
if err == nil {
switch strings.ToLower(u.Scheme) {
case "tcp":
a.core.DEBUG_addTCPConn(u.Host)
a.core.tcp.connect(u.Host)
case "udp":
a.core.DEBUG_maybeSendUDPKeys(u.Host)
a.core.udp.connect(u.Host)
case "socks":
a.core.DEBUG_addSOCKSConn(u.Host, u.Path[1:])
a.core.tcp.connectSOCKS(u.Host, u.Path[1:])
default:
return errors.New("invalid peer: " + addr)
}
@ -368,13 +372,13 @@ func (a *admin) addPeer(addr string) error {
// no url scheme provided
addr = strings.ToLower(addr)
if strings.HasPrefix(addr, "udp:") {
a.core.DEBUG_maybeSendUDPKeys(addr[4:])
a.core.udp.connect(addr[4:])
return nil
} else {
if strings.HasPrefix(addr, "tcp:") {
addr = addr[4:]
}
a.core.DEBUG_addTCPConn(addr)
a.core.tcp.connect(addr)
return nil
}
return errors.New("invalid peer: " + addr)
@ -421,13 +425,10 @@ func (a *admin) startTunWithMTU(ifname string, iftapmode bool, ifmtu int) error
func (a *admin) getData_getSelf() *admin_nodeInfo {
table := a.core.switchTable.table.Load().(lookupTable)
addr := (*a.core.GetAddress())[:]
subnet := (*a.core.GetSubnet())[:]
subnet = append(subnet, 0, 0, 0, 0, 0, 0, 0, 0)
coords := table.self.getCoords()
self := admin_nodeInfo{
{"ip", net.IP(addr[:]).String()},
{"subnet", fmt.Sprintf("%s/64", net.IP(subnet[:]).String())},
{"ip", a.core.GetAddress().String()},
{"subnet", a.core.GetSubnet().String()},
{"coords", fmt.Sprint(coords)},
}
return &self

View file

@ -3,7 +3,13 @@ package yggdrasil
import "io/ioutil"
import "log"
import "regexp"
import "net"
import "fmt"
import "encoding/hex"
import "yggdrasil/config"
// The Core object represents the Yggdrasil node. You should create a Core
// object for each Yggdrasil node you plan to run.
type Core struct {
// This is the main data structure that holds everything else for a node
boxPub boxPubKey
@ -26,8 +32,9 @@ type Core struct {
ifceExpr []*regexp.Regexp // the zone of link-local IPv6 peers must match this
}
// This function is only called by the simulator to set up a node with random
// keys. It should not be used and may be removed in the future.
func (c *Core) Init() {
// Only called by the simulator, to set up nodes with random keys
bpub, bpriv := newBoxKeys()
spub, spriv := newSigKeys()
c.init(bpub, bpriv, spub, spriv)
@ -42,7 +49,9 @@ func (c *Core) init(bpub *boxPubKey,
// Start launches goroutines that depend on structs being set up
// This is pretty much required to completely avoid race conditions
util_initByteStore()
c.log = log.New(ioutil.Discard, "", 0)
if c.log == nil {
c.log = log.New(ioutil.Discard, "", 0)
}
c.boxPub, c.boxPriv = *bpub, *bpriv
c.sigPub, c.sigPriv = *spub, *spriv
c.admin.core = c
@ -57,18 +66,176 @@ func (c *Core) init(bpub *boxPubKey,
c.tun.init(c)
}
// Starts up Yggdrasil using the provided NodeConfig, and outputs debug logging
// through the provided log.Logger. The started stack will include TCP and UDP
// sockets, a multicast discovery socket, an admin socket, router, switch and
// DHT node.
func (c *Core) Start(nc *config.NodeConfig, log *log.Logger) error {
c.log = log
c.log.Println("Starting up...")
var boxPub boxPubKey
var boxPriv boxPrivKey
var sigPub sigPubKey
var sigPriv sigPrivKey
boxPubHex, err := hex.DecodeString(nc.EncryptionPublicKey)
if err != nil {
return err
}
boxPrivHex, err := hex.DecodeString(nc.EncryptionPrivateKey)
if err != nil {
return err
}
sigPubHex, err := hex.DecodeString(nc.SigningPublicKey)
if err != nil {
return err
}
sigPrivHex, err := hex.DecodeString(nc.SigningPrivateKey)
if err != nil {
return err
}
copy(boxPub[:], boxPubHex)
copy(boxPriv[:], boxPrivHex)
copy(sigPub[:], sigPubHex)
copy(sigPriv[:], sigPrivHex)
c.init(&boxPub, &boxPriv, &sigPub, &sigPriv)
c.admin.init(c, nc.AdminListen)
if err := c.tcp.init(c, nc.Listen); err != nil {
c.log.Println("Failed to start TCP interface")
return err
}
if err := c.udp.init(c, nc.Listen); err != nil {
c.log.Println("Failed to start UDP interface")
return err
}
if err := c.router.start(); err != nil {
c.log.Println("Failed to start router")
return err
}
if err := c.switchTable.start(); err != nil {
c.log.Println("Failed to start switch table ticker")
return err
}
ip := net.IP(c.router.addr[:]).String()
if err := c.tun.setup(nc.IfName, nc.IfTAPMode, fmt.Sprintf("%s/8", ip), nc.IfMTU); err != nil {
c.log.Println("Failed to start TUN/TAP")
return err
}
if err := c.admin.start(); err != nil {
c.log.Println("Failed to start admin socket")
return err
}
if err := c.multicast.start(); err != nil {
c.log.Println("Failed to start multicast interface")
return err
}
c.log.Println("Startup complete")
return nil
}
// Stops the Yggdrasil node.
func (c *Core) Stop() {
c.log.Println("Stopping...")
c.tun.close()
}
// Generates a new encryption keypair. The encryption keys are used to
// encrypt traffic and to derive the IPv6 address/subnet of the node.
func (c *Core) NewEncryptionKeys() (*boxPubKey, *boxPrivKey) {
return newBoxKeys()
}
// Generates a new signing keypair. The signing keys are used to derive the
// structure of the spanning tree.
func (c *Core) NewSigningKeys() (*sigPubKey, *sigPrivKey) {
return newSigKeys()
}
// Gets the node ID.
func (c *Core) GetNodeID() *NodeID {
return getNodeID(&c.boxPub)
}
// Gets the tree ID.
func (c *Core) GetTreeID() *TreeID {
return getTreeID(&c.sigPub)
}
func (c *Core) GetAddress() *address {
return address_addrForNodeID(c.GetNodeID())
// Gets the IPv6 address of the Yggdrasil node. This is always a /128.
func (c *Core) GetAddress() *net.IP {
address := net.IP(address_addrForNodeID(c.GetNodeID())[:])
return &address
}
func (c *Core) GetSubnet() *subnet {
return address_subnetForNodeID(c.GetNodeID())
// Gets the routed IPv6 subnet of the Yggdrasil node. This is always a /64.
func (c *Core) GetSubnet() *net.IPNet {
subnet := address_subnetForNodeID(c.GetNodeID())[:]
subnet = append(subnet, 0, 0, 0, 0, 0, 0, 0, 0)
return &net.IPNet{ IP: subnet, Mask: net.CIDRMask(64, 128) }
}
// Sets the output logger of the Yggdrasil node after startup. This may be
// useful if you want to redirect the output later.
func (c *Core) SetLogger(log *log.Logger) {
c.log = log
}
// Adds a peer. This should be specified in the peer URI format, i.e.
// tcp://a.b.c.d:e, udp://a.b.c.d:e, socks://a.b.c.d:e/f.g.h.i:j
func (c *Core) AddPeer(addr string) error {
return c.admin.addPeer(addr)
}
// Adds an expression to select multicast interfaces for peer discovery. This
// should be done before calling Start. This function can be called multiple
// times to add multiple search expressions.
func (c *Core) AddMulticastInterfaceExpr(expr *regexp.Regexp) {
c.ifceExpr = append(c.ifceExpr, expr)
}
// Adds an allowed public key. This allow peerings to be restricted only to
// keys that you have selected.
func (c *Core) AddAllowedEncryptionPublicKey(boxStr string) error {
return c.admin.addAllowedEncryptionPublicKey(boxStr)
}
// Gets the default TUN/TAP interface name for your platform.
func (c *Core) GetTUNDefaultIfName() string {
return getDefaults().defaultIfName
}
// Gets the default TUN/TAP interface MTU for your platform. This can be as high
// as 65535, depending on platform, but is never lower than 1280.
func (c *Core) GetTUNDefaultIfMTU() int {
return getDefaults().defaultIfMTU
}
// Gets the maximum supported TUN/TAP interface MTU for your platform. This
// can be as high as 65535, depending on platform, but is never lower than 1280.
func (c *Core) GetTUNMaximumIfMTU() int {
return getDefaults().maximumIfMTU
}
// Gets the default TUN/TAP interface mode for your platform.
func (c *Core) GetTUNDefaultIfTAPMode() bool {
return getDefaults().defaultIfTAPMode
}
// Gets the current TUN/TAP interface name.
func (c *Core) GetTUNIfName() string {
return c.tun.iface.Name()
}
// Gets the current TUN/TAP interface MTU.
func (c *Core) GetTUNIfMTU() int {
return c.tun.mtu
}

View file

@ -279,6 +279,14 @@ func (c *Core) DEBUG_init(bpub []byte,
copy(sigPub[:], spub)
copy(sigPriv[:], spriv)
c.init(&boxPub, &boxPriv, &sigPub, &sigPriv)
if err := c.router.start(); err != nil {
panic(err)
}
if err := c.switchTable.start(); err != nil {
panic(err)
}
}
////////////////////////////////////////////////////////////////////////////////

View file

@ -48,19 +48,19 @@ func (m *multicast) init(core *Core) {
m.core.log.Println("Found", len(m.interfaces), "multicast interface(s)")
}
func (m *multicast) start() {
func (m *multicast) start() error {
if len(m.core.ifceExpr) == 0 {
m.core.log.Println("Multicast discovery is disabled")
} else {
m.core.log.Println("Multicast discovery is enabled")
addr, err := net.ResolveUDPAddr("udp", m.groupAddr)
if err != nil {
panic(err)
return err
}
listenString := fmt.Sprintf("[::]:%v", addr.Port)
conn, err := net.ListenPacket("udp6", listenString)
if err != nil {
panic(err)
return err
}
//defer conn.Close() // Let it close on its own when the application exits
m.sock = ipv6.NewPacketConn(conn)
@ -72,6 +72,7 @@ func (m *multicast) start() {
go m.listen()
go m.announce()
}
return nil
}
func (m *multicast) announce() {
@ -80,7 +81,7 @@ func (m *multicast) announce() {
panic(err)
}
var anAddr net.TCPAddr
myAddr := m.core.DEBUG_getGlobalTCPAddr()
myAddr := m.core.tcp.getAddr()
anAddr.Port = myAddr.Port
destAddr, err := net.ResolveUDPAddr("udp6", m.groupAddr)
if err != nil {
@ -155,7 +156,7 @@ func (m *multicast) listen() {
saddr := addr.String()
//if _, isIn := n.peers[saddr]; isIn { continue }
//n.peers[saddr] = struct{}{}
m.core.DEBUG_addTCPConn(saddr)
m.core.tcp.connect(saddr)
//fmt.Println("DEBUG:", "added multicast peer:", saddr)
}
}

View file

@ -64,7 +64,13 @@ func (r *router) init(core *Core) {
r.core.tun.send = send
r.reset = make(chan struct{}, 1)
r.admin = make(chan func())
// go r.mainLoop()
}
func (r *router) start() error {
r.core.log.Println("Starting router")
go r.mainLoop()
return nil
}
func (r *router) mainLoop() {

View file

@ -167,6 +167,9 @@ func (t *switchTable) init(core *Core, key sigPubKey) {
t.updater.Store(&sync.Once{})
t.table.Store(lookupTable{})
t.drop = make(map[sigPubKey]int64)
}
func (t *switchTable) start() error {
doTicker := func() {
ticker := time.NewTicker(time.Second)
defer ticker.Stop()
@ -176,6 +179,7 @@ func (t *switchTable) init(core *Core, key sigPubKey) {
}
}
go doTicker()
return nil
}
func (t *switchTable) getLocator() switchLocator {

View file

@ -16,6 +16,7 @@ import "errors"
import "sync"
import "fmt"
import "bufio"
import "golang.org/x/net/proxy"
const tcp_msgSize = 2048 + 65535 // TODO figure out what makes sense
@ -42,6 +43,32 @@ type tcpInfo struct {
remoteAddr string
}
func (iface *tcpInterface) getAddr() *net.TCPAddr {
return iface.serv.Addr().(*net.TCPAddr)
}
func (iface *tcpInterface) connect(addr string) {
iface.call(addr)
}
func (iface *tcpInterface) connectSOCKS(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 {
iface.callWithConn(&wrappedConn{
c: conn,
raddr: &wrappedAddr{
network: "tcp",
addr: peeraddr,
},
})
}
}
}()
}
func (iface *tcpInterface) init(core *Core, addr string) (err error) {
iface.core = core
@ -51,7 +78,8 @@ func (iface *tcpInterface) init(core *Core, addr string) (err error) {
iface.conns = make(map[tcpInfo](chan struct{}))
go iface.listener()
}
return
return err
}
func (iface *tcpInterface) listener() {
@ -274,12 +302,14 @@ func (iface *tcpInterface) reader(sock net.Conn, in func([]byte)) {
sock.SetReadDeadline(timeout)
n, err := sock.Read(bs[len(frag):])
if err != nil || n == 0 {
// iface.core.log.Println(err)
break
}
frag = bs[:len(frag)+n]
for {
msg, ok, err := tcp_chop_msg(&frag)
if err != nil {
// iface.core.log.Println(err)
return
}
if !ok {

View file

@ -65,6 +65,25 @@ type udpKeys struct {
sig sigPubKey
}
func (iface *udpInterface) getAddr() *net.UDPAddr {
return iface.sock.LocalAddr().(*net.UDPAddr)
}
func (iface *udpInterface) connect(saddr string) {
udpAddr, err := net.ResolveUDPAddr("udp", saddr)
if err != nil {
panic(err)
}
var addr connAddr
addr.fromUDPAddr(udpAddr)
iface.mutex.RLock()
_, isIn := iface.conns[addr]
iface.mutex.RUnlock()
if !isIn {
iface.sendKeys(addr)
}
}
func (iface *udpInterface) init(core *Core, addr string) (err error) {
iface.core = core
udpAddr, err := net.ResolveUDPAddr("udp", addr)