5726 add vsock support for client and server

This commit is contained in:
Stefan Heinzel 2023-11-14 15:33:53 +00:00 committed by akallabeth
parent b77be28514
commit 52606929fb
7 changed files with 156 additions and 11 deletions

View File

@ -2315,7 +2315,13 @@ static int parse_host_options(rdpSettings* settings, const COMMAND_LINE_ARGUMENT
/* ipv4 */
if (!p)
{
p = strchr(arg->Value, ':');
const char scheme[] = "://";
const char* val = strstr(arg->Value, scheme);
if (val)
val += strnlen(scheme, sizeof(scheme));
else
val = arg->Value;
p = strchr(val, ':');
if (p)
{

View File

@ -187,4 +187,6 @@
#cmakedefine WITH_PROXY_MODULES
#cmakedefine WITH_PROXY_EMULATE_SMARTCARD
#cmakedefine HAVE_AF_VSOCK_H
#endif /* FREERDP_CONFIG_H */

View File

@ -18,6 +18,8 @@
set(MODULE_NAME "freerdp-core")
set(MODULE_PREFIX "FREERDP_CORE")
CHECK_INCLUDE_FILES("ctype.h;linux/vm_sockets.h" HAVE_AF_VSOCK_H)
freerdp_definition_add(-DEXT_PATH="${FREERDP_EXTENSION_PATH}")
freerdp_include_directory_add(${OPENSSL_INCLUDE_DIR})

View File

@ -40,12 +40,85 @@
#include <net/if.h>
#endif
#if defined(HAVE_AF_VSOCK_H)
#include <ctype.h>
#include <linux/vm_sockets.h>
#endif
#include <winpr/handle.h>
#include "listener.h"
#include "utils.h"
#define TAG FREERDP_TAG("core.listener")
static BOOL freerdp_listener_open_from_vsock(freerdp_listener* instance, const char* bind_address,
UINT16 port)
{
#if defined(HAVE_AF_VSOCK_H)
rdpListener* listener = (rdpListener*)instance->listener;
const int sockfd = socket(AF_VSOCK, SOCK_STREAM, 0);
if (sockfd == -1)
{
WLog_ERR(TAG, "Error creating socket: %s", strerror(errno));
return FALSE;
}
const int flags = fcntl(sockfd, F_GETFL, 0);
if (fcntl(sockfd, F_SETFL, flags | O_NONBLOCK) == -1)
{
WLog_ERR(TAG, "Error making socket nonblocking: %s", strerror(errno));
closesocket((SOCKET)sockfd);
return FALSE;
}
struct sockaddr_vm addr = { 0 };
addr.svm_family = AF_VSOCK;
addr.svm_port = port;
errno = 0;
char* ptr = NULL;
unsigned long val = strtoul(bind_address, &ptr, 10);
if (errno || (val > UINT32_MAX))
{
WLog_ERR(TAG, "could not extract port from '%s', value=%ul, error=%s", bind_address, val,
strerror(errno));
return FALSE;
}
addr.svm_cid = val;
if (bind(sockfd, (struct sockaddr*)&addr, sizeof(struct sockaddr_vm)) == -1)
{
WLog_ERR(TAG, "Error binding vsock at cid %d port %d: %s", addr.svm_cid, port,
strerror(errno));
closesocket((SOCKET)sockfd);
return FALSE;
}
if (listen(sockfd, 10) == -1)
{
WLog_ERR(TAG, "Error listening to socket at cid %d port %d: %s", addr.svm_cid, port,
strerror(errno));
closesocket((SOCKET)sockfd);
return FALSE;
}
listener->sockfds[listener->num_sockfds] = sockfd;
listener->events[listener->num_sockfds] = WSACreateEvent();
if (!listener->events[listener->num_sockfds])
{
listener->num_sockfds = 0;
}
WSAEventSelect(sockfd, listener->events[listener->num_sockfds], FD_READ | FD_ACCEPT | FD_CLOSE);
listener->num_sockfds++;
WLog_INFO(TAG, "Listening on %s:%d", bind_address, port);
return TRUE;
#else
WLog_ERR(TAG, "compiled without AF_VSOCK, '%s' not supported", bind_address);
return FALSE;
#endif
}
static BOOL freerdp_listener_open(freerdp_listener* instance, const char* bind_address, UINT16 port)
{
int ai_flags = 0;
@ -64,6 +137,12 @@ static BOOL freerdp_listener_open(freerdp_listener* instance, const char* bind_a
if (!bind_address)
ai_flags = AI_PASSIVE;
if (utils_is_vsock(bind_address))
{
bind_address = utils_is_vsock(bind_address);
return freerdp_listener_open_from_vsock(instance, bind_address, port);
}
res = freerdp_tcp_resolve_host(bind_address, port, ai_flags);
if (!res)
@ -322,7 +401,7 @@ BOOL freerdp_peer_set_local_and_hostname(freerdp_peer* client,
}
#ifndef _WIN32
#ifdef AF_VSOCK
#if defined(HAVE_AF_VSOCK_H)
else if (peer_addr->ss_family == AF_UNIX || peer_addr->ss_family == AF_VSOCK)
#else
else if (peer_addr->ss_family == AF_UNIX)

View File

@ -85,6 +85,11 @@
#include "tcp.h"
#include "../crypto/opensslcompat.h"
#if defined(HAVE_AF_VSOCK_H)
#include <ctype.h>
#include <linux/vm_sockets.h>
#endif
#define TAG FREERDP_TAG("core")
/* Simple Socket BIO */
@ -1090,6 +1095,7 @@ int freerdp_tcp_default_connect(rdpContext* context, rdpSettings* settings, cons
if (hostname[0] == '|')
useExternalDefinedSocket = TRUE;
const char* vsock = utils_is_vsock(hostname);
if (ipcSocket)
{
sockfd = freerdp_uds_connect(hostname);
@ -1103,6 +1109,40 @@ int freerdp_tcp_default_connect(rdpContext* context, rdpSettings* settings, cons
}
else if (useExternalDefinedSocket)
sockfd = port;
else if (vsock)
{
#if defined(HAVE_AF_VSOCK_H)
hostname = vsock;
sockfd = socket(AF_VSOCK, SOCK_STREAM, 0);
struct sockaddr_vm addr = { 0 };
addr.svm_family = AF_VSOCK;
addr.svm_port = port;
errno = 0;
char* ptr = NULL;
unsigned long val = strtoul(hostname, &ptr, 10);
if (errno || (val > UINT32_MAX))
{
WLog_ERR(TAG, "could not extract port from '%s', value=%ul, error=%s", hostname, val,
strerror(errno));
return -1;
}
addr.svm_cid = val;
if (addr.svm_cid == 2)
{
addr.svm_flags = VMADDR_FLAG_TO_HOST;
}
if ((connect(sockfd, (struct sockaddr*)&addr, sizeof(struct sockaddr_vm))) == -1)
{
WLog_ERR(TAG, "failed to connect to %s", hostname);
return -1;
}
#else
WLog_ERR(TAG, "Compiled without AF_VSOCK, '%s' not supported", hostname);
return -1;
#endif
}
else
{
sockfd = -1;
@ -1185,18 +1225,21 @@ int freerdp_tcp_default_connect(rdpContext* context, rdpSettings* settings, cons
}
}
free(settings->ClientAddress);
settings->ClientAddress = freerdp_tcp_get_ip_address(sockfd, &settings->IPv6Enabled);
if (!settings->ClientAddress)
if (!vsock)
{
if (!useExternalDefinedSocket)
close(sockfd);
free(settings->ClientAddress);
settings->ClientAddress = freerdp_tcp_get_ip_address(sockfd, &settings->IPv6Enabled);
freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_FAILED);
if (!settings->ClientAddress)
{
if (!useExternalDefinedSocket)
close(sockfd);
WLog_ERR(TAG, "Couldn't get socket ip address");
return -1;
freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_FAILED);
WLog_ERR(TAG, "Couldn't get socket ip address");
return -1;
}
}
optval = 1;

View File

@ -288,3 +288,14 @@ BOOL utils_abort_event_is_set(rdpRdp* rdp)
status = WaitForSingleObject(rdp->abortEvent, 0);
return status == WAIT_OBJECT_0;
}
const char* utils_is_vsock(const char* hostname)
{
if (!hostname)
return NULL;
const char vsock[8] = "vsock://";
if (strncmp(hostname, vsock, sizeof(vsock)) == 0)
return &hostname[sizeof(vsock)];
return NULL;
}

View File

@ -45,4 +45,6 @@ BOOL utils_sync_credentials(rdpSettings* settings, BOOL toGateway);
BOOL utils_str_is_empty(const char* str);
BOOL utils_str_copy(const char* value, char** dst);
const char* utils_is_vsock(const char* hostname);
#endif /* FREERDP_LIB_CORE_UTILS_H */