From 73e0c62b4c8dc7eaed202deb2c867d69cabb2a4f Mon Sep 17 00:00:00 2001 From: Steve English Date: Tue, 28 Aug 2012 14:13:25 +0100 Subject: [PATCH 1/3] Don't require Sec-WebSocket-Protocol header. RFC 6455 11.3.4 says this header MAY be used, so allow connections without it. --- other/websocket.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/other/websocket.c b/other/websocket.c index c365409..113256d 100644 --- a/other/websocket.c +++ b/other/websocket.c @@ -475,12 +475,17 @@ int parse_handshake(ws_ctx_t *ws_ctx, char *handshake) { strncpy(headers->connection, start, end-start); headers->connection[end-start] = '\0'; + //RFC 6455 11.3.4 - Sec-WebSocket-Protocol MAY appear multiple times + //in a request. Or it may not appear at all. start = strstr(handshake, "\r\nSec-WebSocket-Protocol: "); - if (!start) { return 0; } - start += 26; - end = strstr(start, "\r\n"); - strncpy(headers->protocols, start, end-start); - headers->protocols[end-start] = '\0'; + if (start) { + start += 26; + end = strstr(start, "\r\n"); + strncpy(headers->protocols, start, end-start); + headers->protocols[end-start] = '\0'; + } else { + headers->protocols[0] = '\0'; + } } else { // Hixie 75 or 76 ws_ctx->hybi = 0; From b5eda78e76a9289378c3d382a46bc393dc2c505d Mon Sep 17 00:00:00 2001 From: Steve English Date: Tue, 28 Aug 2012 14:14:59 +0100 Subject: [PATCH 2/3] Dump status messages to stderr. Stdout may be used for communication with a source process. --- other/websocket.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/other/websocket.h b/other/websocket.h index 7da5275..499aaab 100644 --- a/other/websocket.h +++ b/other/websocket.h @@ -79,6 +79,6 @@ ssize_t ws_send(ws_ctx_t *ctx, const void *buf, size_t len); fprintf(stream, __VA_ARGS__); \ } -#define handler_msg(...) gen_handler_msg(stdout, __VA_ARGS__); +#define handler_msg(...) gen_handler_msg(stderr, __VA_ARGS__); #define handler_emsg(...) gen_handler_msg(stderr, __VA_ARGS__); From af80e4abb76d329657a3d53438ea04bed0c04886 Mon Sep 17 00:00:00 2001 From: Steve English Date: Tue, 28 Aug 2012 14:15:31 +0100 Subject: [PATCH 3/3] Allow using stdin/stdout as a target. If no target is specified then stream data from stdin/stdout to the client. Only allow one client to connect at a time. --- other/websocket.c | 7 +++ other/websocket.h | 1 + other/websockify.c | 120 +++++++++++++++++++++++++++------------------ 3 files changed, 79 insertions(+), 49 deletions(-) diff --git a/other/websocket.c b/other/websocket.c index 113256d..8ccaf6a 100644 --- a/other/websocket.c +++ b/other/websocket.c @@ -788,6 +788,13 @@ void start_server() { break; // Child process exits } else { // parent process settings.handler_id += 1; + + if (settings.one_at_a_time) { + //Block on child process exiting + handler_msg("Waiting for child to finish\n"); + wait(pid); + handler_msg("Child finished\n"); + } } } if (pid == 0) { diff --git a/other/websocket.h b/other/websocket.h index 499aaab..df87413 100644 --- a/other/websocket.h +++ b/other/websocket.h @@ -62,6 +62,7 @@ typedef struct { int ssl_only; int daemon; int run_once; + int one_at_a_time; } settings_t; diff --git a/other/websockify.c b/other/websockify.c index 4032171..4ce14f8 100644 --- a/other/websockify.c +++ b/other/websockify.c @@ -32,7 +32,7 @@ Traffic Legend:\n\ "; char USAGE[] = "Usage: [options] " \ - "[source_addr:]source_port target_addr:target_port\n\n" \ + "[source_addr:]source_port [target_addr:target_port]\n\n" \ " --verbose|-v verbose messages and per frame traffic\n" \ " --daemon|-D become a daemon (background process)\n" \ " --cert CERT SSL certificate file\n" \ @@ -44,13 +44,14 @@ char USAGE[] = "Usage: [options] " \ fprintf(stderr, fmt , ## args); \ exit(1); +int target_local; char target_host[256]; int target_port; extern pipe_error; extern settings_t settings; -void do_proxy(ws_ctx_t *ws_ctx, int target) { +void do_proxy(ws_ctx_t *ws_ctx, int target_read, int target_write) { fd_set rlist, wlist, elist; struct timeval tv; int i, maxfd, client = ws_ctx->sockfd; @@ -61,7 +62,8 @@ void do_proxy(ws_ctx_t *ws_ctx, int target) { tout_start = tout_end = cout_start = cout_end; tin_start = tin_end = 0; - maxfd = client > target ? client+1 : target+1; + maxfd = client > target_read ? client+1 : target_read+1; + maxfd = maxfd > target_write ? maxfd : target_write+1; while (1) { tv.tv_sec = 1; @@ -72,18 +74,19 @@ void do_proxy(ws_ctx_t *ws_ctx, int target) { FD_ZERO(&elist); FD_SET(client, &elist); - FD_SET(target, &elist); + FD_SET(target_read, &elist); + if( target_write != target_read ) { FD_SET(target_write, &elist); } if (tout_end == tout_start) { // Nothing queued for target, so read from client FD_SET(client, &rlist); } else { // Data queued for target, so write to it - FD_SET(target, &wlist); + FD_SET(target_write, &wlist); } if (cout_end == cout_start) { // Nothing queued for client, so read from target - FD_SET(target, &rlist); + FD_SET(target_read, &rlist); } else { // Data queued for client, so write to it FD_SET(client, &wlist); @@ -92,8 +95,12 @@ void do_proxy(ws_ctx_t *ws_ctx, int target) { ret = select(maxfd, &rlist, &wlist, &elist, &tv); if (pipe_error) { break; } - if (FD_ISSET(target, &elist)) { - handler_emsg("target exception\n"); + if (FD_ISSET(target_read, &elist)) { + handler_emsg("target read exception\n"); + break; + } + if (FD_ISSET(target_write, &elist)) { + handler_emsg("target write exception\n"); break; } if (FD_ISSET(client, &elist)) { @@ -109,9 +116,10 @@ void do_proxy(ws_ctx_t *ws_ctx, int target) { continue; } - if (FD_ISSET(target, &wlist)) { + if (FD_ISSET(target_write, &wlist)) { len = tout_end-tout_start; - bytes = send(target, ws_ctx->tout_buf + tout_start, len, 0); + if( target_local ) { bytes = write(target_write, ws_ctx->tout_buf + tout_start, len); } + else { bytes = send(target_write, ws_ctx->tout_buf + tout_start, len, 0); } if (pipe_error) { break; } if (bytes < 0) { handler_emsg("target connection error: %s\n", @@ -145,8 +153,9 @@ void do_proxy(ws_ctx_t *ws_ctx, int target) { } } - if (FD_ISSET(target, &rlist)) { - bytes = recv(target, ws_ctx->cin_buf, DBUFSIZE , 0); + if (FD_ISSET(target_read, &rlist)) { + if( target_local ) { bytes = read(target_read, ws_ctx->cin_buf, DBUFSIZE); } + else { bytes = recv(target_read, ws_ctx->cin_buf, DBUFSIZE , 0); } if (pipe_error) { break; } if (bytes <= 0) { handler_emsg("target closed connection\n"); @@ -236,39 +245,43 @@ void proxy_handler(ws_ctx_t *ws_ctx) { int tsock = 0; struct sockaddr_in taddr; - handler_msg("connecting to: %s:%d\n", target_host, target_port); + if (target_local) { + do_proxy( ws_ctx, fileno(stdin), fileno(stdout) ); + } else { + handler_msg("connecting to: %s:%d\n", target_host, target_port); - tsock = socket(AF_INET, SOCK_STREAM, 0); - if (tsock < 0) { - handler_emsg("Could not create target socket: %s\n", - strerror(errno)); - return; - } - bzero((char *) &taddr, sizeof(taddr)); - taddr.sin_family = AF_INET; - taddr.sin_port = htons(target_port); + tsock = socket(AF_INET, SOCK_STREAM, 0); + if (tsock < 0) { + handler_emsg("Could not create target socket: %s\n", + strerror(errno)); + return; + } + bzero((char *) &taddr, sizeof(taddr)); + taddr.sin_family = AF_INET; + taddr.sin_port = htons(target_port); - /* Resolve target address */ - if (resolve_host(&taddr.sin_addr, target_host) < -1) { - handler_emsg("Could not resolve target address: %s\n", - strerror(errno)); - } + /* Resolve target address */ + if (resolve_host(&taddr.sin_addr, target_host) < -1) { + handler_emsg("Could not resolve target address: %s\n", + strerror(errno)); + } - if (connect(tsock, (struct sockaddr *) &taddr, sizeof(taddr)) < 0) { - handler_emsg("Could not connect to target: %s\n", - strerror(errno)); + if (connect(tsock, (struct sockaddr *) &taddr, sizeof(taddr)) < 0) { + handler_emsg("Could not connect to target: %s\n", + strerror(errno)); + close(tsock); + return; + } + + if ((settings.verbose) && (! settings.daemon)) { + printf("%s", traffic_legend); + } + + do_proxy(ws_ctx, tsock, tsock); + + shutdown(tsock, SHUT_RDWR); close(tsock); - return; } - - if ((settings.verbose) && (! settings.daemon)) { - printf("%s", traffic_legend); - } - - do_proxy(ws_ctx, tsock); - - shutdown(tsock, SHUT_RDWR); - close(tsock); } int main(int argc, char *argv[]) @@ -336,7 +349,7 @@ int main(int argc, char *argv[]) settings.daemon = daemon; settings.run_once = run_once; - if ((argc-optind) != 2) { + if((argc-optind) == 0 ) { usage("Invalid number of arguments\n"); } @@ -353,15 +366,24 @@ int main(int argc, char *argv[]) usage("Could not parse listen_port\n"); } - found = strstr(argv[optind], ":"); - if (found) { - memcpy(target_host, argv[optind], found-argv[optind]); - target_port = strtol(found+1, NULL, 10); + if ((argc-optind) == 1) { + //Connect to target on a socket + target_local = 0; + found = strstr(argv[optind], ":"); + if (found) { + memcpy(target_host, argv[optind], found-argv[optind]); + target_port = strtol(found+1, NULL, 10); + } else { + usage("Target argument must be host:port\n"); + } + if (target_port == 0) { + usage("Could not parse target port\n"); + } + settings.one_at_a_time = 0; } else { - usage("Target argument must be host:port\n"); - } - if (target_port == 0) { - usage("Could not parse target port\n"); + //Use normal io for target + target_local = 1; + settings.one_at_a_time = 1; } if (ssl_only) {