/* * Copyright (C) Internet Systems Consortium, Inc. ("ISC") * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ /* $Id: rcode.c,v 1.9 2020/02/26 18:47:58 florian Exp $ */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define TOTEXTONLY 0x01 #define RCODENAMES \ /* standard rcodes */ \ { dns_rcode_noerror, "NOERROR", 0}, \ { dns_rcode_formerr, "FORMERR", 0}, \ { dns_rcode_servfail, "SERVFAIL", 0}, \ { dns_rcode_nxdomain, "NXDOMAIN", 0}, \ { dns_rcode_notimp, "NOTIMP", 0}, \ { dns_rcode_refused, "REFUSED", 0}, \ { dns_rcode_yxdomain, "YXDOMAIN", 0}, \ { dns_rcode_yxrrset, "YXRRSET", 0}, \ { dns_rcode_nxrrset, "NXRRSET", 0}, \ { dns_rcode_notauth, "NOTAUTH", 0}, \ { dns_rcode_notzone, "NOTZONE", 0}, \ { 11, "RESERVED11", TOTEXTONLY}, \ { 12, "RESERVED12", TOTEXTONLY}, \ { 13, "RESERVED13", TOTEXTONLY}, \ { 14, "RESERVED14", TOTEXTONLY}, \ { 15, "RESERVED15", TOTEXTONLY}, #define TSIGRCODENAMES \ /* extended rcodes */ \ { dns_tsigerror_badsig, "BADSIG", 0}, \ { dns_tsigerror_badkey, "BADKEY", 0}, \ { dns_tsigerror_badtime, "BADTIME", 0}, \ { dns_tsigerror_badmode, "BADMODE", 0}, \ { dns_tsigerror_badname, "BADNAME", 0}, \ { dns_tsigerror_badalg, "BADALG", 0}, \ { dns_tsigerror_badtrunc, "BADTRUNC", 0}, \ { 0, NULL, 0 } /* RFC4398 section 2.1 */ #define CERTNAMES \ { 1, "PKIX", 0}, \ { 2, "SPKI", 0}, \ { 3, "PGP", 0}, \ { 4, "IPKIX", 0}, \ { 5, "ISPKI", 0}, \ { 6, "IPGP", 0}, \ { 7, "ACPKIX", 0}, \ { 8, "IACPKIX", 0}, \ { 253, "URI", 0}, \ { 254, "OID", 0}, \ { 0, NULL, 0} /* RFC2535 section 7, RFC3110 */ #define MD5_SECALGNAMES #define DH_SECALGNAMES #define DSA_SECALGNAMES #define SECALGNAMES \ MD5_SECALGNAMES \ DH_SECALGNAMES \ DSA_SECALGNAMES \ { DNS_KEYALG_ECC, "ECC", 0 }, \ { DNS_KEYALG_RSASHA1, "RSASHA1", 0 }, \ { DNS_KEYALG_NSEC3RSASHA1, "NSEC3RSASHA1", 0 }, \ { DNS_KEYALG_RSASHA256, "RSASHA256", 0 }, \ { DNS_KEYALG_RSASHA512, "RSASHA512", 0 }, \ { DNS_KEYALG_ECCGOST, "ECCGOST", 0 }, \ { DNS_KEYALG_ECDSA256, "ECDSAP256SHA256", 0 }, \ { DNS_KEYALG_ECDSA384, "ECDSAP384SHA384", 0 }, \ { DNS_KEYALG_ED25519, "ED25519", 0 }, \ { DNS_KEYALG_ED448, "ED448", 0 }, \ { DNS_KEYALG_INDIRECT, "INDIRECT", 0 }, \ { DNS_KEYALG_PRIVATEDNS, "PRIVATEDNS", 0 }, \ { DNS_KEYALG_PRIVATEOID, "PRIVATEOID", 0 }, \ { 0, NULL, 0} /* RFC2535 section 7.1 */ struct tbl { unsigned int value; const char *name; int flags; }; static struct tbl tsigrcodes[] = { RCODENAMES TSIGRCODENAMES }; static struct tbl certs[] = { CERTNAMES }; static struct tbl secalgs[] = { SECALGNAMES }; static isc_result_t dns_mnemonic_totext(unsigned int value, isc_buffer_t *target, struct tbl *table) { int i = 0; char buf[sizeof("4294967296")]; while (table[i].name != NULL) { if (table[i].value == value) { return (isc_str_tobuffer(table[i].name, target)); } i++; } snprintf(buf, sizeof(buf), "%u", value); return (isc_str_tobuffer(buf, target)); } isc_result_t dns_tsigrcode_totext(dns_rcode_t rcode, isc_buffer_t *target) { return (dns_mnemonic_totext(rcode, target, tsigrcodes)); } isc_result_t dns_cert_totext(dns_cert_t cert, isc_buffer_t *target) { return (dns_mnemonic_totext(cert, target, certs)); } isc_result_t dns_secalg_totext(dns_secalg_t secalg, isc_buffer_t *target) { return (dns_mnemonic_totext(secalg, target, secalgs)); } void dns_secalg_format(dns_secalg_t alg, char *cp, unsigned int size) { isc_buffer_t b; isc_region_t r; isc_result_t result; REQUIRE(cp != NULL && size > 0); isc_buffer_init(&b, cp, size - 1); result = dns_secalg_totext(alg, &b); isc_buffer_usedregion(&b, &r); r.base[r.length] = 0; if (result != ISC_R_SUCCESS) r.base[0] = 0; } /* * This uses lots of hard coded values, but how often do we actually * add classes? */ isc_result_t dns_rdataclass_fromtext(dns_rdataclass_t *classp, isc_textregion_t *source) { #define COMPARE(string, rdclass) \ if (((sizeof(string) - 1) == source->length) \ && (strncasecmp(source->base, string, source->length) == 0)) { \ *classp = rdclass; \ return (ISC_R_SUCCESS); \ } switch (tolower((unsigned char)source->base[0])) { case 'a': COMPARE("any", dns_rdataclass_any); break; case 'c': /* * RFC1035 says the mnemonic for the CHAOS class is CH, * but historical BIND practice is to call it CHAOS. * We will accept both forms, but only generate CH. */ COMPARE("ch", dns_rdataclass_chaos); COMPARE("chaos", dns_rdataclass_chaos); if (source->length > 5 && source->length < (5 + sizeof("65000")) && strncasecmp("class", source->base, 5) == 0) { char buf[sizeof("65000")]; char *endp; unsigned int val; /* * source->base is not required to be NUL terminated. * Copy up to remaining bytes and NUL terminate. */ snprintf(buf, sizeof(buf), "%.*s", (int)(source->length - 5), source->base + 5); val = strtoul(buf, &endp, 10); if (*endp == '\0' && val <= 0xffff) { *classp = (dns_rdataclass_t)val; return (ISC_R_SUCCESS); } } break; case 'h': COMPARE("hs", dns_rdataclass_hs); COMPARE("hesiod", dns_rdataclass_hs); break; case 'i': COMPARE("in", dns_rdataclass_in); break; case 'n': COMPARE("none", dns_rdataclass_none); break; case 'r': COMPARE("reserved0", dns_rdataclass_reserved0); break; } #undef COMPARE return (DNS_R_UNKNOWN); } isc_result_t dns_rdataclass_totext(dns_rdataclass_t rdclass, isc_buffer_t *target) { char buf[sizeof("CLASS65535")]; switch (rdclass) { case dns_rdataclass_any: return (isc_str_tobuffer("ANY", target)); case dns_rdataclass_chaos: return (isc_str_tobuffer("CH", target)); case dns_rdataclass_hs: return (isc_str_tobuffer("HS", target)); case dns_rdataclass_in: return (isc_str_tobuffer("IN", target)); case dns_rdataclass_none: return (isc_str_tobuffer("NONE", target)); case dns_rdataclass_reserved0: return (isc_str_tobuffer("RESERVED0", target)); default: snprintf(buf, sizeof(buf), "CLASS%u", rdclass); return (isc_str_tobuffer(buf, target)); } } void dns_rdataclass_format(dns_rdataclass_t rdclass, char *array, unsigned int size) { isc_result_t result; isc_buffer_t buf; if (size == 0U) return; isc_buffer_init(&buf, array, size); result = dns_rdataclass_totext(rdclass, &buf); /* * Null terminate. */ if (result == ISC_R_SUCCESS) { if (isc_buffer_availablelength(&buf) >= 1) isc_buffer_putuint8(&buf, 0); else result = ISC_R_NOSPACE; } if (result != ISC_R_SUCCESS) strlcpy(array, "", size); }