From 281219e15c3050acf63e9b9acbd69dc84fcbac40 Mon Sep 17 00:00:00 2001 From: Marco Fortina Date: Sat, 16 May 2026 09:09:23 +0000 Subject: [PATCH] libvncserver: restore AF_UNIX client hosts --- CMakeLists.txt | 8 +++++ src/libvncserver/rfbserver.c | 59 +++++++++++++++++++++++++------ test/unixsocktest.c | 67 ++++++++++++++++++++++++++++++++++++ 3 files changed, 123 insertions(+), 11 deletions(-) create mode 100644 test/unixsocktest.c diff --git a/CMakeLists.txt b/CMakeLists.txt index d9709c809..d419d6dbf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -702,6 +702,11 @@ if(WITH_LIBVNCSERVER) cargstest copyrecttest ) + if(UNIX) + list(APPEND SIMPLETESTS + unixsocktest + ) + endif(UNIX) endif(WITH_LIBVNCSERVER) @@ -758,6 +763,9 @@ endif(LIBVNCSERVER_WITH_WEBSOCKETS AND WITH_LIBVNCSERVER) if(WITH_LIBVNCSERVER) add_test(NAME cargs COMMAND test_cargstest) + if(UNIX) + add_test(NAME unixsock COMMAND test_unixsocktest) + endif(UNIX) endif(WITH_LIBVNCSERVER) if(UNIX) if(WITH_LIBVNCSERVER) diff --git a/src/libvncserver/rfbserver.c b/src/libvncserver/rfbserver.c index 22af22d7d..518c39dc5 100644 --- a/src/libvncserver/rfbserver.c +++ b/src/libvncserver/rfbserver.c @@ -362,13 +362,14 @@ rfbNewTCPOrUDPClient(rfbScreenInfoPtr rfbScreen, rfbProtocolVersionMsg pv; rfbClientIteratorPtr iterator; rfbClientPtr cl,cl_; -#ifdef LIBVNCSERVER_IPv6 +#if defined(LIBVNCSERVER_IPv6) || !defined(WIN32) struct sockaddr_storage addr; #else struct sockaddr_in addr; #endif socklen_t addrlen = sizeof(addr); rfbProtocolExtension* extension; + rfbBool isTcp = FALSE; cl = (rfbClientPtr)calloc(sizeof(rfbClientRec),1); @@ -396,21 +397,57 @@ rfbNewTCPOrUDPClient(rfbScreenInfoPtr rfbScreen, } else { #ifdef LIBVNCSERVER_IPv6 char host[1024]; +#endif +#ifndef WIN32 + struct sockaddr *sockAddr; + sockAddr = (struct sockaddr *)&addr; #endif int one=1; size_t otherClientsCount = 0; - getpeername(sock, (struct sockaddr *)&addr, &addrlen); + if (getpeername(sock, (struct sockaddr *)&addr, &addrlen) < 0) { + rfbLogPerror("rfbNewClient: error in getpeername"); + cl->host = strdup("NON_SOCKET"); + } else { +#ifndef WIN32 + if (sockAddr->sa_family == AF_UNIX) { + struct sockaddr_un uaddr; + addrlen = sizeof(uaddr); + memset(&uaddr, 0, sizeof(uaddr)); + if (getsockname(sock, (struct sockaddr *)&uaddr, &addrlen) < 0) { + rfbLogPerror("rfbNewClient: error in getsockname"); + cl->host = strdup("NAMEFAIL_AF_UNIX"); + } else if (uaddr.sun_path[0] == '\0') { + cl->host = strdup("UNNAMED_AF_UNIX"); + } else { + cl->host = strdup(uaddr.sun_path); + } + } else +#endif #ifdef LIBVNCSERVER_IPv6 - if(getnameinfo((struct sockaddr*)&addr, addrlen, host, sizeof(host), NULL, 0, NI_NUMERICHOST) != 0) { - rfbLogPerror("rfbNewClient: error in getnameinfo"); - cl->host = strdup(""); - } - else - cl->host = strdup(host); + { + if (addr.ss_family == AF_INET || addr.ss_family == AF_INET6) + isTcp = TRUE; + if(getnameinfo((struct sockaddr*)&addr, addrlen, host, sizeof(host), NULL, 0, NI_NUMERICHOST) != 0) { + rfbLogPerror("rfbNewClient: error in getnameinfo"); + cl->host = strdup("UNKNOWN_HOST"); + } + else + cl->host = strdup(host); + } #else - cl->host = strdup(inet_ntoa(addr.sin_addr)); + { + struct sockaddr_in *inetAddr; + inetAddr = (struct sockaddr_in *)&addr; + if (inetAddr->sin_family == AF_INET) { + isTcp = TRUE; + cl->host = strdup(inet_ntoa(inetAddr->sin_addr)); + } else { + cl->host = strdup("UNKNOWN_HOST"); + } + } #endif + } cl->destPort = -1; @@ -426,9 +463,9 @@ rfbNewTCPOrUDPClient(rfbScreenInfoPtr rfbScreen, return NULL; } - if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, + if (isTcp && setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&one, sizeof(one)) < 0) { - rfbLogPerror("setsockopt failed: can't set TCP_NODELAY flag, non TCP socket?"); + rfbLogPerror("setsockopt failed: can't set TCP_NODELAY flag"); } FD_SET(sock,&(rfbScreen->allFds)); diff --git a/test/unixsocktest.c b/test/unixsocktest.c new file mode 100644 index 000000000..1edf0c4b9 --- /dev/null +++ b/test/unixsocktest.c @@ -0,0 +1,67 @@ +#include + +#include +#include +#include +#include + +static char observedHost[256]; +static rfbBool hookWasCalled = FALSE; + +static enum rfbNewClientAction +recordAndRefuseClient(rfbClientPtr cl) +{ + hookWasCalled = TRUE; + if (cl->host) + snprintf(observedHost, sizeof(observedHost), "%s", cl->host); + else + observedHost[0] = '\0'; + return RFB_CLIENT_REFUSE; +} + +int +main(int argc, char **argv) +{ + rfbScreenInfoPtr screen; + int fds[2]; + rfbClientPtr client; + int failed; + + failed = 0; + fds[0] = -1; + fds[1] = -1; + + if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) { + perror("socketpair"); + return 1; + } + + screen = rfbGetScreen(&argc, argv, 8, 8, 8, 3, 4); + if (!screen) { + close(fds[0]); + close(fds[1]); + return 1; + } + + screen->newClientHook = recordAndRefuseClient; + client = rfbNewClient(screen, fds[0]); + if (client != NULL) { + fprintf(stderr, "expected refused client to be cleaned up\n"); + rfbCloseClient(client); + rfbClientConnectionGone(client); + failed = 1; + } + + if (!hookWasCalled) { + fprintf(stderr, "newClientHook was not called\n"); + failed = 1; + } else if (observedHost[0] == '\0') { + fprintf(stderr, "AF_UNIX client host must not be empty\n"); + failed = 1; + } + + rfbScreenCleanup(screen); + close(fds[1]); + + return failed ? 1 : 0; +}