At present, if a request contains no "Host:" header [HTTP pre-1.1] or
if the supplied header does not match any of the servers configured
in httpd.conf, the request is directed to the first server.  This
isn't documented, AFAICT.

For example, if httpd.conf has just one server
        server "www.example.com"
then we currently get
        $ printf "HEAD / HTTP/1.0\r\nHost: www.openbsd.org\r\n\r\n" \
            | nc www.example.com www | sed 1q 
        HTTP/1.0 200 OK

This behaviour strikes me as wrong (or at least sub-optimal) in the
case of non-matching "Host:" headers.  The simplistic patch below
changes things to return a 404 status if no matching server is found.

[If status code 400 (bad request) is preferred, "goto fail;"
could be used.]

Justification:
- This seems more correct, and is consistent with the "fail closed"
  approach.
- There is a net gain in functionality, as use of glob/patterns
  wildcards can easily re-establish the current behaviour.  In
  contrast, there's no way at present to disable the implicit
  match-anything behaviour.

If this is adopted, it should be document in current.html
A followup patch could merge this if statement with the one above it.

Several other issues exist in "Host:" header handling.

Ross
--

Index: server_http.c
===================================================================
RCS file: /cvs/src/usr.sbin/httpd/server_http.c,v
retrieving revision 1.140
diff -u -p -r1.140 server_http.c
--- server_http.c       3 Aug 2020 10:59:53 -0000       1.140
+++ server_http.c       9 Aug 2020 04:37:08 -0000
@@ -1200,7 +1200,7 @@ server_response(struct httpd *httpd, str
        struct server_config    *srv_conf = &srv->srv_conf;
        struct kv               *kv, key, *host;
        struct str_find          sm;
-       int                      portval = -1, ret;
+       int                      hostmatch = 0, portval = -1, ret;
        char                    *hostval, *query;
        const char              *errstr = NULL;
 
@@ -1277,16 +1277,20 @@ server_response(struct httpd *httpd, str
                                /* Replace host configuration */
                                clt->clt_srv_conf = srv_conf;
                                srv_conf = NULL;
+                               hostmatch = 1;
                                break;
                        }
                }
        }
 
-       if (srv_conf != NULL) {
+       if (host == NULL) {
                /* Use the actual server IP address */
                if (server_http_host(&clt->clt_srv_ss, hostname,
                    sizeof(hostname)) == NULL)
                        goto fail;
+       } else if (!hostmatch) {
+               server_abort_http(clt, 404, "not found");
+               return (-1);
        } else {
                /* Host header was valid and found */
                if (strlcpy(hostname, host->kv_value, sizeof(hostname)) >=

Reply via email to