added unbound to external deps

This commit is contained in:
Riccardo Spagni
2014-10-05 23:44:31 +02:00
parent 732493c5cb
commit 9ef094b356
394 changed files with 199264 additions and 0 deletions

2393
external/unbound/validator/autotrust.c vendored Normal file

File diff suppressed because it is too large Load Diff

208
external/unbound/validator/autotrust.h vendored Normal file
View File

@@ -0,0 +1,208 @@
/*
* validator/autotrust.h - RFC5011 trust anchor management for unbound.
*
* Copyright (c) 2009, NLnet Labs. All rights reserved.
*
* This software is open source.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the NLNET LABS nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* \file
*
* Contains autotrust definitions.
*/
#ifndef VALIDATOR_AUTOTRUST_H
#define VALIDATOR_AUTOTRUST_H
#include "util/rbtree.h"
#include "util/data/packed_rrset.h"
struct val_anchors;
struct trust_anchor;
struct ub_packed_rrset_key;
struct module_env;
struct val_env;
struct sldns_buffer;
/** Autotrust anchor states */
typedef enum {
AUTR_STATE_START = 0,
AUTR_STATE_ADDPEND = 1,
AUTR_STATE_VALID = 2,
AUTR_STATE_MISSING = 3,
AUTR_STATE_REVOKED = 4,
AUTR_STATE_REMOVED = 5
} autr_state_t;
/**
* Autotrust metadata for one trust anchor key.
*/
struct autr_ta {
/** next key */
struct autr_ta* next;
/** the RR */
uint8_t* rr;
/** length of rr */
size_t rr_len, dname_len;
/** last update of key state (new pending count keeps date the same) */
time_t last_change;
/** 5011 state */
autr_state_t s;
/** pending count */
uint8_t pending_count;
/** fresh TA was seen */
uint8_t fetched;
/** revoked TA was seen */
uint8_t revoked;
};
/**
* Autotrust metadata for a trust point.
* This is part of the struct trust_anchor data.
*/
struct autr_point_data {
/** file to store the trust point in. chrootdir already applied. */
char* file;
/** rbtree node for probe sort, key is struct trust_anchor */
rbnode_t pnode;
/** the keys */
struct autr_ta* keys;
/** last queried DNSKEY set
* Not all failures are captured in this entry.
* If the validator did not even start (e.g. timeout or localservfail),
* then the last_queried and query_failed values are not updated.
*/
time_t last_queried;
/** last successful DNSKEY set */
time_t last_success;
/** next probe time */
time_t next_probe_time;
/** when to query if !failed */
time_t query_interval;
/** when to retry if failed */
time_t retry_time;
/**
* How many times did it fail. diagnostic only (has no effect).
* Only updated if there was a dnskey rrset that failed to verify.
*/
uint8_t query_failed;
/** true if the trust point has been revoked */
uint8_t revoked;
};
/**
* Autotrust global metadata.
*/
struct autr_global_data {
/** rbtree of autotrust anchors sorted by next probe time.
* When time is equal, sorted by anchor class, name. */
rbtree_t probe;
};
/**
* Create new global 5011 data structure.
* @return new structure or NULL on malloc failure.
*/
struct autr_global_data* autr_global_create(void);
/**
* Delete global 5011 data structure.
* @param global: global autotrust state to delete.
*/
void autr_global_delete(struct autr_global_data* global);
/**
* See if autotrust anchors are configured and how many.
* @param anchors: the trust anchors structure.
* @return number of autotrust trust anchors
*/
size_t autr_get_num_anchors(struct val_anchors* anchors);
/**
* Process probe timer. Add new probes if needed.
* @param env: module environment with time, with anchors and with the mesh.
* @return time of next probe (in seconds from now).
* If 0, then there is no next probe anymore (trust points deleted).
*/
time_t autr_probe_timer(struct module_env* env);
/** probe tree compare function */
int probetree_cmp(const void* x, const void* y);
/**
* Read autotrust file.
* @param anchors: the anchors structure.
* @param nm: name of the file (copied).
* @return false on failure.
*/
int autr_read_file(struct val_anchors* anchors, const char* nm);
/**
* Write autotrust file.
* @param env: environment with scratch space.
* @param tp: trust point to write.
*/
void autr_write_file(struct module_env* env, struct trust_anchor* tp);
/**
* Delete autr anchor, deletes the autr data but does not do
* unlinking from trees, caller does that.
* @param tp: trust point to delete.
*/
void autr_point_delete(struct trust_anchor* tp);
/**
* Perform autotrust processing.
* @param env: qstate environment with the anchors structure.
* @param ve: validator environment for verification of rrsigs.
* @param tp: trust anchor to process.
* @param dnskey_rrset: DNSKEY rrset probed (can be NULL if bad prime result).
* allocated in a region. Has not been validated yet.
* @return false if trust anchor was revoked completely.
* Otherwise logs errors to log, does not change return value.
* On errors, likely the trust point has been unchanged.
*/
int autr_process_prime(struct module_env* env, struct val_env* ve,
struct trust_anchor* tp, struct ub_packed_rrset_key* dnskey_rrset);
/**
* Debug printout of rfc5011 tracked anchors
* @param anchors: all the anchors.
*/
void autr_debug_print(struct val_anchors* anchors);
/** callback for query answer to 5011 probe */
void probe_answer_cb(void* arg, int rcode, struct sldns_buffer* buf,
enum sec_status sec, char* errinf);
#endif /* VALIDATOR_AUTOTRUST_H */

1256
external/unbound/validator/val_anchor.c vendored Normal file

File diff suppressed because it is too large Load Diff

219
external/unbound/validator/val_anchor.h vendored Normal file
View File

@@ -0,0 +1,219 @@
/*
* validator/val_anchor.h - validator trust anchor storage.
*
* Copyright (c) 2007, NLnet Labs. All rights reserved.
*
* This software is open source.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the NLNET LABS nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* \file
*
* This file contains storage for the trust anchors for the validator.
*/
#ifndef VALIDATOR_VAL_ANCHOR_H
#define VALIDATOR_VAL_ANCHOR_H
#include "util/rbtree.h"
#include "util/locks.h"
struct trust_anchor;
struct config_file;
struct ub_packed_rrset_key;
struct autr_point_data;
struct autr_global_data;
struct sldns_buffer;
/**
* Trust anchor store.
* The tree must be locked, while no other locks (from trustanchors) are held.
* And then an anchor searched for. Which can be locked or deleted. Then
* the tree can be unlocked again. This means you have to release the lock
* on a trust anchor and look it up again to delete it.
*/
struct val_anchors {
/** lock on trees */
lock_basic_t lock;
/**
* Anchors are store in this tree. Sort order is chosen, so that
* dnames are in nsec-like order. A lookup on class, name will return
* an exact match of the closest match, with the ancestor needed.
* contents of type trust_anchor.
*/
rbtree_t* tree;
/** The DLV trust anchor (if one is configured, else NULL) */
struct trust_anchor* dlv_anchor;
/** Autotrust global data, anchors sorted by next probe time */
struct autr_global_data* autr;
};
/**
* Trust anchor key
*/
struct ta_key {
/** next in list */
struct ta_key* next;
/** rdata, in wireformat of the key RR. starts with rdlength. */
uint8_t* data;
/** length of the rdata (including rdlength). */
size_t len;
/** DNS type (host format) of the key, DS or DNSKEY */
uint16_t type;
};
/**
* A trust anchor in the trust anchor store.
* Unique by name, class.
*/
struct trust_anchor {
/** rbtree node, key is this structure */
rbnode_t node;
/** lock on the entire anchor and its keys; for autotrust changes */
lock_basic_t lock;
/** 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 */
struct trust_anchor* parent;
/**
* List of DS or DNSKEY rrs that form the trust anchor.
*/
struct ta_key* keylist;
/** Autotrust anchor point data, or NULL */
struct autr_point_data* autr;
/** number of DSs in the keylist */
size_t numDS;
/** number of DNSKEYs in the keylist */
size_t numDNSKEY;
/** the DS RRset */
struct ub_packed_rrset_key* ds_rrset;
/** The DNSKEY RRset */
struct ub_packed_rrset_key* dnskey_rrset;
/** class of the trust anchor */
uint16_t dclass;
};
/**
* Create trust anchor storage
* @return new storage or NULL on error.
*/
struct val_anchors* anchors_create(void);
/**
* Delete trust anchor storage.
* @param anchors: to delete.
*/
void anchors_delete(struct val_anchors* anchors);
/**
* Process trust anchor config.
* @param anchors: struct anchor storage
* @param cfg: config options.
* @return 0 on error.
*/
int anchors_apply_cfg(struct val_anchors* anchors, struct config_file* cfg);
/**
* Recalculate parent pointers. The caller must hold the lock on the
* anchors structure (say after removing an item from the rbtree).
* Caller must not hold any locks on trust anchors.
* After the call is complete the parent pointers are updated and an item
* just removed is no longer referenced in parent pointers.
* @param anchors: the structure to update.
*/
void anchors_init_parents_locked(struct val_anchors* anchors);
/**
* Given a qname/qclass combination, find the trust anchor closest above it.
* Or return NULL if none exists.
*
* @param anchors: struct anchor storage
* @param qname: query name, uncompressed wireformat.
* @param qname_len: length of qname.
* @param qclass: class to query for.
* @return the trust anchor or NULL if none is found. The anchor is locked.
*/
struct trust_anchor* anchors_lookup(struct val_anchors* anchors,
uint8_t* qname, size_t qname_len, uint16_t qclass);
/**
* 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. The anchor is locked.
*/
struct trust_anchor* anchor_find(struct val_anchors* anchors,
uint8_t* name, int namelabs, size_t namelen, uint16_t dclass);
/**
* Store one string as trust anchor RR.
* @param anchors: anchor storage.
* @param buffer: parsing buffer, to generate the RR wireformat in.
* @param str: string.
* @return NULL on error.
*/
struct trust_anchor* anchor_store_str(struct val_anchors* anchors,
struct sldns_buffer* buffer, const char* str);
/**
* Get memory in use by the trust anchor storage
* @param anchors: anchor storage.
* @return memory in use in bytes.
*/
size_t anchors_get_mem(struct val_anchors* anchors);
/** compare two trust anchors */
int anchor_cmp(const void* k1, const void* k2);
/**
* Add insecure point trust anchor. For external use (locks and init_parents)
* @param anchors: anchor storage.
* @param c: class.
* @param nm: name of insecure trust point.
* @return false on alloc failure.
*/
int anchors_add_insecure(struct val_anchors* anchors, uint16_t c, uint8_t* nm);
/**
* Delete insecure point trust anchor. Does not remove if no such point.
* For external use (locks and init_parents)
* @param anchors: anchor storage.
* @param c: class.
* @param nm: name of insecure trust point.
*/
void anchors_delete_insecure(struct val_anchors* anchors, uint16_t c,
uint8_t* nm);
#endif /* VALIDATOR_VAL_ANCHOR_H */

172
external/unbound/validator/val_kcache.c vendored Normal file
View File

@@ -0,0 +1,172 @@
/*
* validator/val_kcache.c - validator key shared cache with validated keys
*
* Copyright (c) 2007, NLnet Labs. All rights reserved.
*
* This software is open source.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the NLNET LABS nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* \file
*
* This file contains functions for dealing with the validator key cache.
*/
#include "config.h"
#include "validator/val_kcache.h"
#include "validator/val_kentry.h"
#include "util/log.h"
#include "util/config_file.h"
#include "util/data/dname.h"
#include "util/module.h"
struct key_cache*
key_cache_create(struct config_file* cfg)
{
struct key_cache* kcache = (struct key_cache*)calloc(1,
sizeof(*kcache));
size_t numtables, start_size, maxmem;
if(!kcache) {
log_err("malloc failure");
return NULL;
}
numtables = cfg->key_cache_slabs;
start_size = HASH_DEFAULT_STARTARRAY;
maxmem = cfg->key_cache_size;
kcache->slab = slabhash_create(numtables, start_size, maxmem,
&key_entry_sizefunc, &key_entry_compfunc,
&key_entry_delkeyfunc, &key_entry_deldatafunc, NULL);
if(!kcache->slab) {
log_err("malloc failure");
free(kcache);
return NULL;
}
return kcache;
}
void
key_cache_delete(struct key_cache* kcache)
{
if(!kcache)
return;
slabhash_delete(kcache->slab);
free(kcache);
}
void
key_cache_insert(struct key_cache* kcache, struct key_entry_key* kkey,
struct module_qstate* qstate)
{
struct key_entry_key* k = key_entry_copy(kkey);
if(!k)
return;
if(key_entry_isbad(k) && qstate->errinf &&
qstate->env->cfg->val_log_level >= 2) {
/* on malloc failure there is simply no reason string */
key_entry_set_reason(k, errinf_to_str(qstate));
}
key_entry_hash(k);
slabhash_insert(kcache->slab, k->entry.hash, &k->entry,
k->entry.data, NULL);
}
/**
* Lookup exactly in the key cache. Returns pointer to locked entry.
* Caller must unlock it after use.
* @param kcache: the key cache.
* @param name: for what name to look; uncompressed wireformat
* @param namelen: length of the name.
* @param key_class: class of the key.
* @param wr: set true to get a writelock.
* @return key entry, locked, or NULL if not found. No TTL checking is
* performed.
*/
static struct key_entry_key*
key_cache_search(struct key_cache* kcache, uint8_t* name, size_t namelen,
uint16_t key_class, int wr)
{
struct lruhash_entry* e;
struct key_entry_key lookfor;
lookfor.entry.key = &lookfor;
lookfor.name = name;
lookfor.namelen = namelen;
lookfor.key_class = key_class;
key_entry_hash(&lookfor);
e = slabhash_lookup(kcache->slab, lookfor.entry.hash, &lookfor, wr);
if(!e)
return NULL;
return (struct key_entry_key*)e->key;
}
struct key_entry_key*
key_cache_obtain(struct key_cache* kcache, uint8_t* name, size_t namelen,
uint16_t key_class, struct regional* region, time_t now)
{
/* keep looking until we find a nonexpired entry */
while(1) {
struct key_entry_key* k = key_cache_search(kcache, name,
namelen, key_class, 0);
if(k) {
/* see if TTL is OK */
struct key_entry_data* d = (struct key_entry_data*)
k->entry.data;
if(now <= d->ttl) {
/* copy and return it */
struct key_entry_key* retkey =
key_entry_copy_toregion(k, region);
lock_rw_unlock(&k->entry.lock);
return retkey;
}
lock_rw_unlock(&k->entry.lock);
}
/* snip off first label to continue */
if(dname_is_root(name))
break;
dname_remove_label(&name, &namelen);
}
return NULL;
}
size_t
key_cache_get_mem(struct key_cache* kcache)
{
return sizeof(*kcache) + slabhash_get_mem(kcache->slab);
}
void key_cache_remove(struct key_cache* kcache,
uint8_t* name, size_t namelen, uint16_t key_class)
{
struct key_entry_key lookfor;
lookfor.entry.key = &lookfor;
lookfor.name = name;
lookfor.namelen = namelen;
lookfor.key_class = key_class;
key_entry_hash(&lookfor);
slabhash_remove(kcache->slab, lookfor.entry.hash, &lookfor);
}

