blob: 33b704cedccbbf431b14e4c806480dd558b1cbbe [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 -080041namespace ndn {
42namespace ndns {
43
Alexander Afanasyev08d18742018-03-15 16:31:28 -040044NDNS_LOG_INIT(ManagementTool);
Jiewen Tan870b29b2014-11-17 19:09:49 -080045
Yumin Xia2c509c22017-02-09 14:37:36 -080046using security::transform::base64Encode;
47using security::transform::streamSink;
48using security::transform::bufferSource;
Alexander Afanasyev60514ec2020-06-03 14:18:53 -040049using security::Certificate;
Yumin Xia2c509c22017-02-09 14:37:36 -080050
Alexander Afanasyevd6b3bda2014-11-25 17:33:58 -080051ManagementTool::ManagementTool(const std::string& dbFile, KeyChain& keyChain)
52 : m_keyChain(keyChain)
53 , m_dbMgr(dbFile)
Jiewen Tan870b29b2014-11-17 19:09:49 -080054{
55}
56
Yumin Xia2c509c22017-02-09 14:37:36 -080057Zone
58ManagementTool::createZone(const Name& zoneName,
Jiewen Tan870b29b2014-11-17 19:09:49 -080059 const Name& parentZoneName,
60 const time::seconds& cacheTtl,
Alexander Afanasyevd6b3bda2014-11-25 17:33:58 -080061 const time::seconds& certValidity,
Jiewen Tan870b29b2014-11-17 19:09:49 -080062 const Name& kskCertName,
Yumin Xia2c509c22017-02-09 14:37:36 -080063 const Name& dskCertName,
64 const Name& dkeyCertName)
Jiewen Tan870b29b2014-11-17 19:09:49 -080065{
66 bool isRoot = zoneName == ROOT_ZONE;
Yumin Xia918343d2017-03-17 19:04:55 -070067 Name zoneIdentityName = Name(zoneName).append(label::NDNS_ITERATIVE_QUERY);
Jiewen Tan870b29b2014-11-17 19:09:49 -080068
69 //check preconditions
70 Zone zone(zoneName, cacheTtl);
71 if (m_dbMgr.find(zone)) {
Davide Pesavento948c50c2020-12-26 21:30:45 -050072 NDN_THROW(Error(zoneName.toUri() + " is already present in the NDNS db"));
Jiewen Tan870b29b2014-11-17 19:09:49 -080073 }
74
75 if (!isRoot && parentZoneName.equals(zoneName)) {
Davide Pesavento948c50c2020-12-26 21:30:45 -050076 NDN_THROW(Error("Parent zone name can not be the zone itself"));
Jiewen Tan870b29b2014-11-17 19:09:49 -080077 }
78
79 if (!isRoot && !parentZoneName.isPrefixOf(zoneName)) {
Davide Pesavento948c50c2020-12-26 21:30:45 -050080 NDN_THROW(Error(parentZoneName.toUri() + " is not a prefix of " + zoneName.toUri()));
Jiewen Tan870b29b2014-11-17 19:09:49 -080081 }
82
Jiewen Tan01693fd2015-03-25 20:34:45 -070083 // if dsk is provided, there is no need to check ksk
Jiewen Tan870b29b2014-11-17 19:09:49 -080084 if (dskCertName != DEFAULT_CERT) {
Yumin Xia2c509c22017-02-09 14:37:36 -080085 if (!matchCertificate(dskCertName, zoneIdentityName)) {
Davide Pesavento948c50c2020-12-26 21:30:45 -050086 NDN_THROW(Error("Cannot verify DSK certificate"));
Jiewen Tan870b29b2014-11-17 19:09:49 -080087 }
88 }
Jiewen Tan01693fd2015-03-25 20:34:45 -070089 else if (kskCertName != DEFAULT_CERT) {
Yumin Xia2c509c22017-02-09 14:37:36 -080090 if (!matchCertificate(kskCertName, zoneIdentityName)) {
Davide Pesavento948c50c2020-12-26 21:30:45 -050091 NDN_THROW(Error("Cannot verify KSK certificate"));
Jiewen Tan01693fd2015-03-25 20:34:45 -070092 }
93 }
Jiewen Tan870b29b2014-11-17 19:09:49 -080094
Yumin Xia2c509c22017-02-09 14:37:36 -080095 if (dkeyCertName == DEFAULT_CERT && isRoot) {
Davide Pesavento948c50c2020-12-26 21:30:45 -050096 NDN_THROW(Error("Cannot generate dkey for root zone"));
Jiewen Tan870b29b2014-11-17 19:09:49 -080097 }
98
Yumin Xia2c509c22017-02-09 14:37:36 -080099 // Generate a parentZone's identity to generate a D-Key.
100 // This D-key will be passed to parent zone and resigned.
101 Name dkeyIdentityName;
102 if (dkeyCertName == DEFAULT_CERT) {
Yumin Xia918343d2017-03-17 19:04:55 -0700103 dkeyIdentityName = Name(parentZoneName).append(label::NDNS_ITERATIVE_QUERY)
Yumin Xia2c509c22017-02-09 14:37:36 -0800104 .append(zoneName.getSubName(parentZoneName.size()));
Jiewen Tan870b29b2014-11-17 19:09:49 -0800105 }
106 else {
Yumin Xia2c509c22017-02-09 14:37:36 -0800107 dkeyIdentityName = CertHelper::getIdentityNameFromCert(dkeyCertName);
108 }
109 NDNS_LOG_INFO("Generated D-Key's identityName: " + dkeyIdentityName.toUri());
110
111 Name dskName;
Davide Pesavento38fd3982022-04-18 22:22:02 -0400112 security::Key ksk;
113 security::Key dsk;
114 security::Key dkey;
Yumin Xia2c509c22017-02-09 14:37:36 -0800115 Certificate dskCert;
116 Certificate kskCert;
117 Certificate dkeyCert;
Davide Pesavento38fd3982022-04-18 22:22:02 -0400118 auto zoneIdentity = m_keyChain.createIdentity(zoneIdentityName);
119 auto dkeyIdentity = m_keyChain.createIdentity(dkeyIdentityName);
Yumin Xia2c509c22017-02-09 14:37:36 -0800120
121 if (dkeyCertName == DEFAULT_CERT) {
122 dkey = m_keyChain.createKey(dkeyIdentity);
123 m_keyChain.deleteCertificate(dkey, dkey.getDefaultCertificate().getName());
124
Yumin Xiafa2bce72017-04-09 16:20:25 -0700125 dkeyCert = CertHelper::createCertificate(m_keyChain, dkey, dkey, label::CERT_RR_TYPE.toUri(), certValidity);
Yumin Xia2c509c22017-02-09 14:37:36 -0800126 dkeyCert.setFreshnessPeriod(cacheTtl);
127 m_keyChain.addCertificate(dkey, dkeyCert);
128 NDNS_LOG_INFO("Generated DKEY: " << dkeyCert.getName());
129
130 }
131 else {
132 dkeyCert = CertHelper::getCertificate(m_keyChain, dkeyIdentityName, dkeyCertName);
133 dkey = dkeyIdentity.getKey(dkeyCert.getKeyName());
134 }
135
136 if (kskCertName == DEFAULT_CERT) {
137 ksk = m_keyChain.createKey(zoneIdentity);
138 // delete automatically generated certificates,
139 // because its issue is 'self' instead of CERT_RR_TYPE
140 m_keyChain.deleteCertificate(ksk, ksk.getDefaultCertificate().getName());
Yumin Xiafa2bce72017-04-09 16:20:25 -0700141 kskCert = CertHelper::createCertificate(m_keyChain, ksk, dkey, label::CERT_RR_TYPE.toUri(), certValidity);
Yumin Xia2c509c22017-02-09 14:37:36 -0800142 kskCert.setFreshnessPeriod(cacheTtl);
143 m_keyChain.addCertificate(ksk, kskCert);
144 NDNS_LOG_INFO("Generated KSK: " << kskCert.getName());
145 }
146 else {
147 // ksk usually might not be the default key of a zone
148 kskCert = CertHelper::getCertificate(m_keyChain, zoneIdentityName, kskCertName);
149 ksk = zoneIdentity.getKey(kskCert.getKeyName());
150 }
151
152 if (dskCertName == DEFAULT_CERT) {
153 // if no dsk provided, then generate a dsk either signed by ksk auto generated or user provided
154 dsk = m_keyChain.createKey(zoneIdentity);
155 m_keyChain.deleteCertificate(dsk, dsk.getDefaultCertificate().getName());
156 dskCert = CertHelper::createCertificate(m_keyChain, dsk, ksk, label::CERT_RR_TYPE.toUri(), certValidity);
157 dskCert.setFreshnessPeriod(cacheTtl);
158 // dskCert will become the default certificate, since the default cert has been deleted.
159 m_keyChain.addCertificate(dsk, dskCert);
160 m_keyChain.setDefaultKey(zoneIdentity, dsk);
161 NDNS_LOG_INFO("Generated DSK: " << dskCert.getName());
162 }
163 else {
164 dskCert = CertHelper::getCertificate(m_keyChain, zoneIdentityName, dskCertName);
165 dsk = zoneIdentity.getKey(dskCert.getKeyName());
166 m_keyChain.setDefaultKey(zoneIdentity, dsk);
167 m_keyChain.setDefaultCertificate(dsk, dskCert);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800168 }
169
170 //second add zone to the database
171 NDNS_LOG_INFO("Start adding new zone to data base");
172 addZone(zone);
173
174 //third create ID-cert
Yumin Xia2c509c22017-02-09 14:37:36 -0800175 NDNS_LOG_INFO("Start adding Certificates to NDNS database");
176 addIdCert(zone, kskCert, cacheTtl, dskCert);
177 addIdCert(zone, dskCert, cacheTtl, dskCert);
178
179 NDNS_LOG_INFO("Start saving KSK and DSK's id to ZoneInfo");
180 m_dbMgr.setZoneInfo(zone, "ksk", kskCert.wireEncode());
181 m_dbMgr.setZoneInfo(zone, "dsk", dskCert.wireEncode());
182
183 NDNS_LOG_INFO("Start saving DKEY certificate id to ZoneInfo");
184 m_dbMgr.setZoneInfo(zone, "dkey", dkeyCert.wireEncode());
185
Yumin Xia55a7cc42017-05-14 18:43:34 -0700186 generateDoe(zone);
Yumin Xia2c509c22017-02-09 14:37:36 -0800187 return zone;
Jiewen Tan870b29b2014-11-17 19:09:49 -0800188}
189
190void
191ManagementTool::deleteZone(const Name& zoneName)
192{
193 //check pre-conditions
194 Zone zone(zoneName);
195 if (!m_dbMgr.find(zone)) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500196 NDN_THROW(Error(zoneName.toUri() + " is not present in the NDNS db"));
Jiewen Tan870b29b2014-11-17 19:09:49 -0800197 }
198
199 //first remove all rrsets of this zone from local ndns database
200 std::vector<Rrset> rrsets = m_dbMgr.findRrsets(zone);
201 for (Rrset& rrset : rrsets) {
202 m_dbMgr.remove(rrset);
203 }
204
205 //second remove zone from local ndns database
206 removeZone(zone);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800207}
208
209void
210ManagementTool::exportCertificate(const Name& certName, const std::string& outFile)
211{
Yumin Xia2c509c22017-02-09 14:37:36 -0800212 // only search in local NDNS database
Alexander Afanasyev60514ec2020-06-03 14:18:53 -0400213 security::Certificate cert;
Yumin Xia2c509c22017-02-09 14:37:36 -0800214 shared_ptr<Regex> regex = make_shared<Regex>("(<>*)<NDNS>(<>+)<CERT><>");
215 if (!regex->match(certName)) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500216 NDN_THROW(Error("Certificate name is illegal"));
Yumin Xia2c509c22017-02-09 14:37:36 -0800217 }
218
219 Name zoneName = regex->expand("\\1");
Yumin Xia918343d2017-03-17 19:04:55 -0700220 Name identityName = Name(zoneName).append(label::NDNS_ITERATIVE_QUERY);
Yumin Xia2c509c22017-02-09 14:37:36 -0800221 Name label = regex->expand("\\2");
222
223 Zone zone(zoneName);
224 Rrset rrset(&zone);
225 rrset.setLabel(label);
226 rrset.setType(label::CERT_RR_TYPE);
227 if (m_dbMgr.find(rrset)) {
Alexander Afanasyev60514ec2020-06-03 14:18:53 -0400228 cert = security::Certificate(rrset.getData());
Jiewen Tan870b29b2014-11-17 19:09:49 -0800229 }
230 else {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500231 NDN_THROW(Error("Cannot find the cert: " + certName.toUri()));
Jiewen Tan870b29b2014-11-17 19:09:49 -0800232 }
233
234 if (outFile == DEFAULT_IO) {
Yumin Xia2c509c22017-02-09 14:37:36 -0800235 ndn::io::save(cert, std::cout);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800236 }
237 else {
Yumin Xia2c509c22017-02-09 14:37:36 -0800238 ndn::io::save(cert, outFile);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800239 NDNS_LOG_INFO("save cert to file: " << outFile);
240 }
241}
242
243void
Yumin Xiaacd21332016-11-28 22:54:48 -0800244ManagementTool::addMultiLevelLabelRrset(Rrset& rrset,
245 RrsetFactory& zoneRrFactory,
246 const time::seconds& authTtl)
247{
248 const Name& label = rrset.getLabel();
249
250 // Check whether it is legal to insert the rrset
251 for (size_t i = 1; i <= label.size() - 1; i++) {
252 Name prefix = label.getPrefix(i);
253 Rrset prefixNsRr(rrset.getZone());
254 prefixNsRr.setLabel(prefix);
255 prefixNsRr.setType(label::NS_RR_TYPE);
256 if (m_dbMgr.find(prefixNsRr)) {
257 Data data(prefixNsRr.getData());
258 if (data.getContentType() == NDNS_LINK) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500259 NDN_THROW(Error("Cannot override " + boost::lexical_cast<std::string>(prefixNsRr) + " (NDNS_LINK)"));
Yumin Xiaacd21332016-11-28 22:54:48 -0800260 }
261 }
262 }
263
264 // check that it does not override existing AUTH
265 if (rrset.getType() == label::NS_RR_TYPE) {
266 Rrset rrsetCopy = rrset;
267 if (m_dbMgr.find(rrsetCopy)) {
268 if (Data(rrsetCopy.getData()).getContentType() == NDNS_AUTH) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500269 NDN_THROW(Error("Cannot override " + boost::lexical_cast<std::string>(rrsetCopy) + " (NDNS_AUTH)"));
Yumin Xiaacd21332016-11-28 22:54:48 -0800270 }
271 }
272 }
273
274 for (size_t i = 1; i <= label.size() - 1; i++) {
275 Name prefix = label.getPrefix(i);
276 Rrset prefixNsRr(rrset.getZone());
277 prefixNsRr.setLabel(prefix);
278 prefixNsRr.setType(label::NS_RR_TYPE);
279 if (m_dbMgr.find(prefixNsRr)) {
280 NDNS_LOG_INFO("NDNS_AUTH Rrset Label=" << prefix << " is already existed, insertion skipped");
281 continue;
282 }
283
Yumin Xiad4e8ce52017-03-17 19:56:52 -0700284 Rrset authRr = zoneRrFactory.generateAuthRrset(prefix,
Yumin Xiaacd21332016-11-28 22:54:48 -0800285 VERSION_USE_UNIX_TIMESTAMP, authTtl);
286 NDNS_LOG_INFO("Adding NDNS_AUTH " << authRr);
287 m_dbMgr.insert(authRr);
288 }
289
290 checkRrsetVersion(rrset);
291 NDNS_LOG_INFO("Adding " << rrset);
292 m_dbMgr.insert(rrset);
Yumin Xia55a7cc42017-05-14 18:43:34 -0700293 generateDoe(*rrset.getZone());
Yumin Xiaacd21332016-11-28 22:54:48 -0800294}
295
296void
Yumin Xia5dd9f2b2016-10-26 20:48:05 -0700297ManagementTool::addRrset(Rrset& rrset)
Jiewen Tan870b29b2014-11-17 19:09:49 -0800298{
Yumin Xiaacd21332016-11-28 22:54:48 -0800299 // check that it does not override existing AUTH
300 Rrset rrsetCopy = rrset;
301 rrsetCopy.setType(label::NS_RR_TYPE);
302 if (m_dbMgr.find(rrsetCopy)) {
303 if (Data(rrsetCopy.getData()).getContentType() == NDNS_AUTH) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500304 NDN_THROW(Error("Can not add this Rrset: it overrides a NDNS_AUTH record"));
Yumin Xiaacd21332016-11-28 22:54:48 -0800305 }
306 }
307
Jiewen Tan8cd35ea2015-03-20 00:44:23 -0700308 checkRrsetVersion(rrset);
Alexander Afanasyevd6b3bda2014-11-25 17:33:58 -0800309 NDNS_LOG_INFO("Added " << rrset);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800310 m_dbMgr.insert(rrset);
Yumin Xia55a7cc42017-05-14 18:43:34 -0700311 generateDoe(*rrset.getZone());
Jiewen Tan870b29b2014-11-17 19:09:49 -0800312}
313
314void
Yumin Xiac5ed63f2017-01-26 13:44:38 -0800315ManagementTool::addRrsetFromFile(const Name& zoneName,
316 const std::string& inFile,
317 const time::seconds& ttl,
318 const Name& inputDskCertName,
Davide Pesavento38fd3982022-04-18 22:22:02 -0400319 ndn::io::IoEncoding encoding,
Yumin Xiac5ed63f2017-01-26 13:44:38 -0800320 bool needResign)
Jiewen Tan870b29b2014-11-17 19:09:49 -0800321{
322 //check precondition
323 Zone zone(zoneName);
Yumin Xia918343d2017-03-17 19:04:55 -0700324 Name zoneIdentityName = Name(zoneName).append(label::NDNS_ITERATIVE_QUERY);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800325 if (!m_dbMgr.find(zone)) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500326 NDN_THROW(Error(zoneName.toUri() + " is not present in the NDNS db"));
Jiewen Tan870b29b2014-11-17 19:09:49 -0800327 }
328
329 Name dskName;
330 Name dskCertName = inputDskCertName;
331 if (dskCertName == DEFAULT_CERT) {
Yumin Xia2c509c22017-02-09 14:37:36 -0800332 dskName = CertHelper::getDefaultKeyNameOfIdentity(m_keyChain, zoneIdentityName);
333 dskCertName = CertHelper::getDefaultCertificateNameOfIdentity(m_keyChain, zoneIdentityName);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800334 }
335 else {
Yumin Xia2c509c22017-02-09 14:37:36 -0800336 if (!matchCertificate(dskCertName, zoneIdentityName)) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500337 NDN_THROW(Error("Cannot verify certificate"));
Jiewen Tan870b29b2014-11-17 19:09:49 -0800338 }
339 }
340
341 if (inFile != DEFAULT_IO) {
342 boost::filesystem::path dir = boost::filesystem::path(inFile);
343 if (!boost::filesystem::exists(dir) || boost::filesystem::is_directory(dir)) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500344 NDN_THROW(Error("Data: " + inFile + " does not exist"));
Jiewen Tan870b29b2014-11-17 19:09:49 -0800345 }
346 }
347
Yumin Xiac5ed63f2017-01-26 13:44:38 -0800348 // load data
Jiewen Tan870b29b2014-11-17 19:09:49 -0800349 shared_ptr<Data> data;
350 if (inFile == DEFAULT_IO)
Jiewen Tan74d745c2015-03-20 01:40:41 -0700351 data = ndn::io::load<ndn::Data>(std::cin, encoding);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800352 else
Jiewen Tan74d745c2015-03-20 01:40:41 -0700353 data = ndn::io::load<ndn::Data>(inFile, encoding);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800354
Jiewen Tand2d21822015-03-19 15:37:03 -0700355 if (data == nullptr) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500356 NDN_THROW(Error("input does not contain a valid Data packet"));
Jiewen Tand2d21822015-03-19 15:37:03 -0700357 }
358
Yumin Xiac5ed63f2017-01-26 13:44:38 -0800359 if (needResign) {
Yumin Xiafa2bce72017-04-09 16:20:25 -0700360 // TODO validityPeriod should be able to be configured
361 SignatureInfo info;
362 info.setValidityPeriod(security::ValidityPeriod(time::system_clock::now(),
363 time::system_clock::now() + DEFAULT_CERT_TTL));
364 m_keyChain.sign(*data, signingByCertificate(dskCertName).setSignatureInfo(info));
Jiewen Tan870b29b2014-11-17 19:09:49 -0800365 }
366
367 // create response for the input data
368 Response re;
Yumin Xia6343c5b2016-10-20 15:45:50 -0700369 re.fromData(zoneName, *data);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800370 Name label = re.getRrLabel();
371 name::Component type = re.getRrType();
372
373 Rrset rrset(&zone);
374 rrset.setLabel(label);
375 rrset.setType(type);
376 if (ttl == DEFAULT_RR_TTL)
377 rrset.setTtl(zone.getTtl());
378 else
379 rrset.setTtl(ttl);
380 rrset.setVersion(re.getVersion());
381 rrset.setData(data->wireEncode());
382
Jiewen Tan8cd35ea2015-03-20 00:44:23 -0700383 checkRrsetVersion(rrset);
Yumin Xia2c509c22017-02-09 14:37:36 -0800384 NDNS_LOG_INFO("Adding rrset from file " << rrset);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800385 m_dbMgr.insert(rrset);
Yumin Xia55a7cc42017-05-14 18:43:34 -0700386 generateDoe(*rrset.getZone());
Jiewen Tan870b29b2014-11-17 19:09:49 -0800387}
388
Alexander Afanasyev60514ec2020-06-03 14:18:53 -0400389security::Certificate
Yumin Xia2c509c22017-02-09 14:37:36 -0800390ManagementTool::getZoneDkey(Zone& zone)
391{
392 std::map<std::string, Block> zoneInfo = m_dbMgr.getZoneInfo(zone);
Alexander Afanasyev60514ec2020-06-03 14:18:53 -0400393 return security::Certificate(zoneInfo["dkey"]);
Yumin Xia2c509c22017-02-09 14:37:36 -0800394}
395
Jiewen Tan870b29b2014-11-17 19:09:49 -0800396void
Davide Pesavento38fd3982022-04-18 22:22:02 -0400397ManagementTool::listZone(const Name& zoneName, std::ostream& os, bool printRaw)
Alexander Afanasyevd6b3bda2014-11-25 17:33:58 -0800398{
Jiewen Tan870b29b2014-11-17 19:09:49 -0800399 Zone zone(zoneName);
400 if (!m_dbMgr.find(zone)) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500401 NDN_THROW(Error("Zone " + zoneName.toUri() + " is not found in the database"));
Jiewen Tan870b29b2014-11-17 19:09:49 -0800402 }
403
404 //first output the zone name
405 os << "; Zone " << zoneName.toUri() << std::endl << std::endl;
406
407 //second output all rrsets
408 std::vector<Rrset> rrsets = m_dbMgr.findRrsets(zone);
409
410 //set width for different columns
411 size_t labelWidth = 0;
412 size_t ttlWidth = 0;
413 size_t typeWidth = 0;
414 for (Rrset& rrset : rrsets) {
415 Data data(rrset.getData());
416 Response re;
Yumin Xia6343c5b2016-10-20 15:45:50 -0700417 re.fromData(zoneName, data);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800418
419 if (rrset.getLabel().toUri().size() > labelWidth)
420 labelWidth = rrset.getLabel().toUri().size();
421
422 std::stringstream seconds;
423 seconds << rrset.getTtl().count();
424 if (seconds.str().size() > ttlWidth)
425 ttlWidth = seconds.str().size();
426
427 if (rrset.getType().toUri().size() > typeWidth)
428 typeWidth = rrset.getType().toUri().size();
429 }
430
431 //output
432 for (Rrset& rrset : rrsets) {
433 Data data(rrset.getData());
434 Response re;
Yumin Xia6343c5b2016-10-20 15:45:50 -0700435 re.fromData(zoneName, data);
Yumin Xia3c6b1fd2016-12-11 19:08:47 -0800436 int iteration = re.getContentType() == NDNS_BLOB
437 || re.getContentType() == NDNS_KEY
438 || re.getContentType() == NDNS_AUTH ? 1 : re.getRrs().size();
439
Davide Pesavento38fd3982022-04-18 22:22:02 -0400440 const auto& rrs = re.getRrs();
Jiewen Tan870b29b2014-11-17 19:09:49 -0800441
Yumin Xia3c6b1fd2016-12-11 19:08:47 -0800442 if (re.getContentType() != NDNS_BLOB && re.getContentType() != NDNS_KEY) {
Jiewen Tan870b29b2014-11-17 19:09:49 -0800443 os << "; rrset=" << rrset.getLabel().toUri()
444 << " type=" << rrset.getType().toUri()
445 << " version=" << rrset.getVersion().toUri()
Davide Pesavento1bff1b22020-06-08 18:46:05 -0400446 << " signed-by=" << data.getKeyLocator()->getName().toUri()
Jiewen Tan870b29b2014-11-17 19:09:49 -0800447 << std::endl;
448 }
449
450 for (int i = 0; i < iteration; i++) {
451 os.setf(os.left);
452 os.width(labelWidth + 2);
453 os << rrset.getLabel().toUri();
454
455 os.width(ttlWidth + 2);
456 os << rrset.getTtl().count();
457
458 os.width(typeWidth + 2);
459 os << rrset.getType().toUri();
460
Yumin Xia3c6b1fd2016-12-11 19:08:47 -0800461 if (re.getContentType() != NDNS_BLOB && re.getContentType() != NDNS_KEY) {
Jiewen Tan870b29b2014-11-17 19:09:49 -0800462 if (rrset.getType() == label::TXT_RR_TYPE) {
463 os.write(reinterpret_cast<const char*>(rrs[i].value()), rrs[i].value_size());
464 os << std::endl;
465 }
466 else if (rrset.getType() == label::NS_RR_TYPE) {
Yumin Xia5dd9f2b2016-10-26 20:48:05 -0700467 BOOST_ASSERT(iteration == 1);
Yumin Xiaa484ba72016-11-10 20:40:12 -0800468 if (re.getContentType() == NDNS_AUTH) {
Yumin Xia5dd9f2b2016-10-26 20:48:05 -0700469 const std::string authStr = "NDNS-Auth";
470 os << authStr;
Yumin Xia2c509c22017-02-09 14:37:36 -0800471 }
472 else {
Yumin Xia5dd9f2b2016-10-26 20:48:05 -0700473 Link link(rrset.getData());
Junxiao Shi81e98762022-01-11 18:17:24 +0000474 for (const auto& delegation : link.getDelegationList()) {
475 os << delegation << ";";
Yumin Xia5dd9f2b2016-10-26 20:48:05 -0700476 }
477 }
Jiewen Tan870b29b2014-11-17 19:09:49 -0800478 os << std::endl;
479 }
480 else {
Davide Pesavento98026122022-03-14 22:00:03 -0400481 bufferSource(rrs[i]) >> base64Encode() >> streamSink(os);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800482 }
483 }
484 }
485
Yumin Xia3c6b1fd2016-12-11 19:08:47 -0800486 if (re.getContentType() == NDNS_BLOB || re.getContentType() == NDNS_KEY) {
Jiewen Tan870b29b2014-11-17 19:09:49 -0800487 os.width();
Yumin Xiaa484ba72016-11-10 20:40:12 -0800488 os << "; content-type=" << re.getContentType()
Jiewen Tan870b29b2014-11-17 19:09:49 -0800489 << " version=" << rrset.getVersion().toUri()
Davide Pesavento1bff1b22020-06-08 18:46:05 -0400490 << " signed-by=" << data.getKeyLocator()->getName().toUri();
Jiewen Tan870b29b2014-11-17 19:09:49 -0800491 os << std::endl;
492
Yumin Xia3c6b1fd2016-12-11 19:08:47 -0800493 if (printRaw && (re.getContentType() == NDNS_BLOB
494 || re.getContentType() == NDNS_KEY)) {
Yumin Xia2c509c22017-02-09 14:37:36 -0800495 ndn::util::IndentedStream istream(os, "; ");
Jiewen Tan870b29b2014-11-17 19:09:49 -0800496
Jiewen Tand1dd86d2015-03-20 10:26:28 -0700497 if (re.getRrType() == label::CERT_RR_TYPE) {
Alexander Afanasyev60514ec2020-06-03 14:18:53 -0400498 security::Certificate cert(rrset.getData());
Yumin Xia2c509c22017-02-09 14:37:36 -0800499 os << cert;
500 // cert.printCertificate(istream);
Jiewen Tand1dd86d2015-03-20 10:26:28 -0700501 }
502 else {
Davide Pesavento98026122022-03-14 22:00:03 -0400503 bufferSource(re.getAppContent()) >> base64Encode() >> streamSink(os);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800504 }
Jiewen Tan870b29b2014-11-17 19:09:49 -0800505 }
Alexander Afanasyevd6b3bda2014-11-25 17:33:58 -0800506 os << std::endl;
Jiewen Tan870b29b2014-11-17 19:09:49 -0800507 }
508 else {
509 os << std::endl;
510 }
511 }
512}
513
514void
Davide Pesavento38fd3982022-04-18 22:22:02 -0400515ManagementTool::listAllZones(std::ostream& os)
516{
Jiewen Tan870b29b2014-11-17 19:09:49 -0800517 std::vector<Zone> zones = m_dbMgr.listZones();
518
519 size_t nameWidth = 0;
520 for (const Zone& zone : zones) {
521 if (zone.getName().toUri().size() > nameWidth)
522 nameWidth = zone.getName().toUri().size();
523 }
524
525 for (const Zone& zone : zones) {
526 os.setf(os.left);
527 os.width(nameWidth + 2);
528 os << zone.getName().toUri();
Yumin Xia918343d2017-03-17 19:04:55 -0700529 Name zoneIdentity = Name(zone.getName()).append(label::NDNS_ITERATIVE_QUERY);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800530
531 os << "; default-ttl=" << zone.getTtl().count();
Yumin Xia2c509c22017-02-09 14:37:36 -0800532 os << " default-key=" << CertHelper::getDefaultKeyNameOfIdentity(m_keyChain, zoneIdentity);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800533 os << " default-certificate="
Yumin Xia2c509c22017-02-09 14:37:36 -0800534 << CertHelper::getDefaultCertificateNameOfIdentity(m_keyChain, zoneIdentity);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800535 os << std::endl;
536 }
537}
538
539void
540ManagementTool::removeRrSet(const Name& zoneName, const Name& label, const name::Component& type)
541{
542 Zone zone(zoneName);
543 Rrset rrset(&zone);
544 rrset.setLabel(label);
545 rrset.setType(type);
546
547 if (!m_dbMgr.find(rrset)) {
548 return;
549 }
550 NDNS_LOG_INFO("Remove rrset with zone-id: " << zone.getId() << " label: " << label << " type: "
551 << type);
552 m_dbMgr.remove(rrset);
Yumin Xia55a7cc42017-05-14 18:43:34 -0700553 generateDoe(zone);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800554}
555
556void
557ManagementTool::getRrSet(const Name& zoneName,
558 const Name& label,
559 const name::Component& type,
560 std::ostream& os)
561{
562 Zone zone(zoneName);
563 Rrset rrset(&zone);
564 rrset.setLabel(label);
565 rrset.setType(type);
566
567 if (!m_dbMgr.find(rrset)) {
568 os << "No record is found" << std::endl;
569 return;
570 }
571
Davide Pesavento98026122022-03-14 22:00:03 -0400572 bufferSource(rrset.getData()) >> base64Encode() >> streamSink(os);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800573}
574
575void
Yumin Xia2c509c22017-02-09 14:37:36 -0800576ManagementTool::addIdCert(Zone& zone, const Certificate& cert,
577 const time::seconds& ttl,
578 const Certificate& dskCert)
Jiewen Tan870b29b2014-11-17 19:09:49 -0800579{
Yumin Xia2c509c22017-02-09 14:37:36 -0800580 Rrset rrsetKey(&zone);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800581 size_t size = zone.getName().size();
Yumin Xia2c509c22017-02-09 14:37:36 -0800582 Name label = cert.getName().getSubName(size + 1, cert.getName().size() - size - 3);
583 rrsetKey.setLabel(label);
584 rrsetKey.setType(label::CERT_RR_TYPE);
585 rrsetKey.setTtl(ttl);
586 rrsetKey.setVersion(cert.getName().get(-1));
587 rrsetKey.setData(cert.wireEncode());
Jiewen Tan870b29b2014-11-17 19:09:49 -0800588
Yumin Xia2c509c22017-02-09 14:37:36 -0800589 if (m_dbMgr.find(rrsetKey)) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500590 NDN_THROW(Error("CERT with label=" + label.toUri() +
591 " is already present in local NDNS database"));
Jiewen Tan870b29b2014-11-17 19:09:49 -0800592 }
Yumin Xia2c509c22017-02-09 14:37:36 -0800593
594 m_dbMgr.insert(rrsetKey);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800595 NDNS_LOG_INFO("Add rrset with zone-id: " << zone.getId() << " label: " << label << " type: "
596 << label::CERT_RR_TYPE);
Jiewen Tan870b29b2014-11-17 19:09:49 -0800597}
598
599void
600ManagementTool::addZone(Zone& zone)
601{
602 if (m_dbMgr.find(zone)) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500603 NDN_THROW(Error("Zone with Name=" + zone.getName().toUri() +
604 " is already present in local NDNS database"));
Jiewen Tan870b29b2014-11-17 19:09:49 -0800605 }
606 NDNS_LOG_INFO("Add zone with Name: " << zone.getName().toUri());
607 m_dbMgr.insert(zone);
608}
609
610void
611ManagementTool::removeZone(Zone& zone)
612{
613 if (!m_dbMgr.find(zone)) {
614 return;
615 }
616 NDNS_LOG_INFO("Remove zone with Name: " << zone.getName().toUri());
617 m_dbMgr.remove(zone);
618}
619
620bool
621ManagementTool::matchCertificate(const Name& certName, const Name& identity)
622{
Davide Pesavento38fd3982022-04-18 22:22:02 -0400623 auto id = m_keyChain.getPib().getIdentity(identity);
624 for (const auto& key : id.getKeys()) {
Yumin Xia2c509c22017-02-09 14:37:36 -0800625 try {
626 key.getCertificate(certName);
627 return true;
Davide Pesavento98026122022-03-14 22:00:03 -0400628 }
629 catch (const std::exception&) {
Yumin Xia2c509c22017-02-09 14:37:36 -0800630 }
Jiewen Tan870b29b2014-11-17 19:09:49 -0800631 }
Yumin Xia2c509c22017-02-09 14:37:36 -0800632 return false;
Jiewen Tan870b29b2014-11-17 19:09:49 -0800633}
634
Jiewen Tan8cd35ea2015-03-20 00:44:23 -0700635void
636ManagementTool::checkRrsetVersion(const Rrset& rrset)
637{
638 Rrset originalRrset(rrset);
639 if (m_dbMgr.find(originalRrset)) {
640 // update only if rrset has a newer version
641 if (originalRrset.getVersion() == rrset.getVersion()) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500642 NDN_THROW(Error("Duplicate: " + boost::lexical_cast<std::string>(originalRrset)));
Jiewen Tan8cd35ea2015-03-20 00:44:23 -0700643 }
644 else if (originalRrset.getVersion() > rrset.getVersion()) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500645 NDN_THROW(Error("Newer version exists: " + boost::lexical_cast<std::string>(originalRrset)));
Jiewen Tan8cd35ea2015-03-20 00:44:23 -0700646 }
647
648 m_dbMgr.remove(originalRrset);
649 }
650}
651
Yumin Xia55a7cc42017-05-14 18:43:34 -0700652void
653ManagementTool::generateDoe(Zone& zone)
654{
655 // check zone existence
656 if (!m_dbMgr.find(zone)) {
Davide Pesavento948c50c2020-12-26 21:30:45 -0500657 NDN_THROW(Error(zone.getName().toUri() + " is not present in the NDNS db"));
Yumin Xia55a7cc42017-05-14 18:43:34 -0700658 }
659
660 // remove all the Doe records
661 m_dbMgr.removeRrsetsOfZoneByType(zone, label::DOE_RR_TYPE);
662
663 // get the records out
664 std::vector<Rrset> allRecords = m_dbMgr.findRrsets(zone);
665
666 // sort them by DoE label name (same as in the database)
667 std::sort(allRecords.begin(), allRecords.end());
668
669 RrsetFactory factory(m_dbMgr.getDbFile(), zone.getName(), m_keyChain, DEFAULT_CERT);
670 factory.checkZoneKey();
671
672 for (size_t i = 0; i < allRecords.size() - 1; i++) {
673 Name lowerLabel = Name(allRecords[i].getLabel()).append(allRecords[i].getType());
674 Name upperLabel = Name(allRecords[i + 1].getLabel()).append(allRecords[i + 1].getType());
675 Rrset doe = factory.generateDoeRrset(lowerLabel,
676 VERSION_USE_UNIX_TIMESTAMP,
677 DEFAULT_CACHE_TTL, lowerLabel, upperLabel);
678 m_dbMgr.insert(doe);
679 }
680
681 Name lastLabel = Name(allRecords.back().getLabel()).append(allRecords.back().getType());
682 Name firstLabel = Name(allRecords.front().getLabel()).append(allRecords.front().getType());
683 Rrset lastRange = factory.generateDoeRrset(lastLabel,
684 VERSION_USE_UNIX_TIMESTAMP,
685 DEFAULT_CACHE_TTL, lastLabel, firstLabel);
686 m_dbMgr.insert(lastRange);
687
688 // This guard will be the lowest label-ranked record
689 // so if requested label+type is less than the lowest label except for this one, it will be choosed
690 // by findLowerBound. This small trick avoids complicated SQL query in findLowerBound
691 Rrset guardRange = factory.generateDoeRrset(Name(""),
692 VERSION_USE_UNIX_TIMESTAMP,
693 DEFAULT_CACHE_TTL, lastLabel, firstLabel);
694 m_dbMgr.insert(guardRange);
695 NDNS_LOG_INFO("DoE record updated");
696}
697
Jiewen Tan870b29b2014-11-17 19:09:49 -0800698} // namespace ndns
699} // namespace ndn