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