1
0
Fork 0
mirror of https://github.com/warmcat/libwebsockets.git synced 2025-03-09 00:00:04 +01:00

SNI-vhost-matching-fallback-to-wildcard

This commit is contained in:
Andy Green 2016-07-11 09:44:17 +08:00
parent 5ab523ec3f
commit 5f73048d58
3 changed files with 59 additions and 2 deletions

View file

@ -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
------------------------------

View file

@ -197,6 +197,11 @@ space" as a virtual filesystem that may or may not be backed by a regular filesy
<div class="fragment"><div class="line"><a name="l00001"></a><span class="lineno"> 1</span>&#160;LWS_VISIBLE struct lws_vhost *</div><div class="line"><a name="l00002"></a><span class="lineno"> 2</span>&#160;lws_create_vhost(struct lws_context *context,</div><div class="line"><a name="l00003"></a><span class="lineno"> 3</span>&#160; struct lws_context_creation_info *info,</div><div class="line"><a name="l00004"></a><span class="lineno"> 4</span>&#160; struct lws_http_mount *mounts);</div></div><!-- fragment --><p><a class="el" href="group__context-and-vhost.html#ga0c54c667ccd9b8b3dddcd123ca72f87c">lws_create_vhost()</a> uses the same info struct as <a class="el" href="group__context-and-vhost.html#gaf2fff58562caab7510c41eeac85a8648">lws_create_context()</a>, it ignores members related to context and uses the ones meaningful for vhost (marked with VH in <a class="el" href="libwebsockets_8h.html">libwebsockets.h</a>).</p>
<div class="fragment"><div class="line"><a name="l00001"></a><span class="lineno"> 1</span>&#160;struct lws_context_creation_info {</div><div class="line"><a name="l00002"></a><span class="lineno"> 2</span>&#160; int port; /* VH */</div><div class="line"><a name="l00003"></a><span class="lineno"> 3</span>&#160; const char *iface; /* VH */</div><div class="line"><a name="l00004"></a><span class="lineno"> 4</span>&#160; const struct lws_protocols *protocols; /* VH */</div><div class="line"><a name="l00005"></a><span class="lineno"> 5</span>&#160; const struct lws_extension *extensions; /* VH */</div><div class="line"><a name="l00006"></a><span class="lineno"> 6</span>&#160;...</div></div><!-- fragment --><p>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.</p>
<p>There are some new members but mainly it's stuff you used to set at context creation time.</p>
<h2>How lws matches hostname or SNI to a vhost </h2>
<p>LWS first strips any trailing :port number.</p>
<p>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.</p>
<p>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.</p>
<p>Connections with SSL will still have the client go on to check the certificate allows wildcards and error out if not.</p>
<h2>Using lws v2 mounts on a vhost </h2>
<p>The last argument to <a class="el" href="group__context-and-vhost.html#ga0c54c667ccd9b8b3dddcd123ca72f87c">lws_create_vhost()</a> lets you associate a linked list of <a class="el" href="structlws__http__mount.html">lws_http_mount</a> 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.</p>
<div class="fragment"><div class="line"><a name="l00001"></a><span class="lineno"> 1</span>&#160;struct lws_http_mount {</div><div class="line"><a name="l00002"></a><span class="lineno"> 2</span>&#160; struct lws_http_mount *mount_next;</div><div class="line"><a name="l00003"></a><span class="lineno"> 3</span>&#160; const char *mountpoint; /* mountpoint in http pathspace, eg, &quot;/&quot; */</div><div class="line"><a name="l00004"></a><span class="lineno"> 4</span>&#160; const char *origin; /* path to be mounted, eg, &quot;/var/www/warmcat.com&quot; */</div><div class="line"><a name="l00005"></a><span class="lineno"> 5</span>&#160; const char *def; /* default target, eg, &quot;index.html&quot; */</div><div class="line"><a name="l00006"></a><span class="lineno"> 6</span>&#160;</div><div class="line"><a name="l00007"></a><span class="lineno"> 7</span>&#160; struct lws_protocol_vhost_options *cgienv;</div><div class="line"><a name="l00008"></a><span class="lineno"> 8</span>&#160;</div><div class="line"><a name="l00009"></a><span class="lineno"> 9</span>&#160; int cgi_timeout;</div><div class="line"><a name="l00010"></a><span class="lineno"> 10</span>&#160; int cache_max_age;</div><div class="line"><a name="l00011"></a><span class="lineno"> 11</span>&#160;</div><div class="line"><a name="l00012"></a><span class="lineno"> 12</span>&#160; unsigned int cache_reusable:1;</div><div class="line"><a name="l00013"></a><span class="lineno"> 13</span>&#160; unsigned int cache_revalidate:1;</div><div class="line"><a name="l00014"></a><span class="lineno"> 14</span>&#160; unsigned int cache_intermediaries:1;</div><div class="line"><a name="l00015"></a><span class="lineno"> 15</span>&#160;</div><div class="line"><a name="l00016"></a><span class="lineno"> 16</span>&#160; unsigned char origin_protocol;</div><div class="line"><a name="l00017"></a><span class="lineno"> 17</span>&#160; unsigned char mountpoint_len;</div><div class="line"><a name="l00018"></a><span class="lineno"> 18</span>&#160;};</div></div><!-- fragment --><p>The last mount structure should have a NULL mount_next, otherwise it should point to the 'next' mount structure in your list.</p>

View file

@ -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) {