mirror of
https://github.com/curl/curl.git
synced 2026-04-11 12:01:42 +08:00
test1658: add unit test for the HTTPS RR decoder
Made the HTTPS-RR parser a little stricter while at it. Drop the ALPN escape handling, that was not needed. Make the hode handle (and ignore) duplicate ALPN entries. Closes #16972
This commit is contained in:
parent
023cc8d595
commit
badfb951ec
62
lib/doh.c
62
lib/doh.c
@ -38,11 +38,13 @@
|
||||
#include "connect.h"
|
||||
#include "strdup.h"
|
||||
#include "dynbuf.h"
|
||||
#include "escape.h"
|
||||
#include "urlapi-int.h"
|
||||
|
||||
/* The last 3 #include files should be in this order */
|
||||
#include "curl_printf.h"
|
||||
#include "curl_memory.h"
|
||||
#include "memdebug.h"
|
||||
#include "escape.h"
|
||||
|
||||
#define DNS_CLASS_IN 0x01
|
||||
|
||||
@ -1014,10 +1016,10 @@ UNITTEST void de_cleanup(struct dohentry *d)
|
||||
* just after the end of the DNS name encoding on output. (And
|
||||
* that is why it is an "unsigned char **" :-)
|
||||
*/
|
||||
static CURLcode doh_decode_rdata_name(unsigned char **buf, size_t *remaining,
|
||||
char **dnsname)
|
||||
static CURLcode doh_decode_rdata_name(const unsigned char **buf,
|
||||
size_t *remaining, char **dnsname)
|
||||
{
|
||||
unsigned char *cp = NULL;
|
||||
const unsigned char *cp = NULL;
|
||||
size_t rem = 0;
|
||||
unsigned char clen = 0; /* chunk len */
|
||||
struct dynbuf thename;
|
||||
@ -1057,43 +1059,23 @@ static CURLcode doh_decode_rdata_name(unsigned char **buf, size_t *remaining,
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
#ifdef DEBUGBUILD
|
||||
static CURLcode doh_test_alpn_escapes(void)
|
||||
{
|
||||
/* we will use an example from draft-ietf-dnsop-svcb, figure 10 */
|
||||
static unsigned char example[] = {
|
||||
0x08, /* length 8 */
|
||||
0x66, 0x5c, 0x6f, 0x6f, 0x2c, 0x62, 0x61, 0x72, /* value "f\\oo,bar" */
|
||||
0x02, /* length 2 */
|
||||
0x68, 0x32 /* value "h2" */
|
||||
};
|
||||
size_t example_len = sizeof(example);
|
||||
unsigned char aval[MAX_HTTPSRR_ALPNS] = { 0 };
|
||||
static const char expected[2] = { ALPN_h2, ALPN_none };
|
||||
UNITTEST CURLcode doh_resp_decode_httpsrr(struct Curl_easy *data,
|
||||
const unsigned char *cp, size_t len,
|
||||
struct Curl_https_rrinfo **hrr);
|
||||
|
||||
if(Curl_httpsrr_decode_alpn(example, example_len, aval) != CURLE_OK)
|
||||
return CURLE_BAD_CONTENT_ENCODING;
|
||||
if(memcmp(aval, expected, sizeof(expected)))
|
||||
return CURLE_BAD_CONTENT_ENCODING;
|
||||
return CURLE_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
static CURLcode doh_resp_decode_httpsrr(struct Curl_easy *data,
|
||||
unsigned char *cp, size_t len,
|
||||
struct Curl_https_rrinfo **hrr)
|
||||
/* @unittest 1658 */
|
||||
UNITTEST CURLcode doh_resp_decode_httpsrr(struct Curl_easy *data,
|
||||
const unsigned char *cp, size_t len,
|
||||
struct Curl_https_rrinfo **hrr)
|
||||
{
|
||||
uint16_t pcode = 0, plen = 0;
|
||||
uint32_t expected_min_pcode = 0;
|
||||
struct Curl_https_rrinfo *lhrr = NULL;
|
||||
char *dnsname = NULL;
|
||||
CURLcode result = CURLE_OUT_OF_MEMORY;
|
||||
size_t olen;
|
||||
|
||||
#ifdef DEBUGBUILD
|
||||
/* a few tests of escaping, should not be here but ok for now */
|
||||
if(doh_test_alpn_escapes() != CURLE_OK)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
#endif
|
||||
*hrr = NULL;
|
||||
if(len <= 2)
|
||||
return CURLE_BAD_FUNCTION_ARGUMENT;
|
||||
lhrr = calloc(1, sizeof(struct Curl_https_rrinfo));
|
||||
@ -1105,6 +1087,11 @@ static CURLcode doh_resp_decode_httpsrr(struct Curl_easy *data,
|
||||
if(doh_decode_rdata_name(&cp, &len, &dnsname) != CURLE_OK)
|
||||
goto err;
|
||||
lhrr->target = dnsname;
|
||||
if(Curl_junkscan(dnsname, &olen, FALSE)) {
|
||||
/* unacceptable hostname content */
|
||||
result = CURLE_WEIRD_SERVER_REPLY;
|
||||
goto err;
|
||||
}
|
||||
lhrr->port = -1; /* until set */
|
||||
while(len >= 4) {
|
||||
pcode = doh_get16bit(cp, 0);
|
||||
@ -1131,9 +1118,12 @@ err:
|
||||
return result;
|
||||
}
|
||||
|
||||
# ifdef DEBUGBUILD
|
||||
static void doh_print_httpsrr(struct Curl_easy *data,
|
||||
struct Curl_https_rrinfo *hrr)
|
||||
#ifdef DEBUGBUILD
|
||||
UNITTEST void doh_print_httpsrr(struct Curl_easy *data,
|
||||
struct Curl_https_rrinfo *hrr);
|
||||
|
||||
UNITTEST void doh_print_httpsrr(struct Curl_easy *data,
|
||||
struct Curl_https_rrinfo *hrr)
|
||||
{
|
||||
DEBUGASSERT(hrr);
|
||||
infof(data, "HTTPS RR: priority %d, target: %s",
|
||||
|
||||
@ -38,76 +38,67 @@
|
||||
#include "curl_memory.h"
|
||||
#include "memdebug.h"
|
||||
|
||||
CURLcode Curl_httpsrr_decode_alpn(const unsigned char *cp, size_t len,
|
||||
unsigned char *alpns)
|
||||
#define MAX_ALPN_LENGTH 255
|
||||
|
||||
static CURLcode httpsrr_decode_alpn(const char *cp, size_t len,
|
||||
unsigned char *alpns)
|
||||
{
|
||||
/*
|
||||
* spec here is as per RFC 9460, section-7.1.1
|
||||
* encoding is a concatenated list of strings each preceded by a one
|
||||
* octet length
|
||||
* output is comma-sep list of the strings
|
||||
* implementations may or may not handle quoting of comma within
|
||||
* string values, so we might see a comma within the wire format
|
||||
* version of a string, in which case we will precede that by a
|
||||
* backslash - same goes for a backslash character, and of course
|
||||
* we need to use two backslashes in strings when we mean one;-)
|
||||
* The wire-format value for "alpn" consists of at least one alpn-id
|
||||
* prefixed by its length as a single octet, and these length-value pairs
|
||||
* are concatenated to form the SvcParamValue. These pairs MUST exactly fill
|
||||
* the SvcParamValue; otherwise, the SvcParamValue is malformed.
|
||||
*/
|
||||
struct dynbuf dval;
|
||||
int idnum = 0;
|
||||
|
||||
Curl_dyn_init(&dval, DYN_DOH_RESPONSE);
|
||||
while(len > 0) {
|
||||
size_t tlen = (size_t) *cp++;
|
||||
size_t i;
|
||||
enum alpnid id;
|
||||
len--;
|
||||
if(tlen > len)
|
||||
goto err;
|
||||
/* add escape char if needed, clunky but easier to read */
|
||||
for(i = 0; i != tlen; i++) {
|
||||
if('\\' == *cp || ',' == *cp) {
|
||||
if(Curl_dyn_addn(&dval, "\\", 1))
|
||||
goto err;
|
||||
}
|
||||
if(Curl_dyn_addn(&dval, cp++, 1))
|
||||
goto err;
|
||||
}
|
||||
len -= tlen;
|
||||
return CURLE_BAD_CONTENT_ENCODING;
|
||||
|
||||
/* we only store ALPN ids we know about */
|
||||
id = Curl_alpn2alpnid(Curl_dyn_ptr(&dval), Curl_dyn_len(&dval));
|
||||
id = Curl_alpn2alpnid(cp, tlen);
|
||||
if(id != ALPN_none) {
|
||||
if(idnum == MAX_HTTPSRR_ALPNS)
|
||||
break;
|
||||
alpns[idnum++] = (unsigned char)id;
|
||||
if(idnum && memchr(alpns, id, idnum))
|
||||
/* this ALPN id is already stored */
|
||||
;
|
||||
else
|
||||
alpns[idnum++] = (unsigned char)id;
|
||||
}
|
||||
Curl_dyn_reset(&dval);
|
||||
cp += tlen;
|
||||
len -= tlen;
|
||||
}
|
||||
Curl_dyn_free(&dval);
|
||||
if(idnum < MAX_HTTPSRR_ALPNS)
|
||||
alpns[idnum] = ALPN_none; /* terminate the list */
|
||||
return CURLE_OK;
|
||||
err:
|
||||
Curl_dyn_free(&dval);
|
||||
return CURLE_BAD_CONTENT_ENCODING;
|
||||
}
|
||||
|
||||
CURLcode Curl_httpsrr_set(struct Curl_easy *data,
|
||||
struct Curl_https_rrinfo *hi,
|
||||
uint16_t rrkey, const uint8_t *val, size_t vlen)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
switch(rrkey) {
|
||||
case HTTPS_RR_CODE_MANDATORY:
|
||||
CURL_TRC_DNS(data, "HTTPS RR MANDATORY left to implement");
|
||||
break;
|
||||
case HTTPS_RR_CODE_ALPN: /* str_list */
|
||||
Curl_httpsrr_decode_alpn(val, vlen, hi->alpns);
|
||||
result = httpsrr_decode_alpn((const char *)val, vlen, hi->alpns);
|
||||
CURL_TRC_DNS(data, "HTTPS RR ALPN: %u %u %u %u",
|
||||
hi->alpns[0], hi->alpns[1], hi->alpns[2], hi->alpns[3]);
|
||||
break;
|
||||
case HTTPS_RR_CODE_NO_DEF_ALPN:
|
||||
if(vlen) /* no data */
|
||||
return CURLE_BAD_FUNCTION_ARGUMENT;
|
||||
hi->no_def_alpn = TRUE;
|
||||
CURL_TRC_DNS(data, "HTTPS RR no-def-alpn");
|
||||
break;
|
||||
case HTTPS_RR_CODE_IPV4: /* addr4 list */
|
||||
if(!vlen)
|
||||
if(!vlen || (vlen & 3)) /* the size must be 4-byte aligned */
|
||||
return CURLE_BAD_FUNCTION_ARGUMENT;
|
||||
hi->ipv4hints = Curl_memdup(val, vlen);
|
||||
if(!hi->ipv4hints)
|
||||
@ -125,7 +116,7 @@ CURLcode Curl_httpsrr_set(struct Curl_easy *data,
|
||||
CURL_TRC_DNS(data, "HTTPS RR ECH");
|
||||
break;
|
||||
case HTTPS_RR_CODE_IPV6: /* addr6 list */
|
||||
if(!vlen)
|
||||
if(!vlen || (vlen & 15)) /* the size must be 16-byte aligned */
|
||||
return CURLE_BAD_FUNCTION_ARGUMENT;
|
||||
hi->ipv6hints = Curl_memdup(val, vlen);
|
||||
if(!hi->ipv6hints)
|
||||
@ -143,7 +134,7 @@ CURLcode Curl_httpsrr_set(struct Curl_easy *data,
|
||||
CURL_TRC_DNS(data, "HTTPS RR unknown code");
|
||||
break;
|
||||
}
|
||||
return CURLE_OK;
|
||||
return result;
|
||||
}
|
||||
|
||||
struct Curl_https_rrinfo *
|
||||
|
||||
@ -68,6 +68,7 @@ void Curl_httpsrr_cleanup(struct Curl_https_rrinfo *rrinfo);
|
||||
/*
|
||||
* Code points for DNS wire format SvcParams as per RFC 9460
|
||||
*/
|
||||
#define HTTPS_RR_CODE_MANDATORY 0x00
|
||||
#define HTTPS_RR_CODE_ALPN 0x01
|
||||
#define HTTPS_RR_CODE_NO_DEF_ALPN 0x02
|
||||
#define HTTPS_RR_CODE_PORT 0x03
|
||||
@ -75,9 +76,6 @@ void Curl_httpsrr_cleanup(struct Curl_https_rrinfo *rrinfo);
|
||||
#define HTTPS_RR_CODE_ECH 0x05
|
||||
#define HTTPS_RR_CODE_IPV6 0x06
|
||||
|
||||
CURLcode Curl_httpsrr_decode_alpn(const unsigned char *cp, size_t len,
|
||||
unsigned char *alpns);
|
||||
|
||||
#if defined(USE_ARES)
|
||||
void Curl_dnsrec_done_cb(void *arg, ares_status_t status,
|
||||
size_t timeouts,
|
||||
|
||||
@ -30,6 +30,8 @@ size_t Curl_is_absolute_url(const char *url, char *buf, size_t buflen,
|
||||
|
||||
CURLUcode Curl_url_set_authority(CURLU *u, const char *authority);
|
||||
|
||||
CURLUcode Curl_junkscan(const char *url, size_t *urllen, bool allowspace);
|
||||
|
||||
#ifdef UNITTESTS
|
||||
UNITTEST CURLUcode Curl_parse_port(struct Curl_URL *u, struct dynbuf *host,
|
||||
bool has_scheme);
|
||||
|
||||
@ -303,7 +303,7 @@ static CURLUcode redirect_url(const char *base, const char *relurl,
|
||||
}
|
||||
|
||||
/* scan for byte values <= 31, 127 and sometimes space */
|
||||
static CURLUcode junkscan(const char *url, size_t *urllen, bool allowspace)
|
||||
CURLUcode Curl_junkscan(const char *url, size_t *urllen, bool allowspace)
|
||||
{
|
||||
size_t n = strlen(url);
|
||||
size_t i;
|
||||
@ -918,7 +918,7 @@ static CURLUcode parseurl(const char *url, CURLU *u, unsigned int flags)
|
||||
|
||||
Curl_dyn_init(&host, CURL_MAX_INPUT_LENGTH);
|
||||
|
||||
result = junkscan(url, &urllen, !!(flags & CURLU_ALLOW_SPACE));
|
||||
result = Curl_junkscan(url, &urllen, !!(flags & CURLU_ALLOW_SPACE));
|
||||
if(result)
|
||||
goto fail;
|
||||
|
||||
|
||||
@ -220,6 +220,7 @@ test1620 test1621 \
|
||||
test1630 test1631 test1632 test1633 test1634 test1635 \
|
||||
\
|
||||
test1650 test1651 test1652 test1653 test1654 test1655 test1656 test1657 \
|
||||
test1658 \
|
||||
test1660 test1661 test1662 test1663 test1664 \
|
||||
\
|
||||
test1670 test1671 \
|
||||
|
||||
30
tests/data/test1658
Normal file
30
tests/data/test1658
Normal file
@ -0,0 +1,30 @@
|
||||
<testcase>
|
||||
<info>
|
||||
<keywords>
|
||||
unittest
|
||||
doh
|
||||
httpsrr
|
||||
</keywords>
|
||||
</info>
|
||||
|
||||
#
|
||||
# Client-side
|
||||
<client>
|
||||
<server>
|
||||
none
|
||||
</server>
|
||||
<features>
|
||||
unittest
|
||||
DoH
|
||||
</features>
|
||||
<name>
|
||||
unit test for doh_resp_decode_httpsrr
|
||||
</name>
|
||||
</client>
|
||||
<verify>
|
||||
<stderr mode="text">
|
||||
URL: -
|
||||
Test ended with result 0
|
||||
</stderr>
|
||||
</verify>
|
||||
</testcase>
|
||||
@ -39,6 +39,7 @@ UNITPROGS = unit1300 unit1302 unit1303 unit1304 unit1305 unit1307 \
|
||||
unit1608 unit1609 unit1610 unit1611 unit1612 unit1614 unit1615 unit1616 \
|
||||
unit1620 unit1621 \
|
||||
unit1650 unit1651 unit1652 unit1653 unit1654 unit1655 unit1656 unit1657 \
|
||||
unit1658 \
|
||||
unit1660 unit1661 unit1663 unit1664 \
|
||||
unit2600 unit2601 unit2602 unit2603 unit2604 \
|
||||
unit3200 \
|
||||
@ -126,6 +127,8 @@ unit1656_SOURCES = unit1656.c $(UNITFILES)
|
||||
|
||||
unit1657_SOURCES = unit1657.c $(UNITFILES)
|
||||
|
||||
unit1658_SOURCES = unit1658.c $(UNITFILES)
|
||||
|
||||
unit1660_SOURCES = unit1660.c $(UNITFILES)
|
||||
|
||||
unit1661_SOURCES = unit1661.c $(UNITFILES)
|
||||
|
||||
553
tests/unit/unit1658.c
Normal file
553
tests/unit/unit1658.c
Normal file
@ -0,0 +1,553 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
*
|
||||
* This software is licensed as described in the file COPYING, which
|
||||
* you should have received as part of this distribution. The terms
|
||||
* are also available at https://curl.se/docs/copyright.html.
|
||||
*
|
||||
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
||||
* copies of the Software, and permit persons to whom the Software is
|
||||
* furnished to do so, under the terms of the COPYING file.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "curlcheck.h"
|
||||
|
||||
#include "doh.h" /* from the lib dir */
|
||||
|
||||
static CURLcode unit_setup(void)
|
||||
{
|
||||
/* whatever you want done first */
|
||||
curl_global_init(CURL_GLOBAL_ALL);
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
static void unit_stop(void)
|
||||
{
|
||||
curl_global_cleanup();
|
||||
/* done before shutting down and exiting */
|
||||
}
|
||||
|
||||
/* DoH + HTTPSRR are required */
|
||||
#if !defined(CURL_DISABLE_DOH) && defined(USE_HTTPSRR)
|
||||
|
||||
extern CURLcode doh_resp_decode_httpsrr(struct Curl_easy *data,
|
||||
const unsigned char *cp, size_t len,
|
||||
struct Curl_https_rrinfo **hrr);
|
||||
extern void doh_print_httpsrr(struct Curl_easy *data,
|
||||
struct Curl_https_rrinfo *hrr);
|
||||
|
||||
struct test {
|
||||
const char *name;
|
||||
const unsigned char *dns;
|
||||
size_t len; /* size of the dns packet */
|
||||
const char *expect;
|
||||
};
|
||||
|
||||
/*
|
||||
* The idea here is that we pass one DNS packet at the time to the decoder. we
|
||||
* then generate a string output with the results and compare if it matches
|
||||
* the expected. One by one.
|
||||
*/
|
||||
|
||||
static char rrbuffer[256];
|
||||
static void rrresults(struct Curl_https_rrinfo *rr, CURLcode result)
|
||||
{
|
||||
char *p = rrbuffer;
|
||||
char *pend = rrbuffer + sizeof(rrbuffer);
|
||||
msnprintf(rrbuffer, sizeof(rrbuffer), "r:%d|", (int)result);
|
||||
p += strlen(rrbuffer);
|
||||
|
||||
if(rr) {
|
||||
unsigned int i;
|
||||
msnprintf(p, pend - p, "p:%d|", rr->priority);
|
||||
p += strlen(p);
|
||||
|
||||
msnprintf(p, pend - p, "%s|", rr->target ? rr->target : "-");
|
||||
p += strlen(p);
|
||||
|
||||
for(i = 0; i < MAX_HTTPSRR_ALPNS && rr->alpns[i] != ALPN_none; i++) {
|
||||
msnprintf(p, pend - p, "alpn:%x|", rr->alpns[i]);
|
||||
p += strlen(p);
|
||||
}
|
||||
if(rr->no_def_alpn) {
|
||||
msnprintf(p, pend - p, "no-def-alpn|");
|
||||
p += strlen(p);
|
||||
}
|
||||
if(rr->port >= 0) {
|
||||
msnprintf(p, pend - p, "port:%d|", rr->port);
|
||||
p += strlen(p);
|
||||
}
|
||||
if(rr->ipv4hints) {
|
||||
for(i = 0; i < rr->ipv4hints_len; i += 4) {
|
||||
msnprintf(p, pend - p, "ipv4:%d.%d.%d.%d|",
|
||||
rr->ipv4hints[i],
|
||||
rr->ipv4hints[i + 1],
|
||||
rr->ipv4hints[i + 2],
|
||||
rr->ipv4hints[i + 3]);
|
||||
p += strlen(p);
|
||||
}
|
||||
}
|
||||
if(rr->echconfiglist) {
|
||||
msnprintf(p, pend - p, "ech:");
|
||||
p += strlen(p);
|
||||
for(i = 0; i < rr->echconfiglist_len; i++) {
|
||||
msnprintf(p, pend - p, "%02x", rr->echconfiglist[i]);
|
||||
p += strlen(p);
|
||||
}
|
||||
msnprintf(p, pend - p, "|");
|
||||
p += strlen(p);
|
||||
}
|
||||
if(rr->ipv6hints) {
|
||||
for(i = 0; i < rr->ipv6hints_len; i += 16) {
|
||||
int x;
|
||||
msnprintf(p, pend - p, "ipv6:");
|
||||
p += strlen(p);
|
||||
for(x = 0; x < 16; x += 2) {
|
||||
msnprintf(p, pend - p, "%s%02x%02x",
|
||||
x ? ":" : "",
|
||||
rr->ipv6hints[i + x],
|
||||
rr->ipv6hints[i + x + 1]);
|
||||
p += strlen(p);
|
||||
}
|
||||
msnprintf(p, pend - p, "|");
|
||||
p += strlen(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UNITTEST_START
|
||||
{
|
||||
/* The "SvcParamKeys" specified within the HTTPS RR packet *must* be
|
||||
provided in numerical order. */
|
||||
|
||||
static struct test t[] = {
|
||||
{
|
||||
"single h2 alpn",
|
||||
(const unsigned char *)"\x00\x00" /* 16-bit prio */
|
||||
"\x04name\x00" /* RNAME */
|
||||
"\x00\x01" /* RR (1 == ALPN) */
|
||||
"\x00\x03" /* data size */
|
||||
"\x02" /* length byte */
|
||||
"h2",
|
||||
15,
|
||||
"r:0|p:0|name.|alpn:10|"
|
||||
},
|
||||
{
|
||||
"single h2 alpn missing last byte",
|
||||
(const unsigned char *)"\x00\x00" /* 16-bit prio */
|
||||
"\x04name\x00" /* RNAME */
|
||||
"\x00\x01" /* RR (1 == ALPN) */
|
||||
"\x00\x03" /* data size */
|
||||
"\x02" /* length byte */
|
||||
"h", /* missing byte */
|
||||
14,
|
||||
"r:8|"
|
||||
},
|
||||
{
|
||||
"two alpns",
|
||||
(const unsigned char *)"\x00\x00" /* 16-bit prio */
|
||||
"\x04name\x04some\x00" /* RNAME */
|
||||
"\x00\x01" /* RR (1 == ALPN) */
|
||||
"\x00\x06" /* data size */
|
||||
"\x02" /* ALPN length byte */
|
||||
"h2"
|
||||
"\x02" /* APLN length byte */
|
||||
"h3",
|
||||
23,
|
||||
"r:0|p:0|name.some.|alpn:10|alpn:20|"
|
||||
},
|
||||
{
|
||||
"wrong syntax alpns",
|
||||
(const unsigned char *)"\x00\x00" /* 16-bit prio */
|
||||
"\x04name\x04some\x00" /* RNAME */
|
||||
"\x00\x01" /* RR (1 == ALPN) */
|
||||
"\x00\x06" /* data size */
|
||||
"\x02" /* ALPN length byte */
|
||||
"h2"
|
||||
"\x03" /* APLN length byte (WRONG) */
|
||||
"h3",
|
||||
23,
|
||||
"r:61|"
|
||||
},
|
||||
{
|
||||
"five alpns (ignore dupes)", /* we only support four */
|
||||
(const unsigned char *)"\x00\x00" /* 16-bit prio */
|
||||
"\x04name\x04some\x00" /* RNAME */
|
||||
"\x00\x01" /* RR (1 == ALPN) */
|
||||
"\x00\x0f" /* data size */
|
||||
"\x02" /* ALPN length byte */
|
||||
"h2"
|
||||
"\x02" /* ALPN length byte */
|
||||
"h2"
|
||||
"\x02" /* ALPN length byte */
|
||||
"h2"
|
||||
"\x02" /* ALPN length byte */
|
||||
"h2"
|
||||
"\x02" /* APLN length byte */
|
||||
"h3",
|
||||
32,
|
||||
"r:0|p:0|name.some.|alpn:10|alpn:20|"
|
||||
},
|
||||
{
|
||||
"rname only",
|
||||
(const unsigned char *)"\x00\x00" /* 16-bit prio */
|
||||
"\x04name\x04some\x00", /* RNAME */
|
||||
13,
|
||||
"r:0|p:0|name.some.|"
|
||||
},
|
||||
{
|
||||
"rname with low ascii byte",
|
||||
(const unsigned char *)"\x00\x00" /* 16-bit prio */
|
||||
"\x04name\x04som\x03\x00", /* RNAME */
|
||||
13,
|
||||
"r:8|"
|
||||
},
|
||||
{
|
||||
"rname with null byte",
|
||||
(const unsigned char *)"\x00\x00" /* 16-bit prio */
|
||||
"\x04sa\x00e\x04some\x00", /* RNAME */
|
||||
13,
|
||||
"r:27|"
|
||||
},
|
||||
{
|
||||
"rname only (missing byte)",
|
||||
(const unsigned char *)"\x00\x00" /* 16-bit prio */
|
||||
"\x04name\x05some\x00", /* RNAME */
|
||||
/* it lacks a byte */
|
||||
13,
|
||||
"r:27|"
|
||||
},
|
||||
{
|
||||
"unrecognized alpn",
|
||||
(const unsigned char *)"\x00\x00" /* 16-bit prio */
|
||||
"\x04name\x04some\x00" /* RNAME */
|
||||
"\x00\x01" /* RR (1 == ALPN) */
|
||||
"\x00\x06" /* data size */
|
||||
"\x02" /* ALPN length byte */
|
||||
"h8" /* unrecognized */
|
||||
"\x02" /* APLN length byte */
|
||||
"h1",
|
||||
23,
|
||||
"r:0|p:0|name.some.|alpn:8|"
|
||||
},
|
||||
{
|
||||
"alnt + no-default-alpn",
|
||||
(const unsigned char *)"\x00\x00" /* 16-bit prio */
|
||||
"\x04name\x04some\x00" /* RNAME */
|
||||
"\x00\x01" /* RR (1 == ALPN) */
|
||||
"\x00\x03" /* data size */
|
||||
"\x02" /* ALPN length byte */
|
||||
"h2"
|
||||
"\x00\x02" /* RR (2 == NO DEFALT ALPN) */
|
||||
"\x00\x00", /* must be zero */
|
||||
24,
|
||||
"r:0|p:0|name.some.|alpn:10|no-def-alpn|"
|
||||
},
|
||||
{
|
||||
"alnt + no-default-alpn with size",
|
||||
(const unsigned char *)"\x00\x00" /* 16-bit prio */
|
||||
"\x04name\x04some\x00" /* RNAME */
|
||||
"\x00\x01" /* RR (1 == ALPN) */
|
||||
"\x00\x03" /* data size */
|
||||
"\x02" /* ALPN length byte */
|
||||
"h2"
|
||||
"\x00\x02" /* RR (2 == NO DEFALT ALPN) */
|
||||
"\x00\x01" /* must be zero */
|
||||
"\xff",
|
||||
25,
|
||||
"r:43|"
|
||||
},
|
||||
{
|
||||
"alnt + no-default-alpn with size too short package",
|
||||
(const unsigned char *)"\x00\x00" /* 16-bit prio */
|
||||
"\x04name\x04some\x00" /* RNAME */
|
||||
"\x00\x01" /* RR (1 == ALPN) */
|
||||
"\x00\x03" /* data size */
|
||||
"\x02" /* ALPN length byte */
|
||||
"h2"
|
||||
"\x00\x02" /* RR (2 == NO DEFALT ALPN) */
|
||||
"\x00\x01", /* must be zero */
|
||||
/* missing last byte in the packet */
|
||||
24,
|
||||
"r:8|"
|
||||
},
|
||||
{
|
||||
"rname + blank alpn field",
|
||||
(const unsigned char *)"\x11\x11" /* 16-bit prio */
|
||||
"\x04name\x04some\x00" /* RNAME */
|
||||
"\x00\x01" /* RR (1 == ALPN) */
|
||||
"\x00\x00", /* data size, strictly speaking this is illegal:
|
||||
"one or more alpn-ids" */
|
||||
17,
|
||||
"r:0|p:4369|name.some.|"
|
||||
},
|
||||
{
|
||||
"no rname + blank alpn",
|
||||
(const unsigned char *)"\x00\x11" /* 16-bit prio */
|
||||
"\x00" /* no RNAME */
|
||||
"\x00\x01" /* RR (1 == ALPN) */
|
||||
"\x00\x00", /* data size */
|
||||
7,
|
||||
"r:0|p:17|.|"
|
||||
},
|
||||
{
|
||||
"unsupported field",
|
||||
(const unsigned char *)"\xff\xff" /* 16-bit prio */
|
||||
"\x00" /* no RNAME */
|
||||
"\x00\x07" /* RR (7 == not a supported data) */
|
||||
"\x00\x02" /* data size */
|
||||
"FF", /* unknown to curl */
|
||||
9,
|
||||
"r:0|p:65535|.|"
|
||||
},
|
||||
{
|
||||
"unsupported field (wrong size)",
|
||||
(const unsigned char *)"\xff\xff" /* 16-bit prio */
|
||||
"\x00" /* no RNAME */
|
||||
"\x00\x07" /* RR (7 == not a supported data) */
|
||||
"\x00\x02" /* data size */
|
||||
"F", /* unknown to curl */
|
||||
8,
|
||||
"r:8|"
|
||||
},
|
||||
{
|
||||
"port number",
|
||||
(const unsigned char *)"\x00\x10" /* 16-bit prio */
|
||||
"\x00" /* no RNAME */
|
||||
"\x00\x01" /* RR (1 == ALPN) */
|
||||
"\x00\x03" /* data size */
|
||||
"\x02" /* ALPN length byte */
|
||||
"h2"
|
||||
"\x00\x03" /* RR (3 == PORT) */
|
||||
"\x00\x02" /* data size */
|
||||
"\x12\x34", /* port number */
|
||||
16,
|
||||
"r:0|p:16|.|alpn:10|port:4660|"
|
||||
},
|
||||
{
|
||||
"port number with wrong size (3 bytes)",
|
||||
(const unsigned char *)"\x00\x10" /* 16-bit prio */
|
||||
"\x00" /* no RNAME */
|
||||
"\x00\x01" /* RR (1 == ALPN) */
|
||||
"\x00\x03" /* data size */
|
||||
"\x02" /* ALPN length byte */
|
||||
"h2"
|
||||
"\x00\x03" /* RR (3 == PORT) */
|
||||
"\x00\x03" /* data size */
|
||||
"\x12\x34\x00", /* 24 bit port number! */
|
||||
17,
|
||||
"r:43|"
|
||||
},
|
||||
{
|
||||
"port number with wrong size (1 byte)",
|
||||
(const unsigned char *)"\x00\x10" /* 16-bit prio */
|
||||
"\x00" /* no RNAME */
|
||||
"\x00\x01" /* RR (1 == ALPN) */
|
||||
"\x00\x03" /* data size */
|
||||
"\x02" /* ALPN length byte */
|
||||
"h2"
|
||||
"\x00\x03" /* RR (3 == PORT) */
|
||||
"\x00\x01" /* data size */
|
||||
"\x12", /* 8 bit port number! */
|
||||
15,
|
||||
"r:43|"
|
||||
},
|
||||
{
|
||||
"alpn + two ipv4 addreses",
|
||||
(const unsigned char *)"\x00\x10" /* 16-bit prio */
|
||||
"\x00" /* no RNAME */
|
||||
"\x00\x01" /* RR (1 == ALPN) */
|
||||
"\x00\x03" /* data size */
|
||||
"\x02" /* ALPN length byte */
|
||||
"h2"
|
||||
"\x00\x04" /* RR (4 == Ipv4hints) */
|
||||
"\x00\x08" /* data size */
|
||||
"\xc0\xa8\x00\x01" /* 32 bits */
|
||||
"\xc0\xa8\x00\x02", /* 32 bits */
|
||||
22,
|
||||
"r:0|p:16|.|alpn:10|ipv4:192.168.0.1|ipv4:192.168.0.2|"
|
||||
},
|
||||
{
|
||||
"alpn + two ipv4 addreses in wrong order",
|
||||
(const unsigned char *)"\x00\x10" /* 16-bit prio */
|
||||
"\x00" /* no RNAME */
|
||||
"\x00\x04" /* RR (4 == Ipv4hints) */
|
||||
"\x00\x08" /* data size */
|
||||
"\xc0\xa8\x00\x01" /* 32 bits */
|
||||
"\xc0\xa8\x00\x02" /* 32 bits */
|
||||
"\x00\x01" /* RR (1 == ALPN) */
|
||||
"\x00\x03" /* data size */
|
||||
"\x02" /* ALPN length byte */
|
||||
"h2",
|
||||
22,
|
||||
"r:8|"
|
||||
},
|
||||
{
|
||||
"alpn + ipv4 address with wrong size",
|
||||
(const unsigned char *)"\x00\x10" /* 16-bit prio */
|
||||
"\x00" /* no RNAME */
|
||||
"\x00\x01" /* RR (1 == ALPN) */
|
||||
"\x00\x03" /* data size */
|
||||
"\x02" /* ALPN length byte */
|
||||
"h2"
|
||||
"\x00\x04" /* RR (4 == Ipv4hints) */
|
||||
"\x00\x05" /* data size */
|
||||
"\xc0\xa8\x00\x01\xff", /* 32 + 8 bits */
|
||||
19,
|
||||
"r:43|"
|
||||
},
|
||||
{
|
||||
"alpn + one ipv6 address",
|
||||
(const unsigned char *)"\x00\x10" /* 16-bit prio */
|
||||
"\x00" /* no RNAME */
|
||||
"\x00\x01" /* RR (1 == ALPN) */
|
||||
"\x00\x03" /* data size */
|
||||
"\x02" /* ALPN length byte */
|
||||
"h2"
|
||||
"\x00\x06" /* RR (6 == Ipv6hints) */
|
||||
"\x00\x10" /* data size */
|
||||
"\xfe\x80\xda\xbb\xc1\xff\xfe\xa3\x8a\x22\x12\x34\x56\x78\x91\x23",
|
||||
30,
|
||||
"r:0|p:16|.|alpn:10|ipv6:fe80:dabb:c1ff:fea3:8a22:1234:5678:9123|"
|
||||
},
|
||||
{
|
||||
"alpn + one ipv6 address with wrong size",
|
||||
(const unsigned char *)"\x00\x10" /* 16-bit prio */
|
||||
"\x00" /* no RNAME */
|
||||
"\x00\x01" /* RR (1 == ALPN) */
|
||||
"\x00\x03" /* data size */
|
||||
"\x02" /* ALPN length byte */
|
||||
"h2"
|
||||
"\x00\x06" /* RR (6 == Ipv6hints) */
|
||||
"\x00\x11" /* data size */
|
||||
"\xfe\x80\xda\xbb\xc1\xff\xfe\xa3\x8a\x22\x12\x34\x56\x78\x91\x23\x45",
|
||||
31,
|
||||
"r:43|"
|
||||
},
|
||||
{
|
||||
"alpn + two ipv6 addresses",
|
||||
(const unsigned char *)"\x00\x10" /* 16-bit prio */
|
||||
"\x00" /* no RNAME */
|
||||
"\x00\x01" /* RR (1 == ALPN) */
|
||||
"\x00\x03" /* data size */
|
||||
"\x02" /* ALPN length byte */
|
||||
"h2"
|
||||
"\x00\x06" /* RR (6 == Ipv6hints) */
|
||||
"\x00\x20" /* data size */
|
||||
"\xfe\x80\xda\xbb\xc1\xff\xfe\xa3\x8a\x22\x12\x34\x56\x78\x91\x23"
|
||||
"\xee\x80\xda\xbb\xc1\xff\xfe\xa3\x8a\x22\x12\x34\x56\x78\x91\x25",
|
||||
46,
|
||||
"r:0|p:16|.|alpn:10|ipv6:fe80:dabb:c1ff:fea3:8a22:1234:5678:9123|"
|
||||
"ipv6:ee80:dabb:c1ff:fea3:8a22:1234:5678:9125|"
|
||||
},
|
||||
{
|
||||
"alpn + ech",
|
||||
(const unsigned char *)"\x00\x10" /* 16-bit prio */
|
||||
"\x00" /* no RNAME */
|
||||
"\x00\x01" /* RR (1 == ALPN) */
|
||||
"\x00\x03" /* data size */
|
||||
"\x02" /* ALPN length byte */
|
||||
"h2"
|
||||
"\x00\x05" /* RR (5 == ECH) */
|
||||
"\x00\x10" /* data size */
|
||||
"\xfe\x80\xda\xbb\xc1\xff\xfe\xa3\x8a\x22\x12\x34\x56\x78\x91\x23",
|
||||
30,
|
||||
"r:0|p:16|.|alpn:10|ech:fe80dabbc1fffea38a22123456789123|"
|
||||
},
|
||||
{
|
||||
"fully packed",
|
||||
(const unsigned char *)"\xa0\x0b" /* 16-bit prio */
|
||||
"\x00" /* no RNAME */
|
||||
"\x00\x00" /* RR (0 == MANDATORY) */
|
||||
"\x00\x00" /* data size */
|
||||
"\x00\x01" /* RR (1 == ALPN) */
|
||||
"\x00\x06" /* data size */
|
||||
"\x02" /* ALPN length byte */
|
||||
"h2"
|
||||
"\x02" /* ALPN length byte */
|
||||
"h1"
|
||||
"\x00\x02" /* RR (2 == NO DEFALT ALPN) */
|
||||
"\x00\x00" /* must be zero */
|
||||
"\x00\x03" /* RR (3 == PORT) */
|
||||
"\x00\x02" /* data size */
|
||||
"\xbc\x71" /* port number */
|
||||
"\x00\x04" /* RR (4 == Ipv4hints) */
|
||||
"\x00\x08" /* data size */
|
||||
"\xc0\xa8\x00\x01" /* 32 bits */
|
||||
"\xc0\xa8\x00\x02" /* 32 bits */
|
||||
"\x00\x05" /* RR (5 == ECH) */
|
||||
"\x00\x10" /* data size */
|
||||
"\xfe\x80\xda\xbb\xc1\xff\x7e\xb3\x8a\x22\x12\x34\x56\x78\x91\x23"
|
||||
"\x00\x06" /* RR (6 == Ipv6hints) */
|
||||
"\x00\x20" /* data size */
|
||||
"\xfe\x80\xda\xbb\xc1\xff\xfe\xa3\x8a\x22\x12\x34\x56\x78\x91\x23"
|
||||
"\xee\x80\xda\xbb\xc1\xff\xfe\xa3\x8a\x22\x12\x34\x56\x78\x91\x25"
|
||||
"\x01\x07" /* RR (263 == not supported) */
|
||||
"\x00\x04" /* data size */
|
||||
"FFAA", /* unknown to the world */
|
||||
103,
|
||||
"r:0|p:40971|.|alpn:10|alpn:8|no-def-alpn|port:48241|"
|
||||
"ipv4:192.168.0.1|ipv4:192.168.0.2|"
|
||||
"ech:fe80dabbc1ff7eb38a22123456789123|"
|
||||
"ipv6:fe80:dabb:c1ff:fea3:8a22:1234:5678:9123|"
|
||||
"ipv6:ee80:dabb:c1ff:fea3:8a22:1234:5678:9125|"
|
||||
}
|
||||
};
|
||||
|
||||
CURLcode result = CURLE_OUT_OF_MEMORY;
|
||||
CURL *easy;
|
||||
|
||||
easy = curl_easy_init();
|
||||
/* so that we get the log output: */
|
||||
curl_easy_setopt(easy, CURLOPT_VERBOSE, 1L);
|
||||
if(easy) {
|
||||
unsigned int i;
|
||||
|
||||
for(i = 0; i < CURL_ARRAYSIZE(t); i++) {
|
||||
struct Curl_https_rrinfo *hrr;
|
||||
|
||||
printf("test %i: %s\n", i, t[i].name);
|
||||
|
||||
result = doh_resp_decode_httpsrr(easy, t[i].dns, t[i].len, &hrr);
|
||||
|
||||
/* create an output */
|
||||
rrresults(hrr, result);
|
||||
|
||||
/* is the output the expected? */
|
||||
if(strcmp(rrbuffer, t[i].expect)) {
|
||||
fprintf(stderr, "Test %s (%i) failed\n"
|
||||
"Expected: %s\n"
|
||||
"Received: %s\n", t[i].name, i, t[i].expect, rrbuffer);
|
||||
unitfail++;
|
||||
}
|
||||
|
||||
/* free the generated struct */
|
||||
if(hrr) {
|
||||
Curl_httpsrr_cleanup(hrr);
|
||||
curl_free(hrr);
|
||||
}
|
||||
}
|
||||
curl_easy_cleanup(easy);
|
||||
}
|
||||
}
|
||||
UNITTEST_STOP
|
||||
|
||||
#else /* CURL_DISABLE_DOH or not HTTPSRR enabled */
|
||||
|
||||
UNITTEST_START
|
||||
/* nothing to do, just succeed */
|
||||
UNITTEST_STOP
|
||||
|
||||
#endif
|
||||
Loading…
Reference in New Issue
Block a user