diff --git a/alpine/packages/tap-vsockd/Makefile b/alpine/packages/tap-vsockd/Makefile index f2fe55ec2..77ebf467b 100644 --- a/alpine/packages/tap-vsockd/Makefile +++ b/alpine/packages/tap-vsockd/Makefile @@ -1,19 +1,22 @@ .PHONY: all -DEPS=tap-vsockd.c compat.h protocol.c protocol.h +DEPS=tap-vsockd.c hvsock.c hvsock.h protocol.c protocol.h all: Dockerfile $(DEPS) docker build -t tap-vsockd:build . docker run --rm tap-vsockd:build cat tap-vsockd > tap-vsockd chmod 755 tap-vsockd -tap-vsockd: protocol.o tap-vsockd.o - gcc -Wall -Werror -o tap-vsockd tap-vsockd.o protocol.o -lpthread +tap-vsockd: hvsock.o protocol.o tap-vsockd.o + gcc -Wall -Werror -o tap-vsockd tap-vsockd.o protocol.o hvsock.o -lpthread + +hvsock.o: hvsock.c hvsock.h + gcc -Wall -Werror -c hvsock.c protocol.o: protocol.c gcc -Wall -Werror -c protocol.c -tap-vsockd.o: tap-vsockd.c compat.h +tap-vsockd.o: tap-vsockd.c hvsock.h gcc -Wall -Werror -c tap-vsockd.c clean: diff --git a/alpine/packages/tap-vsockd/compat.h b/alpine/packages/tap-vsockd/compat.h deleted file mode 100644 index 02f9f7b84..000000000 --- a/alpine/packages/tap-vsockd/compat.h +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Compatibility layer between Windows and Linux - */ -#ifdef _MSC_VER -#undef UNICODE -#define WIN32_LEAN_AND_MEAN -#include -#include -#include -#include - -#pragma comment (lib, "Ws2_32.lib") -#pragma comment (lib, "Mswsock.lib") -#pragma comment (lib, "AdvApi32.lib") - -#else -#include -#include -#include -#include -#endif /* !_MSC_VER */ - -#ifdef _MSC_VER -typedef int socklen_t; -#endif - -#ifndef _MSC_VER -/* Compat layer for Linux/Unix */ -typedef int SOCKET; - -#ifndef SOCKET_ERROR -#define SOCKET_ERROR -1 -#endif - -#ifndef INVALID_SOCKET -#define INVALID_SOCKET -1 -#endif - -#define closesocket(_fd) close(_fd) - -/* Shutdown flags are different too */ -#define SD_SEND SHUT_WR -#define SD_RECEIVE SHUT_RD -#define SD_BOTH SHUT_RDWR - -#define __cdecl - -/* GUID handling */ -typedef struct _GUID { - uint32_t Data1; - uint16_t Data2; - uint16_t Data3; - uint8_t Data4[8]; -} GUID; - -#define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ - const GUID name = {l, w1, w2, {b1, b2, b3, b4, b5, b6, b7, b8}} - - -/* HV Socket definitions */ -#define AF_HYPERV 43 -#define HV_PROTOCOL_RAW 1 - -typedef struct _SOCKADDR_HV -{ - unsigned short Family; - unsigned short Reserved; - GUID VmId; - GUID ServiceId; -} SOCKADDR_HV; - -DEFINE_GUID(HV_GUID_ZERO, - 0x00000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); -DEFINE_GUID(HV_GUID_BROADCAST, - 0xFFFFFFFF, 0xFFFF, 0xFFFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); -DEFINE_GUID(HV_GUID_WILDCARD, - 0x00000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); - -DEFINE_GUID(HV_GUID_CHILDREN, - 0x90db8b89, 0x0d35, 0x4f79, 0x8c, 0xe9, 0x49, 0xea, 0x0a, 0xc8, 0xb7, 0xcd); -DEFINE_GUID(HV_GUID_LOOPBACK, - 0xe0e16197, 0xdd56, 0x4a10, 0x91, 0x95, 0x5e, 0xe7, 0xa1, 0x55, 0xa8, 0x38); -DEFINE_GUID(HV_GUID_PARENT, - 0xa42e7cda, 0xd03f, 0x480c, 0x9c, 0xc2, 0xa4, 0xde, 0x20, 0xab, 0xb8, 0x78); - -#endif - -/* Thread wrappers */ -#ifdef _MSC_VER -typedef HANDLE THREAD_HANDLE; - -static inline int thread_create(THREAD_HANDLE *t, void *(*f)(void *), void *arg) -{ - *t = CreateThread(NULL, 0, f, arg, 0, NULL); - return 0; -} - -static inline int thread_join(THREAD_HANDLE t) -{ - WaitForSingleObject(t, INFINITE); - return 0; -} - -#else -#include - -typedef pthread_t THREAD_HANDLE; - -static inline int thread_create(THREAD_HANDLE *t, void *(*f)(void *), void *arg) -{ - return pthread_create(t, NULL, f, arg); -} - -static inline int thread_join(THREAD_HANDLE t) -{ - return pthread_join(t, NULL); -} -#endif diff --git a/alpine/packages/tap-vsockd/hvsock.c b/alpine/packages/tap-vsockd/hvsock.c new file mode 100644 index 000000000..47c924d63 --- /dev/null +++ b/alpine/packages/tap-vsockd/hvsock.c @@ -0,0 +1,38 @@ +#include + +#include "hvsock.h" + +int parseguid(const char *s, GUID *g) +{ + int res; + int p0, p1, p2, p3, p4, p5, p6, p7; + + res = sscanf(s, GUID_FMT, + &g->Data1, &g->Data2, &g->Data3, + &p0, &p1, &p2, &p3, &p4, &p5, &p6, &p7); + if (res != 11) + return 1; + g->Data4[0] = p0; + g->Data4[1] = p1; + g->Data4[2] = p2; + g->Data4[3] = p3; + g->Data4[4] = p4; + g->Data4[5] = p5; + g->Data4[6] = p6; + g->Data4[7] = p7; + return 0; +} + +DEFINE_GUID(HV_GUID_ZERO, + 0x00000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); +DEFINE_GUID(HV_GUID_BROADCAST, + 0xFFFFFFFF, 0xFFFF, 0xFFFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); +DEFINE_GUID(HV_GUID_WILDCARD, + 0x00000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); + +DEFINE_GUID(HV_GUID_CHILDREN, + 0x90db8b89, 0x0d35, 0x4f79, 0x8c, 0xe9, 0x49, 0xea, 0x0a, 0xc8, 0xb7, 0xcd); +DEFINE_GUID(HV_GUID_LOOPBACK, + 0xe0e16197, 0xdd56, 0x4a10, 0x91, 0x95, 0x5e, 0xe7, 0xa1, 0x55, 0xa8, 0x38); +DEFINE_GUID(HV_GUID_PARENT, + 0xa42e7cda, 0xd03f, 0x480c, 0x9c, 0xc2, 0xa4, 0xde, 0x20, 0xab, 0xb8, 0x78); diff --git a/alpine/packages/tap-vsockd/hvsock.h b/alpine/packages/tap-vsockd/hvsock.h new file mode 100644 index 000000000..6e1ca6695 --- /dev/null +++ b/alpine/packages/tap-vsockd/hvsock.h @@ -0,0 +1,49 @@ +/* AF_HYPERV definitions and utilities */ + +#include +#include +#include +#include + +/* GUID handling */ +typedef struct _GUID { + uint32_t Data1; + uint16_t Data2; + uint16_t Data3; + uint8_t Data4[8]; +} GUID; + +#define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ + const GUID name = {l, w1, w2, {b1, b2, b3, b4, b5, b6, b7, b8}} + +/* Helper macros for parsing/printing GUIDs */ +#define GUID_FMT "%08x-%04hx-%04hx-%02x%02x-%02x%02x%02x%02x%02x%02x" +#define GUID_ARGS(_g) \ + (_g).Data1, (_g).Data2, (_g).Data3, \ + (_g).Data4[0], (_g).Data4[1], (_g).Data4[2], (_g).Data4[3], \ + (_g).Data4[4], (_g).Data4[5], (_g).Data4[6], (_g).Data4[7] +#define GUID_SARGS(_g) \ + &(_g).Data1, &(_g).Data2, &(_g).Data3, \ + &(_g).Data4[0], &(_g).Data4[1], &(_g).Data4[2], &(_g).Data4[3], \ + &(_g).Data4[4], &(_g).Data4[5], &(_g).Data4[6], &(_g).Data4[7] + +extern int parseguid(const char *s, GUID *g); + +/* HV Socket definitions */ +#define AF_HYPERV 43 +#define HV_PROTOCOL_RAW 1 + +typedef struct _SOCKADDR_HV +{ + unsigned short Family; + unsigned short Reserved; + GUID VmId; + GUID ServiceId; +} SOCKADDR_HV; + +extern const GUID HV_GUID_ZERO; +extern const GUID HV_GUID_BROADCAST; +extern const GUID HV_GUID_WILDCARD; +extern const GUID HV_GUID_CHILDREN; +extern const GUID HV_GUID_LOOPBACK; +extern const GUID HV_GUID_PARENT; diff --git a/alpine/packages/tap-vsockd/tap-vsockd.c b/alpine/packages/tap-vsockd/tap-vsockd.c index ae1dd9792..c24edbac9 100644 --- a/alpine/packages/tap-vsockd/tap-vsockd.c +++ b/alpine/packages/tap-vsockd/tap-vsockd.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -24,7 +25,7 @@ #include -#include "compat.h" +#include "hvsock.h" #include "protocol.h" int daemon_flag = 0; @@ -33,25 +34,28 @@ int connect_flag = 0; char *default_sid = "30D48B34-7D27-4B0B-AAAF-BBBED334DD59"; +void fatal(const char *msg) +{ + syslog(LOG_CRIT, "%s Error: %d. %s", msg, errno, strerror(errno)); + exit(1); +} + int alloc_tap(const char *dev) { int fd; struct ifreq ifr; const char *clonedev = "/dev/net/tun"; if ((fd = open(clonedev, O_RDWR)) == -1) { - perror("Failed to open /dev/net/tun"); - exit(1); + fatal("Failed to open /dev/net/tun"); } memset(&ifr, 0, sizeof(ifr)); ifr.ifr_flags = IFF_TAP | IFF_NO_PI; strncpy(ifr.ifr_name, dev, IFNAMSIZ); if (ioctl(fd, TUNSETIFF, (void*) &ifr) < 0) { - perror("TUNSETIFF failed"); - exit(1); + fatal("TUNSETIFF failed"); } int persist = 1; if (ioctl(fd, TUNSETPERSIST, persist) < 0) { - perror("TUNSETPERSIST failed"); - exit(1); + fatal("TUNSETPERSIST failed"); } syslog(LOG_INFO, "successfully created TAP device %s", dev); return fd; @@ -67,57 +71,14 @@ void set_macaddr(const char *dev, uint8_t *mac) { ifq.ifr_hwaddr.sa_family = ARPHRD_ETHER; if (ioctl(fd, SIOCSIFHWADDR, &ifq) == -1) { - perror("SIOCSIFHWADDR failed"); - exit(1); + fatal("SIOCSIFHWADDR failed"); } close(fd); } -#define SVR_BUF_LEN (3 * 4096) -#define MAX_BUF_LEN (2 * 1024 * 1024) - -/* Helper macros for parsing/printing GUIDs */ -#define GUID_FMT "%08x-%04hx-%04hx-%02x%02x-%02x%02x%02x%02x%02x%02x" -#define GUID_ARGS(_g) \ - (_g).Data1, (_g).Data2, (_g).Data3, \ - (_g).Data4[0], (_g).Data4[1], (_g).Data4[2], (_g).Data4[3], \ - (_g).Data4[4], (_g).Data4[5], (_g).Data4[6], (_g).Data4[7] -#define GUID_SARGS(_g) \ - &(_g).Data1, &(_g).Data2, &(_g).Data3, \ - &(_g).Data4[0], &(_g).Data4[1], &(_g).Data4[2], &(_g).Data4[3], \ - &(_g).Data4[4], &(_g).Data4[5], &(_g).Data4[6], &(_g).Data4[7] - - -int parseguid(const char *s, GUID *g) -{ - int res; - int p0, p1, p2, p3, p4, p5, p6, p7; - - res = sscanf(s, GUID_FMT, - &g->Data1, &g->Data2, &g->Data3, - &p0, &p1, &p2, &p3, &p4, &p5, &p6, &p7); - if (res != 11) - return 1; - g->Data4[0] = p0; - g->Data4[1] = p1; - g->Data4[2] = p2; - g->Data4[3] = p3; - g->Data4[4] = p4; - g->Data4[5] = p5; - g->Data4[6] = p6; - g->Data4[7] = p7; - return 0; -} - -/* Slightly different error handling between Windows and Linux */ -void sockerr(const char *msg) -{ - syslog(LOG_CRIT, "%s Error: %d. %s", msg, errno, strerror(errno)); -} - -void negotiate(SOCKET fd, struct vif_info *vif) +void negotiate(int fd, struct vif_info *vif) { /* Negotiate with com.docker.slirp */ struct init_message *me = create_init_message(); @@ -146,14 +107,13 @@ void negotiate(SOCKET fd, struct vif_info *vif) } return; err: - syslog(LOG_CRIT, "Failed to negotiate with com.docker.slirp"); - exit(1); + fatal("Failed to negotiate with com.docker.slirp"); } /* Argument passed to proxy threads */ struct connection { - SOCKET fd; /* Hyper-V socket with vmnet protocol */ + int fd; /* Hyper-V socket with vmnet protocol */ int tapfd; /* TAP device with ethernet frames */ struct vif_info vif; /* Contains VIF MAC, MTU etc, received from server */ }; @@ -167,8 +127,7 @@ static void* vmnet_to_tap(void *arg) for (;;) { if (really_read(connection->fd, &header[0], 2) == -1){ - syslog(LOG_CRIT, "Failed to read a packet header from host"); - exit(1); + fatal("Failed to read a packet header from host"); } length = (header[0] & 0xff) | ((header[1] & 0xff) << 8); if (length > sizeof(buffer)) { @@ -198,8 +157,7 @@ static void* tap_to_vmnet(void *arg) length = read(connection->tapfd, &buffer[0], sizeof(buffer)); if (length == -1) { if (errno == ENXIO) { - syslog(LOG_CRIT, "tap device has gone down"); - exit(0); + fatal("tap device has gone down"); } syslog(LOG_WARNING, "ignoring error %d", errno); /* This is what mirage-net-unix does. Is it a good idea really? */ @@ -208,20 +166,19 @@ static void* tap_to_vmnet(void *arg) header[0] = (length >> 0) & 0xff; header[1] = (length >> 8) & 0xff; if (really_write(connection->fd, &header[0], 2) == -1){ - syslog(LOG_CRIT, "Failed to write packet header"); - exit(1); + fatal("Failed to write packet header"); } if (really_write(connection->fd, &buffer[0], length) == -1) { - syslog(LOG_CRIT, "Failed to write packet body"); - exit(1); + fatal("Failed to write packet body"); } } + return NULL; } /* Handle a connection. Handshake with the com.docker.slirp process and start * exchanging ethernet frames between the socket and the tap device. */ -static void handle(SOCKET fd, char *tap, int tapfd) +static void handle(int fd, char *tap, int tapfd) { struct connection connection; pthread_t v2t, t2v; @@ -237,32 +194,27 @@ static void handle(SOCKET fd, char *tap, int tapfd) connection.tapfd = tapfd; if (pthread_create(&v2t, NULL, vmnet_to_tap, &connection) != 0){ - syslog(LOG_CRIT, "Failed to create the vmnet_to_tap thread"); - exit(1); + fatal("Failed to create the vmnet_to_tap thread"); } if (pthread_create(&t2v, NULL, tap_to_vmnet, &connection) != 0){ - syslog(LOG_CRIT, "Failed to create the tap_to_vmnet thread"); - exit(1); + fatal("Failed to create the tap_to_vmnet thread"); } if (pthread_join(v2t, NULL) != 0){ - syslog(LOG_CRIT, "Failed to join the vmnet_to_tap thread"); - exit(1); + fatal("Failed to join the vmnet_to_tap thread"); } if (pthread_join(t2v, NULL) != 0){ - syslog(LOG_CRIT, "Failed to join the tap_to_vmnet thread"); - exit(1); + fatal("Failed to join the tap_to_vmnet thread"); } } static int create_listening_socket(GUID serviceid) { - SOCKET lsock = INVALID_SOCKET; + int lsock = -1; SOCKADDR_HV sa; int res; lsock = socket(AF_HYPERV, SOCK_STREAM, HV_PROTOCOL_RAW); - if (lsock == INVALID_SOCKET) { - sockerr("socket()"); - exit(1); + if (lsock == -1) { + fatal("socket()"); } sa.Family = AF_HYPERV; @@ -271,30 +223,25 @@ static int create_listening_socket(GUID serviceid) { sa.ServiceId = serviceid; res = bind(lsock, (const struct sockaddr *)&sa, sizeof(sa)); - if (res == SOCKET_ERROR) { - sockerr("bind()"); - closesocket(lsock); - exit(1); + if (res == -1) { + fatal("bind()"); } res = listen(lsock, SOMAXCONN); - if (res == SOCKET_ERROR) { - sockerr("listen()"); - closesocket(lsock); - exit(1); + if (res == -1) { + fatal("listen()"); } return lsock; } static int connect_socket(GUID serviceid) { - SOCKET sock = INVALID_SOCKET; + int sock = -1; SOCKADDR_HV sa; int res; sock = socket(AF_HYPERV, SOCK_STREAM, HV_PROTOCOL_RAW); - if (sock == INVALID_SOCKET) { - sockerr("socket()"); - exit(1); + if (sock == -1) { + fatal("socket()"); } sa.Family = AF_HYPERV; @@ -303,28 +250,24 @@ static int connect_socket(GUID serviceid) { sa.ServiceId = serviceid; res = connect(sock, (const struct sockaddr *)&sa, sizeof(sa)); - if (res == SOCKET_ERROR) { - sockerr("connect()"); - closesocket(sock); - exit(1); + if (res == -1) { + fatal("connect()"); } return sock; } -static int accept_socket(SOCKET lsock) { - SOCKET csock = INVALID_SOCKET; +static int accept_socket(int lsock) { + int csock = -1; SOCKADDR_HV sac; socklen_t socklen = sizeof(sac); csock = accept(lsock, (struct sockaddr *)&sac, &socklen); - if (csock == INVALID_SOCKET) { - sockerr("accept()"); - closesocket(lsock); - exit(1); + if (csock == -1) { + fatal("accept()"); } - printf("Connect from: "GUID_FMT":"GUID_FMT"\n", + syslog(LOG_INFO, "Connect from: "GUID_FMT":"GUID_FMT"\n", GUID_ARGS(sac.VmId), GUID_ARGS(sac.ServiceId)); return csock; } @@ -336,8 +279,7 @@ void write_pidfile(const char *pidfile) { int len; if (asprintf(&pid_s, "%lld", (long long) pid) == -1) { - syslog(LOG_CRIT, "Failed to allocate pidfile string"); - exit(1); + fatal("Failed to allocate pidfile string"); } len = strlen(pid_s); file = fopen(pidfile, "w"); @@ -347,8 +289,7 @@ void write_pidfile(const char *pidfile) { } if (fwrite(pid_s, 1, len, file) != len) { - syslog(LOG_CRIT, "Failed to write pid to pidfile"); - exit(1); + fatal("Failed to write pid to pidfile"); } fclose(file); free(pid_s); @@ -357,18 +298,15 @@ void write_pidfile(const char *pidfile) { void daemonize(const char *pidfile){ pid_t pid = fork (); if (pid == -1) { - syslog(LOG_CRIT, "Failed to fork()"); - exit(1); + fatal("Failed to fork()"); } else if (pid != 0) exit(0); if (setsid () == -1) { - syslog(LOG_CRIT, "Failed to setsid()"); - exit(1); + fatal("Failed to setsid()"); } if (chdir ("/") == -1) { - syslog(LOG_CRIT, "Failed to chdir()"); - exit(1); + fatal("Failed to chdir()"); } int null = open("/dev/null", O_RDWR); dup2(null, STDIN_FILENO); @@ -394,7 +332,7 @@ void usage(char *name) printf("\t--connect: connect to the parent partition\n"); } -int __cdecl main(int argc, char **argv) +int main(int argc, char **argv) { int res = 0; GUID sid; @@ -462,10 +400,10 @@ int __cdecl main(int argc, char **argv) exit(1); } - SOCKET sock = INVALID_SOCKET; + int sock = -1; if (listen_flag) { syslog(LOG_INFO, "starting in listening mode with serviceid=%s and tap=%s", serviceid, tap); - SOCKET lsocket = create_listening_socket(sid); + int lsocket = create_listening_socket(sid); sock = accept_socket(lsocket); } else { syslog(LOG_INFO, "starting in connect mode with serviceid=%s and tap=%s", serviceid, tap);