xref: /openbsd/sbin/unwind/libunbound/util/data/dname.h (revision 7037e34c)
1ae8c6e27Sflorian /*
2ae8c6e27Sflorian  * util/data/dname.h - domain name routines
3ae8c6e27Sflorian  *
4ae8c6e27Sflorian  * Copyright (c) 2007, NLnet Labs. All rights reserved.
5ae8c6e27Sflorian  *
6ae8c6e27Sflorian  * This software is open source.
7ae8c6e27Sflorian  *
8ae8c6e27Sflorian  * Redistribution and use in source and binary forms, with or without
9ae8c6e27Sflorian  * modification, are permitted provided that the following conditions
10ae8c6e27Sflorian  * are met:
11ae8c6e27Sflorian  *
12ae8c6e27Sflorian  * Redistributions of source code must retain the above copyright notice,
13ae8c6e27Sflorian  * this list of conditions and the following disclaimer.
14ae8c6e27Sflorian  *
15ae8c6e27Sflorian  * Redistributions in binary form must reproduce the above copyright notice,
16ae8c6e27Sflorian  * this list of conditions and the following disclaimer in the documentation
17ae8c6e27Sflorian  * and/or other materials provided with the distribution.
18ae8c6e27Sflorian  *
19ae8c6e27Sflorian  * Neither the name of the NLNET LABS nor the names of its contributors may
20ae8c6e27Sflorian  * be used to endorse or promote products derived from this software without
21ae8c6e27Sflorian  * specific prior written permission.
22ae8c6e27Sflorian  *
23ae8c6e27Sflorian  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24ae8c6e27Sflorian  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25ae8c6e27Sflorian  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26ae8c6e27Sflorian  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27ae8c6e27Sflorian  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28ae8c6e27Sflorian  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29ae8c6e27Sflorian  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30ae8c6e27Sflorian  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31ae8c6e27Sflorian  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32ae8c6e27Sflorian  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33ae8c6e27Sflorian  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34ae8c6e27Sflorian  */
35ae8c6e27Sflorian 
36ae8c6e27Sflorian /**
37ae8c6e27Sflorian  * \file
38ae8c6e27Sflorian  *
39ae8c6e27Sflorian  * This file contains functions to deal with domain names (dnames).
40ae8c6e27Sflorian  *
41ae8c6e27Sflorian  * Some of the functions deal with domain names as a wireformat buffer,
42ae8c6e27Sflorian  * with a length.
43ae8c6e27Sflorian  */
44ae8c6e27Sflorian 
45ae8c6e27Sflorian #ifndef UTIL_DATA_DNAME_H
46ae8c6e27Sflorian #define UTIL_DATA_DNAME_H
47ae8c6e27Sflorian #include "util/storage/lruhash.h"
48ae8c6e27Sflorian struct sldns_buffer;
49ae8c6e27Sflorian 
50ae8c6e27Sflorian /** max number of compression ptrs to follow */
51ae8c6e27Sflorian #define MAX_COMPRESS_PTRS 256
52ae8c6e27Sflorian 
53ae8c6e27Sflorian /**
54ae8c6e27Sflorian  * Determine length of dname in buffer, no compression ptrs allowed,
55ae8c6e27Sflorian  * @param query: the ldns buffer, current position at start of dname.
56ae8c6e27Sflorian  *	at end, position is at end of the dname.
57ae8c6e27Sflorian  * @return: 0 on parse failure, or length including ending 0 of dname.
58ae8c6e27Sflorian  */
59ae8c6e27Sflorian size_t query_dname_len(struct sldns_buffer* query);
60ae8c6e27Sflorian 
61ae8c6e27Sflorian /**
62ae8c6e27Sflorian  * Determine if dname in memory is correct. no compression ptrs allowed.
63ae8c6e27Sflorian  * @param dname: where dname starts in memory.
64ae8c6e27Sflorian  * @param len: dname is not allowed to exceed this length (i.e. of allocation).
65ae8c6e27Sflorian  * @return length of dname if dname is ok, 0 on a parse error.
66ae8c6e27Sflorian  */
67ae8c6e27Sflorian size_t dname_valid(uint8_t* dname, size_t len);
68ae8c6e27Sflorian 
69ae8c6e27Sflorian /** lowercase query dname */
70ae8c6e27Sflorian void query_dname_tolower(uint8_t* dname);
71ae8c6e27Sflorian 
72ae8c6e27Sflorian /**
73ae8c6e27Sflorian  * lowercase pkt dname (follows compression pointers)
74ae8c6e27Sflorian  * @param pkt: the packet, used to follow compression pointers. Position
75ae8c6e27Sflorian  *	is unchanged.
76ae8c6e27Sflorian  * @param dname: start of dname in packet.
77ae8c6e27Sflorian  */
78ae8c6e27Sflorian void pkt_dname_tolower(struct sldns_buffer* pkt, uint8_t* dname);
79ae8c6e27Sflorian 
80ae8c6e27Sflorian /**
81ae8c6e27Sflorian  * Compare query dnames (uncompressed storage). The Dnames passed do not
82ae8c6e27Sflorian  * have to be lowercased, comparison routine does this.
83ae8c6e27Sflorian  *
84ae8c6e27Sflorian  * This routine is special, in that the comparison that it does corresponds
85ae8c6e27Sflorian  * with the canonical comparison needed when comparing dnames inside rdata
86ae8c6e27Sflorian  * for RR types that need canonicalization. That means that the first byte
87ae8c6e27Sflorian  * that is smaller (possibly after lowercasing) makes an RR smaller, or the
88ae8c6e27Sflorian  * shortest name makes an RR smaller.
89ae8c6e27Sflorian  *
90ae8c6e27Sflorian  * This routine does not compute the canonical order needed for NSEC
91ae8c6e27Sflorian  * processing.
92ae8c6e27Sflorian  *
93ae8c6e27Sflorian  * Dnames have to be valid format.
94ae8c6e27Sflorian  * @param d1: dname to compare
95ae8c6e27Sflorian  * @param d2: dname to compare
96ae8c6e27Sflorian  * @return: -1, 0, or +1 depending on comparison results.
97ae8c6e27Sflorian  * 	Sort order is first difference found. not the canonical ordering.
98ae8c6e27Sflorian  */
99ae8c6e27Sflorian int query_dname_compare(uint8_t* d1, uint8_t* d2);
100ae8c6e27Sflorian 
101ae8c6e27Sflorian /**
102ae8c6e27Sflorian  * Determine correct, compressed, dname present in packet.
103ae8c6e27Sflorian  * Checks for parse errors.
104ae8c6e27Sflorian  * @param pkt: packet to read from (from current start position).
105ae8c6e27Sflorian  * @return: 0 on parse error.
106ae8c6e27Sflorian  *	At exit the position is right after the (compressed) dname.
107ae8c6e27Sflorian  *	Compression pointers are followed and checked for loops.
108ae8c6e27Sflorian  *	The uncompressed wireformat length is returned.
109ae8c6e27Sflorian  */
110ae8c6e27Sflorian size_t pkt_dname_len(struct sldns_buffer* pkt);
111ae8c6e27Sflorian 
112ae8c6e27Sflorian /**
113ae8c6e27Sflorian  * Compare dnames in packet (compressed). Dnames must be valid.
114ae8c6e27Sflorian  * routine performs lowercasing, so the packet casing is preserved.
115ae8c6e27Sflorian  * @param pkt: packet, used to resolve compression pointers.
116ae8c6e27Sflorian  * @param d1: dname to compare
117ae8c6e27Sflorian  * @param d2: dname to compare
118ae8c6e27Sflorian  * @return: -1, 0, or +1 depending on comparison results.
119ae8c6e27Sflorian  * 	Sort order is first difference found. not the canonical ordering.
120ae8c6e27Sflorian  */
121ae8c6e27Sflorian int dname_pkt_compare(struct sldns_buffer* pkt, uint8_t* d1, uint8_t* d2);
122ae8c6e27Sflorian 
123ae8c6e27Sflorian /**
124ae8c6e27Sflorian  * Hash dname, label by label, lowercasing, into hashvalue.
125ae8c6e27Sflorian  * Dname in query format (not compressed).
126ae8c6e27Sflorian  * @param dname: dname to hash.
127ae8c6e27Sflorian  * @param h: initial hash value.
128ae8c6e27Sflorian  * @return: result hash value.
129ae8c6e27Sflorian  */
130ae8c6e27Sflorian hashvalue_type dname_query_hash(uint8_t* dname, hashvalue_type h);
131ae8c6e27Sflorian 
132ae8c6e27Sflorian /**
133ae8c6e27Sflorian  * Hash dname, label by label, lowercasing, into hashvalue.
134ae8c6e27Sflorian  * Dname in pkt format (compressed).
135ae8c6e27Sflorian  * @param pkt: packet, for resolving compression pointers.
136ae8c6e27Sflorian  * @param dname: dname to hash, pointer to the pkt buffer.
137ae8c6e27Sflorian  * 	Must be valid format. No loops, etc.
138ae8c6e27Sflorian  * @param h: initial hash value.
139ae8c6e27Sflorian  * @return: result hash value.
140ae8c6e27Sflorian  * 	Result is the same as dname_query_hash, even if compression is used.
141ae8c6e27Sflorian  */
142ae8c6e27Sflorian hashvalue_type dname_pkt_hash(struct sldns_buffer* pkt, uint8_t* dname,
143ae8c6e27Sflorian 	hashvalue_type h);
144ae8c6e27Sflorian 
145ae8c6e27Sflorian /**
146ae8c6e27Sflorian  * Copy over a valid dname and decompress it.
147ae8c6e27Sflorian  * @param pkt: packet to resolve compression pointers.
148ae8c6e27Sflorian  * @param to: buffer of size from pkt_len function to hold result.
149ae8c6e27Sflorian  * @param dname: pointer into packet where dname starts.
150ae8c6e27Sflorian  */
151ae8c6e27Sflorian void dname_pkt_copy(struct sldns_buffer* pkt, uint8_t* to, uint8_t* dname);
152ae8c6e27Sflorian 
153ae8c6e27Sflorian /**
154ae8c6e27Sflorian  * Copy over a valid dname to a packet.
155ae8c6e27Sflorian  * @param pkt: packet to copy to.
156ae8c6e27Sflorian  * @param dname: dname to copy.
157ae8c6e27Sflorian  * @return: 0 if not enough space in buffer.
158ae8c6e27Sflorian  */
159ae8c6e27Sflorian int dname_buffer_write(struct sldns_buffer* pkt, uint8_t* dname);
160ae8c6e27Sflorian 
161ae8c6e27Sflorian /**
162ae8c6e27Sflorian  * Count the number of labels in an uncompressed dname in memory.
163ae8c6e27Sflorian  * @param dname: pointer to uncompressed dname.
164ae8c6e27Sflorian  * @return: count of labels, including root label, "com." has 2 labels.
165ae8c6e27Sflorian  */
166ae8c6e27Sflorian int dname_count_labels(uint8_t* dname);
167ae8c6e27Sflorian 
168ae8c6e27Sflorian /**
169ae8c6e27Sflorian  * Count labels and dname length both, for uncompressed dname in memory.
170ae8c6e27Sflorian  * @param dname: pointer to uncompressed dname.
171ae8c6e27Sflorian  * @param size: length of dname, including root label.
172ae8c6e27Sflorian  * @return: count of labels, including root label, "com." has 2 labels.
173ae8c6e27Sflorian  */
174ae8c6e27Sflorian int dname_count_size_labels(uint8_t* dname, size_t* size);
175ae8c6e27Sflorian 
176ae8c6e27Sflorian /**
177ae8c6e27Sflorian  * Compare dnames, sorted not canonical, but by label.
178ae8c6e27Sflorian  * Such that zone contents follows zone apex.
179ae8c6e27Sflorian  * @param d1: first dname. pointer to uncompressed wireformat.
180ae8c6e27Sflorian  * @param labs1: number of labels in first dname.
181ae8c6e27Sflorian  * @param d2: second dname. pointer to uncompressed wireformat.
182ae8c6e27Sflorian  * @param labs2: number of labels in second dname.
183ae8c6e27Sflorian  * @param mlabs: number of labels that matched exactly (the shared topdomain).
184ae8c6e27Sflorian  * @return: 0 for equal, -1 smaller, or +1 d1 larger than d2.
185ae8c6e27Sflorian  */
186ae8c6e27Sflorian int dname_lab_cmp(uint8_t* d1, int labs1, uint8_t* d2, int labs2, int* mlabs);
187ae8c6e27Sflorian 
188ae8c6e27Sflorian /**
189ae8c6e27Sflorian  * Check if labels starts with given prefix
190ae8c6e27Sflorian  * @param label: dname label
191ae8c6e27Sflorian  * @param prefix: the string to match label with, null terminated.
192ae8c6e27Sflorian  * @param endptr: pointer to location in label after prefix, only if return
193ae8c6e27Sflorian  * 	value is 1. NULL if nothing in the label after the prefix, i.e. prefix
194ae8c6e27Sflorian  * 	and label are the same.
195ae8c6e27Sflorian  * @return: 1 if label starts with prefix, else 0
196ae8c6e27Sflorian  */
197ae8c6e27Sflorian int dname_lab_startswith(uint8_t* label, char* prefix, char** endptr);
198ae8c6e27Sflorian 
199ae8c6e27Sflorian /**
200d32eb43cSflorian  * Check if dname contains label
201d32eb43cSflorian  * @param dname: dname
202d32eb43cSflorian  * @param dnamelen: length of dname
203d32eb43cSflorian  * @param label: label to be checked for presence in dname
204d32eb43cSflorian  * @return: 1 if dname has this label, 0 otherwise
205d32eb43cSflorian  */
206d32eb43cSflorian int dname_has_label(uint8_t* dname, size_t dnamelen, uint8_t* label);
207d32eb43cSflorian 
208d32eb43cSflorian /**
209ae8c6e27Sflorian  * See if domain name d1 is a strict subdomain of d2.
210ae8c6e27Sflorian  * That is a subdomain, but not equal.
211ae8c6e27Sflorian  * @param d1: domain name, uncompressed wireformat
212ae8c6e27Sflorian  * @param labs1: number of labels in d1, including root label.
213ae8c6e27Sflorian  * @param d2: domain name, uncompressed wireformat
214ae8c6e27Sflorian  * @param labs2: number of labels in d2, including root label.
215ae8c6e27Sflorian  * @return true if d1 is a subdomain of d2, but not equal to d2.
216ae8c6e27Sflorian  */
217ae8c6e27Sflorian int dname_strict_subdomain(uint8_t* d1, int labs1, uint8_t* d2, int labs2);
218ae8c6e27Sflorian 
219ae8c6e27Sflorian /**
220ae8c6e27Sflorian  * Like dname_strict_subdomain but counts labels
221ae8c6e27Sflorian  * @param d1: domain name, uncompressed wireformat
222ae8c6e27Sflorian  * @param d2: domain name, uncompressed wireformat
223ae8c6e27Sflorian  * @return true if d1 is a subdomain of d2, but not equal to d2.
224ae8c6e27Sflorian  */
225ae8c6e27Sflorian int dname_strict_subdomain_c(uint8_t* d1, uint8_t* d2);
226ae8c6e27Sflorian 
227ae8c6e27Sflorian /**
228*7037e34cSflorian  * Counts labels. Tests if d1 is a subdomain of d2.
229ae8c6e27Sflorian  * @param d1: domain name, uncompressed wireformat
230ae8c6e27Sflorian  * @param d2: domain name, uncompressed wireformat
231ae8c6e27Sflorian  * @return true if d1 is a subdomain of d2.
232ae8c6e27Sflorian  */
233ae8c6e27Sflorian int dname_subdomain_c(uint8_t* d1, uint8_t* d2);
234ae8c6e27Sflorian 
235ae8c6e27Sflorian /**
236ae8c6e27Sflorian  * Debug helper. Print wireformat dname to output.
237ae8c6e27Sflorian  * @param out: like stdout or a file.
238ae8c6e27Sflorian  * @param pkt: if not NULL, the packet for resolving compression ptrs.
239ae8c6e27Sflorian  * @param dname: pointer to (start of) dname.
240ae8c6e27Sflorian  */
241ae8c6e27Sflorian void dname_print(FILE* out, struct sldns_buffer* pkt, uint8_t* dname);
242ae8c6e27Sflorian 
243ae8c6e27Sflorian /**
244ae8c6e27Sflorian  * Debug helper. Print dname to given string buffer (string buffer must
245ae8c6e27Sflorian  * be at least 255 chars + 1 for the 0, in printable form.
246ae8c6e27Sflorian  * This may lose information (? for nonprintable characters, or & if
247ae8c6e27Sflorian  * the name is too long, # for a bad label length).
248ae8c6e27Sflorian  * @param dname: uncompressed wireformat.
249ae8c6e27Sflorian  * @param str: buffer of 255+1 length.
250ae8c6e27Sflorian  */
251ae8c6e27Sflorian void dname_str(uint8_t* dname, char* str);
252ae8c6e27Sflorian 
253ae8c6e27Sflorian /**
254ae8c6e27Sflorian  * Returns true if the uncompressed wireformat dname is the root "."
255ae8c6e27Sflorian  * @param dname: the dname to check
256ae8c6e27Sflorian  * @return true if ".", false if not.
257ae8c6e27Sflorian  */
258ae8c6e27Sflorian int dname_is_root(uint8_t* dname);
259ae8c6e27Sflorian 
260ae8c6e27Sflorian /**
261ae8c6e27Sflorian  * Snip off first label from a dname, returning the parent zone.
262ae8c6e27Sflorian  * @param dname: from what to strip off. uncompressed wireformat.
263ae8c6e27Sflorian  * @param len: length, adjusted to become less.
264411c5950Sflorian  * return stripped off, or "." if input was ".".
265ae8c6e27Sflorian  */
266ae8c6e27Sflorian void dname_remove_label(uint8_t** dname, size_t* len);
267ae8c6e27Sflorian 
268ae8c6e27Sflorian /**
269ae8c6e27Sflorian  * Snip off first N labels from a dname, returning the parent zone.
270ae8c6e27Sflorian  * @param dname: from what to strip off. uncompressed wireformat.
271ae8c6e27Sflorian  * @param len: length, adjusted to become less.
272ae8c6e27Sflorian  * @param n: number of labels to strip off (from the left).
273ae8c6e27Sflorian  * 	if 0, nothing happens.
274411c5950Sflorian  * return stripped off, or "." if input was ".".
275ae8c6e27Sflorian  */
276ae8c6e27Sflorian void dname_remove_labels(uint8_t** dname, size_t* len, int n);
277ae8c6e27Sflorian 
278ae8c6e27Sflorian /**
279ae8c6e27Sflorian  * Count labels for the RRSIG signature label field.
280ae8c6e27Sflorian  * Like a normal labelcount, but "*" wildcard and "." root are not counted.
281ae8c6e27Sflorian  * @param dname: valid uncompressed wireformat.
282ae8c6e27Sflorian  * @return number of labels like in RRSIG; '*' and '.' are not counted.
283ae8c6e27Sflorian  */
284ae8c6e27Sflorian int dname_signame_label_count(uint8_t* dname);
285ae8c6e27Sflorian 
286ae8c6e27Sflorian /**
287ae8c6e27Sflorian  * Return true if the label is a wildcard, *.example.com.
288ae8c6e27Sflorian  * @param dname: valid uncompressed wireformat.
289ae8c6e27Sflorian  * @return true if wildcard, or false.
290ae8c6e27Sflorian  */
291ae8c6e27Sflorian int dname_is_wild(uint8_t* dname);
292ae8c6e27Sflorian 
293ae8c6e27Sflorian /**
294ae8c6e27Sflorian  * Compare dnames, Canonical in rfc4034 sense, but by label.
295ae8c6e27Sflorian  * Such that zone contents follows zone apex.
296ae8c6e27Sflorian  *
297ae8c6e27Sflorian  * @param d1: first dname. pointer to uncompressed wireformat.
298ae8c6e27Sflorian  * @param labs1: number of labels in first dname.
299ae8c6e27Sflorian  * @param d2: second dname. pointer to uncompressed wireformat.
300ae8c6e27Sflorian  * @param labs2: number of labels in second dname.
301ae8c6e27Sflorian  * @param mlabs: number of labels that matched exactly (the shared topdomain).
302ae8c6e27Sflorian  * @return: 0 for equal, -1 smaller, or +1 d1 larger than d2.
303ae8c6e27Sflorian  */
304ae8c6e27Sflorian int dname_canon_lab_cmp(uint8_t* d1, int labs1, uint8_t* d2, int labs2,
305ae8c6e27Sflorian 	int* mlabs);
306ae8c6e27Sflorian 
307ae8c6e27Sflorian /**
308ae8c6e27Sflorian  * Canonical dname compare. Takes care of counting labels.
309ae8c6e27Sflorian  * Per rfc 4034 canonical order.
310ae8c6e27Sflorian  *
311ae8c6e27Sflorian  * @param d1: first dname. pointer to uncompressed wireformat.
312ae8c6e27Sflorian  * @param d2: second dname. pointer to uncompressed wireformat.
313ae8c6e27Sflorian  * @return: 0 for equal, -1 smaller, or +1 d1 larger than d2.
314ae8c6e27Sflorian  */
315ae8c6e27Sflorian int dname_canonical_compare(uint8_t* d1, uint8_t* d2);
316ae8c6e27Sflorian 
317ae8c6e27Sflorian /**
318ae8c6e27Sflorian  * Get the shared topdomain between two names. Root "." or longer.
319ae8c6e27Sflorian  * @param d1: first dname. pointer to uncompressed wireformat.
320ae8c6e27Sflorian  * @param d2: second dname. pointer to uncompressed wireformat.
321ae8c6e27Sflorian  * @return pointer to shared topdomain. Ptr to a part of d1.
322ae8c6e27Sflorian  */
323ae8c6e27Sflorian uint8_t* dname_get_shared_topdomain(uint8_t* d1, uint8_t* d2);
324ae8c6e27Sflorian 
325ae8c6e27Sflorian #endif /* UTIL_DATA_DNAME_H */
326