iprange

package module
v0.6.3 Latest Latest
Warning

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

Go to latest
Published: Feb 4, 2023 License: MIT Imports: 6 Imported by: 0

README

package iprange

Go Reference GitHub release (latest SemVer) CI Coverage Status Stand With Ukraine

package iprange is an extension to net/netip

An additional type IPRange is defined and the most useful methods for it. Not all IP address ranges in the wild are CIDRs, very often you have to deal with ranges not representable as a prefix. This library handels IP ranges and CIDRs transparently.

API

import "github.com/gaissmai/iprange"

type IPRange struct{ ... }

  func FromString(s string) (IPRange, error)
  func FromAddrs(first, last netip.Addr) (IPRange, error)
  func FromPrefix(p netip.Prefix) (IPRange, error)

  func (r IPRange) Addrs() (first, last netip.Addr)
  func (r IPRange) String() string
  func (r IPRange) IsValid() bool

  func Merge(in []IPRange) (out []IPRange)
  func (r IPRange) Remove(in []IPRange) (out []IPRange)

  func (r IPRange) Prefix() (prefix netip.Prefix, ok bool)
  func (r IPRange) Prefixes() []netip.Prefix
  func (r IPRange) PrefixesAppend(dst []netip.Prefix) []netip.Prefix

  func (r IPRange) MarshalBinary() ([]byte, error)
  func (r IPRange) MarshalText() ([]byte, error)

  func (r *IPRange) UnmarshalBinary(data []byte) error
  func (r *IPRange) UnmarshalText(text []byte) error

  func Compare(a, b IPRange) (ll, rr, lr, rl int)

Advanced features

For fast lookups use the Compare function together with the interval package from the same author.

Documentation

Overview

Package iprange is an extension to net/netip.

An additional type IPRange is defined and the most useful methods for it.

For more advanced functionality IPRange implements the interval.Interface for fast lookups.

see also: https://github.com/gaissmai/interval

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Compare added in v0.6.1

func Compare(a, b IPRange) (ll int, rr int, lr int, rl int)

Compare returns four integers comparing the four points of the two IP ranges. Implements the cmp function in the package interval for fast lookups.

Types

type IPRange

type IPRange struct {
	// contains filtered or unexported fields
}

IPRange represents an inclusive range of IP addresses from the same address family.

10.0.0.3-10.0.17.134        // range
2001:db8::1-2001:db8::f6    // range
192.168.0.1/24              // Prefix aka CIDR
::1/128                     // Prefix aka CIDR

Not all IP address ranges in the wild are CIDRs, very often you have to deal with ranges not representable as a prefix.

This library handels IP ranges and CIDRs transparently.

func FromAddrs added in v0.5.0

func FromAddrs(first, last netip.Addr) (IPRange, error)

FromAddrs returns an IPRange from the provided IP addresses.

IP addresses with zones are not allowed.

func FromPrefix added in v0.5.0

func FromPrefix(p netip.Prefix) (IPRange, error)

FromPrefix returns an IPRange from the standard library's netip.Prefix type.

func FromString added in v0.4.0

func FromString(s string) (IPRange, error)

FromString parses the input string and returns an IPRange.

Returns an error on invalid input.

Valid strings are of the form:

192.168.2.3-192.168.7.255
2001:db8::1-2001:db8::ff00:35

2001:db8:dead::/38
10.0.0.0/8

4.4.4.4
::0

Single IP addresses as input are converted to /32 or /128 ranges.

The hard part is done by netip.ParseAddr and netip.ParsePrefix from the stdlib.

Example
package main

import (
	"fmt"

	"github.com/gaissmai/iprange"
)

func isPrefix(p iprange.IPRange) bool {
	_, ok := p.Prefix()
	return ok
}

func main() {
	for _, s := range []string{
		"fe80::1-fe80::2",         // as range
		"10.0.0.0-11.255.255.255", // as range but true CIDR, see output
		"",                        // invalid
	} {
		r, _ := iprange.FromString(s)
		fmt.Printf("%-20s isPrefix: %5v\n", r, isPrefix(r))
	}

}
Output:

fe80::1-fe80::2      isPrefix: false
10.0.0.0/7           isPrefix:  true
invalid IPRange      isPrefix: false

func Merge

func Merge(in []IPRange) (out []IPRange)

Merge adjacent and overlapping IPRanges.

Skip dups and subsets and invalid ranges, returns the remaining IPRanges sorted.

Example
package main

import (
	"fmt"

	"github.com/gaissmai/iprange"
)

func main() {
	var rs []iprange.IPRange
	for _, s := range []string{
		"10.0.0.0/32",
		"10.0.0.1/32",
		"10.0.0.4/30",
		"10.0.0.6-10.0.0.99",
		"fe80::/12",
		"fe80:0000:0000:0000:fe2d:5eff:fef0:fc64/128",
		"fe80::/10",
	} {
		r, _ := iprange.FromString(s)
		rs = append(rs, r)
	}

	merged := iprange.Merge(rs)
	fmt.Printf("%v\n", merged)

}
Output:

[10.0.0.0/31 10.0.0.4-10.0.0.99 fe80::/10]

func (IPRange) Addrs

func (r IPRange) Addrs() (first, last netip.Addr)

Addrs returns the first and last IP address of the IPRange.

Example
package main

import (
	"fmt"

	"github.com/gaissmai/iprange"
)

func mustParse(s string) iprange.IPRange {
	r, err := iprange.FromString(s)
	if err != nil {
		panic(err)
	}
	return r
}

