LCOV - code coverage report
Current view: top level - acl - ip_check.h (source / functions) Hit Total Coverage
Test: report.info Lines: 60 68 88.2 %
Date: 2012-05-15 Functions: 10 20 50.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 69 97 71.1 %

           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:

Generated by: LCOV version 1.9