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 __IP_CHECK_H
16 : : #define __IP_CHECK_H
17 : :
18 : : #include <sys/socket.h>
19 : :
20 : : #include <algorithm>
21 : : #include <cassert>
22 : : #include <functional>
23 : : #include <vector>
24 : :
25 : : #include <boost/static_assert.hpp>
26 : :
27 : : #include <stdint.h>
28 : : #include <arpa/inet.h>
29 : : #include <sys/socket.h> // for AF_INET/AF_INET6
30 : : #include <netinet/in.h>
31 : :
32 : : #include <acl/check.h>
33 : : #include <exceptions/exceptions.h>
34 : : #include <util/strutil.h>
35 : :
36 : : namespace isc {
37 : : namespace acl {
38 : :
39 : : // Free functions. These are not supposed to be used outside this module,
40 : : // but are declared public for testing. To try to conceal them, they are
41 : : // put in an "internal" namespace.
42 : :
43 : : namespace internal {
44 : :
45 : : /// \brief Convert prefix length to mask
46 : : ///
47 : : /// Given a prefix length and a data type, return a value of that data type
48 : : /// with the most significant "prefix length" bits set. For example, if the
49 : : /// data type is an uint8_t and the prefix length is 3, the function would
50 : : /// return a uint8_t holding the binary value 11100000. This value is used as
51 : : /// a mask in the address checks.
52 : : ///
53 : : /// \param prefixlen number of bits to be set in the mask. This must be
54 : : /// between 0 and 8.
55 : : ///
56 : : /// \return uint8_t with the most significant "prefixlen" bits set.
57 : : ///
58 : : /// \exception OutOfRange prefixlen is too large for the data type.
59 : :
60 : : uint8_t createMask(size_t prefixlen);
61 : :
62 : : /// \brief Split IP Address Prefix
63 : : ///
64 : : /// Splits an IP address prefix (given in the form of "xxxxxx/n" or "xxxxx" into
65 : : /// a string representing the IP address and a number giving the length of the
66 : : /// prefix. (In the latter case, the prefix is equal in length to the width in
67 : : /// width in bits of the data type holding the address.) An exception will be
68 : : /// thrown if the string format is invalid or if the prefix length is invalid.
69 : : ///
70 : : /// N.B. This function does NOT check that the address component is a valid IP
71 : : /// address; this is done elsewhere in the address parsing process.
72 : : ///
73 : : /// \param ipprefix Address or address prefix. The string should be passed
74 : : /// without leading or trailing spaces.
75 : : ///
76 : : /// \return Pair of (string, int) holding the address string and the prefix
77 : : /// length. The second element is -1 if no prefix was given.
78 : : ///
79 : : /// \exception InvalidParameter Address prefix not of the expected syntax
80 : :
81 : : std::pair<std::string, int>
82 : : splitIPAddress(const std::string& ipprefix);
83 : :
84 : : } // namespace internal
85 : :
86 : : /// \brief A simple representation of IP address.
87 : : ///
88 : : /// This structure provides address family independent interfaces of an
89 : : /// IP(v4 or v6) address, so that the application can perform
90 : : /// \c IPCheck::matches without knowing which version of address it is
91 : : /// handling. (For example, consider the standard socket API: it uses
92 : : /// the generic \c sockaddr structure to represent endpoints).
93 : : ///
94 : : /// An object of this class could be constructed from various types of
95 : : /// sources, but in the initial implementation there's only one constructor,
96 : : /// which takes a \c sockaddr structure. For efficiency the \c IPAddress
97 : : /// object only retains a reference to the necessary part of \c sockaddr.
98 : : /// Therefore the corresponding \c sockaddr instance must be valid while the
99 : : /// \c IPAddress object is used.
100 : : ///
101 : : /// This class is copyable so that a fixed object can be easily reused for
102 : : /// different addresses. To ensure internal integrity, specific member
103 : : /// variables are kept private and only accessible via read-only accessor
104 : : /// methods. Due to this, it is ensured, for example, that if \c getFamily()
105 : : /// returns \c AF_INET6, \c getLength() always returns 16.
106 : : ///
107 : : /// All accessor methods are straightforward and exception free.
108 : : ///
109 : : /// In future, we may introduce the default constructor to further improve
110 : : /// reusability.
111 : : struct IPAddress {
112 : : /// The constructor from socket address structure.
113 : : ///
114 : : /// This constructor set up the internal data based on the actual type
115 : : /// \c sa. For example, if \c sa.sa_family is \c AF_INET, it assumes
116 : : /// \c sa actually refers to a \c sockaddr_in structure.
117 : : /// The behavior when this assumption isn't held is undefined.
118 : : ///
119 : : /// \param sa A reference to the socket address structure from which the
120 : : /// \c IPAddress is to be constructed.
121 : : explicit IPAddress(const struct sockaddr& sa);
122 : :
123 : : /// Return the address family of the address
124 : : ///
125 : : /// It's AF_INET for IPv4 and AF_INET6 for IPv6.
126 : 0 : int getFamily() const { return (family); }
127 : :
128 : : /// Return the binary representation of the address in network byte order.
129 : : ///
130 : : /// Only the \c getLength() bytes from the returned pointer are ensured
131 : : /// to be valid. In addition, if the \c sockaddr structure given on
132 : : /// construction was dynamically allocated, the data is valid only until
133 : : /// the \c sockaddr is invalidated.
134 : 0 : const uint8_t* getData() const { return (data); }
135 : :
136 : : /// Return the length of the address.
137 : 0 : size_t getLength() const { return (length); }
138 : : private:
139 : : int family;
140 : : const uint8_t* data;
141 : : size_t length;
142 : : };
143 : :
144 : : /// \brief IP Check
145 : : ///
146 : : /// This class performs a match between an IP address prefix specified in an ACL
147 : : /// and a given IP address. The check works for both IPv4 and IPv6 addresses.
148 : : ///
149 : : /// The class is templated on the type of a context structure passed to the
150 : : /// matches() method, and a template specialisation for that method must be
151 : : /// supplied for the class to be used.
152 : :
153 : : template <typename Context>
154 : 6 : class IPCheck : public Check<Context> {
155 : : private:
156 : : // Size of uint8_t array needed to hold different address types
157 : : static const size_t IPV6_SIZE = sizeof(struct in6_addr);
158 : : static const size_t IPV4_SIZE = sizeof(struct in_addr);
159 : :
160 : : // Confirm our assumption of relative sizes - this allows us to assume that
161 : : // an array sized for an IPv6 address can hold an IPv4 address.
162 : : BOOST_STATIC_ASSERT(sizeof(struct in6_addr) > sizeof(struct in_addr));
163 : :
164 : : public:
165 : : /// \brief String Constructor
166 : : ///
167 : : /// Constructs an IP Check object from an address or address prefix in the
168 : : /// form <ip-address>/n".
169 : : ///
170 : : /// Also allowed are the special keywords "any4" and "any6", which match
171 : : /// any IPv4 or IPv6 address. These must be specified in lowercase.
172 : : ///
173 : : /// \param ipprefix IP address prefix in the form "<ip-address>/n"
174 : : /// (where the "/n" part is optional and should be valid for the
175 : : /// address). If "n" is specified as zero, the match is for any
176 : : /// address in that address family. The address can also be
177 : : /// given as "any4" or "any6".
178 : 314 : IPCheck(const std::string& ipprefix) : family_(0) {
179 : :
180 : : // Ensure array elements are correctly initialized with zeroes.
181 : 157 : std::fill(address_, address_ + IPV6_SIZE, 0);
182 : 157 : std::fill(mask_, mask_ + IPV6_SIZE, 0);
183 : :
184 : : // Only deal with the string after we've removed leading and trailing
185 : : // spaces.
186 [ + - ]: 314 : const std::string mod_prefix = isc::util::str::trim(ipprefix);
187 : :
188 : : // Check for special cases first.
189 [ + + ]: 157 : if (mod_prefix == "any4") {
190 : 3 : family_ = AF_INET;
191 : :
192 [ + + ]: 154 : } else if (mod_prefix == "any6") {
193 : 3 : family_ = AF_INET6;
194 : :
195 : : } else {
196 : :
197 : : // General address prefix. Split into address part and prefix
198 : : // length.
199 : : const std::pair<std::string, int> result =
200 [ + + ]: 151 : internal::splitIPAddress(mod_prefix);
201 : :
202 : : // Try to convert the address. If successful, the result is in
203 : : // network-byte order (most significant components at lower
204 : : // addresses).
205 : 129 : int status = inet_pton(AF_INET6, result.first.c_str(), address_);
206 [ + + ]: 129 : if (status == 1) {
207 : : // It was an IPv6 address.
208 : 37 : family_ = AF_INET6;
209 : : } else {
210 : : // IPv6 interpretation failed, try IPv4.
211 : 92 : status = inet_pton(AF_INET, result.first.c_str(), address_);
212 [ + + ]: 92 : if (status == 1) {
213 : 86 : family_ = AF_INET;
214 : : }
215 : : }
216 : :
217 : : // Handle errors.
218 [ + + ]: 129 : if (status == 0) {
219 [ + - ][ + - ]: 12 : isc_throw(isc::InvalidParameter, "address prefix of " <<
[ + - ][ + - ]
220 : : ipprefix << " is not valid");
221 [ - + ]: 123 : } else if (status < 0) {
222 [ # # ][ # # ]: 0 : isc_throw(isc::Unexpected, "address conversion of " <<
[ # # ][ # # ]
223 : : ipprefix << " failed due to a system error");
224 : : }
225 : :
226 : : // All done, so set the mask used in the address comparison.
227 [ + + ]: 123 : setMask(result.second);
228 : : }
229 : 123 : }
230 : :
231 : : /// \brief Destructor
232 : 88 : virtual ~IPCheck() {}
233 : :
234 : : /// \brief The check itself
235 : : ///
236 : : /// Matches the passed argument to the condition stored here. Different
237 : : /// specialisations must be provided for different argument types, and the
238 : : /// program will fail to compile if a required specialisation is not
239 : : /// provided.
240 : : ///
241 : : /// It is expected that matches() will extract the address information from
242 : : /// the Context structure, and use compare() to actually perform the
243 : : /// comparison.
244 : : ///
245 : : /// \param context Information to be matched
246 : : virtual bool matches(const Context& context) const;
247 : :
248 : : /// \brief Estimated cost
249 : : ///
250 : : /// Assume that the cost of the match is linear and depends on the
251 : : /// maximum number of comparison operations.
252 : : ///
253 : : /// \return Estimated cost of the comparison
254 : 0 : virtual unsigned cost() const {
255 [ # # ]: 0 : return ((family_ == AF_INET) ? IPV4_SIZE : IPV6_SIZE);
256 : : }
257 : :
258 : : ///@{
259 : : /// Access methods - mainly for testing
260 : :
261 : : /// \return Stored IP address
262 : 21 : std::vector<uint8_t> getAddress() const {
263 [ + + ]: 21 : const size_t vector_len = (family_ == AF_INET ? IPV4_SIZE : IPV6_SIZE);
264 : 21 : return (std::vector<uint8_t>(address_, address_ + vector_len));
265 : : }
266 : :
267 : : /// \return Network mask applied to match
268 : 8 : std::vector<uint8_t> getMask() const {
269 [ + + ]: 8 : const size_t vector_len = (family_ == AF_INET ? IPV4_SIZE : IPV6_SIZE);
270 : 8 : return (std::vector<uint8_t>(mask_, mask_ + vector_len));
271 : : }
272 : :
273 : : /// \return Prefix length of the match
274 : 19 : size_t getPrefixlen() const {
275 : : // Work this out by counting bits in the mask.
276 : 21 : size_t count = 0;
277 [ + - ][ + - ]: 140 : for (size_t i = 0; i < IPV6_SIZE; ++i) {
[ + ]
278 [ + + ][ + + ]: 138 : if (mask_[i] == 0xff) {
279 : : // All bits set in this byte
280 : 119 : count += 8;
281 : 119 : continue;
282 : :
283 [ + + ][ - + ]: 19 : } else if (mask_[i] != 0) {
284 : : // Only some bits set in this byte. Count them.
285 : 6 : uint8_t byte = mask_[i];
286 [ + + ][ # # ]: 54 : for (int j = 0; j < 8; ++j) {
287 : 48 : count += byte & 0x01; // Add one if the bit is set
288 : 48 : byte >>= 1; // Go for next bit
289 : : }
290 : : }
291 : : break;
292 : : }
293 : 19 : return (count);
294 : : }
295 : :
296 : : /// \return Address family
297 : 0 : int getFamily() const {
298 : 0 : return (family_);
299 : : }
300 : : ///@}
301 : :
302 : : protected:
303 : : /// \brief Comparison
304 : : ///
305 : : /// This is the actual comparison function that checks the IP address passed
306 : : /// to this class with the matching information in the class itself. It is
307 : : /// expected to be called from matches().
308 : : ///
309 : : /// \param testaddr Address (in network byte order) to test against the
310 : : /// check condition in the class. This is expected to
311 : : /// be IPV6_SIZE or IPV4_SIZE bytes long.
312 : : /// \param family Address family of testaddr.
313 : : ///
314 : : /// \return true if the address matches, false if it does not.
315 : 185 : virtual bool compare(const uint8_t* testaddr, int family) const {
316 : :
317 [ + + ]: 185 : if (family != family_) {
318 : : // Can't match if the address is of the wrong family
319 : : return (false);
320 : : }
321 : :
322 : : // Simple check failed, so have to do a complete match. To check that
323 : : // the address given matches the stored network address and mask, we
324 : : // check the simple condition that:
325 : : //
326 : : // address_given & mask_ == stored_address & mask_
327 : : //
328 : : // The result is checked for all bytes for which there are bits set in
329 : : // the mask. We stop at the first non-match (or when we run out of bits
330 : : // in the mask).
331 : : //
332 : : // Note that the mask represents a contiguous set of bits. As such, as
333 : : // soon as we find a mask byte of zeroes, we have run past the part of
334 : : // the address where we need to match.
335 : : //
336 : : // Note also that when checking an IPv4 address, the constructor has
337 : : // set all bytes in the mask beyond the first four bytes to zero.
338 : : // As the loop stops when it encounters a zero mask byte, if the
339 : : // ACL is for an IPV4 address, the loop will never check more than four
340 : : // bytes.
341 : :
342 : : bool match = true;
343 [ + + ][ + + ]: 938 : for (int i = 0; match && (i < IPV6_SIZE) && (mask_[i] != 0); ++i) {
[ + + ][ + + ]
344 : 753 : match = ((testaddr[i] & mask_[i]) == (address_[i] & mask_[i]));
345 : : }
346 : : return (match);
347 : : }
348 : :
349 : : private:
350 : : /// \brief Set Mask
351 : : ///
352 : : /// Sets up the mask from the prefix length. This involves setting
353 : : /// an individual mask in each byte of the mask array.
354 : : ///
355 : : /// The actual allowed value of the prefix length depends on the address
356 : : /// family.
357 : : ///
358 : : /// \param requested Requested prefix length size. If negative, the
359 : : /// maximum for the address family is assumed. (A negative value
360 : : /// will arise if the string constructor was used and no mask size
361 : : /// was given.)
362 : 92 : void setMask(int requested) {
363 : :
364 : : // Set the maximum number of bits allowed in the mask, and request
365 : : // that number of bits if no prefix length was given in the constructor.
366 [ + + ]: 123 : const int maxmask = 8 * ((family_ == AF_INET) ? IPV4_SIZE : IPV6_SIZE);
367 [ + + ]: 123 : if (requested < 0) {
368 : 75 : requested = maxmask;
369 : : }
370 : :
371 : : // Validate that the mask is valid.
372 [ + + ]: 123 : if (requested <= maxmask) {
373 : :
374 : : // Loop, setting the bits in the set of mask bytes until all the
375 : : // specified bits have been used up. As both IPv4 and IPv6
376 : : // addresses are stored in network-byte order, this works in
377 : : // both cases.
378 : 117 : size_t bits_left = requested; // Bits remaining to set
379 : 117 : int i = -1;
380 [ + + ][ + + ]: 809 : while (bits_left > 0) {
381 [ + + ]: 692 : if (bits_left >= 8) {
382 : 682 : mask_[++i] = ~0; // All bits set
383 : 682 : bits_left -= 8;
384 : :
385 [ + - ]: 10 : } else if (bits_left > 0) {
386 [ + - ]: 10 : mask_[++i] = internal::createMask(bits_left);
387 : 692 : bits_left = 0;
388 : : }
389 : : }
390 : : } else {
391 [ + + ][ + + ]: 12 : isc_throw(isc::OutOfRange,
[ + + ][ + + ]
[ + - ][ - ]
[ - ][ - ][ - ]
392 : : "mask size of " << requested << " is invalid " <<
393 : : "for the given address family");
394 : : }
395 : 88 : }
396 : :
397 : : // Member variables.
398 : : uint8_t address_[IPV6_SIZE]; ///< Address in binary form
399 : : uint8_t mask_[IPV6_SIZE]; ///< Address mask
400 : : int family_; ///< Address family
401 : : };
402 : :
403 : : // Some compilers seem to need this to be explicitly defined outside the class
404 : : template <typename Context>
405 : : const size_t IPCheck<Context>::IPV6_SIZE;
406 : :
407 : : template <typename Context>
408 : : const size_t IPCheck<Context>::IPV4_SIZE;
409 : :
410 : : } // namespace acl
411 : : } // namespace isc
412 : :
413 : : #endif // __IP_CHECK_H
414 : :
415 : : // Local Variables:
416 : : // mode: c++
417 : : // End:
|