Line data Source code
1 : // Copyright (c) 2012-2021 Made to Order Software Corp. All Rights Reserved
2 : //
3 : // https://snapwebsites.org/project/libaddr
4 : //
5 : // Permission is hereby granted, free of charge, to any person obtaining a
6 : // copy of this software and associated documentation files (the
7 : // "Software"), to deal in the Software without restriction, including
8 : // without limitation the rights to use, copy, modify, merge, publish,
9 : // distribute, sublicense, and/or sell copies of the Software, and to
10 : // permit persons to whom the Software is furnished to do so, subject to
11 : // the following conditions:
12 : //
13 : // The above copyright notice and this permission notice shall be included
14 : // in all copies or substantial portions of the Software.
15 : //
16 : // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 : // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 : // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 : // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20 : // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21 : // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22 : // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 :
24 :
25 : /** \file
26 : * \brief The implementation of the addr_range class.
27 : *
28 : * This file includes the implementation of the addr_range class
29 : * and the address_match_ranges() global function.
30 : */
31 :
32 : // self
33 : //
34 : #include "libaddr/addr_range.h"
35 : #include "libaddr/addr_exception.h"
36 :
37 :
38 : // C++ library
39 : //
40 : #include <algorithm>
41 :
42 :
43 : // last include
44 : //
45 : #include <snapdev/poison.h>
46 :
47 :
48 :
49 : namespace addr
50 : {
51 :
52 :
53 : /** \brief Return true if the range has a 'from' address defined.
54 : *
55 : * By default the 'from' and 'to' addresses of an addr_range are legal
56 : * but considered undefined. After you called the set_from() function
57 : * once, this function will always return true.
58 : *
59 : * \return false until 'set_from()' is called at least once.
60 : */
61 323 : bool addr_range::has_from() const
62 : {
63 323 : return f_has_from;
64 : }
65 :
66 :
67 : /** \brief Return true if the range has a 'to' address defined.
68 : *
69 : * By default the 'from' and 'to' addresses of an addr_range are legal
70 : * but considered undefined. After you called the set_to() function
71 : * once, this function will always return true.
72 : *
73 : * \return false until 'set_to()' is called at least once.
74 : */
75 290 : bool addr_range::has_to() const
76 : {
77 290 : return f_has_to;
78 : }
79 :
80 :
81 : /** \brief Determine whether an addr_range object is considered a range.
82 : *
83 : * This function returns false until both, set_from() and set_to(),
84 : * were called.
85 : *
86 : * Note that the order in which the two functions get called is not
87 : * important, although we generally expect set_from() to be called
88 : * first, it does not matter.
89 : *
90 : * \return true if both, 'from' and 'to', were set.
91 : */
92 1041 : bool addr_range::is_range() const
93 : {
94 1041 : return f_has_from && f_has_to;
95 : }
96 :
97 :
98 : /** \brief Check whether this range is empty.
99 : *
100 : * If you defined the 'from' and 'to' addresses of the range, then you
101 : * can check whether the range is empty or not.
102 : *
103 : * A range is considered empty if 'from' is larger than 'to' because
104 : * in that case nothing can appear in between (no IP can at the same
105 : * time be larger than 'from' and smaller than 'to' if 'from > to'
106 : * is true.)
107 : *
108 : * \return true if 'from > to' and is_range() returns true.
109 : *
110 : * \sa is_range()
111 : * \sa has_from()
112 : * \sa has_to()
113 : */
114 307 : bool addr_range::is_empty() const
115 : {
116 307 : if(!is_range())
117 : {
118 287 : return false;
119 : }
120 20 : return f_from > f_to;
121 : }
122 :
123 :
124 : /** \brief Check whether \p rhs is part of this range.
125 : *
126 : * If the address specified in rhs is part of this range, then the function
127 : * returns true. The 'from' and 'to' addresses are considered inclusive,
128 : * so if rhs is equal to 'from' or 'to', then the function returns true.
129 : *
130 : * If 'from' is larger than 'to' then the function already returns false
131 : * since the range represents an empty range.
132 : *
133 : * \exception addr_invalid_state_exception
134 : * The addr_range object must be a range or this function throws this
135 : * exception. To test whether you can call this function, first call
136 : * the is_range() function. If it returns true, then is_in() is available.
137 : *
138 : * \param[in] rhs The address to check for inclusion.
139 : *
140 : * \return true if rhs is considered part of this range.
141 : */
142 417 : bool addr_range::is_in(addr const & rhs) const
143 : {
144 417 : if(!is_range())
145 : {
146 10 : throw addr_invalid_state("addr_range::is_in(): range is not complete (from or to missing.)");
147 : }
148 :
149 407 : if(f_from <= f_to)
150 : {
151 : //
152 285 : return rhs >= f_from && rhs <= f_to;
153 : }
154 : //else -- from/to are swapped... this represents an empty range
155 :
156 122 : return false;
157 : }
158 :
159 :
160 : /** \brief Set 'from' address.
161 : *
162 : * This function saves the 'from' address in this range object.
163 : *
164 : * Once this function was called at least once, the has_from() returns true.
165 : *
166 : * \param[in] from The address to save as the 'from' address.
167 : */
168 131867 : void addr_range::set_from(addr const & from)
169 : {
170 131867 : f_has_from = true;
171 131867 : f_from = from;
172 131867 : }
173 :
174 :
175 : /** \brief Get 'from' address.
176 : *
177 : * This function return the 'from' address as set by the set_from()
178 : * functions.
179 : *
180 : * The get_from() function can be called even if the has_from()
181 : * function returns false. It will return a default address
182 : * (a new 'addr' object.)
183 : *
184 : * \return The address saved as the 'from' address.
185 : */
186 568 : addr & addr_range::get_from()
187 : {
188 568 : return f_from;
189 : }
190 :
191 :
192 : /** \brief Get the 'from' address when addr_range is constant.
193 : *
194 : * This function return the 'from' address as set by the set_from()
195 : * functions.
196 : *
197 : * The get_from() function can be called even if the has_from()
198 : * function returns false. It will return a default address
199 : * (a new 'addr' object.)
200 : *
201 : * \return The address saved as the 'from' address.
202 : */
203 131791 : addr const & addr_range::get_from() const
204 : {
205 131791 : return f_from;
206 : }
207 :
208 :
209 : /** \brief Set 'to' address.
210 : *
211 : * This function saves the 'to' address in this range object.
212 : *
213 : * Once this function was called at least once, the has_to() returns true.
214 : *
215 : * \param[in] to The address to save as the 'to' address.
216 : */
217 8 : void addr_range::set_to(addr const & to)
218 : {
219 8 : f_has_to = true;
220 8 : f_to = to;
221 8 : }
222 :
223 :
224 : /** \brief Get the 'to' address.
225 : *
226 : * This function return the 'to' address as set by the set_to()
227 : * function.
228 : *
229 : * The get_from() function can be called even if the has_from()
230 : * function returns false. It will return a default address
231 : * (a new 'addr' object.)
232 : *
233 : * \return The address saved as the 'to' address.
234 : */
235 9 : addr & addr_range::get_to()
236 : {
237 9 : return f_to;
238 : }
239 :
240 :
241 : /** \brief Get the 'to' address when addr_range is constant.
242 : *
243 : * This function return the 'to' address as set by the set_to()
244 : * function.
245 : *
246 : * The get_to() function can be called even if the has_to()
247 : * function returns false. It will return a default address
248 : * (a new 'addr' object.)
249 : *
250 : * \return The address saved as the 'to' address.
251 : */
252 7 : addr const & addr_range::get_to() const
253 : {
254 7 : return f_to;
255 : }
256 :
257 :
258 : /** \brief Compute a new range with the part that is shared between both inputs.
259 : *
260 : * This function computers a range which encompasses all the addresses found
261 : * in \p this range and \p rhs range.
262 : *
263 : * If the two range do not intersect, then the resulting range will be an
264 : * empty range (see is_empty() for details).
265 : *
266 : * The new range receives the largest 'from' address from both inputs and
267 : * the smallest 'to' address from both inputs.
268 : *
269 : * \param[in] rhs The other range to compute the intersection with.
270 : *
271 : * \return The resulting intersection range.
272 : */
273 2 : addr_range addr_range::intersection(addr_range const & rhs) const
274 : {
275 2 : addr_range result;
276 :
277 2 : result.set_from(f_from > rhs.f_from ? f_from : rhs.f_from);
278 2 : result.set_to (f_to < rhs.f_to ? f_to : rhs.f_to);
279 :
280 2 : return result;
281 : }
282 :
283 :
284 : /** \brief Check whether an address matches a range.
285 : *
286 : * This function checks whether an address matches a range of addresses.
287 : *
288 : * The range may be empty, in which case the result is always false.
289 : *
290 : * If the range is a range (i.e. 'from' and 'to' are both defined,)
291 : * then the is_in() function is used to determine whether the address
292 : * is a match.
293 : *
294 : * If only one of the 'from' or 'to' addresses is defined, then that
295 : * one address addr::match() function is used to determine whether the
296 : * input \p address is a match.
297 : *
298 : * \param[in] address The address to match against a range of addresses.
299 : *
300 : * \return true if address matches this range.
301 : */
302 24 : bool addr_range::match(addr const & address) const
303 : {
304 : // if neith 'from' nor 'to' were defined, return
305 : //
306 24 : if(is_empty())
307 : {
308 3 : return false;
309 : }
310 :
311 21 : if(is_range())
312 : {
313 9 : return is_in(address);
314 : }
315 :
316 12 : if(has_from())
317 : {
318 6 : return f_from.match(address);
319 : }
320 : else
321 : {
322 : // if not empty and it does not have 'from', it has to be 'to'
323 : //
324 6 : return f_to.match(address);
325 : }
326 : }
327 :
328 :
329 : /** \brief Check whether an address matches a range.
330 : *
331 : * When you call the addr_parser::parse() function, you get a vector of
332 : * ranges as a result. This function allows you to check whether an
333 : * address matches any one of those ranges.
334 : *
335 : * \param[in] ranges The vector of ranges to search for \p address.
336 : * \param[in] address The address to search in \p ranges.
337 : *
338 : * \return true if \p address matches any one of the \p ranges.
339 : */
340 4 : bool address_match_ranges(addr_range::vector_t ranges, addr const & address)
341 : {
342 : auto const it(std::find_if
343 : ( ranges.begin()
344 : , ranges.end()
345 6 : , [&address](auto const & range)
346 6 : {
347 : return range.match(address);
348 6 : }
349 4 : ));
350 :
351 4 : return it != ranges.end();
352 : }
353 :
354 :
355 :
356 :
357 : }
358 : // namespace addr
359 : // vim: ts=4 sw=4 et
|