mirror of
https://github.com/NLnetLabs/unbound.git
synced 2024-09-21 06:37:08 +00:00
trust anchor storage and config.
git-svn-id: file:///svn/unbound/trunk@486 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
parent
669a20084c
commit
d48e17e1dd
@ -1,3 +1,9 @@
|
||||
3 August 2007: Wouter
|
||||
- replanning.
|
||||
- scrubber check section of lame NS set.
|
||||
- trust anchors can be in config file or read from zone file,
|
||||
DS and DNSKEY entries.
|
||||
|
||||
2 August 2007: Wouter
|
||||
- configure change for latest libevent trunk version (needs -lrt).
|
||||
- query_done and walk_supers are moved out of module interface.
|
||||
|
@ -152,9 +152,16 @@ server:
|
||||
# separated by spaces. "iterator" or "validator iterator"
|
||||
# module-config: "validator iterator"
|
||||
|
||||
# File with trusted keys for validation.
|
||||
# File with trusted keys for validation. Specify more than one file
|
||||
# with several entries, one file per entry.
|
||||
# Zone file format, with DS and DNSKEY entries.
|
||||
# trust-anchor-file: ""
|
||||
|
||||
# Trusted key for validation. DS or DNSKEY. specify the RR on a
|
||||
# single line, surrounded by "". TTL is ignored. class is IN default.
|
||||
# (These examples are from August 2007 and may not be valid anymore).
|
||||
# trust-anchor: "nlnetlabs.nl. DNSKEY 257 3 5 AQPzzTWMz8qSWIQlfRnPckx2BiVmkVN6LPupO3mbz7FhLSnm26n6iG9N Lby97Ji453aWZY3M5/xJBSOS2vWtco2t8C0+xeO1bc/d6ZTy32DHchpW 6rDH1vp86Ll+ha0tmwyy9QP7y2bVw5zSbFCrefk8qCUBgfHm9bHzMG1U BYtEIQ=="
|
||||
# trust-anchor: "jelte.nlnetlabs.nl. DS 42860 5 1 14D739EB566D2B1A5E216A0BA4D17FA9B038BE4A"
|
||||
|
||||
# Stub zones.
|
||||
# Create entries like below, to make all queries for 'example.com' and
|
||||
|
@ -192,6 +192,13 @@ Setting this to "validator iterator" will turn on validation.
|
||||
File with trusted keys for validation. Both DS and DNSKEY entries can appear
|
||||
in the file. The format of the file is the standard DNS Zone file format.
|
||||
Default is "", or no trust anchor file.
|
||||
.It \fBtrust-anchor:\fR <"Resource Record">
|
||||
A DS or DNSKEY RR for a key to use for validation. Multiple entries can be
|
||||
given to specify multiple trusted keys, in addition to the trust-anchor-files.
|
||||
The resource record is entered in the same format as 'dig' or 'drill' prints
|
||||
them, the same format as in the zone file. Has to be on a single line, with
|
||||
"" around it. A TTL can be specified for ease of cut and paste, but is ignored.
|
||||
A class can be specified, but class IN is default.
|
||||
.El
|
||||
|
||||
.Ss Stub Zone Options
|
||||
|
@ -111,7 +111,8 @@ config_create()
|
||||
cfg->hide_version = 0;
|
||||
cfg->identity = NULL;
|
||||
cfg->version = NULL;
|
||||
cfg->trust_anchor_file = NULL;
|
||||
cfg->trust_anchor_file_list = NULL;
|
||||
cfg->trust_anchor_list = NULL;
|
||||
if(!(cfg->module_conf = strdup("iterator"))) goto error_exit;
|
||||
return cfg;
|
||||
error_exit:
|
||||
@ -206,7 +207,8 @@ config_delete(struct config_file* cfg)
|
||||
free(cfg->identity);
|
||||
free(cfg->version);
|
||||
free(cfg->module_conf);
|
||||
free(cfg->trust_anchor_file);
|
||||
config_delstrlist(cfg->trust_anchor_file_list);
|
||||
config_delstrlist(cfg->trust_anchor_list);
|
||||
free(cfg);
|
||||
}
|
||||
|
||||
|
@ -139,8 +139,10 @@ struct config_file {
|
||||
/** the module configuration string */
|
||||
char* module_conf;
|
||||
|
||||
/** file with trusted DS and DNSKEYs in zonefile format */
|
||||
char* trust_anchor_file;
|
||||
/** files with trusted DS and DNSKEYs in zonefile format, list */
|
||||
struct config_strlist* trust_anchor_file_list;
|
||||
/** list of trustanchor keys, linked list */
|
||||
struct config_strlist* trust_anchor_list;
|
||||
|
||||
/** daemonize, i.e. fork into the background. */
|
||||
int do_daemonize;
|
||||
|
@ -143,6 +143,7 @@ identity{COLON} { YDOUT; return VAR_IDENTITY;}
|
||||
version{COLON} { YDOUT; return VAR_VERSION;}
|
||||
module-conf{COLON} { YDOUT; return VAR_MODULE_CONF;}
|
||||
trust-anchor-file{COLON} { YDOUT; return VAR_TRUST_ANCHOR_FILE;}
|
||||
trust-anchor{COLON} { YDOUT; return VAR_TRUST_ANCHOR;}
|
||||
{NEWLINE} { LEXOUT(("NL\n")); cfg_parser->line++;}
|
||||
|
||||
/* Quoted strings. Strip leading and ending quotes */
|
||||
|
@ -80,7 +80,7 @@ extern struct config_parser_state* cfg_parser;
|
||||
%token VAR_FORWARD_ZONE VAR_FORWARD_HOST VAR_FORWARD_ADDR
|
||||
%token VAR_DO_NOT_QUERY_ADDRESS VAR_HIDE_IDENTITY VAR_HIDE_VERSION
|
||||
%token VAR_IDENTITY VAR_VERSION VAR_HARDEN_GLUE VAR_MODULE_CONF
|
||||
%token VAR_TRUST_ANCHOR_FILE
|
||||
%token VAR_TRUST_ANCHOR_FILE VAR_TRUST_ANCHOR
|
||||
|
||||
%%
|
||||
toplevelvars: /* empty */ | toplevelvars toplevelvar ;
|
||||
@ -113,7 +113,8 @@ content_server: server_num_threads | server_verbosity | server_port |
|
||||
server_harden_short_bufsize | server_harden_large_queries |
|
||||
server_do_not_query_address | server_hide_identity |
|
||||
server_hide_version | server_identity | server_version |
|
||||
server_harden_glue | server_module_conf | server_trust_anchor_file
|
||||
server_harden_glue | server_module_conf | server_trust_anchor_file |
|
||||
server_trust_anchor
|
||||
;
|
||||
stubstart: VAR_STUB_ZONE
|
||||
{
|
||||
@ -288,8 +289,16 @@ server_pidfile: VAR_PIDFILE STRING
|
||||
server_trust_anchor_file: VAR_TRUST_ANCHOR_FILE STRING
|
||||
{
|
||||
OUTYY(("P(server_trust_anchor_file:%s)\n", $2));
|
||||
free(cfg_parser->cfg->trust_anchor_file);
|
||||
cfg_parser->cfg->trust_anchor_file = $2;
|
||||
if(!cfg_strlist_insert(&cfg_parser->cfg->
|
||||
trust_anchor_file_list, $2))
|
||||
yyerror("out of memory");
|
||||
}
|
||||
;
|
||||
server_trust_anchor: VAR_TRUST_ANCHOR STRING
|
||||
{
|
||||
OUTYY(("P(server_trust_anchor:%s)\n", $2));
|
||||
if(!cfg_strlist_insert(&cfg_parser->cfg->trust_anchor_list, $2))
|
||||
yyerror("out of memory");
|
||||
}
|
||||
;
|
||||
server_hide_identity: VAR_HIDE_IDENTITY STRING
|
||||
|
@ -43,6 +43,7 @@
|
||||
#include "util/data/packed_rrset.h"
|
||||
#include "util/data/dname.h"
|
||||
#include "util/log.h"
|
||||
#include "util/net_help.h"
|
||||
#include "util/region-allocator.h"
|
||||
#include "util/config_file.h"
|
||||
|
||||
@ -121,13 +122,274 @@ init_parents(struct val_anchors* anchors)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a trust anchor. Exact matching.
|
||||
* @param anchors: anchor storage.
|
||||
* @param name: name of trust anchor (wireformat)
|
||||
* @param namelabs: labels in name
|
||||
* @param namelen: length of name
|
||||
* @param dclass: class of trust anchor
|
||||
* @return NULL if not found.
|
||||
*/
|
||||
static struct trust_anchor*
|
||||
anchor_find(struct val_anchors* anchors, uint8_t* name, int namelabs,
|
||||
size_t namelen, uint16_t dclass)
|
||||
{
|
||||
struct trust_anchor key;
|
||||
rbnode_t* n;
|
||||
key.node.key = &key;
|
||||
key.name = name;
|
||||
key.namelabs = namelabs;
|
||||
key.namelen = namelen;
|
||||
key.dclass = dclass;
|
||||
n = rbtree_search(anchors->tree, &key);
|
||||
if(!n)
|
||||
return NULL;
|
||||
return (struct trust_anchor*)n->key;
|
||||
}
|
||||
|
||||
/** create new trust anchor object */
|
||||
static struct trust_anchor*
|
||||
anchor_new_ta(struct val_anchors* anchors, uint8_t* name, int namelabs,
|
||||
size_t namelen, uint16_t dclass)
|
||||
{
|
||||
struct trust_anchor* ta = (struct trust_anchor*)region_alloc(
|
||||
anchors->region, sizeof(struct trust_anchor));
|
||||
if(!ta)
|
||||
return NULL;
|
||||
memset(ta, 0, sizeof(*ta));
|
||||
ta->node.key = ta;
|
||||
ta->name = name;
|
||||
ta->namelabs = namelabs;
|
||||
ta->namelen = namelen;
|
||||
ta->dclass = dclass;
|
||||
return ta;
|
||||
}
|
||||
|
||||
/** find trustanchor key by exact data match */
|
||||
static struct ta_key*
|
||||
anchor_find_key(struct trust_anchor* ta, uint8_t* rdata, size_t rdata_len,
|
||||
uint16_t type)
|
||||
{
|
||||
struct ta_key* k;
|
||||
for(k = ta->keylist; k; k = k->next) {
|
||||
if(k->type == type && k->len == rdata_len &&
|
||||
memcmp(k->data, rdata, rdata_len) == 0)
|
||||
return k;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** create new trustanchor key */
|
||||
static struct ta_key*
|
||||
anchor_new_ta_key(struct val_anchors* anchors, uint8_t* rdata, size_t rdata_len,
|
||||
uint16_t type)
|
||||
{
|
||||
struct ta_key* k = (struct ta_key*)region_alloc(anchors->region,
|
||||
sizeof(*k));
|
||||
if(!k)
|
||||
return NULL;
|
||||
memset(k, 0, sizeof(*k));
|
||||
k->data = region_alloc_init(anchors->region, rdata, rdata_len);
|
||||
if(!k->data)
|
||||
return NULL;
|
||||
k->len = rdata_len;
|
||||
k->type = type;
|
||||
return k;
|
||||
}
|
||||
|
||||
/**
|
||||
* This routine adds a new RR to a trust anchor. The trust anchor may not
|
||||
* exist yet, and is created if not. The RR can be DS or DNSKEY.
|
||||
* This routine will also remove duplicates; storing them only once.
|
||||
* @param anchors: anchor storage.
|
||||
* @param name: name of trust anchor (wireformat)
|
||||
* @param type: type or RR
|
||||
* @param dclass: class of RR
|
||||
* @param rdata: rdata wireformat, starting with rdlength.
|
||||
* @param rdata_len: length of rdata including rdlength.
|
||||
* @return: 0 on error.
|
||||
*/
|
||||
static int
|
||||
anchor_store_new_key(struct val_anchors* anchors, uint8_t* name, uint16_t type,
|
||||
uint16_t dclass, uint8_t* rdata, size_t rdata_len)
|
||||
{
|
||||
struct ta_key* k;
|
||||
struct trust_anchor* ta;
|
||||
int namelabs;
|
||||
size_t namelen;
|
||||
namelabs = dname_count_size_labels(name, &namelen);
|
||||
if(type != LDNS_RR_TYPE_DS && type != LDNS_RR_TYPE_DNSKEY) {
|
||||
log_err("Bad type for trust anchor");
|
||||
return 0;
|
||||
}
|
||||
/* lookup or create trustanchor */
|
||||
ta = anchor_find(anchors, name, namelabs, namelen, dclass);
|
||||
if(!ta) {
|
||||
ta = anchor_new_ta(anchors, name, namelabs, namelen, dclass);
|
||||
if(!ta)
|
||||
return 0;
|
||||
}
|
||||
/* look for duplicates */
|
||||
if(anchor_find_key(ta, rdata, rdata_len, type)) {
|
||||
return 1;
|
||||
}
|
||||
k = anchor_new_ta_key(anchors, rdata, rdata_len, type);
|
||||
if(!k)
|
||||
return 0;
|
||||
/* add new key */
|
||||
if(type == LDNS_RR_TYPE_DS)
|
||||
ta->numDS++;
|
||||
else ta->numDNSKEY++;
|
||||
k->next = ta->keylist;
|
||||
ta->keylist = k;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add new RR. It converts ldns RR to wire format.
|
||||
* @param anchors: anchor storage.
|
||||
* @param buffer: parsing buffer.
|
||||
* @param rr: the rr (allocated by caller).
|
||||
* @return false on error.
|
||||
*/
|
||||
static int
|
||||
anchor_store_new_rr(struct val_anchors* anchors, ldns_buffer* buffer,
|
||||
ldns_rr* rr)
|
||||
{
|
||||
ldns_rdf* owner = ldns_rr_owner(rr);
|
||||
ldns_status status;
|
||||
ldns_buffer_clear(buffer);
|
||||
ldns_buffer_skip(buffer, 2); /* skip rdatalen */
|
||||
status = ldns_rr_rdata2buffer_wire(buffer, rr);
|
||||
if(status != LDNS_STATUS_OK) {
|
||||
log_err("error converting trustanchor to wireformat: %s",
|
||||
ldns_get_errorstr_by_id(status));
|
||||
return 0;
|
||||
}
|
||||
ldns_buffer_flip(buffer);
|
||||
ldns_buffer_write_u16_at(buffer, 0, ldns_buffer_limit(buffer) - 2);
|
||||
|
||||
if(!anchor_store_new_key(anchors, ldns_rdf_data(owner),
|
||||
ldns_rr_get_type(rr), ldns_rr_get_class(rr),
|
||||
ldns_buffer_begin(buffer), ldns_buffer_limit(buffer))) {
|
||||
return 0;
|
||||
}
|
||||
log_nametypeclass(VERB_DETAIL, "adding trusted key",
|
||||
ldns_rdf_data(owner),
|
||||
ldns_rr_get_type(rr), ldns_rr_get_class(rr));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store one string as trust anchor RR.
|
||||
* @param anchors: anchor storage.
|
||||
* @param buffer: parsing buffer.
|
||||
* @param str: string.
|
||||
* @return false on error.
|
||||
*/
|
||||
static int
|
||||
anchor_store_str(struct val_anchors* anchors, ldns_buffer* buffer,
|
||||
const char* str)
|
||||
{
|
||||
ldns_rr* rr = NULL;
|
||||
ldns_status status = ldns_rr_new_frm_str(&rr, str, 0, NULL, NULL);
|
||||
if(status != LDNS_STATUS_OK) {
|
||||
log_err("error parsing trust anchor: %s",
|
||||
ldns_get_errorstr_by_id(status));
|
||||
ldns_rr_free(rr);
|
||||
return 0;
|
||||
}
|
||||
if(!anchor_store_new_rr(anchors, buffer, rr)) {
|
||||
log_err("out of memory");
|
||||
ldns_rr_free(rr);
|
||||
return 0;
|
||||
}
|
||||
ldns_rr_free(rr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a file with trust anchors
|
||||
* @param anchors: anchor storage.
|
||||
* @param buffer: parsing buffer.
|
||||
* @param fname: string.
|
||||
* @return false on error.
|
||||
*/
|
||||
static int
|
||||
anchor_read_file(struct val_anchors* anchors, ldns_buffer* buffer,
|
||||
const char* fname)
|
||||
{
|
||||
uint32_t default_ttl = 3600;
|
||||
ldns_rdf* origin = NULL, *prev = NULL;
|
||||
int line_nr = 1;
|
||||
ldns_status status;
|
||||
ldns_rr* rr;
|
||||
int ok = 1;
|
||||
FILE* in = fopen(fname, "r");
|
||||
if(!in) {
|
||||
log_err("error opening file %s: %s", fname, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
while(!feof(in)) {
|
||||
rr = NULL;
|
||||
status = ldns_rr_new_frm_fp_l(&rr, in, &default_ttl, &origin,
|
||||
&prev, &line_nr);
|
||||
if(status == LDNS_STATUS_SYNTAX_EMPTY /* empty line */
|
||||
|| status == LDNS_STATUS_SYNTAX_TTL /* $TTL */
|
||||
|| status == LDNS_STATUS_SYNTAX_ORIGIN /* $ORIGIN */)
|
||||
continue;
|
||||
if(status != LDNS_STATUS_OK) {
|
||||
log_err("parse error in %s:%d : %s", fname, line_nr,
|
||||
ldns_get_errorstr_by_id(status));
|
||||
ldns_rr_free(rr);
|
||||
ok = 0;
|
||||
break;
|
||||
}
|
||||
if(ldns_rr_get_type(rr) != LDNS_RR_TYPE_DS &&
|
||||
ldns_rr_get_type(rr) != LDNS_RR_TYPE_DNSKEY) {
|
||||
ldns_rr_free(rr);
|
||||
continue;
|
||||
}
|
||||
if(!anchor_store_new_rr(anchors, buffer, rr)) {
|
||||
log_err("error at %s line %d", fname, line_nr);
|
||||
ldns_rr_free(rr);
|
||||
ok = 0;
|
||||
break;
|
||||
}
|
||||
ldns_rr_free(rr);
|
||||
}
|
||||
ldns_rdf_deep_free(origin);
|
||||
ldns_rdf_deep_free(prev);
|
||||
fclose(in);
|
||||
return ok;
|
||||
}
|
||||
|
||||
int
|
||||
anchors_apply_cfg(struct val_anchors* anchors, struct config_file* cfg)
|
||||
{
|
||||
if(cfg->trust_anchor_file && cfg->trust_anchor_file[0]) {
|
||||
/* read trust anchor file */
|
||||
struct config_strlist* f;
|
||||
ldns_buffer* parsebuf = ldns_buffer_new(65535);
|
||||
for(f = cfg->trust_anchor_file_list; f; f = f->next) {
|
||||
if(!f->str || f->str[0] == 0) /* empty "" */
|
||||
continue;
|
||||
if(!anchor_read_file(anchors, parsebuf, f->str)) {
|
||||
log_err("error reading trust-anchor-file: %s", f->str);
|
||||
ldns_buffer_free(parsebuf);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
for(f = cfg->trust_anchor_list; f; f = f->next) {
|
||||
if(!f->str || f->str[0] == 0) /* empty "" */
|
||||
continue;
|
||||
if(!anchor_store_str(anchors, parsebuf, f->str)) {
|
||||
log_err("error in trust-anchor: \"%s\"", f->str);
|
||||
ldns_buffer_free(parsebuf);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
init_parents(anchors);
|
||||
ldns_buffer_free(parsebuf);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -135,5 +397,33 @@ struct trust_anchor*
|
||||
anchors_lookup(struct val_anchors* anchors,
|
||||
uint8_t* qname, size_t qname_len, uint16_t qclass)
|
||||
{
|
||||
return NULL;
|
||||
struct trust_anchor key;
|
||||
struct trust_anchor* result;
|
||||
rbnode_t* res = NULL;
|
||||
key.node.key = &key;
|
||||
key.name = qname;
|
||||
key.namelabs = dname_count_labels(qname);
|
||||
key.namelen = qname_len;
|
||||
key.dclass = qclass;
|
||||
if(rbtree_find_less_equal(anchors->tree, &key, &res)) {
|
||||
/* exact */
|
||||
result = (struct trust_anchor*)res->key;
|
||||
} else {
|
||||
/* smaller element (or no element) */
|
||||
int m;
|
||||
result = (struct trust_anchor*)res->key;
|
||||
if(!result || result->dclass != qclass)
|
||||
return NULL;
|
||||
/* count number of labels matched */
|
||||
(void)dname_lab_cmp(result->name, result->namelabs, key.name,
|
||||
key.namelabs, &m);
|
||||
while(result) { /* go up until qname is subdomain of stub */
|
||||
if(result->namelabs <= m)
|
||||
break;
|
||||
result = result->parent;
|
||||
}
|
||||
if(!result)
|
||||
return NULL;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -67,9 +67,9 @@ struct val_anchors {
|
||||
struct ta_key {
|
||||
/** next in list */
|
||||
struct ta_key* next;
|
||||
/** rdata, in wireformat of the key RR. */
|
||||
/** rdata, in wireformat of the key RR. starts with rdlength. */
|
||||
uint8_t* data;
|
||||
/** length of the rdata */
|
||||
/** length of the rdata (including rdlength). */
|
||||
size_t len;
|
||||
/** DNS type (host format) of the key, DS or DNSKEY */
|
||||
uint16_t type;
|
||||
@ -84,6 +84,8 @@ struct trust_anchor {
|
||||
rbnode_t node;
|
||||
/** name of this trust anchor */
|
||||
uint8_t* name;
|
||||
/** length of name */
|
||||
size_t namelen;
|
||||
/** number of labels in name of rrset */
|
||||
int namelabs;
|
||||
/** the ancestor in the trustanchor tree */
|
||||
|
Loading…
Reference in New Issue
Block a user