Coverage Report

Created: 2026-10-23 07:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/openssh/openbsd-compat/getrrsetbyname.c
Line
Count
Source
1
/* $OpenBSD: getrrsetbyname.c,v 1.11 2007/10/11 18:36:41 jakob Exp $ */
2
3
/*
4
 * Copyright (c) 2001 Jakob Schlyter. All rights reserved.
5
 *
6
 * Redistribution and use in source and binary forms, with or without
7
 * modification, are permitted provided that the following conditions
8
 * are met:
9
 *
10
 * 1. Redistributions of source code must retain the above copyright
11
 *    notice, this list of conditions and the following disclaimer.
12
 *
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
 */
28
29
/*
30
 * Portions Copyright (c) 1999-2001 Internet Software Consortium.
31
 *
32
 * Permission to use, copy, modify, and distribute this software for any
33
 * purpose with or without fee is hereby granted, provided that the above
34
 * copyright notice and this permission notice appear in all copies.
35
 *
36
 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
37
 * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
38
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
39
 * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
40
 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
41
 * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
42
 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
43
 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
44
 */
45
46
/* OPENBSD ORIGINAL: lib/libc/net/getrrsetbyname.c */
47
48
#include "includes.h"
49
50
#if !defined (HAVE_GETRRSETBYNAME) && !defined (HAVE_LDNS)
51
52
#include <stdlib.h>
53
#include <string.h>
54
55
#include <netinet/in.h>
56
#include <arpa/inet.h>
57
58
#include "getrrsetbyname.h"
59
60
#if defined(HAVE_DECL_H_ERRNO) && !HAVE_DECL_H_ERRNO
61
extern int h_errno;
62
#endif
63
64
/* We don't need multithread support here */
65
#ifdef _THREAD_PRIVATE
66
# undef _THREAD_PRIVATE
67
#endif
68
0
#define _THREAD_PRIVATE(a,b,c) (c)
69
70
#ifndef HAVE__RES_EXTERN
71
struct __res_state _res;
72
#endif
73
74
/* Necessary functions and macros */
75
76
/*
77
 * Inline versions of get/put short/long.  Pointer is advanced.
78
 *
79
 * These macros demonstrate the property of C whereby it can be
80
 * portable or it can be elegant but rarely both.
81
 */
82
83
#ifndef INT32SZ
84
# define INT32SZ  4
85
#endif
86
#ifndef INT16SZ
87
# define INT16SZ  2
88
#endif
89
90
#ifndef GETSHORT
91
#define GETSHORT(s, cp) { \
92
  u_char *t_cp = (u_char *)(cp); \
93
  (s) = ((u_int16_t)t_cp[0] << 8) \
94
      | ((u_int16_t)t_cp[1]) \
95
      ; \
96
  (cp) += INT16SZ; \
97
}
98
#endif
99
100
#ifndef GETLONG
101
#define GETLONG(l, cp) { \
102
  u_char *t_cp = (u_char *)(cp); \
103
  (l) = ((u_int32_t)t_cp[0] << 24) \
104
      | ((u_int32_t)t_cp[1] << 16) \
105
      | ((u_int32_t)t_cp[2] << 8) \
106
      | ((u_int32_t)t_cp[3]) \
107
      ; \
108
  (cp) += INT32SZ; \
109
}
110
#endif
111
112
/*
113
 * If the system doesn't have _getshort/_getlong or that are not exactly what
114
 * we need then use local replacements, avoiding name collisions.
115
 */
116
#if !defined(HAVE__GETSHORT) || !defined(HAVE__GETLONG) || \
117
    !defined(HAVE_DECL__GETSHORT) || HAVE_DECL__GETSHORT == 0 || \
118
    !defined(HAVE_DECL__GETLONG) || HAVE_DECL__GETLONG == 0
119
# ifdef _getshort
120
#  undef _getshort
121
# endif
122
# ifdef _getlong
123
#  undef _getlong
124
# endif
125
0
# define _getshort(x) (_ssh_compat_getshort(x))
126
0
# define _getlong(x) (_ssh_compat_getlong(x))
127
/*
128
 * Routines to insert/extract short/long's.
129
 */
