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