/** load a msg entry */ static int load_msg(SSL* ssl, ldns_buffer* buf, struct worker* worker) { struct regional* region = worker->scratchpad; struct query_info qinf; struct reply_info rep; char* s = (char*)ldns_buffer_begin(buf); unsigned int flags, qdcount, ttl, security, an, ns, ar; size_t i; int go_on = 1; regional_free_all(region); if(strncmp(s, "msg ", 4) != 0) { log_warn("error expected msg but got %s", s); return 0; } s += 4; s = load_qinfo(s, &qinf, buf, region); if(!s) { return 0; } /* read remainder of line */ if(sscanf(s, " %u %u %u %u %u %u %u", &flags, &qdcount, &ttl, &security, &an, &ns, &ar) != 7) { log_warn("error cannot parse numbers: %s", s); return 0; } rep.flags = (uint16_t)flags; rep.qdcount = (uint16_t)qdcount; rep.ttl = (uint32_t)ttl; rep.prefetch_ttl = PREFETCH_TTL_CALC(rep.ttl); rep.security = (enum sec_status)security; rep.an_numrrsets = (size_t)an; rep.ns_numrrsets = (size_t)ns; rep.ar_numrrsets = (size_t)ar; rep.rrset_count = (size_t)an+(size_t)ns+(size_t)ar; rep.rrsets = (struct ub_packed_rrset_key**)regional_alloc_zero( region, sizeof(struct ub_packed_rrset_key*)*rep.rrset_count); /* fill repinfo with references */ for(i=0; i<rep.rrset_count; i++) { if(!load_ref(ssl, buf, worker, region, &rep.rrsets[i], &go_on)) { return 0; } } if(!go_on) return 1; /* skip this one, not all references satisfied */ if(!dns_cache_store(&worker->env, &qinf, &rep, 0, 0, 0, NULL)) { log_warn("error out of memory"); return 0; } return 1; }
/** load a msg rrset reference */ static int load_ref(SSL* ssl, sldns_buffer* buf, struct worker* worker, struct regional *region, struct ub_packed_rrset_key** rrset, int* go_on) { char* s = (char*)sldns_buffer_begin(buf); struct query_info qinfo; unsigned int flags; struct ub_packed_rrset_key* k; /* read line */ if(!ssl_read_buf(ssl, buf)) return 0; if(strncmp(s, "BADREF", 6) == 0) { *go_on = 0; /* its bad, skip it and skip message */ return 1; } s = load_qinfo(s, &qinfo, region); if(!s) { return 0; } if(sscanf(s, " %u", &flags) != 1) { log_warn("error cannot parse flags: %s", s); return 0; } /* lookup in cache */ k = rrset_cache_lookup(worker->env.rrset_cache, qinfo.qname, qinfo.qname_len, qinfo.qtype, qinfo.qclass, (uint32_t)flags, *worker->env.now, 0); if(!k) { /* not found or expired */ *go_on = 0; return 1; } /* store in result */ *rrset = packed_rrset_copy_region(k, region, *worker->env.now); lock_rw_unlock(&k->entry.lock); return (*rrset != NULL); }