• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
ares_dns_write_header(const ares_dns_record_t * dnsrec,ares_buf_t * buf)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 
ares_dns_write_questions(const ares_dns_record_t * dnsrec,ares_llist_t ** namelist,ares_buf_t * buf)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 
ares_dns_write_rr_name(ares_buf_t * buf,const ares_dns_rr_t * rr,ares_llist_t ** namelist,ares_bool_t validate_hostname,ares_dns_rr_key_t key)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 
ares_dns_write_rr_str(ares_buf_t * buf,const ares_dns_rr_t * rr,ares_dns_rr_key_t key)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 
ares_dns_write_binstr(ares_buf_t * buf,const unsigned char * bin,size_t bin_len)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 
ares_dns_write_rr_abin(ares_buf_t * buf,const ares_dns_rr_t * rr,ares_dns_rr_key_t key)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 
ares_dns_write_rr_be32(ares_buf_t * buf,const ares_dns_rr_t * rr,ares_dns_rr_key_t key)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 
ares_dns_write_rr_be16(ares_buf_t * buf,const ares_dns_rr_t * rr,ares_dns_rr_key_t key)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 
ares_dns_write_rr_u8(ares_buf_t * buf,const ares_dns_rr_t * rr,ares_dns_rr_key_t key)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 
ares_dns_write_rr_a(ares_buf_t * buf,const ares_dns_rr_t * rr,ares_llist_t ** namelist)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 
ares_dns_write_rr_ns(ares_buf_t * buf,const ares_dns_rr_t * rr,ares_llist_t ** namelist)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 
ares_dns_write_rr_cname(ares_buf_t * buf,const ares_dns_rr_t * rr,ares_llist_t ** namelist)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 
ares_dns_write_rr_soa(ares_buf_t * buf,const ares_dns_rr_t * rr,ares_llist_t ** namelist)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 
ares_dns_write_rr_ptr(ares_buf_t * buf,const ares_dns_rr_t * rr,ares_llist_t ** namelist)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 
ares_dns_write_rr_hinfo(ares_buf_t * buf,const ares_dns_rr_t * rr,ares_llist_t ** namelist)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 
ares_dns_write_rr_mx(ares_buf_t * buf,const ares_dns_rr_t * rr,ares_llist_t ** namelist)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 
ares_dns_write_rr_txt(ares_buf_t * buf,const ares_dns_rr_t * rr,ares_llist_t ** namelist)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 
ares_dns_write_rr_sig(ares_buf_t * buf,const ares_dns_rr_t * rr,ares_llist_t ** namelist)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 
ares_dns_write_rr_aaaa(ares_buf_t * buf,const ares_dns_rr_t * rr,ares_llist_t ** namelist)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 
ares_dns_write_rr_srv(ares_buf_t * buf,const ares_dns_rr_t * rr,ares_llist_t ** namelist)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 
ares_dns_write_rr_naptr(ares_buf_t * buf,const ares_dns_rr_t * rr,ares_llist_t ** namelist)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 
ares_dns_write_rr_opt(ares_buf_t * buf,const ares_dns_rr_t * rr,ares_llist_t ** namelist)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 
ares_dns_write_rr_tlsa(ares_buf_t * buf,const ares_dns_rr_t * rr,ares_llist_t ** namelist)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 
ares_dns_write_rr_svcb(ares_buf_t * buf,const ares_dns_rr_t * rr,ares_llist_t ** namelist)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 
ares_dns_write_rr_https(ares_buf_t * buf,const ares_dns_rr_t * rr,ares_llist_t ** namelist)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 
ares_dns_write_rr_uri(ares_buf_t * buf,const ares_dns_rr_t * rr,ares_llist_t ** namelist)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 
ares_dns_write_rr_caa(ares_buf_t * buf,const ares_dns_rr_t * rr,ares_llist_t ** namelist)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 
ares_dns_write_rr_raw_rr(ares_buf_t * buf,const ares_dns_rr_t * rr,ares_llist_t ** namelist)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 
ares_dns_write_rr(const ares_dns_record_t * dnsrec,ares_llist_t ** namelist,ares_dns_section_t section,ares_buf_t * buf)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 
ares_dns_write_buf(const ares_dns_record_t * dnsrec,ares_buf_t * buf)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 
ares_dns_write_buf_tcp(const ares_dns_record_t * dnsrec,ares_buf_t * buf)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 
ares_dns_write(const ares_dns_record_t * dnsrec,unsigned char ** buf,size_t * buf_len)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 
ares_dns_record_ttl_decrement(ares_dns_record_t * dnsrec,unsigned int ttl_decrement)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 }
1230