1 /* $NetBSD: dns64_test.c,v 1.3 2025/01/26 16:25:47 christos Exp $ */ 2 3 /* 4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 5 * 6 * SPDX-License-Identifier: MPL-2.0 7 * 8 * This Source Code Form is subject to the terms of the Mozilla Public 9 * License, v. 2.0. If a copy of the MPL was not distributed with this 10 * file, you can obtain one at https://mozilla.org/MPL/2.0/. 11 * 12 * See the COPYRIGHT file distributed with this work for additional 13 * information regarding copyright ownership. 14 */ 15 16 #include <inttypes.h> 17 #include <sched.h> /* IWYU pragma: keep */ 18 #include <setjmp.h> 19 #include <stdarg.h> 20 #include <stddef.h> 21 #include <stdlib.h> 22 #include <string.h> 23 #include <unistd.h> 24 25 #define UNIT_TESTING 26 #include <cmocka.h> 27 28 #include <isc/netaddr.h> 29 #include <isc/result.h> 30 #include <isc/string.h> 31 #include <isc/util.h> 32 33 #include <dns/dns64.h> 34 #include <dns/rdata.h> 35 #include <dns/rdatalist.h> 36 #include <dns/rdataset.h> 37 38 #include <tests/dns.h> 39 40 static void 41 multiple_prefixes(void) { 42 size_t i, count; 43 /* 44 * Two prefix, non consectutive. 45 */ 46 unsigned char aaaa[4][16] = { 47 { 0, 0, 0, 0, 192, 0, 0, 170, 0, 0, 0, 0, 192, 0, 0, 171 }, 48 { 0, 0, 0, 0, 192, 55, 0, 170, 0, 0, 0, 0, 192, 0, 0, 170 }, 49 { 0, 0, 0, 0, 192, 0, 0, 170, 0, 0, 0, 0, 192, 0, 0, 170 }, 50 { 0, 0, 0, 0, 192, 55, 0, 170, 0, 0, 0, 0, 192, 0, 0, 171 }, 51 }; 52 dns_rdataset_t rdataset; 53 dns_rdatalist_t rdatalist; 54 dns_rdata_t rdata[4] = { DNS_RDATA_INIT, DNS_RDATA_INIT, DNS_RDATA_INIT, 55 DNS_RDATA_INIT }; 56 isc_netprefix_t prefix[2]; 57 unsigned char p1[] = { 0, 0, 0, 0, 192, 0, 0, 170, 0, 0, 0, 0 }; 58 unsigned char p2[] = { 0, 0, 0, 0, 192, 55, 0, 170, 0, 0, 0, 0 }; 59 isc_result_t result; 60 bool have_p1, have_p2; 61 62 /* 63 * Construct AAAA rdataset containing 2 prefixes. 64 */ 65 dns_rdatalist_init(&rdatalist); 66 for (i = 0; i < 4; i++) { 67 isc_region_t region; 68 region.base = aaaa[i]; 69 region.length = 16; 70 dns_rdata_fromregion(&rdata[i], dns_rdataclass_in, 71 dns_rdatatype_aaaa, ®ion); 72 ISC_LIST_APPEND(rdatalist.rdata, &rdata[i], link); 73 } 74 rdatalist.type = rdata[0].type; 75 rdatalist.rdclass = rdata[0].rdclass; 76 rdatalist.ttl = 0; 77 dns_rdataset_init(&rdataset); 78 dns_rdatalist_tordataset(&rdatalist, &rdataset); 79 80 count = ARRAY_SIZE(prefix); 81 memset(&prefix, 0, sizeof(prefix)); 82 result = dns_dns64_findprefix(&rdataset, prefix, &count); 83 assert_int_equal(result, ISC_R_SUCCESS); 84 assert_int_equal(count, 2); 85 have_p1 = have_p2 = false; 86 for (i = 0; i < count; i++) { 87 assert_int_equal(prefix[i].prefixlen, 96); 88 assert_int_equal(prefix[i].addr.family, AF_INET6); 89 if (memcmp(prefix[i].addr.type.in6.s6_addr, p1, 12) == 0) { 90 have_p1 = true; 91 } 92 if (memcmp(prefix[i].addr.type.in6.s6_addr, p2, 12) == 0) { 93 have_p2 = true; 94 } 95 } 96 assert_true(have_p1); 97 assert_true(have_p2); 98 99 /* 100 * Check that insufficient prefix space returns ISC_R_NOSPACE 101 * and that the prefix is populated. 102 */ 103 count = 1; 104 memset(&prefix, 0, sizeof(prefix)); 105 result = dns_dns64_findprefix(&rdataset, prefix, &count); 106 assert_int_equal(result, ISC_R_NOSPACE); 107 assert_int_equal(count, 2); 108 have_p1 = have_p2 = false; 109 assert_int_equal(prefix[0].prefixlen, 96); 110 assert_int_equal(prefix[0].addr.family, AF_INET6); 111 if (memcmp(prefix[0].addr.type.in6.s6_addr, p1, 12) == 0) { 112 have_p1 = true; 113 } 114 if (memcmp(prefix[0].addr.type.in6.s6_addr, p2, 12) == 0) { 115 have_p2 = true; 116 } 117 if (!have_p2) { 118 assert_true(have_p1); 119 } 120 if (!have_p1) { 121 assert_true(have_p2); 122 } 123 assert_true(have_p1 != have_p2); 124 } 125 126 ISC_RUN_TEST_IMPL(dns64_findprefix) { 127 unsigned int i, j, o; 128 isc_result_t result; 129 struct { 130 unsigned char prefix[12]; 131 unsigned int prefixlen; 132 isc_result_t result; 133 } tests[] = { 134 /* The WKP with various lengths. */ 135 { { 0, 0x64, 0xff, 0x9b, 0, 0, 0, 0, 0, 0, 0, 0 }, 136 32, 137 ISC_R_SUCCESS }, 138 { { 0, 0x64, 0xff, 0x9b, 0, 0, 0, 0, 0, 0, 0, 0 }, 139 40, 140 ISC_R_SUCCESS }, 141 { { 0, 0x64, 0xff, 0x9b, 0, 0, 0, 0, 0, 0, 0, 0 }, 142 48, 143 ISC_R_SUCCESS }, 144 { { 0, 0x64, 0xff, 0x9b, 0, 0, 0, 0, 0, 0, 0, 0 }, 145 56, 146 ISC_R_SUCCESS }, 147 { { 0, 0x64, 0xff, 0x9b, 0, 0, 0, 0, 0, 0, 0, 0 }, 148 64, 149 ISC_R_SUCCESS }, 150 { { 0, 0x64, 0xff, 0x9b, 0, 0, 0, 0, 0, 0, 0, 0 }, 151 96, 152 ISC_R_SUCCESS }, 153 /* 154 * Prefix with the mapped addresses also appearing in the 155 * prefix. 156 */ 157 { { 0, 0, 0, 0, 192, 0, 0, 170, 0, 0, 0, 0 }, 158 96, 159 ISC_R_SUCCESS }, 160 { { 0, 0, 0, 0, 192, 0, 0, 171, 0, 0, 0, 0 }, 161 96, 162 ISC_R_SUCCESS }, 163 /* Bad prefix, MBZ != 0. */ 164 { { 0, 0x64, 0xff, 0x9b, 0, 0, 0, 0, 1, 0, 0, 0 }, 165 96, 166 ISC_R_NOTFOUND }, 167 }; 168 169 for (i = 0; i < ARRAY_SIZE(tests); i++) { 170 size_t count = 2; 171 dns_rdataset_t rdataset; 172 dns_rdatalist_t rdatalist; 173 dns_rdata_t rdata[2] = { DNS_RDATA_INIT, DNS_RDATA_INIT }; 174 struct in6_addr ina6[2]; 175 isc_netprefix_t prefix[2]; 176 unsigned char aa[] = { 192, 0, 0, 170 }; 177 unsigned char ab[] = { 192, 0, 0, 171 }; 178 isc_region_t region; 179 180 /* 181 * Construct rdata. 182 */ 183 memset(ina6[0].s6_addr, 0, sizeof(ina6[0].s6_addr)); 184 memset(ina6[1].s6_addr, 0, sizeof(ina6[1].s6_addr)); 185 memmove(ina6[0].s6_addr, tests[i].prefix, 12); 186 memmove(ina6[1].s6_addr, tests[i].prefix, 12); 187 o = tests[i].prefixlen / 8; 188 for (j = 0; j < 4; j++) { 189 if ((o + j) == 8U) { 190 o++; /* skip mbz */ 191 } 192 ina6[0].s6_addr[j + o] = aa[j]; 193 ina6[1].s6_addr[j + o] = ab[j]; 194 } 195 region.base = ina6[0].s6_addr; 196 region.length = sizeof(ina6[0].s6_addr); 197 dns_rdata_fromregion(&rdata[0], dns_rdataclass_in, 198 dns_rdatatype_aaaa, ®ion); 199 region.base = ina6[1].s6_addr; 200 region.length = sizeof(ina6[1].s6_addr); 201 dns_rdata_fromregion(&rdata[1], dns_rdataclass_in, 202 dns_rdatatype_aaaa, ®ion); 203 204 dns_rdatalist_init(&rdatalist); 205 rdatalist.type = rdata[0].type; 206 rdatalist.rdclass = rdata[0].rdclass; 207 rdatalist.ttl = 0; 208 ISC_LIST_APPEND(rdatalist.rdata, &rdata[0], link); 209 ISC_LIST_APPEND(rdatalist.rdata, &rdata[1], link); 210 dns_rdataset_init(&rdataset); 211 dns_rdatalist_tordataset(&rdatalist, &rdataset); 212 213 result = dns_dns64_findprefix(&rdataset, prefix, &count); 214 assert_int_equal(result, tests[i].result); 215 if (tests[i].result == ISC_R_SUCCESS) { 216 assert_int_equal(count, 1); 217 assert_int_equal(prefix[0].prefixlen, 218 tests[i].prefixlen); 219 assert_int_equal(prefix[0].addr.family, AF_INET6); 220 assert_memory_equal(prefix[0].addr.type.in6.s6_addr, 221 tests[i].prefix, 222 tests[i].prefixlen / 8); 223 } 224 } 225 226 /* 227 * Test multiple prefixes. 228 */ 229 multiple_prefixes(); 230 } 231 232 ISC_TEST_LIST_START 233 ISC_TEST_ENTRY(dns64_findprefix) 234 ISC_TEST_LIST_END 235 236 ISC_TEST_MAIN 237