- Fix that unparseable error responses are ratelimited.

git-svn-id: file:///svn/unbound/trunk@3429 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
Wouter Wijngaards 2015-05-29 09:27:42 +00:00
parent 5f9d2314a1
commit 4b0c7880e4
3 changed files with 39 additions and 6 deletions

View file

@ -86,6 +86,8 @@
/** Size of an UDP datagram */
#define NORMAL_UDP_SIZE 512 /* bytes */
/** ratelimit for error responses */
#define ERROR_RATELIMIT 100 /* qps */
/**
* seconds to add to prefetch leeway. This is a TTL that expires old rrsets
@ -291,6 +293,26 @@ worker_handle_service_reply(struct comm_point* c, void* arg, int error,
return 0;
}
/** ratelimit error replies
* @param worker: the worker struct with ratelimit counter
* @param err: error code that would be wanted.
* @returned value of err if okay, or -1 if it should be discarded instead.
*/
static int
worker_err_ratelimit(struct worker* worker, int err)
{
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;
} else {
/* new second, new limits */
worker->err_limit_time = *worker->env.now;
worker->err_limit_count = 1;
}
return err;
}
/** check request sanity.
* @param pkt: the wire packet to examine for sanity.
* @param worker: parameters for checking.
@ -315,32 +337,32 @@ worker_check_request(sldns_buffer* pkt, struct worker* worker)
if(LDNS_TC_WIRE(sldns_buffer_begin(pkt))) {
LDNS_TC_CLR(sldns_buffer_begin(pkt));
verbose(VERB_QUERY, "request bad, has TC bit on");
return LDNS_RCODE_FORMERR;
return worker_err_ratelimit(worker, LDNS_RCODE_FORMERR);
}
if(LDNS_OPCODE_WIRE(sldns_buffer_begin(pkt)) != LDNS_PACKET_QUERY) {
verbose(VERB_QUERY, "request unknown opcode %d",
LDNS_OPCODE_WIRE(sldns_buffer_begin(pkt)));
return LDNS_RCODE_NOTIMPL;
return worker_err_ratelimit(worker, LDNS_RCODE_NOTIMPL);
}
if(LDNS_QDCOUNT(sldns_buffer_begin(pkt)) != 1) {
verbose(VERB_QUERY, "request wrong nr qd=%d",
LDNS_QDCOUNT(sldns_buffer_begin(pkt)));
return LDNS_RCODE_FORMERR;
return worker_err_ratelimit(worker, LDNS_RCODE_FORMERR);
}
if(LDNS_ANCOUNT(sldns_buffer_begin(pkt)) != 0) {
verbose(VERB_QUERY, "request wrong nr an=%d",
LDNS_ANCOUNT(sldns_buffer_begin(pkt)));
return LDNS_RCODE_FORMERR;
return worker_err_ratelimit(worker, LDNS_RCODE_FORMERR);
}
if(LDNS_NSCOUNT(sldns_buffer_begin(pkt)) != 0) {
verbose(VERB_QUERY, "request wrong nr ns=%d",
LDNS_NSCOUNT(sldns_buffer_begin(pkt)));
return LDNS_RCODE_FORMERR;
return worker_err_ratelimit(worker, LDNS_RCODE_FORMERR);
}
if(LDNS_ARCOUNT(sldns_buffer_begin(pkt)) > 1) {
verbose(VERB_QUERY, "request wrong nr ar=%d",
LDNS_ARCOUNT(sldns_buffer_begin(pkt)));
return LDNS_RCODE_FORMERR;
return worker_err_ratelimit(worker, LDNS_RCODE_FORMERR);
}
return 0;
}
@ -813,6 +835,10 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
if(!query_info_parse(&qinfo, c->buffer)) {
verbose(VERB_ALGO, "worker parse request: formerror.");
log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
if(worker_err_ratelimit(worker, LDNS_RCODE_FORMERR) == -1) {
comm_point_drop_reply(repinfo);
return 0;
}
sldns_buffer_rewind(c->buffer);
LDNS_QR_SET(sldns_buffer_begin(c->buffer));
LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),

View file

@ -103,6 +103,10 @@ struct worker {
struct comm_point* cmd_com;
/** timer for statistics */
struct comm_timer* stat_timer;
/** ratelimit for errors, time value */
time_t err_limit_time;
/** ratelimit for errors, packet count */
unsigned int err_limit_count;
/** random() table for this worker. */
struct ub_randstate* rndstate;

View file

@ -1,3 +1,6 @@
29 May 2015: Wouter
- Fix that unparseable error responses are ratelimited.
26 May 2015: Wouter
- Document that ratelimit works with unbound-control set_option.