2023-12-01 16:43:40 +00:00
|
|
|
// Adapted (stolen) from: https://github.com/yggdrasil-network/yggdrasil-go/pull/1109
|
|
|
|
|
|
|
|
package radio
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2023-12-29 16:10:51 +00:00
|
|
|
"crypto/ed25519"
|
2023-12-01 16:43:40 +00:00
|
|
|
"encoding/hex"
|
|
|
|
"fmt"
|
|
|
|
"net"
|
|
|
|
"regexp"
|
|
|
|
|
|
|
|
"github.com/gologme/log"
|
|
|
|
|
|
|
|
"github.com/yggdrasil-network/yggdrasil-go/src/admin"
|
|
|
|
"github.com/yggdrasil-network/yggdrasil-go/src/config"
|
|
|
|
"github.com/yggdrasil-network/yggdrasil-go/src/core"
|
|
|
|
"github.com/yggdrasil-network/yggdrasil-go/src/multicast"
|
|
|
|
)
|
|
|
|
|
|
|
|
type Node struct {
|
|
|
|
core *core.Core
|
|
|
|
ctx context.Context
|
|
|
|
cancel context.CancelFunc
|
|
|
|
logger *log.Logger
|
|
|
|
config *config.NodeConfig
|
|
|
|
multicast *multicast.Multicast
|
|
|
|
admin *admin.AdminSocket
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewNode(logger *log.Logger) *Node {
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
|
|
return &Node{
|
|
|
|
ctx: ctx,
|
|
|
|
cancel: cancel,
|
|
|
|
logger: logger,
|
|
|
|
multicast: &multicast.Multicast{},
|
|
|
|
admin: &admin.AdminSocket{},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (n *Node) Close() {
|
|
|
|
n.cancel()
|
|
|
|
_ = n.admin.Stop()
|
|
|
|
_ = n.multicast.Stop()
|
|
|
|
_ = n.core.Close()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (n *Node) Done() <-chan struct{} {
|
|
|
|
return n.ctx.Done()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (n *Node) Address() (net.IP, net.IPNet) {
|
|
|
|
address, subnet := n.core.Address(), n.core.Subnet()
|
|
|
|
return address, subnet
|
|
|
|
}
|
|
|
|
|
|
|
|
func (n *Node) Admin() *admin.AdminSocket {
|
|
|
|
return n.admin
|
|
|
|
}
|
|
|
|
|
2023-12-29 16:10:51 +00:00
|
|
|
func (n *Node) GenerateConfig(privkey ed25519.PrivateKey, listen []string, peers []string, debugSocket string) {
|
2023-12-01 16:43:40 +00:00
|
|
|
// Get the defaults for the platform.
|
|
|
|
defaults := config.GetDefaults()
|
|
|
|
|
|
|
|
// Create a node configuration and populate it.
|
|
|
|
cfg := new(config.NodeConfig)
|
2023-12-29 16:10:51 +00:00
|
|
|
cfg.PrivateKey = config.KeyBytes(privkey)
|
2023-12-04 04:42:15 +00:00
|
|
|
cfg.Listen = listen
|
|
|
|
cfg.AdminListen = debugSocket
|
|
|
|
cfg.Peers = peers
|
2023-12-01 16:43:40 +00:00
|
|
|
cfg.InterfacePeers = map[string][]string{}
|
|
|
|
cfg.AllowedPublicKeys = []string{}
|
|
|
|
cfg.MulticastInterfaces = defaults.DefaultMulticastInterfaces
|
|
|
|
cfg.IfName = "none"
|
|
|
|
cfg.IfMTU = defaults.DefaultIfMTU
|
|
|
|
cfg.NodeInfoPrivacy = true
|
|
|
|
if err := cfg.GenerateSelfSignedCertificate(); err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
n.config = cfg
|
|
|
|
}
|
|
|
|
|
|
|
|
func (n *Node) Config() config.NodeConfig {
|
|
|
|
return *n.config
|
|
|
|
}
|
|
|
|
|
|
|
|
func (n *Node) Run() error {
|
|
|
|
var err error = nil
|
|
|
|
// Have we got a working configuration? Stop if we don't.
|
|
|
|
if n.config == nil {
|
|
|
|
return fmt.Errorf("no configuration supplied")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Setup the Yggdrasil node.
|
|
|
|
{
|
|
|
|
options := []core.SetupOption{
|
|
|
|
core.NodeInfo(n.config.NodeInfo),
|
|
|
|
core.NodeInfoPrivacy(n.config.NodeInfoPrivacy),
|
|
|
|
}
|
|
|
|
for _, addr := range n.config.Listen {
|
|
|
|
options = append(options, core.ListenAddress(addr))
|
|
|
|
}
|
|
|
|
for _, peer := range n.config.Peers {
|
|
|
|
options = append(options, core.Peer{URI: peer})
|
|
|
|
}
|
|
|
|
for intf, peers := range n.config.InterfacePeers {
|
|
|
|
for _, peer := range peers {
|
|
|
|
options = append(options, core.Peer{URI: peer, SourceInterface: intf})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for _, allowed := range n.config.AllowedPublicKeys {
|
|
|
|
k, err := hex.DecodeString(allowed)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
options = append(options, core.AllowedPublicKey(k[:]))
|
|
|
|
}
|
|
|
|
if n.core, err = core.New(n.config.Certificate, n.logger, options...); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Setup the admin socket.
|
|
|
|
{
|
|
|
|
options := []admin.SetupOption{
|
|
|
|
admin.ListenAddress(n.config.AdminListen),
|
|
|
|
}
|
|
|
|
if n.config.LogLookups {
|
|
|
|
options = append(options, admin.LogLookups{})
|
|
|
|
}
|
|
|
|
if n.admin, err = admin.New(n.core, n.logger, options...); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if n.admin != nil {
|
|
|
|
n.admin.SetupAdminHandlers()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Setup the multicast module.
|
|
|
|
{
|
|
|
|
options := []multicast.SetupOption{}
|
|
|
|
for _, intf := range n.config.MulticastInterfaces {
|
|
|
|
options = append(options, multicast.MulticastInterface{
|
|
|
|
Regex: regexp.MustCompile(intf.Regex),
|
|
|
|
Beacon: intf.Beacon,
|
|
|
|
Listen: intf.Listen,
|
|
|
|
Port: intf.Port,
|
|
|
|
Priority: uint8(intf.Priority),
|
|
|
|
Password: intf.Password,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
if n.multicast, err = multicast.New(n.core, n.logger, options...); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if n.admin != nil && n.multicast != nil {
|
|
|
|
n.multicast.SetupAdminHandlers(n.admin)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|