1135446Strhodes/*
2262706Serwin * Copyright (C) 2004-2014  Internet Systems Consortium, Inc. ("ISC")
3135446Strhodes * Copyright (C) 1998-2003  Internet Software Consortium.
4135446Strhodes *
5193149Sdougb * Permission to use, copy, modify, and/or distribute this software for any
6135446Strhodes * purpose with or without fee is hereby granted, provided that the above
7135446Strhodes * copyright notice and this permission notice appear in all copies.
8135446Strhodes *
9135446Strhodes * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10135446Strhodes * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11135446Strhodes * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12135446Strhodes * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13135446Strhodes * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14135446Strhodes * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15135446Strhodes * PERFORMANCE OF THIS SOFTWARE.
16135446Strhodes */
17135446Strhodes
18234010Sdougb/* $Id$ */
19135446Strhodes
20135446Strhodes#include <config.h>
21135446Strhodes#include <ctype.h>
22135446Strhodes
23135446Strhodes#include <isc/buffer.h>
24135446Strhodes#include <isc/parseint.h>
25135446Strhodes#include <isc/print.h>
26135446Strhodes#include <isc/region.h>
27135446Strhodes#include <isc/result.h>
28135446Strhodes#include <isc/stdio.h>
29135446Strhodes#include <isc/stdlib.h>
30135446Strhodes#include <isc/string.h>
31135446Strhodes#include <isc/types.h>
32135446Strhodes#include <isc/util.h>
33135446Strhodes
34135446Strhodes#include <dns/cert.h>
35135446Strhodes#include <dns/keyflags.h>
36135446Strhodes#include <dns/keyvalues.h>
37135446Strhodes#include <dns/rcode.h>
38135446Strhodes#include <dns/rdataclass.h>
39135446Strhodes#include <dns/result.h>
40135446Strhodes#include <dns/secalg.h>
41135446Strhodes#include <dns/secproto.h>
42135446Strhodes
43135446Strhodes#define RETERR(x) \
44135446Strhodes	do { \
45135446Strhodes		isc_result_t _r = (x); \
46135446Strhodes		if (_r != ISC_R_SUCCESS) \
47135446Strhodes			return (_r); \
48135446Strhodes	} while (0)
49135446Strhodes
50135446Strhodes#define NUMBERSIZE sizeof("037777777777") /* 2^32-1 octal + NUL */
51135446Strhodes
52135446Strhodes#define RCODENAMES \
53135446Strhodes	/* standard rcodes */ \
54135446Strhodes	{ dns_rcode_noerror, "NOERROR", 0}, \
55135446Strhodes	{ dns_rcode_formerr, "FORMERR", 0}, \
56135446Strhodes	{ dns_rcode_servfail, "SERVFAIL", 0}, \
57135446Strhodes	{ dns_rcode_nxdomain, "NXDOMAIN", 0}, \
58135446Strhodes	{ dns_rcode_notimp, "NOTIMP", 0}, \
59135446Strhodes	{ dns_rcode_refused, "REFUSED", 0}, \
60135446Strhodes	{ dns_rcode_yxdomain, "YXDOMAIN", 0}, \
61135446Strhodes	{ dns_rcode_yxrrset, "YXRRSET", 0}, \
62135446Strhodes	{ dns_rcode_nxrrset, "NXRRSET", 0}, \
63135446Strhodes	{ dns_rcode_notauth, "NOTAUTH", 0}, \
64135446Strhodes	{ dns_rcode_notzone, "NOTZONE", 0},
65135446Strhodes
66135446Strhodes#define ERCODENAMES \
67135446Strhodes	/* extended rcodes */ \
68135446Strhodes	{ dns_rcode_badvers, "BADVERS", 0}, \
69193149Sdougb	{ 0, NULL, 0 }
70135446Strhodes
71135446Strhodes#define TSIGRCODENAMES \
72135446Strhodes	/* extended rcodes */ \
73135446Strhodes	{ dns_tsigerror_badsig, "BADSIG", 0}, \
74135446Strhodes	{ dns_tsigerror_badkey, "BADKEY", 0}, \
75135446Strhodes	{ dns_tsigerror_badtime, "BADTIME", 0}, \
76135446Strhodes	{ dns_tsigerror_badmode, "BADMODE", 0}, \
77135446Strhodes	{ dns_tsigerror_badname, "BADNAME", 0}, \
78135446Strhodes	{ dns_tsigerror_badalg, "BADALG", 0}, \
79170222Sdougb	{ dns_tsigerror_badtrunc, "BADTRUNC", 0}, \
80135446Strhodes	{ 0, NULL, 0 }
81135446Strhodes
82224092Sdougb/* RFC4398 section 2.1 */
83135446Strhodes
84135446Strhodes#define CERTNAMES \
85135446Strhodes	{ 1, "PKIX", 0}, \
86135446Strhodes	{ 2, "SPKI", 0}, \
87135446Strhodes	{ 3, "PGP", 0}, \
88224092Sdougb	{ 4, "IPKIX", 0}, \
89224092Sdougb	{ 5, "ISPKI", 0}, \
90224092Sdougb	{ 6, "IPGP", 0}, \
91224092Sdougb	{ 7, "ACPKIX", 0}, \
92224092Sdougb	{ 8, "IACPKIX", 0}, \
93135446Strhodes	{ 253, "URI", 0}, \
94135446Strhodes	{ 254, "OID", 0}, \
95135446Strhodes	{ 0, NULL, 0}
96135446Strhodes
97135446Strhodes/* RFC2535 section 7, RFC3110 */
98135446Strhodes
99135446Strhodes#define SECALGNAMES \
100135446Strhodes	{ DNS_KEYALG_RSAMD5, "RSAMD5", 0 }, \
101135446Strhodes	{ DNS_KEYALG_RSAMD5, "RSA", 0 }, \
102135446Strhodes	{ DNS_KEYALG_DH, "DH", 0 }, \
103135446Strhodes	{ DNS_KEYALG_DSA, "DSA", 0 }, \
104193149Sdougb	{ DNS_KEYALG_NSEC3DSA, "NSEC3DSA", 0 }, \
105135446Strhodes	{ DNS_KEYALG_ECC, "ECC", 0 }, \
106135446Strhodes	{ DNS_KEYALG_RSASHA1, "RSASHA1", 0 }, \
107193149Sdougb	{ DNS_KEYALG_NSEC3RSASHA1, "NSEC3RSASHA1", 0 }, \
108204619Sdougb	{ DNS_KEYALG_RSASHA256, "RSASHA256", 0 }, \
109204619Sdougb	{ DNS_KEYALG_RSASHA512, "RSASHA512", 0 }, \
110224092Sdougb	{ DNS_KEYALG_ECCGOST, "ECCGOST", 0 }, \
111245163Serwin	{ DNS_KEYALG_ECDSA256, "ECDSAP256SHA256", 0 }, \
112245163Serwin	{ DNS_KEYALG_ECDSA384, "ECDSAP384SHA384", 0 }, \
113135446Strhodes	{ DNS_KEYALG_INDIRECT, "INDIRECT", 0 }, \
114135446Strhodes	{ DNS_KEYALG_PRIVATEDNS, "PRIVATEDNS", 0 }, \
115135446Strhodes	{ DNS_KEYALG_PRIVATEOID, "PRIVATEOID", 0 }, \
116135446Strhodes	{ 0, NULL, 0}
117135446Strhodes
118135446Strhodes/* RFC2535 section 7.1 */
119135446Strhodes
120135446Strhodes#define SECPROTONAMES \
121135446Strhodes	{   0,    "NONE", 0 }, \
122135446Strhodes	{   1,    "TLS", 0 }, \
123135446Strhodes	{   2,    "EMAIL", 0 }, \
124135446Strhodes	{   3,    "DNSSEC", 0 }, \
125135446Strhodes	{   4,    "IPSEC", 0 }, \
126135446Strhodes	{ 255,    "ALL", 0 }, \
127135446Strhodes	{ 0, NULL, 0}
128135446Strhodes
129193149Sdougb#define HASHALGNAMES \
130193149Sdougb	{ 1, "SHA-1", 0 }, \
131193149Sdougb	{ 0, NULL, 0 }
132193149Sdougb
133135446Strhodesstruct tbl {
134135446Strhodes	unsigned int    value;
135135446Strhodes	const char      *name;
136135446Strhodes	int             flags;
137135446Strhodes};
138135446Strhodes
139135446Strhodesstatic struct tbl rcodes[] = { RCODENAMES ERCODENAMES };
140135446Strhodesstatic struct tbl tsigrcodes[] = { RCODENAMES TSIGRCODENAMES };
141135446Strhodesstatic struct tbl certs[] = { CERTNAMES };
142135446Strhodesstatic struct tbl secalgs[] = { SECALGNAMES };
143135446Strhodesstatic struct tbl secprotos[] = { SECPROTONAMES };
144193149Sdougbstatic struct tbl hashalgs[] = { HASHALGNAMES };
145135446Strhodes
146135446Strhodesstatic struct keyflag {
147135446Strhodes	const char *name;
148135446Strhodes	unsigned int value;
149135446Strhodes	unsigned int mask;
150135446Strhodes} keyflags[] = {
151135446Strhodes	{ "NOCONF", 0x4000, 0xC000 },
152135446Strhodes	{ "NOAUTH", 0x8000, 0xC000 },
153135446Strhodes	{ "NOKEY",  0xC000, 0xC000 },
154135446Strhodes	{ "FLAG2",  0x2000, 0x2000 },
155135446Strhodes	{ "EXTEND", 0x1000, 0x1000 },
156135446Strhodes	{ "FLAG4",  0x0800, 0x0800 },
157135446Strhodes	{ "FLAG5",  0x0400, 0x0400 },
158135446Strhodes	{ "USER",   0x0000, 0x0300 },
159135446Strhodes	{ "ZONE",   0x0100, 0x0300 },
160135446Strhodes	{ "HOST",   0x0200, 0x0300 },
161135446Strhodes	{ "NTYP3",  0x0300, 0x0300 },
162135446Strhodes	{ "FLAG8",  0x0080, 0x0080 },
163135446Strhodes	{ "FLAG9",  0x0040, 0x0040 },
164135446Strhodes	{ "FLAG10", 0x0020, 0x0020 },
165135446Strhodes	{ "FLAG11", 0x0010, 0x0010 },
166135446Strhodes	{ "SIG0",   0x0000, 0x000F },
167135446Strhodes	{ "SIG1",   0x0001, 0x000F },
168135446Strhodes	{ "SIG2",   0x0002, 0x000F },
169135446Strhodes	{ "SIG3",   0x0003, 0x000F },
170135446Strhodes	{ "SIG4",   0x0004, 0x000F },
171135446Strhodes	{ "SIG5",   0x0005, 0x000F },
172135446Strhodes	{ "SIG6",   0x0006, 0x000F },
173135446Strhodes	{ "SIG7",   0x0007, 0x000F },
174135446Strhodes	{ "SIG8",   0x0008, 0x000F },
175135446Strhodes	{ "SIG9",   0x0009, 0x000F },
176135446Strhodes	{ "SIG10",  0x000A, 0x000F },
177135446Strhodes	{ "SIG11",  0x000B, 0x000F },
178135446Strhodes	{ "SIG12",  0x000C, 0x000F },
179135446Strhodes	{ "SIG13",  0x000D, 0x000F },
180135446Strhodes	{ "SIG14",  0x000E, 0x000F },
181135446Strhodes	{ "SIG15",  0x000F, 0x000F },
182135446Strhodes	{ "KSK",  DNS_KEYFLAG_KSK, DNS_KEYFLAG_KSK },
183135446Strhodes	{ NULL,     0, 0 }
184135446Strhodes};
185135446Strhodes
186135446Strhodesstatic isc_result_t
187135446Strhodesstr_totext(const char *source, isc_buffer_t *target) {
188135446Strhodes	unsigned int l;
189135446Strhodes	isc_region_t region;
190135446Strhodes
191135446Strhodes	isc_buffer_availableregion(target, &region);
192135446Strhodes	l = strlen(source);
193135446Strhodes
194135446Strhodes	if (l > region.length)
195135446Strhodes		return (ISC_R_NOSPACE);
196135446Strhodes
197262706Serwin	memmove(region.base, source, l);
198135446Strhodes	isc_buffer_add(target, l);
199135446Strhodes	return (ISC_R_SUCCESS);
200135446Strhodes}
201135446Strhodes
202135446Strhodesstatic isc_result_t
203135446Strhodesmaybe_numeric(unsigned int *valuep, isc_textregion_t *source,
204135446Strhodes	      unsigned int max, isc_boolean_t hex_allowed)
205135446Strhodes{
206135446Strhodes	isc_result_t result;
207135446Strhodes	isc_uint32_t n;
208135446Strhodes	char buffer[NUMBERSIZE];
209135446Strhodes
210135446Strhodes	if (! isdigit(source->base[0] & 0xff) ||
211135446Strhodes	    source->length > NUMBERSIZE - 1)
212135446Strhodes		return (ISC_R_BADNUMBER);
213135446Strhodes
214135446Strhodes	/*
215135446Strhodes	 * We have a potential number.  Try to parse it with
216135446Strhodes	 * isc_parse_uint32().  isc_parse_uint32() requires
217135446Strhodes	 * null termination, so we must make a copy.
218135446Strhodes	 */
219135446Strhodes	strncpy(buffer, source->base, NUMBERSIZE);
220135446Strhodes	INSIST(buffer[source->length] == '\0');
221135446Strhodes
222135446Strhodes	result = isc_parse_uint32(&n, buffer, 10);
223135446Strhodes	if (result == ISC_R_BADNUMBER && hex_allowed)
224135446Strhodes		result = isc_parse_uint32(&n, buffer, 16);
225135446Strhodes	if (result != ISC_R_SUCCESS)
226135446Strhodes		return (result);
227135446Strhodes	if (n > max)
228135446Strhodes		return (ISC_R_RANGE);
229135446Strhodes	*valuep = n;
230135446Strhodes	return (ISC_R_SUCCESS);
231135446Strhodes}
232135446Strhodes
233135446Strhodesstatic isc_result_t
234135446Strhodesdns_mnemonic_fromtext(unsigned int *valuep, isc_textregion_t *source,
235135446Strhodes		      struct tbl *table, unsigned int max)
236135446Strhodes{
237135446Strhodes	isc_result_t result;
238135446Strhodes	int i;
239135446Strhodes
240135446Strhodes	result = maybe_numeric(valuep, source, max, ISC_FALSE);
241135446Strhodes	if (result != ISC_R_BADNUMBER)
242135446Strhodes		return (result);
243135446Strhodes
244135446Strhodes	for (i = 0; table[i].name != NULL; i++) {
245135446Strhodes		unsigned int n;
246135446Strhodes		n = strlen(table[i].name);
247135446Strhodes		if (n == source->length &&
248135446Strhodes		    strncasecmp(source->base, table[i].name, n) == 0) {
249135446Strhodes			*valuep = table[i].value;
250135446Strhodes			return (ISC_R_SUCCESS);
251135446Strhodes		}
252135446Strhodes	}
253135446Strhodes	return (DNS_R_UNKNOWN);
254135446Strhodes}
255135446Strhodes
256135446Strhodesstatic isc_result_t
257135446Strhodesdns_mnemonic_totext(unsigned int value, isc_buffer_t *target,
258193149Sdougb		    struct tbl *table)
259135446Strhodes{
260135446Strhodes	int i = 0;
261135446Strhodes	char buf[sizeof("4294967296")];
262135446Strhodes	while (table[i].name != NULL) {
263135446Strhodes		if (table[i].value == value) {
264135446Strhodes			return (str_totext(table[i].name, target));
265135446Strhodes		}
266135446Strhodes		i++;
267135446Strhodes	}
268135446Strhodes	snprintf(buf, sizeof(buf), "%u", value);
269135446Strhodes	return (str_totext(buf, target));
270135446Strhodes}
271135446Strhodes
272135446Strhodesisc_result_t
273135446Strhodesdns_rcode_fromtext(dns_rcode_t *rcodep, isc_textregion_t *source) {
274135446Strhodes	unsigned int value;
275135446Strhodes	RETERR(dns_mnemonic_fromtext(&value, source, rcodes, 0xffff));
276135446Strhodes	*rcodep = value;
277135446Strhodes	return (ISC_R_SUCCESS);
278135446Strhodes}
279135446Strhodes
280135446Strhodesisc_result_t
281135446Strhodesdns_rcode_totext(dns_rcode_t rcode, isc_buffer_t *target) {
282135446Strhodes	return (dns_mnemonic_totext(rcode, target, rcodes));
283135446Strhodes}
284135446Strhodes
285135446Strhodesisc_result_t
286135446Strhodesdns_tsigrcode_fromtext(dns_rcode_t *rcodep, isc_textregion_t *source) {
287135446Strhodes	unsigned int value;
288135446Strhodes	RETERR(dns_mnemonic_fromtext(&value, source, tsigrcodes, 0xffff));
289135446Strhodes	*rcodep = value;
290135446Strhodes	return (ISC_R_SUCCESS);
291193149Sdougb}
292135446Strhodes
293135446Strhodesisc_result_t
294135446Strhodesdns_tsigrcode_totext(dns_rcode_t rcode, isc_buffer_t *target) {
295135446Strhodes	return (dns_mnemonic_totext(rcode, target, tsigrcodes));
296135446Strhodes}
297135446Strhodes
298135446Strhodesisc_result_t
299135446Strhodesdns_cert_fromtext(dns_cert_t *certp, isc_textregion_t *source) {
300135446Strhodes	unsigned int value;
301135446Strhodes	RETERR(dns_mnemonic_fromtext(&value, source, certs, 0xffff));
302135446Strhodes	*certp = value;
303135446Strhodes	return (ISC_R_SUCCESS);
304135446Strhodes}
305135446Strhodes
306135446Strhodesisc_result_t
307135446Strhodesdns_cert_totext(dns_cert_t cert, isc_buffer_t *target) {
308135446Strhodes	return (dns_mnemonic_totext(cert, target, certs));
309135446Strhodes}
310135446Strhodes
311135446Strhodesisc_result_t
312135446Strhodesdns_secalg_fromtext(dns_secalg_t *secalgp, isc_textregion_t *source) {
313135446Strhodes	unsigned int value;
314135446Strhodes	RETERR(dns_mnemonic_fromtext(&value, source, secalgs, 0xff));
315135446Strhodes	*secalgp = value;
316135446Strhodes	return (ISC_R_SUCCESS);
317135446Strhodes}
318135446Strhodes
319135446Strhodesisc_result_t
320135446Strhodesdns_secalg_totext(dns_secalg_t secalg, isc_buffer_t *target) {
321135446Strhodes	return (dns_mnemonic_totext(secalg, target, secalgs));
322135446Strhodes}
323135446Strhodes
324224092Sdougbvoid
325224092Sdougbdns_secalg_format(dns_secalg_t alg, char *cp, unsigned int size) {
326224092Sdougb	isc_buffer_t b;
327224092Sdougb	isc_region_t r;
328224092Sdougb	isc_result_t result;
329224092Sdougb
330224092Sdougb	REQUIRE(cp != NULL && size > 0);
331224092Sdougb	isc_buffer_init(&b, cp, size - 1);
332224092Sdougb	result = dns_secalg_totext(alg, &b);
333224092Sdougb	isc_buffer_usedregion(&b, &r);
334224092Sdougb	r.base[r.length] = 0;
335224092Sdougb	if (result != ISC_R_SUCCESS)
336224092Sdougb		r.base[0] = 0;
337224092Sdougb}
338224092Sdougb
339135446Strhodesisc_result_t
340135446Strhodesdns_secproto_fromtext(dns_secproto_t *secprotop, isc_textregion_t *source) {
341135446Strhodes	unsigned int value;
342135446Strhodes	RETERR(dns_mnemonic_fromtext(&value, source, secprotos, 0xff));
343135446Strhodes	*secprotop = value;
344135446Strhodes	return (ISC_R_SUCCESS);
345135446Strhodes}
346135446Strhodes
347135446Strhodesisc_result_t
348135446Strhodesdns_secproto_totext(dns_secproto_t secproto, isc_buffer_t *target) {
349135446Strhodes	return (dns_mnemonic_totext(secproto, target, secprotos));
350135446Strhodes}
351135446Strhodes
352135446Strhodesisc_result_t
353193149Sdougbdns_hashalg_fromtext(unsigned char *hashalg, isc_textregion_t *source) {
354193149Sdougb	unsigned int value;
355193149Sdougb	RETERR(dns_mnemonic_fromtext(&value, source, hashalgs, 0xff));
356193149Sdougb	*hashalg = value;
357193149Sdougb	return (ISC_R_SUCCESS);
358193149Sdougb}
359193149Sdougb
360193149Sdougbisc_result_t
361135446Strhodesdns_keyflags_fromtext(dns_keyflags_t *flagsp, isc_textregion_t *source)
362135446Strhodes{
363135446Strhodes	isc_result_t result;
364135446Strhodes	char *text, *end;
365135446Strhodes	unsigned int value, mask;
366135446Strhodes
367135446Strhodes	result = maybe_numeric(&value, source, 0xffff, ISC_TRUE);
368135446Strhodes	if (result == ISC_R_SUCCESS) {
369135446Strhodes		*flagsp = value;
370135446Strhodes		return (ISC_R_SUCCESS);
371135446Strhodes	}
372135446Strhodes	if (result != ISC_R_BADNUMBER)
373135446Strhodes		return (result);
374135446Strhodes
375135446Strhodes	text = source->base;
376135446Strhodes	end = source->base + source->length;
377135446Strhodes	value = mask = 0;
378135446Strhodes
379135446Strhodes	while (text < end) {
380135446Strhodes		struct keyflag *p;
381135446Strhodes		unsigned int len;
382135446Strhodes		char *delim = memchr(text, '|', end - text);
383135446Strhodes		if (delim != NULL)
384262706Serwin			len = (unsigned int)(delim - text);
385135446Strhodes		else
386262706Serwin			len = (unsigned int)(end - text);
387135446Strhodes		for (p = keyflags; p->name != NULL; p++) {
388135446Strhodes			if (strncasecmp(p->name, text, len) == 0)
389135446Strhodes				break;
390135446Strhodes		}
391135446Strhodes		if (p->name == NULL)
392135446Strhodes			return (DNS_R_UNKNOWNFLAG);
393135446Strhodes		value |= p->value;
394135446Strhodes#ifdef notyet
395135446Strhodes		if ((mask & p->mask) != 0)
396135446Strhodes			warn("overlapping key flags");
397135446Strhodes#endif
398135446Strhodes		mask |= p->mask;
399135446Strhodes		text += len;
400135446Strhodes		if (delim != NULL)
401135446Strhodes			text++; /* Skip "|" */
402135446Strhodes	}
403135446Strhodes	*flagsp = value;
404135446Strhodes	return (ISC_R_SUCCESS);
405135446Strhodes}
406135446Strhodes
407135446Strhodes/*
408135446Strhodes * This uses lots of hard coded values, but how often do we actually
409135446Strhodes * add classes?
410135446Strhodes */
411135446Strhodesisc_result_t
412135446Strhodesdns_rdataclass_fromtext(dns_rdataclass_t *classp, isc_textregion_t *source) {
413135446Strhodes#define COMPARE(string, rdclass) \
414135446Strhodes	if (((sizeof(string) - 1) == source->length) \
415135446Strhodes	    && (strncasecmp(source->base, string, source->length) == 0)) { \
416135446Strhodes		*classp = rdclass; \
417135446Strhodes		return (ISC_R_SUCCESS); \
418135446Strhodes	}
419135446Strhodes
420135446Strhodes	switch (tolower((unsigned char)source->base[0])) {
421135446Strhodes	case 'a':
422135446Strhodes		COMPARE("any", dns_rdataclass_any);
423135446Strhodes		break;
424135446Strhodes	case 'c':
425135446Strhodes		/*
426135446Strhodes		 * RFC1035 says the mnemonic for the CHAOS class is CH,
427135446Strhodes		 * but historical BIND practice is to call it CHAOS.
428135446Strhodes		 * We will accept both forms, but only generate CH.
429135446Strhodes		 */
430135446Strhodes		COMPARE("ch", dns_rdataclass_chaos);
431135446Strhodes		COMPARE("chaos", dns_rdataclass_chaos);
432135446Strhodes
433135446Strhodes		if (source->length > 5 &&
434135446Strhodes		    source->length < (5 + sizeof("65000")) &&
435135446Strhodes		    strncasecmp("class", source->base, 5) == 0) {
436135446Strhodes			char buf[sizeof("65000")];
437135446Strhodes			char *endp;
438135446Strhodes			unsigned int val;
439135446Strhodes
440135446Strhodes			strncpy(buf, source->base + 5, source->length - 5);
441135446Strhodes			buf[source->length - 5] = '\0';
442135446Strhodes			val = strtoul(buf, &endp, 10);
443135446Strhodes			if (*endp == '\0' && val <= 0xffff) {
444135446Strhodes				*classp = (dns_rdataclass_t)val;
445135446Strhodes				return (ISC_R_SUCCESS);
446135446Strhodes			}
447135446Strhodes		}
448135446Strhodes		break;
449135446Strhodes	case 'h':
450135446Strhodes		COMPARE("hs", dns_rdataclass_hs);
451135446Strhodes		COMPARE("hesiod", dns_rdataclass_hs);
452135446Strhodes		break;
453135446Strhodes	case 'i':
454135446Strhodes		COMPARE("in", dns_rdataclass_in);
455135446Strhodes		break;
456135446Strhodes	case 'n':
457135446Strhodes		COMPARE("none", dns_rdataclass_none);
458135446Strhodes		break;
459135446Strhodes	case 'r':
460135446Strhodes		COMPARE("reserved0", dns_rdataclass_reserved0);
461135446Strhodes		break;
462135446Strhodes	}
463135446Strhodes
464135446Strhodes#undef COMPARE
465135446Strhodes
466135446Strhodes	return (DNS_R_UNKNOWN);
467135446Strhodes}
468135446Strhodes
469135446Strhodesisc_result_t
470135446Strhodesdns_rdataclass_totext(dns_rdataclass_t rdclass, isc_buffer_t *target) {
471135446Strhodes	char buf[sizeof("CLASS65535")];
472135446Strhodes
473135446Strhodes	switch (rdclass) {
474135446Strhodes	case dns_rdataclass_any:
475135446Strhodes		return (str_totext("ANY", target));
476135446Strhodes	case dns_rdataclass_chaos:
477135446Strhodes		return (str_totext("CH", target));
478135446Strhodes	case dns_rdataclass_hs:
479135446Strhodes		return (str_totext("HS", target));
480135446Strhodes	case dns_rdataclass_in:
481135446Strhodes		return (str_totext("IN", target));
482135446Strhodes	case dns_rdataclass_none:
483135446Strhodes		return (str_totext("NONE", target));
484135446Strhodes	case dns_rdataclass_reserved0:
485135446Strhodes		return (str_totext("RESERVED0", target));
486135446Strhodes	default:
487135446Strhodes		snprintf(buf, sizeof(buf), "CLASS%u", rdclass);
488135446Strhodes		return (str_totext(buf, target));
489135446Strhodes	}
490135446Strhodes}
491135446Strhodes
492135446Strhodesvoid
493135446Strhodesdns_rdataclass_format(dns_rdataclass_t rdclass,
494135446Strhodes		      char *array, unsigned int size)
495135446Strhodes{
496135446Strhodes	isc_result_t result;
497135446Strhodes	isc_buffer_t buf;
498135446Strhodes
499225361Sdougb	if (size == 0U)
500225361Sdougb		return;
501225361Sdougb
502135446Strhodes	isc_buffer_init(&buf, array, size);
503135446Strhodes	result = dns_rdataclass_totext(rdclass, &buf);
504135446Strhodes	/*
505135446Strhodes	 * Null terminate.
506135446Strhodes	 */
507135446Strhodes	if (result == ISC_R_SUCCESS) {
508135446Strhodes		if (isc_buffer_availablelength(&buf) >= 1)
509135446Strhodes			isc_buffer_putuint8(&buf, 0);
510135446Strhodes		else
511135446Strhodes			result = ISC_R_NOSPACE;
512135446Strhodes	}
513225361Sdougb	if (result != ISC_R_SUCCESS)
514225361Sdougb		strlcpy(array, "<unknown>", size);
515135446Strhodes}
516