proxygen
IPAddress.cpp
Go to the documentation of this file.
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/IPAddress.h>
17 
18 #include <limits>
19 #include <ostream>
20 #include <string>
21 #include <vector>
22 
23 #include <folly/Format.h>
24 #include <folly/String.h>
26 
27 using std::ostream;
28 using std::string;
29 using std::vector;
30 
31 namespace folly {
32 
33 // free functions
34 size_t hash_value(const IPAddress& addr) {
35  return addr.hash();
36 }
37 ostream& operator<<(ostream& os, const IPAddress& addr) {
38  os << addr.str();
39  return os;
40 }
41 void toAppend(IPAddress addr, string* result) {
42  result->append(addr.str());
43 }
44 void toAppend(IPAddress addr, fbstring* result) {
45  result->append(addr.str());
46 }
47 
48 bool IPAddress::validate(StringPiece ip) noexcept {
50 }
51 
52 // public static
53 IPAddressV4 IPAddress::createIPv4(const IPAddress& addr) {
54  if (addr.isV4()) {
55  return addr.asV4();
56  } else {
57  return addr.asV6().createIPv4();
58  }
59 }
60 
61 // public static
62 IPAddressV6 IPAddress::createIPv6(const IPAddress& addr) {
63  if (addr.isV6()) {
64  return addr.asV6();
65  } else {
66  return addr.asV4().createIPv6();
67  }
68 }
69 
70 namespace {
71 vector<string> splitIpSlashCidr(StringPiece ipSlashCidr) {
72  vector<string> vec;
73  split("/", ipSlashCidr, vec);
74  return vec;
75 }
76 } // namespace
77 
78 // public static
79 CIDRNetwork IPAddress::createNetwork(
80  StringPiece ipSlashCidr,
81  int defaultCidr, /* = -1 */
82  bool applyMask /* = true */) {
83  auto const ret =
84  IPAddress::tryCreateNetwork(ipSlashCidr, defaultCidr, applyMask);
85 
86  if (ret.hasValue()) {
87  return ret.value();
88  }
89 
90  if (ret.error() == CIDRNetworkError::INVALID_DEFAULT_CIDR) {
91  throw std::range_error("defaultCidr must be <= UINT8_MAX");
92  }
93 
94  if (ret.error() == CIDRNetworkError::INVALID_IP_SLASH_CIDR) {
96  "Invalid ipSlashCidr specified. Expected IP/CIDR format, got '{}'",
97  ipSlashCidr));
98  }
99 
100  // Handler the remaining error cases. We re-parse the ip/mask pair
101  // to make error messages more meaningful
102  auto const vec = splitIpSlashCidr(ipSlashCidr);
103 
104  switch (ret.error()) {
106  CHECK_GE(vec.size(), 1);
108  sformat("Invalid IP address {}", vec.at(0)));
110  CHECK_GE(vec.size(), 2);
111  throw IPAddressFormatException(
112  sformat("Mask value '{}' not a valid mask", vec.at(1)));
114  auto const subnet = IPAddress::tryFromString(vec.at(0)).value();
115  auto cidr = static_cast<uint8_t>(
116  (defaultCidr > -1) ? defaultCidr : (subnet.isV4() ? 32 : 128));
117 
118  throw IPAddressFormatException(sformat(
119  "CIDR value '{}' is > network bit count '{}'",
120  vec.size() == 2 ? vec.at(1) : to<string>(cidr),
121  subnet.bitCount()));
122  }
123  default:
124  // unreachable
125  break;
126  }
127 
128  CHECK(0);
129 
130  return CIDRNetwork{};
131 }
132 
133 // public static
134 Expected<CIDRNetwork, CIDRNetworkError> IPAddress::tryCreateNetwork(
135  StringPiece ipSlashCidr,
136  int defaultCidr,
137  bool applyMask) {
138  if (defaultCidr > std::numeric_limits<uint8_t>::max()) {
140  }
141 
142  auto const vec = splitIpSlashCidr(ipSlashCidr);
143  auto const elemCount = vec.size();
144 
145  if (elemCount == 0 || // weird invalid string
146  elemCount > 2) { // invalid string (IP/CIDR/extras)
148  }
149 
150  auto const subnet = IPAddress::tryFromString(vec.at(0));
151  if (subnet.hasError()) {
153  }
154 
155  auto cidr = static_cast<uint8_t>(
156  (defaultCidr > -1) ? defaultCidr : (subnet.value().isV4() ? 32 : 128));
157 
158  if (elemCount == 2) {
159  auto const maybeCidr = tryTo<uint8_t>(vec.at(1));
160  if (maybeCidr.hasError()) {
162  }
163  cidr = maybeCidr.value();
164  }
165 
166  if (cidr > subnet.value().bitCount()) {
168  }
169 
170  return std::make_pair(
171  applyMask ? subnet.value().mask(cidr) : subnet.value(), cidr);
172 }
173 
174 // public static
175 std::string IPAddress::networkToString(const CIDRNetwork& network) {
176  return sformat("{}/{}", network.first.str(), network.second);
177 }
178 
179 // public static
180 IPAddress IPAddress::fromBinary(ByteRange bytes) {
181  if (bytes.size() == 4) {
182  return IPAddress(IPAddressV4::fromBinary(bytes));
183  } else if (bytes.size() == 16) {
184  return IPAddress(IPAddressV6::fromBinary(bytes));
185  } else {
186  string hexval = detail::Bytes::toHex(bytes.data(), bytes.size());
188  sformat("Invalid address with hex value '{}'", hexval));
189  }
190 }
191 
192 Expected<IPAddress, IPAddressFormatError> IPAddress::tryFromBinary(
193  ByteRange bytes) noexcept {
194  // Check IPv6 first since it's our main protocol.
195  if (bytes.size() == 16) {
196  return IPAddressV6::tryFromBinary(bytes);
197  } else if (bytes.size() == 4) {
198  return IPAddressV4::tryFromBinary(bytes);
199  } else {
201  }
202 }
203 
204 // public static
205 IPAddress IPAddress::fromLong(uint32_t src) {
206  return IPAddress(IPAddressV4::fromLong(src));
207 }
208 IPAddress IPAddress::fromLongHBO(uint32_t src) {
209  return IPAddress(IPAddressV4::fromLongHBO(src));
210 }
211 
212 // default constructor
213 IPAddress::IPAddress() : addr_(), family_(AF_UNSPEC) {}
214 
215 // public string constructor
216 IPAddress::IPAddress(StringPiece str) : addr_(), family_(AF_UNSPEC) {
217  auto maybeIp = tryFromString(str);
218  if (maybeIp.hasError()) {
220  to<std::string>("Invalid IP address '", str, "'"));
221  }
222  *this = std::move(maybeIp.value());
223 }
224 
225 Expected<IPAddress, IPAddressFormatError> IPAddress::tryFromString(
226  StringPiece str) noexcept {
227  // need to check for V4 address second, since IPv4-mapped IPv6 addresses may
228  // contain a period
229  if (str.find(':') != string::npos) {
230  return IPAddressV6::tryFromString(str);
231  } else if (str.find('.') != string::npos) {
232  return IPAddressV4::tryFromString(str);
233  } else {
235  }
236 }
237 
238 // public sockaddr constructor
239 IPAddress::IPAddress(const sockaddr* addr) : addr_(), family_(AF_UNSPEC) {
240  if (addr == nullptr) {
241  throw IPAddressFormatException("sockaddr == nullptr");
242  }
243  family_ = addr->sa_family;
244  switch (addr->sa_family) {
245  case AF_INET: {
246  const sockaddr_in* v4addr = reinterpret_cast<const sockaddr_in*>(addr);
247  addr_.ipV4Addr = IPAddressV4(v4addr->sin_addr);
248  break;
249  }
250  case AF_INET6: {
251  const sockaddr_in6* v6addr = reinterpret_cast<const sockaddr_in6*>(addr);
252  addr_.ipV6Addr = IPAddressV6(*v6addr);
253  break;
254  }
255  default:
256  throw InvalidAddressFamilyException(addr->sa_family);
257  }
258 }
259 
260 // public ipv4 constructor
261 IPAddress::IPAddress(const IPAddressV4 ipV4Addr) noexcept
262  : addr_(ipV4Addr), family_(AF_INET) {}
263 
264 // public ipv4 constructor
265 IPAddress::IPAddress(const in_addr ipV4Addr) noexcept
266  : addr_(IPAddressV4(ipV4Addr)), family_(AF_INET) {}
267 
268 // public ipv6 constructor
269 IPAddress::IPAddress(const IPAddressV6& ipV6Addr) noexcept
270  : addr_(ipV6Addr), family_(AF_INET6) {}
271 
272 // public ipv6 constructor
273 IPAddress::IPAddress(const in6_addr& ipV6Addr) noexcept
274  : addr_(IPAddressV6(ipV6Addr)), family_(AF_INET6) {}
275 
276 // Assign from V4 address
277 IPAddress& IPAddress::operator=(const IPAddressV4& ipv4_addr) noexcept {
278  addr_ = IPAddressV46(ipv4_addr);
279  family_ = AF_INET;
280  return *this;
281 }
282 
283 // Assign from V6 address
284 IPAddress& IPAddress::operator=(const IPAddressV6& ipv6_addr) noexcept {
285  addr_ = IPAddressV46(ipv6_addr);
286  family_ = AF_INET6;
287  return *this;
288 }
289 
290 // public
291 bool IPAddress::inSubnet(StringPiece cidrNetwork) const {
292  auto subnetInfo = IPAddress::createNetwork(cidrNetwork);
293  return inSubnet(subnetInfo.first, subnetInfo.second);
294 }
295 
296 // public
297 bool IPAddress::inSubnet(const IPAddress& subnet, uint8_t cidr) const {
298  if (bitCount() == subnet.bitCount()) {
299  if (isV4()) {
300  return asV4().inSubnet(subnet.asV4(), cidr);
301  } else {
302  return asV6().inSubnet(subnet.asV6(), cidr);
303  }
304  }
305  // an IPv4 address can never belong in a IPv6 subnet unless the IPv6 is a 6to4
306  // address and vice-versa
307  if (isV6()) {
308  const IPAddressV6& v6addr = asV6();
309  const IPAddressV4& v4subnet = subnet.asV4();
310  if (v6addr.is6To4()) {
311  return v6addr.getIPv4For6To4().inSubnet(v4subnet, cidr);
312  }
313  } else if (subnet.isV6()) {
314  const IPAddressV6& v6subnet = subnet.asV6();
315  const IPAddressV4& v4addr = asV4();
316  if (v6subnet.is6To4()) {
317  return v4addr.inSubnet(v6subnet.getIPv4For6To4(), cidr);
318  }
319  }
320  return false;
321 }
322 
323 // public
324 bool IPAddress::inSubnetWithMask(const IPAddress& subnet, ByteRange mask)
325  const {
326  auto mkByteArray4 = [&]() -> ByteArray4 {
327  ByteArray4 ba{{0}};
328  std::memcpy(ba.data(), mask.begin(), std::min<size_t>(mask.size(), 4));
329  return ba;
330  };
331 
332  if (bitCount() == subnet.bitCount()) {
333  if (isV4()) {
334  return asV4().inSubnetWithMask(subnet.asV4(), mkByteArray4());
335  } else {
336  ByteArray16 ba{{0}};
337  std::memcpy(ba.data(), mask.begin(), std::min<size_t>(mask.size(), 16));
338  return asV6().inSubnetWithMask(subnet.asV6(), ba);
339  }
340  }
341 
342  // an IPv4 address can never belong in a IPv6 subnet unless the IPv6 is a 6to4
343  // address and vice-versa
344  if (isV6()) {
345  const IPAddressV6& v6addr = asV6();
346  const IPAddressV4& v4subnet = subnet.asV4();
347  if (v6addr.is6To4()) {
348  return v6addr.getIPv4For6To4().inSubnetWithMask(v4subnet, mkByteArray4());
349  }
350  } else if (subnet.isV6()) {
351  const IPAddressV6& v6subnet = subnet.asV6();
352  const IPAddressV4& v4addr = asV4();
353  if (v6subnet.is6To4()) {
354  return v4addr.inSubnetWithMask(v6subnet.getIPv4For6To4(), mkByteArray4());
355  }
356  }
357  return false;
358 }
359 
360 uint8_t IPAddress::getNthMSByte(size_t byteIndex) const {
361  const auto highestIndex = byteCount() - 1;
362  if (byteIndex > highestIndex) {
363  throw std::invalid_argument(sformat(
364  "Byte index must be <= {} for addresses of type: {}",
365  highestIndex,
366  detail::familyNameStr(family())));
367  }
368  if (isV4()) {
369  return asV4().bytes()[byteIndex];
370  }
371  return asV6().bytes()[byteIndex];
372 }
373 
374 // public
375 bool operator==(const IPAddress& addr1, const IPAddress& addr2) {
376  if (addr1.family() == addr2.family()) {
377  if (addr1.isV6()) {
378  return (addr1.asV6() == addr2.asV6());
379  } else if (addr1.isV4()) {
380  return (addr1.asV4() == addr2.asV4());
381  } else {
382  CHECK_EQ(addr1.family(), AF_UNSPEC);
383  // Two default initialized AF_UNSPEC addresses should be considered equal.
384  // AF_UNSPEC is the only other value for which an IPAddress can be
385  // created, in the default constructor case.
386  return true;
387  }
388  }
389  // addr1 is v4 mapped v6 address, addr2 is v4
390  if (addr1.isIPv4Mapped() && addr2.isV4()) {
391  if (IPAddress::createIPv4(addr1) == addr2.asV4()) {
392  return true;
393  }
394  }
395  // addr2 is v4 mapped v6 address, addr1 is v4
396  if (addr2.isIPv4Mapped() && addr1.isV4()) {
397  if (IPAddress::createIPv4(addr2) == addr1.asV4()) {
398  return true;
399  }
400  }
401  // we only compare IPv4 and IPv6 addresses
402  return false;
403 }
404 
405 bool operator<(const IPAddress& addr1, const IPAddress& addr2) {
406  if (addr1.family() == addr2.family()) {
407  if (addr1.isV6()) {
408  return (addr1.asV6() < addr2.asV6());
409  } else if (addr1.isV4()) {
410  return (addr1.asV4() < addr2.asV4());
411  } else {
412  CHECK_EQ(addr1.family(), AF_UNSPEC);
413  // Two default initialized AF_UNSPEC addresses can not be less than each
414  // other. AF_UNSPEC is the only other value for which an IPAddress can be
415  // created, in the default constructor case.
416  return false;
417  }
418  }
419  if (addr1.isV6()) {
420  // means addr2 is v4, convert it to a mapped v6 address and compare
421  return addr1.asV6() < addr2.asV4().createIPv6();
422  }
423  if (addr2.isV6()) {
424  // means addr2 is v6, convert addr1 to v4 mapped and compare
425  return addr1.asV4().createIPv6() < addr2.asV6();
426  }
427  return false;
428 }
429 
430 CIDRNetwork IPAddress::longestCommonPrefix(
431  const CIDRNetwork& one,
432  const CIDRNetwork& two) {
433  if (one.first.family() != two.first.family()) {
434  throw std::invalid_argument(sformat(
435  "Can't compute longest common prefix between addresses of different"
436  "families. Passed: {} and {}",
437  detail::familyNameStr(one.first.family()),
438  detail::familyNameStr(two.first.family())));
439  }
440  if (one.first.isV4()) {
442  {one.first.asV4(), one.second}, {two.first.asV4(), two.second});
443  return {IPAddress(prefix.first), prefix.second};
444  } else if (one.first.isV6()) {
446  {one.first.asV6(), one.second}, {two.first.asV6(), two.second});
447  return {IPAddress(prefix.first), prefix.second};
448  } else {
449  throw std::invalid_argument("Unknown address family");
450  }
451 }
452 
453 // clang-format off
454 [[noreturn]] void IPAddress::asV4Throw() const {
455  auto fam = detail::familyNameStr(family());
457  sformat("Can't convert address with family {} to AF_INET address", fam));
458 }
459 
460 [[noreturn]] void IPAddress::asV6Throw() const {
461  auto fam = detail::familyNameStr(family());
463  sformat("Can't convert address with family {} to AF_INET6 address", fam));
464 }
465 // clang-format on
466 
467 } // namespace folly
static CIDRNetworkV6 longestCommonPrefix(const CIDRNetworkV6 &one, const CIDRNetworkV6 &two)
static CIDRNetworkV4 longestCommonPrefix(const CIDRNetworkV4 &one, const CIDRNetworkV4 &two)
LogLevel max
Definition: LogLevel.cpp:31
std::string sformat(StringPiece fmt, Args &&...args)
Definition: Format.h:280
static IPAddressV6 fromBinary(ByteRange bytes)
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
size_type find(const_range_type str) const
Definition: Range.h:721
constexpr size_type size() const
Definition: Range.h:431
IPAddressV4 getIPv4For6To4() const
static IPAddressV4 fromBinary(ByteRange bytes)
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
requires E e noexcept(noexcept(s.error(std::move(e))))
bool prefix(Cursor &c, uint32_t expected)
static Expected< IPAddressV4, IPAddressFormatError > tryFromString(StringPiece str) noexcept
Definition: IPAddressV4.cpp:96
void split(const Delim &delimiter, const String &input, std::vector< OutputType > &out, bool ignoreEmpty)
Definition: String-inl.h:382
static Expected< IPAddressV4, IPAddressFormatError > tryFromBinary(ByteRange bytes) noexcept
bool inSubnetWithMask(const IPAddressV4 &subnet, const ByteArray4 mask) const
static Expected< IPAddressV6, IPAddressFormatError > tryFromBinary(ByteRange bytes) noexcept
static IPAddressV4 fromLong(uint32_t src)
Definition: IPAddressV4.cpp:52
constexpr Unexpected< typename std::decay< Error >::type > makeUnexpected(Error &&)
Definition: Expected.h:785
constexpr Iter data() const
Definition: Range.h:446
static bool validate(StringPiece ip) noexcept
Definition: IPAddressV6.cpp:65
static Expected< IPAddressV6, IPAddressFormatError > tryFromString(StringPiece str) noexcept
Definition: IPAddressV6.cpp:82
std::array< uint8_t, 16 > ByteArray16
Definition: IPAddressV6.h:50
size_t hash_value(const IPAddress &addr)
Definition: IPAddress.cpp:34
Definition: Traits.h:588
void toAppend(char value, Tgt *result)
Definition: Conv.h:406
constexpr Iter begin() const
Definition: Range.h:452
bool operator==(const Unexpected< Error > &lhs, const Unexpected< Error > &rhs)
Definition: Expected.h:758
const char * string
Definition: Conv.cpp:212
static IPAddressV4 fromLongHBO(uint32_t src)
Definition: IPAddressV4.cpp:58
uint64_t value(const typename LockFreeRingBuffer< T, Atom >::Cursor &rbcursor)
static bool validate(StringPiece ip) noexcept
Definition: IPAddressV4.cpp:47
vector< string > vec
Definition: StringTest.cpp:35
bool inSubnet(StringPiece cidrNetwork) const
basic_fbstring & append(const basic_fbstring &str)
Definition: FBString.h:1953
std::array< uint8_t, 4 > ByteArray4
Definition: IPAddressV4.h:46
static std::string toHex(const uint8_t *src, std::size_t len)
std::string familyNameStr(sa_family_t family)
Definition: IPAddress.h:30
ThreadPoolListHook * addr
bool is6To4() const
Definition: IPAddressV6.h:170
std::enable_if< IsLessThanComparable< Value >::value, bool >::type operator<(const Expected< Value, Error > &lhs, const Expected< Value, Error > &rhs)
Definition: Expected.h:1321
std::ostream & operator<<(std::ostream &out, dynamic const &d)
Definition: dynamic-inl.h:1158