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