blob: a45e535b5aa9ee295c85fee9d5bd7422becae466 [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 Tkacad1cbd92008-10-06 14:08:00 +000019#ifdef HAVE_COMMON_CONFIG_H
20#include <common-config.h>
21#endif
22
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000023#ifdef WIN32
24//#include <io.h>
25#include <winsock2.h>
26#define errorNumber WSAGetLastError()
27#define snprintf _snprintf
Peter Åstrandddfa1a12008-12-02 08:33:00 +000028#ifndef VNC_SOCKLEN_T
29#define VNC_SOCKLEN_T int
30#endif
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000031#else
32#define errorNumber errno
33#define closesocket close
34#include <sys/types.h>
35#include <sys/socket.h>
36#include <arpa/inet.h>
37#include <netinet/in.h>
38#include <netinet/tcp.h>
39#include <netdb.h>
40#include <unistd.h>
41#include <errno.h>
42#include <string.h>
43#include <signal.h>
44#include <fcntl.h>
45#endif
46
Adam Tkac04b7fd22008-03-19 16:14:48 +000047#include <stdlib.h>
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000048#include <network/TcpSocket.h>
49#include <rfb/util.h>
50#include <rfb/LogWriter.h>
51
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000052#ifndef INADDR_NONE
53#define INADDR_NONE ((unsigned long)-1)
54#endif
55#ifndef INADDR_LOOPBACK
56#define INADDR_LOOPBACK ((unsigned long)0x7F000001)
57#endif
58
59using namespace network;
60using namespace rdr;
61
Adam Tkac9cb6a422008-11-14 15:56:15 +000062typedef struct vnc_sockaddr {
63 union {
64 sockaddr sa;
65 sockaddr_in sin;
66#ifdef HAVE_GETADDRINFO
67 sockaddr_in6 sin6;
68#endif
69 } u;
70} vnc_sockaddr_t;
71
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000072static rfb::LogWriter vlog("TcpSocket");
73
74/* Tunnelling support. */
75int network::findFreeTcpPort (void)
76{
77 int sock, port;
78 struct sockaddr_in addr;
79 memset(&addr, 0, sizeof(addr));
80 addr.sin_family = AF_INET;
81 addr.sin_addr.s_addr = INADDR_ANY;
82
83 if ((sock = socket (AF_INET, SOCK_STREAM, 0)) < 0)
84 throw SocketException ("unable to create socket", errorNumber);
85
86 for (port = TUNNEL_PORT_OFFSET + 99; port > TUNNEL_PORT_OFFSET; port--) {
87 addr.sin_port = htons ((unsigned short) port);
88 if (bind (sock, (struct sockaddr *)&addr, sizeof (addr)) == 0) {
89 closesocket (sock);
90 return port;
91 }
92 }
93 throw SocketException ("no free port in range", 0);
94 return 0;
95}
96
97
98// -=- Socket initialisation
99static bool socketsInitialised = false;
100static void initSockets() {
101 if (socketsInitialised)
102 return;
103#ifdef WIN32
104 WORD requiredVersion = MAKEWORD(2,0);
105 WSADATA initResult;
106
107 if (WSAStartup(requiredVersion, &initResult) != 0)
108 throw SocketException("unable to initialise Winsock2", errorNumber);
109#else
110 signal(SIGPIPE, SIG_IGN);
111#endif
112 socketsInitialised = true;
113}
114
115
116// -=- TcpSocket
117
118TcpSocket::TcpSocket(int sock, bool close)
119 : Socket(new FdInStream(sock), new FdOutStream(sock), true), closeFd(close)
120{
121}
122
123TcpSocket::TcpSocket(const char *host, int port)
124 : closeFd(true)
125{
Adam Tkac9cb6a422008-11-14 15:56:15 +0000126 int sock, err, result, family;
127 vnc_sockaddr_t sa;
128 VNC_SOCKLEN_T salen;
129#ifdef HAVE_GETADDRINFO
130 struct addrinfo *ai, *current, hints;
131#endif
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000132
133 // - Create a socket
134 initSockets();
Adam Tkac9cb6a422008-11-14 15:56:15 +0000135
136#ifdef HAVE_GETADDRINFO
137 memset(&hints, 0, sizeof(struct addrinfo));
138 hints.ai_family = AF_UNSPEC;
139 hints.ai_socktype = SOCK_STREAM;
140 hints.ai_canonname = NULL;
141 hints.ai_addr = NULL;
142 hints.ai_next = NULL;
143
144 if ((result = getaddrinfo(host, NULL, &hints, &ai)) != 0) {
145 throw Exception("unable to resolve host by name: %s",
146 gai_strerror(result));
147 }
148
149 for (current = ai; current != NULL; current = current->ai_next) {
150 family = current->ai_family;
151 if (family != AF_INET && family != AF_INET6)
152 continue;
153
154 salen = current->ai_addrlen;
155 memcpy(&sa, current->ai_addr, salen);
156
157 if (family == AF_INET)
158 sa.u.sin.sin_port = htons(port);
159 else
160 sa.u.sin6.sin6_port = htons(port);
161
162#else /* HAVE_GETADDRINFO */
163 family = AF_INET;
164 salen = sizeof(struct sockaddr_in);
165
166 /* Try processing the host as an IP address */
167 memset(&sa, 0, sizeof(sa));
168 sa.u.sin.sin_family = AF_INET;
169 sa.u.sin.sin_addr.s_addr = inet_addr((char *)host);
170 sa.u.sin.sin_port = htons(port);
171 if ((int)sa.u.sin.sin_addr.s_addr == -1) {
172 /* Host was not an IP address - try resolving as DNS name */
173 struct hostent *hostinfo;
174 hostinfo = gethostbyname((char *)host);
175 if (hostinfo && hostinfo->h_addr) {
176 sa.u.sin.sin_addr.s_addr = ((struct in_addr *)hostinfo->h_addr)->s_addr;
177 } else {
178 err = errorNumber;
179 throw SocketException("unable to resolve host by name", err);
180 }
181 }
182#endif /* HAVE_GETADDRINFO */
183
184 sock = socket (family, SOCK_STREAM, 0);
185 if (sock == -1) {
186 err = errorNumber;
187#ifdef HAVE_GETADDRINFO
188 freeaddrinfo(ai);
189#endif /* HAVE_GETADDRINFO */
190 throw SocketException("unable to create socket", err);
191 }
192
193 /* Attempt to connect to the remote host */
194 while ((result = connect(sock, &sa.u.sa, sizeof(sa))) == -1) {
195 err = errorNumber;
196#ifndef WIN32
197 if (err == EINTR)
198 continue;
199#endif
200 closesocket(sock);
201 break;
202 }
203
204#ifdef HAVE_GETADDRINFO
205 if (result == 0)
206 break;
Adam Tkac9cb6a422008-11-14 15:56:15 +0000207 }
208
209 freeaddrinfo(ai);
210#endif /* HAVE_GETADDRINFO */
211
212 if (result == -1)
213 throw SocketException("unable connect to socket", err);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000214
215#ifndef WIN32
216 // - By default, close the socket on exec()
217 fcntl(sock, F_SETFD, FD_CLOEXEC);
218#endif
219
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000220 // Disable Nagle's algorithm, to reduce latency
221 enableNagles(sock, false);
222
223 // Create the input and output streams
224 instream = new FdInStream(sock);
225 outstream = new FdOutStream(sock);
226 ownStreams = true;
227}
228
229TcpSocket::~TcpSocket() {
230 if (closeFd)
231 closesocket(getFd());
232}
233
234char* TcpSocket::getMyAddress() {
235 struct sockaddr_in info;
236 struct in_addr addr;
237 VNC_SOCKLEN_T info_size = sizeof(info);
238
239 getsockname(getFd(), (struct sockaddr *)&info, &info_size);
240 memcpy(&addr, &info.sin_addr, sizeof(addr));
241
242 char* name = inet_ntoa(addr);
243 if (name) {
244 return rfb::strDup(name);
245 } else {
246 return rfb::strDup("");
247 }
248}
249
250int TcpSocket::getMyPort() {
251 return getSockPort(getFd());
252}
253
254char* TcpSocket::getMyEndpoint() {
255 rfb::CharArray address; address.buf = getMyAddress();
256 int port = getMyPort();
257
258 int buflen = strlen(address.buf) + 32;
259 char* buffer = new char[buflen];
260 sprintf(buffer, "%s::%d", address.buf, port);
261 return buffer;
262}
263
264char* TcpSocket::getPeerAddress() {
265 struct sockaddr_in info;
266 struct in_addr addr;
267 VNC_SOCKLEN_T info_size = sizeof(info);
268
269 getpeername(getFd(), (struct sockaddr *)&info, &info_size);
270 memcpy(&addr, &info.sin_addr, sizeof(addr));
271
272 char* name = inet_ntoa(addr);
273 if (name) {
274 return rfb::strDup(name);
275 } else {
276 return rfb::strDup("");
277 }
278}
279
280int TcpSocket::getPeerPort() {
281 struct sockaddr_in info;
282 VNC_SOCKLEN_T info_size = sizeof(info);
283
284 getpeername(getFd(), (struct sockaddr *)&info, &info_size);
285 return ntohs(info.sin_port);
286}
287
288char* TcpSocket::getPeerEndpoint() {
289 rfb::CharArray address; address.buf = getPeerAddress();
290 int port = getPeerPort();
291
292 int buflen = strlen(address.buf) + 32;
293 char* buffer = new char[buflen];
294 sprintf(buffer, "%s::%d", address.buf, port);
295 return buffer;
296}
297
298bool TcpSocket::sameMachine() {
299 struct sockaddr_in peeraddr, myaddr;
300 VNC_SOCKLEN_T addrlen = sizeof(struct sockaddr_in);
301
302 getpeername(getFd(), (struct sockaddr *)&peeraddr, &addrlen);
303 getsockname(getFd(), (struct sockaddr *)&myaddr, &addrlen);
304
305 return (peeraddr.sin_addr.s_addr == myaddr.sin_addr.s_addr);
306}
307
308void TcpSocket::shutdown()
309{
310 Socket::shutdown();
311 ::shutdown(getFd(), 2);
312}
313
314bool TcpSocket::enableNagles(int sock, bool enable) {
315 int one = enable ? 0 : 1;
316 if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
317 (char *)&one, sizeof(one)) < 0) {
318 int e = errorNumber;
319 vlog.error("unable to setsockopt TCP_NODELAY: %d", e);
320 return false;
321 }
322 return true;
323}
324
325bool TcpSocket::isSocket(int sock)
326{
327 struct sockaddr_in info;
328 VNC_SOCKLEN_T info_size = sizeof(info);
329 return getsockname(sock, (struct sockaddr *)&info, &info_size) >= 0;
330}
331
332bool TcpSocket::isConnected(int sock)
333{
334 struct sockaddr_in info;
335 VNC_SOCKLEN_T info_size = sizeof(info);
336 return getpeername(sock, (struct sockaddr *)&info, &info_size) >= 0;
337}
338
339int TcpSocket::getSockPort(int sock)
340{
341 struct sockaddr_in info;
342 VNC_SOCKLEN_T info_size = sizeof(info);
343 if (getsockname(sock, (struct sockaddr *)&info, &info_size) < 0)
344 return 0;
345 return ntohs(info.sin_port);
346}
347
348
349TcpListener::TcpListener(int port, bool localhostOnly, int sock, bool close_)
350 : closeFd(close_)
351{
352 if (sock != -1) {
353 fd = sock;
354 return;
355 }
356
357 initSockets();
358 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
359 throw SocketException("unable to create listening socket", errorNumber);
360
361#ifndef WIN32
362 // - By default, close the socket on exec()
363 fcntl(fd, F_SETFD, FD_CLOEXEC);
364
365 int one = 1;
366 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
367 (char *)&one, sizeof(one)) < 0) {
368 int e = errorNumber;
369 closesocket(fd);
370 throw SocketException("unable to create listening socket", e);
371 }
372#endif
373
374 // - Bind it to the desired port
375 struct sockaddr_in addr;
376 memset(&addr, 0, sizeof(addr));
377 addr.sin_family = AF_INET;
378 addr.sin_port = htons(port);
379 if (localhostOnly)
380 addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
381 else
382 addr.sin_addr.s_addr = htonl(INADDR_ANY);
383 if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
384 int e = errorNumber;
385 closesocket(fd);
386 throw SocketException("unable to bind listening socket", e);
387 }
388
389 // - Set it to be a listening socket
390 if (listen(fd, 5) < 0) {
391 int e = errorNumber;
392 closesocket(fd);
393 throw SocketException("unable to set socket to listening mode", e);
394 }
395}
396
397TcpListener::~TcpListener() {
398 if (closeFd) closesocket(fd);
399}
400
401void TcpListener::shutdown()
402{
403#ifdef WIN32
404 closesocket(getFd());
405#else
406 ::shutdown(getFd(), 2);
407#endif
408}
409
410
411Socket*
412TcpListener::accept() {
413 int new_sock = -1;
414
415 // Accept an incoming connection
416 if ((new_sock = ::accept(fd, 0, 0)) < 0)
417 throw SocketException("unable to accept new connection", errorNumber);
418
419#ifndef WIN32
420 // - By default, close the socket on exec()
421 fcntl(new_sock, F_SETFD, FD_CLOEXEC);
422#endif
423
424 // Disable Nagle's algorithm, to reduce latency
425 TcpSocket::enableNagles(new_sock, false);
426
427 // Create the socket object & check connection is allowed
428 TcpSocket* s = new TcpSocket(new_sock);
429 if (filter && !filter->verifyConnection(s)) {
430 delete s;
431 return 0;
432 }
433 return s;
434}
435
436void TcpListener::getMyAddresses(std::list<char*>* result) {
437 const hostent* addrs = gethostbyname(0);
438 if (addrs == 0)
439 throw rdr::SystemException("gethostbyname", errorNumber);
440 if (addrs->h_addrtype != AF_INET)
441 throw rdr::Exception("getMyAddresses: bad family");
442 for (int i=0; addrs->h_addr_list[i] != 0; i++) {
443 const char* addrC = inet_ntoa(*((struct in_addr*)addrs->h_addr_list[i]));
444 char* addr = new char[strlen(addrC)+1];
445 strcpy(addr, addrC);
446 result->push_back(addr);
447 }
448}
449
450int TcpListener::getMyPort() {
451 return TcpSocket::getSockPort(getFd());
452}
453
454
455TcpFilter::TcpFilter(const char* spec) {
456 rfb::CharArray tmp;
457 tmp.buf = rfb::strDup(spec);
458 while (tmp.buf) {
459 rfb::CharArray first;
460 rfb::strSplit(tmp.buf, ',', &first.buf, &tmp.buf);
461 if (strlen(first.buf))
462 filter.push_back(parsePattern(first.buf));
463 }
464}
465
466TcpFilter::~TcpFilter() {
467}
468
469
470static bool
471patternMatchIP(const TcpFilter::Pattern& pattern, const char* value) {
472 unsigned long address = inet_addr((char *)value);
473 if (address == INADDR_NONE) return false;
474 return ((pattern.address & pattern.mask) == (address & pattern.mask));
475}
476
477bool
478TcpFilter::verifyConnection(Socket* s) {
479 rfb::CharArray name;
480
481 name.buf = s->getPeerAddress();
482 std::list<TcpFilter::Pattern>::iterator i;
483 for (i=filter.begin(); i!=filter.end(); i++) {
484 if (patternMatchIP(*i, name.buf)) {
485 switch ((*i).action) {
486 case Accept:
487 vlog.debug("ACCEPT %s", name.buf);
488 return true;
489 case Query:
490 vlog.debug("QUERY %s", name.buf);
491 s->setRequiresQuery();
492 return true;
493 case Reject:
494 vlog.debug("REJECT %s", name.buf);
495 return false;
496 }
497 }
498 }
499
500 vlog.debug("[REJECT] %s", name.buf);
501 return false;
502}
503
504
505TcpFilter::Pattern TcpFilter::parsePattern(const char* p) {
506 TcpFilter::Pattern pattern;
507
508 bool expandMask = false;
509 rfb::CharArray addr, mask;
510
511 if (rfb::strSplit(&p[1], '/', &addr.buf, &mask.buf)) {
512 if (rfb::strContains(mask.buf, '.')) {
513 pattern.mask = inet_addr(mask.buf);
514 } else {
515 pattern.mask = atoi(mask.buf);
516 expandMask = true;
517 }
518 } else {
519 pattern.mask = 32;
520 expandMask = true;
521 }
522 if (expandMask) {
523 unsigned long expanded = 0;
524 // *** check endianness!
525 for (int i=0; i<(int)pattern.mask; i++)
526 expanded |= 1<<(31-i);
527 pattern.mask = htonl(expanded);
528 }
529
530 pattern.address = inet_addr(addr.buf) & pattern.mask;
531 if ((pattern.address == INADDR_NONE) ||
532 (pattern.address == 0)) pattern.mask = 0;
533
534 switch(p[0]) {
535 case '+': pattern.action = TcpFilter::Accept; break;
536 case '-': pattern.action = TcpFilter::Reject; break;
537 case '?': pattern.action = TcpFilter::Query; break;
538 };
539
540 return pattern;
541}
542
543char* TcpFilter::patternToStr(const TcpFilter::Pattern& p) {
544 in_addr tmp;
545 rfb::CharArray addr, mask;
546 tmp.s_addr = p.address;
547 addr.buf = rfb::strDup(inet_ntoa(tmp));
548 tmp.s_addr = p.mask;
549 mask.buf = rfb::strDup(inet_ntoa(tmp));
550 char* result = new char[strlen(addr.buf)+1+strlen(mask.buf)+1+1];
551 switch (p.action) {
552 case Accept: result[0] = '+'; break;
553 case Reject: result[0] = '-'; break;
554 case Query: result[0] = '?'; break;
555 };
556 result[1] = 0;
557 strcat(result, addr.buf);
558 strcat(result, "/");
559 strcat(result, mask.buf);
560 return result;
561}