Added logic to find next available IP address

This commit is contained in:
Mike Conrad
2025-04-14 15:50:08 -04:00
parent 2964391f0a
commit d0e3d6777d
5 changed files with 159 additions and 4 deletions

100
ipaddresses.go Normal file
View File

@ -0,0 +1,100 @@
package main
import (
"fmt"
"log"
"net"
"os"
)
func getInterfaceIPAndMask(interfaceName string) (ip net.IP, mask net.IPMask, err error) {
iface, err := net.InterfaceByName(interfaceName)
if err != nil {
return nil, nil, fmt.Errorf("failed to get interface %s: %w", interfaceName, err)
}
addrs, err := iface.Addrs()
if err != nil {
return nil, nil, fmt.Errorf("failed to get addresses for %s: %w", interfaceName, err)
}
for _, addr := range addrs {
ipNet, ok := addr.(*net.IPNet)
if !ok || ipNet.IP.IsLoopback() || ipNet.IP.To4() == nil {
continue
}
return ipNet.IP, ipNet.Mask, nil
}
return nil, nil, fmt.Errorf("no valid IPv4 address found for interface %s", interfaceName)
}
func getNextFreeIP() (net.IP, error) {
var wg string = os.Getenv("WIREGUARD_INTERFACE")
ip, mask, err := getInterfaceIPAndMask(wg)
if err != nil {
log.Fatal(err)
}
used, err := parseUsedIPsFromConfigs("./configs")
if err != nil {
fmt.Println("Error:", err)
return nil, fmt.Errorf("Unkown err: %s", err)
}
for _, ip := range used {
fmt.Println("Used IP:", ip)
}
// used := []net.IP{
// net.ParseIP("10.200.34.1"),
// net.ParseIP("10.200.34.2"),
// net.ParseIP("10.200.34.3"),
// net.ParseIP("10.200.34.4"),
// net.ParseIP("10.200.34.5"),
// net.ParseIP("10.200.34.6"),
// net.ParseIP("10.200.34.225"),
// net.ParseIP("10.200.34.226"),
// net.ParseIP("10.200.34.227"),
// }
network := ip.Mask(mask)
ipNet := &net.IPNet{IP: network, Mask: mask}
// Turn the used list into a map for fast lookup
usedMap := make(map[string]bool)
for _, u := range used {
usedMap[u.String()] = true
}
// Get network boundaries
start := ipToUint32(network) + 1
end := ipToUint32(lastIP(ipNet)) - 1 // Skip broadcast
for i := start; i <= end; i++ {
candidate := uint32ToIP(i)
if !usedMap[candidate.String()] {
return candidate, nil
}
}
return nil, fmt.Errorf("no free IPs in subnet %s", ipNet.String())
}
func ipToUint32(ip net.IP) uint32 {
ip = ip.To4()
return uint32(ip[0])<<24 | uint32(ip[1])<<16 | uint32(ip[2])<<8 | uint32(ip[3])
}
func uint32ToIP(n uint32) net.IP {
return net.IPv4(byte(n>>24), byte(n>>16), byte(n>>8), byte(n))
}
func lastIP(ipNet *net.IPNet) net.IP {
ip := ipNet.IP.To4()
mask := ipNet.Mask
broadcast := make(net.IP, len(ip))
for i := range ip {
broadcast[i] = ip[i] | ^mask[i]
}
return broadcast
}