blob: e789f09e3a324db92a1e1b3496a9d789f6ca801f [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);
91
92 };
93
94 /** \brief error codes
95 * \todo #1872 assign numeric codes to these errors
96 */
97 enum class ErrorCode {
98 NONE = 0,
99 NAME_TOO_SHORT,
100 BAD_TIMESTAMP,
101 BAD_SIG_INFO,
102 MISSING_KEY_LOCATOR,
103 BAD_KEY_LOCATOR_TYPE,
104 BAD_CERT_NAME,
105 TIMESTAMP_OUT_OF_GRACE,
106 TIMESTAMP_REORDER
107 };
108
109 /** \brief constructor
110 * \param inner a Validator for signed Interest signature validation and Data validation;
111 * this must not be nullptr
112 * \param options stop-and-wait command Interest validation options
113 * \throw std::invalid inner is nullptr
114 */
115 explicit
116 CommandInterestValidator(unique_ptr<Validator> inner,
117 const Options& options = Options());
118
119protected:
120 /** \brief validate command Interest
121 *
122 * This function executes the following validation procedure:
123 *
124 * 1. parse the Interest as a command Interest, and extract the public key name
125 * 2. invoke inner validation to verify the signed Interest
126 * 3. classify the command Interest as either initial or subsequent,
127 * and check the timestamp accordingly
128 * 4. record the timestamp as last timestamp of the public key name
129 *
130 * The validation request is rejected if any step in this procedure fails.
131 */
132 virtual void
133 checkPolicy(const Interest& interest, int nSteps,
134 const OnInterestValidated& accept,
135 const OnInterestValidationFailed& reject,
136 std::vector<shared_ptr<ValidationRequest>>& nextSteps) override;
137
138 /** \brief validate Data
139 *
140 * The validation request is redirected to the inner validator.
141 */
142 virtual void
143 checkPolicy(const Data& data, int nSteps,
144 const OnDataValidated& accept,
145 const OnDataValidationFailed& reject,
146 std::vector<shared_ptr<ValidationRequest>>& nextSteps) override;
147
148private:
149 void
150 cleanup();
151
152 ErrorCode
153 parseCommandInterest(const Interest& interest, Name& keyName, uint64_t& timestamp) const;
154
155 ErrorCode
156 checkTimestamp(const Name& keyName, uint64_t timestamp,
157 time::system_clock::TimePoint receiveTime);
158
159private:
160 unique_ptr<Validator> m_inner;
161 Options m_options;
162
163 struct LastTimestampRecord
164 {
165 Name keyName;
166 uint64_t timestamp;
167 time::steady_clock::TimePoint lastRefreshed;
168 };
169
170 typedef boost::multi_index_container<
171 LastTimestampRecord,
172 boost::multi_index::indexed_by<
173 boost::multi_index::ordered_unique<
174 boost::multi_index::member<LastTimestampRecord, Name, &LastTimestampRecord::keyName>
175 >,
176 boost::multi_index::sequenced<>
177 >
178 > Container;
179 typedef Container::nth_index<0>::type Index;
180 typedef Container::nth_index<1>::type Queue;
181
182 Container m_container;
183 Index& m_index;
184 Queue& m_queue;
185};
186
187std::ostream&
188operator<<(std::ostream& os, CommandInterestValidator::ErrorCode error);
189
190} // namespace security
191} // namespace ndn
192
193
194#endif // NDN_SECURITY_COMMAND_INTEREST_VALIDATOR_HPP