cli-plugins: use non-abstract socket on darwin

As macOS does not support the abstract socket namespace, use a temporary
socket in $TMPDIR to connect with the plugin. Ensure this socket is
cleaned up even in the case of crash/ungraceful termination by removing
it after the first connection is accepted.

Co-authored-by: Laura Brehm <laurabrehm@hey.com>
Signed-off-by: Bjorn Neergaard <bjorn.neergaard@docker.com>
This commit is contained in:
Bjorn Neergaard 2024-01-12 11:34:15 -07:00
parent dbf992f91f
commit 6d0b329b0d
No known key found for this signature in database
3 changed files with 41 additions and 8 deletions

View File

@ -16,7 +16,7 @@ const EnvKey = "DOCKER_CLI_PLUGIN_SOCKET"
// SetupConn sets up a Unix socket listener, establishes a goroutine to handle connections // SetupConn sets up a Unix socket listener, establishes a goroutine to handle connections
// and update the conn pointer, and returns the environment variable to pass to the plugin. // and update the conn pointer, and returns the environment variable to pass to the plugin.
func SetupConn(conn **net.UnixConn) (string, error) { func SetupConn(conn **net.UnixConn) (string, error) {
listener, err := listen() listener, err := listen("docker_cli_" + uuid.Generate().String())
if err != nil { if err != nil {
return "", err return "", err
} }
@ -26,13 +26,6 @@ func SetupConn(conn **net.UnixConn) (string, error) {
return EnvKey + "=" + listener.Addr().String(), nil return EnvKey + "=" + listener.Addr().String(), nil
} }
func listen() (*net.UnixListener, error) {
return net.ListenUnix("unix", &net.UnixAddr{
Name: "@docker_cli_" + uuid.Generate().String(),
Net: "unix",
})
}
func accept(listener *net.UnixListener, conn **net.UnixConn) { func accept(listener *net.UnixListener, conn **net.UnixConn) {
defer listener.Close() defer listener.Close()
@ -41,6 +34,8 @@ func accept(listener *net.UnixListener, conn **net.UnixConn) {
// ignore error here, if we failed to accept a connection, // ignore error here, if we failed to accept a connection,
// conn is nil and we fallback to previous behavior // conn is nil and we fallback to previous behavior
*conn, _ = listener.AcceptUnix() *conn, _ = listener.AcceptUnix()
// perform any platform-specific actions on accept (e.g. unlink non-abstract sockets)
onAccept(*conn, listener)
} }
}() }()
} }

View File

@ -0,0 +1,19 @@
package socket
import (
"net"
"os"
"path/filepath"
"syscall"
)
func listen(socketname string) (*net.UnixListener, error) {
return net.ListenUnix("unix", &net.UnixAddr{
Name: filepath.Join(os.TempDir(), socketname),
Net: "unix",
})
}
func onAccept(conn *net.UnixConn, listener *net.UnixListener) {
syscall.Unlink(listener.Addr().String())
}

View File

@ -0,0 +1,19 @@
//go:build !darwin
package socket
import (
"net"
)
func listen(socketname string) (*net.UnixListener, error) {
return net.ListenUnix("unix", &net.UnixAddr{
Name: "@" + socketname,
Net: "unix",
})
}
func onAccept(conn *net.UnixConn, listener *net.UnixListener) {
// do nothing
// while on darwin we would unlink here; on non-darwin the socket is abstract and not present on the filesystem
}