blob: 51989e493392481495d8ce771242da64744d10e2 [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
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000065using namespace network;
66using namespace rdr;
67
68static rfb::LogWriter vlog("TcpSocket");
69
Pierre Ossman39b3b8f2015-01-29 17:35:45 +010070static rfb::BoolParameter UseIPv4("UseIPv4", "Use IPv4 for incoming and outgoing connections.", true);
71#ifdef HAVE_GETADDRINFO
72static rfb::BoolParameter UseIPv6("UseIPv6", "Use IPv6 for incoming and outgoing connections.", true);
73#endif
74
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000075/* Tunnelling support. */
76int network::findFreeTcpPort (void)
77{
DRCb2618e52011-02-21 13:43:44 +000078 int sock;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000079 struct sockaddr_in addr;
80 memset(&addr, 0, sizeof(addr));
81 addr.sin_family = AF_INET;
82 addr.sin_addr.s_addr = INADDR_ANY;
83
84 if ((sock = socket (AF_INET, SOCK_STREAM, 0)) < 0)
85 throw SocketException ("unable to create socket", errorNumber);
86
DRCb2618e52011-02-21 13:43:44 +000087 addr.sin_port = 0;
88 if (bind (sock, (struct sockaddr *)&addr, sizeof (addr)) < 0)
89 throw SocketException ("unable to find free port", errorNumber);
90
91 socklen_t n = sizeof(addr);
92 if (getsockname (sock, (struct sockaddr *)&addr, &n) < 0)
93 throw SocketException ("unable to get port number", errorNumber);
94
95 closesocket (sock);
96 return ntohs(addr.sin_port);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000097}
98
99
100// -=- Socket initialisation
101static bool socketsInitialised = false;
102static void initSockets() {
103 if (socketsInitialised)
104 return;
105#ifdef WIN32
106 WORD requiredVersion = MAKEWORD(2,0);
107 WSADATA initResult;
108
109 if (WSAStartup(requiredVersion, &initResult) != 0)
110 throw SocketException("unable to initialise Winsock2", errorNumber);
111#else
112 signal(SIGPIPE, SIG_IGN);
113#endif
114 socketsInitialised = true;
115}
116
117
118// -=- TcpSocket
119
120TcpSocket::TcpSocket(int sock, bool close)
121 : Socket(new FdInStream(sock), new FdOutStream(sock), true), closeFd(close)
122{
123}
124
125TcpSocket::TcpSocket(const char *host, int port)
126 : closeFd(true)
127{
Adam Tkac9cb6a422008-11-14 15:56:15 +0000128 int sock, err, result, family;
129 vnc_sockaddr_t sa;
Adam Tkacbe4c3ac2008-12-10 16:42:33 +0000130 socklen_t salen;
Adam Tkac9cb6a422008-11-14 15:56:15 +0000131#ifdef HAVE_GETADDRINFO
132 struct addrinfo *ai, *current, hints;
133#endif
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000134
135 // - Create a socket
136 initSockets();
Adam Tkac9cb6a422008-11-14 15:56:15 +0000137
138#ifdef HAVE_GETADDRINFO
139 memset(&hints, 0, sizeof(struct addrinfo));
140 hints.ai_family = AF_UNSPEC;
141 hints.ai_socktype = SOCK_STREAM;
142 hints.ai_canonname = NULL;
143 hints.ai_addr = NULL;
144 hints.ai_next = NULL;
145
146 if ((result = getaddrinfo(host, NULL, &hints, &ai)) != 0) {
147 throw Exception("unable to resolve host by name: %s",
Tim Waugha85363d2015-03-11 13:07:48 +0000148 gai_strerror(result));
Adam Tkac9cb6a422008-11-14 15:56:15 +0000149 }
150
Pierre Ossmanf1a35012015-03-03 16:02:42 +0100151 // This logic is too complex for the compiler to determine if
152 // sock is properly assigned or not.
153 sock = -1;
154
Adam Tkac9cb6a422008-11-14 15:56:15 +0000155 for (current = ai; current != NULL; current = current->ai_next) {
156 family = current->ai_family;
Pierre Ossman39b3b8f2015-01-29 17:35:45 +0100157
158 switch (family) {
159 case AF_INET:
160 if (!UseIPv4)
161 continue;
162 break;
163 case AF_INET6:
164 if (!UseIPv6)
165 continue;
166 break;
167 default:
Adam Tkac9cb6a422008-11-14 15:56:15 +0000168 continue;
Pierre Ossman39b3b8f2015-01-29 17:35:45 +0100169 }
Adam Tkac9cb6a422008-11-14 15:56:15 +0000170
171 salen = current->ai_addrlen;
172 memcpy(&sa, current->ai_addr, salen);
173
174 if (family == AF_INET)
175 sa.u.sin.sin_port = htons(port);
176 else
177 sa.u.sin6.sin6_port = htons(port);
178
179#else /* HAVE_GETADDRINFO */
Pierre Ossman39b3b8f2015-01-29 17:35:45 +0100180 if (!UseIPv4)
181 throw Exception("Only IPv4 available but it is disabled");
182
Adam Tkac9cb6a422008-11-14 15:56:15 +0000183 family = AF_INET;
184 salen = sizeof(struct sockaddr_in);
185
186 /* Try processing the host as an IP address */
187 memset(&sa, 0, sizeof(sa));
188 sa.u.sin.sin_family = AF_INET;
189 sa.u.sin.sin_addr.s_addr = inet_addr((char *)host);
190 sa.u.sin.sin_port = htons(port);
191 if ((int)sa.u.sin.sin_addr.s_addr == -1) {
192 /* Host was not an IP address - try resolving as DNS name */
193 struct hostent *hostinfo;
194 hostinfo = gethostbyname((char *)host);
195 if (hostinfo && hostinfo->h_addr) {
196 sa.u.sin.sin_addr.s_addr = ((struct in_addr *)hostinfo->h_addr)->s_addr;
197 } else {
198 err = errorNumber;
199 throw SocketException("unable to resolve host by name", err);
200 }
201 }
202#endif /* HAVE_GETADDRINFO */
203
204 sock = socket (family, SOCK_STREAM, 0);
205 if (sock == -1) {
206 err = errorNumber;
207#ifdef HAVE_GETADDRINFO
208 freeaddrinfo(ai);
209#endif /* HAVE_GETADDRINFO */
210 throw SocketException("unable to create socket", err);
211 }
212
213 /* Attempt to connect to the remote host */
Adam Tkacc9cda3b2009-10-30 11:13:34 +0000214 while ((result = connect(sock, &sa.u.sa, salen)) == -1) {
Adam Tkac9cb6a422008-11-14 15:56:15 +0000215 err = errorNumber;
216#ifndef WIN32
217 if (err == EINTR)
Tim Waugha85363d2015-03-11 13:07:48 +0000218 continue;
Adam Tkac9cb6a422008-11-14 15:56:15 +0000219#endif
220 closesocket(sock);
221 break;
222 }
223
224#ifdef HAVE_GETADDRINFO
225 if (result == 0)
226 break;
Adam Tkac9cb6a422008-11-14 15:56:15 +0000227 }
228
229 freeaddrinfo(ai);
Pierre Ossmanda9a38d2015-03-03 16:03:32 +0100230
231 if (current == NULL)
232 throw Exception("No useful address for host");
Adam Tkac9cb6a422008-11-14 15:56:15 +0000233#endif /* HAVE_GETADDRINFO */
234
235 if (result == -1)
236 throw SocketException("unable connect to socket", err);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000237
238#ifndef WIN32
239 // - By default, close the socket on exec()
240 fcntl(sock, F_SETFD, FD_CLOEXEC);
241#endif
242
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000243 // Disable Nagle's algorithm, to reduce latency
244 enableNagles(sock, false);
245
246 // Create the input and output streams
247 instream = new FdInStream(sock);
248 outstream = new FdOutStream(sock);
249 ownStreams = true;
250}
251
252TcpSocket::~TcpSocket() {
253 if (closeFd)
254 closesocket(getFd());
255}
256
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000257int TcpSocket::getMyPort() {
258 return getSockPort(getFd());
259}
260
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000261char* TcpSocket::getPeerAddress() {
Tim Waugh6ae42df2014-11-17 17:07:07 +0000262 vnc_sockaddr_t sa;
263 socklen_t sa_size = sizeof(sa);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000264
Tim Waugh6ae42df2014-11-17 17:07:07 +0000265 if (getpeername(getFd(), &sa.u.sa, &sa_size) != 0) {
266 vlog.error("unable to get peer name for socket");
267 return rfb::strDup("");
268 }
269
Tim Waugh892d10a2015-03-11 13:12:07 +0000270#if defined(HAVE_GETADDRINFO)
Pierre Ossman14263e12014-11-19 11:14:49 +0100271 if (sa.u.sa.sa_family == AF_INET6) {
Pierre Ossman07cd2292014-11-19 11:16:04 +0100272 char buffer[INET6_ADDRSTRLEN + 2];
Tim Waugh892d10a2015-03-11 13:12:07 +0000273 int ret;
Tim Waugh6ae42df2014-11-17 17:07:07 +0000274
Pierre Ossman07cd2292014-11-19 11:16:04 +0100275 buffer[0] = '[';
276
Tim Waugh892d10a2015-03-11 13:12:07 +0000277 ret = getnameinfo(&sa.u.sa, sizeof(sa.u.sin6),
278 buffer + 1, sizeof(buffer) - 2, NULL, 0,
279 NI_NUMERICHOST);
280 if (ret != 0) {
Pierre Ossman14263e12014-11-19 11:14:49 +0100281 vlog.error("unable to convert peer name to a string");
282 return rfb::strDup("");
283 }
Tim Waugh6ae42df2014-11-17 17:07:07 +0000284
Pierre Ossman07cd2292014-11-19 11:16:04 +0100285 strcat(buffer, "]");
286
287 return rfb::strDup(buffer);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000288 }
Pierre Ossman14263e12014-11-19 11:14:49 +0100289#endif
290
291 if (sa.u.sa.sa_family == AF_INET) {
292 char *name;
293
294 name = inet_ntoa(sa.u.sin.sin_addr);
295 if (name == NULL) {
296 vlog.error("unable to convert peer name to a string");
297 return rfb::strDup("");
298 }
299
300 return rfb::strDup(name);
301 }
302
303 vlog.error("unknown address family for socket");
304 return rfb::strDup("");
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000305}
306
307int TcpSocket::getPeerPort() {
Tim Waugh6ae42df2014-11-17 17:07:07 +0000308 vnc_sockaddr_t sa;
309 socklen_t sa_size = sizeof(sa);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000310
Tim Waugh6ae42df2014-11-17 17:07:07 +0000311 getpeername(getFd(), &sa.u.sa, &sa_size);
312
313 switch (sa.u.sa.sa_family) {
314#ifdef HAVE_GETADDRINFO
315 case AF_INET6:
316 return ntohs(sa.u.sin6.sin6_port);
317#endif /* HAVE_GETADDRINFO */
Pierre Ossman14263e12014-11-19 11:14:49 +0100318 case AF_INET:
Tim Waugh6ae42df2014-11-17 17:07:07 +0000319 return ntohs(sa.u.sin.sin_port);
Pierre Ossman14263e12014-11-19 11:14:49 +0100320 default:
321 return 0;
Tim Waugh6ae42df2014-11-17 17:07:07 +0000322 }
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000323}
324
325char* TcpSocket::getPeerEndpoint() {
326 rfb::CharArray address; address.buf = getPeerAddress();
327 int port = getPeerPort();
328
329 int buflen = strlen(address.buf) + 32;
330 char* buffer = new char[buflen];
331 sprintf(buffer, "%s::%d", address.buf, port);
332 return buffer;
333}
334
335bool TcpSocket::sameMachine() {
Adam Tkac897814f2009-11-12 10:32:43 +0000336 vnc_sockaddr_t peeraddr, myaddr;
337 socklen_t addrlen;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000338
Adam Tkac897814f2009-11-12 10:32:43 +0000339 addrlen = sizeof(peeraddr);
340 if (getpeername(getFd(), &peeraddr.u.sa, &addrlen) < 0)
341 throw SocketException ("unable to get peer address", errorNumber);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000342
Adam Tkac897814f2009-11-12 10:32:43 +0000343 addrlen = sizeof(myaddr); /* need to reset, since getpeername overwrote */
344 if (getsockname(getFd(), &myaddr.u.sa, &addrlen) < 0)
345 throw SocketException ("unable to get my address", errorNumber);
346
347 if (peeraddr.u.sa.sa_family != myaddr.u.sa.sa_family)
348 return false;
349
350#ifdef HAVE_GETADDRINFO
351 if (peeraddr.u.sa.sa_family == AF_INET6)
352 return IN6_ARE_ADDR_EQUAL(&peeraddr.u.sin6.sin6_addr,
Tim Waugha85363d2015-03-11 13:07:48 +0000353 &myaddr.u.sin6.sin6_addr);
Adam Tkac897814f2009-11-12 10:32:43 +0000354#endif
355
Pierre Ossman14263e12014-11-19 11:14:49 +0100356 if (peeraddr.u.sa.sa_family == AF_INET)
357 return (peeraddr.u.sin.sin_addr.s_addr == myaddr.u.sin.sin_addr.s_addr);
358
359 // No idea what this is. Assume we're on different machines.
360 return false;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000361}
362
363void TcpSocket::shutdown()
364{
365 Socket::shutdown();
366 ::shutdown(getFd(), 2);
367}
368
369bool TcpSocket::enableNagles(int sock, bool enable) {
370 int one = enable ? 0 : 1;
371 if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
Tim Waugha85363d2015-03-11 13:07:48 +0000372 (char *)&one, sizeof(one)) < 0) {
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000373 int e = errorNumber;
374 vlog.error("unable to setsockopt TCP_NODELAY: %d", e);
375 return false;
376 }
377 return true;
378}
379
Pierre Ossman64069a92011-11-08 12:10:55 +0000380bool TcpSocket::cork(int sock, bool enable) {
381#ifndef TCP_CORK
382 return false;
383#else
384 int one = enable ? 1 : 0;
385 if (setsockopt(sock, IPPROTO_TCP, TCP_CORK, (char *)&one, sizeof(one)) < 0)
386 return false;
387 return true;
388#endif
389}
390
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000391bool TcpSocket::isSocket(int sock)
392{
Tim Waugh6ae42df2014-11-17 17:07:07 +0000393 vnc_sockaddr_t sa;
394 socklen_t sa_size = sizeof(sa);
395 return getsockname(sock, &sa.u.sa, &sa_size) >= 0;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000396}
397
398bool TcpSocket::isConnected(int sock)
399{
Tim Waugh6ae42df2014-11-17 17:07:07 +0000400 vnc_sockaddr_t sa;
401 socklen_t sa_size = sizeof(sa);
402 return getpeername(sock, &sa.u.sa, &sa_size) >= 0;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000403}
404
405int TcpSocket::getSockPort(int sock)
406{
Tim Waugh6ae42df2014-11-17 17:07:07 +0000407 vnc_sockaddr_t sa;
408 socklen_t sa_size = sizeof(sa);
409 if (getsockname(sock, &sa.u.sa, &sa_size) < 0)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000410 return 0;
Tim Waugh6ae42df2014-11-17 17:07:07 +0000411
412 switch (sa.u.sa.sa_family) {
413#ifdef HAVE_GETADDRINFO
414 case AF_INET6:
415 return ntohs(sa.u.sin6.sin6_port);
416#endif /* HAVE_GETADDRINFO */
417
418 default:
419 return ntohs(sa.u.sin.sin_port);
420 }
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000421}
422
Tim Waugh892d10a2015-03-11 13:12:07 +0000423TcpListener::TcpListener(int sock)
Tim Waughe4d97262014-11-21 16:07:34 +0000424{
Tim Waugh892d10a2015-03-11 13:12:07 +0000425 fd = sock;
Tim Waughe4d97262014-11-21 16:07:34 +0000426}
427
Tim Waugh892d10a2015-03-11 13:12:07 +0000428TcpListener::TcpListener(const TcpListener& other)
Tim Waughe4d97262014-11-21 16:07:34 +0000429{
Tim Waugh892d10a2015-03-11 13:12:07 +0000430 fd = dup (other.fd);
431 // Hope TcpListener::shutdown(other) doesn't get called...
Tim Waughe4d97262014-11-21 16:07:34 +0000432}
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000433
Tim Waugh892d10a2015-03-11 13:12:07 +0000434TcpListener& TcpListener::operator= (const TcpListener& other)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000435{
Tim Waugh892d10a2015-03-11 13:12:07 +0000436 if (this != &other)
437 {
438 closesocket (fd);
439 fd = dup (other.fd);
440 // Hope TcpListener::shutdown(other) doesn't get called...
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000441 }
Tim Waugh892d10a2015-03-11 13:12:07 +0000442 return *this;
443}
444
445TcpListener::TcpListener(const struct sockaddr *listenaddr,
446 socklen_t listenaddrlen)
447{
448 int one = 1;
449 vnc_sockaddr_t sa;
450 int sock;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000451
452 initSockets();
Tim Waugh892d10a2015-03-11 13:12:07 +0000453
454 if ((sock = socket (listenaddr->sa_family, SOCK_STREAM, 0)) < 0)
455 throw SocketException("unable to create listening socket", errorNumber);
456
457 memcpy (&sa, listenaddr, listenaddrlen);
458#ifdef IPV6_V6ONLY
459 if (listenaddr->sa_family == AF_INET6) {
460 if (setsockopt (sock, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&one, sizeof(one)))
461 throw SocketException("unable to set IPV6_V6ONLY", errorNumber);
462 }
463#endif /* defined(IPV6_V6ONLY) */
464
465 if (bind(sock, &sa.u.sa, listenaddrlen) == -1) {
466 closesocket(sock);
467 throw SocketException("failed to bind socket", errorNumber);
468 }
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000469
470#ifndef WIN32
471 // - By default, close the socket on exec()
Tim Waugh892d10a2015-03-11 13:12:07 +0000472 fcntl(sock, F_SETFD, FD_CLOEXEC);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000473
Tim Waugh892d10a2015-03-11 13:12:07 +0000474 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
475 (char *)&one, sizeof(one)) < 0) {
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000476 int e = errorNumber;
Tim Waugh892d10a2015-03-11 13:12:07 +0000477 closesocket(sock);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000478 throw SocketException("unable to create listening socket", e);
479 }
480#endif
481
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000482 // - Set it to be a listening socket
Tim Waugh892d10a2015-03-11 13:12:07 +0000483 if (listen(sock, 5) < 0) {
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000484 int e = errorNumber;
Tim Waugh892d10a2015-03-11 13:12:07 +0000485 closesocket(sock);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000486 throw SocketException("unable to set socket to listening mode", e);
487 }
Tim Waugh892d10a2015-03-11 13:12:07 +0000488
489 fd = sock;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000490}
491
492TcpListener::~TcpListener() {
Tim Waugh892d10a2015-03-11 13:12:07 +0000493 closesocket(fd);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000494}
495
496void TcpListener::shutdown()
497{
498#ifdef WIN32
499 closesocket(getFd());
500#else
501 ::shutdown(getFd(), 2);
502#endif
503}
504
505
506Socket*
507TcpListener::accept() {
508 int new_sock = -1;
509
510 // Accept an incoming connection
511 if ((new_sock = ::accept(fd, 0, 0)) < 0)
512 throw SocketException("unable to accept new connection", errorNumber);
513
514#ifndef WIN32
515 // - By default, close the socket on exec()
516 fcntl(new_sock, F_SETFD, FD_CLOEXEC);
517#endif
518
519 // Disable Nagle's algorithm, to reduce latency
520 TcpSocket::enableNagles(new_sock, false);
521
522 // Create the socket object & check connection is allowed
523 TcpSocket* s = new TcpSocket(new_sock);
524 if (filter && !filter->verifyConnection(s)) {
525 delete s;
526 return 0;
527 }
528 return s;
529}
530
Tim Waugh892d10a2015-03-11 13:12:07 +0000531int TcpListener::getMyPort() {
532 return TcpSocket::getSockPort(getFd());
533}
534
535
536void network::createLocalTcpListeners(std::list<TcpListener> *listeners,
537 int port)
538{
539 std::list<TcpListener> new_listeners;
540 vnc_sockaddr_t sa;
541#ifdef HAVE_GETADDRINFO
542 if (UseIPv6) {
543 sa.u.sin6.sin6_family = AF_INET6;
544 sa.u.sin6.sin6_port = htons (port);
545 sa.u.sin6.sin6_addr = in6addr_loopback;
546 try {
547 new_listeners.push_back (TcpListener (&sa.u.sa, sizeof (sa.u.sin6)));
548 } catch (SocketException& e) {
549 // Ignore this if it is due to lack of address family support on
550 // the interface or on the system
551 if (e.err != EADDRNOTAVAIL && e.err != EAFNOSUPPORT)
552 // Otherwise, report the error
553 throw;
554 }
555 }
556#endif /* HAVE_GETADDRINFO */
557 if (UseIPv4) {
558 sa.u.sin.sin_family = AF_INET;
559 sa.u.sin.sin_port = htons (port);
560 sa.u.sin.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
561 try {
562 new_listeners.push_back (TcpListener (&sa.u.sa, sizeof (sa.u.sin)));
563 } catch (SocketException& e) {
564 // Ignore this if it is due to lack of address family support on
565 // the interface or on the system
566 if (e.err != EADDRNOTAVAIL && e.err != EAFNOSUPPORT)
567 // Otherwise, report the error
568 throw;
569 }
570 }
571
572 if (new_listeners.empty ())
573 throw SocketException("createLocalTcpListeners: no addresses available",
574 EADDRNOTAVAIL);
575
576 listeners->splice (listeners->end(), new_listeners);
577}
578
579void network::createTcpListeners(std::list<TcpListener> *listeners,
580 const char *addr,
581 int port)
582{
583 std::list<TcpListener> new_listeners;
584
585#ifdef HAVE_GETADDRINFO
Tim Waugh6ae42df2014-11-17 17:07:07 +0000586 struct addrinfo *ai, *current, hints;
Tim Waugh892d10a2015-03-11 13:12:07 +0000587 char service[16];
Tim Waugh6ae42df2014-11-17 17:07:07 +0000588
589 memset(&hints, 0, sizeof(struct addrinfo));
Tim Waugh892d10a2015-03-11 13:12:07 +0000590 hints.ai_flags = AI_PASSIVE | AI_NUMERICSERV;
Tim Waugh6ae42df2014-11-17 17:07:07 +0000591 hints.ai_family = AF_UNSPEC;
592 hints.ai_socktype = SOCK_STREAM;
593 hints.ai_canonname = NULL;
594 hints.ai_addr = NULL;
595 hints.ai_next = NULL;
596
Tim Waugh892d10a2015-03-11 13:12:07 +0000597 snprintf (service, sizeof (service) - 1, "%d", port);
598 service[sizeof (service) - 1] = '\0';
599 if ((getaddrinfo(addr, service, &hints, &ai)) != 0)
600 throw rdr::SystemException("getaddrinfo", errorNumber);
Tim Waugh6ae42df2014-11-17 17:07:07 +0000601
Tim Waugh892d10a2015-03-11 13:12:07 +0000602 for (current = ai; current != NULL; current = current->ai_next) {
603 switch (current->ai_family) {
604 case AF_INET:
605 if (!UseIPv4)
606 continue;
607 break;
608
609 case AF_INET6:
610 if (!UseIPv6)
611 continue;
612 break;
613
614 default:
Tim Waugh6ae42df2014-11-17 17:07:07 +0000615 continue;
Tim Waugh892d10a2015-03-11 13:12:07 +0000616 }
Tim Waugh6ae42df2014-11-17 17:07:07 +0000617
Tim Waugh892d10a2015-03-11 13:12:07 +0000618 try {
619 new_listeners.push_back(TcpListener (current->ai_addr,
620 current->ai_addrlen));
621 } catch (SocketException& e) {
622 // Ignore this if it is due to lack of address family support on
623 // the interface or on the system
624 if (e.err != EADDRNOTAVAIL && e.err != EAFNOSUPPORT) {
625 // Otherwise, report the error
626 freeaddrinfo(ai);
627 throw;
628 }
629 }
Tim Waugh6ae42df2014-11-17 17:07:07 +0000630 }
631 freeaddrinfo(ai);
632#else
Tim Waugh892d10a2015-03-11 13:12:07 +0000633 const hostent* addrs;
634 if (addr) {
635 /* Bind to specific address */
636 addrs = gethostbyname(addr);
637 if (addrs == 0)
638 throw rdr::SystemException("gethostbyname", errorNumber);
639 if (addrs->h_addrtype != AF_INET)
640 throw rdr::Exception("createTcpListeners: bad family");
641 for (int i=0; addrs->h_addr_list[i] != 0; i++) {
642 struct sockaddr_in addr;
643 addr.sin_family = AF_INET;
644 memcpy (&addr.sin_addr, addrs->h_addr_list[i], addrs->h_length);
645 addr.sin_port = htons(port);
646 try {
647 new_listeners.push_back(TcpListener ((struct sockaddr*)&addr,
648 addrs->h_length));
649 } catch (SocketException& e) {
650 // Ignore this if it is due to lack of address family support
651 // on the interface or on the system
652 if (e.err != EADDRNOTAVAIL && e.err != EAFNOSUPPORT) {
653 // Otherwise, report the error
654 freeaddrinfo(ai);
655 throw;
656 }
657 }
658 }
659 } else {
660 /* Bind to any address */
661 struct sockaddr_in addr;
662 addr.sin_family = AF_INET;
663 addr.sin_addr.s_addr = htonl(INADDR_ANY);
664 addr.sin_port = htons(port);
665 try {
666 new_listeners.push_back(TcpListener ((struct sockaddr*)&addr,
667 sizeof (struct sockaddr_in)));
668 } catch (SocketException& e) {
669 // Ignore this if it is due to lack of address family support on
670 // the interface or on the system
671 if (e.err != EADDRNOTAVAIL && e.err != EAFNOSUPPORT) {
672 // Otherwise, report the error
673 freeaddrinfo(ai);
674 throw;
675 }
676 }
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000677 }
Tim Waugh892d10a2015-03-11 13:12:07 +0000678#endif /* defined(HAVE_GETADDRINFO) */
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000679
Tim Waugh892d10a2015-03-11 13:12:07 +0000680 if (new_listeners.empty ())
681 throw SocketException("createTcpListeners: no addresses available",
682 EADDRNOTAVAIL);
683
684 listeners->splice (listeners->end(), new_listeners);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000685}
686
687
688TcpFilter::TcpFilter(const char* spec) {
689 rfb::CharArray tmp;
Adam Tkacd36b6262009-09-04 10:57:20 +0000690 tmp.buf = rfb::strDup(spec);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000691 while (tmp.buf) {
692 rfb::CharArray first;
693 rfb::strSplit(tmp.buf, ',', &first.buf, &tmp.buf);
694 if (strlen(first.buf))
695 filter.push_back(parsePattern(first.buf));
696 }
697}
698
699TcpFilter::~TcpFilter() {
700}
701
702
703static bool
Tim Waughc24a64d2015-03-13 16:07:29 +0000704patternMatchIP(const TcpFilter::Pattern& pattern, vnc_sockaddr_t *sa) {
705 switch (pattern.address.u.sa.sa_family) {
706 unsigned long address;
707
708 case AF_INET:
709 if (sa->u.sa.sa_family != AF_INET)
710 return false;
711
712 address = sa->u.sin.sin_addr.s_addr;
713 if (address == htonl (INADDR_NONE)) return false;
714 return ((pattern.address.u.sin.sin_addr.s_addr &
715 pattern.mask.u.sin.sin_addr.s_addr) ==
716 (address & pattern.mask.u.sin.sin_addr.s_addr));
717
718 case AF_INET6:
719 if (sa->u.sa.sa_family != AF_INET6)
720 return false;
721
722 for (unsigned int n = 0; n < 16; n++) {
723 unsigned int bits = (n + 1) * 8;
724 unsigned int mask;
725 if (pattern.prefixlen > bits)
726 mask = 0xff;
727 else {
728 unsigned int lastbits = 0xff;
729 lastbits <<= bits - pattern.prefixlen;
730 mask = lastbits & 0xff;
731 }
732
733 if ((pattern.address.u.sin6.sin6_addr.s6_addr[n] & mask) !=
734 (sa->u.sin6.sin6_addr.s6_addr[n] & mask))
735 return false;
736
737 if (mask < 0xff)
738 break;
739 }
740
741 return true;
742
743 case AF_UNSPEC:
744 // Any address matches
745 return true;
746
747 default:
748 break;
749 }
750
751 return false;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000752}
753
754bool
755TcpFilter::verifyConnection(Socket* s) {
756 rfb::CharArray name;
Tim Waugh6ae42df2014-11-17 17:07:07 +0000757 vnc_sockaddr_t sa;
758 socklen_t sa_size = sizeof(sa);
Tim Waughc24a64d2015-03-13 16:07:29 +0000759
760 if (getpeername(s->getFd(), &sa.u.sa, &sa_size) != 0)
Tim Waugh6ae42df2014-11-17 17:07:07 +0000761 return false;
Tim Waugh6ae42df2014-11-17 17:07:07 +0000762
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000763 name.buf = s->getPeerAddress();
764 std::list<TcpFilter::Pattern>::iterator i;
765 for (i=filter.begin(); i!=filter.end(); i++) {
Tim Waughc24a64d2015-03-13 16:07:29 +0000766 if (patternMatchIP(*i, &sa)) {
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000767 switch ((*i).action) {
768 case Accept:
769 vlog.debug("ACCEPT %s", name.buf);
770 return true;
771 case Query:
772 vlog.debug("QUERY %s", name.buf);
773 s->setRequiresQuery();
774 return true;
775 case Reject:
776 vlog.debug("REJECT %s", name.buf);
777 return false;
778 }
779 }
780 }
781
782 vlog.debug("[REJECT] %s", name.buf);
783 return false;
784}
785
786
787TcpFilter::Pattern TcpFilter::parsePattern(const char* p) {
788 TcpFilter::Pattern pattern;
789
Tim Waughc24a64d2015-03-13 16:07:29 +0000790 rfb::CharArray addr, pref;
791 bool prefix_specified;
792 int family;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000793
Tim Waughc24a64d2015-03-13 16:07:29 +0000794 prefix_specified = rfb::strSplit(&p[1], '/', &addr.buf, &pref.buf);
795 if (addr.buf[0] == '\0') {
796 // Match any address
797 memset (&pattern.address, 0, sizeof (pattern.address));
798 pattern.address.u.sa.sa_family = AF_UNSPEC;
799 pattern.prefixlen = 0;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000800 } else {
Tim Waughc24a64d2015-03-13 16:07:29 +0000801#ifdef HAVE_GETADDRINFO
802 struct addrinfo hints;
803 struct addrinfo *ai;
804 char *p = addr.buf;
805 int result;
806 memset (&hints, 0, sizeof (hints));
807 hints.ai_family = AF_UNSPEC;
808 hints.ai_flags = AI_NUMERICHOST;
809
810 // Take out brackets, if present
811 if (*p == '[') {
812 size_t len;
813 p++;
814 len = strlen (p);
815 if (len > 0 && p[len - 1] == ']')
816 p[len - 1] = '\0';
817 }
818
819 if ((result = getaddrinfo (p, NULL, &hints, &ai)) != 0) {
820 throw Exception("unable to resolve host by name: %s",
821 gai_strerror(result));
822 }
823
824 memcpy (&pattern.address.u.sa, ai->ai_addr, ai->ai_addrlen);
825 freeaddrinfo (ai);
826#else
827 pattern.address.u.sa.sa_family = AF_INET;
828 pattern.address.u.sin.sin_addr.s_addr = inet_addr(addr.buf);
829#endif /* HAVE_GETADDRINFO */
830
831 family = pattern.address.u.sa.sa_family;
832
833 if (prefix_specified) {
834 if (family == AF_INET &&
835 rfb::strContains(pref.buf, '.')) {
836 throw Exception("mask no longer supported for filter, "
837 "use prefix instead");
838 }
839
840 pattern.prefixlen = (unsigned int) atoi(pref.buf);
841 } else {
842 switch (family) {
843 case AF_INET:
844 pattern.prefixlen = 32;
845 break;
846 case AF_INET6:
847 pattern.prefixlen = 128;
848 break;
849 default:
850 throw Exception("unknown address family");
851 }
852 }
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000853 }
854
Pierre Ossmanfdc55e52015-03-17 12:56:31 +0100855 family = pattern.address.u.sa.sa_family;
856
Tim Waughc24a64d2015-03-13 16:07:29 +0000857 if (pattern.prefixlen > (family == AF_INET ? 32: 128))
858 throw Exception("invalid prefix length for filter address: %u",
859 pattern.prefixlen);
860
861 // Compute mask from address and prefix length
862 memset (&pattern.mask, 0, sizeof (pattern.mask));
863 switch (family) {
864 unsigned long mask;
865 case AF_INET:
866 mask = 0;
867 for (unsigned int i=0; i<pattern.prefixlen; i++)
868 mask |= 1<<(31-i);
869 pattern.mask.u.sin.sin_addr.s_addr = htonl(mask);
870 break;
871
872 case AF_INET6:
873 for (unsigned int n = 0; n < 16; n++) {
874 unsigned int bits = (n + 1) * 8;
875 if (pattern.prefixlen > bits)
876 pattern.mask.u.sin6.sin6_addr.s6_addr[n] = 0xff;
877 else {
878 unsigned int lastbits = 0xff;
879 lastbits <<= bits - pattern.prefixlen;
880 pattern.mask.u.sin6.sin6_addr.s6_addr[n] = lastbits & 0xff;
881 break;
882 }
883 }
884 break;
885 case AF_UNSPEC:
886 // No mask to compute
887 break;
888 default:
889 ; /* not reached */
890 }
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000891
892 switch(p[0]) {
893 case '+': pattern.action = TcpFilter::Accept; break;
894 case '-': pattern.action = TcpFilter::Reject; break;
895 case '?': pattern.action = TcpFilter::Query; break;
896 };
897
898 return pattern;
899}
900
901char* TcpFilter::patternToStr(const TcpFilter::Pattern& p) {
Tim Waughc24a64d2015-03-13 16:07:29 +0000902 rfb::CharArray addr;
903#ifdef HAVE_GETADDRINFO
904 char buffer[INET6_ADDRSTRLEN + 2];
905
906 if (p.address.u.sa.sa_family == AF_INET) {
907 getnameinfo(&p.address.u.sa, sizeof(p.address.u.sin),
908 buffer, sizeof (buffer), NULL, 0, NI_NUMERICHOST);
909 addr.buf = rfb::strDup(buffer);
910 } else if (p.address.u.sa.sa_family == AF_INET6) {
911 buffer[0] = '[';
912 getnameinfo(&p.address.u.sa, sizeof(p.address.u.sin6),
913 buffer + 1, sizeof (buffer) - 2, NULL, 0, NI_NUMERICHOST);
914 strcat(buffer, "]");
915 addr.buf = rfb::strDup(buffer);
916 } else if (p.address.u.sa.sa_family == AF_UNSPEC)
917 addr.buf = rfb::strDup("");
918#else
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000919 in_addr tmp;
Tim Waughc24a64d2015-03-13 16:07:29 +0000920 tmp.s_addr = p.address.u.sin.sin_addr.s_addr;
Adam Tkacd36b6262009-09-04 10:57:20 +0000921 addr.buf = rfb::strDup(inet_ntoa(tmp));
Tim Waughc24a64d2015-03-13 16:07:29 +0000922#endif /* HAVE_GETADDRINFO */
923
924 char action;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000925 switch (p.action) {
Tim Waughc24a64d2015-03-13 16:07:29 +0000926 case Accept: action = '+'; break;
927 case Reject: action = '-'; break;
928 default:
929 case Query: action = '?'; break;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000930 };
Tim Waughc24a64d2015-03-13 16:07:29 +0000931 size_t resultlen = (1 // action
932 + strlen (addr.buf) // address
933 + 1 // slash
934 + 3 // prefix length, max 128
935 + 1); // terminating nul
936 char* result = new char[resultlen];
937 if (addr.buf[0] == '\0')
938 snprintf(result, resultlen, "%c", action);
939 else
940 snprintf(result, resultlen, "%c%s/%u", action, addr.buf, p.prefixlen);
941
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000942 return result;
943}