2024-07-12 13:30:21 +00:00
|
|
|
package nebula
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"net"
|
|
|
|
"net/netip"
|
2024-12-17 10:33:19 +00:00
|
|
|
"testing"
|
2024-07-12 13:30:21 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// IPNet is the CIDR of a nebula network.
|
|
|
|
type IPNet net.IPNet
|
|
|
|
|
2024-12-17 10:33:19 +00:00
|
|
|
// MustParseIPNet is a test helper for parsing a string into an IPNet.
|
|
|
|
func MustParseIPNet(t *testing.T, str string) IPNet {
|
|
|
|
var ipNet IPNet
|
|
|
|
if err := ipNet.UnmarshalText([]byte(str)); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
return ipNet
|
|
|
|
}
|
|
|
|
|
2024-07-12 13:30:21 +00:00
|
|
|
// UnmarshalText parses and validates an IPNet from a text string.
|
|
|
|
func (n *IPNet) UnmarshalText(b []byte) error {
|
|
|
|
str := string(b)
|
|
|
|
_, subnet, err := net.ParseCIDR(str)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if cstr := subnet.String(); cstr != str {
|
|
|
|
return fmt.Errorf("IPNet is not given in its canonical form of %q", cstr)
|
|
|
|
}
|
|
|
|
|
|
|
|
if !subnet.IP.IsPrivate() {
|
|
|
|
return fmt.Errorf("IPNet is not in a private IP range")
|
|
|
|
}
|
|
|
|
|
|
|
|
*n = IPNet(*subnet)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (n IPNet) String() string {
|
|
|
|
return (*net.IPNet)(&n).String()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (n IPNet) MarshalText() ([]byte, error) {
|
|
|
|
return []byte(n.String()), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// FirstAddr returns the first IP address in the subnet.
|
|
|
|
func (n IPNet) FirstAddr() netip.Addr {
|
|
|
|
return netip.MustParseAddr(n.IP.String()).Next()
|
|
|
|
}
|