1 /*
2 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
9 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
11 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
13 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14 * PERFORMANCE OF THIS SOFTWARE.
15 */
16
17 /* $Id: rcode.c,v 1.9 2020/02/26 18:47:58 florian Exp $ */
18
19 #include <ctype.h>
20 #include <stdlib.h>
21 #include <string.h>
22
23 #include <isc/buffer.h>
24 #include <isc/region.h>
25 #include <isc/result.h>
26 #include <isc/types.h>
27 #include <isc/util.h>
28
29 #include <dns/cert.h>
30 #include <dns/keyvalues.h>
31 #include <dns/rcode.h>
32 #include <dns/rdataclass.h>
33 #include <dns/result.h>
34 #include <dns/secalg.h>
35
36 #define TOTEXTONLY 0x01
37
38 #define RCODENAMES \
39 /* standard rcodes */ \
40 { dns_rcode_noerror, "NOERROR", 0}, \
41 { dns_rcode_formerr, "FORMERR", 0}, \
42 { dns_rcode_servfail, "SERVFAIL", 0}, \
43 { dns_rcode_nxdomain, "NXDOMAIN", 0}, \
44 { dns_rcode_notimp, "NOTIMP", 0}, \
45 { dns_rcode_refused, "REFUSED", 0}, \
46 { dns_rcode_yxdomain, "YXDOMAIN", 0}, \
47 { dns_rcode_yxrrset, "YXRRSET", 0}, \
48 { dns_rcode_nxrrset, "NXRRSET", 0}, \
49 { dns_rcode_notauth, "NOTAUTH", 0}, \
50 { dns_rcode_notzone, "NOTZONE", 0}, \
51 { 11, "RESERVED11", TOTEXTONLY}, \
52 { 12, "RESERVED12", TOTEXTONLY}, \
53 { 13, "RESERVED13", TOTEXTONLY}, \
54 { 14, "RESERVED14", TOTEXTONLY}, \
55 { 15, "RESERVED15", TOTEXTONLY},
56
57 #define TSIGRCODENAMES \
58 /* extended rcodes */ \
59 { dns_tsigerror_badsig, "BADSIG", 0}, \
60 { dns_tsigerror_badkey, "BADKEY", 0}, \
61 { dns_tsigerror_badtime, "BADTIME", 0}, \
62 { dns_tsigerror_badmode, "BADMODE", 0}, \
63 { dns_tsigerror_badname, "BADNAME", 0}, \
64 { dns_tsigerror_badalg, "BADALG", 0}, \
65 { dns_tsigerror_badtrunc, "BADTRUNC", 0}, \
66 { 0, NULL, 0 }
67
68 /* RFC4398 section 2.1 */
69
70 #define CERTNAMES \
71 { 1, "PKIX", 0}, \
72 { 2, "SPKI", 0}, \
73 { 3, "PGP", 0}, \
74 { 4, "IPKIX", 0}, \
75 { 5, "ISPKI", 0}, \
76 { 6, "IPGP", 0}, \
77 { 7, "ACPKIX", 0}, \
78 { 8, "IACPKIX", 0}, \
79 { 253, "URI", 0}, \
80 { 254, "OID", 0}, \
81 { 0, NULL, 0}
82
83 /* RFC2535 section 7, RFC3110 */
84
85 #define MD5_SECALGNAMES
86 #define DH_SECALGNAMES
87 #define DSA_SECALGNAMES
88
89 #define SECALGNAMES \
90 MD5_SECALGNAMES \
91 DH_SECALGNAMES \
92 DSA_SECALGNAMES \
93 { DNS_KEYALG_ECC, "ECC", 0 }, \
94 { DNS_KEYALG_RSASHA1, "RSASHA1", 0 }, \
95 { DNS_KEYALG_NSEC3RSASHA1, "NSEC3RSASHA1", 0 }, \
96 { DNS_KEYALG_RSASHA256, "RSASHA256", 0 }, \
97 { DNS_KEYALG_RSASHA512, "RSASHA512", 0 }, \
98 { DNS_KEYALG_ECCGOST, "ECCGOST", 0 }, \
99 { DNS_KEYALG_ECDSA256, "ECDSAP256SHA256", 0 }, \
100 { DNS_KEYALG_ECDSA384, "ECDSAP384SHA384", 0 }, \
101 { DNS_KEYALG_ED25519, "ED25519", 0 }, \
102 { DNS_KEYALG_ED448, "ED448", 0 }, \
103 { DNS_KEYALG_INDIRECT, "INDIRECT", 0 }, \
104 { DNS_KEYALG_PRIVATEDNS, "PRIVATEDNS", 0 }, \
105 { DNS_KEYALG_PRIVATEOID, "PRIVATEOID", 0 }, \
106 { 0, NULL, 0}
107
108 /* RFC2535 section 7.1 */
109
110 struct tbl {
111 unsigned int value;
112 const char *name;
113 int flags;
114 };
115
116 static struct tbl tsigrcodes[] = { RCODENAMES TSIGRCODENAMES };
117 static struct tbl certs[] = { CERTNAMES };
118 static struct tbl secalgs[] = { SECALGNAMES };
119
120 static isc_result_t
dns_mnemonic_totext(unsigned int value,isc_buffer_t * target,struct tbl * table)121 dns_mnemonic_totext(unsigned int value, isc_buffer_t *target,
122 struct tbl *table)
123 {
124 int i = 0;
125 char buf[sizeof("4294967296")];
126 while (table[i].name != NULL) {
127 if (table[i].value == value) {
128 return (isc_str_tobuffer(table[i].name, target));
129 }
130 i++;
131 }
132 snprintf(buf, sizeof(buf), "%u", value);
133 return (isc_str_tobuffer(buf, target));
134 }
135
136 isc_result_t
dns_tsigrcode_totext(dns_rcode_t rcode,isc_buffer_t * target)137 dns_tsigrcode_totext(dns_rcode_t rcode, isc_buffer_t *target) {
138 return (dns_mnemonic_totext(rcode, target, tsigrcodes));
139 }
140
141 isc_result_t
dns_cert_totext(dns_cert_t cert,isc_buffer_t * target)142 dns_cert_totext(dns_cert_t cert, isc_buffer_t *target) {
143 return (dns_mnemonic_totext(cert, target, certs));
144 }
145
146 isc_result_t
dns_secalg_totext(dns_secalg_t secalg,isc_buffer_t * target)147 dns_secalg_totext(dns_secalg_t secalg, isc_buffer_t *target) {
148 return (dns_mnemonic_totext(secalg, target, secalgs));
149 }
150
151 void
dns_secalg_format(dns_secalg_t alg,char * cp,unsigned int size)152 dns_secalg_format(dns_secalg_t alg, char *cp, unsigned int size) {
153 isc_buffer_t b;
154 isc_region_t r;
155 isc_result_t result;
156
157 REQUIRE(cp != NULL && size > 0);
158 isc_buffer_init(&b, cp, size - 1);
159 result = dns_secalg_totext(alg, &b);
160 isc_buffer_usedregion(&b, &r);
161 r.base[r.length] = 0;
162 if (result != ISC_R_SUCCESS)
163 r.base[0] = 0;
164 }
165
166 /*
167 * This uses lots of hard coded values, but how often do we actually
168 * add classes?
169 */
170 isc_result_t
dns_rdataclass_fromtext(dns_rdataclass_t * classp,isc_textregion_t * source)171 dns_rdataclass_fromtext(dns_rdataclass_t *classp, isc_textregion_t *source) {
172 #define COMPARE(string, rdclass) \
173 if (((sizeof(string) - 1) == source->length) \
174 && (strncasecmp(source->base, string, source->length) == 0)) { \
175 *classp = rdclass; \
176 return (ISC_R_SUCCESS); \
177 }
178
179 switch (tolower((unsigned char)source->base[0])) {
180 case 'a':
181 COMPARE("any", dns_rdataclass_any);
182 break;
183 case 'c':
184 /*
185 * RFC1035 says the mnemonic for the CHAOS class is CH,
186 * but historical BIND practice is to call it CHAOS.
187 * We will accept both forms, but only generate CH.
188 */
189 COMPARE("ch", dns_rdataclass_chaos);
190 COMPARE("chaos", dns_rdataclass_chaos);
191
192 if (source->length > 5 &&
193 source->length < (5 + sizeof("65000")) &&
194 strncasecmp("class", source->base, 5) == 0) {
195 char buf[sizeof("65000")];
196 char *endp;
197 unsigned int val;
198
199 /*
200 * source->base is not required to be NUL terminated.
201 * Copy up to remaining bytes and NUL terminate.
202 */
203 snprintf(buf, sizeof(buf), "%.*s",
204 (int)(source->length - 5), source->base + 5);
205 val = strtoul(buf, &endp, 10);
206 if (*endp == '\0' && val <= 0xffff) {
207 *classp = (dns_rdataclass_t)val;
208 return (ISC_R_SUCCESS);
209 }
210 }
211 break;
212 case 'h':
213 COMPARE("hs", dns_rdataclass_hs);
214 COMPARE("hesiod", dns_rdataclass_hs);
215 break;
216 case 'i':
217 COMPARE("in", dns_rdataclass_in);
218 break;
219 case 'n':
220 COMPARE("none", dns_rdataclass_none);
221 break;
222 case 'r':
223 COMPARE("reserved0", dns_rdataclass_reserved0);
224 break;
225 }
226
227 #undef COMPARE
228
229 return (DNS_R_UNKNOWN);
230 }
231
232 isc_result_t
dns_rdataclass_totext(dns_rdataclass_t rdclass,isc_buffer_t * target)233 dns_rdataclass_totext(dns_rdataclass_t rdclass, isc_buffer_t *target) {
234 char buf[sizeof("CLASS65535")];
235
236 switch (rdclass) {
237 case dns_rdataclass_any:
238 return (isc_str_tobuffer("ANY", target));
239 case dns_rdataclass_chaos:
240 return (isc_str_tobuffer("CH", target));
241 case dns_rdataclass_hs:
242 return (isc_str_tobuffer("HS", target));
243 case dns_rdataclass_in:
244 return (isc_str_tobuffer("IN", target));
245 case dns_rdataclass_none:
246 return (isc_str_tobuffer("NONE", target));
247 case dns_rdataclass_reserved0:
248 return (isc_str_tobuffer("RESERVED0", target));
249 default:
250 snprintf(buf, sizeof(buf), "CLASS%u", rdclass);
251 return (isc_str_tobuffer(buf, target));
252 }
253 }
254
255 void
dns_rdataclass_format(dns_rdataclass_t rdclass,char * array,unsigned int size)256 dns_rdataclass_format(dns_rdataclass_t rdclass,
257 char *array, unsigned int size)
258 {
259 isc_result_t result;
260 isc_buffer_t buf;
261
262 if (size == 0U)
263 return;
264
265 isc_buffer_init(&buf, array, size);
266 result = dns_rdataclass_totext(rdclass, &buf);
267 /*
268 * Null terminate.
269 */
270 if (result == ISC_R_SUCCESS) {
271 if (isc_buffer_availablelength(&buf) >= 1)
272 isc_buffer_putuint8(&buf, 0);
273 else
274 result = ISC_R_NOSPACE;
275 }
276 if (result != ISC_R_SUCCESS)
277 strlcpy(array, "<unknown>", size);
278 }
279