IPAddressV6.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444
  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 <cstring>
  18. #include <array>
  19. #include <functional>
  20. #include <iosfwd>
  21. #include <map>
  22. #include <stdexcept>
  23. #include <folly/Expected.h>
  24. #include <folly/FBString.h>
  25. #include <folly/IPAddressException.h>
  26. #include <folly/Optional.h>
  27. #include <folly/Range.h>
  28. #include <folly/detail/IPAddress.h>
  29. #include <folly/hash/Hash.h>
  30. namespace folly {
  31. class IPAddress;
  32. class IPAddressV4;
  33. class IPAddressV6;
  34. class MacAddress;
  35. /**
  36. * Pair of IPAddressV6, netmask
  37. */
  38. typedef std::pair<IPAddressV6, uint8_t> CIDRNetworkV6;
  39. /**
  40. * Specialization for IPv6 addresses
  41. */
  42. typedef std::array<uint8_t, 16> ByteArray16;
  43. /**
  44. * IPv6 variation of IPAddress.
  45. *
  46. * Added methods: createIPv4, getIPv4For6To4, is6To4,
  47. * isTeredo, isIPv4Mapped, tryCreateIPv4, type
  48. *
  49. * @see IPAddress
  50. *
  51. * Notes on scope ID parsing:
  52. *
  53. * getaddrinfo() uses if_nametoindex() to convert interface names
  54. * into a numerical index. For instance,
  55. * "fe80::202:c9ff:fec1:ee08%eth0" may return scope ID 2 on some
  56. * hosts, but other numbers on other hosts. It will fail entirely on
  57. * hosts without an eth0 interface.
  58. *
  59. * Serializing / Deserializing IPAddressB6's on different hosts
  60. * that use link-local scoping probably won't work.
  61. */
  62. class IPAddressV6 {
  63. public:
  64. // V6 Address Type
  65. enum Type {
  66. TEREDO,
  67. T6TO4,
  68. NORMAL,
  69. };
  70. // A constructor parameter to indicate that we should create a link-local
  71. // IPAddressV6.
  72. enum LinkLocalTag {
  73. LINK_LOCAL,
  74. };
  75. // Thrown when a type assertion fails
  76. typedef std::runtime_error TypeError;
  77. // Binary prefix for teredo networks
  78. static const uint32_t PREFIX_TEREDO;
  79. // Binary prefix for 6to4 networks
  80. static const uint32_t PREFIX_6TO4;
  81. // Size of std::string returned by toFullyQualified.
  82. static constexpr size_t kToFullyQualifiedSize =
  83. 8 /*words*/ * 4 /*hex chars per word*/ + 7 /*separators*/;
  84. // returns true iff the input string can be parsed as an ipv6-address
  85. static bool validate(StringPiece ip) noexcept;
  86. /**
  87. * Create a new IPAddress instance from the provided binary data.
  88. * @throws IPAddressFormatException if the input length is not 16 bytes.
  89. */
  90. static IPAddressV6 fromBinary(ByteRange bytes);
  91. /**
  92. * Non-throwing version of fromBinary().
  93. * On failure returns IPAddressFormatError.
  94. */
  95. static Expected<IPAddressV6, IPAddressFormatError> tryFromBinary(
  96. ByteRange bytes) noexcept;
  97. /**
  98. * Tries to create a new IPAddressV6 instance from provided string and
  99. * returns it on success. Returns IPAddressFormatError on failure.
  100. */
  101. static Expected<IPAddressV6, IPAddressFormatError> tryFromString(
  102. StringPiece str) noexcept;
  103. /**
  104. * Create a new IPAddress instance from the ip6.arpa representation.
  105. * @throws IPAddressFormatException if the input is not a valid ip6.arpa
  106. * representation
  107. */
  108. static IPAddressV6 fromInverseArpaName(const std::string& arpaname);
  109. /**
  110. * Returns the address as a Range.
  111. */
  112. ByteRange toBinary() const {
  113. return ByteRange((const unsigned char*)&addr_.in6Addr_.s6_addr, 16);
  114. }
  115. /**
  116. * Default constructor for IPAddressV6.
  117. *
  118. * The address value will be ::0
  119. */
  120. IPAddressV6();
  121. // Create an IPAddressV6 from a string
  122. // @throws IPAddressFormatException
  123. //
  124. explicit IPAddressV6(StringPiece ip);
  125. // ByteArray16 constructor
  126. explicit IPAddressV6(const ByteArray16& src) noexcept;
  127. // in6_addr constructor
  128. explicit IPAddressV6(const in6_addr& src) noexcept;
  129. // sockaddr_in6 constructor
  130. explicit IPAddressV6(const sockaddr_in6& src) noexcept;
  131. /**
  132. * Create a link-local IPAddressV6 from the specified ethernet MAC address.
  133. */
  134. IPAddressV6(LinkLocalTag tag, MacAddress mac);
  135. // return the mapped V4 address
  136. // @throws IPAddressFormatException if !isIPv4Mapped
  137. IPAddressV4 createIPv4() const;
  138. /**
  139. * Return a V4 address if this is a 6To4 address.
  140. * @throws TypeError if not a 6To4 address
  141. */
  142. IPAddressV4 getIPv4For6To4() const;
  143. // Return true if a 6TO4 address
  144. bool is6To4() const {
  145. return type() == IPAddressV6::Type::T6TO4;
  146. }
  147. // Return true if a TEREDO address
  148. bool isTeredo() const {
  149. return type() == IPAddressV6::Type::TEREDO;
  150. }
  151. // return true if this is v4-to-v6-mapped
  152. bool isIPv4Mapped() const;
  153. // Return the V6 address type
  154. Type type() const;
  155. /**
  156. * @see IPAddress#bitCount
  157. * @returns 128
  158. */
  159. static constexpr size_t bitCount() {
  160. return 128;
  161. }
  162. /**
  163. * @see IPAddress#toJson
  164. */
  165. std::string toJson() const;
  166. size_t hash() const;
  167. // @see IPAddress#inSubnet
  168. // @throws IPAddressFormatException if string doesn't contain a V6 address
  169. bool inSubnet(StringPiece cidrNetwork) const;
  170. // return true if address is in subnet
  171. bool inSubnet(const IPAddressV6& subnet, uint8_t cidr) const {
  172. return inSubnetWithMask(subnet, fetchMask(cidr));
  173. }
  174. bool inSubnetWithMask(const IPAddressV6& subnet, const ByteArray16& mask)
  175. const;
  176. // @see IPAddress#isLoopback
  177. bool isLoopback() const;
  178. // @see IPAddress#isNonroutable
  179. bool isNonroutable() const {
  180. return !isRoutable();
  181. }
  182. /**
  183. * Return true if this address is routable.
  184. */
  185. bool isRoutable() const;
  186. // @see IPAddress#isPrivate
  187. bool isPrivate() const;
  188. /**
  189. * Return true if this is a link-local IPv6 address.
  190. *
  191. * Note that this only returns true for addresses in the fe80::/10 range.
  192. * It returns false for the loopback address (::1), even though this address
  193. * is also effectively has link-local scope. It also returns false for
  194. * link-scope and interface-scope multicast addresses.
  195. */
  196. bool isLinkLocal() const;
  197. /**
  198. * Return the mac address if this is a link-local IPv6 address.
  199. *
  200. * @return an Optional<MacAddress> union representing the mac address.
  201. *
  202. * If the address is not a link-local one it will return an empty Optional.
  203. * You can use Optional::value() to check whether the mac address is not null.
  204. */
  205. Optional<MacAddress> getMacAddressFromLinkLocal() const;
  206. /**
  207. * Return the mac address if this is an auto-configured IPv6 address based on
  208. * EUI-64
  209. *
  210. * @return an Optional<MacAddress> union representing the mac address.
  211. * If the address is not based on EUI-64 it will return an empty Optional.
  212. * You can use Optional::value() to check whether the mac address is not null.
  213. */
  214. Optional<MacAddress> getMacAddressFromEUI64() const;
  215. /**
  216. * Return true if this is a multicast address.
  217. */
  218. bool isMulticast() const;
  219. /**
  220. * Return the flags for a multicast address.
  221. * This method may only be called on multicast addresses.
  222. */
  223. uint8_t getMulticastFlags() const;
  224. /**
  225. * Return the scope for a multicast address.
  226. * This method may only be called on multicast addresses.
  227. */
  228. uint8_t getMulticastScope() const;
  229. // @see IPAddress#isZero
  230. bool isZero() const {
  231. constexpr auto zero = ByteArray16{{}};
  232. return 0 == std::memcmp(bytes(), zero.data(), zero.size());
  233. }
  234. bool isLinkLocalBroadcast() const;
  235. // @see IPAddress#mask
  236. IPAddressV6 mask(size_t numBits) const;
  237. // return underlying in6_addr structure
  238. in6_addr toAddr() const {
  239. return addr_.in6Addr_;
  240. }
  241. uint16_t getScopeId() const {
  242. return scope_;
  243. }
  244. void setScopeId(uint16_t scope) {
  245. scope_ = scope;
  246. }
  247. sockaddr_in6 toSockAddr() const {
  248. sockaddr_in6 addr;
  249. memset(&addr, 0, sizeof(sockaddr_in6));
  250. addr.sin6_family = AF_INET6;
  251. addr.sin6_scope_id = scope_;
  252. memcpy(&addr.sin6_addr, &addr_.in6Addr_, sizeof(in6_addr));
  253. return addr;
  254. }
  255. ByteArray16 toByteArray() const {
  256. ByteArray16 ba{{0}};
  257. std::memcpy(ba.data(), bytes(), 16);
  258. return ba;
  259. }
  260. // @see IPAddress#toFullyQualified
  261. std::string toFullyQualified() const;
  262. // @see IPAddress#toFullyQualifiedAppend
  263. void toFullyQualifiedAppend(std::string& out) const;
  264. std::string toInverseArpaName() const;
  265. // @see IPAddress#str
  266. std::string str() const;
  267. // @see IPAddress#version
  268. uint8_t version() const {
  269. return 6;
  270. }
  271. /**
  272. * Return the solicited-node multicast address for this address.
  273. */
  274. IPAddressV6 getSolicitedNodeAddress() const;
  275. /**
  276. * Return the mask associated with the given number of bits.
  277. * If for instance numBits was 24 (e.g. /24) then the V4 mask returned should
  278. * be {0xff, 0xff, 0xff, 0x00}.
  279. * @param [in] numBits bitmask to retrieve
  280. * @throws abort if numBits == 0 or numBits > bitCount()
  281. * @return mask associated with numBits
  282. */
  283. static const ByteArray16 fetchMask(size_t numBits);
  284. // Given 2 IPAddressV6,mask pairs extract the longest common IPAddress,
  285. // mask pair
  286. static CIDRNetworkV6 longestCommonPrefix(
  287. const CIDRNetworkV6& one,
  288. const CIDRNetworkV6& two);
  289. // Number of bytes in the address representation.
  290. static constexpr size_t byteCount() {
  291. return 16;
  292. }
  293. // get nth most significant bit - 0 indexed
  294. bool getNthMSBit(size_t bitIndex) const {
  295. return detail::getNthMSBitImpl(*this, bitIndex, AF_INET6);
  296. }
  297. // get nth most significant byte - 0 indexed
  298. uint8_t getNthMSByte(size_t byteIndex) const;
  299. // get nth bit - 0 indexed
  300. bool getNthLSBit(size_t bitIndex) const {
  301. return getNthMSBit(bitCount() - bitIndex - 1);
  302. }
  303. // get nth byte - 0 indexed
  304. uint8_t getNthLSByte(size_t byteIndex) const {
  305. return getNthMSByte(byteCount() - byteIndex - 1);
  306. }
  307. const unsigned char* bytes() const {
  308. return addr_.in6Addr_.s6_addr;
  309. }
  310. protected:
  311. /**
  312. * Helper that returns true if the address is in the binary subnet specified
  313. * by addr.
  314. */
  315. bool inBinarySubnet(const std::array<uint8_t, 2> addr, size_t numBits) const;
  316. private:
  317. auto tie() const {
  318. return std::tie(addr_.bytes_, scope_);
  319. }
  320. public:
  321. friend inline bool operator==(const IPAddressV6& a, const IPAddressV6& b) {
  322. return a.tie() == b.tie();
  323. }
  324. friend inline bool operator!=(const IPAddressV6& a, const IPAddressV6& b) {
  325. return a.tie() != b.tie();
  326. }
  327. friend inline bool operator<(const IPAddressV6& a, const IPAddressV6& b) {
  328. return a.tie() < b.tie();
  329. }
  330. friend inline bool operator>(const IPAddressV6& a, const IPAddressV6& b) {
  331. return a.tie() > b.tie();
  332. }
  333. friend inline bool operator<=(const IPAddressV6& a, const IPAddressV6& b) {
  334. return a.tie() <= b.tie();
  335. }
  336. friend inline bool operator>=(const IPAddressV6& a, const IPAddressV6& b) {
  337. return a.tie() >= b.tie();
  338. }
  339. private:
  340. union AddressStorage {
  341. in6_addr in6Addr_;
  342. ByteArray16 bytes_;
  343. AddressStorage() {
  344. std::memset(this, 0, sizeof(AddressStorage));
  345. }
  346. explicit AddressStorage(const ByteArray16& bytes) : bytes_(bytes) {}
  347. explicit AddressStorage(const in6_addr& addr) : in6Addr_(addr) {}
  348. explicit AddressStorage(MacAddress mac);
  349. } addr_;
  350. // Link-local scope id. This should always be 0 for IPAddresses that
  351. // are *not* link-local.
  352. uint16_t scope_{0};
  353. /**
  354. * Set the current IPAddressV6 object to have the address specified by bytes.
  355. * Returns IPAddressFormatError if bytes.size() is not 16.
  356. */
  357. Expected<Unit, IPAddressFormatError> trySetFromBinary(
  358. ByteRange bytes) noexcept;
  359. };
  360. // boost::hash uses hash_value() so this allows boost::hash to work
  361. // automatically for IPAddressV6
  362. std::size_t hash_value(const IPAddressV6& addr);
  363. std::ostream& operator<<(std::ostream& os, const IPAddressV6& addr);
  364. // Define toAppend() to allow IPAddressV6 to be used with to<string>
  365. void toAppend(IPAddressV6 addr, std::string* result);
  366. void toAppend(IPAddressV6 addr, fbstring* result);
  367. } // namespace folly
  368. namespace std {
  369. template <>
  370. struct hash<folly::IPAddressV6> {
  371. size_t operator()(const folly::IPAddressV6& addr) const {
  372. return addr.hash();
  373. }
  374. };
  375. } // namespace std