func main() {
	first, last := mustParse("fe80::/10").Addrs()

	fmt.Printf("Addrs() fe80::/10\n")
	fmt.Printf("first:  %s\n", first)
	fmt.Printf("last:   %s\n", last)

}
Output:

Addrs() fe80::/10
first:  fe80::
last:   febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff

func (IPRange) CompareLower deprecated

func (r IPRange) CompareLower(r2 IPRange) int

CompareLower

Deprecated: see Compare

func (IPRange) CompareUpper deprecated

func (r IPRange) CompareUpper(r2 IPRange) int

CompareUpper

Deprecated: see Compare

func (IPRange) IsValid added in v0.4.1

func (r IPRange) IsValid() bool

IsValid reports whether r is a valid IPRange.

func (IPRange) MarshalBinary

func (r IPRange) MarshalBinary() ([]byte, error)

MarshalBinary implements the encoding.BinaryMarshaler interface.

func (IPRange) MarshalText

func (r IPRange) MarshalText() ([]byte, error)

MarshalText implements the encoding.TextMarshaler interface, The encoding is the same as returned by String, with one exception: If r is the zero IPRange, the encoding is the empty string.

func (IPRange) Prefix

func (r IPRange) Prefix() (prefix netip.Prefix, ok bool)

Prefix returns r as a netip.Prefix, if it can be presented exactly as such. If r is not valid or is not exactly equal to one prefix, ok is false.

func (IPRange) Prefixes

func (r IPRange) Prefixes() []netip.Prefix

Prefixes returns the slice of netip.Prefix entries that covers r.

If r is invalid Prefixes returns nil.

Prefixes necessarily allocates. See PrefixesAppend for a version that uses memory you provide.

Example
package main

import (
	"fmt"

	"github.com/gaissmai/iprange"
)

func main() {
	r, _ := iprange.FromString("10.0.0.6-10.0.0.99")
	fmt.Printf("%s -> Prefixes:\n", r)
	for _, p := range r.Prefixes() {
		fmt.Println(p)
	}

	fmt.Println()

	r, _ = iprange.FromString("2001:db8::affe-2001:db8::ffff")
	fmt.Printf("%s -> Prefixes:\n", r)
	for _, p := range r.Prefixes() {
		fmt.Println(p)
	}

}
Output:

10.0.0.6-10.0.0.99 -> Prefixes:
10.0.0.6/31
10.0.0.8/29
10.0.0.16/28
10.0.0.32/27
10.0.0.64/27
10.0.0.96/30

2001:db8::affe-2001:db8::ffff -> Prefixes:
2001:db8::affe/127
2001:db8::b000/116
2001:db8::c000/114

func (IPRange) PrefixesAppend

func (r IPRange) PrefixesAppend(dst []netip.Prefix) []netip.Prefix

PrefixesAppend is the append version of Prefixes.

It appends to dst the netip.Prefix entries that covers r.

func (IPRange) Remove

func (r IPRange) Remove(in []IPRange) (out []IPRange)

Remove the slice of IPRanges from r, returns the remaining IPRanges.

Example (V4)
package main

import (
	"fmt"

	"github.com/gaissmai/iprange"
)

func mustParse(s string) iprange.IPRange {
	r, err := iprange.FromString(s)
	if err != nil {
		panic(err)
	}
	return r
}

func main() {
	outer, _ := iprange.FromString("192.168.2.0/24")
	inner := []iprange.IPRange{
		mustParse("192.168.2.0/26"),
		mustParse("192.168.2.240-192.168.2.249"),
	}

	fmt.Printf("outer: %v\n", outer)
	fmt.Printf("inner: %v\n", inner)
	fmt.Println("Result:")
	for _, r := range outer.Remove(inner) {
		fmt.Println(r)
	}

}
Output:

outer: 192.168.2.0/24
inner: [192.168.2.0/26 192.168.2.240-192.168.2.249]
Result:
192.168.2.64-192.168.2.239
192.168.2.250-192.168.2.255
Example (V6)
package main

import (
	"fmt"

	"github.com/gaissmai/iprange"
)

func mustParse(s string) iprange.IPRange {
	r, err := iprange.FromString(s)
	if err != nil {
		panic(err)
	}
	return r
}

func main() {
	outer, _ := iprange.FromString("2001:db8:de00::/40")
	inner := []iprange.IPRange{mustParse("2001:db8:dea0::/44")}

	fmt.Printf("outer: %v\n", outer)
	fmt.Printf("inner: %v\n", inner)
	fmt.Println("Result:")
	for _, r := range outer.Remove(inner) {
		fmt.Println(r)
	}

}
Output:

outer: 2001:db8:de00::/40
inner: [2001:db8:dea0::/44]
Result:
2001:db8:de00::-2001:db8:de9f:ffff:ffff:ffff:ffff:ffff
2001:db8:deb0::-2001:db8:deff:ffff:ffff:ffff:ffff:ffff

func (IPRange) String

func (r IPRange) String() string

String returns the string form of the IPRange.

"127.0.0.1-127.0.0.19"
"2001:db8::/32"

func (*IPRange) UnmarshalBinary

func (r *IPRange) UnmarshalBinary(data []byte) error

UnmarshalBinary implements the encoding.BinaryUnmarshaler interface. It expects data in the form generated by MarshalBinary.

func (*IPRange) UnmarshalText

func (r *IPRange) UnmarshalText(text []byte) error

UnmarshalText implements the encoding.TextUnmarshaler interface. The IPRange is expected in a form accepted by FromString.

If text is empty, UnmarshalText sets *r to the zero IPRange and returns no error.

Jump to

Keyboard shortcuts

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