mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
net/url: allow IP-literals with IPv4-mapped IPv6 addresses
The security fix we applied in CL709857 was overly broad. It applied rules from RFC 2732, which disallowed IPv4-mapped IPv6 addresses, but these were later allowed in RFC 3986, which is the canonical URI syntax RFC. Revert the portion of CL709857 which restricted IPv4-mapped addresses, and update the related tests. Fixes #75815 Change-Id: I3192f2275ad5c386f5c15006a6716bdb5282919d Reviewed-on: https://go-review.googlesource.com/c/go/+/710375 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Ethan Lee <ethanalee@google.com> Auto-Submit: Roland Shoemaker <roland@golang.org>
This commit is contained in:
parent
8d810286b3
commit
9db7e30bb4
2 changed files with 15 additions and 14 deletions
|
|
@ -689,13 +689,13 @@ func parseHost(host string) (string, error) {
|
||||||
|
|
||||||
// Per RFC 3986, only a host identified by a valid
|
// Per RFC 3986, only a host identified by a valid
|
||||||
// IPv6 address can be enclosed by square brackets.
|
// IPv6 address can be enclosed by square brackets.
|
||||||
// This excludes any IPv4 or IPv4-mapped addresses.
|
// This excludes any IPv4, but notably not IPv4-mapped addresses.
|
||||||
addr, err := netip.ParseAddr(unescapedHostname)
|
addr, err := netip.ParseAddr(unescapedHostname)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("invalid host: %w", err)
|
return "", fmt.Errorf("invalid host: %w", err)
|
||||||
}
|
}
|
||||||
if addr.Is4() || addr.Is4In6() {
|
if addr.Is4() {
|
||||||
return "", errors.New("invalid IPv6 host")
|
return "", errors.New("invalid IP-literal")
|
||||||
}
|
}
|
||||||
return "[" + unescapedHostname + "]" + unescapedColonPort, nil
|
return "[" + unescapedHostname + "]" + unescapedColonPort, nil
|
||||||
} else if i := strings.LastIndex(host, ":"); i != -1 {
|
} else if i := strings.LastIndex(host, ":"); i != -1 {
|
||||||
|
|
|
||||||
|
|
@ -726,7 +726,7 @@ var parseRequestURLTests = []struct {
|
||||||
{"https://[2001:db8::1]/path", true}, // compressed IPv6 address with path
|
{"https://[2001:db8::1]/path", true}, // compressed IPv6 address with path
|
||||||
{"https://[fe80::1%25eth0]/path?query=1", true}, // link-local with zone, path, and query
|
{"https://[fe80::1%25eth0]/path?query=1", true}, // link-local with zone, path, and query
|
||||||
|
|
||||||
{"https://[::ffff:192.0.2.1]", false},
|
{"https://[::ffff:192.0.2.1]", true},
|
||||||
{"https://[:1] ", false},
|
{"https://[:1] ", false},
|
||||||
{"https://[1:2:3:4:5:6:7:8:9]", false},
|
{"https://[1:2:3:4:5:6:7:8:9]", false},
|
||||||
{"https://[1::1::1]", false},
|
{"https://[1::1::1]", false},
|
||||||
|
|
@ -1672,16 +1672,17 @@ func TestParseErrors(t *testing.T) {
|
||||||
{"cache_object:foo/bar", true},
|
{"cache_object:foo/bar", true},
|
||||||
{"cache_object/:foo/bar", false},
|
{"cache_object/:foo/bar", false},
|
||||||
|
|
||||||
{"http://[192.168.0.1]/", true}, // IPv4 in brackets
|
{"http://[192.168.0.1]/", true}, // IPv4 in brackets
|
||||||
{"http://[192.168.0.1]:8080/", true}, // IPv4 in brackets with port
|
{"http://[192.168.0.1]:8080/", true}, // IPv4 in brackets with port
|
||||||
{"http://[::ffff:192.168.0.1]/", true}, // IPv4-mapped IPv6 in brackets
|
{"http://[::ffff:192.168.0.1]/", false}, // IPv4-mapped IPv6 in brackets
|
||||||
{"http://[::ffff:192.168.0.1]:8080/", true}, // IPv4-mapped IPv6 in brackets with port
|
{"http://[::ffff:192.168.0.1000]/", true}, // Out of range IPv4-mapped IPv6 in brackets
|
||||||
{"http://[::ffff:c0a8:1]/", true}, // IPv4-mapped IPv6 in brackets (hex)
|
{"http://[::ffff:192.168.0.1]:8080/", false}, // IPv4-mapped IPv6 in brackets with port
|
||||||
{"http://[not-an-ip]/", true}, // invalid IP string in brackets
|
{"http://[::ffff:c0a8:1]/", false}, // IPv4-mapped IPv6 in brackets (hex)
|
||||||
{"http://[fe80::1%foo]/", true}, // invalid zone format in brackets
|
{"http://[not-an-ip]/", true}, // invalid IP string in brackets
|
||||||
{"http://[fe80::1", true}, // missing closing bracket
|
{"http://[fe80::1%foo]/", true}, // invalid zone format in brackets
|
||||||
{"http://fe80::1]/", true}, // missing opening bracket
|
{"http://[fe80::1", true}, // missing closing bracket
|
||||||
{"http://[test.com]/", true}, // domain name in brackets
|
{"http://fe80::1]/", true}, // missing opening bracket
|
||||||
|
{"http://[test.com]/", true}, // domain name in brackets
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
u, err := Parse(tt.in)
|
u, err := Parse(tt.in)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue