2 Unix SMB/CIFS implementation.
4 manipulate dns name structures
6 Copyright (C) 2010 Kai Blin <kai@samba.org>
8 Heavily based on nbtname.c which is:
10 Copyright (C) Andrew Tridgell 2005
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 3 of the License, or
15 (at your option) any later version.
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program. If not, see <http://www.gnu.org/licenses/>.
27 see rfc1002 for the detailed format of compressed names
31 #include "librpc/gen_ndr/ndr_dns.h"
32 #include "librpc/gen_ndr/ndr_misc.h"
33 #include "librpc/gen_ndr/ndr_dnsp.h"
34 #include "system/locale.h"
35 #include "lib/util/util_net.h"
37 /* don't allow an unlimited number of name components */
38 #define MAX_COMPONENTS 128
43 _PUBLIC_
void ndr_print_dns_string(struct ndr_print
*ndr
,
47 ndr_print_string(ndr
, name
, s
);
51 pull one component of a dns_string
53 static enum ndr_err_code
ndr_pull_component(struct ndr_pull
*ndr
,
59 unsigned int loops
= 0;
61 if (*offset
>= ndr
->data_size
) {
62 return ndr_pull_error(ndr
, NDR_ERR_STRING
,
63 "BAD DNS NAME component, bad offset");
65 len
= ndr
->data
[*offset
];
68 *max_offset
= MAX(*max_offset
, *offset
);
70 return NDR_ERR_SUCCESS
;
72 if ((len
& 0xC0) == 0xC0) {
73 /* its a label pointer */
74 if (1 + *offset
>= ndr
->data_size
) {
75 return ndr_pull_error(ndr
, NDR_ERR_STRING
,
76 "BAD DNS NAME component, " \
79 *max_offset
= MAX(*max_offset
, *offset
+ 2);
80 *offset
= ((len
&0x3F)<<8) | ndr
->data
[1 + *offset
];
81 *max_offset
= MAX(*max_offset
, *offset
);
85 if ((len
& 0xC0) != 0) {
86 /* its a reserved length field */
87 return ndr_pull_error(ndr
, NDR_ERR_STRING
,
88 "BAD DNS NAME component, " \
89 "reserved length field: 0x%02x",
92 if (*offset
+ len
+ 1 > ndr
->data_size
) {
93 return ndr_pull_error(ndr
, NDR_ERR_STRING
,
94 "BAD DNS NAME component, "\
97 *component
= (uint8_t*)talloc_strndup(ndr
,
98 (const char *)&ndr
->data
[1 + *offset
], len
);
99 NDR_ERR_HAVE_NO_MEMORY(*component
);
101 *max_offset
= MAX(*max_offset
, *offset
);
102 return NDR_ERR_SUCCESS
;
105 /* too many pointers */
106 return ndr_pull_error(ndr
, NDR_ERR_STRING
,
107 "BAD DNS NAME component, too many pointers");
111 pull a dns_string from the wire
113 _PUBLIC_
enum ndr_err_code
ndr_pull_dns_string(struct ndr_pull
*ndr
,
117 uint32_t offset
= ndr
->offset
;
118 uint32_t max_offset
= offset
;
119 unsigned num_components
;
122 if (!(ndr_flags
& NDR_SCALARS
)) {
123 return NDR_ERR_SUCCESS
;
126 name
= talloc_strdup(ndr
->current_mem_ctx
, "");
128 /* break up name into a list of components */
129 for (num_components
=0; num_components
<MAX_COMPONENTS
;
131 uint8_t *component
= NULL
;
132 NDR_CHECK(ndr_pull_component(ndr
, &component
, &offset
,
134 if (component
== NULL
) break;
135 if (num_components
> 0) {
136 name
= talloc_asprintf_append_buffer(name
, ".%s",
139 name
= talloc_asprintf_append_buffer(name
, "%s",
142 NDR_ERR_HAVE_NO_MEMORY(name
);
144 if (num_components
== MAX_COMPONENTS
) {
145 return ndr_pull_error(ndr
, NDR_ERR_STRING
,
146 "BAD DNS NAME too many components");
150 ndr
->offset
= max_offset
;
152 return NDR_ERR_SUCCESS
;
156 push a dns string to the wire
158 _PUBLIC_
enum ndr_err_code
ndr_push_dns_string(struct ndr_push
*ndr
,
162 if (!(ndr_flags
& NDR_SCALARS
)) {
163 return NDR_ERR_SUCCESS
;
167 enum ndr_err_code ndr_err
;
172 if (!(ndr
->flags
& LIBNDR_FLAG_NO_COMPRESSION
)) {
173 /* see if we have pushed the remaining string already,
174 * if so we use a label pointer to this string
176 ndr_err
= ndr_token_retrieve_cmp_fn(&ndr
->dns_string_list
, s
,
178 (comparison_fn_t
)strcmp
,
180 if (NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
183 if (offset
> 0x3FFF) {
184 return ndr_push_error(ndr
, NDR_ERR_STRING
,
185 "offset for dns string " \
187 "%u[%08X] > 0x00003FFF",
191 b
[0] = 0xC0 | (offset
>>8);
192 b
[1] = (offset
& 0xFF);
194 return ndr_push_bytes(ndr
, b
, 2);
198 complen
= strcspn(s
, ".");
200 /* we need to make sure the length fits into 6 bytes */
201 if (complen
> 0x3F) {
202 return ndr_push_error(ndr
, NDR_ERR_STRING
,
203 "component length %u[%08X] > " \
209 compname
= talloc_asprintf(ndr
, "%c%*.*s",
210 (unsigned char)complen
,
211 (unsigned char)complen
,
212 (unsigned char)complen
, s
);
213 NDR_ERR_HAVE_NO_MEMORY(compname
);
215 /* remember the current component + the rest of the string
216 * so it can be reused later
218 if (!(ndr
->flags
& LIBNDR_FLAG_NO_COMPRESSION
)) {
219 NDR_CHECK(ndr_token_store(ndr
, &ndr
->dns_string_list
, s
,
223 /* push just this component into the blob */
224 NDR_CHECK(ndr_push_bytes(ndr
, (const uint8_t *)compname
,
226 talloc_free(compname
);
232 /* if we reach the end of the string and have pushed the last component
233 * without using a label pointer, we need to terminate the string
235 return ndr_push_bytes(ndr
, (const uint8_t *)"", 1);
238 _PUBLIC_
enum ndr_err_code
ndr_pull_dns_txt_record(struct ndr_pull
*ndr
, int ndr_flags
, struct dns_txt_record
*r
)
240 NDR_PULL_CHECK_FLAGS(ndr
, ndr_flags
);
241 if (ndr_flags
& NDR_SCALARS
) {
242 enum ndr_err_code ndr_err
;
243 uint32_t data_size
= ndr
->data_size
;
244 uint32_t record_size
= 0;
245 ndr_err
= ndr_token_retrieve(&ndr
->array_size_list
, r
,
247 if (NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
248 NDR_PULL_NEED_BYTES(ndr
, record_size
);
249 ndr
->data_size
= ndr
->offset
+ record_size
;
251 NDR_CHECK(ndr_pull_align(ndr
, 1));
252 NDR_CHECK(ndr_pull_dnsp_string_list(ndr
, NDR_SCALARS
, &r
->txt
));
253 NDR_CHECK(ndr_pull_trailer_align(ndr
, 1));
254 ndr
->data_size
= data_size
;
256 if (ndr_flags
& NDR_BUFFERS
) {
258 return NDR_ERR_SUCCESS
;
261 _PUBLIC_
enum ndr_err_code
ndr_push_dns_res_rec(struct ndr_push
*ndr
,
263 const struct dns_res_rec
*r
)
265 uint32_t _flags_save_STRUCT
= ndr
->flags
;
266 uint32_t _saved_offset1
, _saved_offset2
;
268 ndr_set_flags(&ndr
->flags
, LIBNDR_PRINT_ARRAY_HEX
|
269 LIBNDR_FLAG_NOALIGN
);
270 if (ndr_flags
& NDR_SCALARS
) {
271 uint32_t _flags_save_name
= ndr
->flags
;
273 NDR_CHECK(ndr_push_align(ndr
, 4));
275 switch (r
->rr_type
) {
278 ndr_set_flags(&ndr
->flags
, LIBNDR_FLAG_NO_COMPRESSION
);
283 NDR_CHECK(ndr_push_dns_string(ndr
, NDR_SCALARS
, r
->name
));
284 ndr
->flags
= _flags_save_name
;
286 NDR_CHECK(ndr_push_dns_qtype(ndr
, NDR_SCALARS
, r
->rr_type
));
287 NDR_CHECK(ndr_push_dns_qclass(ndr
, NDR_SCALARS
, r
->rr_class
));
288 NDR_CHECK(ndr_push_uint32(ndr
, NDR_SCALARS
, r
->ttl
));
289 _saved_offset1
= ndr
->offset
;
290 NDR_CHECK(ndr_push_uint16(ndr
, NDR_SCALARS
, 0));
292 NDR_CHECK(ndr_push_set_switch_value(ndr
, &r
->rdata
,
294 NDR_CHECK(ndr_push_dns_rdata(ndr
, NDR_SCALARS
,
296 if (r
->unexpected
.length
> 0) {
297 return ndr_push_error(ndr
,
299 "Invalid...Unexpected " \
300 "blob length is too " \
304 if (r
->unexpected
.length
> UINT16_MAX
) {
305 return ndr_push_error(ndr
, NDR_ERR_LENGTH
,
306 "Unexpected blob length "\
310 NDR_CHECK(ndr_push_bytes(ndr
, r
->unexpected
.data
,
311 r
->unexpected
.length
));
312 NDR_CHECK(ndr_push_trailer_align(ndr
, 4));
313 length
= ndr
->offset
- (_saved_offset1
+ 2);
314 _saved_offset2
= ndr
->offset
;
315 ndr
->offset
= _saved_offset1
;
316 NDR_CHECK(ndr_push_uint16(ndr
, NDR_SCALARS
, length
));
317 ndr
->offset
= _saved_offset2
;
319 if (ndr_flags
& NDR_BUFFERS
) {
320 NDR_CHECK(ndr_push_dns_rdata(ndr
, NDR_BUFFERS
,
323 ndr
->flags
= _flags_save_STRUCT
;
324 return NDR_ERR_SUCCESS
;
327 _PUBLIC_
enum ndr_err_code
ndr_pull_dns_res_rec(struct ndr_pull
*ndr
,
329 struct dns_res_rec
*r
)
331 uint32_t _flags_save_STRUCT
= ndr
->flags
;
332 uint32_t _saved_offset1
;
333 uint32_t pad
, length
;
335 ndr_set_flags(&ndr
->flags
, LIBNDR_PRINT_ARRAY_HEX
|
336 LIBNDR_FLAG_NOALIGN
);
337 if (ndr_flags
& NDR_SCALARS
) {
338 NDR_CHECK(ndr_pull_align(ndr
, 4));
339 NDR_CHECK(ndr_pull_dns_string(ndr
, NDR_SCALARS
, &r
->name
));
340 NDR_CHECK(ndr_pull_dns_qtype(ndr
, NDR_SCALARS
, &r
->rr_type
));
341 NDR_CHECK(ndr_pull_dns_qclass(ndr
, NDR_SCALARS
, &r
->rr_class
));
342 NDR_CHECK(ndr_pull_uint32(ndr
, NDR_SCALARS
, &r
->ttl
));
343 NDR_CHECK(ndr_pull_uint16(ndr
, NDR_SCALARS
, &r
->length
));
344 _saved_offset1
= ndr
->offset
;
346 NDR_CHECK(ndr_token_store(ndr
, &ndr
->array_size_list
,
349 NDR_CHECK(ndr_pull_set_switch_value(ndr
, &r
->rdata
,
351 NDR_CHECK(ndr_pull_dns_rdata(ndr
, NDR_SCALARS
,
354 ZERO_STRUCT(r
->rdata
);
356 length
= ndr
->offset
- _saved_offset1
;
357 if (length
> r
->length
) {
358 return ndr_pull_error(ndr
, NDR_ERR_LENGTH
, "TODO");
361 r
->unexpected
= data_blob_null
;
362 pad
= r
->length
- length
;
364 NDR_PULL_NEED_BYTES(ndr
, pad
);
365 r
->unexpected
= data_blob_talloc(ndr
->current_mem_ctx
,
369 if (r
->unexpected
.data
== NULL
) {
370 return ndr_pull_error(ndr
,
372 "Failed to allocate a " \
379 NDR_CHECK(ndr_pull_trailer_align(ndr
, 4));
381 if (ndr_flags
& NDR_BUFFERS
) {
382 NDR_CHECK(ndr_pull_dns_rdata(ndr
, NDR_BUFFERS
, &r
->rdata
));
384 ndr
->flags
= _flags_save_STRUCT
;
385 return NDR_ERR_SUCCESS
;