ip_check.h 16 KB

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