static int validate_section(kr_rrset_validation_ctx_t *vctx, knot_mm_t *pool) { if (!vctx) { return kr_error(EINVAL); } const knot_pktsection_t *sec = knot_pkt_section(vctx->pkt, vctx->section_id); if (!sec) { return kr_ok(); } int ret = kr_ok(); map_t stash = map_make(); stash.malloc = (map_alloc_f) mm_alloc; stash.free = (map_free_f) mm_free; stash.baton = pool; /* Determine RR types contained in the section. */ for (unsigned i = 0; i < sec->count; ++i) { const knot_rrset_t *rr = knot_pkt_rr(sec, i); if (rr->type == KNOT_RRTYPE_RRSIG) { continue; } if ((rr->type == KNOT_RRTYPE_NS) && (vctx->section_id == KNOT_AUTHORITY)) { continue; } /* Only validate answers from current cut, records above the cut are stripped. */ if (!knot_dname_in(vctx->zone_name, rr->owner)) { continue; } ret = kr_rrmap_add(&stash, rr, 0, pool); if (ret != 0) { goto fail; } } /* Can't use qry->zone_cut.name directly, as this name can * change when updating cut information before validation. */ vctx->zone_name = vctx->keys ? vctx->keys->owner : NULL; ret = map_walk(&stash, &validate_rrset, vctx); if (ret != 0) { return ret; } ret = vctx->result; fail: return ret; }
static int free_key(const char *key, void *val, void *ext) { endpoint_array_t *ep_array = val; array_clear(*ep_array); free(ep_array); return kr_ok(); }
/** * Name error response check (RFC4035 3.1.3.2; RFC4035 5.4, bullet 2). * @note Returned flags must be checked in order to prove denial. * @param flags Flags to be set according to check outcome. * @param nsec NSEC RR. * @param name Name to be checked. * @param pool * @return 0 or error code. */ static int name_error_response_check_rr(int *flags, const knot_rrset_t *nsec, const knot_dname_t *name) { assert(flags && nsec && name); if (nsec_nonamematch(nsec, name) == 0) { *flags |= FLG_NOEXIST_RRSET; } /* Try to find parent wildcard that is proved by this NSEC. */ uint8_t namebuf[KNOT_DNAME_MAXLEN]; int ret = knot_dname_to_wire(namebuf, name, sizeof(namebuf)); if (ret < 0) return ret; knot_dname_t *ptr = namebuf; while (ptr[0]) { /* Remove leftmost label and replace it with '\1*'. */ ptr = (uint8_t *) knot_wire_next_label(ptr, NULL); *(--ptr) = '*'; *(--ptr) = 1; /* True if this wildcard provably doesn't exist. */ if (nsec_nonamematch(nsec, ptr) == 0) { *flags |= FLG_NOEXIST_WILDCARD; break; } /* Remove added leftmost asterisk. */ ptr += 2; } return kr_ok(); }
static int run_worker(uv_loop_t *loop, struct engine *engine) { /* Control sockets or TTY */ auto_free char *sock_file = NULL; uv_pipe_t pipe; uv_pipe_init(loop, &pipe, 0); pipe.data = engine; if (g_interactive) { printf("[system] interactive mode\n> "); fflush(stdout); uv_pipe_open(&pipe, 0); uv_read_start((uv_stream_t*) &pipe, tty_alloc, tty_read); } else { (void) mkdir("tty", S_IRWXU|S_IRWXG); sock_file = afmt("tty/%ld", getpid()); if (sock_file) { uv_pipe_bind(&pipe, sock_file); uv_listen((uv_stream_t *) &pipe, 16, tty_accept); } } /* Run event loop */ uv_run(loop, UV_RUN_DEFAULT); if (sock_file) { unlink(sock_file); } return kr_ok(); }
int ffimodule_register_lua(struct engine *engine, struct kr_module *module, const char *name) { /* Register module in Lua */ lua_State *L = engine->L; lua_getglobal(L, "require"); lua_pushstring(L, name); if (lua_pcall(L, 1, LUA_MULTRET, 0) != 0) { fprintf(stderr, "error: %s\n", lua_tostring(L, -1)); lua_pop(L, 1); return kr_error(ENOENT); } lua_setglobal(L, name); lua_getglobal(L, name); /* Create FFI module with trampolined functions. */ memset(module, 0, sizeof(*module)); module->name = strdup(name); module->init = &l_ffi_init; module->deinit = &l_ffi_deinit; /* Bake layer API if defined in module */ lua_getfield(L, -1, "layer"); if (!lua_isnil(L, -1)) { module->layer = &l_ffi_layer; module->data = l_ffi_layer_create(L, module); } module->lib = L; lua_pop(L, 2); /* Clear the layer + module global */ if (module->init) { return module->init(module); } return kr_ok(); }
static int update_parent_keys(struct kr_query *qry, uint16_t answer_type) { struct kr_query *parent = qry->parent; assert(parent); switch(answer_type) { case KNOT_RRTYPE_DNSKEY: DEBUG_MSG(qry, "<= parent: updating DNSKEY\n"); parent->zone_cut.key = knot_rrset_copy(qry->zone_cut.key, parent->zone_cut.pool); if (!parent->zone_cut.key) { return KNOT_STATE_FAIL; } break; case KNOT_RRTYPE_DS: DEBUG_MSG(qry, "<= parent: updating DS\n"); if (qry->flags & QUERY_DNSSEC_INSECURE) { /* DS non-existence proven. */ parent->flags &= ~QUERY_DNSSEC_WANT; parent->flags |= QUERY_DNSSEC_INSECURE; } else { /* DS existence proven. */ parent->zone_cut.trust_anchor = knot_rrset_copy(qry->zone_cut.trust_anchor, parent->zone_cut.pool); if (!parent->zone_cut.trust_anchor) { return KNOT_STATE_FAIL; } } break; default: break; } return kr_ok(); }
int kr_nsrep_update_rtt(struct kr_nsrep *ns, unsigned score, kr_nsrep_lru_t *cache) { if (!ns || !cache || ns->addr.ip.sa_family == AF_UNSPEC) { return kr_error(EINVAL); } char *addr = kr_nsrep_inaddr(ns->addr); size_t addr_len = kr_nsrep_inaddr_len(ns->addr); unsigned *cur = lru_set(cache, addr, addr_len); if (!cur) { return kr_error(ENOMEM); } /* Score limits */ if (score > KR_NS_MAX_SCORE) { score = KR_NS_MAX_SCORE; } if (score <= KR_NS_GLUED) { score = KR_NS_GLUED + 1; } /* Set initial value or smooth over last two measurements */ if (*cur != 0) { *cur = (*cur + score) / 2; } else { /* First measurement, reset */ *cur = score; } return kr_ok(); }
int engine_register(struct engine *engine, const char *name, const char *precedence, const char* ref) { if (engine == NULL || name == NULL) { return kr_error(EINVAL); } /* Make sure module is unloaded */ (void) engine_unregister(engine, name); /* Find the index of referenced module. */ module_array_t *mod_list = &engine->modules; size_t ref_pos = mod_list->len; if (precedence && ref) { ref_pos = module_find(mod_list, ref); if (ref_pos >= mod_list->len) { return kr_error(EIDRM); } } /* Attempt to load binary module */ struct kr_module *module = malloc(sizeof(*module)); if (!module) { return kr_error(ENOMEM); } module->data = engine; int ret = kr_module_load(module, name, NULL); /* Load Lua module if not a binary */ if (ret == kr_error(ENOENT)) { ret = ffimodule_register_lua(engine, module, name); } if (ret != 0) { free(module); return ret; } if (array_push(engine->modules, module) < 0) { engine_unload(engine, module); return kr_error(ENOMEM); } /* Evaluate precedence operator */ if (precedence) { struct kr_module **arr = mod_list->at; size_t emplacement = mod_list->len; if (strcasecmp(precedence, ">") == 0) { if (ref_pos + 1 < mod_list->len) emplacement = ref_pos + 1; /* Insert after target */ } if (strcasecmp(precedence, "<") == 0) { emplacement = ref_pos; /* Insert at target */ } /* Move the tail if it has some elements. */ if (emplacement + 1 < mod_list->len) { memmove(&arr[emplacement + 1], &arr[emplacement], sizeof(*arr) * (mod_list->len - (emplacement + 1))); arr[emplacement] = module; } } /* Register properties */ if (module->props || module->config) { return register_properties(engine, module); } return kr_ok(); }
static int update_delegation(struct kr_request *req, struct kr_query *qry, knot_pkt_t *answer, bool has_nsec3) { struct kr_zonecut *cut = &qry->zone_cut; /* RFC4035 3.1.4. authoritative must send either DS or proof of non-existence. * If it contains neither, the referral is bogus (or an attempted downgrade attack). */ unsigned section = KNOT_ANSWER; if (!knot_wire_get_aa(answer->wire)) { /* Referral */ section = KNOT_AUTHORITY; } else if (knot_pkt_qtype(answer) == KNOT_RRTYPE_DS) { /* Subrequest */ section = KNOT_ANSWER; } else { /* N/A */ return kr_ok(); } int ret = 0; const knot_dname_t *proved_name = knot_pkt_qname(answer); /* Aggregate DS records (if using multiple keys) */ knot_rrset_t *new_ds = update_ds(cut, knot_pkt_section(answer, section)); if (!new_ds) { /* No DS provided, check for proof of non-existence. */ if (!has_nsec3) { if (!knot_wire_get_aa(answer->wire)) { /* Referral, check if it is referral to unsigned, rfc4035 5.2 */ ret = kr_nsec_ref_to_unsigned(answer); } else { /* No-data answer */ ret = kr_nsec_existence_denial(answer, KNOT_AUTHORITY, proved_name, KNOT_RRTYPE_DS); } } else { if (!knot_wire_get_aa(answer->wire)) { /* Referral, check if it is referral to unsigned, rfc5155 8.9 */ ret = kr_nsec3_ref_to_unsigned(answer); } else { /* No-data answer, QTYPE is DS, rfc5155 8.6 */ ret = kr_nsec3_no_data(answer, KNOT_AUTHORITY, proved_name, KNOT_RRTYPE_DS); } if (ret == kr_error(DNSSEC_NOT_FOUND)) { /* Not bogus, going insecure due to optout */ ret = 0; } } if (ret != 0) { DEBUG_MSG(qry, "<= bogus proof of DS non-existence\n"); qry->flags |= QUERY_DNSSEC_BOGUS; } else { DEBUG_MSG(qry, "<= DS doesn't exist, going insecure\n"); qry->flags &= ~QUERY_DNSSEC_WANT; qry->flags |= QUERY_DNSSEC_INSECURE; } return ret; } /* Extend trust anchor */ DEBUG_MSG(qry, "<= DS: OK\n"); cut->trust_anchor = new_ds; return ret; }
int ffimodule_register_lua(struct engine *engine, struct kr_module *module, const char *name) { /* Register module in Lua */ lua_State *L = engine->L; lua_getglobal(L, "require"); lua_pushstring(L, name); if (lua_pcall(L, 1, LUA_MULTRET, 0) != 0) { fprintf(stderr, "error: %s\n", lua_tostring(L, -1)); lua_pop(L, 1); return kr_error(ENOENT); } lua_setglobal(L, name); lua_getglobal(L, name); /* Create FFI module with trampolined functions. */ memset(module, 0, sizeof(*module)); module->name = strdup(name); module->init = &l_ffi_init; module->deinit = &l_ffi_deinit; REGISTER_FFI_CALL(L, module->layer, "layer", &l_ffi_layer); module->data = (void *)(intptr_t)luaL_ref(L, LUA_REGISTRYINDEX); module->lib = L; lua_pop(L, 1); /* Clear the module global */ if (module->init) { return module->init(module); } return kr_ok(); }
/** * Adjust TTL in wire format. * @param wire RR Set in wire format. * @param wire_size Size of the wire data portion. * @param new_ttl TTL value to be set for all RRs. * @return 0 or error code. */ static int adjust_wire_ttl(uint8_t *wire, size_t wire_size, uint32_t new_ttl) { assert(wire); assert(sizeof(uint16_t) == 2); assert(sizeof(uint32_t) == 4); uint16_t rdlen; int ret; new_ttl = htonl(new_ttl); size_t i = 0; /* RR wire format in RFC1035 3.2.1 */ while(i < wire_size) { ret = knot_dname_size(wire + i); if (ret < 0) { return ret; } i += ret + 4; memcpy(wire + i, &new_ttl, sizeof(uint32_t)); i += sizeof(uint32_t); memcpy(&rdlen, wire + i, sizeof(uint16_t)); rdlen = ntohs(rdlen); i += sizeof(uint16_t) + rdlen; assert(i <= wire_size); } return kr_ok(); }
int kr_nsec_existence_denial(const knot_pkt_t *pkt, knot_section_t section_id, const knot_dname_t *sname, uint16_t stype) { const knot_pktsection_t *sec = knot_pkt_section(pkt, section_id); if (!sec || !sname) { return kr_error(EINVAL); } int flags = 0; for (unsigned i = 0; i < sec->count; ++i) { const knot_rrset_t *rrset = knot_pkt_rr(sec, i); if (rrset->type != KNOT_RRTYPE_NSEC) { continue; } /* NSEC proves that name exists, but has no data (RFC4035 4.9, 1) */ if (knot_dname_is_equal(rrset->owner, sname)) { no_data_response_check_rrtype(&flags, rrset, stype); } else { /* NSEC proves that name doesn't exist (RFC4035, 4.9, 2) */ name_error_response_check_rr(&flags, rrset, sname); } no_data_wildcard_existence_check(&flags, rrset, sec); } return kr_nsec_existence_denied(flags) ? kr_ok() : kr_error(ENOENT); }
int network_close(struct network *net, const char *addr, uint16_t port) { endpoint_array_t *ep_array = map_get(&net->endpoints, addr); if (ep_array == NULL) { return kr_error(ENOENT); } /* Close endpoint in array. */ for (size_t i = ep_array->len; i--;) { struct endpoint *ep = ep_array->at[i]; if (ep->port == port) { close_endpoint(ep); array_del(*ep_array, i); break; } } /* Collapse key if it has no endpoint. */ if (ep_array->len == 0) { free(ep_array); map_del(&net->endpoints, addr); } return kr_ok(); }
static int init_state(struct engine *engine) { /* Initialize Lua state */ engine->L = luaL_newstate(); if (engine->L == NULL) { return kr_error(ENOMEM); } /* Initialize used libraries. */ lua_gc(engine->L, LUA_GCSTOP, 0); luaL_openlibs(engine->L); /* Global functions */ lua_pushcfunction(engine->L, l_help); lua_setglobal(engine->L, "help"); lua_pushcfunction(engine->L, l_quit); lua_setglobal(engine->L, "quit"); lua_pushcfunction(engine->L, l_hostname); lua_setglobal(engine->L, "hostname"); lua_pushcfunction(engine->L, l_verbose); lua_setglobal(engine->L, "verbose"); lua_pushcfunction(engine->L, l_option); lua_setglobal(engine->L, "option"); lua_pushcfunction(engine->L, l_setuser); lua_setglobal(engine->L, "user"); lua_pushcfunction(engine->L, l_trustanchor); lua_setglobal(engine->L, "trustanchor"); lua_pushcfunction(engine->L, l_libpath); lua_setglobal(engine->L, "libpath"); lua_pushliteral(engine->L, MODULEDIR); lua_setglobal(engine->L, "moduledir"); lua_pushliteral(engine->L, ETCDIR); lua_setglobal(engine->L, "etcdir"); lua_pushlightuserdata(engine->L, engine); lua_setglobal(engine->L, "__engine"); return kr_ok(); }
/** * Check whether the NSEC RR proves that there is no closer match for <SNAME, SCLASS>. * @param nsec NSEC RRSet. * @param sname Searched name. * @return 0 or error code. */ static int nsec_nonamematch(const knot_rrset_t *nsec, const knot_dname_t *sname) { assert(nsec && sname); const knot_dname_t *next = knot_nsec_next(&nsec->rrs); /* If NSEC 'owner' >= 'next', it means that there is nothing after 'owner' */ const bool is_last_nsec = (knot_dname_cmp(nsec->owner, next) >= 0); if (is_last_nsec) { /* SNAME is after owner => provably doesn't exist */ if (knot_dname_cmp(nsec->owner, sname) < 0) { return kr_ok(); } } else { /* Prove that SNAME is between 'owner' and 'next' */ if ((knot_dname_cmp(nsec->owner, sname) < 0) && (knot_dname_cmp(sname, next) < 0)) { return kr_ok(); } } return kr_error(EINVAL); }
static int eval_nsrep(const char *k, void *v, void *baton) { struct kr_query *qry = baton; struct kr_nsrep *ns = &qry->ns; struct kr_context *ctx = ns->ctx; unsigned score = KR_NS_MAX_SCORE; unsigned reputation = 0; uint8_t *addr = NULL; /* Fetch NS reputation */ if (ctx->cache_rep) { unsigned *cached = lru_get(ctx->cache_rep, k, knot_dname_size((const uint8_t *)k)); if (cached) { reputation = *cached; } } /* Favour nameservers with unknown addresses to probe them, * otherwise discover the current best address for the NS. */ pack_t *addr_set = (pack_t *)v; if (addr_set->len == 0) { score = KR_NS_UNKNOWN; /* If the server doesn't have IPv6, give it disadvantage. */ if (reputation & KR_NS_NOIP6) { score += FAVOUR_IPV6; /* If the server is unknown but has rep record, treat it as timeouted */ if (reputation & KR_NS_NOIP4) { score = KR_NS_TIMEOUT; reputation = 0; /* Start with clean slate */ } } } else { score = eval_addr_set(addr_set, ctx->cache_rtt, score, &addr); } /* Probabilistic bee foraging strategy (naive). * The fastest NS is preferred by workers until it is depleted (timeouts or degrades), * at the same time long distance scouts probe other sources (low probability). * Servers on TIMEOUT (depleted) can be probed by the dice roll only */ if (score < ns->score && (qry->flags & QUERY_NO_THROTTLE || score < KR_NS_TIMEOUT)) { update_nsrep(ns, (const knot_dname_t *)k, addr, score); ns->reputation = reputation; } else { /* With 5% chance, probe server with a probability given by its RTT / MAX_RTT */ if ((kr_rand_uint(100) < 5) && (kr_rand_uint(KR_NS_MAX_SCORE) >= score)) { /* If this is a low-reliability probe, go with TCP to get ICMP reachability check. */ if (score >= KR_NS_LONG) { qry->flags |= QUERY_TCP; } update_nsrep(ns, (const knot_dname_t *)k, addr, score); ns->reputation = reputation; return 1; /* Stop evaluation */ } } return kr_ok(); }
/** Load C module symbols. */ static int load_sym_c(struct kr_module *module, uint32_t api_required) { /* Check if it's embedded first */ for (unsigned i = 0; i < sizeof(embedded_modules)/sizeof(embedded_modules[0]); ++i) { const struct kr_module *embedded = &embedded_modules[i]; if (strcmp(module->name, embedded->name) == 0) { module->init = embedded->init; module->deinit = embedded->deinit; module->config = embedded->config; module->layer = embedded->layer; module->props = embedded->props; return kr_ok(); } } /* Load dynamic library module */ auto_free char *module_prefix = kr_strcatdup(2, module->name, "_"); ABI_CHECK(module, module_prefix, "api", api_required); ABI_LOAD(module, module_prefix, "init", "deinit", "config", "layer", "props"); return kr_ok(); }
int kr_nsrep_set(struct kr_query *qry, uint8_t *addr, size_t addr_len) { if (!qry || !addr) { return kr_error(EINVAL); } qry->ns.name = (const uint8_t *)""; qry->ns.score = KR_NS_UNKNOWN; qry->ns.reputation = 0; update_nsrep(&qry->ns, 0, addr, addr_len); update_nsrep(&qry->ns, 1, NULL, 0); return kr_ok(); }
int engine_unregister(struct engine *engine, const char *name) { module_array_t *mod_list = &engine->modules; size_t found = module_find(mod_list, name); if (found < mod_list->len) { engine_unload(engine, mod_list->at[found]); array_del(*mod_list, found); return kr_ok(); } return kr_error(ENOENT); }
/** Close endpoint protocols. */ static int close_endpoint(struct endpoint *ep) { if (ep->flags & NET_UDP) { udp_unbind(ep); } if (ep->flags & NET_TCP) { tcp_unbind(ep); } free(ep); return kr_ok(); }
/** Retrieve hint list. */ static int pack_hint(const char *k, void *v, void *baton) { char nsname_str[KNOT_DNAME_MAXLEN] = {'\0'}; knot_dname_to_str(nsname_str, (const uint8_t *)k, sizeof(nsname_str)); JsonNode *root_node = baton; JsonNode *addr_list = pack_addrs((pack_t *)v); if (!addr_list) { return kr_error(ENOMEM); } json_append_member(root_node, nsname_str, addr_list); return kr_ok(); }
/** * @internal Defer execution of current query. * The current layer state and input will be pushed to a stack and resumed on next iteration. */ static int consume_yield(knot_layer_t *ctx, knot_pkt_t *pkt) { struct kr_request *req = ctx->data; knot_pkt_t *pkt_copy = knot_pkt_new(NULL, pkt->size, &req->pool); struct kr_layer_pickle *pickle = mm_alloc(&req->pool, sizeof(*pickle)); if (pickle && pkt_copy && knot_pkt_copy(pkt_copy, pkt) == 0) { struct kr_query *qry = req->current_query; pickle->api = ctx->api; pickle->state = ctx->state; pickle->pkt = pkt_copy; pickle->next = qry->deferred; qry->deferred = pickle; return kr_ok(); } return kr_error(ENOMEM); }
int kr_nsrep_update_rep(struct kr_nsrep *ns, unsigned reputation, kr_nsrep_lru_t *cache) { if (!ns || !cache ) { return kr_error(EINVAL); } /* Store in the struct */ ns->reputation = reputation; /* Store reputation in the LRU cache */ unsigned *cur = lru_set(cache, (const char *)ns->name, knot_dname_size(ns->name)); if (!cur) { return kr_error(ENOMEM); } *cur = reputation; return kr_ok(); }
int engine_start(struct engine *engine, const char *config_path) { /* Load configuration. */ int ret = engine_loadconf(engine, config_path); if (ret != 0) { return ret; } /* Clean up stack and restart GC */ lua_settop(engine->L, 0); lua_gc(engine->L, LUA_GCCOLLECT, 0); lua_gc(engine->L, LUA_GCSETSTEPMUL, 50); lua_gc(engine->L, LUA_GCSETPAUSE, 400); lua_gc(engine->L, LUA_GCRESTART, 0); return kr_ok(); }
/** Append 'addr = {port = int, udp = bool, tcp = bool}' */ static int net_list_add(const char *key, void *val, void *ext) { lua_State *L = (lua_State *)ext; endpoint_array_t *ep_array = val; lua_newtable(L); for (size_t i = ep_array->len; i--;) { struct endpoint *ep = ep_array->at[i]; lua_pushinteger(L, ep->port); lua_setfield(L, -2, "port"); lua_pushboolean(L, ep->flags & NET_UDP); lua_setfield(L, -2, "udp"); lua_pushboolean(L, ep->flags & NET_TCP); lua_setfield(L, -2, "tcp"); } lua_setfield(L, -2, key); return kr_ok(); }
/** * Check the RRSIG RR validity according to RFC4035 5.3.1 . * @param flags The flags are going to be set according to validation result. * @param cov_labels Covered RRSet owner label count. * @param rrsigs RRSet containing the signatures. * @param sig_pos Specifies the signature within the RRSIG RRSet. * @param keys Associated DNSKEY RRSet. * @param key_pos Specifies the key within the DNSKEY RRSet, * @param keytag Used key tag. * @param zone_name The name of the zone cut. * @param timestamp Validation time. */ static int validate_rrsig_rr(int *flags, int cov_labels, const knot_rrset_t *rrsigs, size_t sig_pos, const knot_rrset_t *keys, size_t key_pos, uint16_t keytag, const knot_dname_t *zone_name, uint32_t timestamp) { if (!flags || !rrsigs || !keys || !zone_name) { return kr_error(EINVAL); } /* bullet 5 */ if (knot_rrsig_sig_expiration(&rrsigs->rrs, sig_pos) < timestamp) { return kr_error(EINVAL); } /* bullet 6 */ if (knot_rrsig_sig_inception(&rrsigs->rrs, sig_pos) > timestamp) { return kr_error(EINVAL); } /* bullet 2 */ const knot_dname_t *signer_name = knot_rrsig_signer_name(&rrsigs->rrs, sig_pos); if (!signer_name || !knot_dname_is_equal(signer_name, zone_name)) { return kr_error(EINVAL); } /* bullet 4 */ { int rrsig_labels = knot_rrsig_labels(&rrsigs->rrs, sig_pos); if (rrsig_labels > cov_labels) { return kr_error(EINVAL); } if (rrsig_labels < cov_labels) { *flags |= FLG_WILDCARD_EXPANSION; } } /* bullet 7 */ if ((!knot_dname_is_equal(keys->owner, signer_name)) || (knot_dnskey_alg(&keys->rrs, key_pos) != knot_rrsig_algorithm(&rrsigs->rrs, sig_pos)) || (keytag != knot_rrsig_key_tag(&rrsigs->rrs, sig_pos))) { return kr_error(EINVAL); } /* bullet 8 */ /* Checked somewhere else. */ /* bullet 9 and 10 */ /* One of the requirements should be always fulfilled. */ return kr_ok(); }
/** * Perform check of RR type existence denial according to RFC4035 5.4, bullet 1. * @param flags Flags to be set according to check outcome. * @param nsec NSEC RR. * @param type Type to be checked. * @return 0 or error code. */ static int no_data_response_check_rrtype(int *flags, const knot_rrset_t *nsec, uint16_t type) { assert(flags && nsec); uint8_t *bm = NULL; uint16_t bm_size; knot_nsec_bitmap(&nsec->rrs, &bm, &bm_size); if (!bm) { return kr_error(EINVAL); } if (!kr_nsec_bitmap_contains_type(bm, bm_size, type)) { /* The type is not listed in the NSEC bitmap. */ *flags |= FLG_NOEXIST_RRTYPE; } return kr_ok(); }
int kr_nsrep_elect_addr(struct kr_query *qry, struct kr_context *ctx) { if (!qry || !ctx) { return kr_error(EINVAL); } /* Get address list for this NS */ struct kr_nsrep *ns = &qry->ns; ELECT_INIT(ns, ctx); pack_t *addr_set = map_get(&qry->zone_cut.nsset, (const char *)ns->name); if (!addr_set) { return kr_error(ENOENT); } /* Evaluate addr list */ uint8_t *addr = NULL; unsigned score = eval_addr_set(addr_set, ctx->cache_rtt, ns->score, &addr); update_nsrep(ns, ns->name, addr, score); return kr_ok(); }
int kr_check_signature(const knot_rrset_t *rrsigs, size_t pos, const dnssec_key_t *key, const knot_rrset_t *covered, int trim_labels) { if (!rrsigs || !key || !dnssec_key_can_verify(key)) { return kr_error(EINVAL); } int ret = 0; dnssec_sign_ctx_t *sign_ctx = NULL; dnssec_binary_t signature = {0, }; knot_rrsig_signature(&rrsigs->rrs, pos, &signature.data, &signature.size); if (!signature.data || !signature.size) { ret = kr_error(EINVAL); goto fail; } if (dnssec_sign_new(&sign_ctx, key) != 0) { ret = kr_error(ENOMEM); goto fail; } uint32_t orig_ttl = knot_rrsig_original_ttl(&rrsigs->rrs, pos); const knot_rdata_t *rr_data = knot_rdataset_at(&rrsigs->rrs, pos); uint8_t *rdata = knot_rdata_data(rr_data); if (sign_ctx_add_data(sign_ctx, rdata, covered, orig_ttl, trim_labels) != 0) { ret = kr_error(ENOMEM); goto fail; } if (dnssec_sign_verify(sign_ctx, &signature) != 0) { ret = kr_error(EBADMSG); goto fail; } ret = kr_ok(); fail: dnssec_sign_free(sign_ctx); return ret; }
int kr_nsec_wildcard_answer_response_check(const knot_pkt_t *pkt, knot_section_t section_id, const knot_dname_t *sname) { const knot_pktsection_t *sec = knot_pkt_section(pkt, section_id); if (!sec || !sname) { return kr_error(EINVAL); } for (unsigned i = 0; i < sec->count; ++i) { const knot_rrset_t *rrset = knot_pkt_rr(sec, i); if (rrset->type != KNOT_RRTYPE_NSEC) { continue; } if (nsec_nonamematch(rrset, sname) == 0) { return kr_ok(); } } return kr_error(ENOENT); }