mirror of
https://github.com/yggdrasil-network/yggdrasil-go.git
synced 2025-04-30 15:15:07 +03:00
Simplify configuration code throughout
This commit is contained in:
parent
174ebceaac
commit
029be2d86b
17 changed files with 223 additions and 209 deletions
|
@ -18,7 +18,6 @@ import (
|
||||||
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/kardianos/minwinsvc"
|
||||||
"github.com/mitchellh/mapstructure"
|
|
||||||
|
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/admin"
|
"github.com/yggdrasil-network/yggdrasil-go/src/admin"
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/config"
|
"github.com/yggdrasil-network/yggdrasil-go/src/config"
|
||||||
|
@ -31,7 +30,6 @@ import (
|
||||||
|
|
||||||
type node struct {
|
type node struct {
|
||||||
core yggdrasil.Core
|
core yggdrasil.Core
|
||||||
state *config.NodeState
|
|
||||||
tuntap tuntap.TunAdapter
|
tuntap tuntap.TunAdapter
|
||||||
multicast multicast.Multicast
|
multicast multicast.Multicast
|
||||||
admin admin.AdminSocket
|
admin admin.AdminSocket
|
||||||
|
@ -66,47 +64,10 @@ func readConfig(useconf *bool, useconffile *string, normaliseconf *bool) *config
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Generate a new configuration - this gives us a set of sane defaults -
|
// Generate blank configuration
|
||||||
// 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 := config.GenerateConfig()
|
cfg := config.GenerateConfig()
|
||||||
var dat map[string]interface{}
|
// ... and then update it with the supplied HJSON input
|
||||||
if err := hjson.Unmarshal(conf, &dat); err != nil {
|
if err := cfg.UnmarshalHJSON(conf); err != nil {
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
// Check for fields that have changed type recently, e.g. the Listen config
|
|
||||||
// option is now a []string rather than a string
|
|
||||||
if listen, ok := dat["Listen"].(string); ok {
|
|
||||||
dat["Listen"] = []string{listen}
|
|
||||||
}
|
|
||||||
if tunnelrouting, ok := dat["TunnelRouting"].(map[string]interface{}); ok {
|
|
||||||
if c, ok := tunnelrouting["IPv4Sources"]; ok {
|
|
||||||
delete(tunnelrouting, "IPv4Sources")
|
|
||||||
tunnelrouting["IPv4LocalSubnets"] = c
|
|
||||||
}
|
|
||||||
if c, ok := tunnelrouting["IPv6Sources"]; ok {
|
|
||||||
delete(tunnelrouting, "IPv6Sources")
|
|
||||||
tunnelrouting["IPv6LocalSubnets"] = c
|
|
||||||
}
|
|
||||||
if c, ok := tunnelrouting["IPv4Destinations"]; ok {
|
|
||||||
delete(tunnelrouting, "IPv4Destinations")
|
|
||||||
tunnelrouting["IPv4RemoteSubnets"] = c
|
|
||||||
}
|
|
||||||
if c, ok := tunnelrouting["IPv6Destinations"]; ok {
|
|
||||||
delete(tunnelrouting, "IPv6Destinations")
|
|
||||||
tunnelrouting["IPv6RemoteSubnets"] = c
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Sanitise the config
|
|
||||||
confJson, err := json.Marshal(dat)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
json.Unmarshal(confJson, &cfg)
|
|
||||||
// Overlay our newly mapped configuration onto the autoconf node config that
|
|
||||||
// we generated above.
|
|
||||||
if err = mapstructure.Decode(dat, &cfg); err != nil {
|
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
return cfg
|
return cfg
|
||||||
|
@ -119,9 +80,9 @@ func doGenconf(isjson bool) string {
|
||||||
var bs []byte
|
var bs []byte
|
||||||
var err error
|
var err error
|
||||||
if isjson {
|
if isjson {
|
||||||
bs, err = json.MarshalIndent(cfg, "", " ")
|
bs, err = cfg.MarshalJSON()
|
||||||
} else {
|
} else {
|
||||||
bs, err = hjson.Marshal(cfg)
|
bs, err = cfg.MarshalHJSON()
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
@ -224,7 +185,7 @@ func main() {
|
||||||
n := node{}
|
n := node{}
|
||||||
// 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
|
||||||
n.state, err = n.core.Start(cfg, logger)
|
err = n.core.Start(cfg, logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Errorln("An error occurred during startup")
|
logger.Errorln("An error occurred during startup")
|
||||||
panic(err)
|
panic(err)
|
||||||
|
@ -232,12 +193,12 @@ func main() {
|
||||||
// Register the session firewall gatekeeper function
|
// Register the session firewall gatekeeper function
|
||||||
n.core.SetSessionGatekeeper(n.sessionFirewall)
|
n.core.SetSessionGatekeeper(n.sessionFirewall)
|
||||||
// Start the admin socket
|
// Start the admin socket
|
||||||
n.admin.Init(&n.core, n.state, logger, nil)
|
n.admin.Init(&n.core, logger, nil)
|
||||||
if err := n.admin.Start(); err != nil {
|
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)
|
||||||
}
|
}
|
||||||
// Start the multicast interface
|
// Start the multicast interface
|
||||||
n.multicast.Init(&n.core, n.state, logger, nil)
|
n.multicast.Init(&n.core, logger, nil)
|
||||||
if err := n.multicast.Start(); err != nil {
|
if err := n.multicast.Start(); err != nil {
|
||||||
logger.Errorln("An error occurred starting multicast:", err)
|
logger.Errorln("An error occurred starting multicast:", err)
|
||||||
}
|
}
|
||||||
|
@ -245,7 +206,7 @@ func main() {
|
||||||
// Start the TUN/TAP interface
|
// Start the TUN/TAP interface
|
||||||
if listener, err := n.core.ConnListen(); err == nil {
|
if listener, err := n.core.ConnListen(); err == nil {
|
||||||
if dialer, err := n.core.ConnDialer(); err == nil {
|
if dialer, err := n.core.ConnDialer(); err == nil {
|
||||||
n.tuntap.Init(n.state, logger, listener, dialer)
|
n.tuntap.Init(&n.core, logger, listener, dialer)
|
||||||
if err := n.tuntap.Start(); err != nil {
|
if err := n.tuntap.Start(); err != nil {
|
||||||
logger.Errorln("An error occurred starting TUN/TAP:", err)
|
logger.Errorln("An error occurred starting TUN/TAP:", err)
|
||||||
}
|
}
|
||||||
|
@ -281,8 +242,8 @@ func main() {
|
||||||
cfg = readConfig(useconf, useconffile, normaliseconf)
|
cfg = readConfig(useconf, useconffile, normaliseconf)
|
||||||
logger.Infoln("Reloading configuration from", *useconffile)
|
logger.Infoln("Reloading configuration from", *useconffile)
|
||||||
n.core.UpdateConfig(cfg)
|
n.core.UpdateConfig(cfg)
|
||||||
n.tuntap.UpdateConfig(cfg)
|
n.tuntap.UpdateConfig()
|
||||||
n.multicast.UpdateConfig(cfg)
|
n.multicast.UpdateConfig()
|
||||||
} else {
|
} else {
|
||||||
logger.Errorln("Reloading config at runtime is only possible with -useconffile")
|
logger.Errorln("Reloading config at runtime is only possible with -useconffile")
|
||||||
}
|
}
|
||||||
|
@ -300,18 +261,17 @@ func (n *node) shutdown() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *node) sessionFirewall(pubkey *crypto.BoxPubKey, initiator bool) bool {
|
func (n *node) sessionFirewall(pubkey *crypto.BoxPubKey, initiator bool) bool {
|
||||||
n.state.Mutex.RLock()
|
current := n.core.GetConfig()
|
||||||
defer n.state.Mutex.RUnlock()
|
|
||||||
|
|
||||||
// Allow by default if the session firewall is disabled
|
// Allow by default if the session firewall is disabled
|
||||||
if !n.state.Current.SessionFirewall.Enable {
|
if !current.SessionFirewall.Enable {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepare for checking whitelist/blacklist
|
// Prepare for checking whitelist/blacklist
|
||||||
var box crypto.BoxPubKey
|
var box crypto.BoxPubKey
|
||||||
// Reject blacklisted nodes
|
// Reject blacklisted nodes
|
||||||
for _, b := range n.state.Current.SessionFirewall.BlacklistEncryptionPublicKeys {
|
for _, b := range current.SessionFirewall.BlacklistEncryptionPublicKeys {
|
||||||
key, err := hex.DecodeString(b)
|
key, err := hex.DecodeString(b)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
copy(box[:crypto.BoxPubKeyLen], key)
|
copy(box[:crypto.BoxPubKeyLen], key)
|
||||||
|
@ -322,7 +282,7 @@ func (n *node) sessionFirewall(pubkey *crypto.BoxPubKey, initiator bool) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allow whitelisted nodes
|
// Allow whitelisted nodes
|
||||||
for _, b := range n.state.Current.SessionFirewall.WhitelistEncryptionPublicKeys {
|
for _, b := range current.SessionFirewall.WhitelistEncryptionPublicKeys {
|
||||||
key, err := hex.DecodeString(b)
|
key, err := hex.DecodeString(b)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
copy(box[:crypto.BoxPubKeyLen], key)
|
copy(box[:crypto.BoxPubKeyLen], key)
|
||||||
|
@ -333,7 +293,7 @@ func (n *node) sessionFirewall(pubkey *crypto.BoxPubKey, initiator bool) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allow outbound sessions if appropriate
|
// Allow outbound sessions if appropriate
|
||||||
if n.state.Current.SessionFirewall.AlwaysAllowOutbound {
|
if current.SessionFirewall.AlwaysAllowOutbound {
|
||||||
if initiator {
|
if initiator {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -349,12 +309,12 @@ func (n *node) sessionFirewall(pubkey *crypto.BoxPubKey, initiator bool) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allow direct peers if appropriate
|
// Allow direct peers if appropriate
|
||||||
if n.state.Current.SessionFirewall.AllowFromDirect && isDirectPeer {
|
if current.SessionFirewall.AllowFromDirect && isDirectPeer {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allow remote nodes if appropriate
|
// Allow remote nodes if appropriate
|
||||||
if n.state.Current.SessionFirewall.AllowFromRemote && !isDirectPeer {
|
if current.SessionFirewall.AllowFromRemote && !isDirectPeer {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,6 @@ import (
|
||||||
"github.com/gologme/log"
|
"github.com/gologme/log"
|
||||||
|
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/address"
|
"github.com/yggdrasil-network/yggdrasil-go/src/address"
|
||||||
"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/util"
|
"github.com/yggdrasil-network/yggdrasil-go/src/util"
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/version"
|
"github.com/yggdrasil-network/yggdrasil-go/src/version"
|
||||||
|
@ -54,7 +53,7 @@ func (a *AdminSocket) AddHandler(name string, args []string, handlerfunc func(In
|
||||||
}
|
}
|
||||||
|
|
||||||
// init runs the initial admin setup.
|
// init runs the initial admin setup.
|
||||||
func (a *AdminSocket) Init(c *yggdrasil.Core, state *config.NodeState, log *log.Logger, options interface{}) {
|
func (a *AdminSocket) Init(c *yggdrasil.Core, log *log.Logger, options interface{}) {
|
||||||
a.core = c
|
a.core = c
|
||||||
a.log = log
|
a.log = log
|
||||||
a.reconfigure = make(chan chan error, 1)
|
a.reconfigure = make(chan chan error, 1)
|
||||||
|
@ -62,17 +61,15 @@ func (a *AdminSocket) Init(c *yggdrasil.Core, state *config.NodeState, log *log.
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
e := <-a.reconfigure
|
e := <-a.reconfigure
|
||||||
current, previous := state.GetCurrent(), state.GetPrevious()
|
if newlistenaddr := c.GetConfig().AdminListen; newlistenaddr != a.listenaddr {
|
||||||
if current.AdminListen != previous.AdminListen {
|
a.listenaddr = newlistenaddr
|
||||||
a.listenaddr = current.AdminListen
|
|
||||||
a.Stop()
|
a.Stop()
|
||||||
a.Start()
|
a.Start()
|
||||||
}
|
}
|
||||||
e <- nil
|
e <- nil
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
current := state.GetCurrent()
|
a.listenaddr = c.GetConfig().AdminListen
|
||||||
a.listenaddr = current.AdminListen
|
|
||||||
a.AddHandler("list", []string{}, func(in Info) (Info, error) {
|
a.AddHandler("list", []string{}, func(in Info) (Info, error) {
|
||||||
handlers := make(map[string]interface{})
|
handlers := make(map[string]interface{})
|
||||||
for handlername, handler := range a.handlers {
|
for handlername, handler := range a.handlers {
|
||||||
|
@ -314,6 +311,9 @@ func (a *AdminSocket) Init(c *yggdrasil.Core, state *config.NodeState, log *log.
|
||||||
|
|
||||||
// start runs the admin API socket to listen for / respond to admin API calls.
|
// start runs the admin API socket to listen for / respond to admin API calls.
|
||||||
func (a *AdminSocket) Start() error {
|
func (a *AdminSocket) Start() error {
|
||||||
|
if a.core == nil {
|
||||||
|
return errors.New("admin socket has not been initialised, call Init first")
|
||||||
|
}
|
||||||
if a.listenaddr != "none" && a.listenaddr != "" {
|
if a.listenaddr != "none" && a.listenaddr != "" {
|
||||||
go a.listen()
|
go a.listen()
|
||||||
}
|
}
|
||||||
|
|
5
src/config/admin.go
Normal file
5
src/config/admin.go
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
package config
|
||||||
|
|
||||||
|
type AdminConfig struct {
|
||||||
|
AdminListen string `comment:"Listen address for admin connections. Default is to listen for local\nconnections either on TCP/9001 or a UNIX socket depending on your\nplatform. Use this value for yggdrasilctl -endpoint=X. To disable\nthe admin socket, use the value \"none\" instead."`
|
||||||
|
}
|
|
@ -2,61 +2,29 @@ package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"sync"
|
"encoding/json"
|
||||||
|
|
||||||
|
hjson "github.com/hjson/hjson-go"
|
||||||
|
"github.com/mitchellh/mapstructure"
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/crypto"
|
"github.com/yggdrasil-network/yggdrasil-go/src/crypto"
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/defaults"
|
"github.com/yggdrasil-network/yggdrasil-go/src/defaults"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NodeState represents the active and previous configuration of the node and
|
|
||||||
// protects it with a mutex
|
|
||||||
type NodeState struct {
|
|
||||||
Current NodeConfig
|
|
||||||
Previous NodeConfig
|
|
||||||
Mutex sync.RWMutex
|
|
||||||
}
|
|
||||||
|
|
||||||
// Current returns the current node config
|
|
||||||
func (s *NodeState) GetCurrent() NodeConfig {
|
|
||||||
s.Mutex.RLock()
|
|
||||||
defer s.Mutex.RUnlock()
|
|
||||||
return s.Current
|
|
||||||
}
|
|
||||||
|
|
||||||
// Previous returns the previous node config
|
|
||||||
func (s *NodeState) GetPrevious() NodeConfig {
|
|
||||||
s.Mutex.RLock()
|
|
||||||
defer s.Mutex.RUnlock()
|
|
||||||
return s.Previous
|
|
||||||
}
|
|
||||||
|
|
||||||
// Replace the node configuration with new configuration. This method returns
|
|
||||||
// both the new and the previous node configs
|
|
||||||
func (s *NodeState) Replace(n NodeConfig) {
|
|
||||||
s.Mutex.Lock()
|
|
||||||
defer s.Mutex.Unlock()
|
|
||||||
s.Previous = s.Current
|
|
||||||
s.Current = n
|
|
||||||
}
|
|
||||||
|
|
||||||
// NodeConfig defines all configuration values needed to run a signle yggdrasil node
|
// NodeConfig defines all configuration values needed to run a signle yggdrasil node
|
||||||
type NodeConfig struct {
|
type NodeConfig struct {
|
||||||
Peers []string `comment:"List of connection strings for outbound peer connections in URI format,\ne.g. tcp://a.b.c.d:e or socks://a.b.c.d:e/f.g.h.i:j. These connections\nwill obey the operating system routing table, therefore you should\nuse this section when you may connect via different interfaces."`
|
Peers []string `comment:"List of connection strings for outbound peer connections in URI format,\ne.g. tcp://a.b.c.d:e or socks://a.b.c.d:e/f.g.h.i:j. These connections\nwill obey the operating system routing table, therefore you should\nuse this section when you may connect via different interfaces."`
|
||||||
InterfacePeers map[string][]string `comment:"List of connection strings for outbound peer connections in URI format,\narranged by source interface, e.g. { \"eth0\": [ tcp://a.b.c.d:e ] }.\nNote that SOCKS peerings will NOT be affected by this option and should\ngo in the \"Peers\" section instead."`
|
InterfacePeers map[string][]string `comment:"List of connection strings for outbound peer connections in URI format,\narranged by source interface, e.g. { \"eth0\": [ tcp://a.b.c.d:e ] }.\nNote that SOCKS peerings will NOT be affected by this option and should\ngo in the \"Peers\" section instead."`
|
||||||
Listen []string `comment:"Listen addresses for incoming connections. You will need to add\nlisteners in order to accept incoming peerings from non-local nodes.\nMulticast peer discovery will work regardless of any listeners set\nhere. Each listener should be specified in URI format as above, e.g.\ntcp://0.0.0.0:0 or tcp://[::]:0 to listen on all interfaces."`
|
Listen []string `comment:"Listen addresses for incoming connections. You will need to add\nlisteners in order to accept incoming peerings from non-local nodes.\nMulticast peer discovery will work regardless of any listeners set\nhere. Each listener should be specified in URI format as above, e.g.\ntcp://0.0.0.0:0 or tcp://[::]:0 to listen on all interfaces."`
|
||||||
AdminListen string `comment:"Listen address for admin connections. Default is to listen for local\nconnections either on TCP/9001 or a UNIX socket depending on your\nplatform. Use this value for yggdrasilctl -endpoint=X. To disable\nthe admin socket, use the value \"none\" instead."`
|
AdminConfig ``
|
||||||
MulticastInterfaces []string `comment:"Regular expressions for which interfaces multicast peer discovery\nshould be enabled on. If none specified, multicast peer discovery is\ndisabled. The default value is .* which uses all interfaces."`
|
MulticastConfig ``
|
||||||
AllowedEncryptionPublicKeys []string `comment:"List of peer encryption public keys to allow incoming TCP peering\nconnections from. If left empty/undefined then all connections will\nbe allowed by default. This does not affect outgoing peerings, nor\ndoes it affect link-local peers discovered via multicast."`
|
AllowedEncryptionPublicKeys []string `comment:"List of peer encryption public keys to allow incoming TCP peering\nconnections from. If left empty/undefined then all connections will\nbe allowed by default. This does not affect outgoing peerings, nor\ndoes it affect link-local peers discovered via multicast."`
|
||||||
EncryptionPublicKey string `comment:"Your public encryption key. Your peers may ask you for this to put\ninto their AllowedEncryptionPublicKeys configuration."`
|
EncryptionPublicKey string `comment:"Your public encryption key. Your peers may ask you for this to put\ninto their AllowedEncryptionPublicKeys configuration."`
|
||||||
EncryptionPrivateKey string `comment:"Your private encryption key. DO NOT share this with anyone!"`
|
EncryptionPrivateKey string `comment:"Your private encryption key. DO NOT share this with anyone!"`
|
||||||
SigningPublicKey string `comment:"Your public signing key. You should not ordinarily need to share\nthis with anyone."`
|
SigningPublicKey string `comment:"Your public signing key. You should not ordinarily need to share\nthis with anyone."`
|
||||||
SigningPrivateKey string `comment:"Your private signing key. DO NOT share this with anyone!"`
|
SigningPrivateKey string `comment:"Your private signing key. DO NOT share this with anyone!"`
|
||||||
LinkLocalTCPPort uint16 `comment:"The port number to be used for the link-local TCP listeners for the\nconfigured MulticastInterfaces. This option does not affect listeners\nspecified in the Listen option. Unless you plan to firewall link-local\ntraffic, it is best to leave this as the default value of 0. This\noption cannot currently be changed by reloading config during runtime."`
|
LinkLocalTCPPort uint16 `comment:"The port number to be used for the link-local TCP listeners for the\nconfigured MulticastInterfaces. This option does not affect listeners\nspecified in the Listen option. Unless you plan to firewall link-local\ntraffic, it is best to leave this as the default value of 0. This\noption cannot currently be changed by reloading config during runtime."`
|
||||||
IfName string `comment:"Local network interface name for TUN/TAP adapter, or \"auto\" to select\nan interface automatically, or \"none\" to run without TUN/TAP."`
|
TunTapConfig ``
|
||||||
IfTAPMode bool `comment:"Set local network interface to TAP mode rather than TUN mode if\nsupported by your platform - option will be ignored if not."`
|
|
||||||
IfMTU int `comment:"Maximux Transmission Unit (MTU) size for your local TUN/TAP interface.\nDefault is the largest supported size for your platform. The lowest\npossible value is 1280."`
|
|
||||||
SessionFirewall SessionFirewall `comment:"The session firewall controls who can send/receive network traffic\nto/from. This is useful if you want to protect this node without\nresorting to using a real firewall. This does not affect traffic\nbeing routed via this node to somewhere else. Rules are prioritised as\nfollows: blacklist, whitelist, always allow outgoing, direct, remote."`
|
SessionFirewall SessionFirewall `comment:"The session firewall controls who can send/receive network traffic\nto/from. This is useful if you want to protect this node without\nresorting to using a real firewall. This does not affect traffic\nbeing routed via this node to somewhere else. Rules are prioritised as\nfollows: blacklist, whitelist, always allow outgoing, direct, remote."`
|
||||||
TunnelRouting TunnelRouting `comment:"Allow tunneling non-Yggdrasil traffic over Yggdrasil. This effectively\nallows you to use Yggdrasil to route to, or to bridge other networks,\nsimilar to a VPN tunnel. Tunnelling works between any two nodes and\ndoes not require them to be directly peered."`
|
|
||||||
SwitchOptions SwitchOptions `comment:"Advanced options for tuning the switch. Normally you will not need\nto edit these options."`
|
SwitchOptions SwitchOptions `comment:"Advanced options for tuning the switch. Normally you will not need\nto edit these options."`
|
||||||
NodeInfoPrivacy bool `comment:"By default, nodeinfo contains some defaults including the platform,\narchitecture and Yggdrasil version. These can help when surveying\nthe network and diagnosing network routing problems. Enabling\nnodeinfo privacy prevents this, so that only items specified in\n\"NodeInfo\" are sent back if specified."`
|
NodeInfoPrivacy bool `comment:"By default, nodeinfo contains some defaults including the platform,\narchitecture and Yggdrasil version. These can help when surveying\nthe network and diagnosing network routing problems. Enabling\nnodeinfo privacy prevents this, so that only items specified in\n\"NodeInfo\" are sent back if specified."`
|
||||||
NodeInfo map[string]interface{} `comment:"Optional node info. This must be a { \"key\": \"value\", ... } map\nor set as null. This is entirely optional but, if set, is visible\nto the whole network on request."`
|
NodeInfo map[string]interface{} `comment:"Optional node info. This must be a { \"key\": \"value\", ... } map\nor set as null. This is entirely optional but, if set, is visible\nto the whole network on request."`
|
||||||
|
@ -72,15 +40,6 @@ type SessionFirewall struct {
|
||||||
BlacklistEncryptionPublicKeys []string `comment:"List of public keys from which network traffic is always rejected,\nregardless of the whitelist, AllowFromDirect or AllowFromRemote."`
|
BlacklistEncryptionPublicKeys []string `comment:"List of public keys from which network traffic is always rejected,\nregardless of the whitelist, AllowFromDirect or AllowFromRemote."`
|
||||||
}
|
}
|
||||||
|
|
||||||
// TunnelRouting contains the crypto-key routing tables for tunneling
|
|
||||||
type TunnelRouting struct {
|
|
||||||
Enable bool `comment:"Enable or disable tunnel routing."`
|
|
||||||
IPv6RemoteSubnets map[string]string `comment:"IPv6 subnets belonging to remote nodes, mapped to the node's public\nkey, e.g. { \"aaaa:bbbb:cccc::/e\": \"boxpubkey\", ... }"`
|
|
||||||
IPv6LocalSubnets []string `comment:"IPv6 subnets belonging to this node's end of the tunnels. Only traffic\nfrom these ranges (or the Yggdrasil node's IPv6 address/subnet)\nwill be tunnelled."`
|
|
||||||
IPv4RemoteSubnets map[string]string `comment:"IPv4 subnets belonging to remote nodes, mapped to the node's public\nkey, e.g. { \"a.b.c.d/e\": \"boxpubkey\", ... }"`
|
|
||||||
IPv4LocalSubnets []string `comment:"IPv4 subnets belonging to this node's end of the tunnels. Only traffic\nfrom these ranges will be tunnelled."`
|
|
||||||
}
|
|
||||||
|
|
||||||
// SwitchOptions contains tuning options for the switch
|
// SwitchOptions contains tuning options for the switch
|
||||||
type SwitchOptions struct {
|
type SwitchOptions struct {
|
||||||
MaxTotalQueueSize uint64 `comment:"Maximum size of all switch queues combined (in bytes)."`
|
MaxTotalQueueSize uint64 `comment:"Maximum size of all switch queues combined (in bytes)."`
|
||||||
|
@ -137,3 +96,83 @@ func (cfg *NodeConfig) NewSigningKeys() {
|
||||||
cfg.SigningPublicKey = hex.EncodeToString(spub[:])
|
cfg.SigningPublicKey = hex.EncodeToString(spub[:])
|
||||||
cfg.SigningPrivateKey = hex.EncodeToString(spriv[:])
|
cfg.SigningPrivateKey = hex.EncodeToString(spriv[:])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MarshalJSON exports the configuration into JSON format. No comments are
|
||||||
|
// included in the JSON export as comments are not valid in pure JSON.
|
||||||
|
func (cfg *NodeConfig) MarshalJSON() ([]byte, error) {
|
||||||
|
bs, err := json.MarshalIndent(cfg, "", " ")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return bs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalHJSON exports the configuration into HJSON format, complete with
|
||||||
|
// comments describing what each configuration item does.
|
||||||
|
func (cfg *NodeConfig) MarshalHJSON() ([]byte, error) {
|
||||||
|
bs, err := hjson.Marshal(cfg)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return bs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON parses the configuration in pure JSON format and updates the
|
||||||
|
// NodeConfig accordingly. The input JSON can be partial - only supplied fields
|
||||||
|
// will be updated.
|
||||||
|
func (cfg *NodeConfig) UnmarshalJSON(conf []byte) error {
|
||||||
|
var dat map[string]interface{}
|
||||||
|
if err := json.Unmarshal(conf, &dat); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return cfg.decodeConfig(dat)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalHJSON parses the configuration in HJSON format and updates the
|
||||||
|
// NodeConfig accordingly. The input HJSON can be partial - only supplied fields
|
||||||
|
// will be updated.
|
||||||
|
func (cfg *NodeConfig) UnmarshalHJSON(conf []byte) error {
|
||||||
|
var dat map[string]interface{}
|
||||||
|
if err := hjson.Unmarshal(conf, &dat); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return cfg.decodeConfig(dat)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cfg *NodeConfig) decodeConfig(dat map[string]interface{}) error {
|
||||||
|
// Check for fields that have changed type recently, e.g. the Listen config
|
||||||
|
// option is now a []string rather than a string
|
||||||
|
if listen, ok := dat["Listen"].(string); ok {
|
||||||
|
dat["Listen"] = []string{listen}
|
||||||
|
}
|
||||||
|
if tunnelrouting, ok := dat["TunnelRouting"].(map[string]interface{}); ok {
|
||||||
|
if c, ok := tunnelrouting["IPv4Sources"]; ok {
|
||||||
|
delete(tunnelrouting, "IPv4Sources")
|
||||||
|
tunnelrouting["IPv4LocalSubnets"] = c
|
||||||
|
}
|
||||||
|
if c, ok := tunnelrouting["IPv6Sources"]; ok {
|
||||||
|
delete(tunnelrouting, "IPv6Sources")
|
||||||
|
tunnelrouting["IPv6LocalSubnets"] = c
|
||||||
|
}
|
||||||
|
if c, ok := tunnelrouting["IPv4Destinations"]; ok {
|
||||||
|
delete(tunnelrouting, "IPv4Destinations")
|
||||||
|
tunnelrouting["IPv4RemoteSubnets"] = c
|
||||||
|
}
|
||||||
|
if c, ok := tunnelrouting["IPv6Destinations"]; ok {
|
||||||
|
delete(tunnelrouting, "IPv6Destinations")
|
||||||
|
tunnelrouting["IPv6RemoteSubnets"] = c
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Sanitise the config
|
||||||
|
/*confJson, err := json.Marshal(dat)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
json.Unmarshal(confJson, &cfg)*/
|
||||||
|
// Overlay our newly mapped configuration onto the autoconf node config that
|
||||||
|
// we generated above.
|
||||||
|
if err := mapstructure.Decode(dat, &cfg); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
5
src/config/multicast.go
Normal file
5
src/config/multicast.go
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
package config
|
||||||
|
|
||||||
|
type MulticastConfig struct {
|
||||||
|
MulticastInterfaces []string `comment:"Regular expressions for which interfaces multicast peer discovery\nshould be enabled on. If none specified, multicast peer discovery is\ndisabled. The default value is .* which uses all interfaces."`
|
||||||
|
}
|
17
src/config/tuntap.go
Normal file
17
src/config/tuntap.go
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
package config
|
||||||
|
|
||||||
|
type TunTapConfig struct {
|
||||||
|
IfName string `comment:"Local network interface name for TUN/TAP adapter, or \"auto\" to select\nan interface automatically, or \"none\" to run without TUN/TAP."`
|
||||||
|
IfTAPMode bool `comment:"Set local network interface to TAP mode rather than TUN mode if\nsupported by your platform - option will be ignored if not."`
|
||||||
|
IfMTU int `comment:"Maximux Transmission Unit (MTU) size for your local TUN/TAP interface.\nDefault is the largest supported size for your platform. The lowest\npossible value is 1280."`
|
||||||
|
TunnelRouting TunnelRouting `comment:"Allow tunneling non-Yggdrasil traffic over Yggdrasil. This effectively\nallows you to use Yggdrasil to route to, or to bridge other networks,\nsimilar to a VPN tunnel. Tunnelling works between any two nodes and\ndoes not require them to be directly peered."`
|
||||||
|
}
|
||||||
|
|
||||||
|
// TunnelRouting contains the crypto-key routing tables for tunneling
|
||||||
|
type TunnelRouting struct {
|
||||||
|
Enable bool `comment:"Enable or disable tunnel routing."`
|
||||||
|
IPv6RemoteSubnets map[string]string `comment:"IPv6 subnets belonging to remote nodes, mapped to the node's public\nkey, e.g. { \"aaaa:bbbb:cccc::/e\": \"boxpubkey\", ... }"`
|
||||||
|
IPv6LocalSubnets []string `comment:"IPv6 subnets belonging to this node's end of the tunnels. Only traffic\nfrom these ranges (or the Yggdrasil node's IPv6 address/subnet)\nwill be tunnelled."`
|
||||||
|
IPv4RemoteSubnets map[string]string `comment:"IPv4 subnets belonging to remote nodes, mapped to the node's public\nkey, e.g. { \"a.b.c.d/e\": \"boxpubkey\", ... }"`
|
||||||
|
IPv4LocalSubnets []string `comment:"IPv4 subnets belonging to this node's end of the tunnels. Only traffic\nfrom these ranges will be tunnelled."`
|
||||||
|
}
|
|
@ -2,6 +2,7 @@ package multicast
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
@ -9,7 +10,6 @@ import (
|
||||||
|
|
||||||
"github.com/gologme/log"
|
"github.com/gologme/log"
|
||||||
|
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/config"
|
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/yggdrasil"
|
"github.com/yggdrasil-network/yggdrasil-go/src/yggdrasil"
|
||||||
"golang.org/x/net/ipv6"
|
"golang.org/x/net/ipv6"
|
||||||
)
|
)
|
||||||
|
@ -20,7 +20,6 @@ import (
|
||||||
// automatically.
|
// automatically.
|
||||||
type Multicast struct {
|
type Multicast struct {
|
||||||
core *yggdrasil.Core
|
core *yggdrasil.Core
|
||||||
config *config.NodeState
|
|
||||||
log *log.Logger
|
log *log.Logger
|
||||||
sock *ipv6.PacketConn
|
sock *ipv6.PacketConn
|
||||||
groupAddr string
|
groupAddr string
|
||||||
|
@ -30,13 +29,11 @@ type Multicast struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init prepares the multicast interface for use.
|
// Init prepares the multicast interface for use.
|
||||||
func (m *Multicast) Init(core *yggdrasil.Core, state *config.NodeState, log *log.Logger, options interface{}) error {
|
func (m *Multicast) Init(core *yggdrasil.Core, log *log.Logger, options interface{}) error {
|
||||||
m.core = core
|
m.core = core
|
||||||
m.config = state
|
|
||||||
m.log = log
|
m.log = log
|
||||||
m.listeners = make(map[string]*yggdrasil.TcpListener)
|
m.listeners = make(map[string]*yggdrasil.TcpListener)
|
||||||
current := m.config.GetCurrent()
|
m.listenPort = m.core.GetConfig().LinkLocalTCPPort
|
||||||
m.listenPort = current.LinkLocalTCPPort
|
|
||||||
m.groupAddr = "[ff02::114]:9001"
|
m.groupAddr = "[ff02::114]:9001"
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -45,6 +42,9 @@ func (m *Multicast) Init(core *yggdrasil.Core, state *config.NodeState, log *log
|
||||||
// listen for multicast beacons from other hosts and will advertise multicast
|
// listen for multicast beacons from other hosts and will advertise multicast
|
||||||
// beacons out to the network.
|
// beacons out to the network.
|
||||||
func (m *Multicast) Start() error {
|
func (m *Multicast) Start() error {
|
||||||
|
if m.core == nil {
|
||||||
|
return errors.New("multicast has not been initialised, call Init first")
|
||||||
|
}
|
||||||
addr, err := net.ResolveUDPAddr("udp", m.groupAddr)
|
addr, err := net.ResolveUDPAddr("udp", m.groupAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -80,9 +80,8 @@ func (m *Multicast) Stop() error {
|
||||||
// UpdateConfig updates the multicast module with the provided config.NodeConfig
|
// UpdateConfig updates the multicast module with the provided config.NodeConfig
|
||||||
// and then signals the various module goroutines to reconfigure themselves if
|
// and then signals the various module goroutines to reconfigure themselves if
|
||||||
// needed.
|
// needed.
|
||||||
func (m *Multicast) UpdateConfig(config *config.NodeConfig) {
|
func (m *Multicast) UpdateConfig() {
|
||||||
m.log.Debugln("Reloading multicast configuration...")
|
|
||||||
m.config.Replace(*config)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetInterfaces returns the currently known/enabled multicast interfaces. It is
|
// GetInterfaces returns the currently known/enabled multicast interfaces. It is
|
||||||
|
@ -91,7 +90,7 @@ func (m *Multicast) UpdateConfig(config *config.NodeConfig) {
|
||||||
func (m *Multicast) Interfaces() map[string]net.Interface {
|
func (m *Multicast) Interfaces() map[string]net.Interface {
|
||||||
interfaces := make(map[string]net.Interface)
|
interfaces := make(map[string]net.Interface)
|
||||||
// Get interface expressions from config
|
// Get interface expressions from config
|
||||||
current := m.config.GetCurrent()
|
current := m.core.GetConfig()
|
||||||
exprs := current.MulticastInterfaces
|
exprs := current.MulticastInterfaces
|
||||||
// Ask the system for network interfaces
|
// Ask the system for network interfaces
|
||||||
allifaces, err := net.Interfaces()
|
allifaces, err := net.Interfaces()
|
||||||
|
|
|
@ -44,7 +44,7 @@ func (c *cryptokey) init(tun *TunAdapter) {
|
||||||
|
|
||||||
// Configure the CKR routes. This should only ever be ran by the TUN/TAP actor.
|
// Configure the CKR routes. This should only ever be ran by the TUN/TAP actor.
|
||||||
func (c *cryptokey) configure() {
|
func (c *cryptokey) configure() {
|
||||||
current := c.tun.config.GetCurrent()
|
current := c.tun.core.GetConfig()
|
||||||
|
|
||||||
// Set enabled/disabled state
|
// Set enabled/disabled state
|
||||||
c.setEnabled(current.TunnelRouting.Enable)
|
c.setEnabled(current.TunnelRouting.Enable)
|
||||||
|
|
|
@ -21,7 +21,6 @@ import (
|
||||||
"github.com/yggdrasil-network/water"
|
"github.com/yggdrasil-network/water"
|
||||||
|
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/address"
|
"github.com/yggdrasil-network/yggdrasil-go/src/address"
|
||||||
"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/defaults"
|
"github.com/yggdrasil-network/yggdrasil-go/src/defaults"
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/yggdrasil"
|
"github.com/yggdrasil-network/yggdrasil-go/src/yggdrasil"
|
||||||
|
@ -35,9 +34,9 @@ const tun_ETHER_HEADER_LENGTH = 14
|
||||||
// you should pass this object to the yggdrasil.SetRouterAdapter() function
|
// you should pass this object to the yggdrasil.SetRouterAdapter() function
|
||||||
// before calling yggdrasil.Start().
|
// before calling yggdrasil.Start().
|
||||||
type TunAdapter struct {
|
type TunAdapter struct {
|
||||||
|
core *yggdrasil.Core
|
||||||
writer tunWriter
|
writer tunWriter
|
||||||
reader tunReader
|
reader tunReader
|
||||||
config *config.NodeState
|
|
||||||
log *log.Logger
|
log *log.Logger
|
||||||
reconfigure chan chan error
|
reconfigure chan chan error
|
||||||
listener *yggdrasil.Listener
|
listener *yggdrasil.Listener
|
||||||
|
@ -110,8 +109,8 @@ func MaximumMTU() int {
|
||||||
|
|
||||||
// Init initialises the TUN/TAP module. You must have acquired a Listener from
|
// Init initialises the TUN/TAP module. You must have acquired a Listener from
|
||||||
// the Yggdrasil core before this point and it must not be in use elsewhere.
|
// the Yggdrasil core before this point and it must not be in use elsewhere.
|
||||||
func (tun *TunAdapter) Init(config *config.NodeState, log *log.Logger, listener *yggdrasil.Listener, dialer *yggdrasil.Dialer) {
|
func (tun *TunAdapter) Init(c *yggdrasil.Core, log *log.Logger, listener *yggdrasil.Listener, dialer *yggdrasil.Dialer) {
|
||||||
tun.config = config
|
tun.core = c
|
||||||
tun.log = log
|
tun.log = log
|
||||||
tun.listener = listener
|
tun.listener = listener
|
||||||
tun.dialer = dialer
|
tun.dialer = dialer
|
||||||
|
@ -133,9 +132,9 @@ func (tun *TunAdapter) Start() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tun *TunAdapter) _start() error {
|
func (tun *TunAdapter) _start() error {
|
||||||
current := tun.config.GetCurrent()
|
current := tun.core.GetConfig()
|
||||||
if tun.config == nil || tun.listener == nil || tun.dialer == nil {
|
if tun.core == nil || tun.listener == nil || tun.dialer == nil {
|
||||||
return errors.New("No configuration available to TUN/TAP")
|
return errors.New("TUN/TAP has not been initialised, call Init first")
|
||||||
}
|
}
|
||||||
var boxPub crypto.BoxPubKey
|
var boxPub crypto.BoxPubKey
|
||||||
boxPubHex, err := hex.DecodeString(current.EncryptionPublicKey)
|
boxPubHex, err := hex.DecodeString(current.EncryptionPublicKey)
|
||||||
|
@ -200,12 +199,9 @@ func (tun *TunAdapter) _stop() error {
|
||||||
// UpdateConfig updates the TUN/TAP module with the provided config.NodeConfig
|
// UpdateConfig updates the TUN/TAP module with the provided config.NodeConfig
|
||||||
// and then signals the various module goroutines to reconfigure themselves if
|
// and then signals the various module goroutines to reconfigure themselves if
|
||||||
// needed.
|
// needed.
|
||||||
func (tun *TunAdapter) UpdateConfig(config *config.NodeConfig) {
|
func (tun *TunAdapter) UpdateConfig() {
|
||||||
tun.log.Debugln("Reloading TUN/TAP configuration...")
|
tun.log.Debugln("Reloading TUN/TAP configuration...")
|
||||||
|
|
||||||
// Replace the active configuration with the supplied one
|
|
||||||
tun.config.Replace(*config)
|
|
||||||
|
|
||||||
// Notify children about the configuration change
|
// Notify children about the configuration change
|
||||||
tun.Act(nil, tun.ckr.configure)
|
tun.Act(nil, tun.ckr.configure)
|
||||||
}
|
}
|
||||||
|
|
|
@ -370,13 +370,12 @@ func (c *Core) AddPeer(addr string, sintf string) error {
|
||||||
if err := c.CallPeer(addr, sintf); err != nil {
|
if err := c.CallPeer(addr, sintf); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
c.config.Mutex.Lock()
|
config := c.GetConfig()
|
||||||
if sintf == "" {
|
if sintf == "" {
|
||||||
c.config.Current.Peers = append(c.config.Current.Peers, addr)
|
config.Peers = append(config.Peers, addr)
|
||||||
} else {
|
} else {
|
||||||
c.config.Current.InterfacePeers[sintf] = append(c.config.Current.InterfacePeers[sintf], addr)
|
config.InterfacePeers[sintf] = append(config.InterfacePeers[sintf], addr)
|
||||||
}
|
}
|
||||||
c.config.Mutex.Unlock()
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"errors"
|
"errors"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/Arceliar/phony"
|
"github.com/Arceliar/phony"
|
||||||
|
@ -21,7 +22,7 @@ type Core struct {
|
||||||
// We're going to keep our own copy of the provided config - that way we can
|
// We're going to keep our own copy of the provided config - that way we can
|
||||||
// guarantee that it will be covered by the mutex
|
// guarantee that it will be covered by the mutex
|
||||||
phony.Inbox
|
phony.Inbox
|
||||||
config config.NodeState // Config
|
config atomic.Value // *config.NodeConfig
|
||||||
boxPub crypto.BoxPubKey
|
boxPub crypto.BoxPubKey
|
||||||
boxPriv crypto.BoxPrivKey
|
boxPriv crypto.BoxPrivKey
|
||||||
sigPub crypto.SigPubKey
|
sigPub crypto.SigPubKey
|
||||||
|
@ -42,7 +43,7 @@ func (c *Core) _init() error {
|
||||||
c.log = log.New(ioutil.Discard, "", 0)
|
c.log = log.New(ioutil.Discard, "", 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
current := c.config.GetCurrent()
|
current := c.config.Load().(*config.NodeConfig)
|
||||||
|
|
||||||
boxPrivHex, err := hex.DecodeString(current.EncryptionPrivateKey)
|
boxPrivHex, err := hex.DecodeString(current.EncryptionPrivateKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -87,7 +88,7 @@ func (c *Core) _init() error {
|
||||||
// be reconnected with.
|
// be reconnected with.
|
||||||
func (c *Core) _addPeerLoop() {
|
func (c *Core) _addPeerLoop() {
|
||||||
// Get the peers from the config - these could change!
|
// Get the peers from the config - these could change!
|
||||||
current := c.config.GetCurrent()
|
current := c.GetConfig()
|
||||||
|
|
||||||
// Add peers from the Peers section
|
// Add peers from the Peers section
|
||||||
for _, peer := range current.Peers {
|
for _, peer := range current.Peers {
|
||||||
|
@ -109,6 +110,11 @@ func (c *Core) _addPeerLoop() {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetConfig atomically returns the current active node configuration.
|
||||||
|
func (c *Core) GetConfig() *config.NodeConfig {
|
||||||
|
return c.config.Load().(*config.NodeConfig)
|
||||||
|
}
|
||||||
|
|
||||||
// UpdateConfig updates the configuration in Core with the provided
|
// UpdateConfig updates the configuration in Core with the provided
|
||||||
// config.NodeConfig and then signals the various module goroutines to
|
// config.NodeConfig and then signals the various module goroutines to
|
||||||
// reconfigure themselves if needed.
|
// reconfigure themselves if needed.
|
||||||
|
@ -116,12 +122,16 @@ func (c *Core) UpdateConfig(config *config.NodeConfig) {
|
||||||
c.Act(nil, func() {
|
c.Act(nil, func() {
|
||||||
c.log.Debugln("Reloading node configuration...")
|
c.log.Debugln("Reloading node configuration...")
|
||||||
|
|
||||||
// Replace the active configuration with the supplied one
|
new, old := config, c.GetConfig()
|
||||||
c.config.Replace(*config)
|
c.config.Store(new)
|
||||||
|
|
||||||
// Notify the router and switch about the new configuration
|
// Notify the router and switch about the new configuration
|
||||||
c.router.Act(c, c.router.reconfigure)
|
c.router.Act(c, func() {
|
||||||
c.switchTable.Act(c, c.switchTable.reconfigure)
|
c.router.reconfigure(new, old)
|
||||||
|
})
|
||||||
|
c.switchTable.Act(c, func() {
|
||||||
|
c.switchTable.reconfigure(new, old)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,21 +140,17 @@ func (c *Core) UpdateConfig(config *config.NodeConfig) {
|
||||||
// TCP and UDP sockets, a multicast discovery socket, an admin socket, router,
|
// 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
|
// switch and DHT node. A config.NodeState is returned which contains both the
|
||||||
// current and previous configurations (from reconfigures).
|
// current and previous configurations (from reconfigures).
|
||||||
func (c *Core) Start(nc *config.NodeConfig, log *log.Logger) (conf *config.NodeState, err error) {
|
func (c *Core) Start(nc *config.NodeConfig, log *log.Logger) (err error) {
|
||||||
phony.Block(c, func() {
|
phony.Block(c, func() {
|
||||||
conf, err = c._start(nc, log)
|
err = c._start(nc, log)
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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) _start(nc *config.NodeConfig, log *log.Logger) (*config.NodeState, error) {
|
func (c *Core) _start(nc *config.NodeConfig, log *log.Logger) error {
|
||||||
c.log = log
|
c.log = log
|
||||||
|
c.config.Store(nc)
|
||||||
c.config = config.NodeState{
|
|
||||||
Current: *nc,
|
|
||||||
Previous: *nc,
|
|
||||||
}
|
|
||||||
|
|
||||||
if name := version.BuildName(); name != "unknown" {
|
if name := version.BuildName(); name != "unknown" {
|
||||||
c.log.Infoln("Build name:", name)
|
c.log.Infoln("Build name:", name)
|
||||||
|
@ -158,23 +164,23 @@ func (c *Core) _start(nc *config.NodeConfig, log *log.Logger) (*config.NodeState
|
||||||
|
|
||||||
if err := c.link.init(c); err != nil {
|
if err := c.link.init(c); err != nil {
|
||||||
c.log.Errorln("Failed to start link interfaces")
|
c.log.Errorln("Failed to start link interfaces")
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.switchTable.start(); err != nil {
|
if err := c.switchTable.start(); err != nil {
|
||||||
c.log.Errorln("Failed to start switch")
|
c.log.Errorln("Failed to start switch")
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.router.start(); err != nil {
|
if err := c.router.start(); err != nil {
|
||||||
c.log.Errorln("Failed to start router")
|
c.log.Errorln("Failed to start router")
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Act(c, c._addPeerLoop)
|
c.Act(c, c._addPeerLoop)
|
||||||
|
|
||||||
c.log.Infoln("Startup complete")
|
c.log.Infoln("Startup complete")
|
||||||
return &c.config, nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop shuts down the Yggdrasil node.
|
// Stop shuts down the Yggdrasil node.
|
||||||
|
|
|
@ -14,6 +14,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/address"
|
"github.com/yggdrasil-network/yggdrasil-go/src/address"
|
||||||
|
"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/util"
|
"github.com/yggdrasil-network/yggdrasil-go/src/util"
|
||||||
|
|
||||||
|
@ -79,8 +80,8 @@ func (l *link) init(c *Core) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *link) reconfigure() {
|
func (l *link) reconfigure(current, previous *config.NodeConfig) {
|
||||||
l.tcp.reconfigure()
|
l.tcp.reconfigure(current, previous)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *link) call(uri string, sintf string) error {
|
func (l *link) call(uri string, sintf string) error {
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"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/util"
|
"github.com/yggdrasil-network/yggdrasil-go/src/util"
|
||||||
|
|
||||||
|
@ -34,7 +35,7 @@ func (ps *peers) init(c *Core) {
|
||||||
ps.core = c
|
ps.core = c
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ps *peers) reconfigure() {
|
func (ps *peers) reconfigure(current, previous *config.NodeConfig) {
|
||||||
// This is where reconfiguration would go, if we had anything to do
|
// This is where reconfiguration would go, if we had anything to do
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,42 +43,34 @@ func (ps *peers) reconfigure() {
|
||||||
// because the key is in the whitelist or because the whitelist is empty.
|
// because the key is in the whitelist or because the whitelist is empty.
|
||||||
func (ps *peers) isAllowedEncryptionPublicKey(box *crypto.BoxPubKey) bool {
|
func (ps *peers) isAllowedEncryptionPublicKey(box *crypto.BoxPubKey) bool {
|
||||||
boxstr := hex.EncodeToString(box[:])
|
boxstr := hex.EncodeToString(box[:])
|
||||||
ps.core.config.Mutex.RLock()
|
current := ps.core.GetConfig()
|
||||||
defer ps.core.config.Mutex.RUnlock()
|
for _, v := range current.AllowedEncryptionPublicKeys {
|
||||||
for _, v := range ps.core.config.Current.AllowedEncryptionPublicKeys {
|
|
||||||
if v == boxstr {
|
if v == boxstr {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return len(ps.core.config.Current.AllowedEncryptionPublicKeys) == 0
|
return len(current.AllowedEncryptionPublicKeys) == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adds a key to the whitelist.
|
// Adds a key to the whitelist.
|
||||||
func (ps *peers) addAllowedEncryptionPublicKey(box string) {
|
func (ps *peers) addAllowedEncryptionPublicKey(box string) {
|
||||||
ps.core.config.Mutex.RLock()
|
current := ps.core.GetConfig()
|
||||||
defer ps.core.config.Mutex.RUnlock()
|
current.AllowedEncryptionPublicKeys = append(current.AllowedEncryptionPublicKeys, box)
|
||||||
ps.core.config.Current.AllowedEncryptionPublicKeys =
|
|
||||||
append(ps.core.config.Current.AllowedEncryptionPublicKeys, box)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Removes a key from the whitelist.
|
// Removes a key from the whitelist.
|
||||||
func (ps *peers) removeAllowedEncryptionPublicKey(box string) {
|
func (ps *peers) removeAllowedEncryptionPublicKey(box string) {
|
||||||
ps.core.config.Mutex.RLock()
|
current := ps.core.GetConfig()
|
||||||
defer ps.core.config.Mutex.RUnlock()
|
for k, v := range current.AllowedEncryptionPublicKeys {
|
||||||
for k, v := range ps.core.config.Current.AllowedEncryptionPublicKeys {
|
|
||||||
if v == box {
|
if v == box {
|
||||||
ps.core.config.Current.AllowedEncryptionPublicKeys =
|
current.AllowedEncryptionPublicKeys = append(current.AllowedEncryptionPublicKeys[:k], current.AllowedEncryptionPublicKeys[k+1:]...)
|
||||||
append(ps.core.config.Current.AllowedEncryptionPublicKeys[:k],
|
|
||||||
ps.core.config.Current.AllowedEncryptionPublicKeys[k+1:]...)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gets the whitelist of allowed keys for incoming connections.
|
// Gets the whitelist of allowed keys for incoming connections.
|
||||||
func (ps *peers) getAllowedEncryptionPublicKeys() []string {
|
func (ps *peers) getAllowedEncryptionPublicKeys() []string {
|
||||||
ps.core.config.Mutex.RLock()
|
return ps.core.GetConfig().AllowedEncryptionPublicKeys
|
||||||
defer ps.core.config.Mutex.RUnlock()
|
|
||||||
return ps.core.config.Current.AllowedEncryptionPublicKeys
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Atomically gets a map[switchPort]*peer of known peers.
|
// Atomically gets a map[switchPort]*peer of known peers.
|
||||||
|
|
|
@ -28,6 +28,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/address"
|
"github.com/yggdrasil-network/yggdrasil-go/src/address"
|
||||||
|
"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/util"
|
"github.com/yggdrasil-network/yggdrasil-go/src/util"
|
||||||
|
|
||||||
|
@ -65,9 +66,8 @@ func (r *router) init(core *Core) {
|
||||||
p.out = func(packets [][]byte) { r.handlePackets(p, packets) }
|
p.out = func(packets [][]byte) { r.handlePackets(p, packets) }
|
||||||
r.out = func(bs []byte) { p.handlePacketFrom(r, bs) }
|
r.out = func(bs []byte) { p.handlePacketFrom(r, bs) }
|
||||||
r.nodeinfo.init(r.core)
|
r.nodeinfo.init(r.core)
|
||||||
r.core.config.Mutex.RLock()
|
current := r.core.GetConfig()
|
||||||
r.nodeinfo.setNodeInfo(r.core.config.Current.NodeInfo, r.core.config.Current.NodeInfoPrivacy)
|
r.nodeinfo.setNodeInfo(current.NodeInfo, current.NodeInfoPrivacy)
|
||||||
r.core.config.Mutex.RUnlock()
|
|
||||||
r.dht.init(r)
|
r.dht.init(r)
|
||||||
r.searches.init(r)
|
r.searches.init(r)
|
||||||
r.sessions.init(r)
|
r.sessions.init(r)
|
||||||
|
@ -75,9 +75,8 @@ func (r *router) init(core *Core) {
|
||||||
|
|
||||||
// Reconfigures the router and any child modules. This should only ever be run
|
// Reconfigures the router and any child modules. This should only ever be run
|
||||||
// by the router actor.
|
// by the router actor.
|
||||||
func (r *router) reconfigure() {
|
func (r *router) reconfigure(current, previous *config.NodeConfig) {
|
||||||
// Reconfigure the router
|
// Reconfigure the router
|
||||||
current := r.core.config.GetCurrent()
|
|
||||||
if err := r.nodeinfo.setNodeInfo(current.NodeInfo, current.NodeInfoPrivacy); err != nil {
|
if err := r.nodeinfo.setNodeInfo(current.NodeInfo, current.NodeInfoPrivacy); err != nil {
|
||||||
r.core.log.Errorln("Error reloading NodeInfo:", err)
|
r.core.log.Errorln("Error reloading NodeInfo:", err)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -187,9 +187,7 @@ func (ss *sessions) createSession(theirPermKey *crypto.BoxPubKey) *sessionInfo {
|
||||||
sinfo.mySesPriv = *priv
|
sinfo.mySesPriv = *priv
|
||||||
sinfo.myNonce = *crypto.NewBoxNonce()
|
sinfo.myNonce = *crypto.NewBoxNonce()
|
||||||
sinfo.theirMTU = 1280
|
sinfo.theirMTU = 1280
|
||||||
ss.router.core.config.Mutex.RLock()
|
sinfo.myMTU = uint16(ss.router.core.GetConfig().IfMTU)
|
||||||
sinfo.myMTU = uint16(ss.router.core.config.Current.IfMTU)
|
|
||||||
ss.router.core.config.Mutex.RUnlock()
|
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
sinfo.timeOpened = now
|
sinfo.timeOpened = now
|
||||||
sinfo.time = now
|
sinfo.time = now
|
||||||
|
|
|
@ -17,6 +17,7 @@ import (
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"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/util"
|
"github.com/yggdrasil-network/yggdrasil-go/src/util"
|
||||||
|
|
||||||
|
@ -193,22 +194,21 @@ func (t *switchTable) init(core *Core) {
|
||||||
t.table.Store(lookupTable{})
|
t.table.Store(lookupTable{})
|
||||||
t.drop = make(map[crypto.SigPubKey]int64)
|
t.drop = make(map[crypto.SigPubKey]int64)
|
||||||
phony.Block(t, func() {
|
phony.Block(t, func() {
|
||||||
core.config.Mutex.RLock()
|
current := t.core.GetConfig()
|
||||||
if core.config.Current.SwitchOptions.MaxTotalQueueSize > SwitchQueueTotalMinSize {
|
if current.SwitchOptions.MaxTotalQueueSize > SwitchQueueTotalMinSize {
|
||||||
t.queues.totalMaxSize = core.config.Current.SwitchOptions.MaxTotalQueueSize
|
t.queues.totalMaxSize = current.SwitchOptions.MaxTotalQueueSize
|
||||||
} else {
|
} else {
|
||||||
t.queues.totalMaxSize = SwitchQueueTotalMinSize
|
t.queues.totalMaxSize = SwitchQueueTotalMinSize
|
||||||
}
|
}
|
||||||
core.config.Mutex.RUnlock()
|
|
||||||
t.queues.bufs = make(map[string]switch_buffer)
|
t.queues.bufs = make(map[string]switch_buffer)
|
||||||
t.idle = make(map[switchPort]time.Time)
|
t.idle = make(map[switchPort]time.Time)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *switchTable) reconfigure() {
|
func (t *switchTable) reconfigure(current, previous *config.NodeConfig) {
|
||||||
// This is where reconfiguration would go, if we had anything useful to do.
|
// This is where reconfiguration would go, if we had anything useful to do.
|
||||||
t.core.link.reconfigure()
|
t.core.link.reconfigure(current, previous)
|
||||||
t.core.peers.reconfigure()
|
t.core.peers.reconfigure(current, previous)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Safely gets a copy of this node's locator.
|
// Safely gets a copy of this node's locator.
|
||||||
|
|
|
@ -25,6 +25,7 @@ import (
|
||||||
|
|
||||||
"golang.org/x/net/proxy"
|
"golang.org/x/net/proxy"
|
||||||
|
|
||||||
|
"github.com/yggdrasil-network/yggdrasil-go/src/config"
|
||||||
"github.com/yggdrasil-network/yggdrasil-go/src/util"
|
"github.com/yggdrasil-network/yggdrasil-go/src/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -81,9 +82,7 @@ func (t *tcp) init(l *link) error {
|
||||||
t.listeners = make(map[string]*TcpListener)
|
t.listeners = make(map[string]*TcpListener)
|
||||||
t.mutex.Unlock()
|
t.mutex.Unlock()
|
||||||
|
|
||||||
t.link.core.config.Mutex.RLock()
|
for _, listenaddr := range t.link.core.GetConfig().Listen {
|
||||||
defer t.link.core.config.Mutex.RUnlock()
|
|
||||||
for _, listenaddr := range t.link.core.config.Current.Listen {
|
|
||||||
if listenaddr[:6] != "tcp://" {
|
if listenaddr[:6] != "tcp://" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -95,11 +94,9 @@ func (t *tcp) init(l *link) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *tcp) reconfigure() {
|
func (t *tcp) reconfigure(current, previous *config.NodeConfig) {
|
||||||
t.link.core.config.Mutex.RLock()
|
added := util.Difference(current.Listen, previous.Listen)
|
||||||
added := util.Difference(t.link.core.config.Current.Listen, t.link.core.config.Previous.Listen)
|
deleted := util.Difference(previous.Listen, current.Listen)
|
||||||
deleted := util.Difference(t.link.core.config.Previous.Listen, t.link.core.config.Current.Listen)
|
|
||||||
t.link.core.config.Mutex.RUnlock()
|
|
||||||
if len(added) > 0 || len(deleted) > 0 {
|
if len(added) > 0 || len(deleted) > 0 {
|
||||||
for _, a := range added {
|
for _, a := range added {
|
||||||
if a[:6] != "tcp://" {
|
if a[:6] != "tcp://" {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue