From 87a3b178363111616d67de3cb944e9f073ec9d3d Mon Sep 17 00:00:00 2001 From: Martin Greber Date: Thu, 23 Nov 2023 19:34:38 +1000 Subject: [PATCH] pkg/net: replace net with net/netip This replaces the go net package with net/netip as the latter is a better alternative and supports IPv6 checks. This shouldn't cause any API changes or user-visible breakage, although note that a few error strings are changing since we now expose net/netip errors from net/netip rather than net. Updates #2614. Closes #2706 as merged as of commit 1dfc0e78. Signed-off-by: Martin Greber Change-Id: I064f2c995cdc4f6ecd313709f55c966a4094ea17 Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/1173735 TryBot-Result: CUEcueckoo Unity-Result: CUE porcuepine Reviewed-by: Roger Peppe --- pkg/net/host.go | 2 +- pkg/net/ip.go | 72 +++++++++++++++++++++----------------- pkg/net/testdata/gen.txtar | 4 +-- 3 files changed, 42 insertions(+), 36 deletions(-) diff --git a/pkg/net/host.go b/pkg/net/host.go index 70be5f2b6a1..aef0ad9918e 100644 --- a/pkg/net/host.go +++ b/pkg/net/host.go @@ -56,7 +56,7 @@ func JoinHostPort(host, port cue.Value) (string, error) { switch host.Kind() { case cue.ListKind: ipdata := netGetIP(host) - if len(ipdata) != 4 && len(ipdata) != 16 { + if !ipdata.IsValid() { err = fmt.Errorf("invalid host %s", host) } hostStr = ipdata.String() diff --git a/pkg/net/ip.go b/pkg/net/ip.go index 4fbb6179d23..09684a7b076 100644 --- a/pkg/net/ip.go +++ b/pkg/net/ip.go @@ -17,7 +17,7 @@ package net import ( "fmt" - "net" + "net/netip" "cuelang.org/go/cue" ) @@ -28,76 +28,81 @@ const ( IPv6len = 16 ) -func netGetIP(ip cue.Value) (goip net.IP) { +func netGetIP(ip cue.Value) (goip netip.Addr) { switch ip.Kind() { case cue.StringKind: s, err := ip.String() if err != nil { - return nil + return netip.Addr{} } - goip := net.ParseIP(s) - if goip == nil { - return nil + goip, err := netip.ParseAddr(s) + if err != nil { + return netip.Addr{} } return goip case cue.BytesKind: b, err := ip.Bytes() if err != nil { - return nil + return netip.Addr{} } - goip := net.ParseIP(string(b)) - if goip == nil { - return nil + goip, err := netip.ParseAddr(string(b)) + if err != nil { + return netip.Addr{} } return goip case cue.ListKind: iter, err := ip.List() if err != nil { - return nil + return netip.Addr{} } + var bytes []byte for iter.Next() { v, err := iter.Value().Int64() if err != nil { - return nil + return netip.Addr{} } if v < 0 || 255 < v { - return nil + return netip.Addr{} } - goip = append(goip, byte(v)) + bytes = append(bytes, byte(v)) + } + goip, ok := netip.AddrFromSlice(bytes) + if !ok { + return netip.Addr{} } return goip default: // TODO: return canonical invalid type. - return nil + return netip.Addr{} } } -func netGetIPCIDR(ip cue.Value) (gonet *net.IPNet, err error) { +func netGetIPCIDR(ip cue.Value) (gonet *netip.Prefix, err error) { switch ip.Kind() { case cue.StringKind: s, err := ip.String() if err != nil { return nil, err } - _, gonet, err := net.ParseCIDR(s) + cidr, err := netip.ParsePrefix(s) if err != nil { return nil, err } - return gonet, nil + return &cidr, nil case cue.BytesKind: b, err := ip.Bytes() if err != nil { return nil, err } - _, gonet, err := net.ParseCIDR(string(b)) + cidr, err := netip.ParsePrefix(string(b)) if err != nil { return nil, err } - return gonet, nil + return &cidr, nil default: // TODO: return canonical invalid type. @@ -111,14 +116,14 @@ func netGetIPCIDR(ip cue.Value) (gonet *net.IPNet, err error) { // If s is not a valid textual representation of an IP address, // ParseIP returns nil. func ParseIP(s string) ([]uint, error) { - goip := net.ParseIP(s) - if goip == nil { + goip, err := netip.ParseAddr(s) + if err != nil { return nil, fmt.Errorf("invalid IP address %q", s) } - return netToList(goip), nil + return netToList(goip.AsSlice()), nil } -func netToList(ip net.IP) []uint { +func netToList(ip []byte) []uint { a := make([]uint, len(ip)) for i, p := range ip { a[i] = uint(p) @@ -131,7 +136,7 @@ func netToList(ip net.IP) []uint { // The address may be a string or list of bytes. func IPv4(ip cue.Value) bool { // TODO: convert to native CUE. - return netGetIP(ip).To4() != nil + return netGetIP(ip).Is4() } // IP reports whether s is a valid IPv4 or IPv6 address. @@ -139,7 +144,7 @@ func IPv4(ip cue.Value) bool { // The address may be a string or list of bytes. func IP(ip cue.Value) bool { // TODO: convert to native CUE. - return netGetIP(ip) != nil + return netGetIP(ip).IsValid() } // IPCIDR reports whether ip is a valid IPv4 or IPv6 address with CIDR subnet notation. @@ -196,24 +201,25 @@ func UnspecifiedIP(ip cue.Value) bool { // 4-byte representation. func ToIP4(ip cue.Value) ([]uint, error) { ipdata := netGetIP(ip) - if ipdata == nil { + if !ipdata.IsValid() { return nil, fmt.Errorf("invalid IP %q", ip) } - ipv4 := ipdata.To4() - if ipv4 == nil { + if !ipdata.Is4() { return nil, fmt.Errorf("cannot convert %q to IPv4", ipdata) } - return netToList(ipv4), nil + as4 := ipdata.As4() + return netToList(as4[:]), nil } // ToIP16 converts a given IP address, which may be a string or a list, to its // 16-byte representation. func ToIP16(ip cue.Value) ([]uint, error) { ipdata := netGetIP(ip) - if ipdata == nil { + if !ipdata.IsValid() { return nil, fmt.Errorf("invalid IP %q", ip) } - return netToList(ipdata), nil + as16 := ipdata.As16() + return netToList(as16[:]), nil } // IPString returns the string form of the IP address ip. It returns one of 4 forms: @@ -224,7 +230,7 @@ func ToIP16(ip cue.Value) ([]uint, error) { // - the hexadecimal form of ip, without punctuation, if no other cases apply func IPString(ip cue.Value) (string, error) { ipdata := netGetIP(ip) - if ipdata == nil { + if !ipdata.IsValid() { return "", fmt.Errorf("invalid IP %q", ip) } return ipdata.String(), nil diff --git a/pkg/net/testdata/gen.txtar b/pkg/net/testdata/gen.txtar index aa96db0c25d..acefc71702f 100644 --- a/pkg/net/testdata/gen.txtar +++ b/pkg/net/testdata/gen.txtar @@ -37,7 +37,7 @@ t7: error in call to net.JoinHostPort: invalid host [192, 30, 4]: t13: invalid value "ff02::1:3" (does not satisfy net.IPv4): ./in.cue:15:6 ./in.cue:15:19 -t20: error in call to net.IPCIDR: invalid CIDR address: 172.16.12.3: +t20: error in call to net.IPCIDR: netip.ParsePrefix("172.16.12.3"): no '/': ./in.cue:22:6 Result: @@ -60,7 +60,7 @@ t16: [127, 0, 0, 1] t17: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 127, 0, 0, 1] t18: true t19: true -t20: _|_ // t20: error in call to net.IPCIDR: invalid CIDR address: 172.16.12.3 +t20: _|_ // t20: error in call to net.IPCIDR: netip.ParsePrefix("172.16.12.3"): no '/' t21: "foo%2Fbar" t22: "foo/bar" t23: "f%25o"