From 89e8ac2612e2033d7f17d368ceb930bd32915617 Mon Sep 17 00:00:00 2001 From: Rolf Neugebauer Date: Wed, 20 Apr 2016 15:04:07 +0100 Subject: [PATCH] vsudd: Add support for Hyper-V sockets - If a GUID is passed in use AF_HYPERV else AFVSOCK Signed-off-by: Rolf Neugebauer --- alpine/packages/vsudd/main.go | 120 ++++++++++++++++++++++++++++++++-- 1 file changed, 116 insertions(+), 4 deletions(-) diff --git a/alpine/packages/vsudd/main.go b/alpine/packages/vsudd/main.go index 80a1f6ad5..634a3fd9b 100644 --- a/alpine/packages/vsudd/main.go +++ b/alpine/packages/vsudd/main.go @@ -8,6 +8,7 @@ import ( "net" "os" "strconv" + "strings" "syscall" "time" ) @@ -15,6 +16,7 @@ import ( /* 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) { @@ -26,18 +28,40 @@ int connect_sockaddr_vm(int fd, const struct sockaddr_vm *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 ) 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} ) func init() { @@ -66,11 +90,69 @@ func main() { syscall.Dup2(int(fd), int(os.Stderr.Fd())) } - port, err := strconv.ParseUint(portstr, 10, 32) - if err != nil { - log.Fatalln("Can't convert %s to a uint.", portstr, err) + if strings.Contains(portstr, "-") { + guid, err := guidFromString(portstr) + if err != nil { + log.Fatalln("Failed to parse GUID", portstr, err) + } + hvsockListen(guid) + } 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)) + } +} + +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) + if err != nil { + log.Fatalln("Error accepting connection", err) + } + + 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)) } - vsockListen(uint(port)) } func vsockListen(port uint) { @@ -186,3 +268,33 @@ func handleOne(connid int, fd int) { 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 +}