118
external/unbound/validator/val_kcache.h vendored Normal file
View File

@@ -0,0 +1,118 @@
/*
* validator/val_kcache.h - validator key shared cache with validated keys
*
* Copyright (c) 2007, NLnet Labs. All rights reserved.
*
* This software is open source.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the NLNET LABS nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* \file
*
* This file contains functions for caching validated key entries.
*/
#ifndef VALIDATOR_VAL_KCACHE_H
#define VALIDATOR_VAL_KCACHE_H
#include "util/storage/slabhash.h"
struct key_entry_key;
struct key_entry_data;
struct config_file;
struct regional;
struct module_qstate;
/**
* Key cache
*/
struct key_cache {
/** uses slabhash for storage, type key_entry_key, key_entry_data */
struct slabhash* slab;
};
/**
* Create the key cache
* @param cfg: config settings for the key cache.
* @return new key cache or NULL on malloc failure.
*/
struct key_cache* key_cache_create(struct config_file* cfg);
/**
* Delete the key cache
* @param kcache: to delete
*/
void key_cache_delete(struct key_cache* kcache);
/**
* Insert or update a key cache entry. Note that the insert may silently
* fail if there is not enough memory.
*
* @param kcache: the key cache.
* @param kkey: key entry key, assumed malloced in a region, is copied
* to perform update or insertion. Its data pointer is also copied.
* @param qstate: store errinf reason in case its bad.
*/
void key_cache_insert(struct key_cache* kcache, struct key_entry_key* kkey,
struct module_qstate* qstate);
/**
* Remove an entry from the key cache.
* @param kcache: the key cache.
* @param name: for what name to look; uncompressed wireformat
* @param namelen: length of the name.
* @param key_class: class of the key.
*/
void key_cache_remove(struct key_cache* kcache,
uint8_t* name, size_t namelen, uint16_t key_class);
/**
* Lookup key entry in the cache. Looks up the closest key entry above the
* given name.
* @param kcache: the key cache.
* @param name: for what name to look; uncompressed wireformat
* @param namelen: length of the name.
* @param key_class: class of the key.
* @param region: a copy of the key_entry is allocated in this region.
* @param now: current time.
* @return pointer to a newly allocated key_entry copy in the region, if
* a key entry could be found, and allocation succeeded and TTL was OK.
* Otherwise, NULL is returned.
*/
struct key_entry_key* key_cache_obtain(struct key_cache* kcache,
uint8_t* name, size_t namelen, uint16_t key_class,
struct regional* region, time_t now);
/**
* Get memory in use by the key cache.
* @param kcache: the key cache.
* @return memory in use in bytes.
*/
size_t key_cache_get_mem(struct key_cache* kcache);
#endif /* VALIDATOR_VAL_KCACHE_H */

413
external/unbound/validator/val_kentry.c vendored Normal file
View File

@@ -0,0 +1,413 @@
/*
* validator/val_kentry.c - validator key entry definition.
*
* Copyright (c) 2007, NLnet Labs. All rights reserved.
*
* This software is open source.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the NLNET LABS nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* \file
*
* This file contains functions for dealing with validator key entries.
*/
#include "config.h"
#include "validator/val_kentry.h"
#include "util/data/packed_rrset.h"
#include "util/data/dname.h"
#include "util/storage/lookup3.h"
#include "util/regional.h"
#include "util/net_help.h"
#include "ldns/rrdef.h"
#include "ldns/keyraw.h"
size_t
key_entry_sizefunc(void* key, void* data)
{
struct key_entry_key* kk = (struct key_entry_key*)key;
struct key_entry_data* kd = (struct key_entry_data*)data;
size_t s = sizeof(*kk) + kk->namelen;
s += sizeof(*kd) + lock_get_mem(&kk->entry.lock);
if(kd->rrset_data)
s += packed_rrset_sizeof(kd->rrset_data);
if(kd->reason)
s += strlen(kd->reason)+1;
if(kd->algo)
s += strlen((char*)kd->algo)+1;
return s;
}
int
key_entry_compfunc(void* k1, void* k2)
{
struct key_entry_key* n1 = (struct key_entry_key*)k1;
struct key_entry_key* n2 = (struct key_entry_key*)k2;
if(n1->key_class != n2->key_class) {
if(n1->key_class < n2->key_class)
return -1;
return 1;
}
return query_dname_compare(n1->name, n2->name);
}
void
key_entry_delkeyfunc(void* key, void* ATTR_UNUSED(userarg))
{
struct key_entry_key* kk = (struct key_entry_key*)key;
if(!key)
return;
lock_rw_destroy(&kk->entry.lock);
free(kk->name);
free(kk);
}
void
key_entry_deldatafunc(void* data, void* ATTR_UNUSED(userarg))
{
struct key_entry_data* kd = (struct key_entry_data*)data;
free(kd->reason);
free(kd->rrset_data);
free(kd->algo);
free(kd);
}
void
key_entry_hash(struct key_entry_key* kk)
{
kk->entry.hash = 0x654;
kk->entry.hash = hashlittle(&kk->key_class, sizeof(kk->key_class),
kk->entry.hash);
kk->entry.hash = dname_query_hash(kk->name, kk->entry.hash);
}
struct key_entry_key*
key_entry_copy_toregion(struct key_entry_key* kkey, struct regional* region)
{
struct key_entry_key* newk;
newk = regional_alloc_init(region, kkey, sizeof(*kkey));
if(!newk)
return NULL;
newk->name = regional_alloc_init(region, kkey->name, kkey->namelen);
if(!newk->name)
return NULL;
newk->entry.key = newk;
if(newk->entry.data) {
/* copy data element */
struct key_entry_data *d = (struct key_entry_data*)
kkey->entry.data;
struct key_entry_data *newd;
newd = regional_alloc_init(region, d, sizeof(*d));
if(!newd)
return NULL;
/* copy rrset */
if(d->rrset_data) {
newd->rrset_data = regional_alloc_init(region,
d->rrset_data,
packed_rrset_sizeof(d->rrset_data));
if(!newd->rrset_data)
return NULL;
packed_rrset_ptr_fixup(newd->rrset_data);
}
if(d->reason) {
newd->reason = regional_strdup(region, d->reason);
if(!newd->reason)
return NULL;
}
if(d->algo) {
newd->algo = (uint8_t*)regional_strdup(region,
(char*)d->algo);
if(!newd->algo)
return NULL;
}
newk->entry.data = newd;
}
return newk;
}
struct key_entry_key*
key_entry_copy(struct key_entry_key* kkey)
{
struct key_entry_key* newk;
if(!kkey)
return NULL;
newk = memdup(kkey, sizeof(*kkey));
if(!newk)
return NULL;
newk->name = memdup(kkey->name, kkey->namelen);
if(!newk->name) {
free(newk);
return NULL;
}
lock_rw_init(&newk->entry.lock);
newk->entry.key = newk;
if(newk->entry.data) {
/* copy data element */
struct key_entry_data *d = (struct key_entry_data*)
kkey->entry.data;
struct key_entry_data *newd;
newd = memdup(d, sizeof(*d));
if(!newd) {
free(newk->name);
free(newk);
return NULL;
}
/* copy rrset */
if(d->rrset_data) {
newd->rrset_data = memdup(d->rrset_data,
packed_rrset_sizeof(d->rrset_data));
if(!newd->rrset_data) {
free(newd);
free(newk->name);
free(newk);
return NULL;
}
packed_rrset_ptr_fixup(newd->rrset_data);
}
if(d->reason) {
newd->reason = strdup(d->reason);
if(!newd->reason) {
free(newd->rrset_data);
free(newd);
free(newk->name);
free(newk);
return NULL;
}
}
if(d->algo) {
newd->algo = (uint8_t*)strdup((char*)d->algo);
if(!newd->algo) {
free(newd->rrset_data);
free(newd->reason);
free(newd);
free(newk->name);
free(newk);
return NULL;
}
}
newk->entry.data = newd;
}
return newk;
}
int
key_entry_isnull(struct key_entry_key* kkey)
{
struct key_entry_data* d = (struct key_entry_data*)kkey->entry.data;
return (!d->isbad && d->rrset_data == NULL);
}
int
key_entry_isgood(struct key_entry_key* kkey)
{
struct key_entry_data* d = (struct key_entry_data*)kkey->entry.data;
return (!d->isbad && d->rrset_data != NULL);
}
int
key_entry_isbad(struct key_entry_key* kkey)
{
struct key_entry_data* d = (struct key_entry_data*)kkey->entry.data;
return (int)(d->isbad);
}
void
key_entry_set_reason(struct key_entry_key* kkey, char* reason)
{
struct key_entry_data* d = (struct key_entry_data*)kkey->entry.data;
d->reason = reason;
}
char*
key_entry_get_reason(struct key_entry_key* kkey)
{
struct key_entry_data* d = (struct key_entry_data*)kkey->entry.data;
return d->reason;
}
/** setup key entry in region */
static int
key_entry_setup(struct regional* region,
uint8_t* name, size_t namelen, uint16_t dclass,
struct key_entry_key** k, struct key_entry_data** d)
{
*k = regional_alloc(region, sizeof(**k));
if(!*k)
return 0;
memset(*k, 0, sizeof(**k));
(*k)->entry.key = *k;
(*k)->name = regional_alloc_init(region, name, namelen);
if(!(*k)->name)
return 0;
(*k)->namelen = namelen;
(*k)->key_class = dclass;
*d = regional_alloc(region, sizeof(**d));
if(!*d)
return 0;
(*k)->entry.data = *d;
return 1;
}
struct key_entry_key*
key_entry_create_null(struct regional* region,
uint8_t* name, size_t namelen, uint16_t dclass, time_t ttl,
time_t now)
{
struct key_entry_key* k;
struct key_entry_data* d;
if(!key_entry_setup(region, name, namelen, dclass, &k, &d))
return NULL;
d->ttl = now + ttl;
d->isbad = 0;
d->reason = NULL;
d->rrset_type = LDNS_RR_TYPE_DNSKEY;
d->rrset_data = NULL;
d->algo = NULL;
return k;
}
struct key_entry_key*
key_entry_create_rrset(struct regional* region,
uint8_t* name, size_t namelen, uint16_t dclass,
struct ub_packed_rrset_key* rrset, uint8_t* sigalg, time_t now)
{
struct key_entry_key* k;
struct key_entry_data* d;
struct packed_rrset_data* rd = (struct packed_rrset_data*)
rrset->entry.data;
if(!key_entry_setup(region, name, namelen, dclass, &k, &d))
return NULL;
d->ttl = rd->ttl + now;
d->isbad = 0;
d->reason = NULL;
d->rrset_type = ntohs(rrset->rk.type);
d->rrset_data = (struct packed_rrset_data*)regional_alloc_init(region,
rd, packed_rrset_sizeof(rd));
if(!d->rrset_data)
return NULL;
if(sigalg) {
d->algo = (uint8_t*)regional_strdup(region, (char*)sigalg);
if(!d->algo)
return NULL;
} else d->algo = NULL;
packed_rrset_ptr_fixup(d->rrset_data);
return k;
}
struct key_entry_key*
key_entry_create_bad(struct regional* region,
uint8_t* name, size_t namelen, uint16_t dclass, time_t ttl,
time_t now)
{
struct key_entry_key* k;
struct key_entry_data* d;
if(!key_entry_setup(region, name, namelen, dclass, &k, &d))
return NULL;
d->ttl = now + ttl;
d->isbad = 1;
d->reason = NULL;
d->rrset_type = LDNS_RR_TYPE_DNSKEY;
d->rrset_data = NULL;
d->algo = NULL;
return k;
}
struct ub_packed_rrset_key*
key_entry_get_rrset(struct key_entry_key* kkey, struct regional* region)
{
struct key_entry_data* d = (struct key_entry_data*)kkey->entry.data;
struct ub_packed_rrset_key* rrk;
struct packed_rrset_data* rrd;
if(!d || !d->rrset_data)
return NULL;
rrk = regional_alloc(region, sizeof(*rrk));
if(!rrk)
return NULL;
memset(rrk, 0, sizeof(*rrk));
rrk->rk.dname = regional_alloc_init(region, kkey->name, kkey->namelen);
if(!rrk->rk.dname)
return NULL;
rrk->rk.dname_len = kkey->namelen;
rrk->rk.type = htons(d->rrset_type);
rrk->rk.rrset_class = htons(kkey->key_class);
rrk->entry.key = rrk;
rrd = regional_alloc_init(region, d->rrset_data,
packed_rrset_sizeof(d->rrset_data));
if(!rrd)
return NULL;
rrk->entry.data = rrd;
packed_rrset_ptr_fixup(rrd);
return rrk;
}
/** Get size of key in keyset */
static size_t
dnskey_get_keysize(struct packed_rrset_data* data, size_t idx)
{
unsigned char* pk;
unsigned int pklen = 0;
int algo;
if(data->rr_len[idx] < 2+5)
return 0;
algo = (int)data->rr_data[idx][2+3];
pk = (unsigned char*)data->rr_data[idx]+2+4;
pklen = (unsigned)data->rr_len[idx]-2-4;
return sldns_rr_dnskey_key_size_raw(pk, pklen, algo);
}
/** get dnskey flags from data */
static uint16_t
kd_get_flags(struct packed_rrset_data* data, size_t idx)
{
uint16_t f;
if(data->rr_len[idx] < 2+2)
return 0;
memmove(&f, data->rr_data[idx]+2, 2);
f = ntohs(f);
return f;
}
size_t
key_entry_keysize(struct key_entry_key* kkey)
{
struct packed_rrset_data* d;
/* compute size of smallest ZSK key in the rrset */
size_t i;
size_t bits = 0;
if(!key_entry_isgood(kkey))
return 0;
d = ((struct key_entry_data*)kkey->entry.data)->rrset_data;
for(i=0; i<d->count; i++) {
if(!(kd_get_flags(d, i) & DNSKEY_BIT_ZSK))
continue;
if(i==0 || dnskey_get_keysize(d, i) < bits)
bits = dnskey_get_keysize(d, i);
}
return bits;
}

220
external/unbound/validator/val_kentry.h vendored Normal file
View File

