Skip to content
Snippets Groups Projects
Commit 037924e5 authored by Marek Vavrusa's avatar Marek Vavrusa
Browse files

Removed last knot_dname_t structure remains, new API proposal.

There are still a few deficiencies:
* knot_dname_free should be just free
* many functions could be made more efficiently for uncompressed names

refs #21
parent 761dcc56
Branches
Tags
No related merge requests found
......@@ -31,89 +31,6 @@
#include "util/utils.h"
#include "util/wire.h"
/*----------------------------------------------------------------------------*/
/* Non-API functions */
/*----------------------------------------------------------------------------*/
static knot_dname_t *knot_dname_new()
{
knot_dname_t *dname = malloc(sizeof(knot_dname_t));
dname->name = NULL;
dname->count = 1;
dname->size = 0;
return dname;
}
/*!
* \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 == 0 || size > KNOT_MAX_DNAME_LENGTH) {
return KNOT_EINVAL;
}
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. */
}
/* 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;
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 == 0) {
free(wire);
return KNOT_EMALF;
}
label = w;
*label = '\0';
} else {
*w = *ch;
*label += 1;
}
++w;
++ch;
}
/* Check for non-FQDN name. */
if (*label > 0) {
*w = '\0';
}
dname->name = wire;
dname->size = wire_size;
return KNOT_EOK;
}
/*----------------------------------------------------------------------------*/
static int knot_label_is_equal(const uint8_t *lb1, const uint8_t *lb2)
......@@ -125,137 +42,142 @@ static int knot_label_is_equal(const uint8_t *lb1, const uint8_t *lb2)
/* API functions */
/*----------------------------------------------------------------------------*/
knot_dname_t *knot_dname_new_from_str(const char *name, uint size)
knot_dname_t *knot_dname_parse(const uint8_t *pkt, size_t *pos, size_t maxpos)
{
if (name == NULL || size == 0) {
return NULL;
}
knot_dname_t *dname = knot_dname_new();
if (dname == NULL) {
ERR_ALLOC_FAILED;
return NULL;
}
/*! \todo The function should return error codes. */
int ret = knot_dname_str_to_wire(name, size, dname);
if (ret != 0) {
dbg_dname("Failed to create domain name from string.\n");
knot_dname_free(&dname);
const uint8_t *name = pkt + *pos;
const uint8_t *endp = pkt + maxpos;
int parsed = knot_dname_wire_check(name, endp, pkt);
if (parsed < 0)
return NULL;
}
if (dname->size <= 0) {
dbg_dname("Could not parse domain name "
"from string: '%.*s'\n", size, name);
/* Allocate space for the name. */
knot_dname_t *res = malloc(parsed);
if (res) {
/* Unpack name (expand compression pointers). */
if (knot_dname_unpack(res, name, parsed, pkt) > 0) {
*pos += parsed;
} else {
free(res);
res = NULL;
}
}
assert(dname->name != NULL);
return dname;
return res;
}
/*----------------------------------------------------------------------------*/
knot_dname_t *knot_dname_new_from_wire(const uint8_t *name, uint size)
knot_dname_t *knot_dname_copy(const knot_dname_t *name)
{
if (name == NULL) { /* && size != 0) { !OS: Nerozumjaju */
dbg_dname("No name given!\n");
return NULL;
}
knot_dname_t *dname = knot_dname_new();
return knot_dname_copy_part(name, knot_dname_size(name));
}
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);
knot_dname_t *knot_dname_copy_part(const knot_dname_t *name, unsigned len)
{
assert(name && len > 0);
knot_dname_t *dst = malloc(len);
if (knot_dname_to_wire(dst, name, len) < 1) {
free(dst);
return NULL;
}
/*! \todo this won't work for non-linear names */
memcpy(dname->name, name, size);
dname->size = size;
return dname;
return dst;
}
/*----------------------------------------------------------------------------*/
knot_dname_t *knot_dname_parse_from_wire(const uint8_t *wire,
size_t *pos, size_t size)
int knot_dname_to_wire(uint8_t *dst, const knot_dname_t *src, size_t maxlen)
{
const uint8_t *name = wire + *pos;
const uint8_t *endp = wire + size;
int parsed = knot_dname_wire_check(name, endp, wire);
if (parsed < 0)
return NULL;
knot_dname_t *dname = knot_dname_new_from_wire(name, parsed);
if (dname)
*pos += parsed;
/* Write out non or partially compressed name. */
int len = 0;
while (*src != '\0' && !knot_wire_is_pointer(src)) {
uint8_t lblen = *src + 1;
if (len + lblen > maxlen)
return KNOT_ESPACE;
memcpy(dst + len, src, lblen);
len += lblen;
src += lblen;
}
return dname;
/* Terminated either FQDN \x00, or as a pointer. */
if (*src == '\0') {
if (len + 1> maxlen)
return KNOT_ESPACE;
*(dst + len) = '\0';
len += 1; /* \x00 */
} else {
if (len + 2 > maxlen)
return KNOT_ESPACE;
memcpy(dst + len, src, sizeof(uint16_t));
len += 2; /* ptr */
}
return len;
}
/*----------------------------------------------------------------------------*/
knot_dname_t *knot_dname_deep_copy(const knot_dname_t *dname)
int knot_dname_unpack(uint8_t* dst, const knot_dname_t *src,
size_t maxlen, const uint8_t *pkt)
{
/* dname_new_from_wire() does not accept non-FQDN dnames, so we
* do the copy by hand. It's faster anyway */
if (dst == NULL || src == NULL)
return KNOT_EINVAL;
if (dname == NULL) {
return NULL;
/* Seek first real label occurence. */
while (knot_wire_is_pointer(src)) {
src = knot_wire_next_label(src, pkt);
}
knot_dname_t *copy = knot_dname_new();
CHECK_ALLOC(copy, NULL);
copy->name = (uint8_t *)(malloc(dname->size));
if (copy->name == NULL) {
knot_dname_free(&copy);
return NULL;
/* Unpack rest of the labels. */
int len = 0;
while (*src != '\0') {
uint8_t lblen = *src + 1;
if (len + lblen > maxlen)
return KNOT_ESPACE;
memcpy(dst + len, src, lblen);
len += lblen;
src = knot_wire_next_label(src, pkt);
}
memcpy(copy->name, dname->name, dname->size);
copy->size = dname->size;
/* Terminal label */
if (len + 1 > maxlen)
return KNOT_EINVAL;
return copy;
*(dst + len) = '\0';
return len + 1;
}
/*----------------------------------------------------------------------------*/
char *knot_dname_to_str(const knot_dname_t *dname)
char *knot_dname_to_str(const knot_dname_t *name)
{
if (!dname || dname->size == 0) {
return 0;
}
if (name == NULL)
return NULL;
/*! \todo Supply packet. */
/*! \todo Write to static buffer? */
// Allocate space for dname string + 1 char termination.
size_t alloc_size = dname->size + 1;
char *name = malloc(alloc_size);
if (name == NULL) {
int dname_size = knot_dname_size(name);
size_t alloc_size = dname_size + 1;
char *res = malloc(alloc_size);
if (res == NULL) {
return NULL;
}
uint8_t label_len = 0;
size_t str_len = 0;
for (uint i = 0; i < dname->size; i++) {
uint8_t c = dname->name[i];
for (uint i = 0; i < dname_size; i++) {
uint8_t c = name[i];
// Read next label size.
if (label_len == 0) {
label_len = c;
// Write label separation.
if (str_len > 0 || dname->size == 1) {
name[str_len++] = '.';
if (str_len > 0 || dname_size == 1) {
res[str_len++] = '.';
}
continue;
......@@ -263,35 +185,35 @@ char *knot_dname_to_str(const knot_dname_t *dname)
if (isalnum(c) != 0 || c == '-' || c == '_' || c == '*' ||
c == '/') {
name[str_len++] = c;
res[str_len++] = c;
} else if (ispunct(c) != 0) {
// Increase output size for \x format.
alloc_size += 1;
char *extended = realloc(name, alloc_size);
char *extended = realloc(res, alloc_size);
if (extended == NULL) {
free(name);
free(res);
return NULL;
}
name = extended;
res = extended;
// Write encoded character.
name[str_len++] = '\\';
name[str_len++] = c;
res[str_len++] = '\\';
res[str_len++] = c;
} else {
// Increase output size for \DDD format.
alloc_size += 3;
char *extended = realloc(name, alloc_size);
char *extended = realloc(res, alloc_size);
if (extended == NULL) {
free(name);
free(res);
return NULL;
}
name = extended;
res = extended;
// Write encoded character.
int ret = snprintf(name + str_len, alloc_size - str_len,
int ret = snprintf(res + str_len, alloc_size - str_len,
"\\%03u", c);
if (ret <= 0 || ret >= alloc_size - str_len) {
free(name);
free(res);
return NULL;
}
......@@ -302,160 +224,165 @@ char *knot_dname_to_str(const knot_dname_t *dname)
}
// String_termination.
name[str_len] = 0;
return name;
}
res[str_len] = 0;
/*----------------------------------------------------------------------------*/
int knot_dname_to_lower(knot_dname_t *dname)
{
return knot_dname_to_lower_copy(dname, (char*)dname->name, dname->size);
return res;
}
/*----------------------------------------------------------------------------*/
int knot_dname_to_lower_copy(const knot_dname_t *dname, char *name,
size_t size)
knot_dname_t *knot_dname_from_str(const char *name, unsigned len)
{
if (dname == NULL || name == NULL || size < dname->size) {
return KNOT_EINVAL;
if (len == 0 || len > KNOT_DNAME_MAXLEN) {
return NULL;
}
for (int i = 0; i < dname->size; ++i) {
name[i] = knot_tolower(dname->name[i]);
/* Estimate wire size for special cases. */
unsigned wire_size = len + 1;
if (name[0] == '.' && len == 1) {
wire_size = 1; /* Root label. */
len = 0; /* Do not parse input. */
} else if (name[len - 1] != '.') {
++wire_size; /* No FQDN, reserve last root label. */
}
return KNOT_EOK;
}
/*----------------------------------------------------------------------------*/
/* Create wire. */
uint8_t *wire = malloc(wire_size * sizeof(uint8_t));
if (wire == NULL)
return NULL;
*wire = '\0';
const uint8_t *knot_dname_name(const knot_dname_t *dname)
{
return dname->name;
}
/* Parse labels. */
const uint8_t *ch = (const uint8_t *)name;
const uint8_t *np = ch + len;
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 == 0) {
free(wire);
return NULL;
}
label = w;
*label = '\0';
} else {
*w = *ch;
*label += 1;
}
++w;
++ch;
}
/*----------------------------------------------------------------------------*/
/* Check for non-FQDN name. */
if (*label > 0) {
*w = '\0';
}
uint knot_dname_size(const knot_dname_t *dname)
{
return dname->size;
return wire;
}
/*----------------------------------------------------------------------------*/
int knot_dname_is_fqdn(const knot_dname_t *dname)
int knot_dname_to_lower(knot_dname_t *name)
{
return (dname->name[dname->size - 1] == '\0');
/*! \todo Faster with \xdfdf mask. */
while (*name != '\0') {
for (uint8_t i = 0; i < *name; ++i)
name[1 + i] = knot_tolower(name[1 + i]);
name = (uint8_t *)knot_wire_next_label(name, NULL);
assert(name); /* Must not be used on compressed names. */
}
return KNOT_EOK;
}
/*----------------------------------------------------------------------------*/
knot_dname_t *knot_dname_left_chop(const knot_dname_t *dname)
int knot_dname_size(const knot_dname_t *name)
{
if (dname == NULL || *knot_dname_name(dname) == '\0') { /* root */
return NULL;
}
knot_dname_t *parent = knot_dname_new();
if (parent == NULL) {
return NULL;
/* Count name size without terminal label. */
int len = 0;
while (*name != '\0' && !knot_wire_is_pointer(name)) {
uint8_t lblen = *name + 1;
len += lblen;
name += lblen;
}
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;
}
/* Compression pointer is 2 octets. */
if (knot_wire_is_pointer(name))
return len + 2;
memcpy(parent->name, &dname->name[dname->name[0] + 1], parent->size);
return parent;
return len + 1;
}
/*----------------------------------------------------------------------------*/
void knot_dname_left_chop_no_copy(knot_dname_t *dname)
int knot_dname_wire_size(const knot_dname_t *name, const uint8_t *pkt)
{
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);
return knot_dname_prefixlen(name, KNOT_DNAME_MAXLABELS, pkt);
}
/*----------------------------------------------------------------------------*/
int knot_dname_is_subdomain(const knot_dname_t *sub,
const knot_dname_t *domain)
bool knot_dname_is_sub(const knot_dname_t *sub, const knot_dname_t *domain)
{
if (sub == domain)
return 0;
return false;
/* 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);
int sub_l = knot_dname_labels(sub, NULL);
int domain_l = knot_dname_labels(domain, NULL);
/* Subdomain must have more labels as parent. */
if (sub_l <= domain_l)
return 0;
return false;
/* Align end-to-end to common suffix. */
int common = knot_dname_align(&sub_p, sub_l, &domain_p, domain_l, NULL);
int common = knot_dname_align(&sub, sub_l, &domain, domain_l, NULL);
/* Compare common suffix. */
while(common > 0) {
/* Compare label. */
if (!knot_label_is_equal(sub_p, domain_p))
return 0;
if (!knot_label_is_equal(sub, domain))
return false;
/* Next label. */
sub_p = knot_wire_next_label(sub_p, NULL);
domain_p = knot_wire_next_label(domain_p, NULL);
sub = knot_wire_next_label(sub, NULL);
domain = knot_wire_next_label(domain, NULL);
--common;
}
return 1;
return true;
}
/*----------------------------------------------------------------------------*/
int knot_dname_is_wildcard(const knot_dname_t *dname)
int knot_dname_is_wildcard(const knot_dname_t *name)
{
return (dname->size >= 2
&& dname->name[0] == 1
&& dname->name[1] == '*');
return name[0] == 1 && name[1] == '*';
}
/*----------------------------------------------------------------------------*/
int knot_dname_matched_labels(const knot_dname_t *dname1,
const knot_dname_t *dname2)
int knot_dname_matched_labels(const knot_dname_t *dname1, const knot_dname_t *dname2)
{
/* 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);
int l1 = knot_dname_labels(dname1, NULL);
int l2 = knot_dname_labels(dname2, NULL);
/* Align end-to-end to common suffix. */
int common = knot_dname_align(&d1, l1, &d2, l2, NULL);
int common = knot_dname_align(&dname1, l1, &dname2, l2, NULL);
/* Count longest chain leading to root label. */
int matched = 0;
while (common > 0) {
if (knot_label_is_equal(d1, d2))
if (knot_label_is_equal(dname1, dname2))
++matched;
else
matched = 0; /* Broken chain. */
/* Next label. */
d1 = knot_wire_next_label(d1, NULL);
d2 = knot_wire_next_label(d2, NULL);
dname1 = knot_wire_next_label(dname1, NULL);
dname2 = knot_wire_next_label(dname2, NULL);
--common;
}
......@@ -464,43 +391,43 @@ int knot_dname_matched_labels(const knot_dname_t *dname1,
/*----------------------------------------------------------------------------*/
knot_dname_t *knot_dname_replace_suffix(const knot_dname_t *dname, int size,
knot_dname_t *knot_dname_replace_suffix(const knot_dname_t *dname, unsigned labels,
const knot_dname_t *suffix)
{
dbg_dname_exec_verb(
char *name = knot_dname_to_str(dname);
dbg_dname_verb("Replacing suffix of name %s, size %d with ", name,
size);
free(name);
name = knot_dname_to_str(suffix);
dbg_dname_verb("%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_detail("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);
/* Calculate prefix and suffix lengths. */
int dname_lbs = knot_dname_labels(dname, NULL);
unsigned prefix_lbs = dname_lbs - labels;
dbg_dname_detail("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);
/* Trim 1 octet from prefix, as it is measured as FQDN. */
int prefix_len = knot_dname_prefixlen(dname, prefix_lbs, NULL) - 1;
int suffix_len = knot_dname_size(suffix);
if (prefix_len < 0 || suffix_len < 0)
return NULL;
dbg_dname_detail("Copying %d bytes from the suffix.\n", suffix->size);
memcpy(res->name + dname->size - size, suffix->name, suffix->size);
/* Create target name. */
int new_len = prefix_len + suffix_len;
knot_dname_t *out = malloc(new_len);
if (out == NULL)
return NULL;
dbg_dname_hex((char *)res->name, res->size);
/* Copy prefix. */
uint8_t *dst = out;
while (prefix_lbs > 0) {
memcpy(dst, dname, *dname + 1);
dst += *dname + 1;
dname = knot_wire_next_label(dname, NULL);
--prefix_lbs;
}
return res;
/* Copy suffix. */
while (*suffix != '\0') {
memcpy(dst, suffix, *suffix + 1);
dst += *suffix + 1;
suffix = knot_wire_next_label(suffix, NULL);
}
*dst = '\0';
return out;
}
/*----------------------------------------------------------------------------*/
......@@ -511,71 +438,64 @@ void knot_dname_free(knot_dname_t **dname)
return;
}
free((*dname)->name);
// slab_free(*dname);
free(*dname);
*dname = NULL;
}
/*----------------------------------------------------------------------------*/
int knot_dname_compare(const knot_dname_t *d1, const knot_dname_t *d2)
int knot_dname_cmp(const knot_dname_t *d1, const knot_dname_t *d2)
{
return knot_dname_wire_cmp(d1, d2, NULL);
return knot_dname_cmp_wire(d1, d2, NULL);
}
/*----------------------------------------------------------------------------*/
int knot_dname_compare_cs(const knot_dname_t *d1, const knot_dname_t *d2)
int knot_dname_cmp_wire(const knot_dname_t *d1, const knot_dname_t *d2,
const uint8_t *pkt)
{
return knot_dname_wire_cmp(d1, d2, NULL);
}
/* Convert to lookup format. */
uint8_t d1_lf[KNOT_DNAME_MAXLEN], d2_lf[KNOT_DNAME_MAXLEN];
if (knot_dname_lf(d1_lf, d1, pkt) < 0 || knot_dname_lf(d2_lf, d2, pkt) < 0)
return KNOT_EINVAL;
int knot_dname_compare_non_canon(const knot_dname_t *d1, const knot_dname_t *d2)
{
int ret = memcmp(d1->name, d2->name,
d1->size > d2->size ? d2->size : d1->size);
if (d1->size != d2->size && ret == 0) {
return d1->size < d2->size ? -1 : 1;
} else {
/* 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;
}
/*----------------------------------------------------------------------------*/
knot_dname_t *knot_dname_cat(knot_dname_t *d1, const knot_dname_t *d2)
int knot_dname_is_equal(const knot_dname_t *d1, const knot_dname_t *d2)
{
if (d2->size == 0) {
return d1;
}
// allocate new space
size_t new_size = d1->size + d2->size - 1; /* Trim the d1 \0 label */
uint8_t *new_dname = (uint8_t *)malloc(new_size);
CHECK_ALLOC_LOG(new_dname, NULL);
dbg_dname_detail("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_detail("2: copying %d bytes from adress %p to %p\n",
d2->size, d2->name, new_dname + d1->size);
/* Overwrite the d1 \0 label. */
memcpy(new_dname + d1->size - 1, d2->name, d2->size);
uint8_t *old_name = d1->name;
d1->name = new_dname;
free(old_name);
/*! \todo Could be implemented more efficiently, check profile first. */
return (knot_dname_cmp(d1, d2) == 0);
}
d1->size = new_size;
/*----------------------------------------------------------------------------*/
return d1;
knot_dname_t *knot_dname_cat(knot_dname_t *d1, const knot_dname_t *d2)
{
/* This is problem equal to replacing last \x00 from d1 with d2. */
knot_dname_t *ret = knot_dname_replace_suffix(d1, 0, d2);
/* Like if we are reallocating d1. */
knot_dname_free(&d1);
return ret;
}
int knot_dname_wire_check(const uint8_t *name, const uint8_t *endp,
const uint8_t *pkt)
{
......@@ -594,7 +514,7 @@ int knot_dname_wire_check(const uint8_t *name, const uint8_t *endp,
return KNOT_ESPACE;
/* Reject more labels. */
if (labels == KNOT_MAX_DNAME_LABELS - 1)
if (labels == KNOT_DNAME_MAXLABELS - 1)
return KNOT_EMALF;
if (knot_wire_is_pointer(name)) {
......@@ -618,7 +538,7 @@ int knot_dname_wire_check(const uint8_t *name, const uint8_t *endp,
return KNOT_EMALF;
/* Check if there's enough space. */
int lblen = *name + 1;
if (name_len + lblen > KNOT_MAX_DNAME_LENGTH)
if (name_len + lblen > KNOT_DNAME_MAXLEN)
return KNOT_EMALF;
/* Update wire size only for noncompressed part. */
name_len += lblen;
......@@ -640,11 +560,15 @@ int knot_dname_wire_check(const uint8_t *name, const uint8_t *endp,
return wire_len;
}
int knot_dname_wire_size(const uint8_t *name, const uint8_t *pkt)
int knot_dname_prefixlen(const uint8_t *name, unsigned nlabels, const uint8_t *pkt)
{
if (!name)
return KNOT_EINVAL;
/* Zero labels means 1 octet \x00 */
if (nlabels == 0)
return 1;
/* Seek first real label occurence. */
while (knot_wire_is_pointer(name)) {
name = knot_wire_next_label((uint8_t *)name, (uint8_t *)pkt);
......@@ -654,12 +578,14 @@ int knot_dname_wire_size(const uint8_t *name, const uint8_t *pkt)
while (*name != '\0') {
len += *name + 1;
name = knot_wire_next_label((uint8_t *)name, (uint8_t *)pkt);
if (--nlabels == 0) /* Count N first labels only. */
break;
}
return len;
}
int knot_dname_wire_labels(const uint8_t *name, const uint8_t *pkt)
int knot_dname_labels(const uint8_t *name, const uint8_t *pkt)
{
uint8_t count = 0;
while (*name != '\0') {
......@@ -684,54 +610,30 @@ int knot_dname_align(const uint8_t **d1, uint8_t d1_labels,
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)
int knot_dname_lf(uint8_t *dst, const knot_dname_t *src, const uint8_t *pkt)
{
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;
uint8_t *len = dst++;
*len = '\0';
*dst = '\0';
const uint8_t* l = src;
/*! \todo This could be made as offsets to pkt? */
const uint8_t* lstack[KNOT_DNAME_MAXLEN];
const uint8_t **sp = lstack;
while(*l != 0) { /* build label stack */
*sp++ = (l - src->name);
l += 1 + *l;
*sp++ = l;
l = knot_wire_next_label(l, pkt);
}
while(sp != lstack) { /* consume stack */
l = src->name + *--sp; /* fetch rightmost label */
l = *--sp; /* fetch rightmost label */
memcpy(dst, l+1, *l); /* write label */
dst += *l;
*dst++ = '\0'; /* label separator */
*len += *l + 1;
}
/* root label special case */
if (*len == 0)
*len = 1; /* \x00 */
return KNOT_EOK;
}
......@@ -30,92 +30,81 @@
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <stdbool.h>
#include "libknot/consts.h"
typedef uint8_t knot_dname_t;
/*!
* \brief Structure for representing a domain name.
* \brief Check dname on the wire for constraints.
*
* If the name passes such checks, it is safe to be used in rest of the functions.
*
* Stores the domain name in wire format.
* \param name Name on the wire.
* \param endp Name boundary.
* \param pkt Wire.
*
* \todo Consider restricting to FQDN only (see knot_dname_new_from_str()).
* \retval KNOT_EOK
* \retval KNOT_EMALF
* \retval KNOT_ESPACE
*/
struct knot_dname {
uint8_t *name; /*!< Wire format of the domain name. */
uint32_t count; /*!< Reference counter. */
uint8_t size; /*!< Length of the domain name. */
};
typedef struct knot_dname knot_dname_t;
#define DNAME_LFT_MAXLEN 255 /* maximum lookup format length */
/*----------------------------------------------------------------------------*/
int knot_dname_wire_check(const uint8_t *name, const uint8_t *endp,
const uint8_t *pkt);
/*!
* \brief Creates a dname structure from domain name given in presentation
* format.
*
* The resulting domain name is stored in wire format, but it may not end with
* root label (0).
*
* \note Newly created dname is referenced, caller is responsible for releasing
* it after use.
* \brief Parse dname from wire.
*
* \param name Domain name in presentation format (labels separated by dots).
* \param size Size of the domain name (count of characters with all dots).
* \param pkt Message in wire format.
* \param pos Position of the domain name on wire.
* \param maxpos Domain name length.
*
* \return Newly allocated and initialized dname structure representing the
* given domain name.
* \return parsed domain name or NULL.
*/
knot_dname_t *knot_dname_new_from_str(const char *name, unsigned int size);
knot_dname_t *knot_dname_parse(const uint8_t *pkt, size_t *pos, size_t maxpos);
/*!
* \brief Creates a dname structure from domain name given in wire format.
*
* \note The name is copied into the structure.
* \note If the given name is not a FQDN, the result will be neither.
* \note Newly created dname is referenced, caller is responsible for releasing
* it after use.
* \brief Duplicates the given domain name.
*
* \param name Domain name in wire format.
* \param size Size of the domain name in octets.
* \param dname Domain name to be copied.
*
* \return Newly allocated and initialized dname structure representing the
* given domain name.
* \return New domain name which is an exact copy of \a dname.
*/
knot_dname_t *knot_dname_copy(const knot_dname_t *name);
/*!
* \brief Duplicates part of the given domain name.
*
* \todo This function does not check if the given data is in correct wire
* format at all. It thus creates a invalid domain name, which if passed
* e.g. to knot_dname_to_str() may result in crash. Decide whether it
* is OK to retain this and check the data in other functions before
* calling this one, or if it should verify the given data.
* \param dname Domain name to be copied.
* \param len Part length.
*
* \warning Actually, right now this function does not accept non-FQDN dnames.
* For some reason there is a check for this.
* \return New domain name which is an partial copy of \a dname.
*/
knot_dname_t *knot_dname_new_from_wire(const uint8_t *name, unsigned int size);
knot_dname_t *knot_dname_copy_part(const knot_dname_t *name, unsigned len);
/*!
* \brief Parse dname from wire.
* \brief Copy name to wire as is, no compression pointer expansion will be done.
*
* \param wire Message in wire format.
* \param pos Position of the domain name on wire.
* \param size Domain name length.
* \param dst Destination wire.
* \param src Source name.
* \param maxlen Maximum wire length.
*
* \return parsed domain name or NULL.
* \return number of bytes written
*/
knot_dname_t *knot_dname_parse_from_wire(const uint8_t *wire,
size_t *pos, size_t size);
int knot_dname_to_wire(uint8_t *dst, const knot_dname_t *src, size_t maxlen);
/*!
* \brief Duplicates the given domain name.
* \brief Write unpacked name (i.e. compression pointers expanded)
*
* \note Copied dname referense count is reset to 1, caller is responsible
* for releasing it after use.
*
* \param dname Domain name to be copied.
* \param dst Destination wire.
* \param src Source name.
* \param maxlen Maximum destination wire size.
* \param pkt Name packet wire (for compression pointers).
*
* \return New domain name which is an exact copy of \a dname.
* \return number of bytes written
*/
knot_dname_t *knot_dname_deep_copy(const knot_dname_t *dname);
int knot_dname_unpack(uint8_t *dst, const knot_dname_t *src,
size_t maxlen, const uint8_t *pkt);
/*!
* \brief Converts the given domain name to string representation.
......@@ -127,53 +116,53 @@ knot_dname_t *knot_dname_deep_copy(const knot_dname_t *dname);
* \return 0-terminated string representing the given domain name in
* presentation format.
*/
char *knot_dname_to_str(const knot_dname_t *dname);
int knot_dname_to_lower(knot_dname_t *dname);
int knot_dname_to_lower_copy(const knot_dname_t *dname, char *name,
size_t size);
char *knot_dname_to_str(const knot_dname_t *name);
/*!
* \brief Returns the domain name in wire format.
* \brief Creates a dname structure from domain name given in presentation
* format.
*
* \param dname Domain name.
* The resulting FQDN is stored in the wire format.
*
* \return Wire format of the domain name.
* \param name Domain name in presentation format (labels separated by dots).
* \param len Size of the domain name (count of characters with all dots).
*
* \return new name or NULL
*/
const uint8_t *knot_dname_name(const knot_dname_t *dname);
knot_dname_t *knot_dname_from_str(const char *name, unsigned len);
/*!
* \brief Returns size of the given domain name.
* \brief Convert name to lowercase.
*
* \param dname Domain name to get the size of.
* \note Name must not be compressed.
*
* \param name Domain name to be converted.
*
* \return Size of the domain name in wire format in octets.
* \return KNOT_EOK
* \retval KNOT_EINVAL
*/
unsigned int knot_dname_size(const knot_dname_t *dname);
int knot_dname_to_lower(knot_dname_t *name);
/*!
* \brief Checks if the given domain name is a fully-qualified domain name.
* \brief Returns size of the given domain name.
*
* \param dname Domain name to check.
* \param dname Domain name to get the size of.
*
* \retval <> 0 if \a dname is a FQDN.
* \retval 0 otherwise.
* \retval size of the domain name
* \retval KNOT_ERROR
*/
int knot_dname_is_fqdn(const knot_dname_t *dname);
int knot_dname_size(const knot_dname_t *name);
/*!
* \brief Creates new domain name by removing leftmost label from \a dname.
*
* \note Newly created dname reference count is set to 1, caller is responsible
* for releasing it after use.
* \brief Returns wire size of the given domain name (expaned compression ptrs).
*
* \param dname Domain name to remove the first label from.
* \param dname Domain name to get the size of.
* \param pkt Related packet (or NULL if unpacked)
*
* \return New domain name with the same labels as \a dname, except for the
* leftmost label, which is removed.
* \retval size of the domain name
* \retval KNOT_ERROR
*/
knot_dname_t *knot_dname_left_chop(const knot_dname_t *dname);
int knot_dname_wire_size(const knot_dname_t *name, const uint8_t *pkt);
/*!
* \brief Checks if one domain name is a subdomain of other.
......@@ -184,8 +173,7 @@ knot_dname_t *knot_dname_left_chop(const knot_dname_t *dname);
* \retval <> 0 if \a sub is a subdomain of \a domain.
* \retval 0 otherwise.
*/
int knot_dname_is_subdomain(const knot_dname_t *sub,
const knot_dname_t *domain);
bool knot_dname_is_sub(const knot_dname_t *sub, const knot_dname_t *domain);
/*!
* \brief Checks if the domain name is a wildcard.
......@@ -195,7 +183,7 @@ int knot_dname_is_subdomain(const knot_dname_t *sub,
* \retval <> 0 if \a dname is a wildcard domain name.
* \retval 0 otherwise.
*/
int knot_dname_is_wildcard(const knot_dname_t *dname);
int knot_dname_is_wildcard(const knot_dname_t *name);
/*!
* \brief Returns the number of labels common for the two domain names (counted
......@@ -214,15 +202,15 @@ int knot_dname_matched_labels(const knot_dname_t *dname1,
* name.
*
* \param dname Domain name where to replace the suffix.
* \param size Size of the suffix to be replaced.
* \param labels Size of the suffix to be replaced.
* \param suffix New suffix to be used as a replacement.
*
* \return New domain name created by replacing suffix of \a dname of size
* \a size with \a suffix.
*/
knot_dname_t *knot_dname_replace_suffix(const knot_dname_t *dname,
int size,
const knot_dname_t *suffix);
unsigned labels,
const knot_dname_t *suffix);
/*!
* \brief Destroys the given domain name.
......@@ -247,7 +235,20 @@ void knot_dname_free(knot_dname_t **dname);
* \retval > 0 if \a d1 goes after \a d2 in canonical order.
* \retval 0 if the domain names are identical.
*/
int knot_dname_compare(const knot_dname_t *d1, const knot_dname_t *d2);
int knot_dname_cmp(const knot_dname_t *d1, const knot_dname_t *d2);
/*!
* \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_cmp_wire(const knot_dname_t *d1, const knot_dname_t *d2,
const uint8_t *pkt);
/*!
* \brief Compares two domain names (case sensitive).
......@@ -259,87 +260,46 @@ int knot_dname_compare(const knot_dname_t *d1, const knot_dname_t *d2);
* \retval > 0 if \a d1 goes after \a d2 in canonical order.
* \retval 0 if the domain names are identical.
*/
int knot_dname_compare_cs(const knot_dname_t *d1, const knot_dname_t *d2);
int knot_dname_compare_non_canon(const knot_dname_t *d1,
const knot_dname_t *d2);
int knot_dname_is_equal(const knot_dname_t *d1, const knot_dname_t *d2);
/*!
* \brief Concatenates two domain names.
*
* \note Member \a node is ignored, i.e. preserved.
*
* \param d1 First domain name (will be modified).
* \param d1 First domain name (will be modified).
* \param d2 Second domain name (will not be modified).
*
* \return The concatenated domain name (i.e. modified \a d1) or NULL if
* the operation is not valid (e.g. \a d1 is a FQDN).
* \return The concatenated domain name or NULL
*/
knot_dname_t *knot_dname_cat(knot_dname_t *d1, const knot_dname_t *d2);
/*!
* \brief Increment reference counter for dname.
* \brief Cound length of the N first labels.
*
* Function makes shallow copy (reference).
* \param name Domain name.
* \param nlabels N first labels.
* \param pkt Related packet (or NULL if not compressed).
*
* \param dname Referenced dname.
* \retval length of the prefix
*/
static inline void knot_dname_retain(knot_dname_t *dname) {
if (dname) {
__sync_add_and_fetch(&dname->count, 1);
}
}
int knot_dname_prefixlen(const uint8_t *name, unsigned nlabels, const uint8_t *pkt);
/*!
* \brief Decrement reference counter for dname.
* \brief Return number of labels in the domain name.
*
* \param dname Referenced dname.
*/
static inline void knot_dname_release(knot_dname_t *dname) {
if (dname) {
if (__sync_sub_and_fetch(&dname->count, 1) == 0) {
knot_dname_free(&dname);
}
}
}
/* ! New nocopy based API.
* \note Temporary, subject to name changes.
*/
int knot_dname_wire_check(const uint8_t *name, const uint8_t *endp,
const uint8_t *pkt);
/*! Calculate wire size.
* \note Expects already checked name.
* \note pkt Supply if name uses dname compression, NULL otherwise.
*/
int knot_dname_wire_size(const uint8_t *name, const uint8_t *pkt);
/*! Calculate label count.
* \note Expects already checked name.
* Terminal nullbyte is not counted.
*
* \param name Domain name.
* \param pkt Related packet (or NULL if not compressed).
*/
int knot_dname_wire_labels(const uint8_t *name, const uint8_t *pkt);
int knot_dname_labels(const uint8_t *name, const uint8_t *pkt);
/*!
* \brief Align name and reference to a common number of suffix labels.
* \brief Align name end-to-end and return 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.
*
......@@ -351,17 +311,17 @@ int knot_dname_wire_cmp(const knot_dname_t *d1, const knot_dname_t *d2,
* 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.
* Maximum length of such a domain name is KNOT_DNAME_MAXLEN characters.
*
* \param dst Memory to store converted name into.
* \param maxlen Maximum memory length.
* \param src Source domain name.
* \param pkt Source name packet (NULL if not any).
*
* \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);
int knot_dname_lf(uint8_t *dst, const knot_dname_t *src, const uint8_t *pkt);
#endif /* _KNOT_DNAME_H_ */
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment