Implement session firewall as gatekeeper func in cmd/yggdrasil

This commit is contained in:
Neil Alexander 2019-06-11 12:50:01 +01:00
parent 720a078a35
commit 907986f200
No known key found for this signature in database
GPG Key ID: A02A2019A2BB0944

View File

@ -2,6 +2,7 @@ package main
import (
"bytes"
"encoding/hex"
"encoding/json"
"flag"
"fmt"
@ -20,22 +21,21 @@ import (
"github.com/yggdrasil-network/yggdrasil-go/src/admin"
"github.com/yggdrasil-network/yggdrasil-go/src/config"
"github.com/yggdrasil-network/yggdrasil-go/src/crypto"
"github.com/yggdrasil-network/yggdrasil-go/src/multicast"
"github.com/yggdrasil-network/yggdrasil-go/src/tuntap"
"github.com/yggdrasil-network/yggdrasil-go/src/yggdrasil"
)
type nodeConfig = config.NodeConfig
type Core = yggdrasil.Core
type node struct {
core Core
core yggdrasil.Core
state *config.NodeState
tuntap tuntap.TunAdapter
multicast multicast.Multicast
admin admin.AdminSocket
}
func readConfig(useconf *bool, useconffile *string, normaliseconf *bool) *nodeConfig {
func readConfig(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.
@ -116,7 +116,7 @@ func main() {
logging := flag.String("logging", "info,warn,error", "comma-separated list of logging levels to enable")
flag.Parse()
var cfg *nodeConfig
var cfg *config.NodeConfig
var err error
switch {
case *version:
@ -181,18 +181,20 @@ func main() {
n := node{}
// Now start Yggdrasil - this starts the DHT, router, switch and other core
// components needed for Yggdrasil to operate
state, err := n.core.Start(cfg, logger)
n.state, err = n.core.Start(cfg, logger)
if err != nil {
logger.Errorln("An error occurred during startup")
panic(err)
}
// Register the session firewall gatekeeper function
n.core.SetSessionGatekeeper(n.sessionFirewall)
// Start the admin socket
n.admin.Init(&n.core, state, logger, nil)
n.admin.Init(&n.core, n.state, logger, nil)
if err := n.admin.Start(); err != nil {
logger.Errorln("An error occurred starting admin socket:", err)
}
// Start the multicast interface
n.multicast.Init(&n.core, state, logger, nil)
n.multicast.Init(&n.core, n.state, logger, nil)
if err := n.multicast.Start(); err != nil {
logger.Errorln("An error occurred starting multicast:", err)
}
@ -200,7 +202,7 @@ func main() {
// Start the TUN/TAP interface
if listener, err := n.core.ConnListen(); err == nil {
if dialer, err := n.core.ConnDialer(); err == nil {
n.tuntap.Init(state, logger, listener, dialer)
n.tuntap.Init(n.state, logger, listener, dialer)
if err := n.tuntap.Start(); err != nil {
logger.Errorln("An error occurred starting TUN/TAP:", err)
}
@ -251,3 +253,66 @@ func main() {
}
exit:
}
func (n *node) sessionFirewall(pubkey *crypto.BoxPubKey, initiator bool) bool {
n.state.Mutex.RLock()
defer n.state.Mutex.RUnlock()
// Allow by default if the session firewall is disabled
if !n.state.Current.SessionFirewall.Enable {
return true
}
// Prepare for checking whitelist/blacklist
var box crypto.BoxPubKey
// Reject blacklisted nodes
for _, b := range n.state.Current.SessionFirewall.BlacklistEncryptionPublicKeys {
key, err := hex.DecodeString(b)
if err == nil {
copy(box[:crypto.BoxPubKeyLen], key)
if box == *pubkey {
return false
}
}
}
// Allow whitelisted nodes
for _, b := range n.state.Current.SessionFirewall.WhitelistEncryptionPublicKeys {
key, err := hex.DecodeString(b)
if err == nil {
copy(box[:crypto.BoxPubKeyLen], key)
if box == *pubkey {
return true
}
}
}
// Allow outbound sessions if appropriate
if n.state.Current.SessionFirewall.AlwaysAllowOutbound {
if initiator {
return true
}
}
// Look and see if the pubkey is that of a direct peer
var isDirectPeer bool
for _, peer := range n.core.GetPeers() {
if peer.PublicKey == *pubkey {
isDirectPeer = true
break
}
}
// Allow direct peers if appropriate
if n.state.Current.SessionFirewall.AllowFromDirect && isDirectPeer {
return true
}
// Allow remote nodes if appropriate
if n.state.Current.SessionFirewall.AllowFromRemote && !isDirectPeer {
return true
}
// Finally, default-deny if not matching any of the above rules
return false
}