@@ -0,0 +1,220 @@
/*
* validator/val_kentry.h - validator key entry definition.
*
* Copyright (c) 2007, NLnet Labs. All rights reserved.
*
* This software is open source.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the NLNET LABS nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* \file
*
* This file contains functions for dealing with validator key entries.
*/
#ifndef VALIDATOR_VAL_KENTRY_H
#define VALIDATOR_VAL_KENTRY_H
struct packed_rrset_data;
struct regional;
struct ub_packed_rrset_key;
#include "util/storage/lruhash.h"
/**
* A key entry for the validator.
* This may or may not be a trusted key.
* This is what is stored in the key cache.
* This is the key part for the cache; the key entry key.
*/
struct key_entry_key {
/** lru hash entry */
struct lruhash_entry entry;
/** name of the key */
uint8_t* name;
/** length of name */
size_t namelen;
/** class of the key, host byteorder */
uint16_t key_class;
};
/**
* Key entry for the validator.
* Contains key status.
* This is the data part for the cache, the key entry data.
*
* Can be in three basic states:
* isbad=0: good key
* isbad=1: bad key
* isbad=0 && rrset=0: insecure space.
*/
struct key_entry_data {
/** the TTL of this entry (absolute time) */
time_t ttl;
/** the key rrdata. can be NULL to signal keyless name. */
struct packed_rrset_data* rrset_data;
/** not NULL sometimes to give reason why bogus */
char* reason;
/** list of algorithms signalled, ends with 0, or NULL */
uint8_t* algo;
/** DNS RR type of the rrset data (host order) */
uint16_t rrset_type;
/** if the key is bad: Bogus or malformed */
uint8_t isbad;
};
/** function for lruhash operation */
size_t key_entry_sizefunc(void* key, void* data);
/** function for lruhash operation */
int key_entry_compfunc(void* k1, void* k2);
/** function for lruhash operation */
void key_entry_delkeyfunc(void* key, void* userarg);
/** function for lruhash operation */
void key_entry_deldatafunc(void* data, void* userarg);
/** calculate hash for key entry
* @param kk: key entry. The lruhash entry.hash value is filled in.
*/
void key_entry_hash(struct key_entry_key* kk);
/**
* Copy a key entry, to be region-allocated.
* @param kkey: the key entry key (and data pointer) to copy.
* @param region: where to allocate it
* @return newly region-allocated entry or NULL on a failure to allocate.
*/
struct key_entry_key* key_entry_copy_toregion(struct key_entry_key* kkey,
struct regional* region);
/**
* Copy a key entry, malloced.
* @param kkey: the key entry key (and data pointer) to copy.
* @return newly allocated entry or NULL on a failure to allocate memory.
*/
struct key_entry_key* key_entry_copy(struct key_entry_key* kkey);
/**
* See if this is a null entry. Does not do locking.
* @param kkey: must have data pointer set correctly
* @return true if it is a NULL rrset entry.
*/
int key_entry_isnull(struct key_entry_key* kkey);
/**
* See if this entry is good. Does not do locking.
* @param kkey: must have data pointer set correctly
* @return true if it is good.
*/
int key_entry_isgood(struct key_entry_key* kkey);
/**
* See if this entry is bad. Does not do locking.
* @param kkey: must have data pointer set correctly
* @return true if it is bad.
*/
int key_entry_isbad(struct key_entry_key* kkey);
/**
* Set reason why a key is bad.
* @param kkey: bad key.
* @param reason: string to attach, you must allocate it.
* Not safe to call twice unless you deallocate it yourself.
*/
void key_entry_set_reason(struct key_entry_key* kkey, char* reason);
/**
* Get reason why a key is bad.
* @param kkey: bad key
* @return pointer to string.
* String is part of key entry and is deleted with it.
*/
char* key_entry_get_reason(struct key_entry_key* kkey);
/**
* Create a null entry, in the given region.
* @param region: where to allocate
* @param name: the key name
* @param namelen: length of name
* @param dclass: class of key entry. (host order);
* @param ttl: what ttl should the key have. relative.
* @param now: current time (added to ttl).
* @return new key entry or NULL on alloc failure
*/
struct key_entry_key* key_entry_create_null(struct regional* region,
uint8_t* name, size_t namelen, uint16_t dclass, time_t ttl,
time_t now);
/**
* Create a key entry from an rrset, in the given region.
* @param region: where to allocate.
* @param name: the key name
* @param namelen: length of name
* @param dclass: class of key entry. (host order);
* @param rrset: data for key entry. This is copied to the region.
* @param sigalg: signalled algorithm list (or NULL).
* @param now: current time (added to ttl of rrset)
* @return new key entry or NULL on alloc failure
*/
struct key_entry_key* key_entry_create_rrset(struct regional* region,
uint8_t* name, size_t namelen, uint16_t dclass,
struct ub_packed_rrset_key* rrset, uint8_t* sigalg, time_t now);
/**
* Create a bad entry, in the given region.
* @param region: where to allocate
* @param name: the key name
* @param namelen: length of name
* @param dclass: class of key entry. (host order);
* @param ttl: what ttl should the key have. relative.
* @param now: current time (added to ttl).
* @return new key entry or NULL on alloc failure
*/
struct key_entry_key* key_entry_create_bad(struct regional* region,
uint8_t* name, size_t namelen, uint16_t dclass, time_t ttl,
time_t now);
/**
* Obtain rrset from a key entry, allocated in region.
* @param kkey: key entry to convert to a rrset.
* @param region: where to allocate rrset
* @return rrset copy; if no rrset or alloc error returns NULL.
*/
struct ub_packed_rrset_key* key_entry_get_rrset(struct key_entry_key* kkey,
struct regional* region);
/**
* Get keysize of the keyentry.
* @param kkey: key, must be a good key, with contents.
* @return size in bits of the key.
*/
size_t key_entry_keysize(struct key_entry_key* kkey);
#endif /* VALIDATOR_VAL_KENTRY_H */

1460
external/unbound/validator/val_neg.c vendored Normal file

File diff suppressed because it is too large Load Diff

315
external/unbound/validator/val_neg.h vendored Normal file
View File

@@ -0,0 +1,315 @@
/*
* validator/val_neg.h - validator aggressive negative caching functions.
*
* Copyright (c) 2008, NLnet Labs. All rights reserved.
*
* This software is open source.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the NLNET LABS nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* \file
*
* This file contains helper functions for the validator module.
* The functions help with aggressive negative caching.
* This creates new denials of existance, and proofs for absence of types
* from cached NSEC records.
*/
#ifndef VALIDATOR_VAL_NEG_H
#define VALIDATOR_VAL_NEG_H
#include "util/locks.h"
#include "util/rbtree.h"
struct sldns_buffer;
struct val_neg_data;
struct config_file;
struct reply_info;
struct rrset_cache;
struct regional;
struct query_info;
struct dns_msg;
struct ub_packed_rrset_key;
/**
* The negative cache. It is shared between the threads, so locked.
* Kept as validator-environ-state. It refers back to the rrset cache for
* data elements. It can be out of date and contain conflicting data
* from zone content changes.
* It contains a tree of zones, every zone has a tree of data elements.
* The data elements are part of one big LRU list, with one memory counter.
*/
struct val_neg_cache {
/** the big lock on the negative cache. Because we use a rbtree
* for the data (quick lookup), we need a big lock */
lock_basic_t lock;
/** The zone rbtree. contents sorted canonical, type val_neg_zone */
rbtree_t tree;
/** the first in linked list of LRU of val_neg_data */
struct val_neg_data* first;
/** last in lru (least recently used element) */
struct val_neg_data* last;
/** current memory in use (bytes) */
size_t use;
/** max memory to use (bytes) */
size_t max;
/** max nsec3 iterations allowed */
size_t nsec3_max_iter;
};
/**
* Per Zone aggressive negative caching data.
*/
struct val_neg_zone {
/** rbtree node element, key is this struct: the name, class */
rbnode_t node;
/** name; the key */
uint8_t* name;
/** length of name */
size_t len;
/** labels in name */
int labs;
/** pointer to parent zone in the negative cache */
struct val_neg_zone* parent;
/** the number of elements, including this one and the ones whose
* parents (-parents) include this one, that are in_use
* No elements have a count of zero, those are removed. */
int count;
/** if 0: NSEC zone, else NSEC3 hash algorithm in use */
int nsec3_hash;
/** nsec3 iteration count in use */
size_t nsec3_iter;
/** nsec3 salt in use */
uint8_t* nsec3_salt;
/** length of salt in bytes */
size_t nsec3_saltlen;
/** tree of NSEC data for this zone, sorted canonical
* by NSEC owner name */
rbtree_t tree;
/** class of node; host order */
uint16_t dclass;
/** if this element is in use, boolean */
uint8_t in_use;
};
/**
* Data element for aggressive negative caching.
* The tree of these elements acts as an index onto the rrset cache.
* It shows the NSEC records that (may) exist and are (possibly) secure.
* The rbtree allows for logN search for a covering NSEC record.
* To make tree insertion and deletion logN too, all the parent (one label
* less than the name) data elements are also in the rbtree, with a usage
* count for every data element.
* There is no actual data stored in this data element, if it is in_use,
* then the data can (possibly) be found in the rrset cache.
*/
struct val_neg_data {
/** rbtree node element, key is this struct: the name */
rbnode_t node;
/** name; the key */
uint8_t* name;
/** length of name */
size_t len;
/** labels in name */
int labs;
/** pointer to parent node in the negative cache */
struct val_neg_data* parent;
/** the number of elements, including this one and the ones whose
* parents (-parents) include this one, that are in use
* No elements have a count of zero, those are removed. */
int count;
/** the zone that this denial is part of */
struct val_neg_zone* zone;
/** previous in LRU */
struct val_neg_data* prev;
/** next in LRU (next element was less recently used) */
struct val_neg_data* next;
/** if this element is in use, boolean */
uint8_t in_use;
};
/**
* Create negative cache
* @param cfg: config options.
* @param maxiter: max nsec3 iterations allowed.
* @return neg cache, empty or NULL on failure.
*/
struct val_neg_cache* val_neg_create(struct config_file* cfg, size_t maxiter);
/**
* see how much memory is in use by the negative cache.
* @param neg: negative cache
* @return number of bytes in use.
*/
size_t val_neg_get_mem(struct val_neg_cache* neg);
/**
* Destroy negative cache. There must no longer be any other threads.
* @param neg: negative cache.
*/
void neg_cache_delete(struct val_neg_cache* neg);
/**
* Comparison function for rbtree val neg data elements
*/
int val_neg_data_compare(const void* a, const void* b);
/**
* Comparison function for rbtree val neg zone elements
*/
int val_neg_zone_compare(const void* a, const void* b);
/**
* Insert NSECs from this message into the negative cache for reference.
* @param neg: negative cache
* @param rep: reply with NSECs.
* Errors are ignored, means that storage is omitted.
*/
void val_neg_addreply(struct val_neg_cache* neg, struct reply_info* rep);
/**
* Insert NSECs from this referral into the negative cache for reference.
* @param neg: negative cache
* @param rep: referral reply with NS, NSECs.
* @param zone: bailiwick for the referral.
* Errors are ignored, means that storage is omitted.
*/
void val_neg_addreferral(struct val_neg_cache* neg, struct reply_info* rep,
uint8_t* zone);
/**
* Perform a DLV style lookup
* During the lookup, we could find out that data has expired. In that
* case the neg_cache entries are removed, and lookup fails.
*
* @param neg: negative cache.
* @param qname: name to look for
* @param len: length of qname.
* @param qclass: class to look in.
* @param rrset_cache: the rrset cache, for NSEC lookups.
* @param now: current time for ttl checks.
* @return
* 0 on error
* 0 if no proof of negative
* 1 if indeed negative was proven
* thus, qname DLV qclass does not exist.
*/
int val_neg_dlvlookup(struct val_neg_cache* neg, uint8_t* qname, size_t len,
uint16_t qclass, struct rrset_cache* rrset_cache, time_t now);
/**
* For the given query, try to get a reply out of the negative cache.
* The reply still needs to be validated.
* @param neg: negative cache.
* @param qinfo: query
* @param region: where to allocate reply.
* @param rrset_cache: rrset cache.
* @param buf: temporary buffer.
* @param now: to check TTLs against.
* @param addsoa: if true, produce result for external consumption.
* if false, do not add SOA - for unbound-internal consumption.
* @param topname: do not look higher than this name,
* so that the result cannot be taken from a zone above the current
* trust anchor. Which could happen with multiple islands of trust.
* if NULL, then no trust anchor is used, but also the algorithm becomes
* more conservative, especially for opt-out zones, since the receiver
* may have a trust-anchor below the optout and thus the optout cannot
* be used to create a proof from the negative cache.
* @return a reply message if something was found.
* This reply may still need validation.
* NULL if nothing found (or out of memory).
*/
struct dns_msg* val_neg_getmsg(struct val_neg_cache* neg,
struct query_info* qinfo, struct regional* region,
struct rrset_cache* rrset_cache, struct sldns_buffer* buf, time_t now,
int addsoa, uint8_t* topname);
/**** functions exposed for unit test ****/
/**
* Insert data into the data tree of a zone
* Does not do locking.
* @param neg: negative cache
* @param zone: zone to insert into
* @param nsec: record to insert.
*/
void neg_insert_data(struct val_neg_cache* neg,
struct val_neg_zone* zone, struct ub_packed_rrset_key* nsec);
/**
* Delete a data element from the negative cache.
* May delete other data elements to keep tree coherent, or
* only mark the element as 'not in use'.
* Does not do locking.
* @param neg: negative cache.
* @param el: data element to delete.
*/
void neg_delete_data(struct val_neg_cache* neg, struct val_neg_data* el);
/**
* Find the given zone, from the SOA owner name and class
* Does not do locking.
* @param neg: negative cache
* @param nm: what to look for.
* @param len: length of nm
* @param dclass: class to look for.
* @return zone or NULL if not found.
*/
struct val_neg_zone* neg_find_zone(struct val_neg_cache* neg,
uint8_t* nm, size_t len, uint16_t dclass);
/**
* Create a new zone.
* Does not do locking.
* @param neg: negative cache
* @param nm: what to look for.
* @param nm_len: length of name.
* @param dclass: class of zone, host order.
* @return zone or NULL if out of memory.
*/
struct val_neg_zone* neg_create_zone(struct val_neg_cache* neg,
uint8_t* nm, size_t nm_len, uint16_t dclass);
/**
* take a zone into use. increases counts of parents.
* Does not do locking.
* @param zone: zone to take into use.
*/
void val_neg_zone_take_inuse(struct val_neg_zone* zone);
#endif /* VALIDATOR_VAL_NEG_H */

