]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
options to harden against very small EDNS bufsize or very large query packets.
authorWouter Wijngaards <wouter@nlnetlabs.nl>
Tue, 19 Jun 2007 14:46:14 +0000 (14:46 +0000)
committerWouter Wijngaards <wouter@nlnetlabs.nl>
Tue, 19 Jun 2007 14:46:14 +0000 (14:46 +0000)
git-svn-id: file:///svn/unbound/trunk@400 be551aaa-1e26-0410-a405-d3ace91eadb9

daemon/worker.c
doc/example.conf
doc/unbound.conf.5
util/config_file.c
util/config_file.h
util/configlexer.lex
util/configparser.y

index 671af29d16aac82dbbb3757c861ad4e21f0aa435..a0f20db130d7b09f7b9de92bd8d7022c9e29b5e3 100644 (file)
@@ -63,6 +63,9 @@
 #include <netdb.h>
 #include <signal.h>
 
+/** Size of an UDP datagram */
+#define NORMAL_UDP_SIZE        512 /* bytes */
+
 void 
 worker_send_cmd(struct worker* worker, ldns_buffer* buffer,
        enum worker_commands cmd)
@@ -394,14 +397,20 @@ worker_handle_service_reply(struct comm_point* c, void* arg, int error,
 
 /** check request sanity. Returns error code, 0 OK, or -1 discard. 
  * @param pkt: the wire packet to examine for sanity.
+ * @param worker: parameters for checking.
 */
 static int 
-worker_check_request(ldns_buffer* pkt)
+worker_check_request(ldns_buffer* pkt, struct worker* worker)
 {
        if(ldns_buffer_limit(pkt) < LDNS_HEADER_SIZE) {
                verbose(VERB_DETAIL, "request too short, discarded");
                return -1;
        }
+       if(ldns_buffer_limit(pkt) > NORMAL_UDP_SIZE && 
+               worker->daemon->cfg->harden_large_queries) {
+               verbose(VERB_DETAIL, "request too large, discarded");
+               return -1;
+       }
        if(LDNS_QR_WIRE(ldns_buffer_begin(pkt))) {
                verbose(VERB_DETAIL, "request has QR bit on, discarded");
                return -1;
@@ -525,7 +534,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
                log_err("handle request called with err=%d", error);
                return 0;
        }
-       if((ret=worker_check_request(c->buffer)) != 0) {
+       if((ret=worker_check_request(c->buffer, worker)) != 0) {
                verbose(VERB_ALGO, "worker check request: bad query.");
                if(ret != -1) {
                        LDNS_QR_SET(ldns_buffer_begin(c->buffer));
@@ -571,6 +580,12 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
                attach_edns_record(c->buffer, &edns);
                return 1;
        }
+       if(edns.edns_present && edns.udp_size < NORMAL_UDP_SIZE &&
+               worker->daemon->cfg->harden_short_bufsize) {
+               verbose(VERB_DETAIL, "worker request: EDNS bufsize %d ignored",
+                       (int)edns.udp_size);
+               edns.udp_size = NORMAL_UDP_SIZE;
+       }
        if(edns.edns_present && edns.udp_size < LDNS_HEADER_SIZE) {
                verbose(VERB_ALGO, "worker request: edns is too small.");
                LDNS_QR_SET(ldns_buffer_begin(c->buffer));
index a8bf74c8d95329c7b47707b78b8425bed22c77e0..df5a96fed54e85d80cc62680488d8f25e266d08f 100644 (file)
@@ -128,6 +128,12 @@ server:
        #       positive value: fetch that many targets opportunistically.
        # Enclose the list of numbers between quotes ("").
        # target-fetch-policy: "3 2 1 0 0"
+       
+       # Harden against very small EDNS buffer sizes. 
+       # harden_short_bufsize: no
+       
+       # Harden against unseemly large queries.
+       # harden_large_queries: no
 
 # Stub zones.
 # Create entries like below, to make all queries for 'example.com' and 
index fdf6303fd221ff8b897196b89754e510bda0e650..97f77947b2f72bf4fc5f1dd981d0660fddb740b9 100644 (file)
@@ -134,6 +134,14 @@ that many targets opportunistically. Enclose the list between quotes ("").
 The default is "3 2 1 0 0". Setting all zeroes, "0 0 0 0 0" gives behaviour
 closer to that of BIND 9, while setting "-1 -1 -1 -1 -1" gives behaviour 
 rumoured to be closer to that of BIND 8.
+.It \fBharden-short-bufsize:\fR <yes or no>
+Very small EDNS buffer sizes from queries are ignored. Default is off, since
+it is legal protocol wise to send these, and unbound tries to give very 
+small answers to these queries, where possible.
+.It \fBharden-large-queries:\fR <yes or no>
+Very large queries are ignored. Default is off, since it is legal protocol
+wise to send these, and could be necessary for operation if TSIG or EDNS
+payload is very large.
 .El
 
 .Ss Stub Zone Options
index cf23a906e49c679947538a52a4947b42c5ebedb8..e0c0a2b58e443c768f6d6c325181021f9a7bf150 100644 (file)
@@ -100,6 +100,8 @@ config_create()
        cfg->num_ifs = 0;
        cfg->ifs = NULL;
        cfg->stubs = NULL;
+       cfg->harden_short_bufsize = 0;
+       cfg->harden_large_queries = 0;
        return cfg;
 error_exit:
        config_delete(cfg); 
index 866fd3cd42344f690c32498d218e398d6abdba50..dfad7bea973f7f20dfd584e0644e759d0576fcfb 100644 (file)
@@ -110,6 +110,11 @@ struct config_file {
        /** the stub definitions, linked list */
        struct config_stub* stubs;
 
+       /** harden against very small edns buffer sizes */
+       int harden_short_bufsize;
+       /** harden against very large query sizes */
+       int harden_large_queries;
+
        /** chrootdir, if not "" or chroot will be done */
        char* chrootdir;
        /** username to change to, if not "". */
index 5ef451a02e747d4f7de011a15b4b78698b68bf75..f44f58dca09a6861d5c45b49b6e8649260380b0d 100644 (file)
@@ -128,6 +128,8 @@ infra-cache-numhosts{COLON} { YDOUT; return VAR_INFRA_CACHE_NUMHOSTS;}
 infra-cache-numlame{COLON}     { YDOUT; return VAR_INFRA_CACHE_NUMLAME;}
 num-queries-per-thread{COLON}  { YDOUT; return VAR_NUM_QUERIES_PER_THREAD;}
 target-fetch-policy{COLON}     { YDOUT; return VAR_TARGET_FETCH_POLICY;}
+harden-short-bufsize{COLON}    { YDOUT; return VAR_HARDEN_SHORT_BUFSIZE;}
+harden-large-queries{COLON}    { YDOUT; return VAR_HARDEN_LARGE_QUERIES;}
 stub-zone{COLON}       { YDOUT; return VAR_STUB_ZONE;}
 name{COLON}            { YDOUT; return VAR_NAME;}
 stub-addr{COLON}       { YDOUT; return VAR_STUB_ADDR;}
index 73d82feef7bd18f49f9b4cb790b05d44333751c4..91e0e96de5f6b760dec52334f06fd92f39f5ebf5 100644 (file)
@@ -77,6 +77,7 @@ extern struct config_parser_state* cfg_parser;
 %token VAR_INFRA_HOST_TTL VAR_INFRA_LAME_TTL VAR_INFRA_CACHE_SLABS
 %token VAR_INFRA_CACHE_NUMHOSTS VAR_INFRA_CACHE_NUMLAME VAR_NAME
 %token VAR_STUB_ZONE VAR_STUB_HOST VAR_STUB_ADDR VAR_TARGET_FETCH_POLICY
+%token VAR_HARDEN_SHORT_BUFSIZE VAR_HARDEN_LARGE_QUERIES
 
 %%
 toplevelvars: /* empty */ | toplevelvars toplevelvar ;
@@ -104,7 +105,8 @@ content_server: server_num_threads | server_verbosity | server_port |
        server_infra_host_ttl | server_infra_lame_ttl | 
        server_infra_cache_slabs | server_infra_cache_numhosts |
        server_infra_cache_numlame | stubstart contents_stub | 
-       server_target_fetch_policy
+       server_target_fetch_policy | server_harden_short_bufsize |
+       server_harden_large_queries
        ;
 stubstart: VAR_STUB_ZONE
        {
@@ -385,6 +387,26 @@ server_target_fetch_policy: VAR_TARGET_FETCH_POLICY STRING
                cfg_parser->cfg->target_fetch_policy = $2;
        }
        ;
+server_harden_short_bufsize: VAR_HARDEN_SHORT_BUFSIZE STRING
+       {
+               OUTYY(("P(server_harden_short_bufsize:%s)\n", $2));
+               if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+                       yyerror("expected yes or no.");
+               else cfg_parser->cfg->harden_short_bufsize = 
+                       (strcmp($2, "yes")==0);
+               free($2);
+       }
+       ;
+server_harden_large_queries: VAR_HARDEN_LARGE_QUERIES STRING
+       {
+               OUTYY(("P(server_harden_large_queries:%s)\n", $2));
+               if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+                       yyerror("expected yes or no.");
+               else cfg_parser->cfg->harden_large_queries = 
+                       (strcmp($2, "yes")==0);
+               free($2);
+       }
+       ;
 stub_name: VAR_NAME STRING
        {
                OUTYY(("P(name:%s)\n", $2));