blob: ae748a971717a13198625d0597099b116766ce16 [file] [log] [blame]
xf.li6c8fc1e2023-08-12 00:11:09 -07001/***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 2018 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al.
9 *
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at https://curl.se/docs/copyright.html.
13 *
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 * SPDX-License-Identifier: curl
22 *
23 ***************************************************************************/
24#include "curlcheck.h"
25
26#include "doh.h"
27#include "dynbuf.h"
28
29static CURLcode unit_setup(void)
30{
31 return CURLE_OK;
32}
33
34static void unit_stop(void)
35{
36
37}
38
39#ifndef CURL_DISABLE_DOH
40#define DNS_PREAMBLE "\x00\x00\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00"
41#define LABEL_TEST "\x04\x74\x65\x73\x74"
42#define LABEL_HOST "\x04\x68\x6f\x73\x74"
43#define LABEL_NAME "\x04\x6e\x61\x6d\x65"
44#define DNSA_TYPE "\x01"
45#define DNSAAAA_TYPE "\x1c"
46#define DNSA_EPILOGUE "\x00\x00" DNSA_TYPE "\x00\x01"
47#define DNSAAAA_EPILOGUE "\x00\x00" DNSAAAA_TYPE "\x00\x01"
48
49#define DNS_Q1 DNS_PREAMBLE LABEL_TEST LABEL_HOST LABEL_NAME DNSA_EPILOGUE
50#define DNS_Q2 DNS_PREAMBLE LABEL_TEST LABEL_HOST LABEL_NAME DNSAAAA_EPILOGUE
51
52struct dohrequest {
53 /* input */
54 const char *name;
55 DNStype type;
56
57 /* output */
58 const char *packet;
59 size_t size;
60 int rc;
61};
62
63
64static const struct dohrequest req[] = {
65 {"test.host.name", DNS_TYPE_A, DNS_Q1, sizeof(DNS_Q1)-1, 0 },
66 {"test.host.name", DNS_TYPE_AAAA, DNS_Q2, sizeof(DNS_Q2)-1, 0 },
67 {"zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz"
68 ".host.name",
69 DNS_TYPE_AAAA, NULL, 0, DOH_DNS_BAD_LABEL }
70};
71
72struct dohresp {
73 /* input */
74 const char *packet;
75 size_t size;
76 DNStype type;
77
78 /* output */
79 int rc;
80 const char *out;
81};
82
83#define DNS_FOO_EXAMPLE_COM \
84 "\x00\x00\x01\x00\x00\x01\x00\x01\x00\x00\x00\x00\x03\x66\x6f\x6f" \
85 "\x07\x65\x78\x61\x6d\x70\x6c\x65\x03\x63\x6f\x6d\x00\x00\x01\x00" \
86 "\x01\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\x37\x00\x04\x7f\x00\x00" \
87 "\x01"
88
89static const char full49[] = DNS_FOO_EXAMPLE_COM;
90
91static const struct dohresp resp[] = {
92 {"\x00\x00", 2, DNS_TYPE_A, DOH_TOO_SMALL_BUFFER, NULL },
93 {"\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01", 12,
94 DNS_TYPE_A, DOH_DNS_BAD_ID, NULL },
95 {"\x00\x00\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01", 12,
96 DNS_TYPE_A, DOH_DNS_BAD_RCODE, NULL },
97 {"\x00\x00\x01\x00\x00\x01\x00\x01\x00\x00\x00\x00\x03\x66\x6f\x6f", 16,
98 DNS_TYPE_A, DOH_DNS_OUT_OF_RANGE, NULL },
99 {"\x00\x00\x01\x00\x00\x01\x00\x01\x00\x00\x00\x00\x03\x66\x6f\x6f\x00", 17,
100 DNS_TYPE_A, DOH_DNS_OUT_OF_RANGE, NULL },
101 {"\x00\x00\x01\x00\x00\x01\x00\x01\x00\x00\x00\x00\x03\x66\x6f\x6f\x00"
102 "\x00\x01\x00\x01", 21,
103 DNS_TYPE_A, DOH_DNS_OUT_OF_RANGE, NULL },
104 {"\x00\x00\x01\x00\x00\x01\x00\x01\x00\x00\x00\x00\x03\x66\x6f\x6f\x00"
105 "\x00\x01\x00\x01"
106 "\x04", 18,
107 DNS_TYPE_A, DOH_DNS_OUT_OF_RANGE, NULL },
108
109 {"\x00\x00\x01\x00\x00\x01\x00\x01\x00\x00\x00\x00\x04\x63\x75\x72"
110 "\x6c\x04\x63\x75\x72\x6c\x00\x00\x05\x00\x01\xc0\x0c\x00\x05\x00"
111 "\x01\x00\x00\x00\x37\x00\x11\x08\x61\x6e\x79\x77\x68\x65\x72\x65"
112 "\x06\x72\x65\x61\x6c\x6c\x79\x00", 56,
113 DNS_TYPE_A, DOH_OK, "anywhere.really "},
114
115 {DNS_FOO_EXAMPLE_COM, 49, DNS_TYPE_A, DOH_OK, "127.0.0.1 "},
116
117 {"\x00\x00\x01\x00\x00\x01\x00\x01\x00\x00\x00\x00\x04\x61\x61\x61"
118 "\x61\x07\x65\x78\x61\x6d\x70\x6c\x65\x03\x63\x6f\x6d\x00\x00\x1c"
119 "\x00\x01\xc0\x0c\x00\x1c\x00\x01\x00\x00\x00\x37\x00\x10\x20\x20"
120 "\x20\x20\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\x20", 62,
121 DNS_TYPE_AAAA, DOH_OK,
122 "2020:2020:0000:0000:0000:0000:0000:2020 " },
123
124 {"\x00\x00\x01\x00\x00\x01\x00\x01\x00\x00\x00\x00\x04\x63\x75\x72"
125 "\x6c\x04\x63\x75\x72\x6c\x00\x00\x05\x00\x01\xc0\x0c\x00\x05\x00"
126 "\x01\x00\x00\x00\x37\x00"
127 "\x07\x03\x61\x6e\x79\xc0\x27\x00", 46,
128 DNS_TYPE_A, DOH_DNS_LABEL_LOOP, NULL},
129
130 /* packet with NSCOUNT == 1 */
131 {"\x00\x00\x01\x00\x00\x01\x00\x01\x00\x01\x00\x00\x04\x61\x61\x61"
132 "\x61\x07\x65\x78\x61\x6d\x70\x6c\x65\x03\x63\x6f\x6d\x00\x00\x1c"
133 "\x00\x01\xc0\x0c\x00\x1c\x00\x01\x00\x00\x00\x37\x00\x10\x20\x20"
134 "\x20\x20\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\x20"
135 LABEL_TEST LABEL_HOST LABEL_NAME DNSAAAA_EPILOGUE "\x00\x00\x00\x01"
136 "\00\x04\x01\x01\x01\x01", /* RDDATA */
137
138 62 + 30,
139 DNS_TYPE_AAAA, DOH_OK,
140 "2020:2020:0000:0000:0000:0000:0000:2020 " },
141
142 /* packet with ARCOUNT == 1 */
143 {"\x00\x00\x01\x00\x00\x01\x00\x01\x00\x00\x00\x01\x04\x61\x61\x61"
144 "\x61\x07\x65\x78\x61\x6d\x70\x6c\x65\x03\x63\x6f\x6d\x00\x00\x1c"
145 "\x00\x01\xc0\x0c\x00\x1c\x00\x01\x00\x00\x00\x37\x00\x10\x20\x20"
146 "\x20\x20\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\x20"
147 LABEL_TEST LABEL_HOST LABEL_NAME DNSAAAA_EPILOGUE "\x00\x00\x00\x01"
148 "\00\x04\x01\x01\x01\x01", /* RDDATA */
149
150 62 + 30,
151 DNS_TYPE_AAAA, DOH_OK,
152 "2020:2020:0000:0000:0000:0000:0000:2020 " },
153
154};
155
156UNITTEST_START
157{
158 size_t size = 0;
159 unsigned char buffer[256];
160 size_t i;
161 unsigned char *p;
162 for(i = 0; i < sizeof(req) / sizeof(req[0]); i++) {
163 int rc = doh_encode(req[i].name, req[i].type,
164 buffer, sizeof(buffer), &size);
165 if(rc != req[i].rc) {
166 fprintf(stderr, "req %zu: Expected return code %d got %d\n", i,
167 req[i].rc, rc);
168 return 1;
169 }
170 else if(size != req[i].size) {
171 fprintf(stderr, "req %zu: Expected size %zu got %zu\n", i,
172 req[i].size, size);
173 fprintf(stderr, "DNS encode made: %s\n", hexdump(buffer, size));
174 return 2;
175 }
176 else if(req[i].packet && memcmp(req[i].packet, buffer, size)) {
177 fprintf(stderr, "DNS encode made: %s\n", hexdump(buffer, size));
178 fprintf(stderr, "... instead of: %s\n",
179 hexdump((unsigned char *)req[i].packet, size));
180 return 3;
181 }
182 }
183
184 for(i = 0; i < sizeof(resp) / sizeof(resp[0]); i++) {
185 struct dohentry d;
186 int rc;
187 char *ptr;
188 size_t len;
189 int u;
190 de_init(&d);
191 rc = doh_decode((const unsigned char *)resp[i].packet, resp[i].size,
192 resp[i].type, &d);
193 if(rc != resp[i].rc) {
194 fprintf(stderr, "resp %zu: Expected return code %d got %d\n", i,
195 resp[i].rc, rc);
196 return 4;
197 }
198 len = sizeof(buffer);
199 ptr = (char *)buffer;
200 for(u = 0; u < d.numaddr; u++) {
201 size_t o;
202 struct dohaddr *a;
203 a = &d.addr[u];
204 if(resp[i].type == DNS_TYPE_A) {
205 p = &a->ip.v4[0];
206 msnprintf(ptr, len, "%u.%u.%u.%u ", p[0], p[1], p[2], p[3]);
207 o = strlen(ptr);
208 len -= o;
209 ptr += o;
210 }
211 else {
212 int j;
213 for(j = 0; j < 16; j += 2) {
214 size_t l;
215 msnprintf(ptr, len, "%s%02x%02x", j?":":"", a->ip.v6[j],
216 a->ip.v6[j + 1]);
217 l = strlen(ptr);
218 len -= l;
219 ptr += l;
220 }
221 msnprintf(ptr, len, " ");
222 len--;
223 ptr++;
224 }
225 }
226 for(u = 0; u < d.numcname; u++) {
227 size_t o;
228 msnprintf(ptr, len, "%s ", Curl_dyn_ptr(&d.cname[u]));
229 o = strlen(ptr);
230 len -= o;
231 ptr += o;
232 }
233 de_cleanup(&d);
234 if(resp[i].out && strcmp((char *)buffer, resp[i].out)) {
235 fprintf(stderr, "resp %zu: Expected %s got %s\n", i,
236 resp[i].out, buffer);
237 return 1;
238 }
239 }
240
241 {
242 /* pass all sizes into the decoder until full */
243 for(i = 0; i < sizeof(full49)-1; i++) {
244 struct dohentry d;
245 int rc;
246 memset(&d, 0, sizeof(d));
247 rc = doh_decode((const unsigned char *)full49, i, DNS_TYPE_A, &d);
248 if(!rc) {
249 /* none of them should work */
250 fprintf(stderr, "%zu: %d\n", i, rc);
251 return 5;
252 }
253 }
254 /* and try all pieces from the other end of the packet */
255 for(i = 1; i < sizeof(full49); i++) {
256 struct dohentry d;
257 int rc;
258 memset(&d, 0, sizeof(d));
259 rc = doh_decode((const unsigned char *)&full49[i], sizeof(full49)-i-1,
260 DNS_TYPE_A, &d);
261 if(!rc) {
262 /* none of them should work */
263 fprintf(stderr, "2 %zu: %d\n", i, rc);
264 return 7;
265 }
266 }
267 {
268 int rc;
269 struct dohentry d;
270 struct dohaddr *a;
271 memset(&d, 0, sizeof(d));
272 rc = doh_decode((const unsigned char *)full49, sizeof(full49)-1,
273 DNS_TYPE_A, &d);
274 fail_if(d.numaddr != 1, "missing address");
275 a = &d.addr[0];
276 p = &a->ip.v4[0];
277 msnprintf((char *)buffer, sizeof(buffer),
278 "%u.%u.%u.%u", p[0], p[1], p[2], p[3]);
279 if(rc || strcmp((char *)buffer, "127.0.0.1")) {
280 fprintf(stderr, "bad address decoded: %s, rc == %d\n", buffer, rc);
281 return 7;
282 }
283 fail_if(d.numcname, "bad cname counter");
284 }
285 }
286}
287UNITTEST_STOP
288
289#else /* CURL_DISABLE_DOH */
290UNITTEST_START
291{
292 return 1; /* nothing to do, just fail */
293}
294UNITTEST_STOP
295
296
297#endif