blob: 6d3499764ba12c6385097f76a7ad115da0816e17 [file] [log] [blame]
Jiewen Tan870b29b2014-11-17 19:09:49 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Yumin Xia2c509c22017-02-09 14:37:36 -08002/*
Davide Pesavento1bff1b22020-06-08 18:46:05 -04003 * Copyright (c) 2014-2020, Regents of the University of California.
Jiewen Tan870b29b2014-11-17 19:09:49 -08004 *
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 "management-tool.hpp"
21#include "logger.hpp"
22#include "ndns-label.hpp"
23#include "ndns-tlv.hpp"
Yumin Xia2c509c22017-02-09 14:37:36 -080024#include "util/cert-helper.hpp"
Jiewen Tan870b29b2014-11-17 19:09:49 -080025
Jiewen Tan870b29b2014-11-17 19:09:49 -080026#include <iomanip>
Davide Pesavento948c50c2020-12-26 21:30:45 -050027#include <iostream>
Jiewen Tan870b29b2014-11-17 19:09:49 -080028
29#include <boost/filesystem/operations.hpp>
30#include <boost/filesystem/path.hpp>
31#include <boost/algorithm/string/replace.hpp>
Alexander Afanasyevd6b3bda2014-11-25 17:33:58 -080032#include <boost/lexical_cast.hpp>
Jiewen Tan870b29b2014-11-17 19:09:49 -080033
Jiewen Tan870b29b2014-11-17 19:09:49 -080034#include <ndn-cxx/util/regex.hpp>
Jiewen Tand1dd86d2015-03-20 10:26:28 -070035#include <ndn-cxx/util/indented-stream.hpp>
Yumin Xia2c509c22017-02-09 14:37:36 -080036#include <ndn-cxx/util/io.hpp>
Yumin Xia5dd9f2b2016-10-26 20:48:05 -070037#include <ndn-cxx/link.hpp>
Yumin Xiac5ed63f2017-01-26 13:44:38 -080038#include <ndn-cxx/security/signing-helpers.hpp>
Yumin Xia2c509c22017-02-09 14:37:36 -080039#include <ndn-cxx/security/transform.hpp>
40
Jiewen Tan870b29b2014-11-17 19:09:49 -080041
42namespace ndn {
43namespace ndns {
44
Alexander Afanasyev08d18742018-03-15 16:31:28 -040045NDNS_LOG_INIT(ManagementTool);
Jiewen Tan870b29b2014-11-17 19:09:49 -080046
Yumin Xia2c509c22017-02-09 14:37:36 -080047using security::transform::base64Encode;
48using security::transform::streamSink;
49using security::transform::bufferSource;
Alexander Afanasyev60514ec2020-06-03 14:18:53 -040050using security::Certificate;
Yumin Xia2c509c22017-02-09 14:37:36 -080051using security::Identity;
52using security::Key;
53
Alexander Afanasyevd6b3bda2014-11-25 17:33:58 -080054ManagementTool::ManagementTool(const std::string& dbFile, KeyChain& keyChain)
55 : m_keyChain(keyChain)
56 , m_dbMgr(dbFile)
Jiewen Tan870b29b2014-11-17 19:09:49 -080057{
58}
59
Yumin Xia2c509c22017-02-09 14:37:36 -080060Zone
61ManagementTool::createZone(const Name& zoneName,
Jiewen Tan870b29b2014-11-17 19:09:49 -080062 const Name& parentZoneName,
63 const time::seconds& cacheTtl,
Alexander Afanasyevd6b3bda2014-11-25 17:33:58 -080064 const time::seconds& certValidity,
Jiewen Tan870b29b2014-11-17 19:09:49 -080065 const Name& kskCertName,
Yumin Xia2c509c22017-02-09 14:37:36 -080066 const Name& dskCertName,
67 const Name& dkeyCertName)
Jiewen Tan870b29b2014-11-17 19:09:49 -080068{
69 bool isRoot = zoneName == ROOT_ZONE;
Yumin Xia918343d2017-03-17 19:04:55 -070070 Name zoneIdentityName = Name(zoneName).append(label::NDNS_ITERATIVE_QUERY);
Jiewen Tan870b29b2014-11-17 19:09:49 -080071
72 //check preconditions
73 Zone zone(zoneName, cacheTtl);
74 if (m_dbMgr.find(zone)) {
Davide Pesavento948c50c2020-12-26 21:30:45 -050075 NDN_THROW(Error(zoneName.toUri() + " is already present in the NDNS db"));
Jiewen Tan870b29b2014-11-17 19:09:49 -080076 }
77
78 if (!isRoot && parentZoneName.equals(zoneName)) {
Davide Pesavento948c50c2020-12-26 21:30:45 -050079 NDN_THROW(Error("Parent zone name can not be the zone itself"));
Jiewen Tan870b29b2014-11-17 19:09:49 -080080 }
81
82 if (!isRoot && !parentZoneName.isPrefixOf(zoneName)) {
Davide Pesavento948c50c2020-12-26 21:30:45 -050083 NDN_THROW(Error(parentZoneName.toUri() + " is not a prefix of " + zoneName.toUri()));
Jiewen Tan870b29b2014-11-17 19:09:49 -080084 }
85
Jiewen Tan01693fd2015-03-25 20:34:45 -070086 // if dsk is provided, there is no need to check ksk
Jiewen Tan870b29b2014-11-17 19:09:49 -080087 if (dskCertName != DEFAULT_CERT) {
Yumin Xia2c509c22017-02-09 14:37:36 -080088 if (!matchCertificate(dskCertName, zoneIdentityName)) {
Davide Pesavento948c50c2020-12-26 21:30:45 -050089 NDN_THROW(Error("Cannot verify DSK certificate"));
Jiewen Tan870b29b2014-11-17 19:09:49 -080090 }
91 }
Jiewen Tan01693fd2015-03-25 20:34:45 -070092 else if (kskCertName != DEFAULT_CERT) {
Yumin Xia2c509c22017-02-09 14:37:36 -080093 if (!matchCertificate(kskCertName, zoneIdentityName)) {
Davide Pesavento948c50c2020-12-26 21:30:45 -050094 NDN_THROW(Error("Cannot verify KSK certificate"));
Jiewen Tan01693fd2015-03-25 20:34:45 -070095 }
96 }
Jiewen Tan870b29b2014-11-17 19:09:49 -080097
Yumin Xia2c509c22017-02-09 14:37:36 -080098 if (dkeyCertName == DEFAULT_CERT && isRoot) {
Davide Pesavento948c50c2020-12-26 21:30:45 -050099 NDN_THROW(Error("Cannot generate dkey for root zone"));
Jiewen Tan870b29b2014-11-17 19:09:49 -0800100 }
101
Yumin Xia2c509c22017-02-09 14:37:36 -0800102 // Generate a parentZone's identity to generate a D-Key.
103 // This D-key will be passed to parent zone and resigned.
104 Name dkeyIdentityName;
105 if (dkeyCertName == DEFAULT_CERT) {
Yumin Xia918343d2017-03-17 19:04:55 -0700106 dkeyIdentityName = Name(parentZoneName).append(label::NDNS_ITERATIVE_QUERY)
Yumin Xia2c509c22017-02-09 14:37:36 -0800107 .append(zoneName.getSubName(parentZoneName.size()));
Jiewen Tan870b29b2014-11-17 19:09:49 -0800108 }
109 else {
Yumin Xia2c509c22017-02-09 14:37:36 -0800110 dkeyIdentityName = CertHelper::getIdentityNameFromCert(dkeyCertName);
111 }
112 NDNS_LOG_INFO("Generated D-Key's identityName: " + dkeyIdentityName.toUri());
113
114 Name dskName;
115 Key ksk;
116 Key dsk;
117 Key dkey;
118 Certificate dskCert;
119 Certificate kskCert;
120 Certificate dkeyCert;
121 Identity zoneIdentity = m_keyChain.createIdentity(zoneIdentityName);
122 Identity dkeyIdentity = m_keyChain.createIdentity(dkeyIdentityName);
123
124 if (dkeyCertName == DEFAULT_CERT) {
125 dkey = m_keyChain.createKey(dkeyIdentity);
126 m_keyChain.deleteCertificate(dkey, dkey.getDefaultCertificate().getName());
127
Yumin Xiafa2bce72017-04-09 16:20:25 -0700128 dkeyCert = CertHelper::createCertificate(m_keyChain, dkey, dkey, label::CERT_RR_TYPE.toUri(), certValidity);
Yumin Xia2c509c22017-02-09 14:37:36 -0800129 dkeyCert.setFreshnessPeriod(cacheTtl);
130 m_keyChain.addCertificate(dkey, dkeyCert);
131 NDNS_LOG_INFO("Generated DKEY: " << dkeyCert.getName());
132
133 }
134 else {
135 dkeyCert = CertHelper::getCertificate(m_keyChain, dkeyIdentityName, dkeyCertName);
136 dkey = dkeyIdentity.getKey(dkeyCert.getKeyName());
137 }
138
139 if (kskCertName == DEFAULT_CERT) {
140 ksk = m_keyChain.createKey(zoneIdentity);
141 // delete automatically generated certificates,
142 // because its issue is 'self' instead of CERT_RR_TYPE
143 m_keyChain.deleteCertificate(ksk, ksk.getDefaultCertificate().getName());
Yumin Xiafa2bce72017-04-09 16:20:25 -0700144 kskCert = CertHelper::createCertificate(m_keyChain, ksk, dkey, label::CERT_RR_TYPE.toUri(), certValidity);
Yumin Xia2c509c22017-02-09 14:37:36 -0800145 kskCert.setFreshnessPeriod(cacheTtl);
146 m_keyChain.addCertificate(ksk, kskCert);
147 NDNS_LOG_INFO("Generated KSK: " << kskCert.getName());
148 }
149 else {
150 // ksk usually might not be the default key of a zone
151 kskCert = CertHelper::getCertificate(m_keyChain, zoneIdentityName, kskCertName);
152 ksk = zoneIdentity.getKey(kskCert.getKeyName());
153 }
154
155 if (dskCertName == DEFAULT_CERT) {
156 // if no dsk provided, then generate a dsk either signed by ksk auto generated or user provided
157 dsk = m_keyChain.createKey(zoneIdentity);
158 m_keyChain.deleteCertificate(dsk, dsk.getDefaultCertificate().getName());
159 dskCert = CertHelper::createCertificate(m_keyChain, dsk, ksk, label::CERT_RR_TYPE.toUri(), certValidity);
160 dskCert.setFreshnessPeriod(cacheTtl);
161 // dskCert will become the default certificate, since the default cert has been deleted.
162 m_keyChain.addCertificate(dsk, dskCert);
163 m_keyChain.setDefaultKey(zoneIdentity, dsk);
164 NDNS_LOG_INFO("Generated DSK: " << dskCert.getName());
165 }
166 else {
167 dskCert = CertHelper::getCertificate(m_keyChain, zoneIdentityName, dskCertName);
168 dsk = zoneIdentity.getKey(dskCert.getKeyName());
169 m_keyChain.setDefaultKey(zoneIdentity, dsk);
170 m_keyChain.setDefaultCertificate(dsk, dskCert);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800171 }
172
173 //second add zone to the database
174 NDNS_LOG_INFO("Start adding new zone to data base");
175 addZone(zone);
176
177 //third create ID-cert
Yumin Xia2c509c22017-02-09 14:37:36 -0800178 NDNS_LOG_INFO("Start adding Certificates to NDNS database");
179 addIdCert(zone, kskCert, cacheTtl, dskCert);
180 addIdCert(zone, dskCert, cacheTtl, dskCert);
181
182 NDNS_LOG_INFO("Start saving KSK and DSK's id to ZoneInfo");
183 m_dbMgr.setZoneInfo(zone, "ksk", kskCert.wireEncode());
184 m_dbMgr.setZoneInfo(zone, "dsk", dskCert.wireEncode());
185
186 NDNS_LOG_INFO("Start saving DKEY certificate id to ZoneInfo");
187 m_dbMgr.setZoneInfo(zone, "dkey", dkeyCert.wireEncode());
188
Yumin Xia55a7cc42017-05-14 18:43:34 -0700189 generateDoe(zone);
Yumin Xia2c509c22017-02-09 14:37:36 -0800190 return zone;
Jiewen Tan870b29b2014-11-17 19:09:49 -0800191}
192
193void
194ManagementTool::deleteZone(const Name& zoneName)
195{
196 //check pre-conditions
197 Zone zone(zoneName);
198 if (!m_dbMgr.find(zone)) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500199 NDN_THROW(Error(zoneName.toUri() + " is not present in the NDNS db"));
Jiewen Tan870b29b2014-11-17 19:09:49 -0800200 }
201
202 //first remove all rrsets of this zone from local ndns database
203 std::vector<Rrset> rrsets = m_dbMgr.findRrsets(zone);
204 for (Rrset& rrset : rrsets) {
205 m_dbMgr.remove(rrset);
206 }
207
208 //second remove zone from local ndns database
209 removeZone(zone);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800210}
211
212void
213ManagementTool::exportCertificate(const Name& certName, const std::string& outFile)
214{
Yumin Xia2c509c22017-02-09 14:37:36 -0800215 // only search in local NDNS database
Alexander Afanasyev60514ec2020-06-03 14:18:53 -0400216 security::Certificate cert;
Yumin Xia2c509c22017-02-09 14:37:36 -0800217 shared_ptr<Regex> regex = make_shared<Regex>("(<>*)<NDNS>(<>+)<CERT><>");
218 if (!regex->match(certName)) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500219 NDN_THROW(Error("Certificate name is illegal"));
Yumin Xia2c509c22017-02-09 14:37:36 -0800220 return;
221 }
222
223 Name zoneName = regex->expand("\\1");
Yumin Xia918343d2017-03-17 19:04:55 -0700224 Name identityName = Name(zoneName).append(label::NDNS_ITERATIVE_QUERY);
Yumin Xia2c509c22017-02-09 14:37:36 -0800225 Name label = regex->expand("\\2");
226
227 Zone zone(zoneName);
228 Rrset rrset(&zone);
229 rrset.setLabel(label);
230 rrset.setType(label::CERT_RR_TYPE);
231 if (m_dbMgr.find(rrset)) {
Alexander Afanasyev60514ec2020-06-03 14:18:53 -0400232 cert = security::Certificate(rrset.getData());
Jiewen Tan870b29b2014-11-17 19:09:49 -0800233 }
234 else {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500235 NDN_THROW(Error("Cannot find the cert: " + certName.toUri()));
Jiewen Tan870b29b2014-11-17 19:09:49 -0800236 }
237
238 if (outFile == DEFAULT_IO) {
Yumin Xia2c509c22017-02-09 14:37:36 -0800239 ndn::io::save(cert, std::cout);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800240 }
241 else {
Yumin Xia2c509c22017-02-09 14:37:36 -0800242 ndn::io::save(cert, outFile);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800243 NDNS_LOG_INFO("save cert to file: " << outFile);
244 }
245}
246
247void
Yumin Xiaacd21332016-11-28 22:54:48 -0800248ManagementTool::addMultiLevelLabelRrset(Rrset& rrset,
249 RrsetFactory& zoneRrFactory,
250 const time::seconds& authTtl)
251{
252 const Name& label = rrset.getLabel();
253
254 // Check whether it is legal to insert the rrset
255 for (size_t i = 1; i <= label.size() - 1; i++) {
256 Name prefix = label.getPrefix(i);
257 Rrset prefixNsRr(rrset.getZone());
258 prefixNsRr.setLabel(prefix);
259 prefixNsRr.setType(label::NS_RR_TYPE);
260 if (m_dbMgr.find(prefixNsRr)) {
261 Data data(prefixNsRr.getData());
262 if (data.getContentType() == NDNS_LINK) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500263 NDN_THROW(Error("Cannot override " + boost::lexical_cast<std::string>(prefixNsRr) + " (NDNS_LINK)"));
Yumin Xiaacd21332016-11-28 22:54:48 -0800264 }
265 }
266 }
267
268 // check that it does not override existing AUTH
269 if (rrset.getType() == label::NS_RR_TYPE) {
270 Rrset rrsetCopy = rrset;
271 if (m_dbMgr.find(rrsetCopy)) {
272 if (Data(rrsetCopy.getData()).getContentType() == NDNS_AUTH) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500273 NDN_THROW(Error("Cannot override " + boost::lexical_cast<std::string>(rrsetCopy) + " (NDNS_AUTH)"));
Yumin Xiaacd21332016-11-28 22:54:48 -0800274 }
275 }
276 }
277
278 for (size_t i = 1; i <= label.size() - 1; i++) {
279 Name prefix = label.getPrefix(i);
280 Rrset prefixNsRr(rrset.getZone());
281 prefixNsRr.setLabel(prefix);
282 prefixNsRr.setType(label::NS_RR_TYPE);
283 if (m_dbMgr.find(prefixNsRr)) {
284 NDNS_LOG_INFO("NDNS_AUTH Rrset Label=" << prefix << " is already existed, insertion skipped");
285 continue;
286 }
287
Yumin Xiad4e8ce52017-03-17 19:56:52 -0700288 Rrset authRr = zoneRrFactory.generateAuthRrset(prefix,
Yumin Xiaacd21332016-11-28 22:54:48 -0800289 VERSION_USE_UNIX_TIMESTAMP, authTtl);
290 NDNS_LOG_INFO("Adding NDNS_AUTH " << authRr);
291 m_dbMgr.insert(authRr);
292 }
293
294 checkRrsetVersion(rrset);
295 NDNS_LOG_INFO("Adding " << rrset);
296 m_dbMgr.insert(rrset);
Yumin Xia55a7cc42017-05-14 18:43:34 -0700297 generateDoe(*rrset.getZone());
Yumin Xiaacd21332016-11-28 22:54:48 -0800298}
299
300void
Yumin Xia5dd9f2b2016-10-26 20:48:05 -0700301ManagementTool::addRrset(Rrset& rrset)
Jiewen Tan870b29b2014-11-17 19:09:49 -0800302{
Yumin Xiaacd21332016-11-28 22:54:48 -0800303 // check that it does not override existing AUTH
304 Rrset rrsetCopy = rrset;
305 rrsetCopy.setType(label::NS_RR_TYPE);
306 if (m_dbMgr.find(rrsetCopy)) {
307 if (Data(rrsetCopy.getData()).getContentType() == NDNS_AUTH) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500308 NDN_THROW(Error("Can not add this Rrset: it overrides a NDNS_AUTH record"));
Yumin Xiaacd21332016-11-28 22:54:48 -0800309 }
310 }
311
Jiewen Tan8cd35ea2015-03-20 00:44:23 -0700312 checkRrsetVersion(rrset);
Alexander Afanasyevd6b3bda2014-11-25 17:33:58 -0800313 NDNS_LOG_INFO("Added " << rrset);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800314 m_dbMgr.insert(rrset);
Yumin Xia55a7cc42017-05-14 18:43:34 -0700315 generateDoe(*rrset.getZone());
Jiewen Tan870b29b2014-11-17 19:09:49 -0800316}
317
318void
Yumin Xiac5ed63f2017-01-26 13:44:38 -0800319ManagementTool::addRrsetFromFile(const Name& zoneName,
320 const std::string& inFile,
321 const time::seconds& ttl,
322 const Name& inputDskCertName,
323 const ndn::io::IoEncoding encoding,
324 bool needResign)
Jiewen Tan870b29b2014-11-17 19:09:49 -0800325{
326 //check precondition
327 Zone zone(zoneName);
Yumin Xia918343d2017-03-17 19:04:55 -0700328 Name zoneIdentityName = Name(zoneName).append(label::NDNS_ITERATIVE_QUERY);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800329 if (!m_dbMgr.find(zone)) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500330 NDN_THROW(Error(zoneName.toUri() + " is not present in the NDNS db"));
Jiewen Tan870b29b2014-11-17 19:09:49 -0800331 }
332
333 Name dskName;
334 Name dskCertName = inputDskCertName;
335 if (dskCertName == DEFAULT_CERT) {
Yumin Xia2c509c22017-02-09 14:37:36 -0800336 dskName = CertHelper::getDefaultKeyNameOfIdentity(m_keyChain, zoneIdentityName);
337 dskCertName = CertHelper::getDefaultCertificateNameOfIdentity(m_keyChain, zoneIdentityName);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800338 }
339 else {
Yumin Xia2c509c22017-02-09 14:37:36 -0800340 if (!matchCertificate(dskCertName, zoneIdentityName)) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500341 NDN_THROW(Error("Cannot verify certificate"));
Jiewen Tan870b29b2014-11-17 19:09:49 -0800342 }
343 }
344
345 if (inFile != DEFAULT_IO) {
346 boost::filesystem::path dir = boost::filesystem::path(inFile);
347 if (!boost::filesystem::exists(dir) || boost::filesystem::is_directory(dir)) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500348 NDN_THROW(Error("Data: " + inFile + " does not exist"));
Jiewen Tan870b29b2014-11-17 19:09:49 -0800349 }
350 }
351
Yumin Xiac5ed63f2017-01-26 13:44:38 -0800352 // load data
Jiewen Tan870b29b2014-11-17 19:09:49 -0800353 shared_ptr<Data> data;
354 if (inFile == DEFAULT_IO)
Jiewen Tan74d745c2015-03-20 01:40:41 -0700355 data = ndn::io::load<ndn::Data>(std::cin, encoding);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800356 else
Jiewen Tan74d745c2015-03-20 01:40:41 -0700357 data = ndn::io::load<ndn::Data>(inFile, encoding);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800358
Jiewen Tand2d21822015-03-19 15:37:03 -0700359 if (data == nullptr) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500360 NDN_THROW(Error("input does not contain a valid Data packet"));
Jiewen Tand2d21822015-03-19 15:37:03 -0700361 }
362
Yumin Xiac5ed63f2017-01-26 13:44:38 -0800363 if (needResign) {
Yumin Xiafa2bce72017-04-09 16:20:25 -0700364 // TODO validityPeriod should be able to be configured
365 SignatureInfo info;
366 info.setValidityPeriod(security::ValidityPeriod(time::system_clock::now(),
367 time::system_clock::now() + DEFAULT_CERT_TTL));
368 m_keyChain.sign(*data, signingByCertificate(dskCertName).setSignatureInfo(info));
Jiewen Tan870b29b2014-11-17 19:09:49 -0800369 }
370
371 // create response for the input data
372 Response re;
Yumin Xia6343c5b2016-10-20 15:45:50 -0700373 re.fromData(zoneName, *data);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800374 Name label = re.getRrLabel();
375 name::Component type = re.getRrType();
376
377 Rrset rrset(&zone);
378 rrset.setLabel(label);
379 rrset.setType(type);
380 if (ttl == DEFAULT_RR_TTL)
381 rrset.setTtl(zone.getTtl());
382 else
383 rrset.setTtl(ttl);
384 rrset.setVersion(re.getVersion());
385 rrset.setData(data->wireEncode());
386
Jiewen Tan8cd35ea2015-03-20 00:44:23 -0700387 checkRrsetVersion(rrset);
Yumin Xia2c509c22017-02-09 14:37:36 -0800388 NDNS_LOG_INFO("Adding rrset from file " << rrset);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800389 m_dbMgr.insert(rrset);
Yumin Xia55a7cc42017-05-14 18:43:34 -0700390 generateDoe(*rrset.getZone());
Jiewen Tan870b29b2014-11-17 19:09:49 -0800391}
392
Alexander Afanasyev60514ec2020-06-03 14:18:53 -0400393security::Certificate
Yumin Xia2c509c22017-02-09 14:37:36 -0800394ManagementTool::getZoneDkey(Zone& zone)
395{
396 std::map<std::string, Block> zoneInfo = m_dbMgr.getZoneInfo(zone);
Alexander Afanasyev60514ec2020-06-03 14:18:53 -0400397 return security::Certificate(zoneInfo["dkey"]);
Yumin Xia2c509c22017-02-09 14:37:36 -0800398}
399
Jiewen Tan870b29b2014-11-17 19:09:49 -0800400void
Alexander Afanasyevd6b3bda2014-11-25 17:33:58 -0800401ManagementTool::listZone(const Name& zoneName, std::ostream& os, const bool printRaw)
402{
Jiewen Tan870b29b2014-11-17 19:09:49 -0800403 Zone zone(zoneName);
404 if (!m_dbMgr.find(zone)) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500405 NDN_THROW(Error("Zone " + zoneName.toUri() + " is not found in the database"));
Jiewen Tan870b29b2014-11-17 19:09:49 -0800406 }
407
408 //first output the zone name
409 os << "; Zone " << zoneName.toUri() << std::endl << std::endl;
410
411 //second output all rrsets
412 std::vector<Rrset> rrsets = m_dbMgr.findRrsets(zone);
413
414 //set width for different columns
415 size_t labelWidth = 0;
416 size_t ttlWidth = 0;
417 size_t typeWidth = 0;
418 for (Rrset& rrset : rrsets) {
419 Data data(rrset.getData());
420 Response re;
Yumin Xia6343c5b2016-10-20 15:45:50 -0700421 re.fromData(zoneName, data);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800422
423 if (rrset.getLabel().toUri().size() > labelWidth)
424 labelWidth = rrset.getLabel().toUri().size();
425
426 std::stringstream seconds;
427 seconds << rrset.getTtl().count();
428 if (seconds.str().size() > ttlWidth)
429 ttlWidth = seconds.str().size();
430
431 if (rrset.getType().toUri().size() > typeWidth)
432 typeWidth = rrset.getType().toUri().size();
433 }
434
435 //output
436 for (Rrset& rrset : rrsets) {
437 Data data(rrset.getData());
438 Response re;
Yumin Xia6343c5b2016-10-20 15:45:50 -0700439 re.fromData(zoneName, data);
Yumin Xia3c6b1fd2016-12-11 19:08:47 -0800440 int iteration = re.getContentType() == NDNS_BLOB
441 || re.getContentType() == NDNS_KEY
442 || re.getContentType() == NDNS_AUTH ? 1 : re.getRrs().size();
443
Yumin Xia2c509c22017-02-09 14:37:36 -0800444 const std::vector<Block>& rrs = re.getRrs();
Jiewen Tan870b29b2014-11-17 19:09:49 -0800445
Yumin Xia3c6b1fd2016-12-11 19:08:47 -0800446 if (re.getContentType() != NDNS_BLOB && re.getContentType() != NDNS_KEY) {
Jiewen Tan870b29b2014-11-17 19:09:49 -0800447 os << "; rrset=" << rrset.getLabel().toUri()
448 << " type=" << rrset.getType().toUri()
449 << " version=" << rrset.getVersion().toUri()
Davide Pesavento1bff1b22020-06-08 18:46:05 -0400450 << " signed-by=" << data.getKeyLocator()->getName().toUri()
Jiewen Tan870b29b2014-11-17 19:09:49 -0800451 << std::endl;
452 }
453
454 for (int i = 0; i < iteration; i++) {
455 os.setf(os.left);
456 os.width(labelWidth + 2);
457 os << rrset.getLabel().toUri();
458
459 os.width(ttlWidth + 2);
460 os << rrset.getTtl().count();
461
462 os.width(typeWidth + 2);
463 os << rrset.getType().toUri();
464
Yumin Xia3c6b1fd2016-12-11 19:08:47 -0800465 if (re.getContentType() != NDNS_BLOB && re.getContentType() != NDNS_KEY) {
Jiewen Tan870b29b2014-11-17 19:09:49 -0800466 if (rrset.getType() == label::TXT_RR_TYPE) {
467 os.write(reinterpret_cast<const char*>(rrs[i].value()), rrs[i].value_size());
468 os << std::endl;
469 }
470 else if (rrset.getType() == label::NS_RR_TYPE) {
Yumin Xia5dd9f2b2016-10-26 20:48:05 -0700471 BOOST_ASSERT(iteration == 1);
Yumin Xiaa484ba72016-11-10 20:40:12 -0800472 if (re.getContentType() == NDNS_AUTH) {
Yumin Xia5dd9f2b2016-10-26 20:48:05 -0700473 const std::string authStr = "NDNS-Auth";
474 os << authStr;
Yumin Xia2c509c22017-02-09 14:37:36 -0800475 }
476 else {
Yumin Xia5dd9f2b2016-10-26 20:48:05 -0700477 Link link(rrset.getData());
Yumin Xia2c509c22017-02-09 14:37:36 -0800478 const DelegationList& ds = link.getDelegationList();
Yumin Xia5dd9f2b2016-10-26 20:48:05 -0700479 for (const auto& i: ds) {
Yumin Xia2c509c22017-02-09 14:37:36 -0800480 std::string str = std::to_string(i.preference);
481 + "," + i.name.toUri() + ";";
Yumin Xia5dd9f2b2016-10-26 20:48:05 -0700482 os << str;
483 }
484 }
Jiewen Tan870b29b2014-11-17 19:09:49 -0800485 os << std::endl;
486 }
487 else {
Yumin Xia2c509c22017-02-09 14:37:36 -0800488 bufferSource(rrs[i].wire(), rrs[i].size()) >> base64Encode() >> streamSink(os);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800489 }
490 }
491 }
492
Yumin Xia3c6b1fd2016-12-11 19:08:47 -0800493 if (re.getContentType() == NDNS_BLOB || re.getContentType() == NDNS_KEY) {
Jiewen Tan870b29b2014-11-17 19:09:49 -0800494 os.width();
Yumin Xiaa484ba72016-11-10 20:40:12 -0800495 os << "; content-type=" << re.getContentType()
Jiewen Tan870b29b2014-11-17 19:09:49 -0800496 << " version=" << rrset.getVersion().toUri()
Davide Pesavento1bff1b22020-06-08 18:46:05 -0400497 << " signed-by=" << data.getKeyLocator()->getName().toUri();
Jiewen Tan870b29b2014-11-17 19:09:49 -0800498 os << std::endl;
499
Yumin Xia3c6b1fd2016-12-11 19:08:47 -0800500 if (printRaw && (re.getContentType() == NDNS_BLOB
501 || re.getContentType() == NDNS_KEY)) {
Yumin Xia2c509c22017-02-09 14:37:36 -0800502 ndn::util::IndentedStream istream(os, "; ");
Jiewen Tan870b29b2014-11-17 19:09:49 -0800503
Jiewen Tand1dd86d2015-03-20 10:26:28 -0700504 if (re.getRrType() == label::CERT_RR_TYPE) {
Alexander Afanasyev60514ec2020-06-03 14:18:53 -0400505 security::Certificate cert(rrset.getData());
Yumin Xia2c509c22017-02-09 14:37:36 -0800506 os << cert;
507 // cert.printCertificate(istream);
Jiewen Tand1dd86d2015-03-20 10:26:28 -0700508 }
509 else {
Yumin Xia2c509c22017-02-09 14:37:36 -0800510 bufferSource(re.getAppContent().wire(), re.getAppContent().size()) >> base64Encode() >> streamSink(os);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800511 }
Jiewen Tan870b29b2014-11-17 19:09:49 -0800512 }
Alexander Afanasyevd6b3bda2014-11-25 17:33:58 -0800513 os << std::endl;
Jiewen Tan870b29b2014-11-17 19:09:49 -0800514 }
515 else {
516 os << std::endl;
517 }
518 }
519}
520
521void
522ManagementTool::listAllZones(std::ostream& os) {
523 std::vector<Zone> zones = m_dbMgr.listZones();
524
525 size_t nameWidth = 0;
526 for (const Zone& zone : zones) {
527 if (zone.getName().toUri().size() > nameWidth)
528 nameWidth = zone.getName().toUri().size();
529 }
530
531 for (const Zone& zone : zones) {
532 os.setf(os.left);
533 os.width(nameWidth + 2);
534 os << zone.getName().toUri();
Yumin Xia918343d2017-03-17 19:04:55 -0700535 Name zoneIdentity = Name(zone.getName()).append(label::NDNS_ITERATIVE_QUERY);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800536
537 os << "; default-ttl=" << zone.getTtl().count();
Yumin Xia2c509c22017-02-09 14:37:36 -0800538 os << " default-key=" << CertHelper::getDefaultKeyNameOfIdentity(m_keyChain, zoneIdentity);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800539 os << " default-certificate="
Yumin Xia2c509c22017-02-09 14:37:36 -0800540 << CertHelper::getDefaultCertificateNameOfIdentity(m_keyChain, zoneIdentity);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800541 os << std::endl;
542 }
543}
544
545void
546ManagementTool::removeRrSet(const Name& zoneName, const Name& label, const name::Component& type)
547{
548 Zone zone(zoneName);
549 Rrset rrset(&zone);
550 rrset.setLabel(label);
551 rrset.setType(type);
552
553 if (!m_dbMgr.find(rrset)) {
554 return;
555 }
556 NDNS_LOG_INFO("Remove rrset with zone-id: " << zone.getId() << " label: " << label << " type: "
557 << type);
558 m_dbMgr.remove(rrset);
Yumin Xia55a7cc42017-05-14 18:43:34 -0700559 generateDoe(zone);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800560}
561
562void
563ManagementTool::getRrSet(const Name& zoneName,
564 const Name& label,
565 const name::Component& type,
566 std::ostream& os)
567{
568 Zone zone(zoneName);
569 Rrset rrset(&zone);
570 rrset.setLabel(label);
571 rrset.setType(type);
572
573 if (!m_dbMgr.find(rrset)) {
574 os << "No record is found" << std::endl;
575 return;
576 }
577
Yumin Xia2c509c22017-02-09 14:37:36 -0800578 bufferSource(rrset.getData().wire(), rrset.getData().size()) >> base64Encode() >> streamSink(os);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800579}
580
581void
Yumin Xia2c509c22017-02-09 14:37:36 -0800582ManagementTool::addIdCert(Zone& zone, const Certificate& cert,
583 const time::seconds& ttl,
584 const Certificate& dskCert)
Jiewen Tan870b29b2014-11-17 19:09:49 -0800585{
Yumin Xia2c509c22017-02-09 14:37:36 -0800586 Rrset rrsetKey(&zone);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800587 size_t size = zone.getName().size();
Yumin Xia2c509c22017-02-09 14:37:36 -0800588 Name label = cert.getName().getSubName(size + 1, cert.getName().size() - size - 3);
589 rrsetKey.setLabel(label);
590 rrsetKey.setType(label::CERT_RR_TYPE);
591 rrsetKey.setTtl(ttl);
592 rrsetKey.setVersion(cert.getName().get(-1));
593 rrsetKey.setData(cert.wireEncode());
Jiewen Tan870b29b2014-11-17 19:09:49 -0800594
Yumin Xia2c509c22017-02-09 14:37:36 -0800595 if (m_dbMgr.find(rrsetKey)) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500596 NDN_THROW(Error("CERT with label=" + label.toUri() +
597 " is already present in local NDNS database"));
Jiewen Tan870b29b2014-11-17 19:09:49 -0800598 }
Yumin Xia2c509c22017-02-09 14:37:36 -0800599
600 m_dbMgr.insert(rrsetKey);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800601 NDNS_LOG_INFO("Add rrset with zone-id: " << zone.getId() << " label: " << label << " type: "
602 << label::CERT_RR_TYPE);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800603}
604
605void
606ManagementTool::addZone(Zone& zone)
607{
608 if (m_dbMgr.find(zone)) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500609 NDN_THROW(Error("Zone with Name=" + zone.getName().toUri() +
610 " is already present in local NDNS database"));
Jiewen Tan870b29b2014-11-17 19:09:49 -0800611 }
612 NDNS_LOG_INFO("Add zone with Name: " << zone.getName().toUri());
613 m_dbMgr.insert(zone);
614}
615
616void
617ManagementTool::removeZone(Zone& zone)
618{
619 if (!m_dbMgr.find(zone)) {
620 return;
621 }
622 NDNS_LOG_INFO("Remove zone with Name: " << zone.getName().toUri());
623 m_dbMgr.remove(zone);
624}
625
626bool
627ManagementTool::matchCertificate(const Name& certName, const Name& identity)
628{
Yumin Xia2c509c22017-02-09 14:37:36 -0800629 security::Identity id = m_keyChain.getPib().getIdentity(identity);
630 for (const security::Key& key: id.getKeys()) {
631 try {
632 key.getCertificate(certName);
633 return true;
634 } catch (const std::exception&) {
635 }
Jiewen Tan870b29b2014-11-17 19:09:49 -0800636 }
Yumin Xia2c509c22017-02-09 14:37:36 -0800637 return false;
Jiewen Tan870b29b2014-11-17 19:09:49 -0800638}
639
Jiewen Tan8cd35ea2015-03-20 00:44:23 -0700640void
641ManagementTool::checkRrsetVersion(const Rrset& rrset)
642{
643 Rrset originalRrset(rrset);
644 if (m_dbMgr.find(originalRrset)) {
645 // update only if rrset has a newer version
646 if (originalRrset.getVersion() == rrset.getVersion()) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500647 NDN_THROW(Error("Duplicate: " + boost::lexical_cast<std::string>(originalRrset)));
Jiewen Tan8cd35ea2015-03-20 00:44:23 -0700648 }
649 else if (originalRrset.getVersion() > rrset.getVersion()) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500650 NDN_THROW(Error("Newer version exists: " + boost::lexical_cast<std::string>(originalRrset)));
Jiewen Tan8cd35ea2015-03-20 00:44:23 -0700651 }
652
653 m_dbMgr.remove(originalRrset);
654 }
655}
656
Yumin Xia55a7cc42017-05-14 18:43:34 -0700657void
658ManagementTool::generateDoe(Zone& zone)
659{
660 // check zone existence
661 if (!m_dbMgr.find(zone)) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500662 NDN_THROW(Error(zone.getName().toUri() + " is not present in the NDNS db"));
Yumin Xia55a7cc42017-05-14 18:43:34 -0700663 }
664
665 // remove all the Doe records
666 m_dbMgr.removeRrsetsOfZoneByType(zone, label::DOE_RR_TYPE);
667
668 // get the records out
669 std::vector<Rrset> allRecords = m_dbMgr.findRrsets(zone);
670
671 // sort them by DoE label name (same as in the database)
672 std::sort(allRecords.begin(), allRecords.end());
673
674 RrsetFactory factory(m_dbMgr.getDbFile(), zone.getName(), m_keyChain, DEFAULT_CERT);
675 factory.checkZoneKey();
676
677 for (size_t i = 0; i < allRecords.size() - 1; i++) {
678 Name lowerLabel = Name(allRecords[i].getLabel()).append(allRecords[i].getType());
679 Name upperLabel = Name(allRecords[i + 1].getLabel()).append(allRecords[i + 1].getType());
680 Rrset doe = factory.generateDoeRrset(lowerLabel,
681 VERSION_USE_UNIX_TIMESTAMP,
682 DEFAULT_CACHE_TTL, lowerLabel, upperLabel);
683 m_dbMgr.insert(doe);
684 }
685
686 Name lastLabel = Name(allRecords.back().getLabel()).append(allRecords.back().getType());
687 Name firstLabel = Name(allRecords.front().getLabel()).append(allRecords.front().getType());
688 Rrset lastRange = factory.generateDoeRrset(lastLabel,
689 VERSION_USE_UNIX_TIMESTAMP,
690 DEFAULT_CACHE_TTL, lastLabel, firstLabel);
691 m_dbMgr.insert(lastRange);
692
693 // This guard will be the lowest label-ranked record
694 // so if requested label+type is less than the lowest label except for this one, it will be choosed
695 // by findLowerBound. This small trick avoids complicated SQL query in findLowerBound
696 Rrset guardRange = factory.generateDoeRrset(Name(""),
697 VERSION_USE_UNIX_TIMESTAMP,
698 DEFAULT_CACHE_TTL, lastLabel, firstLabel);
699 m_dbMgr.insert(guardRange);
700 NDNS_LOG_INFO("DoE record updated");
701}
702
Jiewen Tan870b29b2014-11-17 19:09:49 -0800703} // namespace ndns
704} // namespace ndn