/** * Store potential poison in the cache (only if hardening disabled). * The rrset is stored in the cache but removed from the message. * So that it will be used for infrastructure purposes, but not be * returned to the client. * @param pkt: packet * @param msg: message parsed * @param env: environment with cache * @param rrset: to store. */ static void store_rrset(ldns_buffer* pkt, struct msg_parse* msg, struct module_env* env, struct rrset_parse* rrset) { struct ub_packed_rrset_key* k; struct packed_rrset_data* d; struct rrset_ref ref; uint32_t now = *env->now; k = alloc_special_obtain(env->alloc); if(!k) return; k->entry.data = NULL; if(!parse_copy_decompress_rrset(pkt, msg, rrset, NULL, k)) { alloc_special_release(env->alloc, k); return; } d = (struct packed_rrset_data*)k->entry.data; packed_rrset_ttl_add(d, now); ref.key = k; ref.id = k->id; /*ignore ret: it was in the cache, ref updated */ (void)rrset_cache_update(env->rrset_cache, &ref, env->alloc, now); }
struct ub_packed_rrset_key* packed_rrset_copy_alloc(struct ub_packed_rrset_key* key, struct alloc_cache* alloc, time_t now) { struct packed_rrset_data* fd, *dd; struct ub_packed_rrset_key* dk = alloc_special_obtain(alloc); if(!dk) return NULL; fd = (struct packed_rrset_data*)key->entry.data; dk->entry.hash = key->entry.hash; dk->rk = key->rk; dk->rk.dname = (uint8_t*)memdup(key->rk.dname, key->rk.dname_len); if(!dk->rk.dname) { alloc_special_release(alloc, dk); return NULL; } dd = (struct packed_rrset_data*)memdup(fd, packed_rrset_sizeof(fd)); if(!dd) { free(dk->rk.dname); alloc_special_release(alloc, dk); return NULL; } packed_rrset_ptr_fixup(dd); dk->entry.data = (void*)dd; packed_rrset_ttl_add(dd, now); return dk; }
int dns_cache_store(struct module_env* env, struct query_info* msgqinf, struct reply_info* msgrep, int is_referral, time_t leeway, int pside, struct regional* region, uint32_t flags) { struct reply_info* rep = NULL; /* alloc, malloc properly (not in region, like msg is) */ rep = reply_info_copy(msgrep, env->alloc, NULL); if(!rep) return 0; /* ttl must be relative ;i.e. 0..86400 not time(0)+86400. * the env->now is added to message and RRsets in this routine. */ /* the leeway is used to invalidate other rrsets earlier */ if(is_referral) { /* store rrsets */ struct rrset_ref ref; size_t i; for(i=0; i<rep->rrset_count; i++) { packed_rrset_ttl_add((struct packed_rrset_data*) rep->rrsets[i]->entry.data, *env->now); ref.key = rep->rrsets[i]; ref.id = rep->rrsets[i]->id; /*ignore ret: it was in the cache, ref updated */ /* no leeway for typeNS */ (void)rrset_cache_update(env->rrset_cache, &ref, env->alloc, *env->now + ((ntohs(ref.key->rk.type)==LDNS_RR_TYPE_NS && !pside) ? 0:leeway)); } free(rep); return 1; } else { /* store msg, and rrsets */ struct query_info qinf; hashvalue_type h; qinf = *msgqinf; qinf.qname = memdup(msgqinf->qname, msgqinf->qname_len); if(!qinf.qname) { reply_info_parsedelete(rep, env->alloc); return 0; } /* fixup flags to be sensible for a reply based on the cache */ /* this module means that RA is available. It is an answer QR. * Not AA from cache. Not CD in cache (depends on client bit). */ rep->flags |= (BIT_RA | BIT_QR); rep->flags &= ~(BIT_AA | BIT_CD); h = query_info_hash(&qinf, (uint16_t)flags); dns_cache_store_msg(env, &qinf, h, rep, leeway, pside, msgrep, flags, region); /* qname is used inside query_info_entrysetup, and set to * NULL. If it has not been used, free it. free(0) is safe. */ free(qinf.qname); } return 1; }