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