Line data Source code
1 : // Network Address -- classes functions to ease handling IP addresses
2 : // Copyright (C) 2012-2017 Made to Order Software Corp.
3 : //
4 : // http://snapwebsites.org/project/libaddr
5 : //
6 : // This program is free software; you can redistribute it and/or modify
7 : // it under the terms of the GNU General Public License as published by
8 : // the Free Software Foundation; either version 2 of the License, or
9 : // (at your option) any later version.
10 : //
11 : // This program is distributed in the hope that it will be useful,
12 : // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : // GNU General Public License for more details.
15 : //
16 : // You should have received a copy of the GNU General Public License
17 : // along with this program; if not, write to the Free Software
18 : // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 :
20 : /** \file
21 : * \brief The implementation of the addr_range class.
22 : *
23 : * This file includes the implementation of the addr_range class
24 : * and the address_match_ranges() global function.
25 : */
26 :
27 : // self
28 : //
29 : #include "libaddr/addr_range.h"
30 : #include "libaddr/addr_exceptions.h"
31 :
32 : // C++ library
33 : //
34 : #include <algorithm>
35 : //#include <iostream>
36 :
37 :
38 :
39 : namespace addr
40 : {
41 :
42 :
43 : /** \brief Return true if the range has a 'from' address defined.
44 : *
45 : * By default the 'from' and 'to' addresses of an addr_range are legal
46 : * but considered undefined. After you called the set_from() function
47 : * once, this function will always return true.
48 : *
49 : * \return false until 'set_from()' is called at least once.
50 : */
51 289 : bool addr_range::has_from() const
52 : {
53 289 : return f_has_from;
54 : }
55 :
56 :
57 : /** \brief Return true if the range has a 'to' address defined.
58 : *
59 : * By default the 'from' and 'to' addresses of an addr_range are legal
60 : * but considered undefined. After you called the set_to() function
61 : * once, this function will always return true.
62 : *
63 : * \return false until 'set_to()' is called at least once.
64 : */
65 277 : bool addr_range::has_to() const
66 : {
67 277 : return f_has_to;
68 : }
69 :
70 :
71 : /** \brief Determine whether an addr_range object is considered a range.
72 : *
73 : * This function returns false until both, set_from() and set_to(),
74 : * were called.
75 : *
76 : * Note that the order in which the two functions get called is not
77 : * important, although we generally expect set_from() to be called
78 : * first, it does not matter.
79 : *
80 : * \return true if both, 'from' and 'to', were set.
81 : */
82 1028 : bool addr_range::is_range() const
83 : {
84 1028 : return f_has_from && f_has_to;
85 : }
86 :
87 :
88 : /** \brief Check whether this range is empty.
89 : *
90 : * If you defined the 'from' and 'to' addresses of the range, then you
91 : * can check whether the range is empty or not.
92 : *
93 : * A range is considered empty if 'from' is larger than 'to' because
94 : * in that case nothing can appear in between (no IP can at the same
95 : * time be larger than 'from' and smaller than 'to' if 'from > to'
96 : * is true.)
97 : *
98 : * \return true if 'from > to' and is_range() returns true.
99 : *
100 : * \sa is_range()
101 : * \sa has_from()
102 : * \sa has_to()
103 : */
104 307 : bool addr_range::is_empty() const
105 : {
106 307 : if(!is_range())
107 : {
108 287 : return false;
109 : }
110 20 : return f_from > f_to;
111 : }
112 :
113 :
114 : /** \brief Check whether \p rhs is part of this range.
115 : *
116 : * If the address specified in rhs is part of this range, then the function
117 : * returns true. The 'from' and 'to' addresses are considered inclusive,
118 : * so if rhs is equal to 'from' or 'to', then the function returns true.
119 : *
120 : * If 'from' is larger than 'to' then the function already returns false
121 : * since the range represents an empty range.
122 : *
123 : * \exception addr_invalid_state_exception
124 : * The addr_range object must be a range or this function throws this
125 : * exception. To test whether you can call this function, first call
126 : * the is_range() function. If it returns true, then is_in() is available.
127 : *
128 : * \param[in] rhs The address to check for inclusion.
129 : *
130 : * \return true if rhs is considered part of this range.
131 : */
132 417 : bool addr_range::is_in(addr const & rhs) const
133 : {
134 417 : if(!is_range())
135 : {
136 10 : throw addr_invalid_state_exception("addr_range::is_in(): range is not complete (from or to missing.)");
137 : }
138 :
139 407 : if(f_from <= f_to)
140 : {
141 : //
142 285 : return rhs >= f_from && rhs <= f_to;
143 : }
144 : //else -- from/to are swapped... this represents an empty range
145 :
146 122 : return false;
147 : }
148 :
149 :
150 : /** \brief Set 'from' address.
151 : *
152 : * This function saves the 'from' address in this range object.
153 : *
154 : * Once this function was called at least once, the has_from() returns true.
155 : *
156 : * \param[in] from The address to save as the 'from' address.
157 : */
158 131840 : void addr_range::set_from(addr const & from)
159 : {
160 131840 : f_has_from = true;
161 131840 : f_from = from;
162 131840 : }
163 :
164 :
165 : /** \brief Get 'from' address.
166 : *
167 : * This function return the 'from' address as set by the set_from()
168 : * functions.
169 : *
170 : * The get_from() function can be called even if the has_from()
171 : * function returns false. It will return a default address
172 : * (a new 'addr' object.)
173 : *
174 : * \return The address saved as the 'from' address.
175 : */
176 551 : addr & addr_range::get_from()
177 : {
178 551 : return f_from;
179 : }
180 :
181 :
182 : /** \brief Get the 'from' address when addr_range is constant.
183 : *
184 : * This function return the 'from' address as set by the set_from()
185 : * functions.
186 : *
187 : * The get_from() function can be called even if the has_from()
188 : * function returns false. It will return a default address
189 : * (a new 'addr' object.)
190 : *
191 : * \return The address saved as the 'from' address.
192 : */
193 131770 : addr const & addr_range::get_from() const
194 : {
195 131770 : return f_from;
196 : }
197 :
198 :
199 : /** \brief Set 'to' address.
200 : *
201 : * This function saves the 'to' address in this range object.
202 : *
203 : * Once this function was called at least once, the has_to() returns true.
204 : *
205 : * \param[in] to The address to save as the 'to' address.
206 : */
207 8 : void addr_range::set_to(addr const & to)
208 : {
209 8 : f_has_to = true;
210 8 : f_to = to;
211 8 : }
212 :
213 :
214 : /** \brief Get the 'to' address.
215 : *
216 : * This function return the 'to' address as set by the set_to()
217 : * function.
218 : *
219 : * The get_from() function can be called even if the has_from()
220 : * function returns false. It will return a default address
221 : * (a new 'addr' object.)
222 : *
223 : * \return The address saved as the 'to' address.
224 : */
225 9 : addr & addr_range::get_to()
226 : {
227 9 : return f_to;
228 : }
229 :
230 :
231 : /** \brief Get the 'to' address when addr_range is constant.
232 : *
233 : * This function return the 'to' address as set by the set_to()
234 : * function.
235 : *
236 : * The get_to() function can be called even if the has_to()
237 : * function returns false. It will return a default address
238 : * (a new 'addr' object.)
239 : *
240 : * \return The address saved as the 'to' address.
241 : */
242 7 : addr const & addr_range::get_to() const
243 : {
244 7 : return f_to;
245 : }
246 :
247 :
248 : /** \brief Compute a new range with the part that is shared between both inputs.
249 : *
250 : * This function computers a range which encompasses all the addresses found
251 : * in \p this range and \p rhs range.
252 : *
253 : * If the two range do not intersect, then the resulting range will be an
254 : * empty range (see is_empty() for details).
255 : *
256 : * The new range receives the largest 'from' address from both inputs and
257 : * the smallest 'to' address from both inputs.
258 : *
259 : * \param[in] rhs The other range to compute the intersection with.
260 : *
261 : * \return The resulting intersection range.
262 : */
263 2 : addr_range addr_range::intersection(addr_range const & rhs) const
264 : {
265 2 : addr_range result;
266 :
267 2 : result.set_from(f_from > rhs.f_from ? f_from : rhs.f_from);
268 2 : result.set_to (f_to < rhs.f_to ? f_to : rhs.f_to);
269 :
270 2 : return result;
271 : }
272 :
273 :
274 : /** \brief Check whether an address matches a range.
275 : *
276 : * This function checks whether an address matches a range of addresses.
277 : *
278 : * The range may be empty, in which case the result is always false.
279 : *
280 : * If the range is a range (i.e. 'from' and 'to' are both defined,)
281 : * then the is_in() function is used to determine whether the address
282 : * is a match.
283 : *
284 : * If only one of the 'from' or 'to' addresses is defined, then that
285 : * one address addr::match() function is used to determine whether the
286 : * input \p address is a match.
287 : *
288 : * \param[in] address The address to match against a range of addresses.
289 : *
290 : * \return true if address matches this range.
291 : */
292 24 : bool addr_range::match(addr const & address) const
293 : {
294 : // if neith 'from' nor 'to' were defined, return
295 : //
296 24 : if(is_empty())
297 : {
298 3 : return false;
299 : }
300 :
301 21 : if(is_range())
302 : {
303 9 : return is_in(address);
304 : }
305 :
306 12 : if(has_from())
307 : {
308 6 : return f_from.match(address);
309 : }
310 : else
311 : {
312 : // if not empty and it does not have 'from', it has to be 'to'
313 : //
314 6 : return f_to.match(address);
315 : }
316 : }
317 :
318 :
319 : /** \brief Check whether an address matches a range.
320 : *
321 : * When you call the addr_parser::parse() function, you get a vector of
322 : * ranges as a result. This function allows you to check whether an
323 : * address matches any one of those ranges.
324 : *
325 : * \param[in] ranges The vector of ranges to search for \p address.
326 : * \param[in] address The address to search in \p ranges.
327 : *
328 : * \return true if \p address matches any one of the \p ranges.
329 : */
330 4 : bool address_match_ranges(addr_range::vector_t ranges, addr const & address)
331 : {
332 : auto const it(std::find_if
333 : ( ranges.begin()
334 : , ranges.end()
335 6 : , [&address](auto const & range)
336 6 : {
337 : return range.match(address);
338 6 : }
339 4 : ));
340 :
341 4 : return it != ranges.end();
342 : }
343 :
344 :
345 :
346 :
347 : }
348 : // addr namespace
349 : // vim: ts=4 sw=4 et
|