15185a700Sflorian /*
25185a700Sflorian * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
35185a700Sflorian *
45185a700Sflorian * Permission to use, copy, modify, and/or distribute this software for any
55185a700Sflorian * purpose with or without fee is hereby granted, provided that the above
65185a700Sflorian * copyright notice and this permission notice appear in all copies.
75185a700Sflorian *
85185a700Sflorian * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
95185a700Sflorian * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
105185a700Sflorian * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
115185a700Sflorian * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
125185a700Sflorian * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
135185a700Sflorian * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
145185a700Sflorian * PERFORMANCE OF THIS SOFTWARE.
155185a700Sflorian */
165185a700Sflorian
17*873f12b9Sflorian /* $Id: rcode.c,v 1.9 2020/02/26 18:47:58 florian Exp $ */
185185a700Sflorian
195185a700Sflorian #include <ctype.h>
205185a700Sflorian #include <stdlib.h>
214465bcfbSjsg #include <string.h>
225185a700Sflorian
235185a700Sflorian #include <isc/buffer.h>
245185a700Sflorian #include <isc/region.h>
255185a700Sflorian #include <isc/result.h>
265185a700Sflorian #include <isc/types.h>
275185a700Sflorian #include <isc/util.h>
285185a700Sflorian
295185a700Sflorian #include <dns/cert.h>
305185a700Sflorian #include <dns/keyvalues.h>
315185a700Sflorian #include <dns/rcode.h>
325185a700Sflorian #include <dns/rdataclass.h>
335185a700Sflorian #include <dns/result.h>
345185a700Sflorian #include <dns/secalg.h>
355185a700Sflorian
365185a700Sflorian #define TOTEXTONLY 0x01
375185a700Sflorian
385185a700Sflorian #define RCODENAMES \
395185a700Sflorian /* standard rcodes */ \
405185a700Sflorian { dns_rcode_noerror, "NOERROR", 0}, \
415185a700Sflorian { dns_rcode_formerr, "FORMERR", 0}, \
425185a700Sflorian { dns_rcode_servfail, "SERVFAIL", 0}, \
435185a700Sflorian { dns_rcode_nxdomain, "NXDOMAIN", 0}, \
445185a700Sflorian { dns_rcode_notimp, "NOTIMP", 0}, \
455185a700Sflorian { dns_rcode_refused, "REFUSED", 0}, \
465185a700Sflorian { dns_rcode_yxdomain, "YXDOMAIN", 0}, \
475185a700Sflorian { dns_rcode_yxrrset, "YXRRSET", 0}, \
485185a700Sflorian { dns_rcode_nxrrset, "NXRRSET", 0}, \
495185a700Sflorian { dns_rcode_notauth, "NOTAUTH", 0}, \
505185a700Sflorian { dns_rcode_notzone, "NOTZONE", 0}, \
515185a700Sflorian { 11, "RESERVED11", TOTEXTONLY}, \
525185a700Sflorian { 12, "RESERVED12", TOTEXTONLY}, \
535185a700Sflorian { 13, "RESERVED13", TOTEXTONLY}, \
545185a700Sflorian { 14, "RESERVED14", TOTEXTONLY}, \
555185a700Sflorian { 15, "RESERVED15", TOTEXTONLY},
565185a700Sflorian
575185a700Sflorian #define TSIGRCODENAMES \
585185a700Sflorian /* extended rcodes */ \
595185a700Sflorian { dns_tsigerror_badsig, "BADSIG", 0}, \
605185a700Sflorian { dns_tsigerror_badkey, "BADKEY", 0}, \
615185a700Sflorian { dns_tsigerror_badtime, "BADTIME", 0}, \
625185a700Sflorian { dns_tsigerror_badmode, "BADMODE", 0}, \
635185a700Sflorian { dns_tsigerror_badname, "BADNAME", 0}, \
645185a700Sflorian { dns_tsigerror_badalg, "BADALG", 0}, \
655185a700Sflorian { dns_tsigerror_badtrunc, "BADTRUNC", 0}, \
665185a700Sflorian { 0, NULL, 0 }
675185a700Sflorian
685185a700Sflorian /* RFC4398 section 2.1 */
695185a700Sflorian
705185a700Sflorian #define CERTNAMES \
715185a700Sflorian { 1, "PKIX", 0}, \
725185a700Sflorian { 2, "SPKI", 0}, \
735185a700Sflorian { 3, "PGP", 0}, \
745185a700Sflorian { 4, "IPKIX", 0}, \
755185a700Sflorian { 5, "ISPKI", 0}, \
765185a700Sflorian { 6, "IPGP", 0}, \
775185a700Sflorian { 7, "ACPKIX", 0}, \
785185a700Sflorian { 8, "IACPKIX", 0}, \
795185a700Sflorian { 253, "URI", 0}, \
805185a700Sflorian { 254, "OID", 0}, \
815185a700Sflorian { 0, NULL, 0}
825185a700Sflorian
835185a700Sflorian /* RFC2535 section 7, RFC3110 */
845185a700Sflorian
855185a700Sflorian #define MD5_SECALGNAMES
865185a700Sflorian #define DH_SECALGNAMES
875185a700Sflorian #define DSA_SECALGNAMES
885185a700Sflorian
895185a700Sflorian #define SECALGNAMES \
905185a700Sflorian MD5_SECALGNAMES \
915185a700Sflorian DH_SECALGNAMES \
925185a700Sflorian DSA_SECALGNAMES \
935185a700Sflorian { DNS_KEYALG_ECC, "ECC", 0 }, \
945185a700Sflorian { DNS_KEYALG_RSASHA1, "RSASHA1", 0 }, \
955185a700Sflorian { DNS_KEYALG_NSEC3RSASHA1, "NSEC3RSASHA1", 0 }, \
965185a700Sflorian { DNS_KEYALG_RSASHA256, "RSASHA256", 0 }, \
975185a700Sflorian { DNS_KEYALG_RSASHA512, "RSASHA512", 0 }, \
985185a700Sflorian { DNS_KEYALG_ECCGOST, "ECCGOST", 0 }, \
995185a700Sflorian { DNS_KEYALG_ECDSA256, "ECDSAP256SHA256", 0 }, \
1005185a700Sflorian { DNS_KEYALG_ECDSA384, "ECDSAP384SHA384", 0 }, \
1015185a700Sflorian { DNS_KEYALG_ED25519, "ED25519", 0 }, \
1025185a700Sflorian { DNS_KEYALG_ED448, "ED448", 0 }, \
1035185a700Sflorian { DNS_KEYALG_INDIRECT, "INDIRECT", 0 }, \
1045185a700Sflorian { DNS_KEYALG_PRIVATEDNS, "PRIVATEDNS", 0 }, \
1055185a700Sflorian { DNS_KEYALG_PRIVATEOID, "PRIVATEOID", 0 }, \
1065185a700Sflorian { 0, NULL, 0}
1075185a700Sflorian
1085185a700Sflorian /* RFC2535 section 7.1 */
1095185a700Sflorian
1105185a700Sflorian struct tbl {
1115185a700Sflorian unsigned int value;
1125185a700Sflorian const char *name;
1135185a700Sflorian int flags;
1145185a700Sflorian };
1155185a700Sflorian
1165185a700Sflorian static struct tbl tsigrcodes[] = { RCODENAMES TSIGRCODENAMES };
1175185a700Sflorian static struct tbl certs[] = { CERTNAMES };
1185185a700Sflorian static struct tbl secalgs[] = { SECALGNAMES };
1195185a700Sflorian
1205185a700Sflorian static isc_result_t
dns_mnemonic_totext(unsigned int value,isc_buffer_t * target,struct tbl * table)1215185a700Sflorian dns_mnemonic_totext(unsigned int value, isc_buffer_t *target,
1225185a700Sflorian struct tbl *table)
1235185a700Sflorian {
1245185a700Sflorian int i = 0;
1255185a700Sflorian char buf[sizeof("4294967296")];
1265185a700Sflorian while (table[i].name != NULL) {
1275185a700Sflorian if (table[i].value == value) {
128*873f12b9Sflorian return (isc_str_tobuffer(table[i].name, target));
1295185a700Sflorian }
1305185a700Sflorian i++;
1315185a700Sflorian }
1325185a700Sflorian snprintf(buf, sizeof(buf), "%u", value);
133*873f12b9Sflorian return (isc_str_tobuffer(buf, target));
1345185a700Sflorian }
1355185a700Sflorian
1365185a700Sflorian isc_result_t
dns_tsigrcode_totext(dns_rcode_t rcode,isc_buffer_t * target)1375185a700Sflorian dns_tsigrcode_totext(dns_rcode_t rcode, isc_buffer_t *target) {
1385185a700Sflorian return (dns_mnemonic_totext(rcode, target, tsigrcodes));
1395185a700Sflorian }
1405185a700Sflorian
1415185a700Sflorian isc_result_t
dns_cert_totext(dns_cert_t cert,isc_buffer_t * target)1425185a700Sflorian dns_cert_totext(dns_cert_t cert, isc_buffer_t *target) {
1435185a700Sflorian return (dns_mnemonic_totext(cert, target, certs));
1445185a700Sflorian }
1455185a700Sflorian
1465185a700Sflorian isc_result_t
dns_secalg_totext(dns_secalg_t secalg,isc_buffer_t * target)1475185a700Sflorian dns_secalg_totext(dns_secalg_t secalg, isc_buffer_t *target) {
1485185a700Sflorian return (dns_mnemonic_totext(secalg, target, secalgs));
1495185a700Sflorian }
1505185a700Sflorian
1515185a700Sflorian void
dns_secalg_format(dns_secalg_t alg,char * cp,unsigned int size)1525185a700Sflorian dns_secalg_format(dns_secalg_t alg, char *cp, unsigned int size) {
1535185a700Sflorian isc_buffer_t b;
1545185a700Sflorian isc_region_t r;
1555185a700Sflorian isc_result_t result;
1565185a700Sflorian
1575185a700Sflorian REQUIRE(cp != NULL && size > 0);
1585185a700Sflorian isc_buffer_init(&b, cp, size - 1);
1595185a700Sflorian result = dns_secalg_totext(alg, &b);
1605185a700Sflorian isc_buffer_usedregion(&b, &r);
1615185a700Sflorian r.base[r.length] = 0;
1625185a700Sflorian if (result != ISC_R_SUCCESS)
1635185a700Sflorian r.base[0] = 0;
1645185a700Sflorian }
1655185a700Sflorian
1665185a700Sflorian /*
1675185a700Sflorian * This uses lots of hard coded values, but how often do we actually
1685185a700Sflorian * add classes?
1695185a700Sflorian */
1705185a700Sflorian isc_result_t
dns_rdataclass_fromtext(dns_rdataclass_t * classp,isc_textregion_t * source)1715185a700Sflorian dns_rdataclass_fromtext(dns_rdataclass_t *classp, isc_textregion_t *source) {
1725185a700Sflorian #define COMPARE(string, rdclass) \
1735185a700Sflorian if (((sizeof(string) - 1) == source->length) \
1745185a700Sflorian && (strncasecmp(source->base, string, source->length) == 0)) { \
1755185a700Sflorian *classp = rdclass; \
1765185a700Sflorian return (ISC_R_SUCCESS); \
1775185a700Sflorian }
1785185a700Sflorian
1795185a700Sflorian switch (tolower((unsigned char)source->base[0])) {
1805185a700Sflorian case 'a':
1815185a700Sflorian COMPARE("any", dns_rdataclass_any);
1825185a700Sflorian break;
1835185a700Sflorian case 'c':
1845185a700Sflorian /*
1855185a700Sflorian * RFC1035 says the mnemonic for the CHAOS class is CH,
1865185a700Sflorian * but historical BIND practice is to call it CHAOS.
1875185a700Sflorian * We will accept both forms, but only generate CH.
1885185a700Sflorian */
1895185a700Sflorian COMPARE("ch", dns_rdataclass_chaos);
1905185a700Sflorian COMPARE("chaos", dns_rdataclass_chaos);
1915185a700Sflorian
1925185a700Sflorian if (source->length > 5 &&
1935185a700Sflorian source->length < (5 + sizeof("65000")) &&
1945185a700Sflorian strncasecmp("class", source->base, 5) == 0) {
1955185a700Sflorian char buf[sizeof("65000")];
1965185a700Sflorian char *endp;
1975185a700Sflorian unsigned int val;
1985185a700Sflorian
1995185a700Sflorian /*
2005185a700Sflorian * source->base is not required to be NUL terminated.
2015185a700Sflorian * Copy up to remaining bytes and NUL terminate.
2025185a700Sflorian */
2035185a700Sflorian snprintf(buf, sizeof(buf), "%.*s",
2045185a700Sflorian (int)(source->length - 5), source->base + 5);
2055185a700Sflorian val = strtoul(buf, &endp, 10);
2065185a700Sflorian if (*endp == '\0' && val <= 0xffff) {
2075185a700Sflorian *classp = (dns_rdataclass_t)val;
2085185a700Sflorian return (ISC_R_SUCCESS);
2095185a700Sflorian }
2105185a700Sflorian }
2115185a700Sflorian break;
2125185a700Sflorian case 'h':
2135185a700Sflorian COMPARE("hs", dns_rdataclass_hs);
2145185a700Sflorian COMPARE("hesiod", dns_rdataclass_hs);
2155185a700Sflorian break;
2165185a700Sflorian case 'i':
2175185a700Sflorian COMPARE("in", dns_rdataclass_in);
2185185a700Sflorian break;
2195185a700Sflorian case 'n':
2205185a700Sflorian COMPARE("none", dns_rdataclass_none);
2215185a700Sflorian break;
2225185a700Sflorian case 'r':
2235185a700Sflorian COMPARE("reserved0", dns_rdataclass_reserved0);
2245185a700Sflorian break;
2255185a700Sflorian }
2265185a700Sflorian
2275185a700Sflorian #undef COMPARE
2285185a700Sflorian
2295185a700Sflorian return (DNS_R_UNKNOWN);
2305185a700Sflorian }
2315185a700Sflorian
2325185a700Sflorian isc_result_t
dns_rdataclass_totext(dns_rdataclass_t rdclass,isc_buffer_t * target)2335185a700Sflorian dns_rdataclass_totext(dns_rdataclass_t rdclass, isc_buffer_t *target) {
2345185a700Sflorian char buf[sizeof("CLASS65535")];
2355185a700Sflorian
2365185a700Sflorian switch (rdclass) {
2375185a700Sflorian case dns_rdataclass_any:
238*873f12b9Sflorian return (isc_str_tobuffer("ANY", target));
2395185a700Sflorian case dns_rdataclass_chaos:
240*873f12b9Sflorian return (isc_str_tobuffer("CH", target));
2415185a700Sflorian case dns_rdataclass_hs:
242*873f12b9Sflorian return (isc_str_tobuffer("HS", target));
2435185a700Sflorian case dns_rdataclass_in:
244*873f12b9Sflorian return (isc_str_tobuffer("IN", target));
2455185a700Sflorian case dns_rdataclass_none:
246*873f12b9Sflorian return (isc_str_tobuffer("NONE", target));
2475185a700Sflorian case dns_rdataclass_reserved0:
248*873f12b9Sflorian return (isc_str_tobuffer("RESERVED0", target));
2495185a700Sflorian default:
2505185a700Sflorian snprintf(buf, sizeof(buf), "CLASS%u", rdclass);
251*873f12b9Sflorian return (isc_str_tobuffer(buf, target));
2525185a700Sflorian }
2535185a700Sflorian }
2545185a700Sflorian
2555185a700Sflorian void
dns_rdataclass_format(dns_rdataclass_t rdclass,char * array,unsigned int size)2565185a700Sflorian dns_rdataclass_format(dns_rdataclass_t rdclass,
2575185a700Sflorian char *array, unsigned int size)
2585185a700Sflorian {
2595185a700Sflorian isc_result_t result;
2605185a700Sflorian isc_buffer_t buf;
2615185a700Sflorian
2625185a700Sflorian if (size == 0U)
2635185a700Sflorian return;
2645185a700Sflorian
2655185a700Sflorian isc_buffer_init(&buf, array, size);
2665185a700Sflorian result = dns_rdataclass_totext(rdclass, &buf);
2675185a700Sflorian /*
2685185a700Sflorian * Null terminate.
2695185a700Sflorian */
2705185a700Sflorian if (result == ISC_R_SUCCESS) {
2715185a700Sflorian if (isc_buffer_availablelength(&buf) >= 1)
2725185a700Sflorian isc_buffer_putuint8(&buf, 0);
2735185a700Sflorian else
2745185a700Sflorian result = ISC_R_NOSPACE;
2755185a700Sflorian }
2765185a700Sflorian if (result != ISC_R_SUCCESS)
2775185a700Sflorian strlcpy(array, "<unknown>", size);
2785185a700Sflorian }
279