diff options
Diffstat (limited to 'src/libknot/dname.h')
-rw-r--r-- | src/libknot/dname.h | 354 |
1 files changed, 354 insertions, 0 deletions
diff --git a/src/libknot/dname.h b/src/libknot/dname.h new file mode 100644 index 0000000..5733de9 --- /dev/null +++ b/src/libknot/dname.h @@ -0,0 +1,354 @@ +/* Copyright (C) 2022 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 <https://www.gnu.org/licenses/>. + */ + +/*! + * \file + * + * \brief Domain name structure and API for manipulating it. + * + * \addtogroup dname + * @{ + */ + +#pragma once + +#include <stdint.h> +#include <stdbool.h> + +#include "libknot/attribute.h" +#include "libknot/consts.h" +#include "libknot/mm_ctx.h" + +/*! \brief Type representing a domain name in wire format. */ +typedef uint8_t knot_dname_t; + +/*! \brief Local domain name storage. */ +typedef uint8_t knot_dname_storage_t[KNOT_DNAME_MAXLEN]; + +/*! \brief Local textual domain name storage. */ +typedef char knot_dname_txt_storage_t[KNOT_DNAME_TXT_MAXLEN + 1]; + +/*! + * \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. + * + * \param name Name on the wire. + * \param endp Name boundary. + * \param pkt Wire. + * + * \retval (compressed) size of the domain name. + * \retval KNOT_EINVAL + * \retval KNOT_EMALF + */ +_pure_ _mustcheck_ +int knot_dname_wire_check(const uint8_t *name, const uint8_t *endp, + const uint8_t *pkt); + +/*! + * \brief Duplicates the given domain name to a local storage. + * + * \param dst Destination storage. + * \param name Domain name to be copied. + * + * \retval size of the domain name. + * \retval 0 if invalid argument. + */ +_mustcheck_ +size_t knot_dname_store(knot_dname_storage_t dst, const knot_dname_t *name); + +/*! + * \brief Duplicates the given domain name. + * + * \param name Domain name to be copied. + * \param mm Memory context. + * + * \return New domain name which is an exact copy of \a name. + */ +_mustcheck_ +knot_dname_t *knot_dname_copy(const knot_dname_t *name, knot_mm_t *mm); + +/*! + * \brief Copy name to wire as is, no compression pointer expansion will be done. + * + * \param dst Destination wire. + * \param src Source name. + * \param maxlen Maximum wire length. + * + * \return the number of bytes written or negative error code + */ +int knot_dname_to_wire(uint8_t *dst, const knot_dname_t *src, size_t maxlen); + +/*! + * \brief Write unpacked name (i.e. compression pointers expanded) + * + * \note The function is very similar to the knot_dname_to_wire(), except + * it expands compression pointers. E.g. you want to use knot_dname_unpack() + * if you copy a dname from incoming packet to some persistent storage. + * And you want to use knot_dname_to_wire() if you know the name is not + * compressed or you want to copy it 1:1. + * + * \param dst Destination wire. + * \param src Source name. + * \param maxlen Maximum destination wire size. + * \param pkt Name packet wire (for compression pointers). + * + * \return number of bytes written + */ +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 its string representation. + * + * \note Output buffer is allocated automatically if dst is NULL. + * + * \param dst Output buffer. + * \param name Domain name to be converted. + * \param maxlen Output buffer length. + * + * \return 0-terminated string if successful, NULL if error. + */ +char *knot_dname_to_str(char *dst, const knot_dname_t *name, size_t maxlen); + +/*! + * \brief This function is a shortcut for \ref knot_dname_to_str with + * no output buffer parameters. + */ +_mustcheck_ +static inline char *knot_dname_to_str_alloc(const knot_dname_t *name) +{ + return knot_dname_to_str(NULL, name, 0); +} + +/*! + * \brief Creates a dname structure from domain name given in presentation + * format. + * + * \note The resulting FQDN is stored in the wire format. + * \note Output buffer is allocated automatically if dst is NULL. + * + * \param dst Output buffer. + * \param name Domain name in presentation format (labels separated by dots, + * '\0' terminated). + * \param maxlen Output buffer length. + * + * \return New dname if successful, NULL if error. + */ +knot_dname_t *knot_dname_from_str(uint8_t *dst, const char *name, size_t maxlen); + +/*! + * \brief This function is a shortcut for \ref knot_dname_from_str with + * no output buffer parameters. + */ +_mustcheck_ +static inline knot_dname_t *knot_dname_from_str_alloc(const char *name) +{ + return knot_dname_from_str(NULL, name, 0); +} + +/*! + * \brief Convert domain name to lowercase. + * + * \param name Domain name to be converted. + */ +void knot_dname_to_lower(knot_dname_t *name); + +/*! + * \brief Copy lowercased domain name. + * + * \note The output buffer isn't checked if it's big enough! + * + * \param dst Destination buffer. + * \param name Source domain name to be converted. + */ +void knot_dname_copy_lower(knot_dname_t *dst, const knot_dname_t *name); + +/*! + * \brief Returns size of the given domain name. + * + * \note If the domain name is compressed, the length of not compressed part + * is returned. + * + * \param name Domain name to get the size of. + * + * \retval size of the domain name. + * \retval 0 if invalid argument. + */ +_pure_ +size_t knot_dname_size(const knot_dname_t *name); + +/*! + * \brief Returns full size of the given domain name (expanded compression ptrs). + * + * \param name Domain name to get the size of. + * \param pkt Related packet (or NULL if unpacked) + * + * \retval size of the domain name. + * \retval 0 if invalid argument. + */ +_pure_ +size_t knot_dname_realsize(const knot_dname_t *name, const uint8_t *pkt); + +/*! + * \brief Checks if the domain name is a wildcard. + * + * \param name Domain name to check. + * + * \retval true if \a dname is a wildcard domain name. + * \retval false otherwise. + */ +static inline +bool knot_dname_is_wildcard(const knot_dname_t *name) +{ + return name != NULL && name[0] == 1 && name[1] == '*'; +} + +/*! + * \brief Returns the number of labels common for the two domain names (counted + * from the rightmost label. + * + * \param d1 First domain name. + * \param d2 Second domain name. + * + * \return Number of labels common for the two domain names. + */ +_pure_ +size_t knot_dname_matched_labels(const knot_dname_t *d1, const knot_dname_t *d2); + +/*! + * \brief Replaces the suffix of given size in one domain name with other domain + * name. + * + * \param name Domain name where to replace the suffix. + * \param labels Size of the suffix to be replaced. + * \param suffix New suffix to be used as a replacement. + * \param mm Memory context. + * + * \return New domain name created by replacing suffix of \a dname of size + * \a size with \a suffix. + */ +_mustcheck_ +knot_dname_t *knot_dname_replace_suffix(const knot_dname_t *name, unsigned labels, + const knot_dname_t *suffix, knot_mm_t *mm); + +/*! + * \brief Destroys the given domain name. + * + * \param name Domain name to be destroyed. + * \param mm Memory context. + */ +void knot_dname_free(knot_dname_t *name, knot_mm_t *mm); + +/*! + * \brief Compares two domain names by labels (case sensitive). + * + * \param d1 First domain name. + * \param d2 Second domain name. + * + * \retval < 0 if \a d1 goes before \a d2 in canonical order. + * \retval > 0 if \a d1 goes after \a d2 in canonical order. + * \retval 0 if the domain names are identical. + */ +_pure_ +int knot_dname_cmp(const knot_dname_t *d1, const knot_dname_t *d2); + +/*! + * \brief Compares two domain names (case sensitive). + * + * \param d1 First domain name. + * \param d2 Second domain name. + * + * \retval true if the domain names are identical + * \retval false if the domain names are NOT identical + */ +_pure_ +bool knot_dname_is_equal(const knot_dname_t *d1, const knot_dname_t *d2); + +/*! + * \brief Compares two domain names (case insensitive). + * + * \param d1 First domain name. + * \param d2 Second domain name. + * + * \retval true if the domain names are equal + * \retval false if the domain names are NOT equal + */ +_pure_ +bool knot_dname_is_case_equal(const knot_dname_t *d1, const knot_dname_t *d2); + +/*! + * \brief Count length of the N first labels. + * + * \param name Domain name. + * \param nlabels First N labels. + * \param pkt Related packet (or NULL if not compressed). + * + * \return Length of the prefix. + */ +_pure_ +size_t knot_dname_prefixlen(const uint8_t *name, unsigned nlabels, const uint8_t *pkt); + +/*! + * \brief Return number of labels in the domain name. + * + * Terminal nullbyte is not counted. + * + * \param name Domain name. + * \param pkt Related packet (or NULL if not compressed). + * + * \return Number of labels. + */ +_pure_ +size_t knot_dname_labels(const uint8_t *name, const uint8_t *pkt); + +/*! + * \brief Convert domain name from wire to the 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). The first byte of the output + * contains length of the remaining output. + * + * Examples: + * Name: lake.example.com. + * Wire: \\x04lake\\x07example\\x03com\\x00 + * Lookup: \\x11com\\x00example\\x00lake\\x00 + * + * Name: . + * Wire: \\x00 + * Lookup: \\x00 + * + * \param src Source domain name. + * \param storage Memory to store converted name into. Don't use directly! + * + * \retval Lookup format if successful (pointer into the storage). + * \retval NULL on invalid parameters. + */ +uint8_t *knot_dname_lf(const knot_dname_t *src, knot_dname_storage_t storage); + +/*! + * \brief Check whether a domain name is under another one and how deep. + * + * \param name The longer name to check. + * \param bailiwick The shorter name to check. + * + * \retval >=0 a subdomain nested this many labels. + * \retval <0 not a subdomain (KNOT_EOUTOFZONE) or another error (KNOT_EINVAL). + */ +int knot_dname_in_bailiwick(const knot_dname_t *name, const knot_dname_t *bailiwick); + +/*! @} */ |