SNI-vhost-matching-fallback-to-wildcard
authorAndy Green <andy@warmcat.com>
Mon, 11 Jul 2016 01:56:56 +0000 (09:56 +0800)
committerAndy Green <andy@warmcat.com>
Mon, 11 Jul 2016 01:56:56 +0000 (09:56 +0800)
README.coding.md
lib/server.c

index 733508d7a87664083b5ddf229baf998c949dc199..84157646de3a089b8e5753d3856d25dd84a23a5e 100644 (file)
@@ -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
 ------------------------------
 
index fd373b1ec7d16f606ddc5e29adf058ca9919d64d..389d809a3d6eacc01c9d6879380d3a49a79bf373 100644 (file)
@@ -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) {