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 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 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} 289UNITTEST_STOP 290 291#else /* CURL_DISABLE_DOH */ 292UNITTEST_START 293/* nothing to do, just succeed */ 294UNITTEST_STOP 295 296 297#endif 298