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