]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
4223. [bug] Improve HTTP header processing on statschannel.
authorMark Andrews <marka@isc.org>
Wed, 2 Mar 2016 00:04:59 +0000 (11:04 +1100)
committerMark Andrews <marka@isc.org>
Wed, 2 Mar 2016 00:04:59 +0000 (11:04 +1100)
                        [RT #41674]

CHANGES
bin/tests/system/statschannel/tests.sh
lib/isc/httpd.c

diff --git a/CHANGES b/CHANGES
index 9ff6e064635971d6f1cff7337e7710f5f229bd38..f334fb4fafd40c7acaf4410135f2d594681427f0 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,6 @@
+4223.  [bug]           Improve HTTP header processing on statschannel.
+                       [RT #41674]
+
 4322.  [security]      Duplicate EDNS COOKIE options in a response could
                        trigger an assertion failure. (CVE-2016-2088)
                        [RT #41809]
index 30ba853918636db0e1fda1921f2aa52ccd435d49..fe230366bfd07e05699093d0dc9b345f69da97a8 100644 (file)
@@ -57,7 +57,7 @@ gettraffic() {
         *) return 1 ;;
     esac
     file=`$PERL fetch.pl $path`
-    $PERL traffic-${1}.pl $file | sort > traffic.out.$2
+    $PERL traffic-${1}.pl $file 2>/dev/null | sort > traffic.out.$2
     result=$?
     rm -f $file
     return $result
index e4883685401857ca0d03906d1d39e2aebd12b7e4..194ae0745b2660ef02ab6f4d03df6df0a87ecfc1 100644 (file)
@@ -374,14 +374,76 @@ httpdmgr_destroy(isc_httpdmgr_t *httpdmgr) {
 #define LENGTHOK(s) (httpd->recvbuf - (s) < (int)httpd->recvlen)
 #define BUFLENOK(s) (httpd->recvbuf - (s) < HTTP_RECVLEN)
 
+/*
+ * Look for the given header in headers.
+ * If value is specified look for it terminated with a character in eov.
+ */
+static isc_boolean_t
+have_header(isc_httpd_t *httpd, const char *header, const char *value,
+           const char *eov)
+{
+       char *cr, *nl, *h;
+       size_t hlen, vlen;
+
+       h = httpd->headers;
+       hlen = strlen(header);
+       if (value != NULL) {
+               INSIST(eov != NULL);
+               vlen = strlen(value);
+       }
+
+       for (;;) {
+               if (strncasecmp(h, header, hlen) != 0) {
+                       /*
+                        * Skip to next line;
+                        */
+                       cr = strchr(h, '\r');
+                       if (cr != NULL && cr[1] == '\n')
+                               cr++;
+                       nl = strchr(h, '\n');
+                       /* last header? */
+                       if (cr == NULL && nl == NULL)
+                               return(ISC_FALSE);
+                       h = cr;
+                       if (h == NULL || nl < h)
+                               h = nl;
+                       h++;
+                       continue;
+               }
+
+               if (value == NULL)
+                       return (ISC_TRUE);
+
+               /*
+                * Skip optional leading white space.
+                */
+               h += hlen;
+               while (*h == ' ' || *h == '\t')
+                       h++;
+               /*
+                * Terminate token search on NULL or EOL.
+                */
+               while (*h != 0 && *h != '\r' && *h != '\n') {
+                       if (strncasecmp(h, value, vlen) == 0)
+                               if (strchr(eov, h[vlen]) != NULL)
+                                       return (ISC_TRUE);
+                       /*
+                        * Skip to next token.
+                        */
+                       h += strcspn(h, eov);
+                       if (h[0] == '\r' && h[1] == '\n')
+                               h++;
+                       if (h[0] != 0)
+                               h++;
+               }
+               return (ISC_FALSE);
+       }
+}
+
 static isc_result_t
 process_request(isc_httpd_t *httpd, int length) {
        char *s;
        char *p;
-#ifdef HAVE_ZLIB
-       char *e;
-       char *v;
-#endif
        int delim;
 
        ENTER("request");
@@ -396,14 +458,19 @@ process_request(isc_httpd_t *httpd, int length) {
         * more data.
         */
        s = strstr(httpd->recvbuf, "\r\n\r\n");
-       delim = 1;
+       delim = 2;
        if (s == NULL) {
                s = strstr(httpd->recvbuf, "\n\n");
-               delim = 2;
+               delim = 1;
        }
        if (s == NULL)
                return (ISC_R_NOTFOUND);
 
+       /*
+        * NUL terminate request at the blank line.
+        */
+       s[delim] = 0;
+
        /*
         * Determine if this is a POST or GET method.  Any other values will
         * cause an error to be returned.
@@ -462,7 +529,7 @@ process_request(isc_httpd_t *httpd, int length) {
        }
 
        httpd->url = p;
-       p = s + delim;
+       p = s + 1;
        s = p;
 
        /*
@@ -477,7 +544,7 @@ process_request(isc_httpd_t *httpd, int length) {
 
        /*
         * Extract the HTTP/1.X protocol.  We will bounce on anything but
-        * HTTP/1.1 for now.
+        * HTTP/1.0 or HTTP/1.1 for now.
         */
        while (LENGTHOK(s) && BUFLENOK(s) &&
               (*s != '\n' && *s != '\r' && *s != '\0'))
@@ -486,24 +553,30 @@ process_request(isc_httpd_t *httpd, int length) {
                return (ISC_R_NOTFOUND);
        if (!BUFLENOK(s))
                return (ISC_R_NOMEMORY);
+       /*
+        * Check that we have the expected eol delimiter.
+        */
+       if (strncmp(s, delim == 1 ? "\n" : "\r\n", delim) != 0)
+               return (ISC_R_RANGE);
        *s = 0;
        if ((strncmp(p, "HTTP/1.0", 8) != 0)
            && (strncmp(p, "HTTP/1.1", 8) != 0))
                return (ISC_R_RANGE);
        httpd->protocol = p;
-       p = s + 1;
+       p = s + delim;  /* skip past eol */
        s = p;
 
        httpd->headers = s;
 
-       if (strstr(s, "Connection: close") != NULL)
+       if (have_header(httpd, "Connection:", "close", ", \t\r\n"))
                httpd->flags |= HTTPD_CLOSE;
 
-       if (strstr(s, "Host: ") != NULL)
+       if (have_header(httpd, "Host:", NULL, NULL))
                httpd->flags |= HTTPD_FOUNDHOST;
 
        if (strncmp(httpd->protocol, "HTTP/1.0", 8) == 0) {
-               if (strcasestr(s, "Connection: Keep-Alive") != NULL)
+               if (have_header(httpd, "Connection:", "Keep-Alive",
+                               ", \t\r\n"))
                        httpd->flags |= HTTPD_KEEPALIVE;
                else
                        httpd->flags |= HTTPD_CLOSE;
@@ -513,22 +586,8 @@ process_request(isc_httpd_t *httpd, int length) {
         * Check for Accept-Encoding:
         */
 #ifdef HAVE_ZLIB
-       p = strcasestr(s, "Accept-Encoding:");
-       if (p != NULL) {
-               const int l = strlen("deflate");
-               p += strlen("Accept-Encoding:");
-               v = strstr(p, "deflate");
-               e = strstr(p, "\n");            /* this is never NULL */
-               INSIST(e != NULL);
-               if (v != NULL && v < e &&
-                       (v[-1] == ' ' || v[-1] == ',' || v == p) &&
-                       ((v[l] == '\r' && v[l+1] == '\n') ||  /* last on line */
-                         v[l] == ';'  ||                     /* with a 'q=...' */
-                         v[l] == ',')) {                     /* another follows */
-                       httpd->flags |= HTTPD_ACCEPT_DEFLATE;
-               }
-
-       }
+       if (have_header(httpd, "Accept-Encoding:", "deflate", ";, \t\r\n"))
+               httpd->flags |= HTTPD_ACCEPT_DEFLATE;
 #endif
 
        /*