Support IPv6 hosts for postgres connections (#7168)

Fixes #7145
This commit is contained in:
Praveen raj Mani
2019-05-03 17:31:33 +05:30
committed by Nitish Tiwari
parent 4b858b562a
commit 998f01fadc
5 changed files with 235 additions and 127 deletions

View File

@@ -118,7 +118,6 @@ func ParseHost(s string) (*Host, error) {
if !strings.Contains(err.Error(), "missing port in address") {
return nil, err
}
host = s
portStr = ""
} else {
@@ -129,11 +128,23 @@ func ParseHost(s string) (*Host, error) {
isPortSet = true
}
if i := strings.Index(host, "%"); i > -1 {
host = host[:i]
if host != "" {
host, err = trimIPv6(host)
if err != nil {
return nil, err
}
}
if !isValidHost(host) {
// IPv6 requires a link-local address on every network interface.
// `%interface` should be preserved.
trimmedHost := host
if i := strings.LastIndex(trimmedHost, "%"); i > -1 {
// `%interface` can be skipped for validity check though.
trimmedHost = trimmedHost[:i]
}
if !isValidHost(trimmedHost) {
return nil, errors.New("invalid hostname")
}
@@ -143,3 +154,15 @@ func ParseHost(s string) (*Host, error) {
IsPortSet: isPortSet,
}, nil
}
// IPv6 can be embedded with square brackets.
func trimIPv6(host string) (string, error) {
// `missing ']' in host` error is already handled in `SplitHostPort`
if host[len(host)-1] == ']' {
if host[0] != '[' {
return "", errors.New("missing '[' in host")
}
return host[1:][:len(host)-2], nil
}
return host, nil
}

View File

@@ -138,6 +138,13 @@ func TestHostUnmarshalJSON(t *testing.T) {
{[]byte(`"play-minio-io"`), &Host{"play-minio-io", 0, false}, false},
{[]byte(`"play--min.io"`), &Host{"play--min.io", 0, false}, false},
{[]byte(`":9000"`), nil, true},
{[]byte(`"[fe80::8097:76eb:b397:e067%wlp2s0]"`), &Host{"fe80::8097:76eb:b397:e067%wlp2s0", 0, false}, false},
{[]byte(`"[fe80::8097:76eb:b397:e067]:9000"`), &Host{"fe80::8097:76eb:b397:e067", 9000, true}, false},
{[]byte(`"fe80::8097:76eb:b397:e067%wlp2s0"`), nil, true},
{[]byte(`"fe80::8097:76eb:b397:e067%wlp2s0]"`), nil, true},
{[]byte(`"[fe80::8097:76eb:b397:e067%wlp2s0"`), nil, true},
{[]byte(`"[[fe80::8097:76eb:b397:e067%wlp2s0]]"`), nil, true},
{[]byte(`"[[fe80::8097:76eb:b397:e067%wlp2s0"`), nil, true},
{[]byte(`"play:"`), nil, true},
{[]byte(`"play::"`), nil, true},
{[]byte(`"play:90000"`), nil, true},
@@ -207,3 +214,31 @@ func TestParseHost(t *testing.T) {
}
}
}
func TestTrimIPv6(t *testing.T) {
testCases := []struct {
IP string
expectedIP string
expectErr bool
}{
{"[fe80::8097:76eb:b397:e067%wlp2s0]", "fe80::8097:76eb:b397:e067%wlp2s0", false},
{"fe80::8097:76eb:b397:e067%wlp2s0]", "fe80::8097:76eb:b397:e067%wlp2s0", true},
{"[fe80::8097:76eb:b397:e067%wlp2s0]]", "fe80::8097:76eb:b397:e067%wlp2s0]", false},
{"[[fe80::8097:76eb:b397:e067%wlp2s0]]", "[fe80::8097:76eb:b397:e067%wlp2s0]", false},
}
for i, testCase := range testCases {
ip, err := trimIPv6(testCase.IP)
expectErr := (err != nil)
if expectErr != testCase.expectErr {
t.Fatalf("test %v: error: expected: %v, got: %v", i+1, testCase.expectErr, expectErr)
}
if !testCase.expectErr {
if ip != testCase.expectedIP {
t.Fatalf("test %v: IP: expected: %#v, got: %#v", i+1, testCase.expectedIP, ip)
}
}
}
}