mirror of
https://github.com/yggdrasil-network/yggdrasil-go.git
synced 2024-11-27 12:05:23 +00:00
Merge pull request #929 from yggdrasil-network/neilalexander/refactor
Node setup refactoring
This commit is contained in:
commit
af99fa4f6b
@ -36,7 +36,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type node struct {
|
type node struct {
|
||||||
core core.Core
|
core *core.Core
|
||||||
config *config.NodeConfig
|
config *config.NodeConfig
|
||||||
tuntap *tuntap.TunAdapter
|
tuntap *tuntap.TunAdapter
|
||||||
multicast *multicast.Multicast
|
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
|
// Setup the Yggdrasil node itself. The node{} type includes a Core, so we
|
||||||
// don't need to create this manually.
|
// 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}
|
n := node{config: cfg}
|
||||||
// Now start Yggdrasil - this starts the DHT, router, switch and other core
|
n.core, err = core.New(sk[:], options...)
|
||||||
// components needed for Yggdrasil to operate
|
if err != nil {
|
||||||
if err = n.core.Start(cfg, logger); err != nil {
|
|
||||||
logger.Errorln("An error occurred during startup")
|
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
// Register the session firewall gatekeeper function
|
// 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.multicast = &multicast.Multicast{}
|
||||||
n.tuntap = &tuntap.TunAdapter{}
|
n.tuntap = &tuntap.TunAdapter{}
|
||||||
// Start the admin socket
|
// 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)
|
logger.Errorln("An error occurred initialising admin socket:", err)
|
||||||
} else if err := n.admin.Start(); err != nil {
|
} else if err := n.admin.Start(); err != nil {
|
||||||
logger.Errorln("An error occurred starting admin socket:", err)
|
logger.Errorln("An error occurred starting admin socket:", err)
|
||||||
}
|
}
|
||||||
n.admin.SetupAdminHandlers(n.admin)
|
n.admin.SetupAdminHandlers(n.admin)
|
||||||
// Start the multicast interface
|
// 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)
|
logger.Errorln("An error occurred initialising multicast:", err)
|
||||||
} else if err := n.multicast.Start(); err != nil {
|
} else if err := n.multicast.Start(); err != nil {
|
||||||
logger.Errorln("An error occurred starting multicast:", err)
|
logger.Errorln("An error occurred starting multicast:", err)
|
||||||
}
|
}
|
||||||
n.multicast.SetupAdminHandlers(n.admin)
|
n.multicast.SetupAdminHandlers(n.admin)
|
||||||
// Start the TUN/TAP interface
|
// 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 {
|
if err := n.tuntap.Init(rwc, cfg, logger, nil); err != nil {
|
||||||
logger.Errorln("An error occurred initialising TUN/TAP:", err)
|
logger.Errorln("An error occurred initialising TUN/TAP:", err)
|
||||||
} else if err := n.tuntap.Start(); err != nil {
|
} else if err := n.tuntap.Start(); err != nil {
|
||||||
|
@ -25,7 +25,7 @@ import (
|
|||||||
// functions. Note that in the case of iOS we handle reading/writing to/from TUN
|
// functions. Note that in the case of iOS we handle reading/writing to/from TUN
|
||||||
// in Swift therefore we use the "dummy" TUN interface instead.
|
// in Swift therefore we use the "dummy" TUN interface instead.
|
||||||
type Yggdrasil struct {
|
type Yggdrasil struct {
|
||||||
core core.Core
|
core *core.Core
|
||||||
iprwc *ipv6rwc.ReadWriteCloser
|
iprwc *ipv6rwc.ReadWriteCloser
|
||||||
config *config.NodeConfig
|
config *config.NodeConfig
|
||||||
multicast multicast.Multicast
|
multicast multicast.Multicast
|
||||||
@ -48,19 +48,42 @@ func (m *Yggdrasil) StartJSON(configjson []byte) error {
|
|||||||
if err := json.Unmarshal(configjson, &m.config); err != nil {
|
if err := json.Unmarshal(configjson, &m.config); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
m.config.IfName = "none"
|
// Setup the Yggdrasil node itself.
|
||||||
if err := m.core.Start(m.config, logger); err != nil {
|
sk, err := hex.DecodeString(m.config.PrivateKey)
|
||||||
logger.Errorln("An error occured starting Yggdrasil:", err)
|
if err != nil {
|
||||||
return err
|
panic(err)
|
||||||
|
}
|
||||||
|
options := []core.SetupOption{
|
||||||
|
core.IfName("none"),
|
||||||
|
core.IfMTU(m.config.IfMTU),
|
||||||
|
}
|
||||||
|
for _, peer := range m.config.Peers {
|
||||||
|
options = append(options, core.Peer{URI: peer})
|
||||||
|
}
|
||||||
|
for intf, peers := range m.config.InterfacePeers {
|
||||||
|
for _, peer := range peers {
|
||||||
|
options = append(options, core.Peer{URI: peer, SourceInterface: intf})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, allowed := range m.config.AllowedPublicKeys {
|
||||||
|
k, err := hex.DecodeString(allowed)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
options = append(options, core.AllowedPublicKey(k[:]))
|
||||||
|
}
|
||||||
|
m.core, err = core.New(sk[:], options...)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
}
|
}
|
||||||
mtu := m.config.IfMTU
|
mtu := m.config.IfMTU
|
||||||
m.iprwc = ipv6rwc.NewReadWriteCloser(&m.core)
|
m.iprwc = ipv6rwc.NewReadWriteCloser(m.core)
|
||||||
if m.iprwc.MaxMTU() < mtu {
|
if m.iprwc.MaxMTU() < mtu {
|
||||||
mtu = m.iprwc.MaxMTU()
|
mtu = m.iprwc.MaxMTU()
|
||||||
}
|
}
|
||||||
m.iprwc.SetMTU(mtu)
|
m.iprwc.SetMTU(mtu)
|
||||||
if len(m.config.MulticastInterfaces) > 0 {
|
if len(m.config.MulticastInterfaces) > 0 {
|
||||||
if err := m.multicast.Init(&m.core, m.config, logger, nil); err != nil {
|
if err := m.multicast.Init(m.core, m.config, logger, nil); err != nil {
|
||||||
logger.Errorln("An error occurred initialising multicast:", err)
|
logger.Errorln("An error occurred initialising multicast:", err)
|
||||||
} else if err := m.multicast.Start(); err != nil {
|
} else if err := m.multicast.Start(); err != nil {
|
||||||
logger.Errorln("An error occurred starting multicast:", err)
|
logger.Errorln("An error occurred starting multicast:", err)
|
||||||
@ -136,18 +159,18 @@ func (m *Yggdrasil) GetCoordsString() string {
|
|||||||
|
|
||||||
func (m *Yggdrasil) GetPeersJSON() (result string) {
|
func (m *Yggdrasil) GetPeersJSON() (result string) {
|
||||||
peers := []struct {
|
peers := []struct {
|
||||||
core.Peer
|
core.PeerInfo
|
||||||
IP string
|
IP string
|
||||||
}{}
|
}{}
|
||||||
for _, v := range m.core.GetPeers() {
|
for _, v := range m.core.GetPeers() {
|
||||||
a := address.AddrForKey(v.Key)
|
a := address.AddrForKey(v.Key)
|
||||||
ip := net.IP(a[:]).String()
|
ip := net.IP(a[:]).String()
|
||||||
peers = append(peers, struct {
|
peers = append(peers, struct {
|
||||||
core.Peer
|
core.PeerInfo
|
||||||
IP string
|
IP string
|
||||||
}{
|
}{
|
||||||
Peer: v,
|
PeerInfo: v,
|
||||||
IP: ip,
|
IP: ip,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if res, err := json.Marshal(peers); err == nil {
|
if res, err := json.Marshal(peers); err == nil {
|
||||||
|
2
go.mod
2
go.mod
@ -12,7 +12,7 @@ require (
|
|||||||
github.com/kardianos/minwinsvc v1.0.0
|
github.com/kardianos/minwinsvc v1.0.0
|
||||||
github.com/mitchellh/mapstructure v1.4.1
|
github.com/mitchellh/mapstructure v1.4.1
|
||||||
github.com/vishvananda/netlink v1.1.0
|
github.com/vishvananda/netlink v1.1.0
|
||||||
golang.org/x/mobile v0.0.0-20220112015953-858099ff7816
|
golang.org/x/mobile v0.0.0-20220722155234-aaac322e2105
|
||||||
golang.org/x/net v0.0.0-20211101193420-4a448f8816b3
|
golang.org/x/net v0.0.0-20211101193420-4a448f8816b3
|
||||||
golang.org/x/sys v0.0.0-20211102192858-4dd72447c267
|
golang.org/x/sys v0.0.0-20211102192858-4dd72447c267
|
||||||
golang.org/x/text v0.3.8-0.20211004125949-5bd84dd9b33b
|
golang.org/x/text v0.3.8-0.20211004125949-5bd84dd9b33b
|
||||||
|
2
go.sum
2
go.sum
@ -52,6 +52,8 @@ golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+o
|
|||||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||||
golang.org/x/mobile v0.0.0-20220112015953-858099ff7816 h1:jhDgkcu3yQ4tasBZ+1YwDmK7eFmuVf1w1k+NGGGxfmE=
|
golang.org/x/mobile v0.0.0-20220112015953-858099ff7816 h1:jhDgkcu3yQ4tasBZ+1YwDmK7eFmuVf1w1k+NGGGxfmE=
|
||||||
golang.org/x/mobile v0.0.0-20220112015953-858099ff7816/go.mod h1:pe2sM7Uk+2Su1y7u/6Z8KJ24D7lepUjFZbhFOrmDfuQ=
|
golang.org/x/mobile v0.0.0-20220112015953-858099ff7816/go.mod h1:pe2sM7Uk+2Su1y7u/6Z8KJ24D7lepUjFZbhFOrmDfuQ=
|
||||||
|
golang.org/x/mobile v0.0.0-20220722155234-aaac322e2105 h1:3vUV5x5+3LfQbgk7paCM6INOaJG9xXQbn79xoNkwfIk=
|
||||||
|
golang.org/x/mobile v0.0.0-20220722155234-aaac322e2105/go.mod h1:pe2sM7Uk+2Su1y7u/6Z8KJ24D7lepUjFZbhFOrmDfuQ=
|
||||||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||||
golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
|
golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
|
||||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
|
@ -21,13 +21,13 @@ import (
|
|||||||
//"github.com/Arceliar/phony"
|
//"github.com/Arceliar/phony"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Self struct {
|
type SelfInfo struct {
|
||||||
Key ed25519.PublicKey
|
Key ed25519.PublicKey
|
||||||
Root ed25519.PublicKey
|
Root ed25519.PublicKey
|
||||||
Coords []uint64
|
Coords []uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
type Peer struct {
|
type PeerInfo struct {
|
||||||
Key ed25519.PublicKey
|
Key ed25519.PublicKey
|
||||||
Root ed25519.PublicKey
|
Root ed25519.PublicKey
|
||||||
Coords []uint64
|
Coords []uint64
|
||||||
@ -38,23 +38,23 @@ type Peer struct {
|
|||||||
Uptime time.Duration
|
Uptime time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
type DHTEntry struct {
|
type DHTEntryInfo struct {
|
||||||
Key ed25519.PublicKey
|
Key ed25519.PublicKey
|
||||||
Port uint64
|
Port uint64
|
||||||
Rest uint64
|
Rest uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
type PathEntry struct {
|
type PathEntryInfo struct {
|
||||||
Key ed25519.PublicKey
|
Key ed25519.PublicKey
|
||||||
Path []uint64
|
Path []uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
type Session struct {
|
type SessionInfo struct {
|
||||||
Key ed25519.PublicKey
|
Key ed25519.PublicKey
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Core) GetSelf() Self {
|
func (c *Core) GetSelf() SelfInfo {
|
||||||
var self Self
|
var self SelfInfo
|
||||||
s := c.PacketConn.PacketConn.Debug.GetSelf()
|
s := c.PacketConn.PacketConn.Debug.GetSelf()
|
||||||
self.Key = s.Key
|
self.Key = s.Key
|
||||||
self.Root = s.Root
|
self.Root = s.Root
|
||||||
@ -62,8 +62,8 @@ func (c *Core) GetSelf() Self {
|
|||||||
return self
|
return self
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Core) GetPeers() []Peer {
|
func (c *Core) GetPeers() []PeerInfo {
|
||||||
var peers []Peer
|
var peers []PeerInfo
|
||||||
names := make(map[net.Conn]string)
|
names := make(map[net.Conn]string)
|
||||||
c.links.mutex.Lock()
|
c.links.mutex.Lock()
|
||||||
for _, info := range c.links.links {
|
for _, info := range c.links.links {
|
||||||
@ -72,7 +72,7 @@ func (c *Core) GetPeers() []Peer {
|
|||||||
c.links.mutex.Unlock()
|
c.links.mutex.Unlock()
|
||||||
ps := c.PacketConn.PacketConn.Debug.GetPeers()
|
ps := c.PacketConn.PacketConn.Debug.GetPeers()
|
||||||
for _, p := range ps {
|
for _, p := range ps {
|
||||||
var info Peer
|
var info PeerInfo
|
||||||
info.Key = p.Key
|
info.Key = p.Key
|
||||||
info.Root = p.Root
|
info.Root = p.Root
|
||||||
info.Coords = p.Coords
|
info.Coords = p.Coords
|
||||||
@ -91,11 +91,11 @@ func (c *Core) GetPeers() []Peer {
|
|||||||
return peers
|
return peers
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Core) GetDHT() []DHTEntry {
|
func (c *Core) GetDHT() []DHTEntryInfo {
|
||||||
var dhts []DHTEntry
|
var dhts []DHTEntryInfo
|
||||||
ds := c.PacketConn.PacketConn.Debug.GetDHT()
|
ds := c.PacketConn.PacketConn.Debug.GetDHT()
|
||||||
for _, d := range ds {
|
for _, d := range ds {
|
||||||
var info DHTEntry
|
var info DHTEntryInfo
|
||||||
info.Key = d.Key
|
info.Key = d.Key
|
||||||
info.Port = d.Port
|
info.Port = d.Port
|
||||||
info.Rest = d.Rest
|
info.Rest = d.Rest
|
||||||
@ -104,11 +104,11 @@ func (c *Core) GetDHT() []DHTEntry {
|
|||||||
return dhts
|
return dhts
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Core) GetPaths() []PathEntry {
|
func (c *Core) GetPaths() []PathEntryInfo {
|
||||||
var paths []PathEntry
|
var paths []PathEntryInfo
|
||||||
ps := c.PacketConn.PacketConn.Debug.GetPaths()
|
ps := c.PacketConn.PacketConn.Debug.GetPaths()
|
||||||
for _, p := range ps {
|
for _, p := range ps {
|
||||||
var info PathEntry
|
var info PathEntryInfo
|
||||||
info.Key = p.Key
|
info.Key = p.Key
|
||||||
info.Path = p.Path
|
info.Path = p.Path
|
||||||
paths = append(paths, info)
|
paths = append(paths, info)
|
||||||
@ -116,11 +116,11 @@ func (c *Core) GetPaths() []PathEntry {
|
|||||||
return paths
|
return paths
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Core) GetSessions() []Session {
|
func (c *Core) GetSessions() []SessionInfo {
|
||||||
var sessions []Session
|
var sessions []SessionInfo
|
||||||
ss := c.PacketConn.Debug.GetSessions()
|
ss := c.PacketConn.Debug.GetSessions()
|
||||||
for _, s := range ss {
|
for _, s := range ss {
|
||||||
var info Session
|
var info SessionInfo
|
||||||
info.Key = s.Key
|
info.Key = s.Key
|
||||||
sessions = append(sessions, info)
|
sessions = append(sessions, info)
|
||||||
}
|
}
|
||||||
|
176
src/core/core.go
176
src/core/core.go
@ -3,12 +3,11 @@ package core
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/ed25519"
|
"crypto/ed25519"
|
||||||
"encoding/hex"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
iwe "github.com/Arceliar/ironwood/encrypted"
|
iwe "github.com/Arceliar/ironwood/encrypted"
|
||||||
@ -16,9 +15,8 @@ import (
|
|||||||
"github.com/Arceliar/phony"
|
"github.com/Arceliar/phony"
|
||||||
"github.com/gologme/log"
|
"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/version"
|
"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
|
// The Core object represents the Yggdrasil node. You should create a Core
|
||||||
@ -29,62 +27,98 @@ type Core struct {
|
|||||||
// guarantee that it will be covered by the mutex
|
// guarantee that it will be covered by the mutex
|
||||||
phony.Inbox
|
phony.Inbox
|
||||||
*iwe.PacketConn
|
*iwe.PacketConn
|
||||||
config *config.NodeConfig // Config
|
ctx context.Context
|
||||||
|
cancel context.CancelFunc
|
||||||
secret ed25519.PrivateKey
|
secret ed25519.PrivateKey
|
||||||
public ed25519.PublicKey
|
public ed25519.PublicKey
|
||||||
links links
|
links links
|
||||||
proto protoHandler
|
proto protoHandler
|
||||||
log *log.Logger
|
log *log.Logger
|
||||||
addPeerTimer *time.Timer
|
addPeerTimer *time.Timer
|
||||||
ctx context.Context
|
config struct {
|
||||||
ctxCancel context.CancelFunc
|
_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 {
|
func New(secret ed25519.PrivateKey, opts ...SetupOption) (*Core, error) {
|
||||||
// TODO separate init and start functions
|
if len(secret) != ed25519.PrivateKeySize {
|
||||||
// Init sets up structs
|
return nil, fmt.Errorf("private key is incorrect length")
|
||||||
// Start launches goroutines that depend on structs being set up
|
}
|
||||||
// This is pretty much required to completely avoid race conditions
|
c := &Core{
|
||||||
c.config.RLock()
|
secret: secret,
|
||||||
defer c.config.RUnlock()
|
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)
|
||||||
|
}
|
||||||
|
c.config._peers = map[Peer]struct{}{}
|
||||||
|
c.config._listeners = map[ListenAddress]struct{}{}
|
||||||
|
c.config._allowedPublicKeys = map[[32]byte]struct{}{}
|
||||||
|
for _, opt := range opts {
|
||||||
|
c._applyOption(opt)
|
||||||
|
}
|
||||||
if c.log == nil {
|
if c.log == nil {
|
||||||
c.log = log.New(io.Discard, "", 0)
|
c.log = log.New(io.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)
|
c.proto.init(c)
|
||||||
if err := c.proto.nodeinfo.setNodeInfo(c.config.NodeInfo, c.config.NodeInfoPrivacy); err != nil {
|
if err := c.links.init(c); err != nil {
|
||||||
return fmt.Errorf("setNodeInfo: %w", err)
|
return nil, fmt.Errorf("error initialising links: %w", err)
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
c.addPeerTimer = time.AfterFunc(time.Minute, func() {
|
||||||
|
c.Act(nil, c._addPeerLoop)
|
||||||
|
})
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
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 := [32]byte{}
|
||||||
|
copy(pk[:], v)
|
||||||
|
c.config._allowedPublicKeys[pk] = struct{}{}
|
||||||
}
|
}
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If any static peers were provided in the configuration above then we should
|
// If any static peers were provided in the configuration above then we should
|
||||||
// configure them. The loop ensures that disconnected peers will eventually
|
// configure them. The loop ensures that disconnected peers will eventually
|
||||||
// be reconnected with.
|
// be reconnected with.
|
||||||
func (c *Core) _addPeerLoop() {
|
func (c *Core) _addPeerLoop() {
|
||||||
c.config.RLock()
|
|
||||||
defer c.config.RUnlock()
|
|
||||||
|
|
||||||
if c.addPeerTimer == nil {
|
if c.addPeerTimer == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add peers from the Peers section
|
// Add peers from the Peers section
|
||||||
for _, peer := range c.config.Peers {
|
for peer := range c.config._peers {
|
||||||
go func(peer string, intf string) {
|
go func(peer string, intf string) {
|
||||||
u, err := url.Parse(peer)
|
u, err := url.Parse(peer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -93,22 +127,7 @@ func (c *Core) _addPeerLoop() {
|
|||||||
if err := c.CallPeer(u, intf); err != nil {
|
if err := c.CallPeer(u, intf); err != nil {
|
||||||
c.log.Errorln("Failed to add peer:", err)
|
c.log.Errorln("Failed to add peer:", err)
|
||||||
}
|
}
|
||||||
}(peer, "") // TODO: this should be acted and not in a goroutine?
|
}(peer.URI, peer.SourceInterface) // 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.addPeerTimer = time.AfterFunc(time.Minute, func() {
|
||||||
@ -116,49 +135,6 @@ func (c *Core) _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)
|
|
||||||
}
|
|
||||||
|
|
||||||
c.log.Infoln("Starting up...")
|
|
||||||
if err := c._init(); err != nil {
|
|
||||||
c.log.Errorln("Failed to initialize core")
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := c.links.init(c); err != nil {
|
|
||||||
c.log.Errorln("Failed to start link interfaces")
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
c.addPeerTimer = time.AfterFunc(0, func() {
|
|
||||||
c.Act(nil, c._addPeerLoop)
|
|
||||||
})
|
|
||||||
|
|
||||||
c.log.Infoln("Startup complete")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stop shuts down the Yggdrasil node.
|
// Stop shuts down the Yggdrasil node.
|
||||||
func (c *Core) Stop() {
|
func (c *Core) Stop() {
|
||||||
phony.Block(c, func() {
|
phony.Block(c, func() {
|
||||||
@ -168,17 +144,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.
|
// This function is unsafe and should only be ran by the core actor.
|
||||||
func (c *Core) _close() error {
|
func (c *Core) _close() error {
|
||||||
c.ctxCancel()
|
c.cancel()
|
||||||
err := c.PacketConn.Close()
|
err := c.PacketConn.Close()
|
||||||
if c.addPeerTimer != nil {
|
if c.addPeerTimer != nil {
|
||||||
c.addPeerTimer.Stop()
|
c.addPeerTimer.Stop()
|
||||||
|
@ -2,6 +2,7 @@ package core
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"crypto/ed25519"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
@ -9,21 +10,8 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gologme/log"
|
"github.com/gologme/log"
|
||||||
|
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/config"
|
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/defaults"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// GenerateConfig produces default configuration with suitable modifications for tests.
|
|
||||||
func GenerateConfig() *config.NodeConfig {
|
|
||||||
cfg := defaults.GenerateConfig()
|
|
||||||
cfg.AdminListen = "none"
|
|
||||||
cfg.Listen = []string{"tcp://127.0.0.1:0"}
|
|
||||||
cfg.IfName = "none"
|
|
||||||
|
|
||||||
return cfg
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetLoggerWithPrefix creates a new logger instance with prefix.
|
// GetLoggerWithPrefix creates a new logger instance with prefix.
|
||||||
// If verbose is set to true, three log levels are enabled: "info", "warn", "error".
|
// If verbose is set to true, three log levels are enabled: "info", "warn", "error".
|
||||||
func GetLoggerWithPrefix(prefix string, verbose bool) *log.Logger {
|
func GetLoggerWithPrefix(prefix string, verbose bool) *log.Logger {
|
||||||
@ -40,13 +28,18 @@ func GetLoggerWithPrefix(prefix string, verbose bool) *log.Logger {
|
|||||||
// CreateAndConnectTwo creates two nodes. nodeB connects to nodeA.
|
// CreateAndConnectTwo creates two nodes. nodeB connects to nodeA.
|
||||||
// Verbosity flag is passed to logger.
|
// Verbosity flag is passed to logger.
|
||||||
func CreateAndConnectTwo(t testing.TB, verbose bool) (nodeA *Core, nodeB *Core) {
|
func CreateAndConnectTwo(t testing.TB, verbose bool) (nodeA *Core, nodeB *Core) {
|
||||||
nodeA = new(Core)
|
var err error
|
||||||
if err := nodeA.Start(GenerateConfig(), GetLoggerWithPrefix("A: ", verbose)); err != nil {
|
var skA, skB ed25519.PrivateKey
|
||||||
|
if _, skA, err = ed25519.GenerateKey(nil); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
if _, skB, err = ed25519.GenerateKey(nil); err != nil {
|
||||||
nodeB = new(Core)
|
t.Fatal(err)
|
||||||
if err := nodeB.Start(GenerateConfig(), GetLoggerWithPrefix("B: ", verbose)); err != nil {
|
}
|
||||||
|
if nodeA, err = New(skA, ListenAddress("tcp://127.0.0.1:0"), IfName("none")); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if nodeB, err = New(skB, ListenAddress("tcp://127.0.0.1:0"), IfName("none")); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"crypto/ed25519"
|
"crypto/ed25519"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"errors"
|
"errors"
|
||||||
@ -16,6 +17,7 @@ import (
|
|||||||
|
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
|
||||||
|
"github.com/Arceliar/phony"
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/address"
|
"github.com/yggdrasil-network/yggdrasil-go/src/address"
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/util"
|
"github.com/yggdrasil-network/yggdrasil-go/src/util"
|
||||||
"golang.org/x/net/proxy"
|
"golang.org/x/net/proxy"
|
||||||
@ -61,7 +63,14 @@ func (l *links) init(c *Core) error {
|
|||||||
l.mutex.Unlock()
|
l.mutex.Unlock()
|
||||||
l.stopped = make(chan struct{})
|
l.stopped = make(chan struct{})
|
||||||
|
|
||||||
if err := l.tcp.init(l); err != nil {
|
var listeners []ListenAddress
|
||||||
|
phony.Block(c, func() {
|
||||||
|
listeners = make([]ListenAddress, 0, len(c.config._listeners))
|
||||||
|
for listener := range c.config._listeners {
|
||||||
|
listeners = append(listeners, listener)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if err := l.tcp.init(l, listeners); err != nil {
|
||||||
c.log.Errorln("Failed to start TCP interface")
|
c.log.Errorln("Failed to start TCP interface")
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -70,10 +79,6 @@ func (l *links) init(c *Core) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (l *links) call(u *url.URL, sintf string) error {
|
func (l *links) call(u *url.URL, sintf string) error {
|
||||||
//u, err := url.Parse(uri)
|
|
||||||
//if err != nil {
|
|
||||||
// return fmt.Errorf("peer %s is not correctly formatted (%s)", uri, err)
|
|
||||||
//}
|
|
||||||
tcpOpts := tcpOptions{}
|
tcpOpts := tcpOptions{}
|
||||||
if pubkeys, ok := u.Query()["key"]; ok && len(pubkeys) > 0 {
|
if pubkeys, ok := u.Query()["key"]; ok && len(pubkeys) > 0 {
|
||||||
tcpOpts.pinnedEd25519Keys = make(map[keyArray]struct{})
|
tcpOpts.pinnedEd25519Keys = make(map[keyArray]struct{})
|
||||||
@ -215,12 +220,10 @@ func (intf *link) handler() (chan struct{}, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Check if we're authorized to connect to this key / IP
|
// Check if we're authorized to connect to this key / IP
|
||||||
intf.links.core.config.RLock()
|
allowed := intf.links.core.config._allowedPublicKeys
|
||||||
allowed := intf.links.core.config.AllowedPublicKeys
|
|
||||||
intf.links.core.config.RUnlock()
|
|
||||||
isallowed := len(allowed) == 0
|
isallowed := len(allowed) == 0
|
||||||
for _, k := range allowed {
|
for k := range allowed {
|
||||||
if k == hex.EncodeToString(meta.key) { // TODO: this is yuck
|
if bytes.Equal(k[:], meta.key) {
|
||||||
isallowed = true
|
isallowed = true
|
||||||
break
|
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.
|
// Initializes the struct.
|
||||||
func (t *tcp) init(l *links) error {
|
func (t *tcp) init(l *links, listeners []ListenAddress) error {
|
||||||
t.links = l
|
t.links = l
|
||||||
t.tls.init(t)
|
t.tls.init(t)
|
||||||
t.mutex.Lock()
|
t.mutex.Lock()
|
||||||
@ -105,10 +105,8 @@ func (t *tcp) init(l *links) error {
|
|||||||
t.listeners = make(map[string]*TcpListener)
|
t.listeners = make(map[string]*TcpListener)
|
||||||
t.mutex.Unlock()
|
t.mutex.Unlock()
|
||||||
|
|
||||||
t.links.core.config.RLock()
|
for _, listenaddr := range listeners {
|
||||||
defer t.links.core.config.RUnlock()
|
u, err := url.Parse(string(listenaddr))
|
||||||
for _, listenaddr := range t.links.core.config.Listen {
|
|
||||||
u, err := url.Parse(listenaddr)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.links.core.log.Errorln("Failed to parse listener: listener", listenaddr, "is not correctly formatted, ignoring")
|
t.links.core.log.Errorln("Failed to parse listener: listener", listenaddr, "is not correctly formatted, ignoring")
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user