diff --git a/src/knot/server/zones.c b/src/knot/server/zones.c index 2c0a4d763305dbaa50a0d23702992cfa5578f6cc..a041597b6e30fa813c8b73c725a5ac549f4e58aa 100644 --- a/src/knot/server/zones.c +++ b/src/knot/server/zones.c @@ -554,7 +554,7 @@ int zones_changesets_from_binary(knot_changesets_t *chgsets) /*----------------------------------------------------------------------------*/ -static int zones_load_changesets(const knot_zone_t *zone, +int zones_load_changesets(const knot_zone_t *zone, knot_changesets_t *dst, uint32_t from, uint32_t to) { @@ -1313,6 +1313,8 @@ int zones_xfr_check_zone(knot_ns_xfr_t *xfr, knot_rcode_t *rcode) rcode); } +/*! \todo #10 leaving it here for TSIG later on */ +#if 0 /*----------------------------------------------------------------------------*/ /*! \todo This function is here only because TSIG key is associated with the * zone via zonedata. If it was in the zone structure (which would be @@ -1554,6 +1556,7 @@ int zones_normal_query_answer(knot_nameserver_t *nameserver, return KNOT_EOK; } +#endif /*----------------------------------------------------------------------------*/ diff --git a/src/knot/server/zones.h b/src/knot/server/zones.h index c0406f9dca5e9e3f39bef1759ac9480e2bfbb879..da2f741f8ee3c88bf8f9d05f7dddb5c563b71abc 100644 --- a/src/knot/server/zones.h +++ b/src/knot/server/zones.h @@ -122,14 +122,6 @@ int zones_query_check_zone(const knot_zone_t *zone, uint8_t q_opcode, */ int zones_xfr_check_zone(knot_ns_xfr_t *xfr, knot_rcode_t *rcode); -/*! - * \todo Document me. - */ -int zones_normal_query_answer(knot_nameserver_t *nameserver, - knot_pkt_t *query, const sockaddr_t *addr, - uint8_t *response_wire, size_t *rsize, - knot_ns_transport_t transport); - /*! * \todo Document me. */ @@ -256,6 +248,10 @@ int zones_changesets_to_binary(knot_changesets_t *chgsets); int zones_xfr_load_changesets(knot_ns_xfr_t *xfr, uint32_t serial_from, uint32_t serial_to); +int zones_load_changesets(const knot_zone_t *zone, + knot_changesets_t *dst, + uint32_t from, uint32_t to) __attribute__((deprecated)); + /*! * \brief Creates changesets from zones difference. * diff --git a/src/libknot/nameserver/internet.c b/src/libknot/nameserver/internet.c index fed072c8075e39245ee1184c2a42850a0ec5e68f..a4739a4b40815bf389f11197cea976443ef27772 100644 --- a/src/libknot/nameserver/internet.c +++ b/src/libknot/nameserver/internet.c @@ -128,7 +128,7 @@ static int name_found(knot_pkt_t *pkt, const knot_dname_t **name, } int added = 0; /*! \todo useless */ - int ret = ns_put_answer(qdata->node, pkt->zone->contents, *name, qtype, pkt, &added, 0 /*! \todo check from pkt */); + int ret = ns_put_answer(qdata->node, qdata->zone->contents, *name, qtype, pkt, &added, 0 /*! \todo check from pkt */); if (ret != KNOT_EOK) { dbg_ns("%s: failed answer from node %p (%d)\n", __func__, qdata->node, ret); @@ -143,7 +143,7 @@ static int name_found(knot_pkt_t *pkt, const knot_dname_t **name, // or NS records in Answer section if (knot_wire_get_tc(pkt->wire) == 0 && knot_pkt_have_dnssec(pkt->query) - && qdata->node == knot_zone_contents_apex(pkt->zone->contents) + && qdata->node == knot_zone_contents_apex(qdata->zone->contents) && (qtype == KNOT_RRTYPE_SOA || qtype == KNOT_RRTYPE_NS)) { ret = ns_add_dnskey(qdata->node, pkt); if (ret != KNOT_EOK) { @@ -195,7 +195,7 @@ static int solve_name(int state, const knot_dname_t **name, knot_pkt_t *pkt, struct query_data *qdata) { dbg_ns("%s(%d, %p, %p, %p)\n", __func__, state, name, pkt, qdata); - int ret = knot_zone_contents_find_dname(pkt->zone->contents, *name, + int ret = knot_zone_contents_find_dname(qdata->zone->contents, *name, &qdata->node, &qdata->encloser, &qdata->previous); @@ -241,10 +241,11 @@ static int solve_authority(int state, const knot_dname_t **qname, knot_pkt_t *pkt, struct query_data *qdata) { int ret = KNOT_ERROR; + const knot_zone_contents_t *zone_contents = qdata->zone->contents; switch (state) { case HIT: /* Positive response, add (optional) AUTHORITY NS. */ - ret = ns_put_authority_ns(pkt->zone->contents, pkt); + 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; @@ -254,11 +255,11 @@ static int solve_authority(int state, const knot_dname_t **qname, qdata->rcode = KNOT_RCODE_NXDOMAIN; dbg_ns("%s: answer is NXDOMAIN\n", __func__); case NODATA: /* NODATA or NXDOMAIN, append AUTHORITY SOA. */ - ret = ns_put_authority_soa(pkt->zone->contents, pkt); + ret = ns_put_authority_soa(zone_contents, pkt); dbg_ns("%s: putting authority SOA = %d\n", __func__, ret); break; case DELEG: /* Referral response. */ /*! \todo DS + NS */ - ret = ns_referral(qdata->node, pkt->zone->contents, *qname, pkt, knot_pkt_qtype(pkt)); + ret = ns_referral(qdata->node, zone_contents, *qname, pkt, knot_pkt_qtype(pkt)); break; case ERROR: dbg_ns("%s: failed to resolve qname\n", __func__); @@ -280,16 +281,7 @@ int internet_answer(knot_pkt_t *response, struct query_data *qdata) return NS_PROC_FAIL; } - /* Check zone state. */ - switch(knot_zone_state(response->zone)) { - case KNOT_EOK: - break; - case KNOT_ENOENT: - qdata->rcode = KNOT_RCODE_REFUSED; - return NS_PROC_FAIL; - default: - return NS_PROC_FAIL; - } + NS_NEED_VALID_ZONE(qdata, KNOT_RCODE_REFUSED); /* Write answer RRs for QNAME. */ dbg_ns("%s: writing %p ANSWER\n", __func__, response); @@ -315,7 +307,7 @@ int internet_answer(knot_pkt_t *response, struct query_data *qdata) /* Resolve ADDITIONAL. */ dbg_ns("%s: writing %p ADDITIONAL\n", __func__, response); knot_pkt_begin(response, KNOT_ADDITIONAL); - ret = ns_put_additional(response); + ret = ns_put_additional(qdata->zone, response); if (ret != KNOT_EOK) { return NS_PROC_FAIL; @@ -372,28 +364,10 @@ int internet_notify(knot_pkt_t *pkt, knot_nameserver_t *ns, struct query_data *q } /* RFC1996 require SOA question. */ - if (knot_pkt_qtype(qdata->pkt) != KNOT_RRTYPE_SOA) { - dbg_ns("%s: NOTIFY query_type != SOA\n", __func__); - qdata->rcode = KNOT_RCODE_FORMERR; - return NS_PROC_FAIL; - } - - /* Check zone state. */ - switch(knot_zone_state(pkt->zone)) { - case KNOT_EOK: - break; - case KNOT_ENOENT: - /*! \note NOTIFY/RFC1996 isn't clear on error RCODEs. - * Most servers use NOTAUTH from RFC2136. */ - qdata->rcode = KNOT_RCODE_NOTAUTH; - return NS_PROC_FAIL; - default: - return NS_PROC_FAIL; - } - - - /* Process notification. */ - assert(pkt->zone != NULL); /* Should be checked. */ + NS_NEED_QTYPE(qdata, KNOT_RRTYPE_SOA, KNOT_RCODE_FORMERR); + /*! \note NOTIFY/RFC1996 isn't clear on error RCODEs. + * Most servers use NOTAUTH from RFC2136. */ + NS_NEED_VALID_ZONE(qdata, KNOT_RCODE_NOTAUTH); /* SOA RR in answer may be included, recover serial. */ unsigned serial = 0; @@ -409,7 +383,7 @@ int internet_notify(knot_pkt_t *pkt, knot_nameserver_t *ns, struct query_data *q } int next_state = NS_PROC_FAIL; - int ret = notify_reschedule(ns, pkt->zone, NULL /*! \todo API */); + int ret = notify_reschedule(ns, qdata->zone, NULL /*! \todo API */); /* Format resulting log message. */ char *qname_str = knot_dname_to_str(knot_pkt_qname(pkt)); diff --git a/src/libknot/nameserver/internet.h b/src/libknot/nameserver/internet.h index d073bcd2fcd2f236b9a5c1caad2f25435f6b96a2..f617fa7f0acb0b87be8f106fbd05a3ccbcb5b249 100644 --- a/src/libknot/nameserver/internet.h +++ b/src/libknot/nameserver/internet.h @@ -48,6 +48,33 @@ int internet_answer(knot_pkt_t *resp, struct query_data *qdata); */ int internet_notify(knot_pkt_t *pkt, knot_nameserver_t *ns, struct query_data *qdata); + +/*! \brief Require given QUERY TYPE or return error code. */ +#define NS_NEED_QTYPE(qdata, qtype_want, error_rcode) \ + if (knot_pkt_qtype((qdata)->pkt) != (qtype_want)) { \ + qdata->rcode = (error_rcode); \ + return NS_PROC_FAIL; \ + } + +/*! \brief Require given QUERY NAME or return error code. */ +#define NS_NEED_QNAME(qdata, qname_want, error_rcode) \ + if (!knot_dname_is_equal(knot_pkt_qname((qdata)->pkt), (qname_want))) { \ + qdata->rcode = (error_rcode); \ + return NS_PROC_FAIL; \ + } + +/*! \brief Require valid zone or return error code. */ +#define NS_NEED_VALID_ZONE(qdata, error_rcode) \ + switch(knot_zone_state((qdata)->zone)) { \ + case KNOT_EOK: \ + break; \ + case KNOT_ENOENT: \ + qdata->rcode = (error_rcode); \ + return NS_PROC_FAIL; \ + default: \ + return NS_PROC_FAIL; \ + } + #endif /* _KNOT_INTERNET_H_ */ /*! @} */ diff --git a/src/libknot/nameserver/name-server.c b/src/libknot/nameserver/name-server.c index 7fa64206e94882b54b5dc99a6b3a589d4e0b65a9..3851c8d6112311cc6a34ece52bbee364d2695957 100644 --- a/src/libknot/nameserver/name-server.c +++ b/src/libknot/nameserver/name-server.c @@ -276,6 +276,7 @@ static void cname_chain_free(list_t *chain) static int ns_follow_cname(const knot_node_t **node, const knot_dname_t **qname, knot_pkt_t *resp, + const knot_zone_t *zone, int flags) { dbg_ns_verb("Resolving CNAME chain...\n"); @@ -394,7 +395,6 @@ dbg_ns_exec_verb( /* Attempt to find mentioned name in zone. */ rcu_read_lock(); - const knot_zone_t *zone = resp->zone; knot_zone_contents_t *contents = knot_zone_get_contents(zone); const knot_node_t *encloser = NULL, *prev = NULL; knot_zone_contents_find_dname(contents, cname, node, &encloser, &prev); @@ -625,7 +625,7 @@ dbg_ns_exec_verb( * \param resp Response where to add the Additional data. * \param rrset RRSet to get the Additional data for. */ -static int ns_put_additional_for_rrset(knot_pkt_t *resp, uint16_t rr_id) +static int ns_put_additional_for_rrset(const knot_zone_t *zone, knot_pkt_t *resp, uint16_t rr_id) { assert(KNOT_PKT_IN_AR(resp)); assert(rr_id < resp->rrset_count); @@ -652,7 +652,6 @@ dbg_ns_exec_detail( /* Attempt to find mentioned name in zone. */ rcu_read_lock(); - const knot_zone_t *zone = resp->zone; knot_zone_contents_t *contents = knot_zone_get_contents(zone); knot_zone_contents_find_dname(contents, dname, &node, &encloser, &prev); if (node == NULL && encloser && encloser->wildcard_child) @@ -673,7 +672,7 @@ dbg_ns_exec( const knot_dname_t *dname = knot_node_owner(node); assert(KNOT_PKT_IN_AR(resp)); - ret = ns_follow_cname(&node, &dname, resp, 0); + ret = ns_follow_cname(&node, &dname, resp, zone, 0); if (ret != KNOT_EOK) { dbg_ns("Failed to follow CNAME.\n"); return ret; @@ -797,7 +796,7 @@ static int ns_additional_needed(uint16_t qtype) * * \param resp Response to process. */ -int ns_put_additional(knot_pkt_t *resp) +int ns_put_additional(const knot_zone_t *zone, knot_pkt_t *resp) { dbg_ns_verb("ADDITIONAL SECTION PROCESSING\n"); @@ -810,7 +809,7 @@ int ns_put_additional(knot_pkt_t *resp) uint16_t rr_count = resp->rrset_count; for (uint16_t i = 0; i < rr_count; ++i) { if (ns_additional_needed(knot_rrset_type(resp->rr[i]))) { - ret = ns_put_additional_for_rrset(resp, i); + ret = ns_put_additional_for_rrset(zone, resp, i); if (ret != KNOT_EOK) { break; } @@ -1852,98 +1851,6 @@ int ns_referral(const knot_node_t *node, /*----------------------------------------------------------------------------*/ -/*! - * \brief Tries to answer the query from the given node. - * - * Tries to put RRSets of requested type (\a qtype) to the Answer section of the - * response. If successful, it also adds authority NS RRSet to the Authority - * section and it may add NSEC or NSEC3s in case of a wildcard answer (\a node - * is a wildcard node). If not successful (there are no such RRSets), it adds - * the SOA record to the Authority section and may add NSEC or NSEC3s according - * to the type of the response (NXDOMAIN if \a node is an empty non-terminal, - * NODATA if it is a regular node). It also adds any additional data that may - * be required. - * - * \param node Node to answer from. - * \param closest_encloser Closest encloser of \a qname in the zone. - * \param previous Previous domain name of \a qname in canonical order. - * \param zone Zone used for answering. - * \param qname Searched domain name. - * \param qtype Searched RR type. - * \param resp Response. - * - * \retval KNOT_EOK - * \retval NS_ERR_SERVFAIL - */ -static int ns_answer_from_node(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, uint16_t qtype, - knot_pkt_t *resp, int check_any) -{ - dbg_ns_verb("Putting answers from found node to the response...\n"); - int answers = 0; - - int ret = ns_put_answer(node, zone, qname, qtype, resp, &answers, - check_any); - if (ret != KNOT_EOK) { - return ret; - } - - /* ANSWER complete, proceed with AUTHORITY. */ - knot_pkt_begin(resp, KNOT_AUTHORITY); - - assert(ret == KNOT_EOK); - - if (answers == 0) { // if NODATA response, put SOA - ret = ns_put_authority_soa(zone, resp); - if (knot_node_rrset_count(node) == 0 - && !knot_zone_contents_nsec3_enabled(zone)) { - // node is an empty non-terminal => NSEC for NXDOMAIN - //assert(knot_node_rrset_count(closest_encloser) > 0); - dbg_ns_verb("Adding NSEC/NSEC3 for NXDOMAIN.\n"); - ret = ns_put_nsec_nsec3_nxdomain(zone, - knot_node_previous(node), closest_encloser, - qname, resp); - } else { - dbg_ns_verb("Adding NSEC/NSEC3 for NODATA.\n"); - ret = ns_put_nsec_nsec3_nodata(zone, node, resp); - if (ret != KNOT_EOK) { - dbg_ns("Failed adding NSEC/NSEC3 for NODATA: %s" - "\n", knot_strerror(ret)); - return ret; - } - - if (knot_dname_is_wildcard(node->owner)) { - dbg_ns_verb("Putting NSEC/NSEC3 for wildcard" - " NODATA\n"); - ret = ns_put_nsec_nsec3_wildcard_nodata(node, - closest_encloser, previous, zone, qname, - resp); - if (ret != KNOT_EOK) { - return ret; - } - } - } - } else { // else put authority NS - assert(closest_encloser == knot_node_parent(node) - || !knot_dname_is_wildcard(knot_node_owner(node)) - || knot_dname_cmp(qname, knot_node_owner(node)) == 0); - - ret = ns_put_nsec_nsec3_wildcard_answer(node, closest_encloser, - previous, zone, qname, resp); - - if (ret == KNOT_EOK) { - ret = ns_put_authority_ns(zone, resp); - } - } - - return ret; -} - -/*----------------------------------------------------------------------------*/ - /*! * \brief Synthetizes a CNAME RR from a DNAME. * @@ -2113,297 +2020,6 @@ int ns_add_dnskey(const knot_node_t *apex, knot_pkt_t *resp) return ret; } -/*----------------------------------------------------------------------------*/ -/*! - * \brief Answers the query from the given zone. - * - * This function performs the actual answering logic. - * - * \param zone Zone to use for answering. - * \param qname QNAME from the query. - * \param qtype QTYPE from the query. - * \param resp Response to fill in. - * - * \retval KNOT_EOK - * \retval NS_ERR_SERVFAIL - * - * \todo Describe the answering logic in detail. - */ -static int ns_answer_from_zone(const knot_zone_contents_t *zone, - knot_pkt_t *resp, int check_any) -{ - const knot_node_t *node = NULL, *closest_encloser = NULL, - *previous = NULL; - int cname = 0, auth_soa = 0, ret = 0, find_ret = 0; - - const knot_dname_t *qname = knot_pkt_qname(resp); - uint16_t qtype = knot_pkt_qtype(resp); - -search: - // Searching for a name directly is faster than when we need previous dname - node = knot_zone_contents_find_node(zone, qname); - if (node != NULL) { - // If node is found, closest_encloser is equal to node itself - closest_encloser = node; - find_ret = KNOT_ZONE_NAME_FOUND; - } else { - // We need previous and closest encloser, full search has to be done - find_ret = knot_zone_contents_find_dname(zone, qname, &node, - &closest_encloser, &previous); - if (find_ret == KNOT_EINVAL) { - return NS_ERR_SERVFAIL; - } - } - -dbg_ns_exec_verb( - char *name; - if (node) { - name = knot_dname_to_str(node->owner); - dbg_ns_verb("zone_find_dname() returned node %s \n", name); - free(name); - } else { - dbg_ns_verb("zone_find_dname() returned no node,\n"); - } - - if (closest_encloser != NULL) { - name = knot_dname_to_str(closest_encloser->owner); - dbg_ns_verb(" closest encloser %s.\n", name); - free(name); - } else { - dbg_ns_verb(" closest encloser (nil).\n"); - } - if (previous != NULL) { - name = knot_dname_to_str(previous->owner); - dbg_ns_verb(" and previous node: %s.\n", name); - free(name); - } else { - dbg_ns_verb(" and previous node: (nil).\n"); - } -); - if (find_ret == KNOT_EOUTOFZONE) { - // possible only if we followed CNAME or DNAME - assert(cname != 0); - knot_wire_set_rcode(resp->wire, KNOT_RCODE_NOERROR); - auth_soa = 1; - knot_wire_set_aa(resp->wire); - goto finalize; - } - -have_node: - dbg_ns_verb("Closest encloser is deleg. point? %s\n", - (knot_node_is_deleg_point(closest_encloser)) ? "yes" : "no"); - - dbg_ns_verb("Closest encloser is non authoritative? %s\n", - (knot_node_is_non_auth(closest_encloser)) ? "yes" : "no"); - - if (knot_node_is_deleg_point(closest_encloser) - || knot_node_is_non_auth(closest_encloser)) { - ret = ns_referral(closest_encloser, zone, qname, resp, qtype); - goto finalize; - } - - if (find_ret == KNOT_ZONE_NAME_NOT_FOUND) { - // DNAME? - knot_rrset_t *dname_rrset = knot_node_get_rrset( - closest_encloser, KNOT_RRTYPE_DNAME); - if (dname_rrset != NULL - && knot_rrset_rdata_rr_count(dname_rrset) > 0) { - ret = ns_process_dname(dname_rrset, &qname, resp); - - knot_wire_set_aa(resp->wire); - - if (ret != KNOT_EOK) { - goto finalize; - } - - // do not search for the name in new zone - // (out-of-bailiwick), just in the current zone if it - // belongs there - - cname = 1; - goto search; - } - // else check for a wildcard child - const knot_node_t *wildcard_node = - knot_node_wildcard_child(closest_encloser); - - if (wildcard_node == NULL) { - dbg_ns_verb("No wildcard node. (cname: %d)\n", - cname); - auth_soa = 1; - if (cname == 0) { - dbg_ns_detail("Setting NXDOMAIN RCODE.\n"); - // return NXDOMAIN - knot_wire_set_rcode(resp->wire, - KNOT_RCODE_NXDOMAIN); - } else { - knot_wire_set_rcode(resp->wire, - KNOT_RCODE_NOERROR); - } - - if (ns_put_nsec_nsec3_nxdomain(zone, previous, - closest_encloser, qname, resp) != 0) { - return NS_ERR_SERVFAIL; - } - knot_wire_set_aa(resp->wire); - goto finalize; - } - // else set the node from which to take the answers to wild.node - node = wildcard_node; - } - - // now we have the node for answering - if (knot_node_is_deleg_point(node) || knot_node_is_non_auth(node)) { - ret = ns_referral(node, zone, qname, resp, qtype); - goto finalize; - } - - if (knot_node_rrset(node, KNOT_RRTYPE_CNAME) != NULL - && qtype != KNOT_RRTYPE_CNAME && qtype != KNOT_RRTYPE_RRSIG) { -dbg_ns_exec( - char *name = knot_dname_to_str(node->owner); - dbg_ns("Node %s has CNAME record, resolving...\n", name); - free(name); -); - assert(KNOT_PKT_IN_AN(resp)); - const knot_dname_t *act_name = qname; - ret = ns_follow_cname(&node, &act_name, resp, 1); - - /*! \todo IS OK??? */ - knot_wire_set_aa(resp->wire); - - if (ret != KNOT_EOK) { - // KNOT_ESPACE case is handled there - goto finalize; - } -dbg_ns_exec_verb( - char *name = (node != NULL) ? knot_dname_to_str(node->owner) - : "(nil)"; - char *name2 = knot_dname_to_str(act_name); - dbg_ns_verb("Canonical name: %s (%p), node found: %p\n", - name2, act_name, node); - dbg_ns_verb("The node's owner: %s (%p)\n", name, (node != NULL) - ? node->owner : NULL); - if (node != NULL) { - free(name); - } - free(name2); -); - qname = act_name; - cname = 1; - - // otherwise search for the new name - if (node == NULL) { - goto search; - } else if (!knot_dname_is_equal(node->owner, act_name)) { - if(knot_dname_is_wildcard(knot_node_owner(node))) { - // we must set the closest encloser to the - // parent of the node, to be right - closest_encloser = knot_node_parent(node); - assert(closest_encloser != NULL); - } else { - // the stored node is closest encloser - find_ret = KNOT_ZONE_NAME_NOT_FOUND; - closest_encloser = node; - node = NULL; - goto have_node; - } - } - } - - ret = ns_answer_from_node(node, closest_encloser, previous, zone, qname, - qtype, resp, check_any); - if (ret == NS_ERR_SERVFAIL) { - // in this case we should drop the response and send an error - // for now, just send the error code with a non-complete answer - return ret; - } else if (ret != KNOT_EOK) { - /*! \todo Handle RCODE return values!!! */ - // In case ret == KNOT_ESPACE, this is later converted to EOK - // so it does not cause error response - knot_wire_set_aa(resp->wire); - goto finalize; - } - knot_wire_set_aa(resp->wire); - knot_wire_set_rcode(resp->wire, KNOT_RCODE_NOERROR); - - // this is the only case when the servers answers from - // particular node, i.e. the only case when it may return SOA - // or NS records in Answer section - if (knot_wire_get_tc(resp->wire) == 0 && DNSSEC_ENABLED - && knot_pkt_have_dnssec(resp->query) - && node == knot_zone_contents_apex(zone) - && (qtype == KNOT_RRTYPE_SOA || qtype == KNOT_RRTYPE_NS)) { - ret = ns_add_dnskey(node, resp); - } - -finalize: - knot_pkt_begin(resp, KNOT_AUTHORITY); /* #10 this is just plain wrong, this function is so _____ - that it jumps back and forth and we don't know when AN ends - and NS starts. */ - if (ret == KNOT_EOK && knot_wire_get_tc(resp->wire) == 0 && auth_soa) { - ret = ns_put_authority_soa(zone, resp); - } - - if (ret == KNOT_ESPACE) { - knot_wire_set_rcode(resp->wire, KNOT_RCODE_NOERROR); - ret = KNOT_EOK; - } - - // add all missing NSECs/NSEC3s for wildcard nodes - ret = ns_put_nsec_nsec3_wildcard_nodes(resp, zone); - - /* Finished AUTHORITY, continue with ADDITIONALS. */ - knot_pkt_begin(resp, KNOT_ADDITIONAL); - - if (ret == KNOT_EOK) { - ns_put_additional(resp); - } - - return ret; -} - -/*----------------------------------------------------------------------------*/ -/*! - * \brief Answers the query from the given zone database. - * - * First it searches for a zone to answer from. If there is none, it sets - * RCODE REFUSED to the response and ends. Otherwise it tries to answer the - * query using the found zone (see ns_answer_from_zone()). - * - * \param db Zone database to use for answering. - * \param resp Response that holds the parsed query. - * - * \retval KNOT_EOK - * \retval NS_ERR_SERVFAIL - */ -static int ns_answer(const knot_zone_t *zone, knot_pkt_t *resp, - int check_any) -{ - const knot_zone_contents_t *contents = knot_zone_contents(zone); - - // if no zone found, return REFUSED - if (zone == NULL) { - dbg_ns("No zone found.\n"); - knot_wire_set_rcode(resp->wire, KNOT_RCODE_REFUSED); - //knot_dname_free(&qname); - return KNOT_EOK; - } else if (contents == NULL) { - dbg_ns("Zone expired or not bootstrapped. Reply SERVFAIL.\n"); - knot_wire_set_rcode(resp->wire, KNOT_RCODE_SERVFAIL); - return KNOT_EOK; - } - -dbg_ns_exec( - char *name_str2 = knot_dname_to_str(zone->contents->apex->owner); - dbg_ns("Found zone for QNAME %s\n", name_str2); - free(name_str2); -); - - // take the zone contents and use only them for answering - - return ns_answer_from_zone(contents, resp, check_any); -} /*----------------------------------------------------------------------------*/ @@ -3148,144 +2764,6 @@ void knot_ns_error_response_full(knot_nameserver_t *nameserver, /*----------------------------------------------------------------------------*/ -int knot_ns_prep_normal_response(knot_nameserver_t *nameserver, - knot_pkt_t *query, knot_pkt_t *resp, - const knot_zone_t **zone, size_t max_size) -{ - dbg_ns_verb("knot_ns_prep_normal_response()\n"); - - if (nameserver == NULL || query == NULL || resp == NULL - || zone == NULL) { - return KNOT_EINVAL; - } - - // first, parse the rest of the packet - int ret = knot_pkt_parse_payload(query, 0); - if (ret != KNOT_EOK) { - dbg_ns("Failed to parse rest of the query: %s.\n", - knot_strerror(ret)); - return ret; - } - - /* - * Semantic checks - if ANCOUNT > 0 or NSCOUNT > 0, return FORMERR. - */ - if (knot_pkt_qtype(query) != KNOT_RRTYPE_IXFR && - (knot_wire_get_ancount(query->wire) > 0 || knot_wire_get_nscount(query->wire) > 0)) { - dbg_ns("ANCOUNT or NSCOUNT not 0 in query, Reply FORMERR.\n"); - return KNOT_EMALF; - } - - /* #10 move all semantic checks to pkt parsing? */ - - /* - * Check what is in the Additional section. Only OPT and TSIG are - * allowed. TSIG must be the last record if present. - */ - bool ar_check = false; - const knot_pktsection_t *additional = knot_pkt_section(query, KNOT_ADDITIONAL); - - switch(additional->count) { - case 0: /* OK */ - ar_check = true; - break; - case 1: /* TSIG or OPT */ - ar_check = (knot_rrset_type(additional->rr[0]) == KNOT_RRTYPE_OPT - || knot_rrset_type(additional->rr[0]) == KNOT_RRTYPE_TSIG); - break; - case 2: /* OPT, TSIG */ - ar_check = (knot_rrset_type(additional->rr[0]) == KNOT_RRTYPE_OPT - && knot_rrset_type(additional->rr[1]) == KNOT_RRTYPE_TSIG); - break; - default: /* INVALID combination */ - break; - } - - if (!ar_check) { - dbg_ns("Additional section malformed. Reply FORMERR\n"); - return KNOT_EMALF; - } - - size_t resp_max_size = 0; - - if (max_size > 0) { - // if TCP is used, buffer size is the only constraint - assert(max_size > 0); - resp_max_size = max_size; - } else if (knot_pkt_have_edns(query)) { - assert(max_size == 0); - if (knot_edns_get_payload(&query->opt_rr) < - knot_edns_get_payload(nameserver->opt_rr)) { - resp_max_size = knot_edns_get_payload(&query->opt_rr); - } else { - resp_max_size = knot_edns_get_payload( - nameserver->opt_rr); - } - } - - if (resp_max_size < MAX_UDP_PAYLOAD) { - resp_max_size = MAX_UDP_PAYLOAD; - } - - resp->max_size = resp_max_size; - - ret = knot_pkt_init_response(resp, query); - if (ret != KNOT_EOK) { - dbg_ns("Failed to init response structure.\n"); - return ret; - } - - dbg_ns_verb("Query - parsed: %zu, total wire size: %zu\n", - query->parsed, query->size); - dbg_ns_detail("Opt RR: version: %d, payload: %d\n", - query->opt_rr.version, query->opt_rr.payload); - dbg_ns_detail("EDNS supported in query: %d\n", - knot_pkt_have_edns(query)); - - // set the OPT RR to the response - if (knot_pkt_have_edns(query)) { - ret = knot_pkt_add_opt(resp, nameserver->opt_rr, - knot_pkt_have_nsid(query)); - if (ret != KNOT_EOK) { - dbg_ns("Failed to set OPT RR to the response" - ": %s\n", knot_strerror(ret)); - } else { - // copy the DO bit from the query - if (knot_pkt_have_dnssec(query)) { - knot_edns_set_do(&(resp)->opt_rr); - } - } - } - - dbg_ns_verb("Response max size: %zu\n", (resp)->max_size); - - // search for zone only for IN and ANY classes - uint16_t qclass = knot_pkt_qclass(resp); - if (qclass != KNOT_CLASS_IN && qclass != KNOT_CLASS_ANY) - return KNOT_EOK; - - const knot_dname_t *qname = knot_pkt_qname(resp); - assert(qname != NULL); - - uint16_t qtype = knot_pkt_qtype(resp); -dbg_ns_exec_verb( - char *name_str = knot_dname_to_str(qname); - dbg_ns_verb("Trying to find zone for QNAME %s\n", name_str); - free(name_str); -); - // find zone in which to search for the name - knot_zonedb_t *zonedb = rcu_dereference(nameserver->zone_db); - *zone = ns_get_zone_for_qname(zonedb, qname, qtype); - - /* Assign zone to packets. */ - query->zone = *zone; - (resp)->zone = *zone; - - return KNOT_EOK; -} - -/*----------------------------------------------------------------------------*/ - int knot_ns_prep_update_response(knot_nameserver_t *nameserver, knot_pkt_t *query, knot_pkt_t **resp, knot_zone_t **zone, size_t max_size) @@ -3416,38 +2894,6 @@ dbg_ns_exec_verb( /*----------------------------------------------------------------------------*/ -int knot_ns_answer_normal(knot_nameserver_t *nameserver, - const knot_zone_t *zone, knot_pkt_t *resp, - uint8_t *response_wire, size_t *rsize, int check_any) -{ - dbg_ns_verb("ns_answer_normal()\n"); - - int ret = ns_answer(zone, resp, check_any); - - if (ret != 0) { - // now only one type of error (SERVFAIL), later maybe more - knot_ns_error_response_full(nameserver, resp, - KNOT_RCODE_SERVFAIL, - response_wire, rsize); - } else { - dbg_ns_verb("Created response packet.\n"); - - // 4) Transform the packet into wire format - if (ns_response_to_wire(resp, response_wire, rsize) != 0) { - // send back SERVFAIL (as this is our problem) - knot_ns_error_response_full(nameserver, resp, - KNOT_RCODE_SERVFAIL, - response_wire, rsize); - } - } - - dbg_ns_verb("Returning response with wire size %zu\n", *rsize); - - return KNOT_EOK; -} - -/*----------------------------------------------------------------------------*/ - int knot_ns_answer_ixfr_udp(knot_nameserver_t *nameserver, const knot_zone_t *zone, knot_pkt_t *resp, uint8_t *response_wire, size_t *rsize) diff --git a/src/libknot/nameserver/name-server.h b/src/libknot/nameserver/name-server.h index 6418e54c5d03e8909ae388cf08af5016b5ad7ea6..fcbfac1fb1f31e37b91f5d4fd0568518c44d2b05 100644 --- a/src/libknot/nameserver/name-server.h +++ b/src/libknot/nameserver/name-server.h @@ -232,10 +232,6 @@ void knot_ns_error_response_full(knot_nameserver_t *nameserver, knot_pkt_t *response, uint8_t rcode, uint8_t *response_wire, size_t *rsize); -int knot_ns_prep_normal_response(knot_nameserver_t *nameserver, - knot_pkt_t *query, knot_pkt_t *resp, - const knot_zone_t **zone, size_t max_size); - int knot_ns_prep_update_response(knot_nameserver_t *nameserver, knot_pkt_t *query, knot_pkt_t **resp, knot_zone_t **zone, size_t max_size); @@ -400,7 +396,7 @@ const knot_zone_t *ns_get_zone_for_qname(knot_zonedb_t *zdb, const knot_dname_t *qname, uint16_t qtype); -int ns_put_additional(knot_pkt_t *resp); +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, diff --git a/src/libknot/nameserver/ns_proc_query.c b/src/libknot/nameserver/ns_proc_query.c index 3930eadb9cf3465982bb81667824bdf848200642..d9094d997d46a495b5d358e03ddfafbfe38b8d9c 100644 --- a/src/libknot/nameserver/ns_proc_query.c +++ b/src/libknot/nameserver/ns_proc_query.c @@ -282,7 +282,7 @@ static int prepare_answer(const knot_pkt_t *query, knot_pkt_t *resp, ns_proc_con } // find zone for qname - resp->zone = answer_zone_find(query, ctx->ns->zone_db); + QUERY_DATA(ctx)->zone = answer_zone_find(query, ctx->ns->zone_db); /* Update maximal answer size. */ if (!(ctx->flags & NS_PKTSIZE_NOLIMIT)) { diff --git a/src/libknot/nameserver/ns_proc_query.h b/src/libknot/nameserver/ns_proc_query.h index b4b1e7125b6eee20dff38c1fa3a640d97208d210..184ba1e13ff1b1648f98288086fc170af864ff42 100644 --- a/src/libknot/nameserver/ns_proc_query.h +++ b/src/libknot/nameserver/ns_proc_query.h @@ -44,6 +44,7 @@ struct query_data { uint16_t rcode; uint16_t rcode_tsig; knot_pkt_t *pkt; + const knot_zone_t *zone; /*!< Associated zone. */ const knot_node_t *node, *encloser, *previous; list_t wildcards; mm_ctx_t *mm; diff --git a/src/libknot/packet/pkt.c b/src/libknot/packet/pkt.c index c6a905eaac8f48838cd9c71751fb911b0d7e954b..d1d235698ff6ccb71a45f7284f3dc5eebfd09b91 100644 --- a/src/libknot/packet/pkt.c +++ b/src/libknot/packet/pkt.c @@ -80,6 +80,7 @@ static void pkt_wire_set(knot_pkt_t *pkt, void *wire, uint16_t len) pkt->wire = wire; pkt->size = pkt->max_size = len; pkt->parsed = 0; + /*! \todo Merge ->size and ->parsed */ } static uint16_t pkt_remaining(knot_pkt_t *pkt) diff --git a/src/libknot/packet/pkt.h b/src/libknot/packet/pkt.h index c294dc53e7f8ee32aa53c188385fdb47896f1431..a6af0eef03e8123e0ea14caea39936fd32b25e3f 100644 --- a/src/libknot/packet/pkt.h +++ b/src/libknot/packet/pkt.h @@ -105,7 +105,6 @@ typedef struct knot_pkt { /* #10 <<< SHOULD BE IN ANSWERING CONTEXT */ const knot_tsig_key_t *tsig_key; - const knot_zone_t *zone; /*!< Associated zone. */ const struct knot_pkt *query; /*!< Associated query. */ /*! \brief Wildcard nodes to be processed for NSEC/NSEC3. */