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