1238106Sdes/*
2238106Sdes * util/data/dname.h - domain name routines
3238106Sdes *
4238106Sdes * Copyright (c) 2007, NLnet Labs. All rights reserved.
5238106Sdes *
6238106Sdes * This software is open source.
7238106Sdes *
8238106Sdes * Redistribution and use in source and binary forms, with or without
9238106Sdes * modification, are permitted provided that the following conditions
10238106Sdes * are met:
11238106Sdes *
12238106Sdes * Redistributions of source code must retain the above copyright notice,
13238106Sdes * this list of conditions and the following disclaimer.
14238106Sdes *
15238106Sdes * Redistributions in binary form must reproduce the above copyright notice,
16238106Sdes * this list of conditions and the following disclaimer in the documentation
17238106Sdes * and/or other materials provided with the distribution.
18238106Sdes *
19238106Sdes * Neither the name of the NLNET LABS nor the names of its contributors may
20238106Sdes * be used to endorse or promote products derived from this software without
21238106Sdes * specific prior written permission.
22238106Sdes *
23238106Sdes * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24269257Sdes * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25269257Sdes * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26269257Sdes * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27269257Sdes * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28269257Sdes * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29269257Sdes * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30269257Sdes * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31269257Sdes * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32269257Sdes * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33269257Sdes * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34238106Sdes */
35238106Sdes
36238106Sdes/**
37238106Sdes * \file
38238106Sdes *
39238106Sdes * This file contains functions to deal with domain names (dnames).
40238106Sdes *
41238106Sdes * Some of the functions deal with domain names as a wireformat buffer,
42238106Sdes * with a length.
43238106Sdes */
44238106Sdes
45238106Sdes#ifndef UTIL_DATA_DNAME_H
46238106Sdes#define UTIL_DATA_DNAME_H
47238106Sdes#include "util/storage/lruhash.h"
48269257Sdesstruct sldns_buffer;
49238106Sdes
50238106Sdes/** max number of compression ptrs to follow */
51238106Sdes#define MAX_COMPRESS_PTRS 256
52238106Sdes
53238106Sdes/**
54238106Sdes * Determine length of dname in buffer, no compression ptrs allowed,
55238106Sdes * @param query: the ldns buffer, current position at start of dname.
56238106Sdes *	at end, position is at end of the dname.
57238106Sdes * @return: 0 on parse failure, or length including ending 0 of dname.
58238106Sdes */
59269257Sdessize_t query_dname_len(struct sldns_buffer* query);
60238106Sdes
61238106Sdes/**
62238106Sdes * Determine if dname in memory is correct. no compression ptrs allowed.
63238106Sdes * @param dname: where dname starts in memory.
64238106Sdes * @param len: dname is not allowed to exceed this length (i.e. of allocation).
65238106Sdes * @return length of dname if dname is ok, 0 on a parse error.
66238106Sdes */
67238106Sdessize_t dname_valid(uint8_t* dname, size_t len);
68238106Sdes
69238106Sdes/** lowercase query dname */
70238106Sdesvoid query_dname_tolower(uint8_t* dname);
71238106Sdes
72238106Sdes/**
73238106Sdes * lowercase pkt dname (follows compression pointers)
74238106Sdes * @param pkt: the packet, used to follow compression pointers. Position
75238106Sdes *	is unchanged.
76238106Sdes * @param dname: start of dname in packet.
77238106Sdes */
78269257Sdesvoid pkt_dname_tolower(struct sldns_buffer* pkt, uint8_t* dname);
79238106Sdes
80238106Sdes/**
81238106Sdes * Compare query dnames (uncompressed storage). The Dnames passed do not
82238106Sdes * have to be lowercased, comparison routine does this.
83238106Sdes *
84238106Sdes * This routine is special, in that the comparison that it does corresponds
85238106Sdes * with the canonical comparison needed when comparing dnames inside rdata
86238106Sdes * for RR types that need canonicalization. That means that the first byte
87238106Sdes * that is smaller (possibly after lowercasing) makes an RR smaller, or the
88238106Sdes * shortest name makes an RR smaller.
89238106Sdes *
90238106Sdes * This routine does not compute the canonical order needed for NSEC
91238106Sdes * processing.
92238106Sdes *
93238106Sdes * Dnames have to be valid format.
94238106Sdes * @param d1: dname to compare
95238106Sdes * @param d2: dname to compare
96238106Sdes * @return: -1, 0, or +1 depending on comparison results.
97238106Sdes * 	Sort order is first difference found. not the canonical ordering.
98238106Sdes */
99238106Sdesint query_dname_compare(uint8_t* d1, uint8_t* d2);
100238106Sdes
101238106Sdes/**
102238106Sdes * Determine correct, compressed, dname present in packet.
103238106Sdes * Checks for parse errors.
104238106Sdes * @param pkt: packet to read from (from current start position).
105238106Sdes * @return: 0 on parse error.
106238106Sdes *	At exit the position is right after the (compressed) dname.
107238106Sdes *	Compression pointers are followed and checked for loops.
108238106Sdes *	The uncompressed wireformat length is returned.
109238106Sdes */
110269257Sdessize_t pkt_dname_len(struct sldns_buffer* pkt);
111238106Sdes
112238106Sdes/**
113238106Sdes * Compare dnames in packet (compressed). Dnames must be valid.
114238106Sdes * routine performs lowercasing, so the packet casing is preserved.
115238106Sdes * @param pkt: packet, used to resolve compression pointers.
116238106Sdes * @param d1: dname to compare
117238106Sdes * @param d2: dname to compare
118238106Sdes * @return: -1, 0, or +1 depending on comparison results.
119238106Sdes * 	Sort order is first difference found. not the canonical ordering.
120238106Sdes */
121269257Sdesint dname_pkt_compare(struct sldns_buffer* pkt, uint8_t* d1, uint8_t* d2);
122238106Sdes
123238106Sdes/**
124238106Sdes * Hash dname, label by label, lowercasing, into hashvalue.
125238106Sdes * Dname in query format (not compressed).
126238106Sdes * @param dname: dname to hash.
127238106Sdes * @param h: initial hash value.
128238106Sdes * @return: result hash value.
129238106Sdes */
130238106Sdeshashvalue_t dname_query_hash(uint8_t* dname, hashvalue_t h);
131238106Sdes
132238106Sdes/**
133238106Sdes * Hash dname, label by label, lowercasing, into hashvalue.
134238106Sdes * Dname in pkt format (compressed).
135238106Sdes * @param pkt: packet, for resolving compression pointers.
136238106Sdes * @param dname: dname to hash, pointer to the pkt buffer.
137238106Sdes * 	Must be valid format. No loops, etc.
138238106Sdes * @param h: initial hash value.
139238106Sdes * @return: result hash value.
140238106Sdes * 	Result is the same as dname_query_hash, even if compression is used.
141238106Sdes */
142269257Sdeshashvalue_t dname_pkt_hash(struct sldns_buffer* pkt, uint8_t* dname, hashvalue_t h);
143238106Sdes
144238106Sdes/**
145238106Sdes * Copy over a valid dname and decompress it.
146238106Sdes * @param pkt: packet to resolve compression pointers.
147238106Sdes * @param to: buffer of size from pkt_len function to hold result.
148238106Sdes * @param dname: pointer into packet where dname starts.
149238106Sdes */
150269257Sdesvoid dname_pkt_copy(struct sldns_buffer* pkt, uint8_t* to, uint8_t* dname);
151238106Sdes
152238106Sdes/**
153238106Sdes * Copy over a valid dname to a packet.
154238106Sdes * @param pkt: packet to copy to.
155238106Sdes * @param dname: dname to copy.
156238106Sdes * @return: 0 if not enough space in buffer.
157238106Sdes */
158269257Sdesint dname_buffer_write(struct sldns_buffer* pkt, uint8_t* dname);
159238106Sdes
160238106Sdes/**
161238106Sdes * Count the number of labels in an uncompressed dname in memory.
162238106Sdes * @param dname: pointer to uncompressed dname.
163238106Sdes * @return: count of labels, including root label, "com." has 2 labels.
164238106Sdes */
165238106Sdesint dname_count_labels(uint8_t* dname);
166238106Sdes
167238106Sdes/**
168238106Sdes * Count labels and dname length both, for uncompressed dname in memory.
169238106Sdes * @param dname: pointer to uncompressed dname.
170238106Sdes * @param size: length of dname, including root label.
171238106Sdes * @return: count of labels, including root label, "com." has 2 labels.
172238106Sdes */
173238106Sdesint dname_count_size_labels(uint8_t* dname, size_t* size);
174238106Sdes
175238106Sdes/**
176238106Sdes * Compare dnames, sorted not canonical, but by label.
177238106Sdes * Such that zone contents follows zone apex.
178238106Sdes * @param d1: first dname. pointer to uncompressed wireformat.
179238106Sdes * @param labs1: number of labels in first dname.
180238106Sdes * @param d2: second dname. pointer to uncompressed wireformat.
181238106Sdes * @param labs2: number of labels in second dname.
182238106Sdes * @param mlabs: number of labels that matched exactly (the shared topdomain).
183238106Sdes * @return: 0 for equal, -1 smaller, or +1 d1 larger than d2.
184238106Sdes */
185238106Sdesint dname_lab_cmp(uint8_t* d1, int labs1, uint8_t* d2, int labs2, int* mlabs);
186238106Sdes
187238106Sdes/**
188238106Sdes * See if domain name d1 is a strict subdomain of d2.
189238106Sdes * That is a subdomain, but not equal.
190238106Sdes * @param d1: domain name, uncompressed wireformat
191238106Sdes * @param labs1: number of labels in d1, including root label.
192238106Sdes * @param d2: domain name, uncompressed wireformat
193238106Sdes * @param labs2: number of labels in d2, including root label.
194238106Sdes * @return true if d1 is a subdomain of d2, but not equal to d2.
195238106Sdes */
196238106Sdesint dname_strict_subdomain(uint8_t* d1, int labs1, uint8_t* d2, int labs2);
197238106Sdes
198238106Sdes/**
199238106Sdes * Like dname_strict_subdomain but counts labels
200238106Sdes * @param d1: domain name, uncompressed wireformat
201238106Sdes * @param d2: domain name, uncompressed wireformat
202238106Sdes * @return true if d1 is a subdomain of d2, but not equal to d2.
203238106Sdes */
204238106Sdesint dname_strict_subdomain_c(uint8_t* d1, uint8_t* d2);
205238106Sdes
206238106Sdes/**
207238106Sdes * Counts labels. Tests is d1 is a subdomain of d2.
208238106Sdes * @param d1: domain name, uncompressed wireformat
209238106Sdes * @param d2: domain name, uncompressed wireformat
210238106Sdes * @return true if d1 is a subdomain of d2.
211238106Sdes */
212238106Sdesint dname_subdomain_c(uint8_t* d1, uint8_t* d2);
213238106Sdes
214238106Sdes/**
215238106Sdes * Debug helper. Print wireformat dname to output.
216238106Sdes * @param out: like stdout or a file.
217238106Sdes * @param pkt: if not NULL, the packet for resolving compression ptrs.
218238106Sdes * @param dname: pointer to (start of) dname.
219238106Sdes */
220269257Sdesvoid dname_print(FILE* out, struct sldns_buffer* pkt, uint8_t* dname);
221238106Sdes
222238106Sdes/**
223238106Sdes * Debug helper. Print dname to given string buffer (string buffer must
224238106Sdes * be at least 255 chars + 1 for the 0, in printable form.
225238106Sdes * This may lose information (? for nonprintable characters, or & if
226238106Sdes * the name is too long, # for a bad label length).
227238106Sdes * @param dname: uncompressed wireformat.
228238106Sdes * @param str: buffer of 255+1 length.
229238106Sdes */
230238106Sdesvoid dname_str(uint8_t* dname, char* str);
231238106Sdes
232238106Sdes/**
233238106Sdes * Returns true if the uncompressed wireformat dname is the root "."
234238106Sdes * @param dname: the dname to check
235238106Sdes * @return true if ".", false if not.
236238106Sdes */
237238106Sdesint dname_is_root(uint8_t* dname);
238238106Sdes
239238106Sdes/**
240238106Sdes * Snip off first label from a dname, returning the parent zone.
241238106Sdes * @param dname: from what to strip off. uncompressed wireformat.
242238106Sdes * @param len: length, adjusted to become less.
243238106Sdes * @return stripped off, or "." if input was ".".
244238106Sdes */
245238106Sdesvoid dname_remove_label(uint8_t** dname, size_t* len);
246238106Sdes
247238106Sdes/**
248238106Sdes * Snip off first N labels from a dname, returning the parent zone.
249238106Sdes * @param dname: from what to strip off. uncompressed wireformat.
250238106Sdes * @param len: length, adjusted to become less.
251238106Sdes * @param n: number of labels to strip off (from the left).
252238106Sdes * 	if 0, nothing happens.
253238106Sdes * @return stripped off, or "." if input was ".".
254238106Sdes */
255238106Sdesvoid dname_remove_labels(uint8_t** dname, size_t* len, int n);
256238106Sdes
257238106Sdes/**
258238106Sdes * Count labels for the RRSIG signature label field.
259238106Sdes * Like a normal labelcount, but "*" wildcard and "." root are not counted.
260238106Sdes * @param dname: valid uncompressed wireformat.
261238106Sdes * @return number of labels like in RRSIG; '*' and '.' are not counted.
262238106Sdes */
263238106Sdesint dname_signame_label_count(uint8_t* dname);
264238106Sdes
265238106Sdes/**
266238106Sdes * Return true if the label is a wildcard, *.example.com.
267238106Sdes * @param dname: valid uncompressed wireformat.
268238106Sdes * @return true if wildcard, or false.
269238106Sdes */
270238106Sdesint dname_is_wild(uint8_t* dname);
271238106Sdes
272238106Sdes/**
273238106Sdes * Compare dnames, Canonical in rfc4034 sense, but by label.
274238106Sdes * Such that zone contents follows zone apex.
275238106Sdes *
276238106Sdes * @param d1: first dname. pointer to uncompressed wireformat.
277238106Sdes * @param labs1: number of labels in first dname.
278238106Sdes * @param d2: second dname. pointer to uncompressed wireformat.
279238106Sdes * @param labs2: number of labels in second dname.
280238106Sdes * @param mlabs: number of labels that matched exactly (the shared topdomain).
281238106Sdes * @return: 0 for equal, -1 smaller, or +1 d1 larger than d2.
282238106Sdes */
283238106Sdesint dname_canon_lab_cmp(uint8_t* d1, int labs1, uint8_t* d2, int labs2,
284238106Sdes	int* mlabs);
285238106Sdes
286238106Sdes/**
287238106Sdes * Canonical dname compare. Takes care of counting labels.
288238106Sdes * Per rfc 4034 canonical order.
289238106Sdes *
290238106Sdes * @param d1: first dname. pointer to uncompressed wireformat.
291238106Sdes * @param d2: second dname. pointer to uncompressed wireformat.
292238106Sdes * @return: 0 for equal, -1 smaller, or +1 d1 larger than d2.
293238106Sdes */
294238106Sdesint dname_canonical_compare(uint8_t* d1, uint8_t* d2);
295238106Sdes
296238106Sdes/**
297238106Sdes * Get the shared topdomain between two names. Root "." or longer.
298238106Sdes * @param d1: first dname. pointer to uncompressed wireformat.
299238106Sdes * @param d2: second dname. pointer to uncompressed wireformat.
300238106Sdes * @return pointer to shared topdomain. Ptr to a part of d1.
301238106Sdes */
302238106Sdesuint8_t* dname_get_shared_topdomain(uint8_t* d1, uint8_t* d2);
303238106Sdes
304238106Sdes#endif /* UTIL_DATA_DNAME_H */
305