mirror of
				https://github.com/yggdrasil-network/yggdrasil-go.git
				synced 2025-11-04 11:15: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."`
 | 
						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."`
 | 
						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."`
 | 
						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."`
 | 
						//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."`
 | 
						I2P I2PConfig `comment:"Experimental options for configuring peerings over I2P."`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// SessionFirewall controls the session firewall configuration
 | 
				
			||||||
type SessionFirewall struct {
 | 
					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."`
 | 
						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."`
 | 
						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."`
 | 
						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."`
 | 
						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
 | 
							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 {
 | 
						if err := c.admin.start(); err != nil {
 | 
				
			||||||
		c.log.Println("Failed to start admin socket")
 | 
							c.log.Println("Failed to start admin socket")
 | 
				
			||||||
		return err
 | 
							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 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.
 | 
					// The router's mainLoop goroutine is responsible for managing all information related to the dht, searches, and crypto sessions.
 | 
				
			||||||
type router struct {
 | 
					type router struct {
 | 
				
			||||||
	core  *Core
 | 
						core      *Core
 | 
				
			||||||
	addr  address
 | 
						addr      address
 | 
				
			||||||
	in    <-chan []byte // packets we received from the network, link to peer's "out"
 | 
						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"
 | 
						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
 | 
						recv      chan<- []byte // place where the tun pulls received packets from
 | 
				
			||||||
	send  <-chan []byte // place where the tun puts outgoing packets
 | 
						send      <-chan []byte // place where the tun puts outgoing packets
 | 
				
			||||||
	reset chan struct{} // signal that coords changed (re-init sessions/dht)
 | 
						reset     chan struct{} // signal that coords changed (re-init sessions/dht)
 | 
				
			||||||
	admin chan func()   // pass a lambda for the admin socket to query stuff
 | 
						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.
 | 
					// 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.core.tun.send = send
 | 
				
			||||||
	r.reset = make(chan struct{}, 1)
 | 
						r.reset = make(chan struct{}, 1)
 | 
				
			||||||
	r.admin = make(chan func())
 | 
						r.admin = make(chan func())
 | 
				
			||||||
 | 
						r.cryptokey.init(r.core)
 | 
				
			||||||
	// go r.mainLoop()
 | 
						// go r.mainLoop()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue