#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 <sys/types.h>
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,
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));
}
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,
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 <yes or no>
+If enabled id.server and hostname.bind queries are refused.
+.It \fBidentity:\fR <string>
+Set the identity to report. If set to "", the default, then the hostname
+of the server is returned.
+.It \fBhide-version:\fR <yes or no>
+If enabled version.server and version.bind queries are refused.
+.It \fBversion:\fR <string>
+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
%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 ;
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
{
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));