1ae8c6e27Sflorian /* 2ae8c6e27Sflorian * util/data/msgparse.c - parse wireformat DNS messages. 3ae8c6e27Sflorian * 4ae8c6e27Sflorian * Copyright (c) 2007, NLnet Labs. All rights reserved. 5ae8c6e27Sflorian * 6ae8c6e27Sflorian * This software is open source. 7ae8c6e27Sflorian * 8ae8c6e27Sflorian * Redistribution and use in source and binary forms, with or without 9ae8c6e27Sflorian * modification, are permitted provided that the following conditions 10ae8c6e27Sflorian * are met: 11ae8c6e27Sflorian * 12ae8c6e27Sflorian * Redistributions of source code must retain the above copyright notice, 13ae8c6e27Sflorian * this list of conditions and the following disclaimer. 14ae8c6e27Sflorian * 15ae8c6e27Sflorian * Redistributions in binary form must reproduce the above copyright notice, 16ae8c6e27Sflorian * this list of conditions and the following disclaimer in the documentation 17ae8c6e27Sflorian * and/or other materials provided with the distribution. 18ae8c6e27Sflorian * 19ae8c6e27Sflorian * Neither the name of the NLNET LABS nor the names of its contributors may 20ae8c6e27Sflorian * be used to endorse or promote products derived from this software without 21ae8c6e27Sflorian * specific prior written permission. 22ae8c6e27Sflorian * 23ae8c6e27Sflorian * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24ae8c6e27Sflorian * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25ae8c6e27Sflorian * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 26ae8c6e27Sflorian * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27ae8c6e27Sflorian * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28ae8c6e27Sflorian * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29ae8c6e27Sflorian * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30ae8c6e27Sflorian * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31ae8c6e27Sflorian * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32ae8c6e27Sflorian * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33ae8c6e27Sflorian * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34ae8c6e27Sflorian */ 35ae8c6e27Sflorian /** 36ae8c6e27Sflorian * \file 37ae8c6e27Sflorian * Routines for message parsing a packet buffer to a descriptive structure. 38ae8c6e27Sflorian */ 39ae8c6e27Sflorian #include "config.h" 40a1a7ba80Sflorian #include "util/config_file.h" 41ae8c6e27Sflorian #include "util/data/msgparse.h" 42ae8c6e27Sflorian #include "util/data/msgreply.h" 43ae8c6e27Sflorian #include "util/data/dname.h" 44ae8c6e27Sflorian #include "util/data/packed_rrset.h" 45a1a7ba80Sflorian #include "util/netevent.h" 46ae8c6e27Sflorian #include "util/storage/lookup3.h" 47ae8c6e27Sflorian #include "util/regional.h" 48d500c338Sflorian #include "util/rfc_1982.h" 49d500c338Sflorian #include "util/edns.h" 5054cc57acSflorian #include "util/net_help.h" 51ae8c6e27Sflorian #include "sldns/rrdef.h" 52ae8c6e27Sflorian #include "sldns/sbuffer.h" 53ae8c6e27Sflorian #include "sldns/parseutil.h" 54ae8c6e27Sflorian #include "sldns/wire2str.h" 55ae8c6e27Sflorian 56ae8c6e27Sflorian /** smart comparison of (compressed, valid) dnames from packet */ 57ae8c6e27Sflorian static int 58ae8c6e27Sflorian smart_compare(sldns_buffer* pkt, uint8_t* dnow, 59ae8c6e27Sflorian uint8_t* dprfirst, uint8_t* dprlast) 60ae8c6e27Sflorian { 61ae8c6e27Sflorian if(LABEL_IS_PTR(*dnow)) { 62ae8c6e27Sflorian /* ptr points to a previous dname */ 635a7d75e6Ssthen uint8_t* p; 645a7d75e6Ssthen if((size_t)PTR_OFFSET(dnow[0], dnow[1]) 655a7d75e6Ssthen >= sldns_buffer_limit(pkt)) 665a7d75e6Ssthen return -1; 675a7d75e6Ssthen p = sldns_buffer_at(pkt, PTR_OFFSET(dnow[0], dnow[1])); 68ae8c6e27Sflorian if( p == dprfirst || p == dprlast ) 69ae8c6e27Sflorian return 0; 70ae8c6e27Sflorian /* prev dname is also a ptr, both ptrs are the same. */ 71ae8c6e27Sflorian if(LABEL_IS_PTR(*dprlast) && 72ae8c6e27Sflorian dprlast[0] == dnow[0] && dprlast[1] == dnow[1]) 73ae8c6e27Sflorian return 0; 74ae8c6e27Sflorian } 75ae8c6e27Sflorian return dname_pkt_compare(pkt, dnow, dprlast); 76ae8c6e27Sflorian } 77ae8c6e27Sflorian 78ae8c6e27Sflorian /** 79ae8c6e27Sflorian * Allocate new rrset in region, fill with data. 80ae8c6e27Sflorian */ 81ae8c6e27Sflorian static struct rrset_parse* 82ae8c6e27Sflorian new_rrset(struct msg_parse* msg, uint8_t* dname, size_t dnamelen, 83ae8c6e27Sflorian uint16_t type, uint16_t dclass, hashvalue_type hash, 84ae8c6e27Sflorian uint32_t rrset_flags, sldns_pkt_section section, 85ae8c6e27Sflorian struct regional* region) 86ae8c6e27Sflorian { 87ae8c6e27Sflorian struct rrset_parse* p = regional_alloc(region, sizeof(*p)); 88ae8c6e27Sflorian if(!p) return NULL; 89ae8c6e27Sflorian p->rrset_bucket_next = msg->hashtable[hash & (PARSE_TABLE_SIZE-1)]; 90ae8c6e27Sflorian msg->hashtable[hash & (PARSE_TABLE_SIZE-1)] = p; 91ae8c6e27Sflorian p->rrset_all_next = 0; 92ae8c6e27Sflorian if(msg->rrset_last) 93ae8c6e27Sflorian msg->rrset_last->rrset_all_next = p; 94ae8c6e27Sflorian else msg->rrset_first = p; 95ae8c6e27Sflorian msg->rrset_last = p; 96ae8c6e27Sflorian p->hash = hash; 97ae8c6e27Sflorian p->section = section; 98ae8c6e27Sflorian p->dname = dname; 99ae8c6e27Sflorian p->dname_len = dnamelen; 100ae8c6e27Sflorian p->type = type; 101ae8c6e27Sflorian p->rrset_class = dclass; 102ae8c6e27Sflorian p->flags = rrset_flags; 103ae8c6e27Sflorian p->rr_count = 0; 104ae8c6e27Sflorian p->size = 0; 105ae8c6e27Sflorian p->rr_first = 0; 106ae8c6e27Sflorian p->rr_last = 0; 107ae8c6e27Sflorian p->rrsig_count = 0; 108ae8c6e27Sflorian p->rrsig_first = 0; 109ae8c6e27Sflorian p->rrsig_last = 0; 110ae8c6e27Sflorian return p; 111ae8c6e27Sflorian } 112ae8c6e27Sflorian 113ae8c6e27Sflorian /** See if next rrset is nsec at zone apex */ 114ae8c6e27Sflorian static int 115ae8c6e27Sflorian nsec_at_apex(sldns_buffer* pkt) 116ae8c6e27Sflorian { 117ae8c6e27Sflorian /* we are at ttl position in packet. */ 118ae8c6e27Sflorian size_t pos = sldns_buffer_position(pkt); 119ae8c6e27Sflorian uint16_t rdatalen; 120ae8c6e27Sflorian if(sldns_buffer_remaining(pkt) < 7) /* ttl+len+root */ 121ae8c6e27Sflorian return 0; /* eek! */ 122ae8c6e27Sflorian sldns_buffer_skip(pkt, 4); /* ttl */; 123ae8c6e27Sflorian rdatalen = sldns_buffer_read_u16(pkt); 124ae8c6e27Sflorian if(sldns_buffer_remaining(pkt) < rdatalen) { 125ae8c6e27Sflorian sldns_buffer_set_position(pkt, pos); 126ae8c6e27Sflorian return 0; /* parse error happens later */ 127ae8c6e27Sflorian } 128ae8c6e27Sflorian /* must validate the nsec next domain name format */ 129ae8c6e27Sflorian if(pkt_dname_len(pkt) == 0) { 130ae8c6e27Sflorian sldns_buffer_set_position(pkt, pos); 131ae8c6e27Sflorian return 0; /* parse error */ 132ae8c6e27Sflorian } 133ae8c6e27Sflorian 134ae8c6e27Sflorian /* see if SOA bit is set. */ 135ae8c6e27Sflorian if(sldns_buffer_position(pkt) < pos+4+rdatalen) { 136ae8c6e27Sflorian /* nsec type bitmap contains items */ 137ae8c6e27Sflorian uint8_t win, blen, bits; 138ae8c6e27Sflorian /* need: windownum, bitmap len, firstbyte */ 139ae8c6e27Sflorian if(sldns_buffer_position(pkt)+3 > pos+4+rdatalen) { 140ae8c6e27Sflorian sldns_buffer_set_position(pkt, pos); 141ae8c6e27Sflorian return 0; /* malformed nsec */ 142ae8c6e27Sflorian } 143ae8c6e27Sflorian win = sldns_buffer_read_u8(pkt); 144ae8c6e27Sflorian blen = sldns_buffer_read_u8(pkt); 145ae8c6e27Sflorian bits = sldns_buffer_read_u8(pkt); 146ae8c6e27Sflorian /* 0window always first window. bitlen >=1 or parse 147ae8c6e27Sflorian error really. bit 0x2 is SOA. */ 148ae8c6e27Sflorian if(win == 0 && blen >= 1 && (bits & 0x02)) { 149ae8c6e27Sflorian sldns_buffer_set_position(pkt, pos); 150ae8c6e27Sflorian return 1; 151ae8c6e27Sflorian } 152ae8c6e27Sflorian } 153ae8c6e27Sflorian 154ae8c6e27Sflorian sldns_buffer_set_position(pkt, pos); 155ae8c6e27Sflorian return 0; 156ae8c6e27Sflorian } 157ae8c6e27Sflorian 158ae8c6e27Sflorian /** Calculate rrset flags */ 159ae8c6e27Sflorian static uint32_t 160ae8c6e27Sflorian pkt_rrset_flags(sldns_buffer* pkt, uint16_t type, sldns_pkt_section sec) 161ae8c6e27Sflorian { 162ae8c6e27Sflorian uint32_t f = 0; 163ae8c6e27Sflorian if(type == LDNS_RR_TYPE_NSEC && nsec_at_apex(pkt)) { 164ae8c6e27Sflorian f |= PACKED_RRSET_NSEC_AT_APEX; 165ae8c6e27Sflorian } else if(type == LDNS_RR_TYPE_SOA && sec == LDNS_SECTION_AUTHORITY) { 166ae8c6e27Sflorian f |= PACKED_RRSET_SOA_NEG; 167ae8c6e27Sflorian } 168ae8c6e27Sflorian return f; 169ae8c6e27Sflorian } 170ae8c6e27Sflorian 171ae8c6e27Sflorian hashvalue_type 172ae8c6e27Sflorian pkt_hash_rrset(sldns_buffer* pkt, uint8_t* dname, uint16_t type, 173ae8c6e27Sflorian uint16_t dclass, uint32_t rrset_flags) 174ae8c6e27Sflorian { 175ae8c6e27Sflorian /* note this MUST be identical to rrset_key_hash in packed_rrset.c */ 176ae8c6e27Sflorian /* this routine handles compressed names */ 177ae8c6e27Sflorian hashvalue_type h = 0xab; 178ae8c6e27Sflorian h = dname_pkt_hash(pkt, dname, h); 179ae8c6e27Sflorian h = hashlittle(&type, sizeof(type), h); /* host order */ 180ae8c6e27Sflorian h = hashlittle(&dclass, sizeof(dclass), h); /* netw order */ 181ae8c6e27Sflorian h = hashlittle(&rrset_flags, sizeof(uint32_t), h); 182ae8c6e27Sflorian return h; 183ae8c6e27Sflorian } 184ae8c6e27Sflorian 185ae8c6e27Sflorian /** create partial dname hash for rrset hash */ 186ae8c6e27Sflorian static hashvalue_type 187ae8c6e27Sflorian pkt_hash_rrset_first(sldns_buffer* pkt, uint8_t* dname) 188ae8c6e27Sflorian { 189ae8c6e27Sflorian /* works together with pkt_hash_rrset_rest */ 190ae8c6e27Sflorian /* note this MUST be identical to rrset_key_hash in packed_rrset.c */ 191ae8c6e27Sflorian /* this routine handles compressed names */ 192ae8c6e27Sflorian hashvalue_type h = 0xab; 193ae8c6e27Sflorian h = dname_pkt_hash(pkt, dname, h); 194ae8c6e27Sflorian return h; 195ae8c6e27Sflorian } 196ae8c6e27Sflorian 197ae8c6e27Sflorian /** create a rrset hash from a partial dname hash */ 198ae8c6e27Sflorian static hashvalue_type 199ae8c6e27Sflorian pkt_hash_rrset_rest(hashvalue_type dname_h, uint16_t type, uint16_t dclass, 200ae8c6e27Sflorian uint32_t rrset_flags) 201ae8c6e27Sflorian { 202ae8c6e27Sflorian /* works together with pkt_hash_rrset_first */ 203ae8c6e27Sflorian /* note this MUST be identical to rrset_key_hash in packed_rrset.c */ 204ae8c6e27Sflorian hashvalue_type h; 205ae8c6e27Sflorian h = hashlittle(&type, sizeof(type), dname_h); /* host order */ 206ae8c6e27Sflorian h = hashlittle(&dclass, sizeof(dclass), h); /* netw order */ 207ae8c6e27Sflorian h = hashlittle(&rrset_flags, sizeof(uint32_t), h); 208ae8c6e27Sflorian return h; 209ae8c6e27Sflorian } 210ae8c6e27Sflorian 211ae8c6e27Sflorian /** compare rrset_parse with data */ 212ae8c6e27Sflorian static int 213ae8c6e27Sflorian rrset_parse_equals(struct rrset_parse* p, sldns_buffer* pkt, hashvalue_type h, 214ae8c6e27Sflorian uint32_t rrset_flags, uint8_t* dname, size_t dnamelen, 215ae8c6e27Sflorian uint16_t type, uint16_t dclass) 216ae8c6e27Sflorian { 217ae8c6e27Sflorian if(p->hash == h && p->dname_len == dnamelen && p->type == type && 218ae8c6e27Sflorian p->rrset_class == dclass && p->flags == rrset_flags && 219ae8c6e27Sflorian dname_pkt_compare(pkt, dname, p->dname) == 0) 220ae8c6e27Sflorian return 1; 221ae8c6e27Sflorian return 0; 222ae8c6e27Sflorian } 223ae8c6e27Sflorian 224ae8c6e27Sflorian 225ae8c6e27Sflorian struct rrset_parse* 226ae8c6e27Sflorian msgparse_hashtable_lookup(struct msg_parse* msg, sldns_buffer* pkt, 227ae8c6e27Sflorian hashvalue_type h, uint32_t rrset_flags, uint8_t* dname, 228ae8c6e27Sflorian size_t dnamelen, uint16_t type, uint16_t dclass) 229ae8c6e27Sflorian { 230ae8c6e27Sflorian struct rrset_parse* p = msg->hashtable[h & (PARSE_TABLE_SIZE-1)]; 231ae8c6e27Sflorian while(p) { 232ae8c6e27Sflorian if(rrset_parse_equals(p, pkt, h, rrset_flags, dname, dnamelen, 233ae8c6e27Sflorian type, dclass)) 234ae8c6e27Sflorian return p; 235ae8c6e27Sflorian p = p->rrset_bucket_next; 236ae8c6e27Sflorian } 237ae8c6e27Sflorian return NULL; 238ae8c6e27Sflorian } 239ae8c6e27Sflorian 240ae8c6e27Sflorian /** return type networkformat that rrsig in packet covers */ 241ae8c6e27Sflorian static int 242ae8c6e27Sflorian pkt_rrsig_covered(sldns_buffer* pkt, uint8_t* here, uint16_t* type) 243ae8c6e27Sflorian { 244ae8c6e27Sflorian size_t pos = sldns_buffer_position(pkt); 245ae8c6e27Sflorian sldns_buffer_set_position(pkt, (size_t)(here-sldns_buffer_begin(pkt))); 246ae8c6e27Sflorian /* ttl + len + size of small rrsig(rootlabel, no signature) */ 247ae8c6e27Sflorian if(sldns_buffer_remaining(pkt) < 4+2+19) 248ae8c6e27Sflorian return 0; 249ae8c6e27Sflorian sldns_buffer_skip(pkt, 4); /* ttl */ 250ae8c6e27Sflorian if(sldns_buffer_read_u16(pkt) < 19) /* too short */ { 251ae8c6e27Sflorian sldns_buffer_set_position(pkt, pos); 252ae8c6e27Sflorian return 0; 253ae8c6e27Sflorian } 254ae8c6e27Sflorian *type = sldns_buffer_read_u16(pkt); 255ae8c6e27Sflorian sldns_buffer_set_position(pkt, pos); 256ae8c6e27Sflorian return 1; 257ae8c6e27Sflorian } 258ae8c6e27Sflorian 259ae8c6e27Sflorian /** true if covered type equals prevtype */ 260ae8c6e27Sflorian static int 261ae8c6e27Sflorian pkt_rrsig_covered_equals(sldns_buffer* pkt, uint8_t* here, uint16_t type) 262ae8c6e27Sflorian { 263ae8c6e27Sflorian uint16_t t; 264ae8c6e27Sflorian if(pkt_rrsig_covered(pkt, here, &t) && t == type) 265ae8c6e27Sflorian return 1; 266ae8c6e27Sflorian return 0; 267ae8c6e27Sflorian } 268ae8c6e27Sflorian 269ae8c6e27Sflorian void 270ae8c6e27Sflorian msgparse_bucket_remove(struct msg_parse* msg, struct rrset_parse* rrset) 271ae8c6e27Sflorian { 272ae8c6e27Sflorian struct rrset_parse** p; 273ae8c6e27Sflorian p = &msg->hashtable[ rrset->hash & (PARSE_TABLE_SIZE-1) ]; 274ae8c6e27Sflorian while(*p) { 275ae8c6e27Sflorian if(*p == rrset) { 276ae8c6e27Sflorian *p = rrset->rrset_bucket_next; 277ae8c6e27Sflorian return; 278ae8c6e27Sflorian } 279ae8c6e27Sflorian p = &( (*p)->rrset_bucket_next ); 280ae8c6e27Sflorian } 281ae8c6e27Sflorian } 282ae8c6e27Sflorian 283ae8c6e27Sflorian /** change section of rrset from previous to current section */ 284ae8c6e27Sflorian static void 285ae8c6e27Sflorian change_section(struct msg_parse* msg, struct rrset_parse* rrset, 286ae8c6e27Sflorian sldns_pkt_section section) 287ae8c6e27Sflorian { 288ae8c6e27Sflorian struct rrset_parse *p, *prev; 289ae8c6e27Sflorian /* remove from list */ 290ae8c6e27Sflorian if(section == rrset->section) 291ae8c6e27Sflorian return; 292ae8c6e27Sflorian p = msg->rrset_first; 293ae8c6e27Sflorian prev = 0; 294ae8c6e27Sflorian while(p) { 295ae8c6e27Sflorian if(p == rrset) { 296ae8c6e27Sflorian if(prev) prev->rrset_all_next = p->rrset_all_next; 297ae8c6e27Sflorian else msg->rrset_first = p->rrset_all_next; 298ae8c6e27Sflorian if(msg->rrset_last == rrset) 299ae8c6e27Sflorian msg->rrset_last = prev; 300ae8c6e27Sflorian break; 301ae8c6e27Sflorian } 302ae8c6e27Sflorian prev = p; 303ae8c6e27Sflorian p = p->rrset_all_next; 304ae8c6e27Sflorian } 305ae8c6e27Sflorian /* remove from count */ 306ae8c6e27Sflorian switch(rrset->section) { 307ae8c6e27Sflorian case LDNS_SECTION_ANSWER: msg->an_rrsets--; break; 308ae8c6e27Sflorian case LDNS_SECTION_AUTHORITY: msg->ns_rrsets--; break; 309ae8c6e27Sflorian case LDNS_SECTION_ADDITIONAL: msg->ar_rrsets--; break; 310ae8c6e27Sflorian default: log_assert(0); 311ae8c6e27Sflorian } 312ae8c6e27Sflorian /* insert at end of list */ 313ae8c6e27Sflorian rrset->rrset_all_next = 0; 314ae8c6e27Sflorian if(msg->rrset_last) 315ae8c6e27Sflorian msg->rrset_last->rrset_all_next = rrset; 316ae8c6e27Sflorian else msg->rrset_first = rrset; 317ae8c6e27Sflorian msg->rrset_last = rrset; 318ae8c6e27Sflorian /* up count of new section */ 319ae8c6e27Sflorian switch(section) { 320ae8c6e27Sflorian case LDNS_SECTION_AUTHORITY: msg->ns_rrsets++; break; 321ae8c6e27Sflorian case LDNS_SECTION_ADDITIONAL: msg->ar_rrsets++; break; 322ae8c6e27Sflorian default: log_assert(0); 323ae8c6e27Sflorian } 324ae8c6e27Sflorian rrset->section = section; 325ae8c6e27Sflorian } 326ae8c6e27Sflorian 327ae8c6e27Sflorian /** see if rrset of type RRSIG contains sig over given type */ 328ae8c6e27Sflorian static int 329ae8c6e27Sflorian rrset_has_sigover(sldns_buffer* pkt, struct rrset_parse* rrset, uint16_t type, 330ae8c6e27Sflorian int* hasother) 331ae8c6e27Sflorian { 332ae8c6e27Sflorian int res = 0; 333ae8c6e27Sflorian struct rr_parse* rr = rrset->rr_first; 334ae8c6e27Sflorian log_assert( rrset->type == LDNS_RR_TYPE_RRSIG ); 335ae8c6e27Sflorian while(rr) { 336ae8c6e27Sflorian if(pkt_rrsig_covered_equals(pkt, rr->ttl_data, type)) 337ae8c6e27Sflorian res = 1; 338ae8c6e27Sflorian else *hasother = 1; 339ae8c6e27Sflorian rr = rr->next; 340ae8c6e27Sflorian } 341ae8c6e27Sflorian return res; 342ae8c6e27Sflorian } 343ae8c6e27Sflorian 344ae8c6e27Sflorian /** move rrsigs from sigset to dataset */ 345ae8c6e27Sflorian static int 346ae8c6e27Sflorian moveover_rrsigs(sldns_buffer* pkt, struct regional* region, 347ae8c6e27Sflorian struct rrset_parse* sigset, struct rrset_parse* dataset, int duplicate) 348ae8c6e27Sflorian { 349ae8c6e27Sflorian struct rr_parse* sig = sigset->rr_first; 350ae8c6e27Sflorian struct rr_parse* prev = NULL; 351ae8c6e27Sflorian struct rr_parse* insert; 352ae8c6e27Sflorian struct rr_parse* nextsig; 353ae8c6e27Sflorian while(sig) { 354ae8c6e27Sflorian nextsig = sig->next; 355ae8c6e27Sflorian if(pkt_rrsig_covered_equals(pkt, sig->ttl_data, 356ae8c6e27Sflorian dataset->type)) { 357ae8c6e27Sflorian if(duplicate) { 358ae8c6e27Sflorian /* new */ 359ae8c6e27Sflorian insert = (struct rr_parse*)regional_alloc( 360ae8c6e27Sflorian region, sizeof(struct rr_parse)); 361ae8c6e27Sflorian if(!insert) return 0; 362ae8c6e27Sflorian insert->outside_packet = 0; 363ae8c6e27Sflorian insert->ttl_data = sig->ttl_data; 364ae8c6e27Sflorian insert->size = sig->size; 365ae8c6e27Sflorian /* prev not used */ 366ae8c6e27Sflorian } else { 367ae8c6e27Sflorian /* remove from sigset */ 368ae8c6e27Sflorian if(prev) prev->next = sig->next; 369ae8c6e27Sflorian else sigset->rr_first = sig->next; 370ae8c6e27Sflorian if(sigset->rr_last == sig) 371ae8c6e27Sflorian sigset->rr_last = prev; 372ae8c6e27Sflorian sigset->rr_count--; 373ae8c6e27Sflorian sigset->size -= sig->size; 374ae8c6e27Sflorian insert = sig; 375ae8c6e27Sflorian /* prev not changed */ 376ae8c6e27Sflorian } 377ae8c6e27Sflorian /* add to dataset */ 378ae8c6e27Sflorian dataset->rrsig_count++; 379ae8c6e27Sflorian insert->next = 0; 380ae8c6e27Sflorian if(dataset->rrsig_last) 381ae8c6e27Sflorian dataset->rrsig_last->next = insert; 382ae8c6e27Sflorian else dataset->rrsig_first = insert; 383ae8c6e27Sflorian dataset->rrsig_last = insert; 384ae8c6e27Sflorian dataset->size += insert->size; 385ae8c6e27Sflorian } else { 386ae8c6e27Sflorian prev = sig; 387ae8c6e27Sflorian } 388ae8c6e27Sflorian sig = nextsig; 389ae8c6e27Sflorian } 390ae8c6e27Sflorian return 1; 391ae8c6e27Sflorian } 392ae8c6e27Sflorian 393ae8c6e27Sflorian /** change an rrsig rrset for use as data rrset */ 394ae8c6e27Sflorian static struct rrset_parse* 395ae8c6e27Sflorian change_rrsig_rrset(struct rrset_parse* sigset, struct msg_parse* msg, 396ae8c6e27Sflorian sldns_buffer* pkt, uint16_t datatype, uint32_t rrset_flags, 397ae8c6e27Sflorian int hasother, sldns_pkt_section section, struct regional* region) 398ae8c6e27Sflorian { 399ae8c6e27Sflorian struct rrset_parse* dataset = sigset; 400ae8c6e27Sflorian hashvalue_type hash = pkt_hash_rrset(pkt, sigset->dname, datatype, 401ae8c6e27Sflorian sigset->rrset_class, rrset_flags); 402ae8c6e27Sflorian log_assert( sigset->type == LDNS_RR_TYPE_RRSIG ); 403ae8c6e27Sflorian log_assert( datatype != LDNS_RR_TYPE_RRSIG ); 404ae8c6e27Sflorian if(hasother) { 405ae8c6e27Sflorian /* need to make new rrset to hold data type */ 406ae8c6e27Sflorian dataset = new_rrset(msg, sigset->dname, sigset->dname_len, 407ae8c6e27Sflorian datatype, sigset->rrset_class, hash, rrset_flags, 408ae8c6e27Sflorian section, region); 409ae8c6e27Sflorian if(!dataset) 410ae8c6e27Sflorian return NULL; 411ae8c6e27Sflorian switch(section) { 412ae8c6e27Sflorian case LDNS_SECTION_ANSWER: msg->an_rrsets++; break; 413ae8c6e27Sflorian case LDNS_SECTION_AUTHORITY: msg->ns_rrsets++; break; 414ae8c6e27Sflorian case LDNS_SECTION_ADDITIONAL: msg->ar_rrsets++; break; 415ae8c6e27Sflorian default: log_assert(0); 416ae8c6e27Sflorian } 417ae8c6e27Sflorian if(!moveover_rrsigs(pkt, region, sigset, dataset, 418ae8c6e27Sflorian msg->qtype == LDNS_RR_TYPE_RRSIG || 419ae8c6e27Sflorian (msg->qtype == LDNS_RR_TYPE_ANY && 420ae8c6e27Sflorian section != LDNS_SECTION_ANSWER) )) 421ae8c6e27Sflorian return NULL; 422ae8c6e27Sflorian return dataset; 423ae8c6e27Sflorian } 424ae8c6e27Sflorian /* changeover the type of the rrset to data set */ 425ae8c6e27Sflorian msgparse_bucket_remove(msg, dataset); 426ae8c6e27Sflorian /* insert into new hash bucket */ 427ae8c6e27Sflorian dataset->rrset_bucket_next = msg->hashtable[hash&(PARSE_TABLE_SIZE-1)]; 428ae8c6e27Sflorian msg->hashtable[hash&(PARSE_TABLE_SIZE-1)] = dataset; 429ae8c6e27Sflorian dataset->hash = hash; 430ae8c6e27Sflorian /* use section of data item for result */ 431ae8c6e27Sflorian change_section(msg, dataset, section); 432ae8c6e27Sflorian dataset->type = datatype; 433ae8c6e27Sflorian dataset->flags = rrset_flags; 434ae8c6e27Sflorian dataset->rrsig_count += dataset->rr_count; 435ae8c6e27Sflorian dataset->rr_count = 0; 436ae8c6e27Sflorian /* move sigs to end of siglist */ 437ae8c6e27Sflorian if(dataset->rrsig_last) 438ae8c6e27Sflorian dataset->rrsig_last->next = dataset->rr_first; 439ae8c6e27Sflorian else dataset->rrsig_first = dataset->rr_first; 440ae8c6e27Sflorian dataset->rrsig_last = dataset->rr_last; 441ae8c6e27Sflorian dataset->rr_first = 0; 442ae8c6e27Sflorian dataset->rr_last = 0; 443ae8c6e27Sflorian return dataset; 444ae8c6e27Sflorian } 445ae8c6e27Sflorian 446ae8c6e27Sflorian /** Find rrset. If equal to previous it is fast. hash if not so. 447ae8c6e27Sflorian * @param msg: the message with hash table. 448ae8c6e27Sflorian * @param pkt: the packet in wireformat (needed for compression ptrs). 449ae8c6e27Sflorian * @param dname: pointer to start of dname (compressed) in packet. 450ae8c6e27Sflorian * @param dnamelen: uncompressed wirefmt length of dname. 451ae8c6e27Sflorian * @param type: type of current rr. 452ae8c6e27Sflorian * @param dclass: class of current rr. 453ae8c6e27Sflorian * @param hash: hash value is returned if the rrset could not be found. 454ae8c6e27Sflorian * @param rrset_flags: is returned if the rrset could not be found. 455ae8c6e27Sflorian * @param prev_dname_first: dname of last seen RR. First seen dname. 456ae8c6e27Sflorian * @param prev_dname_last: dname of last seen RR. Last seen dname. 457ae8c6e27Sflorian * @param prev_dnamelen: dname len of last seen RR. 458ae8c6e27Sflorian * @param prev_type: type of last seen RR. 459ae8c6e27Sflorian * @param prev_dclass: class of last seen RR. 460ae8c6e27Sflorian * @param rrset_prev: last seen RRset. 461ae8c6e27Sflorian * @param section: the current section in the packet. 462ae8c6e27Sflorian * @param region: used to allocate temporary parsing data. 463ae8c6e27Sflorian * @return 0 on out of memory. 464ae8c6e27Sflorian */ 465ae8c6e27Sflorian static int 466ae8c6e27Sflorian find_rrset(struct msg_parse* msg, sldns_buffer* pkt, uint8_t* dname, 467ae8c6e27Sflorian size_t dnamelen, uint16_t type, uint16_t dclass, hashvalue_type* hash, 468ae8c6e27Sflorian uint32_t* rrset_flags, 469ae8c6e27Sflorian uint8_t** prev_dname_first, uint8_t** prev_dname_last, 470ae8c6e27Sflorian size_t* prev_dnamelen, uint16_t* prev_type, 471ae8c6e27Sflorian uint16_t* prev_dclass, struct rrset_parse** rrset_prev, 472ae8c6e27Sflorian sldns_pkt_section section, struct regional* region) 473ae8c6e27Sflorian { 474ae8c6e27Sflorian hashvalue_type dname_h = pkt_hash_rrset_first(pkt, dname); 475ae8c6e27Sflorian uint16_t covtype; 476ae8c6e27Sflorian if(*rrset_prev) { 477ae8c6e27Sflorian /* check if equal to previous item */ 478ae8c6e27Sflorian if(type == *prev_type && dclass == *prev_dclass && 479ae8c6e27Sflorian dnamelen == *prev_dnamelen && 480ae8c6e27Sflorian smart_compare(pkt, dname, *prev_dname_first, 481ae8c6e27Sflorian *prev_dname_last) == 0 && 482ae8c6e27Sflorian type != LDNS_RR_TYPE_RRSIG) { 483ae8c6e27Sflorian /* same as previous */ 484ae8c6e27Sflorian *prev_dname_last = dname; 485ae8c6e27Sflorian return 1; 486ae8c6e27Sflorian } 487ae8c6e27Sflorian /* check if rrsig over previous item */ 488ae8c6e27Sflorian if(type == LDNS_RR_TYPE_RRSIG && dclass == *prev_dclass && 489ae8c6e27Sflorian pkt_rrsig_covered_equals(pkt, sldns_buffer_current(pkt), 490ae8c6e27Sflorian *prev_type) && 491ae8c6e27Sflorian smart_compare(pkt, dname, *prev_dname_first, 492ae8c6e27Sflorian *prev_dname_last) == 0) { 493ae8c6e27Sflorian /* covers previous */ 494ae8c6e27Sflorian *prev_dname_last = dname; 495ae8c6e27Sflorian return 1; 496ae8c6e27Sflorian } 497ae8c6e27Sflorian } 498ae8c6e27Sflorian /* find by hashing and lookup in hashtable */ 499ae8c6e27Sflorian *rrset_flags = pkt_rrset_flags(pkt, type, section); 500ae8c6e27Sflorian 501ae8c6e27Sflorian /* if rrsig - try to lookup matching data set first */ 502ae8c6e27Sflorian if(type == LDNS_RR_TYPE_RRSIG && pkt_rrsig_covered(pkt, 503ae8c6e27Sflorian sldns_buffer_current(pkt), &covtype)) { 504ae8c6e27Sflorian *hash = pkt_hash_rrset_rest(dname_h, covtype, dclass, 505ae8c6e27Sflorian *rrset_flags); 506ae8c6e27Sflorian *rrset_prev = msgparse_hashtable_lookup(msg, pkt, *hash, 507ae8c6e27Sflorian *rrset_flags, dname, dnamelen, covtype, dclass); 508ae8c6e27Sflorian if(!*rrset_prev && covtype == LDNS_RR_TYPE_NSEC) { 509ae8c6e27Sflorian /* if NSEC try with NSEC apex bit twiddled */ 510ae8c6e27Sflorian *rrset_flags ^= PACKED_RRSET_NSEC_AT_APEX; 511ae8c6e27Sflorian *hash = pkt_hash_rrset_rest(dname_h, covtype, dclass, 512ae8c6e27Sflorian *rrset_flags); 513ae8c6e27Sflorian *rrset_prev = msgparse_hashtable_lookup(msg, pkt, 514ae8c6e27Sflorian *hash, *rrset_flags, dname, dnamelen, covtype, 515ae8c6e27Sflorian dclass); 516ae8c6e27Sflorian if(!*rrset_prev) /* untwiddle if not found */ 517ae8c6e27Sflorian *rrset_flags ^= PACKED_RRSET_NSEC_AT_APEX; 518ae8c6e27Sflorian } 519ae8c6e27Sflorian if(!*rrset_prev && covtype == LDNS_RR_TYPE_SOA) { 520ae8c6e27Sflorian /* if SOA try with SOA neg flag twiddled */ 521ae8c6e27Sflorian *rrset_flags ^= PACKED_RRSET_SOA_NEG; 522ae8c6e27Sflorian *hash = pkt_hash_rrset_rest(dname_h, covtype, dclass, 523ae8c6e27Sflorian *rrset_flags); 524ae8c6e27Sflorian *rrset_prev = msgparse_hashtable_lookup(msg, pkt, 525ae8c6e27Sflorian *hash, *rrset_flags, dname, dnamelen, covtype, 526ae8c6e27Sflorian dclass); 527ae8c6e27Sflorian if(!*rrset_prev) /* untwiddle if not found */ 528ae8c6e27Sflorian *rrset_flags ^= PACKED_RRSET_SOA_NEG; 529ae8c6e27Sflorian } 530ae8c6e27Sflorian if(*rrset_prev) { 531ae8c6e27Sflorian *prev_dname_first = (*rrset_prev)->dname; 532ae8c6e27Sflorian *prev_dname_last = dname; 533ae8c6e27Sflorian *prev_dnamelen = dnamelen; 534ae8c6e27Sflorian *prev_type = covtype; 535ae8c6e27Sflorian *prev_dclass = dclass; 536ae8c6e27Sflorian return 1; 537ae8c6e27Sflorian } 538ae8c6e27Sflorian } 539ae8c6e27Sflorian if(type != LDNS_RR_TYPE_RRSIG) { 540ae8c6e27Sflorian int hasother = 0; 541ae8c6e27Sflorian /* find matching rrsig */ 542ae8c6e27Sflorian *hash = pkt_hash_rrset_rest(dname_h, LDNS_RR_TYPE_RRSIG, 543ae8c6e27Sflorian dclass, 0); 544ae8c6e27Sflorian *rrset_prev = msgparse_hashtable_lookup(msg, pkt, *hash, 545ae8c6e27Sflorian 0, dname, dnamelen, LDNS_RR_TYPE_RRSIG, 546ae8c6e27Sflorian dclass); 547ae8c6e27Sflorian if(*rrset_prev && rrset_has_sigover(pkt, *rrset_prev, type, 548ae8c6e27Sflorian &hasother)) { 549ae8c6e27Sflorian /* yes! */ 550ae8c6e27Sflorian *prev_dname_first = (*rrset_prev)->dname; 551ae8c6e27Sflorian *prev_dname_last = dname; 552ae8c6e27Sflorian *prev_dnamelen = dnamelen; 553ae8c6e27Sflorian *prev_type = type; 554ae8c6e27Sflorian *prev_dclass = dclass; 555ae8c6e27Sflorian *rrset_prev = change_rrsig_rrset(*rrset_prev, msg, 556ae8c6e27Sflorian pkt, type, *rrset_flags, hasother, section, 557ae8c6e27Sflorian region); 558ae8c6e27Sflorian if(!*rrset_prev) return 0; 559ae8c6e27Sflorian return 1; 560ae8c6e27Sflorian } 561ae8c6e27Sflorian } 562ae8c6e27Sflorian 563ae8c6e27Sflorian *hash = pkt_hash_rrset_rest(dname_h, type, dclass, *rrset_flags); 564ae8c6e27Sflorian *rrset_prev = msgparse_hashtable_lookup(msg, pkt, *hash, *rrset_flags, 565ae8c6e27Sflorian dname, dnamelen, type, dclass); 566ae8c6e27Sflorian if(*rrset_prev) 567ae8c6e27Sflorian *prev_dname_first = (*rrset_prev)->dname; 568ae8c6e27Sflorian else *prev_dname_first = dname; 569ae8c6e27Sflorian *prev_dname_last = dname; 570ae8c6e27Sflorian *prev_dnamelen = dnamelen; 571ae8c6e27Sflorian *prev_type = type; 572ae8c6e27Sflorian *prev_dclass = dclass; 573ae8c6e27Sflorian return 1; 574ae8c6e27Sflorian } 575ae8c6e27Sflorian 576ae8c6e27Sflorian /** 577ae8c6e27Sflorian * Parse query section. 578ae8c6e27Sflorian * @param pkt: packet, position at call must be at start of query section. 579ae8c6e27Sflorian * at end position is after query section. 580ae8c6e27Sflorian * @param msg: store results here. 581ae8c6e27Sflorian * @return: 0 if OK, or rcode on error. 582ae8c6e27Sflorian */ 583ae8c6e27Sflorian static int 584ae8c6e27Sflorian parse_query_section(sldns_buffer* pkt, struct msg_parse* msg) 585ae8c6e27Sflorian { 586ae8c6e27Sflorian if(msg->qdcount == 0) 587ae8c6e27Sflorian return 0; 588ae8c6e27Sflorian if(msg->qdcount > 1) 589ae8c6e27Sflorian return LDNS_RCODE_FORMERR; 590ae8c6e27Sflorian log_assert(msg->qdcount == 1); 591ae8c6e27Sflorian if(sldns_buffer_remaining(pkt) <= 0) 592ae8c6e27Sflorian return LDNS_RCODE_FORMERR; 593ae8c6e27Sflorian msg->qname = sldns_buffer_current(pkt); 594ae8c6e27Sflorian if((msg->qname_len = pkt_dname_len(pkt)) == 0) 595ae8c6e27Sflorian return LDNS_RCODE_FORMERR; 596ae8c6e27Sflorian if(sldns_buffer_remaining(pkt) < sizeof(uint16_t)*2) 597ae8c6e27Sflorian return LDNS_RCODE_FORMERR; 598ae8c6e27Sflorian msg->qtype = sldns_buffer_read_u16(pkt); 599ae8c6e27Sflorian msg->qclass = sldns_buffer_read_u16(pkt); 600ae8c6e27Sflorian return 0; 601ae8c6e27Sflorian } 602ae8c6e27Sflorian 603ae8c6e27Sflorian size_t 604ae8c6e27Sflorian get_rdf_size(sldns_rdf_type rdf) 605ae8c6e27Sflorian { 606ae8c6e27Sflorian switch(rdf) { 607ae8c6e27Sflorian case LDNS_RDF_TYPE_CLASS: 608ae8c6e27Sflorian case LDNS_RDF_TYPE_ALG: 609ae8c6e27Sflorian case LDNS_RDF_TYPE_INT8: 610ae8c6e27Sflorian return 1; 611ae8c6e27Sflorian break; 612ae8c6e27Sflorian case LDNS_RDF_TYPE_INT16: 613ae8c6e27Sflorian case LDNS_RDF_TYPE_TYPE: 614ae8c6e27Sflorian case LDNS_RDF_TYPE_CERT_ALG: 615ae8c6e27Sflorian return 2; 616ae8c6e27Sflorian break; 617ae8c6e27Sflorian case LDNS_RDF_TYPE_INT32: 618ae8c6e27Sflorian case LDNS_RDF_TYPE_TIME: 619ae8c6e27Sflorian case LDNS_RDF_TYPE_A: 620ae8c6e27Sflorian case LDNS_RDF_TYPE_PERIOD: 621ae8c6e27Sflorian return 4; 622ae8c6e27Sflorian break; 623ae8c6e27Sflorian case LDNS_RDF_TYPE_TSIGTIME: 624ae8c6e27Sflorian return 6; 625ae8c6e27Sflorian break; 626ae8c6e27Sflorian case LDNS_RDF_TYPE_AAAA: 627ae8c6e27Sflorian return 16; 628ae8c6e27Sflorian break; 629ae8c6e27Sflorian default: 630ae8c6e27Sflorian log_assert(0); /* add type above */ 631ae8c6e27Sflorian /* only types that appear before a domain * 632ae8c6e27Sflorian * name are needed. rest is simply copied. */ 633ae8c6e27Sflorian } 634ae8c6e27Sflorian return 0; 635ae8c6e27Sflorian } 636ae8c6e27Sflorian 637ae8c6e27Sflorian /** calculate the size of one rr */ 638ae8c6e27Sflorian static int 639ae8c6e27Sflorian calc_size(sldns_buffer* pkt, uint16_t type, struct rr_parse* rr) 640ae8c6e27Sflorian { 641ae8c6e27Sflorian const sldns_rr_descriptor* desc; 642ae8c6e27Sflorian uint16_t pkt_len; /* length of rr inside the packet */ 643ae8c6e27Sflorian rr->size = sizeof(uint16_t); /* the rdatalen */ 644ae8c6e27Sflorian sldns_buffer_skip(pkt, 4); /* skip ttl */ 645ae8c6e27Sflorian pkt_len = sldns_buffer_read_u16(pkt); 646ae8c6e27Sflorian if(sldns_buffer_remaining(pkt) < pkt_len) 647ae8c6e27Sflorian return 0; 648ae8c6e27Sflorian desc = sldns_rr_descript(type); 649ae8c6e27Sflorian if(pkt_len > 0 && desc && desc->_dname_count > 0) { 650ae8c6e27Sflorian int count = (int)desc->_dname_count; 651ae8c6e27Sflorian int rdf = 0; 652ae8c6e27Sflorian size_t len; 653ae8c6e27Sflorian size_t oldpos; 654ae8c6e27Sflorian /* skip first part. */ 655ae8c6e27Sflorian while(pkt_len > 0 && count) { 656ae8c6e27Sflorian switch(desc->_wireformat[rdf]) { 657ae8c6e27Sflorian case LDNS_RDF_TYPE_DNAME: 658ae8c6e27Sflorian /* decompress every domain name */ 659ae8c6e27Sflorian oldpos = sldns_buffer_position(pkt); 660ae8c6e27Sflorian if((len = pkt_dname_len(pkt)) == 0) 661ae8c6e27Sflorian return 0; /* malformed dname */ 662ae8c6e27Sflorian if(sldns_buffer_position(pkt)-oldpos > pkt_len) 663ae8c6e27Sflorian return 0; /* dname exceeds rdata */ 664ae8c6e27Sflorian pkt_len -= sldns_buffer_position(pkt)-oldpos; 665ae8c6e27Sflorian rr->size += len; 666ae8c6e27Sflorian count--; 667ae8c6e27Sflorian len = 0; 668ae8c6e27Sflorian break; 669ae8c6e27Sflorian case LDNS_RDF_TYPE_STR: 670ae8c6e27Sflorian if(pkt_len < 1) { 671ae8c6e27Sflorian /* NOTREACHED, due to 'while(>0)' */ 672ae8c6e27Sflorian return 0; /* len byte exceeds rdata */ 673ae8c6e27Sflorian } 674ae8c6e27Sflorian len = sldns_buffer_current(pkt)[0] + 1; 675ae8c6e27Sflorian break; 676ae8c6e27Sflorian default: 677ae8c6e27Sflorian len = get_rdf_size(desc->_wireformat[rdf]); 678ae8c6e27Sflorian } 679ae8c6e27Sflorian if(len) { 680ae8c6e27Sflorian if(pkt_len < len) 681ae8c6e27Sflorian return 0; /* exceeds rdata */ 682ae8c6e27Sflorian pkt_len -= len; 683ae8c6e27Sflorian sldns_buffer_skip(pkt, (ssize_t)len); 684ae8c6e27Sflorian rr->size += len; 685ae8c6e27Sflorian } 686ae8c6e27Sflorian rdf++; 687ae8c6e27Sflorian } 688ae8c6e27Sflorian } 689ae8c6e27Sflorian /* remaining rdata */ 690ae8c6e27Sflorian rr->size += pkt_len; 691ae8c6e27Sflorian sldns_buffer_skip(pkt, (ssize_t)pkt_len); 692ae8c6e27Sflorian return 1; 693ae8c6e27Sflorian } 694ae8c6e27Sflorian 695ae8c6e27Sflorian /** skip rr ttl and rdata */ 696ae8c6e27Sflorian static int 697ae8c6e27Sflorian skip_ttl_rdata(sldns_buffer* pkt) 698ae8c6e27Sflorian { 699ae8c6e27Sflorian uint16_t rdatalen; 700ae8c6e27Sflorian if(sldns_buffer_remaining(pkt) < 6) /* ttl + rdatalen */ 701ae8c6e27Sflorian return 0; 702ae8c6e27Sflorian sldns_buffer_skip(pkt, 4); /* ttl */ 703ae8c6e27Sflorian rdatalen = sldns_buffer_read_u16(pkt); 704ae8c6e27Sflorian if(sldns_buffer_remaining(pkt) < rdatalen) 705ae8c6e27Sflorian return 0; 706ae8c6e27Sflorian sldns_buffer_skip(pkt, (ssize_t)rdatalen); 707ae8c6e27Sflorian return 1; 708ae8c6e27Sflorian } 709ae8c6e27Sflorian 710ae8c6e27Sflorian /** see if RRSIG is a duplicate of another */ 711ae8c6e27Sflorian static int 712ae8c6e27Sflorian sig_is_double(sldns_buffer* pkt, struct rrset_parse* rrset, uint8_t* ttldata) 713ae8c6e27Sflorian { 714ae8c6e27Sflorian uint16_t rlen, siglen; 715ae8c6e27Sflorian size_t pos = sldns_buffer_position(pkt); 716ae8c6e27Sflorian struct rr_parse* sig; 717ae8c6e27Sflorian if(sldns_buffer_remaining(pkt) < 6) 718ae8c6e27Sflorian return 0; 719ae8c6e27Sflorian sldns_buffer_skip(pkt, 4); /* ttl */ 720ae8c6e27Sflorian rlen = sldns_buffer_read_u16(pkt); 721ae8c6e27Sflorian if(sldns_buffer_remaining(pkt) < rlen) { 722ae8c6e27Sflorian sldns_buffer_set_position(pkt, pos); 723ae8c6e27Sflorian return 0; 724ae8c6e27Sflorian } 725ae8c6e27Sflorian sldns_buffer_set_position(pkt, pos); 726ae8c6e27Sflorian 727ae8c6e27Sflorian sig = rrset->rrsig_first; 728ae8c6e27Sflorian while(sig) { 729ae8c6e27Sflorian /* check if rdatalen is same */ 730ae8c6e27Sflorian memmove(&siglen, sig->ttl_data+4, sizeof(siglen)); 731ae8c6e27Sflorian siglen = ntohs(siglen); 732ae8c6e27Sflorian /* checks if data in packet is exactly the same, this means 733ae8c6e27Sflorian * also dname in rdata is the same, but rrsig is not allowed 734ae8c6e27Sflorian * to have compressed dnames anyway. If it is compressed anyway 735ae8c6e27Sflorian * it will lead to duplicate rrs for qtype=RRSIG. (or ANY). 736ae8c6e27Sflorian * 737ae8c6e27Sflorian * Cannot use sig->size because size of the other one is not 738ae8c6e27Sflorian * calculated yet. 739ae8c6e27Sflorian */ 740ae8c6e27Sflorian if(siglen == rlen) { 741ae8c6e27Sflorian if(siglen>0 && memcmp(sig->ttl_data+6, ttldata+6, 742ae8c6e27Sflorian siglen) == 0) { 743ae8c6e27Sflorian /* same! */ 744ae8c6e27Sflorian return 1; 745ae8c6e27Sflorian } 746ae8c6e27Sflorian } 747ae8c6e27Sflorian sig = sig->next; 748ae8c6e27Sflorian } 749ae8c6e27Sflorian return 0; 750ae8c6e27Sflorian } 751ae8c6e27Sflorian 752ae8c6e27Sflorian /** Add rr (from packet here) to rrset, skips rr */ 753ae8c6e27Sflorian static int 754ae8c6e27Sflorian add_rr_to_rrset(struct rrset_parse* rrset, sldns_buffer* pkt, 755ae8c6e27Sflorian struct msg_parse* msg, struct regional* region, 756ae8c6e27Sflorian sldns_pkt_section section, uint16_t type) 757ae8c6e27Sflorian { 758ae8c6e27Sflorian struct rr_parse* rr; 759ae8c6e27Sflorian /* check section of rrset. */ 760ae8c6e27Sflorian if(rrset->section != section && type != LDNS_RR_TYPE_RRSIG && 761ae8c6e27Sflorian rrset->type != LDNS_RR_TYPE_RRSIG) { 762ae8c6e27Sflorian /* silently drop it - we drop the last part, since 763ae8c6e27Sflorian * trust in rr data depends on the section it is in. 764ae8c6e27Sflorian * the less trustworthy part is discarded. 765ae8c6e27Sflorian * also the last part is more likely to be incomplete. 766ae8c6e27Sflorian * RFC 2181: must put RRset only once in response. */ 767ae8c6e27Sflorian /* 768ae8c6e27Sflorian verbose(VERB_QUERY, "Packet contains rrset data in " 769ae8c6e27Sflorian "multiple sections, dropped last part."); 770ae8c6e27Sflorian log_buf(VERB_QUERY, "packet was", pkt); 771ae8c6e27Sflorian */ 772ae8c6e27Sflorian /* forwards */ 773ae8c6e27Sflorian if(!skip_ttl_rdata(pkt)) 774ae8c6e27Sflorian return LDNS_RCODE_FORMERR; 775ae8c6e27Sflorian return 0; 776ae8c6e27Sflorian } 777ae8c6e27Sflorian 778ae8c6e27Sflorian if( (msg->qtype == LDNS_RR_TYPE_RRSIG || 779ae8c6e27Sflorian msg->qtype == LDNS_RR_TYPE_ANY) 780ae8c6e27Sflorian && sig_is_double(pkt, rrset, sldns_buffer_current(pkt))) { 781ae8c6e27Sflorian if(!skip_ttl_rdata(pkt)) 782ae8c6e27Sflorian return LDNS_RCODE_FORMERR; 783ae8c6e27Sflorian return 0; 784ae8c6e27Sflorian } 785ae8c6e27Sflorian 786ae8c6e27Sflorian /* create rr */ 787ae8c6e27Sflorian if(!(rr = (struct rr_parse*)regional_alloc(region, sizeof(*rr)))) 788ae8c6e27Sflorian return LDNS_RCODE_SERVFAIL; 789ae8c6e27Sflorian rr->outside_packet = 0; 790ae8c6e27Sflorian rr->ttl_data = sldns_buffer_current(pkt); 791ae8c6e27Sflorian rr->next = 0; 792ae8c6e27Sflorian if(type == LDNS_RR_TYPE_RRSIG && rrset->type != LDNS_RR_TYPE_RRSIG) { 793ae8c6e27Sflorian if(rrset->rrsig_last) 794ae8c6e27Sflorian rrset->rrsig_last->next = rr; 795ae8c6e27Sflorian else rrset->rrsig_first = rr; 796ae8c6e27Sflorian rrset->rrsig_last = rr; 797ae8c6e27Sflorian rrset->rrsig_count++; 798ae8c6e27Sflorian } else { 799ae8c6e27Sflorian if(rrset->rr_last) 800ae8c6e27Sflorian rrset->rr_last->next = rr; 801ae8c6e27Sflorian else rrset->rr_first = rr; 802ae8c6e27Sflorian rrset->rr_last = rr; 803ae8c6e27Sflorian rrset->rr_count++; 804ae8c6e27Sflorian } 805ae8c6e27Sflorian 806ae8c6e27Sflorian /* calc decompressed size */ 807ae8c6e27Sflorian if(!calc_size(pkt, type, rr)) 808ae8c6e27Sflorian return LDNS_RCODE_FORMERR; 809ae8c6e27Sflorian rrset->size += rr->size; 810ae8c6e27Sflorian 811ae8c6e27Sflorian return 0; 812ae8c6e27Sflorian } 813ae8c6e27Sflorian 814ae8c6e27Sflorian /** 815ae8c6e27Sflorian * Parse packet RR section, for answer, authority and additional sections. 816ae8c6e27Sflorian * @param pkt: packet, position at call must be at start of section. 817ae8c6e27Sflorian * at end position is after section. 818ae8c6e27Sflorian * @param msg: store results here. 819ae8c6e27Sflorian * @param region: how to alloc results. 820ae8c6e27Sflorian * @param section: section enum. 821ae8c6e27Sflorian * @param num_rrs: how many rrs are in the section. 822ae8c6e27Sflorian * @param num_rrsets: returns number of rrsets in the section. 823ae8c6e27Sflorian * @return: 0 if OK, or rcode on error. 824ae8c6e27Sflorian */ 825ae8c6e27Sflorian static int 826ae8c6e27Sflorian parse_section(sldns_buffer* pkt, struct msg_parse* msg, 827ae8c6e27Sflorian struct regional* region, sldns_pkt_section section, 828ae8c6e27Sflorian uint16_t num_rrs, size_t* num_rrsets) 829ae8c6e27Sflorian { 830ae8c6e27Sflorian uint16_t i; 831ae8c6e27Sflorian uint8_t* dname, *prev_dname_f = NULL, *prev_dname_l = NULL; 832ae8c6e27Sflorian size_t dnamelen, prev_dnamelen = 0; 833ae8c6e27Sflorian uint16_t type, prev_type = 0; 834ae8c6e27Sflorian uint16_t dclass, prev_dclass = 0; 835ae8c6e27Sflorian uint32_t rrset_flags = 0; 836ae8c6e27Sflorian hashvalue_type hash = 0; 837ae8c6e27Sflorian struct rrset_parse* rrset = NULL; 838ae8c6e27Sflorian int r; 839ae8c6e27Sflorian 840ae8c6e27Sflorian if(num_rrs == 0) 841ae8c6e27Sflorian return 0; 842ae8c6e27Sflorian if(sldns_buffer_remaining(pkt) <= 0) 843ae8c6e27Sflorian return LDNS_RCODE_FORMERR; 844ae8c6e27Sflorian for(i=0; i<num_rrs; i++) { 845ae8c6e27Sflorian /* parse this RR. */ 846ae8c6e27Sflorian dname = sldns_buffer_current(pkt); 847ae8c6e27Sflorian if((dnamelen = pkt_dname_len(pkt)) == 0) 848ae8c6e27Sflorian return LDNS_RCODE_FORMERR; 849ae8c6e27Sflorian if(sldns_buffer_remaining(pkt) < 10) /* type, class, ttl, len */ 850ae8c6e27Sflorian return LDNS_RCODE_FORMERR; 851ae8c6e27Sflorian type = sldns_buffer_read_u16(pkt); 852ae8c6e27Sflorian sldns_buffer_read(pkt, &dclass, sizeof(dclass)); 853ae8c6e27Sflorian 854ae8c6e27Sflorian if(0) { /* debug show what is being parsed. */ 855ae8c6e27Sflorian if(type == LDNS_RR_TYPE_RRSIG) { 856ae8c6e27Sflorian uint16_t t; 857ae8c6e27Sflorian if(pkt_rrsig_covered(pkt, 858ae8c6e27Sflorian sldns_buffer_current(pkt), &t)) 859ae8c6e27Sflorian fprintf(stderr, "parse of %s(%d) [%s(%d)]", 860ae8c6e27Sflorian sldns_rr_descript(type)? 861ae8c6e27Sflorian sldns_rr_descript(type)->_name: "??", 862ae8c6e27Sflorian (int)type, 863ae8c6e27Sflorian sldns_rr_descript(t)? 864ae8c6e27Sflorian sldns_rr_descript(t)->_name: "??", 865ae8c6e27Sflorian (int)t); 866ae8c6e27Sflorian } else 867ae8c6e27Sflorian fprintf(stderr, "parse of %s(%d)", 868ae8c6e27Sflorian sldns_rr_descript(type)? 869ae8c6e27Sflorian sldns_rr_descript(type)->_name: "??", 870ae8c6e27Sflorian (int)type); 871ae8c6e27Sflorian fprintf(stderr, " %s(%d) ", 872ae8c6e27Sflorian sldns_lookup_by_id(sldns_rr_classes, 873ae8c6e27Sflorian (int)ntohs(dclass))?sldns_lookup_by_id( 874ae8c6e27Sflorian sldns_rr_classes, (int)ntohs(dclass))->name: 875ae8c6e27Sflorian "??", (int)ntohs(dclass)); 876ae8c6e27Sflorian dname_print(stderr, pkt, dname); 877ae8c6e27Sflorian fprintf(stderr, "\n"); 878ae8c6e27Sflorian } 879ae8c6e27Sflorian 880ae8c6e27Sflorian /* see if it is part of an existing RR set */ 881ae8c6e27Sflorian if(!find_rrset(msg, pkt, dname, dnamelen, type, dclass, &hash, 882ae8c6e27Sflorian &rrset_flags, &prev_dname_f, &prev_dname_l, 883ae8c6e27Sflorian &prev_dnamelen, &prev_type, &prev_dclass, &rrset, 884ae8c6e27Sflorian section, region)) 885ae8c6e27Sflorian return LDNS_RCODE_SERVFAIL; 886ae8c6e27Sflorian if(!rrset) { 887ae8c6e27Sflorian /* it is a new RR set. hash&flags already calculated.*/ 888ae8c6e27Sflorian (*num_rrsets)++; 889ae8c6e27Sflorian rrset = new_rrset(msg, dname, dnamelen, type, dclass, 890ae8c6e27Sflorian hash, rrset_flags, section, region); 891ae8c6e27Sflorian if(!rrset) 892ae8c6e27Sflorian return LDNS_RCODE_SERVFAIL; 893ae8c6e27Sflorian } 894ae8c6e27Sflorian else if(0) { 895ae8c6e27Sflorian fprintf(stderr, "is part of existing: "); 896ae8c6e27Sflorian dname_print(stderr, pkt, rrset->dname); 897ae8c6e27Sflorian fprintf(stderr, " type %s(%d)\n", 898ae8c6e27Sflorian sldns_rr_descript(rrset->type)? 899ae8c6e27Sflorian sldns_rr_descript(rrset->type)->_name: "??", 900ae8c6e27Sflorian (int)rrset->type); 901ae8c6e27Sflorian } 902ae8c6e27Sflorian /* add to rrset. */ 903ae8c6e27Sflorian if((r=add_rr_to_rrset(rrset, pkt, msg, region, section, 904ae8c6e27Sflorian type)) != 0) 905ae8c6e27Sflorian return r; 906ae8c6e27Sflorian } 907ae8c6e27Sflorian return 0; 908ae8c6e27Sflorian } 909ae8c6e27Sflorian 910ae8c6e27Sflorian int 911ae8c6e27Sflorian parse_packet(sldns_buffer* pkt, struct msg_parse* msg, struct regional* region) 912ae8c6e27Sflorian { 913ae8c6e27Sflorian int ret; 914ae8c6e27Sflorian if(sldns_buffer_remaining(pkt) < LDNS_HEADER_SIZE) 915ae8c6e27Sflorian return LDNS_RCODE_FORMERR; 916ae8c6e27Sflorian /* read the header */ 917ae8c6e27Sflorian sldns_buffer_read(pkt, &msg->id, sizeof(uint16_t)); 918ae8c6e27Sflorian msg->flags = sldns_buffer_read_u16(pkt); 919ae8c6e27Sflorian msg->qdcount = sldns_buffer_read_u16(pkt); 920ae8c6e27Sflorian msg->ancount = sldns_buffer_read_u16(pkt); 921ae8c6e27Sflorian msg->nscount = sldns_buffer_read_u16(pkt); 922ae8c6e27Sflorian msg->arcount = sldns_buffer_read_u16(pkt); 923ae8c6e27Sflorian if(msg->qdcount > 1) 924ae8c6e27Sflorian return LDNS_RCODE_FORMERR; 925ae8c6e27Sflorian if((ret = parse_query_section(pkt, msg)) != 0) 926ae8c6e27Sflorian return ret; 927ae8c6e27Sflorian if((ret = parse_section(pkt, msg, region, LDNS_SECTION_ANSWER, 928ae8c6e27Sflorian msg->ancount, &msg->an_rrsets)) != 0) 929ae8c6e27Sflorian return ret; 930ae8c6e27Sflorian if((ret = parse_section(pkt, msg, region, LDNS_SECTION_AUTHORITY, 931ae8c6e27Sflorian msg->nscount, &msg->ns_rrsets)) != 0) 932ae8c6e27Sflorian return ret; 933ae8c6e27Sflorian if(sldns_buffer_remaining(pkt) == 0 && msg->arcount == 1) { 934ae8c6e27Sflorian /* BIND accepts leniently that an EDNS record is missing. 935ae8c6e27Sflorian * so, we do too. */ 936ae8c6e27Sflorian } else if((ret = parse_section(pkt, msg, region, 937ae8c6e27Sflorian LDNS_SECTION_ADDITIONAL, msg->arcount, &msg->ar_rrsets)) != 0) 938ae8c6e27Sflorian return ret; 939ae8c6e27Sflorian /* if(sldns_buffer_remaining(pkt) > 0) { */ 940ae8c6e27Sflorian /* there is spurious data at end of packet. ignore */ 941ae8c6e27Sflorian /* } */ 942ae8c6e27Sflorian msg->rrset_count = msg->an_rrsets + msg->ns_rrsets + msg->ar_rrsets; 943ae8c6e27Sflorian return 0; 944ae8c6e27Sflorian } 945ae8c6e27Sflorian 946ae8c6e27Sflorian /** parse EDNS options from EDNS wireformat rdata */ 947ae8c6e27Sflorian static int 948a1a7ba80Sflorian parse_edns_options_from_query(uint8_t* rdata_ptr, size_t rdata_len, 949a1a7ba80Sflorian struct edns_data* edns, struct config_file* cfg, struct comm_point* c, 950*7037e34cSflorian struct comm_reply* repinfo, uint32_t now, struct regional* region, 951*7037e34cSflorian struct cookie_secrets* cookie_secrets) 952ae8c6e27Sflorian { 953a1a7ba80Sflorian /* To respond with a Keepalive option, the client connection must have 954a1a7ba80Sflorian * received one message with a TCP Keepalive EDNS option, and that 955a1a7ba80Sflorian * option must have 0 length data. Subsequent messages sent on that 956a1a7ba80Sflorian * connection will have a TCP Keepalive option. 957a1a7ba80Sflorian * 958a1a7ba80Sflorian * In the if-statement below, the option is added unsolicited. This 959a1a7ba80Sflorian * means that the client has sent an KEEPALIVE option earlier. We know 960a1a7ba80Sflorian * here this is true, because c->tcp_keepalive is set. 961a1a7ba80Sflorian */ 962a1a7ba80Sflorian if (cfg && cfg->do_tcp_keepalive && c && c->type != comm_udp && c->tcp_keepalive) { 963a1a7ba80Sflorian if(!edns_opt_list_append_keepalive(&edns->opt_list_out, 964a1a7ba80Sflorian c->tcp_timeout_msec / 100, region)) { 965a1a7ba80Sflorian log_err("out of memory"); 966a1a7ba80Sflorian return LDNS_RCODE_SERVFAIL; 967a1a7ba80Sflorian } 968a1a7ba80Sflorian } 969a1a7ba80Sflorian 970ae8c6e27Sflorian /* while still more options, and have code+len to read */ 971ae8c6e27Sflorian /* ignores partial content (i.e. rdata len 3) */ 972ae8c6e27Sflorian while(rdata_len >= 4) { 973ae8c6e27Sflorian uint16_t opt_code = sldns_read_uint16(rdata_ptr); 974ae8c6e27Sflorian uint16_t opt_len = sldns_read_uint16(rdata_ptr+2); 975d500c338Sflorian uint8_t server_cookie[40]; 976d500c338Sflorian enum edns_cookie_val_status cookie_val_status; 977d500c338Sflorian int cookie_is_v4 = 1; 978d500c338Sflorian 979ae8c6e27Sflorian rdata_ptr += 4; 980ae8c6e27Sflorian rdata_len -= 4; 981ae8c6e27Sflorian if(opt_len > rdata_len) 982ae8c6e27Sflorian break; /* option code partial */ 983a1a7ba80Sflorian 984a1a7ba80Sflorian /* handle parse time edns options here */ 985a1a7ba80Sflorian switch(opt_code) { 986a1a7ba80Sflorian case LDNS_EDNS_NSID: 987a1a7ba80Sflorian if (!cfg || !cfg->nsid) 988a1a7ba80Sflorian break; 989a1a7ba80Sflorian if(!edns_opt_list_append(&edns->opt_list_out, 990a1a7ba80Sflorian LDNS_EDNS_NSID, cfg->nsid_len, 991a1a7ba80Sflorian cfg->nsid, region)) { 992ae8c6e27Sflorian log_err("out of memory"); 993a1a7ba80Sflorian return LDNS_RCODE_SERVFAIL; 994a1a7ba80Sflorian } 995a1a7ba80Sflorian break; 996a1a7ba80Sflorian 997a1a7ba80Sflorian case LDNS_EDNS_KEEPALIVE: 998a1a7ba80Sflorian /* To respond with a Keepalive option, the client 999a1a7ba80Sflorian * connection must have received one message with a TCP 1000a1a7ba80Sflorian * Keepalive EDNS option, and that option must have 0 1001a1a7ba80Sflorian * length data. Subsequent messages sent on that 1002a1a7ba80Sflorian * connection will have a TCP Keepalive option. 1003a1a7ba80Sflorian * 1004a1a7ba80Sflorian * This should be the first time the client sends this 1005a1a7ba80Sflorian * option, so c->tcp_keepalive is not set. 1006a1a7ba80Sflorian * Besides adding the reply KEEPALIVE option, 1007a1a7ba80Sflorian * c->tcp_keepalive will be set so that the 1008a1a7ba80Sflorian * option will be added unsolicited in subsequent 1009a1a7ba80Sflorian * responses (see the comment above the if-statement 1010a1a7ba80Sflorian * at the start of this function). 1011a1a7ba80Sflorian */ 1012a1a7ba80Sflorian if (!cfg || !cfg->do_tcp_keepalive || !c || 1013a1a7ba80Sflorian c->type == comm_udp || c->tcp_keepalive) 1014a1a7ba80Sflorian break; 1015a1a7ba80Sflorian if(opt_len) { 1016a1a7ba80Sflorian verbose(VERB_ALGO, "query with bad edns keepalive."); 1017a1a7ba80Sflorian return LDNS_RCODE_FORMERR; 1018a1a7ba80Sflorian } 1019a1a7ba80Sflorian if(!edns_opt_list_append_keepalive(&edns->opt_list_out, 1020a1a7ba80Sflorian c->tcp_timeout_msec / 100, 1021a1a7ba80Sflorian region)) { 1022a1a7ba80Sflorian log_err("out of memory"); 1023a1a7ba80Sflorian return LDNS_RCODE_SERVFAIL; 1024a1a7ba80Sflorian } 1025a1a7ba80Sflorian c->tcp_keepalive = 1; 1026a1a7ba80Sflorian break; 1027a1a7ba80Sflorian 1028a1a7ba80Sflorian case LDNS_EDNS_PADDING: 1029a1a7ba80Sflorian if(!cfg || !cfg->pad_responses || 1030a1a7ba80Sflorian !c || c->type != comm_tcp ||!c->ssl) 1031a1a7ba80Sflorian break; 1032a1a7ba80Sflorian if(!edns_opt_list_append(&edns->opt_list_out, 1033a1a7ba80Sflorian LDNS_EDNS_PADDING, 1034a1a7ba80Sflorian 0, NULL, region)) { 1035a1a7ba80Sflorian log_err("out of memory"); 1036a1a7ba80Sflorian return LDNS_RCODE_SERVFAIL; 1037a1a7ba80Sflorian } 1038a1a7ba80Sflorian edns->padding_block_size = cfg->pad_responses_block_size; 1039a1a7ba80Sflorian break; 1040a1a7ba80Sflorian 1041d500c338Sflorian case LDNS_EDNS_COOKIE: 1042d500c338Sflorian if(!cfg || !cfg->do_answer_cookie || !repinfo) 1043d500c338Sflorian break; 1044d500c338Sflorian if(opt_len != 8 && (opt_len < 16 || opt_len > 40)) { 1045d500c338Sflorian verbose(VERB_ALGO, "worker request: " 1046d500c338Sflorian "badly formatted cookie"); 1047d500c338Sflorian return LDNS_RCODE_FORMERR; 1048d500c338Sflorian } 1049d500c338Sflorian edns->cookie_present = 1; 1050d500c338Sflorian 1051d500c338Sflorian /* Copy client cookie, version and timestamp for 1052d500c338Sflorian * validation and creation purposes. 1053d500c338Sflorian */ 1054d500c338Sflorian if(opt_len >= 16) { 1055d500c338Sflorian memmove(server_cookie, rdata_ptr, 16); 1056d500c338Sflorian } else { 1057d500c338Sflorian memset(server_cookie, 0, 16); 1058d500c338Sflorian memmove(server_cookie, rdata_ptr, opt_len); 1059d500c338Sflorian } 1060d500c338Sflorian 1061d500c338Sflorian /* Copy client ip for validation and creation 1062d500c338Sflorian * purposes. It will be overwritten if (re)creation 1063d500c338Sflorian * is needed. 1064d500c338Sflorian */ 1065d500c338Sflorian if(repinfo->remote_addr.ss_family == AF_INET) { 1066d500c338Sflorian memcpy(server_cookie + 16, 1067d500c338Sflorian &((struct sockaddr_in*)&repinfo->remote_addr)->sin_addr, 4); 1068d500c338Sflorian } else { 1069d500c338Sflorian cookie_is_v4 = 0; 1070d500c338Sflorian memcpy(server_cookie + 16, 1071d500c338Sflorian &((struct sockaddr_in6*)&repinfo->remote_addr)->sin6_addr, 16); 1072d500c338Sflorian } 1073d500c338Sflorian 1074*7037e34cSflorian if(cfg->cookie_secret_file && 1075*7037e34cSflorian cfg->cookie_secret_file[0]) { 1076*7037e34cSflorian /* Loop over the active and staging cookies. */ 1077*7037e34cSflorian cookie_val_status = 1078*7037e34cSflorian cookie_secrets_server_validate( 1079*7037e34cSflorian rdata_ptr, opt_len, cookie_secrets, 1080*7037e34cSflorian cookie_is_v4, server_cookie, now); 1081*7037e34cSflorian } else { 1082*7037e34cSflorian /* Use the cookie option value to validate. */ 1083d500c338Sflorian cookie_val_status = edns_cookie_server_validate( 1084d500c338Sflorian rdata_ptr, opt_len, cfg->cookie_secret, 1085d500c338Sflorian cfg->cookie_secret_len, cookie_is_v4, 1086d500c338Sflorian server_cookie, now); 1087*7037e34cSflorian } 1088*7037e34cSflorian if(cookie_val_status == COOKIE_STATUS_VALID_RENEW) 1089*7037e34cSflorian edns->cookie_valid = 1; 1090d500c338Sflorian switch(cookie_val_status) { 1091d500c338Sflorian case COOKIE_STATUS_VALID: 1092d500c338Sflorian edns->cookie_valid = 1; 1093d500c338Sflorian /* Reuse cookie */ 1094d500c338Sflorian if(!edns_opt_list_append( 1095d500c338Sflorian &edns->opt_list_out, LDNS_EDNS_COOKIE, 1096d500c338Sflorian opt_len, rdata_ptr, region)) { 1097d500c338Sflorian log_err("out of memory"); 1098d500c338Sflorian return LDNS_RCODE_SERVFAIL; 1099d500c338Sflorian } 1100d500c338Sflorian /* Cookie to be reused added to outgoing 1101d500c338Sflorian * options. Done! 1102d500c338Sflorian */ 1103d500c338Sflorian break; 1104d500c338Sflorian case COOKIE_STATUS_CLIENT_ONLY: 1105d500c338Sflorian edns->cookie_client = 1; 1106*7037e34cSflorian ATTR_FALLTHROUGH 1107d500c338Sflorian /* fallthrough */ 1108*7037e34cSflorian case COOKIE_STATUS_VALID_RENEW: 1109d500c338Sflorian case COOKIE_STATUS_FUTURE: 1110d500c338Sflorian case COOKIE_STATUS_EXPIRED: 1111d500c338Sflorian case COOKIE_STATUS_INVALID: 1112d500c338Sflorian default: 1113*7037e34cSflorian if(cfg->cookie_secret_file && 1114*7037e34cSflorian cfg->cookie_secret_file[0]) { 1115*7037e34cSflorian if(!cookie_secrets) 1116*7037e34cSflorian break; 1117*7037e34cSflorian lock_basic_lock(&cookie_secrets->lock); 1118*7037e34cSflorian if(cookie_secrets->cookie_count < 1) { 1119*7037e34cSflorian lock_basic_unlock(&cookie_secrets->lock); 1120*7037e34cSflorian break; 1121*7037e34cSflorian } 1122*7037e34cSflorian edns_cookie_server_write(server_cookie, 1123*7037e34cSflorian cookie_secrets->cookie_secrets[0].cookie_secret, 1124*7037e34cSflorian cookie_is_v4, now); 1125*7037e34cSflorian lock_basic_unlock(&cookie_secrets->lock); 1126*7037e34cSflorian } else { 1127d500c338Sflorian edns_cookie_server_write(server_cookie, 1128d500c338Sflorian cfg->cookie_secret, cookie_is_v4, now); 1129*7037e34cSflorian } 1130d500c338Sflorian if(!edns_opt_list_append(&edns->opt_list_out, 1131d500c338Sflorian LDNS_EDNS_COOKIE, 24, server_cookie, 1132d500c338Sflorian region)) { 1133d500c338Sflorian log_err("out of memory"); 1134d500c338Sflorian return LDNS_RCODE_SERVFAIL; 1135d500c338Sflorian } 1136d500c338Sflorian break; 1137d500c338Sflorian } 1138d500c338Sflorian break; 1139a1a7ba80Sflorian default: 1140a1a7ba80Sflorian break; 1141a1a7ba80Sflorian } 1142a1a7ba80Sflorian if(!edns_opt_list_append(&edns->opt_list_in, 1143a1a7ba80Sflorian opt_code, opt_len, rdata_ptr, region)) { 1144a1a7ba80Sflorian log_err("out of memory"); 1145a1a7ba80Sflorian return LDNS_RCODE_SERVFAIL; 1146ae8c6e27Sflorian } 1147ae8c6e27Sflorian rdata_ptr += opt_len; 1148ae8c6e27Sflorian rdata_len -= opt_len; 1149ae8c6e27Sflorian } 1150a1a7ba80Sflorian return LDNS_RCODE_NOERROR; 1151ae8c6e27Sflorian } 1152ae8c6e27Sflorian 1153ae8c6e27Sflorian int 1154a1a7ba80Sflorian parse_extract_edns_from_response_msg(struct msg_parse* msg, 1155a1a7ba80Sflorian struct edns_data* edns, struct regional* region) 1156ae8c6e27Sflorian { 1157ae8c6e27Sflorian struct rrset_parse* rrset = msg->rrset_first; 1158ae8c6e27Sflorian struct rrset_parse* prev = 0; 1159ae8c6e27Sflorian struct rrset_parse* found = 0; 1160ae8c6e27Sflorian struct rrset_parse* found_prev = 0; 1161ae8c6e27Sflorian size_t rdata_len; 1162ae8c6e27Sflorian uint8_t* rdata_ptr; 1163ae8c6e27Sflorian /* since the class encodes the UDP size, we cannot use hash table to 1164ae8c6e27Sflorian * find the EDNS OPT record. Scan the packet. */ 1165ae8c6e27Sflorian while(rrset) { 1166ae8c6e27Sflorian if(rrset->type == LDNS_RR_TYPE_OPT) { 1167ae8c6e27Sflorian /* only one OPT RR allowed. */ 1168ae8c6e27Sflorian if(found) return LDNS_RCODE_FORMERR; 1169ae8c6e27Sflorian /* found it! */ 1170ae8c6e27Sflorian found_prev = prev; 1171ae8c6e27Sflorian found = rrset; 1172ae8c6e27Sflorian } 1173ae8c6e27Sflorian prev = rrset; 1174ae8c6e27Sflorian rrset = rrset->rrset_all_next; 1175ae8c6e27Sflorian } 1176ae8c6e27Sflorian if(!found) { 1177ae8c6e27Sflorian memset(edns, 0, sizeof(*edns)); 1178ae8c6e27Sflorian edns->udp_size = 512; 1179ae8c6e27Sflorian return 0; 1180ae8c6e27Sflorian } 1181ae8c6e27Sflorian /* check the found RRset */ 1182ae8c6e27Sflorian /* most lenient check possible. ignore dname, use last opt */ 1183ae8c6e27Sflorian if(found->section != LDNS_SECTION_ADDITIONAL) 1184ae8c6e27Sflorian return LDNS_RCODE_FORMERR; 1185ae8c6e27Sflorian if(found->rr_count == 0) 1186ae8c6e27Sflorian return LDNS_RCODE_FORMERR; 1187ae8c6e27Sflorian if(0) { /* strict checking of dname and RRcount */ 1188ae8c6e27Sflorian if(found->dname_len != 1 || !found->dname 1189ae8c6e27Sflorian || found->dname[0] != 0) return LDNS_RCODE_FORMERR; 1190ae8c6e27Sflorian if(found->rr_count != 1) return LDNS_RCODE_FORMERR; 1191ae8c6e27Sflorian } 1192ae8c6e27Sflorian log_assert(found->rr_first && found->rr_last); 1193ae8c6e27Sflorian 1194ae8c6e27Sflorian /* remove from packet */ 1195ae8c6e27Sflorian if(found_prev) found_prev->rrset_all_next = found->rrset_all_next; 1196ae8c6e27Sflorian else msg->rrset_first = found->rrset_all_next; 1197ae8c6e27Sflorian if(found == msg->rrset_last) 1198ae8c6e27Sflorian msg->rrset_last = found_prev; 1199ae8c6e27Sflorian msg->arcount --; 1200ae8c6e27Sflorian msg->ar_rrsets --; 1201ae8c6e27Sflorian msg->rrset_count --; 1202ae8c6e27Sflorian 1203ae8c6e27Sflorian /* take the data ! */ 1204ae8c6e27Sflorian edns->edns_present = 1; 1205ae8c6e27Sflorian edns->ext_rcode = found->rr_last->ttl_data[0]; 1206ae8c6e27Sflorian edns->edns_version = found->rr_last->ttl_data[1]; 1207ae8c6e27Sflorian edns->bits = sldns_read_uint16(&found->rr_last->ttl_data[2]); 1208ae8c6e27Sflorian edns->udp_size = ntohs(found->rrset_class); 1209a1a7ba80Sflorian edns->opt_list_in = NULL; 1210a1a7ba80Sflorian edns->opt_list_out = NULL; 1211a1a7ba80Sflorian edns->opt_list_inplace_cb_out = NULL; 1212a8eaceedSflorian edns->padding_block_size = 0; 1213d500c338Sflorian edns->cookie_present = 0; 1214d500c338Sflorian edns->cookie_valid = 0; 1215ae8c6e27Sflorian 1216ae8c6e27Sflorian /* take the options */ 1217ae8c6e27Sflorian rdata_len = found->rr_first->size-2; 1218ae8c6e27Sflorian rdata_ptr = found->rr_first->ttl_data+6; 1219ae8c6e27Sflorian 1220a1a7ba80Sflorian /* while still more options, and have code+len to read */ 1221a1a7ba80Sflorian /* ignores partial content (i.e. rdata len 3) */ 1222a1a7ba80Sflorian while(rdata_len >= 4) { 1223a1a7ba80Sflorian uint16_t opt_code = sldns_read_uint16(rdata_ptr); 1224a1a7ba80Sflorian uint16_t opt_len = sldns_read_uint16(rdata_ptr+2); 1225a1a7ba80Sflorian rdata_ptr += 4; 1226a1a7ba80Sflorian rdata_len -= 4; 1227a1a7ba80Sflorian if(opt_len > rdata_len) 1228a1a7ba80Sflorian break; /* option code partial */ 1229a1a7ba80Sflorian 1230a1a7ba80Sflorian if(!edns_opt_list_append(&edns->opt_list_in, 1231a1a7ba80Sflorian opt_code, opt_len, rdata_ptr, region)) { 1232a1a7ba80Sflorian log_err("out of memory"); 1233a1a7ba80Sflorian break; 1234a1a7ba80Sflorian } 1235a1a7ba80Sflorian rdata_ptr += opt_len; 1236a1a7ba80Sflorian rdata_len -= opt_len; 1237a1a7ba80Sflorian } 1238ae8c6e27Sflorian /* ignore rrsigs */ 1239a1a7ba80Sflorian return LDNS_RCODE_NOERROR; 1240ae8c6e27Sflorian } 1241ae8c6e27Sflorian 1242ae8c6e27Sflorian /** skip RR in packet */ 1243ae8c6e27Sflorian static int 1244ae8c6e27Sflorian skip_pkt_rr(sldns_buffer* pkt) 1245ae8c6e27Sflorian { 1246ae8c6e27Sflorian if(sldns_buffer_remaining(pkt) < 1) return 0; 1247ae8c6e27Sflorian if(!pkt_dname_len(pkt)) 1248ae8c6e27Sflorian return 0; 1249ae8c6e27Sflorian if(sldns_buffer_remaining(pkt) < 4) return 0; 1250ae8c6e27Sflorian sldns_buffer_skip(pkt, 4); /* type and class */ 1251ae8c6e27Sflorian if(!skip_ttl_rdata(pkt)) 1252ae8c6e27Sflorian return 0; 1253ae8c6e27Sflorian return 1; 1254ae8c6e27Sflorian } 1255ae8c6e27Sflorian 1256ae8c6e27Sflorian /** skip RRs from packet */ 12577a05b9dfSflorian int 1258ae8c6e27Sflorian skip_pkt_rrs(sldns_buffer* pkt, int num) 1259ae8c6e27Sflorian { 1260ae8c6e27Sflorian int i; 1261ae8c6e27Sflorian for(i=0; i<num; i++) { 1262ae8c6e27Sflorian if(!skip_pkt_rr(pkt)) 1263ae8c6e27Sflorian return 0; 1264ae8c6e27Sflorian } 1265ae8c6e27Sflorian return 1; 1266ae8c6e27Sflorian } 1267ae8c6e27Sflorian 1268ae8c6e27Sflorian int 1269a1a7ba80Sflorian parse_edns_from_query_pkt(sldns_buffer* pkt, struct edns_data* edns, 1270d500c338Sflorian struct config_file* cfg, struct comm_point* c, 1271*7037e34cSflorian struct comm_reply* repinfo, time_t now, struct regional* region, 1272*7037e34cSflorian struct cookie_secrets* cookie_secrets) 1273ae8c6e27Sflorian { 1274ae8c6e27Sflorian size_t rdata_len; 1275ae8c6e27Sflorian uint8_t* rdata_ptr; 1276ae8c6e27Sflorian log_assert(LDNS_QDCOUNT(sldns_buffer_begin(pkt)) == 1); 1277fadbf8b1Sflorian memset(edns, 0, sizeof(*edns)); 1278ae8c6e27Sflorian if(LDNS_ANCOUNT(sldns_buffer_begin(pkt)) != 0 || 1279ae8c6e27Sflorian LDNS_NSCOUNT(sldns_buffer_begin(pkt)) != 0) { 1280ae8c6e27Sflorian if(!skip_pkt_rrs(pkt, ((int)LDNS_ANCOUNT(sldns_buffer_begin(pkt)))+ 1281ae8c6e27Sflorian ((int)LDNS_NSCOUNT(sldns_buffer_begin(pkt))))) 1282fadbf8b1Sflorian return LDNS_RCODE_FORMERR; 1283ae8c6e27Sflorian } 1284ae8c6e27Sflorian /* check edns section is present */ 1285ae8c6e27Sflorian if(LDNS_ARCOUNT(sldns_buffer_begin(pkt)) > 1) { 1286ae8c6e27Sflorian return LDNS_RCODE_FORMERR; 1287ae8c6e27Sflorian } 1288ae8c6e27Sflorian if(LDNS_ARCOUNT(sldns_buffer_begin(pkt)) == 0) { 1289ae8c6e27Sflorian edns->udp_size = 512; 1290ae8c6e27Sflorian return 0; 1291ae8c6e27Sflorian } 1292ae8c6e27Sflorian /* domain name must be the root of length 1. */ 1293ae8c6e27Sflorian if(pkt_dname_len(pkt) != 1) 1294ae8c6e27Sflorian return LDNS_RCODE_FORMERR; 1295ae8c6e27Sflorian if(sldns_buffer_remaining(pkt) < 10) /* type, class, ttl, rdatalen */ 1296ae8c6e27Sflorian return LDNS_RCODE_FORMERR; 1297ae8c6e27Sflorian if(sldns_buffer_read_u16(pkt) != LDNS_RR_TYPE_OPT) 1298ae8c6e27Sflorian return LDNS_RCODE_FORMERR; 1299ae8c6e27Sflorian edns->edns_present = 1; 1300ae8c6e27Sflorian edns->udp_size = sldns_buffer_read_u16(pkt); /* class is udp size */ 1301ae8c6e27Sflorian edns->ext_rcode = sldns_buffer_read_u8(pkt); /* ttl used for bits */ 1302ae8c6e27Sflorian edns->edns_version = sldns_buffer_read_u8(pkt); 1303ae8c6e27Sflorian edns->bits = sldns_buffer_read_u16(pkt); 1304a1a7ba80Sflorian edns->opt_list_in = NULL; 1305a1a7ba80Sflorian edns->opt_list_out = NULL; 1306a1a7ba80Sflorian edns->opt_list_inplace_cb_out = NULL; 1307a8eaceedSflorian edns->padding_block_size = 0; 1308d500c338Sflorian edns->cookie_present = 0; 1309d500c338Sflorian edns->cookie_valid = 0; 1310ae8c6e27Sflorian 1311ae8c6e27Sflorian /* take the options */ 1312ae8c6e27Sflorian rdata_len = sldns_buffer_read_u16(pkt); 1313ae8c6e27Sflorian if(sldns_buffer_remaining(pkt) < rdata_len) 1314ae8c6e27Sflorian return LDNS_RCODE_FORMERR; 1315ae8c6e27Sflorian rdata_ptr = sldns_buffer_current(pkt); 1316ae8c6e27Sflorian /* ignore rrsigs */ 1317a1a7ba80Sflorian return parse_edns_options_from_query(rdata_ptr, rdata_len, edns, cfg, 1318*7037e34cSflorian c, repinfo, now, region, cookie_secrets); 1319ae8c6e27Sflorian } 1320ae8c6e27Sflorian 1321ae8c6e27Sflorian void 1322ae8c6e27Sflorian log_edns_opt_list(enum verbosity_value level, const char* info_str, 1323ae8c6e27Sflorian struct edns_option* list) 1324ae8c6e27Sflorian { 1325ae8c6e27Sflorian if(verbosity >= level && list) { 1326ae8c6e27Sflorian char str[128], *s; 1327ae8c6e27Sflorian size_t slen; 1328ae8c6e27Sflorian verbose(level, "%s", info_str); 1329ae8c6e27Sflorian while(list) { 1330ae8c6e27Sflorian s = str; 1331ae8c6e27Sflorian slen = sizeof(str); 1332ae8c6e27Sflorian (void)sldns_wire2str_edns_option_print(&s, &slen, list->opt_code, 1333ae8c6e27Sflorian list->opt_data, list->opt_len); 1334ae8c6e27Sflorian verbose(level, " %s", str); 1335ae8c6e27Sflorian list = list->next; 1336ae8c6e27Sflorian } 1337ae8c6e27Sflorian } 1338ae8c6e27Sflorian } 13397a05b9dfSflorian 134054cc57acSflorian /** remove RR from msgparse RRset, return true if rrset is entirely bad */ 134154cc57acSflorian int 134254cc57acSflorian msgparse_rrset_remove_rr(const char* str, sldns_buffer* pkt, struct rrset_parse* rrset, 134354cc57acSflorian struct rr_parse* prev, struct rr_parse* rr, struct sockaddr_storage* addr, socklen_t addrlen) 134454cc57acSflorian { 134554cc57acSflorian if(verbosity >= VERB_QUERY && rrset->dname_len <= LDNS_MAX_DOMAINLEN && str) { 134654cc57acSflorian uint8_t buf[LDNS_MAX_DOMAINLEN+1]; 134754cc57acSflorian dname_pkt_copy(pkt, buf, rrset->dname); 134854cc57acSflorian if(addr) 134954cc57acSflorian log_name_addr(VERB_QUERY, str, buf, addr, addrlen); 135054cc57acSflorian else log_nametypeclass(VERB_QUERY, str, buf, 135154cc57acSflorian rrset->type, ntohs(rrset->rrset_class)); 135254cc57acSflorian } 135354cc57acSflorian if(prev) 135454cc57acSflorian prev->next = rr->next; 135554cc57acSflorian else rrset->rr_first = rr->next; 135654cc57acSflorian if(rrset->rr_last == rr) 135754cc57acSflorian rrset->rr_last = prev; 135854cc57acSflorian rrset->rr_count --; 135954cc57acSflorian rrset->size -= rr->size; 136054cc57acSflorian /* rr struct still exists, but is unlinked, so that in the for loop 136154cc57acSflorian * the rr->next works fine to continue. */ 136254cc57acSflorian return rrset->rr_count == 0; 136354cc57acSflorian } 1364