ip_check.h 16 KB

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