mavtables  0.2.1
MAVLink router and firewall.
Chain.cpp
Go to the documentation of this file.
1 // MAVLink router and firewall.
2 // Copyright (C) 2018 Michael R. Shannon <mrshannon.aerospace@gmail.com>
3 //
4 // This program is free software; you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation; either version 2 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
16 
17 
18 #include <cstddef>
19 #include <memory>
20 #include <ostream>
21 #include <set>
22 #include <stdexcept>
23 #include <string>
24 #include <vector>
25 
26 #include "Action.hpp"
27 #include "Chain.hpp"
28 #include "MAVAddress.hpp"
29 #include "MAVSubnet.hpp"
30 #include "Packet.hpp"
31 #include "RecursionGuard.hpp"
32 
33 
34 /** Copy constructor.
35  *
36  * \param other Chain to copy from.
37  */
38 Chain::Chain(const Chain &other)
39  : name_(other.name_)
40 {
41  for (auto &rule : other.rules_)
42  {
43  rules_.push_back(rule->clone());
44  }
45 }
46 
47 
48 /** Construct a new filter chain.
49  *
50  * \note No rule in the chain may contain a \ref GoTo or \ref Call that would
51  * directly or indirectly result in returning to this chain.
52  *
53  * \param name The name of the filter chain. This is only used when printing
54  * the chain. The name cannot contain whitespace.
55  * \param rules A vector of the rules used in the filter chain. This must be
56  * moved from since the vector is made up of std::unique_ptr's.
57  * \throws std::invalid_argument if the \p name contains whitespace.
58  */
60  std::string name, std::vector<std::unique_ptr<Rule>> &&rules)
61  : name_(std::move(name)), rules_(std::move(rules))
62 {
63  if (name_.find_first_of("\t\n ") != std::string::npos)
64  {
65  throw std::invalid_argument("Chain names cannot contain whitespace.");
66  }
67 }
68 
69 
70 /** Decide what to do with a \ref Packet.
71  *
72  * Determine what action to take with the given \p packet sent to the
73  * given \p address. The possible actions are documented in the \ref
74  * Action class.
75  *
76  * The filter chain will loop through all the rules and the first one that
77  * matches and returns something other than the continue \ref Action will be
78  * taken as the result.
79  *
80  * \note An error will be thrown if any \ref Call or \ref GoTo rule matches
81  * that directly or indirectly loops back to this chain.
82  *
83  * \param packet The packet to determine whether to allow or not.
84  * \param address The address the \p packet will be sent out on if the
85  * action allows it.
86  * \returns The action to take with the packet. %If this is the accept \ref
87  * Action object, it may also contain a priority for the packet.
88  * \throws RecursionError if a rule loops back to this chain.
89  */
91  const Packet &packet, const MAVAddress &address)
92 {
93  // Prevent recursion.
94  RecursionGuard recursion_guard(recursion_data_);
95 
96  // Loop throught the rules.
97  for (auto const &rule : rules_)
98  {
99  auto result = rule->action(packet, address);
100 
101  // Return rule result if not CONTINUE.
102  if (result.action() != Action::CONTINUE)
103  {
104  return result;
105  }
106  }
107 
108  return Action::make_continue();
109 }
110 
111 
112 /** Append a new rule to the filter chain.
113  *
114  * \param rule A new filter rule to append to the chain.
115  */
116 void Chain::append(std::unique_ptr<Rule> rule)
117 {
118  rules_.push_back(std::move(rule));
119 }
120 
121 
122 /** Return the name of the chain.
123  *
124  * \note This is only used when printing the chain.
125  *
126  * \returns The chain's name.
127  */
128 const std::string &Chain::name() const
129 {
130  return name_;
131 }
132 
133 
134 /** Assignment operator.
135  *
136  * \param other Chain to copy from.
137  */
139 {
140  name_ = other.name_;
141  rules_.clear();
142 
143  for (auto &rule : other.rules_)
144  {
145  rules_.push_back(rule->clone());
146  }
147 
148  recursion_data_ = other.recursion_data_;
149  return *this;
150 }
151 
152 
153 /** Equality comparison.
154  *
155  * Compares the chain name and each \ref Rule in the chain.
156  *
157  * \relates Chain
158  * \param lhs The left hand side filter chain.
159  * \param rhs The right hand side filter chain.
160  * \retval true if \p lhs is the same as rhs.
161  * \retval false if \p lhs is not the same as rhs.
162  */
163 bool operator==(const Chain &lhs, const Chain &rhs)
164 {
165  // Compare names.
166  if (lhs.name() != rhs.name())
167  {
168  return false;
169  }
170 
171  // Compare number of rules.
172  if (lhs.rules_.size() != rhs.rules_.size())
173  {
174  return false;
175  }
176 
177  // Compare rules one by one.
178  for (size_t i = 0; i < lhs.rules_.size(); ++i)
179  {
180  if (*(lhs.rules_[i]) != *(rhs.rules_[i]))
181  {
182  return false;
183  }
184  }
185 
186  return true;
187 }
188 
189 
190 /** Inequality comparison.
191  *
192  * Compares the chain name and each \ref Rule in the chain.
193  *
194  * \relates Chain
195  * \param lhs The left hand side action.
196  * \param rhs The right hand side action.
197  * \retval true if \p lhs is not the same as rhs.
198  * \retval false if \p lhs is the same as rhs.
199  */
200 bool operator!=(const Chain &lhs, const Chain &rhs)
201 {
202  return !(lhs == rhs);
203 }
204 
205 
206 /** Print the given filter chain to to the given output stream.
207  *
208  * An example is:
209  * ```
210  * chain default {
211  * reject if HEARTBEAT from 10.10;
212  * accept with priority -3 if GPS_STATUS to 172.0/8;
213  * accept if GLOBAL_POSITION_INT to 172.0/8;
214  * goto ap-in with priority 3 if from 192.168;
215  * call ap-out if to 192.168;
216  * reject;
217  * }
218  * ```
219  *
220  * \relates Chain
221  * \param os The output stream to print to.
222  * \param chain The filter chain to print.
223  * \returns The output stream.
224  */
225 std::ostream &operator<<(std::ostream &os, const Chain &chain)
226 {
227  os << "chain " << chain.name() << " {" << std::endl;
228 
229  for (auto const &rule : chain.rules_)
230  {
231  os << " " << *rule << ";" << std::endl;
232  }
233 
234  os << "}";
235  return os;
236 }
const std::string & name() const
Definition: Chain.cpp:128
Continue evaluating rules.
Definition: Action.hpp:39
STL namespace.
virtual std::unique_ptr< Rule > clone() const =0
Chain & operator=(const Chain &other)
Definition: Chain.cpp:138
static Action make_continue()
Definition: Action.cpp:126
std::ostream & operator<<(std::ostream &os, const Action &action)
Definition: Action.cpp:188
TEST_VIRTUAL Action action(const Packet &packet, const MAVAddress &address)
Definition: Chain.cpp:90
bool operator==(const Action &lhs, const Action &rhs)
Definition: Action.cpp:154
bool operator!=(const Action &lhs, const Action &rhs)
Definition: Action.cpp:168
Definition: Chain.hpp:37
void append(std::unique_ptr< Rule > rule)
Definition: Chain.cpp:116
Chain(const Chain &other)
Definition: Chain.cpp:38
Rule & rule
Definition: test_Call.cpp:231
virtual Action action(const Packet &packet, const MAVAddress &address) const =0