mirror of
				https://github.com/yggdrasil-network/yggdrasil-go.git
				synced 2025-11-04 11:15: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
 | 
							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
 | 
						// Check if we already have this CIDR
 | 
				
			||||||
	for _, subnet := range c.ipv6sources {
 | 
						for _, subnet := range *routingsources {
 | 
				
			||||||
		if subnet.String() == ipnet.String() {
 | 
							if subnet.String() == ipnet.String() {
 | 
				
			||||||
			return errors.New("Source subnet already configured")
 | 
								return errors.New("Source subnet already configured")
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Add the source subnet
 | 
						// Add the source subnet
 | 
				
			||||||
	c.ipv6sources = append(c.ipv6sources, *ipnet)
 | 
						*routingsources = append(*routingsources, *ipnet)
 | 
				
			||||||
	c.core.log.Println("Added CKR source subnet", cidr)
 | 
						c.core.log.Println("Added CKR source subnet", cidr)
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -102,8 +117,21 @@ func (c *cryptokey) addRoute(cidr string, dest string) error {
 | 
				
			||||||
	// Get the prefix length and size
 | 
						// Get the prefix length and size
 | 
				
			||||||
	_, prefixsize := ipnet.Mask.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
 | 
						// Check if the prefix is IPv4 or IPv6
 | 
				
			||||||
	if prefixsize == net.IPv6len*8 {
 | 
						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?
 | 
						// Is the route an Yggdrasil destination?
 | 
				
			||||||
	var addr address
 | 
						var addr address
 | 
				
			||||||
	var snet subnet
 | 
						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")
 | 
							return errors.New("Can't specify Yggdrasil destination as crypto-key route")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	// Do we already have a route for this subnet?
 | 
						// Do we already have a route for this subnet?
 | 
				
			||||||
		for _, route := range c.ipv6routes {
 | 
						for _, route := range *routingtable {
 | 
				
			||||||
		if route.subnet.String() == ipnet.String() {
 | 
							if route.subnet.String() == ipnet.String() {
 | 
				
			||||||
			return errors.New(fmt.Sprintf("Route already exists for %s", cidr))
 | 
								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
 | 
							return err
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		// Add the new crypto-key route
 | 
							// Add the new crypto-key route
 | 
				
			||||||
			c.ipv6routes = append(c.ipv6routes, cryptokey_route{
 | 
							*routingtable = append(*routingtable, cryptokey_route{
 | 
				
			||||||
			subnet:      *ipnet,
 | 
								subnet:      *ipnet,
 | 
				
			||||||
			destination: boxPubKey,
 | 
								destination: boxPubKey,
 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Sort so most specific routes are first
 | 
							// Sort so most specific routes are first
 | 
				
			||||||
			sort.Slice(c.ipv6routes, func(i, j int) bool {
 | 
							sort.Slice(*routingtable, func(i, j int) bool {
 | 
				
			||||||
				im, _ := c.ipv6routes[i].subnet.Mask.Size()
 | 
								im, _ := (*routingtable)[i].subnet.Mask.Size()
 | 
				
			||||||
				jm, _ := c.ipv6routes[j].subnet.Mask.Size()
 | 
								jm, _ := (*routingtable)[j].subnet.Mask.Size()
 | 
				
			||||||
			return im > jm
 | 
								return im > jm
 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// Clear the cache as this route might change future routing
 | 
							// Clear the cache as this route might change future routing
 | 
				
			||||||
		// Setting an empty slice keeps the memory whereas nil invokes GC
 | 
							// Setting an empty slice keeps the memory whereas nil invokes GC
 | 
				
			||||||
			for k := range c.ipv6cache {
 | 
							for k := range *routingcache {
 | 
				
			||||||
				delete(c.ipv6cache, k)
 | 
								delete(*routingcache, k)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		c.core.log.Println("Added CKR destination subnet", cidr)
 | 
							c.core.log.Println("Added CKR destination subnet", cidr)
 | 
				
			||||||
		return nil
 | 
							return nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	} else if prefixsize == net.IPv4len*8 {
 | 
					
 | 
				
			||||||
		// IPv4
 | 
					 | 
				
			||||||
		return errors.New("IPv4 not supported at this time")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return errors.New("Unspecified error")
 | 
						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
 | 
						// Check if the address is a valid Yggdrasil address - if so it
 | 
				
			||||||
	// is exempt from all CKR checking
 | 
						// is exempt from all CKR checking
 | 
				
			||||||
	if addr.isValid() {
 | 
						if addr.isValid() {
 | 
				
			||||||
		return boxPubKey{}, errors.New("Cannot look up CKR for Yggdrasil addresses")
 | 
							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
 | 
						// 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
 | 
							var box boxPubKey
 | 
				
			||||||
		copy(box[:boxPubKeyLen], route.destination)
 | 
							copy(box[:boxPubKeyLen], route.destination)
 | 
				
			||||||
		return box, nil
 | 
							return box, nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// No cache was found - start by converting the address into a net.IP
 | 
						// No cache was found - start by converting the address into a net.IP
 | 
				
			||||||
	ip := make(net.IP, 16)
 | 
						ip := make(net.IP, addrlen)
 | 
				
			||||||
	copy(ip[:16], addr[:])
 | 
						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
 | 
						// Check if we have a route. At this point c.ipv6routes should be
 | 
				
			||||||
	// pre-sorted so that the most specific routes are first
 | 
						// 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?
 | 
							// Does this subnet match the given IP?
 | 
				
			||||||
		if route.subnet.Contains(ip) {
 | 
							if route.subnet.Contains(ip) {
 | 
				
			||||||
			// Cache the entry for future packets to get a faster lookup
 | 
								// Cache the entry for future packets to get a faster lookup
 | 
				
			||||||
				c.ipv6cache[addr] = route
 | 
								(*routingcache)[addr] = route
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// Return the boxPubKey
 | 
								// Return the boxPubKey
 | 
				
			||||||
			var box boxPubKey
 | 
								var box boxPubKey
 | 
				
			||||||
| 
						 | 
					@ -185,10 +223,6 @@ func (c *cryptokey) getPublicKeyForAddress(addr address) (boxPubKey, error) {
 | 
				
			||||||
			return box, nil
 | 
								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
 | 
						// No route was found if we got to this point
 | 
				
			||||||
	return boxPubKey{}, errors.New(fmt.Sprintf("No route to %s", ip.String()))
 | 
						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."`
 | 
						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."`
 | 
						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."`
 | 
						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)
 | 
									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 {
 | 
						if err := c.admin.start(); err != nil {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -134,7 +134,7 @@ func (r *router) sendPacket(bs []byte) {
 | 
				
			||||||
	copy(dest[:], bs[24:])
 | 
						copy(dest[:], bs[24:])
 | 
				
			||||||
	copy(snet[:], bs[24:])
 | 
						copy(snet[:], bs[24:])
 | 
				
			||||||
	if !dest.isValid() && !snet.isValid() {
 | 
						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))
 | 
								addr := *address_addrForNodeID(getNodeID(&key))
 | 
				
			||||||
			copy(dest[:], addr[:])
 | 
								copy(dest[:], addr[:])
 | 
				
			||||||
			copy(snet[:], addr[:])
 | 
								copy(snet[:], addr[:])
 | 
				
			||||||
| 
						 | 
					@ -273,7 +273,7 @@ func (r *router) recvPacket(bs []byte, sinfo *sessionInfo) {
 | 
				
			||||||
	case source.isValid() && source == sinfo.theirAddr:
 | 
						case source.isValid() && source == sinfo.theirAddr:
 | 
				
			||||||
	case snet.isValid() && snet == sinfo.theirSubnet:
 | 
						case snet.isValid() && snet == sinfo.theirSubnet:
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		key, err := r.cryptokey.getPublicKeyForAddress(source)
 | 
							key, err := r.cryptokey.getPublicKeyForAddress(source, 16)
 | 
				
			||||||
		if err != nil || key != sinfo.theirPermPub {
 | 
							if err != nil || key != sinfo.theirPermPub {
 | 
				
			||||||
			util_putBytes(bs)
 | 
								util_putBytes(bs)
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue