diff --git a/src/knot/nameserver/internet.c b/src/knot/nameserver/internet.c index 03f53db27c05d161049574d685f84338b8a51873..5b21d31b10beda336c14f70cd65a25819a656cd6 100644 --- a/src/knot/nameserver/internet.c +++ b/src/knot/nameserver/internet.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2013 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2016 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,20 +15,14 @@ */ #include "libknot/libknot.h" -#include "libknot/descriptor.h" -#include "libknot/rrtype/rdname.h" -#include "libknot/rrtype/soa.h" #include "knot/common/log.h" -#include "knot/dnssec/rrset-sign.h" +#include "knot/query/query.h" #include "knot/nameserver/internet.h" #include "knot/nameserver/nsec_proofs.h" #include "knot/nameserver/process_query.h" -#include "knot/query/query.h" #include "knot/nameserver/query_module.h" #include "knot/zone/serial.h" -#include "knot/zone/zonedb.h" #include "contrib/mempattern.h" -#include "contrib/sockaddr.h" /*! \brief Check if given node was already visited. */ static int wildcard_has_visited(struct query_data *qdata, const zone_node_t *node) @@ -128,47 +122,6 @@ static bool have_dnssec(struct query_data *qdata) zone_contents_is_signed(qdata->zone->contents); } -/*! \brief Synthesize RRSIG for given parameters, store in 'qdata' for later use */ -static int put_rrsig(const knot_dname_t *sig_owner, uint16_t type, - const knot_rrset_t *rrsigs, - knot_rrinfo_t *rrinfo, - struct query_data *qdata) -{ - knot_rdataset_t synth_rrs; - knot_rdataset_init(&synth_rrs); - int ret = knot_synth_rrsig(type, &rrsigs->rrs, &synth_rrs, qdata->mm); - if (ret == KNOT_ENOENT) { - // No signature - return KNOT_EOK; - } - if (ret != KNOT_EOK) { - return ret; - } - - /* Create rrsig info structure. */ - struct rrsig_info *info = mm_alloc(qdata->mm, sizeof(struct rrsig_info)); - if (info == NULL) { - knot_rdataset_clear(&synth_rrs, qdata->mm); - return KNOT_ENOMEM; - } - - /* Store RRSIG into info structure. */ - knot_dname_t *owner_copy = knot_dname_copy(sig_owner, qdata->mm); - if (owner_copy == NULL) { - mm_free(qdata->mm, info); - knot_rdataset_clear(&synth_rrs, qdata->mm); - return KNOT_ENOMEM; - } - knot_rrset_init(&info->synth_rrsig, owner_copy, rrsigs->type, rrsigs->rclass); - /* Store filtered signature. */ - info->synth_rrsig.rrs = synth_rrs; - - info->rrinfo = rrinfo; - add_tail(&qdata->rrsigs, &info->n); - - return KNOT_EOK; -} - /*! \brief This is a wildcard-covered or any other terminal node for QNAME. * e.g. positive answer. */ @@ -200,7 +153,8 @@ static int put_answer(knot_pkt_t *pkt, uint16_t type, struct query_data *qdata) } for (unsigned i = 0; i < qdata->node->rrset_count; ++i) { rrset = node_rrset_at(qdata->node, i); - ret = ns_put_rr(pkt, &rrset, NULL, compr_hint, 0, qdata); + ret = process_query_put_rr(pkt, qdata, &rrset, NULL, + compr_hint, 0); if (ret != KNOT_EOK) { break; } @@ -211,7 +165,8 @@ static int put_answer(knot_pkt_t *pkt, uint16_t type, struct query_data *qdata) rrset = node_rrset(qdata->node, type); if (!knot_rrset_empty(&rrset)) { knot_rrset_t rrsigs = node_rrset(qdata->node, KNOT_RRTYPE_RRSIG); - ret = ns_put_rr(pkt, &rrset, &rrsigs, compr_hint, 0, qdata); + ret = process_query_put_rr(pkt, qdata, &rrset, &rrsigs, + compr_hint, 0); } break; } @@ -251,7 +206,8 @@ static int put_authority_soa(knot_pkt_t *pkt, struct query_data *qdata, soa_rrset = copy; } - ret = ns_put_rr(pkt, &soa_rrset, &rrsigs, KNOT_COMPR_HINT_NONE, flags, qdata); + ret = process_query_put_rr(pkt, qdata, &soa_rrset, &rrsigs, + KNOT_COMPR_HINT_NONE, flags); if (ret != KNOT_EOK && (flags & KNOT_PF_FREE)) { knot_rrset_clear(&soa_rrset, &pkt->mm); } @@ -270,7 +226,8 @@ static int put_delegation(knot_pkt_t *pkt, struct query_data *qdata) /* Insert NS record. */ knot_rrset_t rrset = node_rrset(qdata->node, KNOT_RRTYPE_NS); knot_rrset_t rrsigs = node_rrset(qdata->node, KNOT_RRTYPE_RRSIG); - return ns_put_rr(pkt, &rrset, &rrsigs, KNOT_COMPR_HINT_NONE, 0, qdata); + return process_query_put_rr(pkt, qdata, &rrset, &rrsigs, + KNOT_COMPR_HINT_NONE, 0); } /*! \brief Put additional records for given RR. */ @@ -308,7 +265,8 @@ static int put_additional(knot_pkt_t *pkt, const knot_rrset_t *rr, if (knot_rrset_empty(&rrset)) { continue; } - ret = ns_put_rr(pkt, &rrset, &rrsigs, hint, flags, qdata); + ret = process_query_put_rr(pkt, qdata, &rrset, &rrsigs, + hint, flags); if (ret != KNOT_EOK) { break; } @@ -331,7 +289,7 @@ static int follow_cname(knot_pkt_t *pkt, uint16_t rrtype, struct query_data *qda /* Now, try to put CNAME to answer. */ uint16_t rr_count_before = pkt->rrset_count; - int ret = ns_put_rr(pkt, &cname_rr, &rrsigs, 0, flags, qdata); + int ret = process_query_put_rr(pkt, qdata, &cname_rr, &rrsigs, 0, flags); switch (ret) { case KNOT_EOK: break; case KNOT_ESPACE: return TRUNC; @@ -357,7 +315,7 @@ static int follow_cname(knot_pkt_t *pkt, uint16_t rrtype, struct query_data *qda qdata->rcode = KNOT_RCODE_SERVFAIL; return ERROR; } - ret = ns_put_rr(pkt, &cname_rr, NULL, 0, KNOT_PF_FREE, qdata); + ret = process_query_put_rr(pkt, qdata, &cname_rr, NULL, 0, KNOT_PF_FREE); switch (ret) { case KNOT_EOK: break; case KNOT_ESPACE: return TRUNC; @@ -647,72 +605,16 @@ static int solve_additional_dnssec(int state, knot_pkt_t *pkt, struct query_data } } -int ns_put_rr(knot_pkt_t *pkt, const knot_rrset_t *rr, - const knot_rrset_t *rrsigs, uint16_t compr_hint, - uint32_t flags, struct query_data *qdata) -{ - if (rr->rrs.rr_count < 1) { - return KNOT_EMALF; - } - - /* Wildcard expansion applies only for answers. */ - bool expand = false; - if (pkt->current == KNOT_ANSWER) { - /* Expand if RR is wildcard & we didn't query for wildcard. */ - expand = (knot_dname_is_wildcard(rr->owner) && !knot_dname_is_wildcard(qdata->name)); - } - - int ret = KNOT_EOK; - - /* If we already have compressed name on the wire and compression hint, - * we can just insert RRSet and fake synthesis by using compression - * hint. */ - knot_rrset_t to_add; - if (compr_hint == KNOT_COMPR_HINT_NONE && expand) { - knot_dname_t *qname_cpy = knot_dname_copy(qdata->name, &pkt->mm); - if (qname_cpy == NULL) { - return KNOT_ENOMEM; - } - knot_rrset_init(&to_add, qname_cpy, rr->type, rr->rclass); - ret = knot_rdataset_copy(&to_add.rrs, &rr->rrs, &pkt->mm); - if (ret != KNOT_EOK) { - knot_dname_free(&qname_cpy, &pkt->mm); - return ret; - } - to_add.additional = rr->additional; - flags |= KNOT_PF_FREE; - } else { - to_add = *rr; - } - - uint16_t prev_count = pkt->rrset_count; - ret = knot_pkt_put(pkt, compr_hint, &to_add, flags); - if (ret != KNOT_EOK && (flags & KNOT_PF_FREE)) { - knot_rrset_clear(&to_add, &pkt->mm); - return ret; - } - - const bool inserted = (prev_count != pkt->rrset_count); - if (inserted && - !knot_rrset_empty(rrsigs) && rr->type != KNOT_RRTYPE_RRSIG) { - // Get rrinfo of just inserted RR. - knot_rrinfo_t *rrinfo = &pkt->rr_info[pkt->rrset_count - 1]; - ret = put_rrsig(rr->owner, rr->type, rrsigs, rrinfo, qdata); - } - - return ret; -} - /*! \brief Helper for internet_query repetitive code. */ #define SOLVE_STEP(solver, state, context) \ - state = (solver)(state, response, qdata, context); \ + state = (solver)(state, pkt, qdata, context); \ if (state == TRUNC) { \ return KNOT_STATE_DONE; \ } else if (state == ERROR) { \ return KNOT_STATE_FAIL; \ } -static int answer_query(struct query_plan *plan, knot_pkt_t *response, struct query_data *qdata) +static int answer_query(struct query_plan *plan, knot_pkt_t *pkt, struct query_data *qdata) { int state = BEGIN; struct query_plan *global_plan = conf()->query_plan; @@ -726,7 +628,7 @@ static int answer_query(struct query_plan *plan, knot_pkt_t *response, struct qu } /* Resolve ANSWER. */ - knot_pkt_begin(response, KNOT_ANSWER); + knot_pkt_begin(pkt, KNOT_ANSWER); if (global_plan != NULL) { WALK_LIST(step, global_plan->stage[QPLAN_ANSWER]) { SOLVE_STEP(step->process, state, step->ctx); @@ -741,7 +643,7 @@ static int answer_query(struct query_plan *plan, knot_pkt_t *response, struct qu } /* Resolve AUTHORITY. */ - knot_pkt_begin(response, KNOT_AUTHORITY); + knot_pkt_begin(pkt, KNOT_AUTHORITY); if (global_plan != NULL) { WALK_LIST(step, global_plan->stage[QPLAN_AUTHORITY]) { SOLVE_STEP(step->process, state, step->ctx); @@ -756,7 +658,7 @@ static int answer_query(struct query_plan *plan, knot_pkt_t *response, struct qu } /* Resolve ADDITIONAL. */ - knot_pkt_begin(response, KNOT_ADDITIONAL); + knot_pkt_begin(pkt, KNOT_ADDITIONAL); if (global_plan != NULL) { WALK_LIST(step, global_plan->stage[QPLAN_ADDITIONAL]) { SOLVE_STEP(step->process, state, step->ctx); @@ -778,16 +680,16 @@ static int answer_query(struct query_plan *plan, knot_pkt_t *response, struct qu } /* Write resulting RCODE. */ - knot_wire_set_rcode(response->wire, qdata->rcode); + knot_wire_set_rcode(pkt->wire, qdata->rcode); return KNOT_STATE_DONE; } #undef SOLVE_STEP -int internet_process_query(knot_pkt_t *response, struct query_data *qdata) +int internet_process_query(knot_pkt_t *pkt, struct query_data *qdata) { - if (response == NULL || qdata == NULL) { + if (pkt == NULL || qdata == NULL) { return KNOT_STATE_FAIL; } @@ -800,7 +702,7 @@ int internet_process_query(knot_pkt_t *response, struct query_data *qdata) NS_NEED_AUTH(qdata, qdata->zone->name, ACL_ACTION_NONE); /* Reserve space for TSIG. */ - knot_pkt_reserve(response, knot_tsig_wire_maxsize(&qdata->sign.tsig_key)); + knot_pkt_reserve(pkt, knot_tsig_wire_maxsize(&qdata->sign.tsig_key)); } NS_NEED_ZONE_CONTENTS(qdata, KNOT_RCODE_SERVFAIL); /* Expired */ @@ -808,7 +710,7 @@ int internet_process_query(knot_pkt_t *response, struct query_data *qdata) /* Get answer to QNAME. */ qdata->name = knot_pkt_qname(qdata->query); - return answer_query(qdata->zone->query_plan, response, qdata); + return answer_query(qdata->zone->query_plan, pkt, qdata); } #include "knot/nameserver/log.h" diff --git a/src/knot/nameserver/internet.h b/src/knot/nameserver/internet.h index b5e0354670e26e54b385e2d92c37532fe3cce132..2917600b089fdef6805635fc8d0318fc3a756f5a 100644 --- a/src/knot/nameserver/internet.h +++ b/src/knot/nameserver/internet.h @@ -13,24 +13,12 @@ You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ -/*! - * \file - * - * \brief IN zone lookup. - * - * \addtogroup query_processing - * @{ - */ #pragma once #include "libknot/packet/pkt.h" -#include "knot/query/layer.h" -/* Query data (from query processing). */ struct query_data; -struct query_plan; -struct query_module; struct answer_data; /*! \brief Internet query processing states. */ @@ -48,37 +36,20 @@ enum { /*! * \brief Answer query from an IN class zone. * - * \retval FAIL if it encountered an error. - * \retval DONE if finished. + * \retval KNOT_STATE_FAIL if it encountered an error. + * \retval KNOT_STATE_DONE if finished. */ -int internet_process_query(knot_pkt_t *resp, struct query_data *qdata); +int internet_process_query(knot_pkt_t *pkt, struct query_data *qdata); /*! * \brief Process answer in an IN class zone. * - * \retval FAIL if it encountered an error. - * \retval DONE if finished. - * \retval NOOP if not supported. + * \retval KNOT_STATE_FAIL if it encountered an error. + * \retval KNOT_STATE_DONE if finished. + * \retval KNOT_STATE_NOOP if not supported. */ int internet_process_answer(knot_pkt_t *pkt, struct answer_data *data); -/*! - * \brief Puts RRSet to packet, will store its RRSIG for later use. - * - * \param pkt Packet to store RRSet into. - * \param rr RRSet to be stored. - * \param rrsigs RRSIGs to be stored. - * \param compr_hint Compression hint. - * \param flags Flags. - * \param expand Set to true if wildcards should be expanded. - * \param qdata Query data structure. - * - * \return KNOT_E* - */ -int ns_put_rr(knot_pkt_t *pkt, const knot_rrset_t *rr, - const knot_rrset_t *rrsigs, uint16_t compr_hint, - uint32_t flags, 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)->query) != (qtype_want)) { \ @@ -117,9 +88,8 @@ int ns_put_rr(knot_pkt_t *pkt, const knot_rrset_t *rr, } \ } +/*! \brief Require maximum number of unsigned messages. */ #define NS_NEED_TSIG_SIGNED(tsig_ctx, max_unsigned) \ if (tsig_unsigned_count(tsig_ctx) > max_unsigned) { \ return KNOT_STATE_FAIL; \ } - -/*! @} */ diff --git a/src/knot/nameserver/nsec_proofs.c b/src/knot/nameserver/nsec_proofs.c index 880dc3620b19f846dd4da6d92877a3e0f32d4d96..8cc6330a69835701418b986a0ef24d49b0eb6850 100644 --- a/src/knot/nameserver/nsec_proofs.c +++ b/src/knot/nameserver/nsec_proofs.c @@ -173,8 +173,8 @@ static int put_nxt_from_node(const zone_node_t *node, knot_rrset_t rrsigs = node_rrset(node, KNOT_RRTYPE_RRSIG); - return ns_put_rr(resp, &rrset, &rrsigs, KNOT_COMPR_HINT_NONE, - KNOT_PF_CHECKDUP, qdata); + return process_query_put_rr(resp, qdata, &rrset, &rrsigs, + KNOT_COMPR_HINT_NONE, KNOT_PF_CHECKDUP); } /*! @@ -667,7 +667,8 @@ int nsec_prove_dp_security(knot_pkt_t *pkt, struct query_data *qdata) knot_rrset_t rrset = node_rrset(qdata->node, KNOT_RRTYPE_DS); if (!knot_rrset_empty(&rrset)) { knot_rrset_t rrsigs = node_rrset(qdata->node, KNOT_RRTYPE_RRSIG); - return ns_put_rr(pkt, &rrset, &rrsigs, KNOT_COMPR_HINT_NONE, 0, qdata); + return process_query_put_rr(pkt, qdata, &rrset, &rrsigs, + KNOT_COMPR_HINT_NONE, 0); } // Alternatively prove that DS doesn't exist. diff --git a/src/knot/nameserver/process_query.c b/src/knot/nameserver/process_query.c index ebcde545a929a3f7036c7e5da8b370f75674297d..ee98cfcc948a17af9acc90e69314a8e081842d51 100644 --- a/src/knot/nameserver/process_query.c +++ b/src/knot/nameserver/process_query.c @@ -18,6 +18,7 @@ #include "dnssec/tsig.h" #include "knot/common/log.h" +#include "knot/dnssec/rrset-sign.h" #include "knot/nameserver/process_query.h" #include "knot/nameserver/query_module.h" #include "knot/nameserver/chaos.h" @@ -748,6 +749,102 @@ int process_query_qname_case_lower(knot_pkt_t *pkt) return knot_dname_to_lower(qname); } +/*! \brief Synthesize RRSIG for given parameters, store in 'qdata' for later use */ +static int put_rrsig(const knot_dname_t *sig_owner, uint16_t type, + const knot_rrset_t *rrsigs, knot_rrinfo_t *rrinfo, + struct query_data *qdata) +{ + knot_rdataset_t synth_rrs; + knot_rdataset_init(&synth_rrs); + int ret = knot_synth_rrsig(type, &rrsigs->rrs, &synth_rrs, qdata->mm); + if (ret == KNOT_ENOENT) { + // No signature + return KNOT_EOK; + } + if (ret != KNOT_EOK) { + return ret; + } + + /* Create rrsig info structure. */ + struct rrsig_info *info = mm_alloc(qdata->mm, sizeof(struct rrsig_info)); + if (info == NULL) { + knot_rdataset_clear(&synth_rrs, qdata->mm); + return KNOT_ENOMEM; + } + + /* Store RRSIG into info structure. */ + knot_dname_t *owner_copy = knot_dname_copy(sig_owner, qdata->mm); + if (owner_copy == NULL) { + mm_free(qdata->mm, info); + knot_rdataset_clear(&synth_rrs, qdata->mm); + return KNOT_ENOMEM; + } + knot_rrset_init(&info->synth_rrsig, owner_copy, rrsigs->type, rrsigs->rclass); + /* Store filtered signature. */ + info->synth_rrsig.rrs = synth_rrs; + + info->rrinfo = rrinfo; + add_tail(&qdata->rrsigs, &info->n); + + return KNOT_EOK; +} + +int process_query_put_rr(knot_pkt_t *pkt, struct query_data *qdata, + const knot_rrset_t *rr, const knot_rrset_t *rrsigs, + uint16_t compr_hint, uint32_t flags) +{ + if (rr->rrs.rr_count < 1) { + return KNOT_EMALF; + } + + /* Wildcard expansion applies only for answers. */ + bool expand = false; + if (pkt->current == KNOT_ANSWER) { + /* Expand if RR is wildcard & we didn't query for wildcard. */ + expand = (knot_dname_is_wildcard(rr->owner) && !knot_dname_is_wildcard(qdata->name)); + } + + int ret = KNOT_EOK; + + /* If we already have compressed name on the wire and compression hint, + * we can just insert RRSet and fake synthesis by using compression + * hint. */ + knot_rrset_t to_add; + if (compr_hint == KNOT_COMPR_HINT_NONE && expand) { + knot_dname_t *qname_cpy = knot_dname_copy(qdata->name, &pkt->mm); + if (qname_cpy == NULL) { + return KNOT_ENOMEM; + } + knot_rrset_init(&to_add, qname_cpy, rr->type, rr->rclass); + ret = knot_rdataset_copy(&to_add.rrs, &rr->rrs, &pkt->mm); + if (ret != KNOT_EOK) { + knot_dname_free(&qname_cpy, &pkt->mm); + return ret; + } + to_add.additional = rr->additional; + flags |= KNOT_PF_FREE; + } else { + to_add = *rr; + } + + uint16_t prev_count = pkt->rrset_count; + ret = knot_pkt_put(pkt, compr_hint, &to_add, flags); + if (ret != KNOT_EOK && (flags & KNOT_PF_FREE)) { + knot_rrset_clear(&to_add, &pkt->mm); + return ret; + } + + const bool inserted = (prev_count != pkt->rrset_count); + if (inserted && + !knot_rrset_empty(rrsigs) && rr->type != KNOT_RRTYPE_RRSIG) { + // Get rrinfo of just inserted RR. + knot_rrinfo_t *rrinfo = &pkt->rr_info[pkt->rrset_count - 1]; + ret = put_rrsig(rr->owner, rr->type, rrsigs, rrinfo, qdata); + } + + return ret; +} + /*! \brief Module implementation. */ const knot_layer_api_t *process_query_layer(void) { diff --git a/src/knot/nameserver/process_query.h b/src/knot/nameserver/process_query.h index 5897b2f4fac561636909fcbca12328874ecc830f..0698e6d7a4c8f4b6388533b334d6ac261560a268 100644 --- a/src/knot/nameserver/process_query.h +++ b/src/knot/nameserver/process_query.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2015 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2016 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -13,14 +13,6 @@ You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ -/*! - * \file - * - * \brief Query processor. - * - * \addtogroup query_processing - * @{ - */ #pragma once @@ -145,4 +137,18 @@ void process_query_qname_case_restore(knot_pkt_t *pkt, struct query_data *qdata) */ int process_query_qname_case_lower(knot_pkt_t *pkt); -/*! @} */ +/*! + * \brief Puts RRSet to packet, will store its RRSIG for later use. + * + * \param pkt Packet to store RRSet into. + * \param qdata Query data structure. + * \param rr RRSet to be stored. + * \param rrsigs RRSIGs to be stored. + * \param compr_hint Compression hint. + * \param flags Flags. + * + * \return KNOT_E* + */ +int process_query_put_rr(knot_pkt_t *pkt, struct query_data *qdata, + const knot_rrset_t *rr, const knot_rrset_t *rrsigs, + uint16_t compr_hint, uint32_t flags);