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(); }
static int knot_zone_diff_load_soas(const zone_contents_t *zone1, const zone_contents_t *zone2, changeset_t *changeset) { if (zone1 == NULL || zone2 == NULL || changeset == NULL) { return KNOT_EINVAL; } const zone_node_t *apex1 = zone1->apex; const zone_node_t *apex2 = zone2->apex; if (apex1 == NULL || apex2 == NULL) { return KNOT_EINVAL; } knot_rrset_t soa_rrset1 = node_rrset(apex1, KNOT_RRTYPE_SOA); knot_rrset_t soa_rrset2 = node_rrset(apex2, KNOT_RRTYPE_SOA); if (knot_rrset_empty(&soa_rrset1) || knot_rrset_empty(&soa_rrset2)) { return KNOT_EINVAL; } if (soa_rrset1.rrs.rr_count == 0 || soa_rrset2.rrs.rr_count == 0) { return KNOT_EINVAL; } int64_t soa_serial1 = knot_soa_serial(&soa_rrset1.rrs); int64_t soa_serial2 = knot_soa_serial(&soa_rrset2.rrs); if (serial_compare(soa_serial1, soa_serial2) == 0) { return KNOT_ENODIFF; } if (serial_compare(soa_serial1, soa_serial2) > 0) { return KNOT_ERANGE; } assert(changeset); changeset->soa_from = knot_rrset_copy(&soa_rrset1, NULL); if (changeset->soa_from == NULL) { return KNOT_ENOMEM; } changeset->soa_to = knot_rrset_copy(&soa_rrset2, NULL); if (changeset->soa_to == NULL) { knot_rrset_free(&changeset->soa_from, NULL); return KNOT_ENOMEM; } dbg_zonediff_verb("zone_diff: load_soas: SOAs diffed. " "(%"PRId64" -> %"PRId64")\n", soa_serial1, soa_serial2); return KNOT_EOK; }
static knot_rrset_t *update_ds(struct kr_zonecut *cut, const knot_pktsection_t *sec) { /* Aggregate DS records (if using multiple keys) */ knot_rrset_t *new_ds = NULL; for (unsigned i = 0; i < sec->count; ++i) { const knot_rrset_t *rr = knot_pkt_rr(sec, i); if (rr->type != KNOT_RRTYPE_DS) { continue; } int ret = 0; if (new_ds) { ret = knot_rdataset_merge(&new_ds->rrs, &rr->rrs, cut->pool); } else { new_ds = knot_rrset_copy(rr, cut->pool); if (!new_ds) { return NULL; } } if (ret != 0) { knot_rrset_free(&new_ds, cut->pool); return NULL; } } return new_ds; }
static int wrk_resolve(lua_State *L) { struct worker_ctx *worker = wrk_luaget(L); if (!worker) { return 0; } /* Create query packet */ knot_pkt_t *pkt = knot_pkt_new(NULL, KNOT_EDNS_MAX_UDP_PAYLOAD, NULL); if (!pkt) { lua_pushstring(L, strerror(ENOMEM)); lua_error(L); } uint8_t dname[KNOT_DNAME_MAXLEN]; knot_dname_from_str(dname, lua_tostring(L, 1), sizeof(dname)); /* Check class and type */ uint16_t rrtype = lua_tointeger(L, 2); if (!lua_isnumber(L, 2)) { lua_pushstring(L, "invalid RR type"); lua_error(L); } uint16_t rrclass = lua_tointeger(L, 3); if (!lua_isnumber(L, 3)) { /* Default class is IN */ rrclass = KNOT_CLASS_IN; } knot_pkt_put_question(pkt, dname, rrclass, rrtype); knot_wire_set_rd(pkt->wire); /* Add OPT RR */ pkt->opt_rr = knot_rrset_copy(worker->engine->resolver.opt_rr, NULL); if (!pkt->opt_rr) { return kr_error(ENOMEM); } /* Add completion callback */ int ret = 0; unsigned options = lua_tointeger(L, 4); if (lua_isfunction(L, 5)) { /* Store callback in registry */ lua_pushvalue(L, 5); int cb = luaL_ref(L, LUA_REGISTRYINDEX); ret = worker_resolve(worker, pkt, options, resolve_callback, (void *) (intptr_t)cb); } else { ret = worker_resolve(worker, pkt, options, NULL, NULL); } knot_rrset_free(&pkt->opt_rr, NULL); knot_pkt_free(&pkt); lua_pushboolean(L, ret == 0); return 1; }
static int validate_records(struct kr_query *qry, knot_pkt_t *answer, knot_mm_t *pool, bool has_nsec3) { if (!qry->zone_cut.key) { DEBUG_MSG(qry, "<= no DNSKEY, can't validate\n"); return kr_error(EBADMSG); } kr_rrset_validation_ctx_t vctx = { .pkt = answer, .section_id = KNOT_ANSWER, .keys = qry->zone_cut.key, .zone_name = qry->zone_cut.name, .timestamp = qry->timestamp.tv_sec, .has_nsec3 = has_nsec3, .flags = 0, .result = 0 }; int ret = validate_section(&vctx, pool); if (ret != 0) { return ret; } uint32_t an_flags = vctx.flags; vctx.section_id = KNOT_AUTHORITY; /* zone_name can be changed by validate_section(), restore it */ vctx.zone_name = qry->zone_cut.name; vctx.flags = 0; vctx.result = 0; ret = validate_section(&vctx, pool); if (ret != 0) { return ret; } /* Records were validated. * If there is wildcard expansion in answer, flag the query. */ if (an_flags & KR_DNSSEC_VFLG_WEXPAND) { qry->flags |= QUERY_DNSSEC_WEXPAND; } return ret; } static int validate_keyset(struct kr_query *qry, knot_pkt_t *answer, bool has_nsec3) { /* Merge DNSKEY records from answer that are below/at current cut. */ bool updated_key = false; const knot_pktsection_t *an = knot_pkt_section(answer, KNOT_ANSWER); for (unsigned i = 0; i < an->count; ++i) { const knot_rrset_t *rr = knot_pkt_rr(an, i); if ((rr->type != KNOT_RRTYPE_DNSKEY) || !knot_dname_in(qry->zone_cut.name, rr->owner)) { continue; } /* Merge with zone cut (or replace ancestor key). */ if (!qry->zone_cut.key || !knot_dname_is_equal(qry->zone_cut.key->owner, rr->owner)) { qry->zone_cut.key = knot_rrset_copy(rr, qry->zone_cut.pool); if (!qry->zone_cut.key) { return kr_error(ENOMEM); } updated_key = true; } else { int ret = knot_rdataset_merge(&qry->zone_cut.key->rrs, &rr->rrs, qry->zone_cut.pool); if (ret != 0) { knot_rrset_free(&qry->zone_cut.key, qry->zone_cut.pool); return ret; } updated_key = true; } } /* Check if there's a key for current TA. */ if (updated_key && !(qry->flags & QUERY_CACHED)) { kr_rrset_validation_ctx_t vctx = { .pkt = answer, .section_id = KNOT_ANSWER, .keys = qry->zone_cut.key, .zone_name = qry->zone_cut.name, .timestamp = qry->timestamp.tv_sec, .has_nsec3 = has_nsec3, .flags = 0, .result = 0 }; int ret = kr_dnskeys_trusted(&vctx, qry->zone_cut.trust_anchor); if (ret != 0) { knot_rrset_free(&qry->zone_cut.key, qry->zone_cut.pool); return ret; } if (vctx.flags & KR_DNSSEC_VFLG_WEXPAND) { qry->flags |= QUERY_DNSSEC_WEXPAND; } } return kr_ok(); }