inet

package
v2.1.0 Latest Latest
Warning

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

Go to latest
Published: Jul 25, 2022 License: MIT Imports: 9 Imported by: 1

Documentation

Overview

Package inet represents IP-addresses and IP-Blocks as comparable types.

Some missing utility functions in the standard library for IP-addresses and IP-blocks are provided.

This IP representation is comparable and can be sorted very quickly without prior conversions to/from the different IP versions.

The library is mainly intended for fast ACL-lookups and for IP address management (IPAM) in global scope and not for host related systems programming.

So, no IP address zone indices are supported and IPv4-mapped IPv6 addresses are stripped down to plain IPv4 addresses. The information of the prior mapping is discarded.

Blocks are IP-networks or arbitrary IP-ranges, e.g.

192.168.0.1/24              // network
::1/128                     // network
10.0.0.3-10.0.17.134        // range
2001:db8::1-2001:db8::f6    // range

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Block

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

Block is an IP-network or IP-range, e.g.

192.168.0.1/24              // network, with CIDR mask
::1/128                     // network, with CIDR mask
10.0.0.3-10.0.17.134        // range
2001:db8::1-2001:db8::f6    // range

This Block representation is comparable and can be used as key in maps and fast sorted without conversions to/from the different IP versions.

Each Block object only stores two IP addresses, the base and last address of the range or network.

func FromStdIPNet

func FromStdIPNet(stdNet net.IPNet) (b Block, err error)

FromStdIPNet returns an Block from the standard library's IPNet type. If std is invalid, ok is false. If std is invalid, returns Block{} and error.

func Merge

func Merge(bs []Block) []Block

Merge adjacent blocks, remove dups and subsets, returns the remaining blocks sorted.

Example
package main

import (
	"fmt"

	"github.com/gaissmai/go-inet/v2/inet"
)

func main() {
	var bs []inet.Block
	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",
	} {
		b, _ := inet.ParseBlock(s)
		bs = append(bs, b)
	}

	packed := inet.Merge(bs)
	fmt.Printf("%v\n", packed)

}
Output:

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

func ParseBlock

func ParseBlock(s string) (b Block, err error)

ParseBlock parses and returns the input string as type Block.

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

IP addresses as input are converted to /32 or /128 blocks. Returns error and Block{} on invalid input.

The hard part is done by net.ParseIP() and net.ParseCIDR().

Example
package main

import (
	"fmt"

	"github.com/gaissmai/go-inet/v2/inet"
)

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
	} {
		a, _ := inet.ParseBlock(s)
		fmt.Printf("block: %-20s IsValid: %5v, IsCIDR: %5v, Is4: %5v, Is6: %5v\n", a, a.IsValid(), a.IsCIDR(), a.Is4(), a.Is6())
	}

}
Output:

block: fe80::1-fe80::2      IsValid:  true, IsCIDR: false, Is4: false, Is6:  true
block: 10.0.0.0/7           IsValid:  true, IsCIDR:  true, Is4:  true, Is6: false
block: invalid Block        IsValid: false, IsCIDR: false, Is4: false, Is6: false

func (Block) Base

func (b Block) Base() IP

Base returns the base IP address of the block.

func (Block) CIDRs

func (b Block) CIDRs() []Block

CIDRs returns a list of CIDRs that span b.

Example
package main

import (
	"fmt"

	"github.com/gaissmai/go-inet/v2/inet"
)

func main() {
	b, _ := inet.ParseBlock("10.0.0.6-10.0.0.99")
	fmt.Printf("%v\n", b.CIDRs())

	b, _ = inet.ParseBlock("2001:db8::affe-2001:db8::ffff")
	fmt.Printf("%v\n", b.CIDRs())

}
Output:

[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/127 2001:db8::b000/116 2001:db8::c000/114]

func (Block) Covers

func (b Block) Covers(c Block) bool

Covers reports whether Block b contains Block c. b and c may NOT coincide. b.Covers(c) returns true when b is a *true* cover of c, b == c must then be false.

