mirror of
https://github.com/cwinfo/yggdrasil-go.git
synced 2024-11-09 16:20:26 +00:00
Don't lose my work
This commit is contained in:
parent
41b4bf69cf
commit
5616b9fc84
@ -36,7 +36,7 @@ import (
|
||||
)
|
||||
|
||||
type node struct {
|
||||
core core.Core
|
||||
core *core.Core
|
||||
config *config.NodeConfig
|
||||
tuntap *tuntap.TunAdapter
|
||||
multicast *multicast.Multicast
|
||||
@ -327,11 +327,32 @@ func run(args yggArgs, ctx context.Context, done chan struct{}) {
|
||||
|
||||
// Setup the Yggdrasil node itself. The node{} type includes a Core, so we
|
||||
// don't need to create this manually.
|
||||
sk, err := hex.DecodeString(cfg.PrivateKey)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
options := []core.SetupOption{
|
||||
core.IfName(cfg.IfName),
|
||||
core.IfMTU(cfg.IfMTU),
|
||||
}
|
||||
for _, peer := range cfg.Peers {
|
||||
options = append(options, core.Peer{URI: peer})
|
||||
}
|
||||
for intf, peers := range cfg.InterfacePeers {
|
||||
for _, peer := range peers {
|
||||
options = append(options, core.Peer{URI: peer, SourceInterface: intf})
|
||||
}
|
||||
}
|
||||
for _, allowed := range cfg.AllowedPublicKeys {
|
||||
k, err := hex.DecodeString(allowed)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
options = append(options, core.AllowedPublicKey(k[:]))
|
||||
}
|
||||
n := node{config: cfg}
|
||||
// Now start Yggdrasil - this starts the DHT, router, switch and other core
|
||||
// components needed for Yggdrasil to operate
|
||||
if err = n.core.Start(cfg, logger); err != nil {
|
||||
logger.Errorln("An error occurred during startup")
|
||||
n.core, err = core.New(sk[:], options...)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// Register the session firewall gatekeeper function
|
||||
@ -340,21 +361,21 @@ func run(args yggArgs, ctx context.Context, done chan struct{}) {
|
||||
n.multicast = &multicast.Multicast{}
|
||||
n.tuntap = &tuntap.TunAdapter{}
|
||||
// Start the admin socket
|
||||
if err := n.admin.Init(&n.core, cfg, logger, nil); err != nil {
|
||||
if err := n.admin.Init(n.core, cfg, logger, nil); err != nil {
|
||||
logger.Errorln("An error occurred initialising admin socket:", err)
|
||||
} else if err := n.admin.Start(); err != nil {
|
||||
logger.Errorln("An error occurred starting admin socket:", err)
|
||||
}
|
||||
n.admin.SetupAdminHandlers(n.admin)
|
||||
// Start the multicast interface
|
||||
if err := n.multicast.Init(&n.core, cfg, logger, nil); err != nil {
|
||||
if err := n.multicast.Init(n.core, cfg, logger, nil); err != nil {
|
||||
logger.Errorln("An error occurred initialising multicast:", err)
|
||||
} else if err := n.multicast.Start(); err != nil {
|
||||
logger.Errorln("An error occurred starting multicast:", err)
|
||||
}
|
||||
n.multicast.SetupAdminHandlers(n.admin)
|
||||
// Start the TUN/TAP interface
|
||||
rwc := ipv6rwc.NewReadWriteCloser(&n.core)
|
||||
rwc := ipv6rwc.NewReadWriteCloser(n.core)
|
||||
if err := n.tuntap.Init(rwc, cfg, logger, nil); err != nil {
|
||||
logger.Errorln("An error occurred initialising TUN/TAP:", err)
|
||||
} else if err := n.tuntap.Start(); err != nil {
|
||||
|
@ -2,8 +2,6 @@ package core
|
||||
|
||||
import (
|
||||
"crypto/ed25519"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
//"encoding/hex"
|
||||
"encoding/json"
|
||||
@ -27,6 +25,7 @@ type Self struct {
|
||||
Coords []uint64
|
||||
}
|
||||
|
||||
/*
|
||||
type Peer struct {
|
||||
Key ed25519.PublicKey
|
||||
Root ed25519.PublicKey
|
||||
@ -37,6 +36,7 @@ type Peer struct {
|
||||
TXBytes uint64
|
||||
Uptime time.Duration
|
||||
}
|
||||
*/
|
||||
|
||||
type DHTEntry struct {
|
||||
Key ed25519.PublicKey
|
||||
@ -62,6 +62,7 @@ func (c *Core) GetSelf() Self {
|
||||
return self
|
||||
}
|
||||
|
||||
/*
|
||||
func (c *Core) GetPeers() []Peer {
|
||||
var peers []Peer
|
||||
names := make(map[net.Conn]string)
|
||||
@ -90,6 +91,7 @@ func (c *Core) GetPeers() []Peer {
|
||||
}
|
||||
return peers
|
||||
}
|
||||
*/
|
||||
|
||||
func (c *Core) GetDHT() []DHTEntry {
|
||||
var dhts []DHTEntry
|
||||
|
188
src/core/core.go
188
src/core/core.go
@ -3,12 +3,11 @@ package core
|
||||
import (
|
||||
"context"
|
||||
"crypto/ed25519"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/url"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
iwe "github.com/Arceliar/ironwood/encrypted"
|
||||
@ -16,9 +15,9 @@ import (
|
||||
"github.com/Arceliar/phony"
|
||||
"github.com/gologme/log"
|
||||
|
||||
"github.com/yggdrasil-network/yggdrasil-go/src/config"
|
||||
//"github.com/yggdrasil-network/yggdrasil-go/src/crypto"
|
||||
"github.com/yggdrasil-network/yggdrasil-go/src/crypto"
|
||||
"github.com/yggdrasil-network/yggdrasil-go/src/version"
|
||||
//"github.com/yggdrasil-network/yggdrasil-go/src/crypto"
|
||||
)
|
||||
|
||||
// The Core object represents the Yggdrasil node. You should create a Core
|
||||
@ -29,134 +28,109 @@ type Core struct {
|
||||
// guarantee that it will be covered by the mutex
|
||||
phony.Inbox
|
||||
*iwe.PacketConn
|
||||
config *config.NodeConfig // Config
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
secret ed25519.PrivateKey
|
||||
public ed25519.PublicKey
|
||||
links links
|
||||
proto protoHandler
|
||||
log *log.Logger
|
||||
addPeerTimer *time.Timer
|
||||
ctx context.Context
|
||||
ctxCancel context.CancelFunc
|
||||
config struct {
|
||||
_peers map[Peer]struct{} // configurable after startup
|
||||
_listeners map[ListenAddress]struct{} // configurable after startup
|
||||
nodeinfo NodeInfo // immutable after startup
|
||||
nodeinfoPrivacy NodeInfoPrivacy // immutable after startup
|
||||
ifname IfName // immutable after startup
|
||||
ifmtu IfMTU // immutable after startup
|
||||
_allowedPublicKeys map[[32]byte]struct{} // configurable after startup
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Core) _init() error {
|
||||
// TODO separate init and start functions
|
||||
// Init sets up structs
|
||||
// Start launches goroutines that depend on structs being set up
|
||||
// This is pretty much required to completely avoid race conditions
|
||||
c.config.RLock()
|
||||
defer c.config.RUnlock()
|
||||
func New(secret ed25519.PrivateKey, opts ...SetupOption) (*Core, error) {
|
||||
if len(secret) != ed25519.PrivateKeySize {
|
||||
return nil, fmt.Errorf("private key is incorrect length")
|
||||
}
|
||||
c := &Core{
|
||||
secret: secret,
|
||||
public: secret.Public().(ed25519.PublicKey),
|
||||
log: log.New(os.Stdout, "", 0), // TODO: not this
|
||||
}
|
||||
c.ctx, c.cancel = context.WithCancel(context.Background())
|
||||
var err error
|
||||
if c.PacketConn, err = iwe.NewPacketConn(c.secret); err != nil {
|
||||
return nil, fmt.Errorf("error creating encryption: %w", err)
|
||||
}
|
||||
for _, opt := range opts {
|
||||
c._applyOption(opt)
|
||||
}
|
||||
if c.log == nil {
|
||||
c.log = log.New(ioutil.Discard, "", 0)
|
||||
}
|
||||
|
||||
sigPriv, err := hex.DecodeString(c.config.PrivateKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(sigPriv) < ed25519.PrivateKeySize {
|
||||
return errors.New("PrivateKey is incorrect length")
|
||||
}
|
||||
|
||||
c.secret = ed25519.PrivateKey(sigPriv)
|
||||
c.public = c.secret.Public().(ed25519.PublicKey)
|
||||
// TODO check public against current.PublicKey, error if they don't match
|
||||
|
||||
c.PacketConn, err = iwe.NewPacketConn(c.secret)
|
||||
c.ctx, c.ctxCancel = context.WithCancel(context.Background())
|
||||
c.proto.init(c)
|
||||
if err := c.proto.nodeinfo.setNodeInfo(c.config.NodeInfo, c.config.NodeInfoPrivacy); err != nil {
|
||||
return fmt.Errorf("setNodeInfo: %w", err)
|
||||
if err := c.links.init(c); err != nil {
|
||||
return nil, fmt.Errorf("error initialising links: %w", err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// If any static peers were provided in the configuration above then we should
|
||||
// configure them. The loop ensures that disconnected peers will eventually
|
||||
// be reconnected with.
|
||||
func (c *Core) _addPeerLoop() {
|
||||
c.config.RLock()
|
||||
defer c.config.RUnlock()
|
||||
|
||||
if c.addPeerTimer == nil {
|
||||
return
|
||||
if err := c.proto.nodeinfo.setNodeInfo(c.config.nodeinfo, bool(c.config.nodeinfoPrivacy)); err != nil {
|
||||
return nil, fmt.Errorf("error setting node info: %w", err)
|
||||
}
|
||||
|
||||
// Add peers from the Peers section
|
||||
for _, peer := range c.config.Peers {
|
||||
go func(peer string, intf string) {
|
||||
u, err := url.Parse(peer)
|
||||
if err != nil {
|
||||
c.log.Errorln("Failed to parse peer url:", peer, err)
|
||||
}
|
||||
if err := c.CallPeer(u, intf); err != nil {
|
||||
c.log.Errorln("Failed to add peer:", err)
|
||||
}
|
||||
}(peer, "") // TODO: this should be acted and not in a goroutine?
|
||||
}
|
||||
|
||||
// Add peers from the InterfacePeers section
|
||||
for intf, intfpeers := range c.config.InterfacePeers {
|
||||
for _, peer := range intfpeers {
|
||||
go func(peer string, intf string) {
|
||||
u, err := url.Parse(peer)
|
||||
if err != nil {
|
||||
c.log.Errorln("Failed to parse peer url:", peer, err)
|
||||
}
|
||||
if err := c.CallPeer(u, intf); err != nil {
|
||||
c.log.Errorln("Failed to add peer:", err)
|
||||
}
|
||||
}(peer, intf) // TODO: this should be acted and not in a goroutine?
|
||||
}
|
||||
}
|
||||
|
||||
c.addPeerTimer = time.AfterFunc(time.Minute, func() {
|
||||
c.Act(nil, c._addPeerLoop)
|
||||
})
|
||||
}
|
||||
|
||||
// Start starts up Yggdrasil using the provided config.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. A config.NodeState is returned which contains both the
|
||||
// current and previous configurations (from reconfigures).
|
||||
func (c *Core) Start(nc *config.NodeConfig, log *log.Logger) (err error) {
|
||||
phony.Block(c, func() {
|
||||
err = c._start(nc, log)
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// This function is unsafe and should only be ran by the core actor.
|
||||
func (c *Core) _start(nc *config.NodeConfig, log *log.Logger) error {
|
||||
c.log = log
|
||||
c.config = nc
|
||||
|
||||
if name := version.BuildName(); name != "unknown" {
|
||||
c.log.Infoln("Build name:", name)
|
||||
}
|
||||
if version := version.BuildVersion(); version != "unknown" {
|
||||
c.log.Infoln("Build version:", version)
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
c.log.Infoln("Starting up...")
|
||||
if err := c._init(); err != nil {
|
||||
c.log.Errorln("Failed to initialize core")
|
||||
return err
|
||||
func (c *Core) _applyOption(opt SetupOption) {
|
||||
switch v := opt.(type) {
|
||||
case Peer:
|
||||
c.config._peers[v] = struct{}{}
|
||||
case ListenAddress:
|
||||
c.config._listeners[v] = struct{}{}
|
||||
case NodeInfo:
|
||||
c.config.nodeinfo = v
|
||||
case NodeInfoPrivacy:
|
||||
c.config.nodeinfoPrivacy = v
|
||||
case IfName:
|
||||
c.config.ifname = v
|
||||
case IfMTU:
|
||||
c.config.ifmtu = v
|
||||
case AllowedPublicKey:
|
||||
pk := crypto.SigPubKey{}
|
||||
copy(pk[:], v)
|
||||
c.config._allowedPublicKeys[pk] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
// If any static peers were provided in the configuration above then we should
|
||||
// configure them. The loop ensures that disconnected peers will eventually
|
||||
// be reconnected with.
|
||||
func (c *Core) _addPeerLoop() {
|
||||
if c.addPeerTimer == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err := c.links.init(c); err != nil {
|
||||
c.log.Errorln("Failed to start link interfaces")
|
||||
return err
|
||||
// Add peers from the Peers section
|
||||
for peer := range c.config._peers {
|
||||
go func(peer string, intf string) {
|
||||
u, err := url.Parse(peer)
|
||||
if err != nil {
|
||||
c.log.Errorln("Failed to parse peer url:", peer, err)
|
||||
}
|
||||
if err := c.CallPeer(u, intf); err != nil {
|
||||
c.log.Errorln("Failed to add peer:", err)
|
||||
}
|
||||
}(peer.URI, peer.SourceInterface) // TODO: this should be acted and not in a goroutine?
|
||||
}
|
||||
|
||||
c.addPeerTimer = time.AfterFunc(0, func() {
|
||||
c.addPeerTimer = time.AfterFunc(time.Minute, func() {
|
||||
c.Act(nil, c._addPeerLoop)
|
||||
})
|
||||
|
||||
c.log.Infoln("Startup complete")
|
||||
return nil
|
||||
}
|
||||
|
||||
// Stop shuts down the Yggdrasil node.
|
||||
@ -168,17 +142,9 @@ func (c *Core) Stop() {
|
||||
})
|
||||
}
|
||||
|
||||
func (c *Core) Close() error {
|
||||
var err error
|
||||
phony.Block(c, func() {
|
||||
err = c._close()
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
// This function is unsafe and should only be ran by the core actor.
|
||||
func (c *Core) _close() error {
|
||||
c.ctxCancel()
|
||||
c.cancel()
|
||||
err := c.PacketConn.Close()
|
||||
if c.addPeerTimer != nil {
|
||||
c.addPeerTimer.Stop()
|
||||
|
@ -1,6 +1,7 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/ed25519"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
@ -215,12 +216,10 @@ func (intf *link) handler() (chan struct{}, error) {
|
||||
}
|
||||
}
|
||||
// Check if we're authorized to connect to this key / IP
|
||||
intf.links.core.config.RLock()
|
||||
allowed := intf.links.core.config.AllowedPublicKeys
|
||||
intf.links.core.config.RUnlock()
|
||||
allowed := intf.links.core.config._allowedPublicKeys
|
||||
isallowed := len(allowed) == 0
|
||||
for _, k := range allowed {
|
||||
if k == hex.EncodeToString(meta.key) { // TODO: this is yuck
|
||||
for k := range allowed {
|
||||
if bytes.Equal(k[:], meta.key) {
|
||||
isallowed = true
|
||||
break
|
||||
}
|
||||
|
30
src/core/options.go
Normal file
30
src/core/options.go
Normal file
@ -0,0 +1,30 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"crypto/ed25519"
|
||||
)
|
||||
|
||||
type SetupOption interface {
|
||||
isSetupOption()
|
||||
}
|
||||
|
||||
type ListenAddress string
|
||||
type AdminListenAddress string
|
||||
type Peer struct {
|
||||
URI string
|
||||
SourceInterface string
|
||||
}
|
||||
type NodeInfo map[string]interface{}
|
||||
type NodeInfoPrivacy bool
|
||||
type IfName string
|
||||
type IfMTU uint16
|
||||
type AllowedPublicKey ed25519.PublicKey
|
||||
|
||||
func (a ListenAddress) isSetupOption() {}
|
||||
func (a AdminListenAddress) isSetupOption() {}
|
||||
func (a Peer) isSetupOption() {}
|
||||
func (a NodeInfo) isSetupOption() {}
|
||||
func (a NodeInfoPrivacy) isSetupOption() {}
|
||||
func (a IfName) isSetupOption() {}
|
||||
func (a IfMTU) isSetupOption() {}
|
||||
func (a AllowedPublicKey) isSetupOption() {}
|
@ -96,7 +96,7 @@ func (t *tcp) getAddr() *net.TCPAddr {
|
||||
}
|
||||
|
||||
// Initializes the struct.
|
||||
func (t *tcp) init(l *links) error {
|
||||
func (t *tcp) init(l *links, listeners []ListenAddress) error {
|
||||
t.links = l
|
||||
t.tls.init(t)
|
||||
t.mutex.Lock()
|
||||
@ -105,10 +105,8 @@ func (t *tcp) init(l *links) error {
|
||||
t.listeners = make(map[string]*TcpListener)
|
||||
t.mutex.Unlock()
|
||||
|
||||
t.links.core.config.RLock()
|
||||
defer t.links.core.config.RUnlock()
|
||||
for _, listenaddr := range t.links.core.config.Listen {
|
||||
u, err := url.Parse(listenaddr)
|
||||
for _, listenaddr := range listeners {
|
||||
u, err := url.Parse(string(listenaddr))
|
||||
if err != nil {
|
||||
t.links.core.log.Errorln("Failed to parse listener: listener", listenaddr, "is not correctly formatted, ignoring")
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user