130
static u_int16_t
131
_getshort(const u_char *msgp)
132
0
{
133
0
  u_int16_t u;
134
135
0
  GETSHORT(u, msgp);
136
0
  return (u);
137
0
}
138
139
static u_int32_t
140
_getlong(const u_char *msgp)
141
0
{
142
0
  u_int32_t u;
143
144
0
  GETLONG(u, msgp);
145
0
  return (u);
146
0
}
147
#endif /* missing _getshort/_getlong */
148
149
/* ************** */
150
151
#define ANSWER_BUFFER_SIZE 0xffff
152
153
struct dns_query {
154
  char      *name;
155
  u_int16_t   type;
156
  u_int16_t   class;
157
  struct dns_query  *next;
158
};
159
160
struct dns_rr {
161
  char      *name;
162
  u_int16_t   type;
163
  u_int16_t   class;
164
  u_int16_t   ttl;
165
  u_int16_t   size;
166
  void      *rdata;
167
  struct dns_rr   *next;
168
};
169
170
struct dns_response {
171
  HEADER      header;
172
  struct dns_query  *query;
173
  struct dns_rr   *answer;
174
  struct dns_rr   *authority;
175
  struct dns_rr   *additional;
176
};
177
178
static struct dns_response *parse_dns_response(const u_char *, int);
179
static struct dns_query *parse_dns_qsection(const u_char *, int,
180
    const u_char **, int);
181
static struct dns_rr *parse_dns_rrsection(const u_char *, int, const u_char **,
182
    int);
183
184
static void free_dns_query(struct dns_query *);
185
static void free_dns_rr(struct dns_rr *);
186
static void free_dns_response(struct dns_response *);
187
188
static int count_dns_rr(struct dns_rr *, u_int16_t, u_int16_t);
189
190
int
191
getrrsetbyname(const char *hostname, unsigned int rdclass,
192
    unsigned int rdtype, unsigned int flags,
193
    struct rrsetinfo **res)
