mirror of
https://github.com/golang/go
synced 2024-11-17 04:24:47 -07:00
net/netip: return an error from ParsePrefix with IPv6 zone input
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>
This commit is contained in:
parent
9b90838712
commit
ae9ce822ff
@ -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 {
|
||||
|
@ -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},
|
||||
|
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user