blob: 02299c94cb5f031a6940585285e48975a28e2a31 [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 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());
Junxiao Shi81e98762022-01-11 18:17:24 +0000478 for (const auto& delegation : link.getDelegationList()) {
479 os << delegation << ";";
Yumin Xia5dd9f2b2016-10-26 20:48:05 -0700480 }
481 }
Jiewen Tan870b29b2014-11-17 19:09:49 -0800482 os << std::endl;
483 }
484 else {
Yumin Xia2c509c22017-02-09 14:37:36 -0800485 bufferSource(rrs[i].wire(), rrs[i].size()) >> base64Encode() >> streamSink(os);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800486 }
487 }
488 }
489
Yumin Xia3c6b1fd2016-12-11 19:08:47 -0800490 if (re.getContentType() == NDNS_BLOB || re.getContentType() == NDNS_KEY) {
Jiewen Tan870b29b2014-11-17 19:09:49 -0800491 os.width();
Yumin Xiaa484ba72016-11-10 20:40:12 -0800492 os << "; content-type=" << re.getContentType()
Jiewen Tan870b29b2014-11-17 19:09:49 -0800493 << " version=" << rrset.getVersion().toUri()
Davide Pesavento1bff1b22020-06-08 18:46:05 -0400494 << " signed-by=" << data.getKeyLocator()->getName().toUri();
Jiewen Tan870b29b2014-11-17 19:09:49 -0800495 os << std::endl;
496
Yumin Xia3c6b1fd2016-12-11 19:08:47 -0800497 if (printRaw && (re.getContentType() == NDNS_BLOB
498 || re.getContentType() == NDNS_KEY)) {
Yumin Xia2c509c22017-02-09 14:37:36 -0800499 ndn::util::IndentedStream istream(os, "; ");
Jiewen Tan870b29b2014-11-17 19:09:49 -0800500
Jiewen Tand1dd86d2015-03-20 10:26:28 -0700501 if (re.getRrType() == label::CERT_RR_TYPE) {
Alexander Afanasyev60514ec2020-06-03 14:18:53 -0400502 security::Certificate cert(rrset.getData());
Yumin Xia2c509c22017-02-09 14:37:36 -0800503 os << cert;
504 // cert.printCertificate(istream);
Jiewen Tand1dd86d2015-03-20 10:26:28 -0700505 }
506 else {
Yumin Xia2c509c22017-02-09 14:37:36 -0800507 bufferSource(re.getAppContent().wire(), re.getAppContent().size()) >> base64Encode() >> streamSink(os);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800508 }
Jiewen Tan870b29b2014-11-17 19:09:49 -0800509 }
Alexander Afanasyevd6b3bda2014-11-25 17:33:58 -0800510 os << std::endl;
Jiewen Tan870b29b2014-11-17 19:09:49 -0800511 }
512 else {
513 os << std::endl;
514 }
515 }
516}
517
518void
519ManagementTool::listAllZones(std::ostream& os) {
520 std::vector<Zone> zones = m_dbMgr.listZones();
521
522 size_t nameWidth = 0;
523 for (const Zone& zone : zones) {
524 if (zone.getName().toUri().size() > nameWidth)
525 nameWidth = zone.getName().toUri().size();
526 }
527
528 for (const Zone& zone : zones) {
529 os.setf(os.left);
530 os.width(nameWidth + 2);
531 os << zone.getName().toUri();
Yumin Xia918343d2017-03-17 19:04:55 -0700532 Name zoneIdentity = Name(zone.getName()).append(label::NDNS_ITERATIVE_QUERY);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800533
534 os << "; default-ttl=" << zone.getTtl().count();
Yumin Xia2c509c22017-02-09 14:37:36 -0800535 os << " default-key=" << CertHelper::getDefaultKeyNameOfIdentity(m_keyChain, zoneIdentity);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800536 os << " default-certificate="
Yumin Xia2c509c22017-02-09 14:37:36 -0800537 << CertHelper::getDefaultCertificateNameOfIdentity(m_keyChain, zoneIdentity);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800538 os << std::endl;
539 }
540}
541
542void
543ManagementTool::removeRrSet(const Name& zoneName, const Name& label, const name::Component& type)
544{
545 Zone zone(zoneName);
546 Rrset rrset(&zone);
547 rrset.setLabel(label);
548 rrset.setType(type);
549
550 if (!m_dbMgr.find(rrset)) {
551 return;
552 }
553 NDNS_LOG_INFO("Remove rrset with zone-id: " << zone.getId() << " label: " << label << " type: "
554 << type);
555 m_dbMgr.remove(rrset);
Yumin Xia55a7cc42017-05-14 18:43:34 -0700556 generateDoe(zone);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800557}
558
559void
560ManagementTool::getRrSet(const Name& zoneName,
561 const Name& label,
562 const name::Component& type,
563 std::ostream& os)
564{
565 Zone zone(zoneName);
566 Rrset rrset(&zone);
567 rrset.setLabel(label);
568 rrset.setType(type);
569
570 if (!m_dbMgr.find(rrset)) {
571 os << "No record is found" << std::endl;
572 return;
573 }
574
Yumin Xia2c509c22017-02-09 14:37:36 -0800575 bufferSource(rrset.getData().wire(), rrset.getData().size()) >> base64Encode() >> streamSink(os);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800576}
577
578void
Yumin Xia2c509c22017-02-09 14:37:36 -0800579ManagementTool::addIdCert(Zone& zone, const Certificate& cert,
580 const time::seconds& ttl,
581 const Certificate& dskCert)
Jiewen Tan870b29b2014-11-17 19:09:49 -0800582{
Yumin Xia2c509c22017-02-09 14:37:36 -0800583 Rrset rrsetKey(&zone);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800584 size_t size = zone.getName().size();
Yumin Xia2c509c22017-02-09 14:37:36 -0800585 Name label = cert.getName().getSubName(size + 1, cert.getName().size() - size - 3);
586 rrsetKey.setLabel(label);
587 rrsetKey.setType(label::CERT_RR_TYPE);
588 rrsetKey.setTtl(ttl);
589 rrsetKey.setVersion(cert.getName().get(-1));
590 rrsetKey.setData(cert.wireEncode());
Jiewen Tan870b29b2014-11-17 19:09:49 -0800591
Yumin Xia2c509c22017-02-09 14:37:36 -0800592 if (m_dbMgr.find(rrsetKey)) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500593 NDN_THROW(Error("CERT with label=" + label.toUri() +
594 " is already present in local NDNS database"));
Jiewen Tan870b29b2014-11-17 19:09:49 -0800595 }
Yumin Xia2c509c22017-02-09 14:37:36 -0800596
597 m_dbMgr.insert(rrsetKey);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800598 NDNS_LOG_INFO("Add rrset with zone-id: " << zone.getId() << " label: " << label << " type: "
599 << label::CERT_RR_TYPE);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800600}
601
602void
603ManagementTool::addZone(Zone& zone)
604{
605 if (m_dbMgr.find(zone)) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500606 NDN_THROW(Error("Zone with Name=" + zone.getName().toUri() +
607 " is already present in local NDNS database"));
Jiewen Tan870b29b2014-11-17 19:09:49 -0800608 }
609 NDNS_LOG_INFO("Add zone with Name: " << zone.getName().toUri());
610 m_dbMgr.insert(zone);
611}
612
613void
614ManagementTool::removeZone(Zone& zone)
615{
616 if (!m_dbMgr.find(zone)) {
617 return;
618 }
619 NDNS_LOG_INFO("Remove zone with Name: " << zone.getName().toUri());
620 m_dbMgr.remove(zone);
621}
622
623bool
624ManagementTool::matchCertificate(const Name& certName, const Name& identity)
625{
Yumin Xia2c509c22017-02-09 14:37:36 -0800626 security::Identity id = m_keyChain.getPib().getIdentity(identity);
627 for (const security::Key& key: id.getKeys()) {
628 try {
629 key.getCertificate(certName);
630 return true;
631 } catch (const std::exception&) {
632 }
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