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 /* see if we have pushed the remaining string already,
173 * if so we use a label pointer to this string
175 ndr_err
= ndr_token_retrieve_cmp_fn(&ndr
->dns_string_list
, s
,
177 (comparison_fn_t
)strcmp
,
179 if (NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
182 if (offset
> 0x3FFF) {
183 return ndr_push_error(ndr
, NDR_ERR_STRING
,
184 "offset for dns string " \
186 "%u[%08X] > 0x00003FFF",
190 b
[0] = 0xC0 | (offset
>>8);
191 b
[1] = (offset
& 0xFF);
193 return ndr_push_bytes(ndr
, b
, 2);
196 complen
= strcspn(s
, ".");
198 /* we need to make sure the length fits into 6 bytes */
199 if (complen
> 0x3F) {
200 return ndr_push_error(ndr
, NDR_ERR_STRING
,
201 "component length %u[%08X] > " \
207 compname
= talloc_asprintf(ndr
, "%c%*.*s",
208 (unsigned char)complen
,
209 (unsigned char)complen
,
210 (unsigned char)complen
, s
);
211 NDR_ERR_HAVE_NO_MEMORY(compname
);
213 /* remember the current componemt + the rest of the string
214 * so it can be reused later
216 NDR_CHECK(ndr_token_store(ndr
, &ndr
->dns_string_list
, s
,
219 /* push just this component into the blob */
220 NDR_CHECK(ndr_push_bytes(ndr
, (const uint8_t *)compname
,
222 talloc_free(compname
);
228 /* if we reach the end of the string and have pushed the last component
229 * without using a label pointer, we need to terminate the string
231 return ndr_push_bytes(ndr
, (const uint8_t *)"", 1);
234 _PUBLIC_
enum ndr_err_code
ndr_pull_dns_txt_record(struct ndr_pull
*ndr
, int ndr_flags
, struct dns_txt_record
*r
)
236 NDR_PULL_CHECK_FLAGS(ndr
, ndr_flags
);
237 if (ndr_flags
& NDR_SCALARS
) {
238 enum ndr_err_code ndr_err
;
239 uint32_t data_size
= ndr
->data_size
;
240 uint32_t record_size
= 0;
241 ndr_err
= ndr_token_retrieve(&ndr
->array_size_list
, r
,
243 if (NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
244 NDR_PULL_NEED_BYTES(ndr
, record_size
);
245 ndr
->data_size
= ndr
->offset
+ record_size
;
247 NDR_CHECK(ndr_pull_align(ndr
, 1));
248 NDR_CHECK(ndr_pull_dnsp_string_list(ndr
, NDR_SCALARS
, &r
->txt
));
249 NDR_CHECK(ndr_pull_trailer_align(ndr
, 1));
250 ndr
->data_size
= data_size
;
252 if (ndr_flags
& NDR_BUFFERS
) {
254 return NDR_ERR_SUCCESS
;
257 _PUBLIC_
enum ndr_err_code
ndr_push_dns_res_rec(struct ndr_push
*ndr
,
259 const struct dns_res_rec
*r
)
261 uint32_t _flags_save_STRUCT
= ndr
->flags
;
262 uint32_t _saved_offset1
, _saved_offset2
;
264 ndr_set_flags(&ndr
->flags
, LIBNDR_PRINT_ARRAY_HEX
|
265 LIBNDR_FLAG_NOALIGN
);
266 if (ndr_flags
& NDR_SCALARS
) {
267 NDR_CHECK(ndr_push_align(ndr
, 4));
268 NDR_CHECK(ndr_push_dns_string(ndr
, NDR_SCALARS
, r
->name
));
269 NDR_CHECK(ndr_push_dns_qtype(ndr
, NDR_SCALARS
, r
->rr_type
));
270 NDR_CHECK(ndr_push_dns_qclass(ndr
, NDR_SCALARS
, r
->rr_class
));
271 NDR_CHECK(ndr_push_uint32(ndr
, NDR_SCALARS
, r
->ttl
));
272 _saved_offset1
= ndr
->offset
;
273 NDR_CHECK(ndr_push_uint16(ndr
, NDR_SCALARS
, 0));
275 NDR_CHECK(ndr_push_set_switch_value(ndr
, &r
->rdata
,
277 NDR_CHECK(ndr_push_dns_rdata(ndr
, NDR_SCALARS
,
279 if (r
->unexpected
.length
> 0) {
280 return ndr_push_error(ndr
,
282 "Invalid...Unexpected " \
283 "blob length is too " \
287 if (r
->unexpected
.length
> UINT16_MAX
) {
288 return ndr_push_error(ndr
, NDR_ERR_LENGTH
,
289 "Unexpected blob length "\
293 NDR_CHECK(ndr_push_bytes(ndr
, r
->unexpected
.data
,
294 r
->unexpected
.length
));
295 NDR_CHECK(ndr_push_trailer_align(ndr
, 4));
296 length
= ndr
->offset
- (_saved_offset1
+ 2);
297 _saved_offset2
= ndr
->offset
;
298 ndr
->offset
= _saved_offset1
;
299 NDR_CHECK(ndr_push_uint16(ndr
, NDR_SCALARS
, length
));
300 ndr
->offset
= _saved_offset2
;
302 if (ndr_flags
& NDR_BUFFERS
) {
303 NDR_CHECK(ndr_push_dns_rdata(ndr
, NDR_BUFFERS
,
306 ndr
->flags
= _flags_save_STRUCT
;
307 return NDR_ERR_SUCCESS
;
310 _PUBLIC_
enum ndr_err_code
ndr_pull_dns_res_rec(struct ndr_pull
*ndr
,
312 struct dns_res_rec
*r
)
314 uint32_t _flags_save_STRUCT
= ndr
->flags
;
315 uint32_t _saved_offset1
;
316 uint32_t pad
, length
;
318 ndr_set_flags(&ndr
->flags
, LIBNDR_PRINT_ARRAY_HEX
|
319 LIBNDR_FLAG_NOALIGN
);
320 if (ndr_flags
& NDR_SCALARS
) {
321 NDR_CHECK(ndr_pull_align(ndr
, 4));
322 NDR_CHECK(ndr_pull_dns_string(ndr
, NDR_SCALARS
, &r
->name
));
323 NDR_CHECK(ndr_pull_dns_qtype(ndr
, NDR_SCALARS
, &r
->rr_type
));
324 NDR_CHECK(ndr_pull_dns_qclass(ndr
, NDR_SCALARS
, &r
->rr_class
));
325 NDR_CHECK(ndr_pull_uint32(ndr
, NDR_SCALARS
, &r
->ttl
));
326 NDR_CHECK(ndr_pull_uint16(ndr
, NDR_SCALARS
, &r
->length
));
327 _saved_offset1
= ndr
->offset
;
329 NDR_CHECK(ndr_token_store(ndr
, &ndr
->array_size_list
,
332 NDR_CHECK(ndr_pull_set_switch_value(ndr
, &r
->rdata
,
334 NDR_CHECK(ndr_pull_dns_rdata(ndr
, NDR_SCALARS
,
337 ZERO_STRUCT(r
->rdata
);
339 length
= ndr
->offset
- _saved_offset1
;
340 if (length
> r
->length
) {
341 return ndr_pull_error(ndr
, NDR_ERR_LENGTH
, "TODO");
344 r
->unexpected
= data_blob_null
;
345 pad
= r
->length
- length
;
347 NDR_PULL_NEED_BYTES(ndr
, pad
);
348 r
->unexpected
= data_blob_talloc(ndr
->current_mem_ctx
,
352 if (r
->unexpected
.data
== NULL
) {
353 return ndr_pull_error(ndr
,
355 "Failed to allocate a " \
362 NDR_CHECK(ndr_pull_trailer_align(ndr
, 4));
364 if (ndr_flags
& NDR_BUFFERS
) {
365 NDR_CHECK(ndr_pull_dns_rdata(ndr
, NDR_BUFFERS
, &r
->rdata
));
367 ndr
->flags
= _flags_save_STRUCT
;
368 return NDR_ERR_SUCCESS
;