blob: 21c532b58eac99c5ac352ee66315174bc81459a5 [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];
Pierre Ossmanf7d15002015-03-17 17:10:56 +0100671 int result;
Tim Waugh6ae42df2014-11-17 17:07:07 +0000672
Pierre Ossman9d784402015-03-17 17:10:10 +0100673 initSockets();
674
Tim Waugh6ae42df2014-11-17 17:07:07 +0000675 memset(&hints, 0, sizeof(struct addrinfo));
Tim Waugh892d10a2015-03-11 13:12:07 +0000676 hints.ai_flags = AI_PASSIVE | AI_NUMERICSERV;
Tim Waugh6ae42df2014-11-17 17:07:07 +0000677 hints.ai_family = AF_UNSPEC;
678 hints.ai_socktype = SOCK_STREAM;
679 hints.ai_canonname = NULL;
680 hints.ai_addr = NULL;
681 hints.ai_next = NULL;
682
Tim Waugh892d10a2015-03-11 13:12:07 +0000683 snprintf (service, sizeof (service) - 1, "%d", port);
684 service[sizeof (service) - 1] = '\0';
Pierre Ossmanf7d15002015-03-17 17:10:56 +0100685 if ((result = getaddrinfo(addr, service, &hints, &ai)) != 0)
686 throw rdr::Exception("unable to resolve listening address: %s",
687 gai_strerror(result));
Tim Waugh6ae42df2014-11-17 17:07:07 +0000688
Tim Waugh892d10a2015-03-11 13:12:07 +0000689 for (current = ai; current != NULL; current = current->ai_next) {
690 switch (current->ai_family) {
691 case AF_INET:
692 if (!UseIPv4)
693 continue;
694 break;
695
696 case AF_INET6:
697 if (!UseIPv6)
698 continue;
699 break;
700
701 default:
Tim Waugh6ae42df2014-11-17 17:07:07 +0000702 continue;
Tim Waugh892d10a2015-03-11 13:12:07 +0000703 }
Tim Waugh6ae42df2014-11-17 17:07:07 +0000704
Tim Waugh892d10a2015-03-11 13:12:07 +0000705 try {
706 new_listeners.push_back(TcpListener (current->ai_addr,
707 current->ai_addrlen));
708 } catch (SocketException& e) {
709 // Ignore this if it is due to lack of address family support on
710 // the interface or on the system
711 if (e.err != EADDRNOTAVAIL && e.err != EAFNOSUPPORT) {
712 // Otherwise, report the error
713 freeaddrinfo(ai);
714 throw;
715 }
716 }
Tim Waugh6ae42df2014-11-17 17:07:07 +0000717 }
718 freeaddrinfo(ai);
719#else
Tim Waugh892d10a2015-03-11 13:12:07 +0000720 const hostent* addrs;
721 if (addr) {
722 /* Bind to specific address */
723 addrs = gethostbyname(addr);
724 if (addrs == 0)
725 throw rdr::SystemException("gethostbyname", errorNumber);
726 if (addrs->h_addrtype != AF_INET)
727 throw rdr::Exception("createTcpListeners: bad family");
728 for (int i=0; addrs->h_addr_list[i] != 0; i++) {
729 struct sockaddr_in addr;
730 addr.sin_family = AF_INET;
731 memcpy (&addr.sin_addr, addrs->h_addr_list[i], addrs->h_length);
732 addr.sin_port = htons(port);
733 try {
734 new_listeners.push_back(TcpListener ((struct sockaddr*)&addr,
735 addrs->h_length));
736 } catch (SocketException& e) {
737 // Ignore this if it is due to lack of address family support
738 // on the interface or on the system
739 if (e.err != EADDRNOTAVAIL && e.err != EAFNOSUPPORT) {
740 // Otherwise, report the error
741 freeaddrinfo(ai);
742 throw;
743 }
744 }
745 }
746 } else {
747 /* Bind to any address */
748 struct sockaddr_in addr;
749 addr.sin_family = AF_INET;
750 addr.sin_addr.s_addr = htonl(INADDR_ANY);
751 addr.sin_port = htons(port);
752 try {
753 new_listeners.push_back(TcpListener ((struct sockaddr*)&addr,
754 sizeof (struct sockaddr_in)));
755 } catch (SocketException& e) {
756 // Ignore this if it is due to lack of address family support on
757 // the interface or on the system
758 if (e.err != EADDRNOTAVAIL && e.err != EAFNOSUPPORT) {
759 // Otherwise, report the error
760 freeaddrinfo(ai);
761 throw;
762 }
763 }
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000764 }
Tim Waugh892d10a2015-03-11 13:12:07 +0000765#endif /* defined(HAVE_GETADDRINFO) */
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000766
Tim Waugh892d10a2015-03-11 13:12:07 +0000767 if (new_listeners.empty ())
768 throw SocketException("createTcpListeners: no addresses available",
769 EADDRNOTAVAIL);
770
771 listeners->splice (listeners->end(), new_listeners);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000772}
773
774
775TcpFilter::TcpFilter(const char* spec) {
776 rfb::CharArray tmp;
Adam Tkacd36b6262009-09-04 10:57:20 +0000777 tmp.buf = rfb::strDup(spec);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000778 while (tmp.buf) {
779 rfb::CharArray first;
780 rfb::strSplit(tmp.buf, ',', &first.buf, &tmp.buf);
781 if (strlen(first.buf))
782 filter.push_back(parsePattern(first.buf));
783 }
784}
785
786TcpFilter::~TcpFilter() {
787}
788
789
790static bool
Tim Waughc24a64d2015-03-13 16:07:29 +0000791patternMatchIP(const TcpFilter::Pattern& pattern, vnc_sockaddr_t *sa) {
792 switch (pattern.address.u.sa.sa_family) {
793 unsigned long address;
794
795 case AF_INET:
796 if (sa->u.sa.sa_family != AF_INET)
797 return false;
798
799 address = sa->u.sin.sin_addr.s_addr;
800 if (address == htonl (INADDR_NONE)) return false;
801 return ((pattern.address.u.sin.sin_addr.s_addr &
802 pattern.mask.u.sin.sin_addr.s_addr) ==
803 (address & pattern.mask.u.sin.sin_addr.s_addr));
804
805 case AF_INET6:
806 if (sa->u.sa.sa_family != AF_INET6)
807 return false;
808
809 for (unsigned int n = 0; n < 16; n++) {
810 unsigned int bits = (n + 1) * 8;
811 unsigned int mask;
812 if (pattern.prefixlen > bits)
813 mask = 0xff;
814 else {
815 unsigned int lastbits = 0xff;
816 lastbits <<= bits - pattern.prefixlen;
817 mask = lastbits & 0xff;
818 }
819
820 if ((pattern.address.u.sin6.sin6_addr.s6_addr[n] & mask) !=
821 (sa->u.sin6.sin6_addr.s6_addr[n] & mask))
822 return false;
823
824 if (mask < 0xff)
825 break;
826 }
827
828 return true;
829
830 case AF_UNSPEC:
831 // Any address matches
832 return true;
833
834 default:
835 break;
836 }
837
838 return false;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000839}
840
841bool
842TcpFilter::verifyConnection(Socket* s) {
843 rfb::CharArray name;
Tim Waugh6ae42df2014-11-17 17:07:07 +0000844 vnc_sockaddr_t sa;
845 socklen_t sa_size = sizeof(sa);
Tim Waughc24a64d2015-03-13 16:07:29 +0000846
847 if (getpeername(s->getFd(), &sa.u.sa, &sa_size) != 0)
Tim Waugh6ae42df2014-11-17 17:07:07 +0000848 return false;
Tim Waugh6ae42df2014-11-17 17:07:07 +0000849
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000850 name.buf = s->getPeerAddress();
851 std::list<TcpFilter::Pattern>::iterator i;
852 for (i=filter.begin(); i!=filter.end(); i++) {
Tim Waughc24a64d2015-03-13 16:07:29 +0000853 if (patternMatchIP(*i, &sa)) {
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000854 switch ((*i).action) {
855 case Accept:
856 vlog.debug("ACCEPT %s", name.buf);
857 return true;
858 case Query:
859 vlog.debug("QUERY %s", name.buf);
860 s->setRequiresQuery();
861 return true;
862 case Reject:
863 vlog.debug("REJECT %s", name.buf);
864 return false;
865 }
866 }
867 }
868
869 vlog.debug("[REJECT] %s", name.buf);
870 return false;
871}
872
873
874TcpFilter::Pattern TcpFilter::parsePattern(const char* p) {
875 TcpFilter::Pattern pattern;
876
Tim Waughc24a64d2015-03-13 16:07:29 +0000877 rfb::CharArray addr, pref;
878 bool prefix_specified;
879 int family;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000880
Tim Waughc24a64d2015-03-13 16:07:29 +0000881 prefix_specified = rfb::strSplit(&p[1], '/', &addr.buf, &pref.buf);
882 if (addr.buf[0] == '\0') {
883 // Match any address
884 memset (&pattern.address, 0, sizeof (pattern.address));
885 pattern.address.u.sa.sa_family = AF_UNSPEC;
886 pattern.prefixlen = 0;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000887 } else {
Tim Waughc24a64d2015-03-13 16:07:29 +0000888#ifdef HAVE_GETADDRINFO
889 struct addrinfo hints;
890 struct addrinfo *ai;
891 char *p = addr.buf;
892 int result;
893 memset (&hints, 0, sizeof (hints));
894 hints.ai_family = AF_UNSPEC;
895 hints.ai_flags = AI_NUMERICHOST;
896
897 // Take out brackets, if present
898 if (*p == '[') {
899 size_t len;
900 p++;
901 len = strlen (p);
902 if (len > 0 && p[len - 1] == ']')
903 p[len - 1] = '\0';
904 }
905
906 if ((result = getaddrinfo (p, NULL, &hints, &ai)) != 0) {
907 throw Exception("unable to resolve host by name: %s",
908 gai_strerror(result));
909 }
910
911 memcpy (&pattern.address.u.sa, ai->ai_addr, ai->ai_addrlen);
912 freeaddrinfo (ai);
913#else
914 pattern.address.u.sa.sa_family = AF_INET;
915 pattern.address.u.sin.sin_addr.s_addr = inet_addr(addr.buf);
916#endif /* HAVE_GETADDRINFO */
917
918 family = pattern.address.u.sa.sa_family;
919
920 if (prefix_specified) {
921 if (family == AF_INET &&
922 rfb::strContains(pref.buf, '.')) {
923 throw Exception("mask no longer supported for filter, "
924 "use prefix instead");
925 }
926
927 pattern.prefixlen = (unsigned int) atoi(pref.buf);
928 } else {
929 switch (family) {
930 case AF_INET:
931 pattern.prefixlen = 32;
932 break;
933 case AF_INET6:
934 pattern.prefixlen = 128;
935 break;
936 default:
937 throw Exception("unknown address family");
938 }
939 }
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000940 }
941
Pierre Ossmanfdc55e52015-03-17 12:56:31 +0100942 family = pattern.address.u.sa.sa_family;
943
Tim Waughc24a64d2015-03-13 16:07:29 +0000944 if (pattern.prefixlen > (family == AF_INET ? 32: 128))
945 throw Exception("invalid prefix length for filter address: %u",
946 pattern.prefixlen);
947
948 // Compute mask from address and prefix length
949 memset (&pattern.mask, 0, sizeof (pattern.mask));
950 switch (family) {
951 unsigned long mask;
952 case AF_INET:
953 mask = 0;
954 for (unsigned int i=0; i<pattern.prefixlen; i++)
955 mask |= 1<<(31-i);
956 pattern.mask.u.sin.sin_addr.s_addr = htonl(mask);
957 break;
958
959 case AF_INET6:
960 for (unsigned int n = 0; n < 16; n++) {
961 unsigned int bits = (n + 1) * 8;
962 if (pattern.prefixlen > bits)
963 pattern.mask.u.sin6.sin6_addr.s6_addr[n] = 0xff;
964 else {
965 unsigned int lastbits = 0xff;
966 lastbits <<= bits - pattern.prefixlen;
967 pattern.mask.u.sin6.sin6_addr.s6_addr[n] = lastbits & 0xff;
968 break;
969 }
970 }
971 break;
972 case AF_UNSPEC:
973 // No mask to compute
974 break;
975 default:
976 ; /* not reached */
977 }
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000978
979 switch(p[0]) {
980 case '+': pattern.action = TcpFilter::Accept; break;
981 case '-': pattern.action = TcpFilter::Reject; break;
982 case '?': pattern.action = TcpFilter::Query; break;
983 };
984
985 return pattern;
986}
987
988char* TcpFilter::patternToStr(const TcpFilter::Pattern& p) {
Tim Waughc24a64d2015-03-13 16:07:29 +0000989 rfb::CharArray addr;
990#ifdef HAVE_GETADDRINFO
991 char buffer[INET6_ADDRSTRLEN + 2];
992
993 if (p.address.u.sa.sa_family == AF_INET) {
994 getnameinfo(&p.address.u.sa, sizeof(p.address.u.sin),
995 buffer, sizeof (buffer), NULL, 0, NI_NUMERICHOST);
996 addr.buf = rfb::strDup(buffer);
997 } else if (p.address.u.sa.sa_family == AF_INET6) {
998 buffer[0] = '[';
999 getnameinfo(&p.address.u.sa, sizeof(p.address.u.sin6),
1000 buffer + 1, sizeof (buffer) - 2, NULL, 0, NI_NUMERICHOST);
1001 strcat(buffer, "]");
1002 addr.buf = rfb::strDup(buffer);
1003 } else if (p.address.u.sa.sa_family == AF_UNSPEC)
1004 addr.buf = rfb::strDup("");
1005#else
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +00001006 in_addr tmp;
Tim Waughc24a64d2015-03-13 16:07:29 +00001007 tmp.s_addr = p.address.u.sin.sin_addr.s_addr;
Adam Tkacd36b6262009-09-04 10:57:20 +00001008 addr.buf = rfb::strDup(inet_ntoa(tmp));
Tim Waughc24a64d2015-03-13 16:07:29 +00001009#endif /* HAVE_GETADDRINFO */
1010
1011 char action;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +00001012 switch (p.action) {
Tim Waughc24a64d2015-03-13 16:07:29 +00001013 case Accept: action = '+'; break;
1014 case Reject: action = '-'; break;
1015 default:
1016 case Query: action = '?'; break;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +00001017 };
Tim Waughc24a64d2015-03-13 16:07:29 +00001018 size_t resultlen = (1 // action
1019 + strlen (addr.buf) // address
1020 + 1 // slash
1021 + 3 // prefix length, max 128
1022 + 1); // terminating nul
1023 char* result = new char[resultlen];
1024 if (addr.buf[0] == '\0')
1025 snprintf(result, resultlen, "%c", action);
1026 else
1027 snprintf(result, resultlen, "%c%s/%u", action, addr.buf, p.prefixlen);
1028
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +00001029 return result;
1030}