return 0;
}
+#define REQUEST_OK 0
+#define DROP_REQUEST -1
+#define RESPONSE_MESSAGE -2
+
+
/** ratelimit error replies
* @param worker: the worker struct with ratelimit counter
* @param err: error code that would be wanted.
if(worker->err_limit_time == *worker->env.now) {
/* see if limit is exceeded for this second */
if(worker->err_limit_count++ > ERROR_RATELIMIT)
- return -1;
+ return DROP_REQUEST;
} else {
/* new second, new limits */
worker->err_limit_time = *worker->env.now;
* 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.
+ * When value is a positive number, it countains the error to return.
+ * Otherwise DROP_REQUEST (-1) is returned, or RESPONSE_MESSAGE (-2) in
+ * case the qr bit was set. Value is set to REQUEST_OK (0) if all is good.
*/
struct check_request_result {
int checked;
out->checked = 1;
if(sldns_buffer_limit(pkt) < LDNS_HEADER_SIZE) {
verbose(VERB_QUERY, "request too short, discarded");
- out->value = -1;
+ out->value = DROP_REQUEST;
return;
}
if(sldns_buffer_limit(pkt) > NORMAL_UDP_SIZE &&
worker->daemon->cfg->harden_large_queries) {
verbose(VERB_QUERY, "request too large, discarded");
- out->value = -1;
+ out->value = DROP_REQUEST;
return;
}
if(LDNS_QR_WIRE(sldns_buffer_begin(pkt))) {
- verbose(VERB_QUERY, "request has QR bit on, discarded");
- out->value = -1;
+ /* verbose(VERB_QUERY, "request has QR bit on, discarded"); */
+ out->value = RESPONSE_MESSAGE;
return;
}
if(LDNS_TC_WIRE(sldns_buffer_begin(pkt))) {
out->value = worker_err_ratelimit(worker, LDNS_RCODE_FORMERR);
return;
}
- out->value = 0;
+ out->value = REQUEST_OK;
return;
}
+/** check response sanity.
+ * @param pkt: the wire packet to examine for sanity.
+ * @param worker: parameters for checking.
+ * @param out: 1 on success, otherwise 0.
+*/
+static int
+worker_check_response(sldns_buffer* pkt, struct worker* worker)
+{
+ if(LDNS_TC_WIRE(sldns_buffer_begin(pkt))) {
+ LDNS_TC_CLR(sldns_buffer_begin(pkt));
+ verbose(VERB_QUERY, "response bad, has TC bit on");
+ return 0;
+ }
+ if(LDNS_OPCODE_WIRE(sldns_buffer_begin(pkt)) != LDNS_PACKET_QUERY) {
+ verbose(VERB_QUERY, "not a query response");
+ return 0;
+ }
+ if(LDNS_QDCOUNT(sldns_buffer_begin(pkt)) != 1) {
+ verbose(VERB_QUERY, "request wrong nr qd=%d",
+ LDNS_QDCOUNT(sldns_buffer_begin(pkt)));
+ return 0;
+ }
+ if(LDNS_ANCOUNT(sldns_buffer_begin(pkt)) == 0) {
+ verbose(VERB_QUERY, "response must be an answer message");
+ return 0;
+ }
+ return 1;
+}
+
void
worker_handle_control_cmd(struct tube* ATTR_UNUSED(tube), uint8_t* msg,
size_t len, int error, void* arg)
if(worker->stats.extended)
worker->stats.unwanted_queries++;
worker_check_request(c->buffer, worker, check_result);
- if(check_result->value != 0) {
- if(check_result->value != -1) {
+ if(check_result->value != REQUEST_OK) {
+ if(check_result->value > 0) {
LDNS_QR_SET(sldns_buffer_begin(c->buffer));
LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
check_result->value);
char buf[LDNS_MAX_DOMAINLEN];
/* Check if this is unencrypted and asking for certs */
worker_check_request(c->buffer, worker, &check_result);
- if(check_result.value != 0) {
+ if(check_result.value != REQUEST_OK) {
verbose(VERB_ALGO,
"dnscrypt: worker check request: bad query.");
log_addr(VERB_CLIENT,"from",&repinfo->client_addr,
}
worker_check_request(c->buffer, worker, &check_result);
- if(check_result.value != 0) {
+ if (check_result.value == RESPONSE_MESSAGE) {
+ struct reply_info *rep = NULL;
+ int r;
+
+ if (!worker_check_response(c->buffer, worker)) {
+ log_err("Not a suitable response to cache");
+ comm_point_drop_reply(repinfo);
+ return 0;
+ }
+ if((r = reply_info_parse(c->buffer, worker->env.alloc, &qinfo,
+ &rep, worker->scratchpad, &edns))) {
+ log_err("bad response. Will not cache it (%d)", r);
+ comm_point_drop_reply(repinfo);
+ return 0;
+ }
+ dns_cache_store(&worker->env, &qinfo, rep, 0 /* is_referral */,
+ 0 /* leeway */, 0 /* pside */,
+ NULL /* region */, 0 /* flags */,
+ *worker->env.now, 0 /* is_valrec */);
+ comm_point_drop_reply(repinfo);
+ return 0;
+ } else if(check_result.value != REQUEST_OK) {
verbose(VERB_ALGO, "worker check request: bad query.");
log_addr(VERB_CLIENT,"from",&repinfo->client_addr, repinfo->client_addrlen);
- if(check_result.value != -1) {
+ if(check_result.value > REQUEST_OK) {
LDNS_QR_SET(sldns_buffer_begin(c->buffer));
LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
check_result.value);