blob: f14d3f654cf9a21d28ca3cc56ec22f07b2d68a0a [file] [log] [blame]
Alexander Afanasyev82afa1a2014-03-20 16:56:56 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Davide Pesaventoa997d292017-08-24 20:16:59 -04002/*
Davide Pesavento45c1f6a2025-01-01 19:30:30 -05003 * Copyright (c) 2014-2025, Regents of the University of California,
Junxiao Shifbf78342015-01-23 14:46:41 -07004 * Arizona Board of Regents,
5 * Colorado State University,
6 * University Pierre & Marie Curie, Sorbonne University,
7 * Washington University in St. Louis,
8 * Beijing Institute of Technology,
9 * The University of Memphis.
Alexander Afanasyev9bcbc7c2014-04-06 19:37:37 -070010 *
11 * This file is part of NFD (Named Data Networking Forwarding Daemon).
12 * See AUTHORS.md for complete list of NFD authors and contributors.
13 *
14 * NFD is free software: you can redistribute it and/or modify it under the terms
15 * of the GNU General Public License as published by the Free Software Foundation,
16 * either version 3 of the License, or (at your option) any later version.
17 *
18 * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
19 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
20 * PURPOSE. See the GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License along with
23 * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
Junxiao Shidda0b462014-06-30 19:42:29 -070024 */
Alexander Afanasyev82afa1a2014-03-20 16:56:56 -070025
Davide Pesaventoa997d292017-08-24 20:16:59 -040026#include "core/network.hpp"
27#include "core/version.hpp"
28
Alexander Afanasyev4a771362014-04-24 21:29:33 -070029#include <ndn-cxx/face.hpp>
Davide Pesavento45c1f6a2025-01-01 19:30:30 -050030#include <ndn-cxx/mgmt/nfd/control-command.hpp>
Junxiao Shi25c6ce42016-09-09 13:49:59 +000031#include <ndn-cxx/mgmt/nfd/controller.hpp>
32#include <ndn-cxx/mgmt/nfd/face-monitor.hpp>
Davide Pesavento40641272023-03-16 13:31:12 -040033#include <ndn-cxx/mgmt/nfd/status-dataset.hpp>
Junxiao Shi83be1da2017-06-30 13:37:37 +000034#include <ndn-cxx/net/face-uri.hpp>
Junxiao Shi08e96312017-06-29 18:07:27 +000035#include <ndn-cxx/security/key-chain.hpp>
Alexander Afanasyev82afa1a2014-03-20 16:56:56 -070036
Davide Pesaventoa9b09b62022-06-04 14:07:25 -040037#include <boost/asio/signal_set.hpp>
Davide Pesavento97e33022019-02-14 16:00:50 -050038#include <boost/exception/diagnostic_information.hpp>
Alexander Afanasyev82afa1a2014-03-20 16:56:56 -070039#include <boost/program_options/options_description.hpp>
Alexander Afanasyev82afa1a2014-03-20 16:56:56 -070040#include <boost/program_options/parsers.hpp>
Davide Pesaventoe422f9e2022-06-03 01:30:23 -040041#include <boost/program_options/variables_map.hpp>
Alexander Afanasyev82afa1a2014-03-20 16:56:56 -070042
Davide Pesaventoa997d292017-08-24 20:16:59 -040043#include <iostream>
Alexander Afanasyev82afa1a2014-03-20 16:56:56 -070044
Davide Pesaventoe422f9e2022-06-03 01:30:23 -040045namespace nfd::tools::autoreg {
Junxiao Shi08e96312017-06-29 18:07:27 +000046
Davide Pesaventoa9b09b62022-06-04 14:07:25 -040047using ndn::FaceUri;
48using ndn::Name;
49
Junxiao Shidda0b462014-06-30 19:42:29 -070050class AutoregServer : boost::noncopyable
Alexander Afanasyev82afa1a2014-03-20 16:56:56 -070051{
52public:
Davide Pesaventoe422f9e2022-06-03 01:30:23 -040053 static void
Alexander Afanasyev81c1a2a2014-08-14 16:07:47 -070054 onRegisterCommandSuccess(uint64_t faceId, const Name& prefix)
Alexander Afanasyev82afa1a2014-03-20 16:56:56 -070055 {
Davide Pesaventoe422f9e2022-06-03 01:30:23 -040056 std::cerr << "SUCCESS: register " << prefix << " on face " << faceId << std::endl;
Alexander Afanasyev82afa1a2014-03-20 16:56:56 -070057 }
58
Davide Pesaventoe422f9e2022-06-03 01:30:23 -040059 static void
Alexander Afanasyev81c1a2a2014-08-14 16:07:47 -070060 onRegisterCommandFailure(uint64_t faceId, const Name& prefix,
Davide Pesaventoe422f9e2022-06-03 01:30:23 -040061 const ndn::nfd::ControlResponse& response)
Alexander Afanasyev82afa1a2014-03-20 16:56:56 -070062 {
Alexander Afanasyev81c1a2a2014-08-14 16:07:47 -070063 std::cerr << "FAILED: register " << prefix << " on face " << faceId
Junxiao Shi29b41282016-08-22 03:47:02 +000064 << " (code: " << response.getCode() << ", reason: " << response.getText() << ")"
65 << std::endl;
Alexander Afanasyev82afa1a2014-03-20 16:56:56 -070066 }
67
Junxiao Shidda0b462014-06-30 19:42:29 -070068 /**
Alexander Afanasyev81c1a2a2014-08-14 16:07:47 -070069 * \return true if uri has schema allowed to do auto-registrations
Junxiao Shidda0b462014-06-30 19:42:29 -070070 */
Davide Pesavento59769b12017-11-12 23:52:06 -050071 static bool
Alexander Afanasyev81c1a2a2014-08-14 16:07:47 -070072 hasAllowedSchema(const FaceUri& uri)
Alexander Afanasyev82afa1a2014-03-20 16:56:56 -070073 {
74 const std::string& scheme = uri.getScheme();
Davide Pesavento59769b12017-11-12 23:52:06 -050075 return scheme == "udp4" || scheme == "tcp4" ||
76 scheme == "udp6" || scheme == "tcp6";
Alexander Afanasyev81c1a2a2014-08-14 16:07:47 -070077 }
Alexander Afanasyev82afa1a2014-03-20 16:56:56 -070078
Alexander Afanasyev81c1a2a2014-08-14 16:07:47 -070079 /**
Alexander Afanasyevf056c112014-08-14 16:39:25 -070080 * \return true if address is blacklisted
Alexander Afanasyev81c1a2a2014-08-14 16:07:47 -070081 */
82 bool
Davide Pesavento59769b12017-11-12 23:52:06 -050083 isBlacklisted(const boost::asio::ip::address& address) const
Alexander Afanasyev81c1a2a2014-08-14 16:07:47 -070084 {
Junxiao Shi08e96312017-06-29 18:07:27 +000085 return std::any_of(m_blackList.begin(), m_blackList.end(),
Davide Pesaventoe422f9e2022-06-03 01:30:23 -040086 [&] (const auto& net) { return net.doesContain(address); });
Alexander Afanasyev81c1a2a2014-08-14 16:07:47 -070087 }
88
89 /**
Alexander Afanasyevf056c112014-08-14 16:39:25 -070090 * \return true if address is whitelisted
Alexander Afanasyev81c1a2a2014-08-14 16:07:47 -070091 */
92 bool
Davide Pesavento59769b12017-11-12 23:52:06 -050093 isWhitelisted(const boost::asio::ip::address& address) const
Alexander Afanasyev81c1a2a2014-08-14 16:07:47 -070094 {
Junxiao Shi08e96312017-06-29 18:07:27 +000095 return std::any_of(m_whiteList.begin(), m_whiteList.end(),
Davide Pesaventoe422f9e2022-06-03 01:30:23 -040096 [&] (const auto& net) { return net.doesContain(address); });
Alexander Afanasyev82afa1a2014-03-20 16:56:56 -070097 }
98
99 void
Davide Pesavento22db5392017-04-14 00:56:43 -0400100 registerPrefixesForFace(uint64_t faceId, const std::vector<Name>& prefixes)
Alexander Afanasyev82afa1a2014-03-20 16:56:56 -0700101 {
Junxiao Shi08e96312017-06-29 18:07:27 +0000102 for (const Name& prefix : prefixes) {
Davide Pesaventoe422f9e2022-06-03 01:30:23 -0400103 m_controller.start<ndn::nfd::RibRegisterCommand>(
104 ndn::nfd::ControlParameters()
Junxiao Shi08e96312017-06-29 18:07:27 +0000105 .setName(prefix)
106 .setFaceId(faceId)
Davide Pesaventoe422f9e2022-06-03 01:30:23 -0400107 .setOrigin(ndn::nfd::ROUTE_ORIGIN_AUTOREG)
Junxiao Shi08e96312017-06-29 18:07:27 +0000108 .setCost(m_cost)
Davide Pesaventoa9b09b62022-06-04 14:07:25 -0400109 .setExpirationPeriod(ndn::time::milliseconds::max()),
Davide Pesaventoe422f9e2022-06-03 01:30:23 -0400110 [=] (auto&&...) { onRegisterCommandSuccess(faceId, prefix); },
111 [=] (const auto& response) { onRegisterCommandFailure(faceId, prefix, response); });
Junxiao Shi08e96312017-06-29 18:07:27 +0000112 }
Alexander Afanasyev82afa1a2014-03-20 16:56:56 -0700113 }
114
115 void
Davide Pesaventoe422f9e2022-06-03 01:30:23 -0400116 registerPrefixesIfNeeded(uint64_t faceId, const FaceUri& uri, ndn::nfd::FacePersistency facePersistency)
Alexander Afanasyevf056c112014-08-14 16:39:25 -0700117 {
118 if (hasAllowedSchema(uri)) {
119 boost::system::error_code ec;
Davide Pesaventod91fe6d2023-10-04 21:40:02 -0400120 auto address = boost::asio::ip::make_address(uri.getHost(), ec);
Alexander Afanasyevf056c112014-08-14 16:39:25 -0700121
122 if (!address.is_multicast()) {
123 // register all-face prefixes
124 registerPrefixesForFace(faceId, m_allFacesPrefixes);
125
126 // register autoreg prefixes if new face is on-demand and not blacklisted and whitelisted
Davide Pesaventoe422f9e2022-06-03 01:30:23 -0400127 if (facePersistency == ndn::nfd::FACE_PERSISTENCY_ON_DEMAND &&
Chengyu Fan9942cea2014-10-13 14:47:13 -0600128 !isBlacklisted(address) && isWhitelisted(address)) {
Alexander Afanasyevf056c112014-08-14 16:39:25 -0700129 registerPrefixesForFace(faceId, m_autoregPrefixes);
130 }
131 }
132 }
133 }
134
135 void
Davide Pesaventoe422f9e2022-06-03 01:30:23 -0400136 onNotification(const ndn::nfd::FaceEventNotification& notification)
Alexander Afanasyev82afa1a2014-03-20 16:56:56 -0700137 {
Davide Pesaventoe422f9e2022-06-03 01:30:23 -0400138 if (notification.getKind() == ndn::nfd::FACE_EVENT_CREATED &&
139 notification.getFaceScope() != ndn::nfd::FACE_SCOPE_LOCAL) {
Junxiao Shi08e96312017-06-29 18:07:27 +0000140 std::cerr << "PROCESSING: " << notification << std::endl;
Alexander Afanasyev81c1a2a2014-08-14 16:07:47 -0700141
Junxiao Shi08e96312017-06-29 18:07:27 +0000142 registerPrefixesIfNeeded(notification.getFaceId(), FaceUri(notification.getRemoteUri()),
143 notification.getFacePersistency());
144 }
145 else {
146 std::cerr << "IGNORED: " << notification << std::endl;
147 }
Alexander Afanasyev82afa1a2014-03-20 16:56:56 -0700148 }
149
Alexander Afanasyev82afa1a2014-03-20 16:56:56 -0700150 void
151 startProcessing()
152 {
Junxiao Shidda0b462014-06-30 19:42:29 -0700153 std::cerr << "AUTOREG prefixes: " << std::endl;
Junxiao Shi08e96312017-06-29 18:07:27 +0000154 for (const Name& prefix : m_autoregPrefixes) {
155 std::cout << " " << prefix << std::endl;
156 }
Alexander Afanasyev81c1a2a2014-08-14 16:07:47 -0700157 std::cerr << "ALL-FACES-AUTOREG prefixes: " << std::endl;
Junxiao Shi08e96312017-06-29 18:07:27 +0000158 for (const Name& prefix : m_allFacesPrefixes) {
159 std::cout << " " << prefix << std::endl;
160 }
Alexander Afanasyev82afa1a2014-03-20 16:56:56 -0700161
Junxiao Shi08e96312017-06-29 18:07:27 +0000162 if (!m_blackList.empty()) {
163 std::cerr << "Blacklisted networks: " << std::endl;
164 for (const Network& network : m_blackList) {
165 std::cout << " " << network << std::endl;
Alexander Afanasyev82afa1a2014-03-20 16:56:56 -0700166 }
Junxiao Shi08e96312017-06-29 18:07:27 +0000167 }
Alexander Afanasyev82afa1a2014-03-20 16:56:56 -0700168
Junxiao Shidda0b462014-06-30 19:42:29 -0700169 std::cerr << "Whitelisted networks: " << std::endl;
Junxiao Shi08e96312017-06-29 18:07:27 +0000170 for (const Network& network : m_whiteList) {
171 std::cout << " " << network << std::endl;
172 }
Alexander Afanasyev82afa1a2014-03-20 16:56:56 -0700173
Davide Pesaventoe422f9e2022-06-03 01:30:23 -0400174 m_faceMonitor.onNotification.connect([this] (const auto& notif) { onNotification(notif); });
Junxiao Shi15b12e72014-08-09 19:56:24 -0700175 m_faceMonitor.start();
Alexander Afanasyev82afa1a2014-03-20 16:56:56 -0700176
Davide Pesaventoe277f8b2023-11-11 17:14:02 -0500177 boost::asio::signal_set signalSet(m_face.getIoContext(), SIGINT, SIGTERM);
Davide Pesavento412c9822021-07-02 00:21:05 -0400178 signalSet.async_wait([this] (auto&&...) { m_face.shutdown(); });
Alexander Afanasyev82afa1a2014-03-20 16:56:56 -0700179
180 m_face.processEvents();
181 }
182
Alexander Afanasyevf056c112014-08-14 16:39:25 -0700183 void
184 startFetchingFaceStatusDataset()
185 {
Davide Pesaventoe422f9e2022-06-03 01:30:23 -0400186 m_controller.fetch<ndn::nfd::FaceDataset>(
Davide Pesavento412c9822021-07-02 00:21:05 -0400187 [this] (const auto& faces) {
Davide Pesavento22db5392017-04-14 00:56:43 -0400188 for (const auto& faceStatus : faces) {
Weiwei Liu7c795132016-10-07 14:22:54 -0700189 registerPrefixesIfNeeded(faceStatus.getFaceId(), FaceUri(faceStatus.getRemoteUri()),
190 faceStatus.getFacePersistency());
191 }
192 },
Davide Pesavento412c9822021-07-02 00:21:05 -0400193 [] (auto&&...) {});
Alexander Afanasyevf056c112014-08-14 16:39:25 -0700194 }
195
Alexander Afanasyev82afa1a2014-03-20 16:56:56 -0700196 int
197 main(int argc, char* argv[])
198 {
Davide Pesavento22db5392017-04-14 00:56:43 -0400199 namespace po = boost::program_options;
200
Davide Pesavento59769b12017-11-12 23:52:06 -0500201 po::options_description optionsDesc("Options");
202 optionsDesc.add_options()
203 ("help,h", "print this message and exit")
204 ("version,V", "show version information and exit")
Davide Pesavento22db5392017-04-14 00:56:43 -0400205 ("prefix,i", po::value<std::vector<Name>>(&m_autoregPrefixes)->composing(),
Davide Pesavento59769b12017-11-12 23:52:06 -0500206 "prefix that should be automatically registered when a new non-local face is created")
Davide Pesavento22db5392017-04-14 00:56:43 -0400207 ("all-faces-prefix,a", po::value<std::vector<Name>>(&m_allFacesPrefixes)->composing(),
Alexander Afanasyev81c1a2a2014-08-14 16:07:47 -0700208 "prefix that should be automatically registered for all TCP and UDP non-local faces "
209 "(blacklists and whitelists do not apply to this prefix)")
Davide Pesaventoe422f9e2022-06-03 01:30:23 -0400210 ("cost,c", po::value<uint64_t>(&m_cost)->default_value(m_cost),
Davide Pesavento59769b12017-11-12 23:52:06 -0500211 "FIB cost that should be assigned to autoreg nexthops")
Davide Pesavento22db5392017-04-14 00:56:43 -0400212 ("whitelist,w", po::value<std::vector<Network>>(&m_whiteList)->composing(),
Alexander Afanasyev82afa1a2014-03-20 16:56:56 -0700213 "Whitelisted network, e.g., 192.168.2.0/24 or ::1/128")
Davide Pesavento22db5392017-04-14 00:56:43 -0400214 ("blacklist,b", po::value<std::vector<Network>>(&m_blackList)->composing(),
Alexander Afanasyev82afa1a2014-03-20 16:56:56 -0700215 "Blacklisted network, e.g., 192.168.2.32/30 or ::1/128")
216 ;
217
Davide Pesaventoe422f9e2022-06-03 01:30:23 -0400218 auto usage = [&] (std::ostream& os) {
219 os << "Usage: " << argv[0] << " [--prefix=</autoreg/prefix>]... [options]\n"
220 << "\n"
221 << optionsDesc;
222 };
223
Alexander Afanasyev82afa1a2014-03-20 16:56:56 -0700224 po::variables_map options;
Junxiao Shi08e96312017-06-29 18:07:27 +0000225 try {
Davide Pesavento59769b12017-11-12 23:52:06 -0500226 po::store(po::parse_command_line(argc, argv, optionsDesc), options);
Junxiao Shi08e96312017-06-29 18:07:27 +0000227 po::notify(options);
228 }
229 catch (const std::exception& e) {
230 std::cerr << "ERROR: " << e.what() << std::endl << std::endl;
Davide Pesaventoe422f9e2022-06-03 01:30:23 -0400231 usage(std::cerr);
Davide Pesavento59769b12017-11-12 23:52:06 -0500232 return 2;
Junxiao Shi08e96312017-06-29 18:07:27 +0000233 }
Alexander Afanasyev82afa1a2014-03-20 16:56:56 -0700234
Davide Pesavento59769b12017-11-12 23:52:06 -0500235 if (options.count("help") > 0) {
Davide Pesaventoe422f9e2022-06-03 01:30:23 -0400236 usage(std::cout);
Junxiao Shi08e96312017-06-29 18:07:27 +0000237 return 0;
238 }
Alexander Afanasyev82afa1a2014-03-20 16:56:56 -0700239
Davide Pesavento59769b12017-11-12 23:52:06 -0500240 if (options.count("version") > 0) {
Junxiao Shi08e96312017-06-29 18:07:27 +0000241 std::cout << NFD_VERSION_BUILD_STRING << std::endl;
242 return 0;
243 }
Alexander Afanasyevb47d5382014-05-05 14:35:03 -0700244
Junxiao Shi08e96312017-06-29 18:07:27 +0000245 if (m_autoregPrefixes.empty() && m_allFacesPrefixes.empty()) {
246 std::cerr << "ERROR: at least one --prefix or --all-faces-prefix must be specified"
247 << std::endl << std::endl;
Davide Pesaventoe422f9e2022-06-03 01:30:23 -0400248 usage(std::cerr);
Junxiao Shi08e96312017-06-29 18:07:27 +0000249 return 2;
250 }
Alexander Afanasyev82afa1a2014-03-20 16:56:56 -0700251
Junxiao Shi08e96312017-06-29 18:07:27 +0000252 if (m_whiteList.empty()) {
253 // Allow everything
254 m_whiteList.push_back(Network::getMaxRangeV4());
255 m_whiteList.push_back(Network::getMaxRangeV6());
256 }
Alexander Afanasyev82afa1a2014-03-20 16:56:56 -0700257
Junxiao Shi08e96312017-06-29 18:07:27 +0000258 try {
259 startFetchingFaceStatusDataset();
260 startProcessing();
261 }
262 catch (const std::exception& e) {
Davide Pesavento97e33022019-02-14 16:00:50 -0500263 std::cerr << "ERROR: " << boost::diagnostic_information(e);
Davide Pesavento59769b12017-11-12 23:52:06 -0500264 return 1;
Junxiao Shi08e96312017-06-29 18:07:27 +0000265 }
Alexander Afanasyev82afa1a2014-03-20 16:56:56 -0700266
267 return 0;
268 }
269
270private:
Davide Pesaventoe422f9e2022-06-03 01:30:23 -0400271 ndn::Face m_face;
272 ndn::KeyChain m_keyChain;
273 ndn::nfd::Controller m_controller{m_face, m_keyChain};
274 ndn::nfd::FaceMonitor m_faceMonitor{m_face};
Davide Pesavento22db5392017-04-14 00:56:43 -0400275 std::vector<Name> m_autoregPrefixes;
276 std::vector<Name> m_allFacesPrefixes;
Davide Pesaventoe422f9e2022-06-03 01:30:23 -0400277 uint64_t m_cost = 255;
Alexander Afanasyev82afa1a2014-03-20 16:56:56 -0700278 std::vector<Network> m_whiteList;
279 std::vector<Network> m_blackList;
280};
281
Davide Pesaventoe422f9e2022-06-03 01:30:23 -0400282} // namespace nfd::tools::autoreg
Alexander Afanasyev82afa1a2014-03-20 16:56:56 -0700283
284int
285main(int argc, char* argv[])
286{
Davide Pesaventoe422f9e2022-06-03 01:30:23 -0400287 nfd::tools::autoreg::AutoregServer server;
Alexander Afanasyev82afa1a2014-03-20 16:56:56 -0700288 return server.main(argc, argv);
289}