IPAddress.h 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500
  1. /*
  2. * Copyright 2014-present Facebook, Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #pragma once
  17. #include <functional>
  18. #include <iosfwd>
  19. #include <memory>
  20. #include <string>
  21. #include <utility> // std::pair
  22. #include <folly/IPAddressException.h>
  23. #include <folly/IPAddressV4.h>
  24. #include <folly/IPAddressV6.h>
  25. #include <folly/Range.h>
  26. #include <folly/detail/IPAddress.h>
  27. namespace folly {
  28. class IPAddress;
  29. /**
  30. * Pair of IPAddress, netmask
  31. */
  32. typedef std::pair<IPAddress, uint8_t> CIDRNetwork;
  33. /**
  34. * Provides a unified interface for IP addresses.
  35. *
  36. * @note If you compare 2 IPAddress instances, v4-to-v6-mapped addresses are
  37. * compared as V4 addresses.
  38. *
  39. * @note toLong/fromLong deal in network byte order, use toLongHBO/fromLongHBO
  40. * if working in host byte order.
  41. *
  42. * Example usage:
  43. * @code
  44. * IPAddress v4addr("192.0.2.129");
  45. * IPAddress v6map("::ffff:192.0.2.129");
  46. * CHECK(v4addr.inSubnet("192.0.2.0/24") ==
  47. * v4addr.inSubnet(IPAddress("192.0.2.0"), 24));
  48. * CHECK(v4addr.inSubnet("192.0.2.128/30"));
  49. * CHECK(!v4addr.inSubnet("192.0.2.128/32"));
  50. * CHECK(v4addr.asV4().toLong() == 2164392128);
  51. * CHECK(v4addr.asV4().toLongHBO() == 3221226113);
  52. * CHECK(v4addr.isV4());
  53. * CHECK(v6addr.isV6());
  54. * CHECK(v4addr == v6map);
  55. * CHECK(v6map.isIPv4Mapped());
  56. * CHECK(v4addr.asV4() == IPAddress::createIPv4(v6map));
  57. * CHECK(IPAddress::createIPv6(v4addr) == v6map.asV6());
  58. * @encode
  59. */
  60. class IPAddress {
  61. private:
  62. template <typename F>
  63. auto pick(F f) const {
  64. return isV4() ? f(asV4()) : f(asV6());
  65. }
  66. public:
  67. // returns true iff the input string can be parsed as an ip-address
  68. static bool validate(StringPiece ip) noexcept;
  69. // return the V4 representation of the address, converting it from V6 to V4 if
  70. // needed. Note that this will throw an IPAddressFormatException if the V6
  71. // address is not IPv4Mapped.
  72. static IPAddressV4 createIPv4(const IPAddress& addr);
  73. // return the V6 representation of the address, converting it from V4 to V6 if
  74. // needed.
  75. static IPAddressV6 createIPv6(const IPAddress& addr);
  76. /**
  77. * Create a network and mask from a CIDR formatted address string.
  78. * @param [in] ipSlashCidr IP/CIDR formatted string to split
  79. * @param [in] defaultCidr default value if no /N specified (if defaultCidr
  80. * is -1, will use /32 for IPv4 and /128 for IPv6)
  81. * @param [in] mask apply mask on the address or not,
  82. * e.g. 192.168.13.46/24 => 192.168.13.0/24
  83. * @return either pair with IPAddress network and uint8_t mask or
  84. * CIDRNetworkError
  85. */
  86. static Expected<CIDRNetwork, CIDRNetworkError> tryCreateNetwork(
  87. StringPiece ipSlashCidr,
  88. int defaultCidr = -1,
  89. bool mask = true);
  90. /**
  91. * Create a network and mask from a CIDR formatted address string.
  92. * Same as tryCreateNetwork() but throws IPAddressFormatException on error.
  93. * The implementation calls tryCreateNetwork(...) underneath
  94. *
  95. * @throws IPAddressFormatException if invalid address
  96. * @return pair with IPAddress network and uint8_t mask
  97. */
  98. static CIDRNetwork createNetwork(
  99. StringPiece ipSlashCidr,
  100. int defaultCidr = -1,
  101. bool mask = true);
  102. /**
  103. * Return a string representation of a CIDR block created with createNetwork.
  104. * @param [in] network, pair of address and cidr
  105. *
  106. * @return string representing the netblock
  107. */
  108. static std::string networkToString(const CIDRNetwork& network);
  109. /**
  110. * Create a new IPAddress instance from the provided binary data
  111. * in network byte order.
  112. * @throws IPAddressFormatException if len is not 4 or 16
  113. */
  114. static IPAddress fromBinary(ByteRange bytes);
  115. /**
  116. * Non-throwing version of fromBinary().
  117. * On failure returns IPAddressFormatError.
  118. */
  119. static Expected<IPAddress, IPAddressFormatError> tryFromBinary(
  120. ByteRange bytes) noexcept;
  121. /**
  122. * Tries to create a new IPAddress instance from provided string and
  123. * returns it on success. Returns IPAddressFormatError on failure.
  124. */
  125. static Expected<IPAddress, IPAddressFormatError> tryFromString(
  126. StringPiece str) noexcept;
  127. /**
  128. * Create an IPAddress from a 32bit long (network byte order).
  129. * @throws IPAddressFormatException
  130. */
  131. static IPAddress fromLong(uint32_t src);
  132. // Same as above, but host byte order
  133. static IPAddress fromLongHBO(uint32_t src);
  134. // Given 2 IPAddress,mask pairs extract the longest common IPAddress,
  135. // mask pair
  136. static CIDRNetwork longestCommonPrefix(
  137. const CIDRNetwork& one,
  138. const CIDRNetwork& two);
  139. /**
  140. * Constructs an uninitialized IPAddress.
  141. */
  142. IPAddress();
  143. /**
  144. * Parse an IPAddress from a string representation.
  145. *
  146. * Formats accepted are exactly the same as the ones accepted by inet_pton(),
  147. * using AF_INET6 if the string contains colons, and AF_INET otherwise;
  148. * with the exception that the whole address can optionally be enclosed
  149. * in square brackets.
  150. *
  151. * @throws IPAddressFormatException
  152. */
  153. explicit IPAddress(StringPiece ip);
  154. /**
  155. * Create an IPAddress from a sockaddr.
  156. * @throws IPAddressFormatException if nullptr or not AF_INET or AF_INET6
  157. */
  158. explicit IPAddress(const sockaddr* addr);
  159. // Create an IPAddress from a V4 address
  160. /* implicit */ IPAddress(const IPAddressV4 ipV4Addr) noexcept;
  161. /* implicit */ IPAddress(const in_addr addr) noexcept;
  162. // Create an IPAddress from a V6 address
  163. /* implicit */ IPAddress(const IPAddressV6& ipV6Addr) noexcept;
  164. /* implicit */ IPAddress(const in6_addr& addr) noexcept;
  165. // Assign from V4 address
  166. IPAddress& operator=(const IPAddressV4& ipV4Addr) noexcept;
  167. // Assign from V6 address
  168. IPAddress& operator=(const IPAddressV6& ipV6Addr) noexcept;
  169. /**
  170. * Converts an IPAddress to an IPAddressV4 instance.
  171. * @note This is not some handy convenience wrapper to convert an IPv4 address
  172. * to a mapped IPv6 address. If you want that use
  173. * IPAddress::createIPv6(addr)
  174. * @throws InvalidAddressFamilyException is not a V4 instance
  175. */
  176. const IPAddressV4& asV4() const {
  177. if (UNLIKELY(!isV4())) {
  178. asV4Throw();
  179. }
  180. return addr_.ipV4Addr;
  181. }
  182. /**
  183. * Converts an IPAddress to an IPAddressV6 instance.
  184. * @throws InvalidAddressFamilyException is not a V6 instance
  185. */
  186. const IPAddressV6& asV6() const {
  187. if (UNLIKELY(!isV6())) {
  188. asV6Throw();
  189. }
  190. return addr_.ipV6Addr;
  191. }
  192. // Return sa_family_t of IPAddress
  193. sa_family_t family() const {
  194. return family_;
  195. }
  196. // Populate sockaddr_storage with an appropriate value
  197. int toSockaddrStorage(sockaddr_storage* dest, uint16_t port = 0) const {
  198. if (dest == nullptr) {
  199. throw IPAddressFormatException("dest must not be null");
  200. }
  201. memset(dest, 0, sizeof(sockaddr_storage));
  202. dest->ss_family = family();
  203. if (isV4()) {
  204. sockaddr_in* sin = reinterpret_cast<sockaddr_in*>(dest);
  205. sin->sin_addr = asV4().toAddr();
  206. sin->sin_port = port;
  207. #if defined(__APPLE__)
  208. sin->sin_len = sizeof(*sin);
  209. #endif
  210. return sizeof(*sin);
  211. } else if (isV6()) {
  212. sockaddr_in6* sin = reinterpret_cast<sockaddr_in6*>(dest);
  213. sin->sin6_addr = asV6().toAddr();
  214. sin->sin6_port = port;
  215. sin->sin6_scope_id = asV6().getScopeId();
  216. #if defined(__APPLE__)
  217. sin->sin6_len = sizeof(*sin);
  218. #endif
  219. return sizeof(*sin);
  220. } else {
  221. throw InvalidAddressFamilyException(family());
  222. }
  223. }
  224. /**
  225. * Check if the address is found in the specified CIDR netblock.
  226. *
  227. * This will return false if the specified cidrNet is V4, but the address is
  228. * V6. It will also return false if the specified cidrNet is V6 but the
  229. * address is V4. This method will do the right thing in the case of a v6
  230. * mapped v4 address.
  231. *
  232. * @note This is slower than the below counterparts. If perf is important use
  233. * one of the two argument variations below.
  234. * @param [in] ipSlashCidr address in "192.168.1.0/24" format
  235. * @throws IPAddressFormatException if no /mask
  236. * @return true if address is part of specified subnet with cidr
  237. */
  238. bool inSubnet(StringPiece ipSlashCidr) const;
  239. /**
  240. * Check if an IPAddress belongs to a subnet.
  241. * @param [in] subnet Subnet to check against (e.g. 192.168.1.0)
  242. * @param [in] cidr CIDR for subnet (e.g. 24 for /24)
  243. * @return true if address is part of specified subnet with cidr
  244. */
  245. bool inSubnet(const IPAddress& subnet, uint8_t cidr) const;
  246. /**
  247. * Check if an IPAddress belongs to the subnet with the given mask.
  248. * This is the same as inSubnet but the mask is provided instead of looked up
  249. * from the cidr.
  250. * @param [in] subnet Subnet to check against
  251. * @param [in] mask The netmask for the subnet
  252. * @return true if address is part of the specified subnet with mask
  253. */
  254. bool inSubnetWithMask(const IPAddress& subnet, ByteRange mask) const;
  255. // @return true if address is a v4 mapped address
  256. bool isIPv4Mapped() const {
  257. return isV6() && asV6().isIPv4Mapped();
  258. }
  259. // @return true if address is uninitialized
  260. bool empty() const {
  261. return family_ == AF_UNSPEC;
  262. }
  263. // @return true if address is initialized
  264. explicit operator bool() const {
  265. return !empty();
  266. }
  267. // @return true if this is an IPAddressV4 instance
  268. bool isV4() const {
  269. return family_ == AF_INET;
  270. }
  271. // @return true if this is an IPAddressV6 instance
  272. bool isV6() const {
  273. return family_ == AF_INET6;
  274. }
  275. // @return true if this address is all zeros
  276. bool isZero() const {
  277. return pick([&](auto& _) { return _.isZero(); });
  278. }
  279. // Number of bits in the address representation.
  280. size_t bitCount() const {
  281. return pick([&](auto& _) { return _.bitCount(); });
  282. }
  283. // Number of bytes in the address representation.
  284. size_t byteCount() const {
  285. return bitCount() / 8;
  286. }
  287. // get nth most significant bit - 0 indexed
  288. bool getNthMSBit(size_t bitIndex) const {
  289. return detail::getNthMSBitImpl(*this, bitIndex, family());
  290. }
  291. // get nth most significant byte - 0 indexed
  292. uint8_t getNthMSByte(size_t byteIndex) const;
  293. // get nth bit - 0 indexed
  294. bool getNthLSBit(size_t bitIndex) const {
  295. return getNthMSBit(bitCount() - bitIndex - 1);
  296. }
  297. // get nth byte - 0 indexed
  298. uint8_t getNthLSByte(size_t byteIndex) const {
  299. return getNthMSByte(byteCount() - byteIndex - 1);
  300. }
  301. /**
  302. * Get human-readable string representation of the address.
  303. *
  304. * This prints a string representation of the address, for human consumption
  305. * or logging. The string will take the form of a JSON object that looks like:
  306. * {family:'AF_INET|AF_INET6', addr:'address', hash:long}.
  307. */
  308. std::string toJson() const {
  309. return pick([&](auto& _) { return _.toJson(); });
  310. }
  311. // Hash of address
  312. std::size_t hash() const {
  313. return pick([&](auto& _) { return _.hash(); });
  314. }
  315. // Return true if the address qualifies as localhost.
  316. bool isLoopback() const {
  317. return pick([&](auto& _) { return _.isLoopback(); });
  318. }
  319. // Return true if the address qualifies as link local
  320. bool isLinkLocal() const {
  321. return pick([&](auto& _) { return _.isLinkLocal(); });
  322. }
  323. // Return true if the address qualifies as broadcast.
  324. bool isLinkLocalBroadcast() const {
  325. return pick([&](auto& _) { return _.isLinkLocalBroadcast(); });
  326. }
  327. /**
  328. * Return true if the address is a special purpose address, as per rfc6890
  329. * (i.e. 0.0.0.0).
  330. * For V6, true if the address is not in one of global scope blocks:
  331. * 2000::/3, ffxe::/16.
  332. */
  333. bool isNonroutable() const {
  334. return pick([&](auto& _) { return _.isNonroutable(); });
  335. }
  336. /**
  337. * Return true if the address is private, as per rfc1918 and rfc4193
  338. * (for example, 192.168.xxx.xxx or fc00::/7 addresses)
  339. */
  340. bool isPrivate() const {
  341. return pick([&](auto& _) { return _.isPrivate(); });
  342. }
  343. // Return true if the address is a multicast address.
  344. bool isMulticast() const {
  345. return pick([&](auto& _) { return _.isMulticast(); });
  346. }
  347. /**
  348. * Creates IPAddress instance with all but most significant numBits set to 0.
  349. * @param [in] numBits number of bits to mask
  350. * @throws abort if numBits > bitCount()
  351. * @return IPAddress instance with bits set to 0
  352. */
  353. IPAddress mask(uint8_t numBits) const {
  354. return pick([&](auto& _) { return IPAddress(_.mask(numBits)); });
  355. }
  356. /**
  357. * Provides a string representation of address.
  358. * @note The string representation is calculated on demand.
  359. * @throws IPAddressFormatException on inet_ntop error
  360. */
  361. std::string str() const {
  362. return pick([&](auto& _) { return _.str(); });
  363. }
  364. /**
  365. * Return the fully qualified string representation of the address.
  366. * For V4 addresses this is the same as calling str(). For V6 addresses
  367. * this is the hex representation with : characters inserted every 4 digits.
  368. */
  369. std::string toFullyQualified() const {
  370. return pick([&](auto& _) { return _.toFullyQualified(); });
  371. }
  372. /// Same as toFullyQualified but append to an output string.
  373. void toFullyQualifiedAppend(std::string& out) const {
  374. return pick([&](auto& _) { return _.toFullyQualifiedAppend(out); });
  375. }
  376. // Address version (4 or 6)
  377. uint8_t version() const {
  378. return pick([&](auto& _) { return _.version(); });
  379. }
  380. /**
  381. * Access to address bytes, in network byte order.
  382. */
  383. const unsigned char* bytes() const {
  384. return pick([&](auto& _) { return _.bytes(); });
  385. }
  386. private:
  387. [[noreturn]] void asV4Throw() const;
  388. [[noreturn]] void asV6Throw() const;
  389. typedef union IPAddressV46 {
  390. IPAddressV4 ipV4Addr;
  391. IPAddressV6 ipV6Addr;
  392. // default constructor
  393. IPAddressV46() noexcept {
  394. std::memset(this, 0, sizeof(IPAddressV46));
  395. }
  396. explicit IPAddressV46(const IPAddressV4& addr) noexcept : ipV4Addr(addr) {}
  397. explicit IPAddressV46(const IPAddressV6& addr) noexcept : ipV6Addr(addr) {}
  398. } IPAddressV46;
  399. IPAddressV46 addr_;
  400. sa_family_t family_;
  401. };
  402. // boost::hash uses hash_value() so this allows boost::hash to work
  403. // automatically for IPAddress
  404. std::size_t hash_value(const IPAddress& addr);
  405. std::ostream& operator<<(std::ostream& os, const IPAddress& addr);
  406. // Define toAppend() to allow IPAddress to be used with folly::to<string>
  407. void toAppend(IPAddress addr, std::string* result);
  408. void toAppend(IPAddress addr, fbstring* result);
  409. /**
  410. * Return true if two addresses are equal.
  411. *
  412. * @note This takes into consideration V4 mapped addresses as well. If one
  413. * address is v4 mapped we compare the v4 addresses.
  414. *
  415. * @return true if the two addresses are equal.
  416. */
  417. bool operator==(const IPAddress& addr1, const IPAddress& addr2);
  418. // Return true if addr1 < addr2
  419. bool operator<(const IPAddress& addr1, const IPAddress& addr2);
  420. // Derived operators
  421. inline bool operator!=(const IPAddress& a, const IPAddress& b) {
  422. return !(a == b);
  423. }
  424. inline bool operator>(const IPAddress& a, const IPAddress& b) {
  425. return b < a;
  426. }
  427. inline bool operator<=(const IPAddress& a, const IPAddress& b) {
  428. return !(a > b);
  429. }
  430. inline bool operator>=(const IPAddress& a, const IPAddress& b) {
  431. return !(a < b);
  432. }
  433. } // namespace folly
  434. namespace std {
  435. template <>
  436. struct hash<folly::IPAddress> {
  437. size_t operator()(const folly::IPAddress& addr) const {
  438. return addr.hash();
  439. }
  440. };
  441. } // namespace std