From: Libor Peltan Date: Mon, 27 Oct 2025 16:17:24 +0000 (+0100) Subject: libknot/rrset-dump/bugfix: ERANGE instead of enlarging output buffer if overflow... X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=245ea349813fbf077a63acb6c61e933bde40ea26;p=thirdparty%2Fknot-dns.git libknot/rrset-dump/bugfix: ERANGE instead of enlarging output buffer if overflow inside base64_encode --- diff --git a/Knot.files b/Knot.files index e2065759cd..437b96ed23 100644 --- a/Knot.files +++ b/Knot.files @@ -743,6 +743,7 @@ tests/libknot/test_pkt.c tests/libknot/test_probe.c tests/libknot/test_rdata.c tests/libknot/test_rdataset.c +tests/libknot/test_rrset-dump.c tests/libknot/test_rrset-wire.c tests/libknot/test_rrset.c tests/libknot/test_tsig.c diff --git a/src/contrib/base32hex.c b/src/contrib/base32hex.c index 8a7d7dc43f..6affc9180a 100644 --- a/src/contrib/base32hex.c +++ b/src/contrib/base32hex.c @@ -78,9 +78,12 @@ int32_t knot_base32hex_encode(const uint8_t *in, if (in == NULL || out == NULL) { return KNOT_EINVAL; } - if (in_len > MAX_B32_BIN_DATA_LEN || out_len < ((in_len + 4) / 5) * 8) { + if (in_len > MAX_B32_BIN_DATA_LEN) { return KNOT_ERANGE; } + if (out_len < ((in_len + 4) / 5) * 8) { + return KNOT_ESPACE; // NOTE it is essential to return KNOT_ESPACE when output buffer overflows because this is directly called in rrset_dump and there is a realloc/retry mechanism in KNOT_ESPACE case. + } uint8_t rest_len = in_len % 5; const uint8_t *stop = in + in_len - rest_len; @@ -191,9 +194,12 @@ int32_t knot_base32hex_decode(const uint8_t *in, if (in == NULL || out == NULL) { return KNOT_EINVAL; } - if (in_len > INT32_MAX || out_len < ((in_len + 7) / 8) * 5) { + if (in_len > INT32_MAX) { return KNOT_ERANGE; } + if (out_len < ((in_len + 7) / 8) * 5) { + return KNOT_ESPACE; + } if ((in_len % 8) != 0) { return KNOT_BASE32HEX_ESIZE; } diff --git a/src/contrib/base32hex.h b/src/contrib/base32hex.h index c5a81a58af..5a907b9b2a 100644 --- a/src/contrib/base32hex.h +++ b/src/contrib/base32hex.h @@ -26,7 +26,8 @@ * \param out_len Size of output buffer. * * \retval >=0 length of output string. - * \retval KNOT_E* if error. + * \retval KNOT_ESPACE if output buffer is not large enough. + * \return KNOT_E* if other error. */ int32_t knot_base32hex_encode(const uint8_t *in, const uint32_t in_len, @@ -65,7 +66,8 @@ int32_t knot_base32hex_encode_alloc(const uint8_t *in, * \param out_len Size of output buffer. * * \retval >=0 length of output data. - * \retval KNOT_E* if error. + * \retval KNOT_ESPACE if output buffer is not large enough. + * \return KNOT_E* if other error. */ int32_t knot_base32hex_decode(const uint8_t *in, const uint32_t in_len, diff --git a/src/contrib/base64.c b/src/contrib/base64.c index ed123fec7b..a878731878 100644 --- a/src/contrib/base64.c +++ b/src/contrib/base64.c @@ -79,9 +79,12 @@ int32_t knot_base64_encode(const uint8_t *in, if (in == NULL || out == NULL) { return KNOT_EINVAL; } - if (in_len > MAX_B64_BIN_DATA_LEN || out_len < ((in_len + 2) / 3) * 4) { + if (in_len > MAX_B64_BIN_DATA_LEN) { return KNOT_ERANGE; } + if (out_len < ((in_len + 2) / 3) * 4) { + return KNOT_ESPACE; // NOTE it is essential to return KNOT_ESPACE when output buffer overflows because this is directly called in rrset_dump and there is a realloc/retry mechanism in KNOT_ESPACE case. + } uint8_t rest_len = in_len % 3; const uint8_t *stop = in + in_len - rest_len; @@ -158,9 +161,12 @@ int32_t knot_base64_decode(const uint8_t *in, if (in == NULL || out == NULL) { return KNOT_EINVAL; } - if (in_len > INT32_MAX || out_len < ((in_len + 3) / 4) * 3) { + if (in_len > INT32_MAX) { return KNOT_ERANGE; } + if (out_len < ((in_len + 3) / 4) * 3) { + return KNOT_ESPACE; + } if ((in_len % 4) != 0) { return KNOT_BASE64_ESIZE; } diff --git a/src/contrib/base64.h b/src/contrib/base64.h index f512dba075..c6bc79796f 100644 --- a/src/contrib/base64.h +++ b/src/contrib/base64.h @@ -23,7 +23,8 @@ * \param out_len Size of output buffer. * * \retval >=0 length of output string. - * \retval KNOT_E* if error. + * \retval KNOT_ESPACE if output buffer is not large enough. + * \return KNOT_E* if other error. */ int32_t knot_base64_encode(const uint8_t *in, const uint32_t in_len, @@ -62,7 +63,8 @@ int32_t knot_base64_encode_alloc(const uint8_t *in, * \param out_len Size of output buffer. * * \retval >=0 length of output data. - * \retval KNOT_E* if error. + * \retval KNOT_ESPACE if output buffer is not large enough. + * \return KNOT_E* if other error. */ int32_t knot_base64_decode(const uint8_t *in, const uint32_t in_len, diff --git a/src/contrib/base64url.c b/src/contrib/base64url.c index 38c8fd9c04..64bf1bcb63 100644 --- a/src/contrib/base64url.c +++ b/src/contrib/base64url.c @@ -80,9 +80,12 @@ int32_t knot_base64url_encode(const uint8_t *in, if (in == NULL || out == NULL) { return KNOT_EINVAL; } - if (in_len > MAX_BIN_DATA_LEN || out_len < ((in_len + 2) / 3) * 4) { + if (in_len > MAX_BIN_DATA_LEN) { return KNOT_ERANGE; } + if (out_len < ((in_len + 2) / 3) * 4) { + return KNOT_ESPACE; + } uint8_t rest_len = in_len % 3; const uint8_t *stop = in + in_len - rest_len; @@ -170,9 +173,12 @@ int32_t knot_base64url_decode(const uint8_t *in, } } - if (in_len > INT32_MAX || out_len < ((in_len + 3) / 4) * 3) { + if (in_len > INT32_MAX) { return KNOT_ERANGE; } + if (out_len < ((in_len + 3) / 4) * 3) { + return KNOT_ESPACE; + } const uint8_t *stop = in + in_len; uint8_t *bin = out; diff --git a/src/contrib/base64url.h b/src/contrib/base64url.h index 43c27c355b..07f8e617ad 100644 --- a/src/contrib/base64url.h +++ b/src/contrib/base64url.h @@ -23,7 +23,8 @@ * \param out_len Size of output buffer. * * \retval >=0 length of output string. - * \retval KNOT_E* if error. + * \retval KNOT_ESPACE if output buffer is not large enough. + * \return KNOT_E* if other error. */ int32_t knot_base64url_encode(const uint8_t *in, const uint32_t in_len, @@ -62,7 +63,8 @@ int32_t knot_base64url_encode_alloc(const uint8_t *in, * \param out_len Size of output buffer. * * \retval >=0 length of output data. - * \retval KNOT_E* if error. + * \retval KNOT_ESPACE if output buffer is not large enough. + * \return KNOT_E* if other error. */ int32_t knot_base64url_decode(const uint8_t *in, uint32_t in_len, diff --git a/src/libknot/descriptor.c b/src/libknot/descriptor.c index dcd0eda264..441e45a953 100644 --- a/src/libknot/descriptor.c +++ b/src/libknot/descriptor.c @@ -9,6 +9,7 @@ #include "libknot/attribute.h" #include "libknot/descriptor.h" +#include "libknot/errcode.h" /*! * \brief Table with supported DNS classes. @@ -197,7 +198,7 @@ int knot_rrtype_to_string(const uint16_t rrtype, const size_t out_len) { if (out == NULL) { - return -1; + return KNOT_EINVAL; } int ret; @@ -211,7 +212,7 @@ int knot_rrtype_to_string(const uint16_t rrtype, } if (ret <= 0 || (size_t)ret >= out_len) { - return -1; + return KNOT_ESPACE; // NOTE it is essential to return KNOT_ESPACE when output buffer overflows because this is directly called in rrset_dump and there is a realloc/retry mechanism in KNOT_ESPACE case. } else { return ret; } @@ -221,7 +222,7 @@ _public_ int knot_rrtype_from_string(const char *name, uint16_t *num) { if (name == NULL || num == NULL) { - return -1; + return KNOT_EINVAL; } int i; @@ -233,13 +234,13 @@ int knot_rrtype_from_string(const char *name, uint16_t *num) if (rdata_descriptors[i].type_name != NULL && strcasecmp(rdata_descriptors[i].type_name, name) == 0) { *num = i; - return 0; + return KNOT_EOK; } } // Type name must begin with TYPE. if (strncasecmp(name, "TYPE", 4) != 0) { - return -1; + return KNOT_ENOTYPE; } else { name += 4; } @@ -247,11 +248,11 @@ int knot_rrtype_from_string(const char *name, uint16_t *num) // The rest must be a number. n = strtoul(name, &end, 10); if (end == name || *end != '\0' || n > UINT16_MAX) { - return -1; + return KNOT_ENOTYPE; } *num = n; - return 0; + return KNOT_EOK; } _public_ @@ -260,7 +261,7 @@ int knot_rrclass_to_string(const uint16_t rrclass, const size_t out_len) { if (out == NULL) { - return -1; + return KNOT_EINVAL; } int ret; @@ -272,7 +273,7 @@ int knot_rrclass_to_string(const uint16_t rrclass, } if (ret <= 0 || (size_t)ret >= out_len) { - return -1; + return KNOT_ESPACE; } else { return ret; } @@ -282,7 +283,7 @@ _public_ int knot_rrclass_from_string(const char *name, uint16_t *num) { if (name == NULL || num == NULL) { - return -1; + return KNOT_EINVAL; } int i; @@ -295,13 +296,13 @@ int knot_rrclass_from_string(const char *name, uint16_t *num) if ((row[0] != NULL && strcasecmp(row[0], name) == 0) || (row[1] != NULL && strcasecmp(row[1], name) == 0)) { *num = i; - return 0; + return KNOT_EOK; } } // Class name must begin with CLASS. if (strncasecmp(name, "CLASS", 5) != 0) { - return -1; + return KNOT_ENOCLASS; } else { name += 5; } @@ -309,11 +310,11 @@ int knot_rrclass_from_string(const char *name, uint16_t *num) // The rest must be a number. n = strtoul(name, &end, 10); if (end == name || *end != '\0' || n > UINT16_MAX) { - return -1; + return KNOT_ENOCLASS; } *num = n; - return 0; + return KNOT_EOK; } _public_ @@ -382,7 +383,7 @@ _public_ int knot_opt_code_to_string(const uint16_t code, char *out, const size_t out_len) { if (out == NULL) { - return -1; + return KNOT_EINVAL; } const char *name = NULL; @@ -412,7 +413,7 @@ int knot_opt_code_to_string(const uint16_t code, char *out, const size_t out_len } if (ret <= 0 || (size_t)ret >= out_len) { - return -1; + return KNOT_ESPACE; } else { return ret; } diff --git a/src/libknot/descriptor.h b/src/libknot/descriptor.h index d4644a04b2..bd8a695525 100644 --- a/src/libknot/descriptor.h +++ b/src/libknot/descriptor.h @@ -196,7 +196,8 @@ const knot_rdata_descriptor_t *knot_get_obsolete_rdata_descriptor(const uint16_t * \param out_len Length of the output buffer. * * \retval Length of output string. - * \retval -1 if error. + * \retval KNOT_ESPACE if output buffer not large enough. + * \return KNOT_E* if other error. */ int knot_rrtype_to_string(const uint16_t rrtype, char *out, @@ -208,8 +209,7 @@ int knot_rrtype_to_string(const uint16_t rrtype, * \param name Mnemonic string to be converted. * \param num Output variable. * - * \retval 0 if OK. - * \retval -1 if error. + * \return KNOT_E* */ int knot_rrtype_from_string(const char *name, uint16_t *num); @@ -221,7 +221,8 @@ int knot_rrtype_from_string(const char *name, uint16_t *num); * \param out_len Length of the output buffer. * * \retval Length of output string. - * \retval -1 if error. + * \retval KNOT_ESPACE if output buffer not large enough. + * \return KNOT_E* if other error. */ int knot_rrclass_to_string(const uint16_t rrclass, char *out, @@ -233,8 +234,7 @@ int knot_rrclass_to_string(const uint16_t rrclass, * \param name Mnemonic string to be converted. * \param num Output variable. * - * \retval 0 if OK. - * \retval -1 if error. + * \return KNOT_E* */ int knot_rrclass_from_string(const char *name, uint16_t *num); @@ -292,7 +292,8 @@ bool knot_rrtype_should_be_lowercased(const uint16_t type); * \param out_len The available size of the buffer. * * \retval Length of output string. - * \retval -1 if error. + * \retval KNOT_ESPACE if output buffer not large enough. + * \return KNOT_E* if other error. */ int knot_opt_code_to_string(const uint16_t code, char *out, const size_t out_len); diff --git a/src/libknot/errcode.h b/src/libknot/errcode.h index afa69f0999..fe3a2dab88 100644 --- a/src/libknot/errcode.h +++ b/src/libknot/errcode.h @@ -102,6 +102,8 @@ enum knot_error { KNOT_EMODINVAL, KNOT_EEXTERNAL, KNOT_ERDB, + KNOT_ENOTYPE, + KNOT_ENOCLASS, KNOT_GENERAL_ERROR = -900, diff --git a/src/libknot/error.c b/src/libknot/error.c index a2b3e213f1..c6e32b104c 100644 --- a/src/libknot/error.c +++ b/src/libknot/error.c @@ -100,6 +100,8 @@ static const struct error errors[] = { { KNOT_EMODINVAL, "invalid module" }, { KNOT_EEXTERNAL, "external validation failed" }, { KNOT_ERDB, "zone database error" }, + { KNOT_ENOTYPE, "no such RR type" }, + { KNOT_ENOCLASS, "no such CLASS" }, { KNOT_GENERAL_ERROR, "unknown general error" }, diff --git a/tests/.gitignore b/tests/.gitignore index a553a648a4..123430fc01 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -79,6 +79,7 @@ /libknot/test_rdata /libknot/test_rdataset /libknot/test_rrset +/libknot/test_rrset-dump /libknot/test_rrset-wire /libknot/test_tsig /libknot/test_xdp_tcp diff --git a/tests/Makefile.am b/tests/Makefile.am index 6e662272d8..e39d9eafdd 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -147,6 +147,7 @@ check_PROGRAMS += \ libknot/test_rdata \ libknot/test_rdataset \ libknot/test_rrset \ + libknot/test_rrset-dump \ libknot/test_rrset-wire \ libknot/test_tsig \ libknot/test_yparser \ diff --git a/tests/contrib/test_base32hex.c b/tests/contrib/test_base32hex.c index 6ad468826e..492ff2902a 100644 --- a/tests/contrib/test_base32hex.c +++ b/tests/contrib/test_base32hex.c @@ -31,7 +31,7 @@ int main(int argc, char *argv[]) ret = knot_base32hex_encode(in, MAX_BIN_DATA_LEN + 1, out, BUF_LEN); is_int(KNOT_ERANGE, ret, "knot_base32hex_encode: input buffer too large"); ret = knot_base32hex_encode(in, BUF_LEN, out, BUF_LEN); - is_int(KNOT_ERANGE, ret, "knot_base32hex_encode: output buffer too small"); + is_int(KNOT_ESPACE, ret, "knot_base32hex_encode: output buffer too small"); ret = knot_base32hex_encode_alloc(NULL, 0, &out3); is_int(KNOT_EINVAL, ret, "knot_base32hex_encode_alloc: NULL input buffer"); @@ -47,7 +47,7 @@ int main(int argc, char *argv[]) ret = knot_base32hex_decode(in, UINT32_MAX, out, BUF_LEN); is_int(KNOT_ERANGE, ret, "knot_base32hex_decode: input buffer too large"); ret = knot_base32hex_decode(in, BUF_LEN, out, 0); - is_int(KNOT_ERANGE, ret, "knot_base32hex_decode: output buffer too small"); + is_int(KNOT_ESPACE, ret, "knot_base32hex_decode: output buffer too small"); ret = knot_base32hex_decode_alloc(NULL, 0, &out3); is_int(KNOT_EINVAL, ret, "knot_base32hex_decode_alloc: NULL input buffer"); diff --git a/tests/contrib/test_base64.c b/tests/contrib/test_base64.c index e6eb72499c..83dc72a248 100644 --- a/tests/contrib/test_base64.c +++ b/tests/contrib/test_base64.c @@ -31,7 +31,7 @@ int main(int argc, char *argv[]) ret = knot_base64_encode(in, MAX_BIN_DATA_LEN + 1, out, BUF_LEN); is_int(KNOT_ERANGE, ret, "knot_base64_encode: input buffer too large"); ret = knot_base64_encode(in, BUF_LEN, out, BUF_LEN); - is_int(KNOT_ERANGE, ret, "knot_base64_encode: output buffer too small"); + is_int(KNOT_ESPACE, ret, "knot_base64_encode: output buffer too small"); ret = knot_base64_encode_alloc(NULL, 0, &out3); is_int(KNOT_EINVAL, ret, "knot_base64_encode_alloc: NULL input buffer"); @@ -47,7 +47,7 @@ int main(int argc, char *argv[]) ret = knot_base64_decode(in, UINT32_MAX, out, BUF_LEN); is_int(KNOT_ERANGE, ret, "knot_base64_decode: input buffer too large"); ret = knot_base64_decode(in, BUF_LEN, out, 0); - is_int(KNOT_ERANGE, ret, "knot_base64_decode: output buffer too small"); + is_int(KNOT_ESPACE, ret, "knot_base64_decode: output buffer too small"); ret = knot_base64_decode_alloc(NULL, 0, &out3); is_int(KNOT_EINVAL, ret, "knot_base64_decode_alloc: NULL input buffer"); diff --git a/tests/contrib/test_base64url.c b/tests/contrib/test_base64url.c index 458c4e7503..4540ae568e 100644 --- a/tests/contrib/test_base64url.c +++ b/tests/contrib/test_base64url.c @@ -31,7 +31,7 @@ int main(int argc, char *argv[]) ret = knot_base64url_encode(in, MAX_BIN_DATA_LEN + 1, out, BUF_LEN); is_int(KNOT_ERANGE, ret, "knot_base64ulr_encode: input buffer too large"); ret = knot_base64url_encode(in, BUF_LEN, out, BUF_LEN); - is_int(KNOT_ERANGE, ret, "knot_base64ulr_encode: output buffer too small"); + is_int(KNOT_ESPACE, ret, "knot_base64ulr_encode: output buffer too small"); ret = knot_base64url_encode_alloc(NULL, 0, &out3); is_int(KNOT_EINVAL, ret, "knot_base64ulr_encode_alloc: NULL input buffer"); @@ -45,7 +45,7 @@ int main(int argc, char *argv[]) ret = knot_base64url_decode(in, BUF_LEN, NULL, 0); is_int(KNOT_EINVAL, ret, "knot_base64ulr_decode: NULL output buffer"); ret = knot_base64url_decode(in, BUF_LEN, out, 0); - is_int(KNOT_ERANGE, ret, "knot_base64ulr_decode: output buffer too small"); + is_int(KNOT_ESPACE, ret, "knot_base64ulr_decode: output buffer too small"); ret = knot_base64url_decode_alloc(NULL, 0, &out3); is_int(KNOT_EINVAL, ret, "knot_base64ulr_decode_alloc: NULL input buffer"); diff --git a/tests/libknot/test_descriptor.c b/tests/libknot/test_descriptor.c index 7c10fd63fa..d04bc4b8ce 100644 --- a/tests/libknot/test_descriptor.c +++ b/tests/libknot/test_descriptor.c @@ -9,6 +9,7 @@ #include #include "libknot/descriptor.h" +#include "libknot/errcode.h" #define BUF_LEN 256 @@ -31,7 +32,7 @@ int main(int argc, char *argv[]) "get TYPE0 descriptor 2. item type"); ret = knot_rrtype_to_string(0, name, BUF_LEN); - ok(ret != -1, "get TYPE0 ret"); + ok(ret > 0, "get TYPE0 ret"); ok(strcmp(name, "TYPE0") == 0, "get TYPE0 name"); // 2. A @@ -43,7 +44,7 @@ int main(int argc, char *argv[]) "get A descriptor 2. item type"); ret = knot_rrtype_to_string(1, name, BUF_LEN); - ok(ret != -1, "get A ret"); + ok(ret > 0, "get A ret"); ok(strcmp(name, "A") == 0, "get A name"); // 3. CNAME @@ -55,7 +56,7 @@ int main(int argc, char *argv[]) "get CNAME descriptor 2. item type"); ret = knot_rrtype_to_string(5, name, BUF_LEN); - ok(ret != -1, "get CNAME ret"); + ok(ret > 0, "get CNAME ret"); ok(strcmp(name, "CNAME") == 0, "get CNAME name"); // 4. TYPE38 (A6) @@ -67,7 +68,7 @@ int main(int argc, char *argv[]) "get TYPE38 descriptor 2. item type"); ret = knot_rrtype_to_string(38, name, BUF_LEN); - ok(ret != -1, "get TYPE38 ret"); + ok(ret > 0, "get TYPE38 ret"); ok(strcmp(name, "TYPE38") == 0, "get TYPE38 name"); // 5. ANY @@ -79,7 +80,7 @@ int main(int argc, char *argv[]) "get ANY descriptor 2. item type"); ret = knot_rrtype_to_string(255, name, BUF_LEN); - ok(ret != -1, "get ANY ret"); + ok(ret > 0, "get ANY ret"); ok(strcmp(name, "ANY") == 0, "get ANY name"); // 6. TYPE65535 @@ -91,121 +92,121 @@ int main(int argc, char *argv[]) "get TYPE65535 descriptor 2. item type"); ret = knot_rrtype_to_string(65535, name, BUF_LEN); - ok(ret != -1, "get TYPE65535 ret"); + ok(ret > 0, "get TYPE65535 ret"); ok(strcmp(name, "TYPE65535") == 0, "get TYPE65535 name"); // Class num to string: // 7. CLASS0 ret = knot_rrclass_to_string(0, name, BUF_LEN); - ok(ret != -1, "get CLASS0 ret"); + ok(ret > 0, "get CLASS0 ret"); ok(strcmp(name, "CLASS0") == 0, "get CLASS0 name"); // 8. IN ret = knot_rrclass_to_string(1, name, BUF_LEN); - ok(ret != -1, "get IN ret"); + ok(ret > 0, "get IN ret"); ok(strcmp(name, "IN") == 0, "get IN name"); // 9. ANY ret = knot_rrclass_to_string(255, name, BUF_LEN); - ok(ret != -1, "get ANY ret"); + ok(ret > 0, "get ANY ret"); ok(strcmp(name, "ANY") == 0, "get ANY name"); // 10. CLASS65535 ret = knot_rrclass_to_string(65535, name, BUF_LEN); - ok(ret != -1, "get CLASS65535 ret"); + ok(ret > 0, "get CLASS65535 ret"); ok(strcmp(name, "CLASS65535") == 0, "get CLASS65535 name"); // String to type num: // 11. A ret = knot_rrtype_from_string("A", &num); - ok(ret != -1, "get A num ret"); + ok(ret == KNOT_EOK, "get A num ret"); ok(num == 1, "get A num"); // 12. a ret = knot_rrtype_from_string("a", &num); - ok(ret != -1, "get a num ret"); + ok(ret == KNOT_EOK, "get a num ret"); ok(num == 1, "get a num"); // 13. AaAa ret = knot_rrtype_from_string("AaAa", &num); - ok(ret != -1, "get AaAa num ret"); + ok(ret == KNOT_EOK, "get AaAa num ret"); ok(num == 28, "get AaAa num"); // 14. "" ret = knot_rrtype_from_string("", &num); - ok(ret == -1, "get "" num ret"); + ok(ret == KNOT_ENOTYPE, "get "" num ret"); // 15. DUMMY ret = knot_rrtype_from_string("DUMMY", &num); - ok(ret == -1, "get DUMMY num ret"); + ok(ret == KNOT_ENOTYPE, "get DUMMY num ret"); // 16. TypE33 ret = knot_rrtype_from_string("TypE33", &num); - ok(ret != -1, "get TypE33 num ret"); + ok(ret == KNOT_EOK, "get TypE33 num ret"); ok(num == 33, "get TypE33 num"); // 17. TYPE ret = knot_rrtype_from_string("TYPE", &num); - ok(ret == -1, "get TYPE num ret"); + ok(ret == KNOT_ENOTYPE, "get TYPE num ret"); // 18. TYPE0 ret = knot_rrtype_from_string("TYPE0", &num); - ok(ret != -1, "get TYPE0 num ret"); + ok(ret == KNOT_EOK, "get TYPE0 num ret"); ok(num == 0, "get TYPE0 num"); // 19. TYPE65535 ret = knot_rrtype_from_string("TYPE65535", &num); - ok(ret != -1, "get TYPE65535 num ret"); + ok(ret == KNOT_EOK, "get TYPE65535 num ret"); ok(num == 65535, "get TYPE65535 num"); // 20. TYPE65536 ret = knot_rrtype_from_string("TYPE65536", &num); - ok(ret == -1, "get TYPE65536 num ret"); + ok(ret == KNOT_ENOTYPE, "get TYPE65536 num ret"); // String to class num: // 21. In ret = knot_rrclass_from_string("In", &num); - ok(ret != -1, "get In num ret"); + ok(ret == KNOT_EOK, "get In num ret"); ok(num == 1, "get In num"); ret = knot_rrclass_from_string("Internet", &num); - ok(ret != -1, "get In num ret"); + ok(ret == KNOT_EOK, "get In num ret"); ok(num == 1, "get In num"); // 22. ANY ret = knot_rrclass_from_string("ANY", &num); - ok(ret != -1, "get ANY num ret"); + ok(ret == KNOT_EOK, "get ANY num ret"); ok(num == 255, "get ANY num"); // 23. "" ret = knot_rrclass_from_string("", &num); - ok(ret == -1, "get "" num ret"); + ok(ret == KNOT_ENOCLASS, "get "" num ret"); // 24. DUMMY ret = knot_rrclass_from_string("DUMMY", &num); - ok(ret == -1, "get DUMMY num ret"); + ok(ret == KNOT_ENOCLASS, "get DUMMY num ret"); // 25. CLass33 ret = knot_rrclass_from_string("CLass33", &num); - ok(ret != -1, "get CLass33 num ret"); + ok(ret == KNOT_EOK, "get CLass33 num ret"); ok(num == 33, "get CLass33 num"); // 26. CLASS ret = knot_rrclass_from_string("CLASS", &num); - ok(ret == -1, "get CLASS num ret"); + ok(ret == KNOT_ENOCLASS, "get CLASS num ret"); // 27. CLASS0 ret = knot_rrclass_from_string("CLASS0", &num); - ok(ret != -1, "get CLASS0 num ret"); + ok(ret == KNOT_EOK, "get CLASS0 num ret"); ok(num == 0, "get CLASS0 num"); // 28. CLASS65535 ret = knot_rrclass_from_string("CLASS65535", &num); - ok(ret != -1, "get CLASS65535 num ret"); + ok(ret == KNOT_EOK, "get CLASS65535 num ret"); ok(num == 65535, "get CLASS65535 num"); // 29. CLASS65536 ret = knot_rrclass_from_string("CLASS65536", &num); - ok(ret == -1, "get CLASS65536 num ret"); + ok(ret == KNOT_ENOCLASS, "get CLASS65536 num ret"); // Get obsolete descriptor: // 30. TYPE0 @@ -242,13 +243,22 @@ int main(int argc, char *argv[]) ok(descr->block_types[1] == KNOT_RDATA_WF_END, "get TYPE38 descriptor 2. item type"); - // knot_rrtype_to_string invalid output buffer size + // knot_rrtype_to_string NULL output buffer ret = knot_rrtype_to_string(1, NULL, 0); - ok(ret == -1, "knot_rrtype_to_string: invalid output buffer size"); + ok(ret == KNOT_EINVAL, "knot_rrtype_to_string: NULL output buffer"); - // knot_rrclass_to_string invalid output buffer size + // knot_rrclass_to_string NULL output buffer ret = knot_rrclass_to_string(1, NULL, 0); - ok(ret == -1, "knot_rrclass_to_string: invalid output buffer size"); + ok(ret == KNOT_EINVAL, "knot_rrclass_to_string: NULL output buffer"); + + char dummy_buf[1] = { 0 }; + // knot_rrtype_to_string invalid output buffer size + ret = knot_rrtype_to_string(1, dummy_buf, 1); + ok(ret == KNOT_ESPACE, "knot_rrtype_to_string: invalid output buffer size"); + + // knot_rrclass_to_string invalid output buffer size + ret = knot_rrclass_to_string(1, dummy_buf, 1); + ok(ret == KNOT_ESPACE, "knot_rrclass_to_string: invalid output buffer size"); // knot_rrtype_is_metatype ok(knot_rrtype_is_metatype(0) == 0, diff --git a/tests/libknot/test_rrset-dump.c b/tests/libknot/test_rrset-dump.c new file mode 100644 index 0000000000..216fae5173 --- /dev/null +++ b/tests/libknot/test_rrset-dump.c @@ -0,0 +1,80 @@ +/* Copyright (C) CZ.NIC, z.s.p.o. and contributors + * SPDX-License-Identifier: GPL-2.0-or-later + * For more information, see + */ + +#include + +#include +#include +#include +#include + +#include "libknot/rrset-dump.h" + +/* BACKGROUND: + * + * This unit test could be used for testing rrset-dump with newly implemented RR types. + * But so far, the functional test records/load is used for this purpose. + * This unit test ought to catch different quirks of knot_rrset_txt_dump, + * like re-allocating the given output buffer based on errcode (KNOT_ESPACE). + */ + +const knot_dump_style_t *dump_style = &KNOT_DUMP_STYLE_DEFAULT; + +typedef struct { + const char *description; + knot_rrset_t rrset; + const char *expect_out; + int expect_ret; + size_t buf_sizes[8]; +} rrset_dump_test_case_t; + +const char * const rrsig_case_text = "test. \t1234567890\tRRSIG\tDNSKEY 13 1 1234567890 20251015085855 20251015063355 33658 test. uj40mBZYSg21VqhF7AcU6CTp3dM2k8G/Br8ZP902OCrsDjRq3qPZySxYwmcnbNYeAdVyT1m2zLmKZbYa8cCqRA==\n"; + +knot_rdata_t rrsig_case_rdata = { + 88, { 0x00, 0x30, 0x0d, 0x01, 0x49, 0x96, 0x02, 0xd2, 0x68, 0xef, 0x62, 0x4f, 0x68, 0xef, 0x40, 0x53, 0x83, 0x7a, 0x04, 0x74, 0x65, 0x73, 0x74, 0x00, + 0xba, 0x3e, 0x34, 0x98, 0x16, 0x58, 0x4a, 0x0d, 0xb5, 0x56, 0xa8, 0x45, 0xec, 0x07, 0x14, 0xe8, 0x24, 0xe9, 0xdd, 0xd3, 0x36, 0x93, 0xc1, 0xbf, 0x06, 0xbf, 0x19, 0x3f, 0xdd, 0x36, 0x38, 0x2a, + 0xec, 0x0e, 0x34, 0x6a, 0xde, 0xa3, 0xd9, 0xc9, 0x2c, 0x58, 0xc2, 0x67, 0x27, 0x6c, 0xd6, 0x1e, 0x01, 0xd5, 0x72, 0x4f, 0x59, 0xb6, 0xcc, 0xb9, 0x8a, 0x65, 0xb6, 0x1a, 0xf1, 0xc0, 0xaa, 0x44 + } +}; + +rrset_dump_test_case_t rrset_dump_test_cases[] = { + { "some RRSIG", { (knot_dname_t *)"\x04""test", 1234567890U, KNOT_RRTYPE_RRSIG, KNOT_CLASS_IN, { 1, 90, &rrsig_case_rdata }, NULL }, rrsig_case_text, KNOT_EOK, { 1, 3, 5, 7, 9, 11 } }, +}; + +void test_rrset_dump(const char *description, const knot_rrset_t *rrset, const char *expect_out, int expect_ret, size_t initial_buf) +{ + size_t bufsize = initial_buf; + char *buf = calloc(1, initial_buf); + assert(buf != NULL); + + if (expect_ret == KNOT_EOK) { + expect_ret = strlen(expect_out); + } + + int ret = knot_rrset_txt_dump(rrset, &buf, &bufsize, dump_style); + ok(ret == expect_ret, "%s (init buf %zu): return code %d found %d", description, initial_buf, expect_ret, ret); + + if (expect_out != NULL) { + ok(strcmp(buf, expect_out) == 0, "%s (init buf %zu): output string '%s' found '%s'", description, initial_buf, expect_out, buf); + } + + free(buf); +} + +int main(int argc, char *argv[]) +{ + plan_lazy(); + + for (size_t i = 0; i < sizeof(rrset_dump_test_cases) / sizeof(*rrset_dump_test_cases); i++) { + rrset_dump_test_case_t *c = &rrset_dump_test_cases[i]; + for (size_t j = 0; j < sizeof(c->buf_sizes) / sizeof(*c->buf_sizes); j++) { + if (c->buf_sizes[j] > 0) { + test_rrset_dump(c->description, &c->rrset, c->expect_out, c->expect_ret, c->buf_sizes[j]); + } + } + } + + return 0; +}