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 "system/locale.h"
34 #include "lib/util/util_net.h"
36 /* don't allow an unlimited number of name components */
37 #define MAX_COMPONENTS 128
42 _PUBLIC_
void ndr_print_dns_string(struct ndr_print
*ndr
,
46 ndr_print_string(ndr
, name
, s
);
50 pull one component of a dns_string
52 static enum ndr_err_code
ndr_pull_component(struct ndr_pull
*ndr
,
58 unsigned int loops
= 0;
60 if (*offset
>= ndr
->data_size
) {
61 return ndr_pull_error(ndr
, NDR_ERR_STRING
,
62 "BAD DNS NAME component, bad offset");
64 len
= ndr
->data
[*offset
];
67 *max_offset
= MAX(*max_offset
, *offset
);
69 return NDR_ERR_SUCCESS
;
71 if ((len
& 0xC0) == 0xC0) {
72 /* its a label pointer */
73 if (1 + *offset
>= ndr
->data_size
) {
74 return ndr_pull_error(ndr
, NDR_ERR_STRING
,
75 "BAD DNS NAME component, " \
78 *max_offset
= MAX(*max_offset
, *offset
+ 2);
79 *offset
= ((len
&0x3F)<<8) | ndr
->data
[1 + *offset
];
80 *max_offset
= MAX(*max_offset
, *offset
);
84 if ((len
& 0xC0) != 0) {
85 /* its a reserved length field */
86 return ndr_pull_error(ndr
, NDR_ERR_STRING
,
87 "BAD DNS NAME component, " \
88 "reserved length field: 0x%02x",
91 if (*offset
+ len
+ 1 > ndr
->data_size
) {
92 return ndr_pull_error(ndr
, NDR_ERR_STRING
,
93 "BAD DNS NAME component, "\
96 *component
= (uint8_t*)talloc_strndup(ndr
,
97 (const char *)&ndr
->data
[1 + *offset
], len
);
98 NDR_ERR_HAVE_NO_MEMORY(*component
);
100 *max_offset
= MAX(*max_offset
, *offset
);
101 return NDR_ERR_SUCCESS
;
104 /* too many pointers */
105 return ndr_pull_error(ndr
, NDR_ERR_STRING
,
106 "BAD DNS NAME component, too many pointers");
110 pull a dns_string from the wire
112 _PUBLIC_
enum ndr_err_code
ndr_pull_dns_string(struct ndr_pull
*ndr
,
116 uint32_t offset
= ndr
->offset
;
117 uint32_t max_offset
= offset
;
118 unsigned num_components
;
121 if (!(ndr_flags
& NDR_SCALARS
)) {
122 return NDR_ERR_SUCCESS
;
125 name
= talloc_strdup(ndr
->current_mem_ctx
, "");
127 /* break up name into a list of components */
128 for (num_components
=0; num_components
<MAX_COMPONENTS
;
130 uint8_t *component
= NULL
;
131 NDR_CHECK(ndr_pull_component(ndr
, &component
, &offset
,
133 if (component
== NULL
) break;
134 if (num_components
> 0) {
135 name
= talloc_asprintf_append_buffer(name
, ".%s",
138 name
= talloc_asprintf_append_buffer(name
, "%s",
141 NDR_ERR_HAVE_NO_MEMORY(name
);
143 if (num_components
== MAX_COMPONENTS
) {
144 return ndr_pull_error(ndr
, NDR_ERR_STRING
,
145 "BAD DNS NAME too many components");
149 ndr
->offset
= max_offset
;
151 return NDR_ERR_SUCCESS
;
155 push a dns string to the wire
157 _PUBLIC_
enum ndr_err_code
ndr_push_dns_string(struct ndr_push
*ndr
,
161 if (!(ndr_flags
& NDR_SCALARS
)) {
162 return NDR_ERR_SUCCESS
;
166 enum ndr_err_code ndr_err
;
171 /* see if we have pushed the remaing string allready,
172 * if so we use a label pointer to this string
174 ndr_err
= ndr_token_retrieve_cmp_fn(&ndr
->dns_string_list
, s
,
176 (comparison_fn_t
)strcmp
,
178 if (NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
181 if (offset
> 0x3FFF) {
182 return ndr_push_error(ndr
, NDR_ERR_STRING
,
183 "offset for dns string " \
185 "%u[%08X] > 0x00003FFF",
189 b
[0] = 0xC0 | (offset
>>8);
190 b
[1] = (offset
& 0xFF);
192 return ndr_push_bytes(ndr
, b
, 2);
195 complen
= strcspn(s
, ".");
197 /* we need to make sure the length fits into 6 bytes */
198 if (complen
> 0x3F) {
199 return ndr_push_error(ndr
, NDR_ERR_STRING
,
200 "component length %u[%08X] > " \
206 compname
= talloc_asprintf(ndr
, "%c%*.*s",
207 (unsigned char)complen
,
208 (unsigned char)complen
,
209 (unsigned char)complen
, s
);
210 NDR_ERR_HAVE_NO_MEMORY(compname
);
212 /* remember the current componemt + the rest of the string
213 * so it can be reused later
215 NDR_CHECK(ndr_token_store(ndr
, &ndr
->dns_string_list
, s
,
218 /* push just this component into the blob */
219 NDR_CHECK(ndr_push_bytes(ndr
, (const uint8_t *)compname
,
221 talloc_free(compname
);
227 /* if we reach the end of the string and have pushed the last component
228 * without using a label pointer, we need to terminate the string
230 return ndr_push_bytes(ndr
, (const uint8_t *)"", 1);
233 _PUBLIC_
enum ndr_err_code
ndr_push_dns_res_rec(struct ndr_push
*ndr
,
235 const struct dns_res_rec
*r
)
237 uint32_t _flags_save_STRUCT
= ndr
->flags
;
238 uint32_t _saved_offset1
, _saved_offset2
;
240 ndr_set_flags(&ndr
->flags
, LIBNDR_PRINT_ARRAY_HEX
|
241 LIBNDR_FLAG_NOALIGN
);
242 if (ndr_flags
& NDR_SCALARS
) {
243 NDR_CHECK(ndr_push_align(ndr
, 4));
244 NDR_CHECK(ndr_push_dns_string(ndr
, NDR_SCALARS
, r
->name
));
245 NDR_CHECK(ndr_push_dns_qtype(ndr
, NDR_SCALARS
, r
->rr_type
));
246 NDR_CHECK(ndr_push_dns_qclass(ndr
, NDR_SCALARS
, r
->rr_class
));
247 NDR_CHECK(ndr_push_uint32(ndr
, NDR_SCALARS
, r
->ttl
));
248 _saved_offset1
= ndr
->offset
;
249 NDR_CHECK(ndr_push_uint16(ndr
, NDR_SCALARS
, 0));
251 NDR_CHECK(ndr_push_set_switch_value(ndr
, &r
->rdata
,
253 NDR_CHECK(ndr_push_dns_rdata(ndr
, NDR_SCALARS
,
255 if (r
->unexpected
.length
> 0) {
256 return ndr_push_error(ndr
,
258 "Invalid...Unexpected " \
259 "blob length is too " \
263 if (r
->unexpected
.length
> UINT16_MAX
) {
264 return ndr_push_error(ndr
, NDR_ERR_LENGTH
,
265 "Unexpected blob length "\
269 NDR_CHECK(ndr_push_bytes(ndr
, r
->unexpected
.data
,
270 r
->unexpected
.length
));
271 NDR_CHECK(ndr_push_trailer_align(ndr
, 4));
272 length
= ndr
->offset
- (_saved_offset1
+ 2);
273 _saved_offset2
= ndr
->offset
;
274 ndr
->offset
= _saved_offset1
;
275 NDR_CHECK(ndr_push_uint16(ndr
, NDR_SCALARS
, length
));
276 ndr
->offset
= _saved_offset2
;
278 if (ndr_flags
& NDR_BUFFERS
) {
279 NDR_CHECK(ndr_push_dns_rdata(ndr
, NDR_BUFFERS
,
282 ndr
->flags
= _flags_save_STRUCT
;
283 return NDR_ERR_SUCCESS
;
286 _PUBLIC_
enum ndr_err_code
ndr_pull_dns_res_rec(struct ndr_pull
*ndr
,
288 struct dns_res_rec
*r
)
290 uint32_t _flags_save_STRUCT
= ndr
->flags
;
291 uint32_t _saved_offset1
;
292 uint32_t pad
, length
;
294 ndr_set_flags(&ndr
->flags
, LIBNDR_PRINT_ARRAY_HEX
|
295 LIBNDR_FLAG_NOALIGN
);
296 if (ndr_flags
& NDR_SCALARS
) {
297 NDR_CHECK(ndr_pull_align(ndr
, 4));
298 NDR_CHECK(ndr_pull_dns_string(ndr
, NDR_SCALARS
, &r
->name
));
299 NDR_CHECK(ndr_pull_dns_qtype(ndr
, NDR_SCALARS
, &r
->rr_type
));
300 NDR_CHECK(ndr_pull_dns_qclass(ndr
, NDR_SCALARS
, &r
->rr_class
));
301 NDR_CHECK(ndr_pull_uint32(ndr
, NDR_SCALARS
, &r
->ttl
));
302 NDR_CHECK(ndr_pull_uint16(ndr
, NDR_SCALARS
, &r
->length
));
303 _saved_offset1
= ndr
->offset
;
305 NDR_CHECK(ndr_pull_set_switch_value(ndr
, &r
->rdata
,
307 NDR_CHECK(ndr_pull_dns_rdata(ndr
, NDR_SCALARS
,
310 ZERO_STRUCT(r
->rdata
);
312 length
= ndr
->offset
- _saved_offset1
;
313 if (length
> r
->length
) {
314 return ndr_pull_error(ndr
, NDR_ERR_LENGTH
, "TODO");
317 r
->unexpected
= data_blob_null
;
318 pad
= r
->length
- length
;
320 NDR_PULL_NEED_BYTES(ndr
, pad
);
321 r
->unexpected
= data_blob_talloc(ndr
->current_mem_ctx
,
325 if (r
->unexpected
.data
== NULL
) {
326 return ndr_pull_error(ndr
,
328 "Failed to allocate a " \
335 NDR_CHECK(ndr_pull_trailer_align(ndr
, 4));
337 if (ndr_flags
& NDR_BUFFERS
) {
338 NDR_CHECK(ndr_pull_dns_rdata(ndr
, NDR_BUFFERS
, &r
->rdata
));
340 ndr
->flags
= _flags_save_STRUCT
;
341 return NDR_ERR_SUCCESS
;