aboutsummaryrefslogtreecommitdiff
path: root/testcode/unitmain.c
diff options
context:
space:
mode:
Diffstat (limited to 'testcode/unitmain.c')
-rw-r--r--testcode/unitmain.c416
1 files changed, 416 insertions, 0 deletions
diff --git a/testcode/unitmain.c b/testcode/unitmain.c
index b6dac5507faf..647cbca3b05b 100644
--- a/testcode/unitmain.c
+++ b/testcode/unitmain.c
@@ -530,6 +530,207 @@ infra_test(void)
config_delete(cfg);
}
+#include "util/edns.h"
+/* Complete version-invalid client cookie; needs a new one.
+ * Based on edns_cookie_rfc9018_a2 */
+static void
+edns_cookie_invalid_version(void)
+{
+ uint32_t timestamp = 1559734385;
+ uint8_t client_cookie[] = {
+ 0x24, 0x64, 0xc4, 0xab, 0xcf, 0x10, 0xc9, 0x57,
+ 0x99, 0x00, 0x00, 0x00,
+ 0x5c, 0xf7, 0x9f, 0x11,
+ 0x1f, 0x81, 0x30, 0xc3, 0xee, 0xe2, 0x94, 0x80 };
+ uint8_t server_cookie[] = {
+ 0x24, 0x64, 0xc4, 0xab, 0xcf, 0x10, 0xc9, 0x57,
+ 0x01, 0x00, 0x00, 0x00,
+ 0x5c, 0xf7, 0xa8, 0x71,
+ 0xd4, 0xa5, 0x64, 0xa1, 0x44, 0x2a, 0xca, 0x77 };
+ uint8_t server_secret[] = {
+ 0xe5, 0xe9, 0x73, 0xe5, 0xa6, 0xb2, 0xa4, 0x3f,
+ 0x48, 0xe7, 0xdc, 0x84, 0x9e, 0x37, 0xbf, 0xcf };
+ uint8_t buf[32];
+ /* copy client cookie|version|reserved|timestamp */
+ memcpy(buf, client_cookie, 8 + 4 + 4);
+ /* copy ip 198.51.100.100 */
+ memcpy(buf + 16, "\306\063\144\144", 4);
+ unit_assert(edns_cookie_server_validate(client_cookie,
+ sizeof(client_cookie), server_secret, sizeof(server_secret), 1,
+ buf, timestamp) == COOKIE_STATUS_INVALID);
+ edns_cookie_server_write(buf, server_secret, 1, timestamp);
+ unit_assert(memcmp(server_cookie, buf, 24) == 0);
+}
+
+/* Complete hash-invalid client cookie; needs a new one. */
+static void
+edns_cookie_invalid_hash(void)
+{
+ uint32_t timestamp = 0;
+ uint8_t client_cookie[] = {
+ 0xfc, 0x93, 0xfc, 0x62, 0x80, 0x7d, 0xdb, 0x86,
+ 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x32, 0xF2, 0x43, 0xB9, 0xBC, 0xFE, 0xC4, 0x06 };
+ uint8_t server_cookie[] = {
+ 0xfc, 0x93, 0xfc, 0x62, 0x80, 0x7d, 0xdb, 0x86,
+ 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0xBA, 0x0D, 0x82, 0x90, 0x8F, 0xAA, 0xEB, 0xBD };
+ uint8_t server_secret[] = {
+ 0xe5, 0xe9, 0x73, 0xe5, 0xa6, 0xb2, 0xa4, 0x3f,
+ 0x48, 0xe7, 0xdc, 0x84, 0x9e, 0x37, 0xbf, 0xcf };
+ uint8_t buf[32];
+ /* copy client cookie|version|reserved|timestamp */
+ memcpy(buf, client_cookie, 8 + 4 + 4);
+ /* copy ip 203.0.113.203 */
+ memcpy(buf + 16, "\313\000\161\313", 4);
+ unit_assert(edns_cookie_server_validate(client_cookie,
+ sizeof(client_cookie), server_secret, sizeof(server_secret), 1,
+ buf, timestamp) == COOKIE_STATUS_INVALID);
+ edns_cookie_server_write(buf, server_secret, 1, timestamp);
+ unit_assert(memcmp(server_cookie, buf, 24) == 0);
+}
+
+/* Complete hash-valid client cookie; more than 30 minutes old; needs a
+ * refreshed server cookie.
+ * A slightly better variation of edns_cookie_rfc9018_a3 for Unbound to check
+ * that RESERVED bits do not influence cookie validation. */
+static void
+edns_cookie_rfc9018_a3_better(void)
+{
+ uint32_t timestamp = 1800 + 1;
+ uint8_t client_cookie[] = {
+ 0xfc, 0x93, 0xfc, 0x62, 0x80, 0x7d, 0xdb, 0x86,
+ 0x01, 0xab, 0xcd, 0xef,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x32, 0xF2, 0x43, 0xB9, 0xBC, 0xFE, 0xC4, 0x06 };
+ uint8_t server_cookie[] = {
+ 0xfc, 0x93, 0xfc, 0x62, 0x80, 0x7d, 0xdb, 0x86,
+ 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x07, 0x09,
+ 0x62, 0xD5, 0x93, 0x09, 0x14, 0x5C, 0x23, 0x9D };
+ uint8_t server_secret[] = {
+ 0xe5, 0xe9, 0x73, 0xe5, 0xa6, 0xb2, 0xa4, 0x3f,
+ 0x48, 0xe7, 0xdc, 0x84, 0x9e, 0x37, 0xbf, 0xcf };
+ uint8_t buf[32];
+ /* copy client cookie|version|reserved|timestamp */
+ memcpy(buf, client_cookie, 8 + 4 + 4);
+ /* copy ip 203.0.113.203 */
+ memcpy(buf + 16, "\313\000\161\313", 4);
+ unit_assert(edns_cookie_server_validate(client_cookie,
+ sizeof(client_cookie), server_secret, sizeof(server_secret), 1,
+ buf, timestamp) == COOKIE_STATUS_VALID_RENEW);
+ edns_cookie_server_write(buf, server_secret, 1, timestamp);
+ unit_assert(memcmp(server_cookie, buf, 24) == 0);
+}
+
+/* Complete hash-valid client cookie; more than 60 minutes old (expired);
+ * needs a refreshed server cookie. */
+static void
+edns_cookie_rfc9018_a3(void)
+{
+ uint32_t timestamp = 1559734700;
+ uint8_t client_cookie[] = {
+ 0xfc, 0x93, 0xfc, 0x62, 0x80, 0x7d, 0xdb, 0x86,
+ 0x01, 0xab, 0xcd, 0xef,
+ 0x5c, 0xf7, 0x8f, 0x71,
+ 0xa3, 0x14, 0x22, 0x7b, 0x66, 0x79, 0xeb, 0xf5 };
+ uint8_t server_cookie[] = {
+ 0xfc, 0x93, 0xfc, 0x62, 0x80, 0x7d, 0xdb, 0x86,
+ 0x01, 0x00, 0x00, 0x00,
+ 0x5c, 0xf7, 0xa9, 0xac,
+ 0xf7, 0x3a, 0x78, 0x10, 0xac, 0xa2, 0x38, 0x1e };
+ uint8_t server_secret[] = {
+ 0xe5, 0xe9, 0x73, 0xe5, 0xa6, 0xb2, 0xa4, 0x3f,
+ 0x48, 0xe7, 0xdc, 0x84, 0x9e, 0x37, 0xbf, 0xcf };
+ uint8_t buf[32];
+ /* copy client cookie|version|reserved|timestamp */
+ memcpy(buf, client_cookie, 8 + 4 + 4);
+ /* copy ip 203.0.113.203 */
+ memcpy(buf + 16, "\313\000\161\313", 4);
+ unit_assert(edns_cookie_server_validate(client_cookie,
+ sizeof(client_cookie), server_secret, sizeof(server_secret), 1,
+ buf, timestamp) == COOKIE_STATUS_EXPIRED);
+ edns_cookie_server_write(buf, server_secret, 1, timestamp);
+ unit_assert(memcmp(server_cookie, buf, 24) == 0);
+}
+
+/* Complete hash-valid client cookie; more than 30 minutes old; needs a
+ * refreshed server cookie. */
+static void
+edns_cookie_rfc9018_a2(void)
+{
+ uint32_t timestamp = 1559734385;
+ uint8_t client_cookie[] = {
+ 0x24, 0x64, 0xc4, 0xab, 0xcf, 0x10, 0xc9, 0x57,
+ 0x01, 0x00, 0x00, 0x00,
+ 0x5c, 0xf7, 0x9f, 0x11,
+ 0x1f, 0x81, 0x30, 0xc3, 0xee, 0xe2, 0x94, 0x80 };
+ uint8_t server_cookie[] = {
+ 0x24, 0x64, 0xc4, 0xab, 0xcf, 0x10, 0xc9, 0x57,
+ 0x01, 0x00, 0x00, 0x00,
+ 0x5c, 0xf7, 0xa8, 0x71,
+ 0xd4, 0xa5, 0x64, 0xa1, 0x44, 0x2a, 0xca, 0x77 };
+ uint8_t server_secret[] = {
+ 0xe5, 0xe9, 0x73, 0xe5, 0xa6, 0xb2, 0xa4, 0x3f,
+ 0x48, 0xe7, 0xdc, 0x84, 0x9e, 0x37, 0xbf, 0xcf };
+ uint8_t buf[32];
+ /* copy client cookie|version|reserved|timestamp */
+ memcpy(buf, client_cookie, 8 + 4 + 4);
+ /* copy ip 198.51.100.100 */
+ memcpy(buf + 16, "\306\063\144\144", 4);
+ unit_assert(edns_cookie_server_validate(client_cookie,
+ sizeof(client_cookie), server_secret, sizeof(server_secret), 1,
+ buf, timestamp) == COOKIE_STATUS_VALID_RENEW);
+ edns_cookie_server_write(buf, server_secret, 1, timestamp);
+ unit_assert(memcmp(server_cookie, buf, 24) == 0);
+}
+
+/* Only client cookie; needs a complete server cookie. */
+static void
+edns_cookie_rfc9018_a1(void)
+{
+ uint32_t timestamp = 1559731985;
+ uint8_t client_cookie[] = {
+ 0x24, 0x64, 0xc4, 0xab, 0xcf, 0x10, 0xc9, 0x57 };
+ uint8_t server_cookie[] = {
+ 0x24, 0x64, 0xc4, 0xab, 0xcf, 0x10, 0xc9, 0x57,
+ 0x01, 0x00, 0x00, 0x00,
+ 0x5c, 0xf7, 0x9f, 0x11,
+ 0x1f, 0x81, 0x30, 0xc3, 0xee, 0xe2, 0x94, 0x80 };
+ uint8_t server_secret[] = {
+ 0xe5, 0xe9, 0x73, 0xe5, 0xa6, 0xb2, 0xa4, 0x3f,
+ 0x48, 0xe7, 0xdc, 0x84, 0x9e, 0x37, 0xbf, 0xcf };
+ uint8_t buf[32];
+ /* copy client cookie|version|reserved|timestamp */
+ memcpy(buf, server_cookie, 8 + 4 + 4);
+ /* copy ip 198.51.100.100 */
+ memcpy(buf + 16, "\306\063\144\144", 4);
+ unit_assert(edns_cookie_server_validate(client_cookie,
+ sizeof(client_cookie),
+ /* these will not be used; it will return invalid
+ * because of the size. */
+ NULL, 0, 1, NULL, 0) == COOKIE_STATUS_CLIENT_ONLY);
+ edns_cookie_server_write(buf, server_secret, 1, timestamp);
+ unit_assert(memcmp(server_cookie, buf, 24) == 0);
+}
+
+/** test interoperable DNS cookies (RFC9018) */
+static void
+edns_cookie_test(void)
+{
+ unit_show_feature("interoperable dns cookies");
+ /* Check RFC9018 appendix test vectors */
+ edns_cookie_rfc9018_a1();
+ edns_cookie_rfc9018_a2();
+ edns_cookie_rfc9018_a3();
+ /* More tests */
+ edns_cookie_rfc9018_a3_better();
+ edns_cookie_invalid_hash();
+ edns_cookie_invalid_version();
+}
+
#include "util/random.h"
/** test randomness */
static void
@@ -839,6 +1040,218 @@ static void respip_test(void)
respip_conf_actions_test();
}
+#include "util/regional.h"
+#include "sldns/sbuffer.h"
+#include "util/data/dname.h"
+#include "util/data/msgreply.h"
+#include "util/data/msgencode.h"
+#include "sldns/str2wire.h"
+
+static void edns_ede_encode_setup(struct edns_data* edns,
+ struct regional* region)
+{
+ memset(edns, 0, sizeof(*edns));
+ edns->edns_present = 1;
+ edns->edns_version = EDNS_ADVERTISED_VERSION;
+ edns->udp_size = EDNS_ADVERTISED_SIZE;
+ edns->bits &= EDNS_DO;
+ /* Fill up opt_list_out with EDEs */
+ unit_assert(
+ edns_opt_list_append_ede(&edns->opt_list_out, region,
+ LDNS_EDE_OTHER, "Too long other text"));
+ unit_assert(
+ edns_opt_list_append_ede(&edns->opt_list_out, region,
+ LDNS_EDE_OTHER, "Too long other text"));
+ unit_assert(
+ edns_opt_list_append_ede(&edns->opt_list_out, region,
+ LDNS_EDE_BLOCKED, "Too long blocked text"));
+ unit_assert(
+ edns_opt_list_append_ede(&edns->opt_list_out, region,
+ LDNS_EDE_OTHER, "Too long other text"));
+ unit_assert(
+ edns_opt_list_append_ede(&edns->opt_list_out, region,
+ LDNS_EDE_BLOCKED, "Too long blocked text"));
+ /* Fill up opt_list_inplace_cb_out with EDEs */
+ unit_assert(
+ edns_opt_list_append_ede(&edns->opt_list_inplace_cb_out, region,
+ LDNS_EDE_OTHER, "Too long other text"));
+ unit_assert(
+ edns_opt_list_append_ede(&edns->opt_list_inplace_cb_out, region,
+ LDNS_EDE_OTHER, "Too long other text"));
+ unit_assert(
+ edns_opt_list_append_ede(&edns->opt_list_inplace_cb_out, region,
+ LDNS_EDE_BLOCKED, "Too long blocked text"));
+ unit_assert(
+ edns_opt_list_append_ede(&edns->opt_list_inplace_cb_out, region,
+ LDNS_EDE_OTHER, "Too long other text"));
+ unit_assert(
+ edns_opt_list_append_ede(&edns->opt_list_inplace_cb_out, region,
+ LDNS_EDE_BLOCKED, "Too long blocked text"));
+ /* append another EDNS option to both lists */
+ unit_assert(
+ edns_opt_list_append(&edns->opt_list_out,
+ LDNS_EDNS_UNBOUND_CACHEDB_TESTFRAME_TEST, 0, NULL, region));
+ unit_assert(
+ edns_opt_list_append(&edns->opt_list_inplace_cb_out,
+ LDNS_EDNS_UNBOUND_CACHEDB_TESTFRAME_TEST, 0, NULL, region));
+ /* append LDNS_EDE_OTHER at the end of both lists */
+ unit_assert(
+ edns_opt_list_append_ede(&edns->opt_list_out, region,
+ LDNS_EDE_OTHER, "Too long other text"));
+ unit_assert(
+ edns_opt_list_append_ede(&edns->opt_list_inplace_cb_out, region,
+ LDNS_EDE_OTHER, "Too long other text"));
+}
+
+static void edns_ede_encode_encodedecode(struct query_info* qinfo,
+ struct reply_info* rep, struct regional* region,
+ struct edns_data* edns, sldns_buffer* pkt)
+{
+ /* encode */
+ unit_assert(
+ reply_info_answer_encode(qinfo, rep, 1, rep->flags, pkt,
+ 0, 0, region, 65535, edns, 0, 0));
+ /* buffer ready for reading; skip after the question section */
+ sldns_buffer_skip(pkt, LDNS_HEADER_SIZE);
+ (void)query_dname_len(pkt);
+ sldns_buffer_skip(pkt, 2 + 2);
+ /* decode */
+ unit_assert(parse_edns_from_query_pkt(pkt, edns, NULL, NULL, NULL, 0,
+ region) == 0);
+}
+
+static void edns_ede_encode_check(struct edns_data* edns, int* found_ede,
+ int* found_ede_other, int* found_ede_txt, int* found_other_edns)
+{
+ struct edns_option* opt;
+ for(opt = edns->opt_list_in; opt; opt = opt->next) {
+ if(opt->opt_code == LDNS_EDNS_EDE) {
+ (*found_ede)++;
+ if(opt->opt_len > 2)
+ (*found_ede_txt)++;
+ if(opt->opt_len >= 2 && sldns_read_uint16(
+ opt->opt_data) == LDNS_EDE_OTHER)
+ (*found_ede_other)++;
+ } else {
+ (*found_other_edns)++;
+ }
+ }
+
+}
+
+static void edns_ede_encode_fit_test(struct query_info* qinfo,
+ struct reply_info* rep, struct regional* region)
+{
+ struct edns_data edns;
+ int found_ede = 0, found_ede_other = 0, found_ede_txt = 0;
+ int found_other_edns = 0;
+ sldns_buffer* pkt = sldns_buffer_new(65535);
+ unit_assert(pkt);
+ edns_ede_encode_setup(&edns, region);
+ /* leave the pkt buffer as is; everything should fit */
+ edns_ede_encode_encodedecode(qinfo, rep, region, &edns, pkt);
+ edns_ede_encode_check(&edns, &found_ede, &found_ede_other,
+ &found_ede_txt, &found_other_edns);
+ unit_assert(found_ede == 12);
+ unit_assert(found_ede_other == 8);
+ unit_assert(found_ede_txt == 12);
+ unit_assert(found_other_edns == 2);
+ /* cleanup */
+ sldns_buffer_free(pkt);
+}
+
+static void edns_ede_encode_notxt_fit_test( struct query_info* qinfo,
+ struct reply_info* rep, struct regional* region)
+{
+ struct edns_data edns;
+ sldns_buffer* pkt;
+ uint16_t edns_field_size, ede_txt_size;
+ int found_ede = 0, found_ede_other = 0, found_ede_txt = 0;
+ int found_other_edns = 0;
+ edns_ede_encode_setup(&edns, region);
+ /* pkt buffer should fit everything if the ede txt is cropped.
+ * OTHER EDE should not be there since it is useless without text. */
+ edns_field_size = calc_edns_field_size(&edns);
+ (void)calc_ede_option_size(&edns, &ede_txt_size);
+ pkt = sldns_buffer_new(LDNS_HEADER_SIZE
+ + qinfo->qname_len
+ + 2 + 2 /* qtype + qclass */
+ + 11 /* opt record */
+ + edns_field_size
+ - ede_txt_size);
+ unit_assert(pkt);
+ edns_ede_encode_encodedecode(qinfo, rep, region, &edns, pkt);
+ edns_ede_encode_check(&edns, &found_ede, &found_ede_other,
+ &found_ede_txt, &found_other_edns);
+ unit_assert(found_ede == 4);
+ unit_assert(found_ede_other == 0);
+ unit_assert(found_ede_txt == 0);
+ unit_assert(found_other_edns == 2);
+ /* cleanup */
+ sldns_buffer_free(pkt);
+}
+
+static void edns_ede_encode_no_fit_test( struct query_info* qinfo,
+ struct reply_info* rep, struct regional* region)
+{
+ struct edns_data edns;
+ sldns_buffer* pkt;
+ uint16_t edns_field_size, ede_size, ede_txt_size;
+ int found_ede = 0, found_ede_other = 0, found_ede_txt = 0;
+ int found_other_edns = 0;
+ edns_ede_encode_setup(&edns, region);
+ /* pkt buffer should fit only non-EDE options. */
+ edns_field_size = calc_edns_field_size(&edns);
+ ede_size = calc_ede_option_size(&edns, &ede_txt_size);
+ pkt = sldns_buffer_new(LDNS_HEADER_SIZE
+ + qinfo->qname_len
+ + 2 + 2 /* qtype + qclass */
+ + 11 /* opt record */
+ + edns_field_size
+ - ede_size);
+ unit_assert(pkt);
+ edns_ede_encode_encodedecode(qinfo, rep, region, &edns, pkt);
+ edns_ede_encode_check(&edns, &found_ede, &found_ede_other,
+ &found_ede_txt, &found_other_edns);
+ unit_assert(found_ede == 0);
+ unit_assert(found_ede_other == 0);
+ unit_assert(found_ede_txt == 0);
+ unit_assert(found_other_edns == 2);
+ /* cleanup */
+ sldns_buffer_free(pkt);
+}
+
+/** test optional EDE encoding with various buffer
+ * available sizes */
+static void edns_ede_answer_encode_test(void)
+{
+ struct regional* region = regional_create();
+ struct reply_info* rep;
+ struct query_info qinfo;
+ unit_show_feature("edns ede optional encoding");
+ unit_assert(region);
+ rep = construct_reply_info_base(region,
+ LDNS_RCODE_NOERROR | BIT_QR, 1,
+ 3600, 3600, 3600,
+ 0, 0, 0, 0,
+ sec_status_unchecked, LDNS_EDE_NONE);
+ unit_assert(rep);
+ memset(&qinfo, 0, sizeof(qinfo));
+ qinfo.qname = sldns_str2wire_dname("encode.ede.", &qinfo.qname_len);
+ unit_assert(qinfo.qname);
+ qinfo.qtype = LDNS_RR_TYPE_TXT;
+ qinfo.qclass = LDNS_RR_CLASS_IN;
+
+ edns_ede_encode_fit_test(&qinfo, rep, region);
+ edns_ede_encode_notxt_fit_test(&qinfo, rep, region);
+ edns_ede_encode_no_fit_test(&qinfo, rep, region);
+
+ /* cleanup */
+ free(qinfo.qname);
+ regional_free_all(region);
+ regional_destroy(region);
+}
+
void unit_show_func(const char* file, const char* func)
{
printf("test %s:%s\n", file, func);
@@ -852,6 +1265,7 @@ void unit_show_feature(const char* feature)
#ifdef USE_ECDSA_EVP_WORKAROUND
void ecdsa_evp_workaround_init(void);
#endif
+
/**
* Main unit test program. Setup, teardown and report errors.
* @param argc: arg count.
@@ -906,9 +1320,11 @@ main(int argc, char* argv[])
slabhash_test();
infra_test();
ldns_test();
+ edns_cookie_test();
zonemd_test();
tcpreuse_test();
msgparse_test();
+ edns_ede_answer_encode_test();
#ifdef CLIENT_SUBNET
ecs_test();
#endif /* CLIENT_SUBNET */