b |-----------------| |-----------------| |-----------------|
c   |------------|    |------------|           |------------|

func (Block) Diff

func (b Block) Diff(bs []Block) []Block

Diff the slice of blocks from receiver, returns the remaining blocks.

Example (V4)
package main

import (
	"fmt"

	"github.com/gaissmai/go-inet/v2/inet"
)

func mustParseBlock(s string) inet.Block {
	b, err := inet.ParseBlock(s)
	if err != nil {
		panic(err)
	}
	return b
}

func main() {
	outer, _ := inet.ParseBlock("192.168.2.0/24")
	inner := []inet.Block{
		mustParseBlock("192.168.2.0/26"),
		mustParseBlock("192.168.2.240-192.168.2.249"),
	}

	fmt.Printf("%v - %v\ndiff: %v\n", outer, inner, outer.Diff(inner))

}
Output:

192.168.2.0/24 - [192.168.2.0/26 192.168.2.240-192.168.2.249]
diff: [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/go-inet/v2/inet"
)

func main() {

	outer, _ := inet.ParseBlock("2001:db8:de00::/40")
	inner, _ := inet.ParseBlock("2001:db8:dea0::/44")

	fmt.Printf("%v - %v\ndiff: %v\n", outer, inner, outer.Diff([]inet.Block{inner}))

}
Output:

2001:db8:de00::/40 - 2001:db8:dea0::/44
diff: [2001:db8:de00::-2001:db8:de9f:ffff:ffff:ffff:ffff:ffff 2001:db8:deb0::-2001:db8:deff:ffff:ffff:ffff:ffff:ffff]

func (Block) Is4

func (b Block) Is4() bool

Is4 reports whether block is IPv4.

func (Block) Is6

func (b Block) Is6() bool

Is6 reports whether block is IPv6.

func (Block) IsCIDR

func (b Block) IsCIDR() bool

IsCIDR returns true if the block has a common prefix netmask.

func (Block) IsValid

func (b Block) IsValid() bool

IsValid reports whether block is valid and not the zero value of the Block type. The zero value is not a valid Block of any type.

func (Block) Last

func (b Block) Last() IP

Last returns the last IP address of the block.

func (Block) Less

func (b Block) Less(c Block) bool

Less reports whether the block b should be sorted before c. REMEMBER: sort the supersets always to the left of their subsets! If b.Covers(c) is true then b.Less(c) must also be true.

b |---|
c       |------|

b |-------|
c    |------------|

b |-----------------|
c    |----------|

b |-----------------|
c |------------|
Example
package main

import (
	"fmt"
	"sort"

	"github.com/gaissmai/go-inet/v2/inet"
)

func main() {
	var buf []inet.Block
	for _, s := range []string{
		"2001:db8:dead:beef::/44",
		"10.0.0.0/9",
		"::/0",
		"10.96.0.2-10.96.1.17",
		"0.0.0.0/0",
		"::-::ffff",
		"2001:db8::/32",
	} {
		b, _ := inet.ParseBlock(s)
		buf = append(buf, b)
	}

	sort.Slice(buf, func(i, j int) bool { return buf[i].Less(buf[j]) })
	fmt.Printf("%v\n", buf)

}
Output:

[0.0.0.0/0 10.0.0.0/9 10.96.0.2-10.96.1.17 ::/0 ::/112 2001:db8::/32 2001:db8:dea0::/44]

func (Block) String

func (b Block) String() string

String returns the string form of the Block. It returns one of 3 forms:

"invalid Block"         if b.IsValid() is false
"127.0.0.1-127.0.0.19"  if b.IsCIDR is false
"2001:db8::/32"         if b.IsCIDR is true

type IP

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

IP represents a single IPv4 or IPv6 address.

func FromStdIP

func FromStdIP(std net.IP) (ip IP, err error)

FromStdIP returns an IP from the standard library's IP type.

If std is <nil>, returns the zero value and error.

func ParseIP

