diff --git a/docker/daemon.go b/docker/daemon.go index 804775667c..a6f9d5cdcd 100644 --- a/docker/daemon.go +++ b/docker/daemon.go @@ -250,11 +250,24 @@ func (cli *DaemonCli) CmdDaemon(args ...string) error { if len(protoAddrParts) != 2 { logrus.Fatalf("bad format %s, expected PROTO://ADDR", protoAddr) } - l, err := listeners.Init(protoAddrParts[0], protoAddrParts[1], serverConfig.SocketGroup, serverConfig.TLSConfig) + + proto := protoAddrParts[0] + addr := protoAddrParts[1] + + // It's a bad idea to bind to TCP without tlsverify. + if proto == "tcp" && (serverConfig.TLSConfig == nil || serverConfig.TLSConfig.ClientAuth != tls.RequireAndVerifyClientCert) { + logrus.Warn("[!] DON'T BIND ON ANY IP ADDRESS WITHOUT setting -tlsverify IF YOU DON'T KNOW WHAT YOU'RE DOING [!]") + } + l, err := listeners.Init(proto, addr, serverConfig.SocketGroup, serverConfig.TLSConfig) if err != nil { logrus.Fatal(err) } - + // If we're binding to a TCP port, make sure that a container doesn't try to use it. + if proto == "tcp" { + if err := allocateDaemonPort(addr); err != nil { + logrus.Fatal(err) + } + } logrus.Debugf("Listener created for HTTP on %s (%s)", protoAddrParts[0], protoAddrParts[1]) api.Accept(protoAddrParts[1], l...) } diff --git a/docker/daemon_unix.go b/docker/daemon_unix.go index 809a756334..b1c0bfe24b 100644 --- a/docker/daemon_unix.go +++ b/docker/daemon_unix.go @@ -4,9 +4,11 @@ package main import ( "fmt" + "net" "os" "os/signal" "path/filepath" + "strconv" "syscall" "github.com/Sirupsen/logrus" @@ -15,6 +17,7 @@ import ( "github.com/docker/docker/libcontainerd" "github.com/docker/docker/pkg/mflag" "github.com/docker/docker/pkg/system" + "github.com/docker/libnetwork/portallocator" ) const defaultDaemonConfigFile = "/etc/docker/daemon.json" @@ -87,3 +90,32 @@ func (cli *DaemonCli) getPlatformRemoteOptions() []libcontainerd.RemoteOption { func (cli *DaemonCli) getLibcontainerdRoot() string { return filepath.Join(cli.Config.ExecRoot, "libcontainerd") } + +// allocateDaemonPort ensures that there are no containers +// that try to use any port allocated for the docker server. +func allocateDaemonPort(addr string) error { + host, port, err := net.SplitHostPort(addr) + if err != nil { + return err + } + + intPort, err := strconv.Atoi(port) + if err != nil { + return err + } + + var hostIPs []net.IP + if parsedIP := net.ParseIP(host); parsedIP != nil { + hostIPs = append(hostIPs, parsedIP) + } else if hostIPs, err = net.LookupIP(host); err != nil { + return fmt.Errorf("failed to lookup %s address in host specification", host) + } + + pa := portallocator.Get() + for _, hostIP := range hostIPs { + if _, err := pa.RequestPort(hostIP, "tcp", intPort); err != nil { + return fmt.Errorf("failed to allocate daemon listening port %d (err: %v)", intPort, err) + } + } + return nil +} diff --git a/docker/daemon_windows.go b/docker/daemon_windows.go index aca59101d6..5d4b10c8ea 100644 --- a/docker/daemon_windows.go +++ b/docker/daemon_windows.go @@ -69,3 +69,7 @@ func (cli *DaemonCli) getPlatformRemoteOptions() []libcontainerd.RemoteOption { func (cli *DaemonCli) getLibcontainerdRoot() string { return "" } + +func allocateDaemonPort(addr string) error { + return nil +} diff --git a/pkg/listeners/listeners.go b/pkg/listeners/listeners.go deleted file mode 100644 index 7823054a54..0000000000 --- a/pkg/listeners/listeners.go +++ /dev/null @@ -1,24 +0,0 @@ -package listeners - -import ( - "crypto/tls" - "net" - - "github.com/Sirupsen/logrus" - "github.com/docker/go-connections/sockets" -) - -func initTCPSocket(addr string, tlsConfig *tls.Config) (l net.Listener, err error) { - if tlsConfig == nil || tlsConfig.ClientAuth != tls.RequireAndVerifyClientCert { - // TODO: Move this outside pkg/listeners since it's Docker-specific. - // ... and slightly scary. - logrus.Warn("/!\\ DON'T BIND ON ANY IP ADDRESS WITHOUT setting -tlsverify IF YOU DON'T KNOW WHAT YOU'RE DOING /!\\") - } - if l, err = sockets.NewTCPSocket(addr, tlsConfig); err != nil { - return nil, err - } - if err := allocateDaemonPort(addr); err != nil { - return nil, err - } - return -} diff --git a/pkg/listeners/listeners_unix.go b/pkg/listeners/listeners_unix.go index 29dd8c6570..fddd3a8ed8 100644 --- a/pkg/listeners/listeners_unix.go +++ b/pkg/listeners/listeners_unix.go @@ -11,19 +11,22 @@ import ( "github.com/Sirupsen/logrus" "github.com/coreos/go-systemd/activation" "github.com/docker/go-connections/sockets" - "github.com/docker/libnetwork/portallocator" ) // Init creates new listeners for the server. -func Init(proto, addr, socketGroup string, tlsConfig *tls.Config) (ls []net.Listener, err error) { +// TODO: Clean up the fact that socketGroup and tlsConfig aren't always used. +func Init(proto, addr, socketGroup string, tlsConfig *tls.Config) ([]net.Listener, error) { + ls := []net.Listener{} + switch proto { case "fd": - ls, err = listenFD(addr, tlsConfig) + fds, err := listenFD(addr, tlsConfig) if err != nil { return nil, err } + ls = append(ls, fds...) case "tcp": - l, err := initTCPSocket(addr, tlsConfig) + l, err := sockets.NewTCPSocket(addr, tlsConfig) if err != nil { return nil, err } @@ -38,7 +41,7 @@ func Init(proto, addr, socketGroup string, tlsConfig *tls.Config) (ls []net.List return nil, fmt.Errorf("invalid protocol format: %q", proto) } - return + return ls, nil } // listenFD returns the specified socket activated files as a slice of @@ -89,34 +92,3 @@ func listenFD(addr string, tlsConfig *tls.Config) ([]net.Listener, error) { } return []net.Listener{listeners[fdOffset]}, nil } - -// allocateDaemonPort ensures that there are no containers -// that try to use any port allocated for the docker server. -// TODO: Move this outside pkg/listeners since it's Docker-specific, and requires -// libnetwork which increases the dependency tree quite drastically. -func allocateDaemonPort(addr string) error { - host, port, err := net.SplitHostPort(addr) - if err != nil { - return err - } - - intPort, err := strconv.Atoi(port) - if err != nil { - return err - } - - var hostIPs []net.IP - if parsedIP := net.ParseIP(host); parsedIP != nil { - hostIPs = append(hostIPs, parsedIP) - } else if hostIPs, err = net.LookupIP(host); err != nil { - return fmt.Errorf("failed to lookup %s address in host specification", host) - } - - pa := portallocator.Get() - for _, hostIP := range hostIPs { - if _, err := pa.RequestPort(hostIP, "tcp", intPort); err != nil { - return fmt.Errorf("failed to allocate daemon listening port %d (err: %v)", intPort, err) - } - } - return nil -} diff --git a/pkg/listeners/listeners_windows.go b/pkg/listeners/listeners_windows.go index 2099c0e59d..5b5a470fc6 100644 --- a/pkg/listeners/listeners_windows.go +++ b/pkg/listeners/listeners_windows.go @@ -7,13 +7,16 @@ import ( "strings" "github.com/Microsoft/go-winio" + "github.com/docker/go-connections/sockets" ) // Init creates new listeners for the server. -func Init(proto, addr, socketGroup string, tlsConfig *tls.Config) (ls []net.Listener, err error) { +func Init(proto, addr, socketGroup string, tlsConfig *tls.Config) ([]net.Listener, error) { + ls := []net.Listener{} + switch proto { case "tcp": - l, err := initTCPSocket(addr, tlsConfig) + l, err := sockets.NewTCPSocket(addr, tlsConfig) if err != nil { return nil, err } @@ -47,11 +50,5 @@ func Init(proto, addr, socketGroup string, tlsConfig *tls.Config) (ls []net.List return nil, fmt.Errorf("invalid protocol format: windows only supports tcp and npipe") } - return -} - -// allocateDaemonPort ensures that there are no containers -// that try to use any port allocated for the docker server. -func allocateDaemonPort(addr string) error { - return nil + return ls, nil }