iplib

package module
v1.0.8 Latest Latest
Warning

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

Go to latest
Published: Dec 24, 2023 License: MIT Imports: 12 Imported by: 53

README

IPLib

Documentation CircleCI Go Report Card Coverage Status

I really enjoy Python's ipaddress library and Ruby's ipaddr, I think you can write a lot of neat software if some of the little problems around manipulating IP addresses and netblocks are taken care of for you, so I set out to write something like them for my language of choice, Go. This is what I've come up with.

IPLib is a hopefully useful, aspirationally full-featured library built around and on top of the address primitives found in the net package, it seeks to make them more accessible and easier to manipulate.

It includes:

net.IP tools

Some simple tools for performing common tasks against IP objects:

  • compare two addresses
  • make a copy of a net.IP address
  • get the delta between two addresses
  • sort
  • decrement or increment addresses
  • print addresses as binary or hexadecimal strings, or print their addr.ARPA DNS name
  • print v6 in fully expanded form
  • convert between net.IP and integer values
  • get the version of a v4 address or force a IPv4-mapped IPv6address to be a v4 address
iplib.Net

An enhancement of net.IPNet, iplib.Net is an interface with two, version- specific implementations providing features such as:

  • retrieve the first and last usable address
  • retrieve the wildcard mask
  • enumerate all or part of a netblock to []net.IP
  • decrement or increment addresses within the boundaries of the netblock
  • return the supernet of a netblock
  • allocate subnets within the netblock
  • return next- or previous-adjacent netblocks
Net4 and Net6 implementations of Net

The two address versions behave differently in both large and subtle ways, and the version-specific implementations seek to account for this. For example the Net4 implementation omits the network and broadcast addresses from consideration during enumeration; while the Net6 implementation introduces the concept of a HostMask, which blocks usable addresses off from the right in the same way that a netmask constrains them from the left

Additional version-specific considerations described in the Net4 and Net6 sections below.

Sub-modules

Installing

go get -u github.com/c-robinson/iplib

Using iplib

There are a series of functions for working with v4 or v6 net.IP objects:

package main

import (
	"fmt"
	"net"
	"sort"
	
	"github.com/c-robinson/iplib"
)


func main() {
	ipa := net.ParseIP("192.168.1.1")
	ipb := iplib.IncrementIPBy(ipa, 15)      // ipb is 192.168.1.16
	ipc := iplib.NextIP(ipa)                 // ipc is 192.168.1.2

	fmt.Println(iplib.CompareIPs(ipa, ipb))  // -1
    
	fmt.Println(iplib.DeltaIP(ipa, ipb))     // 15
    
	fmt.Println(iplib.IPToHexString(ipc))    // "c0a80102"

	iplist := []net.IP{ ipb, ipc, ipa }
	sort.Sort(iplib.ByIP(iplist))            // []net.IP{ipa, ipc, ipb}

	fmt.Println(iplib.IP4ToUint32(ipa))      // 3232235777
	fmt.Println(iplib.IPToBinaryString(ipa)) // 11000000.10101000.00000001.00000001
	fmt.Println(iplib.IP4ToARPA(ipa))        // 1.1.168.192.in-addr.arpa
}

Addresses that require or return a count default to using uint32, which is sufficient for working with the entire IPv4 space. As a rule these functions are just lowest-common wrappers around IPv4- or IPv6-specific functions. The IPv6-specific variants use big.Int so they can access the entire v6 space.

The iplib.Net interface

Net describes an iplib.Net object, the exposed functions are those that are required for comparison, sorting, generic initialization and for ancillary functions such as those found in this package's submodules.

Using iplib.Net4

Net4 represents an IPv4 network. Since the first and last addresses of a v4 network are typically not allocated for use these will be omitted by Enumerate(), NextIP() and PreviousIP(); they wont show up in Count(); and FirstAddress() and LastAddress() show the 2nd and 2nd-to-the-last addresses respectively. The v4-specific method NetworkAddress() returns the first address, while BroadcastAddress() returns the last. There is an exception made for Net4 networks defined with a 31-bit netmask, since these are assumed to be for RFC3021 point-to-point links.

Additionally Net4 contains a Wildcard() method which will return the network's wildcard address.

n := iplib.NewNet4(net.ParseIP("192.168.0.0"), 16)
fmt.Println(n.Count())            // 65534 (note: not 65536)
fmt.Println(n.Enumerate(2, 1024)) // [192.168.4.1 192.168.4.2]
fmt.Println(n.IP())               // 192.168.0.0
fmt.Println(n.FirstAddress())     // 192.168.0.1
fmt.Println(n.LastAddress())      // 192.168.255.254
fmt.Println(n.BroadcastAddress()) // 192.168.255.255
fmt.Println(n.Wildcard())         // 0000ffff
fmt.Println(n.Subnet(0))          // [192.168.0.0/17 192.168.128.0/17] <nil>
fmt.Println(n.Supernet(0))        // 192.168.0.0/15 <nil>

Using iplib.Net6

Net6 represents and IPv6 network. In some ways v6 is simpler than v4, as it does away with the special behavior of addresses at the front and back of the netblock. For IPv6 the primary problem is the sheer size of the thing: there are 2^128th addresses in IPv6, which translates to 340 undecillion!

n := iplib.NewNet6(net.ParseIP("2001:db8::"), 56, 0)
fmt.Println(n.Count())                  // 4722366482869645213696
fmt.Println(n.Enumerate(2, 1024))       // [2001:db8::400 2001:db8::401]
fmt.Println(n.FirstAddress())           // 2001:db8::
fmt.Println(n.NextIP(n.FirstAddress())) // 2001:db8::1 <nil>
fmt.Println(n.LastAddress())            // 2001:db8:0:ff:ffff:ffff:ffff:ffff
fmt.Println(n.Subnet(0, 0))             // [2001:db8::/57 2001:db8:0:80::/57] <nil>
fmt.Println(n.Supernet(0, 0))           // 2001:db8::/55 <nil>
HostMasks with Net6

