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