rdata.c revision 193149
1/*
2 * Copyright (C) 2004-2009  Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1998-2003  Internet Software Consortium.
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
16 */
17
18/* $Id: rdata.c,v 1.199.50.2 2009/02/16 23:47:15 tbox Exp $ */
19
20/*! \file */
21
22#include <config.h>
23#include <ctype.h>
24
25#include <isc/base64.h>
26#include <isc/hex.h>
27#include <isc/lex.h>
28#include <isc/mem.h>
29#include <isc/parseint.h>
30#include <isc/print.h>
31#include <isc/string.h>
32#include <isc/stdlib.h>
33#include <isc/util.h>
34
35#include <dns/callbacks.h>
36#include <dns/cert.h>
37#include <dns/compress.h>
38#include <dns/enumtype.h>
39#include <dns/keyflags.h>
40#include <dns/keyvalues.h>
41#include <dns/rcode.h>
42#include <dns/rdata.h>
43#include <dns/rdataclass.h>
44#include <dns/rdatastruct.h>
45#include <dns/rdatatype.h>
46#include <dns/result.h>
47#include <dns/secalg.h>
48#include <dns/secproto.h>
49#include <dns/time.h>
50#include <dns/ttl.h>
51
52#define RETERR(x) \
53	do { \
54		isc_result_t _r = (x); \
55		if (_r != ISC_R_SUCCESS) \
56			return (_r); \
57	} while (0)
58
59#define RETTOK(x) \
60	do { \
61		isc_result_t _r = (x); \
62		if (_r != ISC_R_SUCCESS) { \
63			isc_lex_ungettoken(lexer, &token); \
64			return (_r); \
65		} \
66	} while (0)
67
68#define DNS_AS_STR(t) ((t).value.as_textregion.base)
69
70#define ARGS_FROMTEXT	int rdclass, dns_rdatatype_t type, \
71			isc_lex_t *lexer, dns_name_t *origin, \
72			unsigned int options, isc_buffer_t *target, \
73			dns_rdatacallbacks_t *callbacks
74
75#define ARGS_TOTEXT	dns_rdata_t *rdata, dns_rdata_textctx_t *tctx, \
76			isc_buffer_t *target
77
78#define ARGS_FROMWIRE	int rdclass, dns_rdatatype_t type, \
79			isc_buffer_t *source, dns_decompress_t *dctx, \
80			unsigned int options, isc_buffer_t *target
81
82#define ARGS_TOWIRE	dns_rdata_t *rdata, dns_compress_t *cctx, \
83			isc_buffer_t *target
84
85#define ARGS_COMPARE	const dns_rdata_t *rdata1, const dns_rdata_t *rdata2
86
87#define ARGS_FROMSTRUCT	int rdclass, dns_rdatatype_t type, \
88			void *source, isc_buffer_t *target
89
90#define ARGS_TOSTRUCT	dns_rdata_t *rdata, void *target, isc_mem_t *mctx
91
92#define ARGS_FREESTRUCT void *source
93
94#define ARGS_ADDLDATA	dns_rdata_t *rdata, dns_additionaldatafunc_t add, \
95			void *arg
96
97#define ARGS_DIGEST	dns_rdata_t *rdata, dns_digestfunc_t digest, void *arg
98
99#define ARGS_CHECKOWNER dns_name_t *name, dns_rdataclass_t rdclass, \
100			dns_rdatatype_t type, isc_boolean_t wildcard
101
102#define ARGS_CHECKNAMES dns_rdata_t *rdata, dns_name_t *owner, dns_name_t *bad
103
104
105/*%
106 * Context structure for the totext_ functions.
107 * Contains formatting options for rdata-to-text
108 * conversion.
109 */
110typedef struct dns_rdata_textctx {
111	dns_name_t *origin;	/*%< Current origin, or NULL. */
112	unsigned int flags;	/*%< DNS_STYLEFLAG_*  */
113	unsigned int width;	/*%< Width of rdata column. */
114	const char *linebreak;	/*%< Line break string. */
115} dns_rdata_textctx_t;
116
117static isc_result_t
118txt_totext(isc_region_t *source, isc_buffer_t *target);
119
120static isc_result_t
121txt_fromtext(isc_textregion_t *source, isc_buffer_t *target);
122
123static isc_result_t
124txt_fromwire(isc_buffer_t *source, isc_buffer_t *target);
125
126static isc_boolean_t
127name_prefix(dns_name_t *name, dns_name_t *origin, dns_name_t *target);
128
129static unsigned int
130name_length(dns_name_t *name);
131
132static isc_result_t
133str_totext(const char *source, isc_buffer_t *target);
134
135static isc_result_t
136inet_totext(int af, isc_region_t *src, isc_buffer_t *target);
137
138static isc_boolean_t
139buffer_empty(isc_buffer_t *source);
140
141static void
142buffer_fromregion(isc_buffer_t *buffer, isc_region_t *region);
143
144static isc_result_t
145uint32_tobuffer(isc_uint32_t, isc_buffer_t *target);
146
147static isc_result_t
148uint16_tobuffer(isc_uint32_t, isc_buffer_t *target);
149
150static isc_result_t
151uint8_tobuffer(isc_uint32_t, isc_buffer_t *target);
152
153static isc_result_t
154name_tobuffer(dns_name_t *name, isc_buffer_t *target);
155
156static isc_uint32_t
157uint32_fromregion(isc_region_t *region);
158
159static isc_uint16_t
160uint16_fromregion(isc_region_t *region);
161
162static isc_uint8_t
163uint8_fromregion(isc_region_t *region);
164
165static isc_uint8_t
166uint8_consume_fromregion(isc_region_t *region);
167
168static isc_result_t
169mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length);
170
171static int
172hexvalue(char value);
173
174static int
175decvalue(char value);
176
177static isc_result_t
178btoa_totext(unsigned char *inbuf, int inbuflen, isc_buffer_t *target);
179
180static isc_result_t
181atob_tobuffer(isc_lex_t *lexer, isc_buffer_t *target);
182
183static void
184default_fromtext_callback(dns_rdatacallbacks_t *callbacks, const char *, ...)
185     ISC_FORMAT_PRINTF(2, 3);
186
187static void
188fromtext_error(void (*callback)(dns_rdatacallbacks_t *, const char *, ...),
189	       dns_rdatacallbacks_t *callbacks, const char *name,
190	       unsigned long line, isc_token_t *token, isc_result_t result);
191
192static void
193fromtext_warneof(isc_lex_t *lexer, dns_rdatacallbacks_t *callbacks);
194
195static isc_result_t
196rdata_totext(dns_rdata_t *rdata, dns_rdata_textctx_t *tctx,
197	     isc_buffer_t *target);
198
199static void
200warn_badname(dns_name_t *name, isc_lex_t *lexer,
201	     dns_rdatacallbacks_t *callbacks);
202
203static void
204warn_badmx(isc_token_t *token, isc_lex_t *lexer,
205	   dns_rdatacallbacks_t *callbacks);
206
207static isc_uint16_t
208uint16_consume_fromregion(isc_region_t *region);
209
210static inline int
211getquad(const void *src, struct in_addr *dst,
212	isc_lex_t *lexer, dns_rdatacallbacks_t *callbacks)
213{
214	int result;
215	struct in_addr *tmp;
216
217	result = inet_aton(src, dst);
218	if (result == 1 && callbacks != NULL &&
219	    inet_pton(AF_INET, src, &tmp) != 1) {
220		const char *name = isc_lex_getsourcename(lexer);
221		if (name == NULL)
222			name = "UNKNOWN";
223		(*callbacks->warn)(callbacks, "%s:%lu: \"%s\" "
224				   "is not a decimal dotted quad", name,
225				   isc_lex_getsourceline(lexer), src);
226	}
227	return (result);
228}
229
230static inline isc_result_t
231name_duporclone(dns_name_t *source, isc_mem_t *mctx, dns_name_t *target) {
232
233	if (mctx != NULL)
234		return (dns_name_dup(source, mctx, target));
235	dns_name_clone(source, target);
236	return (ISC_R_SUCCESS);
237}
238
239static inline void *
240mem_maybedup(isc_mem_t *mctx, void *source, size_t length) {
241	void *new;
242
243	if (mctx == NULL)
244		return (source);
245	new = isc_mem_allocate(mctx, length);
246	if (new != NULL)
247		memcpy(new, source, length);
248
249	return (new);
250}
251
252static const char hexdigits[] = "0123456789abcdef";
253static const char decdigits[] = "0123456789";
254
255#include "code.h"
256
257#define META 0x0001
258#define RESERVED 0x0002
259
260/***
261 *** Initialization
262 ***/
263
264void
265dns_rdata_init(dns_rdata_t *rdata) {
266
267	REQUIRE(rdata != NULL);
268
269	rdata->data = NULL;
270	rdata->length = 0;
271	rdata->rdclass = 0;
272	rdata->type = 0;
273	rdata->flags = 0;
274	ISC_LINK_INIT(rdata, link);
275	/* ISC_LIST_INIT(rdata->list); */
276}
277
278#if 1
279#define DNS_RDATA_INITIALIZED(rdata) \
280	((rdata)->data == NULL && (rdata)->length == 0 && \
281	 (rdata)->rdclass == 0 && (rdata)->type == 0 && (rdata)->flags == 0 && \
282	 !ISC_LINK_LINKED((rdata), link))
283#else
284#ifdef ISC_LIST_CHECKINIT
285#define DNS_RDATA_INITIALIZED(rdata) \
286	(!ISC_LINK_LINKED((rdata), link))
287#else
288#define DNS_RDATA_INITIALIZED(rdata) ISC_TRUE
289#endif
290#endif
291
292#define DNS_RDATA_VALIDFLAGS(rdata) \
293	(((rdata)->flags & ~(DNS_RDATA_UPDATE|DNS_RDATA_OFFLINE)) == 0)
294
295void
296dns_rdata_reset(dns_rdata_t *rdata) {
297
298	REQUIRE(rdata != NULL);
299
300	REQUIRE(!ISC_LINK_LINKED(rdata, link));
301	REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
302
303	rdata->data = NULL;
304	rdata->length = 0;
305	rdata->rdclass = 0;
306	rdata->type = 0;
307	rdata->flags = 0;
308}
309
310/***
311 ***
312 ***/
313
314void
315dns_rdata_clone(const dns_rdata_t *src, dns_rdata_t *target) {
316
317	REQUIRE(src != NULL);
318	REQUIRE(target != NULL);
319
320	REQUIRE(DNS_RDATA_INITIALIZED(target));
321
322	REQUIRE(DNS_RDATA_VALIDFLAGS(src));
323	REQUIRE(DNS_RDATA_VALIDFLAGS(target));
324
325	target->data = src->data;
326	target->length = src->length;
327	target->rdclass = src->rdclass;
328	target->type = src->type;
329	target->flags = src->flags;
330}
331
332
333/***
334 *** Comparisons
335 ***/
336
337int
338dns_rdata_compare(const dns_rdata_t *rdata1, const dns_rdata_t *rdata2) {
339	int result = 0;
340	isc_boolean_t use_default = ISC_FALSE;
341
342	REQUIRE(rdata1 != NULL);
343	REQUIRE(rdata2 != NULL);
344	REQUIRE(rdata1->data != NULL);
345	REQUIRE(rdata2->data != NULL);
346	REQUIRE(DNS_RDATA_VALIDFLAGS(rdata1));
347	REQUIRE(DNS_RDATA_VALIDFLAGS(rdata2));
348
349	if (rdata1->rdclass != rdata2->rdclass)
350		return (rdata1->rdclass < rdata2->rdclass ? -1 : 1);
351
352	if (rdata1->type != rdata2->type)
353		return (rdata1->type < rdata2->type ? -1 : 1);
354
355	COMPARESWITCH
356
357	if (use_default) {
358		isc_region_t r1;
359		isc_region_t r2;
360
361		dns_rdata_toregion(rdata1, &r1);
362		dns_rdata_toregion(rdata2, &r2);
363		result = isc_region_compare(&r1, &r2);
364	}
365	return (result);
366}
367
368/***
369 *** Conversions
370 ***/
371
372void
373dns_rdata_fromregion(dns_rdata_t *rdata, dns_rdataclass_t rdclass,
374		     dns_rdatatype_t type, isc_region_t *r)
375{
376
377	REQUIRE(rdata != NULL);
378	REQUIRE(DNS_RDATA_INITIALIZED(rdata));
379	REQUIRE(r != NULL);
380
381	REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
382
383	rdata->data = r->base;
384	rdata->length = r->length;
385	rdata->rdclass = rdclass;
386	rdata->type = type;
387	rdata->flags = 0;
388}
389
390void
391dns_rdata_toregion(const dns_rdata_t *rdata, isc_region_t *r) {
392
393	REQUIRE(rdata != NULL);
394	REQUIRE(r != NULL);
395	REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
396
397	r->base = rdata->data;
398	r->length = rdata->length;
399}
400
401isc_result_t
402dns_rdata_fromwire(dns_rdata_t *rdata, dns_rdataclass_t rdclass,
403		   dns_rdatatype_t type, isc_buffer_t *source,
404		   dns_decompress_t *dctx, unsigned int options,
405		   isc_buffer_t *target)
406{
407	isc_result_t result = ISC_R_NOTIMPLEMENTED;
408	isc_region_t region;
409	isc_buffer_t ss;
410	isc_buffer_t st;
411	isc_boolean_t use_default = ISC_FALSE;
412	isc_uint32_t activelength;
413
414	REQUIRE(dctx != NULL);
415	if (rdata != NULL) {
416		REQUIRE(DNS_RDATA_INITIALIZED(rdata));
417		REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
418	}
419
420	if (type == 0)
421		return (DNS_R_FORMERR);
422
423	ss = *source;
424	st = *target;
425
426	activelength = isc_buffer_activelength(source);
427	INSIST(activelength < 65536);
428
429	FROMWIRESWITCH
430
431	if (use_default) {
432		if (activelength > isc_buffer_availablelength(target))
433			result = ISC_R_NOSPACE;
434		else {
435			isc_buffer_putmem(target, isc_buffer_current(source),
436					  activelength);
437			isc_buffer_forward(source, activelength);
438			result = ISC_R_SUCCESS;
439		}
440	}
441
442	/*
443	 * We should have consumed all of our buffer.
444	 */
445	if (result == ISC_R_SUCCESS && !buffer_empty(source))
446		result = DNS_R_EXTRADATA;
447
448	if (rdata != NULL && result == ISC_R_SUCCESS) {
449		region.base = isc_buffer_used(&st);
450		region.length = isc_buffer_usedlength(target) -
451				isc_buffer_usedlength(&st);
452		dns_rdata_fromregion(rdata, rdclass, type, &region);
453	}
454
455	if (result != ISC_R_SUCCESS) {
456		*source = ss;
457		*target = st;
458	}
459	return (result);
460}
461
462isc_result_t
463dns_rdata_towire(dns_rdata_t *rdata, dns_compress_t *cctx,
464		 isc_buffer_t *target)
465{
466	isc_result_t result = ISC_R_NOTIMPLEMENTED;
467	isc_boolean_t use_default = ISC_FALSE;
468	isc_region_t tr;
469	isc_buffer_t st;
470
471	REQUIRE(rdata != NULL);
472	REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
473
474	/*
475	 * Some DynDNS meta-RRs have empty rdata.
476	 */
477	if ((rdata->flags & DNS_RDATA_UPDATE) != 0) {
478		INSIST(rdata->length == 0);
479		return (ISC_R_SUCCESS);
480	}
481
482	st = *target;
483
484	TOWIRESWITCH
485
486	if (use_default) {
487		isc_buffer_availableregion(target, &tr);
488		if (tr.length < rdata->length)
489			return (ISC_R_NOSPACE);
490		memcpy(tr.base, rdata->data, rdata->length);
491		isc_buffer_add(target, rdata->length);
492		return (ISC_R_SUCCESS);
493	}
494	if (result != ISC_R_SUCCESS) {
495		*target = st;
496		INSIST(target->used < 65536);
497		dns_compress_rollback(cctx, (isc_uint16_t)target->used);
498	}
499	return (result);
500}
501
502/*
503 * If the binary data in 'src' is valid uncompressed wire format
504 * rdata of class 'rdclass' and type 'type', return ISC_R_SUCCESS
505 * and copy the validated rdata to 'dest'.  Otherwise return an error.
506 */
507static isc_result_t
508rdata_validate(isc_buffer_t *src, isc_buffer_t *dest, dns_rdataclass_t rdclass,
509	    dns_rdatatype_t type)
510{
511	dns_decompress_t dctx;
512	dns_rdata_t rdata = DNS_RDATA_INIT;
513	isc_result_t result;
514
515	dns_decompress_init(&dctx, -1, DNS_DECOMPRESS_NONE);
516	isc_buffer_setactive(src, isc_buffer_usedlength(src));
517	result = dns_rdata_fromwire(&rdata, rdclass, type, src,
518				    &dctx, 0, dest);
519	dns_decompress_invalidate(&dctx);
520
521	return (result);
522}
523
524static isc_result_t
525unknown_fromtext(dns_rdataclass_t rdclass, dns_rdatatype_t type,
526		 isc_lex_t *lexer, isc_mem_t *mctx, isc_buffer_t *target)
527{
528	isc_result_t result;
529	isc_buffer_t *buf = NULL;
530	isc_token_t token;
531
532	if (type == 0 || dns_rdatatype_ismeta(type))
533		return (DNS_R_METATYPE);
534
535	result = isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
536					ISC_FALSE);
537	if (result == ISC_R_SUCCESS && token.value.as_ulong > 65535U)
538		return (ISC_R_RANGE);
539	result = isc_buffer_allocate(mctx, &buf, token.value.as_ulong);
540	if (result != ISC_R_SUCCESS)
541		return (result);
542
543	result = isc_hex_tobuffer(lexer, buf,
544				  (unsigned int)token.value.as_ulong);
545	if (result != ISC_R_SUCCESS)
546	       goto failure;
547	if (isc_buffer_usedlength(buf) != token.value.as_ulong) {
548		result = ISC_R_UNEXPECTEDEND;
549		goto failure;
550	}
551
552	if (dns_rdatatype_isknown(type)) {
553		result = rdata_validate(buf, target, rdclass, type);
554	} else {
555		isc_region_t r;
556		isc_buffer_usedregion(buf, &r);
557		result = isc_buffer_copyregion(target, &r);
558	}
559	if (result != ISC_R_SUCCESS)
560		goto failure;
561
562	isc_buffer_free(&buf);
563	return (ISC_R_SUCCESS);
564
565 failure:
566	isc_buffer_free(&buf);
567	return (result);
568}
569
570isc_result_t
571dns_rdata_fromtext(dns_rdata_t *rdata, dns_rdataclass_t rdclass,
572		   dns_rdatatype_t type, isc_lex_t *lexer,
573		   dns_name_t *origin, unsigned int options, isc_mem_t *mctx,
574		   isc_buffer_t *target, dns_rdatacallbacks_t *callbacks)
575{
576	isc_result_t result = ISC_R_NOTIMPLEMENTED;
577	isc_region_t region;
578	isc_buffer_t st;
579	isc_token_t token;
580	unsigned int lexoptions = ISC_LEXOPT_EOL | ISC_LEXOPT_EOF |
581				  ISC_LEXOPT_DNSMULTILINE | ISC_LEXOPT_ESCAPE;
582	char *name;
583	unsigned long line;
584	void (*callback)(dns_rdatacallbacks_t *, const char *, ...);
585	isc_result_t tresult;
586
587	REQUIRE(origin == NULL || dns_name_isabsolute(origin) == ISC_TRUE);
588	if (rdata != NULL) {
589		REQUIRE(DNS_RDATA_INITIALIZED(rdata));
590		REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
591	}
592	if (callbacks != NULL) {
593		REQUIRE(callbacks->warn != NULL);
594		REQUIRE(callbacks->error != NULL);
595	}
596
597	st = *target;
598
599	if (callbacks != NULL)
600		callback = callbacks->error;
601	else
602		callback = default_fromtext_callback;
603
604	result = isc_lex_getmastertoken(lexer, &token, isc_tokentype_qstring,
605					ISC_FALSE);
606	if (result != ISC_R_SUCCESS) {
607		name = isc_lex_getsourcename(lexer);
608		line = isc_lex_getsourceline(lexer);
609		fromtext_error(callback, callbacks, name, line,
610			       &token, result);
611		return (result);
612	}
613
614	if (strcmp(DNS_AS_STR(token), "\\#") == 0)
615		result = unknown_fromtext(rdclass, type, lexer, mctx, target);
616	else {
617		isc_lex_ungettoken(lexer, &token);
618
619		FROMTEXTSWITCH
620	}
621
622	/*
623	 * Consume to end of line / file.
624	 * If not at end of line initially set error code.
625	 * Call callback via fromtext_error once if there was an error.
626	 */
627	do {
628		name = isc_lex_getsourcename(lexer);
629		line = isc_lex_getsourceline(lexer);
630		tresult = isc_lex_gettoken(lexer, lexoptions, &token);
631		if (tresult != ISC_R_SUCCESS) {
632			if (result == ISC_R_SUCCESS)
633				result = tresult;
634			if (callback != NULL)
635				fromtext_error(callback, callbacks, name,
636					       line, NULL, result);
637			break;
638		} else if (token.type != isc_tokentype_eol &&
639			   token.type != isc_tokentype_eof) {
640			if (result == ISC_R_SUCCESS)
641				result = DNS_R_EXTRATOKEN;
642			if (callback != NULL) {
643				fromtext_error(callback, callbacks, name,
644					       line, &token, result);
645				callback = NULL;
646			}
647		} else if (result != ISC_R_SUCCESS && callback != NULL) {
648			fromtext_error(callback, callbacks, name, line,
649				       &token, result);
650			break;
651		} else {
652			if (token.type == isc_tokentype_eof)
653				fromtext_warneof(lexer, callbacks);
654			break;
655		}
656	} while (1);
657
658	if (rdata != NULL && result == ISC_R_SUCCESS) {
659		region.base = isc_buffer_used(&st);
660		region.length = isc_buffer_usedlength(target) -
661				isc_buffer_usedlength(&st);
662		dns_rdata_fromregion(rdata, rdclass, type, &region);
663	}
664	if (result != ISC_R_SUCCESS) {
665		*target = st;
666	}
667	return (result);
668}
669
670static isc_result_t
671rdata_totext(dns_rdata_t *rdata, dns_rdata_textctx_t *tctx,
672	     isc_buffer_t *target)
673{
674	isc_result_t result = ISC_R_NOTIMPLEMENTED;
675	isc_boolean_t use_default = ISC_FALSE;
676	char buf[sizeof("65535")];
677	isc_region_t sr;
678
679	REQUIRE(rdata != NULL);
680	REQUIRE(tctx->origin == NULL ||
681		dns_name_isabsolute(tctx->origin) == ISC_TRUE);
682
683	/*
684	 * Some DynDNS meta-RRs have empty rdata.
685	 */
686	if ((rdata->flags & DNS_RDATA_UPDATE) != 0) {
687		INSIST(rdata->length == 0);
688		return (ISC_R_SUCCESS);
689	}
690
691	TOTEXTSWITCH
692
693	if (use_default) {
694		strlcpy(buf, "\\# ", sizeof(buf));
695		result = str_totext(buf, target);
696		dns_rdata_toregion(rdata, &sr);
697		INSIST(sr.length < 65536);
698		snprintf(buf, sizeof(buf), "%u", sr.length);
699		result = str_totext(buf, target);
700		if (sr.length != 0 && result == ISC_R_SUCCESS) {
701			if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0)
702				result = str_totext(" ( ", target);
703			else
704				result = str_totext(" ", target);
705			if (result == ISC_R_SUCCESS)
706				result = isc_hex_totext(&sr, tctx->width - 2,
707							tctx->linebreak,
708							target);
709			if (result == ISC_R_SUCCESS &&
710			    (tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0)
711				result = str_totext(" )", target);
712		}
713	}
714
715	return (result);
716}
717
718isc_result_t
719dns_rdata_totext(dns_rdata_t *rdata, dns_name_t *origin, isc_buffer_t *target)
720{
721	dns_rdata_textctx_t tctx;
722
723	REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
724
725	/*
726	 * Set up formatting options for single-line output.
727	 */
728	tctx.origin = origin;
729	tctx.flags = 0;
730	tctx.width = 60;
731	tctx.linebreak = " ";
732	return (rdata_totext(rdata, &tctx, target));
733}
734
735isc_result_t
736dns_rdata_tofmttext(dns_rdata_t *rdata, dns_name_t *origin,
737		    unsigned int flags, unsigned int width,
738		    const char *linebreak, isc_buffer_t *target)
739{
740	dns_rdata_textctx_t tctx;
741
742	REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
743
744	/*
745	 * Set up formatting options for formatted output.
746	 */
747	tctx.origin = origin;
748	tctx.flags = flags;
749	if ((flags & DNS_STYLEFLAG_MULTILINE) != 0) {
750		tctx.width = width;
751		tctx.linebreak = linebreak;
752	} else {
753		tctx.width = 60; /* Used for hex word length only. */
754		tctx.linebreak = " ";
755	}
756	return (rdata_totext(rdata, &tctx, target));
757}
758
759isc_result_t
760dns_rdata_fromstruct(dns_rdata_t *rdata, dns_rdataclass_t rdclass,
761		     dns_rdatatype_t type, void *source,
762		     isc_buffer_t *target)
763{
764	isc_result_t result = ISC_R_NOTIMPLEMENTED;
765	isc_buffer_t st;
766	isc_region_t region;
767	isc_boolean_t use_default = ISC_FALSE;
768
769	REQUIRE(source != NULL);
770	if (rdata != NULL) {
771		REQUIRE(DNS_RDATA_INITIALIZED(rdata));
772		REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
773	}
774
775	st = *target;
776
777	FROMSTRUCTSWITCH
778
779	if (use_default)
780		(void)NULL;
781
782	if (rdata != NULL && result == ISC_R_SUCCESS) {
783		region.base = isc_buffer_used(&st);
784		region.length = isc_buffer_usedlength(target) -
785				isc_buffer_usedlength(&st);
786		dns_rdata_fromregion(rdata, rdclass, type, &region);
787	}
788	if (result != ISC_R_SUCCESS)
789		*target = st;
790	return (result);
791}
792
793isc_result_t
794dns_rdata_tostruct(dns_rdata_t *rdata, void *target, isc_mem_t *mctx) {
795	isc_result_t result = ISC_R_NOTIMPLEMENTED;
796	isc_boolean_t use_default = ISC_FALSE;
797
798	REQUIRE(rdata != NULL);
799	REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
800
801	TOSTRUCTSWITCH
802
803	if (use_default)
804		(void)NULL;
805
806	return (result);
807}
808
809void
810dns_rdata_freestruct(void *source) {
811	dns_rdatacommon_t *common = source;
812	REQUIRE(source != NULL);
813
814	FREESTRUCTSWITCH
815}
816
817isc_result_t
818dns_rdata_additionaldata(dns_rdata_t *rdata, dns_additionaldatafunc_t add,
819			 void *arg)
820{
821	isc_result_t result = ISC_R_NOTIMPLEMENTED;
822	isc_boolean_t use_default = ISC_FALSE;
823
824	/*
825	 * Call 'add' for each name and type from 'rdata' which is subject to
826	 * additional section processing.
827	 */
828
829	REQUIRE(rdata != NULL);
830	REQUIRE(add != NULL);
831	REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
832
833	ADDITIONALDATASWITCH
834
835	/* No additional processing for unknown types */
836	if (use_default)
837		result = ISC_R_SUCCESS;
838
839	return (result);
840}
841
842isc_result_t
843dns_rdata_digest(dns_rdata_t *rdata, dns_digestfunc_t digest, void *arg) {
844	isc_result_t result = ISC_R_NOTIMPLEMENTED;
845	isc_boolean_t use_default = ISC_FALSE;
846	isc_region_t r;
847
848	/*
849	 * Send 'rdata' in DNSSEC canonical form to 'digest'.
850	 */
851
852	REQUIRE(rdata != NULL);
853	REQUIRE(digest != NULL);
854	REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
855
856	DIGESTSWITCH
857
858	if (use_default) {
859		dns_rdata_toregion(rdata, &r);
860		result = (digest)(arg, &r);
861	}
862
863	return (result);
864}
865
866isc_boolean_t
867dns_rdata_checkowner(dns_name_t *name, dns_rdataclass_t rdclass,
868		     dns_rdatatype_t type, isc_boolean_t wildcard)
869{
870	isc_boolean_t result;
871
872	CHECKOWNERSWITCH
873	return (result);
874}
875
876isc_boolean_t
877dns_rdata_checknames(dns_rdata_t *rdata, dns_name_t *owner, dns_name_t *bad)
878{
879	isc_boolean_t result;
880
881	CHECKNAMESSWITCH
882	return (result);
883}
884
885unsigned int
886dns_rdatatype_attributes(dns_rdatatype_t type)
887{
888	RDATATYPE_ATTRIBUTE_SW
889	if (type >= (dns_rdatatype_t)128 && type < (dns_rdatatype_t)255)
890		return (DNS_RDATATYPEATTR_UNKNOWN | DNS_RDATATYPEATTR_META);
891	return (DNS_RDATATYPEATTR_UNKNOWN);
892}
893
894isc_result_t
895dns_rdatatype_fromtext(dns_rdatatype_t *typep, isc_textregion_t *source) {
896	unsigned int hash;
897	unsigned int n;
898	unsigned char a, b;
899
900	n = source->length;
901
902	if (n == 0)
903		return (DNS_R_UNKNOWN);
904
905	a = tolower((unsigned char)source->base[0]);
906	b = tolower((unsigned char)source->base[n - 1]);
907
908	hash = ((a + n) * b) % 256;
909
910	/*
911	 * This switch block is inlined via \#define, and will use "return"
912	 * to return a result to the caller if it is a valid (known)
913	 * rdatatype name.
914	 */
915	RDATATYPE_FROMTEXT_SW(hash, source->base, n, typep);
916
917	if (source->length > 4 && source->length < (4 + sizeof("65000")) &&
918	    strncasecmp("type", source->base, 4) == 0) {
919		char buf[sizeof("65000")];
920		char *endp;
921		unsigned int val;
922
923		strncpy(buf, source->base + 4, source->length - 4);
924		buf[source->length - 4] = '\0';
925		val = strtoul(buf, &endp, 10);
926		if (*endp == '\0' && val <= 0xffff) {
927			*typep = (dns_rdatatype_t)val;
928			return (ISC_R_SUCCESS);
929		}
930	}
931
932	return (DNS_R_UNKNOWN);
933}
934
935isc_result_t
936dns_rdatatype_totext(dns_rdatatype_t type, isc_buffer_t *target) {
937	char buf[sizeof("TYPE65535")];
938
939	RDATATYPE_TOTEXT_SW
940	snprintf(buf, sizeof(buf), "TYPE%u", type);
941	return (str_totext(buf, target));
942}
943
944void
945dns_rdatatype_format(dns_rdatatype_t rdtype,
946		     char *array, unsigned int size)
947{
948	isc_result_t result;
949	isc_buffer_t buf;
950
951	isc_buffer_init(&buf, array, size);
952	result = dns_rdatatype_totext(rdtype, &buf);
953	/*
954	 * Null terminate.
955	 */
956	if (result == ISC_R_SUCCESS) {
957		if (isc_buffer_availablelength(&buf) >= 1)
958			isc_buffer_putuint8(&buf, 0);
959		else
960			result = ISC_R_NOSPACE;
961	}
962	if (result != ISC_R_SUCCESS) {
963		snprintf(array, size, "<unknown>");
964		array[size - 1] = '\0';
965	}
966}
967
968/*
969 * Private function.
970 */
971
972static unsigned int
973name_length(dns_name_t *name) {
974	return (name->length);
975}
976
977static isc_result_t
978txt_totext(isc_region_t *source, isc_buffer_t *target) {
979	unsigned int tl;
980	unsigned int n;
981	unsigned char *sp;
982	char *tp;
983	isc_region_t region;
984
985	isc_buffer_availableregion(target, &region);
986	sp = source->base;
987	tp = (char *)region.base;
988	tl = region.length;
989
990	n = *sp++;
991
992	REQUIRE(n + 1 <= source->length);
993
994	if (tl < 1)
995		return (ISC_R_NOSPACE);
996	*tp++ = '"';
997	tl--;
998	while (n--) {
999		if (*sp < 0x20 || *sp >= 0x7f) {
1000			if (tl < 4)
1001				return (ISC_R_NOSPACE);
1002			*tp++ = 0x5c;
1003			*tp++ = 0x30 + ((*sp / 100) % 10);
1004			*tp++ = 0x30 + ((*sp / 10) % 10);
1005			*tp++ = 0x30 + (*sp % 10);
1006			sp++;
1007			tl -= 4;
1008			continue;
1009		}
1010		/* double quote, semi-colon, backslash */
1011		if (*sp == 0x22 || *sp == 0x3b || *sp == 0x5c) {
1012			if (tl < 2)
1013				return (ISC_R_NOSPACE);
1014			*tp++ = '\\';
1015			tl--;
1016		}
1017		if (tl < 1)
1018			return (ISC_R_NOSPACE);
1019		*tp++ = *sp++;
1020		tl--;
1021	}
1022	if (tl < 1)
1023		return (ISC_R_NOSPACE);
1024	*tp++ = '"';
1025	tl--;
1026	isc_buffer_add(target, tp - (char *)region.base);
1027	isc_region_consume(source, *source->base + 1);
1028	return (ISC_R_SUCCESS);
1029}
1030
1031static isc_result_t
1032txt_fromtext(isc_textregion_t *source, isc_buffer_t *target) {
1033	isc_region_t tregion;
1034	isc_boolean_t escape;
1035	unsigned int n, nrem;
1036	char *s;
1037	unsigned char *t;
1038	int d;
1039	int c;
1040
1041	isc_buffer_availableregion(target, &tregion);
1042	s = source->base;
1043	n = source->length;
1044	t = tregion.base;
1045	nrem = tregion.length;
1046	escape = ISC_FALSE;
1047	if (nrem < 1)
1048		return (ISC_R_NOSPACE);
1049	/*
1050	 * Length byte.
1051	 */
1052	nrem--;
1053	t++;
1054	/*
1055	 * Maximum text string length.
1056	 */
1057	if (nrem > 255)
1058		nrem = 255;
1059	while (n-- != 0) {
1060		c = (*s++) & 0xff;
1061		if (escape && (d = decvalue((char)c)) != -1) {
1062			c = d;
1063			if (n == 0)
1064				return (DNS_R_SYNTAX);
1065			n--;
1066			if ((d = decvalue(*s++)) != -1)
1067				c = c * 10 + d;
1068			else
1069				return (DNS_R_SYNTAX);
1070			if (n == 0)
1071				return (DNS_R_SYNTAX);
1072			n--;
1073			if ((d = decvalue(*s++)) != -1)
1074				c = c * 10 + d;
1075			else
1076				return (DNS_R_SYNTAX);
1077			if (c > 255)
1078				return (DNS_R_SYNTAX);
1079		} else if (!escape && c == '\\') {
1080			escape = ISC_TRUE;
1081			continue;
1082		}
1083		escape = ISC_FALSE;
1084		if (nrem == 0)
1085			return (ISC_R_NOSPACE);
1086		*t++ = c;
1087		nrem--;
1088	}
1089	if (escape)
1090		return (DNS_R_SYNTAX);
1091	*tregion.base = t - tregion.base - 1;
1092	isc_buffer_add(target, *tregion.base + 1);
1093	return (ISC_R_SUCCESS);
1094}
1095
1096static isc_result_t
1097txt_fromwire(isc_buffer_t *source, isc_buffer_t *target) {
1098	unsigned int n;
1099	isc_region_t sregion;
1100	isc_region_t tregion;
1101
1102	isc_buffer_activeregion(source, &sregion);
1103	if (sregion.length == 0)
1104		return(ISC_R_UNEXPECTEDEND);
1105	n = *sregion.base + 1;
1106	if (n > sregion.length)
1107		return (ISC_R_UNEXPECTEDEND);
1108
1109	isc_buffer_availableregion(target, &tregion);
1110	if (n > tregion.length)
1111		return (ISC_R_NOSPACE);
1112
1113	memcpy(tregion.base, sregion.base, n);
1114	isc_buffer_forward(source, n);
1115	isc_buffer_add(target, n);
1116	return (ISC_R_SUCCESS);
1117}
1118
1119static isc_boolean_t
1120name_prefix(dns_name_t *name, dns_name_t *origin, dns_name_t *target) {
1121	int l1, l2;
1122
1123	if (origin == NULL)
1124		goto return_false;
1125
1126	if (dns_name_compare(origin, dns_rootname) == 0)
1127		goto return_false;
1128
1129	if (!dns_name_issubdomain(name, origin))
1130		goto return_false;
1131
1132	l1 = dns_name_countlabels(name);
1133	l2 = dns_name_countlabels(origin);
1134
1135	if (l1 == l2)
1136		goto return_false;
1137
1138	dns_name_getlabelsequence(name, 0, l1 - l2, target);
1139	return (ISC_TRUE);
1140
1141return_false:
1142	*target = *name;
1143	return (ISC_FALSE);
1144}
1145
1146static isc_result_t
1147str_totext(const char *source, isc_buffer_t *target) {
1148	unsigned int l;
1149	isc_region_t region;
1150
1151	isc_buffer_availableregion(target, &region);
1152	l = strlen(source);
1153
1154	if (l > region.length)
1155		return (ISC_R_NOSPACE);
1156
1157	memcpy(region.base, source, l);
1158	isc_buffer_add(target, l);
1159	return (ISC_R_SUCCESS);
1160}
1161
1162static isc_result_t
1163inet_totext(int af, isc_region_t *src, isc_buffer_t *target) {
1164	char tmpbuf[64];
1165
1166	/* Note - inet_ntop doesn't do size checking on its input. */
1167	if (inet_ntop(af, src->base, tmpbuf, sizeof(tmpbuf)) == NULL)
1168		return (ISC_R_NOSPACE);
1169	if (strlen(tmpbuf) > isc_buffer_availablelength(target))
1170		return (ISC_R_NOSPACE);
1171	isc_buffer_putstr(target, tmpbuf);
1172	return (ISC_R_SUCCESS);
1173}
1174
1175static isc_boolean_t
1176buffer_empty(isc_buffer_t *source) {
1177	return((source->current == source->active) ? ISC_TRUE : ISC_FALSE);
1178}
1179
1180static void
1181buffer_fromregion(isc_buffer_t *buffer, isc_region_t *region) {
1182	isc_buffer_init(buffer, region->base, region->length);
1183	isc_buffer_add(buffer, region->length);
1184	isc_buffer_setactive(buffer, region->length);
1185}
1186
1187static isc_result_t
1188uint32_tobuffer(isc_uint32_t value, isc_buffer_t *target) {
1189	isc_region_t region;
1190
1191	isc_buffer_availableregion(target, &region);
1192	if (region.length < 4)
1193		return (ISC_R_NOSPACE);
1194	isc_buffer_putuint32(target, value);
1195	return (ISC_R_SUCCESS);
1196}
1197
1198static isc_result_t
1199uint16_tobuffer(isc_uint32_t value, isc_buffer_t *target) {
1200	isc_region_t region;
1201
1202	if (value > 0xffff)
1203		return (ISC_R_RANGE);
1204	isc_buffer_availableregion(target, &region);
1205	if (region.length < 2)
1206		return (ISC_R_NOSPACE);
1207	isc_buffer_putuint16(target, (isc_uint16_t)value);
1208	return (ISC_R_SUCCESS);
1209}
1210
1211static isc_result_t
1212uint8_tobuffer(isc_uint32_t value, isc_buffer_t *target) {
1213	isc_region_t region;
1214
1215	if (value > 0xff)
1216		return (ISC_R_RANGE);
1217	isc_buffer_availableregion(target, &region);
1218	if (region.length < 1)
1219		return (ISC_R_NOSPACE);
1220	isc_buffer_putuint8(target, (isc_uint8_t)value);
1221	return (ISC_R_SUCCESS);
1222}
1223
1224static isc_result_t
1225name_tobuffer(dns_name_t *name, isc_buffer_t *target) {
1226	isc_region_t r;
1227	dns_name_toregion(name, &r);
1228	return (isc_buffer_copyregion(target, &r));
1229}
1230
1231static isc_uint32_t
1232uint32_fromregion(isc_region_t *region) {
1233	isc_uint32_t value;
1234
1235	REQUIRE(region->length >= 4);
1236	value = region->base[0] << 24;
1237	value |= region->base[1] << 16;
1238	value |= region->base[2] << 8;
1239	value |= region->base[3];
1240	return(value);
1241}
1242
1243static isc_uint16_t
1244uint16_consume_fromregion(isc_region_t *region) {
1245	isc_uint16_t r = uint16_fromregion(region);
1246
1247	isc_region_consume(region, 2);
1248	return r;
1249}
1250
1251static isc_uint16_t
1252uint16_fromregion(isc_region_t *region) {
1253
1254	REQUIRE(region->length >= 2);
1255
1256	return ((region->base[0] << 8) | region->base[1]);
1257}
1258
1259static isc_uint8_t
1260uint8_fromregion(isc_region_t *region) {
1261
1262	REQUIRE(region->length >= 1);
1263
1264	return (region->base[0]);
1265}
1266
1267static isc_uint8_t
1268uint8_consume_fromregion(isc_region_t *region) {
1269	isc_uint8_t r = uint8_fromregion(region);
1270
1271	isc_region_consume(region, 1);
1272	return r;
1273}
1274
1275static isc_result_t
1276mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length) {
1277	isc_region_t tr;
1278
1279	isc_buffer_availableregion(target, &tr);
1280	if (length > tr.length)
1281		return (ISC_R_NOSPACE);
1282	memcpy(tr.base, base, length);
1283	isc_buffer_add(target, length);
1284	return (ISC_R_SUCCESS);
1285}
1286
1287static int
1288hexvalue(char value) {
1289	char *s;
1290	unsigned char c;
1291
1292	c = (unsigned char)value;
1293
1294	if (!isascii(c))
1295		return (-1);
1296	if (isupper(c))
1297		c = tolower(c);
1298	if ((s = strchr(hexdigits, c)) == NULL)
1299		return (-1);
1300	return (s - hexdigits);
1301}
1302
1303static int
1304decvalue(char value) {
1305	char *s;
1306
1307	/*
1308	 * isascii() is valid for full range of int values, no need to
1309	 * mask or cast.
1310	 */
1311	if (!isascii(value))
1312		return (-1);
1313	if ((s = strchr(decdigits, value)) == NULL)
1314		return (-1);
1315	return (s - decdigits);
1316}
1317
1318static const char atob_digits[86] =
1319	"!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`" \
1320	"abcdefghijklmnopqrstu";
1321/*
1322 * Subroutines to convert between 8 bit binary bytes and printable ASCII.
1323 * Computes the number of bytes, and three kinds of simple checksums.
1324 * Incoming bytes are collected into 32-bit words, then printed in base 85:
1325 *	exp(85,5) > exp(2,32)
1326 * The ASCII characters used are between '!' and 'u';
1327 * 'z' encodes 32-bit zero; 'x' is used to mark the end of encoded data.
1328 *
1329 * Originally by Paul Rutter (philabs!per) and Joe Orost (petsd!joe) for
1330 * the atob/btoa programs, released with the compress program, in mod.sources.
1331 * Modified by Mike Schwartz 8/19/86 for use in BIND.
1332 * Modified to be re-entrant 3/2/99.
1333 */
1334
1335
1336struct state {
1337	isc_int32_t Ceor;
1338	isc_int32_t Csum;
1339	isc_int32_t Crot;
1340	isc_int32_t word;
1341	isc_int32_t bcount;
1342};
1343
1344#define Ceor state->Ceor
1345#define Csum state->Csum
1346#define Crot state->Crot
1347#define word state->word
1348#define bcount state->bcount
1349
1350#define times85(x)	((((((x<<2)+x)<<2)+x)<<2)+x)
1351
1352static isc_result_t	byte_atob(int c, isc_buffer_t *target,
1353				  struct state *state);
1354static isc_result_t	putbyte(int c, isc_buffer_t *, struct state *state);
1355static isc_result_t	byte_btoa(int c, isc_buffer_t *, struct state *state);
1356
1357/*
1358 * Decode ASCII-encoded byte c into binary representation and
1359 * place into *bufp, advancing bufp.
1360 */
1361static isc_result_t
1362byte_atob(int c, isc_buffer_t *target, struct state *state) {
1363	char *s;
1364	if (c == 'z') {
1365		if (bcount != 0)
1366			return(DNS_R_SYNTAX);
1367		else {
1368			RETERR(putbyte(0, target, state));
1369			RETERR(putbyte(0, target, state));
1370			RETERR(putbyte(0, target, state));
1371			RETERR(putbyte(0, target, state));
1372		}
1373	} else if ((s = strchr(atob_digits, c)) != NULL) {
1374		if (bcount == 0) {
1375			word = s - atob_digits;
1376			++bcount;
1377		} else if (bcount < 4) {
1378			word = times85(word);
1379			word += s - atob_digits;
1380			++bcount;
1381		} else {
1382			word = times85(word);
1383			word += s - atob_digits;
1384			RETERR(putbyte((word >> 24) & 0xff, target, state));
1385			RETERR(putbyte((word >> 16) & 0xff, target, state));
1386			RETERR(putbyte((word >> 8) & 0xff, target, state));
1387			RETERR(putbyte(word & 0xff, target, state));
1388			word = 0;
1389			bcount = 0;
1390		}
1391	} else
1392		return(DNS_R_SYNTAX);
1393	return(ISC_R_SUCCESS);
1394}
1395
1396/*
1397 * Compute checksum info and place c into target.
1398 */
1399static isc_result_t
1400putbyte(int c, isc_buffer_t *target, struct state *state) {
1401	isc_region_t tr;
1402
1403	Ceor ^= c;
1404	Csum += c;
1405	Csum += 1;
1406	if ((Crot & 0x80000000)) {
1407		Crot <<= 1;
1408		Crot += 1;
1409	} else {
1410		Crot <<= 1;
1411	}
1412	Crot += c;
1413	isc_buffer_availableregion(target, &tr);
1414	if (tr.length < 1)
1415		return (ISC_R_NOSPACE);
1416	tr.base[0] = c;
1417	isc_buffer_add(target, 1);
1418	return (ISC_R_SUCCESS);
1419}
1420
1421/*
1422 * Read the ASCII-encoded data from inbuf, of length inbuflen, and convert
1423 * it into T_UNSPEC (binary data) in outbuf, not to exceed outbuflen bytes;
1424 * outbuflen must be divisible by 4.  (Note: this is because outbuf is filled
1425 * in 4 bytes at a time.  If the actual data doesn't end on an even 4-byte
1426 * boundary, there will be no problem...it will be padded with 0 bytes, and
1427 * numbytes will indicate the correct number of bytes.  The main point is
1428 * that since the buffer is filled in 4 bytes at a time, even if there is
1429 * not a full 4 bytes of data at the end, there has to be room to 0-pad the
1430 * data, so the buffer must be of size divisible by 4).  Place the number of
1431 * output bytes in numbytes, and return a failure/success status.
1432 */
1433
1434static isc_result_t
1435atob_tobuffer(isc_lex_t *lexer, isc_buffer_t *target) {
1436	long oeor, osum, orot;
1437	struct state statebuf, *state= &statebuf;
1438	isc_token_t token;
1439	char c;
1440	char *e;
1441
1442	Ceor = Csum = Crot = word = bcount = 0;
1443
1444	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
1445				      ISC_FALSE));
1446	while (token.value.as_textregion.length != 0) {
1447		if ((c = token.value.as_textregion.base[0]) == 'x') {
1448			break;
1449		} else
1450			RETERR(byte_atob(c, target, state));
1451		isc_textregion_consume(&token.value.as_textregion, 1);
1452	}
1453
1454	/*
1455	 * Number of bytes.
1456	 */
1457	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
1458				      ISC_FALSE));
1459	if ((token.value.as_ulong % 4) != 0U)
1460		isc_buffer_subtract(target,  4 - (token.value.as_ulong % 4));
1461
1462	/*
1463	 * Checksum.
1464	 */
1465	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
1466				      ISC_FALSE));
1467	oeor = strtol(DNS_AS_STR(token), &e, 16);
1468	if (*e != 0)
1469		return (DNS_R_SYNTAX);
1470
1471	/*
1472	 * Checksum.
1473	 */
1474	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
1475				      ISC_FALSE));
1476	osum = strtol(DNS_AS_STR(token), &e, 16);
1477	if (*e != 0)
1478		return (DNS_R_SYNTAX);
1479
1480	/*
1481	 * Checksum.
1482	 */
1483	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
1484				      ISC_FALSE));
1485	orot = strtol(DNS_AS_STR(token), &e, 16);
1486	if (*e != 0)
1487		return (DNS_R_SYNTAX);
1488
1489	if ((oeor != Ceor) || (osum != Csum) || (orot != Crot))
1490		return(DNS_R_BADCKSUM);
1491	return (ISC_R_SUCCESS);
1492}
1493
1494/*
1495 * Encode binary byte c into ASCII representation and place into *bufp,
1496 * advancing bufp.
1497 */
1498static isc_result_t
1499byte_btoa(int c, isc_buffer_t *target, struct state *state) {
1500	isc_region_t tr;
1501
1502	isc_buffer_availableregion(target, &tr);
1503	Ceor ^= c;
1504	Csum += c;
1505	Csum += 1;
1506	if ((Crot & 0x80000000)) {
1507		Crot <<= 1;
1508		Crot += 1;
1509	} else {
1510		Crot <<= 1;
1511	}
1512	Crot += c;
1513
1514	word <<= 8;
1515	word |= c;
1516	if (bcount == 3) {
1517		if (word == 0) {
1518			if (tr.length < 1)
1519				return (ISC_R_NOSPACE);
1520			tr.base[0] = 'z';
1521			isc_buffer_add(target, 1);
1522		} else {
1523		    register int tmp = 0;
1524		    register isc_int32_t tmpword = word;
1525
1526		    if (tmpword < 0) {
1527			   /*
1528			    * Because some don't support u_long.
1529			    */
1530			tmp = 32;
1531			tmpword -= (isc_int32_t)(85 * 85 * 85 * 85 * 32);
1532		    }
1533		    if (tmpword < 0) {
1534			tmp = 64;
1535			tmpword -= (isc_int32_t)(85 * 85 * 85 * 85 * 32);
1536		    }
1537			if (tr.length < 5)
1538				return (ISC_R_NOSPACE);
1539			tr.base[0] = atob_digits[(tmpword /
1540					      (isc_int32_t)(85 * 85 * 85 * 85))
1541						+ tmp];
1542			tmpword %= (isc_int32_t)(85 * 85 * 85 * 85);
1543			tr.base[1] = atob_digits[tmpword / (85 * 85 * 85)];
1544			tmpword %= (85 * 85 * 85);
1545			tr.base[2] = atob_digits[tmpword / (85 * 85)];
1546			tmpword %= (85 * 85);
1547			tr.base[3] = atob_digits[tmpword / 85];
1548			tmpword %= 85;
1549			tr.base[4] = atob_digits[tmpword];
1550			isc_buffer_add(target, 5);
1551		}
1552		bcount = 0;
1553	} else {
1554		bcount += 1;
1555	}
1556	return (ISC_R_SUCCESS);
1557}
1558
1559
1560/*
1561 * Encode the binary data from inbuf, of length inbuflen, into a
1562 * target.  Return success/failure status
1563 */
1564static isc_result_t
1565btoa_totext(unsigned char *inbuf, int inbuflen, isc_buffer_t *target) {
1566	int inc;
1567	struct state statebuf, *state = &statebuf;
1568	char buf[sizeof("x 2000000000 ffffffff ffffffff ffffffff")];
1569
1570	Ceor = Csum = Crot = word = bcount = 0;
1571	for (inc = 0; inc < inbuflen; inbuf++, inc++)
1572		RETERR(byte_btoa(*inbuf, target, state));
1573
1574	while (bcount != 0)
1575		RETERR(byte_btoa(0, target, state));
1576
1577	/*
1578	 * Put byte count and checksum information at end of buffer,
1579	 * delimited by 'x'
1580	 */
1581	snprintf(buf, sizeof(buf), "x %d %x %x %x", inbuflen, Ceor, Csum, Crot);
1582	return (str_totext(buf, target));
1583}
1584
1585
1586static void
1587default_fromtext_callback(dns_rdatacallbacks_t *callbacks, const char *fmt,
1588			  ...)
1589{
1590	va_list ap;
1591
1592	UNUSED(callbacks);
1593
1594	va_start(ap, fmt);
1595	vfprintf(stderr, fmt, ap);
1596	va_end(ap);
1597	fprintf(stderr, "\n");
1598}
1599
1600static void
1601fromtext_warneof(isc_lex_t *lexer, dns_rdatacallbacks_t *callbacks) {
1602	if (isc_lex_isfile(lexer) && callbacks != NULL) {
1603		const char *name = isc_lex_getsourcename(lexer);
1604		if (name == NULL)
1605			name = "UNKNOWN";
1606		(*callbacks->warn)(callbacks,
1607				   "%s:%lu: file does not end with newline",
1608				   name, isc_lex_getsourceline(lexer));
1609	}
1610}
1611
1612static void
1613warn_badmx(isc_token_t *token, isc_lex_t *lexer,
1614	   dns_rdatacallbacks_t *callbacks)
1615{
1616	const char *file;
1617	unsigned long line;
1618
1619	if (lexer != NULL) {
1620		file = isc_lex_getsourcename(lexer);
1621		line = isc_lex_getsourceline(lexer);
1622		(*callbacks->warn)(callbacks, "%s:%u: warning: '%s': %s",
1623				   file, line, DNS_AS_STR(*token),
1624				   dns_result_totext(DNS_R_MXISADDRESS));
1625	}
1626}
1627
1628static void
1629warn_badname(dns_name_t *name, isc_lex_t *lexer,
1630	     dns_rdatacallbacks_t *callbacks)
1631{
1632	const char *file;
1633	unsigned long line;
1634	char namebuf[DNS_NAME_FORMATSIZE];
1635
1636	if (lexer != NULL) {
1637		file = isc_lex_getsourcename(lexer);
1638		line = isc_lex_getsourceline(lexer);
1639		dns_name_format(name, namebuf, sizeof(namebuf));
1640		(*callbacks->warn)(callbacks, "%s:%u: warning: %s: %s",
1641				   file, line, namebuf,
1642				   dns_result_totext(DNS_R_BADNAME));
1643	}
1644}
1645
1646static void
1647fromtext_error(void (*callback)(dns_rdatacallbacks_t *, const char *, ...),
1648	       dns_rdatacallbacks_t *callbacks, const char *name,
1649	       unsigned long line, isc_token_t *token, isc_result_t result)
1650{
1651	if (name == NULL)
1652		name = "UNKNOWN";
1653
1654	if (token != NULL) {
1655		switch (token->type) {
1656		case isc_tokentype_eol:
1657			(*callback)(callbacks, "%s: %s:%lu: near eol: %s",
1658				    "dns_rdata_fromtext", name, line,
1659				    dns_result_totext(result));
1660			break;
1661		case isc_tokentype_eof:
1662			(*callback)(callbacks, "%s: %s:%lu: near eof: %s",
1663				    "dns_rdata_fromtext", name, line,
1664				    dns_result_totext(result));
1665			break;
1666		case isc_tokentype_number:
1667			(*callback)(callbacks, "%s: %s:%lu: near %lu: %s",
1668				    "dns_rdata_fromtext", name, line,
1669				    token->value.as_ulong,
1670				    dns_result_totext(result));
1671			break;
1672		case isc_tokentype_string:
1673		case isc_tokentype_qstring:
1674			(*callback)(callbacks, "%s: %s:%lu: near '%s': %s",
1675				    "dns_rdata_fromtext", name, line,
1676				    DNS_AS_STR(*token),
1677				    dns_result_totext(result));
1678			break;
1679		default:
1680			(*callback)(callbacks, "%s: %s:%lu: %s",
1681				    "dns_rdata_fromtext", name, line,
1682				    dns_result_totext(result));
1683			break;
1684		}
1685	} else {
1686		(*callback)(callbacks, "dns_rdata_fromtext: %s:%lu: %s",
1687			    name, line, dns_result_totext(result));
1688	}
1689}
1690
1691dns_rdatatype_t
1692dns_rdata_covers(dns_rdata_t *rdata) {
1693	if (rdata->type == 46)
1694		return (covers_rrsig(rdata));
1695	return (covers_sig(rdata));
1696}
1697
1698isc_boolean_t
1699dns_rdatatype_ismeta(dns_rdatatype_t type) {
1700	if ((dns_rdatatype_attributes(type) & DNS_RDATATYPEATTR_META) != 0)
1701		return (ISC_TRUE);
1702	return (ISC_FALSE);
1703}
1704
1705isc_boolean_t
1706dns_rdatatype_issingleton(dns_rdatatype_t type) {
1707	if ((dns_rdatatype_attributes(type) & DNS_RDATATYPEATTR_SINGLETON)
1708	    != 0)
1709		return (ISC_TRUE);
1710	return (ISC_FALSE);
1711}
1712
1713isc_boolean_t
1714dns_rdatatype_notquestion(dns_rdatatype_t type) {
1715	if ((dns_rdatatype_attributes(type) & DNS_RDATATYPEATTR_NOTQUESTION)
1716	    != 0)
1717		return (ISC_TRUE);
1718	return (ISC_FALSE);
1719}
1720
1721isc_boolean_t
1722dns_rdatatype_questiononly(dns_rdatatype_t type) {
1723	if ((dns_rdatatype_attributes(type) & DNS_RDATATYPEATTR_QUESTIONONLY)
1724	    != 0)
1725		return (ISC_TRUE);
1726	return (ISC_FALSE);
1727}
1728
1729isc_boolean_t
1730dns_rdatatype_atparent(dns_rdatatype_t type) {
1731	if ((dns_rdatatype_attributes(type) & DNS_RDATATYPEATTR_ATPARENT) != 0)
1732		return (ISC_TRUE);
1733	return (ISC_FALSE);
1734}
1735
1736isc_boolean_t
1737dns_rdataclass_ismeta(dns_rdataclass_t rdclass) {
1738
1739	if (rdclass == dns_rdataclass_reserved0
1740	    || rdclass == dns_rdataclass_none
1741	    || rdclass == dns_rdataclass_any)
1742		return (ISC_TRUE);
1743
1744	return (ISC_FALSE);  /* Assume it is not a meta class. */
1745}
1746
1747isc_boolean_t
1748dns_rdatatype_isdnssec(dns_rdatatype_t type) {
1749	if ((dns_rdatatype_attributes(type) & DNS_RDATATYPEATTR_DNSSEC) != 0)
1750		return (ISC_TRUE);
1751	return (ISC_FALSE);
1752}
1753
1754isc_boolean_t
1755dns_rdatatype_iszonecutauth(dns_rdatatype_t type) {
1756	if ((dns_rdatatype_attributes(type)
1757	     & (DNS_RDATATYPEATTR_DNSSEC | DNS_RDATATYPEATTR_ZONECUTAUTH))
1758	    != 0)
1759		return (ISC_TRUE);
1760	return (ISC_FALSE);
1761}
1762
1763isc_boolean_t
1764dns_rdatatype_isknown(dns_rdatatype_t type) {
1765	if ((dns_rdatatype_attributes(type) & DNS_RDATATYPEATTR_UNKNOWN)
1766	    == 0)
1767		return (ISC_TRUE);
1768	return (ISC_FALSE);
1769}
1770