]>
Commit | Line | Data |
---|---|---|
9b12e4fe JC |
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 | } |