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