Documentation
¶
Overview ¶
Discrete sets and ranges of IP addresses.
Set Types ¶
Interface hierarchy: Block set is Interval set is Discrete set.
NewBlock creates a RFC-4632 CIDR Block set. NewSingle creates a Block set from a single address.
NewInterval creates contiguous Interval set of addresses from lower and upper bounds.
NewDiscrete creates Discrete set as union of other address sets. Use NewDiscrete to create the empty set.
Functions return a struct that conforms to the most specialized interface possible.
Iteration ¶
Use Discrete.Addresses to iterate over constituent addresses.
Use Discrete.Intervals to iterate over constituent Interval sets.
Use the Blocks function to iterate over constituent Block sets within Interval sets.
References ¶
Index ¶
- func Adjacent[A ip.Int[A]](i0, i1 Interval[A]) bool
- func Blocks[A ip.Int[A]](set Interval[A]) iter.Seq[Block[A]]
- func Contiguous[A ip.Int[A]](i0, i1 Interval[A]) bool
- func Eq[A ip.Int[A]](set0, set1 Discrete[A]) (equal bool)
- func Intersect[A ip.Int[A]](i0, i1 Interval[A]) bool
- func ParseCIDRNotation[A ip.Int[A]](f ip.Family[A], notation string) (netAddress A, maskBits int, err error)
- func ParseUnknownCIDRNotation(notation string) (netAddress ip.Address, maskBits int, err error)
- func Subnets[A ip.Int[A]](b Block[A], maskBits int) iter.Seq[Block[A]]
- type Block
- type Discrete
- type Interval
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Blocks ¶
Subdivides Interval into CIDR Block sets
Example ¶
package main import ( "github.com/ipfreely-uk/go/ip" "github.com/ipfreely-uk/go/ipset" ) func main() { first := ip.V4().MustFromBytes(192, 0, 2, 101) last := ip.V4().MustFromBytes(192, 0, 2, 240) freeAddresses := ipset.NewInterval(first, last) printCidrBlocksIn(freeAddresses) } func printCidrBlocksIn[A ip.Int[A]](addressRange ipset.Interval[A]) { for block := range ipset.Blocks(addressRange) { println(block.String()) } }
Output:
func Contiguous ¶
func Eq ¶
Tests if two discrete sets are equal. Iterates each Discrete set's Interval sets comparing first and last elements.
func ParseCIDRNotation ¶
func ParseCIDRNotation[A ip.Int[A]](f ip.Family[A], notation string) (netAddress A, maskBits int, err error)
Parses RFC 4632 CIDR notation. See also the NewBlock function.
For the IPv4 family and expression "192.168.0.0/128", returns 192.168.0.0 as the network address part and 128 as the mask bits.
Returns error if second argument is invalid CIDR notation.
Example ¶
address, mask, _ := ipset.ParseCIDRNotation(ip.V6(), "2001:db8::/32") reservedForDocumentation := ipset.NewBlock(address, mask) printRangeDetails(reservedForDocumentation)
Output:
func ParseUnknownCIDRNotation ¶
Parses CIDR notation where IP address family is unknown. Returns error if argument is invalid CIDR notation.
Example ¶
reservedForDocumentation := []string{ "192.0.2.0/24", "198.51.100.0/24", "203.0.113.0/24", "2001:db8::/32", } for _, notation := range reservedForDocumentation { address, mask, err := ipset.ParseUnknownCIDRNotation(notation) if err != nil { panic(err) } switch a := address.(type) { case ip.Addr4: printRangeDetails(ipset.NewBlock(a, mask)) case ip.Addr6: printRangeDetails(ipset.NewBlock(a, mask)) } }
Output:
func Subnets ¶
Splits Block into subnets of a given size.
Panics on illegal mask bits. maskBits must be greater or equal to Block.MaskSize and less than or equal to the bit width of the address family.
Example ¶
package main import ( "fmt" "math/big" humanize "github.com/dustin/go-humanize" "github.com/ipfreely-uk/go/ip" "github.com/ipfreely-uk/go/ipset" ) func maskRequiredFor[A ip.Int[A]](f ip.Family[A], allocateableAddresses *big.Int) (bits int) { var min *big.Int if f.Version() == ip.V4().Version() { two := big.NewInt(2) min = two.Add(two, allocateableAddresses) } else { min = allocateableAddresses } width := f.Width() for m := width; m >= 0; m-- { sizeForMask := ip.SubnetAddressCount(f, m) if sizeForMask.Cmp(min) >= 0 { return m } } formatted := humanize.BigComma(allocateableAddresses) msg := fmt.Sprintf("%s is larger than family %s", formatted, f.String()) panic(msg) } func main() { oneHundredAddresses := big.NewInt(100) mask := maskRequiredFor(ip.V4(), oneHundredAddresses) netAddr, bits, _ := ipset.ParseCIDRNotation(ip.V4(), "203.0.113.0/24") block := ipset.NewBlock(netAddr, bits) println(fmt.Sprintf("Dividing %s into blocks of at least %s addresses", block.CidrNotation(), oneHundredAddresses.String())) for sub := range ipset.Subnets(block, mask) { println(sub.String()) } }
Output:
Types ¶
type Block ¶
type Block[A ip.Int[A]] interface { Interval[A] // Mask size in bits MaskSize() (bits int) // Mask as IP address Mask() (address A) // The block in CIDR notation. CidrNotation() string }
Immutable RFC-4632 CIDR block. Roughly equivalent to the [netip.Prefix] type.
Example ¶
package main import ( "crypto/rand" "github.com/ipfreely-uk/go/ip" "github.com/ipfreely-uk/go/ipset" ) func main() { netAddress := ip.MustParse(ip.V6(), "2001:db8:cafe::") block := ipset.NewBlock(netAddress, 56) for i := 0; i < 3; i++ { randomAddr := randomAddressFrom(block) println("Random address from", block.String(), "=", randomAddr.String()) } } // Pick random address from block func randomAddressFrom[A ip.Int[A]](netBlock ipset.Block[A]) (address A) { netAddr := netBlock.First() family := netAddr.Family() inverseMask := netBlock.Mask().Not() return random(family).And(inverseMask).Or(netAddr) } // Generate a random address for given family func random[A ip.Int[A]](f ip.Family[A]) (address A) { slice := make([]byte, f.Width()/8) _, _ = rand.Read(slice) return f.MustFromBytes(slice...) }
Output:
func NewBlock ¶
Creates Block set.
Panics if mask does not cover network address or is out of range for address family.
Example ¶
package main import ( humanize "github.com/dustin/go-humanize" "github.com/ipfreely-uk/go/ip" "github.com/ipfreely-uk/go/ipset" ) func main() { network := ip.MustParse(ip.V6(), "2001:db8::") block := ipset.NewBlock(network, 32) println("Block", block.String()) println("First", block.First().String()) println("Last", block.Last().String()) println("Size", humanize.BigComma(block.Size())) }
Output:
Example (Second) ¶
package main import ( "github.com/ipfreely-uk/go/ip" "github.com/ipfreely-uk/go/ipset" ) func main() { network := ip.MustParse(ip.V4(), "192.168.0.0") mask := ip.MustParse(ip.V4(), "255.255.255.0") subnet := block(network, mask) println(subnet.String()) } func block[A ip.Int[A]](network, mask A) ipset.Block[A] { bits := ip.SubnetMaskBits(mask) return ipset.NewBlock(network, bits) }
Output:
type Discrete ¶
type Discrete[A ip.Int[A]] interface { // Tests if address in set Contains(address A) bool // Number of unique addresses. Size() (cardinality *big.Int) // Unique addresses from least to greatest Addresses() iter.Seq[A] // Contents as distinct [Interval] sets. // Intervals do not [Intersect] and are not [Adjacent]. // Intervals are returned from least address to greatest. Intervals() iter.Seq[Interval[A]] // Informational only String() string }
Immutable discrete ordered set of IP addresses. Seq types provided by implementations are reusable.
func NewDiscrete ¶
Creates Discrete set as a union of addresses from the operand elements.
If set is contiguous range returns result of NewInterval function. If set is CIDR range returns result of NewBlock function. Zero-length slice returns the empty set.
Example ¶
package main import ( "github.com/ipfreely-uk/go/ip" "github.com/ipfreely-uk/go/ipset" ) func main() { set := func(first, last string) ipset.Interval[ip.Addr4] { v4 := ip.V4() p := ip.MustParse[ip.Addr4] return ipset.NewInterval(p(v4, first), p(v4, last)) } r0 := set("192.0.2.0", "192.0.2.100") r1 := set("192.0.2.101", "192.0.2.111") r2 := set("192.0.2.200", "192.0.2.200") union := ipset.NewDiscrete(r0, r1, r2) println(r0.String(), "\u222A", r1.String(), "\u222A", r2.String(), "=", union.String()) }
Output:
Example (Second) ¶
package main import ( "github.com/ipfreely-uk/go/ip" "github.com/ipfreely-uk/go/ipset" ) func main() { printEmptySetFor(ip.V4()) printEmptySetFor(ip.V6()) } func printEmptySetFor[A ip.Int[A]](f ip.Family[A]) { empty := ipset.NewDiscrete[A]() println(f.String(), empty.String()) }
Output:
Example (Third) ¶
package main import ( "fmt" "github.com/ipfreely-uk/go/ip" "github.com/ipfreely-uk/go/ipset" ) func main() { s0 := parseV4("192.0.2.0/32") s1 := parseV4("192.0.2.11/32") s2 := parseV4("192.0.2.12/32") printSetType(s0) printSetType(s1, s2) printSetType(s0, s1, s2) } func parseV4(notation string) ipset.Block[ip.Addr4] { a, m, err := ipset.ParseCIDRNotation(ip.V4(), notation) if err != nil { panic(err) } return ipset.NewBlock(a, m) } func printSetType[A ip.Int[A]](sets ...ipset.Discrete[A]) { union := ipset.NewDiscrete(sets...) switch s := union.(type) { case ipset.Block[A]: println(fmt.Sprintf("%s is a block set", s.String())) case ipset.Interval[A]: println(fmt.Sprintf("%s is an interval set", s.String())) case ipset.Discrete[A]: println(fmt.Sprintf("%s is a discrete set", s.String())) } }
Output:
type Interval ¶
type Interval[A ip.Int[A]] interface { Discrete[A] // Least address First() (address A) // Greatest address Last() (address A) }
Immutable set of IP addresses between first and last inclusive.
A range of one or more IP addresses. The name interval was chosen because range is a keyword in Go. Interval is a term from mathematical set theory.
func Extremes ¶
Creates Interval using least and greatest values from each
Example ¶
package main import ( "github.com/ipfreely-uk/go/ip" "github.com/ipfreely-uk/go/ipset" ) func main() { r0 := parseV6Interval("2001:db8::", "2001:db8::100") r1 := parseV6Interval("2001:db8::10", "2001:db8::ffff:ffff:ffff") if ipset.Contiguous(r0, r1) { r2 := ipset.Extremes(r0, r1) println(r2.String()) } } func parseV6Interval(first, last string) ipset.Interval[ip.Addr6] { v6 := ip.V6() p := ip.MustParse[ip.Addr6] return ipset.NewInterval(p(v6, first), p(v6, last)) }
Output:
func NewInterval ¶
Creates Interval set.
If range is valid CIDR block returns value from NewBlock instead.
Example ¶
package main import ( "github.com/ipfreely-uk/go/ip" "github.com/ipfreely-uk/go/ipset" ) func main() { // 1st address in IPv4 subnet is network address. // Last address in IPv4 subnet is broadcast address. // The rest can be used for unicast. sub := ipset.NewBlock(ip.V4().MustFromBytes(203, 0, 113, 8), 29) first := ip.Next(sub.First()) last := ip.Prev(sub.Last()) allocations := ipset.NewInterval(first, last) println("Assignable addresses in ", sub.String()) for a := range allocations.Addresses() { println(a.String()) } }
Output: