1 /***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 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
unit_setup(void)29 static CURLcode unit_setup(void)
30 {
31 return CURLE_OK;
32 }
33
unit_stop(void)34 static 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
52 struct 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
64 static 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
72 struct 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
89 static const char full49[] = DNS_FOO_EXAMPLE_COM;
90
91 static 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
156 UNITTEST_START
157 {
158 size_t size = 0;
159 unsigned char buffer[256];
160 size_t i;
161 unsigned char *p;
162
163 for(i = 0; i < sizeof(req) / sizeof(req[0]); i++) {
164 int rc = doh_encode(req[i].name, req[i].type,
165 buffer, sizeof(buffer), &size);
166 if(rc != req[i].rc) {
167 fprintf(stderr, "req %zu: Expected return code %d got %d\n", i,
168 req[i].rc, rc);
169 abort_if(rc != req[i].rc, "return code");
170 }
171 if(size != req[i].size) {
172 fprintf(stderr, "req %zu: Expected size %zu got %zu\n", i,
173 req[i].size, size);
174 fprintf(stderr, "DNS encode made: %s\n", hexdump(buffer, size));
175 abort_if(size != req[i].size, "size");
176 }
177 if(req[i].packet && memcmp(req[i].packet, buffer, size)) {
178 fprintf(stderr, "DNS encode made: %s\n", hexdump(buffer, size));
179 fprintf(stderr, "... instead of: %s\n",
180 hexdump((unsigned char *)req[i].packet, size));
181 abort_if(req[i].packet && memcmp(req[i].packet, buffer, size),
182 "contents");
183 }
184 }
185
186 for(i = 0; i < sizeof(resp) / sizeof(resp[0]); i++) {
187 struct dohentry d;
188 int rc;
189 char *ptr;
190 size_t len;
191 int u;
192 de_init(&d);
193 rc = doh_decode((const unsigned char *)resp[i].packet, resp[i].size,
194 resp[i].type, &d);
195 if(rc != resp[i].rc) {
196 fprintf(stderr, "resp %zu: Expected return code %d got %d\n", i,
197 resp[i].rc, rc);
198 abort_if(rc != resp[i].rc, "return code");
199 }
200 len = sizeof(buffer);
201 ptr = (char *)buffer;
202 for(u = 0; u < d.numaddr; u++) {
203 size_t o;
204 struct dohaddr *a;
205 a = &d.addr[u];
206 if(resp[i].type == DNS_TYPE_A) {
207 p = &a->ip.v4[0];
208 msnprintf(ptr, len, "%u.%u.%u.%u ", p[0], p[1], p[2], p[3]);
209 o = strlen(ptr);
210 len -= o;
211 ptr += o;
212 }
213 else {
214 int j;
215 for(j = 0; j < 16; j += 2) {
216 size_t l;
217 msnprintf(ptr, len, "%s%02x%02x", j?":":"", a->ip.v6[j],
218 a->ip.v6[j + 1]);
219 l = strlen(ptr);
220 len -= l;
221 ptr += l;
222 }
223 msnprintf(ptr, len, " ");
224 len--;
225 ptr++;
226 }
227 }
228 for(u = 0; u < d.numcname; u++) {
229 size_t o;
230 msnprintf(ptr, len, "%s ", Curl_dyn_ptr(&d.cname[u]));
231 o = strlen(ptr);
232 len -= o;
233 ptr += o;
234 }
235 de_cleanup(&d);
236 if(resp[i].out && strcmp((char *)buffer, resp[i].out)) {
237 fprintf(stderr, "resp %zu: Expected %s got %s\n", i,
238 resp[i].out, buffer);
239 abort_if(resp[i].out && strcmp((char *)buffer, resp[i].out), "content");
240 }
241 }
242
243 /* pass all sizes into the decoder until full */
244 for(i = 0; i < sizeof(full49)-1; i++) {
245 struct dohentry d;
246 int rc;
247 memset(&d, 0, sizeof(d));
248 rc = doh_decode((const unsigned char *)full49, i, DNS_TYPE_A, &d);
249 if(!rc) {
250 /* none of them should work */
251 fprintf(stderr, "%zu: %d\n", i, rc);
252 abort_if(!rc, "error rc");
253 }
254 }
255
256 /* and try all pieces from the other end of the packet */
257 for(i = 1; i < sizeof(full49); i++) {
258 struct dohentry d;
259 int rc;
260 memset(&d, 0, sizeof(d));
261 rc = doh_decode((const unsigned char *)&full49[i], sizeof(full49)-i-1,
262 DNS_TYPE_A, &d);
263 if(!rc) {
264 /* none of them should work */
265 fprintf(stderr, "2 %zu: %d\n", i, rc);
266 abort_if(!rc, "error rc");
267 }
268 }
269
270 {
271 int rc;
272 struct dohentry d;
273 struct dohaddr *a;
274 memset(&d, 0, sizeof(d));
275 rc = doh_decode((const unsigned char *)full49, sizeof(full49)-1,
276 DNS_TYPE_A, &d);
277 fail_if(d.numaddr != 1, "missing address");
278 a = &d.addr[0];
279 p = &a->ip.v4[0];
280 msnprintf((char *)buffer, sizeof(buffer),
281 "%u.%u.%u.%u", p[0], p[1], p[2], p[3]);
282 if(rc || strcmp((char *)buffer, "127.0.0.1")) {
283 fprintf(stderr, "bad address decoded: %s, rc == %d\n", buffer, rc);
284 abort_if(rc || strcmp((char *)buffer, "127.0.0.1"), "bad address");
285 }
286 fail_if(d.numcname, "bad cname counter");
287 }
288 }
289 UNITTEST_STOP
290
291 #else /* CURL_DISABLE_DOH */
292 UNITTEST_START
293 /* nothing to do, just succeed */
294 UNITTEST_STOP
295
296
297 #endif
298