mirror of
				https://github.com/yggdrasil-network/yggdrasil-go.git
				synced 2025-11-04 03:05:07 +03:00 
			
		
		
		
	Support IPv4 in ckr.go
This commit is contained in:
		
							parent
							
								
									cb7a5f17d9
								
							
						
					
					
						commit
						424faa1c51
					
				
					 4 changed files with 113 additions and 67 deletions
				
			
		| 
						 | 
				
			
			@ -79,15 +79,30 @@ func (c *cryptokey) addSourceSubnet(cidr string) error {
 | 
			
		|||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Get the prefix length and size
 | 
			
		||||
	_, prefixsize := ipnet.Mask.Size()
 | 
			
		||||
 | 
			
		||||
	// Build our references to the routing sources
 | 
			
		||||
	var routingsources *[]net.IPNet
 | 
			
		||||
 | 
			
		||||
	// Check if the prefix is IPv4 or IPv6
 | 
			
		||||
	if prefixsize == net.IPv6len*8 {
 | 
			
		||||
		routingsources = &c.ipv6sources
 | 
			
		||||
	} else if prefixsize == net.IPv4len*8 {
 | 
			
		||||
		routingsources = &c.ipv4sources
 | 
			
		||||
	} else {
 | 
			
		||||
		return errors.New("Unexpected prefix size")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Check if we already have this CIDR
 | 
			
		||||
	for _, subnet := range c.ipv6sources {
 | 
			
		||||
	for _, subnet := range *routingsources {
 | 
			
		||||
		if subnet.String() == ipnet.String() {
 | 
			
		||||
			return errors.New("Source subnet already configured")
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Add the source subnet
 | 
			
		||||
	c.ipv6sources = append(c.ipv6sources, *ipnet)
 | 
			
		||||
	*routingsources = append(*routingsources, *ipnet)
 | 
			
		||||
	c.core.log.Println("Added CKR source subnet", cidr)
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -102,8 +117,21 @@ func (c *cryptokey) addRoute(cidr string, dest string) error {
 | 
			
		|||
	// Get the prefix length and size
 | 
			
		||||
	_, prefixsize := ipnet.Mask.Size()
 | 
			
		||||
 | 
			
		||||
	// Build our references to the routing table and cache
 | 
			
		||||
	var routingtable *[]cryptokey_route
 | 
			
		||||
	var routingcache *map[address]cryptokey_route
 | 
			
		||||
 | 
			
		||||
	// Check if the prefix is IPv4 or IPv6
 | 
			
		||||
	if prefixsize == net.IPv6len*8 {
 | 
			
		||||
		routingtable = &c.ipv6routes
 | 
			
		||||
		routingcache = &c.ipv6cache
 | 
			
		||||
	} else if prefixsize == net.IPv4len*8 {
 | 
			
		||||
		routingtable = &c.ipv4routes
 | 
			
		||||
		routingcache = &c.ipv4cache
 | 
			
		||||
	} else {
 | 
			
		||||
		return errors.New("Unexpected prefix size")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Is the route an Yggdrasil destination?
 | 
			
		||||
	var addr address
 | 
			
		||||
	var snet subnet
 | 
			
		||||
| 
						 | 
				
			
			@ -113,7 +141,7 @@ func (c *cryptokey) addRoute(cidr string, dest string) error {
 | 
			
		|||
		return errors.New("Can't specify Yggdrasil destination as crypto-key route")
 | 
			
		||||
	}
 | 
			
		||||
	// Do we already have a route for this subnet?
 | 
			
		||||
		for _, route := range c.ipv6routes {
 | 
			
		||||
	for _, route := range *routingtable {
 | 
			
		||||
		if route.subnet.String() == ipnet.String() {
 | 
			
		||||
			return errors.New(fmt.Sprintf("Route already exists for %s", cidr))
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -123,61 +151,71 @@ func (c *cryptokey) addRoute(cidr string, dest string) error {
 | 
			
		|||
		return err
 | 
			
		||||
	} else {
 | 
			
		||||
		// Add the new crypto-key route
 | 
			
		||||
			c.ipv6routes = append(c.ipv6routes, cryptokey_route{
 | 
			
		||||
		*routingtable = append(*routingtable, 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()
 | 
			
		||||
		sort.Slice(*routingtable, func(i, j int) bool {
 | 
			
		||||
			im, _ := (*routingtable)[i].subnet.Mask.Size()
 | 
			
		||||
			jm, _ := (*routingtable)[j].subnet.Mask.Size()
 | 
			
		||||
			return im > jm
 | 
			
		||||
		})
 | 
			
		||||
 | 
			
		||||
		// Clear the cache as this route might change future routing
 | 
			
		||||
		// Setting an empty slice keeps the memory whereas nil invokes GC
 | 
			
		||||
			for k := range c.ipv6cache {
 | 
			
		||||
				delete(c.ipv6cache, k)
 | 
			
		||||
		for k := range *routingcache {
 | 
			
		||||
			delete(*routingcache, k)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		c.core.log.Println("Added CKR destination subnet", cidr)
 | 
			
		||||
		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 address) (boxPubKey, error) {
 | 
			
		||||
func (c *cryptokey) getPublicKeyForAddress(addr address, addrlen int) (boxPubKey, error) {
 | 
			
		||||
	// Check if the address is a valid Yggdrasil address - if so it
 | 
			
		||||
	// is exempt from all CKR checking
 | 
			
		||||
	if addr.isValid() {
 | 
			
		||||
		return boxPubKey{}, errors.New("Cannot look up CKR for Yggdrasil addresses")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Build our references to the routing table and cache
 | 
			
		||||
	var routingtable *[]cryptokey_route
 | 
			
		||||
	var routingcache *map[address]cryptokey_route
 | 
			
		||||
 | 
			
		||||
	// Check if the prefix is IPv4 or IPv6
 | 
			
		||||
	if addrlen == net.IPv6len {
 | 
			
		||||
		routingtable = &c.ipv6routes
 | 
			
		||||
		routingcache = &c.ipv6cache
 | 
			
		||||
	} else if addrlen == net.IPv4len {
 | 
			
		||||
		routingtable = &c.ipv4routes
 | 
			
		||||
		routingcache = &c.ipv4cache
 | 
			
		||||
	} else {
 | 
			
		||||
		return boxPubKey{}, errors.New("Unexpected prefix size")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Check if there's a cache entry for this addr
 | 
			
		||||
	if route, ok := c.ipv6cache[addr]; ok {
 | 
			
		||||
	if route, ok := (*routingcache)[addr]; ok {
 | 
			
		||||
		var box boxPubKey
 | 
			
		||||
		copy(box[:boxPubKeyLen], route.destination)
 | 
			
		||||
		return box, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// No cache was found - start by converting the address into a net.IP
 | 
			
		||||
	ip := make(net.IP, 16)
 | 
			
		||||
	copy(ip[:16], addr[:])
 | 
			
		||||
	ip := make(net.IP, addrlen)
 | 
			
		||||
	copy(ip[:addrlen], addr[:])
 | 
			
		||||
 | 
			
		||||
	// Check whether it's an IPv4 or an IPv6 address
 | 
			
		||||
	if ip.To4() == nil {
 | 
			
		||||
	// Check if we have a route. At this point c.ipv6routes should be
 | 
			
		||||
	// pre-sorted so that the most specific routes are first
 | 
			
		||||
		for _, route := range c.ipv6routes {
 | 
			
		||||
	for _, route := range *routingtable {
 | 
			
		||||
		// Does this subnet match the given IP?
 | 
			
		||||
		if route.subnet.Contains(ip) {
 | 
			
		||||
			// Cache the entry for future packets to get a faster lookup
 | 
			
		||||
				c.ipv6cache[addr] = route
 | 
			
		||||
			(*routingcache)[addr] = route
 | 
			
		||||
 | 
			
		||||
			// Return the boxPubKey
 | 
			
		||||
			var box boxPubKey
 | 
			
		||||
| 
						 | 
				
			
			@ -185,10 +223,6 @@ func (c *cryptokey) getPublicKeyForAddress(addr address) (boxPubKey, error) {
 | 
			
		|||
			return box, nil
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	} else {
 | 
			
		||||
		// IPv4 isn't supported yet
 | 
			
		||||
		return boxPubKey{}, errors.New("IPv4 not supported at this time")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// No route was found if we got to this point
 | 
			
		||||
	return boxPubKey{}, errors.New(fmt.Sprintf("No route to %s", ip.String()))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -42,4 +42,6 @@ type TunnelRouting struct {
 | 
			
		|||
	Enable           bool              `comment:"Enable or disable tunneling."`
 | 
			
		||||
	IPv6Destinations map[string]string `comment:"IPv6 subnets, mapped to the EncryptionPublicKey to which they should\nbe routed to."`
 | 
			
		||||
	IPv6Sources      []string          `comment:"Optional IPv6 subnets which are allowed to be used as source addresses\nin addition to this node's Yggdrasil address/subnet."`
 | 
			
		||||
	IPv4Destinations map[string]string `comment:"IPv4 subnets, mapped to the EncryptionPublicKey to which they should\nbe routed to."`
 | 
			
		||||
	IPv4Sources      []string          `comment:"Optional IPv4 subnets which are allowed to be used as source addresses."`
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -134,6 +134,16 @@ func (c *Core) Start(nc *config.NodeConfig, log *log.Logger) error {
 | 
			
		|||
				panic(err)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		for ipv4, pubkey := range nc.TunnelRouting.IPv4Destinations {
 | 
			
		||||
			if err := c.router.cryptokey.addRoute(ipv4, pubkey); err != nil {
 | 
			
		||||
				panic(err)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		for _, source := range nc.TunnelRouting.IPv4Sources {
 | 
			
		||||
			if c.router.cryptokey.addSourceSubnet(source); err != nil {
 | 
			
		||||
				panic(err)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := c.admin.start(); err != nil {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -134,7 +134,7 @@ func (r *router) sendPacket(bs []byte) {
 | 
			
		|||
	copy(dest[:], bs[24:])
 | 
			
		||||
	copy(snet[:], bs[24:])
 | 
			
		||||
	if !dest.isValid() && !snet.isValid() {
 | 
			
		||||
		if key, err := r.cryptokey.getPublicKeyForAddress(dest); err == nil {
 | 
			
		||||
		if key, err := r.cryptokey.getPublicKeyForAddress(dest, 16); err == nil {
 | 
			
		||||
			addr := *address_addrForNodeID(getNodeID(&key))
 | 
			
		||||
			copy(dest[:], addr[:])
 | 
			
		||||
			copy(snet[:], addr[:])
 | 
			
		||||
| 
						 | 
				
			
			@ -273,7 +273,7 @@ func (r *router) recvPacket(bs []byte, sinfo *sessionInfo) {
 | 
			
		|||
	case source.isValid() && source == sinfo.theirAddr:
 | 
			
		||||
	case snet.isValid() && snet == sinfo.theirSubnet:
 | 
			
		||||
	default:
 | 
			
		||||
		key, err := r.cryptokey.getPublicKeyForAddress(source)
 | 
			
		||||
		key, err := r.cryptokey.getPublicKeyForAddress(source, 16)
 | 
			
		||||
		if err != nil || key != sinfo.theirPermPub {
 | 
			
		||||
			util_putBytes(bs)
 | 
			
		||||
			return
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue