]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
- Fix that unparseable error responses are ratelimited.
authorWouter Wijngaards <wouter@nlnetlabs.nl>
Fri, 29 May 2015 09:27:42 +0000 (09:27 +0000)
committerWouter Wijngaards <wouter@nlnetlabs.nl>
Fri, 29 May 2015 09:27:42 +0000 (09:27 +0000)
git-svn-id: file:///svn/unbound/trunk@3429 be551aaa-1e26-0410-a405-d3ace91eadb9

daemon/worker.c
daemon/worker.h
doc/Changelog

index 93481354f143ae11c7ed2e7c019ccc599e4c2555..4e4593f3b7ba17d54bb28d333445ad9627c1cb00 100644 (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), 
index ff69bc1acfd4ee905d39b06bb34707841ae11dab..63613430b0544a589d400b3c1b4ce433e4d8223d 100644 (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;
index 7995ddb10ff48b52f85365dab3f99b1d995589ae..50c27740a13aa90a811f0d86630289aee538b226 100644 (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.