diff options
Diffstat (limited to 'src/libknot/dname.c')
-rw-r--r-- | src/libknot/dname.c | 1070 |
1 files changed, 1070 insertions, 0 deletions
diff --git a/src/libknot/dname.c b/src/libknot/dname.c new file mode 100644 index 0000000..869b342 --- /dev/null +++ b/src/libknot/dname.c @@ -0,0 +1,1070 @@ +/* Copyright (C) 2011 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/>. + */ + +#include <config.h> +#include <stdint.h> +#include <stdlib.h> +#include <assert.h> +#include <string.h> +#include <ctype.h> // tolower() + +#include "common.h" +#include "util/error.h" +#include "dname.h" +#include "consts.h" +#include "util/tolower.h" +#include "util/debug.h" +#include "util/utils.h" +#include "util/wire.h" + +/*! \todo dnames allocated from TLS cache will be discarded after thread + * termination. This shouldn't happpen. + */ +#if 0 +/* + * Memory cache. + */ +#include "common/slab/slab.h" +#include <stdio.h> +#include <pthread.h> + +/*! \brief TLS unique key for each thread cache. */ +static pthread_key_t dname_ckey; +static pthread_once_t dname_once = PTHREAD_ONCE_INIT; + +/*! \brief Destroy thread dname cache (automatically called). */ +static void knot_dname_cache_free(void *ptr) +{ + slab_cache_t* cache = (slab_cache_t*)ptr; + if (cache) { + slab_cache_destroy(cache); + free(cache); + } +} + +/*! \brief Cleanup for main() TLS. */ +static void knot_dname_cache_main_free() +{ + knot_dname_cache_free(pthread_getspecific(dname_ckey)); +} + +static void knot_dname_cache_init() +{ + (void) pthread_key_create(&dname_ckey, knot_dname_cache_free); + atexit(knot_dname_cache_main_free); // Main thread cleanup +} +#endif + +/*! + * \brief Allocate item from thread cache. + * \retval Allocated dname instance on success. + * \retval NULL on error. + */ +static knot_dname_t* knot_dname_alloc() +{ + return malloc(sizeof(knot_dname_t)); + + /*! \todo dnames allocated from TLS cache will be discarded after thread + * termination. This shouldn't happpen. + */ +#if 0 + /* Initialize dname cache TLS key. */ + (void)pthread_once(&dname_once, knot_dname_cache_init); + + /* Create cache if not exists. */ + slab_cache_t* cache = pthread_getspecific(dname_ckey); + if (unlikely(!cache)) { + cache = malloc(sizeof(slab_cache_t)); + if (!cache) { + return 0; + } + + /* Initialize cache. */ + slab_cache_init(cache, sizeof(knot_dname_t)); + (void)pthread_setspecific(dname_ckey, cache); + } + + return slab_cache_alloc(cache); +#endif +} + +/*----------------------------------------------------------------------------*/ +/* Non-API functions */ +/*----------------------------------------------------------------------------*/ + +static int knot_dname_set(knot_dname_t *dname, uint8_t *wire, + short wire_size, const uint8_t *labels, + short label_count) +{ + dname->name = wire; + dname->size = wire_size; + dname->label_count = label_count; + + assert(label_count >= 0); + + dname->labels = (uint8_t *)malloc(dname->label_count * sizeof(uint8_t)); + CHECK_ALLOC_LOG(dname->labels, -1); + memcpy(dname->labels, labels, dname->label_count); + + return 0; +} + +/*! + * \brief Converts domain name from string representation to wire format. + * + * This function also allocates the space for the wire format. + * + * \param name Domain name in string representation (presentation format). + * \param size Size of the given domain name in characters (not counting the + * terminating 0 character. + * \param dname Domain name where to store the wire format. + * + * \return Size of the wire format of the domain name in octets. If 0, no + * space has been allocated. + * + * \todo handle \X and \DDD (RFC 1035 5.1) or it can be handled by the parser? + */ +static int knot_dname_str_to_wire(const char *name, uint size, + knot_dname_t *dname) +{ + if (size > KNOT_MAX_DNAME_LENGTH) { + return -1; + } + + uint wire_size; + int root = (*name == '.' && size == 1); + // root => different size + if (root) { + wire_size = 1; + } else { + wire_size = size + 1; + } + + uint8_t *wire; + uint8_t labels[KNOT_MAX_DNAME_LABELS]; + short label_count = 0; + + // signed / unsigned issues?? + wire = (uint8_t *)malloc(wire_size * sizeof(uint8_t)); + if (wire == NULL) { + return -1; + } + + dbg_dname("Allocated space for wire format of dname: %p\n", + wire); + + if (root) { + *wire = '\0'; + label_count = 0; + return knot_dname_set(dname, wire, wire_size, labels, + label_count); + } + + const uint8_t *ch = (const uint8_t *)name; + uint8_t *label_start = wire; + uint8_t *w = wire + 1; + uint8_t label_length = 0; + + while (ch - (const uint8_t *)name < size) { + assert(w - wire - 1 == ch - (const uint8_t *)name); + + if (*ch == '.') { + dbg_dname("Position %zd (%p): " + "label length: %u\n", + label_start - wire, + label_start, label_length); + *label_start = label_length; + labels[label_count++] = label_start - wire; + label_start = w; + label_length = 0; + } else { + assert(w - wire < wire_size); + dbg_dname("Position %zd (%p): character: %c\n", + w - wire, w, *ch); + *w = *ch; + ++label_length; + } + + ++w; + ++ch; + assert(ch >= (const uint8_t *)name); + } + + --ch; + if (*ch == '.') { // put 0 for root label if the name ended with . + --w; + dbg_dname("Position %zd (%p): character: (null)\n", + w - wire, w); + *w = 0; + } else { // otherwise we did not save the last label length + dbg_dname("Position %zd (%p): " + "label length: %u\n", + label_start - wire, + label_start, label_length); + *label_start = label_length; + labels[label_count++] = label_start - wire; + } + + return knot_dname_set(dname, wire, wire_size, labels, label_count); +} + +/*----------------------------------------------------------------------------*/ + +static inline int knot_dname_tolower(uint8_t c, int cs) +{ + return (cs) ? c : knot_tolower(c); +} + +/*----------------------------------------------------------------------------*/ + +static int knot_dname_compare_labels(const uint8_t *label1, + const uint8_t *label2, int cs) +{ + const uint8_t *pos1 = label1; + const uint8_t *pos2 = label2; + + int label_length = (*pos1 < *pos2) ? *pos1 : *pos2; + int i = 0; + + while (i < label_length + && knot_dname_tolower(*(++pos1), cs) + == knot_dname_tolower(*(++pos2), cs)) { + ++i; + } + + if (i < label_length) { // difference in some octet + return (knot_dname_tolower(*pos1, cs) + - knot_dname_tolower(*pos2, cs)); + } + + return (label1[0] - label2[0]); +} + +/*----------------------------------------------------------------------------*/ + +static int knot_dname_find_labels(knot_dname_t *dname, int alloc) +{ + const uint8_t *name = dname->name; + const uint8_t *pos = name; + const uint size = dname->size; + + uint8_t labels[KNOT_MAX_DNAME_LABELS]; + short label_count = 0; + + while (pos - name < size && *pos != '\0') { + labels[label_count++] = pos - name; + pos += *pos + 1; + } + + // TODO: how to check if the domain name has right format? + if (pos - name > size || *pos != '\0') { + dbg_dname("Wrong wire format of domain name!\n"); + dbg_dname("Position: %d, character: %d, expected" + " size: %d\n", pos - name, *pos, size); + return -1; + } + + if (alloc) { + dname->labels + = (uint8_t *)malloc(label_count * sizeof(uint8_t)); + CHECK_ALLOC_LOG(dname->labels, KNOT_ENOMEM); + } + + memcpy(dname->labels, labels, label_count); + dname->label_count = label_count; + + return 0; +} + +/*----------------------------------------------------------------------------*/ + +static int knot_dname_cmp(const knot_dname_t *d1, const knot_dname_t *d2, + int cs) +{ +dbg_dname_exec( + char *name1 = knot_dname_to_str(d1); + char *name2 = knot_dname_to_str(d2); + + dbg_dname("Comparing dnames %s and %s\n", + name1, name2); + + for (int i = 0; i < strlen(name1); ++i) { + name1[i] = knot_tolower(name1[i]); + } + for (int i = 0; i < strlen(name2); ++i) { + name2[i] = knot_tolower(name2[i]); + } + + dbg_dname("After to lower: %s and %s\n", + name1, name2); + + free(name1); + free(name2); +); + + if (!cs && d1 == d2) { + return 0; + } + + int l1 = d1->label_count; + int l2 = d2->label_count; + dbg_dname("Label counts: %d and %d\n", l1, l2); + assert(l1 >= 0); + assert(l2 >= 0); + + // compare labels from last to first + while (l1 > 0 && l2 > 0) { + dbg_dname("Comparing labels %d and %d\n", + l1 - 1, l2 - 1); + dbg_dname(" at offsets: %d and %d\n", + d1->labels[l1 - 1], d2->labels[l2 - 1]); + int res = knot_dname_compare_labels( + &d1->name[d1->labels[--l1]], + &d2->name[d2->labels[--l2]], + cs); + if (res != 0) { + return res; + } // otherwise the labels are identical, continue with previous + } + + // if all labels matched, the shorter name is first + if (l1 == 0 && l2 > 0) { + return -1; + } + + if (l1 > 0 && l2 == 0) { + return 1; + } + + return 0; +} + +/*! \brief Destructor for reference counter. */ +static void knot_dname_dtor(struct ref_t *p) +{ + knot_dname_t *dname = (knot_dname_t *)p; + knot_dname_free(&dname); +} + +/*----------------------------------------------------------------------------*/ +/* API functions */ +/*----------------------------------------------------------------------------*/ + +knot_dname_t *knot_dname_new() +{ + knot_dname_t *dname = knot_dname_alloc(); + dname->name = NULL; + dname->size = 0; + dname->node = NULL; + dname->labels = NULL; + dname->label_count = -1; + dname->id = 0; + + /* Initialize reference counting. */ + ref_init(&dname->ref, knot_dname_dtor); + + /* Set reference counter to 1, caller should release it after use. */ + knot_dname_retain(dname); + + return dname; +} + +/*----------------------------------------------------------------------------*/ + +knot_dname_t *knot_dname_new_from_str(const char *name, uint size, + struct knot_node *node) +{ + if (name == NULL || size == 0) { + return NULL; + } + +// knot_dname_t *dname = knot_dname_alloc(); + knot_dname_t *dname = knot_dname_new(); + + if (dname == NULL) { + ERR_ALLOC_FAILED; + return NULL; + } + + knot_dname_str_to_wire(name, size, dname); + dbg_dname("Created dname with size: %d\n", dname->size); + dbg_dname("Label offsets: "); + for (int i = 0; i < dname->label_count; ++i) { + dbg_dname("%d, ", dname->labels[i]); + } + dbg_dname("\n"); + + if (dname->size <= 0) { + fprintf(stderr, "Could not parse domain name " + "from string: '%.*s'\n", size, name); + } + assert(dname->name != NULL); + + dname->node = node; + dname->id = 0; + + return dname; +} + +/*----------------------------------------------------------------------------*/ + +//int knot_dname_from_wire(knot_dname_t *dname, const uint8_t *name, +// uint size) +//{ +// int i = 0; +// uint8_t labels[KNOT_MAX_DNAME_LABELS]; +// int label_i = 0; + +// while (name[i] != 0) { +// labels[label_i++] = i; +// uint8_t label_length = name[i]; +// if (i + label_length >= size) { +// return -2; +// } +// for (int j = 1; j <= label_length; ++j) { +// } +// } +//} + +/*----------------------------------------------------------------------------*/ + +knot_dname_t *knot_dname_new_from_wire(const uint8_t *name, uint size, + struct knot_node *node) +{ + if (name == NULL) { /* && size != 0) { !OS: Nerozumjaju */ + dbg_dname("No name given!\n"); + return NULL; + } + + knot_dname_t *dname = knot_dname_new(); + + if (dname == NULL) { + ERR_ALLOC_FAILED; + return NULL; + } + + dname->name = (uint8_t *)malloc(size * sizeof(uint8_t)); + if (dname->name == NULL) { + ERR_ALLOC_FAILED; + knot_dname_free(&dname); + return NULL; + } + + memcpy(dname->name, name, size); + dname->size = size; + + if (knot_dname_find_labels(dname, 1) != 0) { + knot_dname_free(&dname); + return NULL; + } + + dname->node = node; + dname->id = 0; + + return dname; +} + +/*----------------------------------------------------------------------------*/ + +knot_dname_t *knot_dname_parse_from_wire(const uint8_t *wire, + size_t *pos, size_t size, + knot_node_t *node) +{ + uint8_t name[KNOT_MAX_DNAME_LENGTH]; + uint8_t labels[KNOT_MAX_DNAME_LABELS]; + + short l = 0; + size_t i = 0, p = *pos; + int pointer_used = 0; + + while (p < size && wire[p] != 0) { + labels[l] = i; + dbg_dname("Next label (%d.) position: %zu\n", l, i); + + if (knot_wire_is_pointer(wire + p)) { + // pointer. +// printf("Pointer.\n"); + p = knot_wire_get_pointer(wire + p); + if (!pointer_used) { + *pos += 2; + pointer_used = 1; + } + if (p >= size) { + return NULL; + } + } else { + // label; first byte is label length + uint8_t length = *(wire + p); +// printf("Label, length: %u.\n", length); + memcpy(name + i, wire + p, length + 1); + p += length + 1; + i += length + 1; + if (!pointer_used) { + *pos += length + 1; + } + ++l; + } + } + if (p >= size) { + return NULL; + } + + name[i] = 0; + if (!pointer_used) { + *pos += 1; + } + + knot_dname_t *dname = knot_dname_new(); + + if (dname == NULL) { + ERR_ALLOC_FAILED; + return NULL; + } + + dname->name = (uint8_t *)malloc((i + 1) * sizeof(uint8_t)); + if (dname->name == NULL) { + ERR_ALLOC_FAILED; + knot_dname_free(&dname); + return NULL; + } + + memcpy(dname->name, name, i + 1); + dname->size = i + 1; + + dname->labels = (uint8_t *)malloc((l + 1) * sizeof(uint8_t)); + if (dname->labels == NULL) { + ERR_ALLOC_FAILED; + knot_dname_free(&dname); + return NULL; + } + memcpy(dname->labels, labels, l + 1); + + dname->label_count = l; + + dname->node = node; + + return dname; +} + +/*----------------------------------------------------------------------------*/ + +int knot_dname_from_wire(const uint8_t *name, uint size, + struct knot_node *node, knot_dname_t *target) +{ + if (name == NULL || target == NULL) { + return KNOT_EBADARG; + } + + memcpy(target->name, name, size); + target->size = size; + target->node = node; + target->id = 0; + + return knot_dname_find_labels(target, 0); +} + +/*----------------------------------------------------------------------------*/ + +knot_dname_t *knot_dname_deep_copy(const knot_dname_t *dname) +{ + return knot_dname_new_from_wire(dname->name, dname->size, + dname->node); +} + +/*----------------------------------------------------------------------------*/ + +char *knot_dname_to_str(const knot_dname_t *dname) +{ + if (!dname || dname->size == 0) { + return 0; + } + + char *name; + + // root => special treatment + if (dname->size == 1) { + assert(dname->name[0] == 0); + name = (char *)malloc(2 * sizeof(char)); + name[0] = '.'; + name[1] = '\0'; + return name; + } + + name = (char *)malloc(dname->size * sizeof(char)); + if (name == NULL) { + return NULL; + } + + uint8_t *w = dname->name; + char *ch = name; + int i = 0; + + do { + assert(*w != 0); + int label_size = *(w++); + // copy the label + memcpy(ch, w, label_size); + i += label_size; + ch += label_size; + w += label_size; + if (w - dname->name < dname->size) { // another label following + *(ch++) = '.'; + ++i; + } + } while (i < dname->size - 1); + + *ch = 0; + assert(ch - name == dname->size - 1); + + return name; +} + +/*----------------------------------------------------------------------------*/ + +int knot_dname_to_lower(knot_dname_t *dname) +{ + if (dname == NULL) { + return KNOT_EBADARG; + } + + for (int i = 0; i < dname->size; ++i) { + dname->name[i] = knot_tolower(dname->name[i]); + } + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +int knot_dname_to_lower_copy(const knot_dname_t *dname, char *name, + size_t size) +{ + if (dname == NULL || name == NULL || size < dname->size) { + return KNOT_EBADARG; + } + + for (int i = 0; i < dname->size; ++i) { + name[i] = knot_tolower(dname->name[i]); + } + return KNOT_EOK; +} + +/*----------------------------------------------------------------------------*/ + +const uint8_t *knot_dname_name(const knot_dname_t *dname) +{ + return dname->name; +} + +/*----------------------------------------------------------------------------*/ + +uint knot_dname_size(const knot_dname_t *dname) +{ + return dname->size; +} + +/*----------------------------------------------------------------------------*/ + +unsigned int knot_dname_id(const knot_dname_t *dname) +{ + return dname->id; +} + +/*----------------------------------------------------------------------------*/ + +uint8_t knot_dname_size_part(const knot_dname_t *dname, int labels) +{ + assert(labels < dname->label_count); + assert(dname->labels != NULL); + return (dname->labels[labels]); +} + +/*----------------------------------------------------------------------------*/ + +const struct knot_node *knot_dname_node(const knot_dname_t *dname, + int check_version) + +{ + if (check_version) { + return knot_node_current(dname->node); + } else { + return dname->node; + } +} + +/*----------------------------------------------------------------------------*/ + +struct knot_node *knot_dname_get_node(knot_dname_t *dname, + int check_version) +{ + if (check_version) { + return knot_node_get_current(dname->node); + } else { + return dname->node; + } +} + +/*----------------------------------------------------------------------------*/ + +void knot_dname_set_node(knot_dname_t *dname, knot_node_t *node) +{ + dname->node = node; +} + +/*----------------------------------------------------------------------------*/ + +void knot_dname_update_node(knot_dname_t *dname) +{ + knot_node_update_ref(&dname->node); +} + +/*----------------------------------------------------------------------------*/ + +int knot_dname_is_fqdn(const knot_dname_t *dname) +{ + return (dname->name[dname->size - 1] == '\0'); +} + +/*----------------------------------------------------------------------------*/ + +knot_dname_t *knot_dname_left_chop(const knot_dname_t *dname) +{ + knot_dname_t *parent = knot_dname_new(); + if (parent == NULL) { + return NULL; + } + + parent->size = dname->size - dname->name[0] - 1; + parent->name = (uint8_t *)malloc(parent->size); + if (parent->name == NULL) { + ERR_ALLOC_FAILED; + knot_dname_free(&parent); + return NULL; + } + + parent->labels = (uint8_t *)malloc(dname->label_count - 1); + if (parent->labels == NULL) { + ERR_ALLOC_FAILED; + free(parent->name); + knot_dname_free(&parent); + return NULL; + } + + memcpy(parent->name, &dname->name[dname->name[0] + 1], parent->size); + + short first_label_length = dname->labels[1]; + + for (int i = 0; i < dname->label_count - 1; ++i) { + parent->labels[i] = dname->labels[i + 1] - first_label_length; + } + parent->label_count = dname->label_count - 1; + + return parent; +} + +/*----------------------------------------------------------------------------*/ + +void knot_dname_left_chop_no_copy(knot_dname_t *dname) +{ + // copy the name + short first_label_length = dname->labels[1]; + + if (dname->label_count > 1) { + memmove(dname->name, &dname->name[dname->labels[1]], + dname->size - first_label_length); + // adjust labels + for (int i = 0; i < dname->label_count - 1; ++i) { + dname->labels[i] = dname->labels[i + 1] + - first_label_length; + } + dname->label_count = dname->label_count - 1; + dname->size -= first_label_length; + } else { + dname->name[0] = '\0'; + dname->size = 1; + dname->label_count = 0; + } +} + +/*----------------------------------------------------------------------------*/ + +int knot_dname_is_subdomain(const knot_dname_t *sub, + const knot_dname_t *domain) +{ +dbg_dname_exec( + char *name1 = knot_dname_to_str(sub); + char *name2 = knot_dname_to_str(domain); + + dbg_dname("Checking if %s is subdomain of %s\n", + name1, name2); + free(name1); + free(name2); +); + + if (sub == domain) { + return 0; + } + + // if one of the names is fqdn and the other is not + if ((sub->name[sub->size - 1] == '\0' + && domain->name[domain->size - 1] != '\0') + || (sub->name[sub->size - 1] != '\0' + && domain->name[domain->size - 1] == '\0')) { + return 0; + } + + int l1 = sub->label_count; + int l2 = domain->label_count; + + dbg_dname("Label counts: %d and %d\n", l1, l2); + + if (l1 <= l2) { // if sub does not have more labes than domain + return 0; // it is not its subdomain + } + + // compare labels from last to first + while (l1 > 0 && l2 > 0) { + dbg_dname("Comparing labels %d and %d\n", + l1 - 1, l2 - 1); + dbg_dname(" at offsets: %d and %d\n", + sub->labels[l1 - 1], domain->labels[l2 - 1]); + // if some labels do not match + if (knot_dname_compare_labels(&sub->name[sub->labels[--l1]], + &domain->name[domain->labels[--l2]], 0) + != 0) { + return 0; // sub is not a subdomain of domain + } // otherwise the labels are identical, continue with previous + } + + // if all labels matched, it should be subdomain (more labels) + assert(l1 > l2); + + return 1; +} + +/*----------------------------------------------------------------------------*/ + +int knot_dname_is_wildcard(const knot_dname_t *dname) +{ + return (dname->size >= 2 + && dname->name[0] == 1 + && dname->name[1] == '*'); +} + +/*----------------------------------------------------------------------------*/ + +int knot_dname_matched_labels(const knot_dname_t *dname1, + const knot_dname_t *dname2) +{ + int l1 = dname1->label_count; + int l2 = dname2->label_count; + + // compare labels from last to first + int matched = 0; + while (l1 > 0 && l2 > 0) { + int res = knot_dname_compare_labels( + &dname1->name[dname1->labels[--l1]], + &dname2->name[dname2->labels[--l2]], 0); + if (res == 0) { + ++matched; + } else { + break; + } + } + + return matched; +} + +/*----------------------------------------------------------------------------*/ + +int knot_dname_label_count(const knot_dname_t *dname) +{ + return dname->label_count; +} + +/*----------------------------------------------------------------------------*/ + +uint8_t knot_dname_label_size(const knot_dname_t *dname, int i) +{ +// printf("Returning size of %d. label starting on %d\n", +// i, dname->labels[i]); +// printf("Label count: %d, size of %d. label: %d, size of %d.label: %d\n", +// dname->label_count, i, dname->labels[i], i + 1, +// dname->labels[i+1]); +// printf("Size from the name: %u\n", dname->name[dname->labels[i]]); +// printf("Size from label offsets: %u\n", +// dname->labels[i + 1] - dname->labels[i]); + + assert(i >= 0); + assert(dname->size == 1 || i + 1 == dname->label_count + || dname->labels[i + 1] - dname->labels[i] - 1 + == dname->name[dname->labels[i]]); + return dname->name[dname->labels[i]]; +} + +/*----------------------------------------------------------------------------*/ + +knot_dname_t *knot_dname_replace_suffix(const knot_dname_t *dname, + int size, + const knot_dname_t *suffix) +{ +dbg_dname_exec( + char *name = knot_dname_to_str(dname); + dbg_dname("Replacing suffix of name %s, size %d with ", name, + size); + free(name); + name = knot_dname_to_str(suffix); + dbg_dname("%s (size %d)\n", name, suffix->size); + free(name); +); + knot_dname_t *res = knot_dname_new(); + CHECK_ALLOC(res, NULL); + + res->size = dname->size - size + suffix->size; + + dbg_dname("Allocating %d bytes...\n", res->size); + res->name = (uint8_t *)malloc(res->size); + if (res->name == NULL) { + knot_dname_free(&res); + return NULL; + } + + dbg_dname_hex((char *)res->name, res->size); + + dbg_dname("Copying %d bytes from the original name.\n", + dname->size - size); + memcpy(res->name, dname->name, dname->size - size); + dbg_dname_hex((char *)res->name, res->size); + + dbg_dname("Copying %d bytes from the suffix.\n", suffix->size); + memcpy(res->name + dname->size - size, suffix->name, suffix->size); + + dbg_dname_hex((char *)res->name, res->size); + + knot_dname_find_labels(res, 1); + + return res; +} + +/*----------------------------------------------------------------------------*/ + +void knot_dname_free(knot_dname_t **dname) +{ + if (dname == NULL || *dname == NULL) { + return; + } + +// char *name = knot_dname_to_str((*dname)); + +// printf("freeing in dname: %s %p\n", name, *dname); + +// free(name); + + + if ((*dname)->name != NULL) { + free((*dname)->name); + } + + if((*dname)->labels != NULL) { + free((*dname)->labels); + } + + +// slab_free(*dname); + free(*dname); + *dname = NULL; +} + +/*----------------------------------------------------------------------------*/ + +int knot_dname_compare(const knot_dname_t *d1, const knot_dname_t *d2) +{ + return knot_dname_cmp(d1, d2, 0); +} + +/*----------------------------------------------------------------------------*/ + +int knot_dname_compare_cs(const knot_dname_t *d1, const knot_dname_t *d2) +{ + return knot_dname_cmp(d1, d2, 1); +} + +/*----------------------------------------------------------------------------*/ + +knot_dname_t *knot_dname_cat(knot_dname_t *d1, const knot_dname_t *d2) +{ + if (d2->size == 0) { + return d1; + } + + if (knot_dname_is_fqdn(d1)) { + return NULL; + } + + // allocate new space + uint8_t *new_dname = (uint8_t *)malloc(d1->size + d2->size); + CHECK_ALLOC_LOG(new_dname, NULL); + + uint8_t *new_labels = (uint8_t *)malloc(d1->label_count + + d2->label_count); + if (new_labels == NULL) { + ERR_ALLOC_FAILED; + free(new_dname); + return NULL; + } + + dbg_dname("1: copying %d bytes from adress %p to %p\n", + d1->size, d1->name, new_dname); + + memcpy(new_dname, d1->name, d1->size); + + dbg_dname("2: copying %d bytes from adress %p to %p\n", + d2->size, d2->name, new_dname + d1->size); + + memcpy(new_dname + d1->size, d2->name, d2->size); + + // update labels + memcpy(new_labels, d1->labels, d1->label_count); + for (int i = 0; i < d2->label_count; ++i) { + new_labels[d1->label_count + i] = d2->labels[i] + d1->size; + } + + uint8_t *old_labels = d1->labels; + d1->labels = new_labels; + free(old_labels); + d1->label_count += d2->label_count; + + uint8_t *old_name = d1->name; + d1->name = new_dname; + free(old_name); + + d1->size += d2->size; + + return d1; +} + +void knot_dname_set_id(knot_dname_t *dname, unsigned int id) +{ + dname->id = id; +} + +unsigned int knot_dname_get_id(const knot_dname_t *dname) +{ + if (dname != NULL) { + return dname->id; + } else { + return 0; /* 0 should never be used and is reserved for err. */ + } +} |