From 1978b9d8f987ef83d619d0f76884cb9576f40089 Mon Sep 17 00:00:00 2001 From: Dee Koder Date: Thu, 10 Aug 2017 16:54:19 -0700 Subject: [PATCH] Prevent minio server starting in standalone erasure mode for wrong inputs. (#4700) It is possible at times due to a typo when distributed mode was intended a user might end up starting standalone erasure mode causing confusion. Add code to check this based on some standard heuristic guess work and report an error to the user. Fixes #4686 --- cmd/endpoint.go | 8 +++++++- cmd/endpoint_test.go | 2 ++ cmd/net.go | 9 +++++++++ cmd/net_test.go | 20 ++++++++++++++++++++ 4 files changed, 38 insertions(+), 1 deletion(-) diff --git a/cmd/endpoint.go b/cmd/endpoint.go index ccc2890c8..539ff4b1b 100644 --- a/cmd/endpoint.go +++ b/cmd/endpoint.go @@ -132,6 +132,12 @@ func NewEndpoint(arg string) (ep Endpoint, e error) { return ep, err } } else { + // Only check if the arg is an ip address and ask for scheme since its absent. + // localhost, example.com, any FQDN cannot be disambiguated from a regular file path such as + // /mnt/export1. So we go ahead and start the minio server in FS modes in these cases. + if isHostIPv4(arg) { + return ep, fmt.Errorf("invalid URL endpoint format: missing scheme http or https") + } u = &url.URL{Path: path.Clean(arg)} isLocal = true } @@ -212,7 +218,6 @@ func NewEndpointList(args ...string) (endpoints EndpointList, err error) { return nil, fmt.Errorf("duplicate endpoints found") } uniqueArgs.Add(arg) - endpoints = append(endpoints, endpoint) } @@ -267,6 +272,7 @@ func CreateEndpoints(serverAddr string, args ...string) (string, EndpointList, S localEndpointCount := 0 localServerAddrSet := set.NewStringSet() localPortSet := set.NewStringSet() + for _, endpoint := range endpoints { endpointPathSet.Add(endpoint.Path) if endpoint.IsLocal { diff --git a/cmd/endpoint_test.go b/cmd/endpoint_test.go index ed3fdff8d..e93dd1013 100644 --- a/cmd/endpoint_test.go +++ b/cmd/endpoint_test.go @@ -70,6 +70,7 @@ func TestNewEndpoint(t *testing.T) { {"http://server:8080//", Endpoint{}, -1, fmt.Errorf("empty or root path is not supported in URL endpoint")}, {"http://server:8080/", Endpoint{}, -1, fmt.Errorf("empty or root path is not supported in URL endpoint")}, {"http://server/path", Endpoint{}, -1, fmt.Errorf("lookup server" + errMsg)}, + {"192.168.1.210:9000", Endpoint{}, -1, fmt.Errorf("invalid URL endpoint format: missing scheme http or https")}, } for _, testCase := range testCases { @@ -122,6 +123,7 @@ func TestNewEndpointList(t *testing.T) { {[]string{"ftp://server/d1", "http://server/d2", "http://server/d3", "http://server/d4"}, fmt.Errorf("'ftp://server/d1': invalid URL endpoint format")}, {[]string{"d1", "http://localhost/d2", "d3", "d4"}, fmt.Errorf("mixed style endpoints are not supported")}, {[]string{"http://example.org/d1", "https://example.com/d1", "http://example.net/d1", "https://example.edut/d1"}, fmt.Errorf("mixed scheme is not supported")}, + {[]string{"192.168.1.210:9000/tmp/dir0", "192.168.1.210:9000/tmp/dir1", "192.168.1.210:9000/tmp/dir2", "192.168.110:9000/tmp/dir3"}, fmt.Errorf("'192.168.1.210:9000/tmp/dir0': invalid URL endpoint format: missing scheme http or https")}, } for _, testCase := range testCases { diff --git a/cmd/net.go b/cmd/net.go index 4c73ecc81..b2ed5b311 100644 --- a/cmd/net.go +++ b/cmd/net.go @@ -153,6 +153,15 @@ func getAPIEndpoints(serverAddr string) (apiEndpoints []string) { return apiEndpoints } +// isHostIPv4 - helper for validating if the provided arg is an ip address. +func isHostIPv4(ipAddress string) bool { + host, _, err := net.SplitHostPort(ipAddress) + if err != nil { + host = ipAddress + } + return net.ParseIP(host) != nil +} + // checkPortAvailability - check if given port is already in use. // Note: The check method tries to listen on given port and closes it. // It is possible to have a disconnected client in this tiny window of time. diff --git a/cmd/net_test.go b/cmd/net_test.go index 50d3c1818..4dde1d9b2 100644 --- a/cmd/net_test.go +++ b/cmd/net_test.go @@ -317,3 +317,23 @@ func TestSameLocalAddrs(t *testing.T) { } } } +func TestIsHostIPv4(t *testing.T) { + testCases := []struct { + args string + expectedResult bool + }{ + {"localhost", false}, + {"localhost:9000", false}, + {"example.com", false}, + {"http://192.168.1.0", false}, + {"http://192.168.1.0:9000", false}, + {"192.168.1.0", true}, + } + + for _, testCase := range testCases { + ret := isHostIPv4(testCase.args) + if testCase.expectedResult != ret { + t.Fatalf("expected: %v , got: %v", testCase.expectedResult, ret) + } + } +}