diff --git a/alpine/packages/vsudd/.gitignore b/alpine/packages/vsudd/.gitignore index e4461fbd4..50802866b 100644 --- a/alpine/packages/vsudd/.gitignore +++ b/alpine/packages/vsudd/.gitignore @@ -1 +1,2 @@ /vsudd +/vendor \ No newline at end of file diff --git a/alpine/packages/vsudd/Makefile b/alpine/packages/vsudd/Makefile index 43c2ecb95..2a205ed97 100644 --- a/alpine/packages/vsudd/Makefile +++ b/alpine/packages/vsudd/Makefile @@ -1,10 +1,15 @@ all: vsudd -vsudd: Dockerfile main.go +.PHONY: vendor +vendor: + mkdir -p ./vendor + cp -r ../go/vendor/* ./vendor/ + +vsudd: Dockerfile main.go vendor docker build --build-arg GOOS=$(OS) --build-arg GOARCH=$(ARCH) -t vsudd:build . docker run --rm vsudd:build cat /go/bin/vsudd > vsudd chmod 755 vsudd clean: - rm -f vsudd + rm -rf vsudd vendor docker images -q vsudd:build | xargs docker rmi -f diff --git a/alpine/packages/vsudd/main.go b/alpine/packages/vsudd/main.go index f67450623..6e039e851 100644 --- a/alpine/packages/vsudd/main.go +++ b/alpine/packages/vsudd/main.go @@ -2,7 +2,6 @@ package main import ( "flag" - "fmt" "io" "log" "net" @@ -11,59 +10,24 @@ import ( "strings" "syscall" "time" -) -/* No way to teach net or syscall about vsock sockaddr, so go right to C */ - -/* -#include -#include -#include "include/uapi/linux/vm_sockets.h" -int bind_sockaddr_vm(int fd, const struct sockaddr_vm *sa_vm) { - return bind(fd, (const struct sockaddr*)sa_vm, sizeof(*sa_vm)); -} -int connect_sockaddr_vm(int fd, const struct sockaddr_vm *sa_vm) { - return connect(fd, (const struct sockaddr*)sa_vm, sizeof(*sa_vm)); -} -int accept_vm(int fd, struct sockaddr_vm *sa_vm, socklen_t *sa_vm_len) { - return accept4(fd, (struct sockaddr *)sa_vm, sa_vm_len, 0); -} - -struct sockaddr_hv { - unsigned short shv_family; - unsigned short reserved; - unsigned char shv_vm_id[16]; - unsigned char shv_service_id[16]; -}; -int bind_sockaddr_hv(int fd, const struct sockaddr_hv *sa_hv) { - return bind(fd, (const struct sockaddr*)sa_hv, sizeof(*sa_hv)); -} -int connect_sockaddr_hv(int fd, const struct sockaddr_hv *sa_hv) { - return connect(fd, (const struct sockaddr*)sa_hv, sizeof(*sa_hv)); -} -int accept_hv(int fd, struct sockaddr_hv *sa_hv, socklen_t *sa_hv_len) { - return accept4(fd, (struct sockaddr *)sa_hv, sa_hv_len, 0); -} -*/ -import "C" - -type GUID [16]byte - -const ( - AF_VSOCK = 40 - VSOCK_CID_ANY = 4294967295 /* 2^32-1 */ - - AF_HYPERV = 42 - SHV_PROTO_RAW = 1 + "github.com/rneugeba/virtsock/go/hvsock" + "github.com/rneugeba/virtsock/go/vsock" ) var ( - portstr string - sock string - detach bool - SHV_VMID_GUEST = GUID{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + portstr string + sock string + detach bool + useHVsock bool ) +type vConn interface { + net.Conn + CloseRead() error + CloseWrite() error +} + func init() { flag.StringVar(&portstr, "port", "2376", "vsock port to forward") flag.StringVar(&sock, "sock", "/var/run/docker.sock", "path of the local Unix domain socket to forward to") @@ -90,118 +54,53 @@ func main() { syscall.Dup2(int(fd), int(os.Stderr.Fd())) } + var l net.Listener if strings.Contains(portstr, "-") { - guid, err := guidFromString(portstr) + svcid, err := hvsock.GuidFromString(portstr) if err != nil { log.Fatalln("Failed to parse GUID", portstr, err) } - hvsockListen(guid) + l, err = hvsock.Listen(hvsock.HypervAddr{VmId: hvsock.GUID_WILDCARD, ServiceId: svcid}) + if err != nil { + log.Fatalf("Failed to bind to hvsock port: %#v", err) + } + log.Printf("Listening on ServiceId %s", svcid) + useHVsock = true } else { port, err := strconv.ParseUint(portstr, 10, 32) if err != nil { log.Fatalln("Can't convert %s to a uint.", portstr, err) } - vsockListen(uint(port)) + l, err = vsock.Listen(uint(port)) + if err != nil { + log.Fatalf("Failed to bind to vsock port %u: %#v", port, err) + } + log.Printf("Listening on port %u", port) + useHVsock = false } -} - -func hvsockListen(port GUID) { - accept_fd, err := syscall.Socket(AF_HYPERV, syscall.SOCK_STREAM, SHV_PROTO_RAW) - if err != nil { - log.Fatal(err) - } - - sa := C.struct_sockaddr_hv{} - sa.shv_family = AF_HYPERV - sa.reserved = 0 - /* TODO: Turn this into a function */ - for i := 0; i < 16; i++ { - sa.shv_vm_id[i] = C.uchar(SHV_VMID_GUEST[i]) - } - for i := 0; i < 16; i++ { - sa.shv_service_id[i] = C.uchar(port[i]) - } - - if ret := C.bind_sockaddr_hv(C.int(accept_fd), &sa); ret != 0 { - log.Fatal(fmt.Sprintf("failed bind hvsock connection to %s.%s, returned %d", - SHV_VMID_GUEST.toString(), port.toString(), ret)) - } - - err = syscall.Listen(accept_fd, syscall.SOMAXCONN) - if err != nil { - log.Fatalln("Failed to listen to VSOCK", err) - } - - log.Printf("Listening on fd %d", accept_fd) connid := 0 - for { - var accept_sa C.struct_sockaddr_hv - var accept_sa_len C.socklen_t - connid++ - accept_sa_len = C.sizeof_struct_sockaddr_hv - fd, err := C.accept_hv(C.int(accept_fd), &accept_sa, &accept_sa_len) + conn, err := l.Accept() if err != nil { - log.Fatalln("Error accepting connection", err) + log.Printf("Error accepting connection: %#v", err) + return // no more listening } + log.Printf("Connection %d from: %s\n", connid, conn.RemoteAddr()) - accept_vm_id := guidFromC(accept_sa.shv_vm_id) - accept_svc_id := guidFromC(accept_sa.shv_service_id) - log.Printf("%d Accepted connection on fd %d from %s.%s", - connid, fd, accept_vm_id.toString(), accept_svc_id.toString()) - go handleOne(connid, int(fd)) + go handleOne(connid, conn.(vConn)) } } -func vsockListen(port uint) { - accept_fd, err := syscall.Socket(AF_VSOCK, syscall.SOCK_STREAM, 0) - if err != nil { - log.Fatal(err) - } - - sa := C.struct_sockaddr_vm{} - sa.svm_family = AF_VSOCK - sa.svm_port = C.uint(port) - sa.svm_cid = VSOCK_CID_ANY - - if ret := C.bind_sockaddr_vm(C.int(accept_fd), &sa); ret != 0 { - log.Fatal(fmt.Sprintf("failed bind vsock connection to %08x.%08x, returned %d", - sa.svm_cid, sa.svm_port, ret)) - } - - err = syscall.Listen(accept_fd, syscall.SOMAXCONN) - if err != nil { - log.Fatalln("Failed to listen to VSOCK", err) - } - - log.Printf("Listening on fd %d", accept_fd) - - connid := 0 - - for { - var accept_sa C.struct_sockaddr_vm - var accept_sa_len C.socklen_t - - connid++ - accept_sa_len = C.sizeof_struct_sockaddr_vm - fd, err := C.accept_vm(C.int(accept_fd), &accept_sa, &accept_sa_len) - if err != nil { - log.Fatalln("Error accepting connection", err) - } - log.Printf("%d Accepted connection on fd %d from %08x.%08x", - connid, fd, uint(accept_sa.svm_cid), uint(accept_sa.svm_port)) - go handleOne(connid, int(fd)) - } -} - -func handleOne(connid int, fd int) { - vsock := os.NewFile(uintptr(fd), fmt.Sprintf("vsock:%d", fd)) - +func handleOne(connid int, conn vConn) { defer func() { - if err := vsock.Close(); err != nil { - log.Println(connid, "Error closing", vsock, ":", err) + if err := conn.Close(); err != nil { + // On windows we get an EINVAL when the other end already closed + // Don't bother spilling this into the logs + if !(useHVsock && err == syscall.EINVAL) { + log.Println(connid, "Error closing", conn, ":", err) + } } }() @@ -229,7 +128,7 @@ func handleOne(connid int, fd int) { w := make(chan int64) go func() { - n, err := io.Copy(vsock, docker) + n, err := io.Copy(conn, docker) if err != nil { log.Println(connid, "error copying from docker to vsock:", err) } @@ -238,14 +137,14 @@ func handleOne(connid int, fd int) { if err != nil { log.Println(connid, "error CloseRead on docker socket:", err) } - err = syscall.Shutdown(fd, syscall.SHUT_WR) + err = conn.CloseWrite() if err != nil { - log.Println(connid, "error SHUT_WR on vsock:", err) + log.Println(connid, "error CloseWrite on vsock:", err) } w <- n }() - n, err := io.Copy(docker, vsock) + n, err := io.Copy(docker, conn) if err != nil { log.Println(connid, "error copying from vsock to docker:", err) } @@ -255,41 +154,11 @@ func handleOne(connid int, fd int) { if err != nil { log.Println(connid, "error CloseWrite on docker socket:", err) } - err = syscall.Shutdown(fd, syscall.SHUT_RD) + err = conn.CloseRead() if err != nil { - log.Println(connid, "error SHUT_RD on vsock:", err) + log.Println(connid, "error CloseRead on vsock:", err) } totalWritten := <-w log.Println(connid, "Done. read:", totalRead, "written:", totalWritten) } - -func (g *GUID) toString() string { - /* XXX This assume little endian */ - return fmt.Sprintf("%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", - g[3], g[2], g[1], g[0], - g[5], g[4], - g[7], g[6], - g[8], g[9], - g[10], g[11], g[12], g[13], g[14], g[15]) -} - -func guidFromString(s string) (GUID, error) { - var g GUID - var err error - _, err = fmt.Sscanf(s, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", - &g[3], &g[2], &g[1], &g[0], - &g[5], &g[4], - &g[7], &g[6], - &g[8], &g[9], - &g[10], &g[11], &g[12], &g[13], &g[14], &g[15]) - return g, err -} - -func guidFromC(cg [16]C.uchar) GUID { - var g GUID - for i := 0; i < 16; i++ { - g[i] = byte(cg[i]) - } - return g -}