Skip to content

Commit 9db7e30

Browse files
rolandshoemakergopherbot
authored andcommitted
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 golang#75815 Change-Id: I3192f2275ad5c386f5c15006a6716bdb5282919d Reviewed-on: https://go-review.googlesource.com/c/go/+/710375 LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Ethan Lee <[email protected]> Auto-Submit: Roland Shoemaker <[email protected]>
1 parent 8d81028 commit 9db7e30

File tree

2 files changed

+15
-14
lines changed

2 files changed

+15
-14
lines changed

src/net/url/url.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -689,13 +689,13 @@ func parseHost(host string) (string, error) {
689689

690690
// Per RFC 3986, only a host identified by a valid
691691
// IPv6 address can be enclosed by square brackets.
692-
// This excludes any IPv4 or IPv4-mapped addresses.
692+
// This excludes any IPv4, but notably not IPv4-mapped addresses.
693693
addr, err := netip.ParseAddr(unescapedHostname)
694694
if err != nil {
695695
return "", fmt.Errorf("invalid host: %w", err)
696696
}
697-
if addr.Is4() || addr.Is4In6() {
698-
return "", errors.New("invalid IPv6 host")
697+
if addr.Is4() {
698+
return "", errors.New("invalid IP-literal")
699699
}
700700
return "[" + unescapedHostname + "]" + unescapedColonPort, nil
701701
} else if i := strings.LastIndex(host, ":"); i != -1 {

src/net/url/url_test.go

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -726,7 +726,7 @@ var parseRequestURLTests = []struct {
726726
{"https://[2001:db8::1]/path", true}, // compressed IPv6 address with path
727727
{"https://[fe80::1%25eth0]/path?query=1", true}, // link-local with zone, path, and query
728728

729-
{"https://[::ffff:192.0.2.1]", false},
729+
{"https://[::ffff:192.0.2.1]", true},
730730
{"https://[:1] ", false},
731731
{"https://[1:2:3:4:5:6:7:8:9]", false},
732732
{"https://[1::1::1]", false},
@@ -1672,16 +1672,17 @@ func TestParseErrors(t *testing.T) {
16721672
{"cache_object:foo/bar", true},
16731673
{"cache_object/:foo/bar", false},
16741674

1675-
{"http://[192.168.0.1]/", true}, // IPv4 in brackets
1676-
{"http://[192.168.0.1]:8080/", true}, // IPv4 in brackets with port
1677-
{"http://[::ffff:192.168.0.1]/", true}, // IPv4-mapped IPv6 in brackets
1678-
{"http://[::ffff:192.168.0.1]:8080/", true}, // IPv4-mapped IPv6 in brackets with port
1679-
{"http://[::ffff:c0a8:1]/", true}, // IPv4-mapped IPv6 in brackets (hex)
1680-
{"http://[not-an-ip]/", true}, // invalid IP string in brackets
1681-
{"http://[fe80::1%foo]/", true}, // invalid zone format in brackets
1682-
{"http://[fe80::1", true}, // missing closing bracket
1683-
{"http://fe80::1]/", true}, // missing opening bracket
1684-
{"http://[test.com]/", true}, // domain name in brackets
1675+
{"http://[192.168.0.1]/", true}, // IPv4 in brackets
1676+
{"http://[192.168.0.1]:8080/", true}, // IPv4 in brackets with port
1677+
{"http://[::ffff:192.168.0.1]/", false}, // IPv4-mapped IPv6 in brackets
1678+
{"http://[::ffff:192.168.0.1000]/", true}, // Out of range IPv4-mapped IPv6 in brackets
1679+
{"http://[::ffff:192.168.0.1]:8080/", false}, // IPv4-mapped IPv6 in brackets with port
1680+
{"http://[::ffff:c0a8:1]/", false}, // IPv4-mapped IPv6 in brackets (hex)
1681+
{"http://[not-an-ip]/", true}, // invalid IP string in brackets
1682+
{"http://[fe80::1%foo]/", true}, // invalid zone format in brackets
1683+
{"http://[fe80::1", true}, // missing closing bracket
1684+
{"http://fe80::1]/", true}, // missing opening bracket
1685+
{"http://[test.com]/", true}, // domain name in brackets
16851686
}
16861687
for _, tt := range tests {
16871688
u, err := Parse(tt.in)

0 commit comments

Comments
 (0)