From: Daniel Stenberg Date: Thu, 5 Jun 2025 20:59:24 +0000 (+0200) Subject: tests/dnsd: read config from file X-Git-Tag: curl-8_15_0~179 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=aed828cc5171aeb53d613847b469c2a0160dd3c4;p=thirdparty%2Fcurl.git tests/dnsd: read config from file Make the tag in a test case control what is stored there. Also documented. Make test 2102 and 2103 use the new tag. Lets the test case config the A and AAAA contents the server replies with. Initial work for the HTTPS RR exists, but does not yet work. Closes #17543 --- diff --git a/docs/tests/FILEFORMAT.md b/docs/tests/FILEFORMAT.md index 062329d211..98b09ed3a0 100644 --- a/docs/tests/FILEFORMAT.md +++ b/docs/tests/FILEFORMAT.md @@ -383,6 +383,14 @@ issue. `writedelay: [secs]` delay this amount between reply packets (each packet being 512 bytes payload) +### `` + +Commands for the test DNS server. + +- `A: [dotted ipv4 address]` - set IPv4 address to return +- `AAAA: [numerical IPv6 address]` - set IPv6 address to return, with or + without `[]` + ## `` ### `` diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am index 8e502220f1..f5f83f2b46 100644 --- a/tests/data/Makefile.am +++ b/tests/data/Makefile.am @@ -253,7 +253,7 @@ test2064 test2065 test2066 test2067 test2068 test2069 test2070 test2071 \ test2072 test2073 test2074 test2075 test2076 test2077 test2078 test2079 \ test2080 test2081 test2082 test2083 test2084 test2085 test2086 test2087 \ test2088 test2089 \ -test2100 test2101 test2102 \ +test2100 test2101 test2102 test2103 \ \ test2200 test2201 test2202 test2203 test2204 test2205 \ \ diff --git a/tests/data/test2102 b/tests/data/test2102 index 32b29658dc..5ee35bdf6e 100644 --- a/tests/data/test2102 +++ b/tests/data/test2102 @@ -23,6 +23,10 @@ Funny-head: yesyes -foo- + +A: %HOSTIP +AAAA: %HOST6IP + # diff --git a/tests/data/test2103 b/tests/data/test2103 new file mode 100644 index 0000000000..fd214e57ae --- /dev/null +++ b/tests/data/test2103 @@ -0,0 +1,45 @@ + + + +DNS fail + + + +# +# Server-side + + +A: none +AAAA: none + + + +# +# Client-side + + +dns + + +override-dns + + +HTTP GET with bad host name + + +CURL_DNS_SERVER=127.0.0.1:%DNSPORT + + +http://examplehost.example/%TESTNUMBER + + + +# +# Verify data after the test has been "shot" + +# curl: (6) Could not resolve host: examplehost.example + +6 + + + diff --git a/tests/globalconfig.pm b/tests/globalconfig.pm index 7aabd9d48d..b120250f1b 100644 --- a/tests/globalconfig.pm +++ b/tests/globalconfig.pm @@ -61,6 +61,7 @@ BEGIN { $run_duphandle $run_event_based $SERVERCMD + $DNSCMD $SERVERIN $srcdir $TESTDIR @@ -134,6 +135,7 @@ our $SERVERIN="server.input"; # what curl sent the server our $PROXYIN="proxy.input"; # what curl sent the proxy our $MEMDUMP="memdump"; # file that the memory debugging creates our $SERVERCMD="server.cmd"; # copy server instructions here +our $DNSCMD="dnsd.cmd"; # write DNS instructions here # other config variables our @protocols; # array of lowercase supported protocol servers diff --git a/tests/runner.pm b/tests/runner.pm index 324c49dcf7..36127c7c03 100644 --- a/tests/runner.pm +++ b/tests/runner.pm @@ -750,11 +750,16 @@ sub singletest_prepare { unlink("$LOGDIR/$SERVERIN"); unlink("$LOGDIR/$PROXYIN"); - # if this section exists, it might be FTP server instructions: - my @ftpservercmd = getpart("reply", "servercmd"); - push @ftpservercmd, "Testnum $testnum\n"; + # if this section exists, it might be server instructions: + my @servercmd = getpart("reply", "servercmd"); + push @servercmd, "Testnum $testnum\n"; # write the instructions to file - writearray("$LOGDIR/$SERVERCMD", \@ftpservercmd); + writearray("$LOGDIR/$SERVERCMD", \@servercmd); + + # if this section exists, it might be DNS instructions: + my @dnscmd = getpart("reply", "dns"); + # write the instructions to file + writearray("$LOGDIR/$DNSCMD", \@dnscmd); # provide an environment variable $ENV{'CURL_TESTNUM'} = $testnum; diff --git a/tests/server/Makefile.inc b/tests/server/Makefile.inc index 84b4261dab..82916744b8 100644 --- a/tests/server/Makefile.inc +++ b/tests/server/Makefile.inc @@ -34,6 +34,7 @@ UTILS = getpart.c util.c CURLX_CFILES = \ ../../lib/curlx/base64.c \ ../../lib/curlx/inet_pton.c \ + ../../lib/curlx/inet_ntop.c \ ../../lib/curlx/multibyte.c \ ../../lib/curlx/nonblock.c \ ../../lib/curlx/strparse.c \ diff --git a/tests/server/dnsd.c b/tests/server/dnsd.c index 069a93f33e..3050303760 100644 --- a/tests/server/dnsd.c +++ b/tests/server/dnsd.c @@ -62,6 +62,7 @@ static int qname(const unsigned char **pkt, size_t *size) #define QTYPE_A 1 #define QTYPE_AAAA 28 +#define QTYPE_HTTPS 0x41 /* * Handle initial connection protocol. @@ -142,11 +143,13 @@ static int store_incoming(const unsigned char *data, size_t size, logmsg("Question for '%s' type %x", name, qd); qd = get16bit(&data, &size); - fprintf(server, "QCLASS: %04x\n", qd); + logmsg("QCLASS: %04x\n", qd); *qlen = qsize - size; /* total size of the query */ memcpy(qbuf, qptr, *qlen); } + else + logmsg("Bad input qname"); #if 0 for(i = 0; i < size; i++) { fprintf(server, "%02d", (unsigned int)data[i]); @@ -159,76 +162,6 @@ static int store_incoming(const unsigned char *data, size_t size, return 0; } -#if 0 -static int send_response(curl_socket_t sock, - struct sockaddr *addr, - curl_socklen_t addrlen, - unsigned short id) -{ - ssize_t rc; - unsigned char bytes[] = { - 0x80, 0xea, /* ID, overwrite */ - 0x81, 0x80, - /* - Flags: 0x8180 Standard query response, No error - 1... .... .... .... = Response: Message is a response - .000 0... .... .... = Opcode: Standard query (0) - .... .0.. .... .... = Authoritative: Server is not an authority for - domain - .... ..0. .... .... = Truncated: Message is not truncated - .... ...1 .... .... = Recursion desired: Do query recursively - .... .... 1... .... = Recursion available: Server can do recursive - queries - .... .... .0.. .... = Z: reserved (0) - .... .... ..0. .... = Answer authenticated: Answer/authority portion - was not authenticated by the server - .... .... ...0 .... = Non-authenticated data: Unacceptable - .... .... .... 0000 = Reply code: No error (0) - */ - 0x0, 0x1, /* QDCOUNT */ - 0x0, 0x4, /* ANCOUNT */ - 0x0, 0x0, /* NSCOUNT */ - 0x0, 0x0, /* ARCOUNT */ - - /* here's the question */ - 0x4, 0x63, 0x75, 0x72, 0x6c, 0x2, 0x73, 0x65, 0x0, /* curl.se */ - 0x0, 0x1, /* QTYPE: A */ - 0x0, 0x1, /* QCLASS: IN */ - - /* 4 answers */ - 0xc0, 0xc, /* points to curl.se */ - 0x0, 0x1, /* QTYPE A */ - 0x0, 0x1, /* QCLASS IN */ - 0x0, 0x0, 0xa, 0x14, /* Time to live: 2580 (43 minutes) */ - 0x0, 0x4, /* data length */ - 0x97, 0x65, 0x41, 0x5b, /* Address: 151.101.65.91 */ - - 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0xa, 0x14, - 0x0, 0x4, 0x97, 0x65, 0x81, 0x5b, /* Address: 151.101.129.91 */ - 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0xa, 0x14, - 0x0, 0x4, 0x97, 0x65, 0xc1, 0x5b, /* Address: 151.101.193.91 */ - 0xc0, 0xc, 0x0, 0x1, 0x0, 0x1, 0x0, 0x0, 0xa, 0x14, - 0x0, 0x4, 0x97, 0x65, 0x1, 0x5b, /* Address: 151.101.1.91 */ -#if 0 - /* 1 additional record (ARCOUNT) */ - - 0x0, 0x0, 0x29, 0x4, 0xd0, 0x0, 0x0, - 0x0, 0x0, 0x0, 0x0 -#endif - }; - size_t len = sizeof(bytes); - - bytes[0] = (unsigned char)(id >> 8); - bytes[1] = (unsigned char)(id & 0xff); - - rc = sendto(sock, bytes, len, 0, addr, addrlen); - if(rc != (ssize_t)len) { - fprintf(stderr, "failed sending %d bytes\n", (int)len); - } - return 0; -} -#endif - static void add_answer(unsigned char *bytes, size_t *w, const unsigned char *a, size_t alen, unsigned short qtype) @@ -269,6 +202,17 @@ static void add_answer(unsigned char *bytes, size_t *w, #define SENDTO3 size_t #endif +#define INSTRUCTIONS "dnsd.cmd" + +#define MAX_ALPN 5 + +static unsigned char ipv4_pref[4]; +static unsigned char ipv6_pref[16]; +static unsigned char alpn_pref[MAX_ALPN]; +static int alpn_count; +static unsigned char ancount_a; +static unsigned char ancount_aaaa; + /* this is an answer to a question */ static int send_response(curl_socket_t sock, const struct sockaddr *addr, curl_socklen_t addrlen, @@ -278,7 +222,7 @@ static int send_response(curl_socket_t sock, ssize_t rc; size_t i; int a; - unsigned char ancount = 3; + char addrbuf[128]; /* IP address buffer */ unsigned char bytes[256] = { 0x80, 0xea, /* ID, overwrite */ 0x81, 0x80, @@ -303,14 +247,9 @@ static int send_response(curl_socket_t sock, 0x0, 0x0, /* NSCOUNT */ 0x0, 0x0 /* ARCOUNT */ }; - static const unsigned char ipv4_localhost[] = { 127, 0, 0, 1 }; - static const unsigned char ipv6_localhost[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 - }; bytes[0] = (unsigned char)(id >> 8); bytes[1] = (unsigned char)(id & 0xff); - bytes[7] = ancount; if(qlen > (sizeof(bytes) - 12)) return -1; @@ -320,16 +259,28 @@ static int send_response(curl_socket_t sock, i = 12 + qlen; - for(a = 0; a < ancount; a++) { - switch(qtype) { - case QTYPE_A: - add_answer(bytes, &i, ipv4_localhost, sizeof(ipv4_localhost), QTYPE_A); - break; - case QTYPE_AAAA: - add_answer(bytes, &i, ipv6_localhost, sizeof(ipv6_localhost), - QTYPE_AAAA); - break; + switch(qtype) { + case QTYPE_A: + bytes[7] = ancount_a; + for(a = 0; a < ancount_a; a++) { + const unsigned char *store = ipv4_pref; + add_answer(bytes, &i, store, sizeof(ipv4_pref), QTYPE_A); + logmsg("Sending back A (%x) '%s'", QTYPE_A, + curlx_inet_ntop(AF_INET, store, addrbuf, sizeof(addrbuf))); + } + break; + case QTYPE_AAAA: + bytes[7] = ancount_aaaa; + for(a = 0; a < ancount_aaaa; a++) { + const unsigned char *store = ipv6_pref; + add_answer(bytes, &i, store, sizeof(ipv6_pref), QTYPE_AAAA); + logmsg("Sending back AAAA (%x) '%s'", QTYPE_AAAA, + curlx_inet_ntop(AF_INET6, store, addrbuf, sizeof(addrbuf))); } + break; + case QTYPE_HTTPS: + bytes[7] = 1; /* one answer */ + break; } #ifdef __AMIGA__ @@ -349,6 +300,68 @@ static int send_response(curl_socket_t sock, return 0; } + +static void read_instructions(void) +{ + char file[256]; + FILE *f; + snprintf(file, sizeof(file), "%s/" INSTRUCTIONS, logdir); + f = fopen(file, FOPEN_READTEXT); + if(f) { + char buf[256]; + ancount_aaaa = ancount_a = 0; + alpn_count = 0; + while(fgets(buf, sizeof(buf), f)) { + char *p = strchr(buf, '\n'); + if(p) { + int rc; + *p = 0; + if(!strncmp("A: ", buf, 3)) { + rc = curlx_inet_pton(AF_INET, &buf[3], ipv4_pref); + ancount_a = (rc == 1); + } + else if(!strncmp("AAAA: ", buf, 6)) { + char *p6 = &buf[6]; + if(*p6 == '[') { + char *pt = strchr(p6, ']'); + if(pt) + *pt = 0; + p6++; + } + rc = curlx_inet_pton(AF_INET6, p6, ipv6_pref); + ancount_aaaa = (rc == 1); + } + else if(!strncmp("ALPN: ", buf, 6)) { + char *ap = &buf[6]; + rc = 0; + while(*ap) { + if('h' == *ap) { + ap++; + if(*ap >= '1' && *ap <= '3') { + if(alpn_count < MAX_ALPN) + alpn_pref[alpn_count++] = *ap; + } + else + break; + } + else + break; + } + } + else { + rc = 0; + } + if(rc != 1) { + logmsg("Bad line in %s: '%s'\n", file, buf); + } + } + } + fclose(f); + } + else + logmsg("Error opening file '%s'", file); +} + static int test_dnsd(int argc, char **argv) { srvr_sockaddr_union_t me; @@ -586,6 +599,10 @@ static int test_dnsd(int argc, char **argv) break; } + /* read once per incoming query, which is probably more than one + per test case */ + read_instructions(); + store_incoming(inbuffer, n, qbuf, &qlen, &qtype, &id); set_advisor_read_lock(loglockfile);