From 5e48023c6c0f48f39ba68cdbc04ce5dced03f475 Mon Sep 17 00:00:00 2001 From: Wouter Wijngaards Date: Thu, 19 Jul 2007 13:50:00 +0000 Subject: [PATCH] version.server and consorts support. git-svn-id: file:///svn/unbound/trunk@438 be551aaa-1e26-0410-a405-d3ace91eadb9 --- daemon/worker.c | 96 +++++++++++++++++++++++++++++++++++++++++++- doc/Changelog | 1 + doc/example.conf | 12 ++++++ doc/unbound.conf.5 | 10 +++++ util/config_file.c | 6 +++ util/config_file.h | 9 +++++ util/configlexer.lex | 4 ++ util/configparser.y | 38 +++++++++++++++++- 8 files changed, 173 insertions(+), 3 deletions(-) diff --git a/daemon/worker.c b/daemon/worker.c index 8ac337512..d48d486bb 100644 --- a/daemon/worker.c +++ b/daemon/worker.c @@ -57,6 +57,7 @@ #include "services/mesh.h" #include "util/data/msgparse.h" #include "util/data/msgencode.h" +#include "util/data/dname.h" #ifdef HAVE_SYS_TYPES_H # include @@ -260,6 +261,94 @@ answer_from_cache(struct worker* worker, struct lruhash_entry* e, uint16_t id, return 1; } +/** + * Fill CH class answer into buffer. Keeps query. + * @param pkt: buffer + * @param str: string to put into text record (<255). + * @param edns: edns reply information. + */ +static void +chaos_replystr(ldns_buffer* pkt, const char* str, struct edns_data* edns) +{ + int len = strlen(str); + int rd = LDNS_RD_WIRE(ldns_buffer_begin(pkt)); + int cd = LDNS_CD_WIRE(ldns_buffer_begin(pkt)); + if(len>255) len=255; /* cap size of TXT record */ + ldns_buffer_clear(pkt); + ldns_buffer_skip(pkt, sizeof(uint16_t)); /* skip id */ + ldns_buffer_write_u16(pkt, BIT_QR|BIT_RA); /* noerror, no flags */ + if(rd) LDNS_RD_SET(ldns_buffer_begin(pkt)); + if(cd) LDNS_CD_SET(ldns_buffer_begin(pkt)); + ldns_buffer_write_u16(pkt, 1); /* qdcount */ + ldns_buffer_write_u16(pkt, 1); /* ancount */ + ldns_buffer_write_u16(pkt, 0); /* nscount */ + ldns_buffer_write_u16(pkt, 0); /* arcount */ + (void)query_dname_len(pkt); /* skip qname */ + ldns_buffer_skip(pkt, sizeof(uint16_t)); /* skip qtype */ + ldns_buffer_skip(pkt, sizeof(uint16_t)); /* skip qclass */ + ldns_buffer_write_u16(pkt, 0xc00c); /* compr ptr to query */ + ldns_buffer_write_u16(pkt, LDNS_RR_TYPE_TXT); + ldns_buffer_write_u16(pkt, LDNS_RR_CLASS_CH); + ldns_buffer_write_u32(pkt, 0); /* TTL */ + ldns_buffer_write_u16(pkt, sizeof(uint8_t) + len); + ldns_buffer_write_u8(pkt, len); + ldns_buffer_write(pkt, str, len); + ldns_buffer_flip(pkt); + edns->edns_version = EDNS_ADVERTISED_VERSION; + edns->udp_size = EDNS_ADVERTISED_SIZE; + edns->bits &= EDNS_DO; + attach_edns_record(pkt, edns); +} + +/** + * Answer CH class queries. + * @param w: worker + * @param qinfo: query info. Pointer into packet buffer. + * @param edns: edns info from query. + * @param pkt: packet buffer. + * @return: true if a reply is to be sent. + */ +static int +answer_chaos(struct worker* w, struct query_info* qinfo, + struct edns_data* edns, ldns_buffer* pkt) +{ + struct config_file* cfg = w->env.cfg; + if(qinfo->qtype != LDNS_RR_TYPE_ANY && qinfo->qtype != LDNS_RR_TYPE_TXT) + return 0; + if(query_dname_compare(qinfo->qname, + (uint8_t*)"\002id\006server") == 0 || + query_dname_compare(qinfo->qname, + (uint8_t*)"\010hostname\004bind") == 0) + { + if(cfg->hide_identity) + return 0; + if(cfg->identity==NULL || cfg->identity[0]==0) { + char buf[MAXHOSTNAMELEN]; + if (gethostname(buf, MAXHOSTNAMELEN) == 0) + chaos_replystr(pkt, buf, edns); + else { + log_err("gethostname: %s", strerror(errno)); + chaos_replystr(pkt, "no hostname", edns); + } + } + else chaos_replystr(pkt, cfg->identity, edns); + return 1; + } + if(query_dname_compare(qinfo->qname, + (uint8_t*)"\007version\006server") == 0 || + query_dname_compare(qinfo->qname, + (uint8_t*)"\007version\004bind") == 0) + { + if(cfg->hide_version) + return 0; + if(cfg->version==NULL || cfg->version[0]==0) + chaos_replystr(pkt, PACKAGE_STRING, edns); + else chaos_replystr(pkt, cfg->version, edns); + return 1; + } + return 0; +} + /** handles callbacks from listening event interface */ static int worker_handle_request(struct comm_point* c, void* arg, int error, @@ -303,7 +392,6 @@ worker_handle_request(struct comm_point* c, void* arg, int error, LDNS_RCODE_REFUSED); return 1; } - h = query_info_hash(&qinfo); if((ret=parse_edns_from_pkt(c->buffer, &edns)) != 0) { verbose(VERB_ALGO, "worker parse edns: formerror."); LDNS_QR_SET(ldns_buffer_begin(c->buffer)); @@ -340,6 +428,12 @@ worker_handle_request(struct comm_point* c, void* arg, int error, } if(c->type != comm_udp) edns.udp_size = 65535; /* max size for TCP replies */ + if(qinfo.qclass == LDNS_RR_CLASS_CH && answer_chaos(worker, &qinfo, + &edns, c->buffer)) { + verbose(VERB_ALGO, "class CH reply"); + return 1; + } + h = query_info_hash(&qinfo); if((e=slabhash_lookup(worker->env.msg_cache, h, &qinfo, 0))) { /* answer from cache - we have acquired a readlock on it */ if(answer_from_cache(worker, e, diff --git a/doc/Changelog b/doc/Changelog index 9e8b64a03..e84d93a71 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -2,6 +2,7 @@ - shuffle NS selection when getting nameserver target addresses. - fixup of deadlock warnings, yield cpu in checklock code so that freebsd scheduler selects correct process to run. + - added identity and version config options and replies. 18 July 2007: Wouter - do not query addresses, 127.0.0.1, and ::1 by default. diff --git a/doc/example.conf b/doc/example.conf index dbafea0d8..d18f0d38f 100644 --- a/doc/example.conf +++ b/doc/example.conf @@ -111,6 +111,18 @@ server: # the pid file. # pidfile: "unbound.pid" + # enable to not answer id.server and hostname.bind queries. + # hide-identity: no + + # enable to not answer version.server and version.bind queries. + # hide-version: no + + # the identity to report. Leave "" or default to return hostname. + # identity: "" + + # the version to report. Leave "" or default to return package version. + # version: "" + # the target fetch policy. # series of integers describing the policy per dependency depth. # The number of values in the list determines the maximum dependency diff --git a/doc/unbound.conf.5 b/doc/unbound.conf.5 index f5064e8b5..9d55faee4 100644 --- a/doc/unbound.conf.5 +++ b/doc/unbound.conf.5 @@ -117,6 +117,16 @@ The logfile is appended to, in the following format: The process id is written to the file. Default is "unbound.pid". So, kill -HUP `cat /etc/unbound/unbound.pid` will trigger a reload, kill -QUIT `cat /etc/unbound/unbound.pid` will gracefully terminate. +.It \fBhide-identity:\fR +If enabled id.server and hostname.bind queries are refused. +.It \fBidentity:\fR +Set the identity to report. If set to "", the default, then the hostname +of the server is returned. +.It \fBhide-version:\fR +If enabled version.server and version.bind queries are refused. +.It \fBversion:\fR +Set the version to report. If set to "", the default, then the package +version is returned. .It \fBtarget-fetch-policy:\fR <"list of numbers"> Set the target fetch policy used by unbound to determine if it should fetch nameserver target addresses opportunistically. The policy is described per diff --git a/util/config_file.c b/util/config_file.c index c5300bd8b..a4ab1cf44 100644 --- a/util/config_file.c +++ b/util/config_file.c @@ -106,6 +106,10 @@ config_create() cfg->forwards = NULL; cfg->harden_short_bufsize = 0; cfg->harden_large_queries = 0; + cfg->hide_identity = 0; + cfg->hide_version = 0; + cfg->identity = NULL; + cfg->version = NULL; return cfg; error_exit: config_delete(cfg); @@ -196,6 +200,8 @@ config_delete(struct config_file* cfg) config_delstubs(cfg->stubs); config_delstubs(cfg->forwards); config_delstrlist(cfg->donotqueryaddrs); + free(cfg->identity); + free(cfg->version); free(cfg); } diff --git a/util/config_file.h b/util/config_file.h index c49fb7b11..f0a799661 100644 --- a/util/config_file.h +++ b/util/config_file.h @@ -124,6 +124,15 @@ struct config_file { char* logfile; /** pidfile to write pid to. */ char* pidfile; + + /** do not report identity (id.server, hostname.bind) */ + int hide_identity; + /** do not report version (version.server, version.bind) */ + int hide_version; + /** identity, hostname is returned if "". */ + char* identity; + /** version, package version returned if "". */ + char* version; /** daemonize, i.e. fork into the background. */ int do_daemonize; diff --git a/util/configlexer.lex b/util/configlexer.lex index a5ba7432c..5631c0478 100644 --- a/util/configlexer.lex +++ b/util/configlexer.lex @@ -136,6 +136,10 @@ forward-zone{COLON} { YDOUT; return VAR_FORWARD_ZONE;} forward-addr{COLON} { YDOUT; return VAR_FORWARD_ADDR;} forward-host{COLON} { YDOUT; return VAR_FORWARD_HOST;} do-not-query-address{COLON} { YDOUT; return VAR_DO_NOT_QUERY_ADDRESS;} +hide-identity{COLON} { YDOUT; return VAR_HIDE_IDENTITY;} +hide-version{COLON} { YDOUT; return VAR_HIDE_VERSION;} +identity{COLON} { YDOUT; return VAR_IDENTITY;} +version{COLON} { YDOUT; return VAR_VERSION;} {NEWLINE} { LEXOUT(("NL\n")); cfg_parser->line++;} /* Quoted strings. Strip leading and ending quotes */ diff --git a/util/configparser.y b/util/configparser.y index 38335eefc..31b982dd5 100644 --- a/util/configparser.y +++ b/util/configparser.y @@ -78,7 +78,8 @@ extern struct config_parser_state* cfg_parser; %token VAR_STUB_ZONE VAR_STUB_HOST VAR_STUB_ADDR VAR_TARGET_FETCH_POLICY %token VAR_HARDEN_SHORT_BUFSIZE VAR_HARDEN_LARGE_QUERIES %token VAR_FORWARD_ZONE VAR_FORWARD_HOST VAR_FORWARD_ADDR -%token VAR_DO_NOT_QUERY_ADDRESS +%token VAR_DO_NOT_QUERY_ADDRESS VAR_HIDE_IDENTITY VAR_HIDE_VERSION +%token VAR_IDENTITY VAR_VERSION %% toplevelvars: /* empty */ | toplevelvars toplevelvar ; @@ -109,7 +110,8 @@ content_server: server_num_threads | server_verbosity | server_port | server_infra_cache_slabs | server_infra_cache_numhosts | server_infra_cache_numlame | server_target_fetch_policy | server_harden_short_bufsize | server_harden_large_queries | - server_do_not_query_address + server_do_not_query_address | server_hide_identity | + server_hide_version | server_identity | server_version ; stubstart: VAR_STUB_ZONE { @@ -281,6 +283,38 @@ server_pidfile: VAR_PIDFILE STRING cfg_parser->cfg->pidfile = $2; } ; +server_hide_identity: VAR_HIDE_IDENTITY STRING + { + OUTYY(("P(server_hide_identity:%s)\n", $2)); + if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) + yyerror("expected yes or no."); + else cfg_parser->cfg->hide_identity = (strcmp($2, "yes")==0); + free($2); + } + ; +server_hide_version: VAR_HIDE_VERSION STRING + { + OUTYY(("P(server_hide_version:%s)\n", $2)); + if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) + yyerror("expected yes or no."); + else cfg_parser->cfg->hide_version = (strcmp($2, "yes")==0); + free($2); + } + ; +server_identity: VAR_IDENTITY STRING + { + OUTYY(("P(server_identity:%s)\n", $2)); + free(cfg_parser->cfg->identity); + cfg_parser->cfg->identity = $2; + } + ; +server_version: VAR_VERSION STRING + { + OUTYY(("P(server_version:%s)\n", $2)); + free(cfg_parser->cfg->version); + cfg_parser->cfg->version = $2; + } + ; server_msg_cache_size: VAR_MSG_CACHE_SIZE STRING { OUTYY(("P(server_msg_cache_size:%s)\n", $2)); -- 2.47.2