To manage the address space, Net6 introduces HostMask. This optional constraint can be used to block addresses on the right-side of a netblock somewhat like Netmasks do on the left. Hostmask must be specified at initialization time and, if set, will affect the behavior of Count(), Enumerate(), LastAddress(), NextIP() and PreviousIP(). Subnet() and Supernet() generate objects that inherit the hostmask of their parent, while a hostmask must be specified for NextNet() and PreviousNet().

// this is the same as the previous example, except with a hostmask set
n := NewNet6(net.ParseIP("2001:db8::"), 56, 60)
fmt.Println(n.Count())                  // 4096
fmt.Println(n.Enumerate(2, 1024))       // [2001:db8:0:40:: 2001:db8:0:40:100::]
fmt.Println(n.FirstAddress())           // 2001:db8::
fmt.Println(n.NextIP(n.FirstAddress())) // 2001:db8:0:0:100:: <nil>
fmt.Println(n.LastAddress())            // 2001:db8:0:ff:f00::
fmt.Println(n.Mask().String())          // ffffffffffffff000000000000000000
fmt.Println(n.Hostmask.String())        // 0000000000000000f0ffffffffffffff
fmt.Println(n.Subnet(0, 60))            // [2001:db8::/57 2001:db8:0:80::/57] <nil>
fmt.Println(n.Supernet(0, 60))          // 2001:db8::/55 <nil>

Documentation

Overview

Package iplib provides enhanced tools for working with IP networks and addresses. These tools are built upon and extend the generic functionality found in the Go "net" package.

The main library comes in two parts: a series of utilities for working with net.IP (sort, increment, decrement, delta, compare, convert to binary or hex- string, convert between net.IP and integer) and an enhancement of net.IPNet called iplib.Net that can calculate the first and last IPs of a block as well as enumerating the block into []net.IP, incrementing and decrementing within the boundaries of the block and creating sub- or super-nets of it.

For most features iplib exposes a v4 and a v6 variant to handle each network properly, but in all cases there is a generic function that handles any IP and routes between them. One caveat to this is those functions that require or return an integer value representing the address, in these cases the IPv4 variants take an int32 as input while the IPv6 functions require a *big.Int in order to work with the 128bits of address.

For managing the complexity of IPv6 address-spaces, this library adds a new mask, called a Hostmask, as an optional constraint on iplib.Net6 networks, please see the type-documentation for more information on using it.

For functions where it is possible to exceed the address-space the rule is that underflows return the version-appropriate all-zeroes address while overflows return the all-ones.

There are also two submodules under iplib: the iplib/iid module contains functions for generating RFC 7217-compliant IPv6 Interface ID addresses, and iplib/iana imports the IANA IP Special Registries and exposes functions for comparing IP addresses against those registries to determine if the IP is part of a special reservation (for example RFC 1918 private networks or the RFC 3849 documentation network).

Index

Examples

Constants

View Source
const (
	// MaxIPv4 is the max size of a uint32, also the IPv4 address space
	MaxIPv4 uint32 = 1<<32 - 1

	// IP4Version is the label returned by IPv4 addresses
	IP4Version = 4

	// IP6Version is the label returned by IPv6 addresses
	IP6Version = 6
)

Variables

View Source
var (
	ErrAddressOutOfRange = errors.New("address is not a part of this netblock")
	ErrBadMaskLength     = errors.New("illegal mask length provided")
	ErrBroadcastAddress  = errors.New("address is the broadcast address of this netblock (and not considered usable)")
	ErrNetworkAddress    = errors.New("address is the network address of this netblock (and not considered usable)")
	ErrNoValidRange      = errors.New("no netblock can be found between the supplied values")
)

Errors that may be returned by functions in this package

Functions

func BigintToIP6

func BigintToIP6(z *big.Int) net.IP

BigintToIP6 converts a big.Int to an ip6 address and returns it as a net.IP

Example
z := big.Int{}
z.SetString("42540766452641154071740215577757643572", 10)
fmt.Println(BigintToIP6(&z))
Output:

2001:db8:85a3::8a2e:370:7334

func CompareIPs

func CompareIPs(a, b net.IP) int

CompareIPs is just a thin wrapper around bytes.Compare, but is here for completeness as this is a good way to compare two IP objects. Since it uses bytes.Compare the return value is identical: 0 if a==b, -1 if a<b, 1 if a>b

Example
fmt.Println(CompareIPs(net.ParseIP("192.168.1.0"), net.ParseIP("192.168.1.1")))
fmt.Println(CompareIPs(net.ParseIP("10.0.0.0"), net.ParseIP("10.0.0.0")))
fmt.Println(CompareIPs(net.ParseIP("2001:db8::100"), net.ParseIP("2001:db8::99")))
Output:

-1
0
1

func CompareNets

func CompareNets(a, b Net) int

CompareNets compares two iplib.Net objects by evaluating their network address (the first address in a CIDR range) and, if they're equal, comparing their netmasks (smallest wins). This means that if a network is compared to one of its subnets, the enclosing network sorts first.

func CopyIP added in v1.0.6

func CopyIP(ip net.IP) net.IP

CopyIP creates a new net.IP object containing the same data as the supplied net.IP (e.g. creates a new array and duplicates the contents)

func DecrementIP4By

func DecrementIP4By(ip net.IP, count uint32) net.IP

DecrementIP4By returns a v4 net.IP that is lower than the supplied net.IP by the supplied integer value. If you underflow the IP space it will return 0.0.0.0

Example
ip := net.ParseIP("192.168.2.0")
fmt.Println(DecrementIP4By(ip, 255))
Output:

192.168.1.1

func DecrementIP6By

func DecrementIP6By(ip net.IP, count *big.Int) net.IP

DecrementIP6By returns a net.IP that is lower than the supplied net.IP by the supplied integer value. If you underflow the IP space it will return ::

Example
z := big.NewInt(16777215)
ip := net.ParseIP("2001:db8::ffff:ffff")
fmt.Println(DecrementIP6By(ip, z))
Output:

2001:db8::ff00:0

func DecrementIP6WithinHostmask added in v1.0.0

func DecrementIP6WithinHostmask(ip net.IP, hm HostMask, count *big.Int) (net.IP, error)