602
external/unbound/validator/val_nsec.c vendored Normal file
View File

@@ -0,0 +1,602 @@
/*
* validator/val_nsec.c - validator NSEC denial of existance functions.
*
* Copyright (c) 2007, NLnet Labs. All rights reserved.
*
* This software is open source.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the NLNET LABS nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* \file
*
* This file contains helper functions for the validator module.
* The functions help with NSEC checking, the different NSEC proofs
* for denial of existance, and proofs for presence of types.
*/
#include "config.h"
#include "validator/val_nsec.h"
#include "validator/val_utils.h"
#include "util/data/msgreply.h"
#include "util/data/dname.h"
#include "util/net_help.h"
#include "util/module.h"
#include "services/cache/rrset.h"
/** get ttl of rrset */
static uint32_t
rrset_get_ttl(struct ub_packed_rrset_key* k)
{
struct packed_rrset_data* d = (struct packed_rrset_data*)k->entry.data;
return d->ttl;
}
int
nsecbitmap_has_type_rdata(uint8_t* bitmap, size_t len, uint16_t type)
{
/* Check type present in NSEC typemap with bitmap arg */
/* bitmasks for determining type-lowerbits presence */
uint8_t masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
uint8_t type_window = type>>8;
uint8_t type_low = type&0xff;
uint8_t win, winlen;
/* read each of the type bitmap windows and see if the searched
* type is amongst it */
while(len > 0) {
if(len < 3) /* bad window, at least window# winlen bitmap */
return 0;
win = *bitmap++;
winlen = *bitmap++;
len -= 2;
if(len < winlen || winlen < 1 || winlen > 32)
return 0; /* bad window length */
if(win == type_window) {
/* search window bitmap for the correct byte */
/* mybyte is 0 if we need the first byte */
size_t mybyte = type_low>>3;
if(winlen <= mybyte)
return 0; /* window too short */
return (int)(bitmap[mybyte] & masks[type_low&0x7]);
} else {
/* not the window we are looking for */
bitmap += winlen;
len -= winlen;
}
}
/* end of bitmap reached, no type found */
return 0;
}
int
nsec_has_type(struct ub_packed_rrset_key* nsec, uint16_t type)
{
struct packed_rrset_data* d = (struct packed_rrset_data*)nsec->
entry.data;
size_t len;
if(!d || d->count == 0 || d->rr_len[0] < 2+1)
return 0;
len = dname_valid(d->rr_data[0]+2, d->rr_len[0]-2);
if(!len)
return 0;
return nsecbitmap_has_type_rdata(d->rr_data[0]+2+len,
d->rr_len[0]-2-len, type);
}
/**
* Get next owner name from nsec record
* @param nsec: the nsec RRset.
* If there are multiple RRs, then this will only return one of them.
* @param nm: the next name is returned.
* @param ln: length of nm is returned.
* @return false on a bad NSEC RR (too short, malformed dname).
*/
static int
nsec_get_next(struct ub_packed_rrset_key* nsec, uint8_t** nm, size_t* ln)
{
struct packed_rrset_data* d = (struct packed_rrset_data*)nsec->
entry.data;
if(!d || d->count == 0 || d->rr_len[0] < 2+1) {
*nm = 0;
*ln = 0;
return 0;
}
*nm = d->rr_data[0]+2;
*ln = dname_valid(*nm, d->rr_len[0]-2);
if(!*ln) {
*nm = 0;
*ln = 0;
return 0;
}
return 1;
}
/**
* For an NSEC that matches the DS queried for, check absence of DS type.
*
* @param nsec: NSEC for proof, must be trusted.
* @param qinfo: what is queried for.
* @return if secure the nsec proves that no DS is present, or
* insecure if it proves it is not a delegation point.
* or bogus if something was wrong.
*/
static enum sec_status
val_nsec_proves_no_ds(struct ub_packed_rrset_key* nsec,
struct query_info* qinfo)
{
log_assert(qinfo->qtype == LDNS_RR_TYPE_DS);
log_assert(ntohs(nsec->rk.type) == LDNS_RR_TYPE_NSEC);
if(nsec_has_type(nsec, LDNS_RR_TYPE_SOA) && qinfo->qname_len != 1) {
/* SOA present means that this is the NSEC from the child,
* not the parent (so it is the wrong one). */
return sec_status_bogus;
}
if(nsec_has_type(nsec, LDNS_RR_TYPE_DS)) {
/* DS present means that there should have been a positive
* response to the DS query, so there is something wrong. */
return sec_status_bogus;
}
if(!nsec_has_type(nsec, LDNS_RR_TYPE_NS)) {
/* If there is no NS at this point at all, then this
* doesn't prove anything one way or the other. */
return sec_status_insecure;
}
/* Otherwise, this proves no DS. */
return sec_status_secure;
}
/** check security status from cache or verify rrset, returns true if secure */
static int
nsec_verify_rrset(struct module_env* env, struct val_env* ve,
struct ub_packed_rrset_key* nsec, struct key_entry_key* kkey,
char** reason)
{
struct packed_rrset_data* d = (struct packed_rrset_data*)
nsec->entry.data;
if(d->security == sec_status_secure)
return 1;
rrset_check_sec_status(env->rrset_cache, nsec, *env->now);
if(d->security == sec_status_secure)
return 1;
d->security = val_verify_rrset_entry(env, ve, nsec, kkey, reason);
if(d->security == sec_status_secure) {
rrset_update_sec_status(env->rrset_cache, nsec, *env->now);
return 1;
}
return 0;
}
enum sec_status
val_nsec_prove_nodata_dsreply(struct module_env* env, struct val_env* ve,
struct query_info* qinfo, struct reply_info* rep,
struct key_entry_key* kkey, time_t* proof_ttl, char** reason)
{
struct ub_packed_rrset_key* nsec = reply_find_rrset_section_ns(
rep, qinfo->qname, qinfo->qname_len, LDNS_RR_TYPE_NSEC,
qinfo->qclass);
enum sec_status sec;
size_t i;
uint8_t* wc = NULL, *ce = NULL;
int valid_nsec = 0;
struct ub_packed_rrset_key* wc_nsec = NULL;
/* If we have a NSEC at the same name, it must prove one
* of two things
* --
* 1) this is a delegation point and there is no DS
* 2) this is not a delegation point */
if(nsec) {
if(!nsec_verify_rrset(env, ve, nsec, kkey, reason)) {
verbose(VERB_ALGO, "NSEC RRset for the "
"referral did not verify.");
return sec_status_bogus;
}
sec = val_nsec_proves_no_ds(nsec, qinfo);
if(sec == sec_status_bogus) {
/* something was wrong. */
*reason = "NSEC does not prove absence of DS";
return sec;
} else if(sec == sec_status_insecure) {
/* this wasn't a delegation point. */
return sec;
} else if(sec == sec_status_secure) {
/* this proved no DS. */
*proof_ttl = ub_packed_rrset_ttl(nsec);
return sec;
}
/* if unchecked, fall through to next proof */
}
/* Otherwise, there is no NSEC at qname. This could be an ENT.
* (ENT=empty non terminal). If not, this is broken. */
/* verify NSEC rrsets in auth section */
for(i=rep->an_numrrsets; i < rep->an_numrrsets+rep->ns_numrrsets;
i++) {
if(rep->rrsets[i]->rk.type != htons(LDNS_RR_TYPE_NSEC))
continue;
if(!nsec_verify_rrset(env, ve, rep->rrsets[i], kkey, reason)) {
verbose(VERB_ALGO, "NSEC for empty non-terminal "
"did not verify.");
return sec_status_bogus;
}
if(nsec_proves_nodata(rep->rrsets[i], qinfo, &wc)) {
verbose(VERB_ALGO, "NSEC for empty non-terminal "
"proved no DS.");
*proof_ttl = rrset_get_ttl(rep->rrsets[i]);
if(wc && dname_is_wild(rep->rrsets[i]->rk.dname))
wc_nsec = rep->rrsets[i];
valid_nsec = 1;
}
if(val_nsec_proves_name_error(rep->rrsets[i], qinfo->qname)) {
ce = nsec_closest_encloser(qinfo->qname,
rep->rrsets[i]);
}
}
if(wc && !ce)
valid_nsec = 0;
else if(wc && ce) {
/* ce and wc must match */
if(query_dname_compare(wc, ce) != 0)
valid_nsec = 0;
else if(!wc_nsec)
valid_nsec = 0;
}
if(valid_nsec) {
if(wc) {
/* check if this is a delegation */
*reason = "NSEC for wildcard does not prove absence of DS";
return val_nsec_proves_no_ds(wc_nsec, qinfo);
}
/* valid nsec proves empty nonterminal */
return sec_status_insecure;
}
/* NSEC proof did not conlusively point to DS or no DS */
return sec_status_unchecked;
}
int nsec_proves_nodata(struct ub_packed_rrset_key* nsec,
struct query_info* qinfo, uint8_t** wc)
{
log_assert(wc);
if(query_dname_compare(nsec->rk.dname, qinfo->qname) != 0) {
uint8_t* nm;
size_t ln;
/* empty-non-terminal checking.
* Done before wildcard, because this is an exact match,
* and would prevent a wildcard from matching. */
/* If the nsec is proving that qname is an ENT, the nsec owner
* will be less than qname, and the next name will be a child
* domain of the qname. */
if(!nsec_get_next(nsec, &nm, &ln))
return 0; /* bad nsec */
if(dname_strict_subdomain_c(nm, qinfo->qname) &&
dname_canonical_compare(nsec->rk.dname,
qinfo->qname) < 0) {
return 1; /* proves ENT */
}
/* wildcard checking. */
/* If this is a wildcard NSEC, make sure that a) it was
* possible to have generated qname from the wildcard and
* b) the type map does not contain qtype. Note that this
* does NOT prove that this wildcard was the applicable
* wildcard. */
if(dname_is_wild(nsec->rk.dname)) {
/* the purported closest encloser. */
uint8_t* ce = nsec->rk.dname;
size_t ce_len = nsec->rk.dname_len;
dname_remove_label(&ce, &ce_len);
/* The qname must be a strict subdomain of the
* closest encloser, for the wildcard to apply
*/
if(dname_strict_subdomain_c(qinfo->qname, ce)) {
/* here we have a matching NSEC for the qname,
* perform matching NSEC checks */
if(nsec_has_type(nsec, LDNS_RR_TYPE_CNAME)) {
/* should have gotten the wildcard CNAME */
return 0;
}
if(nsec_has_type(nsec, LDNS_RR_TYPE_NS) &&
!nsec_has_type(nsec, LDNS_RR_TYPE_SOA)) {
/* wrong parentside (wildcard) NSEC used */
return 0;
}
if(nsec_has_type(nsec, qinfo->qtype)) {
return 0;
}
*wc = ce;
return 1;
}
}
/* Otherwise, this NSEC does not prove ENT and is not a
* wildcard, so it does not prove NODATA. */
return 0;
}
/* If the qtype exists, then we should have gotten it. */
if(nsec_has_type(nsec, qinfo->qtype)) {
return 0;
}
/* if the name is a CNAME node, then we should have gotten the CNAME*/
if(nsec_has_type(nsec, LDNS_RR_TYPE_CNAME)) {
return 0;
}
/* If an NS set exists at this name, and NOT a SOA (so this is a
* zone cut, not a zone apex), then we should have gotten a
* referral (or we just got the wrong NSEC).
* The reverse of this check is used when qtype is DS, since that
* must use the NSEC from above the zone cut. */
if(qinfo->qtype != LDNS_RR_TYPE_DS &&
nsec_has_type(nsec, LDNS_RR_TYPE_NS) &&
!nsec_has_type(nsec, LDNS_RR_TYPE_SOA)) {
return 0;
} else if(qinfo->qtype == LDNS_RR_TYPE_DS &&
nsec_has_type(nsec, LDNS_RR_TYPE_SOA) &&
!dname_is_root(qinfo->qname)) {
return 0;
}
return 1;
}
int
val_nsec_proves_name_error(struct ub_packed_rrset_key* nsec, uint8_t* qname)
{
uint8_t* owner = nsec->rk.dname;
uint8_t* next;
size_t nlen;
if(!nsec_get_next(nsec, &next, &nlen))
return 0;
/* If NSEC owner == qname, then this NSEC proves that qname exists. */
if(query_dname_compare(qname, owner) == 0) {
return 0;
}
/* If NSEC is a parent of qname, we need to check the type map
* If the parent name has a DNAME or is a delegation point, then
* this NSEC is being misused. */
if(dname_subdomain_c(qname, owner) &&
(nsec_has_type(nsec, LDNS_RR_TYPE_DNAME) ||
(nsec_has_type(nsec, LDNS_RR_TYPE_NS)
&& !nsec_has_type(nsec, LDNS_RR_TYPE_SOA))
)) {
return 0;
}
if(query_dname_compare(owner, next) == 0) {
/* this nsec is the only nsec */
/* zone.name NSEC zone.name, disproves everything else */
/* but only for subdomains of that zone */
if(dname_strict_subdomain_c(qname, next))
return 1;
}
else if(dname_canonical_compare(owner, next) > 0) {
/* this is the last nsec, ....(bigger) NSEC zonename(smaller) */
/* the names after the last (owner) name do not exist
* there are no names before the zone name in the zone
* but the qname must be a subdomain of the zone name(next). */
if(dname_canonical_compare(owner, qname) < 0 &&
dname_strict_subdomain_c(qname, next))
return 1;
} else {
/* regular NSEC, (smaller) NSEC (larger) */
if(dname_canonical_compare(owner, qname) < 0 &&
dname_canonical_compare(qname, next) < 0) {
return 1;
}
}
return 0;
}
int val_nsec_proves_insecuredelegation(struct ub_packed_rrset_key* nsec,
struct query_info* qinfo)
{
if(nsec_has_type(nsec, LDNS_RR_TYPE_NS) &&
!nsec_has_type(nsec, LDNS_RR_TYPE_DS) &&
!nsec_has_type(nsec, LDNS_RR_TYPE_SOA)) {
/* see if nsec signals an insecure delegation */
if(qinfo->qtype == LDNS_RR_TYPE_DS) {
/* if type is DS and qname is equal to nsec, then it
* is an exact match nsec, result not insecure */
if(dname_strict_subdomain_c(qinfo->qname,
nsec->rk.dname))
return 1;
} else {
if(dname_subdomain_c(qinfo->qname, nsec->rk.dname))
return 1;
}
}
return 0;
}
uint8_t*
nsec_closest_encloser(uint8_t* qname, struct ub_packed_rrset_key* nsec)
{
uint8_t* next;
size_t nlen;
uint8_t* common1, *common2;
if(!nsec_get_next(nsec, &next, &nlen))
return NULL;
/* longest common with owner or next name */
common1 = dname_get_shared_topdomain(nsec->rk.dname, qname);
common2 = dname_get_shared_topdomain(next, qname);
if(dname_count_labels(common1) > dname_count_labels(common2))
return common1;
return common2;
}
int val_nsec_proves_positive_wildcard(struct ub_packed_rrset_key* nsec,
struct query_info* qinf, uint8_t* wc)
{
uint8_t* ce;
/* 1) prove that qname doesn't exist and
* 2) that the correct wildcard was used
* nsec has been verified already. */
if(!val_nsec_proves_name_error(nsec, qinf->qname))
return 0;
/* check wildcard name */
ce = nsec_closest_encloser(qinf->qname, nsec);
if(!ce)
return 0;
if(query_dname_compare(wc, ce) != 0) {
return 0;
}
return 1;
}
int
val_nsec_proves_no_wc(struct ub_packed_rrset_key* nsec, uint8_t* qname,
size_t qnamelen)
{
/* Determine if a NSEC record proves the non-existence of a
* wildcard that could have produced qname. */
int labs;
int i;
uint8_t* ce = nsec_closest_encloser(qname, nsec);
uint8_t* strip;
size_t striplen;
uint8_t buf[LDNS_MAX_DOMAINLEN+3];
if(!ce)
return 0;
/* we can subtract the closest encloser count - since that is the
* largest shared topdomain with owner and next NSEC name,
* because the NSEC is no proof for names shorter than the owner
* and next names. */
labs = dname_count_labels(qname) - dname_count_labels(ce);
for(i=labs; i>0; i--) {
/* i is number of labels to strip off qname, prepend * wild */
strip = qname;
striplen = qnamelen;
dname_remove_labels(&strip, &striplen, i);
if(striplen > LDNS_MAX_DOMAINLEN-2)
continue; /* too long to prepend wildcard */
buf[0] = 1;
buf[1] = (uint8_t)'*';
memmove(buf+2, strip, striplen);
if(val_nsec_proves_name_error(nsec, buf)) {
return 1;
}
}
return 0;
}
/**
* Find shared topdomain that exists
*/
static void
dlv_topdomain(struct ub_packed_rrset_key* nsec, uint8_t* qname,
uint8_t** nm, size_t* nm_len)
{
/* make sure reply is part of nm */
/* take shared topdomain with left of NSEC. */
/* because, if empty nonterminal, then right is subdomain of qname.
* and any shared topdomain would be empty nonterminals.
*
* If nxdomain, then the right is bigger, and could have an
* interesting shared topdomain, but if it does have one, it is
* an empty nonterminal. An empty nonterminal shared with the left
* one. */
int n;
uint8_t* common = dname_get_shared_topdomain(qname, nsec->rk.dname);
n = dname_count_labels(*nm) - dname_count_labels(common);
dname_remove_labels(nm, nm_len, n);
}
int val_nsec_check_dlv(struct query_info* qinfo,
struct reply_info* rep, uint8_t** nm, size_t* nm_len)
{
uint8_t* next;
size_t i, nlen;
int c;
/* we should now have a NOERROR/NODATA or NXDOMAIN message */
if(rep->an_numrrsets != 0) {
return 0;
}
/* is this NOERROR ? */
if(FLAGS_GET_RCODE(rep->flags) == LDNS_RCODE_NOERROR) {
/* it can be a plain NSEC match - go up one more level. */
/* or its an empty nonterminal - go up to nonempty level */
for(i=0; i<rep->ns_numrrsets; i++) {
if(htons(rep->rrsets[i]->rk.type)!=LDNS_RR_TYPE_NSEC ||
!nsec_get_next(rep->rrsets[i], &next, &nlen))
continue;
c = dname_canonical_compare(
rep->rrsets[i]->rk.dname, qinfo->qname);
if(c == 0) {
/* plain match */
if(nsec_has_type(rep->rrsets[i],
LDNS_RR_TYPE_DLV))
return 0;
dname_remove_label(nm, nm_len);
return 1;
} else if(c < 0 &&
dname_strict_subdomain_c(next, qinfo->qname)) {
/* ENT */
dlv_topdomain(rep->rrsets[i], qinfo->qname,
nm, nm_len);
return 1;
}
}
return 0;
}
/* is this NXDOMAIN ? */
if(FLAGS_GET_RCODE(rep->flags) == LDNS_RCODE_NXDOMAIN) {
/* find the qname denial NSEC record. It can tell us
* a closest encloser name; or that we not need bother */
for(i=0; i<rep->ns_numrrsets; i++) {
if(htons(rep->rrsets[i]->rk.type) != LDNS_RR_TYPE_NSEC)
continue;
if(val_nsec_proves_name_error(rep->rrsets[i],
qinfo->qname)) {
log_nametypeclass(VERB_ALGO, "topdomain on",
rep->rrsets[i]->rk.dname,
ntohs(rep->rrsets[i]->rk.type), 0);
dlv_topdomain(rep->rrsets[i], qinfo->qname,
nm, nm_len);
return 1;
}
}
return 0;
}
return 0;
}

