summaryrefslogtreecommitdiffstats
path: root/src/libknot/error.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libknot/error.c')
-rw-r--r--src/libknot/error.c239
1 files changed, 239 insertions, 0 deletions
diff --git a/src/libknot/error.c b/src/libknot/error.c
new file mode 100644
index 0000000..352acd3
--- /dev/null
+++ b/src/libknot/error.c
@@ -0,0 +1,239 @@
+/* Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <lmdb.h>
+
+#include "libknot/attribute.h"
+#include "libknot/error.h"
+#include "libdnssec/error.h"
+
+struct error {
+ int code;
+ const char *message;
+};
+
+static const struct error errors[] = {
+ { KNOT_EOK, "OK" },
+
+ /* Directly mapped error codes. */
+ { KNOT_ENOMEM, "not enough memory" },
+ { KNOT_EINVAL, "invalid parameter" },
+ { KNOT_ENOTSUP, "operation not supported" },
+ { KNOT_EBUSY, "requested resource is busy" },
+ { KNOT_EAGAIN, "OS lacked necessary resources" },
+ { KNOT_ENOBUFS, "no buffers" },
+ { KNOT_EMFILE, "too many open files" },
+ { KNOT_ENFILE, "too many open files in system" },
+ { KNOT_EACCES, "operation not permitted" },
+ { KNOT_EISCONN, "already connected" },
+ { KNOT_ECONNREFUSED, "connection refused" },
+ { KNOT_EALREADY, "operation already in progress" },
+ { KNOT_ECONNRESET, "connection reset by peer" },
+ { KNOT_ECONNABORTED, "connection aborted" },
+ { KNOT_ENETRESET, "connection aborted by network" },
+ { KNOT_EHOSTUNREACH, "host is unreachable" },
+ { KNOT_ENETUNREACH, "network is unreachable" },
+ { KNOT_EHOSTDOWN, "host is down" },
+ { KNOT_ENETDOWN, "network is down" },
+ { KNOT_EADDRINUSE, "address already in use" },
+ { KNOT_ENOENT, "not exists" },
+ { KNOT_EEXIST, "already exists" },
+ { KNOT_ERANGE, "value is out of range" },
+ { KNOT_EADDRNOTAVAIL, "address is not available" },
+ { KNOT_ENOTDIR, "not a directory" },
+
+ { KNOT_ERRNO_ERROR, "unknown system error" },
+
+ /* General errors. */
+ { KNOT_ERROR, "failed" },
+ { KNOT_EPARSEFAIL, "parser failed" },
+ { KNOT_ESEMCHECK, "semantic check" },
+ { KNOT_EUPTODATE, "zone is up-to-date" },
+ { KNOT_EFEWDATA, "not enough data to parse" },
+ { KNOT_ESPACE, "not enough space provided" },
+ { KNOT_EMALF, "malformed data" },
+ { KNOT_ENSEC3PAR, "missing or wrong NSEC3PARAM record" },
+ { KNOT_ENSEC3CHAIN, "missing or wrong NSEC3 chain in the zone" },
+ { KNOT_EOUTOFZONE, "name does not belong to the zone" },
+ { KNOT_EZONEINVAL, "invalid zone file" },
+ { KNOT_ENOZONE, "no such zone found" },
+ { KNOT_ENONODE, "no such node in zone found" },
+ { KNOT_ENORECORD, "no such record in zone found" },
+ { KNOT_EISRECORD, "such record already exists in zone" },
+ { KNOT_ENOMASTER, "no usable master" },
+ { KNOT_EPREREQ, "UPDATE prerequisite not met" },
+ { KNOT_ETTL, "TTL mismatch" },
+ { KNOT_ENOTTL, "no TTL specified" },
+ { KNOT_ENOXFR, "transfer was not sent" },
+ { KNOT_EDENIED, "not allowed" },
+ { KNOT_ECONN, "connection reset" },
+ { KNOT_ETIMEOUT, "connection timeout" },
+ { KNOT_ENODIFF, "cannot create zone diff" },
+ { KNOT_ENOTSIG, "expected a TSIG or SIG(0)" },
+ { KNOT_ELIMIT, "exceeded limit" },
+ { KNOT_EZONESIZE, "zone size exceeded" },
+ { KNOT_EOF, "end of file" },
+ { KNOT_ESYSTEM, "system error" },
+ { KNOT_EFILE, "file error" },
+ { KNOT_ESOAINVAL, "SOA mismatch" },
+ { KNOT_ETRAIL, "trailing data" },
+ { KNOT_EPROCESSING, "processing error" },
+ { KNOT_EPROGRESS, "in progress" },
+ { KNOT_ELOOP, "loop detected" },
+ { KNOT_EPROGRAM, "program not loaded" },
+ { KNOT_EFD, "file descriptor error" },
+ { KNOT_ENOPARAM, "missing parameter" },
+ { KNOT_EXPARAM, "parameter conflict" },
+ { KNOT_EEMPTYZONE, "zone is empty" },
+ { KNOT_ENODB, "database does not exist" },
+ { KNOT_EUNREACH, "remote known to be unreachable" },
+
+ { KNOT_GENERAL_ERROR, "unknown general error" },
+
+ /* Control states. */
+ { KNOT_CTL_ESTOP, "stopping server" },
+ { KNOT_CTL_EZONE, "operation failed for some zones" },
+
+ /* Network errors. */
+ { KNOT_NET_EADDR, "bad address or host name" },
+ { KNOT_NET_ESOCKET, "can't create socket" },
+ { KNOT_NET_ECONNECT, "can't connect" },
+ { KNOT_NET_ESEND, "can't send data" },
+ { KNOT_NET_ERECV, "can't receive data" },
+ { KNOT_NET_ETIMEOUT, "network timeout" },
+
+ /* Encoding errors. */
+ { KNOT_BASE64_ESIZE, "invalid base64 string length" },
+ { KNOT_BASE64_ECHAR, "invalid base64 character" },
+ { KNOT_BASE32HEX_ESIZE, "invalid base32hex string length" },
+ { KNOT_BASE32HEX_ECHAR, "invalid base32hex character" },
+
+ /* TSIG errors. */
+ { KNOT_TSIG_EBADSIG, "failed to verify TSIG" },
+ { KNOT_TSIG_EBADKEY, "TSIG key not recognized or invalid" },
+ { KNOT_TSIG_EBADTIME, "TSIG out of time window" },
+ { KNOT_TSIG_EBADTRUNC, "TSIG bad truncation" },
+
+ /* DNSSEC errors. */
+ { KNOT_DNSSEC_ENOKEY, "no keys for signing" },
+ { KNOT_DNSSEC_EMISSINGKEYTYPE, "missing active KSK or ZSK" },
+ { KNOT_DNSSEC_ENOSIG, "no valid signature for a record" },
+ { KNOT_DNSSEC_ENONSEC, "missing NSEC(3) record" },
+ { KNOT_DNSSEC_ENSEC_BITMAP, "wrong NSEC(3) bitmap" },
+ { KNOT_DNSSEC_ENSEC_CHAIN, "inconsistent NSEC(3) chain" },
+ { KNOT_DNSSEC_ENSEC3_OPTOUT, "wrong NSEC3 opt-out" },
+
+ /* Yparser errors. */
+ { KNOT_YP_ECHAR_TAB, "tabulator character is not allowed" },
+ { KNOT_YP_EINVAL_ITEM, "invalid item" },
+ { KNOT_YP_EINVAL_ID, "invalid identifier" },
+ { KNOT_YP_EINVAL_DATA, "invalid value" },
+ { KNOT_YP_EINVAL_INDENT, "invalid indentation" },
+ { KNOT_YP_ENOTSUP_DATA, "value not supported" },
+ { KNOT_YP_ENOTSUP_ID, "identifier not supported" },
+ { KNOT_YP_ENODATA, "missing value" },
+ { KNOT_YP_ENOID, "missing identifier" },
+
+ /* Configuration errors. */
+ { KNOT_CONF_ENOTINIT, "config DB not initialized" },
+ { KNOT_CONF_EVERSION, "invalid config DB version" },
+ { KNOT_CONF_EREDEFINE, "duplicate identifier" },
+
+ /* Transaction errors. */
+ { KNOT_TXN_EEXISTS, "too many transactions" },
+ { KNOT_TXN_ENOTEXISTS, "no active transaction" },
+
+ /* DNSSEC errors. */
+ { KNOT_INVALID_PUBLIC_KEY, "invalid public key" },
+ { KNOT_INVALID_PRIVATE_KEY, "invalid private key" },
+ { KNOT_INVALID_KEY_ALGORITHM, "invalid key algorithm" },
+ { KNOT_INVALID_KEY_SIZE, "invalid key size" },
+ { KNOT_INVALID_KEY_ID, "invalid key ID" },
+ { KNOT_INVALID_KEY_NAME, "invalid key name" },
+ { KNOT_NO_PUBLIC_KEY, "no public key" },
+ { KNOT_NO_PRIVATE_KEY, "no private key" },
+ { KNOT_NO_READY_KEY, "no key ready for submission" },
+
+ /* Terminator */
+ { KNOT_ERROR, NULL }
+};
+
+/*!
+ * \brief Lookup error message by error code.
+ */
+static const char *lookup_message(int code)
+{
+ for (const struct error *e = errors; e->message; e++) {
+ if (e->code == code) {
+ return e->message;
+ }
+ }
+
+ return NULL;
+}
+
+_public_
+int knot_error_from_libdnssec(int libdnssec_errcode)
+{
+ switch (libdnssec_errcode) {
+ case DNSSEC_ERROR:
+ return KNOT_ERROR;
+ case DNSSEC_MALFORMED_DATA:
+ return KNOT_EMALF;
+ case DNSSEC_NOT_FOUND:
+ return KNOT_ENOENT;
+ case DNSSEC_NO_PUBLIC_KEY:
+ case DNSSEC_NO_PRIVATE_KEY:
+ return KNOT_DNSSEC_ENOKEY;
+ // EOK, EINVAL, ENOMEM and ENOENT are identical, no need to translate
+ case DNSSEC_INVALID_PUBLIC_KEY ... DNSSEC_INVALID_KEY_NAME:
+ return libdnssec_errcode
+ - DNSSEC_INVALID_PUBLIC_KEY + KNOT_INVALID_PUBLIC_KEY;
+ default:
+ return libdnssec_errcode;
+ }
+}
+
+_public_
+const char *knot_strerror(int code)
+{
+ const char *msg;
+
+ switch (code) {
+ case INT_MIN: // Cannot convert to a positive value.
+ code = KNOT_ERROR;
+ // FALLTHROUGH
+ case KNOT_ERROR_MIN ... KNOT_EOK:
+ msg = lookup_message(code); break;
+ case DNSSEC_ERROR_MIN ... DNSSEC_ERROR_MAX:
+ msg = dnssec_strerror(code); break;
+ case MDB_KEYEXIST ... MDB_LAST_ERRCODE:
+ msg = mdb_strerror(code); break;
+ default:
+ msg = NULL;
+ }
+
+ if (msg != NULL) {
+ return msg;
+ } else {
+ // strerror_r would be better but it requires thread local storage.
+ return strerror(abs(code));
+ }
+}