rdata.c revision 170223
160484Sobrien/*
260484Sobrien * Copyright (C) 2004-2006  Internet Systems Consortium, Inc. ("ISC")
360484Sobrien * Copyright (C) 1998-2003  Internet Software Consortium.
460484Sobrien *
560484Sobrien * Permission to use, copy, modify, and distribute this software for any
660484Sobrien * purpose with or without fee is hereby granted, provided that the above
760484Sobrien * copyright notice and this permission notice appear in all copies.
860484Sobrien *
9218822Sdim * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
1060484Sobrien * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
1160484Sobrien * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
1260484Sobrien * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
1360484Sobrien * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
1460484Sobrien * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
1560484Sobrien * PERFORMANCE OF THIS SOFTWARE.
1660484Sobrien */
1760484Sobrien
1860484Sobrien/* $Id: rdata.c,v 1.184.18.9 2006/07/21 02:05:57 marka Exp $ */
1960484Sobrien
2060484Sobrien/*! \file */
2160484Sobrien
2260484Sobrien#include <config.h>
2360484Sobrien#include <ctype.h>
2460484Sobrien
2560484Sobrien#include <isc/base64.h>
2660484Sobrien#include <isc/hex.h>
2760484Sobrien#include <isc/lex.h>
2860484Sobrien#include <isc/mem.h>
2960484Sobrien#include <isc/parseint.h>
3060484Sobrien#include <isc/print.h>
3160484Sobrien#include <isc/string.h>
3260484Sobrien#include <isc/stdlib.h>
3360484Sobrien#include <isc/util.h>
3460484Sobrien
3560484Sobrien#include <dns/callbacks.h>
3660484Sobrien#include <dns/cert.h>
3760484Sobrien#include <dns/compress.h>
38218822Sdim#include <dns/enumtype.h>
3960484Sobrien#include <dns/keyflags.h>
4060484Sobrien#include <dns/keyvalues.h>
4160484Sobrien#include <dns/rcode.h>
4260484Sobrien#include <dns/rdata.h>
4360484Sobrien#include <dns/rdataclass.h>
4460484Sobrien#include <dns/rdatastruct.h>
4560484Sobrien#include <dns/rdatatype.h>
4660484Sobrien#include <dns/result.h>
4760484Sobrien#include <dns/secalg.h>
4860484Sobrien#include <dns/secproto.h>
4960484Sobrien#include <dns/time.h>
5060484Sobrien#include <dns/ttl.h>
5160484Sobrien
5260484Sobrien#define RETERR(x) \
5360484Sobrien	do { \
5460484Sobrien		isc_result_t _r = (x); \
5560484Sobrien		if (_r != ISC_R_SUCCESS) \
5660484Sobrien			return (_r); \
5760484Sobrien	} while (0)
5860484Sobrien
5960484Sobrien#define RETTOK(x) \
6060484Sobrien	do { \
6160484Sobrien		isc_result_t _r = (x); \
6260484Sobrien		if (_r != ISC_R_SUCCESS) { \
6360484Sobrien			isc_lex_ungettoken(lexer, &token); \
6460484Sobrien			return (_r); \
6560484Sobrien		} \
6660484Sobrien	} while (0)
6760484Sobrien
6860484Sobrien#define DNS_AS_STR(t) ((t).value.as_textregion.base)
6960484Sobrien
7060484Sobrien#define ARGS_FROMTEXT	int rdclass, dns_rdatatype_t type, \
7160484Sobrien			isc_lex_t *lexer, dns_name_t *origin, \
7260484Sobrien			unsigned int options, isc_buffer_t *target, \
7360484Sobrien			dns_rdatacallbacks_t *callbacks
7460484Sobrien
7560484Sobrien#define ARGS_TOTEXT	dns_rdata_t *rdata, dns_rdata_textctx_t *tctx, \
7660484Sobrien			isc_buffer_t *target
7760484Sobrien
7860484Sobrien#define ARGS_FROMWIRE	int rdclass, dns_rdatatype_t type, \
7960484Sobrien			isc_buffer_t *source, dns_decompress_t *dctx, \
8060484Sobrien			unsigned int options, isc_buffer_t *target
8160484Sobrien
8260484Sobrien#define ARGS_TOWIRE	dns_rdata_t *rdata, dns_compress_t *cctx, \
8360484Sobrien			isc_buffer_t *target
8460484Sobrien
8560484Sobrien#define ARGS_COMPARE	const dns_rdata_t *rdata1, const dns_rdata_t *rdata2
8660484Sobrien
8760484Sobrien#define ARGS_FROMSTRUCT	int rdclass, dns_rdatatype_t type, \
8860484Sobrien			void *source, isc_buffer_t *target
8960484Sobrien
9060484Sobrien#define ARGS_TOSTRUCT	dns_rdata_t *rdata, void *target, isc_mem_t *mctx
9160484Sobrien
9260484Sobrien#define ARGS_FREESTRUCT void *source
9360484Sobrien
9460484Sobrien#define ARGS_ADDLDATA	dns_rdata_t *rdata, dns_additionaldatafunc_t add, \
9560484Sobrien			void *arg
9660484Sobrien
9760484Sobrien#define ARGS_DIGEST	dns_rdata_t *rdata, dns_digestfunc_t digest, void *arg
9860484Sobrien
9960484Sobrien#define ARGS_CHECKOWNER dns_name_t *name, dns_rdataclass_t rdclass, \
10060484Sobrien			dns_rdatatype_t type, isc_boolean_t wildcard
10160484Sobrien
10260484Sobrien#define ARGS_CHECKNAMES dns_rdata_t *rdata, dns_name_t *owner, dns_name_t *bad
10360484Sobrien
10460484Sobrien
10560484Sobrien/*%
106218822Sdim * Context structure for the totext_ functions.
10760484Sobrien * Contains formatting options for rdata-to-text
10860484Sobrien * conversion.
10960484Sobrien */
11060484Sobrientypedef struct dns_rdata_textctx {
11160484Sobrien	dns_name_t *origin;	/*%< Current origin, or NULL. */
11260484Sobrien	unsigned int flags;	/*%< DNS_STYLEFLAG_*  */
11360484Sobrien	unsigned int width;	/*%< Width of rdata column. */
11460484Sobrien  	const char *linebreak;	/*%< Line break string. */
11560484Sobrien} dns_rdata_textctx_t;
11660484Sobrien
11760484Sobrienstatic isc_result_t
11860484Sobrientxt_totext(isc_region_t *source, isc_buffer_t *target);
11960484Sobrien
12060484Sobrienstatic isc_result_t
12160484Sobrientxt_fromtext(isc_textregion_t *source, isc_buffer_t *target);
12260484Sobrien
12360484Sobrienstatic isc_result_t
12460484Sobrientxt_fromwire(isc_buffer_t *source, isc_buffer_t *target);
12560484Sobrien
12660484Sobrienstatic isc_boolean_t
12760484Sobrienname_prefix(dns_name_t *name, dns_name_t *origin, dns_name_t *target);
12860484Sobrien
12960484Sobrienstatic unsigned int
13060484Sobrienname_length(dns_name_t *name);
13160484Sobrien
13260484Sobrienstatic isc_result_t
13360484Sobrienstr_totext(const char *source, isc_buffer_t *target);
13460484Sobrien
135218822Sdimstatic isc_result_t
13660484Sobrieninet_totext(int af, isc_region_t *src, isc_buffer_t *target);
13760484Sobrien
13860484Sobrienstatic isc_boolean_t
13960484Sobrienbuffer_empty(isc_buffer_t *source);
14060484Sobrien
14160484Sobrienstatic void
14260484Sobrienbuffer_fromregion(isc_buffer_t *buffer, isc_region_t *region);
14360484Sobrien
14460484Sobrienstatic isc_result_t
14560484Sobrienuint32_tobuffer(isc_uint32_t, isc_buffer_t *target);
14660484Sobrien
14760484Sobrienstatic isc_result_t
14860484Sobrienuint16_tobuffer(isc_uint32_t, isc_buffer_t *target);
14960484Sobrien
15060484Sobrienstatic isc_result_t
15160484Sobrienuint8_tobuffer(isc_uint32_t, isc_buffer_t *target);
15260484Sobrien
15360484Sobrienstatic isc_result_t
15460484Sobrienname_tobuffer(dns_name_t *name, isc_buffer_t *target);
15560484Sobrien
15660484Sobrienstatic isc_uint32_t
15760484Sobrienuint32_fromregion(isc_region_t *region);
15860484Sobrien
15960484Sobrienstatic isc_uint16_t
16060484Sobrienuint16_fromregion(isc_region_t *region);
16160484Sobrien
16260484Sobrienstatic isc_uint8_t
16360484Sobrienuint8_fromregion(isc_region_t *region);
16460484Sobrien
16560484Sobrienstatic isc_result_t
16660484Sobrienmem_tobuffer(isc_buffer_t *target, void *base, unsigned int length);
16760484Sobrien
16860484Sobrienstatic int
16960484Sobrienhexvalue(char value);
17060484Sobrien
17160484Sobrienstatic int
17260484Sobriendecvalue(char value);
17360484Sobrien
17460484Sobrienstatic isc_result_t
17560484Sobrienbtoa_totext(unsigned char *inbuf, int inbuflen, isc_buffer_t *target);
17660484Sobrien
17760484Sobrienstatic isc_result_t
17860484Sobrienatob_tobuffer(isc_lex_t *lexer, isc_buffer_t *target);
17960484Sobrien
18060484Sobrienstatic void
18160484Sobriendefault_fromtext_callback(dns_rdatacallbacks_t *callbacks, const char *, ...)
18260484Sobrien     ISC_FORMAT_PRINTF(2, 3);
18360484Sobrien
18460484Sobrienstatic void
18560484Sobrienfromtext_error(void (*callback)(dns_rdatacallbacks_t *, const char *, ...),
18660484Sobrien	       dns_rdatacallbacks_t *callbacks, const char *name,
18760484Sobrien	       unsigned long line, isc_token_t *token, isc_result_t result);
18860484Sobrien
18960484Sobrienstatic void
19060484Sobrienfromtext_warneof(isc_lex_t *lexer, dns_rdatacallbacks_t *callbacks);
19160484Sobrien
19260484Sobrienstatic isc_result_t
19360484Sobrienrdata_totext(dns_rdata_t *rdata, dns_rdata_textctx_t *tctx,
19460484Sobrien	     isc_buffer_t *target);
19560484Sobrien
19660484Sobrienstatic void
19760484Sobrienwarn_badname(dns_name_t *name, isc_lex_t *lexer,
19860484Sobrien	     dns_rdatacallbacks_t *callbacks);
19960484Sobrien
20060484Sobrienstatic void
20160484Sobrienwarn_badmx(isc_token_t *token, isc_lex_t *lexer,
202218822Sdim	   dns_rdatacallbacks_t *callbacks);
20360484Sobrien
20460484Sobrienstatic inline int
20560484Sobriengetquad(const void *src, struct in_addr *dst,
20660484Sobrien	isc_lex_t *lexer, dns_rdatacallbacks_t *callbacks)
20760484Sobrien{
20860484Sobrien	int result;
209104834Sobrien	struct in_addr *tmp;
21060484Sobrien
21160484Sobrien	result = inet_aton(src, dst);
21260484Sobrien	if (result == 1 && callbacks != NULL &&
21360484Sobrien	    inet_pton(AF_INET, src, &tmp) != 1) {
21460484Sobrien		const char *name = isc_lex_getsourcename(lexer);
21560484Sobrien		if (name == NULL)
21660484Sobrien			name = "UNKNOWN";
21760484Sobrien		(*callbacks->warn)(callbacks, "%s:%lu: \"%s\" "
21860484Sobrien				   "is not a decimal dotted quad", name,
21960484Sobrien				   isc_lex_getsourceline(lexer), src);
22060484Sobrien	}
22160484Sobrien	return (result);
22260484Sobrien}
22360484Sobrien
22460484Sobrienstatic inline isc_result_t
22560484Sobrienname_duporclone(dns_name_t *source, isc_mem_t *mctx, dns_name_t *target) {
22660484Sobrien
227104834Sobrien	if (mctx != NULL)
22860484Sobrien		return (dns_name_dup(source, mctx, target));
22960484Sobrien	dns_name_clone(source, target);
23060484Sobrien	return (ISC_R_SUCCESS);
23160484Sobrien}
23260484Sobrien
23360484Sobrienstatic inline void *
23460484Sobrienmem_maybedup(isc_mem_t *mctx, void *source, size_t length) {
23560484Sobrien	void *new;
23660484Sobrien
23760484Sobrien	if (mctx == NULL)
23860484Sobrien		return (source);
23960484Sobrien	new = isc_mem_allocate(mctx, length);
24060484Sobrien	if (new != NULL)
24160484Sobrien		memcpy(new, source, length);
24260484Sobrien
24360484Sobrien	return (new);
244218822Sdim}
24560484Sobrien
24660484Sobrienstatic const char hexdigits[] = "0123456789abcdef";
24760484Sobrienstatic const char decdigits[] = "0123456789";
24860484Sobrien
24960484Sobrien#include "code.h"
250104834Sobrien
25160484Sobrien#define META 0x0001
25260484Sobrien#define RESERVED 0x0002
25360484Sobrien
25460484Sobrien/***
25560484Sobrien *** Initialization
25660484Sobrien ***/
25760484Sobrien
25860484Sobrienvoid
25960484Sobriendns_rdata_init(dns_rdata_t *rdata) {
26060484Sobrien
26160484Sobrien	REQUIRE(rdata != NULL);
26260484Sobrien
26360484Sobrien	rdata->data = NULL;
26460484Sobrien	rdata->length = 0;
265218822Sdim	rdata->rdclass = 0;
26660484Sobrien	rdata->type = 0;
26760484Sobrien	rdata->flags = 0;
26860484Sobrien	ISC_LINK_INIT(rdata, link);
26960484Sobrien	/* ISC_LIST_INIT(rdata->list); */
27060484Sobrien}
271104834Sobrien
27260484Sobrien#if 0
27360484Sobrien#define DNS_RDATA_INITIALIZED(rdata) \
27460484Sobrien	((rdata)->data == NULL && (rdata)->length == 0 && \
27560484Sobrien	 (rdata)->rdclass == 0 && (rdata)->type == 0 && (rdata)->flags == 0 && \
27660484Sobrien	 !ISC_LINK_LINKED((rdata), link))
27760484Sobrien#else
27860484Sobrien#ifdef ISC_LIST_CHECKINIT
27960484Sobrien#define DNS_RDATA_INITIALIZED(rdata) \
28060484Sobrien	(!ISC_LINK_LINKED((rdata), link))
28160484Sobrien#else
28260484Sobrien#define DNS_RDATA_INITIALIZED(rdata) ISC_TRUE
28360484Sobrien#endif
28460484Sobrien#endif
28560484Sobrien#define DNS_RDATA_VALIDFLAGS(rdata) \
28660484Sobrien	(((rdata)->flags & ~DNS_RDATA_UPDATE) == 0)
287218822Sdim
28860484Sobrienvoid
28960484Sobriendns_rdata_reset(dns_rdata_t *rdata) {
29060484Sobrien
29160484Sobrien	REQUIRE(rdata != NULL);
29260484Sobrien
293104834Sobrien	REQUIRE(!ISC_LINK_LINKED(rdata, link));
29460484Sobrien	REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
29560484Sobrien
29660484Sobrien	rdata->data = NULL;
29760484Sobrien	rdata->length = 0;
29860484Sobrien	rdata->rdclass = 0;
29960484Sobrien	rdata->type = 0;
30060484Sobrien	rdata->flags = 0;
30160484Sobrien}
30260484Sobrien
30360484Sobrien/***
30460484Sobrien ***
30560484Sobrien ***/
306104834Sobrien
30760484Sobrienvoid
30860484Sobriendns_rdata_clone(const dns_rdata_t *src, dns_rdata_t *target) {
30960484Sobrien
31060484Sobrien	REQUIRE(src != NULL);
31160484Sobrien	REQUIRE(target != NULL);
31260484Sobrien
31360484Sobrien	REQUIRE(DNS_RDATA_INITIALIZED(target));
31460484Sobrien
31560484Sobrien	REQUIRE(DNS_RDATA_VALIDFLAGS(src));
31660484Sobrien	REQUIRE(DNS_RDATA_VALIDFLAGS(target));
31760484Sobrien
31860484Sobrien	target->data = src->data;
319104834Sobrien	target->length = src->length;
32060484Sobrien	target->rdclass = src->rdclass;
32160484Sobrien	target->type = src->type;
32260484Sobrien	target->flags = src->flags;
32360484Sobrien}
32460484Sobrien
32560484Sobrien
32660484Sobrien/***
32760484Sobrien *** Comparisons
32860484Sobrien ***/
32960484Sobrien
33060484Sobrienint
33160484Sobriendns_rdata_compare(const dns_rdata_t *rdata1, const dns_rdata_t *rdata2) {
33260484Sobrien	int result = 0;
33360484Sobrien	isc_boolean_t use_default = ISC_FALSE;
33460484Sobrien
33560484Sobrien	REQUIRE(rdata1 != NULL);
33660484Sobrien	REQUIRE(rdata2 != NULL);
33760484Sobrien	REQUIRE(rdata1->data != NULL);
338218822Sdim	REQUIRE(rdata2->data != NULL);
33960484Sobrien	REQUIRE(DNS_RDATA_VALIDFLAGS(rdata1));
34060484Sobrien	REQUIRE(DNS_RDATA_VALIDFLAGS(rdata2));
34160484Sobrien
34260484Sobrien	if (rdata1->rdclass != rdata2->rdclass)
34360484Sobrien		return (rdata1->rdclass < rdata2->rdclass ? -1 : 1);
34460484Sobrien
345104834Sobrien	if (rdata1->type != rdata2->type)
34660484Sobrien		return (rdata1->type < rdata2->type ? -1 : 1);
34760484Sobrien
34860484Sobrien	COMPARESWITCH
34960484Sobrien
35060484Sobrien	if (use_default) {
35160484Sobrien		isc_region_t r1;
35260484Sobrien		isc_region_t r2;
35360484Sobrien
35460484Sobrien		dns_rdata_toregion(rdata1, &r1);
35560484Sobrien		dns_rdata_toregion(rdata2, &r2);
35660484Sobrien		result = isc_region_compare(&r1, &r2);
35760484Sobrien	}
35860484Sobrien	return (result);
35960484Sobrien}
36060484Sobrien
36160484Sobrien/***
36260484Sobrien *** Conversions
363104834Sobrien ***/
36460484Sobrien
36560484Sobrienvoid
36660484Sobriendns_rdata_fromregion(dns_rdata_t *rdata, dns_rdataclass_t rdclass,
36760484Sobrien		     dns_rdatatype_t type, isc_region_t *r)
36860484Sobrien{
36960484Sobrien
37060484Sobrien	REQUIRE(rdata != NULL);
37160484Sobrien	REQUIRE(DNS_RDATA_INITIALIZED(rdata));
37260484Sobrien	REQUIRE(r != NULL);
37360484Sobrien
37460484Sobrien	REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
37560484Sobrien
37660484Sobrien	rdata->data = r->base;
37760484Sobrien	rdata->length = r->length;
378218822Sdim	rdata->rdclass = rdclass;
37960484Sobrien	rdata->type = type;
38060484Sobrien	rdata->flags = 0;
38160484Sobrien}
38260484Sobrien
38360484Sobrienvoid
38460484Sobriendns_rdata_toregion(const dns_rdata_t *rdata, isc_region_t *r) {
38560484Sobrien
38660484Sobrien	REQUIRE(rdata != NULL);
38760484Sobrien	REQUIRE(r != NULL);
38860484Sobrien	REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
38960484Sobrien
39060484Sobrien	r->base = rdata->data;
391104834Sobrien	r->length = rdata->length;
39260484Sobrien}
39360484Sobrien
39460484Sobrienisc_result_t
39560484Sobriendns_rdata_fromwire(dns_rdata_t *rdata, dns_rdataclass_t rdclass,
39660484Sobrien		   dns_rdatatype_t type, isc_buffer_t *source,
39760484Sobrien		   dns_decompress_t *dctx, unsigned int options,
39860484Sobrien		   isc_buffer_t *target)
39960484Sobrien{
40060484Sobrien	isc_result_t result = ISC_R_NOTIMPLEMENTED;
40160484Sobrien	isc_region_t region;
40260484Sobrien	isc_buffer_t ss;
40360484Sobrien	isc_buffer_t st;
40460484Sobrien	isc_boolean_t use_default = ISC_FALSE;
40560484Sobrien	isc_uint32_t activelength;
40660484Sobrien
40760484Sobrien	REQUIRE(dctx != NULL);
40860484Sobrien	if (rdata != NULL) {
40960484Sobrien		REQUIRE(DNS_RDATA_INITIALIZED(rdata));
41060484Sobrien		REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
41160484Sobrien	}
41260484Sobrien
41360484Sobrien	if (type == 0)
41460484Sobrien		return (DNS_R_FORMERR);
41560484Sobrien
41660484Sobrien	ss = *source;
41760484Sobrien	st = *target;
41860484Sobrien
41960484Sobrien	activelength = isc_buffer_activelength(source);
42060484Sobrien	INSIST(activelength < 65536);
42160484Sobrien
42260484Sobrien	FROMWIRESWITCH
423104834Sobrien
42460484Sobrien	if (use_default) {
42560484Sobrien		if (activelength > isc_buffer_availablelength(target))
42660484Sobrien			result = ISC_R_NOSPACE;
42760484Sobrien		else {
42860484Sobrien			isc_buffer_putmem(target, isc_buffer_current(source),
42960484Sobrien					  activelength);
43060484Sobrien			isc_buffer_forward(source, activelength);
43160484Sobrien			result = ISC_R_SUCCESS;
43260484Sobrien		}
43360484Sobrien	}
43460484Sobrien
43560484Sobrien	/*
43660484Sobrien	 * We should have consumed all of our buffer.
43760484Sobrien	 */
43860484Sobrien	if (result == ISC_R_SUCCESS && !buffer_empty(source))
43960484Sobrien		result = DNS_R_EXTRADATA;
44060484Sobrien
44160484Sobrien	if (rdata != NULL && result == ISC_R_SUCCESS) {
44260484Sobrien		region.base = isc_buffer_used(&st);
44360484Sobrien		region.length = isc_buffer_usedlength(target) -
44460484Sobrien				isc_buffer_usedlength(&st);
44560484Sobrien		dns_rdata_fromregion(rdata, rdclass, type, &region);
44660484Sobrien	}
44760484Sobrien
44860484Sobrien	if (result != ISC_R_SUCCESS) {
44960484Sobrien		*source = ss;
45060484Sobrien		*target = st;
45160484Sobrien	}
45260484Sobrien	return (result);
45360484Sobrien}
45460484Sobrien
45560484Sobrienisc_result_t
45660484Sobriendns_rdata_towire(dns_rdata_t *rdata, dns_compress_t *cctx,
45760484Sobrien		 isc_buffer_t *target)
45860484Sobrien{
45960484Sobrien	isc_result_t result = ISC_R_NOTIMPLEMENTED;
460218822Sdim	isc_boolean_t use_default = ISC_FALSE;
46160484Sobrien	isc_region_t tr;
46260484Sobrien	isc_buffer_t st;
46360484Sobrien
46460484Sobrien	REQUIRE(rdata != NULL);
46560484Sobrien	REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
466104834Sobrien
46760484Sobrien	/*
46860484Sobrien	 * Some DynDNS meta-RRs have empty rdata.
46960484Sobrien	 */
47060484Sobrien	if ((rdata->flags & DNS_RDATA_UPDATE) != 0) {
47160484Sobrien		INSIST(rdata->length == 0);
47260484Sobrien		return (ISC_R_SUCCESS);
47360484Sobrien	}
47460484Sobrien
47560484Sobrien	st = *target;
47660484Sobrien
47760484Sobrien	TOWIRESWITCH
47860484Sobrien
47960484Sobrien	if (use_default) {
480218822Sdim		isc_buffer_availableregion(target, &tr);
48160484Sobrien		if (tr.length < rdata->length)
48260484Sobrien			return (ISC_R_NOSPACE);
48360484Sobrien		memcpy(tr.base, rdata->data, rdata->length);
48460484Sobrien		isc_buffer_add(target, rdata->length);
48560484Sobrien		return (ISC_R_SUCCESS);
486104834Sobrien	}
48760484Sobrien	if (result != ISC_R_SUCCESS) {
48860484Sobrien		*target = st;
48960484Sobrien		INSIST(target->used < 65536);
49060484Sobrien		dns_compress_rollback(cctx, (isc_uint16_t)target->used);
49160484Sobrien	}
49260484Sobrien	return (result);
49360484Sobrien}
49460484Sobrien
49560484Sobrien/*
49660484Sobrien * If the binary data in 'src' is valid uncompressed wire format
49760484Sobrien * rdata of class 'rdclass' and type 'type', return ISC_R_SUCCESS
49860484Sobrien * and copy the validated rdata to 'dest'.  Otherwise return an error.
49960484Sobrien */
50060484Sobrienstatic isc_result_t
501218822Sdimrdata_validate(isc_buffer_t *src, isc_buffer_t *dest, dns_rdataclass_t rdclass,
50260484Sobrien	    dns_rdatatype_t type)
50360484Sobrien{
50460484Sobrien	dns_decompress_t dctx;
50560484Sobrien	dns_rdata_t rdata = DNS_RDATA_INIT;
50660484Sobrien	isc_result_t result;
50760484Sobrien
50860484Sobrien	dns_decompress_init(&dctx, -1, DNS_DECOMPRESS_NONE);
509104834Sobrien	isc_buffer_setactive(src, isc_buffer_usedlength(src));
51060484Sobrien	result = dns_rdata_fromwire(&rdata, rdclass, type, src,
51160484Sobrien				    &dctx, 0, dest);
51260484Sobrien	dns_decompress_invalidate(&dctx);
51360484Sobrien
51460484Sobrien	return (result);
51560484Sobrien}
51660484Sobrien
51760484Sobrienstatic isc_result_t
51860484Sobrienunknown_fromtext(dns_rdataclass_t rdclass, dns_rdatatype_t type,
51960484Sobrien		 isc_lex_t *lexer, isc_mem_t *mctx, isc_buffer_t *target)
52060484Sobrien{
52160484Sobrien	isc_result_t result;
52260484Sobrien	isc_buffer_t *buf = NULL;
52360484Sobrien	isc_token_t token;
524104834Sobrien
52560484Sobrien	if (type == 0 || dns_rdatatype_ismeta(type))
52660484Sobrien		return (DNS_R_METATYPE);
52760484Sobrien
52860484Sobrien	result = isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
52960484Sobrien					ISC_FALSE);
53060484Sobrien	if (result == ISC_R_SUCCESS && token.value.as_ulong > 65535U)
53160484Sobrien		return (ISC_R_RANGE);
53260484Sobrien	result = isc_buffer_allocate(mctx, &buf, token.value.as_ulong);
53360484Sobrien	if (result != ISC_R_SUCCESS)
53460484Sobrien		return (result);
53560484Sobrien
53660484Sobrien	result = isc_hex_tobuffer(lexer, buf,
53760484Sobrien				  (unsigned int)token.value.as_ulong);
53860484Sobrien	if (result != ISC_R_SUCCESS)
539104834Sobrien	       goto failure;
54060484Sobrien	if (isc_buffer_usedlength(buf) != token.value.as_ulong) {
54160484Sobrien		result = ISC_R_UNEXPECTEDEND;
54260484Sobrien		goto failure;
54360484Sobrien	}
54460484Sobrien
54560484Sobrien	if (dns_rdatatype_isknown(type)) {
54660484Sobrien		result = rdata_validate(buf, target, rdclass, type);
54760484Sobrien	} else {
54860484Sobrien		isc_region_t r;
54960484Sobrien		isc_buffer_usedregion(buf, &r);
55060484Sobrien		result = isc_buffer_copyregion(target, &r);
55160484Sobrien	}
55260484Sobrien	if (result != ISC_R_SUCCESS)
55360484Sobrien		goto failure;
55460484Sobrien
55560484Sobrien	isc_buffer_free(&buf);
556104834Sobrien	return (ISC_R_SUCCESS);
55760484Sobrien
55860484Sobrien failure:
55960484Sobrien	isc_buffer_free(&buf);
56060484Sobrien	return (result);
56160484Sobrien}
56260484Sobrien
56360484Sobrienisc_result_t
56460484Sobriendns_rdata_fromtext(dns_rdata_t *rdata, dns_rdataclass_t rdclass,
56560484Sobrien		   dns_rdatatype_t type, isc_lex_t *lexer,
56660484Sobrien		   dns_name_t *origin, unsigned int options, isc_mem_t *mctx,
56760484Sobrien		   isc_buffer_t *target, dns_rdatacallbacks_t *callbacks)
56860484Sobrien{
56960484Sobrien	isc_result_t result = ISC_R_NOTIMPLEMENTED;
57060484Sobrien	isc_region_t region;
57160484Sobrien	isc_buffer_t st;
57260484Sobrien	isc_token_t token;
57360484Sobrien	unsigned int lexoptions = ISC_LEXOPT_EOL | ISC_LEXOPT_EOF |
574104834Sobrien				  ISC_LEXOPT_DNSMULTILINE | ISC_LEXOPT_ESCAPE;
57560484Sobrien	char *name;
57660484Sobrien	unsigned long line;
57760484Sobrien	void (*callback)(dns_rdatacallbacks_t *, const char *, ...);
57860484Sobrien	isc_result_t tresult;
57960484Sobrien
58060484Sobrien	REQUIRE(origin == NULL || dns_name_isabsolute(origin) == ISC_TRUE);
58160484Sobrien	if (rdata != NULL) {
58260484Sobrien		REQUIRE(DNS_RDATA_INITIALIZED(rdata));
58360484Sobrien		REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
58460484Sobrien	}
58560484Sobrien	if (callbacks != NULL) {
58660484Sobrien		REQUIRE(callbacks->warn != NULL);
58760484Sobrien		REQUIRE(callbacks->error != NULL);
58860484Sobrien	}
58960484Sobrien
59060484Sobrien	st = *target;
59160484Sobrien
59260484Sobrien	if (callbacks != NULL)
59360484Sobrien		callback = callbacks->error;
594218822Sdim	else
59560484Sobrien		callback = default_fromtext_callback;
59660484Sobrien
59760484Sobrien	result = isc_lex_getmastertoken(lexer, &token, isc_tokentype_qstring,
59860484Sobrien					ISC_FALSE);
59960484Sobrien	if (result != ISC_R_SUCCESS) {
600104834Sobrien		name = isc_lex_getsourcename(lexer);
60160484Sobrien		line = isc_lex_getsourceline(lexer);
60260484Sobrien		fromtext_error(callback, callbacks, name, line,
60360484Sobrien			       &token, result);
60460484Sobrien		return (result);
60560484Sobrien	}
60660484Sobrien
60760484Sobrien	if (strcmp(DNS_AS_STR(token), "\\#") == 0)
60860484Sobrien		result = unknown_fromtext(rdclass, type, lexer, mctx, target);
60960484Sobrien	else {
61060484Sobrien		isc_lex_ungettoken(lexer, &token);
61160484Sobrien
61260484Sobrien		FROMTEXTSWITCH
61360484Sobrien	}
61460484Sobrien
61560484Sobrien	/*
616104834Sobrien	 * Consume to end of line / file.
61760484Sobrien	 * If not at end of line initially set error code.
61860484Sobrien	 * Call callback via fromtext_error once if there was an error.
61960484Sobrien	 */
62060484Sobrien	do {
62160484Sobrien		name = isc_lex_getsourcename(lexer);
62260484Sobrien		line = isc_lex_getsourceline(lexer);
62360484Sobrien		tresult = isc_lex_gettoken(lexer, lexoptions, &token);
62460484Sobrien		if (tresult != ISC_R_SUCCESS) {
62560484Sobrien			if (result == ISC_R_SUCCESS)
62660484Sobrien				result = tresult;
62760484Sobrien			if (callback != NULL)
62860484Sobrien				fromtext_error(callback, callbacks, name,
62960484Sobrien					       line, NULL, result);
63060484Sobrien			break;
631104834Sobrien		} else if (token.type != isc_tokentype_eol &&
63260484Sobrien			   token.type != isc_tokentype_eof) {
63360484Sobrien			if (result == ISC_R_SUCCESS)
63460484Sobrien				result = DNS_R_EXTRATOKEN;
63560484Sobrien			if (callback != NULL) {
63660484Sobrien				fromtext_error(callback, callbacks, name,
63760484Sobrien					       line, &token, result);
63860484Sobrien				callback = NULL;
63960484Sobrien			}
64060484Sobrien		} else if (result != ISC_R_SUCCESS && callback != NULL) {
64160484Sobrien			fromtext_error(callback, callbacks, name, line,
64260484Sobrien				       &token, result);
64360484Sobrien			break;
64460484Sobrien		} else {
64560484Sobrien			if (token.type == isc_tokentype_eof)
646104834Sobrien				fromtext_warneof(lexer, callbacks);
64760484Sobrien			break;
64860484Sobrien		}
64960484Sobrien	} while (1);
65060484Sobrien
65160484Sobrien	if (rdata != NULL && result == ISC_R_SUCCESS) {
65260484Sobrien		region.base = isc_buffer_used(&st);
65360484Sobrien		region.length = isc_buffer_usedlength(target) -
65460484Sobrien				isc_buffer_usedlength(&st);
65560484Sobrien		dns_rdata_fromregion(rdata, rdclass, type, &region);
65660484Sobrien	}
65760484Sobrien	if (result != ISC_R_SUCCESS) {
65860484Sobrien		*target = st;
65960484Sobrien	}
66060484Sobrien	return (result);
661104834Sobrien}
66260484Sobrien
66360484Sobrienstatic isc_result_t
66460484Sobrienrdata_totext(dns_rdata_t *rdata, dns_rdata_textctx_t *tctx,
66560484Sobrien	     isc_buffer_t *target)
66660484Sobrien{
66760484Sobrien	isc_result_t result = ISC_R_NOTIMPLEMENTED;
66860484Sobrien	isc_boolean_t use_default = ISC_FALSE;
66960484Sobrien	char buf[sizeof("65535")];
67060484Sobrien	isc_region_t sr;
67160484Sobrien
67260484Sobrien	REQUIRE(rdata != NULL);
67360484Sobrien	REQUIRE(tctx->origin == NULL ||
67460484Sobrien		dns_name_isabsolute(tctx->origin) == ISC_TRUE);
675104834Sobrien
67660484Sobrien	/*
67760484Sobrien	 * Some DynDNS meta-RRs have empty rdata.
67860484Sobrien	 */
67960484Sobrien	if ((rdata->flags & DNS_RDATA_UPDATE) != 0) {
68060484Sobrien		INSIST(rdata->length == 0);
68160484Sobrien		return (ISC_R_SUCCESS);
68260484Sobrien	}
68360484Sobrien
68460484Sobrien	TOTEXTSWITCH
685104834Sobrien
68660484Sobrien	if (use_default) {
68760484Sobrien		strlcpy(buf, "\\# ", sizeof(buf));
68860484Sobrien		result = str_totext(buf, target);
68960484Sobrien		dns_rdata_toregion(rdata, &sr);
69060484Sobrien		INSIST(sr.length < 65536);
69160484Sobrien		snprintf(buf, sizeof(buf), "%u", sr.length);
69260484Sobrien		result = str_totext(buf, target);
69360484Sobrien		if (sr.length != 0 && result == ISC_R_SUCCESS) {
694104834Sobrien			if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0)
69560484Sobrien				result = str_totext(" ( ", target);
69660484Sobrien			else
69760484Sobrien				result = str_totext(" ", target);
69860484Sobrien			if (result == ISC_R_SUCCESS)
69960484Sobrien				result = isc_hex_totext(&sr, tctx->width - 2,
70060484Sobrien							tctx->linebreak,
70160484Sobrien							target);
70260484Sobrien			if (result == ISC_R_SUCCESS &&
703104834Sobrien			    (tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0)
70460484Sobrien				result = str_totext(" )", target);
70560484Sobrien		}
70660484Sobrien	}
70760484Sobrien
70860484Sobrien	return (result);
70960484Sobrien}
71060484Sobrien
71160484Sobrienisc_result_t
712104834Sobriendns_rdata_totext(dns_rdata_t *rdata, dns_name_t *origin, isc_buffer_t *target)
71360484Sobrien{
71460484Sobrien	dns_rdata_textctx_t tctx;
71560484Sobrien
71660484Sobrien	REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
71760484Sobrien
71860484Sobrien	/*
71960484Sobrien	 * Set up formatting options for single-line output.
72060484Sobrien	 */
72160484Sobrien	tctx.origin = origin;
72260484Sobrien	tctx.flags = 0;
72360484Sobrien	tctx.width = 60;
72460484Sobrien	tctx.linebreak = " ";
72560484Sobrien	return (rdata_totext(rdata, &tctx, target));
72660484Sobrien}
72760484Sobrien
72860484Sobrienisc_result_t
72960484Sobriendns_rdata_tofmttext(dns_rdata_t *rdata, dns_name_t *origin,
73060484Sobrien		    unsigned int flags, unsigned int width,
73160484Sobrien		    char *linebreak, isc_buffer_t *target)
73260484Sobrien{
73360484Sobrien	dns_rdata_textctx_t tctx;
73460484Sobrien
73560484Sobrien	REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
73660484Sobrien
73760484Sobrien	/*
73860484Sobrien	 * Set up formatting options for formatted output.
73960484Sobrien	 */
74060484Sobrien	tctx.origin = origin;
74160484Sobrien	tctx.flags = flags;
74260484Sobrien	if ((flags & DNS_STYLEFLAG_MULTILINE) != 0) {
74360484Sobrien		tctx.width = width;
74460484Sobrien		tctx.linebreak = linebreak;
74560484Sobrien	} else {
74660484Sobrien		tctx.width = 60; /* Used for hex word length only. */
74760484Sobrien		tctx.linebreak = " ";
74860484Sobrien	}
74960484Sobrien	return (rdata_totext(rdata, &tctx, target));
75060484Sobrien}
75160484Sobrien
75260484Sobrienisc_result_t
75360484Sobriendns_rdata_fromstruct(dns_rdata_t *rdata, dns_rdataclass_t rdclass,
75460484Sobrien		     dns_rdatatype_t type, void *source,
755218822Sdim		     isc_buffer_t *target)
75660484Sobrien{
75760484Sobrien	isc_result_t result = ISC_R_NOTIMPLEMENTED;
75860484Sobrien	isc_buffer_t st;
75960484Sobrien	isc_region_t region;
76060484Sobrien	isc_boolean_t use_default = ISC_FALSE;
76160484Sobrien
76260484Sobrien	REQUIRE(source != NULL);
76360484Sobrien	if (rdata != NULL) {
76460484Sobrien		REQUIRE(DNS_RDATA_INITIALIZED(rdata));
76560484Sobrien		REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
76660484Sobrien	}
76760484Sobrien
76860484Sobrien	st = *target;
76960484Sobrien
77060484Sobrien	FROMSTRUCTSWITCH
77160484Sobrien
77260484Sobrien	if (use_default)
77360484Sobrien		(void)NULL;
77460484Sobrien
77560484Sobrien	if (rdata != NULL && result == ISC_R_SUCCESS) {
77660484Sobrien		region.base = isc_buffer_used(&st);
77760484Sobrien		region.length = isc_buffer_usedlength(target) -
77860484Sobrien				isc_buffer_usedlength(&st);
77960484Sobrien		dns_rdata_fromregion(rdata, rdclass, type, &region);
78060484Sobrien	}
78160484Sobrien	if (result != ISC_R_SUCCESS)
78260484Sobrien		*target = st;
78360484Sobrien	return (result);
78460484Sobrien}
78560484Sobrien
78660484Sobrienisc_result_t
78760484Sobriendns_rdata_tostruct(dns_rdata_t *rdata, void *target, isc_mem_t *mctx) {
78860484Sobrien	isc_result_t result = ISC_R_NOTIMPLEMENTED;
78960484Sobrien	isc_boolean_t use_default = ISC_FALSE;
79060484Sobrien
791218822Sdim	REQUIRE(rdata != NULL);
79260484Sobrien	REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
79360484Sobrien
79460484Sobrien	TOSTRUCTSWITCH
79560484Sobrien
79660484Sobrien	if (use_default)
79760484Sobrien		(void)NULL;
79860484Sobrien
79960484Sobrien	return (result);
80060484Sobrien}
80160484Sobrien
80260484Sobrienvoid
80360484Sobriendns_rdata_freestruct(void *source) {
80460484Sobrien	dns_rdatacommon_t *common = source;
80560484Sobrien	REQUIRE(source != NULL);
80660484Sobrien
80760484Sobrien	FREESTRUCTSWITCH
80860484Sobrien}
80960484Sobrien
81060484Sobrienisc_result_t
81160484Sobriendns_rdata_additionaldata(dns_rdata_t *rdata, dns_additionaldatafunc_t add,
812218822Sdim			 void *arg)
81360484Sobrien{
81460484Sobrien	isc_result_t result = ISC_R_NOTIMPLEMENTED;
81560484Sobrien	isc_boolean_t use_default = ISC_FALSE;
81660484Sobrien
81760484Sobrien	/*
81860484Sobrien	 * Call 'add' for each name and type from 'rdata' which is subject to
81960484Sobrien	 * additional section processing.
82060484Sobrien	 */
82160484Sobrien
82260484Sobrien	REQUIRE(rdata != NULL);
82360484Sobrien	REQUIRE(add != NULL);
82460484Sobrien	REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
82560484Sobrien
82660484Sobrien	ADDITIONALDATASWITCH
82760484Sobrien
82860484Sobrien	/* No additional processing for unknown types */
82960484Sobrien	if (use_default)
83060484Sobrien		result = ISC_R_SUCCESS;
83160484Sobrien
83260484Sobrien	return (result);
83360484Sobrien}
83460484Sobrien
83560484Sobrienisc_result_t
83660484Sobriendns_rdata_digest(dns_rdata_t *rdata, dns_digestfunc_t digest, void *arg) {
83760484Sobrien	isc_result_t result = ISC_R_NOTIMPLEMENTED;
83860484Sobrien	isc_boolean_t use_default = ISC_FALSE;
83960484Sobrien	isc_region_t r;
84060484Sobrien
84160484Sobrien	/*
84260484Sobrien	 * Send 'rdata' in DNSSEC canonical form to 'digest'.
84360484Sobrien	 */
84460484Sobrien
84560484Sobrien	REQUIRE(rdata != NULL);
84660484Sobrien	REQUIRE(digest != NULL);
847218822Sdim	REQUIRE(DNS_RDATA_VALIDFLAGS(rdata));
84860484Sobrien
84960484Sobrien	DIGESTSWITCH
85060484Sobrien
85160484Sobrien	if (use_default) {
852218822Sdim		dns_rdata_toregion(rdata, &r);
85360484Sobrien		result = (digest)(arg, &r);
85460484Sobrien	}
85560484Sobrien
85660484Sobrien	return (result);
85760484Sobrien}
85860484Sobrien
85960484Sobrienisc_boolean_t
86060484Sobriendns_rdata_checkowner(dns_name_t *name, dns_rdataclass_t rdclass,
861104834Sobrien		     dns_rdatatype_t type, isc_boolean_t wildcard)
86260484Sobrien{
863104834Sobrien	isc_boolean_t result;
86460484Sobrien
86560484Sobrien	CHECKOWNERSWITCH
86660484Sobrien	return (result);
86760484Sobrien}
86860484Sobrien
86960484Sobrienisc_boolean_t
87060484Sobriendns_rdata_checknames(dns_rdata_t *rdata, dns_name_t *owner, dns_name_t *bad)
87160484Sobrien{
87260484Sobrien	isc_boolean_t result;
873104834Sobrien
87460484Sobrien	CHECKNAMESSWITCH
87560484Sobrien	return (result);
87660484Sobrien}
87760484Sobrien
87860484Sobrienunsigned int
87960484Sobriendns_rdatatype_attributes(dns_rdatatype_t type)
88060484Sobrien{
88160484Sobrien	RDATATYPE_ATTRIBUTE_SW
88260484Sobrien	if (type >= (dns_rdatatype_t)128 && type < (dns_rdatatype_t)255)
88360484Sobrien		return (DNS_RDATATYPEATTR_UNKNOWN | DNS_RDATATYPEATTR_META);
88460484Sobrien	return (DNS_RDATATYPEATTR_UNKNOWN);
88560484Sobrien}
88660484Sobrien
88760484Sobrienisc_result_t
88860484Sobriendns_rdatatype_fromtext(dns_rdatatype_t *typep, isc_textregion_t *source) {
88960484Sobrien	unsigned int hash;
89060484Sobrien	unsigned int n;
89160484Sobrien	unsigned char a, b;
89260484Sobrien
89360484Sobrien	n = source->length;
894104834Sobrien
89560484Sobrien	if (n == 0)
89660484Sobrien		return (DNS_R_UNKNOWN);
89760484Sobrien
89860484Sobrien	a = tolower((unsigned char)source->base[0]);
89960484Sobrien	b = tolower((unsigned char)source->base[n - 1]);
90060484Sobrien
90160484Sobrien	hash = ((a + n) * b) % 256;
90260484Sobrien
90360484Sobrien	/*
90460484Sobrien	 * This switch block is inlined via #define, and will use "return"
90560484Sobrien	 * to return a result to the caller if it is a valid (known)
90660484Sobrien	 * rdatatype name.
90760484Sobrien	 */
90860484Sobrien	RDATATYPE_FROMTEXT_SW(hash, source->base, n, typep);
90960484Sobrien
91060484Sobrien	if (source->length > 4 && source->length < (4 + sizeof("65000")) &&
91160484Sobrien	    strncasecmp("type", source->base, 4) == 0) {
91260484Sobrien		char buf[sizeof("65000")];
91360484Sobrien		char *endp;
91460484Sobrien		unsigned int val;
91560484Sobrien
91660484Sobrien		strncpy(buf, source->base + 4, source->length - 4);
91760484Sobrien		buf[source->length - 4] = '\0';
91860484Sobrien		val = strtoul(buf, &endp, 10);
91960484Sobrien		if (*endp == '\0' && val <= 0xffff) {
92060484Sobrien			*typep = (dns_rdatatype_t)val;
92160484Sobrien			return (ISC_R_SUCCESS);
92260484Sobrien		}
92360484Sobrien	}
92460484Sobrien
92560484Sobrien	return (DNS_R_UNKNOWN);
92660484Sobrien}
92760484Sobrien
92860484Sobrienisc_result_t
92960484Sobriendns_rdatatype_totext(dns_rdatatype_t type, isc_buffer_t *target) {
93060484Sobrien	char buf[sizeof("TYPE65535")];
93160484Sobrien
93260484Sobrien	RDATATYPE_TOTEXT_SW
93360484Sobrien	snprintf(buf, sizeof(buf), "TYPE%u", type);
93460484Sobrien	return (str_totext(buf, target));
93560484Sobrien}
93660484Sobrien
93760484Sobrienvoid
938218822Sdimdns_rdatatype_format(dns_rdatatype_t rdtype,
93960484Sobrien		     char *array, unsigned int size)
94060484Sobrien{
94160484Sobrien	isc_result_t result;
94260484Sobrien	isc_buffer_t buf;
94360484Sobrien
94460484Sobrien	isc_buffer_init(&buf, array, size);
94560484Sobrien	result = dns_rdatatype_totext(rdtype, &buf);
94660484Sobrien	/*
94760484Sobrien	 * Null terminate.
94860484Sobrien	 */
94960484Sobrien	if (result == ISC_R_SUCCESS) {
95060484Sobrien		if (isc_buffer_availablelength(&buf) >= 1)
95160484Sobrien			isc_buffer_putuint8(&buf, 0);
95260484Sobrien		else
953104834Sobrien			result = ISC_R_NOSPACE;
95460484Sobrien	}
95560484Sobrien	if (result != ISC_R_SUCCESS) {
95660484Sobrien		snprintf(array, size, "<unknown>");
95760484Sobrien		array[size - 1] = '\0';
95860484Sobrien	}
95960484Sobrien}
96060484Sobrien
96160484Sobrien/*
962104834Sobrien * Private function.
963104834Sobrien */
964104834Sobrien
96560484Sobrienstatic unsigned int
966104834Sobrienname_length(dns_name_t *name) {
96760484Sobrien	return (name->length);
96860484Sobrien}
969104834Sobrien
970104834Sobrienstatic isc_result_t
971104834Sobrientxt_totext(isc_region_t *source, isc_buffer_t *target) {
972104834Sobrien	unsigned int tl;
97360484Sobrien	unsigned int n;
97460484Sobrien	unsigned char *sp;
97560484Sobrien	char *tp;
97660484Sobrien	isc_region_t region;
97760484Sobrien
97860484Sobrien	isc_buffer_availableregion(target, &region);
97960484Sobrien	sp = source->base;
98060484Sobrien	tp = (char *)region.base;
98160484Sobrien	tl = region.length;
98260484Sobrien
98360484Sobrien	n = *sp++;
98460484Sobrien
98560484Sobrien	REQUIRE(n + 1 <= source->length);
98660484Sobrien
98760484Sobrien	if (tl < 1)
988104834Sobrien		return (ISC_R_NOSPACE);
989104834Sobrien	*tp++ = '"';
990104834Sobrien	tl--;
99160484Sobrien	while (n--) {
992104834Sobrien		if (*sp < 0x20 || *sp >= 0x7f) {
99360484Sobrien			if (tl < 4)
99460484Sobrien				return (ISC_R_NOSPACE);
995104834Sobrien			*tp++ = 0x5c;
996104834Sobrien			*tp++ = 0x30 + ((*sp / 100) % 10);
997104834Sobrien			*tp++ = 0x30 + ((*sp / 10) % 10);
998104834Sobrien			*tp++ = 0x30 + (*sp % 10);
99960484Sobrien			sp++;
100060484Sobrien			tl -= 4;
100160484Sobrien			continue;
100260484Sobrien		}
100360484Sobrien		/* double quote, semi-colon, backslash */
100460484Sobrien		if (*sp == 0x22 || *sp == 0x3b || *sp == 0x5c) {
100560484Sobrien			if (tl < 2)
100660484Sobrien				return (ISC_R_NOSPACE);
100760484Sobrien			*tp++ = '\\';
100860484Sobrien			tl--;
100960484Sobrien		}
101060484Sobrien		if (tl < 1)
101160484Sobrien			return (ISC_R_NOSPACE);
101260484Sobrien		*tp++ = *sp++;
101360484Sobrien		tl--;
101460484Sobrien	}
101560484Sobrien	if (tl < 1)
101660484Sobrien		return (ISC_R_NOSPACE);
101760484Sobrien	*tp++ = '"';
101860484Sobrien	tl--;
101960484Sobrien	isc_buffer_add(target, tp - (char *)region.base);
102060484Sobrien	isc_region_consume(source, *source->base + 1);
102160484Sobrien	return (ISC_R_SUCCESS);
102260484Sobrien}
102360484Sobrien
102460484Sobrienstatic isc_result_t
102560484Sobrientxt_fromtext(isc_textregion_t *source, isc_buffer_t *target) {
102660484Sobrien	isc_region_t tregion;
1027218822Sdim	isc_boolean_t escape;
102860484Sobrien	unsigned int n, nrem;
102960484Sobrien	char *s;
103060484Sobrien	unsigned char *t;
103160484Sobrien	int d;
103260484Sobrien	int c;
103360484Sobrien
103460484Sobrien	isc_buffer_availableregion(target, &tregion);
103560484Sobrien	s = source->base;
103660484Sobrien	n = source->length;
103760484Sobrien	t = tregion.base;
103860484Sobrien	nrem = tregion.length;
103960484Sobrien	escape = ISC_FALSE;
104060484Sobrien	if (nrem < 1)
104160484Sobrien		return (ISC_R_NOSPACE);
104260484Sobrien	/*
104360484Sobrien	 * Length byte.
104460484Sobrien	 */
104560484Sobrien	nrem--;
104660484Sobrien	t++;
104760484Sobrien	/*
104860484Sobrien	 * Maximum text string length.
104960484Sobrien	 */
105060484Sobrien	if (nrem > 255)
105160484Sobrien		nrem = 255;
105260484Sobrien	while (n-- != 0) {
105360484Sobrien		c = (*s++) & 0xff;
105460484Sobrien		if (escape && (d = decvalue((char)c)) != -1) {
105560484Sobrien			c = d;
105660484Sobrien			if (n == 0)
105760484Sobrien				return (DNS_R_SYNTAX);
105860484Sobrien			n--;
105960484Sobrien			if ((d = decvalue(*s++)) != -1)
106060484Sobrien				c = c * 10 + d;
106160484Sobrien			else
106277298Sobrien				return (DNS_R_SYNTAX);
106360484Sobrien			if (n == 0)
106460484Sobrien				return (DNS_R_SYNTAX);
106560484Sobrien			n--;
106660484Sobrien			if ((d = decvalue(*s++)) != -1)
106760484Sobrien				c = c * 10 + d;
106860484Sobrien			else
106960484Sobrien				return (DNS_R_SYNTAX);
107060484Sobrien			if (c > 255)
107160484Sobrien				return (DNS_R_SYNTAX);
107260484Sobrien		} else if (!escape && c == '\\') {
1073218822Sdim			escape = ISC_TRUE;
107460484Sobrien			continue;
107560484Sobrien		}
107660484Sobrien		escape = ISC_FALSE;
107760484Sobrien		if (nrem == 0)
1078218822Sdim			return (ISC_R_NOSPACE);
107960484Sobrien		*t++ = c;
108060484Sobrien		nrem--;
108160484Sobrien	}
108260484Sobrien	if (escape)
108360484Sobrien		return (DNS_R_SYNTAX);
108460484Sobrien	*tregion.base = t - tregion.base - 1;
108560484Sobrien	isc_buffer_add(target, *tregion.base + 1);
108660484Sobrien	return (ISC_R_SUCCESS);
108760484Sobrien}
1088104834Sobrien
108960484Sobrienstatic isc_result_t
109060484Sobrientxt_fromwire(isc_buffer_t *source, isc_buffer_t *target) {
109160484Sobrien	unsigned int n;
109260484Sobrien	isc_region_t sregion;
109360484Sobrien	isc_region_t tregion;
109460484Sobrien
109560484Sobrien	isc_buffer_activeregion(source, &sregion);
109660484Sobrien	if (sregion.length == 0)
109760484Sobrien		return(ISC_R_UNEXPECTEDEND);
109860484Sobrien	n = *sregion.base + 1;
109960484Sobrien	if (n > sregion.length)
1100104834Sobrien		return (ISC_R_UNEXPECTEDEND);
110160484Sobrien
1102104834Sobrien	isc_buffer_availableregion(target, &tregion);
110360484Sobrien	if (n > tregion.length)
110460484Sobrien		return (ISC_R_NOSPACE);
110560484Sobrien
110660484Sobrien	memcpy(tregion.base, sregion.base, n);
110760484Sobrien	isc_buffer_forward(source, n);
110860484Sobrien	isc_buffer_add(target, n);
110960484Sobrien	return (ISC_R_SUCCESS);
111060484Sobrien}
111160484Sobrien
1112104834Sobrienstatic isc_boolean_t
111360484Sobrienname_prefix(dns_name_t *name, dns_name_t *origin, dns_name_t *target) {
111460484Sobrien	int l1, l2;
111560484Sobrien
111660484Sobrien	if (origin == NULL)
111760484Sobrien		goto return_false;
111860484Sobrien
111960484Sobrien	if (dns_name_compare(origin, dns_rootname) == 0)
112060484Sobrien		goto return_false;
112160484Sobrien
112260484Sobrien	if (!dns_name_issubdomain(name, origin))
112360484Sobrien		goto return_false;
112460484Sobrien
112560484Sobrien	l1 = dns_name_countlabels(name);
112660484Sobrien	l2 = dns_name_countlabels(origin);
112760484Sobrien
112860484Sobrien	if (l1 == l2)
112960484Sobrien		goto return_false;
113060484Sobrien
113160484Sobrien	dns_name_getlabelsequence(name, 0, l1 - l2, target);
113260484Sobrien	return (ISC_TRUE);
1133104834Sobrien
113460484Sobrienreturn_false:
113560484Sobrien	*target = *name;
113660484Sobrien	return (ISC_FALSE);
113760484Sobrien}
113860484Sobrien
113960484Sobrienstatic isc_result_t
114060484Sobrienstr_totext(const char *source, isc_buffer_t *target) {
114160484Sobrien	unsigned int l;
114260484Sobrien	isc_region_t region;
114360484Sobrien
114460484Sobrien	isc_buffer_availableregion(target, &region);
114560484Sobrien	l = strlen(source);
114660484Sobrien
114760484Sobrien	if (l > region.length)
114860484Sobrien		return (ISC_R_NOSPACE);
114960484Sobrien
115060484Sobrien	memcpy(region.base, source, l);
115160484Sobrien	isc_buffer_add(target, l);
115260484Sobrien	return (ISC_R_SUCCESS);
115360484Sobrien}
115460484Sobrien
115560484Sobrienstatic isc_result_t
115660484Sobrieninet_totext(int af, isc_region_t *src, isc_buffer_t *target) {
115760484Sobrien	char tmpbuf[64];
115860484Sobrien
115960484Sobrien	/* Note - inet_ntop doesn't do size checking on its input. */
116060484Sobrien	if (inet_ntop(af, src->base, tmpbuf, sizeof(tmpbuf)) == NULL)
116160484Sobrien		return (ISC_R_NOSPACE);
116260484Sobrien	if (strlen(tmpbuf) > isc_buffer_availablelength(target))
116360484Sobrien		return (ISC_R_NOSPACE);
116460484Sobrien	isc_buffer_putstr(target, tmpbuf);
116560484Sobrien	return (ISC_R_SUCCESS);
116660484Sobrien}
116760484Sobrien
116860484Sobrienstatic isc_boolean_t
116960484Sobrienbuffer_empty(isc_buffer_t *source) {
117060484Sobrien	return((source->current == source->active) ? ISC_TRUE : ISC_FALSE);
1171218822Sdim}
117260484Sobrien
117360484Sobrienstatic void
117460484Sobrienbuffer_fromregion(isc_buffer_t *buffer, isc_region_t *region) {
117560484Sobrien	isc_buffer_init(buffer, region->base, region->length);
117660484Sobrien	isc_buffer_add(buffer, region->length);
117760484Sobrien	isc_buffer_setactive(buffer, region->length);
117860484Sobrien}
117960484Sobrien
118060484Sobrienstatic isc_result_t
118160484Sobrienuint32_tobuffer(isc_uint32_t value, isc_buffer_t *target) {
118260484Sobrien	isc_region_t region;
118360484Sobrien
118460484Sobrien	isc_buffer_availableregion(target, &region);
118560484Sobrien	if (region.length < 4)
1186104834Sobrien		return (ISC_R_NOSPACE);
118760484Sobrien	isc_buffer_putuint32(target, value);
118860484Sobrien	return (ISC_R_SUCCESS);
118960484Sobrien}
119060484Sobrien
119160484Sobrienstatic isc_result_t
119260484Sobrienuint16_tobuffer(isc_uint32_t value, isc_buffer_t *target) {
119360484Sobrien	isc_region_t region;
119460484Sobrien
1195104834Sobrien	if (value > 0xffff)
1196104834Sobrien		return (ISC_R_RANGE);
1197104834Sobrien	isc_buffer_availableregion(target, &region);
119860484Sobrien	if (region.length < 2)
1199104834Sobrien		return (ISC_R_NOSPACE);
120060484Sobrien	isc_buffer_putuint16(target, (isc_uint16_t)value);
120160484Sobrien	return (ISC_R_SUCCESS);
1202104834Sobrien}
1203104834Sobrien
1204104834Sobrienstatic isc_result_t
1205104834Sobrienuint8_tobuffer(isc_uint32_t value, isc_buffer_t *target) {
120660484Sobrien	isc_region_t region;
120760484Sobrien
120860484Sobrien	if (value > 0xff)
120960484Sobrien		return (ISC_R_RANGE);
121060484Sobrien	isc_buffer_availableregion(target, &region);
121160484Sobrien	if (region.length < 1)
121260484Sobrien		return (ISC_R_NOSPACE);
121360484Sobrien	isc_buffer_putuint8(target, (isc_uint8_t)value);
121460484Sobrien	return (ISC_R_SUCCESS);
121560484Sobrien}
121660484Sobrien
121760484Sobrienstatic isc_result_t
121860484Sobrienname_tobuffer(dns_name_t *name, isc_buffer_t *target) {
121960484Sobrien	isc_region_t r;
122060484Sobrien	dns_name_toregion(name, &r);
1221104834Sobrien	return (isc_buffer_copyregion(target, &r));
1222104834Sobrien}
1223104834Sobrien
122460484Sobrienstatic isc_uint32_t
1225104834Sobrienuint32_fromregion(isc_region_t *region) {
122660484Sobrien	isc_uint32_t value;
122760484Sobrien
1228104834Sobrien	REQUIRE(region->length >= 4);
1229104834Sobrien	value = region->base[0] << 24;
1230104834Sobrien	value |= region->base[1] << 16;
1231104834Sobrien	value |= region->base[2] << 8;
123260484Sobrien	value |= region->base[3];
123360484Sobrien	return(value);
123460484Sobrien}
123560484Sobrien
123660484Sobrienstatic isc_uint16_t
123760484Sobrienuint16_fromregion(isc_region_t *region) {
123860484Sobrien
123960484Sobrien	REQUIRE(region->length >= 2);
124060484Sobrien
124160484Sobrien	return ((region->base[0] << 8) | region->base[1]);
124260484Sobrien}
124360484Sobrien
124460484Sobrienstatic isc_uint8_t
124560484Sobrienuint8_fromregion(isc_region_t *region) {
124660484Sobrien
124760484Sobrien	REQUIRE(region->length >= 1);
124860484Sobrien
124960484Sobrien	return (region->base[0]);
125060484Sobrien}
125160484Sobrien
125260484Sobrienstatic isc_result_t
125360484Sobrienmem_tobuffer(isc_buffer_t *target, void *base, unsigned int length) {
125460484Sobrien	isc_region_t tr;
125560484Sobrien
125660484Sobrien	isc_buffer_availableregion(target, &tr);
125760484Sobrien	if (length > tr.length)
125860484Sobrien		return (ISC_R_NOSPACE);
125960484Sobrien	memcpy(tr.base, base, length);
1260218822Sdim	isc_buffer_add(target, length);
126160484Sobrien	return (ISC_R_SUCCESS);
126260484Sobrien}
126360484Sobrien
126460484Sobrienstatic int
126560484Sobrienhexvalue(char value) {
126660484Sobrien	char *s;
126760484Sobrien	unsigned char c;
126860484Sobrien
126960484Sobrien	c = (unsigned char)value;
127060484Sobrien
127160484Sobrien	if (!isascii(c))
127260484Sobrien		return (-1);
127360484Sobrien	if (isupper(c))
127460484Sobrien		c = tolower(c);
127560484Sobrien	if ((s = strchr(hexdigits, c)) == NULL)
127660484Sobrien		return (-1);
127760484Sobrien	return (s - hexdigits);
127860484Sobrien}
127960484Sobrien
128060484Sobrienstatic int
128160484Sobriendecvalue(char value) {
128260484Sobrien	char *s;
128360484Sobrien
128460484Sobrien	/*
128560484Sobrien	 * isascii() is valid for full range of int values, no need to
128660484Sobrien	 * mask or cast.
128760484Sobrien	 */
128860484Sobrien	if (!isascii(value))
128960484Sobrien		return (-1);
1290218822Sdim	if ((s = strchr(decdigits, value)) == NULL)
129160484Sobrien		return (-1);
129260484Sobrien	return (s - decdigits);
129360484Sobrien}
129460484Sobrien
129560484Sobrienstatic const char atob_digits[86] =
1296218822Sdim	"!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`" \
129760484Sobrien	"abcdefghijklmnopqrstu";
129860484Sobrien/*
129960484Sobrien * Subroutines to convert between 8 bit binary bytes and printable ASCII.
130060484Sobrien * Computes the number of bytes, and three kinds of simple checksums.
130160484Sobrien * Incoming bytes are collected into 32-bit words, then printed in base 85:
130260484Sobrien *	exp(85,5) > exp(2,32)
130360484Sobrien * The ASCII characters used are between '!' and 'u';
130460484Sobrien * 'z' encodes 32-bit zero; 'x' is used to mark the end of encoded data.
1305104834Sobrien *
130660484Sobrien * Originally by Paul Rutter (philabs!per) and Joe Orost (petsd!joe) for
1307104834Sobrien * the atob/btoa programs, released with the compress program, in mod.sources.
130860484Sobrien * Modified by Mike Schwartz 8/19/86 for use in BIND.
130960484Sobrien * Modified to be re-entrant 3/2/99.
131060484Sobrien */
131160484Sobrien
131260484Sobrien
131360484Sobrienstruct state {
131460484Sobrien	isc_int32_t Ceor;
131560484Sobrien	isc_int32_t Csum;
131660484Sobrien	isc_int32_t Crot;
1317104834Sobrien	isc_int32_t word;
131860484Sobrien	isc_int32_t bcount;
131960484Sobrien};
132060484Sobrien
132160484Sobrien#define Ceor state->Ceor
132260484Sobrien#define Csum state->Csum
132360484Sobrien#define Crot state->Crot
132460484Sobrien#define word state->word
132560484Sobrien#define bcount state->bcount
132660484Sobrien
132760484Sobrien#define times85(x)	((((((x<<2)+x)<<2)+x)<<2)+x)
132860484Sobrien
132960484Sobrienstatic isc_result_t	byte_atob(int c, isc_buffer_t *target,
133060484Sobrien				  struct state *state);
133160484Sobrienstatic isc_result_t	putbyte(int c, isc_buffer_t *, struct state *state);
133260484Sobrienstatic isc_result_t	byte_btoa(int c, isc_buffer_t *, struct state *state);
133360484Sobrien
133460484Sobrien/*
133560484Sobrien * Decode ASCII-encoded byte c into binary representation and
133660484Sobrien * place into *bufp, advancing bufp.
133760484Sobrien */
1338104834Sobrienstatic isc_result_t
133960484Sobrienbyte_atob(int c, isc_buffer_t *target, struct state *state) {
134060484Sobrien	char *s;
134160484Sobrien	if (c == 'z') {
134260484Sobrien		if (bcount != 0)
134360484Sobrien			return(DNS_R_SYNTAX);
134460484Sobrien		else {
134560484Sobrien			RETERR(putbyte(0, target, state));
134660484Sobrien			RETERR(putbyte(0, target, state));
134760484Sobrien			RETERR(putbyte(0, target, state));
134860484Sobrien			RETERR(putbyte(0, target, state));
134960484Sobrien		}
135060484Sobrien	} else if ((s = strchr(atob_digits, c)) != NULL) {
135160484Sobrien		if (bcount == 0) {
135260484Sobrien			word = s - atob_digits;
135360484Sobrien			++bcount;
135460484Sobrien		} else if (bcount < 4) {
135560484Sobrien			word = times85(word);
135660484Sobrien			word += s - atob_digits;
135760484Sobrien			++bcount;
135860484Sobrien		} else {
135960484Sobrien			word = times85(word);
136060484Sobrien			word += s - atob_digits;
136160484Sobrien			RETERR(putbyte((word >> 24) & 0xff, target, state));
136260484Sobrien			RETERR(putbyte((word >> 16) & 0xff, target, state));
136360484Sobrien			RETERR(putbyte((word >> 8) & 0xff, target, state));
136460484Sobrien			RETERR(putbyte(word & 0xff, target, state));
136560484Sobrien			word = 0;
136660484Sobrien			bcount = 0;
136760484Sobrien		}
136860484Sobrien	} else
136960484Sobrien		return(DNS_R_SYNTAX);
1370218822Sdim	return(ISC_R_SUCCESS);
137160484Sobrien}
137260484Sobrien
137360484Sobrien/*
137460484Sobrien * Compute checksum info and place c into target.
137560484Sobrien */
137660484Sobrienstatic isc_result_t
137760484Sobrienputbyte(int c, isc_buffer_t *target, struct state *state) {
137860484Sobrien	isc_region_t tr;
137960484Sobrien
138060484Sobrien	Ceor ^= c;
138160484Sobrien	Csum += c;
138260484Sobrien	Csum += 1;
1383104834Sobrien	if ((Crot & 0x80000000)) {
138460484Sobrien		Crot <<= 1;
138560484Sobrien		Crot += 1;
1386104834Sobrien	} else {
138760484Sobrien		Crot <<= 1;
138860484Sobrien	}
138960484Sobrien	Crot += c;
139060484Sobrien	isc_buffer_availableregion(target, &tr);
139160484Sobrien	if (tr.length < 1)
139260484Sobrien		return (ISC_R_NOSPACE);
139360484Sobrien	tr.base[0] = c;
139460484Sobrien	isc_buffer_add(target, 1);
139560484Sobrien	return (ISC_R_SUCCESS);
139660484Sobrien}
139760484Sobrien
139860484Sobrien/*
139960484Sobrien * Read the ASCII-encoded data from inbuf, of length inbuflen, and convert
140060484Sobrien * it into T_UNSPEC (binary data) in outbuf, not to exceed outbuflen bytes;
140160484Sobrien * outbuflen must be divisible by 4.  (Note: this is because outbuf is filled
1402104834Sobrien * in 4 bytes at a time.  If the actual data doesn't end on an even 4-byte
140360484Sobrien * boundary, there will be no problem...it will be padded with 0 bytes, and
1404104834Sobrien * numbytes will indicate the correct number of bytes.  The main point is
140560484Sobrien * that since the buffer is filled in 4 bytes at a time, even if there is
140660484Sobrien * not a full 4 bytes of data at the end, there has to be room to 0-pad the
140760484Sobrien * data, so the buffer must be of size divisible by 4).  Place the number of
140860484Sobrien * output bytes in numbytes, and return a failure/success status.
140960484Sobrien */
141060484Sobrien
141160484Sobrienstatic isc_result_t
141260484Sobrienatob_tobuffer(isc_lex_t *lexer, isc_buffer_t *target) {
141360484Sobrien	long oeor, osum, orot;
141460484Sobrien	struct state statebuf, *state= &statebuf;
141560484Sobrien	isc_token_t token;
141660484Sobrien	char c;
141760484Sobrien	char *e;
1418104834Sobrien
141960484Sobrien	Ceor = Csum = Crot = word = bcount = 0;
142060484Sobrien
1421104834Sobrien	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
142260484Sobrien				      ISC_FALSE));
142360484Sobrien	while (token.value.as_textregion.length != 0) {
142460484Sobrien		if ((c = token.value.as_textregion.base[0]) == 'x') {
142560484Sobrien			break;
142660484Sobrien		} else
142760484Sobrien			RETERR(byte_atob(c, target, state));
142860484Sobrien		isc_textregion_consume(&token.value.as_textregion, 1);
142960484Sobrien	}
143060484Sobrien
143160484Sobrien	/*
143260484Sobrien	 * Number of bytes.
1433104834Sobrien	 */
143460484Sobrien	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
1435104834Sobrien				      ISC_FALSE));
143660484Sobrien	if ((token.value.as_ulong % 4) != 0U)
143760484Sobrien		isc_buffer_subtract(target,  4 - (token.value.as_ulong % 4));
143860484Sobrien
143960484Sobrien	/*
144060484Sobrien	 * Checksum.
144160484Sobrien	 */
144260484Sobrien	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
144360484Sobrien				      ISC_FALSE));
144460484Sobrien	oeor = strtol(DNS_AS_STR(token), &e, 16);
144560484Sobrien	if (*e != 0)
144660484Sobrien		return (DNS_R_SYNTAX);
144760484Sobrien
144860484Sobrien	/*
144960484Sobrien	 * Checksum.
145060484Sobrien	 */
145160484Sobrien	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
145260484Sobrien				      ISC_FALSE));
145360484Sobrien	osum = strtol(DNS_AS_STR(token), &e, 16);
145460484Sobrien	if (*e != 0)
145560484Sobrien		return (DNS_R_SYNTAX);
145660484Sobrien
1457218822Sdim	/*
145860484Sobrien	 * Checksum.
145960484Sobrien	 */
146060484Sobrien	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
146160484Sobrien				      ISC_FALSE));
146260484Sobrien	orot = strtol(DNS_AS_STR(token), &e, 16);
146360484Sobrien	if (*e != 0)
146460484Sobrien		return (DNS_R_SYNTAX);
146560484Sobrien
1466104834Sobrien	if ((oeor != Ceor) || (osum != Csum) || (orot != Crot))
146760484Sobrien		return(DNS_R_BADCKSUM);
1468104834Sobrien	return (ISC_R_SUCCESS);
146960484Sobrien}
147060484Sobrien
147160484Sobrien/*
147260484Sobrien * Encode binary byte c into ASCII representation and place into *bufp,
147360484Sobrien * advancing bufp.
147460484Sobrien */
147560484Sobrienstatic isc_result_t
147660484Sobrienbyte_btoa(int c, isc_buffer_t *target, struct state *state) {
147760484Sobrien	isc_region_t tr;
147860484Sobrien
147960484Sobrien	isc_buffer_availableregion(target, &tr);
148060484Sobrien	Ceor ^= c;
148160484Sobrien	Csum += c;
148260484Sobrien	Csum += 1;
148360484Sobrien	if ((Crot & 0x80000000)) {
148460484Sobrien		Crot <<= 1;
148560484Sobrien		Crot += 1;
148660484Sobrien	} else {
148760484Sobrien		Crot <<= 1;
148860484Sobrien	}
1489104834Sobrien	Crot += c;
149060484Sobrien
149160484Sobrien	word <<= 8;
149260484Sobrien	word |= c;
149360484Sobrien	if (bcount == 3) {
149460484Sobrien		if (word == 0) {
149560484Sobrien			if (tr.length < 1)
149660484Sobrien				return (ISC_R_NOSPACE);
149760484Sobrien			tr.base[0] = 'z';
149860484Sobrien			isc_buffer_add(target, 1);
149960484Sobrien		} else {
150060484Sobrien		    register int tmp = 0;
150160484Sobrien		    register isc_int32_t tmpword = word;
150260484Sobrien
150360484Sobrien		    if (tmpword < 0) {
150460484Sobrien			   /*
150560484Sobrien			    * Because some don't support u_long.
150660484Sobrien			    */
150760484Sobrien		    	tmp = 32;
150860484Sobrien		    	tmpword -= (isc_int32_t)(85 * 85 * 85 * 85 * 32);
150960484Sobrien		    }
151060484Sobrien		    if (tmpword < 0) {
151160484Sobrien		    	tmp = 64;
151260484Sobrien		    	tmpword -= (isc_int32_t)(85 * 85 * 85 * 85 * 32);
151360484Sobrien		    }
151460484Sobrien			if (tr.length < 5)
151560484Sobrien				return (ISC_R_NOSPACE);
151660484Sobrien		    	tr.base[0] = atob_digits[(tmpword /
151760484Sobrien					      (isc_int32_t)(85 * 85 * 85 * 85))
151860484Sobrien						+ tmp];
1519218822Sdim			tmpword %= (isc_int32_t)(85 * 85 * 85 * 85);
152060484Sobrien			tr.base[1] = atob_digits[tmpword / (85 * 85 * 85)];
152160484Sobrien			tmpword %= (85 * 85 * 85);
152260484Sobrien			tr.base[2] = atob_digits[tmpword / (85 * 85)];
152360484Sobrien			tmpword %= (85 * 85);
152460484Sobrien			tr.base[3] = atob_digits[tmpword / 85];
152560484Sobrien			tmpword %= 85;
152660484Sobrien			tr.base[4] = atob_digits[tmpword];
152760484Sobrien			isc_buffer_add(target, 5);
1528104834Sobrien		}
152960484Sobrien		bcount = 0;
1530104834Sobrien	} else {
153160484Sobrien		bcount += 1;
153260484Sobrien	}
153360484Sobrien	return (ISC_R_SUCCESS);
153460484Sobrien}
153560484Sobrien
153660484Sobrien
153760484Sobrien/*
153860484Sobrien * Encode the binary data from inbuf, of length inbuflen, into a
153960484Sobrien * target.  Return success/failure status
154060484Sobrien */
154160484Sobrienstatic isc_result_t
154260484Sobrienbtoa_totext(unsigned char *inbuf, int inbuflen, isc_buffer_t *target) {
154360484Sobrien	int inc;
154460484Sobrien	struct state statebuf, *state = &statebuf;
154560484Sobrien	char buf[sizeof("x 2000000000 ffffffff ffffffff ffffffff")];
154660484Sobrien
154760484Sobrien	Ceor = Csum = Crot = word = bcount = 0;
154860484Sobrien	for (inc = 0; inc < inbuflen; inbuf++, inc++)
154960484Sobrien		RETERR(byte_btoa(*inbuf, target, state));
155060484Sobrien
1551104834Sobrien	while (bcount != 0)
155260484Sobrien		RETERR(byte_btoa(0, target, state));
155360484Sobrien
155460484Sobrien	/*
155560484Sobrien	 * Put byte count and checksum information at end of buffer,
155660484Sobrien	 * delimited by 'x'
155760484Sobrien	 */
155860484Sobrien	snprintf(buf, sizeof(buf), "x %d %x %x %x", inbuflen, Ceor, Csum, Crot);
155960484Sobrien	return (str_totext(buf, target));
156060484Sobrien}
156160484Sobrien
1562104834Sobrien
156360484Sobrienstatic void
156460484Sobriendefault_fromtext_callback(dns_rdatacallbacks_t *callbacks, const char *fmt,
156560484Sobrien			  ...)
156660484Sobrien{
156760484Sobrien	va_list ap;
156860484Sobrien
156960484Sobrien	UNUSED(callbacks);
157060484Sobrien
157160484Sobrien	va_start(ap, fmt);
157260484Sobrien	vfprintf(stderr, fmt, ap);
157360484Sobrien	va_end(ap);
157460484Sobrien	fprintf(stderr, "\n");
157560484Sobrien}
157660484Sobrien
157760484Sobrienstatic void
157860484Sobrienfromtext_warneof(isc_lex_t *lexer, dns_rdatacallbacks_t *callbacks) {
157960484Sobrien	if (isc_lex_isfile(lexer) && callbacks != NULL) {
158060484Sobrien		const char *name = isc_lex_getsourcename(lexer);
158160484Sobrien		if (name == NULL)
158260484Sobrien			name = "UNKNOWN";
158360484Sobrien		(*callbacks->warn)(callbacks,
158460484Sobrien				   "%s:%lu: file does not end with newline",
1585218822Sdim				   name, isc_lex_getsourceline(lexer));
158660484Sobrien	}
158760484Sobrien}
158860484Sobrien
1589218822Sdimstatic void
159060484Sobrienwarn_badmx(isc_token_t *token, isc_lex_t *lexer,
159160484Sobrien	   dns_rdatacallbacks_t *callbacks)
159260484Sobrien{
159360484Sobrien	const char *file;
159460484Sobrien	unsigned long line;
159560484Sobrien
159660484Sobrien	if (lexer != NULL) {
159760484Sobrien		file = isc_lex_getsourcename(lexer);
1598104834Sobrien		line = isc_lex_getsourceline(lexer);
159960484Sobrien		(*callbacks->warn)(callbacks, "%s:%u: warning: '%s': %s",
1600104834Sobrien				   file, line, DNS_AS_STR(*token),
160160484Sobrien				   dns_result_totext(DNS_R_MXISADDRESS));
160260484Sobrien	}
160360484Sobrien}
160460484Sobrien
160560484Sobrienstatic void
160660484Sobrienwarn_badname(dns_name_t *name, isc_lex_t *lexer,
160760484Sobrien	     dns_rdatacallbacks_t *callbacks)
160860484Sobrien{
160960484Sobrien	const char *file;
1610104834Sobrien	unsigned long line;
161160484Sobrien	char namebuf[DNS_NAME_FORMATSIZE];
161260484Sobrien
161360484Sobrien	if (lexer != NULL) {
161460484Sobrien		file = isc_lex_getsourcename(lexer);
161560484Sobrien		line = isc_lex_getsourceline(lexer);
161660484Sobrien		dns_name_format(name, namebuf, sizeof(namebuf));
161760484Sobrien		(*callbacks->warn)(callbacks, "%s:%u: warning: %s: %s",
161860484Sobrien				   file, line, namebuf,
161960484Sobrien				   dns_result_totext(DNS_R_BADNAME));
162060484Sobrien	}
162160484Sobrien}
162260484Sobrien
162360484Sobrienstatic void
162460484Sobrienfromtext_error(void (*callback)(dns_rdatacallbacks_t *, const char *, ...),
162560484Sobrien	       dns_rdatacallbacks_t *callbacks, const char *name,
162660484Sobrien	       unsigned long line, isc_token_t *token, isc_result_t result)
162760484Sobrien{
162860484Sobrien	if (name == NULL)
162960484Sobrien		name = "UNKNOWN";
163060484Sobrien
1631104834Sobrien	if (token != NULL) {
163260484Sobrien		switch (token->type) {
163360484Sobrien		case isc_tokentype_eol:
163460484Sobrien			(*callback)(callbacks, "%s: %s:%lu: near eol: %s",
163560484Sobrien				    "dns_rdata_fromtext", name, line,
163660484Sobrien				    dns_result_totext(result));
163760484Sobrien			break;
163860484Sobrien		case isc_tokentype_eof:
163960484Sobrien			(*callback)(callbacks, "%s: %s:%lu: near eof: %s",
164060484Sobrien				    "dns_rdata_fromtext", name, line,
164160484Sobrien				    dns_result_totext(result));
164260484Sobrien			break;
164360484Sobrien		case isc_tokentype_number:
164460484Sobrien			(*callback)(callbacks, "%s: %s:%lu: near %lu: %s",
164560484Sobrien				    "dns_rdata_fromtext", name, line,
164660484Sobrien				    token->value.as_ulong,
164760484Sobrien				    dns_result_totext(result));
164860484Sobrien			break;
164960484Sobrien		case isc_tokentype_string:
165060484Sobrien		case isc_tokentype_qstring:
165160484Sobrien			(*callback)(callbacks, "%s: %s:%lu: near '%s': %s",
165260484Sobrien				    "dns_rdata_fromtext", name, line,
165360484Sobrien				    DNS_AS_STR(*token),
165460484Sobrien				    dns_result_totext(result));
165560484Sobrien			break;
165660484Sobrien		default:
165760484Sobrien			(*callback)(callbacks, "%s: %s:%lu: %s",
165860484Sobrien				    "dns_rdata_fromtext", name, line,
165960484Sobrien				    dns_result_totext(result));
166060484Sobrien			break;
166160484Sobrien		}
166260484Sobrien	} else {
166360484Sobrien		(*callback)(callbacks, "dns_rdata_fromtext: %s:%lu: %s",
166460484Sobrien			    name, line, dns_result_totext(result));
166560484Sobrien	}
1666218822Sdim}
166760484Sobrien
166860484Sobriendns_rdatatype_t
166960484Sobriendns_rdata_covers(dns_rdata_t *rdata) {
167060484Sobrien	if (rdata->type == 46)
167160484Sobrien		return (covers_rrsig(rdata));
167260484Sobrien	return (covers_sig(rdata));
167360484Sobrien}
167460484Sobrien
167560484Sobrienisc_boolean_t
167660484Sobriendns_rdatatype_ismeta(dns_rdatatype_t type) {
167760484Sobrien	if ((dns_rdatatype_attributes(type) & DNS_RDATATYPEATTR_META) != 0)
167860484Sobrien		return (ISC_TRUE);
167960484Sobrien	return (ISC_FALSE);
168060484Sobrien}
168160484Sobrien
168260484Sobrienisc_boolean_t
168360484Sobriendns_rdatatype_issingleton(dns_rdatatype_t type) {
1684104834Sobrien	if ((dns_rdatatype_attributes(type) & DNS_RDATATYPEATTR_SINGLETON)
168560484Sobrien	    != 0)
168660484Sobrien		return (ISC_TRUE);
168760484Sobrien	return (ISC_FALSE);
168860484Sobrien}
168960484Sobrien
169060484Sobrienisc_boolean_t
169160484Sobriendns_rdatatype_notquestion(dns_rdatatype_t type) {
169260484Sobrien	if ((dns_rdatatype_attributes(type) & DNS_RDATATYPEATTR_NOTQUESTION)
169360484Sobrien	    != 0)
169460484Sobrien		return (ISC_TRUE);
169560484Sobrien	return (ISC_FALSE);
169660484Sobrien}
169760484Sobrien
169860484Sobrienisc_boolean_t
169960484Sobriendns_rdatatype_questiononly(dns_rdatatype_t type) {
1700104834Sobrien	if ((dns_rdatatype_attributes(type) & DNS_RDATATYPEATTR_QUESTIONONLY)
170160484Sobrien	    != 0)
170260484Sobrien		return (ISC_TRUE);
170360484Sobrien	return (ISC_FALSE);
170460484Sobrien}
170560484Sobrien
170660484Sobrienisc_boolean_t
170760484Sobriendns_rdatatype_atparent(dns_rdatatype_t type) {
170860484Sobrien	if ((dns_rdatatype_attributes(type) & DNS_RDATATYPEATTR_ATPARENT) != 0)
1709104834Sobrien		return (ISC_TRUE);
171060484Sobrien	return (ISC_FALSE);
171160484Sobrien}
171260484Sobrien
171360484Sobrienisc_boolean_t
171460484Sobriendns_rdataclass_ismeta(dns_rdataclass_t rdclass) {
171560484Sobrien
171660484Sobrien	if (rdclass == dns_rdataclass_reserved0
171760484Sobrien	    || rdclass == dns_rdataclass_none
171860484Sobrien	    || rdclass == dns_rdataclass_any)
171960484Sobrien		return (ISC_TRUE);
1720104834Sobrien
172160484Sobrien	return (ISC_FALSE);  /* Assume it is not a meta class. */
172260484Sobrien}
172360484Sobrien
172460484Sobrienisc_boolean_t
172560484Sobriendns_rdatatype_isdnssec(dns_rdatatype_t type) {
172660484Sobrien	if ((dns_rdatatype_attributes(type) & DNS_RDATATYPEATTR_DNSSEC) != 0)
172760484Sobrien		return (ISC_TRUE);
172860484Sobrien	return (ISC_FALSE);
172960484Sobrien}
173060484Sobrien
173160484Sobrienisc_boolean_t
173260484Sobriendns_rdatatype_iszonecutauth(dns_rdatatype_t type) {
173360484Sobrien	if ((dns_rdatatype_attributes(type)
173460484Sobrien	     & (DNS_RDATATYPEATTR_DNSSEC | DNS_RDATATYPEATTR_ZONECUTAUTH))
173560484Sobrien	    != 0)
173660484Sobrien		return (ISC_TRUE);
173760484Sobrien	return (ISC_FALSE);
173860484Sobrien}
173960484Sobrien
1740218822Sdimisc_boolean_t
174160484Sobriendns_rdatatype_isknown(dns_rdatatype_t type) {
174260484Sobrien	if ((dns_rdatatype_attributes(type) & DNS_RDATATYPEATTR_UNKNOWN)
174360484Sobrien	    == 0)
174460484Sobrien		return (ISC_TRUE);
174560484Sobrien	return (ISC_FALSE);
174660484Sobrien}
174760484Sobrien