5
0
mirror of https://github.com/cwinfo/yggdrasil-go.git synced 2024-11-29 14:21:37 +00:00

Merge pull request #312 from neilalexander/nodeconfig

Further nodeconfig changes
This commit is contained in:
Neil Alexander 2019-01-16 20:51:55 +00:00 committed by GitHub
commit 2219d96df1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 54 additions and 111 deletions

View File

@ -227,11 +227,6 @@ func main() {
logger.Println("An error occurred during startup")
panic(err)
}
// Check to see if any allowed encryption keys were provided in the config.
// If they were then set them now.
for _, pBoxStr := range cfg.AllowedEncryptionPublicKeys {
n.core.AddAllowedEncryptionPublicKey(pBoxStr)
}
// The Stop function ensures that the TUN/TAP adapter is correctly shut down
// before the program exits.
defer func() {

View File

@ -765,35 +765,20 @@ func (a *admin) getData_getSessions() []admin_nodeInfo {
// getAllowedEncryptionPublicKeys returns the public keys permitted for incoming peer connections.
func (a *admin) getAllowedEncryptionPublicKeys() []string {
pubs := a.core.peers.getAllowedEncryptionPublicKeys()
var out []string
for _, pub := range pubs {
out = append(out, hex.EncodeToString(pub[:]))
}
return out
return a.core.peers.getAllowedEncryptionPublicKeys()
}
// addAllowedEncryptionPublicKey whitelists a key for incoming peer connections.
func (a *admin) addAllowedEncryptionPublicKey(bstr string) (err error) {
boxBytes, err := hex.DecodeString(bstr)
if err == nil {
var box crypto.BoxPubKey
copy(box[:], boxBytes)
a.core.peers.addAllowedEncryptionPublicKey(&box)
}
return
a.core.peers.addAllowedEncryptionPublicKey(bstr)
return nil
}
// removeAllowedEncryptionPublicKey removes a key from the whitelist for incoming peer connections.
// If none are set, an empty list permits all incoming connections.
func (a *admin) removeAllowedEncryptionPublicKey(bstr string) (err error) {
boxBytes, err := hex.DecodeString(bstr)
if err == nil {
var box crypto.BoxPubKey
copy(box[:], boxBytes)
a.core.peers.removeAllowedEncryptionPublicKey(&box)
}
return
a.core.peers.removeAllowedEncryptionPublicKey(bstr)
return nil
}
// Send a DHT ping to the node with the provided key and coords, optionally looking up the specified target NodeID.

View File

@ -212,15 +212,6 @@ func (c *Core) Start(nc *config.NodeConfig, log *log.Logger) error {
return err
}
c.sessions.setSessionFirewallState(nc.SessionFirewall.Enable)
c.sessions.setSessionFirewallDefaults(
nc.SessionFirewall.AllowFromDirect,
nc.SessionFirewall.AllowFromRemote,
nc.SessionFirewall.AlwaysAllowOutbound,
)
c.sessions.setSessionFirewallWhitelist(nc.SessionFirewall.WhitelistEncryptionPublicKeys)
c.sessions.setSessionFirewallBlacklist(nc.SessionFirewall.BlacklistEncryptionPublicKeys)
if err := c.router.start(); err != nil {
c.log.Println("Failed to start router")
return err

View File

@ -5,6 +5,7 @@ package yggdrasil
// Live code should be better commented
import (
"encoding/hex"
"sync"
"sync/atomic"
"time"
@ -18,12 +19,10 @@ import (
// In most cases, this involves passing the packet to the handler for outgoing traffic to another peer.
// In other cases, it's link protocol traffic used to build the spanning tree, in which case this checks signatures and passes the message along to the switch.
type peers struct {
core *Core
reconfigure chan chan error
mutex sync.Mutex // Synchronize writes to atomic
ports atomic.Value //map[switchPort]*peer, use CoW semantics
authMutex sync.RWMutex
allowedEncryptionPublicKeys map[crypto.BoxPubKey]struct{}
core *Core
reconfigure chan chan error
mutex sync.Mutex // Synchronize writes to atomic
ports atomic.Value //map[switchPort]*peer, use CoW semantics
}
// Initializes the peers struct.
@ -39,40 +38,48 @@ func (ps *peers) init(c *Core) {
e <- nil
}
}()
ps.allowedEncryptionPublicKeys = make(map[crypto.BoxPubKey]struct{})
}
// Returns true if an incoming peer connection to a key is allowed, either because the key is in the whitelist or because the whitelist is empty.
// Returns true if an incoming peer connection to a key is allowed, either
// because the key is in the whitelist or because the whitelist is empty.
func (ps *peers) isAllowedEncryptionPublicKey(box *crypto.BoxPubKey) bool {
ps.authMutex.RLock()
defer ps.authMutex.RUnlock()
_, isIn := ps.allowedEncryptionPublicKeys[*box]
return isIn || len(ps.allowedEncryptionPublicKeys) == 0
boxstr := hex.EncodeToString(box[:])
ps.core.configMutex.RLock()
defer ps.core.configMutex.RUnlock()
for _, v := range ps.core.config.AllowedEncryptionPublicKeys {
if v == boxstr {
return true
}
}
return len(ps.core.config.AllowedEncryptionPublicKeys) == 0
}
// Adds a key to the whitelist.
func (ps *peers) addAllowedEncryptionPublicKey(box *crypto.BoxPubKey) {
ps.authMutex.Lock()
defer ps.authMutex.Unlock()
ps.allowedEncryptionPublicKeys[*box] = struct{}{}
func (ps *peers) addAllowedEncryptionPublicKey(box string) {
ps.core.configMutex.RLock()
defer ps.core.configMutex.RUnlock()
ps.core.config.AllowedEncryptionPublicKeys =
append(ps.core.config.AllowedEncryptionPublicKeys, box)
}
// Removes a key from the whitelist.
func (ps *peers) removeAllowedEncryptionPublicKey(box *crypto.BoxPubKey) {
ps.authMutex.Lock()
defer ps.authMutex.Unlock()
delete(ps.allowedEncryptionPublicKeys, *box)
func (ps *peers) removeAllowedEncryptionPublicKey(box string) {
ps.core.configMutex.RLock()
defer ps.core.configMutex.RUnlock()
for k, v := range ps.core.config.AllowedEncryptionPublicKeys {
if v == box {
ps.core.config.AllowedEncryptionPublicKeys =
append(ps.core.config.AllowedEncryptionPublicKeys[:k],
ps.core.config.AllowedEncryptionPublicKeys[k+1:]...)
}
}
}
// Gets the whitelist of allowed keys for incoming connections.
func (ps *peers) getAllowedEncryptionPublicKeys() []crypto.BoxPubKey {
ps.authMutex.RLock()
defer ps.authMutex.RUnlock()
keys := make([]crypto.BoxPubKey, 0, len(ps.allowedEncryptionPublicKeys))
for key := range ps.allowedEncryptionPublicKeys {
keys = append(keys, key)
}
return keys
func (ps *peers) getAllowedEncryptionPublicKeys() []string {
ps.core.configMutex.RLock()
defer ps.core.configMutex.RUnlock()
return ps.core.config.AllowedEncryptionPublicKeys
}
// Atomically gets a map[switchPort]*peer of known peers.

View File

@ -7,7 +7,6 @@ package yggdrasil
import (
"bytes"
"encoding/hex"
"sync"
"time"
"github.com/yggdrasil-network/yggdrasil-go/src/address"
@ -115,14 +114,6 @@ type sessions struct {
byTheirPerm map[crypto.BoxPubKey]*crypto.Handle
addrToPerm map[address.Address]*crypto.BoxPubKey
subnetToPerm map[address.Subnet]*crypto.BoxPubKey
// Options from the session firewall
sessionFirewallMutex sync.RWMutex
sessionFirewallEnabled bool
sessionFirewallAllowsDirect bool
sessionFirewallAllowsRemote bool
sessionFirewallAlwaysAllowsOutbound bool
sessionFirewallWhitelist []string
sessionFirewallBlacklist []string
}
// Initializes the session struct.
@ -155,51 +146,28 @@ func (ss *sessions) init(core *Core) {
ss.lastCleanup = time.Now()
}
// Enable or disable the session firewall
func (ss *sessions) setSessionFirewallState(enabled bool) {
ss.sessionFirewallMutex.Lock()
defer ss.sessionFirewallMutex.Unlock()
ss.sessionFirewallEnabled = enabled
}
// Determines whether the session firewall is enabled.
func (ss *sessions) isSessionFirewallEnabled() bool {
ss.core.configMutex.RLock()
defer ss.core.configMutex.RUnlock()
// Set the session firewall defaults (first parameter is whether to allow
// sessions from direct peers, second is whether to allow from remote nodes).
func (ss *sessions) setSessionFirewallDefaults(allowsDirect bool, allowsRemote bool, alwaysAllowsOutbound bool) {
ss.sessionFirewallMutex.Lock()
defer ss.sessionFirewallMutex.Unlock()
ss.sessionFirewallAllowsDirect = allowsDirect
ss.sessionFirewallAllowsRemote = allowsRemote
ss.sessionFirewallAlwaysAllowsOutbound = alwaysAllowsOutbound
}
// Set the session firewall whitelist - nodes always allowed to open sessions.
func (ss *sessions) setSessionFirewallWhitelist(whitelist []string) {
ss.sessionFirewallMutex.Lock()
defer ss.sessionFirewallMutex.Unlock()
ss.sessionFirewallWhitelist = whitelist
}
// Set the session firewall blacklist - nodes never allowed to open sessions.
func (ss *sessions) setSessionFirewallBlacklist(blacklist []string) {
ss.sessionFirewallMutex.Lock()
defer ss.sessionFirewallMutex.Unlock()
ss.sessionFirewallBlacklist = blacklist
return ss.core.config.SessionFirewall.Enable
}
// Determines whether the session with a given publickey is allowed based on
// session firewall rules.
func (ss *sessions) isSessionAllowed(pubkey *crypto.BoxPubKey, initiator bool) bool {
ss.sessionFirewallMutex.RLock()
defer ss.sessionFirewallMutex.RUnlock()
ss.core.configMutex.RLock()
defer ss.core.configMutex.RUnlock()
// Allow by default if the session firewall is disabled
if !ss.sessionFirewallEnabled {
if !ss.isSessionFirewallEnabled() {
return true
}
// Prepare for checking whitelist/blacklist
var box crypto.BoxPubKey
// Reject blacklisted nodes
for _, b := range ss.sessionFirewallBlacklist {
for _, b := range ss.core.config.SessionFirewall.BlacklistEncryptionPublicKeys {
key, err := hex.DecodeString(b)
if err == nil {
copy(box[:crypto.BoxPubKeyLen], key)
@ -209,7 +177,7 @@ func (ss *sessions) isSessionAllowed(pubkey *crypto.BoxPubKey, initiator bool) b
}
}
// Allow whitelisted nodes
for _, b := range ss.sessionFirewallWhitelist {
for _, b := range ss.core.config.SessionFirewall.WhitelistEncryptionPublicKeys {
key, err := hex.DecodeString(b)
if err == nil {
copy(box[:crypto.BoxPubKeyLen], key)
@ -219,7 +187,7 @@ func (ss *sessions) isSessionAllowed(pubkey *crypto.BoxPubKey, initiator bool) b
}
}
// Allow outbound sessions if appropriate
if ss.sessionFirewallAlwaysAllowsOutbound {
if ss.core.config.SessionFirewall.AlwaysAllowOutbound {
if initiator {
return true
}
@ -233,11 +201,11 @@ func (ss *sessions) isSessionAllowed(pubkey *crypto.BoxPubKey, initiator bool) b
}
}
// Allow direct peers if appropriate
if ss.sessionFirewallAllowsDirect && isDirectPeer {
if ss.core.config.SessionFirewall.AllowFromDirect && isDirectPeer {
return true
}
// Allow remote nodes if appropriate
if ss.sessionFirewallAllowsRemote && !isDirectPeer {
if ss.core.config.SessionFirewall.AllowFromRemote && !isDirectPeer {
return true
}
// Finally, default-deny if not matching any of the above rules
@ -474,14 +442,11 @@ func (ss *sessions) handlePing(ping *sessionPing) {
// Get the corresponding session (or create a new session)
sinfo, isIn := ss.getByTheirPerm(&ping.SendPermPub)
// Check the session firewall
ss.sessionFirewallMutex.RLock()
if !isIn && ss.sessionFirewallEnabled {
if !isIn && ss.isSessionFirewallEnabled() {
if !ss.isSessionAllowed(&ping.SendPermPub, false) {
ss.sessionFirewallMutex.RUnlock()
return
}
}
ss.sessionFirewallMutex.RUnlock()
if !isIn || sinfo.timedout() {
if isIn {
sinfo.close()