int reply_info_parse(sldns_buffer* pkt, struct alloc_cache* alloc, struct query_info* qinf, struct reply_info** rep, struct regional* region, struct edns_data* edns) { /* use scratch pad region-allocator during parsing. */ struct msg_parse* msg; int ret; qinf->qname = NULL; *rep = NULL; if(!(msg = regional_alloc(region, sizeof(*msg)))) { return LDNS_RCODE_SERVFAIL; } memset(msg, 0, sizeof(*msg)); sldns_buffer_set_position(pkt, 0); if((ret = parse_packet(pkt, msg, region)) != 0) { return ret; } if((ret = parse_extract_edns(msg, edns)) != 0) return ret; /* parse OK, allocate return structures */ /* this also performs dname decompression */ if(!parse_create_msg(pkt, msg, alloc, qinf, rep, NULL)) { query_info_clear(qinf); reply_info_parsedelete(*rep, alloc); *rep = NULL; return LDNS_RCODE_SERVFAIL; } return 0; }
/* Create response according to the ldns packet content */ int createResponse(struct module_qstate* qstate, sldns_buffer* pkt) { struct msg_parse* prs; struct edns_data edns; /* parse message */ prs = (struct msg_parse*) regional_alloc(qstate->env->scratch, sizeof(struct msg_parse)); if (!prs) { log_err("storeResponse: out of memory on incoming message"); return 0; } memset(prs, 0, sizeof(*prs)); memset(&edns, 0, sizeof(edns)); sldns_buffer_set_position(pkt, 0); if (parse_packet(pkt, prs, qstate->env->scratch) != LDNS_RCODE_NOERROR) { verbose(VERB_ALGO, "storeResponse: parse error on reply packet"); return 0; } /* edns is not examined, but removed from message to help cache */ if(parse_extract_edns(prs, &edns) != LDNS_RCODE_NOERROR) return 0; /* remove CD-bit, we asked for in case we handle validation ourself */ prs->flags &= ~BIT_CD; /* allocate response dns_msg in region */ qstate->return_msg = (struct dns_msg*)regional_alloc(qstate->region, sizeof(struct dns_msg)); if (!qstate->return_msg) return 0; memset(qstate->return_msg, 0, sizeof(*qstate->return_msg)); if(!parse_create_msg(pkt, prs, NULL, &(qstate->return_msg)->qinfo, &(qstate->return_msg)->rep, qstate->region)) { log_err("storeResponse: malloc failure: allocating incoming dns_msg"); return 0; } /* Make sure that the RA flag is set (since the presence of * this module means that recursion is available) */ /* qstate->return_msg->rep->flags |= BIT_RA; */ /* Clear the AA flag */ /* FIXME: does this action go here or in some other module? */ /*qstate->return_msg->rep->flags &= ~BIT_AA; */ /* make sure QR flag is on */ /*qstate->return_msg->rep->flags |= BIT_QR; */ if(verbosity >= VERB_ALGO) log_dns_msg("storeResponse: packet:", &qstate->return_msg->qinfo, qstate->return_msg->rep); return 1; }
/** convert dns message in buffer to return_msg */ static int parse_data(struct module_qstate* qstate, struct sldns_buffer* buf) { struct msg_parse* prs; struct edns_data edns; uint64_t timestamp, expiry; time_t adjust; size_t lim = sldns_buffer_limit(buf); if(lim < LDNS_HEADER_SIZE+sizeof(timestamp)+sizeof(expiry)) return 0; /* too short */ /* remove timestamp and expiry from end */ sldns_buffer_read_at(buf, lim-sizeof(expiry), &expiry, sizeof(expiry)); sldns_buffer_read_at(buf, lim-sizeof(expiry)-sizeof(timestamp), ×tamp, sizeof(timestamp)); expiry = be64toh(expiry); timestamp = be64toh(timestamp); /* parse DNS packet */ regional_free_all(qstate->env->scratch); prs = (struct msg_parse*)regional_alloc(qstate->env->scratch, sizeof(struct msg_parse)); if(!prs) return 0; /* out of memory */ memset(prs, 0, sizeof(*prs)); memset(&edns, 0, sizeof(edns)); sldns_buffer_set_limit(buf, lim - sizeof(expiry)-sizeof(timestamp)); if(parse_packet(buf, prs, qstate->env->scratch) != LDNS_RCODE_NOERROR) { sldns_buffer_set_limit(buf, lim); return 0; } if(parse_extract_edns(prs, &edns, qstate->env->scratch) != LDNS_RCODE_NOERROR) { sldns_buffer_set_limit(buf, lim); return 0; } qstate->return_msg = dns_alloc_msg(buf, prs, qstate->region); sldns_buffer_set_limit(buf, lim); if(!qstate->return_msg) return 0; qstate->return_rcode = LDNS_RCODE_NOERROR; /* see how much of the TTL expired, and remove it */ if(*qstate->env->now <= (time_t)timestamp) { verbose(VERB_ALGO, "cachedb msg adjust by zero"); return 1; /* message from the future (clock skew?) */ } adjust = *qstate->env->now - (time_t)timestamp; if(qstate->return_msg->rep->ttl < adjust) { verbose(VERB_ALGO, "cachedb msg expired"); /* If serve-expired is enabled, we still use an expired message * setting the TTL to 0. */ if(qstate->env->cfg->serve_expired) adjust = -1; else return 0; /* message expired */ } verbose(VERB_ALGO, "cachedb msg adjusted down by %d", (int)adjust); adjust_msg_ttl(qstate->return_msg, adjust); /* Similar to the unbound worker, if serve-expired is enabled and * the msg would be considered to be expired, mark the state so a * refetch will be scheduled. The comparison between 'expiry' and * 'now' should be redundant given how these values were calculated, * but we check it just in case as does good_expiry_and_qinfo(). */ if(qstate->env->cfg->serve_expired && (adjust == -1 || (time_t)expiry < *qstate->env->now)) { qstate->need_refetch = 1; } return 1; }