182
external/unbound/validator/val_nsec.h vendored Normal file
View File

@@ -0,0 +1,182 @@
/*
* validator/val_nsec.h - validator NSEC denial of existance functions.
*
* Copyright (c) 2007, NLnet Labs. All rights reserved.
*
* This software is open source.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the NLNET LABS nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* \file
*
* This file contains helper functions for the validator module.
* The functions help with NSEC checking, the different NSEC proofs
* for denial of existance, and proofs for presence of types.
*/
#ifndef VALIDATOR_VAL_NSEC_H
#define VALIDATOR_VAL_NSEC_H
#include "util/data/packed_rrset.h"
struct val_env;
struct module_env;
struct ub_packed_rrset_key;
struct reply_info;
struct query_info;
struct key_entry_key;
/**
* Check DS absence.
* There is a NODATA reply to a DS that needs checking.
* NSECs can prove this is not a delegation point, or sucessfully prove
* that there is no DS. Or this fails.
*
* @param env: module env for rrsig verification routines.
* @param ve: validator env for rrsig verification routines.
* @param qinfo: the DS queried for.
* @param rep: reply received.
* @param kkey: key entry to use for verification of signatures.
* @param proof_ttl: if secure, the TTL of how long this proof lasts.
* @param reason: string explaining why bogus.
* @return security status.
* SECURE: proved absence of DS.
* INSECURE: proved that this was not a delegation point.
* BOGUS: crypto bad, or no absence of DS proven.
* UNCHECKED: there was no way to prove anything (no NSECs, unknown algo).
*/
enum sec_status val_nsec_prove_nodata_dsreply(struct module_env* env,
struct val_env* ve, struct query_info* qinfo,
struct reply_info* rep, struct key_entry_key* kkey,
time_t* proof_ttl, char** reason);
/**
* nsec typemap check, takes an NSEC-type bitmap as argument, checks for type.
* @param bitmap: pointer to the bitmap part of wireformat rdata.
* @param len: length of the bitmap, in bytes.
* @param type: the type (in host order) to check for.
* @return true if the type bit was set in the bitmap. false if not, or
* if the bitmap was malformed in some way.
*/
int nsecbitmap_has_type_rdata(uint8_t* bitmap, size_t len, uint16_t type);
/**
* Check if type is present in the NSEC typemap
* @param nsec: the nsec RRset.
* If there are multiple RRs, then each must have the same typemap,
* since the typemap represents the types at this domain node.
* @param type: type to check for, host order.
* @return true if present
*/
int nsec_has_type(struct ub_packed_rrset_key* nsec, uint16_t type);
/**
* Determine if a NSEC proves the NOERROR/NODATA conditions. This will also
* handle the empty non-terminal (ENT) case and partially handle the
* wildcard case. If the ownername of 'nsec' is a wildcard, the validator
* must still be provided proof that qname did not directly exist and that
* the wildcard is, in fact, *.closest_encloser.
*
* @param nsec: the nsec record to check against.
* @param qinfo: the query info.
* @param wc: if the nodata is proven for a wildcard match, the wildcard
* closest encloser is returned, else NULL (wc is unchanged).
* This closest encloser must then match the nameerror given for the
* nextcloser of qname.
* @return true if NSEC proves this.
*/
int nsec_proves_nodata(struct ub_packed_rrset_key* nsec,
struct query_info* qinfo, uint8_t** wc);
/**
* Determine if the given NSEC proves a NameError (NXDOMAIN) for a given
* qname.
*
* @param nsec: the nsec to check
* @param qname: what was queried.
* @return true if proven.
*/
int val_nsec_proves_name_error(struct ub_packed_rrset_key* nsec,
uint8_t* qname);
/**
* Determine if the given NSEC proves a positive wildcard response.
* @param nsec: the nsec to check
* @param qinf: what was queried.
* @param wc: wildcard (without *. label)
* @return true if proven.
*/
int val_nsec_proves_positive_wildcard(struct ub_packed_rrset_key* nsec,
struct query_info* qinf, uint8_t* wc);
/**
* Determine closest encloser of a query name and the NSEC that covers it
* (and thus disproved it).
* A name error must have been proven already, otherwise this will be invalid.
* @param qname: the name queried for.
* @param nsec: the nsec RRset.
* @return closest encloser dname or NULL on error (bad nsec RRset).
*/
uint8_t* nsec_closest_encloser(uint8_t* qname,
struct ub_packed_rrset_key* nsec);
/**
* Determine if the given NSEC proves that a wildcard match does not exist.
*
* @param nsec: the nsec RRset.
* @param qname: the name queried for.
* @param qnamelen: length of qname.
* @return true if proven.
*/
int val_nsec_proves_no_wc(struct ub_packed_rrset_key* nsec, uint8_t* qname,
size_t qnamelen);
/**
* Determine the DLV result, what to do with NSEC DLV reply.
* @param qinfo: what was queried for.
* @param rep: the nonpositive reply.
* @param nm: dlv lookup name, to adjust for new lookup name (if needed).
* @param nm_len: length of lookup name.
* @return 0 on error, 1 if a higher point is found.
* If the higher point is above the dlv repo anchor, the qname does
* not exist.
*/
int val_nsec_check_dlv(struct query_info* qinfo,
struct reply_info* rep, uint8_t** nm, size_t* nm_len);
/**
* Determine if an nsec proves an insecure delegation towards the qname.
* @param nsec: nsec rrset.
* @param qinfo: what was queries for.
* @return 0 if not, 1 if an NSEC that signals an insecure delegation to
* the qname.
*/
int val_nsec_proves_insecuredelegation(struct ub_packed_rrset_key* nsec,
struct query_info* qinfo);
#endif /* VALIDATOR_VAL_NSEC_H */

1488
external/unbound/validator/val_nsec3.c vendored Normal file

File diff suppressed because it is too large Load Diff

380
external/unbound/validator/val_nsec3.h vendored Normal file
View File

