blob: c377142cf8f1fb9b722ebdf788e275018e2e679e [file] [log] [blame]
Junxiao Shidc2d6d22016-08-04 14:30:23 +00001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
3 * Copyright (c) 2013-2016 Regents of the University of California.
4 *
5 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
6 *
7 * ndn-cxx library is free software: you can redistribute it and/or modify it under the
8 * terms of the GNU Lesser General Public License as published by the Free Software
9 * Foundation, either version 3 of the License, or (at your option) any later version.
10 *
11 * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
14 *
15 * You should have received copies of the GNU General Public License and GNU Lesser
16 * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
20 */
21
22#ifndef NDN_SECURITY_COMMAND_INTEREST_VALIDATOR_HPP
23#define NDN_SECURITY_COMMAND_INTEREST_VALIDATOR_HPP
24
25#include "validator.hpp"
26#include <boost/multi_index_container.hpp>
27#include <boost/multi_index/ordered_index.hpp>
28#include <boost/multi_index/sequenced_index.hpp>
29#include <boost/multi_index/key_extractors.hpp>
30
31namespace ndn {
32namespace security {
33
34/** \brief a validator for stop-and-wait command Interests
35 * \sa https://redmine.named-data.net/projects/ndn-cxx/wiki/CommandInterest
36 *
37 * This validator checks timestamp field of a stop-and-wait command Interest.
38 * Signed Interest validation and Data validation requests are delegated to an inner validator.
39 */
40class CommandInterestValidator : public Validator
41{
42public:
43 class Options
44 {
45 public:
46 Options()
47 {
48 }
49
50 public:
51 /** \brief tolerance of initial timestamp
52 *
53 * A stop-and-wait command Interest is considered "initial" if the validator
54 * has not recorded the last timestamp from the same public key, or when
55 * such knowledge has been erased.
56 * For an initial command Interest, its timestamp is compared to the current
57 * system clock, and the command Interest is rejected if the absolute difference
58 * is greater than the grace interval.
59 *
60 * This should be positive.
61 * Setting this option to 0 or negative causes the validator to require exactly same
62 * timestamp as the system clock, which most likely rejects all command Interests.
63 */
64 time::nanoseconds gracePeriod = time::seconds(120);
65
66 /** \brief max number of distinct public keys to record last timestamp
67 *
68 * The validator records last timestamps for every public key.
69 * For a subsequent command Interest using the same public key,
70 * its timestamp is compared to the last timestamp from that public key,
71 * and the command Interest is rejected if its timestamp is
72 * less than or equal to the recorded timestamp.
73 *
74 * This option limits the number of distinct public keys being tracked.
75 * If the limit is exceeded, the oldest record is deleted.
76 *
77 * Setting this option to -1 allows tracking unlimited public keys.
78 * Setting this option to 0 disables last timestamp records and causes
79 * every command Interest to be processed as initial.
80 */
81 ssize_t maxTimestamps = 1000;
82
83 /** \brief max lifetime of a last timestamp record
84 *
85 * A last timestamp record expires and can be deleted if it has not been refreshed
86 * within this duration.
87 * Setting this option to 0 or negative makes last timestamp records expire immediately
88 * and causes every command Interest to be processed as initial.
89 */
90 time::nanoseconds timestampTtl = time::hours(1);
Junxiao Shidc2d6d22016-08-04 14:30:23 +000091 };
92
93 /** \brief error codes
94 * \todo #1872 assign numeric codes to these errors
95 */
96 enum class ErrorCode {
97 NONE = 0,
98 NAME_TOO_SHORT,
99 BAD_TIMESTAMP,
100 BAD_SIG_INFO,
101 MISSING_KEY_LOCATOR,
102 BAD_KEY_LOCATOR_TYPE,
103 BAD_CERT_NAME,
104 TIMESTAMP_OUT_OF_GRACE,
105 TIMESTAMP_REORDER
106 };
107
108 /** \brief constructor
109 * \param inner a Validator for signed Interest signature validation and Data validation;
110 * this must not be nullptr
111 * \param options stop-and-wait command Interest validation options
112 * \throw std::invalid inner is nullptr
113 */
114 explicit
115 CommandInterestValidator(unique_ptr<Validator> inner,
116 const Options& options = Options());
117
118protected:
119 /** \brief validate command Interest
120 *
121 * This function executes the following validation procedure:
122 *
123 * 1. parse the Interest as a command Interest, and extract the public key name
124 * 2. invoke inner validation to verify the signed Interest
125 * 3. classify the command Interest as either initial or subsequent,
126 * and check the timestamp accordingly
127 * 4. record the timestamp as last timestamp of the public key name
128 *
129 * The validation request is rejected if any step in this procedure fails.
130 */
Davide Pesavento57c07df2016-12-11 18:41:45 -0500131 void
Junxiao Shidc2d6d22016-08-04 14:30:23 +0000132 checkPolicy(const Interest& interest, int nSteps,
133 const OnInterestValidated& accept,
134 const OnInterestValidationFailed& reject,
135 std::vector<shared_ptr<ValidationRequest>>& nextSteps) override;
136
137 /** \brief validate Data
138 *
139 * The validation request is redirected to the inner validator.
140 */
Davide Pesavento57c07df2016-12-11 18:41:45 -0500141 void
Junxiao Shidc2d6d22016-08-04 14:30:23 +0000142 checkPolicy(const Data& data, int nSteps,
143 const OnDataValidated& accept,
144 const OnDataValidationFailed& reject,
145 std::vector<shared_ptr<ValidationRequest>>& nextSteps) override;
146
147private:
148 void
149 cleanup();
150
151 ErrorCode
152 parseCommandInterest(const Interest& interest, Name& keyName, uint64_t& timestamp) const;
153
154 ErrorCode
155 checkTimestamp(const Name& keyName, uint64_t timestamp,
156 time::system_clock::TimePoint receiveTime);
157
158private:
159 unique_ptr<Validator> m_inner;
160 Options m_options;
161
162 struct LastTimestampRecord
163 {
164 Name keyName;
165 uint64_t timestamp;
166 time::steady_clock::TimePoint lastRefreshed;
167 };
168
169 typedef boost::multi_index_container<
170 LastTimestampRecord,
171 boost::multi_index::indexed_by<
172 boost::multi_index::ordered_unique<
173 boost::multi_index::member<LastTimestampRecord, Name, &LastTimestampRecord::keyName>
174 >,
175 boost::multi_index::sequenced<>
176 >
177 > Container;
178 typedef Container::nth_index<0>::type Index;
179 typedef Container::nth_index<1>::type Queue;
180
181 Container m_container;
182 Index& m_index;
183 Queue& m_queue;
184};
185
186std::ostream&
187operator<<(std::ostream& os, CommandInterestValidator::ErrorCode error);
188
189} // namespace security
190} // namespace ndn
191
192
193#endif // NDN_SECURITY_COMMAND_INTEREST_VALIDATOR_HPP