DecrementIP6WithinHostmask returns a net.IP that is less than the unmasked portion of the supplied net.IP by the supplied integer value. If the input or output value fall outside the boundaries of the hostmask a ErrAddressOutOfRange will be returned

Example
ip := net.ParseIP("2001:db8:1000::")
ip1, _ := DecrementIP6WithinHostmask(ip, NewHostMask(0), big.NewInt(1))
ip2, _ := DecrementIP6WithinHostmask(ip, NewHostMask(56), big.NewInt(1))
fmt.Println(ip1)
fmt.Println(ip2)
Output:

2001:db8:fff:ffff:ffff:ffff:ffff:ffff
2001:db8:fff:ffff:ff00::

func DecrementIPBy

func DecrementIPBy(ip net.IP, count uint32) net.IP

DecrementIPBy returns a net.IP that is lower than the supplied net.IP by the supplied integer value. If you underflow the IP space it will return the zero address.

func DeltaIP

func DeltaIP(a, b net.IP) uint32

DeltaIP takes two net.IP's as input and returns the difference between them up to the limit of uint32.

func DeltaIP4

func DeltaIP4(a, b net.IP) uint32

DeltaIP4 takes two net.IP's as input and returns a total of the number of addresses between them, up to the limit of uint32.

Example
ipa := net.ParseIP("192.168.1.1")
ipb := net.ParseIP("192.168.2.0")
fmt.Println(DeltaIP4(ipa, ipb))
Output:

255

func DeltaIP6

func DeltaIP6(a, b net.IP) *big.Int

DeltaIP6 takes two net.IP's as input and returns a total of the number of addressed between them as a big.Int. It will technically work on v4 as well but is considerably slower than DeltaIP4.

Example
ipa := net.ParseIP("2001:db8::ffff:ffff")
ipb := net.ParseIP("2001:db8::ff00:0")
fmt.Println(DeltaIP6(ipa, ipb))
Output:

16777215

func EffectiveVersion

func EffectiveVersion(ip net.IP) int

EffectiveVersion returns 4 if the net.IP either contains a v4 address or if it contains the v4-encapsulating v6 address range ::ffff. Note that the second example below is a v6 address but reports as v4 because it is in the 4in6 block. This mirrors how Go's `net` package would treat the address

Example
fmt.Println(EffectiveVersion(net.ParseIP("192.168.1.1")))
fmt.Println(EffectiveVersion(net.ParseIP("::ffff:c0a8:101")))
fmt.Println(EffectiveVersion(net.ParseIP("2001:db8::c0a8:101")))
Output:

4
4
6

func ExpandIP6

func ExpandIP6(ip net.IP) string

ExpandIP6 takes a net.IP containing an IPv6 address and returns a string of the address fully expanded

Example
fmt.Println(ExpandIP6(net.ParseIP("2001:db8::1")))
Output:

2001:0db8:0000:0000:0000:0000:0000:0001

func ForceIP4

func ForceIP4(ip net.IP) net.IP

ForceIP4 takes a net.IP containing an RFC4291 IPv4-mapped IPv6 address and returns only the encapsulated v4 address.

Example
fmt.Println(len(ForceIP4(net.ParseIP("::ffff:c0a8:101"))))
Output:

4

func HexStringToIP

func HexStringToIP(s string) net.IP

HexStringToIP converts a hexadecimal string to an IP address. If the given string cannot be converted nil is returned. Input strings may contain '.' or ':'

Example
ip := HexStringToIP("c0a80101")
fmt.Println(ip.String())
Output:

192.168.1.1

func IP4ToARPA added in v0.2.0

func IP4ToARPA(ip net.IP) string

IP4ToARPA takes a net.IP containing an IPv4 address and returns a string of the address represented as dotted-decimals in reverse-order and followed by the IPv4 ARPA domain "in-addr.arpa"

Example
fmt.Println(IP4ToARPA(net.ParseIP("192.168.1.1")))
Output:

1.1.168.192.in-addr.arpa

func IP4ToUint32

func IP4ToUint32(ip net.IP) uint32

IP4ToUint32 converts a net.IPv4 to a uint32.

Example
fmt.Println(IP4ToUint32(net.ParseIP("192.168.1.1")))
Output:

3232235777

func IP6ToARPA added in v0.2.0

func IP6ToARPA(ip net.IP) string

IP6ToARPA takes a net.IP containing an IPv6 address and returns a string of the address represented as a sequence of 4-bit nibbles in reverse order and followed by the IPv6 ARPA domain "ip6.arpa"

Example
fmt.Println(IP6ToARPA(net.ParseIP("2001:db8::ffff:ffff")))
Output:

f.f.f.f.f.f.f.f.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa

func IP6ToUint64 added in v1.0.0

func IP6ToUint64(ip net.IP) uint64

IP6ToUint64 converts a net.IPv6 to a uint64, but only the first 64bits of address are considered meaningful (any information in the last 64bits will be lost). To work with entire IPv6 addresses use IPToBigint()

func IPToARPA added in v0.2.0

func IPToARPA(ip net.IP) string

IPToARPA takes a net.IP as input and returns a string of the version- appropriate ARPA DNS name

func IPToBigint

func IPToBigint(ip net.IP) *big.Int

IPToBigint converts a net.IP to big.Int.

func IPToBinaryString added in v0.2.0

func IPToBinaryString(ip net.IP) string

IPToBinaryString returns the given net.IP as a binary string

Example
fmt.Println(IPToBinaryString(net.ParseIP("192.168.1.1")))
fmt.Println(IPToBinaryString(net.ParseIP("2001:db8::ffff:ffff")))
Output:

11000000.10101000.00000001.00000001
00100000.00000001.00001101.10111000.00000000.00000000.00000000.00000000.00000000.00000000.00000000.00000000.11111111.11111111.11111111.11111111

func IPToHexString

func IPToHexString(ip net.IP) string

IPToHexString returns the given net.IP as a hexadecimal string. This is the default stringer format for v6 net.IP

Example
fmt.Println(IPToHexString(net.ParseIP("192.168.1.1")))
Output:

