/*
* dname.h -- Domain name handling.
*
* Copyright (c) 2001-2006, NLnet Labs. All rights reserved.
*
* See LICENSE for the license.
*
*/
#ifndef _DNAME_H_
#define _DNAME_H_
#include <assert.h>
#include <stdio.h>
#include "buffer.h"
#include "region-allocator.h"
#if defined(NAMEDB_UPPERCASE) || defined(USE_NAMEDB_UPPERCASE)
#define DNAME_NORMALIZE toupper
#else
#define DNAME_NORMALIZE tolower
#endif
/*
* Domain names stored in memory add some additional information to be
* able to quickly index and compare by label.
*/
typedef struct dname dname_type;
struct dname
{
/*
* The size (in bytes) of the domain name in wire format.
*/
uint8_t name_size;
/*
* The number of labels in this domain name (including the
* root label).
*/
uint8_t label_count;
/*
uint8_t label_offsets[label_count];
uint8_t name[name_size];
*/
};
/*
* Construct a new domain name based on NAME in wire format. NAME
* cannot contain compression pointers.
*
* Pre: NAME != NULL.
*/
const dname_type *dname_make(region_type *region, const uint8_t *name,
int normalize);
/*
* Construct a new domain name based on wire format dname stored at
* PACKET's current position. Compression pointers are followed. The
* PACKET's current position is changed to the end of the wire format
* dname or set to just after the first compression pointer.
*/
const dname_type *dname_make_from_packet(region_type *region,
buffer_type *packet,
int allow_pointers,
int normalize);
/*
* parse wireformat from packet (following pointers) into the
* given buffer. Returns length in buffer or 0 on error.
* buffer must be MAXDOMAINLEN+1 long.
*/
int dname_make_wire_from_packet(uint8_t *buf,
buffer_type *packet,
int allow_pointers);
/*
* Construct a new domain name based on the ASCII representation NAME.
* If ORIGIN is not NULL and NAME is not terminated by a "." the
* ORIGIN is appended to the result. NAME can contain escape
* sequences.
*
* Returns NULL on failure. Otherwise a newly allocated domain name
* is returned.
*
* Pre: name != NULL.
*/
const dname_type *dname_parse(region_type *region, const char *name);
/*
* parse ascii string to wireformat domain name (without compression ptrs)
* returns 0 on failure, the length of the wireformat on success.
* the result is stored in the wirefmt which must be at least MAXDOMAINLEN
* in size. On failure, the wirefmt can be altered.
*/
int dname_parse_wire(uint8_t* wirefmt, const char* name);
/*
* Return NULL if DNAME is NULL or a copy of DNAME otherwise.
*/
const dname_type *dname_copy(region_type *region, const dname_type *dname);
/*
* Copy the most significant LABEL_COUNT labels from dname.
*/
const dname_type *dname_partial_copy(region_type *region,
const dname_type *dname,
uint8_t label_count);
/*
* The origin of DNAME.
*/
const dname_type *dname_origin(region_type *region, const dname_type *dname);
/*
* Return true if LEFT is a subdomain of RIGHT.
*/
int dname_is_subdomain(const dname_type *left, const dname_type *right);
/*
* Offsets into NAME for each label starting with the most
* significant label (the root label, followed by the TLD,
* etc).
*/
static inline const uint8_t *
dname_label_offsets(const dname_type *dname)
{
return (const uint8_t *) ((const char *) dname + sizeof(dname_type));
}
/*
* The actual name in wire format (a sequence of label, each
* prefixed by a length byte, terminated by a zero length
* label).
*/
static inline const uint8_t *
dname_name(const dname_type *dname)
{
return (const uint8_t *) ((const char *) dname
+ sizeof(dname_type)
+ dname->label_count * sizeof(uint8_t));
}
/*
* Return the label for DNAME specified by LABEL_INDEX. The first
* label (LABEL_INDEX == 0) is the root label, the next label is the
* TLD, etc.
*
* Pre: dname != NULL && label_index < dname->label_count.
*/
static inline const uint8_t *
dname_label(const dname_type *dname, uint8_t label)
{
uint8_t label_index;
assert(dname != NULL);
assert(label < dname->label_count);
label_index = dname_label_offsets(dname)[label];
assert(label_index < dname->name_size);
return dname_name(dname) + label_index;
}
/*
* Compare two domain names. The comparison defines a lexicographical
* ordering based on the domain name's labels, starting with the most
* significant label.
*
* Return < 0 if LEFT < RIGHT, 0 if LEFT == RIGHT, and > 0 if LEFT >
* RIGHT. The comparison is case sensitive.
*
* Pre: left != NULL && right != NULL
*/
int dname_compare(const dname_type *left, const dname_type *right);
/*
* Compare two labels. The comparison defines a lexicographical
* ordering based on the characters in the labels.
*
* Return < 0 if LEFT < RIGHT, 0 if LEFT == RIGHT, and > 0 if LEFT >
* RIGHT. The comparison is case sensitive.
*
* Pre: left != NULL && right != NULL
* label_is_normal(left) && label_is_normal(right)
*/
int label_compare(const uint8_t *left, const uint8_t *right);
/*
* Returns the number of labels that match in LEFT and RIGHT, starting
* with the most significant label. Because the root label always
* matches, the result will always be >= 1.
*
* Pre: left != NULL && right != NULL
*/
uint8_t dname_label_match_count(const dname_type *left,
const dname_type *right);
/*
* The total size (in bytes) allocated to store DNAME.
*
* Pre: dname != NULL
*/
static inline size_t
dname_total_size(const dname_type *dname)
{
return (sizeof(dname_type)
+ ((((size_t)dname->label_count) + ((size_t)dname->name_size))
* sizeof(uint8_t)));
}
/*
* Is LABEL a normal LABEL (not a pointer or reserved)?
*
* Pre: label != NULL;
*/
static inline int
label_is_normal(const uint8_t *label)
{
assert(label);
return (label[0] & 0xc0) == 0;
}
/*
* Is LABEL a pointer?
*
* Pre: label != NULL;
*/
static inline int
label_is_pointer(const uint8_t *label)
{
assert(label);
return (label[0] & 0xc0) == 0xc0;
}
/*
* LABEL's pointer location.
*
* Pre: label != NULL && label_is_pointer(label)
*/
static inline uint16_t
label_pointer_location(const uint8_t *label)
{
assert(label);
assert(label_is_pointer(label));
return ((uint16_t) (label[0] & ~0xc0) << 8) | (uint16_t) label[1];
}
/*
* Length of LABEL.
*
* Pre: label != NULL && label_is_normal(label)
*/
static inline uint8_t
label_length(const uint8_t *label)
{
assert(label);
assert(label_is_normal(label));
return label[0];
}
/*
* The data of LABEL.
*
* Pre: label != NULL && label_is_normal(label)
*/
static inline const uint8_t *
label_data(const uint8_t *label)
{
assert(label);
assert(label_is_normal(label));
return label + 1;
}
/*
* Is LABEL the root label?
*
* Pre: label != NULL
*/
static inline int
label_is_root(const uint8_t *label)
{
assert(label);
return label[0] == 0;
}
/*
* Is LABEL the wildcard label?
*
* Pre: label != NULL
*/
static inline int
label_is_wildcard(const uint8_t *label)
{
assert(label);
return label[0] == 1 && label[1] == '*';
}
/*
* The next label of LABEL.
*
* Pre: label != NULL
* label_is_normal(label)
* !label_is_root(label)
*/
static inline const uint8_t *
label_next(const uint8_t *label)
{
assert(label);
assert(label_is_normal(label));
assert(!label_is_root(label));
return label + label_length(label) + 1;
}
/*
* Convert DNAME to its string representation. The result points to a
* static buffer that is overwritten the next time this function is
* invoked.
*
* If ORIGIN is provided and DNAME is a subdomain of ORIGIN the dname
* will be represented relative to ORIGIN.
*
* Pre: dname != NULL
*/
const char *dname_to_string(const dname_type *dname,
const dname_type *origin);
/*
* Create a dname containing the single label specified by STR
* followed by the root label.
*/
const dname_type *dname_make_from_label(region_type *region,
const uint8_t *label,
const size_t length);
/*
* Concatenate two dnames.
*/
const dname_type *dname_concatenate(region_type *region,
const dname_type *left,
const dname_type *right);
/*
* Perform DNAME substitution on a name, replace src with dest.
* Name must be a subdomain of src. The returned name is a subdomain of dest.
* Returns NULL if the result domain name is too long.
*/
const dname_type *dname_replace(region_type* region,
const dname_type* name,
const dname_type* src,
const dname_type* dest);
/** Convert uncompressed wireformat dname to a string */
char* wiredname2str(const uint8_t* dname);
/** convert uncompressed label to string */
char* wirelabel2str(const uint8_t* label);
/** check if two uncompressed dnames of the same total length are equal */
int dname_equal_nocase(uint8_t* a, uint8_t* b, uint16_t len);
#endif /* _DNAME_H_ */