5
0
mirror of https://github.com/cwinfo/yggdrasil-go.git synced 2024-11-10 06:20:26 +00:00

Merge branch 'develop' into ios

This commit is contained in:
Neil Alexander 2019-01-17 23:15:00 +00:00
commit 30df632eb2
No known key found for this signature in database
GPG Key ID: A02A2019A2BB0944
6 changed files with 74 additions and 119 deletions

View File

@ -227,11 +227,6 @@ func main() {
logger.Println("An error occurred during startup") logger.Println("An error occurred during startup")
panic(err) 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 // The Stop function ensures that the TUN/TAP adapter is correctly shut down
// before the program exits. // before the program exits.
defer func() { 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. // getAllowedEncryptionPublicKeys returns the public keys permitted for incoming peer connections.
func (a *admin) getAllowedEncryptionPublicKeys() []string { func (a *admin) getAllowedEncryptionPublicKeys() []string {
pubs := a.core.peers.getAllowedEncryptionPublicKeys() return a.core.peers.getAllowedEncryptionPublicKeys()
var out []string
for _, pub := range pubs {
out = append(out, hex.EncodeToString(pub[:]))
}
return out
} }
// addAllowedEncryptionPublicKey whitelists a key for incoming peer connections. // addAllowedEncryptionPublicKey whitelists a key for incoming peer connections.
func (a *admin) addAllowedEncryptionPublicKey(bstr string) (err error) { func (a *admin) addAllowedEncryptionPublicKey(bstr string) (err error) {
boxBytes, err := hex.DecodeString(bstr) a.core.peers.addAllowedEncryptionPublicKey(bstr)
if err == nil { return nil
var box crypto.BoxPubKey
copy(box[:], boxBytes)
a.core.peers.addAllowedEncryptionPublicKey(&box)
}
return
} }
// removeAllowedEncryptionPublicKey removes a key from the whitelist for incoming peer connections. // removeAllowedEncryptionPublicKey removes a key from the whitelist for incoming peer connections.
// If none are set, an empty list permits all incoming connections. // If none are set, an empty list permits all incoming connections.
func (a *admin) removeAllowedEncryptionPublicKey(bstr string) (err error) { func (a *admin) removeAllowedEncryptionPublicKey(bstr string) (err error) {
boxBytes, err := hex.DecodeString(bstr) a.core.peers.removeAllowedEncryptionPublicKey(bstr)
if err == nil { return nil
var box crypto.BoxPubKey
copy(box[:], boxBytes)
a.core.peers.removeAllowedEncryptionPublicKey(&box)
}
return
} }
// Send a DHT ping to the node with the provided key and coords, optionally looking up the specified target NodeID. // 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 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 { if err := c.router.start(); err != nil {
c.log.Println("Failed to start router") c.log.Println("Failed to start router")
return err return err

View File

@ -5,6 +5,7 @@ package yggdrasil
// Live code should be better commented // Live code should be better commented
import ( import (
"encoding/hex"
"sync" "sync"
"sync/atomic" "sync/atomic"
"time" "time"
@ -18,12 +19,10 @@ import (
// In most cases, this involves passing the packet to the handler for outgoing traffic to another peer. // 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. // 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 { type peers struct {
core *Core core *Core
reconfigure chan chan error reconfigure chan chan error
mutex sync.Mutex // Synchronize writes to atomic mutex sync.Mutex // Synchronize writes to atomic
ports atomic.Value //map[switchPort]*peer, use CoW semantics ports atomic.Value //map[switchPort]*peer, use CoW semantics
authMutex sync.RWMutex
allowedEncryptionPublicKeys map[crypto.BoxPubKey]struct{}
} }
// Initializes the peers struct. // Initializes the peers struct.
@ -39,40 +38,48 @@ func (ps *peers) init(c *Core) {
e <- nil 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 { func (ps *peers) isAllowedEncryptionPublicKey(box *crypto.BoxPubKey) bool {
ps.authMutex.RLock() boxstr := hex.EncodeToString(box[:])
defer ps.authMutex.RUnlock() ps.core.configMutex.RLock()
_, isIn := ps.allowedEncryptionPublicKeys[*box] defer ps.core.configMutex.RUnlock()
return isIn || len(ps.allowedEncryptionPublicKeys) == 0 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. // Adds a key to the whitelist.
func (ps *peers) addAllowedEncryptionPublicKey(box *crypto.BoxPubKey) { func (ps *peers) addAllowedEncryptionPublicKey(box string) {
ps.authMutex.Lock() ps.core.configMutex.RLock()
defer ps.authMutex.Unlock() defer ps.core.configMutex.RUnlock()
ps.allowedEncryptionPublicKeys[*box] = struct{}{} ps.core.config.AllowedEncryptionPublicKeys =
append(ps.core.config.AllowedEncryptionPublicKeys, box)
} }
// Removes a key from the whitelist. // Removes a key from the whitelist.
func (ps *peers) removeAllowedEncryptionPublicKey(box *crypto.BoxPubKey) { func (ps *peers) removeAllowedEncryptionPublicKey(box string) {
ps.authMutex.Lock() ps.core.configMutex.RLock()
defer ps.authMutex.Unlock() defer ps.core.configMutex.RUnlock()
delete(ps.allowedEncryptionPublicKeys, *box) 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. // Gets the whitelist of allowed keys for incoming connections.
func (ps *peers) getAllowedEncryptionPublicKeys() []crypto.BoxPubKey { func (ps *peers) getAllowedEncryptionPublicKeys() []string {
ps.authMutex.RLock() ps.core.configMutex.RLock()
defer ps.authMutex.RUnlock() defer ps.core.configMutex.RUnlock()
keys := make([]crypto.BoxPubKey, 0, len(ps.allowedEncryptionPublicKeys)) return ps.core.config.AllowedEncryptionPublicKeys
for key := range ps.allowedEncryptionPublicKeys {
keys = append(keys, key)
}
return keys
} }
// Atomically gets a map[switchPort]*peer of known peers. // Atomically gets a map[switchPort]*peer of known peers.

View File

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

View File

@ -245,15 +245,27 @@ func (iface *tcpInterface) call(saddr string, socksaddr *string, sintf string) {
if err != nil { if err != nil {
continue continue
} }
if (src.To4() != nil) == (dst.IP.To4() != nil) { if src.Equal(dst.IP) {
if addrindex == len(addrs)-1 || src.IsGlobalUnicast() { continue
dialer.LocalAddr = &net.TCPAddr{ }
IP: src, if !src.IsGlobalUnicast() && !src.IsLinkLocalUnicast() {
Port: 0, continue
Zone: sintf, }
} bothglobal := src.IsGlobalUnicast() == dst.IP.IsGlobalUnicast()
break bothlinklocal := src.IsLinkLocalUnicast() == dst.IP.IsLinkLocalUnicast()
if !bothglobal && !bothlinklocal {
continue
}
if (src.To4() != nil) != (dst.IP.To4() != nil) {
continue
}
if bothglobal || bothlinklocal || addrindex == len(addrs)-1 {
dialer.LocalAddr = &net.TCPAddr{
IP: src,
Port: 0,
Zone: sintf,
} }
break
} }
} }
if dialer.LocalAddr == nil { if dialer.LocalAddr == nil {