vsudd: Make incoming socket forwarding more generic

Rather than hardcoding a single vsock<->docker.sock mapping allow arbitrary
incoming connection forwarding between vsocks and unix domain sockets.

The intention was to subsequently extend this further to support arbitrary
forwarding of outgoing connections too and to use that to forward the syslog
socket out to a vsock.

This turned out not to be a good plan, partly since the syslog socket needs to
be SOCK_DATAGRAM but vsocks only does SOCK_STREAM today (meaning we need some
additional framing here) and partly because handling syslog forwarding in
common code makes error logging in the common code somewhat trickier (logging
syslog errors over syslog).

So instead syslog will be handled as a special case in a following patch.
However some vestiges of the original plan remain, e.g. the inForwards name and
the net field in the forwards which could be unixgram but currently is only
supporting unix(stream).

In principal this patch could be dropped, but it adds some flexibility which
might be useful in the future.

Signed-off-by: Ian Campbell <ian.campbell@docker.com>
This commit is contained in:
Ian Campbell 2016-07-01 11:04:17 +01:00
parent f70ff0aeac
commit b61451047d
2 changed files with 92 additions and 44 deletions

View File

@ -9,12 +9,12 @@ depend()
start() start()
{ {
ebegin "Starting docker socket vsock passthrough" ebegin "Starting vsock proxy"
if [ -d /sys/bus/vmbus ]; then if [ -d /sys/bus/vmbus ]; then
PORT=23a432c2-537a-4291-bcb5-d62504644739 DOCKER_PORT=23a432c2-537a-4291-bcb5-d62504644739
else else
PORT=2376 DOCKER_PORT=2376
fi fi
[ -n "${PIDFILE}" ] || PIDFILE=/var/run/vsudd.pid [ -n "${PIDFILE}" ] || PIDFILE=/var/run/vsudd.pid
@ -25,7 +25,7 @@ start()
--exec /sbin/vsudd \ --exec /sbin/vsudd \
--make-pidfile --pidfile ${PIDFILE} \ --make-pidfile --pidfile ${PIDFILE} \
--stderr "${LOGFILE}" --stdout "${LOGFILE}" \ --stderr "${LOGFILE}" --stdout "${LOGFILE}" \
-- -port "${PORT}" -sock /var/run/docker.sock -- -inport "${DOCKER_PORT}:unix:/var/run/docker.sock"
eend $? "Failed to start vsudd" eend $? "Failed to start vsudd"
} }

View File

@ -2,12 +2,14 @@ package main
import ( import (
"flag" "flag"
"fmt"
"io" "io"
"log" "log"
"net" "net"
"os" "os"
"strconv" "strconv"
"strings" "strings"
"sync"
"syscall" "syscall"
"time" "time"
@ -15,9 +17,16 @@ import (
"github.com/rneugeba/virtsock/go/vsock" "github.com/rneugeba/virtsock/go/vsock"
) )
type forward struct {
vsock string
net string // "unix" or "unixgram"
usock string
}
type forwards []forward
var ( var (
portstr string inForwards forwards
sock string
detach bool detach bool
useHVsock bool useHVsock bool
) )
@ -28,9 +37,25 @@ type vConn interface {
CloseWrite() error CloseWrite() error
} }
func (f *forwards) String() string {
return "Forwards"
}
func (f *forwards) Set(value string) error {
s := strings.SplitN(value, ":", 3)
if len(s) != 3 {
return fmt.Errorf("Failed to parse: %s", value)
}
var newF forward
newF.vsock = s[0]
newF.net = s[1]
newF.usock = s[2]
*f = append(*f, newF)
return nil
}
func init() { func init() {
flag.StringVar(&portstr, "port", "2376", "vsock port to forward") flag.Var(&inForwards, "inport", "incoming port to forward")
flag.StringVar(&sock, "sock", "/var/run/docker.sock", "path of the local Unix domain socket to forward to")
flag.BoolVar(&detach, "detach", false, "detach from terminal") flag.BoolVar(&detach, "detach", false, "detach from terminal")
} }
@ -54,7 +79,23 @@ func main() {
syscall.Dup2(int(fd), int(os.Stderr.Fd())) syscall.Dup2(int(fd), int(os.Stderr.Fd()))
} }
var wg sync.WaitGroup
connid := 0
for _, inF := range inForwards {
var portstr = inF.vsock
var network = inF.net
var usock = inF.usock
var l net.Listener var l net.Listener
if network != "unix" {
log.Fatalf("cannot forward incoming port to %s:%s", network, usock)
}
log.Printf("incoming port forward from %s to %s", portstr, usock)
if strings.Contains(portstr, "-") { if strings.Contains(portstr, "-") {
svcid, err := hvsock.GuidFromString(portstr) svcid, err := hvsock.GuidFromString(portstr)
if err != nil { if err != nil {
@ -73,13 +114,16 @@ func main() {
} }
l, err = vsock.Listen(uint(port)) l, err = vsock.Listen(uint(port))
if err != nil { if err != nil {
log.Fatalf("Failed to bind to vsock port %u: %s", port, err) log.Fatalf("Failed to bind to vsock port %d: %s", port, err)
} }
log.Printf("Listening on port %u", port) log.Printf("Listening on port %s", portstr)
useHVsock = false useHVsock = false
} }
connid := 0 wg.Add(1)
go func() {
defer wg.Done()
for { for {
connid++ connid++
conn, err := l.Accept() conn, err := l.Accept()
@ -87,13 +131,17 @@ func main() {
log.Printf("Error accepting connection: %s", err) log.Printf("Error accepting connection: %s", err)
return // no more listening return // no more listening
} }
log.Printf("Connection %d from: %s\n", connid, conn.RemoteAddr()) log.Printf("Connection %d to: %s from: %s\n", connid, portstr, conn.RemoteAddr())
go handleOne(connid, conn.(vConn)) go handleOneIn(connid, conn.(vConn), usock)
} }
}()
}
wg.Wait()
} }
func handleOne(connid int, conn vConn) { func handleOneIn(connid int, conn vConn, sock string) {
defer func() { defer func() {
if err := conn.Close(); err != nil { if err := conn.Close(); err != nil {
// On windows we get an EINVAL when the other end already closed // On windows we get an EINVAL when the other end already closed