From 3e6eeb504d967cd1ea58e1aecb76dcac9d31f2de Mon Sep 17 00:00:00 2001 From: Tom Carpay Date: Wed, 27 Oct 2021 13:48:49 +0000 Subject: [PATCH 01/14] Modules have their own outgoing ends options list But nothing happens with it yet --- daemon/worker.c | 3 +++ libunbound/libworker.c | 1 + services/authzone.c | 3 +++ util/data/msgparse.c | 2 ++ util/data/msgparse.h | 3 +++ validator/autotrust.c | 1 + 6 files changed, 13 insertions(+) diff --git a/daemon/worker.c b/daemon/worker.c index b438700af..dbb2da1fc 100644 --- a/daemon/worker.c +++ b/daemon/worker.c @@ -1012,6 +1012,7 @@ answer_notify(struct worker* w, struct query_info* qinfo, edns->ext_rcode = 0; edns->bits &= EDNS_DO; edns->opt_list = NULL; + edns->opt_list_modules_out = NULL; error_encode(pkt, rcode, qinfo, *(uint16_t*)(void *)sldns_buffer_begin(pkt), sldns_buffer_read_u16_at(pkt, 2), edns); @@ -1270,6 +1271,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error, edns.udp_size = EDNS_ADVERTISED_SIZE; edns.bits &= EDNS_DO; edns.opt_list = NULL; + edns.opt_list_modules_out = NULL; edns.padding_block_size = 0; verbose(VERB_ALGO, "query with bad edns version."); log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen); @@ -1297,6 +1299,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error, edns.udp_size = EDNS_ADVERTISED_SIZE; edns.bits &= EDNS_DO; edns.opt_list = NULL; + edns.opt_list_modules_out = NULL; verbose(VERB_ALGO, "query with bad edns keepalive."); log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen); error_encode(c->buffer, LDNS_RCODE_FORMERR, &qinfo, diff --git a/libunbound/libworker.c b/libunbound/libworker.c index 151f50cf5..c4ed660f3 100644 --- a/libunbound/libworker.c +++ b/libunbound/libworker.c @@ -601,6 +601,7 @@ setup_qinfo_edns(struct libworker* w, struct ctx_query* q, edns->edns_version = 0; edns->bits = EDNS_DO; edns->opt_list = NULL; + edns->opt_list_modules_out = NULL; edns->padding_block_size = 0; if(sldns_buffer_capacity(w->back->udp_buff) < 65535) edns->udp_size = (uint16_t)sldns_buffer_capacity( diff --git a/services/authzone.c b/services/authzone.c index 44dda2a71..38cc7ab21 100644 --- a/services/authzone.c +++ b/services/authzone.c @@ -5359,6 +5359,7 @@ xfr_transfer_lookup_host(struct auth_xfer* xfr, struct module_env* env) edns.edns_version = 0; edns.bits = EDNS_DO; edns.opt_list = NULL; + edns.opt_list_modules_out = NULL; edns.padding_block_size = 0; if(sldns_buffer_capacity(buf) < 65535) edns.udp_size = (uint16_t)sldns_buffer_capacity(buf); @@ -6548,6 +6549,7 @@ xfr_probe_lookup_host(struct auth_xfer* xfr, struct module_env* env) edns.edns_version = 0; edns.bits = EDNS_DO; edns.opt_list = NULL; + edns.opt_list_modules_out = NULL; edns.padding_block_size = 0; if(sldns_buffer_capacity(buf) < 65535) edns.udp_size = (uint16_t)sldns_buffer_capacity(buf); @@ -8323,6 +8325,7 @@ zonemd_lookup_dnskey(struct auth_zone* z, struct module_env* env) edns.edns_version = 0; edns.bits = EDNS_DO; edns.opt_list = NULL; + edns.opt_list_modules_out = NULL; if(sldns_buffer_capacity(buf) < 65535) edns.udp_size = (uint16_t)sldns_buffer_capacity(buf); else edns.udp_size = 65535; diff --git a/util/data/msgparse.c b/util/data/msgparse.c index 6ee5559db..fb50c9165 100644 --- a/util/data/msgparse.c +++ b/util/data/msgparse.c @@ -1020,6 +1020,7 @@ parse_extract_edns(struct msg_parse* msg, struct edns_data* edns, edns->bits = sldns_read_uint16(&found->rr_last->ttl_data[2]); edns->udp_size = ntohs(found->rrset_class); edns->opt_list = NULL; + edns->opt_list_modules_out = NULL; edns->padding_block_size = 0; /* take the options */ @@ -1094,6 +1095,7 @@ parse_edns_from_pkt(sldns_buffer* pkt, struct edns_data* edns, edns->edns_version = sldns_buffer_read_u8(pkt); edns->bits = sldns_buffer_read_u16(pkt); edns->opt_list = NULL; + edns->opt_list_modules_out = NULL; edns->padding_block_size = 0; /* take the options */ diff --git a/util/data/msgparse.h b/util/data/msgparse.h index d2fd9c806..434a5b0b8 100644 --- a/util/data/msgparse.h +++ b/util/data/msgparse.h @@ -227,6 +227,9 @@ struct edns_data { uint16_t udp_size; /** rdata element list, or NULL if none */ struct edns_option* opt_list; + /** rdata element list of outgoing edns options from modules + * or NULL if none */ + struct edns_option* opt_list_modules_out; /** block size to pad */ uint16_t padding_block_size; }; diff --git a/validator/autotrust.c b/validator/autotrust.c index 9643a3ddb..080385e93 100644 --- a/validator/autotrust.c +++ b/validator/autotrust.c @@ -2378,6 +2378,7 @@ probe_anchor(struct module_env* env, struct trust_anchor* tp) edns.edns_version = 0; edns.bits = EDNS_DO; edns.opt_list = NULL; + edns.opt_list_modules_out = NULL; edns.padding_block_size = 0; if(sldns_buffer_capacity(buf) < 65535) edns.udp_size = (uint16_t)sldns_buffer_capacity(buf); From 3ebfa9fc9752f33db65bf84ec8d1071a53ca11e4 Mon Sep 17 00:00:00 2001 From: Tom Carpay Date: Wed, 27 Oct 2021 14:01:56 +0000 Subject: [PATCH 02/14] Outgoing module options go to opt_list_modules_out And opt_list_modules_out is reset in case of failure BEWARE! No options from modules will be encoded in the responses now! --- daemon/worker.c | 6 +++--- services/authzone.c | 2 +- services/localzone.c | 2 +- services/mesh.c | 16 ++++++++-------- util/data/msgreply.c | 2 +- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/daemon/worker.c b/daemon/worker.c index dbb2da1fc..0d483de73 100644 --- a/daemon/worker.c +++ b/daemon/worker.c @@ -526,7 +526,7 @@ answer_norec_from_cache(struct worker* worker, struct query_info* qinfo, if(!inplace_cb_reply_servfail_call(&worker->env, qinfo, NULL, NULL, LDNS_RCODE_SERVFAIL, edns, repinfo, worker->scratchpad, worker->env.now_tv)) - edns->opt_list = NULL; + edns->opt_list_modules_out = NULL; error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL, &msg->qinfo, id, flags, edns); } @@ -730,7 +730,7 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo, if(!inplace_cb_reply_servfail_call(&worker->env, qinfo, NULL, NULL, LDNS_RCODE_SERVFAIL, edns, repinfo, worker->scratchpad, worker->env.now_tv)) - edns->opt_list = NULL; + edns->opt_list_modules_out = NULL; error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL, qinfo, id, flags, edns); } @@ -796,7 +796,7 @@ chaos_replystr(sldns_buffer* pkt, char** str, int num, struct edns_data* edns, if(!inplace_cb_reply_local_call(&worker->env, NULL, NULL, NULL, LDNS_RCODE_NOERROR, edns, repinfo, worker->scratchpad, worker->env.now_tv)) - edns->opt_list = NULL; + edns->opt_list_modules_out = NULL; sldns_buffer_clear(pkt); sldns_buffer_skip(pkt, (ssize_t)sizeof(uint16_t)); /* skip id */ sldns_buffer_write_u16(pkt, (uint16_t)(BIT_QR|BIT_RA)); diff --git a/services/authzone.c b/services/authzone.c index 38cc7ab21..58056a13b 100644 --- a/services/authzone.c +++ b/services/authzone.c @@ -3518,7 +3518,7 @@ auth_error_encode(struct query_info* qinfo, struct module_env* env, if(!inplace_cb_reply_local_call(env, qinfo, NULL, NULL, rcode, edns, repinfo, temp, env->now_tv)) - edns->opt_list = NULL; + edns->opt_list_modules_out = NULL; error_encode(buf, rcode|BIT_AA, qinfo, *(uint16_t*)sldns_buffer_begin(buf), sldns_buffer_read_u16_at(buf, 2), edns); diff --git a/services/localzone.c b/services/localzone.c index 17dd46813..03d16f965 100644 --- a/services/localzone.c +++ b/services/localzone.c @@ -1299,7 +1299,7 @@ local_error_encode(struct query_info* qinfo, struct module_env* env, if(!inplace_cb_reply_local_call(env, qinfo, NULL, NULL, rcode, edns, repinfo, temp, env->now_tv)) - edns->opt_list = NULL; + edns->opt_list_modules_out = NULL; error_encode(buf, r, qinfo, *(uint16_t*)sldns_buffer_begin(buf), sldns_buffer_read_u16_at(buf, 2), edns); } diff --git a/services/mesh.c b/services/mesh.c index 200531903..be532610f 100644 --- a/services/mesh.c +++ b/services/mesh.c @@ -505,7 +505,7 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo, log_err("mesh_state_create: out of memory; SERVFAIL"); if(!inplace_cb_reply_servfail_call(mesh->env, qinfo, NULL, NULL, LDNS_RCODE_SERVFAIL, edns, rep, mesh->env->scratch, mesh->env->now_tv)) - edns->opt_list = NULL; + edns->opt_list_modules_out = NULL; error_encode(r_buffer, LDNS_RCODE_SERVFAIL, qinfo, qid, qflags, edns); comm_point_send_reply(rep); @@ -521,7 +521,7 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo, log_err("mesh_state_create: out of memory; SERVFAIL"); if(!inplace_cb_reply_servfail_call(mesh->env, qinfo, NULL, NULL, LDNS_RCODE_SERVFAIL, edns, rep, mesh->env->scratch, mesh->env->now_tv)) - edns->opt_list = NULL; + edns->opt_list_modules_out = NULL; error_encode(r_buffer, LDNS_RCODE_SERVFAIL, qinfo, qid, qflags, edns); comm_point_send_reply(rep); @@ -594,7 +594,7 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo, servfail_mem: if(!inplace_cb_reply_servfail_call(mesh->env, qinfo, &s->s, NULL, LDNS_RCODE_SERVFAIL, edns, rep, mesh->env->scratch, mesh->env->now_tv)) - edns->opt_list = NULL; + edns->opt_list_modules_out = NULL; error_encode(r_buffer, LDNS_RCODE_SERVFAIL, qinfo, qid, qflags, edns); comm_point_send_reply(rep); @@ -1145,11 +1145,11 @@ mesh_do_callback(struct mesh_state* m, int rcode, struct reply_info* rep, if(rcode == LDNS_RCODE_SERVFAIL) { if(!inplace_cb_reply_servfail_call(m->s.env, &m->s.qinfo, &m->s, rep, rcode, &r->edns, NULL, m->s.region, start_time)) - r->edns.opt_list = NULL; + r->edns.opt_list_modules_out = NULL; } else { if(!inplace_cb_reply_call(m->s.env, &m->s.qinfo, &m->s, rep, rcode, &r->edns, NULL, m->s.region, start_time)) - r->edns.opt_list = NULL; + r->edns.opt_list_modules_out = NULL; } fptr_ok(fptr_whitelist_mesh_cb(r->cb)); (*r->cb)(r->cb_arg, rcode, r->buf, sec_status_unchecked, NULL, @@ -1286,11 +1286,11 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep, if(rcode == LDNS_RCODE_SERVFAIL) { if(!inplace_cb_reply_servfail_call(m->s.env, &m->s.qinfo, &m->s, rep, rcode, &r->edns, &r->query_reply, m->s.region, &r->start_time)) - r->edns.opt_list = NULL; + r->edns.opt_list_modules_out = NULL; } else { if(!inplace_cb_reply_call(m->s.env, &m->s.qinfo, &m->s, rep, rcode, &r->edns, &r->query_reply, m->s.region, &r->start_time)) - r->edns.opt_list = NULL; + r->edns.opt_list_modules_out = NULL; } error_encode(r_buffer, rcode, &m->s.qinfo, r->qid, r->qflags, &r->edns); @@ -1317,7 +1317,7 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep, { if(!inplace_cb_reply_servfail_call(m->s.env, &m->s.qinfo, &m->s, rep, LDNS_RCODE_SERVFAIL, &r->edns, &r->query_reply, m->s.region, &r->start_time)) - r->edns.opt_list = NULL; + r->edns.opt_list_modules_out = NULL; error_encode(r_buffer, LDNS_RCODE_SERVFAIL, &m->s.qinfo, r->qid, r->qflags, &r->edns); } diff --git a/util/data/msgreply.c b/util/data/msgreply.c index 16441a79d..67a47a7b3 100644 --- a/util/data/msgreply.c +++ b/util/data/msgreply.c @@ -1097,7 +1097,7 @@ static int inplace_cb_reply_call_generic( (void)(*(inplace_cb_reply_func_type*)cb->cb)(qinfo, qstate, rep, rcode, edns, &opt_list_out, repinfo, region, start_time, cb->id, cb->cb_arg); } - edns->opt_list = opt_list_out; + edns->opt_list_modules_out = opt_list_out; return 1; } From 3925297d07ee17ba1aeb76020c00488161fd2559 Mon Sep 17 00:00:00 2001 From: Tom Carpay Date: Mon, 1 Nov 2021 10:44:55 +0000 Subject: [PATCH 03/14] Remove apply_edns_options from worker and mesh... to be returned in message encoding later... --- daemon/worker.c | 12 ++---------- services/mesh.c | 7 ------- 2 files changed, 2 insertions(+), 17 deletions(-) diff --git a/daemon/worker.c b/daemon/worker.c index 0d483de73..7965a1881 100644 --- a/daemon/worker.c +++ b/daemon/worker.c @@ -449,7 +449,6 @@ answer_norec_from_cache(struct worker* worker, struct query_info* qinfo, * Then check if it needs validation, if so, this routine fails, * so that iterator can prime and validator can verify rrsets. */ - struct edns_data edns_bak; uint16_t udpsize = edns->udp_size; int secure = 0; time_t timenow = *worker->env.now; @@ -508,7 +507,6 @@ answer_norec_from_cache(struct worker* worker, struct query_info* qinfo, } } /* return this delegation from the cache */ - edns_bak = *edns; edns->edns_version = EDNS_ADVERTISED_VERSION; edns->udp_size = EDNS_ADVERTISED_SIZE; edns->ext_rcode = 0; @@ -518,9 +516,7 @@ answer_norec_from_cache(struct worker* worker, struct query_info* qinfo, worker->env.now_tv)) return 0; msg->rep->flags |= BIT_QR|BIT_RA; - if(!apply_edns_options(edns, &edns_bak, worker->env.cfg, - repinfo->c, worker->scratchpad) || - !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, udpsize, edns, (int)(edns->bits & EDNS_DO), secure)) { if(!inplace_cb_reply_servfail_call(&worker->env, qinfo, NULL, NULL, @@ -604,7 +600,6 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo, struct reply_info* rep, uint16_t id, uint16_t flags, struct comm_reply* repinfo, struct edns_data* edns) { - struct edns_data edns_bak; time_t timenow = *worker->env.now; uint16_t udpsize = edns->udp_size; struct reply_info* encode_rep = rep; @@ -685,7 +680,6 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo, } } else *is_secure_answer = 0; - edns_bak = *edns; edns->edns_version = EDNS_ADVERTISED_VERSION; edns->udp_size = EDNS_ADVERTISED_SIZE; edns->ext_rcode = 0; @@ -722,9 +716,7 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo, if(!*partial_repp) goto bail_out; } - } else if(!apply_edns_options(edns, &edns_bak, worker->env.cfg, - repinfo->c, worker->scratchpad) || - !reply_info_answer_encode(qinfo, encode_rep, id, flags, + } else if(!reply_info_answer_encode(qinfo, encode_rep, id, flags, repinfo->c->buffer, timenow, 1, worker->scratchpad, udpsize, edns, (int)(edns->bits & EDNS_DO), *is_secure_answer)) { if(!inplace_cb_reply_servfail_call(&worker->env, qinfo, NULL, NULL, diff --git a/services/mesh.c b/services/mesh.c index be532610f..df99f891c 100644 --- a/services/mesh.c +++ b/services/mesh.c @@ -1217,9 +1217,6 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep, struct timeval end_time; struct timeval duration; int secure; - /* Copy the client's EDNS for later restore, to make sure the edns - * compare is with the correct edns options. */ - struct edns_data edns_bak = r->edns; /* briefly set the replylist to null in case the * meshsendreply calls tcpreqinfo sendreply that * comm_point_drops because of size, and then the @@ -1307,9 +1304,6 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep, m->s.qinfo.local_alias = r->local_alias; if(!inplace_cb_reply_call(m->s.env, &m->s.qinfo, &m->s, rep, LDNS_RCODE_NOERROR, &r->edns, &r->query_reply, m->s.region, &r->start_time) || - !apply_edns_options(&r->edns, &edns_bak, - m->s.env->cfg, r->query_reply.c, - m->s.region) || !reply_info_answer_encode(&m->s.qinfo, rep, r->qid, r->qflags, r_buffer, 0, 1, m->s.env->scratch, udp_size, &r->edns, (int)(r->edns.bits & EDNS_DO), @@ -1321,7 +1315,6 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep, error_encode(r_buffer, LDNS_RCODE_SERVFAIL, &m->s.qinfo, r->qid, r->qflags, &r->edns); } - r->edns = edns_bak; m->reply_list = NULL; comm_point_send_reply(&r->query_reply); m->reply_list = rlist; From 89d747653902798af8703e0723ebf6d44aa53e7d Mon Sep 17 00:00:00 2001 From: Tom Carpay Date: Mon, 1 Nov 2021 12:48:40 +0000 Subject: [PATCH 04/14] split edns_data.opt_list in opt_list_in and opt_list_out opt_list_in for parsed (incoming) edns options, and opt_list_out for outgoing (to be encoded) edns options --- daemon/worker.c | 14 +++++++----- iterator/iterator.c | 4 ++-- libunbound/libworker.c | 3 ++- services/authzone.c | 9 +++++--- services/mesh.c | 45 ++++++++++++++++++++++++++------------ services/outside_network.c | 8 ++++--- testcode/fake_event.c | 4 +++- util/data/msgencode.c | 16 ++++++++++---- util/data/msgparse.c | 10 +++++---- util/data/msgparse.h | 8 +++++-- util/data/msgreply.c | 28 ------------------------ util/data/msgreply.h | 12 ---------- util/edns.c | 12 +++++----- validator/autotrust.c | 3 ++- 14 files changed, 90 insertions(+), 86 deletions(-) diff --git a/daemon/worker.c b/daemon/worker.c index 7965a1881..abfb84fbe 100644 --- a/daemon/worker.c +++ b/daemon/worker.c @@ -1003,7 +1003,8 @@ answer_notify(struct worker* w, struct query_info* qinfo, edns->udp_size = EDNS_ADVERTISED_SIZE; edns->ext_rcode = 0; edns->bits &= EDNS_DO; - edns->opt_list = NULL; + edns->opt_list_in = NULL; + edns->opt_list_out = NULL; edns->opt_list_modules_out = NULL; error_encode(pkt, rcode, qinfo, *(uint16_t*)(void *)sldns_buffer_begin(pkt), @@ -1262,7 +1263,8 @@ worker_handle_request(struct comm_point* c, void* arg, int error, edns.edns_version = EDNS_ADVERTISED_VERSION; edns.udp_size = EDNS_ADVERTISED_SIZE; edns.bits &= EDNS_DO; - edns.opt_list = NULL; + edns.opt_list_in = NULL; + edns.opt_list_out = NULL; edns.opt_list_modules_out = NULL; edns.padding_block_size = 0; verbose(VERB_ALGO, "query with bad edns version."); @@ -1284,13 +1286,15 @@ worker_handle_request(struct comm_point* c, void* arg, int error, edns.udp_size = NORMAL_UDP_SIZE; } if(c->type != comm_udp) { - edns_opt = edns_opt_list_find(edns.opt_list, LDNS_EDNS_KEEPALIVE); + /* @TODO reuse what we found at parse time */ + edns_opt = edns_opt_list_find(edns.opt_list_in, LDNS_EDNS_KEEPALIVE); if(edns_opt && edns_opt->opt_len > 0) { edns.ext_rcode = 0; edns.edns_version = EDNS_ADVERTISED_VERSION; edns.udp_size = EDNS_ADVERTISED_SIZE; edns.bits &= EDNS_DO; - edns.opt_list = NULL; + edns.opt_list_in = NULL; + edns.opt_list_out = NULL; edns.opt_list_modules_out = NULL; verbose(VERB_ALGO, "query with bad edns keepalive."); log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen); @@ -1455,7 +1459,7 @@ lookup_cache: * this is a two-pass operation, and lookup_qinfo is different for * each pass. We should still pass the original qinfo to * answer_from_cache(), however, since it's used to build the reply. */ - if(!edns_bypass_cache_stage(edns.opt_list, &worker->env)) { + if(!edns_bypass_cache_stage(edns.opt_list_in, &worker->env)) { is_expired_answer = 0; is_secure_answer = 0; h = query_info_hash(lookup_qinfo, sldns_buffer_read_u16_at(c->buffer, 2)); diff --git a/iterator/iterator.c b/iterator/iterator.c index 45e9f7bf4..64a0602d5 100644 --- a/iterator/iterator.c +++ b/iterator/iterator.c @@ -3859,8 +3859,8 @@ process_response(struct module_qstate* qstate, struct iter_qstate* iq, } /* Copy the edns options we may got from the back end */ - if(edns.opt_list) { - qstate->edns_opts_back_in = edns_opt_copy_region(edns.opt_list, + if(edns.opt_list_in) { + qstate->edns_opts_back_in = edns_opt_copy_region(edns.opt_list_in, qstate->region); if(!qstate->edns_opts_back_in) { log_err("out of memory on incoming message"); diff --git a/libunbound/libworker.c b/libunbound/libworker.c index c4ed660f3..b43bd9604 100644 --- a/libunbound/libworker.c +++ b/libunbound/libworker.c @@ -600,7 +600,8 @@ setup_qinfo_edns(struct libworker* w, struct ctx_query* q, edns->ext_rcode = 0; edns->edns_version = 0; edns->bits = EDNS_DO; - edns->opt_list = NULL; + edns->opt_list_in = NULL; + edns->opt_list_out = NULL; edns->opt_list_modules_out = NULL; edns->padding_block_size = 0; if(sldns_buffer_capacity(w->back->udp_buff) < 65535) diff --git a/services/authzone.c b/services/authzone.c index 58056a13b..d59573881 100644 --- a/services/authzone.c +++ b/services/authzone.c @@ -5358,7 +5358,8 @@ xfr_transfer_lookup_host(struct auth_xfer* xfr, struct module_env* env) edns.ext_rcode = 0; edns.edns_version = 0; edns.bits = EDNS_DO; - edns.opt_list = NULL; + edns.opt_list_in = NULL; + edns.opt_list_out = NULL; edns.opt_list_modules_out = NULL; edns.padding_block_size = 0; if(sldns_buffer_capacity(buf) < 65535) @@ -6548,7 +6549,8 @@ xfr_probe_lookup_host(struct auth_xfer* xfr, struct module_env* env) edns.ext_rcode = 0; edns.edns_version = 0; edns.bits = EDNS_DO; - edns.opt_list = NULL; + edns.opt_list_in = NULL; + edns.opt_list_out = NULL; edns.opt_list_modules_out = NULL; edns.padding_block_size = 0; if(sldns_buffer_capacity(buf) < 65535) @@ -8324,7 +8326,8 @@ zonemd_lookup_dnskey(struct auth_zone* z, struct module_env* env) edns.ext_rcode = 0; edns.edns_version = 0; edns.bits = EDNS_DO; - edns.opt_list = NULL; + edns.opt_list_in = NULL; + edns.opt_list_out = NULL; edns.opt_list_modules_out = NULL; if(sldns_buffer_capacity(buf) < 65535) edns.udp_size = (uint16_t)sldns_buffer_capacity(buf); diff --git a/services/mesh.c b/services/mesh.c index df99f891c..0bfa152ee 100644 --- a/services/mesh.c +++ b/services/mesh.c @@ -461,7 +461,7 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo, struct edns_data* edns, struct comm_reply* rep, uint16_t qid) { struct mesh_state* s = NULL; - int unique = unique_mesh_state(edns->opt_list, mesh->env); + int unique = unique_mesh_state(edns->opt_list_in, mesh->env); int was_detached = 0; int was_noreply = 0; int added = 0; @@ -514,8 +514,8 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo, if(unique) mesh_state_make_unique(s); /* copy the edns options we got from the front */ - if(edns->opt_list) { - s->s.edns_opts_front_in = edns_opt_copy_region(edns->opt_list, + if(edns->opt_list_in) { + s->s.edns_opts_front_in = edns_opt_copy_region(edns->opt_list_in, s->s.region); if(!s->s.edns_opts_front_in) { log_err("mesh_state_create: out of memory; SERVFAIL"); @@ -609,7 +609,7 @@ mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo, uint16_t qid, mesh_cb_func_type cb, void* cb_arg) { struct mesh_state* s = NULL; - int unique = unique_mesh_state(edns->opt_list, mesh->env); + int unique = unique_mesh_state(edns->opt_list_in, mesh->env); int timeout = mesh->env->cfg->serve_expired? mesh->env->cfg->serve_expired_client_timeout:0; int was_detached = 0; @@ -632,8 +632,8 @@ mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo, } if(unique) mesh_state_make_unique(s); - if(edns->opt_list) { - s->s.edns_opts_front_in = edns_opt_copy_region(edns->opt_list, + if(edns->opt_list_in) { + s->s.edns_opts_front_in = edns_opt_copy_region(edns->opt_list_in, s->s.region); if(!s->s.edns_opts_front_in) { return 0; @@ -1266,8 +1266,9 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep, prev->edns.edns_present == r->edns.edns_present && prev->edns.bits == r->edns.bits && prev->edns.udp_size == r->edns.udp_size && - edns_opt_list_compare(prev->edns.opt_list, r->edns.opt_list) - == 0) { + edns_opt_list_compare(prev->edns.opt_list_out, r->edns.opt_list_out) == 0 && + edns_opt_list_compare(prev->edns.opt_list_modules_out, r->edns.opt_list_modules_out) == 0 + ) { /* if the previous reply is identical to this one, fix ID */ if(prev_buffer != r_buffer) sldns_buffer_copy(r_buffer, prev_buffer); @@ -1502,10 +1503,18 @@ int mesh_state_add_cb(struct mesh_state* s, struct edns_data* edns, r->cb = cb; r->cb_arg = cb_arg; r->edns = *edns; - if(edns->opt_list) { - r->edns.opt_list = edns_opt_copy_region(edns->opt_list, + if(edns->opt_list_in || edns->opt_list_out || edns->opt_list_modules_out) { + r->edns.opt_list_in = edns_opt_copy_region(edns->opt_list_in, s->s.region); - if(!r->edns.opt_list) + if(!r->edns.opt_list_in) + return 0; + r->edns.opt_list_out = edns_opt_copy_region(edns->opt_list_out, + s->s.region); + if(!r->edns.opt_list_out) + return 0; + r->edns.opt_list_modules_out = edns_opt_copy_region(edns->opt_list_modules_out, + s->s.region); + if(!r->edns.opt_list_modules_out) return 0; } r->qid = qid; @@ -1526,10 +1535,18 @@ int mesh_state_add_reply(struct mesh_state* s, struct edns_data* edns, return 0; r->query_reply = *rep; r->edns = *edns; - if(edns->opt_list) { - r->edns.opt_list = edns_opt_copy_region(edns->opt_list, + if(edns->opt_list_in || edns->opt_list_out || edns->opt_list_modules_out) { + r->edns.opt_list_in = edns_opt_copy_region(edns->opt_list_in, s->s.region); - if(!r->edns.opt_list) + if(!r->edns.opt_list_in) + return 0; + r->edns.opt_list_out = edns_opt_copy_region(edns->opt_list_out, + s->s.region); + if(!r->edns.opt_list_out) + return 0; + r->edns.opt_list_modules_out = edns_opt_copy_region(edns->opt_list_modules_out, + s->s.region); + if(!r->edns.opt_list_modules_out) return 0; } r->qid = qid; diff --git a/services/outside_network.c b/services/outside_network.c index 666e46f98..d5443ad44 100644 --- a/services/outside_network.c +++ b/services/outside_network.c @@ -2709,7 +2709,9 @@ serviced_encode(struct serviced_query* sq, sldns_buffer* buff, int with_edns) edns.edns_present = 1; edns.ext_rcode = 0; edns.edns_version = EDNS_ADVERTISED_VERSION; - edns.opt_list = sq->opt_list; + edns.opt_list_in = NULL; + edns.opt_list_out = sq->opt_list; + edns.opt_list_modules_out = NULL; if(sq->status == serviced_query_UDP_EDNS_FRAG) { if(addr_is_ip6(&sq->addr, sq->addrlen)) { if(EDNS_FRAG_SIZE_IP6 < EDNS_ADVERTISED_SIZE) @@ -2732,8 +2734,8 @@ serviced_encode(struct serviced_query* sq, sldns_buffer* buff, int with_edns) padding_option.opt_code = LDNS_EDNS_PADDING; padding_option.opt_len = 0; padding_option.opt_data = NULL; - padding_option.next = edns.opt_list; - edns.opt_list = &padding_option; + padding_option.next = edns.opt_list_out; + edns.opt_list_out = &padding_option; edns.padding_block_size = sq->padding_block_size; } attach_edns_record(buff, &edns); diff --git a/testcode/fake_event.c b/testcode/fake_event.c index 5f81b9eb8..6b0fed2f4 100644 --- a/testcode/fake_event.c +++ b/testcode/fake_event.c @@ -1244,7 +1244,9 @@ struct serviced_query* outnet_serviced_query(struct outside_network* outnet, client_string_addr->string_len, client_string_addr->string, qstate->region); } - edns.opt_list = qstate->edns_opts_back_out; + edns.opt_list_in = NULL; + edns.opt_list_out = qstate->edns_opts_back_out; + edns.opt_list_modules_out = NULL; attach_edns_record(pend->buffer, &edns); } memcpy(&pend->addr, addr, addrlen); diff --git a/util/data/msgencode.c b/util/data/msgencode.c index 5f297b551..05c0d1a99 100644 --- a/util/data/msgencode.c +++ b/util/data/msgencode.c @@ -796,7 +796,10 @@ calc_edns_field_size(struct edns_data* edns) struct edns_option* opt; if(!edns || !edns->edns_present) return 0; - for(opt = edns->opt_list; opt; opt = opt->next) { + for(opt = edns->opt_list_modules_out; opt; opt = opt->next) { + rdatalen += 4 + opt->opt_len; + } + for(opt = edns->opt_list_out; opt; opt = opt->next) { rdatalen += 4 + opt->opt_len; } /* domain root '.' + type + class + ttl + rdatalen */ @@ -827,7 +830,13 @@ attach_edns_record_max_msg_sz(sldns_buffer* pkt, struct edns_data* edns, rdatapos = sldns_buffer_position(pkt); sldns_buffer_write_u16(pkt, 0); /* rdatalen */ /* write rdata */ - for(opt=edns->opt_list; opt; opt=opt->next) { + for(opt=edns->opt_list_modules_out; 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); + } + for(opt=edns->opt_list_out; opt; opt=opt->next) { if (opt->opt_code == LDNS_EDNS_PADDING) { padding_option = opt; continue; @@ -860,8 +869,7 @@ attach_edns_record_max_msg_sz(sldns_buffer* pkt, struct edns_data* edns, sldns_buffer_skip(pkt, pad_sz); } } - if(edns->opt_list) - sldns_buffer_write_u16_at(pkt, rdatapos, + sldns_buffer_write_u16_at(pkt, rdatapos, sldns_buffer_position(pkt)-rdatapos-2); sldns_buffer_flip(pkt); } diff --git a/util/data/msgparse.c b/util/data/msgparse.c index fb50c9165..b3ff35341 100644 --- a/util/data/msgparse.c +++ b/util/data/msgparse.c @@ -952,8 +952,8 @@ parse_edns_options(uint8_t* rdata_ptr, size_t rdata_len, rdata_len -= 4; if(opt_len > rdata_len) break; /* option code partial */ - if(!edns_opt_append(edns, region, opt_code, opt_len, - rdata_ptr)) { + if(!edns_opt_list_append(&edns->opt_list_in, opt_code, opt_len, + rdata_ptr, region)) { log_err("out of memory"); return 0; } @@ -1019,7 +1019,8 @@ parse_extract_edns(struct msg_parse* msg, struct edns_data* edns, 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); - edns->opt_list = NULL; + edns->opt_list_in = NULL; + edns->opt_list_out = NULL; edns->opt_list_modules_out = NULL; edns->padding_block_size = 0; @@ -1094,7 +1095,8 @@ parse_edns_from_pkt(sldns_buffer* pkt, struct edns_data* edns, edns->ext_rcode = sldns_buffer_read_u8(pkt); /* ttl used for bits */ edns->edns_version = sldns_buffer_read_u8(pkt); edns->bits = sldns_buffer_read_u16(pkt); - edns->opt_list = NULL; + edns->opt_list_in = NULL; + edns->opt_list_out = NULL; edns->opt_list_modules_out = NULL; edns->padding_block_size = 0; diff --git a/util/data/msgparse.h b/util/data/msgparse.h index 434a5b0b8..4bb82cc3c 100644 --- a/util/data/msgparse.h +++ b/util/data/msgparse.h @@ -225,8 +225,12 @@ struct edns_data { uint16_t bits; /** UDP reassembly size. */ uint16_t udp_size; - /** rdata element list, or NULL if none */ - struct edns_option* opt_list; + /** rdata element list of options of an incoming packet created at + * parse time, or NULL if none */ + struct edns_option* opt_list_in; + /** rdata element list of options to encode for outgoing packets, + * or NULL if none */ + struct edns_option* opt_list_out; /** rdata element list of outgoing edns options from modules * or NULL if none */ struct edns_option* opt_list_modules_out; diff --git a/util/data/msgreply.c b/util/data/msgreply.c index 67a47a7b3..1d5a1f214 100644 --- a/util/data/msgreply.c +++ b/util/data/msgreply.c @@ -989,34 +989,6 @@ parse_reply_in_temp_region(sldns_buffer* pkt, struct regional* region, return rep; } -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 = NULL; - if(len > 0) { - 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_list_append(struct edns_option** list, uint16_t code, size_t len, uint8_t* data, struct regional* region) { diff --git a/util/data/msgreply.h b/util/data/msgreply.h index 5a30a1d77..81c763fc7 100644 --- a/util/data/msgreply.h +++ b/util/data/msgreply.h @@ -518,18 +518,6 @@ void log_reply_info(enum verbosity_value v, struct query_info *qinf, void log_query_info(enum verbosity_value v, const char* str, struct query_info* qinf); -/** - * Append edns option to edns data structure - * @param edns: the edns data structure to append the edns option to. - * @param region: region to allocate the new edns option. - * @param code: the edns option's code. - * @param len: the edns option's length. - * @param data: the edns option's data. - * @return false on failure. - */ -int edns_opt_append(struct edns_data* edns, struct regional* region, - uint16_t code, size_t len, uint8_t* data); - /** * Append edns option to edns option list * @param list: the edns option list to append the edns option to. diff --git a/util/edns.c b/util/edns.c index 84308449c..2081cd1e6 100644 --- a/util/edns.c +++ b/util/edns.c @@ -140,12 +140,12 @@ static int edns_keepalive(struct edns_data* edns_out, struct edns_data* edns_in, * sent on that connection will have a TCP Keepalive option. */ if(c->tcp_keepalive || - edns_opt_list_find(edns_in->opt_list, LDNS_EDNS_KEEPALIVE)) { + edns_opt_list_find(edns_in->opt_list_in, LDNS_EDNS_KEEPALIVE)) { int keepalive = c->tcp_timeout_msec / 100; uint8_t data[2]; data[0] = (uint8_t)((keepalive >> 8) & 0xff); data[1] = (uint8_t)(keepalive & 0xff); - if(!edns_opt_list_append(&edns_out->opt_list, LDNS_EDNS_KEEPALIVE, + if(!edns_opt_list_append(&edns_out->opt_list_out, LDNS_EDNS_KEEPALIVE, sizeof(data), data, region)) return 0; c->tcp_keepalive = 1; @@ -160,17 +160,17 @@ int apply_edns_options(struct edns_data* edns_out, struct edns_data* edns_in, !edns_keepalive(edns_out, edns_in, c, region)) return 0; - if (cfg->nsid && edns_opt_list_find(edns_in->opt_list, LDNS_EDNS_NSID) - && !edns_opt_list_append(&edns_out->opt_list, + if (cfg->nsid && edns_opt_list_find(edns_in->opt_list_in, LDNS_EDNS_NSID) + && !edns_opt_list_append(&edns_out->opt_list_out, LDNS_EDNS_NSID, cfg->nsid_len, cfg->nsid, region)) return 0; if(!cfg->pad_responses || c->type != comm_tcp || !c->ssl - || !edns_opt_list_find(edns_in->opt_list, LDNS_EDNS_PADDING)) { + || !edns_opt_list_find(edns_in->opt_list_in, LDNS_EDNS_PADDING)) { ; /* pass */ } - else if(!edns_opt_list_append(&edns_out->opt_list, LDNS_EDNS_PADDING + else if(!edns_opt_list_append(&edns_out->opt_list_out, LDNS_EDNS_PADDING , 0, NULL, region)) return 0; else diff --git a/validator/autotrust.c b/validator/autotrust.c index 080385e93..f26bfdb44 100644 --- a/validator/autotrust.c +++ b/validator/autotrust.c @@ -2377,7 +2377,8 @@ probe_anchor(struct module_env* env, struct trust_anchor* tp) edns.ext_rcode = 0; edns.edns_version = 0; edns.bits = EDNS_DO; - edns.opt_list = NULL; + edns.opt_list_in = NULL; + edns.opt_list_out = NULL; edns.opt_list_modules_out = NULL; edns.padding_block_size = 0; if(sldns_buffer_capacity(buf) < 65535) From 5f8447830ae74cba4c602cf6fa5367eee033b5af Mon Sep 17 00:00:00 2001 From: Tom Carpay Date: Mon, 1 Nov 2021 13:48:31 +0000 Subject: [PATCH 05/14] Move option handling to parse-time --- daemon/worker.c | 3 +- services/mesh.c | 46 +++++++++++----------------- util/data/msgparse.c | 73 +++++++++++++++++++++++++++++++++++++++----- util/data/msgparse.h | 6 +++- util/edns.c | 50 ------------------------------ util/edns.h | 12 -------- 6 files changed, 90 insertions(+), 100 deletions(-) diff --git a/daemon/worker.c b/daemon/worker.c index abfb84fbe..67b2e3166 100644 --- a/daemon/worker.c +++ b/daemon/worker.c @@ -1242,7 +1242,8 @@ worker_handle_request(struct comm_point* c, void* arg, int error, } goto send_reply; } - if((ret=parse_edns_from_pkt(c->buffer, &edns, worker->scratchpad)) != 0) { + if((ret=parse_edns_from_pkt(c->buffer, &edns, worker->env.cfg, c, + worker->scratchpad)) != 0) { struct edns_data reply_edns; verbose(VERB_ALGO, "worker parse edns: formerror."); log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen); diff --git a/services/mesh.c b/services/mesh.c index 0bfa152ee..e91c28485 100644 --- a/services/mesh.c +++ b/services/mesh.c @@ -1503,20 +1503,15 @@ int mesh_state_add_cb(struct mesh_state* s, struct edns_data* edns, r->cb = cb; r->cb_arg = cb_arg; r->edns = *edns; - if(edns->opt_list_in || edns->opt_list_out || edns->opt_list_modules_out) { - r->edns.opt_list_in = edns_opt_copy_region(edns->opt_list_in, - s->s.region); - if(!r->edns.opt_list_in) - return 0; - r->edns.opt_list_out = edns_opt_copy_region(edns->opt_list_out, - s->s.region); - if(!r->edns.opt_list_out) - return 0; - r->edns.opt_list_modules_out = edns_opt_copy_region(edns->opt_list_modules_out, - s->s.region); - if(!r->edns.opt_list_modules_out) - return 0; - } + if(edns->opt_list_in && !(r->edns.opt_list_in = + edns_opt_copy_region(edns->opt_list_in, s->s.region))) + return 0; + if(edns->opt_list_out && !(r->edns.opt_list_out = + edns_opt_copy_region(edns->opt_list_out, s->s.region))) + return 0; + if(edns->opt_list_modules_out && !(r->edns.opt_list_modules_out = + edns_opt_copy_region(edns->opt_list_modules_out, s->s.region))) + return 0; r->qid = qid; r->qflags = qflags; r->next = s->cb_list; @@ -1535,20 +1530,15 @@ int mesh_state_add_reply(struct mesh_state* s, struct edns_data* edns, return 0; r->query_reply = *rep; r->edns = *edns; - if(edns->opt_list_in || edns->opt_list_out || edns->opt_list_modules_out) { - r->edns.opt_list_in = edns_opt_copy_region(edns->opt_list_in, - s->s.region); - if(!r->edns.opt_list_in) - return 0; - r->edns.opt_list_out = edns_opt_copy_region(edns->opt_list_out, - s->s.region); - if(!r->edns.opt_list_out) - return 0; - r->edns.opt_list_modules_out = edns_opt_copy_region(edns->opt_list_modules_out, - s->s.region); - if(!r->edns.opt_list_modules_out) - return 0; - } + if(edns->opt_list_in && !(r->edns.opt_list_in = + edns_opt_copy_region(edns->opt_list_in, s->s.region))) + return 0; + if(edns->opt_list_out && !(r->edns.opt_list_out = + edns_opt_copy_region(edns->opt_list_out, s->s.region))) + return 0; + if(edns->opt_list_modules_out && !(r->edns.opt_list_modules_out = + edns_opt_copy_region(edns->opt_list_modules_out, s->s.region))) + return 0; r->qid = qid; r->qflags = qflags; r->start_time = *s->s.env->now_tv; diff --git a/util/data/msgparse.c b/util/data/msgparse.c index b3ff35341..1fc7f2d55 100644 --- a/util/data/msgparse.c +++ b/util/data/msgparse.c @@ -37,10 +37,12 @@ * Routines for message parsing a packet buffer to a descriptive structure. */ #include "config.h" +#include "util/config_file.h" #include "util/data/msgparse.h" #include "util/data/msgreply.h" #include "util/data/dname.h" #include "util/data/packed_rrset.h" +#include "util/netevent.h" #include "util/storage/lookup3.h" #include "util/regional.h" #include "sldns/rrdef.h" @@ -941,8 +943,12 @@ parse_packet(sldns_buffer* pkt, struct msg_parse* msg, struct regional* region) /** 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) + struct edns_data* edns, struct config_file* cfg, struct comm_point* c, + struct regional* region) { + int keepalive; + uint8_t data[2]; /* For keepalive value */ + /* while still more options, and have code+len to read */ /* ignores partial content (i.e. rdata len 3) */ while(rdata_len >= 4) { @@ -952,10 +958,61 @@ parse_edns_options(uint8_t* rdata_ptr, size_t rdata_len, rdata_len -= 4; if(opt_len > rdata_len) break; /* option code partial */ - if(!edns_opt_list_append(&edns->opt_list_in, opt_code, opt_len, - rdata_ptr, region)) { - log_err("out of memory"); - return 0; + + /* handle parse time edns options here */ + switch(opt_code) { + case LDNS_EDNS_NSID: + if (!cfg->nsid) + break; + if(!edns_opt_list_append(&edns->opt_list_out, + LDNS_EDNS_NSID, cfg->nsid_len, + cfg->nsid, region)) { + log_err("out of memory"); + return 0; + } + break; + + case LDNS_EDNS_KEEPALIVE: + /* To respond with a Keepalive option, the client + * connection must have received one message with a TCP + * Keepalive EDNS option, and that option must have 0 + * length data. Subsequent messages sent on that + * connection will have a TCP Keepalive option. + */ + if (!cfg->do_tcp_keepalive || c->type != comm_udp || + !c->tcp_keepalive) + break; + keepalive = c->tcp_timeout_msec / 100; + data[0] = (uint8_t)((keepalive >> 8) & 0xff); + data[1] = (uint8_t)(keepalive & 0xff); + if(!edns_opt_list_append(&edns->opt_list_out, + LDNS_EDNS_KEEPALIVE, + sizeof(data), data, region)) { + log_err("out of memory"); + return 0; + } + c->tcp_keepalive = 1; + break; + + case LDNS_EDNS_PADDING: + if(!cfg->pad_responses || c->type != comm_tcp ||!c->ssl) + break; + if(!edns_opt_list_append(&edns->opt_list_out, + LDNS_EDNS_PADDING, + 0, NULL, region)) { + log_err("out of memory"); + return 0; + } + edns->padding_block_size = cfg->pad_responses_block_size; + break; + + default: + if(!edns_opt_list_append(&edns->opt_list_in, + opt_code, opt_len, rdata_ptr, region)) { + log_err("out of memory"); + return 0; + } + break; } rdata_ptr += opt_len; rdata_len -= opt_len; @@ -1027,7 +1084,7 @@ parse_extract_edns(struct msg_parse* msg, struct edns_data* edns, /* take the options */ rdata_len = found->rr_first->size-2; rdata_ptr = found->rr_first->ttl_data+6; - if(!parse_edns_options(rdata_ptr, rdata_len, edns, region)) + if(!parse_edns_options(rdata_ptr, rdata_len, edns, NULL, NULL, region)) return 0; /* ignore rrsigs */ @@ -1063,7 +1120,7 @@ skip_pkt_rrs(sldns_buffer* pkt, int num) int parse_edns_from_pkt(sldns_buffer* pkt, struct edns_data* edns, - struct regional* region) + struct config_file* cfg, struct comm_point* c, struct regional* region) { size_t rdata_len; uint8_t* rdata_ptr; @@ -1105,7 +1162,7 @@ parse_edns_from_pkt(sldns_buffer* pkt, struct edns_data* edns, 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)) + if(!parse_edns_options(rdata_ptr, rdata_len, edns, cfg, c, region)) return LDNS_RCODE_SERVFAIL; /* ignore rrsigs */ diff --git a/util/data/msgparse.h b/util/data/msgparse.h index 4bb82cc3c..518161760 100644 --- a/util/data/msgparse.h +++ b/util/data/msgparse.h @@ -70,6 +70,8 @@ struct rrset_parse; struct rr_parse; struct regional; struct edns_option; +struct config_file; +struct comm_point; /** number of buckets in parse rrset hash table. Must be power of 2. */ #define PARSE_TABLE_SIZE 32 @@ -297,12 +299,14 @@ int parse_extract_edns(struct msg_parse* msg, struct edns_data* edns, * 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 * initialised. + * @param cfg: the configuration (with nsid value etc.) + * @param c: commpoint to determine transport (if needed) * @param region: region to alloc results in (edns option contents) * @return: 0 on success, or an RCODE on error. * RCODE formerr if OPT is badly formatted and so on. */ int parse_edns_from_pkt(struct sldns_buffer* pkt, struct edns_data* edns, - struct regional* region); + struct config_file* cfg, struct comm_point* c, struct regional* region); /** * Calculate hash value for rrset in packet. diff --git a/util/edns.c b/util/edns.c index 2081cd1e6..f55dcb97e 100644 --- a/util/edns.c +++ b/util/edns.c @@ -128,53 +128,3 @@ edns_string_addr_lookup(rbtree_type* tree, struct sockaddr_storage* addr, return (struct edns_string_addr*)addr_tree_lookup(tree, addr, addrlen); } -static int edns_keepalive(struct edns_data* edns_out, struct edns_data* edns_in, - struct comm_point* c, struct regional* region) -{ - if(c->type == comm_udp) - return 1; - - /* To respond with a Keepalive option, the client connection - * must have received one message with a TCP Keepalive EDNS option, - * and that option must have 0 length data. Subsequent messages - * sent on that connection will have a TCP Keepalive option. - */ - if(c->tcp_keepalive || - edns_opt_list_find(edns_in->opt_list_in, LDNS_EDNS_KEEPALIVE)) { - int keepalive = c->tcp_timeout_msec / 100; - uint8_t data[2]; - data[0] = (uint8_t)((keepalive >> 8) & 0xff); - data[1] = (uint8_t)(keepalive & 0xff); - if(!edns_opt_list_append(&edns_out->opt_list_out, LDNS_EDNS_KEEPALIVE, - sizeof(data), data, region)) - return 0; - c->tcp_keepalive = 1; - } - return 1; -} - -int apply_edns_options(struct edns_data* edns_out, struct edns_data* edns_in, - struct config_file* cfg, struct comm_point* c, struct regional* region) -{ - if(cfg->do_tcp_keepalive && - !edns_keepalive(edns_out, edns_in, c, region)) - return 0; - - if (cfg->nsid && edns_opt_list_find(edns_in->opt_list_in, LDNS_EDNS_NSID) - && !edns_opt_list_append(&edns_out->opt_list_out, - LDNS_EDNS_NSID, cfg->nsid_len, cfg->nsid, region)) - return 0; - - if(!cfg->pad_responses || c->type != comm_tcp || !c->ssl - || !edns_opt_list_find(edns_in->opt_list_in, LDNS_EDNS_PADDING)) { - ; /* pass */ - } - - else if(!edns_opt_list_append(&edns_out->opt_list_out, LDNS_EDNS_PADDING - , 0, NULL, region)) - return 0; - else - edns_out->padding_block_size = cfg->pad_responses_block_size; - - return 1; -} diff --git a/util/edns.h b/util/edns.h index 11742eb5b..d9ded0b84 100644 --- a/util/edns.h +++ b/util/edns.h @@ -106,16 +106,4 @@ struct edns_string_addr* edns_string_addr_lookup(rbtree_type* tree, struct sockaddr_storage* addr, socklen_t addrlen); -/** - * Apply common EDNS options. - * - * @param edns_out: initialised edns information with outbound edns. - * @param edns_in: initialised edns information with received edns. - * @param cfg: configuration. - * @param c: comm channel. - * @param region: the region to allocate the edns options in. - */ -int apply_edns_options(struct edns_data* edns_out, struct edns_data* edns_in, - struct config_file* cfg, struct comm_point* c, struct regional* region); - #endif From cb48d9e4a1a834419ce366a7b4ead167b8fb8724 Mon Sep 17 00:00:00 2001 From: Tom Carpay Date: Mon, 1 Nov 2021 15:01:07 +0000 Subject: [PATCH 06/14] Fix keepalive logic --- daemon/worker.c | 24 ---------------- util/data/msgparse.c | 66 ++++++++++++++++++++++++++++++-------------- 2 files changed, 46 insertions(+), 44 deletions(-) diff --git a/daemon/worker.c b/daemon/worker.c index 67b2e3166..6a13dbe29 100644 --- a/daemon/worker.c +++ b/daemon/worker.c @@ -1258,7 +1258,6 @@ worker_handle_request(struct comm_point* c, void* arg, int error, goto send_reply; } if(edns.edns_present) { - struct edns_option* edns_opt; if(edns.edns_version != 0) { edns.ext_rcode = (uint8_t)(EDNS_RCODE_BADVERS>>4); edns.edns_version = EDNS_ADVERTISED_VERSION; @@ -1286,29 +1285,6 @@ worker_handle_request(struct comm_point* c, void* arg, int error, log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen); edns.udp_size = NORMAL_UDP_SIZE; } - if(c->type != comm_udp) { - /* @TODO reuse what we found at parse time */ - edns_opt = edns_opt_list_find(edns.opt_list_in, LDNS_EDNS_KEEPALIVE); - if(edns_opt && edns_opt->opt_len > 0) { - edns.ext_rcode = 0; - edns.edns_version = EDNS_ADVERTISED_VERSION; - edns.udp_size = EDNS_ADVERTISED_SIZE; - edns.bits &= EDNS_DO; - edns.opt_list_in = NULL; - edns.opt_list_out = NULL; - edns.opt_list_modules_out = NULL; - verbose(VERB_ALGO, "query with bad edns keepalive."); - log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen); - error_encode(c->buffer, LDNS_RCODE_FORMERR, &qinfo, - *(uint16_t*)(void *)sldns_buffer_begin(c->buffer), - sldns_buffer_read_u16_at(c->buffer, 2), NULL); - if(sldns_buffer_capacity(c->buffer) >= - sldns_buffer_limit(c->buffer)+calc_edns_field_size(&edns)) - attach_edns_record(c->buffer, &edns); - regional_free_all(worker->scratchpad); - goto send_reply; - } - } } if(edns.udp_size > worker->daemon->cfg->max_udp_size && c->type == comm_udp) { diff --git a/util/data/msgparse.c b/util/data/msgparse.c index 1fc7f2d55..35f58c2fe 100644 --- a/util/data/msgparse.c +++ b/util/data/msgparse.c @@ -940,14 +940,36 @@ parse_packet(sldns_buffer* pkt, struct msg_parse* msg, struct regional* region) return 0; } +static int +edns_opt_list_append_keepalive(struct edns_option** list, int msec, + struct regional* region) +{ + uint8_t data[2]; /* For keepalive value */ + data[0] = (uint8_t)((msec >> 8) & 0xff); + data[1] = (uint8_t)(msec & 0xff); + return edns_opt_list_append(list, LDNS_EDNS_KEEPALIVE, sizeof(data), + data, region); +} + /** 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 config_file* cfg, struct comm_point* c, struct regional* region) { - int keepalive; - uint8_t data[2]; /* For keepalive value */ + /* To respond with a Keepalive option, the client connection must have + * received one message with a TCP Keepalive EDNS option, and that + * option must have 0 length data. Subsequent messages sent on that + * connection will have a TCP Keepalive option. + */ + if (cfg && cfg->do_tcp_keepalive && c && c->type != comm_udp && c->tcp_keepalive) { + if(!edns_opt_list_append_keepalive(&edns->opt_list_out, + c->tcp_timeout_msec / 100, region)) { + log_err("out of memory"); + return LDNS_RCODE_SERVFAIL; + } + c->tcp_keepalive = 1; + } /* while still more options, and have code+len to read */ /* ignores partial content (i.e. rdata len 3) */ @@ -962,13 +984,13 @@ parse_edns_options(uint8_t* rdata_ptr, size_t rdata_len, /* handle parse time edns options here */ switch(opt_code) { case LDNS_EDNS_NSID: - if (!cfg->nsid) + if (!cfg || !cfg->nsid) break; if(!edns_opt_list_append(&edns->opt_list_out, LDNS_EDNS_NSID, cfg->nsid_len, cfg->nsid, region)) { log_err("out of memory"); - return 0; + return LDNS_RCODE_SERVFAIL; } break; @@ -979,29 +1001,31 @@ parse_edns_options(uint8_t* rdata_ptr, size_t rdata_len, * length data. Subsequent messages sent on that * connection will have a TCP Keepalive option. */ - if (!cfg->do_tcp_keepalive || c->type != comm_udp || - !c->tcp_keepalive) + if (!cfg || !cfg->do_tcp_keepalive || !c || + c->type == comm_udp || c->tcp_keepalive) break; - keepalive = c->tcp_timeout_msec / 100; - data[0] = (uint8_t)((keepalive >> 8) & 0xff); - data[1] = (uint8_t)(keepalive & 0xff); - if(!edns_opt_list_append(&edns->opt_list_out, - LDNS_EDNS_KEEPALIVE, - sizeof(data), data, region)) { + if(opt_len) { + verbose(VERB_ALGO, "query with bad edns keepalive."); + return LDNS_RCODE_FORMERR; + } + if(!edns_opt_list_append_keepalive(&edns->opt_list_out, + c->tcp_timeout_msec / 100, + region)) { log_err("out of memory"); - return 0; + return LDNS_RCODE_SERVFAIL; } c->tcp_keepalive = 1; break; case LDNS_EDNS_PADDING: - if(!cfg->pad_responses || c->type != comm_tcp ||!c->ssl) + if(!cfg || !cfg->pad_responses || + !c || c->type != comm_tcp ||!c->ssl) break; if(!edns_opt_list_append(&edns->opt_list_out, LDNS_EDNS_PADDING, 0, NULL, region)) { log_err("out of memory"); - return 0; + return LDNS_RCODE_SERVFAIL; } edns->padding_block_size = cfg->pad_responses_block_size; break; @@ -1010,14 +1034,14 @@ parse_edns_options(uint8_t* rdata_ptr, size_t rdata_len, if(!edns_opt_list_append(&edns->opt_list_in, opt_code, opt_len, rdata_ptr, region)) { log_err("out of memory"); - return 0; + return LDNS_RCODE_SERVFAIL; } break; } rdata_ptr += opt_len; rdata_len -= opt_len; } - return 1; + return 0; } int @@ -1084,7 +1108,7 @@ parse_extract_edns(struct msg_parse* msg, struct edns_data* edns, /* take the options */ rdata_len = found->rr_first->size-2; rdata_ptr = found->rr_first->ttl_data+6; - if(!parse_edns_options(rdata_ptr, rdata_len, edns, NULL, NULL, region)) + if(parse_edns_options(rdata_ptr, rdata_len, edns, NULL, NULL, region)) return 0; /* ignore rrsigs */ @@ -1122,6 +1146,7 @@ int parse_edns_from_pkt(sldns_buffer* pkt, struct edns_data* edns, struct config_file* cfg, struct comm_point* c, struct regional* region) { + int rcode; size_t rdata_len; uint8_t* rdata_ptr; log_assert(LDNS_QDCOUNT(sldns_buffer_begin(pkt)) == 1); @@ -1162,8 +1187,9 @@ parse_edns_from_pkt(sldns_buffer* pkt, struct edns_data* edns, 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, cfg, c, region)) - return LDNS_RCODE_SERVFAIL; + rcode = parse_edns_options(rdata_ptr, rdata_len, edns, cfg, c, region); + if(rcode) + return rcode; /* ignore rrsigs */ From fa73142b7949849c9262ce533ed25753b5929e5f Mon Sep 17 00:00:00 2001 From: tcarpay <8014108+TCY16@users.noreply.github.com> Date: Mon, 8 Nov 2021 11:02:54 +0100 Subject: [PATCH 07/14] Apply suggestions from code review Co-authored-by: Willem Toorop --- daemon/worker.c | 3 --- util/data/msgencode.c | 4 ++++ util/data/msgparse.c | 21 ++++++++------------- util/data/msgparse.h | 2 +- 4 files changed, 13 insertions(+), 17 deletions(-) diff --git a/daemon/worker.c b/daemon/worker.c index 6a13dbe29..b9103488f 100644 --- a/daemon/worker.c +++ b/daemon/worker.c @@ -1003,9 +1003,6 @@ answer_notify(struct worker* w, struct query_info* qinfo, edns->udp_size = EDNS_ADVERTISED_SIZE; edns->ext_rcode = 0; edns->bits &= EDNS_DO; - edns->opt_list_in = NULL; - edns->opt_list_out = NULL; - edns->opt_list_modules_out = NULL; error_encode(pkt, rcode, qinfo, *(uint16_t*)(void *)sldns_buffer_begin(pkt), sldns_buffer_read_u16_at(pkt, 2), edns); diff --git a/util/data/msgencode.c b/util/data/msgencode.c index 05c0d1a99..f0017089d 100644 --- a/util/data/msgencode.c +++ b/util/data/msgencode.c @@ -831,6 +831,10 @@ attach_edns_record_max_msg_sz(sldns_buffer* pkt, struct edns_data* edns, sldns_buffer_write_u16(pkt, 0); /* rdatalen */ /* write rdata */ for(opt=edns->opt_list_modules_out; opt; opt=opt->next) { + if (opt->opt_code == LDNS_EDNS_PADDING) { + padding_option = opt; + continue; + } sldns_buffer_write_u16(pkt, opt->opt_code); sldns_buffer_write_u16(pkt, opt->opt_len); if(opt->opt_len != 0) diff --git a/util/data/msgparse.c b/util/data/msgparse.c index 35f58c2fe..3e6a0affa 100644 --- a/util/data/msgparse.c +++ b/util/data/msgparse.c @@ -968,7 +968,6 @@ parse_edns_options(uint8_t* rdata_ptr, size_t rdata_len, log_err("out of memory"); return LDNS_RCODE_SERVFAIL; } - c->tcp_keepalive = 1; } /* while still more options, and have code+len to read */ @@ -1031,17 +1030,17 @@ parse_edns_options(uint8_t* rdata_ptr, size_t rdata_len, break; default: - if(!edns_opt_list_append(&edns->opt_list_in, - opt_code, opt_len, rdata_ptr, region)) { - log_err("out of memory"); - return LDNS_RCODE_SERVFAIL; - } break; } + if(!edns_opt_list_append(&edns->opt_list_in, + opt_code, opt_len, rdata_ptr, region)) { + log_err("out of memory"); + return LDNS_RCODE_SERVFAIL; + } rdata_ptr += opt_len; rdata_len -= opt_len; } - return 0; + return LDNS_RCODE_NOERROR; } int @@ -1109,7 +1108,7 @@ parse_extract_edns(struct msg_parse* msg, struct edns_data* edns, rdata_len = found->rr_first->size-2; rdata_ptr = found->rr_first->ttl_data+6; if(parse_edns_options(rdata_ptr, rdata_len, edns, NULL, NULL, region)) - return 0; + return LDNS_RCODE_NOERROR; /* ignore rrsigs */ @@ -1187,12 +1186,8 @@ parse_edns_from_pkt(sldns_buffer* pkt, struct edns_data* edns, if(sldns_buffer_remaining(pkt) < rdata_len) return LDNS_RCODE_FORMERR; rdata_ptr = sldns_buffer_current(pkt); - rcode = parse_edns_options(rdata_ptr, rdata_len, edns, cfg, c, region); - if(rcode) - return rcode; - /* ignore rrsigs */ - + return parse_edns_options(rdata_ptr, rdata_len, edns, cfg, c, region); return 0; } diff --git a/util/data/msgparse.h b/util/data/msgparse.h index 518161760..0c70d3b15 100644 --- a/util/data/msgparse.h +++ b/util/data/msgparse.h @@ -235,7 +235,7 @@ struct edns_data { struct edns_option* opt_list_out; /** rdata element list of outgoing edns options from modules * or NULL if none */ - struct edns_option* opt_list_modules_out; + struct edns_option* opt_list_inplace_cb_out; /** block size to pad */ uint16_t padding_block_size; }; From 8205c87a96a8ec62098d4bc7578cbeaeeab686de Mon Sep 17 00:00:00 2001 From: TCY16 Date: Mon, 8 Nov 2021 11:50:29 +0100 Subject: [PATCH 08/14] complete renaming of the modules edns list --- daemon/worker.c | 8 ++++---- libunbound/libworker.c | 2 +- services/authzone.c | 8 ++++---- services/localzone.c | 2 +- services/mesh.c | 26 +++++++++++++------------- services/outside_network.c | 2 +- testcode/fake_event.c | 2 +- util/data/msgencode.c | 4 ++-- util/data/msgparse.c | 5 ++--- util/data/msgreply.c | 2 +- validator/autotrust.c | 2 +- 11 files changed, 31 insertions(+), 32 deletions(-) diff --git a/daemon/worker.c b/daemon/worker.c index b9103488f..8880cac19 100644 --- a/daemon/worker.c +++ b/daemon/worker.c @@ -522,7 +522,7 @@ answer_norec_from_cache(struct worker* worker, struct query_info* qinfo, if(!inplace_cb_reply_servfail_call(&worker->env, qinfo, NULL, NULL, LDNS_RCODE_SERVFAIL, edns, repinfo, worker->scratchpad, worker->env.now_tv)) - edns->opt_list_modules_out = NULL; + edns->opt_list_inplace_cb_out = NULL; error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL, &msg->qinfo, id, flags, edns); } @@ -722,7 +722,7 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo, if(!inplace_cb_reply_servfail_call(&worker->env, qinfo, NULL, NULL, LDNS_RCODE_SERVFAIL, edns, repinfo, worker->scratchpad, worker->env.now_tv)) - edns->opt_list_modules_out = NULL; + edns->opt_list_inplace_cb_out = NULL; error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL, qinfo, id, flags, edns); } @@ -788,7 +788,7 @@ chaos_replystr(sldns_buffer* pkt, char** str, int num, struct edns_data* edns, if(!inplace_cb_reply_local_call(&worker->env, NULL, NULL, NULL, LDNS_RCODE_NOERROR, edns, repinfo, worker->scratchpad, worker->env.now_tv)) - edns->opt_list_modules_out = NULL; + edns->opt_list_inplace_cb_out = NULL; sldns_buffer_clear(pkt); sldns_buffer_skip(pkt, (ssize_t)sizeof(uint16_t)); /* skip id */ sldns_buffer_write_u16(pkt, (uint16_t)(BIT_QR|BIT_RA)); @@ -1262,7 +1262,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error, edns.bits &= EDNS_DO; edns.opt_list_in = NULL; edns.opt_list_out = NULL; - edns.opt_list_modules_out = NULL; + edns.opt_list_inplace_cb_out = NULL; edns.padding_block_size = 0; verbose(VERB_ALGO, "query with bad edns version."); log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen); diff --git a/libunbound/libworker.c b/libunbound/libworker.c index b43bd9604..7f753435d 100644 --- a/libunbound/libworker.c +++ b/libunbound/libworker.c @@ -602,7 +602,7 @@ setup_qinfo_edns(struct libworker* w, struct ctx_query* q, edns->bits = EDNS_DO; edns->opt_list_in = NULL; edns->opt_list_out = NULL; - edns->opt_list_modules_out = NULL; + edns->opt_list_inplace_cb_out = NULL; edns->padding_block_size = 0; if(sldns_buffer_capacity(w->back->udp_buff) < 65535) edns->udp_size = (uint16_t)sldns_buffer_capacity( diff --git a/services/authzone.c b/services/authzone.c index d59573881..3cf87ffd0 100644 --- a/services/authzone.c +++ b/services/authzone.c @@ -3518,7 +3518,7 @@ auth_error_encode(struct query_info* qinfo, struct module_env* env, if(!inplace_cb_reply_local_call(env, qinfo, NULL, NULL, rcode, edns, repinfo, temp, env->now_tv)) - edns->opt_list_modules_out = NULL; + edns->opt_list_inplace_cb_out = NULL; error_encode(buf, rcode|BIT_AA, qinfo, *(uint16_t*)sldns_buffer_begin(buf), sldns_buffer_read_u16_at(buf, 2), edns); @@ -5360,7 +5360,7 @@ xfr_transfer_lookup_host(struct auth_xfer* xfr, struct module_env* env) edns.bits = EDNS_DO; edns.opt_list_in = NULL; edns.opt_list_out = NULL; - edns.opt_list_modules_out = NULL; + edns.opt_list_inplace_cb_out = NULL; edns.padding_block_size = 0; if(sldns_buffer_capacity(buf) < 65535) edns.udp_size = (uint16_t)sldns_buffer_capacity(buf); @@ -6551,7 +6551,7 @@ xfr_probe_lookup_host(struct auth_xfer* xfr, struct module_env* env) edns.bits = EDNS_DO; edns.opt_list_in = NULL; edns.opt_list_out = NULL; - edns.opt_list_modules_out = NULL; + edns.opt_list_inplace_cb_out = NULL; edns.padding_block_size = 0; if(sldns_buffer_capacity(buf) < 65535) edns.udp_size = (uint16_t)sldns_buffer_capacity(buf); @@ -8328,7 +8328,7 @@ zonemd_lookup_dnskey(struct auth_zone* z, struct module_env* env) edns.bits = EDNS_DO; edns.opt_list_in = NULL; edns.opt_list_out = NULL; - edns.opt_list_modules_out = NULL; + edns.opt_list_inplace_cb_out = NULL; if(sldns_buffer_capacity(buf) < 65535) edns.udp_size = (uint16_t)sldns_buffer_capacity(buf); else edns.udp_size = 65535; diff --git a/services/localzone.c b/services/localzone.c index 03d16f965..a69aef8fd 100644 --- a/services/localzone.c +++ b/services/localzone.c @@ -1299,7 +1299,7 @@ local_error_encode(struct query_info* qinfo, struct module_env* env, if(!inplace_cb_reply_local_call(env, qinfo, NULL, NULL, rcode, edns, repinfo, temp, env->now_tv)) - edns->opt_list_modules_out = NULL; + edns->opt_list_inplace_cb_out = NULL; error_encode(buf, r, qinfo, *(uint16_t*)sldns_buffer_begin(buf), sldns_buffer_read_u16_at(buf, 2), edns); } diff --git a/services/mesh.c b/services/mesh.c index e91c28485..d2a1c6856 100644 --- a/services/mesh.c +++ b/services/mesh.c @@ -505,7 +505,7 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo, log_err("mesh_state_create: out of memory; SERVFAIL"); if(!inplace_cb_reply_servfail_call(mesh->env, qinfo, NULL, NULL, LDNS_RCODE_SERVFAIL, edns, rep, mesh->env->scratch, mesh->env->now_tv)) - edns->opt_list_modules_out = NULL; + edns->opt_list_inplace_cb_out = NULL; error_encode(r_buffer, LDNS_RCODE_SERVFAIL, qinfo, qid, qflags, edns); comm_point_send_reply(rep); @@ -521,7 +521,7 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo, log_err("mesh_state_create: out of memory; SERVFAIL"); if(!inplace_cb_reply_servfail_call(mesh->env, qinfo, NULL, NULL, LDNS_RCODE_SERVFAIL, edns, rep, mesh->env->scratch, mesh->env->now_tv)) - edns->opt_list_modules_out = NULL; + edns->opt_list_inplace_cb_out = NULL; error_encode(r_buffer, LDNS_RCODE_SERVFAIL, qinfo, qid, qflags, edns); comm_point_send_reply(rep); @@ -594,7 +594,7 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo, servfail_mem: if(!inplace_cb_reply_servfail_call(mesh->env, qinfo, &s->s, NULL, LDNS_RCODE_SERVFAIL, edns, rep, mesh->env->scratch, mesh->env->now_tv)) - edns->opt_list_modules_out = NULL; + edns->opt_list_inplace_cb_out = NULL; error_encode(r_buffer, LDNS_RCODE_SERVFAIL, qinfo, qid, qflags, edns); comm_point_send_reply(rep); @@ -1145,11 +1145,11 @@ mesh_do_callback(struct mesh_state* m, int rcode, struct reply_info* rep, if(rcode == LDNS_RCODE_SERVFAIL) { if(!inplace_cb_reply_servfail_call(m->s.env, &m->s.qinfo, &m->s, rep, rcode, &r->edns, NULL, m->s.region, start_time)) - r->edns.opt_list_modules_out = NULL; + r->edns.opt_list_inplace_cb_out = NULL; } else { if(!inplace_cb_reply_call(m->s.env, &m->s.qinfo, &m->s, rep, rcode, &r->edns, NULL, m->s.region, start_time)) - r->edns.opt_list_modules_out = NULL; + r->edns.opt_list_inplace_cb_out = NULL; } fptr_ok(fptr_whitelist_mesh_cb(r->cb)); (*r->cb)(r->cb_arg, rcode, r->buf, sec_status_unchecked, NULL, @@ -1267,7 +1267,7 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep, prev->edns.bits == r->edns.bits && prev->edns.udp_size == r->edns.udp_size && edns_opt_list_compare(prev->edns.opt_list_out, r->edns.opt_list_out) == 0 && - edns_opt_list_compare(prev->edns.opt_list_modules_out, r->edns.opt_list_modules_out) == 0 + edns_opt_list_compare(prev->edns.opt_list_inplace_cb_out, r->edns.opt_list_inplace_cb_out) == 0 ) { /* if the previous reply is identical to this one, fix ID */ if(prev_buffer != r_buffer) @@ -1284,11 +1284,11 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep, if(rcode == LDNS_RCODE_SERVFAIL) { if(!inplace_cb_reply_servfail_call(m->s.env, &m->s.qinfo, &m->s, rep, rcode, &r->edns, &r->query_reply, m->s.region, &r->start_time)) - r->edns.opt_list_modules_out = NULL; + r->edns.opt_list_inplace_cb_out = NULL; } else { if(!inplace_cb_reply_call(m->s.env, &m->s.qinfo, &m->s, rep, rcode, &r->edns, &r->query_reply, m->s.region, &r->start_time)) - r->edns.opt_list_modules_out = NULL; + r->edns.opt_list_inplace_cb_out = NULL; } error_encode(r_buffer, rcode, &m->s.qinfo, r->qid, r->qflags, &r->edns); @@ -1312,7 +1312,7 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep, { if(!inplace_cb_reply_servfail_call(m->s.env, &m->s.qinfo, &m->s, rep, LDNS_RCODE_SERVFAIL, &r->edns, &r->query_reply, m->s.region, &r->start_time)) - r->edns.opt_list_modules_out = NULL; + r->edns.opt_list_inplace_cb_out = NULL; error_encode(r_buffer, LDNS_RCODE_SERVFAIL, &m->s.qinfo, r->qid, r->qflags, &r->edns); } @@ -1509,8 +1509,8 @@ int mesh_state_add_cb(struct mesh_state* s, struct edns_data* edns, if(edns->opt_list_out && !(r->edns.opt_list_out = edns_opt_copy_region(edns->opt_list_out, s->s.region))) return 0; - if(edns->opt_list_modules_out && !(r->edns.opt_list_modules_out = - edns_opt_copy_region(edns->opt_list_modules_out, s->s.region))) + if(edns->opt_list_inplace_cb_out && !(r->edns.opt_list_inplace_cb_out = + edns_opt_copy_region(edns->opt_list_inplace_cb_out, s->s.region))) return 0; r->qid = qid; r->qflags = qflags; @@ -1536,8 +1536,8 @@ int mesh_state_add_reply(struct mesh_state* s, struct edns_data* edns, if(edns->opt_list_out && !(r->edns.opt_list_out = edns_opt_copy_region(edns->opt_list_out, s->s.region))) return 0; - if(edns->opt_list_modules_out && !(r->edns.opt_list_modules_out = - edns_opt_copy_region(edns->opt_list_modules_out, s->s.region))) + if(edns->opt_list_inplace_cb_out && !(r->edns.opt_list_inplace_cb_out = + edns_opt_copy_region(edns->opt_list_inplace_cb_out, s->s.region))) return 0; r->qid = qid; r->qflags = qflags; diff --git a/services/outside_network.c b/services/outside_network.c index d5443ad44..fdfba7897 100644 --- a/services/outside_network.c +++ b/services/outside_network.c @@ -2711,7 +2711,7 @@ serviced_encode(struct serviced_query* sq, sldns_buffer* buff, int with_edns) edns.edns_version = EDNS_ADVERTISED_VERSION; edns.opt_list_in = NULL; edns.opt_list_out = sq->opt_list; - edns.opt_list_modules_out = NULL; + edns.opt_list_inplace_cb_out = NULL; if(sq->status == serviced_query_UDP_EDNS_FRAG) { if(addr_is_ip6(&sq->addr, sq->addrlen)) { if(EDNS_FRAG_SIZE_IP6 < EDNS_ADVERTISED_SIZE) diff --git a/testcode/fake_event.c b/testcode/fake_event.c index 6b0fed2f4..6a8245d4a 100644 --- a/testcode/fake_event.c +++ b/testcode/fake_event.c @@ -1246,7 +1246,7 @@ struct serviced_query* outnet_serviced_query(struct outside_network* outnet, } edns.opt_list_in = NULL; edns.opt_list_out = qstate->edns_opts_back_out; - edns.opt_list_modules_out = NULL; + edns.opt_list_inplace_cb_out = NULL; attach_edns_record(pend->buffer, &edns); } memcpy(&pend->addr, addr, addrlen); diff --git a/util/data/msgencode.c b/util/data/msgencode.c index f0017089d..fe21cfb86 100644 --- a/util/data/msgencode.c +++ b/util/data/msgencode.c @@ -796,7 +796,7 @@ calc_edns_field_size(struct edns_data* edns) struct edns_option* opt; if(!edns || !edns->edns_present) return 0; - for(opt = edns->opt_list_modules_out; opt; opt = opt->next) { + for(opt = edns->opt_list_inplace_cb_out; opt; opt = opt->next) { rdatalen += 4 + opt->opt_len; } for(opt = edns->opt_list_out; opt; opt = opt->next) { @@ -830,7 +830,7 @@ attach_edns_record_max_msg_sz(sldns_buffer* pkt, struct edns_data* edns, rdatapos = sldns_buffer_position(pkt); sldns_buffer_write_u16(pkt, 0); /* rdatalen */ /* write rdata */ - for(opt=edns->opt_list_modules_out; opt; opt=opt->next) { + for(opt=edns->opt_list_inplace_cb_out; opt; opt=opt->next) { if (opt->opt_code == LDNS_EDNS_PADDING) { padding_option = opt; continue; diff --git a/util/data/msgparse.c b/util/data/msgparse.c index 3e6a0affa..7841b628b 100644 --- a/util/data/msgparse.c +++ b/util/data/msgparse.c @@ -1101,7 +1101,7 @@ parse_extract_edns(struct msg_parse* msg, struct edns_data* edns, edns->udp_size = ntohs(found->rrset_class); edns->opt_list_in = NULL; edns->opt_list_out = NULL; - edns->opt_list_modules_out = NULL; + edns->opt_list_inplace_cb_out = NULL; edns->padding_block_size = 0; /* take the options */ @@ -1145,7 +1145,6 @@ int parse_edns_from_pkt(sldns_buffer* pkt, struct edns_data* edns, struct config_file* cfg, struct comm_point* c, struct regional* region) { - int rcode; size_t rdata_len; uint8_t* rdata_ptr; log_assert(LDNS_QDCOUNT(sldns_buffer_begin(pkt)) == 1); @@ -1178,7 +1177,7 @@ parse_edns_from_pkt(sldns_buffer* pkt, struct edns_data* edns, edns->bits = sldns_buffer_read_u16(pkt); edns->opt_list_in = NULL; edns->opt_list_out = NULL; - edns->opt_list_modules_out = NULL; + edns->opt_list_inplace_cb_out = NULL; edns->padding_block_size = 0; /* take the options */ diff --git a/util/data/msgreply.c b/util/data/msgreply.c index 1d5a1f214..5fb28a9e4 100644 --- a/util/data/msgreply.c +++ b/util/data/msgreply.c @@ -1069,7 +1069,7 @@ static int inplace_cb_reply_call_generic( (void)(*(inplace_cb_reply_func_type*)cb->cb)(qinfo, qstate, rep, rcode, edns, &opt_list_out, repinfo, region, start_time, cb->id, cb->cb_arg); } - edns->opt_list_modules_out = opt_list_out; + edns->opt_list_inplace_cb_out = opt_list_out; return 1; } diff --git a/validator/autotrust.c b/validator/autotrust.c index f26bfdb44..55e82c176 100644 --- a/validator/autotrust.c +++ b/validator/autotrust.c @@ -2379,7 +2379,7 @@ probe_anchor(struct module_env* env, struct trust_anchor* tp) edns.bits = EDNS_DO; edns.opt_list_in = NULL; edns.opt_list_out = NULL; - edns.opt_list_modules_out = NULL; + edns.opt_list_inplace_cb_out = NULL; edns.padding_block_size = 0; if(sldns_buffer_capacity(buf) < 65535) edns.udp_size = (uint16_t)sldns_buffer_capacity(buf); From f5b586dbdcfee507b4c1012becdabfa027d290ae Mon Sep 17 00:00:00 2001 From: TCY16 Date: Mon, 8 Nov 2021 11:50:57 +0100 Subject: [PATCH 09/14] add potential EDE spots --- validator/validator.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/validator/validator.c b/validator/validator.c index d4d48d956..1c7039e0c 100644 --- a/validator/validator.c +++ b/validator/validator.c @@ -1643,6 +1643,9 @@ processInit(struct module_qstate* qstate, struct val_qstate* vq, /* no retries, stop bothering the authority until timeout */ vq->restart_count = ve->max_restart; vq->chase_reply->security = sec_status_bogus; + + // @TODO ADD Error Code 6 - DNSSEC Bogus + text chain of trust? + vq->state = VAL_FINISHED_STATE; return 1; } @@ -1849,6 +1852,7 @@ processValidate(struct module_qstate* qstate, struct val_qstate* vq, LDNS_RR_TYPE_DNSKEY, vq->key_entry->key_class); vq->chase_reply->security = sec_status_bogus; errinf(qstate, "while building chain of trust"); + // @TODO ADD Error Code 6 - DNSSEC Bogus + text chain of trust? if(vq->restart_count >= ve->max_restart) key_cache_insert(ve->kcache, vq->key_entry, qstate); return 1; From a0df340b1e6b641ebcf8268658c81814426fed4b Mon Sep 17 00:00:00 2001 From: tcarpay <8014108+TCY16@users.noreply.github.com> Date: Mon, 8 Nov 2021 12:28:03 +0100 Subject: [PATCH 10/14] Update util/data/msgparse.c Co-authored-by: gthess --- util/data/msgparse.c | 1 - 1 file changed, 1 deletion(-) diff --git a/util/data/msgparse.c b/util/data/msgparse.c index 7841b628b..f9e7881b8 100644 --- a/util/data/msgparse.c +++ b/util/data/msgparse.c @@ -1187,7 +1187,6 @@ parse_edns_from_pkt(sldns_buffer* pkt, struct edns_data* edns, rdata_ptr = sldns_buffer_current(pkt); /* ignore rrsigs */ return parse_edns_options(rdata_ptr, rdata_len, edns, cfg, c, region); - return 0; } void From c5a1e87f75852dc04288f61d26b559cdf1b7020e Mon Sep 17 00:00:00 2001 From: tcarpay <8014108+TCY16@users.noreply.github.com> Date: Mon, 15 Nov 2021 13:03:26 +0100 Subject: [PATCH 11/14] Remove wrongly added EDE comments Co-authored-by: Wouter Wijngaards --- validator/validator.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/validator/validator.c b/validator/validator.c index 1c7039e0c..d4d48d956 100644 --- a/validator/validator.c +++ b/validator/validator.c @@ -1643,9 +1643,6 @@ processInit(struct module_qstate* qstate, struct val_qstate* vq, /* no retries, stop bothering the authority until timeout */ vq->restart_count = ve->max_restart; vq->chase_reply->security = sec_status_bogus; - - // @TODO ADD Error Code 6 - DNSSEC Bogus + text chain of trust? - vq->state = VAL_FINISHED_STATE; return 1; } @@ -1852,7 +1849,6 @@ processValidate(struct module_qstate* qstate, struct val_qstate* vq, LDNS_RR_TYPE_DNSKEY, vq->key_entry->key_class); vq->chase_reply->security = sec_status_bogus; errinf(qstate, "while building chain of trust"); - // @TODO ADD Error Code 6 - DNSSEC Bogus + text chain of trust? if(vq->restart_count >= ve->max_restart) key_cache_insert(ve->kcache, vq->key_entry, qstate); return 1; From b47dc528aac9ebd739ee398a41e0420657c6c6f5 Mon Sep 17 00:00:00 2001 From: Tom Carpay Date: Mon, 15 Nov 2021 12:33:08 +0000 Subject: [PATCH 12/14] add missing return code --- util/data/msgparse.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/data/msgparse.c b/util/data/msgparse.c index f9e7881b8..fcf2f2325 100644 --- a/util/data/msgparse.c +++ b/util/data/msgparse.c @@ -1112,7 +1112,7 @@ parse_extract_edns(struct msg_parse* msg, struct edns_data* edns, /* ignore rrsigs */ - return 0; + return LDNS_RCODE_NOERROR; } /** skip RR in packet */ From e899b4cefe99dc69590dda79940cf096819c04b3 Mon Sep 17 00:00:00 2001 From: Tom Carpay Date: Mon, 15 Nov 2021 13:40:51 +0000 Subject: [PATCH 13/14] Make explicit whether edns options are parsed from queries or responses --- cachedb/cachedb.c | 2 +- daemon/worker.c | 2 +- iterator/iterator.c | 2 +- pythonmod/pythonmod_utils.c | 2 +- util/data/msgparse.c | 32 ++++++++++++++++++++++++-------- util/data/msgparse.h | 6 +++--- util/data/msgreply.c | 2 +- 7 files changed, 32 insertions(+), 16 deletions(-) diff --git a/cachedb/cachedb.c b/cachedb/cachedb.c index af4ffe5f2..725bc6ce8 100644 --- a/cachedb/cachedb.c +++ b/cachedb/cachedb.c @@ -519,7 +519,7 @@ parse_data(struct module_qstate* qstate, struct sldns_buffer* buf) sldns_buffer_set_limit(buf, lim); return 0; } - if(parse_extract_edns(prs, &edns, qstate->env->scratch) != + if(parse_extract_edns_from_response_msg(prs, &edns, qstate->env->scratch) != LDNS_RCODE_NOERROR) { sldns_buffer_set_limit(buf, lim); return 0; diff --git a/daemon/worker.c b/daemon/worker.c index 8880cac19..5d2483cd2 100644 --- a/daemon/worker.c +++ b/daemon/worker.c @@ -1239,7 +1239,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error, } goto send_reply; } - if((ret=parse_edns_from_pkt(c->buffer, &edns, worker->env.cfg, c, + if((ret=parse_edns_from_query_pkt(c->buffer, &edns, worker->env.cfg, c, worker->scratchpad)) != 0) { struct edns_data reply_edns; verbose(VERB_ALGO, "worker parse edns: formerror."); diff --git a/iterator/iterator.c b/iterator/iterator.c index 64a0602d5..55d53da63 100644 --- a/iterator/iterator.c +++ b/iterator/iterator.c @@ -3852,7 +3852,7 @@ process_response(struct module_qstate* qstate, struct iter_qstate* iq, goto handle_it; } /* edns is not examined, but removed from message to help cache */ - if(parse_extract_edns(prs, &edns, qstate->env->scratch) != + if(parse_extract_edns_from_response_msg(prs, &edns, qstate->env->scratch) != LDNS_RCODE_NOERROR) { iq->parse_failures++; goto handle_it; diff --git a/pythonmod/pythonmod_utils.c b/pythonmod/pythonmod_utils.c index 21a16bbe8..34a20ba76 100644 --- a/pythonmod/pythonmod_utils.c +++ b/pythonmod/pythonmod_utils.c @@ -132,7 +132,7 @@ int createResponse(struct module_qstate* qstate, sldns_buffer* pkt) return 0; } /* edns is not examined, but removed from message to help cache */ - if(parse_extract_edns(prs, &edns, qstate->env->scratch) != + if(parse_extract_edns_from_response_msg(prs, &edns, qstate->env->scratch) != LDNS_RCODE_NOERROR) return 0; diff --git a/util/data/msgparse.c b/util/data/msgparse.c index fcf2f2325..415973cdd 100644 --- a/util/data/msgparse.c +++ b/util/data/msgparse.c @@ -953,7 +953,7 @@ edns_opt_list_append_keepalive(struct edns_option** list, int msec, /** parse EDNS options from EDNS wireformat rdata */ static int -parse_edns_options(uint8_t* rdata_ptr, size_t rdata_len, +parse_edns_options_from_query(uint8_t* rdata_ptr, size_t rdata_len, struct edns_data* edns, struct config_file* cfg, struct comm_point* c, struct regional* region) { @@ -1044,8 +1044,8 @@ parse_edns_options(uint8_t* rdata_ptr, size_t rdata_len, } int -parse_extract_edns(struct msg_parse* msg, struct edns_data* edns, - struct regional* region) +parse_extract_edns_from_response_msg(struct msg_parse* msg, + struct edns_data* edns, struct regional* region) { struct rrset_parse* rrset = msg->rrset_first; struct rrset_parse* prev = 0; @@ -1107,11 +1107,26 @@ parse_extract_edns(struct msg_parse* msg, struct edns_data* edns, /* take the options */ rdata_len = found->rr_first->size-2; rdata_ptr = found->rr_first->ttl_data+6; - if(parse_edns_options(rdata_ptr, rdata_len, edns, NULL, NULL, region)) - return LDNS_RCODE_NOERROR; + /* 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_list_append(&edns->opt_list_in, + opt_code, opt_len, rdata_ptr, region)) { + log_err("out of memory"); + break; + } + rdata_ptr += opt_len; + rdata_len -= opt_len; + } /* ignore rrsigs */ - return LDNS_RCODE_NOERROR; } @@ -1142,7 +1157,7 @@ skip_pkt_rrs(sldns_buffer* pkt, int num) } int -parse_edns_from_pkt(sldns_buffer* pkt, struct edns_data* edns, +parse_edns_from_query_pkt(sldns_buffer* pkt, struct edns_data* edns, struct config_file* cfg, struct comm_point* c, struct regional* region) { size_t rdata_len; @@ -1186,7 +1201,8 @@ parse_edns_from_pkt(sldns_buffer* pkt, struct edns_data* edns, return LDNS_RCODE_FORMERR; rdata_ptr = sldns_buffer_current(pkt); /* ignore rrsigs */ - return parse_edns_options(rdata_ptr, rdata_len, edns, cfg, c, region); + return parse_edns_options_from_query(rdata_ptr, rdata_len, edns, cfg, + c, region); } void diff --git a/util/data/msgparse.h b/util/data/msgparse.h index 0c70d3b15..4c0559a73 100644 --- a/util/data/msgparse.h +++ b/util/data/msgparse.h @@ -290,8 +290,8 @@ int parse_packet(struct sldns_buffer* pkt, struct msg_parse* msg, * @return: 0 on success. or an RCODE on an error. * RCODE formerr if OPT in wrong section, and so on. */ -int parse_extract_edns(struct msg_parse* msg, struct edns_data* edns, - struct regional* region); +int parse_extract_edns_from_response_msg(struct msg_parse* msg, + struct edns_data* edns, struct regional* region); /** * If EDNS data follows a query section, extract it and initialize edns struct. @@ -305,7 +305,7 @@ int parse_extract_edns(struct msg_parse* msg, struct edns_data* edns, * @return: 0 on success, or an RCODE on error. * 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_query_pkt(struct sldns_buffer* pkt, struct edns_data* edns, struct config_file* cfg, struct comm_point* c, struct regional* region); /** diff --git a/util/data/msgreply.c b/util/data/msgreply.c index 5fb28a9e4..ec46e4724 100644 --- a/util/data/msgreply.c +++ b/util/data/msgreply.c @@ -518,7 +518,7 @@ int reply_info_parse(sldns_buffer* pkt, struct alloc_cache* alloc, if((ret = parse_packet(pkt, msg, region)) != 0) { return ret; } - if((ret = parse_extract_edns(msg, edns, region)) != 0) + if((ret = parse_extract_edns_from_response_msg(msg, edns, region)) != 0) return ret; /* parse OK, allocate return structures */ From ff030fa332b88bbd577b045efaee21c0f2d945dd Mon Sep 17 00:00:00 2001 From: Tom Carpay Date: Mon, 15 Nov 2021 14:00:31 +0000 Subject: [PATCH 14/14] Clarify KEEPALIVE EDNS0 option operation --- util/data/msgparse.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/util/data/msgparse.c b/util/data/msgparse.c index 415973cdd..a600a8c60 100644 --- a/util/data/msgparse.c +++ b/util/data/msgparse.c @@ -961,6 +961,10 @@ parse_edns_options_from_query(uint8_t* rdata_ptr, size_t rdata_len, * received one message with a TCP Keepalive EDNS option, and that * option must have 0 length data. Subsequent messages sent on that * connection will have a TCP Keepalive option. + * + * In the if-statement below, the option is added unsolicited. This + * means that the client has sent an KEEPALIVE option earlier. We know + * here this is true, because c->tcp_keepalive is set. */ if (cfg && cfg->do_tcp_keepalive && c && c->type != comm_udp && c->tcp_keepalive) { if(!edns_opt_list_append_keepalive(&edns->opt_list_out, @@ -999,6 +1003,14 @@ parse_edns_options_from_query(uint8_t* rdata_ptr, size_t rdata_len, * Keepalive EDNS option, and that option must have 0 * length data. Subsequent messages sent on that * connection will have a TCP Keepalive option. + * + * This should be the first time the client sends this + * option, so c->tcp_keepalive is not set. + * Besides adding the reply KEEPALIVE option, + * c->tcp_keepalive will be set so that the + * option will be added unsolicited in subsequent + * responses (see the comment above the if-statement + * at the start of this function). */ if (!cfg || !cfg->do_tcp_keepalive || !c || c->type == comm_udp || c->tcp_keepalive)