From: Thomas Egerer Date: Tue, 30 Apr 2024 12:20:57 +0000 (+0200) Subject: streams: Add support for AF_VSOCK sockets on Linux X-Git-Tag: android-2.5.2~23 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3d7d527ad9a5fe4f88565744b686d4a91eaea6e0;p=thirdparty%2Fstrongswan.git streams: Add support for AF_VSOCK sockets on Linux These allow, for instance, a vici client on a host to communicate with an IKE daemon running in a VM. Signed-off-by: Thomas Egerer --- diff --git a/configure.ac b/configure.ac index f6e8701d07..2eaeb0f5a6 100644 --- a/configure.ac +++ b/configure.ac @@ -713,6 +713,11 @@ AC_CHECK_HEADERS([netinet/ip6.h linux/fib_rules.h], [], [], #include #include ]) +AC_CHECK_HEADERS([linux/vm_sockets.h], [have_vm_sockets=true], [], +[ + #include +]) +AM_CONDITIONAL(USE_VM_SOCKETS, [test "x$have_vm_sockets" = xtrue]) AC_CHECK_MEMBERS([struct sockaddr.sa_len], [], [], [ diff --git a/src/libstrongswan/Makefile.am b/src/libstrongswan/Makefile.am index e28a9b765a..66ee7b5ed9 100644 --- a/src/libstrongswan/Makefile.am +++ b/src/libstrongswan/Makefile.am @@ -62,6 +62,12 @@ if !USE_WINDOWS networking/streams/stream_service_unix.c endif +if USE_VM_SOCKETS + libstrongswan_la_SOURCES += \ + networking/streams/stream_vsock.c \ + networking/streams/stream_service_vsock.c +endif + # private header files noinst_HEADERS = \ settings/settings_types.h @@ -133,6 +139,11 @@ utils/utils/strerror.h utils/compat/windows.h utils/compat/apple.h utils/compat/ utils/utils/atomics.h utils/utils/types.h utils/utils/byteorder.h \ utils/utils/string.h utils/utils/memory.h utils/utils/tty.h utils/utils/path.h \ utils/utils/status.h utils/utils/object.h utils/utils/time.h utils/utils/align.h +if USE_VM_SOCKETS + nobase_strongswan_include_HEADERS += \ + networking/streams/stream_vsock.h \ + networking/streams/stream_service_vsock.h +endif endif library.lo : $(top_builddir)/config.status diff --git a/src/libstrongswan/networking/streams/stream_manager.c b/src/libstrongswan/networking/streams/stream_manager.c index 63d3db1d07..e30b3b4292 100644 --- a/src/libstrongswan/networking/streams/stream_manager.c +++ b/src/libstrongswan/networking/streams/stream_manager.c @@ -22,6 +22,10 @@ # include "stream_unix.h" # include "stream_service_unix.h" #endif +#ifdef HAVE_LINUX_VM_SOCKETS_H +# include "stream_vsock.h" +# include "stream_service_vsock.h" +#endif #ifdef USE_SYSTEMD # include "stream_service_systemd.h" #endif @@ -210,6 +214,10 @@ METHOD(stream_manager_t, destroy, void, remove_stream(this, stream_create_unix); remove_service(this, stream_service_create_unix); #endif +#ifdef HAVE_LINUX_VM_SOCKETS_H + remove_stream(this, stream_create_vsock); + remove_service(this, stream_service_create_vsock); +#endif #ifdef USE_SYSTEMD remove_service(this, stream_service_create_systemd); #endif @@ -248,6 +256,10 @@ stream_manager_t *stream_manager_create() add_stream(this, "unix://", stream_create_unix); add_service(this, "unix://", stream_service_create_unix); #endif +#ifdef HAVE_LINUX_VM_SOCKETS_H + add_stream(this, "vsock://", stream_create_vsock); + add_service(this, "vsock://", stream_service_create_vsock); +#endif #ifdef USE_SYSTEMD add_service(this, "systemd://", stream_service_create_systemd); #endif diff --git a/src/libstrongswan/networking/streams/stream_service_vsock.c b/src/libstrongswan/networking/streams/stream_service_vsock.c new file mode 100644 index 0000000000..586830e5e7 --- /dev/null +++ b/src/libstrongswan/networking/streams/stream_service_vsock.c @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2024 Thomas Egerer + * + * Copyright (C) secunet Security Networks AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include + +#include "stream_service_vsock.h" +#include "stream_vsock.h" + +/* + * Described in header + */ +stream_service_t *stream_service_create_vsock(char *uri, int backlog) +{ + int fd = stream_initialize_socket_vsock(uri, &backlog); + + return (fd == -1) ? NULL : stream_service_create_from_fd(fd); +} diff --git a/src/libstrongswan/networking/streams/stream_service_vsock.h b/src/libstrongswan/networking/streams/stream_service_vsock.h new file mode 100644 index 0000000000..1c7b8c8321 --- /dev/null +++ b/src/libstrongswan/networking/streams/stream_service_vsock.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2024 Thomas Egerer + * + * Copyright (C) secunet Security Networks AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup stream_service_vsock stream_service_vsock + * @{ @ingroup stream + */ + +#ifndef STREAM_SERVICE_VSOCK_H_ +#define STREAM_SERVICE_VSOCK_H_ + +/** + * Create a service instance for VSOCK sockets. + * + * @param uri VSOCK socket specific URI, must start with "vsock://" + * @param backlog size of the backlog queue, as passed to listen() + * @return stream_service instance, NULL on failure + */ +stream_service_t *stream_service_create_vsock(char *uri, int backlog); + +#endif /** STREAM_SERVICE_VSOCK_H_ @}*/ diff --git a/src/libstrongswan/networking/streams/stream_vsock.c b/src/libstrongswan/networking/streams/stream_vsock.c new file mode 100644 index 0000000000..4cfab426ec --- /dev/null +++ b/src/libstrongswan/networking/streams/stream_vsock.c @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2024 Thomas Egerer + * + * Copyright (C) secunet Security Networks AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "stream_vsock.h" + +/** + * Helper function to parse a vsock:// URI to a sockaddr. + * Returns the length of the sockaddr or -1. + */ +static int stream_parse_uri_vsock(char *uri, struct sockaddr_vm *addr) +{ + unsigned long cid, port; + + if (!strpfx(uri, "vsock://")) + { + return -1; + } + + uri += strlen("vsock://"); + cid = strtoul(uri, &uri, 10); + + if (*uri != ':' || cid > UINT_MAX) + { + return -1; + } + + port = strtoul(uri + 1, &uri, 10); + if (port > UINT_MAX || *uri) + { + return -1; + } + + *addr = (struct sockaddr_vm){ + .svm_family = AF_VSOCK, + .svm_port = port, + .svm_cid = cid, + }; + return sizeof(*addr); +} + +/* + * Described in header + */ +int stream_initialize_socket_vsock(char *uri, int *backlog) +{ + int fd, len; + struct sockaddr_vm addr; + + len = stream_parse_uri_vsock(uri, &addr); + if (len == -1) + { + DBG1(DBG_NET, "invalid stream URI: '%s'", uri); + return -1; + } + + fd = socket(AF_VSOCK, SOCK_STREAM, 0); + if (fd == -1) + { + DBG1(DBG_NET, "opening socket '%s' failed: %s", uri, strerror(errno)); + return -1; + } + + if (backlog) + { + if (bind(fd, (struct sockaddr*)&addr, len) < 0) + { + DBG1(DBG_NET, "binding socket '%s' failed: %s", uri, + strerror(errno)); + close(fd); + return -1; + } + + if (listen(fd, *backlog) < 0) + { + DBG1(DBG_NET, "listen on socket '%s' failed: %s", uri, + strerror(errno)); + close(fd); + return -1; + } + } + else + { + if (connect(fd, (struct sockaddr*)&addr, len) < 0) + { + DBG1(DBG_NET, "connecting to '%s' failed: %s", uri, + strerror(errno)); + close(fd); + return -1; + } + } + return fd; +} + +/* + * Described in header + */ +stream_t *stream_create_vsock(char *uri) +{ + int fd = stream_initialize_socket_vsock(uri, NULL); + + return (fd == -1) ? NULL : stream_create_from_fd(fd); +} diff --git a/src/libstrongswan/networking/streams/stream_vsock.h b/src/libstrongswan/networking/streams/stream_vsock.h new file mode 100644 index 0000000000..14ef11a0f8 --- /dev/null +++ b/src/libstrongswan/networking/streams/stream_vsock.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2024 Thomas Egerer + * + * Copyright (C) secunet Security Networks AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup stream_vsock stream_vsock + * @{ @ingroup streams + */ + +#ifndef STREAM_VSOCK_H_ +#define STREAM_VSOCK_H_ + +/** + * Create a stream for VSOCK sockets. + * + * VSOCK URIs start with vsock://, followed by an integer address (context + * identifier, CID), followed by a colon separated port. CID as well as port + * are 32-bit unsigned integers. A full VSOCK uri looks something like: + * + * vsock://2:12345 + * + * There is no default port, so a colon after vsock:// is mandatory. + * + * @param uri VSOCK socket specific URI, must start with "vsock://" + * @return stream instance, NULL on failure + */ +stream_t *stream_create_vsock(char *uri); + +/** + * Create and initialize a VSOCK socket. + * + * @param uri VSOCK socket specific URI, must start with "vsock://" + * @param backlog pointer to value for backlog for listen(2) if a service + * socket shall be created (bind/listen); use NULL for a + * VSOCK socket that just connects to \p uri + * @return file descriptor for created socket, -1 on error + */ +int stream_initialize_socket_vsock(char *uri, int *backlog); + +#endif /** STREAM_VSOCK_H_ @}*/