Branch data Line data Source code
1 : : // Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
2 : : //
3 : : // Permission to use, copy, modify, and/or distribute this software for any
4 : : // purpose with or without fee is hereby granted, provided that the above
5 : : // copyright notice and this permission notice appear in all copies.
6 : : //
7 : : // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
8 : : // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
9 : : // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
10 : : // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
11 : : // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
12 : : // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
13 : : // PERFORMANCE OF THIS SOFTWARE.
14 : :
15 : : #ifndef ACL_CHECK_H
16 : : #define ACL_CHECK_H
17 : :
18 : : #include <vector>
19 : : #include <typeinfo>
20 : : #include <sstream>
21 : :
22 : : namespace isc {
23 : : namespace acl {
24 : :
25 : : /**
26 : : * \brief ACL check base class.
27 : : *
28 : : * It is intended that all ACL checks are inherited (maybe indirectly) from
29 : : * this base class. This will allow us to define new types of checks without
30 : : * changing any of the code that is using it and with the correct
31 : : * implementation even without changing the thing that parses configuration
32 : : * and creates instances of the checks.
33 : : *
34 : : * It is implemented as a template. This allows easy reuse of the code for
35 : : * checking of different types of things (packets of different protocols, etc).
36 : : * We'll implement the loader and compound checks as templates as well (
37 : : * and just make sure they are instantiated for each type of thing we want
38 : : * to check). While most of concrete checks will be specific for one protocol
39 : : * (or whatever the entity we check is), it makes sense to implement some of
40 : : * these as templates as well (for example the IP address check, for whatever
41 : : * context that contains member called ip and has the right methods).
42 : : *
43 : : * The Context carries whatever information might be checked for that protocol
44 : : * (eg. the packet, information where it came from, to what port, ...).
45 : : */
46 : 0 : template<typename Context> class Check {
47 : : protected:
48 : : /// \brief Constructor.
49 : : ///
50 : : /// Just to make sure this thing is not directly instantiated.
51 : 332 : Check() { }
52 : : public:
53 : : /**
54 : : * \brief The check itself.
55 : : *
56 : : * The actual check will be performed here. Every concrete child class
57 : : * will reimplement it and decide based on the context passed if it
58 : : * matches.
59 : : *
60 : : * The caller should expect this method can throw. The list of exceptions
61 : : * isn't restricted, as we don't know what kind of checks will be needed.
62 : : * An exception should be considered as it is impossible to check the
63 : : * condition. It should lead to either blackholing the packet or returning
64 : : * some 500-like error (ServFail).
65 : : *
66 : : * \param context The thing we are trying to match against this check.
67 : : * \return true if the context satisfies the check, false otherwise.
68 : : */
69 : : virtual bool matches(const Context& context) const = 0;
70 : :
71 : : /**
72 : : * \brief Cost for unknown cost estimate.
73 : : *
74 : : * This indicates that the estimate for cost is not provided. This
75 : : * is arbitrary large value, meaning "somehow longish time". To be
76 : : * on the safe side, we guess more and be just happily suprirised
77 : : * if it turns out to run faster.
78 : : */
79 : : static const unsigned UNKNOWN_COST;
80 : :
81 : : /**
82 : : * \brief The expected cost of single match.
83 : : *
84 : : * This is here to provide some kind of cost information to optimising
85 : : * routines. It is in units without any real size, just bigger number
86 : : * means the check takes longer time. It is expected to be linear scale.
87 : : * It doesn't need to be exact, but better accuracy might lead to better
88 : : * optimisations. As of writing this, no optimisations exist yet, but
89 : : * are expected to exist in future.
90 : : *
91 : : * The default is UNKNOWN_COST.
92 : : */
93 : 2 : virtual unsigned cost() const {
94 : 2 : return (UNKNOWN_COST);
95 : : }
96 : :
97 : : /// \brief Virtual destructor, as we're virtual
98 : 302 : virtual ~ Check() { }
99 : :
100 : : /**
101 : : * \brief Conversion to text.
102 : : *
103 : : * This is meant for debugging purposes, it doesn't have to
104 : : * serialise the whole information stored in this Check.
105 : : *
106 : : * If the check is compound, it should not include the subexpressions
107 : : * (while we're able to build whatever treeish representation using
108 : : * CompoundCheck::subexpressions, we're not able to separate them
109 : : * automatically, as this may produce any kind of free-form string).
110 : : */
111 : 1 : virtual std::string toText() const {
112 : 2 : std::stringstream output;
113 [ + - ][ + - ]: 1 : output << typeid(*this).name() << "@" << this;
114 [ + - ]: 2 : return (output.rdbuf()->str());
115 : : }
116 : : };
117 : :
118 : : // This seems to be the propper way for static template members
119 : : template<typename Context> const unsigned Check<Context>::UNKNOWN_COST = 10000;
120 : :
121 : : /**
122 : : * \brief Base class for compound checks.
123 : : *
124 : : * While some checks will be a match against some property of the information
125 : : * passed (eg. the sender's IP address must be in some range), others will
126 : : * combine results of more checks together to get their own. This is base class
127 : : * for the second type, allowing listing of the subexpressions (mostly for
128 : : * debugging purposes to print the whole tree of matches and possible future
129 : : * optimisations which would like to crawl the expression tree).
130 : : */
131 : 0 : template<typename Context> class CompoundCheck : public Check<Context> {
132 : : public:
133 : : /// \brief Abbreviated name for list of subexpressions
134 : : typedef std::vector<const Check<Context>*> Checks;
135 : :
136 : : /**
137 : : * \brief Get the list of subexpressions.
138 : : *
139 : : * The result contains pointers to the all subexpressions this check holds
140 : : * (and therefore might call during its own match() function).
141 : : *
142 : : * Using shared pointers looks an overkill here. All the checks must be
143 : : * alive for the whole life of this one and this check will hold their
144 : : * ownership. Therefore the only thing the caller needs to do is to make
145 : : * sure this check is not deleted while it's still using the ones from the
146 : : * result.
147 : : *
148 : : * This method must not throw except for the standard allocation exceptions
149 : : * to allocate the result.
150 : : */
151 : : virtual Checks getSubexpressions() const = 0;
152 : :
153 : : /**
154 : : * \brief If the result depends only on results of subexpressions.
155 : : *
156 : : * Some optimisations might use the fact that a compound expression is
157 : : * a function of results of its subexpressions (subchecks) only. But
158 : : * some compound checks might want to look into the provided context in
159 : : * their match() as well as looking at the results of the subexpressions.
160 : : *
161 : : * This function informs the optimisation routines if it is safe to use
162 : : * these optimisations.
163 : : *
164 : : * \return true if the check depends only on results of subexpressions
165 : : * only, false if it examines the context itself as well.
166 : : * \note The default implementation returns true, as it is expected to
167 : : * be the case in majority of cases.
168 : : */
169 : 0 : virtual bool pure() const { return (true); }
170 : :
171 : : /**
172 : : * \brief Default compound cost function.
173 : : *
174 : : * It is simply sum of all subexpressions, as an expected upper bound
175 : : * on the cost. This expects that the combining itself is cheap relatively
176 : : * to the checks performed by the subexpressions. In most cases, this
177 : : * should be good enough, but it can be reimplemented in situations
178 : : * where most of the subexpressions will be avoided in usual situations.
179 : : * Replacing the default of 10000 from Check.
180 : : */
181 : 1 : virtual unsigned cost() const {
182 : 2 : Checks checks(getSubexpressions());
183 : 1 : unsigned result(0);
184 [ + + ]: 3 : for (typename Checks::const_iterator i(checks.begin());
185 : : i != checks.end(); ++ i) {
186 [ + - ]: 2 : result += (*i)->cost();
187 : : }
188 : 1 : return (result);
189 : : }
190 : : };
191 : :
192 : : }
193 : : }
194 : :
195 : : #endif
|