diff --git a/lib/roles/h1/ops-h1.c b/lib/roles/h1/ops-h1.c index a90e89a10..c06b92c0f 100644 --- a/lib/roles/h1/ops-h1.c +++ b/lib/roles/h1/ops-h1.c @@ -807,9 +807,18 @@ rops_adoption_bind_h1(struct lws *wsi, int type, const char *vh_prot_name) lws_role_transition(wsi, LWSIFR_SERVER, (type & LWS_ADOPT_ALLOW_SSL) ? LRS_SSL_INIT : LRS_HEADERS, &role_ops_h1); - if (!vh_prot_name) + /* + * We have to bind to h1 as a default even when we're actually going to + * replace it as an h2 bind later. So don't take this seriously if the + * default is disabled (ws upgrade caees properly about it) + */ + + if (!vh_prot_name && wsi->vhost->default_protocol_index < + wsi->vhost->count_protocols) wsi->protocol = &wsi->vhost->protocols[ - wsi->vhost->default_protocol_index]; + wsi->vhost->default_protocol_index]; + else + wsi->protocol = &wsi->vhost->protocols[0]; /* the transport is accepted... give him time to negotiate */ lws_set_timeout(wsi, PENDING_TIMEOUT_ESTABLISH_WITH_SERVER, diff --git a/lib/roles/http/server/lejp-conf.c b/lib/roles/http/server/lejp-conf.c index 005b5c935..d3bec2152 100644 --- a/lib/roles/http/server/lejp-conf.c +++ b/lib/roles/http/server/lejp-conf.c @@ -118,6 +118,8 @@ static const char * const paths_vhosts[] = { "vhosts[].allow-non-tls", "vhosts[].redirect-http", "vhosts[].allow-http-on-https", + + "vhosts[].disable-no-protocol-ws-upgrades", }; enum lejp_vhost_paths { @@ -182,6 +184,8 @@ enum lejp_vhost_paths { LEJPVP_FLAG_ALLOW_NON_TLS, LEJPVP_FLAG_REDIRECT_HTTP, LEJPVP_FLAG_ALLOW_HTTP_ON_HTTPS, + + LEJPVP_FLAG_DISABLE_NO_PROTOCOL_WS_UPGRADES, }; static const char * const parser_errs[] = { @@ -228,6 +232,7 @@ struct jpargs { const char **plugin_dirs; int count_plugin_dirs; + unsigned int reject_ws_with_no_protocol:1; unsigned int enable_client_ssl:1; unsigned int fresh_mount:1; unsigned int any_vhosts:1; @@ -367,6 +372,7 @@ lejp_vhosts_cb(struct lejp_ctx *ctx, char reason) const char *ss; /* set the defaults for this vhost */ + a->reject_ws_with_no_protocol = 0; a->valid = 1; a->head = NULL; a->last = NULL; @@ -502,6 +508,12 @@ lejp_vhosts_cb(struct lejp_ctx *ctx, char reason) } a->any_vhosts = 1; + if (a->reject_ws_with_no_protocol) { + a->reject_ws_with_no_protocol = 0; + + vhost->default_protocol_index = 255; + } + #if defined(LWS_WITH_TLS) if (a->enable_client_ssl) { const char *cert_filepath = @@ -835,6 +847,10 @@ lejp_vhosts_cb(struct lejp_ctx *ctx, char reason) LWS_SERVER_OPTION_ALLOW_HTTP_ON_HTTPS_LISTENER); return 0; + case LEJPVP_FLAG_DISABLE_NO_PROTOCOL_WS_UPGRADES: + a->reject_ws_with_no_protocol = 1; + return 0; + default: return 0; } diff --git a/lib/roles/raw-file/ops-raw-file.c b/lib/roles/raw-file/ops-raw-file.c index 4c9e43a75..6fabae381 100644 --- a/lib/roles/raw-file/ops-raw-file.c +++ b/lib/roles/raw-file/ops-raw-file.c @@ -63,9 +63,14 @@ rops_adoption_bind_raw_file(struct lws *wsi, int type, const char *vh_prot_name) lws_role_transition(wsi, 0, LRS_ESTABLISHED, &role_ops_raw_file); - if (!vh_prot_name) + if (!vh_prot_name) { + if (wsi->vhost->default_protocol_index >= + wsi->vhost->count_protocols) + return 0; + wsi->protocol = &wsi->vhost->protocols[ wsi->vhost->default_protocol_index]; + } return 1; /* bound */ } diff --git a/lib/roles/ws/server-ws.c b/lib/roles/ws/server-ws.c index 79cb6815f..688e81cc9 100644 --- a/lib/roles/ws/server-ws.c +++ b/lib/roles/ws/server-ws.c @@ -323,10 +323,22 @@ lws_process_ws_upgrade(struct lws *wsi) if (!ts.len) { int n = wsi->vhost->default_protocol_index; /* - * some clients only have one protocol and do not send the + * Some clients only have one protocol and do not send the * protocol list header... allow it and match to the vhost's - * default protocol (which itself defaults to zero) + * default protocol (which itself defaults to zero). + * + * Setting the vhost default protocol index to -1 or anything + * more than the actual number of protocols on the vhost causes + * these "no protocol" ws connections to be rejected. */ + + if (n >= wsi->vhost->count_protocols) { + lwsl_notice("%s: rejecting ws upg with no protocol\n", + __func__); + + return 1; + } + lwsl_info("%s: defaulting to prot handler %d\n", __func__, n); lws_bind_protocol(wsi, &wsi->vhost->protocols[n],