@@ -0,0 +1,380 @@
/*
* validator/val_nsec3.h - validator NSEC3 denial of existance functions.
*
* Copyright (c) 2007, NLnet Labs. All rights reserved.
*
* This software is open source.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the NLNET LABS nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* \file
*
* This file contains helper functions for the validator module.
* The functions help with NSEC3 checking, the different NSEC3 proofs
* for denial of existance, and proofs for presence of types.
*
* NSEC3
* 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Hash Alg. | Flags | Iterations |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Salt Length | Salt /
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Hash Length | Next Hashed Owner Name /
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* / Type Bit Maps /
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
* NSEC3PARAM
* 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Hash Alg. | Flags | Iterations |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Salt Length | Salt /
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
*/
#ifndef VALIDATOR_VAL_NSEC3_H
#define VALIDATOR_VAL_NSEC3_H
#include "util/rbtree.h"
#include "util/data/packed_rrset.h"
struct val_env;
struct regional;
struct module_env;
struct ub_packed_rrset_key;
struct reply_info;
struct query_info;
struct key_entry_key;
struct sldns_buffer;
/**
* 0 1 2 3 4 5 6 7
* +-+-+-+-+-+-+-+-+
* | |O|
* +-+-+-+-+-+-+-+-+
* The OPT-OUT bit in the NSEC3 flags field.
* If enabled, there can be zero or more unsigned delegations in the span.
* If disabled, there are zero unsigned delegations in the span.
*/
#define NSEC3_OPTOUT 0x01
/**
* The unknown flags in the NSEC3 flags field.
* They must be zero, or the NSEC3 is ignored.
*/
#define NSEC3_UNKNOWN_FLAGS 0xFE
/** The SHA1 hash algorithm for NSEC3 */
#define NSEC3_HASH_SHA1 0x01
/**
* Determine if the set of NSEC3 records provided with a response prove NAME
* ERROR. This means that the NSEC3s prove a) the closest encloser exists,
* b) the direct child of the closest encloser towards qname doesn't exist,
* and c) *.closest encloser does not exist.
*
* @param env: module environment with temporary region and buffer.
* @param ve: validator environment, with iteration count settings.
* @param list: array of RRsets, some of which are NSEC3s.
* @param num: number of RRsets in the array to examine.
* @param qinfo: query that is verified for.
* @param kkey: key entry that signed the NSEC3s.
* @return:
* sec_status SECURE of the Name Error is proven by the NSEC3 RRs,
* BOGUS if not, INSECURE if all of the NSEC3s could be validly ignored.
*/
enum sec_status
nsec3_prove_nameerror(struct module_env* env, struct val_env* ve,
struct ub_packed_rrset_key** list, size_t num,
struct query_info* qinfo, struct key_entry_key* kkey);
/**
* Determine if the NSEC3s provided in a response prove the NOERROR/NODATA
* status. There are a number of different variants to this:
*
* 1) Normal NODATA -- qname is matched to an NSEC3 record, type is not
* present.
*
* 2) ENT NODATA -- because there must be NSEC3 record for
* empty-non-terminals, this is the same as #1.
*
* 3) NSEC3 ownername NODATA -- qname matched an existing, lone NSEC3
* ownername, but qtype was not NSEC3. NOTE: as of nsec-05, this case no
* longer exists.
*
* 4) Wildcard NODATA -- A wildcard matched the name, but not the type.
*
* 5) Opt-In DS NODATA -- the qname is covered by an opt-in span and qtype ==
* DS. (or maybe some future record with the same parent-side-only property)
*
* @param env: module environment with temporary region and buffer.
* @param ve: validator environment, with iteration count settings.
* @param list: array of RRsets, some of which are NSEC3s.
* @param num: number of RRsets in the array to examine.
* @param qinfo: query that is verified for.
* @param kkey: key entry that signed the NSEC3s.
* @return:
* sec_status SECURE of the proposition is proven by the NSEC3 RRs,
* BOGUS if not, INSECURE if all of the NSEC3s could be validly ignored.
*/
enum sec_status
nsec3_prove_nodata(struct module_env* env, struct val_env* ve,
struct ub_packed_rrset_key** list, size_t num,
struct query_info* qinfo, struct key_entry_key* kkey);
/**
* Prove that a positive wildcard match was appropriate (no direct match
* RRset).
*
* @param env: module environment with temporary region and buffer.
* @param ve: validator environment, with iteration count settings.
* @param list: array of RRsets, some of which are NSEC3s.
* @param num: number of RRsets in the array to examine.
* @param qinfo: query that is verified for.
* @param kkey: key entry that signed the NSEC3s.
* @param wc: The purported wildcard that matched. This is the wildcard name
* as *.wildcard.name., with the *. label already removed.
* @return:
* sec_status SECURE of the proposition is proven by the NSEC3 RRs,
* BOGUS if not, INSECURE if all of the NSEC3s could be validly ignored.
*/
enum sec_status
nsec3_prove_wildcard(struct module_env* env, struct val_env* ve,
struct ub_packed_rrset_key** list, size_t num,
struct query_info* qinfo, struct key_entry_key* kkey, uint8_t* wc);
/**
* Prove that a DS response either had no DS, or wasn't a delegation point.
*
* Fundamentally there are two cases here: normal NODATA and Opt-In NODATA.
*
* @param env: module environment with temporary region and buffer.
* @param ve: validator environment, with iteration count settings.
* @param list: array of RRsets, some of which are NSEC3s.
* @param num: number of RRsets in the array to examine.
* @param qinfo: query that is verified for.
* @param kkey: key entry that signed the NSEC3s.
* @param reason: string for bogus result.
* @return:
* sec_status SECURE of the proposition is proven by the NSEC3 RRs,
* BOGUS if not, INSECURE if all of the NSEC3s could be validly ignored.
* or if there was no DS in an insecure (i.e., opt-in) way,
* INDETERMINATE if it was clear that this wasn't a delegation point.
*/
enum sec_status
nsec3_prove_nods(struct module_env* env, struct val_env* ve,
struct ub_packed_rrset_key** list, size_t num,
struct query_info* qinfo, struct key_entry_key* kkey, char** reason);
/**
* Prove NXDOMAIN or NODATA.
*
* @param env: module environment with temporary region and buffer.
* @param ve: validator environment, with iteration count settings.
* @param list: array of RRsets, some of which are NSEC3s.
* @param num: number of RRsets in the array to examine.
* @param qinfo: query that is verified for.
* @param kkey: key entry that signed the NSEC3s.
* @param nodata: if return value is secure, this indicates if nodata or
* nxdomain was proven.
* @return:
* sec_status SECURE of the proposition is proven by the NSEC3 RRs,
* BOGUS if not, INSECURE if all of the NSEC3s could be validly ignored.
*/
enum sec_status
nsec3_prove_nxornodata(struct module_env* env, struct val_env* ve,
struct ub_packed_rrset_key** list, size_t num,
struct query_info* qinfo, struct key_entry_key* kkey, int* nodata);
/**
* The NSEC3 hash result storage.
* Consists of an rbtree, with these nodes in it.
* The nodes detail how a set of parameters (from nsec3 rr) plus
* a dname result in a hash.
*/
struct nsec3_cached_hash {
/** rbtree node, key is this structure */
rbnode_t node;
/** where are the parameters for conversion, in this rrset data */
struct ub_packed_rrset_key* nsec3;
/** where are the parameters for conversion, this RR number in data */
int rr;
/** the name to convert */
uint8_t* dname;
/** length of the dname */
size_t dname_len;
/** the hash result (not base32 encoded) */
uint8_t* hash;
/** length of hash in bytes */
size_t hash_len;
/** the hash result in base32 encoding */
uint8_t* b32;
/** length of base32 encoding (as a label) */
size_t b32_len;
};
/**
* Rbtree for hash cache comparison function.
* @param c1: key 1.
* @param c2: key 2.
* @return: comparison code, -1, 0, 1, of the keys.
*/
int nsec3_hash_cmp(const void* c1, const void* c2);
/**
* Obtain the hash of an owner name.
* Used internally by the nsec3 proof functions in this file.
* published to enable unit testing of hash algorithms and cache.
*
* @param table: the cache table. Must be inited at start.
* @param region: scratch region to use for allocation.
* This region holds the tree, if you wipe the region, reinit the tree.
* @param buf: temporary buffer.
* @param nsec3: the rrset with parameters
* @param rr: rr number from d that has the NSEC3 parameters to hash to.
* @param dname: name to hash
* This pointer is used inside the tree, assumed region-alloced.
* @param dname_len: the length of the name.
* @param hash: the hash node is returned on success.
* @return:
* 1 on success, either from cache or newly hashed hash is returned.
* 0 on a malloc failure.
* -1 if the NSEC3 rr was badly formatted (i.e. formerr).
*/
int nsec3_hash_name(rbtree_t* table, struct regional* region,
struct sldns_buffer* buf, struct ub_packed_rrset_key* nsec3, int rr,
uint8_t* dname, size_t dname_len, struct nsec3_cached_hash** hash);
/**
* Get next owner name, converted to base32 encoding and with the
* zone name (taken from the nsec3 owner name) appended.
* @param rrset: the NSEC3 rrset.
* @param r: the rr num of the nsec3 in the rrset.
* @param buf: buffer to store name in
* @param max: size of buffer.
* @return length of name on success. 0 on failure (buffer too short or
* bad format nsec3 record).
*/
size_t nsec3_get_nextowner_b32(struct ub_packed_rrset_key* rrset, int r,
uint8_t* buf, size_t max);
/**
* Convert hash into base32 encoding and with the
* zone name appended.
* @param hash: hashed buffer
* @param hashlen: length of hash
* @param zone: name of zone
* @param zonelen: length of zonename.
* @param buf: buffer to store name in
* @param max: size of buffer.
* @return length of name on success. 0 on failure (buffer too short or
* bad format nsec3 record).
*/
size_t nsec3_hash_to_b32(uint8_t* hash, size_t hashlen, uint8_t* zone,
size_t zonelen, uint8_t* buf, size_t max);
/**
* Get NSEC3 parameters out of rr.
* @param rrset: the NSEC3 rrset.
* @param r: the rr num of the nsec3 in the rrset.
* @param algo: nsec3 hash algo.
* @param iter: iteration count.
* @param salt: ptr to salt inside rdata.
* @param saltlen: length of salt.
* @return 0 if bad formatted, unknown nsec3 hash algo, or unknown flags set.
*/
int nsec3_get_params(struct ub_packed_rrset_key* rrset, int r,
int* algo, size_t* iter, uint8_t** salt, size_t* saltlen);
/**
* Get NSEC3 hashed in a buffer
* @param buf: buffer for temp use.
* @param nm: name to hash
* @param nmlen: length of nm.
* @param algo: algo to use, must be known.
* @param iter: iterations
* @param salt: salt for nsec3
* @param saltlen: length of salt.
* @param res: result of hash stored here.
* @param max: maximum space for result.
* @return 0 on failure, otherwise bytelength stored.
*/
size_t nsec3_get_hashed(struct sldns_buffer* buf, uint8_t* nm, size_t nmlen,
int algo, size_t iter, uint8_t* salt, size_t saltlen, uint8_t* res,
size_t max);
/**
* see if NSEC3 RR contains given type
* @param rrset: NSEC3 rrset
* @param r: RR in rrset
* @param type: in host order to check bit for.
* @return true if bit set, false if not or error.
*/
int nsec3_has_type(struct ub_packed_rrset_key* rrset, int r, uint16_t type);
/**
* return if nsec3 RR has the optout flag
* @param rrset: NSEC3 rrset
* @param r: RR in rrset
* @return true if optout, false on error or not optout
*/
int nsec3_has_optout(struct ub_packed_rrset_key* rrset, int r);
/**
* Return nsec3 RR next hashed owner name
* @param rrset: NSEC3 rrset
* @param r: RR in rrset
* @param next: ptr into rdata to next owner hash
* @param nextlen: length of hash.
* @return false on malformed
*/
int nsec3_get_nextowner(struct ub_packed_rrset_key* rrset, int r,
uint8_t** next, size_t* nextlen);
/**
* nsec3Covers
* Given a hash and a candidate NSEC3Record, determine if that NSEC3Record
* covers the hash. Covers specifically means that the hash is in between
* the owner and next hashes and does not equal either.
*
* @param zone: the zone name.
* @param hash: the hash of the name
* @param rrset: the rrset of the NSEC3.
* @param rr: which rr in the rrset.
* @param buf: temporary buffer.
* @return true if covers, false if not.
*/
int nsec3_covers(uint8_t* zone, struct nsec3_cached_hash* hash,
struct ub_packed_rrset_key* rrset, int rr, struct sldns_buffer* buf);
#endif /* VALIDATOR_VAL_NSEC3_H */

1072
external/unbound/validator/val_secalgo.c vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,84 @@
/*
* validator/val_secalgo.h - validator security algorithm functions.
*
* Copyright (c) 2012, NLnet Labs. All rights reserved.
*
* This software is open source.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the NLNET LABS nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* \file
*
* This file contains helper functions for the validator module.
* The functions take buffers with raw data and convert to library calls.
*/
#ifndef VALIDATOR_VAL_SECALGO_H
#define VALIDATOR_VAL_SECALGO_H
struct sldns_buffer;
/**
* Return size of DS digest according to its hash algorithm.
* @param algo: DS digest algo.
* @return size in bytes of digest, or 0 if not supported.
*/
size_t ds_digest_size_supported(int algo);
/**
* @param algo: the DS digest algo
* @param buf: the buffer to digest
* @param len: length of buffer to digest.
* @param res: result stored here (must have sufficient space).
* @return false on failure.
*/
int secalgo_ds_digest(int algo, unsigned char* buf, size_t len,
unsigned char* res);
/** return true if DNSKEY algorithm id is supported */
int dnskey_algo_id_is_supported(int id);
/**
* Check a canonical sig+rrset and signature against a dnskey
* @param buf: buffer with data to verify, the first rrsig part and the
* canonicalized rrset.
* @param algo: DNSKEY algorithm.
* @param sigblock: signature rdata field from RRSIG
* @param sigblock_len: length of sigblock data.
* @param key: public key data from DNSKEY RR.
* @param keylen: length of keydata.
* @param reason: bogus reason in more detail.
* @return secure if verification succeeded, bogus on crypto failure,
* unchecked on format errors and alloc failures.
*/
enum sec_status verify_canonrrset(struct sldns_buffer* buf, int algo,
unsigned char* sigblock, unsigned int sigblock_len,
unsigned char* key, unsigned int keylen, char** reason);
#endif /* VALIDATOR_VAL_SECALGO_H */

