1 /* fromwire.c 2 * 3 * Copyright (c) 2018-2021 Apple Inc. All rights reserved. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * https://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 * DNS wire-format functions. 18 * 19 * These are really simple functions for constructing DNS messages wire format. 20 * The flow is that there is a transaction structure which contains pointers to both 21 * a message output buffer and a response input buffer. The structure is initialized, 22 * and then the various wire format functions are called repeatedly to store data. 23 * If an error occurs during this process, it's okay to just keep going, because the 24 * error is recorded in the transaction; once all of the copy-in functions have been 25 * called, the error status can be checked once at the end. 26 */ 27 28 #include <stdio.h> 29 #include <unistd.h> 30 #include <string.h> 31 #include <errno.h> 32 #include <sys/socket.h> 33 #include <arpa/inet.h> 34 #include <stdlib.h> 35 #include <ctype.h> 36 #include "srp.h" 37 #include "dns-msg.h" 38 39 bool 40 dns_opt_parse(dns_edns0_t *NONNULL *NULLABLE ret, dns_rr_t *rr) 41 { 42 dns_edns0_t *edns0, **p_edns0 = ret; 43 unsigned offset = 0; 44 dns_rdata_unparsed_t opt; 45 46 // This would be a weird coding error. 47 if (rr->type != dns_rrtype_opt) { 48 return false; 49 } 50 opt = rr->data.unparsed; 51 52 // RDATA is a series of TLVs 53 while (offset < opt.len) { 54 uint16_t tlv_type, tlv_len; 55 56 // Parse the TLV type and length. 57 if (!dns_u16_parse(opt.data, opt.len, &offset, &tlv_type) || 58 !dns_u16_parse(opt.data, opt.len, &offset, &tlv_len)) 59 { 60 return false; 61 } 62 63 // Range check the contents. 64 if (offset + tlv_len > opt.len) { 65 return false; 66 } 67 68 edns0 = calloc(1, tlv_len + sizeof(*edns0)); 69 if (edns0 == NULL) { 70 return false; 71 } 72 // Stash the record. 73 edns0->length = tlv_len; 74 edns0->type = tlv_type; 75 memcpy(edns0->data, &opt.data[offset], tlv_len); 76 *p_edns0 = edns0; 77 p_edns0 = &edns0->next; 78 offset += tlv_len; 79 } 80 return true; 81 } 82 83 dns_label_t * NULLABLE 84 dns_label_parse_(const uint8_t *buf, unsigned mlen, unsigned *NONNULL offp, const char *file, int line) 85 { 86 uint8_t llen = buf[*offp]; 87 dns_label_t *rv; 88 89 // Make sure that we got the data this label claims to encompass. 90 if (*offp + llen + 1 > mlen) { 91 DEBUG("claimed length of label is too long: %u > %u.\n", *offp + llen + 1, mlen); 92 return NULL; 93 } 94 95 #ifdef MALLOC_DEBUG_LOGGING 96 rv = debug_calloc(1, (sizeof(*rv) - DNS_MAX_LABEL_SIZE) + llen + 1, file, line); 97 #else 98 (void)file; (void)line; 99 rv = calloc(1, (sizeof(*rv) - DNS_MAX_LABEL_SIZE) + llen + 1); 100 #endif 101 if (rv == NULL) { 102 DEBUG("memory allocation for %u byte label (%.*s) failed.\n", 103 *offp + llen + 1, *offp + llen + 1, &buf[*offp + 1]); 104 return NULL; 105 } 106 107 rv->len = llen; 108 memcpy(rv->data, &buf[*offp + 1], llen); 109 rv->data[llen] = 0; // We NUL-terminate the label for convenience 110 *offp += llen + 1; 111 return rv; 112 } 113 114 static bool 115 dns_name_parse_in(dns_label_t *NONNULL *NULLABLE ret, const uint8_t *buf, unsigned len, 116 unsigned *NONNULL offp, unsigned base, const char *file, int line) 117 { 118 dns_label_t *rv; 119 120 if (*offp == len) { 121 return false; 122 } 123 124 // A pointer? 125 if ((buf[*offp] & 0xC0) == 0xC0) { 126 unsigned pointer; 127 if (*offp + 2 > len) { 128 DEBUG("incomplete compression pointer: %u > %u", *offp + 2, len); 129 return false; 130 } 131 pointer = (((unsigned)buf[*offp] & 0x3f) << 8) | (unsigned)buf[*offp + 1]; 132 *offp += 2; 133 if (pointer < DNS_HEADER_SIZE) { 134 // Don't allow pointers into the header. 135 DEBUG("compression pointer points into header: %u.\n", pointer); 136 return false; 137 } 138 pointer -= DNS_HEADER_SIZE; 139 if (pointer >= base) { 140 // Don't allow a pointer forward, or to a pointer we've already visited. 141 DEBUG("compression pointer points forward: %u >= %u.\n", pointer, base); 142 return false; 143 } 144 if (buf[pointer] & 0xC0) { 145 // If this is a pointer to a pointer, it's not valid. 146 DEBUG("compression pointer points into pointer: %u %02x%02x.\n", pointer, 147 buf[pointer], pointer + 1 < len ? buf[pointer + 1] : 0xFF); 148 return false; 149 } 150 if (buf[pointer] + pointer >= base || buf[pointer] + pointer >= *offp) { 151 // Possibly this isn't worth checking. 152 DEBUG("compression pointer points to something that goes past current position: %u %u\n", 153 pointer, buf[pointer]); 154 return false; 155 } 156 return dns_name_parse_in(ret, buf, len, &pointer, pointer, file, line); 157 } 158 // We don't support binary labels, which are historical, and at this time there are no other valid 159 // DNS label types. 160 if (buf[*offp] & 0xC0) { 161 DEBUG("invalid label type: %x\n", buf[*offp]); 162 return false; 163 } 164 165 rv = dns_label_parse_(buf, len, offp, file, line); 166 if (rv == NULL) { 167 return false; 168 } 169 170 *ret = rv; 171 172 if (rv->len == 0) { 173 return true; 174 } 175 return dns_name_parse_in(&rv->next, buf, len, offp, base, file, line); 176 } 177 178 bool 179 dns_name_parse_(dns_label_t *NONNULL *NULLABLE ret, const uint8_t *buf, 180 unsigned len, unsigned *NONNULL offp, unsigned base, const char *file, int line) 181 { 182 dns_label_t *rv = NULL, *next; 183 184 if (!dns_name_parse_in(&rv, buf, len, offp, base, file, line)) { 185 for (; rv != NULL; rv = next) { 186 next = rv->next; 187 free(rv); 188 } 189 return false; 190 } 191 *ret = rv; 192 return true; 193 } 194 195 bool 196 dns_u8_parse(const uint8_t *buf, unsigned len, unsigned *NONNULL offp, uint8_t *NONNULL ret) 197 { 198 uint8_t rv; 199 if (*offp + 1 > len) { 200 DEBUG("dns_u8_parse: not enough room: %u > %u.\n", *offp + 1, len); 201 return false; 202 } 203 204 rv = buf[*offp]; 205 *offp += 1; 206 *ret = rv; 207 return true; 208 } 209 210 bool 211 dns_u16_parse(const uint8_t *buf, unsigned len, unsigned *NONNULL offp, uint16_t *NONNULL ret) 212 { 213 uint16_t rv; 214 if (*offp + 2 > len) { 215 DEBUG("dns_u16_parse: not enough room: %u > %u.\n", *offp + 2, len); 216 return false; 217 } 218 219 rv = (uint16_t)(buf[*offp] << 8) | (uint16_t)(buf[*offp + 1]); 220 *offp += 2; 221 *ret = rv; 222 return true; 223 } 224 225 bool 226 dns_u32_parse(const uint8_t *buf, unsigned len, unsigned *NONNULL offp, uint32_t *NONNULL ret) 227 { 228 uint32_t rv; 229 if (*offp + 4 > len) { 230 DEBUG("dns_u32_parse: not enough room: %u > %u.\n", *offp + 4, len); 231 return false; 232 } 233 234 rv = (((uint32_t)(buf[*offp]) << 24) | ((uint32_t)(buf[*offp + 1]) << 16) | 235 ((uint32_t)(buf[*offp + 2]) << 8) | (uint32_t)(buf[*offp + 3])); 236 *offp += 4; 237 *ret = rv; 238 return true; 239 } 240 241 bool 242 dns_u64_parse(const uint8_t *buf, unsigned len, unsigned *NONNULL offp, uint64_t *NONNULL ret) 243 { 244 uint64_t rv; 245 if (*offp + 8 > len) { 246 DEBUG("dns_u64_parse: not enough room: %u > %u.\n", *offp + 8, len); 247 return false; 248 } 249 250 rv = (((uint64_t)(buf[*offp] ) << 56) | ((uint64_t)(buf[*offp + 1]) << 48) | 251 ((uint64_t)(buf[*offp + 2]) << 40) | ((uint64_t)(buf[*offp + 3]) << 32) | 252 ((uint64_t)(buf[*offp + 4]) << 24) | ((uint64_t)(buf[*offp + 5]) << 16) | 253 ((uint64_t)(buf[*offp + 6]) << 8) | ((uint64_t)(buf[*offp + 7]))); 254 *offp += 8; 255 *ret = rv; 256 return true; 257 } 258 259 static void 260 dns_rrdata_dump(dns_rr_t *rr, bool dump_to_stderr) 261 { 262 char outbuf[2048]; 263 264 dns_rdata_dump_to_buf(rr, outbuf, sizeof(outbuf)); 265 266 if (dump_to_stderr) { 267 fprintf(stderr, "%s\n", outbuf); 268 } else { 269 DEBUG(PUB_S_SRP, outbuf); 270 } 271 } 272 273 size_t 274 dns_rdata_dump_to_buf(dns_rr_t *rr, char *outbuf, size_t bufsize) 275 { 276 char nbuf[INET6_ADDRSTRLEN]; 277 char buf[DNS_MAX_NAME_SIZE_ESCAPED + 1]; 278 size_t output_len, avail = bufsize; 279 char *obp; 280 281 obp = outbuf; 282 avail = bufsize; 283 284 #define ADVANCE(result, start, remaining) \ 285 output_len = strlen(start); \ 286 result = start + output_len; \ 287 avail = (remaining) - output_len 288 #define DEPCHAR(ch) \ 289 do { \ 290 if (avail > 1) { \ 291 *obp++ = (ch); \ 292 *obp = 0; \ 293 --avail; \ 294 } \ 295 } while (0) 296 297 switch(rr->type) { 298 case dns_rrtype_key: 299 snprintf(outbuf, bufsize, 300 "KEY <AC %d> <Z %d> <XT %d> <ZZ %d> <NAMTYPE %d> <ZZZZ %d> <ORY %d> %d %d ", 301 ((rr->data.key.flags & 0xC000) >> 14 & 3), ((rr->data.key.flags & 0x2000) >> 13) & 1, 302 ((rr->data.key.flags & 0x1000) >> 12) & 1, ((rr->data.key.flags & 0xC00) >> 10) & 3, 303 ((rr->data.key.flags & 0x300) >> 8) & 3, ((rr->data.key.flags & 0xF0) >> 4) & 15, 304 rr->data.key.flags & 15, rr->data.key.protocol, rr->data.key.algorithm); 305 ADVANCE(obp, outbuf, bufsize); 306 307 for (unsigned i = 0; i < rr->data.key.len; i++) { 308 if (i == 0) { 309 snprintf(obp, avail, "%d [%02x", rr->data.key.len, rr->data.key.key[i]); 310 ADVANCE(obp, obp, avail); 311 } else { 312 snprintf(obp, avail, " %02x", rr->data.key.key[i]); 313 ADVANCE(obp, obp, avail); 314 } 315 } 316 DEPCHAR(']'); 317 break; 318 319 case dns_rrtype_sig: 320 dns_name_print(rr->data.sig.signer, buf, sizeof(buf)); 321 snprintf(outbuf, bufsize, "SIG %d %d %d %lu %lu %lu %d %s", 322 rr->data.sig.type, rr->data.sig.algorithm, rr->data.sig.label, 323 (unsigned long)rr->data.sig.rrttl, (unsigned long)rr->data.sig.expiry, 324 (unsigned long)rr->data.sig.inception, rr->data.sig.key_tag, buf); 325 ADVANCE(obp, outbuf, bufsize); 326 for (unsigned i = 0; i < rr->data.sig.len; i++) { 327 if (i == 0) { 328 snprintf(obp, avail, "%d [%02x", rr->data.sig.len, rr->data.sig.signature[i]); 329 ADVANCE(obp, obp, avail); 330 } else { 331 snprintf(obp, avail, " %02x", rr->data.sig.signature[i]); 332 ADVANCE(obp, obp, avail); 333 } 334 } 335 DEPCHAR(']'); 336 break; 337 338 case dns_rrtype_srv: 339 dns_name_print(rr->data.srv.name, buf, sizeof(buf)); 340 snprintf(outbuf, bufsize, "SRV %d %d %d %s", rr->data.srv.priority, rr->data.srv.weight, 341 rr->data.srv.port, buf); 342 ADVANCE(obp, outbuf, bufsize); 343 break; 344 345 case dns_rrtype_ptr: 346 dns_name_print(rr->data.ptr.name, buf, sizeof(buf)); 347 snprintf(outbuf, bufsize, "PTR %s", buf); 348 ADVANCE(obp, outbuf, bufsize); 349 break; 350 351 case dns_rrtype_cname: 352 dns_name_print(rr->data.cname.name, buf, sizeof(buf)); 353 snprintf(outbuf, bufsize, "CNAME %s", buf); 354 ADVANCE(obp, outbuf, bufsize); 355 break; 356 357 case dns_rrtype_soa: 358 dns_name_print(rr->data.soa.mname, buf, sizeof(buf)); 359 snprintf(outbuf, bufsize, "SOA %s", buf); 360 ADVANCE(obp, outbuf, bufsize); 361 dns_name_print(rr->data.soa.rname, buf, sizeof(buf)); 362 snprintf(outbuf, bufsize, "%s %u %d %d %d %d", buf, rr->data.soa.serial, rr->data.soa.refresh, 363 rr->data.soa.retry, rr->data.soa.expire, rr->data.soa.minimum); 364 ADVANCE(obp, outbuf, bufsize); 365 break; 366 367 case dns_rrtype_a: 368 inet_ntop(AF_INET, &rr->data.a, nbuf, sizeof(nbuf)); 369 snprintf(outbuf, bufsize, "A %s", nbuf); 370 ADVANCE(obp, outbuf, bufsize); 371 break; 372 373 case dns_rrtype_aaaa: 374 inet_ntop(AF_INET6, &rr->data.aaaa, nbuf, sizeof(nbuf)); 375 snprintf(outbuf, bufsize, "AAAA %s", nbuf); 376 ADVANCE(obp, outbuf, bufsize); 377 break; 378 379 case dns_rrtype_txt: 380 strcpy(outbuf, "TXT "); 381 ADVANCE(obp, outbuf, bufsize); 382 for (unsigned i = 0; i < rr->data.txt.len; i++) { 383 if (isascii(rr->data.txt.data[i]) && isprint(rr->data.txt.data[i])) { 384 DEPCHAR(rr->data.txt.data[i]); 385 } else { 386 snprintf(obp, avail, "<%x>", rr->data.txt.data[i]); 387 ADVANCE(obp, obp, avail); 388 } 389 } 390 DEPCHAR('"'); 391 break; 392 393 default: 394 snprintf(outbuf, bufsize, "<rrtype %d>:", rr->type); 395 ADVANCE(obp, outbuf, bufsize); 396 if (rr->data.unparsed.len == 0) { 397 snprintf(obp, avail, " <none>"); 398 ADVANCE(obp, obp, avail); 399 } else { 400 for (unsigned i = 0; i < rr->data.unparsed.len; i++) { 401 snprintf(obp, avail, " %02x", rr->data.unparsed.data[i]); 402 ADVANCE(obp, obp, avail); 403 } 404 } 405 break; 406 } 407 *obp = 0; 408 return obp - buf; 409 } 410 411 bool 412 dns_rdata_parse_data_(dns_rr_t *NONNULL rr, const uint8_t *buf, unsigned *NONNULL offp, unsigned target, uint16_t rdlen, 413 unsigned rrstart, const char *file, int line) 414 { 415 if (target < *offp) { 416 DEBUG("target %u < *offp %u", target, *offp); 417 return false; 418 } 419 switch(rr->type) { 420 case dns_rrtype_key: 421 if (!dns_u16_parse(buf, target, offp, &rr->data.key.flags) || 422 !dns_u8_parse(buf, target, offp, &rr->data.key.protocol) || 423 !dns_u8_parse(buf, target, offp, &rr->data.key.algorithm)) { 424 return false; 425 } 426 rr->data.key.len = (unsigned)(target - *offp); 427 #ifdef MALLOC_DEBUG_LOGGING 428 rr->data.key.key = debug_malloc(rr->data.key.len, file, line); 429 #else 430 rr->data.key.key = malloc(rr->data.key.len); 431 #endif 432 if (!rr->data.key.key) { 433 return false; 434 } 435 memcpy(rr->data.key.key, &buf[*offp], rr->data.key.len); 436 *offp += rr->data.key.len; 437 break; 438 439 case dns_rrtype_sig: 440 rr->data.sig.start = rrstart; 441 if (!dns_u16_parse(buf, target, offp, &rr->data.sig.type) || 442 !dns_u8_parse(buf, target, offp, &rr->data.sig.algorithm) || 443 !dns_u8_parse(buf, target, offp, &rr->data.sig.label) || 444 !dns_u32_parse(buf, target, offp, &rr->data.sig.rrttl) || 445 !dns_u32_parse(buf, target, offp, &rr->data.sig.expiry) || 446 !dns_u32_parse(buf, target, offp, &rr->data.sig.inception) || 447 !dns_u16_parse(buf, target, offp, &rr->data.sig.key_tag) || 448 !dns_name_parse_(&rr->data.sig.signer, buf, target, offp, *offp, file, line)) { 449 return false; 450 } 451 // The signature is what's left of the RRDATA. It covers the message up to the signature, so we 452 // remember where it starts so as to know what memory to cover to validate it. 453 rr->data.sig.len = target - *offp; 454 #ifdef MALLOC_DEBUG_LOGGING 455 rr->data.sig.signature = debug_malloc(rr->data.sig.len, file, line); 456 #else 457 rr->data.sig.signature = malloc(rr->data.sig.len); 458 #endif 459 if (!rr->data.sig.signature) { 460 return false; 461 } 462 memcpy(rr->data.sig.signature, &buf[*offp], rr->data.sig.len); 463 *offp += rr->data.sig.len; 464 break; 465 466 case dns_rrtype_srv: 467 if (!dns_u16_parse(buf, target, offp, &rr->data.srv.priority) || 468 !dns_u16_parse(buf, target, offp, &rr->data.srv.weight) || 469 !dns_u16_parse(buf, target, offp, &rr->data.srv.port)) 470 { 471 return false; 472 } 473 // This fallthrough assumes that the first element in the srv, ptr and cname structs is 474 // a pointer to a domain name. 475 476 case dns_rrtype_ns: 477 case dns_rrtype_ptr: 478 case dns_rrtype_cname: 479 if (!dns_name_parse_(&rr->data.ptr.name, buf, target, offp, *offp, file, line)) { 480 return false; 481 } 482 break; 483 484 case dns_rrtype_soa: 485 if (!dns_name_parse_(&rr->data.soa.mname, buf, target, offp, *offp, file, line)) { 486 return false; 487 } 488 if (!dns_name_parse_(&rr->data.soa.rname, buf, target, offp, *offp, file, line)) { 489 return false; 490 } 491 if (!dns_u32_parse(buf, target, offp, &rr->data.soa.serial) || 492 !dns_u32_parse(buf, target, offp, &rr->data.soa.refresh) || 493 !dns_u32_parse(buf, target, offp, &rr->data.soa.retry) || 494 !dns_u32_parse(buf, target, offp, &rr->data.soa.expire) || 495 !dns_u32_parse(buf, target, offp, &rr->data.soa.minimum)) 496 { 497 return false; 498 } 499 break; 500 501 case dns_rrtype_a: 502 if (rdlen != 4) { 503 DEBUG("dns_rdata_parse: A rdlen is not 4: %u", rdlen); 504 return false; 505 } 506 memcpy(&rr->data.a, &buf[*offp], rdlen); 507 *offp = target; 508 break; 509 510 case dns_rrtype_aaaa: 511 if (rdlen != 16) { 512 DEBUG("dns_rdata_parse: AAAA rdlen is not 16: %u", rdlen); 513 return false; 514 } 515 memcpy(&rr->data.aaaa, &buf[*offp], rdlen); 516 *offp = target; 517 break; 518 519 case dns_rrtype_txt: 520 { 521 unsigned left = target - *offp; 522 if (left != rdlen) { 523 ERROR("TXT record length %u doesn't match remaining space %d", rdlen, left); 524 } 525 if (left > UINT8_MAX) { 526 ERROR("TXT record length %u is longer than 255", left); 527 } 528 rr->data.txt.len = (uint8_t)left; 529 #ifdef MALLOC_DEBUG_LOGGING 530 rr->data.txt.data = debug_malloc(rr->data.txt.len, file, line); 531 #else 532 rr->data.txt.data = malloc(rr->data.txt.len); 533 #endif 534 if (rr->data.txt.data == NULL) { 535 DEBUG("dns_rdata_parse: no memory for TXT RR"); 536 return false; 537 } 538 memcpy(rr->data.txt.data, &buf[*offp], rr->data.txt.len); 539 *offp = target; 540 break; 541 } 542 543 default: 544 if (rdlen > 0) { 545 #ifdef MALLOC_DEBUG_LOGGING 546 rr->data.unparsed.data = debug_malloc(rdlen, file, line); 547 #else 548 rr->data.unparsed.data = malloc(rdlen); 549 #endif 550 if (rr->data.unparsed.data == NULL) { 551 return false; 552 } 553 memcpy(rr->data.unparsed.data, &buf[*offp], rdlen); 554 } 555 rr->data.unparsed.len = rdlen; 556 *offp = target; 557 break; 558 } 559 if (*offp != target) { 560 DEBUG("dns_rdata_parse: parse for rrtype %d not fully contained: %u %u", rr->type, target, *offp); 561 return false; 562 } 563 return true; 564 } 565 566 static bool 567 dns_rdata_parse_(dns_rr_t *NONNULL rr, 568 const uint8_t *buf, unsigned len, unsigned *NONNULL offp, unsigned rrstart, const char *file, int line) 569 { 570 uint16_t rdlen; 571 unsigned target; 572 573 if (!dns_u16_parse(buf, len, offp, &rdlen)) { 574 return false; 575 } 576 target = *offp + rdlen; 577 if (target > len) { 578 return false; 579 } 580 return dns_rdata_parse_data_(rr, buf, offp, target, rdlen, rrstart, file, line); 581 } 582 583 bool 584 dns_rr_parse_(dns_rr_t *NONNULL rr, const uint8_t *buf, unsigned len, unsigned *NONNULL offp, bool rrdata_expected, 585 bool dump_stderr, const char *file, int line) 586 { 587 unsigned rrstart = *offp; // Needed to mark the start of the SIG RR for SIG(0). 588 589 memset(rr, 0, sizeof(*rr)); 590 if (!dns_name_parse_(&rr->name, buf, len, offp, *offp, file, line)) { 591 return false; 592 } 593 594 if (!dns_u16_parse(buf, len, offp, &rr->type)) { 595 return false; 596 } 597 598 if (!dns_u16_parse(buf, len, offp, &rr->qclass)) { 599 return false; 600 } 601 602 if (rrdata_expected) { 603 if (!dns_u32_parse(buf, len, offp, &rr->ttl)) { 604 return false; 605 } 606 if (!dns_rdata_parse_(rr, buf, len, offp, rrstart, file, line)) { 607 return false; 608 } 609 } 610 611 DNS_NAME_GEN_SRP(rr->name, name_buf); 612 if (dump_stderr) { 613 fprintf(stderr, "rrtype: %u qclass: %u name: %s %s\n", 614 rr->type, rr->qclass, DNS_NAME_PARAM_SRP(rr->name, name_buf), rrdata_expected ? " rrdata:" : ""); 615 } else { 616 DEBUG("rrtype: %u qclass: %u name: " PRI_DNS_NAME_SRP PUB_S_SRP, 617 rr->type, rr->qclass, DNS_NAME_PARAM_SRP(rr->name, name_buf), rrdata_expected ? " rrdata:" : ""); 618 } 619 if (rrdata_expected) { 620 dns_rrdata_dump(rr, dump_stderr); 621 } 622 return true; 623 } 624 625 void 626 dns_rrdata_free(dns_rr_t *rr) 627 { 628 if (rr == NULL) { 629 return; 630 } 631 switch(rr->type) { 632 case dns_rrtype_a: 633 case dns_rrtype_aaaa: 634 break; 635 636 case dns_rrtype_key: 637 free(rr->data.key.key); 638 break; 639 640 case dns_rrtype_sig: 641 dns_name_free(rr->data.sig.signer); 642 free(rr->data.sig.signature); 643 break; 644 645 case dns_rrtype_srv: 646 case dns_rrtype_ptr: 647 case dns_rrtype_ns: 648 case dns_rrtype_cname: 649 dns_name_free(rr->data.ptr.name); 650 #ifndef __clang_analyzer__ 651 rr->data.ptr.name = NULL; 652 #endif 653 break; 654 655 case dns_rrtype_soa: 656 if (rr->data.soa.mname != NULL) { 657 dns_name_free(rr->data.soa.mname); 658 } 659 if (rr->data.soa.rname != NULL) { 660 dns_name_free(rr->data.soa.rname); 661 } 662 break; 663 664 case dns_rrtype_txt: 665 free(rr->data.txt.data); 666 #ifndef __clang_analyzer__ 667 rr->data.txt.data = NULL; 668 #endif 669 break; 670 671 default: 672 if (rr->data.unparsed.len > 0 && rr->data.unparsed.data != NULL) { 673 free(rr->data.unparsed.data); 674 } 675 rr->data.unparsed.data = NULL; 676 } 677 } 678 679 void 680 dns_message_free(dns_message_t *message) 681 { 682 dns_edns0_t *edns0, *next; 683 684 #define FREE(count, sets) \ 685 if (message->sets) { \ 686 for (unsigned i = 0; i < message->count; i++) { \ 687 dns_rr_t *set = &message->sets[i]; \ 688 if (set->type == dns_invalid_rr) { \ 689 continue; \ 690 } \ 691 if (set->name) { \ 692 dns_name_free(set->name); \ 693 } \ 694 dns_rrdata_free(set); \ 695 } \ 696 free(message->sets); \ 697 } 698 FREE(qdcount, questions); 699 FREE(ancount, answers); 700 FREE(nscount, authority); 701 FREE(arcount, additional); 702 #undef FREE 703 for (edns0 = message->edns0; edns0 != NULL; edns0 = next) { 704 next = edns0->next; 705 free(edns0); 706 } 707 free(message); 708 } 709 710 bool 711 dns_wire_parse_(dns_message_t *NONNULL *NULLABLE ret, dns_wire_t *message, unsigned len, bool dump_to_stderr, 712 const char *file, int line) 713 { 714 unsigned offset = 0; 715 unsigned data_len = len - DNS_HEADER_SIZE; 716 dns_message_t *rv; 717 718 if (len < DNS_HEADER_SIZE) { 719 return false; 720 } 721 #ifdef MALLOC_DEBUG_LOGGING 722 rv = debug_calloc(1, sizeof(*rv), file, line); 723 #else 724 rv = calloc(1, sizeof(*rv)); 725 #endif 726 if (rv == NULL) { 727 return false; 728 } 729 730 #define PARSE(count, sets, name, rrdata_expected) \ 731 rv->count = ntohs(message->count); \ 732 if (rv->count > 50) { \ 733 rv->count = 0; \ 734 dns_message_free(rv); \ 735 return false; \ 736 } \ 737 DEBUG("Section %s, %d records", name, rv->count); \ 738 \ 739 if (rv->count != 0) { \ 740 rv->sets = calloc(rv->count, sizeof(*rv->sets)); \ 741 if (rv->sets == NULL) { \ 742 dns_message_free(rv); \ 743 return false; \ 744 } \ 745 } \ 746 \ 747 for (unsigned i = 0; i < rv->count; i++) { \ 748 if (!dns_rr_parse_(&rv->sets[i], message->data, data_len, &offset, \ 749 rrdata_expected, dump_to_stderr, file, line)) { \ 750 dns_message_free(rv); \ 751 ERROR(name " %d RR parse failed.\n", i); \ 752 return false; \ 753 } \ 754 } 755 PARSE(qdcount, questions, "question", false); 756 PARSE(ancount, answers, "answers", true); 757 PARSE(nscount, authority, "authority", true); 758 PARSE(arcount, additional, "additional", true); 759 #undef PARSE 760 761 for (unsigned i = 0; i < rv->arcount; i++) { 762 // Parse EDNS(0) 763 if (rv->additional[i].type == dns_rrtype_opt) { 764 if (!dns_opt_parse(&rv->edns0, &rv->additional[i])) { 765 dns_message_free(rv); 766 return false; 767 } 768 } 769 } 770 *ret = rv; 771 return true; 772 } 773 774 // Local Variables: 775 // mode: C 776 // tab-width: 4 777 // c-file-style: "bsd" 778 // c-basic-offset: 4 779 // fill-column: 108 780 // indent-tabs-mode: nil 781 // End: 782