• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt/router/samba-3.5.8/source3/libaddns/
1/*
2  Linux DNS client library implementation
3  Copyright (C) 2006 Gerald Carter <jerry@samba.org>
4
5     ** NOTE! The following LGPL license applies to the libaddns
6     ** library. This does NOT imply that all of Samba is released
7     ** under the LGPL
8
9  This library is free software; you can redistribute it and/or
10  modify it under the terms of the GNU Lesser General Public
11  License as published by the Free Software Foundation; either
12  version 2.1 of the License, or (at your option) any later version.
13
14  This library is distributed in the hope that it will be useful,
15  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  Lesser General Public License for more details.
18
19  You should have received a copy of the GNU Lesser General Public
20  License along with this library; if not, see <http://www.gnu.org/licenses/>.
21*/
22
23#include "dns.h"
24#include "assert.h"
25
26struct dns_buffer *dns_create_buffer(TALLOC_CTX *mem_ctx)
27{
28	struct dns_buffer *result;
29
30	if (!(result = talloc(mem_ctx, struct dns_buffer))) {
31		return NULL;
32	}
33
34	result->offset = 0;
35	result->error = ERROR_DNS_SUCCESS;
36
37	/*
38	 * Small inital size to excercise the realloc code
39	 */
40	result->size = 2;
41
42	if (!(result->data = TALLOC_ARRAY(result, uint8, result->size))) {
43		TALLOC_FREE(result);
44		return NULL;
45	}
46
47	return result;
48}
49
50void dns_marshall_buffer(struct dns_buffer *buf, const uint8 *data,
51			 size_t len)
52{
53	if (!ERR_DNS_IS_OK(buf->error)) return;
54
55	if (buf->offset + len < buf->offset) {
56		/*
57		 * Wraparound!
58		 */
59		buf->error = ERROR_DNS_INVALID_PARAMETER;
60		return;
61	}
62
63	if ((buf->offset + len) > 0xffff) {
64		/*
65		 * Only 64k possible
66		 */
67		buf->error = ERROR_DNS_INVALID_PARAMETER;
68		return;
69	}
70
71	if (buf->offset + len > buf->size) {
72		size_t new_size = buf->offset + len;
73		uint8 *new_data;
74
75		/*
76		 * Don't do too many reallocs, round up to some multiple
77		 */
78
79		new_size += (64 - (new_size % 64));
80
81		if (!(new_data = TALLOC_REALLOC_ARRAY(buf, buf->data, uint8,
82						      new_size))) {
83			buf->error = ERROR_DNS_NO_MEMORY;
84			return;
85		}
86
87		buf->size = new_size;
88		buf->data = new_data;
89	}
90
91	memcpy(buf->data + buf->offset, data, len);
92	buf->offset += len;
93	return;
94}
95
96void dns_marshall_uint16(struct dns_buffer *buf, uint16 val)
97{
98	uint16 n_val = htons(val);
99	dns_marshall_buffer(buf, (uint8 *)&n_val, sizeof(n_val));
100}
101
102void dns_marshall_uint32(struct dns_buffer *buf, uint32 val)
103{
104	uint32 n_val = htonl(val);
105	dns_marshall_buffer(buf, (uint8 *)&n_val, sizeof(n_val));
106}
107
108void dns_unmarshall_buffer(struct dns_buffer *buf, uint8 *data,
109			   size_t len)
110{
111	if (!(ERR_DNS_IS_OK(buf->error))) return;
112
113	if ((len > buf->size) || (buf->offset + len > buf->size)) {
114		buf->error = ERROR_DNS_INVALID_MESSAGE;
115		return;
116	}
117
118	memcpy((void *)data, (const void *)(buf->data + buf->offset), len);
119	buf->offset += len;
120
121	return;
122}
123
124void dns_unmarshall_uint16(struct dns_buffer *buf, uint16 *val)
125{
126	uint16 n_val;
127
128	dns_unmarshall_buffer(buf, (uint8 *)&n_val, sizeof(n_val));
129	if (!(ERR_DNS_IS_OK(buf->error))) return;
130
131	*val = ntohs(n_val);
132}
133
134void dns_unmarshall_uint32(struct dns_buffer *buf, uint32 *val)
135{
136	uint32 n_val;
137
138	dns_unmarshall_buffer(buf, (uint8 *)&n_val, sizeof(n_val));
139	if (!(ERR_DNS_IS_OK(buf->error))) return;
140
141	*val = ntohl(n_val);
142}
143
144void dns_marshall_domain_name(struct dns_buffer *buf,
145			      const struct dns_domain_name *name)
146{
147	struct dns_domain_label *label;
148	char end_char = '\0';
149
150	/*
151	 * TODO: Implement DNS compression
152	 */
153
154	for (label = name->pLabelList; label != NULL; label = label->next) {
155		uint8 len = label->len;
156
157		dns_marshall_buffer(buf, (uint8 *)&len, sizeof(len));
158		if (!ERR_DNS_IS_OK(buf->error)) return;
159
160		dns_marshall_buffer(buf, (uint8 *)label->label, len);
161		if (!ERR_DNS_IS_OK(buf->error)) return;
162	}
163
164	dns_marshall_buffer(buf, (uint8 *)&end_char, 1);
165}
166
167static void dns_unmarshall_label(TALLOC_CTX *mem_ctx,
168				 int level,
169				 struct dns_buffer *buf,
170				 struct dns_domain_label **plabel)
171{
172	struct dns_domain_label *label;
173	uint8 len;
174
175	if (!ERR_DNS_IS_OK(buf->error)) return;
176
177	if (level > 128) {
178		/*
179		 * Protect against recursion
180		 */
181		buf->error = ERROR_DNS_INVALID_MESSAGE;
182		return;
183	}
184
185	dns_unmarshall_buffer(buf, &len, sizeof(len));
186	if (!ERR_DNS_IS_OK(buf->error)) return;
187
188	if (len == 0) {
189		*plabel = NULL;
190		return;
191	}
192
193	if ((len & 0xc0) == 0xc0) {
194		/*
195		 * We've got a compressed name. Build up a new "fake" buffer
196		 * and using the calculated offset.
197		 */
198		struct dns_buffer new_buf;
199		uint8 low;
200
201		dns_unmarshall_buffer(buf, &low, sizeof(low));
202		if (!ERR_DNS_IS_OK(buf->error)) return;
203
204		new_buf = *buf;
205		new_buf.offset = len & 0x3f;
206		new_buf.offset <<= 8;
207		new_buf.offset |= low;
208
209		dns_unmarshall_label(mem_ctx, level+1, &new_buf, plabel);
210		buf->error = new_buf.error;
211		return;
212	}
213
214	if ((len & 0xc0) != 0) {
215		buf->error = ERROR_DNS_INVALID_NAME;
216		return;
217	}
218
219	if (!(label = talloc(mem_ctx, struct dns_domain_label))) {
220		buf->error = ERROR_DNS_NO_MEMORY;
221		return;
222	}
223
224	label->len = len;
225
226	if (!(label->label = TALLOC_ARRAY(label, char, len+1))) {
227		buf->error = ERROR_DNS_NO_MEMORY;
228		goto error;
229	}
230
231	dns_unmarshall_buffer(buf, (uint8 *)label->label, len);
232	if (!ERR_DNS_IS_OK(buf->error)) goto error;
233
234	dns_unmarshall_label(label, level+1, buf, &label->next);
235	if (!ERR_DNS_IS_OK(buf->error)) goto error;
236
237	*plabel = label;
238	return;
239
240 error:
241	TALLOC_FREE(label);
242	return;
243}
244
245void dns_unmarshall_domain_name(TALLOC_CTX *mem_ctx,
246				struct dns_buffer *buf,
247				struct dns_domain_name **pname)
248{
249	struct dns_domain_name *name;
250
251	if (!ERR_DNS_IS_OK(buf->error)) return;
252
253	if (!(name = talloc(mem_ctx, struct dns_domain_name))) {
254		buf->error = ERROR_DNS_NO_MEMORY;
255		return;
256	}
257
258	dns_unmarshall_label(name, 0, buf, &name->pLabelList);
259
260	if (!ERR_DNS_IS_OK(buf->error)) {
261		return;
262	}
263
264	*pname = name;
265	return;
266}
267
268static void dns_marshall_question(struct dns_buffer *buf,
269				  const struct dns_question *q)
270{
271	dns_marshall_domain_name(buf, q->name);
272	dns_marshall_uint16(buf, q->q_type);
273	dns_marshall_uint16(buf, q->q_class);
274}
275
276static void dns_unmarshall_question(TALLOC_CTX *mem_ctx,
277				    struct dns_buffer *buf,
278				    struct dns_question **pq)
279{
280	struct dns_question *q;
281
282	if (!(ERR_DNS_IS_OK(buf->error))) return;
283
284	if (!(q = talloc(mem_ctx, struct dns_question))) {
285		buf->error = ERROR_DNS_NO_MEMORY;
286		return;
287	}
288
289	dns_unmarshall_domain_name(q, buf, &q->name);
290	dns_unmarshall_uint16(buf, &q->q_type);
291	dns_unmarshall_uint16(buf, &q->q_class);
292
293	if (!(ERR_DNS_IS_OK(buf->error))) return;
294
295	*pq = q;
296}
297
298static void dns_marshall_rr(struct dns_buffer *buf,
299			    const struct dns_rrec *r)
300{
301	dns_marshall_domain_name(buf, r->name);
302	dns_marshall_uint16(buf, r->type);
303	dns_marshall_uint16(buf, r->r_class);
304	dns_marshall_uint32(buf, r->ttl);
305	dns_marshall_uint16(buf, r->data_length);
306	dns_marshall_buffer(buf, r->data, r->data_length);
307}
308
309static void dns_unmarshall_rr(TALLOC_CTX *mem_ctx,
310			      struct dns_buffer *buf,
311			      struct dns_rrec **pr)
312{
313	struct dns_rrec *r;
314
315	if (!(ERR_DNS_IS_OK(buf->error))) return;
316
317	if (!(r = talloc(mem_ctx, struct dns_rrec))) {
318		buf->error = ERROR_DNS_NO_MEMORY;
319		return;
320	}
321
322	dns_unmarshall_domain_name(r, buf, &r->name);
323	dns_unmarshall_uint16(buf, &r->type);
324	dns_unmarshall_uint16(buf, &r->r_class);
325	dns_unmarshall_uint32(buf, &r->ttl);
326	dns_unmarshall_uint16(buf, &r->data_length);
327	r->data = NULL;
328
329	if (!(ERR_DNS_IS_OK(buf->error))) return;
330
331	if (r->data_length != 0) {
332		if (!(r->data = TALLOC_ARRAY(r, uint8, r->data_length))) {
333			buf->error = ERROR_DNS_NO_MEMORY;
334			return;
335		}
336		dns_unmarshall_buffer(buf, r->data, r->data_length);
337	}
338
339	if (!(ERR_DNS_IS_OK(buf->error))) return;
340
341	*pr = r;
342}
343
344DNS_ERROR dns_marshall_request(TALLOC_CTX *mem_ctx,
345			       const struct dns_request *req,
346			       struct dns_buffer **pbuf)
347{
348	struct dns_buffer *buf;
349	uint16 i;
350
351	if (!(buf = dns_create_buffer(mem_ctx))) {
352		return ERROR_DNS_NO_MEMORY;
353	}
354
355	dns_marshall_uint16(buf, req->id);
356	dns_marshall_uint16(buf, req->flags);
357	dns_marshall_uint16(buf, req->num_questions);
358	dns_marshall_uint16(buf, req->num_answers);
359	dns_marshall_uint16(buf, req->num_auths);
360	dns_marshall_uint16(buf, req->num_additionals);
361
362	for (i=0; i<req->num_questions; i++) {
363		dns_marshall_question(buf, req->questions[i]);
364	}
365	for (i=0; i<req->num_answers; i++) {
366		dns_marshall_rr(buf, req->answers[i]);
367	}
368	for (i=0; i<req->num_auths; i++) {
369		dns_marshall_rr(buf, req->auths[i]);
370	}
371	for (i=0; i<req->num_additionals; i++) {
372		dns_marshall_rr(buf, req->additionals[i]);
373	}
374
375	if (!ERR_DNS_IS_OK(buf->error)) {
376		DNS_ERROR err = buf->error;
377		TALLOC_FREE(buf);
378		return err;
379	}
380
381	*pbuf = buf;
382	return ERROR_DNS_SUCCESS;
383}
384
385DNS_ERROR dns_unmarshall_request(TALLOC_CTX *mem_ctx,
386				 struct dns_buffer *buf,
387				 struct dns_request **preq)
388{
389	struct dns_request *req;
390	uint16 i;
391	DNS_ERROR err;
392
393	if (!(req = TALLOC_ZERO_P(mem_ctx, struct dns_request))) {
394		return ERROR_DNS_NO_MEMORY;
395	}
396
397	dns_unmarshall_uint16(buf, &req->id);
398	dns_unmarshall_uint16(buf, &req->flags);
399	dns_unmarshall_uint16(buf, &req->num_questions);
400	dns_unmarshall_uint16(buf, &req->num_answers);
401	dns_unmarshall_uint16(buf, &req->num_auths);
402	dns_unmarshall_uint16(buf, &req->num_additionals);
403
404	if (!ERR_DNS_IS_OK(buf->error)) goto error;
405
406	err = ERROR_DNS_NO_MEMORY;
407
408	if ((req->num_questions != 0) &&
409	    !(req->questions = TALLOC_ARRAY(req, struct dns_question *,
410					    req->num_questions))) {
411		goto error;
412	}
413	if ((req->num_answers != 0) &&
414	    !(req->answers = TALLOC_ARRAY(req, struct dns_rrec *,
415					  req->num_answers))) {
416		goto error;
417	}
418	if ((req->num_auths != 0) &&
419	    !(req->auths = TALLOC_ARRAY(req, struct dns_rrec *,
420					req->num_auths))) {
421		goto error;
422	}
423	if ((req->num_additionals != 0) &&
424	    !(req->additionals = TALLOC_ARRAY(req, struct dns_rrec *,
425					      req->num_additionals))) {
426		goto error;
427	}
428
429	for (i=0; i<req->num_questions; i++) {
430		dns_unmarshall_question(req->questions, buf,
431					&req->questions[i]);
432	}
433	for (i=0; i<req->num_answers; i++) {
434		dns_unmarshall_rr(req->answers, buf,
435				  &req->answers[i]);
436	}
437	for (i=0; i<req->num_auths; i++) {
438		dns_unmarshall_rr(req->auths, buf,
439				  &req->auths[i]);
440	}
441	for (i=0; i<req->num_additionals; i++) {
442		dns_unmarshall_rr(req->additionals, buf,
443				  &req->additionals[i]);
444	}
445
446	if (!ERR_DNS_IS_OK(buf->error)) {
447		err = buf->error;
448		goto error;
449	}
450
451	*preq = req;
452	return ERROR_DNS_SUCCESS;
453
454 error:
455	err = buf->error;
456	TALLOC_FREE(req);
457	return err;
458}
459
460struct dns_request *dns_update2request(struct dns_update_request *update)
461{
462	struct dns_request *req;
463
464	/*
465	 * This is a non-specified construct that happens to work on Linux/gcc
466	 * and I would expect it to work everywhere else. dns_request and
467	 * dns_update_request are essentially the same structures with
468	 * different names, so any difference would mean that the compiler
469	 * applied two different variations of padding given the same types in
470	 * the structures.
471	 */
472
473	req = (struct dns_request *)(void *)update;
474
475	/*
476	 * The assert statement here looks like we could do the equivalent
477	 * assignments to get portable, but it would mean that we have to
478	 * allocate the dns_question record for the dns_zone records. We
479	 * assume that if this assert works then the same holds true for
480	 * dns_zone<>dns_question as well.
481	 */
482
483#ifdef DEVELOPER
484	assert((req->id == update->id) && (req->flags == update->flags) &&
485	       (req->num_questions == update->num_zones) &&
486	       (req->num_answers == update->num_preqs) &&
487	       (req->num_auths == update->num_updates) &&
488	       (req->num_additionals == update->num_additionals) &&
489	       (req->questions ==
490		(struct dns_question **)(void *)update->zones) &&
491	       (req->answers == update->preqs) &&
492	       (req->auths == update->updates) &&
493	       (req->additionals == update->additionals));
494#endif
495
496	return req;
497}
498
499struct dns_update_request *dns_request2update(struct dns_request *request)
500{
501	/*
502	 * For portability concerns see dns_update2request;
503	 */
504	return (struct dns_update_request *)(void *)request;
505}
506
507DNS_ERROR dns_marshall_update_request(TALLOC_CTX *mem_ctx,
508				      struct dns_update_request *update,
509				      struct dns_buffer **pbuf)
510{
511	return dns_marshall_request(mem_ctx, dns_update2request(update), pbuf);
512}
513
514DNS_ERROR dns_unmarshall_update_request(TALLOC_CTX *mem_ctx,
515					struct dns_buffer *buf,
516					struct dns_update_request **pupreq)
517{
518	/*
519	 * See comments above about portability. If the above works, this will
520	 * as well.
521	 */
522
523	return dns_unmarshall_request(mem_ctx, buf,
524				      (struct dns_request **)(void *)pupreq);
525}
526
527uint16 dns_response_code(uint16 flags)
528{
529	return flags & 0xF;
530}
531