int parse_extract_edns(struct msg_parse* msg, struct edns_data* edns) { struct rrset_parse* rrset = msg->rrset_first; struct rrset_parse* prev = 0; struct rrset_parse* found = 0; struct rrset_parse* found_prev = 0; /* since the class encodes the UDP size, we cannot use hash table to * find the EDNS OPT record. Scan the packet. */ while(rrset) { if(rrset->type == LDNS_RR_TYPE_OPT) { /* only one OPT RR allowed. */ if(found) return LDNS_RCODE_FORMERR; /* found it! */ found_prev = prev; found = rrset; } prev = rrset; rrset = rrset->rrset_all_next; } if(!found) { memset(edns, 0, sizeof(*edns)); edns->udp_size = 512; return 0; } /* check the found RRset */ /* most lenient check possible. ignore dname, use last opt */ if(found->section != LDNS_SECTION_ADDITIONAL) return LDNS_RCODE_FORMERR; if(found->rr_count == 0) return LDNS_RCODE_FORMERR; if(0) { /* strict checking of dname and RRcount */ if(found->dname_len != 1 || !found->dname || found->dname[0] != 0) return LDNS_RCODE_FORMERR; if(found->rr_count != 1) return LDNS_RCODE_FORMERR; } log_assert(found->rr_first && found->rr_last); /* remove from packet */ if(found_prev) found_prev->rrset_all_next = found->rrset_all_next; else msg->rrset_first = found->rrset_all_next; if(found == msg->rrset_last) msg->rrset_last = found_prev; msg->arcount --; msg->ar_rrsets --; msg->rrset_count --; /* take the data ! */ edns->edns_present = 1; edns->ext_rcode = found->rr_last->ttl_data[0]; edns->edns_version = found->rr_last->ttl_data[1]; edns->bits = sldns_read_uint16(&found->rr_last->ttl_data[2]); edns->udp_size = ntohs(found->rrset_class); /* ignore rdata and rrsigs */ return 0; }
/** find the minimumttl in the rdata of SOA record */ static time_t soa_find_minttl(struct rr_parse* rr) { uint16_t rlen = sldns_read_uint16(rr->ttl_data+4); if(rlen < 20) return 0; /* rdata too small for SOA (dname, dname, 5*32bit) */ /* minimum TTL is the last 32bit value in the rdata of the record */ /* at position ttl_data + 4(ttl) + 2(rdatalen) + rdatalen - 4(timeval)*/ return (time_t)sldns_read_uint32(rr->ttl_data+6+rlen-4); }
int delegpt_rrset_add_ns(struct delegpt* dp, struct regional* region, struct ub_packed_rrset_key* ns_rrset, uint8_t lame) { struct packed_rrset_data* nsdata = (struct packed_rrset_data*) ns_rrset->entry.data; size_t i; log_assert(!dp->dp_type_mlc); if(nsdata->security == sec_status_bogus) dp->bogus = 1; for(i=0; i<nsdata->count; i++) { if(nsdata->rr_len[i] < 2+1) continue; /* len + root label */ if(dname_valid(nsdata->rr_data[i]+2, nsdata->rr_len[i]-2) != (size_t)sldns_read_uint16(nsdata->rr_data[i])) continue; /* bad format */ /* add rdata of NS (= wirefmt dname), skip rdatalen bytes */ if(!delegpt_add_ns(dp, region, nsdata->rr_data[i]+2, lame)) return 0; } return 1; }
void get_cname_target(struct ub_packed_rrset_key* rrset, uint8_t** dname, size_t* dname_len) { struct packed_rrset_data* d; size_t len; if(ntohs(rrset->rk.type) != LDNS_RR_TYPE_CNAME && ntohs(rrset->rk.type) != LDNS_RR_TYPE_DNAME) return; d = (struct packed_rrset_data*)rrset->entry.data; if(d->count < 1) return; if(d->rr_len[0] < 3) /* at least rdatalen + 0byte root label */ return; len = sldns_read_uint16(d->rr_data[0]); if(len != d->rr_len[0] - sizeof(uint16_t)) return; if(dname_valid(d->rr_data[0]+sizeof(uint16_t), len) != len) return; *dname = d->rr_data[0]+sizeof(uint16_t); *dname_len = len; }
/** * Check if right hand name in NSEC is within zone * @param rrset: the NSEC rrset * @param zonename: the zone name. * @return true if BAD. */ static int sanitize_nsec_is_overreach(struct rrset_parse* rrset, uint8_t* zonename) { struct rr_parse* rr; uint8_t* rhs; size_t len; log_assert(rrset->type == LDNS_RR_TYPE_NSEC); for(rr = rrset->rr_first; rr; rr = rr->next) { rhs = rr->ttl_data+4+2; len = sldns_read_uint16(rr->ttl_data+4); if(!dname_valid(rhs, len)) { /* malformed domain name in rdata */ return 1; } if(!dname_subdomain_c(rhs, zonename)) { /* overreaching */ return 1; } } /* all NSEC RRs OK */ return 0; }
/** get additional name from rrset RR, return false if no name present */ static int get_additional_name(struct rrset_parse* rrset, struct rr_parse* rr, uint8_t** nm, size_t* nmlen, sldns_buffer* pkt) { size_t offset = 0; size_t len, oldpos; switch(rrset->type) { case LDNS_RR_TYPE_MB: case LDNS_RR_TYPE_MD: case LDNS_RR_TYPE_MF: case LDNS_RR_TYPE_NS: offset = 0; break; case LDNS_RR_TYPE_MX: case LDNS_RR_TYPE_KX: offset = 2; break; case LDNS_RR_TYPE_SRV: offset = 6; break; case LDNS_RR_TYPE_NAPTR: /* TODO: NAPTR not supported, glue stripped off */ return 0; default: return 0; } len = sldns_read_uint16(rr->ttl_data+sizeof(uint32_t)); if(len < offset+1) return 0; /* rdata field too small */ *nm = rr->ttl_data+sizeof(uint32_t)+sizeof(uint16_t)+offset; oldpos = sldns_buffer_position(pkt); sldns_buffer_set_position(pkt, (size_t)(*nm - sldns_buffer_begin(pkt))); *nmlen = pkt_dname_len(pkt); sldns_buffer_set_position(pkt, oldpos); if(*nmlen == 0) return 0; return 1; }