network

package
v0.0.13-alpha Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 15, 2024 License: Apache-2.0 Imports: 9 Imported by: 0

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 over constituent addresses. Use [AddressSet_Ranges] to iterate over constituent [AddressRange]s. Use Blocks to iterate over constituent [Block]s.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Adjacent

func Adjacent[A ip.Address[A]](r0, r1 AddressRange[A]) bool

Tests if [Range]s are one element from overlap

func Contiguous

func Contiguous[A ip.Address[A]](r0, r1 AddressRange[A]) bool

Tests if [Range]s 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.Address[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.Address[A]](r0, r1 AddressRange[A]) bool

Test if [Range]s have common elements

func ParseCIDRNotation

func ParseCIDRNotation[A ip.Address[A]](f ip.Family[A], notation string) (netAddress A, maskBits int, err error)

Parses CIDR notation

Example
address, mask, _ := network.ParseCIDRNotation(ip.V6(), "2001:db8::/32")
reservedForDocumentation := network.NewBlock(address, mask)
printRangeDetails(reservedForDocumentation)
Output:

func ParseUnknownCIDRNotation

func ParseUnknownCIDRNotation(notation string) (netAddress ip.Untyped, maskBits int, err error)

Parses CIDR notation where IP address family is unknown. Returns error if operand is not valid 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.Address[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.Address[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.Address[A]](first, last A) AddressRange[A]

Creates new AddressRange. Return value conforms to Block if possible.

type AddressSet

type AddressSet[A ip.Address[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.Address[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.Address[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.Address[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.Address[A]](netBlock network.Block[A]) A {
	netAddr := netBlock.First()
	family := netAddr.Family()
	inverseMask := netBlock.Mask().Not()

	return randomAddress(family).And(inverseMask).Or(netAddr)
}

func randomAddress[A ip.Address[A]](f ip.Family[A]) A {
	slice := make([]byte, f.Width()/8)
	_, _ = rand.Read(slice)
	return f.MustFromBytes(slice...)
}
Output:

func NewBlock

func NewBlock[A ip.Address[A]](network A, mask int) Block[A]

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

type Iterator[E any] func() (element E, exists bool)

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() {
	first := ip.V4().MustFromBytes(192, 168, 0, 1)
	last := ip.V4().MustFromBytes(192, 168, 0, 254)
	assignable := network.NewRange(first, last)

	// iterator of addresses
	next := assignable.Addresses()
	for address, exists := next(); exists; address, exists = next() {
		println(address.String())
	}
}
Output:

func Blocks

func Blocks[A ip.Address[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.Address[A]](addressRange network.AddressRange[A]) {
	next := network.Blocks(addressRange)
	for block, exists := next(); exists; block, exists = next() {
		println(block.String())
	}
}
Output:

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL