From 761722395d9565455f67f8ab49e5d1afbf12a856 Mon Sep 17 00:00:00 2001
From: allencloud <allen.sun@daocloud.io>
Date: Mon, 17 Oct 2016 23:37:10 +0800
Subject: [PATCH] validate network and endpoint name more strictly

Signed-off-by: allencloud <allen.sun@daocloud.io>
---
 libnetwork/config/config.go      | 18 +++++++++++++-----
 libnetwork/config/config_test.go |  9 ++++++---
 libnetwork/controller.go         |  4 ++--
 libnetwork/error.go              |  2 +-
 libnetwork/network.go            |  5 +++--
 5 files changed, 25 insertions(+), 13 deletions(-)

diff --git a/libnetwork/config/config.go b/libnetwork/config/config.go
index 8c3af13b22..a6ebd05284 100644
--- a/libnetwork/config/config.go
+++ b/libnetwork/config/config.go
@@ -1,6 +1,8 @@
 package config
 
 import (
+	"fmt"
+	"regexp"
 	"strings"
 
 	"github.com/BurntSushi/toml"
@@ -15,6 +17,12 @@ import (
 	"github.com/docker/libnetwork/osl"
 )
 
+// RestrictedNameChars collects the characters allowed to represent a network or endpoint name.
+const restrictedNameChars = `[a-zA-Z0-9][a-zA-Z0-9_.-]`
+
+// RestrictedNamePattern is a regular expression to validate names against the collection of restricted characters.
+var restrictedNamePattern = regexp.MustCompile(`^/?` + restrictedNameChars + `+$`)
+
 // Config encapsulates configurations of various Libnetwork components
 type Config struct {
 	Daemon          DaemonCfg
@@ -223,12 +231,12 @@ func (c *Config) ProcessOptions(options ...Option) {
 	}
 }
 
-// IsValidName validates configuration objects supported by libnetwork
-func IsValidName(name string) bool {
-	if strings.TrimSpace(name) == "" {
-		return false
+// ValidateName validates configuration objects supported by libnetwork
+func ValidateName(name string) error {
+	if !restrictedNamePattern.MatchString(name) {
+		return fmt.Errorf("%s includes invalid characters, only %q are allowed", name, restrictedNameChars)
 	}
-	return true
+	return nil
 }
 
 // OptionLocalKVProvider function returns an option setter for kvstore provider
diff --git a/libnetwork/config/config_test.go b/libnetwork/config/config_test.go
index ade9f746cd..a5feebac58 100644
--- a/libnetwork/config/config_test.go
+++ b/libnetwork/config/config_test.go
@@ -46,13 +46,16 @@ func TestOptionsLabels(t *testing.T) {
 }
 
 func TestValidName(t *testing.T) {
-	if !IsValidName("test") {
+	if err := ValidateName("test"); err != nil {
 		t.Fatal("Name validation fails for a name that must be accepted")
 	}
-	if IsValidName("") {
+	if err := ValidateName(""); err == nil {
 		t.Fatal("Name validation succeeds for a case when it is expected to fail")
 	}
-	if IsValidName("   ") {
+	if err := ValidateName("   "); err == nil {
+		t.Fatal("Name validation succeeds for a case when it is expected to fail")
+	}
+	if err := ValidateName("<>$$^"); err == nil {
 		t.Fatal("Name validation succeeds for a case when it is expected to fail")
 	}
 }
diff --git a/libnetwork/controller.go b/libnetwork/controller.go
index 914287a5be..c86df6686f 100644
--- a/libnetwork/controller.go
+++ b/libnetwork/controller.go
@@ -626,8 +626,8 @@ func (c *controller) NewNetwork(networkType, name string, id string, options ...
 		}
 	}
 
-	if !config.IsValidName(name) {
-		return nil, ErrInvalidName(name)
+	if err := config.ValidateName(name); err != nil {
+		return nil, ErrInvalidName(err.Error())
 	}
 
 	if id == "" {
diff --git a/libnetwork/error.go b/libnetwork/error.go
index d1291f1db6..6c41bf166a 100644
--- a/libnetwork/error.go
+++ b/libnetwork/error.go
@@ -69,7 +69,7 @@ func (ii ErrInvalidID) Error() string {
 func (ii ErrInvalidID) BadRequest() {}
 
 // ErrInvalidName is returned when a query-by-name or resource create method is
-// invoked with an empty name parameter
+// invoked with an invalid name parameter
 type ErrInvalidName string
 
 func (in ErrInvalidName) Error() string {
diff --git a/libnetwork/network.go b/libnetwork/network.go
index 8a068d22e9..eebb46ffb2 100644
--- a/libnetwork/network.go
+++ b/libnetwork/network.go
@@ -848,8 +848,9 @@ func (n *network) addEndpoint(ep *endpoint) error {
 
 func (n *network) CreateEndpoint(name string, options ...EndpointOption) (Endpoint, error) {
 	var err error
-	if !config.IsValidName(name) {
-		return nil, ErrInvalidName(name)
+
+	if err = config.ValidateName(name); err != nil {
+		return nil, ErrInvalidName(err.Error())
 	}
 
 	if _, err = n.EndpointByName(name); err == nil {