blob: 0bb9d0b329b3958c8799f3577789653d9ab26e83 [file] [log] [blame]
Shock Jiang698e6ed2014-11-09 11:22:24 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Yumin Xia2c509c22017-02-09 14:37:36 -08002/*
Davide Pesavento9a0d2132024-02-10 16:55:04 -05003 * Copyright (c) 2014-2024, Regents of the University of California.
Shock Jiang698e6ed2014-11-09 11:22:24 -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 "ndns-label.hpp"
21#include "logger.hpp"
22#include "clients/response.hpp"
23#include "clients/query.hpp"
24#include "clients/iterative-query-controller.hpp"
Yumin Xia99c821a2017-04-07 11:01:08 -070025#include "validator/validator.hpp"
Shock Jiang06cd2142014-11-23 17:36:02 -080026#include "util/util.hpp"
Shock Jiang698e6ed2014-11-09 11:22:24 -080027
Shock Jiang698e6ed2014-11-09 11:22:24 -080028#include <ndn-cxx/face.hpp>
Davide Pesavento948c50c2020-12-26 21:30:45 -050029#include <ndn-cxx/security/key-chain.hpp>
Shock Jiang698e6ed2014-11-09 11:22:24 -080030
Davide Pesavento948c50c2020-12-26 21:30:45 -050031#include <boost/asio/io_service.hpp>
32#include <boost/program_options.hpp>
33
Yumin Xia2c509c22017-02-09 14:37:36 -080034#include <fstream>
Davide Pesavento948c50c2020-12-26 21:30:45 -050035#include <iostream>
Shock Jiang698e6ed2014-11-09 11:22:24 -080036
Alexander Afanasyev08d18742018-03-15 16:31:28 -040037NDNS_LOG_INIT(Dig);
Shock Jiang5d5928c2014-12-03 13:41:22 -080038
Shock Jiang698e6ed2014-11-09 11:22:24 -080039namespace ndn {
40namespace ndns {
Shock Jiang698e6ed2014-11-09 11:22:24 -080041
42class NdnsDig
43{
44public:
Yumin Xia6343c5b2016-10-20 15:45:50 -070045 NdnsDig(const Name& dstLabel,
Shock Jiang5d5928c2014-12-03 13:41:22 -080046 const name::Component& rrType, bool shouldValidateIntermediate)
Shock Jiang698e6ed2014-11-09 11:22:24 -080047 : m_dstLabel(dstLabel)
48 , m_rrType(rrType)
Shock Jiang698e6ed2014-11-09 11:22:24 -080049 , m_interestLifetime(DEFAULT_INTEREST_LIFETIME)
Yumin Xia2c509c22017-02-09 14:37:36 -080050 , m_validator(NdnsValidatorBuilder::create(m_face))
Shock Jiang5d5928c2014-12-03 13:41:22 -080051 , m_shouldValidateIntermediate(shouldValidateIntermediate)
Shock Jiang698e6ed2014-11-09 11:22:24 -080052 , m_hasError(false)
53 {
Shock Jiang5d5928c2014-12-03 13:41:22 -080054 if (m_shouldValidateIntermediate)
55 m_ctr = std::unique_ptr<IterativeQueryController>
56 (new IterativeQueryController(m_dstLabel, m_rrType, m_interestLifetime,
57 bind(&NdnsDig::onSucceed, this, _1, _2),
58 bind(&NdnsDig::onFail, this, _1, _2),
Yumin Xia2c509c22017-02-09 14:37:36 -080059 m_face, m_validator.get()));
Shock Jiang5d5928c2014-12-03 13:41:22 -080060 else
61 m_ctr = std::unique_ptr<IterativeQueryController>
62 (new IterativeQueryController(m_dstLabel, m_rrType, m_interestLifetime,
63 bind(&NdnsDig::onSucceed, this, _1, _2),
64 bind(&NdnsDig::onFail, this, _1, _2),
65 m_face, nullptr));
Shock Jiang698e6ed2014-11-09 11:22:24 -080066 }
67
68 void
69 run()
70 {
71 NDNS_LOG_INFO(" =================================== "
72 << "start to dig label = " << this->m_dstLabel
73 << " for type = " << this->m_rrType
74 << " =================================== ");
75
76 try {
77 m_ctr->start(); // non-block, may throw exception
78 m_face.processEvents();
79 }
Yumin Xia2c509c22017-02-09 14:37:36 -080080 catch (const std::exception& e) {
Shock Jiang5d5928c2014-12-03 13:41:22 -080081 std::cerr << "Error: " << e.what();
Shock Jiang698e6ed2014-11-09 11:22:24 -080082 m_hasError = true;
83 }
84 }
85
86 void
87 stop()
88 {
Davide Pesavento9a0d2132024-02-10 16:55:04 -050089 m_face.getIoContext().stop();
Shock Jiang698e6ed2014-11-09 11:22:24 -080090 NDNS_LOG_TRACE("application stops.");
91 }
92
Shock Jiang5d5928c2014-12-03 13:41:22 -080093 void
94 setStartZone(const Name& start)
95 {
96 m_ctr->setStartComponentIndex(start.size());
97 }
98
Shock Jiang698e6ed2014-11-09 11:22:24 -080099private:
100 void
101 onSucceed(const Data& data, const Response& response)
102 {
Shock Jiang06cd2142014-11-23 17:36:02 -0800103 NDNS_LOG_INFO("Dig get following Response (need verification):");
104 Name name = Name().append(response.getZone()).append(response.getRrLabel());
105 if (name == m_dstLabel && m_rrType == response.getRrType()) {
106 NDNS_LOG_INFO("This is the final response returned by zone=" << response.getZone()
Yumin Xiaa484ba72016-11-10 20:40:12 -0800107 << " and NdnsType=" << response.getContentType()
Shock Jiang06cd2142014-11-23 17:36:02 -0800108 << ". It contains " << response.getRrs().size() << " RR(s)");
109
110 std::string msg;
111 size_t i = 0;
112 for (const auto& rr : response.getRrs()) {
113 try {
114 msg = std::string(reinterpret_cast<const char*>(rr.value()), rr.value_size());
115 NDNS_LOG_INFO("succeed to get the info from RR[" << i << "]"
116 "type=" << rr.type() << " content=" << msg);
117 }
Yumin Xia2c509c22017-02-09 14:37:36 -0800118 catch (const std::exception& e) {
Shock Jiang06cd2142014-11-23 17:36:02 -0800119 NDNS_LOG_INFO("error to get the info from RR[" << i << "]"
120 "type=" << rr.type());
121 }
122 ++i;
123 }
124 }
125 else {
126 NDNS_LOG_INFO("[* !! *] This is not final response.The target Label: "
127 << m_dstLabel << " may not exist");
128 }
129
130 if (m_dstFile.empty()) {
131 ;
132 }
133 else if (m_dstFile == "-") {
134 output(data, std::cout, true);
135 }
136 else {
137 NDNS_LOG_INFO("output Data packet to " << m_dstFile << " with BASE64 encoding format");
138 std::filebuf fb;
139 fb.open(m_dstFile, std::ios::out);
140 std::ostream os(&fb);
141 output(data, os, false);
142 }
143
Shock Jiang698e6ed2014-11-09 11:22:24 -0800144 NDNS_LOG_INFO(response);
Shock Jiang06cd2142014-11-23 17:36:02 -0800145
Shock Jiang698e6ed2014-11-09 11:22:24 -0800146 NDNS_LOG_TRACE("to verify the response");
Yumin Xia2c509c22017-02-09 14:37:36 -0800147 m_validator->validate(data,
Shock Jiang698e6ed2014-11-09 11:22:24 -0800148 bind(&NdnsDig::onDataValidated, this, _1),
149 bind(&NdnsDig::onDataValidationFailed, this, _1, _2)
150 );
151 }
152
Shock Jiang06cd2142014-11-23 17:36:02 -0800153
Shock Jiang698e6ed2014-11-09 11:22:24 -0800154 void
155 onFail(uint32_t errCode, const std::string& errMsg)
156 {
157 NDNS_LOG_INFO("fail to get response: errCode=" << errCode << " msg=" << errMsg);
158 m_hasError = true;
159 this->stop();
160 }
161
162 void
Yumin Xia2c509c22017-02-09 14:37:36 -0800163 onDataValidated(const Data& data)
Shock Jiang698e6ed2014-11-09 11:22:24 -0800164 {
165 NDNS_LOG_INFO("final data pass verification");
166 this->stop();
167 }
168
169 void
Alexander Afanasyev60514ec2020-06-03 14:18:53 -0400170 onDataValidationFailed(const Data& data, const security::ValidationError& err)
Shock Jiang698e6ed2014-11-09 11:22:24 -0800171 {
172 NDNS_LOG_INFO("final data does not pass verification");
173 m_hasError = true;
174 this->stop();
175 }
176
177public:
178 void
179 setInterestLifetime(const time::milliseconds& lifetime)
180 {
181 m_interestLifetime = lifetime;
182 }
183
Alexander Afanasyev984ca9d2016-12-19 13:09:14 -0800184 bool
Shock Jiang698e6ed2014-11-09 11:22:24 -0800185 hasError() const
186 {
187 return m_hasError;
188 }
189
Shock Jiang06cd2142014-11-23 17:36:02 -0800190 void
191 setDstFile(const std::string& dstFile)
192 {
193 m_dstFile = dstFile;
194 }
195
Shock Jiang698e6ed2014-11-09 11:22:24 -0800196private:
197 Name m_dstLabel;
198 name::Component m_rrType;
199
Shock Jiang698e6ed2014-11-09 11:22:24 -0800200 Name m_certName;
201 time::milliseconds m_interestLifetime;
202
203 Face m_face;
204
Alexander Afanasyev60514ec2020-06-03 14:18:53 -0400205 unique_ptr<security::Validator> m_validator;
Shock Jiang5d5928c2014-12-03 13:41:22 -0800206 bool m_shouldValidateIntermediate;
Shock Jiang698e6ed2014-11-09 11:22:24 -0800207 std::unique_ptr<QueryController> m_ctr;
208
209 bool m_hasError;
Shock Jiang06cd2142014-11-23 17:36:02 -0800210 std::string m_dstFile;
Shock Jiang698e6ed2014-11-09 11:22:24 -0800211};
212
213} // namespace ndns
214} // namespace ndn
215
216
217int
218main(int argc, char* argv[])
219{
Shock Jiang698e6ed2014-11-09 11:22:24 -0800220 using std::string;
221 using namespace ndn;
222
223 Name dstLabel;
224 int ttl = 4;
225 string rrType = "TXT";
Shock Jiang06cd2142014-11-23 17:36:02 -0800226 string dstFile;
Shock Jiang5d5928c2014-12-03 13:41:22 -0800227 bool shouldValidateIntermediate = true;
228 Name start("/ndn");
229
Shock Jiang698e6ed2014-11-09 11:22:24 -0800230 try {
231 namespace po = boost::program_options;
232 po::variables_map vm;
233
234 po::options_description generic("Generic Options");
235 generic.add_options()("help,h", "print help message");
236
237 po::options_description config("Configuration");
238 config.add_options()
Shock Jiangbb4e15b2014-12-05 09:48:02 -0800239 ("timeout,T", po::value<int>(&ttl), "query timeout. default: 4 sec")
Shock Jiang698e6ed2014-11-09 11:22:24 -0800240 ("rrtype,t", po::value<std::string>(&rrType), "set request RR Type. default: TXT")
Shock Jiang06cd2142014-11-23 17:36:02 -0800241 ("dstFile,d", po::value<std::string>(&dstFile), "set output file of the received Data. "
242 "if omitted, not print; if set to be -, print to stdout; else print to file")
Shock Jiang5d5928c2014-12-03 13:41:22 -0800243 ("start,s", po::value<Name>(&start)->default_value("/ndn"), "set first zone to query")
244 ("not-validate,n", "trigger not validate intermediate results")
Shock Jiang698e6ed2014-11-09 11:22:24 -0800245 ;
246
247 po::options_description hidden("Hidden Options");
248 hidden.add_options()
249 ("name", po::value<Name>(&dstLabel), "name to be resolved")
250 ;
251 po::positional_options_description postion;
252 postion.add("name", 1);
253
254 po::options_description cmdline_options;
255 cmdline_options.add(generic).add(config).add(hidden);
256
257 po::options_description config_file_options;
258 config_file_options.add(config).add(hidden);
259
Shock Jiang06cd2142014-11-23 17:36:02 -0800260 po::options_description visible("Usage: ndns-dig /name/to/be/resolved [-t rrType] [-T ttl]"
Shock Jiangbb4e15b2014-12-05 09:48:02 -0800261 "[-d dstFile] [-s startZone] [-n]\n"
Shock Jiang06cd2142014-11-23 17:36:02 -0800262 "Allowed options");
263
Shock Jiang698e6ed2014-11-09 11:22:24 -0800264 visible.add(generic).add(config);
265
266 po::parsed_options parsed =
267 po::command_line_parser(argc, argv).options(cmdline_options).positional(postion).run();
268
269 po::store(parsed, vm);
270 po::notify(vm);
271
272 if (vm.count("help")) {
Shock Jiang698e6ed2014-11-09 11:22:24 -0800273 std::cout << visible << std::endl;
274 return 0;
275 }
Shock Jiang5d5928c2014-12-03 13:41:22 -0800276
Shock Jiangbb4e15b2014-12-05 09:48:02 -0800277 if (!vm.count("name")) {
278 std::cerr << "must contain a target label parameter." << std::endl;
279 std::cerr << visible << std::endl;
280 return 1;
281 }
282
Shock Jiang5d5928c2014-12-03 13:41:22 -0800283 if (!start.isPrefixOf(dstLabel)) {
284 std::cerr << "Error: start zone " << start << " is not prefix of the target label "
285 << dstLabel << std::endl;
286 return 1;
287 }
288
289 if (vm.count("not-validate")) {
290 shouldValidateIntermediate = false;
291 }
292
293 if (ttl < 0) {
294 std::cerr << "Error: ttl parameter cannot be negative" << std::endl;
295 return 1;
296 }
Shock Jiang698e6ed2014-11-09 11:22:24 -0800297 }
298 catch (const std::exception& ex) {
299 std::cerr << "Parameter Error: " << ex.what() << std::endl;
Shock Jiang5d5928c2014-12-03 13:41:22 -0800300 return 1;
Shock Jiang698e6ed2014-11-09 11:22:24 -0800301 }
302
Shock Jiangbb4e15b2014-12-05 09:48:02 -0800303 try {
Yumin Xia6343c5b2016-10-20 15:45:50 -0700304 ndn::ndns::NdnsDig dig(dstLabel, ndn::name::Component(rrType), shouldValidateIntermediate);
Shock Jiangbb4e15b2014-12-05 09:48:02 -0800305 dig.setInterestLifetime(ndn::time::seconds(ttl));
306 dig.setDstFile(dstFile);
Shock Jiang5d5928c2014-12-03 13:41:22 -0800307
Shock Jiangbb4e15b2014-12-05 09:48:02 -0800308 // Due to ndn testbed does not contain the root zone
309 // dig here starts from the TLD (Top-level Domain)
310 // precondition is that TLD : 1) only contains one component in its name; 2) its name is routable
311 dig.setStartZone(start);
Shock Jiang698e6ed2014-11-09 11:22:24 -0800312
Shock Jiangbb4e15b2014-12-05 09:48:02 -0800313 dig.run();
Shock Jiang5d5928c2014-12-03 13:41:22 -0800314
Shock Jiangbb4e15b2014-12-05 09:48:02 -0800315 if (dig.hasError())
316 return 1;
317 else
318 return 0;
319 }
Shock Jiangbb4e15b2014-12-05 09:48:02 -0800320 catch (const std::exception& e) {
321 std::cerr << "Error: " << e.what() << std::endl;
322 return 1;
323 }
324
Shock Jiang698e6ed2014-11-09 11:22:24 -0800325}