Documentation ¶
Overview ¶
Network ranges and IP address sets.
NewRange creates contiguous AddressRange set. NewBlock creates RFC-4632 https://www.rfc-editor.org/rfc/rfc4632 CIDR Block set. NewSet creates non-contigous AddressSet.
Use [AddressSet.Addresses] to iterate constituent addresses. Use [AddressSet.Ranges] to iterate constituent AddressRange types. Use Blocks to iterate constituent Block types.
Index ¶
- func Adjacent[A ip.Number[A]](r0, r1 AddressRange[A]) bool
- func Contiguous[A ip.Number[A]](r0, r1 AddressRange[A]) bool
- func Intersect[A ip.Number[A]](r0, r1 AddressRange[A]) bool
- func ParseCIDRNotation[A ip.Number[A]](f ip.Family[A], notation string) (netAddress A, maskBits int, err error)
- func ParseUnknownCIDRNotation(notation string) (netAddress ip.Address, maskBits int, err error)
- type AddressRange
- type AddressSet
- type Block
- type Iterator
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Adjacent ¶
func Adjacent[A ip.Number[A]](r0, r1 AddressRange[A]) bool
Tests if ranges are one element from overlap
func Contiguous ¶
func Contiguous[A ip.Number[A]](r0, r1 AddressRange[A]) bool
Tests if ranges either Intersect or are Adjacent
Example ¶
package main import ( "github.com/ipfreely-uk/go/ip" "github.com/ipfreely-uk/go/ip/network" ) func main() { r0 := makeRange(ip.V6(), "2001:db8::", "2001:db8::100") r1 := makeRange(ip.V6(), "2001:db8::10", "2001:db8::ffff:ffff:ffff") if network.Contiguous(r0, r1) { r2 := network.Join(r0, r1) println(r2.String()) } } func makeRange[A ip.Number[A]](family ip.Family[A], first, last string) network.AddressRange[A] { f := ip.MustParse(family, first) l := ip.MustParse(family, last) return network.NewRange(f, l) }
Output:
func Intersect ¶
func Intersect[A ip.Number[A]](r0, r1 AddressRange[A]) bool
Test if ranges have common elements
func ParseCIDRNotation ¶
func ParseCIDRNotation[A ip.Number[A]](f ip.Family[A], notation string) (netAddress A, maskBits int, err error)
Parses CIDR notation. Returns error if second argument is invalid CIDR notation.
Example ¶
address, mask, _ := network.ParseCIDRNotation(ip.V6(), "2001:db8::/32") reservedForDocumentation := network.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 := network.ParseUnknownCIDRNotation(notation) if err != nil { panic(err) } switch a := address.(type) { case ip.Addr4: printRangeDetails(network.NewBlock(a, mask)) case ip.Addr6: printRangeDetails(network.NewBlock(a, mask)) } }
Output:
Types ¶
type AddressRange ¶
type AddressRange[A ip.Number[A]] interface { AddressSet[A] // Least address First() (address A) // Greatest address Last() (address A) }
Immutable contiguous range of one or more IP addresses.
func Join ¶
func Join[A ip.Number[A]](r0, r1 AddressRange[A]) AddressRange[A]
Joins ranges using least and greatest elements from both. Ranges do not have to be contiguous.
func NewRange ¶
func NewRange[A ip.Number[A]](first, last A) AddressRange[A]
Creates new AddressRange. Return value conforms to Block if possible.
type AddressSet ¶
type AddressSet[A ip.Number[A]] interface { // Tests if address in set Contains(address A) bool // Number of unique addresses Size() *big.Int // Unique addresses from least to greatest Addresses() Iterator[A] // Non-contiguous ranges from least to greatest Ranges() Iterator[AddressRange[A]] // Informational only String() string }
IP address set.
func NewSet ¶
func NewSet[A ip.Number[A]](ranges ...AddressRange[A]) AddressSet[A]
Creates AddressSet from given IP address ranges. Ranges may overlap. If set reduces to contiguous range returns type that conforms to AddressRange.
Example ¶
package main import ( "github.com/ipfreely-uk/go/ip" "github.com/ipfreely-uk/go/ip/network" ) func main() { family := ip.V4() r0 := exampleRange(family, "192.0.2.0", "192.0.2.100") r1 := exampleRange(family, "192.0.2.101", "192.0.2.111") r2 := exampleRange(family, "192.0.2.200", "192.0.2.255") r3 := exampleRange(family, "203.0.113.0", "203.0.113.255") r4 := exampleRange(family, "192.0.2.0", "192.0.2.100") addresses := network.NewSet(r0, r1, r2, r3, r4) println("Rationalized ranges:") next := addresses.Ranges() for aRange, exists := next(); exists; aRange, exists = next() { println(aRange.String()) } } func exampleRange[A ip.Number[A]](family ip.Family[A], first, last string) network.AddressRange[A] { a0 := ip.MustParse(family, first) a1 := ip.MustParse(family, last) return network.NewRange(a0, a1) }
Output:
type Block ¶
type Block[A ip.Number[A]] interface { AddressRange[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/ip/network" ) func main() { netAddress := ip.MustParse(ip.V6(), "2001:db8:cafe::") block := network.NewBlock(netAddress, 56) randomAddr := randomAddressFrom(block) println("Random address from", block.String(), "=", randomAddr.String()) } func randomAddressFrom[A ip.Number[A]](netBlock network.Block[A]) (address A) { netAddr := netBlock.First() family := netAddr.Family() inverseMask := netBlock.Mask().Not() return random(family).And(inverseMask).Or(netAddr) } func random[A ip.Number[A]](f ip.Family[A]) (address A) { slice := make([]byte, f.Width()/8) _, _ = rand.Read(slice) return f.MustFromBytes(slice...) }
Output:
Example (Second) ¶
package main import ( "github.com/ipfreely-uk/go/ip" "github.com/ipfreely-uk/go/ip/compare" "github.com/ipfreely-uk/go/ip/network" ) func main() { netAddress := ip.MustParse(ip.V6(), "2001:db8:cafe::") block := network.NewBlock(netAddress, 56) next := split(block, 60) for subnet, exists := next(); exists; subnet, exists = next() { println(subnet.String()) } } // Split subnet into smaller subnets func split[A ip.Number[A]](b network.Block[A], newMaskSize int) network.Iterator[network.Block[A]] { if newMaskSize < b.MaskSize() { panic("invalid split size") } current := network.NewBlock(b.First(), newMaskSize) one := current.First().Family().FromInt(1) increment := current.Last().Subtract(current.First()).Add(one) exhausted := false return func() (element network.Block[A], exists bool) { if exhausted { return nil, false } result := current exhausted = compare.Eq(current.Last(), b.Last()) if !exhausted { first := current.First().Add(increment) current = network.NewBlock(first, newMaskSize) } return result, true } }
Output:
func NewBlock ¶
Creates Block. 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/ip/network" ) func main() { netAddress := ip.MustParse(ip.V6(), "2001:db8::") block := network.NewBlock(netAddress, 32) println("Block", block.String()) println("First", block.First().String()) println("Last", block.Last().String()) println("Size", humanize.BigComma(block.Size())) }
Output:
type Iterator ¶
Iterator function that returns whether element returned and element
Example ¶
package main import ( "github.com/ipfreely-uk/go/ip" "github.com/ipfreely-uk/go/ip/network" ) func main() { netaddr, mask, _ := network.ParseCIDRNotation(ip.V4(), "192.0.2.128/28") subnet := network.NewBlock(netaddr, mask) firstAssigneable := ip.Next(subnet.First()) lastAssigneable := ip.Prev(subnet.Last()) assignable := network.NewRange(firstAssigneable, lastAssigneable) // iterator of addresses next := assignable.Addresses() for address, exists := next(); exists; address, exists = next() { println(address.String()) } }
Output:
func Blocks ¶
func Blocks[A ip.Number[A]](r AddressRange[A]) Iterator[Block[A]]
Subdivides AddressRange into valid CIDR blocks
Example ¶
package main import ( "github.com/ipfreely-uk/go/ip" "github.com/ipfreely-uk/go/ip/network" ) func main() { first := ip.V4().MustFromBytes(192, 0, 2, 101) last := ip.V4().MustFromBytes(192, 0, 2, 240) freeAddresses := network.NewRange(first, last) printCidrBlocksIn(freeAddresses) } func printCidrBlocksIn[A ip.Number[A]](addressRange network.AddressRange[A]) { next := network.Blocks(addressRange) for block, exists := next(); exists; block, exists = next() { println(block.String()) } }
Output: