blob: 035c7f261f348b182ab427b0579ed0ae8dc03ca4 [file] [log] [blame]
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +00001/* Copyright (C) 2002-2004 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
19#ifdef WIN32
20//#include <io.h>
21#include <winsock2.h>
22#define errorNumber WSAGetLastError()
23#define snprintf _snprintf
24#else
25#define errorNumber errno
26#define closesocket close
27#include <sys/types.h>
28#include <sys/socket.h>
29#include <arpa/inet.h>
30#include <netinet/in.h>
31#include <netinet/tcp.h>
32#include <netdb.h>
33#include <unistd.h>
34#include <errno.h>
35#include <string.h>
36#include <signal.h>
37#include <fcntl.h>
38#endif
39
40#include <network/TcpSocket.h>
41#include <rfb/util.h>
42#include <rfb/LogWriter.h>
43
44#ifndef VNC_SOCKLEN_T
45#define VNC_SOCKLEN_T int
46#endif
47
48#ifndef INADDR_NONE
49#define INADDR_NONE ((unsigned long)-1)
50#endif
Constantin Kaplinskya6866902006-03-02 12:03:30 +000051#ifndef INADDR_LOOPBACK
52#define INADDR_LOOPBACK ((unsigned long)0x7F000001)
53#endif
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +000054
55using namespace network;
56using namespace rdr;
57
58static rfb::LogWriter vlog("TcpSocket");
59
Peter Åstrandef07ae82005-02-14 13:11:35 +000060/* Tunnelling support. */
61int network::findFreeTcpPort (void)
62{
63 int sock, port;
64 struct sockaddr_in addr;
65 memset(&addr, 0, sizeof(addr));
66 addr.sin_family = AF_INET;
67 addr.sin_addr.s_addr = INADDR_ANY;
68
69 if ((sock = socket (AF_INET, SOCK_STREAM, 0)) < 0)
70 throw SocketException ("unable to create socket", errorNumber);
71
72 for (port = TUNNEL_PORT_OFFSET + 99; port > TUNNEL_PORT_OFFSET; port--) {
73 addr.sin_port = htons ((unsigned short) port);
74 if (bind (sock, (struct sockaddr *)&addr, sizeof (addr)) == 0) {
Peter Åstrand2ca93452005-02-21 10:17:21 +000075 closesocket (sock);
Peter Åstrandef07ae82005-02-14 13:11:35 +000076 return port;
77 }
78 }
79 throw SocketException ("no free port in range", 0);
80 return 0;
81}
82
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +000083
84void
85TcpSocket::initTcpSockets() {
86#ifdef WIN32
87 WORD requiredVersion = MAKEWORD(2,0);
88 WSADATA initResult;
89
90 if (WSAStartup(requiredVersion, &initResult) != 0)
91 throw SocketException("unable to initialise Winsock2", errorNumber);
92#else
93 signal(SIGPIPE, SIG_IGN);
94#endif
95}
96
97// -=- TcpSocket
98
99TcpSocket::TcpSocket(int sock, bool close)
100 : Socket(new FdInStream(sock), new FdOutStream(sock), true), closeFd(close)
101{
102}
103
104TcpSocket::TcpSocket(const char *host, int port)
105 : closeFd(true)
106{
107 int sock;
108
109 // - Create a socket
110 if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
111 throw SocketException("unable to create socket", errorNumber);
112
113#ifndef WIN32
114 // - By default, close the socket on exec()
115 fcntl(sock, F_SETFD, FD_CLOEXEC);
116#endif
117
118 // - Connect it to something
119
120 // Try processing the host as an IP address
121 struct sockaddr_in addr;
122 memset(&addr, 0, sizeof(addr));
123 addr.sin_family = AF_INET;
Constantin Kaplinskya6866902006-03-02 12:03:30 +0000124 addr.sin_addr.s_addr = inet_addr((char *)host);
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000125 addr.sin_port = htons(port);
126 if ((int)addr.sin_addr.s_addr == -1) {
127 // Host was not an IP address - try resolving as DNS name
128 struct hostent *hostinfo;
Constantin Kaplinskya6866902006-03-02 12:03:30 +0000129 hostinfo = gethostbyname((char *)host);
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000130 if (hostinfo && hostinfo->h_addr) {
131 addr.sin_addr.s_addr = ((struct in_addr *)hostinfo->h_addr)->s_addr;
132 } else {
133 int e = errorNumber;
134 closesocket(sock);
135 throw SocketException("unable to resolve host by name", e);
136 }
137 }
138
139 // Attempt to connect to the remote host
Peter Åstrand67ecfb42005-02-14 12:58:45 +0000140 for (;;) {
141 if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) != 0) {
142 int e = errorNumber;
Peter Åstrand2ca93452005-02-21 10:17:21 +0000143#ifndef WIN32
Peter Åstrand67ecfb42005-02-14 12:58:45 +0000144 if (e == EINTR)
145 continue;
Peter Åstrand2ca93452005-02-21 10:17:21 +0000146#endif
Peter Åstrand67ecfb42005-02-14 12:58:45 +0000147 closesocket(sock);
148 throw SocketException("unable to connect to host", e);
149 } else break;
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000150 }
151
152 int one = 1;
153 if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
154 (char *)&one, sizeof(one)) < 0) {
155 int e = errorNumber;
156 closesocket(sock);
157 throw SocketException("unable to setsockopt TCP_NODELAY", e);
158 }
159
160 // Create the input and output streams
161 instream = new FdInStream(sock);
162 outstream = new FdOutStream(sock);
163 own_streams = true;
164}
165
166TcpSocket::~TcpSocket() {
167 if (closeFd)
168 closesocket(getFd());
169}
170
171char* TcpSocket::getMyAddress() {
172 struct sockaddr_in info;
173 struct in_addr addr;
174 VNC_SOCKLEN_T info_size = sizeof(info);
175
176 getsockname(getFd(), (struct sockaddr *)&info, &info_size);
177 memcpy(&addr, &info.sin_addr, sizeof(addr));
178
179 char* name = inet_ntoa(addr);
180 if (name) {
181 return rfb::strDup(name);
182 } else {
183 return rfb::strDup("");
184 }
185}
186
187int TcpSocket::getMyPort() {
188 return getSockPort(getFd());
189}
190
191char* TcpSocket::getMyEndpoint() {
192 rfb::CharArray address; address.buf = getMyAddress();
193 int port = getMyPort();
194
195 int buflen = strlen(address.buf) + 32;
196 char* buffer = new char[buflen];
197 sprintf(buffer, "%s::%d", address.buf, port);
198 return buffer;
199}
200
201char* TcpSocket::getPeerAddress() {
202 struct sockaddr_in info;
203 struct in_addr addr;
204 VNC_SOCKLEN_T info_size = sizeof(info);
205
206 getpeername(getFd(), (struct sockaddr *)&info, &info_size);
207 memcpy(&addr, &info.sin_addr, sizeof(addr));
208
209 char* name = inet_ntoa(addr);
210 if (name) {
211 return rfb::strDup(name);
212 } else {
213 return rfb::strDup("");
214 }
215}
216
217int TcpSocket::getPeerPort() {
218 struct sockaddr_in info;
219 VNC_SOCKLEN_T info_size = sizeof(info);
220
221 getpeername(getFd(), (struct sockaddr *)&info, &info_size);
222 return ntohs(info.sin_port);
223}
224
225char* TcpSocket::getPeerEndpoint() {
226 rfb::CharArray address; address.buf = getPeerAddress();
227 int port = getPeerPort();
228
229 int buflen = strlen(address.buf) + 32;
230 char* buffer = new char[buflen];
231 sprintf(buffer, "%s::%d", address.buf, port);
232 return buffer;
233}
234
235bool TcpSocket::sameMachine() {
236 struct sockaddr_in peeraddr, myaddr;
237 VNC_SOCKLEN_T addrlen = sizeof(struct sockaddr_in);
238
239 getpeername(getFd(), (struct sockaddr *)&peeraddr, &addrlen);
240 getsockname(getFd(), (struct sockaddr *)&myaddr, &addrlen);
241
242 return (peeraddr.sin_addr.s_addr == myaddr.sin_addr.s_addr);
243}
244
245void TcpSocket::shutdown()
246{
247 ::shutdown(getFd(), 2);
248}
249
250bool TcpSocket::isSocket(int sock)
251{
252 struct sockaddr_in info;
253 VNC_SOCKLEN_T info_size = sizeof(info);
254 return getsockname(sock, (struct sockaddr *)&info, &info_size) >= 0;
255}
256
257bool TcpSocket::isConnected(int sock)
258{
259 struct sockaddr_in info;
260 VNC_SOCKLEN_T info_size = sizeof(info);
261 return getpeername(sock, (struct sockaddr *)&info, &info_size) >= 0;
262}
263
264int TcpSocket::getSockPort(int sock)
265{
266 struct sockaddr_in info;
267 VNC_SOCKLEN_T info_size = sizeof(info);
268 if (getsockname(sock, (struct sockaddr *)&info, &info_size) < 0)
269 return 0;
270 return ntohs(info.sin_port);
271}
272
273
274TcpListener::TcpListener(int port, bool localhostOnly, int sock, bool close_)
275 : closeFd(close_)
276{
277 if (sock != -1) {
278 fd = sock;
279 return;
280 }
281
282 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
283 throw SocketException("unable to create listening socket", errorNumber);
284
285#ifndef WIN32
286 // - By default, close the socket on exec()
287 fcntl(sock, F_SETFD, FD_CLOEXEC);
288
289 int one = 1;
290 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
Constantin Kaplinskya6866902006-03-02 12:03:30 +0000291 (char *)&one, sizeof(one)) < 0) {
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000292 int e = errorNumber;
293 closesocket(fd);
294 throw SocketException("unable to create listening socket", e);
295 }
296#endif
297
298 // - Bind it to the desired port
299 struct sockaddr_in addr;
300 memset(&addr, 0, sizeof(addr));
301 addr.sin_family = AF_INET;
302 addr.sin_port = htons(port);
303 if (localhostOnly)
304 addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
305 else
306 addr.sin_addr.s_addr = htonl(INADDR_ANY);
307 if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
308 int e = errorNumber;
309 closesocket(fd);
310 throw SocketException("unable to bind listening socket", e);
311 }
312
313 // - Set it to be a listening socket
314 if (listen(fd, 5) < 0) {
315 int e = errorNumber;
316 closesocket(fd);
317 throw SocketException("unable to set socket to listening mode", e);
318 }
319}
320
321TcpListener::~TcpListener() {
322 if (closeFd) closesocket(fd);
323}
324
325void TcpListener::shutdown()
326{
327#ifdef WIN32
328 closesocket(getFd());
329#else
330 ::shutdown(getFd(), 2);
331#endif
332}
333
334
335Socket*
336TcpListener::accept() {
337 int new_sock = -1;
338
339 // Accept an incoming connection
340 if ((new_sock = ::accept(fd, 0, 0)) < 0)
341 throw SocketException("unable to accept new connection", errorNumber);
342
343#ifndef WIN32
344 // - By default, close the socket on exec()
345 fcntl(new_sock, F_SETFD, FD_CLOEXEC);
346#endif
347
348 // Disable Nagle's algorithm
349 int one = 1;
350 if (setsockopt(new_sock, IPPROTO_TCP, TCP_NODELAY,
351 (char *)&one, sizeof(one)) < 0) {
352 int e = errorNumber;
353 closesocket(new_sock);
354 throw SocketException("unable to setsockopt TCP_NODELAY", e);
355 }
356
357 // Create the socket object & check connection is allowed
358 TcpSocket* s = new TcpSocket(new_sock);
359 if (filter && !filter->verifyConnection(s)) {
360 delete s;
361 return 0;
362 }
363 return s;
364}
365
366void TcpListener::getMyAddresses(std::list<char*>* result) {
367 const hostent* addrs = gethostbyname(0);
368 if (addrs == 0)
369 throw rdr::SystemException("gethostbyname", errorNumber);
370 if (addrs->h_addrtype != AF_INET)
371 throw rdr::Exception("getMyAddresses: bad family");
372 for (int i=0; addrs->h_addr_list[i] != 0; i++) {
373 const char* addrC = inet_ntoa(*((struct in_addr*)addrs->h_addr_list[i]));
374 char* addr = new char[strlen(addrC)+1];
375 strcpy(addr, addrC);
376 result->push_back(addr);
377 }
378}
379
380int TcpListener::getMyPort() {
381 return TcpSocket::getSockPort(getFd());
382}
383
384
385TcpFilter::TcpFilter(const char* spec) {
386 rfb::CharArray tmp;
387 tmp.buf = rfb::strDup(spec);
388 while (tmp.buf) {
389 rfb::CharArray first;
390 rfb::strSplit(tmp.buf, ',', &first.buf, &tmp.buf);
391 if (strlen(first.buf))
392 filter.push_back(parsePattern(first.buf));
393 }
394}
395
396TcpFilter::~TcpFilter() {
397}
398
399
400static bool
401patternMatchIP(const TcpFilter::Pattern& pattern, const char* value) {
Constantin Kaplinskya6866902006-03-02 12:03:30 +0000402 unsigned long address = inet_addr((char *)value);
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000403 if (address == INADDR_NONE) return false;
404 return ((pattern.address & pattern.mask) == (address & pattern.mask));
405}
406
407bool
408TcpFilter::verifyConnection(Socket* s) {
409 rfb::CharArray name;
410
411 name.buf = s->getPeerAddress();
412 std::list<TcpFilter::Pattern>::iterator i;
413 for (i=filter.begin(); i!=filter.end(); i++) {
414 if (patternMatchIP(*i, name.buf)) {
415 switch ((*i).action) {
416 case Accept:
417 vlog.debug("ACCEPT %s", name.buf);
418 return true;
419 case Query:
420 vlog.debug("QUERY %s", name.buf);
421 return queryUserAcceptConnection(s);
422 case Reject:
423 vlog.debug("REJECT %s", name.buf);
424 return false;
425 }
426 }
427 }
428
429 vlog.debug("[REJECT] %s", name.buf);
430 return false;
431}
432
433
434TcpFilter::Pattern TcpFilter::parsePattern(const char* p) {
435 TcpFilter::Pattern pattern;
436
437 bool expandMask = false;
438 rfb::CharArray addr, mask;
439
440 if (rfb::strSplit(&p[1], '/', &addr.buf, &mask.buf)) {
441 if (rfb::strContains(mask.buf, '.')) {
442 pattern.mask = inet_addr(mask.buf);
443 } else {
444 pattern.mask = atoi(mask.buf);
445 expandMask = true;
446 }
447 } else {
448 pattern.mask = 32;
449 expandMask = true;
450 }
451 if (expandMask) {
452 unsigned long expanded = 0;
453 // *** check endianness!
454 for (int i=0; i<(int)pattern.mask; i++)
455 expanded |= 1<<(31-i);
456 pattern.mask = htonl(expanded);
457 }
458
459 pattern.address = inet_addr(addr.buf) & pattern.mask;
460 if ((pattern.address == INADDR_NONE) ||
461 (pattern.address == 0)) pattern.mask = 0;
462
463 switch(p[0]) {
464 case '+': pattern.action = TcpFilter::Accept; break;
465 case '-': pattern.action = TcpFilter::Reject; break;
466 case '?': pattern.action = TcpFilter::Query; break;
467 };
468
469 return pattern;
470}
471
472char* TcpFilter::patternToStr(const TcpFilter::Pattern& p) {
473 in_addr tmp;
474 rfb::CharArray addr, mask;
475 tmp.s_addr = p.address;
476 addr.buf = rfb::strDup(inet_ntoa(tmp));
477 tmp.s_addr = p.mask;
478 mask.buf = rfb::strDup(inet_ntoa(tmp));
479 char* result = new char[strlen(addr.buf)+1+strlen(mask.buf)+1+1];
480 switch (p.action) {
481 case Accept: result[0] = '+'; break;
482 case Reject: result[0] = '-'; break;
483 case Query: result[0] = '?'; break;
484 };
485 result[1] = 0;
486 strcat(result, addr.buf);
487 strcat(result, "/");
488 strcat(result, mask.buf);
489 return result;
490}