13b6c3722Schristos /*
23b6c3722Schristos * validator/autotrust.c - RFC5011 trust anchor management for unbound.
33b6c3722Schristos *
43b6c3722Schristos * Copyright (c) 2009, NLnet Labs. All rights reserved.
53b6c3722Schristos *
63b6c3722Schristos * This software is open source.
73b6c3722Schristos *
83b6c3722Schristos * Redistribution and use in source and binary forms, with or without
93b6c3722Schristos * modification, are permitted provided that the following conditions
103b6c3722Schristos * are met:
113b6c3722Schristos *
123b6c3722Schristos * Redistributions of source code must retain the above copyright notice,
133b6c3722Schristos * this list of conditions and the following disclaimer.
143b6c3722Schristos *
153b6c3722Schristos * Redistributions in binary form must reproduce the above copyright notice,
163b6c3722Schristos * this list of conditions and the following disclaimer in the documentation
173b6c3722Schristos * and/or other materials provided with the distribution.
183b6c3722Schristos *
193b6c3722Schristos * Neither the name of the NLNET LABS nor the names of its contributors may
203b6c3722Schristos * be used to endorse or promote products derived from this software without
213b6c3722Schristos * specific prior written permission.
223b6c3722Schristos *
233b6c3722Schristos * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
243b6c3722Schristos * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
253b6c3722Schristos * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
263b6c3722Schristos * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
273b6c3722Schristos * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
283b6c3722Schristos * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
293b6c3722Schristos * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
303b6c3722Schristos * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
313b6c3722Schristos * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
323b6c3722Schristos * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
333b6c3722Schristos * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
343b6c3722Schristos */
353b6c3722Schristos
363b6c3722Schristos /**
373b6c3722Schristos * \file
383b6c3722Schristos *
393b6c3722Schristos * Contains autotrust implementation. The implementation was taken from
403b6c3722Schristos * the autotrust daemon (BSD licensed), written by Matthijs Mekking.
413b6c3722Schristos * It was modified to fit into unbound. The state table process is the same.
423b6c3722Schristos */
433b6c3722Schristos #include "config.h"
443b6c3722Schristos #include "validator/autotrust.h"
453b6c3722Schristos #include "validator/val_anchor.h"
463b6c3722Schristos #include "validator/val_utils.h"
473b6c3722Schristos #include "validator/val_sigcrypt.h"
483b6c3722Schristos #include "util/data/dname.h"
493b6c3722Schristos #include "util/data/packed_rrset.h"
503b6c3722Schristos #include "util/log.h"
513b6c3722Schristos #include "util/module.h"
523b6c3722Schristos #include "util/net_help.h"
533b6c3722Schristos #include "util/config_file.h"
543b6c3722Schristos #include "util/regional.h"
553b6c3722Schristos #include "util/random.h"
563b6c3722Schristos #include "util/data/msgparse.h"
573b6c3722Schristos #include "services/mesh.h"
583b6c3722Schristos #include "services/cache/rrset.h"
593b6c3722Schristos #include "validator/val_kcache.h"
603b6c3722Schristos #include "sldns/sbuffer.h"
613b6c3722Schristos #include "sldns/wire2str.h"
623b6c3722Schristos #include "sldns/str2wire.h"
633b6c3722Schristos #include "sldns/keyraw.h"
643b6c3722Schristos #include "sldns/rrdef.h"
653b6c3722Schristos #include <stdarg.h>
663b6c3722Schristos #include <ctype.h>
673b6c3722Schristos
683b6c3722Schristos /** number of times a key must be seen before it can become valid */
693b6c3722Schristos #define MIN_PENDINGCOUNT 2
703b6c3722Schristos
713b6c3722Schristos /** Event: Revoked */
723b6c3722Schristos static void do_revoked(struct module_env* env, struct autr_ta* anchor, int* c);
733b6c3722Schristos
autr_global_create(void)743b6c3722Schristos struct autr_global_data* autr_global_create(void)
753b6c3722Schristos {
763b6c3722Schristos struct autr_global_data* global;
773b6c3722Schristos global = (struct autr_global_data*)malloc(sizeof(*global));
783b6c3722Schristos if(!global)
793b6c3722Schristos return NULL;
803b6c3722Schristos rbtree_init(&global->probe, &probetree_cmp);
813b6c3722Schristos return global;
823b6c3722Schristos }
833b6c3722Schristos
autr_global_delete(struct autr_global_data * global)843b6c3722Schristos void autr_global_delete(struct autr_global_data* global)
853b6c3722Schristos {
863b6c3722Schristos if(!global)
873b6c3722Schristos return;
883b6c3722Schristos /* elements deleted by parent */
893b6c3722Schristos free(global);
903b6c3722Schristos }
913b6c3722Schristos
probetree_cmp(const void * x,const void * y)923b6c3722Schristos int probetree_cmp(const void* x, const void* y)
933b6c3722Schristos {
943b6c3722Schristos struct trust_anchor* a = (struct trust_anchor*)x;
953b6c3722Schristos struct trust_anchor* b = (struct trust_anchor*)y;
963b6c3722Schristos log_assert(a->autr && b->autr);
973b6c3722Schristos if(a->autr->next_probe_time < b->autr->next_probe_time)
983b6c3722Schristos return -1;
993b6c3722Schristos if(a->autr->next_probe_time > b->autr->next_probe_time)
1003b6c3722Schristos return 1;
1013b6c3722Schristos /* time is equal, sort on trust point identity */
1023b6c3722Schristos return anchor_cmp(x, y);
1033b6c3722Schristos }
1043b6c3722Schristos
1053b6c3722Schristos size_t
autr_get_num_anchors(struct val_anchors * anchors)1063b6c3722Schristos autr_get_num_anchors(struct val_anchors* anchors)
1073b6c3722Schristos {
1083b6c3722Schristos size_t res = 0;
1093b6c3722Schristos if(!anchors)
1103b6c3722Schristos return 0;
1113b6c3722Schristos lock_basic_lock(&anchors->lock);
1123b6c3722Schristos if(anchors->autr)
1133b6c3722Schristos res = anchors->autr->probe.count;
1143b6c3722Schristos lock_basic_unlock(&anchors->lock);
1153b6c3722Schristos return res;
1163b6c3722Schristos }
1173b6c3722Schristos
1183b6c3722Schristos /** Position in string */
1193b6c3722Schristos static int
position_in_string(char * str,const char * sub)1203b6c3722Schristos position_in_string(char *str, const char* sub)
1213b6c3722Schristos {
1223b6c3722Schristos char* pos = strstr(str, sub);
1233b6c3722Schristos if(pos)
1243b6c3722Schristos return (int)(pos-str)+(int)strlen(sub);
1253b6c3722Schristos return -1;
1263b6c3722Schristos }
1273b6c3722Schristos
1283b6c3722Schristos /** Debug routine to print pretty key information */
1293b6c3722Schristos static void
1303b6c3722Schristos verbose_key(struct autr_ta* ta, enum verbosity_value level,
1313b6c3722Schristos const char* format, ...) ATTR_FORMAT(printf, 3, 4);
1323b6c3722Schristos
1333b6c3722Schristos /**
1343b6c3722Schristos * Implementation of debug pretty key print
1353b6c3722Schristos * @param ta: trust anchor key with DNSKEY data.
1363b6c3722Schristos * @param level: verbosity level to print at.
1373b6c3722Schristos * @param format: printf style format string.
1383b6c3722Schristos */
1393b6c3722Schristos static void
verbose_key(struct autr_ta * ta,enum verbosity_value level,const char * format,...)1403b6c3722Schristos verbose_key(struct autr_ta* ta, enum verbosity_value level,
1413b6c3722Schristos const char* format, ...)
1423b6c3722Schristos {
1433b6c3722Schristos va_list args;
1443b6c3722Schristos va_start(args, format);
1453b6c3722Schristos if(verbosity >= level) {
1463b6c3722Schristos char* str = sldns_wire2str_dname(ta->rr, ta->dname_len);
1473b6c3722Schristos int keytag = (int)sldns_calc_keytag_raw(sldns_wirerr_get_rdata(
1483b6c3722Schristos ta->rr, ta->rr_len, ta->dname_len),
1493b6c3722Schristos sldns_wirerr_get_rdatalen(ta->rr, ta->rr_len,
1503b6c3722Schristos ta->dname_len));
1513b6c3722Schristos char msg[MAXSYSLOGMSGLEN];
1523b6c3722Schristos vsnprintf(msg, sizeof(msg), format, args);
1533b6c3722Schristos verbose(level, "%s key %d %s", str?str:"??", keytag, msg);
1543b6c3722Schristos free(str);
1553b6c3722Schristos }
1563b6c3722Schristos va_end(args);
1573b6c3722Schristos }
1583b6c3722Schristos
1593b6c3722Schristos /**
1603b6c3722Schristos * Parse comments
1613b6c3722Schristos * @param str: to parse
1623b6c3722Schristos * @param ta: trust key autotrust metadata
1633b6c3722Schristos * @return false on failure.
1643b6c3722Schristos */
1653b6c3722Schristos static int
parse_comments(char * str,struct autr_ta * ta)1663b6c3722Schristos parse_comments(char* str, struct autr_ta* ta)
1673b6c3722Schristos {
1683b6c3722Schristos int len = (int)strlen(str), pos = 0, timestamp = 0;
1693b6c3722Schristos char* comment = (char*) malloc(sizeof(char)*len+1);
1703b6c3722Schristos char* comments = comment;
1713b6c3722Schristos if(!comment) {
1723b6c3722Schristos log_err("malloc failure in parse");
1733b6c3722Schristos return 0;
1743b6c3722Schristos }
1753b6c3722Schristos /* skip over whitespace and data at start of line */
1763b6c3722Schristos while (*str != '\0' && *str != ';')
1773b6c3722Schristos str++;
1783b6c3722Schristos if (*str == ';')
1793b6c3722Schristos str++;
1803b6c3722Schristos /* copy comments */
1813b6c3722Schristos while (*str != '\0')
1823b6c3722Schristos {
1833b6c3722Schristos *comments = *str;
1843b6c3722Schristos comments++;
1853b6c3722Schristos str++;
1863b6c3722Schristos }
1873b6c3722Schristos *comments = '\0';
1883b6c3722Schristos
1893b6c3722Schristos comments = comment;
1903b6c3722Schristos
1913b6c3722Schristos /* read state */
1923b6c3722Schristos pos = position_in_string(comments, "state=");
1933b6c3722Schristos if (pos >= (int) strlen(comments))
1943b6c3722Schristos {
1953b6c3722Schristos log_err("parse error");
1963b6c3722Schristos free(comment);
1973b6c3722Schristos return 0;
1983b6c3722Schristos }
1993b6c3722Schristos if (pos <= 0)
2003b6c3722Schristos ta->s = AUTR_STATE_VALID;
2013b6c3722Schristos else
2023b6c3722Schristos {
2033b6c3722Schristos int s = (int) comments[pos] - '0';
2043b6c3722Schristos switch(s)
2053b6c3722Schristos {
2063b6c3722Schristos case AUTR_STATE_START:
2073b6c3722Schristos case AUTR_STATE_ADDPEND:
2083b6c3722Schristos case AUTR_STATE_VALID:
2093b6c3722Schristos case AUTR_STATE_MISSING:
2103b6c3722Schristos case AUTR_STATE_REVOKED:
2113b6c3722Schristos case AUTR_STATE_REMOVED:
2123b6c3722Schristos ta->s = s;
2133b6c3722Schristos break;
2143b6c3722Schristos default:
2153b6c3722Schristos verbose_key(ta, VERB_OPS, "has undefined "
2163b6c3722Schristos "state, considered NewKey");
2173b6c3722Schristos ta->s = AUTR_STATE_START;
2183b6c3722Schristos break;
2193b6c3722Schristos }
2203b6c3722Schristos }
2213b6c3722Schristos /* read pending count */
2223b6c3722Schristos pos = position_in_string(comments, "count=");
2233b6c3722Schristos if (pos >= (int) strlen(comments))
2243b6c3722Schristos {
2253b6c3722Schristos log_err("parse error");
2263b6c3722Schristos free(comment);
2273b6c3722Schristos return 0;
2283b6c3722Schristos }
2293b6c3722Schristos if (pos <= 0)
2303b6c3722Schristos ta->pending_count = 0;
2313b6c3722Schristos else
2323b6c3722Schristos {
2333b6c3722Schristos comments += pos;
2343b6c3722Schristos ta->pending_count = (uint8_t)atoi(comments);
2353b6c3722Schristos }
2363b6c3722Schristos
2373b6c3722Schristos /* read last change */
2383b6c3722Schristos pos = position_in_string(comments, "lastchange=");
2393b6c3722Schristos if (pos >= (int) strlen(comments))
2403b6c3722Schristos {
2413b6c3722Schristos log_err("parse error");
2423b6c3722Schristos free(comment);
2433b6c3722Schristos return 0;
2443b6c3722Schristos }
2453b6c3722Schristos if (pos >= 0)
2463b6c3722Schristos {
2473b6c3722Schristos comments += pos;
2483b6c3722Schristos timestamp = atoi(comments);
2493b6c3722Schristos }
2503b6c3722Schristos if (pos < 0 || !timestamp)
2513b6c3722Schristos ta->last_change = 0;
2523b6c3722Schristos else
2533b6c3722Schristos ta->last_change = (time_t)timestamp;
2543b6c3722Schristos
2553b6c3722Schristos free(comment);
2563b6c3722Schristos return 1;
2573b6c3722Schristos }
2583b6c3722Schristos
2593b6c3722Schristos /** Check if a line contains data (besides comments) */
2603b6c3722Schristos static int
str_contains_data(char * str,char comment)2613b6c3722Schristos str_contains_data(char* str, char comment)
2623b6c3722Schristos {
2633b6c3722Schristos while (*str != '\0') {
2643b6c3722Schristos if (*str == comment || *str == '\n')
2653b6c3722Schristos return 0;
2663b6c3722Schristos if (*str != ' ' && *str != '\t')
2673b6c3722Schristos return 1;
2683b6c3722Schristos str++;
2693b6c3722Schristos }
2703b6c3722Schristos return 0;
2713b6c3722Schristos }
2723b6c3722Schristos
2733b6c3722Schristos /** Get DNSKEY flags
2743b6c3722Schristos * rdata without rdatalen in front of it. */
2753b6c3722Schristos static int
dnskey_flags(uint16_t t,uint8_t * rdata,size_t len)2763b6c3722Schristos dnskey_flags(uint16_t t, uint8_t* rdata, size_t len)
2773b6c3722Schristos {
2783b6c3722Schristos uint16_t f;
2793b6c3722Schristos if(t != LDNS_RR_TYPE_DNSKEY)
2803b6c3722Schristos return 0;
2813b6c3722Schristos if(len < 2)
2823b6c3722Schristos return 0;
2833b6c3722Schristos memmove(&f, rdata, 2);
2843b6c3722Schristos f = ntohs(f);
2853b6c3722Schristos return (int)f;
2863b6c3722Schristos }
2873b6c3722Schristos
2883b6c3722Schristos /** Check if KSK DNSKEY.
2893b6c3722Schristos * pass rdata without rdatalen in front of it */
2903b6c3722Schristos static int
rr_is_dnskey_sep(uint16_t t,uint8_t * rdata,size_t len)2913b6c3722Schristos rr_is_dnskey_sep(uint16_t t, uint8_t* rdata, size_t len)
2923b6c3722Schristos {
2933b6c3722Schristos return (dnskey_flags(t, rdata, len)&DNSKEY_BIT_SEP);
2943b6c3722Schristos }
2953b6c3722Schristos
2963b6c3722Schristos /** Check if TA is KSK DNSKEY */
2973b6c3722Schristos static int
ta_is_dnskey_sep(struct autr_ta * ta)2983b6c3722Schristos ta_is_dnskey_sep(struct autr_ta* ta)
2993b6c3722Schristos {
3003b6c3722Schristos return (dnskey_flags(
3013b6c3722Schristos sldns_wirerr_get_type(ta->rr, ta->rr_len, ta->dname_len),
3023b6c3722Schristos sldns_wirerr_get_rdata(ta->rr, ta->rr_len, ta->dname_len),
3033b6c3722Schristos sldns_wirerr_get_rdatalen(ta->rr, ta->rr_len, ta->dname_len)
3043b6c3722Schristos ) & DNSKEY_BIT_SEP);
3053b6c3722Schristos }
3063b6c3722Schristos
3073b6c3722Schristos /** Check if REVOKED DNSKEY
3083b6c3722Schristos * pass rdata without rdatalen in front of it */
3093b6c3722Schristos static int
rr_is_dnskey_revoked(uint16_t t,uint8_t * rdata,size_t len)3103b6c3722Schristos rr_is_dnskey_revoked(uint16_t t, uint8_t* rdata, size_t len)
3113b6c3722Schristos {
3123b6c3722Schristos return (dnskey_flags(t, rdata, len)&LDNS_KEY_REVOKE_KEY);
3133b6c3722Schristos }
3143b6c3722Schristos
3153b6c3722Schristos /** create ta */
3163b6c3722Schristos static struct autr_ta*
autr_ta_create(uint8_t * rr,size_t rr_len,size_t dname_len)3173b6c3722Schristos autr_ta_create(uint8_t* rr, size_t rr_len, size_t dname_len)
3183b6c3722Schristos {
3193b6c3722Schristos struct autr_ta* ta = (struct autr_ta*)calloc(1, sizeof(*ta));
3203b6c3722Schristos if(!ta) {
3213b6c3722Schristos free(rr);
3223b6c3722Schristos return NULL;
3233b6c3722Schristos }
3243b6c3722Schristos ta->rr = rr;
3253b6c3722Schristos ta->rr_len = rr_len;
3263b6c3722Schristos ta->dname_len = dname_len;
3273b6c3722Schristos return ta;
3283b6c3722Schristos }
3293b6c3722Schristos
3303b6c3722Schristos /** create tp */
3313b6c3722Schristos static struct trust_anchor*
autr_tp_create(struct val_anchors * anchors,uint8_t * own,size_t own_len,uint16_t dc)3323b6c3722Schristos autr_tp_create(struct val_anchors* anchors, uint8_t* own, size_t own_len,
3333b6c3722Schristos uint16_t dc)
3343b6c3722Schristos {
3353b6c3722Schristos struct trust_anchor* tp = (struct trust_anchor*)calloc(1, sizeof(*tp));
3363b6c3722Schristos if(!tp) return NULL;
3373b6c3722Schristos tp->name = memdup(own, own_len);
3383b6c3722Schristos if(!tp->name) {
3393b6c3722Schristos free(tp);
3403b6c3722Schristos return NULL;
3413b6c3722Schristos }
3423b6c3722Schristos tp->namelen = own_len;
3433b6c3722Schristos tp->namelabs = dname_count_labels(tp->name);
3443b6c3722Schristos tp->node.key = tp;
3453b6c3722Schristos tp->dclass = dc;
3463b6c3722Schristos tp->autr = (struct autr_point_data*)calloc(1, sizeof(*tp->autr));
3473b6c3722Schristos if(!tp->autr) {
3483b6c3722Schristos free(tp->name);
3493b6c3722Schristos free(tp);
3503b6c3722Schristos return NULL;
3513b6c3722Schristos }
3523b6c3722Schristos tp->autr->pnode.key = tp;
3533b6c3722Schristos
3543b6c3722Schristos lock_basic_lock(&anchors->lock);
3553b6c3722Schristos if(!rbtree_insert(anchors->tree, &tp->node)) {
3563b6c3722Schristos lock_basic_unlock(&anchors->lock);
3573b6c3722Schristos log_err("trust anchor presented twice");
3583b6c3722Schristos free(tp->name);
3593b6c3722Schristos free(tp->autr);
3603b6c3722Schristos free(tp);
3613b6c3722Schristos return NULL;
3623b6c3722Schristos }
3633b6c3722Schristos if(!rbtree_insert(&anchors->autr->probe, &tp->autr->pnode)) {
3643b6c3722Schristos (void)rbtree_delete(anchors->tree, tp);
3653b6c3722Schristos lock_basic_unlock(&anchors->lock);
3663b6c3722Schristos log_err("trust anchor in probetree twice");
3673b6c3722Schristos free(tp->name);
3683b6c3722Schristos free(tp->autr);
3693b6c3722Schristos free(tp);
3703b6c3722Schristos return NULL;
3713b6c3722Schristos }
3723b6c3722Schristos lock_basic_init(&tp->lock);
3733b6c3722Schristos lock_protect(&tp->lock, tp, sizeof(*tp));
3743b6c3722Schristos lock_protect(&tp->lock, tp->autr, sizeof(*tp->autr));
37501049ae6Schristos lock_basic_unlock(&anchors->lock);
3763b6c3722Schristos return tp;
3773b6c3722Schristos }
3783b6c3722Schristos
3793b6c3722Schristos /** delete assembled rrsets */
3803b6c3722Schristos static void
autr_rrset_delete(struct ub_packed_rrset_key * r)3813b6c3722Schristos autr_rrset_delete(struct ub_packed_rrset_key* r)
3823b6c3722Schristos {
3833b6c3722Schristos if(r) {
3843b6c3722Schristos free(r->rk.dname);
3853b6c3722Schristos free(r->entry.data);
3863b6c3722Schristos free(r);
3873b6c3722Schristos }
3883b6c3722Schristos }
3893b6c3722Schristos
autr_point_delete(struct trust_anchor * tp)3903b6c3722Schristos void autr_point_delete(struct trust_anchor* tp)
3913b6c3722Schristos {
3923b6c3722Schristos if(!tp)
3933b6c3722Schristos return;
3943b6c3722Schristos lock_unprotect(&tp->lock, tp);
3953b6c3722Schristos lock_unprotect(&tp->lock, tp->autr);
3963b6c3722Schristos lock_basic_destroy(&tp->lock);
3973b6c3722Schristos autr_rrset_delete(tp->ds_rrset);
3983b6c3722Schristos autr_rrset_delete(tp->dnskey_rrset);
3993b6c3722Schristos if(tp->autr) {
4003b6c3722Schristos struct autr_ta* p = tp->autr->keys, *np;
4013b6c3722Schristos while(p) {
4023b6c3722Schristos np = p->next;
4033b6c3722Schristos free(p->rr);
4043b6c3722Schristos free(p);
4053b6c3722Schristos p = np;
4063b6c3722Schristos }
4073b6c3722Schristos free(tp->autr->file);
4083b6c3722Schristos free(tp->autr);
4093b6c3722Schristos }
4103b6c3722Schristos free(tp->name);
4113b6c3722Schristos free(tp);
4123b6c3722Schristos }
4133b6c3722Schristos
4143b6c3722Schristos /** find or add a new trust point for autotrust */
4153b6c3722Schristos static struct trust_anchor*
find_add_tp(struct val_anchors * anchors,uint8_t * rr,size_t rr_len,size_t dname_len)4163b6c3722Schristos find_add_tp(struct val_anchors* anchors, uint8_t* rr, size_t rr_len,
4173b6c3722Schristos size_t dname_len)
4183b6c3722Schristos {
4193b6c3722Schristos struct trust_anchor* tp;
4203b6c3722Schristos tp = anchor_find(anchors, rr, dname_count_labels(rr), dname_len,
4213b6c3722Schristos sldns_wirerr_get_class(rr, rr_len, dname_len));
4223b6c3722Schristos if(tp) {
4233b6c3722Schristos if(!tp->autr) {
4243b6c3722Schristos log_err("anchor cannot be with and without autotrust");
4253b6c3722Schristos lock_basic_unlock(&tp->lock);
4263b6c3722Schristos return NULL;
4273b6c3722Schristos }
4283b6c3722Schristos return tp;
4293b6c3722Schristos }
4303b6c3722Schristos tp = autr_tp_create(anchors, rr, dname_len, sldns_wirerr_get_class(rr,
4313b6c3722Schristos rr_len, dname_len));
4320cd9f4ecSchristos if(!tp)
4330cd9f4ecSchristos return NULL;
4343b6c3722Schristos lock_basic_lock(&tp->lock);
4353b6c3722Schristos return tp;
4363b6c3722Schristos }
4373b6c3722Schristos
4383b6c3722Schristos /** Add trust anchor from RR */
4393b6c3722Schristos static struct autr_ta*
add_trustanchor_frm_rr(struct val_anchors * anchors,uint8_t * rr,size_t rr_len,size_t dname_len,struct trust_anchor ** tp)4403b6c3722Schristos add_trustanchor_frm_rr(struct val_anchors* anchors, uint8_t* rr, size_t rr_len,
4413b6c3722Schristos size_t dname_len, struct trust_anchor** tp)
4423b6c3722Schristos {
4433b6c3722Schristos struct autr_ta* ta = autr_ta_create(rr, rr_len, dname_len);
4443b6c3722Schristos if(!ta)
4453b6c3722Schristos return NULL;
4463b6c3722Schristos *tp = find_add_tp(anchors, rr, rr_len, dname_len);
4473b6c3722Schristos if(!*tp) {
4483b6c3722Schristos free(ta->rr);
4493b6c3722Schristos free(ta);
4503b6c3722Schristos return NULL;
4513b6c3722Schristos }
4523b6c3722Schristos /* add ta to tp */
4533b6c3722Schristos ta->next = (*tp)->autr->keys;
4543b6c3722Schristos (*tp)->autr->keys = ta;
4553b6c3722Schristos lock_basic_unlock(&(*tp)->lock);
4563b6c3722Schristos return ta;
4573b6c3722Schristos }
4583b6c3722Schristos
4593b6c3722Schristos /**
4603b6c3722Schristos * Add new trust anchor from a string in file.
4613b6c3722Schristos * @param anchors: all anchors
4623b6c3722Schristos * @param str: string with anchor and comments, if any comments.
4633b6c3722Schristos * @param tp: trust point returned.
4643b6c3722Schristos * @param origin: what to use for @
4653b6c3722Schristos * @param origin_len: length of origin
4663b6c3722Schristos * @param prev: previous rr name
4673b6c3722Schristos * @param prev_len: length of prev
4683b6c3722Schristos * @param skip: if true, the result is NULL, but not an error, skip it.
4693b6c3722Schristos * @return new key in trust point.
4703b6c3722Schristos */
4713b6c3722Schristos static struct autr_ta*
add_trustanchor_frm_str(struct val_anchors * anchors,char * str,struct trust_anchor ** tp,uint8_t * origin,size_t origin_len,uint8_t ** prev,size_t * prev_len,int * skip)4723b6c3722Schristos add_trustanchor_frm_str(struct val_anchors* anchors, char* str,
4733b6c3722Schristos struct trust_anchor** tp, uint8_t* origin, size_t origin_len,
4743b6c3722Schristos uint8_t** prev, size_t* prev_len, int* skip)
4753b6c3722Schristos {
4763b6c3722Schristos uint8_t rr[LDNS_RR_BUF_SIZE];
4773b6c3722Schristos size_t rr_len = sizeof(rr), dname_len;
4783b6c3722Schristos uint8_t* drr;
4793b6c3722Schristos int lstatus;
4803b6c3722Schristos if (!str_contains_data(str, ';')) {
4813b6c3722Schristos *skip = 1;
4823b6c3722Schristos return NULL; /* empty line */
4833b6c3722Schristos }
4843b6c3722Schristos if(0 != (lstatus = sldns_str2wire_rr_buf(str, rr, &rr_len, &dname_len,
4853b6c3722Schristos 0, origin, origin_len, *prev, *prev_len)))
4863b6c3722Schristos {
4873b6c3722Schristos log_err("ldns error while converting string to RR at%d: %s: %s",
4883b6c3722Schristos LDNS_WIREPARSE_OFFSET(lstatus),
4893b6c3722Schristos sldns_get_errorstr_parse(lstatus), str);
4903b6c3722Schristos return NULL;
4913b6c3722Schristos }
4923b6c3722Schristos free(*prev);
4933b6c3722Schristos *prev = memdup(rr, dname_len);
4943b6c3722Schristos *prev_len = dname_len;
4953b6c3722Schristos if(!*prev) {
4963b6c3722Schristos log_err("malloc failure in add_trustanchor");
4973b6c3722Schristos return NULL;
4983b6c3722Schristos }
4993b6c3722Schristos if(sldns_wirerr_get_type(rr, rr_len, dname_len)!=LDNS_RR_TYPE_DNSKEY &&
5003b6c3722Schristos sldns_wirerr_get_type(rr, rr_len, dname_len)!=LDNS_RR_TYPE_DS) {
5013b6c3722Schristos *skip = 1;
5023b6c3722Schristos return NULL; /* only DS and DNSKEY allowed */
5033b6c3722Schristos }
5043b6c3722Schristos drr = memdup(rr, rr_len);
5053b6c3722Schristos if(!drr) {
5063b6c3722Schristos log_err("malloc failure in add trustanchor");
5073b6c3722Schristos return NULL;
5083b6c3722Schristos }
5093b6c3722Schristos return add_trustanchor_frm_rr(anchors, drr, rr_len, dname_len, tp);
5103b6c3722Schristos }
5113b6c3722Schristos
5123b6c3722Schristos /**
5133b6c3722Schristos * Load single anchor
5143b6c3722Schristos * @param anchors: all points.
5153b6c3722Schristos * @param str: comments line
5163b6c3722Schristos * @param fname: filename
5173b6c3722Schristos * @param origin: the $ORIGIN.
5183b6c3722Schristos * @param origin_len: length of origin
5193b6c3722Schristos * @param prev: passed to ldns.
5203b6c3722Schristos * @param prev_len: length of prev
5213b6c3722Schristos * @param skip: if true, the result is NULL, but not an error, skip it.
5223b6c3722Schristos * @return false on failure, otherwise the tp read.
5233b6c3722Schristos */
5243b6c3722Schristos static struct trust_anchor*
load_trustanchor(struct val_anchors * anchors,char * str,const char * fname,uint8_t * origin,size_t origin_len,uint8_t ** prev,size_t * prev_len,int * skip)5253b6c3722Schristos load_trustanchor(struct val_anchors* anchors, char* str, const char* fname,
5263b6c3722Schristos uint8_t* origin, size_t origin_len, uint8_t** prev, size_t* prev_len,
5273b6c3722Schristos int* skip)
5283b6c3722Schristos {
5293b6c3722Schristos struct autr_ta* ta = NULL;
5303b6c3722Schristos struct trust_anchor* tp = NULL;
5313b6c3722Schristos
5323b6c3722Schristos ta = add_trustanchor_frm_str(anchors, str, &tp, origin, origin_len,
5333b6c3722Schristos prev, prev_len, skip);
5343b6c3722Schristos if(!ta)
5353b6c3722Schristos return NULL;
5363b6c3722Schristos lock_basic_lock(&tp->lock);
5373b6c3722Schristos if(!parse_comments(str, ta)) {
5383b6c3722Schristos lock_basic_unlock(&tp->lock);
5393b6c3722Schristos return NULL;
5403b6c3722Schristos }
5413b6c3722Schristos if(!tp->autr->file) {
5423b6c3722Schristos tp->autr->file = strdup(fname);
5433b6c3722Schristos if(!tp->autr->file) {
5443b6c3722Schristos lock_basic_unlock(&tp->lock);
5453b6c3722Schristos log_err("malloc failure");
5463b6c3722Schristos return NULL;
5473b6c3722Schristos }
5483b6c3722Schristos }
5493b6c3722Schristos lock_basic_unlock(&tp->lock);
5503b6c3722Schristos return tp;
5513b6c3722Schristos }
5523b6c3722Schristos
5533b6c3722Schristos /** iterator for DSes from keylist. return true if a next element exists */
5543b6c3722Schristos static int
assemble_iterate_ds(struct autr_ta ** list,uint8_t ** rr,size_t * rr_len,size_t * dname_len)5553b6c3722Schristos assemble_iterate_ds(struct autr_ta** list, uint8_t** rr, size_t* rr_len,
5563b6c3722Schristos size_t* dname_len)
5573b6c3722Schristos {
5583b6c3722Schristos while(*list) {
5593b6c3722Schristos if(sldns_wirerr_get_type((*list)->rr, (*list)->rr_len,
5603b6c3722Schristos (*list)->dname_len) == LDNS_RR_TYPE_DS) {
5613b6c3722Schristos *rr = (*list)->rr;
5623b6c3722Schristos *rr_len = (*list)->rr_len;
5633b6c3722Schristos *dname_len = (*list)->dname_len;
5643b6c3722Schristos *list = (*list)->next;
5653b6c3722Schristos return 1;
5663b6c3722Schristos }
5673b6c3722Schristos *list = (*list)->next;
5683b6c3722Schristos }
5693b6c3722Schristos return 0;
5703b6c3722Schristos }
5713b6c3722Schristos
5723b6c3722Schristos /** iterator for DNSKEYs from keylist. return true if a next element exists */
5733b6c3722Schristos static int
assemble_iterate_dnskey(struct autr_ta ** list,uint8_t ** rr,size_t * rr_len,size_t * dname_len)5743b6c3722Schristos assemble_iterate_dnskey(struct autr_ta** list, uint8_t** rr, size_t* rr_len,
5753b6c3722Schristos size_t* dname_len)
5763b6c3722Schristos {
5773b6c3722Schristos while(*list) {
5783b6c3722Schristos if(sldns_wirerr_get_type((*list)->rr, (*list)->rr_len,
5793b6c3722Schristos (*list)->dname_len) != LDNS_RR_TYPE_DS &&
5803b6c3722Schristos ((*list)->s == AUTR_STATE_VALID ||
5813b6c3722Schristos (*list)->s == AUTR_STATE_MISSING)) {
5823b6c3722Schristos *rr = (*list)->rr;
5833b6c3722Schristos *rr_len = (*list)->rr_len;
5843b6c3722Schristos *dname_len = (*list)->dname_len;
5853b6c3722Schristos *list = (*list)->next;
5863b6c3722Schristos return 1;
5873b6c3722Schristos }
5883b6c3722Schristos *list = (*list)->next;
5893b6c3722Schristos }
5903b6c3722Schristos return 0;
5913b6c3722Schristos }
5923b6c3722Schristos
5933b6c3722Schristos /** see if iterator-list has any elements in it, or it is empty */
5943b6c3722Schristos static int
assemble_iterate_hasfirst(int iter (struct autr_ta **,uint8_t **,size_t *,size_t *),struct autr_ta * list)5953b6c3722Schristos assemble_iterate_hasfirst(int iter(struct autr_ta**, uint8_t**, size_t*,
5963b6c3722Schristos size_t*), struct autr_ta* list)
5973b6c3722Schristos {
5983b6c3722Schristos uint8_t* rr = NULL;
5993b6c3722Schristos size_t rr_len = 0, dname_len = 0;
6003b6c3722Schristos return iter(&list, &rr, &rr_len, &dname_len);
6013b6c3722Schristos }
6023b6c3722Schristos
6033b6c3722Schristos /** number of elements in iterator list */
6043b6c3722Schristos static size_t
assemble_iterate_count(int iter (struct autr_ta **,uint8_t **,size_t *,size_t *),struct autr_ta * list)6053b6c3722Schristos assemble_iterate_count(int iter(struct autr_ta**, uint8_t**, size_t*,
6063b6c3722Schristos size_t*), struct autr_ta* list)
6073b6c3722Schristos {
6083b6c3722Schristos uint8_t* rr = NULL;
6093b6c3722Schristos size_t i = 0, rr_len = 0, dname_len = 0;
6103b6c3722Schristos while(iter(&list, &rr, &rr_len, &dname_len)) {
6113b6c3722Schristos i++;
6123b6c3722Schristos }
6133b6c3722Schristos return i;
6143b6c3722Schristos }
6153b6c3722Schristos
6163b6c3722Schristos /**
6173b6c3722Schristos * Create a ub_packed_rrset_key allocated on the heap.
6183b6c3722Schristos * It therefore does not have the correct ID value, and cannot be used
6193b6c3722Schristos * inside the cache. It can be used in storage outside of the cache.
6203b6c3722Schristos * Keys for the cache have to be obtained from alloc.h .
6213b6c3722Schristos * @param iter: iterator over the elements in the list. It filters elements.
6223b6c3722Schristos * @param list: the list.
6233b6c3722Schristos * @return key allocated or NULL on failure.
6243b6c3722Schristos */
6253b6c3722Schristos static struct ub_packed_rrset_key*
ub_packed_rrset_heap_key(int iter (struct autr_ta **,uint8_t **,size_t *,size_t *),struct autr_ta * list)6263b6c3722Schristos ub_packed_rrset_heap_key(int iter(struct autr_ta**, uint8_t**, size_t*,
6273b6c3722Schristos size_t*), struct autr_ta* list)
6283b6c3722Schristos {
6293b6c3722Schristos uint8_t* rr = NULL;
6303b6c3722Schristos size_t rr_len = 0, dname_len = 0;
6313b6c3722Schristos struct ub_packed_rrset_key* k;
6323b6c3722Schristos if(!iter(&list, &rr, &rr_len, &dname_len))
6333b6c3722Schristos return NULL;
6343b6c3722Schristos k = (struct ub_packed_rrset_key*)calloc(1, sizeof(*k));
6353b6c3722Schristos if(!k)
6363b6c3722Schristos return NULL;
6373b6c3722Schristos k->rk.type = htons(sldns_wirerr_get_type(rr, rr_len, dname_len));
6383b6c3722Schristos k->rk.rrset_class = htons(sldns_wirerr_get_class(rr, rr_len, dname_len));
6393b6c3722Schristos k->rk.dname_len = dname_len;
6403b6c3722Schristos k->rk.dname = memdup(rr, dname_len);
6413b6c3722Schristos if(!k->rk.dname) {
6423b6c3722Schristos free(k);
6433b6c3722Schristos return NULL;
6443b6c3722Schristos }
6453b6c3722Schristos return k;
6463b6c3722Schristos }
6473b6c3722Schristos
6483b6c3722Schristos /**
6493b6c3722Schristos * Create packed_rrset data on the heap.
6503b6c3722Schristos * @param iter: iterator over the elements in the list. It filters elements.
6513b6c3722Schristos * @param list: the list.
6523b6c3722Schristos * @return data allocated or NULL on failure.
6533b6c3722Schristos */
6543b6c3722Schristos static struct packed_rrset_data*
packed_rrset_heap_data(int iter (struct autr_ta **,uint8_t **,size_t *,size_t *),struct autr_ta * list)6553b6c3722Schristos packed_rrset_heap_data(int iter(struct autr_ta**, uint8_t**, size_t*,
6563b6c3722Schristos size_t*), struct autr_ta* list)
6573b6c3722Schristos {
6583b6c3722Schristos uint8_t* rr = NULL;
6593b6c3722Schristos size_t rr_len = 0, dname_len = 0;
6603b6c3722Schristos struct packed_rrset_data* data;
6613b6c3722Schristos size_t count=0, rrsig_count=0, len=0, i, total;
6623b6c3722Schristos uint8_t* nextrdata;
6633b6c3722Schristos struct autr_ta* list_i;
6643b6c3722Schristos time_t ttl = 0;
6653b6c3722Schristos
6663b6c3722Schristos list_i = list;
6673b6c3722Schristos while(iter(&list_i, &rr, &rr_len, &dname_len)) {
6683b6c3722Schristos if(sldns_wirerr_get_type(rr, rr_len, dname_len) ==
6693b6c3722Schristos LDNS_RR_TYPE_RRSIG)
6703b6c3722Schristos rrsig_count++;
6713b6c3722Schristos else count++;
6723b6c3722Schristos /* sizeof the rdlength + rdatalen */
6733b6c3722Schristos len += 2 + sldns_wirerr_get_rdatalen(rr, rr_len, dname_len);
6743b6c3722Schristos ttl = (time_t)sldns_wirerr_get_ttl(rr, rr_len, dname_len);
6753b6c3722Schristos }
6763b6c3722Schristos if(count == 0 && rrsig_count == 0)
6773b6c3722Schristos return NULL;
6783b6c3722Schristos
6793b6c3722Schristos /* allocate */
6803b6c3722Schristos total = count + rrsig_count;
6813b6c3722Schristos len += sizeof(*data) + total*(sizeof(size_t) + sizeof(time_t) +
6823b6c3722Schristos sizeof(uint8_t*));
6833b6c3722Schristos data = (struct packed_rrset_data*)calloc(1, len);
6843b6c3722Schristos if(!data)
6853b6c3722Schristos return NULL;
6863b6c3722Schristos
6873b6c3722Schristos /* fill it */
6883b6c3722Schristos data->ttl = ttl;
6893b6c3722Schristos data->count = count;
6903b6c3722Schristos data->rrsig_count = rrsig_count;
6913b6c3722Schristos data->rr_len = (size_t*)((uint8_t*)data +
6923b6c3722Schristos sizeof(struct packed_rrset_data));
6933b6c3722Schristos data->rr_data = (uint8_t**)&(data->rr_len[total]);
6943b6c3722Schristos data->rr_ttl = (time_t*)&(data->rr_data[total]);
6953b6c3722Schristos nextrdata = (uint8_t*)&(data->rr_ttl[total]);
6963b6c3722Schristos
6973b6c3722Schristos /* fill out len, ttl, fields */
6983b6c3722Schristos list_i = list;
6993b6c3722Schristos i = 0;
7003b6c3722Schristos while(iter(&list_i, &rr, &rr_len, &dname_len)) {
7013b6c3722Schristos data->rr_ttl[i] = (time_t)sldns_wirerr_get_ttl(rr, rr_len,
7023b6c3722Schristos dname_len);
7033b6c3722Schristos if(data->rr_ttl[i] < data->ttl)
7043b6c3722Schristos data->ttl = data->rr_ttl[i];
7053b6c3722Schristos data->rr_len[i] = 2 /* the rdlength */ +
7063b6c3722Schristos sldns_wirerr_get_rdatalen(rr, rr_len, dname_len);
7073b6c3722Schristos i++;
7083b6c3722Schristos }
7093b6c3722Schristos
7103b6c3722Schristos /* fixup rest of ptrs */
7113b6c3722Schristos for(i=0; i<total; i++) {
7123b6c3722Schristos data->rr_data[i] = nextrdata;
7133b6c3722Schristos nextrdata += data->rr_len[i];
7143b6c3722Schristos }
7153b6c3722Schristos
7163b6c3722Schristos /* copy data in there */
7173b6c3722Schristos list_i = list;
7183b6c3722Schristos i = 0;
7193b6c3722Schristos while(iter(&list_i, &rr, &rr_len, &dname_len)) {
720f42d8de7Schristos log_assert(data->rr_data[i]);
7213b6c3722Schristos memmove(data->rr_data[i],
7223b6c3722Schristos sldns_wirerr_get_rdatawl(rr, rr_len, dname_len),
7233b6c3722Schristos data->rr_len[i]);
7243b6c3722Schristos i++;
7253b6c3722Schristos }
7263b6c3722Schristos
7273b6c3722Schristos if(data->rrsig_count && data->count == 0) {
7283b6c3722Schristos data->count = data->rrsig_count; /* rrset type is RRSIG */
7293b6c3722Schristos data->rrsig_count = 0;
7303b6c3722Schristos }
7313b6c3722Schristos return data;
7323b6c3722Schristos }
7333b6c3722Schristos
7343b6c3722Schristos /**
7353b6c3722Schristos * Assemble the trust anchors into DS and DNSKEY packed rrsets.
7363b6c3722Schristos * Uses only VALID and MISSING DNSKEYs.
7373b6c3722Schristos * Read the sldns_rrs and builds packed rrsets
7383b6c3722Schristos * @param tp: the trust point. Must be locked.
7393b6c3722Schristos * @return false on malloc failure.
7403b6c3722Schristos */
7413b6c3722Schristos static int
autr_assemble(struct trust_anchor * tp)7423b6c3722Schristos autr_assemble(struct trust_anchor* tp)
7433b6c3722Schristos {
7443b6c3722Schristos struct ub_packed_rrset_key* ubds=NULL, *ubdnskey=NULL;
7453b6c3722Schristos
7463b6c3722Schristos /* make packed rrset keys - malloced with no ID number, they
7473b6c3722Schristos * are not in the cache */
7483b6c3722Schristos /* make packed rrset data (if there is a key) */
7493b6c3722Schristos if(assemble_iterate_hasfirst(assemble_iterate_ds, tp->autr->keys)) {
7503b6c3722Schristos ubds = ub_packed_rrset_heap_key(
7513b6c3722Schristos assemble_iterate_ds, tp->autr->keys);
7523b6c3722Schristos if(!ubds)
7533b6c3722Schristos goto error_cleanup;
7543b6c3722Schristos ubds->entry.data = packed_rrset_heap_data(
7553b6c3722Schristos assemble_iterate_ds, tp->autr->keys);
7563b6c3722Schristos if(!ubds->entry.data)
7573b6c3722Schristos goto error_cleanup;
7583b6c3722Schristos }
7593b6c3722Schristos
7603b6c3722Schristos /* make packed DNSKEY data */
7613b6c3722Schristos if(assemble_iterate_hasfirst(assemble_iterate_dnskey, tp->autr->keys)) {
7623b6c3722Schristos ubdnskey = ub_packed_rrset_heap_key(
7633b6c3722Schristos assemble_iterate_dnskey, tp->autr->keys);
7643b6c3722Schristos if(!ubdnskey)
7653b6c3722Schristos goto error_cleanup;
7663b6c3722Schristos ubdnskey->entry.data = packed_rrset_heap_data(
7673b6c3722Schristos assemble_iterate_dnskey, tp->autr->keys);
7683b6c3722Schristos if(!ubdnskey->entry.data) {
7693b6c3722Schristos error_cleanup:
7703b6c3722Schristos autr_rrset_delete(ubds);
7713b6c3722Schristos autr_rrset_delete(ubdnskey);
7723b6c3722Schristos return 0;
7733b6c3722Schristos }
7743b6c3722Schristos }
7753b6c3722Schristos
7763b6c3722Schristos /* we have prepared the new keys so nothing can go wrong any more.
7773b6c3722Schristos * And we are sure we cannot be left without trustanchor after
7783b6c3722Schristos * any errors. Put in the new keys and remove old ones. */
7793b6c3722Schristos
7803b6c3722Schristos /* free the old data */
7813b6c3722Schristos autr_rrset_delete(tp->ds_rrset);
7823b6c3722Schristos autr_rrset_delete(tp->dnskey_rrset);
7833b6c3722Schristos
7843b6c3722Schristos /* assign the data to replace the old */
7853b6c3722Schristos tp->ds_rrset = ubds;
7863b6c3722Schristos tp->dnskey_rrset = ubdnskey;
7873b6c3722Schristos tp->numDS = assemble_iterate_count(assemble_iterate_ds,
7883b6c3722Schristos tp->autr->keys);
7893b6c3722Schristos tp->numDNSKEY = assemble_iterate_count(assemble_iterate_dnskey,
7903b6c3722Schristos tp->autr->keys);
7913b6c3722Schristos return 1;
7923b6c3722Schristos }
7933b6c3722Schristos
7943b6c3722Schristos /** parse integer */
7953b6c3722Schristos static unsigned int
parse_int(char * line,int * ret)7963b6c3722Schristos parse_int(char* line, int* ret)
7973b6c3722Schristos {
7983b6c3722Schristos char *e;
7993b6c3722Schristos unsigned int x = (unsigned int)strtol(line, &e, 10);
8003b6c3722Schristos if(line == e) {
8013b6c3722Schristos *ret = -1; /* parse error */
8023b6c3722Schristos return 0;
8033b6c3722Schristos }
8043b6c3722Schristos *ret = 1; /* matched */
8053b6c3722Schristos return x;
8063b6c3722Schristos }
8073b6c3722Schristos
8083b6c3722Schristos /** parse id sequence for anchor */
8093b6c3722Schristos static struct trust_anchor*
parse_id(struct val_anchors * anchors,char * line)8103b6c3722Schristos parse_id(struct val_anchors* anchors, char* line)
8113b6c3722Schristos {
8123b6c3722Schristos struct trust_anchor *tp;
8133b6c3722Schristos int r;
8143b6c3722Schristos uint16_t dclass;
8153b6c3722Schristos uint8_t* dname;
8163b6c3722Schristos size_t dname_len;
8173b6c3722Schristos /* read the owner name */
8183b6c3722Schristos char* next = strchr(line, ' ');
8193b6c3722Schristos if(!next)
8203b6c3722Schristos return NULL;
8213b6c3722Schristos next[0] = 0;
8223b6c3722Schristos dname = sldns_str2wire_dname(line, &dname_len);
8233b6c3722Schristos if(!dname)
8243b6c3722Schristos return NULL;
8253b6c3722Schristos
8263b6c3722Schristos /* read the class */
8273b6c3722Schristos dclass = parse_int(next+1, &r);
8283b6c3722Schristos if(r == -1) {
8293b6c3722Schristos free(dname);
8303b6c3722Schristos return NULL;
8313b6c3722Schristos }
8323b6c3722Schristos
8333b6c3722Schristos /* find the trust point */
8343b6c3722Schristos tp = autr_tp_create(anchors, dname, dname_len, dclass);
8353b6c3722Schristos free(dname);
8363b6c3722Schristos return tp;
8373b6c3722Schristos }
8383b6c3722Schristos
8393b6c3722Schristos /**
8403b6c3722Schristos * Parse variable from trustanchor header
8413b6c3722Schristos * @param line: to parse
8423b6c3722Schristos * @param anchors: the anchor is added to this, if "id:" is seen.
8433b6c3722Schristos * @param anchor: the anchor as result value or previously returned anchor
8443b6c3722Schristos * value to read the variable lines into.
8453b6c3722Schristos * @return: 0 no match, -1 failed syntax error, +1 success line read.
8463b6c3722Schristos * +2 revoked trust anchor file.
8473b6c3722Schristos */
8483b6c3722Schristos static int
parse_var_line(char * line,struct val_anchors * anchors,struct trust_anchor ** anchor)8493b6c3722Schristos parse_var_line(char* line, struct val_anchors* anchors,
8503b6c3722Schristos struct trust_anchor** anchor)
8513b6c3722Schristos {
8523b6c3722Schristos struct trust_anchor* tp = *anchor;
8533b6c3722Schristos int r = 0;
8543b6c3722Schristos if(strncmp(line, ";;id: ", 6) == 0) {
8553b6c3722Schristos *anchor = parse_id(anchors, line+6);
8563b6c3722Schristos if(!*anchor) return -1;
8573b6c3722Schristos else return 1;
8583b6c3722Schristos } else if(strncmp(line, ";;REVOKED", 9) == 0) {
8593b6c3722Schristos if(tp) {
8603b6c3722Schristos log_err("REVOKED statement must be at start of file");
8613b6c3722Schristos return -1;
8623b6c3722Schristos }
8633b6c3722Schristos return 2;
8643b6c3722Schristos } else if(strncmp(line, ";;last_queried: ", 16) == 0) {
8653b6c3722Schristos if(!tp) return -1;
8663b6c3722Schristos lock_basic_lock(&tp->lock);
8673b6c3722Schristos tp->autr->last_queried = (time_t)parse_int(line+16, &r);
8683b6c3722Schristos lock_basic_unlock(&tp->lock);
8693b6c3722Schristos } else if(strncmp(line, ";;last_success: ", 16) == 0) {
8703b6c3722Schristos if(!tp) return -1;
8713b6c3722Schristos lock_basic_lock(&tp->lock);
8723b6c3722Schristos tp->autr->last_success = (time_t)parse_int(line+16, &r);
8733b6c3722Schristos lock_basic_unlock(&tp->lock);
8743b6c3722Schristos } else if(strncmp(line, ";;next_probe_time: ", 19) == 0) {
8753b6c3722Schristos if(!tp) return -1;
8763b6c3722Schristos lock_basic_lock(&anchors->lock);
8773b6c3722Schristos lock_basic_lock(&tp->lock);
8783b6c3722Schristos (void)rbtree_delete(&anchors->autr->probe, tp);
8793b6c3722Schristos tp->autr->next_probe_time = (time_t)parse_int(line+19, &r);
8803b6c3722Schristos (void)rbtree_insert(&anchors->autr->probe, &tp->autr->pnode);
8813b6c3722Schristos lock_basic_unlock(&tp->lock);
8823b6c3722Schristos lock_basic_unlock(&anchors->lock);
8833b6c3722Schristos } else if(strncmp(line, ";;query_failed: ", 16) == 0) {
8843b6c3722Schristos if(!tp) return -1;
8853b6c3722Schristos lock_basic_lock(&tp->lock);
8863b6c3722Schristos tp->autr->query_failed = (uint8_t)parse_int(line+16, &r);
8873b6c3722Schristos lock_basic_unlock(&tp->lock);
8883b6c3722Schristos } else if(strncmp(line, ";;query_interval: ", 18) == 0) {
8893b6c3722Schristos if(!tp) return -1;
8903b6c3722Schristos lock_basic_lock(&tp->lock);
8913b6c3722Schristos tp->autr->query_interval = (time_t)parse_int(line+18, &r);
8923b6c3722Schristos lock_basic_unlock(&tp->lock);
8933b6c3722Schristos } else if(strncmp(line, ";;retry_time: ", 14) == 0) {
8943b6c3722Schristos if(!tp) return -1;
8953b6c3722Schristos lock_basic_lock(&tp->lock);
8963b6c3722Schristos tp->autr->retry_time = (time_t)parse_int(line+14, &r);
8973b6c3722Schristos lock_basic_unlock(&tp->lock);
8983b6c3722Schristos }
8993b6c3722Schristos return r;
9003b6c3722Schristos }
9013b6c3722Schristos
9023b6c3722Schristos /** handle origin lines */
9033b6c3722Schristos static int
handle_origin(char * line,uint8_t ** origin,size_t * origin_len)9043b6c3722Schristos handle_origin(char* line, uint8_t** origin, size_t* origin_len)
9053b6c3722Schristos {
9063b6c3722Schristos size_t len = 0;
9073b6c3722Schristos while(isspace((unsigned char)*line))
9083b6c3722Schristos line++;
9093b6c3722Schristos if(strncmp(line, "$ORIGIN", 7) != 0)
9103b6c3722Schristos return 0;
9113b6c3722Schristos free(*origin);
9123b6c3722Schristos line += 7;
9133b6c3722Schristos while(isspace((unsigned char)*line))
9143b6c3722Schristos line++;
9153b6c3722Schristos *origin = sldns_str2wire_dname(line, &len);
9163b6c3722Schristos *origin_len = len;
9173b6c3722Schristos if(!*origin)
9183b6c3722Schristos log_warn("malloc failure or parse error in $ORIGIN");
9193b6c3722Schristos return 1;
9203b6c3722Schristos }
9213b6c3722Schristos
9223b6c3722Schristos /** Read one line and put multiline RRs onto one line string */
9233b6c3722Schristos static int
read_multiline(char * buf,size_t len,FILE * in,int * linenr)9243b6c3722Schristos read_multiline(char* buf, size_t len, FILE* in, int* linenr)
9253b6c3722Schristos {
9263b6c3722Schristos char* pos = buf;
9273b6c3722Schristos size_t left = len;
9283b6c3722Schristos int depth = 0;
9293b6c3722Schristos buf[len-1] = 0;
9303b6c3722Schristos while(left > 0 && fgets(pos, (int)left, in) != NULL) {
9313b6c3722Schristos size_t i, poslen = strlen(pos);
9323b6c3722Schristos (*linenr)++;
9333b6c3722Schristos
9343b6c3722Schristos /* check what the new depth is after the line */
9353b6c3722Schristos /* this routine cannot handle braces inside quotes,
9363b6c3722Schristos say for TXT records, but this routine only has to read keys */
9373b6c3722Schristos for(i=0; i<poslen; i++) {
9383b6c3722Schristos if(pos[i] == '(') {
9393b6c3722Schristos depth++;
9403b6c3722Schristos } else if(pos[i] == ')') {
9413b6c3722Schristos if(depth == 0) {
9423b6c3722Schristos log_err("mismatch: too many ')'");
9433b6c3722Schristos return -1;
9443b6c3722Schristos }
9453b6c3722Schristos depth--;
9463b6c3722Schristos } else if(pos[i] == ';') {
9473b6c3722Schristos break;
9483b6c3722Schristos }
9493b6c3722Schristos }
9503b6c3722Schristos
9513b6c3722Schristos /* normal oneline or last line: keeps newline and comments */
9523b6c3722Schristos if(depth == 0) {
9533b6c3722Schristos return 1;
9543b6c3722Schristos }
9553b6c3722Schristos
9563b6c3722Schristos /* more lines expected, snip off comments and newline */
9573b6c3722Schristos if(poslen>0)
9583b6c3722Schristos pos[poslen-1] = 0; /* strip newline */
9593b6c3722Schristos if(strchr(pos, ';'))
9603b6c3722Schristos strchr(pos, ';')[0] = 0; /* strip comments */
9613b6c3722Schristos
9623b6c3722Schristos /* move to paste other lines behind this one */
9633b6c3722Schristos poslen = strlen(pos);
9643b6c3722Schristos pos += poslen;
9653b6c3722Schristos left -= poslen;
9663b6c3722Schristos /* the newline is changed into a space */
9673b6c3722Schristos if(left <= 2 /* space and eos */) {
9683b6c3722Schristos log_err("line too long");
9693b6c3722Schristos return -1;
9703b6c3722Schristos }
9713b6c3722Schristos pos[0] = ' ';
9723b6c3722Schristos pos[1] = 0;
9733b6c3722Schristos pos += 1;
9743b6c3722Schristos left -= 1;
9753b6c3722Schristos }
9763b6c3722Schristos if(depth != 0) {
9773b6c3722Schristos log_err("mismatch: too many '('");
9783b6c3722Schristos return -1;
9793b6c3722Schristos }
9803b6c3722Schristos if(pos != buf)
9813b6c3722Schristos return 1;
9823b6c3722Schristos return 0;
9833b6c3722Schristos }
9843b6c3722Schristos
autr_read_file(struct val_anchors * anchors,const char * nm)9853b6c3722Schristos int autr_read_file(struct val_anchors* anchors, const char* nm)
9863b6c3722Schristos {
9873b6c3722Schristos /* the file descriptor */
9883b6c3722Schristos FILE* fd;
9893b6c3722Schristos /* keep track of line numbers */
9903b6c3722Schristos int line_nr = 0;
9913b6c3722Schristos /* single line */
9923b6c3722Schristos char line[10240];
9933b6c3722Schristos /* trust point being read */
9943b6c3722Schristos struct trust_anchor *tp = NULL, *tp2;
9953b6c3722Schristos int r;
9963b6c3722Schristos /* for $ORIGIN parsing */
9973b6c3722Schristos uint8_t *origin=NULL, *prev=NULL;
9983b6c3722Schristos size_t origin_len=0, prev_len=0;
9993b6c3722Schristos
10003b6c3722Schristos if (!(fd = fopen(nm, "r"))) {
10013b6c3722Schristos log_err("unable to open %s for reading: %s",
10023b6c3722Schristos nm, strerror(errno));
10033b6c3722Schristos return 0;
10043b6c3722Schristos }
10053b6c3722Schristos verbose(VERB_ALGO, "reading autotrust anchor file %s", nm);
10063b6c3722Schristos while ( (r=read_multiline(line, sizeof(line), fd, &line_nr)) != 0) {
10073b6c3722Schristos if(r == -1 || (r = parse_var_line(line, anchors, &tp)) == -1) {
10083b6c3722Schristos log_err("could not parse auto-trust-anchor-file "
10093b6c3722Schristos "%s line %d", nm, line_nr);
10103b6c3722Schristos fclose(fd);
10113b6c3722Schristos free(origin);
10123b6c3722Schristos free(prev);
10133b6c3722Schristos return 0;
10143b6c3722Schristos } else if(r == 1) {
10153b6c3722Schristos continue;
10163b6c3722Schristos } else if(r == 2) {
10173b6c3722Schristos log_warn("trust anchor %s has been revoked", nm);
10183b6c3722Schristos fclose(fd);
10193b6c3722Schristos free(origin);
10203b6c3722Schristos free(prev);
10213b6c3722Schristos return 1;
10223b6c3722Schristos }
10233b6c3722Schristos if (!str_contains_data(line, ';'))
10243b6c3722Schristos continue; /* empty lines allowed */
10253b6c3722Schristos if(handle_origin(line, &origin, &origin_len))
10263b6c3722Schristos continue;
10273b6c3722Schristos r = 0;
10283b6c3722Schristos if(!(tp2=load_trustanchor(anchors, line, nm, origin,
10293b6c3722Schristos origin_len, &prev, &prev_len, &r))) {
10303b6c3722Schristos if(!r) log_err("failed to load trust anchor from %s "
10313b6c3722Schristos "at line %i, skipping", nm, line_nr);
10323b6c3722Schristos /* try to do the rest */
10333b6c3722Schristos continue;
10343b6c3722Schristos }
10353b6c3722Schristos if(tp && tp != tp2) {
10363b6c3722Schristos log_err("file %s has mismatching data inside: "
10373b6c3722Schristos "the file may only contain keys for one name, "
10383b6c3722Schristos "remove keys for other domain names", nm);
10393b6c3722Schristos fclose(fd);
10403b6c3722Schristos free(origin);
10413b6c3722Schristos free(prev);
10423b6c3722Schristos return 0;
10433b6c3722Schristos }
10443b6c3722Schristos tp = tp2;
10453b6c3722Schristos }
10463b6c3722Schristos fclose(fd);
10473b6c3722Schristos free(origin);
10483b6c3722Schristos free(prev);
10493b6c3722Schristos if(!tp) {
10503b6c3722Schristos log_err("failed to read %s", nm);
10513b6c3722Schristos return 0;
10523b6c3722Schristos }
10533b6c3722Schristos
10543b6c3722Schristos /* now assemble the data into DNSKEY and DS packed rrsets */
10553b6c3722Schristos lock_basic_lock(&tp->lock);
10563b6c3722Schristos if(!autr_assemble(tp)) {
10573b6c3722Schristos lock_basic_unlock(&tp->lock);
10583b6c3722Schristos log_err("malloc failure assembling %s", nm);
10593b6c3722Schristos return 0;
10603b6c3722Schristos }
10613b6c3722Schristos lock_basic_unlock(&tp->lock);
10623b6c3722Schristos return 1;
10633b6c3722Schristos }
10643b6c3722Schristos
10653b6c3722Schristos /** string for a trustanchor state */
10663b6c3722Schristos static const char*
trustanchor_state2str(autr_state_type s)10670cd9f4ecSchristos trustanchor_state2str(autr_state_type s)
10683b6c3722Schristos {
10693b6c3722Schristos switch (s) {
10703b6c3722Schristos case AUTR_STATE_START: return " START ";
10713b6c3722Schristos case AUTR_STATE_ADDPEND: return " ADDPEND ";
10723b6c3722Schristos case AUTR_STATE_VALID: return " VALID ";
10733b6c3722Schristos case AUTR_STATE_MISSING: return " MISSING ";
10743b6c3722Schristos case AUTR_STATE_REVOKED: return " REVOKED ";
10753b6c3722Schristos case AUTR_STATE_REMOVED: return " REMOVED ";
10763b6c3722Schristos }
10773b6c3722Schristos return " UNKNOWN ";
10783b6c3722Schristos }
10793b6c3722Schristos
10807a540f2bSchristos /** ctime r for autotrust */
autr_ctime_r(time_t * t,char * s)10817a540f2bSchristos static char* autr_ctime_r(time_t* t, char* s)
10827a540f2bSchristos {
10837a540f2bSchristos ctime_r(t, s);
10847a540f2bSchristos #ifdef USE_WINSOCK
10857a540f2bSchristos if(strlen(s) > 10 && s[7]==' ' && s[8]=='0')
10867a540f2bSchristos s[8]=' '; /* fix error in windows ctime */
10877a540f2bSchristos #endif
10887a540f2bSchristos return s;
10897a540f2bSchristos }
10907a540f2bSchristos
10913b6c3722Schristos /** print ID to file */
10923b6c3722Schristos static int
print_id(FILE * out,char * fname,uint8_t * nm,size_t nmlen,uint16_t dclass)10933b6c3722Schristos print_id(FILE* out, char* fname, uint8_t* nm, size_t nmlen, uint16_t dclass)
10943b6c3722Schristos {
10953b6c3722Schristos char* s = sldns_wire2str_dname(nm, nmlen);
10963b6c3722Schristos if(!s) {
10973b6c3722Schristos log_err("malloc failure in write to %s", fname);
10983b6c3722Schristos return 0;
10993b6c3722Schristos }
11003b6c3722Schristos if(fprintf(out, ";;id: %s %d\n", s, (int)dclass) < 0) {
11013b6c3722Schristos log_err("could not write to %s: %s", fname, strerror(errno));
11023b6c3722Schristos free(s);
11033b6c3722Schristos return 0;
11043b6c3722Schristos }
11053b6c3722Schristos free(s);
11063b6c3722Schristos return 1;
11073b6c3722Schristos }
11083b6c3722Schristos
11093b6c3722Schristos static int
autr_write_contents(FILE * out,char * fn,struct trust_anchor * tp)11103b6c3722Schristos autr_write_contents(FILE* out, char* fn, struct trust_anchor* tp)
11113b6c3722Schristos {
11123b6c3722Schristos char tmi[32];
11133b6c3722Schristos struct autr_ta* ta;
11143b6c3722Schristos char* str;
11153b6c3722Schristos
11163b6c3722Schristos /* write pretty header */
11173b6c3722Schristos if(fprintf(out, "; autotrust trust anchor file\n") < 0) {
11183b6c3722Schristos log_err("could not write to %s: %s", fn, strerror(errno));
11193b6c3722Schristos return 0;
11203b6c3722Schristos }
11213b6c3722Schristos if(tp->autr->revoked) {
11223b6c3722Schristos if(fprintf(out, ";;REVOKED\n") < 0 ||
11233b6c3722Schristos fprintf(out, "; The zone has all keys revoked, and is\n"
11243b6c3722Schristos "; considered as if it has no trust anchors.\n"
11253b6c3722Schristos "; the remainder of the file is the last probe.\n"
11263b6c3722Schristos "; to restart the trust anchor, overwrite this file.\n"
11273b6c3722Schristos "; with one containing valid DNSKEYs or DSes.\n") < 0) {
11283b6c3722Schristos log_err("could not write to %s: %s", fn, strerror(errno));
11293b6c3722Schristos return 0;
11303b6c3722Schristos }
11313b6c3722Schristos }
11323b6c3722Schristos if(!print_id(out, fn, tp->name, tp->namelen, tp->dclass)) {
11333b6c3722Schristos return 0;
11343b6c3722Schristos }
11353b6c3722Schristos if(fprintf(out, ";;last_queried: %u ;;%s",
11363b6c3722Schristos (unsigned int)tp->autr->last_queried,
11377a540f2bSchristos autr_ctime_r(&(tp->autr->last_queried), tmi)) < 0 ||
11383b6c3722Schristos fprintf(out, ";;last_success: %u ;;%s",
11393b6c3722Schristos (unsigned int)tp->autr->last_success,
11407a540f2bSchristos autr_ctime_r(&(tp->autr->last_success), tmi)) < 0 ||
11413b6c3722Schristos fprintf(out, ";;next_probe_time: %u ;;%s",
11423b6c3722Schristos (unsigned int)tp->autr->next_probe_time,
11437a540f2bSchristos autr_ctime_r(&(tp->autr->next_probe_time), tmi)) < 0 ||
11443b6c3722Schristos fprintf(out, ";;query_failed: %d\n", (int)tp->autr->query_failed)<0
11453b6c3722Schristos || fprintf(out, ";;query_interval: %d\n",
11463b6c3722Schristos (int)tp->autr->query_interval) < 0 ||
11473b6c3722Schristos fprintf(out, ";;retry_time: %d\n", (int)tp->autr->retry_time) < 0) {
11483b6c3722Schristos log_err("could not write to %s: %s", fn, strerror(errno));
11493b6c3722Schristos return 0;
11503b6c3722Schristos }
11513b6c3722Schristos
11523b6c3722Schristos /* write anchors */
11533b6c3722Schristos for(ta=tp->autr->keys; ta; ta=ta->next) {
11543b6c3722Schristos /* by default do not store START and REMOVED keys */
11553b6c3722Schristos if(ta->s == AUTR_STATE_START)
11563b6c3722Schristos continue;
11573b6c3722Schristos if(ta->s == AUTR_STATE_REMOVED)
11583b6c3722Schristos continue;
11593b6c3722Schristos /* only store keys */
11603b6c3722Schristos if(sldns_wirerr_get_type(ta->rr, ta->rr_len, ta->dname_len)
11613b6c3722Schristos != LDNS_RR_TYPE_DNSKEY)
11623b6c3722Schristos continue;
11633b6c3722Schristos str = sldns_wire2str_rr(ta->rr, ta->rr_len);
11643b6c3722Schristos if(!str || !str[0]) {
11653b6c3722Schristos free(str);
11663b6c3722Schristos log_err("malloc failure writing %s", fn);
11673b6c3722Schristos return 0;
11683b6c3722Schristos }
11693b6c3722Schristos str[strlen(str)-1] = 0; /* remove newline */
11703b6c3722Schristos if(fprintf(out, "%s ;;state=%d [%s] ;;count=%d "
11713b6c3722Schristos ";;lastchange=%u ;;%s", str, (int)ta->s,
11723b6c3722Schristos trustanchor_state2str(ta->s), (int)ta->pending_count,
11733b6c3722Schristos (unsigned int)ta->last_change,
11747a540f2bSchristos autr_ctime_r(&(ta->last_change), tmi)) < 0) {
11753b6c3722Schristos log_err("could not write to %s: %s", fn, strerror(errno));
11763b6c3722Schristos free(str);
11773b6c3722Schristos return 0;
11783b6c3722Schristos }
11793b6c3722Schristos free(str);
11803b6c3722Schristos }
11813b6c3722Schristos return 1;
11823b6c3722Schristos }
11833b6c3722Schristos
autr_write_file(struct module_env * env,struct trust_anchor * tp)11843b6c3722Schristos void autr_write_file(struct module_env* env, struct trust_anchor* tp)
11853b6c3722Schristos {
11863b6c3722Schristos FILE* out;
11873b6c3722Schristos char* fname = tp->autr->file;
118801049ae6Schristos #ifndef S_SPLINT_S
118901049ae6Schristos long long llvalue;
119001049ae6Schristos #endif
11913b6c3722Schristos char tempf[2048];
11923b6c3722Schristos log_assert(tp->autr);
11933b6c3722Schristos if(!env) {
11943b6c3722Schristos log_err("autr_write_file: Module environment is NULL.");
11953b6c3722Schristos return;
11963b6c3722Schristos }
119701049ae6Schristos /* unique name with pid number, thread number, and struct pointer
119801049ae6Schristos * (the pointer uniquifies for multiple libunbound contexts) */
119901049ae6Schristos #ifndef S_SPLINT_S
120001049ae6Schristos #if defined(SIZE_MAX) && defined(UINT32_MAX) && (UINT32_MAX == SIZE_MAX || INT32_MAX == SIZE_MAX)
120101049ae6Schristos /* avoid warning about upcast on 32bit systems */
120201049ae6Schristos llvalue = (unsigned long)tp;
120301049ae6Schristos #else
120401049ae6Schristos llvalue = (unsigned long long)tp;
120501049ae6Schristos #endif
12067a540f2bSchristos snprintf(tempf, sizeof(tempf), "%s.%d-%d-" ARG_LL "x", fname, (int)getpid(),
120701049ae6Schristos env->worker?*(int*)env->worker:0, llvalue);
120801049ae6Schristos #endif /* S_SPLINT_S */
12093b6c3722Schristos verbose(VERB_ALGO, "autotrust: write to disk: %s", tempf);
12103b6c3722Schristos out = fopen(tempf, "w");
12113b6c3722Schristos if(!out) {
12123b6c3722Schristos fatal_exit("could not open autotrust file for writing, %s: %s",
12133b6c3722Schristos tempf, strerror(errno));
12143b6c3722Schristos return;
12153b6c3722Schristos }
12163b6c3722Schristos if(!autr_write_contents(out, tempf, tp)) {
12173b6c3722Schristos /* failed to write contents (completely) */
12183b6c3722Schristos fclose(out);
12193b6c3722Schristos unlink(tempf);
12203b6c3722Schristos fatal_exit("could not completely write: %s", fname);
12213b6c3722Schristos return;
12223b6c3722Schristos }
12233b6c3722Schristos if(fflush(out) != 0)
12243b6c3722Schristos log_err("could not fflush(%s): %s", fname, strerror(errno));
12253b6c3722Schristos #ifdef HAVE_FSYNC
12263b6c3722Schristos if(fsync(fileno(out)) != 0)
12273b6c3722Schristos log_err("could not fsync(%s): %s", fname, strerror(errno));
12283b6c3722Schristos #else
12290cd9f4ecSchristos FlushFileBuffers((HANDLE)_get_osfhandle(_fileno(out)));
12303b6c3722Schristos #endif
12313b6c3722Schristos if(fclose(out) != 0) {
12323b6c3722Schristos fatal_exit("could not complete write: %s: %s",
12333b6c3722Schristos fname, strerror(errno));
12343b6c3722Schristos unlink(tempf);
12353b6c3722Schristos return;
12363b6c3722Schristos }
12373b6c3722Schristos /* success; overwrite actual file */
12383b6c3722Schristos verbose(VERB_ALGO, "autotrust: replaced %s", fname);
12393b6c3722Schristos #ifdef UB_ON_WINDOWS
12403b6c3722Schristos (void)unlink(fname); /* windows does not replace file with rename() */
12413b6c3722Schristos #endif
12423b6c3722Schristos if(rename(tempf, fname) < 0) {
12433b6c3722Schristos fatal_exit("rename(%s to %s): %s", tempf, fname, strerror(errno));
12443b6c3722Schristos }
12453b6c3722Schristos }
12463b6c3722Schristos
12473b6c3722Schristos /**
12483b6c3722Schristos * Verify if dnskey works for trust point
12493b6c3722Schristos * @param env: environment (with time) for verification
12503b6c3722Schristos * @param ve: validator environment (with options) for verification.
12513b6c3722Schristos * @param tp: trust point to verify with
12523b6c3722Schristos * @param rrset: DNSKEY rrset to verify.
12530cd9f4ecSchristos * @param qstate: qstate with region.
12543b6c3722Schristos * @return false on failure, true if verification successful.
12553b6c3722Schristos */
12563b6c3722Schristos static int
verify_dnskey(struct module_env * env,struct val_env * ve,struct trust_anchor * tp,struct ub_packed_rrset_key * rrset,struct module_qstate * qstate)12573b6c3722Schristos verify_dnskey(struct module_env* env, struct val_env* ve,
12580cd9f4ecSchristos struct trust_anchor* tp, struct ub_packed_rrset_key* rrset,
12590cd9f4ecSchristos struct module_qstate* qstate)
12603b6c3722Schristos {
12613b6c3722Schristos char* reason = NULL;
12623b6c3722Schristos uint8_t sigalg[ALGO_NEEDS_MAX+1];
12633b6c3722Schristos int downprot = env->cfg->harden_algo_downgrade;
12643b6c3722Schristos enum sec_status sec = val_verify_DNSKEY_with_TA(env, ve, rrset,
12650cd9f4ecSchristos tp->ds_rrset, tp->dnskey_rrset, downprot?sigalg:NULL, &reason,
12667a540f2bSchristos NULL, qstate);
12673b6c3722Schristos /* sigalg is ignored, it returns algorithms signalled to exist, but
12683b6c3722Schristos * in 5011 there are no other rrsets to check. if downprot is
12693b6c3722Schristos * enabled, then it checks that the DNSKEY is signed with all
12703b6c3722Schristos * algorithms available in the trust store. */
12713b6c3722Schristos verbose(VERB_ALGO, "autotrust: validate DNSKEY with anchor: %s",
12723b6c3722Schristos sec_status_to_string(sec));
12733b6c3722Schristos return sec == sec_status_secure;
12743b6c3722Schristos }
12753b6c3722Schristos
12763b6c3722Schristos static int32_t
rrsig_get_expiry(uint8_t * d,size_t len)12773b6c3722Schristos rrsig_get_expiry(uint8_t* d, size_t len)
12783b6c3722Schristos {
12793b6c3722Schristos /* rrsig: 2(rdlen), 2(type) 1(alg) 1(v) 4(origttl), then 4(expi), (4)incep) */
12803b6c3722Schristos if(len < 2+8+4)
12813b6c3722Schristos return 0;
12823b6c3722Schristos return sldns_read_uint32(d+2+8);
12833b6c3722Schristos }
12843b6c3722Schristos
12853b6c3722Schristos /** Find minimum expiration interval from signatures */
12863b6c3722Schristos static time_t
min_expiry(struct module_env * env,struct packed_rrset_data * dd)12873b6c3722Schristos min_expiry(struct module_env* env, struct packed_rrset_data* dd)
12883b6c3722Schristos {
12893b6c3722Schristos size_t i;
12903b6c3722Schristos int32_t t, r = 15 * 24 * 3600; /* 15 days max */
12913b6c3722Schristos for(i=dd->count; i<dd->count+dd->rrsig_count; i++) {
12923b6c3722Schristos t = rrsig_get_expiry(dd->rr_data[i], dd->rr_len[i]);
12933b6c3722Schristos if((int32_t)t - (int32_t)*env->now > 0) {
12943b6c3722Schristos t -= (int32_t)*env->now;
12953b6c3722Schristos if(t < r)
12963b6c3722Schristos r = t;
12973b6c3722Schristos }
12983b6c3722Schristos }
12993b6c3722Schristos return (time_t)r;
13003b6c3722Schristos }
13013b6c3722Schristos
13023b6c3722Schristos /** Is rr self-signed revoked key */
13033b6c3722Schristos static int
rr_is_selfsigned_revoked(struct module_env * env,struct val_env * ve,struct ub_packed_rrset_key * dnskey_rrset,size_t i,struct module_qstate * qstate)13043b6c3722Schristos rr_is_selfsigned_revoked(struct module_env* env, struct val_env* ve,
13050cd9f4ecSchristos struct ub_packed_rrset_key* dnskey_rrset, size_t i,
13060cd9f4ecSchristos struct module_qstate* qstate)
13073b6c3722Schristos {
13083b6c3722Schristos enum sec_status sec;
13093b6c3722Schristos char* reason = NULL;
13103b6c3722Schristos verbose(VERB_ALGO, "seen REVOKE flag, check self-signed, rr %d",
13113b6c3722Schristos (int)i);
13123b6c3722Schristos /* no algorithm downgrade protection necessary, if it is selfsigned
13133b6c3722Schristos * revoked it can be removed. */
13143b6c3722Schristos sec = dnskey_verify_rrset(env, ve, dnskey_rrset, dnskey_rrset, i,
13157a540f2bSchristos &reason, NULL, LDNS_SECTION_ANSWER, qstate);
13163b6c3722Schristos return (sec == sec_status_secure);
13173b6c3722Schristos }
13183b6c3722Schristos
13193b6c3722Schristos /** Set fetched value */
13203b6c3722Schristos static void
seen_trustanchor(struct autr_ta * ta,uint8_t seen)13213b6c3722Schristos seen_trustanchor(struct autr_ta* ta, uint8_t seen)
13223b6c3722Schristos {
13233b6c3722Schristos ta->fetched = seen;
13243b6c3722Schristos if(ta->pending_count < 250) /* no numerical overflow, please */
13253b6c3722Schristos ta->pending_count++;
13263b6c3722Schristos }
13273b6c3722Schristos
13283b6c3722Schristos /** set revoked value */
13293b6c3722Schristos static void
seen_revoked_trustanchor(struct autr_ta * ta,uint8_t revoked)13303b6c3722Schristos seen_revoked_trustanchor(struct autr_ta* ta, uint8_t revoked)
13313b6c3722Schristos {
13323b6c3722Schristos ta->revoked = revoked;
13333b6c3722Schristos }
13343b6c3722Schristos
13353b6c3722Schristos /** revoke a trust anchor */
13363b6c3722Schristos static void
revoke_dnskey(struct autr_ta * ta,int off)13373b6c3722Schristos revoke_dnskey(struct autr_ta* ta, int off)
13383b6c3722Schristos {
13393b6c3722Schristos uint16_t flags;
13403b6c3722Schristos uint8_t* data;
13413b6c3722Schristos if(sldns_wirerr_get_type(ta->rr, ta->rr_len, ta->dname_len) !=
13423b6c3722Schristos LDNS_RR_TYPE_DNSKEY)
13433b6c3722Schristos return;
13443b6c3722Schristos if(sldns_wirerr_get_rdatalen(ta->rr, ta->rr_len, ta->dname_len) < 2)
13453b6c3722Schristos return;
13463b6c3722Schristos data = sldns_wirerr_get_rdata(ta->rr, ta->rr_len, ta->dname_len);
13473b6c3722Schristos flags = sldns_read_uint16(data);
13483b6c3722Schristos if (off && (flags&LDNS_KEY_REVOKE_KEY))
13493b6c3722Schristos flags ^= LDNS_KEY_REVOKE_KEY; /* flip */
13503b6c3722Schristos else
13513b6c3722Schristos flags |= LDNS_KEY_REVOKE_KEY;
13523b6c3722Schristos sldns_write_uint16(data, flags);
13533b6c3722Schristos }
13543b6c3722Schristos
13553b6c3722Schristos /** Compare two RRs skipping the REVOKED bit. Pass rdata(no len) */
13563b6c3722Schristos static int
dnskey_compare_skip_revbit(uint8_t * a,size_t a_len,uint8_t * b,size_t b_len)13573b6c3722Schristos dnskey_compare_skip_revbit(uint8_t* a, size_t a_len, uint8_t* b, size_t b_len)
13583b6c3722Schristos {
13593b6c3722Schristos size_t i;
13603b6c3722Schristos if(a_len != b_len)
13613b6c3722Schristos return -1;
13623b6c3722Schristos /* compare RRs RDATA byte for byte. */
13633b6c3722Schristos for(i = 0; i < a_len; i++)
13643b6c3722Schristos {
13653b6c3722Schristos uint8_t rdf1, rdf2;
13663b6c3722Schristos rdf1 = a[i];
13673b6c3722Schristos rdf2 = b[i];
13683b6c3722Schristos if(i==1) {
13693b6c3722Schristos /* this is the second part of the flags field */
13703b6c3722Schristos rdf1 |= LDNS_KEY_REVOKE_KEY;
13713b6c3722Schristos rdf2 |= LDNS_KEY_REVOKE_KEY;
13723b6c3722Schristos }
13733b6c3722Schristos if (rdf1 < rdf2) return -1;
13743b6c3722Schristos else if (rdf1 > rdf2) return 1;
13753b6c3722Schristos }
13763b6c3722Schristos return 0;
13773b6c3722Schristos }
13783b6c3722Schristos
13793b6c3722Schristos
13803b6c3722Schristos /** compare trust anchor with rdata, 0 if equal. Pass rdata(no len) */
13813b6c3722Schristos static int
ta_compare(struct autr_ta * a,uint16_t t,uint8_t * b,size_t b_len)13823b6c3722Schristos ta_compare(struct autr_ta* a, uint16_t t, uint8_t* b, size_t b_len)
13833b6c3722Schristos {
13843b6c3722Schristos if(!a) return -1;
13853b6c3722Schristos else if(!b) return -1;
13863b6c3722Schristos else if(sldns_wirerr_get_type(a->rr, a->rr_len, a->dname_len) != t)
13873b6c3722Schristos return (int)sldns_wirerr_get_type(a->rr, a->rr_len,
13883b6c3722Schristos a->dname_len) - (int)t;
13893b6c3722Schristos else if(t == LDNS_RR_TYPE_DNSKEY) {
13903b6c3722Schristos return dnskey_compare_skip_revbit(
13913b6c3722Schristos sldns_wirerr_get_rdata(a->rr, a->rr_len, a->dname_len),
13923b6c3722Schristos sldns_wirerr_get_rdatalen(a->rr, a->rr_len,
13933b6c3722Schristos a->dname_len), b, b_len);
13943b6c3722Schristos }
13953b6c3722Schristos else if(t == LDNS_RR_TYPE_DS) {
13963b6c3722Schristos if(sldns_wirerr_get_rdatalen(a->rr, a->rr_len, a->dname_len) !=
13973b6c3722Schristos b_len)
13983b6c3722Schristos return -1;
13993b6c3722Schristos return memcmp(sldns_wirerr_get_rdata(a->rr,
14003b6c3722Schristos a->rr_len, a->dname_len), b, b_len);
14013b6c3722Schristos }
14023b6c3722Schristos return -1;
14033b6c3722Schristos }
14043b6c3722Schristos
14053b6c3722Schristos /**
14063b6c3722Schristos * Find key
14073b6c3722Schristos * @param tp: to search in
14083b6c3722Schristos * @param t: rr type of the rdata.
14093b6c3722Schristos * @param rdata: to look for (no rdatalen in it)
14103b6c3722Schristos * @param rdata_len: length of rdata
14113b6c3722Schristos * @param result: returns NULL or the ta key looked for.
14123b6c3722Schristos * @return false on malloc failure during search. if true examine result.
14133b6c3722Schristos */
14143b6c3722Schristos static int
find_key(struct trust_anchor * tp,uint16_t t,uint8_t * rdata,size_t rdata_len,struct autr_ta ** result)14153b6c3722Schristos find_key(struct trust_anchor* tp, uint16_t t, uint8_t* rdata, size_t rdata_len,
14163b6c3722Schristos struct autr_ta** result)
14173b6c3722Schristos {
14183b6c3722Schristos struct autr_ta* ta;
14193b6c3722Schristos if(!tp || !rdata) {
14203b6c3722Schristos *result = NULL;
14213b6c3722Schristos return 0;
14223b6c3722Schristos }
14233b6c3722Schristos for(ta=tp->autr->keys; ta; ta=ta->next) {
14243b6c3722Schristos if(ta_compare(ta, t, rdata, rdata_len) == 0) {
14253b6c3722Schristos *result = ta;
14263b6c3722Schristos return 1;
14273b6c3722Schristos }
14283b6c3722Schristos }
14293b6c3722Schristos *result = NULL;
14303b6c3722Schristos return 1;
14313b6c3722Schristos }
14323b6c3722Schristos
14333b6c3722Schristos /** add key and clone RR and tp already locked. rdata without rdlen. */
14343b6c3722Schristos static struct autr_ta*
add_key(struct trust_anchor * tp,uint32_t ttl,uint8_t * rdata,size_t rdata_len)14353b6c3722Schristos add_key(struct trust_anchor* tp, uint32_t ttl, uint8_t* rdata, size_t rdata_len)
14363b6c3722Schristos {
14373b6c3722Schristos struct autr_ta* ta;
14383b6c3722Schristos uint8_t* rr;
14393b6c3722Schristos size_t rr_len, dname_len;
14403b6c3722Schristos uint16_t rrtype = htons(LDNS_RR_TYPE_DNSKEY);
14413b6c3722Schristos uint16_t rrclass = htons(LDNS_RR_CLASS_IN);
14423b6c3722Schristos uint16_t rdlen = htons(rdata_len);
14433b6c3722Schristos dname_len = tp->namelen;
14443b6c3722Schristos ttl = htonl(ttl);
14453b6c3722Schristos rr_len = dname_len + 10 /* type,class,ttl,rdatalen */ + rdata_len;
14463b6c3722Schristos rr = (uint8_t*)malloc(rr_len);
14473b6c3722Schristos if(!rr) return NULL;
14483b6c3722Schristos memmove(rr, tp->name, tp->namelen);
14493b6c3722Schristos memmove(rr+dname_len, &rrtype, 2);
14503b6c3722Schristos memmove(rr+dname_len+2, &rrclass, 2);
14513b6c3722Schristos memmove(rr+dname_len+4, &ttl, 4);
14523b6c3722Schristos memmove(rr+dname_len+8, &rdlen, 2);
14533b6c3722Schristos memmove(rr+dname_len+10, rdata, rdata_len);
14543b6c3722Schristos ta = autr_ta_create(rr, rr_len, dname_len);
14553b6c3722Schristos if(!ta) {
14563b6c3722Schristos /* rr freed in autr_ta_create */
14573b6c3722Schristos return NULL;
14583b6c3722Schristos }
14593b6c3722Schristos /* link in, tp already locked */
14603b6c3722Schristos ta->next = tp->autr->keys;
14613b6c3722Schristos tp->autr->keys = ta;
14623b6c3722Schristos return ta;
14633b6c3722Schristos }
14643b6c3722Schristos
14653b6c3722Schristos /** get TTL from DNSKEY rrset */
14663b6c3722Schristos static time_t
key_ttl(struct ub_packed_rrset_key * k)14673b6c3722Schristos key_ttl(struct ub_packed_rrset_key* k)
14683b6c3722Schristos {
14693b6c3722Schristos struct packed_rrset_data* d = (struct packed_rrset_data*)k->entry.data;
14703b6c3722Schristos return d->ttl;
14713b6c3722Schristos }
14723b6c3722Schristos
14733b6c3722Schristos /** update the time values for the trustpoint */
14743b6c3722Schristos static void
set_tp_times(struct trust_anchor * tp,time_t rrsig_exp_interval,time_t origttl,int * changed)14753b6c3722Schristos set_tp_times(struct trust_anchor* tp, time_t rrsig_exp_interval,
14763b6c3722Schristos time_t origttl, int* changed)
14773b6c3722Schristos {
14783b6c3722Schristos time_t x, qi = tp->autr->query_interval, rt = tp->autr->retry_time;
14793b6c3722Schristos
14803b6c3722Schristos /* x = MIN(15days, ttl/2, expire/2) */
14813b6c3722Schristos x = 15 * 24 * 3600;
14823b6c3722Schristos if(origttl/2 < x)
14833b6c3722Schristos x = origttl/2;
14843b6c3722Schristos if(rrsig_exp_interval/2 < x)
14853b6c3722Schristos x = rrsig_exp_interval/2;
14863b6c3722Schristos /* MAX(1hr, x) */
14873b6c3722Schristos if(!autr_permit_small_holddown) {
14883b6c3722Schristos if(x < 3600)
14893b6c3722Schristos tp->autr->query_interval = 3600;
14903b6c3722Schristos else tp->autr->query_interval = x;
14913b6c3722Schristos } else tp->autr->query_interval = x;
14923b6c3722Schristos
14933b6c3722Schristos /* x= MIN(1day, ttl/10, expire/10) */
14943b6c3722Schristos x = 24 * 3600;
14953b6c3722Schristos if(origttl/10 < x)
14963b6c3722Schristos x = origttl/10;
14973b6c3722Schristos if(rrsig_exp_interval/10 < x)
14983b6c3722Schristos x = rrsig_exp_interval/10;
14993b6c3722Schristos /* MAX(1hr, x) */
15003b6c3722Schristos if(!autr_permit_small_holddown) {
15013b6c3722Schristos if(x < 3600)
15023b6c3722Schristos tp->autr->retry_time = 3600;
15033b6c3722Schristos else tp->autr->retry_time = x;
15043b6c3722Schristos } else tp->autr->retry_time = x;
15053b6c3722Schristos
15063b6c3722Schristos if(qi != tp->autr->query_interval || rt != tp->autr->retry_time) {
15073b6c3722Schristos *changed = 1;
15083b6c3722Schristos verbose(VERB_ALGO, "orig_ttl is %d", (int)origttl);
15093b6c3722Schristos verbose(VERB_ALGO, "rrsig_exp_interval is %d",
15103b6c3722Schristos (int)rrsig_exp_interval);
15113b6c3722Schristos verbose(VERB_ALGO, "query_interval: %d, retry_time: %d",
15123b6c3722Schristos (int)tp->autr->query_interval,
15133b6c3722Schristos (int)tp->autr->retry_time);
15143b6c3722Schristos }
15153b6c3722Schristos }
15163b6c3722Schristos
15173b6c3722Schristos /** init events to zero */
15183b6c3722Schristos static void
init_events(struct trust_anchor * tp)15193b6c3722Schristos init_events(struct trust_anchor* tp)
15203b6c3722Schristos {
15213b6c3722Schristos struct autr_ta* ta;
15223b6c3722Schristos for(ta=tp->autr->keys; ta; ta=ta->next) {
15233b6c3722Schristos ta->fetched = 0;
15243b6c3722Schristos }
15253b6c3722Schristos }
15263b6c3722Schristos
15273b6c3722Schristos /** check for revoked keys without trusting any other information */
15283b6c3722Schristos static void
check_contains_revoked(struct module_env * env,struct val_env * ve,struct trust_anchor * tp,struct ub_packed_rrset_key * dnskey_rrset,int * changed,struct module_qstate * qstate)15293b6c3722Schristos check_contains_revoked(struct module_env* env, struct val_env* ve,
15303b6c3722Schristos struct trust_anchor* tp, struct ub_packed_rrset_key* dnskey_rrset,
15310cd9f4ecSchristos int* changed, struct module_qstate* qstate)
15323b6c3722Schristos {
15333b6c3722Schristos struct packed_rrset_data* dd = (struct packed_rrset_data*)
15343b6c3722Schristos dnskey_rrset->entry.data;
15353b6c3722Schristos size_t i;
15363b6c3722Schristos log_assert(ntohs(dnskey_rrset->rk.type) == LDNS_RR_TYPE_DNSKEY);
15373b6c3722Schristos for(i=0; i<dd->count; i++) {
15383b6c3722Schristos struct autr_ta* ta = NULL;
15393b6c3722Schristos if(!rr_is_dnskey_sep(ntohs(dnskey_rrset->rk.type),
15403b6c3722Schristos dd->rr_data[i]+2, dd->rr_len[i]-2) ||
15413b6c3722Schristos !rr_is_dnskey_revoked(ntohs(dnskey_rrset->rk.type),
15423b6c3722Schristos dd->rr_data[i]+2, dd->rr_len[i]-2))
15433b6c3722Schristos continue; /* not a revoked KSK */
15443b6c3722Schristos if(!find_key(tp, ntohs(dnskey_rrset->rk.type),
15453b6c3722Schristos dd->rr_data[i]+2, dd->rr_len[i]-2, &ta)) {
15463b6c3722Schristos log_err("malloc failure");
15473b6c3722Schristos continue; /* malloc fail in compare*/
15483b6c3722Schristos }
15493b6c3722Schristos if(!ta)
15503b6c3722Schristos continue; /* key not found */
15510cd9f4ecSchristos if(rr_is_selfsigned_revoked(env, ve, dnskey_rrset, i, qstate)) {
15523b6c3722Schristos /* checked if there is an rrsig signed by this key. */
15533b6c3722Schristos /* same keytag, but stored can be revoked already, so
15543b6c3722Schristos * compare keytags, with +0 or +128(REVOKE flag) */
15553b6c3722Schristos log_assert(dnskey_calc_keytag(dnskey_rrset, i)-128 ==
15563b6c3722Schristos sldns_calc_keytag_raw(sldns_wirerr_get_rdata(
15573b6c3722Schristos ta->rr, ta->rr_len, ta->dname_len),
15583b6c3722Schristos sldns_wirerr_get_rdatalen(ta->rr, ta->rr_len,
15593b6c3722Schristos ta->dname_len)) ||
15603b6c3722Schristos dnskey_calc_keytag(dnskey_rrset, i) ==
15613b6c3722Schristos sldns_calc_keytag_raw(sldns_wirerr_get_rdata(
15623b6c3722Schristos ta->rr, ta->rr_len, ta->dname_len),
15633b6c3722Schristos sldns_wirerr_get_rdatalen(ta->rr, ta->rr_len,
15643b6c3722Schristos ta->dname_len))); /* checks conversion*/
15653b6c3722Schristos verbose_key(ta, VERB_ALGO, "is self-signed revoked");
15663b6c3722Schristos if(!ta->revoked)
15673b6c3722Schristos *changed = 1;
15683b6c3722Schristos seen_revoked_trustanchor(ta, 1);
15693b6c3722Schristos do_revoked(env, ta, changed);
15703b6c3722Schristos }
15713b6c3722Schristos }
15723b6c3722Schristos }
15733b6c3722Schristos
15743b6c3722Schristos /** See if a DNSKEY is verified by one of the DSes */
15753b6c3722Schristos static int
key_matches_a_ds(struct module_env * env,struct val_env * ve,struct ub_packed_rrset_key * dnskey_rrset,size_t key_idx,struct ub_packed_rrset_key * ds_rrset)15763b6c3722Schristos key_matches_a_ds(struct module_env* env, struct val_env* ve,
15773b6c3722Schristos struct ub_packed_rrset_key* dnskey_rrset, size_t key_idx,
15783b6c3722Schristos struct ub_packed_rrset_key* ds_rrset)
15793b6c3722Schristos {
15803b6c3722Schristos struct packed_rrset_data* dd = (struct packed_rrset_data*)
15813b6c3722Schristos ds_rrset->entry.data;
15823b6c3722Schristos size_t ds_idx, num = dd->count;
15833b6c3722Schristos int d = val_favorite_ds_algo(ds_rrset);
15843b6c3722Schristos char* reason = "";
15853b6c3722Schristos for(ds_idx=0; ds_idx<num; ds_idx++) {
15863b6c3722Schristos if(!ds_digest_algo_is_supported(ds_rrset, ds_idx) ||
15873b6c3722Schristos !ds_key_algo_is_supported(ds_rrset, ds_idx) ||
15887a540f2bSchristos !dnskey_size_is_supported(dnskey_rrset, key_idx) ||
15893b6c3722Schristos ds_get_digest_algo(ds_rrset, ds_idx) != d)
15903b6c3722Schristos continue;
15913b6c3722Schristos if(ds_get_key_algo(ds_rrset, ds_idx)
15923b6c3722Schristos != dnskey_get_algo(dnskey_rrset, key_idx)
15933b6c3722Schristos || dnskey_calc_keytag(dnskey_rrset, key_idx)
15943b6c3722Schristos != ds_get_keytag(ds_rrset, ds_idx)) {
15953b6c3722Schristos continue;
15963b6c3722Schristos }
15973b6c3722Schristos if(!ds_digest_match_dnskey(env, dnskey_rrset, key_idx,
15983b6c3722Schristos ds_rrset, ds_idx)) {
15993b6c3722Schristos verbose(VERB_ALGO, "DS match attempt failed");
16003b6c3722Schristos continue;
16013b6c3722Schristos }
16020cd9f4ecSchristos /* match of hash is sufficient for bootstrap of trust point */
16030cd9f4ecSchristos (void)reason;
16040cd9f4ecSchristos (void)ve;
16050cd9f4ecSchristos return 1;
16060cd9f4ecSchristos /* no need to check RRSIG, DS hash already matched with source
16073b6c3722Schristos if(dnskey_verify_rrset(env, ve, dnskey_rrset,
16083b6c3722Schristos dnskey_rrset, key_idx, &reason) == sec_status_secure) {
16093b6c3722Schristos return 1;
16103b6c3722Schristos } else {
16113b6c3722Schristos verbose(VERB_ALGO, "DS match failed because the key "
16123b6c3722Schristos "does not verify the keyset: %s", reason);
16133b6c3722Schristos }
16140cd9f4ecSchristos */
16153b6c3722Schristos }
16163b6c3722Schristos return 0;
16173b6c3722Schristos }
16183b6c3722Schristos
16193b6c3722Schristos /** Set update events */
16203b6c3722Schristos static int
update_events(struct module_env * env,struct val_env * ve,struct trust_anchor * tp,struct ub_packed_rrset_key * dnskey_rrset,int * changed)16213b6c3722Schristos update_events(struct module_env* env, struct val_env* ve,
16223b6c3722Schristos struct trust_anchor* tp, struct ub_packed_rrset_key* dnskey_rrset,
16233b6c3722Schristos int* changed)
16243b6c3722Schristos {
16253b6c3722Schristos struct packed_rrset_data* dd = (struct packed_rrset_data*)
16263b6c3722Schristos dnskey_rrset->entry.data;
16273b6c3722Schristos size_t i;
16283b6c3722Schristos log_assert(ntohs(dnskey_rrset->rk.type) == LDNS_RR_TYPE_DNSKEY);
16293b6c3722Schristos init_events(tp);
16303b6c3722Schristos for(i=0; i<dd->count; i++) {
16313b6c3722Schristos struct autr_ta* ta = NULL;
16323b6c3722Schristos if(!rr_is_dnskey_sep(ntohs(dnskey_rrset->rk.type),
16333b6c3722Schristos dd->rr_data[i]+2, dd->rr_len[i]-2))
16343b6c3722Schristos continue;
16353b6c3722Schristos if(rr_is_dnskey_revoked(ntohs(dnskey_rrset->rk.type),
16363b6c3722Schristos dd->rr_data[i]+2, dd->rr_len[i]-2)) {
16373b6c3722Schristos /* self-signed revoked keys already detected before,
16383b6c3722Schristos * other revoked keys are not 'added' again */
16393b6c3722Schristos continue;
16403b6c3722Schristos }
16413b6c3722Schristos /* is a key of this type supported?. Note rr_list and
16423b6c3722Schristos * packed_rrset are in the same order. */
16437a540f2bSchristos if(!dnskey_algo_is_supported(dnskey_rrset, i) ||
16447a540f2bSchristos !dnskey_size_is_supported(dnskey_rrset, i)) {
16453b6c3722Schristos /* skip unknown algorithm key, it is useless to us */
16463b6c3722Schristos log_nametypeclass(VERB_DETAIL, "trust point has "
16473b6c3722Schristos "unsupported algorithm at",
16483b6c3722Schristos tp->name, LDNS_RR_TYPE_DNSKEY, tp->dclass);
16493b6c3722Schristos continue;
16503b6c3722Schristos }
16513b6c3722Schristos
16523b6c3722Schristos /* is it new? if revocation bit set, find the unrevoked key */
16533b6c3722Schristos if(!find_key(tp, ntohs(dnskey_rrset->rk.type),
16543b6c3722Schristos dd->rr_data[i]+2, dd->rr_len[i]-2, &ta)) {
16553b6c3722Schristos return 0;
16563b6c3722Schristos }
16573b6c3722Schristos if(!ta) {
16583b6c3722Schristos ta = add_key(tp, (uint32_t)dd->rr_ttl[i],
16593b6c3722Schristos dd->rr_data[i]+2, dd->rr_len[i]-2);
16603b6c3722Schristos *changed = 1;
16613b6c3722Schristos /* first time seen, do we have DSes? if match: VALID */
16623b6c3722Schristos if(ta && tp->ds_rrset && key_matches_a_ds(env, ve,
16633b6c3722Schristos dnskey_rrset, i, tp->ds_rrset)) {
16643b6c3722Schristos verbose_key(ta, VERB_ALGO, "verified by DS");
16653b6c3722Schristos ta->s = AUTR_STATE_VALID;
16663b6c3722Schristos }
16673b6c3722Schristos }
16683b6c3722Schristos if(!ta) {
16693b6c3722Schristos return 0;
16703b6c3722Schristos }
16713b6c3722Schristos seen_trustanchor(ta, 1);
16723b6c3722Schristos verbose_key(ta, VERB_ALGO, "in DNS response");
16733b6c3722Schristos }
16743b6c3722Schristos set_tp_times(tp, min_expiry(env, dd), key_ttl(dnskey_rrset), changed);
16753b6c3722Schristos return 1;
16763b6c3722Schristos }
16773b6c3722Schristos
16783b6c3722Schristos /**
16793b6c3722Schristos * Check if the holddown time has already exceeded
16803b6c3722Schristos * setting: add-holddown: add holddown timer
16813b6c3722Schristos * setting: del-holddown: del holddown timer
16823b6c3722Schristos * @param env: environment with current time
16833b6c3722Schristos * @param ta: trust anchor to check for.
16843b6c3722Schristos * @param holddown: the timer value
16853b6c3722Schristos * @return number of seconds the holddown has passed.
16863b6c3722Schristos */
16873b6c3722Schristos static time_t
check_holddown(struct module_env * env,struct autr_ta * ta,unsigned int holddown)16883b6c3722Schristos check_holddown(struct module_env* env, struct autr_ta* ta,
16893b6c3722Schristos unsigned int holddown)
16903b6c3722Schristos {
16913b6c3722Schristos time_t elapsed;
16923b6c3722Schristos if(*env->now < ta->last_change) {
16933b6c3722Schristos log_warn("time goes backwards. delaying key holddown");
16943b6c3722Schristos return 0;
16953b6c3722Schristos }
16963b6c3722Schristos elapsed = *env->now - ta->last_change;
16973b6c3722Schristos if (elapsed > (time_t)holddown) {
16983b6c3722Schristos return elapsed-(time_t)holddown;
16993b6c3722Schristos }
17003b6c3722Schristos verbose_key(ta, VERB_ALGO, "holddown time " ARG_LL "d seconds to go",
17013b6c3722Schristos (long long) ((time_t)holddown-elapsed));
17023b6c3722Schristos return 0;
17033b6c3722Schristos }
17043b6c3722Schristos
17053b6c3722Schristos
17063b6c3722Schristos /** Set last_change to now */
17073b6c3722Schristos static void
reset_holddown(struct module_env * env,struct autr_ta * ta,int * changed)17083b6c3722Schristos reset_holddown(struct module_env* env, struct autr_ta* ta, int* changed)
17093b6c3722Schristos {
17103b6c3722Schristos ta->last_change = *env->now;
17113b6c3722Schristos *changed = 1;
17123b6c3722Schristos }
17133b6c3722Schristos
17143b6c3722Schristos /** Set the state for this trust anchor */
17153b6c3722Schristos static void
set_trustanchor_state(struct module_env * env,struct autr_ta * ta,int * changed,autr_state_type s)17163b6c3722Schristos set_trustanchor_state(struct module_env* env, struct autr_ta* ta, int* changed,
17170cd9f4ecSchristos autr_state_type s)
17183b6c3722Schristos {
17193b6c3722Schristos verbose_key(ta, VERB_ALGO, "update: %s to %s",
17203b6c3722Schristos trustanchor_state2str(ta->s), trustanchor_state2str(s));
17213b6c3722Schristos ta->s = s;
17223b6c3722Schristos reset_holddown(env, ta, changed);
17233b6c3722Schristos }
17243b6c3722Schristos
17253b6c3722Schristos
17263b6c3722Schristos /** Event: NewKey */
17273b6c3722Schristos static void
do_newkey(struct module_env * env,struct autr_ta * anchor,int * c)17283b6c3722Schristos do_newkey(struct module_env* env, struct autr_ta* anchor, int* c)
17293b6c3722Schristos {
17303b6c3722Schristos if (anchor->s == AUTR_STATE_START)
17313b6c3722Schristos set_trustanchor_state(env, anchor, c, AUTR_STATE_ADDPEND);
17323b6c3722Schristos }
17333b6c3722Schristos
17343b6c3722Schristos /** Event: AddTime */
17353b6c3722Schristos static void
do_addtime(struct module_env * env,struct autr_ta * anchor,int * c)17363b6c3722Schristos do_addtime(struct module_env* env, struct autr_ta* anchor, int* c)
17373b6c3722Schristos {
17383b6c3722Schristos /* This not according to RFC, this is 30 days, but the RFC demands
17393b6c3722Schristos * MAX(30days, TTL expire time of first DNSKEY set with this key),
17403b6c3722Schristos * The value may be too small if a very large TTL was used. */
17413b6c3722Schristos time_t exceeded = check_holddown(env, anchor, env->cfg->add_holddown);
17423b6c3722Schristos if (exceeded && anchor->s == AUTR_STATE_ADDPEND) {
17433b6c3722Schristos verbose_key(anchor, VERB_ALGO, "add-holddown time exceeded "
17443b6c3722Schristos ARG_LL "d seconds ago, and pending-count %d",
17453b6c3722Schristos (long long)exceeded, anchor->pending_count);
17463b6c3722Schristos if(anchor->pending_count >= MIN_PENDINGCOUNT) {
17473b6c3722Schristos set_trustanchor_state(env, anchor, c, AUTR_STATE_VALID);
17483b6c3722Schristos anchor->pending_count = 0;
17493b6c3722Schristos return;
17503b6c3722Schristos }
17513b6c3722Schristos verbose_key(anchor, VERB_ALGO, "add-holddown time sanity check "
17523b6c3722Schristos "failed (pending count: %d)", anchor->pending_count);
17533b6c3722Schristos }
17543b6c3722Schristos }
17553b6c3722Schristos
17563b6c3722Schristos /** Event: RemTime */
17573b6c3722Schristos static void
do_remtime(struct module_env * env,struct autr_ta * anchor,int * c)17583b6c3722Schristos do_remtime(struct module_env* env, struct autr_ta* anchor, int* c)
17593b6c3722Schristos {
17603b6c3722Schristos time_t exceeded = check_holddown(env, anchor, env->cfg->del_holddown);
17613b6c3722Schristos if(exceeded && anchor->s == AUTR_STATE_REVOKED) {
17623b6c3722Schristos verbose_key(anchor, VERB_ALGO, "del-holddown time exceeded "
17633b6c3722Schristos ARG_LL "d seconds ago", (long long)exceeded);
17643b6c3722Schristos set_trustanchor_state(env, anchor, c, AUTR_STATE_REMOVED);
17653b6c3722Schristos }
17663b6c3722Schristos }
17673b6c3722Schristos
17683b6c3722Schristos /** Event: KeyRem */
17693b6c3722Schristos static void
do_keyrem(struct module_env * env,struct autr_ta * anchor,int * c)17703b6c3722Schristos do_keyrem(struct module_env* env, struct autr_ta* anchor, int* c)
17713b6c3722Schristos {
17723b6c3722Schristos if(anchor->s == AUTR_STATE_ADDPEND) {
17733b6c3722Schristos set_trustanchor_state(env, anchor, c, AUTR_STATE_START);
17743b6c3722Schristos anchor->pending_count = 0;
17753b6c3722Schristos } else if(anchor->s == AUTR_STATE_VALID)
17763b6c3722Schristos set_trustanchor_state(env, anchor, c, AUTR_STATE_MISSING);
17773b6c3722Schristos }
17783b6c3722Schristos
17793b6c3722Schristos /** Event: KeyPres */
17803b6c3722Schristos static void
do_keypres(struct module_env * env,struct autr_ta * anchor,int * c)17813b6c3722Schristos do_keypres(struct module_env* env, struct autr_ta* anchor, int* c)
17823b6c3722Schristos {
17833b6c3722Schristos if(anchor->s == AUTR_STATE_MISSING)
17843b6c3722Schristos set_trustanchor_state(env, anchor, c, AUTR_STATE_VALID);
17853b6c3722Schristos }
17863b6c3722Schristos
17873b6c3722Schristos /* Event: Revoked */
17883b6c3722Schristos static void
do_revoked(struct module_env * env,struct autr_ta * anchor,int * c)17893b6c3722Schristos do_revoked(struct module_env* env, struct autr_ta* anchor, int* c)
17903b6c3722Schristos {
17913b6c3722Schristos if(anchor->s == AUTR_STATE_VALID || anchor->s == AUTR_STATE_MISSING) {
17923b6c3722Schristos set_trustanchor_state(env, anchor, c, AUTR_STATE_REVOKED);
17933b6c3722Schristos verbose_key(anchor, VERB_ALGO, "old id, prior to revocation");
17943b6c3722Schristos revoke_dnskey(anchor, 0);
17953b6c3722Schristos verbose_key(anchor, VERB_ALGO, "new id, after revocation");
17963b6c3722Schristos }
17973b6c3722Schristos }
17983b6c3722Schristos
17993b6c3722Schristos /** Do statestable transition matrix for anchor */
18003b6c3722Schristos static void
anchor_state_update(struct module_env * env,struct autr_ta * anchor,int * c)18013b6c3722Schristos anchor_state_update(struct module_env* env, struct autr_ta* anchor, int* c)
18023b6c3722Schristos {
18033b6c3722Schristos log_assert(anchor);
18043b6c3722Schristos switch(anchor->s) {
18053b6c3722Schristos /* START */
18063b6c3722Schristos case AUTR_STATE_START:
18073b6c3722Schristos /* NewKey: ADDPEND */
18083b6c3722Schristos if (anchor->fetched)
18093b6c3722Schristos do_newkey(env, anchor, c);
18103b6c3722Schristos break;
18113b6c3722Schristos /* ADDPEND */
18123b6c3722Schristos case AUTR_STATE_ADDPEND:
18133b6c3722Schristos /* KeyRem: START */
18143b6c3722Schristos if (!anchor->fetched)
18153b6c3722Schristos do_keyrem(env, anchor, c);
18163b6c3722Schristos /* AddTime: VALID */
18173b6c3722Schristos else do_addtime(env, anchor, c);
18183b6c3722Schristos break;
18193b6c3722Schristos /* VALID */
18203b6c3722Schristos case AUTR_STATE_VALID:
18213b6c3722Schristos /* RevBit: REVOKED */
18223b6c3722Schristos if (anchor->revoked)
18233b6c3722Schristos do_revoked(env, anchor, c);
18243b6c3722Schristos /* KeyRem: MISSING */
18253b6c3722Schristos else if (!anchor->fetched)
18263b6c3722Schristos do_keyrem(env, anchor, c);
18273b6c3722Schristos else if(!anchor->last_change) {
18283b6c3722Schristos verbose_key(anchor, VERB_ALGO, "first seen");
18293b6c3722Schristos reset_holddown(env, anchor, c);
18303b6c3722Schristos }
18313b6c3722Schristos break;
18323b6c3722Schristos /* MISSING */
18333b6c3722Schristos case AUTR_STATE_MISSING:
18343b6c3722Schristos /* RevBit: REVOKED */
18353b6c3722Schristos if (anchor->revoked)
18363b6c3722Schristos do_revoked(env, anchor, c);
18373b6c3722Schristos /* KeyPres */
18383b6c3722Schristos else if (anchor->fetched)
18393b6c3722Schristos do_keypres(env, anchor, c);
18403b6c3722Schristos break;
18413b6c3722Schristos /* REVOKED */
18423b6c3722Schristos case AUTR_STATE_REVOKED:
18433b6c3722Schristos if (anchor->fetched)
18443b6c3722Schristos reset_holddown(env, anchor, c);
18453b6c3722Schristos /* RemTime: REMOVED */
18463b6c3722Schristos else do_remtime(env, anchor, c);
18473b6c3722Schristos break;
18483b6c3722Schristos /* REMOVED */
18493b6c3722Schristos case AUTR_STATE_REMOVED:
18503b6c3722Schristos default:
18513b6c3722Schristos break;
18523b6c3722Schristos }
18533b6c3722Schristos }
18543b6c3722Schristos
18553b6c3722Schristos /** if ZSK init then trust KSKs */
18563b6c3722Schristos static int
init_zsk_to_ksk(struct module_env * env,struct trust_anchor * tp,int * changed)18573b6c3722Schristos init_zsk_to_ksk(struct module_env* env, struct trust_anchor* tp, int* changed)
18583b6c3722Schristos {
18593b6c3722Schristos /* search for VALID ZSKs */
18603b6c3722Schristos struct autr_ta* anchor;
18613b6c3722Schristos int validzsk = 0;
18623b6c3722Schristos int validksk = 0;
18633b6c3722Schristos for(anchor = tp->autr->keys; anchor; anchor = anchor->next) {
18643b6c3722Schristos /* last_change test makes sure it was manually configured */
18653b6c3722Schristos if(sldns_wirerr_get_type(anchor->rr, anchor->rr_len,
18663b6c3722Schristos anchor->dname_len) == LDNS_RR_TYPE_DNSKEY &&
18673b6c3722Schristos anchor->last_change == 0 &&
18683b6c3722Schristos !ta_is_dnskey_sep(anchor) &&
18693b6c3722Schristos anchor->s == AUTR_STATE_VALID)
18703b6c3722Schristos validzsk++;
18713b6c3722Schristos }
18723b6c3722Schristos if(validzsk == 0)
18733b6c3722Schristos return 0;
18743b6c3722Schristos for(anchor = tp->autr->keys; anchor; anchor = anchor->next) {
18753b6c3722Schristos if (ta_is_dnskey_sep(anchor) &&
18763b6c3722Schristos anchor->s == AUTR_STATE_ADDPEND) {
18773b6c3722Schristos verbose_key(anchor, VERB_ALGO, "trust KSK from "
18783b6c3722Schristos "ZSK(config)");
18793b6c3722Schristos set_trustanchor_state(env, anchor, changed,
18803b6c3722Schristos AUTR_STATE_VALID);
18813b6c3722Schristos validksk++;
18823b6c3722Schristos }
18833b6c3722Schristos }
18843b6c3722Schristos return validksk;
18853b6c3722Schristos }
18863b6c3722Schristos
18873b6c3722Schristos /** Remove missing trustanchors so the list does not grow forever */
18883b6c3722Schristos static void
remove_missing_trustanchors(struct module_env * env,struct trust_anchor * tp,int * changed)18893b6c3722Schristos remove_missing_trustanchors(struct module_env* env, struct trust_anchor* tp,
18903b6c3722Schristos int* changed)
18913b6c3722Schristos {
18923b6c3722Schristos struct autr_ta* anchor;
18933b6c3722Schristos time_t exceeded;
18943b6c3722Schristos int valid = 0;
18953b6c3722Schristos /* see if we have anchors that are valid */
18963b6c3722Schristos for(anchor = tp->autr->keys; anchor; anchor = anchor->next) {
18973b6c3722Schristos /* Only do KSKs */
18983b6c3722Schristos if (!ta_is_dnskey_sep(anchor))
18993b6c3722Schristos continue;
19003b6c3722Schristos if (anchor->s == AUTR_STATE_VALID)
19013b6c3722Schristos valid++;
19023b6c3722Schristos }
19033b6c3722Schristos /* if there are no SEP Valid anchors, see if we started out with
19043b6c3722Schristos * a ZSK (last-change=0) anchor, which is VALID and there are KSKs
19053b6c3722Schristos * now that can be made valid. Do this immediately because there
19063b6c3722Schristos * is no guarantee that the ZSKs get announced long enough. Usually
19073b6c3722Schristos * this is immediately after init with a ZSK trusted, unless the domain
19083b6c3722Schristos * was not advertising any KSKs at all. In which case we perfectly
19093b6c3722Schristos * track the zero number of KSKs. */
19103b6c3722Schristos if(valid == 0) {
19113b6c3722Schristos valid = init_zsk_to_ksk(env, tp, changed);
19123b6c3722Schristos if(valid == 0)
19133b6c3722Schristos return;
19143b6c3722Schristos }
19153b6c3722Schristos
19163b6c3722Schristos for(anchor = tp->autr->keys; anchor; anchor = anchor->next) {
19173b6c3722Schristos /* ignore ZSKs if newly added */
19183b6c3722Schristos if(anchor->s == AUTR_STATE_START)
19193b6c3722Schristos continue;
19203b6c3722Schristos /* remove ZSKs if a KSK is present */
19213b6c3722Schristos if (!ta_is_dnskey_sep(anchor)) {
19223b6c3722Schristos if(valid > 0) {
19233b6c3722Schristos verbose_key(anchor, VERB_ALGO, "remove ZSK "
19243b6c3722Schristos "[%d key(s) VALID]", valid);
19253b6c3722Schristos set_trustanchor_state(env, anchor, changed,
19263b6c3722Schristos AUTR_STATE_REMOVED);
19273b6c3722Schristos }
19283b6c3722Schristos continue;
19293b6c3722Schristos }
19303b6c3722Schristos /* Only do MISSING keys */
19313b6c3722Schristos if (anchor->s != AUTR_STATE_MISSING)
19323b6c3722Schristos continue;
19333b6c3722Schristos if(env->cfg->keep_missing == 0)
19343b6c3722Schristos continue; /* keep forever */
19353b6c3722Schristos
19363b6c3722Schristos exceeded = check_holddown(env, anchor, env->cfg->keep_missing);
19373b6c3722Schristos /* If keep_missing has exceeded and we still have more than
19383b6c3722Schristos * one valid KSK: remove missing trust anchor */
19393b6c3722Schristos if (exceeded && valid > 0) {
19403b6c3722Schristos verbose_key(anchor, VERB_ALGO, "keep-missing time "
19413b6c3722Schristos "exceeded " ARG_LL "d seconds ago, [%d key(s) VALID]",
19423b6c3722Schristos (long long)exceeded, valid);
19433b6c3722Schristos set_trustanchor_state(env, anchor, changed,
19443b6c3722Schristos AUTR_STATE_REMOVED);
19453b6c3722Schristos }
19463b6c3722Schristos }
19473b6c3722Schristos }
19483b6c3722Schristos
19493b6c3722Schristos /** Do the statetable from RFC5011 transition matrix */
19503b6c3722Schristos static int
do_statetable(struct module_env * env,struct trust_anchor * tp,int * changed)19513b6c3722Schristos do_statetable(struct module_env* env, struct trust_anchor* tp, int* changed)
19523b6c3722Schristos {
19533b6c3722Schristos struct autr_ta* anchor;
19543b6c3722Schristos for(anchor = tp->autr->keys; anchor; anchor = anchor->next) {
19553b6c3722Schristos /* Only do KSKs */
19563b6c3722Schristos if(!ta_is_dnskey_sep(anchor))
19573b6c3722Schristos continue;
19583b6c3722Schristos anchor_state_update(env, anchor, changed);
19593b6c3722Schristos }
19603b6c3722Schristos remove_missing_trustanchors(env, tp, changed);
19613b6c3722Schristos return 1;
19623b6c3722Schristos }
19633b6c3722Schristos
19643b6c3722Schristos /** See if time alone makes ADDPEND to VALID transition */
19653b6c3722Schristos static void
autr_holddown_exceed(struct module_env * env,struct trust_anchor * tp,int * c)19663b6c3722Schristos autr_holddown_exceed(struct module_env* env, struct trust_anchor* tp, int* c)
19673b6c3722Schristos {
19683b6c3722Schristos struct autr_ta* anchor;
19693b6c3722Schristos for(anchor = tp->autr->keys; anchor; anchor = anchor->next) {
19703b6c3722Schristos if(ta_is_dnskey_sep(anchor) &&
19713b6c3722Schristos anchor->s == AUTR_STATE_ADDPEND)
19723b6c3722Schristos do_addtime(env, anchor, c);
19733b6c3722Schristos }
19743b6c3722Schristos }
19753b6c3722Schristos
19763b6c3722Schristos /** cleanup key list */
19773b6c3722Schristos static void
autr_cleanup_keys(struct trust_anchor * tp)19783b6c3722Schristos autr_cleanup_keys(struct trust_anchor* tp)
19793b6c3722Schristos {
19803b6c3722Schristos struct autr_ta* p, **prevp;
19813b6c3722Schristos prevp = &tp->autr->keys;
19823b6c3722Schristos p = tp->autr->keys;
19833b6c3722Schristos while(p) {
19843b6c3722Schristos /* do we want to remove this key? */
19853b6c3722Schristos if(p->s == AUTR_STATE_START || p->s == AUTR_STATE_REMOVED ||
19863b6c3722Schristos sldns_wirerr_get_type(p->rr, p->rr_len, p->dname_len)
19873b6c3722Schristos != LDNS_RR_TYPE_DNSKEY) {
19883b6c3722Schristos struct autr_ta* np = p->next;
19893b6c3722Schristos /* remove */
19903b6c3722Schristos free(p->rr);
19913b6c3722Schristos free(p);
19923b6c3722Schristos /* snip and go to next item */
19933b6c3722Schristos *prevp = np;
19943b6c3722Schristos p = np;
19953b6c3722Schristos continue;
19963b6c3722Schristos }
19973b6c3722Schristos /* remove pending counts if no longer pending */
19983b6c3722Schristos if(p->s != AUTR_STATE_ADDPEND)
19993b6c3722Schristos p->pending_count = 0;
20003b6c3722Schristos prevp = &p->next;
20013b6c3722Schristos p = p->next;
20023b6c3722Schristos }
20033b6c3722Schristos }
20043b6c3722Schristos
20053b6c3722Schristos /** calculate next probe time */
20063b6c3722Schristos static time_t
calc_next_probe(struct module_env * env,time_t wait)20073b6c3722Schristos calc_next_probe(struct module_env* env, time_t wait)
20083b6c3722Schristos {
20093b6c3722Schristos /* make it random, 90-100% */
20103b6c3722Schristos time_t rnd, rest;
20113b6c3722Schristos if(!autr_permit_small_holddown) {
20123b6c3722Schristos if(wait < 3600)
20133b6c3722Schristos wait = 3600;
20143b6c3722Schristos } else {
20153b6c3722Schristos if(wait == 0) wait = 1;
20163b6c3722Schristos }
20173b6c3722Schristos rnd = wait/10;
20183b6c3722Schristos rest = wait-rnd;
20193b6c3722Schristos rnd = (time_t)ub_random_max(env->rnd, (long int)rnd);
20203b6c3722Schristos return (time_t)(*env->now + rest + rnd);
20213b6c3722Schristos }
20223b6c3722Schristos
20233b6c3722Schristos /** what is first probe time (anchors must be locked) */
20243b6c3722Schristos static time_t
wait_probe_time(struct val_anchors * anchors)20253b6c3722Schristos wait_probe_time(struct val_anchors* anchors)
20263b6c3722Schristos {
20270cd9f4ecSchristos rbnode_type* t = rbtree_first(&anchors->autr->probe);
20283b6c3722Schristos if(t != RBTREE_NULL)
20293b6c3722Schristos return ((struct trust_anchor*)t->key)->autr->next_probe_time;
20303b6c3722Schristos return 0;
20313b6c3722Schristos }
20323b6c3722Schristos
20333b6c3722Schristos /** reset worker timer */
20343b6c3722Schristos static void
reset_worker_timer(struct module_env * env)20353b6c3722Schristos reset_worker_timer(struct module_env* env)
20363b6c3722Schristos {
20373b6c3722Schristos struct timeval tv;
20383b6c3722Schristos #ifndef S_SPLINT_S
20393b6c3722Schristos time_t next = (time_t)wait_probe_time(env->anchors);
20403b6c3722Schristos /* in case this is libunbound, no timer */
20413b6c3722Schristos if(!env->probe_timer)
20423b6c3722Schristos return;
20433b6c3722Schristos if(next > *env->now)
20443b6c3722Schristos tv.tv_sec = (time_t)(next - *env->now);
20453b6c3722Schristos else tv.tv_sec = 0;
20463b6c3722Schristos #endif
20473b6c3722Schristos tv.tv_usec = 0;
20483b6c3722Schristos comm_timer_set(env->probe_timer, &tv);
20493b6c3722Schristos verbose(VERB_ALGO, "scheduled next probe in " ARG_LL "d sec", (long long)tv.tv_sec);
20503b6c3722Schristos }
20513b6c3722Schristos
20523b6c3722Schristos /** set next probe for trust anchor */
20533b6c3722Schristos static int
set_next_probe(struct module_env * env,struct trust_anchor * tp,struct ub_packed_rrset_key * dnskey_rrset)20543b6c3722Schristos set_next_probe(struct module_env* env, struct trust_anchor* tp,
20553b6c3722Schristos struct ub_packed_rrset_key* dnskey_rrset)
20563b6c3722Schristos {
20573b6c3722Schristos struct trust_anchor key, *tp2;
20583b6c3722Schristos time_t mold, mnew;
20593b6c3722Schristos /* use memory allocated in rrset for temporary name storage */
20603b6c3722Schristos key.node.key = &key;
20613b6c3722Schristos key.name = dnskey_rrset->rk.dname;
20623b6c3722Schristos key.namelen = dnskey_rrset->rk.dname_len;
20633b6c3722Schristos key.namelabs = dname_count_labels(key.name);
20643b6c3722Schristos key.dclass = tp->dclass;
20653b6c3722Schristos lock_basic_unlock(&tp->lock);
20663b6c3722Schristos
20673b6c3722Schristos /* fetch tp again and lock anchors, so that we can modify the trees */
20683b6c3722Schristos lock_basic_lock(&env->anchors->lock);
20693b6c3722Schristos tp2 = (struct trust_anchor*)rbtree_search(env->anchors->tree, &key);
20703b6c3722Schristos if(!tp2) {
20713b6c3722Schristos verbose(VERB_ALGO, "trustpoint was deleted in set_next_probe");
20723b6c3722Schristos lock_basic_unlock(&env->anchors->lock);
20733b6c3722Schristos return 0;
20743b6c3722Schristos }
20753b6c3722Schristos log_assert(tp == tp2);
20763b6c3722Schristos lock_basic_lock(&tp->lock);
20773b6c3722Schristos
20783b6c3722Schristos /* schedule */
20793b6c3722Schristos mold = wait_probe_time(env->anchors);
20803b6c3722Schristos (void)rbtree_delete(&env->anchors->autr->probe, tp);
20813b6c3722Schristos tp->autr->next_probe_time = calc_next_probe(env,
20823b6c3722Schristos tp->autr->query_interval);
20833b6c3722Schristos (void)rbtree_insert(&env->anchors->autr->probe, &tp->autr->pnode);
20843b6c3722Schristos mnew = wait_probe_time(env->anchors);
20853b6c3722Schristos
20863b6c3722Schristos lock_basic_unlock(&env->anchors->lock);
20873b6c3722Schristos verbose(VERB_ALGO, "next probe set in %d seconds",
20883b6c3722Schristos (int)tp->autr->next_probe_time - (int)*env->now);
20893b6c3722Schristos if(mold != mnew) {
20903b6c3722Schristos reset_worker_timer(env);
20913b6c3722Schristos }
20923b6c3722Schristos return 1;
20933b6c3722Schristos }
20943b6c3722Schristos
20953b6c3722Schristos /** Revoke and Delete a trust point */
20963b6c3722Schristos static void
autr_tp_remove(struct module_env * env,struct trust_anchor * tp,struct ub_packed_rrset_key * dnskey_rrset)20973b6c3722Schristos autr_tp_remove(struct module_env* env, struct trust_anchor* tp,
20983b6c3722Schristos struct ub_packed_rrset_key* dnskey_rrset)
20993b6c3722Schristos {
21003b6c3722Schristos struct trust_anchor* del_tp;
21013b6c3722Schristos struct trust_anchor key;
21023b6c3722Schristos struct autr_point_data pd;
21033b6c3722Schristos time_t mold, mnew;
21043b6c3722Schristos
21053b6c3722Schristos log_nametypeclass(VERB_OPS, "trust point was revoked",
21063b6c3722Schristos tp->name, LDNS_RR_TYPE_DNSKEY, tp->dclass);
21073b6c3722Schristos tp->autr->revoked = 1;
21083b6c3722Schristos
21093b6c3722Schristos /* use space allocated for dnskey_rrset to save name of anchor */
21103b6c3722Schristos memset(&key, 0, sizeof(key));
21113b6c3722Schristos memset(&pd, 0, sizeof(pd));
21123b6c3722Schristos key.autr = &pd;
21133b6c3722Schristos key.node.key = &key;
21143b6c3722Schristos pd.pnode.key = &key;
21153b6c3722Schristos pd.next_probe_time = tp->autr->next_probe_time;
21163b6c3722Schristos key.name = dnskey_rrset->rk.dname;
21173b6c3722Schristos key.namelen = tp->namelen;
21183b6c3722Schristos key.namelabs = tp->namelabs;
21193b6c3722Schristos key.dclass = tp->dclass;
21203b6c3722Schristos
21213b6c3722Schristos /* unlock */
21223b6c3722Schristos lock_basic_unlock(&tp->lock);
21233b6c3722Schristos
21243b6c3722Schristos /* take from tree. It could be deleted by someone else,hence (void). */
21253b6c3722Schristos lock_basic_lock(&env->anchors->lock);
21263b6c3722Schristos del_tp = (struct trust_anchor*)rbtree_delete(env->anchors->tree, &key);
21273b6c3722Schristos mold = wait_probe_time(env->anchors);
21283b6c3722Schristos (void)rbtree_delete(&env->anchors->autr->probe, &key);
21293b6c3722Schristos mnew = wait_probe_time(env->anchors);
21303b6c3722Schristos anchors_init_parents_locked(env->anchors);
21313b6c3722Schristos lock_basic_unlock(&env->anchors->lock);
21323b6c3722Schristos
21333b6c3722Schristos /* if !del_tp then the trust point is no longer present in the tree,
21343b6c3722Schristos * it was deleted by someone else, who will write the zonefile and
21353b6c3722Schristos * clean up the structure */
21363b6c3722Schristos if(del_tp) {
21373b6c3722Schristos /* save on disk */
21383b6c3722Schristos del_tp->autr->next_probe_time = 0; /* no more probing for it */
21393b6c3722Schristos autr_write_file(env, del_tp);
21403b6c3722Schristos
21413b6c3722Schristos /* delete */
21423b6c3722Schristos autr_point_delete(del_tp);
21433b6c3722Schristos }
21443b6c3722Schristos if(mold != mnew) {
21453b6c3722Schristos reset_worker_timer(env);
21463b6c3722Schristos }
21473b6c3722Schristos }
21483b6c3722Schristos
autr_process_prime(struct module_env * env,struct val_env * ve,struct trust_anchor * tp,struct ub_packed_rrset_key * dnskey_rrset,struct module_qstate * qstate)21493b6c3722Schristos int autr_process_prime(struct module_env* env, struct val_env* ve,
21500cd9f4ecSchristos struct trust_anchor* tp, struct ub_packed_rrset_key* dnskey_rrset,
21510cd9f4ecSchristos struct module_qstate* qstate)
21523b6c3722Schristos {
21533b6c3722Schristos int changed = 0;
21543b6c3722Schristos log_assert(tp && tp->autr);
21553b6c3722Schristos /* autotrust update trust anchors */
21563b6c3722Schristos /* the tp is locked, and stays locked unless it is deleted */
21573b6c3722Schristos
21583b6c3722Schristos /* we could just catch the anchor here while another thread
21593b6c3722Schristos * is busy deleting it. Just unlock and let the other do its job */
21603b6c3722Schristos if(tp->autr->revoked) {
21613b6c3722Schristos log_nametypeclass(VERB_ALGO, "autotrust not processed, "
21623b6c3722Schristos "trust point revoked", tp->name,
21633b6c3722Schristos LDNS_RR_TYPE_DNSKEY, tp->dclass);
21643b6c3722Schristos lock_basic_unlock(&tp->lock);
21653b6c3722Schristos return 0; /* it is revoked */
21663b6c3722Schristos }
21673b6c3722Schristos
21683b6c3722Schristos /* query_dnskeys(): */
21693b6c3722Schristos tp->autr->last_queried = *env->now;
21703b6c3722Schristos
21713b6c3722Schristos log_nametypeclass(VERB_ALGO, "autotrust process for",
21723b6c3722Schristos tp->name, LDNS_RR_TYPE_DNSKEY, tp->dclass);
21733b6c3722Schristos /* see if time alone makes some keys valid */
21743b6c3722Schristos autr_holddown_exceed(env, tp, &changed);
21753b6c3722Schristos if(changed) {
21763b6c3722Schristos verbose(VERB_ALGO, "autotrust: morekeys, reassemble");
21773b6c3722Schristos if(!autr_assemble(tp)) {
21783b6c3722Schristos log_err("malloc failure assembling autotrust keys");
21793b6c3722Schristos return 1; /* unchanged */
21803b6c3722Schristos }
21813b6c3722Schristos }
21823b6c3722Schristos /* did we get any data? */
21833b6c3722Schristos if(!dnskey_rrset) {
21843b6c3722Schristos verbose(VERB_ALGO, "autotrust: no dnskey rrset");
21853b6c3722Schristos /* no update of query_failed, because then we would have
21863b6c3722Schristos * to write to disk. But we cannot because we maybe are
21870cd9f4ecSchristos * still 'initializing' with DS records, that we cannot write
21883b6c3722Schristos * in the full format (which only contains KSKs). */
21893b6c3722Schristos return 1; /* trust point exists */
21903b6c3722Schristos }
21913b6c3722Schristos /* check for revoked keys to remove immediately */
21920cd9f4ecSchristos check_contains_revoked(env, ve, tp, dnskey_rrset, &changed, qstate);
21933b6c3722Schristos if(changed) {
21943b6c3722Schristos verbose(VERB_ALGO, "autotrust: revokedkeys, reassemble");
21953b6c3722Schristos if(!autr_assemble(tp)) {
21963b6c3722Schristos log_err("malloc failure assembling autotrust keys");
21973b6c3722Schristos return 1; /* unchanged */
21983b6c3722Schristos }
21993b6c3722Schristos if(!tp->ds_rrset && !tp->dnskey_rrset) {
22003b6c3722Schristos /* no more keys, all are revoked */
22013b6c3722Schristos /* this is a success for this probe attempt */
22023b6c3722Schristos tp->autr->last_success = *env->now;
22033b6c3722Schristos autr_tp_remove(env, tp, dnskey_rrset);
22043b6c3722Schristos return 0; /* trust point removed */
22053b6c3722Schristos }
22063b6c3722Schristos }
22073b6c3722Schristos /* verify the dnskey rrset and see if it is valid. */
22080cd9f4ecSchristos if(!verify_dnskey(env, ve, tp, dnskey_rrset, qstate)) {
22093b6c3722Schristos verbose(VERB_ALGO, "autotrust: dnskey did not verify.");
22103b6c3722Schristos /* only increase failure count if this is not the first prime,
22113b6c3722Schristos * this means there was a previous successful probe */
22123b6c3722Schristos if(tp->autr->last_success) {
22133b6c3722Schristos tp->autr->query_failed += 1;
22143b6c3722Schristos autr_write_file(env, tp);
22153b6c3722Schristos }
22163b6c3722Schristos return 1; /* trust point exists */
22173b6c3722Schristos }
22183b6c3722Schristos
22193b6c3722Schristos tp->autr->last_success = *env->now;
22203b6c3722Schristos tp->autr->query_failed = 0;
22213b6c3722Schristos
22223b6c3722Schristos /* Add new trust anchors to the data structure
22233b6c3722Schristos * - note which trust anchors are seen this probe.
22243b6c3722Schristos * Set trustpoint query_interval and retry_time.
22253b6c3722Schristos * - find minimum rrsig expiration interval
22263b6c3722Schristos */
22273b6c3722Schristos if(!update_events(env, ve, tp, dnskey_rrset, &changed)) {
22283b6c3722Schristos log_err("malloc failure in autotrust update_events. "
22293b6c3722Schristos "trust point unchanged.");
22303b6c3722Schristos return 1; /* trust point unchanged, so exists */
22313b6c3722Schristos }
22323b6c3722Schristos
22333b6c3722Schristos /* - for every SEP key do the 5011 statetable.
22343b6c3722Schristos * - remove missing trustanchors (if veryold and we have new anchors).
22353b6c3722Schristos */
22363b6c3722Schristos if(!do_statetable(env, tp, &changed)) {
22373b6c3722Schristos log_err("malloc failure in autotrust do_statetable. "
22383b6c3722Schristos "trust point unchanged.");
22393b6c3722Schristos return 1; /* trust point unchanged, so exists */
22403b6c3722Schristos }
22413b6c3722Schristos
22423b6c3722Schristos autr_cleanup_keys(tp);
22433b6c3722Schristos if(!set_next_probe(env, tp, dnskey_rrset))
22443b6c3722Schristos return 0; /* trust point does not exist */
22453b6c3722Schristos autr_write_file(env, tp);
22463b6c3722Schristos if(changed) {
22473b6c3722Schristos verbose(VERB_ALGO, "autotrust: changed, reassemble");
22483b6c3722Schristos if(!autr_assemble(tp)) {
22493b6c3722Schristos log_err("malloc failure assembling autotrust keys");
22503b6c3722Schristos return 1; /* unchanged */
22513b6c3722Schristos }
22523b6c3722Schristos if(!tp->ds_rrset && !tp->dnskey_rrset) {
22533b6c3722Schristos /* no more keys, all are revoked */
22543b6c3722Schristos autr_tp_remove(env, tp, dnskey_rrset);
22553b6c3722Schristos return 0; /* trust point removed */
22563b6c3722Schristos }
22573b6c3722Schristos } else verbose(VERB_ALGO, "autotrust: no changes");
22583b6c3722Schristos
22593b6c3722Schristos return 1; /* trust point exists */
22603b6c3722Schristos }
22613b6c3722Schristos
22623b6c3722Schristos /** debug print a trust anchor key */
22633b6c3722Schristos static void
autr_debug_print_ta(struct autr_ta * ta)22643b6c3722Schristos autr_debug_print_ta(struct autr_ta* ta)
22653b6c3722Schristos {
22663b6c3722Schristos char buf[32];
22673b6c3722Schristos char* str = sldns_wire2str_rr(ta->rr, ta->rr_len);
22683b6c3722Schristos if(!str) {
22693b6c3722Schristos log_info("out of memory in debug_print_ta");
22703b6c3722Schristos return;
22713b6c3722Schristos }
227201049ae6Schristos if(str[0]) str[strlen(str)-1]=0; /* remove newline */
22737a540f2bSchristos (void)autr_ctime_r(&ta->last_change, buf);
22743b6c3722Schristos if(buf[0]) buf[strlen(buf)-1]=0; /* remove newline */
22753b6c3722Schristos log_info("[%s] %s ;;state:%d ;;pending_count:%d%s%s last:%s",
22763b6c3722Schristos trustanchor_state2str(ta->s), str, ta->s, ta->pending_count,
22773b6c3722Schristos ta->fetched?" fetched":"", ta->revoked?" revoked":"", buf);
22783b6c3722Schristos free(str);
22793b6c3722Schristos }
22803b6c3722Schristos
22813b6c3722Schristos /** debug print a trust point */
22823b6c3722Schristos static void
autr_debug_print_tp(struct trust_anchor * tp)22833b6c3722Schristos autr_debug_print_tp(struct trust_anchor* tp)
22843b6c3722Schristos {
22853b6c3722Schristos struct autr_ta* ta;
22863b6c3722Schristos char buf[257];
22873b6c3722Schristos if(!tp->autr)
22883b6c3722Schristos return;
22893b6c3722Schristos dname_str(tp->name, buf);
22903b6c3722Schristos log_info("trust point %s : %d", buf, (int)tp->dclass);
22913b6c3722Schristos log_info("assembled %d DS and %d DNSKEYs",
22923b6c3722Schristos (int)tp->numDS, (int)tp->numDNSKEY);
22933b6c3722Schristos if(tp->ds_rrset) {
229401049ae6Schristos log_packed_rrset(NO_VERBOSE, "DS:", tp->ds_rrset);
22953b6c3722Schristos }
22963b6c3722Schristos if(tp->dnskey_rrset) {
229701049ae6Schristos log_packed_rrset(NO_VERBOSE, "DNSKEY:", tp->dnskey_rrset);
22983b6c3722Schristos }
22993b6c3722Schristos log_info("file %s", tp->autr->file);
23007a540f2bSchristos (void)autr_ctime_r(&tp->autr->last_queried, buf);
23013b6c3722Schristos if(buf[0]) buf[strlen(buf)-1]=0; /* remove newline */
23023b6c3722Schristos log_info("last_queried: %u %s", (unsigned)tp->autr->last_queried, buf);
23037a540f2bSchristos (void)autr_ctime_r(&tp->autr->last_success, buf);
23043b6c3722Schristos if(buf[0]) buf[strlen(buf)-1]=0; /* remove newline */
23053b6c3722Schristos log_info("last_success: %u %s", (unsigned)tp->autr->last_success, buf);
23067a540f2bSchristos (void)autr_ctime_r(&tp->autr->next_probe_time, buf);
23073b6c3722Schristos if(buf[0]) buf[strlen(buf)-1]=0; /* remove newline */
23083b6c3722Schristos log_info("next_probe_time: %u %s", (unsigned)tp->autr->next_probe_time,
23093b6c3722Schristos buf);
23103b6c3722Schristos log_info("query_interval: %u", (unsigned)tp->autr->query_interval);
23113b6c3722Schristos log_info("retry_time: %u", (unsigned)tp->autr->retry_time);
23123b6c3722Schristos log_info("query_failed: %u", (unsigned)tp->autr->query_failed);
23133b6c3722Schristos
23143b6c3722Schristos for(ta=tp->autr->keys; ta; ta=ta->next) {
23153b6c3722Schristos autr_debug_print_ta(ta);
23163b6c3722Schristos }
23173b6c3722Schristos }
23183b6c3722Schristos
23193b6c3722Schristos void
autr_debug_print(struct val_anchors * anchors)23203b6c3722Schristos autr_debug_print(struct val_anchors* anchors)
23213b6c3722Schristos {
23223b6c3722Schristos struct trust_anchor* tp;
23233b6c3722Schristos lock_basic_lock(&anchors->lock);
23243b6c3722Schristos RBTREE_FOR(tp, struct trust_anchor*, anchors->tree) {
23253b6c3722Schristos lock_basic_lock(&tp->lock);
23263b6c3722Schristos autr_debug_print_tp(tp);
23273b6c3722Schristos lock_basic_unlock(&tp->lock);
23283b6c3722Schristos }
23293b6c3722Schristos lock_basic_unlock(&anchors->lock);
23303b6c3722Schristos }
23313b6c3722Schristos
probe_answer_cb(void * arg,int ATTR_UNUSED (rcode),sldns_buffer * ATTR_UNUSED (buf),enum sec_status ATTR_UNUSED (sec),char * ATTR_UNUSED (why_bogus),int ATTR_UNUSED (was_ratelimited))23323b6c3722Schristos void probe_answer_cb(void* arg, int ATTR_UNUSED(rcode),
23333b6c3722Schristos sldns_buffer* ATTR_UNUSED(buf), enum sec_status ATTR_UNUSED(sec),
2334f42d8de7Schristos char* ATTR_UNUSED(why_bogus), int ATTR_UNUSED(was_ratelimited))
23353b6c3722Schristos {
23363b6c3722Schristos /* retry was set before the query was done,
23373b6c3722Schristos * re-querytime is set when query succeeded, but that may not
23383b6c3722Schristos * have reset this timer because the query could have been
23393b6c3722Schristos * handled by another thread. In that case, this callback would
23403b6c3722Schristos * get called after the original timeout is done.
23413b6c3722Schristos * By not resetting the timer, it may probe more often, but not
23423b6c3722Schristos * less often.
23433b6c3722Schristos * Unless the new lookup resulted in smaller TTLs and thus smaller
23443b6c3722Schristos * timeout values. In that case one old TTL could be mistakenly done.
23453b6c3722Schristos */
23463b6c3722Schristos struct module_env* env = (struct module_env*)arg;
23473b6c3722Schristos verbose(VERB_ALGO, "autotrust probe answer cb");
23483b6c3722Schristos reset_worker_timer(env);
23493b6c3722Schristos }
23503b6c3722Schristos
23513b6c3722Schristos /** probe a trust anchor DNSKEY and unlocks tp */
23523b6c3722Schristos static void
probe_anchor(struct module_env * env,struct trust_anchor * tp)23533b6c3722Schristos probe_anchor(struct module_env* env, struct trust_anchor* tp)
23543b6c3722Schristos {
23553b6c3722Schristos struct query_info qinfo;
23563b6c3722Schristos uint16_t qflags = BIT_RD;
23573b6c3722Schristos struct edns_data edns;
23583b6c3722Schristos sldns_buffer* buf = env->scratch_buffer;
23593b6c3722Schristos qinfo.qname = regional_alloc_init(env->scratch, tp->name, tp->namelen);
23603b6c3722Schristos if(!qinfo.qname) {
23613b6c3722Schristos log_err("out of memory making 5011 probe");
23623b6c3722Schristos return;
23633b6c3722Schristos }
23643b6c3722Schristos qinfo.qname_len = tp->namelen;
23653b6c3722Schristos qinfo.qtype = LDNS_RR_TYPE_DNSKEY;
23663b6c3722Schristos qinfo.qclass = tp->dclass;
23670cd9f4ecSchristos qinfo.local_alias = NULL;
23683b6c3722Schristos log_query_info(VERB_ALGO, "autotrust probe", &qinfo);
23693b6c3722Schristos verbose(VERB_ALGO, "retry probe set in %d seconds",
23703b6c3722Schristos (int)tp->autr->next_probe_time - (int)*env->now);
23713b6c3722Schristos edns.edns_present = 1;
23723b6c3722Schristos edns.ext_rcode = 0;
23733b6c3722Schristos edns.edns_version = 0;
23743b6c3722Schristos edns.bits = EDNS_DO;
23757a540f2bSchristos edns.opt_list_in = NULL;
23767a540f2bSchristos edns.opt_list_out = NULL;
23777a540f2bSchristos edns.opt_list_inplace_cb_out = NULL;
2378d0eba39bSchristos edns.padding_block_size = 0;
2379*91f7d55fSchristos edns.cookie_present = 0;
2380*91f7d55fSchristos edns.cookie_valid = 0;
23813b6c3722Schristos if(sldns_buffer_capacity(buf) < 65535)
23823b6c3722Schristos edns.udp_size = (uint16_t)sldns_buffer_capacity(buf);
23833b6c3722Schristos else edns.udp_size = 65535;
23843b6c3722Schristos
23853b6c3722Schristos /* can't hold the lock while mesh_run is processing */
23863b6c3722Schristos lock_basic_unlock(&tp->lock);
23873b6c3722Schristos
23883b6c3722Schristos /* delete the DNSKEY from rrset and key cache so an active probe
23893b6c3722Schristos * is done. First the rrset so another thread does not use it
23903b6c3722Schristos * to recreate the key entry in a race condition. */
23913b6c3722Schristos rrset_cache_remove(env->rrset_cache, qinfo.qname, qinfo.qname_len,
23923b6c3722Schristos qinfo.qtype, qinfo.qclass, 0);
23933b6c3722Schristos key_cache_remove(env->key_cache, qinfo.qname, qinfo.qname_len,
23943b6c3722Schristos qinfo.qclass);
23953b6c3722Schristos
23963b6c3722Schristos if(!mesh_new_callback(env->mesh, &qinfo, qflags, &edns, buf, 0,
23977a540f2bSchristos &probe_answer_cb, env, 0)) {
23983b6c3722Schristos log_err("out of memory making 5011 probe");
23993b6c3722Schristos }
24003b6c3722Schristos }
24013b6c3722Schristos
24023b6c3722Schristos /** fetch first to-probe trust-anchor and lock it and set retrytime */
24033b6c3722Schristos static struct trust_anchor*
todo_probe(struct module_env * env,time_t * next)24043b6c3722Schristos todo_probe(struct module_env* env, time_t* next)
24053b6c3722Schristos {
24063b6c3722Schristos struct trust_anchor* tp;
24070cd9f4ecSchristos rbnode_type* el;
24083b6c3722Schristos /* get first one */
24093b6c3722Schristos lock_basic_lock(&env->anchors->lock);
24103b6c3722Schristos if( (el=rbtree_first(&env->anchors->autr->probe)) == RBTREE_NULL) {
24113b6c3722Schristos /* in case of revoked anchors */
24123b6c3722Schristos lock_basic_unlock(&env->anchors->lock);
24133b6c3722Schristos /* signal that there are no anchors to probe */
24143b6c3722Schristos *next = 0;
24153b6c3722Schristos return NULL;
24163b6c3722Schristos }
24173b6c3722Schristos tp = (struct trust_anchor*)el->key;
24183b6c3722Schristos lock_basic_lock(&tp->lock);
24193b6c3722Schristos
24203b6c3722Schristos /* is it eligible? */
24213b6c3722Schristos if((time_t)tp->autr->next_probe_time > *env->now) {
24223b6c3722Schristos /* no more to probe */
24233b6c3722Schristos *next = (time_t)tp->autr->next_probe_time - *env->now;
24243b6c3722Schristos lock_basic_unlock(&tp->lock);
24253b6c3722Schristos lock_basic_unlock(&env->anchors->lock);
24263b6c3722Schristos return NULL;
24273b6c3722Schristos }
24283b6c3722Schristos
24293b6c3722Schristos /* reset its next probe time */
24303b6c3722Schristos (void)rbtree_delete(&env->anchors->autr->probe, tp);
24313b6c3722Schristos tp->autr->next_probe_time = calc_next_probe(env, tp->autr->retry_time);
24323b6c3722Schristos (void)rbtree_insert(&env->anchors->autr->probe, &tp->autr->pnode);
24333b6c3722Schristos lock_basic_unlock(&env->anchors->lock);
24343b6c3722Schristos
24353b6c3722Schristos return tp;
24363b6c3722Schristos }
24373b6c3722Schristos
24383b6c3722Schristos time_t
autr_probe_timer(struct module_env * env)24393b6c3722Schristos autr_probe_timer(struct module_env* env)
24403b6c3722Schristos {
24413b6c3722Schristos struct trust_anchor* tp;
24423b6c3722Schristos time_t next_probe = 3600;
24433b6c3722Schristos int num = 0;
24443b6c3722Schristos if(autr_permit_small_holddown) next_probe = 1;
24453b6c3722Schristos verbose(VERB_ALGO, "autotrust probe timer callback");
24463b6c3722Schristos /* while there are still anchors to probe */
24473b6c3722Schristos while( (tp = todo_probe(env, &next_probe)) ) {
24483b6c3722Schristos /* make a probe for this anchor */
24493b6c3722Schristos probe_anchor(env, tp);
24503b6c3722Schristos num++;
24513b6c3722Schristos }
24523b6c3722Schristos regional_free_all(env->scratch);
24533b6c3722Schristos if(next_probe == 0)
24543b6c3722Schristos return 0; /* no trust points to probe */
24553b6c3722Schristos verbose(VERB_ALGO, "autotrust probe timer %d callbacks done", num);
24563b6c3722Schristos return next_probe;
24573b6c3722Schristos }
2458