1238106Sdes/* 2238106Sdes * validator/autotrust.c - RFC5011 trust anchor management for unbound. 3238106Sdes * 4238106Sdes * Copyright (c) 2009, NLnet Labs. All rights reserved. 5238106Sdes * 6238106Sdes * This software is open source. 7238106Sdes * 8238106Sdes * Redistribution and use in source and binary forms, with or without 9238106Sdes * modification, are permitted provided that the following conditions 10238106Sdes * are met: 11238106Sdes * 12238106Sdes * Redistributions of source code must retain the above copyright notice, 13238106Sdes * this list of conditions and the following disclaimer. 14238106Sdes * 15238106Sdes * Redistributions in binary form must reproduce the above copyright notice, 16238106Sdes * this list of conditions and the following disclaimer in the documentation 17238106Sdes * and/or other materials provided with the distribution. 18238106Sdes * 19238106Sdes * Neither the name of the NLNET LABS nor the names of its contributors may 20238106Sdes * be used to endorse or promote products derived from this software without 21238106Sdes * specific prior written permission. 22238106Sdes * 23238106Sdes * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24269257Sdes * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25269257Sdes * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 26269257Sdes * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27269257Sdes * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28269257Sdes * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29269257Sdes * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30269257Sdes * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31269257Sdes * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32269257Sdes * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33269257Sdes * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34238106Sdes */ 35238106Sdes 36238106Sdes/** 37238106Sdes * \file 38238106Sdes * 39238106Sdes * Contains autotrust implementation. The implementation was taken from 40238106Sdes * the autotrust daemon (BSD licensed), written by Matthijs Mekking. 41238106Sdes * It was modified to fit into unbound. The state table process is the same. 42238106Sdes */ 43238106Sdes#include "config.h" 44238106Sdes#include "validator/autotrust.h" 45238106Sdes#include "validator/val_anchor.h" 46238106Sdes#include "validator/val_utils.h" 47238106Sdes#include "validator/val_sigcrypt.h" 48238106Sdes#include "util/data/dname.h" 49238106Sdes#include "util/data/packed_rrset.h" 50238106Sdes#include "util/log.h" 51238106Sdes#include "util/module.h" 52238106Sdes#include "util/net_help.h" 53238106Sdes#include "util/config_file.h" 54238106Sdes#include "util/regional.h" 55238106Sdes#include "util/random.h" 56238106Sdes#include "util/data/msgparse.h" 57238106Sdes#include "services/mesh.h" 58238106Sdes#include "services/cache/rrset.h" 59238106Sdes#include "validator/val_kcache.h" 60291767Sdes#include "sldns/sbuffer.h" 61291767Sdes#include "sldns/wire2str.h" 62291767Sdes#include "sldns/str2wire.h" 63291767Sdes#include "sldns/keyraw.h" 64291767Sdes#include "sldns/rrdef.h" 65269257Sdes#include <stdarg.h> 66269257Sdes#include <ctype.h> 67238106Sdes 68238106Sdes/** number of times a key must be seen before it can become valid */ 69238106Sdes#define MIN_PENDINGCOUNT 2 70238106Sdes 71238106Sdes/** Event: Revoked */ 72238106Sdesstatic void do_revoked(struct module_env* env, struct autr_ta* anchor, int* c); 73238106Sdes 74238106Sdesstruct autr_global_data* autr_global_create(void) 75238106Sdes{ 76238106Sdes struct autr_global_data* global; 77238106Sdes global = (struct autr_global_data*)malloc(sizeof(*global)); 78238106Sdes if(!global) 79238106Sdes return NULL; 80238106Sdes rbtree_init(&global->probe, &probetree_cmp); 81238106Sdes return global; 82238106Sdes} 83238106Sdes 84238106Sdesvoid autr_global_delete(struct autr_global_data* global) 85238106Sdes{ 86238106Sdes if(!global) 87238106Sdes return; 88238106Sdes /* elements deleted by parent */ 89238106Sdes memset(global, 0, sizeof(*global)); 90238106Sdes free(global); 91238106Sdes} 92238106Sdes 93238106Sdesint probetree_cmp(const void* x, const void* y) 94238106Sdes{ 95238106Sdes struct trust_anchor* a = (struct trust_anchor*)x; 96238106Sdes struct trust_anchor* b = (struct trust_anchor*)y; 97238106Sdes log_assert(a->autr && b->autr); 98238106Sdes if(a->autr->next_probe_time < b->autr->next_probe_time) 99238106Sdes return -1; 100238106Sdes if(a->autr->next_probe_time > b->autr->next_probe_time) 101238106Sdes return 1; 102238106Sdes /* time is equal, sort on trust point identity */ 103238106Sdes return anchor_cmp(x, y); 104238106Sdes} 105238106Sdes 106238106Sdessize_t 107238106Sdesautr_get_num_anchors(struct val_anchors* anchors) 108238106Sdes{ 109238106Sdes size_t res = 0; 110238106Sdes if(!anchors) 111238106Sdes return 0; 112238106Sdes lock_basic_lock(&anchors->lock); 113238106Sdes if(anchors->autr) 114238106Sdes res = anchors->autr->probe.count; 115238106Sdes lock_basic_unlock(&anchors->lock); 116238106Sdes return res; 117238106Sdes} 118238106Sdes 119238106Sdes/** Position in string */ 120238106Sdesstatic int 121238106Sdesposition_in_string(char *str, const char* sub) 122238106Sdes{ 123238106Sdes char* pos = strstr(str, sub); 124238106Sdes if(pos) 125238106Sdes return (int)(pos-str)+(int)strlen(sub); 126238106Sdes return -1; 127238106Sdes} 128238106Sdes 129238106Sdes/** Debug routine to print pretty key information */ 130238106Sdesstatic void 131238106Sdesverbose_key(struct autr_ta* ta, enum verbosity_value level, 132238106Sdes const char* format, ...) ATTR_FORMAT(printf, 3, 4); 133238106Sdes 134238106Sdes/** 135238106Sdes * Implementation of debug pretty key print 136238106Sdes * @param ta: trust anchor key with DNSKEY data. 137238106Sdes * @param level: verbosity level to print at. 138238106Sdes * @param format: printf style format string. 139238106Sdes */ 140238106Sdesstatic void 141238106Sdesverbose_key(struct autr_ta* ta, enum verbosity_value level, 142238106Sdes const char* format, ...) 143238106Sdes{ 144238106Sdes va_list args; 145238106Sdes va_start(args, format); 146238106Sdes if(verbosity >= level) { 147269257Sdes char* str = sldns_wire2str_dname(ta->rr, ta->dname_len); 148269257Sdes int keytag = (int)sldns_calc_keytag_raw(sldns_wirerr_get_rdata( 149269257Sdes ta->rr, ta->rr_len, ta->dname_len), 150269257Sdes sldns_wirerr_get_rdatalen(ta->rr, ta->rr_len, 151269257Sdes ta->dname_len)); 152238106Sdes char msg[MAXSYSLOGMSGLEN]; 153238106Sdes vsnprintf(msg, sizeof(msg), format, args); 154238106Sdes verbose(level, "%s key %d %s", str?str:"??", keytag, msg); 155238106Sdes free(str); 156238106Sdes } 157238106Sdes va_end(args); 158238106Sdes} 159238106Sdes 160238106Sdes/** 161238106Sdes * Parse comments 162238106Sdes * @param str: to parse 163238106Sdes * @param ta: trust key autotrust metadata 164238106Sdes * @return false on failure. 165238106Sdes */ 166238106Sdesstatic int 167238106Sdesparse_comments(char* str, struct autr_ta* ta) 168238106Sdes{ 169238106Sdes int len = (int)strlen(str), pos = 0, timestamp = 0; 170238106Sdes char* comment = (char*) malloc(sizeof(char)*len+1); 171238106Sdes char* comments = comment; 172238106Sdes if(!comment) { 173238106Sdes log_err("malloc failure in parse"); 174238106Sdes return 0; 175238106Sdes } 176238106Sdes /* skip over whitespace and data at start of line */ 177238106Sdes while (*str != '\0' && *str != ';') 178238106Sdes str++; 179238106Sdes if (*str == ';') 180238106Sdes str++; 181238106Sdes /* copy comments */ 182238106Sdes while (*str != '\0') 183238106Sdes { 184238106Sdes *comments = *str; 185238106Sdes comments++; 186238106Sdes str++; 187238106Sdes } 188238106Sdes *comments = '\0'; 189238106Sdes 190238106Sdes comments = comment; 191238106Sdes 192238106Sdes /* read state */ 193238106Sdes pos = position_in_string(comments, "state="); 194238106Sdes if (pos >= (int) strlen(comments)) 195238106Sdes { 196238106Sdes log_err("parse error"); 197238106Sdes free(comment); 198238106Sdes return 0; 199238106Sdes } 200238106Sdes if (pos <= 0) 201238106Sdes ta->s = AUTR_STATE_VALID; 202238106Sdes else 203238106Sdes { 204238106Sdes int s = (int) comments[pos] - '0'; 205238106Sdes switch(s) 206238106Sdes { 207238106Sdes case AUTR_STATE_START: 208238106Sdes case AUTR_STATE_ADDPEND: 209238106Sdes case AUTR_STATE_VALID: 210238106Sdes case AUTR_STATE_MISSING: 211238106Sdes case AUTR_STATE_REVOKED: 212238106Sdes case AUTR_STATE_REMOVED: 213238106Sdes ta->s = s; 214238106Sdes break; 215238106Sdes default: 216238106Sdes verbose_key(ta, VERB_OPS, "has undefined " 217238106Sdes "state, considered NewKey"); 218238106Sdes ta->s = AUTR_STATE_START; 219238106Sdes break; 220238106Sdes } 221238106Sdes } 222238106Sdes /* read pending count */ 223238106Sdes pos = position_in_string(comments, "count="); 224238106Sdes if (pos >= (int) strlen(comments)) 225238106Sdes { 226238106Sdes log_err("parse error"); 227238106Sdes free(comment); 228238106Sdes return 0; 229238106Sdes } 230238106Sdes if (pos <= 0) 231238106Sdes ta->pending_count = 0; 232238106Sdes else 233238106Sdes { 234238106Sdes comments += pos; 235238106Sdes ta->pending_count = (uint8_t)atoi(comments); 236238106Sdes } 237238106Sdes 238238106Sdes /* read last change */ 239238106Sdes pos = position_in_string(comments, "lastchange="); 240238106Sdes if (pos >= (int) strlen(comments)) 241238106Sdes { 242238106Sdes log_err("parse error"); 243238106Sdes free(comment); 244238106Sdes return 0; 245238106Sdes } 246238106Sdes if (pos >= 0) 247238106Sdes { 248238106Sdes comments += pos; 249238106Sdes timestamp = atoi(comments); 250238106Sdes } 251238106Sdes if (pos < 0 || !timestamp) 252238106Sdes ta->last_change = 0; 253238106Sdes else 254269257Sdes ta->last_change = (time_t)timestamp; 255238106Sdes 256238106Sdes free(comment); 257238106Sdes return 1; 258238106Sdes} 259238106Sdes 260238106Sdes/** Check if a line contains data (besides comments) */ 261238106Sdesstatic int 262238106Sdesstr_contains_data(char* str, char comment) 263238106Sdes{ 264238106Sdes while (*str != '\0') { 265238106Sdes if (*str == comment || *str == '\n') 266238106Sdes return 0; 267238106Sdes if (*str != ' ' && *str != '\t') 268238106Sdes return 1; 269238106Sdes str++; 270238106Sdes } 271238106Sdes return 0; 272238106Sdes} 273238106Sdes 274269257Sdes/** Get DNSKEY flags 275269257Sdes * rdata without rdatalen in front of it. */ 276238106Sdesstatic int 277269257Sdesdnskey_flags(uint16_t t, uint8_t* rdata, size_t len) 278238106Sdes{ 279269257Sdes uint16_t f; 280269257Sdes if(t != LDNS_RR_TYPE_DNSKEY) 281238106Sdes return 0; 282269257Sdes if(len < 2) 283269257Sdes return 0; 284269257Sdes memmove(&f, rdata, 2); 285269257Sdes f = ntohs(f); 286269257Sdes return (int)f; 287238106Sdes} 288238106Sdes 289269257Sdes/** Check if KSK DNSKEY. 290269257Sdes * pass rdata without rdatalen in front of it */ 291269257Sdesstatic int 292269257Sdesrr_is_dnskey_sep(uint16_t t, uint8_t* rdata, size_t len) 293269257Sdes{ 294269257Sdes return (dnskey_flags(t, rdata, len)&DNSKEY_BIT_SEP); 295269257Sdes} 296238106Sdes 297269257Sdes/** Check if TA is KSK DNSKEY */ 298238106Sdesstatic int 299269257Sdesta_is_dnskey_sep(struct autr_ta* ta) 300238106Sdes{ 301269257Sdes return (dnskey_flags( 302269257Sdes sldns_wirerr_get_type(ta->rr, ta->rr_len, ta->dname_len), 303269257Sdes sldns_wirerr_get_rdata(ta->rr, ta->rr_len, ta->dname_len), 304269257Sdes sldns_wirerr_get_rdatalen(ta->rr, ta->rr_len, ta->dname_len) 305269257Sdes ) & DNSKEY_BIT_SEP); 306238106Sdes} 307238106Sdes 308269257Sdes/** Check if REVOKED DNSKEY 309269257Sdes * pass rdata without rdatalen in front of it */ 310238106Sdesstatic int 311269257Sdesrr_is_dnskey_revoked(uint16_t t, uint8_t* rdata, size_t len) 312238106Sdes{ 313269257Sdes return (dnskey_flags(t, rdata, len)&LDNS_KEY_REVOKE_KEY); 314238106Sdes} 315238106Sdes 316238106Sdes/** create ta */ 317238106Sdesstatic struct autr_ta* 318269257Sdesautr_ta_create(uint8_t* rr, size_t rr_len, size_t dname_len) 319238106Sdes{ 320238106Sdes struct autr_ta* ta = (struct autr_ta*)calloc(1, sizeof(*ta)); 321238106Sdes if(!ta) { 322269257Sdes free(rr); 323238106Sdes return NULL; 324238106Sdes } 325238106Sdes ta->rr = rr; 326269257Sdes ta->rr_len = rr_len; 327269257Sdes ta->dname_len = dname_len; 328238106Sdes return ta; 329238106Sdes} 330238106Sdes 331238106Sdes/** create tp */ 332238106Sdesstatic struct trust_anchor* 333269257Sdesautr_tp_create(struct val_anchors* anchors, uint8_t* own, size_t own_len, 334269257Sdes uint16_t dc) 335238106Sdes{ 336238106Sdes struct trust_anchor* tp = (struct trust_anchor*)calloc(1, sizeof(*tp)); 337238106Sdes if(!tp) return NULL; 338269257Sdes tp->name = memdup(own, own_len); 339238106Sdes if(!tp->name) { 340238106Sdes free(tp); 341238106Sdes return NULL; 342238106Sdes } 343269257Sdes tp->namelen = own_len; 344238106Sdes tp->namelabs = dname_count_labels(tp->name); 345238106Sdes tp->node.key = tp; 346238106Sdes tp->dclass = dc; 347238106Sdes tp->autr = (struct autr_point_data*)calloc(1, sizeof(*tp->autr)); 348238106Sdes if(!tp->autr) { 349238106Sdes free(tp->name); 350238106Sdes free(tp); 351238106Sdes return NULL; 352238106Sdes } 353238106Sdes tp->autr->pnode.key = tp; 354238106Sdes 355238106Sdes lock_basic_lock(&anchors->lock); 356238106Sdes if(!rbtree_insert(anchors->tree, &tp->node)) { 357238106Sdes lock_basic_unlock(&anchors->lock); 358238106Sdes log_err("trust anchor presented twice"); 359238106Sdes free(tp->name); 360238106Sdes free(tp->autr); 361238106Sdes free(tp); 362238106Sdes return NULL; 363238106Sdes } 364238106Sdes if(!rbtree_insert(&anchors->autr->probe, &tp->autr->pnode)) { 365238106Sdes (void)rbtree_delete(anchors->tree, tp); 366238106Sdes lock_basic_unlock(&anchors->lock); 367238106Sdes log_err("trust anchor in probetree twice"); 368238106Sdes free(tp->name); 369238106Sdes free(tp->autr); 370238106Sdes free(tp); 371238106Sdes return NULL; 372238106Sdes } 373238106Sdes lock_basic_unlock(&anchors->lock); 374238106Sdes lock_basic_init(&tp->lock); 375238106Sdes lock_protect(&tp->lock, tp, sizeof(*tp)); 376238106Sdes lock_protect(&tp->lock, tp->autr, sizeof(*tp->autr)); 377238106Sdes return tp; 378238106Sdes} 379238106Sdes 380238106Sdes/** delete assembled rrsets */ 381238106Sdesstatic void 382238106Sdesautr_rrset_delete(struct ub_packed_rrset_key* r) 383238106Sdes{ 384238106Sdes if(r) { 385238106Sdes free(r->rk.dname); 386238106Sdes free(r->entry.data); 387238106Sdes free(r); 388238106Sdes } 389238106Sdes} 390238106Sdes 391238106Sdesvoid autr_point_delete(struct trust_anchor* tp) 392238106Sdes{ 393238106Sdes if(!tp) 394238106Sdes return; 395238106Sdes lock_unprotect(&tp->lock, tp); 396238106Sdes lock_unprotect(&tp->lock, tp->autr); 397238106Sdes lock_basic_destroy(&tp->lock); 398238106Sdes autr_rrset_delete(tp->ds_rrset); 399238106Sdes autr_rrset_delete(tp->dnskey_rrset); 400238106Sdes if(tp->autr) { 401238106Sdes struct autr_ta* p = tp->autr->keys, *np; 402238106Sdes while(p) { 403238106Sdes np = p->next; 404269257Sdes free(p->rr); 405238106Sdes free(p); 406238106Sdes p = np; 407238106Sdes } 408238106Sdes free(tp->autr->file); 409238106Sdes free(tp->autr); 410238106Sdes } 411238106Sdes free(tp->name); 412238106Sdes free(tp); 413238106Sdes} 414238106Sdes 415238106Sdes/** find or add a new trust point for autotrust */ 416238106Sdesstatic struct trust_anchor* 417269257Sdesfind_add_tp(struct val_anchors* anchors, uint8_t* rr, size_t rr_len, 418269257Sdes size_t dname_len) 419238106Sdes{ 420238106Sdes struct trust_anchor* tp; 421269257Sdes tp = anchor_find(anchors, rr, dname_count_labels(rr), dname_len, 422269257Sdes sldns_wirerr_get_class(rr, rr_len, dname_len)); 423238106Sdes if(tp) { 424238106Sdes if(!tp->autr) { 425238106Sdes log_err("anchor cannot be with and without autotrust"); 426238106Sdes lock_basic_unlock(&tp->lock); 427238106Sdes return NULL; 428238106Sdes } 429238106Sdes return tp; 430238106Sdes } 431269257Sdes tp = autr_tp_create(anchors, rr, dname_len, sldns_wirerr_get_class(rr, 432269257Sdes rr_len, dname_len)); 433238106Sdes lock_basic_lock(&tp->lock); 434238106Sdes return tp; 435238106Sdes} 436238106Sdes 437238106Sdes/** Add trust anchor from RR */ 438238106Sdesstatic struct autr_ta* 439269257Sdesadd_trustanchor_frm_rr(struct val_anchors* anchors, uint8_t* rr, size_t rr_len, 440269257Sdes size_t dname_len, struct trust_anchor** tp) 441238106Sdes{ 442269257Sdes struct autr_ta* ta = autr_ta_create(rr, rr_len, dname_len); 443238106Sdes if(!ta) 444238106Sdes return NULL; 445269257Sdes *tp = find_add_tp(anchors, rr, rr_len, dname_len); 446238106Sdes if(!*tp) { 447269257Sdes free(ta->rr); 448238106Sdes free(ta); 449238106Sdes return NULL; 450238106Sdes } 451238106Sdes /* add ta to tp */ 452238106Sdes ta->next = (*tp)->autr->keys; 453238106Sdes (*tp)->autr->keys = ta; 454238106Sdes lock_basic_unlock(&(*tp)->lock); 455238106Sdes return ta; 456238106Sdes} 457238106Sdes 458238106Sdes/** 459238106Sdes * Add new trust anchor from a string in file. 460238106Sdes * @param anchors: all anchors 461238106Sdes * @param str: string with anchor and comments, if any comments. 462238106Sdes * @param tp: trust point returned. 463238106Sdes * @param origin: what to use for @ 464269257Sdes * @param origin_len: length of origin 465238106Sdes * @param prev: previous rr name 466269257Sdes * @param prev_len: length of prev 467238106Sdes * @param skip: if true, the result is NULL, but not an error, skip it. 468238106Sdes * @return new key in trust point. 469238106Sdes */ 470238106Sdesstatic struct autr_ta* 471238106Sdesadd_trustanchor_frm_str(struct val_anchors* anchors, char* str, 472269257Sdes struct trust_anchor** tp, uint8_t* origin, size_t origin_len, 473269257Sdes uint8_t** prev, size_t* prev_len, int* skip) 474238106Sdes{ 475269257Sdes uint8_t rr[LDNS_RR_BUF_SIZE]; 476269257Sdes size_t rr_len = sizeof(rr), dname_len; 477269257Sdes uint8_t* drr; 478269257Sdes int lstatus; 479238106Sdes if (!str_contains_data(str, ';')) { 480238106Sdes *skip = 1; 481238106Sdes return NULL; /* empty line */ 482238106Sdes } 483269257Sdes if(0 != (lstatus = sldns_str2wire_rr_buf(str, rr, &rr_len, &dname_len, 484269257Sdes 0, origin, origin_len, *prev, *prev_len))) 485269257Sdes { 486269257Sdes log_err("ldns error while converting string to RR at%d: %s: %s", 487269257Sdes LDNS_WIREPARSE_OFFSET(lstatus), 488269257Sdes sldns_get_errorstr_parse(lstatus), str); 489269257Sdes return NULL; 490269257Sdes } 491269257Sdes free(*prev); 492269257Sdes *prev = memdup(rr, dname_len); 493269257Sdes *prev_len = dname_len; 494269257Sdes if(!*prev) { 495269257Sdes log_err("malloc failure in add_trustanchor"); 496269257Sdes return NULL; 497269257Sdes } 498269257Sdes if(sldns_wirerr_get_type(rr, rr_len, dname_len)!=LDNS_RR_TYPE_DNSKEY && 499269257Sdes sldns_wirerr_get_type(rr, rr_len, dname_len)!=LDNS_RR_TYPE_DS) { 500238106Sdes *skip = 1; 501238106Sdes return NULL; /* only DS and DNSKEY allowed */ 502238106Sdes } 503269257Sdes drr = memdup(rr, rr_len); 504269257Sdes if(!drr) { 505269257Sdes log_err("malloc failure in add trustanchor"); 506269257Sdes return NULL; 507269257Sdes } 508269257Sdes return add_trustanchor_frm_rr(anchors, drr, rr_len, dname_len, tp); 509238106Sdes} 510238106Sdes 511238106Sdes/** 512238106Sdes * Load single anchor 513238106Sdes * @param anchors: all points. 514238106Sdes * @param str: comments line 515238106Sdes * @param fname: filename 516249141Sdes * @param origin: the $ORIGIN. 517269257Sdes * @param origin_len: length of origin 518238106Sdes * @param prev: passed to ldns. 519269257Sdes * @param prev_len: length of prev 520238106Sdes * @param skip: if true, the result is NULL, but not an error, skip it. 521238106Sdes * @return false on failure, otherwise the tp read. 522238106Sdes */ 523238106Sdesstatic struct trust_anchor* 524238106Sdesload_trustanchor(struct val_anchors* anchors, char* str, const char* fname, 525269257Sdes uint8_t* origin, size_t origin_len, uint8_t** prev, size_t* prev_len, 526269257Sdes int* skip) 527238106Sdes{ 528269257Sdes struct autr_ta* ta = NULL; 529269257Sdes struct trust_anchor* tp = NULL; 530238106Sdes 531269257Sdes ta = add_trustanchor_frm_str(anchors, str, &tp, origin, origin_len, 532269257Sdes prev, prev_len, skip); 533238106Sdes if(!ta) 534238106Sdes return NULL; 535238106Sdes lock_basic_lock(&tp->lock); 536238106Sdes if(!parse_comments(str, ta)) { 537238106Sdes lock_basic_unlock(&tp->lock); 538238106Sdes return NULL; 539238106Sdes } 540238106Sdes if(!tp->autr->file) { 541238106Sdes tp->autr->file = strdup(fname); 542238106Sdes if(!tp->autr->file) { 543238106Sdes lock_basic_unlock(&tp->lock); 544238106Sdes log_err("malloc failure"); 545238106Sdes return NULL; 546238106Sdes } 547238106Sdes } 548238106Sdes lock_basic_unlock(&tp->lock); 549238106Sdes return tp; 550238106Sdes} 551238106Sdes 552269257Sdes/** iterator for DSes from keylist. return true if a next element exists */ 553269257Sdesstatic int 554269257Sdesassemble_iterate_ds(struct autr_ta** list, uint8_t** rr, size_t* rr_len, 555269257Sdes size_t* dname_len) 556269257Sdes{ 557269257Sdes while(*list) { 558269257Sdes if(sldns_wirerr_get_type((*list)->rr, (*list)->rr_len, 559269257Sdes (*list)->dname_len) == LDNS_RR_TYPE_DS) { 560269257Sdes *rr = (*list)->rr; 561269257Sdes *rr_len = (*list)->rr_len; 562269257Sdes *dname_len = (*list)->dname_len; 563269257Sdes *list = (*list)->next; 564269257Sdes return 1; 565269257Sdes } 566269257Sdes *list = (*list)->next; 567269257Sdes } 568269257Sdes return 0; 569269257Sdes} 570269257Sdes 571269257Sdes/** iterator for DNSKEYs from keylist. return true if a next element exists */ 572269257Sdesstatic int 573269257Sdesassemble_iterate_dnskey(struct autr_ta** list, uint8_t** rr, size_t* rr_len, 574269257Sdes size_t* dname_len) 575269257Sdes{ 576269257Sdes while(*list) { 577269257Sdes if(sldns_wirerr_get_type((*list)->rr, (*list)->rr_len, 578269257Sdes (*list)->dname_len) != LDNS_RR_TYPE_DS && 579269257Sdes ((*list)->s == AUTR_STATE_VALID || 580269257Sdes (*list)->s == AUTR_STATE_MISSING)) { 581269257Sdes *rr = (*list)->rr; 582269257Sdes *rr_len = (*list)->rr_len; 583269257Sdes *dname_len = (*list)->dname_len; 584269257Sdes *list = (*list)->next; 585269257Sdes return 1; 586269257Sdes } 587269257Sdes *list = (*list)->next; 588269257Sdes } 589269257Sdes return 0; 590269257Sdes} 591269257Sdes 592269257Sdes/** see if iterator-list has any elements in it, or it is empty */ 593269257Sdesstatic int 594269257Sdesassemble_iterate_hasfirst(int iter(struct autr_ta**, uint8_t**, size_t*, 595269257Sdes size_t*), struct autr_ta* list) 596269257Sdes{ 597269257Sdes uint8_t* rr = NULL; 598269257Sdes size_t rr_len = 0, dname_len = 0; 599269257Sdes return iter(&list, &rr, &rr_len, &dname_len); 600269257Sdes} 601269257Sdes 602269257Sdes/** number of elements in iterator list */ 603269257Sdesstatic size_t 604269257Sdesassemble_iterate_count(int iter(struct autr_ta**, uint8_t**, size_t*, 605269257Sdes size_t*), struct autr_ta* list) 606269257Sdes{ 607269257Sdes uint8_t* rr = NULL; 608269257Sdes size_t i = 0, rr_len = 0, dname_len = 0; 609269257Sdes while(iter(&list, &rr, &rr_len, &dname_len)) { 610269257Sdes i++; 611269257Sdes } 612269257Sdes return i; 613269257Sdes} 614269257Sdes 615238106Sdes/** 616269257Sdes * Create a ub_packed_rrset_key allocated on the heap. 617269257Sdes * It therefore does not have the correct ID value, and cannot be used 618269257Sdes * inside the cache. It can be used in storage outside of the cache. 619269257Sdes * Keys for the cache have to be obtained from alloc.h . 620269257Sdes * @param iter: iterator over the elements in the list. It filters elements. 621269257Sdes * @param list: the list. 622269257Sdes * @return key allocated or NULL on failure. 623269257Sdes */ 624269257Sdesstatic struct ub_packed_rrset_key* 625269257Sdesub_packed_rrset_heap_key(int iter(struct autr_ta**, uint8_t**, size_t*, 626269257Sdes size_t*), struct autr_ta* list) 627269257Sdes{ 628269257Sdes uint8_t* rr = NULL; 629269257Sdes size_t rr_len = 0, dname_len = 0; 630269257Sdes struct ub_packed_rrset_key* k; 631269257Sdes if(!iter(&list, &rr, &rr_len, &dname_len)) 632269257Sdes return NULL; 633269257Sdes k = (struct ub_packed_rrset_key*)calloc(1, sizeof(*k)); 634269257Sdes if(!k) 635269257Sdes return NULL; 636269257Sdes k->rk.type = htons(sldns_wirerr_get_type(rr, rr_len, dname_len)); 637269257Sdes k->rk.rrset_class = htons(sldns_wirerr_get_class(rr, rr_len, dname_len)); 638269257Sdes k->rk.dname_len = dname_len; 639269257Sdes k->rk.dname = memdup(rr, dname_len); 640269257Sdes if(!k->rk.dname) { 641269257Sdes free(k); 642269257Sdes return NULL; 643269257Sdes } 644269257Sdes return k; 645269257Sdes} 646269257Sdes 647269257Sdes/** 648269257Sdes * Create packed_rrset data on the heap. 649269257Sdes * @param iter: iterator over the elements in the list. It filters elements. 650269257Sdes * @param list: the list. 651269257Sdes * @return data allocated or NULL on failure. 652269257Sdes */ 653269257Sdesstatic struct packed_rrset_data* 654269257Sdespacked_rrset_heap_data(int iter(struct autr_ta**, uint8_t**, size_t*, 655269257Sdes size_t*), struct autr_ta* list) 656269257Sdes{ 657269257Sdes uint8_t* rr = NULL; 658269257Sdes size_t rr_len = 0, dname_len = 0; 659269257Sdes struct packed_rrset_data* data; 660269257Sdes size_t count=0, rrsig_count=0, len=0, i, total; 661269257Sdes uint8_t* nextrdata; 662269257Sdes struct autr_ta* list_i; 663269257Sdes time_t ttl = 0; 664269257Sdes 665269257Sdes list_i = list; 666269257Sdes while(iter(&list_i, &rr, &rr_len, &dname_len)) { 667269257Sdes if(sldns_wirerr_get_type(rr, rr_len, dname_len) == 668269257Sdes LDNS_RR_TYPE_RRSIG) 669269257Sdes rrsig_count++; 670269257Sdes else count++; 671269257Sdes /* sizeof the rdlength + rdatalen */ 672269257Sdes len += 2 + sldns_wirerr_get_rdatalen(rr, rr_len, dname_len); 673269257Sdes ttl = (time_t)sldns_wirerr_get_ttl(rr, rr_len, dname_len); 674269257Sdes } 675269257Sdes if(count == 0 && rrsig_count == 0) 676269257Sdes return NULL; 677269257Sdes 678269257Sdes /* allocate */ 679269257Sdes total = count + rrsig_count; 680269257Sdes len += sizeof(*data) + total*(sizeof(size_t) + sizeof(time_t) + 681269257Sdes sizeof(uint8_t*)); 682269257Sdes data = (struct packed_rrset_data*)calloc(1, len); 683269257Sdes if(!data) 684269257Sdes return NULL; 685269257Sdes 686269257Sdes /* fill it */ 687269257Sdes data->ttl = ttl; 688269257Sdes data->count = count; 689269257Sdes data->rrsig_count = rrsig_count; 690269257Sdes data->rr_len = (size_t*)((uint8_t*)data + 691269257Sdes sizeof(struct packed_rrset_data)); 692269257Sdes data->rr_data = (uint8_t**)&(data->rr_len[total]); 693269257Sdes data->rr_ttl = (time_t*)&(data->rr_data[total]); 694269257Sdes nextrdata = (uint8_t*)&(data->rr_ttl[total]); 695269257Sdes 696269257Sdes /* fill out len, ttl, fields */ 697269257Sdes list_i = list; 698269257Sdes i = 0; 699269257Sdes while(iter(&list_i, &rr, &rr_len, &dname_len)) { 700269257Sdes data->rr_ttl[i] = (time_t)sldns_wirerr_get_ttl(rr, rr_len, 701269257Sdes dname_len); 702269257Sdes if(data->rr_ttl[i] < data->ttl) 703269257Sdes data->ttl = data->rr_ttl[i]; 704269257Sdes data->rr_len[i] = 2 /* the rdlength */ + 705269257Sdes sldns_wirerr_get_rdatalen(rr, rr_len, dname_len); 706269257Sdes i++; 707269257Sdes } 708269257Sdes 709269257Sdes /* fixup rest of ptrs */ 710269257Sdes for(i=0; i<total; i++) { 711269257Sdes data->rr_data[i] = nextrdata; 712269257Sdes nextrdata += data->rr_len[i]; 713269257Sdes } 714269257Sdes 715269257Sdes /* copy data in there */ 716269257Sdes list_i = list; 717269257Sdes i = 0; 718269257Sdes while(iter(&list_i, &rr, &rr_len, &dname_len)) { 719269257Sdes memmove(data->rr_data[i], 720269257Sdes sldns_wirerr_get_rdatawl(rr, rr_len, dname_len), 721269257Sdes data->rr_len[i]); 722269257Sdes i++; 723269257Sdes } 724269257Sdes 725269257Sdes if(data->rrsig_count && data->count == 0) { 726269257Sdes data->count = data->rrsig_count; /* rrset type is RRSIG */ 727269257Sdes data->rrsig_count = 0; 728269257Sdes } 729269257Sdes return data; 730269257Sdes} 731269257Sdes 732269257Sdes/** 733238106Sdes * Assemble the trust anchors into DS and DNSKEY packed rrsets. 734238106Sdes * Uses only VALID and MISSING DNSKEYs. 735269257Sdes * Read the sldns_rrs and builds packed rrsets 736238106Sdes * @param tp: the trust point. Must be locked. 737238106Sdes * @return false on malloc failure. 738238106Sdes */ 739238106Sdesstatic int 740238106Sdesautr_assemble(struct trust_anchor* tp) 741238106Sdes{ 742238106Sdes struct ub_packed_rrset_key* ubds=NULL, *ubdnskey=NULL; 743238106Sdes 744238106Sdes /* make packed rrset keys - malloced with no ID number, they 745238106Sdes * are not in the cache */ 746238106Sdes /* make packed rrset data (if there is a key) */ 747269257Sdes if(assemble_iterate_hasfirst(assemble_iterate_ds, tp->autr->keys)) { 748269257Sdes ubds = ub_packed_rrset_heap_key( 749269257Sdes assemble_iterate_ds, tp->autr->keys); 750269257Sdes if(!ubds) 751238106Sdes goto error_cleanup; 752269257Sdes ubds->entry.data = packed_rrset_heap_data( 753269257Sdes assemble_iterate_ds, tp->autr->keys); 754238106Sdes if(!ubds->entry.data) 755238106Sdes goto error_cleanup; 756238106Sdes } 757269257Sdes 758269257Sdes /* make packed DNSKEY data */ 759269257Sdes if(assemble_iterate_hasfirst(assemble_iterate_dnskey, tp->autr->keys)) { 760269257Sdes ubdnskey = ub_packed_rrset_heap_key( 761269257Sdes assemble_iterate_dnskey, tp->autr->keys); 762238106Sdes if(!ubdnskey) 763238106Sdes goto error_cleanup; 764269257Sdes ubdnskey->entry.data = packed_rrset_heap_data( 765269257Sdes assemble_iterate_dnskey, tp->autr->keys); 766238106Sdes if(!ubdnskey->entry.data) { 767238106Sdes error_cleanup: 768238106Sdes autr_rrset_delete(ubds); 769238106Sdes autr_rrset_delete(ubdnskey); 770238106Sdes return 0; 771238106Sdes } 772238106Sdes } 773269257Sdes 774238106Sdes /* we have prepared the new keys so nothing can go wrong any more. 775238106Sdes * And we are sure we cannot be left without trustanchor after 776238106Sdes * any errors. Put in the new keys and remove old ones. */ 777238106Sdes 778238106Sdes /* free the old data */ 779238106Sdes autr_rrset_delete(tp->ds_rrset); 780238106Sdes autr_rrset_delete(tp->dnskey_rrset); 781238106Sdes 782238106Sdes /* assign the data to replace the old */ 783238106Sdes tp->ds_rrset = ubds; 784238106Sdes tp->dnskey_rrset = ubdnskey; 785269257Sdes tp->numDS = assemble_iterate_count(assemble_iterate_ds, 786269257Sdes tp->autr->keys); 787269257Sdes tp->numDNSKEY = assemble_iterate_count(assemble_iterate_dnskey, 788269257Sdes tp->autr->keys); 789238106Sdes return 1; 790238106Sdes} 791238106Sdes 792238106Sdes/** parse integer */ 793238106Sdesstatic unsigned int 794238106Sdesparse_int(char* line, int* ret) 795238106Sdes{ 796238106Sdes char *e; 797238106Sdes unsigned int x = (unsigned int)strtol(line, &e, 10); 798238106Sdes if(line == e) { 799238106Sdes *ret = -1; /* parse error */ 800238106Sdes return 0; 801238106Sdes } 802238106Sdes *ret = 1; /* matched */ 803238106Sdes return x; 804238106Sdes} 805238106Sdes 806238106Sdes/** parse id sequence for anchor */ 807238106Sdesstatic struct trust_anchor* 808238106Sdesparse_id(struct val_anchors* anchors, char* line) 809238106Sdes{ 810238106Sdes struct trust_anchor *tp; 811238106Sdes int r; 812238106Sdes uint16_t dclass; 813269257Sdes uint8_t* dname; 814269257Sdes size_t dname_len; 815238106Sdes /* read the owner name */ 816238106Sdes char* next = strchr(line, ' '); 817238106Sdes if(!next) 818238106Sdes return NULL; 819238106Sdes next[0] = 0; 820269257Sdes dname = sldns_str2wire_dname(line, &dname_len); 821269257Sdes if(!dname) 822238106Sdes return NULL; 823238106Sdes 824238106Sdes /* read the class */ 825238106Sdes dclass = parse_int(next+1, &r); 826238106Sdes if(r == -1) { 827269257Sdes free(dname); 828238106Sdes return NULL; 829238106Sdes } 830238106Sdes 831238106Sdes /* find the trust point */ 832269257Sdes tp = autr_tp_create(anchors, dname, dname_len, dclass); 833269257Sdes free(dname); 834238106Sdes return tp; 835238106Sdes} 836238106Sdes 837238106Sdes/** 838238106Sdes * Parse variable from trustanchor header 839238106Sdes * @param line: to parse 840238106Sdes * @param anchors: the anchor is added to this, if "id:" is seen. 841238106Sdes * @param anchor: the anchor as result value or previously returned anchor 842238106Sdes * value to read the variable lines into. 843238106Sdes * @return: 0 no match, -1 failed syntax error, +1 success line read. 844238106Sdes * +2 revoked trust anchor file. 845238106Sdes */ 846238106Sdesstatic int 847238106Sdesparse_var_line(char* line, struct val_anchors* anchors, 848238106Sdes struct trust_anchor** anchor) 849238106Sdes{ 850238106Sdes struct trust_anchor* tp = *anchor; 851238106Sdes int r = 0; 852238106Sdes if(strncmp(line, ";;id: ", 6) == 0) { 853238106Sdes *anchor = parse_id(anchors, line+6); 854238106Sdes if(!*anchor) return -1; 855238106Sdes else return 1; 856238106Sdes } else if(strncmp(line, ";;REVOKED", 9) == 0) { 857238106Sdes if(tp) { 858238106Sdes log_err("REVOKED statement must be at start of file"); 859238106Sdes return -1; 860238106Sdes } 861238106Sdes return 2; 862238106Sdes } else if(strncmp(line, ";;last_queried: ", 16) == 0) { 863238106Sdes if(!tp) return -1; 864238106Sdes lock_basic_lock(&tp->lock); 865238106Sdes tp->autr->last_queried = (time_t)parse_int(line+16, &r); 866238106Sdes lock_basic_unlock(&tp->lock); 867238106Sdes } else if(strncmp(line, ";;last_success: ", 16) == 0) { 868238106Sdes if(!tp) return -1; 869238106Sdes lock_basic_lock(&tp->lock); 870238106Sdes tp->autr->last_success = (time_t)parse_int(line+16, &r); 871238106Sdes lock_basic_unlock(&tp->lock); 872238106Sdes } else if(strncmp(line, ";;next_probe_time: ", 19) == 0) { 873238106Sdes if(!tp) return -1; 874238106Sdes lock_basic_lock(&anchors->lock); 875238106Sdes lock_basic_lock(&tp->lock); 876238106Sdes (void)rbtree_delete(&anchors->autr->probe, tp); 877238106Sdes tp->autr->next_probe_time = (time_t)parse_int(line+19, &r); 878238106Sdes (void)rbtree_insert(&anchors->autr->probe, &tp->autr->pnode); 879238106Sdes lock_basic_unlock(&tp->lock); 880238106Sdes lock_basic_unlock(&anchors->lock); 881238106Sdes } else if(strncmp(line, ";;query_failed: ", 16) == 0) { 882238106Sdes if(!tp) return -1; 883238106Sdes lock_basic_lock(&tp->lock); 884238106Sdes tp->autr->query_failed = (uint8_t)parse_int(line+16, &r); 885238106Sdes lock_basic_unlock(&tp->lock); 886238106Sdes } else if(strncmp(line, ";;query_interval: ", 18) == 0) { 887238106Sdes if(!tp) return -1; 888238106Sdes lock_basic_lock(&tp->lock); 889269257Sdes tp->autr->query_interval = (time_t)parse_int(line+18, &r); 890238106Sdes lock_basic_unlock(&tp->lock); 891238106Sdes } else if(strncmp(line, ";;retry_time: ", 14) == 0) { 892238106Sdes if(!tp) return -1; 893238106Sdes lock_basic_lock(&tp->lock); 894269257Sdes tp->autr->retry_time = (time_t)parse_int(line+14, &r); 895238106Sdes lock_basic_unlock(&tp->lock); 896238106Sdes } 897238106Sdes return r; 898238106Sdes} 899238106Sdes 900238106Sdes/** handle origin lines */ 901238106Sdesstatic int 902269257Sdeshandle_origin(char* line, uint8_t** origin, size_t* origin_len) 903238106Sdes{ 904269257Sdes size_t len = 0; 905285206Sdes while(isspace((unsigned char)*line)) 906238106Sdes line++; 907238106Sdes if(strncmp(line, "$ORIGIN", 7) != 0) 908238106Sdes return 0; 909269257Sdes free(*origin); 910238106Sdes line += 7; 911285206Sdes while(isspace((unsigned char)*line)) 912238106Sdes line++; 913269257Sdes *origin = sldns_str2wire_dname(line, &len); 914269257Sdes *origin_len = len; 915238106Sdes if(!*origin) 916238106Sdes log_warn("malloc failure or parse error in $ORIGIN"); 917238106Sdes return 1; 918238106Sdes} 919238106Sdes 920238106Sdes/** Read one line and put multiline RRs onto one line string */ 921238106Sdesstatic int 922238106Sdesread_multiline(char* buf, size_t len, FILE* in, int* linenr) 923238106Sdes{ 924238106Sdes char* pos = buf; 925238106Sdes size_t left = len; 926238106Sdes int depth = 0; 927238106Sdes buf[len-1] = 0; 928238106Sdes while(left > 0 && fgets(pos, (int)left, in) != NULL) { 929238106Sdes size_t i, poslen = strlen(pos); 930238106Sdes (*linenr)++; 931238106Sdes 932238106Sdes /* check what the new depth is after the line */ 933238106Sdes /* this routine cannot handle braces inside quotes, 934238106Sdes say for TXT records, but this routine only has to read keys */ 935238106Sdes for(i=0; i<poslen; i++) { 936238106Sdes if(pos[i] == '(') { 937238106Sdes depth++; 938238106Sdes } else if(pos[i] == ')') { 939238106Sdes if(depth == 0) { 940238106Sdes log_err("mismatch: too many ')'"); 941238106Sdes return -1; 942238106Sdes } 943238106Sdes depth--; 944238106Sdes } else if(pos[i] == ';') { 945238106Sdes break; 946238106Sdes } 947238106Sdes } 948238106Sdes 949238106Sdes /* normal oneline or last line: keeps newline and comments */ 950238106Sdes if(depth == 0) { 951238106Sdes return 1; 952238106Sdes } 953238106Sdes 954238106Sdes /* more lines expected, snip off comments and newline */ 955238106Sdes if(poslen>0) 956238106Sdes pos[poslen-1] = 0; /* strip newline */ 957238106Sdes if(strchr(pos, ';')) 958238106Sdes strchr(pos, ';')[0] = 0; /* strip comments */ 959238106Sdes 960238106Sdes /* move to paste other lines behind this one */ 961238106Sdes poslen = strlen(pos); 962238106Sdes pos += poslen; 963238106Sdes left -= poslen; 964238106Sdes /* the newline is changed into a space */ 965238106Sdes if(left <= 2 /* space and eos */) { 966238106Sdes log_err("line too long"); 967238106Sdes return -1; 968238106Sdes } 969238106Sdes pos[0] = ' '; 970238106Sdes pos[1] = 0; 971238106Sdes pos += 1; 972238106Sdes left -= 1; 973238106Sdes } 974238106Sdes if(depth != 0) { 975238106Sdes log_err("mismatch: too many '('"); 976238106Sdes return -1; 977238106Sdes } 978238106Sdes if(pos != buf) 979238106Sdes return 1; 980238106Sdes return 0; 981238106Sdes} 982238106Sdes 983238106Sdesint autr_read_file(struct val_anchors* anchors, const char* nm) 984238106Sdes{ 985238106Sdes /* the file descriptor */ 986238106Sdes FILE* fd; 987238106Sdes /* keep track of line numbers */ 988238106Sdes int line_nr = 0; 989238106Sdes /* single line */ 990238106Sdes char line[10240]; 991238106Sdes /* trust point being read */ 992238106Sdes struct trust_anchor *tp = NULL, *tp2; 993238106Sdes int r; 994238106Sdes /* for $ORIGIN parsing */ 995269257Sdes uint8_t *origin=NULL, *prev=NULL; 996269257Sdes size_t origin_len=0, prev_len=0; 997238106Sdes 998238106Sdes if (!(fd = fopen(nm, "r"))) { 999238106Sdes log_err("unable to open %s for reading: %s", 1000238106Sdes nm, strerror(errno)); 1001238106Sdes return 0; 1002238106Sdes } 1003238106Sdes verbose(VERB_ALGO, "reading autotrust anchor file %s", nm); 1004238106Sdes while ( (r=read_multiline(line, sizeof(line), fd, &line_nr)) != 0) { 1005238106Sdes if(r == -1 || (r = parse_var_line(line, anchors, &tp)) == -1) { 1006238106Sdes log_err("could not parse auto-trust-anchor-file " 1007238106Sdes "%s line %d", nm, line_nr); 1008238106Sdes fclose(fd); 1009269257Sdes free(origin); 1010269257Sdes free(prev); 1011238106Sdes return 0; 1012238106Sdes } else if(r == 1) { 1013238106Sdes continue; 1014238106Sdes } else if(r == 2) { 1015238106Sdes log_warn("trust anchor %s has been revoked", nm); 1016238106Sdes fclose(fd); 1017269257Sdes free(origin); 1018269257Sdes free(prev); 1019238106Sdes return 1; 1020238106Sdes } 1021238106Sdes if (!str_contains_data(line, ';')) 1022238106Sdes continue; /* empty lines allowed */ 1023269257Sdes if(handle_origin(line, &origin, &origin_len)) 1024238106Sdes continue; 1025238106Sdes r = 0; 1026269257Sdes if(!(tp2=load_trustanchor(anchors, line, nm, origin, 1027269257Sdes origin_len, &prev, &prev_len, &r))) { 1028238106Sdes if(!r) log_err("failed to load trust anchor from %s " 1029238106Sdes "at line %i, skipping", nm, line_nr); 1030238106Sdes /* try to do the rest */ 1031238106Sdes continue; 1032238106Sdes } 1033238106Sdes if(tp && tp != tp2) { 1034238106Sdes log_err("file %s has mismatching data inside: " 1035238106Sdes "the file may only contain keys for one name, " 1036238106Sdes "remove keys for other domain names", nm); 1037238106Sdes fclose(fd); 1038269257Sdes free(origin); 1039269257Sdes free(prev); 1040238106Sdes return 0; 1041238106Sdes } 1042238106Sdes tp = tp2; 1043238106Sdes } 1044238106Sdes fclose(fd); 1045269257Sdes free(origin); 1046269257Sdes free(prev); 1047238106Sdes if(!tp) { 1048238106Sdes log_err("failed to read %s", nm); 1049238106Sdes return 0; 1050238106Sdes } 1051238106Sdes 1052238106Sdes /* now assemble the data into DNSKEY and DS packed rrsets */ 1053238106Sdes lock_basic_lock(&tp->lock); 1054238106Sdes if(!autr_assemble(tp)) { 1055238106Sdes lock_basic_unlock(&tp->lock); 1056238106Sdes log_err("malloc failure assembling %s", nm); 1057238106Sdes return 0; 1058238106Sdes } 1059238106Sdes lock_basic_unlock(&tp->lock); 1060238106Sdes return 1; 1061238106Sdes} 1062238106Sdes 1063238106Sdes/** string for a trustanchor state */ 1064238106Sdesstatic const char* 1065238106Sdestrustanchor_state2str(autr_state_t s) 1066238106Sdes{ 1067238106Sdes switch (s) { 1068238106Sdes case AUTR_STATE_START: return " START "; 1069238106Sdes case AUTR_STATE_ADDPEND: return " ADDPEND "; 1070238106Sdes case AUTR_STATE_VALID: return " VALID "; 1071238106Sdes case AUTR_STATE_MISSING: return " MISSING "; 1072238106Sdes case AUTR_STATE_REVOKED: return " REVOKED "; 1073238106Sdes case AUTR_STATE_REMOVED: return " REMOVED "; 1074238106Sdes } 1075238106Sdes return " UNKNOWN "; 1076238106Sdes} 1077238106Sdes 1078238106Sdes/** print ID to file */ 1079238106Sdesstatic int 1080269257Sdesprint_id(FILE* out, char* fname, uint8_t* nm, size_t nmlen, uint16_t dclass) 1081238106Sdes{ 1082269257Sdes char* s = sldns_wire2str_dname(nm, nmlen); 1083269257Sdes if(!s) { 1084269257Sdes log_err("malloc failure in write to %s", fname); 1085269257Sdes return 0; 1086269257Sdes } 1087269257Sdes if(fprintf(out, ";;id: %s %d\n", s, (int)dclass) < 0) { 1088238106Sdes log_err("could not write to %s: %s", fname, strerror(errno)); 1089269257Sdes free(s); 1090238106Sdes return 0; 1091238106Sdes } 1092269257Sdes free(s); 1093238106Sdes return 1; 1094238106Sdes} 1095238106Sdes 1096238106Sdesstatic int 1097269257Sdesautr_write_contents(FILE* out, char* fn, struct trust_anchor* tp) 1098238106Sdes{ 1099238106Sdes char tmi[32]; 1100238106Sdes struct autr_ta* ta; 1101238106Sdes char* str; 1102238106Sdes 1103238106Sdes /* write pretty header */ 1104238106Sdes if(fprintf(out, "; autotrust trust anchor file\n") < 0) { 1105238106Sdes log_err("could not write to %s: %s", fn, strerror(errno)); 1106238106Sdes return 0; 1107238106Sdes } 1108238106Sdes if(tp->autr->revoked) { 1109238106Sdes if(fprintf(out, ";;REVOKED\n") < 0 || 1110238106Sdes fprintf(out, "; The zone has all keys revoked, and is\n" 1111238106Sdes "; considered as if it has no trust anchors.\n" 1112238106Sdes "; the remainder of the file is the last probe.\n" 1113238106Sdes "; to restart the trust anchor, overwrite this file.\n" 1114238106Sdes "; with one containing valid DNSKEYs or DSes.\n") < 0) { 1115238106Sdes log_err("could not write to %s: %s", fn, strerror(errno)); 1116238106Sdes return 0; 1117238106Sdes } 1118238106Sdes } 1119269257Sdes if(!print_id(out, fn, tp->name, tp->namelen, tp->dclass)) { 1120238106Sdes return 0; 1121238106Sdes } 1122238106Sdes if(fprintf(out, ";;last_queried: %u ;;%s", 1123238106Sdes (unsigned int)tp->autr->last_queried, 1124238106Sdes ctime_r(&(tp->autr->last_queried), tmi)) < 0 || 1125238106Sdes fprintf(out, ";;last_success: %u ;;%s", 1126238106Sdes (unsigned int)tp->autr->last_success, 1127238106Sdes ctime_r(&(tp->autr->last_success), tmi)) < 0 || 1128238106Sdes fprintf(out, ";;next_probe_time: %u ;;%s", 1129238106Sdes (unsigned int)tp->autr->next_probe_time, 1130238106Sdes ctime_r(&(tp->autr->next_probe_time), tmi)) < 0 || 1131238106Sdes fprintf(out, ";;query_failed: %d\n", (int)tp->autr->query_failed)<0 1132238106Sdes || fprintf(out, ";;query_interval: %d\n", 1133238106Sdes (int)tp->autr->query_interval) < 0 || 1134238106Sdes fprintf(out, ";;retry_time: %d\n", (int)tp->autr->retry_time) < 0) { 1135238106Sdes log_err("could not write to %s: %s", fn, strerror(errno)); 1136238106Sdes return 0; 1137238106Sdes } 1138238106Sdes 1139238106Sdes /* write anchors */ 1140238106Sdes for(ta=tp->autr->keys; ta; ta=ta->next) { 1141238106Sdes /* by default do not store START and REMOVED keys */ 1142238106Sdes if(ta->s == AUTR_STATE_START) 1143238106Sdes continue; 1144238106Sdes if(ta->s == AUTR_STATE_REMOVED) 1145238106Sdes continue; 1146238106Sdes /* only store keys */ 1147269257Sdes if(sldns_wirerr_get_type(ta->rr, ta->rr_len, ta->dname_len) 1148269257Sdes != LDNS_RR_TYPE_DNSKEY) 1149238106Sdes continue; 1150269257Sdes str = sldns_wire2str_rr(ta->rr, ta->rr_len); 1151238106Sdes if(!str || !str[0]) { 1152238106Sdes free(str); 1153238106Sdes log_err("malloc failure writing %s", fn); 1154238106Sdes return 0; 1155238106Sdes } 1156238106Sdes str[strlen(str)-1] = 0; /* remove newline */ 1157238106Sdes if(fprintf(out, "%s ;;state=%d [%s] ;;count=%d " 1158238106Sdes ";;lastchange=%u ;;%s", str, (int)ta->s, 1159238106Sdes trustanchor_state2str(ta->s), (int)ta->pending_count, 1160238106Sdes (unsigned int)ta->last_change, 1161238106Sdes ctime_r(&(ta->last_change), tmi)) < 0) { 1162238106Sdes log_err("could not write to %s: %s", fn, strerror(errno)); 1163238106Sdes free(str); 1164238106Sdes return 0; 1165238106Sdes } 1166238106Sdes free(str); 1167238106Sdes } 1168238106Sdes return 1; 1169238106Sdes} 1170238106Sdes 1171238106Sdesvoid autr_write_file(struct module_env* env, struct trust_anchor* tp) 1172238106Sdes{ 1173238106Sdes FILE* out; 1174238106Sdes char* fname = tp->autr->file; 1175238106Sdes char tempf[2048]; 1176238106Sdes log_assert(tp->autr); 1177269257Sdes if(!env) { 1178269257Sdes log_err("autr_write_file: Module environment is NULL."); 1179269257Sdes return; 1180269257Sdes } 1181238106Sdes /* unique name with pid number and thread number */ 1182238106Sdes snprintf(tempf, sizeof(tempf), "%s.%d-%d", fname, (int)getpid(), 1183269257Sdes env->worker?*(int*)env->worker:0); 1184238106Sdes verbose(VERB_ALGO, "autotrust: write to disk: %s", tempf); 1185238106Sdes out = fopen(tempf, "w"); 1186238106Sdes if(!out) { 1187291767Sdes fatal_exit("could not open autotrust file for writing, %s: %s", 1188238106Sdes tempf, strerror(errno)); 1189238106Sdes return; 1190238106Sdes } 1191269257Sdes if(!autr_write_contents(out, tempf, tp)) { 1192238106Sdes /* failed to write contents (completely) */ 1193238106Sdes fclose(out); 1194238106Sdes unlink(tempf); 1195291767Sdes fatal_exit("could not completely write: %s", fname); 1196238106Sdes return; 1197238106Sdes } 1198294190Sdes if(fflush(out) != 0) 1199294190Sdes log_err("could not fflush(%s): %s", fname, strerror(errno)); 1200294190Sdes#ifdef HAVE_FSYNC 1201294190Sdes if(fsync(fileno(out)) != 0) 1202294190Sdes log_err("could not fsync(%s): %s", fname, strerror(errno)); 1203294190Sdes#else 1204294190Sdes FlushFileBuffers((HANDLE)_fileno(out)); 1205294190Sdes#endif 1206269257Sdes if(fclose(out) != 0) { 1207291767Sdes fatal_exit("could not complete write: %s: %s", 1208269257Sdes fname, strerror(errno)); 1209269257Sdes unlink(tempf); 1210269257Sdes return; 1211269257Sdes } 1212238106Sdes /* success; overwrite actual file */ 1213238106Sdes verbose(VERB_ALGO, "autotrust: replaced %s", fname); 1214238106Sdes#ifdef UB_ON_WINDOWS 1215238106Sdes (void)unlink(fname); /* windows does not replace file with rename() */ 1216238106Sdes#endif 1217238106Sdes if(rename(tempf, fname) < 0) { 1218291767Sdes fatal_exit("rename(%s to %s): %s", tempf, fname, strerror(errno)); 1219238106Sdes } 1220238106Sdes} 1221238106Sdes 1222238106Sdes/** 1223238106Sdes * Verify if dnskey works for trust point 1224238106Sdes * @param env: environment (with time) for verification 1225238106Sdes * @param ve: validator environment (with options) for verification. 1226238106Sdes * @param tp: trust point to verify with 1227238106Sdes * @param rrset: DNSKEY rrset to verify. 1228238106Sdes * @return false on failure, true if verification successful. 1229238106Sdes */ 1230238106Sdesstatic int 1231238106Sdesverify_dnskey(struct module_env* env, struct val_env* ve, 1232238106Sdes struct trust_anchor* tp, struct ub_packed_rrset_key* rrset) 1233238106Sdes{ 1234238106Sdes char* reason = NULL; 1235238106Sdes uint8_t sigalg[ALGO_NEEDS_MAX+1]; 1236291767Sdes int downprot = env->cfg->harden_algo_downgrade; 1237238106Sdes enum sec_status sec = val_verify_DNSKEY_with_TA(env, ve, rrset, 1238238106Sdes tp->ds_rrset, tp->dnskey_rrset, downprot?sigalg:NULL, &reason); 1239238106Sdes /* sigalg is ignored, it returns algorithms signalled to exist, but 1240238106Sdes * in 5011 there are no other rrsets to check. if downprot is 1241238106Sdes * enabled, then it checks that the DNSKEY is signed with all 1242238106Sdes * algorithms available in the trust store. */ 1243238106Sdes verbose(VERB_ALGO, "autotrust: validate DNSKEY with anchor: %s", 1244238106Sdes sec_status_to_string(sec)); 1245238106Sdes return sec == sec_status_secure; 1246238106Sdes} 1247238106Sdes 1248269257Sdesstatic int32_t 1249269257Sdesrrsig_get_expiry(uint8_t* d, size_t len) 1250269257Sdes{ 1251269257Sdes /* rrsig: 2(rdlen), 2(type) 1(alg) 1(v) 4(origttl), then 4(expi), (4)incep) */ 1252269257Sdes if(len < 2+8+4) 1253269257Sdes return 0; 1254269257Sdes return sldns_read_uint32(d+2+8); 1255269257Sdes} 1256269257Sdes 1257238106Sdes/** Find minimum expiration interval from signatures */ 1258269257Sdesstatic time_t 1259269257Sdesmin_expiry(struct module_env* env, struct packed_rrset_data* dd) 1260238106Sdes{ 1261238106Sdes size_t i; 1262269257Sdes int32_t t, r = 15 * 24 * 3600; /* 15 days max */ 1263269257Sdes for(i=dd->count; i<dd->count+dd->rrsig_count; i++) { 1264269257Sdes t = rrsig_get_expiry(dd->rr_data[i], dd->rr_len[i]); 1265269257Sdes if((int32_t)t - (int32_t)*env->now > 0) { 1266269257Sdes t -= (int32_t)*env->now; 1267238106Sdes if(t < r) 1268238106Sdes r = t; 1269238106Sdes } 1270238106Sdes } 1271269257Sdes return (time_t)r; 1272238106Sdes} 1273238106Sdes 1274238106Sdes/** Is rr self-signed revoked key */ 1275238106Sdesstatic int 1276238106Sdesrr_is_selfsigned_revoked(struct module_env* env, struct val_env* ve, 1277238106Sdes struct ub_packed_rrset_key* dnskey_rrset, size_t i) 1278238106Sdes{ 1279238106Sdes enum sec_status sec; 1280238106Sdes char* reason = NULL; 1281238106Sdes verbose(VERB_ALGO, "seen REVOKE flag, check self-signed, rr %d", 1282238106Sdes (int)i); 1283238106Sdes /* no algorithm downgrade protection necessary, if it is selfsigned 1284238106Sdes * revoked it can be removed. */ 1285238106Sdes sec = dnskey_verify_rrset(env, ve, dnskey_rrset, dnskey_rrset, i, 1286238106Sdes &reason); 1287238106Sdes return (sec == sec_status_secure); 1288238106Sdes} 1289238106Sdes 1290238106Sdes/** Set fetched value */ 1291238106Sdesstatic void 1292238106Sdesseen_trustanchor(struct autr_ta* ta, uint8_t seen) 1293238106Sdes{ 1294238106Sdes ta->fetched = seen; 1295238106Sdes if(ta->pending_count < 250) /* no numerical overflow, please */ 1296238106Sdes ta->pending_count++; 1297238106Sdes} 1298238106Sdes 1299238106Sdes/** set revoked value */ 1300238106Sdesstatic void 1301238106Sdesseen_revoked_trustanchor(struct autr_ta* ta, uint8_t revoked) 1302238106Sdes{ 1303238106Sdes ta->revoked = revoked; 1304238106Sdes} 1305238106Sdes 1306238106Sdes/** revoke a trust anchor */ 1307238106Sdesstatic void 1308238106Sdesrevoke_dnskey(struct autr_ta* ta, int off) 1309238106Sdes{ 1310269257Sdes uint16_t flags; 1311269257Sdes uint8_t* data; 1312269257Sdes if(sldns_wirerr_get_type(ta->rr, ta->rr_len, ta->dname_len) != 1313269257Sdes LDNS_RR_TYPE_DNSKEY) 1314238106Sdes return; 1315269257Sdes if(sldns_wirerr_get_rdatalen(ta->rr, ta->rr_len, ta->dname_len) < 2) 1316269257Sdes return; 1317269257Sdes data = sldns_wirerr_get_rdata(ta->rr, ta->rr_len, ta->dname_len); 1318269257Sdes flags = sldns_read_uint16(data); 1319238106Sdes if (off && (flags&LDNS_KEY_REVOKE_KEY)) 1320238106Sdes flags ^= LDNS_KEY_REVOKE_KEY; /* flip */ 1321238106Sdes else 1322238106Sdes flags |= LDNS_KEY_REVOKE_KEY; 1323269257Sdes sldns_write_uint16(data, flags); 1324238106Sdes} 1325238106Sdes 1326269257Sdes/** Compare two RRs skipping the REVOKED bit. Pass rdata(no len) */ 1327238106Sdesstatic int 1328269257Sdesdnskey_compare_skip_revbit(uint8_t* a, size_t a_len, uint8_t* b, size_t b_len) 1329238106Sdes{ 1330269257Sdes size_t i; 1331269257Sdes if(a_len != b_len) 1332269257Sdes return -1; 1333238106Sdes /* compare RRs RDATA byte for byte. */ 1334269257Sdes for(i = 0; i < a_len; i++) 1335238106Sdes { 1336269257Sdes uint8_t rdf1, rdf2; 1337269257Sdes rdf1 = a[i]; 1338269257Sdes rdf2 = b[i]; 1339269257Sdes if(i==1) { 1340238106Sdes /* this is the second part of the flags field */ 1341269257Sdes rdf1 |= LDNS_KEY_REVOKE_KEY; 1342269257Sdes rdf2 |= LDNS_KEY_REVOKE_KEY; 1343238106Sdes } 1344269257Sdes if (rdf1 < rdf2) return -1; 1345269257Sdes else if (rdf1 > rdf2) return 1; 1346238106Sdes } 1347238106Sdes return 0; 1348238106Sdes} 1349238106Sdes 1350238106Sdes 1351269257Sdes/** compare trust anchor with rdata, 0 if equal. Pass rdata(no len) */ 1352238106Sdesstatic int 1353269257Sdesta_compare(struct autr_ta* a, uint16_t t, uint8_t* b, size_t b_len) 1354238106Sdes{ 1355269257Sdes if(!a) return -1; 1356269257Sdes else if(!b) return -1; 1357269257Sdes else if(sldns_wirerr_get_type(a->rr, a->rr_len, a->dname_len) != t) 1358269257Sdes return (int)sldns_wirerr_get_type(a->rr, a->rr_len, 1359269257Sdes a->dname_len) - (int)t; 1360269257Sdes else if(t == LDNS_RR_TYPE_DNSKEY) { 1361269257Sdes return dnskey_compare_skip_revbit( 1362269257Sdes sldns_wirerr_get_rdata(a->rr, a->rr_len, a->dname_len), 1363269257Sdes sldns_wirerr_get_rdatalen(a->rr, a->rr_len, 1364269257Sdes a->dname_len), b, b_len); 1365238106Sdes } 1366269257Sdes else if(t == LDNS_RR_TYPE_DS) { 1367269257Sdes if(sldns_wirerr_get_rdatalen(a->rr, a->rr_len, a->dname_len) != 1368269257Sdes b_len) 1369269257Sdes return -1; 1370269257Sdes return memcmp(sldns_wirerr_get_rdata(a->rr, 1371269257Sdes a->rr_len, a->dname_len), b, b_len); 1372269257Sdes } 1373269257Sdes return -1; 1374238106Sdes} 1375238106Sdes 1376238106Sdes/** 1377238106Sdes * Find key 1378238106Sdes * @param tp: to search in 1379269257Sdes * @param t: rr type of the rdata. 1380269257Sdes * @param rdata: to look for (no rdatalen in it) 1381269257Sdes * @param rdata_len: length of rdata 1382238106Sdes * @param result: returns NULL or the ta key looked for. 1383238106Sdes * @return false on malloc failure during search. if true examine result. 1384238106Sdes */ 1385238106Sdesstatic int 1386269257Sdesfind_key(struct trust_anchor* tp, uint16_t t, uint8_t* rdata, size_t rdata_len, 1387269257Sdes struct autr_ta** result) 1388238106Sdes{ 1389238106Sdes struct autr_ta* ta; 1390269257Sdes if(!tp || !rdata) { 1391269257Sdes *result = NULL; 1392238106Sdes return 0; 1393269257Sdes } 1394238106Sdes for(ta=tp->autr->keys; ta; ta=ta->next) { 1395269257Sdes if(ta_compare(ta, t, rdata, rdata_len) == 0) { 1396238106Sdes *result = ta; 1397238106Sdes return 1; 1398238106Sdes } 1399238106Sdes } 1400238106Sdes *result = NULL; 1401238106Sdes return 1; 1402238106Sdes} 1403238106Sdes 1404269257Sdes/** add key and clone RR and tp already locked. rdata without rdlen. */ 1405238106Sdesstatic struct autr_ta* 1406269257Sdesadd_key(struct trust_anchor* tp, uint32_t ttl, uint8_t* rdata, size_t rdata_len) 1407238106Sdes{ 1408238106Sdes struct autr_ta* ta; 1409269257Sdes uint8_t* rr; 1410269257Sdes size_t rr_len, dname_len; 1411269257Sdes uint16_t rrtype = htons(LDNS_RR_TYPE_DNSKEY); 1412269257Sdes uint16_t rrclass = htons(LDNS_RR_CLASS_IN); 1413269257Sdes uint16_t rdlen = htons(rdata_len); 1414269257Sdes dname_len = tp->namelen; 1415269257Sdes ttl = htonl(ttl); 1416269257Sdes rr_len = dname_len + 10 /* type,class,ttl,rdatalen */ + rdata_len; 1417269257Sdes rr = (uint8_t*)malloc(rr_len); 1418269257Sdes if(!rr) return NULL; 1419269257Sdes memmove(rr, tp->name, tp->namelen); 1420269257Sdes memmove(rr+dname_len, &rrtype, 2); 1421269257Sdes memmove(rr+dname_len+2, &rrclass, 2); 1422269257Sdes memmove(rr+dname_len+4, &ttl, 4); 1423269257Sdes memmove(rr+dname_len+8, &rdlen, 2); 1424269257Sdes memmove(rr+dname_len+10, rdata, rdata_len); 1425269257Sdes ta = autr_ta_create(rr, rr_len, dname_len); 1426238106Sdes if(!ta) { 1427269257Sdes /* rr freed in autr_ta_create */ 1428238106Sdes return NULL; 1429238106Sdes } 1430238106Sdes /* link in, tp already locked */ 1431238106Sdes ta->next = tp->autr->keys; 1432238106Sdes tp->autr->keys = ta; 1433238106Sdes return ta; 1434238106Sdes} 1435238106Sdes 1436238106Sdes/** get TTL from DNSKEY rrset */ 1437269257Sdesstatic time_t 1438238106Sdeskey_ttl(struct ub_packed_rrset_key* k) 1439238106Sdes{ 1440238106Sdes struct packed_rrset_data* d = (struct packed_rrset_data*)k->entry.data; 1441238106Sdes return d->ttl; 1442238106Sdes} 1443238106Sdes 1444238106Sdes/** update the time values for the trustpoint */ 1445238106Sdesstatic void 1446269257Sdesset_tp_times(struct trust_anchor* tp, time_t rrsig_exp_interval, 1447269257Sdes time_t origttl, int* changed) 1448238106Sdes{ 1449269257Sdes time_t x, qi = tp->autr->query_interval, rt = tp->autr->retry_time; 1450238106Sdes 1451238106Sdes /* x = MIN(15days, ttl/2, expire/2) */ 1452238106Sdes x = 15 * 24 * 3600; 1453238106Sdes if(origttl/2 < x) 1454238106Sdes x = origttl/2; 1455238106Sdes if(rrsig_exp_interval/2 < x) 1456238106Sdes x = rrsig_exp_interval/2; 1457238106Sdes /* MAX(1hr, x) */ 1458291767Sdes if(!autr_permit_small_holddown) { 1459291767Sdes if(x < 3600) 1460291767Sdes tp->autr->query_interval = 3600; 1461291767Sdes else tp->autr->query_interval = x; 1462291767Sdes } else tp->autr->query_interval = x; 1463238106Sdes 1464238106Sdes /* x= MIN(1day, ttl/10, expire/10) */ 1465238106Sdes x = 24 * 3600; 1466238106Sdes if(origttl/10 < x) 1467238106Sdes x = origttl/10; 1468238106Sdes if(rrsig_exp_interval/10 < x) 1469238106Sdes x = rrsig_exp_interval/10; 1470238106Sdes /* MAX(1hr, x) */ 1471291767Sdes if(!autr_permit_small_holddown) { 1472291767Sdes if(x < 3600) 1473291767Sdes tp->autr->retry_time = 3600; 1474291767Sdes else tp->autr->retry_time = x; 1475291767Sdes } else tp->autr->retry_time = x; 1476238106Sdes 1477238106Sdes if(qi != tp->autr->query_interval || rt != tp->autr->retry_time) { 1478238106Sdes *changed = 1; 1479238106Sdes verbose(VERB_ALGO, "orig_ttl is %d", (int)origttl); 1480238106Sdes verbose(VERB_ALGO, "rrsig_exp_interval is %d", 1481238106Sdes (int)rrsig_exp_interval); 1482238106Sdes verbose(VERB_ALGO, "query_interval: %d, retry_time: %d", 1483238106Sdes (int)tp->autr->query_interval, 1484238106Sdes (int)tp->autr->retry_time); 1485238106Sdes } 1486238106Sdes} 1487238106Sdes 1488238106Sdes/** init events to zero */ 1489238106Sdesstatic void 1490238106Sdesinit_events(struct trust_anchor* tp) 1491238106Sdes{ 1492238106Sdes struct autr_ta* ta; 1493238106Sdes for(ta=tp->autr->keys; ta; ta=ta->next) { 1494238106Sdes ta->fetched = 0; 1495238106Sdes } 1496238106Sdes} 1497238106Sdes 1498238106Sdes/** check for revoked keys without trusting any other information */ 1499238106Sdesstatic void 1500238106Sdescheck_contains_revoked(struct module_env* env, struct val_env* ve, 1501238106Sdes struct trust_anchor* tp, struct ub_packed_rrset_key* dnskey_rrset, 1502238106Sdes int* changed) 1503238106Sdes{ 1504269257Sdes struct packed_rrset_data* dd = (struct packed_rrset_data*) 1505269257Sdes dnskey_rrset->entry.data; 1506238106Sdes size_t i; 1507269257Sdes log_assert(ntohs(dnskey_rrset->rk.type) == LDNS_RR_TYPE_DNSKEY); 1508269257Sdes for(i=0; i<dd->count; i++) { 1509238106Sdes struct autr_ta* ta = NULL; 1510269257Sdes if(!rr_is_dnskey_sep(ntohs(dnskey_rrset->rk.type), 1511269257Sdes dd->rr_data[i]+2, dd->rr_len[i]-2) || 1512269257Sdes !rr_is_dnskey_revoked(ntohs(dnskey_rrset->rk.type), 1513269257Sdes dd->rr_data[i]+2, dd->rr_len[i]-2)) 1514238106Sdes continue; /* not a revoked KSK */ 1515269257Sdes if(!find_key(tp, ntohs(dnskey_rrset->rk.type), 1516269257Sdes dd->rr_data[i]+2, dd->rr_len[i]-2, &ta)) { 1517238106Sdes log_err("malloc failure"); 1518238106Sdes continue; /* malloc fail in compare*/ 1519238106Sdes } 1520238106Sdes if(!ta) 1521238106Sdes continue; /* key not found */ 1522238106Sdes if(rr_is_selfsigned_revoked(env, ve, dnskey_rrset, i)) { 1523238106Sdes /* checked if there is an rrsig signed by this key. */ 1524269257Sdes /* same keytag, but stored can be revoked already, so 1525269257Sdes * compare keytags, with +0 or +128(REVOKE flag) */ 1526269257Sdes log_assert(dnskey_calc_keytag(dnskey_rrset, i)-128 == 1527269257Sdes sldns_calc_keytag_raw(sldns_wirerr_get_rdata( 1528269257Sdes ta->rr, ta->rr_len, ta->dname_len), 1529269257Sdes sldns_wirerr_get_rdatalen(ta->rr, ta->rr_len, 1530269257Sdes ta->dname_len)) || 1531269257Sdes dnskey_calc_keytag(dnskey_rrset, i) == 1532269257Sdes sldns_calc_keytag_raw(sldns_wirerr_get_rdata( 1533269257Sdes ta->rr, ta->rr_len, ta->dname_len), 1534269257Sdes sldns_wirerr_get_rdatalen(ta->rr, ta->rr_len, 1535269257Sdes ta->dname_len))); /* checks conversion*/ 1536238106Sdes verbose_key(ta, VERB_ALGO, "is self-signed revoked"); 1537238106Sdes if(!ta->revoked) 1538238106Sdes *changed = 1; 1539238106Sdes seen_revoked_trustanchor(ta, 1); 1540238106Sdes do_revoked(env, ta, changed); 1541238106Sdes } 1542238106Sdes } 1543238106Sdes} 1544238106Sdes 1545238106Sdes/** See if a DNSKEY is verified by one of the DSes */ 1546238106Sdesstatic int 1547238106Sdeskey_matches_a_ds(struct module_env* env, struct val_env* ve, 1548238106Sdes struct ub_packed_rrset_key* dnskey_rrset, size_t key_idx, 1549238106Sdes struct ub_packed_rrset_key* ds_rrset) 1550238106Sdes{ 1551238106Sdes struct packed_rrset_data* dd = (struct packed_rrset_data*) 1552238106Sdes ds_rrset->entry.data; 1553238106Sdes size_t ds_idx, num = dd->count; 1554238106Sdes int d = val_favorite_ds_algo(ds_rrset); 1555238106Sdes char* reason = ""; 1556238106Sdes for(ds_idx=0; ds_idx<num; ds_idx++) { 1557238106Sdes if(!ds_digest_algo_is_supported(ds_rrset, ds_idx) || 1558238106Sdes !ds_key_algo_is_supported(ds_rrset, ds_idx) || 1559238106Sdes ds_get_digest_algo(ds_rrset, ds_idx) != d) 1560238106Sdes continue; 1561238106Sdes if(ds_get_key_algo(ds_rrset, ds_idx) 1562238106Sdes != dnskey_get_algo(dnskey_rrset, key_idx) 1563238106Sdes || dnskey_calc_keytag(dnskey_rrset, key_idx) 1564238106Sdes != ds_get_keytag(ds_rrset, ds_idx)) { 1565238106Sdes continue; 1566238106Sdes } 1567238106Sdes if(!ds_digest_match_dnskey(env, dnskey_rrset, key_idx, 1568238106Sdes ds_rrset, ds_idx)) { 1569238106Sdes verbose(VERB_ALGO, "DS match attempt failed"); 1570238106Sdes continue; 1571238106Sdes } 1572238106Sdes if(dnskey_verify_rrset(env, ve, dnskey_rrset, 1573238106Sdes dnskey_rrset, key_idx, &reason) == sec_status_secure) { 1574238106Sdes return 1; 1575238106Sdes } else { 1576238106Sdes verbose(VERB_ALGO, "DS match failed because the key " 1577238106Sdes "does not verify the keyset: %s", reason); 1578238106Sdes } 1579238106Sdes } 1580238106Sdes return 0; 1581238106Sdes} 1582238106Sdes 1583238106Sdes/** Set update events */ 1584238106Sdesstatic int 1585238106Sdesupdate_events(struct module_env* env, struct val_env* ve, 1586238106Sdes struct trust_anchor* tp, struct ub_packed_rrset_key* dnskey_rrset, 1587238106Sdes int* changed) 1588238106Sdes{ 1589269257Sdes struct packed_rrset_data* dd = (struct packed_rrset_data*) 1590269257Sdes dnskey_rrset->entry.data; 1591238106Sdes size_t i; 1592269257Sdes log_assert(ntohs(dnskey_rrset->rk.type) == LDNS_RR_TYPE_DNSKEY); 1593238106Sdes init_events(tp); 1594269257Sdes for(i=0; i<dd->count; i++) { 1595238106Sdes struct autr_ta* ta = NULL; 1596269257Sdes if(!rr_is_dnskey_sep(ntohs(dnskey_rrset->rk.type), 1597269257Sdes dd->rr_data[i]+2, dd->rr_len[i]-2)) 1598238106Sdes continue; 1599269257Sdes if(rr_is_dnskey_revoked(ntohs(dnskey_rrset->rk.type), 1600269257Sdes dd->rr_data[i]+2, dd->rr_len[i]-2)) { 1601238106Sdes /* self-signed revoked keys already detected before, 1602238106Sdes * other revoked keys are not 'added' again */ 1603238106Sdes continue; 1604238106Sdes } 1605238106Sdes /* is a key of this type supported?. Note rr_list and 1606238106Sdes * packed_rrset are in the same order. */ 1607238106Sdes if(!dnskey_algo_is_supported(dnskey_rrset, i)) { 1608238106Sdes /* skip unknown algorithm key, it is useless to us */ 1609238106Sdes log_nametypeclass(VERB_DETAIL, "trust point has " 1610238106Sdes "unsupported algorithm at", 1611238106Sdes tp->name, LDNS_RR_TYPE_DNSKEY, tp->dclass); 1612238106Sdes continue; 1613238106Sdes } 1614238106Sdes 1615238106Sdes /* is it new? if revocation bit set, find the unrevoked key */ 1616269257Sdes if(!find_key(tp, ntohs(dnskey_rrset->rk.type), 1617269257Sdes dd->rr_data[i]+2, dd->rr_len[i]-2, &ta)) { 1618238106Sdes return 0; 1619238106Sdes } 1620238106Sdes if(!ta) { 1621269257Sdes ta = add_key(tp, (uint32_t)dd->rr_ttl[i], 1622269257Sdes dd->rr_data[i]+2, dd->rr_len[i]-2); 1623238106Sdes *changed = 1; 1624238106Sdes /* first time seen, do we have DSes? if match: VALID */ 1625238106Sdes if(ta && tp->ds_rrset && key_matches_a_ds(env, ve, 1626238106Sdes dnskey_rrset, i, tp->ds_rrset)) { 1627238106Sdes verbose_key(ta, VERB_ALGO, "verified by DS"); 1628238106Sdes ta->s = AUTR_STATE_VALID; 1629238106Sdes } 1630238106Sdes } 1631238106Sdes if(!ta) { 1632238106Sdes return 0; 1633238106Sdes } 1634238106Sdes seen_trustanchor(ta, 1); 1635238106Sdes verbose_key(ta, VERB_ALGO, "in DNS response"); 1636238106Sdes } 1637269257Sdes set_tp_times(tp, min_expiry(env, dd), key_ttl(dnskey_rrset), changed); 1638238106Sdes return 1; 1639238106Sdes} 1640238106Sdes 1641238106Sdes/** 1642238106Sdes * Check if the holddown time has already exceeded 1643238106Sdes * setting: add-holddown: add holddown timer 1644238106Sdes * setting: del-holddown: del holddown timer 1645238106Sdes * @param env: environment with current time 1646238106Sdes * @param ta: trust anchor to check for. 1647238106Sdes * @param holddown: the timer value 1648238106Sdes * @return number of seconds the holddown has passed. 1649238106Sdes */ 1650269257Sdesstatic time_t 1651269257Sdescheck_holddown(struct module_env* env, struct autr_ta* ta, 1652238106Sdes unsigned int holddown) 1653238106Sdes{ 1654269257Sdes time_t elapsed; 1655269257Sdes if(*env->now < ta->last_change) { 1656238106Sdes log_warn("time goes backwards. delaying key holddown"); 1657238106Sdes return 0; 1658238106Sdes } 1659269257Sdes elapsed = *env->now - ta->last_change; 1660269257Sdes if (elapsed > (time_t)holddown) { 1661269257Sdes return elapsed-(time_t)holddown; 1662238106Sdes } 1663269257Sdes verbose_key(ta, VERB_ALGO, "holddown time " ARG_LL "d seconds to go", 1664269257Sdes (long long) ((time_t)holddown-elapsed)); 1665238106Sdes return 0; 1666238106Sdes} 1667238106Sdes 1668238106Sdes 1669238106Sdes/** Set last_change to now */ 1670238106Sdesstatic void 1671238106Sdesreset_holddown(struct module_env* env, struct autr_ta* ta, int* changed) 1672238106Sdes{ 1673238106Sdes ta->last_change = *env->now; 1674238106Sdes *changed = 1; 1675238106Sdes} 1676238106Sdes 1677238106Sdes/** Set the state for this trust anchor */ 1678238106Sdesstatic void 1679238106Sdesset_trustanchor_state(struct module_env* env, struct autr_ta* ta, int* changed, 1680238106Sdes autr_state_t s) 1681238106Sdes{ 1682238106Sdes verbose_key(ta, VERB_ALGO, "update: %s to %s", 1683238106Sdes trustanchor_state2str(ta->s), trustanchor_state2str(s)); 1684238106Sdes ta->s = s; 1685238106Sdes reset_holddown(env, ta, changed); 1686238106Sdes} 1687238106Sdes 1688238106Sdes 1689238106Sdes/** Event: NewKey */ 1690238106Sdesstatic void 1691238106Sdesdo_newkey(struct module_env* env, struct autr_ta* anchor, int* c) 1692238106Sdes{ 1693238106Sdes if (anchor->s == AUTR_STATE_START) 1694238106Sdes set_trustanchor_state(env, anchor, c, AUTR_STATE_ADDPEND); 1695238106Sdes} 1696238106Sdes 1697238106Sdes/** Event: AddTime */ 1698238106Sdesstatic void 1699238106Sdesdo_addtime(struct module_env* env, struct autr_ta* anchor, int* c) 1700238106Sdes{ 1701238106Sdes /* This not according to RFC, this is 30 days, but the RFC demands 1702238106Sdes * MAX(30days, TTL expire time of first DNSKEY set with this key), 1703238106Sdes * The value may be too small if a very large TTL was used. */ 1704269257Sdes time_t exceeded = check_holddown(env, anchor, env->cfg->add_holddown); 1705238106Sdes if (exceeded && anchor->s == AUTR_STATE_ADDPEND) { 1706238106Sdes verbose_key(anchor, VERB_ALGO, "add-holddown time exceeded " 1707269257Sdes ARG_LL "d seconds ago, and pending-count %d", 1708269257Sdes (long long)exceeded, anchor->pending_count); 1709238106Sdes if(anchor->pending_count >= MIN_PENDINGCOUNT) { 1710238106Sdes set_trustanchor_state(env, anchor, c, AUTR_STATE_VALID); 1711238106Sdes anchor->pending_count = 0; 1712238106Sdes return; 1713238106Sdes } 1714238106Sdes verbose_key(anchor, VERB_ALGO, "add-holddown time sanity check " 1715238106Sdes "failed (pending count: %d)", anchor->pending_count); 1716238106Sdes } 1717238106Sdes} 1718238106Sdes 1719238106Sdes/** Event: RemTime */ 1720238106Sdesstatic void 1721238106Sdesdo_remtime(struct module_env* env, struct autr_ta* anchor, int* c) 1722238106Sdes{ 1723269257Sdes time_t exceeded = check_holddown(env, anchor, env->cfg->del_holddown); 1724238106Sdes if(exceeded && anchor->s == AUTR_STATE_REVOKED) { 1725238106Sdes verbose_key(anchor, VERB_ALGO, "del-holddown time exceeded " 1726269257Sdes ARG_LL "d seconds ago", (long long)exceeded); 1727238106Sdes set_trustanchor_state(env, anchor, c, AUTR_STATE_REMOVED); 1728238106Sdes } 1729238106Sdes} 1730238106Sdes 1731238106Sdes/** Event: KeyRem */ 1732238106Sdesstatic void 1733238106Sdesdo_keyrem(struct module_env* env, struct autr_ta* anchor, int* c) 1734238106Sdes{ 1735238106Sdes if(anchor->s == AUTR_STATE_ADDPEND) { 1736238106Sdes set_trustanchor_state(env, anchor, c, AUTR_STATE_START); 1737238106Sdes anchor->pending_count = 0; 1738238106Sdes } else if(anchor->s == AUTR_STATE_VALID) 1739238106Sdes set_trustanchor_state(env, anchor, c, AUTR_STATE_MISSING); 1740238106Sdes} 1741238106Sdes 1742238106Sdes/** Event: KeyPres */ 1743238106Sdesstatic void 1744238106Sdesdo_keypres(struct module_env* env, struct autr_ta* anchor, int* c) 1745238106Sdes{ 1746238106Sdes if(anchor->s == AUTR_STATE_MISSING) 1747238106Sdes set_trustanchor_state(env, anchor, c, AUTR_STATE_VALID); 1748238106Sdes} 1749238106Sdes 1750238106Sdes/* Event: Revoked */ 1751238106Sdesstatic void 1752238106Sdesdo_revoked(struct module_env* env, struct autr_ta* anchor, int* c) 1753238106Sdes{ 1754238106Sdes if(anchor->s == AUTR_STATE_VALID || anchor->s == AUTR_STATE_MISSING) { 1755238106Sdes set_trustanchor_state(env, anchor, c, AUTR_STATE_REVOKED); 1756238106Sdes verbose_key(anchor, VERB_ALGO, "old id, prior to revocation"); 1757238106Sdes revoke_dnskey(anchor, 0); 1758238106Sdes verbose_key(anchor, VERB_ALGO, "new id, after revocation"); 1759238106Sdes } 1760238106Sdes} 1761238106Sdes 1762238106Sdes/** Do statestable transition matrix for anchor */ 1763238106Sdesstatic void 1764238106Sdesanchor_state_update(struct module_env* env, struct autr_ta* anchor, int* c) 1765238106Sdes{ 1766238106Sdes log_assert(anchor); 1767238106Sdes switch(anchor->s) { 1768238106Sdes /* START */ 1769238106Sdes case AUTR_STATE_START: 1770238106Sdes /* NewKey: ADDPEND */ 1771238106Sdes if (anchor->fetched) 1772238106Sdes do_newkey(env, anchor, c); 1773238106Sdes break; 1774238106Sdes /* ADDPEND */ 1775238106Sdes case AUTR_STATE_ADDPEND: 1776238106Sdes /* KeyRem: START */ 1777238106Sdes if (!anchor->fetched) 1778238106Sdes do_keyrem(env, anchor, c); 1779238106Sdes /* AddTime: VALID */ 1780238106Sdes else do_addtime(env, anchor, c); 1781238106Sdes break; 1782238106Sdes /* VALID */ 1783238106Sdes case AUTR_STATE_VALID: 1784238106Sdes /* RevBit: REVOKED */ 1785238106Sdes if (anchor->revoked) 1786238106Sdes do_revoked(env, anchor, c); 1787238106Sdes /* KeyRem: MISSING */ 1788238106Sdes else if (!anchor->fetched) 1789238106Sdes do_keyrem(env, anchor, c); 1790238106Sdes else if(!anchor->last_change) { 1791238106Sdes verbose_key(anchor, VERB_ALGO, "first seen"); 1792238106Sdes reset_holddown(env, anchor, c); 1793238106Sdes } 1794238106Sdes break; 1795238106Sdes /* MISSING */ 1796238106Sdes case AUTR_STATE_MISSING: 1797238106Sdes /* RevBit: REVOKED */ 1798238106Sdes if (anchor->revoked) 1799238106Sdes do_revoked(env, anchor, c); 1800238106Sdes /* KeyPres */ 1801238106Sdes else if (anchor->fetched) 1802238106Sdes do_keypres(env, anchor, c); 1803238106Sdes break; 1804238106Sdes /* REVOKED */ 1805238106Sdes case AUTR_STATE_REVOKED: 1806238106Sdes if (anchor->fetched) 1807238106Sdes reset_holddown(env, anchor, c); 1808238106Sdes /* RemTime: REMOVED */ 1809238106Sdes else do_remtime(env, anchor, c); 1810238106Sdes break; 1811238106Sdes /* REMOVED */ 1812238106Sdes case AUTR_STATE_REMOVED: 1813238106Sdes default: 1814238106Sdes break; 1815238106Sdes } 1816238106Sdes} 1817238106Sdes 1818238106Sdes/** if ZSK init then trust KSKs */ 1819238106Sdesstatic int 1820238106Sdesinit_zsk_to_ksk(struct module_env* env, struct trust_anchor* tp, int* changed) 1821238106Sdes{ 1822238106Sdes /* search for VALID ZSKs */ 1823238106Sdes struct autr_ta* anchor; 1824238106Sdes int validzsk = 0; 1825238106Sdes int validksk = 0; 1826238106Sdes for(anchor = tp->autr->keys; anchor; anchor = anchor->next) { 1827238106Sdes /* last_change test makes sure it was manually configured */ 1828269257Sdes if(sldns_wirerr_get_type(anchor->rr, anchor->rr_len, 1829269257Sdes anchor->dname_len) == LDNS_RR_TYPE_DNSKEY && 1830238106Sdes anchor->last_change == 0 && 1831269257Sdes !ta_is_dnskey_sep(anchor) && 1832238106Sdes anchor->s == AUTR_STATE_VALID) 1833238106Sdes validzsk++; 1834238106Sdes } 1835238106Sdes if(validzsk == 0) 1836238106Sdes return 0; 1837238106Sdes for(anchor = tp->autr->keys; anchor; anchor = anchor->next) { 1838269257Sdes if (ta_is_dnskey_sep(anchor) && 1839238106Sdes anchor->s == AUTR_STATE_ADDPEND) { 1840238106Sdes verbose_key(anchor, VERB_ALGO, "trust KSK from " 1841238106Sdes "ZSK(config)"); 1842238106Sdes set_trustanchor_state(env, anchor, changed, 1843238106Sdes AUTR_STATE_VALID); 1844238106Sdes validksk++; 1845238106Sdes } 1846238106Sdes } 1847238106Sdes return validksk; 1848238106Sdes} 1849238106Sdes 1850238106Sdes/** Remove missing trustanchors so the list does not grow forever */ 1851238106Sdesstatic void 1852238106Sdesremove_missing_trustanchors(struct module_env* env, struct trust_anchor* tp, 1853238106Sdes int* changed) 1854238106Sdes{ 1855238106Sdes struct autr_ta* anchor; 1856269257Sdes time_t exceeded; 1857238106Sdes int valid = 0; 1858238106Sdes /* see if we have anchors that are valid */ 1859238106Sdes for(anchor = tp->autr->keys; anchor; anchor = anchor->next) { 1860238106Sdes /* Only do KSKs */ 1861269257Sdes if (!ta_is_dnskey_sep(anchor)) 1862238106Sdes continue; 1863238106Sdes if (anchor->s == AUTR_STATE_VALID) 1864238106Sdes valid++; 1865238106Sdes } 1866238106Sdes /* if there are no SEP Valid anchors, see if we started out with 1867238106Sdes * a ZSK (last-change=0) anchor, which is VALID and there are KSKs 1868238106Sdes * now that can be made valid. Do this immediately because there 1869238106Sdes * is no guarantee that the ZSKs get announced long enough. Usually 1870238106Sdes * this is immediately after init with a ZSK trusted, unless the domain 1871238106Sdes * was not advertising any KSKs at all. In which case we perfectly 1872238106Sdes * track the zero number of KSKs. */ 1873238106Sdes if(valid == 0) { 1874238106Sdes valid = init_zsk_to_ksk(env, tp, changed); 1875238106Sdes if(valid == 0) 1876238106Sdes return; 1877238106Sdes } 1878238106Sdes 1879238106Sdes for(anchor = tp->autr->keys; anchor; anchor = anchor->next) { 1880238106Sdes /* ignore ZSKs if newly added */ 1881238106Sdes if(anchor->s == AUTR_STATE_START) 1882238106Sdes continue; 1883238106Sdes /* remove ZSKs if a KSK is present */ 1884269257Sdes if (!ta_is_dnskey_sep(anchor)) { 1885238106Sdes if(valid > 0) { 1886238106Sdes verbose_key(anchor, VERB_ALGO, "remove ZSK " 1887238106Sdes "[%d key(s) VALID]", valid); 1888238106Sdes set_trustanchor_state(env, anchor, changed, 1889238106Sdes AUTR_STATE_REMOVED); 1890238106Sdes } 1891238106Sdes continue; 1892238106Sdes } 1893238106Sdes /* Only do MISSING keys */ 1894238106Sdes if (anchor->s != AUTR_STATE_MISSING) 1895238106Sdes continue; 1896238106Sdes if(env->cfg->keep_missing == 0) 1897238106Sdes continue; /* keep forever */ 1898238106Sdes 1899238106Sdes exceeded = check_holddown(env, anchor, env->cfg->keep_missing); 1900238106Sdes /* If keep_missing has exceeded and we still have more than 1901238106Sdes * one valid KSK: remove missing trust anchor */ 1902238106Sdes if (exceeded && valid > 0) { 1903238106Sdes verbose_key(anchor, VERB_ALGO, "keep-missing time " 1904269257Sdes "exceeded " ARG_LL "d seconds ago, [%d key(s) VALID]", 1905269257Sdes (long long)exceeded, valid); 1906238106Sdes set_trustanchor_state(env, anchor, changed, 1907238106Sdes AUTR_STATE_REMOVED); 1908238106Sdes } 1909238106Sdes } 1910238106Sdes} 1911238106Sdes 1912238106Sdes/** Do the statetable from RFC5011 transition matrix */ 1913238106Sdesstatic int 1914238106Sdesdo_statetable(struct module_env* env, struct trust_anchor* tp, int* changed) 1915238106Sdes{ 1916238106Sdes struct autr_ta* anchor; 1917238106Sdes for(anchor = tp->autr->keys; anchor; anchor = anchor->next) { 1918238106Sdes /* Only do KSKs */ 1919269257Sdes if(!ta_is_dnskey_sep(anchor)) 1920238106Sdes continue; 1921238106Sdes anchor_state_update(env, anchor, changed); 1922238106Sdes } 1923238106Sdes remove_missing_trustanchors(env, tp, changed); 1924238106Sdes return 1; 1925238106Sdes} 1926238106Sdes 1927238106Sdes/** See if time alone makes ADDPEND to VALID transition */ 1928238106Sdesstatic void 1929238106Sdesautr_holddown_exceed(struct module_env* env, struct trust_anchor* tp, int* c) 1930238106Sdes{ 1931238106Sdes struct autr_ta* anchor; 1932238106Sdes for(anchor = tp->autr->keys; anchor; anchor = anchor->next) { 1933269257Sdes if(ta_is_dnskey_sep(anchor) && 1934238106Sdes anchor->s == AUTR_STATE_ADDPEND) 1935238106Sdes do_addtime(env, anchor, c); 1936238106Sdes } 1937238106Sdes} 1938238106Sdes 1939238106Sdes/** cleanup key list */ 1940238106Sdesstatic void 1941238106Sdesautr_cleanup_keys(struct trust_anchor* tp) 1942238106Sdes{ 1943238106Sdes struct autr_ta* p, **prevp; 1944238106Sdes prevp = &tp->autr->keys; 1945238106Sdes p = tp->autr->keys; 1946238106Sdes while(p) { 1947238106Sdes /* do we want to remove this key? */ 1948238106Sdes if(p->s == AUTR_STATE_START || p->s == AUTR_STATE_REMOVED || 1949269257Sdes sldns_wirerr_get_type(p->rr, p->rr_len, p->dname_len) 1950269257Sdes != LDNS_RR_TYPE_DNSKEY) { 1951238106Sdes struct autr_ta* np = p->next; 1952238106Sdes /* remove */ 1953269257Sdes free(p->rr); 1954238106Sdes free(p); 1955238106Sdes /* snip and go to next item */ 1956238106Sdes *prevp = np; 1957238106Sdes p = np; 1958238106Sdes continue; 1959238106Sdes } 1960238106Sdes /* remove pending counts if no longer pending */ 1961238106Sdes if(p->s != AUTR_STATE_ADDPEND) 1962238106Sdes p->pending_count = 0; 1963238106Sdes prevp = &p->next; 1964238106Sdes p = p->next; 1965238106Sdes } 1966238106Sdes} 1967238106Sdes 1968238106Sdes/** calculate next probe time */ 1969238106Sdesstatic time_t 1970269257Sdescalc_next_probe(struct module_env* env, time_t wait) 1971238106Sdes{ 1972238106Sdes /* make it random, 90-100% */ 1973269257Sdes time_t rnd, rest; 1974291767Sdes if(!autr_permit_small_holddown) { 1975291767Sdes if(wait < 3600) 1976291767Sdes wait = 3600; 1977291767Sdes } else { 1978291767Sdes if(wait == 0) wait = 1; 1979291767Sdes } 1980238106Sdes rnd = wait/10; 1981238106Sdes rest = wait-rnd; 1982269257Sdes rnd = (time_t)ub_random_max(env->rnd, (long int)rnd); 1983238106Sdes return (time_t)(*env->now + rest + rnd); 1984238106Sdes} 1985238106Sdes 1986238106Sdes/** what is first probe time (anchors must be locked) */ 1987238106Sdesstatic time_t 1988238106Sdeswait_probe_time(struct val_anchors* anchors) 1989238106Sdes{ 1990238106Sdes rbnode_t* t = rbtree_first(&anchors->autr->probe); 1991238106Sdes if(t != RBTREE_NULL) 1992238106Sdes return ((struct trust_anchor*)t->key)->autr->next_probe_time; 1993238106Sdes return 0; 1994238106Sdes} 1995238106Sdes 1996238106Sdes/** reset worker timer */ 1997238106Sdesstatic void 1998238106Sdesreset_worker_timer(struct module_env* env) 1999238106Sdes{ 2000238106Sdes struct timeval tv; 2001238106Sdes#ifndef S_SPLINT_S 2002269257Sdes time_t next = (time_t)wait_probe_time(env->anchors); 2003238106Sdes /* in case this is libunbound, no timer */ 2004238106Sdes if(!env->probe_timer) 2005238106Sdes return; 2006238106Sdes if(next > *env->now) 2007238106Sdes tv.tv_sec = (time_t)(next - *env->now); 2008238106Sdes else tv.tv_sec = 0; 2009238106Sdes#endif 2010238106Sdes tv.tv_usec = 0; 2011238106Sdes comm_timer_set(env->probe_timer, &tv); 2012269257Sdes verbose(VERB_ALGO, "scheduled next probe in " ARG_LL "d sec", (long long)tv.tv_sec); 2013238106Sdes} 2014238106Sdes 2015238106Sdes/** set next probe for trust anchor */ 2016238106Sdesstatic int 2017238106Sdesset_next_probe(struct module_env* env, struct trust_anchor* tp, 2018238106Sdes struct ub_packed_rrset_key* dnskey_rrset) 2019238106Sdes{ 2020238106Sdes struct trust_anchor key, *tp2; 2021238106Sdes time_t mold, mnew; 2022238106Sdes /* use memory allocated in rrset for temporary name storage */ 2023238106Sdes key.node.key = &key; 2024238106Sdes key.name = dnskey_rrset->rk.dname; 2025238106Sdes key.namelen = dnskey_rrset->rk.dname_len; 2026238106Sdes key.namelabs = dname_count_labels(key.name); 2027238106Sdes key.dclass = tp->dclass; 2028238106Sdes lock_basic_unlock(&tp->lock); 2029238106Sdes 2030238106Sdes /* fetch tp again and lock anchors, so that we can modify the trees */ 2031238106Sdes lock_basic_lock(&env->anchors->lock); 2032238106Sdes tp2 = (struct trust_anchor*)rbtree_search(env->anchors->tree, &key); 2033238106Sdes if(!tp2) { 2034238106Sdes verbose(VERB_ALGO, "trustpoint was deleted in set_next_probe"); 2035238106Sdes lock_basic_unlock(&env->anchors->lock); 2036238106Sdes return 0; 2037238106Sdes } 2038238106Sdes log_assert(tp == tp2); 2039238106Sdes lock_basic_lock(&tp->lock); 2040238106Sdes 2041238106Sdes /* schedule */ 2042238106Sdes mold = wait_probe_time(env->anchors); 2043238106Sdes (void)rbtree_delete(&env->anchors->autr->probe, tp); 2044238106Sdes tp->autr->next_probe_time = calc_next_probe(env, 2045238106Sdes tp->autr->query_interval); 2046238106Sdes (void)rbtree_insert(&env->anchors->autr->probe, &tp->autr->pnode); 2047238106Sdes mnew = wait_probe_time(env->anchors); 2048238106Sdes 2049238106Sdes lock_basic_unlock(&env->anchors->lock); 2050238106Sdes verbose(VERB_ALGO, "next probe set in %d seconds", 2051238106Sdes (int)tp->autr->next_probe_time - (int)*env->now); 2052238106Sdes if(mold != mnew) { 2053238106Sdes reset_worker_timer(env); 2054238106Sdes } 2055238106Sdes return 1; 2056238106Sdes} 2057238106Sdes 2058238106Sdes/** Revoke and Delete a trust point */ 2059238106Sdesstatic void 2060238106Sdesautr_tp_remove(struct module_env* env, struct trust_anchor* tp, 2061238106Sdes struct ub_packed_rrset_key* dnskey_rrset) 2062238106Sdes{ 2063249141Sdes struct trust_anchor* del_tp; 2064238106Sdes struct trust_anchor key; 2065238106Sdes struct autr_point_data pd; 2066238106Sdes time_t mold, mnew; 2067238106Sdes 2068238106Sdes log_nametypeclass(VERB_OPS, "trust point was revoked", 2069238106Sdes tp->name, LDNS_RR_TYPE_DNSKEY, tp->dclass); 2070238106Sdes tp->autr->revoked = 1; 2071238106Sdes 2072238106Sdes /* use space allocated for dnskey_rrset to save name of anchor */ 2073238106Sdes memset(&key, 0, sizeof(key)); 2074238106Sdes memset(&pd, 0, sizeof(pd)); 2075238106Sdes key.autr = &pd; 2076238106Sdes key.node.key = &key; 2077238106Sdes pd.pnode.key = &key; 2078238106Sdes pd.next_probe_time = tp->autr->next_probe_time; 2079238106Sdes key.name = dnskey_rrset->rk.dname; 2080238106Sdes key.namelen = tp->namelen; 2081238106Sdes key.namelabs = tp->namelabs; 2082238106Sdes key.dclass = tp->dclass; 2083238106Sdes 2084238106Sdes /* unlock */ 2085238106Sdes lock_basic_unlock(&tp->lock); 2086238106Sdes 2087238106Sdes /* take from tree. It could be deleted by someone else,hence (void). */ 2088238106Sdes lock_basic_lock(&env->anchors->lock); 2089249141Sdes del_tp = (struct trust_anchor*)rbtree_delete(env->anchors->tree, &key); 2090238106Sdes mold = wait_probe_time(env->anchors); 2091238106Sdes (void)rbtree_delete(&env->anchors->autr->probe, &key); 2092238106Sdes mnew = wait_probe_time(env->anchors); 2093238106Sdes anchors_init_parents_locked(env->anchors); 2094238106Sdes lock_basic_unlock(&env->anchors->lock); 2095238106Sdes 2096249141Sdes /* if !del_tp then the trust point is no longer present in the tree, 2097249141Sdes * it was deleted by someone else, who will write the zonefile and 2098249141Sdes * clean up the structure */ 2099249141Sdes if(del_tp) { 2100249141Sdes /* save on disk */ 2101249141Sdes del_tp->autr->next_probe_time = 0; /* no more probing for it */ 2102249141Sdes autr_write_file(env, del_tp); 2103238106Sdes 2104249141Sdes /* delete */ 2105249141Sdes autr_point_delete(del_tp); 2106249141Sdes } 2107238106Sdes if(mold != mnew) { 2108238106Sdes reset_worker_timer(env); 2109238106Sdes } 2110238106Sdes} 2111238106Sdes 2112238106Sdesint autr_process_prime(struct module_env* env, struct val_env* ve, 2113238106Sdes struct trust_anchor* tp, struct ub_packed_rrset_key* dnskey_rrset) 2114238106Sdes{ 2115238106Sdes int changed = 0; 2116238106Sdes log_assert(tp && tp->autr); 2117238106Sdes /* autotrust update trust anchors */ 2118238106Sdes /* the tp is locked, and stays locked unless it is deleted */ 2119238106Sdes 2120238106Sdes /* we could just catch the anchor here while another thread 2121238106Sdes * is busy deleting it. Just unlock and let the other do its job */ 2122238106Sdes if(tp->autr->revoked) { 2123238106Sdes log_nametypeclass(VERB_ALGO, "autotrust not processed, " 2124238106Sdes "trust point revoked", tp->name, 2125238106Sdes LDNS_RR_TYPE_DNSKEY, tp->dclass); 2126238106Sdes lock_basic_unlock(&tp->lock); 2127238106Sdes return 0; /* it is revoked */ 2128238106Sdes } 2129238106Sdes 2130238106Sdes /* query_dnskeys(): */ 2131238106Sdes tp->autr->last_queried = *env->now; 2132238106Sdes 2133238106Sdes log_nametypeclass(VERB_ALGO, "autotrust process for", 2134238106Sdes tp->name, LDNS_RR_TYPE_DNSKEY, tp->dclass); 2135238106Sdes /* see if time alone makes some keys valid */ 2136238106Sdes autr_holddown_exceed(env, tp, &changed); 2137238106Sdes if(changed) { 2138238106Sdes verbose(VERB_ALGO, "autotrust: morekeys, reassemble"); 2139238106Sdes if(!autr_assemble(tp)) { 2140238106Sdes log_err("malloc failure assembling autotrust keys"); 2141238106Sdes return 1; /* unchanged */ 2142238106Sdes } 2143238106Sdes } 2144238106Sdes /* did we get any data? */ 2145238106Sdes if(!dnskey_rrset) { 2146238106Sdes verbose(VERB_ALGO, "autotrust: no dnskey rrset"); 2147238106Sdes /* no update of query_failed, because then we would have 2148238106Sdes * to write to disk. But we cannot because we maybe are 2149238106Sdes * still 'initialising' with DS records, that we cannot write 2150238106Sdes * in the full format (which only contains KSKs). */ 2151238106Sdes return 1; /* trust point exists */ 2152238106Sdes } 2153238106Sdes /* check for revoked keys to remove immediately */ 2154238106Sdes check_contains_revoked(env, ve, tp, dnskey_rrset, &changed); 2155238106Sdes if(changed) { 2156238106Sdes verbose(VERB_ALGO, "autotrust: revokedkeys, reassemble"); 2157238106Sdes if(!autr_assemble(tp)) { 2158238106Sdes log_err("malloc failure assembling autotrust keys"); 2159238106Sdes return 1; /* unchanged */ 2160238106Sdes } 2161238106Sdes if(!tp->ds_rrset && !tp->dnskey_rrset) { 2162238106Sdes /* no more keys, all are revoked */ 2163238106Sdes /* this is a success for this probe attempt */ 2164238106Sdes tp->autr->last_success = *env->now; 2165238106Sdes autr_tp_remove(env, tp, dnskey_rrset); 2166238106Sdes return 0; /* trust point removed */ 2167238106Sdes } 2168238106Sdes } 2169238106Sdes /* verify the dnskey rrset and see if it is valid. */ 2170238106Sdes if(!verify_dnskey(env, ve, tp, dnskey_rrset)) { 2171238106Sdes verbose(VERB_ALGO, "autotrust: dnskey did not verify."); 2172238106Sdes /* only increase failure count if this is not the first prime, 2173294190Sdes * this means there was a previous successful probe */ 2174238106Sdes if(tp->autr->last_success) { 2175238106Sdes tp->autr->query_failed += 1; 2176238106Sdes autr_write_file(env, tp); 2177238106Sdes } 2178238106Sdes return 1; /* trust point exists */ 2179238106Sdes } 2180238106Sdes 2181238106Sdes tp->autr->last_success = *env->now; 2182238106Sdes tp->autr->query_failed = 0; 2183238106Sdes 2184238106Sdes /* Add new trust anchors to the data structure 2185238106Sdes * - note which trust anchors are seen this probe. 2186238106Sdes * Set trustpoint query_interval and retry_time. 2187238106Sdes * - find minimum rrsig expiration interval 2188238106Sdes */ 2189238106Sdes if(!update_events(env, ve, tp, dnskey_rrset, &changed)) { 2190238106Sdes log_err("malloc failure in autotrust update_events. " 2191238106Sdes "trust point unchanged."); 2192238106Sdes return 1; /* trust point unchanged, so exists */ 2193238106Sdes } 2194238106Sdes 2195238106Sdes /* - for every SEP key do the 5011 statetable. 2196238106Sdes * - remove missing trustanchors (if veryold and we have new anchors). 2197238106Sdes */ 2198238106Sdes if(!do_statetable(env, tp, &changed)) { 2199238106Sdes log_err("malloc failure in autotrust do_statetable. " 2200238106Sdes "trust point unchanged."); 2201238106Sdes return 1; /* trust point unchanged, so exists */ 2202238106Sdes } 2203238106Sdes 2204238106Sdes autr_cleanup_keys(tp); 2205238106Sdes if(!set_next_probe(env, tp, dnskey_rrset)) 2206238106Sdes return 0; /* trust point does not exist */ 2207238106Sdes autr_write_file(env, tp); 2208238106Sdes if(changed) { 2209238106Sdes verbose(VERB_ALGO, "autotrust: changed, reassemble"); 2210238106Sdes if(!autr_assemble(tp)) { 2211238106Sdes log_err("malloc failure assembling autotrust keys"); 2212238106Sdes return 1; /* unchanged */ 2213238106Sdes } 2214238106Sdes if(!tp->ds_rrset && !tp->dnskey_rrset) { 2215238106Sdes /* no more keys, all are revoked */ 2216238106Sdes autr_tp_remove(env, tp, dnskey_rrset); 2217238106Sdes return 0; /* trust point removed */ 2218238106Sdes } 2219238106Sdes } else verbose(VERB_ALGO, "autotrust: no changes"); 2220238106Sdes 2221238106Sdes return 1; /* trust point exists */ 2222238106Sdes} 2223238106Sdes 2224238106Sdes/** debug print a trust anchor key */ 2225238106Sdesstatic void 2226238106Sdesautr_debug_print_ta(struct autr_ta* ta) 2227238106Sdes{ 2228238106Sdes char buf[32]; 2229269257Sdes char* str = sldns_wire2str_rr(ta->rr, ta->rr_len); 2230238106Sdes if(!str) { 2231238106Sdes log_info("out of memory in debug_print_ta"); 2232238106Sdes return; 2233238106Sdes } 2234238106Sdes if(str && str[0]) str[strlen(str)-1]=0; /* remove newline */ 2235238106Sdes ctime_r(&ta->last_change, buf); 2236238106Sdes if(buf[0]) buf[strlen(buf)-1]=0; /* remove newline */ 2237238106Sdes log_info("[%s] %s ;;state:%d ;;pending_count:%d%s%s last:%s", 2238238106Sdes trustanchor_state2str(ta->s), str, ta->s, ta->pending_count, 2239238106Sdes ta->fetched?" fetched":"", ta->revoked?" revoked":"", buf); 2240238106Sdes free(str); 2241238106Sdes} 2242238106Sdes 2243238106Sdes/** debug print a trust point */ 2244238106Sdesstatic void 2245238106Sdesautr_debug_print_tp(struct trust_anchor* tp) 2246238106Sdes{ 2247238106Sdes struct autr_ta* ta; 2248238106Sdes char buf[257]; 2249238106Sdes if(!tp->autr) 2250238106Sdes return; 2251238106Sdes dname_str(tp->name, buf); 2252238106Sdes log_info("trust point %s : %d", buf, (int)tp->dclass); 2253238106Sdes log_info("assembled %d DS and %d DNSKEYs", 2254238106Sdes (int)tp->numDS, (int)tp->numDNSKEY); 2255269257Sdes if(tp->ds_rrset) { 2256269257Sdes log_packed_rrset(0, "DS:", tp->ds_rrset); 2257238106Sdes } 2258269257Sdes if(tp->dnskey_rrset) { 2259269257Sdes log_packed_rrset(0, "DNSKEY:", tp->dnskey_rrset); 2260269257Sdes } 2261238106Sdes log_info("file %s", tp->autr->file); 2262238106Sdes ctime_r(&tp->autr->last_queried, buf); 2263238106Sdes if(buf[0]) buf[strlen(buf)-1]=0; /* remove newline */ 2264238106Sdes log_info("last_queried: %u %s", (unsigned)tp->autr->last_queried, buf); 2265238106Sdes ctime_r(&tp->autr->last_success, buf); 2266238106Sdes if(buf[0]) buf[strlen(buf)-1]=0; /* remove newline */ 2267238106Sdes log_info("last_success: %u %s", (unsigned)tp->autr->last_success, buf); 2268238106Sdes ctime_r(&tp->autr->next_probe_time, buf); 2269238106Sdes if(buf[0]) buf[strlen(buf)-1]=0; /* remove newline */ 2270238106Sdes log_info("next_probe_time: %u %s", (unsigned)tp->autr->next_probe_time, 2271238106Sdes buf); 2272238106Sdes log_info("query_interval: %u", (unsigned)tp->autr->query_interval); 2273238106Sdes log_info("retry_time: %u", (unsigned)tp->autr->retry_time); 2274238106Sdes log_info("query_failed: %u", (unsigned)tp->autr->query_failed); 2275238106Sdes 2276238106Sdes for(ta=tp->autr->keys; ta; ta=ta->next) { 2277238106Sdes autr_debug_print_ta(ta); 2278238106Sdes } 2279238106Sdes} 2280238106Sdes 2281238106Sdesvoid 2282238106Sdesautr_debug_print(struct val_anchors* anchors) 2283238106Sdes{ 2284238106Sdes struct trust_anchor* tp; 2285238106Sdes lock_basic_lock(&anchors->lock); 2286238106Sdes RBTREE_FOR(tp, struct trust_anchor*, anchors->tree) { 2287238106Sdes lock_basic_lock(&tp->lock); 2288238106Sdes autr_debug_print_tp(tp); 2289238106Sdes lock_basic_unlock(&tp->lock); 2290238106Sdes } 2291238106Sdes lock_basic_unlock(&anchors->lock); 2292238106Sdes} 2293238106Sdes 2294238106Sdesvoid probe_answer_cb(void* arg, int ATTR_UNUSED(rcode), 2295269257Sdes sldns_buffer* ATTR_UNUSED(buf), enum sec_status ATTR_UNUSED(sec), 2296238106Sdes char* ATTR_UNUSED(why_bogus)) 2297238106Sdes{ 2298238106Sdes /* retry was set before the query was done, 2299238106Sdes * re-querytime is set when query succeeded, but that may not 2300238106Sdes * have reset this timer because the query could have been 2301238106Sdes * handled by another thread. In that case, this callback would 2302238106Sdes * get called after the original timeout is done. 2303238106Sdes * By not resetting the timer, it may probe more often, but not 2304238106Sdes * less often. 2305238106Sdes * Unless the new lookup resulted in smaller TTLs and thus smaller 2306238106Sdes * timeout values. In that case one old TTL could be mistakenly done. 2307238106Sdes */ 2308238106Sdes struct module_env* env = (struct module_env*)arg; 2309238106Sdes verbose(VERB_ALGO, "autotrust probe answer cb"); 2310238106Sdes reset_worker_timer(env); 2311238106Sdes} 2312238106Sdes 2313238106Sdes/** probe a trust anchor DNSKEY and unlocks tp */ 2314238106Sdesstatic void 2315238106Sdesprobe_anchor(struct module_env* env, struct trust_anchor* tp) 2316238106Sdes{ 2317238106Sdes struct query_info qinfo; 2318238106Sdes uint16_t qflags = BIT_RD; 2319238106Sdes struct edns_data edns; 2320269257Sdes sldns_buffer* buf = env->scratch_buffer; 2321238106Sdes qinfo.qname = regional_alloc_init(env->scratch, tp->name, tp->namelen); 2322238106Sdes if(!qinfo.qname) { 2323238106Sdes log_err("out of memory making 5011 probe"); 2324238106Sdes return; 2325238106Sdes } 2326238106Sdes qinfo.qname_len = tp->namelen; 2327238106Sdes qinfo.qtype = LDNS_RR_TYPE_DNSKEY; 2328238106Sdes qinfo.qclass = tp->dclass; 2329238106Sdes log_query_info(VERB_ALGO, "autotrust probe", &qinfo); 2330238106Sdes verbose(VERB_ALGO, "retry probe set in %d seconds", 2331238106Sdes (int)tp->autr->next_probe_time - (int)*env->now); 2332238106Sdes edns.edns_present = 1; 2333238106Sdes edns.ext_rcode = 0; 2334238106Sdes edns.edns_version = 0; 2335238106Sdes edns.bits = EDNS_DO; 2336269257Sdes if(sldns_buffer_capacity(buf) < 65535) 2337269257Sdes edns.udp_size = (uint16_t)sldns_buffer_capacity(buf); 2338238106Sdes else edns.udp_size = 65535; 2339238106Sdes 2340238106Sdes /* can't hold the lock while mesh_run is processing */ 2341238106Sdes lock_basic_unlock(&tp->lock); 2342238106Sdes 2343238106Sdes /* delete the DNSKEY from rrset and key cache so an active probe 2344238106Sdes * is done. First the rrset so another thread does not use it 2345238106Sdes * to recreate the key entry in a race condition. */ 2346238106Sdes rrset_cache_remove(env->rrset_cache, qinfo.qname, qinfo.qname_len, 2347238106Sdes qinfo.qtype, qinfo.qclass, 0); 2348238106Sdes key_cache_remove(env->key_cache, qinfo.qname, qinfo.qname_len, 2349238106Sdes qinfo.qclass); 2350238106Sdes 2351238106Sdes if(!mesh_new_callback(env->mesh, &qinfo, qflags, &edns, buf, 0, 2352238106Sdes &probe_answer_cb, env)) { 2353238106Sdes log_err("out of memory making 5011 probe"); 2354238106Sdes } 2355238106Sdes} 2356238106Sdes 2357238106Sdes/** fetch first to-probe trust-anchor and lock it and set retrytime */ 2358238106Sdesstatic struct trust_anchor* 2359269257Sdestodo_probe(struct module_env* env, time_t* next) 2360238106Sdes{ 2361238106Sdes struct trust_anchor* tp; 2362238106Sdes rbnode_t* el; 2363238106Sdes /* get first one */ 2364238106Sdes lock_basic_lock(&env->anchors->lock); 2365238106Sdes if( (el=rbtree_first(&env->anchors->autr->probe)) == RBTREE_NULL) { 2366238106Sdes /* in case of revoked anchors */ 2367238106Sdes lock_basic_unlock(&env->anchors->lock); 2368291767Sdes /* signal that there are no anchors to probe */ 2369291767Sdes *next = 0; 2370238106Sdes return NULL; 2371238106Sdes } 2372238106Sdes tp = (struct trust_anchor*)el->key; 2373238106Sdes lock_basic_lock(&tp->lock); 2374238106Sdes 2375238106Sdes /* is it eligible? */ 2376269257Sdes if((time_t)tp->autr->next_probe_time > *env->now) { 2377238106Sdes /* no more to probe */ 2378269257Sdes *next = (time_t)tp->autr->next_probe_time - *env->now; 2379238106Sdes lock_basic_unlock(&tp->lock); 2380238106Sdes lock_basic_unlock(&env->anchors->lock); 2381238106Sdes return NULL; 2382238106Sdes } 2383238106Sdes 2384238106Sdes /* reset its next probe time */ 2385238106Sdes (void)rbtree_delete(&env->anchors->autr->probe, tp); 2386238106Sdes tp->autr->next_probe_time = calc_next_probe(env, tp->autr->retry_time); 2387238106Sdes (void)rbtree_insert(&env->anchors->autr->probe, &tp->autr->pnode); 2388238106Sdes lock_basic_unlock(&env->anchors->lock); 2389238106Sdes 2390238106Sdes return tp; 2391238106Sdes} 2392238106Sdes 2393269257Sdestime_t 2394238106Sdesautr_probe_timer(struct module_env* env) 2395238106Sdes{ 2396238106Sdes struct trust_anchor* tp; 2397269257Sdes time_t next_probe = 3600; 2398238106Sdes int num = 0; 2399291767Sdes if(autr_permit_small_holddown) next_probe = 1; 2400238106Sdes verbose(VERB_ALGO, "autotrust probe timer callback"); 2401238106Sdes /* while there are still anchors to probe */ 2402238106Sdes while( (tp = todo_probe(env, &next_probe)) ) { 2403238106Sdes /* make a probe for this anchor */ 2404238106Sdes probe_anchor(env, tp); 2405238106Sdes num++; 2406238106Sdes } 2407238106Sdes regional_free_all(env->scratch); 2408291767Sdes if(next_probe == 0) 2409238106Sdes return 0; /* no trust points to probe */ 2410238106Sdes verbose(VERB_ALGO, "autotrust probe timer %d callbacks done", num); 2411238106Sdes return next_probe; 2412238106Sdes} 2413