package iptools import ( "fmt" "net/netip" "time" ) const ( DefaultMaskBits = 24 ) type Range struct { Start netip.Addr `yaml:"start"` End netip.Addr `yaml:"end"` Network netip.Prefix `yaml:"network"` Expiry time.Duration `yaml:"expiry"` NoHostName bool `yaml:"no_hostname"` // don't set the hostname } func (r *Range) Validate() error { if !r.Start.Is4() { return fmt.Errorf("range start %s is not a valid IPv4 address", r.Start) } if !r.End.Is4() { return fmt.Errorf("range end %s is not a valid IPv4 address", r.End) } // Compare returns -1 if lhs < rhs, 0 if lhs == rhs, and 1 if lhs > rhs. if r.End.Compare(r.Start) != 1 { return fmt.Errorf("start address %s is not before end address %s", r.Start, r.End) } var err error if !r.Network.IsValid() { r.Network, err = r.Start.Prefix(DefaultMaskBits) if err != nil { return err } } if !r.Network.Contains(r.Start) { return fmt.Errorf("prefix %s does not contain start address %s", r.Network, r.Start) } if !r.Network.Contains(r.End) { return fmt.Errorf("prefix %s does not contain end address %s", r.Network, r.End) } return nil } // this is probably dumb, but it's a one-time cost upfront on pool instantiation. func (r *Range) numHosts() int { cur := r.Start hosts := 0 for cur.Compare(r.End) < 1 { hosts++ cur = cur.Next() } return hosts }