1 /*------------------------------------------------------------------------------
2  *
3  * Copyright (c) 2011-2021, EURid vzw. All rights reserved.
4  * The YADIFA TM software product is provided under the BSD 3-clause license:
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  *        * Redistributions of source code must retain the above copyright
11  *          notice, this list of conditions and the following disclaimer.
12  *        * Redistributions in binary form must reproduce the above copyright
13  *          notice, this list of conditions and the following disclaimer in the
14  *          documentation and/or other materials provided with the distribution.
15  *        * Neither the name of EURid nor the names of its contributors may be
16  *          used to endorse or promote products derived from this software
17  *          without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  *
31  *------------------------------------------------------------------------------
32  *
33  */
34 
35 /** @defgroup dnscore
36  *  @ingroup dnscore
37  *  @brief Functions used to manipulate dns formatted names and labels
38  *
39  * DNS names are stored in many ways:
40  * _ C string : ASCII with a '\0' sentinel
41  * _ DNS wire : label_length_byte + label_bytes) ending with a label_length_byte with a value of 0
42  * _ simple array of pointers to labels
43  * _ simple stack of pointers to labels (so the same as above, but with the order reversed)
44  * _ sized array of pointers to labels
45  * _ sized stack of pointers to labels (so the same as above, but with the order reversed)
46  *
47  * @{
48  */
49 
50 #define DNSNAME_C_ 1
51 
52 #include "dnscore/dnscore-config.h"
53 #include <stdlib.h>
54 #include <string.h>
55 #include <strings.h>
56 #include <ctype.h>
57 
58 #include "dnscore/dnscore-config.h"
59 #include "dnscore/sys_types.h"
60 
61 
62 const u8 __LOCASE_TABLE__[256] =
63 {
64     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
65     0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
66     0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
67     0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
68 
69     0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
70     0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
71     0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
72     0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
73 
74     0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
75     0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
76     0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
77     0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
78 
79     0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
80     0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
81     0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
82     0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
83 };
84 
85 
86 #include "dnscore/dnsname.h"
87 #include "dnscore/rfc.h"
88 #include "dnscore/zalloc.h"
89 
90 #define DNSNAMED_TAG 0x44454d414e534e44
91 
92 /*****************************************************************************
93  *
94  * BUFFER
95  *
96  *****************************************************************************/
97 
98 /** @brief Converts a C string to a dns name.
99  *
100  *  Converts a C string to a dns name.
101  *
102  *  @param[in] str a pointer to the source c-string
103  *  @param[in] name a pointer to a buffer that will get the full dns name
104  *
105  *  @return Returns the length of the string
106  */
107 
108 /* TWO uses */
109 
110 /*
111  * This table contains TRUE for both expected name terminators
112  */
113 
114 static bool cstr_to_dnsname_terminators[256] =
115 {
116     TRUE,  FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, /* '\0' */
117     FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
118     FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE,  FALSE, /* '.' */
119     FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
120     FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
121     FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
122     FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
123     FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
124     FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
125     FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
126     FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
127     FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
128     FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
129     FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
130     FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
131     FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
132 };
133 
134 /**
135  *  0: out of space
136  *  1: in space
137  * -1: terminator
138  *
139  * =>
140  *
141  * test the map
142  * signed -> terminator
143  *   zero -> out of space
144  *
145  */
146 
147 #if !HAS_FULL_ASCII7
148 
149 /*
150  * The list of characters that are valid in a zone: * - _ 0..9 A..Z a..z
151  *
152  */
153 
154 static s8 cstr_to_dnsname_map[256] =
155 {// 0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
156    -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 00 (HEX) */
157     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10 */
158     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,-1, 0, /* 20 */
159     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 30 */
160     0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 40 */
161     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* 50 */
162     0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 60 */
163     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 70 */
164     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 */
165     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 90 */
166     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
167     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
168     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
169     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
170     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
171     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
172 };
173 
174 /*
175  * The list of characters that are valid in a zone: - _ 0..9 A..Z a..z
176  */
177 
178 static s8 cstr_to_dnsname_map_nostar[256] =
179 {// 0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
180    -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 00 (HEX) */
181     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10 */
182     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,-1, 0, /* 20 */
183     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 30 */
184     0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 40 */
185     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* 50 */
186     0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 60 */
187     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 70 */
188     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 */
189     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 90 */
190     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
191     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
192     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
193     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
194     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
195     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
196 };
197 
198 #else
199 
200 static s8 cstr_to_dnsname_map[256] =
201 {
202    -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 00 (HEX) */
203     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 10 */
204     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,-1, 1, /* 20 */
205     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 30 */
206     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 40 */
207     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 50 */
208     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 60 */
209     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 70 */
210     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 */
211     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 90 */
212     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
213     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
214     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
215     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
216     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
217     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
218 };
219 
220 static s8 cstr_to_dnsname_map_nostar[256] =
221 {
222    -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 00 (HEX) */
223     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 10 */
224     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,-1, 1, /* 20 */
225     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 30 */
226     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 40 */
227     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 50 */
228     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 60 */
229     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 70 */
230     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 */
231     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 90 */
232     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
233     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
234     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
235     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
236     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
237     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
238 };
239 
240 #endif // ASCII7 charset instead of strict DNS
241 
242 /**
243  * This is a set for rname in the SOA TYPE
244  *
245  *  0: out of space
246  *  1: in space
247  * -1: terminator
248  *
249  * =>
250  *
251  * test the map
252  * signed -> terminator
253  *   zero -> out of space
254  *
255  */
256 
257 #if !HAS_FULL_ASCII7
258 
259 static const s8 cstr_to_dnsrname_map[256] =
260 {
261    -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 00 (HEX) */
262     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10 */
263     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,-1, 0, /* 20 */
264     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 30 */
265     0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 40 */
266     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 2, 0, 0, 1, /* 50 */
267     0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 60 */
268     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 70 */
269     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 */
270     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 90 */
271     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
272     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
273     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
274     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
275     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
276     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
277 };
278 
279 #else
280 
281 static const s8 cstr_to_dnsrname_map[256] =
282 {
283    -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 00 (HEX) */
284     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 10 */
285     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,-1, 1, /* 20 */
286     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 30 */
287     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 40 */
288     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, /* 50 */
289     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 60 */
290     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 70 */
291     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 */
292     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 90 */
293     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
294     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
295     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
296     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
297     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
298     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
299 };
300 
301 #endif
302 
303 /**
304  * char DNS charset test
305  *
306  * @param c
307  * @return TRUE iff c in in the DNS charset
308  *
309  */
310 
311 bool
dnsname_is_charspace(u8 c)312 dnsname_is_charspace(u8 c)
313 {
314     return cstr_to_dnsname_map[c] == 1;
315 }
316 
317 s32
dnslabel_compare(const u8 * a,const u8 * b)318 dnslabel_compare(const u8 *a, const u8 *b)
319 {
320     int len = MIN(*a, *b);
321     int d = memcmp(a+1, b+1, len);
322     if(d == 0)
323     {
324         d = *a;
325         d -= *b;
326     }
327     return d;
328 }
329 
330 /**
331  * label DNS charset test
332  *
333  * @param label
334  * @return TRUE iff each char in the label in in the DNS charset
335  *
336  */
337 
338 bool
dnslabel_verify_charspace(const u8 * label)339 dnslabel_verify_charspace(const u8 *label)
340 {
341     u8 n = *label;
342 
343     if(n > MAX_LABEL_LENGTH)
344     {
345         return FALSE;
346     }
347 
348     const u8 *const limit = &label[n];
349 
350     while(++label < limit)
351     {
352         u8 c = *label;
353 
354         if(cstr_to_dnsname_map[c] != 1)
355         {
356             return FALSE;
357         }
358     }
359 
360     return TRUE;
361 }
362 
363 /**
364  * dns name DNS charset test
365  *
366  * @param name_wire
367  * @return TRUE if each char in the name is in the DNS charset
368  *
369  */
370 
371 bool
dnsname_verify_charspace(const u8 * name_wire)372 dnsname_verify_charspace(const u8 *name_wire)
373 {
374     u8 n;
375 
376     for(;;)
377     {
378         n = *name_wire;
379 
380         if(n == 0)
381         {
382             return TRUE;
383         }
384 
385         if(n > MAX_LABEL_LENGTH)
386         {
387             return FALSE;
388         }
389 
390         const u8 *const limit = &name_wire[n];
391 
392         while(++name_wire <= limit)
393         {
394             u8 c = *name_wire;
395 
396             if(cstr_to_dnsname_map[c] != 1)
397             {
398                 return FALSE;
399             }
400         }
401     }
402 }
403 
404 
405 /**
406  * label DNS charset test and set to lower case
407  *
408  * @param label
409  * @return TRUE iff each char in the label in in the DNS charset
410  *
411  */
412 
413 bool
dnslabel_locase_verify_charspace(u8 * label)414 dnslabel_locase_verify_charspace(u8 *label)
415 {
416     u8 n = *label;
417 
418     if(n > MAX_LABEL_LENGTH)
419     {
420         return FALSE;
421     }
422 
423     u8 * const limit = &label[n];
424 
425     while(++label <= limit)
426     {
427         u8 c = *label;
428 
429         if(cstr_to_dnsname_map[c] != 1)
430         {
431             return FALSE;
432         }
433 
434         *label = LOCASE(c);
435     }
436 
437     return TRUE;
438 }
439 
440 /**
441  * dns name DNS charset test and set to lower case
442  *
443  * @param name_wire
444  * @return TRUE iff each char in the name is in the DNS charset
445  *
446  */
447 
448 bool
dnsname_locase_verify_charspace(u8 * name_wire)449 dnsname_locase_verify_charspace(u8 *name_wire)
450 {
451     u8 n;
452 
453     for(;;)
454     {
455         n = *name_wire;
456 
457         if(n == 0)
458         {
459             return TRUE;
460         }
461 
462         if(n > MAX_LABEL_LENGTH)
463         {
464             return FALSE;
465         }
466 
467         u8 * const limit = &name_wire[n];
468 
469         while(++name_wire <= limit)
470         {
471             u8 c = *name_wire;
472 
473             if(cstr_to_dnsname_map[c] != 1)
474             {
475                 return FALSE;
476             }
477 
478             *name_wire = LOCASE(c);
479         }
480     }
481 }
482 
483 /**
484  * dns name DNS charset test and set to lower case
485  *
486  * LOCASE is done using tolower(c)
487  *
488  * @param name_wire
489  * @return TRUE iff each char in the name in in the DNS charset
490  *
491  */
492 
493 bool
dnsname_locase_verify_extended_charspace(u8 * name_wire)494 dnsname_locase_verify_extended_charspace(u8 *name_wire)
495 {
496     u8 n;
497 
498     for(;;)
499     {
500         n = *name_wire;
501 
502         if(n == 0)
503         {
504             return TRUE;
505         }
506 
507         if(n > MAX_LABEL_LENGTH)
508         {
509             return FALSE;
510         }
511 
512         u8 * const limit = &name_wire[n];
513 
514         while(++name_wire <= limit)
515         {
516             u8 c = *name_wire;
517 
518             if(cstr_to_dnsname_map[c] != 1)
519             {
520                 return FALSE;
521             }
522 
523             *name_wire = tolower(c);
524         }
525     }
526 }
527 
528 /**
529  *  @brief Converts a C string to a dns name.
530  *
531  *  Converts a C string to a dns name.
532  *
533  *  @param[in] name_parm a pointer to a buffer that will get the full dns name
534  *  @param[in] str a pointer to the source c-string
535  *
536  *  @return Returns the length of the string up to the last '\0'
537  */
538 
539 ya_result
cstr_to_dnsname(u8 * name_parm,const char * str)540 cstr_to_dnsname(u8* name_parm, const char* str)
541 {
542     u8 * const limit = &name_parm[MAX_DOMAIN_LENGTH];
543     u8 *s = name_parm;
544     u8 *p = &name_parm[1];
545 
546     u8 c;
547 
548     for(c = *str++;; c = *str++)
549     {
550         if(!cstr_to_dnsname_terminators[c] /*(c != '.') && (c != '\0')*/)
551         {
552             *p = c;
553         }
554         else
555         {
556             u8 l = p - s - 1;
557             *s = l;
558             s = p;
559 
560             if(l == 0)
561             {
562                 break;
563             }
564 
565             if(l > MAX_LABEL_LENGTH)
566             {
567                 return LABEL_TOO_LONG;
568             }
569 
570             if(c == '\0')
571             {
572                 if(p >= limit)
573                 {
574                     return DOMAIN_TOO_LONG;
575                 }
576 
577                 *s++ = '\0';
578                 break;
579             }
580         }
581 
582         if(++p > limit)
583         {
584             return DOMAIN_TOO_LONG;
585         }
586     }
587 
588     return s - name_parm;
589 }
590 
591 ya_result
cstr_to_locase_dnsname(u8 * name_parm,const char * str)592 cstr_to_locase_dnsname(u8* name_parm, const char* str)
593 {
594     u8 * const limit = &name_parm[MAX_DOMAIN_LENGTH];
595     u8 *s = name_parm;
596     u8 *p = &name_parm[1];
597 
598     u8 c;
599 
600     for(c = *str++;; c = *str++)
601     {
602         if(!cstr_to_dnsname_terminators[c] /*(c != '.') && (c != '\0')*/)
603         {
604             *p = LOCASE(c);
605         }
606         else
607         {
608             u8 l = p - s - 1;
609             *s = l;
610             s = p;
611 
612             if(l == 0)
613             {
614                 break;
615             }
616 
617             if(l > MAX_LABEL_LENGTH)
618             {
619                 return LABEL_TOO_LONG;
620             }
621 
622             if(c == '\0')
623             {
624                 if(p >= limit)
625                 {
626                     return DOMAIN_TOO_LONG;
627                 }
628 
629                 *s++ = '\0';
630                 break;
631             }
632         }
633 
634         if(++p > limit)
635         {
636             return DOMAIN_TOO_LONG;
637         }
638     }
639 
640     return s - name_parm;
641 }
642 
643 ya_result
charp_to_dnsname(u8 * name_parm,const char * str,u32 str_len)644 charp_to_dnsname(u8* name_parm, const char* str, u32 str_len)
645 {
646     const char * const limit = &str[str_len];
647     u8 *s = name_parm;
648     u8 *p = &name_parm[1];
649 
650     u8 c;
651 
652     if(str_len >= MAX_DOMAIN_LENGTH)
653     {
654         return DOMAIN_TOO_LONG;
655     }
656 
657     for(c = *str++; ; c = *str++)
658     {
659         if((str <= limit) && !cstr_to_dnsname_terminators[c] /*(c != '.') && (c != '\0')*/)
660         {
661             *p = c;
662         }
663         else
664         {
665             u8 l = p - s - 1;
666             *s = l;
667             s = p;
668 
669             if(l == 0)
670             {
671                 break;
672             }
673 
674             if(l > MAX_LABEL_LENGTH)
675             {
676                 return LABEL_TOO_LONG;
677             }
678 
679             if(str >= limit)
680             {
681                 *s++ = '\0';
682                 break;
683             }
684         }
685 
686         ++p;
687     }
688 
689     return s - name_parm;
690 }
691 
692 ya_result
charp_to_locase_dnsname(u8 * name_parm,const char * str,u32 str_len)693 charp_to_locase_dnsname(u8* name_parm, const char* str, u32 str_len)
694 {
695     const char * const limit = &str[str_len];
696     u8 *s = name_parm;
697     u8 *p = &name_parm[1];
698 
699     u8 c;
700 
701     if(str_len >= MAX_DOMAIN_LENGTH)
702     {
703         return DOMAIN_TOO_LONG;
704     }
705 
706     for(c = *str++; ; c = *str++)
707     {
708         if((str <= limit) && !cstr_to_dnsname_terminators[c] /*(c != '.') && (c != '\0')*/)
709         {
710             *p = LOCASE(c);
711         }
712         else
713         {
714             u8 l = p - s - 1;
715             *s = l;
716             s = p;
717 
718             if(l == 0)
719             {
720                 break;
721             }
722 
723             if(l > MAX_LABEL_LENGTH)
724             {
725                 return LABEL_TOO_LONG;
726             }
727 
728             if(str >= limit)
729             {
730                 *s++ = '\0';
731                 break;
732             }
733         }
734 
735         ++p;
736     }
737 
738     return s - name_parm;
739 }
740 
741 /**
742  * Allows for '*'
743  */
744 
745 ya_result
charp_to_locase_dnsname_with_check(u8 * name_parm,const char * str,u32 str_len)746 charp_to_locase_dnsname_with_check(u8* name_parm, const char* str, u32 str_len)
747 {
748     const char * const limit = &str[str_len];
749     u8 *s = name_parm;
750     u8 *p = &name_parm[1];
751 
752     u8 c;
753 
754     if(str_len >= MAX_DOMAIN_LENGTH)
755     {
756         return DOMAIN_TOO_LONG;
757     }
758 
759     for(c = *str++; ; c = *str++)
760     {
761         if((str <= limit) && !cstr_to_dnsname_terminators[c] /*(c != '.') && (c != '\0')*/)
762         {
763             if(cstr_to_dnsname_map[c] == 0)
764             {
765                 return INVALID_CHARSET;
766             }
767 
768             *p = LOCASE(c);
769         }
770         else
771         {
772             u8 l = p - s - 1;
773             *s = l;
774             s = p;
775 
776             if(l == 0)
777             {
778                 break;
779             }
780 
781             if(l > MAX_LABEL_LENGTH)
782             {
783                 return LABEL_TOO_LONG;
784             }
785 
786             if(str >= limit)
787             {
788                 *s++ = '\0';
789                 break;
790             }
791         }
792 
793         ++p;
794     }
795 
796     return s - name_parm;
797 }
798 
799 /**
800  *  @brief Converts a C string to a dns name and checks for validity
801  *
802  *  Converts a C string to a dns name.
803  *
804  *  @param[in] name_parm a pointer to a buffer that will get the full dns name
805  *  @param[in] str a pointer to the source c-string
806  *
807  *  @return Returns the length of the string up to the last '\0'
808  */
809 
810 ya_result
cstr_to_dnsname_with_check(u8 * name_parm,const char * str)811 cstr_to_dnsname_with_check(u8* name_parm, const char* str)
812 {
813     u8 * const limit = &name_parm[MAX_DOMAIN_LENGTH];
814     u8 *s = name_parm;
815     u8 *p = &name_parm[1];
816 
817     u8 c;
818 
819     /*
820      * I cannot check this in one go actually.
821      *
822      * It would work 99.9999999% of the time but if the string is "" and is at the end of a page it would overlap to a non-mapped
823      * memory and crash.
824      *
825      */
826 
827     if((str[0] == '.') && (str[1] == '\0'))
828     {
829         *name_parm = 0;
830         return 1;
831     }
832 
833     if(str[0] == '*')
834     {
835         if(str[1] == '\0')
836         {
837             name_parm[0] = 1;
838             name_parm[1] = '*';
839             name_parm[2] = '\0';
840             return 3;
841         }
842         else if(str[1] == '.')
843         {
844             name_parm[0] = 1;
845             name_parm[1] = '*';
846             str += 2;
847             s += 2;
848             p += 2;
849         }
850         else
851         {
852             return DOMAINNAME_INVALID;
853         }
854     }
855 
856     for(c = *str++;; c = *str++)
857     { /* test if a switch/case is better (break mix issues for this switch in this particular loop)
858 	   *
859 	   * in theory this is test/jb/jz
860 	   * a switch would be jmp [v]
861 	   *
862 	   */
863 
864         if(cstr_to_dnsname_map_nostar[c] >= 0 /*(c != '.') && (c != '\0')*/)
865         {
866             if(cstr_to_dnsname_map_nostar[c] == 0)
867             {
868                 return INVALID_CHARSET;
869             }
870 
871             *p = c;
872         }
873         else
874         {
875             u8 l = p - s - 1;
876             *s = l;
877             s = p;
878 
879             if(l == 0)
880             {
881                 if(c != '\0')
882                 {
883                     return DOMAINNAME_INVALID;
884                 }
885 
886                 break;
887             }
888 
889             if(l > MAX_LABEL_LENGTH)
890             {
891                 return LABEL_TOO_LONG;
892             }
893 
894             if(c == '\0')
895             {
896                 if(p >= limit)
897                 {
898                     return DOMAIN_TOO_LONG;
899                 }
900 
901                 *s++ = '\0';
902                 break;
903             }
904         }
905 
906         if(++p > limit)
907         {
908             return DOMAIN_TOO_LONG;
909         }
910     }
911 
912     return s - name_parm;
913 }
914 
915 ya_result
cstr_to_dnsname_with_check_len(u8 * name_parm,const char * text,u32 text_len)916 cstr_to_dnsname_with_check_len(u8* name_parm, const char* text, u32 text_len)
917 {
918     /*
919      * .        => 1 => 00 => 1
920      *
921      * a        => 1 => 01 'A' 00 => 3
922      * a.b      => 3 => 01 'A' 01 'B' 00 => 5
923      * a.b.     => 4 => 01 'A' 01 'B' 00 => 5
924      *
925      */
926 
927     u8 *label_start = name_parm;
928     u8 *p = &name_parm[1];
929 
930     u8 c;
931 
932     /*
933      * I cannot check this in one go actually.
934      *
935      * It would work 99.9999999% of the time but if the string is "" and is at the end of a page it would overlap to a non-mapped
936      * memory and crash.
937      *
938      */
939 
940     if(text_len == 0)
941     {
942         return DOMAINNAME_INVALID;
943     }
944 
945     if(text[0] == '.')
946     {
947         if(text_len == 1)
948         {
949             *name_parm = 0;
950             return 1;
951         }
952         else
953         {
954             return DOMAINNAME_INVALID;
955         }
956     }
957 
958     if(text[0] != '*')
959     {
960         // ensure the length is acceptable
961 
962         u32 output_len = text_len + 1;
963 
964         if(text[text_len - 1] != '.')
965         {
966             output_len += 1;
967         }
968 
969         if(output_len > MAX_DOMAIN_LENGTH)
970         {
971             return DOMAIN_TOO_LONG;
972         }
973     }
974     else
975     {
976         if(text_len == 1)      // '*'
977         {
978             name_parm[0] = 1;
979             name_parm[1] = '*';
980             name_parm[2] = '\0';
981             return 3;
982         }
983         else if(text[1] == '.')  //  '*.????' note: at this point str_len is 2 or more
984         {
985             // ensure the length is acceptable
986 
987             u32 output_len = text_len + 1;
988 
989             if(text[text_len - 1] != '.')
990             {
991                 output_len += 1;
992             }
993 
994             if(output_len > MAX_DOMAIN_LENGTH)
995             {
996                 return DOMAIN_TOO_LONG;
997             }
998 
999             name_parm[0] = 1;
1000             name_parm[1] = '*';
1001 
1002             if(text_len == 2)
1003             {
1004                 name_parm[2] = '\0';
1005                 return 3;
1006             }
1007 
1008             text += 2;
1009             label_start += 2;
1010             p += 2;
1011         }
1012         else                    // '*????'
1013         {
1014             return DOMAINNAME_INVALID;
1015         }
1016     }
1017 
1018     const char * const text_limit = &text[text_len];
1019 
1020     for(c = *text++; ; c = *text++)
1021     {
1022         /* test if a switch/case is better (break mix issues for this switch in this particular loop)
1023          *
1024          * in theory this is test/jb/jz
1025          * a switch would be jmp [v]
1026          *
1027          */
1028 
1029         if(cstr_to_dnsname_map_nostar[c] >= 0)          // (c != '.') && (c != '\0')
1030         {
1031             if(cstr_to_dnsname_map_nostar[c] == 0)
1032             {
1033                 return INVALID_CHARSET;
1034             }
1035 
1036             *p++ = c;
1037 
1038             if(text == text_limit)
1039             {
1040                 // close the label
1041 
1042                 u8 label_length = p - label_start - 1;      // size of the label
1043 
1044                 if(label_length > MAX_LABEL_LENGTH)
1045                 {
1046                     return LABEL_TOO_LONG;
1047                 }
1048 
1049                 *label_start = label_length;
1050 
1051                 // close the fqdn
1052 
1053                 *p++ = 0;
1054 
1055                 return p - name_parm;
1056             }
1057         }
1058         else    // reached '.' or end of cstr (which should not occur in this algorithm)
1059         {
1060             u8 label_length = p - label_start - 1;      // size of the label
1061             /*
1062             if(label_length == 0)                       // .. case
1063             {
1064                 if(c != '\0')
1065                 {
1066                     return DOMAINNAME_INVALID;
1067                 }
1068 
1069                 break;
1070             }
1071             */
1072             if(label_length > MAX_LABEL_LENGTH)
1073             {
1074                 return LABEL_TOO_LONG;
1075             }
1076 
1077             *label_start = label_length;
1078 
1079             if(text == text_limit)
1080             {
1081                 *p++ = '\0';
1082                 return p - name_parm;
1083             }
1084 
1085             label_start = p;
1086             p++;
1087         }
1088     }
1089 }
1090 
1091 ya_result
cstr_to_locase_dnsname_with_check_len(u8 * name_parm,const char * text,u32 text_len)1092 cstr_to_locase_dnsname_with_check_len(u8* name_parm, const char* text, u32 text_len)
1093 {
1094     /*
1095      * .        => 1 => 00 => 1
1096      *
1097      * a        => 1 => 01 'A' 00 => 3
1098      * a.b      => 3 => 01 'A' 01 'B' 00 => 5
1099      * a.b.     => 4 => 01 'A' 01 'B' 00 => 5
1100      *
1101      */
1102 
1103     u8 *label_start = name_parm;
1104     u8 *p = &name_parm[1];
1105 
1106     u8 c;
1107 
1108     /*
1109      * I cannot check this in one go actually.
1110      *
1111      * It would work 99.9999999% of the time but if the string is "" and is at the end of a page it would overlap to a non-mapped
1112      * memory and crash.
1113      *
1114      */
1115 
1116     if(text_len == 0)
1117     {
1118         return DOMAINNAME_INVALID;
1119     }
1120 
1121     if(text[0] == '.')
1122     {
1123         if(text_len == 1)
1124         {
1125             *name_parm = 0;
1126             return 1;
1127         }
1128         else
1129         {
1130             return DOMAINNAME_INVALID;
1131         }
1132     }
1133 
1134     if(text[0] != '*')
1135     {
1136         // ensure the length is acceptable
1137 
1138         u32 output_len = text_len + 1;
1139 
1140         if(text[text_len - 1] != '.')
1141         {
1142             output_len += 1;
1143         }
1144 
1145         if(output_len > MAX_DOMAIN_LENGTH)
1146         {
1147             return DOMAIN_TOO_LONG;
1148         }
1149     }
1150     else
1151     {
1152         if(text_len == 1)      // '*'
1153         {
1154             name_parm[0] = 1;
1155             name_parm[1] = '*';
1156             name_parm[2] = '\0';
1157             return 3;
1158         }
1159         else if(text[1] == '.')  //  '*.????' note: at this point str_len is 2 or more
1160         {
1161             // ensure the length is acceptable
1162 
1163             u32 output_len = text_len + 1;
1164 
1165             if(text[text_len - 1] != '.')
1166             {
1167                 output_len += 1;
1168             }
1169 
1170             if(output_len > MAX_DOMAIN_LENGTH)
1171             {
1172                 return DOMAIN_TOO_LONG;
1173             }
1174 
1175             name_parm[0] = 1;
1176             name_parm[1] = '*';
1177 
1178             if(text_len == 2)
1179             {
1180                 name_parm[2] = '\0';
1181                 return 3;
1182             }
1183 
1184             text += 2;
1185             label_start += 2;
1186             p += 2;
1187         }
1188         else                    // '*????'
1189         {
1190             return DOMAINNAME_INVALID;
1191         }
1192     }
1193 
1194     const char * const text_limit = &text[text_len];
1195 
1196     for(c = *text++; ; c = *text++)
1197     {
1198         /* test if a switch/case is better (break mix issues for this switch in this particular loop)
1199          *
1200          * in theory this is test/jb/jz
1201          * a switch would be jmp [v]
1202          *
1203          */
1204 
1205         if(cstr_to_dnsname_map_nostar[c] >= 0)          // (c != '.') && (c != '\0')
1206         {
1207             if(cstr_to_dnsname_map_nostar[c] == 0)
1208             {
1209                 return INVALID_CHARSET;
1210             }
1211 
1212             *p++ = LOCASE(c);
1213 
1214             if(text == text_limit)
1215             {
1216                 // close the label
1217 
1218                 u8 label_length = p - label_start - 1;      // size of the label
1219 
1220                 if(label_length > MAX_LABEL_LENGTH)
1221                 {
1222                     return LABEL_TOO_LONG;
1223                 }
1224 
1225                 *label_start = label_length;
1226 
1227                 // close the fqdn
1228 
1229                 *p++ = 0;
1230 
1231                 return p - name_parm;
1232             }
1233         }
1234         else    // reached '.' or end of cstr (which should not occur in this algorithm)
1235         {
1236             u8 label_length = p - label_start - 1;      // size of the label
1237             /*
1238             if(label_length == 0)                       // .. case
1239             {
1240                 if(c != '\0')
1241                 {
1242                     return DOMAINNAME_INVALID;
1243                 }
1244 
1245                 break;
1246             }
1247             */
1248             if(label_length > MAX_LABEL_LENGTH)
1249             {
1250                 return LABEL_TOO_LONG;
1251             }
1252 
1253             *label_start = label_length;
1254 
1255             if(text == text_limit)
1256             {
1257                 *p++ = '\0';
1258                 return p - name_parm;
1259             }
1260 
1261             label_start = p;
1262             p++;
1263         }
1264     }
1265 }
1266 
1267 ya_result
cstr_to_dnsname_with_check_len_with_origin(u8 * name_parm,const char * text,u32 text_len,const u8 * origin)1268 cstr_to_dnsname_with_check_len_with_origin(u8* name_parm, const char* text, u32 text_len, const u8 *origin)
1269 {
1270     /*
1271      * .        => 1 => 00 => 1
1272      *
1273      * a        => 1 => 01 'A' 00 => 3
1274      * a.b      => 3 => 01 'A' 01 'B' 00 => 5
1275      * a.b.     => 4 => 01 'A' 01 'B' 00 => 5
1276      *
1277      */
1278 
1279     u8 *label_start = name_parm;
1280     u8 *p = &name_parm[1];
1281 
1282     u8 c;
1283 
1284     /*
1285      * I cannot check this in one go actually.
1286      *
1287      * It would work 99.9999999% of the time but if the string is "" and is at the end of a page it would overlap to a non-mapped
1288      * memory and crash.
1289      *
1290      */
1291 
1292     if(text_len == 0)
1293     {
1294         return DOMAINNAME_INVALID;
1295     }
1296 
1297     if(text[0] == '.')
1298     {
1299         if(text_len == 1)
1300         {
1301             *name_parm = 0;
1302             return 1;
1303         }
1304         else
1305         {
1306             return DOMAINNAME_INVALID;
1307         }
1308     }
1309 
1310     if(text[0] != '*')
1311     {
1312         // ensure the length is acceptable
1313 
1314         u32 output_len = text_len + 1;
1315 
1316         if(text[text_len - 1] != '.')
1317         {
1318             output_len += 1;
1319         }
1320 
1321         if(output_len > MAX_DOMAIN_LENGTH)
1322         {
1323             return DOMAIN_TOO_LONG;
1324         }
1325     }
1326     else
1327     {
1328         if(text_len == 1)      // '*'
1329         {
1330             name_parm[0] = 1;
1331             name_parm[1] = '*';
1332 
1333             ya_result return_value = dnsname_copy(&name_parm[2], origin) + 2;
1334 
1335             return return_value;
1336         }
1337         else if(text[1] == '.')  //  '*.????' note: at this point str_len is 2 or more
1338         {
1339             // ensure the length is acceptable
1340 
1341             u32 output_len = text_len + 1;
1342 
1343             if(text[text_len - 1] != '.')
1344             {
1345                 output_len += 1;
1346             }
1347 
1348             if(output_len > MAX_DOMAIN_LENGTH)
1349             {
1350                 return DOMAIN_TOO_LONG;
1351             }
1352 
1353             name_parm[0] = 1;
1354             name_parm[1] = '*';
1355 
1356             if(text_len == 2)
1357             {
1358                 name_parm[2] = '\0';
1359                 return 3;
1360             }
1361 
1362             text += 2;
1363             label_start += 2;
1364             p += 2;
1365         }
1366         else                    // '*????'
1367         {
1368             return DOMAINNAME_INVALID;
1369         }
1370     }
1371 
1372     const char * const text_limit = &text[text_len];
1373 
1374     for(c = *text++; ; c = *text++)
1375     {
1376         /* test if a switch/case is better (break mix issues for this switch in this particular loop)
1377          *
1378          * in theory this is test/jb/jz
1379          * a switch would be jmp [v]
1380          *
1381          */
1382 
1383         if(cstr_to_dnsname_map_nostar[c] >= 0)          // (c != '.') && (c != '\0')
1384         {
1385             if(cstr_to_dnsname_map_nostar[c] == 0)
1386             {
1387                 return INVALID_CHARSET;
1388             }
1389 
1390             *p++ = c;
1391 
1392             if(text == text_limit)
1393             {
1394                 // close the label
1395 
1396                 u8 label_length = p - label_start - 1;      // size of the label
1397 
1398                 if(label_length > MAX_LABEL_LENGTH)
1399                 {
1400                     return LABEL_TOO_LONG;
1401                 }
1402 
1403                 *label_start = label_length;
1404 
1405                 // close the fqdn
1406 
1407                 ya_result return_value = dnsname_copy(p, origin) + p - name_parm;
1408 
1409                 return return_value;
1410             }
1411         }
1412         else    // reached '.' or end of cstr (which should not occur in this algorithm)
1413         {
1414             u8 label_length = p - label_start - 1;      // size of the label
1415 
1416             if(label_length > MAX_LABEL_LENGTH)
1417             {
1418                 return LABEL_TOO_LONG;
1419             }
1420 
1421             *label_start = label_length;
1422 
1423             if(text == text_limit)
1424             {
1425                 *p++ = '\0';
1426                 return p - name_parm;
1427             }
1428 
1429             label_start = p;
1430             p++;
1431         }
1432     }
1433 }
1434 
1435 ya_result
cstr_to_locase_dnsname_with_check_len_with_origin(u8 * name_parm,const char * text,u32 text_len,const u8 * origin)1436 cstr_to_locase_dnsname_with_check_len_with_origin(u8* name_parm, const char* text, u32 text_len, const u8 *origin)
1437 {
1438     /*
1439      * .        => 1 => 00 => 1
1440      *
1441      * a        => 1 => 01 'A' 00 => 3
1442      * a.b      => 3 => 01 'A' 01 'B' 00 => 5
1443      * a.b.     => 4 => 01 'A' 01 'B' 00 => 5
1444      *
1445      */
1446 
1447     u8 *label_start = name_parm;
1448     u8 *p = &name_parm[1];
1449 
1450     u8 c;
1451 
1452     /*
1453      * I cannot check this in one go actually.
1454      *
1455      * It would work 99.9999999% of the time but if the string is "" and is at the end of a page it would overlap to a non-mapped
1456      * memory and crash.
1457      *
1458      */
1459 
1460     if(text_len == 0)
1461     {
1462         return DOMAINNAME_INVALID;
1463     }
1464 
1465     if(text[0] == '.')
1466     {
1467         if(text_len == 1)
1468         {
1469             *name_parm = 0;
1470             return 1;
1471         }
1472         else
1473         {
1474             return DOMAINNAME_INVALID;
1475         }
1476     }
1477 
1478     if(text[0] != '*')
1479     {
1480         // ensure the length is acceptable
1481 
1482         u32 output_len = text_len + 1;
1483 
1484         if(text[text_len - 1] != '.')
1485         {
1486             output_len += 1;
1487         }
1488 
1489         if(output_len > MAX_DOMAIN_LENGTH)
1490         {
1491             return DOMAIN_TOO_LONG;
1492         }
1493     }
1494     else
1495     {
1496         if(text_len == 1)      // '*'
1497         {
1498             name_parm[0] = 1;
1499             name_parm[1] = '*';
1500 
1501             //ya_result return_value = dnsname_copy(&name_parm[2], origin) + 2;
1502             ya_result return_value = dnsname_canonize(origin, &name_parm[2]) + 2;
1503 
1504             return return_value;
1505         }
1506         else if(text[1] == '.')  //  '*.????' note: at this point str_len is 2 or more
1507         {
1508             // ensure the length is acceptable
1509 
1510             u32 output_len = text_len + 1;
1511 
1512             if(text[text_len - 1] != '.')
1513             {
1514                 output_len += 1;
1515             }
1516 
1517             if(output_len > MAX_DOMAIN_LENGTH)
1518             {
1519                 return DOMAIN_TOO_LONG;
1520             }
1521 
1522             name_parm[0] = 1;
1523             name_parm[1] = '*';
1524 
1525             if(text_len == 2)
1526             {
1527                 name_parm[2] = '\0';
1528                 return 3;
1529             }
1530 
1531             text += 2;
1532             label_start += 2;
1533             text_len -= 2;
1534             p += 2;
1535         }
1536         else                    // '*????'
1537         {
1538             return DOMAINNAME_INVALID;
1539         }
1540     }
1541 
1542     const char * const text_limit = &text[text_len];
1543 
1544     for(c = *text++; ; c = *text++)
1545     {
1546         /* test if a switch/case is better (break mix issues for this switch in this particular loop)
1547          *
1548          * in theory this is test/jb/jz
1549          * a switch would be jmp [v]
1550          *
1551          */
1552 
1553         if(cstr_to_dnsname_map_nostar[c] >= 0)          // (c != '.') && (c != '\0')
1554         {
1555             if(cstr_to_dnsname_map_nostar[c] == 0)
1556             {
1557                 return INVALID_CHARSET;
1558             }
1559 
1560             *p++ = LOCASE(c);
1561 
1562             if(text == text_limit)
1563             {
1564                 // close the label
1565 
1566                 u8 label_length = p - label_start - 1;      // size of the label
1567 
1568                 if(label_length > MAX_LABEL_LENGTH)
1569                 {
1570                     return LABEL_TOO_LONG;
1571                 }
1572 
1573                 *label_start = label_length;
1574 
1575                 // close the fqdn
1576 
1577                 ya_result return_value = dnsname_copy(p, origin) + p - name_parm;
1578 
1579                 return return_value;
1580             }
1581         }
1582         else    // reached '.' or end of cstr (which should not occur in this algorithm)
1583         {
1584             u8 label_length = p - label_start - 1;      // size of the label
1585 
1586             if(label_length > MAX_LABEL_LENGTH)
1587             {
1588                 return LABEL_TOO_LONG;
1589             }
1590 
1591             *label_start = label_length;
1592 
1593             if(text == text_limit)
1594             {
1595                 if(label_length > 0)
1596                 {
1597                     *p++ = '\0';
1598                 }
1599                 return p - name_parm;
1600             }
1601 
1602             label_start = p;
1603             p++;
1604         }
1605     }
1606 }
1607 
1608 /**
1609  *  @brief Converts a C string to a dns rname and checks for validity
1610  *
1611  *  Converts a C string to a dns rname.
1612  *
1613  *  @param[in] name_parm a pointer to a buffer that will get the full dns name
1614  *  @param[in] str a pointer to the source c-string
1615  *
1616  *  @return the length of the string up to the last '\0'
1617  */
1618 
1619 ya_result
cstr_to_dnsrname_with_check(u8 * name_parm,const char * str)1620 cstr_to_dnsrname_with_check(u8* name_parm, const char* str)
1621 {
1622     u8 * const limit = &name_parm[MAX_DOMAIN_LENGTH];
1623     u8 *s = name_parm;
1624     u8 *p = &name_parm[1];
1625 
1626     u8 c;
1627 
1628     bool escaped = FALSE;
1629 
1630     /*
1631      * I cannot check this in one go actually.
1632      *
1633      * It would work 99.9999999% of the time but if the string is "" and is at the end of a page it would overlap to a non-mapped
1634      * memory and crash.
1635      *
1636      */
1637 
1638     for(c = *str++;; c = *str++)
1639     { /* test if a switch/case is better (break mix issues for this switch in this particular loop)
1640 	 *
1641 	 * in theory this is test/jb/jz
1642 	 * a switch would be jmp [v]
1643 	 * mmhh ...
1644 	 *
1645 	 */
1646         if((cstr_to_dnsrname_map[c] >= 0)  /*(c != '.') && (c != '\0')*/ || escaped)
1647         {
1648             if(!escaped)
1649             {
1650                 if(cstr_to_dnsrname_map[c] == 0)
1651                 {
1652                     return INVALID_CHARSET;
1653                 }
1654 
1655                 /* escape character */
1656                 /* AFAIK there is only one escape : '\', so why use an indexed memory to test it ?  if (cstr_to_dnsrname_map[c] == 2) */
1657                 if(c == '\\')
1658                 {
1659                     escaped = TRUE;
1660                     /* reading the next char here is wrong is the record is corrupt and ends with my-wrong-rname\. */
1661                     continue;
1662                 }
1663             }
1664 
1665             *p = c;
1666             escaped = FALSE;
1667         }
1668         else
1669         {
1670             u8 l = p - s - 1;
1671             *s = l;
1672 
1673             s = p;
1674 
1675             if(l == 0)
1676             {
1677                 if(c != '\0')
1678                 {
1679                     return DOMAINNAME_INVALID;
1680                 }
1681 
1682                 break;
1683             }
1684 
1685             if(l > MAX_LABEL_LENGTH)
1686             {
1687                 return LABEL_TOO_LONG;
1688             }
1689 
1690             if(c == '\0')
1691             {
1692                 if(p >= limit)
1693                 {
1694                     return DOMAIN_TOO_LONG;
1695                 }
1696 
1697                 *s++ = '\0';
1698                 break;
1699             }
1700         }
1701 
1702         if(++p > limit)
1703         {
1704             return DOMAIN_TOO_LONG;
1705         }
1706     }
1707 
1708     if(escaped)
1709     {
1710         return DOMAINNAME_INVALID;
1711     }
1712 
1713     return s - name_parm;
1714 }
1715 
1716 /* ONE use */
1717 
1718 ya_result
cstr_get_dnsname_len(const char * str)1719 cstr_get_dnsname_len(const char* str)
1720 {
1721     ya_result total = 0;
1722     const char* start;
1723 
1724     if(*str == '.')
1725     {
1726         str++;
1727     }
1728 
1729     s32 label_len;
1730 
1731     do
1732     {
1733         char c;
1734 
1735         start = str;
1736 
1737         do
1738         {
1739             c = *str++;
1740         }
1741         while(c != '.' && c != '\0');
1742 
1743         label_len = (str - start) - 1;
1744 
1745         if(label_len > MAX_LABEL_LENGTH)
1746         {
1747             return LABEL_TOO_LONG;
1748         }
1749 
1750         total += label_len + 1;
1751 
1752         if(c == '\0')
1753         {
1754             if(label_len != 0)
1755             {
1756                 total++;
1757             }
1758 
1759             break;
1760         }
1761     }
1762     while(label_len != 0);
1763 
1764     return total;
1765 }
1766 
1767 /** @brief Converts a dns name to a C string
1768  *
1769  *  Converts a dns name to a C string
1770  *
1771  *  @param[in] name a pointer to the source dns name
1772  *  @param[in] str a pointer to a buffer that will get the c-string
1773  *
1774  *  @return Returns the length of the string
1775  */
1776 
1777 /* FOUR uses */
1778 
1779 u32
dnsname_to_cstr(char * dest_cstr,const u8 * name)1780 dnsname_to_cstr(char* dest_cstr, const u8* name)
1781 {
1782 #if DEBUG
1783     yassert(name != NULL);
1784 #endif
1785 
1786     char* start = dest_cstr;
1787 
1788     u8 len;
1789 
1790     len = *name++;
1791 
1792     if(len != 0)
1793     {
1794         do
1795         {
1796             MEMCOPY(dest_cstr, name, len);
1797             dest_cstr += len;
1798             *dest_cstr++ = '.';
1799             name += len;
1800             len = *name++;
1801         }
1802         while(len != 0);
1803     }
1804     else
1805     {
1806         *dest_cstr++ = '.';
1807     }
1808 
1809     *dest_cstr = '\0';
1810 
1811     return (u32)(dest_cstr - start);
1812 }
1813 
1814 /** @brief Tests if two DNS labels are equals
1815  *
1816  *  Tests if two DNS labels are equals
1817  *
1818  *  @param[in] name_a a pointer to a dnsname to compare
1819  *  @param[in] name_b a pointer to a dnsname to compare
1820  *
1821  *  @return Returns TRUE if names are equal, else FALSE.
1822  */
1823 
1824 /* ELEVEN uses */
1825 
1826 #if !DNSCORE_HAS_MEMALIGN_ISSUES
1827 
1828 bool
dnslabel_equals(const u8 * name_a,const u8 * name_b)1829 dnslabel_equals(const u8* name_a, const u8* name_b)
1830 {
1831     u8 len = *name_a;
1832 
1833     if(len != *name_b)
1834     {
1835         return FALSE;
1836     }
1837 
1838     len++;
1839 
1840     /* Hopefully the compiler just does register renaming */
1841 
1842     const u32* name_a_32 = (const u32*)name_a;
1843     const u32* name_b_32 = (const u32*)name_b;
1844     int idx;
1845     int len4 = len & ~3;
1846     for(idx = 0; idx < len4; idx += 4)
1847     {
1848         if(GET_U32_AT(name_a[idx]) != GET_U32_AT(name_b[idx]))
1849         {
1850             return FALSE;
1851         }
1852     }
1853 
1854     /* Hopefully the compiler just does register renaming */
1855 
1856     name_a = (const u8*)name_a_32;
1857     name_b = (const u8*)name_b_32;
1858 
1859     switch(len & 3)
1860     {
1861         case 0:
1862             return TRUE;
1863         case 1:
1864             return name_a[idx] == name_b[idx];
1865         case 2:
1866             return GET_U16_AT(name_a[idx]) == GET_U16_AT(name_b[idx]);
1867         case 3:
1868             return (GET_U16_AT(name_a[idx]) == GET_U16_AT(name_b[idx])) && (name_a[idx+2] == name_b[idx+2]);
1869     }
1870 
1871     // icc complains here but is wrong.
1872     // this line cannot EVER be reached
1873 
1874     assert(FALSE); /* NOT zassert */
1875 
1876     return FALSE;
1877 }
1878 
1879 #else
1880 
1881 bool
dnslabel_equals(const u8 * name_a,const u8 * name_b)1882 dnslabel_equals(const u8* name_a, const u8* name_b)
1883 {
1884     u8 len = *name_a;
1885 
1886     if(*name_b == len)
1887     {
1888         return memcmp(name_a + 1, name_b + 1, len) == 0;
1889     }
1890 
1891     return FALSE;
1892 }
1893 
1894 #endif
1895 
1896 /** @brief Tests if two DNS labels are (case-insensitive) equals
1897  *
1898  *  Tests if two DNS labels are (case-insensitive) equals
1899  *
1900  *  @param[in] name_a a pointer to a dnsname to compare
1901  *  @param[in] name_b a pointer to a dnsname to compare
1902  *
1903  *  @return Returns TRUE if names are equal, else FALSE.
1904  */
1905 
1906 #if !DNSCORE_HAS_MEMALIGN_ISSUES
1907 
1908 bool
dnslabel_equals_ignorecase_left1(const u8 * name_a,const u8 * name_b)1909 dnslabel_equals_ignorecase_left1(const u8* name_a, const u8* name_b)
1910 {
1911     int len = (int)* name_a;
1912 
1913     if(len != (int)* name_b)
1914     {
1915         return FALSE;
1916     }
1917 
1918     len++;
1919 
1920     /*
1921      * Label size must match
1922      */
1923 
1924     int idx;
1925     int len4 = len & ~3;
1926     for(idx = 0; idx < len4; idx += 4)
1927     {
1928         if(!LOCASEEQUALSBY4(&name_a[idx], &name_b[idx])) /* can be used because left is locase */
1929         {
1930             return FALSE;
1931         }
1932     }
1933 
1934     /* Hopefully the compiler just does register renaming */
1935 
1936     switch(len & 3)
1937     {
1938         case 0:
1939             return TRUE;
1940         case 1:
1941             return LOCASEEQUALS(name_a[idx], name_b[idx]); /* can be used because left is locase */
1942         case 2:
1943             return LOCASEEQUALSBY2(&name_a[idx], &name_b[idx]); /* can be used because left is locase */
1944         case 3:
1945             return LOCASEEQUALSBY3(&name_a[idx], &name_b[idx]); /* can be used because left is locase */
1946     }
1947 
1948     assert(FALSE); /* NOT zassert */
1949 
1950     return FALSE;
1951 }
1952 
1953 bool
dnslabel_equals_ignorecase_left2(const u8 * name_a,const u8 * name_b)1954 dnslabel_equals_ignorecase_left2(const u8* name_a, const u8* name_b)
1955 {
1956     int len = (int)* name_a;
1957 
1958     if(len != (int)* name_b)
1959     {
1960         return FALSE;
1961     }
1962 
1963     for(int i = 1; i < len; ++i)
1964     {
1965         //if(__LOCASE_TABLE__[name_a[i]] != __LOCASE_TABLE__[name_b[i]])
1966         if(name_a[i] != __LOCASE_TABLE__[name_b[i]])
1967         {
1968             return FALSE;
1969         }
1970     }
1971 
1972     return TRUE;
1973 }
1974 
1975 bool
dnslabel_equals_ignorecase_left3(const u8 * name_a,const u8 * name_b)1976 dnslabel_equals_ignorecase_left3(const u8* name_a, const u8* name_b)
1977 {
1978     int len = (int)* name_a;
1979 
1980     if(len != (int)* name_b)
1981     {
1982         return FALSE;
1983     }
1984 
1985     for(name_a++, name_b++; len > 4; len -= 4, name_a += 4, name_b += 4)
1986     {
1987         //if(__LOCASE_TABLE__[name_a[i]] != __LOCASE_TABLE__[name_b[i]])
1988         u32 w = GET_U32_AT_P(name_a);
1989         u32 x = GET_U32_AT_P(name_b);
1990 
1991         if((w & 0xff) != __LOCASE_TABLE__[x & 0xff])
1992         {
1993             return FALSE;
1994         }
1995 
1996         w >>= 8;
1997         x >>= 8;
1998 
1999         if((w & 0xff) != __LOCASE_TABLE__[x & 0xff])
2000         {
2001             return FALSE;
2002         }
2003 
2004         w >>= 8;
2005         x >>= 8;
2006 
2007         if((w & 0xff) != __LOCASE_TABLE__[x & 0xff])
2008         {
2009             return FALSE;
2010         }
2011 
2012         w >>= 8;
2013         x >>= 8;
2014 
2015         if((w) != __LOCASE_TABLE__[x])
2016         {
2017             return FALSE;
2018         }
2019     }
2020 
2021     for(int i = 0; i < len; ++i)
2022     {
2023         //if(__LOCASE_TABLE__[name_a[i]] != __LOCASE_TABLE__[name_b[i]])
2024         if(name_a[i] != __LOCASE_TABLE__[name_b[i]])
2025         {
2026             return FALSE;
2027         }
2028     }
2029 
2030     return TRUE;
2031 }
2032 
2033 bool
dnslabel_equals_ignorecase_left4(const u8 * name_a,const u8 * name_b)2034 dnslabel_equals_ignorecase_left4(const u8* name_a, const u8* name_b)
2035 {
2036     int len = (int)* name_a;
2037 
2038     if(len != (int)* name_b)
2039     {
2040         return FALSE;
2041     }
2042 
2043     for(name_a++, name_b++; len > 4; len -= 4, name_a += 4, name_b += 4)
2044     {
2045         //if(__LOCASE_TABLE__[name_a[i]] != __LOCASE_TABLE__[name_b[i]])
2046         u32 w = GET_U32_AT_P(name_a);
2047         u32 x = GET_U32_AT_P(name_b);
2048 
2049         u32 z = (u32)__LOCASE_TABLE__[x & 0xff] |
2050                 ((u32)__LOCASE_TABLE__[(x >> 8) & 0xff] << 8) |
2051                 ((u32)__LOCASE_TABLE__[(x >> 16) & 0xff] << 16) |
2052                 ((u32)__LOCASE_TABLE__[(x >> 24) & 0xff] << 24);
2053 
2054         if(w != z)
2055         {
2056             return FALSE;
2057         }
2058     }
2059 
2060     for(int i = 0; i < len; ++i)
2061     {
2062         //if(__LOCASE_TABLE__[name_a[i]] != __LOCASE_TABLE__[name_b[i]])
2063         if(name_a[i] != __LOCASE_TABLE__[name_b[i]])
2064         {
2065             return FALSE;
2066         }
2067     }
2068 
2069     return TRUE;
2070 }
2071 
2072 bool
dnslabel_equals_ignorecase_left5(const u8 * name_a,const u8 * name_b)2073 dnslabel_equals_ignorecase_left5(const u8* name_a, const u8* name_b)
2074 {
2075     return strcasecmp((const char*)name_a, (const char*)name_b) == 0;
2076 }
2077 
2078 #else
2079 
2080 /**
2081  * This WILL work with label size too since a label size is 0->63
2082  * which is well outside the [A-Za-z] space.
2083  */
2084 
2085 bool
dnslabel_equals_ignorecase_left(const u8 * name_a,const u8 * name_b)2086 dnslabel_equals_ignorecase_left(const u8* name_a, const u8* name_b)
2087 {
2088     return strcasecmp((const char*)name_a, (const char*)name_b) == 0;
2089 }
2090 
2091 #endif
2092 
2093 /** @brief Tests if two DNS names are equals
2094  *
2095  *  Tests if two DNS labels are equals
2096  *
2097  *  @param[in] name_a a pointer to a dnsname to compare
2098  *  @param[in] name_b a pointer to a dnsname to compare
2099  *
2100  *  @return Returns TRUE if names are equal, else FALSE.
2101  */
2102 
2103 /* TWO uses */
2104 
2105 bool
dnsname_equals(const u8 * name_a,const u8 * name_b)2106 dnsname_equals(const u8* name_a, const u8* name_b)
2107 {
2108     int la = dnsname_len(name_a);
2109     int lb = dnsname_len(name_b);
2110 
2111     if(la == lb)
2112     {
2113         return memcmp(name_a, name_b, la) == 0;
2114     }
2115 
2116     return FALSE;
2117 }
2118 
2119 /*
2120  * Comparison of a name by label
2121  */
2122 
2123 int
dnsname_compare(const u8 * name_a,const u8 * name_b)2124 dnsname_compare(const u8* name_a, const u8* name_b)
2125 {
2126     for(;;)
2127     {
2128         s8 la = (s8)name_a[0];
2129         s8 lb = (s8)name_b[0];
2130 
2131         name_a++;
2132         name_b++;
2133 
2134         if(la == lb)
2135         {
2136             if( la > 0)
2137             {
2138                 int c =  memcmp(name_a, name_b, la);
2139 
2140                 if( c != 0)
2141                 {
2142                     return c;
2143                 }
2144             }
2145             else
2146             {
2147                 return 0;
2148             }
2149         }
2150         else
2151         {
2152             int c =  memcmp(name_a, name_b, MIN(la,lb));
2153 
2154             if( c == 0)
2155             {
2156                 c = la - lb;
2157             }
2158 
2159             return c;
2160         }
2161 
2162         name_a += la;
2163         name_b += lb;
2164     }
2165 }
2166 
2167 bool
dnsname_is_subdomain(const u8 * subdomain,const u8 * domain)2168 dnsname_is_subdomain(const u8* subdomain, const u8* domain)
2169 {
2170 #if !HAS_FULL_ASCII7
2171     u32 len = dnsname_len(domain);
2172     u32 sub_len = dnsname_len(subdomain);
2173 
2174     if(sub_len >= len)
2175     {
2176         subdomain += sub_len - len;
2177 
2178         if(domain[0] == subdomain[0])
2179         {
2180             int ret = memcmp(subdomain, domain, len);
2181             return ret == 0;
2182         }
2183     }
2184 #else
2185     dnsname_stack subdomain_stack;
2186     dnsname_stack domain_stack;
2187     s32 subdomain_top = dnsname_to_dnsname_stack(subdomain, &subdomain_stack);
2188     s32 domain_top = dnsname_to_dnsname_stack(domain, &domain_stack);
2189 
2190     if(subdomain_top >= domain_top)
2191     {
2192         for(int i = 0; i <= domain_top; ++i)
2193         {
2194             const u8 *sublabel = subdomain_stack.labels[i];
2195             const u8 *label = domain_stack.labels[i];
2196 
2197             if(!dnslabel_equals(sublabel, label))
2198             {
2199                 return FALSE;
2200             }
2201         }
2202 
2203         return TRUE;
2204     }
2205 #endif
2206 
2207     return FALSE;
2208 }
2209 
2210 /** @brief Tests if two DNS names are (ignore case) equals
2211  *
2212  *  Tests if two DNS labels are (ignore case) equals
2213  *
2214  *  @param[in] name_a a pointer to a LO-CASE dnsname to compare
2215  *  @param[in] name_b a pointer to a dnsname to compare
2216  *
2217  *  @return Returns TRUE if names are equal, else FALSE.
2218  */
2219 
2220 /* TWO uses */
2221 
2222 bool
dnsname_equals_ignorecase1(const u8 * name_a,const u8 * name_b)2223 dnsname_equals_ignorecase1(const u8* name_a, const u8* name_b)
2224 {
2225     int len;
2226 
2227     do
2228     {
2229         len = (int)*name_a++;
2230 
2231         if(len != (int)*name_b++)
2232         {
2233             return FALSE;
2234         }
2235 
2236         if(len == 0)
2237         {
2238             return TRUE;
2239         }
2240 
2241         while(len > 4 && (LOCASEEQUALSBY4(name_a++,name_b++)))
2242         {
2243             len--;
2244         }
2245 
2246         while(len > 0 && (LOCASEEQUALS(*name_a++,*name_b++)))
2247         {
2248             len--;
2249         }
2250     }
2251     while(len == 0);
2252 
2253     return FALSE;
2254 }
2255 
2256 bool
dnsname_equals_ignorecase2(const u8 * name_a,const u8 * name_b)2257 dnsname_equals_ignorecase2(const u8* name_a, const u8* name_b)
2258 {
2259     int len;
2260 
2261     for(int i = 0;; ++i)
2262     {
2263         len = (int)name_a[i];
2264 
2265         if(len != (int)name_b[i])
2266         {
2267             return FALSE;
2268         }
2269 
2270         if(len == 0)
2271         {
2272             return TRUE;
2273         }
2274 
2275         len += i;
2276 
2277         for(; i < len; ++i)
2278         {
2279             if(__LOCASE_TABLE__[name_a[i]] != __LOCASE_TABLE__[name_b[i]])
2280             {
2281                 return FALSE;
2282             }
2283         }
2284     }
2285 }
2286 
2287 bool
dnsname_equals_ignorecase3(const u8 * name_a,const u8 * name_b)2288 dnsname_equals_ignorecase3(const u8* name_a, const u8* name_b)
2289 {
2290     int len_a = dnsname_len(name_a);
2291     int len_b = dnsname_len(name_b);
2292     return ((len_a == len_b) && (strncasecmp((const char*)name_a, (const char*)name_b, len_a) == 0));
2293 }
2294 
2295 /** @brief Returns the full length of a dns name
2296  *
2297  *  Returns the full length of a dns name
2298  *
2299  *  @param[in] name a pointer to the dnsname
2300  *
2301  *  @return The length of the dnsname, "." ( zero ) included
2302  */
2303 
2304 /* SEVENTEEN uses (more or less) */
2305 
2306 u32
dnsname_len(const u8 * name)2307 dnsname_len(const u8 *name)
2308 {
2309     yassert(name != NULL);
2310 
2311     const u8 *start = name;
2312 
2313     u8 c;
2314 
2315     while((c = *name++) > 0)
2316     {
2317         name += c;
2318     }
2319 
2320     return name - start;
2321 }
2322 
2323 ya_result
dnsname_len_checked(const u8 * name)2324 dnsname_len_checked(const u8 *name)
2325 {
2326     yassert(name != NULL);
2327 
2328     ya_result total = 0;
2329 
2330     u8 c;
2331 
2332     while((c = *name++) > 0)
2333     {
2334         name += c;
2335         total += c;
2336         if(total > MAX_DOMAIN_LENGTH)
2337         {
2338             return DOMAIN_TOO_LONG;
2339         }
2340     }
2341 
2342     return total + 1;
2343 }
2344 
2345 
2346 s32
dnsname_len_with_limit(const u8 * name,const u8 * name_limit)2347 dnsname_len_with_limit(const u8 *name, const u8 *name_limit)
2348 {
2349     yassert(name != NULL);
2350 
2351     const u8 *start = name;
2352 
2353     u8 c;
2354 
2355     for(;;)
2356     {
2357         if(name >= name_limit)
2358         {
2359             return DOMAINNAME_INVALID;
2360         }
2361 
2362         c = *name;
2363 
2364         name += c;
2365 
2366         if(c == 0)
2367         {
2368             break;
2369         }
2370 
2371         ++name;
2372     }
2373 
2374     return name - start;
2375 }
2376 
2377 /* ONE use */
2378 
2379 u32
dnsname_getdepth(const u8 * name)2380 dnsname_getdepth(const u8 *name)
2381 {
2382     yassert(name != NULL);
2383 
2384     u32 d = 0;
2385 
2386     u8 c;
2387 
2388     while((c = *name) > 0)
2389     {
2390         name += c + 1;
2391         d++;
2392     }
2393 
2394     return d;
2395 }
2396 
2397 u8*
dnsname_dup(const u8 * src)2398 dnsname_dup(const u8* src)
2399 {
2400     u8 *dst;
2401     u32 len = dnsname_len(src);
2402     MALLOC_OR_DIE(u8*, dst, len, DNSNAMED_TAG);
2403     MEMCOPY(dst, src, len);
2404 
2405     return dst;
2406 }
2407 
2408 void
dnsname_free(u8 * ptr)2409 dnsname_free(u8* ptr)
2410 {
2411 #if DEBUG
2412     u32 len = dnsname_len(ptr);
2413     memset(ptr, 0xfe, len);
2414 #endif
2415     free(ptr);
2416 }
2417 
2418 /* ONE use */
2419 
2420 u32
dnsname_copy(u8 * dst,const u8 * src)2421 dnsname_copy(u8* dst, const u8* src)
2422 {
2423     u32 len = dnsname_len(src);
2424 
2425     MEMCOPY(dst, src, len);
2426 
2427     return len;
2428 }
2429 
2430 ya_result
dnsname_copy_checked(u8 * dst,const u8 * src)2431 dnsname_copy_checked(u8* dst, const u8* src)
2432 {
2433     ya_result len = dnsname_len_checked(src);
2434     if(ISOK(len))
2435     {
2436         MEMCOPY(dst, src, len);
2437     }
2438     return len;
2439 }
2440 
2441 /** @brief Canonizes a dns name.
2442  *
2443  *  Canonizes a dns name. (A.K.A : lo-cases it)
2444  *
2445  *  @param[in] src a pointer to the dns name
2446  *  @param[out] dst a pointer to a buffer that will hold the canonized dns name
2447  *
2448  *  @return The length of the dns name
2449  */
2450 
2451 /* TWELVE uses */
2452 
2453 u32
dnsname_canonize(const u8 * src,u8 * dst)2454 dnsname_canonize(const u8* src, u8* dst)
2455 {
2456     const u8* org = src;
2457 
2458     u32 len;
2459 
2460     for(;;)
2461     {
2462         len = *src++;
2463         *dst++ = len;
2464 
2465         if(len == 0)
2466         {
2467             break;
2468         }
2469 
2470         while(len > 0)
2471         {
2472             *dst++ = LOCASE(*src++); /* Works with the dns character set */
2473             len--;
2474         }
2475     }
2476 
2477     return (u32)(src - org);
2478 }
2479 
2480 /*****************************************************************************
2481  *
2482  * VECTOR
2483  *
2484  *****************************************************************************/
2485 
2486 /* NO use (test) */
2487 
2488 u32
dnslabel_vector_to_dnsname(const_dnslabel_vector_reference name,s32 top,u8 * str_start)2489 dnslabel_vector_to_dnsname(const_dnslabel_vector_reference name, s32 top, u8* str_start)
2490 {
2491     u8* str = str_start;
2492 
2493     const_dnslabel_vector_reference limit = &name[top];
2494 
2495     while(name <= limit)
2496     {
2497         const u8* label = *name++;
2498         u8 len = label[0] + 1;
2499         MEMCOPY(str, label, len);
2500         str += len;
2501     }
2502 
2503     *str++ = 0;
2504 
2505     return str - str_start;
2506 }
2507 
2508 /* NO use (test) */
2509 
2510 u32
dnslabel_vector_to_cstr(const_dnslabel_vector_reference name,s32 top,char * str)2511 dnslabel_vector_to_cstr(const_dnslabel_vector_reference name, s32 top, char* str)
2512 {
2513     const_dnslabel_vector_reference limit = &name[top];
2514 
2515     char* start = str;
2516 
2517     while(name < limit)
2518     {
2519         const u8* label = *name++;
2520         u8 len = *label++;
2521 
2522         MEMCOPY(str, label, len);
2523         str += len;
2524 
2525         *str++ = '.';
2526     }
2527 
2528     *str++ = '\0';
2529 
2530     return (u32)(str - start);
2531 }
2532 
2533 /* ONE use */
2534 
2535 u32
dnslabel_vector_dnslabel_to_dnsname(const u8 * prefix,const dnsname_vector * namestack,s32 bottom,u8 * str)2536 dnslabel_vector_dnslabel_to_dnsname(const u8 *prefix, const dnsname_vector *namestack, s32 bottom, u8 *str)
2537 {
2538     u8* start = str;
2539 
2540     u32 len = *prefix;
2541     MEMCOPY(str, prefix, len + 1);
2542     str += len + 1;
2543 
2544     const_dnslabel_vector_reference name = &namestack->labels[bottom];
2545     u32 top = (u32)namestack->size;
2546 
2547     while(bottom <= (s32)top)
2548     {
2549         const u8* label = *name++;
2550         u32 len = *label;
2551 
2552         MEMCOPY(str, label, len + 1);
2553         str += len + 1;
2554 
2555         bottom--;
2556     }
2557 
2558     *str++ = '\0';
2559 
2560     return (u32)(str - start);
2561 }
2562 
2563 u32
dnslabel_vector_len(const_dnslabel_vector_reference name,s32 top)2564 dnslabel_vector_len(const_dnslabel_vector_reference name, s32 top)
2565 {
2566     u32 ret = 1;
2567 
2568     for(s32 i = 0; i <= top; i++)
2569     {
2570         ret += name[i][0];
2571     }
2572 
2573     return ret;
2574 }
2575 
2576 /* ONE use */
2577 
2578 u32
dnsname_vector_sub_to_dnsname(const dnsname_vector * name,s32 from,u8 * name_start)2579 dnsname_vector_sub_to_dnsname(const dnsname_vector *name, s32 from, u8 *name_start)
2580 {
2581     u8* str = name_start;
2582 
2583     const_dnslabel_vector_reference limit = &name->labels[name->size];
2584     const_dnslabel_vector_reference labelp = &name->labels[from];
2585 
2586     while(labelp <= limit)
2587     {
2588         u32 len = *labelp[0] + 1;
2589         MEMCOPY(str, *labelp, len);
2590         str += len;
2591         labelp++;
2592     }
2593 
2594     *str++ = 0;
2595 
2596     return str - name_start;
2597 }
2598 
2599 /** @brief Divides a name into sections
2600  *
2601  *  Divides a name into sections.
2602  *  Writes a pointer to each label of the dnsname into an array
2603  *  "." is never put in there.
2604  *
2605  *  @param[in] name a pointer to the dnsname
2606  *  @param[out] sections a pointer to the target array of pointers
2607  *
2608  *  @return The index of the top-level label ("." is never put in there)
2609  */
2610 
2611 /* TWO uses */
2612 
2613 s32
dnsname_to_dnslabel_vector(const u8 * dns_name,dnslabel_vector_reference labels)2614 dnsname_to_dnslabel_vector(const u8 *dns_name, dnslabel_vector_reference labels)
2615 {
2616     yassert(dns_name != NULL && labels != NULL);
2617 
2618     s32 idx = -1;
2619     int offset = 0;
2620 
2621     for(;;)
2622     {
2623         u32 len = dns_name[offset];
2624 
2625         if(len == 0)
2626         {
2627             break;
2628         }
2629 
2630         labels[++idx] = &dns_name[offset];
2631         offset += len + 1;
2632     }
2633 
2634     return idx;
2635 }
2636 
2637 /** @brief Divides a name into sections
2638  *
2639  *  Divides a name into sections.
2640  *  Writes a pointer to each label of the dnsname into an array
2641  *  "." is never put in there.
2642  *
2643  *  @param[in] name a pointer to the dnsname
2644  *  @param[out] sections a pointer to the target array of pointers
2645  *
2646  *  @return The index of the top-level label ("." is never put in there)
2647  */
2648 
2649 /* TWENTY-ONE uses */
2650 
2651 s32
dnsname_to_dnsname_vector(const u8 * dns_name,dnsname_vector * name)2652 dnsname_to_dnsname_vector(const u8* dns_name, dnsname_vector* name)
2653 {
2654     yassert(dns_name != NULL && name != NULL);
2655 
2656     s32 size = dnsname_to_dnslabel_vector(dns_name, name->labels);
2657     name->size = size;
2658 
2659     return size;
2660 }
2661 
dnsname_vector_copy(dnsname_vector * dst,const dnsname_vector * src)2662 u32 dnsname_vector_copy(dnsname_vector* dst, const dnsname_vector* src)
2663 {
2664     dst->size = src->size;
2665     if(dst->size > 0)
2666     {
2667         memcpy(&dst->labels[0], &src->labels[0], sizeof(u8*) * dst->size);
2668     }
2669     return dst->size;
2670 }
2671 
2672 u32
dnsname_vector_len(dnsname_vector * name_vector)2673 dnsname_vector_len(dnsname_vector *name_vector)
2674 {
2675     u32 len = 1;
2676 
2677     for(s32 size = 0; size <= name_vector->size; size++)
2678     {
2679         len += name_vector->labels[size][0] + 1;
2680     }
2681 
2682     return len;
2683 }
2684 
2685 /*****************************************************************************
2686  *
2687  * STACK
2688  *
2689  *****************************************************************************/
2690 
2691 /** @brief Converts a stack of dns labels to a C string
2692  *
2693  *  Converts a stack of dns labels to a C string
2694  *
2695  *  @param[in] name a pointer to the dnslabel stack
2696  *  @param[in] top the index of the top of the stack
2697  *  @param[in] str a pointer to a buffer that will get the c-string
2698  *
2699  *  @return Returns the length of the string
2700  */
2701 
2702 /* ONE use */
2703 
2704 u32
dnslabel_stack_to_cstr(const_dnslabel_stack_reference name,s32 top,char * str)2705 dnslabel_stack_to_cstr(const_dnslabel_stack_reference name, s32 top, char* str)
2706 {
2707     char* start = str;
2708     if(top >= 0)
2709     {
2710         do
2711         {
2712             const u8* label = name[top];
2713             u8 len = *label++;
2714 
2715             MEMCOPY(str, label, len);
2716             str += len;
2717 
2718             *str++ = '.';
2719             top--;
2720         }
2721         while(top >= 0);
2722     }
2723     else
2724     {
2725         *str++ = '.';
2726     }
2727     *str++ = '\0';
2728 
2729     return (u32)(str - start);
2730 }
2731 
2732 /* ONE use */
2733 
2734 u32
dnslabel_stack_to_dnsname(const_dnslabel_stack_reference name,s32 top,u8 * str_start)2735 dnslabel_stack_to_dnsname(const_dnslabel_stack_reference name, s32 top, u8* str_start)
2736 {
2737 
2738     u8* str = str_start;
2739     const_dnslabel_stack_reference base = name;
2740 
2741     name += top;
2742 
2743     while(name >= base)
2744     {
2745         const u8* label = *name--;
2746         u32 len = *label;
2747 
2748         MEMCOPY(str, label, len + 1);
2749         str += len + 1;
2750     }
2751 
2752     *str++ = '\0';
2753 
2754     return (u32)(str - str_start);
2755 }
2756 
2757 s32
dnsname_to_dnslabel_stack(const u8 * dns_name,dnslabel_stack_reference labels)2758 dnsname_to_dnslabel_stack(const u8* dns_name, dnslabel_stack_reference labels)
2759 {
2760     s32 label_pointers_top = -1;
2761     const u8 * label_pointers[MAX_LABEL_COUNT];
2762 
2763     for(;;)
2764     {
2765         u8 len = *dns_name;
2766 
2767         if(len == 0)
2768         {
2769             break;
2770         }
2771 
2772         label_pointers[++label_pointers_top] = dns_name;
2773 
2774         dns_name += len + 1;
2775     }
2776 
2777     s32 size = label_pointers_top;
2778 
2779     const u8** labelp = labels;
2780     while(label_pointers_top >= 0)
2781     {
2782         *labelp++ = (u8*)label_pointers[label_pointers_top--];
2783     }
2784 
2785     return size;
2786 }
2787 
2788 /* ONE use */
2789 
2790 u32
dnsname_stack_to_dnsname(const dnsname_stack * name_stack,u8 * name_start)2791 dnsname_stack_to_dnsname(const dnsname_stack *name_stack, u8 *name_start)
2792 {
2793     u8* name = name_start;
2794 
2795     for(s32 size = name_stack->size; size >= 0; size--)
2796     {
2797         u32 len = name_stack->labels[size][0] + 1;
2798         MEMCOPY(name, name_stack->labels[size], len);
2799         name += len;
2800     }
2801 
2802     *name++ = '\0';
2803 
2804     return name - name_start;
2805 }
2806 
2807 u32
dnsname_stack_len(const dnsname_stack * name_stack)2808 dnsname_stack_len(const dnsname_stack* name_stack)
2809 {
2810     u32 len = 1;
2811 
2812     for(s32 size = 0; size <= name_stack->size; size++)
2813     {
2814         len += name_stack->labels[size][0] + 1;
2815     }
2816 
2817     return len;
2818 }
2819 
2820 /* TWO uses (debug) */
2821 
2822 u32
dnsname_stack_to_cstr(const dnsname_stack * name,char * str)2823 dnsname_stack_to_cstr(const dnsname_stack* name, char* str)
2824 {
2825     return dnslabel_stack_to_cstr(name->labels, name->size, str);
2826 }
2827 
2828 /* ONE use */
2829 
2830 bool
dnsname_equals_dnsname_stack(const u8 * str,const dnsname_stack * name)2831 dnsname_equals_dnsname_stack(const u8* str, const dnsname_stack* name)
2832 {
2833     s32 size = name->size;
2834 
2835     while(size >= 0)
2836     {
2837         const u8* label = name->labels[size];
2838         u8 len = *label;
2839 
2840         if(len != *str)
2841         {
2842             return FALSE;
2843         }
2844 
2845         label++;
2846         str++;
2847 
2848         if(memcmp(str, label, len) != 0)
2849         {
2850             return FALSE;
2851         }
2852 
2853         str += len;
2854 
2855         size--;
2856     }
2857 
2858     return *str == 0;
2859 }
2860 
2861 bool
dnsname_under_dnsname_stack(const u8 * str,const dnsname_stack * name)2862 dnsname_under_dnsname_stack(const u8* str, const dnsname_stack* name)
2863 {
2864     s32 size = name->size;
2865 
2866     while(size >= 0)
2867     {
2868         const u8* label = name->labels[size];
2869         u8 len = *label;
2870 
2871         if(len != *str)
2872         {
2873             return (len != 0);
2874         }
2875 
2876         label++;
2877         str++;
2878 
2879         if(memcmp(str, label, len) != 0)
2880         {
2881             return FALSE;
2882         }
2883 
2884         str += len;
2885 
2886         size--;
2887     }
2888 
2889     return *str == 0;
2890 }
2891 
2892 /* FOUR uses */
2893 
2894 s32
dnsname_stack_push_label(dnsname_stack * dns_name,const u8 * dns_label)2895 dnsname_stack_push_label(dnsname_stack* dns_name, const u8* dns_label)
2896 {
2897     yassert(dns_name != NULL && dns_label != NULL);
2898 
2899     dns_name->labels[++dns_name->size] = dns_label;
2900 
2901     return dns_name->size;
2902 }
2903 
2904 /* FOUR uses */
2905 
2906 s32
dnsname_stack_pop_label(dnsname_stack * name)2907 dnsname_stack_pop_label(dnsname_stack* name)
2908 {
2909     yassert(name != NULL);
2910 
2911 #if DEBUG
2912     name->labels[name->size] = (u8*)~0;
2913 #endif
2914 
2915     return name->size--;
2916 }
2917 
2918 s32
dnsname_to_dnsname_stack(const u8 * dns_name,dnsname_stack * name)2919 dnsname_to_dnsname_stack(const u8* dns_name, dnsname_stack* name)
2920 {
2921     s32 label_pointers_top = -1;
2922     u8 * label_pointers[MAX_LABEL_COUNT];
2923 
2924     for(;;)
2925     {
2926         u8 len = *dns_name;
2927 
2928         if(len == 0)
2929         {
2930             break;
2931         }
2932 
2933         label_pointers[++label_pointers_top] = (u8*)dns_name;
2934 
2935         dns_name += len + 1;
2936     }
2937 
2938     name->size = label_pointers_top;
2939 
2940     const u8** labelp = name->labels;
2941     while(label_pointers_top >= 0)
2942     {
2943         *labelp++ = label_pointers[label_pointers_top--];
2944     }
2945 
2946     return name->size;
2947 }
2948 
2949 /** @brief Allocates and duplicates a name with ZALLOC.
2950  *
2951  *  Allocates and duplicates a dns name with ZALLOC.
2952  *
2953  *  @param[in] name a pointer to the dnsname
2954  *
2955  *  @return A new instance of the dnsname.
2956  */
2957 
2958 u8*
dnsname_zdup(const u8 * name)2959 dnsname_zdup(const u8* name)
2960 {
2961     yassert(name != NULL);
2962 
2963     u32 len = dnsname_len(name);
2964 
2965     u8* dup;
2966 
2967     ZALLOC_OBJECT_ARRAY_OR_DIE(dup, u8, len, ZDB_NAME_TAG);
2968     MEMCOPY(dup, name, len); // nothing wrong here
2969 
2970     return dup;
2971 }
2972 
2973 /** @brief Converts a name to a newly allocated dns name with ZALLOC.
2974  *
2975  *  Converts a name to a newly allocated dns name with ZALLOC.
2976  *
2977  *  @param domainname a pointer to the name
2978  *
2979  *  @return a new instance of the name converted to a dnsname
2980  */
2981 
2982 u8*
dnsname_zdup_from_name(const char * domainname)2983 dnsname_zdup_from_name(const char* domainname)
2984 {
2985     yassert(domainname != NULL);
2986 
2987     u32 len = cstr_get_dnsname_len(domainname);
2988     ya_result ret;
2989     u8* dup;
2990 
2991     ZALLOC_OBJECT_ARRAY_OR_DIE(dup, u8, len, ZDB_NAME_TAG);
2992     if(ISOK(ret = cstr_to_dnsname_with_check(dup, domainname)))
2993     {
2994     }
2995     else
2996     {
2997         ZFREE_ARRAY(dup, len);
2998         dup = NULL;
2999     }
3000 
3001     return dup;
3002 }
3003 
3004 void
dnsname_zfree(u8 * name)3005 dnsname_zfree(u8 *name)
3006 {
3007     ZFREE_ARRAY(name, dnsname_len(name));
3008 }
3009 
3010 /** @brief Allocates and duplicates a label with ZALLOC.
3011  *
3012  *  Allocates and duplicates a label with ZALLOC.
3013  *
3014  *  @param[in] name a pointer to the label
3015  *
3016  *  @return A new instance of the label
3017  */
3018 
3019 u8*
dnslabel_zdup(const u8 * name)3020 dnslabel_zdup(const u8* name)
3021 {
3022     yassert(name != NULL);
3023 
3024     u32 len = name[0] + 1;
3025 
3026     u8* dup;
3027     ZALLOC_OBJECT_ARRAY_OR_DIE(dup, u8, len, ZDB_LABEL_TAG);
3028     MEMCOPY(dup, name, len);
3029 
3030     return dup;
3031 }
3032 
3033 void
dnslabel_zfree(u8 * name)3034 dnslabel_zfree(u8 *name)
3035 {
3036     u32 len = name[0] + 1;
3037     ZFREE_ARRAY(name, len);
3038     (void)len; // silences warning  on some build settings
3039 }
3040 
3041 /**
3042  *
3043  * Expands a compressed FQDN from a wire.
3044  *
3045  * @param wire_base_ the address of the wire buffer
3046  * @param wire_size the size of the wire buffer
3047  * @param compressed_fqdn the address, in the wire buffer, of the FQDN to expand
3048  * @param output_fqdn the address of the buffer that will get a copy of the expanded FQDN
3049  * @param output_fqdn_size the size of the buffer that will get a a copy of the expanded FQDN
3050  *
3051  * @return a pointer to the next byte after the expanded FQDN (ie: points to a type) or NULL if an error occurred
3052  */
3053 
3054 const u8*
dnsname_expand_compressed(const void * wire_base_,size_t wire_size,const void * compressed_fqdn,u8 * output_fqdn,u32 output_fqdn_size)3055 dnsname_expand_compressed(const void *wire_base_, size_t wire_size, const void *compressed_fqdn, u8 *output_fqdn, u32 output_fqdn_size)
3056 {
3057     const u8 *base = (const u8*)wire_base_;
3058     const u8 *p_limit = &base[wire_size];
3059 
3060     yassert(output_fqdn_size >= MAX_DOMAIN_LENGTH);
3061 
3062     u8 *buffer = output_fqdn;
3063     u8 * const buffer_limit = &buffer[output_fqdn_size];  // pointer to the byte that must never be reached
3064     const u8 *p = (const u8*)compressed_fqdn;
3065     const u8 *ret_ptr;
3066 
3067     if((p < base) || (p >= p_limit))
3068     {
3069         return NULL; /* EOF */
3070     }
3071 
3072     for(;;)
3073     {
3074         u8 len = *p++;  // get the next byte (length)
3075 
3076         if((len & 0xc0) == 0xc0)    // test if it's a compressed code
3077         {
3078             ret_ptr = p + 1;
3079 
3080             /* reposition the pointer */
3081             u32 new_offset = len & 0x3f;
3082             new_offset <<= 8;
3083             new_offset |= *p;
3084 
3085             p = &base[new_offset];
3086 
3087             if(p < p_limit) // ensure we are not outside the message
3088             {
3089                 break;
3090             }
3091 
3092             return NULL;
3093         }
3094 
3095         if((p + len >= p_limit) || (buffer + len + 1 >= buffer_limit))
3096         {
3097             return NULL;
3098         }
3099 
3100         *buffer++ = len;
3101 
3102         if(len == 0)
3103         {
3104             return p;
3105         }
3106 
3107         u8 *label_limit = &buffer[len];
3108         do
3109         {
3110             *buffer++ = tolower(*p++);
3111         }
3112         while(buffer < label_limit);
3113     }
3114 
3115     for(;;)
3116     {
3117         u8 len = *p;
3118 
3119         if((len & 0xc0) == 0xc0) /* EDF: better yet: cmp len, 192; jge  */
3120         {
3121             /* reposition the pointer */
3122             u32 new_offset = len & 0x3f;
3123             new_offset <<= 8;
3124             new_offset |= p[1];
3125 
3126             const u8* q = &base[new_offset];
3127 
3128             if(q < p)
3129             {
3130                 p = q;
3131                 continue;
3132             }
3133 
3134             return NULL;
3135         }
3136 
3137         if((p + len >= p_limit) || (buffer + len + 1>= buffer_limit))
3138         {
3139             return NULL;
3140         }
3141 
3142         *buffer++ = len;
3143 
3144         if(len == 0)
3145         {
3146             return ret_ptr;
3147         }
3148 
3149         ++p;
3150 
3151         u8 *label_limit = &buffer[len];
3152         do
3153         {
3154             *buffer++ = tolower(*p++);
3155         }
3156         while(buffer < label_limit);
3157     }
3158 
3159     // never reached
3160 }
3161 
3162 /**
3163  *
3164  * Skip a compressed FQDN from a wire to position right after the FQDN.
3165  *
3166  * @param wire_base_ the address of the wire buffer
3167  * @param wire_size the size of the wire buffer
3168  * @param compressed_fqdn the address, in the wire buffer, of the FQDN to expand
3169  *
3170  * @return a pointer to the next byte after the FQDN (ie: points to a type) or NULL if an error occurred
3171  */
3172 
3173 const u8*
dnsname_skip_compressed(const void * wire_base_,size_t wire_size,const void * compressed_fqdn)3174 dnsname_skip_compressed(const void *wire_base_, size_t wire_size, const void *compressed_fqdn)
3175 {
3176     const u8 *base = (const u8*)wire_base_;
3177 
3178     const u8 *p_limit = &base[wire_size];
3179 
3180     const u8 *p = (const u8*)compressed_fqdn;
3181 
3182     if((p < base) || (p >= p_limit))
3183     {
3184         return NULL; /* EOF */
3185     }
3186 
3187     for(;;)
3188     {
3189         u8 len = *p++;
3190 
3191         if((len & 0xc0) == 0xc0)
3192         {
3193             return p + 1;   // yes, read the purpose of the function
3194         }
3195 
3196         if(len == 0)
3197         {
3198             return p;
3199         }
3200 
3201         p += len;
3202 
3203         if(p >= p_limit)
3204         {
3205             return NULL;
3206         }
3207     }
3208 
3209     // never reached
3210 }
3211 
3212 /** @} */
3213