/* * Copyright (C) Internet Systems Consortium, Inc. ("ISC") * * SPDX-License-Identifier: MPL-2.0 * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, you can obtain one at https://mozilla.org/MPL/2.0/. * * See the COPYRIGHT file distributed with this work for additional * information regarding copyright ownership. */ #include #include /* IWYU pragma: keep */ #include #include #include #include #include #define UNIT_TESTING #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* Helper function to create a vecheader directly */ static isc_result_t create_vecheader(isc_mem_t *mctx, dns_rdatatype_t type, dns_rdataclass_t rdclass, dns_ttl_t ttl, const char *rdata_text, dns_vecheader_t **headerp) { dns_rdataset_t rdataset; dns_rdatalist_t *rdatalist; dns_rdata_t *rdata; unsigned char *data; isc_region_t region; isc_result_t result; /* Allocate temporary structures */ data = isc_mem_get(mctx, 256); rdatalist = isc_mem_get(mctx, sizeof(*rdatalist)); rdata = isc_mem_get(mctx, sizeof(*rdata)); /* Initialize rdataset and rdatalist */ dns_rdataset_init(&rdataset); dns_rdatalist_init(rdatalist); rdatalist->type = type; rdatalist->rdclass = rdclass; rdatalist->ttl = ttl; /* Create rdata */ dns_rdata_init(rdata); CHECK(dns_test_rdatafromstring(rdata, rdclass, type, data, 256, rdata_text, false)); ISC_LIST_APPEND(rdatalist->rdata, rdata, link); dns_rdatalist_tordataset(rdatalist, &rdataset); /* Convert to vecheader */ CHECK(dns_rdatavec_fromrdataset(&rdataset, mctx, ®ion, 0)); *headerp = (dns_vecheader_t *)region.base; /* Cleanup rdataset */ dns_rdataset_disassociate(&rdataset); cleanup: /* Cleanup temporary structures */ isc_mem_put(mctx, rdata, sizeof(*rdata)); isc_mem_put(mctx, rdatalist, sizeof(*rdatalist)); isc_mem_put(mctx, data, 256); return result; } /* Helper function to create an rdataset from a vecheader */ static void create_rdataset_from_vecheader(dns_vecheader_t *header, dns_rdataclass_t rdclass, dns_rdatatype_t type, dns_rdataset_t *rdataset) { dns_rdataset_init(rdataset); rdataset->methods = &dns_rdatavec_rdatasetmethods; rdataset->rdclass = rdclass; rdataset->type = type; rdataset->vec.header = header; } /* Test merging two headers */ ISC_RUN_TEST_IMPL(merge_headers) { isc_mem_t *mctx = isc_g_mctx; UNUSED(state); dns_vecheader_t *header1 = NULL, *header2 = NULL, *merged_header = NULL; unsigned int size1, size2, merged_size, expected_size; unsigned int count1, count2, merged_count, expected_count; isc_result_t result; /* Create vecheaders with A records */ CHECK(create_vecheader(mctx, dns_rdatatype_a, dns_rdataclass_in, 300, "192.168.1.1", &header1)); CHECK(create_vecheader(mctx, dns_rdatatype_a, dns_rdataclass_in, 300, "192.168.1.2", &header2)); /* Get sizes and counts before merging */ size1 = dns_rdatavec_size(header1); size2 = dns_rdatavec_size(header2); count1 = dns_rdatavec_count(header1); count2 = dns_rdatavec_count(header2); /* Merge headers */ CHECK(dns_rdatavec_merge(header1, header2, mctx, dns_rdataclass_in, dns_rdatatype_a, 0, 0, &merged_header)); assert_non_null(merged_header); /* Get merged size and count */ merged_size = dns_rdatavec_size(merged_header); merged_count = dns_rdatavec_count(merged_header); /* Test: merged size should be first_size + second_size - sizeof(header) * - count_field_size */ expected_size = size1 + size2 - sizeof(dns_vecheader_t) - 2; assert_int_equal(merged_size, expected_size); /* Test: merged count should be first_count + second_count */ expected_count = count1 + count2; assert_int_equal(merged_count, expected_count); cleanup: /* Cleanup */ if (header1 != NULL) { size1 = dns_rdatavec_size(header1); isc_mem_put(mctx, header1, size1); } if (header2 != NULL) { size2 = dns_rdatavec_size(header2); isc_mem_put(mctx, header2, size2); } if (merged_header != NULL) { merged_size = dns_rdatavec_size(merged_header); isc_mem_put(mctx, merged_header, merged_size); } } /* Test case preservation during merge */ ISC_RUN_TEST_IMPL(merge_case_preservation) { isc_mem_t *mctx = isc_g_mctx; UNUSED(state); dns_vecheader_t *header1 = NULL, *header2 = NULL, *merged_header = NULL; dns_fixedname_t fname1, fname2, fmerged_name; dns_name_t *name1 = dns_fixedname_initname(&fname1); dns_name_t *name2 = dns_fixedname_initname(&fname2); dns_name_t *merged_name = dns_fixedname_initname(&fmerged_name); unsigned int size1, size2, merged_size; isc_result_t result; dns_test_namefromstring("Example.COM", &fname1); dns_test_namefromstring("example.com", &fname2); /* Create vecheaders */ CHECK(create_vecheader(mctx, dns_rdatatype_a, dns_rdataclass_in, 300, "192.168.1.1", &header1)); CHECK(create_vecheader(mctx, dns_rdatatype_a, dns_rdataclass_in, 300, "192.168.1.2", &header2)); /* Set case on first header */ dns_vecheader_setownercase(header1, name1); /* Set case on second header */ dns_vecheader_setownercase(header2, name2); /* Get sizes */ size1 = dns_rdatavec_size(header1); size2 = dns_rdatavec_size(header2); /* Merge headers */ CHECK(dns_rdatavec_merge(header1, header2, mctx, dns_rdataclass_in, dns_rdatatype_a, 0, 0, &merged_header)); assert_non_null(merged_header); /* Test: case should be the same as the first header */ /* Copy the name for testing */ dns_name_copy(name1, merged_name); /* Create a test rdataset from merged header to test case */ dns_rdataset_t test_rdataset; create_rdataset_from_vecheader(merged_header, dns_rdataclass_in, dns_rdatatype_a, &test_rdataset); /* Apply case from merged header */ dns_rdataset_getownercase(&test_rdataset, merged_name); /* The case should match the original first name */ assert_true(dns_name_caseequal(name1, merged_name)); cleanup: /* Cleanup */ if (header1 != NULL) { size1 = dns_rdatavec_size(header1); isc_mem_put(mctx, header1, size1); } if (header2 != NULL) { size2 = dns_rdatavec_size(header2); isc_mem_put(mctx, header2, size2); } if (merged_header != NULL) { merged_size = dns_rdatavec_size(merged_header); isc_mem_put(mctx, merged_header, merged_size); } } /* Test size consistency after setting case */ ISC_RUN_TEST_IMPL(setcase_size_consistency) { isc_mem_t *mctx = isc_g_mctx; UNUSED(state); dns_vecheader_t *header = NULL; dns_fixedname_t fname, flower_fname, fretrieved_fname; dns_name_t *name = dns_fixedname_initname(&fname); dns_name_t *lower_name = dns_fixedname_initname(&flower_fname); dns_name_t *retrieved_name = dns_fixedname_initname(&fretrieved_fname); unsigned int original_size, cased_size; dns_rdataset_t test_rdataset; isc_result_t result; /* Initialize name */ dns_test_namefromstring("Example.COM", &fname); /* Create vecheader */ CHECK(create_vecheader(mctx, dns_rdatatype_a, dns_rdataclass_in, 300, "192.168.1.1", &header)); /* Get original size */ original_size = dns_rdatavec_size(header); /* Set case */ dns_vecheader_setownercase(header, name); /* Get size after setting case */ cased_size = dns_rdatavec_size(header); /* Test: size should be the same after setting case */ assert_int_equal(cased_size, original_size); /* Create lowercase version of the original name */ dns_test_namefromstring("example.com", &flower_fname); /* Copy lowercase name to retrieved_name for testing */ dns_name_copy(lower_name, retrieved_name); /* Create a test rdataset from cased header */ create_rdataset_from_vecheader(header, dns_rdataclass_in, dns_rdatatype_a, &test_rdataset); /* Apply case from cased header to retrieved_name */ dns_rdataset_getownercase(&test_rdataset, retrieved_name); /* Test: retrieved case should match the original mixed case */ assert_true(dns_name_caseequal(name, retrieved_name)); cleanup: /* Cleanup */ if (header != NULL) { cased_size = dns_rdatavec_size(header); isc_mem_put(mctx, header, cased_size); } } ISC_TEST_LIST_START ISC_TEST_ENTRY_CUSTOM(merge_headers, setup_mctx, teardown_mctx) ISC_TEST_ENTRY_CUSTOM(merge_case_preservation, setup_mctx, teardown_mctx) ISC_TEST_ENTRY_CUSTOM(setcase_size_consistency, setup_mctx, teardown_mctx) ISC_TEST_LIST_END ISC_TEST_MAIN