mirror of
https://github.com/NLnetLabs/unbound.git
synced 2025-12-20 23:00:56 -05:00
- Properly handle all return values of worker_check_request during
early EDE code. - Do not check the incoming request more than once.
This commit is contained in:
parent
f9317d65b3
commit
0f1ea7e490
2 changed files with 68 additions and 27 deletions
|
|
@ -289,61 +289,83 @@ worker_err_ratelimit(struct worker* worker, int err)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Structure holding the result of the worker_check_request function.
|
||||||
|
* Based on configuration it could be called up to four times; ideally should
|
||||||
|
* be called once.
|
||||||
|
*/
|
||||||
|
struct check_request_result {
|
||||||
|
int checked;
|
||||||
|
int value;
|
||||||
|
};
|
||||||
/** check request sanity.
|
/** check request sanity.
|
||||||
* @param pkt: the wire packet to examine for sanity.
|
* @param pkt: the wire packet to examine for sanity.
|
||||||
* @param worker: parameters for checking.
|
* @param worker: parameters for checking.
|
||||||
* @return error code, 0 OK, or -1 discard.
|
* @param out: struct to update with the result.
|
||||||
*/
|
*/
|
||||||
static int
|
static void
|
||||||
worker_check_request(sldns_buffer* pkt, struct worker* worker)
|
worker_check_request(sldns_buffer* pkt, struct worker* worker,
|
||||||
|
struct check_request_result* out)
|
||||||
{
|
{
|
||||||
|
if(out->checked) return;
|
||||||
|
out->checked = 1;
|
||||||
if(sldns_buffer_limit(pkt) < LDNS_HEADER_SIZE) {
|
if(sldns_buffer_limit(pkt) < LDNS_HEADER_SIZE) {
|
||||||
verbose(VERB_QUERY, "request too short, discarded");
|
verbose(VERB_QUERY, "request too short, discarded");
|
||||||
return -1;
|
out->value = -1;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
if(sldns_buffer_limit(pkt) > NORMAL_UDP_SIZE &&
|
if(sldns_buffer_limit(pkt) > NORMAL_UDP_SIZE &&
|
||||||
worker->daemon->cfg->harden_large_queries) {
|
worker->daemon->cfg->harden_large_queries) {
|
||||||
verbose(VERB_QUERY, "request too large, discarded");
|
verbose(VERB_QUERY, "request too large, discarded");
|
||||||
return -1;
|
out->value = -1;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
if(LDNS_QR_WIRE(sldns_buffer_begin(pkt))) {
|
if(LDNS_QR_WIRE(sldns_buffer_begin(pkt))) {
|
||||||
verbose(VERB_QUERY, "request has QR bit on, discarded");
|
verbose(VERB_QUERY, "request has QR bit on, discarded");
|
||||||
return -1;
|
out->value = -1;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
if(LDNS_TC_WIRE(sldns_buffer_begin(pkt))) {
|
if(LDNS_TC_WIRE(sldns_buffer_begin(pkt))) {
|
||||||
LDNS_TC_CLR(sldns_buffer_begin(pkt));
|
LDNS_TC_CLR(sldns_buffer_begin(pkt));
|
||||||
verbose(VERB_QUERY, "request bad, has TC bit on");
|
verbose(VERB_QUERY, "request bad, has TC bit on");
|
||||||
return worker_err_ratelimit(worker, LDNS_RCODE_FORMERR);
|
out->value = worker_err_ratelimit(worker, LDNS_RCODE_FORMERR);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
if(LDNS_OPCODE_WIRE(sldns_buffer_begin(pkt)) != LDNS_PACKET_QUERY &&
|
if(LDNS_OPCODE_WIRE(sldns_buffer_begin(pkt)) != LDNS_PACKET_QUERY &&
|
||||||
LDNS_OPCODE_WIRE(sldns_buffer_begin(pkt)) != LDNS_PACKET_NOTIFY) {
|
LDNS_OPCODE_WIRE(sldns_buffer_begin(pkt)) != LDNS_PACKET_NOTIFY) {
|
||||||
verbose(VERB_QUERY, "request unknown opcode %d",
|
verbose(VERB_QUERY, "request unknown opcode %d",
|
||||||
LDNS_OPCODE_WIRE(sldns_buffer_begin(pkt)));
|
LDNS_OPCODE_WIRE(sldns_buffer_begin(pkt)));
|
||||||
return worker_err_ratelimit(worker, LDNS_RCODE_NOTIMPL);
|
out->value = worker_err_ratelimit(worker, LDNS_RCODE_NOTIMPL);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
if(LDNS_QDCOUNT(sldns_buffer_begin(pkt)) != 1) {
|
if(LDNS_QDCOUNT(sldns_buffer_begin(pkt)) != 1) {
|
||||||
verbose(VERB_QUERY, "request wrong nr qd=%d",
|
verbose(VERB_QUERY, "request wrong nr qd=%d",
|
||||||
LDNS_QDCOUNT(sldns_buffer_begin(pkt)));
|
LDNS_QDCOUNT(sldns_buffer_begin(pkt)));
|
||||||
return worker_err_ratelimit(worker, LDNS_RCODE_FORMERR);
|
out->value = worker_err_ratelimit(worker, LDNS_RCODE_FORMERR);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
if(LDNS_ANCOUNT(sldns_buffer_begin(pkt)) != 0 &&
|
if(LDNS_ANCOUNT(sldns_buffer_begin(pkt)) != 0 &&
|
||||||
(LDNS_ANCOUNT(sldns_buffer_begin(pkt)) != 1 ||
|
(LDNS_ANCOUNT(sldns_buffer_begin(pkt)) != 1 ||
|
||||||
LDNS_OPCODE_WIRE(sldns_buffer_begin(pkt)) != LDNS_PACKET_NOTIFY)) {
|
LDNS_OPCODE_WIRE(sldns_buffer_begin(pkt)) != LDNS_PACKET_NOTIFY)) {
|
||||||
verbose(VERB_QUERY, "request wrong nr an=%d",
|
verbose(VERB_QUERY, "request wrong nr an=%d",
|
||||||
LDNS_ANCOUNT(sldns_buffer_begin(pkt)));
|
LDNS_ANCOUNT(sldns_buffer_begin(pkt)));
|
||||||
return worker_err_ratelimit(worker, LDNS_RCODE_FORMERR);
|
out->value = worker_err_ratelimit(worker, LDNS_RCODE_FORMERR);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
if(LDNS_NSCOUNT(sldns_buffer_begin(pkt)) != 0) {
|
if(LDNS_NSCOUNT(sldns_buffer_begin(pkt)) != 0) {
|
||||||
verbose(VERB_QUERY, "request wrong nr ns=%d",
|
verbose(VERB_QUERY, "request wrong nr ns=%d",
|
||||||
LDNS_NSCOUNT(sldns_buffer_begin(pkt)));
|
LDNS_NSCOUNT(sldns_buffer_begin(pkt)));
|
||||||
return worker_err_ratelimit(worker, LDNS_RCODE_FORMERR);
|
out->value = worker_err_ratelimit(worker, LDNS_RCODE_FORMERR);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
if(LDNS_ARCOUNT(sldns_buffer_begin(pkt)) > 1) {
|
if(LDNS_ARCOUNT(sldns_buffer_begin(pkt)) > 1) {
|
||||||
verbose(VERB_QUERY, "request wrong nr ar=%d",
|
verbose(VERB_QUERY, "request wrong nr ar=%d",
|
||||||
LDNS_ARCOUNT(sldns_buffer_begin(pkt)));
|
LDNS_ARCOUNT(sldns_buffer_begin(pkt)));
|
||||||
return worker_err_ratelimit(worker, LDNS_RCODE_FORMERR);
|
out->value = worker_err_ratelimit(worker, LDNS_RCODE_FORMERR);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
return 0;
|
out->value = 0;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -1058,7 +1080,8 @@ static int
|
||||||
deny_refuse(struct comm_point* c, enum acl_access acl,
|
deny_refuse(struct comm_point* c, enum acl_access acl,
|
||||||
enum acl_access deny, enum acl_access refuse,
|
enum acl_access deny, enum acl_access refuse,
|
||||||
struct worker* worker, struct comm_reply* repinfo,
|
struct worker* worker, struct comm_reply* repinfo,
|
||||||
struct acl_addr* acladdr, int ede)
|
struct acl_addr* acladdr, int ede,
|
||||||
|
struct check_request_result* check_result)
|
||||||
{
|
{
|
||||||
if(acl == deny) {
|
if(acl == deny) {
|
||||||
if(verbosity >= VERB_ALGO) {
|
if(verbosity >= VERB_ALGO) {
|
||||||
|
|
@ -1081,9 +1104,16 @@ deny_refuse(struct comm_point* c, enum acl_access acl,
|
||||||
|
|
||||||
if(worker->stats.extended)
|
if(worker->stats.extended)
|
||||||
worker->stats.unwanted_queries++;
|
worker->stats.unwanted_queries++;
|
||||||
if(worker_check_request(c->buffer, worker) == -1) {
|
worker_check_request(c->buffer, worker, check_result);
|
||||||
|
if(check_result->value != 0) {
|
||||||
|
if(check_result->value != -1) {
|
||||||
|
LDNS_QR_SET(sldns_buffer_begin(c->buffer));
|
||||||
|
LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
|
||||||
|
check_result->value);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
comm_point_drop_reply(repinfo);
|
comm_point_drop_reply(repinfo);
|
||||||
return 0; /* discard this */
|
return 0;
|
||||||
}
|
}
|
||||||
/* worker_check_request() above guarantees that the buffer contains at
|
/* worker_check_request() above guarantees that the buffer contains at
|
||||||
* least a header and that qdcount == 1
|
* least a header and that qdcount == 1
|
||||||
|
|
@ -1237,7 +1267,8 @@ deny_refuse(struct comm_point* c, enum acl_access acl,
|
||||||
static int
|
static int
|
||||||
deny_refuse_all(struct comm_point* c, enum acl_access* acl,
|
deny_refuse_all(struct comm_point* c, enum acl_access* acl,
|
||||||
struct worker* worker, struct comm_reply* repinfo,
|
struct worker* worker, struct comm_reply* repinfo,
|
||||||
struct acl_addr** acladdr, int ede, int check_proxy)
|
struct acl_addr** acladdr, int ede, int check_proxy,
|
||||||
|
struct check_request_result* check_result)
|
||||||
{
|
{
|
||||||
if(check_proxy) {
|
if(check_proxy) {
|
||||||
*acladdr = acl_addr_lookup(worker->daemon->acl,
|
*acladdr = acl_addr_lookup(worker->daemon->acl,
|
||||||
|
|
@ -1252,16 +1283,17 @@ deny_refuse_all(struct comm_point* c, enum acl_access* acl,
|
||||||
}
|
}
|
||||||
*acl = acl_get_control(*acladdr);
|
*acl = acl_get_control(*acladdr);
|
||||||
return deny_refuse(c, *acl, acl_deny, acl_refuse, worker, repinfo,
|
return deny_refuse(c, *acl, acl_deny, acl_refuse, worker, repinfo,
|
||||||
*acladdr, ede);
|
*acladdr, ede, check_result);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
deny_refuse_non_local(struct comm_point* c, enum acl_access acl,
|
deny_refuse_non_local(struct comm_point* c, enum acl_access acl,
|
||||||
struct worker* worker, struct comm_reply* repinfo,
|
struct worker* worker, struct comm_reply* repinfo,
|
||||||
struct acl_addr* acladdr, int ede)
|
struct acl_addr* acladdr, int ede,
|
||||||
|
struct check_request_result* check_result)
|
||||||
{
|
{
|
||||||
return deny_refuse(c, acl, acl_deny_non_local, acl_refuse_non_local,
|
return deny_refuse(c, acl, acl_deny_non_local, acl_refuse_non_local,
|
||||||
worker, repinfo, acladdr, ede);
|
worker, repinfo, acladdr, ede, check_result);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|
@ -1292,6 +1324,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||||
struct query_info qinfo_tmp; /* placeholder for lookup_qinfo */
|
struct query_info qinfo_tmp; /* placeholder for lookup_qinfo */
|
||||||
struct respip_client_info* cinfo = NULL, cinfo_tmp;
|
struct respip_client_info* cinfo = NULL, cinfo_tmp;
|
||||||
struct timeval wait_time;
|
struct timeval wait_time;
|
||||||
|
struct check_request_result check_result = {0,0};
|
||||||
memset(&qinfo, 0, sizeof(qinfo));
|
memset(&qinfo, 0, sizeof(qinfo));
|
||||||
|
|
||||||
if((error != NETEVENT_NOERROR && error != NETEVENT_DONE)|| !repinfo) {
|
if((error != NETEVENT_NOERROR && error != NETEVENT_DONE)|| !repinfo) {
|
||||||
|
|
@ -1322,7 +1355,8 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||||
if(c->dnscrypt && !repinfo->is_dnscrypted) {
|
if(c->dnscrypt && !repinfo->is_dnscrypted) {
|
||||||
char buf[LDNS_MAX_DOMAINLEN+1];
|
char buf[LDNS_MAX_DOMAINLEN+1];
|
||||||
/* Check if this is unencrypted and asking for certs */
|
/* Check if this is unencrypted and asking for certs */
|
||||||
if(worker_check_request(c->buffer, worker) != 0) {
|
worker_check_request(c->buffer, worker, &check_result);
|
||||||
|
if(check_result.value != 0) {
|
||||||
verbose(VERB_ALGO,
|
verbose(VERB_ALGO,
|
||||||
"dnscrypt: worker check request: bad query.");
|
"dnscrypt: worker check request: bad query.");
|
||||||
log_addr(VERB_CLIENT,"from",&repinfo->client_addr,
|
log_addr(VERB_CLIENT,"from",&repinfo->client_addr,
|
||||||
|
|
@ -1371,25 +1405,27 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||||
/* Check deny/refuse ACLs */
|
/* Check deny/refuse ACLs */
|
||||||
if(repinfo->is_proxied) {
|
if(repinfo->is_proxied) {
|
||||||
if((ret=deny_refuse_all(c, &acl, worker, repinfo, &acladdr,
|
if((ret=deny_refuse_all(c, &acl, worker, repinfo, &acladdr,
|
||||||
worker->env.cfg->ede, 1)) != -1) {
|
worker->env.cfg->ede, 1, &check_result)) != -1) {
|
||||||
if(ret == 1)
|
if(ret == 1)
|
||||||
goto send_reply;
|
goto send_reply;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if((ret=deny_refuse_all(c, &acl, worker, repinfo, &acladdr,
|
if((ret=deny_refuse_all(c, &acl, worker, repinfo, &acladdr,
|
||||||
worker->env.cfg->ede, 0)) != -1) {
|
worker->env.cfg->ede, 0, &check_result)) != -1) {
|
||||||
if(ret == 1)
|
if(ret == 1)
|
||||||
goto send_reply;
|
goto send_reply;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if((ret=worker_check_request(c->buffer, worker)) != 0) {
|
worker_check_request(c->buffer, worker, &check_result);
|
||||||
|
if(check_result.value != 0) {
|
||||||
verbose(VERB_ALGO, "worker check request: bad query.");
|
verbose(VERB_ALGO, "worker check request: bad query.");
|
||||||
log_addr(VERB_CLIENT,"from",&repinfo->client_addr, repinfo->client_addrlen);
|
log_addr(VERB_CLIENT,"from",&repinfo->client_addr, repinfo->client_addrlen);
|
||||||
if(ret != -1) {
|
if(check_result.value != -1) {
|
||||||
LDNS_QR_SET(sldns_buffer_begin(c->buffer));
|
LDNS_QR_SET(sldns_buffer_begin(c->buffer));
|
||||||
LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), ret);
|
LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
|
||||||
|
check_result.value);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
comm_point_drop_reply(repinfo);
|
comm_point_drop_reply(repinfo);
|
||||||
|
|
@ -1612,7 +1648,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||||
/* We've looked in our local zones. If the answer isn't there, we
|
/* We've looked in our local zones. If the answer isn't there, we
|
||||||
* 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, acladdr,
|
if((ret=deny_refuse_non_local(c, acl, worker, repinfo, acladdr,
|
||||||
worker->env.cfg->ede)) != -1)
|
worker->env.cfg->ede, &check_result)) != -1)
|
||||||
{
|
{
|
||||||
regional_free_all(worker->scratchpad);
|
regional_free_all(worker->scratchpad);
|
||||||
if(ret == 1)
|
if(ret == 1)
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,8 @@
|
||||||
|
14 June 2023: George
|
||||||
|
- Properly handle all return values of worker_check_request during
|
||||||
|
early EDE code.
|
||||||
|
- Do not check the incoming request more than once.
|
||||||
|
|
||||||
12 June 2023: Wouter
|
12 June 2023: Wouter
|
||||||
- Merge #896: Fix: #895: pythonmodule: add all site-packages
|
- Merge #896: Fix: #895: pythonmodule: add all site-packages
|
||||||
directories to sys.path.
|
directories to sys.path.
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue