blob: 6fca3018a72c28776c6c85181b15ebf220b41ca4 [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
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000049#ifndef INADDR_NONE
50#define INADDR_NONE ((unsigned long)-1)
51#endif
52#ifndef INADDR_LOOPBACK
53#define INADDR_LOOPBACK ((unsigned long)0x7F000001)
54#endif
55
Pierre Ossman8b6aa202012-12-13 13:55:22 +000056#if defined(HAVE_GETADDRINFO) && !defined(IN6_ARE_ADDR_EQUAL)
57#define IN6_ARE_ADDR_EQUAL(a,b) \
58 (memcmp ((const void*)(a), (const void*)(b), sizeof (struct in6_addr)) == 0)
59#endif
60
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000061using namespace network;
62using namespace rdr;
63
64static rfb::LogWriter vlog("TcpSocket");
65
Pierre Ossman39b3b8f2015-01-29 17:35:45 +010066static rfb::BoolParameter UseIPv4("UseIPv4", "Use IPv4 for incoming and outgoing connections.", true);
67#ifdef HAVE_GETADDRINFO
68static rfb::BoolParameter UseIPv6("UseIPv6", "Use IPv6 for incoming and outgoing connections.", true);
69#endif
70
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000071/* Tunnelling support. */
72int network::findFreeTcpPort (void)
73{
DRCb2618e52011-02-21 13:43:44 +000074 int sock;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000075 struct sockaddr_in addr;
76 memset(&addr, 0, sizeof(addr));
77 addr.sin_family = AF_INET;
78 addr.sin_addr.s_addr = INADDR_ANY;
79
80 if ((sock = socket (AF_INET, SOCK_STREAM, 0)) < 0)
81 throw SocketException ("unable to create socket", errorNumber);
82
DRCb2618e52011-02-21 13:43:44 +000083 addr.sin_port = 0;
84 if (bind (sock, (struct sockaddr *)&addr, sizeof (addr)) < 0)
85 throw SocketException ("unable to find free port", errorNumber);
86
87 socklen_t n = sizeof(addr);
88 if (getsockname (sock, (struct sockaddr *)&addr, &n) < 0)
89 throw SocketException ("unable to get port number", errorNumber);
90
91 closesocket (sock);
92 return ntohs(addr.sin_port);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000093}
94
95
96// -=- Socket initialisation
97static bool socketsInitialised = false;
98static void initSockets() {
99 if (socketsInitialised)
100 return;
101#ifdef WIN32
102 WORD requiredVersion = MAKEWORD(2,0);
103 WSADATA initResult;
104
105 if (WSAStartup(requiredVersion, &initResult) != 0)
106 throw SocketException("unable to initialise Winsock2", errorNumber);
107#else
108 signal(SIGPIPE, SIG_IGN);
109#endif
110 socketsInitialised = true;
111}
112
113
114// -=- TcpSocket
115
116TcpSocket::TcpSocket(int sock, bool close)
117 : Socket(new FdInStream(sock), new FdOutStream(sock), true), closeFd(close)
118{
119}
120
121TcpSocket::TcpSocket(const char *host, int port)
122 : closeFd(true)
123{
Adam Tkac9cb6a422008-11-14 15:56:15 +0000124 int sock, err, result, family;
125 vnc_sockaddr_t sa;
Adam Tkacbe4c3ac2008-12-10 16:42:33 +0000126 socklen_t salen;
Adam Tkac9cb6a422008-11-14 15:56:15 +0000127#ifdef HAVE_GETADDRINFO
128 struct addrinfo *ai, *current, hints;
129#endif
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000130
131 // - Create a socket
132 initSockets();
Adam Tkac9cb6a422008-11-14 15:56:15 +0000133
134#ifdef HAVE_GETADDRINFO
135 memset(&hints, 0, sizeof(struct addrinfo));
136 hints.ai_family = AF_UNSPEC;
137 hints.ai_socktype = SOCK_STREAM;
138 hints.ai_canonname = NULL;
139 hints.ai_addr = NULL;
140 hints.ai_next = NULL;
141
142 if ((result = getaddrinfo(host, NULL, &hints, &ai)) != 0) {
143 throw Exception("unable to resolve host by name: %s",
Tim Waugha85363d2015-03-11 13:07:48 +0000144 gai_strerror(result));
Adam Tkac9cb6a422008-11-14 15:56:15 +0000145 }
146
Pierre Ossmanf1a35012015-03-03 16:02:42 +0100147 // This logic is too complex for the compiler to determine if
148 // sock is properly assigned or not.
149 sock = -1;
150
Adam Tkac9cb6a422008-11-14 15:56:15 +0000151 for (current = ai; current != NULL; current = current->ai_next) {
152 family = current->ai_family;
Pierre Ossman39b3b8f2015-01-29 17:35:45 +0100153
154 switch (family) {
155 case AF_INET:
156 if (!UseIPv4)
157 continue;
158 break;
159 case AF_INET6:
160 if (!UseIPv6)
161 continue;
162 break;
163 default:
Adam Tkac9cb6a422008-11-14 15:56:15 +0000164 continue;
Pierre Ossman39b3b8f2015-01-29 17:35:45 +0100165 }
Adam Tkac9cb6a422008-11-14 15:56:15 +0000166
167 salen = current->ai_addrlen;
168 memcpy(&sa, current->ai_addr, salen);
169
170 if (family == AF_INET)
171 sa.u.sin.sin_port = htons(port);
172 else
173 sa.u.sin6.sin6_port = htons(port);
174
175#else /* HAVE_GETADDRINFO */
Pierre Ossman39b3b8f2015-01-29 17:35:45 +0100176 if (!UseIPv4)
177 throw Exception("Only IPv4 available but it is disabled");
178
Adam Tkac9cb6a422008-11-14 15:56:15 +0000179 family = AF_INET;
180 salen = sizeof(struct sockaddr_in);
181
182 /* Try processing the host as an IP address */
183 memset(&sa, 0, sizeof(sa));
184 sa.u.sin.sin_family = AF_INET;
185 sa.u.sin.sin_addr.s_addr = inet_addr((char *)host);
186 sa.u.sin.sin_port = htons(port);
187 if ((int)sa.u.sin.sin_addr.s_addr == -1) {
188 /* Host was not an IP address - try resolving as DNS name */
189 struct hostent *hostinfo;
190 hostinfo = gethostbyname((char *)host);
191 if (hostinfo && hostinfo->h_addr) {
192 sa.u.sin.sin_addr.s_addr = ((struct in_addr *)hostinfo->h_addr)->s_addr;
193 } else {
194 err = errorNumber;
195 throw SocketException("unable to resolve host by name", err);
196 }
197 }
198#endif /* HAVE_GETADDRINFO */
199
200 sock = socket (family, SOCK_STREAM, 0);
201 if (sock == -1) {
202 err = errorNumber;
203#ifdef HAVE_GETADDRINFO
204 freeaddrinfo(ai);
205#endif /* HAVE_GETADDRINFO */
206 throw SocketException("unable to create socket", err);
207 }
208
209 /* Attempt to connect to the remote host */
Adam Tkacc9cda3b2009-10-30 11:13:34 +0000210 while ((result = connect(sock, &sa.u.sa, salen)) == -1) {
Adam Tkac9cb6a422008-11-14 15:56:15 +0000211 err = errorNumber;
212#ifndef WIN32
213 if (err == EINTR)
Tim Waugha85363d2015-03-11 13:07:48 +0000214 continue;
Adam Tkac9cb6a422008-11-14 15:56:15 +0000215#endif
216 closesocket(sock);
217 break;
218 }
219
220#ifdef HAVE_GETADDRINFO
221 if (result == 0)
222 break;
Adam Tkac9cb6a422008-11-14 15:56:15 +0000223 }
224
225 freeaddrinfo(ai);
Pierre Ossmanda9a38d2015-03-03 16:03:32 +0100226
227 if (current == NULL)
228 throw Exception("No useful address for host");
Adam Tkac9cb6a422008-11-14 15:56:15 +0000229#endif /* HAVE_GETADDRINFO */
230
231 if (result == -1)
232 throw SocketException("unable connect to socket", err);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000233
234#ifndef WIN32
235 // - By default, close the socket on exec()
236 fcntl(sock, F_SETFD, FD_CLOEXEC);
237#endif
238
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000239 // Disable Nagle's algorithm, to reduce latency
240 enableNagles(sock, false);
241
242 // Create the input and output streams
243 instream = new FdInStream(sock);
244 outstream = new FdOutStream(sock);
245 ownStreams = true;
246}
247
248TcpSocket::~TcpSocket() {
249 if (closeFd)
250 closesocket(getFd());
251}
252
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000253int TcpSocket::getMyPort() {
254 return getSockPort(getFd());
255}
256
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000257char* TcpSocket::getPeerAddress() {
Tim Waugh6ae42df2014-11-17 17:07:07 +0000258 vnc_sockaddr_t sa;
259 socklen_t sa_size = sizeof(sa);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000260
Tim Waugh6ae42df2014-11-17 17:07:07 +0000261 if (getpeername(getFd(), &sa.u.sa, &sa_size) != 0) {
262 vlog.error("unable to get peer name for socket");
263 return rfb::strDup("");
264 }
265
Tim Waugh892d10a2015-03-11 13:12:07 +0000266#if defined(HAVE_GETADDRINFO)
Pierre Ossman14263e12014-11-19 11:14:49 +0100267 if (sa.u.sa.sa_family == AF_INET6) {
Pierre Ossman07cd2292014-11-19 11:16:04 +0100268 char buffer[INET6_ADDRSTRLEN + 2];
Tim Waugh892d10a2015-03-11 13:12:07 +0000269 int ret;
Tim Waugh6ae42df2014-11-17 17:07:07 +0000270
Pierre Ossman07cd2292014-11-19 11:16:04 +0100271 buffer[0] = '[';
272
Tim Waugh892d10a2015-03-11 13:12:07 +0000273 ret = getnameinfo(&sa.u.sa, sizeof(sa.u.sin6),
274 buffer + 1, sizeof(buffer) - 2, NULL, 0,
275 NI_NUMERICHOST);
276 if (ret != 0) {
Pierre Ossman14263e12014-11-19 11:14:49 +0100277 vlog.error("unable to convert peer name to a string");
278 return rfb::strDup("");
279 }
Tim Waugh6ae42df2014-11-17 17:07:07 +0000280
Pierre Ossman07cd2292014-11-19 11:16:04 +0100281 strcat(buffer, "]");
282
283 return rfb::strDup(buffer);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000284 }
Pierre Ossman14263e12014-11-19 11:14:49 +0100285#endif
286
287 if (sa.u.sa.sa_family == AF_INET) {
288 char *name;
289
290 name = inet_ntoa(sa.u.sin.sin_addr);
291 if (name == NULL) {
292 vlog.error("unable to convert peer name to a string");
293 return rfb::strDup("");
294 }
295
296 return rfb::strDup(name);
297 }
298
299 vlog.error("unknown address family for socket");
300 return rfb::strDup("");
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000301}
302
303int TcpSocket::getPeerPort() {
Tim Waugh6ae42df2014-11-17 17:07:07 +0000304 vnc_sockaddr_t sa;
305 socklen_t sa_size = sizeof(sa);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000306
Tim Waugh6ae42df2014-11-17 17:07:07 +0000307 getpeername(getFd(), &sa.u.sa, &sa_size);
308
309 switch (sa.u.sa.sa_family) {
310#ifdef HAVE_GETADDRINFO
311 case AF_INET6:
312 return ntohs(sa.u.sin6.sin6_port);
313#endif /* HAVE_GETADDRINFO */
Pierre Ossman14263e12014-11-19 11:14:49 +0100314 case AF_INET:
Tim Waugh6ae42df2014-11-17 17:07:07 +0000315 return ntohs(sa.u.sin.sin_port);
Pierre Ossman14263e12014-11-19 11:14:49 +0100316 default:
317 return 0;
Tim Waugh6ae42df2014-11-17 17:07:07 +0000318 }
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000319}
320
321char* TcpSocket::getPeerEndpoint() {
322 rfb::CharArray address; address.buf = getPeerAddress();
323 int port = getPeerPort();
324
325 int buflen = strlen(address.buf) + 32;
326 char* buffer = new char[buflen];
327 sprintf(buffer, "%s::%d", address.buf, port);
328 return buffer;
329}
330
331bool TcpSocket::sameMachine() {
Adam Tkac897814f2009-11-12 10:32:43 +0000332 vnc_sockaddr_t peeraddr, myaddr;
333 socklen_t addrlen;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000334
Adam Tkac897814f2009-11-12 10:32:43 +0000335 addrlen = sizeof(peeraddr);
336 if (getpeername(getFd(), &peeraddr.u.sa, &addrlen) < 0)
337 throw SocketException ("unable to get peer address", errorNumber);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000338
Adam Tkac897814f2009-11-12 10:32:43 +0000339 addrlen = sizeof(myaddr); /* need to reset, since getpeername overwrote */
340 if (getsockname(getFd(), &myaddr.u.sa, &addrlen) < 0)
341 throw SocketException ("unable to get my address", errorNumber);
342
343 if (peeraddr.u.sa.sa_family != myaddr.u.sa.sa_family)
344 return false;
345
346#ifdef HAVE_GETADDRINFO
347 if (peeraddr.u.sa.sa_family == AF_INET6)
348 return IN6_ARE_ADDR_EQUAL(&peeraddr.u.sin6.sin6_addr,
Tim Waugha85363d2015-03-11 13:07:48 +0000349 &myaddr.u.sin6.sin6_addr);
Adam Tkac897814f2009-11-12 10:32:43 +0000350#endif
351
Pierre Ossman14263e12014-11-19 11:14:49 +0100352 if (peeraddr.u.sa.sa_family == AF_INET)
353 return (peeraddr.u.sin.sin_addr.s_addr == myaddr.u.sin.sin_addr.s_addr);
354
355 // No idea what this is. Assume we're on different machines.
356 return false;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000357}
358
359void TcpSocket::shutdown()
360{
361 Socket::shutdown();
362 ::shutdown(getFd(), 2);
363}
364
365bool TcpSocket::enableNagles(int sock, bool enable) {
366 int one = enable ? 0 : 1;
367 if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
Tim Waugha85363d2015-03-11 13:07:48 +0000368 (char *)&one, sizeof(one)) < 0) {
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000369 int e = errorNumber;
370 vlog.error("unable to setsockopt TCP_NODELAY: %d", e);
371 return false;
372 }
373 return true;
374}
375
Pierre Ossman64069a92011-11-08 12:10:55 +0000376bool TcpSocket::cork(int sock, bool enable) {
377#ifndef TCP_CORK
378 return false;
379#else
380 int one = enable ? 1 : 0;
381 if (setsockopt(sock, IPPROTO_TCP, TCP_CORK, (char *)&one, sizeof(one)) < 0)
382 return false;
383 return true;
384#endif
385}
386
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000387bool TcpSocket::isSocket(int sock)
388{
Tim Waugh6ae42df2014-11-17 17:07:07 +0000389 vnc_sockaddr_t sa;
390 socklen_t sa_size = sizeof(sa);
391 return getsockname(sock, &sa.u.sa, &sa_size) >= 0;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000392}
393
394bool TcpSocket::isConnected(int sock)
395{
Tim Waugh6ae42df2014-11-17 17:07:07 +0000396 vnc_sockaddr_t sa;
397 socklen_t sa_size = sizeof(sa);
398 return getpeername(sock, &sa.u.sa, &sa_size) >= 0;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000399}
400
401int TcpSocket::getSockPort(int sock)
402{
Tim Waugh6ae42df2014-11-17 17:07:07 +0000403 vnc_sockaddr_t sa;
404 socklen_t sa_size = sizeof(sa);
405 if (getsockname(sock, &sa.u.sa, &sa_size) < 0)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000406 return 0;
Tim Waugh6ae42df2014-11-17 17:07:07 +0000407
408 switch (sa.u.sa.sa_family) {
409#ifdef HAVE_GETADDRINFO
410 case AF_INET6:
411 return ntohs(sa.u.sin6.sin6_port);
412#endif /* HAVE_GETADDRINFO */
413
414 default:
415 return ntohs(sa.u.sin.sin_port);
416 }
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000417}
418
Tim Waugh892d10a2015-03-11 13:12:07 +0000419TcpListener::TcpListener(int sock)
Tim Waughe4d97262014-11-21 16:07:34 +0000420{
Tim Waugh892d10a2015-03-11 13:12:07 +0000421 fd = sock;
Tim Waughe4d97262014-11-21 16:07:34 +0000422}
423
Tim Waugh892d10a2015-03-11 13:12:07 +0000424TcpListener::TcpListener(const TcpListener& other)
Tim Waughe4d97262014-11-21 16:07:34 +0000425{
Tim Waugh892d10a2015-03-11 13:12:07 +0000426 fd = dup (other.fd);
427 // Hope TcpListener::shutdown(other) doesn't get called...
Tim Waughe4d97262014-11-21 16:07:34 +0000428}
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000429
Tim Waugh892d10a2015-03-11 13:12:07 +0000430TcpListener& TcpListener::operator= (const TcpListener& other)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000431{
Tim Waugh892d10a2015-03-11 13:12:07 +0000432 if (this != &other)
433 {
434 closesocket (fd);
435 fd = dup (other.fd);
436 // Hope TcpListener::shutdown(other) doesn't get called...
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000437 }
Tim Waugh892d10a2015-03-11 13:12:07 +0000438 return *this;
439}
440
441TcpListener::TcpListener(const struct sockaddr *listenaddr,
442 socklen_t listenaddrlen)
443{
444 int one = 1;
445 vnc_sockaddr_t sa;
446 int sock;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000447
448 initSockets();
Tim Waugh892d10a2015-03-11 13:12:07 +0000449
450 if ((sock = socket (listenaddr->sa_family, SOCK_STREAM, 0)) < 0)
451 throw SocketException("unable to create listening socket", errorNumber);
452
453 memcpy (&sa, listenaddr, listenaddrlen);
454#ifdef IPV6_V6ONLY
455 if (listenaddr->sa_family == AF_INET6) {
456 if (setsockopt (sock, IPPROTO_IPV6, IPV6_V6ONLY, (char*)&one, sizeof(one)))
457 throw SocketException("unable to set IPV6_V6ONLY", errorNumber);
458 }
459#endif /* defined(IPV6_V6ONLY) */
460
461 if (bind(sock, &sa.u.sa, listenaddrlen) == -1) {
462 closesocket(sock);
463 throw SocketException("failed to bind socket", errorNumber);
464 }
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000465
466#ifndef WIN32
467 // - By default, close the socket on exec()
Tim Waugh892d10a2015-03-11 13:12:07 +0000468 fcntl(sock, F_SETFD, FD_CLOEXEC);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000469
Tim Waugh892d10a2015-03-11 13:12:07 +0000470 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
471 (char *)&one, sizeof(one)) < 0) {
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000472 int e = errorNumber;
Tim Waugh892d10a2015-03-11 13:12:07 +0000473 closesocket(sock);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000474 throw SocketException("unable to create listening socket", e);
475 }
476#endif
477
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000478 // - Set it to be a listening socket
Tim Waugh892d10a2015-03-11 13:12:07 +0000479 if (listen(sock, 5) < 0) {
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000480 int e = errorNumber;
Tim Waugh892d10a2015-03-11 13:12:07 +0000481 closesocket(sock);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000482 throw SocketException("unable to set socket to listening mode", e);
483 }
Tim Waugh892d10a2015-03-11 13:12:07 +0000484
485 fd = sock;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000486}
487
488TcpListener::~TcpListener() {
Tim Waugh892d10a2015-03-11 13:12:07 +0000489 closesocket(fd);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000490}
491
492void TcpListener::shutdown()
493{
494#ifdef WIN32
495 closesocket(getFd());
496#else
497 ::shutdown(getFd(), 2);
498#endif
499}
500
501
502Socket*
503TcpListener::accept() {
504 int new_sock = -1;
505
506 // Accept an incoming connection
507 if ((new_sock = ::accept(fd, 0, 0)) < 0)
508 throw SocketException("unable to accept new connection", errorNumber);
509
510#ifndef WIN32
511 // - By default, close the socket on exec()
512 fcntl(new_sock, F_SETFD, FD_CLOEXEC);
513#endif
514
515 // Disable Nagle's algorithm, to reduce latency
516 TcpSocket::enableNagles(new_sock, false);
517
518 // Create the socket object & check connection is allowed
519 TcpSocket* s = new TcpSocket(new_sock);
520 if (filter && !filter->verifyConnection(s)) {
521 delete s;
522 return 0;
523 }
524 return s;
525}
526
Tim Waugh892d10a2015-03-11 13:12:07 +0000527int TcpListener::getMyPort() {
528 return TcpSocket::getSockPort(getFd());
529}
530
531
532void network::createLocalTcpListeners(std::list<TcpListener> *listeners,
533 int port)
534{
535 std::list<TcpListener> new_listeners;
536 vnc_sockaddr_t sa;
537#ifdef HAVE_GETADDRINFO
538 if (UseIPv6) {
539 sa.u.sin6.sin6_family = AF_INET6;
540 sa.u.sin6.sin6_port = htons (port);
541 sa.u.sin6.sin6_addr = in6addr_loopback;
542 try {
543 new_listeners.push_back (TcpListener (&sa.u.sa, sizeof (sa.u.sin6)));
544 } catch (SocketException& e) {
545 // Ignore this if it is due to lack of address family support on
546 // the interface or on the system
547 if (e.err != EADDRNOTAVAIL && e.err != EAFNOSUPPORT)
548 // Otherwise, report the error
549 throw;
550 }
551 }
552#endif /* HAVE_GETADDRINFO */
553 if (UseIPv4) {
554 sa.u.sin.sin_family = AF_INET;
555 sa.u.sin.sin_port = htons (port);
556 sa.u.sin.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
557 try {
558 new_listeners.push_back (TcpListener (&sa.u.sa, sizeof (sa.u.sin)));
559 } catch (SocketException& e) {
560 // Ignore this if it is due to lack of address family support on
561 // the interface or on the system
562 if (e.err != EADDRNOTAVAIL && e.err != EAFNOSUPPORT)
563 // Otherwise, report the error
564 throw;
565 }
566 }
567
568 if (new_listeners.empty ())
569 throw SocketException("createLocalTcpListeners: no addresses available",
570 EADDRNOTAVAIL);
571
572 listeners->splice (listeners->end(), new_listeners);
573}
574
575void network::createTcpListeners(std::list<TcpListener> *listeners,
576 const char *addr,
577 int port)
578{
579 std::list<TcpListener> new_listeners;
580
581#ifdef HAVE_GETADDRINFO
Tim Waugh6ae42df2014-11-17 17:07:07 +0000582 struct addrinfo *ai, *current, hints;
Tim Waugh892d10a2015-03-11 13:12:07 +0000583 char service[16];
Tim Waugh6ae42df2014-11-17 17:07:07 +0000584
585 memset(&hints, 0, sizeof(struct addrinfo));
Tim Waugh892d10a2015-03-11 13:12:07 +0000586 hints.ai_flags = AI_PASSIVE | AI_NUMERICSERV;
Tim Waugh6ae42df2014-11-17 17:07:07 +0000587 hints.ai_family = AF_UNSPEC;
588 hints.ai_socktype = SOCK_STREAM;
589 hints.ai_canonname = NULL;
590 hints.ai_addr = NULL;
591 hints.ai_next = NULL;
592
Tim Waugh892d10a2015-03-11 13:12:07 +0000593 snprintf (service, sizeof (service) - 1, "%d", port);
594 service[sizeof (service) - 1] = '\0';
595 if ((getaddrinfo(addr, service, &hints, &ai)) != 0)
596 throw rdr::SystemException("getaddrinfo", errorNumber);
Tim Waugh6ae42df2014-11-17 17:07:07 +0000597
Tim Waugh892d10a2015-03-11 13:12:07 +0000598 for (current = ai; current != NULL; current = current->ai_next) {
599 switch (current->ai_family) {
600 case AF_INET:
601 if (!UseIPv4)
602 continue;
603 break;
604
605 case AF_INET6:
606 if (!UseIPv6)
607 continue;
608 break;
609
610 default:
Tim Waugh6ae42df2014-11-17 17:07:07 +0000611 continue;
Tim Waugh892d10a2015-03-11 13:12:07 +0000612 }
Tim Waugh6ae42df2014-11-17 17:07:07 +0000613
Tim Waugh892d10a2015-03-11 13:12:07 +0000614 try {
615 new_listeners.push_back(TcpListener (current->ai_addr,
616 current->ai_addrlen));
617 } catch (SocketException& e) {
618 // Ignore this if it is due to lack of address family support on
619 // the interface or on the system
620 if (e.err != EADDRNOTAVAIL && e.err != EAFNOSUPPORT) {
621 // Otherwise, report the error
622 freeaddrinfo(ai);
623 throw;
624 }
625 }
Tim Waugh6ae42df2014-11-17 17:07:07 +0000626 }
627 freeaddrinfo(ai);
628#else
Tim Waugh892d10a2015-03-11 13:12:07 +0000629 const hostent* addrs;
630 if (addr) {
631 /* Bind to specific address */
632 addrs = gethostbyname(addr);
633 if (addrs == 0)
634 throw rdr::SystemException("gethostbyname", errorNumber);
635 if (addrs->h_addrtype != AF_INET)
636 throw rdr::Exception("createTcpListeners: bad family");
637 for (int i=0; addrs->h_addr_list[i] != 0; i++) {
638 struct sockaddr_in addr;
639 addr.sin_family = AF_INET;
640 memcpy (&addr.sin_addr, addrs->h_addr_list[i], addrs->h_length);
641 addr.sin_port = htons(port);
642 try {
643 new_listeners.push_back(TcpListener ((struct sockaddr*)&addr,
644 addrs->h_length));
645 } catch (SocketException& e) {
646 // Ignore this if it is due to lack of address family support
647 // on the interface or on the system
648 if (e.err != EADDRNOTAVAIL && e.err != EAFNOSUPPORT) {
649 // Otherwise, report the error
650 freeaddrinfo(ai);
651 throw;
652 }
653 }
654 }
655 } else {
656 /* Bind to any address */
657 struct sockaddr_in addr;
658 addr.sin_family = AF_INET;
659 addr.sin_addr.s_addr = htonl(INADDR_ANY);
660 addr.sin_port = htons(port);
661 try {
662 new_listeners.push_back(TcpListener ((struct sockaddr*)&addr,
663 sizeof (struct sockaddr_in)));
664 } catch (SocketException& e) {
665 // Ignore this if it is due to lack of address family support on
666 // the interface or on the system
667 if (e.err != EADDRNOTAVAIL && e.err != EAFNOSUPPORT) {
668 // Otherwise, report the error
669 freeaddrinfo(ai);
670 throw;
671 }
672 }
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000673 }
Tim Waugh892d10a2015-03-11 13:12:07 +0000674#endif /* defined(HAVE_GETADDRINFO) */
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000675
Tim Waugh892d10a2015-03-11 13:12:07 +0000676 if (new_listeners.empty ())
677 throw SocketException("createTcpListeners: no addresses available",
678 EADDRNOTAVAIL);
679
680 listeners->splice (listeners->end(), new_listeners);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000681}
682
683
684TcpFilter::TcpFilter(const char* spec) {
685 rfb::CharArray tmp;
Adam Tkacd36b6262009-09-04 10:57:20 +0000686 tmp.buf = rfb::strDup(spec);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000687 while (tmp.buf) {
688 rfb::CharArray first;
689 rfb::strSplit(tmp.buf, ',', &first.buf, &tmp.buf);
690 if (strlen(first.buf))
691 filter.push_back(parsePattern(first.buf));
692 }
693}
694
695TcpFilter::~TcpFilter() {
696}
697
698
699static bool
Tim Waughc24a64d2015-03-13 16:07:29 +0000700patternMatchIP(const TcpFilter::Pattern& pattern, vnc_sockaddr_t *sa) {
701 switch (pattern.address.u.sa.sa_family) {
702 unsigned long address;
703
704 case AF_INET:
705 if (sa->u.sa.sa_family != AF_INET)
706 return false;
707
708 address = sa->u.sin.sin_addr.s_addr;
709 if (address == htonl (INADDR_NONE)) return false;
710 return ((pattern.address.u.sin.sin_addr.s_addr &
711 pattern.mask.u.sin.sin_addr.s_addr) ==
712 (address & pattern.mask.u.sin.sin_addr.s_addr));
713
714 case AF_INET6:
715 if (sa->u.sa.sa_family != AF_INET6)
716 return false;
717
718 for (unsigned int n = 0; n < 16; n++) {
719 unsigned int bits = (n + 1) * 8;
720 unsigned int mask;
721 if (pattern.prefixlen > bits)
722 mask = 0xff;
723 else {
724 unsigned int lastbits = 0xff;
725 lastbits <<= bits - pattern.prefixlen;
726 mask = lastbits & 0xff;
727 }
728
729 if ((pattern.address.u.sin6.sin6_addr.s6_addr[n] & mask) !=
730 (sa->u.sin6.sin6_addr.s6_addr[n] & mask))
731 return false;
732
733 if (mask < 0xff)
734 break;
735 }
736
737 return true;
738
739 case AF_UNSPEC:
740 // Any address matches
741 return true;
742
743 default:
744 break;
745 }
746
747 return false;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000748}
749
750bool
751TcpFilter::verifyConnection(Socket* s) {
752 rfb::CharArray name;
Tim Waugh6ae42df2014-11-17 17:07:07 +0000753 vnc_sockaddr_t sa;
754 socklen_t sa_size = sizeof(sa);
Tim Waughc24a64d2015-03-13 16:07:29 +0000755
756 if (getpeername(s->getFd(), &sa.u.sa, &sa_size) != 0)
Tim Waugh6ae42df2014-11-17 17:07:07 +0000757 return false;
Tim Waugh6ae42df2014-11-17 17:07:07 +0000758
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000759 name.buf = s->getPeerAddress();
760 std::list<TcpFilter::Pattern>::iterator i;
761 for (i=filter.begin(); i!=filter.end(); i++) {
Tim Waughc24a64d2015-03-13 16:07:29 +0000762 if (patternMatchIP(*i, &sa)) {
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000763 switch ((*i).action) {
764 case Accept:
765 vlog.debug("ACCEPT %s", name.buf);
766 return true;
767 case Query:
768 vlog.debug("QUERY %s", name.buf);
769 s->setRequiresQuery();
770 return true;
771 case Reject:
772 vlog.debug("REJECT %s", name.buf);
773 return false;
774 }
775 }
776 }
777
778 vlog.debug("[REJECT] %s", name.buf);
779 return false;
780}
781
782
783TcpFilter::Pattern TcpFilter::parsePattern(const char* p) {
784 TcpFilter::Pattern pattern;
785
Tim Waughc24a64d2015-03-13 16:07:29 +0000786 rfb::CharArray addr, pref;
787 bool prefix_specified;
788 int family;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000789
Tim Waughc24a64d2015-03-13 16:07:29 +0000790 prefix_specified = rfb::strSplit(&p[1], '/', &addr.buf, &pref.buf);
791 if (addr.buf[0] == '\0') {
792 // Match any address
793 memset (&pattern.address, 0, sizeof (pattern.address));
794 pattern.address.u.sa.sa_family = AF_UNSPEC;
795 pattern.prefixlen = 0;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000796 } else {
Tim Waughc24a64d2015-03-13 16:07:29 +0000797#ifdef HAVE_GETADDRINFO
798 struct addrinfo hints;
799 struct addrinfo *ai;
800 char *p = addr.buf;
801 int result;
802 memset (&hints, 0, sizeof (hints));
803 hints.ai_family = AF_UNSPEC;
804 hints.ai_flags = AI_NUMERICHOST;
805
806 // Take out brackets, if present
807 if (*p == '[') {
808 size_t len;
809 p++;
810 len = strlen (p);
811 if (len > 0 && p[len - 1] == ']')
812 p[len - 1] = '\0';
813 }
814
815 if ((result = getaddrinfo (p, NULL, &hints, &ai)) != 0) {
816 throw Exception("unable to resolve host by name: %s",
817 gai_strerror(result));
818 }
819
820 memcpy (&pattern.address.u.sa, ai->ai_addr, ai->ai_addrlen);
821 freeaddrinfo (ai);
822#else
823 pattern.address.u.sa.sa_family = AF_INET;
824 pattern.address.u.sin.sin_addr.s_addr = inet_addr(addr.buf);
825#endif /* HAVE_GETADDRINFO */
826
827 family = pattern.address.u.sa.sa_family;
828
829 if (prefix_specified) {
830 if (family == AF_INET &&
831 rfb::strContains(pref.buf, '.')) {
832 throw Exception("mask no longer supported for filter, "
833 "use prefix instead");
834 }
835
836 pattern.prefixlen = (unsigned int) atoi(pref.buf);
837 } else {
838 switch (family) {
839 case AF_INET:
840 pattern.prefixlen = 32;
841 break;
842 case AF_INET6:
843 pattern.prefixlen = 128;
844 break;
845 default:
846 throw Exception("unknown address family");
847 }
848 }
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000849 }
850
Tim Waughc24a64d2015-03-13 16:07:29 +0000851 if (pattern.prefixlen > (family == AF_INET ? 32: 128))
852 throw Exception("invalid prefix length for filter address: %u",
853 pattern.prefixlen);
854
855 // Compute mask from address and prefix length
856 memset (&pattern.mask, 0, sizeof (pattern.mask));
857 switch (family) {
858 unsigned long mask;
859 case AF_INET:
860 mask = 0;
861 for (unsigned int i=0; i<pattern.prefixlen; i++)
862 mask |= 1<<(31-i);
863 pattern.mask.u.sin.sin_addr.s_addr = htonl(mask);
864 break;
865
866 case AF_INET6:
867 for (unsigned int n = 0; n < 16; n++) {
868 unsigned int bits = (n + 1) * 8;
869 if (pattern.prefixlen > bits)
870 pattern.mask.u.sin6.sin6_addr.s6_addr[n] = 0xff;
871 else {
872 unsigned int lastbits = 0xff;
873 lastbits <<= bits - pattern.prefixlen;
874 pattern.mask.u.sin6.sin6_addr.s6_addr[n] = lastbits & 0xff;
875 break;
876 }
877 }
878 break;
879 case AF_UNSPEC:
880 // No mask to compute
881 break;
882 default:
883 ; /* not reached */
884 }
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000885
886 switch(p[0]) {
887 case '+': pattern.action = TcpFilter::Accept; break;
888 case '-': pattern.action = TcpFilter::Reject; break;
889 case '?': pattern.action = TcpFilter::Query; break;
890 };
891
892 return pattern;
893}
894
895char* TcpFilter::patternToStr(const TcpFilter::Pattern& p) {
Tim Waughc24a64d2015-03-13 16:07:29 +0000896 rfb::CharArray addr;
897#ifdef HAVE_GETADDRINFO
898 char buffer[INET6_ADDRSTRLEN + 2];
899
900 if (p.address.u.sa.sa_family == AF_INET) {
901 getnameinfo(&p.address.u.sa, sizeof(p.address.u.sin),
902 buffer, sizeof (buffer), NULL, 0, NI_NUMERICHOST);
903 addr.buf = rfb::strDup(buffer);
904 } else if (p.address.u.sa.sa_family == AF_INET6) {
905 buffer[0] = '[';
906 getnameinfo(&p.address.u.sa, sizeof(p.address.u.sin6),
907 buffer + 1, sizeof (buffer) - 2, NULL, 0, NI_NUMERICHOST);
908 strcat(buffer, "]");
909 addr.buf = rfb::strDup(buffer);
910 } else if (p.address.u.sa.sa_family == AF_UNSPEC)
911 addr.buf = rfb::strDup("");
912#else
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000913 in_addr tmp;
Tim Waughc24a64d2015-03-13 16:07:29 +0000914 tmp.s_addr = p.address.u.sin.sin_addr.s_addr;
Adam Tkacd36b6262009-09-04 10:57:20 +0000915 addr.buf = rfb::strDup(inet_ntoa(tmp));
Tim Waughc24a64d2015-03-13 16:07:29 +0000916#endif /* HAVE_GETADDRINFO */
917
918 char action;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000919 switch (p.action) {
Tim Waughc24a64d2015-03-13 16:07:29 +0000920 case Accept: action = '+'; break;
921 case Reject: action = '-'; break;
922 default:
923 case Query: action = '?'; break;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000924 };
Tim Waughc24a64d2015-03-13 16:07:29 +0000925 size_t resultlen = (1 // action
926 + strlen (addr.buf) // address
927 + 1 // slash
928 + 3 // prefix length, max 128
929 + 1); // terminating nul
930 char* result = new char[resultlen];
931 if (addr.buf[0] == '\0')
932 snprintf(result, resultlen, "%c", action);
933 else
934 snprintf(result, resultlen, "%c%s/%u", action, addr.buf, p.prefixlen);
935
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000936 return result;
937}