diff --git a/src/knot/modules/synth_record.c b/src/knot/modules/synth_record.c index f918248f3cbb438c3e4a86bc8b673acacc404e8c..1d4640408852dac1058258bbb8ea8d7aa3e15474 100644 --- a/src/knot/modules/synth_record.c +++ b/src/knot/modules/synth_record.c @@ -46,13 +46,14 @@ static char str_separator(int addr_family) return '.'; } -/*! \brief QTYPE to address family. */ -static int qtype_addrfamily(uint16_t qtype) +/*! \brief Return true if query type is satisfied with provided address family. */ +static bool query_satisfied_by_family(uint16_t qtype, int family) { switch(qtype) { - case KNOT_RRTYPE_A: return AF_INET; - case KNOT_RRTYPE_AAAA: return AF_INET6; - default: return AF_UNSPEC; + case KNOT_RRTYPE_A: return family == AF_INET; + case KNOT_RRTYPE_AAAA: return family == AF_INET6; + case KNOT_RRTYPE_ANY: return true; + default: return false; } } @@ -62,7 +63,7 @@ static int reverse_addr_parse(struct query_data *qdata, synth_template_t *tpl, c /* QNAME required format is [address].[subnet/zone] * f.e. [1.0...0].[h.g.f.e.0.0.0.0.d.c.b.a.ip6.arpa] represents * [abcd:0:efgh::1] */ - const knot_dname_t* label = knot_pkt_qname(qdata->query); + const knot_dname_t* label = qdata->name; const uint8_t *query_wire = qdata->query->wire; /* Push labels on stack for reverse walkthrough. */ @@ -104,7 +105,7 @@ static int reverse_addr_parse(struct query_data *qdata, synth_template_t *tpl, c static int forward_addr_parse(struct query_data *qdata, synth_template_t *tpl, char *addr_str) { /* Find prefix label count (additive to prefix length). */ - const knot_dname_t *addr_label = knot_pkt_qname(qdata->query); + const knot_dname_t *addr_label = qdata->name; /* Mismatch if label shorter/equal than prefix. */ int prefix_len = strlen(tpl->prefix); @@ -126,7 +127,7 @@ static int addr_parse(struct query_data *qdata, synth_template_t *tpl, char *add { /* Check if we have at least 1 label below zone. */ int zone_labels = knot_dname_labels(qdata->zone->name, NULL); - int label_count = knot_dname_labels(knot_pkt_qname(qdata->query), qdata->query->wire); + int label_count = knot_dname_labels(qdata->name, qdata->query->wire); if (label_count < zone_labels + 1) { return KNOT_EINVAL; } @@ -170,67 +171,68 @@ static knot_dname_t *synth_ptrname(const char *addr_str, synth_template_t *tpl) return knot_dname_from_str(ptrname); } -static knot_rrset_t *reverse_rr(char *addr_str, synth_template_t *tpl, knot_pkt_t *pkt, struct query_data *qdata) +static int reverse_rr(char *addr_str, synth_template_t *tpl, knot_pkt_t *pkt, knot_rrset_t *rr) { - /* Synthetize PTR record. */ - knot_dname_t* qname = knot_dname_copy(knot_pkt_qname(qdata->query)); - knot_rrset_t *rr = knot_rrset_new(qname, KNOT_RRTYPE_PTR, KNOT_CLASS_IN, &pkt->mm); - if (rr == NULL) { - knot_dname_free(&qname); - return NULL; - } - /* Synthetize PTR record data. */ knot_dname_t *ptrname = synth_ptrname(addr_str, tpl); if (ptrname == NULL) { - return NULL; + return KNOT_ENOMEM; } + + rr->type = KNOT_RRTYPE_PTR; knot_rrset_add_rr(rr, ptrname, knot_dname_size(ptrname), tpl->ttl, &pkt->mm); knot_dname_free(&ptrname); - return rr; + return KNOT_EOK; } -static knot_rrset_t *forward_rr(char *addr_str, synth_template_t *tpl, knot_pkt_t *pkt, struct query_data *qdata) +static int forward_rr(char *addr_str, synth_template_t *tpl, knot_pkt_t *pkt, knot_rrset_t *rr) { - /* Decide synthetic record A/AAAA type. */ - int family = tpl->subnet.ss.ss_family; - uint16_t rr_class = KNOT_RRTYPE_A; - if (family == AF_INET6) { - rr_class = KNOT_RRTYPE_AAAA; - } - - knot_dname_t* qname = knot_dname_copy(knot_pkt_qname(qdata->query)); - knot_rrset_t *rr = knot_rrset_new(qname, rr_class, KNOT_CLASS_IN, &pkt->mm); - if (rr == NULL) { - knot_dname_free(&qname); - return NULL; - } - struct sockaddr_storage query_addr = {'\0'}; - sockaddr_set(&query_addr, family, addr_str, 0); + sockaddr_set(&query_addr, tpl->subnet.ss.ss_family, addr_str, 0); - /* Append address. */ - if (family == AF_INET6) { + /* Specify address type and data. */ + if (tpl->subnet.ss.ss_family == AF_INET6) { + rr->type = KNOT_RRTYPE_AAAA; const struct sockaddr_in6* ip = (const struct sockaddr_in6*)&query_addr; knot_rrset_add_rr(rr, (const uint8_t *)&ip->sin6_addr, sizeof(struct in6_addr), tpl->ttl, &pkt->mm); - } else { + } else if (tpl->subnet.ss.ss_family == AF_INET) { + rr->type = KNOT_RRTYPE_A; const struct sockaddr_in* ip = (const struct sockaddr_in*)&query_addr; knot_rrset_add_rr(rr, (const uint8_t *)&ip->sin_addr, sizeof(struct in_addr), tpl->ttl, &pkt->mm); + } else { + return KNOT_EINVAL; } - return rr; + return KNOT_EOK; } static knot_rrset_t *synth_rr(char *addr_str, synth_template_t *tpl, knot_pkt_t *pkt, struct query_data *qdata) { + /* Synthetize empty RR. */ + knot_dname_t* qname = knot_dname_copy(qdata->name); + knot_rrset_t *rr = knot_rrset_new(qname, 0, KNOT_CLASS_IN, &pkt->mm); + if (rr == NULL) { + knot_dname_free(&qname); + return NULL; + } + + /* Fill in the specific data. */ + int ret = KNOT_ERROR; switch(tpl->type) { - case SYNTH_REVERSE: return reverse_rr(addr_str, tpl, pkt, qdata); - case SYNTH_FORWARD: return forward_rr(addr_str, tpl, pkt, qdata); - default: return NULL; + case SYNTH_REVERSE: ret = reverse_rr(addr_str, tpl, pkt, rr); break; + case SYNTH_FORWARD: ret = forward_rr(addr_str, tpl, pkt, rr); break; + default: break; } + + if (ret != KNOT_EOK) { + knot_rrset_deep_free(&rr, true, &pkt->mm); + return NULL; + } + + return rr; } /*! \brief Check if query fits the template requirements. */ @@ -255,12 +257,22 @@ static int template_match(int state, synth_template_t *tpl, knot_pkt_t *pkt, str } /* Check if the request is for a available query type. */ - if (tpl->type == SYNTH_FORWARD) { - int requested_af = qtype_addrfamily(knot_pkt_qtype(qdata->query)); - if (requested_af != provided_af) { + uint16_t qtype = knot_pkt_qtype(qdata->query); + switch(tpl->type) { + case SYNTH_FORWARD: + if (!query_satisfied_by_family(qtype, provided_af)) { qdata->rcode = KNOT_RCODE_NOERROR; return NODATA; } + break; + case SYNTH_REVERSE: + if (qtype != KNOT_RRTYPE_PTR && qtype != KNOT_RRTYPE_ANY) { + qdata->rcode = KNOT_RCODE_NOERROR; + return NODATA; + } + break; + default: + break; } /* Synthetise record from template. */ @@ -270,12 +282,14 @@ static int template_match(int state, synth_template_t *tpl, knot_pkt_t *pkt, str return ERROR; } - /* Create empty response with PTR record in AN. */ - knot_pkt_init_response(pkt, qdata->query); - if (knot_pkt_put(pkt, COMPR_HINT_QNAME, rr, KNOT_PF_FREE) != KNOT_EOK) { + /* Insert synthetic response into packet. */ + if (knot_pkt_put(pkt, 0, rr, KNOT_PF_FREE) != KNOT_EOK) { return ERROR; } + /* Authoritative response. */ + knot_wire_set_aa(pkt->wire); + return HIT; }