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