[lxc-devel] [lxd/master] proxy: Support unix sockets
monstermunchkin on Github
lxc-bot at linuxcontainers.org
Mon May 28 14:10:25 UTC 2018
A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 316 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20180528/b31d88d5/attachment.bin>
-------------- next part --------------
From c849cb7d9e0d279359a09fe880ac567fa8755613 Mon Sep 17 00:00:00 2001
From: Thomas Hipp <thomas.hipp at canonical.com>
Date: Fri, 25 May 2018 19:53:23 +0200
Subject: [PATCH 1/2] proxy: Support unix sockets
Signed-off-by: Thomas Hipp <thomas.hipp at canonical.com>
---
lxd/main_forkproxy.go | 39 ++++++++++++++++++++++++++++++++++-----
lxd/proxy_device_utils.go | 15 +++++++++++++--
2 files changed, 47 insertions(+), 7 deletions(-)
diff --git a/lxd/main_forkproxy.go b/lxd/main_forkproxy.go
index 0c02199f9..89f62ce71 100644
--- a/lxd/main_forkproxy.go
+++ b/lxd/main_forkproxy.go
@@ -5,6 +5,7 @@ import (
"io"
"net"
"os"
+ "os/signal"
"strconv"
"strings"
"syscall"
@@ -188,9 +189,6 @@ func (c *cmdForkproxy) Run(cmd *cobra.Command, args []string) error {
defer file.Close()
listenerFd := file.Fd()
- if err != nil {
- return fmt.Errorf("Failed to duplicate the listener fd: %v", err)
- }
newFd, err := syscall.Dup(int(listenerFd))
if err != nil {
@@ -215,7 +213,30 @@ func (c *cmdForkproxy) Run(cmd *cobra.Command, args []string) error {
return fmt.Errorf("Failed to re-assemble listener: %v", err)
}
- defer listener.Close()
+ // Handl SIGTERM which is sent when the proxy is to be removed
+ terminate := false
+ sigs := make(chan os.Signal, 1)
+ signal.Notify(sigs, syscall.SIGTERM)
+
+ // Wait for SIGTERM and close the listener in order to exit the loop below
+ go func() {
+ <-sigs
+ terminate = true
+ listener.Close()
+ }()
+
+ if strings.HasPrefix(connectAddr, "unix:") {
+ file, err := getListenerFile(connectAddr)
+ if err != nil {
+ return err
+ }
+
+ defer func() {
+ file.Close()
+ os.Remove(strings.TrimPrefix(listenAddr, "unix:"))
+ os.Remove(strings.TrimPrefix(connectAddr, "unix:"))
+ }()
+ }
fmt.Printf("Starting to proxy\n")
@@ -224,6 +245,10 @@ func (c *cmdForkproxy) Run(cmd *cobra.Command, args []string) error {
// Accept a new client
srcConn, err := listener.Accept()
if err != nil {
+ if terminate {
+ break
+ }
+
fmt.Printf("error: Failed to accept new connection: %v\n", err)
continue
}
@@ -240,6 +265,10 @@ func (c *cmdForkproxy) Run(cmd *cobra.Command, args []string) error {
go io.Copy(eagain.Writer{Writer: srcConn}, eagain.Reader{Reader: dstConn})
go io.Copy(eagain.Writer{Writer: dstConn}, eagain.Reader{Reader: srcConn})
}
+
+ fmt.Println("Stopping proxy")
+
+ return nil
}
func getListenerFile(listenAddr string) (os.File, error) {
@@ -248,7 +277,7 @@ func getListenerFile(listenAddr string) (os.File, error) {
listener, err := net.Listen(fields[0], addr)
if err != nil {
- return os.File{}, err
+ return os.File{}, fmt.Errorf("Failed to listen on %s: %v", addr, err)
}
file := &os.File{}
diff --git a/lxd/proxy_device_utils.go b/lxd/proxy_device_utils.go
index 1984062b5..bea9dabce 100644
--- a/lxd/proxy_device_utils.go
+++ b/lxd/proxy_device_utils.go
@@ -31,10 +31,10 @@ func setupProxyProcInfo(c container, device map[string]string) (*proxyProcInfo,
connectionType := strings.SplitN(connectAddr, ":", 2)[0]
listenerType := strings.SplitN(listenAddr, ":", 2)[0]
- if connectionType != "tcp" {
+ if !shared.StringInSlice(connectionType, []string{"tcp", "unix"}) {
return nil, fmt.Errorf("Proxy device doesn't support the connection type: %s", connectionType)
}
- if listenerType != "tcp" {
+ if !shared.StringInSlice(listenerType, []string{"tcp", "unix"}) {
return nil, fmt.Errorf("Proxy device doesn't support the listener type: %s", listenerType)
}
@@ -53,6 +53,17 @@ func setupProxyProcInfo(c container, device map[string]string) (*proxyProcInfo,
return nil, fmt.Errorf("Invalid binding side given. Must be \"host\" or \"container\".")
}
+ if connectionType == "unix" {
+ fields := strings.SplitN(connectAddr, ":", 2)
+ if len(fields) == 2 {
+ // Prefix provided connectAddr with the container rootfs path
+ addr := filepath.Join(c.Path(), "rootfs", fields[1])
+ connectAddr = fmt.Sprintf("%s:%s", connectionType, addr)
+ } else {
+ return nil, fmt.Errorf("Missing connection address")
+ }
+ }
+
p := &proxyProcInfo{
listenPid: listenPid,
connectPid: connectPid,
From 9d6b866d5dcbe2114defc271c449f906f3c6a490 Mon Sep 17 00:00:00 2001
From: Thomas Hipp <thomas.hipp at canonical.com>
Date: Mon, 28 May 2018 16:05:47 +0200
Subject: [PATCH 2/2] proxy: Handle abstract sockets and OOB data
Signed-off-by: Thomas Hipp <thomas.hipp at canonical.com>
---
lxd/main_forkproxy.go | 104 +++++++++++++++++++++++++++++++++++++++++++---
lxd/proxy_device_utils.go | 9 ++--
2 files changed, 105 insertions(+), 8 deletions(-)
diff --git a/lxd/main_forkproxy.go b/lxd/main_forkproxy.go
index 89f62ce71..1dbbb8ccc 100644
--- a/lxd/main_forkproxy.go
+++ b/lxd/main_forkproxy.go
@@ -129,6 +129,12 @@ type cmdForkproxy struct {
global *cmdGlobal
}
+type proxyAddress struct {
+ connType string
+ addr string
+ abstract bool
+}
+
func (c *cmdForkproxy) Command() *cobra.Command {
// Main subcommand
cmd := &cobra.Command{}
@@ -225,7 +231,11 @@ func (c *cmdForkproxy) Run(cmd *cobra.Command, args []string) error {
listener.Close()
}()
- if strings.HasPrefix(connectAddr, "unix:") {
+ cAddr := parseAddr(connectAddr)
+ lAddr := parseAddr(listenAddr)
+
+ if cAddr.connType == "unix" && !cAddr.abstract {
+ // Create socket
file, err := getListenerFile(connectAddr)
if err != nil {
return err
@@ -233,11 +243,14 @@ func (c *cmdForkproxy) Run(cmd *cobra.Command, args []string) error {
defer func() {
file.Close()
- os.Remove(strings.TrimPrefix(listenAddr, "unix:"))
- os.Remove(strings.TrimPrefix(connectAddr, "unix:"))
+ os.Remove(cAddr.addr)
}()
}
+ if lAddr.connType == "unix" && !lAddr.abstract {
+ defer os.Remove(lAddr.addr)
+ }
+
fmt.Printf("Starting to proxy\n")
// begin proxying
@@ -262,8 +275,14 @@ func (c *cmdForkproxy) Run(cmd *cobra.Command, args []string) error {
continue
}
- go io.Copy(eagain.Writer{Writer: srcConn}, eagain.Reader{Reader: dstConn})
- go io.Copy(eagain.Writer{Writer: dstConn}, eagain.Reader{Reader: srcConn})
+ if cAddr.connType == "unix" && lAddr.connType == "unix" {
+ // Handle OOB if both src and dst are using unix sockets
+ go relay(srcConn.(*net.UnixConn), dstConn.(*net.UnixConn))
+ go relay(dstConn.(*net.UnixConn), srcConn.(*net.UnixConn))
+ } else {
+ go io.Copy(eagain.Writer{Writer: srcConn}, eagain.Reader{Reader: dstConn})
+ go io.Copy(eagain.Writer{Writer: dstConn}, eagain.Reader{Reader: srcConn})
+ }
}
fmt.Println("Stopping proxy")
@@ -302,3 +321,78 @@ func getDestConn(connectAddr string) (net.Conn, error) {
addr := strings.Join(fields[1:], "")
return net.Dial(fields[0], addr)
}
+
+func relay(src *net.UnixConn, dst *net.UnixConn) {
+ for {
+ dataBuf := make([]byte, 4096)
+ oobBuf := make([]byte, 4096)
+
+ // Read from the source
+ sData, sOob, _, _, err := src.ReadMsgUnix(dataBuf, oobBuf)
+ if err != nil {
+ fmt.Printf("Disconnected during read: %v\n", err)
+ src.Close()
+ dst.Close()
+ return
+ }
+
+ var fds []int
+ if sOob > 0 {
+ entries, err := syscall.ParseSocketControlMessage(oobBuf[:sOob])
+ if err != nil {
+ fmt.Printf("Failed to parse control message: %v\n", err)
+ src.Close()
+ dst.Close()
+ return
+ }
+
+ for _, msg := range entries {
+ fds, err = syscall.ParseUnixRights(&msg)
+ if err != nil {
+ fmt.Printf("Failed to get fds list for control message: %v\n", err)
+ src.Close()
+ dst.Close()
+ return
+ }
+ }
+ }
+
+ // Send to the destination
+ tData, tOob, err := dst.WriteMsgUnix(dataBuf[:sData], oobBuf[:sOob], nil)
+ if err != nil {
+ fmt.Printf("Disconnected during write: %v\n", err)
+ src.Close()
+ dst.Close()
+ return
+ }
+
+ if sData != tData || sOob != tOob {
+ fmt.Printf("Some data got lost during transfer, disconnecting.")
+ src.Close()
+ dst.Close()
+ return
+ }
+
+ // Close those fds we received
+ if fds != nil {
+ for _, fd := range fds {
+ err := syscall.Close(fd)
+ if err != nil {
+ fmt.Printf("Failed to close fd %d: %v\n", fd, err)
+ src.Close()
+ dst.Close()
+ return
+ }
+ }
+ }
+ }
+}
+
+func parseAddr(addr string) *proxyAddress {
+ fields := strings.SplitN(addr, ":", 2)
+ return &proxyAddress{
+ connType: fields[0],
+ addr: fields[1],
+ abstract: strings.HasPrefix(fields[1], "@"),
+ }
+}
diff --git a/lxd/proxy_device_utils.go b/lxd/proxy_device_utils.go
index bea9dabce..c85f0b137 100644
--- a/lxd/proxy_device_utils.go
+++ b/lxd/proxy_device_utils.go
@@ -56,9 +56,12 @@ func setupProxyProcInfo(c container, device map[string]string) (*proxyProcInfo,
if connectionType == "unix" {
fields := strings.SplitN(connectAddr, ":", 2)
if len(fields) == 2 {
- // Prefix provided connectAddr with the container rootfs path
- addr := filepath.Join(c.Path(), "rootfs", fields[1])
- connectAddr = fmt.Sprintf("%s:%s", connectionType, addr)
+ // Prefix provided connectAddr with the container rootfs path if
+ // it's not an abstract socket
+ if !strings.HasPrefix(fields[1], "@") {
+ addr := filepath.Join(c.Path(), "rootfs", fields[1])
+ connectAddr = fmt.Sprintf("%s:%s", connectionType, addr)
+ }
} else {
return nil, fmt.Errorf("Missing connection address")
}
More information about the lxc-devel
mailing list