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"
36 #include "ndr_dns_utils.h"
38 /* don't allow an unlimited number of name components */
39 #define MAX_COMPONENTS 128
44 _PUBLIC_
void ndr_print_dns_string(struct ndr_print
*ndr
,
48 ndr_print_string(ndr
, name
, s
);
52 pull one component of a dns_string
54 static enum ndr_err_code
ndr_pull_component(struct ndr_pull
*ndr
,
60 unsigned int loops
= 0;
62 if (*offset
>= ndr
->data_size
) {
63 return ndr_pull_error(ndr
, NDR_ERR_STRING
,
64 "BAD DNS NAME component, bad offset");
66 len
= ndr
->data
[*offset
];
69 *max_offset
= MAX(*max_offset
, *offset
);
71 return NDR_ERR_SUCCESS
;
73 if ((len
& 0xC0) == 0xC0) {
74 /* its a label pointer */
75 if (1 + *offset
>= ndr
->data_size
) {
76 return ndr_pull_error(ndr
, NDR_ERR_STRING
,
77 "BAD DNS NAME component, " \
80 *max_offset
= MAX(*max_offset
, *offset
+ 2);
81 *offset
= ((len
&0x3F)<<8) | ndr
->data
[1 + *offset
];
82 *max_offset
= MAX(*max_offset
, *offset
);
86 if ((len
& 0xC0) != 0) {
87 /* its a reserved length field */
88 return ndr_pull_error(ndr
, NDR_ERR_STRING
,
89 "BAD DNS NAME component, " \
90 "reserved length field: 0x%02x",
93 if (*offset
+ len
+ 1 > ndr
->data_size
) {
94 return ndr_pull_error(ndr
, NDR_ERR_STRING
,
95 "BAD DNS NAME component, "\
98 *component
= (uint8_t*)talloc_strndup(ndr
,
99 (const char *)&ndr
->data
[1 + *offset
], len
);
100 NDR_ERR_HAVE_NO_MEMORY(*component
);
102 *max_offset
= MAX(*max_offset
, *offset
);
103 return NDR_ERR_SUCCESS
;
106 /* too many pointers */
107 return ndr_pull_error(ndr
, NDR_ERR_STRING
,
108 "BAD DNS NAME component, too many pointers");
112 pull a dns_string from the wire
114 _PUBLIC_
enum ndr_err_code
ndr_pull_dns_string(struct ndr_pull
*ndr
,
118 uint32_t offset
= ndr
->offset
;
119 uint32_t max_offset
= offset
;
120 unsigned num_components
;
123 if (!(ndr_flags
& NDR_SCALARS
)) {
124 return NDR_ERR_SUCCESS
;
127 name
= talloc_strdup(ndr
->current_mem_ctx
, "");
129 /* break up name into a list of components */
130 for (num_components
=0; num_components
<MAX_COMPONENTS
;
132 uint8_t *component
= NULL
;
133 NDR_CHECK(ndr_pull_component(ndr
, &component
, &offset
,
135 if (component
== NULL
) break;
136 if (num_components
> 0) {
137 name
= talloc_asprintf_append_buffer(name
, ".%s",
140 name
= talloc_asprintf_append_buffer(name
, "%s",
143 NDR_ERR_HAVE_NO_MEMORY(name
);
145 if (num_components
== MAX_COMPONENTS
) {
146 return ndr_pull_error(ndr
, NDR_ERR_STRING
,
147 "BAD DNS NAME too many components");
151 ndr
->offset
= max_offset
;
153 return NDR_ERR_SUCCESS
;
157 push a dns string to the wire
159 _PUBLIC_
enum ndr_err_code
ndr_push_dns_string(struct ndr_push
*ndr
,
163 return ndr_push_dns_string_list(ndr
,
164 &ndr
->dns_string_list
,
170 _PUBLIC_
enum ndr_err_code
ndr_pull_dns_txt_record(struct ndr_pull
*ndr
, int ndr_flags
, struct dns_txt_record
*r
)
172 NDR_PULL_CHECK_FLAGS(ndr
, ndr_flags
);
173 if (ndr_flags
& NDR_SCALARS
) {
174 enum ndr_err_code ndr_err
;
175 uint32_t data_size
= ndr
->data_size
;
176 uint32_t record_size
= 0;
177 ndr_err
= ndr_token_retrieve(&ndr
->array_size_list
, r
,
179 if (NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
180 NDR_PULL_NEED_BYTES(ndr
, record_size
);
181 ndr
->data_size
= ndr
->offset
+ record_size
;
183 NDR_CHECK(ndr_pull_align(ndr
, 1));
184 NDR_CHECK(ndr_pull_dnsp_string_list(ndr
, NDR_SCALARS
, &r
->txt
));
185 NDR_CHECK(ndr_pull_trailer_align(ndr
, 1));
186 ndr
->data_size
= data_size
;
188 if (ndr_flags
& NDR_BUFFERS
) {
190 return NDR_ERR_SUCCESS
;
193 _PUBLIC_
enum ndr_err_code
ndr_push_dns_res_rec(struct ndr_push
*ndr
,
195 const struct dns_res_rec
*r
)
197 uint32_t _flags_save_STRUCT
= ndr
->flags
;
198 uint32_t _saved_offset1
, _saved_offset2
;
200 ndr_set_flags(&ndr
->flags
, LIBNDR_PRINT_ARRAY_HEX
|
201 LIBNDR_FLAG_NOALIGN
);
202 if (ndr_flags
& NDR_SCALARS
) {
203 uint32_t _flags_save_name
= ndr
->flags
;
205 NDR_CHECK(ndr_push_align(ndr
, 4));
207 switch (r
->rr_type
) {
210 ndr_set_flags(&ndr
->flags
, LIBNDR_FLAG_NO_COMPRESSION
);
215 NDR_CHECK(ndr_push_dns_string(ndr
, NDR_SCALARS
, r
->name
));
216 ndr
->flags
= _flags_save_name
;
218 NDR_CHECK(ndr_push_dns_qtype(ndr
, NDR_SCALARS
, r
->rr_type
));
219 NDR_CHECK(ndr_push_dns_qclass(ndr
, NDR_SCALARS
, r
->rr_class
));
220 NDR_CHECK(ndr_push_uint32(ndr
, NDR_SCALARS
, r
->ttl
));
221 _saved_offset1
= ndr
->offset
;
222 NDR_CHECK(ndr_push_uint16(ndr
, NDR_SCALARS
, 0));
224 uint32_t _saved_offset3
;
226 NDR_CHECK(ndr_push_set_switch_value(ndr
, &r
->rdata
,
228 _saved_offset3
= ndr
->offset
;
229 NDR_CHECK(ndr_push_dns_rdata(ndr
, NDR_SCALARS
,
231 if ((ndr
->offset
!= _saved_offset3
) &&
232 (r
->unexpected
.length
> 0)) {
234 * ndr_push_dns_rdata pushed a known
235 * record, but we have something
236 * unexpected. That's invalid.
238 return ndr_push_error(ndr
,
240 "Invalid...Unexpected " \
241 "blob length is too " \
245 if (r
->unexpected
.length
> UINT16_MAX
) {
246 return ndr_push_error(ndr
, NDR_ERR_LENGTH
,
247 "Unexpected blob length "\
251 NDR_CHECK(ndr_push_bytes(ndr
, r
->unexpected
.data
,
252 r
->unexpected
.length
));
253 NDR_CHECK(ndr_push_trailer_align(ndr
, 4));
254 length
= ndr
->offset
- (_saved_offset1
+ 2);
255 _saved_offset2
= ndr
->offset
;
256 ndr
->offset
= _saved_offset1
;
257 NDR_CHECK(ndr_push_uint16(ndr
, NDR_SCALARS
, length
));
258 ndr
->offset
= _saved_offset2
;
260 if (ndr_flags
& NDR_BUFFERS
) {
261 NDR_CHECK(ndr_push_dns_rdata(ndr
, NDR_BUFFERS
,
264 ndr
->flags
= _flags_save_STRUCT
;
265 return NDR_ERR_SUCCESS
;
268 _PUBLIC_
enum ndr_err_code
ndr_pull_dns_res_rec(struct ndr_pull
*ndr
,
270 struct dns_res_rec
*r
)
272 uint32_t _flags_save_STRUCT
= ndr
->flags
;
273 uint32_t _saved_offset1
;
274 uint32_t pad
, length
;
276 ndr_set_flags(&ndr
->flags
, LIBNDR_PRINT_ARRAY_HEX
|
277 LIBNDR_FLAG_NOALIGN
);
278 if (ndr_flags
& NDR_SCALARS
) {
279 NDR_CHECK(ndr_pull_align(ndr
, 4));
280 NDR_CHECK(ndr_pull_dns_string(ndr
, NDR_SCALARS
, &r
->name
));
281 NDR_CHECK(ndr_pull_dns_qtype(ndr
, NDR_SCALARS
, &r
->rr_type
));
282 NDR_CHECK(ndr_pull_dns_qclass(ndr
, NDR_SCALARS
, &r
->rr_class
));
283 NDR_CHECK(ndr_pull_uint32(ndr
, NDR_SCALARS
, &r
->ttl
));
284 NDR_CHECK(ndr_pull_uint16(ndr
, NDR_SCALARS
, &r
->length
));
285 _saved_offset1
= ndr
->offset
;
287 NDR_CHECK(ndr_token_store(ndr
, &ndr
->array_size_list
,
290 NDR_CHECK(ndr_pull_set_switch_value(ndr
, &r
->rdata
,
292 NDR_CHECK(ndr_pull_dns_rdata(ndr
, NDR_SCALARS
,
295 ZERO_STRUCT(r
->rdata
);
297 length
= ndr
->offset
- _saved_offset1
;
298 if (length
> r
->length
) {
299 return ndr_pull_error(ndr
, NDR_ERR_LENGTH
, "TODO");
302 r
->unexpected
= data_blob_null
;
303 pad
= r
->length
- length
;
305 NDR_PULL_NEED_BYTES(ndr
, pad
);
306 r
->unexpected
= data_blob_talloc(ndr
->current_mem_ctx
,
310 if (r
->unexpected
.data
== NULL
) {
311 return ndr_pull_error(ndr
,
313 "Failed to allocate a " \
320 NDR_CHECK(ndr_pull_trailer_align(ndr
, 4));
322 if (ndr_flags
& NDR_BUFFERS
) {
323 NDR_CHECK(ndr_pull_dns_rdata(ndr
, NDR_BUFFERS
, &r
->rdata
));
325 ndr
->flags
= _flags_save_STRUCT
;
326 return NDR_ERR_SUCCESS
;