1437
external/unbound/validator/val_sigcrypt.c vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,323 @@
/*
* validator/val_sigcrypt.h - validator signature crypto functions.
*
* Copyright (c) 2007, NLnet Labs. All rights reserved.
*
* This software is open source.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the NLNET LABS nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* \file
*
* This file contains helper functions for the validator module.
* The functions help with signature verification and checking, the
* bridging between RR wireformat data and crypto calls.
*/
#ifndef VALIDATOR_VAL_SIGCRYPT_H
#define VALIDATOR_VAL_SIGCRYPT_H
#include "util/data/packed_rrset.h"
struct val_env;
struct module_env;
struct ub_packed_rrset_key;
struct rbtree_t;
struct regional;
struct sldns_buffer;
/** number of entries in algorithm needs array */
#define ALGO_NEEDS_MAX 256
/**
* Storage for algorithm needs. DNSKEY algorithms.
*/
struct algo_needs {
/** the algorithms (8-bit) with each a number.
* 0: not marked.
* 1: marked 'necessary but not yet fulfilled'
* 2: marked bogus.
* Indexed by algorithm number.
*/
uint8_t needs[ALGO_NEEDS_MAX];
/** the number of entries in the array that are unfulfilled */
size_t num;
};
/**
* Initialize algo needs structure, set algos from rrset as needed.
* Results are added to an existing need structure.
* @param n: struct with storage.
* @param dnskey: algos from this struct set as necessary. DNSKEY set.
* @param sigalg: adds to signalled algorithm list too.
*/
void algo_needs_init_dnskey_add(struct algo_needs* n,
struct ub_packed_rrset_key* dnskey, uint8_t* sigalg);
/**
* Initialize algo needs structure from a signalled algo list.
* @param n: struct with storage.
* @param sigalg: signalled algorithm list, numbers ends with 0.
*/
void algo_needs_init_list(struct algo_needs* n, uint8_t* sigalg);
/**
* Initialize algo needs structure, set algos from rrset as needed.
* @param n: struct with storage.
* @param ds: algos from this struct set as necessary. DS set.
* @param fav_ds_algo: filter to use only this DS algo.
* @param sigalg: list of signalled algos, constructed as output,
* provide size ALGO_NEEDS_MAX+1. list of algonumbers, ends with a zero.
*/
void algo_needs_init_ds(struct algo_needs* n, struct ub_packed_rrset_key* ds,
int fav_ds_algo, uint8_t* sigalg);
/**
* Mark this algorithm as a success, sec_secure, and see if we are done.
* @param n: storage structure processed.
* @param algo: the algorithm processed to be secure.
* @return if true, processing has finished successfully, we are satisfied.
*/
int algo_needs_set_secure(struct algo_needs* n, uint8_t algo);
/**
* Mark this algorithm a failure, sec_bogus. It can later be overridden
* by a success for this algorithm (with a different signature).
* @param n: storage structure processed.
* @param algo: the algorithm processed to be bogus.
*/
void algo_needs_set_bogus(struct algo_needs* n, uint8_t algo);
/**
* See how many algorithms are missing (not bogus or secure, but not processed)
* @param n: storage structure processed.
* @return number of algorithms missing after processing.
*/
size_t algo_needs_num_missing(struct algo_needs* n);
/**
* See which algo is missing.
* @param n: struct after processing.
* @return if 0 an algorithm was bogus, if a number, this algorithm was
* missing. So on 0, report why that was bogus, on number report a missing
* algorithm. There could be multiple missing, this reports the first one.
*/
int algo_needs_missing(struct algo_needs* n);
/**
* Format error reason for algorithm missing.
* @param env: module env with scratch for temp storage of string.
* @param alg: DNSKEY-algorithm missing.
* @param reason: destination.
* @param s: string, appended with 'with algorithm ..'.
*/
void algo_needs_reason(struct module_env* env, int alg, char** reason, char* s);
/**
* Check if dnskey matches a DS digest
* Does not check dnskey-keyid footprint, just the digest.
* @param env: module environment. Uses scratch space.
* @param dnskey_rrset: DNSKEY rrset.
* @param dnskey_idx: index of RR in rrset.
* @param ds_rrset: DS rrset
* @param ds_idx: index of RR in DS rrset.
* @return true if it matches, false on error, not supported or no match.
*/
int ds_digest_match_dnskey(struct module_env* env,
struct ub_packed_rrset_key* dnskey_rrset, size_t dnskey_idx,
struct ub_packed_rrset_key* ds_rrset, size_t ds_idx);
/**
* Get dnskey keytag, footprint value
* @param dnskey_rrset: DNSKEY rrset.
* @param dnskey_idx: index of RR in rrset.
* @return the keytag or 0 for badly formatted DNSKEYs.
*/
uint16_t dnskey_calc_keytag(struct ub_packed_rrset_key* dnskey_rrset,
size_t dnskey_idx);
/**
* Get DS keytag, footprint value that matches the DNSKEY keytag it signs.
* @param ds_rrset: DS rrset
* @param ds_idx: index of RR in DS rrset.
* @return the keytag or 0 for badly formatted DSs.
*/
uint16_t ds_get_keytag(struct ub_packed_rrset_key* ds_rrset, size_t ds_idx);
/**
* See if DNSKEY algorithm is supported
* @param dnskey_rrset: DNSKEY rrset.
* @param dnskey_idx: index of RR in rrset.
* @return true if supported.
*/
int dnskey_algo_is_supported(struct ub_packed_rrset_key* dnskey_rrset,
size_t dnskey_idx);
/**
* See if DS digest algorithm is supported
* @param ds_rrset: DS rrset
* @param ds_idx: index of RR in DS rrset.
* @return true if supported.
*/
int ds_digest_algo_is_supported(struct ub_packed_rrset_key* ds_rrset,
size_t ds_idx);
/**
* Get DS RR digest algorithm
* @param ds_rrset: DS rrset.
* @param ds_idx: which DS.
* @return algorithm or 0 if DS too short.
*/
int ds_get_digest_algo(struct ub_packed_rrset_key* ds_rrset, size_t ds_idx);
/**
* See if DS key algorithm is supported
* @param ds_rrset: DS rrset
* @param ds_idx: index of RR in DS rrset.
* @return true if supported.
*/
int ds_key_algo_is_supported(struct ub_packed_rrset_key* ds_rrset,
size_t ds_idx);
/**
* Get DS RR key algorithm. This value should match with the DNSKEY algo.
* @param k: DS rrset.
* @param idx: which DS.
* @return algorithm or 0 if DS too short.
*/
int ds_get_key_algo(struct ub_packed_rrset_key* k, size_t idx);
/**
* Get DNSKEY RR signature algorithm
* @param k: DNSKEY rrset.
* @param idx: which DNSKEY RR.
* @return algorithm or 0 if DNSKEY too short.
*/
int dnskey_get_algo(struct ub_packed_rrset_key* k, size_t idx);
/**
* Get DNSKEY RR flags
* @param k: DNSKEY rrset.
* @param idx: which DNSKEY RR.
* @return flags or 0 if DNSKEY too short.
*/
uint16_t dnskey_get_flags(struct ub_packed_rrset_key* k, size_t idx);
/**
* Verify rrset against dnskey rrset.
* @param env: module environment, scratch space is used.
* @param ve: validator environment, date settings.
* @param rrset: to be validated.
* @param dnskey: DNSKEY rrset, keyset to try.
* @param sigalg: if nonNULL provide downgrade protection otherwise one
* algorithm is enough.
* @param reason: if bogus, a string returned, fixed or alloced in scratch.
* @return SECURE if one key in the set verifies one rrsig.
* UNCHECKED on allocation errors, unsupported algorithms, malformed data,
* and BOGUS on verification failures (no keys match any signatures).
*/
enum sec_status dnskeyset_verify_rrset(struct module_env* env,
struct val_env* ve, struct ub_packed_rrset_key* rrset,
struct ub_packed_rrset_key* dnskey, uint8_t* sigalg, char** reason);
/**
* verify rrset against one specific dnskey (from rrset)
* @param env: module environment, scratch space is used.
* @param ve: validator environment, date settings.
* @param rrset: to be validated.
* @param dnskey: DNSKEY rrset, keyset.
* @param dnskey_idx: which key from the rrset to try.
* @param reason: if bogus, a string returned, fixed or alloced in scratch.
* @return secure if *this* key signs any of the signatures on rrset.
* unchecked on error or and bogus on bad signature.
*/
enum sec_status dnskey_verify_rrset(struct module_env* env,
struct val_env* ve, struct ub_packed_rrset_key* rrset,
struct ub_packed_rrset_key* dnskey, size_t dnskey_idx, char** reason);
/**
* verify rrset, with dnskey rrset, for a specific rrsig in rrset
* @param env: module environment, scratch space is used.
* @param ve: validator environment, date settings.
* @param now: current time for validation (can be overridden).
* @param rrset: to be validated.
* @param dnskey: DNSKEY rrset, keyset to try.
* @param sig_idx: which signature to try to validate.
* @param sortree: reused sorted order. Stored in region. Pass NULL at start,
* and for a new rrset.
* @param reason: if bogus, a string returned, fixed or alloced in scratch.
* @return secure if any key signs *this* signature. bogus if no key signs it,
* or unchecked on error.
*/
enum sec_status dnskeyset_verify_rrset_sig(struct module_env* env,
struct val_env* ve, time_t now, struct ub_packed_rrset_key* rrset,
struct ub_packed_rrset_key* dnskey, size_t sig_idx,
struct rbtree_t** sortree, char** reason);
/**
* verify rrset, with specific dnskey(from set), for a specific rrsig
* @param region: scratch region used for temporary allocation.
* @param buf: scratch buffer used for canonicalized rrset data.
* @param ve: validator environment, date settings.
* @param now: current time for validation (can be overridden).
* @param rrset: to be validated.
* @param dnskey: DNSKEY rrset, keyset.
* @param dnskey_idx: which key from the rrset to try.
* @param sig_idx: which signature to try to validate.
* @param sortree: pass NULL at start, the sorted rrset order is returned.
* pass it again for the same rrset.
* @param buf_canon: if true, the buffer is already canonical.
* pass false at start. pass old value only for same rrset and same
* signature (but perhaps different key) for reuse.
* @param reason: if bogus, a string returned, fixed or alloced in scratch.
* @return secure if this key signs this signature. unchecked on error or
* bogus if it did not validate.
*/
enum sec_status dnskey_verify_rrset_sig(struct regional* region,
struct sldns_buffer* buf, struct val_env* ve, time_t now,
struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey,
size_t dnskey_idx, size_t sig_idx,
struct rbtree_t** sortree, int* buf_canon, char** reason);
/**
* canonical compare for two tree entries
*/
int canonical_tree_compare(const void* k1, const void* k2);
/**
* Compare two rrsets and see if they are the same, canonicalised.
* The rrsets are not altered.
* @param region: temporary region.
* @param k1: rrset1
* @param k2: rrset2
* @return true if equal.
*/
int rrset_canonical_equal(struct regional* region,
struct ub_packed_rrset_key* k1, struct ub_packed_rrset_key* k2);
#endif /* VALIDATOR_VAL_SIGCRYPT_H */

1083
external/unbound/validator/val_utils.c vendored Normal file

File diff suppressed because it is too large Load Diff

403
external/unbound/validator/val_utils.h vendored Normal file
View File

