mirror of
https://github.com/cwinfo/yggdrasil-go.git
synced 2024-11-29 14:21:37 +00:00
Add SetSessionGatekeeper
This allows you to define a function which determines whether a session connection (either incoming or outgoing) is allowed based on the public key.
This commit is contained in:
parent
d4a3b2bc76
commit
720a078a35
@ -395,6 +395,18 @@ func (c *Core) GetNodeInfo(keyString, coordString string, nocache bool) (NodeInf
|
|||||||
return NodeInfoPayload{}, errors.New(fmt.Sprintf("getNodeInfo timeout: %s", keyString))
|
return NodeInfoPayload{}, errors.New(fmt.Sprintf("getNodeInfo timeout: %s", keyString))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetSessionGatekeeper allows you to configure a handler function for deciding
|
||||||
|
// whether a session should be allowed or not. The default session firewall is
|
||||||
|
// implemented in this way. The function receives the public key of the remote
|
||||||
|
// side, and a boolean which is true if we initiated the session or false if we
|
||||||
|
// received an incoming session request.
|
||||||
|
func (c *Core) SetSessionGatekeeper(f func(pubkey *crypto.BoxPubKey, initiator bool) bool) {
|
||||||
|
c.sessions.isAllowedMutex.Lock()
|
||||||
|
defer c.sessions.isAllowedMutex.Unlock()
|
||||||
|
|
||||||
|
c.sessions.isAllowedHandler = f
|
||||||
|
}
|
||||||
|
|
||||||
// SetLogger sets the output logger of the Yggdrasil node after startup. This
|
// SetLogger sets the output logger of the Yggdrasil node after startup. This
|
||||||
// may be useful if you want to redirect the output later.
|
// may be useful if you want to redirect the output later.
|
||||||
func (c *Core) SetLogger(log *log.Logger) {
|
func (c *Core) SetLogger(log *log.Logger) {
|
||||||
|
@ -6,7 +6,6 @@ package yggdrasil
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/hex"
|
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -111,18 +110,20 @@ func (s *sessionInfo) update(p *sessionPing) bool {
|
|||||||
// Sessions are indexed by handle.
|
// Sessions are indexed by handle.
|
||||||
// Additionally, stores maps of address/subnet onto keys, and keys onto handles.
|
// Additionally, stores maps of address/subnet onto keys, and keys onto handles.
|
||||||
type sessions struct {
|
type sessions struct {
|
||||||
core *Core
|
core *Core
|
||||||
listener *Listener
|
listener *Listener
|
||||||
listenerMutex sync.Mutex
|
listenerMutex sync.Mutex
|
||||||
reconfigure chan chan error
|
reconfigure chan chan error
|
||||||
lastCleanup time.Time
|
lastCleanup time.Time
|
||||||
permShared map[crypto.BoxPubKey]*crypto.BoxSharedKey // Maps known permanent keys to their shared key, used by DHT a lot
|
isAllowedHandler func(pubkey *crypto.BoxPubKey, initiator bool) bool // Returns true or false if session setup is allowed
|
||||||
sinfos map[crypto.Handle]*sessionInfo // Maps (secret) handle onto session info
|
isAllowedMutex sync.RWMutex // Protects the above
|
||||||
conns map[crypto.Handle]*Conn // Maps (secret) handle onto connections
|
permShared map[crypto.BoxPubKey]*crypto.BoxSharedKey // Maps known permanent keys to their shared key, used by DHT a lot
|
||||||
byMySes map[crypto.BoxPubKey]*crypto.Handle // Maps mySesPub onto handle
|
sinfos map[crypto.Handle]*sessionInfo // Maps (secret) handle onto session info
|
||||||
byTheirPerm map[crypto.BoxPubKey]*crypto.Handle // Maps theirPermPub onto handle
|
conns map[crypto.Handle]*Conn // Maps (secret) handle onto connections
|
||||||
addrToPerm map[address.Address]*crypto.BoxPubKey
|
byMySes map[crypto.BoxPubKey]*crypto.Handle // Maps mySesPub onto handle
|
||||||
subnetToPerm map[address.Subnet]*crypto.BoxPubKey
|
byTheirPerm map[crypto.BoxPubKey]*crypto.Handle // Maps theirPermPub onto handle
|
||||||
|
addrToPerm map[address.Address]*crypto.BoxPubKey
|
||||||
|
subnetToPerm map[address.Subnet]*crypto.BoxPubKey
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initializes the session struct.
|
// Initializes the session struct.
|
||||||
@ -155,70 +156,17 @@ func (ss *sessions) init(core *Core) {
|
|||||||
ss.lastCleanup = time.Now()
|
ss.lastCleanup = time.Now()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determines whether the session firewall is enabled.
|
|
||||||
func (ss *sessions) isSessionFirewallEnabled() bool {
|
|
||||||
ss.core.config.Mutex.RLock()
|
|
||||||
defer ss.core.config.Mutex.RUnlock()
|
|
||||||
|
|
||||||
return ss.core.config.Current.SessionFirewall.Enable
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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.core.config.Mutex.RLock()
|
ss.isAllowedMutex.RLock()
|
||||||
defer ss.core.config.Mutex.RUnlock()
|
defer ss.isAllowedMutex.RUnlock()
|
||||||
|
|
||||||
// Allow by default if the session firewall is disabled
|
if ss.isAllowedHandler == nil {
|
||||||
if !ss.isSessionFirewallEnabled() {
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
// Prepare for checking whitelist/blacklist
|
|
||||||
var box crypto.BoxPubKey
|
return ss.isAllowedHandler(pubkey, initiator)
|
||||||
// Reject blacklisted nodes
|
|
||||||
for _, b := range ss.core.config.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 ss.core.config.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 ss.core.config.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 ss.core.peers.ports.Load().(map[switchPort]*peer) {
|
|
||||||
if peer.box == *pubkey {
|
|
||||||
isDirectPeer = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Allow direct peers if appropriate
|
|
||||||
if ss.core.config.Current.SessionFirewall.AllowFromDirect && isDirectPeer {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
// Allow remote nodes if appropriate
|
|
||||||
if ss.core.config.Current.SessionFirewall.AllowFromRemote && !isDirectPeer {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
// Finally, default-deny if not matching any of the above rules
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gets the session corresponding to a given handle.
|
// Gets the session corresponding to a given handle.
|
||||||
@ -444,12 +392,11 @@ func (ss *sessions) sendPingPong(sinfo *sessionInfo, isPong bool) {
|
|||||||
func (ss *sessions) handlePing(ping *sessionPing) {
|
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 if the session is allowed
|
||||||
if !isIn && ss.isSessionFirewallEnabled() {
|
if !isIn && !ss.isSessionAllowed(&ping.SendPermPub, false) {
|
||||||
if !ss.isSessionAllowed(&ping.SendPermPub, false) {
|
return
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
// Create the session if it doesn't already exist
|
||||||
if !isIn {
|
if !isIn {
|
||||||
ss.createSession(&ping.SendPermPub)
|
ss.createSession(&ping.SendPermPub)
|
||||||
sinfo, isIn = ss.getByTheirPerm(&ping.SendPermPub)
|
sinfo, isIn = ss.getByTheirPerm(&ping.SendPermPub)
|
||||||
|
Loading…
Reference in New Issue
Block a user