| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054 |
- #ifndef CONFIG
- #define CONFIG "config.h"
- #endif // CONFIG
- #include CONFIG
- #ifndef USE_MSRPC
- #ifndef _GNU_SOURCE
- #define _GNU_SOURCE
- #endif
- #include "types.h"
- #if HAVE_GETIFADDR && _WIN32
- #include <iphlpapi.h>
- #endif
- #include <string.h>
- #ifndef _WIN32
- #include <signal.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include <errno.h>
- #include <netinet/in.h>
- #include <sys/types.h>
- #if HAVE_GETIFADDR
- #if __ANDROID__
- #include "ifaddrs-android.h"
- #elif defined(GETIFADDRS_MUSL)
- #include "ifaddrs-musl.h"
- #else // getifaddrs from OS
- #include <ifaddrs.h>
- #endif // getifaddrs from OS
- #endif // HAVE_GETIFADDR
- #endif // !WIN32
- #include "network.h"
- #include "endian.h"
- //#include "output.h"
- #include "helpers.h"
- #include "shared_globals.h"
- #include "rpc.h"
- #ifndef _WIN32
- typedef ssize_t (*sendrecv_t)(int, void*, size_t, int);
- #else
- typedef int (WINAPI *sendrecv_t)(SOCKET, void*, int, int);
- #endif
- // Send or receive a fixed number of bytes regardless if received in one or more chunks
- int_fast8_t sendrecv(SOCKET sock, BYTE *data, int len, int_fast8_t do_send)
- {
- int n;
- sendrecv_t f = do_send
- ? (sendrecv_t) send
- : (sendrecv_t) recv;
- do
- {
- n = f(sock, data, len, 0);
- }
- while (
- ( n < 0 && socket_errno == VLMCSD_EINTR ) || ( n > 0 && ( data += n, (len -= n) > 0 ) ));
- return ! len;
- }
- static int_fast8_t ip2str(char *restrict result, const size_t resultLength, const struct sockaddr *const restrict socketAddress, const socklen_t socketLength)
- {
- static const char *const fIPv4 = "%s:%s";
- static const char *const fIPv6 = "[%s]:%s";
- char ipAddress[64], portNumber[8];
- if (getnameinfo
- (
- socketAddress,
- socketLength,
- ipAddress,
- sizeof(ipAddress),
- portNumber,
- sizeof(portNumber),
- NI_NUMERICHOST | NI_NUMERICSERV
- ))
- {
- return FALSE;
- }
- if ((unsigned int)vlmcsd_snprintf(result, resultLength, socketAddress->sa_family == AF_INET6 ? fIPv6 : fIPv4, ipAddress, portNumber) > resultLength) return FALSE;
- return TRUE;
- }
- static int_fast8_t getSocketList(struct addrinfo **saList, const char *const addr, const int flags, const int AddressFamily)
- {
- int status;
- char *szHost, *szPort;
- size_t len = strlen(addr) + 1;
- // Don't alloca too much
- if (len > 264) return FALSE;
- char *addrcopy = (char*)alloca(len);
- memcpy(addrcopy, addr, len);
- parseAddress(addrcopy, &szHost, &szPort);
- struct addrinfo hints;
- memset(&hints, 0, sizeof(struct addrinfo));
- hints.ai_family = AddressFamily;
- hints.ai_socktype = SOCK_STREAM;
- hints.ai_protocol = IPPROTO_TCP;
- hints.ai_flags = flags;
- if ((status = getaddrinfo(szHost, szPort, &hints, saList)))
- {
- printerrorf("Warning: %s: %s\n", addr, gai_strerror(status));
- return FALSE;
- }
- return TRUE;
- }
- static int_fast8_t setBlockingEnabled(SOCKET fd, int_fast8_t blocking)
- {
- if (fd == INVALID_SOCKET) return FALSE;
- #ifdef _WIN32
- unsigned long mode = blocking ? 0 : 1;
- return (ioctlsocket(fd, FIONBIO, &mode) == 0) ? TRUE : FALSE;
- #else // POSIX
- int flags = fcntl(fd, F_GETFL, 0);
- if (flags < 0) return FALSE;
- flags = blocking ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK);
- return (fcntl(fd, F_SETFL, flags) == 0) ? TRUE : FALSE;
- #endif // POSIX
- }
- int_fast8_t isDisconnected(const SOCKET s)
- {
- char buffer[1];
- if (!setBlockingEnabled(s, FALSE)) return TRUE;
- int n = recv(s, buffer, 1, MSG_PEEK);
- if (!setBlockingEnabled(s, TRUE)) return TRUE;
- if (n == 0) return TRUE;
- return FALSE;
- }
- #if !defined(NO_PRIVATE_IP_DETECT)
- // Check, if a sockaddr is a private IPv4 or IPv6 address
- static int_fast8_t isPrivateIPAddress(struct sockaddr* addr, socklen_t* length)
- {
- union v6addr
- {
- uint8_t bytes[16];
- uint16_t words[8];
- uint32_t dwords[4];
- uint64_t qwords[2];
- };
- if (addr == NULL) return FALSE;
- switch (addr->sa_family)
- {
- case AF_INET6:
- {
- union v6addr* ipv6addr = (union v6addr*)&((struct sockaddr_in6*)addr)->sin6_addr;
- if
- (
- (ipv6addr->qwords[0] != 0 || BE64(ipv6addr->qwords[1]) != 1) && // ::1 IPv6 localhost
- (BE16(ipv6addr->words[0]) & 0xe000) == 0x2000 // !2000::/3
- )
- {
- return FALSE;
- }
- if (length) *length = sizeof(struct sockaddr_in6);
- break;
- }
- case AF_INET:
- {
- uint32_t ipv4addr = BE32(((struct sockaddr_in*)addr)->sin_addr.s_addr);
- if
- (
- (ipv4addr & 0xff000000) != 0x7f000000 && // 127.x.x.x localhost
- (ipv4addr & 0xffff0000) != 0xc0a80000 && // 192.168.x.x private routeable
- (ipv4addr & 0xffff0000) != 0xa9fe0000 && // 169.254.x.x link local
- (ipv4addr & 0xff000000) != 0x0a000000 && // 10.x.x.x private routeable
- (ipv4addr & 0xfff00000) != 0xac100000 // 172.16-31.x.x private routeable
- )
- {
- return FALSE;
- }
- if (length) *length = sizeof(struct sockaddr_in);
- break;
- }
- default:
- return FALSE;
- }
- return TRUE;
- }
- #endif // !defined(NO_PRIVATE_IP_DETECT)
- // Connect to TCP address addr (e.g. "kms.example.com:1688") and return an
- // open socket for the connection if successful or INVALID_SOCKET otherwise
- SOCKET connectToAddress(const char *const addr, const int AddressFamily, int_fast8_t showHostName)
- {
- struct addrinfo *saList, *sa;
- SOCKET s = INVALID_SOCKET;
- char szAddr[128];
- if (!getSocketList(&saList, addr, 0, AddressFamily)) return INVALID_SOCKET;
- for (sa = saList; sa; sa = sa->ai_next)
- {
- // struct sockaddr_in* addr4 = (struct sockaddr_in*)sa->ai_addr;
- // struct sockaddr_in6* addr6 = (struct sockaddr_in6*)sa->ai_addr;
- if (ip2str(szAddr, sizeof(szAddr), sa->ai_addr, (socklen_t)sa->ai_addrlen))
- {
- if (showHostName)
- printf("Connecting to %s (%s) ... ", addr, szAddr);
- else
- printf("Connecting to %s ... ", szAddr);
- fflush(stdout);
- }
- s = socket(sa->ai_family, SOCK_STREAM, IPPROTO_TCP);
- # if !defined(NO_TIMEOUT) && !__minix__
- # ifndef _WIN32 // Standard Posix timeout structure
- struct timeval to;
- to.tv_sec = 10;
- to.tv_usec = 0;
- # else // Windows requires a DWORD with milliseconds
- DWORD to = 10000;
- # endif // _WIN32
- setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (sockopt_t)&to, sizeof(to));
- setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, (sockopt_t)&to, sizeof(to));
- # endif // !defined(NO_TIMEOUT) && !__minix__
- if (!connect(s, sa->ai_addr, (int)sa->ai_addrlen))
- {
- printf("successful\n");
- break;
- }
- printerrorf("%s: %s\n", szAddr, socket_errno == VLMCSD_EINPROGRESS ? "Timed out" : vlmcsd_strerror(socket_errno));
- socketclose(s);
- s = INVALID_SOCKET;
- }
- freeaddrinfo(saList);
- return s;
- }
- // fix for lame tomato toolchain
- # if !defined(IPV6_V6ONLY) && defined(__linux__)
- # define IPV6_V6ONLY (26)
- # endif // !defined(IPV6_V6ONLY) && defined(__linux__)
- #ifndef NO_SOCKETS
- #ifdef SIMPLE_SOCKETS
- static int_fast8_t allowSocketReuse(SOCKET s)
- {
- # if !defined(_WIN32) && !defined(__CYGWIN__)
- BOOL socketOption = TRUE;
- # else // _WIN32
- BOOL socketOption = FALSE;
- # endif // _WIN32
- if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (sockopt_t)&socketOption, sizeof(socketOption)))
- {
- # ifdef _PEDANTIC
- printerrorf("Warning: Socket option SO_REUSEADDR unsupported: %s\n", vlmcsd_strerror(socket_errno));
- # endif // _PEDANTIC
- }
- return 0;
- }
- int listenOnAllAddresses()
- {
- uint32_t port_listen;
- if (!stringToInt(defaultport, 1, 65535, &port_listen))
- {
- printerrorf("Fatal: Port must be numeric between 1 and 65535.\n");
- exit(!0);
- }
- struct sockaddr_in6 addr;
- memset(&addr, 0, sizeof(addr));
- addr.sin6_family = AF_INET6;
- addr.sin6_port = BE16((uint16_t)port_listen);
- addr.sin6_addr = in6addr_any;
- BOOL v6only = FALSE;
- s_server = socket(AF_INET6, SOCK_STREAM, 0);
- if (s_server == INVALID_SOCKET
- || allowSocketReuse(s_server)
- || setsockopt(s_server, IPPROTO_IPV6, IPV6_V6ONLY, (sockopt_t)&v6only, sizeof(v6only))
- || bind(s_server, (struct sockaddr *)&addr, sizeof(addr))
- || listen(s_server, SOMAXCONN) )
- {
- socketclose(s_server);
- struct sockaddr_in addr = {
- .sin_family = AF_INET,
- .sin_port = BE16((uint16_t)port_listen),
- };
- addr.sin_addr.s_addr = BE32(INADDR_ANY);
- s_server = socket(AF_INET, SOCK_STREAM, 0);
- if ( s_server == INVALID_SOCKET
- || allowSocketReuse(s_server)
- || bind(s_server, (struct sockaddr *)&addr, sizeof(addr))
- || listen(s_server, SOMAXCONN) )
- {
- int error = socket_errno;
- printerrorf("Fatal: Cannot bind to TCP port %u: %s\n", port_listen, vlmcsd_strerror(error));
- return error;
- }
- }
- #ifndef NO_LOG
- logger("Listening on TCP port %u\n", port_listen);
- #endif // NO_LOG
- return 0;
- }
- #else // !SIMPLE_SOCKETS
- #if HAVE_GETIFADDR && !defined(NO_PRIVATE_IP_DETECT)
- // Get list of private IP addresses.
- // Returns 0 on success or an errno error code on failure
- void getPrivateIPAddresses(int* numAddresses, char*** ipAddresses)
- {
- # if _WIN32
- PIP_ADAPTER_ADDRESSES firstAdapter, currentAdapter;
- DWORD dwRetVal = NO_ERROR;
- ULONG outBufLen = 16384;
- ULONG flags = GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME;
- firstAdapter = (PIP_ADAPTER_ADDRESSES)vlmcsd_malloc(outBufLen);
- if ((dwRetVal = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, firstAdapter, &outBufLen)) == ERROR_BUFFER_OVERFLOW)
- {
- free(firstAdapter);
- firstAdapter = (PIP_ADAPTER_ADDRESSES)vlmcsd_malloc(outBufLen);
- dwRetVal = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, firstAdapter, &outBufLen);
- }
- if (dwRetVal != NO_ERROR)
- {
- printerrorf("FATAL: Could not get network address list: %s\n", vlmcsd_strerror(dwRetVal));
- exit(dwRetVal);
- }
- for (currentAdapter = firstAdapter, *numAddresses = 0; currentAdapter != NULL; currentAdapter = currentAdapter->Next)
- {
- PIP_ADAPTER_UNICAST_ADDRESS currentAddress;
- int length;
- if (currentAdapter->OperStatus != IfOperStatusUp) continue;
- for (currentAddress = currentAdapter->FirstUnicastAddress; currentAddress != NULL; currentAddress = currentAddress->Next)
- {
- if (isPrivateIPAddress(currentAddress->Address.lpSockaddr, &length)) (*numAddresses)++;
- }
- }
- *ipAddresses = (char**)vlmcsd_malloc(*numAddresses * sizeof(char*));
- for (currentAdapter = firstAdapter, *numAddresses = 0; currentAdapter != NULL; currentAdapter = currentAdapter->Next)
- {
- PIP_ADAPTER_UNICAST_ADDRESS currentAddress;
- int length;
- if (currentAdapter->OperStatus != IfOperStatusUp) continue;
- for (currentAddress = currentAdapter->FirstUnicastAddress; currentAddress != NULL; currentAddress = currentAddress->Next)
- {
- if (!isPrivateIPAddress(currentAddress->Address.lpSockaddr, &length)) continue;
- char *ipAddress = (char*)vlmcsd_malloc(64);
- int error = getnameinfo(currentAddress->Address.lpSockaddr, currentAddress->Address.iSockaddrLength, ipAddress, 64, NULL, 0, NI_NUMERICHOST);
- if (error)
- {
- printerrorf("WARNING: Could not get IP address from interface list: %s\n", gai_strerror(error));
- *ipAddress = 0;
- }
- (*ipAddresses)[(*numAddresses)++] = ipAddress;
- }
- }
- free(firstAdapter);
- # else // !_WIN32
- struct ifaddrs *addrs, *addr;
- if (getifaddrs(&addrs))
- {
- printerrorf("FATAL: Could not get network address list: %s\n", vlmcsd_strerror(errno));
- exit(errno);
- }
- socklen_t length;
- for (addr = addrs, *numAddresses = 0; addr != NULL; addr = addr->ifa_next)
- {
- if (!isPrivateIPAddress(addr->ifa_addr, &length)) continue;
- (*numAddresses)++;
- }
- *ipAddresses = (char**)vlmcsd_malloc(*numAddresses * sizeof(char*));
- for (addr = addrs, *numAddresses = 0; addr != NULL; addr = addr->ifa_next)
- {
- if (!isPrivateIPAddress(addr->ifa_addr, &length)) continue;
- char *ipAddress = (char*)vlmcsd_malloc(64);
- int error = getnameinfo(addr->ifa_addr, length, ipAddress, 64, NULL, 0, NI_NUMERICHOST);
- if (error)
- {
- printerrorf("WARNING: Could not get IP address from interface list: %s\n", gai_strerror(error));
- *ipAddress = 0;
- }
- # if __UCLIBC__ || __gnu_hurd__
- size_t adrlen = strlen(ipAddress);
- if
- (
- addr->ifa_addr->sa_family == AF_INET6 &&
- adrlen > 5 &&
- !strchr(ipAddress, '%') &&
- (BE16(*(uint16_t*)&((struct sockaddr_in6*)addr->ifa_addr)->sin6_addr) & 0xffc0) == 0xfe80
- )
- {
- size_t ifnamelen = strlen(addr->ifa_name);
- char* workaroundIpAddress = (char*)vlmcsd_malloc(adrlen + ifnamelen + 2);
- strcpy(workaroundIpAddress, ipAddress);
- strcat(workaroundIpAddress, "%");
- strcat(workaroundIpAddress, addr->ifa_name);
- (*ipAddresses)[(*numAddresses)++] = workaroundIpAddress;
- free(ipAddress);
- }
- else
- {
- (*ipAddresses)[(*numAddresses)++] = ipAddress;
- }
- # else // !__UCLIBC__
- (*ipAddresses)[(*numAddresses)++] = ipAddress;
- # endif // !__UCLIBC__
- }
- freeifaddrs(addrs);
- # endif // !_WIN32
- }
- #endif // HAVE_GETIFADDR && !defined(NO_PRIVATE_IP_DETECT)
- // Create a Listening socket for addrinfo sa and return socket s
- // szHost and szPort are for logging only
- static int listenOnAddress(const struct addrinfo *const ai, SOCKET *s)
- {
- int error;
- char ipstr[64];
- ip2str(ipstr, sizeof(ipstr), ai->ai_addr, (socklen_t)ai->ai_addrlen);
- //*s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
- *s = socket(ai->ai_family, SOCK_STREAM, IPPROTO_TCP);
- if (*s == INVALID_SOCKET)
- {
- error = socket_errno;
- printerrorf("Warning: %s error. %s\n", ai->ai_family == AF_INET6 ? cIPv6 : cIPv4, vlmcsd_strerror(error));
- return error;
- }
- # if !defined(_WIN32) && !defined(NO_SIGHUP)
- int flags = fcntl(*s, F_GETFD, 0);
- if (flags != -1)
- {
- flags |= FD_CLOEXEC;
- fcntl(*s, F_SETFD, flags);
- }
- # ifdef _PEDANTIC
- else
- {
- printerrorf("Warning: Could not set FD_CLOEXEC flag on %s: %s\n", ipstr, vlmcsd_strerror(errno));
- }
- # endif // _PEDANTIC
- # endif // !defined(_WIN32) && !defined(NO_SIGHUP)
- BOOL socketOption = TRUE;
- # ifdef IPV6_V6ONLY
- if (ai->ai_family == AF_INET6 && setsockopt(*s, IPPROTO_IPV6, IPV6_V6ONLY, (sockopt_t)&socketOption, sizeof(socketOption)))
- {
- # ifdef _PEDANTIC
- # if defined(_WIN32) || defined(__CYGWIN__)
- // if (IsWindowsVistaOrGreater()) //Doesn't work with older version of MingW32-w64 toolchain
- if ((GetVersion() & 0xff) > 5)
- # endif // _WIN32
- printerrorf("Warning: %s does not support socket option IPV6_V6ONLY: %s\n", ipstr, vlmcsd_strerror(socket_errno));
- # endif // _PEDANTIC
- }
- # endif
- # ifndef _WIN32
- if (setsockopt(*s, SOL_SOCKET, SO_REUSEADDR, (sockopt_t)&socketOption, sizeof(socketOption)))
- {
- # ifdef _PEDANTIC
- printerrorf("Warning: %s does not support socket option SO_REUSEADDR: %s\n", ipstr, vlmcsd_strerror(socket_errno));
- # endif // _PEDANTIC
- }
- # endif // _WIN32
- # if HAVE_FREEBIND
- # if (defined(IP_NONLOCALOK) || __FreeBSD_kernel__ || __FreeBSD__) && !defined(IPV6_BINDANY)
- # define IPV6_BINDANY 64
- # endif // (defined(IP_NONLOCALOK) || __FreeBSD_kernel__ || __FreeBSD__) && !defined(IPV6_BINDANY)
- if (freebind)
- {
- # if defined(IP_FREEBIND) // Linux
- if (setsockopt(*s, IPPROTO_IP, IP_FREEBIND, (sockopt_t)&socketOption, sizeof(socketOption)))
- {
- printerrorf("Warning: Cannot use FREEBIND on %s: %s\n", ipstr, vlmcsd_strerror(socket_errno));
- }
- # endif // defined(IP_FREEBIND)
- # if defined(IP_BINDANY) // FreeBSD IPv4
- if (ai->ai_family == AF_INET && setsockopt(*s, IPPROTO_IP, IP_BINDANY, (sockopt_t)&socketOption, sizeof(socketOption)))
- {
- printerrorf("Warning: Cannot use BINDANY on %s: %s\n", ipstr, vlmcsd_strerror(socket_errno));
- }
- # endif // defined(IP_BINDANY)
- # if defined(IPV6_BINDANY) // FreeBSD IPv6
- if (ai->ai_family == AF_INET6 && setsockopt(*s, IPPROTO_IP, IPV6_BINDANY, (sockopt_t)&socketOption, sizeof(socketOption)))
- {
- # ifdef _PEDANTIC // FreeBSD defines the symbol but doesn't have BINDANY in IPv6 (Kame stack doesn't have it)
- printerrorf("Warning: Cannot use BINDANY on %s: %s\n", ipstr, vlmcsd_strerror(socket_errno));
- # endif
- }
- # endif // defined(IPV6_BINDANY)
- # if defined(IP_NONLOCALOK) && !defined(IP_BINDANY) // FreeBSD with GNU userspace IPv4
- if (ai->ai_family == AF_INET && setsockopt(*s, IPPROTO_IP, IP_NONLOCALOK, (sockopt_t)&socketOption, sizeof(socketOption)))
- {
- printerrorf("Warning: Cannot use BINDANY on %s: %s\n", ipstr, vlmcsd_strerror(socket_errno));
- }
- # endif // defined(IP_NONLOCALOK) && !defined(IP_BINDANY)
- }
- # endif // HAVE_FREEBIND
- if (bind(*s, ai->ai_addr, (int)ai->ai_addrlen) || listen(*s, SOMAXCONN))
- {
- error = socket_errno;
- printerrorf("Warning: %s: %s\n", ipstr, vlmcsd_strerror(error));
- socketclose(*s);
- return error;
- }
- # ifndef NO_LOG
- logger("Listening on %s\n", ipstr);
- # endif
- return 0;
- }
- // Adds a listening socket for an address string,
- // e.g. 127.0.0.1:1688 or [2001:db8:dead:beef::1]:1688
- BOOL addListeningSocket(const char *const addr)
- {
- struct addrinfo *aiList, *ai;
- int result = FALSE;
- SOCKET *s = SocketList + numsockets;
- if (getSocketList(&aiList, addr, AI_PASSIVE | AI_NUMERICHOST, AF_UNSPEC))
- {
- for (ai = aiList; ai; ai = ai->ai_next)
- {
- // struct sockaddr_in* addr4 = (struct sockaddr_in*)sa->ai_addr;
- // struct sockaddr_in6* addr6 = (struct sockaddr_in6*)sa->ai_addr;
- if (numsockets >= FD_SETSIZE)
- {
- #ifdef _PEDANTIC // Do not report this error in normal builds to keep file size low
- printerrorf("Warning: Cannot listen on %s. Your OS only supports %u listening sockets in an FD_SET.\n", addr, FD_SETSIZE);
- #endif
- break;
- }
- if (!listenOnAddress(ai, s))
- {
- numsockets++;
- result = TRUE;
- }
- }
- freeaddrinfo(aiList);
- }
- return result;
- }
- // Just create some dummy sockets to see if we have a specific protocol (IPv4 or IPv6)
- __pure int_fast8_t checkProtocolStack(const int addressfamily)
- {
- SOCKET s; // = INVALID_SOCKET;
- s = socket(addressfamily, SOCK_STREAM, 0);
- int_fast8_t success = (s != INVALID_SOCKET);
- socketclose(s);
- return success;
- }
- // Build an fd_set of all listening socket then use select to wait for an incoming connection
- static SOCKET network_accept_any()
- {
- fd_set ListeningSocketsList;
- SOCKET maxSocket, sock;
- int i;
- int status;
- FD_ZERO(&ListeningSocketsList);
- maxSocket = 0;
- for (i = 0; i < numsockets; i++)
- {
- FD_SET(SocketList[i], &ListeningSocketsList);
- if (SocketList[i] > maxSocket) maxSocket = SocketList[i];
- }
- status = select((int)maxSocket + 1, &ListeningSocketsList, NULL, NULL, NULL);
- if (status < 0) return INVALID_SOCKET;
- sock = INVALID_SOCKET;
- for (i = 0; i < numsockets; i++)
- {
- if (FD_ISSET(SocketList[i], &ListeningSocketsList))
- {
- sock = SocketList[i];
- break;
- }
- }
- if (sock == INVALID_SOCKET)
- return INVALID_SOCKET;
- else
- return accept(sock, NULL, NULL);
- }
- #endif // !SIMPLE_SOCKETS
- void closeAllListeningSockets()
- {
- # ifdef SIMPLE_SOCKETS
- shutdown(s_server, VLMCSD_SHUT_RDWR);
- socketclose(s_server);
- # else // !SIMPLE_SOCKETS
- int i;
- for (i = 0; i < numsockets; i++)
- {
- shutdown(SocketList[i], VLMCSD_SHUT_RDWR);
- socketclose(SocketList[i]);
- }
- #endif // !SIMPLE_SOCKETS
- }
- #endif // NO_SOCKETS
- static void serveClient(const SOCKET s_client, const DWORD RpcAssocGroup)
- {
- # if !defined(NO_TIMEOUT) && !__minix__
- # ifndef _WIN32 // Standard Posix timeout structure
- struct timeval to;
- to.tv_sec = ServerTimeout;
- to.tv_usec = 0;
- #else // Windows requires a DWORD with milliseconds
- DWORD to = ServerTimeout * 1000;
- # endif // _WIN32
- # if !defined(NO_LOG) && defined(_PEDANTIC)
- int result =
- setsockopt(s_client, SOL_SOCKET, SO_RCVTIMEO, (sockopt_t)&to, sizeof(to)) ||
- setsockopt(s_client, SOL_SOCKET, SO_SNDTIMEO, (sockopt_t)&to, sizeof(to));
- if (result) logger("Warning: Set timeout failed: %s\n", vlmcsd_strerror(socket_errno));
- # else // !(!defined(NO_LOG) && defined(_PEDANTIC))
- setsockopt(s_client, SOL_SOCKET, SO_RCVTIMEO, (sockopt_t)&to, sizeof(to));
- setsockopt(s_client, SOL_SOCKET, SO_SNDTIMEO, (sockopt_t)&to, sizeof(to));
- # endif // !(!defined(NO_LOG) && defined(_PEDANTIC))
- # endif // !defined(NO_TIMEOUT) && !__minix__
- char ipstr[64];
- socklen_t len;
- struct sockaddr_storage addr;
- len = sizeof addr;
- if (getpeername(s_client, (struct sockaddr*)&addr, &len) ||
- !ip2str(ipstr, sizeof(ipstr), (struct sockaddr*)&addr, len))
- {
- # if !defined(NO_LOG) && defined(_PEDANTIC)
- logger("Fatal: Cannot determine client's IP address: %s\n", vlmcsd_strerror(errno));
- # endif // !defined(NO_LOG) && defined(_PEDANTIC)
- socketclose(s_client);
- return;
- }
- # ifndef NO_LOG
- const char *const connection_type = addr.ss_family == AF_INET6 ? cIPv6 : cIPv4;
- static const char *const cAccepted = "accepted";
- static const char *const cClosed = "closed";
- static const char *const fIP = "%s connection %s: %s.\n";
- logger(fIP, connection_type, cAccepted, ipstr);
- #endif // NO_LOG
- # if !defined(NO_PRIVATE_IP_DETECT)
- if (!(PublicIPProtectionLevel & 2) || isPrivateIPAddress((struct sockaddr*)&addr, NULL))
- {
- rpcServer(s_client, RpcAssocGroup, ipstr);
- }
- # ifndef NO_LOG
- else
- {
- logger("Client with public IP address rejected\n");
- }
- # endif // NO_LOG
- # else // defined(NO_PRIVATE_IP_DETECT)
- rpcServer(s_client, RpcAssocGroup, ipstr);
- # endif // defined(NO_PRIVATE_IP_DETECT)
- # ifndef NO_LOG
- logger(fIP, connection_type, cClosed, ipstr);
- # endif // NO_LOG
- socketclose(s_client);
- }
- #ifndef NO_SOCKETS
- static void post_sem(void)
- {
- #if !defined(NO_LIMIT) && !__minix__
- if (!InetdMode && MaxTasks != SEM_VALUE_MAX)
- {
- semaphore_post(Semaphore);
- }
- #endif // !defined(NO_LIMIT) && !__minix__
- }
- static void wait_sem(void)
- {
- #if !defined(NO_LIMIT) && !__minix__
- if (!InetdMode && MaxTasks != SEM_VALUE_MAX)
- {
- semaphore_wait(Semaphore);
- }
- #endif // !defined(NO_LIMIT) && !__minix__
- }
- #endif // NO_SOCKETS
- #if defined(USE_THREADS) && !defined(NO_SOCKETS)
- #if defined(_WIN32) || defined(__CYGWIN__) // Win32 Threads
- static DWORD WINAPI serveClientThreadProc(PCLDATA clData)
- #else // Posix threads
- static void *serveClientThreadProc (PCLDATA clData)
- #endif // Thread proc is identical in WIN32 and Posix threads
- {
- serveClient(clData->socket, clData->RpcAssocGroup);
- free(clData);
- post_sem();
- return 0;
- }
- #endif // USE_THREADS
- #ifndef NO_SOCKETS
- #if defined(USE_THREADS) && (defined(_WIN32) || defined(__CYGWIN__)) // Windows Threads
- static int serveClientAsyncWinThreads(PCLDATA thr_CLData)
- {
- wait_sem();
- HANDLE h = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)serveClientThreadProc, thr_CLData, 0, NULL);
- if (h)
- CloseHandle(h);
- else
- {
- socketclose(thr_CLData->socket);
- free(thr_CLData);
- post_sem();
- return GetLastError();
- }
- return NO_ERROR;
- }
- #endif // defined(USE_THREADS) && defined(_WIN32) // Windows Threads
- #if defined(USE_THREADS) && !defined(_WIN32) && !defined(__CYGWIN__) // Posix Threads
- static int ServeClientAsyncPosixThreads(const PCLDATA thr_CLData)
- {
- pthread_t p_thr;
- pthread_attr_t attr;
- wait_sem();
- // Must set detached state to avoid memory leak
- if (pthread_attr_init(&attr) ||
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) ||
- pthread_create(&p_thr, &attr, (void * (*)(void *))serveClientThreadProc, thr_CLData))
- {
- socketclose(thr_CLData->socket);
- free(thr_CLData);
- post_sem();
- return !0;
- }
- return 0;
- }
- #endif // defined(USE_THREADS) && !defined(_WIN32) // Posix Threads
- #ifndef USE_THREADS // fork() implementation
- static void ChildSignalHandler(const int signal)
- {
- if (signal == SIGHUP) return;
- post_sem();
- #ifndef NO_LOG
- logger("Warning: Child killed/crashed by %s\n", strsignal(signal));
- #endif // NO_LOG
- exit(!0);
- }
- static int ServeClientAsyncFork(const SOCKET s_client, const DWORD RpcAssocGroup)
- {
- int pid;
- wait_sem();
- if ((pid = fork()) < 0)
- {
- return errno;
- }
- else if ( pid )
- {
- // Parent process
- socketclose(s_client);
- return 0;
- }
- else
- {
- // Child process
- // Setup a Child Handler for most common termination signals
- struct sigaction sa;
- sa.sa_flags = 0;
- sa.sa_handler = ChildSignalHandler;
- static int signallist[] = { SIGHUP, SIGINT, SIGTERM, SIGSEGV, SIGILL, SIGFPE, SIGBUS };
- if (!sigemptyset(&sa.sa_mask))
- {
- uint_fast8_t i;
- for (i = 0; i < _countof(signallist); i++)
- {
- sigaction(signallist[i], &sa, NULL);
- }
- }
- serveClient(s_client, RpcAssocGroup);
- post_sem();
- exit(0);
- }
- }
- #endif
- int serveClientAsync(const SOCKET s_client, const DWORD RpcAssocGroup)
- {
- #ifndef USE_THREADS // fork() implementation
- return ServeClientAsyncFork(s_client, RpcAssocGroup);
- #else // threads implementation
- PCLDATA thr_CLData = (PCLDATA)vlmcsd_malloc(sizeof(CLDATA));
- thr_CLData->socket = s_client;
- thr_CLData->RpcAssocGroup = RpcAssocGroup;
- #if defined(_WIN32) || defined (__CYGWIN__) // Windows threads
- return serveClientAsyncWinThreads(thr_CLData);
- #else // Posix Threads
- return ServeClientAsyncPosixThreads(thr_CLData);
- #endif // Posix Threads
- #endif // USE_THREADS
- }
- #endif // NO_SOCKETS
- int runServer()
- {
- DWORD RpcAssocGroup = rand32();
- // If compiled for inetd-only mode just serve the stdin socket
- #ifdef NO_SOCKETS
- serveClient(STDIN_FILENO, RpcAssocGroup);
- return 0;
- #else
- // In inetd mode just handle the stdin socket
- if (InetdMode)
- {
- serveClient(STDIN_FILENO, RpcAssocGroup);
- return 0;
- }
- for (;;)
- {
- int error;
- SOCKET s_client;
- #ifdef SIMPLE_SOCKETS
- if ( (s_client = accept(s_server, NULL, NULL)) == INVALID_SOCKET )
- #else // Standalone mode fully featured sockets
- if ( (s_client = network_accept_any()) == INVALID_SOCKET )
- #endif // Standalone mode fully featured sockets
- {
- error = socket_errno;
- if (error == VLMCSD_EINTR || error == VLMCSD_ECONNABORTED) continue;
- #ifdef _NTSERVICE
- if (ServiceShutdown) return 0;
- #endif
- #ifndef NO_LOG
- logger("Fatal: %s\n",vlmcsd_strerror(error));
- #endif
- return error;
- }
- RpcAssocGroup++;
- serveClientAsync(s_client, RpcAssocGroup);
- }
- #endif // NO_SOCKETS
- return 0;
- }
- #endif // USE_MSRPC
|