package config import ( "encoding/binary" "fmt" "net/netip" "os" "strings" ) const ( DefaultLXCNATSubnet = "10.0.3.0/24" DefaultKVMNATSubnet = "192.168.122.0/24" ) type NATNetwork struct { Subnet string `json:"subnet"` Gateway string `json:"gateway"` Netmask string `json:"netmask"` DHCPStart string `json:"dhcp_start"` DHCPEnd string `json:"dhcp_end"` DHCPMax int `json:"dhcp_max"` PrefixBits int `json:"prefix_bits"` } func ParseNATNetwork(raw string) (NATNetwork, error) { prefix, err := netip.ParsePrefix(strings.TrimSpace(raw)) if err != nil || !prefix.Addr().Is4() { return NATNetwork{}, fmt.Errorf("NAT subnet must be a valid IPv4 CIDR") } prefix = prefix.Masked() if prefix.Bits() < 16 || prefix.Bits() > 28 { return NATNetwork{}, fmt.Errorf("NAT subnet prefix must be between /16 and /28") } if !isRFC1918Prefix(prefix) { return NATNetwork{}, fmt.Errorf("NAT subnet must use an RFC1918 private IPv4 range") } network := ipv4Uint32(prefix.Addr()) hostBits := 32 - prefix.Bits() broadcast := network | uint32((uint64(1)< 0 { mask = ^uint32(0) << (32 - bits) } return uint32IPv4(mask).String() }