IPAddressV6.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536
  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. #include <folly/IPAddressV6.h>
  17. #include <ostream>
  18. #include <string>
  19. #include <folly/Format.h>
  20. #include <folly/IPAddress.h>
  21. #include <folly/IPAddressV4.h>
  22. #include <folly/MacAddress.h>
  23. #include <folly/detail/IPAddressSource.h>
  24. #if !_WIN32
  25. #include <net/if.h>
  26. #else
  27. // Because of the massive pain that is libnl, this can't go into the socket
  28. // portability header as you can't include <linux/if.h> and <net/if.h> in
  29. // the same translation unit without getting errors -_-...
  30. #include <iphlpapi.h> // @manual
  31. #include <ntddndis.h> // @manual
  32. // Alias the max size of an interface name to what posix expects.
  33. #define IFNAMSIZ IF_NAMESIZE
  34. #endif
  35. using std::ostream;
  36. using std::string;
  37. namespace folly {
  38. // public static const
  39. const uint32_t IPAddressV6::PREFIX_TEREDO = 0x20010000;
  40. const uint32_t IPAddressV6::PREFIX_6TO4 = 0x2002;
  41. // free functions
  42. size_t hash_value(const IPAddressV6& addr) {
  43. return addr.hash();
  44. }
  45. ostream& operator<<(ostream& os, const IPAddressV6& addr) {
  46. os << addr.str();
  47. return os;
  48. }
  49. void toAppend(IPAddressV6 addr, string* result) {
  50. result->append(addr.str());
  51. }
  52. void toAppend(IPAddressV6 addr, fbstring* result) {
  53. result->append(addr.str());
  54. }
  55. bool IPAddressV6::validate(StringPiece ip) noexcept {
  56. return tryFromString(ip).hasValue();
  57. }
  58. // public default constructor
  59. IPAddressV6::IPAddressV6() {}
  60. // public string constructor
  61. IPAddressV6::IPAddressV6(StringPiece addr) {
  62. auto maybeIp = tryFromString(addr);
  63. if (maybeIp.hasError()) {
  64. throw IPAddressFormatException(
  65. to<std::string>("Invalid IPv6 address '", addr, "'"));
  66. }
  67. *this = std::move(maybeIp.value());
  68. }
  69. Expected<IPAddressV6, IPAddressFormatError> IPAddressV6::tryFromString(
  70. StringPiece str) noexcept {
  71. auto ip = str.str();
  72. // Allow addresses surrounded in brackets
  73. if (ip.size() < 2) {
  74. return makeUnexpected(IPAddressFormatError::INVALID_IP);
  75. }
  76. if (ip.front() == '[' && ip.back() == ']') {
  77. ip = ip.substr(1, ip.size() - 2);
  78. }
  79. struct addrinfo* result;
  80. struct addrinfo hints;
  81. memset(&hints, 0, sizeof(hints));
  82. hints.ai_family = AF_INET6;
  83. hints.ai_socktype = SOCK_STREAM;
  84. hints.ai_flags = AI_NUMERICHOST;
  85. if (::getaddrinfo(ip.c_str(), nullptr, &hints, &result) == 0) {
  86. SCOPE_EXIT {
  87. ::freeaddrinfo(result);
  88. };
  89. const struct sockaddr_in6* sa =
  90. reinterpret_cast<struct sockaddr_in6*>(result->ai_addr);
  91. return IPAddressV6(*sa);
  92. }
  93. return makeUnexpected(IPAddressFormatError::INVALID_IP);
  94. }
  95. // in6_addr constructor
  96. IPAddressV6::IPAddressV6(const in6_addr& src) noexcept : addr_(src) {}
  97. // sockaddr_in6 constructor
  98. IPAddressV6::IPAddressV6(const sockaddr_in6& src) noexcept
  99. : addr_(src.sin6_addr), scope_(uint16_t(src.sin6_scope_id)) {}
  100. // ByteArray16 constructor
  101. IPAddressV6::IPAddressV6(const ByteArray16& src) noexcept : addr_(src) {}
  102. // link-local constructor
  103. IPAddressV6::IPAddressV6(LinkLocalTag, MacAddress mac) : addr_(mac) {}
  104. IPAddressV6::AddressStorage::AddressStorage(MacAddress mac) {
  105. // The link-local address uses modified EUI-64 format,
  106. // See RFC 4291 sections 2.5.1, 2.5.6, and Appendix A
  107. const auto* macBytes = mac.bytes();
  108. memcpy(&bytes_.front(), "\xfe\x80\x00\x00\x00\x00\x00\x00", 8);
  109. bytes_[8] = uint8_t(macBytes[0] ^ 0x02);
  110. bytes_[9] = macBytes[1];
  111. bytes_[10] = macBytes[2];
  112. bytes_[11] = 0xff;
  113. bytes_[12] = 0xfe;
  114. bytes_[13] = macBytes[3];
  115. bytes_[14] = macBytes[4];
  116. bytes_[15] = macBytes[5];
  117. }
  118. Optional<MacAddress> IPAddressV6::getMacAddressFromLinkLocal() const {
  119. // Returned MacAddress must be constructed from a link-local IPv6 address.
  120. if (!isLinkLocal()) {
  121. return folly::none;
  122. }
  123. return getMacAddressFromEUI64();
  124. }
  125. Optional<MacAddress> IPAddressV6::getMacAddressFromEUI64() const {
  126. if (!(addr_.bytes_[11] == 0xff && addr_.bytes_[12] == 0xfe)) {
  127. return folly::none;
  128. }
  129. // The auto configured address uses modified EUI-64 format,
  130. // See RFC 4291 sections 2.5.1, 2.5.6, and Appendix A
  131. std::array<uint8_t, MacAddress::SIZE> bytes;
  132. // Step 1: first 8 bytes are network prefix, and can be stripped
  133. // Step 2: invert the universal/local (U/L) flag (bit 7)
  134. bytes[0] = addr_.bytes_[8] ^ 0x02;
  135. // Step 3: copy these bytes as they are
  136. bytes[1] = addr_.bytes_[9];
  137. bytes[2] = addr_.bytes_[10];
  138. // Step 4: strip bytes (0xfffe), which are bytes_[11] and bytes_[12]
  139. // Step 5: copy the rest.
  140. bytes[3] = addr_.bytes_[13];
  141. bytes[4] = addr_.bytes_[14];
  142. bytes[5] = addr_.bytes_[15];
  143. return Optional<MacAddress>(MacAddress::fromBinary(range(bytes)));
  144. }
  145. IPAddressV6 IPAddressV6::fromBinary(ByteRange bytes) {
  146. auto maybeIp = tryFromBinary(bytes);
  147. if (maybeIp.hasError()) {
  148. throw IPAddressFormatException(to<std::string>(
  149. "Invalid IPv6 binary data: length must be 16 bytes, got ",
  150. bytes.size()));
  151. }
  152. return maybeIp.value();
  153. }
  154. Expected<IPAddressV6, IPAddressFormatError> IPAddressV6::tryFromBinary(
  155. ByteRange bytes) noexcept {
  156. IPAddressV6 addr;
  157. auto setResult = addr.trySetFromBinary(bytes);
  158. if (setResult.hasError()) {
  159. return makeUnexpected(std::move(setResult.error()));
  160. }
  161. return addr;
  162. }
  163. Expected<Unit, IPAddressFormatError> IPAddressV6::trySetFromBinary(
  164. ByteRange bytes) noexcept {
  165. if (bytes.size() != 16) {
  166. return makeUnexpected(IPAddressFormatError::INVALID_IP);
  167. }
  168. memcpy(&addr_.in6Addr_.s6_addr, bytes.data(), sizeof(in6_addr));
  169. scope_ = 0;
  170. return unit;
  171. }
  172. // static
  173. IPAddressV6 IPAddressV6::fromInverseArpaName(const std::string& arpaname) {
  174. auto piece = StringPiece(arpaname);
  175. if (!piece.removeSuffix(".ip6.arpa")) {
  176. throw IPAddressFormatException(sformat(
  177. "Invalid input. Should end with 'ip6.arpa'. Got '{}'", arpaname));
  178. }
  179. std::vector<StringPiece> pieces;
  180. split(".", piece, pieces);
  181. if (pieces.size() != 32) {
  182. throw IPAddressFormatException(sformat("Invalid input. Got '{}'", piece));
  183. }
  184. std::array<char, IPAddressV6::kToFullyQualifiedSize> ip;
  185. size_t pos = 0;
  186. int count = 0;
  187. for (size_t i = 1; i <= pieces.size(); i++) {
  188. ip[pos] = pieces[pieces.size() - i][0];
  189. pos++;
  190. count++;
  191. // add ':' every 4 chars
  192. if (count == 4 && pos < ip.size()) {
  193. ip[pos++] = ':';
  194. count = 0;
  195. }
  196. }
  197. return IPAddressV6(folly::range(ip));
  198. }
  199. // public
  200. IPAddressV4 IPAddressV6::createIPv4() const {
  201. if (!isIPv4Mapped()) {
  202. throw IPAddressFormatException("addr is not v4-to-v6-mapped");
  203. }
  204. const unsigned char* by = bytes();
  205. return IPAddressV4(detail::Bytes::mkAddress4(&by[12]));
  206. }
  207. // convert two uint8_t bytes into a uint16_t as hibyte.lobyte
  208. static inline uint16_t unpack(uint8_t lobyte, uint8_t hibyte) {
  209. return uint16_t((uint16_t(hibyte) << 8) | lobyte);
  210. }
  211. // given a src string, unpack count*2 bytes into dest
  212. // dest must have as much storage as count
  213. static inline void
  214. unpackInto(const unsigned char* src, uint16_t* dest, size_t count) {
  215. for (size_t i = 0, hi = 1, lo = 0; i < count; i++) {
  216. dest[i] = unpack(src[hi], src[lo]);
  217. hi += 2;
  218. lo += 2;
  219. }
  220. }
  221. // public
  222. IPAddressV4 IPAddressV6::getIPv4For6To4() const {
  223. if (!is6To4()) {
  224. throw IPAddressV6::TypeError(
  225. sformat("Invalid IP '{}': not a 6to4 address", str()));
  226. }
  227. // convert 16x8 bytes into first 4x16 bytes
  228. uint16_t ints[4] = {0, 0, 0, 0};
  229. unpackInto(bytes(), ints, 4);
  230. // repack into 4x8
  231. union {
  232. unsigned char bytes[4];
  233. in_addr addr;
  234. } ipv4;
  235. ipv4.bytes[0] = (uint8_t)((ints[1] & 0xFF00) >> 8);
  236. ipv4.bytes[1] = (uint8_t)(ints[1] & 0x00FF);
  237. ipv4.bytes[2] = (uint8_t)((ints[2] & 0xFF00) >> 8);
  238. ipv4.bytes[3] = (uint8_t)(ints[2] & 0x00FF);
  239. return IPAddressV4(ipv4.addr);
  240. }
  241. // public
  242. bool IPAddressV6::isIPv4Mapped() const {
  243. // v4 mapped addresses have their first 10 bytes set to 0, the next 2 bytes
  244. // set to 255 (0xff);
  245. const unsigned char* by = bytes();
  246. // check if first 10 bytes are 0
  247. for (int i = 0; i < 10; i++) {
  248. if (by[i] != 0x00) {
  249. return false;
  250. }
  251. }
  252. // check if bytes 11 and 12 are 255
  253. if (by[10] == 0xff && by[11] == 0xff) {
  254. return true;
  255. }
  256. return false;
  257. }
  258. // public
  259. IPAddressV6::Type IPAddressV6::type() const {
  260. // convert 16x8 bytes into first 2x16 bytes
  261. uint16_t ints[2] = {0, 0};
  262. unpackInto(bytes(), ints, 2);
  263. if ((((uint32_t)ints[0] << 16) | ints[1]) == IPAddressV6::PREFIX_TEREDO) {
  264. return Type::TEREDO;
  265. }
  266. if ((uint32_t)ints[0] == IPAddressV6::PREFIX_6TO4) {
  267. return Type::T6TO4;
  268. }
  269. return Type::NORMAL;
  270. }
  271. // public
  272. string IPAddressV6::toJson() const {
  273. return sformat("{{family:'AF_INET6', addr:'{}', hash:{}}}", str(), hash());
  274. }
  275. // public
  276. size_t IPAddressV6::hash() const {
  277. if (isIPv4Mapped()) {
  278. /* An IPAddress containing this object would be equal (i.e. operator==)
  279. to an IPAddress containing the corresponding IPv4.
  280. So we must make sure that the hash values are the same as well */
  281. return IPAddress::createIPv4(*this).hash();
  282. }
  283. static const uint64_t seed = AF_INET6;
  284. uint64_t hash1 = 0, hash2 = 0;
  285. hash::SpookyHashV2::Hash128(&addr_, 16, &hash1, &hash2);
  286. return hash::hash_combine(seed, hash1, hash2);
  287. }
  288. // public
  289. bool IPAddressV6::inSubnet(StringPiece cidrNetwork) const {
  290. auto subnetInfo = IPAddress::createNetwork(cidrNetwork);
  291. auto addr = subnetInfo.first;
  292. if (!addr.isV6()) {
  293. throw IPAddressFormatException(
  294. sformat("Address '{}' is not a V6 address", addr.toJson()));
  295. }
  296. return inSubnetWithMask(addr.asV6(), fetchMask(subnetInfo.second));
  297. }
  298. // public
  299. bool IPAddressV6::inSubnetWithMask(
  300. const IPAddressV6& subnet,
  301. const ByteArray16& cidrMask) const {
  302. const auto mask = detail::Bytes::mask(toByteArray(), cidrMask);
  303. const auto subMask = detail::Bytes::mask(subnet.toByteArray(), cidrMask);
  304. return (mask == subMask);
  305. }
  306. // public
  307. bool IPAddressV6::isLoopback() const {
  308. // Check if v4 mapped is loopback
  309. if (isIPv4Mapped() && createIPv4().isLoopback()) {
  310. return true;
  311. }
  312. auto socka = toSockAddr();
  313. return IN6_IS_ADDR_LOOPBACK(&socka.sin6_addr);
  314. }
  315. bool IPAddressV6::isRoutable() const {
  316. return
  317. // 2000::/3 is the only assigned global unicast block
  318. inBinarySubnet({{0x20, 0x00}}, 3) ||
  319. // ffxe::/16 are global scope multicast addresses,
  320. // which are eligible to be routed over the internet
  321. (isMulticast() && getMulticastScope() == 0xe);
  322. }
  323. bool IPAddressV6::isLinkLocalBroadcast() const {
  324. static const IPAddressV6 kLinkLocalBroadcast("ff02::1");
  325. return *this == kLinkLocalBroadcast;
  326. }
  327. // public
  328. bool IPAddressV6::isPrivate() const {
  329. // Check if mapped is private
  330. if (isIPv4Mapped() && createIPv4().isPrivate()) {
  331. return true;
  332. }
  333. return isLoopback() || inBinarySubnet({{0xfc, 0x00}}, 7);
  334. }
  335. // public
  336. bool IPAddressV6::isLinkLocal() const {
  337. return inBinarySubnet({{0xfe, 0x80}}, 10);
  338. }
  339. bool IPAddressV6::isMulticast() const {
  340. return addr_.bytes_[0] == 0xff;
  341. }
  342. uint8_t IPAddressV6::getMulticastFlags() const {
  343. DCHECK(isMulticast());
  344. return uint8_t((addr_.bytes_[1] >> 4) & 0xf);
  345. }
  346. uint8_t IPAddressV6::getMulticastScope() const {
  347. DCHECK(isMulticast());
  348. return uint8_t(addr_.bytes_[1] & 0xf);
  349. }
  350. IPAddressV6 IPAddressV6::getSolicitedNodeAddress() const {
  351. // Solicted node addresses must be constructed from unicast (or anycast)
  352. // addresses
  353. DCHECK(!isMulticast());
  354. uint8_t bytes[16] = {
  355. 0xff,
  356. 0x02,
  357. 0x00,
  358. 0x00,
  359. 0x00,
  360. 0x00,
  361. 0x00,
  362. 0x00,
  363. 0x00,
  364. 0x00,
  365. 0x00,
  366. 0x01,
  367. 0xff,
  368. addr_.bytes_[13],
  369. addr_.bytes_[14],
  370. addr_.bytes_[15],
  371. };
  372. return IPAddressV6::fromBinary(ByteRange(bytes, 16));
  373. }
  374. // public
  375. IPAddressV6 IPAddressV6::mask(size_t numBits) const {
  376. static const auto bits = bitCount();
  377. if (numBits > bits) {
  378. throw IPAddressFormatException(
  379. sformat("numBits({}) > bitCount({})", numBits, bits));
  380. }
  381. ByteArray16 ba = detail::Bytes::mask(fetchMask(numBits), addr_.bytes_);
  382. return IPAddressV6(ba);
  383. }
  384. // public
  385. string IPAddressV6::str() const {
  386. char buffer[INET6_ADDRSTRLEN + IFNAMSIZ + 1];
  387. if (!inet_ntop(AF_INET6, toAddr().s6_addr, buffer, INET6_ADDRSTRLEN)) {
  388. throw IPAddressFormatException(sformat(
  389. "Invalid address with hex '{}' with error {}",
  390. detail::Bytes::toHex(bytes(), 16),
  391. errnoStr(errno)));
  392. }
  393. auto scopeId = getScopeId();
  394. if (scopeId != 0) {
  395. auto len = strlen(buffer);
  396. buffer[len] = '%';
  397. auto errsv = errno;
  398. if (!if_indextoname(scopeId, buffer + len + 1)) {
  399. // if we can't map the if because eg. it no longer exists,
  400. // append the if index instead
  401. snprintf(buffer + len + 1, IFNAMSIZ, "%u", scopeId);
  402. }
  403. errno = errsv;
  404. }
  405. return string(buffer);
  406. }
  407. // public
  408. string IPAddressV6::toFullyQualified() const {
  409. return detail::fastIpv6ToString(addr_.in6Addr_);
  410. }
  411. // public
  412. void IPAddressV6::toFullyQualifiedAppend(std::string& out) const {
  413. detail::fastIpv6AppendToString(addr_.in6Addr_, out);
  414. }
  415. // public
  416. string IPAddressV6::toInverseArpaName() const {
  417. constexpr folly::StringPiece lut = "0123456789abcdef";
  418. std::array<char, 32> a;
  419. int j = 0;
  420. for (int i = 15; i >= 0; i--) {
  421. a[j] = (lut[bytes()[i] & 0xf]);
  422. a[j + 1] = (lut[bytes()[i] >> 4]);
  423. j += 2;
  424. }
  425. return sformat("{}.ip6.arpa", join(".", a));
  426. }
  427. // public
  428. uint8_t IPAddressV6::getNthMSByte(size_t byteIndex) const {
  429. const auto highestIndex = byteCount() - 1;
  430. if (byteIndex > highestIndex) {
  431. throw std::invalid_argument(sformat(
  432. "Byte index must be <= {} for addresses of type: {}",
  433. highestIndex,
  434. detail::familyNameStr(AF_INET6)));
  435. }
  436. return bytes()[byteIndex];
  437. }
  438. // protected
  439. const ByteArray16 IPAddressV6::fetchMask(size_t numBits) {
  440. static const size_t bits = bitCount();
  441. if (numBits > bits) {
  442. throw IPAddressFormatException("IPv6 addresses are 128 bits.");
  443. }
  444. if (numBits == 0) {
  445. return {{0}};
  446. }
  447. constexpr auto _0s = uint64_t(0);
  448. constexpr auto _1s = ~_0s;
  449. auto const fragment = Endian::big(_1s << ((128 - numBits) % 64));
  450. auto const hi = numBits <= 64 ? fragment : _1s;
  451. auto const lo = numBits <= 64 ? _0s : fragment;
  452. uint64_t const parts[] = {hi, lo};
  453. ByteArray16 arr;
  454. std::memcpy(arr.data(), parts, sizeof(parts));
  455. return arr;
  456. }
  457. // public static
  458. CIDRNetworkV6 IPAddressV6::longestCommonPrefix(
  459. const CIDRNetworkV6& one,
  460. const CIDRNetworkV6& two) {
  461. auto prefix = detail::Bytes::longestCommonPrefix(
  462. one.first.addr_.bytes_, one.second, two.first.addr_.bytes_, two.second);
  463. return {IPAddressV6(prefix.first), prefix.second};
  464. }
  465. // protected
  466. bool IPAddressV6::inBinarySubnet(
  467. const std::array<uint8_t, 2> addr,
  468. size_t numBits) const {
  469. auto masked = mask(numBits);
  470. return (std::memcmp(addr.data(), masked.bytes(), 2) == 0);
  471. }
  472. } // namespace folly