diff --git a/src/libknot/dname.c b/src/libknot/dname.c index 05de73c924a74a7c7f4f083b4774db13387c02c5..4602f7033c4fcb35c853e500cec72157c6089dfd 100644 --- a/src/libknot/dname.c +++ b/src/libknot/dname.c @@ -41,32 +41,13 @@ static knot_dname_t *knot_dname_new() knot_dname_t *dname = malloc(sizeof(knot_dname_t)); dname->name = NULL; - dname->labels = NULL; dname->node = NULL; dname->count = 1; dname->size = 0; - dname->label_count = 0; return dname; } -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. * @@ -85,228 +66,60 @@ static int knot_dname_set(knot_dname_t *dname, uint8_t *wire, 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; + if (size == 0 || size > KNOT_MAX_DNAME_LENGTH) { + return KNOT_EINVAL; } - 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; + unsigned wire_size = size + 1; + if (name[0] == '.' && size == 1) { + wire_size = 1; /* Root label. */ + size = 0; /* Do not parse input. */ + } else if (name[size - 1] != '.') { + ++wire_size; /* No FQDN, reserve last root label. */ } - dbg_dname_verb("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); - } + /* Create wire. */ + uint8_t *wire = malloc(wire_size * sizeof(uint8_t)); + if (wire == NULL) + return KNOT_ENOMEM; + *wire = '\0'; 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); - + const uint8_t *np = ch + size; + uint8_t *label = wire; + uint8_t *w = wire + 1; /* Reserve 1 for label len */ + while (*ch != *np) { if (*ch == '.') { /* Zero-length label inside a dname - invalid. */ - if (label_length == 0) { + if (*label == 0) { free(wire); - return -1; + return KNOT_EMALF; } - dbg_dname_detail("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; + label = w; + *label = '\0'; } else { - assert(w - wire < wire_size); - dbg_dname_detail("Position %zd (%p): character: %c\n", - w - wire, w, *ch); *w = *ch; - ++label_length; + *label += 1; } - ++w; ++ch; - assert(ch >= (const uint8_t *)name); - } - - --ch; - if (*ch == '.') { // put 0 for root label if the name ended with . - --w; - dbg_dname_detail("Position %zd (%p): character: (null)\n", - w - wire, w); - *w = 0; - } else { // otherwise we did not save the last label length - dbg_dname_detail("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' && label_count < KNOT_MAX_DNAME_LABELS ) { - if (*pos > 63) { /* Check label lengths. */ - dbg_dname("Wrong wire format of domain name!\n"); - dbg_dname("Label %d exceeds 63 bytes.\n", label_count); - return -1; - } - labels[label_count++] = pos - name; - pos += *pos + 1; } - // TODO: how to check if the domain name has right format? - if (label_count == KNOT_MAX_DNAME_LABELS) { - dbg_dname("Wrong wire format of domain name!\n"); - dbg_dname("Too many labels: %s\n", name); - return -1; - } - - if (pos - name > size || *pos != '\0' ) { - dbg_dname("Wrong wire format of domain name!\n"); - dbg_dname("Position: %"PRIuPTR", character: %d, expected size: %d\n", - pos - name, *pos, size); - return -1; + /* Check for non-FQDN name. */ + if (*label > 0) { + *w = '\0'; } - 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; + dname->name = wire; + dname->size = wire_size; + return KNOT_EOK; } /*----------------------------------------------------------------------------*/ -static int knot_dname_cmp(const knot_dname_t *d1, const knot_dname_t *d2, - int cs) +static int knot_label_is_equal(const uint8_t *lb1, const uint8_t *lb2) { -dbg_dname_exec_verb( - char *name1 = knot_dname_to_str(d1); - char *name2 = knot_dname_to_str(d2); - - dbg_dname_verb("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_detail("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_detail("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_detail("Comparing labels %d and %d\n", - l1 - 1, l2 - 1); - dbg_dname_detail(" 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; + return (*lb1 == *lb2) && memcmp(lb1 + 1, lb2 + 1, *lb1) == 0; } /*----------------------------------------------------------------------------*/ @@ -320,7 +133,6 @@ knot_dname_t *knot_dname_new_from_str(const char *name, uint size, return NULL; } -// knot_dname_t *dname = knot_dname_alloc(); knot_dname_t *dname = knot_dname_new(); if (dname == NULL) { @@ -336,15 +148,6 @@ knot_dname_t *knot_dname_new_from_str(const char *name, uint size, return NULL; } -dbg_dname_exec_verb( - dbg_dname_verb("Created dname with size: %d\n", dname->size); - dbg_dname_verb("Label offsets: "); - for (int i = 0; i < dname->label_count; ++i) { - dbg_dname_verb("%d, ", dname->labels[i]); - } - dbg_dname_verb("\n"); -); - if (dname->size <= 0) { dbg_dname("Could not parse domain name " "from string: '%.*s'\n", size, name); @@ -357,24 +160,6 @@ dbg_dname_exec_verb( /*----------------------------------------------------------------------------*/ -knot_dname_t *knot_dname_new_from_nonfqdn_str(const char *name, uint size, - struct knot_node *node) -{ - knot_dname_t *dname = NULL; - - if (name[size - 1] != '.') { - char *fqdn = strcdup(name, "."); - dname = knot_dname_new_from_str(fqdn, size + 1, node); - free(fqdn); - } else { - dname = knot_dname_new_from_str(name, size, node); - } - - return dname; -} - -/*----------------------------------------------------------------------------*/ - knot_dname_t *knot_dname_new_from_wire(const uint8_t *name, uint size, struct knot_node *node) { @@ -397,15 +182,9 @@ knot_dname_t *knot_dname_new_from_wire(const uint8_t *name, uint size, return NULL; } + /*! \todo this won't work for non-linear names */ memcpy(dname->name, name, size); dname->size = size; - - if (knot_dname_find_labels(dname, 1) != 0) { - dbg_dname("Could not find labels in dname (new from wire).\n"); - knot_dname_free(&dname); - return NULL; - } - dname->node = node; return dname; } @@ -485,10 +264,8 @@ knot_dname_t *knot_dname_parse_from_wire(const uint8_t *wire, /* Allocate if NULL. */ if (dname == NULL) { dname = knot_dname_new(); - if (dname) { + if (dname) dname->name = (uint8_t *)malloc((i + 1) * sizeof(uint8_t)); - dname->labels = (uint8_t *)malloc((l + 1) * sizeof(uint8_t)); - } } if (dname == NULL) { @@ -496,16 +273,14 @@ knot_dname_t *knot_dname_parse_from_wire(const uint8_t *wire, return NULL; } - if (dname->name == NULL || dname->labels == NULL) { + if (dname->name == NULL) { ERR_ALLOC_FAILED; knot_dname_free(&dname); return NULL; } memcpy(dname->name, name, i + 1); - memcpy(dname->labels, labels, l + 1); dname->size = i + 1; - dname->label_count = l; dname->node = node; return dname; @@ -526,22 +301,12 @@ knot_dname_t *knot_dname_deep_copy(const knot_dname_t *dname) knot_dname_t *copy = knot_dname_new(); CHECK_ALLOC(copy, NULL); - copy->labels = (uint8_t *)(malloc(dname->label_count)); - - if (copy->labels == NULL) { - knot_dname_free(©); - return NULL; - } - copy->name = (uint8_t *)(malloc(dname->size)); if (copy->name == NULL) { knot_dname_free(©); return NULL; } - memcpy(copy->labels, dname->labels, dname->label_count); - copy->label_count = dname->label_count; - memcpy(copy->name, dname->name, dname->size); copy->size = dname->size; @@ -633,14 +398,7 @@ char *knot_dname_to_str(const knot_dname_t *dname) int knot_dname_to_lower(knot_dname_t *dname) { - if (dname == NULL) { - return KNOT_EINVAL; - } - - for (int i = 0; i < dname->size; ++i) { - dname->name[i] = knot_tolower(dname->name[i]); - } - return KNOT_EOK; + return knot_dname_to_lower_copy(dname, (char*)dname->name, dname->size); } /*----------------------------------------------------------------------------*/ @@ -758,10 +516,7 @@ int knot_dname_is_fqdn(const knot_dname_t *dname) knot_dname_t *knot_dname_left_chop(const knot_dname_t *dname) { - if (dname == NULL || - /* Root domain. */ - ((knot_dname_label_count(dname) == 0) && - (knot_dname_is_fqdn(dname)))) { + if (dname == NULL || *knot_dname_name(dname) == '\0') { /* root */ return NULL; } @@ -770,25 +525,6 @@ knot_dname_t *knot_dname_left_chop(const knot_dname_t *dname) return NULL; } - // last label, the result should be root domain - if (dname->label_count == 1) { - dbg_dname_verb("Chopping last label.\n"); - parent->label_count = 0; - - parent->name = (uint8_t *)malloc(1); - if (parent->name == NULL) { - ERR_ALLOC_FAILED; - knot_dname_free(&parent); - return NULL; - } - - *parent->name = 0; - - parent->size = 1; - - return parent; - } - parent->size = dname->size - dname->name[0] - 1; parent->name = (uint8_t *)malloc(parent->size); if (parent->name == NULL) { @@ -797,24 +533,7 @@ knot_dname_t *knot_dname_left_chop(const knot_dname_t *dname) 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; } @@ -822,24 +541,13 @@ knot_dname_t *knot_dname_left_chop(const knot_dname_t *dname) void knot_dname_left_chop_no_copy(knot_dname_t *dname) { - // copy the name - if (dname->label_count > 1) { - short first_label_length = dname->labels[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; - } + uint8_t len = *knot_dname_name(dname); + if (len == 0) + return; + + /*! \todo this will work only with linearized names (as of now) */ + dname->size -= (len + 1); + memmove(dname->name, dname->name + len + 1, dname->size); } /*----------------------------------------------------------------------------*/ @@ -847,53 +555,32 @@ void knot_dname_left_chop_no_copy(knot_dname_t *dname) int knot_dname_is_subdomain(const knot_dname_t *sub, const knot_dname_t *domain) { -dbg_dname_exec_verb( - char *name1 = knot_dname_to_str(sub); - char *name2 = knot_dname_to_str(domain); - - dbg_dname_verb("Checking if %s is subdomain of %s\n", name1, name2); - free(name1); - free(name2); -); - - if (sub == domain) { + 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; + /* Count labels. */ + const uint8_t *sub_p = sub->name; + const uint8_t *domain_p = domain->name; + int sub_l = knot_dname_wire_labels(sub_p, NULL); + int domain_l = knot_dname_wire_labels(domain_p, NULL); - dbg_dname_detail("Label counts: %d and %d\n", l1, l2); + /* Subdomain can't have >= labels as parent. */ + if (sub_l >= domain_l) + return 0; - if (l1 <= l2) { // if sub does not have more labes than domain - return 0; // it is not its subdomain - } + /* Align end-to-end to common suffix. */ + int common = knot_dname_align(&sub_p, sub_l, &domain_p, domain_l, NULL); - // compare labels from last to first - while (l1 > 0 && l2 > 0) { - dbg_dname_detail("Comparing labels %d and %d\n", - l1 - 1, l2 - 1); - dbg_dname_detail(" 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 + /* Compare common suffix. */ + while(common > 0) { + /* Compare label. */ + if (!knot_label_is_equal(sub_p, domain_p)) + return 0; + /* Next label. */ + sub_p = knot_wire_next_label(sub_p, NULL); + domain_p = knot_wire_next_label(domain_p, NULL); + --common; } - - // if all labels matched, it should be subdomain (more labels) - assert(l1 > l2); - return 1; } @@ -911,20 +598,27 @@ int knot_dname_is_wildcard(const knot_dname_t *dname) 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; + /* Count labels. */ + const uint8_t *d1 = dname1->name; + const uint8_t *d2 = dname2->name; + int l1 = knot_dname_wire_labels(d1, NULL); + int l2 = knot_dname_wire_labels(d2, NULL); - // compare labels from last to first + /* Align end-to-end to common suffix. */ + int common = knot_dname_align(&d1, l1, &d2, l2, NULL); + + /* Count longest chain leading to root label. */ 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) { + while (common > 0) { + if (knot_label_is_equal(d1, d2)) ++matched; - } else { - break; - } + else + matched = 0; /* Broken chain. */ + + /* Next label. */ + d1 = knot_wire_next_label(d1, NULL); + d2 = knot_wire_next_label(d2, NULL); + --common; } return matched; @@ -932,13 +626,6 @@ int knot_dname_matched_labels(const knot_dname_t *dname1, /*----------------------------------------------------------------------------*/ -int knot_dname_label_count(const knot_dname_t *dname) -{ - return dname->label_count; -} - -/*----------------------------------------------------------------------------*/ - knot_dname_t *knot_dname_replace_suffix(const knot_dname_t *dname, int size, const knot_dname_t *suffix) { @@ -975,8 +662,6 @@ dbg_dname_exec_verb( dbg_dname_hex((char *)res->name, res->size); - knot_dname_find_labels(res, 1); - return res; } @@ -990,9 +675,6 @@ void knot_dname_free(knot_dname_t **dname) free((*dname)->name); - free((*dname)->labels); - - // slab_free(*dname); free(*dname); *dname = NULL; @@ -1002,14 +684,14 @@ void knot_dname_free(knot_dname_t **dname) int knot_dname_compare(const knot_dname_t *d1, const knot_dname_t *d2) { - return knot_dname_cmp(d1, d2, 0); + return knot_dname_wire_cmp(d1, d2, NULL); } /*----------------------------------------------------------------------------*/ int knot_dname_compare_cs(const knot_dname_t *d1, const knot_dname_t *d2) { - return knot_dname_cmp(d1, d2, 1); + return knot_dname_wire_cmp(d1, d2, NULL); } int knot_dname_compare_non_canon(const knot_dname_t *d1, const knot_dname_t *d2) @@ -1039,14 +721,6 @@ knot_dname_t *knot_dname_cat(knot_dname_t *d1, const knot_dname_t *d2) 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_detail("1: copying %d bytes from adress %p to %p\n", d1->size, d1->name, new_dname); @@ -1057,17 +731,6 @@ knot_dname_t *knot_dname_cat(knot_dname_t *d1, const knot_dname_t *d2) 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); @@ -1080,7 +743,7 @@ knot_dname_t *knot_dname_cat(knot_dname_t *d1, const knot_dname_t *d2) int knot_dname_wire_check(const uint8_t *name, const uint8_t *endp, const uint8_t *pkt) { - if (name == NULL) + if (name == NULL || name == endp) return KNOT_EMALF; int wire_len = 0; /* Keep terminal label in advance. */ @@ -1089,9 +752,11 @@ int knot_dname_wire_check(const uint8_t *name, const uint8_t *endp, uint8_t labels = 0; while (*name != '\0') { + /* Check bounds (must have at least 2 octets remaining). */ - if (name + 2 >= endp) + if (name + 2 > endp) return KNOT_ESPACE; + /* Reject more labels. */ if (labels == KNOT_MAX_DNAME_LABELS - 1) return KNOT_EMALF; @@ -1100,7 +765,8 @@ int knot_dname_wire_check(const uint8_t *name, const uint8_t *endp, /* Check that the pointer points backwards * otherwise it could result in infinite loop */ - assert(pkt); + if (pkt == NULL) + return KNOT_EINVAL; uint16_t ptr = knot_wire_get_pointer(name); if (ptr >= (name - pkt)) return KNOT_EMALF; @@ -1126,6 +792,10 @@ int knot_dname_wire_check(const uint8_t *name, const uint8_t *endp, name += lblen; ++labels; } + + /* Check bounds (must have at least 1 octet). */ + if (name + 1 > endp) + return KNOT_ESPACE; } if (!is_compressed) /* Terminal label. */ @@ -1163,3 +833,68 @@ int knot_dname_wire_labels(const uint8_t *name, const uint8_t *pkt) } return count; } + +int knot_dname_align(const uint8_t **d1, uint8_t d1_labels, + const uint8_t **d2, uint8_t d2_labels, + uint8_t *wire) +{ + for (unsigned j = d1_labels; j < d2_labels; ++j) + *d2 = knot_wire_next_label(*d2, wire); + + for (unsigned j = d2_labels; j < d1_labels; ++j) + *d1 = knot_wire_next_label(*d1, wire); + + return (d1_labels < d2_labels) ? d1_labels : d2_labels; +} + +int knot_dname_wire_cmp(const knot_dname_t *d1, const knot_dname_t *d2, + const uint8_t *pkt) +{ + /*! \todo lf conversion should respect packet wire. */ + + /* Convert to lookup format. */ + unsigned buflen = DNAME_LFT_MAXLEN; + uint8_t d1_lf[DNAME_LFT_MAXLEN], d2_lf[DNAME_LFT_MAXLEN]; + if (dname_lf(d1_lf, d1, buflen) < 0 || dname_lf(d2_lf, d2, buflen) < 0) + return KNOT_EINVAL; + + /* Compare common part. */ + uint8_t common = d1_lf[0]; + if (common > d2_lf[0]) + common = d2_lf[0]; + int ret = memcmp(d1_lf+1, d2_lf+1, common); + if (ret != 0) + return ret; + + /* If they match, compare lengths. */ + if (d1_lf[0] < d2_lf[0]) + return -1; + if (d1_lf[0] > d2_lf[0]) + return 1; + return 0; +} + +int dname_lf(uint8_t *dst, const knot_dname_t *src, size_t maxlen) +{ + if (src->size > maxlen) + return KNOT_ESPACE; + *dst = (uint8_t)src->size; + /* need to save last \x00 for root dname */ + if (*dst > 1) + *dst -= 1; + *++dst = '\0'; + uint8_t* l = src->name; + uint8_t lstack[DNAME_LFT_MAXLEN]; + uint8_t *sp = lstack; + while(*l != 0) { /* build label stack */ + *sp++ = (l - src->name); + l += 1 + *l; + } + while(sp != lstack) { /* consume stack */ + l = src->name + *--sp; /* fetch rightmost label */ + memcpy(dst, l+1, *l); /* write label */ + dst += *l; + *dst++ = '\0'; /* label separator */ + } + return KNOT_EOK; +} diff --git a/src/libknot/dname.h b/src/libknot/dname.h index 7fc081f8b2adae5aa16a17e8725f86d7d5395283..e4d3c7dd8391be36e3632149e2da8123ce0b4f82 100644 --- a/src/libknot/dname.h +++ b/src/libknot/dname.h @@ -43,15 +43,15 @@ struct knot_node; */ struct knot_dname { uint8_t *name; /*!< Wire format of the domain name. */ - uint8_t *labels; /*!< Array of labels positions in name. */ struct knot_node *node; /*!< Zone node the domain name belongs to. */ uint32_t count; /*!< Reference counter. */ uint8_t size; /*!< Length of the domain name. */ - uint8_t label_count; /*!< Number of labels. */ }; typedef struct knot_dname knot_dname_t; +#define DNAME_LFT_MAXLEN 255 /* maximum lookup format length */ + /*----------------------------------------------------------------------------*/ /*! @@ -75,20 +75,6 @@ typedef struct knot_dname knot_dname_t; knot_dname_t *knot_dname_new_from_str(const char *name, unsigned int size, struct knot_node *node); -/*! - * \brief Creates a dname structure from domain name possibly given in - * non-presentation format. - * - * Works the same as knot_dname_new_from_str but makes sure, that the name - * is terminated with a dot. - * - * \see knot_dname_new_from_str - * - */ -knot_dname_t *knot_dname_new_from_nonfqdn_str(const char *name, - unsigned int size, - struct knot_node *node); - /*! * \brief Creates a dname structure from domain name given in wire format. * @@ -218,13 +204,6 @@ int knot_dname_is_fqdn(const knot_dname_t *dname); */ knot_dname_t *knot_dname_left_chop(const knot_dname_t *dname); -/*! - * \brief Removes leftmost label from \a dname. - * - * \param dname Domain name to remove the first label from. - */ -void knot_dname_left_chop_no_copy(knot_dname_t *dname); - /*! * \brief Checks if one domain name is a subdomain of other. * @@ -257,18 +236,7 @@ int knot_dname_is_wildcard(const knot_dname_t *dname); * \return Number of labels common for the two domain names. */ int knot_dname_matched_labels(const knot_dname_t *dname1, - const knot_dname_t *dname2); - -/*! - * \brief Returns the number of labels in the domain name. - * - * \param dname Domain name to get the label count of. - * - * \return Number of labels in \a dname. - * - * \todo Find out if this counts the root label also. - */ -int knot_dname_label_count(const knot_dname_t *dname); + const knot_dname_t *dname2); /*! * \brief Replaces the suffix of given size in one domain name with other domain @@ -381,6 +349,49 @@ int knot_dname_wire_size(const uint8_t *name, const uint8_t *pkt); */ int knot_dname_wire_labels(const uint8_t *name, const uint8_t *pkt); +/*! + * \brief Align name and reference to a common number of suffix labels. + */ +int knot_dname_align(const uint8_t **d1, uint8_t d1_labels, + const uint8_t **d2, uint8_t d2_labels, + uint8_t *wire); + +/*! + * \brief Compare domain name by labels. + * + * \todo No case insensitivity, flags... + * + * \param d1 Domain name. + * \param d2 Domain name. + * \param pkt Packet wire related to names (or NULL). + * \return + */ +int knot_dname_wire_cmp(const knot_dname_t *d1, const knot_dname_t *d2, + const uint8_t *pkt); + +/*! + * \brief Convert domain name from wire to lookup format. + * + * Formats names from rightmost label to the leftmost, separated by the lowest + * possible character (\x00). Sorting such formatted names also gives + * correct canonical order (for NSEC/NSEC3). + * + * Example: + * Name: lake.example.com. Wire: \x04lake\x07example\x03com\x00 + * Lookup format com\x00example\x00lake\x00 + * + * Maximum length of such a domain name is DNAME_LFT_MAXLEN characters. + * + * \param dst Memory to store converted name into. + * \param maxlen Maximum memory length. + * \param src Source domain name. + * + * \retval KNOT_EOK if successful + * \retval KNOT_ESPACE when not enough memory. + * \retval KNOT_EINVAL on invalid parameters + */ +int dname_lf(uint8_t *dst, const knot_dname_t *src, size_t maxlen); + #endif /* _KNOT_DNAME_H_ */ /*! @} */ diff --git a/src/tests/libknot/dname_tests.c b/src/tests/libknot/dname_tests.c index 73ca67de9647df7a8133d922fb8836bf36e1fbe1..72600bdef5950cd149f691c97bdd941a59f539e7 100644 --- a/src/tests/libknot/dname_tests.c +++ b/src/tests/libknot/dname_tests.c @@ -20,18 +20,8 @@ /* Test dname_parse_from_wire */ static int test_fw(size_t l, const char *w) { - size_t p = 0; - knot_dname_t *d = NULL; - d = knot_dname_parse_from_wire((const uint8_t*)w, &p, l, NULL, NULL); - int ret = (d != NULL); -// d = knot_dname_new_from_wire((const uint8_t*)w, l, 0); -// if (d) { -// for(unsigned i = 0; i < d->label_count; ++i) { -// diag("%d", knot_dname_label_size(d, i)); -// } -// } - knot_dname_free(&d); - return ret; + const uint8_t *np = (const uint8_t *)w + l; + return knot_dname_wire_check((const uint8_t *)w, np, NULL) > 0; } static int dname_tests_count(int argc, char *argv[]); @@ -45,12 +35,14 @@ unit_api dname_tests_api = { static int dname_tests_count(int argc, char *argv[]) { - return 8; + return 11; } static int dname_tests_run(int argc, char *argv[]) { - const char *w = NULL; + knot_dname_t *d = NULL; + const char *w = NULL, *t = NULL; + unsigned len = 0; /* 1. NULL wire */ ok(!test_fw(0, NULL), "parsing NULL dname"); @@ -80,5 +72,26 @@ static int dname_tests_run(int argc, char *argv[]) w = "\x20\x68\x6d\x6e\x63\x62\x67\x61\x61\x61\x61\x65\x72\x6b\x30\x30\x30\x30\x64\x6c\x61\x61\x61\x61\x61\x61\x61\x61\x62\x65\x6a\x61\x6d\x20\x67\x6e\x69\x64\x68\x62\x61\x61\x61\x61\x65\x6c\x64\x30\x30\x30\x30\x64\x6c\x61\x61\x61\x61\x61\x61\x61\x61\x62\x65\x6a\x61\x6d\x20\x61\x63\x6f\x63\x64\x62\x61\x61\x61\x61\x65\x6b\x72\x30\x30\x30\x30\x64\x6c\x61\x61\x61\x61\x61\x61\x61\x61\x62\x65\x6a\x61\x6d\x20\x69\x62\x63\x6d\x6a\x6f\x61\x61\x61\x61\x65\x72\x6a\x30\x30\x30\x30\x64\x6c\x61\x61\x61\x61\x61\x61\x61\x61\x62\x65\x6a\x61\x6d\x20\x6f\x6c\x6e\x6c\x67\x68\x61\x61\x61\x61\x65\x73\x72\x30\x30\x30\x30\x64\x6c\x61\x61\x61\x61\x61\x61\x61\x61\x62\x65\x6a\x61\x6d\x20\x6a\x6b\x64\x66\x66\x67\x61\x61\x61\x61\x65\x6c\x68\x30\x30\x30\x30\x64\x6c\x61\x61\x61\x61\x61\x61\x61\x61\x62\x65\x6a\x61\x6d\x20\x67\x67\x6c\x70\x70\x61\x61\x61\x61\x61\x65\x73\x72\x30\x30\x30\x30\x64\x6c\x61\x61\x61\x61\x61\x61\x61\x61\x62\x65\x6a\x61\x6d\x20\x65\x6b\x6c\x67\x70\x66\x61\x61\x61\x61\x65\x6c\x68\x30\x30\x30\x30\x64\x6c\x61\x61\x61\x61\x61\x0\x21\x42\x63\x84\xa5\xc6\xe7\x8\xa\xd\x11\x73\x3\x6e\x69\x63\x2\x43\x5a"; ok(!test_fw(277, w), "parsing invalid label (spec. case 1)"); + /* 9. parse from string (correct) .*/ + len = 10; + w = "\x04""abcd""\x03""efg"; + t = "abcd.efg"; + d = knot_dname_new_from_str(t, strlen(t), NULL); + ok(d && d->size == len && memcmp(d->name, w, len) == 0, + "dname_fromstr: parsed correct non-FQDN name"); + knot_dname_free(&d); + + /* 10. parse FQDN from string (correct) .*/ + t = "abcd.efg."; + d = knot_dname_new_from_str(t, strlen(t), NULL); + ok(d && d->size == len && memcmp(d->name, w, len) == 0, + "dname_fromstr: parsed correct FQDN name"); + knot_dname_free(&d); + + /* 11. parse name from string (incorrect) .*/ + t = ".."; + d = knot_dname_new_from_str(t, strlen(t), NULL); + ok(d == NULL, "dname_fromstr: parsed incorrect name"); + return 0; }