FreeRDP
Loading...
Searching...
No Matches
listener.c
1
20#include <freerdp/config.h>
21
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <fcntl.h>
26#include <errno.h>
27
28#include <winpr/crt.h>
29#include <winpr/windows.h>
30#include <freerdp/log.h>
31
32#ifdef _WIN32
33#include <afunix.h>
34#else
35#include <netdb.h>
36#include <unistd.h>
37#include <sys/un.h>
38#include <sys/ioctl.h>
39#include <sys/socket.h>
40#include <arpa/inet.h>
41#include <netinet/in.h>
42#include <net/if.h>
43#endif
44
45#if defined(HAVE_AF_VSOCK_H)
46#include <ctype.h>
47#include <linux/vm_sockets.h>
48#endif
49
50#include <winpr/handle.h>
51
52#include "listener.h"
53#include "utils.h"
54
55#define TAG FREERDP_TAG("core.listener")
56
57static BOOL freerdp_listener_open_from_vsock(WINPR_ATTR_UNUSED freerdp_listener* instance,
58 WINPR_ATTR_UNUSED const char* bind_address,
59 WINPR_ATTR_UNUSED UINT16 port)
60{
61#if defined(HAVE_AF_VSOCK_H)
62 rdpListener* listener = (rdpListener*)instance->listener;
63 const int sockfd = socket(AF_VSOCK, SOCK_STREAM, 0);
64 if (sockfd == -1)
65 {
66 char ebuffer[256] = WINPR_C_ARRAY_INIT;
67 WLog_ERR(TAG, "Error creating socket: %s", winpr_strerror(errno, ebuffer, sizeof(ebuffer)));
68 return FALSE;
69 }
70 const int flags = fcntl(sockfd, F_GETFL, 0);
71 if (fcntl(sockfd, F_SETFL, flags | O_NONBLOCK) == -1)
72 {
73 char ebuffer[256] = WINPR_C_ARRAY_INIT;
74 WLog_ERR(TAG, "Error making socket nonblocking: %s",
75 winpr_strerror(errno, ebuffer, sizeof(ebuffer)));
76 close(sockfd);
77 return FALSE;
78 }
79 struct sockaddr_vm addr = WINPR_C_ARRAY_INIT;
80
81 addr.svm_family = AF_VSOCK;
82 addr.svm_port = port;
83
84 errno = 0;
85 char* ptr = nullptr;
86 unsigned long val = strtoul(bind_address, &ptr, 10);
87 if (errno || (val > UINT32_MAX))
88 {
89 /* handle VMADDR_CID_ANY (-1U) */
90 if ((val == ULONG_MAX) && (errno == 0))
91 val = UINT32_MAX;
92 else
93 {
94 char ebuffer[256] = WINPR_C_ARRAY_INIT;
95 WLog_ERR(TAG, "could not extract port from '%s', value=%lu, error=%s", bind_address,
96 val, winpr_strerror(errno, ebuffer, sizeof(ebuffer)));
97 close(sockfd);
98 return FALSE;
99 }
100 }
101 addr.svm_cid = WINPR_ASSERTING_INT_CAST(unsigned int, val);
102 if (bind(sockfd, (struct sockaddr*)&addr, sizeof(struct sockaddr_vm)) == -1)
103 {
104 char ebuffer[256] = WINPR_C_ARRAY_INIT;
105 WLog_ERR(TAG, "Error binding vsock at cid %u port %d: %s", addr.svm_cid, port,
106 winpr_strerror(errno, ebuffer, sizeof(ebuffer)));
107 close(sockfd);
108 return FALSE;
109 }
110
111 if (listen(sockfd, 10) == -1)
112 {
113 char ebuffer[256] = WINPR_C_ARRAY_INIT;
114 WLog_ERR(TAG, "Error listening to socket at cid %u port %d: %s", addr.svm_cid, port,
115 winpr_strerror(errno, ebuffer, sizeof(ebuffer)));
116 close(sockfd);
117 return FALSE;
118 }
119 listener->sockfds[listener->num_sockfds] = sockfd;
120 listener->events[listener->num_sockfds] = WSACreateEvent();
121
122 if (!listener->events[listener->num_sockfds])
123 {
124 listener->num_sockfds = 0;
125 }
126
127 WSAEventSelect((SOCKET)sockfd, listener->events[listener->num_sockfds],
128 FD_READ | FD_ACCEPT | FD_CLOSE);
129 listener->num_sockfds++;
130
131 WLog_INFO(TAG, "Listening on %s:%d", bind_address, port);
132 return TRUE;
133#else
134 WLog_ERR(TAG, "compiled without AF_VSOCK, '%s' not supported", bind_address);
135 return FALSE;
136#endif
137}
138
139static BOOL freerdp_listener_open(freerdp_listener* instance, const char* bind_address, UINT16 port)
140{
141 int ai_flags = 0;
142 int status = 0;
143 int sockfd = 0;
144 char addr[64];
145 void* sin_addr = nullptr;
146 int option_value = 0;
147 struct addrinfo* res = nullptr;
148 rdpListener* listener = (rdpListener*)instance->listener;
149#ifdef _WIN32
150 u_long arg;
151#endif
152
153 if (!bind_address)
154 ai_flags = AI_PASSIVE;
155
156 if (utils_is_vsock(bind_address))
157 {
158 bind_address = utils_is_vsock(bind_address);
159 return freerdp_listener_open_from_vsock(instance, bind_address, port);
160 }
161
162 res = freerdp_tcp_resolve_host(bind_address, port, ai_flags);
163
164 if (!res)
165 return FALSE;
166
167 for (struct addrinfo* ai = res; ai && (listener->num_sockfds < 5); ai = ai->ai_next)
168 {
169 if ((ai->ai_family != AF_INET) && (ai->ai_family != AF_INET6))
170 continue;
171
172 if (listener->num_sockfds == MAX_LISTENER_HANDLES)
173 {
174 WLog_ERR(TAG, "too many listening sockets");
175 continue;
176 }
177
178 sockfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
179
180 if (sockfd == -1)
181 {
182 WLog_ERR(TAG, "socket");
183 continue;
184 }
185
186 option_value = 1;
187
188 if (ai->ai_family == AF_INET)
189 sin_addr = &((WINPR_PACKED_ALIGN_CAST(struct sockaddr_in*, ai->ai_addr))->sin_addr);
190 else
191 {
192 sin_addr = &((WINPR_PACKED_ALIGN_CAST(struct sockaddr_in6*, ai->ai_addr))->sin6_addr);
193 if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, (void*)&option_value,
194 sizeof(option_value)) == -1)
195 WLog_ERR(TAG, "setsockopt");
196 }
197
198 inet_ntop(ai->ai_family, sin_addr, addr, sizeof(addr));
199
200 if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (void*)&option_value,
201 sizeof(option_value)) == -1)
202 WLog_ERR(TAG, "setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR)");
203
204#ifndef _WIN32
205 if (fcntl(sockfd, F_SETFL, O_NONBLOCK) != 0)
206 WLog_ERR(TAG, "fcntl(sockfd, F_SETFL, O_NONBLOCK)");
207#else
208 arg = 1;
209 ioctlsocket(sockfd, FIONBIO, &arg);
210#endif
211 status = _bind((SOCKET)sockfd, ai->ai_addr, WINPR_ASSERTING_INT_CAST(int, ai->ai_addrlen));
212
213 if (status != 0)
214 {
215 closesocket((SOCKET)sockfd);
216 continue;
217 }
218
219 status = _listen((SOCKET)sockfd, 10);
220
221 if (status != 0)
222 {
223 WLog_ERR(TAG, "listen");
224 closesocket((SOCKET)sockfd);
225 continue;
226 }
227
228 /* FIXME: these file descriptors do not work on Windows */
229 listener->sockfds[listener->num_sockfds] = sockfd;
230 listener->events[listener->num_sockfds] = WSACreateEvent();
231
232 if (!listener->events[listener->num_sockfds])
233 {
234 listener->num_sockfds = 0;
235 break;
236 }
237
238 WSAEventSelect((SOCKET)sockfd, listener->events[listener->num_sockfds],
239 FD_READ | FD_ACCEPT | FD_CLOSE);
240 listener->num_sockfds++;
241 WLog_INFO(TAG, "Listening on [%s]:%" PRIu16, addr, port);
242 }
243
244 freeaddrinfo(res);
245 return ((listener->num_sockfds > 0));
246}
247
248static BOOL freerdp_listener_open_local(freerdp_listener* instance, const char* path)
249{
250#ifndef _WIN32
251 int status = 0;
252 int sockfd = 0;
253 struct sockaddr_un addr = WINPR_C_ARRAY_INIT;
254 rdpListener* listener = (rdpListener*)instance->listener;
255 HANDLE hevent = nullptr;
256
257 if (listener->num_sockfds == MAX_LISTENER_HANDLES)
258 {
259 WLog_ERR(TAG, "too many listening sockets");
260 return FALSE;
261 }
262
263 sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
264
265 if (sockfd == -1)
266 {
267 WLog_ERR(TAG, "socket");
268 return FALSE;
269 }
270
271 int rc = fcntl(sockfd, F_SETFL, O_NONBLOCK);
272 if (rc != 0)
273 {
274 WLog_ERR(TAG, "fcntl(sockfd, F_SETFL, O_NONBLOCK)");
275 closesocket((SOCKET)sockfd);
276 return FALSE;
277 }
278
279 addr.sun_family = AF_UNIX;
280 strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1);
281 unlink(path);
282 status = _bind((SOCKET)sockfd, (struct sockaddr*)&addr, sizeof(addr));
283
284 if (status != 0)
285 {
286 WLog_ERR(TAG, "bind");
287 closesocket((SOCKET)sockfd);
288 return FALSE;
289 }
290
291 status = _listen((SOCKET)sockfd, 10);
292
293 if (status != 0)
294 {
295 WLog_ERR(TAG, "listen");
296 closesocket((SOCKET)sockfd);
297 return FALSE;
298 }
299
300 hevent = CreateFileDescriptorEvent(nullptr, FALSE, FALSE, sockfd, WINPR_FD_READ);
301
302 if (!hevent)
303 {
304 WLog_ERR(TAG, "failed to create sockfd event");
305 closesocket((SOCKET)sockfd);
306 return FALSE;
307 }
308
309 listener->sockfds[listener->num_sockfds] = sockfd;
310 listener->events[listener->num_sockfds] = hevent;
311 listener->num_sockfds++;
312 WLog_INFO(TAG, "Listening on socket %s.", addr.sun_path);
313 return TRUE;
314#else
315 /* Windows 10 1803 and later: AF_UNIX stream sockets through Winsock. Who
316 * may connect is the socket file's ACL, inherited from its folder. */
317 rdpListener* listener = (rdpListener*)instance->listener;
318 SOCKADDR_UN addr = WINPR_C_ARRAY_INIT;
319 u_long nonblocking = 1;
320
321 if (listener->num_sockfds == MAX_LISTENER_HANDLES)
322 {
323 WLog_ERR(TAG, "too many listening sockets");
324 return FALSE;
325 }
326
327 if (strnlen(path, sizeof(addr.sun_path)) >= sizeof(addr.sun_path))
328 {
329 WLog_ERR(TAG, "socket path too long: %s", path);
330 return FALSE;
331 }
332
333 SOCKET sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
334
335 if (sockfd == INVALID_SOCKET)
336 {
337 WLog_ERR(TAG, "socket(AF_UNIX) failed: %d (Windows 10 1803 or later is needed)",
338 WSAGetLastError());
339 return FALSE;
340 }
341
342 (void)ioctlsocket(sockfd, FIONBIO, &nonblocking);
343 addr.sun_family = AF_UNIX;
344 strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1);
345 /* a socket file left by an earlier run would make bind fail */
346 (void)DeleteFileA(path);
347
348 if (_bind(sockfd, (struct sockaddr*)&addr, sizeof(addr)) != 0)
349 {
350 WLog_ERR(TAG, "bind(%s) failed: %d", path, WSAGetLastError());
351 closesocket(sockfd);
352 return FALSE;
353 }
354
355 if (_listen(sockfd, 10) != 0)
356 {
357 WLog_ERR(TAG, "listen(%s) failed: %d", path, WSAGetLastError());
358 closesocket(sockfd);
359 return FALSE;
360 }
361
362 HANDLE hevent = WSACreateEvent();
363
364 if (!hevent)
365 {
366 WLog_ERR(TAG, "failed to create the socket's event");
367 closesocket(sockfd);
368 return FALSE;
369 }
370
371 WSAEventSelect(sockfd, hevent, FD_READ | FD_ACCEPT | FD_CLOSE);
372 listener->sockfds[listener->num_sockfds] = (int)sockfd;
373 listener->events[listener->num_sockfds] = hevent;
374 listener->num_sockfds++;
375 WLog_INFO(TAG, "Listening on socket %s.", addr.sun_path);
376 return TRUE;
377#endif
378}
379
380static BOOL freerdp_listener_open_from_socket(freerdp_listener* instance, int fd)
381{
382#ifndef _WIN32
383 rdpListener* listener = (rdpListener*)instance->listener;
384
385 if (listener->num_sockfds == MAX_LISTENER_HANDLES)
386 {
387 WLog_ERR(TAG, "too many listening sockets");
388 return FALSE;
389 }
390
391 if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
392 return FALSE;
393
394 listener->sockfds[listener->num_sockfds] = fd;
395 listener->events[listener->num_sockfds] = WSACreateEvent();
396
397 if (!listener->events[listener->num_sockfds])
398 return FALSE;
399
400 WSAEventSelect((SOCKET)fd, listener->events[listener->num_sockfds],
401 FD_READ | FD_ACCEPT | FD_CLOSE);
402
403 listener->num_sockfds++;
404 WLog_INFO(TAG, "Listening on socket %d.", fd);
405 return TRUE;
406#else
407 return FALSE;
408#endif
409}
410
411static void freerdp_listener_close(freerdp_listener* instance)
412{
413 rdpListener* listener = (rdpListener*)instance->listener;
414
415 for (int i = 0; i < listener->num_sockfds; i++)
416 {
417 closesocket((SOCKET)listener->sockfds[i]);
418 (void)CloseHandle(listener->events[i]);
419 }
420
421 listener->num_sockfds = 0;
422}
423
424#if defined(WITH_FREERDP_DEPRECATED)
425static BOOL freerdp_listener_get_fds(freerdp_listener* instance, void** rfds, int* rcount)
426{
427 rdpListener* listener = (rdpListener*)instance->listener;
428
429 if (listener->num_sockfds < 1)
430 return FALSE;
431
432 for (int index = 0; index < listener->num_sockfds; index++)
433 {
434 rfds[*rcount] = (void*)(long)(listener->sockfds[index]);
435 (*rcount)++;
436 }
437
438 return TRUE;
439}
440#endif
441
442static DWORD freerdp_listener_get_event_handles(freerdp_listener* instance, HANDLE* events,
443 DWORD nCount)
444{
445 rdpListener* listener = (rdpListener*)instance->listener;
446
447 if (listener->num_sockfds < 1)
448 return 0;
449
450 if (listener->num_sockfds > (INT64)nCount)
451 return 0;
452
453 for (int index = 0; index < listener->num_sockfds; index++)
454 {
455 events[index] = listener->events[index];
456 }
457
458 return WINPR_ASSERTING_INT_CAST(uint32_t, listener->num_sockfds);
459}
460
461BOOL freerdp_peer_set_local_and_hostname(freerdp_peer* client,
462 const struct sockaddr_storage* peer_addr)
463{
464 const void* sin_addr = nullptr;
465 const BYTE localhost6_bytes[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
466
467 WINPR_ASSERT(client);
468 WINPR_ASSERT(peer_addr);
469
470 if (peer_addr->ss_family == AF_INET)
471 {
472 const UINT32* usin_addr = sin_addr = &(((const struct sockaddr_in*)peer_addr)->sin_addr);
473
474 if ((*usin_addr) == 0x0100007f)
475 client->local = TRUE;
476 }
477 else if (peer_addr->ss_family == AF_INET6)
478 {
479 const struct sockaddr_in6* usin_addr = sin_addr =
480 &(((const struct sockaddr_in6*)peer_addr)->sin6_addr);
481
482 if (memcmp(usin_addr, localhost6_bytes, 16) == 0)
483 client->local = TRUE;
484 }
485
486#if defined(HAVE_AF_VSOCK_H)
487 else if (peer_addr->ss_family == AF_UNIX || peer_addr->ss_family == AF_VSOCK)
488#else
489 else if (peer_addr->ss_family == AF_UNIX)
490#endif
491 client->local = TRUE;
492
493 if (client->local)
494 WLog_INFO(TAG, "Accepting client from localhost");
495
496 if (sin_addr)
497 inet_ntop(peer_addr->ss_family, sin_addr, client->hostname, sizeof(client->hostname));
498
499 return TRUE;
500}
501
502static BOOL freerdp_check_and_create_client(freerdp_listener* instance, int peer_sockfd,
503 const struct sockaddr_storage* peer_addr)
504{
505 WINPR_ASSERT(instance);
506 WINPR_ASSERT(peer_sockfd >= 0);
507 WINPR_ASSERT(peer_addr);
508
509 const BOOL check = IFCALLRESULT(TRUE, instance->CheckPeerAcceptRestrictions, instance);
510 if (!check)
511 {
512 closesocket((SOCKET)peer_sockfd);
513 return TRUE;
514 }
515
516 freerdp_peer* client = freerdp_peer_new(peer_sockfd);
517 if (!client)
518 {
519 closesocket((SOCKET)peer_sockfd);
520 return FALSE;
521 }
522
523 if (!freerdp_peer_set_local_and_hostname(client, peer_addr))
524 {
525 freerdp_peer_free(client);
526 return FALSE;
527 }
528
529 const BOOL peer_accepted = IFCALLRESULT(FALSE, instance->PeerAccepted, instance, client);
530 if (!peer_accepted)
531 {
532 WLog_ERR(TAG, "PeerAccepted callback failed");
533 freerdp_peer_free(client);
534 }
535
536 return TRUE;
537}
538
539static BOOL freerdp_listener_check_fds(freerdp_listener* instance)
540{
541 rdpListener* listener = (rdpListener*)instance->listener;
542
543 if (listener->num_sockfds < 1)
544 return FALSE;
545
546 for (int i = 0; i < listener->num_sockfds; i++)
547 {
548 struct sockaddr_storage peer_addr = WINPR_C_ARRAY_INIT;
549
550 (void)WSAResetEvent(listener->events[i]);
551 int peer_addr_size = sizeof(peer_addr);
552 SOCKET peer_sockfd =
553 _accept((SOCKET)listener->sockfds[i], (struct sockaddr*)&peer_addr, &peer_addr_size);
554
555 if (peer_sockfd == (SOCKET)-1)
556 {
557 char buffer[128] = WINPR_C_ARRAY_INIT;
558#ifdef _WIN32
559 int wsa_error = WSAGetLastError();
560
561 /* No data available */
562 if (wsa_error == WSAEWOULDBLOCK)
563 continue;
564
565#else
566
567 if (errno == EAGAIN || errno == EWOULDBLOCK)
568 continue;
569
570#endif
571 WLog_WARN(TAG, "accept failed with %s", winpr_strerror(errno, buffer, sizeof(buffer)));
572 return FALSE;
573 }
574
575 if (!freerdp_check_and_create_client(instance, (int)peer_sockfd, &peer_addr))
576 return FALSE;
577 }
578
579 return TRUE;
580}
581
582freerdp_listener* freerdp_listener_new(void)
583{
584 if (!utils_set_umask())
585 return nullptr;
586
587 freerdp_listener* instance = (freerdp_listener*)calloc(1, sizeof(freerdp_listener));
588
589 if (!instance)
590 return nullptr;
591
592 instance->Open = freerdp_listener_open;
593 instance->OpenLocal = freerdp_listener_open_local;
594 instance->OpenFromSocket = freerdp_listener_open_from_socket;
595#if defined(WITH_FREERDP_DEPRECATED)
596 instance->GetFileDescriptor = freerdp_listener_get_fds;
597#endif
598 instance->GetEventHandles = freerdp_listener_get_event_handles;
599 instance->CheckFileDescriptor = freerdp_listener_check_fds;
600 instance->Close = freerdp_listener_close;
601 rdpListener* listener = (rdpListener*)calloc(1, sizeof(rdpListener));
602
603 if (!listener)
604 {
605 free(instance);
606 return nullptr;
607 }
608
609 listener->instance = instance;
610 instance->listener = (void*)listener;
611 return instance;
612}
613
614void freerdp_listener_free(freerdp_listener* instance)
615{
616 if (instance)
617 {
618 free(instance->listener);
619 free(instance);
620 }
621}