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