blob: 9ac88cfef3e20a5cc1b630af9092a618be7f3b91 [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/*
Junxiao Shi81e98762022-01-11 18:17:24 +00003 * Copyright (c) 2014-2022, 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 }
221
222 Name zoneName = regex->expand("\\1");
Yumin Xia918343d2017-03-17 19:04:55 -0700223 Name identityName = Name(zoneName).append(label::NDNS_ITERATIVE_QUERY);
Yumin Xia2c509c22017-02-09 14:37:36 -0800224 Name label = regex->expand("\\2");
225
226 Zone zone(zoneName);
227 Rrset rrset(&zone);
228 rrset.setLabel(label);
229 rrset.setType(label::CERT_RR_TYPE);
230 if (m_dbMgr.find(rrset)) {
Alexander Afanasyev60514ec2020-06-03 14:18:53 -0400231 cert = security::Certificate(rrset.getData());
Jiewen Tan870b29b2014-11-17 19:09:49 -0800232 }
233 else {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500234 NDN_THROW(Error("Cannot find the cert: " + certName.toUri()));
Jiewen Tan870b29b2014-11-17 19:09:49 -0800235 }
236
237 if (outFile == DEFAULT_IO) {
Yumin Xia2c509c22017-02-09 14:37:36 -0800238 ndn::io::save(cert, std::cout);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800239 }
240 else {
Yumin Xia2c509c22017-02-09 14:37:36 -0800241 ndn::io::save(cert, outFile);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800242 NDNS_LOG_INFO("save cert to file: " << outFile);
243 }
244}
245
246void
Yumin Xiaacd21332016-11-28 22:54:48 -0800247ManagementTool::addMultiLevelLabelRrset(Rrset& rrset,
248 RrsetFactory& zoneRrFactory,
249 const time::seconds& authTtl)
250{
251 const Name& label = rrset.getLabel();
252
253 // Check whether it is legal to insert the rrset
254 for (size_t i = 1; i <= label.size() - 1; i++) {
255 Name prefix = label.getPrefix(i);
256 Rrset prefixNsRr(rrset.getZone());
257 prefixNsRr.setLabel(prefix);
258 prefixNsRr.setType(label::NS_RR_TYPE);
259 if (m_dbMgr.find(prefixNsRr)) {
260 Data data(prefixNsRr.getData());
261 if (data.getContentType() == NDNS_LINK) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500262 NDN_THROW(Error("Cannot override " + boost::lexical_cast<std::string>(prefixNsRr) + " (NDNS_LINK)"));
Yumin Xiaacd21332016-11-28 22:54:48 -0800263 }
264 }
265 }
266
267 // check that it does not override existing AUTH
268 if (rrset.getType() == label::NS_RR_TYPE) {
269 Rrset rrsetCopy = rrset;
270 if (m_dbMgr.find(rrsetCopy)) {
271 if (Data(rrsetCopy.getData()).getContentType() == NDNS_AUTH) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500272 NDN_THROW(Error("Cannot override " + boost::lexical_cast<std::string>(rrsetCopy) + " (NDNS_AUTH)"));
Yumin Xiaacd21332016-11-28 22:54:48 -0800273 }
274 }
275 }
276
277 for (size_t i = 1; i <= label.size() - 1; i++) {
278 Name prefix = label.getPrefix(i);
279 Rrset prefixNsRr(rrset.getZone());
280 prefixNsRr.setLabel(prefix);
281 prefixNsRr.setType(label::NS_RR_TYPE);
282 if (m_dbMgr.find(prefixNsRr)) {
283 NDNS_LOG_INFO("NDNS_AUTH Rrset Label=" << prefix << " is already existed, insertion skipped");
284 continue;
285 }
286
Yumin Xiad4e8ce52017-03-17 19:56:52 -0700287 Rrset authRr = zoneRrFactory.generateAuthRrset(prefix,
Yumin Xiaacd21332016-11-28 22:54:48 -0800288 VERSION_USE_UNIX_TIMESTAMP, authTtl);
289 NDNS_LOG_INFO("Adding NDNS_AUTH " << authRr);
290 m_dbMgr.insert(authRr);
291 }
292
293 checkRrsetVersion(rrset);
294 NDNS_LOG_INFO("Adding " << rrset);
295 m_dbMgr.insert(rrset);
Yumin Xia55a7cc42017-05-14 18:43:34 -0700296 generateDoe(*rrset.getZone());
Yumin Xiaacd21332016-11-28 22:54:48 -0800297}
298
299void
Yumin Xia5dd9f2b2016-10-26 20:48:05 -0700300ManagementTool::addRrset(Rrset& rrset)
Jiewen Tan870b29b2014-11-17 19:09:49 -0800301{
Yumin Xiaacd21332016-11-28 22:54:48 -0800302 // check that it does not override existing AUTH
303 Rrset rrsetCopy = rrset;
304 rrsetCopy.setType(label::NS_RR_TYPE);
305 if (m_dbMgr.find(rrsetCopy)) {
306 if (Data(rrsetCopy.getData()).getContentType() == NDNS_AUTH) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500307 NDN_THROW(Error("Can not add this Rrset: it overrides a NDNS_AUTH record"));
Yumin Xiaacd21332016-11-28 22:54:48 -0800308 }
309 }
310
Jiewen Tan8cd35ea2015-03-20 00:44:23 -0700311 checkRrsetVersion(rrset);
Alexander Afanasyevd6b3bda2014-11-25 17:33:58 -0800312 NDNS_LOG_INFO("Added " << rrset);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800313 m_dbMgr.insert(rrset);
Yumin Xia55a7cc42017-05-14 18:43:34 -0700314 generateDoe(*rrset.getZone());
Jiewen Tan870b29b2014-11-17 19:09:49 -0800315}
316
317void
Yumin Xiac5ed63f2017-01-26 13:44:38 -0800318ManagementTool::addRrsetFromFile(const Name& zoneName,
319 const std::string& inFile,
320 const time::seconds& ttl,
321 const Name& inputDskCertName,
322 const ndn::io::IoEncoding encoding,
323 bool needResign)
Jiewen Tan870b29b2014-11-17 19:09:49 -0800324{
325 //check precondition
326 Zone zone(zoneName);
Yumin Xia918343d2017-03-17 19:04:55 -0700327 Name zoneIdentityName = Name(zoneName).append(label::NDNS_ITERATIVE_QUERY);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800328 if (!m_dbMgr.find(zone)) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500329 NDN_THROW(Error(zoneName.toUri() + " is not present in the NDNS db"));
Jiewen Tan870b29b2014-11-17 19:09:49 -0800330 }
331
332 Name dskName;
333 Name dskCertName = inputDskCertName;
334 if (dskCertName == DEFAULT_CERT) {
Yumin Xia2c509c22017-02-09 14:37:36 -0800335 dskName = CertHelper::getDefaultKeyNameOfIdentity(m_keyChain, zoneIdentityName);
336 dskCertName = CertHelper::getDefaultCertificateNameOfIdentity(m_keyChain, zoneIdentityName);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800337 }
338 else {
Yumin Xia2c509c22017-02-09 14:37:36 -0800339 if (!matchCertificate(dskCertName, zoneIdentityName)) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500340 NDN_THROW(Error("Cannot verify certificate"));
Jiewen Tan870b29b2014-11-17 19:09:49 -0800341 }
342 }
343
344 if (inFile != DEFAULT_IO) {
345 boost::filesystem::path dir = boost::filesystem::path(inFile);
346 if (!boost::filesystem::exists(dir) || boost::filesystem::is_directory(dir)) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500347 NDN_THROW(Error("Data: " + inFile + " does not exist"));
Jiewen Tan870b29b2014-11-17 19:09:49 -0800348 }
349 }
350
Yumin Xiac5ed63f2017-01-26 13:44:38 -0800351 // load data
Jiewen Tan870b29b2014-11-17 19:09:49 -0800352 shared_ptr<Data> data;
353 if (inFile == DEFAULT_IO)
Jiewen Tan74d745c2015-03-20 01:40:41 -0700354 data = ndn::io::load<ndn::Data>(std::cin, encoding);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800355 else
Jiewen Tan74d745c2015-03-20 01:40:41 -0700356 data = ndn::io::load<ndn::Data>(inFile, encoding);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800357
Jiewen Tand2d21822015-03-19 15:37:03 -0700358 if (data == nullptr) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500359 NDN_THROW(Error("input does not contain a valid Data packet"));
Jiewen Tand2d21822015-03-19 15:37:03 -0700360 }
361
Yumin Xiac5ed63f2017-01-26 13:44:38 -0800362 if (needResign) {
Yumin Xiafa2bce72017-04-09 16:20:25 -0700363 // TODO validityPeriod should be able to be configured
364 SignatureInfo info;
365 info.setValidityPeriod(security::ValidityPeriod(time::system_clock::now(),
366 time::system_clock::now() + DEFAULT_CERT_TTL));
367 m_keyChain.sign(*data, signingByCertificate(dskCertName).setSignatureInfo(info));
Jiewen Tan870b29b2014-11-17 19:09:49 -0800368 }
369
370 // create response for the input data
371 Response re;
Yumin Xia6343c5b2016-10-20 15:45:50 -0700372 re.fromData(zoneName, *data);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800373 Name label = re.getRrLabel();
374 name::Component type = re.getRrType();
375
376 Rrset rrset(&zone);
377 rrset.setLabel(label);
378 rrset.setType(type);
379 if (ttl == DEFAULT_RR_TTL)
380 rrset.setTtl(zone.getTtl());
381 else
382 rrset.setTtl(ttl);
383 rrset.setVersion(re.getVersion());
384 rrset.setData(data->wireEncode());
385
Jiewen Tan8cd35ea2015-03-20 00:44:23 -0700386 checkRrsetVersion(rrset);
Yumin Xia2c509c22017-02-09 14:37:36 -0800387 NDNS_LOG_INFO("Adding rrset from file " << rrset);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800388 m_dbMgr.insert(rrset);
Yumin Xia55a7cc42017-05-14 18:43:34 -0700389 generateDoe(*rrset.getZone());
Jiewen Tan870b29b2014-11-17 19:09:49 -0800390}
391
Alexander Afanasyev60514ec2020-06-03 14:18:53 -0400392security::Certificate
Yumin Xia2c509c22017-02-09 14:37:36 -0800393ManagementTool::getZoneDkey(Zone& zone)
394{
395 std::map<std::string, Block> zoneInfo = m_dbMgr.getZoneInfo(zone);
Alexander Afanasyev60514ec2020-06-03 14:18:53 -0400396 return security::Certificate(zoneInfo["dkey"]);
Yumin Xia2c509c22017-02-09 14:37:36 -0800397}
398
Jiewen Tan870b29b2014-11-17 19:09:49 -0800399void
Alexander Afanasyevd6b3bda2014-11-25 17:33:58 -0800400ManagementTool::listZone(const Name& zoneName, std::ostream& os, const bool printRaw)
401{
Jiewen Tan870b29b2014-11-17 19:09:49 -0800402 Zone zone(zoneName);
403 if (!m_dbMgr.find(zone)) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500404 NDN_THROW(Error("Zone " + zoneName.toUri() + " is not found in the database"));
Jiewen Tan870b29b2014-11-17 19:09:49 -0800405 }
406
407 //first output the zone name
408 os << "; Zone " << zoneName.toUri() << std::endl << std::endl;
409
410 //second output all rrsets
411 std::vector<Rrset> rrsets = m_dbMgr.findRrsets(zone);
412
413 //set width for different columns
414 size_t labelWidth = 0;
415 size_t ttlWidth = 0;
416 size_t typeWidth = 0;
417 for (Rrset& rrset : rrsets) {
418 Data data(rrset.getData());
419 Response re;
Yumin Xia6343c5b2016-10-20 15:45:50 -0700420 re.fromData(zoneName, data);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800421
422 if (rrset.getLabel().toUri().size() > labelWidth)
423 labelWidth = rrset.getLabel().toUri().size();
424
425 std::stringstream seconds;
426 seconds << rrset.getTtl().count();
427 if (seconds.str().size() > ttlWidth)
428 ttlWidth = seconds.str().size();
429
430 if (rrset.getType().toUri().size() > typeWidth)
431 typeWidth = rrset.getType().toUri().size();
432 }
433
434 //output
435 for (Rrset& rrset : rrsets) {
436 Data data(rrset.getData());
437 Response re;
Yumin Xia6343c5b2016-10-20 15:45:50 -0700438 re.fromData(zoneName, data);
Yumin Xia3c6b1fd2016-12-11 19:08:47 -0800439 int iteration = re.getContentType() == NDNS_BLOB
440 || re.getContentType() == NDNS_KEY
441 || re.getContentType() == NDNS_AUTH ? 1 : re.getRrs().size();
442
Yumin Xia2c509c22017-02-09 14:37:36 -0800443 const std::vector<Block>& rrs = re.getRrs();
Jiewen Tan870b29b2014-11-17 19:09:49 -0800444
Yumin Xia3c6b1fd2016-12-11 19:08:47 -0800445 if (re.getContentType() != NDNS_BLOB && re.getContentType() != NDNS_KEY) {
Jiewen Tan870b29b2014-11-17 19:09:49 -0800446 os << "; rrset=" << rrset.getLabel().toUri()
447 << " type=" << rrset.getType().toUri()
448 << " version=" << rrset.getVersion().toUri()
Davide Pesavento1bff1b22020-06-08 18:46:05 -0400449 << " signed-by=" << data.getKeyLocator()->getName().toUri()
Jiewen Tan870b29b2014-11-17 19:09:49 -0800450 << std::endl;
451 }
452
453 for (int i = 0; i < iteration; i++) {
454 os.setf(os.left);
455 os.width(labelWidth + 2);
456 os << rrset.getLabel().toUri();
457
458 os.width(ttlWidth + 2);
459 os << rrset.getTtl().count();
460
461 os.width(typeWidth + 2);
462 os << rrset.getType().toUri();
463
Yumin Xia3c6b1fd2016-12-11 19:08:47 -0800464 if (re.getContentType() != NDNS_BLOB && re.getContentType() != NDNS_KEY) {
Jiewen Tan870b29b2014-11-17 19:09:49 -0800465 if (rrset.getType() == label::TXT_RR_TYPE) {
466 os.write(reinterpret_cast<const char*>(rrs[i].value()), rrs[i].value_size());
467 os << std::endl;
468 }
469 else if (rrset.getType() == label::NS_RR_TYPE) {
Yumin Xia5dd9f2b2016-10-26 20:48:05 -0700470 BOOST_ASSERT(iteration == 1);
Yumin Xiaa484ba72016-11-10 20:40:12 -0800471 if (re.getContentType() == NDNS_AUTH) {
Yumin Xia5dd9f2b2016-10-26 20:48:05 -0700472 const std::string authStr = "NDNS-Auth";
473 os << authStr;
Yumin Xia2c509c22017-02-09 14:37:36 -0800474 }
475 else {
Yumin Xia5dd9f2b2016-10-26 20:48:05 -0700476 Link link(rrset.getData());
Junxiao Shi81e98762022-01-11 18:17:24 +0000477 for (const auto& delegation : link.getDelegationList()) {
478 os << delegation << ";";
Yumin Xia5dd9f2b2016-10-26 20:48:05 -0700479 }
480 }
Jiewen Tan870b29b2014-11-17 19:09:49 -0800481 os << std::endl;
482 }
483 else {
Davide Pesavento98026122022-03-14 22:00:03 -0400484 bufferSource(rrs[i]) >> base64Encode() >> streamSink(os);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800485 }
486 }
487 }
488
Yumin Xia3c6b1fd2016-12-11 19:08:47 -0800489 if (re.getContentType() == NDNS_BLOB || re.getContentType() == NDNS_KEY) {
Jiewen Tan870b29b2014-11-17 19:09:49 -0800490 os.width();
Yumin Xiaa484ba72016-11-10 20:40:12 -0800491 os << "; content-type=" << re.getContentType()
Jiewen Tan870b29b2014-11-17 19:09:49 -0800492 << " version=" << rrset.getVersion().toUri()
Davide Pesavento1bff1b22020-06-08 18:46:05 -0400493 << " signed-by=" << data.getKeyLocator()->getName().toUri();
Jiewen Tan870b29b2014-11-17 19:09:49 -0800494 os << std::endl;
495
Yumin Xia3c6b1fd2016-12-11 19:08:47 -0800496 if (printRaw && (re.getContentType() == NDNS_BLOB
497 || re.getContentType() == NDNS_KEY)) {
Yumin Xia2c509c22017-02-09 14:37:36 -0800498 ndn::util::IndentedStream istream(os, "; ");
Jiewen Tan870b29b2014-11-17 19:09:49 -0800499
Jiewen Tand1dd86d2015-03-20 10:26:28 -0700500 if (re.getRrType() == label::CERT_RR_TYPE) {
Alexander Afanasyev60514ec2020-06-03 14:18:53 -0400501 security::Certificate cert(rrset.getData());
Yumin Xia2c509c22017-02-09 14:37:36 -0800502 os << cert;
503 // cert.printCertificate(istream);
Jiewen Tand1dd86d2015-03-20 10:26:28 -0700504 }
505 else {
Davide Pesavento98026122022-03-14 22:00:03 -0400506 bufferSource(re.getAppContent()) >> base64Encode() >> streamSink(os);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800507 }
Jiewen Tan870b29b2014-11-17 19:09:49 -0800508 }
Alexander Afanasyevd6b3bda2014-11-25 17:33:58 -0800509 os << std::endl;
Jiewen Tan870b29b2014-11-17 19:09:49 -0800510 }
511 else {
512 os << std::endl;
513 }
514 }
515}
516
517void
518ManagementTool::listAllZones(std::ostream& os) {
519 std::vector<Zone> zones = m_dbMgr.listZones();
520
521 size_t nameWidth = 0;
522 for (const Zone& zone : zones) {
523 if (zone.getName().toUri().size() > nameWidth)
524 nameWidth = zone.getName().toUri().size();
525 }
526
527 for (const Zone& zone : zones) {
528 os.setf(os.left);
529 os.width(nameWidth + 2);
530 os << zone.getName().toUri();
Yumin Xia918343d2017-03-17 19:04:55 -0700531 Name zoneIdentity = Name(zone.getName()).append(label::NDNS_ITERATIVE_QUERY);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800532
533 os << "; default-ttl=" << zone.getTtl().count();
Yumin Xia2c509c22017-02-09 14:37:36 -0800534 os << " default-key=" << CertHelper::getDefaultKeyNameOfIdentity(m_keyChain, zoneIdentity);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800535 os << " default-certificate="
Yumin Xia2c509c22017-02-09 14:37:36 -0800536 << CertHelper::getDefaultCertificateNameOfIdentity(m_keyChain, zoneIdentity);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800537 os << std::endl;
538 }
539}
540
541void
542ManagementTool::removeRrSet(const Name& zoneName, const Name& label, const name::Component& type)
543{
544 Zone zone(zoneName);
545 Rrset rrset(&zone);
546 rrset.setLabel(label);
547 rrset.setType(type);
548
549 if (!m_dbMgr.find(rrset)) {
550 return;
551 }
552 NDNS_LOG_INFO("Remove rrset with zone-id: " << zone.getId() << " label: " << label << " type: "
553 << type);
554 m_dbMgr.remove(rrset);
Yumin Xia55a7cc42017-05-14 18:43:34 -0700555 generateDoe(zone);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800556}
557
558void
559ManagementTool::getRrSet(const Name& zoneName,
560 const Name& label,
561 const name::Component& type,
562 std::ostream& os)
563{
564 Zone zone(zoneName);
565 Rrset rrset(&zone);
566 rrset.setLabel(label);
567 rrset.setType(type);
568
569 if (!m_dbMgr.find(rrset)) {
570 os << "No record is found" << std::endl;
571 return;
572 }
573
Davide Pesavento98026122022-03-14 22:00:03 -0400574 bufferSource(rrset.getData()) >> base64Encode() >> streamSink(os);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800575}
576
577void
Yumin Xia2c509c22017-02-09 14:37:36 -0800578ManagementTool::addIdCert(Zone& zone, const Certificate& cert,
579 const time::seconds& ttl,
580 const Certificate& dskCert)
Jiewen Tan870b29b2014-11-17 19:09:49 -0800581{
Yumin Xia2c509c22017-02-09 14:37:36 -0800582 Rrset rrsetKey(&zone);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800583 size_t size = zone.getName().size();
Yumin Xia2c509c22017-02-09 14:37:36 -0800584 Name label = cert.getName().getSubName(size + 1, cert.getName().size() - size - 3);
585 rrsetKey.setLabel(label);
586 rrsetKey.setType(label::CERT_RR_TYPE);
587 rrsetKey.setTtl(ttl);
588 rrsetKey.setVersion(cert.getName().get(-1));
589 rrsetKey.setData(cert.wireEncode());
Jiewen Tan870b29b2014-11-17 19:09:49 -0800590
Yumin Xia2c509c22017-02-09 14:37:36 -0800591 if (m_dbMgr.find(rrsetKey)) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500592 NDN_THROW(Error("CERT with label=" + label.toUri() +
593 " is already present in local NDNS database"));
Jiewen Tan870b29b2014-11-17 19:09:49 -0800594 }
Yumin Xia2c509c22017-02-09 14:37:36 -0800595
596 m_dbMgr.insert(rrsetKey);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800597 NDNS_LOG_INFO("Add rrset with zone-id: " << zone.getId() << " label: " << label << " type: "
598 << label::CERT_RR_TYPE);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800599}
600
601void
602ManagementTool::addZone(Zone& zone)
603{
604 if (m_dbMgr.find(zone)) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500605 NDN_THROW(Error("Zone with Name=" + zone.getName().toUri() +
606 " is already present in local NDNS database"));
Jiewen Tan870b29b2014-11-17 19:09:49 -0800607 }
608 NDNS_LOG_INFO("Add zone with Name: " << zone.getName().toUri());
609 m_dbMgr.insert(zone);
610}
611
612void
613ManagementTool::removeZone(Zone& zone)
614{
615 if (!m_dbMgr.find(zone)) {
616 return;
617 }
618 NDNS_LOG_INFO("Remove zone with Name: " << zone.getName().toUri());
619 m_dbMgr.remove(zone);
620}
621
622bool
623ManagementTool::matchCertificate(const Name& certName, const Name& identity)
624{
Yumin Xia2c509c22017-02-09 14:37:36 -0800625 security::Identity id = m_keyChain.getPib().getIdentity(identity);
Davide Pesavento98026122022-03-14 22:00:03 -0400626 for (const security::Key& key : id.getKeys()) {
Yumin Xia2c509c22017-02-09 14:37:36 -0800627 try {
628 key.getCertificate(certName);
629 return true;
Davide Pesavento98026122022-03-14 22:00:03 -0400630 }
631 catch (const std::exception&) {
Yumin Xia2c509c22017-02-09 14:37:36 -0800632 }
Jiewen Tan870b29b2014-11-17 19:09:49 -0800633 }
Yumin Xia2c509c22017-02-09 14:37:36 -0800634 return false;
Jiewen Tan870b29b2014-11-17 19:09:49 -0800635}
636
Jiewen Tan8cd35ea2015-03-20 00:44:23 -0700637void
638ManagementTool::checkRrsetVersion(const Rrset& rrset)
639{
640 Rrset originalRrset(rrset);
641 if (m_dbMgr.find(originalRrset)) {
642 // update only if rrset has a newer version
643 if (originalRrset.getVersion() == rrset.getVersion()) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500644 NDN_THROW(Error("Duplicate: " + boost::lexical_cast<std::string>(originalRrset)));
Jiewen Tan8cd35ea2015-03-20 00:44:23 -0700645 }
646 else if (originalRrset.getVersion() > rrset.getVersion()) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500647 NDN_THROW(Error("Newer version exists: " + boost::lexical_cast<std::string>(originalRrset)));
Jiewen Tan8cd35ea2015-03-20 00:44:23 -0700648 }
649
650 m_dbMgr.remove(originalRrset);
651 }
652}
653
Yumin Xia55a7cc42017-05-14 18:43:34 -0700654void
655ManagementTool::generateDoe(Zone& zone)
656{
657 // check zone existence
658 if (!m_dbMgr.find(zone)) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500659 NDN_THROW(Error(zone.getName().toUri() + " is not present in the NDNS db"));
Yumin Xia55a7cc42017-05-14 18:43:34 -0700660 }
661
662 // remove all the Doe records
663 m_dbMgr.removeRrsetsOfZoneByType(zone, label::DOE_RR_TYPE);
664
665 // get the records out
666 std::vector<Rrset> allRecords = m_dbMgr.findRrsets(zone);
667
668 // sort them by DoE label name (same as in the database)
669 std::sort(allRecords.begin(), allRecords.end());
670
671 RrsetFactory factory(m_dbMgr.getDbFile(), zone.getName(), m_keyChain, DEFAULT_CERT);
672 factory.checkZoneKey();
673
674 for (size_t i = 0; i < allRecords.size() - 1; i++) {
675 Name lowerLabel = Name(allRecords[i].getLabel()).append(allRecords[i].getType());
676 Name upperLabel = Name(allRecords[i + 1].getLabel()).append(allRecords[i + 1].getType());
677 Rrset doe = factory.generateDoeRrset(lowerLabel,
678 VERSION_USE_UNIX_TIMESTAMP,
679 DEFAULT_CACHE_TTL, lowerLabel, upperLabel);
680 m_dbMgr.insert(doe);
681 }
682
683 Name lastLabel = Name(allRecords.back().getLabel()).append(allRecords.back().getType());
684 Name firstLabel = Name(allRecords.front().getLabel()).append(allRecords.front().getType());
685 Rrset lastRange = factory.generateDoeRrset(lastLabel,
686 VERSION_USE_UNIX_TIMESTAMP,
687 DEFAULT_CACHE_TTL, lastLabel, firstLabel);
688 m_dbMgr.insert(lastRange);
689
690 // This guard will be the lowest label-ranked record
691 // so if requested label+type is less than the lowest label except for this one, it will be choosed
692 // by findLowerBound. This small trick avoids complicated SQL query in findLowerBound
693 Rrset guardRange = factory.generateDoeRrset(Name(""),
694 VERSION_USE_UNIX_TIMESTAMP,
695 DEFAULT_CACHE_TTL, lastLabel, firstLabel);
696 m_dbMgr.insert(guardRange);
697 NDNS_LOG_INFO("DoE record updated");
698}
699
Jiewen Tan870b29b2014-11-17 19:09:49 -0800700} // namespace ndns
701} // namespace ndn