c0a80101

func IncrementIP4By

func IncrementIP4By(ip net.IP, count uint32) net.IP

IncrementIP4By returns a v4 net.IP that is greater than the supplied net.IP by the supplied integer value. If you overflow the IP space it will return 255.255.255.255

Example
ip := net.ParseIP("192.168.1.1")
fmt.Println(IncrementIP4By(ip, 255))
Output:

192.168.2.0

func IncrementIP6By

func IncrementIP6By(ip net.IP, count *big.Int) net.IP

IncrementIP6By returns a net.IP that is greater than the supplied net.IP by the supplied integer value. If you overflow the IP space it will return the (meaningless in this context) all-ones address

Example
z := big.NewInt(16777215)
ip := net.ParseIP("2001:db8::ff00:0")
fmt.Println(IncrementIP6By(ip, z))
Output:

2001:db8::ffff:ffff

func IncrementIP6WithinHostmask added in v1.0.0

func IncrementIP6WithinHostmask(ip net.IP, hm HostMask, count *big.Int) (net.IP, error)

IncrementIP6WithinHostmask returns a net.IP that is greater than the unmasked portion of the supplied net.IP by the supplied integer value. If the input or output value fall outside the boundaries of the hostmask a ErrAddressOutOfRange will be returned

Example
ip := net.ParseIP("2001:db8:1000::")
ip1, _ := IncrementIP6WithinHostmask(ip, NewHostMask(0), big.NewInt(1))
ip2, _ := IncrementIP6WithinHostmask(ip, NewHostMask(56), big.NewInt(1))
fmt.Println(ip1)
fmt.Println(ip2)
Output:

2001:db8:1000::1
2001:db8:1000:0:100::

func IncrementIPBy

func IncrementIPBy(ip net.IP, count uint32) net.IP

IncrementIPBy returns a net.IP that is greater than the supplied net.IP by the supplied integer value. If you overflow the IP space it will return the all-ones address

func Is4in6 added in v1.0.0

func Is4in6(ip net.IP) bool

Is4in6 returns true if the supplied net.IP is an IPv4 address encapsulated in an IPv6 address. It is very common for the net library to re-write v4 addresses into v6 addresses prefixed 0000:0000:0000:0000:ffff. When this happens net.IP will have a 16-byte array but always return a v4 address (in fact there is no way to force it to behave as a v6 address), which has lead to many confused message board comments

func IsAllOnes added in v1.0.0

func IsAllOnes(ip net.IP) bool

IsAllOnes returns true if the supplied net.IP is the all-ones address, if given a 4-in-6 address this function will treat it as IPv4

func IsAllZeroes added in v1.0.0

func IsAllZeroes(ip net.IP) bool

IsAllZeroes returns true if the supplied net.IP is the all-zero address, if given a 4-in-6 address this function will treat it as IPv4

func NextIP

func NextIP(ip net.IP) net.IP

NextIP returns a net.IP incremented by one from the input address. This function is roughly as fast for v4 as IncrementIP4By(1) but is consistently 4x faster on v6 than IncrementIP6By(1). The bundled tests provide benchmarks doing so, as well as iterating over the entire v4 address space.

Example
fmt.Println(NextIP(net.ParseIP("192.168.1.1")))
fmt.Println(NextIP(net.ParseIP("2001:db8::ffff:fffe")))
Output:

192.168.1.2
2001:db8::ffff:ffff

func NextIP6WithinHostmask added in v1.0.0

func NextIP6WithinHostmask(ip net.IP, hm HostMask) (net.IP, error)

NextIP6WithinHostmask takes a net.IP and Hostmask as arguments and attempts to increment the IP by one, within the boundary of the hostmask. If bits inside the hostmask are set, an empty net.IP{} and an ErrAddressOutOfRange will be returned

Example
ip, _ := NextIP6WithinHostmask(net.ParseIP("2001:db8:1234:5678::"), NewHostMask(56))
fmt.Println(ip)
Output:

2001:db8:1234:5678:100::

func PreviousIP added in v0.2.0

func PreviousIP(ip net.IP) net.IP

PreviousIP returns a net.IP decremented by one from the input address. This function is roughly as fast for v4 as DecrementIP4By(1) but is consistently 4x faster on v6 than DecrementIP6By(1). The bundled tests provide benchmarks doing so, as well as iterating over the entire v4 address space.

Example
fmt.Println(PreviousIP(net.ParseIP("192.168.1.2")))
fmt.Println(PreviousIP(net.ParseIP("2001:db8::ffff:ffff")))
Output:

192.168.1.1
2001:db8::ffff:fffe

func PreviousIP6WithinHostmask added in v1.0.0

func PreviousIP6WithinHostmask(ip net.IP, hm HostMask) (net.IP, error)

PreviousIP6WithinHostmask takes a net.IP and Hostmask as arguments and attempts to decrement the IP by one, within the boundary of the hostmask. If bits inside the hostmask are set, an empty net.IP{} and an ErrAddressOutOfRange will be returned

Example
ip, _ := PreviousIP6WithinHostmask(net.ParseIP("2001:db8:1234:5678::"), NewHostMask(56))
fmt.Println(ip)
Output:

2001:db8:1234:5677:ff00::

func Uint32ToIP4

func Uint32ToIP4(i uint32) net.IP

Uint32ToIP4 converts a uint32 to an ip4 address and returns it as a net.IP

Example
fmt.Println(Uint32ToIP4(3232235777))
Output:

192.168.1.1

func Uint64ToIP6 added in v1.0.0

func Uint64ToIP6(i uint64) net.IP

Uint64ToIP6 converts a uint64 to an IPv6 address, but only the left-most half of a (128bit) IPv6 address can be accessed in this way, the back half of the address is lost. To manipulate the entire address, see BigintToIP6()

func Version

func Version(ip net.IP) int

Version returns 4 if the net.IP contains a v4 address. It will return 6 for any v6 address, including the v4-encapsulating v6 address range ::ffff. Contrast with EffectiveVersion above and note that in the provided example ForceIP4() is used because, by default, net.ParseIP() stores IPv4 addresses as 4in6 encapsulating v6 addresses. One consequence of which is that it is impossible to use a 4in6 address as a v6 address

