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 network_listen(struct network *net, const char *addr, uint16_t port, uint32_t flags) { if (net == NULL || addr == 0 || port == 0) { return kr_error(EINVAL); } /* Parse address. */ int ret = 0; struct sockaddr_storage sa; if (strchr(addr, ':') != NULL) { ret = uv_ip6_addr(addr, port, (struct sockaddr_in6 *)&sa); } else { ret = uv_ip4_addr(addr, port, (struct sockaddr_in *)&sa); } if (ret != 0) { return ret; } /* Bind interfaces */ struct endpoint *ep = malloc(sizeof(*ep)); memset(ep, 0, sizeof(*ep)); ep->flags = NET_DOWN; ep->port = port; ret = open_endpoint(net, ep, (struct sockaddr *)&sa, flags); if (ret == 0) { ret = insert_endpoint(net, addr, ep); } if (ret != 0) { close_endpoint(ep); } return ret; }
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(); }
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(); }
int kr_dnssec_key_match(const uint8_t *key_a_rdata, size_t key_a_rdlen, const uint8_t *key_b_rdata, size_t key_b_rdlen) { dnssec_key_t *key_a = NULL, *key_b = NULL; int ret = kr_dnssec_key_from_rdata((struct dseckey **)&key_a, NULL, key_a_rdata, key_a_rdlen); if (ret != 0) { return ret; } ret = kr_dnssec_key_from_rdata((struct dseckey **)&key_b, NULL, key_b_rdata, key_b_rdlen); if (ret != 0) { dnssec_key_free(key_a); return ret; } /* If the algorithm and the public key match, we can be sure * that they are the same key. */ ret = kr_error(ENOENT); dnssec_binary_t pk_a, pk_b; if (dnssec_key_get_algorithm(key_a) == dnssec_key_get_algorithm(key_b) && dnssec_key_get_pubkey(key_a, &pk_a) == DNSSEC_EOK && dnssec_key_get_pubkey(key_b, &pk_b) == DNSSEC_EOK) { if (pk_a.size == pk_b.size && memcmp(pk_a.data, pk_b.data, pk_a.size) == 0) { ret = 0; } } dnssec_key_free(key_a); dnssec_key_free(key_b); 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; /* 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(); }
int kr_rrset_validate(const knot_pkt_t *pkt, knot_section_t section_id, const knot_rrset_t *covered, const knot_rrset_t *keys, const knot_dname_t *zone_name, uint32_t timestamp, bool has_nsec3) { if (!pkt || !covered || !keys || !zone_name) { return kr_error(EINVAL); } for (unsigned i = 0; i < keys->rrs.rr_count; ++i) { int ret = kr_rrset_validate_with_key(pkt, section_id, covered, keys, i, NULL, zone_name, timestamp, has_nsec3); if (ret == 0) { return ret; } } return kr_error(ENOENT); }
static int cdb_clear(knot_db_t *db) { struct memcached_cli *cli = db; memcached_return_t ret = memcached_flush(cli->handle, 0); if (ret != 0) { return kr_error(EIO); } return 0; }
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_nsrep_elect(struct kr_query *qry, struct kr_context *ctx) { if (!qry || !ctx) { return kr_error(EINVAL); } struct kr_nsrep *ns = &qry->ns; ELECT_INIT(ns, ctx); return map_walk(&qry->zone_cut.nsset, eval_nsrep, qry); }
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; }
/** @internal Schedule deferred continuation. */ static int l_ffi_defer(lua_State *L) { uv_idle_t *check = malloc(sizeof(*check)); if (!check) { return kr_error(ENOMEM); } uv_idle_init(uv_default_loop(), check); check->data = L; return uv_idle_start(check, l_ffi_resume_cb); }
static int answer_query(knot_pkt_t *pkt, pack_t *addr_set, struct kr_query *qry) { uint16_t rrtype = qry->stype; uint16_t rrclass = qry->sclass; if (rrtype != KNOT_RRTYPE_A && rrtype != KNOT_RRTYPE_AAAA) { return kr_error(ENOENT); } knot_dname_t *qname = knot_dname_copy(qry->sname, &pkt->mm); knot_rrset_t rr; knot_rrset_init(&rr, qname, rrtype, rrclass); int family_len = sizeof(struct in_addr); if (rr.type == KNOT_RRTYPE_AAAA) { family_len = sizeof(struct in6_addr); } /* Append address records from hints */ uint8_t *addr = pack_head(*addr_set); while (addr != pack_tail(*addr_set)) { size_t len = pack_obj_len(addr); void *addr_val = pack_obj_val(addr); if (len == family_len) { knot_rrset_add_rdata(&rr, addr_val, len, 0, &pkt->mm); } addr = pack_obj_next(addr); } int ret = kr_error(ENOENT); if (!knot_rrset_empty(&rr)) { /* Update packet question */ if (!knot_dname_is_equal(knot_pkt_qname(pkt), qname)) { KR_PKT_RECYCLE(pkt); knot_pkt_put_question(pkt, qname, rrclass, rrtype); } /* Append to packet */ ret = knot_pkt_put(pkt, KNOT_COMPR_HINT_QNAME, &rr, KNOT_PF_FREE); } /* Clear RR if failed */ if (ret != 0) { knot_rrset_clear(&rr, &pkt->mm); } 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); }
int kr_dnssec_key_tag(uint16_t rrtype, const uint8_t *rdata, size_t rdlen) { if (!rdata || rdlen == 0 || (rrtype != KNOT_RRTYPE_DS && rrtype != KNOT_RRTYPE_DNSKEY)) { return kr_error(EINVAL); } if (rrtype == KNOT_RRTYPE_DS) { return wire_read_u16(rdata); } else if (rrtype == KNOT_RRTYPE_DNSKEY) { struct dseckey *key = NULL; int ret = kr_dnssec_key_from_rdata(&key, NULL, rdata, rdlen); if (ret != 0) { return ret; } uint16_t keytag = dnssec_key_get_keytag((dnssec_key_t *)key); kr_dnssec_key_free(&key); return keytag; } else { return kr_error(EINVAL); } }
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(); }
static int authenticate_ds(const dnssec_key_t *key, dnssec_binary_t *ds_rdata, uint8_t digest_type) { /* Compute DS RDATA from the DNSKEY. */ dnssec_binary_t computed_ds = {0, }; int ret = dnssec_key_create_ds(key, digest_type, &computed_ds); if (ret != DNSSEC_EOK) { ret = kr_error(ENOMEM); goto fail; } /* DS records contain algorithm, key tag and the digest. * Therefore the comparison of the two DS is sufficient. */ ret = (ds_rdata->size == computed_ds.size) && (memcmp(ds_rdata->data, computed_ds.data, ds_rdata->size) == 0); ret = ret ? kr_ok() : kr_error(ENOENT); fail: dnssec_binary_free(&computed_ds); return ret; }
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); }
int udp_bindfd(uv_udp_t *handle, int fd) { if (!handle) { return kr_error(EINVAL); } int ret = uv_udp_open(handle, (uv_os_sock_t) fd); if (ret != 0) { return ret; } return udp_bind_finalize((uv_handle_t *)handle); }
static int cdb_count(knot_db_t *db) { struct memcached_cli *cli = db; memcached_return_t error = 0; memcached_stat_st *stats = memcached_stat(cli->handle, NULL, &error); if (error != 0) { return kr_error(EIO); } size_t ret = stats->curr_items; free(stats); return (ret > INT_MAX) ? INT_MAX : ret; }
/** Fetch or create endpoint array and insert endpoint. */ static int insert_endpoint(struct network *net, const char *addr, struct endpoint *ep) { /* Fetch or insert address into map */ endpoint_array_t *ep_array = map_get(&net->endpoints, addr); if (ep_array == NULL) { ep_array = malloc(sizeof(*ep_array)); if (ep_array == NULL) { return kr_error(ENOMEM); } if (map_set(&net->endpoints, addr, ep_array) != 0) { free(ep_array); return kr_error(ENOMEM); } array_init(*ep_array); } if (array_push(*ep_array, ep) < 0) { return kr_error(ENOMEM); } 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(); }
int kr_dnssec_key_from_rdata(struct dseckey **key, const knot_dname_t *kown, const uint8_t *rdata, size_t rdlen) { if (!key || !rdata || rdlen == 0) { return kr_error(EINVAL); } dnssec_key_t *new_key = NULL; const dnssec_binary_t binary_key = { .size = rdlen, .data = (uint8_t *)rdata }; int ret = dnssec_key_new(&new_key); if (ret != DNSSEC_EOK) { return kr_error(ENOMEM); } ret = dnssec_key_set_rdata(new_key, &binary_key); if (ret != DNSSEC_EOK) { dnssec_key_free(new_key); return kr_error(ENOMEM); } if (kown) { ret = dnssec_key_set_dname(new_key, kown); if (ret != DNSSEC_EOK) { dnssec_key_free(new_key); return kr_error(ENOMEM); } } *key = (struct dseckey *) new_key; return kr_ok(); } void kr_dnssec_key_free(struct dseckey **key) { assert(key); dnssec_key_free((dnssec_key_t *) *key); *key = NULL; }
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 load_library(struct kr_module *module, const char *name, const char *path) { /* Absolute or relative path (then only library search path is used). */ auto_free char *lib_path = NULL; if (path != NULL) { lib_path = kr_strcatdup(4, path, "/", name, LIBEXT); } else { lib_path = kr_strcatdup(2, name, LIBEXT); } if (lib_path == NULL) { return kr_error(ENOMEM); } /* Workaround for buggy _fini/__attribute__((destructor)) and dlclose(), * this keeps the library mapped until the program finishes though. */ module->lib = dlopen(lib_path, RTLD_NOW | RTLD_NODELETE); if (module->lib) { return kr_ok(); } return kr_error(ENOENT); }
int kr_nsec_name_error_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); } 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; } int ret = name_error_response_check_rr(&flags, rrset, sname); if (ret != 0) { return ret; } } return kr_nsec_existence_denied(flags) ? kr_ok() : kr_error(ENOENT); }
static int add_pair(struct kr_zonecut *hints, const char *name, const char *addr) { /* Build key */ knot_dname_t key[KNOT_DNAME_MAXLEN]; if (!knot_dname_from_str(key, name, sizeof(key))) { return kr_error(EINVAL); } /* Parse address string */ struct sockaddr_storage ss; if (parse_addr_str(&ss, addr) != 0) { return kr_error(EINVAL); } /* Build rdata */ size_t addr_len = 0; uint8_t *raw_addr = sockaddr_raw(&ss, &addr_len); knot_rdata_t rdata[knot_rdata_array_size(addr_len)]; knot_rdata_init(rdata, addr_len, raw_addr, 0); return kr_zonecut_add(hints, key, rdata); }
int engine_cmd(struct engine *engine, const char *str) { if (engine == NULL || engine->L == NULL) { return kr_error(ENOEXEC); } /* Evaluate results */ lua_getglobal(engine->L, "eval_cmd"); lua_pushstring(engine->L, str); /* Check result. */ return engine_pcall(engine->L, 1); }
int kr_dnskeys_trusted(const knot_pkt_t *pkt, knot_section_t section_id, const knot_rrset_t *keys, const knot_rrset_t *ta, const knot_dname_t *zone_name, uint32_t timestamp, bool has_nsec3) { if (!pkt || !keys || !ta) { return kr_error(EINVAL); } /* RFC4035 5.2, bullet 1 * The supplied DS record has been authenticated. * It has been validated or is part of a configured trust anchor. */ for (uint16_t i = 0; i < keys->rrs.rr_count; ++i) { /* RFC4035 5.3.1, bullet 8 */ /* ZSK */ const knot_rdata_t *krr = knot_rdataset_at(&keys->rrs, i); const uint8_t *key_data = knot_rdata_data(krr); if (!kr_dnssec_key_zsk(key_data) || kr_dnssec_key_revoked(key_data)) { continue; } struct dseckey *key; if (kr_dnssec_key_from_rdata(&key, keys->owner, key_data, knot_rdata_rdlen(krr)) != 0) { continue; } if (kr_authenticate_referral(ta, (dnssec_key_t *) key) != 0) { kr_dnssec_key_free(&key); continue; } if (kr_rrset_validate_with_key(pkt, section_id, keys, keys, i, key, zone_name, timestamp, has_nsec3) != 0) { kr_dnssec_key_free(&key); continue; } kr_dnssec_key_free(&key); return kr_ok(); } /* No useable key found */ return kr_error(ENOENT); }
int kr_module_load(struct kr_module *module, const char *name, const char *path) { if (module == NULL || name == NULL) { return kr_error(EINVAL); } /* Initialize, keep userdata */ void *data = module->data; memset(module, 0, sizeof(struct kr_module)); module->data = data; module->name = strdup(name); if (module->name == NULL) { return kr_error(ENOMEM); } /* Search for module library, use current namespace if not found. */ if (load_library(module, name, path) != 0) { /* Expand HOME env variable, as the linker may not expand it. */ auto_free char *local_path = kr_strcatdup(2, getenv("HOME"), "/.local/lib/kdns_modules"); if (load_library(module, name, local_path) != 0) { if (load_library(module, name, MODULEDIR) != 0) { module->lib = RTLD_DEFAULT; } } } /* Try to load module ABI. */ int ret = load_sym_c(module, KR_MODULE_API); if (ret == 0 && module->init) { ret = module->init(module); } if (ret != 0) { kr_module_unload(module); } return ret; }