diff --git a/README.coding.md b/README.coding.md index 733508d7..84157646 100644 --- a/README.coding.md +++ b/README.coding.md @@ -497,6 +497,25 @@ There are some new members but mainly it's stuff you used to set at context creation time. +How lws matches hostname or SNI to a vhost +------------------------------------------ + +LWS first strips any trailing :port number. + +Then it tries to find an exact name match for a vhost listening on the correct +port, ie, if SNI or the Host: header provided abc.com:1234, it will match on a +vhost named abc.com that is listening on port 1234. + +If there is no exact match, lws will consider wildcard matches, for example +if cats.abc.com:1234 is provided by the client by SNI or Host: header, it will +accept a vhost "abc.com" listening on port 1234. If there was a better, exact, +match, it will have been chosen in preference to this. + +Connections with SSL will still have the client go on to check the +certificate allows wildcards and error out if not. + + + Using lws v2 mounts on a vhost ------------------------------ diff --git a/lib/server.c b/lib/server.c index fd373b1e..389d809a 100644 --- a/lib/server.c +++ b/lib/server.c @@ -179,16 +179,48 @@ struct lws_vhost * lws_select_vhost(struct lws_context *context, int port, const char *servername) { struct lws_vhost *vhost = context->vhost_list; + const char *p; + int n, m, colon; + + n = strlen(servername); + colon = n; + p = strchr(servername, ':'); + if (p) + colon = p - servername; + + /* first try exact matches */ while (vhost) { if (port == vhost->listen_port && - !strcmp(vhost->name, servername)) { + !strncmp(vhost->name, servername, colon)) { lwsl_info("SNI: Found: %s\n", servername); return vhost; } vhost = vhost->vhost_next; } + /* + * if no exact matches, try matching *.vhost-name + * unintentional matches are possible but resolve to x.com for *.x.com + * which is reasonable. If exact match exists we already chose it and + * never reach here. SSL will still fail it if the cert doesn't allow + * *.x.com. + */ + + vhost = context->vhost_list; + while (vhost) { + m = strlen(vhost->name); + if (port == vhost->listen_port && + m <= (colon - 2) && + servername[colon - m - 1] == '.' && + !strncmp(vhost->name, servername + colon - m, m)) { + lwsl_info("SNI: Found %s on wildcard: %s\n", + servername, vhost->name); + return vhost; + } + vhost = vhost->vhost_next; + } + return NULL; } @@ -807,7 +839,8 @@ lws_handshake_server(struct lws *wsi, unsigned char **buf, size_t len) if (vhost) wsi->vhost = vhost; - } + } else + lwsl_info("no host\n"); wsi->vhost->trans++; if (!wsi->conn_stat_done) {