func ParseIP(s string) (ip IP, err error)

ParseIP parses and returns the input as type IP. Returns the zero value for IP and error on invalid input.

The string form can be in IPv4 dotted decimal ("192.168.2.1"), IPv6 ("2001:db8::affe"), or IPv4-mapped IPv6 ("::ffff:172.16.0.1").

The hard part is done by net.ParseIP().

Example
package main

import (
	"fmt"

	"github.com/gaissmai/go-inet/v2/inet"
)

func main() {
	for _, s := range []string{
		"2001:db8::",         // IPv6
		"::ffff:192.168.0.1", // IPv4-mapped IPv6
		"10.0.0.1",           // IPv4
	} {
		ip, _ := inet.ParseIP(s)
		fmt.Printf("ip: %v\n", ip)
	}

}
Output:

ip: 2001:db8::
ip: 192.168.0.1
ip: 10.0.0.1

func (IP) Expand

func (ip IP) Expand() string

Expand IP address into canonical form, useful for grep, aligned output and lexical sort.

Example
package main

import (
	"fmt"

	"github.com/gaissmai/go-inet/v2/inet"
)

func main() {
	ip1, _ := inet.ParseIP("192.168.2.1")
	ip2, _ := inet.ParseIP("fffe:db8::")

	fmt.Printf("%q\n", ip1.Expand())
	fmt.Printf("%q\n", ip2.Expand())

}
Output:

"192.168.002.001"
"fffe:0db8:0000:0000:0000:0000:0000:0000"

func (IP) Is4

func (ip IP) Is4() bool

Is4 reports whether ip is an IPv4 address.

There is no Is4in6. IPv4-mapped IPv6 addresses are stripped down to IPv4 otherwise the sort order would be undefined.

func (IP) Is6

func (ip IP) Is6() bool

Is6 reports whether ip is an IPv6 address.

There is no Is4in6. IPv4-mapped IPv6 addresses are stripped down to IPv4 otherwise the sort order would be undefined.

func (IP) IsValid

func (ip IP) IsValid() bool

IsValid reports whether ip is a valid address and not the zero value of the IP type. The zero value is not a valid IP address of any type.

Note that "0.0.0.0" and "::" are not the zero value.

func (IP) Less

func (ip IP) Less(ip2 IP) bool

Less reports whether the ip should sort before ip2. IPv4 addresses sorts always before IPv6 addresses.

Example
package main

import (
	"fmt"
	"sort"

	"github.com/gaissmai/go-inet/v2/inet"
)

func main() {
	s := []string{
		"0.0.0.1",
		"fe80::1",
		"0.0.0.0",
		"127.0.0.1",
		"::",
		"::1",
		"255.255.255.255",
	}
	var ips []inet.IP
	for _, v := range s {
		ip, _ := inet.ParseIP(v)
		ips = append(ips, ip)
	}

	sort.Slice(ips, func(i, j int) bool { return ips[i].Less(ips[j]) })
	for _, ip := range ips {
		fmt.Println(ip)
	}

}
Output:

0.0.0.0
0.0.0.1
127.0.0.1
255.255.255.255
::
::1
fe80::1

func (IP) Reverse

func (ip IP) Reverse() string

Reverse IP address, needed for PTR entries in DNS zone files.

Example
package main

import (
	"fmt"

	"github.com/gaissmai/go-inet/v2/inet"
)

func main() {
	ip1, _ := inet.ParseIP("192.168.2.1")
	ip2, _ := inet.ParseIP("fffe:db8::")

	fmt.Printf("%q\n", ip1.Reverse())
	fmt.Printf("%q\n", ip2.Reverse())

}
Output:

"1.2.168.192"
"0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.e.f.f.f"

func (IP) String

func (ip IP) String() string

String returns the string form of the IP address. It returns one of 3 forms:

"invalid IP"  if ip.IsValid() is false
"127.0.0.1"
"2001:db8::1"

Jump to

Keyboard shortcuts

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