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