From 890a3fe0a9084538a768c673960a4a681c174bb7 Mon Sep 17 00:00:00 2001 From: Wouter Wijngaards Date: Tue, 19 Jun 2007 14:46:14 +0000 Subject: [PATCH] options to harden against very small EDNS bufsize or very large query packets. git-svn-id: file:///svn/unbound/trunk@400 be551aaa-1e26-0410-a405-d3ace91eadb9 --- daemon/worker.c | 19 +++++++++++++++++-- doc/example.conf | 6 ++++++ doc/unbound.conf.5 | 8 ++++++++ util/config_file.c | 2 ++ util/config_file.h | 5 +++++ util/configlexer.lex | 2 ++ util/configparser.y | 24 +++++++++++++++++++++++- 7 files changed, 63 insertions(+), 3 deletions(-) diff --git a/daemon/worker.c b/daemon/worker.c index 671af29d1..a0f20db13 100644 --- a/daemon/worker.c +++ b/daemon/worker.c @@ -63,6 +63,9 @@ #include #include +/** 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)); diff --git a/doc/example.conf b/doc/example.conf index a8bf74c8d..df5a96fed 100644 --- a/doc/example.conf +++ b/doc/example.conf @@ -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 diff --git a/doc/unbound.conf.5 b/doc/unbound.conf.5 index fdf6303fd..97f77947b 100644 --- a/doc/unbound.conf.5 +++ b/doc/unbound.conf.5 @@ -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 +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 +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 diff --git a/util/config_file.c b/util/config_file.c index cf23a906e..e0c0a2b58 100644 --- a/util/config_file.c +++ b/util/config_file.c @@ -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); diff --git a/util/config_file.h b/util/config_file.h index 866fd3cd4..dfad7bea9 100644 --- a/util/config_file.h +++ b/util/config_file.h @@ -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 "". */ diff --git a/util/configlexer.lex b/util/configlexer.lex index 5ef451a02..f44f58dca 100644 --- a/util/configlexer.lex +++ b/util/configlexer.lex @@ -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;} diff --git a/util/configparser.y b/util/configparser.y index 73d82feef..91e0e96de 100644 --- a/util/configparser.y +++ b/util/configparser.y @@ -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)); -- 2.47.2