Example
fmt.Println(Version(ForceIP4(net.ParseIP("192.168.1.1"))))
fmt.Println(Version(net.ParseIP("::ffff:c0a8:101")))
fmt.Println(Version(net.ParseIP("2001:db8::c0a8:101")))
Output:

4
6
6

Types

type ByIP

type ByIP []net.IP

ByIP implements sort.Interface for net.IP addresses

func (ByIP) Len

func (bi ByIP) Len() int

Len implements sort.interface Len(), returning the length of the ByIP array

func (ByIP) Less

func (bi ByIP) Less(a, b int) bool

Less implements sort.interface Less(), given two elements in the array it returns true if the LHS should sort before the RHS. For details on the implementation, see CompareIPs()

func (ByIP) Swap

func (bi ByIP) Swap(a, b int)

Swap implements sort.interface Swap(), swapping two elements in our array

type ByNet

type ByNet []Net

ByNet implements sort.Interface for iplib.Net based on the starting address of the netblock, with the netmask as a tie breaker. So if two Networks are submitted and one is a subset of the other, the enclosing network will be returned first.

func (ByNet) Len

func (bn ByNet) Len() int

Len implements sort.interface Len(), returning the length of the ByNetwork array

func (ByNet) Less

func (bn ByNet) Less(a, b int) bool

Less implements sort.interface Less(), given two elements in the array it returns true if the LHS should sort before the RHS. For details on the implementation, see CompareNets()

func (ByNet) Swap

func (bn ByNet) Swap(a, b int)

Swap implements sort.interface Swap(), swapping two elements in our array

type HostMask added in v1.0.0

type HostMask []byte

HostMask is a mask that can be applied to IPv6 addresses to mask out bits from the right side of the address instead of the left (which is the purview of a netmask), the intended use-case is for situations where there is a desire to reserve a portion of the address for some other purpose and only allow iplib to manage the remainder. A concrete example would be IPv6 Interface Identifiers as described in RFC4291, RFC4941 or RFC7217 in which the final 64bits of the address are used to construct a unique host identifier and the allocator only has control of the first 64bits. So the next IP from 2001:db8:1234:5678:: would be 2001:db8:1234:5679 instead of 2001:db8:1234:5678::1. Here is a Net6 object eing initialized without a hostmask:

n := NewNet6(2001:db8::, 56, 0)
Address            2001:db8::
Netmask            ffff:ffff:ffff:ff00:0000:0000:0000:0000
Hostmask           0000:0000:0000:0000:0000:0000:0000:0000
First              2001:0db8:0000:0000:0000:0000:0000:0000
Last               2001:0db8:0000:00ff:ffff:ffff:ffff:ffff
Count              4722366482869645213696

This creates a block with 4.7 sextillion usable addresses. Below is he same block with a hostmask of /60. The mask is applied from the rightmost byte, leaving 12 unmasked bits for a total of 4096 allocatable addresses:

n:= NewNet6(2001:db8::, 56, 60)
Address            2001:db8::
Netmask            ffff:ffff:ffff:ff00:0000:0000:0000:0000
Hostmask           0000:0000:0000:0000:0fff:ffff:ffff:ffff
First              2001:0db8:0000:0000:0000:0000:0000:0000
Last               2001:0db8:0000:00ff:f000:0000:0000:0000
Count              4096

In the first example the second IP address of the netblock is 2001:db8::1, in the second example it is 2001:db8:0:1::

One important note: even though bytes are filled in from the right the bits within those bytes are still blocked out left-to-right, so that address incrementing/decrementing makes sense to the end user, as shown here:

BINARY      Base16  Base10  Example Max16  Max10
0000 0000     0x00       0      /56  0xFF    255
1000 0000     0x80     128      /57  0x7F    127
1100 0000     0xC0     192      /58  0x3F     63
1110 0000     0xE0     224      /59  0x1F     31
1111 0000     0xF0     240      /60  0x0F     15
1111 1000     0xF8     248      /61  0x07      7
1111 1100     0xFC     252      /62  0x03      3
1111 1110     0xFE     254      /63  0x01      1

A hostmask of /1 will block out the left-most bit of the 16th byte while a /8 will block the entire 16th byte.

To initialize a hostmask you must give it an integer value between 1 and 128, which represent the number of bits in the mask.

func NewHostMask added in v1.0.0

func NewHostMask(masklen int) HostMask

NewHostMask returns a HostMask initialized to masklen

func (HostMask) BoundaryByte added in v1.0.0

func (m HostMask) BoundaryByte() (byte, int)

BoundaryByte returns the rightmost byte in the mask in which any bits fall inside the hostmask, as well as the position of that byte. For example a masklength of 58 would return "0xc0, 8" while 32 would return "0xff, 12". If the hostmask is unset "0x00, -1" will be returned

func (HostMask) Size added in v1.0.0

func (m HostMask) Size() (int, int)

Size returns the number of ones and total bits in the mask

func (HostMask) String added in v1.0.0

func (m HostMask) String() string

String returns the hexadecimal form of m, with no punctuation

type Net

type Net interface {
	Contains(ip net.IP) bool
	ContainsNet(network Net) bool
	FirstAddress() net.IP
	IP() net.IP
	LastAddress() net.IP
	Mask() net.IPMask
	String() string
	Version() int
}

Net describes an iplib.Net object, the enumerated functions are those that are required for comparison, sorting, generic initialization and for ancillary functions such as those found in the iid and iana submodules

func NewNet

func NewNet(ip net.IP, masklen int) Net

NewNet returns a new Net object containing ip at the specified masklen. In the Net6 case the hostbits value will be set to 0. If the masklen is set to an insane value (greater than 32 for IPv4 or 128 for IPv6) an empty Net will be returned

func NewNetBetween

func NewNetBetween(a, b net.IP) (Net, bool, error)

NewNetBetween takes two net.IP's as input and will return the largest netblock that can fit between them (exclusive of the IP's themselves). If there is an exact fit it will set a boolean to true, otherwise the bool will be false. If no fit can be found (probably because a >= b) an ErrNoValidRange will be returned.