@@ -0,0 +1,403 @@
/*
* validator/val_utils.h - validator utility functions.
*
* Copyright (c) 2007, NLnet Labs. All rights reserved.
*
* This software is open source.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the NLNET LABS nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* \file
*
* This file contains helper functions for the validator module.
*/
#ifndef VALIDATOR_VAL_UTILS_H
#define VALIDATOR_VAL_UTILS_H
#include "util/data/packed_rrset.h"
struct query_info;
struct reply_info;
struct val_env;
struct module_env;
struct ub_packed_rrset_key;
struct key_entry_key;
struct regional;
struct val_anchors;
struct rrset_cache;
struct sock_list;
/**
* Response classifications for the validator. The different types of proofs.
*/
enum val_classification {
/** Not subtyped yet. */
VAL_CLASS_UNTYPED = 0,
/** Not a recognized subtype. */
VAL_CLASS_UNKNOWN,
/** A positive, direct, response */
VAL_CLASS_POSITIVE,
/** A positive response, with a CNAME/DNAME chain. */
VAL_CLASS_CNAME,
/** A NOERROR/NODATA response. */
VAL_CLASS_NODATA,
/** A NXDOMAIN response. */
VAL_CLASS_NAMEERROR,
/** A CNAME/DNAME chain, and the offset is at the end of it,
* but there is no answer here, it can be NAMERROR or NODATA. */
VAL_CLASS_CNAMENOANSWER,
/** A referral, from cache with a nonRD query. */
VAL_CLASS_REFERRAL,
/** A response to a qtype=ANY query. */
VAL_CLASS_ANY
};
/**
* Given a response, classify ANSWER responses into a subtype.
* @param query_flags: query flags for the original query.
* @param origqinf: query info. The original query name.
* @param qinf: query info. The chased query name.
* @param rep: response. The original response.
* @param skip: offset into the original response answer section.
* @return A subtype, all values possible except UNTYPED .
* Once CNAME type is returned you can increase skip.
* Then, another CNAME type, CNAME_NOANSWER or POSITIVE are possible.
*/
enum val_classification val_classify_response(uint16_t query_flags,
struct query_info* origqinf, struct query_info* qinf,
struct reply_info* rep, size_t skip);
/**
* Given a response, determine the name of the "signer". This is primarily
* to determine if the response is, in fact, signed at all, and, if so, what
* is the name of the most pertinent keyset.
*
* @param subtype: the type from classify.
* @param qinf: query, the chased query name.
* @param rep: response to that, original response.
* @param cname_skip: how many answer rrsets have been skipped due to CNAME
* chains being chased around.
* @param signer_name: signer name, if the response is signed
* (even partially), or null if the response isn't signed.
* @param signer_len: length of signer_name of 0 if signer_name is NULL.
*/
void val_find_signer(enum val_classification subtype,
struct query_info* qinf, struct reply_info* rep,
size_t cname_skip, uint8_t** signer_name, size_t* signer_len);
/**
* Verify RRset with keys
* @param env: module environment (scratch buffer)
* @param ve: validator environment (verification settings)
* @param rrset: what to verify
* @param keys: dnskey rrset to verify with.
* @param sigalg: if nonNULL provide downgrade protection otherwise one
* algorithm is enough. Algo list is constructed in here.
* @param reason: reason of failure. Fixed string or alloced in scratch.
* @return security status of verification.
*/
enum sec_status val_verify_rrset(struct module_env* env, struct val_env* ve,
struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* keys,
uint8_t* sigalg, char** reason);
/**
* Verify RRset with keys from a keyset.
* @param env: module environment (scratch buffer)
* @param ve: validator environment (verification settings)
* @param rrset: what to verify
* @param kkey: key_entry to verify with.
* @param reason: reason of failure. Fixed string or alloced in scratch.
* @return security status of verification.
*/
enum sec_status val_verify_rrset_entry(struct module_env* env,
struct val_env* ve, struct ub_packed_rrset_key* rrset,
struct key_entry_key* kkey, char** reason);
/**
* Verify DNSKEYs with DS rrset. Like val_verify_new_DNSKEYs but
* returns a sec_status instead of a key_entry.
* @param env: module environment (scratch buffer)
* @param ve: validator environment (verification settings)
* @param dnskey_rrset: DNSKEY rrset to verify
* @param ds_rrset: DS rrset to verify with.
* @param sigalg: if nonNULL provide downgrade protection otherwise one
* algorithm is enough. The list of signalled algorithms is returned,
* must have enough space for ALGO_NEEDS_MAX+1.
* @param reason: reason of failure. Fixed string or alloced in scratch.
* @return: sec_status_secure if a DS matches.
* sec_status_insecure if end of trust (i.e., unknown algorithms).
* sec_status_bogus if it fails.
*/
enum sec_status val_verify_DNSKEY_with_DS(struct module_env* env,
struct val_env* ve, struct ub_packed_rrset_key* dnskey_rrset,
struct ub_packed_rrset_key* ds_rrset, uint8_t* sigalg, char** reason);
/**
* Verify DNSKEYs with DS and DNSKEY rrset. Like val_verify_DNSKEY_with_DS
* but for a trust anchor.
* @param env: module environment (scratch buffer)
* @param ve: validator environment (verification settings)
* @param dnskey_rrset: DNSKEY rrset to verify
* @param ta_ds: DS rrset to verify with.
* @param ta_dnskey: DNSKEY rrset to verify with.
* @param sigalg: if nonNULL provide downgrade protection otherwise one
* algorithm is enough. The list of signalled algorithms is returned,
* must have enough space for ALGO_NEEDS_MAX+1.
* @param reason: reason of failure. Fixed string or alloced in scratch.
* @return: sec_status_secure if a DS matches.
* sec_status_insecure if end of trust (i.e., unknown algorithms).
* sec_status_bogus if it fails.
*/
enum sec_status val_verify_DNSKEY_with_TA(struct module_env* env,
struct val_env* ve, struct ub_packed_rrset_key* dnskey_rrset,
struct ub_packed_rrset_key* ta_ds,
struct ub_packed_rrset_key* ta_dnskey, uint8_t* sigalg, char** reason);
/**
* Verify new DNSKEYs with DS rrset. The DS contains hash values that should
* match the DNSKEY keys.
* match the DS to a DNSKEY and verify the DNSKEY rrset with that key.
*
* @param region: where to allocate key entry result.
* @param env: module environment (scratch buffer)
* @param ve: validator environment (verification settings)
* @param dnskey_rrset: DNSKEY rrset to verify
* @param ds_rrset: DS rrset to verify with.
* @param downprot: if true provide downgrade protection otherwise one
* algorithm is enough.
* @param reason: reason of failure. Fixed string or alloced in scratch.
* @return a KeyEntry. This will either contain the now trusted
* dnskey_rrset, a "null" key entry indicating that this DS
* rrset/DNSKEY pair indicate an secure end to the island of trust
* (i.e., unknown algorithms), or a "bad" KeyEntry if the dnskey
* rrset fails to verify. Note that the "null" response should
* generally only occur in a private algorithm scenario: normally
* this sort of thing is checked before fetching the matching DNSKEY
* rrset.
* if downprot is set, a key entry with an algo list is made.
*/
struct key_entry_key* val_verify_new_DNSKEYs(struct regional* region,
struct module_env* env, struct val_env* ve,
struct ub_packed_rrset_key* dnskey_rrset,
struct ub_packed_rrset_key* ds_rrset, int downprot, char** reason);
/**
* Verify rrset with trust anchor: DS and DNSKEY rrset.
*
* @param region: where to allocate key entry result.
* @param env: module environment (scratch buffer)
* @param ve: validator environment (verification settings)
* @param dnskey_rrset: DNSKEY rrset to verify
* @param ta_ds_rrset: DS rrset to verify with.
* @param ta_dnskey_rrset: the DNSKEY rrset to verify with.
* @param downprot: if true provide downgrade protection otherwise one
* algorithm is enough.
* @param reason: reason of failure. Fixed string or alloced in scratch.
* @return a KeyEntry. This will either contain the now trusted
* dnskey_rrset, a "null" key entry indicating that this DS
* rrset/DNSKEY pair indicate an secure end to the island of trust
* (i.e., unknown algorithms), or a "bad" KeyEntry if the dnskey
* rrset fails to verify. Note that the "null" response should
* generally only occur in a private algorithm scenario: normally
* this sort of thing is checked before fetching the matching DNSKEY
* rrset.
* if downprot is set, a key entry with an algo list is made.
*/
struct key_entry_key* val_verify_new_DNSKEYs_with_ta(struct regional* region,
struct module_env* env, struct val_env* ve,
struct ub_packed_rrset_key* dnskey_rrset,
struct ub_packed_rrset_key* ta_ds_rrset,
struct ub_packed_rrset_key* ta_dnskey_rrset,
int downprot, char** reason);
/**
* Determine if DS rrset is usable for validator or not.
* Returns true if the algorithms for key and DShash are supported,
* for at least one RR.
*
* @param ds_rrset: the newly received DS rrset.
* @return true or false if not usable.
*/
int val_dsset_isusable(struct ub_packed_rrset_key* ds_rrset);
/**
* Determine by looking at a signed RRset whether or not the RRset name was
* the result of a wildcard expansion. If so, return the name of the
* generating wildcard.
*
* @param rrset The rrset to chedck.
* @param wc: the wildcard name, if the rrset was synthesized from a wildcard.
* unchanged if not. The wildcard name, without "*." in front, is
* returned. This is a pointer into the rrset owner name.
* @return false if the signatures are inconsistent in indicating the
* wildcard status; possible spoofing of wildcard response for other
* responses is being tried. We lost the status which rrsig was verified
* after the verification routine finished, so we simply check if
* the signatures are consistent; inserting a fake signature is a denial
* of service; but in that you could also have removed the real
* signature anyway.
*/
int val_rrset_wildcard(struct ub_packed_rrset_key* rrset, uint8_t** wc);
/**
* Chase the cname to the next query name.
* @param qchase: the current query name, updated to next target.
* @param rep: original message reply to look at CNAMEs.
* @param cname_skip: the skip into the answer section. Updated to skip
* DNAME and CNAME to the next part of the answer.
* @return false on error (bad rdata).
*/
int val_chase_cname(struct query_info* qchase, struct reply_info* rep,
size_t* cname_skip);
/**
* Fill up the chased reply with the content from the original reply;
* as pointers to those rrsets. Select the part after the cname_skip into
* the answer section, NS and AR sections that are signed with same signer.
*
* @param chase: chased reply, filled up.
* @param orig: original reply.
* @param cname_skip: which part of the answer section to skip.
* The skipped part contains CNAME(and DNAME)s that have been chased.
* @param name: the signer name to look for.
* @param len: length of name.
* @param signer: signer name or NULL if an unsigned RRset is considered.
* If NULL, rrsets with the lookup name are copied over.
*/
void val_fill_reply(struct reply_info* chase, struct reply_info* orig,
size_t cname_skip, uint8_t* name, size_t len, uint8_t* signer);
/**
* Remove all unsigned or non-secure status rrsets from NS and AR sections.
* So that unsigned data does not get let through to clients, when we have
* found the data to be secure.
*
* @param ve: validator environment with cleaning options.
* @param rep: reply to dump all nonsecure stuff out of.
*/
void val_check_nonsecure(struct val_env* ve, struct reply_info* rep);
/**
* Mark all unchecked rrset entries not below a trust anchor as indeterminate.
* Only security==unchecked rrsets are updated.
* @param rep: the reply with rrsets.
* @param anchors: the trust anchors.
* @param r: rrset cache to store updated security status into.
* @param env: module environment
*/
void val_mark_indeterminate(struct reply_info* rep,
struct val_anchors* anchors, struct rrset_cache* r,
struct module_env* env);
/**
* Mark all unchecked rrset entries below a NULL key entry as insecure.
* Only security==unchecked rrsets are updated.
* @param rep: the reply with rrsets.
* @param kname: end of secure space name.
* @param r: rrset cache to store updated security status into.
* @param env: module environment
*/
void val_mark_insecure(struct reply_info* rep, uint8_t* kname,
struct rrset_cache* r, struct module_env* env);
/**
* Find next unchecked rrset position, return it for skip.
* @param rep: the original reply to look into.
* @param skip: the skip now.
* @return new skip, which may be at the rep->rrset_count position to signal
* there are no unchecked items.
*/
size_t val_next_unchecked(struct reply_info* rep, size_t skip);
/**
* Find the signer name for an RRset.
* @param rrset: the rrset.
* @param sname: signer name is returned or NULL if not signed.
* @param slen: length of sname (or 0).
*/
void val_find_rrset_signer(struct ub_packed_rrset_key* rrset, uint8_t** sname,
size_t* slen);
/**
* Get string to denote the classification result.
* @param subtype: from classification function.
* @return static string to describe the classification.
*/
const char* val_classification_to_string(enum val_classification subtype);
/**
* Add existing list to blacklist.
* @param blacklist: the blacklist with result
* @param region: the region where blacklist is allocated.
* Allocation failures are logged.
* @param origin: origin list to add, if NULL, a cache-entry is added to
* the blacklist to stop cache from being used.
* @param cross: if true this is a cross-qstate copy, and the 'origin'
* list is not allocated in the same region as the blacklist.
*/
void val_blacklist(struct sock_list** blacklist, struct regional* region,
struct sock_list* origin, int cross);
/**
* check if has dnssec info, and if it has signed nsecs. gives error reason.
* @param rep: reply to check.
* @param reason: returned on fail.
* @return false if message has no signed nsecs. Can not prove negatives.
*/
int val_has_signed_nsecs(struct reply_info* rep, char** reason);
/**
* Return algo number for favorite (best) algorithm that we support in DS.
* @param ds_rrset: the DSes in this rrset are inspected and best algo chosen.
* @return algo number or 0 if none supported. 0 is unused as algo number.
*/
int val_favorite_ds_algo(struct ub_packed_rrset_key* ds_rrset);
/**
* Find DS denial message in cache. Saves new qstate allocation and allows
* the validator to use partial content which is not enough to construct a
* message for network (or user) consumption. Without SOA for example,
* which is a common occurence in the unbound code since the referrals contain
* NSEC/NSEC3 rrs without the SOA element, thus do not allow synthesis of a
* full negative reply, but do allow synthesis of sufficient proof.
* @param env: query env with caches and time.
* @param nm: name of DS record sought.
* @param nmlen: length of name.
* @param c: class of DS RR.
* @param region: where to allocate result.
* @param topname: name of the key that is currently in use, that will get
* used to validate the result, and thus no higher entries from the
* negative cache need to be examined.
* @return a dns_msg on success. NULL on failure.
*/
struct dns_msg* val_find_DS(struct module_env* env, uint8_t* nm, size_t nmlen,
uint16_t c, struct regional* region, uint8_t* topname);
#endif /* VALIDATOR_VAL_UTILS_H */

2985
external/unbound/validator/validator.c vendored Normal file

File diff suppressed because it is too large Load Diff

294
external/unbound/validator/validator.h vendored Normal file
View File

@@ -0,0 +1,294 @@
/*
* validator/validator.h - secure validator DNS query response module
*
* Copyright (c) 2007, NLnet Labs. All rights reserved.
*
* This software is open source.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the NLNET LABS nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* \file
*
* This file contains a module that performs validation of DNS queries.
* According to RFC 4034.
*/
#ifndef VALIDATOR_VALIDATOR_H
#define VALIDATOR_VALIDATOR_H
#include "util/module.h"
#include "util/data/msgreply.h"
#include "validator/val_utils.h"
struct val_anchors;
struct key_cache;
struct key_entry_key;
struct val_neg_cache;
struct config_strlist;
/**
* This is the TTL to use when a trust anchor fails to prime. A trust anchor
* will be primed no more often than this interval. Used when harden-
* dnssec-stripped is off and the trust anchor fails.
*/
#define NULL_KEY_TTL 60 /* seconds */
/**
* TTL for bogus key entries. When a DS or DNSKEY fails in the chain of
* trust the entire zone for that name is blacked out for this TTL.
*/
#define BOGUS_KEY_TTL 60 /* seconds */
/** max number of query restarts, number of IPs to probe */
#define VAL_MAX_RESTART_COUNT 5
/**
* Global state for the validator.
*/
struct val_env {
/** key cache; these are validated keys. trusted keys only
* end up here after being primed. */
struct key_cache* kcache;
/** aggressive negative cache. index into NSECs in rrset cache. */
struct val_neg_cache* neg_cache;
/** for debug testing a fixed validation date can be entered.
* if 0, current time is used for rrsig validation */
int32_t date_override;
/** clock skew min for signatures */
int32_t skew_min;
/** clock skew max for signatures */
int32_t skew_max;
/** TTL for bogus data; used instead of untrusted TTL from data.
* Bogus data will not be verified more often than this interval.
* seconds. */
uint32_t bogus_ttl;
/** If set, the validator should clean the additional section of
* secure messages.
*/
int clean_additional;
/**
* If set, the validator will not make messages bogus, instead
* indeterminate is issued, so that no clients receive SERVFAIL.
* This allows an operator to run validation 'shadow' without
* hurting responses to clients.
*/
int permissive_mode;
/**
* Number of entries in the NSEC3 maximum iteration count table.
* Keep this table short, and sorted by size
*/
int nsec3_keyiter_count;
/**
* NSEC3 maximum iteration count per signing key size.
* This array contains key size values (in increasing order)
*/
size_t* nsec3_keysize;
/**
* NSEC3 maximum iteration count per signing key size.
* This array contains the maximum iteration count for the keysize
* in the keysize array.
*/
size_t* nsec3_maxiter;
/** lock on bogus counter */
lock_basic_t bogus_lock;
/** number of times rrsets marked bogus */
size_t num_rrset_bogus;
};
/**
* State of the validator for a query.
*/
enum val_state {
/** initial state for validation */
VAL_INIT_STATE = 0,
/** find the proper keys for validation, follow trust chain */
VAL_FINDKEY_STATE,
/** validate the answer, using found key entry */
VAL_VALIDATE_STATE,
/** finish up */
VAL_FINISHED_STATE,
/** DLV lookup state, processing DLV queries */
VAL_DLVLOOKUP_STATE
};
/**
* Per query state for the validator module.
*/
struct val_qstate {
/**
* State of the validator module.
*/
enum val_state state;
/**
* The original message we have been given to validate.
*/
struct dns_msg* orig_msg;
/**
* The query restart count
*/
int restart_count;
/** The blacklist saved for chainoftrust elements */
struct sock_list* chain_blacklist;
/**
* The query name we have chased to; qname after following CNAMEs
*/
struct query_info qchase;
/**
* The chased reply, extract from original message. Can be:
* o CNAME
* o DNAME + CNAME
* o answer
* plus authority, additional (nsecs) that have same signature.
*/
struct reply_info* chase_reply;
/**
* The cname skip value; the number of rrsets that have been skipped
* due to chasing cnames. This is the offset into the
* orig_msg->rep->rrsets array, into the answer section.
* starts at 0 - for the full original message.
* if it is >0 - qchase followed the cname, chase_reply setup to be
* that message and relevant authority rrsets.
*
* The skip is also used for referral messages, where it will
* range from 0, over the answer, authority and additional sections.
*/
size_t rrset_skip;
/** trust anchor name */
uint8_t* trust_anchor_name;
/** trust anchor labels */
int trust_anchor_labs;
/** trust anchor length */
size_t trust_anchor_len;
/** the DS rrset */
struct ub_packed_rrset_key* ds_rrset;
/** domain name for empty nonterminal detection */
uint8_t* empty_DS_name;
/** length of empty_DS_name */
size_t empty_DS_len;
/** the current key entry */
struct key_entry_key* key_entry;
/** subtype */
enum val_classification subtype;
/** signer name */
uint8_t* signer_name;
/** length of signer_name */
size_t signer_len;
/** true if this state is waiting to prime a trust anchor */
int wait_prime_ta;
/** have we already checked the DLV? */
int dlv_checked;
/** The name for which the DLV is looked up. For the current message
* or for the current RRset (for CNAME, REFERRAL types).
* If there is signer name, that may be it, else a domain name */
uint8_t* dlv_lookup_name;
/** length of dlv lookup name */
size_t dlv_lookup_name_len;
/** Name at which chain of trust stopped with insecure, starting DLV
* DLV must result in chain going further down */
uint8_t* dlv_insecure_at;
/** length of dlv insecure point name */
size_t dlv_insecure_at_len;
/** status of DLV lookup. Indication to VAL_DLV_STATE what to do */
enum dlv_status {
dlv_error, /* server failure */
dlv_success, /* got a DLV */
dlv_ask_higher, /* ask again */
dlv_there_is_no_dlv /* got no DLV, sure of it */
} dlv_status;
};
/**
* Get the validator function block.
* @return: function block with function pointers to validator methods.
*/
struct module_func_block* val_get_funcblock(void);
/**
* Get validator state as a string
* @param state: to convert
* @return constant string that is printable.
*/
const char* val_state_to_string(enum val_state state);
/** validator init */
int val_init(struct module_env* env, int id);
/** validator deinit */
void val_deinit(struct module_env* env, int id);
/** validator operate on a query */
void val_operate(struct module_qstate* qstate, enum module_ev event, int id,
struct outbound_entry* outbound);
/**
* inform validator super.
*
* @param qstate: query state that finished.
* @param id: module id.
* @param super: the qstate to inform.
*/
void val_inform_super(struct module_qstate* qstate, int id,
struct module_qstate* super);
/** validator cleanup query state */
void val_clear(struct module_qstate* qstate, int id);
/**
* Debug helper routine that assists worker in determining memory in
* use.
* @param env: module environment
* @param id: module id.
* @return memory in use in bytes.
*/
size_t val_get_mem(struct module_env* env, int id);
#endif /* VALIDATOR_VALIDATOR_H */