mirror of
https://github.com/yggdrasil-network/yggdrasil-go.git
synced 2025-04-29 22:55:06 +03:00
Refactor node setup, config, defaults
This commit is contained in:
parent
559e31c502
commit
8be919abba
13 changed files with 395 additions and 331 deletions
|
@ -1,235 +1,36 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"context"
|
|
||||||
"crypto/ed25519"
|
"crypto/ed25519"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"strings"
|
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"golang.org/x/text/encoding/unicode"
|
|
||||||
|
|
||||||
"github.com/gologme/log"
|
"github.com/gologme/log"
|
||||||
gsyslog "github.com/hashicorp/go-syslog"
|
gsyslog "github.com/hashicorp/go-syslog"
|
||||||
"github.com/hjson/hjson-go"
|
"github.com/hjson/hjson-go"
|
||||||
"github.com/kardianos/minwinsvc"
|
|
||||||
"github.com/mitchellh/mapstructure"
|
|
||||||
|
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/address"
|
"github.com/yggdrasil-network/yggdrasil-go/src/address"
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/admin"
|
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/config"
|
"github.com/yggdrasil-network/yggdrasil-go/src/config"
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/defaults"
|
"github.com/yggdrasil-network/yggdrasil-go/src/setup"
|
||||||
|
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/core"
|
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/ipv6rwc"
|
"github.com/yggdrasil-network/yggdrasil-go/src/ipv6rwc"
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/multicast"
|
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/tuntap"
|
"github.com/yggdrasil-network/yggdrasil-go/src/tuntap"
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/version"
|
"github.com/yggdrasil-network/yggdrasil-go/src/version"
|
||||||
)
|
)
|
||||||
|
|
||||||
type node struct {
|
|
||||||
core core.Core
|
|
||||||
config *config.NodeConfig
|
|
||||||
tuntap *tuntap.TunAdapter
|
|
||||||
multicast *multicast.Multicast
|
|
||||||
admin *admin.AdminSocket
|
|
||||||
}
|
|
||||||
|
|
||||||
func readConfig(log *log.Logger, useconf bool, useconffile string, normaliseconf bool) *config.NodeConfig {
|
|
||||||
// Use a configuration file. If -useconf, the configuration will be read
|
|
||||||
// from stdin. If -useconffile, the configuration will be read from the
|
|
||||||
// filesystem.
|
|
||||||
var conf []byte
|
|
||||||
var err error
|
|
||||||
if useconffile != "" {
|
|
||||||
// Read the file from the filesystem
|
|
||||||
conf, err = ioutil.ReadFile(useconffile)
|
|
||||||
} else {
|
|
||||||
// Read the file from stdin.
|
|
||||||
conf, err = ioutil.ReadAll(os.Stdin)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
// If there's a byte order mark - which Windows 10 is now incredibly fond of
|
|
||||||
// throwing everywhere when it's converting things into UTF-16 for the hell
|
|
||||||
// of it - remove it and decode back down into UTF-8. This is necessary
|
|
||||||
// because hjson doesn't know what to do with UTF-16 and will panic
|
|
||||||
if bytes.Equal(conf[0:2], []byte{0xFF, 0xFE}) ||
|
|
||||||
bytes.Equal(conf[0:2], []byte{0xFE, 0xFF}) {
|
|
||||||
utf := unicode.UTF16(unicode.BigEndian, unicode.UseBOM)
|
|
||||||
decoder := utf.NewDecoder()
|
|
||||||
conf, err = decoder.Bytes(conf)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Generate a new configuration - this gives us a set of sane defaults -
|
|
||||||
// then parse the configuration we loaded above on top of it. The effect
|
|
||||||
// of this is that any configuration item that is missing from the provided
|
|
||||||
// configuration will use a sane default.
|
|
||||||
cfg := defaults.GenerateConfig()
|
|
||||||
var dat map[string]interface{}
|
|
||||||
if err := hjson.Unmarshal(conf, &dat); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
// Check if we have old field names
|
|
||||||
if _, ok := dat["TunnelRouting"]; ok {
|
|
||||||
log.Warnln("WARNING: Tunnel routing is no longer supported")
|
|
||||||
}
|
|
||||||
if old, ok := dat["SigningPrivateKey"]; ok {
|
|
||||||
log.Warnln("WARNING: The \"SigningPrivateKey\" configuration option has been renamed to \"PrivateKey\"")
|
|
||||||
if _, ok := dat["PrivateKey"]; !ok {
|
|
||||||
if privstr, err := hex.DecodeString(old.(string)); err == nil {
|
|
||||||
priv := ed25519.PrivateKey(privstr)
|
|
||||||
pub := priv.Public().(ed25519.PublicKey)
|
|
||||||
dat["PrivateKey"] = hex.EncodeToString(priv[:])
|
|
||||||
dat["PublicKey"] = hex.EncodeToString(pub[:])
|
|
||||||
} else {
|
|
||||||
log.Warnln("WARNING: The \"SigningPrivateKey\" configuration option contains an invalid value and will be ignored")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if oldmc, ok := dat["MulticastInterfaces"]; ok {
|
|
||||||
if oldmcvals, ok := oldmc.([]interface{}); ok {
|
|
||||||
var newmc []config.MulticastInterfaceConfig
|
|
||||||
for _, oldmcval := range oldmcvals {
|
|
||||||
if str, ok := oldmcval.(string); ok {
|
|
||||||
newmc = append(newmc, config.MulticastInterfaceConfig{
|
|
||||||
Regex: str,
|
|
||||||
Beacon: true,
|
|
||||||
Listen: true,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if newmc != nil {
|
|
||||||
if oldport, ok := dat["LinkLocalTCPPort"]; ok {
|
|
||||||
// numbers parse to float64 by default
|
|
||||||
if port, ok := oldport.(float64); ok {
|
|
||||||
for idx := range newmc {
|
|
||||||
newmc[idx].Port = uint16(port)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dat["MulticastInterfaces"] = newmc
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Sanitise the config
|
|
||||||
confJson, err := json.Marshal(dat)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
if err := json.Unmarshal(confJson, &cfg); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
// Overlay our newly mapped configuration onto the autoconf node config that
|
|
||||||
// we generated above.
|
|
||||||
if err = mapstructure.Decode(dat, &cfg); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return cfg
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generates a new configuration and returns it in HJSON format. This is used
|
|
||||||
// with -genconf.
|
|
||||||
func doGenconf(isjson bool) string {
|
|
||||||
cfg := defaults.GenerateConfig()
|
|
||||||
var bs []byte
|
|
||||||
var err error
|
|
||||||
if isjson {
|
|
||||||
bs, err = json.MarshalIndent(cfg, "", " ")
|
|
||||||
} else {
|
|
||||||
bs, err = hjson.Marshal(cfg)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return string(bs)
|
|
||||||
}
|
|
||||||
|
|
||||||
func setLogLevel(loglevel string, logger *log.Logger) {
|
|
||||||
levels := [...]string{"error", "warn", "info", "debug", "trace"}
|
|
||||||
loglevel = strings.ToLower(loglevel)
|
|
||||||
|
|
||||||
contains := func() bool {
|
|
||||||
for _, l := range levels {
|
|
||||||
if l == loglevel {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if !contains() { // set default log level
|
|
||||||
logger.Infoln("Loglevel parse failed. Set default level(info)")
|
|
||||||
loglevel = "info"
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, l := range levels {
|
|
||||||
logger.EnableLevel(l)
|
|
||||||
if l == loglevel {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type yggArgs struct {
|
|
||||||
genconf bool
|
|
||||||
useconf bool
|
|
||||||
normaliseconf bool
|
|
||||||
confjson bool
|
|
||||||
autoconf bool
|
|
||||||
ver bool
|
|
||||||
getaddr bool
|
|
||||||
getsnet bool
|
|
||||||
useconffile string
|
|
||||||
logto string
|
|
||||||
loglevel string
|
|
||||||
}
|
|
||||||
|
|
||||||
func getArgs() yggArgs {
|
|
||||||
genconf := flag.Bool("genconf", false, "print a new config to stdout")
|
|
||||||
useconf := flag.Bool("useconf", false, "read HJSON/JSON config from stdin")
|
|
||||||
useconffile := flag.String("useconffile", "", "read HJSON/JSON config from specified file path")
|
|
||||||
normaliseconf := flag.Bool("normaliseconf", false, "use in combination with either -useconf or -useconffile, outputs your configuration normalised")
|
|
||||||
confjson := flag.Bool("json", false, "print configuration from -genconf or -normaliseconf as JSON instead of HJSON")
|
|
||||||
autoconf := flag.Bool("autoconf", false, "automatic mode (dynamic IP, peer with IPv6 neighbors)")
|
|
||||||
ver := flag.Bool("version", false, "prints the version of this build")
|
|
||||||
logto := flag.String("logto", "stdout", "file path to log to, \"syslog\" or \"stdout\"")
|
|
||||||
getaddr := flag.Bool("address", false, "returns the IPv6 address as derived from the supplied configuration")
|
|
||||||
getsnet := flag.Bool("subnet", false, "returns the IPv6 subnet as derived from the supplied configuration")
|
|
||||||
loglevel := flag.String("loglevel", "info", "loglevel to enable")
|
|
||||||
flag.Parse()
|
|
||||||
return yggArgs{
|
|
||||||
genconf: *genconf,
|
|
||||||
useconf: *useconf,
|
|
||||||
useconffile: *useconffile,
|
|
||||||
normaliseconf: *normaliseconf,
|
|
||||||
confjson: *confjson,
|
|
||||||
autoconf: *autoconf,
|
|
||||||
ver: *ver,
|
|
||||||
logto: *logto,
|
|
||||||
getaddr: *getaddr,
|
|
||||||
getsnet: *getsnet,
|
|
||||||
loglevel: *loglevel,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// The main function is responsible for configuring and starting Yggdrasil.
|
// The main function is responsible for configuring and starting Yggdrasil.
|
||||||
func run(args yggArgs, ctx context.Context, done chan struct{}) {
|
func main() {
|
||||||
defer close(done)
|
args := setup.ParseArguments()
|
||||||
|
|
||||||
// Create a new logger that logs output to stdout.
|
// Create a new logger that logs output to stdout.
|
||||||
var logger *log.Logger
|
var logger *log.Logger
|
||||||
switch args.logto {
|
switch args.LogTo {
|
||||||
case "stdout":
|
case "stdout":
|
||||||
logger = log.New(os.Stdout, "", log.Flags())
|
logger = log.New(os.Stdout, "", log.Flags())
|
||||||
case "syslog":
|
case "syslog":
|
||||||
|
@ -237,7 +38,7 @@ func run(args yggArgs, ctx context.Context, done chan struct{}) {
|
||||||
logger = log.New(syslogger, "", log.Flags())
|
logger = log.New(syslogger, "", log.Flags())
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
if logfd, err := os.OpenFile(args.logto, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644); err == nil {
|
if logfd, err := os.OpenFile(args.LogTo, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644); err == nil {
|
||||||
logger = log.New(logfd, "", log.Flags())
|
logger = log.New(logfd, "", log.Flags())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -246,33 +47,27 @@ func run(args yggArgs, ctx context.Context, done chan struct{}) {
|
||||||
logger.Warnln("Logging defaulting to stdout")
|
logger.Warnln("Logging defaulting to stdout")
|
||||||
}
|
}
|
||||||
|
|
||||||
if args.normaliseconf {
|
|
||||||
setLogLevel("error", logger)
|
|
||||||
} else {
|
|
||||||
setLogLevel(args.loglevel, logger)
|
|
||||||
}
|
|
||||||
|
|
||||||
var cfg *config.NodeConfig
|
var cfg *config.NodeConfig
|
||||||
var err error
|
var err error
|
||||||
switch {
|
switch {
|
||||||
case args.ver:
|
case args.Version:
|
||||||
fmt.Println("Build name:", version.BuildName())
|
fmt.Println("Build name:", version.BuildName())
|
||||||
fmt.Println("Build version:", version.BuildVersion())
|
fmt.Println("Build version:", version.BuildVersion())
|
||||||
return
|
return
|
||||||
case args.autoconf:
|
case args.AutoConf:
|
||||||
// Use an autoconf-generated config, this will give us random keys and
|
// Use an autoconf-generated config, this will give us random keys and
|
||||||
// port numbers, and will use an automatically selected TUN/TAP interface.
|
// port numbers, and will use an automatically selected TUN/TAP interface.
|
||||||
cfg = defaults.GenerateConfig()
|
cfg = config.GenerateConfig()
|
||||||
case args.useconffile != "" || args.useconf:
|
case args.UseConfFile != "" || args.UseConf:
|
||||||
// Read the configuration from either stdin or from the filesystem
|
// Read the configuration from either stdin or from the filesystem
|
||||||
cfg = readConfig(logger, args.useconf, args.useconffile, args.normaliseconf)
|
cfg = setup.ReadConfig(logger, args.UseConf, args.UseConfFile, args.NormaliseConf)
|
||||||
// If the -normaliseconf option was specified then remarshal the above
|
// If the -normaliseconf option was specified then remarshal the above
|
||||||
// configuration and print it back to stdout. This lets the user update
|
// configuration and print it back to stdout. This lets the user update
|
||||||
// their configuration file with newly mapped names (like above) or to
|
// their configuration file with newly mapped names (like above) or to
|
||||||
// convert from plain JSON to commented HJSON.
|
// convert from plain JSON to commented HJSON.
|
||||||
if args.normaliseconf {
|
if args.NormaliseConf {
|
||||||
var bs []byte
|
var bs []byte
|
||||||
if args.confjson {
|
if args.ConfJSON {
|
||||||
bs, err = json.MarshalIndent(cfg, "", " ")
|
bs, err = json.MarshalIndent(cfg, "", " ")
|
||||||
} else {
|
} else {
|
||||||
bs, err = hjson.Marshal(cfg)
|
bs, err = hjson.Marshal(cfg)
|
||||||
|
@ -283,9 +78,9 @@ func run(args yggArgs, ctx context.Context, done chan struct{}) {
|
||||||
fmt.Println(string(bs))
|
fmt.Println(string(bs))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
case args.genconf:
|
case args.GenConf:
|
||||||
// Generate a new configuration and print it to stdout.
|
// Generate a new configuration and print it to stdout.
|
||||||
fmt.Println(doGenconf(args.confjson))
|
fmt.Println(config.GenerateConfigJSON(args.ConfJSON))
|
||||||
return
|
return
|
||||||
default:
|
default:
|
||||||
// No flags were provided, therefore print the list of flags to stdout.
|
// No flags were provided, therefore print the list of flags to stdout.
|
||||||
|
@ -297,6 +92,11 @@ func run(args yggArgs, ctx context.Context, done chan struct{}) {
|
||||||
if cfg == nil {
|
if cfg == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create a new standalone node
|
||||||
|
n := setup.NewNode(cfg, logger)
|
||||||
|
n.SetLogLevel(args.LogLevel)
|
||||||
|
|
||||||
// Have we been asked for the node address yet? If so, print it and then stop.
|
// Have we been asked for the node address yet? If so, print it and then stop.
|
||||||
getNodeKey := func() ed25519.PublicKey {
|
getNodeKey := func() ed25519.PublicKey {
|
||||||
if pubkey, err := hex.DecodeString(cfg.PrivateKey); err == nil {
|
if pubkey, err := hex.DecodeString(cfg.PrivateKey); err == nil {
|
||||||
|
@ -305,14 +105,14 @@ func run(args yggArgs, ctx context.Context, done chan struct{}) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
switch {
|
switch {
|
||||||
case args.getaddr:
|
case args.GetAddr:
|
||||||
if key := getNodeKey(); key != nil {
|
if key := getNodeKey(); key != nil {
|
||||||
addr := address.AddrForKey(key)
|
addr := address.AddrForKey(key)
|
||||||
ip := net.IP(addr[:])
|
ip := net.IP(addr[:])
|
||||||
fmt.Println(ip.String())
|
fmt.Println(ip.String())
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
case args.getsnet:
|
case args.GetSubnet:
|
||||||
if key := getNodeKey(); key != nil {
|
if key := getNodeKey(); key != nil {
|
||||||
snet := address.SubnetForKey(key)
|
snet := address.SubnetForKey(key)
|
||||||
ipnet := net.IPNet{
|
ipnet := net.IPNet{
|
||||||
|
@ -325,84 +125,39 @@ func run(args yggArgs, ctx context.Context, done chan struct{}) {
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup the Yggdrasil node itself. The node{} type includes a Core, so we
|
|
||||||
// don't need to create this manually.
|
|
||||||
n := node{config: cfg}
|
|
||||||
// Now start Yggdrasil - this starts the DHT, router, switch and other core
|
// Now start Yggdrasil - this starts the DHT, router, switch and other core
|
||||||
// components needed for Yggdrasil to operate
|
// components needed for Yggdrasil to operate
|
||||||
if err = n.core.Start(cfg, logger); err != nil {
|
if err = n.Run(args); err != nil {
|
||||||
logger.Errorln("An error occurred during startup")
|
logger.Fatalln(err)
|
||||||
panic(err)
|
|
||||||
}
|
}
|
||||||
// Register the session firewall gatekeeper function
|
|
||||||
// Allocate our modules
|
|
||||||
n.admin = &admin.AdminSocket{}
|
|
||||||
n.multicast = &multicast.Multicast{}
|
|
||||||
n.tuntap = &tuntap.TunAdapter{}
|
|
||||||
// Start the admin socket
|
|
||||||
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 {
|
|
||||||
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
|
// Start the TUN/TAP interface
|
||||||
rwc := ipv6rwc.NewReadWriteCloser(&n.core)
|
tuntap := &tuntap.TunAdapter{}
|
||||||
if err := n.tuntap.Init(rwc, cfg, logger, nil); err != nil {
|
rwc := ipv6rwc.NewReadWriteCloser(&n.Core)
|
||||||
|
if err := 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 := tuntap.Start(); err != nil {
|
||||||
logger.Errorln("An error occurred starting TUN/TAP:", err)
|
logger.Errorln("An error occurred starting TUN/TAP:", err)
|
||||||
}
|
}
|
||||||
n.tuntap.SetupAdminHandlers(n.admin)
|
tuntap.SetupAdminHandlers(n.Admin())
|
||||||
|
|
||||||
// Make some nice output that tells us what our IPv6 address and subnet are.
|
// Make some nice output that tells us what our IPv6 address and subnet are.
|
||||||
// This is just logged to stdout for the user.
|
// This is just logged to stdout for the user.
|
||||||
address := n.core.Address()
|
address := n.Address()
|
||||||
subnet := n.core.Subnet()
|
subnet := n.Subnet()
|
||||||
public := n.core.GetSelf().Key
|
public := n.GetSelf().Key
|
||||||
logger.Infof("Your public key is %s", hex.EncodeToString(public[:]))
|
logger.Infof("Your public key is %s", hex.EncodeToString(public[:]))
|
||||||
logger.Infof("Your IPv6 address is %s", address.String())
|
logger.Infof("Your IPv6 address is %s", address.String())
|
||||||
logger.Infof("Your IPv6 subnet is %s", subnet.String())
|
logger.Infof("Your IPv6 subnet is %s", subnet.String())
|
||||||
// Catch interrupts from the operating system to exit gracefully.
|
|
||||||
<-ctx.Done()
|
|
||||||
// Capture the service being stopped on Windows.
|
|
||||||
minwinsvc.SetOnExit(n.shutdown)
|
|
||||||
n.shutdown()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *node) shutdown() {
|
|
||||||
_ = n.admin.Stop()
|
|
||||||
_ = n.multicast.Stop()
|
|
||||||
_ = n.tuntap.Stop()
|
|
||||||
n.core.Stop()
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
args := getArgs()
|
|
||||||
hup := make(chan os.Signal, 1)
|
|
||||||
//signal.Notify(hup, os.Interrupt, syscall.SIGHUP)
|
|
||||||
term := make(chan os.Signal, 1)
|
term := make(chan os.Signal, 1)
|
||||||
signal.Notify(term, os.Interrupt, syscall.SIGTERM)
|
signal.Notify(term, os.Interrupt, syscall.SIGTERM)
|
||||||
for {
|
|
||||||
done := make(chan struct{})
|
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
|
||||||
go run(args, ctx, done)
|
|
||||||
select {
|
select {
|
||||||
case <-hup:
|
case <-n.Done():
|
||||||
cancel()
|
|
||||||
<-done
|
|
||||||
case <-term:
|
case <-term:
|
||||||
cancel()
|
|
||||||
<-done
|
|
||||||
return
|
|
||||||
case <-done:
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
n.Close()
|
||||||
|
_ = tuntap.Stop()
|
||||||
}
|
}
|
||||||
|
|
3
go.mod
3
go.mod
|
@ -9,6 +9,7 @@ require (
|
||||||
github.com/cheggaaa/pb/v3 v3.0.8
|
github.com/cheggaaa/pb/v3 v3.0.8
|
||||||
github.com/fatih/color v1.12.0 // indirect
|
github.com/fatih/color v1.12.0 // indirect
|
||||||
github.com/gologme/log v1.2.0
|
github.com/gologme/log v1.2.0
|
||||||
|
github.com/google/btree v1.0.1 // indirect
|
||||||
github.com/hashicorp/go-syslog v1.0.0
|
github.com/hashicorp/go-syslog v1.0.0
|
||||||
github.com/hjson/hjson-go v3.1.0+incompatible
|
github.com/hjson/hjson-go v3.1.0+incompatible
|
||||||
github.com/kardianos/minwinsvc v1.0.0
|
github.com/kardianos/minwinsvc v1.0.0
|
||||||
|
@ -21,6 +22,8 @@ require (
|
||||||
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
|
||||||
|
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 // indirect
|
||||||
golang.zx2c4.com/wireguard v0.0.0-20211017052713-f87e87af0d9a
|
golang.zx2c4.com/wireguard v0.0.0-20211017052713-f87e87af0d9a
|
||||||
golang.zx2c4.com/wireguard/windows v0.4.12
|
golang.zx2c4.com/wireguard/windows v0.4.12
|
||||||
|
inet.af/netstack v0.0.0-20211120045802-8aa80cf23d3c
|
||||||
)
|
)
|
||||||
|
|
6
go.sum
6
go.sum
|
@ -13,6 +13,8 @@ github.com/fatih/color v1.12.0 h1:mRhaKNwANqRgUBGKmnI5ZxEk7QXmjQeCcuYFMX2bfcc=
|
||||||
github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
|
github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
|
||||||
github.com/gologme/log v1.2.0 h1:Ya5Ip/KD6FX7uH0S31QO87nCCSucKtF44TLbTtO7V4c=
|
github.com/gologme/log v1.2.0 h1:Ya5Ip/KD6FX7uH0S31QO87nCCSucKtF44TLbTtO7V4c=
|
||||||
github.com/gologme/log v1.2.0/go.mod h1:gq31gQ8wEHkR+WekdWsqDuf8pXTUZA9BnnzTuPz1Y9U=
|
github.com/gologme/log v1.2.0/go.mod h1:gq31gQ8wEHkR+WekdWsqDuf8pXTUZA9BnnzTuPz1Y9U=
|
||||||
|
github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4=
|
||||||
|
github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
|
||||||
github.com/hashicorp/go-syslog v1.0.0 h1:KaodqZuhUoZereWVIYmpUgZysurB1kBLX2j0MwMrUAE=
|
github.com/hashicorp/go-syslog v1.0.0 h1:KaodqZuhUoZereWVIYmpUgZysurB1kBLX2j0MwMrUAE=
|
||||||
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
|
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
|
||||||
github.com/hjson/hjson-go v3.1.0+incompatible h1:DY/9yE8ey8Zv22bY+mHV1uk2yRy0h8tKhZ77hEdi0Aw=
|
github.com/hjson/hjson-go v3.1.0+incompatible h1:DY/9yE8ey8Zv22bY+mHV1uk2yRy0h8tKhZ77hEdi0Aw=
|
||||||
|
@ -89,6 +91,8 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.8-0.20211004125949-5bd84dd9b33b h1:NXqSWXSRUSCaFuvitrWtU169I3876zRTalMRbfd6LL0=
|
golang.org/x/text v0.3.8-0.20211004125949-5bd84dd9b33b h1:NXqSWXSRUSCaFuvitrWtU169I3876zRTalMRbfd6LL0=
|
||||||
golang.org/x/text v0.3.8-0.20211004125949-5bd84dd9b33b/go.mod h1:EFNZuWvGYxIRUEX+K8UmCFwYmZjqcrnq15ZuVldZkZ0=
|
golang.org/x/text v0.3.8-0.20211004125949-5bd84dd9b33b/go.mod h1:EFNZuWvGYxIRUEX+K8UmCFwYmZjqcrnq15ZuVldZkZ0=
|
||||||
|
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 h1:GZokNIeuVkl3aZHJchRrr13WCsols02MLUcz1U9is6M=
|
||||||
|
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
@ -104,3 +108,5 @@ golang.zx2c4.com/wireguard v0.0.0-20211017052713-f87e87af0d9a h1:tTbyylK9/D3u/wE
|
||||||
golang.zx2c4.com/wireguard v0.0.0-20211017052713-f87e87af0d9a/go.mod h1:id8Oh3eCCmpj9uVGWVjsUAl6UPX5ysMLzu6QxJU2UOU=
|
golang.zx2c4.com/wireguard v0.0.0-20211017052713-f87e87af0d9a/go.mod h1:id8Oh3eCCmpj9uVGWVjsUAl6UPX5ysMLzu6QxJU2UOU=
|
||||||
golang.zx2c4.com/wireguard/windows v0.4.12 h1:CUmbdWKVNzTSsVb4yUAiEwL3KsabdJkEPdDjCHxBlhA=
|
golang.zx2c4.com/wireguard/windows v0.4.12 h1:CUmbdWKVNzTSsVb4yUAiEwL3KsabdJkEPdDjCHxBlhA=
|
||||||
golang.zx2c4.com/wireguard/windows v0.4.12/go.mod h1:PW4y+d9oY83XU9rRwRwrJDwEMuhVjMxu2gfD1cfzS7w=
|
golang.zx2c4.com/wireguard/windows v0.4.12/go.mod h1:PW4y+d9oY83XU9rRwRwrJDwEMuhVjMxu2gfD1cfzS7w=
|
||||||
|
inet.af/netstack v0.0.0-20211120045802-8aa80cf23d3c h1:nr31qYr+91rWD8klUkPx3eGTZzumCC414UJG1QRKZTc=
|
||||||
|
inet.af/netstack v0.0.0-20211120045802-8aa80cf23d3c/go.mod h1:KOJdAzQzMLKzwFEdOOnrnSrLIhaFVB+NQoME/e5wllA=
|
||||||
|
|
|
@ -19,7 +19,12 @@ package config
|
||||||
import (
|
import (
|
||||||
"crypto/ed25519"
|
"crypto/ed25519"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
|
"encoding/json"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/hjson/hjson-go"
|
||||||
|
"github.com/mitchellh/mapstructure"
|
||||||
|
"github.com/yggdrasil-network/yggdrasil-go/src/defaults"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NodeConfig is the main configuration structure, containing configuration
|
// NodeConfig is the main configuration structure, containing configuration
|
||||||
|
@ -59,3 +64,106 @@ func (cfg *NodeConfig) NewKeys() {
|
||||||
cfg.PublicKey = hex.EncodeToString(spub[:])
|
cfg.PublicKey = hex.EncodeToString(spub[:])
|
||||||
cfg.PrivateKey = hex.EncodeToString(spriv[:])
|
cfg.PrivateKey = hex.EncodeToString(spriv[:])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Generates default configuration and returns a pointer to the resulting
|
||||||
|
// NodeConfig. This is used when outputting the -genconf parameter and also when
|
||||||
|
// using -autoconf.
|
||||||
|
func GenerateConfig() *NodeConfig {
|
||||||
|
defaults := defaults.GetDefaults()
|
||||||
|
cfg := &NodeConfig{}
|
||||||
|
cfg.NewKeys()
|
||||||
|
cfg.Listen = []string{}
|
||||||
|
cfg.AdminListen = defaults.DefaultAdminListen
|
||||||
|
cfg.Peers = []string{}
|
||||||
|
cfg.InterfacePeers = map[string][]string{}
|
||||||
|
cfg.AllowedPublicKeys = []string{}
|
||||||
|
for _, regex := range defaults.DefaultMulticastInterfaces {
|
||||||
|
cfg.MulticastInterfaces = append(cfg.MulticastInterfaces, MulticastInterfaceConfig{
|
||||||
|
Regex: regex,
|
||||||
|
Beacon: true,
|
||||||
|
Listen: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
cfg.IfName = defaults.DefaultIfName
|
||||||
|
cfg.IfMTU = defaults.DefaultIfMTU
|
||||||
|
cfg.NodeInfoPrivacy = false
|
||||||
|
return cfg
|
||||||
|
}
|
||||||
|
|
||||||
|
func GenerateConfigJSON(isjson bool) []byte {
|
||||||
|
// Generates a new configuration and returns it in HJSON or JSON format.
|
||||||
|
cfg := GenerateConfig()
|
||||||
|
var bs []byte
|
||||||
|
var err error
|
||||||
|
if isjson {
|
||||||
|
bs, err = json.MarshalIndent(cfg, "", " ")
|
||||||
|
} else {
|
||||||
|
bs, err = hjson.Marshal(cfg)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return bs
|
||||||
|
}
|
||||||
|
|
||||||
|
func ReadConfig(conf []byte) *NodeConfig {
|
||||||
|
// Generate a new configuration - this gives us a set of sane defaults -
|
||||||
|
// then parse the configuration we loaded above on top of it. The effect
|
||||||
|
// of this is that any configuration item that is missing from the provided
|
||||||
|
// configuration will use a sane default.
|
||||||
|
cfg := GenerateConfig()
|
||||||
|
var dat map[string]interface{}
|
||||||
|
if err := hjson.Unmarshal(conf, &dat); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
// Check if we have old field names
|
||||||
|
if old, ok := dat["SigningPrivateKey"]; ok {
|
||||||
|
if _, ok := dat["PrivateKey"]; !ok {
|
||||||
|
if privstr, err := hex.DecodeString(old.(string)); err == nil {
|
||||||
|
priv := ed25519.PrivateKey(privstr)
|
||||||
|
pub := priv.Public().(ed25519.PublicKey)
|
||||||
|
dat["PrivateKey"] = hex.EncodeToString(priv[:])
|
||||||
|
dat["PublicKey"] = hex.EncodeToString(pub[:])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if oldmc, ok := dat["MulticastInterfaces"]; ok {
|
||||||
|
if oldmcvals, ok := oldmc.([]interface{}); ok {
|
||||||
|
var newmc []MulticastInterfaceConfig
|
||||||
|
for _, oldmcval := range oldmcvals {
|
||||||
|
if str, ok := oldmcval.(string); ok {
|
||||||
|
newmc = append(newmc, MulticastInterfaceConfig{
|
||||||
|
Regex: str,
|
||||||
|
Beacon: true,
|
||||||
|
Listen: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if newmc != nil {
|
||||||
|
if oldport, ok := dat["LinkLocalTCPPort"]; ok {
|
||||||
|
// numbers parse to float64 by default
|
||||||
|
if port, ok := oldport.(float64); ok {
|
||||||
|
for idx := range newmc {
|
||||||
|
newmc[idx].Port = uint16(port)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dat["MulticastInterfaces"] = newmc
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Sanitise the config
|
||||||
|
confJson, err := json.Marshal(dat)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(confJson, &cfg); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
// Overlay our newly mapped configuration onto the autoconf node config that
|
||||||
|
// we generated above.
|
||||||
|
if err = mapstructure.Decode(dat, &cfg); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return cfg
|
||||||
|
}
|
||||||
|
|
|
@ -11,12 +11,11 @@ import (
|
||||||
"github.com/gologme/log"
|
"github.com/gologme/log"
|
||||||
|
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/config"
|
"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.
|
// GenerateConfig produces default configuration with suitable modifications for tests.
|
||||||
func GenerateConfig() *config.NodeConfig {
|
func GenerateConfig() *config.NodeConfig {
|
||||||
cfg := defaults.GenerateConfig()
|
cfg := config.GenerateConfig()
|
||||||
cfg.AdminListen = "none"
|
cfg.AdminListen = "none"
|
||||||
cfg.Listen = []string{"tcp://127.0.0.1:0"}
|
cfg.Listen = []string{"tcp://127.0.0.1:0"}
|
||||||
cfg.IfName = "none"
|
cfg.IfName = "none"
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
package defaults
|
package defaults
|
||||||
|
|
||||||
import "github.com/yggdrasil-network/yggdrasil-go/src/config"
|
type MulticastInterfaceConfig struct {
|
||||||
|
Regex string
|
||||||
type MulticastInterfaceConfig = config.MulticastInterfaceConfig
|
Beacon bool
|
||||||
|
Listen bool
|
||||||
|
Port uint16
|
||||||
|
}
|
||||||
|
|
||||||
// Defines which parameters are expected by default for configuration on a
|
// Defines which parameters are expected by default for configuration on a
|
||||||
// specific platform. These values are populated in the relevant defaults_*.go
|
// specific platform. These values are populated in the relevant defaults_*.go
|
||||||
|
@ -15,30 +18,10 @@ type platformDefaultParameters struct {
|
||||||
DefaultConfigFile string
|
DefaultConfigFile string
|
||||||
|
|
||||||
// Multicast interfaces
|
// Multicast interfaces
|
||||||
DefaultMulticastInterfaces []MulticastInterfaceConfig
|
DefaultMulticastInterfaces []string
|
||||||
|
|
||||||
// TUN/TAP
|
// TUN/TAP
|
||||||
MaximumIfMTU uint64
|
MaximumIfMTU uint64
|
||||||
DefaultIfMTU uint64
|
DefaultIfMTU uint64
|
||||||
DefaultIfName string
|
DefaultIfName string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generates default configuration and returns a pointer to the resulting
|
|
||||||
// NodeConfig. This is used when outputting the -genconf parameter and also when
|
|
||||||
// using -autoconf.
|
|
||||||
func GenerateConfig() *config.NodeConfig {
|
|
||||||
// Create a node configuration and populate it.
|
|
||||||
cfg := new(config.NodeConfig)
|
|
||||||
cfg.NewKeys()
|
|
||||||
cfg.Listen = []string{}
|
|
||||||
cfg.AdminListen = GetDefaults().DefaultAdminListen
|
|
||||||
cfg.Peers = []string{}
|
|
||||||
cfg.InterfacePeers = map[string][]string{}
|
|
||||||
cfg.AllowedPublicKeys = []string{}
|
|
||||||
cfg.MulticastInterfaces = GetDefaults().DefaultMulticastInterfaces
|
|
||||||
cfg.IfName = GetDefaults().DefaultIfName
|
|
||||||
cfg.IfMTU = GetDefaults().DefaultIfMTU
|
|
||||||
cfg.NodeInfoPrivacy = false
|
|
||||||
|
|
||||||
return cfg
|
|
||||||
}
|
|
||||||
|
|
|
@ -14,10 +14,7 @@ func GetDefaults() platformDefaultParameters {
|
||||||
DefaultConfigFile: "/etc/yggdrasil.conf",
|
DefaultConfigFile: "/etc/yggdrasil.conf",
|
||||||
|
|
||||||
// Multicast interfaces
|
// Multicast interfaces
|
||||||
DefaultMulticastInterfaces: []MulticastInterfaceConfig{
|
DefaultMulticastInterfaces: []string{"en.*", "bridge.*"},
|
||||||
{Regex: "en.*", Beacon: true, Listen: true},
|
|
||||||
{Regex: "bridge.*", Beacon: true, Listen: true},
|
|
||||||
},
|
|
||||||
|
|
||||||
// TUN/TAP
|
// TUN/TAP
|
||||||
MaximumIfMTU: 65535,
|
MaximumIfMTU: 65535,
|
||||||
|
|
|
@ -14,9 +14,7 @@ func GetDefaults() platformDefaultParameters {
|
||||||
DefaultConfigFile: "/usr/local/etc/yggdrasil.conf",
|
DefaultConfigFile: "/usr/local/etc/yggdrasil.conf",
|
||||||
|
|
||||||
// Multicast interfaces
|
// Multicast interfaces
|
||||||
DefaultMulticastInterfaces: []MulticastInterfaceConfig{
|
DefaultMulticastInterfaces: []string{".*"},
|
||||||
{Regex: ".*", Beacon: true, Listen: true},
|
|
||||||
},
|
|
||||||
|
|
||||||
// TUN/TAP
|
// TUN/TAP
|
||||||
MaximumIfMTU: 32767,
|
MaximumIfMTU: 32767,
|
||||||
|
|
|
@ -14,9 +14,7 @@ func GetDefaults() platformDefaultParameters {
|
||||||
DefaultConfigFile: "/etc/yggdrasil.conf",
|
DefaultConfigFile: "/etc/yggdrasil.conf",
|
||||||
|
|
||||||
// Multicast interfaces
|
// Multicast interfaces
|
||||||
DefaultMulticastInterfaces: []MulticastInterfaceConfig{
|
DefaultMulticastInterfaces: []string{".*"},
|
||||||
{Regex: ".*", Beacon: true, Listen: true},
|
|
||||||
},
|
|
||||||
|
|
||||||
// TUN/TAP
|
// TUN/TAP
|
||||||
MaximumIfMTU: 65535,
|
MaximumIfMTU: 65535,
|
||||||
|
|
|
@ -14,9 +14,7 @@ func GetDefaults() platformDefaultParameters {
|
||||||
DefaultConfigFile: "/etc/yggdrasil.conf",
|
DefaultConfigFile: "/etc/yggdrasil.conf",
|
||||||
|
|
||||||
// Multicast interfaces
|
// Multicast interfaces
|
||||||
DefaultMulticastInterfaces: []MulticastInterfaceConfig{
|
DefaultMulticastInterfaces: []string{".*"},
|
||||||
{Regex: ".*", Beacon: true, Listen: true},
|
|
||||||
},
|
|
||||||
|
|
||||||
// TUN/TAP
|
// TUN/TAP
|
||||||
MaximumIfMTU: 16384,
|
MaximumIfMTU: 16384,
|
||||||
|
|
|
@ -14,9 +14,7 @@ func GetDefaults() platformDefaultParameters {
|
||||||
DefaultConfigFile: "/etc/yggdrasil.conf",
|
DefaultConfigFile: "/etc/yggdrasil.conf",
|
||||||
|
|
||||||
// Multicast interfaces
|
// Multicast interfaces
|
||||||
DefaultMulticastInterfaces: []MulticastInterfaceConfig{
|
DefaultMulticastInterfaces: []string{".*"},
|
||||||
{Regex: ".*", Beacon: true, Listen: true},
|
|
||||||
},
|
|
||||||
|
|
||||||
// TUN/TAP
|
// TUN/TAP
|
||||||
MaximumIfMTU: 65535,
|
MaximumIfMTU: 65535,
|
||||||
|
|
|
@ -14,9 +14,7 @@ func GetDefaults() platformDefaultParameters {
|
||||||
DefaultConfigFile: "C:\\Program Files\\Yggdrasil\\yggdrasil.conf",
|
DefaultConfigFile: "C:\\Program Files\\Yggdrasil\\yggdrasil.conf",
|
||||||
|
|
||||||
// Multicast interfaces
|
// Multicast interfaces
|
||||||
DefaultMulticastInterfaces: []MulticastInterfaceConfig{
|
DefaultMulticastInterfaces: []string{".*"},
|
||||||
{Regex: ".*", Beacon: true, Listen: true},
|
|
||||||
},
|
|
||||||
|
|
||||||
// TUN/TAP
|
// TUN/TAP
|
||||||
MaximumIfMTU: 65535,
|
MaximumIfMTU: 65535,
|
||||||
|
|
223
src/setup/setup.go
Normal file
223
src/setup/setup.go
Normal file
|
@ -0,0 +1,223 @@
|
||||||
|
package setup
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"crypto/ed25519"
|
||||||
|
"encoding/hex"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/gologme/log"
|
||||||
|
"github.com/yggdrasil-network/yggdrasil-go/src/address"
|
||||||
|
"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"
|
||||||
|
"golang.org/x/text/encoding/unicode"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Node struct {
|
||||||
|
core.Core
|
||||||
|
ctx context.Context
|
||||||
|
cancel context.CancelFunc
|
||||||
|
logger *log.Logger
|
||||||
|
config *config.NodeConfig
|
||||||
|
multicast *multicast.Multicast
|
||||||
|
admin *admin.AdminSocket
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewNode(cfg *config.NodeConfig, logger *log.Logger) *Node {
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
return &Node{
|
||||||
|
ctx: ctx,
|
||||||
|
cancel: cancel,
|
||||||
|
logger: logger,
|
||||||
|
config: cfg,
|
||||||
|
multicast: &multicast.Multicast{},
|
||||||
|
admin: &admin.AdminSocket{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *Node) Close() {
|
||||||
|
n.cancel()
|
||||||
|
_ = n.multicast.Stop()
|
||||||
|
_ = n.admin.Stop()
|
||||||
|
_ = n.Core.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *Node) Done() <-chan struct{} {
|
||||||
|
return n.ctx.Done()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *Node) Admin() *admin.AdminSocket {
|
||||||
|
return n.admin
|
||||||
|
}
|
||||||
|
|
||||||
|
// The main function is responsible for configuring and starting Yggdrasil.
|
||||||
|
func (n *Node) Run(args Arguments) error {
|
||||||
|
// Have we got a working configuration? If we don't then it probably means
|
||||||
|
// that neither -autoconf, -useconf or -useconffile were set above. Stop
|
||||||
|
// if we don't.
|
||||||
|
if n.config == nil {
|
||||||
|
return fmt.Errorf("no configuration supplied")
|
||||||
|
}
|
||||||
|
// Have we been asked for the node address yet? If so, print it and then stop.
|
||||||
|
getNodeKey := func() ed25519.PublicKey {
|
||||||
|
if pubkey, err := hex.DecodeString(n.config.PrivateKey); err == nil {
|
||||||
|
return ed25519.PrivateKey(pubkey).Public().(ed25519.PublicKey)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
switch {
|
||||||
|
case args.GetAddr:
|
||||||
|
if key := getNodeKey(); key != nil {
|
||||||
|
addr := address.AddrForKey(key)
|
||||||
|
ip := net.IP(addr[:])
|
||||||
|
fmt.Println(ip.String())
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
case args.GetSubnet:
|
||||||
|
if key := getNodeKey(); key != nil {
|
||||||
|
snet := address.SubnetForKey(key)
|
||||||
|
ipnet := net.IPNet{
|
||||||
|
IP: append(snet[:], 0, 0, 0, 0, 0, 0, 0, 0),
|
||||||
|
Mask: net.CIDRMask(len(snet)*8, 128),
|
||||||
|
}
|
||||||
|
fmt.Println(ipnet.String())
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now start Yggdrasil - this starts the DHT, router, switch and other core
|
||||||
|
// components needed for Yggdrasil to operate
|
||||||
|
if err := n.Core.Start(n.config, n.logger); err != nil {
|
||||||
|
return fmt.Errorf("n.core.Start: %w", err)
|
||||||
|
}
|
||||||
|
// Register the session firewall gatekeeper function
|
||||||
|
// Allocate our modules
|
||||||
|
|
||||||
|
// Start the admin socket
|
||||||
|
n.admin = &admin.AdminSocket{}
|
||||||
|
if err := n.admin.Init(&n.Core, n.config, n.logger, nil); err != nil {
|
||||||
|
return fmt.Errorf("n.admin.Init: %w", err)
|
||||||
|
} else if err := n.admin.Start(); err != nil {
|
||||||
|
return fmt.Errorf("n.admin.Start: %w", err)
|
||||||
|
}
|
||||||
|
n.admin.SetupAdminHandlers(n.admin)
|
||||||
|
|
||||||
|
// Start the multicast interface
|
||||||
|
if err := n.multicast.Init(&n.Core, n.config, n.logger, nil); err != nil {
|
||||||
|
return fmt.Errorf("n.multicast.Init: %w", err)
|
||||||
|
} else if err := n.multicast.Start(); err != nil {
|
||||||
|
return fmt.Errorf("n.admin.Start: %w", err)
|
||||||
|
}
|
||||||
|
n.multicast.SetupAdminHandlers(n.admin)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *Node) SetLogLevel(loglevel string) {
|
||||||
|
levels := [...]string{"error", "warn", "info", "debug", "trace"}
|
||||||
|
loglevel = strings.ToLower(loglevel)
|
||||||
|
|
||||||
|
contains := func() bool {
|
||||||
|
for _, l := range levels {
|
||||||
|
if l == loglevel {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if !contains() { // set default log level
|
||||||
|
n.logger.Infoln("Loglevel parse failed. Set default level(info)")
|
||||||
|
loglevel = "info"
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, l := range levels {
|
||||||
|
n.logger.EnableLevel(l)
|
||||||
|
if l == loglevel {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ReadConfig(log *log.Logger, useconf bool, useconffile string, normaliseconf bool) *config.NodeConfig {
|
||||||
|
// Use a configuration file. If -useconf, the configuration will be read
|
||||||
|
// from stdin. If -useconffile, the configuration will be read from the
|
||||||
|
// filesystem.
|
||||||
|
var conf []byte
|
||||||
|
var err error
|
||||||
|
if useconffile != "" {
|
||||||
|
// Read the file from the filesystem
|
||||||
|
conf, err = ioutil.ReadFile(useconffile)
|
||||||
|
} else {
|
||||||
|
// Read the file from stdin.
|
||||||
|
conf, err = ioutil.ReadAll(os.Stdin)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
// If there's a byte order mark - which Windows 10 is now incredibly fond of
|
||||||
|
// throwing everywhere when it's converting things into UTF-16 for the hell
|
||||||
|
// of it - remove it and decode back down into UTF-8. This is necessary
|
||||||
|
// because hjson doesn't know what to do with UTF-16 and will panic
|
||||||
|
if bytes.Equal(conf[0:2], []byte{0xFF, 0xFE}) ||
|
||||||
|
bytes.Equal(conf[0:2], []byte{0xFE, 0xFF}) {
|
||||||
|
utf := unicode.UTF16(unicode.BigEndian, unicode.UseBOM)
|
||||||
|
decoder := utf.NewDecoder()
|
||||||
|
conf, err = decoder.Bytes(conf)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return config.ReadConfig(conf)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Arguments struct {
|
||||||
|
GenConf bool
|
||||||
|
UseConf bool
|
||||||
|
NormaliseConf bool
|
||||||
|
ConfJSON bool
|
||||||
|
AutoConf bool
|
||||||
|
Version bool
|
||||||
|
GetAddr bool
|
||||||
|
GetSubnet bool
|
||||||
|
UseConfFile string
|
||||||
|
LogTo string
|
||||||
|
LogLevel string
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseArguments() Arguments {
|
||||||
|
genconf := flag.Bool("genconf", false, "print a new config to stdout")
|
||||||
|
useconf := flag.Bool("useconf", false, "read HJSON/JSON config from stdin")
|
||||||
|
useconffile := flag.String("useconffile", "", "read HJSON/JSON config from specified file path")
|
||||||
|
normaliseconf := flag.Bool("normaliseconf", false, "use in combination with either -useconf or -useconffile, outputs your configuration normalised")
|
||||||
|
confjson := flag.Bool("json", false, "print configuration from -genconf or -normaliseconf as JSON instead of HJSON")
|
||||||
|
autoconf := flag.Bool("autoconf", false, "automatic mode (dynamic IP, peer with IPv6 neighbors)")
|
||||||
|
ver := flag.Bool("version", false, "prints the version of this build")
|
||||||
|
logto := flag.String("logto", "stdout", "file path to log to, \"syslog\" or \"stdout\"")
|
||||||
|
getaddr := flag.Bool("address", false, "returns the IPv6 address as derived from the supplied configuration")
|
||||||
|
getsnet := flag.Bool("subnet", false, "returns the IPv6 subnet as derived from the supplied configuration")
|
||||||
|
loglevel := flag.String("loglevel", "info", "loglevel to enable")
|
||||||
|
flag.Parse()
|
||||||
|
return Arguments{
|
||||||
|
GenConf: *genconf,
|
||||||
|
UseConf: *useconf,
|
||||||
|
UseConfFile: *useconffile,
|
||||||
|
NormaliseConf: *normaliseconf,
|
||||||
|
ConfJSON: *confjson,
|
||||||
|
AutoConf: *autoconf,
|
||||||
|
Version: *ver,
|
||||||
|
LogTo: *logto,
|
||||||
|
GetAddr: *getaddr,
|
||||||
|
GetSubnet: *getsnet,
|
||||||
|
LogLevel: *loglevel,
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue