blob: 1ed6df0842590a6e1b52084b5f09ebcae1ba7021 [file] [log] [blame]
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +00001/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
2 *
3 * This is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This software is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this software; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
16 * USA.
17 */
18
Adam Tkac8aee1a82009-09-04 12:08:56 +000019#ifdef HAVE_CONFIG_H
20#include <config.h>
Adam Tkacad1cbd92008-10-06 14:08:00 +000021#endif
22
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000023#ifdef WIN32
24//#include <io.h>
25#include <winsock2.h>
Pierre Ossman0153e232011-03-08 13:05:27 +000026#include <ws2tcpip.h>
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000027#define errorNumber WSAGetLastError()
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000028#else
29#define errorNumber errno
30#define closesocket close
31#include <sys/types.h>
32#include <sys/socket.h>
33#include <arpa/inet.h>
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000034#include <netinet/tcp.h>
35#include <netdb.h>
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000036#include <errno.h>
37#include <string.h>
38#include <signal.h>
39#include <fcntl.h>
40#endif
41
Adam Tkac04b7fd22008-03-19 16:14:48 +000042#include <stdlib.h>
Tim Waugh892d10a2015-03-11 13:12:07 +000043#include <unistd.h>
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000044#include <network/TcpSocket.h>
45#include <rfb/util.h>
46#include <rfb/LogWriter.h>
Pierre Ossman39b3b8f2015-01-29 17:35:45 +010047#include <rfb/Configuration.h>
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000048
Pierre Ossman2f744172015-03-17 13:38:21 +010049#ifdef WIN32
50#include <os/winerrno.h>
51#endif
52
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000053#ifndef INADDR_NONE
54#define INADDR_NONE ((unsigned long)-1)
55#endif
56#ifndef INADDR_LOOPBACK
57#define INADDR_LOOPBACK ((unsigned long)0x7F000001)
58#endif
59
Pierre Ossman8b6aa202012-12-13 13:55:22 +000060#if defined(HAVE_GETADDRINFO) && !defined(IN6_ARE_ADDR_EQUAL)
61#define IN6_ARE_ADDR_EQUAL(a,b) \
62 (memcmp ((const void*)(a), (const void*)(b), sizeof (struct in6_addr)) == 0)
63#endif
64
Pierre Ossmana6570c52015-03-17 13:38:59 +010065// Missing on older Windows and OS X
66#ifndef AI_NUMERICSERV
67#define AI_NUMERICSERV 0
68#endif
69
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000070using namespace network;
71using namespace rdr;
72
73static rfb::LogWriter vlog("TcpSocket");
74
Pierre Ossman39b3b8f2015-01-29 17:35:45 +010075static rfb::BoolParameter UseIPv4("UseIPv4", "Use IPv4 for incoming and outgoing connections.", true);
76#ifdef HAVE_GETADDRINFO
77static rfb::BoolParameter UseIPv6("UseIPv6", "Use IPv6 for incoming and outgoing connections.", true);
78#endif
79
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000080/* Tunnelling support. */
81int network::findFreeTcpPort (void)
82{
DRCb2618e52011-02-21 13:43:44 +000083 int sock;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000084 struct sockaddr_in addr;
85 memset(&addr, 0, sizeof(addr));
86 addr.sin_family = AF_INET;
87 addr.sin_addr.s_addr = INADDR_ANY;
88
89 if ((sock = socket (AF_INET, SOCK_STREAM, 0)) < 0)
90 throw SocketException ("unable to create socket", errorNumber);
91
DRCb2618e52011-02-21 13:43:44 +000092 addr.sin_port = 0;
93 if (bind (sock, (struct sockaddr *)&addr, sizeof (addr)) < 0)
94 throw SocketException ("unable to find free port", errorNumber);
95
96 socklen_t n = sizeof(addr);
97 if (getsockname (sock, (struct sockaddr *)&addr, &n) < 0)
98 throw SocketException ("unable to get port number", errorNumber);
99
100 closesocket (sock);
101 return ntohs(addr.sin_port);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000102}
103
104
105// -=- Socket initialisation
106static bool socketsInitialised = false;
107static void initSockets() {
108 if (socketsInitialised)
109 return;
110#ifdef WIN32
111 WORD requiredVersion = MAKEWORD(2,0);
112 WSADATA initResult;
113
114 if (WSAStartup(requiredVersion, &initResult) != 0)
115 throw SocketException("unable to initialise Winsock2", errorNumber);
116#else
117 signal(SIGPIPE, SIG_IGN);
118#endif
119 socketsInitialised = true;
120}
121
122
Pierre Ossman3ab5db42015-03-17 17:06:22 +0100123// -=- Socket duplication help for Windows
124static int dupsocket(int fd)
125{
126#ifdef WIN32
127 int ret;
128 WSAPROTOCOL_INFO info;
129 ret = WSADuplicateSocket(fd, GetCurrentProcessId(), &info);
130 if (ret != 0)
131 throw SocketException("unable to duplicate socket", errorNumber);
132 return WSASocket(info.iAddressFamily, info.iSocketType, info.iProtocol,
133 &info, 0, 0);
134#else
135 return dup(fd);
136#endif
137}
138
139
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000140// -=- TcpSocket
141
142TcpSocket::TcpSocket(int sock, bool close)
143 : Socket(new FdInStream(sock), new FdOutStream(sock), true), closeFd(close)
144{
145}
146
147TcpSocket::TcpSocket(const char *host, int port)
148 : closeFd(true)
149{
Adam Tkac9cb6a422008-11-14 15:56:15 +0000150 int sock, err, result, family;
151 vnc_sockaddr_t sa;
Adam Tkacbe4c3ac2008-12-10 16:42:33 +0000152 socklen_t salen;
Adam Tkac9cb6a422008-11-14 15:56:15 +0000153#ifdef HAVE_GETADDRINFO
154 struct addrinfo *ai, *current, hints;
155#endif
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000156
157 // - Create a socket
158 initSockets();
Adam Tkac9cb6a422008-11-14 15:56:15 +0000159
160#ifdef HAVE_GETADDRINFO
161 memset(&hints, 0, sizeof(struct addrinfo));
162 hints.ai_family = AF_UNSPEC;
163 hints.ai_socktype = SOCK_STREAM;
164 hints.ai_canonname = NULL;
165 hints.ai_addr = NULL;
166 hints.ai_next = NULL;
167
168 if ((result = getaddrinfo(host, NULL, &hints, &ai)) != 0) {
169 throw Exception("unable to resolve host by name: %s",
Tim Waugha85363d2015-03-11 13:07:48 +0000170 gai_strerror(result));
Adam Tkac9cb6a422008-11-14 15:56:15 +0000171 }
172
Pierre Ossmanf1a35012015-03-03 16:02:42 +0100173 // This logic is too complex for the compiler to determine if
174 // sock is properly assigned or not.
175 sock = -1;
176
Adam Tkac9cb6a422008-11-14 15:56:15 +0000177 for (current = ai; current != NULL; current = current->ai_next) {
178 family = current->ai_family;
Pierre Ossman39b3b8f2015-01-29 17:35:45 +0100179
180 switch (family) {
181 case AF_INET:
182 if (!UseIPv4)
183 continue;
184 break;
185 case AF_INET6:
186 if (!UseIPv6)
187 continue;
188 break;
189 default:
Adam Tkac9cb6a422008-11-14 15:56:15 +0000190 continue;
Pierre Ossman39b3b8f2015-01-29 17:35:45 +0100191 }
Adam Tkac9cb6a422008-11-14 15:56:15 +0000192
193 salen = current->ai_addrlen;
194 memcpy(&sa, current->ai_addr, salen);
195
196 if (family == AF_INET)
197 sa.u.sin.sin_port = htons(port);
198 else
199 sa.u.sin6.sin6_port = htons(port);
200
201#else /* HAVE_GETADDRINFO */
Pierre Ossman39b3b8f2015-01-29 17:35:45 +0100202 if (!UseIPv4)
203 throw Exception("Only IPv4 available but it is disabled");
204
Adam Tkac9cb6a422008-11-14 15:56:15 +0000205 family = AF_INET;
206 salen = sizeof(struct sockaddr_in);
207
208 /* Try processing the host as an IP address */
209 memset(&sa, 0, sizeof(sa));
210 sa.u.sin.sin_family = AF_INET;
211 sa.u.sin.sin_addr.s_addr = inet_addr((char *)host);
212 sa.u.sin.sin_port = htons(port);
213 if ((int)sa.u.sin.sin_addr.s_addr == -1) {
214 /* Host was not an IP address - try resolving as DNS name */
215 struct hostent *hostinfo;
216 hostinfo = gethostbyname((char *)host);
217 if (hostinfo && hostinfo->h_addr) {
218 sa.u.sin.sin_addr.s_addr = ((struct in_addr *)hostinfo->h_addr)->s_addr;
219 } else {
220 err = errorNumber;
221 throw SocketException("unable to resolve host by name", err);
222 }
223 }
224#endif /* HAVE_GETADDRINFO */
225
226 sock = socket (family, SOCK_STREAM, 0);
227 if (sock == -1) {
228 err = errorNumber;
229#ifdef HAVE_GETADDRINFO
230 freeaddrinfo(ai);
231#endif /* HAVE_GETADDRINFO */
232 throw SocketException("unable to create socket", err);
233 }
234
235 /* Attempt to connect to the remote host */
Adam Tkacc9cda3b2009-10-30 11:13:34 +0000236 while ((result = connect(sock, &sa.u.sa, salen)) == -1) {
Adam Tkac9cb6a422008-11-14 15:56:15 +0000237 err = errorNumber;
238#ifndef WIN32
239 if (err == EINTR)
Tim Waugha85363d2015-03-11 13:07:48 +0000240 continue;
Adam Tkac9cb6a422008-11-14 15:56:15 +0000241#endif
242 closesocket(sock);
243 break;
244 }
245
246#ifdef HAVE_GETADDRINFO
247 if (result == 0)
248 break;
Adam Tkac9cb6a422008-11-14 15:56:15 +0000249 }
250
251 freeaddrinfo(ai);
Pierre Ossmanda9a38d2015-03-03 16:03:32 +0100252
253 if (current == NULL)
254 throw Exception("No useful address for host");
Adam Tkac9cb6a422008-11-14 15:56:15 +0000255#endif /* HAVE_GETADDRINFO */
256
257 if (result == -1)
258 throw SocketException("unable connect to socket", err);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000259
260#ifndef WIN32
261 // - By default, close the socket on exec()
262 fcntl(sock, F_SETFD, FD_CLOEXEC);
263#endif
264
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000265 // Disable Nagle's algorithm, to reduce latency
266 enableNagles(sock, false);
267
268 // Create the input and output streams
269 instream = new FdInStream(sock);
270 outstream = new FdOutStream(sock);
271 ownStreams = true;
272}
273
274TcpSocket::~TcpSocket() {
275 if (closeFd)
276 closesocket(getFd());
277}
278
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000279int TcpSocket::getMyPort() {
280 return getSockPort(getFd());
281}
282
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000283char* TcpSocket::getPeerAddress() {
Tim Waugh6ae42df2014-11-17 17:07:07 +0000284 vnc_sockaddr_t sa;
285 socklen_t sa_size = sizeof(sa);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000286
Tim Waugh6ae42df2014-11-17 17:07:07 +0000287 if (getpeername(getFd(), &sa.u.sa, &sa_size) != 0) {
288 vlog.error("unable to get peer name for socket");
289 return rfb::strDup("");
290 }
291
Tim Waugh892d10a2015-03-11 13:12:07 +0000292#if defined(HAVE_GETADDRINFO)
Pierre Ossman14263e12014-11-19 11:14:49 +0100293 if (sa.u.sa.sa_family == AF_INET6) {
Pierre Ossman07cd2292014-11-19 11:16:04 +0100294 char buffer[INET6_ADDRSTRLEN + 2];
Tim Waugh892d10a2015-03-11 13:12:07 +0000295 int ret;
Tim Waugh6ae42df2014-11-17 17:07:07 +0000296
Pierre Ossman07cd2292014-11-19 11:16:04 +0100297 buffer[0] = '[';
298
Tim Waugh892d10a2015-03-11 13:12:07 +0000299 ret = getnameinfo(&sa.u.sa, sizeof(sa.u.sin6),
300 buffer + 1, sizeof(buffer) - 2, NULL, 0,
301 NI_NUMERICHOST);
302 if (ret != 0) {
Pierre Ossman14263e12014-11-19 11:14:49 +0100303 vlog.error("unable to convert peer name to a string");
304 return rfb::strDup("");
305 }
Tim Waugh6ae42df2014-11-17 17:07:07 +0000306
Pierre Ossman07cd2292014-11-19 11:16:04 +0100307 strcat(buffer, "]");
308
309 return rfb::strDup(buffer);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000310 }
Pierre Ossman14263e12014-11-19 11:14:49 +0100311#endif
312
313 if (sa.u.sa.sa_family == AF_INET) {
314 char *name;
315
316 name = inet_ntoa(sa.u.sin.sin_addr);
317 if (name == NULL) {
318 vlog.error("unable to convert peer name to a string");
319 return rfb::strDup("");
320 }
321
322 return rfb::strDup(name);
323 }
324
325 vlog.error("unknown address family for socket");
326 return rfb::strDup("");
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000327}
328
329int TcpSocket::getPeerPort() {
Tim Waugh6ae42df2014-11-17 17:07:07 +0000330 vnc_sockaddr_t sa;
331 socklen_t sa_size = sizeof(sa);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000332
Tim Waugh6ae42df2014-11-17 17:07:07 +0000333 getpeername(getFd(), &sa.u.sa, &sa_size);
334
335 switch (sa.u.sa.sa_family) {
336#ifdef HAVE_GETADDRINFO
337 case AF_INET6:
338 return ntohs(sa.u.sin6.sin6_port);
339#endif /* HAVE_GETADDRINFO */
Pierre Ossman14263e12014-11-19 11:14:49 +0100340 case AF_INET:
Tim Waugh6ae42df2014-11-17 17:07:07 +0000341 return ntohs(sa.u.sin.sin_port);
Pierre Ossman14263e12014-11-19 11:14:49 +0100342 default:
343 return 0;
Tim Waugh6ae42df2014-11-17 17:07:07 +0000344 }
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000345}
346
347char* TcpSocket::getPeerEndpoint() {
348 rfb::CharArray address; address.buf = getPeerAddress();
349 int port = getPeerPort();
350
351 int buflen = strlen(address.buf) + 32;
352 char* buffer = new char[buflen];
353 sprintf(buffer, "%s::%d", address.buf, port);
354 return buffer;
355}
356
357bool TcpSocket::sameMachine() {
Adam Tkac897814f2009-11-12 10:32:43 +0000358 vnc_sockaddr_t peeraddr, myaddr;
359 socklen_t addrlen;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000360
Adam Tkac897814f2009-11-12 10:32:43 +0000361 addrlen = sizeof(peeraddr);
362 if (getpeername(getFd(), &peeraddr.u.sa, &addrlen) < 0)
363 throw SocketException ("unable to get peer address", errorNumber);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000364
Adam Tkac897814f2009-11-12 10:32:43 +0000365 addrlen = sizeof(myaddr); /* need to reset, since getpeername overwrote */
366 if (getsockname(getFd(), &myaddr.u.sa, &addrlen) < 0)
367 throw SocketException ("unable to get my address", errorNumber);
368
369 if (peeraddr.u.sa.sa_family != myaddr.u.sa.sa_family)
370 return false;
371
372#ifdef HAVE_GETADDRINFO
373 if (peeraddr.u.sa.sa_family == AF_INET6)
374 return IN6_ARE_ADDR_EQUAL(&peeraddr.u.sin6.sin6_addr,
Tim Waugha85363d2015-03-11 13:07:48 +0000375 &myaddr.u.sin6.sin6_addr);
Adam Tkac897814f2009-11-12 10:32:43 +0000376#endif
377
Pierre Ossman14263e12014-11-19 11:14:49 +0100378 if (peeraddr.u.sa.sa_family == AF_INET)
379 return (peeraddr.u.sin.sin_addr.s_addr == myaddr.u.sin.sin_addr.s_addr);
380
381 // No idea what this is. Assume we're on different machines.
382 return false;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000383}
384
385void TcpSocket::shutdown()
386{
387 Socket::shutdown();
388 ::shutdown(getFd(), 2);
389}
390
391bool TcpSocket::enableNagles(int sock, bool enable) {
392 int one = enable ? 0 : 1;
393 if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
Tim Waugha85363d2015-03-11 13:07:48 +0000394 (char *)&one, sizeof(one)) < 0) {
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000395 int e = errorNumber;
396 vlog.error("unable to setsockopt TCP_NODELAY: %d", e);
397 return false;
398 }
399 return true;
400}
401
Pierre Ossman64069a92011-11-08 12:10:55 +0000402bool TcpSocket::cork(int sock, bool enable) {
403#ifndef TCP_CORK
404 return false;
405#else
406 int one = enable ? 1 : 0;
407 if (setsockopt(sock, IPPROTO_TCP, TCP_CORK, (char *)&one, sizeof(one)) < 0)
408 return false;
409 return true;
410#endif
411}
412
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000413bool TcpSocket::isSocket(int sock)
414{
Tim Waugh6ae42df2014-11-17 17:07:07 +0000415 vnc_sockaddr_t sa;
416 socklen_t sa_size = sizeof(sa);
417 return getsockname(sock, &sa.u.sa, &sa_size) >= 0;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000418}
419
420bool TcpSocket::isConnected(int sock)
421{
Tim Waugh6ae42df2014-11-17 17:07:07 +0000422 vnc_sockaddr_t sa;
423 socklen_t sa_size = sizeof(sa);
424 return getpeername(sock, &sa.u.sa, &sa_size) >= 0;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000425}
426
427int TcpSocket::getSockPort(int sock)
428{
Tim Waugh6ae42df2014-11-17 17:07:07 +0000429 vnc_sockaddr_t sa;
430 socklen_t sa_size = sizeof(sa);
431 if (getsockname(sock, &sa.u.sa, &sa_size) < 0)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000432 return 0;
Tim Waugh6ae42df2014-11-17 17:07:07 +0000433
434 switch (sa.u.sa.sa_family) {
435#ifdef HAVE_GETADDRINFO
436 case AF_INET6:
437 return ntohs(sa.u.sin6.sin6_port);
438#endif /* HAVE_GETADDRINFO */
439
440 default:
441 return ntohs(sa.u.sin.sin_port);
442 }
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000443}
444
Tim Waugh892d10a2015-03-11 13:12:07 +0000445TcpListener::TcpListener(int sock)
Tim Waughe4d97262014-11-21 16:07:34 +0000446{
Tim Waugh892d10a2015-03-11 13:12:07 +0000447 fd = sock;
Tim Waughe4d97262014-11-21 16:07:34 +0000448}
449
Tim Waugh892d10a2015-03-11 13:12:07 +0000450TcpListener::TcpListener(const TcpListener& other)
Tim Waughe4d97262014-11-21 16:07:34 +0000451{
Pierre Ossman3ab5db42015-03-17 17:06:22 +0100452 fd = dupsocket (other.fd);
Tim Waugh892d10a2015-03-11 13:12:07 +0000453 // Hope TcpListener::shutdown(other) doesn't get called...
Tim Waughe4d97262014-11-21 16:07:34 +0000454}
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000455
Tim Waugh892d10a2015-03-11 13:12:07 +0000456TcpListener& TcpListener::operator= (const TcpListener& other)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000457{
Tim Waugh892d10a2015-03-11 13:12:07 +0000458 if (this != &other)
459 {
460 closesocket (fd);
Pierre Ossman3ab5db42015-03-17 17:06:22 +0100461 fd = dupsocket (other.fd);
Tim Waugh892d10a2015-03-11 13:12:07 +0000462 // Hope TcpListener::shutdown(other) doesn't get called...
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000463 }
Tim Waugh892d10a2015-03-11 13:12:07 +0000464 return *this;
465}
466
467TcpListener::TcpListener(const struct sockaddr *listenaddr,
468 socklen_t listenaddrlen)
469{
470 int one = 1;
471 vnc_sockaddr_t sa;
472 int sock;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000473
474 initSockets();
Tim Waugh892d10a2015-03-11 13:12:07 +0000475
476 if ((sock = socket (listenaddr->sa_family, SOCK_STREAM, 0)) < 0)
477 throw SocketException("unable to create listening socket", errorNumber);
478
479 memcpy (&sa, listenaddr, listenaddrlen);
480#ifdef IPV6_V6ONLY
481 if (listenaddr->sa_family == AF_INET6) {
482 if (setsockopt (sock, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&one, sizeof(one)))
483 throw SocketException("unable to set IPV6_V6ONLY", errorNumber);
484 }
485#endif /* defined(IPV6_V6ONLY) */
486
487 if (bind(sock, &sa.u.sa, listenaddrlen) == -1) {
488 closesocket(sock);
489 throw SocketException("failed to bind socket", errorNumber);
490 }
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000491
492#ifndef WIN32
493 // - By default, close the socket on exec()
Tim Waugh892d10a2015-03-11 13:12:07 +0000494 fcntl(sock, F_SETFD, FD_CLOEXEC);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000495
Tim Waugh892d10a2015-03-11 13:12:07 +0000496 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
497 (char *)&one, sizeof(one)) < 0) {
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000498 int e = errorNumber;
Tim Waugh892d10a2015-03-11 13:12:07 +0000499 closesocket(sock);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000500 throw SocketException("unable to create listening socket", e);
501 }
502#endif
503
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000504 // - Set it to be a listening socket
Tim Waugh892d10a2015-03-11 13:12:07 +0000505 if (listen(sock, 5) < 0) {
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000506 int e = errorNumber;
Tim Waugh892d10a2015-03-11 13:12:07 +0000507 closesocket(sock);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000508 throw SocketException("unable to set socket to listening mode", e);
509 }
Tim Waugh892d10a2015-03-11 13:12:07 +0000510
511 fd = sock;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000512}
513
514TcpListener::~TcpListener() {
Tim Waugh892d10a2015-03-11 13:12:07 +0000515 closesocket(fd);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000516}
517
518void TcpListener::shutdown()
519{
520#ifdef WIN32
521 closesocket(getFd());
522#else
523 ::shutdown(getFd(), 2);
524#endif
525}
526
527
528Socket*
529TcpListener::accept() {
530 int new_sock = -1;
531
532 // Accept an incoming connection
533 if ((new_sock = ::accept(fd, 0, 0)) < 0)
534 throw SocketException("unable to accept new connection", errorNumber);
535
536#ifndef WIN32
537 // - By default, close the socket on exec()
538 fcntl(new_sock, F_SETFD, FD_CLOEXEC);
539#endif
540
541 // Disable Nagle's algorithm, to reduce latency
542 TcpSocket::enableNagles(new_sock, false);
543
544 // Create the socket object & check connection is allowed
545 TcpSocket* s = new TcpSocket(new_sock);
546 if (filter && !filter->verifyConnection(s)) {
547 delete s;
548 return 0;
549 }
550 return s;
551}
552
Pierre Ossman57cab512015-03-17 13:39:39 +0100553void TcpListener::getMyAddresses(std::list<char*>* result) {
554#if defined(HAVE_GETADDRINFO)
555 struct addrinfo *ai, *current, hints;
556
557 initSockets();
558
559 memset(&hints, 0, sizeof(struct addrinfo));
560 hints.ai_flags = AI_PASSIVE | AI_NUMERICSERV;
561 hints.ai_family = AF_UNSPEC;
562 hints.ai_socktype = SOCK_STREAM;
563 hints.ai_canonname = NULL;
564 hints.ai_addr = NULL;
565 hints.ai_next = NULL;
566
567 // Windows doesn't like NULL for service, so specify something
568 if ((getaddrinfo(NULL, "1", &hints, &ai)) != 0)
569 return;
570
571 for (current= ai; current != NULL; current = current->ai_next) {
572 switch (current->ai_family) {
573 case AF_INET:
574 if (!UseIPv4)
575 continue;
576 break;
577 case AF_INET6:
578 if (!UseIPv6)
579 continue;
580 break;
581 default:
582 continue;
583 }
584
585 char *addr = new char[INET6_ADDRSTRLEN];
586
587 getnameinfo(current->ai_addr, current->ai_addrlen, addr, INET6_ADDRSTRLEN,
588 NULL, 0, NI_NUMERICHOST);
589
590 result->push_back(addr);
591 }
592
593 freeaddrinfo(ai);
594#else
595 const hostent* addrs = gethostbyname(0);
596 if (!UseIPv4)
597 return;
598 if (addrs == 0)
599 throw rdr::SystemException("gethostbyname", errorNumber);
600 if (addrs->h_addrtype != AF_INET)
601 throw rdr::Exception("getMyAddresses: bad family");
602 for (int i=0; addrs->h_addr_list[i] != 0; i++) {
603 const char* addrC = inet_ntoa(*((struct in_addr*)addrs->h_addr_list[i]));
604 char* addr = new char[strlen(addrC)+1];
605 strcpy(addr, addrC);
606 result->push_back(addr);
607 }
608#endif /* defined(HAVE_GETADDRINFO) */
609}
610
Tim Waugh892d10a2015-03-11 13:12:07 +0000611int TcpListener::getMyPort() {
612 return TcpSocket::getSockPort(getFd());
613}
614
615
616void network::createLocalTcpListeners(std::list<TcpListener> *listeners,
617 int port)
618{
619 std::list<TcpListener> new_listeners;
620 vnc_sockaddr_t sa;
Pierre Ossman9d784402015-03-17 17:10:10 +0100621
622 initSockets();
623
Tim Waugh892d10a2015-03-11 13:12:07 +0000624#ifdef HAVE_GETADDRINFO
625 if (UseIPv6) {
626 sa.u.sin6.sin6_family = AF_INET6;
627 sa.u.sin6.sin6_port = htons (port);
628 sa.u.sin6.sin6_addr = in6addr_loopback;
629 try {
630 new_listeners.push_back (TcpListener (&sa.u.sa, sizeof (sa.u.sin6)));
631 } catch (SocketException& e) {
632 // Ignore this if it is due to lack of address family support on
633 // the interface or on the system
634 if (e.err != EADDRNOTAVAIL && e.err != EAFNOSUPPORT)
635 // Otherwise, report the error
636 throw;
637 }
638 }
639#endif /* HAVE_GETADDRINFO */
640 if (UseIPv4) {
641 sa.u.sin.sin_family = AF_INET;
642 sa.u.sin.sin_port = htons (port);
643 sa.u.sin.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
644 try {
645 new_listeners.push_back (TcpListener (&sa.u.sa, sizeof (sa.u.sin)));
646 } catch (SocketException& e) {
647 // Ignore this if it is due to lack of address family support on
648 // the interface or on the system
649 if (e.err != EADDRNOTAVAIL && e.err != EAFNOSUPPORT)
650 // Otherwise, report the error
651 throw;
652 }
653 }
654
655 if (new_listeners.empty ())
656 throw SocketException("createLocalTcpListeners: no addresses available",
657 EADDRNOTAVAIL);
658
659 listeners->splice (listeners->end(), new_listeners);
660}
661
662void network::createTcpListeners(std::list<TcpListener> *listeners,
663 const char *addr,
664 int port)
665{
666 std::list<TcpListener> new_listeners;
667
668#ifdef HAVE_GETADDRINFO
Tim Waugh6ae42df2014-11-17 17:07:07 +0000669 struct addrinfo *ai, *current, hints;
Tim Waugh892d10a2015-03-11 13:12:07 +0000670 char service[16];
Tim Waugh6ae42df2014-11-17 17:07:07 +0000671
Pierre Ossman9d784402015-03-17 17:10:10 +0100672 initSockets();
673
Tim Waugh6ae42df2014-11-17 17:07:07 +0000674 memset(&hints, 0, sizeof(struct addrinfo));
Tim Waugh892d10a2015-03-11 13:12:07 +0000675 hints.ai_flags = AI_PASSIVE | AI_NUMERICSERV;
Tim Waugh6ae42df2014-11-17 17:07:07 +0000676 hints.ai_family = AF_UNSPEC;
677 hints.ai_socktype = SOCK_STREAM;
678 hints.ai_canonname = NULL;
679 hints.ai_addr = NULL;
680 hints.ai_next = NULL;
681
Tim Waugh892d10a2015-03-11 13:12:07 +0000682 snprintf (service, sizeof (service) - 1, "%d", port);
683 service[sizeof (service) - 1] = '\0';
684 if ((getaddrinfo(addr, service, &hints, &ai)) != 0)
685 throw rdr::SystemException("getaddrinfo", errorNumber);
Tim Waugh6ae42df2014-11-17 17:07:07 +0000686
Tim Waugh892d10a2015-03-11 13:12:07 +0000687 for (current = ai; current != NULL; current = current->ai_next) {
688 switch (current->ai_family) {
689 case AF_INET:
690 if (!UseIPv4)
691 continue;
692 break;
693
694 case AF_INET6:
695 if (!UseIPv6)
696 continue;
697 break;
698
699 default:
Tim Waugh6ae42df2014-11-17 17:07:07 +0000700 continue;
Tim Waugh892d10a2015-03-11 13:12:07 +0000701 }
Tim Waugh6ae42df2014-11-17 17:07:07 +0000702
Tim Waugh892d10a2015-03-11 13:12:07 +0000703 try {
704 new_listeners.push_back(TcpListener (current->ai_addr,
705 current->ai_addrlen));
706 } catch (SocketException& e) {
707 // Ignore this if it is due to lack of address family support on
708 // the interface or on the system
709 if (e.err != EADDRNOTAVAIL && e.err != EAFNOSUPPORT) {
710 // Otherwise, report the error
711 freeaddrinfo(ai);
712 throw;
713 }
714 }
Tim Waugh6ae42df2014-11-17 17:07:07 +0000715 }
716 freeaddrinfo(ai);
717#else
Tim Waugh892d10a2015-03-11 13:12:07 +0000718 const hostent* addrs;
719 if (addr) {
720 /* Bind to specific address */
721 addrs = gethostbyname(addr);
722 if (addrs == 0)
723 throw rdr::SystemException("gethostbyname", errorNumber);
724 if (addrs->h_addrtype != AF_INET)
725 throw rdr::Exception("createTcpListeners: bad family");
726 for (int i=0; addrs->h_addr_list[i] != 0; i++) {
727 struct sockaddr_in addr;
728 addr.sin_family = AF_INET;
729 memcpy (&addr.sin_addr, addrs->h_addr_list[i], addrs->h_length);
730 addr.sin_port = htons(port);
731 try {
732 new_listeners.push_back(TcpListener ((struct sockaddr*)&addr,
733 addrs->h_length));
734 } catch (SocketException& e) {
735 // Ignore this if it is due to lack of address family support
736 // on the interface or on the system
737 if (e.err != EADDRNOTAVAIL && e.err != EAFNOSUPPORT) {
738 // Otherwise, report the error
739 freeaddrinfo(ai);
740 throw;
741 }
742 }
743 }
744 } else {
745 /* Bind to any address */
746 struct sockaddr_in addr;
747 addr.sin_family = AF_INET;
748 addr.sin_addr.s_addr = htonl(INADDR_ANY);
749 addr.sin_port = htons(port);
750 try {
751 new_listeners.push_back(TcpListener ((struct sockaddr*)&addr,
752 sizeof (struct sockaddr_in)));
753 } catch (SocketException& e) {
754 // Ignore this if it is due to lack of address family support on
755 // the interface or on the system
756 if (e.err != EADDRNOTAVAIL && e.err != EAFNOSUPPORT) {
757 // Otherwise, report the error
758 freeaddrinfo(ai);
759 throw;
760 }
761 }
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000762 }
Tim Waugh892d10a2015-03-11 13:12:07 +0000763#endif /* defined(HAVE_GETADDRINFO) */
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000764
Tim Waugh892d10a2015-03-11 13:12:07 +0000765 if (new_listeners.empty ())
766 throw SocketException("createTcpListeners: no addresses available",
767 EADDRNOTAVAIL);
768
769 listeners->splice (listeners->end(), new_listeners);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000770}
771
772
773TcpFilter::TcpFilter(const char* spec) {
774 rfb::CharArray tmp;
Adam Tkacd36b6262009-09-04 10:57:20 +0000775 tmp.buf = rfb::strDup(spec);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000776 while (tmp.buf) {
777 rfb::CharArray first;
778 rfb::strSplit(tmp.buf, ',', &first.buf, &tmp.buf);
779 if (strlen(first.buf))
780 filter.push_back(parsePattern(first.buf));
781 }
782}
783
784TcpFilter::~TcpFilter() {
785}
786
787
788static bool
Tim Waughc24a64d2015-03-13 16:07:29 +0000789patternMatchIP(const TcpFilter::Pattern& pattern, vnc_sockaddr_t *sa) {
790 switch (pattern.address.u.sa.sa_family) {
791 unsigned long address;
792
793 case AF_INET:
794 if (sa->u.sa.sa_family != AF_INET)
795 return false;
796
797 address = sa->u.sin.sin_addr.s_addr;
798 if (address == htonl (INADDR_NONE)) return false;
799 return ((pattern.address.u.sin.sin_addr.s_addr &
800 pattern.mask.u.sin.sin_addr.s_addr) ==
801 (address & pattern.mask.u.sin.sin_addr.s_addr));
802
803 case AF_INET6:
804 if (sa->u.sa.sa_family != AF_INET6)
805 return false;
806
807 for (unsigned int n = 0; n < 16; n++) {
808 unsigned int bits = (n + 1) * 8;
809 unsigned int mask;
810 if (pattern.prefixlen > bits)
811 mask = 0xff;
812 else {
813 unsigned int lastbits = 0xff;
814 lastbits <<= bits - pattern.prefixlen;
815 mask = lastbits & 0xff;
816 }
817
818 if ((pattern.address.u.sin6.sin6_addr.s6_addr[n] & mask) !=
819 (sa->u.sin6.sin6_addr.s6_addr[n] & mask))
820 return false;
821
822 if (mask < 0xff)
823 break;
824 }
825
826 return true;
827
828 case AF_UNSPEC:
829 // Any address matches
830 return true;
831
832 default:
833 break;
834 }
835
836 return false;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000837}
838
839bool
840TcpFilter::verifyConnection(Socket* s) {
841 rfb::CharArray name;
Tim Waugh6ae42df2014-11-17 17:07:07 +0000842 vnc_sockaddr_t sa;
843 socklen_t sa_size = sizeof(sa);
Tim Waughc24a64d2015-03-13 16:07:29 +0000844
845 if (getpeername(s->getFd(), &sa.u.sa, &sa_size) != 0)
Tim Waugh6ae42df2014-11-17 17:07:07 +0000846 return false;
Tim Waugh6ae42df2014-11-17 17:07:07 +0000847
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000848 name.buf = s->getPeerAddress();
849 std::list<TcpFilter::Pattern>::iterator i;
850 for (i=filter.begin(); i!=filter.end(); i++) {
Tim Waughc24a64d2015-03-13 16:07:29 +0000851 if (patternMatchIP(*i, &sa)) {
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000852 switch ((*i).action) {
853 case Accept:
854 vlog.debug("ACCEPT %s", name.buf);
855 return true;
856 case Query:
857 vlog.debug("QUERY %s", name.buf);
858 s->setRequiresQuery();
859 return true;
860 case Reject:
861 vlog.debug("REJECT %s", name.buf);
862 return false;
863 }
864 }
865 }
866
867 vlog.debug("[REJECT] %s", name.buf);
868 return false;
869}
870
871
872TcpFilter::Pattern TcpFilter::parsePattern(const char* p) {
873 TcpFilter::Pattern pattern;
874
Tim Waughc24a64d2015-03-13 16:07:29 +0000875 rfb::CharArray addr, pref;
876 bool prefix_specified;
877 int family;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000878
Tim Waughc24a64d2015-03-13 16:07:29 +0000879 prefix_specified = rfb::strSplit(&p[1], '/', &addr.buf, &pref.buf);
880 if (addr.buf[0] == '\0') {
881 // Match any address
882 memset (&pattern.address, 0, sizeof (pattern.address));
883 pattern.address.u.sa.sa_family = AF_UNSPEC;
884 pattern.prefixlen = 0;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000885 } else {
Tim Waughc24a64d2015-03-13 16:07:29 +0000886#ifdef HAVE_GETADDRINFO
887 struct addrinfo hints;
888 struct addrinfo *ai;
889 char *p = addr.buf;
890 int result;
891 memset (&hints, 0, sizeof (hints));
892 hints.ai_family = AF_UNSPEC;
893 hints.ai_flags = AI_NUMERICHOST;
894
895 // Take out brackets, if present
896 if (*p == '[') {
897 size_t len;
898 p++;
899 len = strlen (p);
900 if (len > 0 && p[len - 1] == ']')
901 p[len - 1] = '\0';
902 }
903
904 if ((result = getaddrinfo (p, NULL, &hints, &ai)) != 0) {
905 throw Exception("unable to resolve host by name: %s",
906 gai_strerror(result));
907 }
908
909 memcpy (&pattern.address.u.sa, ai->ai_addr, ai->ai_addrlen);
910 freeaddrinfo (ai);
911#else
912 pattern.address.u.sa.sa_family = AF_INET;
913 pattern.address.u.sin.sin_addr.s_addr = inet_addr(addr.buf);
914#endif /* HAVE_GETADDRINFO */
915
916 family = pattern.address.u.sa.sa_family;
917
918 if (prefix_specified) {
919 if (family == AF_INET &&
920 rfb::strContains(pref.buf, '.')) {
921 throw Exception("mask no longer supported for filter, "
922 "use prefix instead");
923 }
924
925 pattern.prefixlen = (unsigned int) atoi(pref.buf);
926 } else {
927 switch (family) {
928 case AF_INET:
929 pattern.prefixlen = 32;
930 break;
931 case AF_INET6:
932 pattern.prefixlen = 128;
933 break;
934 default:
935 throw Exception("unknown address family");
936 }
937 }
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000938 }
939
Pierre Ossmanfdc55e52015-03-17 12:56:31 +0100940 family = pattern.address.u.sa.sa_family;
941
Tim Waughc24a64d2015-03-13 16:07:29 +0000942 if (pattern.prefixlen > (family == AF_INET ? 32: 128))
943 throw Exception("invalid prefix length for filter address: %u",
944 pattern.prefixlen);
945
946 // Compute mask from address and prefix length
947 memset (&pattern.mask, 0, sizeof (pattern.mask));
948 switch (family) {
949 unsigned long mask;
950 case AF_INET:
951 mask = 0;
952 for (unsigned int i=0; i<pattern.prefixlen; i++)
953 mask |= 1<<(31-i);
954 pattern.mask.u.sin.sin_addr.s_addr = htonl(mask);
955 break;
956
957 case AF_INET6:
958 for (unsigned int n = 0; n < 16; n++) {
959 unsigned int bits = (n + 1) * 8;
960 if (pattern.prefixlen > bits)
961 pattern.mask.u.sin6.sin6_addr.s6_addr[n] = 0xff;
962 else {
963 unsigned int lastbits = 0xff;
964 lastbits <<= bits - pattern.prefixlen;
965 pattern.mask.u.sin6.sin6_addr.s6_addr[n] = lastbits & 0xff;
966 break;
967 }
968 }
969 break;
970 case AF_UNSPEC:
971 // No mask to compute
972 break;
973 default:
974 ; /* not reached */
975 }
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000976
977 switch(p[0]) {
978 case '+': pattern.action = TcpFilter::Accept; break;
979 case '-': pattern.action = TcpFilter::Reject; break;
980 case '?': pattern.action = TcpFilter::Query; break;
981 };
982
983 return pattern;
984}
985
986char* TcpFilter::patternToStr(const TcpFilter::Pattern& p) {
Tim Waughc24a64d2015-03-13 16:07:29 +0000987 rfb::CharArray addr;
988#ifdef HAVE_GETADDRINFO
989 char buffer[INET6_ADDRSTRLEN + 2];
990
991 if (p.address.u.sa.sa_family == AF_INET) {
992 getnameinfo(&p.address.u.sa, sizeof(p.address.u.sin),
993 buffer, sizeof (buffer), NULL, 0, NI_NUMERICHOST);
994 addr.buf = rfb::strDup(buffer);
995 } else if (p.address.u.sa.sa_family == AF_INET6) {
996 buffer[0] = '[';
997 getnameinfo(&p.address.u.sa, sizeof(p.address.u.sin6),
998 buffer + 1, sizeof (buffer) - 2, NULL, 0, NI_NUMERICHOST);
999 strcat(buffer, "]");
1000 addr.buf = rfb::strDup(buffer);
1001 } else if (p.address.u.sa.sa_family == AF_UNSPEC)
1002 addr.buf = rfb::strDup("");
1003#else
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +00001004 in_addr tmp;
Tim Waughc24a64d2015-03-13 16:07:29 +00001005 tmp.s_addr = p.address.u.sin.sin_addr.s_addr;
Adam Tkacd36b6262009-09-04 10:57:20 +00001006 addr.buf = rfb::strDup(inet_ntoa(tmp));
Tim Waughc24a64d2015-03-13 16:07:29 +00001007#endif /* HAVE_GETADDRINFO */
1008
1009 char action;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +00001010 switch (p.action) {
Tim Waughc24a64d2015-03-13 16:07:29 +00001011 case Accept: action = '+'; break;
1012 case Reject: action = '-'; break;
1013 default:
1014 case Query: action = '?'; break;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +00001015 };
Tim Waughc24a64d2015-03-13 16:07:29 +00001016 size_t resultlen = (1 // action
1017 + strlen (addr.buf) // address
1018 + 1 // slash
1019 + 3 // prefix length, max 128
1020 + 1); // terminating nul
1021 char* result = new char[resultlen];
1022 if (addr.buf[0] == '\0')
1023 snprintf(result, resultlen, "%c", action);
1024 else
1025 snprintf(result, resultlen, "%c%s/%u", action, addr.buf, p.prefixlen);
1026
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +00001027 return result;
1028}