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