altsvc: accept and parse IPv6 addresses in response headers

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
This commit is contained in:
Daniel Stenberg 2023-08-27 00:06:02 +02:00
Родитель a06de2b772
Коммит 25ca79df1e
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 5CC908FDB71E12C2
5 изменённых файлов: 231 добавлений и 14 удалений

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

68
tests/data/test437 Normal file
Просмотреть файл

@ -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
Host: %HOSTIP:%HTTPPORT
User-Agent: curl/%VERSION
Accept: */*
</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>

90
tests/data/test438 Normal file
Просмотреть файл

@ -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
Date: Tue, 09 Nov 2010 14:49:00 GMT
Content-Length: 6
Connection: close
Content-Type: text/html
Funny-Head: yesyes
Alt-Svc: h1="%HOST6IP:%HTTP6PORT", ma=315360000; persist=0
-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
Date: Tue, 09 Nov 2010 14:49:00 GMT
Content-Length: 6
Connection: close
Content-Type: text/html
Funny-Head: yesyes
Alt-Svc: h1="%HOST6IP:%HTTP6PORT", ma=315360000; persist=0
-foo-
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="%HOST6IP:%HTTP6PORT", ma=315360000; persist=0
-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>