]> Cypherpunks repositories - gostls13.git/commitdiff
net/netip: return an error from ParsePrefix with IPv6 zone input
authorMatt Layher <mdlayher@gmail.com>
Tue, 29 Mar 2022 14:42:58 +0000 (10:42 -0400)
committerMatt Layher <mdlayher@gmail.com>
Tue, 29 Mar 2022 15:43:06 +0000 (15:43 +0000)
net.ParseCIDR already rejects input in the form of 2001:db8::%a/32, but
netip.ParsePrefix previously accepted the input and silently dropped the
zone. Make the two consistent by always returning an error if an IPv6
zone is present in CIDR input for ParsePrefix.

Fixes #51899.

Change-Id: Iee7d8d4a5161e0b54a4ee1bd68b02c1a287ff399
Reviewed-on: https://go-review.googlesource.com/c/go/+/396299
Trust: Matt Layher <mdlayher@gmail.com>
Run-TryBot: Matt Layher <mdlayher@gmail.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Damien Neil <dneil@google.com>
Trust: Damien Neil <dneil@google.com>

src/net/netip/netip.go
src/net/netip/netip_pkg_test.go
src/net/netip/netip_test.go

index 1cf75fb5a1ff60df6ead5931ade71da20904dc36..893eeea7f0de624f86495f5628cca4194ce4247f 100644 (file)
@@ -1290,6 +1290,8 @@ func (p Prefix) IsSingleIP() bool { return p.bits != 0 && int(p.bits) == p.ip.Bi
 // ParsePrefix parses s as an IP address prefix.
 // The string can be in the form "192.168.1.0/24" or "2001:db8::/32",
 // the CIDR notation defined in RFC 4632 and RFC 4291.
+// IPv6 zones are not permitted in prefixes, and an error will be returned if a
+// zone is present.
 //
 // Note that masked address bits are not zeroed. Use Masked for that.
 func ParsePrefix(s string) (Prefix, error) {
@@ -1301,6 +1303,11 @@ func ParsePrefix(s string) (Prefix, error) {
        if err != nil {
                return Prefix{}, errors.New("netip.ParsePrefix(" + strconv.Quote(s) + "): " + err.Error())
        }
+       // IPv6 zones are not allowed: https://go.dev/issue/51899
+       if ip.Is6() && ip.z != z6noz {
+               return Prefix{}, errors.New("netip.ParsePrefix(" + strconv.Quote(s) + "): IPv6 zones cannot be present in a prefix")
+       }
+
        bitsStr := s[i+1:]
        bits, err := strconv.Atoi(bitsStr)
        if err != nil {
index f5cd9ee86d83bae81c6ccc4b60a2b062599684b7..677f523e6d9667cfe18769da6dc13b5c62a8fd39 100644 (file)
@@ -160,9 +160,9 @@ func TestPrefixContains(t *testing.T) {
                {mustPrefix("::1/127"), mustIP("::2"), false},
                {mustPrefix("::1/128"), mustIP("::1"), true},
                {mustPrefix("::1/127"), mustIP("::2"), false},
-               // zones support
-               {mustPrefix("::1%a/128"), mustIP("::1"), true},    // prefix zones are stripped...
-               {mustPrefix("::1%a/128"), mustIP("::1%a"), false}, // but ip zones are not
+               // Zones ignored: https://go.dev/issue/51899
+               {Prefix{mustIP("1.2.3.4").WithZone("a"), 32}, mustIP("1.2.3.4"), true},
+               {Prefix{mustIP("::1").WithZone("a"), 128}, mustIP("::1"), true},
                // invalid IP
                {mustPrefix("::1/0"), Addr{}, false},
                {mustPrefix("1.2.3.4/0"), Addr{}, false},
index a72390fd5b08ecfb4f096ce324ec2386b085600b..c2811c47030638d2e1cff42b81c9e8b5b9ea9637 100644 (file)
@@ -421,8 +421,8 @@ func TestPrefixMarshalTextString(t *testing.T) {
                {mustPrefix("1.2.3.4/24"), "1.2.3.4/24"},
                {mustPrefix("fd7a:115c:a1e0:ab12:4843:cd96:626b:430b/118"), "fd7a:115c:a1e0:ab12:4843:cd96:626b:430b/118"},
                {mustPrefix("::ffff:c000:0280/96"), "::ffff:192.0.2.128/96"},
-               {mustPrefix("::ffff:c000:0280%eth0/37"), "::ffff:192.0.2.128/37"}, // Zone should be stripped
                {mustPrefix("::ffff:192.168.140.255/8"), "::ffff:192.168.140.255/8"},
+               {PrefixFrom(mustIP("::ffff:c000:0280").WithZone("eth0"), 37), "::ffff:192.0.2.128/37"}, // Zone should be stripped
        }
        for i, tt := range tests {
                if got := tt.in.String(); got != tt.want {
@@ -448,7 +448,7 @@ func TestPrefixMarshalUnmarshalBinary(t *testing.T) {
                {mustPrefix("1.2.3.4/24"), 4 + 1},
                {mustPrefix("fd7a:115c:a1e0:ab12:4843:cd96:626b:430b/118"), 16 + 1},
                {mustPrefix("::ffff:c000:0280/96"), 16 + 1},
-               {mustPrefix("::ffff:c000:0280%eth0/37"), 16 + 1}, // Zone should be stripped
+               {PrefixFrom(mustIP("::ffff:c000:0280").WithZone("eth0"), 37), 16 + 1}, // Zone should be stripped
        }
        tests = append(tests,
                testCase{PrefixFrom(tests[0].prefix.Addr(), 33), tests[0].wantSize},
@@ -901,25 +901,25 @@ func TestPrefixMasking(t *testing.T) {
                        {
                                ip:   mustIP(fmt.Sprintf("2001:db8::1%s", zone)),
                                bits: 32,
-                               p:    mustPrefix(fmt.Sprintf("2001:db8::%s/32", zone)),
+                               p:    mustPrefix("2001:db8::/32"),
                                ok:   true,
                        },
                        {
                                ip:   mustIP(fmt.Sprintf("fe80::dead:beef:dead:beef%s", zone)),
                                bits: 96,
-                               p:    mustPrefix(fmt.Sprintf("fe80::dead:beef:0:0%s/96", zone)),
+                               p:    mustPrefix("fe80::dead:beef:0:0/96"),
                                ok:   true,
                        },
                        {
                                ip:   mustIP(fmt.Sprintf("aaaa::%s", zone)),
                                bits: 4,
-                               p:    mustPrefix(fmt.Sprintf("a000::%s/4", zone)),
+                               p:    mustPrefix("a000::/4"),
                                ok:   true,
                        },
                        {
                                ip:   mustIP(fmt.Sprintf("::%s", zone)),
                                bits: 63,
-                               p:    mustPrefix(fmt.Sprintf("::%s/63", zone)),
+                               p:    mustPrefix("::/63"),
                                ok:   true,
                        },
                }
@@ -1047,26 +1047,6 @@ func TestPrefixMarshalUnmarshal(t *testing.T) {
        }
 }
 
-func TestPrefixMarshalUnmarshalZone(t *testing.T) {
-       orig := `"fe80::1cc0:3e8c:119f:c2e1%ens18/128"`
-       unzoned := `"fe80::1cc0:3e8c:119f:c2e1/128"`
-
-       var p Prefix
-       if err := json.Unmarshal([]byte(orig), &p); err != nil {
-               t.Fatalf("failed to unmarshal: %v", err)
-       }
-
-       pb, err := json.Marshal(p)
-       if err != nil {
-               t.Fatalf("failed to marshal: %v", err)
-       }
-
-       back := string(pb)
-       if back != unzoned {
-               t.Errorf("Marshal = %q; want %q", back, unzoned)
-       }
-}
-
 func TestPrefixUnmarshalTextNonZero(t *testing.T) {
        ip := mustPrefix("fe80::/64")
        if err := ip.UnmarshalText([]byte("xxx")); err == nil {
@@ -1222,14 +1202,6 @@ func TestPrefix(t *testing.T) {
                        contains:    mustIPs("2001:db8::1"),
                        notContains: mustIPs("fe80::1"),
                },
-               {
-                       prefix:      "::%0/00/80",
-                       ip:          mustIP("::"),
-                       bits:        80,
-                       str:         "::/80",
-                       contains:    mustIPs("::"),
-                       notContains: mustIPs("ff::%0/00", "ff::%1/23", "::%0/00", "::%1/23"),
-               },
        }
        for _, test := range tests {
                t.Run(test.prefix, func(t *testing.T) {
@@ -1348,6 +1320,15 @@ func TestParsePrefixError(t *testing.T) {
                        prefix: "2001::/129",
                        errstr: "out of range",
                },
+               // Zones are not allowed: https://go.dev/issue/51899
+               {
+                       prefix: "1.1.1.0%a/24",
+                       errstr: "unexpected character",
+               },
+               {
+                       prefix: "2001:db8::%a/32",
+                       errstr: "zones cannot be present",
+               },
        }
        for _, test := range tests {
                t.Run(test.prefix, func(t *testing.T) {