func ParseCIDR

func ParseCIDR(s string) (net.IP, Net, error)

ParseCIDR returns a new Net object. It is a passthrough to net.ParseCIDR and will return any error it generates to the caller. There is one major difference between how net.IPNet manages addresses and how ipnet.Net does, and this function exposes it: net.ParseCIDR *always* returns an IPv6 address; if given a v4 address it returns the RFC4291 IPv4-mapped IPv6 address internally, but treats it like v4 in practice. In contrast iplib.ParseCIDR will re-encode it as a v4

type Net4 added in v1.0.0

type Net4 struct {
	net.IPNet
	// contains filtered or unexported fields
}

Net4 is an implementation of Net intended for IPv4 netblocks. It has functions to return the broadcast address and wildcard mask not present in the IPv6 implementation

func Net4FromStr added in v1.0.0

func Net4FromStr(s string) Net4

Net4FromStr takes a string which should be a v4 address in CIDR notation and returns an initialized Net4. If the string isn't parseable an empty Net4 will be returned

func NewNet4 added in v1.0.0

func NewNet4(ip net.IP, masklen int) Net4

NewNet4 returns an initialized Net4 object at the specified masklen. If mask is greater than 32, or if a v6 address is supplied, an empty Net4 will be returned

func (Net4) BroadcastAddress added in v1.0.0

func (n Net4) BroadcastAddress() net.IP

BroadcastAddress returns the broadcast address for the represented network. In the context of IPv6 broadcast is meaningless and the value will be equivalent to LastAddress().

func (Net4) Contains added in v1.0.0

func (n Net4) Contains(ip net.IP) bool

Contains returns true if ip is contained in the represented netblock

Example
n := NewNet4(net.ParseIP("192.168.1.0"), 24)
fmt.Println(n.Contains(net.ParseIP("192.168.1.111")))
fmt.Println(n.Contains(net.ParseIP("10.14.0.1")))
Output:

true
false

func (Net4) ContainsNet added in v1.0.0

func (n Net4) ContainsNet(network Net) bool

ContainsNet returns true if the given Net is contained within the represented block

Example
n1 := NewNet4(net.ParseIP("192.168.0.0"), 16)
n2 := NewNet4(net.ParseIP("192.168.1.0"), 24)
fmt.Println(n1.ContainsNet(n2))
fmt.Println(n2.ContainsNet(n1))
Output:

true
false

func (Net4) Count added in v1.0.0

func (n Net4) Count() uint32

Count returns the total number of usable IP addresses in the represented network..

Example
n := NewNet4(net.ParseIP("192.168.0.0"), 16)
fmt.Println(n.Count())
Output:

65534

func (Net4) Enumerate added in v1.0.0

func (n Net4) Enumerate(size, offset int) []net.IP

Enumerate generates an array of all usable addresses in Net up to the given size starting at the given offset. If size=0 the entire block is enumerated.

NOTE: RFC3021 defines a use case for netblocks of /31 for use in point-to- point links. For this reason enumerating networks at these lengths will return a 2-element array even though it would naturally return none.

For consistency, enumerating a /32 will return the IP in a 1 element array

Example
n := NewNet4(net.ParseIP("192.168.0.0"), 16)
fmt.Println(n.Enumerate(2, 100))
Output:

[192.168.0.101 192.168.0.102]

func (Net4) FirstAddress added in v1.0.0

func (n Net4) FirstAddress() net.IP

FirstAddress returns the first usable address for the represented network

func (Net4) IP added in v1.0.0

func (n Net4) IP() net.IP

IP returns the network address for the represented network, e.g. the lowest IP address in the given block

func (Net4) Is4in6 added in v1.0.0

func (n Net4) Is4in6() bool

Is4in6 will return true if this Net4 object or any of its parents were explicitly initialized with a 4in6 address (::ffff:xxxx.xxx)

func (Net4) LastAddress added in v1.0.0

func (n Net4) LastAddress() net.IP

LastAddress returns the last usable address for the represented network

func (Net4) Mask added in v1.0.0

func (n Net4) Mask() net.IPMask

Mask returns the netmask of the netblock

func (Net4) NetworkAddress added in v1.0.0

func (n Net4) NetworkAddress() net.IP

NetworkAddress returns the network address for the represented network, e.g. the lowest IP address in the given block

func (Net4) NextIP added in v1.0.0

func (n Net4) NextIP(ip net.IP) (net.IP, error)

NextIP takes a net.IP as an argument and attempts to increment it by one. If the resulting address is outside of the range of the represented network it will return an empty net.IP and an ErrAddressOutOfRange. If the result is the broadcast address, the address _will_ be returned, but so will an ErrBroadcastAddress, to indicate that the address is technically outside the usable scope

func (Net4) NextNet added in v1.0.0

func (n Net4) NextNet(masklen int) Net4

NextNet takes a CIDR mask-size as an argument and attempts to create a new Net object just after the current Net, at the requested mask length

Example
n := NewNet4(net.ParseIP("192.168.1.0"), 24)
fmt.Println(n.NextNet(24))
Output:

192.168.2.0/24

func (Net4) PreviousIP added in v1.0.0

func (n Net4) PreviousIP(ip net.IP) (net.IP, error)

PreviousIP takes a net.IP as an argument and attempts to decrement it by one. If the resulting address is outside of the range of the represented network it will return an empty net.IP and an ErrAddressOutOfRange. If the result is the network address, the address _will_ be returned, but so will an ErrNetworkAddress, to indicate that the address is technically outside the usable scope

func (Net4) PreviousNet added in v1.0.0

func (n Net4) PreviousNet(masklen int) Net4

PreviousNet takes a CIDR mask-size as an argument and creates a new Net object just before the current one, at the requested mask length. If the specified mask is for a larger network than the current one then the new network may encompass the current one, e.g.:

iplib.Net{192.168.4.0/22}.Subnet(21) -> 192.168.0.0/21

In the above case 192.168.4.0/22 is part of 192.168.0.0/21

