Home | History | Annotate | Line # | Download | only in ServiceRegistration
      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