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 <[email protected]>
This commit is contained in:
Thomas Egerer
2024-05-17 14:00:12 +02:00
committed by Tobias Brunner
parent 9228a5109b
commit 3d7d527ad9
7 changed files with 269 additions and 0 deletions
+5
View 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], [], [],
[
+11
View 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
@@ -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
@@ -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);
}
@@ -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_ @}*/
@@ -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);
}
@@ -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_ @}*/