1933707f3Ssthen /* 2933707f3Ssthen * util/data/dname.h - domain name routines 3933707f3Ssthen * 4933707f3Ssthen * Copyright (c) 2007, NLnet Labs. All rights reserved. 5933707f3Ssthen * 6933707f3Ssthen * This software is open source. 7933707f3Ssthen * 8933707f3Ssthen * Redistribution and use in source and binary forms, with or without 9933707f3Ssthen * modification, are permitted provided that the following conditions 10933707f3Ssthen * are met: 11933707f3Ssthen * 12933707f3Ssthen * Redistributions of source code must retain the above copyright notice, 13933707f3Ssthen * this list of conditions and the following disclaimer. 14933707f3Ssthen * 15933707f3Ssthen * Redistributions in binary form must reproduce the above copyright notice, 16933707f3Ssthen * this list of conditions and the following disclaimer in the documentation 17933707f3Ssthen * and/or other materials provided with the distribution. 18933707f3Ssthen * 19933707f3Ssthen * Neither the name of the NLNET LABS nor the names of its contributors may 20933707f3Ssthen * be used to endorse or promote products derived from this software without 21933707f3Ssthen * specific prior written permission. 22933707f3Ssthen * 23933707f3Ssthen * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 245d76a658Ssthen * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 255d76a658Ssthen * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 265d76a658Ssthen * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 275d76a658Ssthen * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 285d76a658Ssthen * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 295d76a658Ssthen * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 305d76a658Ssthen * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 315d76a658Ssthen * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 325d76a658Ssthen * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 335d76a658Ssthen * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34933707f3Ssthen */ 35933707f3Ssthen 36933707f3Ssthen /** 37933707f3Ssthen * \file 38933707f3Ssthen * 39933707f3Ssthen * This file contains functions to deal with domain names (dnames). 40933707f3Ssthen * 41933707f3Ssthen * Some of the functions deal with domain names as a wireformat buffer, 42933707f3Ssthen * with a length. 43933707f3Ssthen */ 44933707f3Ssthen 45933707f3Ssthen #ifndef UTIL_DATA_DNAME_H 46933707f3Ssthen #define UTIL_DATA_DNAME_H 47933707f3Ssthen #include "util/storage/lruhash.h" 485d76a658Ssthen struct sldns_buffer; 49933707f3Ssthen 50933707f3Ssthen /** max number of compression ptrs to follow */ 51933707f3Ssthen #define MAX_COMPRESS_PTRS 256 52933707f3Ssthen 53933707f3Ssthen /** 54933707f3Ssthen * Determine length of dname in buffer, no compression ptrs allowed, 55933707f3Ssthen * @param query: the ldns buffer, current position at start of dname. 56933707f3Ssthen * at end, position is at end of the dname. 57933707f3Ssthen * @return: 0 on parse failure, or length including ending 0 of dname. 58933707f3Ssthen */ 595d76a658Ssthen size_t query_dname_len(struct sldns_buffer* query); 60933707f3Ssthen 61933707f3Ssthen /** 62933707f3Ssthen * Determine if dname in memory is correct. no compression ptrs allowed. 63933707f3Ssthen * @param dname: where dname starts in memory. 64933707f3Ssthen * @param len: dname is not allowed to exceed this length (i.e. of allocation). 65933707f3Ssthen * @return length of dname if dname is ok, 0 on a parse error. 66933707f3Ssthen */ 67933707f3Ssthen size_t dname_valid(uint8_t* dname, size_t len); 68933707f3Ssthen 69933707f3Ssthen /** lowercase query dname */ 70933707f3Ssthen void query_dname_tolower(uint8_t* dname); 71933707f3Ssthen 72933707f3Ssthen /** 73933707f3Ssthen * lowercase pkt dname (follows compression pointers) 74933707f3Ssthen * @param pkt: the packet, used to follow compression pointers. Position 75933707f3Ssthen * is unchanged. 76933707f3Ssthen * @param dname: start of dname in packet. 77933707f3Ssthen */ 785d76a658Ssthen void pkt_dname_tolower(struct sldns_buffer* pkt, uint8_t* dname); 79933707f3Ssthen 80933707f3Ssthen /** 81933707f3Ssthen * Compare query dnames (uncompressed storage). The Dnames passed do not 82933707f3Ssthen * have to be lowercased, comparison routine does this. 83933707f3Ssthen * 84933707f3Ssthen * This routine is special, in that the comparison that it does corresponds 85933707f3Ssthen * with the canonical comparison needed when comparing dnames inside rdata 86933707f3Ssthen * for RR types that need canonicalization. That means that the first byte 87933707f3Ssthen * that is smaller (possibly after lowercasing) makes an RR smaller, or the 88933707f3Ssthen * shortest name makes an RR smaller. 89933707f3Ssthen * 90933707f3Ssthen * This routine does not compute the canonical order needed for NSEC 91933707f3Ssthen * processing. 92933707f3Ssthen * 93933707f3Ssthen * Dnames have to be valid format. 94933707f3Ssthen * @param d1: dname to compare 95933707f3Ssthen * @param d2: dname to compare 96933707f3Ssthen * @return: -1, 0, or +1 depending on comparison results. 97933707f3Ssthen * Sort order is first difference found. not the canonical ordering. 98933707f3Ssthen */ 99933707f3Ssthen int query_dname_compare(uint8_t* d1, uint8_t* d2); 100933707f3Ssthen 101933707f3Ssthen /** 102933707f3Ssthen * Determine correct, compressed, dname present in packet. 103933707f3Ssthen * Checks for parse errors. 104933707f3Ssthen * @param pkt: packet to read from (from current start position). 105933707f3Ssthen * @return: 0 on parse error. 106933707f3Ssthen * At exit the position is right after the (compressed) dname. 107933707f3Ssthen * Compression pointers are followed and checked for loops. 108933707f3Ssthen * The uncompressed wireformat length is returned. 109933707f3Ssthen */ 1105d76a658Ssthen size_t pkt_dname_len(struct sldns_buffer* pkt); 111933707f3Ssthen 112933707f3Ssthen /** 113933707f3Ssthen * Compare dnames in packet (compressed). Dnames must be valid. 114933707f3Ssthen * routine performs lowercasing, so the packet casing is preserved. 115933707f3Ssthen * @param pkt: packet, used to resolve compression pointers. 116933707f3Ssthen * @param d1: dname to compare 117933707f3Ssthen * @param d2: dname to compare 118933707f3Ssthen * @return: -1, 0, or +1 depending on comparison results. 119933707f3Ssthen * Sort order is first difference found. not the canonical ordering. 120933707f3Ssthen */ 1215d76a658Ssthen int dname_pkt_compare(struct sldns_buffer* pkt, uint8_t* d1, uint8_t* d2); 122933707f3Ssthen 123933707f3Ssthen /** 124933707f3Ssthen * Hash dname, label by label, lowercasing, into hashvalue. 125933707f3Ssthen * Dname in query format (not compressed). 126933707f3Ssthen * @param dname: dname to hash. 127933707f3Ssthen * @param h: initial hash value. 128933707f3Ssthen * @return: result hash value. 129933707f3Ssthen */ 13077079be7Ssthen hashvalue_type dname_query_hash(uint8_t* dname, hashvalue_type h); 131933707f3Ssthen 132933707f3Ssthen /** 133933707f3Ssthen * Hash dname, label by label, lowercasing, into hashvalue. 134933707f3Ssthen * Dname in pkt format (compressed). 135933707f3Ssthen * @param pkt: packet, for resolving compression pointers. 136933707f3Ssthen * @param dname: dname to hash, pointer to the pkt buffer. 137933707f3Ssthen * Must be valid format. No loops, etc. 138933707f3Ssthen * @param h: initial hash value. 139933707f3Ssthen * @return: result hash value. 140933707f3Ssthen * Result is the same as dname_query_hash, even if compression is used. 141933707f3Ssthen */ 14277079be7Ssthen hashvalue_type dname_pkt_hash(struct sldns_buffer* pkt, uint8_t* dname, 14377079be7Ssthen hashvalue_type h); 144933707f3Ssthen 145933707f3Ssthen /** 146933707f3Ssthen * Copy over a valid dname and decompress it. 147933707f3Ssthen * @param pkt: packet to resolve compression pointers. 148933707f3Ssthen * @param to: buffer of size from pkt_len function to hold result. 149933707f3Ssthen * @param dname: pointer into packet where dname starts. 150933707f3Ssthen */ 1515d76a658Ssthen void dname_pkt_copy(struct sldns_buffer* pkt, uint8_t* to, uint8_t* dname); 152933707f3Ssthen 153933707f3Ssthen /** 154933707f3Ssthen * Copy over a valid dname to a packet. 155933707f3Ssthen * @param pkt: packet to copy to. 156933707f3Ssthen * @param dname: dname to copy. 157933707f3Ssthen * @return: 0 if not enough space in buffer. 158933707f3Ssthen */ 1595d76a658Ssthen int dname_buffer_write(struct sldns_buffer* pkt, uint8_t* dname); 160933707f3Ssthen 161933707f3Ssthen /** 162933707f3Ssthen * Count the number of labels in an uncompressed dname in memory. 163933707f3Ssthen * @param dname: pointer to uncompressed dname. 164933707f3Ssthen * @return: count of labels, including root label, "com." has 2 labels. 165933707f3Ssthen */ 166933707f3Ssthen int dname_count_labels(uint8_t* dname); 167933707f3Ssthen 168933707f3Ssthen /** 169933707f3Ssthen * Count labels and dname length both, for uncompressed dname in memory. 170933707f3Ssthen * @param dname: pointer to uncompressed dname. 171933707f3Ssthen * @param size: length of dname, including root label. 172933707f3Ssthen * @return: count of labels, including root label, "com." has 2 labels. 173933707f3Ssthen */ 174933707f3Ssthen int dname_count_size_labels(uint8_t* dname, size_t* size); 175933707f3Ssthen 176933707f3Ssthen /** 177933707f3Ssthen * Compare dnames, sorted not canonical, but by label. 178933707f3Ssthen * Such that zone contents follows zone apex. 179933707f3Ssthen * @param d1: first dname. pointer to uncompressed wireformat. 180933707f3Ssthen * @param labs1: number of labels in first dname. 181933707f3Ssthen * @param d2: second dname. pointer to uncompressed wireformat. 182933707f3Ssthen * @param labs2: number of labels in second dname. 183933707f3Ssthen * @param mlabs: number of labels that matched exactly (the shared topdomain). 184933707f3Ssthen * @return: 0 for equal, -1 smaller, or +1 d1 larger than d2. 185933707f3Ssthen */ 186933707f3Ssthen int dname_lab_cmp(uint8_t* d1, int labs1, uint8_t* d2, int labs2, int* mlabs); 187933707f3Ssthen 188933707f3Ssthen /** 18920237c55Ssthen * Check if labels starts with given prefix 19020237c55Ssthen * @param label: dname label 19120237c55Ssthen * @param prefix: the string to match label with, null terminated. 19220237c55Ssthen * @param endptr: pointer to location in label after prefix, only if return 19320237c55Ssthen * value is 1. NULL if nothing in the label after the prefix, i.e. prefix 19420237c55Ssthen * and label are the same. 19520237c55Ssthen * @return: 1 if label starts with prefix, else 0 19620237c55Ssthen */ 19720237c55Ssthen int dname_lab_startswith(uint8_t* label, char* prefix, char** endptr); 19820237c55Ssthen 19920237c55Ssthen /** 200eaf2578eSsthen * Check if dname contains label 201eaf2578eSsthen * @param dname: dname 202eaf2578eSsthen * @param dnamelen: length of dname 203eaf2578eSsthen * @param label: label to be checked for presence in dname 204eaf2578eSsthen * @return: 1 if dname has this label, 0 otherwise 205eaf2578eSsthen */ 206eaf2578eSsthen int dname_has_label(uint8_t* dname, size_t dnamelen, uint8_t* label); 207eaf2578eSsthen 208eaf2578eSsthen /** 209933707f3Ssthen * See if domain name d1 is a strict subdomain of d2. 210933707f3Ssthen * That is a subdomain, but not equal. 211933707f3Ssthen * @param d1: domain name, uncompressed wireformat 212933707f3Ssthen * @param labs1: number of labels in d1, including root label. 213933707f3Ssthen * @param d2: domain name, uncompressed wireformat 214933707f3Ssthen * @param labs2: number of labels in d2, including root label. 215933707f3Ssthen * @return true if d1 is a subdomain of d2, but not equal to d2. 216933707f3Ssthen */ 217933707f3Ssthen int dname_strict_subdomain(uint8_t* d1, int labs1, uint8_t* d2, int labs2); 218933707f3Ssthen 219933707f3Ssthen /** 220933707f3Ssthen * Like dname_strict_subdomain but counts labels 221933707f3Ssthen * @param d1: domain name, uncompressed wireformat 222933707f3Ssthen * @param d2: domain name, uncompressed wireformat 223933707f3Ssthen * @return true if d1 is a subdomain of d2, but not equal to d2. 224933707f3Ssthen */ 225933707f3Ssthen int dname_strict_subdomain_c(uint8_t* d1, uint8_t* d2); 226933707f3Ssthen 227933707f3Ssthen /** 228*98bc733bSsthen * Counts labels. Tests if d1 is a subdomain of d2. 229933707f3Ssthen * @param d1: domain name, uncompressed wireformat 230933707f3Ssthen * @param d2: domain name, uncompressed wireformat 231933707f3Ssthen * @return true if d1 is a subdomain of d2. 232933707f3Ssthen */ 233933707f3Ssthen int dname_subdomain_c(uint8_t* d1, uint8_t* d2); 234933707f3Ssthen 235933707f3Ssthen /** 236933707f3Ssthen * Debug helper. Print wireformat dname to output. 237933707f3Ssthen * @param out: like stdout or a file. 238933707f3Ssthen * @param pkt: if not NULL, the packet for resolving compression ptrs. 239933707f3Ssthen * @param dname: pointer to (start of) dname. 240933707f3Ssthen */ 2415d76a658Ssthen void dname_print(FILE* out, struct sldns_buffer* pkt, uint8_t* dname); 242933707f3Ssthen 243933707f3Ssthen /** 244933707f3Ssthen * Debug helper. Print dname to given string buffer (string buffer must 245933707f3Ssthen * be at least 255 chars + 1 for the 0, in printable form. 246933707f3Ssthen * This may lose information (? for nonprintable characters, or & if 247933707f3Ssthen * the name is too long, # for a bad label length). 248933707f3Ssthen * @param dname: uncompressed wireformat. 249933707f3Ssthen * @param str: buffer of 255+1 length. 250933707f3Ssthen */ 251933707f3Ssthen void dname_str(uint8_t* dname, char* str); 252933707f3Ssthen 253933707f3Ssthen /** 254933707f3Ssthen * Returns true if the uncompressed wireformat dname is the root "." 255933707f3Ssthen * @param dname: the dname to check 256933707f3Ssthen * @return true if ".", false if not. 257933707f3Ssthen */ 258933707f3Ssthen int dname_is_root(uint8_t* dname); 259933707f3Ssthen 260933707f3Ssthen /** 261933707f3Ssthen * Snip off first label from a dname, returning the parent zone. 262933707f3Ssthen * @param dname: from what to strip off. uncompressed wireformat. 263933707f3Ssthen * @param len: length, adjusted to become less. 264191f22c6Ssthen * return stripped off, or "." if input was ".". 265933707f3Ssthen */ 266933707f3Ssthen void dname_remove_label(uint8_t** dname, size_t* len); 267933707f3Ssthen 268933707f3Ssthen /** 269933707f3Ssthen * Snip off first N labels from a dname, returning the parent zone. 270933707f3Ssthen * @param dname: from what to strip off. uncompressed wireformat. 271933707f3Ssthen * @param len: length, adjusted to become less. 272933707f3Ssthen * @param n: number of labels to strip off (from the left). 273933707f3Ssthen * if 0, nothing happens. 274191f22c6Ssthen * return stripped off, or "." if input was ".". 275933707f3Ssthen */ 276933707f3Ssthen void dname_remove_labels(uint8_t** dname, size_t* len, int n); 277933707f3Ssthen 278933707f3Ssthen /** 279933707f3Ssthen * Count labels for the RRSIG signature label field. 280933707f3Ssthen * Like a normal labelcount, but "*" wildcard and "." root are not counted. 281933707f3Ssthen * @param dname: valid uncompressed wireformat. 282933707f3Ssthen * @return number of labels like in RRSIG; '*' and '.' are not counted. 283933707f3Ssthen */ 284933707f3Ssthen int dname_signame_label_count(uint8_t* dname); 285933707f3Ssthen 286933707f3Ssthen /** 287933707f3Ssthen * Return true if the label is a wildcard, *.example.com. 288933707f3Ssthen * @param dname: valid uncompressed wireformat. 289933707f3Ssthen * @return true if wildcard, or false. 290933707f3Ssthen */ 291933707f3Ssthen int dname_is_wild(uint8_t* dname); 292933707f3Ssthen 293933707f3Ssthen /** 294933707f3Ssthen * Compare dnames, Canonical in rfc4034 sense, but by label. 295933707f3Ssthen * Such that zone contents follows zone apex. 296933707f3Ssthen * 297933707f3Ssthen * @param d1: first dname. pointer to uncompressed wireformat. 298933707f3Ssthen * @param labs1: number of labels in first dname. 299933707f3Ssthen * @param d2: second dname. pointer to uncompressed wireformat. 300933707f3Ssthen * @param labs2: number of labels in second dname. 301933707f3Ssthen * @param mlabs: number of labels that matched exactly (the shared topdomain). 302933707f3Ssthen * @return: 0 for equal, -1 smaller, or +1 d1 larger than d2. 303933707f3Ssthen */ 304933707f3Ssthen int dname_canon_lab_cmp(uint8_t* d1, int labs1, uint8_t* d2, int labs2, 305933707f3Ssthen int* mlabs); 306933707f3Ssthen 307933707f3Ssthen /** 308933707f3Ssthen * Canonical dname compare. Takes care of counting labels. 309933707f3Ssthen * Per rfc 4034 canonical order. 310933707f3Ssthen * 311933707f3Ssthen * @param d1: first dname. pointer to uncompressed wireformat. 312933707f3Ssthen * @param d2: second dname. pointer to uncompressed wireformat. 313933707f3Ssthen * @return: 0 for equal, -1 smaller, or +1 d1 larger than d2. 314933707f3Ssthen */ 315933707f3Ssthen int dname_canonical_compare(uint8_t* d1, uint8_t* d2); 316933707f3Ssthen 317933707f3Ssthen /** 318933707f3Ssthen * Get the shared topdomain between two names. Root "." or longer. 319933707f3Ssthen * @param d1: first dname. pointer to uncompressed wireformat. 320933707f3Ssthen * @param d2: second dname. pointer to uncompressed wireformat. 321933707f3Ssthen * @return pointer to shared topdomain. Ptr to a part of d1. 322933707f3Ssthen */ 323933707f3Ssthen uint8_t* dname_get_shared_topdomain(uint8_t* d1, uint8_t* d2); 324933707f3Ssthen 325933707f3Ssthen #endif /* UTIL_DATA_DNAME_H */ 326