1238106Sdes/* 2238106Sdes * util/data/msgreply.c - store message and reply data. 3238106Sdes * 4238106Sdes * Copyright (c) 2007, NLnet Labs. All rights reserved. 5238106Sdes * 6238106Sdes * This software is open source. 7238106Sdes * 8238106Sdes * Redistribution and use in source and binary forms, with or without 9238106Sdes * modification, are permitted provided that the following conditions 10238106Sdes * are met: 11238106Sdes * 12238106Sdes * Redistributions of source code must retain the above copyright notice, 13238106Sdes * this list of conditions and the following disclaimer. 14238106Sdes * 15238106Sdes * Redistributions in binary form must reproduce the above copyright notice, 16238106Sdes * this list of conditions and the following disclaimer in the documentation 17238106Sdes * and/or other materials provided with the distribution. 18238106Sdes * 19238106Sdes * Neither the name of the NLNET LABS nor the names of its contributors may 20238106Sdes * be used to endorse or promote products derived from this software without 21238106Sdes * specific prior written permission. 22238106Sdes * 23238106Sdes * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24269257Sdes * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25269257Sdes * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 26269257Sdes * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27269257Sdes * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28269257Sdes * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29269257Sdes * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30269257Sdes * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31269257Sdes * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32269257Sdes * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33269257Sdes * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34238106Sdes */ 35238106Sdes 36238106Sdes/** 37238106Sdes * \file 38238106Sdes * 39238106Sdes * This file contains a data structure to store a message and its reply. 40238106Sdes */ 41238106Sdes 42238106Sdes#include "config.h" 43238106Sdes#include "util/data/msgreply.h" 44238106Sdes#include "util/storage/lookup3.h" 45238106Sdes#include "util/log.h" 46238106Sdes#include "util/alloc.h" 47238106Sdes#include "util/netevent.h" 48238106Sdes#include "util/net_help.h" 49238106Sdes#include "util/data/dname.h" 50238106Sdes#include "util/regional.h" 51238106Sdes#include "util/data/msgparse.h" 52238106Sdes#include "util/data/msgencode.h" 53291767Sdes#include "sldns/sbuffer.h" 54291767Sdes#include "sldns/wire2str.h" 55238106Sdes 56238106Sdes/** MAX TTL default for messages and rrsets */ 57269257Sdestime_t MAX_TTL = 3600 * 24 * 10; /* ten days */ 58238106Sdes/** MIN TTL default for messages and rrsets */ 59269257Sdestime_t MIN_TTL = 0; 60291767Sdes/** MAX Negative TTL, for SOA records in authority section */ 61291767Sdestime_t MAX_NEG_TTL = 3600; /* one hour */ 62238106Sdes 63238106Sdes/** allocate qinfo, return 0 on error */ 64238106Sdesstatic int 65269257Sdesparse_create_qinfo(sldns_buffer* pkt, struct msg_parse* msg, 66238106Sdes struct query_info* qinf, struct regional* region) 67238106Sdes{ 68238106Sdes if(msg->qname) { 69238106Sdes if(region) 70238106Sdes qinf->qname = (uint8_t*)regional_alloc(region, 71238106Sdes msg->qname_len); 72238106Sdes else qinf->qname = (uint8_t*)malloc(msg->qname_len); 73238106Sdes if(!qinf->qname) return 0; 74238106Sdes dname_pkt_copy(pkt, qinf->qname, msg->qname); 75238106Sdes } else qinf->qname = 0; 76238106Sdes qinf->qname_len = msg->qname_len; 77238106Sdes qinf->qtype = msg->qtype; 78238106Sdes qinf->qclass = msg->qclass; 79238106Sdes return 1; 80238106Sdes} 81238106Sdes 82238106Sdes/** constructor for replyinfo */ 83285206Sdesstruct reply_info* 84238106Sdesconstruct_reply_info_base(struct regional* region, uint16_t flags, size_t qd, 85269257Sdes time_t ttl, time_t prettl, size_t an, size_t ns, size_t ar, 86238106Sdes size_t total, enum sec_status sec) 87238106Sdes{ 88238106Sdes struct reply_info* rep; 89238106Sdes /* rrset_count-1 because the first ref is part of the struct. */ 90238106Sdes size_t s = sizeof(struct reply_info) - sizeof(struct rrset_ref) + 91238106Sdes sizeof(struct ub_packed_rrset_key*) * total; 92291767Sdes if(total >= RR_COUNT_MAX) return NULL; /* sanity check on numRRS*/ 93238106Sdes if(region) 94238106Sdes rep = (struct reply_info*)regional_alloc(region, s); 95238106Sdes else rep = (struct reply_info*)malloc(s + 96238106Sdes sizeof(struct rrset_ref) * (total)); 97238106Sdes if(!rep) 98238106Sdes return NULL; 99238106Sdes rep->flags = flags; 100238106Sdes rep->qdcount = qd; 101238106Sdes rep->ttl = ttl; 102238106Sdes rep->prefetch_ttl = prettl; 103238106Sdes rep->an_numrrsets = an; 104238106Sdes rep->ns_numrrsets = ns; 105238106Sdes rep->ar_numrrsets = ar; 106238106Sdes rep->rrset_count = total; 107238106Sdes rep->security = sec; 108238106Sdes rep->authoritative = 0; 109238106Sdes /* array starts after the refs */ 110238106Sdes if(region) 111238106Sdes rep->rrsets = (struct ub_packed_rrset_key**)&(rep->ref[0]); 112238106Sdes else rep->rrsets = (struct ub_packed_rrset_key**)&(rep->ref[total]); 113238106Sdes /* zero the arrays to assist cleanup in case of malloc failure */ 114238106Sdes memset( rep->rrsets, 0, sizeof(struct ub_packed_rrset_key*) * total); 115238106Sdes if(!region) 116238106Sdes memset( &rep->ref[0], 0, sizeof(struct rrset_ref) * total); 117238106Sdes return rep; 118238106Sdes} 119238106Sdes 120238106Sdes/** allocate replyinfo, return 0 on error */ 121238106Sdesstatic int 122238106Sdesparse_create_repinfo(struct msg_parse* msg, struct reply_info** rep, 123238106Sdes struct regional* region) 124238106Sdes{ 125238106Sdes *rep = construct_reply_info_base(region, msg->flags, msg->qdcount, 0, 126238106Sdes 0, msg->an_rrsets, msg->ns_rrsets, msg->ar_rrsets, 127238106Sdes msg->rrset_count, sec_status_unchecked); 128238106Sdes if(!*rep) 129238106Sdes return 0; 130238106Sdes return 1; 131238106Sdes} 132238106Sdes 133238106Sdes/** allocate (special) rrset keys, return 0 on error */ 134238106Sdesstatic int 135238106Sdesrepinfo_alloc_rrset_keys(struct reply_info* rep, struct alloc_cache* alloc, 136238106Sdes struct regional* region) 137238106Sdes{ 138238106Sdes size_t i; 139238106Sdes for(i=0; i<rep->rrset_count; i++) { 140238106Sdes if(region) { 141238106Sdes rep->rrsets[i] = (struct ub_packed_rrset_key*) 142238106Sdes regional_alloc(region, 143238106Sdes sizeof(struct ub_packed_rrset_key)); 144238106Sdes if(rep->rrsets[i]) { 145238106Sdes memset(rep->rrsets[i], 0, 146238106Sdes sizeof(struct ub_packed_rrset_key)); 147238106Sdes rep->rrsets[i]->entry.key = rep->rrsets[i]; 148238106Sdes } 149238106Sdes } 150238106Sdes else rep->rrsets[i] = alloc_special_obtain(alloc); 151238106Sdes if(!rep->rrsets[i]) 152238106Sdes return 0; 153238106Sdes rep->rrsets[i]->entry.data = NULL; 154238106Sdes } 155238106Sdes return 1; 156238106Sdes} 157238106Sdes 158291767Sdes/** find the minimumttl in the rdata of SOA record */ 159291767Sdesstatic time_t 160291767Sdessoa_find_minttl(struct rr_parse* rr) 161291767Sdes{ 162291767Sdes uint16_t rlen = sldns_read_uint16(rr->ttl_data+4); 163291767Sdes if(rlen < 20) 164291767Sdes return 0; /* rdata too small for SOA (dname, dname, 5*32bit) */ 165291767Sdes /* minimum TTL is the last 32bit value in the rdata of the record */ 166291767Sdes /* at position ttl_data + 4(ttl) + 2(rdatalen) + rdatalen - 4(timeval)*/ 167291767Sdes return (time_t)sldns_read_uint32(rr->ttl_data+6+rlen-4); 168291767Sdes} 169291767Sdes 170238106Sdes/** do the rdata copy */ 171238106Sdesstatic int 172269257Sdesrdata_copy(sldns_buffer* pkt, struct packed_rrset_data* data, uint8_t* to, 173291767Sdes struct rr_parse* rr, time_t* rr_ttl, uint16_t type, 174291767Sdes sldns_pkt_section section) 175238106Sdes{ 176238106Sdes uint16_t pkt_len; 177269257Sdes const sldns_rr_descriptor* desc; 178238106Sdes 179269257Sdes *rr_ttl = sldns_read_uint32(rr->ttl_data); 180238106Sdes /* RFC 2181 Section 8. if msb of ttl is set treat as if zero. */ 181238106Sdes if(*rr_ttl & 0x80000000U) 182238106Sdes *rr_ttl = 0; 183291767Sdes if(type == LDNS_RR_TYPE_SOA && section == LDNS_SECTION_AUTHORITY) { 184291767Sdes /* negative response. see if TTL of SOA record larger than the 185291767Sdes * minimum-ttl in the rdata of the SOA record */ 186291767Sdes if(*rr_ttl > soa_find_minttl(rr)) 187291767Sdes *rr_ttl = soa_find_minttl(rr); 188291767Sdes if(*rr_ttl > MAX_NEG_TTL) 189291767Sdes *rr_ttl = MAX_NEG_TTL; 190291767Sdes } 191238106Sdes if(*rr_ttl < MIN_TTL) 192238106Sdes *rr_ttl = MIN_TTL; 193238106Sdes if(*rr_ttl < data->ttl) 194238106Sdes data->ttl = *rr_ttl; 195238106Sdes 196238106Sdes if(rr->outside_packet) { 197238106Sdes /* uncompressed already, only needs copy */ 198238106Sdes memmove(to, rr->ttl_data+sizeof(uint32_t), rr->size); 199238106Sdes return 1; 200238106Sdes } 201238106Sdes 202269257Sdes sldns_buffer_set_position(pkt, (size_t) 203269257Sdes (rr->ttl_data - sldns_buffer_begin(pkt) + sizeof(uint32_t))); 204238106Sdes /* insert decompressed size into rdata len stored in memory */ 205238106Sdes /* -2 because rdatalen bytes are not included. */ 206238106Sdes pkt_len = htons(rr->size - 2); 207238106Sdes memmove(to, &pkt_len, sizeof(uint16_t)); 208238106Sdes to += 2; 209238106Sdes /* read packet rdata len */ 210269257Sdes pkt_len = sldns_buffer_read_u16(pkt); 211269257Sdes if(sldns_buffer_remaining(pkt) < pkt_len) 212238106Sdes return 0; 213269257Sdes desc = sldns_rr_descript(type); 214238106Sdes if(pkt_len > 0 && desc && desc->_dname_count > 0) { 215238106Sdes int count = (int)desc->_dname_count; 216238106Sdes int rdf = 0; 217238106Sdes size_t len; 218238106Sdes size_t oldpos; 219238106Sdes /* decompress dnames. */ 220238106Sdes while(pkt_len > 0 && count) { 221238106Sdes switch(desc->_wireformat[rdf]) { 222238106Sdes case LDNS_RDF_TYPE_DNAME: 223269257Sdes oldpos = sldns_buffer_position(pkt); 224238106Sdes dname_pkt_copy(pkt, to, 225269257Sdes sldns_buffer_current(pkt)); 226238106Sdes to += pkt_dname_len(pkt); 227269257Sdes pkt_len -= sldns_buffer_position(pkt)-oldpos; 228238106Sdes count--; 229238106Sdes len = 0; 230238106Sdes break; 231238106Sdes case LDNS_RDF_TYPE_STR: 232269257Sdes len = sldns_buffer_current(pkt)[0] + 1; 233238106Sdes break; 234238106Sdes default: 235238106Sdes len = get_rdf_size(desc->_wireformat[rdf]); 236238106Sdes break; 237238106Sdes } 238238106Sdes if(len) { 239269257Sdes memmove(to, sldns_buffer_current(pkt), len); 240238106Sdes to += len; 241269257Sdes sldns_buffer_skip(pkt, (ssize_t)len); 242238106Sdes log_assert(len <= pkt_len); 243238106Sdes pkt_len -= len; 244238106Sdes } 245238106Sdes rdf++; 246238106Sdes } 247238106Sdes } 248238106Sdes /* copy remaining rdata */ 249238106Sdes if(pkt_len > 0) 250269257Sdes memmove(to, sldns_buffer_current(pkt), pkt_len); 251238106Sdes 252238106Sdes return 1; 253238106Sdes} 254238106Sdes 255238106Sdes/** copy over the data into packed rrset */ 256238106Sdesstatic int 257269257Sdesparse_rr_copy(sldns_buffer* pkt, struct rrset_parse* pset, 258238106Sdes struct packed_rrset_data* data) 259238106Sdes{ 260238106Sdes size_t i; 261238106Sdes struct rr_parse* rr = pset->rr_first; 262238106Sdes uint8_t* nextrdata; 263238106Sdes size_t total = pset->rr_count + pset->rrsig_count; 264238106Sdes data->ttl = MAX_TTL; 265238106Sdes data->count = pset->rr_count; 266238106Sdes data->rrsig_count = pset->rrsig_count; 267238106Sdes data->trust = rrset_trust_none; 268238106Sdes data->security = sec_status_unchecked; 269238106Sdes /* layout: struct - rr_len - rr_data - rr_ttl - rdata - rrsig */ 270238106Sdes data->rr_len = (size_t*)((uint8_t*)data + 271238106Sdes sizeof(struct packed_rrset_data)); 272238106Sdes data->rr_data = (uint8_t**)&(data->rr_len[total]); 273269257Sdes data->rr_ttl = (time_t*)&(data->rr_data[total]); 274238106Sdes nextrdata = (uint8_t*)&(data->rr_ttl[total]); 275238106Sdes for(i=0; i<data->count; i++) { 276238106Sdes data->rr_len[i] = rr->size; 277238106Sdes data->rr_data[i] = nextrdata; 278238106Sdes nextrdata += rr->size; 279238106Sdes if(!rdata_copy(pkt, data, data->rr_data[i], rr, 280291767Sdes &data->rr_ttl[i], pset->type, pset->section)) 281238106Sdes return 0; 282238106Sdes rr = rr->next; 283238106Sdes } 284238106Sdes /* if rrsig, its rdata is at nextrdata */ 285238106Sdes rr = pset->rrsig_first; 286238106Sdes for(i=data->count; i<total; i++) { 287238106Sdes data->rr_len[i] = rr->size; 288238106Sdes data->rr_data[i] = nextrdata; 289238106Sdes nextrdata += rr->size; 290238106Sdes if(!rdata_copy(pkt, data, data->rr_data[i], rr, 291291767Sdes &data->rr_ttl[i], LDNS_RR_TYPE_RRSIG, pset->section)) 292238106Sdes return 0; 293238106Sdes rr = rr->next; 294238106Sdes } 295238106Sdes return 1; 296238106Sdes} 297238106Sdes 298238106Sdes/** create rrset return 0 on failure */ 299238106Sdesstatic int 300269257Sdesparse_create_rrset(sldns_buffer* pkt, struct rrset_parse* pset, 301238106Sdes struct packed_rrset_data** data, struct regional* region) 302238106Sdes{ 303238106Sdes /* allocate */ 304291767Sdes size_t s; 305291767Sdes if(pset->rr_count > RR_COUNT_MAX || pset->rrsig_count > RR_COUNT_MAX || 306291767Sdes pset->size > RR_COUNT_MAX) 307291767Sdes return 0; /* protect against integer overflow */ 308291767Sdes s = sizeof(struct packed_rrset_data) + 309238106Sdes (pset->rr_count + pset->rrsig_count) * 310269257Sdes (sizeof(size_t)+sizeof(uint8_t*)+sizeof(time_t)) + 311238106Sdes pset->size; 312238106Sdes if(region) 313238106Sdes *data = regional_alloc(region, s); 314238106Sdes else *data = malloc(s); 315238106Sdes if(!*data) 316238106Sdes return 0; 317238106Sdes /* copy & decompress */ 318238106Sdes if(!parse_rr_copy(pkt, pset, *data)) { 319238106Sdes if(!region) free(*data); 320238106Sdes return 0; 321238106Sdes } 322238106Sdes return 1; 323238106Sdes} 324238106Sdes 325238106Sdes/** get trust value for rrset */ 326238106Sdesstatic enum rrset_trust 327238106Sdesget_rrset_trust(struct msg_parse* msg, struct rrset_parse* rrset) 328238106Sdes{ 329238106Sdes uint16_t AA = msg->flags & BIT_AA; 330238106Sdes if(rrset->section == LDNS_SECTION_ANSWER) { 331238106Sdes if(AA) { 332238106Sdes /* RFC2181 says remainder of CNAME chain is nonauth*/ 333238106Sdes if(msg->rrset_first && 334238106Sdes msg->rrset_first->section==LDNS_SECTION_ANSWER 335238106Sdes && msg->rrset_first->type==LDNS_RR_TYPE_CNAME){ 336238106Sdes if(rrset == msg->rrset_first) 337238106Sdes return rrset_trust_ans_AA; 338238106Sdes else return rrset_trust_ans_noAA; 339238106Sdes } 340238106Sdes if(msg->rrset_first && 341238106Sdes msg->rrset_first->section==LDNS_SECTION_ANSWER 342238106Sdes && msg->rrset_first->type==LDNS_RR_TYPE_DNAME){ 343238106Sdes if(rrset == msg->rrset_first || 344238106Sdes rrset == msg->rrset_first->rrset_all_next) 345238106Sdes return rrset_trust_ans_AA; 346238106Sdes else return rrset_trust_ans_noAA; 347238106Sdes } 348238106Sdes return rrset_trust_ans_AA; 349238106Sdes } 350238106Sdes else return rrset_trust_ans_noAA; 351238106Sdes } else if(rrset->section == LDNS_SECTION_AUTHORITY) { 352238106Sdes if(AA) return rrset_trust_auth_AA; 353238106Sdes else return rrset_trust_auth_noAA; 354238106Sdes } else { 355238106Sdes /* addit section */ 356238106Sdes if(AA) return rrset_trust_add_AA; 357238106Sdes else return rrset_trust_add_noAA; 358238106Sdes } 359238106Sdes /* NOTREACHED */ 360238106Sdes return rrset_trust_none; 361238106Sdes} 362238106Sdes 363238106Sdesint 364269257Sdesparse_copy_decompress_rrset(sldns_buffer* pkt, struct msg_parse* msg, 365238106Sdes struct rrset_parse *pset, struct regional* region, 366238106Sdes struct ub_packed_rrset_key* pk) 367238106Sdes{ 368238106Sdes struct packed_rrset_data* data; 369238106Sdes pk->rk.flags = pset->flags; 370238106Sdes pk->rk.dname_len = pset->dname_len; 371238106Sdes if(region) 372238106Sdes pk->rk.dname = (uint8_t*)regional_alloc( 373238106Sdes region, pset->dname_len); 374238106Sdes else pk->rk.dname = 375238106Sdes (uint8_t*)malloc(pset->dname_len); 376238106Sdes if(!pk->rk.dname) 377238106Sdes return 0; 378238106Sdes /** copy & decompress dname */ 379238106Sdes dname_pkt_copy(pkt, pk->rk.dname, pset->dname); 380238106Sdes /** copy over type and class */ 381238106Sdes pk->rk.type = htons(pset->type); 382238106Sdes pk->rk.rrset_class = pset->rrset_class; 383238106Sdes /** read data part. */ 384238106Sdes if(!parse_create_rrset(pkt, pset, &data, region)) 385238106Sdes return 0; 386238106Sdes pk->entry.data = (void*)data; 387238106Sdes pk->entry.key = (void*)pk; 388238106Sdes pk->entry.hash = pset->hash; 389238106Sdes data->trust = get_rrset_trust(msg, pset); 390238106Sdes return 1; 391238106Sdes} 392238106Sdes 393238106Sdes/** 394238106Sdes * Copy and decompress rrs 395238106Sdes * @param pkt: the packet for compression pointer resolution. 396238106Sdes * @param msg: the parsed message 397238106Sdes * @param rep: reply info to put rrs into. 398238106Sdes * @param region: if not NULL, used for allocation. 399238106Sdes * @return 0 on failure. 400238106Sdes */ 401238106Sdesstatic int 402269257Sdesparse_copy_decompress(sldns_buffer* pkt, struct msg_parse* msg, 403238106Sdes struct reply_info* rep, struct regional* region) 404238106Sdes{ 405238106Sdes size_t i; 406238106Sdes struct rrset_parse *pset = msg->rrset_first; 407238106Sdes struct packed_rrset_data* data; 408238106Sdes log_assert(rep); 409238106Sdes rep->ttl = MAX_TTL; 410238106Sdes rep->security = sec_status_unchecked; 411238106Sdes if(rep->rrset_count == 0) 412238106Sdes rep->ttl = NORR_TTL; 413238106Sdes 414238106Sdes for(i=0; i<rep->rrset_count; i++) { 415238106Sdes if(!parse_copy_decompress_rrset(pkt, msg, pset, region, 416238106Sdes rep->rrsets[i])) 417238106Sdes return 0; 418238106Sdes data = (struct packed_rrset_data*)rep->rrsets[i]->entry.data; 419238106Sdes if(data->ttl < rep->ttl) 420238106Sdes rep->ttl = data->ttl; 421238106Sdes 422238106Sdes pset = pset->rrset_all_next; 423238106Sdes } 424238106Sdes rep->prefetch_ttl = PREFETCH_TTL_CALC(rep->ttl); 425238106Sdes return 1; 426238106Sdes} 427238106Sdes 428238106Sdesint 429269257Sdesparse_create_msg(sldns_buffer* pkt, struct msg_parse* msg, 430238106Sdes struct alloc_cache* alloc, struct query_info* qinf, 431238106Sdes struct reply_info** rep, struct regional* region) 432238106Sdes{ 433238106Sdes log_assert(pkt && msg); 434238106Sdes if(!parse_create_qinfo(pkt, msg, qinf, region)) 435238106Sdes return 0; 436238106Sdes if(!parse_create_repinfo(msg, rep, region)) 437238106Sdes return 0; 438238106Sdes if(!repinfo_alloc_rrset_keys(*rep, alloc, region)) 439238106Sdes return 0; 440238106Sdes if(!parse_copy_decompress(pkt, msg, *rep, region)) 441238106Sdes return 0; 442238106Sdes return 1; 443238106Sdes} 444238106Sdes 445269257Sdesint reply_info_parse(sldns_buffer* pkt, struct alloc_cache* alloc, 446238106Sdes struct query_info* qinf, struct reply_info** rep, 447238106Sdes struct regional* region, struct edns_data* edns) 448238106Sdes{ 449238106Sdes /* use scratch pad region-allocator during parsing. */ 450238106Sdes struct msg_parse* msg; 451238106Sdes int ret; 452238106Sdes 453238106Sdes qinf->qname = NULL; 454238106Sdes *rep = NULL; 455238106Sdes if(!(msg = regional_alloc(region, sizeof(*msg)))) { 456238106Sdes return LDNS_RCODE_SERVFAIL; 457238106Sdes } 458238106Sdes memset(msg, 0, sizeof(*msg)); 459238106Sdes 460269257Sdes sldns_buffer_set_position(pkt, 0); 461238106Sdes if((ret = parse_packet(pkt, msg, region)) != 0) { 462238106Sdes return ret; 463238106Sdes } 464238106Sdes if((ret = parse_extract_edns(msg, edns)) != 0) 465238106Sdes return ret; 466238106Sdes 467238106Sdes /* parse OK, allocate return structures */ 468238106Sdes /* this also performs dname decompression */ 469238106Sdes if(!parse_create_msg(pkt, msg, alloc, qinf, rep, NULL)) { 470238106Sdes query_info_clear(qinf); 471238106Sdes reply_info_parsedelete(*rep, alloc); 472238106Sdes *rep = NULL; 473238106Sdes return LDNS_RCODE_SERVFAIL; 474238106Sdes } 475238106Sdes return 0; 476238106Sdes} 477238106Sdes 478238106Sdes/** helper compare function to sort in lock order */ 479238106Sdesstatic int 480238106Sdesreply_info_sortref_cmp(const void* a, const void* b) 481238106Sdes{ 482238106Sdes struct rrset_ref* x = (struct rrset_ref*)a; 483238106Sdes struct rrset_ref* y = (struct rrset_ref*)b; 484238106Sdes if(x->key < y->key) return -1; 485238106Sdes if(x->key > y->key) return 1; 486238106Sdes return 0; 487238106Sdes} 488238106Sdes 489238106Sdesvoid 490238106Sdesreply_info_sortref(struct reply_info* rep) 491238106Sdes{ 492238106Sdes qsort(&rep->ref[0], rep->rrset_count, sizeof(struct rrset_ref), 493238106Sdes reply_info_sortref_cmp); 494238106Sdes} 495238106Sdes 496238106Sdesvoid 497269257Sdesreply_info_set_ttls(struct reply_info* rep, time_t timenow) 498238106Sdes{ 499238106Sdes size_t i, j; 500238106Sdes rep->ttl += timenow; 501238106Sdes rep->prefetch_ttl += timenow; 502238106Sdes for(i=0; i<rep->rrset_count; i++) { 503238106Sdes struct packed_rrset_data* data = (struct packed_rrset_data*) 504238106Sdes rep->ref[i].key->entry.data; 505238106Sdes if(i>0 && rep->ref[i].key == rep->ref[i-1].key) 506238106Sdes continue; 507238106Sdes data->ttl += timenow; 508238106Sdes for(j=0; j<data->count + data->rrsig_count; j++) { 509238106Sdes data->rr_ttl[j] += timenow; 510238106Sdes } 511238106Sdes } 512238106Sdes} 513238106Sdes 514238106Sdesvoid 515238106Sdesreply_info_parsedelete(struct reply_info* rep, struct alloc_cache* alloc) 516238106Sdes{ 517238106Sdes size_t i; 518238106Sdes if(!rep) 519238106Sdes return; 520238106Sdes /* no need to lock, since not shared in hashtables. */ 521238106Sdes for(i=0; i<rep->rrset_count; i++) { 522238106Sdes ub_packed_rrset_parsedelete(rep->rrsets[i], alloc); 523238106Sdes } 524238106Sdes free(rep); 525238106Sdes} 526238106Sdes 527238106Sdesint 528269257Sdesquery_info_parse(struct query_info* m, sldns_buffer* query) 529238106Sdes{ 530269257Sdes uint8_t* q = sldns_buffer_begin(query); 531238106Sdes /* minimum size: header + \0 + qtype + qclass */ 532269257Sdes if(sldns_buffer_limit(query) < LDNS_HEADER_SIZE + 5) 533238106Sdes return 0; 534238106Sdes if(LDNS_OPCODE_WIRE(q) != LDNS_PACKET_QUERY || 535269257Sdes LDNS_QDCOUNT(q) != 1 || sldns_buffer_position(query) != 0) 536238106Sdes return 0; 537269257Sdes sldns_buffer_skip(query, LDNS_HEADER_SIZE); 538269257Sdes m->qname = sldns_buffer_current(query); 539238106Sdes if((m->qname_len = query_dname_len(query)) == 0) 540238106Sdes return 0; /* parse error */ 541269257Sdes if(sldns_buffer_remaining(query) < 4) 542238106Sdes return 0; /* need qtype, qclass */ 543269257Sdes m->qtype = sldns_buffer_read_u16(query); 544269257Sdes m->qclass = sldns_buffer_read_u16(query); 545238106Sdes return 1; 546238106Sdes} 547238106Sdes 548238106Sdes/** tiny subroutine for msgreply_compare */ 549238106Sdes#define COMPARE_IT(x, y) \ 550238106Sdes if( (x) < (y) ) return -1; \ 551238106Sdes else if( (x) > (y) ) return +1; \ 552238106Sdes log_assert( (x) == (y) ); 553238106Sdes 554238106Sdesint 555238106Sdesquery_info_compare(void* m1, void* m2) 556238106Sdes{ 557238106Sdes struct query_info* msg1 = (struct query_info*)m1; 558238106Sdes struct query_info* msg2 = (struct query_info*)m2; 559238106Sdes int mc; 560238106Sdes /* from most different to least different for speed */ 561238106Sdes COMPARE_IT(msg1->qtype, msg2->qtype); 562238106Sdes if((mc = query_dname_compare(msg1->qname, msg2->qname)) != 0) 563238106Sdes return mc; 564238106Sdes log_assert(msg1->qname_len == msg2->qname_len); 565238106Sdes COMPARE_IT(msg1->qclass, msg2->qclass); 566238106Sdes return 0; 567238106Sdes#undef COMPARE_IT 568238106Sdes} 569238106Sdes 570238106Sdesvoid 571238106Sdesquery_info_clear(struct query_info* m) 572238106Sdes{ 573238106Sdes free(m->qname); 574238106Sdes m->qname = NULL; 575238106Sdes} 576238106Sdes 577238106Sdessize_t 578238106Sdesmsgreply_sizefunc(void* k, void* d) 579238106Sdes{ 580238106Sdes struct msgreply_entry* q = (struct msgreply_entry*)k; 581238106Sdes struct reply_info* r = (struct reply_info*)d; 582238106Sdes size_t s = sizeof(struct msgreply_entry) + sizeof(struct reply_info) 583238106Sdes + q->key.qname_len + lock_get_mem(&q->entry.lock) 584238106Sdes - sizeof(struct rrset_ref); 585238106Sdes s += r->rrset_count * sizeof(struct rrset_ref); 586238106Sdes s += r->rrset_count * sizeof(struct ub_packed_rrset_key*); 587238106Sdes return s; 588238106Sdes} 589238106Sdes 590238106Sdesvoid 591238106Sdesquery_entry_delete(void *k, void* ATTR_UNUSED(arg)) 592238106Sdes{ 593238106Sdes struct msgreply_entry* q = (struct msgreply_entry*)k; 594238106Sdes lock_rw_destroy(&q->entry.lock); 595238106Sdes query_info_clear(&q->key); 596238106Sdes free(q); 597238106Sdes} 598238106Sdes 599238106Sdesvoid 600238106Sdesreply_info_delete(void* d, void* ATTR_UNUSED(arg)) 601238106Sdes{ 602238106Sdes struct reply_info* r = (struct reply_info*)d; 603238106Sdes free(r); 604238106Sdes} 605238106Sdes 606238106Sdeshashvalue_t 607285206Sdesquery_info_hash(struct query_info *q, uint16_t flags) 608238106Sdes{ 609238106Sdes hashvalue_t h = 0xab; 610238106Sdes h = hashlittle(&q->qtype, sizeof(q->qtype), h); 611285206Sdes if(q->qtype == LDNS_RR_TYPE_AAAA && (flags&BIT_CD)) 612285206Sdes h++; 613238106Sdes h = hashlittle(&q->qclass, sizeof(q->qclass), h); 614238106Sdes h = dname_query_hash(q->qname, h); 615238106Sdes return h; 616238106Sdes} 617238106Sdes 618238106Sdesstruct msgreply_entry* 619238106Sdesquery_info_entrysetup(struct query_info* q, struct reply_info* r, 620238106Sdes hashvalue_t h) 621238106Sdes{ 622238106Sdes struct msgreply_entry* e = (struct msgreply_entry*)malloc( 623238106Sdes sizeof(struct msgreply_entry)); 624238106Sdes if(!e) return NULL; 625238106Sdes memcpy(&e->key, q, sizeof(*q)); 626238106Sdes e->entry.hash = h; 627238106Sdes e->entry.key = e; 628238106Sdes e->entry.data = r; 629238106Sdes lock_rw_init(&e->entry.lock); 630238106Sdes lock_protect(&e->entry.lock, &e->key, sizeof(e->key)); 631238106Sdes lock_protect(&e->entry.lock, &e->entry.hash, sizeof(e->entry.hash) + 632238106Sdes sizeof(e->entry.key) + sizeof(e->entry.data)); 633238106Sdes lock_protect(&e->entry.lock, e->key.qname, e->key.qname_len); 634238106Sdes q->qname = NULL; 635238106Sdes return e; 636238106Sdes} 637238106Sdes 638238106Sdes/** copy rrsets from replyinfo to dest replyinfo */ 639238106Sdesstatic int 640238106Sdesrepinfo_copy_rrsets(struct reply_info* dest, struct reply_info* from, 641238106Sdes struct regional* region) 642238106Sdes{ 643238106Sdes size_t i, s; 644238106Sdes struct packed_rrset_data* fd, *dd; 645238106Sdes struct ub_packed_rrset_key* fk, *dk; 646238106Sdes for(i=0; i<dest->rrset_count; i++) { 647238106Sdes fk = from->rrsets[i]; 648238106Sdes dk = dest->rrsets[i]; 649238106Sdes fd = (struct packed_rrset_data*)fk->entry.data; 650238106Sdes dk->entry.hash = fk->entry.hash; 651238106Sdes dk->rk = fk->rk; 652238106Sdes if(region) { 653238106Sdes dk->id = fk->id; 654238106Sdes dk->rk.dname = (uint8_t*)regional_alloc_init(region, 655238106Sdes fk->rk.dname, fk->rk.dname_len); 656238106Sdes } else 657238106Sdes dk->rk.dname = (uint8_t*)memdup(fk->rk.dname, 658238106Sdes fk->rk.dname_len); 659238106Sdes if(!dk->rk.dname) 660238106Sdes return 0; 661238106Sdes s = packed_rrset_sizeof(fd); 662238106Sdes if(region) 663238106Sdes dd = (struct packed_rrset_data*)regional_alloc_init( 664238106Sdes region, fd, s); 665238106Sdes else dd = (struct packed_rrset_data*)memdup(fd, s); 666238106Sdes if(!dd) 667238106Sdes return 0; 668238106Sdes packed_rrset_ptr_fixup(dd); 669238106Sdes dk->entry.data = (void*)dd; 670238106Sdes } 671238106Sdes return 1; 672238106Sdes} 673238106Sdes 674238106Sdesstruct reply_info* 675238106Sdesreply_info_copy(struct reply_info* rep, struct alloc_cache* alloc, 676238106Sdes struct regional* region) 677238106Sdes{ 678238106Sdes struct reply_info* cp; 679238106Sdes cp = construct_reply_info_base(region, rep->flags, rep->qdcount, 680238106Sdes rep->ttl, rep->prefetch_ttl, rep->an_numrrsets, 681238106Sdes rep->ns_numrrsets, rep->ar_numrrsets, rep->rrset_count, 682238106Sdes rep->security); 683238106Sdes if(!cp) 684238106Sdes return NULL; 685238106Sdes /* allocate ub_key structures special or not */ 686238106Sdes if(!repinfo_alloc_rrset_keys(cp, alloc, region)) { 687238106Sdes if(!region) 688238106Sdes reply_info_parsedelete(cp, alloc); 689238106Sdes return NULL; 690238106Sdes } 691238106Sdes if(!repinfo_copy_rrsets(cp, rep, region)) { 692238106Sdes if(!region) 693238106Sdes reply_info_parsedelete(cp, alloc); 694238106Sdes return NULL; 695238106Sdes } 696238106Sdes return cp; 697238106Sdes} 698238106Sdes 699238106Sdesuint8_t* 700238106Sdesreply_find_final_cname_target(struct query_info* qinfo, struct reply_info* rep) 701238106Sdes{ 702238106Sdes uint8_t* sname = qinfo->qname; 703238106Sdes size_t snamelen = qinfo->qname_len; 704238106Sdes size_t i; 705238106Sdes for(i=0; i<rep->an_numrrsets; i++) { 706238106Sdes struct ub_packed_rrset_key* s = rep->rrsets[i]; 707238106Sdes /* follow CNAME chain (if any) */ 708238106Sdes if(ntohs(s->rk.type) == LDNS_RR_TYPE_CNAME && 709238106Sdes ntohs(s->rk.rrset_class) == qinfo->qclass && 710238106Sdes snamelen == s->rk.dname_len && 711238106Sdes query_dname_compare(sname, s->rk.dname) == 0) { 712238106Sdes get_cname_target(s, &sname, &snamelen); 713238106Sdes } 714238106Sdes } 715238106Sdes if(sname != qinfo->qname) 716238106Sdes return sname; 717238106Sdes return NULL; 718238106Sdes} 719238106Sdes 720238106Sdesstruct ub_packed_rrset_key* 721238106Sdesreply_find_answer_rrset(struct query_info* qinfo, struct reply_info* rep) 722238106Sdes{ 723238106Sdes uint8_t* sname = qinfo->qname; 724238106Sdes size_t snamelen = qinfo->qname_len; 725238106Sdes size_t i; 726238106Sdes for(i=0; i<rep->an_numrrsets; i++) { 727238106Sdes struct ub_packed_rrset_key* s = rep->rrsets[i]; 728238106Sdes /* first match type, for query of qtype cname */ 729238106Sdes if(ntohs(s->rk.type) == qinfo->qtype && 730238106Sdes ntohs(s->rk.rrset_class) == qinfo->qclass && 731238106Sdes snamelen == s->rk.dname_len && 732238106Sdes query_dname_compare(sname, s->rk.dname) == 0) { 733238106Sdes return s; 734238106Sdes } 735238106Sdes /* follow CNAME chain (if any) */ 736238106Sdes if(ntohs(s->rk.type) == LDNS_RR_TYPE_CNAME && 737238106Sdes ntohs(s->rk.rrset_class) == qinfo->qclass && 738238106Sdes snamelen == s->rk.dname_len && 739238106Sdes query_dname_compare(sname, s->rk.dname) == 0) { 740238106Sdes get_cname_target(s, &sname, &snamelen); 741238106Sdes } 742238106Sdes } 743238106Sdes return NULL; 744238106Sdes} 745238106Sdes 746238106Sdesstruct ub_packed_rrset_key* reply_find_rrset_section_an(struct reply_info* rep, 747238106Sdes uint8_t* name, size_t namelen, uint16_t type, uint16_t dclass) 748238106Sdes{ 749238106Sdes size_t i; 750238106Sdes for(i=0; i<rep->an_numrrsets; i++) { 751238106Sdes struct ub_packed_rrset_key* s = rep->rrsets[i]; 752238106Sdes if(ntohs(s->rk.type) == type && 753238106Sdes ntohs(s->rk.rrset_class) == dclass && 754238106Sdes namelen == s->rk.dname_len && 755238106Sdes query_dname_compare(name, s->rk.dname) == 0) { 756238106Sdes return s; 757238106Sdes } 758238106Sdes } 759238106Sdes return NULL; 760238106Sdes} 761238106Sdes 762238106Sdesstruct ub_packed_rrset_key* reply_find_rrset_section_ns(struct reply_info* rep, 763238106Sdes uint8_t* name, size_t namelen, uint16_t type, uint16_t dclass) 764238106Sdes{ 765238106Sdes size_t i; 766238106Sdes for(i=rep->an_numrrsets; i<rep->an_numrrsets+rep->ns_numrrsets; i++) { 767238106Sdes struct ub_packed_rrset_key* s = rep->rrsets[i]; 768238106Sdes if(ntohs(s->rk.type) == type && 769238106Sdes ntohs(s->rk.rrset_class) == dclass && 770238106Sdes namelen == s->rk.dname_len && 771238106Sdes query_dname_compare(name, s->rk.dname) == 0) { 772238106Sdes return s; 773238106Sdes } 774238106Sdes } 775238106Sdes return NULL; 776238106Sdes} 777238106Sdes 778238106Sdesstruct ub_packed_rrset_key* reply_find_rrset(struct reply_info* rep, 779238106Sdes uint8_t* name, size_t namelen, uint16_t type, uint16_t dclass) 780238106Sdes{ 781238106Sdes size_t i; 782238106Sdes for(i=0; i<rep->rrset_count; i++) { 783238106Sdes struct ub_packed_rrset_key* s = rep->rrsets[i]; 784238106Sdes if(ntohs(s->rk.type) == type && 785238106Sdes ntohs(s->rk.rrset_class) == dclass && 786238106Sdes namelen == s->rk.dname_len && 787238106Sdes query_dname_compare(name, s->rk.dname) == 0) { 788238106Sdes return s; 789238106Sdes } 790238106Sdes } 791238106Sdes return NULL; 792238106Sdes} 793238106Sdes 794238106Sdesvoid 795238106Sdeslog_dns_msg(const char* str, struct query_info* qinfo, struct reply_info* rep) 796238106Sdes{ 797238106Sdes /* not particularly fast but flexible, make wireformat and print */ 798269257Sdes sldns_buffer* buf = sldns_buffer_new(65535); 799238106Sdes struct regional* region = regional_create(); 800238106Sdes if(!reply_info_encode(qinfo, rep, 0, rep->flags, buf, 0, 801238106Sdes region, 65535, 1)) { 802238106Sdes log_info("%s: log_dns_msg: out of memory", str); 803238106Sdes } else { 804285206Sdes char* s = sldns_wire2str_pkt(sldns_buffer_begin(buf), 805269257Sdes sldns_buffer_limit(buf)); 806285206Sdes if(!s) { 807269257Sdes log_info("%s: log_dns_msg: ldns tostr failed", str); 808238106Sdes } else { 809285206Sdes log_info("%s %s", str, s); 810238106Sdes } 811285206Sdes free(s); 812238106Sdes } 813269257Sdes sldns_buffer_free(buf); 814238106Sdes regional_destroy(region); 815238106Sdes} 816238106Sdes 817238106Sdesvoid 818238106Sdeslog_query_info(enum verbosity_value v, const char* str, 819238106Sdes struct query_info* qinf) 820238106Sdes{ 821238106Sdes log_nametypeclass(v, str, qinf->qname, qinf->qtype, qinf->qclass); 822238106Sdes} 823238106Sdes 824238106Sdesint 825291767Sdesreply_check_cname_chain(struct query_info* qinfo, struct reply_info* rep) 826238106Sdes{ 827238106Sdes /* check only answer section rrs for matching cname chain. 828238106Sdes * the cache may return changed rdata, but owner names are untouched.*/ 829238106Sdes size_t i; 830291767Sdes uint8_t* sname = qinfo->qname; 831291767Sdes size_t snamelen = qinfo->qname_len; 832238106Sdes for(i=0; i<rep->an_numrrsets; i++) { 833238106Sdes uint16_t t = ntohs(rep->rrsets[i]->rk.type); 834238106Sdes if(t == LDNS_RR_TYPE_DNAME) 835238106Sdes continue; /* skip dnames; note TTL 0 not cached */ 836238106Sdes /* verify that owner matches current sname */ 837238106Sdes if(query_dname_compare(sname, rep->rrsets[i]->rk.dname) != 0){ 838238106Sdes /* cname chain broken */ 839238106Sdes return 0; 840238106Sdes } 841238106Sdes /* if this is a cname; move on */ 842238106Sdes if(t == LDNS_RR_TYPE_CNAME) { 843238106Sdes get_cname_target(rep->rrsets[i], &sname, &snamelen); 844238106Sdes } 845238106Sdes } 846238106Sdes return 1; 847238106Sdes} 848238106Sdes 849238106Sdesint 850238106Sdesreply_all_rrsets_secure(struct reply_info* rep) 851238106Sdes{ 852238106Sdes size_t i; 853238106Sdes for(i=0; i<rep->rrset_count; i++) { 854238106Sdes if( ((struct packed_rrset_data*)rep->rrsets[i]->entry.data) 855238106Sdes ->security != sec_status_secure ) 856238106Sdes return 0; 857238106Sdes } 858238106Sdes return 1; 859238106Sdes} 860