FreeRDP/libfreerdp/core/listener.c

550 lines
13 KiB
C
Raw Permalink Normal View History

2011-08-18 12:06:32 +04:00
/**
2012-10-09 07:02:04 +04:00
* FreeRDP: A Remote Desktop Protocol Implementation
2011-08-18 12:06:32 +04:00
* RDP Server Listener
*
* Copyright 2011 Vic Lee
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
2022-02-16 13:20:38 +03:00
#include <freerdp/config.h>
2011-08-18 12:06:32 +04:00
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
2017-11-14 18:10:52 +03:00
#include <errno.h>
#include <winpr/crt.h>
2014-02-11 07:12:13 +04:00
#include <winpr/windows.h>
#include <freerdp/log.h>
2011-08-18 12:06:32 +04:00
#ifndef _WIN32
#include <netdb.h>
#include <unistd.h>
#include <sys/un.h>
2011-08-18 12:06:32 +04:00
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <net/if.h>
2011-08-18 12:06:32 +04:00
#endif
#if defined(HAVE_AF_VSOCK_H)
#include <ctype.h>
#include <linux/vm_sockets.h>
#endif
#include <winpr/handle.h>
2011-08-18 12:06:32 +04:00
#include "listener.h"
#include "utils.h"
2011-08-18 12:06:32 +04:00
#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)
{
char ebuffer[256] = { 0 };
WLog_ERR(TAG, "Error creating socket: %s", winpr_strerror(errno, ebuffer, sizeof(ebuffer)));
return FALSE;
}
const int flags = fcntl(sockfd, F_GETFL, 0);
if (fcntl(sockfd, F_SETFL, flags | O_NONBLOCK) == -1)
{
char ebuffer[256] = { 0 };
WLog_ERR(TAG, "Error making socket nonblocking: %s",
winpr_strerror(errno, ebuffer, sizeof(ebuffer)));
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))
{
char ebuffer[256] = { 0 };
WLog_ERR(TAG, "could not extract port from '%s', value=%ul, error=%s", bind_address, val,
winpr_strerror(errno, ebuffer, sizeof(ebuffer)));
return FALSE;
}
addr.svm_cid = val;
if (bind(sockfd, (struct sockaddr*)&addr, sizeof(struct sockaddr_vm)) == -1)
{
char ebuffer[256] = { 0 };
WLog_ERR(TAG, "Error binding vsock at cid %d port %d: %s", addr.svm_cid, port,
winpr_strerror(errno, ebuffer, sizeof(ebuffer)));
closesocket((SOCKET)sockfd);
return FALSE;
}
if (listen(sockfd, 10) == -1)
{
char ebuffer[256] = { 0 };
WLog_ERR(TAG, "Error listening to socket at cid %d port %d: %s", addr.svm_cid, port,
winpr_strerror(errno, ebuffer, sizeof(ebuffer)));
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)
2011-08-18 12:06:32 +04:00
{
2018-09-27 17:08:28 +03:00
int ai_flags = 0;
int status = 0;
int sockfd = 0;
char addr[64];
void* sin_addr = NULL;
int option_value = 0;
struct addrinfo* res = NULL;
2019-11-06 17:24:51 +03:00
rdpListener* listener = (rdpListener*)instance->listener;
#ifdef _WIN32
u_long arg;
#endif
2012-06-08 03:51:00 +04:00
if (!bind_address)
2018-09-27 17:08:28 +03:00
ai_flags = AI_PASSIVE;
2011-08-18 12:06:32 +04:00
if (utils_is_vsock(bind_address))
{
bind_address = utils_is_vsock(bind_address);
return freerdp_listener_open_from_vsock(instance, bind_address, port);
}
2018-09-27 17:08:28 +03:00
res = freerdp_tcp_resolve_host(bind_address, port, ai_flags);
2012-06-08 03:51:00 +04:00
2018-09-27 17:08:28 +03:00
if (!res)
return FALSE;
2011-08-18 12:06:32 +04:00
for (struct addrinfo* ai = res; ai && (listener->num_sockfds < 5); ai = ai->ai_next)
2011-08-18 12:06:32 +04:00
{
if ((ai->ai_family != AF_INET) && (ai->ai_family != AF_INET6))
2011-08-18 12:06:32 +04:00
continue;
2015-05-08 11:05:39 +03:00
if (listener->num_sockfds == MAX_LISTENER_HANDLES)
{
WLog_ERR(TAG, "too many listening sockets");
continue;
}
2011-08-18 12:06:32 +04:00
sockfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
2012-06-08 03:51:00 +04:00
2011-08-18 12:06:32 +04:00
if (sockfd == -1)
{
WLog_ERR(TAG, "socket");
2011-08-18 12:06:32 +04:00
continue;
}
option_value = 1;
if (ai->ai_family == AF_INET)
2019-11-06 17:24:51 +03:00
sin_addr = &(((struct sockaddr_in*)ai->ai_addr)->sin_addr);
else
{
2019-11-06 17:24:51 +03:00
sin_addr = &(((struct sockaddr_in6*)ai->ai_addr)->sin6_addr);
if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, (void*)&option_value,
sizeof(option_value)) == -1)
WLog_ERR(TAG, "setsockopt");
}
inet_ntop(ai->ai_family, sin_addr, addr, sizeof(addr));
2019-11-06 17:24:51 +03:00
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (void*)&option_value,
sizeof(option_value)) == -1)
2024-04-12 14:16:40 +03:00
WLog_ERR(TAG, "setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR)");
#ifndef _WIN32
2024-04-12 14:16:40 +03:00
if (fcntl(sockfd, F_SETFL, O_NONBLOCK) != 0)
WLog_ERR(TAG, "fcntl(sockfd, F_SETFL, O_NONBLOCK)");
#else
arg = 1;
ioctlsocket(sockfd, FIONBIO, &arg);
#endif
2019-11-06 17:24:51 +03:00
status = _bind((SOCKET)sockfd, ai->ai_addr, ai->ai_addrlen);
2012-06-08 03:51:00 +04:00
2011-08-18 12:06:32 +04:00
if (status != 0)
{
2019-11-06 17:24:51 +03:00
closesocket((SOCKET)sockfd);
2011-08-18 12:06:32 +04:00
continue;
}
2019-11-06 17:24:51 +03:00
status = _listen((SOCKET)sockfd, 10);
2012-06-08 03:51:00 +04:00
2011-08-18 12:06:32 +04:00
if (status != 0)
{
WLog_ERR(TAG, "listen");
2019-11-06 17:24:51 +03:00
closesocket((SOCKET)sockfd);
2011-08-18 12:06:32 +04:00
continue;
}
2014-08-16 02:12:53 +04:00
/* FIXME: these file descriptors do not work on Windows */
listener->sockfds[listener->num_sockfds] = sockfd;
listener->events[listener->num_sockfds] = WSACreateEvent();
2017-11-14 18:10:52 +03:00
if (!listener->events[listener->num_sockfds])
{
listener->num_sockfds = 0;
break;
}
2017-11-14 18:10:52 +03:00
2019-11-06 17:24:51 +03:00
WSAEventSelect(sockfd, listener->events[listener->num_sockfds],
FD_READ | FD_ACCEPT | FD_CLOSE);
listener->num_sockfds++;
WLog_INFO(TAG, "Listening on [%s]:%" PRIu16, addr, port);
2011-08-18 12:06:32 +04:00
}
freeaddrinfo(res);
return (listener->num_sockfds > 0 ? TRUE : FALSE);
2011-08-18 12:06:32 +04:00
}
static BOOL freerdp_listener_open_local(freerdp_listener* instance, const char* path)
{
#ifndef _WIN32
int status = 0;
int sockfd = 0;
struct sockaddr_un addr = { 0 };
2019-11-06 17:24:51 +03:00
rdpListener* listener = (rdpListener*)instance->listener;
HANDLE hevent = NULL;
2015-05-08 11:05:39 +03:00
if (listener->num_sockfds == MAX_LISTENER_HANDLES)
{
WLog_ERR(TAG, "too many listening sockets");
return FALSE;
}
sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
2012-06-08 03:51:00 +04:00
if (sockfd == -1)
{
WLog_ERR(TAG, "socket");
return FALSE;
}
int rc = fcntl(sockfd, F_SETFL, O_NONBLOCK);
if (rc != 0)
{
WLog_ERR(TAG, "fcntl(sockfd, F_SETFL, O_NONBLOCK)");
closesocket((SOCKET)sockfd);
return FALSE;
}
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1);
unlink(path);
2019-11-06 17:24:51 +03:00
status = _bind(sockfd, (struct sockaddr*)&addr, sizeof(addr));
2012-06-08 03:51:00 +04:00
if (status != 0)
{
WLog_ERR(TAG, "bind");
2019-11-06 17:24:51 +03:00
closesocket((SOCKET)sockfd);
return FALSE;
}
status = _listen(sockfd, 10);
2012-06-08 03:51:00 +04:00
if (status != 0)
{
WLog_ERR(TAG, "listen");
2019-11-06 17:24:51 +03:00
closesocket((SOCKET)sockfd);
return FALSE;
}
hevent = CreateFileDescriptorEvent(NULL, FALSE, FALSE, sockfd, WINPR_FD_READ);
2017-11-14 18:10:52 +03:00
2015-07-03 10:36:58 +03:00
if (!hevent)
{
WLog_ERR(TAG, "failed to create sockfd event");
2019-11-06 17:24:51 +03:00
closesocket((SOCKET)sockfd);
return FALSE;
}
listener->sockfds[listener->num_sockfds] = sockfd;
listener->events[listener->num_sockfds] = hevent;
listener->num_sockfds++;
WLog_INFO(TAG, "Listening on socket %s.", addr.sun_path);
return TRUE;
#else
return TRUE;
#endif
}
static BOOL freerdp_listener_open_from_socket(freerdp_listener* instance, int fd)
{
#ifndef _WIN32
2019-11-06 17:24:51 +03:00
rdpListener* listener = (rdpListener*)instance->listener;
2015-05-08 11:05:39 +03:00
if (listener->num_sockfds == MAX_LISTENER_HANDLES)
{
WLog_ERR(TAG, "too many listening sockets");
return FALSE;
}
if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
return FALSE;
listener->sockfds[listener->num_sockfds] = fd;
listener->events[listener->num_sockfds] = WSACreateEvent();
2017-11-14 18:10:52 +03:00
if (!listener->events[listener->num_sockfds])
return FALSE;
WSAEventSelect(fd, listener->events[listener->num_sockfds], FD_READ | FD_ACCEPT | FD_CLOSE);
listener->num_sockfds++;
WLog_INFO(TAG, "Listening on socket %d.", fd);
return TRUE;
2015-05-08 11:07:29 +03:00
#else
return FALSE;
#endif
}
2011-08-18 12:06:32 +04:00
static void freerdp_listener_close(freerdp_listener* instance)
{
2019-11-06 17:24:51 +03:00
rdpListener* listener = (rdpListener*)instance->listener;
2011-08-18 12:06:32 +04:00
for (int i = 0; i < listener->num_sockfds; i++)
2011-08-18 12:06:32 +04:00
{
2019-11-06 17:24:51 +03:00
closesocket((SOCKET)listener->sockfds[i]);
2024-09-16 05:58:36 +03:00
(void)CloseHandle(listener->events[i]);
2011-08-18 12:06:32 +04:00
}
2011-08-18 12:06:32 +04:00
listener->num_sockfds = 0;
}
#if defined(WITH_FREERDP_DEPRECATED)
static BOOL freerdp_listener_get_fds(freerdp_listener* instance, void** rfds, int* rcount)
2011-08-18 12:06:32 +04:00
{
2019-11-06 17:24:51 +03:00
rdpListener* listener = (rdpListener*)instance->listener;
2011-08-18 12:06:32 +04:00
if (listener->num_sockfds < 1)
return FALSE;
2011-08-18 12:06:32 +04:00
for (int index = 0; index < listener->num_sockfds; index++)
2011-08-18 12:06:32 +04:00
{
rfds[*rcount] = (void*)(long)(listener->sockfds[index]);
2011-08-18 12:06:32 +04:00
(*rcount)++;
}
return TRUE;
2011-08-18 12:06:32 +04:00
}
#endif
2011-08-18 12:06:32 +04:00
2019-11-20 13:30:14 +03:00
static DWORD freerdp_listener_get_event_handles(freerdp_listener* instance, HANDLE* events,
DWORD nCount)
{
2019-11-06 17:24:51 +03:00
rdpListener* listener = (rdpListener*)instance->listener;
if (listener->num_sockfds < 1)
return 0;
2019-02-07 16:22:28 +03:00
if (listener->num_sockfds > (INT64)nCount)
return 0;
for (int index = 0; index < listener->num_sockfds; index++)
{
2015-04-21 16:10:17 +03:00
events[index] = listener->events[index];
}
return listener->num_sockfds;
}
BOOL freerdp_peer_set_local_and_hostname(freerdp_peer* client,
const struct sockaddr_storage* peer_addr)
{
2022-04-27 22:02:18 +03:00
const void* sin_addr = NULL;
const BYTE localhost6_bytes[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
WINPR_ASSERT(client);
WINPR_ASSERT(peer_addr);
if (peer_addr->ss_family == AF_INET)
{
2022-04-27 22:02:18 +03:00
const UINT32* usin_addr = sin_addr = &(((const struct sockaddr_in*)peer_addr)->sin_addr);
2022-04-27 22:02:18 +03:00
if ((*usin_addr) == 0x0100007f)
client->local = TRUE;
}
else if (peer_addr->ss_family == AF_INET6)
{
2022-04-27 22:02:18 +03:00
const struct sockaddr_in6* usin_addr = sin_addr =
&(((const struct sockaddr_in6*)peer_addr)->sin6_addr);
2022-04-27 22:02:18 +03:00
if (memcmp(usin_addr, localhost6_bytes, 16) == 0)
client->local = TRUE;
}
#ifndef _WIN32
#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)
#endif
client->local = TRUE;
#endif
if (client->local)
WLog_INFO(TAG, "Accepting client from localhost");
if (sin_addr)
inet_ntop(peer_addr->ss_family, sin_addr, client->hostname, sizeof(client->hostname));
return TRUE;
}
static BOOL freerdp_check_and_create_client(freerdp_listener* instance, int peer_sockfd,
const struct sockaddr_storage* peer_addr)
{
WINPR_ASSERT(instance);
WINPR_ASSERT(peer_sockfd >= 0);
WINPR_ASSERT(peer_addr);
const BOOL check = IFCALLRESULT(TRUE, instance->CheckPeerAcceptRestrictions, instance);
if (!check)
{
closesocket((SOCKET)peer_sockfd);
return TRUE;
}
freerdp_peer* client = freerdp_peer_new(peer_sockfd);
if (!client)
{
closesocket((SOCKET)peer_sockfd);
return FALSE;
}
if (!freerdp_peer_set_local_and_hostname(client, peer_addr))
{
freerdp_peer_free(client);
return FALSE;
}
const BOOL peer_accepted = IFCALLRESULT(FALSE, instance->PeerAccepted, instance, client);
if (!peer_accepted)
{
WLog_ERR(TAG, "PeerAccepted callback failed");
freerdp_peer_free(client);
}
return TRUE;
}
static BOOL freerdp_listener_check_fds(freerdp_listener* instance)
2011-08-18 12:06:32 +04:00
{
2019-11-06 17:24:51 +03:00
rdpListener* listener = (rdpListener*)instance->listener;
2011-08-18 12:06:32 +04:00
if (listener->num_sockfds < 1)
return FALSE;
2011-08-18 12:06:32 +04:00
for (int i = 0; i < listener->num_sockfds; i++)
2011-08-18 12:06:32 +04:00
{
struct sockaddr_storage peer_addr = { 0 };
2024-09-16 05:53:18 +03:00
(void)WSAResetEvent(listener->events[i]);
int peer_addr_size = sizeof(peer_addr);
int peer_sockfd =
_accept(listener->sockfds[i], (struct sockaddr*)&peer_addr, &peer_addr_size);
2011-08-18 12:06:32 +04:00
if (peer_sockfd == -1)
{
2021-09-17 10:25:57 +03:00
char buffer[8192] = { 0 };
#ifdef _WIN32
int wsa_error = WSAGetLastError();
/* No data available */
if (wsa_error == WSAEWOULDBLOCK)
continue;
2017-11-14 18:10:52 +03:00
#else
2017-11-14 18:10:52 +03:00
2011-08-18 12:06:32 +04:00
if (errno == EAGAIN || errno == EWOULDBLOCK)
continue;
2017-11-14 18:10:52 +03:00
#endif
2021-09-17 10:25:57 +03:00
WLog_WARN(TAG, "accept failed with %s", winpr_strerror(errno, buffer, sizeof(buffer)));
return FALSE;
2011-08-18 12:06:32 +04:00
}
if (!freerdp_check_and_create_client(instance, peer_sockfd, &peer_addr))
return FALSE;
2011-08-18 12:06:32 +04:00
}
return TRUE;
2011-08-18 12:06:32 +04:00
}
freerdp_listener* freerdp_listener_new(void)
{
freerdp_listener* instance = NULL;
rdpListener* listener = NULL;
2019-11-06 17:24:51 +03:00
instance = (freerdp_listener*)calloc(1, sizeof(freerdp_listener));
if (!instance)
return NULL;
2011-08-18 12:06:32 +04:00
instance->Open = freerdp_listener_open;
instance->OpenLocal = freerdp_listener_open_local;
instance->OpenFromSocket = freerdp_listener_open_from_socket;
#if defined(WITH_FREERDP_DEPRECATED)
2011-08-18 12:06:32 +04:00
instance->GetFileDescriptor = freerdp_listener_get_fds;
#endif
instance->GetEventHandles = freerdp_listener_get_event_handles;
2011-08-18 12:06:32 +04:00
instance->CheckFileDescriptor = freerdp_listener_check_fds;
instance->Close = freerdp_listener_close;
2019-11-06 17:24:51 +03:00
listener = (rdpListener*)calloc(1, sizeof(rdpListener));
if (!listener)
2014-11-17 02:36:50 +03:00
{
2017-11-14 18:10:52 +03:00
free(instance);
return NULL;
2014-11-17 02:36:50 +03:00
}
2011-08-18 12:06:32 +04:00
listener->instance = instance;
2019-11-06 17:24:51 +03:00
instance->listener = (void*)listener;
2011-08-18 12:06:32 +04:00
return instance;
}
void freerdp_listener_free(freerdp_listener* instance)
{
if (instance)
{
free(instance->listener);
free(instance);
}
2011-08-18 12:06:32 +04:00
}