]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
altsvc: accept and parse IPv6 addresses in response headers
authorDaniel Stenberg <daniel@haxx.se>
Sat, 26 Aug 2023 22:06:02 +0000 (00:06 +0200)
committerDaniel Stenberg <daniel@haxx.se>
Mon, 28 Aug 2023 15:08:42 +0000 (17:08 +0200)
Store numerical IPv6 addresses in the alt-svc file with the brackets
present.

Verify with test 437 and 438

Fixes #11737
Reported-by: oliverpool on github
Closes #11743

docs/ALTSVC.md
lib/altsvc.c
tests/data/Makefile.inc
tests/data/test437 [new file with mode: 0644]
tests/data/test438 [new file with mode: 0644]

index 560b43748ac066b210065be93147bfb2cc2db73a..b9117e4d46cf9d89a85c347e7b65fa07eb32a943 100644 (file)
@@ -33,6 +33,9 @@ space separated fields.
 8. Boolean (1 or 0) if "persist" was set for this entry
 9. Integer priority value (not currently used)
 
+If the host name is an IPv6 numerical address, it is stored with brackets such
+as `[::1]`.
+
 # TODO
 
 - handle multiple response headers, when one of them says `clear` (should
index 11009d5ac8f497052e0c17eee2755543a109ac0e..22b0b69c77f625b1af46aecf9294fc510b3c761e 100644 (file)
@@ -38,6 +38,8 @@
 #include "warnless.h"
 #include "fopen.h"
 #include "rename.h"
+#include "strdup.h"
+#include "inet_pton.h"
 
 /* The last 3 #include files should be in this order */
 #include "curl_printf.h"
@@ -97,19 +99,39 @@ static struct altsvc *altsvc_createid(const char *srchost,
 {
   struct altsvc *as = calloc(sizeof(struct altsvc), 1);
   size_t hlen;
+  size_t dlen;
   if(!as)
     return NULL;
   hlen = strlen(srchost);
+  dlen = strlen(dsthost);
   DEBUGASSERT(hlen);
-  as->src.host = strdup(srchost);
+  DEBUGASSERT(dlen);
+  if(!hlen || !dlen)
+    /* bad input */
+    return NULL;
+  if((hlen > 2) && srchost[0] == '[') {
+    /* IPv6 address, strip off brackets */
+    srchost++;
+    hlen -= 2;
+  }
+  else if(srchost[hlen - 1] == '.')
+    /* strip off trailing dot */
+    hlen--;
+  if((dlen > 2) && dsthost[0] == '[') {
+    /* IPv6 address, strip off brackets */
+    dsthost++;
+    dlen -= 2;
+  }
+
+  as->src.host = Curl_memdup(srchost, hlen + 1);
   if(!as->src.host)
     goto error;
-  if(hlen && (srchost[hlen - 1] == '.'))
-    /* strip off trailing any dot */
-    as->src.host[--hlen] = 0;
-  as->dst.host = strdup(dsthost);
+  as->src.host[hlen] = 0;
+
+  as->dst.host = Curl_memdup(dsthost, dlen + 1);
   if(!as->dst.host)
     goto error;
+  as->dst.host[dlen] = 0;
 
   as->src.alpnid = srcalpnid;
   as->dst.alpnid = dstalpnid;
@@ -231,18 +253,40 @@ fail:
 static CURLcode altsvc_out(struct altsvc *as, FILE *fp)
 {
   struct tm stamp;
+  const char *dst6_pre = "";
+  const char *dst6_post = "";
+  const char *src6_pre = "";
+  const char *src6_post = "";
   CURLcode result = Curl_gmtime(as->expires, &stamp);
   if(result)
     return result;
-
+#ifdef ENABLE_IPV6
+  else {
+    char ipv6_unused[16];
+    if(1 == Curl_inet_pton(AF_INET6, as->dst.host, ipv6_unused)) {
+      dst6_pre = "[";
+      dst6_post = "]";
+    }
+    if(1 == Curl_inet_pton(AF_INET6, as->src.host, ipv6_unused)) {
+      src6_pre = "[";
+      src6_post = "]";
+    }
+  }
+#endif
   fprintf(fp,
-          "%s %s %u "
-          "%s %s %u "
+          "%s %s%s%s %u "
+          "%s %s%s%s %u "
           "\"%d%02d%02d "
           "%02d:%02d:%02d\" "
           "%u %d\n",
-          Curl_alpnid2str(as->src.alpnid), as->src.host, as->src.port,
-          Curl_alpnid2str(as->dst.alpnid), as->dst.host, as->dst.port,
+          Curl_alpnid2str(as->src.alpnid),
+          src6_pre, as->src.host, src6_post,
+          as->src.port,
+
+          Curl_alpnid2str(as->dst.alpnid),
+          dst6_pre, as->dst.host, dst6_post,
+          as->dst.port,
+
           stamp.tm_year + 1900, stamp.tm_mon + 1, stamp.tm_mday,
           stamp.tm_hour, stamp.tm_min, stamp.tm_sec,
           as->persist, as->prio);
@@ -500,9 +544,21 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data,
         if(*p != ':') {
           /* host name starts here */
           const char *hostp = p;
-          while(*p && (ISALNUM(*p) || (*p == '.') || (*p == '-')))
-            p++;
-          len = p - hostp;
+          if(*p == '[') {
+            /* pass all valid IPv6 letters - does not handle zone id */
+            len = strspn(++p, "0123456789abcdefABCDEF:.");
+            if(p[len] != ']')
+              /* invalid host syntax, bail out */
+              break;
+            /* we store the IPv6 numerical address *with* brackets */
+            len += 2;
+            p = &p[len-1];
+          }
+          else {
+            while(*p && (ISALNUM(*p) || (*p == '.') || (*p == '-')))
+              p++;
+            len = p - hostp;
+          }
           if(!len || (len >= MAX_ALTSVC_HOSTLEN)) {
             infof(data, "Excessive alt-svc host name, ignoring.");
             valid = FALSE;
index 78edff66c48ad50e50aeb509c6f85c379087be64..a0015b3b203b4fd88f354242e81b991fc5c41953 100644 (file)
@@ -70,7 +70,7 @@ test399 test400 test401 test402 test403 test404 test405 test406 test407 \
 test408 test409 test410 test411 test412 test413 test414 test415 test416 \
 test417 test418 test419 test420 test421 test422 test423 test424 test425 \
 test426 test427 test428 test429 test430 test431 test432 test433 test434 \
-test435 test436 \
+test435 test436 test437 test438 \
 \
 test440 test441 test442 test443 test444 test445 test446 test447 test448 \
 test449 test450 test451 test452 test453 test454 test455 test456 \
diff --git a/tests/data/test437 b/tests/data/test437
new file mode 100644 (file)
index 0000000..a49fb8c
--- /dev/null
@@ -0,0 +1,68 @@
+<testcase>
+<info>
+<keywords>
+HTTP
+Alt-Svc
+</keywords>
+</info>
+
+#
+# Server-side
+<reply>
+<data>
+HTTP/1.1 200 OK
+Date: Tue, 09 Nov 2010 14:49:00 GMT
+Content-Length: 6
+Connection: close
+Content-Type: text/html
+Funny-head: yesyes
+Alt-Svc: h1="[ffff::1]:8181"
+
+-foo-
+</data>
+</reply>
+
+#
+# Client-side
+<client>
+<features>
+debug
+alt-svc
+</features>
+<server>
+http
+</server>
+ <name>
+Alt-Svc to numerical IPv6 address
+ </name>
+<setenv>
+# make debug-curl accept Alt-Svc over plain HTTP
+CURL_ALTSVC_HTTP="yeah"
+</setenv>
+ <command>
+http://%HOSTIP:%HTTPPORT/%TESTNUMBER --alt-svc "%LOGDIR/altsvc-%TESTNUMBER"
+</command>
+</client>
+
+#
+# Verify data after the test has been "shot"
+<verify>
+<protocol>
+GET /%TESTNUMBER HTTP/1.1\r
+Host: %HOSTIP:%HTTPPORT\r
+User-Agent: curl/%VERSION\r
+Accept: */*\r
+\r
+</protocol>
+<stripfile>
+# strip out the (dynamic) expire date from the file so that the rest
+# matches
+s/\"([^\"]*)\"/TIMESTAMP/
+</stripfile>
+<file name="%LOGDIR/altsvc-%TESTNUMBER" mode="text">
+# Your alt-svc cache. https://curl.se/docs/alt-svc.html
+# This file was generated by libcurl! Edit at your own risk.
+h1 %HOSTIP %HTTPPORT h1 [ffff::1] 8181 TIMESTAMP 0 0
+</file>
+</verify>
+</testcase>
diff --git a/tests/data/test438 b/tests/data/test438
new file mode 100644 (file)
index 0000000..9015e92
--- /dev/null
@@ -0,0 +1,90 @@
+<testcase>
+<info>
+<keywords>
+HTTP
+HTTP GET
+Alt-Svc
+HTTP/2
+</keywords>
+</info>
+
+#
+# Server-side
+<reply>
+<data nocheck="yes">
+HTTP/1.1 200 OK\r
+Date: Tue, 09 Nov 2010 14:49:00 GMT\r
+Content-Length: 6\r
+Connection: close\r
+Content-Type: text/html\r
+Funny-Head: yesyes\r
+Alt-Svc: h1="%HOST6IP:%HTTP6PORT", ma=315360000; persist=0\r
+\r
+-foo-
+</data>
+</reply>
+
+#
+# Client-side
+<client>
+<features>
+alt-svc
+debug
+ipv6
+</features>
+<server>
+http
+http-ipv6
+</server>
+ <name>
+HTTPS IPv4 GET translated by alt-svc to IPv6 address
+ </name>
+<setenv>
+# make debug-curl accept Alt-Svc over plain HTTP
+CURL_ALTSVC_HTTP="yeah"
+</setenv>
+ <command>
+--alt-svc "%LOGDIR/altsvc-%TESTNUMBER" "http://%HOSTIP:%HTTPPORT/%TESTNUMBER" "http://%HOSTIP:%HTTPPORT/%TESTNUMBER"
+</command>
+<file name="%LOGDIR/altsvc-%TESTNUMBER">
+h1 %HOSTIP %HTTPPORT h1 %HOST6IP %HTTP6PORT "20290222 22:19:28" 0 0
+</file>
+
+</client>
+
+#
+# Verify data after the test has been "shot"
+<verify>
+<stdout>
+HTTP/1.1 200 OK\r
+Date: Tue, 09 Nov 2010 14:49:00 GMT\r
+Content-Length: 6\r
+Connection: close\r
+Content-Type: text/html\r
+Funny-Head: yesyes\r
+Alt-Svc: h1="%HOST6IP:%HTTP6PORT", ma=315360000; persist=0\r
+\r
+-foo-
+HTTP/1.1 200 OK\r
+Date: Tue, 09 Nov 2010 14:49:00 GMT\r
+Content-Length: 6\r
+Connection: close\r
+Content-Type: text/html\r
+Funny-Head: yesyes\r
+Alt-Svc: h1="%HOST6IP:%HTTP6PORT", ma=315360000; persist=0\r
+\r
+-foo-
+</stdout>
+<stripfile>
+s/^server: nghttpx.*\r?\n//
+# strip out the (dynamic) expire date from the file so that the rest
+# matches
+s/\"2([^\"]*)\"/TIMESTAMP/
+</stripfile>
+<file name="%LOGDIR/altsvc-%TESTNUMBER" mode="text">
+# Your alt-svc cache. https://curl.se/docs/alt-svc.html
+# This file was generated by libcurl! Edit at your own risk.
+h1 %HOSTIP %HTTPPORT h1 %HOST6IP %HTTP6PORT TIMESTAMP 0 0
+</file>
+</verify>
+</testcase>