xref: /openbsd-src/usr.sbin/unbound/util/data/dname.h (revision 98bc733b08604094f4138174a0ee0bb9faaca4bd)
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