wsproxy.c 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. /*
  2. * A WebSocket to TCP socket proxy with support for "wss://" encryption.
  3. * Copyright 2010 Joel Martin
  4. * Licensed under LGPL version 3 (see docs/LICENSE.LGPL-3)
  5. *
  6. * You can make a cert/key with openssl using:
  7. * openssl req -new -x509 -days 365 -nodes -out self.pem -keyout self.pem
  8. * as taken from http://docs.python.org/dev/library/ssl.html#certificates
  9. */
  10. #include <stdio.h>
  11. #include <errno.h>
  12. #include <limits.h>
  13. #include <getopt.h>
  14. #include <sys/socket.h>
  15. #include <netinet/in.h>
  16. #include <netdb.h>
  17. #include <sys/select.h>
  18. #include <fcntl.h>
  19. #include <sys/stat.h>
  20. #include "websocket.h"
  21. char traffic_legend[] = "\n\
  22. Traffic Legend:\n\
  23. } - Client receive\n\
  24. }. - Client receive partial\n\
  25. { - Target receive\n\
  26. \n\
  27. > - Target send\n\
  28. >. - Target send partial\n\
  29. < - Client send\n\
  30. <. - Client send partial\n\
  31. ";
  32. char USAGE[] = "Usage: [options] " \
  33. "[source_addr:]source_port target_addr:target_port\n\n" \
  34. " --cert CERT load CERT as SSL certificate\n" \
  35. " --foreground|-f run in the foreground\n" \
  36. " --ssl-only disallow non-SSL connections";
  37. #define usage(fmt, args...) \
  38. fprintf(stderr, "%s\n\n", USAGE); \
  39. fprintf(stderr, fmt , ## args); \
  40. exit(1);
  41. char target_host[256];
  42. int target_port;
  43. extern pipe_error;
  44. extern settings_t settings;
  45. extern char *tbuf, *cbuf, *tbuf_tmp, *cbuf_tmp;
  46. extern unsigned int bufsize, dbufsize;
  47. void do_proxy(ws_ctx_t *ws_ctx, int target) {
  48. fd_set rlist, wlist, elist;
  49. struct timeval tv;
  50. int i, maxfd, client = ws_ctx->sockfd;
  51. unsigned int tstart, tend, cstart, cend, ret;
  52. ssize_t len, bytes;
  53. tstart = tend = cstart = cend = 0;
  54. maxfd = client > target ? client+1 : target+1;
  55. while (1) {
  56. tv.tv_sec = 1;
  57. tv.tv_usec = 0;
  58. FD_ZERO(&rlist);
  59. FD_ZERO(&wlist);
  60. FD_ZERO(&elist);
  61. FD_SET(client, &elist);
  62. FD_SET(target, &elist);
  63. if (tend == tstart) {
  64. // Nothing queued for target, so read from client
  65. FD_SET(client, &rlist);
  66. } else {
  67. // Data queued for target, so write to it
  68. FD_SET(target, &wlist);
  69. }
  70. if (cend == cstart) {
  71. // Nothing queued for client, so read from target
  72. FD_SET(target, &rlist);
  73. } else {
  74. // Data queued for client, so write to it
  75. FD_SET(client, &wlist);
  76. }
  77. ret = select(maxfd, &rlist, &wlist, &elist, &tv);
  78. if (pipe_error) { break; }
  79. if (FD_ISSET(target, &elist)) {
  80. handler_emsg("target exception\n");
  81. break;
  82. }
  83. if (FD_ISSET(client, &elist)) {
  84. handler_emsg("client exception\n");
  85. break;
  86. }
  87. if (ret == -1) {
  88. handler_emsg("select(): %s\n", strerror(errno));
  89. break;
  90. } else if (ret == 0) {
  91. //handler_emsg("select timeout\n");
  92. continue;
  93. }
  94. if (FD_ISSET(target, &wlist)) {
  95. len = tend-tstart;
  96. bytes = send(target, tbuf + tstart, len, 0);
  97. if (pipe_error) { break; }
  98. if (bytes < 0) {
  99. handler_emsg("target connection error: %s\n",
  100. strerror(errno));
  101. break;
  102. }
  103. tstart += bytes;
  104. if (tstart >= tend) {
  105. tstart = tend = 0;
  106. traffic(">");
  107. } else {
  108. traffic(">.");
  109. }
  110. }
  111. if (FD_ISSET(client, &wlist)) {
  112. len = cend-cstart;
  113. bytes = ws_send(ws_ctx, cbuf + cstart, len);
  114. if (pipe_error) { break; }
  115. if (len < 3) {
  116. handler_emsg("len: %d, bytes: %d: %d\n", len, bytes, *(cbuf + cstart));
  117. }
  118. cstart += bytes;
  119. if (cstart >= cend) {
  120. cstart = cend = 0;
  121. traffic("<");
  122. } else {
  123. traffic("<.");
  124. }
  125. }
  126. if (FD_ISSET(target, &rlist)) {
  127. bytes = recv(target, cbuf_tmp, dbufsize , 0);
  128. if (pipe_error) { break; }
  129. if (bytes <= 0) {
  130. handler_emsg("target closed connection\n");
  131. break;
  132. }
  133. cstart = 0;
  134. cend = encode(cbuf_tmp, bytes, cbuf, bufsize);
  135. /*
  136. printf("encoded: ");
  137. for (i=0; i< cend; i++) {
  138. printf("%u,", (unsigned char) *(cbuf+i));
  139. }
  140. printf("\n");
  141. */
  142. if (cend < 0) {
  143. handler_emsg("encoding error\n");
  144. break;
  145. }
  146. traffic("{");
  147. }
  148. if (FD_ISSET(client, &rlist)) {
  149. bytes = ws_recv(ws_ctx, tbuf_tmp, bufsize-1);
  150. if (pipe_error) { break; }
  151. if (bytes <= 0) {
  152. handler_emsg("client closed connection\n");
  153. break;
  154. } else if ((bytes == 2) &&
  155. (tbuf_tmp[0] == '\xff') &&
  156. (tbuf_tmp[1] == '\x00')) {
  157. handler_emsg("client sent orderly close frame\n");
  158. break;
  159. }
  160. /*
  161. printf("before decode: ");
  162. for (i=0; i< bytes; i++) {
  163. printf("%u,", (unsigned char) *(tbuf_tmp+i));
  164. }
  165. printf("\n");
  166. */
  167. len = decode(tbuf_tmp, bytes, tbuf, bufsize-1);
  168. /*
  169. printf("decoded: ");
  170. for (i=0; i< len; i++) {
  171. printf("%u,", (unsigned char) *(tbuf+i));
  172. }
  173. printf("\n");
  174. */
  175. if (len < 0) {
  176. handler_emsg("decoding error\n");
  177. break;
  178. }
  179. traffic("}");
  180. tstart = 0;
  181. tend = len;
  182. }
  183. }
  184. }
  185. void proxy_handler(ws_ctx_t *ws_ctx) {
  186. int tsock = 0;
  187. struct sockaddr_in taddr;
  188. handler_msg("connecting to: %s:%d\n", target_host, target_port);
  189. tsock = socket(AF_INET, SOCK_STREAM, 0);
  190. if (tsock < 0) {
  191. handler_emsg("Could not create target socket: %s\n",
  192. strerror(errno));
  193. return;
  194. }
  195. bzero((char *) &taddr, sizeof(taddr));
  196. taddr.sin_family = AF_INET;
  197. taddr.sin_port = htons(target_port);
  198. /* Resolve target address */
  199. if (resolve_host(&taddr.sin_addr, target_host) < -1) {
  200. handler_emsg("Could not resolve target address: %s\n",
  201. strerror(errno));
  202. }
  203. if (connect(tsock, (struct sockaddr *) &taddr, sizeof(taddr)) < 0) {
  204. handler_emsg("Could not connect to target: %s\n",
  205. strerror(errno));
  206. close(tsock);
  207. return;
  208. }
  209. if ((settings.verbose) && (! settings.daemon)) {
  210. printf("%s", traffic_legend);
  211. }
  212. do_proxy(ws_ctx, tsock);
  213. close(tsock);
  214. }
  215. int main(int argc, char *argv[])
  216. {
  217. int fd, c, option_index = 0;
  218. static int ssl_only = 0, foreground = 0, verbose = 0;
  219. char *found;
  220. static struct option long_options[] = {
  221. {"verbose", no_argument, &verbose, 'v'},
  222. {"ssl-only", no_argument, &ssl_only, 1 },
  223. {"foreground", no_argument, &foreground, 'f'},
  224. /* ---- */
  225. {"cert", required_argument, 0, 'c'},
  226. {0, 0, 0, 0}
  227. };
  228. settings.cert = realpath("self.pem", NULL);
  229. while (1) {
  230. c = getopt_long (argc, argv, "vfc:",
  231. long_options, &option_index);
  232. /* Detect the end */
  233. if (c == -1) { break; }
  234. switch (c) {
  235. case 0:
  236. break; // ignore
  237. case 1:
  238. break; // ignore
  239. case 'v':
  240. verbose = 1;
  241. break;
  242. case 'f':
  243. foreground = 1;
  244. break;
  245. case 'r':
  246. if ((fd = open(optarg, O_CREAT,
  247. S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) < -1) {
  248. usage("Could not access %s\n", optarg);
  249. }
  250. close(fd);
  251. break;
  252. case 'c':
  253. settings.cert = realpath(optarg, NULL);
  254. if (! settings.cert) {
  255. usage("No cert file at %s\n", optarg);
  256. }
  257. break;
  258. default:
  259. usage("");
  260. }
  261. }
  262. settings.verbose = verbose;
  263. settings.ssl_only = ssl_only;
  264. settings.daemon = foreground ? 0: 1;
  265. if ((argc-optind) != 2) {
  266. usage("Invalid number of arguments\n");
  267. }
  268. found = strstr(argv[optind], ":");
  269. if (found) {
  270. memcpy(settings.listen_host, argv[optind], found-argv[optind]);
  271. settings.listen_port = strtol(found+1, NULL, 10);
  272. } else {
  273. settings.listen_host[0] = '\0';
  274. settings.listen_port = strtol(argv[optind], NULL, 10);
  275. }
  276. optind++;
  277. if (settings.listen_port == 0) {
  278. usage("Could not parse listen_port\n");
  279. }
  280. found = strstr(argv[optind], ":");
  281. if (found) {
  282. memcpy(target_host, argv[optind], found-argv[optind]);
  283. target_port = strtol(found+1, NULL, 10);
  284. } else {
  285. usage("Target argument must be host:port\n");
  286. }
  287. if (target_port == 0) {
  288. usage("Could not parse target port\n");
  289. }
  290. if (ssl_only) {
  291. printf("cert: %s\n", settings.cert);
  292. if (!settings.cert || !access(settings.cert)) {
  293. usage("SSL only and cert file not found\n");
  294. }
  295. }
  296. //printf(" verbose: %d\n", settings.verbose);
  297. //printf(" ssl_only: %d\n", settings.ssl_only);
  298. //printf(" daemon: %d\n", settings.daemon);
  299. //printf(" cert: %s\n", settings.cert);
  300. settings.handler = proxy_handler;
  301. start_server();
  302. free(tbuf);
  303. free(cbuf);
  304. free(tbuf_tmp);
  305. free(cbuf_tmp);
  306. }