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