blob: 32f911c91b815bbb0533a2883bc6d18ac397c82d [file] [log] [blame]
Shock Jiangcde28712014-10-19 21:17:20 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
3 * Copyright (c) 2014, Regents of the University of California.
4 *
5 * This file is part of NDNS (Named Data Networking Domain Name Service).
6 * See AUTHORS.md for complete list of NDNS authors and contributors.
7 *
8 * NDNS is free software: you can redistribute it and/or modify it under the terms
9 * of the GNU General Public License as published by the Free Software Foundation,
10 * either version 3 of the License, or (at your option) any later version.
11 *
12 * NDNS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
13 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 * PURPOSE. See the GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * NDNS, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include "daemon/db-mgr.hpp"
21#include "daemon/name-server.hpp"
22#include "clients/response.hpp"
23#include "clients/query.hpp"
24#include "logger.hpp"
25
26#include "../database-test-data.hpp"
27#include "../../boost-test.hpp"
28
29#include <boost/filesystem.hpp>
30#include <ndn-cxx/face.hpp>
31#include <ndn-cxx/util/dummy-client-face.hpp>
32
33namespace ndn {
34namespace ndns {
35namespace tests {
36
Alexander Afanasyevc7c99002015-10-09 17:27:30 -070037NDNS_LOG_INIT("NameServerTest")
Shock Jiangcde28712014-10-19 21:17:20 -070038
39class NameServerFixture : public DbTestData
40{
41public:
42 NameServerFixture()
43 : face(ndn::util::makeDummyClientFace({ false, true }))
Shock Jiange1a81fd2014-11-20 20:25:49 -080044 , zone(m_root.getName())
Shock Jiangcde28712014-10-19 21:17:20 -070045 , validator(*face)
46 , server(zone, m_certName, *face, m_session, m_keyChain, validator)
47 {
48 // ensure prefix is registered
49 run();
50 }
51
52 void
53 run()
54 {
55 face->getIoService().poll();
56 face->getIoService().reset();
57 }
58
59public:
60 shared_ptr<ndn::util::DummyClientFace> face;
61 Name hint;
62 const Name& zone;
63 Validator validator;
64 ndns::NameServer server;
65};
66
67BOOST_FIXTURE_TEST_SUITE(NameServer, NameServerFixture)
68
69BOOST_AUTO_TEST_CASE(NdnsQuery)
70{
71 Query q(hint, zone, ndns::label::NDNS_ITERATIVE_QUERY);
Shock Jiange1a81fd2014-11-20 20:25:49 -080072 q.setRrLabel(Name("net"));
Shock Jiangcde28712014-10-19 21:17:20 -070073 q.setRrType(ndns::label::NS_RR_TYPE);
74
75 bool hasDataBack = false;
76
Junxiao Shi8f5be2a2015-01-06 10:06:43 -070077 face->onSendData.connectSingleShot([&] (const Data& data) {
Shock Jiangcde28712014-10-19 21:17:20 -070078 hasDataBack = true;
79 NDNS_LOG_TRACE("get Data back");
80 BOOST_CHECK_EQUAL(data.getName().getPrefix(-1), q.toInterest().getName());
81
82 Response resp;
83 BOOST_CHECK_NO_THROW(resp.fromData(hint, zone, data));
84 BOOST_CHECK_EQUAL(resp.getNdnsType(), NDNS_RESP);
Junxiao Shi8f5be2a2015-01-06 10:06:43 -070085 });
Shock Jiangcde28712014-10-19 21:17:20 -070086
87 face->receive(q.toInterest());
88
89 run();
90
91 BOOST_CHECK_EQUAL(hasDataBack, true);
92}
93
94BOOST_AUTO_TEST_CASE(KeyQuery)
95{
96 Query q(hint, zone, ndns::label::NDNS_ITERATIVE_QUERY);
97 q.setQueryType(ndns::label::NDNS_CERT_QUERY);
98 q.setRrType(ndns::label::CERT_RR_TYPE);
99
100 size_t nDataBack = 0;
101
102 // will ask for non-existing record
Junxiao Shi8f5be2a2015-01-06 10:06:43 -0700103 face->onSendData.connectSingleShot([&] (const Data& data) {
Shock Jiangcde28712014-10-19 21:17:20 -0700104 ++nDataBack;
105 NDNS_LOG_TRACE("get Data back");
106 BOOST_CHECK_EQUAL(data.getName().getPrefix(-1), q.toInterest().getName());
107
108 Response resp;
109 BOOST_CHECK_NO_THROW(resp.fromData(hint, zone, data));
110 BOOST_CHECK_EQUAL(resp.getNdnsType(), NDNS_NACK);
Junxiao Shi8f5be2a2015-01-06 10:06:43 -0700111 });
Shock Jiangcde28712014-10-19 21:17:20 -0700112
113 face->receive(q.toInterest());
114 run();
115
116 // will ask for the existing record (will have type NDNS_RAW, as it is certificate)
Junxiao Shi8f5be2a2015-01-06 10:06:43 -0700117 face->onSendData.connectSingleShot([&] (const Data& data) {
Shock Jiangcde28712014-10-19 21:17:20 -0700118 ++nDataBack;
119 NDNS_LOG_TRACE("get Data back");
120 BOOST_CHECK_EQUAL(data.getName().getPrefix(-1), q.toInterest().getName());
121
122 Response resp;
123 BOOST_CHECK_NO_THROW(resp.fromData(hint, zone, data));
124 BOOST_CHECK_EQUAL(resp.getNdnsType(), NDNS_RAW);
Junxiao Shi8f5be2a2015-01-06 10:06:43 -0700125 });
Shock Jiangcde28712014-10-19 21:17:20 -0700126
Shock Jiange1a81fd2014-11-20 20:25:49 -0800127 q.setRrLabel("dsk-1");
Shock Jiangcde28712014-10-19 21:17:20 -0700128
129 face->receive(q.toInterest());
130 run();
131
132 BOOST_CHECK_EQUAL(nDataBack, 2);
133}
134
135BOOST_AUTO_TEST_CASE(UpdateReplaceRr)
136{
137 Response re;
138 re.setZone(zone);
139 re.setQueryType(label::NDNS_ITERATIVE_QUERY);
Shock Jiange1a81fd2014-11-20 20:25:49 -0800140 re.setRrLabel(Name("net"));
Shock Jiangcde28712014-10-19 21:17:20 -0700141 re.setRrType(label::NS_RR_TYPE);
142 re.setNdnsType(NDNS_RESP);
143
144 std::string str = "ns1.ndnsim.net";
145 re.addRr(dataBlock(ndns::tlv::RrData, str.c_str(), str.size()));
146 str = "ns2.ndnsim.net";
147 re.addRr(dataBlock(ndns::tlv::RrData, str.c_str(), str.size()));
148
149 shared_ptr<Data> data = re.toData();
150 m_keyChain.sign(*data, m_certName);
151
152 Query q(Name(hint), Name(zone), ndns::label::NDNS_ITERATIVE_QUERY);
153 const Block& block = data->wireEncode();
154 Name name;
155 name.append(block);
156
157 q.setRrLabel(name);
158 q.setRrType(label::NDNS_UPDATE_LABEL);
159
160 bool hasDataBack = false;
161
Junxiao Shi8f5be2a2015-01-06 10:06:43 -0700162 face->onSendData.connectSingleShot([&] (const Data& data) {
Shock Jiangcde28712014-10-19 21:17:20 -0700163 hasDataBack = true;
164 NDNS_LOG_TRACE("get Data back");
165 BOOST_CHECK_EQUAL(data.getName().getPrefix(-1), q.toInterest().getName());
166 Response resp;
167
168 BOOST_CHECK_NO_THROW(resp.fromData(hint, zone, data));
Shock Jiangcde28712014-10-19 21:17:20 -0700169 BOOST_CHECK_EQUAL(resp.getNdnsType(), NDNS_RESP); // by default NDNS_RAW is enough
170 BOOST_CHECK_GT(resp.getRrs().size(), 0);
171 Block block = resp.getRrs()[0];
172 block.parse();
173 int ret = -1;
174 BOOST_CHECK_EQUAL(block.type(), ndns::tlv::RrData);
175 Block::element_const_iterator val = block.elements_begin();
176 BOOST_CHECK_EQUAL(val->type(), ndns::tlv::UpdateReturnCode); // the first must be return code
177 ret = readNonNegativeInteger(*val);
178 BOOST_CHECK_EQUAL(ret, 0);
Junxiao Shi8f5be2a2015-01-06 10:06:43 -0700179 });
Shock Jiangcde28712014-10-19 21:17:20 -0700180
181 face->receive(q.toInterest());
182 run();
183
184 BOOST_CHECK_EQUAL(hasDataBack, true);
185}
186
187BOOST_AUTO_TEST_CASE(UpdateInsertNewRr)
188{
189 Response re;
190 re.setZone(zone);
191 re.setQueryType(label::NDNS_ITERATIVE_QUERY);
Shock Jiange1a81fd2014-11-20 20:25:49 -0800192 re.setRrLabel(Name("net-XYZ")); // insert new records
Shock Jiangcde28712014-10-19 21:17:20 -0700193 re.setRrType(label::NS_RR_TYPE);
194 re.setNdnsType(NDNS_RESP);
195
196 std::string str = "ns1.ndnsim.net";
197 re.addRr(dataBlock(ndns::tlv::RrData, str.c_str(), str.size()));
198 str = "ns2.ndnsim.net";
199 re.addRr(dataBlock(ndns::tlv::RrData, str.c_str(), str.size()));
200
201 shared_ptr<Data> data = re.toData();
202 m_keyChain.sign(*data, m_certName);
203
204 Query q(Name(hint), Name(zone), ndns::label::NDNS_ITERATIVE_QUERY);
205 const Block& block = data->wireEncode();
206 Name name;
207 name.append(block);
208
209 q.setRrLabel(name);
210 q.setRrType(label::NDNS_UPDATE_LABEL);
211
212 bool hasDataBack = false;
213
Junxiao Shi8f5be2a2015-01-06 10:06:43 -0700214 face->onSendData.connectSingleShot([&] (const Data& data) {
Shock Jiangcde28712014-10-19 21:17:20 -0700215 hasDataBack = true;
216 NDNS_LOG_TRACE("get Data back");
217 BOOST_CHECK_EQUAL(data.getName().getPrefix(-1), q.toInterest().getName());
218 Response resp;
219
220 BOOST_CHECK_NO_THROW(resp.fromData(hint, zone, data));
Shock Jiangcde28712014-10-19 21:17:20 -0700221 BOOST_CHECK_EQUAL(resp.getNdnsType(), NDNS_RESP); // by default NDNS_RAW is enough
222 BOOST_CHECK_GT(resp.getRrs().size(), 0);
223 Block block = resp.getRrs()[0];
224 block.parse();
225 int ret = -1;
226 BOOST_CHECK_EQUAL(block.type(), ndns::tlv::RrData);
227 Block::element_const_iterator val = block.elements_begin();
228 BOOST_CHECK_EQUAL(val->type(), ndns::tlv::UpdateReturnCode); // the first must be return code
229 ret = readNonNegativeInteger(*val);
230 BOOST_CHECK_EQUAL(ret, 0);
Junxiao Shi8f5be2a2015-01-06 10:06:43 -0700231 });
Shock Jiangcde28712014-10-19 21:17:20 -0700232
233 face->receive(q.toInterest());
234 run();
235
236 BOOST_CHECK_EQUAL(hasDataBack, true);
237}
238
Shock Jiange1a81fd2014-11-20 20:25:49 -0800239BOOST_AUTO_TEST_CASE(UpdateValidatorCannotFetchCert)
240{
241 Name dskName = m_keyChain.generateRsaKeyPair(TEST_IDENTITY_NAME, false);
242 std::vector<CertificateSubjectDescription> desc;
243 time::system_clock::TimePoint notBefore = time::system_clock::now();
244 time::system_clock::TimePoint notAfter = notBefore + time::days(365);
245 shared_ptr<IdentityCertificate> dskCert =
246 m_keyChain.prepareUnsignedIdentityCertificate(dskName, m_certName,
247 notBefore, notAfter, desc);
248
249 m_keyChain.sign(*dskCert, m_certName);
250 m_keyChain.addCertificateAsKeyDefault(*dskCert);
251 NDNS_LOG_TRACE("KeyChain: add cert: " << dskCert->getName() << ". KeyLocator: "
252 << dskCert->getSignature().getKeyLocator().getName());
253
254 Rrset rrset(&m_root);
255 Name label = dskCert->getName().getPrefix(-2).getSubName(m_root.getName().size() + 1);
256 rrset.setLabel(label);
257 rrset.setType(label::CERT_RR_TYPE);
258 rrset.setVersion(dskCert->getName().get(-1));
259 rrset.setTtl(m_root.getTtl());
260 rrset.setData(dskCert->wireEncode());
261 m_session.insert(rrset);
262 NDNS_LOG_TRACE("DB: zone " << m_root << " add a ID-CERT RR with name="
263 << dskCert->getName() << " rrLabel=" << label);
264
265 Response re;
266 re.setZone(zone);
267 re.setQueryType(label::NDNS_ITERATIVE_QUERY);
268 re.setRrLabel(Name("ndnsim-XYZ")); // insert new records
269 re.setRrType(label::NS_RR_TYPE);
270 re.setNdnsType(NDNS_RESP);
271
272 std::string str = "ns1.ndnsim.net";
273 re.addRr(dataBlock(ndns::tlv::RrData, str.c_str(), str.size()));
274 str = "ns2.ndnsim.net";
275 re.addRr(dataBlock(ndns::tlv::RrData, str.c_str(), str.size()));
276
277 shared_ptr<Data> data = re.toData();
278 m_keyChain.sign(*data, dskCert->getName());
279
280 Query q(Name(hint), Name(zone), ndns::label::NDNS_ITERATIVE_QUERY);
281 const Block& block = data->wireEncode();
282 Name name;
283 name.append(block);
284
285 q.setRrLabel(name);
286 q.setRrType(label::NDNS_UPDATE_LABEL);
287
288 bool hasDataBack = false;
289
290 // no data back, since the Update cannot pass verification
Junxiao Shi8f5be2a2015-01-06 10:06:43 -0700291 face->onSendData.connectSingleShot([&] (const Data& data) {
Shock Jiange1a81fd2014-11-20 20:25:49 -0800292 hasDataBack = true;
293 BOOST_FAIL("UNEXPECTED");
Junxiao Shi8f5be2a2015-01-06 10:06:43 -0700294 });
Shock Jiange1a81fd2014-11-20 20:25:49 -0800295
296 face->receive(q.toInterest());
297 run();
298
299 BOOST_CHECK_EQUAL(hasDataBack, false);
300}
301
302class NameServerFixture2 : public DbTestData
303{
304public:
305 NameServerFixture2()
306 : face(ndn::util::makeDummyClientFace(io, { false, true }))
307 , validatorFace(ndn::util::makeDummyClientFace(io, { false, true }))
308 , zone(m_root.getName())
309 , validator(*validatorFace) // different face for validator
310 , server(zone, m_certName, *face, m_session, m_keyChain, validator)
311 {
312 // ensure prefix is registered
313 run();
Alexander Afanasyeva81266c2015-05-10 20:18:57 -0700314
315 validatorFace->onSendInterest.connect([this] (const Interest& interest) {
Shock Jiange1a81fd2014-11-20 20:25:49 -0800316 NDNS_LOG_TRACE("validatorFace get Interest: " << interest.getName());
Alexander Afanasyeva81266c2015-05-10 20:18:57 -0700317
318 shared_ptr<const Interest> i = interest.shared_from_this();
319 io.post([i, this] {
320 face->receive(*i);
321 });
Junxiao Shi8f5be2a2015-01-06 10:06:43 -0700322 });
Shock Jiange1a81fd2014-11-20 20:25:49 -0800323 }
324
325 void
326 run()
327 {
328 io.poll();
329 io.reset();
330 }
331
332public:
333 boost::asio::io_service io;
334 shared_ptr<ndn::util::DummyClientFace> face;
335 shared_ptr<ndn::util::DummyClientFace> validatorFace;
336 Name hint;
337 const Name& zone;
338 Validator validator;
339 ndns::NameServer server;
340};
341
342BOOST_FIXTURE_TEST_CASE(UpdateValidatorFetchCert, NameServerFixture2)
343{
344 Name dskName = m_keyChain.generateRsaKeyPair(TEST_IDENTITY_NAME, false);
345 std::vector<CertificateSubjectDescription> desc;
346 time::system_clock::TimePoint notBefore = time::system_clock::now();
347 time::system_clock::TimePoint notAfter = notBefore + time::days(365);
348 shared_ptr<IdentityCertificate> dskCert =
349 m_keyChain.prepareUnsignedIdentityCertificate(dskName, m_certName,
350 notBefore, notAfter, desc);
351
352 m_keyChain.sign(*dskCert, m_certName);
353 m_keyChain.addCertificateAsKeyDefault(*dskCert);
354 NDNS_LOG_TRACE("KeyChain: add cert: " << dskCert->getName() << ". KeyLocator: "
355 << dskCert->getSignature().getKeyLocator().getName());
356
357 Rrset rrset(&m_root);
358 Name label = dskCert->getName().getPrefix(-2).getSubName(m_root.getName().size() + 1);
359 rrset.setLabel(label);
360 rrset.setType(label::CERT_RR_TYPE);
361 rrset.setVersion(dskCert->getName().get(-1));
362 rrset.setTtl(m_root.getTtl());
363 rrset.setData(dskCert->wireEncode());
364 m_session.insert(rrset);
365 NDNS_LOG_TRACE("DB: zone " << m_root << " add a ID-CERT RR with name="
366 << dskCert->getName() << " rrLabel=" << label);
367
368 Response re;
369 re.setZone(zone);
370 re.setQueryType(label::NDNS_ITERATIVE_QUERY);
371 re.setRrLabel(Name("ndnsim-XYZ")); // insert new records
372 re.setRrType(label::NS_RR_TYPE);
373 re.setNdnsType(NDNS_RESP);
374
375 std::string str = "ns1.ndnsim.net";
376 re.addRr(dataBlock(ndns::tlv::RrData, str.c_str(), str.size()));
377 str = "ns2.ndnsim.net";
378 re.addRr(dataBlock(ndns::tlv::RrData, str.c_str(), str.size()));
379
380 shared_ptr<Data> data = re.toData();
381 m_keyChain.sign(*data, dskCert->getName());
382
383 Query q(Name(hint), Name(zone), ndns::label::NDNS_ITERATIVE_QUERY);
384 const Block& block = data->wireEncode();
385 Name name;
386 name.append(block);
387
388 q.setRrLabel(name);
389 q.setRrType(label::NDNS_UPDATE_LABEL);
390
391 bool hasDataBack = false;
392
393 shared_ptr<Regex> regex = make_shared<Regex>("(<>*)<KEY>(<>+)<ID-CERT><>");
Alexander Afanasyeva81266c2015-05-10 20:18:57 -0700394 face->onSendData.connect([&] (const Data& data) {
Shock Jiange1a81fd2014-11-20 20:25:49 -0800395 if (regex->match(data.getName())) {
Alexander Afanasyeva81266c2015-05-10 20:18:57 -0700396 shared_ptr<const Data> d = data.shared_from_this();
397 io.post([d, this] {
398 validatorFace->receive(*d); // It's data requested by validator
399 });
Shock Jiange1a81fd2014-11-20 20:25:49 -0800400 }
401 else {
402 // cert is requested by validator
403 hasDataBack = true;
404 NDNS_LOG_TRACE("get Data back");
405 BOOST_CHECK_EQUAL(data.getName().getPrefix(-1), q.toInterest().getName());
406 Response resp;
407
408 BOOST_CHECK_NO_THROW(resp.fromData(hint, zone, data));
Shock Jiange1a81fd2014-11-20 20:25:49 -0800409 BOOST_CHECK_EQUAL(resp.getNdnsType(), NDNS_RESP); // by default NDNS_RAW is enough
410 BOOST_CHECK_GT(resp.getRrs().size(), 0);
411 Block block = resp.getRrs()[0];
412 block.parse();
413 int ret = -1;
414 BOOST_CHECK_EQUAL(block.type(), ndns::tlv::RrData);
415 Block::element_const_iterator val = block.elements_begin();
416 BOOST_CHECK_EQUAL(val->type(), ndns::tlv::UpdateReturnCode); // the first must be return code
417 ret = readNonNegativeInteger(*val);
418 BOOST_CHECK_EQUAL(ret, 0);
419 }
Junxiao Shi8f5be2a2015-01-06 10:06:43 -0700420 });
Shock Jiange1a81fd2014-11-20 20:25:49 -0800421
422 face->receive(q.toInterest());
423 run();
424
425 BOOST_CHECK_EQUAL(hasDataBack, true);
426}
427
Shock Jiangcde28712014-10-19 21:17:20 -0700428BOOST_AUTO_TEST_SUITE_END()
429
430} // namespace tests
431} // namespace ndns
432} // namespace ndn