Documentation
¶
Overview ¶
Package iprange parses IPv4/IPv6 addresses from strings in IP range format and handles interval mathematics between multiple IP ranges.
The following IP range formats are supported:
172.18.0.1 fd00::1 172.18.0.0/24 fd00::/64 172.18.0.1-10 fd00::1-a 172.18.0.1-172.18.1.10 fd00::1-fd00::1:a
It takes a set of IP range strings, and returns a list of start-end IP address pairs, which can then be automatically extended and normalized, for instance:
v4Ranges, err := iprange.Parse("172.18.0.1", "172.18.0.0/24") // √
v6Ranges, err := iprange.Parse("fd00::1", "fd00::/64") // √
invalid, err := iprange.Parse("Invalid IP range string") // ×
dual, err := iprange.Parse("172.18.0.1", "fd00::/64") // ×
When parsing an invalid IP range string, error errInvalidIPRangeFormat will be returned, and dual-stack IP ranges are not allowed because this approach is too complex and confusing. Use the following functions to assert the errors:
func IsInvalidIPRangeFormat(err error) bool func IsDualStackIPRanges(err error) bool
Use the interval methods of IPRanges to calculate the union, difference or intersection of two IPRanges. They do not change the original parameters (rr and rs), just calculate, and return the results.
func (rr *IPRanges) Union(rs *IPRanges) *IPRanges func (rr *IPRanges) Diff(rs *IPRanges) *IPRanges func (rr *IPRanges) Intersect(rs *IPRanges) *IPRanges
However, do not attempt to perform calculations on two IPRanges with different IP versions, it won't work:
res := v4Ranges.Diff(v6Ranges) // res will be equal to v4Ranges.
The IPRanges can be converted into individual net.IP through its own iterator. Continuously call the method Next() to iterate through the IPRanges until nil is returned:
iter := ranges.Iterator()
for {
ip := iter.Next()
if ip == nil {
break
}
// Do someting.
}
Finally, the inspiration for writing this package comes from
CNI plugins: https://github.com/containernetworking/plugins malfunkt/iprange: https://github.com/malfunkt/iprange
both of which are great!
Index ¶
- Constants
- func IsDualStackIPRanges(err error) bool
- func IsInvalidIPRangeFormat(err error) bool
- type IPRanges
- func (rr *IPRanges) Contains(ip net.IP) bool
- func (rr *IPRanges) Diff(rs *IPRanges) *IPRanges
- func (rr1 *IPRanges) Equal(rr2 *IPRanges) bool
- func (rr *IPRanges) Intersect(rs *IPRanges) *IPRanges
- func (rr *IPRanges) Iterator() *rangesIterator
- func (rr *IPRanges) Merge() *IPRanges
- func (rr1 *IPRanges) MergeEqual(rr2 *IPRanges) bool
- func (rr *IPRanges) Size() *big.Int
- func (rr *IPRanges) String() string
- func (rr *IPRanges) Union(rs *IPRanges) *IPRanges
- func (rr *IPRanges) Version() family
Examples ¶
Constants ¶
const ( Unknow family = iota IPv4 IPv6 )
Standard IP version 4 or 6. Unknown represents an invalid IP version, which is commonly used in the zero value of an IPRanges struct or to distinguish an invalid xIP.
Variables ¶
This section is empty.
Functions ¶
func IsDualStackIPRanges ¶
IsDualStackIPRanges asserts whether the err is errDualStackIPRanges.
func IsInvalidIPRangeFormat ¶
IsInvalidIPRangeFormat asserts whether the err is errInvalidIPRangeFormat.
Types ¶
type IPRanges ¶
type IPRanges struct {
// contains filtered or unexported fields
}
IPRanges is a set of ipRange that uses the starting and ending IP addresses to represent any IP range of any size. The following IP range formats are valid:
172.18.0.1 fd00::1 172.18.0.0/24 fd00::/64 172.18.0.1-10 fd00::1-a 172.18.0.1-172.18.1.10 fd00::1-fd00::1:a
Dual-stack IP ranges are not allowed, The IP version of an IPRanges can only be IPv4, IPv6, or unknown (zero value).
func Parse ¶
Parse parses a set of IP range format strings as IPRanges, the slice of ipRange with the same IP version, which records the starting and ending IP addresses.
The error errInvalidIPRangeFormat wiil be returned when one of IP range string is invalid. And dual-stack IP ranges are not allowed, the error errDualStackIPRanges occurs when parsing a set of IP range strings, where there are both IPv4 and IPv6 addresses.
Example ¶
package main
import (
"fmt"
"log"
"github.com/iiiceoo/iprange"
)
func main() {
v4Ranges, err := iprange.Parse("172.18.0.1", "172.18.0.0/24")
if err != nil {
log.Fatalf("error parsing IP ranges: %v", err)
}
v6Ranges, err := iprange.Parse("fd00::1-a", "fd00::1-fd00::1:a")
if err != nil {
log.Fatalf("error parsing IP ranges: %v", err)
}
fmt.Println(v4Ranges)
fmt.Println(v6Ranges)
}
Output: [172.18.0.1 172.18.0.0-172.18.0.255] [fd00::1-fd00::a fd00::1-fd00::1:a]
func (*IPRanges) Contains ¶
Contains reports whether IPRanges rr contain net.IP ip. If rr is IPv4 and ip is IPv6, then it is also considered not contained, and vice versa.
Example ¶
package main
import (
"fmt"
"log"
"net"
"github.com/iiiceoo/iprange"
)
func main() {
ranges, err := iprange.Parse("172.18.0.0/24")
if err != nil {
log.Fatalf("error parsing IP ranges: %v", err)
}
fmt.Println(ranges.Contains(net.ParseIP("172.18.0.1")))
fmt.Println(ranges.Contains(net.ParseIP("172.19.0.1")))
fmt.Println(ranges.Contains(net.ParseIP("fd00::1")))
}
Output: true false false
func (*IPRanges) Diff ¶
Diff calculates the difference of IPRanges rr and rs with the same IP version. The result is always merged (ordered and deduplicated).
do: [172.18.0.20-30, 172.18.0.1-25] - [172.18.0.5-25] res: [172.18.0.1-4, 172.18.0.26-30]
Example ¶
package main
import (
"fmt"
"log"
"github.com/iiiceoo/iprange"
)
func main() {
ranges1, err := iprange.Parse("172.18.0.20-30", "172.18.0.1-25")
if err != nil {
log.Fatalf("error parsing IP ranges: %v", err)
}
ranges2, err := iprange.Parse("172.18.0.5-25")
if err != nil {
log.Fatalf("error parsing IP ranges: %v", err)
}
fmt.Println(ranges1.Diff(ranges2))
}
Output: [172.18.0.1-172.18.0.4 172.18.0.26-172.18.0.30]
func (*IPRanges) Equal ¶
Equal reports whether IPRanges rr1 is equal to rr2.
Example ¶
package main
import (
"fmt"
"log"
"github.com/iiiceoo/iprange"
)
func main() {
ranges1, err := iprange.Parse("172.18.0.0/24")
if err != nil {
log.Fatalf("error parsing IP ranges: %v", err)
}
ranges2, err := iprange.Parse("172.18.0.100-255", "172.18.0.0-200")
if err != nil {
log.Fatalf("error parsing IP ranges: %v", err)
}
fmt.Println(ranges1.Equal(ranges2))
fmt.Println(ranges1.Equal(ranges1))
}
Output: false true
func (*IPRanges) Intersect ¶
Intersect calculates the intersection of IPRanges rr and rs with the same IP version. The result is always merged (ordered and deduplicated).
do: [172.18.0.20-30, 172.18.0.1-25] ∩ [172.18.0.5-25] res: [172.18.0.5-25]
Example ¶
package main
import (
"fmt"
"log"
"github.com/iiiceoo/iprange"
)
func main() {
ranges1, err := iprange.Parse("172.18.0.20-30", "172.18.0.1-25")
if err != nil {
log.Fatalf("error parsing IP ranges: %v", err)
}
ranges2, err := iprange.Parse("172.18.0.5-25")
if err != nil {
log.Fatalf("error parsing IP ranges: %v", err)
}
fmt.Println(ranges1.Intersect(ranges2))
}
Output: [172.18.0.5-172.18.0.25]
func (*IPRanges) Iterator ¶
func (rr *IPRanges) Iterator() *rangesIterator
Iterator generates a new iterator for IPRanges rr, which stores the merged IP ranges (ordered and deduplicated) and always points the cursor to the first IP address. Call Next to iterate through the IPRanges.
Example ¶
package main
import (
"fmt"
"log"
"github.com/iiiceoo/iprange"
)
func main() {
ranges, err := iprange.Parse("172.18.0.1-3")
if err != nil {
log.Fatalf("error parsing IP ranges: %v", err)
}
iter := ranges.Iterator()
for {
ip := iter.Next()
if ip == nil {
break
}
fmt.Println(ip)
}
}
Output: 172.18.0.1 172.18.0.2 172.18.0.3
func (*IPRanges) Merge ¶
Merge merges the duplicate parts of multiple ipRanges in rr and sort them by their respective starting xIP.
Example ¶
package main
import (
"fmt"
"log"
"github.com/iiiceoo/iprange"
)
func main() {
ranges, err := iprange.Parse("172.18.1.1", "172.18.0.100-200", "172.18.0.1-150")
if err != nil {
log.Fatalf("error parsing IP ranges: %v", err)
}
fmt.Println(ranges)
fmt.Println(ranges.Merge())
}
Output: [172.18.1.1 172.18.0.100-172.18.0.200 172.18.0.1-172.18.0.150] [172.18.0.1-172.18.0.200 172.18.1.1]
func (*IPRanges) MergeEqual ¶
MergeEqual reports whether IPRanges rr1 is equal to rr2, but both rr1 and rr2 are pre-merged, which means they are both ordered and deduplicated.
Example ¶
package main
import (
"fmt"
"log"
"github.com/iiiceoo/iprange"
)
func main() {
ranges1, err := iprange.Parse("172.18.0.0/24")
if err != nil {
log.Fatalf("error parsing IP ranges: %v", err)
}
ranges2, err := iprange.Parse("172.18.0.100-255", "172.18.0.0-200")
if err != nil {
log.Fatalf("error parsing IP ranges: %v", err)
}
fmt.Println(ranges1.MergeEqual(ranges2))
}
Output: true
func (*IPRanges) Size ¶ added in v0.0.2
Size calculates the total number of IP addresses that pertain to IPRanges rr.
Example ¶
package main
import (
"fmt"
"log"
"github.com/iiiceoo/iprange"
)
func main() {
ranges, err := iprange.Parse("172.18.0.0/24")
if err != nil {
log.Fatalf("error parsing IP ranges: %v", err)
}
zero := iprange.IPRanges{}
fmt.Println(ranges.Size())
fmt.Println(zero.Size())
}
Output: 256 0
func (*IPRanges) Union ¶
Union calculates the union of IPRanges rr and rs with the same IP version. The result is always merged (ordered and deduplicated).
do: [172.18.0.20-30, 172.18.0.1-25] U [172.18.0.5-25] res: [172.18.0.1-30]
Example ¶
package main
import (
"fmt"
"log"
"github.com/iiiceoo/iprange"
)
func main() {
ranges1, err := iprange.Parse("172.18.0.20-30", "172.18.0.1-25")
if err != nil {
log.Fatalf("error parsing IP ranges: %v", err)
}
ranges2, err := iprange.Parse("172.18.0.5-25")
if err != nil {
log.Fatalf("error parsing IP ranges: %v", err)
}
fmt.Println(ranges1.Union(ranges2))
}
Output: [172.18.0.1-172.18.0.30]
func (*IPRanges) Version ¶ added in v0.0.4
func (rr *IPRanges) Version() family
Version returns the IP version of IPRanges:
1: IPv4 2: IPv6 0: zero value of IPRanges
Do not compare family with a regular int value, which is confusing. Use predefined const such as IPv4, IPv6, or Unknown.
Example ¶
package main
import (
"fmt"
"log"
"github.com/iiiceoo/iprange"
)
func main() {
v4Ranges, err := iprange.Parse("172.18.0.1", "172.18.0.0/24")
if err != nil {
log.Fatalf("error parsing IP ranges: %v", err)
}
v6Ranges, err := iprange.Parse("fd00::1-a", "fd00::1-fd00::1:a")
if err != nil {
log.Fatalf("error parsing IP ranges: %v", err)
}
zero := iprange.IPRanges{}
fmt.Println(v4Ranges.Version())
fmt.Println(v6Ranges.Version())
fmt.Println(zero.Version())
}
Output: IPv4 IPv6 Unknow