Description
EDIT 2022-03-29: Go is documented to comply with https://www.rfc-editor.org/rfc/rfc4291.html#section-2.3 which makes no mention of IPv6 prefix + zone syntax.
Leaving the rest of this message alone for historical context.
What version of Go are you using (go version
)?
Go 1.18, tip
Does this issue reproduce with the latest release?
Yes
What operating system and processor architecture are you using (go env
)?
linux/amd64, but n/a.
What did you do?
Attempted to parse a link-local IPv6 address prefix with zone: fe80::%2/64
https://go.dev/play/p/EeZwl0aah3q
What did you expect to see?
net.ParseCIDR
: no error, valid*net.IPNet
with zonenetip.ParsePrefix
: no error, valid*netip.Prefix
with zone
What did you see instead?
net.ParseCIDR
: error:invalid CIDR address: fe80::%2/64
netip.ParsePrefix
: no error,fe80::/64
returned with zone stripped
This was brought to my attention by a blog and associated thread on reddit:
https://old.reddit.com/r/golang/comments/tkf9rm/a_tiny_flaw_in_gos_netip_design/
https://adam-p.ca/blog/2022/03/go-netip-flaw/
While working on inet.af/netaddr
which ultimately became net/netip
, I don't believe we were able to find any evidence of an IPv6 prefix with associated zone. However, that evidence turned up today while I was doing further research:
RFC 4007: IPv6 Scoped Address Architecture, March 2005
https://datatracker.ietf.org/doc/html/rfc4007#section-11.7
[11.7] Combinations of Delimiter Characters
There are other kinds of delimiter characters defined for IPv6
addresses. In this subsection, we describe how they should be
combined with the format for non-global addresses.
The IPv6 addressing architecture [[1](https://datatracker.ietf.org/doc/html/rfc4007#ref-1)] also defines the syntax of IPv6
prefixes. If the address portion of a prefix is non-global and its
scope zone should be disambiguated, the address portion SHOULD be in
the format. For example, a link-local prefix fe80::/64 on the second
link can be represented as follows:
fe80::%2/64
Note that the prefix fe80::%2/64
should be considered valid, and thus both the current behaviors of net.ParseCIDR
and netip.ParsePrefix
are incorrect. I believe this was an oversight on my part during the development of inet.af/netaddr
, as I was the primary user of IPv6 link-local addresses with zones. However, I have not run into a need to use IPv6 prefixes with zones as of yet.
Either way, I believe both functions should be updated to handle this case as appropriate.
In addition, RFC6874, Section 1 (https://datatracker.ietf.org/doc/html/rfc6874#section-1) says:
It should be noted that
zone identifiers have purely local meaning within the node in which
they are defined, often being the same as IPv6 interface names. They
are completely meaningless for any other node. Today, they are
meaningful only when attached to addresses with less than global
scope, but it is possible that other uses might be defined in the
future.
I don't believe the status quo has changed in the 9 years since that RFC, and would suggest that we do one of the following:
- parse prefix zones for any type of IPv6 address prefix (link-local is the only current "less than global scope" user, but zones could also be used for other address types later)
- parse prefix zones for only link-local IPv6 address prefixes; that is, if
ip.IsLinkLocalUnicast() == true
or IP is contained infe80::/10
EDIT: as a data point, since net/netip
already accepts the following, even given the RFC text above, I am in favor of option 1.
fmt.Println(netip.MustParseAddr("2001:db8::1%eth0"))
// 2001:db8::1%eth0
I do think this should be fixed for link-local addresses at a minimum though. If we agree this should be done, I'm happy to fix this in both net
and net/netip
.