mirror of
				https://github.com/juanfont/headscale.git
				synced 2025-10-28 10:51:44 +01:00 
			
		
		
		
	This is a massive commit that restructures the code into modules:
db/
    All functions related to modifying the Database
types/
    All type definitions and methods that can be exclusivly used on
    these types without dependencies
policy/
    All Policy related code, now without dependencies on the Database.
policy/matcher/
    Dedicated code to match machines in a list of FilterRules
Signed-off-by: Kristoffer Dalby <kristoffer@tailscale.com>
		
	
			
		
			
				
	
	
		
			100 lines
		
	
	
		
			2.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			100 lines
		
	
	
		
			2.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Codehere is mostly taken from github.com/tailscale/tailscale
 | |
| // Copyright (c) 2020 Tailscale Inc & AUTHORS All rights reserved.
 | |
| // Use of this source code is governed by a BSD-style
 | |
| // license that can be found in the LICENSE file.
 | |
| 
 | |
| package db
 | |
| 
 | |
| import (
 | |
| 	"errors"
 | |
| 	"fmt"
 | |
| 	"net/netip"
 | |
| 
 | |
| 	"github.com/juanfont/headscale/hscontrol/types"
 | |
| 	"github.com/juanfont/headscale/hscontrol/util"
 | |
| 	"go4.org/netipx"
 | |
| )
 | |
| 
 | |
| var ErrCouldNotAllocateIP = errors.New("could not find any suitable IP")
 | |
| 
 | |
| func (hsdb *HSDatabase) getAvailableIPs() (types.MachineAddresses, error) {
 | |
| 	var ips types.MachineAddresses
 | |
| 	var err error
 | |
| 	for _, ipPrefix := range hsdb.ipPrefixes {
 | |
| 		var ip *netip.Addr
 | |
| 		ip, err = hsdb.getAvailableIP(ipPrefix)
 | |
| 		if err != nil {
 | |
| 			return ips, err
 | |
| 		}
 | |
| 		ips = append(ips, *ip)
 | |
| 	}
 | |
| 
 | |
| 	return ips, err
 | |
| }
 | |
| 
 | |
| func (hsdb *HSDatabase) getAvailableIP(ipPrefix netip.Prefix) (*netip.Addr, error) {
 | |
| 	usedIps, err := hsdb.getUsedIPs()
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	ipPrefixNetworkAddress, ipPrefixBroadcastAddress := util.GetIPPrefixEndpoints(ipPrefix)
 | |
| 
 | |
| 	// Get the first IP in our prefix
 | |
| 	ip := ipPrefixNetworkAddress.Next()
 | |
| 
 | |
| 	for {
 | |
| 		if !ipPrefix.Contains(ip) {
 | |
| 			return nil, ErrCouldNotAllocateIP
 | |
| 		}
 | |
| 
 | |
| 		switch {
 | |
| 		case ip.Compare(ipPrefixBroadcastAddress) == 0:
 | |
| 			fallthrough
 | |
| 		case usedIps.Contains(ip):
 | |
| 			fallthrough
 | |
| 		case ip == netip.Addr{} || ip.IsLoopback():
 | |
| 			ip = ip.Next()
 | |
| 
 | |
| 			continue
 | |
| 
 | |
| 		default:
 | |
| 			return &ip, nil
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (hsdb *HSDatabase) getUsedIPs() (*netipx.IPSet, error) {
 | |
| 	// FIXME: This really deserves a better data model,
 | |
| 	// but this was quick to get running and it should be enough
 | |
| 	// to begin experimenting with a dual stack tailnet.
 | |
| 	var addressesSlices []string
 | |
| 	hsdb.db.Model(&types.Machine{}).Pluck("ip_addresses", &addressesSlices)
 | |
| 
 | |
| 	var ips netipx.IPSetBuilder
 | |
| 	for _, slice := range addressesSlices {
 | |
| 		var machineAddresses types.MachineAddresses
 | |
| 		err := machineAddresses.Scan(slice)
 | |
| 		if err != nil {
 | |
| 			return &netipx.IPSet{}, fmt.Errorf(
 | |
| 				"failed to read ip from database: %w",
 | |
| 				err,
 | |
| 			)
 | |
| 		}
 | |
| 
 | |
| 		for _, ip := range machineAddresses {
 | |
| 			ips.Add(ip)
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	ipSet, err := ips.IPSet()
 | |
| 	if err != nil {
 | |
| 		return &netipx.IPSet{}, fmt.Errorf(
 | |
| 			"failed to build IP Set: %w",
 | |
| 			err,
 | |
| 		)
 | |
| 	}
 | |
| 
 | |
| 	return ipSet, nil
 | |
| }
 |