mirror of
https://github.com/NLnetLabs/unbound.git
synced 2024-09-21 14:47:09 +00:00
- generic edns option parse and store code.
git-svn-id: file:///svn/unbound/trunk@3740 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
parent
41b78b263d
commit
40dd2acfd9
@ -406,7 +406,8 @@ parse_data(struct module_qstate* qstate, struct sldns_buffer* buf)
|
|||||||
sldns_buffer_set_limit(buf, lim);
|
sldns_buffer_set_limit(buf, lim);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if(parse_extract_edns(prs, &edns) != LDNS_RCODE_NOERROR) {
|
if(parse_extract_edns(prs, &edns, qstate->env->scratch) !=
|
||||||
|
LDNS_RCODE_NOERROR) {
|
||||||
sldns_buffer_set_limit(buf, lim);
|
sldns_buffer_set_limit(buf, lim);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -483,7 +483,6 @@ answer_norec_from_cache(struct worker* worker, struct query_info* qinfo,
|
|||||||
qinfo->qname_len, qinfo->qtype, qinfo->qclass,
|
qinfo->qname_len, qinfo->qtype, qinfo->qclass,
|
||||||
worker->scratchpad, &msg, timenow);
|
worker->scratchpad, &msg, timenow);
|
||||||
if(!dp) { /* no delegation, need to reprime */
|
if(!dp) { /* no delegation, need to reprime */
|
||||||
regional_free_all(worker->scratchpad);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if(must_validate) {
|
if(must_validate) {
|
||||||
@ -491,7 +490,6 @@ answer_norec_from_cache(struct worker* worker, struct query_info* qinfo,
|
|||||||
case sec_status_unchecked:
|
case sec_status_unchecked:
|
||||||
/* some rrsets have not been verified yet, go and
|
/* some rrsets have not been verified yet, go and
|
||||||
* let validator do that */
|
* let validator do that */
|
||||||
regional_free_all(worker->scratchpad);
|
|
||||||
return 0;
|
return 0;
|
||||||
case sec_status_bogus:
|
case sec_status_bogus:
|
||||||
/* some rrsets are bogus, reply servfail */
|
/* some rrsets are bogus, reply servfail */
|
||||||
@ -499,9 +497,10 @@ answer_norec_from_cache(struct worker* worker, struct query_info* qinfo,
|
|||||||
edns->udp_size = EDNS_ADVERTISED_SIZE;
|
edns->udp_size = EDNS_ADVERTISED_SIZE;
|
||||||
edns->ext_rcode = 0;
|
edns->ext_rcode = 0;
|
||||||
edns->bits &= EDNS_DO;
|
edns->bits &= EDNS_DO;
|
||||||
|
if(!edns_opt_inplace_reply(edns, worker->scratchpad))
|
||||||
|
return 0;
|
||||||
error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL,
|
error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL,
|
||||||
&msg->qinfo, id, flags, edns);
|
&msg->qinfo, id, flags, edns);
|
||||||
regional_free_all(worker->scratchpad);
|
|
||||||
if(worker->stats.extended) {
|
if(worker->stats.extended) {
|
||||||
worker->stats.ans_bogus++;
|
worker->stats.ans_bogus++;
|
||||||
worker->stats.ans_rcode[LDNS_RCODE_SERVFAIL]++;
|
worker->stats.ans_rcode[LDNS_RCODE_SERVFAIL]++;
|
||||||
@ -527,6 +526,8 @@ answer_norec_from_cache(struct worker* worker, struct query_info* qinfo,
|
|||||||
edns->udp_size = EDNS_ADVERTISED_SIZE;
|
edns->udp_size = EDNS_ADVERTISED_SIZE;
|
||||||
edns->ext_rcode = 0;
|
edns->ext_rcode = 0;
|
||||||
edns->bits &= EDNS_DO;
|
edns->bits &= EDNS_DO;
|
||||||
|
if(!edns_opt_inplace_reply(edns, worker->scratchpad))
|
||||||
|
return 0;
|
||||||
msg->rep->flags |= BIT_QR|BIT_RA;
|
msg->rep->flags |= BIT_QR|BIT_RA;
|
||||||
if(!reply_info_answer_encode(&msg->qinfo, msg->rep, id, flags,
|
if(!reply_info_answer_encode(&msg->qinfo, msg->rep, id, flags,
|
||||||
repinfo->c->buffer, 0, 1, worker->scratchpad,
|
repinfo->c->buffer, 0, 1, worker->scratchpad,
|
||||||
@ -534,7 +535,6 @@ answer_norec_from_cache(struct worker* worker, struct query_info* qinfo,
|
|||||||
error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL,
|
error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL,
|
||||||
&msg->qinfo, id, flags, edns);
|
&msg->qinfo, id, flags, edns);
|
||||||
}
|
}
|
||||||
regional_free_all(worker->scratchpad);
|
|
||||||
if(worker->stats.extended) {
|
if(worker->stats.extended) {
|
||||||
if(secure) worker->stats.ans_secure++;
|
if(secure) worker->stats.ans_secure++;
|
||||||
server_stats_insrcode(&worker->stats, repinfo->c->buffer);
|
server_stats_insrcode(&worker->stats, repinfo->c->buffer);
|
||||||
@ -574,7 +574,6 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo,
|
|||||||
bail_out:
|
bail_out:
|
||||||
rrset_array_unlock_touch(worker->env.rrset_cache,
|
rrset_array_unlock_touch(worker->env.rrset_cache,
|
||||||
worker->scratchpad, rep->ref, rep->rrset_count);
|
worker->scratchpad, rep->ref, rep->rrset_count);
|
||||||
regional_free_all(worker->scratchpad);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -585,11 +584,12 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo,
|
|||||||
edns->udp_size = EDNS_ADVERTISED_SIZE;
|
edns->udp_size = EDNS_ADVERTISED_SIZE;
|
||||||
edns->ext_rcode = 0;
|
edns->ext_rcode = 0;
|
||||||
edns->bits &= EDNS_DO;
|
edns->bits &= EDNS_DO;
|
||||||
|
if(!edns_opt_inplace_reply(edns, worker->scratchpad))
|
||||||
|
return 0;
|
||||||
error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL,
|
error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL,
|
||||||
qinfo, id, flags, edns);
|
qinfo, id, flags, edns);
|
||||||
rrset_array_unlock_touch(worker->env.rrset_cache,
|
rrset_array_unlock_touch(worker->env.rrset_cache,
|
||||||
worker->scratchpad, rep->ref, rep->rrset_count);
|
worker->scratchpad, rep->ref, rep->rrset_count);
|
||||||
regional_free_all(worker->scratchpad);
|
|
||||||
if(worker->stats.extended) {
|
if(worker->stats.extended) {
|
||||||
worker->stats.ans_bogus ++;
|
worker->stats.ans_bogus ++;
|
||||||
worker->stats.ans_rcode[LDNS_RCODE_SERVFAIL] ++;
|
worker->stats.ans_rcode[LDNS_RCODE_SERVFAIL] ++;
|
||||||
@ -616,6 +616,8 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo,
|
|||||||
edns->udp_size = EDNS_ADVERTISED_SIZE;
|
edns->udp_size = EDNS_ADVERTISED_SIZE;
|
||||||
edns->ext_rcode = 0;
|
edns->ext_rcode = 0;
|
||||||
edns->bits &= EDNS_DO;
|
edns->bits &= EDNS_DO;
|
||||||
|
if(!edns_opt_inplace_reply(edns, worker->scratchpad))
|
||||||
|
return 0;
|
||||||
if(!reply_info_answer_encode(qinfo, rep, id, flags,
|
if(!reply_info_answer_encode(qinfo, rep, id, flags,
|
||||||
repinfo->c->buffer, timenow, 1, worker->scratchpad,
|
repinfo->c->buffer, timenow, 1, worker->scratchpad,
|
||||||
udpsize, edns, (int)(edns->bits & EDNS_DO), secure)) {
|
udpsize, edns, (int)(edns->bits & EDNS_DO), secure)) {
|
||||||
@ -626,7 +628,6 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo,
|
|||||||
* is bad while holding locks. */
|
* is bad while holding locks. */
|
||||||
rrset_array_unlock_touch(worker->env.rrset_cache, worker->scratchpad,
|
rrset_array_unlock_touch(worker->env.rrset_cache, worker->scratchpad,
|
||||||
rep->ref, rep->rrset_count);
|
rep->ref, rep->rrset_count);
|
||||||
regional_free_all(worker->scratchpad);
|
|
||||||
if(worker->stats.extended) {
|
if(worker->stats.extended) {
|
||||||
if(secure) worker->stats.ans_secure++;
|
if(secure) worker->stats.ans_secure++;
|
||||||
server_stats_insrcode(&worker->stats, repinfo->c->buffer);
|
server_stats_insrcode(&worker->stats, repinfo->c->buffer);
|
||||||
@ -660,7 +661,8 @@ reply_and_prefetch(struct worker* worker, struct query_info* qinfo,
|
|||||||
* @param edns: edns reply information.
|
* @param edns: edns reply information.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
chaos_replystr(sldns_buffer* pkt, const char* str, struct edns_data* edns)
|
chaos_replystr(sldns_buffer* pkt, const char* str, struct edns_data* edns,
|
||||||
|
struct worker* worker)
|
||||||
{
|
{
|
||||||
size_t len = strlen(str);
|
size_t len = strlen(str);
|
||||||
unsigned int rd = LDNS_RD_WIRE(sldns_buffer_begin(pkt));
|
unsigned int rd = LDNS_RD_WIRE(sldns_buffer_begin(pkt));
|
||||||
@ -689,6 +691,8 @@ chaos_replystr(sldns_buffer* pkt, const char* str, struct edns_data* edns)
|
|||||||
edns->edns_version = EDNS_ADVERTISED_VERSION;
|
edns->edns_version = EDNS_ADVERTISED_VERSION;
|
||||||
edns->udp_size = EDNS_ADVERTISED_SIZE;
|
edns->udp_size = EDNS_ADVERTISED_SIZE;
|
||||||
edns->bits &= EDNS_DO;
|
edns->bits &= EDNS_DO;
|
||||||
|
if(!edns_opt_inplace_reply(edns, worker->scratchpad))
|
||||||
|
edns->opt_list = NULL;
|
||||||
attach_edns_record(pkt, edns);
|
attach_edns_record(pkt, edns);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -718,13 +722,13 @@ answer_chaos(struct worker* w, struct query_info* qinfo,
|
|||||||
char buf[MAXHOSTNAMELEN+1];
|
char buf[MAXHOSTNAMELEN+1];
|
||||||
if (gethostname(buf, MAXHOSTNAMELEN) == 0) {
|
if (gethostname(buf, MAXHOSTNAMELEN) == 0) {
|
||||||
buf[MAXHOSTNAMELEN] = 0;
|
buf[MAXHOSTNAMELEN] = 0;
|
||||||
chaos_replystr(pkt, buf, edns);
|
chaos_replystr(pkt, buf, edns, w);
|
||||||
} else {
|
} else {
|
||||||
log_err("gethostname: %s", strerror(errno));
|
log_err("gethostname: %s", strerror(errno));
|
||||||
chaos_replystr(pkt, "no hostname", edns);
|
chaos_replystr(pkt, "no hostname", edns, w);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else chaos_replystr(pkt, cfg->identity, edns);
|
else chaos_replystr(pkt, cfg->identity, edns, w);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if(query_dname_compare(qinfo->qname,
|
if(query_dname_compare(qinfo->qname,
|
||||||
@ -735,8 +739,8 @@ answer_chaos(struct worker* w, struct query_info* qinfo,
|
|||||||
if(cfg->hide_version)
|
if(cfg->hide_version)
|
||||||
return 0;
|
return 0;
|
||||||
if(cfg->version==NULL || cfg->version[0]==0)
|
if(cfg->version==NULL || cfg->version[0]==0)
|
||||||
chaos_replystr(pkt, PACKAGE_STRING, edns);
|
chaos_replystr(pkt, PACKAGE_STRING, edns, w);
|
||||||
else chaos_replystr(pkt, cfg->version, edns);
|
else chaos_replystr(pkt, cfg->version, edns, w);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@ -865,7 +869,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
|||||||
}
|
}
|
||||||
goto send_reply;
|
goto send_reply;
|
||||||
}
|
}
|
||||||
if((ret=parse_edns_from_pkt(c->buffer, &edns)) != 0) {
|
if((ret=parse_edns_from_pkt(c->buffer, &edns, worker->scratchpad)) != 0) {
|
||||||
struct edns_data reply_edns;
|
struct edns_data reply_edns;
|
||||||
verbose(VERB_ALGO, "worker parse edns: formerror.");
|
verbose(VERB_ALGO, "worker parse edns: formerror.");
|
||||||
log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
|
log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
|
||||||
@ -876,6 +880,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
|||||||
error_encode(c->buffer, ret, &qinfo,
|
error_encode(c->buffer, ret, &qinfo,
|
||||||
*(uint16_t*)(void *)sldns_buffer_begin(c->buffer),
|
*(uint16_t*)(void *)sldns_buffer_begin(c->buffer),
|
||||||
sldns_buffer_read_u16_at(c->buffer, 2), &reply_edns);
|
sldns_buffer_read_u16_at(c->buffer, 2), &reply_edns);
|
||||||
|
regional_free_all(worker->scratchpad);
|
||||||
server_stats_insrcode(&worker->stats, c->buffer);
|
server_stats_insrcode(&worker->stats, c->buffer);
|
||||||
goto send_reply;
|
goto send_reply;
|
||||||
}
|
}
|
||||||
@ -884,12 +889,14 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
|||||||
edns.edns_version = EDNS_ADVERTISED_VERSION;
|
edns.edns_version = EDNS_ADVERTISED_VERSION;
|
||||||
edns.udp_size = EDNS_ADVERTISED_SIZE;
|
edns.udp_size = EDNS_ADVERTISED_SIZE;
|
||||||
edns.bits &= EDNS_DO;
|
edns.bits &= EDNS_DO;
|
||||||
|
edns.opt_list = NULL;
|
||||||
verbose(VERB_ALGO, "query with bad edns version.");
|
verbose(VERB_ALGO, "query with bad edns version.");
|
||||||
log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
|
log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
|
||||||
error_encode(c->buffer, EDNS_RCODE_BADVERS&0xf, &qinfo,
|
error_encode(c->buffer, EDNS_RCODE_BADVERS&0xf, &qinfo,
|
||||||
*(uint16_t*)(void *)sldns_buffer_begin(c->buffer),
|
*(uint16_t*)(void *)sldns_buffer_begin(c->buffer),
|
||||||
sldns_buffer_read_u16_at(c->buffer, 2), NULL);
|
sldns_buffer_read_u16_at(c->buffer, 2), NULL);
|
||||||
attach_edns_record(c->buffer, &edns);
|
attach_edns_record(c->buffer, &edns);
|
||||||
|
regional_free_all(worker->scratchpad);
|
||||||
goto send_reply;
|
goto send_reply;
|
||||||
}
|
}
|
||||||
if(edns.edns_present && edns.udp_size < NORMAL_UDP_SIZE &&
|
if(edns.edns_present && edns.udp_size < NORMAL_UDP_SIZE &&
|
||||||
@ -918,6 +925,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
|||||||
sldns_buffer_write_at(c->buffer, 4,
|
sldns_buffer_write_at(c->buffer, 4,
|
||||||
(uint8_t*)"\0\0\0\0\0\0\0\0", 8);
|
(uint8_t*)"\0\0\0\0\0\0\0\0", 8);
|
||||||
sldns_buffer_flip(c->buffer);
|
sldns_buffer_flip(c->buffer);
|
||||||
|
regional_free_all(worker->scratchpad);
|
||||||
goto send_reply;
|
goto send_reply;
|
||||||
}
|
}
|
||||||
if(worker->stats.extended)
|
if(worker->stats.extended)
|
||||||
@ -928,6 +936,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
|||||||
if(qinfo.qclass == LDNS_RR_CLASS_CH && answer_chaos(worker, &qinfo,
|
if(qinfo.qclass == LDNS_RR_CLASS_CH && answer_chaos(worker, &qinfo,
|
||||||
&edns, c->buffer)) {
|
&edns, c->buffer)) {
|
||||||
server_stats_insrcode(&worker->stats, c->buffer);
|
server_stats_insrcode(&worker->stats, c->buffer);
|
||||||
|
regional_free_all(worker->scratchpad);
|
||||||
goto send_reply;
|
goto send_reply;
|
||||||
}
|
}
|
||||||
if(local_zones_answer(worker->daemon->local_zones, &qinfo, &edns,
|
if(local_zones_answer(worker->daemon->local_zones, &qinfo, &edns,
|
||||||
@ -945,6 +954,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
|||||||
* might need to bail out based on ACLs now. */
|
* might need to bail out based on ACLs now. */
|
||||||
if((ret=deny_refuse_non_local(c, acl, worker, repinfo)) != -1)
|
if((ret=deny_refuse_non_local(c, acl, worker, repinfo)) != -1)
|
||||||
{
|
{
|
||||||
|
regional_free_all(worker->scratchpad);
|
||||||
if(ret == 1)
|
if(ret == 1)
|
||||||
goto send_reply;
|
goto send_reply;
|
||||||
return ret;
|
return ret;
|
||||||
@ -961,6 +971,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
|||||||
LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
|
LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
|
||||||
LDNS_RCODE_REFUSED);
|
LDNS_RCODE_REFUSED);
|
||||||
sldns_buffer_flip(c->buffer);
|
sldns_buffer_flip(c->buffer);
|
||||||
|
regional_free_all(worker->scratchpad);
|
||||||
server_stats_insrcode(&worker->stats, c->buffer);
|
server_stats_insrcode(&worker->stats, c->buffer);
|
||||||
log_addr(VERB_ALGO, "refused nonrec (cache snoop) query from",
|
log_addr(VERB_ALGO, "refused nonrec (cache snoop) query from",
|
||||||
&repinfo->addr, repinfo->addrlen);
|
&repinfo->addr, repinfo->addrlen);
|
||||||
@ -984,9 +995,11 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
|||||||
sldns_buffer_read_u16_at(c->buffer, 2),
|
sldns_buffer_read_u16_at(c->buffer, 2),
|
||||||
repinfo, leeway);
|
repinfo, leeway);
|
||||||
rc = 0;
|
rc = 0;
|
||||||
|
regional_free_all(worker->scratchpad);
|
||||||
goto send_reply_rc;
|
goto send_reply_rc;
|
||||||
}
|
}
|
||||||
lock_rw_unlock(&e->lock);
|
lock_rw_unlock(&e->lock);
|
||||||
|
regional_free_all(worker->scratchpad);
|
||||||
goto send_reply;
|
goto send_reply;
|
||||||
}
|
}
|
||||||
verbose(VERB_ALGO, "answer from the cache failed");
|
verbose(VERB_ALGO, "answer from the cache failed");
|
||||||
@ -997,6 +1010,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
|||||||
*(uint16_t*)(void *)sldns_buffer_begin(c->buffer),
|
*(uint16_t*)(void *)sldns_buffer_begin(c->buffer),
|
||||||
sldns_buffer_read_u16_at(c->buffer, 2), repinfo,
|
sldns_buffer_read_u16_at(c->buffer, 2), repinfo,
|
||||||
&edns)) {
|
&edns)) {
|
||||||
|
regional_free_all(worker->scratchpad);
|
||||||
goto send_reply;
|
goto send_reply;
|
||||||
}
|
}
|
||||||
verbose(VERB_ALGO, "answer norec from cache -- "
|
verbose(VERB_ALGO, "answer norec from cache -- "
|
||||||
@ -1017,6 +1031,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
|||||||
mesh_new_client(worker->env.mesh, &qinfo,
|
mesh_new_client(worker->env.mesh, &qinfo,
|
||||||
sldns_buffer_read_u16_at(c->buffer, 2),
|
sldns_buffer_read_u16_at(c->buffer, 2),
|
||||||
&edns, repinfo, *(uint16_t*)(void *)sldns_buffer_begin(c->buffer));
|
&edns, repinfo, *(uint16_t*)(void *)sldns_buffer_begin(c->buffer));
|
||||||
|
regional_free_all(worker->scratchpad);
|
||||||
worker_mem_report(worker, NULL);
|
worker_mem_report(worker, NULL);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
- Fix windows service to be created run with limited rights, as a
|
- Fix windows service to be created run with limited rights, as a
|
||||||
network service account, from Mario Turschmann.
|
network service account, from Mario Turschmann.
|
||||||
- compat strsep implementation.
|
- compat strsep implementation.
|
||||||
|
- generic edns option parse and store code.
|
||||||
|
|
||||||
30 May 2016: Wouter
|
30 May 2016: Wouter
|
||||||
- Fix time in case answer comes from cache in ub_resolve_event().
|
- Fix time in case answer comes from cache in ub_resolve_event().
|
||||||
|
@ -3124,7 +3124,8 @@ process_response(struct module_qstate* qstate, struct iter_qstate* iq,
|
|||||||
goto handle_it;
|
goto handle_it;
|
||||||
}
|
}
|
||||||
/* edns is not examined, but removed from message to help cache */
|
/* edns is not examined, but removed from message to help cache */
|
||||||
if(parse_extract_edns(prs, &edns) != LDNS_RCODE_NOERROR)
|
if(parse_extract_edns(prs, &edns, qstate->env->scratch) !=
|
||||||
|
LDNS_RCODE_NOERROR)
|
||||||
goto handle_it;
|
goto handle_it;
|
||||||
/* remove CD-bit, we asked for in case we handle validation ourself */
|
/* remove CD-bit, we asked for in case we handle validation ourself */
|
||||||
prs->flags &= ~BIT_CD;
|
prs->flags &= ~BIT_CD;
|
||||||
|
@ -129,7 +129,8 @@ int createResponse(struct module_qstate* qstate, sldns_buffer* pkt)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/* edns is not examined, but removed from message to help cache */
|
/* edns is not examined, but removed from message to help cache */
|
||||||
if(parse_extract_edns(prs, &edns) != LDNS_RCODE_NOERROR)
|
if(parse_extract_edns(prs, &edns, qstate->env->scratch) !=
|
||||||
|
LDNS_RCODE_NOERROR)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* remove CD-bit, we asked for in case we handle validation ourself */
|
/* remove CD-bit, we asked for in case we handle validation ourself */
|
||||||
|
@ -1042,7 +1042,8 @@ local_encode(struct query_info* qinfo, struct edns_data* edns,
|
|||||||
edns->udp_size = EDNS_ADVERTISED_SIZE;
|
edns->udp_size = EDNS_ADVERTISED_SIZE;
|
||||||
edns->ext_rcode = 0;
|
edns->ext_rcode = 0;
|
||||||
edns->bits &= EDNS_DO;
|
edns->bits &= EDNS_DO;
|
||||||
if(!reply_info_answer_encode(qinfo, &rep,
|
if(!edns_opt_inplace_reply(edns, temp) ||
|
||||||
|
!reply_info_answer_encode(qinfo, &rep,
|
||||||
*(uint16_t*)sldns_buffer_begin(buf),
|
*(uint16_t*)sldns_buffer_begin(buf),
|
||||||
sldns_buffer_read_u16_at(buf, 2),
|
sldns_buffer_read_u16_at(buf, 2),
|
||||||
buf, 0, 0, temp, udpsize, edns,
|
buf, 0, 0, temp, udpsize, edns,
|
||||||
|
@ -315,6 +315,8 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
|
|||||||
s = mesh_state_create(mesh->env, qinfo, qflags&(BIT_RD|BIT_CD), 0, 0);
|
s = mesh_state_create(mesh->env, qinfo, qflags&(BIT_RD|BIT_CD), 0, 0);
|
||||||
if(!s) {
|
if(!s) {
|
||||||
log_err("mesh_state_create: out of memory; SERVFAIL");
|
log_err("mesh_state_create: out of memory; SERVFAIL");
|
||||||
|
if(!edns_opt_inplace_reply(edns, mesh->env->scratch))
|
||||||
|
edns->opt_list = NULL;
|
||||||
error_encode(rep->c->buffer, LDNS_RCODE_SERVFAIL,
|
error_encode(rep->c->buffer, LDNS_RCODE_SERVFAIL,
|
||||||
qinfo, qid, qflags, edns);
|
qinfo, qid, qflags, edns);
|
||||||
comm_point_send_reply(rep);
|
comm_point_send_reply(rep);
|
||||||
@ -338,6 +340,8 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
|
|||||||
/* add reply to s */
|
/* add reply to s */
|
||||||
if(!mesh_state_add_reply(s, edns, rep, qid, qflags, qinfo->qname)) {
|
if(!mesh_state_add_reply(s, edns, rep, qid, qflags, qinfo->qname)) {
|
||||||
log_err("mesh_new_client: out of memory; SERVFAIL");
|
log_err("mesh_new_client: out of memory; SERVFAIL");
|
||||||
|
if(!edns_opt_inplace_reply(edns, mesh->env->scratch))
|
||||||
|
edns->opt_list = NULL;
|
||||||
error_encode(rep->c->buffer, LDNS_RCODE_SERVFAIL,
|
error_encode(rep->c->buffer, LDNS_RCODE_SERVFAIL,
|
||||||
qinfo, qid, qflags, edns);
|
qinfo, qid, qflags, edns);
|
||||||
comm_point_send_reply(rep);
|
comm_point_send_reply(rep);
|
||||||
@ -809,7 +813,8 @@ mesh_do_callback(struct mesh_state* m, int rcode, struct reply_info* rep,
|
|||||||
r->edns.udp_size = EDNS_ADVERTISED_SIZE;
|
r->edns.udp_size = EDNS_ADVERTISED_SIZE;
|
||||||
r->edns.ext_rcode = 0;
|
r->edns.ext_rcode = 0;
|
||||||
r->edns.bits &= EDNS_DO;
|
r->edns.bits &= EDNS_DO;
|
||||||
if(!reply_info_answer_encode(&m->s.qinfo, rep, r->qid,
|
if(!edns_opt_inplace_reply(&r->edns, m->s.region) ||
|
||||||
|
!reply_info_answer_encode(&m->s.qinfo, rep, r->qid,
|
||||||
r->qflags, r->buf, 0, 1,
|
r->qflags, r->buf, 0, 1,
|
||||||
m->s.env->scratch, udp_size, &r->edns,
|
m->s.env->scratch, udp_size, &r->edns,
|
||||||
(int)(r->edns.bits & EDNS_DO), secure))
|
(int)(r->edns.bits & EDNS_DO), secure))
|
||||||
@ -859,7 +864,8 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep,
|
|||||||
if(prev && prev->qflags == r->qflags &&
|
if(prev && prev->qflags == r->qflags &&
|
||||||
prev->edns.edns_present == r->edns.edns_present &&
|
prev->edns.edns_present == r->edns.edns_present &&
|
||||||
prev->edns.bits == r->edns.bits &&
|
prev->edns.bits == r->edns.bits &&
|
||||||
prev->edns.udp_size == r->edns.udp_size) {
|
prev->edns.udp_size == r->edns.udp_size &&
|
||||||
|
edns_opt_list_equal(prev->edns.opt_list, r->edns.opt_list)) {
|
||||||
/* if the previous reply is identical to this one, fix ID */
|
/* if the previous reply is identical to this one, fix ID */
|
||||||
if(prev->query_reply.c->buffer != r->query_reply.c->buffer)
|
if(prev->query_reply.c->buffer != r->query_reply.c->buffer)
|
||||||
sldns_buffer_copy(r->query_reply.c->buffer,
|
sldns_buffer_copy(r->query_reply.c->buffer,
|
||||||
@ -881,7 +887,8 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep,
|
|||||||
r->edns.ext_rcode = 0;
|
r->edns.ext_rcode = 0;
|
||||||
r->edns.bits &= EDNS_DO;
|
r->edns.bits &= EDNS_DO;
|
||||||
m->s.qinfo.qname = r->qname;
|
m->s.qinfo.qname = r->qname;
|
||||||
if(!reply_info_answer_encode(&m->s.qinfo, rep, r->qid,
|
if(!edns_opt_inplace_reply(&r->edns, m->s.region) ||
|
||||||
|
!reply_info_answer_encode(&m->s.qinfo, rep, r->qid,
|
||||||
r->qflags, r->query_reply.c->buffer, 0, 1,
|
r->qflags, r->query_reply.c->buffer, 0, 1,
|
||||||
m->s.env->scratch, udp_size, &r->edns,
|
m->s.env->scratch, udp_size, &r->edns,
|
||||||
(int)(r->edns.bits & EDNS_DO), secure))
|
(int)(r->edns.bits & EDNS_DO), secure))
|
||||||
@ -973,6 +980,12 @@ int mesh_state_add_cb(struct mesh_state* s, struct edns_data* edns,
|
|||||||
r->cb = cb;
|
r->cb = cb;
|
||||||
r->cb_arg = cb_arg;
|
r->cb_arg = cb_arg;
|
||||||
r->edns = *edns;
|
r->edns = *edns;
|
||||||
|
if(edns->opt_list) {
|
||||||
|
r->edns.opt_list = edns_opt_copy_region(edns->opt_list,
|
||||||
|
s->s.region);
|
||||||
|
if(!r->edns.opt_list)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
r->qid = qid;
|
r->qid = qid;
|
||||||
r->qflags = qflags;
|
r->qflags = qflags;
|
||||||
r->next = s->cb_list;
|
r->next = s->cb_list;
|
||||||
@ -990,6 +1003,12 @@ int mesh_state_add_reply(struct mesh_state* s, struct edns_data* edns,
|
|||||||
return 0;
|
return 0;
|
||||||
r->query_reply = *rep;
|
r->query_reply = *rep;
|
||||||
r->edns = *edns;
|
r->edns = *edns;
|
||||||
|
if(edns->opt_list) {
|
||||||
|
r->edns.opt_list = edns_opt_copy_region(edns->opt_list,
|
||||||
|
s->s.region);
|
||||||
|
if(!r->edns.opt_list)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
r->qid = qid;
|
r->qid = qid;
|
||||||
r->qflags = qflags;
|
r->qflags = qflags;
|
||||||
r->start_time = *s->s.env->now_tv;
|
r->start_time = *s->s.env->now_tv;
|
||||||
@ -1000,7 +1019,6 @@ int mesh_state_add_reply(struct mesh_state* s, struct edns_data* edns,
|
|||||||
return 0;
|
return 0;
|
||||||
s->reply_list = r;
|
s->reply_list = r;
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1077,6 +1077,7 @@ struct serviced_query* outnet_serviced_query(struct outside_network* outnet,
|
|||||||
edns.edns_version = EDNS_ADVERTISED_VERSION;
|
edns.edns_version = EDNS_ADVERTISED_VERSION;
|
||||||
edns.udp_size = EDNS_ADVERTISED_SIZE;
|
edns.udp_size = EDNS_ADVERTISED_SIZE;
|
||||||
edns.bits = 0;
|
edns.bits = 0;
|
||||||
|
edns.opt_list = NULL;
|
||||||
if(dnssec)
|
if(dnssec)
|
||||||
edns.bits = EDNS_DO;
|
edns.bits = EDNS_DO;
|
||||||
attach_edns_record(pend->buffer, &edns);
|
attach_edns_record(pend->buffer, &edns);
|
||||||
|
@ -717,16 +717,23 @@ reply_info_encode(struct query_info* qinfo, struct reply_info* rep,
|
|||||||
uint16_t
|
uint16_t
|
||||||
calc_edns_field_size(struct edns_data* edns)
|
calc_edns_field_size(struct edns_data* edns)
|
||||||
{
|
{
|
||||||
|
size_t rdatalen = 0;
|
||||||
|
struct edns_option* opt;
|
||||||
if(!edns || !edns->edns_present)
|
if(!edns || !edns->edns_present)
|
||||||
return 0;
|
return 0;
|
||||||
/* domain root '.' + type + class + ttl + rdatalen(=0) */
|
for(opt = edns->opt_list; opt; opt = opt->next) {
|
||||||
return 1 + 2 + 2 + 4 + 2;
|
rdatalen += 4 + opt->opt_len;
|
||||||
|
}
|
||||||
|
/* domain root '.' + type + class + ttl + rdatalen */
|
||||||
|
return 1 + 2 + 2 + 4 + 2 + rdatalen;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
attach_edns_record(sldns_buffer* pkt, struct edns_data* edns)
|
attach_edns_record(sldns_buffer* pkt, struct edns_data* edns)
|
||||||
{
|
{
|
||||||
size_t len;
|
size_t len;
|
||||||
|
size_t rdatapos;
|
||||||
|
struct edns_option* opt;
|
||||||
if(!edns || !edns->edns_present)
|
if(!edns || !edns->edns_present)
|
||||||
return;
|
return;
|
||||||
/* inc additional count */
|
/* inc additional count */
|
||||||
@ -742,7 +749,18 @@ attach_edns_record(sldns_buffer* pkt, struct edns_data* edns)
|
|||||||
sldns_buffer_write_u8(pkt, edns->ext_rcode); /* ttl */
|
sldns_buffer_write_u8(pkt, edns->ext_rcode); /* ttl */
|
||||||
sldns_buffer_write_u8(pkt, edns->edns_version);
|
sldns_buffer_write_u8(pkt, edns->edns_version);
|
||||||
sldns_buffer_write_u16(pkt, edns->bits);
|
sldns_buffer_write_u16(pkt, edns->bits);
|
||||||
|
rdatapos = sldns_buffer_position(pkt);
|
||||||
sldns_buffer_write_u16(pkt, 0); /* rdatalen */
|
sldns_buffer_write_u16(pkt, 0); /* rdatalen */
|
||||||
|
/* write rdata */
|
||||||
|
for(opt=edns->opt_list; opt; opt=opt->next) {
|
||||||
|
sldns_buffer_write_u16(pkt, opt->opt_code);
|
||||||
|
sldns_buffer_write_u16(pkt, opt->opt_len);
|
||||||
|
if(opt->opt_len != 0)
|
||||||
|
sldns_buffer_write(pkt, opt->opt_data, opt->opt_len);
|
||||||
|
}
|
||||||
|
if(edns->opt_list)
|
||||||
|
sldns_buffer_write_u16_at(pkt, rdatapos,
|
||||||
|
sldns_buffer_position(pkt)-rdatapos-2);
|
||||||
sldns_buffer_flip(pkt);
|
sldns_buffer_flip(pkt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,6 +38,7 @@
|
|||||||
*/
|
*/
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "util/data/msgparse.h"
|
#include "util/data/msgparse.h"
|
||||||
|
#include "util/data/msgreply.h"
|
||||||
#include "util/data/dname.h"
|
#include "util/data/dname.h"
|
||||||
#include "util/data/packed_rrset.h"
|
#include "util/data/packed_rrset.h"
|
||||||
#include "util/storage/lookup3.h"
|
#include "util/storage/lookup3.h"
|
||||||
@ -933,13 +934,41 @@ parse_packet(sldns_buffer* pkt, struct msg_parse* msg, struct regional* region)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** parse EDNS options from EDNS wireformat rdata */
|
||||||
|
static int
|
||||||
|
parse_edns_options(uint8_t* rdata_ptr, size_t rdata_len,
|
||||||
|
struct edns_data* edns, struct regional* region)
|
||||||
|
{
|
||||||
|
/* while still more options, and have code+len to read */
|
||||||
|
/* ignores partial content (i.e. rdata len 3) */
|
||||||
|
while(rdata_len >= 4) {
|
||||||
|
uint16_t opt_code = sldns_read_uint16(rdata_ptr);
|
||||||
|
uint16_t opt_len = sldns_read_uint16(rdata_ptr+2);
|
||||||
|
rdata_ptr += 4;
|
||||||
|
rdata_len -= 4;
|
||||||
|
if(opt_len > rdata_len)
|
||||||
|
break; /* option code partial */
|
||||||
|
if(!edns_opt_append(edns, region, opt_code, opt_len,
|
||||||
|
rdata_ptr)) {
|
||||||
|
log_err("out of memory");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
rdata_ptr += opt_len;
|
||||||
|
rdata_len -= opt_len;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
parse_extract_edns(struct msg_parse* msg, struct edns_data* edns)
|
parse_extract_edns(struct msg_parse* msg, struct edns_data* edns,
|
||||||
|
struct regional* region)
|
||||||
{
|
{
|
||||||
struct rrset_parse* rrset = msg->rrset_first;
|
struct rrset_parse* rrset = msg->rrset_first;
|
||||||
struct rrset_parse* prev = 0;
|
struct rrset_parse* prev = 0;
|
||||||
struct rrset_parse* found = 0;
|
struct rrset_parse* found = 0;
|
||||||
struct rrset_parse* found_prev = 0;
|
struct rrset_parse* found_prev = 0;
|
||||||
|
size_t rdata_len;
|
||||||
|
uint8_t* rdata_ptr;
|
||||||
/* since the class encodes the UDP size, we cannot use hash table to
|
/* since the class encodes the UDP size, we cannot use hash table to
|
||||||
* find the EDNS OPT record. Scan the packet. */
|
* find the EDNS OPT record. Scan the packet. */
|
||||||
while(rrset) {
|
while(rrset) {
|
||||||
@ -986,13 +1015,25 @@ parse_extract_edns(struct msg_parse* msg, struct edns_data* edns)
|
|||||||
edns->edns_version = found->rr_last->ttl_data[1];
|
edns->edns_version = found->rr_last->ttl_data[1];
|
||||||
edns->bits = sldns_read_uint16(&found->rr_last->ttl_data[2]);
|
edns->bits = sldns_read_uint16(&found->rr_last->ttl_data[2]);
|
||||||
edns->udp_size = ntohs(found->rrset_class);
|
edns->udp_size = ntohs(found->rrset_class);
|
||||||
/* ignore rdata and rrsigs */
|
edns->opt_list = NULL;
|
||||||
|
|
||||||
|
/* take the options */
|
||||||
|
rdata_len = found->rr_first->size;
|
||||||
|
rdata_ptr = found->rr_first->ttl_data+6;
|
||||||
|
if(!parse_edns_options(rdata_ptr, rdata_len, edns, region))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* ignore rrsigs */
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
parse_edns_from_pkt(sldns_buffer* pkt, struct edns_data* edns)
|
parse_edns_from_pkt(sldns_buffer* pkt, struct edns_data* edns,
|
||||||
|
struct regional* region)
|
||||||
{
|
{
|
||||||
|
size_t rdata_len;
|
||||||
|
uint8_t* rdata_ptr;
|
||||||
log_assert(LDNS_QDCOUNT(sldns_buffer_begin(pkt)) == 1);
|
log_assert(LDNS_QDCOUNT(sldns_buffer_begin(pkt)) == 1);
|
||||||
log_assert(LDNS_ANCOUNT(sldns_buffer_begin(pkt)) == 0);
|
log_assert(LDNS_ANCOUNT(sldns_buffer_begin(pkt)) == 0);
|
||||||
log_assert(LDNS_NSCOUNT(sldns_buffer_begin(pkt)) == 0);
|
log_assert(LDNS_NSCOUNT(sldns_buffer_begin(pkt)) == 0);
|
||||||
@ -1017,6 +1058,17 @@ parse_edns_from_pkt(sldns_buffer* pkt, struct edns_data* edns)
|
|||||||
edns->ext_rcode = sldns_buffer_read_u8(pkt); /* ttl used for bits */
|
edns->ext_rcode = sldns_buffer_read_u8(pkt); /* ttl used for bits */
|
||||||
edns->edns_version = sldns_buffer_read_u8(pkt);
|
edns->edns_version = sldns_buffer_read_u8(pkt);
|
||||||
edns->bits = sldns_buffer_read_u16(pkt);
|
edns->bits = sldns_buffer_read_u16(pkt);
|
||||||
/* ignore rdata and rrsigs */
|
edns->opt_list = NULL;
|
||||||
|
|
||||||
|
/* take the options */
|
||||||
|
rdata_len = sldns_buffer_read_u16(pkt);
|
||||||
|
if(sldns_buffer_remaining(pkt) < rdata_len)
|
||||||
|
return LDNS_RCODE_FORMERR;
|
||||||
|
rdata_ptr = sldns_buffer_current(pkt);
|
||||||
|
if(!parse_edns_options(rdata_ptr, rdata_len, edns, region))
|
||||||
|
return LDNS_RCODE_SERVFAIL;
|
||||||
|
|
||||||
|
/* ignore rrsigs */
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -69,6 +69,7 @@ struct sldns_buffer;
|
|||||||
struct rrset_parse;
|
struct rrset_parse;
|
||||||
struct rr_parse;
|
struct rr_parse;
|
||||||
struct regional;
|
struct regional;
|
||||||
|
struct edns_option;
|
||||||
|
|
||||||
/** number of buckets in parse rrset hash table. Must be power of 2. */
|
/** number of buckets in parse rrset hash table. Must be power of 2. */
|
||||||
#define PARSE_TABLE_SIZE 32
|
#define PARSE_TABLE_SIZE 32
|
||||||
@ -202,7 +203,8 @@ struct rr_parse {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* EDNS data storage
|
* EDNS data storage
|
||||||
* EDNS rdata is ignored.
|
* rdata is parsed in a list (has accessor functions). allocated in a
|
||||||
|
* region.
|
||||||
*/
|
*/
|
||||||
struct edns_data {
|
struct edns_data {
|
||||||
/** if EDNS OPT record was present */
|
/** if EDNS OPT record was present */
|
||||||
@ -215,6 +217,22 @@ struct edns_data {
|
|||||||
uint16_t bits;
|
uint16_t bits;
|
||||||
/** UDP reassembly size. */
|
/** UDP reassembly size. */
|
||||||
uint16_t udp_size;
|
uint16_t udp_size;
|
||||||
|
/** rdata element list, or NULL if none */
|
||||||
|
struct edns_option* opt_list;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* EDNS option
|
||||||
|
*/
|
||||||
|
struct edns_option {
|
||||||
|
/** next item in list */
|
||||||
|
struct edns_option* next;
|
||||||
|
/** type of this edns option */
|
||||||
|
uint16_t opt_code;
|
||||||
|
/** length of this edns option (cannot exceed uint16 in encoding) */
|
||||||
|
size_t opt_len;
|
||||||
|
/** data of this edns option; allocated in region, or NULL if len=0 */
|
||||||
|
uint8_t* opt_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -249,10 +267,12 @@ int parse_packet(struct sldns_buffer* pkt, struct msg_parse* msg,
|
|||||||
* @param msg: parsed message structure. Modified on exit, if EDNS was present
|
* @param msg: parsed message structure. Modified on exit, if EDNS was present
|
||||||
* it is removed from the additional section.
|
* it is removed from the additional section.
|
||||||
* @param edns: the edns data is stored here. Does not have to be initialised.
|
* @param edns: the edns data is stored here. Does not have to be initialised.
|
||||||
|
* @param region: region to alloc results in (edns option contents)
|
||||||
* @return: 0 on success. or an RCODE on an error.
|
* @return: 0 on success. or an RCODE on an error.
|
||||||
* RCODE formerr if OPT in wrong section, and so on.
|
* RCODE formerr if OPT in wrong section, and so on.
|
||||||
*/
|
*/
|
||||||
int parse_extract_edns(struct msg_parse* msg, struct edns_data* edns);
|
int parse_extract_edns(struct msg_parse* msg, struct edns_data* edns,
|
||||||
|
struct regional* region);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If EDNS data follows a query section, extract it and initialize edns struct.
|
* If EDNS data follows a query section, extract it and initialize edns struct.
|
||||||
@ -260,10 +280,12 @@ int parse_extract_edns(struct msg_parse* msg, struct edns_data* edns);
|
|||||||
* section. At end, right after EDNS data or no movement if failed.
|
* section. At end, right after EDNS data or no movement if failed.
|
||||||
* @param edns: the edns data allocated by the caller. Does not have to be
|
* @param edns: the edns data allocated by the caller. Does not have to be
|
||||||
* initialised.
|
* initialised.
|
||||||
|
* @param region: region to alloc results in (edns option contents)
|
||||||
* @return: 0 on success, or an RCODE on error.
|
* @return: 0 on success, or an RCODE on error.
|
||||||
* RCODE formerr if OPT is badly formatted and so on.
|
* RCODE formerr if OPT is badly formatted and so on.
|
||||||
*/
|
*/
|
||||||
int parse_edns_from_pkt(struct sldns_buffer* pkt, struct edns_data* edns);
|
int parse_edns_from_pkt(struct sldns_buffer* pkt, struct edns_data* edns,
|
||||||
|
struct regional* region);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculate hash value for rrset in packet.
|
* Calculate hash value for rrset in packet.
|
||||||
|
@ -461,7 +461,7 @@ int reply_info_parse(sldns_buffer* pkt, struct alloc_cache* alloc,
|
|||||||
if((ret = parse_packet(pkt, msg, region)) != 0) {
|
if((ret = parse_packet(pkt, msg, region)) != 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
if((ret = parse_extract_edns(msg, edns)) != 0)
|
if((ret = parse_extract_edns(msg, edns, region)) != 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
/* parse OK, allocate return structures */
|
/* parse OK, allocate return structures */
|
||||||
@ -857,3 +857,88 @@ reply_all_rrsets_secure(struct reply_info* rep)
|
|||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int edns_opt_append(struct edns_data* edns, struct regional* region,
|
||||||
|
uint16_t code, size_t len, uint8_t* data)
|
||||||
|
{
|
||||||
|
struct edns_option** prevp;
|
||||||
|
struct edns_option* opt;
|
||||||
|
|
||||||
|
/* allocate new element */
|
||||||
|
opt = (struct edns_option*)regional_alloc(region, sizeof(*opt));
|
||||||
|
if(!opt)
|
||||||
|
return 0;
|
||||||
|
opt->next = NULL;
|
||||||
|
opt->opt_code = code;
|
||||||
|
opt->opt_len = len;
|
||||||
|
opt->opt_data = regional_alloc_init(region, data, len);
|
||||||
|
if(!opt->opt_data)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* append at end of list */
|
||||||
|
prevp = &edns->opt_list;
|
||||||
|
while(*prevp != NULL)
|
||||||
|
prevp = &((*prevp)->next);
|
||||||
|
*prevp = opt;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int edns_opt_inplace_reply(struct edns_data* edns, struct regional* region)
|
||||||
|
{
|
||||||
|
(void)region;
|
||||||
|
/* remove all edns options from the reply, because only the
|
||||||
|
* options that we understand should be in the reply
|
||||||
|
* (sec 6.1.2 RFC 6891) */
|
||||||
|
edns->opt_list = NULL;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct edns_option* edns_opt_copy_region(struct edns_option* list,
|
||||||
|
struct regional* region)
|
||||||
|
{
|
||||||
|
struct edns_option* result = NULL, *cur = NULL, *s;
|
||||||
|
while(list) {
|
||||||
|
/* copy edns option structure */
|
||||||
|
s = regional_alloc_init(region, list, sizeof(*list));
|
||||||
|
if(!s) return NULL;
|
||||||
|
s->next = NULL;
|
||||||
|
|
||||||
|
/* copy option data */
|
||||||
|
if(s->opt_data) {
|
||||||
|
s->opt_data = regional_alloc_init(region, s->opt_data,
|
||||||
|
s->opt_len);
|
||||||
|
if(!s->opt_data)
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* link into list */
|
||||||
|
if(cur)
|
||||||
|
cur->next = s;
|
||||||
|
else result = s;
|
||||||
|
cur = s;
|
||||||
|
|
||||||
|
/* examine next element */
|
||||||
|
list = list->next;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int edns_opt_list_equal(struct edns_option* p, struct edns_option* q)
|
||||||
|
{
|
||||||
|
while(p && q) {
|
||||||
|
/* compare elements */
|
||||||
|
if(p->opt_code != q->opt_code ||
|
||||||
|
p->opt_len != q->opt_len)
|
||||||
|
return 0;
|
||||||
|
if(p->opt_len > 0 && q->opt_len > 0) {
|
||||||
|
if(memcmp(p->opt_data, q->opt_data, p->opt_len) != 0)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
p = p->next;
|
||||||
|
q = q->next;
|
||||||
|
}
|
||||||
|
if(p || q)
|
||||||
|
return 0; /* uneven length lists */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
@ -437,4 +437,33 @@ void log_dns_msg(const char* str, struct query_info* qinfo,
|
|||||||
void log_query_info(enum verbosity_value v, const char* str,
|
void log_query_info(enum verbosity_value v, const char* str,
|
||||||
struct query_info* qinf);
|
struct query_info* qinf);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Append edns option to edns data structure
|
||||||
|
*/
|
||||||
|
int edns_opt_append(struct edns_data* edns, struct regional* region,
|
||||||
|
uint16_t code, size_t len, uint8_t* data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transform edns data structure from query structure into reply structure.
|
||||||
|
* In place transform, for errors and cache replies.
|
||||||
|
* @param edns: on input contains the edns from the query. On output contains
|
||||||
|
* the edns for the answer. Add new options to the opt_list to put them
|
||||||
|
* in the answer (allocated in the region, with edns_opt_append).
|
||||||
|
* @param region: to allocate stuff in.
|
||||||
|
* @return false on failure (servfail to client, or for some error encodings,
|
||||||
|
* no EDNS options in the answer).
|
||||||
|
*/
|
||||||
|
int edns_opt_inplace_reply(struct edns_data* edns, struct regional* region);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy edns option list allocated to the new region
|
||||||
|
*/
|
||||||
|
struct edns_option* edns_opt_copy_region(struct edns_option* list,
|
||||||
|
struct regional* region);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See if edns option lists are equal, also order and contents of options.
|
||||||
|
*/
|
||||||
|
int edns_opt_list_equal(struct edns_option* p, struct edns_option* q);
|
||||||
|
|
||||||
#endif /* UTIL_DATA_MSGREPLY_H */
|
#endif /* UTIL_DATA_MSGREPLY_H */
|
||||||
|
@ -2333,6 +2333,7 @@ probe_anchor(struct module_env* env, struct trust_anchor* tp)
|
|||||||
edns.ext_rcode = 0;
|
edns.ext_rcode = 0;
|
||||||
edns.edns_version = 0;
|
edns.edns_version = 0;
|
||||||
edns.bits = EDNS_DO;
|
edns.bits = EDNS_DO;
|
||||||
|
edns.opt_list = NULL;
|
||||||
if(sldns_buffer_capacity(buf) < 65535)
|
if(sldns_buffer_capacity(buf) < 65535)
|
||||||
edns.udp_size = (uint16_t)sldns_buffer_capacity(buf);
|
edns.udp_size = (uint16_t)sldns_buffer_capacity(buf);
|
||||||
else edns.udp_size = 65535;
|
else edns.udp_size = 65535;
|
||||||
|
Loading…
Reference in New Issue
Block a user