You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

TcpSocket.cxx 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458
  1. /* 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. #ifdef WIN32
  19. //#include <io.h>
  20. #include <winsock2.h>
  21. #define errorNumber WSAGetLastError()
  22. #define snprintf _snprintf
  23. #else
  24. #define errorNumber errno
  25. #define closesocket close
  26. #include <sys/types.h>
  27. #include <sys/socket.h>
  28. #include <arpa/inet.h>
  29. #include <netinet/in.h>
  30. #include <netinet/tcp.h>
  31. #include <netdb.h>
  32. #include <unistd.h>
  33. #include <errno.h>
  34. #include <string.h>
  35. #include <signal.h>
  36. #include <fcntl.h>
  37. #endif
  38. #include <network/TcpSocket.h>
  39. #include <rfb/util.h>
  40. #include <rfb/LogWriter.h>
  41. #ifndef VNC_SOCKLEN_T
  42. #define VNC_SOCKLEN_T int
  43. #endif
  44. #ifndef INADDR_NONE
  45. #define INADDR_NONE ((unsigned long)-1)
  46. #endif
  47. using namespace network;
  48. using namespace rdr;
  49. static rfb::LogWriter vlog("TcpSocket");
  50. void
  51. TcpSocket::initTcpSockets() {
  52. #ifdef WIN32
  53. WORD requiredVersion = MAKEWORD(2,0);
  54. WSADATA initResult;
  55. if (WSAStartup(requiredVersion, &initResult) != 0)
  56. throw SocketException("unable to initialise Winsock2", errorNumber);
  57. #else
  58. signal(SIGPIPE, SIG_IGN);
  59. #endif
  60. }
  61. // -=- TcpSocket
  62. TcpSocket::TcpSocket(int sock, bool close)
  63. : Socket(new FdInStream(sock), new FdOutStream(sock), true), closeFd(close)
  64. {
  65. }
  66. TcpSocket::TcpSocket(const char *host, int port)
  67. : closeFd(true)
  68. {
  69. int sock;
  70. // - Create a socket
  71. if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
  72. throw SocketException("unable to create socket", errorNumber);
  73. #ifndef WIN32
  74. // - By default, close the socket on exec()
  75. fcntl(sock, F_SETFD, FD_CLOEXEC);
  76. #endif
  77. // - Connect it to something
  78. // Try processing the host as an IP address
  79. struct sockaddr_in addr;
  80. memset(&addr, 0, sizeof(addr));
  81. addr.sin_family = AF_INET;
  82. addr.sin_addr.s_addr = inet_addr(host);
  83. addr.sin_port = htons(port);
  84. if ((int)addr.sin_addr.s_addr == -1) {
  85. // Host was not an IP address - try resolving as DNS name
  86. struct hostent *hostinfo;
  87. hostinfo = gethostbyname(host);
  88. if (hostinfo && hostinfo->h_addr) {
  89. addr.sin_addr.s_addr = ((struct in_addr *)hostinfo->h_addr)->s_addr;
  90. } else {
  91. int e = errorNumber;
  92. closesocket(sock);
  93. throw SocketException("unable to resolve host by name", e);
  94. }
  95. }
  96. // Attempt to connect to the remote host
  97. if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) != 0) {
  98. int e = errorNumber;
  99. closesocket(sock);
  100. throw SocketException("unable to connect to host", e);
  101. }
  102. int one = 1;
  103. if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
  104. (char *)&one, sizeof(one)) < 0) {
  105. int e = errorNumber;
  106. closesocket(sock);
  107. throw SocketException("unable to setsockopt TCP_NODELAY", e);
  108. }
  109. // Create the input and output streams
  110. instream = new FdInStream(sock);
  111. outstream = new FdOutStream(sock);
  112. own_streams = true;
  113. }
  114. TcpSocket::~TcpSocket() {
  115. if (closeFd)
  116. closesocket(getFd());
  117. }
  118. char* TcpSocket::getMyAddress() {
  119. struct sockaddr_in info;
  120. struct in_addr addr;
  121. VNC_SOCKLEN_T info_size = sizeof(info);
  122. getsockname(getFd(), (struct sockaddr *)&info, &info_size);
  123. memcpy(&addr, &info.sin_addr, sizeof(addr));
  124. char* name = inet_ntoa(addr);
  125. if (name) {
  126. return rfb::strDup(name);
  127. } else {
  128. return rfb::strDup("");
  129. }
  130. }
  131. int TcpSocket::getMyPort() {
  132. return getSockPort(getFd());
  133. }
  134. char* TcpSocket::getMyEndpoint() {
  135. rfb::CharArray address; address.buf = getMyAddress();
  136. int port = getMyPort();
  137. int buflen = strlen(address.buf) + 32;
  138. char* buffer = new char[buflen];
  139. sprintf(buffer, "%s::%d", address.buf, port);
  140. return buffer;
  141. }
  142. char* TcpSocket::getPeerAddress() {
  143. struct sockaddr_in info;
  144. struct in_addr addr;
  145. VNC_SOCKLEN_T info_size = sizeof(info);
  146. getpeername(getFd(), (struct sockaddr *)&info, &info_size);
  147. memcpy(&addr, &info.sin_addr, sizeof(addr));
  148. char* name = inet_ntoa(addr);
  149. if (name) {
  150. return rfb::strDup(name);
  151. } else {
  152. return rfb::strDup("");
  153. }
  154. }
  155. int TcpSocket::getPeerPort() {
  156. struct sockaddr_in info;
  157. VNC_SOCKLEN_T info_size = sizeof(info);
  158. getpeername(getFd(), (struct sockaddr *)&info, &info_size);
  159. return ntohs(info.sin_port);
  160. }
  161. char* TcpSocket::getPeerEndpoint() {
  162. rfb::CharArray address; address.buf = getPeerAddress();
  163. int port = getPeerPort();
  164. int buflen = strlen(address.buf) + 32;
  165. char* buffer = new char[buflen];
  166. sprintf(buffer, "%s::%d", address.buf, port);
  167. return buffer;
  168. }
  169. bool TcpSocket::sameMachine() {
  170. struct sockaddr_in peeraddr, myaddr;
  171. VNC_SOCKLEN_T addrlen = sizeof(struct sockaddr_in);
  172. getpeername(getFd(), (struct sockaddr *)&peeraddr, &addrlen);
  173. getsockname(getFd(), (struct sockaddr *)&myaddr, &addrlen);
  174. return (peeraddr.sin_addr.s_addr == myaddr.sin_addr.s_addr);
  175. }
  176. void TcpSocket::shutdown()
  177. {
  178. ::shutdown(getFd(), 2);
  179. }
  180. bool TcpSocket::isSocket(int sock)
  181. {
  182. struct sockaddr_in info;
  183. VNC_SOCKLEN_T info_size = sizeof(info);
  184. return getsockname(sock, (struct sockaddr *)&info, &info_size) >= 0;
  185. }
  186. bool TcpSocket::isConnected(int sock)
  187. {
  188. struct sockaddr_in info;
  189. VNC_SOCKLEN_T info_size = sizeof(info);
  190. return getpeername(sock, (struct sockaddr *)&info, &info_size) >= 0;
  191. }
  192. int TcpSocket::getSockPort(int sock)
  193. {
  194. struct sockaddr_in info;
  195. VNC_SOCKLEN_T info_size = sizeof(info);
  196. if (getsockname(sock, (struct sockaddr *)&info, &info_size) < 0)
  197. return 0;
  198. return ntohs(info.sin_port);
  199. }
  200. TcpListener::TcpListener(int port, bool localhostOnly, int sock, bool close_)
  201. : closeFd(close_)
  202. {
  203. if (sock != -1) {
  204. fd = sock;
  205. return;
  206. }
  207. if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
  208. throw SocketException("unable to create listening socket", errorNumber);
  209. #ifndef WIN32
  210. // - By default, close the socket on exec()
  211. fcntl(sock, F_SETFD, FD_CLOEXEC);
  212. int one = 1;
  213. if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
  214. (const char *)&one, sizeof(one)) < 0) {
  215. int e = errorNumber;
  216. closesocket(fd);
  217. throw SocketException("unable to create listening socket", e);
  218. }
  219. #endif
  220. // - Bind it to the desired port
  221. struct sockaddr_in addr;
  222. memset(&addr, 0, sizeof(addr));
  223. addr.sin_family = AF_INET;
  224. addr.sin_port = htons(port);
  225. if (localhostOnly)
  226. addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
  227. else
  228. addr.sin_addr.s_addr = htonl(INADDR_ANY);
  229. if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
  230. int e = errorNumber;
  231. closesocket(fd);
  232. throw SocketException("unable to bind listening socket", e);
  233. }
  234. // - Set it to be a listening socket
  235. if (listen(fd, 5) < 0) {
  236. int e = errorNumber;
  237. closesocket(fd);
  238. throw SocketException("unable to set socket to listening mode", e);
  239. }
  240. }
  241. TcpListener::~TcpListener() {
  242. if (closeFd) closesocket(fd);
  243. }
  244. void TcpListener::shutdown()
  245. {
  246. #ifdef WIN32
  247. closesocket(getFd());
  248. #else
  249. ::shutdown(getFd(), 2);
  250. #endif
  251. }
  252. Socket*
  253. TcpListener::accept() {
  254. int new_sock = -1;
  255. // Accept an incoming connection
  256. if ((new_sock = ::accept(fd, 0, 0)) < 0)
  257. throw SocketException("unable to accept new connection", errorNumber);
  258. #ifndef WIN32
  259. // - By default, close the socket on exec()
  260. fcntl(new_sock, F_SETFD, FD_CLOEXEC);
  261. #endif
  262. // Disable Nagle's algorithm
  263. int one = 1;
  264. if (setsockopt(new_sock, IPPROTO_TCP, TCP_NODELAY,
  265. (char *)&one, sizeof(one)) < 0) {
  266. int e = errorNumber;
  267. closesocket(new_sock);
  268. throw SocketException("unable to setsockopt TCP_NODELAY", e);
  269. }
  270. // Create the socket object & check connection is allowed
  271. TcpSocket* s = new TcpSocket(new_sock);
  272. if (filter && !filter->verifyConnection(s)) {
  273. delete s;
  274. return 0;
  275. }
  276. return s;
  277. }
  278. void TcpListener::getMyAddresses(std::list<char*>* result) {
  279. const hostent* addrs = gethostbyname(0);
  280. if (addrs == 0)
  281. throw rdr::SystemException("gethostbyname", errorNumber);
  282. if (addrs->h_addrtype != AF_INET)
  283. throw rdr::Exception("getMyAddresses: bad family");
  284. for (int i=0; addrs->h_addr_list[i] != 0; i++) {
  285. const char* addrC = inet_ntoa(*((struct in_addr*)addrs->h_addr_list[i]));
  286. char* addr = new char[strlen(addrC)+1];
  287. strcpy(addr, addrC);
  288. result->push_back(addr);
  289. }
  290. }
  291. int TcpListener::getMyPort() {
  292. return TcpSocket::getSockPort(getFd());
  293. }
  294. TcpFilter::TcpFilter(const char* spec) {
  295. rfb::CharArray tmp;
  296. tmp.buf = rfb::strDup(spec);
  297. while (tmp.buf) {
  298. rfb::CharArray first;
  299. rfb::strSplit(tmp.buf, ',', &first.buf, &tmp.buf);
  300. if (strlen(first.buf))
  301. filter.push_back(parsePattern(first.buf));
  302. }
  303. }
  304. TcpFilter::~TcpFilter() {
  305. }
  306. static bool
  307. patternMatchIP(const TcpFilter::Pattern& pattern, const char* value) {
  308. unsigned long address = inet_addr(value);
  309. if (address == INADDR_NONE) return false;
  310. return ((pattern.address & pattern.mask) == (address & pattern.mask));
  311. }
  312. bool
  313. TcpFilter::verifyConnection(Socket* s) {
  314. rfb::CharArray name;
  315. name.buf = s->getPeerAddress();
  316. std::list<TcpFilter::Pattern>::iterator i;
  317. for (i=filter.begin(); i!=filter.end(); i++) {
  318. if (patternMatchIP(*i, name.buf)) {
  319. switch ((*i).action) {
  320. case Accept:
  321. vlog.debug("ACCEPT %s", name.buf);
  322. return true;
  323. case Query:
  324. vlog.debug("QUERY %s", name.buf);
  325. return queryUserAcceptConnection(s);
  326. case Reject:
  327. vlog.debug("REJECT %s", name.buf);
  328. return false;
  329. }
  330. }
  331. }
  332. vlog.debug("[REJECT] %s", name.buf);
  333. return false;
  334. }
  335. TcpFilter::Pattern TcpFilter::parsePattern(const char* p) {
  336. TcpFilter::Pattern pattern;
  337. bool expandMask = false;
  338. rfb::CharArray addr, mask;
  339. if (rfb::strSplit(&p[1], '/', &addr.buf, &mask.buf)) {
  340. if (rfb::strContains(mask.buf, '.')) {
  341. pattern.mask = inet_addr(mask.buf);
  342. } else {
  343. pattern.mask = atoi(mask.buf);
  344. expandMask = true;
  345. }
  346. } else {
  347. pattern.mask = 32;
  348. expandMask = true;
  349. }
  350. if (expandMask) {
  351. unsigned long expanded = 0;
  352. // *** check endianness!
  353. for (int i=0; i<(int)pattern.mask; i++)
  354. expanded |= 1<<(31-i);
  355. pattern.mask = htonl(expanded);
  356. }
  357. pattern.address = inet_addr(addr.buf) & pattern.mask;
  358. if ((pattern.address == INADDR_NONE) ||
  359. (pattern.address == 0)) pattern.mask = 0;
  360. switch(p[0]) {
  361. case '+': pattern.action = TcpFilter::Accept; break;
  362. case '-': pattern.action = TcpFilter::Reject; break;
  363. case '?': pattern.action = TcpFilter::Query; break;
  364. };
  365. return pattern;
  366. }
  367. char* TcpFilter::patternToStr(const TcpFilter::Pattern& p) {
  368. in_addr tmp;
  369. rfb::CharArray addr, mask;
  370. tmp.s_addr = p.address;
  371. addr.buf = rfb::strDup(inet_ntoa(tmp));
  372. tmp.s_addr = p.mask;
  373. mask.buf = rfb::strDup(inet_ntoa(tmp));
  374. char* result = new char[strlen(addr.buf)+1+strlen(mask.buf)+1+1];
  375. switch (p.action) {
  376. case Accept: result[0] = '+'; break;
  377. case Reject: result[0] = '-'; break;
  378. case Query: result[0] = '?'; break;
  379. };
  380. result[1] = 0;
  381. strcat(result, addr.buf);
  382. strcat(result, "/");
  383. strcat(result, mask.buf);
  384. return result;
  385. }