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" 53269257Sdes#include "ldns/sbuffer.h" 54269257Sdes#include "ldns/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; 60238106Sdes 61238106Sdes/** allocate qinfo, return 0 on error */ 62238106Sdesstatic int 63269257Sdesparse_create_qinfo(sldns_buffer* pkt, struct msg_parse* msg, 64238106Sdes struct query_info* qinf, struct regional* region) 65238106Sdes{ 66238106Sdes if(msg->qname) { 67238106Sdes if(region) 68238106Sdes qinf->qname = (uint8_t*)regional_alloc(region, 69238106Sdes msg->qname_len); 70238106Sdes else qinf->qname = (uint8_t*)malloc(msg->qname_len); 71238106Sdes if(!qinf->qname) return 0; 72238106Sdes dname_pkt_copy(pkt, qinf->qname, msg->qname); 73238106Sdes } else qinf->qname = 0; 74238106Sdes qinf->qname_len = msg->qname_len; 75238106Sdes qinf->qtype = msg->qtype; 76238106Sdes qinf->qclass = msg->qclass; 77238106Sdes return 1; 78238106Sdes} 79238106Sdes 80238106Sdes/** constructor for replyinfo */ 81238106Sdesstatic struct reply_info* 82238106Sdesconstruct_reply_info_base(struct regional* region, uint16_t flags, size_t qd, 83269257Sdes time_t ttl, time_t prettl, size_t an, size_t ns, size_t ar, 84238106Sdes size_t total, enum sec_status sec) 85238106Sdes{ 86238106Sdes struct reply_info* rep; 87238106Sdes /* rrset_count-1 because the first ref is part of the struct. */ 88238106Sdes size_t s = sizeof(struct reply_info) - sizeof(struct rrset_ref) + 89238106Sdes sizeof(struct ub_packed_rrset_key*) * total; 90238106Sdes if(region) 91238106Sdes rep = (struct reply_info*)regional_alloc(region, s); 92238106Sdes else rep = (struct reply_info*)malloc(s + 93238106Sdes sizeof(struct rrset_ref) * (total)); 94238106Sdes if(!rep) 95238106Sdes return NULL; 96238106Sdes rep->flags = flags; 97238106Sdes rep->qdcount = qd; 98238106Sdes rep->ttl = ttl; 99238106Sdes rep->prefetch_ttl = prettl; 100238106Sdes rep->an_numrrsets = an; 101238106Sdes rep->ns_numrrsets = ns; 102238106Sdes rep->ar_numrrsets = ar; 103238106Sdes rep->rrset_count = total; 104238106Sdes rep->security = sec; 105238106Sdes rep->authoritative = 0; 106238106Sdes /* array starts after the refs */ 107238106Sdes if(region) 108238106Sdes rep->rrsets = (struct ub_packed_rrset_key**)&(rep->ref[0]); 109238106Sdes else rep->rrsets = (struct ub_packed_rrset_key**)&(rep->ref[total]); 110238106Sdes /* zero the arrays to assist cleanup in case of malloc failure */ 111238106Sdes memset( rep->rrsets, 0, sizeof(struct ub_packed_rrset_key*) * total); 112238106Sdes if(!region) 113238106Sdes memset( &rep->ref[0], 0, sizeof(struct rrset_ref) * total); 114238106Sdes return rep; 115238106Sdes} 116238106Sdes 117238106Sdes/** allocate replyinfo, return 0 on error */ 118238106Sdesstatic int 119238106Sdesparse_create_repinfo(struct msg_parse* msg, struct reply_info** rep, 120238106Sdes struct regional* region) 121238106Sdes{ 122238106Sdes *rep = construct_reply_info_base(region, msg->flags, msg->qdcount, 0, 123238106Sdes 0, msg->an_rrsets, msg->ns_rrsets, msg->ar_rrsets, 124238106Sdes msg->rrset_count, sec_status_unchecked); 125238106Sdes if(!*rep) 126238106Sdes return 0; 127238106Sdes return 1; 128238106Sdes} 129238106Sdes 130238106Sdes/** allocate (special) rrset keys, return 0 on error */ 131238106Sdesstatic int 132238106Sdesrepinfo_alloc_rrset_keys(struct reply_info* rep, struct alloc_cache* alloc, 133238106Sdes struct regional* region) 134238106Sdes{ 135238106Sdes size_t i; 136238106Sdes for(i=0; i<rep->rrset_count; i++) { 137238106Sdes if(region) { 138238106Sdes rep->rrsets[i] = (struct ub_packed_rrset_key*) 139238106Sdes regional_alloc(region, 140238106Sdes sizeof(struct ub_packed_rrset_key)); 141238106Sdes if(rep->rrsets[i]) { 142238106Sdes memset(rep->rrsets[i], 0, 143238106Sdes sizeof(struct ub_packed_rrset_key)); 144238106Sdes rep->rrsets[i]->entry.key = rep->rrsets[i]; 145238106Sdes } 146238106Sdes } 147238106Sdes else rep->rrsets[i] = alloc_special_obtain(alloc); 148238106Sdes if(!rep->rrsets[i]) 149238106Sdes return 0; 150238106Sdes rep->rrsets[i]->entry.data = NULL; 151238106Sdes } 152238106Sdes return 1; 153238106Sdes} 154238106Sdes 155238106Sdes/** do the rdata copy */ 156238106Sdesstatic int 157269257Sdesrdata_copy(sldns_buffer* pkt, struct packed_rrset_data* data, uint8_t* to, 158269257Sdes struct rr_parse* rr, time_t* rr_ttl, uint16_t type) 159238106Sdes{ 160238106Sdes uint16_t pkt_len; 161269257Sdes const sldns_rr_descriptor* desc; 162238106Sdes 163269257Sdes *rr_ttl = sldns_read_uint32(rr->ttl_data); 164238106Sdes /* RFC 2181 Section 8. if msb of ttl is set treat as if zero. */ 165238106Sdes if(*rr_ttl & 0x80000000U) 166238106Sdes *rr_ttl = 0; 167238106Sdes if(*rr_ttl < MIN_TTL) 168238106Sdes *rr_ttl = MIN_TTL; 169238106Sdes if(*rr_ttl < data->ttl) 170238106Sdes data->ttl = *rr_ttl; 171238106Sdes 172238106Sdes if(rr->outside_packet) { 173238106Sdes /* uncompressed already, only needs copy */ 174238106Sdes memmove(to, rr->ttl_data+sizeof(uint32_t), rr->size); 175238106Sdes return 1; 176238106Sdes } 177238106Sdes 178269257Sdes sldns_buffer_set_position(pkt, (size_t) 179269257Sdes (rr->ttl_data - sldns_buffer_begin(pkt) + sizeof(uint32_t))); 180238106Sdes /* insert decompressed size into rdata len stored in memory */ 181238106Sdes /* -2 because rdatalen bytes are not included. */ 182238106Sdes pkt_len = htons(rr->size - 2); 183238106Sdes memmove(to, &pkt_len, sizeof(uint16_t)); 184238106Sdes to += 2; 185238106Sdes /* read packet rdata len */ 186269257Sdes pkt_len = sldns_buffer_read_u16(pkt); 187269257Sdes if(sldns_buffer_remaining(pkt) < pkt_len) 188238106Sdes return 0; 189269257Sdes desc = sldns_rr_descript(type); 190238106Sdes if(pkt_len > 0 && desc && desc->_dname_count > 0) { 191238106Sdes int count = (int)desc->_dname_count; 192238106Sdes int rdf = 0; 193238106Sdes size_t len; 194238106Sdes size_t oldpos; 195238106Sdes /* decompress dnames. */ 196238106Sdes while(pkt_len > 0 && count) { 197238106Sdes switch(desc->_wireformat[rdf]) { 198238106Sdes case LDNS_RDF_TYPE_DNAME: 199269257Sdes oldpos = sldns_buffer_position(pkt); 200238106Sdes dname_pkt_copy(pkt, to, 201269257Sdes sldns_buffer_current(pkt)); 202238106Sdes to += pkt_dname_len(pkt); 203269257Sdes pkt_len -= sldns_buffer_position(pkt)-oldpos; 204238106Sdes count--; 205238106Sdes len = 0; 206238106Sdes break; 207238106Sdes case LDNS_RDF_TYPE_STR: 208269257Sdes len = sldns_buffer_current(pkt)[0] + 1; 209238106Sdes break; 210238106Sdes default: 211238106Sdes len = get_rdf_size(desc->_wireformat[rdf]); 212238106Sdes break; 213238106Sdes } 214238106Sdes if(len) { 215269257Sdes memmove(to, sldns_buffer_current(pkt), len); 216238106Sdes to += len; 217269257Sdes sldns_buffer_skip(pkt, (ssize_t)len); 218238106Sdes log_assert(len <= pkt_len); 219238106Sdes pkt_len -= len; 220238106Sdes } 221238106Sdes rdf++; 222238106Sdes } 223238106Sdes } 224238106Sdes /* copy remaining rdata */ 225238106Sdes if(pkt_len > 0) 226269257Sdes memmove(to, sldns_buffer_current(pkt), pkt_len); 227238106Sdes 228238106Sdes return 1; 229238106Sdes} 230238106Sdes 231238106Sdes/** copy over the data into packed rrset */ 232238106Sdesstatic int 233269257Sdesparse_rr_copy(sldns_buffer* pkt, struct rrset_parse* pset, 234238106Sdes struct packed_rrset_data* data) 235238106Sdes{ 236238106Sdes size_t i; 237238106Sdes struct rr_parse* rr = pset->rr_first; 238238106Sdes uint8_t* nextrdata; 239238106Sdes size_t total = pset->rr_count + pset->rrsig_count; 240238106Sdes data->ttl = MAX_TTL; 241238106Sdes data->count = pset->rr_count; 242238106Sdes data->rrsig_count = pset->rrsig_count; 243238106Sdes data->trust = rrset_trust_none; 244238106Sdes data->security = sec_status_unchecked; 245238106Sdes /* layout: struct - rr_len - rr_data - rr_ttl - rdata - rrsig */ 246238106Sdes data->rr_len = (size_t*)((uint8_t*)data + 247238106Sdes sizeof(struct packed_rrset_data)); 248238106Sdes data->rr_data = (uint8_t**)&(data->rr_len[total]); 249269257Sdes data->rr_ttl = (time_t*)&(data->rr_data[total]); 250238106Sdes nextrdata = (uint8_t*)&(data->rr_ttl[total]); 251238106Sdes for(i=0; i<data->count; i++) { 252238106Sdes data->rr_len[i] = rr->size; 253238106Sdes data->rr_data[i] = nextrdata; 254238106Sdes nextrdata += rr->size; 255238106Sdes if(!rdata_copy(pkt, data, data->rr_data[i], rr, 256238106Sdes &data->rr_ttl[i], pset->type)) 257238106Sdes return 0; 258238106Sdes rr = rr->next; 259238106Sdes } 260238106Sdes /* if rrsig, its rdata is at nextrdata */ 261238106Sdes rr = pset->rrsig_first; 262238106Sdes for(i=data->count; i<total; i++) { 263238106Sdes data->rr_len[i] = rr->size; 264238106Sdes data->rr_data[i] = nextrdata; 265238106Sdes nextrdata += rr->size; 266238106Sdes if(!rdata_copy(pkt, data, data->rr_data[i], rr, 267238106Sdes &data->rr_ttl[i], LDNS_RR_TYPE_RRSIG)) 268238106Sdes return 0; 269238106Sdes rr = rr->next; 270238106Sdes } 271238106Sdes return 1; 272238106Sdes} 273238106Sdes 274238106Sdes/** create rrset return 0 on failure */ 275238106Sdesstatic int 276269257Sdesparse_create_rrset(sldns_buffer* pkt, struct rrset_parse* pset, 277238106Sdes struct packed_rrset_data** data, struct regional* region) 278238106Sdes{ 279238106Sdes /* allocate */ 280238106Sdes size_t s = sizeof(struct packed_rrset_data) + 281238106Sdes (pset->rr_count + pset->rrsig_count) * 282269257Sdes (sizeof(size_t)+sizeof(uint8_t*)+sizeof(time_t)) + 283238106Sdes pset->size; 284238106Sdes if(region) 285238106Sdes *data = regional_alloc(region, s); 286238106Sdes else *data = malloc(s); 287238106Sdes if(!*data) 288238106Sdes return 0; 289238106Sdes /* copy & decompress */ 290238106Sdes if(!parse_rr_copy(pkt, pset, *data)) { 291238106Sdes if(!region) free(*data); 292238106Sdes return 0; 293238106Sdes } 294238106Sdes return 1; 295238106Sdes} 296238106Sdes 297238106Sdes/** get trust value for rrset */ 298238106Sdesstatic enum rrset_trust 299238106Sdesget_rrset_trust(struct msg_parse* msg, struct rrset_parse* rrset) 300238106Sdes{ 301238106Sdes uint16_t AA = msg->flags & BIT_AA; 302238106Sdes if(rrset->section == LDNS_SECTION_ANSWER) { 303238106Sdes if(AA) { 304238106Sdes /* RFC2181 says remainder of CNAME chain is nonauth*/ 305238106Sdes if(msg->rrset_first && 306238106Sdes msg->rrset_first->section==LDNS_SECTION_ANSWER 307238106Sdes && msg->rrset_first->type==LDNS_RR_TYPE_CNAME){ 308238106Sdes if(rrset == msg->rrset_first) 309238106Sdes return rrset_trust_ans_AA; 310238106Sdes else return rrset_trust_ans_noAA; 311238106Sdes } 312238106Sdes if(msg->rrset_first && 313238106Sdes msg->rrset_first->section==LDNS_SECTION_ANSWER 314238106Sdes && msg->rrset_first->type==LDNS_RR_TYPE_DNAME){ 315238106Sdes if(rrset == msg->rrset_first || 316238106Sdes rrset == msg->rrset_first->rrset_all_next) 317238106Sdes return rrset_trust_ans_AA; 318238106Sdes else return rrset_trust_ans_noAA; 319238106Sdes } 320238106Sdes return rrset_trust_ans_AA; 321238106Sdes } 322238106Sdes else return rrset_trust_ans_noAA; 323238106Sdes } else if(rrset->section == LDNS_SECTION_AUTHORITY) { 324238106Sdes if(AA) return rrset_trust_auth_AA; 325238106Sdes else return rrset_trust_auth_noAA; 326238106Sdes } else { 327238106Sdes /* addit section */ 328238106Sdes if(AA) return rrset_trust_add_AA; 329238106Sdes else return rrset_trust_add_noAA; 330238106Sdes } 331238106Sdes /* NOTREACHED */ 332238106Sdes return rrset_trust_none; 333238106Sdes} 334238106Sdes 335238106Sdesint 336269257Sdesparse_copy_decompress_rrset(sldns_buffer* pkt, struct msg_parse* msg, 337238106Sdes struct rrset_parse *pset, struct regional* region, 338238106Sdes struct ub_packed_rrset_key* pk) 339238106Sdes{ 340238106Sdes struct packed_rrset_data* data; 341238106Sdes pk->rk.flags = pset->flags; 342238106Sdes pk->rk.dname_len = pset->dname_len; 343238106Sdes if(region) 344238106Sdes pk->rk.dname = (uint8_t*)regional_alloc( 345238106Sdes region, pset->dname_len); 346238106Sdes else pk->rk.dname = 347238106Sdes (uint8_t*)malloc(pset->dname_len); 348238106Sdes if(!pk->rk.dname) 349238106Sdes return 0; 350238106Sdes /** copy & decompress dname */ 351238106Sdes dname_pkt_copy(pkt, pk->rk.dname, pset->dname); 352238106Sdes /** copy over type and class */ 353238106Sdes pk->rk.type = htons(pset->type); 354238106Sdes pk->rk.rrset_class = pset->rrset_class; 355238106Sdes /** read data part. */ 356238106Sdes if(!parse_create_rrset(pkt, pset, &data, region)) 357238106Sdes return 0; 358238106Sdes pk->entry.data = (void*)data; 359238106Sdes pk->entry.key = (void*)pk; 360238106Sdes pk->entry.hash = pset->hash; 361238106Sdes data->trust = get_rrset_trust(msg, pset); 362238106Sdes return 1; 363238106Sdes} 364238106Sdes 365238106Sdes/** 366238106Sdes * Copy and decompress rrs 367238106Sdes * @param pkt: the packet for compression pointer resolution. 368238106Sdes * @param msg: the parsed message 369238106Sdes * @param rep: reply info to put rrs into. 370238106Sdes * @param region: if not NULL, used for allocation. 371238106Sdes * @return 0 on failure. 372238106Sdes */ 373238106Sdesstatic int 374269257Sdesparse_copy_decompress(sldns_buffer* pkt, struct msg_parse* msg, 375238106Sdes struct reply_info* rep, struct regional* region) 376238106Sdes{ 377238106Sdes size_t i; 378238106Sdes struct rrset_parse *pset = msg->rrset_first; 379238106Sdes struct packed_rrset_data* data; 380238106Sdes log_assert(rep); 381238106Sdes rep->ttl = MAX_TTL; 382238106Sdes rep->security = sec_status_unchecked; 383238106Sdes if(rep->rrset_count == 0) 384238106Sdes rep->ttl = NORR_TTL; 385238106Sdes 386238106Sdes for(i=0; i<rep->rrset_count; i++) { 387238106Sdes if(!parse_copy_decompress_rrset(pkt, msg, pset, region, 388238106Sdes rep->rrsets[i])) 389238106Sdes return 0; 390238106Sdes data = (struct packed_rrset_data*)rep->rrsets[i]->entry.data; 391238106Sdes if(data->ttl < rep->ttl) 392238106Sdes rep->ttl = data->ttl; 393238106Sdes 394238106Sdes pset = pset->rrset_all_next; 395238106Sdes } 396238106Sdes rep->prefetch_ttl = PREFETCH_TTL_CALC(rep->ttl); 397238106Sdes return 1; 398238106Sdes} 399238106Sdes 400238106Sdesint 401269257Sdesparse_create_msg(sldns_buffer* pkt, struct msg_parse* msg, 402238106Sdes struct alloc_cache* alloc, struct query_info* qinf, 403238106Sdes struct reply_info** rep, struct regional* region) 404238106Sdes{ 405238106Sdes log_assert(pkt && msg); 406238106Sdes if(!parse_create_qinfo(pkt, msg, qinf, region)) 407238106Sdes return 0; 408238106Sdes if(!parse_create_repinfo(msg, rep, region)) 409238106Sdes return 0; 410238106Sdes if(!repinfo_alloc_rrset_keys(*rep, alloc, region)) 411238106Sdes return 0; 412238106Sdes if(!parse_copy_decompress(pkt, msg, *rep, region)) 413238106Sdes return 0; 414238106Sdes return 1; 415238106Sdes} 416238106Sdes 417269257Sdesint reply_info_parse(sldns_buffer* pkt, struct alloc_cache* alloc, 418238106Sdes struct query_info* qinf, struct reply_info** rep, 419238106Sdes struct regional* region, struct edns_data* edns) 420238106Sdes{ 421238106Sdes /* use scratch pad region-allocator during parsing. */ 422238106Sdes struct msg_parse* msg; 423238106Sdes int ret; 424238106Sdes 425238106Sdes qinf->qname = NULL; 426238106Sdes *rep = NULL; 427238106Sdes if(!(msg = regional_alloc(region, sizeof(*msg)))) { 428238106Sdes return LDNS_RCODE_SERVFAIL; 429238106Sdes } 430238106Sdes memset(msg, 0, sizeof(*msg)); 431238106Sdes 432269257Sdes sldns_buffer_set_position(pkt, 0); 433238106Sdes if((ret = parse_packet(pkt, msg, region)) != 0) { 434238106Sdes return ret; 435238106Sdes } 436238106Sdes if((ret = parse_extract_edns(msg, edns)) != 0) 437238106Sdes return ret; 438238106Sdes 439238106Sdes /* parse OK, allocate return structures */ 440238106Sdes /* this also performs dname decompression */ 441238106Sdes if(!parse_create_msg(pkt, msg, alloc, qinf, rep, NULL)) { 442238106Sdes query_info_clear(qinf); 443238106Sdes reply_info_parsedelete(*rep, alloc); 444238106Sdes *rep = NULL; 445238106Sdes return LDNS_RCODE_SERVFAIL; 446238106Sdes } 447238106Sdes return 0; 448238106Sdes} 449238106Sdes 450238106Sdes/** helper compare function to sort in lock order */ 451238106Sdesstatic int 452238106Sdesreply_info_sortref_cmp(const void* a, const void* b) 453238106Sdes{ 454238106Sdes struct rrset_ref* x = (struct rrset_ref*)a; 455238106Sdes struct rrset_ref* y = (struct rrset_ref*)b; 456238106Sdes if(x->key < y->key) return -1; 457238106Sdes if(x->key > y->key) return 1; 458238106Sdes return 0; 459238106Sdes} 460238106Sdes 461238106Sdesvoid 462238106Sdesreply_info_sortref(struct reply_info* rep) 463238106Sdes{ 464238106Sdes qsort(&rep->ref[0], rep->rrset_count, sizeof(struct rrset_ref), 465238106Sdes reply_info_sortref_cmp); 466238106Sdes} 467238106Sdes 468238106Sdesvoid 469269257Sdesreply_info_set_ttls(struct reply_info* rep, time_t timenow) 470238106Sdes{ 471238106Sdes size_t i, j; 472238106Sdes rep->ttl += timenow; 473238106Sdes rep->prefetch_ttl += timenow; 474238106Sdes for(i=0; i<rep->rrset_count; i++) { 475238106Sdes struct packed_rrset_data* data = (struct packed_rrset_data*) 476238106Sdes rep->ref[i].key->entry.data; 477238106Sdes if(i>0 && rep->ref[i].key == rep->ref[i-1].key) 478238106Sdes continue; 479238106Sdes data->ttl += timenow; 480238106Sdes for(j=0; j<data->count + data->rrsig_count; j++) { 481238106Sdes data->rr_ttl[j] += timenow; 482238106Sdes } 483238106Sdes } 484238106Sdes} 485238106Sdes 486238106Sdesvoid 487238106Sdesreply_info_parsedelete(struct reply_info* rep, struct alloc_cache* alloc) 488238106Sdes{ 489238106Sdes size_t i; 490238106Sdes if(!rep) 491238106Sdes return; 492238106Sdes /* no need to lock, since not shared in hashtables. */ 493238106Sdes for(i=0; i<rep->rrset_count; i++) { 494238106Sdes ub_packed_rrset_parsedelete(rep->rrsets[i], alloc); 495238106Sdes } 496238106Sdes free(rep); 497238106Sdes} 498238106Sdes 499238106Sdesint 500269257Sdesquery_info_parse(struct query_info* m, sldns_buffer* query) 501238106Sdes{ 502269257Sdes uint8_t* q = sldns_buffer_begin(query); 503238106Sdes /* minimum size: header + \0 + qtype + qclass */ 504269257Sdes if(sldns_buffer_limit(query) < LDNS_HEADER_SIZE + 5) 505238106Sdes return 0; 506238106Sdes if(LDNS_OPCODE_WIRE(q) != LDNS_PACKET_QUERY || 507269257Sdes LDNS_QDCOUNT(q) != 1 || sldns_buffer_position(query) != 0) 508238106Sdes return 0; 509269257Sdes sldns_buffer_skip(query, LDNS_HEADER_SIZE); 510269257Sdes m->qname = sldns_buffer_current(query); 511238106Sdes if((m->qname_len = query_dname_len(query)) == 0) 512238106Sdes return 0; /* parse error */ 513269257Sdes if(sldns_buffer_remaining(query) < 4) 514238106Sdes return 0; /* need qtype, qclass */ 515269257Sdes m->qtype = sldns_buffer_read_u16(query); 516269257Sdes m->qclass = sldns_buffer_read_u16(query); 517238106Sdes return 1; 518238106Sdes} 519238106Sdes 520238106Sdes/** tiny subroutine for msgreply_compare */ 521238106Sdes#define COMPARE_IT(x, y) \ 522238106Sdes if( (x) < (y) ) return -1; \ 523238106Sdes else if( (x) > (y) ) return +1; \ 524238106Sdes log_assert( (x) == (y) ); 525238106Sdes 526238106Sdesint 527238106Sdesquery_info_compare(void* m1, void* m2) 528238106Sdes{ 529238106Sdes struct query_info* msg1 = (struct query_info*)m1; 530238106Sdes struct query_info* msg2 = (struct query_info*)m2; 531238106Sdes int mc; 532238106Sdes /* from most different to least different for speed */ 533238106Sdes COMPARE_IT(msg1->qtype, msg2->qtype); 534238106Sdes if((mc = query_dname_compare(msg1->qname, msg2->qname)) != 0) 535238106Sdes return mc; 536238106Sdes log_assert(msg1->qname_len == msg2->qname_len); 537238106Sdes COMPARE_IT(msg1->qclass, msg2->qclass); 538238106Sdes return 0; 539238106Sdes#undef COMPARE_IT 540238106Sdes} 541238106Sdes 542238106Sdesvoid 543238106Sdesquery_info_clear(struct query_info* m) 544238106Sdes{ 545238106Sdes free(m->qname); 546238106Sdes m->qname = NULL; 547238106Sdes} 548238106Sdes 549238106Sdessize_t 550238106Sdesmsgreply_sizefunc(void* k, void* d) 551238106Sdes{ 552238106Sdes struct msgreply_entry* q = (struct msgreply_entry*)k; 553238106Sdes struct reply_info* r = (struct reply_info*)d; 554238106Sdes size_t s = sizeof(struct msgreply_entry) + sizeof(struct reply_info) 555238106Sdes + q->key.qname_len + lock_get_mem(&q->entry.lock) 556238106Sdes - sizeof(struct rrset_ref); 557238106Sdes s += r->rrset_count * sizeof(struct rrset_ref); 558238106Sdes s += r->rrset_count * sizeof(struct ub_packed_rrset_key*); 559238106Sdes return s; 560238106Sdes} 561238106Sdes 562238106Sdesvoid 563238106Sdesquery_entry_delete(void *k, void* ATTR_UNUSED(arg)) 564238106Sdes{ 565238106Sdes struct msgreply_entry* q = (struct msgreply_entry*)k; 566238106Sdes lock_rw_destroy(&q->entry.lock); 567238106Sdes query_info_clear(&q->key); 568238106Sdes free(q); 569238106Sdes} 570238106Sdes 571238106Sdesvoid 572238106Sdesreply_info_delete(void* d, void* ATTR_UNUSED(arg)) 573238106Sdes{ 574238106Sdes struct reply_info* r = (struct reply_info*)d; 575238106Sdes free(r); 576238106Sdes} 577238106Sdes 578238106Sdeshashvalue_t 579238106Sdesquery_info_hash(struct query_info *q) 580238106Sdes{ 581238106Sdes hashvalue_t h = 0xab; 582238106Sdes h = hashlittle(&q->qtype, sizeof(q->qtype), h); 583238106Sdes h = hashlittle(&q->qclass, sizeof(q->qclass), h); 584238106Sdes h = dname_query_hash(q->qname, h); 585238106Sdes return h; 586238106Sdes} 587238106Sdes 588238106Sdesstruct msgreply_entry* 589238106Sdesquery_info_entrysetup(struct query_info* q, struct reply_info* r, 590238106Sdes hashvalue_t h) 591238106Sdes{ 592238106Sdes struct msgreply_entry* e = (struct msgreply_entry*)malloc( 593238106Sdes sizeof(struct msgreply_entry)); 594238106Sdes if(!e) return NULL; 595238106Sdes memcpy(&e->key, q, sizeof(*q)); 596238106Sdes e->entry.hash = h; 597238106Sdes e->entry.key = e; 598238106Sdes e->entry.data = r; 599238106Sdes lock_rw_init(&e->entry.lock); 600238106Sdes lock_protect(&e->entry.lock, &e->key, sizeof(e->key)); 601238106Sdes lock_protect(&e->entry.lock, &e->entry.hash, sizeof(e->entry.hash) + 602238106Sdes sizeof(e->entry.key) + sizeof(e->entry.data)); 603238106Sdes lock_protect(&e->entry.lock, e->key.qname, e->key.qname_len); 604238106Sdes q->qname = NULL; 605238106Sdes return e; 606238106Sdes} 607238106Sdes 608238106Sdes/** copy rrsets from replyinfo to dest replyinfo */ 609238106Sdesstatic int 610238106Sdesrepinfo_copy_rrsets(struct reply_info* dest, struct reply_info* from, 611238106Sdes struct regional* region) 612238106Sdes{ 613238106Sdes size_t i, s; 614238106Sdes struct packed_rrset_data* fd, *dd; 615238106Sdes struct ub_packed_rrset_key* fk, *dk; 616238106Sdes for(i=0; i<dest->rrset_count; i++) { 617238106Sdes fk = from->rrsets[i]; 618238106Sdes dk = dest->rrsets[i]; 619238106Sdes fd = (struct packed_rrset_data*)fk->entry.data; 620238106Sdes dk->entry.hash = fk->entry.hash; 621238106Sdes dk->rk = fk->rk; 622238106Sdes if(region) { 623238106Sdes dk->id = fk->id; 624238106Sdes dk->rk.dname = (uint8_t*)regional_alloc_init(region, 625238106Sdes fk->rk.dname, fk->rk.dname_len); 626238106Sdes } else 627238106Sdes dk->rk.dname = (uint8_t*)memdup(fk->rk.dname, 628238106Sdes fk->rk.dname_len); 629238106Sdes if(!dk->rk.dname) 630238106Sdes return 0; 631238106Sdes s = packed_rrset_sizeof(fd); 632238106Sdes if(region) 633238106Sdes dd = (struct packed_rrset_data*)regional_alloc_init( 634238106Sdes region, fd, s); 635238106Sdes else dd = (struct packed_rrset_data*)memdup(fd, s); 636238106Sdes if(!dd) 637238106Sdes return 0; 638238106Sdes packed_rrset_ptr_fixup(dd); 639238106Sdes dk->entry.data = (void*)dd; 640238106Sdes } 641238106Sdes return 1; 642238106Sdes} 643238106Sdes 644238106Sdesstruct reply_info* 645238106Sdesreply_info_copy(struct reply_info* rep, struct alloc_cache* alloc, 646238106Sdes struct regional* region) 647238106Sdes{ 648238106Sdes struct reply_info* cp; 649238106Sdes cp = construct_reply_info_base(region, rep->flags, rep->qdcount, 650238106Sdes rep->ttl, rep->prefetch_ttl, rep->an_numrrsets, 651238106Sdes rep->ns_numrrsets, rep->ar_numrrsets, rep->rrset_count, 652238106Sdes rep->security); 653238106Sdes if(!cp) 654238106Sdes return NULL; 655238106Sdes /* allocate ub_key structures special or not */ 656238106Sdes if(!repinfo_alloc_rrset_keys(cp, alloc, region)) { 657238106Sdes if(!region) 658238106Sdes reply_info_parsedelete(cp, alloc); 659238106Sdes return NULL; 660238106Sdes } 661238106Sdes if(!repinfo_copy_rrsets(cp, rep, region)) { 662238106Sdes if(!region) 663238106Sdes reply_info_parsedelete(cp, alloc); 664238106Sdes return NULL; 665238106Sdes } 666238106Sdes return cp; 667238106Sdes} 668238106Sdes 669238106Sdesuint8_t* 670238106Sdesreply_find_final_cname_target(struct query_info* qinfo, struct reply_info* rep) 671238106Sdes{ 672238106Sdes uint8_t* sname = qinfo->qname; 673238106Sdes size_t snamelen = qinfo->qname_len; 674238106Sdes size_t i; 675238106Sdes for(i=0; i<rep->an_numrrsets; i++) { 676238106Sdes struct ub_packed_rrset_key* s = rep->rrsets[i]; 677238106Sdes /* follow CNAME chain (if any) */ 678238106Sdes if(ntohs(s->rk.type) == LDNS_RR_TYPE_CNAME && 679238106Sdes ntohs(s->rk.rrset_class) == qinfo->qclass && 680238106Sdes snamelen == s->rk.dname_len && 681238106Sdes query_dname_compare(sname, s->rk.dname) == 0) { 682238106Sdes get_cname_target(s, &sname, &snamelen); 683238106Sdes } 684238106Sdes } 685238106Sdes if(sname != qinfo->qname) 686238106Sdes return sname; 687238106Sdes return NULL; 688238106Sdes} 689238106Sdes 690238106Sdesstruct ub_packed_rrset_key* 691238106Sdesreply_find_answer_rrset(struct query_info* qinfo, struct reply_info* rep) 692238106Sdes{ 693238106Sdes uint8_t* sname = qinfo->qname; 694238106Sdes size_t snamelen = qinfo->qname_len; 695238106Sdes size_t i; 696238106Sdes for(i=0; i<rep->an_numrrsets; i++) { 697238106Sdes struct ub_packed_rrset_key* s = rep->rrsets[i]; 698238106Sdes /* first match type, for query of qtype cname */ 699238106Sdes if(ntohs(s->rk.type) == qinfo->qtype && 700238106Sdes ntohs(s->rk.rrset_class) == qinfo->qclass && 701238106Sdes snamelen == s->rk.dname_len && 702238106Sdes query_dname_compare(sname, s->rk.dname) == 0) { 703238106Sdes return s; 704238106Sdes } 705238106Sdes /* follow CNAME chain (if any) */ 706238106Sdes if(ntohs(s->rk.type) == LDNS_RR_TYPE_CNAME && 707238106Sdes ntohs(s->rk.rrset_class) == qinfo->qclass && 708238106Sdes snamelen == s->rk.dname_len && 709238106Sdes query_dname_compare(sname, s->rk.dname) == 0) { 710238106Sdes get_cname_target(s, &sname, &snamelen); 711238106Sdes } 712238106Sdes } 713238106Sdes return NULL; 714238106Sdes} 715238106Sdes 716238106Sdesstruct ub_packed_rrset_key* reply_find_rrset_section_an(struct reply_info* rep, 717238106Sdes uint8_t* name, size_t namelen, uint16_t type, uint16_t dclass) 718238106Sdes{ 719238106Sdes size_t i; 720238106Sdes for(i=0; i<rep->an_numrrsets; i++) { 721238106Sdes struct ub_packed_rrset_key* s = rep->rrsets[i]; 722238106Sdes if(ntohs(s->rk.type) == type && 723238106Sdes ntohs(s->rk.rrset_class) == dclass && 724238106Sdes namelen == s->rk.dname_len && 725238106Sdes query_dname_compare(name, s->rk.dname) == 0) { 726238106Sdes return s; 727238106Sdes } 728238106Sdes } 729238106Sdes return NULL; 730238106Sdes} 731238106Sdes 732238106Sdesstruct ub_packed_rrset_key* reply_find_rrset_section_ns(struct reply_info* rep, 733238106Sdes uint8_t* name, size_t namelen, uint16_t type, uint16_t dclass) 734238106Sdes{ 735238106Sdes size_t i; 736238106Sdes for(i=rep->an_numrrsets; i<rep->an_numrrsets+rep->ns_numrrsets; i++) { 737238106Sdes struct ub_packed_rrset_key* s = rep->rrsets[i]; 738238106Sdes if(ntohs(s->rk.type) == type && 739238106Sdes ntohs(s->rk.rrset_class) == dclass && 740238106Sdes namelen == s->rk.dname_len && 741238106Sdes query_dname_compare(name, s->rk.dname) == 0) { 742238106Sdes return s; 743238106Sdes } 744238106Sdes } 745238106Sdes return NULL; 746238106Sdes} 747238106Sdes 748238106Sdesstruct ub_packed_rrset_key* reply_find_rrset(struct reply_info* rep, 749238106Sdes uint8_t* name, size_t namelen, uint16_t type, uint16_t dclass) 750238106Sdes{ 751238106Sdes size_t i; 752238106Sdes for(i=0; i<rep->rrset_count; i++) { 753238106Sdes struct ub_packed_rrset_key* s = rep->rrsets[i]; 754238106Sdes if(ntohs(s->rk.type) == type && 755238106Sdes ntohs(s->rk.rrset_class) == dclass && 756238106Sdes namelen == s->rk.dname_len && 757238106Sdes query_dname_compare(name, s->rk.dname) == 0) { 758238106Sdes return s; 759238106Sdes } 760238106Sdes } 761238106Sdes return NULL; 762238106Sdes} 763238106Sdes 764238106Sdesvoid 765238106Sdeslog_dns_msg(const char* str, struct query_info* qinfo, struct reply_info* rep) 766238106Sdes{ 767238106Sdes /* not particularly fast but flexible, make wireformat and print */ 768269257Sdes sldns_buffer* buf = sldns_buffer_new(65535); 769238106Sdes struct regional* region = regional_create(); 770238106Sdes if(!reply_info_encode(qinfo, rep, 0, rep->flags, buf, 0, 771238106Sdes region, 65535, 1)) { 772238106Sdes log_info("%s: log_dns_msg: out of memory", str); 773238106Sdes } else { 774269257Sdes char* str = sldns_wire2str_pkt(sldns_buffer_begin(buf), 775269257Sdes sldns_buffer_limit(buf)); 776269257Sdes if(!str) { 777269257Sdes log_info("%s: log_dns_msg: ldns tostr failed", str); 778238106Sdes } else { 779269257Sdes log_info("%s %s", 780269257Sdes str, (char*)sldns_buffer_begin(buf)); 781238106Sdes } 782269257Sdes free(str); 783238106Sdes } 784269257Sdes sldns_buffer_free(buf); 785238106Sdes regional_destroy(region); 786238106Sdes} 787238106Sdes 788238106Sdesvoid 789238106Sdeslog_query_info(enum verbosity_value v, const char* str, 790238106Sdes struct query_info* qinf) 791238106Sdes{ 792238106Sdes log_nametypeclass(v, str, qinf->qname, qinf->qtype, qinf->qclass); 793238106Sdes} 794238106Sdes 795238106Sdesint 796238106Sdesreply_check_cname_chain(struct reply_info* rep) 797238106Sdes{ 798238106Sdes /* check only answer section rrs for matching cname chain. 799238106Sdes * the cache may return changed rdata, but owner names are untouched.*/ 800238106Sdes size_t i; 801238106Sdes uint8_t* sname = rep->rrsets[0]->rk.dname; 802238106Sdes size_t snamelen = rep->rrsets[0]->rk.dname_len; 803238106Sdes for(i=0; i<rep->an_numrrsets; i++) { 804238106Sdes uint16_t t = ntohs(rep->rrsets[i]->rk.type); 805238106Sdes if(t == LDNS_RR_TYPE_DNAME) 806238106Sdes continue; /* skip dnames; note TTL 0 not cached */ 807238106Sdes /* verify that owner matches current sname */ 808238106Sdes if(query_dname_compare(sname, rep->rrsets[i]->rk.dname) != 0){ 809238106Sdes /* cname chain broken */ 810238106Sdes return 0; 811238106Sdes } 812238106Sdes /* if this is a cname; move on */ 813238106Sdes if(t == LDNS_RR_TYPE_CNAME) { 814238106Sdes get_cname_target(rep->rrsets[i], &sname, &snamelen); 815238106Sdes } 816238106Sdes } 817238106Sdes return 1; 818238106Sdes} 819238106Sdes 820238106Sdesint 821238106Sdesreply_all_rrsets_secure(struct reply_info* rep) 822238106Sdes{ 823238106Sdes size_t i; 824238106Sdes for(i=0; i<rep->rrset_count; i++) { 825238106Sdes if( ((struct packed_rrset_data*)rep->rrsets[i]->entry.data) 826238106Sdes ->security != sec_status_secure ) 827238106Sdes return 0; 828238106Sdes } 829238106Sdes return 1; 830238106Sdes} 831