1178479Sjb/* 2178479Sjb * util/data/msgreply.c - store message and reply data. 3178479Sjb * 4178479Sjb * Copyright (c) 2007, NLnet Labs. All rights reserved. 5178479Sjb * 6178479Sjb * This software is open source. 7178479Sjb * 8178479Sjb * Redistribution and use in source and binary forms, with or without 9178479Sjb * modification, are permitted provided that the following conditions 10178479Sjb * are met: 11178479Sjb * 12178479Sjb * Redistributions of source code must retain the above copyright notice, 13178479Sjb * this list of conditions and the following disclaimer. 14178479Sjb * 15178479Sjb * Redistributions in binary form must reproduce the above copyright notice, 16178479Sjb * this list of conditions and the following disclaimer in the documentation 17178479Sjb * and/or other materials provided with the distribution. 18178479Sjb * 19178479Sjb * Neither the name of the NLNET LABS nor the names of its contributors may 20178479Sjb * be used to endorse or promote products derived from this software without 21178479Sjb * specific prior written permission. 22178479Sjb * 23210767Srpaulo * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24237624Spfg * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25253725Spfg * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 26178479Sjb * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27178479Sjb * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28178552Sjb * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29178479Sjb * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30178552Sjb * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31178552Sjb * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32178552Sjb * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33178552Sjb * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34178479Sjb */ 35178479Sjb 36178552Sjb/** 37178479Sjb * \file 38178552Sjb * 39178479Sjb * This file contains a data structure to store a message and its reply. 40178479Sjb */ 41178479Sjb 42178479Sjb#include "config.h" 43210767Srpaulo#include "util/data/msgreply.h" 44210767Srpaulo#include "util/storage/lookup3.h" 45210767Srpaulo#include "util/log.h" 46210767Srpaulo#include "util/alloc.h" 47210767Srpaulo#include "util/netevent.h" 48178479Sjb#include "util/net_help.h" 49178479Sjb#include "util/data/dname.h" 50178479Sjb#include "util/regional.h" 51178479Sjb#include "util/data/msgparse.h" 52178479Sjb#include "util/data/msgencode.h" 53178479Sjb#include "sldns/sbuffer.h" 54178479Sjb#include "sldns/wire2str.h" 55178479Sjb#include "util/module.h" 56178479Sjb#include "util/fptr_wlist.h" 57178479Sjb 58178479Sjb/** MAX TTL default for messages and rrsets */ 59178479Sjbtime_t MAX_TTL = 3600 * 24 * 10; /* ten days */ 60178479Sjb/** MIN TTL default for messages and rrsets */ 61178479Sjbtime_t MIN_TTL = 0; 62178479Sjb/** MAX Negative TTL, for SOA records in authority section */ 63178479Sjbtime_t MAX_NEG_TTL = 3600; /* one hour */ 64178479Sjb/** If we serve expired entries and prefetch them */ 65178479Sjbint SERVE_EXPIRED = 0; 66178479Sjb/** Time to serve records after expiration */ 67178479Sjbtime_t SERVE_EXPIRED_TTL = 0; 68178479Sjb/** TTL to use for expired records */ 69178479Sjbtime_t SERVE_EXPIRED_REPLY_TTL = 30; 70178479Sjb/** If we serve the original TTL or decrementing TTLs */ 71178479Sjbint SERVE_ORIGINAL_TTL = 0; 72178479Sjb 73178479Sjb/** allocate qinfo, return 0 on error */ 74178479Sjbstatic int 75178479Sjbparse_create_qinfo(sldns_buffer* pkt, struct msg_parse* msg, 76178479Sjb struct query_info* qinf, struct regional* region) 77178479Sjb{ 78178479Sjb if(msg->qname) { 79178479Sjb if(region) 80178479Sjb qinf->qname = (uint8_t*)regional_alloc(region, 81178479Sjb msg->qname_len); 82178479Sjb else qinf->qname = (uint8_t*)malloc(msg->qname_len); 83178479Sjb if(!qinf->qname) return 0; 84178479Sjb dname_pkt_copy(pkt, qinf->qname, msg->qname); 85178479Sjb } else qinf->qname = 0; 86178479Sjb qinf->qname_len = msg->qname_len; 87178479Sjb qinf->qtype = msg->qtype; 88178479Sjb qinf->qclass = msg->qclass; 89178479Sjb qinf->local_alias = NULL; 90178479Sjb return 1; 91178479Sjb} 92178479Sjb 93178479Sjb/** constructor for replyinfo */ 94178479Sjbstruct reply_info* 95178479Sjbconstruct_reply_info_base(struct regional* region, uint16_t flags, size_t qd, 96178479Sjb time_t ttl, time_t prettl, time_t expttl, size_t an, size_t ns, 97178479Sjb size_t ar, size_t total, enum sec_status sec, sldns_ede_code reason_bogus) 98178479Sjb{ 99178479Sjb struct reply_info* rep; 100178479Sjb /* rrset_count-1 because the first ref is part of the struct. */ 101178479Sjb size_t s = sizeof(struct reply_info) - sizeof(struct rrset_ref) + 102178479Sjb sizeof(struct ub_packed_rrset_key*) * total; 103178479Sjb if(total >= RR_COUNT_MAX) return NULL; /* sanity check on numRRS*/ 104178479Sjb if(region) 105178479Sjb rep = (struct reply_info*)regional_alloc(region, s); 106178479Sjb else rep = (struct reply_info*)malloc(s + 107178479Sjb sizeof(struct rrset_ref) * (total)); 108178479Sjb if(!rep) 109178479Sjb return NULL; 110178479Sjb rep->flags = flags; 111178479Sjb rep->qdcount = qd; 112178479Sjb rep->ttl = ttl; 113178479Sjb rep->prefetch_ttl = prettl; 114178479Sjb rep->serve_expired_ttl = expttl; 115178479Sjb rep->an_numrrsets = an; 116178479Sjb rep->ns_numrrsets = ns; 117178479Sjb rep->ar_numrrsets = ar; 118178479Sjb rep->rrset_count = total; 119178479Sjb rep->security = sec; 120178479Sjb rep->reason_bogus = reason_bogus; 121178479Sjb /* this is only allocated and used for caching on copy */ 122178479Sjb rep->reason_bogus_str = NULL; 123178479Sjb rep->authoritative = 0; 124178479Sjb /* array starts after the refs */ 125178479Sjb if(region) 126178479Sjb rep->rrsets = (struct ub_packed_rrset_key**)&(rep->ref[0]); 127178479Sjb else rep->rrsets = (struct ub_packed_rrset_key**)&(rep->ref[total]); 128178479Sjb /* zero the arrays to assist cleanup in case of malloc failure */ 129178479Sjb memset( rep->rrsets, 0, sizeof(struct ub_packed_rrset_key*) * total); 130178479Sjb if(!region) 131178479Sjb memset( &rep->ref[0], 0, sizeof(struct rrset_ref) * total); 132178479Sjb return rep; 133178479Sjb} 134178479Sjb 135178479Sjb/** allocate replyinfo, return 0 on error */ 136178479Sjbstatic int 137178479Sjbparse_create_repinfo(struct msg_parse* msg, struct reply_info** rep, 138178479Sjb struct regional* region) 139178479Sjb{ 140178479Sjb *rep = construct_reply_info_base(region, msg->flags, msg->qdcount, 0, 141178479Sjb 0, 0, msg->an_rrsets, msg->ns_rrsets, msg->ar_rrsets, 142178479Sjb msg->rrset_count, sec_status_unchecked, LDNS_EDE_NONE); 143178479Sjb if(!*rep) 144178479Sjb return 0; 145178479Sjb return 1; 146178479Sjb} 147178479Sjb 148178479Sjbint 149178479Sjbreply_info_alloc_rrset_keys(struct reply_info* rep, struct alloc_cache* alloc, 150178479Sjb struct regional* region) 151178479Sjb{ 152178479Sjb size_t i; 153178479Sjb for(i=0; i<rep->rrset_count; i++) { 154178479Sjb if(region) { 155178479Sjb rep->rrsets[i] = (struct ub_packed_rrset_key*) 156178479Sjb regional_alloc(region, 157178479Sjb sizeof(struct ub_packed_rrset_key)); 158178479Sjb if(rep->rrsets[i]) { 159178479Sjb memset(rep->rrsets[i], 0, 160178479Sjb sizeof(struct ub_packed_rrset_key)); 161178479Sjb rep->rrsets[i]->entry.key = rep->rrsets[i]; 162178479Sjb } 163178479Sjb } 164178479Sjb else rep->rrsets[i] = alloc_special_obtain(alloc); 165253725Spfg if(!rep->rrsets[i]) 166178479Sjb return 0; 167178479Sjb rep->rrsets[i]->entry.data = NULL; 168178479Sjb } 169178479Sjb return 1; 170178479Sjb} 171178479Sjb 172178479Sjbstruct reply_info * 173178479Sjbmake_new_reply_info(const struct reply_info* rep, struct regional* region, 174178479Sjb size_t an_numrrsets, size_t copy_rrsets) 175178479Sjb{ 176178479Sjb struct reply_info* new_rep; 177178479Sjb size_t i; 178178479Sjb 179178479Sjb /* create a base struct. we specify 'insecure' security status as 180178479Sjb * the modified response won't be DNSSEC-valid. In our faked response 181178479Sjb * the authority and additional sections will be empty (except possible 182178479Sjb * EDNS0 OPT RR in the additional section appended on sending it out), 183178479Sjb * so the total number of RRsets is an_numrrsets. */ 184178479Sjb new_rep = construct_reply_info_base(region, rep->flags, 185178479Sjb rep->qdcount, rep->ttl, rep->prefetch_ttl, 186178479Sjb rep->serve_expired_ttl, an_numrrsets, 0, 0, an_numrrsets, 187178479Sjb sec_status_insecure, LDNS_EDE_NONE); 188178479Sjb if(!new_rep) 189178479Sjb return NULL; 190178479Sjb if(!reply_info_alloc_rrset_keys(new_rep, NULL, region)) 191178479Sjb return NULL; 192178479Sjb for(i=0; i<copy_rrsets; i++) 193178479Sjb new_rep->rrsets[i] = rep->rrsets[i]; 194178479Sjb 195178479Sjb return new_rep; 196178479Sjb} 197178479Sjb 198178479Sjb/** find the minimumttl in the rdata of SOA record */ 199178479Sjbstatic time_t 200178479Sjbsoa_find_minttl(struct rr_parse* rr) 201178479Sjb{ 202178479Sjb uint16_t rlen = sldns_read_uint16(rr->ttl_data+4); 203178479Sjb if(rlen < 20) 204178479Sjb return 0; /* rdata too small for SOA (dname, dname, 5*32bit) */ 205178479Sjb /* minimum TTL is the last 32bit value in the rdata of the record */ 206178479Sjb /* at position ttl_data + 4(ttl) + 2(rdatalen) + rdatalen - 4(timeval)*/ 207178479Sjb return (time_t)sldns_read_uint32(rr->ttl_data+6+rlen-4); 208178479Sjb} 209178479Sjb 210178479Sjb/** do the rdata copy */ 211178479Sjbstatic int 212178479Sjbrdata_copy(sldns_buffer* pkt, struct packed_rrset_data* data, uint8_t* to, 213178479Sjb struct rr_parse* rr, time_t* rr_ttl, uint16_t type, 214178479Sjb sldns_pkt_section section) 215178479Sjb{ 216178479Sjb uint16_t pkt_len; 217178479Sjb const sldns_rr_descriptor* desc; 218178479Sjb 219178479Sjb *rr_ttl = sldns_read_uint32(rr->ttl_data); 220178479Sjb /* RFC 2181 Section 8. if msb of ttl is set treat as if zero. */ 221178479Sjb if(*rr_ttl & 0x80000000U) 222178479Sjb *rr_ttl = 0; 223178479Sjb if(type == LDNS_RR_TYPE_SOA && section == LDNS_SECTION_AUTHORITY) { 224178479Sjb /* negative response. see if TTL of SOA record larger than the 225178479Sjb * minimum-ttl in the rdata of the SOA record */ 226178479Sjb if(*rr_ttl > soa_find_minttl(rr)) 227178479Sjb *rr_ttl = soa_find_minttl(rr); 228178479Sjb } 229178479Sjb if(!SERVE_ORIGINAL_TTL && (*rr_ttl < MIN_TTL)) 230178479Sjb *rr_ttl = MIN_TTL; 231178479Sjb if(!SERVE_ORIGINAL_TTL && (*rr_ttl > MAX_TTL)) 232178479Sjb *rr_ttl = MAX_TTL; 233178479Sjb if(type == LDNS_RR_TYPE_SOA && section == LDNS_SECTION_AUTHORITY) { 234178479Sjb /* max neg ttl overrides the min and max ttl of everything 235178479Sjb * else, it is for a more specific record */ 236178479Sjb if(*rr_ttl > MAX_NEG_TTL) 237178479Sjb *rr_ttl = MAX_NEG_TTL; 238178479Sjb } 239178479Sjb if(*rr_ttl < data->ttl) 240178479Sjb data->ttl = *rr_ttl; 241178479Sjb 242178479Sjb if(rr->outside_packet) { 243178479Sjb /* uncompressed already, only needs copy */ 244178479Sjb memmove(to, rr->ttl_data+sizeof(uint32_t), rr->size); 245178479Sjb return 1; 246178479Sjb } 247178479Sjb 248178479Sjb sldns_buffer_set_position(pkt, (size_t) 249178479Sjb (rr->ttl_data - sldns_buffer_begin(pkt) + sizeof(uint32_t))); 250178479Sjb /* insert decompressed size into rdata len stored in memory */ 251178479Sjb /* -2 because rdatalen bytes are not included. */ 252178479Sjb pkt_len = htons(rr->size - 2); 253178479Sjb memmove(to, &pkt_len, sizeof(uint16_t)); 254178479Sjb to += 2; 255178479Sjb /* read packet rdata len */ 256178479Sjb pkt_len = sldns_buffer_read_u16(pkt); 257178479Sjb if(sldns_buffer_remaining(pkt) < pkt_len) 258178479Sjb return 0; 259178479Sjb desc = sldns_rr_descript(type); 260178479Sjb if(pkt_len > 0 && desc && desc->_dname_count > 0) { 261178479Sjb int count = (int)desc->_dname_count; 262178479Sjb int rdf = 0; 263178479Sjb size_t len; 264178479Sjb size_t oldpos; 265178479Sjb /* decompress dnames. */ 266178479Sjb while(pkt_len > 0 && count) { 267178479Sjb switch(desc->_wireformat[rdf]) { 268178479Sjb case LDNS_RDF_TYPE_DNAME: 269178479Sjb oldpos = sldns_buffer_position(pkt); 270178479Sjb dname_pkt_copy(pkt, to, 271178479Sjb sldns_buffer_current(pkt)); 272178479Sjb to += pkt_dname_len(pkt); 273178479Sjb pkt_len -= sldns_buffer_position(pkt)-oldpos; 274178479Sjb count--; 275178479Sjb len = 0; 276178479Sjb break; 277178479Sjb case LDNS_RDF_TYPE_STR: 278178479Sjb len = sldns_buffer_current(pkt)[0] + 1; 279178479Sjb break; 280178479Sjb default: 281178479Sjb len = get_rdf_size(desc->_wireformat[rdf]); 282178479Sjb break; 283178479Sjb } 284178479Sjb if(len) { 285178479Sjb log_assert(len <= pkt_len); 286178479Sjb memmove(to, sldns_buffer_current(pkt), len); 287178479Sjb to += len; 288178479Sjb sldns_buffer_skip(pkt, (ssize_t)len); 289178479Sjb pkt_len -= len; 290178479Sjb } 291178479Sjb rdf++; 292178479Sjb } 293178479Sjb } 294178479Sjb /* copy remaining rdata */ 295178479Sjb if(pkt_len > 0) 296178479Sjb memmove(to, sldns_buffer_current(pkt), pkt_len); 297178479Sjb 298178479Sjb return 1; 299178479Sjb} 300178479Sjb 301178479Sjb/** copy over the data into packed rrset */ 302178479Sjbstatic int 303178479Sjbparse_rr_copy(sldns_buffer* pkt, struct rrset_parse* pset, 304178479Sjb struct packed_rrset_data* data) 305178479Sjb{ 306178479Sjb size_t i; 307178479Sjb struct rr_parse* rr = pset->rr_first; 308178479Sjb uint8_t* nextrdata; 309178479Sjb size_t total = pset->rr_count + pset->rrsig_count; 310178479Sjb data->ttl = MAX_TTL; 311178479Sjb data->count = pset->rr_count; 312178479Sjb data->rrsig_count = pset->rrsig_count; 313183153Simp data->trust = rrset_trust_none; 314178479Sjb data->security = sec_status_unchecked; 315178479Sjb /* layout: struct - rr_len - rr_data - rr_ttl - rdata - rrsig */ 316178479Sjb data->rr_len = (size_t*)((uint8_t*)data + 317178552Sjb sizeof(struct packed_rrset_data)); 318178479Sjb data->rr_data = (uint8_t**)&(data->rr_len[total]); 319178479Sjb data->rr_ttl = (time_t*)&(data->rr_data[total]); 320178479Sjb nextrdata = (uint8_t*)&(data->rr_ttl[total]); 321178479Sjb for(i=0; i<data->count; i++) { 322178479Sjb data->rr_len[i] = rr->size; 323178479Sjb data->rr_data[i] = nextrdata; 324178479Sjb nextrdata += rr->size; 325178479Sjb if(!rdata_copy(pkt, data, data->rr_data[i], rr, 326178479Sjb &data->rr_ttl[i], pset->type, pset->section)) 327178479Sjb return 0; 328178479Sjb rr = rr->next; 329178479Sjb } 330178479Sjb /* if rrsig, its rdata is at nextrdata */ 331178479Sjb rr = pset->rrsig_first; 332178479Sjb for(i=data->count; i<total; i++) { 333178479Sjb data->rr_len[i] = rr->size; 334178479Sjb data->rr_data[i] = nextrdata; 335178479Sjb nextrdata += rr->size; 336178479Sjb if(!rdata_copy(pkt, data, data->rr_data[i], rr, 337178479Sjb &data->rr_ttl[i], LDNS_RR_TYPE_RRSIG, pset->section)) 338178479Sjb return 0; 339178479Sjb rr = rr->next; 340178479Sjb } 341178479Sjb return 1; 342178479Sjb} 343178479Sjb 344178479Sjb/** create rrset return 0 on failure */ 345178479Sjbstatic int 346210767Srpauloparse_create_rrset(sldns_buffer* pkt, struct rrset_parse* pset, 347178479Sjb struct packed_rrset_data** data, struct regional* region) 348178479Sjb{ 349178479Sjb /* allocate */ 350178479Sjb size_t s; 351178479Sjb if(pset->rr_count > RR_COUNT_MAX || pset->rrsig_count > RR_COUNT_MAX || 352178479Sjb pset->size > RR_COUNT_MAX) 353178479Sjb return 0; /* protect against integer overflow */ 354178479Sjb s = sizeof(struct packed_rrset_data) + 355178479Sjb (pset->rr_count + pset->rrsig_count) * 356178479Sjb (sizeof(size_t)+sizeof(uint8_t*)+sizeof(time_t)) + 357178479Sjb pset->size; 358178479Sjb if(region) 359178479Sjb *data = regional_alloc_zero(region, s); 360178479Sjb else *data = calloc(1, s); 361178479Sjb if(!*data) 362178479Sjb return 0; 363178479Sjb /* copy & decompress */ 364178479Sjb if(!parse_rr_copy(pkt, pset, *data)) { 365178479Sjb if(!region) { 366178479Sjb free(*data); 367178479Sjb *data = NULL; 368178479Sjb } 369178479Sjb return 0; 370178479Sjb } 371178479Sjb return 1; 372178479Sjb} 373178479Sjb 374178479Sjb/** get trust value for rrset */ 375178479Sjbstatic enum rrset_trust 376178479Sjbget_rrset_trust(struct msg_parse* msg, struct rrset_parse* rrset) 377178479Sjb{ 378178479Sjb uint16_t AA = msg->flags & BIT_AA; 379178479Sjb if(rrset->section == LDNS_SECTION_ANSWER) { 380178479Sjb if(AA) { 381178479Sjb /* RFC2181 says remainder of CNAME chain is nonauth*/ 382178479Sjb if(msg->rrset_first && 383178479Sjb msg->rrset_first->section==LDNS_SECTION_ANSWER 384178479Sjb && msg->rrset_first->type==LDNS_RR_TYPE_CNAME){ 385178479Sjb if(rrset == msg->rrset_first) 386178479Sjb return rrset_trust_ans_AA; 387178479Sjb else return rrset_trust_ans_noAA; 388178479Sjb } 389178479Sjb if(msg->rrset_first && 390178479Sjb msg->rrset_first->section==LDNS_SECTION_ANSWER 391178479Sjb && msg->rrset_first->type==LDNS_RR_TYPE_DNAME){ 392178479Sjb if(rrset == msg->rrset_first || 393178479Sjb rrset == msg->rrset_first->rrset_all_next) 394178479Sjb return rrset_trust_ans_AA; 395178479Sjb else return rrset_trust_ans_noAA; 396178479Sjb } 397178479Sjb return rrset_trust_ans_AA; 398178479Sjb } 399210767Srpaulo else return rrset_trust_ans_noAA; 400178479Sjb } else if(rrset->section == LDNS_SECTION_AUTHORITY) { 401178479Sjb if(AA) return rrset_trust_auth_AA; 402178479Sjb else return rrset_trust_auth_noAA; 403178479Sjb } else { 404178479Sjb /* addit section */ 405178479Sjb if(AA) return rrset_trust_add_AA; 406178479Sjb else return rrset_trust_add_noAA; 407178479Sjb } 408178479Sjb /* NOTREACHED */ 409178479Sjb return rrset_trust_none; 410178479Sjb} 411178479Sjb 412178479Sjbint 413178479Sjbparse_copy_decompress_rrset(sldns_buffer* pkt, struct msg_parse* msg, 414178479Sjb struct rrset_parse *pset, struct regional* region, 415178479Sjb struct ub_packed_rrset_key* pk) 416178479Sjb{ 417178479Sjb struct packed_rrset_data* data; 418178479Sjb pk->rk.flags = pset->flags; 419178479Sjb pk->rk.dname_len = pset->dname_len; 420178479Sjb if(region) 421178479Sjb pk->rk.dname = (uint8_t*)regional_alloc( 422178479Sjb region, pset->dname_len); 423178479Sjb else pk->rk.dname = 424178479Sjb (uint8_t*)malloc(pset->dname_len); 425178479Sjb if(!pk->rk.dname) 426178479Sjb return 0; 427178479Sjb /** copy & decompress dname */ 428178479Sjb dname_pkt_copy(pkt, pk->rk.dname, pset->dname); 429178479Sjb /** copy over type and class */ 430178479Sjb pk->rk.type = htons(pset->type); 431178479Sjb pk->rk.rrset_class = pset->rrset_class; 432178479Sjb /** read data part. */ 433178479Sjb if(!parse_create_rrset(pkt, pset, &data, region)) { 434178479Sjb if(!region) { 435178479Sjb free(pk->rk.dname); 436178479Sjb pk->rk.dname = NULL; 437178479Sjb } 438178479Sjb return 0; 439178479Sjb } 440178479Sjb pk->entry.data = (void*)data; 441178479Sjb pk->entry.key = (void*)pk; 442178479Sjb pk->entry.hash = pset->hash; 443178479Sjb data->trust = get_rrset_trust(msg, pset); 444178479Sjb return 1; 445178479Sjb} 446178479Sjb 447178479Sjb/** 448178479Sjb * Copy and decompress rrs 449178479Sjb * @param pkt: the packet for compression pointer resolution. 450178479Sjb * @param msg: the parsed message 451178479Sjb * @param rep: reply info to put rrs into. 452178479Sjb * @param region: if not NULL, used for allocation. 453178479Sjb * @return 0 on failure. 454178479Sjb */ 455178479Sjbstatic int 456178479Sjbparse_copy_decompress(sldns_buffer* pkt, struct msg_parse* msg, 457178479Sjb struct reply_info* rep, struct regional* region) 458178479Sjb{ 459178479Sjb size_t i; 460178479Sjb struct rrset_parse *pset = msg->rrset_first; 461178479Sjb struct packed_rrset_data* data; 462178479Sjb log_assert(rep); 463178479Sjb rep->ttl = MAX_TTL; 464178479Sjb rep->security = sec_status_unchecked; 465178479Sjb if(rep->rrset_count == 0) 466178479Sjb rep->ttl = NORR_TTL; 467178479Sjb 468178479Sjb for(i=0; i<rep->rrset_count; i++) { 469178479Sjb if(!parse_copy_decompress_rrset(pkt, msg, pset, region, 470178552Sjb rep->rrsets[i])) 471178479Sjb return 0; 472178552Sjb data = (struct packed_rrset_data*)rep->rrsets[i]->entry.data; 473178552Sjb if(data->ttl < rep->ttl) 474178552Sjb rep->ttl = data->ttl; 475178479Sjb 476178479Sjb pset = pset->rrset_all_next; 477178479Sjb } 478178479Sjb rep->prefetch_ttl = PREFETCH_TTL_CALC(rep->ttl); 479178479Sjb rep->serve_expired_ttl = rep->ttl + SERVE_EXPIRED_TTL; 480178479Sjb return 1; 481178479Sjb} 482178479Sjb 483178479Sjbint 484178479Sjbparse_create_msg(sldns_buffer* pkt, struct msg_parse* msg, 485178479Sjb struct alloc_cache* alloc, struct query_info* qinf, 486178479Sjb struct reply_info** rep, struct regional* region) 487178479Sjb{ 488178479Sjb log_assert(pkt && msg); 489178479Sjb if(!parse_create_qinfo(pkt, msg, qinf, region)) 490178479Sjb return 0; 491178479Sjb if(!parse_create_repinfo(msg, rep, region)) 492178479Sjb return 0; 493178479Sjb if(!reply_info_alloc_rrset_keys(*rep, alloc, region)) { 494178479Sjb if(!region) reply_info_parsedelete(*rep, alloc); 495178479Sjb return 0; 496178479Sjb } 497178479Sjb if(!parse_copy_decompress(pkt, msg, *rep, region)) { 498178479Sjb if(!region) reply_info_parsedelete(*rep, alloc); 499178479Sjb return 0; 500178479Sjb } 501178479Sjb return 1; 502178479Sjb} 503178479Sjb 504178479Sjbint reply_info_parse(sldns_buffer* pkt, struct alloc_cache* alloc, 505178479Sjb struct query_info* qinf, struct reply_info** rep, 506178479Sjb struct regional* region, struct edns_data* edns) 507178479Sjb{ 508178479Sjb /* use scratch pad region-allocator during parsing. */ 509178479Sjb struct msg_parse* msg; 510178479Sjb int ret; 511178479Sjb 512178479Sjb qinf->qname = NULL; 513178479Sjb qinf->local_alias = NULL; 514210767Srpaulo *rep = NULL; 515210767Srpaulo if(!(msg = regional_alloc(region, sizeof(*msg)))) { 516210767Srpaulo return LDNS_RCODE_SERVFAIL; 517210767Srpaulo } 518210767Srpaulo memset(msg, 0, sizeof(*msg)); 519210767Srpaulo 520210767Srpaulo sldns_buffer_set_position(pkt, 0); 521210767Srpaulo if((ret = parse_packet(pkt, msg, region)) != 0) { 522210767Srpaulo return ret; 523210767Srpaulo } 524210767Srpaulo if((ret = parse_extract_edns_from_response_msg(msg, edns, region)) != 0) 525210767Srpaulo return ret; 526210767Srpaulo 527210767Srpaulo /* parse OK, allocate return structures */ 528210767Srpaulo /* this also performs dname decompression */ 529210767Srpaulo if(!parse_create_msg(pkt, msg, alloc, qinf, rep, NULL)) { 530210767Srpaulo query_info_clear(qinf); 531210767Srpaulo *rep = NULL; 532210767Srpaulo return LDNS_RCODE_SERVFAIL; 533210767Srpaulo } 534210767Srpaulo return 0; 535210767Srpaulo} 536210767Srpaulo 537210767Srpaulo/** helper compare function to sort in lock order */ 538210767Srpaulostatic int 539210767Srpauloreply_info_sortref_cmp(const void* a, const void* b) 540210767Srpaulo{ 541210767Srpaulo struct rrset_ref* x = (struct rrset_ref*)a; 542210767Srpaulo struct rrset_ref* y = (struct rrset_ref*)b; 543210767Srpaulo if(x->key < y->key) return -1; 544210767Srpaulo if(x->key > y->key) return 1; 545210767Srpaulo return 0; 546210767Srpaulo} 547210767Srpaulo 548210767Srpaulovoid 549210767Srpauloreply_info_sortref(struct reply_info* rep) 550210767Srpaulo{ 551210767Srpaulo qsort(&rep->ref[0], rep->rrset_count, sizeof(struct rrset_ref), 552210767Srpaulo reply_info_sortref_cmp); 553210767Srpaulo} 554210767Srpaulo 555210767Srpaulovoid 556210767Srpauloreply_info_set_ttls(struct reply_info* rep, time_t timenow) 557210767Srpaulo{ 558210767Srpaulo size_t i, j; 559210767Srpaulo rep->ttl += timenow; 560210767Srpaulo rep->prefetch_ttl += timenow; 561210767Srpaulo rep->serve_expired_ttl += timenow; 562210767Srpaulo for(i=0; i<rep->rrset_count; i++) { 563210767Srpaulo struct packed_rrset_data* data = (struct packed_rrset_data*) 564210767Srpaulo rep->ref[i].key->entry.data; 565210767Srpaulo if(i>0 && rep->ref[i].key == rep->ref[i-1].key) 566178479Sjb continue; 567178479Sjb data->ttl += timenow; 568178479Sjb for(j=0; j<data->count + data->rrsig_count; j++) { 569178479Sjb data->rr_ttl[j] += timenow; 570178479Sjb } 571178479Sjb data->ttl_add = timenow; 572178479Sjb } 573178479Sjb} 574178479Sjb 575178479Sjbvoid 576178479Sjbreply_info_parsedelete(struct reply_info* rep, struct alloc_cache* alloc) 577178479Sjb{ 578178479Sjb size_t i; 579178479Sjb if(!rep) 580178479Sjb return; 581178479Sjb /* no need to lock, since not shared in hashtables. */ 582178479Sjb for(i=0; i<rep->rrset_count; i++) { 583178479Sjb ub_packed_rrset_parsedelete(rep->rrsets[i], alloc); 584178479Sjb } 585178479Sjb if(rep->reason_bogus_str) { 586178479Sjb free(rep->reason_bogus_str); 587178479Sjb rep->reason_bogus_str = NULL; 588178479Sjb } 589178479Sjb free(rep); 590178479Sjb} 591178479Sjb 592178479Sjbint 593178479Sjbquery_info_parse(struct query_info* m, sldns_buffer* query) 594178479Sjb{ 595178479Sjb uint8_t* q = sldns_buffer_begin(query); 596178479Sjb /* minimum size: header + \0 + qtype + qclass */ 597178479Sjb if(sldns_buffer_limit(query) < LDNS_HEADER_SIZE + 5) 598178479Sjb return 0; 599178479Sjb if((LDNS_OPCODE_WIRE(q) != LDNS_PACKET_QUERY && LDNS_OPCODE_WIRE(q) != 600178479Sjb LDNS_PACKET_NOTIFY) || LDNS_QDCOUNT(q) != 1 || 601178479Sjb sldns_buffer_position(query) != 0) 602178479Sjb return 0; 603178479Sjb sldns_buffer_skip(query, LDNS_HEADER_SIZE); 604178479Sjb m->qname = sldns_buffer_current(query); 605178479Sjb if((m->qname_len = query_dname_len(query)) == 0) 606178479Sjb return 0; /* parse error */ 607178479Sjb if(sldns_buffer_remaining(query) < 4) 608178479Sjb return 0; /* need qtype, qclass */ 609178479Sjb m->qtype = sldns_buffer_read_u16(query); 610178479Sjb m->qclass = sldns_buffer_read_u16(query); 611178479Sjb m->local_alias = NULL; 612178479Sjb return 1; 613178479Sjb} 614178479Sjb 615178479Sjb/** tiny subroutine for msgreply_compare */ 616178479Sjb#define COMPARE_IT(x, y) \ 617178479Sjb if( (x) < (y) ) return -1; \ 618178479Sjb else if( (x) > (y) ) return +1; \ 619178479Sjb log_assert( (x) == (y) ); 620178479Sjb 621178479Sjbint 622178479Sjbquery_info_compare(void* m1, void* m2) 623178479Sjb{ 624178479Sjb struct query_info* msg1 = (struct query_info*)m1; 625178479Sjb struct query_info* msg2 = (struct query_info*)m2; 626178479Sjb int mc; 627178479Sjb /* from most different to least different for speed */ 628178479Sjb COMPARE_IT(msg1->qtype, msg2->qtype); 629178479Sjb if((mc = query_dname_compare(msg1->qname, msg2->qname)) != 0) 630178479Sjb return mc; 631178479Sjb log_assert(msg1->qname_len == msg2->qname_len); 632178479Sjb COMPARE_IT(msg1->qclass, msg2->qclass); 633178479Sjb return 0; 634178479Sjb#undef COMPARE_IT 635178479Sjb} 636178479Sjb 637178479Sjbvoid 638178479Sjbquery_info_clear(struct query_info* m) 639178479Sjb{ 640178479Sjb free(m->qname); 641178479Sjb m->qname = NULL; 642178479Sjb} 643178479Sjb 644178479Sjbsize_t 645178479Sjbmsgreply_sizefunc(void* k, void* d) 646178479Sjb{ 647178479Sjb struct msgreply_entry* q = (struct msgreply_entry*)k; 648178479Sjb struct reply_info* r = (struct reply_info*)d; 649178479Sjb size_t s = sizeof(struct msgreply_entry) + sizeof(struct reply_info) 650178479Sjb + q->key.qname_len + lock_get_mem(&q->entry.lock) 651178479Sjb - sizeof(struct rrset_ref); 652178479Sjb s += r->rrset_count * sizeof(struct rrset_ref); 653178479Sjb s += r->rrset_count * sizeof(struct ub_packed_rrset_key*); 654178479Sjb return s; 655178479Sjb} 656178479Sjb 657178479Sjbvoid 658178479Sjbquery_entry_delete(void *k, void* ATTR_UNUSED(arg)) 659178479Sjb{ 660178479Sjb struct msgreply_entry* q = (struct msgreply_entry*)k; 661178479Sjb lock_rw_destroy(&q->entry.lock); 662178479Sjb query_info_clear(&q->key); 663178479Sjb free(q); 664178479Sjb} 665178479Sjb 666178479Sjbvoid 667178479Sjbreply_info_delete(void* d, void* ATTR_UNUSED(arg)) 668253725Spfg{ 669210767Srpaulo struct reply_info* r = (struct reply_info*)d; 670178479Sjb if(r->reason_bogus_str) { 671178479Sjb free(r->reason_bogus_str); 672178479Sjb r->reason_bogus_str = NULL; 673178479Sjb } 674178479Sjb free(r); 675178479Sjb} 676178479Sjb 677178479Sjbhashvalue_type 678178479Sjbquery_info_hash(struct query_info *q, uint16_t flags) 679178479Sjb{ 680178479Sjb hashvalue_type h = 0xab; 681178479Sjb h = hashlittle(&q->qtype, sizeof(q->qtype), h); 682178479Sjb if(q->qtype == LDNS_RR_TYPE_AAAA && (flags&BIT_CD)) 683178479Sjb h++; 684178479Sjb h = hashlittle(&q->qclass, sizeof(q->qclass), h); 685178479Sjb h = dname_query_hash(q->qname, h); 686178479Sjb return h; 687178479Sjb} 688178479Sjb 689178479Sjbstruct msgreply_entry* 690178479Sjbquery_info_entrysetup(struct query_info* q, struct reply_info* r, 691178479Sjb hashvalue_type h) 692210767Srpaulo{ 693178479Sjb struct msgreply_entry* e = (struct msgreply_entry*)malloc( 694178479Sjb sizeof(struct msgreply_entry)); 695178479Sjb if(!e) return NULL; 696178479Sjb memcpy(&e->key, q, sizeof(*q)); 697178479Sjb e->entry.hash = h; 698178479Sjb e->entry.key = e; 699178479Sjb e->entry.data = r; 700178479Sjb lock_rw_init(&e->entry.lock); 701178479Sjb lock_protect(&e->entry.lock, &e->key.qname, sizeof(e->key.qname)); 702178479Sjb lock_protect(&e->entry.lock, &e->key.qname_len, sizeof(e->key.qname_len)); 703178479Sjb lock_protect(&e->entry.lock, &e->key.qtype, sizeof(e->key.qtype)); 704178479Sjb lock_protect(&e->entry.lock, &e->key.qclass, sizeof(e->key.qclass)); 705178479Sjb lock_protect(&e->entry.lock, &e->key.local_alias, sizeof(e->key.local_alias)); 706178479Sjb lock_protect(&e->entry.lock, &e->entry.hash, sizeof(e->entry.hash)); 707178479Sjb lock_protect(&e->entry.lock, &e->entry.key, sizeof(e->entry.key)); 708178479Sjb lock_protect(&e->entry.lock, &e->entry.data, sizeof(e->entry.data)); 709178479Sjb lock_protect(&e->entry.lock, e->key.qname, e->key.qname_len); 710178479Sjb q->qname = NULL; 711178479Sjb return e; 712178479Sjb} 713178479Sjb 714178479Sjb/** copy rrsets from replyinfo to dest replyinfo */ 715178479Sjbstatic int 716178479Sjbrepinfo_copy_rrsets(struct reply_info* dest, struct reply_info* from, 717178479Sjb struct regional* region) 718178479Sjb{ 719178479Sjb size_t i, s; 720178479Sjb struct packed_rrset_data* fd, *dd; 721178479Sjb struct ub_packed_rrset_key* fk, *dk; 722178479Sjb for(i=0; i<dest->rrset_count; i++) { 723178479Sjb fk = from->rrsets[i]; 724178479Sjb dk = dest->rrsets[i]; 725178479Sjb fd = (struct packed_rrset_data*)fk->entry.data; 726178479Sjb dk->entry.hash = fk->entry.hash; 727178479Sjb dk->rk = fk->rk; 728178479Sjb if(region) { 729178479Sjb dk->id = fk->id; 730178479Sjb dk->rk.dname = (uint8_t*)regional_alloc_init(region, 731178479Sjb fk->rk.dname, fk->rk.dname_len); 732178479Sjb } else 733178479Sjb dk->rk.dname = (uint8_t*)memdup(fk->rk.dname, 734178479Sjb fk->rk.dname_len); 735178479Sjb if(!dk->rk.dname) 736178479Sjb return 0; 737178479Sjb s = packed_rrset_sizeof(fd); 738178479Sjb if(region) 739178479Sjb dd = (struct packed_rrset_data*)regional_alloc_init( 740178479Sjb region, fd, s); 741178479Sjb else dd = (struct packed_rrset_data*)memdup(fd, s); 742178479Sjb if(!dd) 743178479Sjb return 0; 744178479Sjb packed_rrset_ptr_fixup(dd); 745178479Sjb dk->entry.data = (void*)dd; 746178479Sjb } 747178479Sjb return 1; 748178479Sjb} 749178479Sjb 750178479Sjbstruct reply_info* 751178479Sjbreply_info_copy(struct reply_info* rep, struct alloc_cache* alloc, 752178479Sjb struct regional* region) 753178479Sjb{ 754178479Sjb struct reply_info* cp; 755178479Sjb cp = construct_reply_info_base(region, rep->flags, rep->qdcount, 756178479Sjb rep->ttl, rep->prefetch_ttl, rep->serve_expired_ttl, 757178479Sjb rep->an_numrrsets, rep->ns_numrrsets, rep->ar_numrrsets, 758178479Sjb rep->rrset_count, rep->security, rep->reason_bogus); 759178479Sjb if(!cp) 760178479Sjb return NULL; 761178479Sjb 762178479Sjb if(rep->reason_bogus_str && *rep->reason_bogus_str != 0) { 763178479Sjb if(region) { 764178479Sjb cp->reason_bogus_str = (char*)regional_alloc(region, 765178479Sjb sizeof(char) 766178479Sjb * (strlen(rep->reason_bogus_str)+1)); 767178479Sjb } else { 768178479Sjb cp->reason_bogus_str = malloc(sizeof(char) 769178479Sjb * (strlen(rep->reason_bogus_str)+1)); 770178479Sjb } 771178479Sjb if(!cp->reason_bogus_str) { 772178479Sjb if(!region) 773178479Sjb reply_info_parsedelete(cp, alloc); 774178479Sjb return NULL; 775178479Sjb } 776178479Sjb memcpy(cp->reason_bogus_str, rep->reason_bogus_str, 777178479Sjb strlen(rep->reason_bogus_str)+1); 778178479Sjb } 779178479Sjb 780178479Sjb /* allocate ub_key structures special or not */ 781178479Sjb if(!reply_info_alloc_rrset_keys(cp, alloc, region)) { 782178479Sjb if(!region) 783178479Sjb reply_info_parsedelete(cp, alloc); 784178479Sjb return NULL; 785178479Sjb } 786178479Sjb if(!repinfo_copy_rrsets(cp, rep, region)) { 787178479Sjb if(!region) 788178479Sjb reply_info_parsedelete(cp, alloc); 789178479Sjb return NULL; 790178479Sjb } 791178479Sjb return cp; 792178479Sjb} 793178479Sjb 794178479Sjbuint8_t* 795178479Sjbreply_find_final_cname_target(struct query_info* qinfo, struct reply_info* rep) 796178479Sjb{ 797178479Sjb uint8_t* sname = qinfo->qname; 798178479Sjb size_t snamelen = qinfo->qname_len; 799178479Sjb size_t i; 800178479Sjb for(i=0; i<rep->an_numrrsets; i++) { 801178479Sjb struct ub_packed_rrset_key* s = rep->rrsets[i]; 802178479Sjb /* follow CNAME chain (if any) */ 803178479Sjb if(ntohs(s->rk.type) == LDNS_RR_TYPE_CNAME && 804178479Sjb ntohs(s->rk.rrset_class) == qinfo->qclass && 805178479Sjb snamelen == s->rk.dname_len && 806178479Sjb query_dname_compare(sname, s->rk.dname) == 0) { 807178479Sjb get_cname_target(s, &sname, &snamelen); 808178479Sjb } 809178479Sjb } 810178479Sjb if(sname != qinfo->qname) 811178479Sjb return sname; 812178479Sjb return NULL; 813178479Sjb} 814178479Sjb 815178479Sjbstruct ub_packed_rrset_key* 816178479Sjbreply_find_answer_rrset(struct query_info* qinfo, struct reply_info* rep) 817178479Sjb{ 818178479Sjb uint8_t* sname = qinfo->qname; 819178479Sjb size_t snamelen = qinfo->qname_len; 820178479Sjb size_t i; 821178479Sjb for(i=0; i<rep->an_numrrsets; i++) { 822178479Sjb struct ub_packed_rrset_key* s = rep->rrsets[i]; 823178479Sjb /* first match type, for query of qtype cname */ 824178479Sjb if(ntohs(s->rk.type) == qinfo->qtype && 825178479Sjb ntohs(s->rk.rrset_class) == qinfo->qclass && 826178479Sjb snamelen == s->rk.dname_len && 827178479Sjb query_dname_compare(sname, s->rk.dname) == 0) { 828178479Sjb return s; 829178479Sjb } 830178479Sjb /* follow CNAME chain (if any) */ 831178479Sjb if(ntohs(s->rk.type) == LDNS_RR_TYPE_CNAME && 832178479Sjb ntohs(s->rk.rrset_class) == qinfo->qclass && 833178479Sjb snamelen == s->rk.dname_len && 834178479Sjb query_dname_compare(sname, s->rk.dname) == 0) { 835178479Sjb get_cname_target(s, &sname, &snamelen); 836178479Sjb } 837178479Sjb } 838178479Sjb return NULL; 839178479Sjb} 840178479Sjb 841178479Sjbstruct ub_packed_rrset_key* reply_find_rrset_section_an(struct reply_info* rep, 842178479Sjb uint8_t* name, size_t namelen, uint16_t type, uint16_t dclass) 843178479Sjb{ 844178479Sjb size_t i; 845178479Sjb for(i=0; i<rep->an_numrrsets; i++) { 846178479Sjb struct ub_packed_rrset_key* s = rep->rrsets[i]; 847178479Sjb if(ntohs(s->rk.type) == type && 848178479Sjb ntohs(s->rk.rrset_class) == dclass && 849178479Sjb namelen == s->rk.dname_len && 850178479Sjb query_dname_compare(name, s->rk.dname) == 0) { 851178479Sjb return s; 852178479Sjb } 853178479Sjb } 854178479Sjb return NULL; 855178479Sjb} 856178479Sjb 857178479Sjbstruct ub_packed_rrset_key* reply_find_rrset_section_ns(struct reply_info* rep, 858178479Sjb uint8_t* name, size_t namelen, uint16_t type, uint16_t dclass) 859178479Sjb{ 860178479Sjb size_t i; 861178479Sjb for(i=rep->an_numrrsets; i<rep->an_numrrsets+rep->ns_numrrsets; i++) { 862178479Sjb struct ub_packed_rrset_key* s = rep->rrsets[i]; 863178479Sjb if(ntohs(s->rk.type) == type && 864178479Sjb ntohs(s->rk.rrset_class) == dclass && 865178479Sjb namelen == s->rk.dname_len && 866178479Sjb query_dname_compare(name, s->rk.dname) == 0) { 867178479Sjb return s; 868178479Sjb } 869178479Sjb } 870178479Sjb return NULL; 871178479Sjb} 872178479Sjb 873178479Sjbstruct ub_packed_rrset_key* reply_find_rrset(struct reply_info* rep, 874178479Sjb uint8_t* name, size_t namelen, uint16_t type, uint16_t dclass) 875178479Sjb{ 876178479Sjb size_t i; 877178479Sjb for(i=0; i<rep->rrset_count; i++) { 878178479Sjb struct ub_packed_rrset_key* s = rep->rrsets[i]; 879178479Sjb if(ntohs(s->rk.type) == type && 880178479Sjb ntohs(s->rk.rrset_class) == dclass && 881178479Sjb namelen == s->rk.dname_len && 882178479Sjb query_dname_compare(name, s->rk.dname) == 0) { 883178479Sjb return s; 884178479Sjb } 885178479Sjb } 886178479Sjb return NULL; 887178479Sjb} 888178479Sjb 889178479Sjbvoid 890178479Sjblog_dns_msg(const char* str, struct query_info* qinfo, struct reply_info* rep) 891178479Sjb{ 892178479Sjb /* not particularly fast but flexible, make wireformat and print */ 893178479Sjb sldns_buffer* buf = sldns_buffer_new(65535); 894178479Sjb struct regional* region = regional_create(); 895178479Sjb if(!(buf && region)) { 896178479Sjb log_err("%s: log_dns_msg: out of memory", str); 897178479Sjb sldns_buffer_free(buf); 898178479Sjb regional_destroy(region); 899178479Sjb return; 900178479Sjb } 901178479Sjb if(!reply_info_encode(qinfo, rep, 0, rep->flags, buf, 0, 902178479Sjb region, 65535, 1, 0)) { 903178479Sjb log_err("%s: log_dns_msg: out of memory", str); 904178479Sjb } else { 905178479Sjb char* s = sldns_wire2str_pkt(sldns_buffer_begin(buf), 906178479Sjb sldns_buffer_limit(buf)); 907178479Sjb if(!s) { 908178479Sjb log_info("%s: log_dns_msg: ldns tostr failed", str); 909178479Sjb } else { 910178479Sjb log_info("%s %s", str, s); 911178479Sjb } 912178479Sjb free(s); 913178479Sjb } 914178479Sjb sldns_buffer_free(buf); 915178479Sjb regional_destroy(region); 916178479Sjb} 917178479Sjb 918178479Sjbvoid 919178479Sjblog_reply_info(enum verbosity_value v, struct query_info *qinf, 920178479Sjb struct sockaddr_storage *addr, socklen_t addrlen, struct timeval dur, 921178479Sjb int cached, struct sldns_buffer *rmsg, struct sockaddr_storage* daddr, 922178479Sjb enum comm_point_type tp) 923178479Sjb{ 924178479Sjb char qname_buf[LDNS_MAX_DOMAINLEN+1]; 925178479Sjb char clientip_buf[128]; 926178479Sjb char rcode_buf[16]; 927178479Sjb char type_buf[16]; 928178479Sjb char class_buf[16]; 929178479Sjb char dest_buf[160]; 930178479Sjb size_t pktlen; 931178479Sjb uint16_t rcode = FLAGS_GET_RCODE(sldns_buffer_read_u16_at(rmsg, 2)); 932178479Sjb 933178479Sjb if(verbosity < v) 934178479Sjb return; 935178479Sjb 936178479Sjb sldns_wire2str_rcode_buf((int)rcode, rcode_buf, sizeof(rcode_buf)); 937178479Sjb addr_to_str(addr, addrlen, clientip_buf, sizeof(clientip_buf)); 938178479Sjb if(daddr) { 939178479Sjb char da[128]; 940178479Sjb int port = 0; 941178479Sjb char* comm; 942178479Sjb if(daddr->ss_family == AF_INET6) { 943178479Sjb struct sockaddr_in6 *d = (struct sockaddr_in6 *)daddr; 944178479Sjb if(inet_ntop(d->sin6_family, &d->sin6_addr, da, 945178479Sjb sizeof(*d)) == 0) 946178479Sjb snprintf(dest_buf, sizeof(dest_buf), 947178479Sjb "(inet_ntop_error)"); 948178479Sjb port = ntohs(d->sin6_port); 949178479Sjb } else if(daddr->ss_family == AF_INET) { 950178479Sjb struct sockaddr_in *d = (struct sockaddr_in *)daddr; 951178479Sjb if(inet_ntop(d->sin_family, &d->sin_addr, da, 952178479Sjb sizeof(*d)) == 0) 953178479Sjb snprintf(dest_buf, sizeof(dest_buf), 954178479Sjb "(inet_ntop_error)"); 955178479Sjb port = ntohs(d->sin_port); 956178479Sjb } else { 957178479Sjb snprintf(da, sizeof(da), "socket%d", 958178479Sjb (int)daddr->ss_family); 959178479Sjb } 960178479Sjb comm = "udp"; 961178479Sjb if(tp == comm_tcp) comm = "tcp"; 962178479Sjb else if(tp == comm_tcp_accept) comm = "tcp"; 963178479Sjb else if(tp == comm_http) comm = "dot"; 964178479Sjb else if(tp == comm_local) comm = "unix"; 965178479Sjb else if(tp == comm_raw) comm = "raw"; 966178479Sjb snprintf(dest_buf, sizeof(dest_buf), " on %s %s %d", 967178479Sjb comm, da, port); 968178479Sjb } else { 969178479Sjb dest_buf[0]=0; 970178479Sjb } 971178479Sjb if(rcode == LDNS_RCODE_FORMERR) 972178479Sjb { 973178479Sjb if(LOG_TAG_QUERYREPLY) 974178479Sjb log_reply("%s - - - %s - - -%s", clientip_buf, 975178479Sjb rcode_buf, dest_buf); 976178479Sjb else log_info("%s - - - %s - - -%s", clientip_buf, 977178479Sjb rcode_buf, dest_buf); 978178479Sjb } else { 979178479Sjb if(qinf->qname) 980178479Sjb dname_str(qinf->qname, qname_buf); 981178479Sjb else snprintf(qname_buf, sizeof(qname_buf), "null"); 982178479Sjb pktlen = sldns_buffer_limit(rmsg); 983178479Sjb sldns_wire2str_type_buf(qinf->qtype, type_buf, sizeof(type_buf)); 984178479Sjb sldns_wire2str_class_buf(qinf->qclass, class_buf, sizeof(class_buf)); 985178479Sjb if(LOG_TAG_QUERYREPLY) 986178479Sjb log_reply("%s %s %s %s %s " ARG_LL "d.%6.6d %d %d%s", 987178479Sjb clientip_buf, qname_buf, type_buf, class_buf, 988178479Sjb rcode_buf, (long long)dur.tv_sec, (int)dur.tv_usec, 989178479Sjb cached, (int)pktlen, dest_buf); 990178479Sjb else log_info("%s %s %s %s %s " ARG_LL "d.%6.6d %d %d%s", 991178479Sjb clientip_buf, qname_buf, type_buf, class_buf, 992178479Sjb rcode_buf, (long long)dur.tv_sec, (int)dur.tv_usec, 993178479Sjb cached, (int)pktlen, dest_buf); 994178479Sjb } 995178479Sjb} 996178479Sjb 997178479Sjbvoid 998178479Sjblog_query_info(enum verbosity_value v, const char* str, 999178479Sjb struct query_info* qinf) 1000178479Sjb{ 1001178479Sjb log_nametypeclass(v, str, qinf->qname, qinf->qtype, qinf->qclass); 1002178479Sjb} 1003178479Sjb 1004178479Sjbint 1005178479Sjbreply_check_cname_chain(struct query_info* qinfo, struct reply_info* rep) 1006178479Sjb{ 1007178479Sjb /* check only answer section rrs for matching cname chain. 1008178479Sjb * the cache may return changed rdata, but owner names are untouched.*/ 1009178479Sjb size_t i; 1010178479Sjb uint8_t* sname = qinfo->qname; 1011178479Sjb size_t snamelen = qinfo->qname_len; 1012178479Sjb for(i=0; i<rep->an_numrrsets; i++) { 1013178479Sjb uint16_t t = ntohs(rep->rrsets[i]->rk.type); 1014178479Sjb if(t == LDNS_RR_TYPE_DNAME) 1015178479Sjb continue; /* skip dnames; note TTL 0 not cached */ 1016178479Sjb /* verify that owner matches current sname */ 1017178479Sjb if(query_dname_compare(sname, rep->rrsets[i]->rk.dname) != 0){ 1018178479Sjb /* cname chain broken */ 1019178479Sjb return 0; 1020178479Sjb } 1021178479Sjb /* if this is a cname; move on */ 1022178479Sjb if(t == LDNS_RR_TYPE_CNAME) { 1023178479Sjb get_cname_target(rep->rrsets[i], &sname, &snamelen); 1024178479Sjb } 1025178479Sjb } 1026178479Sjb return 1; 1027178479Sjb} 1028178479Sjb 1029178479Sjbint 1030178479Sjbreply_all_rrsets_secure(struct reply_info* rep) 1031178479Sjb{ 1032178479Sjb size_t i; 1033178479Sjb for(i=0; i<rep->rrset_count; i++) { 1034178479Sjb if( ((struct packed_rrset_data*)rep->rrsets[i]->entry.data) 1035178479Sjb ->security != sec_status_secure ) 1036178479Sjb return 0; 1037178479Sjb } 1038178479Sjb return 1; 1039178479Sjb} 1040178479Sjb 1041178479Sjbstruct reply_info* 1042178479Sjbparse_reply_in_temp_region(sldns_buffer* pkt, struct regional* region, 1043178479Sjb struct query_info* qi) 1044178479Sjb{ 1045178479Sjb struct reply_info* rep; 1046178479Sjb struct msg_parse* msg; 1047178479Sjb if(!(msg = regional_alloc(region, sizeof(*msg)))) { 1048178479Sjb return NULL; 1049178479Sjb } 1050178479Sjb memset(msg, 0, sizeof(*msg)); 1051178479Sjb sldns_buffer_set_position(pkt, 0); 1052178479Sjb if(parse_packet(pkt, msg, region) != 0){ 1053178479Sjb return 0; 1054178479Sjb } 1055178479Sjb if(!parse_create_msg(pkt, msg, NULL, qi, &rep, region)) { 1056178479Sjb return 0; 1057178479Sjb } 1058178479Sjb return rep; 1059178479Sjb} 1060178479Sjb 1061178479Sjbint edns_opt_list_append_ede(struct edns_option** list, struct regional* region, 1062178479Sjb sldns_ede_code code, const char *txt) 1063178479Sjb{ 1064178479Sjb struct edns_option** prevp; 1065178479Sjb struct edns_option* opt; 1066178479Sjb size_t txt_len = txt ? strlen(txt) : 0; 1067178479Sjb 1068178479Sjb /* allocate new element */ 1069178479Sjb opt = (struct edns_option*)regional_alloc(region, sizeof(*opt)); 1070178479Sjb if(!opt) 1071178479Sjb return 0; 1072178479Sjb opt->next = NULL; 1073178479Sjb opt->opt_code = LDNS_EDNS_EDE; 1074178479Sjb opt->opt_len = txt_len + sizeof(uint16_t); 1075178479Sjb opt->opt_data = regional_alloc(region, txt_len + sizeof(uint16_t)); 1076178479Sjb if(!opt->opt_data) 1077178479Sjb return 0; 1078178479Sjb sldns_write_uint16(opt->opt_data, (uint16_t)code); 1079178479Sjb if (txt_len) 1080178479Sjb memmove(opt->opt_data + 2, txt, txt_len); 1081178479Sjb 1082178479Sjb /* append at end of list */ 1083178479Sjb prevp = list; 1084178479Sjb while(*prevp != NULL) 1085178479Sjb prevp = &((*prevp)->next); 1086178479Sjb verbose(VERB_ALGO, "attached EDE code: %d with message: %s", code, (txt?txt:"\"\"")); 1087178479Sjb *prevp = opt; 1088178479Sjb return 1; 1089178479Sjb} 1090178479Sjb 1091178479Sjbint edns_opt_list_append_keepalive(struct edns_option** list, int msec, 1092178479Sjb struct regional* region) 1093178479Sjb{ 1094178479Sjb uint8_t data[2]; /* For keepalive value */ 1095178479Sjb data[0] = (uint8_t)((msec >> 8) & 0xff); 1096178479Sjb data[1] = (uint8_t)(msec & 0xff); 1097178479Sjb return edns_opt_list_append(list, LDNS_EDNS_KEEPALIVE, sizeof(data), 1098178479Sjb data, region); 1099178479Sjb} 1100178479Sjb 1101178479Sjbint edns_opt_list_append(struct edns_option** list, uint16_t code, size_t len, 1102178479Sjb uint8_t* data, struct regional* region) 1103178479Sjb{ 1104178479Sjb struct edns_option** prevp; 1105178479Sjb struct edns_option* opt; 1106178479Sjb 1107178479Sjb /* allocate new element */ 1108178479Sjb opt = (struct edns_option*)regional_alloc(region, sizeof(*opt)); 1109178479Sjb if(!opt) 1110178479Sjb return 0; 1111178479Sjb opt->next = NULL; 1112178479Sjb opt->opt_code = code; 1113178479Sjb opt->opt_len = len; 1114178479Sjb opt->opt_data = NULL; 1115178479Sjb if(len > 0) { 1116178479Sjb opt->opt_data = regional_alloc_init(region, data, len); 1117178479Sjb if(!opt->opt_data) 1118178479Sjb return 0; 1119178479Sjb } 1120178479Sjb 1121178479Sjb /* append at end of list */ 1122178479Sjb prevp = list; 1123178479Sjb while(*prevp != NULL) { 1124178479Sjb prevp = &((*prevp)->next); 1125178479Sjb } 1126178479Sjb *prevp = opt; 1127178479Sjb return 1; 1128178479Sjb} 1129178479Sjb 1130178479Sjbint edns_opt_list_remove(struct edns_option** list, uint16_t code) 1131178479Sjb{ 1132178479Sjb /* The list should already be allocated in a region. Freeing the 1133178479Sjb * allocated space in a region is not possible. We just unlink the 1134178479Sjb * required elements and they will be freed together with the region. */ 1135178479Sjb 1136178479Sjb struct edns_option* prev; 1137178479Sjb struct edns_option* curr; 1138178479Sjb if(!list || !(*list)) return 0; 1139178479Sjb 1140178479Sjb /* Unlink and repoint if the element(s) are first in list */ 1141178479Sjb while(list && *list && (*list)->opt_code == code) { 1142178479Sjb *list = (*list)->next; 1143178479Sjb } 1144178479Sjb 1145178479Sjb if(!list || !(*list)) return 1; 1146178479Sjb /* Unlink elements and reattach the list */ 1147178479Sjb prev = *list; 1148178479Sjb curr = (*list)->next; 1149178479Sjb while(curr != NULL) { 1150178479Sjb if(curr->opt_code == code) { 1151178479Sjb prev->next = curr->next; 1152178479Sjb curr = curr->next; 1153178479Sjb } else { 1154178479Sjb prev = curr; 1155178479Sjb curr = curr->next; 1156178479Sjb } 1157178479Sjb } 1158178479Sjb return 1; 1159178479Sjb} 1160178479Sjb 1161178479Sjbstatic int inplace_cb_reply_call_generic( 1162178479Sjb struct inplace_cb* callback_list, enum inplace_cb_list_type type, 1163178479Sjb struct query_info* qinfo, struct module_qstate* qstate, 1164178479Sjb struct reply_info* rep, int rcode, struct edns_data* edns, 1165178479Sjb struct comm_reply* repinfo, struct regional* region, 1166178479Sjb struct timeval* start_time) 1167178479Sjb{ 1168178479Sjb struct inplace_cb* cb; 1169178479Sjb struct edns_option* opt_list_out = NULL; 1170178479Sjb#if defined(EXPORT_ALL_SYMBOLS) 1171178479Sjb (void)type; /* param not used when fptr_ok disabled */ 1172178479Sjb#endif 1173178479Sjb if(qstate) 1174178479Sjb opt_list_out = qstate->edns_opts_front_out; 1175178479Sjb for(cb=callback_list; cb; cb=cb->next) { 1176178479Sjb fptr_ok(fptr_whitelist_inplace_cb_reply_generic( 1177178479Sjb (inplace_cb_reply_func_type*)cb->cb, type)); 1178178479Sjb (void)(*(inplace_cb_reply_func_type*)cb->cb)(qinfo, qstate, rep, 1179178479Sjb rcode, edns, &opt_list_out, repinfo, region, start_time, cb->id, cb->cb_arg); 1180178479Sjb } 1181178479Sjb edns->opt_list_inplace_cb_out = opt_list_out; 1182178479Sjb return 1; 1183178479Sjb} 1184178479Sjb 1185178479Sjbint inplace_cb_reply_call(struct module_env* env, struct query_info* qinfo, 1186178479Sjb struct module_qstate* qstate, struct reply_info* rep, int rcode, 1187178479Sjb struct edns_data* edns, struct comm_reply* repinfo, struct regional* region, 1188178479Sjb struct timeval* start_time) 1189178479Sjb{ 1190178479Sjb return inplace_cb_reply_call_generic( 1191178479Sjb env->inplace_cb_lists[inplace_cb_reply], inplace_cb_reply, qinfo, 1192178479Sjb qstate, rep, rcode, edns, repinfo, region, start_time); 1193178479Sjb} 1194178479Sjb 1195178479Sjbint inplace_cb_reply_cache_call(struct module_env* env, 1196178479Sjb struct query_info* qinfo, struct module_qstate* qstate, 1197178479Sjb struct reply_info* rep, int rcode, struct edns_data* edns, 1198178479Sjb struct comm_reply* repinfo, struct regional* region, 1199178479Sjb struct timeval* start_time) 1200178479Sjb{ 1201178479Sjb return inplace_cb_reply_call_generic( 1202178479Sjb env->inplace_cb_lists[inplace_cb_reply_cache], inplace_cb_reply_cache, 1203178479Sjb qinfo, qstate, rep, rcode, edns, repinfo, region, start_time); 1204178479Sjb} 1205178479Sjb 1206178479Sjbint inplace_cb_reply_local_call(struct module_env* env, 1207178479Sjb struct query_info* qinfo, struct module_qstate* qstate, 1208178479Sjb struct reply_info* rep, int rcode, struct edns_data* edns, 1209178479Sjb struct comm_reply* repinfo, struct regional* region, 1210178479Sjb struct timeval* start_time) 1211178479Sjb{ 1212178479Sjb return inplace_cb_reply_call_generic( 1213178479Sjb env->inplace_cb_lists[inplace_cb_reply_local], inplace_cb_reply_local, 1214178479Sjb qinfo, qstate, rep, rcode, edns, repinfo, region, start_time); 1215178479Sjb} 1216178479Sjb 1217178479Sjbint inplace_cb_reply_servfail_call(struct module_env* env, 1218178479Sjb struct query_info* qinfo, struct module_qstate* qstate, 1219178479Sjb struct reply_info* rep, int rcode, struct edns_data* edns, 1220178479Sjb struct comm_reply* repinfo, struct regional* region, 1221178479Sjb struct timeval* start_time) 1222178479Sjb{ 1223178479Sjb /* We are going to servfail. Remove any potential edns options. */ 1224178479Sjb if(qstate) 1225178479Sjb qstate->edns_opts_front_out = NULL; 1226178479Sjb return inplace_cb_reply_call_generic( 1227178479Sjb env->inplace_cb_lists[inplace_cb_reply_servfail], 1228178479Sjb inplace_cb_reply_servfail, qinfo, qstate, rep, rcode, edns, repinfo, 1229178479Sjb region, start_time); 1230178479Sjb} 1231178479Sjb 1232178479Sjbint inplace_cb_query_call(struct module_env* env, struct query_info* qinfo, 1233178479Sjb uint16_t flags, struct sockaddr_storage* addr, socklen_t addrlen, 1234178479Sjb uint8_t* zone, size_t zonelen, struct module_qstate* qstate, 1235178479Sjb struct regional* region) 1236178479Sjb{ 1237178479Sjb struct inplace_cb* cb = env->inplace_cb_lists[inplace_cb_query]; 1238178479Sjb for(; cb; cb=cb->next) { 1239178479Sjb fptr_ok(fptr_whitelist_inplace_cb_query( 1240178479Sjb (inplace_cb_query_func_type*)cb->cb)); 1241178479Sjb (void)(*(inplace_cb_query_func_type*)cb->cb)(qinfo, flags, 1242178479Sjb qstate, addr, addrlen, zone, zonelen, region, 1243178479Sjb cb->id, cb->cb_arg); 1244178479Sjb } 1245178479Sjb return 1; 1246178479Sjb} 1247178479Sjb 1248178479Sjbint inplace_cb_edns_back_parsed_call(struct module_env* env, 1249178479Sjb struct module_qstate* qstate) 1250178479Sjb{ 1251178479Sjb struct inplace_cb* cb = 1252178479Sjb env->inplace_cb_lists[inplace_cb_edns_back_parsed]; 1253178479Sjb for(; cb; cb=cb->next) { 1254178479Sjb fptr_ok(fptr_whitelist_inplace_cb_edns_back_parsed( 1255178479Sjb (inplace_cb_edns_back_parsed_func_type*)cb->cb)); 1256178479Sjb (void)(*(inplace_cb_edns_back_parsed_func_type*)cb->cb)(qstate, 1257178479Sjb cb->id, cb->cb_arg); 1258178479Sjb } 1259178479Sjb return 1; 1260178479Sjb} 1261178479Sjb 1262178479Sjbint inplace_cb_query_response_call(struct module_env* env, 1263178479Sjb struct module_qstate* qstate, struct dns_msg* response) { 1264178479Sjb struct inplace_cb* cb = 1265178479Sjb env->inplace_cb_lists[inplace_cb_query_response]; 1266178479Sjb for(; cb; cb=cb->next) { 1267178479Sjb fptr_ok(fptr_whitelist_inplace_cb_query_response( 1268178479Sjb (inplace_cb_query_response_func_type*)cb->cb)); 1269178479Sjb (void)(*(inplace_cb_query_response_func_type*)cb->cb)(qstate, 1270178479Sjb response, cb->id, cb->cb_arg); 1271178479Sjb } 1272178479Sjb return 1; 1273178479Sjb} 1274178479Sjb 1275178479Sjbstruct edns_option* edns_opt_copy_region(struct edns_option* list, 1276178479Sjb struct regional* region) 1277178479Sjb{ 1278178479Sjb struct edns_option* result = NULL, *cur = NULL, *s; 1279178479Sjb while(list) { 1280178479Sjb /* copy edns option structure */ 1281178479Sjb s = regional_alloc_init(region, list, sizeof(*list)); 1282178479Sjb if(!s) return NULL; 1283178479Sjb s->next = NULL; 1284178479Sjb 1285178479Sjb /* copy option data */ 1286178479Sjb if(s->opt_data) { 1287178479Sjb s->opt_data = regional_alloc_init(region, s->opt_data, 1288178479Sjb s->opt_len); 1289178479Sjb if(!s->opt_data) 1290178479Sjb return NULL; 1291178479Sjb } 1292178479Sjb 1293178479Sjb /* link into list */ 1294178479Sjb if(cur) 1295178479Sjb cur->next = s; 1296178479Sjb else result = s; 1297178479Sjb cur = s; 1298178479Sjb 1299210767Srpaulo /* examine next element */ 1300210767Srpaulo list = list->next; 1301210767Srpaulo } 1302210767Srpaulo return result; 1303210767Srpaulo} 1304210767Srpaulo 1305210767Srpaulostruct edns_option* edns_opt_copy_filter_region(struct edns_option* list, 1306210767Srpaulo uint16_t* filter_list, size_t filter_list_len, struct regional* region) 1307210767Srpaulo{ 1308210767Srpaulo struct edns_option* result = NULL, *cur = NULL, *s; 1309210767Srpaulo size_t i; 1310210767Srpaulo while(list) { 1311210767Srpaulo for(i=0; i<filter_list_len; i++) 1312210767Srpaulo if(filter_list[i] == list->opt_code) goto found; 1313178479Sjb if(i == filter_list_len) goto next; 1314178479Sjbfound: 1315178479Sjb /* copy edns option structure */ 1316178479Sjb s = regional_alloc_init(region, list, sizeof(*list)); 1317178479Sjb if(!s) return NULL; 1318178479Sjb s->next = NULL; 1319178479Sjb 1320178479Sjb /* copy option data */ 1321178479Sjb if(s->opt_data) { 1322178479Sjb s->opt_data = regional_alloc_init(region, s->opt_data, 1323178479Sjb s->opt_len); 1324178479Sjb if(!s->opt_data) 1325178479Sjb return NULL; 1326178479Sjb } 1327237624Spfg 1328178479Sjb /* link into list */ 1329237624Spfg if(cur) 1330237624Spfg cur->next = s; 1331237624Spfg else result = s; 1332237624Spfg cur = s; 1333237624Spfg 1334237624Spfgnext: 1335237624Spfg /* examine next element */ 1336178479Sjb list = list->next; 1337178479Sjb } 1338178479Sjb return result; 1339178479Sjb} 1340178479Sjb 1341178479Sjbint edns_opt_compare(struct edns_option* p, struct edns_option* q) 1342178479Sjb{ 1343178479Sjb if(!p && !q) return 0; 1344178479Sjb if(!p) return -1; 1345178479Sjb if(!q) return 1; 1346178479Sjb log_assert(p && q); 1347178479Sjb if(p->opt_code != q->opt_code) 1348178479Sjb return (int)q->opt_code - (int)p->opt_code; 1349178479Sjb if(p->opt_len != q->opt_len) 1350178479Sjb return (int)q->opt_len - (int)p->opt_len; 1351178479Sjb if(p->opt_len != 0) 1352178479Sjb return memcmp(p->opt_data, q->opt_data, p->opt_len); 1353178479Sjb return 0; 1354178479Sjb} 1355178479Sjb 1356178479Sjbint edns_opt_list_compare(struct edns_option* p, struct edns_option* q) 1357178479Sjb{ 1358178479Sjb int r; 1359178479Sjb while(p && q) { 1360178479Sjb r = edns_opt_compare(p, q); 1361178479Sjb if(r != 0) 1362178479Sjb return r; 1363178479Sjb p = p->next; 1364178479Sjb q = q->next; 1365178479Sjb } 1366178479Sjb if(p || q) { 1367178479Sjb /* uneven length lists */ 1368178479Sjb if(p) return 1; 1369178479Sjb if(q) return -1; 1370178479Sjb } 1371178479Sjb return 0; 1372178479Sjb} 1373178479Sjb 1374178479Sjbvoid edns_opt_list_free(struct edns_option* list) 1375178479Sjb{ 1376178479Sjb struct edns_option* n; 1377178479Sjb while(list) { 1378178479Sjb free(list->opt_data); 1379178479Sjb n = list->next; 1380178479Sjb free(list); 1381178479Sjb list = n; 1382178479Sjb } 1383178479Sjb} 1384178479Sjb 1385178479Sjbstruct edns_option* edns_opt_copy_alloc(struct edns_option* list) 1386178479Sjb{ 1387178479Sjb struct edns_option* result = NULL, *cur = NULL, *s; 1388178479Sjb while(list) { 1389178479Sjb /* copy edns option structure */ 1390178479Sjb s = memdup(list, sizeof(*list)); 1391178479Sjb if(!s) { 1392178479Sjb edns_opt_list_free(result); 1393178479Sjb return NULL; 1394178479Sjb } 1395178479Sjb s->next = NULL; 1396178479Sjb 1397178479Sjb /* copy option data */ 1398178479Sjb if(s->opt_data) { 1399178479Sjb s->opt_data = memdup(s->opt_data, s->opt_len); 1400178479Sjb if(!s->opt_data) { 1401178479Sjb free(s); 1402178479Sjb edns_opt_list_free(result); 1403178479Sjb return NULL; 1404178479Sjb } 1405178479Sjb } 1406178479Sjb 1407178479Sjb /* link into list */ 1408178479Sjb if(cur) 1409178479Sjb cur->next = s; 1410178479Sjb else result = s; 1411178479Sjb cur = s; 1412178479Sjb 1413178479Sjb /* examine next element */ 1414178479Sjb list = list->next; 1415178479Sjb } 1416178479Sjb return result; 1417178479Sjb} 1418178479Sjb 1419178479Sjbstruct edns_option* edns_opt_list_find(struct edns_option* list, uint16_t code) 1420178479Sjb{ 1421178479Sjb struct edns_option* p; 1422178479Sjb for(p=list; p; p=p->next) { 1423178479Sjb if(p->opt_code == code) 1424178479Sjb return p; 1425178479Sjb } 1426178479Sjb return NULL; 1427178479Sjb} 1428178479Sjb