blob: 1d0de9f2f4bf980c5d023f0e212e340142f56a09 [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) {
Peter Åstrand2ca93452005-02-21 10:17:21 +000072 closesocket (sock);
Peter Åstrandef07ae82005-02-14 13:11:35 +000073 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;
Peter Åstrand2ca93452005-02-21 10:17:21 +0000140#ifndef WIN32
Peter Åstrand67ecfb42005-02-14 12:58:45 +0000141 if (e == EINTR)
142 continue;
Peter Åstrand2ca93452005-02-21 10:17:21 +0000143#endif
Peter Åstrand67ecfb42005-02-14 12:58:45 +0000144 closesocket(sock);
145 throw SocketException("unable to connect to host", e);
146 } else break;
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000147 }
148
149 int one = 1;
150 if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
151 (char *)&one, sizeof(one)) < 0) {
152 int e = errorNumber;
153 closesocket(sock);
154 throw SocketException("unable to setsockopt TCP_NODELAY", e);
155 }
156
157 // Create the input and output streams
158 instream = new FdInStream(sock);
159 outstream = new FdOutStream(sock);
160 own_streams = true;
161}
162
163TcpSocket::~TcpSocket() {
164 if (closeFd)
165 closesocket(getFd());
166}
167
168char* TcpSocket::getMyAddress() {
169 struct sockaddr_in info;
170 struct in_addr addr;
171 VNC_SOCKLEN_T info_size = sizeof(info);
172
173 getsockname(getFd(), (struct sockaddr *)&info, &info_size);
174 memcpy(&addr, &info.sin_addr, sizeof(addr));
175
176 char* name = inet_ntoa(addr);
177 if (name) {
178 return rfb::strDup(name);
179 } else {
180 return rfb::strDup("");
181 }
182}
183
184int TcpSocket::getMyPort() {
185 return getSockPort(getFd());
186}
187
188char* TcpSocket::getMyEndpoint() {
189 rfb::CharArray address; address.buf = getMyAddress();
190 int port = getMyPort();
191
192 int buflen = strlen(address.buf) + 32;
193 char* buffer = new char[buflen];
194 sprintf(buffer, "%s::%d", address.buf, port);
195 return buffer;
196}
197
198char* TcpSocket::getPeerAddress() {
199 struct sockaddr_in info;
200 struct in_addr addr;
201 VNC_SOCKLEN_T info_size = sizeof(info);
202
203 getpeername(getFd(), (struct sockaddr *)&info, &info_size);
204 memcpy(&addr, &info.sin_addr, sizeof(addr));
205
206 char* name = inet_ntoa(addr);
207 if (name) {
208 return rfb::strDup(name);
209 } else {
210 return rfb::strDup("");
211 }
212}
213
214int TcpSocket::getPeerPort() {
215 struct sockaddr_in info;
216 VNC_SOCKLEN_T info_size = sizeof(info);
217
218 getpeername(getFd(), (struct sockaddr *)&info, &info_size);
219 return ntohs(info.sin_port);
220}
221
222char* TcpSocket::getPeerEndpoint() {
223 rfb::CharArray address; address.buf = getPeerAddress();
224 int port = getPeerPort();
225
226 int buflen = strlen(address.buf) + 32;
227 char* buffer = new char[buflen];
228 sprintf(buffer, "%s::%d", address.buf, port);
229 return buffer;
230}
231
232bool TcpSocket::sameMachine() {
233 struct sockaddr_in peeraddr, myaddr;
234 VNC_SOCKLEN_T addrlen = sizeof(struct sockaddr_in);
235
236 getpeername(getFd(), (struct sockaddr *)&peeraddr, &addrlen);
237 getsockname(getFd(), (struct sockaddr *)&myaddr, &addrlen);
238
239 return (peeraddr.sin_addr.s_addr == myaddr.sin_addr.s_addr);
240}
241
242void TcpSocket::shutdown()
243{
244 ::shutdown(getFd(), 2);
245}
246
247bool TcpSocket::isSocket(int sock)
248{
249 struct sockaddr_in info;
250 VNC_SOCKLEN_T info_size = sizeof(info);
251 return getsockname(sock, (struct sockaddr *)&info, &info_size) >= 0;
252}
253
254bool TcpSocket::isConnected(int sock)
255{
256 struct sockaddr_in info;
257 VNC_SOCKLEN_T info_size = sizeof(info);
258 return getpeername(sock, (struct sockaddr *)&info, &info_size) >= 0;
259}
260
261int TcpSocket::getSockPort(int sock)
262{
263 struct sockaddr_in info;
264 VNC_SOCKLEN_T info_size = sizeof(info);
265 if (getsockname(sock, (struct sockaddr *)&info, &info_size) < 0)
266 return 0;
267 return ntohs(info.sin_port);
268}
269
270
271TcpListener::TcpListener(int port, bool localhostOnly, int sock, bool close_)
272 : closeFd(close_)
273{
274 if (sock != -1) {
275 fd = sock;
276 return;
277 }
278
279 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
280 throw SocketException("unable to create listening socket", errorNumber);
281
282#ifndef WIN32
283 // - By default, close the socket on exec()
284 fcntl(sock, F_SETFD, FD_CLOEXEC);
285
286 int one = 1;
287 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
288 (const char *)&one, sizeof(one)) < 0) {
289 int e = errorNumber;
290 closesocket(fd);
291 throw SocketException("unable to create listening socket", e);
292 }
293#endif
294
295 // - Bind it to the desired port
296 struct sockaddr_in addr;
297 memset(&addr, 0, sizeof(addr));
298 addr.sin_family = AF_INET;
299 addr.sin_port = htons(port);
300 if (localhostOnly)
301 addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
302 else
303 addr.sin_addr.s_addr = htonl(INADDR_ANY);
304 if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
305 int e = errorNumber;
306 closesocket(fd);
307 throw SocketException("unable to bind listening socket", e);
308 }
309
310 // - Set it to be a listening socket
311 if (listen(fd, 5) < 0) {
312 int e = errorNumber;
313 closesocket(fd);
314 throw SocketException("unable to set socket to listening mode", e);
315 }
316}
317
318TcpListener::~TcpListener() {
319 if (closeFd) closesocket(fd);
320}
321
322void TcpListener::shutdown()
323{
324#ifdef WIN32
325 closesocket(getFd());
326#else
327 ::shutdown(getFd(), 2);
328#endif
329}
330
331
332Socket*
333TcpListener::accept() {
334 int new_sock = -1;
335
336 // Accept an incoming connection
337 if ((new_sock = ::accept(fd, 0, 0)) < 0)
338 throw SocketException("unable to accept new connection", errorNumber);
339
340#ifndef WIN32
341 // - By default, close the socket on exec()
342 fcntl(new_sock, F_SETFD, FD_CLOEXEC);
343#endif
344
345 // Disable Nagle's algorithm
346 int one = 1;
347 if (setsockopt(new_sock, IPPROTO_TCP, TCP_NODELAY,
348 (char *)&one, sizeof(one)) < 0) {
349 int e = errorNumber;
350 closesocket(new_sock);
351 throw SocketException("unable to setsockopt TCP_NODELAY", e);
352 }
353
354 // Create the socket object & check connection is allowed
355 TcpSocket* s = new TcpSocket(new_sock);
356 if (filter && !filter->verifyConnection(s)) {
357 delete s;
358 return 0;
359 }
360 return s;
361}
362
363void TcpListener::getMyAddresses(std::list<char*>* result) {
364 const hostent* addrs = gethostbyname(0);
365 if (addrs == 0)
366 throw rdr::SystemException("gethostbyname", errorNumber);
367 if (addrs->h_addrtype != AF_INET)
368 throw rdr::Exception("getMyAddresses: bad family");
369 for (int i=0; addrs->h_addr_list[i] != 0; i++) {
370 const char* addrC = inet_ntoa(*((struct in_addr*)addrs->h_addr_list[i]));
371 char* addr = new char[strlen(addrC)+1];
372 strcpy(addr, addrC);
373 result->push_back(addr);
374 }
375}
376
377int TcpListener::getMyPort() {
378 return TcpSocket::getSockPort(getFd());
379}
380
381
382TcpFilter::TcpFilter(const char* spec) {
383 rfb::CharArray tmp;
384 tmp.buf = rfb::strDup(spec);
385 while (tmp.buf) {
386 rfb::CharArray first;
387 rfb::strSplit(tmp.buf, ',', &first.buf, &tmp.buf);
388 if (strlen(first.buf))
389 filter.push_back(parsePattern(first.buf));
390 }
391}
392
393TcpFilter::~TcpFilter() {
394}
395
396
397static bool
398patternMatchIP(const TcpFilter::Pattern& pattern, const char* value) {
399 unsigned long address = inet_addr(value);
400 if (address == INADDR_NONE) return false;
401 return ((pattern.address & pattern.mask) == (address & pattern.mask));
402}
403
404bool
405TcpFilter::verifyConnection(Socket* s) {
406 rfb::CharArray name;
407
408 name.buf = s->getPeerAddress();
409 std::list<TcpFilter::Pattern>::iterator i;
410 for (i=filter.begin(); i!=filter.end(); i++) {
411 if (patternMatchIP(*i, name.buf)) {
412 switch ((*i).action) {
413 case Accept:
414 vlog.debug("ACCEPT %s", name.buf);
415 return true;
416 case Query:
417 vlog.debug("QUERY %s", name.buf);
418 return queryUserAcceptConnection(s);
419 case Reject:
420 vlog.debug("REJECT %s", name.buf);
421 return false;
422 }
423 }
424 }
425
426 vlog.debug("[REJECT] %s", name.buf);
427 return false;
428}
429
430
431TcpFilter::Pattern TcpFilter::parsePattern(const char* p) {
432 TcpFilter::Pattern pattern;
433
434 bool expandMask = false;
435 rfb::CharArray addr, mask;
436
437 if (rfb::strSplit(&p[1], '/', &addr.buf, &mask.buf)) {
438 if (rfb::strContains(mask.buf, '.')) {
439 pattern.mask = inet_addr(mask.buf);
440 } else {
441 pattern.mask = atoi(mask.buf);
442 expandMask = true;
443 }
444 } else {
445 pattern.mask = 32;
446 expandMask = true;
447 }
448 if (expandMask) {
449 unsigned long expanded = 0;
450 // *** check endianness!
451 for (int i=0; i<(int)pattern.mask; i++)
452 expanded |= 1<<(31-i);
453 pattern.mask = htonl(expanded);
454 }
455
456 pattern.address = inet_addr(addr.buf) & pattern.mask;
457 if ((pattern.address == INADDR_NONE) ||
458 (pattern.address == 0)) pattern.mask = 0;
459
460 switch(p[0]) {
461 case '+': pattern.action = TcpFilter::Accept; break;
462 case '-': pattern.action = TcpFilter::Reject; break;
463 case '?': pattern.action = TcpFilter::Query; break;
464 };
465
466 return pattern;
467}
468
469char* TcpFilter::patternToStr(const TcpFilter::Pattern& p) {
470 in_addr tmp;
471 rfb::CharArray addr, mask;
472 tmp.s_addr = p.address;
473 addr.buf = rfb::strDup(inet_ntoa(tmp));
474 tmp.s_addr = p.mask;
475 mask.buf = rfb::strDup(inet_ntoa(tmp));
476 char* result = new char[strlen(addr.buf)+1+strlen(mask.buf)+1+1];
477 switch (p.action) {
478 case Accept: result[0] = '+'; break;
479 case Reject: result[0] = '-'; break;
480 case Query: result[0] = '?'; break;
481 };
482 result[1] = 0;
483 strcat(result, addr.buf);
484 strcat(result, "/");
485 strcat(result, mask.buf);
486 return result;
487}