quickjs-tart

quickjs-based runtime for wallet-core logic
Log | Files | Refs | README | LICENSE

ares_dns_write.c (35667B)


      1 /* MIT License
      2  *
      3  * Copyright (c) 2023 Brad House
      4  *
      5  * Permission is hereby granted, free of charge, to any person obtaining a copy
      6  * of this software and associated documentation files (the "Software"), to deal
      7  * in the Software without restriction, including without limitation the rights
      8  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
      9  * copies of the Software, and to permit persons to whom the Software is
     10  * furnished to do so, subject to the following conditions:
     11  *
     12  * The above copyright notice and this permission notice (including the next
     13  * paragraph) shall be included in all copies or substantial portions of the
     14  * Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     22  * SOFTWARE.
     23  *
     24  * SPDX-License-Identifier: MIT
     25  */
     26 #include "ares_private.h"
     27 #include <limits.h>
     28 #ifdef HAVE_STDINT_H
     29 #  include <stdint.h>
     30 #endif
     31 
     32 
     33 static ares_status_t ares_dns_write_header(const ares_dns_record_t *dnsrec,
     34                                            ares_buf_t              *buf)
     35 {
     36   unsigned short u16;
     37   unsigned short opcode;
     38   unsigned short rcode;
     39 
     40   ares_status_t  status;
     41 
     42   /* ID */
     43   status = ares_buf_append_be16(buf, dnsrec->id);
     44   if (status != ARES_SUCCESS) {
     45     return status; /* LCOV_EXCL_LINE: OutOfMemory */
     46   }
     47 
     48   /* Flags */
     49   u16 = 0;
     50 
     51   /* QR */
     52   if (dnsrec->flags & ARES_FLAG_QR) {
     53     u16 |= 0x8000;
     54   }
     55 
     56   /* OPCODE */
     57   opcode   = (unsigned short)(dnsrec->opcode & 0xF);
     58   opcode <<= 11;
     59   u16     |= opcode;
     60 
     61   /* AA */
     62   if (dnsrec->flags & ARES_FLAG_AA) {
     63     u16 |= 0x400;
     64   }
     65 
     66   /* TC */
     67   if (dnsrec->flags & ARES_FLAG_TC) {
     68     u16 |= 0x200;
     69   }
     70 
     71   /* RD */
     72   if (dnsrec->flags & ARES_FLAG_RD) {
     73     u16 |= 0x100;
     74   }
     75 
     76   /* RA */
     77   if (dnsrec->flags & ARES_FLAG_RA) {
     78     u16 |= 0x80;
     79   }
     80 
     81   /* Z -- unused */
     82 
     83   /* AD */
     84   if (dnsrec->flags & ARES_FLAG_AD) {
     85     u16 |= 0x20;
     86   }
     87 
     88   /* CD */
     89   if (dnsrec->flags & ARES_FLAG_CD) {
     90     u16 |= 0x10;
     91   }
     92 
     93   /* RCODE */
     94   if (dnsrec->rcode > 15 && ares_dns_get_opt_rr_const(dnsrec) == NULL) {
     95     /* Must have OPT RR in order to write extended error codes */
     96     rcode = ARES_RCODE_SERVFAIL;
     97   } else {
     98     rcode = (unsigned short)(dnsrec->rcode & 0xF);
     99   }
    100   u16 |= rcode;
    101 
    102   status = ares_buf_append_be16(buf, u16);
    103   if (status != ARES_SUCCESS) {
    104     return status; /* LCOV_EXCL_LINE: OutOfMemory */
    105   }
    106 
    107   /* QDCOUNT */
    108   status = ares_buf_append_be16(
    109     buf, (unsigned short)ares_dns_record_query_cnt(dnsrec));
    110   if (status != ARES_SUCCESS) {
    111     return status; /* LCOV_EXCL_LINE: OutOfMemory */
    112   }
    113 
    114   /* ANCOUNT */
    115   status = ares_buf_append_be16(
    116     buf, (unsigned short)ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_ANSWER));
    117   if (status != ARES_SUCCESS) {
    118     return status; /* LCOV_EXCL_LINE: OutOfMemory */
    119   }
    120 
    121   /* NSCOUNT */
    122   status = ares_buf_append_be16(buf, (unsigned short)ares_dns_record_rr_cnt(
    123                                        dnsrec, ARES_SECTION_AUTHORITY));
    124   if (status != ARES_SUCCESS) {
    125     return status; /* LCOV_EXCL_LINE: OutOfMemory */
    126   }
    127 
    128   /* ARCOUNT */
    129   status = ares_buf_append_be16(buf, (unsigned short)ares_dns_record_rr_cnt(
    130                                        dnsrec, ARES_SECTION_ADDITIONAL));
    131   if (status != ARES_SUCCESS) {
    132     return status; /* LCOV_EXCL_LINE: OutOfMemory */
    133   }
    134 
    135   return ARES_SUCCESS;
    136 }
    137 
    138 static ares_status_t ares_dns_write_questions(const ares_dns_record_t *dnsrec,
    139                                               ares_llist_t           **namelist,
    140                                               ares_buf_t              *buf)
    141 {
    142   size_t i;
    143 
    144   for (i = 0; i < ares_dns_record_query_cnt(dnsrec); i++) {
    145     ares_status_t       status;
    146     const char         *name = NULL;
    147     ares_dns_rec_type_t qtype;
    148     ares_dns_class_t    qclass;
    149 
    150     status = ares_dns_record_query_get(dnsrec, i, &name, &qtype, &qclass);
    151     if (status != ARES_SUCCESS) {
    152       return status;
    153     }
    154 
    155     /* Name */
    156     status = ares_dns_name_write(buf, namelist, ARES_TRUE, name);
    157     if (status != ARES_SUCCESS) {
    158       return status;
    159     }
    160 
    161     /* Type */
    162     status = ares_buf_append_be16(buf, (unsigned short)qtype);
    163     if (status != ARES_SUCCESS) {
    164       return status; /* LCOV_EXCL_LINE: OutOfMemory */
    165     }
    166 
    167     /* Class */
    168     status = ares_buf_append_be16(buf, (unsigned short)qclass);
    169     if (status != ARES_SUCCESS) {
    170       return status; /* LCOV_EXCL_LINE: OutOfMemory */
    171     }
    172   }
    173 
    174   return ARES_SUCCESS;
    175 }
    176 
    177 static ares_status_t ares_dns_write_rr_name(ares_buf_t          *buf,
    178                                             const ares_dns_rr_t *rr,
    179                                             ares_llist_t       **namelist,
    180                                             ares_bool_t       validate_hostname,
    181                                             ares_dns_rr_key_t key)
    182 {
    183   const char *name;
    184 
    185   name = ares_dns_rr_get_str(rr, key);
    186   if (name == NULL) {
    187     return ARES_EFORMERR; /* LCOV_EXCL_LINE: DefensiveCoding */
    188   }
    189 
    190   return ares_dns_name_write(buf, namelist, validate_hostname, name);
    191 }
    192 
    193 static ares_status_t ares_dns_write_rr_str(ares_buf_t          *buf,
    194                                            const ares_dns_rr_t *rr,
    195                                            ares_dns_rr_key_t    key)
    196 {
    197   const char   *str;
    198   size_t        len;
    199   ares_status_t status;
    200 
    201   str = ares_dns_rr_get_str(rr, key);
    202   if (str == NULL) {
    203     return ARES_EFORMERR; /* LCOV_EXCL_LINE: DefensiveCoding */
    204   }
    205 
    206   len = ares_strlen(str);
    207   if (len > 255) {
    208     return ARES_EFORMERR;
    209   }
    210 
    211   /* Write 1 byte length */
    212   status = ares_buf_append_byte(buf, (unsigned char)(len & 0xFF));
    213   if (status != ARES_SUCCESS) {
    214     return status; /* LCOV_EXCL_LINE: OutOfMemory */
    215   }
    216 
    217   if (len == 0) {
    218     return ARES_SUCCESS;
    219   }
    220 
    221   /* Write string */
    222   return ares_buf_append(buf, (const unsigned char *)str, len);
    223 }
    224 
    225 static ares_status_t ares_dns_write_binstr(ares_buf_t          *buf,
    226                                            const unsigned char *bin,
    227                                            size_t               bin_len)
    228 {
    229   const unsigned char *ptr;
    230   size_t               ptr_len;
    231   ares_status_t        status;
    232 
    233   /* split into possible multiple 255-byte or less length strings */
    234   ptr     = bin;
    235   ptr_len = bin_len;
    236   do {
    237     size_t len = ptr_len;
    238     if (len > 255) {
    239       len = 255;
    240     }
    241 
    242     /* Length */
    243     status = ares_buf_append_byte(buf, (unsigned char)(len & 0xFF));
    244     if (status != ARES_SUCCESS) {
    245       return status; /* LCOV_EXCL_LINE: OutOfMemory */
    246     }
    247 
    248     /* String */
    249     if (len) {
    250       status = ares_buf_append(buf, ptr, len);
    251       if (status != ARES_SUCCESS) {
    252         return status; /* LCOV_EXCL_LINE: OutOfMemory */
    253       }
    254     }
    255 
    256     ptr     += len;
    257     ptr_len -= len;
    258   } while (ptr_len > 0);
    259 
    260   return ARES_SUCCESS;
    261 }
    262 
    263 static ares_status_t ares_dns_write_rr_abin(ares_buf_t          *buf,
    264                                             const ares_dns_rr_t *rr,
    265                                             ares_dns_rr_key_t    key)
    266 {
    267   ares_status_t status = ARES_EFORMERR;
    268   size_t        i;
    269   size_t        cnt = ares_dns_rr_get_abin_cnt(rr, key);
    270 
    271   if (cnt == 0) {
    272     return ARES_EFORMERR;
    273   }
    274 
    275   for (i = 0; i < cnt; i++) {
    276     const unsigned char *bin;
    277     size_t               bin_len;
    278 
    279     bin = ares_dns_rr_get_abin(rr, key, i, &bin_len);
    280 
    281     status = ares_dns_write_binstr(buf, bin, bin_len);
    282     if (status != ARES_SUCCESS) {
    283       break;
    284     }
    285   }
    286 
    287   return status;
    288 }
    289 
    290 static ares_status_t ares_dns_write_rr_be32(ares_buf_t          *buf,
    291                                             const ares_dns_rr_t *rr,
    292                                             ares_dns_rr_key_t    key)
    293 {
    294   if (ares_dns_rr_key_datatype(key) != ARES_DATATYPE_U32) {
    295     return ARES_EFORMERR; /* LCOV_EXCL_LINE: DefensiveCoding */
    296   }
    297   return ares_buf_append_be32(buf, ares_dns_rr_get_u32(rr, key));
    298 }
    299 
    300 static ares_status_t ares_dns_write_rr_be16(ares_buf_t          *buf,
    301                                             const ares_dns_rr_t *rr,
    302                                             ares_dns_rr_key_t    key)
    303 {
    304   if (ares_dns_rr_key_datatype(key) != ARES_DATATYPE_U16) {
    305     return ARES_EFORMERR; /* LCOV_EXCL_LINE: DefensiveCoding */
    306   }
    307   return ares_buf_append_be16(buf, ares_dns_rr_get_u16(rr, key));
    308 }
    309 
    310 static ares_status_t ares_dns_write_rr_u8(ares_buf_t          *buf,
    311                                           const ares_dns_rr_t *rr,
    312                                           ares_dns_rr_key_t    key)
    313 {
    314   if (ares_dns_rr_key_datatype(key) != ARES_DATATYPE_U8) {
    315     return ARES_EFORMERR; /* LCOV_EXCL_LINE: DefensiveCoding */
    316   }
    317   return ares_buf_append_byte(buf, ares_dns_rr_get_u8(rr, key));
    318 }
    319 
    320 static ares_status_t ares_dns_write_rr_a(ares_buf_t          *buf,
    321                                          const ares_dns_rr_t *rr,
    322                                          ares_llist_t       **namelist)
    323 {
    324   const struct in_addr *addr;
    325   (void)namelist;
    326 
    327   addr = ares_dns_rr_get_addr(rr, ARES_RR_A_ADDR);
    328   if (addr == NULL) {
    329     return ARES_EFORMERR; /* LCOV_EXCL_LINE: DefensiveCoding */
    330   }
    331 
    332   return ares_buf_append(buf, (const unsigned char *)addr, sizeof(*addr));
    333 }
    334 
    335 static ares_status_t ares_dns_write_rr_ns(ares_buf_t          *buf,
    336                                           const ares_dns_rr_t *rr,
    337                                           ares_llist_t       **namelist)
    338 {
    339   return ares_dns_write_rr_name(buf, rr, namelist, ARES_FALSE,
    340                                 ARES_RR_NS_NSDNAME);
    341 }
    342 
    343 static ares_status_t ares_dns_write_rr_cname(ares_buf_t          *buf,
    344                                              const ares_dns_rr_t *rr,
    345                                              ares_llist_t       **namelist)
    346 {
    347   return ares_dns_write_rr_name(buf, rr, namelist, ARES_FALSE,
    348                                 ARES_RR_CNAME_CNAME);
    349 }
    350 
    351 static ares_status_t ares_dns_write_rr_soa(ares_buf_t          *buf,
    352                                            const ares_dns_rr_t *rr,
    353                                            ares_llist_t       **namelist)
    354 {
    355   ares_status_t status;
    356 
    357   /* MNAME */
    358   status =
    359     ares_dns_write_rr_name(buf, rr, namelist, ARES_FALSE, ARES_RR_SOA_MNAME);
    360   if (status != ARES_SUCCESS) {
    361     return status;
    362   }
    363 
    364   /* RNAME */
    365   status =
    366     ares_dns_write_rr_name(buf, rr, namelist, ARES_FALSE, ARES_RR_SOA_RNAME);
    367   if (status != ARES_SUCCESS) {
    368     return status;
    369   }
    370 
    371   /* SERIAL */
    372   status = ares_dns_write_rr_be32(buf, rr, ARES_RR_SOA_SERIAL);
    373   if (status != ARES_SUCCESS) {
    374     return status; /* LCOV_EXCL_LINE: OutOfMemory */
    375   }
    376 
    377   /* REFRESH */
    378   status = ares_dns_write_rr_be32(buf, rr, ARES_RR_SOA_REFRESH);
    379   if (status != ARES_SUCCESS) {
    380     return status; /* LCOV_EXCL_LINE: OutOfMemory */
    381   }
    382 
    383   /* RETRY */
    384   status = ares_dns_write_rr_be32(buf, rr, ARES_RR_SOA_RETRY);
    385   if (status != ARES_SUCCESS) {
    386     return status; /* LCOV_EXCL_LINE: OutOfMemory */
    387   }
    388 
    389   /* EXPIRE */
    390   status = ares_dns_write_rr_be32(buf, rr, ARES_RR_SOA_EXPIRE);
    391   if (status != ARES_SUCCESS) {
    392     return status; /* LCOV_EXCL_LINE: OutOfMemory */
    393   }
    394 
    395   /* MINIMUM */
    396   return ares_dns_write_rr_be32(buf, rr, ARES_RR_SOA_MINIMUM);
    397 }
    398 
    399 static ares_status_t ares_dns_write_rr_ptr(ares_buf_t          *buf,
    400                                            const ares_dns_rr_t *rr,
    401                                            ares_llist_t       **namelist)
    402 {
    403   return ares_dns_write_rr_name(buf, rr, namelist, ARES_FALSE,
    404                                 ARES_RR_PTR_DNAME);
    405 }
    406 
    407 static ares_status_t ares_dns_write_rr_hinfo(ares_buf_t          *buf,
    408                                              const ares_dns_rr_t *rr,
    409                                              ares_llist_t       **namelist)
    410 {
    411   ares_status_t status;
    412 
    413   (void)namelist;
    414 
    415   /* CPU */
    416   status = ares_dns_write_rr_str(buf, rr, ARES_RR_HINFO_CPU);
    417   if (status != ARES_SUCCESS) {
    418     return status;
    419   }
    420 
    421   /* OS */
    422   return ares_dns_write_rr_str(buf, rr, ARES_RR_HINFO_OS);
    423 }
    424 
    425 static ares_status_t ares_dns_write_rr_mx(ares_buf_t          *buf,
    426                                           const ares_dns_rr_t *rr,
    427                                           ares_llist_t       **namelist)
    428 {
    429   ares_status_t status;
    430 
    431   /* PREFERENCE */
    432   status = ares_dns_write_rr_be16(buf, rr, ARES_RR_MX_PREFERENCE);
    433   if (status != ARES_SUCCESS) {
    434     return status; /* LCOV_EXCL_LINE: OutOfMemory */
    435   }
    436 
    437   /* EXCHANGE */
    438   return ares_dns_write_rr_name(buf, rr, namelist, ARES_FALSE,
    439                                 ARES_RR_MX_EXCHANGE);
    440 }
    441 
    442 static ares_status_t ares_dns_write_rr_txt(ares_buf_t          *buf,
    443                                            const ares_dns_rr_t *rr,
    444                                            ares_llist_t       **namelist)
    445 {
    446   (void)namelist;
    447   return ares_dns_write_rr_abin(buf, rr, ARES_RR_TXT_DATA);
    448 }
    449 
    450 static ares_status_t ares_dns_write_rr_sig(ares_buf_t          *buf,
    451                                            const ares_dns_rr_t *rr,
    452                                            ares_llist_t       **namelist)
    453 {
    454   ares_status_t        status;
    455   const unsigned char *data;
    456   size_t               len = 0;
    457 
    458   (void)namelist;
    459 
    460   /* TYPE COVERED */
    461   status = ares_dns_write_rr_be16(buf, rr, ARES_RR_SIG_TYPE_COVERED);
    462   if (status != ARES_SUCCESS) {
    463     return status; /* LCOV_EXCL_LINE: OutOfMemory */
    464   }
    465 
    466   /* ALGORITHM */
    467   status = ares_dns_write_rr_u8(buf, rr, ARES_RR_SIG_ALGORITHM);
    468   if (status != ARES_SUCCESS) {
    469     return status; /* LCOV_EXCL_LINE: OutOfMemory */
    470   }
    471 
    472   /* LABELS */
    473   status = ares_dns_write_rr_u8(buf, rr, ARES_RR_SIG_LABELS);
    474   if (status != ARES_SUCCESS) {
    475     return status; /* LCOV_EXCL_LINE: OutOfMemory */
    476   }
    477 
    478   /* ORIGINAL TTL */
    479   status = ares_dns_write_rr_be32(buf, rr, ARES_RR_SIG_ORIGINAL_TTL);
    480   if (status != ARES_SUCCESS) {
    481     return status; /* LCOV_EXCL_LINE: OutOfMemory */
    482   }
    483 
    484   /* EXPIRATION */
    485   status = ares_dns_write_rr_be32(buf, rr, ARES_RR_SIG_EXPIRATION);
    486   if (status != ARES_SUCCESS) {
    487     return status; /* LCOV_EXCL_LINE: OutOfMemory */
    488   }
    489 
    490   /* INCEPTION */
    491   status = ares_dns_write_rr_be32(buf, rr, ARES_RR_SIG_INCEPTION);
    492   if (status != ARES_SUCCESS) {
    493     return status; /* LCOV_EXCL_LINE: OutOfMemory */
    494   }
    495 
    496   /* KEY TAG */
    497   status = ares_dns_write_rr_be16(buf, rr, ARES_RR_SIG_KEY_TAG);
    498   if (status != ARES_SUCCESS) {
    499     return status; /* LCOV_EXCL_LINE: OutOfMemory */
    500   }
    501 
    502   /* SIGNERS NAME */
    503   status = ares_dns_write_rr_name(buf, rr, namelist, ARES_FALSE,
    504                                   ARES_RR_SIG_SIGNERS_NAME);
    505   if (status != ARES_SUCCESS) {
    506     return status;
    507   }
    508 
    509   /* SIGNATURE -- binary, rest of buffer, required to be non-zero length */
    510   data = ares_dns_rr_get_bin(rr, ARES_RR_SIG_SIGNATURE, &len);
    511   if (data == NULL || len == 0) {
    512     return ARES_EFORMERR;
    513   }
    514 
    515   return ares_buf_append(buf, data, len);
    516 }
    517 
    518 static ares_status_t ares_dns_write_rr_aaaa(ares_buf_t          *buf,
    519                                             const ares_dns_rr_t *rr,
    520                                             ares_llist_t       **namelist)
    521 {
    522   const struct ares_in6_addr *addr;
    523   (void)namelist;
    524 
    525   addr = ares_dns_rr_get_addr6(rr, ARES_RR_AAAA_ADDR);
    526   if (addr == NULL) {
    527     return ARES_EFORMERR; /* LCOV_EXCL_LINE: DefensiveCoding */
    528   }
    529 
    530   return ares_buf_append(buf, (const unsigned char *)addr, sizeof(*addr));
    531 }
    532 
    533 static ares_status_t ares_dns_write_rr_srv(ares_buf_t          *buf,
    534                                            const ares_dns_rr_t *rr,
    535                                            ares_llist_t       **namelist)
    536 {
    537   ares_status_t status;
    538 
    539   /* PRIORITY */
    540   status = ares_dns_write_rr_be16(buf, rr, ARES_RR_SRV_PRIORITY);
    541   if (status != ARES_SUCCESS) {
    542     return status; /* LCOV_EXCL_LINE: OutOfMemory */
    543   }
    544 
    545   /* WEIGHT */
    546   status = ares_dns_write_rr_be16(buf, rr, ARES_RR_SRV_WEIGHT);
    547   if (status != ARES_SUCCESS) {
    548     return status; /* LCOV_EXCL_LINE: OutOfMemory */
    549   }
    550 
    551   /* PORT */
    552   status = ares_dns_write_rr_be16(buf, rr, ARES_RR_SRV_PORT);
    553   if (status != ARES_SUCCESS) {
    554     return status; /* LCOV_EXCL_LINE: OutOfMemory */
    555   }
    556 
    557   /* TARGET */
    558   return ares_dns_write_rr_name(buf, rr, namelist, ARES_FALSE,
    559                                 ARES_RR_SRV_TARGET);
    560 }
    561 
    562 static ares_status_t ares_dns_write_rr_naptr(ares_buf_t          *buf,
    563                                              const ares_dns_rr_t *rr,
    564                                              ares_llist_t       **namelist)
    565 {
    566   ares_status_t status;
    567 
    568   /* ORDER */
    569   status = ares_dns_write_rr_be16(buf, rr, ARES_RR_NAPTR_ORDER);
    570   if (status != ARES_SUCCESS) {
    571     return status; /* LCOV_EXCL_LINE: OutOfMemory */
    572   }
    573 
    574   /* PREFERENCE */
    575   status = ares_dns_write_rr_be16(buf, rr, ARES_RR_NAPTR_PREFERENCE);
    576   if (status != ARES_SUCCESS) {
    577     return status; /* LCOV_EXCL_LINE: OutOfMemory */
    578   }
    579 
    580   /* FLAGS */
    581   status = ares_dns_write_rr_str(buf, rr, ARES_RR_NAPTR_FLAGS);
    582   if (status != ARES_SUCCESS) {
    583     return status; /* LCOV_EXCL_LINE: OutOfMemory */
    584   }
    585 
    586   /* SERVICES */
    587   status = ares_dns_write_rr_str(buf, rr, ARES_RR_NAPTR_SERVICES);
    588   if (status != ARES_SUCCESS) {
    589     return status; /* LCOV_EXCL_LINE: OutOfMemory */
    590   }
    591 
    592   /* REGEXP */
    593   status = ares_dns_write_rr_str(buf, rr, ARES_RR_NAPTR_REGEXP);
    594   if (status != ARES_SUCCESS) {
    595     return status; /* LCOV_EXCL_LINE: OutOfMemory */
    596   }
    597 
    598   /* REPLACEMENT */
    599   return ares_dns_write_rr_name(buf, rr, namelist, ARES_FALSE,
    600                                 ARES_RR_NAPTR_REPLACEMENT);
    601 }
    602 
    603 static ares_status_t ares_dns_write_rr_opt(ares_buf_t          *buf,
    604                                            const ares_dns_rr_t *rr,
    605                                            ares_llist_t       **namelist)
    606 {
    607   size_t         len = ares_buf_len(buf);
    608   ares_status_t  status;
    609   unsigned int   ttl = 0;
    610   size_t         i;
    611   unsigned short rcode = (unsigned short)((rr->parent->rcode >> 4) & 0xFF);
    612 
    613   (void)namelist;
    614 
    615   /* Coverity reports on this even though its not possible when taken
    616    * into context */
    617   if (len == 0) {
    618     return ARES_EFORMERR; /* LCOV_EXCL_LINE: DefensiveCoding */
    619   }
    620 
    621   /* We need to go back and overwrite the class and ttl that were emitted as
    622    * the OPT record overloads them for its own use (yes, very strange!) */
    623   status = ares_buf_set_length(buf, len - 2 /* RDLENGTH */
    624                                       - 4   /* TTL */
    625                                       - 2 /* CLASS */);
    626   if (status != ARES_SUCCESS) {
    627     return status;
    628   }
    629 
    630   /* Class -> UDP Size */
    631   status = ares_dns_write_rr_be16(buf, rr, ARES_RR_OPT_UDP_SIZE);
    632   if (status != ARES_SUCCESS) {
    633     return status; /* LCOV_EXCL_LINE: OutOfMemory */
    634   }
    635 
    636   /* TTL -> rcode (u8) << 24 | version (u8) << 16 | flags (u16) */
    637   ttl |= (unsigned int)rcode << 24;
    638   ttl |= (unsigned int)ares_dns_rr_get_u8(rr, ARES_RR_OPT_VERSION) << 16;
    639   ttl |= (unsigned int)ares_dns_rr_get_u16(rr, ARES_RR_OPT_FLAGS);
    640 
    641   status = ares_buf_append_be32(buf, ttl);
    642   if (status != ARES_SUCCESS) {
    643     return status; /* LCOV_EXCL_LINE: OutOfMemory */
    644   }
    645 
    646   /* Now go back to real end */
    647   status = ares_buf_set_length(buf, len);
    648   if (status != ARES_SUCCESS) {
    649     return status;
    650   }
    651 
    652   /* Append Options */
    653   for (i = 0; i < ares_dns_rr_get_opt_cnt(rr, ARES_RR_OPT_OPTIONS); i++) {
    654     unsigned short       opt;
    655     size_t               val_len;
    656     const unsigned char *val;
    657 
    658     opt = ares_dns_rr_get_opt(rr, ARES_RR_OPT_OPTIONS, i, &val, &val_len);
    659 
    660     /* BE16 option */
    661     status = ares_buf_append_be16(buf, opt);
    662     if (status != ARES_SUCCESS) {
    663       return status; /* LCOV_EXCL_LINE: OutOfMemory */
    664     }
    665 
    666     /* BE16 length */
    667     status = ares_buf_append_be16(buf, (unsigned short)(val_len & 0xFFFF));
    668     if (status != ARES_SUCCESS) {
    669       return status; /* LCOV_EXCL_LINE: OutOfMemory */
    670     }
    671 
    672     /* Value */
    673     if (val && val_len) {
    674       status = ares_buf_append(buf, val, val_len);
    675       if (status != ARES_SUCCESS) {
    676         return status; /* LCOV_EXCL_LINE: OutOfMemory */
    677       }
    678     }
    679   }
    680 
    681   return ARES_SUCCESS;
    682 }
    683 
    684 static ares_status_t ares_dns_write_rr_tlsa(ares_buf_t          *buf,
    685                                             const ares_dns_rr_t *rr,
    686                                             ares_llist_t       **namelist)
    687 {
    688   ares_status_t        status;
    689   const unsigned char *data;
    690   size_t               len = 0;
    691 
    692   (void)namelist;
    693 
    694   /* CERT_USAGE */
    695   status = ares_dns_write_rr_u8(buf, rr, ARES_RR_TLSA_CERT_USAGE);
    696   if (status != ARES_SUCCESS) {
    697     return status; /* LCOV_EXCL_LINE: OutOfMemory */
    698   }
    699 
    700   /* SELECTOR */
    701   status = ares_dns_write_rr_u8(buf, rr, ARES_RR_TLSA_SELECTOR);
    702   if (status != ARES_SUCCESS) {
    703     return status; /* LCOV_EXCL_LINE: OutOfMemory */
    704   }
    705 
    706   /* MATCH */
    707   status = ares_dns_write_rr_u8(buf, rr, ARES_RR_TLSA_MATCH);
    708   if (status != ARES_SUCCESS) {
    709     return status; /* LCOV_EXCL_LINE: OutOfMemory */
    710   }
    711 
    712   /* DATA -- binary, rest of buffer, required to be non-zero length */
    713   data = ares_dns_rr_get_bin(rr, ARES_RR_TLSA_DATA, &len);
    714   if (data == NULL || len == 0) {
    715     return ARES_EFORMERR;
    716   }
    717 
    718   return ares_buf_append(buf, data, len);
    719 }
    720 
    721 static ares_status_t ares_dns_write_rr_svcb(ares_buf_t          *buf,
    722                                             const ares_dns_rr_t *rr,
    723                                             ares_llist_t       **namelist)
    724 {
    725   ares_status_t status;
    726   size_t        i;
    727 
    728   /* PRIORITY */
    729   status = ares_dns_write_rr_be16(buf, rr, ARES_RR_SVCB_PRIORITY);
    730   if (status != ARES_SUCCESS) {
    731     return status; /* LCOV_EXCL_LINE: OutOfMemory */
    732   }
    733 
    734   /* TARGET */
    735   status =
    736     ares_dns_write_rr_name(buf, rr, namelist, ARES_FALSE, ARES_RR_SVCB_TARGET);
    737   if (status != ARES_SUCCESS) {
    738     return status;
    739   }
    740 
    741   /* Append Params */
    742   for (i = 0; i < ares_dns_rr_get_opt_cnt(rr, ARES_RR_SVCB_PARAMS); i++) {
    743     unsigned short       opt;
    744     size_t               val_len;
    745     const unsigned char *val;
    746 
    747     opt = ares_dns_rr_get_opt(rr, ARES_RR_SVCB_PARAMS, i, &val, &val_len);
    748 
    749     /* BE16 option */
    750     status = ares_buf_append_be16(buf, opt);
    751     if (status != ARES_SUCCESS) {
    752       return status; /* LCOV_EXCL_LINE: OutOfMemory */
    753     }
    754 
    755     /* BE16 length */
    756     status = ares_buf_append_be16(buf, (unsigned short)(val_len & 0xFFFF));
    757     if (status != ARES_SUCCESS) {
    758       return status; /* LCOV_EXCL_LINE: OutOfMemory */
    759     }
    760 
    761     /* Value */
    762     if (val && val_len) {
    763       status = ares_buf_append(buf, val, val_len);
    764       if (status != ARES_SUCCESS) {
    765         return status; /* LCOV_EXCL_LINE: OutOfMemory */
    766       }
    767     }
    768   }
    769   return ARES_SUCCESS;
    770 }
    771 
    772 static ares_status_t ares_dns_write_rr_https(ares_buf_t          *buf,
    773                                              const ares_dns_rr_t *rr,
    774                                              ares_llist_t       **namelist)
    775 {
    776   ares_status_t status;
    777   size_t        i;
    778 
    779   /* PRIORITY */
    780   status = ares_dns_write_rr_be16(buf, rr, ARES_RR_HTTPS_PRIORITY);
    781   if (status != ARES_SUCCESS) {
    782     return status; /* LCOV_EXCL_LINE: OutOfMemory */
    783   }
    784 
    785   /* TARGET */
    786   status =
    787     ares_dns_write_rr_name(buf, rr, namelist, ARES_FALSE, ARES_RR_HTTPS_TARGET);
    788   if (status != ARES_SUCCESS) {
    789     return status;
    790   }
    791 
    792   /* Append Params */
    793   for (i = 0; i < ares_dns_rr_get_opt_cnt(rr, ARES_RR_HTTPS_PARAMS); i++) {
    794     unsigned short       opt;
    795     size_t               val_len;
    796     const unsigned char *val;
    797 
    798     opt = ares_dns_rr_get_opt(rr, ARES_RR_HTTPS_PARAMS, i, &val, &val_len);
    799 
    800     /* BE16 option */
    801     status = ares_buf_append_be16(buf, opt);
    802     if (status != ARES_SUCCESS) {
    803       return status; /* LCOV_EXCL_LINE: OutOfMemory */
    804     }
    805 
    806     /* BE16 length */
    807     status = ares_buf_append_be16(buf, (unsigned short)(val_len & 0xFFFF));
    808     if (status != ARES_SUCCESS) {
    809       return status; /* LCOV_EXCL_LINE: OutOfMemory */
    810     }
    811 
    812     /* Value */
    813     if (val && val_len) {
    814       status = ares_buf_append(buf, val, val_len);
    815       if (status != ARES_SUCCESS) {
    816         return status; /* LCOV_EXCL_LINE: OutOfMemory */
    817       }
    818     }
    819   }
    820   return ARES_SUCCESS;
    821 }
    822 
    823 static ares_status_t ares_dns_write_rr_uri(ares_buf_t          *buf,
    824                                            const ares_dns_rr_t *rr,
    825                                            ares_llist_t       **namelist)
    826 {
    827   ares_status_t status;
    828   const char   *target;
    829 
    830   (void)namelist;
    831 
    832   /* PRIORITY */
    833   status = ares_dns_write_rr_be16(buf, rr, ARES_RR_URI_PRIORITY);
    834   if (status != ARES_SUCCESS) {
    835     return status; /* LCOV_EXCL_LINE: OutOfMemory */
    836   }
    837 
    838   /* WEIGHT */
    839   status = ares_dns_write_rr_be16(buf, rr, ARES_RR_URI_WEIGHT);
    840   if (status != ARES_SUCCESS) {
    841     return status; /* LCOV_EXCL_LINE: OutOfMemory */
    842   }
    843 
    844   /* TARGET -- not in DNS string format, rest of buffer, required to be
    845    * non-zero length */
    846   target = ares_dns_rr_get_str(rr, ARES_RR_URI_TARGET);
    847   if (target == NULL || ares_strlen(target) == 0) {
    848     return ARES_EFORMERR;
    849   }
    850 
    851   return ares_buf_append(buf, (const unsigned char *)target,
    852                          ares_strlen(target));
    853 }
    854 
    855 static ares_status_t ares_dns_write_rr_caa(ares_buf_t          *buf,
    856                                            const ares_dns_rr_t *rr,
    857                                            ares_llist_t       **namelist)
    858 {
    859   const unsigned char *data     = NULL;
    860   size_t               data_len = 0;
    861   ares_status_t        status;
    862 
    863   (void)namelist;
    864 
    865   /* CRITICAL */
    866   status = ares_dns_write_rr_u8(buf, rr, ARES_RR_CAA_CRITICAL);
    867   if (status != ARES_SUCCESS) {
    868     return status; /* LCOV_EXCL_LINE: OutOfMemory */
    869   }
    870 
    871   /* Tag */
    872   status = ares_dns_write_rr_str(buf, rr, ARES_RR_CAA_TAG);
    873   if (status != ARES_SUCCESS) {
    874     return status; /* LCOV_EXCL_LINE: OutOfMemory */
    875   }
    876 
    877   /* Value - binary! (remaining buffer */
    878   data = ares_dns_rr_get_bin(rr, ARES_RR_CAA_VALUE, &data_len);
    879   if (data == NULL || data_len == 0) {
    880     return ARES_EFORMERR;
    881   }
    882 
    883   return ares_buf_append(buf, data, data_len);
    884 }
    885 
    886 static ares_status_t ares_dns_write_rr_raw_rr(ares_buf_t          *buf,
    887                                               const ares_dns_rr_t *rr,
    888                                               ares_llist_t       **namelist)
    889 {
    890   size_t               len = ares_buf_len(buf);
    891   ares_status_t        status;
    892   const unsigned char *data     = NULL;
    893   size_t               data_len = 0;
    894 
    895   (void)namelist;
    896 
    897   /* Coverity reports on this even though its not possible when taken
    898    * into context */
    899   if (len == 0) {
    900     return ARES_EFORMERR; /* LCOV_EXCL_LINE: DefensiveCoding */
    901   }
    902 
    903   /* We need to go back and overwrite the type that was emitted by the parent
    904    * function */
    905   status = ares_buf_set_length(buf, len - 2 /* RDLENGTH */
    906                                       - 4   /* TTL */
    907                                       - 2   /* CLASS */
    908                                       - 2 /* TYPE */);
    909   if (status != ARES_SUCCESS) {
    910     return status;
    911   }
    912 
    913   status = ares_dns_write_rr_be16(buf, rr, ARES_RR_RAW_RR_TYPE);
    914   if (status != ARES_SUCCESS) {
    915     return status; /* LCOV_EXCL_LINE: OutOfMemory */
    916   }
    917 
    918   /* Now go back to real end */
    919   status = ares_buf_set_length(buf, len);
    920   if (status != ARES_SUCCESS) {
    921     return status;
    922   }
    923 
    924   /* Output raw data */
    925   data = ares_dns_rr_get_bin(rr, ARES_RR_RAW_RR_DATA, &data_len);
    926   if (data == NULL) {
    927     return ARES_EFORMERR;
    928   }
    929 
    930   if (data_len == 0) {
    931     return ARES_SUCCESS;
    932   }
    933 
    934   return ares_buf_append(buf, data, data_len);
    935 }
    936 
    937 static ares_status_t ares_dns_write_rr(const ares_dns_record_t *dnsrec,
    938                                        ares_llist_t           **namelist,
    939                                        ares_dns_section_t       section,
    940                                        ares_buf_t              *buf)
    941 {
    942   size_t i;
    943 
    944   for (i = 0; i < ares_dns_record_rr_cnt(dnsrec, section); i++) {
    945     const ares_dns_rr_t *rr;
    946     ares_dns_rec_type_t  type;
    947     ares_bool_t          allow_compress;
    948     ares_llist_t       **namelistptr = NULL;
    949     size_t               pos_len;
    950     ares_status_t        status;
    951     size_t               rdlength;
    952     size_t               end_length;
    953     unsigned int         ttl;
    954 
    955     rr = ares_dns_record_rr_get_const(dnsrec, section, i);
    956     if (rr == NULL) {
    957       return ARES_EFORMERR; /* LCOV_EXCL_LINE: DefensiveCoding */
    958     }
    959 
    960     type           = ares_dns_rr_get_type(rr);
    961     allow_compress = ares_dns_rec_allow_name_comp(type);
    962     if (allow_compress) {
    963       namelistptr = namelist;
    964     }
    965 
    966     /* Name */
    967     status =
    968       ares_dns_name_write(buf, namelist, ARES_TRUE, ares_dns_rr_get_name(rr));
    969     if (status != ARES_SUCCESS) {
    970       return status;
    971     }
    972 
    973     /* Type */
    974     status = ares_buf_append_be16(buf, (unsigned short)type);
    975     if (status != ARES_SUCCESS) {
    976       return status; /* LCOV_EXCL_LINE: OutOfMemory */
    977     }
    978 
    979     /* Class */
    980     status =
    981       ares_buf_append_be16(buf, (unsigned short)ares_dns_rr_get_class(rr));
    982     if (status != ARES_SUCCESS) {
    983       return status; /* LCOV_EXCL_LINE: OutOfMemory */
    984     }
    985 
    986     /* TTL */
    987     ttl = ares_dns_rr_get_ttl(rr);
    988     if (rr->parent->ttl_decrement > ttl) {
    989       ttl = 0;
    990     } else {
    991       ttl -= rr->parent->ttl_decrement;
    992     }
    993     status = ares_buf_append_be32(buf, ttl);
    994     if (status != ARES_SUCCESS) {
    995       return status; /* LCOV_EXCL_LINE: OutOfMemory */
    996     }
    997 
    998     /* Length */
    999     pos_len = ares_buf_len(buf); /* Save to write real length later */
   1000     status  = ares_buf_append_be16(buf, 0);
   1001     if (status != ARES_SUCCESS) {
   1002       return status; /* LCOV_EXCL_LINE: OutOfMemory */
   1003     }
   1004 
   1005     /* Data */
   1006     switch (type) {
   1007       case ARES_REC_TYPE_A:
   1008         status = ares_dns_write_rr_a(buf, rr, namelistptr);
   1009         break;
   1010       case ARES_REC_TYPE_NS:
   1011         status = ares_dns_write_rr_ns(buf, rr, namelistptr);
   1012         break;
   1013       case ARES_REC_TYPE_CNAME:
   1014         status = ares_dns_write_rr_cname(buf, rr, namelistptr);
   1015         break;
   1016       case ARES_REC_TYPE_SOA:
   1017         status = ares_dns_write_rr_soa(buf, rr, namelistptr);
   1018         break;
   1019       case ARES_REC_TYPE_PTR:
   1020         status = ares_dns_write_rr_ptr(buf, rr, namelistptr);
   1021         break;
   1022       case ARES_REC_TYPE_HINFO:
   1023         status = ares_dns_write_rr_hinfo(buf, rr, namelistptr);
   1024         break;
   1025       case ARES_REC_TYPE_MX:
   1026         status = ares_dns_write_rr_mx(buf, rr, namelistptr);
   1027         break;
   1028       case ARES_REC_TYPE_TXT:
   1029         status = ares_dns_write_rr_txt(buf, rr, namelistptr);
   1030         break;
   1031       case ARES_REC_TYPE_SIG:
   1032         status = ares_dns_write_rr_sig(buf, rr, namelistptr);
   1033         break;
   1034       case ARES_REC_TYPE_AAAA:
   1035         status = ares_dns_write_rr_aaaa(buf, rr, namelistptr);
   1036         break;
   1037       case ARES_REC_TYPE_SRV:
   1038         status = ares_dns_write_rr_srv(buf, rr, namelistptr);
   1039         break;
   1040       case ARES_REC_TYPE_NAPTR:
   1041         status = ares_dns_write_rr_naptr(buf, rr, namelistptr);
   1042         break;
   1043       case ARES_REC_TYPE_ANY:
   1044         status = ARES_EFORMERR;
   1045         break;
   1046       case ARES_REC_TYPE_OPT:
   1047         status = ares_dns_write_rr_opt(buf, rr, namelistptr);
   1048         break;
   1049       case ARES_REC_TYPE_TLSA:
   1050         status = ares_dns_write_rr_tlsa(buf, rr, namelistptr);
   1051         break;
   1052       case ARES_REC_TYPE_SVCB:
   1053         status = ares_dns_write_rr_svcb(buf, rr, namelistptr);
   1054         break;
   1055       case ARES_REC_TYPE_HTTPS:
   1056         status = ares_dns_write_rr_https(buf, rr, namelistptr);
   1057         break;
   1058       case ARES_REC_TYPE_URI:
   1059         status = ares_dns_write_rr_uri(buf, rr, namelistptr);
   1060         break;
   1061       case ARES_REC_TYPE_CAA:
   1062         status = ares_dns_write_rr_caa(buf, rr, namelistptr);
   1063         break;
   1064       case ARES_REC_TYPE_RAW_RR:
   1065         status = ares_dns_write_rr_raw_rr(buf, rr, namelistptr);
   1066         break;
   1067     }
   1068 
   1069     if (status != ARES_SUCCESS) {
   1070       return status;
   1071     }
   1072 
   1073     /* Back off write pointer, write real length, then go back to proper
   1074      * position */
   1075     end_length = ares_buf_len(buf);
   1076     rdlength   = end_length - pos_len - 2;
   1077 
   1078     status = ares_buf_set_length(buf, pos_len);
   1079     if (status != ARES_SUCCESS) {
   1080       return status;
   1081     }
   1082 
   1083     status = ares_buf_append_be16(buf, (unsigned short)(rdlength & 0xFFFF));
   1084     if (status != ARES_SUCCESS) {
   1085       return status; /* LCOV_EXCL_LINE: OutOfMemory */
   1086     }
   1087 
   1088     status = ares_buf_set_length(buf, end_length);
   1089     if (status != ARES_SUCCESS) {
   1090       return status;
   1091     }
   1092   }
   1093 
   1094   return ARES_SUCCESS;
   1095 }
   1096 
   1097 ares_status_t ares_dns_write_buf(const ares_dns_record_t *dnsrec,
   1098                                  ares_buf_t              *buf)
   1099 {
   1100   ares_llist_t *namelist = NULL;
   1101   size_t        orig_len;
   1102   ares_status_t status;
   1103 
   1104   if (dnsrec == NULL || buf == NULL) {
   1105     return ARES_EFORMERR;
   1106   }
   1107 
   1108   orig_len = ares_buf_len(buf);
   1109 
   1110   status = ares_dns_write_header(dnsrec, buf);
   1111   if (status != ARES_SUCCESS) {
   1112     goto done;
   1113   }
   1114 
   1115   status = ares_dns_write_questions(dnsrec, &namelist, buf);
   1116   if (status != ARES_SUCCESS) {
   1117     goto done;
   1118   }
   1119 
   1120   status = ares_dns_write_rr(dnsrec, &namelist, ARES_SECTION_ANSWER, buf);
   1121   if (status != ARES_SUCCESS) {
   1122     goto done;
   1123   }
   1124 
   1125   status = ares_dns_write_rr(dnsrec, &namelist, ARES_SECTION_AUTHORITY, buf);
   1126   if (status != ARES_SUCCESS) {
   1127     goto done;
   1128   }
   1129 
   1130   status = ares_dns_write_rr(dnsrec, &namelist, ARES_SECTION_ADDITIONAL, buf);
   1131   if (status != ARES_SUCCESS) {
   1132     goto done;
   1133   }
   1134 
   1135 done:
   1136   ares_llist_destroy(namelist);
   1137   if (status != ARES_SUCCESS) {
   1138     ares_buf_set_length(buf, orig_len);
   1139   }
   1140 
   1141   return status;
   1142 }
   1143 
   1144 ares_status_t ares_dns_write_buf_tcp(const ares_dns_record_t *dnsrec,
   1145                                      ares_buf_t              *buf)
   1146 {
   1147   ares_status_t status;
   1148   size_t        orig_len;
   1149   size_t        msg_len;
   1150   size_t        len;
   1151 
   1152   if (dnsrec == NULL || buf == NULL) {
   1153     return ARES_EFORMERR;
   1154   }
   1155 
   1156   orig_len = ares_buf_len(buf);
   1157 
   1158   /* Write placeholder for length */
   1159   status = ares_buf_append_be16(buf, 0);
   1160   if (status != ARES_SUCCESS) {
   1161     goto done; /* LCOV_EXCL_LINE: OutOfMemory */
   1162   }
   1163 
   1164   /* Write message */
   1165   status = ares_dns_write_buf(dnsrec, buf);
   1166   if (status != ARES_SUCCESS) {
   1167     goto done; /* LCOV_EXCL_LINE: OutOfMemory */
   1168   }
   1169 
   1170   len     = ares_buf_len(buf);
   1171   msg_len = len - orig_len - 2;
   1172   if (msg_len > 65535) {
   1173     status = ARES_EBADQUERY;
   1174     goto done;
   1175   }
   1176 
   1177   /* Now we need to overwrite the length, so we jump back to the original
   1178    * message length, overwrite the section and jump back */
   1179   ares_buf_set_length(buf, orig_len);
   1180   status = ares_buf_append_be16(buf, (unsigned short)(msg_len & 0xFFFF));
   1181   if (status != ARES_SUCCESS) {
   1182     goto done; /* LCOV_EXCL_LINE: UntestablePath */
   1183   }
   1184   ares_buf_set_length(buf, len);
   1185 
   1186 done:
   1187   if (status != ARES_SUCCESS) {
   1188     ares_buf_set_length(buf, orig_len);
   1189   }
   1190   return status;
   1191 }
   1192 
   1193 ares_status_t ares_dns_write(const ares_dns_record_t *dnsrec,
   1194                              unsigned char **buf, size_t *buf_len)
   1195 {
   1196   ares_buf_t   *b = NULL;
   1197   ares_status_t status;
   1198 
   1199   if (buf == NULL || buf_len == NULL || dnsrec == NULL) {
   1200     return ARES_EFORMERR;
   1201   }
   1202 
   1203   *buf     = NULL;
   1204   *buf_len = 0;
   1205 
   1206   b = ares_buf_create();
   1207   if (b == NULL) {
   1208     return ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */
   1209   }
   1210 
   1211   status = ares_dns_write_buf(dnsrec, b);
   1212 
   1213   if (status != ARES_SUCCESS) {
   1214     ares_buf_destroy(b);
   1215     return status;
   1216   }
   1217 
   1218   *buf = ares_buf_finish_bin(b, buf_len);
   1219   return status;
   1220 }
   1221 
   1222 void ares_dns_record_ttl_decrement(ares_dns_record_t *dnsrec,
   1223                                    unsigned int       ttl_decrement)
   1224 {
   1225   if (dnsrec == NULL) {
   1226     return;
   1227   }
   1228   dnsrec->ttl_decrement = ttl_decrement;
   1229 }