mirror of
				https://github.com/yggdrasil-network/yggdrasil-go.git
				synced 2025-11-04 03:05:07 +03:00 
			
		
		
		
	Add initial crypto-key routing handlers
This commit is contained in:
		
							parent
							
								
									f088a244da
								
							
						
					
					
						commit
						52206dc381
					
				
					 4 changed files with 130 additions and 8 deletions
				
			
		
							
								
								
									
										104
									
								
								src/yggdrasil/ckr.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								src/yggdrasil/ckr.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,104 @@
 | 
			
		|||
package yggdrasil
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/hex"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"net"
 | 
			
		||||
	"sort"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// This module implements crypto-key routing, similar to Wireguard, where we
 | 
			
		||||
// allow traffic for non-Yggdrasil ranges to be routed over Yggdrasil.
 | 
			
		||||
 | 
			
		||||
type cryptokey struct {
 | 
			
		||||
	core       *Core
 | 
			
		||||
	enabled    bool
 | 
			
		||||
	ipv4routes []cryptokey_route
 | 
			
		||||
	ipv6routes []cryptokey_route
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type cryptokey_route struct {
 | 
			
		||||
	subnet      net.IPNet
 | 
			
		||||
	destination []byte
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *cryptokey) init(core *Core) {
 | 
			
		||||
	c.core = core
 | 
			
		||||
	c.ipv4routes = make([]cryptokey_route, 0)
 | 
			
		||||
	c.ipv6routes = make([]cryptokey_route, 0)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *cryptokey) isEnabled() bool {
 | 
			
		||||
	return c.enabled
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *cryptokey) addRoute(cidr string, dest string) error {
 | 
			
		||||
	// Is the CIDR we've been given valid?
 | 
			
		||||
	_, ipnet, err := net.ParseCIDR(cidr)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Get the prefix length and size
 | 
			
		||||
	prefixlen, prefixsize := ipnet.Mask.Size()
 | 
			
		||||
 | 
			
		||||
	// Check if the prefix is IPv4 or IPv6
 | 
			
		||||
	if prefixsize == net.IPv6len*8 {
 | 
			
		||||
		// IPv6
 | 
			
		||||
		for _, route := range c.ipv6routes {
 | 
			
		||||
			// Do we already have a route for this subnet?
 | 
			
		||||
			routeprefixlen, _ := route.subnet.Mask.Size()
 | 
			
		||||
			if route.subnet.IP.Equal(ipnet.IP) && routeprefixlen == prefixlen {
 | 
			
		||||
				return errors.New("IPv6 route already exists")
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		// Decode the public key
 | 
			
		||||
		if boxPubKey, err := hex.DecodeString(dest); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		} else {
 | 
			
		||||
			// Add the new crypto-key route
 | 
			
		||||
			c.ipv6routes = append(c.ipv6routes, cryptokey_route{
 | 
			
		||||
				subnet:      *ipnet,
 | 
			
		||||
				destination: boxPubKey,
 | 
			
		||||
			})
 | 
			
		||||
			// Sort so most specific routes are first
 | 
			
		||||
			sort.Slice(c.ipv6routes, func(i, j int) bool {
 | 
			
		||||
				im, _ := c.ipv6routes[i].subnet.Mask.Size()
 | 
			
		||||
				jm, _ := c.ipv6routes[j].subnet.Mask.Size()
 | 
			
		||||
				return im > jm
 | 
			
		||||
			})
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
	} else if prefixsize == net.IPv4len*8 {
 | 
			
		||||
		// IPv4
 | 
			
		||||
		return errors.New("IPv4 not supported at this time")
 | 
			
		||||
	}
 | 
			
		||||
	return errors.New("Unspecified error")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *cryptokey) getPublicKeyForAddress(addr string) (boxPubKey, error) {
 | 
			
		||||
	ipaddr := net.ParseIP(addr)
 | 
			
		||||
 | 
			
		||||
	if ipaddr.To4() == nil {
 | 
			
		||||
		// IPv6
 | 
			
		||||
		for _, route := range c.ipv6routes {
 | 
			
		||||
			if route.subnet.Contains(ipaddr) {
 | 
			
		||||
				var box boxPubKey
 | 
			
		||||
				copy(box[:boxPubKeyLen], route.destination)
 | 
			
		||||
				return box, nil
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		// IPv4
 | 
			
		||||
		return boxPubKey{}, errors.New("IPv4 not supported at this time")
 | 
			
		||||
		/*
 | 
			
		||||
			    for _, route := range c.ipv4routes {
 | 
			
		||||
						if route.subnet.Contains(ipaddr) {
 | 
			
		||||
							return route.destination, nil
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
		*/
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return boxPubKey{}, errors.New("No route")
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -17,6 +17,7 @@ type NodeConfig struct {
 | 
			
		|||
	IfTAPMode                   bool                `comment:"Set local network interface to TAP mode rather than TUN mode if\nsupported by your platform - option will be ignored if not."`
 | 
			
		||||
	IfMTU                       int                 `comment:"Maximux Transmission Unit (MTU) size for your local TUN/TAP interface.\nDefault is the largest supported size for your platform. The lowest\npossible value is 1280."`
 | 
			
		||||
	SessionFirewall             SessionFirewall     `comment:"The session firewall controls who can send/receive network traffic\nto/from. This is useful if you want to protect this node without\nresorting to using a real firewall. This does not affect traffic\nbeing routed via this node to somewhere else. Rules are prioritised as\nfollows: blacklist, whitelist, always allow outgoing, direct, remote."`
 | 
			
		||||
	TunnelRouting               TunnelRouting       `comment:"Allow tunneling non-Yggdrasil traffic over Yggdrasil."`
 | 
			
		||||
	//Net                         NetConfig `comment:"Extended options for connecting to peers over other networks."`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -26,6 +27,7 @@ type NetConfig struct {
 | 
			
		|||
	I2P I2PConfig `comment:"Experimental options for configuring peerings over I2P."`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SessionFirewall controls the session firewall configuration
 | 
			
		||||
type SessionFirewall struct {
 | 
			
		||||
	Enable                        bool     `comment:"Enable or disable the session firewall. If disabled, network traffic\nfrom any node will be allowed. If enabled, the below rules apply."`
 | 
			
		||||
	AllowFromDirect               bool     `comment:"Allow network traffic from directly connected peers."`
 | 
			
		||||
| 
						 | 
				
			
			@ -34,3 +36,9 @@ type SessionFirewall struct {
 | 
			
		|||
	WhitelistEncryptionPublicKeys []string `comment:"List of public keys from which network traffic is always accepted,\nregardless of AllowFromDirect or AllowFromRemote."`
 | 
			
		||||
	BlacklistEncryptionPublicKeys []string `comment:"List of public keys from which network traffic is always rejected,\nregardless of the whitelist, AllowFromDirect or AllowFromRemote."`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TunnelRouting contains the crypto-key routing tables for tunneling
 | 
			
		||||
type TunnelRouting struct {
 | 
			
		||||
	Enable     bool              `comment:"Enable or disable tunneling."`
 | 
			
		||||
	IPv6Routes map[string]string `comment:"IPv6 subnets, mapped to the public keys to which they should be routed."`
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -121,6 +121,14 @@ func (c *Core) Start(nc *config.NodeConfig, log *log.Logger) error {
 | 
			
		|||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if nc.TunnelRouting.Enable {
 | 
			
		||||
		for ipv6, pubkey := range nc.TunnelRouting.IPv6Routes {
 | 
			
		||||
			if err := c.router.cryptokey.addRoute(ipv6, pubkey); err != nil {
 | 
			
		||||
				panic(err)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := c.admin.start(); err != nil {
 | 
			
		||||
		c.log.Println("Failed to start admin socket")
 | 
			
		||||
		return err
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -32,14 +32,15 @@ import (
 | 
			
		|||
// The router struct has channels to/from the tun/tap device and a self peer (0), which is how messages are passed between this node and the peers/switch layer.
 | 
			
		||||
// The router's mainLoop goroutine is responsible for managing all information related to the dht, searches, and crypto sessions.
 | 
			
		||||
type router struct {
 | 
			
		||||
	core  *Core
 | 
			
		||||
	addr  address
 | 
			
		||||
	in    <-chan []byte // packets we received from the network, link to peer's "out"
 | 
			
		||||
	out   func([]byte)  // packets we're sending to the network, link to peer's "in"
 | 
			
		||||
	recv  chan<- []byte // place where the tun pulls received packets from
 | 
			
		||||
	send  <-chan []byte // place where the tun puts outgoing packets
 | 
			
		||||
	reset chan struct{} // signal that coords changed (re-init sessions/dht)
 | 
			
		||||
	admin chan func()   // pass a lambda for the admin socket to query stuff
 | 
			
		||||
	core      *Core
 | 
			
		||||
	addr      address
 | 
			
		||||
	in        <-chan []byte // packets we received from the network, link to peer's "out"
 | 
			
		||||
	out       func([]byte)  // packets we're sending to the network, link to peer's "in"
 | 
			
		||||
	recv      chan<- []byte // place where the tun pulls received packets from
 | 
			
		||||
	send      <-chan []byte // place where the tun puts outgoing packets
 | 
			
		||||
	reset     chan struct{} // signal that coords changed (re-init sessions/dht)
 | 
			
		||||
	admin     chan func()   // pass a lambda for the admin socket to query stuff
 | 
			
		||||
	cryptokey cryptokey
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Initializes the router struct, which includes setting up channels to/from the tun/tap.
 | 
			
		||||
| 
						 | 
				
			
			@ -67,6 +68,7 @@ func (r *router) init(core *Core) {
 | 
			
		|||
	r.core.tun.send = send
 | 
			
		||||
	r.reset = make(chan struct{}, 1)
 | 
			
		||||
	r.admin = make(chan func())
 | 
			
		||||
	r.cryptokey.init(r.core)
 | 
			
		||||
	// go r.mainLoop()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue