]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
streams: Add support for AF_VSOCK sockets on Linux
authorThomas Egerer <thomas.egerer@secunet.com>
Tue, 30 Apr 2024 12:20:57 +0000 (14:20 +0200)
committerTobias Brunner <tobias@strongswan.org>
Fri, 17 May 2024 12:00:12 +0000 (14:00 +0200)
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 <thomas.egerer@secunet.com>
configure.ac
src/libstrongswan/Makefile.am
src/libstrongswan/networking/streams/stream_manager.c
src/libstrongswan/networking/streams/stream_service_vsock.c [new file with mode: 0644]
src/libstrongswan/networking/streams/stream_service_vsock.h [new file with mode: 0644]
src/libstrongswan/networking/streams/stream_vsock.c [new file with mode: 0644]
src/libstrongswan/networking/streams/stream_vsock.h [new file with mode: 0644]

index f6e8701d07e0d410c1d8547da0edcd28d716b608..2eaeb0f5a66acbd643fe14863e1060cc668d3c09 100644 (file)
@@ -713,6 +713,11 @@ AC_CHECK_HEADERS([netinet/ip6.h linux/fib_rules.h], [], [],
        #include <sys/types.h>
        #include <netinet/in.h>
 ])
+AC_CHECK_HEADERS([linux/vm_sockets.h], [have_vm_sockets=true], [],
+[
+       #include <sys/socket.h>
+])
+AM_CONDITIONAL(USE_VM_SOCKETS, [test "x$have_vm_sockets" = xtrue])
 
 AC_CHECK_MEMBERS([struct sockaddr.sa_len], [], [],
 [
index e28a9b765a9bcd38c5f22e1c3360d1f0769b6e52..66ee7b5ed9c8b90315131e392dc2cd73b04850ac 100644 (file)
@@ -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
index 63d3db1d076d1682f37e5c7b4bc0fe80acdd8228..e30b3b42925517544261e5d696ade8d66ba8af5d 100644 (file)
 # 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 (file)
index 0000000..586830e
--- /dev/null
@@ -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 <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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 <library.h>
+
+#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 (file)
index 0000000..1c7b8c8
--- /dev/null
@@ -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 <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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 (file)
index 0000000..4cfab42
--- /dev/null
@@ -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 <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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 <errno.h>
+#include <limits.h>
+#include <sys/socket.h>
+#include <linux/vm_sockets.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <library.h>
+
+#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 (file)
index 0000000..14ef11a
--- /dev/null
@@ -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 <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * 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_ @}*/