blob: bd9971c138186732b4d4751c5517e51dfa5a8733 [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
123// -=- TcpSocket
124
125TcpSocket::TcpSocket(int sock, bool close)
126 : Socket(new FdInStream(sock), new FdOutStream(sock), true), closeFd(close)
127{
128}
129
130TcpSocket::TcpSocket(const char *host, int port)
131 : closeFd(true)
132{
Adam Tkac9cb6a422008-11-14 15:56:15 +0000133 int sock, err, result, family;
134 vnc_sockaddr_t sa;
Adam Tkacbe4c3ac2008-12-10 16:42:33 +0000135 socklen_t salen;
Adam Tkac9cb6a422008-11-14 15:56:15 +0000136#ifdef HAVE_GETADDRINFO
137 struct addrinfo *ai, *current, hints;
138#endif
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000139
140 // - Create a socket
141 initSockets();
Adam Tkac9cb6a422008-11-14 15:56:15 +0000142
143#ifdef HAVE_GETADDRINFO
144 memset(&hints, 0, sizeof(struct addrinfo));
145 hints.ai_family = AF_UNSPEC;
146 hints.ai_socktype = SOCK_STREAM;
147 hints.ai_canonname = NULL;
148 hints.ai_addr = NULL;
149 hints.ai_next = NULL;
150
151 if ((result = getaddrinfo(host, NULL, &hints, &ai)) != 0) {
152 throw Exception("unable to resolve host by name: %s",
Tim Waugha85363d2015-03-11 13:07:48 +0000153 gai_strerror(result));
Adam Tkac9cb6a422008-11-14 15:56:15 +0000154 }
155
Pierre Ossmanf1a35012015-03-03 16:02:42 +0100156 // This logic is too complex for the compiler to determine if
157 // sock is properly assigned or not.
158 sock = -1;
159
Adam Tkac9cb6a422008-11-14 15:56:15 +0000160 for (current = ai; current != NULL; current = current->ai_next) {
161 family = current->ai_family;
Pierre Ossman39b3b8f2015-01-29 17:35:45 +0100162
163 switch (family) {
164 case AF_INET:
165 if (!UseIPv4)
166 continue;
167 break;
168 case AF_INET6:
169 if (!UseIPv6)
170 continue;
171 break;
172 default:
Adam Tkac9cb6a422008-11-14 15:56:15 +0000173 continue;
Pierre Ossman39b3b8f2015-01-29 17:35:45 +0100174 }
Adam Tkac9cb6a422008-11-14 15:56:15 +0000175
176 salen = current->ai_addrlen;
177 memcpy(&sa, current->ai_addr, salen);
178
179 if (family == AF_INET)
180 sa.u.sin.sin_port = htons(port);
181 else
182 sa.u.sin6.sin6_port = htons(port);
183
184#else /* HAVE_GETADDRINFO */
Pierre Ossman39b3b8f2015-01-29 17:35:45 +0100185 if (!UseIPv4)
186 throw Exception("Only IPv4 available but it is disabled");
187
Adam Tkac9cb6a422008-11-14 15:56:15 +0000188 family = AF_INET;
189 salen = sizeof(struct sockaddr_in);
190
191 /* Try processing the host as an IP address */
192 memset(&sa, 0, sizeof(sa));
193 sa.u.sin.sin_family = AF_INET;
194 sa.u.sin.sin_addr.s_addr = inet_addr((char *)host);
195 sa.u.sin.sin_port = htons(port);
196 if ((int)sa.u.sin.sin_addr.s_addr == -1) {
197 /* Host was not an IP address - try resolving as DNS name */
198 struct hostent *hostinfo;
199 hostinfo = gethostbyname((char *)host);
200 if (hostinfo && hostinfo->h_addr) {
201 sa.u.sin.sin_addr.s_addr = ((struct in_addr *)hostinfo->h_addr)->s_addr;
202 } else {
203 err = errorNumber;
204 throw SocketException("unable to resolve host by name", err);
205 }
206 }
207#endif /* HAVE_GETADDRINFO */
208
209 sock = socket (family, SOCK_STREAM, 0);
210 if (sock == -1) {
211 err = errorNumber;
212#ifdef HAVE_GETADDRINFO
213 freeaddrinfo(ai);
214#endif /* HAVE_GETADDRINFO */
215 throw SocketException("unable to create socket", err);
216 }
217
218 /* Attempt to connect to the remote host */
Adam Tkacc9cda3b2009-10-30 11:13:34 +0000219 while ((result = connect(sock, &sa.u.sa, salen)) == -1) {
Adam Tkac9cb6a422008-11-14 15:56:15 +0000220 err = errorNumber;
221#ifndef WIN32
222 if (err == EINTR)
Tim Waugha85363d2015-03-11 13:07:48 +0000223 continue;
Adam Tkac9cb6a422008-11-14 15:56:15 +0000224#endif
225 closesocket(sock);
226 break;
227 }
228
229#ifdef HAVE_GETADDRINFO
230 if (result == 0)
231 break;
Adam Tkac9cb6a422008-11-14 15:56:15 +0000232 }
233
234 freeaddrinfo(ai);
Pierre Ossmanda9a38d2015-03-03 16:03:32 +0100235
236 if (current == NULL)
237 throw Exception("No useful address for host");
Adam Tkac9cb6a422008-11-14 15:56:15 +0000238#endif /* HAVE_GETADDRINFO */
239
240 if (result == -1)
241 throw SocketException("unable connect to socket", err);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000242
243#ifndef WIN32
244 // - By default, close the socket on exec()
245 fcntl(sock, F_SETFD, FD_CLOEXEC);
246#endif
247
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000248 // Disable Nagle's algorithm, to reduce latency
249 enableNagles(sock, false);
250
251 // Create the input and output streams
252 instream = new FdInStream(sock);
253 outstream = new FdOutStream(sock);
254 ownStreams = true;
255}
256
257TcpSocket::~TcpSocket() {
258 if (closeFd)
259 closesocket(getFd());
260}
261
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000262int TcpSocket::getMyPort() {
263 return getSockPort(getFd());
264}
265
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000266char* TcpSocket::getPeerAddress() {
Tim Waugh6ae42df2014-11-17 17:07:07 +0000267 vnc_sockaddr_t sa;
268 socklen_t sa_size = sizeof(sa);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000269
Tim Waugh6ae42df2014-11-17 17:07:07 +0000270 if (getpeername(getFd(), &sa.u.sa, &sa_size) != 0) {
271 vlog.error("unable to get peer name for socket");
272 return rfb::strDup("");
273 }
274
Tim Waugh892d10a2015-03-11 13:12:07 +0000275#if defined(HAVE_GETADDRINFO)
Pierre Ossman14263e12014-11-19 11:14:49 +0100276 if (sa.u.sa.sa_family == AF_INET6) {
Pierre Ossman07cd2292014-11-19 11:16:04 +0100277 char buffer[INET6_ADDRSTRLEN + 2];
Tim Waugh892d10a2015-03-11 13:12:07 +0000278 int ret;
Tim Waugh6ae42df2014-11-17 17:07:07 +0000279
Pierre Ossman07cd2292014-11-19 11:16:04 +0100280 buffer[0] = '[';
281
Tim Waugh892d10a2015-03-11 13:12:07 +0000282 ret = getnameinfo(&sa.u.sa, sizeof(sa.u.sin6),
283 buffer + 1, sizeof(buffer) - 2, NULL, 0,
284 NI_NUMERICHOST);
285 if (ret != 0) {
Pierre Ossman14263e12014-11-19 11:14:49 +0100286 vlog.error("unable to convert peer name to a string");
287 return rfb::strDup("");
288 }
Tim Waugh6ae42df2014-11-17 17:07:07 +0000289
Pierre Ossman07cd2292014-11-19 11:16:04 +0100290 strcat(buffer, "]");
291
292 return rfb::strDup(buffer);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000293 }
Pierre Ossman14263e12014-11-19 11:14:49 +0100294#endif
295
296 if (sa.u.sa.sa_family == AF_INET) {
297 char *name;
298
299 name = inet_ntoa(sa.u.sin.sin_addr);
300 if (name == NULL) {
301 vlog.error("unable to convert peer name to a string");
302 return rfb::strDup("");
303 }
304
305 return rfb::strDup(name);
306 }
307
308 vlog.error("unknown address family for socket");
309 return rfb::strDup("");
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000310}
311
312int TcpSocket::getPeerPort() {
Tim Waugh6ae42df2014-11-17 17:07:07 +0000313 vnc_sockaddr_t sa;
314 socklen_t sa_size = sizeof(sa);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000315
Tim Waugh6ae42df2014-11-17 17:07:07 +0000316 getpeername(getFd(), &sa.u.sa, &sa_size);
317
318 switch (sa.u.sa.sa_family) {
319#ifdef HAVE_GETADDRINFO
320 case AF_INET6:
321 return ntohs(sa.u.sin6.sin6_port);
322#endif /* HAVE_GETADDRINFO */
Pierre Ossman14263e12014-11-19 11:14:49 +0100323 case AF_INET:
Tim Waugh6ae42df2014-11-17 17:07:07 +0000324 return ntohs(sa.u.sin.sin_port);
Pierre Ossman14263e12014-11-19 11:14:49 +0100325 default:
326 return 0;
Tim Waugh6ae42df2014-11-17 17:07:07 +0000327 }
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000328}
329
330char* TcpSocket::getPeerEndpoint() {
331 rfb::CharArray address; address.buf = getPeerAddress();
332 int port = getPeerPort();
333
334 int buflen = strlen(address.buf) + 32;
335 char* buffer = new char[buflen];
336 sprintf(buffer, "%s::%d", address.buf, port);
337 return buffer;
338}
339
340bool TcpSocket::sameMachine() {
Adam Tkac897814f2009-11-12 10:32:43 +0000341 vnc_sockaddr_t peeraddr, myaddr;
342 socklen_t addrlen;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000343
Adam Tkac897814f2009-11-12 10:32:43 +0000344 addrlen = sizeof(peeraddr);
345 if (getpeername(getFd(), &peeraddr.u.sa, &addrlen) < 0)
346 throw SocketException ("unable to get peer address", errorNumber);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000347
Adam Tkac897814f2009-11-12 10:32:43 +0000348 addrlen = sizeof(myaddr); /* need to reset, since getpeername overwrote */
349 if (getsockname(getFd(), &myaddr.u.sa, &addrlen) < 0)
350 throw SocketException ("unable to get my address", errorNumber);
351
352 if (peeraddr.u.sa.sa_family != myaddr.u.sa.sa_family)
353 return false;
354
355#ifdef HAVE_GETADDRINFO
356 if (peeraddr.u.sa.sa_family == AF_INET6)
357 return IN6_ARE_ADDR_EQUAL(&peeraddr.u.sin6.sin6_addr,
Tim Waugha85363d2015-03-11 13:07:48 +0000358 &myaddr.u.sin6.sin6_addr);
Adam Tkac897814f2009-11-12 10:32:43 +0000359#endif
360
Pierre Ossman14263e12014-11-19 11:14:49 +0100361 if (peeraddr.u.sa.sa_family == AF_INET)
362 return (peeraddr.u.sin.sin_addr.s_addr == myaddr.u.sin.sin_addr.s_addr);
363
364 // No idea what this is. Assume we're on different machines.
365 return false;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000366}
367
368void TcpSocket::shutdown()
369{
370 Socket::shutdown();
371 ::shutdown(getFd(), 2);
372}
373
374bool TcpSocket::enableNagles(int sock, bool enable) {
375 int one = enable ? 0 : 1;
376 if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
Tim Waugha85363d2015-03-11 13:07:48 +0000377 (char *)&one, sizeof(one)) < 0) {
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000378 int e = errorNumber;
379 vlog.error("unable to setsockopt TCP_NODELAY: %d", e);
380 return false;
381 }
382 return true;
383}
384
Pierre Ossman64069a92011-11-08 12:10:55 +0000385bool TcpSocket::cork(int sock, bool enable) {
386#ifndef TCP_CORK
387 return false;
388#else
389 int one = enable ? 1 : 0;
390 if (setsockopt(sock, IPPROTO_TCP, TCP_CORK, (char *)&one, sizeof(one)) < 0)
391 return false;
392 return true;
393#endif
394}
395
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000396bool TcpSocket::isSocket(int sock)
397{
Tim Waugh6ae42df2014-11-17 17:07:07 +0000398 vnc_sockaddr_t sa;
399 socklen_t sa_size = sizeof(sa);
400 return getsockname(sock, &sa.u.sa, &sa_size) >= 0;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000401}
402
403bool TcpSocket::isConnected(int sock)
404{
Tim Waugh6ae42df2014-11-17 17:07:07 +0000405 vnc_sockaddr_t sa;
406 socklen_t sa_size = sizeof(sa);
407 return getpeername(sock, &sa.u.sa, &sa_size) >= 0;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000408}
409
410int TcpSocket::getSockPort(int sock)
411{
Tim Waugh6ae42df2014-11-17 17:07:07 +0000412 vnc_sockaddr_t sa;
413 socklen_t sa_size = sizeof(sa);
414 if (getsockname(sock, &sa.u.sa, &sa_size) < 0)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000415 return 0;
Tim Waugh6ae42df2014-11-17 17:07:07 +0000416
417 switch (sa.u.sa.sa_family) {
418#ifdef HAVE_GETADDRINFO
419 case AF_INET6:
420 return ntohs(sa.u.sin6.sin6_port);
421#endif /* HAVE_GETADDRINFO */
422
423 default:
424 return ntohs(sa.u.sin.sin_port);
425 }
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000426}
427
Tim Waugh892d10a2015-03-11 13:12:07 +0000428TcpListener::TcpListener(int sock)
Tim Waughe4d97262014-11-21 16:07:34 +0000429{
Tim Waugh892d10a2015-03-11 13:12:07 +0000430 fd = sock;
Tim Waughe4d97262014-11-21 16:07:34 +0000431}
432
Tim Waugh892d10a2015-03-11 13:12:07 +0000433TcpListener::TcpListener(const TcpListener& other)
Tim Waughe4d97262014-11-21 16:07:34 +0000434{
Tim Waugh892d10a2015-03-11 13:12:07 +0000435 fd = dup (other.fd);
436 // Hope TcpListener::shutdown(other) doesn't get called...
Tim Waughe4d97262014-11-21 16:07:34 +0000437}
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000438
Tim Waugh892d10a2015-03-11 13:12:07 +0000439TcpListener& TcpListener::operator= (const TcpListener& other)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000440{
Tim Waugh892d10a2015-03-11 13:12:07 +0000441 if (this != &other)
442 {
443 closesocket (fd);
444 fd = dup (other.fd);
445 // Hope TcpListener::shutdown(other) doesn't get called...
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000446 }
Tim Waugh892d10a2015-03-11 13:12:07 +0000447 return *this;
448}
449
450TcpListener::TcpListener(const struct sockaddr *listenaddr,
451 socklen_t listenaddrlen)
452{
453 int one = 1;
454 vnc_sockaddr_t sa;
455 int sock;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000456
457 initSockets();
Tim Waugh892d10a2015-03-11 13:12:07 +0000458
459 if ((sock = socket (listenaddr->sa_family, SOCK_STREAM, 0)) < 0)
460 throw SocketException("unable to create listening socket", errorNumber);
461
462 memcpy (&sa, listenaddr, listenaddrlen);
463#ifdef IPV6_V6ONLY
464 if (listenaddr->sa_family == AF_INET6) {
465 if (setsockopt (sock, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&one, sizeof(one)))
466 throw SocketException("unable to set IPV6_V6ONLY", errorNumber);
467 }
468#endif /* defined(IPV6_V6ONLY) */
469
470 if (bind(sock, &sa.u.sa, listenaddrlen) == -1) {
471 closesocket(sock);
472 throw SocketException("failed to bind socket", errorNumber);
473 }
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000474
475#ifndef WIN32
476 // - By default, close the socket on exec()
Tim Waugh892d10a2015-03-11 13:12:07 +0000477 fcntl(sock, F_SETFD, FD_CLOEXEC);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000478
Tim Waugh892d10a2015-03-11 13:12:07 +0000479 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
480 (char *)&one, sizeof(one)) < 0) {
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000481 int e = errorNumber;
Tim Waugh892d10a2015-03-11 13:12:07 +0000482 closesocket(sock);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000483 throw SocketException("unable to create listening socket", e);
484 }
485#endif
486
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000487 // - Set it to be a listening socket
Tim Waugh892d10a2015-03-11 13:12:07 +0000488 if (listen(sock, 5) < 0) {
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000489 int e = errorNumber;
Tim Waugh892d10a2015-03-11 13:12:07 +0000490 closesocket(sock);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000491 throw SocketException("unable to set socket to listening mode", e);
492 }
Tim Waugh892d10a2015-03-11 13:12:07 +0000493
494 fd = sock;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000495}
496
497TcpListener::~TcpListener() {
Tim Waugh892d10a2015-03-11 13:12:07 +0000498 closesocket(fd);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000499}
500
501void TcpListener::shutdown()
502{
503#ifdef WIN32
504 closesocket(getFd());
505#else
506 ::shutdown(getFd(), 2);
507#endif
508}
509
510
511Socket*
512TcpListener::accept() {
513 int new_sock = -1;
514
515 // Accept an incoming connection
516 if ((new_sock = ::accept(fd, 0, 0)) < 0)
517 throw SocketException("unable to accept new connection", errorNumber);
518
519#ifndef WIN32
520 // - By default, close the socket on exec()
521 fcntl(new_sock, F_SETFD, FD_CLOEXEC);
522#endif
523
524 // Disable Nagle's algorithm, to reduce latency
525 TcpSocket::enableNagles(new_sock, false);
526
527 // Create the socket object & check connection is allowed
528 TcpSocket* s = new TcpSocket(new_sock);
529 if (filter && !filter->verifyConnection(s)) {
530 delete s;
531 return 0;
532 }
533 return s;
534}
535
Pierre Ossman57cab512015-03-17 13:39:39 +0100536void TcpListener::getMyAddresses(std::list<char*>* result) {
537#if defined(HAVE_GETADDRINFO)
538 struct addrinfo *ai, *current, hints;
539
540 initSockets();
541
542 memset(&hints, 0, sizeof(struct addrinfo));
543 hints.ai_flags = AI_PASSIVE | AI_NUMERICSERV;
544 hints.ai_family = AF_UNSPEC;
545 hints.ai_socktype = SOCK_STREAM;
546 hints.ai_canonname = NULL;
547 hints.ai_addr = NULL;
548 hints.ai_next = NULL;
549
550 // Windows doesn't like NULL for service, so specify something
551 if ((getaddrinfo(NULL, "1", &hints, &ai)) != 0)
552 return;
553
554 for (current= ai; current != NULL; current = current->ai_next) {
555 switch (current->ai_family) {
556 case AF_INET:
557 if (!UseIPv4)
558 continue;
559 break;
560 case AF_INET6:
561 if (!UseIPv6)
562 continue;
563 break;
564 default:
565 continue;
566 }
567
568 char *addr = new char[INET6_ADDRSTRLEN];
569
570 getnameinfo(current->ai_addr, current->ai_addrlen, addr, INET6_ADDRSTRLEN,
571 NULL, 0, NI_NUMERICHOST);
572
573 result->push_back(addr);
574 }
575
576 freeaddrinfo(ai);
577#else
578 const hostent* addrs = gethostbyname(0);
579 if (!UseIPv4)
580 return;
581 if (addrs == 0)
582 throw rdr::SystemException("gethostbyname", errorNumber);
583 if (addrs->h_addrtype != AF_INET)
584 throw rdr::Exception("getMyAddresses: bad family");
585 for (int i=0; addrs->h_addr_list[i] != 0; i++) {
586 const char* addrC = inet_ntoa(*((struct in_addr*)addrs->h_addr_list[i]));
587 char* addr = new char[strlen(addrC)+1];
588 strcpy(addr, addrC);
589 result->push_back(addr);
590 }
591#endif /* defined(HAVE_GETADDRINFO) */
592}
593
Tim Waugh892d10a2015-03-11 13:12:07 +0000594int TcpListener::getMyPort() {
595 return TcpSocket::getSockPort(getFd());
596}
597
598
599void network::createLocalTcpListeners(std::list<TcpListener> *listeners,
600 int port)
601{
602 std::list<TcpListener> new_listeners;
603 vnc_sockaddr_t sa;
Pierre Ossman9d784402015-03-17 17:10:10 +0100604
605 initSockets();
606
Tim Waugh892d10a2015-03-11 13:12:07 +0000607#ifdef HAVE_GETADDRINFO
608 if (UseIPv6) {
609 sa.u.sin6.sin6_family = AF_INET6;
610 sa.u.sin6.sin6_port = htons (port);
611 sa.u.sin6.sin6_addr = in6addr_loopback;
612 try {
613 new_listeners.push_back (TcpListener (&sa.u.sa, sizeof (sa.u.sin6)));
614 } catch (SocketException& e) {
615 // Ignore this if it is due to lack of address family support on
616 // the interface or on the system
617 if (e.err != EADDRNOTAVAIL && e.err != EAFNOSUPPORT)
618 // Otherwise, report the error
619 throw;
620 }
621 }
622#endif /* HAVE_GETADDRINFO */
623 if (UseIPv4) {
624 sa.u.sin.sin_family = AF_INET;
625 sa.u.sin.sin_port = htons (port);
626 sa.u.sin.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
627 try {
628 new_listeners.push_back (TcpListener (&sa.u.sa, sizeof (sa.u.sin)));
629 } catch (SocketException& e) {
630 // Ignore this if it is due to lack of address family support on
631 // the interface or on the system
632 if (e.err != EADDRNOTAVAIL && e.err != EAFNOSUPPORT)
633 // Otherwise, report the error
634 throw;
635 }
636 }
637
638 if (new_listeners.empty ())
639 throw SocketException("createLocalTcpListeners: no addresses available",
640 EADDRNOTAVAIL);
641
642 listeners->splice (listeners->end(), new_listeners);
643}
644
645void network::createTcpListeners(std::list<TcpListener> *listeners,
646 const char *addr,
647 int port)
648{
649 std::list<TcpListener> new_listeners;
650
651#ifdef HAVE_GETADDRINFO
Tim Waugh6ae42df2014-11-17 17:07:07 +0000652 struct addrinfo *ai, *current, hints;
Tim Waugh892d10a2015-03-11 13:12:07 +0000653 char service[16];
Tim Waugh6ae42df2014-11-17 17:07:07 +0000654
Pierre Ossman9d784402015-03-17 17:10:10 +0100655 initSockets();
656
Tim Waugh6ae42df2014-11-17 17:07:07 +0000657 memset(&hints, 0, sizeof(struct addrinfo));
Tim Waugh892d10a2015-03-11 13:12:07 +0000658 hints.ai_flags = AI_PASSIVE | AI_NUMERICSERV;
Tim Waugh6ae42df2014-11-17 17:07:07 +0000659 hints.ai_family = AF_UNSPEC;
660 hints.ai_socktype = SOCK_STREAM;
661 hints.ai_canonname = NULL;
662 hints.ai_addr = NULL;
663 hints.ai_next = NULL;
664
Tim Waugh892d10a2015-03-11 13:12:07 +0000665 snprintf (service, sizeof (service) - 1, "%d", port);
666 service[sizeof (service) - 1] = '\0';
667 if ((getaddrinfo(addr, service, &hints, &ai)) != 0)
668 throw rdr::SystemException("getaddrinfo", errorNumber);
Tim Waugh6ae42df2014-11-17 17:07:07 +0000669
Tim Waugh892d10a2015-03-11 13:12:07 +0000670 for (current = ai; current != NULL; current = current->ai_next) {
671 switch (current->ai_family) {
672 case AF_INET:
673 if (!UseIPv4)
674 continue;
675 break;
676
677 case AF_INET6:
678 if (!UseIPv6)
679 continue;
680 break;
681
682 default:
Tim Waugh6ae42df2014-11-17 17:07:07 +0000683 continue;
Tim Waugh892d10a2015-03-11 13:12:07 +0000684 }
Tim Waugh6ae42df2014-11-17 17:07:07 +0000685
Tim Waugh892d10a2015-03-11 13:12:07 +0000686 try {
687 new_listeners.push_back(TcpListener (current->ai_addr,
688 current->ai_addrlen));
689 } catch (SocketException& e) {
690 // Ignore this if it is due to lack of address family support on
691 // the interface or on the system
692 if (e.err != EADDRNOTAVAIL && e.err != EAFNOSUPPORT) {
693 // Otherwise, report the error
694 freeaddrinfo(ai);
695 throw;
696 }
697 }
Tim Waugh6ae42df2014-11-17 17:07:07 +0000698 }
699 freeaddrinfo(ai);
700#else
Tim Waugh892d10a2015-03-11 13:12:07 +0000701 const hostent* addrs;
702 if (addr) {
703 /* Bind to specific address */
704 addrs = gethostbyname(addr);
705 if (addrs == 0)
706 throw rdr::SystemException("gethostbyname", errorNumber);
707 if (addrs->h_addrtype != AF_INET)
708 throw rdr::Exception("createTcpListeners: bad family");
709 for (int i=0; addrs->h_addr_list[i] != 0; i++) {
710 struct sockaddr_in addr;
711 addr.sin_family = AF_INET;
712 memcpy (&addr.sin_addr, addrs->h_addr_list[i], addrs->h_length);
713 addr.sin_port = htons(port);
714 try {
715 new_listeners.push_back(TcpListener ((struct sockaddr*)&addr,
716 addrs->h_length));
717 } catch (SocketException& e) {
718 // Ignore this if it is due to lack of address family support
719 // on the interface or on the system
720 if (e.err != EADDRNOTAVAIL && e.err != EAFNOSUPPORT) {
721 // Otherwise, report the error
722 freeaddrinfo(ai);
723 throw;
724 }
725 }
726 }
727 } else {
728 /* Bind to any address */
729 struct sockaddr_in addr;
730 addr.sin_family = AF_INET;
731 addr.sin_addr.s_addr = htonl(INADDR_ANY);
732 addr.sin_port = htons(port);
733 try {
734 new_listeners.push_back(TcpListener ((struct sockaddr*)&addr,
735 sizeof (struct sockaddr_in)));
736 } catch (SocketException& e) {
737 // Ignore this if it is due to lack of address family support on
738 // 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 }
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000745 }
Tim Waugh892d10a2015-03-11 13:12:07 +0000746#endif /* defined(HAVE_GETADDRINFO) */
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000747
Tim Waugh892d10a2015-03-11 13:12:07 +0000748 if (new_listeners.empty ())
749 throw SocketException("createTcpListeners: no addresses available",
750 EADDRNOTAVAIL);
751
752 listeners->splice (listeners->end(), new_listeners);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000753}
754
755
756TcpFilter::TcpFilter(const char* spec) {
757 rfb::CharArray tmp;
Adam Tkacd36b6262009-09-04 10:57:20 +0000758 tmp.buf = rfb::strDup(spec);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000759 while (tmp.buf) {
760 rfb::CharArray first;
761 rfb::strSplit(tmp.buf, ',', &first.buf, &tmp.buf);
762 if (strlen(first.buf))
763 filter.push_back(parsePattern(first.buf));
764 }
765}
766
767TcpFilter::~TcpFilter() {
768}
769
770
771static bool
Tim Waughc24a64d2015-03-13 16:07:29 +0000772patternMatchIP(const TcpFilter::Pattern& pattern, vnc_sockaddr_t *sa) {
773 switch (pattern.address.u.sa.sa_family) {
774 unsigned long address;
775
776 case AF_INET:
777 if (sa->u.sa.sa_family != AF_INET)
778 return false;
779
780 address = sa->u.sin.sin_addr.s_addr;
781 if (address == htonl (INADDR_NONE)) return false;
782 return ((pattern.address.u.sin.sin_addr.s_addr &
783 pattern.mask.u.sin.sin_addr.s_addr) ==
784 (address & pattern.mask.u.sin.sin_addr.s_addr));
785
786 case AF_INET6:
787 if (sa->u.sa.sa_family != AF_INET6)
788 return false;
789
790 for (unsigned int n = 0; n < 16; n++) {
791 unsigned int bits = (n + 1) * 8;
792 unsigned int mask;
793 if (pattern.prefixlen > bits)
794 mask = 0xff;
795 else {
796 unsigned int lastbits = 0xff;
797 lastbits <<= bits - pattern.prefixlen;
798 mask = lastbits & 0xff;
799 }
800
801 if ((pattern.address.u.sin6.sin6_addr.s6_addr[n] & mask) !=
802 (sa->u.sin6.sin6_addr.s6_addr[n] & mask))
803 return false;
804
805 if (mask < 0xff)
806 break;
807 }
808
809 return true;
810
811 case AF_UNSPEC:
812 // Any address matches
813 return true;
814
815 default:
816 break;
817 }
818
819 return false;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000820}
821
822bool
823TcpFilter::verifyConnection(Socket* s) {
824 rfb::CharArray name;
Tim Waugh6ae42df2014-11-17 17:07:07 +0000825 vnc_sockaddr_t sa;
826 socklen_t sa_size = sizeof(sa);
Tim Waughc24a64d2015-03-13 16:07:29 +0000827
828 if (getpeername(s->getFd(), &sa.u.sa, &sa_size) != 0)
Tim Waugh6ae42df2014-11-17 17:07:07 +0000829 return false;
Tim Waugh6ae42df2014-11-17 17:07:07 +0000830
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000831 name.buf = s->getPeerAddress();
832 std::list<TcpFilter::Pattern>::iterator i;
833 for (i=filter.begin(); i!=filter.end(); i++) {
Tim Waughc24a64d2015-03-13 16:07:29 +0000834 if (patternMatchIP(*i, &sa)) {
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000835 switch ((*i).action) {
836 case Accept:
837 vlog.debug("ACCEPT %s", name.buf);
838 return true;
839 case Query:
840 vlog.debug("QUERY %s", name.buf);
841 s->setRequiresQuery();
842 return true;
843 case Reject:
844 vlog.debug("REJECT %s", name.buf);
845 return false;
846 }
847 }
848 }
849
850 vlog.debug("[REJECT] %s", name.buf);
851 return false;
852}
853
854
855TcpFilter::Pattern TcpFilter::parsePattern(const char* p) {
856 TcpFilter::Pattern pattern;
857
Tim Waughc24a64d2015-03-13 16:07:29 +0000858 rfb::CharArray addr, pref;
859 bool prefix_specified;
860 int family;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000861
Tim Waughc24a64d2015-03-13 16:07:29 +0000862 prefix_specified = rfb::strSplit(&p[1], '/', &addr.buf, &pref.buf);
863 if (addr.buf[0] == '\0') {
864 // Match any address
865 memset (&pattern.address, 0, sizeof (pattern.address));
866 pattern.address.u.sa.sa_family = AF_UNSPEC;
867 pattern.prefixlen = 0;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000868 } else {
Tim Waughc24a64d2015-03-13 16:07:29 +0000869#ifdef HAVE_GETADDRINFO
870 struct addrinfo hints;
871 struct addrinfo *ai;
872 char *p = addr.buf;
873 int result;
874 memset (&hints, 0, sizeof (hints));
875 hints.ai_family = AF_UNSPEC;
876 hints.ai_flags = AI_NUMERICHOST;
877
878 // Take out brackets, if present
879 if (*p == '[') {
880 size_t len;
881 p++;
882 len = strlen (p);
883 if (len > 0 && p[len - 1] == ']')
884 p[len - 1] = '\0';
885 }
886
887 if ((result = getaddrinfo (p, NULL, &hints, &ai)) != 0) {
888 throw Exception("unable to resolve host by name: %s",
889 gai_strerror(result));
890 }
891
892 memcpy (&pattern.address.u.sa, ai->ai_addr, ai->ai_addrlen);
893 freeaddrinfo (ai);
894#else
895 pattern.address.u.sa.sa_family = AF_INET;
896 pattern.address.u.sin.sin_addr.s_addr = inet_addr(addr.buf);
897#endif /* HAVE_GETADDRINFO */
898
899 family = pattern.address.u.sa.sa_family;
900
901 if (prefix_specified) {
902 if (family == AF_INET &&
903 rfb::strContains(pref.buf, '.')) {
904 throw Exception("mask no longer supported for filter, "
905 "use prefix instead");
906 }
907
908 pattern.prefixlen = (unsigned int) atoi(pref.buf);
909 } else {
910 switch (family) {
911 case AF_INET:
912 pattern.prefixlen = 32;
913 break;
914 case AF_INET6:
915 pattern.prefixlen = 128;
916 break;
917 default:
918 throw Exception("unknown address family");
919 }
920 }
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000921 }
922
Pierre Ossmanfdc55e52015-03-17 12:56:31 +0100923 family = pattern.address.u.sa.sa_family;
924
Tim Waughc24a64d2015-03-13 16:07:29 +0000925 if (pattern.prefixlen > (family == AF_INET ? 32: 128))
926 throw Exception("invalid prefix length for filter address: %u",
927 pattern.prefixlen);
928
929 // Compute mask from address and prefix length
930 memset (&pattern.mask, 0, sizeof (pattern.mask));
931 switch (family) {
932 unsigned long mask;
933 case AF_INET:
934 mask = 0;
935 for (unsigned int i=0; i<pattern.prefixlen; i++)
936 mask |= 1<<(31-i);
937 pattern.mask.u.sin.sin_addr.s_addr = htonl(mask);
938 break;
939
940 case AF_INET6:
941 for (unsigned int n = 0; n < 16; n++) {
942 unsigned int bits = (n + 1) * 8;
943 if (pattern.prefixlen > bits)
944 pattern.mask.u.sin6.sin6_addr.s6_addr[n] = 0xff;
945 else {
946 unsigned int lastbits = 0xff;
947 lastbits <<= bits - pattern.prefixlen;
948 pattern.mask.u.sin6.sin6_addr.s6_addr[n] = lastbits & 0xff;
949 break;
950 }
951 }
952 break;
953 case AF_UNSPEC:
954 // No mask to compute
955 break;
956 default:
957 ; /* not reached */
958 }
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000959
960 switch(p[0]) {
961 case '+': pattern.action = TcpFilter::Accept; break;
962 case '-': pattern.action = TcpFilter::Reject; break;
963 case '?': pattern.action = TcpFilter::Query; break;
964 };
965
966 return pattern;
967}
968
969char* TcpFilter::patternToStr(const TcpFilter::Pattern& p) {
Tim Waughc24a64d2015-03-13 16:07:29 +0000970 rfb::CharArray addr;
971#ifdef HAVE_GETADDRINFO
972 char buffer[INET6_ADDRSTRLEN + 2];
973
974 if (p.address.u.sa.sa_family == AF_INET) {
975 getnameinfo(&p.address.u.sa, sizeof(p.address.u.sin),
976 buffer, sizeof (buffer), NULL, 0, NI_NUMERICHOST);
977 addr.buf = rfb::strDup(buffer);
978 } else if (p.address.u.sa.sa_family == AF_INET6) {
979 buffer[0] = '[';
980 getnameinfo(&p.address.u.sa, sizeof(p.address.u.sin6),
981 buffer + 1, sizeof (buffer) - 2, NULL, 0, NI_NUMERICHOST);
982 strcat(buffer, "]");
983 addr.buf = rfb::strDup(buffer);
984 } else if (p.address.u.sa.sa_family == AF_UNSPEC)
985 addr.buf = rfb::strDup("");
986#else
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000987 in_addr tmp;
Tim Waughc24a64d2015-03-13 16:07:29 +0000988 tmp.s_addr = p.address.u.sin.sin_addr.s_addr;
Adam Tkacd36b6262009-09-04 10:57:20 +0000989 addr.buf = rfb::strDup(inet_ntoa(tmp));
Tim Waughc24a64d2015-03-13 16:07:29 +0000990#endif /* HAVE_GETADDRINFO */
991
992 char action;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000993 switch (p.action) {
Tim Waughc24a64d2015-03-13 16:07:29 +0000994 case Accept: action = '+'; break;
995 case Reject: action = '-'; break;
996 default:
997 case Query: action = '?'; break;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000998 };
Tim Waughc24a64d2015-03-13 16:07:29 +0000999 size_t resultlen = (1 // action
1000 + strlen (addr.buf) // address
1001 + 1 // slash
1002 + 3 // prefix length, max 128
1003 + 1); // terminating nul
1004 char* result = new char[resultlen];
1005 if (addr.buf[0] == '\0')
1006 snprintf(result, resultlen, "%c", action);
1007 else
1008 snprintf(result, resultlen, "%c%s/%u", action, addr.buf, p.prefixlen);
1009
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +00001010 return result;
1011}