diff --git a/README.coding.md b/README.coding.md index aab6d772..5b438397 100644 --- a/README.coding.md +++ b/README.coding.md @@ -534,6 +534,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/doc/html/md_README.coding.html b/doc/html/md_README.coding.html index 997db81f..570e6764 100644 --- a/doc/html/md_README.coding.html +++ b/doc/html/md_README.coding.html @@ -197,6 +197,11 @@ space" as a virtual filesystem that may or may not be backed by a regular filesy
lws_create_vhost() uses the same info struct as lws_create_context(), it ignores members related to context and uses the ones meaningful for vhost (marked with VH in libwebsockets.h).
When you attach the vhost, if the vhost's port already has a listen socket then both vhosts share it and use SNI (is SSL in use) or the Host: header from the client to select the right one. Or if no other vhost already listening the a new listen socket is created.
There are some new members but mainly it's stuff you used to set at context creation time.
+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.
The last argument to lws_create_vhost() lets you associate a linked list of lws_http_mount structures with that vhost's URL 'namespace', in a similar way that unix lets you mount filesystems into areas of your / filesystem how you like and deal with the contents transparently.
The last mount structure should have a NULL mount_next, otherwise it should point to the 'next' mount structure in your list.
diff --git a/lib/server.c b/lib/server.c index 902bf94d..d5272c67 100644 --- a/lib/server.c +++ b/lib/server.c @@ -193,16 +193,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; } @@ -990,7 +1022,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) {