github.com/ruphin/docker@v1.10.1/opts/hosts.go (about)

     1  package opts
     2  
     3  import (
     4  	"fmt"
     5  	"net"
     6  	"net/url"
     7  	"runtime"
     8  	"strconv"
     9  	"strings"
    10  )
    11  
    12  var (
    13  	// DefaultHTTPPort Default HTTP Port used if only the protocol is provided to -H flag e.g. docker daemon -H tcp://
    14  	// TODO Windows. DefaultHTTPPort is only used on Windows if a -H parameter
    15  	// is not supplied. A better longer term solution would be to use a named
    16  	// pipe as the default on the Windows daemon.
    17  	// These are the IANA registered port numbers for use with Docker
    18  	// see http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml?search=docker
    19  	DefaultHTTPPort = 2375 // Default HTTP Port
    20  	// DefaultTLSHTTPPort Default HTTP Port used when TLS enabled
    21  	DefaultTLSHTTPPort = 2376 // Default TLS encrypted HTTP Port
    22  	// DefaultUnixSocket Path for the unix socket.
    23  	// Docker daemon by default always listens on the default unix socket
    24  	DefaultUnixSocket = "/var/run/docker.sock"
    25  	// DefaultTCPHost constant defines the default host string used by docker on Windows
    26  	DefaultTCPHost = fmt.Sprintf("tcp://%s:%d", DefaultHTTPHost, DefaultHTTPPort)
    27  	// DefaultTLSHost constant defines the default host string used by docker for TLS sockets
    28  	DefaultTLSHost = fmt.Sprintf("tcp://%s:%d", DefaultHTTPHost, DefaultTLSHTTPPort)
    29  )
    30  
    31  // ValidateHost validates that the specified string is a valid host and returns it.
    32  func ValidateHost(val string) (string, error) {
    33  	_, err := parseDockerDaemonHost(DefaultTCPHost, DefaultTLSHost, DefaultUnixSocket, "", val)
    34  	if err != nil {
    35  		return val, err
    36  	}
    37  	// Note: unlike most flag validators, we don't return the mutated value here
    38  	//       we need to know what the user entered later (using ParseHost) to adjust for tls
    39  	return val, nil
    40  }
    41  
    42  // ParseHost and set defaults for a Daemon host string
    43  func ParseHost(defaultHost, val string) (string, error) {
    44  	host, err := parseDockerDaemonHost(DefaultTCPHost, DefaultTLSHost, DefaultUnixSocket, defaultHost, val)
    45  	if err != nil {
    46  		return val, err
    47  	}
    48  	return host, nil
    49  }
    50  
    51  // parseDockerDaemonHost parses the specified address and returns an address that will be used as the host.
    52  // Depending of the address specified, will use the defaultTCPAddr or defaultUnixAddr
    53  // defaultUnixAddr must be a absolute file path (no `unix://` prefix)
    54  // defaultTCPAddr must be the full `tcp://host:port` form
    55  func parseDockerDaemonHost(defaultTCPAddr, defaultTLSHost, defaultUnixAddr, defaultAddr, addr string) (string, error) {
    56  	addr = strings.TrimSpace(addr)
    57  	if addr == "" {
    58  		if defaultAddr == defaultTLSHost {
    59  			return defaultTLSHost, nil
    60  		}
    61  		if runtime.GOOS != "windows" {
    62  			return fmt.Sprintf("unix://%s", defaultUnixAddr), nil
    63  		}
    64  		return defaultTCPAddr, nil
    65  	}
    66  	addrParts := strings.Split(addr, "://")
    67  	if len(addrParts) == 1 {
    68  		addrParts = []string{"tcp", addrParts[0]}
    69  	}
    70  
    71  	switch addrParts[0] {
    72  	case "tcp":
    73  		return parseTCPAddr(addrParts[1], defaultTCPAddr)
    74  	case "unix":
    75  		return parseUnixAddr(addrParts[1], defaultUnixAddr)
    76  	case "fd":
    77  		return addr, nil
    78  	default:
    79  		return "", fmt.Errorf("Invalid bind address format: %s", addr)
    80  	}
    81  }
    82  
    83  // parseUnixAddr parses and validates that the specified address is a valid UNIX
    84  // socket address. It returns a formatted UNIX socket address, either using the
    85  // address parsed from addr, or the contents of defaultAddr if addr is a blank
    86  // string.
    87  func parseUnixAddr(addr string, defaultAddr string) (string, error) {
    88  	addr = strings.TrimPrefix(addr, "unix://")
    89  	if strings.Contains(addr, "://") {
    90  		return "", fmt.Errorf("Invalid proto, expected unix: %s", addr)
    91  	}
    92  	if addr == "" {
    93  		addr = defaultAddr
    94  	}
    95  	return fmt.Sprintf("unix://%s", addr), nil
    96  }
    97  
    98  // parseTCPAddr parses and validates that the specified address is a valid TCP
    99  // address. It returns a formatted TCP address, either using the address parsed
   100  // from tryAddr, or the contents of defaultAddr if tryAddr is a blank string.
   101  // tryAddr is expected to have already been Trim()'d
   102  // defaultAddr must be in the full `tcp://host:port` form
   103  func parseTCPAddr(tryAddr string, defaultAddr string) (string, error) {
   104  	if tryAddr == "" || tryAddr == "tcp://" {
   105  		return defaultAddr, nil
   106  	}
   107  	addr := strings.TrimPrefix(tryAddr, "tcp://")
   108  	if strings.Contains(addr, "://") || addr == "" {
   109  		return "", fmt.Errorf("Invalid proto, expected tcp: %s", tryAddr)
   110  	}
   111  
   112  	defaultAddr = strings.TrimPrefix(defaultAddr, "tcp://")
   113  	defaultHost, defaultPort, err := net.SplitHostPort(defaultAddr)
   114  	if err != nil {
   115  		return "", err
   116  	}
   117  	// url.Parse fails for trailing colon on IPv6 brackets on Go 1.5, but
   118  	// not 1.4. See https://github.com/golang/go/issues/12200 and
   119  	// https://github.com/golang/go/issues/6530.
   120  	if strings.HasSuffix(addr, "]:") {
   121  		addr += defaultPort
   122  	}
   123  
   124  	u, err := url.Parse("tcp://" + addr)
   125  	if err != nil {
   126  		return "", err
   127  	}
   128  
   129  	host, port, err := net.SplitHostPort(u.Host)
   130  	if err != nil {
   131  		return "", fmt.Errorf("Invalid bind address format: %s", tryAddr)
   132  	}
   133  
   134  	if host == "" {
   135  		host = defaultHost
   136  	}
   137  	if port == "" {
   138  		port = defaultPort
   139  	}
   140  	p, err := strconv.Atoi(port)
   141  	if err != nil && p == 0 {
   142  		return "", fmt.Errorf("Invalid bind address format: %s", tryAddr)
   143  	}
   144  
   145  	return fmt.Sprintf("tcp://%s%s", net.JoinHostPort(host, port), u.Path), nil
   146  }