package main import ( "errors" "fmt" "os" "strings" "github.com/edwarnicke/exechelper" ) type AddressCounter = int type Ip4AddressAllocator struct { networks map[int]AddressCounter chosenOctet int assignedIps []string } func (a *Ip4AddressAllocator) AddNetwork(networkNumber int) { a.networks[networkNumber] = 1 } func (a *Ip4AddressAllocator) NewIp4InterfaceAddress(inputNetworkNumber ...int) (string, error) { var networkNumber int = 0 if len(inputNetworkNumber) > 0 { networkNumber = inputNetworkNumber[0] } if _, ok := a.networks[networkNumber]; !ok { a.AddNetwork(networkNumber) } numberOfAddresses := a.networks[networkNumber] if numberOfAddresses == 254 { return "", fmt.Errorf("no available IPv4 addresses") } address, err := a.createIpAddress(networkNumber, numberOfAddresses) a.networks[networkNumber] = numberOfAddresses + 1 return address + "/24", err } // Creates a file every time an IP is assigned: used to keep track of addresses in use. // If an address is not in use, 'counter' is then copied to 'chosenOctet' and it is used for the remaining tests. // Also checks host IP addresses. func (a *Ip4AddressAllocator) createIpAddress(networkNumber int, numberOfAddresses int) (string, error) { hostIps, _ := exechelper.CombinedOutput("ip a") counter := 10 var address string for { if a.chosenOctet != 0 { address = fmt.Sprintf("10.%v.%v.%v", a.chosenOctet, networkNumber, numberOfAddresses) file, err := os.Create(address) if err != nil { return "", errors.New("unable to create file: " + fmt.Sprint(err)) } file.Close() break } else { address = fmt.Sprintf("10.%v.%v.%v", counter, networkNumber, numberOfAddresses) _, err := os.Stat(address) if err == nil || strings.Contains(string(hostIps), address) { counter++ } else if os.IsNotExist(err) { file, err := os.Create(address) if err != nil { return "", errors.New("unable to create file: " + fmt.Sprint(err)) } file.Close() a.chosenOctet = counter break } else { return "", errors.New("an error occurred while checking if a file exists: " + fmt.Sprint(err)) } } } a.assignedIps = append(a.assignedIps, address) return address, nil } func (a *Ip4AddressAllocator) deleteIpAddresses() { for ip := range a.assignedIps { os.Remove(a.assignedIps[ip]) } } func NewIp4AddressAllocator() *Ip4AddressAllocator { var ip4AddrAllocator = new(Ip4AddressAllocator) ip4AddrAllocator.networks = make(map[int]AddressCounter) ip4AddrAllocator.AddNetwork(0) return ip4AddrAllocator }