blob: aebbdf1f162b1cfdb3409920cee920394fe06704 [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/*
3 * Copyright (c) 2014-2017, 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"
25#include "validator.hpp"
Shock Jiang06cd2142014-11-23 17:36:02 -080026#include "util/util.hpp"
Shock Jiang698e6ed2014-11-09 11:22:24 -080027
28#include <ndn-cxx/security/key-chain.hpp>
29#include <ndn-cxx/face.hpp>
30#include <boost/program_options.hpp>
31#include <boost/asio.hpp>
32#include <boost/filesystem.hpp>
33#include <boost/noncopyable.hpp>
34
Yumin Xia2c509c22017-02-09 14:37:36 -080035#include <iostream>
Shock Jiang698e6ed2014-11-09 11:22:24 -080036#include <memory>
37#include <string>
Yumin Xia2c509c22017-02-09 14:37:36 -080038#include <fstream>
Shock Jiang698e6ed2014-11-09 11:22:24 -080039
Alexander Afanasyevc7c99002015-10-09 17:27:30 -070040NDNS_LOG_INIT("NdnsDig")
Shock Jiang5d5928c2014-12-03 13:41:22 -080041
Shock Jiang698e6ed2014-11-09 11:22:24 -080042namespace ndn {
43namespace ndns {
Shock Jiang698e6ed2014-11-09 11:22:24 -080044
45class NdnsDig
46{
47public:
Yumin Xia6343c5b2016-10-20 15:45:50 -070048 NdnsDig(const Name& dstLabel,
Shock Jiang5d5928c2014-12-03 13:41:22 -080049 const name::Component& rrType, bool shouldValidateIntermediate)
Shock Jiang698e6ed2014-11-09 11:22:24 -080050 : m_dstLabel(dstLabel)
51 , m_rrType(rrType)
Shock Jiang698e6ed2014-11-09 11:22:24 -080052 , m_interestLifetime(DEFAULT_INTEREST_LIFETIME)
Yumin Xia2c509c22017-02-09 14:37:36 -080053 , m_validator(NdnsValidatorBuilder::create(m_face))
Shock Jiang5d5928c2014-12-03 13:41:22 -080054 , m_shouldValidateIntermediate(shouldValidateIntermediate)
Shock Jiang698e6ed2014-11-09 11:22:24 -080055 , m_hasError(false)
56 {
Shock Jiang5d5928c2014-12-03 13:41:22 -080057 if (m_shouldValidateIntermediate)
58 m_ctr = std::unique_ptr<IterativeQueryController>
59 (new IterativeQueryController(m_dstLabel, m_rrType, m_interestLifetime,
60 bind(&NdnsDig::onSucceed, this, _1, _2),
61 bind(&NdnsDig::onFail, this, _1, _2),
Yumin Xia2c509c22017-02-09 14:37:36 -080062 m_face, m_validator.get()));
Shock Jiang5d5928c2014-12-03 13:41:22 -080063 else
64 m_ctr = std::unique_ptr<IterativeQueryController>
65 (new IterativeQueryController(m_dstLabel, m_rrType, m_interestLifetime,
66 bind(&NdnsDig::onSucceed, this, _1, _2),
67 bind(&NdnsDig::onFail, this, _1, _2),
68 m_face, nullptr));
Shock Jiang698e6ed2014-11-09 11:22:24 -080069 }
70
71 void
72 run()
73 {
74 NDNS_LOG_INFO(" =================================== "
75 << "start to dig label = " << this->m_dstLabel
76 << " for type = " << this->m_rrType
77 << " =================================== ");
78
79 try {
80 m_ctr->start(); // non-block, may throw exception
81 m_face.processEvents();
82 }
Yumin Xia2c509c22017-02-09 14:37:36 -080083 catch (const std::exception& e) {
Shock Jiang5d5928c2014-12-03 13:41:22 -080084 std::cerr << "Error: " << e.what();
Shock Jiang698e6ed2014-11-09 11:22:24 -080085 m_hasError = true;
86 }
87 }
88
89 void
90 stop()
91 {
92 m_face.getIoService().stop();
93 NDNS_LOG_TRACE("application stops.");
94 }
95
Shock Jiang5d5928c2014-12-03 13:41:22 -080096 void
97 setStartZone(const Name& start)
98 {
99 m_ctr->setStartComponentIndex(start.size());
100 }
101
Shock Jiang698e6ed2014-11-09 11:22:24 -0800102private:
103 void
104 onSucceed(const Data& data, const Response& response)
105 {
Shock Jiang06cd2142014-11-23 17:36:02 -0800106 NDNS_LOG_INFO("Dig get following Response (need verification):");
107 Name name = Name().append(response.getZone()).append(response.getRrLabel());
108 if (name == m_dstLabel && m_rrType == response.getRrType()) {
109 NDNS_LOG_INFO("This is the final response returned by zone=" << response.getZone()
Yumin Xiaa484ba72016-11-10 20:40:12 -0800110 << " and NdnsType=" << response.getContentType()
Shock Jiang06cd2142014-11-23 17:36:02 -0800111 << ". It contains " << response.getRrs().size() << " RR(s)");
112
113 std::string msg;
114 size_t i = 0;
115 for (const auto& rr : response.getRrs()) {
116 try {
117 msg = std::string(reinterpret_cast<const char*>(rr.value()), rr.value_size());
118 NDNS_LOG_INFO("succeed to get the info from RR[" << i << "]"
119 "type=" << rr.type() << " content=" << msg);
120 }
Yumin Xia2c509c22017-02-09 14:37:36 -0800121 catch (const std::exception& e) {
Shock Jiang06cd2142014-11-23 17:36:02 -0800122 NDNS_LOG_INFO("error to get the info from RR[" << i << "]"
123 "type=" << rr.type());
124 }
125 ++i;
126 }
127 }
128 else {
129 NDNS_LOG_INFO("[* !! *] This is not final response.The target Label: "
130 << m_dstLabel << " may not exist");
131 }
132
133 if (m_dstFile.empty()) {
134 ;
135 }
136 else if (m_dstFile == "-") {
137 output(data, std::cout, true);
138 }
139 else {
140 NDNS_LOG_INFO("output Data packet to " << m_dstFile << " with BASE64 encoding format");
141 std::filebuf fb;
142 fb.open(m_dstFile, std::ios::out);
143 std::ostream os(&fb);
144 output(data, os, false);
145 }
146
Shock Jiang698e6ed2014-11-09 11:22:24 -0800147 NDNS_LOG_INFO(response);
Shock Jiang06cd2142014-11-23 17:36:02 -0800148
Shock Jiang698e6ed2014-11-09 11:22:24 -0800149 NDNS_LOG_TRACE("to verify the response");
Yumin Xia2c509c22017-02-09 14:37:36 -0800150 m_validator->validate(data,
Shock Jiang698e6ed2014-11-09 11:22:24 -0800151 bind(&NdnsDig::onDataValidated, this, _1),
152 bind(&NdnsDig::onDataValidationFailed, this, _1, _2)
153 );
154 }
155
Shock Jiang06cd2142014-11-23 17:36:02 -0800156
Shock Jiang698e6ed2014-11-09 11:22:24 -0800157 void
158 onFail(uint32_t errCode, const std::string& errMsg)
159 {
160 NDNS_LOG_INFO("fail to get response: errCode=" << errCode << " msg=" << errMsg);
161 m_hasError = true;
162 this->stop();
163 }
164
165 void
Yumin Xia2c509c22017-02-09 14:37:36 -0800166 onDataValidated(const Data& data)
Shock Jiang698e6ed2014-11-09 11:22:24 -0800167 {
168 NDNS_LOG_INFO("final data pass verification");
169 this->stop();
170 }
171
172 void
Yumin Xia2c509c22017-02-09 14:37:36 -0800173 onDataValidationFailed(const Data& data, const security::v2::ValidationError& err)
Shock Jiang698e6ed2014-11-09 11:22:24 -0800174 {
175 NDNS_LOG_INFO("final data does not pass verification");
176 m_hasError = true;
177 this->stop();
178 }
179
180public:
181 void
182 setInterestLifetime(const time::milliseconds& lifetime)
183 {
184 m_interestLifetime = lifetime;
185 }
186
Alexander Afanasyev984ca9d2016-12-19 13:09:14 -0800187 bool
Shock Jiang698e6ed2014-11-09 11:22:24 -0800188 hasError() const
189 {
190 return m_hasError;
191 }
192
Shock Jiang06cd2142014-11-23 17:36:02 -0800193 void
194 setDstFile(const std::string& dstFile)
195 {
196 m_dstFile = dstFile;
197 }
198
Shock Jiang698e6ed2014-11-09 11:22:24 -0800199private:
200 Name m_dstLabel;
201 name::Component m_rrType;
202
Shock Jiang698e6ed2014-11-09 11:22:24 -0800203 Name m_certName;
204 time::milliseconds m_interestLifetime;
205
206 Face m_face;
207
Yumin Xia2c509c22017-02-09 14:37:36 -0800208 unique_ptr<security::v2::Validator> m_validator;
Shock Jiang5d5928c2014-12-03 13:41:22 -0800209 bool m_shouldValidateIntermediate;
Shock Jiang698e6ed2014-11-09 11:22:24 -0800210 std::unique_ptr<QueryController> m_ctr;
211
212 bool m_hasError;
Shock Jiang06cd2142014-11-23 17:36:02 -0800213 std::string m_dstFile;
Shock Jiang698e6ed2014-11-09 11:22:24 -0800214};
215
216} // namespace ndns
217} // namespace ndn
218
219
220int
221main(int argc, char* argv[])
222{
223 ndn::ndns::log::init();
224 using std::string;
225 using namespace ndn;
226
227 Name dstLabel;
228 int ttl = 4;
229 string rrType = "TXT";
Shock Jiang06cd2142014-11-23 17:36:02 -0800230 string dstFile;
Shock Jiang5d5928c2014-12-03 13:41:22 -0800231 bool shouldValidateIntermediate = true;
232 Name start("/ndn");
233
Shock Jiang698e6ed2014-11-09 11:22:24 -0800234 try {
235 namespace po = boost::program_options;
236 po::variables_map vm;
237
238 po::options_description generic("Generic Options");
239 generic.add_options()("help,h", "print help message");
240
241 po::options_description config("Configuration");
242 config.add_options()
Shock Jiangbb4e15b2014-12-05 09:48:02 -0800243 ("timeout,T", po::value<int>(&ttl), "query timeout. default: 4 sec")
Shock Jiang698e6ed2014-11-09 11:22:24 -0800244 ("rrtype,t", po::value<std::string>(&rrType), "set request RR Type. default: TXT")
Shock Jiang06cd2142014-11-23 17:36:02 -0800245 ("dstFile,d", po::value<std::string>(&dstFile), "set output file of the received Data. "
246 "if omitted, not print; if set to be -, print to stdout; else print to file")
Shock Jiang5d5928c2014-12-03 13:41:22 -0800247 ("start,s", po::value<Name>(&start)->default_value("/ndn"), "set first zone to query")
248 ("not-validate,n", "trigger not validate intermediate results")
Shock Jiang698e6ed2014-11-09 11:22:24 -0800249 ;
250
251 po::options_description hidden("Hidden Options");
252 hidden.add_options()
253 ("name", po::value<Name>(&dstLabel), "name to be resolved")
254 ;
255 po::positional_options_description postion;
256 postion.add("name", 1);
257
258 po::options_description cmdline_options;
259 cmdline_options.add(generic).add(config).add(hidden);
260
261 po::options_description config_file_options;
262 config_file_options.add(config).add(hidden);
263
Shock Jiang06cd2142014-11-23 17:36:02 -0800264 po::options_description visible("Usage: ndns-dig /name/to/be/resolved [-t rrType] [-T ttl]"
Shock Jiangbb4e15b2014-12-05 09:48:02 -0800265 "[-d dstFile] [-s startZone] [-n]\n"
Shock Jiang06cd2142014-11-23 17:36:02 -0800266 "Allowed options");
267
Shock Jiang698e6ed2014-11-09 11:22:24 -0800268 visible.add(generic).add(config);
269
270 po::parsed_options parsed =
271 po::command_line_parser(argc, argv).options(cmdline_options).positional(postion).run();
272
273 po::store(parsed, vm);
274 po::notify(vm);
275
276 if (vm.count("help")) {
Shock Jiang698e6ed2014-11-09 11:22:24 -0800277 std::cout << visible << std::endl;
278 return 0;
279 }
Shock Jiang5d5928c2014-12-03 13:41:22 -0800280
Shock Jiangbb4e15b2014-12-05 09:48:02 -0800281 if (!vm.count("name")) {
282 std::cerr << "must contain a target label parameter." << std::endl;
283 std::cerr << visible << std::endl;
284 return 1;
285 }
286
Shock Jiang5d5928c2014-12-03 13:41:22 -0800287 if (!start.isPrefixOf(dstLabel)) {
288 std::cerr << "Error: start zone " << start << " is not prefix of the target label "
289 << dstLabel << std::endl;
290 return 1;
291 }
292
293 if (vm.count("not-validate")) {
294 shouldValidateIntermediate = false;
295 }
296
297 if (ttl < 0) {
298 std::cerr << "Error: ttl parameter cannot be negative" << std::endl;
299 return 1;
300 }
Shock Jiang698e6ed2014-11-09 11:22:24 -0800301 }
302 catch (const std::exception& ex) {
303 std::cerr << "Parameter Error: " << ex.what() << std::endl;
Shock Jiang5d5928c2014-12-03 13:41:22 -0800304 return 1;
Shock Jiang698e6ed2014-11-09 11:22:24 -0800305 }
306
Shock Jiangbb4e15b2014-12-05 09:48:02 -0800307 try {
Yumin Xia6343c5b2016-10-20 15:45:50 -0700308 ndn::ndns::NdnsDig dig(dstLabel, ndn::name::Component(rrType), shouldValidateIntermediate);
Shock Jiangbb4e15b2014-12-05 09:48:02 -0800309 dig.setInterestLifetime(ndn::time::seconds(ttl));
310 dig.setDstFile(dstFile);
Shock Jiang5d5928c2014-12-03 13:41:22 -0800311
Shock Jiangbb4e15b2014-12-05 09:48:02 -0800312 // Due to ndn testbed does not contain the root zone
313 // dig here starts from the TLD (Top-level Domain)
314 // precondition is that TLD : 1) only contains one component in its name; 2) its name is routable
315 dig.setStartZone(start);
Shock Jiang698e6ed2014-11-09 11:22:24 -0800316
Shock Jiangbb4e15b2014-12-05 09:48:02 -0800317 dig.run();
Shock Jiang5d5928c2014-12-03 13:41:22 -0800318
Shock Jiangbb4e15b2014-12-05 09:48:02 -0800319 if (dig.hasError())
320 return 1;
321 else
322 return 0;
323 }
Shock Jiangbb4e15b2014-12-05 09:48:02 -0800324 catch (const std::exception& e) {
325 std::cerr << "Error: " << e.what() << std::endl;
326 return 1;
327 }
328
Shock Jiang698e6ed2014-11-09 11:22:24 -0800329}