ip_check.h 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  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 <algorithm>
  17. #include <functional>
  18. #include <iterator>
  19. #include <utility>
  20. #include <vector>
  21. #include <boost/lexical_cast.hpp>
  22. #include <boost/static_assert.hpp>
  23. #include <boost/scoped_ptr.hpp>
  24. #include <stdint.h>
  25. #include <arpa/inet.h>
  26. #include <netinet/in.h>
  27. #include <acl/check.h>
  28. #include <exceptions/exceptions.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. /// The function is templated on the data type of the mask.
  44. ///
  45. /// \param prefixlen number of bits to be set in the mask. This must be
  46. /// between 0 and 8*sizeof(T).
  47. ///
  48. /// \return Value with the most significant "prefixlen" bits set.
  49. ///
  50. /// \exception OutOfRange prefixlen is too large for the data type.
  51. template <typename T>
  52. T createMask(size_t prefixlen) {
  53. if (prefixlen == 0) {
  54. return (0);
  55. } else if (prefixlen <= 8 * sizeof(T)) {
  56. // In the following discussion:
  57. //
  58. // w is the width of the data type T in bits.
  59. // m is the value of prefixlen, the number of most signifcant bits we
  60. // want to set.
  61. // ** is exponentiation (i.e. 2**n is 2 raised to the power of n).
  62. //
  63. // We note that the value of 2**m - 1 gives a value with the least
  64. // significant m bits set. For a data type of width w, this means that
  65. // the most signficant (w-m) bits are clear.
  66. //
  67. // Hence the value 2**(w-m) - 1 gives a result with the least signficant
  68. // w-m bits set and the most significant m bits clear. The 1's
  69. // complement of this value gives is the result we want.
  70. //
  71. // Final note: at this point in the logic, m is non-zero, so w-m < w.
  72. // This means 1<<(w-m) will fit into a variable of width w bits. In
  73. // other words, in the expression below, no term will cause an integer
  74. // overflow.
  75. return (~((1 << (8 * sizeof(T) - prefixlen)) - 1));
  76. }
  77. // Mask size is too large. (Note that prefixlen is unsigned, so can't be
  78. // negative.)
  79. isc_throw(isc::OutOfRange, "prefixlen argument must be between 0 and " <<
  80. 8 * sizeof(T));
  81. }
  82. /// \brief Split IP Address Prefix
  83. ///
  84. /// Splits an IP address prefix (given in the form of "xxxxxx/n" or "xxxxx" into
  85. /// a string representing the IP address and a number giving the length of the
  86. /// prefix. (In the latter case, the prefix is equal in length to the width in
  87. /// width in bits of the data type holding the address.) An exception will be
  88. /// thrown if the string format is invalid or if the prefix length is invalid.
  89. ///
  90. /// N.B. This function does NOT check that the address component is a valid IP
  91. /// address; this is done elsewhere in the address parsing process.
  92. ///
  93. /// \param ipprefix Address or address prefix. The string should be passed
  94. /// without leading or trailing spaces.
  95. ///
  96. /// \return Pair of (string, int) holding the address string and the prefix
  97. /// length. The second element is -1 if no prefix was given.
  98. ///
  99. /// \exception InvalidParameter Address prefix not of the expected syntax
  100. std::pair<std::string, int>
  101. splitIPAddress(const std::string& ipprefix);
  102. } // namespace internal
  103. /// \brief IP Check
  104. ///
  105. /// This class performs a match between an IP address prefix specified in an ACL
  106. /// and a given IP address. The check works for both IPV4 and IPV6 addresses.
  107. ///
  108. /// The class is templated on the type of a context structure passed to the
  109. /// matches() method, and a template specialisation for that method must be
  110. /// supplied for the class to be used.
  111. template <typename Context>
  112. class IPCheck : public Check<Context> {
  113. private:
  114. // Size of uint8_t array to holds different address types
  115. static const size_t IPV6_SIZE = sizeof(struct in6_addr);
  116. static const size_t IPV4_SIZE = sizeof(struct in_addr);
  117. public:
  118. /// \brief Default Constructor
  119. ///
  120. /// Constructs an empty IPCheck object. The address family returned will
  121. /// be zero.
  122. IPCheck() : address_(), mask_(), family_(0)
  123. {}
  124. /// \brief IPV4 Constructor
  125. ///
  126. /// Constructs an IPCheck object from a network address given as a
  127. /// 32-bit value in network byte order and a prefix length.
  128. ///
  129. /// \param address IP address to check for (as an address in host-byte
  130. /// order). Note host-byte order - this is different to the IPV6
  131. /// constructor.
  132. /// \param prefixlen The prefix length specified as an integer between 0
  133. /// and 32. This determines the number of bits of the address to
  134. /// check. (A value of zero imples match all IPV4 addresses.)
  135. IPCheck(uint32_t address, int prefixlen = 8 * IPV4_SIZE) :
  136. address_(IPV4_SIZE), mask_(), family_(AF_INET)
  137. {
  138. // The address is stored in network-byte order, so the MS byte should
  139. // be stored at the lowest address in the array.
  140. address_[3] = static_cast<uint8_t>((address ) & 0xff);
  141. address_[2] = static_cast<uint8_t>((address >> 8) & 0xff);
  142. address_[1] = static_cast<uint8_t>((address >> 16) & 0xff);
  143. address_[0] = static_cast<uint8_t>((address >> 24) & 0xff);
  144. setMask(prefixlen);
  145. }
  146. /// \brief IPV6 Constructor
  147. ///
  148. /// Constructs an IPV6 Check object from a network address given as a
  149. /// 16-byte array in network-byte order and a prefix length.
  150. ///
  151. /// \param address IP address to check for (as an address in network-byte
  152. /// order).
  153. /// \param prefixlen The prefix length specified as an integer between 0
  154. /// and 128. This determines the number of bits of the address to
  155. /// check.
  156. IPCheck(const uint8_t* address, int prefixlen = 8 * IPV6_SIZE) :
  157. address_(address, address + IPV6_SIZE), mask_(), family_(AF_INET6)
  158. {
  159. setMask(prefixlen);
  160. }
  161. /// \brief String Constructor
  162. ///
  163. /// Constructs an IP Check object from an address or address prefix in the
  164. /// form <ip-address>/n".
  165. ///
  166. /// Also allowed are the special keywords "any4" and "any6", which match
  167. /// any IPV4 or IPV6 address. These must be specified exactly as-is
  168. /// (i.e. lowercase, with no leading or trailing spaces).
  169. ///
  170. /// \param ipprefix IP address prefix in the form "<ip-address>/n"
  171. /// (where the "/n" part is optional and should be valid for the
  172. /// address). If "n" is specified as zero, the match is for any
  173. /// address in that address family. The address can also be
  174. /// given as "any4" or "any6".
  175. IPCheck(const std::string& ipprefix) : address_(), mask_(), family_(0) {
  176. // Check for special cases first.
  177. if (ipprefix == "any4") {
  178. family_ = AF_INET;
  179. } else if (ipprefix == "any6") {
  180. family_ = AF_INET6;
  181. } else {
  182. // General address prefix. Split into address part and prefix
  183. // length.
  184. const std::pair<std::string, int> result =
  185. internal::splitIPAddress(ipprefix);
  186. // Try to convert the address. If successful, the result is in
  187. // network-byte order (most significant components at lower
  188. // addresses).
  189. BOOST_STATIC_ASSERT(IPV6_SIZE > IPV4_SIZE);
  190. uint8_t address_bytes[IPV6_SIZE];
  191. int status = inet_pton(AF_INET6, result.first.c_str(),
  192. address_bytes);
  193. if (status == 1) {
  194. // It was an IPV6 address, copy into the address store
  195. std::copy(address_bytes, address_bytes + IPV6_SIZE,
  196. std::back_inserter(address_));
  197. family_ = AF_INET6;
  198. } else {
  199. // Not IPV6, try IPV4
  200. int status = inet_pton(AF_INET, result.first.c_str(),
  201. address_bytes);
  202. if (status == 1) {
  203. std::copy(address_bytes, address_bytes + IPV4_SIZE,
  204. std::back_inserter(address_));
  205. family_ = AF_INET;
  206. } else {
  207. isc_throw(isc::InvalidParameter, "address prefix of " <<
  208. ipprefix << " is a not valid");
  209. }
  210. }
  211. // All done, so set the mask used in address comparison.
  212. setMask(result.second);
  213. }
  214. }
  215. /// \brief Destructor
  216. virtual ~IPCheck() {}
  217. /// \brief The check itself
  218. ///
  219. /// Matches the passed argument to the condition stored here. Different
  220. /// specialisations must be provided for different argument types, and the
  221. /// program will fail to compile if a required specialisation is not
  222. /// provided.
  223. ///
  224. /// \param context Information to be matched
  225. virtual bool matches(const Context& context) const;
  226. /// \brief Estimated cost
  227. ///
  228. /// Assume that the cost of the match is linear and depends on the
  229. /// maximum number of comparison operations.
  230. ///
  231. /// \return Estimated cost of the comparison
  232. virtual unsigned cost() const {
  233. return ((family_ == AF_INET) ? IPV4_SIZE : IPV6_SIZE);
  234. }
  235. ///@{
  236. /// Access methods - mainly for testing
  237. /// \return Stored IP address
  238. std::vector<uint8_t> getAddress() const {
  239. return (address_);
  240. }
  241. /// \return Network mask applied to match
  242. std::vector<uint8_t> getMask() const {
  243. return (mask_);
  244. }
  245. /// \return Prefix length of the match
  246. size_t getPrefixlen() const {
  247. // Work this out by shifting bits out of the mask
  248. size_t count = 0;
  249. for (size_t i = 0; i < mask_.size(); ++i) {
  250. if (mask_[i] == 0xff) {
  251. // Full byte, 8 bit set
  252. count += 8;
  253. } else if (mask_[i] != 0) {
  254. // Partial set, count the bits
  255. uint8_t byte = mask_[i];
  256. for (int i = 0; i < 8 * sizeof(uint8_t); ++i) {
  257. count += byte & 0x01; // Add one if the bit is set
  258. byte >>= 1; // Go for next bit
  259. }
  260. // There won't be any more bits set after this, so exit
  261. break;
  262. }
  263. }
  264. return (count);
  265. }
  266. /// \return Address family
  267. int getFamily() const {
  268. // Check that a family_ value of 0 does not imply IPV4 or IPV6.
  269. // This avoids confusion if getFamily() is called on an object that
  270. // has been initialized by default.
  271. BOOST_STATIC_ASSERT(AF_INET != 0);
  272. BOOST_STATIC_ASSERT(AF_INET6 != 0);
  273. return (family_);
  274. }
  275. ///@}
  276. private:
  277. /// \brief Comparison
  278. ///
  279. /// This is the actual comparison function that checks the IP address passed
  280. /// to this class with the matching information in the class itself. It is
  281. /// expected to be called from matches().
  282. ///
  283. /// \param testaddr Address (in network byte order) to test against the
  284. /// check condition in the class. This is expected to
  285. /// be IPV6_SIZE or IPV4_SIZE bytes long.
  286. /// \param family Address family of testaddr.
  287. ///
  288. /// \return true if the address matches, false if it does not.
  289. virtual bool compare(const uint8_t* testaddr, int family) const {
  290. if (family != family_) {
  291. // Can't match if the address is of the wrong family
  292. return (false);
  293. }
  294. // Simple check failed, so have to do a complete match. To check that
  295. // the address given matches the stored network address and mask, we
  296. // check the simple condition that:
  297. //
  298. // address_given & mask_ == stored_address & mask_
  299. //
  300. // The result is checked for all bytes for which there are bits set in
  301. // the mask. We stop at the first non-match (or when we run out of bits
  302. // in the mask). (Note that the mask represents a contiguous set of
  303. // bits. As such, as soon as we find a mask byte of zeroes, we have run
  304. // past the part of the address where we need to match.
  305. //
  306. // Note that if the passed address was any4 or any6, we rely on the
  307. // fact that the size of address_ is zero - the loop will terminate
  308. // before the first iteration.
  309. bool match = true;
  310. for (int i = 0; match && (i < address_.size()) &&
  311. (mask_[i] != 0); ++i) {
  312. match = ((testaddr[i] & mask_[i]) == (address_[i] & mask_[i]));
  313. }
  314. return (match);
  315. }
  316. /// \brief Set Mask
  317. ///
  318. /// Sets up the mask from the prefix length. This involves setting
  319. /// an individual mask in each byte of the mask array.
  320. ///
  321. /// The actual allowed value of the prefix length depends on the address
  322. /// family.
  323. ///
  324. /// \param requested Requested prefix length size. If negative, the
  325. /// maximum for the address family is assumed. (A negative value
  326. /// will arise if the string constructor was used and no mask size
  327. /// was given.)
  328. void setMask(int requested) {
  329. mask_.clear();
  330. mask_.resize((family_ == AF_INET) ? IPV4_SIZE : IPV6_SIZE);
  331. // Set the maximum number of bits allowed in the mask.
  332. int maxmask = 8 * (mask_.size());
  333. if (requested < 0) {
  334. requested = maxmask;
  335. }
  336. // Validate that the mask is valid.
  337. if (requested <= maxmask) {
  338. // Loop, setting the bits in the set of mask bytes until all the
  339. // specified bits have been used up. As both IPV4 and IPV6
  340. // addresses are stored in network-byte order, this works in
  341. // both cases.
  342. size_t bits_left = requested; // Bits remaining to set
  343. int i = -1;
  344. while (bits_left > 0) {
  345. if (bits_left >= 8) {
  346. mask_[++i] = ~0; // All bits set
  347. bits_left -= 8;
  348. } else if (bits_left > 0) {
  349. mask_[++i] = internal::createMask<uint8_t>(bits_left);
  350. bits_left = 0;
  351. }
  352. }
  353. } else {
  354. isc_throw(isc::OutOfRange,
  355. "mask size of " << requested << " is invalid " <<
  356. "for the given address");
  357. }
  358. }
  359. // Member variables
  360. std::vector<uint8_t> address_; ///< Address in binary form
  361. std::vector<uint8_t> mask_; ///< Address mask
  362. int family_; ///< Address family
  363. };
  364. } // namespace acl
  365. } // namespace isc
  366. #endif // __IP_CHECK_H