194
0
{
195
0
  struct __res_state *_resp = _THREAD_PRIVATE(_res, _res, &_res);
196
0
  int result;
197
0
  struct rrsetinfo *rrset = NULL;
198
0
  struct dns_response *response = NULL;
199
0
  struct dns_rr *rr;
200
0
  struct rdatainfo *rdata;
201
0
  int length;
202
0
  unsigned int index_ans, index_sig;
203
0
  u_char answer[ANSWER_BUFFER_SIZE];
204
205
  /* check for invalid class and type */
206
0
  if (rdclass > 0xffff || rdtype > 0xffff) {
207
0
    result = ERRSET_INVAL;
208
0
    goto fail;
209
0
  }
210
211
  /* don't allow queries of class or type ANY */
212
0
  if (rdclass == 0xff || rdtype == 0xff) {
213
0
    result = ERRSET_INVAL;
214
0
    goto fail;
215
0
  }
216
217
  /* don't allow flags yet, unimplemented */
218
0
  if (flags) {
219
0
    result = ERRSET_INVAL;
220
0
    goto fail;
221
0
  }
222
223
  /* initialize resolver */
224
0
  if ((_resp->options & RES_INIT) == 0 && res_init() == -1) {
225
0
    result = ERRSET_FAIL;
226
0
    goto fail;
227
0
  }
228
229
#ifdef DEBUG
230
  _resp->options |= RES_DEBUG;
231
#endif /* DEBUG */
232
233
0
#ifdef RES_USE_DNSSEC
234
  /* turn on DNSSEC if EDNS0 is configured */
235
0
  if (_resp->options & RES_USE_EDNS0)
236
0
    _resp->options |= RES_USE_DNSSEC;
237
0
#endif /* RES_USE_DNSEC */
238
239
  /* make query */
240
0
  length = res_query(hostname, (signed int) rdclass, (signed int) rdtype,
241
0
      answer, sizeof(answer));
242
0
  if (length < 0) {
243
0
    switch(h_errno) {
244
0
    case HOST_NOT_FOUND:
245
0
      result = ERRSET_NONAME;
246
0
      goto fail;
247
0
    case NO_DATA:
248
0
      result = ERRSET_NODATA;
249
0
      goto fail;
250
0
    default:
251
0
      result = ERRSET_FAIL;
252
0
      goto fail;
253
0
    }
254
0
  }
255
256
  /* parse result */
257
0
  response = parse_dns_response(answer, length);
258
0
  if (response == NULL) {
259
0
    result = ERRSET_FAIL;
260
0
    goto fail;
261
0
  }
262
263
0
  if (response->header.qdcount != 1) {
264
0
    result = ERRSET_FAIL;
265
0
    goto fail;
266
0
  }
267
268
  /* initialize rrset */
269
0
  rrset = calloc(1, sizeof(struct rrsetinfo));
270
0
  if (rrset == NULL) {
271
0
    result = ERRSET_NOMEMORY;
272
0
    goto fail;
273
0
  }
274
0
  rrset->rri_rdclass = response->query->class;
275
0
  rrset->rri_rdtype = response->query->type;
276
0
  rrset->rri_ttl = response->answer->ttl;
277
0
  rrset->rri_nrdatas = response->header.ancount;
278
279
0
#ifdef HAVE_HEADER_AD
280
  /* check for authenticated data */
281
0
  if (response->header.ad == 1)
282
0
    rrset->rri_flags |= RRSET_VALIDATED;
283
0
#endif
284
285
  /* copy name from answer section */
286
0
  rrset->rri_name = strdup(response->answer->name);
287
0
  if (rrset->rri_name == NULL) {
288
0
    result = ERRSET_NOMEMORY;
289
0
    goto fail;
290
0
  }
291
292
  /* count answers */
293
0
  rrset->rri_nrdatas = count_dns_rr(response->answer, rrset->rri_rdclass,
294
0
      rrset->rri_rdtype);
295
0
  rrset->rri_nsigs = count_dns_rr(response->answer, rrset->rri_rdclass,
296
0
      T_RRSIG);
297
298
  /* allocate memory for answers */
299
0
  rrset->rri_rdatas = calloc(rrset->rri_nrdatas,
300
0
      sizeof(struct rdatainfo));
301
0
  if (rrset->rri_rdatas == NULL) {
302
0
    result = ERRSET_NOMEMORY;
303
0
    goto fail;
304
0
  }
305
306
  /* allocate memory for signatures */
307
0
  if (rrset->rri_nsigs > 0) {
308
0
    rrset->rri_sigs = calloc(rrset->rri_nsigs, sizeof(struct rdatainfo));
309
0
    if (rrset->rri_sigs == NULL) {
310
0
      result = ERRSET_NOMEMORY;
311
0
      goto fail;
312
0
    }
313
0
  }
314
315
  /* copy answers & signatures */
316
0
  for (rr = response->answer, index_ans = 0, index_sig = 0;
317
0
      rr; rr = rr->next) {
318
319
0
    rdata = NULL;
320
321
0
    if (rr->class == rrset->rri_rdclass &&
322
0
        rr->type  == rrset->rri_rdtype)
323
0
      rdata = &rrset->rri_rdatas[index_ans++];
324
325
0
    if (rr->class == rrset->rri_rdclass &&
326
0
        rr->type  == T_RRSIG)
327
0
      rdata = &rrset->rri_sigs[index_sig++];
328
329
0
    if (rdata) {
330
0
      rdata->rdi_length = rr->size;
331
0
      if (rr->size != 0) {
332
0
        rdata->rdi_data   = malloc(rr->size);
333
0
        if (rdata->rdi_data == NULL) {
334
0
          result = ERRSET_NOMEMORY;
335
0
          goto fail;
336
0
        }
337
0
        memcpy(rdata->rdi_data, rr->rdata, rr->size);
338
0
      }
339
0
    }
340
0
  }
341
0
  free_dns_response(response);
342
343
0
  *res = rrset;
344
0
  return (ERRSET_SUCCESS);
345
346
0
fail:
347
0
  if (rrset != NULL)
348
0
    freerrset(rrset);
349
0
  if (response != NULL)
350
0
    free_dns_response(response);
351
0
  return (result);
352
0
}
353
354
void
355
freerrset(struct rrsetinfo *rrset)
356
0
{
357
0
  u_int16_t i;
358
359
0
  if (rrset == NULL)
360
0
    return;
361
362
0
  if (rrset->rri_rdatas) {
363
0
    for (i = 0; i < rrset->rri_nrdatas; i++) {
364
0
      if (rrset->rri_rdatas[i].rdi_data == NULL)
365
0
        break;
366
0
      free(rrset->rri_rdatas[i].rdi_data);
367
0
    }
368
0
    free(rrset->rri_rdatas);
369
0
  }
370
371
0
  if (rrset->rri_sigs) {
372
0
    for (i = 0; i < rrset->rri_nsigs; i++) {
373
0
      if (rrset->rri_sigs[i].rdi_data == NULL)
374
0
        break;
375
0
      free(rrset->rri_sigs[i].rdi_data);
376
0
    }
377
0
    free(rrset->rri_sigs);
378
0
  }
379
380
0
  if (rrset->rri_name)
381
0
    free(rrset->rri_name);
382
0
  free(rrset);
383
0
}
384
385
/*
386
 * DNS response parsing routines
387
 */
