getrrsetbyname.c revision 124208
1124208Sdes/* $OpenBSD: getrrsetbyname.c,v 1.7 2003/03/07 07:34:14 itojun Exp $ */ 2124208Sdes 3124208Sdes/* 4124208Sdes * Copyright (c) 2001 Jakob Schlyter. All rights reserved. 5124208Sdes * 6124208Sdes * Redistribution and use in source and binary forms, with or without 7124208Sdes * modification, are permitted provided that the following conditions 8124208Sdes * are met: 9124208Sdes * 10124208Sdes * 1. Redistributions of source code must retain the above copyright 11124208Sdes * notice, this list of conditions and the following disclaimer. 12124208Sdes * 13124208Sdes * 2. Redistributions in binary form must reproduce the above copyright 14124208Sdes * notice, this list of conditions and the following disclaimer in the 15124208Sdes * documentation and/or other materials provided with the distribution. 16124208Sdes * 17124208Sdes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18124208Sdes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19124208Sdes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20124208Sdes * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21124208Sdes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22124208Sdes * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23124208Sdes * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24124208Sdes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25124208Sdes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26124208Sdes * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27124208Sdes */ 28124208Sdes 29124208Sdes/* 30124208Sdes * Portions Copyright (c) 1999-2001 Internet Software Consortium. 31124208Sdes * 32124208Sdes * Permission to use, copy, modify, and distribute this software for any 33124208Sdes * purpose with or without fee is hereby granted, provided that the above 34124208Sdes * copyright notice and this permission notice appear in all copies. 35124208Sdes * 36124208Sdes * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM 37124208Sdes * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL 38124208Sdes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL 39124208Sdes * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, 40124208Sdes * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING 41124208Sdes * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, 42124208Sdes * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 43124208Sdes * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 44124208Sdes */ 45124208Sdes 46124208Sdes#include "includes.h" 47124208Sdes 48124208Sdes#if defined(DNS) && !defined(HAVE_GETRRSETBYNAME) 49124208Sdes 50124208Sdes#include "getrrsetbyname.h" 51124208Sdes 52124208Sdes/* #include "thread_private.h" */ 53124208Sdes 54124208Sdes#define ANSWER_BUFFER_SIZE 1024*64 55124208Sdes 56124208Sdesstruct dns_query { 57124208Sdes char *name; 58124208Sdes u_int16_t type; 59124208Sdes u_int16_t class; 60124208Sdes struct dns_query *next; 61124208Sdes}; 62124208Sdes 63124208Sdesstruct dns_rr { 64124208Sdes char *name; 65124208Sdes u_int16_t type; 66124208Sdes u_int16_t class; 67124208Sdes u_int16_t ttl; 68124208Sdes u_int16_t size; 69124208Sdes void *rdata; 70124208Sdes struct dns_rr *next; 71124208Sdes}; 72124208Sdes 73124208Sdesstruct dns_response { 74124208Sdes HEADER header; 75124208Sdes struct dns_query *query; 76124208Sdes struct dns_rr *answer; 77124208Sdes struct dns_rr *authority; 78124208Sdes struct dns_rr *additional; 79124208Sdes}; 80124208Sdes 81124208Sdesstatic struct dns_response *parse_dns_response(const u_char *, int); 82124208Sdesstatic struct dns_query *parse_dns_qsection(const u_char *, int, 83124208Sdes const u_char **, int); 84124208Sdesstatic struct dns_rr *parse_dns_rrsection(const u_char *, int, const u_char **, 85124208Sdes int); 86124208Sdes 87124208Sdesstatic void free_dns_query(struct dns_query *); 88124208Sdesstatic void free_dns_rr(struct dns_rr *); 89124208Sdesstatic void free_dns_response(struct dns_response *); 90124208Sdes 91124208Sdesstatic int count_dns_rr(struct dns_rr *, u_int16_t, u_int16_t); 92124208Sdes 93124208Sdes/* 94124208Sdes * Inline versions of get/put short/long. Pointer is advanced. 95124208Sdes * 96124208Sdes * These macros demonstrate the property of C whereby it can be 97124208Sdes * portable or it can be elegant but rarely both. 98124208Sdes */ 99124208Sdes 100124208Sdes#ifndef INT32SZ 101124208Sdes# define INT32SZ 4 102124208Sdes#endif 103124208Sdes#ifndef INT16SZ 104124208Sdes# define INT16SZ 2 105124208Sdes#endif 106124208Sdes 107124208Sdes#ifndef GETSHORT 108124208Sdes#define GETSHORT(s, cp) { \ 109124208Sdes register u_char *t_cp = (u_char *)(cp); \ 110124208Sdes (s) = ((u_int16_t)t_cp[0] << 8) \ 111124208Sdes | ((u_int16_t)t_cp[1]) \ 112124208Sdes ; \ 113124208Sdes (cp) += INT16SZ; \ 114124208Sdes} 115124208Sdes#endif 116124208Sdes 117124208Sdes#ifndef GETLONG 118124208Sdes#define GETLONG(l, cp) { \ 119124208Sdes register u_char *t_cp = (u_char *)(cp); \ 120124208Sdes (l) = ((u_int32_t)t_cp[0] << 24) \ 121124208Sdes | ((u_int32_t)t_cp[1] << 16) \ 122124208Sdes | ((u_int32_t)t_cp[2] << 8) \ 123124208Sdes | ((u_int32_t)t_cp[3]) \ 124124208Sdes ; \ 125124208Sdes (cp) += INT32SZ; \ 126124208Sdes} 127124208Sdes#endif 128124208Sdes 129124208Sdes/* 130124208Sdes * Routines to insert/extract short/long's. 131124208Sdes */ 132124208Sdes 133124208Sdes#ifndef HAVE__GETSHORT 134124208Sdesstatic u_int16_t 135124208Sdes_getshort(msgp) 136124208Sdes register const u_char *msgp; 137124208Sdes{ 138124208Sdes register u_int16_t u; 139124208Sdes 140124208Sdes GETSHORT(u, msgp); 141124208Sdes return (u); 142124208Sdes} 143124208Sdes#endif 144124208Sdes 145124208Sdes#ifndef HAVE__GETLONG 146124208Sdesstatic u_int32_t 147124208Sdes_getlong(msgp) 148124208Sdes register const u_char *msgp; 149124208Sdes{ 150124208Sdes register u_int32_t u; 151124208Sdes 152124208Sdes GETLONG(u, msgp); 153124208Sdes return (u); 154124208Sdes} 155124208Sdes#endif 156124208Sdes 157124208Sdesint 158124208Sdesgetrrsetbyname(const char *hostname, unsigned int rdclass, 159124208Sdes unsigned int rdtype, unsigned int flags, 160124208Sdes struct rrsetinfo **res) 161124208Sdes{ 162124208Sdes struct __res_state *_resp = &_res; 163124208Sdes int result; 164124208Sdes struct rrsetinfo *rrset = NULL; 165124208Sdes struct dns_response *response; 166124208Sdes struct dns_rr *rr; 167124208Sdes struct rdatainfo *rdata; 168124208Sdes int length; 169124208Sdes unsigned int index_ans, index_sig; 170124208Sdes u_char answer[ANSWER_BUFFER_SIZE]; 171124208Sdes 172124208Sdes /* check for invalid class and type */ 173124208Sdes if (rdclass > 0xffff || rdtype > 0xffff) { 174124208Sdes result = ERRSET_INVAL; 175124208Sdes goto fail; 176124208Sdes } 177124208Sdes 178124208Sdes /* don't allow queries of class or type ANY */ 179124208Sdes if (rdclass == 0xff || rdtype == 0xff) { 180124208Sdes result = ERRSET_INVAL; 181124208Sdes goto fail; 182124208Sdes } 183124208Sdes 184124208Sdes /* don't allow flags yet, unimplemented */ 185124208Sdes if (flags) { 186124208Sdes result = ERRSET_INVAL; 187124208Sdes goto fail; 188124208Sdes } 189124208Sdes 190124208Sdes /* initialize resolver */ 191124208Sdes if ((_resp->options & RES_INIT) == 0 && res_init() == -1) { 192124208Sdes result = ERRSET_FAIL; 193124208Sdes goto fail; 194124208Sdes } 195124208Sdes 196124208Sdes#ifdef DEBUG 197124208Sdes _resp->options |= RES_DEBUG; 198124208Sdes#endif /* DEBUG */ 199124208Sdes 200124208Sdes#ifdef RES_USE_DNSSEC 201124208Sdes /* turn on DNSSEC if EDNS0 is configured */ 202124208Sdes if (_resp->options & RES_USE_EDNS0) 203124208Sdes _resp->options |= RES_USE_DNSSEC; 204124208Sdes#endif /* RES_USE_DNSEC */ 205124208Sdes 206124208Sdes /* make query */ 207124208Sdes length = res_query(hostname, (signed int) rdclass, (signed int) rdtype, 208124208Sdes answer, sizeof(answer)); 209124208Sdes if (length < 0) { 210124208Sdes switch(h_errno) { 211124208Sdes case HOST_NOT_FOUND: 212124208Sdes result = ERRSET_NONAME; 213124208Sdes goto fail; 214124208Sdes case NO_DATA: 215124208Sdes result = ERRSET_NODATA; 216124208Sdes goto fail; 217124208Sdes default: 218124208Sdes result = ERRSET_FAIL; 219124208Sdes goto fail; 220124208Sdes } 221124208Sdes } 222124208Sdes 223124208Sdes /* parse result */ 224124208Sdes response = parse_dns_response(answer, length); 225124208Sdes if (response == NULL) { 226124208Sdes result = ERRSET_FAIL; 227124208Sdes goto fail; 228124208Sdes } 229124208Sdes 230124208Sdes if (response->header.qdcount != 1) { 231124208Sdes result = ERRSET_FAIL; 232124208Sdes goto fail; 233124208Sdes } 234124208Sdes 235124208Sdes /* initialize rrset */ 236124208Sdes rrset = calloc(1, sizeof(struct rrsetinfo)); 237124208Sdes if (rrset == NULL) { 238124208Sdes result = ERRSET_NOMEMORY; 239124208Sdes goto fail; 240124208Sdes } 241124208Sdes rrset->rri_rdclass = response->query->class; 242124208Sdes rrset->rri_rdtype = response->query->type; 243124208Sdes rrset->rri_ttl = response->answer->ttl; 244124208Sdes rrset->rri_nrdatas = response->header.ancount; 245124208Sdes 246124208Sdes#ifdef HAVE_HEADER_AD 247124208Sdes /* check for authenticated data */ 248124208Sdes if (response->header.ad == 1) 249124208Sdes rrset->rri_flags |= RRSET_VALIDATED; 250124208Sdes#endif 251124208Sdes 252124208Sdes /* copy name from answer section */ 253124208Sdes length = strlen(response->answer->name); 254124208Sdes rrset->rri_name = malloc(length + 1); 255124208Sdes if (rrset->rri_name == NULL) { 256124208Sdes result = ERRSET_NOMEMORY; 257124208Sdes goto fail; 258124208Sdes } 259124208Sdes strlcpy(rrset->rri_name, response->answer->name, length + 1); 260124208Sdes 261124208Sdes /* count answers */ 262124208Sdes rrset->rri_nrdatas = count_dns_rr(response->answer, rrset->rri_rdclass, 263124208Sdes rrset->rri_rdtype); 264124208Sdes rrset->rri_nsigs = count_dns_rr(response->answer, rrset->rri_rdclass, 265124208Sdes T_SIG); 266124208Sdes 267124208Sdes /* allocate memory for answers */ 268124208Sdes rrset->rri_rdatas = calloc(rrset->rri_nrdatas, 269124208Sdes sizeof(struct rdatainfo)); 270124208Sdes if (rrset->rri_rdatas == NULL) { 271124208Sdes result = ERRSET_NOMEMORY; 272124208Sdes goto fail; 273124208Sdes } 274124208Sdes 275124208Sdes /* allocate memory for signatures */ 276124208Sdes rrset->rri_sigs = calloc(rrset->rri_nsigs, sizeof(struct rdatainfo)); 277124208Sdes if (rrset->rri_sigs == NULL) { 278124208Sdes result = ERRSET_NOMEMORY; 279124208Sdes goto fail; 280124208Sdes } 281124208Sdes 282124208Sdes /* copy answers & signatures */ 283124208Sdes for (rr = response->answer, index_ans = 0, index_sig = 0; 284124208Sdes rr; rr = rr->next) { 285124208Sdes 286124208Sdes rdata = NULL; 287124208Sdes 288124208Sdes if (rr->class == rrset->rri_rdclass && 289124208Sdes rr->type == rrset->rri_rdtype) 290124208Sdes rdata = &rrset->rri_rdatas[index_ans++]; 291124208Sdes 292124208Sdes if (rr->class == rrset->rri_rdclass && 293124208Sdes rr->type == T_SIG) 294124208Sdes rdata = &rrset->rri_sigs[index_sig++]; 295124208Sdes 296124208Sdes if (rdata) { 297124208Sdes rdata->rdi_length = rr->size; 298124208Sdes rdata->rdi_data = malloc(rr->size); 299124208Sdes 300124208Sdes if (rdata->rdi_data == NULL) { 301124208Sdes result = ERRSET_NOMEMORY; 302124208Sdes goto fail; 303124208Sdes } 304124208Sdes memcpy(rdata->rdi_data, rr->rdata, rr->size); 305124208Sdes } 306124208Sdes } 307124208Sdes 308124208Sdes *res = rrset; 309124208Sdes return (ERRSET_SUCCESS); 310124208Sdes 311124208Sdesfail: 312124208Sdes if (rrset != NULL) 313124208Sdes freerrset(rrset); 314124208Sdes return (result); 315124208Sdes} 316124208Sdes 317124208Sdesvoid 318124208Sdesfreerrset(struct rrsetinfo *rrset) 319124208Sdes{ 320124208Sdes u_int16_t i; 321124208Sdes 322124208Sdes if (rrset == NULL) 323124208Sdes return; 324124208Sdes 325124208Sdes if (rrset->rri_rdatas) { 326124208Sdes for (i = 0; i < rrset->rri_nrdatas; i++) { 327124208Sdes if (rrset->rri_rdatas[i].rdi_data == NULL) 328124208Sdes break; 329124208Sdes free(rrset->rri_rdatas[i].rdi_data); 330124208Sdes } 331124208Sdes free(rrset->rri_rdatas); 332124208Sdes } 333124208Sdes 334124208Sdes if (rrset->rri_sigs) { 335124208Sdes for (i = 0; i < rrset->rri_nsigs; i++) { 336124208Sdes if (rrset->rri_sigs[i].rdi_data == NULL) 337124208Sdes break; 338124208Sdes free(rrset->rri_sigs[i].rdi_data); 339124208Sdes } 340124208Sdes free(rrset->rri_sigs); 341124208Sdes } 342124208Sdes 343124208Sdes if (rrset->rri_name) 344124208Sdes free(rrset->rri_name); 345124208Sdes free(rrset); 346124208Sdes} 347124208Sdes 348124208Sdes/* 349124208Sdes * DNS response parsing routines 350124208Sdes */ 351124208Sdesstatic struct dns_response * 352124208Sdesparse_dns_response(const u_char *answer, int size) 353124208Sdes{ 354124208Sdes struct dns_response *resp; 355124208Sdes const u_char *cp; 356124208Sdes 357124208Sdes /* allocate memory for the response */ 358124208Sdes resp = calloc(1, sizeof(*resp)); 359124208Sdes if (resp == NULL) 360124208Sdes return (NULL); 361124208Sdes 362124208Sdes /* initialize current pointer */ 363124208Sdes cp = answer; 364124208Sdes 365124208Sdes /* copy header */ 366124208Sdes memcpy(&resp->header, cp, HFIXEDSZ); 367124208Sdes cp += HFIXEDSZ; 368124208Sdes 369124208Sdes /* fix header byte order */ 370124208Sdes resp->header.qdcount = ntohs(resp->header.qdcount); 371124208Sdes resp->header.ancount = ntohs(resp->header.ancount); 372124208Sdes resp->header.nscount = ntohs(resp->header.nscount); 373124208Sdes resp->header.arcount = ntohs(resp->header.arcount); 374124208Sdes 375124208Sdes /* there must be at least one query */ 376124208Sdes if (resp->header.qdcount < 1) { 377124208Sdes free_dns_response(resp); 378124208Sdes return (NULL); 379124208Sdes } 380124208Sdes 381124208Sdes /* parse query section */ 382124208Sdes resp->query = parse_dns_qsection(answer, size, &cp, 383124208Sdes resp->header.qdcount); 384124208Sdes if (resp->header.qdcount && resp->query == NULL) { 385124208Sdes free_dns_response(resp); 386124208Sdes return (NULL); 387124208Sdes } 388124208Sdes 389124208Sdes /* parse answer section */ 390124208Sdes resp->answer = parse_dns_rrsection(answer, size, &cp, 391124208Sdes resp->header.ancount); 392124208Sdes if (resp->header.ancount && resp->answer == NULL) { 393124208Sdes free_dns_response(resp); 394124208Sdes return (NULL); 395124208Sdes } 396124208Sdes 397124208Sdes /* parse authority section */ 398124208Sdes resp->authority = parse_dns_rrsection(answer, size, &cp, 399124208Sdes resp->header.nscount); 400124208Sdes if (resp->header.nscount && resp->authority == NULL) { 401124208Sdes free_dns_response(resp); 402124208Sdes return (NULL); 403124208Sdes } 404124208Sdes 405124208Sdes /* parse additional section */ 406124208Sdes resp->additional = parse_dns_rrsection(answer, size, &cp, 407124208Sdes resp->header.arcount); 408124208Sdes if (resp->header.arcount && resp->additional == NULL) { 409124208Sdes free_dns_response(resp); 410124208Sdes return (NULL); 411124208Sdes } 412124208Sdes 413124208Sdes return (resp); 414124208Sdes} 415124208Sdes 416124208Sdesstatic struct dns_query * 417124208Sdesparse_dns_qsection(const u_char *answer, int size, const u_char **cp, int count) 418124208Sdes{ 419124208Sdes struct dns_query *head, *curr, *prev; 420124208Sdes int i, length; 421124208Sdes char name[MAXDNAME]; 422124208Sdes 423124208Sdes for (i = 1, head = NULL, prev = NULL; i <= count; i++, prev = curr) { 424124208Sdes 425124208Sdes /* allocate and initialize struct */ 426124208Sdes curr = calloc(1, sizeof(struct dns_query)); 427124208Sdes if (curr == NULL) { 428124208Sdes free_dns_query(head); 429124208Sdes return (NULL); 430124208Sdes } 431124208Sdes if (head == NULL) 432124208Sdes head = curr; 433124208Sdes if (prev != NULL) 434124208Sdes prev->next = curr; 435124208Sdes 436124208Sdes /* name */ 437124208Sdes length = dn_expand(answer, answer + size, *cp, name, 438124208Sdes sizeof(name)); 439124208Sdes if (length < 0) { 440124208Sdes free_dns_query(head); 441124208Sdes return (NULL); 442124208Sdes } 443124208Sdes curr->name = strdup(name); 444124208Sdes if (curr->name == NULL) { 445124208Sdes free_dns_query(head); 446124208Sdes return (NULL); 447124208Sdes } 448124208Sdes *cp += length; 449124208Sdes 450124208Sdes /* type */ 451124208Sdes curr->type = _getshort(*cp); 452124208Sdes *cp += INT16SZ; 453124208Sdes 454124208Sdes /* class */ 455124208Sdes curr->class = _getshort(*cp); 456124208Sdes *cp += INT16SZ; 457124208Sdes } 458124208Sdes 459124208Sdes return (head); 460124208Sdes} 461124208Sdes 462124208Sdesstatic struct dns_rr * 463124208Sdesparse_dns_rrsection(const u_char *answer, int size, const u_char **cp, int count) 464124208Sdes{ 465124208Sdes struct dns_rr *head, *curr, *prev; 466124208Sdes int i, length; 467124208Sdes char name[MAXDNAME]; 468124208Sdes 469124208Sdes for (i = 1, head = NULL, prev = NULL; i <= count; i++, prev = curr) { 470124208Sdes 471124208Sdes /* allocate and initialize struct */ 472124208Sdes curr = calloc(1, sizeof(struct dns_rr)); 473124208Sdes if (curr == NULL) { 474124208Sdes free_dns_rr(head); 475124208Sdes return (NULL); 476124208Sdes } 477124208Sdes if (head == NULL) 478124208Sdes head = curr; 479124208Sdes if (prev != NULL) 480124208Sdes prev->next = curr; 481124208Sdes 482124208Sdes /* name */ 483124208Sdes length = dn_expand(answer, answer + size, *cp, name, 484124208Sdes sizeof(name)); 485124208Sdes if (length < 0) { 486124208Sdes free_dns_rr(head); 487124208Sdes return (NULL); 488124208Sdes } 489124208Sdes curr->name = strdup(name); 490124208Sdes if (curr->name == NULL) { 491124208Sdes free_dns_rr(head); 492124208Sdes return (NULL); 493124208Sdes } 494124208Sdes *cp += length; 495124208Sdes 496124208Sdes /* type */ 497124208Sdes curr->type = _getshort(*cp); 498124208Sdes *cp += INT16SZ; 499124208Sdes 500124208Sdes /* class */ 501124208Sdes curr->class = _getshort(*cp); 502124208Sdes *cp += INT16SZ; 503124208Sdes 504124208Sdes /* ttl */ 505124208Sdes curr->ttl = _getlong(*cp); 506124208Sdes *cp += INT32SZ; 507124208Sdes 508124208Sdes /* rdata size */ 509124208Sdes curr->size = _getshort(*cp); 510124208Sdes *cp += INT16SZ; 511124208Sdes 512124208Sdes /* rdata itself */ 513124208Sdes curr->rdata = malloc(curr->size); 514124208Sdes if (curr->rdata == NULL) { 515124208Sdes free_dns_rr(head); 516124208Sdes return (NULL); 517124208Sdes } 518124208Sdes memcpy(curr->rdata, *cp, curr->size); 519124208Sdes *cp += curr->size; 520124208Sdes } 521124208Sdes 522124208Sdes return (head); 523124208Sdes} 524124208Sdes 525124208Sdesstatic void 526124208Sdesfree_dns_query(struct dns_query *p) 527124208Sdes{ 528124208Sdes if (p == NULL) 529124208Sdes return; 530124208Sdes 531124208Sdes if (p->name) 532124208Sdes free(p->name); 533124208Sdes free_dns_query(p->next); 534124208Sdes free(p); 535124208Sdes} 536124208Sdes 537124208Sdesstatic void 538124208Sdesfree_dns_rr(struct dns_rr *p) 539124208Sdes{ 540124208Sdes if (p == NULL) 541124208Sdes return; 542124208Sdes 543124208Sdes if (p->name) 544124208Sdes free(p->name); 545124208Sdes if (p->rdata) 546124208Sdes free(p->rdata); 547124208Sdes free_dns_rr(p->next); 548124208Sdes free(p); 549124208Sdes} 550124208Sdes 551124208Sdesstatic void 552124208Sdesfree_dns_response(struct dns_response *p) 553124208Sdes{ 554124208Sdes if (p == NULL) 555124208Sdes return; 556124208Sdes 557124208Sdes free_dns_query(p->query); 558124208Sdes free_dns_rr(p->answer); 559124208Sdes free_dns_rr(p->authority); 560124208Sdes free_dns_rr(p->additional); 561124208Sdes free(p); 562124208Sdes} 563124208Sdes 564124208Sdesstatic int 565124208Sdescount_dns_rr(struct dns_rr *p, u_int16_t class, u_int16_t type) 566124208Sdes{ 567124208Sdes int n = 0; 568124208Sdes 569124208Sdes while(p) { 570124208Sdes if (p->class == class && p->type == type) 571124208Sdes n++; 572124208Sdes p = p->next; 573124208Sdes } 574124208Sdes 575124208Sdes return (n); 576124208Sdes} 577124208Sdes 578124208Sdes#endif /* defined(DNS) && !defined(HAVE_GETRRSETBYNAME) */ 579