From 1761a1343d01ec4f889ea9a2ac48583ceb4eacdd Mon Sep 17 00:00:00 2001 From: Lubos Slovak <lubos.slovak@nic.cz> Date: Tue, 16 Sep 2014 18:50:29 +0200 Subject: [PATCH] RDATA lowercase: Converting in packet parsing + zone load. Converting to lowercase when saving to zone proved insufficient, because case-insensitive comparison of RDATA would be needed in some scenarios - e.g. in IXFR (SOA replacement) and DDNS processing. Moved the conversion to packet parsing - all dnames in RDATA are converted to lowercase when parsed from wire. RDATA parsed from zone file are converted there (in scanner_process()). Later the conversion may be moved to a lower level of parsing (and with some option to turn it on/off). QNAME is unaffected by this change. --- Knot.files | 1 + src/knot/zone/contents.c | 83 ++------------------------------- src/knot/zone/zonefile.c | 42 ++++++++++++++++- src/libknot/packet/rrset-wire.c | 31 ++++++------ src/libknot/rrtype/naptr.h | 56 ++++++++++++++++++++++ 5 files changed, 116 insertions(+), 97 deletions(-) create mode 100644 src/libknot/rrtype/naptr.h diff --git a/Knot.files b/Knot.files index 57f992eb5..a973e89a4 100644 --- a/Knot.files +++ b/Knot.files @@ -347,3 +347,4 @@ tests/zone_events.c tests/zone_update.c tests/zonedb.c tests/ztree.c +src/libknot/rrtype/naptr.h diff --git a/src/knot/zone/contents.c b/src/knot/zone/contents.c index f09b018a1..2aaae40c8 100644 --- a/src/knot/zone/contents.c +++ b/src/knot/zone/contents.c @@ -733,87 +733,14 @@ static bool rrset_is_nsec3rel(const knot_rrset_t *rr) == KNOT_RRTYPE_NSEC3)); } -static size_t naptr_header_size(uint8_t *naptr, uint8_t *maxp) -{ - /*! \todo Copy-pasted from rrset.c. Unify. */ - - size_t size = 0; - - /* Fixed fields size (order, preference) */ - size += 2 * sizeof(uint16_t); - - /* Variable fields size (flags, services, regexp) */ - for (int i = 0; i < 3; i++) { - uint8_t *len_ptr = naptr + size; - assert(len_ptr < maxp); - size += 1 + *len_ptr; - } - - return size; -} - -static void convert_to_lowercase(knot_rrset_t *rrset) -{ - int ret = knot_dname_to_lower(rrset->owner); - assert(ret == KNOT_EOK); - - const rdata_descriptor_t *desc = knot_get_rdata_descriptor(rrset->type); - - for (int j = 0; j < rrset->rrs.rr_count; ++j) { - knot_rdata_t *rdata = knot_rdataset_at(&rrset->rrs, j); - - uint16_t rdlen = knot_rdata_rdlen(rdata); - uint8_t *pos = knot_rdata_data(rdata); - - for (int i = 0; desc->block_types[i] != KNOT_RDATA_WF_END; ++i) { - int type = desc->block_types[i]; - switch (type) { - case KNOT_RDATA_WF_COMPRESSIBLE_DNAME: - case KNOT_RDATA_WF_DECOMPRESSIBLE_DNAME: - case KNOT_RDATA_WF_FIXED_DNAME: - ret = knot_dname_to_lower(pos); - assert(ret == KNOT_EOK); - pos += knot_dname_size(pos); - break; - case KNOT_RDATA_WF_NAPTR_HEADER: - pos += naptr_header_size(pos, rdata + rdlen); - break; - case KNOT_RDATA_WF_REMAINDER: - break; - default: - /* Fixed size block */ - assert(type > 0); - pos += type; - } - } - } -} - -static knot_rrset_t *rrset_to_lowercase(const knot_rrset_t *rrset) -{ - knot_rrset_t *rr_l = knot_rrset_copy(rrset, NULL); - if (rr_l != NULL) { - convert_to_lowercase(rr_l); - } - - return rr_l; -} - int zone_contents_add_rr(zone_contents_t *z, const knot_rrset_t *rr, zone_node_t **n) { - /* Convert all dnames in RRSet to lowercase. */ - knot_rrset_t *rr_lc = rrset_to_lowercase(rr); - - int ret; - if (rr_lc != NULL) { - ret = insert_rr(z, rr_lc, n, rrset_is_nsec3rel(rr)); - knot_rrset_free(&rr_lc, NULL); - } else { - ret = KNOT_ERROR; - } - - return ret; + if (z == NULL || rr == NULL) { + return KNOT_EINVAL; + } + + return insert_rr(z, rr, n, rrset_is_nsec3rel(rr)); } /*----------------------------------------------------------------------------*/ diff --git a/src/knot/zone/zonefile.c b/src/knot/zone/zonefile.c index 70ee8e988..1275b1905 100644 --- a/src/knot/zone/zonefile.c +++ b/src/knot/zone/zonefile.c @@ -37,6 +37,7 @@ #include "knot/zone/zonefile.h" #include "libknot/rdata.h" #include "knot/zone/zone-dump.h" +#include "libknot/rrtype/naptr.h" #define ERROR(zone, fmt...) log_zone_error(zone, "zone loader, " fmt) #define WARNING(zone, fmt...) log_zone_warning(zone, "zone loader, " fmt) @@ -144,6 +145,43 @@ int zcreator_step(zcreator_t *zc, const knot_rrset_t *rr) return sem_fatal_error ? KNOT_ESEMCHECK : KNOT_EOK; } +static void convert_to_lowercase(knot_rrset_t *rrset) +{ + int ret = knot_dname_to_lower(rrset->owner); + assert(ret == KNOT_EOK); + + const rdata_descriptor_t *desc = knot_get_rdata_descriptor(rrset->type); + + for (int j = 0; j < rrset->rrs.rr_count; ++j) { + knot_rdata_t *rdata = knot_rdataset_at(&rrset->rrs, j); + + uint16_t rdlen = knot_rdata_rdlen(rdata); + uint8_t *pos = knot_rdata_data(rdata); + + for (int i = 0; desc->block_types[i] != KNOT_RDATA_WF_END; ++i) { + int type = desc->block_types[i]; + switch (type) { + case KNOT_RDATA_WF_COMPRESSIBLE_DNAME: + case KNOT_RDATA_WF_DECOMPRESSIBLE_DNAME: + case KNOT_RDATA_WF_FIXED_DNAME: + ret = knot_dname_to_lower(pos); + assert(ret == KNOT_EOK); + pos += knot_dname_size(pos); + break; + case KNOT_RDATA_WF_NAPTR_HEADER: + pos += naptr_header_size(pos, rdata + rdlen); + break; + case KNOT_RDATA_WF_REMAINDER: + break; + default: + /* Fixed size block */ + assert(type > 0); + pos += type; + } + } + } +} + /*! \brief Creates RR from parser input, passes it to handling function. */ static void scanner_process(zs_scanner_t *scanner) { @@ -158,7 +196,6 @@ static void scanner_process(zs_scanner_t *scanner) zc->ret = KNOT_ENOMEM; return; } - knot_dname_to_lower(owner); knot_rrset_t rr; knot_rrset_init(&rr, owner, scanner->r_type, scanner->r_class); @@ -174,6 +211,9 @@ static void scanner_process(zs_scanner_t *scanner) return; } + /* Convert RDATA dnames to lowercase before adding to zone. */ + convert_to_lowercase(&rr); + zc->ret = zcreator_step(zc, &rr); knot_dname_free(&owner, NULL); knot_rdataset_clear(&rr.rrs, NULL); diff --git a/src/libknot/packet/rrset-wire.c b/src/libknot/packet/rrset-wire.c index 594f55eeb..39af97af8 100644 --- a/src/libknot/packet/rrset-wire.c +++ b/src/libknot/packet/rrset-wire.c @@ -29,6 +29,7 @@ #include "libknot/packet/rrset-wire.h" #include "libknot/packet/wire.h" #include "libknot/rrset.h" +#include "libknot/rrtype/naptr.h" /*! * \brief Get maximal size of a domain name in a wire with given capacity. @@ -114,26 +115,14 @@ static int write_rdata_naptr_header(const uint8_t **src, size_t *src_avail, assert(dst && *dst); assert(dst_avail); - size_t size = 0; + int ret = naptr_header_size(*src, *src + *src_avail); - /* Fixed fields size (order, preference) */ - - size += 2 * sizeof(uint16_t); - - /* Variable fields size (flags, services, regexp) */ - - for (int i = 0; i < 3; i++) { - const uint8_t *len_ptr = *src + size; - if (len_ptr >= *src + *src_avail) { - return KNOT_EMALF; - } - - size += 1 + *len_ptr; + if (ret < 0) { + return ret; } /* Copy the data */ - - return write_rdata_fixed(src, src_avail, dst, dst_avail, size); + return write_rdata_fixed(src, src_avail, dst, dst_avail, ret); } /*! @@ -522,7 +511,7 @@ static int decompress_rdata_dname(const uint8_t **src, size_t *src_avail, assert(dst && *dst); assert(dst_avail); assert(dname_cfg); - UNUSED(flags); + UNUSED(dname_type); int compr_size = knot_dname_wire_check(*src, *src + *src_avail, dname_cfg->pkt_wire); if (compr_size <= 0) { @@ -533,6 +522,12 @@ static int decompress_rdata_dname(const uint8_t **src, size_t *src_avail, if (decompr_size <= 0) { return decompr_size; } + + /* Convert to lowercase. */ + if (flags & KNOT_RRSET_WIRE_CANONICAL) { + int ret = knot_dname_to_lower(*dst); + assert(ret == KNOT_EOK); + } /* Update buffers */ *dst += decompr_size; @@ -597,7 +592,7 @@ static int parse_rdata(const uint8_t *pkt_wire, size_t *pos, size_t pkt_size, }; int ret = rdata_traverse(&src, &src_avail, &dst, &dst_avail, - desc, &dname_cfg, KNOT_RRSET_WIRE_NONE); + desc, &dname_cfg, KNOT_RRSET_WIRE_CANONICAL); if (ret != KNOT_EOK) { return ret; } diff --git a/src/libknot/rrtype/naptr.h b/src/libknot/rrtype/naptr.h new file mode 100644 index 000000000..215ce4792 --- /dev/null +++ b/src/libknot/rrtype/naptr.h @@ -0,0 +1,56 @@ +/* Copyright (C) 2014 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 + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + 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 naptr.h + * + * \author Lubos Slovak <lubos.slovak@nic.cz> + * + * \brief Functions for manipulation of NAPTR RDATA. + * + * \addtogroup libknot + * @{ + */ + +#pragma once + +#include <stdbool.h> +#include <stdint.h> +#include <string.h> + +#include "libknot/errcode.h" + +static inline int naptr_header_size(const uint8_t *naptr, const uint8_t *maxp) +{ + size_t size = 0; + + /* Fixed fields size (order, preference) */ + size += 2 * sizeof(uint16_t); + + /* Variable fields size (flags, services, regexp) */ + for (int i = 0; i < 3; i++) { + uint8_t *len_ptr = naptr + size; + printf("Checking len_ptr = %p, maxp = %p\n", + len_ptr, maxp); + if (len_ptr >= maxp) { + return KNOT_EMALF; + } + size += 1 + *len_ptr; + } + + return size; +} + +/*! @} */ -- GitLab