diff --git a/src/libknot/nameserver/internet.c b/src/libknot/nameserver/internet.c index a4739a4b40815bf389f11197cea976443ef27772..e604d1c38677e2d4cd7ebeb185a38f5fb84fbee8 100644 --- a/src/libknot/nameserver/internet.c +++ b/src/libknot/nameserver/internet.c @@ -15,6 +15,13 @@ */ #include "knot/server/zones.h" +/* Visited wildcard node list. */ +struct wildcard_hit { + node_t n; + const knot_node_t *node; + const knot_dname_t *sname; +}; + /*! \brief Query processing states. */ enum { BEGIN, /* Begin name resolution. */ @@ -26,6 +33,53 @@ enum { ERROR /* Resolution failed. */ }; +/*! \brief Check if given node was already visited. */ +static int wildcard_has_visited(struct query_data *qdata, const knot_node_t *node) +{ + struct wildcard_hit *item = NULL; + WALK_LIST(item, qdata->wildcards) { + if (item->node == node) { + return true; + } + } + return false; +} + +/*! \brief Mark given node as visited. */ +static int wildcard_visit(struct query_data *qdata, const knot_node_t *node, const knot_dname_t *sname) +{ + assert(qdata); + assert(node); + + mm_ctx_t *mm = qdata->mm; + struct wildcard_hit *item = mm->alloc(mm->ctx, sizeof(struct wildcard_hit)); + item->node = node; + item->sname = sname; + add_tail(&qdata->wildcards, (node_t *)item); + return KNOT_EOK; +} + +/*! \brief Put all covering records for wildcard list. */ +static int wildcard_list_cover(knot_pkt_t *pkt, struct query_data *qdata) +{ + int ret = KNOT_EOK; + struct wildcard_hit *item = NULL; + + WALK_LIST(item, qdata->wildcards) { + ret = ns_put_nsec_nsec3_wildcard_answer( + item->node, + knot_node_parent(item->node), + NULL, qdata->zone->contents, + item->sname, + pkt); + if (ret != KNOT_EOK) { + break; + } + } + + return ret; +} + static int follow_cname(knot_pkt_t *pkt, const knot_dname_t **name, struct query_data *qdata) { dbg_ns("%s(%p, %p, %p)\n", __func__, name, pkt, qdata); @@ -43,14 +97,14 @@ static int follow_cname(knot_pkt_t *pkt, const knot_dname_t **name, struct query /* Check if is not in wildcard nodes (loop). */ dbg_ns("%s: CNAME node %p is wildcard\n", __func__, cname_node); - if (ptrlist_contains(&qdata->wildcards, cname_node)) { + if (wildcard_has_visited(qdata, cname_node)) { dbg_ns("%s: node %p already visited => CNAME loop\n", __func__, cname_node); return HIT; } /* Put to wildcard node list. */ - if (ptrlist_add(&qdata->wildcards, cname_node, qdata->mm) == NULL) { + if (wildcard_visit(qdata, cname_node, *name) != KNOT_EOK) { return ERROR; } @@ -169,8 +223,14 @@ static int name_not_found(knot_pkt_t *pkt, const knot_dname_t **name, if (wildcard_node) { dbg_ns("%s: name %p covered by wildcard\n", __func__, *name); qdata->node = wildcard_node; - qdata->encloser = wildcard_node; + /* keep encloser */ qdata->previous = NULL; + + /* Put to wildcard node list. */ + if (wildcard_visit(qdata, qdata->encloser, *name) != KNOT_EOK) { + return ERROR; + } + return name_found(pkt, name, qdata); } @@ -187,6 +247,13 @@ static int name_not_found(knot_pkt_t *pkt, const knot_dname_t **name, return FOLLOW; } + /* Name is below delegation. */ + if (knot_node_is_deleg_point(qdata->encloser)) { + dbg_ns("%s: name below delegation point %p\n", __func__, *name); + qdata->node = qdata->encloser; + return DELEG; + } + dbg_ns("%s: name not found in zone %p\n", __func__, *name); return MISS; } @@ -245,18 +312,43 @@ static int solve_authority(int state, const knot_dname_t **qname, switch (state) { case HIT: /* Positive response, add (optional) AUTHORITY NS. */ + dbg_ns("%s: answer is POSITIVE\n", __func__); ret = ns_put_authority_ns(zone_contents, pkt); - dbg_ns("%s: putting authority NS = %d\n", __func__, ret); if (ret == KNOT_ESPACE) { /* Optional. */ ret = KNOT_EOK; } + /* Put NSEC/NSEC3 Wildcard proof if answered from wildcard. */ + if (ret == KNOT_EOK && knot_pkt_have_dnssec(qdata->pkt)) { + ret = wildcard_list_cover(pkt, qdata); + } break; case MISS: /* MISS, set NXDOMAIN RCODE. */ - qdata->rcode = KNOT_RCODE_NXDOMAIN; dbg_ns("%s: answer is NXDOMAIN\n", __func__); - case NODATA: /* NODATA or NXDOMAIN, append AUTHORITY SOA. */ + qdata->rcode = KNOT_RCODE_NXDOMAIN; ret = ns_put_authority_soa(zone_contents, pkt); - dbg_ns("%s: putting authority SOA = %d\n", __func__, ret); + if (ret == KNOT_EOK && knot_pkt_have_dnssec(qdata->pkt)) { + ret = ns_put_nsec_nsec3_nxdomain(zone_contents, + qdata->previous, + qdata->encloser, + *qname, pkt); + } + break; + case NODATA: /* NODATA append AUTHORITY SOA + NSEC/NSEC3. */ + dbg_ns("%s: answer is NODATA\n", __func__); + ret = ns_put_authority_soa(zone_contents, pkt); + if (ret == KNOT_EOK && knot_pkt_have_dnssec(qdata->pkt)) { + if (knot_dname_is_wildcard(qdata->node->owner)) { + ret = ns_put_nsec_nsec3_wildcard_nodata(qdata->node, + qdata->encloser, + qdata->previous, + qdata->zone->contents, + *qname, pkt); + } else { + ret = ns_put_nsec_nsec3_nodata(zone_contents, + qdata->node, + pkt); + } + } break; case DELEG: /* Referral response. */ /*! \todo DS + NS */ ret = ns_referral(qdata->node, zone_contents, *qname, pkt, knot_pkt_qtype(pkt)); diff --git a/src/libknot/nameserver/name-server.c b/src/libknot/nameserver/name-server.c index 3851c8d6112311cc6a34ece52bbee364d2695957..75f0cbcc2f0f991ad9008c7f3bcf46766070d128 100644 --- a/src/libknot/nameserver/name-server.c +++ b/src/libknot/nameserver/name-server.c @@ -829,7 +829,7 @@ int ns_put_additional(const knot_zone_t *zone, knot_pkt_t *resp) int ns_put_authority_ns(const knot_zone_contents_t *zone, knot_pkt_t *resp) { - dbg_ns_verb("PUTTING AUTHORITY NS\n"); + dbg_ns("%s: putting authority NS\n", __func__); assert(KNOT_PKT_IN_NS(resp)); knot_rrset_t *ns_rrset = knot_node_get_rrset( @@ -869,7 +869,7 @@ int ns_put_authority_soa(const knot_zone_contents_t *zone, knot_pkt_t *resp) { assert(KNOT_PKT_IN_NS(resp)); - dbg_ns_verb("PUTTING AUTHORITY SOA\n"); + dbg_ns("%s: putting authority SOA\n", __func__); int ret; @@ -1219,9 +1219,9 @@ static int ns_put_nsec3_no_wildcard_child(const knot_zone_contents_t *zone, * RRSets of the requested type). * \param resp Response where to add the NSECs or NSEC3s. */ -static int ns_put_nsec_nsec3_nodata(const knot_zone_contents_t *zone, - const knot_node_t *node, - knot_pkt_t *resp) +int ns_put_nsec_nsec3_nodata(const knot_zone_contents_t *zone, + const knot_node_t *node, + knot_pkt_t *resp) { if (!DNSSEC_ENABLED || !knot_pkt_have_dnssec(resp->query)) { @@ -1235,8 +1235,7 @@ static int ns_put_nsec_nsec3_nodata(const knot_zone_contents_t *zone, if (knot_zone_contents_nsec3_enabled(zone)) { knot_node_t *nsec3_node = knot_node_get_nsec3_node(node); - dbg_ns_verb("Adding NSEC3 for NODATA, NSEC3 node: %p\n", - nsec3_node); + dbg_ns("%s: adding NSEC3 NODATA\n", __func__); if (nsec3_node != NULL && (rrset = knot_node_get_rrset(nsec3_node, @@ -1249,7 +1248,7 @@ static int ns_put_nsec_nsec3_nodata(const knot_zone_contents_t *zone, return KNOT_ENONODE; } } else { - dbg_ns_verb("Adding NSEC for NODATA\n"); + dbg_ns("%s: adding NSEC NODATA\n", __func__); if ((rrset = knot_node_get_rrset(node, KNOT_RRTYPE_NSEC)) != NULL && knot_rrset_rdata_rr_count(rrset)) { @@ -1464,7 +1463,7 @@ static int ns_put_nsec3_nxdomain(const knot_zone_contents_t *zone, * \retval KNOT_EOK * \retval NS_ERR_SERVFAIL */ -static int ns_put_nsec_nsec3_nxdomain(const knot_zone_contents_t *zone, +int ns_put_nsec_nsec3_nxdomain(const knot_zone_contents_t *zone, const knot_node_t *previous, const knot_node_t *closest_encloser, const knot_dname_t *qname, @@ -1612,25 +1611,25 @@ static int ns_put_nsec_wildcard(const knot_zone_contents_t *zone, * \retval KNOT_EOK * \retval NS_ERR_SERVFAIL */ -static int ns_put_nsec_nsec3_wildcard_nodata(const knot_node_t *node, - const knot_node_t *closest_encloser, - const knot_node_t *previous, - const knot_zone_contents_t *zone, - const knot_dname_t *qname, - knot_pkt_t *resp) +int ns_put_nsec_nsec3_wildcard_nodata(const knot_node_t *node, + const knot_node_t *closest_encloser, + const knot_node_t *previous, + const knot_zone_contents_t *zone, + const knot_dname_t *qname, + knot_pkt_t *resp) { int ret = KNOT_EOK; if (DNSSEC_ENABLED && knot_pkt_have_dnssec(resp->query)) { if (knot_zone_contents_nsec3_enabled(zone)) { ret = ns_put_nsec3_closest_encloser_proof(zone, - &closest_encloser, - qname, resp); + &closest_encloser, + qname, resp); const knot_node_t *nsec3_node; if (ret == KNOT_EOK && (nsec3_node = knot_node_nsec3_node(node)) - != NULL) { + != NULL) { ret = ns_put_nsec3_from_node(nsec3_node, resp); } } else { @@ -1684,29 +1683,7 @@ int ns_put_nsec_nsec3_wildcard_answer(const knot_node_t *node, /*----------------------------------------------------------------------------*/ -static int ns_put_nsec_nsec3_wildcard_nodes(knot_pkt_t *response, - const knot_zone_contents_t *zone) -{ - assert(response != NULL); - assert(zone != NULL); - int ret = 0; - - for (int i = 0; i < response->wildcard_nodes.count; ++i) { - ret = ns_put_nsec_nsec3_wildcard_answer( - response->wildcard_nodes.nodes[i], - knot_node_parent( - response->wildcard_nodes.nodes[i]), - NULL, zone, - response->wildcard_nodes.snames[i], - response); - if (ret != KNOT_EOK) { - return ret; - } - } - - return KNOT_EOK; -} /*----------------------------------------------------------------------------*/ /*! @@ -2172,11 +2149,6 @@ static int ns_xfr_send_and_clear(knot_ns_xfr_t *xfr, int add_tsig) knot_pkt_tsig_set(xfr->response, NULL); } -dbg_ns_exec_verb( - dbg_ns_verb("Response structure after clearing:\n"); - knot_pkt_dump(xfr->response); -); - return KNOT_EOK; } @@ -2966,11 +2938,6 @@ int knot_ns_init_xfr(knot_nameserver_t *nameserver, knot_ns_xfr_t *xfr) return ret; } -dbg_ns_exec_verb( - dbg_ns_verb("Parsed XFR query:\n"); - knot_pkt_dump(xfr->query); -); - knot_zonedb_t *zonedb = rcu_dereference(nameserver->zone_db); const knot_dname_t *qname = knot_pkt_qname(xfr->query); @@ -3558,6 +3525,16 @@ int ns_proc_begin(ns_proc_context_t *ctx, const ns_proc_module_t *module) return NS_PROC_NOOP; } +#ifdef KNOT_NS_DEBUG + /* Check module API. */ + assert(module->begin); + assert(module->in); + assert(module->out); + assert(module->err); + assert(module->reset); + assert(module->finish); +#endif /* KNOT_NS_DEBUG */ + ctx->module = module; ctx->state = module->begin(ctx); diff --git a/src/libknot/nameserver/name-server.h b/src/libknot/nameserver/name-server.h index fcbfac1fb1f31e37b91f5d4fd0568518c44d2b05..e0d70e3acc2d81aabff4888063e216c9523317b8 100644 --- a/src/libknot/nameserver/name-server.h +++ b/src/libknot/nameserver/name-server.h @@ -397,12 +397,6 @@ const knot_zone_t *ns_get_zone_for_qname(knot_zonedb_t *zdb, uint16_t qtype); int ns_put_additional(const knot_zone_t *zone, knot_pkt_t *resp); -int ns_put_nsec_nsec3_wildcard_answer(const knot_node_t *node, - const knot_node_t *closest_encloser, - const knot_node_t *previous, - const knot_zone_contents_t *zone, - const knot_dname_t *qname, - knot_pkt_t *resp); int ns_put_authority_soa(const knot_zone_contents_t *zone, knot_pkt_t *resp); @@ -431,6 +425,30 @@ int ns_process_dname(knot_rrset_t *dname_rrset, int ns_add_dnskey(const knot_node_t *apex, knot_pkt_t *resp); +int ns_put_nsec_nsec3_nodata(const knot_zone_contents_t *zone, + const knot_node_t *node, + knot_pkt_t *resp); + +int ns_put_nsec_nsec3_nxdomain(const knot_zone_contents_t *zone, + const knot_node_t *previous, + const knot_node_t *closest_encloser, + const knot_dname_t *qname, + knot_pkt_t *resp); + +int ns_put_nsec_nsec3_wildcard_answer(const knot_node_t *node, + const knot_node_t *closest_encloser, + const knot_node_t *previous, + const knot_zone_contents_t *zone, + const knot_dname_t *qname, + knot_pkt_t *resp); + +int ns_put_nsec_nsec3_wildcard_nodata(const knot_node_t *node, + const knot_node_t *closest_encloser, + const knot_node_t *previous, + const knot_zone_contents_t *zone, + const knot_dname_t *qname, + knot_pkt_t *resp); + /* #10 >>> Exposed API. */ /* #10 <<< Next-gen API. */