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
 | 
						|
}
 |