Refactor so that the Host flag validation doesn't destroy the user's input,
and then post process the flags when we know the TLS options
Signed-off-by: Sven Dowideit <SvenDowideit@home.org.au>
| ... | ... |
@@ -106,13 +106,6 @@ func NewDockerCli(in io.ReadCloser, out, err io.Writer, clientFlags *cli.ClientF |
| 106 | 106 |
switch len(hosts) {
|
| 107 | 107 |
case 0: |
| 108 | 108 |
defaultHost := os.Getenv("DOCKER_HOST")
|
| 109 |
- if defaultHost == "" {
|
|
| 110 |
- defaultHost = opts.DefaultHost |
|
| 111 |
- } |
|
| 112 |
- defaultHost, err := opts.ValidateHost(defaultHost) |
|
| 113 |
- if err != nil {
|
|
| 114 |
- return err |
|
| 115 |
- } |
|
| 116 | 109 |
hosts = []string{defaultHost}
|
| 117 | 110 |
case 1: |
| 118 | 111 |
// only accept one host to talk to |
| ... | ... |
@@ -120,6 +113,15 @@ func NewDockerCli(in io.ReadCloser, out, err io.Writer, clientFlags *cli.ClientF |
| 120 | 120 |
return errors.New("Please specify only one -H")
|
| 121 | 121 |
} |
| 122 | 122 |
|
| 123 |
+ defaultHost := opts.DefaultTCPHost |
|
| 124 |
+ if clientFlags.Common.TLSOptions != nil {
|
|
| 125 |
+ defaultHost = opts.DefaultTLSHost |
|
| 126 |
+ } |
|
| 127 |
+ var e error |
|
| 128 |
+ if hosts[0], e = opts.ParseHost(defaultHost, hosts[0]); e != nil {
|
|
| 129 |
+ return e |
|
| 130 |
+ } |
|
| 131 |
+ |
|
| 123 | 132 |
protoAddrParts := strings.SplitN(hosts[0], "://", 2) |
| 124 | 133 |
cli.proto, cli.addr = protoAddrParts[0], protoAddrParts[1] |
| 125 | 134 |
|
| ... | ... |
@@ -169,9 +169,6 @@ func (cli *DaemonCli) CmdDaemon(args ...string) error {
|
| 169 | 169 |
daemonFlags.ParseFlags(args, true) |
| 170 | 170 |
commonFlags.PostParse() |
| 171 | 171 |
|
| 172 |
- if len(commonFlags.Hosts) == 0 {
|
|
| 173 |
- commonFlags.Hosts = []string{opts.DefaultHost}
|
|
| 174 |
- } |
|
| 175 | 172 |
if commonFlags.TrustKey == "" {
|
| 176 | 173 |
commonFlags.TrustKey = filepath.Join(getDaemonConfDir(), defaultTrustKeyFile) |
| 177 | 174 |
} |
| ... | ... |
@@ -212,6 +209,7 @@ func (cli *DaemonCli) CmdDaemon(args ...string) error {
|
| 212 | 212 |
} |
| 213 | 213 |
serverConfig = setPlatformServerConfig(serverConfig, cli.Config) |
| 214 | 214 |
|
| 215 |
+ defaultHost := opts.DefaultHost |
|
| 215 | 216 |
if commonFlags.TLSOptions != nil {
|
| 216 | 217 |
if !commonFlags.TLSOptions.InsecureSkipVerify {
|
| 217 | 218 |
// server requires and verifies client's certificate |
| ... | ... |
@@ -222,6 +220,14 @@ func (cli *DaemonCli) CmdDaemon(args ...string) error {
|
| 222 | 222 |
logrus.Fatal(err) |
| 223 | 223 |
} |
| 224 | 224 |
serverConfig.TLSConfig = tlsConfig |
| 225 |
+ defaultHost = opts.DefaultTLSHost |
|
| 226 |
+ } |
|
| 227 |
+ |
|
| 228 |
+ for i := 0; i < len(commonFlags.Hosts); i++ {
|
|
| 229 |
+ var err error |
|
| 230 |
+ if commonFlags.Hosts[i], err = opts.ParseHost(defaultHost, commonFlags.Hosts[i]); err != nil {
|
|
| 231 |
+ logrus.Fatalf("error parsing -H %s : %v", commonFlags.Hosts[i], err)
|
|
| 232 |
+ } |
|
| 225 | 233 |
} |
| 226 | 234 |
for _, protoAddr := range commonFlags.Hosts {
|
| 227 | 235 |
protoAddrParts := strings.SplitN(protoAddr, "://", 2) |
| ... | ... |
@@ -82,13 +82,17 @@ then it is trivial for someone to gain root access to the host where the |
| 82 | 82 |
daemon is running. |
| 83 | 83 |
|
| 84 | 84 |
Similarly, the Docker client can use `-H` to connect to a custom port. |
| 85 |
+The Docker client will default to connecting to `unix:///var/run/docker.sock` |
|
| 86 |
+on Linux, and `tcp://127.0.0.1:2376` on Windows. |
|
| 85 | 87 |
|
| 86 | 88 |
`-H` accepts host and port assignment in the following format: |
| 87 | 89 |
|
| 88 |
- tcp://[host][:port][path] or unix://path |
|
| 90 |
+ tcp://[host]:[port][path] or unix://path |
|
| 89 | 91 |
|
| 90 | 92 |
For example: |
| 91 | 93 |
|
| 94 |
+- `tcp://` -> TCP connection to `127.0.0.1` on either port `2376` when TLS encryption |
|
| 95 |
+ is on, or port `2375` when communication is in plain text. |
|
| 92 | 96 |
- `tcp://host:2375` -> TCP connection on |
| 93 | 97 |
host:2375 |
| 94 | 98 |
- `tcp://host:2375/path` -> TCP connection on |
| ... | ... |
@@ -101,7 +105,7 @@ when no `-H` was passed in. |
| 101 | 101 |
|
| 102 | 102 |
`-H` also accepts short form for TCP bindings: |
| 103 | 103 |
|
| 104 |
- host[:port] or :port |
|
| 104 |
+ `host:` or `host:port` or `:port` |
|
| 105 | 105 |
|
| 106 | 106 |
Run Docker in daemon mode: |
| 107 | 107 |
|
| ... | ... |
@@ -265,9 +265,11 @@ Docker uses a bridge to manage container networking. By default, UFW drops all |
| 265 | 265 |
forwarding traffic. As a result, for Docker to run when UFW is |
| 266 | 266 |
enabled, you must set UFW's forwarding policy appropriately. |
| 267 | 267 |
|
| 268 |
-Also, UFW's default set of rules denies all incoming traffic. If you want to be able |
|
| 269 |
-to reach your containers from another host then you should also allow incoming |
|
| 270 |
-connections on the Docker port (default `2375`). |
|
| 268 |
+Also, UFW's default set of rules denies all incoming traffic. If you want to |
|
| 269 |
+reach your containers from another host allow incoming connections on the Docker |
|
| 270 |
+port. The Docker port defaults to `2376` if TLS is enabled or `2375` when it is |
|
| 271 |
+not. If TLS is not enabled, communication is unencrypted. By default, Docker |
|
| 272 |
+runs without TLS enabled. |
|
| 271 | 273 |
|
| 272 | 274 |
To configure UFW and allow incoming connections on the Docker port: |
| 273 | 275 |
|
| ... | ... |
@@ -18,7 +18,7 @@ or execute `docker help`: |
| 18 | 18 |
docker daemon [ --help | ... ] |
| 19 | 19 |
docker [ --help | -v | --version ] |
| 20 | 20 |
|
| 21 |
- -H, --host=[]: The socket(s) to bind to in daemon mode, specified using one or more tcp://host:port, unix:///path/to/socket, fd://* or fd://socketfd. |
|
| 21 |
+ -H, --host=[]: The socket(s) to talk to the Docker daemon in the format of tcp://host:port/path, unix:///path/to/socket, fd://* or fd://socketfd. |
|
| 22 | 22 |
|
| 23 | 23 |
A self-sufficient runtime for Linux containers. |
| 24 | 24 |
|
| ... | ... |
@@ -36,10 +36,12 @@ To see the man page for a command run **man docker <command>**. |
| 36 | 36 |
**-D**, **--debug**=*true*|*false* |
| 37 | 37 |
Enable debug mode. Default is false. |
| 38 | 38 |
|
| 39 |
-**-H**, **--host**=[unix:///var/run/docker.sock]: tcp://[host:port] to bind or |
|
| 39 |
+**-H**, **--host**=[unix:///var/run/docker.sock]: tcp://[host]:[port][path] to bind or |
|
| 40 | 40 |
unix://[/path/to/socket] to use. |
| 41 | 41 |
The socket(s) to bind to in daemon mode specified using one or more |
| 42 |
- tcp://host:port, unix:///path/to/socket, fd://* or fd://socketfd. |
|
| 42 |
+ tcp://host:port/path, unix:///path/to/socket, fd://* or fd://socketfd. |
|
| 43 |
+ If the tcp port is not specified, then it will default to either `2375` when |
|
| 44 |
+ `--tls` is off, or `2376` when `--tls` is on, or `--tlsverify` is specified. |
|
| 43 | 45 |
|
| 44 | 46 |
**-l**, **--log-level**="*debug*|*info*|*warn*|*error*|*fatal*"" |
| 45 | 47 |
Set the logging level. Default is `info`. |
| ... | ... |
@@ -17,16 +17,23 @@ var ( |
| 17 | 17 |
domainRegexp = regexp.MustCompile(`^(:?(:?[a-zA-Z0-9]|(:?[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9]))(:?\.(:?[a-zA-Z0-9]|(:?[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])))*)\.?\s*$`) |
| 18 | 18 |
// DefaultHTTPHost Default HTTP Host used if only port is provided to -H flag e.g. docker daemon -H tcp://:8080 |
| 19 | 19 |
DefaultHTTPHost = "127.0.0.1" |
| 20 |
+ |
|
| 20 | 21 |
// DefaultHTTPPort Default HTTP Port used if only the protocol is provided to -H flag e.g. docker daemon -H tcp:// |
| 21 | 22 |
// TODO Windows. DefaultHTTPPort is only used on Windows if a -H parameter |
| 22 | 23 |
// is not supplied. A better longer term solution would be to use a named |
| 23 | 24 |
// pipe as the default on the Windows daemon. |
| 25 |
+ // These are the IANA registered port numbers for use with Docker |
|
| 26 |
+ // see http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml?search=docker |
|
| 24 | 27 |
DefaultHTTPPort = 2375 // Default HTTP Port |
| 28 |
+ // DefaultTLSHTTPPort Default HTTP Port used when TLS enabled |
|
| 29 |
+ DefaultTLSHTTPPort = 2376 // Default TLS encrypted HTTP Port |
|
| 25 | 30 |
// DefaultUnixSocket Path for the unix socket. |
| 26 | 31 |
// Docker daemon by default always listens on the default unix socket |
| 27 | 32 |
DefaultUnixSocket = "/var/run/docker.sock" |
| 28 | 33 |
// DefaultTCPHost constant defines the default host string used by docker on Windows |
| 29 | 34 |
DefaultTCPHost = fmt.Sprintf("tcp://%s:%d", DefaultHTTPHost, DefaultHTTPPort)
|
| 35 |
+ // DefaultTLSHost constant defines the default host string used by docker for TLS sockets |
|
| 36 |
+ DefaultTLSHost = fmt.Sprintf("tcp://%s:%d", DefaultHTTPHost, DefaultTLSHTTPPort)
|
|
| 30 | 37 |
) |
| 31 | 38 |
|
| 32 | 39 |
// ListOpts holds a list of values and a validation function. |
| ... | ... |
@@ -335,6 +342,17 @@ func ValidateLabel(val string) (string, error) {
|
| 335 | 335 |
|
| 336 | 336 |
// ValidateHost validates that the specified string is a valid host and returns it. |
| 337 | 337 |
func ValidateHost(val string) (string, error) {
|
| 338 |
+ _, err := parsers.ParseDockerDaemonHost(DefaultTCPHost, DefaultUnixSocket, val) |
|
| 339 |
+ if err != nil {
|
|
| 340 |
+ return val, err |
|
| 341 |
+ } |
|
| 342 |
+ // Note: unlike most flag validators, we don't return the mutated value here |
|
| 343 |
+ // we need to know what the user entered later (using ParseHost) to adjust for tls |
|
| 344 |
+ return val, nil |
|
| 345 |
+} |
|
| 346 |
+ |
|
| 347 |
+// ParseHost and set defaults for a Daemon host string |
|
| 348 |
+func ParseHost(defaultHTTPHost, val string) (string, error) {
|
|
| 338 | 349 |
host, err := parsers.ParseDockerDaemonHost(DefaultTCPHost, DefaultUnixSocket, val) |
| 339 | 350 |
if err != nil {
|
| 340 | 351 |
return val, err |
| ... | ... |
@@ -3,6 +3,7 @@ package opts |
| 3 | 3 |
import ( |
| 4 | 4 |
"fmt" |
| 5 | 5 |
"os" |
| 6 |
+ "runtime" |
|
| 6 | 7 |
"strings" |
| 7 | 8 |
"testing" |
| 8 | 9 |
) |
| ... | ... |
@@ -423,7 +424,7 @@ func TestValidateLabel(t *testing.T) {
|
| 423 | 423 |
} |
| 424 | 424 |
} |
| 425 | 425 |
|
| 426 |
-func TestValidateHost(t *testing.T) {
|
|
| 426 |
+func TestParseHost(t *testing.T) {
|
|
| 427 | 427 |
invalid := map[string]string{
|
| 428 | 428 |
"anything": "Invalid bind address format: anything", |
| 429 | 429 |
"something with spaces": "Invalid bind address format: something with spaces", |
| ... | ... |
@@ -433,7 +434,14 @@ func TestValidateHost(t *testing.T) {
|
| 433 | 433 |
"tcp://invalid": "Invalid bind address format: invalid", |
| 434 | 434 |
"tcp://invalid:port": "Invalid bind address format: invalid:port", |
| 435 | 435 |
} |
| 436 |
+ const defaultHTTPHost = "tcp://127.0.0.1:2375" |
|
| 437 |
+ var defaultHOST = "unix:///var/run/docker.sock" |
|
| 438 |
+ |
|
| 439 |
+ if runtime.GOOS == "windows" {
|
|
| 440 |
+ defaultHOST = defaultHTTPHost |
|
| 441 |
+ } |
|
| 436 | 442 |
valid := map[string]string{
|
| 443 |
+ "": defaultHOST, |
|
| 437 | 444 |
"fd://": "fd://", |
| 438 | 445 |
"fd://something": "fd://something", |
| 439 | 446 |
"tcp://host:": "tcp://host:2375", |
| ... | ... |
@@ -450,12 +458,12 @@ func TestValidateHost(t *testing.T) {
|
| 450 | 450 |
} |
| 451 | 451 |
|
| 452 | 452 |
for value, errorMessage := range invalid {
|
| 453 |
- if _, err := ValidateHost(value); err == nil || err.Error() != errorMessage {
|
|
| 453 |
+ if _, err := ParseHost(defaultHTTPHost, value); err == nil || err.Error() != errorMessage {
|
|
| 454 | 454 |
t.Fatalf("Expected an error for %v with [%v], got [%v]", value, errorMessage, err)
|
| 455 | 455 |
} |
| 456 | 456 |
} |
| 457 | 457 |
for value, expected := range valid {
|
| 458 |
- if actual, err := ValidateHost(value); err != nil || actual != expected {
|
|
| 458 |
+ if actual, err := ParseHost(defaultHTTPHost, value); err != nil || actual != expected {
|
|
| 459 | 459 |
t.Fatalf("Expected for %v [%v], got [%v, %v]", value, expected, actual, err)
|
| 460 | 460 |
} |
| 461 | 461 |
} |