]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/recursordist/test-reczones-helpers.cc
Merge pull request #13387 from omoerbeek/rec-b-root-servers
[thirdparty/pdns.git] / pdns / recursordist / test-reczones-helpers.cc
1 #define BOOST_TEST_DYN_LINK
2 #include <boost/test/unit_test.hpp>
3
4 #include <cstdio>
5
6 #include "test-syncres_cc.hh"
7 #include "reczones-helpers.hh"
8
9 BOOST_AUTO_TEST_SUITE(reczones_helpers)
10
11 static const std::array<std::string, 10> hostLines = {
12 "192.168.0.1 foo bar\n",
13 "192.168.0.1 dupfoo\n",
14 "192.168.0.2 baz\n",
15 "1.1.1.1 fancy\n",
16 "2.2.2.2 more.fancy\n",
17 "2001:db8::567:89ab foo6 bar6\n",
18 "2001:db8::567:89ab dupfoo6\n",
19 "127.0.0.1 localhost\n",
20 "::1 localhost self\n",
21 "2001:db8::567:89ac some.address.somewhere some some.address\n",
22 };
23
24 struct Fixture
25 {
26 static std::shared_ptr<DNSRecordContent> makeLocalhostRootDRC()
27 {
28 return DNSRecordContent::make(QType::SOA, QClass::IN, "localhost. root 1 604800 86400 2419200 604800");
29 }
30
31 static std::shared_ptr<DNSRecordContent> makeLocalhostDRC()
32 {
33 return DNSRecordContent::make(QType::NS, QClass::IN, "localhost.");
34 }
35
36 static std::shared_ptr<DNSRecordContent> makePtrDRC(const std::string& name)
37 {
38 return DNSRecordContent::make(QType::PTR, QClass::IN, name);
39 }
40
41 static void addDomainMapFixtureEntry(SyncRes::domainmap_t& domainMap,
42 const std::string& name,
43 const SyncRes::AuthDomain::records_t& records)
44 {
45 domainMap[DNSName{name}] = SyncRes::AuthDomain{
46 .d_records = records,
47 .d_servers = {},
48 .d_name = DNSName{name},
49 .d_rdForward = false,
50 };
51 }
52
53 static void addDomainMapFixtureEntry(SyncRes::domainmap_t& domainMap,
54 const std::string& name,
55 const QType type,
56 const std::string& address)
57 {
58 domainMap[DNSName{name}] = SyncRes::AuthDomain{
59 .d_records = {
60 DNSRecord(name, DNSRecordContent::make(type, QClass::IN, address), type),
61 DNSRecord(name, makeLocalhostDRC(), QType::NS),
62 DNSRecord(name, makeLocalhostRootDRC(), QType::SOA),
63 },
64 .d_servers = {},
65 .d_name = DNSName{name},
66 .d_rdForward = false,
67 };
68 }
69
70 static void populateDomainMapFixture(SyncRes::domainmap_t& domainMap,
71 const std::string& searchSuffix = "")
72 {
73 const auto actualSearchSuffix = searchSuffix.empty() ? "" : "." + searchSuffix;
74
75 addDomainMapFixtureEntry(domainMap, "foo" + actualSearchSuffix, QType::A, "192.168.0.1");
76 addDomainMapFixtureEntry(domainMap, "bar" + actualSearchSuffix, QType::A, "192.168.0.1");
77 addDomainMapFixtureEntry(domainMap, "dupfoo" + actualSearchSuffix, QType::A, "192.168.0.1");
78 addDomainMapFixtureEntry(
79 domainMap,
80 "1.0.168.192.in-addr.arpa",
81 {
82 DNSRecord("1.0.168.192.in-addr.arpa", makeLocalhostDRC(), QType::NS),
83 DNSRecord("1.0.168.192.in-addr.arpa", makeLocalhostRootDRC(), QType::SOA),
84 DNSRecord("1.0.168.192.in-addr.arpa", makePtrDRC("foo" + actualSearchSuffix), QType::PTR),
85 });
86 addDomainMapFixtureEntry(domainMap, "baz" + actualSearchSuffix, QType::A, "192.168.0.2");
87 addDomainMapFixtureEntry(
88 domainMap,
89 "2.0.168.192.in-addr.arpa",
90 {
91 DNSRecord("2.0.168.192.in-addr.arpa", makeLocalhostDRC(), QType::NS),
92 DNSRecord("2.0.168.192.in-addr.arpa", makeLocalhostRootDRC(), QType::SOA),
93 DNSRecord("2.0.168.192.in-addr.arpa", makePtrDRC("baz" + actualSearchSuffix), QType::PTR),
94 });
95 addDomainMapFixtureEntry(domainMap, "fancy" + actualSearchSuffix, QType::A, "1.1.1.1");
96 addDomainMapFixtureEntry(
97 domainMap,
98 "1.1.1.1.in-addr.arpa",
99 {
100 DNSRecord("1.1.1.1.in-addr.arpa", makeLocalhostDRC(), QType::NS),
101 DNSRecord("1.1.1.1.in-addr.arpa", makeLocalhostRootDRC(), QType::SOA),
102 DNSRecord("1.1.1.1.in-addr.arpa", makePtrDRC("fancy" + actualSearchSuffix), QType::PTR),
103 });
104 addDomainMapFixtureEntry(domainMap, "more.fancy", QType::A, "2.2.2.2");
105 addDomainMapFixtureEntry(
106 domainMap,
107 "2.2.2.2.in-addr.arpa",
108 {
109 DNSRecord("2.2.2.2.in-addr.arpa", makeLocalhostDRC(), QType::NS),
110 DNSRecord("2.2.2.2.in-addr.arpa", makeLocalhostRootDRC(), QType::SOA),
111 DNSRecord("2.2.2.2.in-addr.arpa", makePtrDRC("more.fancy."), QType::PTR),
112 });
113
114 addDomainMapFixtureEntry(domainMap, "foo6" + actualSearchSuffix, QType::AAAA, "2001:db8::567:89ab");
115 addDomainMapFixtureEntry(domainMap, "bar6" + actualSearchSuffix, QType::AAAA, "2001:db8::567:89ab");
116 addDomainMapFixtureEntry(domainMap, "dupfoo6" + actualSearchSuffix, QType::AAAA, "2001:db8::567:89ab");
117 addDomainMapFixtureEntry(
118 domainMap,
119 "b.a.9.8.7.6.5.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa",
120 {
121 DNSRecord("b.a.9.8.7.6.5.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa", makeLocalhostDRC(), QType::NS),
122 DNSRecord("b.a.9.8.7.6.5.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa", makeLocalhostRootDRC(), QType::SOA),
123 DNSRecord("b.a.9.8.7.6.5.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa", makePtrDRC("foo6" + actualSearchSuffix), QType::PTR),
124 });
125
126 addDomainMapFixtureEntry(
127 domainMap,
128 "localhost" + actualSearchSuffix,
129 {DNSRecord("localhost" + actualSearchSuffix, makeLocalhostDRC(), QType::NS),
130 DNSRecord("localhost" + actualSearchSuffix, makeLocalhostRootDRC(), QType::SOA),
131 DNSRecord("localhost" + actualSearchSuffix, DNSRecordContent::make(QType::AAAA, QClass::IN, "::1"), QType::AAAA),
132 DNSRecord("localhost" + actualSearchSuffix, DNSRecordContent::make(QType::A, QClass::IN, "127.0.0.1"), QType::A)});
133 addDomainMapFixtureEntry(domainMap, "self" + actualSearchSuffix, QType::AAAA, "::1");
134 addDomainMapFixtureEntry(
135 domainMap,
136 "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa",
137 {
138 DNSRecord("1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa", makeLocalhostDRC(), QType::NS),
139 DNSRecord("1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa", makeLocalhostRootDRC(), QType::SOA),
140 DNSRecord("1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa", makePtrDRC("localhost" + actualSearchSuffix), QType::PTR),
141 });
142 addDomainMapFixtureEntry(
143 domainMap,
144 "1.0.0.127.in-addr.arpa",
145 {
146 DNSRecord("1.0.0.127.in-addr.arpa", makeLocalhostDRC(), QType::NS),
147 DNSRecord("1.0.0.127.in-addr.arpa", makeLocalhostRootDRC(), QType::SOA),
148 DNSRecord("1.0.0.127.in-addr.arpa", makePtrDRC("localhost" + actualSearchSuffix), QType::PTR),
149 });
150
151 addDomainMapFixtureEntry(domainMap, "some" + actualSearchSuffix, QType::AAAA, "2001:db8::567:89ac");
152 addDomainMapFixtureEntry(domainMap, "some.address.somewhere", QType::AAAA, "2001:db8::567:89ac");
153 addDomainMapFixtureEntry(domainMap, "some.address", QType::AAAA, "2001:db8::567:89ac");
154 addDomainMapFixtureEntry(
155 domainMap,
156 "c.a.9.8.7.6.5.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa",
157 {
158 DNSRecord("c.a.9.8.7.6.5.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa", makeLocalhostDRC(), QType::NS),
159 DNSRecord("c.a.9.8.7.6.5.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa", makeLocalhostRootDRC(), QType::SOA),
160 DNSRecord("c.a.9.8.7.6.5.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa", makePtrDRC("some.address.somewhere."), QType::PTR),
161 });
162 }
163
164 Fixture()
165 {
166 populateDomainMapFixture(domainMapFixture);
167 populateDomainMapFixture(domainMapFixtureWithSearchSuffix, "search.suffix");
168 }
169
170 using DomainMapEntry = std::pair<DNSName, SyncRes::AuthDomain>;
171
172 static std::vector<DomainMapEntry> sortDomainMap(const SyncRes::domainmap_t& domainMap)
173 {
174 std::vector<DomainMapEntry> sorted{};
175 sorted.reserve(domainMap.size());
176 for (const auto& pair : domainMap) {
177 sorted.emplace_back(pair.first, pair.second);
178 }
179 std::stable_sort(std::begin(sorted), std::end(sorted), [](const DomainMapEntry& a, const DomainMapEntry& b) {
180 return a.first < b.first && a.second.d_name < b.second.d_name;
181 });
182 return sorted;
183 }
184
185 static std::string printDomainMap(const std::vector<DomainMapEntry>& domainMap)
186 {
187 std::stringstream s{};
188 for (const auto& entry : domainMap) {
189 s << "Entry `" << entry.first << "` {" << std::endl;
190 s << entry.second.print(" ");
191 s << "}" << std::endl;
192 }
193 return s.str();
194 }
195
196 std::vector<DomainMapEntry> getDomainMapFixture() const
197 {
198 return sortDomainMap(domainMapFixture);
199 }
200
201 std::vector<DomainMapEntry> getDomainMapFixtureWithSearchSuffix() const
202 {
203 return sortDomainMap(domainMapFixtureWithSearchSuffix);
204 }
205
206 private:
207 SyncRes::domainmap_t domainMapFixture{};
208 SyncRes::domainmap_t domainMapFixtureWithSearchSuffix{};
209 };
210
211 BOOST_FIXTURE_TEST_CASE(test_loading_etc_hosts, Fixture)
212 {
213 auto log = g_slog->withName("config");
214
215 auto domainMap = std::make_shared<SyncRes::domainmap_t>();
216 auto domainMapWithSearchSuffix = std::make_shared<SyncRes::domainmap_t>();
217 std::vector<std::string> parts{};
218 for (auto line : hostLines) {
219 BOOST_REQUIRE(parseEtcHostsLine(parts, line));
220 addForwardAndReverseLookupEntries(*domainMap, "", parts, log);
221 addForwardAndReverseLookupEntries(*domainMapWithSearchSuffix, "search.suffix", parts, log);
222 }
223
224 BOOST_TEST_MESSAGE("Actual and expected outputs without search suffixes:");
225
226 auto actual = sortDomainMap(*domainMap);
227 BOOST_TEST_MESSAGE("Actual:");
228 BOOST_TEST_MESSAGE(printDomainMap(actual));
229
230 auto expected = getDomainMapFixture();
231 BOOST_TEST_MESSAGE("Expected:");
232 BOOST_TEST_MESSAGE(printDomainMap(expected));
233
234 BOOST_CHECK_EQUAL(actual.size(), expected.size());
235 for (std::vector<DomainMapEntry>::size_type i = 0; i < actual.size(); i++) {
236 BOOST_CHECK(actual[i].first == expected[i].first);
237 BOOST_CHECK(actual[i].second == expected[i].second);
238 }
239
240 BOOST_TEST_MESSAGE("-----------------------------------------------------");
241
242 BOOST_TEST_MESSAGE("Actual and expected outputs with search suffixes:");
243
244 auto actualSearchSuffix = sortDomainMap(*domainMapWithSearchSuffix);
245 BOOST_TEST_MESSAGE("Actual (with search suffix):");
246 BOOST_TEST_MESSAGE(printDomainMap(actualSearchSuffix));
247
248 auto expectedSearchSuffix = getDomainMapFixtureWithSearchSuffix();
249 BOOST_TEST_MESSAGE("Expected (with search suffix):");
250 BOOST_TEST_MESSAGE(printDomainMap(expectedSearchSuffix));
251
252 BOOST_CHECK_EQUAL(actualSearchSuffix.size(), expectedSearchSuffix.size());
253 for (std::vector<DomainMapEntry>::size_type i = 0; i < actualSearchSuffix.size(); i++) {
254 BOOST_CHECK(actualSearchSuffix[i].first == expectedSearchSuffix[i].first);
255 BOOST_CHECK(actualSearchSuffix[i].second == expectedSearchSuffix[i].second);
256 }
257
258 BOOST_TEST_MESSAGE("-----------------------------------------------------");
259 }
260
261 const std::string hints = ". 3600 IN NS ns.\n"
262 ". 3600 IN NS ns1.\n"
263 "ns. 3600 IN A 192.168.178.16\n"
264 "ns. 3600 IN A 192.168.178.17\n"
265 "ns. 3600 IN A 192.168.178.18\n"
266 "ns. 3600 IN AAAA 1::2\n"
267 "ns. 3600 IN AAAA 1::3\n"
268 "ns1. 3600 IN A 192.168.178.18\n";
269
270 BOOST_AUTO_TEST_CASE(test_UserHints)
271 {
272
273 g_recCache = make_unique<MemRecursorCache>();
274
275 ::arg().set("max-generate-steps") = "0";
276 ::arg().set("max-include-depth") = "0";
277 char temp[] = "/tmp/hintsXXXXXXXXXX";
278 int fd = mkstemp(temp);
279 BOOST_REQUIRE(fd > 0);
280 FILE* fp = fdopen(fd, "w");
281 BOOST_REQUIRE(fp != nullptr);
282 size_t written = fwrite(hints.data(), 1, hints.length(), fp);
283 BOOST_REQUIRE(written == hints.length());
284 BOOST_REQUIRE(fclose(fp) == 0);
285
286 time_t now = time(nullptr);
287 std::vector<DNSRecord> nsvec;
288
289 auto ok = readHintsIntoCache(now, std::string(temp), nsvec);
290 BOOST_CHECK(ok);
291 BOOST_CHECK_EQUAL(nsvec.size(), 2U);
292
293 const MemRecursorCache::Flags flags = 0;
294
295 BOOST_CHECK(g_recCache->get(now, DNSName("ns"), QType::A, flags, &nsvec, ComboAddress()) > 0);
296 BOOST_CHECK_EQUAL(nsvec.size(), 3U);
297
298 BOOST_CHECK(g_recCache->get(now, DNSName("ns"), QType::AAAA, flags, &nsvec, ComboAddress()) > 0);
299 BOOST_CHECK_EQUAL(nsvec.size(), 2U);
300
301 BOOST_CHECK(g_recCache->get(now, DNSName("ns1"), QType::A, flags, &nsvec, ComboAddress()) > 0);
302 BOOST_CHECK_EQUAL(nsvec.size(), 1U);
303 }
304
305 BOOST_AUTO_TEST_SUITE_END()