mirror of
				https://github.com/yggdrasil-network/yggdrasil-go.git
				synced 2025-11-04 11:15:07 +03: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
					
				
					 2 changed files with 35 additions and 76 deletions
				
			
		| 
						 | 
					@ -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"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -116,6 +115,8 @@ type sessions struct {
 | 
				
			||||||
	listenerMutex    sync.Mutex
 | 
						listenerMutex    sync.Mutex
 | 
				
			||||||
	reconfigure      chan chan error
 | 
						reconfigure      chan chan error
 | 
				
			||||||
	lastCleanup      time.Time
 | 
						lastCleanup      time.Time
 | 
				
			||||||
 | 
						isAllowedHandler func(pubkey *crypto.BoxPubKey, initiator bool) bool // Returns true or false if session setup is allowed
 | 
				
			||||||
 | 
						isAllowedMutex   sync.RWMutex                                        // Protects the above
 | 
				
			||||||
	permShared       map[crypto.BoxPubKey]*crypto.BoxSharedKey           // Maps known permanent keys to their shared key, used by DHT a lot
 | 
						permShared       map[crypto.BoxPubKey]*crypto.BoxSharedKey           // Maps known permanent keys to their shared key, used by DHT a lot
 | 
				
			||||||
	sinfos           map[crypto.Handle]*sessionInfo                      // Maps (secret) handle onto session info
 | 
						sinfos           map[crypto.Handle]*sessionInfo                      // Maps (secret) handle onto session info
 | 
				
			||||||
	conns            map[crypto.Handle]*Conn                             // Maps (secret) handle onto connections
 | 
						conns            map[crypto.Handle]*Conn                             // Maps (secret) handle onto connections
 | 
				
			||||||
| 
						 | 
					@ -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…
	
	Add table
		Add a link
		
	
		Reference in a new issue