From: Shuanglei Tao Date: Mon, 10 Oct 2016 15:33:00 +0000 (+0800) Subject: Add support for the --check-origin option X-Git-Url: http://git.prime8.dev/?a=commitdiff_plain;h=e714cc87187528d2964583adc6ce387153d17ea5;p=ttyd.git Add support for the --check-origin option requires libwebsockets 1.7.0+ since lws_parse_uri is available from 1.7.0 --- diff --git a/CMakeLists.txt b/CMakeLists.txt index c6fc9b2..161f238 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,7 +9,7 @@ endif() project(ttyd) -set(LIBWEBSOCKETS_MIN_VERSION 1.6) +set(LIBWEBSOCKETS_MIN_VERSION 1.7.0) set(SOURCE_FILES src/server.c src/http.c src/protocol.c src/utils.c) find_package(OpenSSL REQUIRED) diff --git a/README.md b/README.md index e44aa53..d4e131d 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,7 @@ OPTIONS: --signal, -s Signal to send to the command when exit it (default: SIGHUP) --reconnect, -r Time to reconnect for the client in seconds (default: 10) --readonly, -R Do not allow clients to write to the TTY + --check-origin, -O Do not allow websocket connection from different origin --once, -o Accept only one client and exit on disconnection --ssl, -S Enable ssl --ssl-cert, -C Ssl certificate file path diff --git a/src/index.html b/src/index.html index 25e5c63..6e1f6a9 100644 --- a/src/index.html +++ b/src/index.html @@ -616,11 +616,15 @@ term.installKeyboard(); }; - term.decorate(document.getElementById("terminal")); + var termContainer = document.getElementById('terminal'); + while (termContainer.firstChild) { + termContainer.removeChild(termContainer.firstChild); + } + term.decorate(termContainer); }; ws.onmessage = function(event) { - data = event.data.slice(1); + var data = event.data.slice(1); switch(event.data[0]) { case '0': term.io.writeUTF8(window.atob(data)); @@ -662,6 +666,7 @@ var errorNode = document.createElement('div'); errorNode.style.cssText = [ "color: red", + "background-color: white", "font-size: x-large", "opacity: 0.75", "text-align: center", @@ -670,11 +675,10 @@ "border: 0.1em dotted #ccc" ].join(";"); errorNode.textContent = "Websocket handshake failed!"; - document.getElementById("terminal").appendChild(errorNode); + document.getElementById('terminal').appendChild(errorNode); }; }; - var sendPing = function(ws) { ws.send("1"); }; diff --git a/src/protocol.c b/src/protocol.c index 5e68dcc..d7b5c6f 100644 --- a/src/protocol.c +++ b/src/protocol.c @@ -63,6 +63,29 @@ parse_window_size(const char *json) { return size; } +bool +check_host_origin(struct lws *wsi) { + int origin_length = lws_hdr_total_length(wsi, WSI_TOKEN_ORIGIN); + char buf[origin_length + 1]; + memset(buf, 0, sizeof(buf)); + int len = lws_hdr_copy(wsi, buf, sizeof(buf), WSI_TOKEN_ORIGIN); + if (len > 0) { + const char *prot, *address, *path; + int port; + if (lws_parse_uri(buf, &prot, &address, &port, &path)) + return false; + sprintf(buf, "%s:%d", address, port); + int host_length = lws_hdr_total_length(wsi, WSI_TOKEN_HOST); + if (host_length != strlen(buf)) + return false; + char host_buf[host_length + 1]; + memset(host_buf, 0, sizeof(host_buf)); + len = lws_hdr_copy(wsi, host_buf, sizeof(host_buf), WSI_TOKEN_HOST); + return len > 0 && strcasecmp(buf, host_buf) == 0; + } + return false; +} + void tty_client_destroy(struct tty_client *client) { if (client->exit || client->pid <= 0) @@ -164,6 +187,10 @@ callback_tty(struct lws *wsi, enum lws_callback_reasons reason, lwsl_notice("refuse to serve new client due to the --once option.\n"); return -1; } + if (server->check_origin && !check_host_origin(wsi)) { + lwsl_notice("refuse to serve new client from different origin due to the --check-origin option.\n"); + return -1; + } break; case LWS_CALLBACK_ESTABLISHED: client->exit = false; diff --git a/src/server.c b/src/server.c index a401409..0e4a96f 100644 --- a/src/server.c +++ b/src/server.c @@ -34,13 +34,14 @@ static const struct option options[] = { {"ssl-key", required_argument, NULL, 'K'}, {"ssl-ca", required_argument, NULL, 'A'}, {"readonly", no_argument, NULL, 'R'}, + {"check-origin", no_argument, NULL, 'O'}, {"once", no_argument, NULL, 'o'}, {"debug", required_argument, NULL, 'd'}, {"version", no_argument, NULL, 'v'}, {"help", no_argument, NULL, 'h'}, {NULL, 0, 0, 0} }; -static const char *opt_string = "p:i:c:u:g:s:r:aSC:K:A:Rod:vh"; +static const char *opt_string = "p:i:c:u:g:s:r:aSC:K:A:ROod:vh"; void print_help() { fprintf(stderr, "ttyd is a tool for sharing terminal over the web\n\n" @@ -57,6 +58,7 @@ void print_help() { " --signal, -s Signal to send to the command when exit it (default: SIGHUP)\n" " --reconnect, -r Time to reconnect for the client in seconds (default: 10)\n" " --readonly, -R Do not allow clients to write to the TTY\n" + " --check-origin, -O Do not allow websocket connection from different origin\n" " --once, -o Accept only one client and exit on disconnection\n" " --ssl, -S Enable ssl\n" " --ssl-cert, -C Ssl certificate file path\n" @@ -207,6 +209,9 @@ main(int argc, char **argv) { case 'R': server->readonly = true; break; + case 'O': + server->check_origin = true; + break; case 'o': server->once = true; break; @@ -327,6 +332,8 @@ main(int argc, char **argv) { lwsl_notice(" start command: %s\n", server->command); lwsl_notice(" reconnect timeout: %ds\n", server->reconnect); lwsl_notice(" close signal: %s (%d)\n", server->sig_name, server->sig_code); + if (server->check_origin) + lwsl_notice(" check origin: true\n"); if (server->readonly) lwsl_notice(" readonly: true\n"); if (server->once) diff --git a/src/server.h b/src/server.h index c985b07..2cd52f6 100644 --- a/src/server.h +++ b/src/server.h @@ -72,6 +72,7 @@ struct tty_server { int sig_code; // close signal char *sig_name; // human readable signal string bool readonly; // whether not allow clients to write to the TTY + bool check_origin; // whether allow websocket connection from different origin bool once; // whether accept only one client and exit on disconnection pthread_mutex_t lock; };