388
static struct dns_response *
389
parse_dns_response(const u_char *answer, int size)
390
0
{
391
0
  struct dns_response *resp;
392
0
  const u_char *cp;
393
394
0
  if (size < HFIXEDSZ)
395
0
    return (NULL);
396
397
  /* allocate memory for the response */
398
0
  resp = calloc(1, sizeof(*resp));
399
0
  if (resp == NULL)
400
0
    return (NULL);
401
402
  /* initialize current pointer */
403
0
  cp = answer;
404
405
  /* copy header */
406
0
  memcpy(&resp->header, cp, HFIXEDSZ);
407
0
  cp += HFIXEDSZ;
408
409
  /* fix header byte order */
410
0
  resp->header.qdcount = ntohs(resp->header.qdcount);
411
0
  resp->header.ancount = ntohs(resp->header.ancount);
412
0
  resp->header.nscount = ntohs(resp->header.nscount);
413
0
  resp->header.arcount = ntohs(resp->header.arcount);
414
415
  /* there must be at least one query */
416
0
  if (resp->header.qdcount < 1) {
417
0
    free_dns_response(resp);
418
0
    return (NULL);
419
0
  }
420
421
  /* parse query section */
422
0
  resp->query = parse_dns_qsection(answer, size, &cp,
423
0
      resp->header.qdcount);
424
0
  if (resp->header.qdcount && resp->query == NULL) {
425
0
    free_dns_response(resp);
426
0
    return (NULL);
427
0
  }
428
429
  /* parse answer section */
430
0
  resp->answer = parse_dns_rrsection(answer, size, &cp,
431
0
      resp->header.ancount);
432
0
  if (resp->header.ancount && resp->answer == NULL) {
433
0
    free_dns_response(resp);
434
0
    return (NULL);
435
0
  }
436
437
  /* parse authority section */
438
0
  resp->authority = parse_dns_rrsection(answer, size, &cp,
439
0
      resp->header.nscount);
440
0
  if (resp->header.nscount && resp->authority == NULL) {
441
0
    free_dns_response(resp);
442
0
    return (NULL);
443
0
  }
444
445
  /* parse additional section */
446
0
  resp->additional = parse_dns_rrsection(answer, size, &cp,
447
0
      resp->header.arcount);
448
0
  if (resp->header.arcount && resp->additional == NULL) {
449
0
    free_dns_response(resp);
450
0
    return (NULL);
451
0
  }
452
453
0
  return (resp);
454
0
}
455
456
static struct dns_query *
457
parse_dns_qsection(const u_char *answer, int size, const u_char **cp, int count)
458
0
{
459
0
  struct dns_query *head, *curr, *prev;
460
0
  int i, length;
461
0
  char name[MAXDNAME];
462
463
0
#define NEED(need) \
464
0
  do { \
465
0
    if (*cp + need > answer + size) \
466
0
      goto fail; \
467
0
  } while (0)
468
469
0
  for (i = 1, head = NULL, prev = NULL; i <= count; i++, prev = curr) {
470
0
    if (*cp >= answer + size) {
471
0
 fail:
472
0
      free_dns_query(head);
473
0
      return (NULL);
474
0
    }
475
    /* allocate and initialize struct */
476
0
    curr = calloc(1, sizeof(struct dns_query));
477
0
    if (curr == NULL)
478
0
      goto fail;
479
0
    if (head == NULL)
480
0
      head = curr;
481
0
    if (prev != NULL)
482
0
      prev->next = curr;
483
484
    /* name */
485
0
    length = dn_expand(answer, answer + size, *cp, name,
486
0
        sizeof(name));
487
0
    if (length < 0) {
488
0
      free_dns_query(head);
489
0
      return (NULL);
490
0
    }
491
0
    curr->name = strdup(name);
492
0
    if (curr->name == NULL) {
493
0
      free_dns_query(head);
494
0
      return (NULL);
495
0
    }
496
0
    NEED(length);
497
0
    *cp += length;
498
499
    /* type */
500
0
    NEED(INT16SZ);
501
0
    curr->type = _getshort(*cp);
502
0
    *cp += INT16SZ;
503
504
    /* class */
505
0
    NEED(INT16SZ);
506
0
    curr->class = _getshort(*cp);
507
0
    *cp += INT16SZ;
508
0
  }
509
0
#undef NEED
510
511
0
  return (head);
512
0
}
513
514
static struct dns_rr *
515
parse_dns_rrsection(const u_char *answer, int size, const u_char **cp,
516
    int count)
