/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) */ |