Example
n := NewNet4(net.ParseIP("192.168.1.0"), 24)
fmt.Println(n.PreviousNet(24))
Output:

192.168.0.0/24

func (Net4) RandomIP added in v1.0.6

func (n Net4) RandomIP() net.IP

RandomIP returns a random address from this Net4. It uses crypto/rand and *big.Int so is not the most performant implementation possible

func (Net4) String added in v1.0.0

func (n Net4) String() string

String returns the CIDR notation of the enclosed network e.g. 192.168.0.1/24

func (Net4) Subnet added in v1.0.0

func (n Net4) Subnet(masklen int) ([]Net4, error)

Subnet takes a CIDR mask-size as an argument and carves the current Net object into subnets of that size, returning them as a []Net. The mask provided must be a larger-integer than the current mask. If set to 0 Subnet will carve the network in half

Example
n := NewNet4(net.ParseIP("192.168.0.0"), 16)
sub, _ := n.Subnet(17)
fmt.Println(sub)
Output:

[192.168.0.0/17 192.168.128.0/17]

func (Net4) Supernet added in v1.0.0

func (n Net4) Supernet(masklen int) (Net4, error)

Supernet takes a CIDR mask-size as an argument and returns a Net object containing the supernet of the current Net at the requested mask length. The mask provided must be a smaller-integer than the current mask. If set to 0 Supernet will return the next-largest network

