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