517
0
{
518
0
  struct dns_rr *head, *curr, *prev;
519
0
  int i, length;
520
0
  char name[MAXDNAME];
521
522
0
#define NEED(need) \
523
0
  do { \
524
0
    if (*cp + need > answer + size) \
525
0
      goto fail; \
526
0
  } while (0)
527
528
0
  for (i = 1, head = NULL, prev = NULL; i <= count; i++, prev = curr) {
529
0
    if (*cp >= answer + size) {
530
0
 fail:
531
0
      free_dns_rr(head);
532
0
      return (NULL);
533
0
    }
534
535
    /* allocate and initialize struct */
536
0
    curr = calloc(1, sizeof(struct dns_rr));
537
0
    if (curr == NULL)
538
0
      goto fail;
539
0
    if (head == NULL)
540
0
      head = curr;
541
0
    if (prev != NULL)
542
0
      prev->next = curr;
543
544
    /* name */
545
0
    length = dn_expand(answer, answer + size, *cp, name,
546
0
        sizeof(name));
547
0
    if (length < 0) {
548
0
      free_dns_rr(head);
549
0
      return (NULL);
550
0
    }
551
0
    curr->name = strdup(name);
552
0
    if (curr->name == NULL) {
553
0
      free_dns_rr(head);
554
0
      return (NULL);
555
0
    }
556
0
    NEED(length);
557
0
    *cp += length;
558
559
    /* type */
560
0
    NEED(INT16SZ);
561
0
    curr->type = _getshort(*cp);
562
0
    *cp += INT16SZ;
563
564
    /* class */
565
0
    NEED(INT16SZ);
566
0
    curr->class = _getshort(*cp);
567
0
    *cp += INT16SZ;
568
569
    /* ttl */
570
0
    NEED(INT32SZ);
571
0
    curr->ttl = _getlong(*cp);
572
0
    *cp += INT32SZ;
573
574
    /* rdata size */
575
0
    NEED(INT16SZ);
576
0
    curr->size = _getshort(*cp);
577
0
    *cp += INT16SZ;
578
579
    /* rdata itself */
580
0
    NEED(curr->size);
581
0
    if (curr->size != 0) {
582
0
      if ((curr->rdata = malloc(curr->size)) == NULL) {
583
0
        free_dns_rr(head);
584
0
        return (NULL);
585
0
      }
586
0
      memcpy(curr->rdata, *cp, curr->size);
587
0
    }
588
0
    *cp += curr->size;
589
0
  }
590
0
#undef NEED
591
592
0
  return (head);
593
0
}
594
595
static void
596
free_dns_query(struct dns_query *p)
597
0
{
598
0
  struct dns_query *next;
599
600
0
  while (p != NULL) {
601
0
    next = p->next;
602
0
    free(p->name);
603
0
    free(p);
604
0
    p = next;
605
0
  }
606
0
}
607
608
static void
609
free_dns_rr(struct dns_rr *p)
610
0
{
611
0
  struct dns_rr *next;
612
613
0
  while (p != NULL) {
614
0
    next = p->next;
615
0
    free(p->name);
616
0
    free(p->rdata);
617
0
    free(p);
618
0
    p = next;
619
0
  }
620
0
}
621
622
static void
623
free_dns_response(struct dns_response *p)
624
0
{
625
0
  if (p == NULL)
626
0
    return;
627
628
0
  free_dns_query(p->query);
629
0
  free_dns_rr(p->answer);
630
0
  free_dns_rr(p->authority);
631
0
  free_dns_rr(p->additional);
632
0
  free(p);
633
0
}
634
635
static int
636
count_dns_rr(struct dns_rr *p, u_int16_t class, u_int16_t type)
637
0
{
638
0
  int n = 0;
639
640
0
  while(p) {
641
0
    if (p->class == class && p->type == type)
642
0
      n++;
643
0
    p = p->next;
644
0
  }
645
646
0
  return (n);
647
0
}
648
649
#endif /*  !defined (HAVE_GETRRSETBYNAME) && !defined (HAVE_LDNS) */