Examples: Net{192.168.1.0/24}.Supernet(0) -> Net{192.168.0.0/23} Net{192.168.1.0/24}.Supernet(22) -> Net{Net{192.168.0.0/22}

Example
n := NewNet4(net.ParseIP("192.168.1.0"), 24)
n2, _ := n.Supernet(22)
fmt.Println(n2)
Output:

192.168.0.0/22

func (Net4) Version added in v1.0.0

func (n Net4) Version() int

Version returns the version of IP for the enclosed netblock, 4 in this case

func (Net4) Wildcard added in v1.0.0

func (n Net4) Wildcard() net.IPMask

Wildcard will return the wildcard mask for a given netmask

Example
n := NewNet4(net.ParseIP("192.168.0.0"), 16)
fmt.Println(n.Wildcard())
Output:

0000ffff

type Net6 added in v1.0.0

type Net6 struct {
	net.IPNet
	Hostmask HostMask
}

Net6 is an implementation of Net that supports IPv6 operations. To initialize a Net6 you must supply a network address and mask prefix as with Net4, but you may also optionally supply an integer value between 0 and 128 that Net6 will mask out from the right, via a HostMask (see the documentation for HostMask in this library). If "0" HostMask will be ignored. The sum of netmask prefix and hostmask must be less than 128.

Hostmask affects Count, Enumerate, LastAddress, NextIP and PreviousIP; it also affects NextNet and PreviousNet which will inherit the hostmask from their parent. Subnet and Supernet both require a hostmask in their function calls

func Net6FromStr added in v1.0.0

func Net6FromStr(s string) Net6

Net6FromStr takes a string which should be a v6 address in CIDR notation and returns an initialized Net6. If the string isn't parseable an empty Net6 will be returned

func NewNet6 added in v1.0.0

func NewNet6(ip net.IP, netmasklen, hostmasklen int) Net6

NewNet6 returns an initialized Net6 object at the specified netmasklen with the specified hostmasklen. If netmasklen or hostmasklen is greater than 128 it will return an empty object; it will also return an empty object if the sum of the two masks is 128 or greater. If a v4 address is supplied it will be treated as a RFC4291 v6-encapsulated-v4 network (which is the default behavior for net.IP)

func (Net6) Contains added in v1.0.0

func (n Net6) Contains(ip net.IP) bool

Contains returns true if ip is contained in the represented netblock

Example
n := NewNet6(net.ParseIP("2001:db8:1234:5678::"), 64, 0)
fmt.Println(n.Contains(net.ParseIP("2001:db8:1234:5678::1")))
fmt.Println(n.Contains(net.ParseIP("2001:db8:1234::")))
Output:

true
false

func (Net6) ContainsNet added in v1.0.0

func (n Net6) ContainsNet(network Net) bool

ContainsNet returns true if the given Net is contained within the represented block

func (Net6) Controls added in v1.0.0

func (n Net6) Controls(ip net.IP) bool

Controls returns true if ip is within the scope of the represented block, meaning that it is both inside of the netmask and outside of the hostmask. In other words this function will return true if ip would be enumerated by this Net6 instance

func (Net6) Count added in v1.0.0

func (n Net6) Count() *big.Int

Count returns the number of IP addresses in the represented netblock

Example
// without hostmask
n := NewNet6(net.ParseIP("2001:db8:1234:5678::"), 64, 0)
fmt.Println(n.Count())

// with hostmask set to 56, leaving 8 usable bytes between the two masks
n = NewNet6(net.ParseIP("2001:db8:1234:5678::"), 64, 56)
fmt.Println(n.Count())
Output:

18446744073709551616
256

func (Net6) Enumerate added in v1.0.0

func (n Net6) Enumerate(size, offset int) []net.IP

Enumerate generates an array of all usable addresses in Net up to the given size starting at the given offset, so long as the result is less than MaxUint32. If size=0 the entire block is enumerated (again, so long as the result is less than MaxUint32).

For consistency, enumerating a /128 will return the IP in a 1 element array

func (Net6) FirstAddress added in v1.0.0

func (n Net6) FirstAddress() net.IP

FirstAddress returns the first usable address for the represented network

func (Net6) IP added in v1.0.0

func (n Net6) IP() net.IP

IP returns the network address for the represented network, e.g. the lowest IP address in the given block

func (Net6) LastAddress added in v1.0.0

func (n Net6) LastAddress() net.IP

LastAddress returns the last usable address for the represented network

Example
// without hostmask
n := NewNet6(net.ParseIP("2001:db8:1234:5678::"), 64, 0)
fmt.Println(n.LastAddress())

// with hostmask set to 56, leaving 8 usable bytes between the two masks
n = NewNet6(net.ParseIP("2001:db8:1234:5678::"), 64, 56)
fmt.Println(n.LastAddress())
Output:

2001:db8:1234:5678:ffff:ffff:ffff:ffff
2001:db8:1234:5678:ff00::

func (Net6) Mask added in v1.0.0

func (n Net6) Mask() net.IPMask

Mask returns the netmask of the netblock

func (Net6) NextIP added in v1.0.0

func (n Net6) NextIP(ip net.IP) (net.IP, error)

NextIP takes a net.IP as an argument and attempts to increment it by one within the boundary of allocated network-bytes. If the resulting address is outside of the range of the represented network it will return an empty net.IP and an ErrAddressOutOfRange

Example
// without hostmask
n := NewNet6(net.ParseIP("2001:db8:1234:5678::"), 64, 0)
fmt.Println(n.NextIP(net.ParseIP("2001:db8:1234:5678::")))

// with hostmask set to 56, leaving 8 usable bytes between the two masks
n = NewNet6(net.ParseIP("2001:db8:1234:5678::"), 64, 56)
fmt.Println(n.NextIP(net.ParseIP("2001:db8:1234:5678::")))

// as above, but trying to scan past the end of the netblock
fmt.Println(n.NextIP(net.ParseIP("2001:db8:1234:5678:ff00::")))
Output:

2001:db8:1234:5678::1 <nil>
2001:db8:1234:5678:100:: <nil>
<nil> address is not a part of this netblock

func (Net6) NextNet added in v1.0.0

func (n Net6) NextNet(masklen int) Net6

NextNet takes a CIDR mask-size as an argument and attempts to create a new Net object just after the current Net, at the requested mask length and with the same hostmask as the current Net

Example
n := NewNet6(net.ParseIP("2001:db8:1234:5678::"), 64, 0)
fmt.Println(n.NextNet(0))
Output:

2001:db8:1234:5679::/64

func (Net6) PreviousIP added in v1.0.0

func (n Net6) PreviousIP(ip net.IP) (net.IP, error)

PreviousIP takes a net.IP as an argument and attempts to decrement it by one within the boundary of the allocated network-bytes. If the resulting address is outside the range of the represented netblock it will return an empty net.IP and an ErrAddressOutOfRange

Example
// without hostmask
n := NewNet6(net.ParseIP("2001:db8:1234:5678::"), 64, 0)
fmt.Println(n.PreviousIP(net.ParseIP("2001:db8:1234:5678:ff00::")))

// as above, but trying to scan past the end of the netblock
fmt.Println(n.PreviousIP(net.ParseIP("2001:db8:1234:5678::")))

// with hostmask set to 56, leaving 8 usable bytes between the two masks
n = NewNet6(net.ParseIP("2001:db8:1234:5678::"), 64, 56)
fmt.Println(n.PreviousIP(net.ParseIP("2001:db8:1234:5678:ff00::")))
Output:

2001:db8:1234:5678:feff:ffff:ffff:ffff <nil>
<nil> address is not a part of this netblock
2001:db8:1234:5678:fe00:: <nil>

func (Net6) PreviousNet added in v1.0.0

func (n Net6) PreviousNet(masklen int) Net6

PreviousNet takes a CIDR mask-size as an argument and creates a new Net object just before the current one, at the requested mask length. If the specified mask is for a larger network than the current one then the new network may encompass the current one

Example
n := NewNet6(net.ParseIP("2001:db8:1234:5678::"), 64, 0)

// at the same netmask
fmt.Println(n.PreviousNet(0))

// at a larger netmask (result encompasses the starting network)
fmt.Println(n.PreviousNet(62))
Output:

2001:db8:1234:5677::/64
2001:db8:1234:5674::/62

func (Net6) RandomIP added in v1.0.6

func (n Net6) RandomIP() net.IP

RandomIP returns a random address from this Net6. It uses crypto/rand and so is not the most performant implementation possible

func (Net6) String added in v1.0.0

func (n Net6) String() string

String returns the CIDR notation of the enclosed network e.g. 2001:db8::/16

func (Net6) Subnet added in v1.0.0

func (n Net6) Subnet(netmasklen, hostmasklen int) ([]Net6, error)

Subnet takes a CIDR mask-size as an argument and carves the current Net object into subnets of that size, returning them as a []Net. The mask provided must be a larger-integer than the current mask. If set to 0 Subnet will carve the network in half. Hostmask must be provided if desired

Example
n := NewNet6(net.ParseIP("2001:db8:1234:5678::"), 64, 0)
for _, i := range []int{65, 66} {
	sub, _ := n.Subnet(i, 0)
	fmt.Println(sub)
}
Output:

[2001:db8:1234:5678::/65 2001:db8:1234:5678:8000::/65]
[2001:db8:1234:5678::/66 2001:db8:1234:5678:4000::/66 2001:db8:1234:5678:8000::/66 2001:db8:1234:5678:c000::/66]

func (Net6) Supernet added in v1.0.0

func (n Net6) Supernet(netmasklen, hostmasklen int) (Net6, error)

Supernet takes a CIDR mask-size as an argument and returns a Net object containing the supernet of the current Net at the requested mask length. The mask provided must be a smaller-integer than the current mask. If set to 0 Supernet will return the next-largest network

Example
n := NewNet6(net.ParseIP("2001:db8:1234:5678::"), 64, 0)
fmt.Println(n.Supernet(0, 0))
Output:

2001:db8:1234:5678::/63 <nil>

func (Net6) Version added in v1.0.0

func (n Net6) Version() int

Version returns the version of IP for the enclosed netblock as an int. 6 in this case

Directories

Path Synopsis
Package iana imports the Internet Assigned Numbers Authority (IANA) IP Special Registries as a data structure and implements functions to compare the reserved networks against iplib.Net objects.
Package iana imports the Internet Assigned Numbers Authority (IANA) IP Special Registries as a data structure and implements functions to compare the reserved networks against iplib.Net objects.
Package iid provides functions for generating and validating IPv6 Interface Identifiers (IID's).
Package iid provides functions for generating and validating IPv6 Interface Identifiers (IID's).

Jump to

Keyboard shortcuts

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