add support for whenAll to waitWithSemaphore
[folly.git] / folly / IPAddress.h
1 /*
2  * Copyright 2014 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 <iostream>
21 #include <memory>
22 #include <string>
23 #include <utility> // std::pair
24
25 #include <boost/operators.hpp>
26
27 #include "folly/Format.h"
28 #include "folly/Range.h"
29 #include "folly/IPAddressException.h"
30 #include "folly/IPAddressV4.h"
31 #include "folly/IPAddressV6.h"
32 #include "folly/detail/IPAddress.h"
33
34 namespace folly {
35
36 class IPAddress;
37
38 /**
39  * Pair of IPAddress, netmask
40  */
41 typedef std::pair<IPAddress, uint8_t> CIDRNetwork;
42
43 /**
44  * Provides a unified interface for IP addresses.
45  *
46  * @note If you compare 2 IPAddress instances, v4-to-v6-mapped addresses are
47  * compared as V4 addresses.
48  *
49  * @note toLong/fromLong deal in network byte order, use toLongHBO/fromLongHBO
50  * if working in host byte order.
51  *
52  * Example usage:
53  * @code
54  *   IPAddress v4addr("192.0.2.129");
55  *   IPAddress v6map("::ffff:192.0.2.129");
56  *   CHECK(v4addr.inSubnet("192.0.2.0/24") ==
57  *         v4addr.inSubnet(IPAddress("192.0.2.0"), 24));
58  *   CHECK(v4addr.inSubnet("192.0.2.128/30"));
59  *   CHECK(!v4addr.inSubnet("192.0.2.128/32"));
60  *   CHECK(v4addr.asV4().toLong() == 2164392128);
61  *   CHECK(v4addr.asV4().toLongHBO() == 3221226113);
62  *   CHECK(v4addr.isV4());
63  *   CHECK(v6addr.isV6());
64  *   CHECK(v4addr == v6map);
65  *   CHECK(v6map.isIPv4Mapped());
66  *   CHECK(v4addr.asV4() == IPAddress::createIPv4(v6map));
67  *   CHECK(IPAddress::createIPv6(v4addr) == v6map.asV6());
68  * @encode
69  */
70 class IPAddress : boost::totally_ordered<IPAddress> {
71  public:
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     return network.first.str() + "/" + std::to_string(network.second);
102   }
103
104   /**
105    * Create a new IPAddress instance from the provided binary data
106    * in network byte order.
107    * @throws IPAddressFormatException if len is not 4 or 16
108    */
109   static IPAddress fromBinary(ByteRange bytes);
110
111   /**
112    * Create an IPAddress from a 32bit long (network byte order).
113    * @throws IPAddressFormatException
114    */
115   static IPAddress fromLong(uint32_t src);
116   // Same as above, but host byte order
117   static IPAddress fromLongHBO(uint32_t src);
118
119   // Given 2 IPAddress,mask pairs extract the longest common IPAddress,
120   // mask pair
121   static CIDRNetwork longestCommonPrefix(const CIDRNetwork& one,
122                                          const CIDRNetwork& two);
123
124   /**
125    * Constructs an uninitialized IPAddress.
126    */
127   IPAddress();
128
129   /**
130    * Parse an IPAddress from a string representation.
131    *
132    * Formats accepted are exactly the same as the ones accepted by inet_pton(),
133    * using AF_INET6 if the string contains colons, and AF_INET otherwise;
134    * with the exception that the whole address can optionally be enclosed
135    * in square brackets.
136    *
137    * @throws IPAddressFormatException
138    */
139   explicit IPAddress(StringPiece ip);
140
141   /**
142    * Create an IPAddress from a sockaddr.
143    * @throws IPAddressFormatException if nullptr or not AF_INET or AF_INET6
144    */
145   explicit IPAddress(const sockaddr* addr);
146
147   // Create an IPAddress from a V4 address
148   /* implicit */ IPAddress(const IPAddressV4 ipV4Addr);
149   /* implicit */ IPAddress(const in_addr addr);
150
151   // Create an IPAddress from a V6 address
152   /* implicit */ IPAddress(const IPAddressV6& ipV6Addr);
153   /* implicit */ IPAddress(const in6_addr& addr);
154
155   // Assign from V4 address
156   IPAddress& operator=(const IPAddressV4& ipV4Addr);
157
158   // Assign from V6 address
159   IPAddress& operator=(const IPAddressV6& ipV6Addr);
160
161   /**
162    * Converts an IPAddress to an IPAddressV4 instance.
163    * @note This is not some handy convenience wrapper to convert an IPv4 address
164    *       to a mapped IPv6 address. If you want that use
165    *       IPAddress::createIPv6(addr)
166    * @throws IPAddressFormatException is not a V4 instance
167    */
168   const IPAddressV4& asV4() const {
169     if (!isV4()) {
170       auto familyName = detail::familyNameStr(family());
171       throw InvalidAddressFamilyException("Can't convert address with family ",
172                                           familyName, " to AF_INET address");
173     }
174     return addr_.ipV4Addr;
175   }
176
177   /**
178    * Converts an IPAddress to an IPAddressV6 instance.
179    * @throws InvalidAddressFamilyException is not a V6 instance
180    */
181   const IPAddressV6& asV6() const {
182     if (!isV6()) {
183       auto familyName = detail::familyNameStr(family());
184       throw InvalidAddressFamilyException("Can't convert address with family ",
185                                           familyName, " to AF_INET6 address");
186     }
187     return addr_.ipV6Addr;
188   }
189
190   // Return sa_family_t of IPAddress
191   sa_family_t family() const { return family_; }
192
193   // Populate sockaddr_storage with an appropriate value
194   int toSockaddrStorage(sockaddr_storage *dest, uint16_t port = 0) const {
195     if (dest == nullptr) {
196       throw IPAddressFormatException("dest must not be null");
197     }
198     memset(dest, 0, sizeof(sockaddr_storage));
199     dest->ss_family = family();
200     if (isV4()) {
201       sockaddr_in *sin = reinterpret_cast<sockaddr_in*>(dest);
202       sin->sin_addr = asV4().toAddr();
203       sin->sin_port = port;
204       return sizeof(*sin);
205     } else if (isV6()) {
206       sockaddr_in6 *sin = reinterpret_cast<sockaddr_in6*>(dest);
207       sin->sin6_addr = asV6().toAddr();
208       sin->sin6_port = port;
209       return sizeof(*sin);
210     } else {
211       throw InvalidAddressFamilyException(family());
212     }
213   }
214
215   /**
216    * Check if the address is found in the specified CIDR netblock.
217    *
218    * This will return false if the specified cidrNet is V4, but the address is
219    * V6. It will also return false if the specified cidrNet is V6 but the
220    * address is V4. This method will do the right thing in the case of a v6
221    * mapped v4 address.
222    *
223    * @note This is slower than the below counterparts. If perf is important use
224    *       one of the two argument variations below.
225    * @param [in] ipSlashCidr address in "192.168.1.0/24" format
226    * @throws IPAddressFormatException if no /mask
227    * @return true if address is part of specified subnet with cidr
228    */
229   bool inSubnet(StringPiece ipSlashCidr) const;
230
231   /**
232    * Check if an IPAddress belongs to a subnet.
233    * @param [in] subnet Subnet to check against (e.g. 192.168.1.0)
234    * @param [in] cidr   CIDR for subnet (e.g. 24 for /24)
235    * @return true if address is part of specified subnet with cidr
236    */
237   bool inSubnet(const IPAddress& subnet, uint8_t cidr) const;
238
239   /**
240    * Check if an IPAddress belongs to the subnet with the given mask.
241    * This is the same as inSubnet but the mask is provided instead of looked up
242    * from the cidr.
243    * @param [in] subnet Subnet to check against
244    * @param [in] mask   The netmask for the subnet
245    * @return true if address is part of the specified subnet with mask
246    */
247   bool inSubnetWithMask(const IPAddress& subnet, ByteRange mask) const;
248
249   // @return true if address is a v4 mapped address
250   bool isIPv4Mapped() const {
251     return isV6() && asV6().isIPv4Mapped();
252   }
253
254   // @return true if this is an IPAddressV4 instance
255   bool isV4() const { return (family_ == AF_INET); }
256
257   // @return true if this is an IPAddressV6 instance
258   bool isV6() const { return (family_ == AF_INET6); }
259
260   // @return true if this address is all zeros
261   bool isZero() const {
262     return isV4() ? asV4().isZero()
263                   : asV6().isZero();
264   }
265
266   // Number of bits in the address representation.
267   size_t bitCount() const {
268     return isV4() ? IPAddressV4::bitCount()
269                   : IPAddressV6::bitCount();
270   }
271   // Number of bytes in the address representation.
272   size_t byteCount() const {
273     return bitCount() / 8;
274   }
275   //get nth most significant bit - 0 indexed
276   bool getNthMSBit(size_t bitIndex) const {
277     return detail::getNthMSBitImpl(*this, bitIndex, family());
278   }
279   //get nth most significant byte - 0 indexed
280   uint8_t getNthMSByte(size_t byteIndex) const;
281   //get nth bit - 0 indexed
282   bool getNthLSBit(size_t bitIndex) const {
283     return getNthMSBit(bitCount() - bitIndex - 1);
284   }
285   //get nth byte - 0 indexed
286   uint8_t getNthLSByte(size_t byteIndex) const {
287     return getNthMSByte(byteCount() - byteIndex - 1);
288   }
289   /**
290    * Get human-readable string representation of the address.
291    *
292    * This prints a string representation of the address, for human consumption
293    * or logging. The string will take the form of a JSON object that looks like:
294    * {family:'AF_INET|AF_INET6', addr:'address', hash:long}.
295    */
296   std::string toJson() const {
297     return isV4() ? asV4().toJson()
298                   : asV6().toJson();
299   }
300
301   // Hash of address
302   std::size_t hash() const {
303     return isV4() ? asV4().hash()
304                   : asV6().hash();
305   }
306
307   // Return true if the address qualifies as localhost.
308   bool isLoopback() const {
309     return isV4() ? asV4().isLoopback()
310                   : asV6().isLoopback();
311   }
312
313   // Return true if the address qualifies as broadcast.
314   bool isLinkLocalBroadcast() const {
315     return isV4() ? asV4().isLinkLocalBroadcast()
316                   : asV6().isLinkLocalBroadcast();
317   }
318
319   /**
320    * Return true if the address is a special purpose address, as per rfc6890
321    * (i.e. 0.0.0.0).
322    * For V6, true if the address is not in one of global scope blocks:
323    * 2000::/3, ffxe::/16.
324    */
325   bool isNonroutable() const {
326     return isV4() ? asV4().isNonroutable()
327                   : asV6().isNonroutable();
328   }
329
330   /**
331    * Return true if the address is private, as per rfc1918 and rfc4193
332    * (for example, 192.168.xxx.xxx or fc00::/7 addresses)
333    */
334   bool isPrivate() const {
335     return isV4() ? asV4().isPrivate()
336                   : asV6().isPrivate();
337   }
338
339   // Return true if the address is a multicast address.
340   bool isMulticast() const {
341     return isV4() ? asV4().isMulticast()
342                   : asV6().isMulticast();
343   }
344
345   /**
346    * Creates IPAddress instance with all but most significant numBits set to 0.
347    * @param [in] numBits number of bits to mask
348    * @throws abort if numBits > bitCount()
349    * @return IPAddress instance with bits set to 0
350    */
351   IPAddress mask(uint8_t numBits) const {
352     return isV4() ? IPAddress(std::move(asV4().mask(numBits)))
353                   : IPAddress(std::move(asV6().mask(numBits)));
354   }
355
356   /**
357    * Provides a string representation of address.
358    * @note The string representation is calculated on demand.
359    * @throws IPAddressFormatException on inet_ntop error
360    */
361   std::string str() const {
362     return isV4() ? asV4().str()
363                   : asV6().str();
364   }
365
366   /**
367    * Return the fully qualified string representation of the address.
368    * For V4 addresses this is the same as calling str(). For V6 addresses
369    * this is the hex representation with : characters inserted every 4 digits.
370    */
371   std::string toFullyQualified() const {
372     return isV4() ? asV4().toFullyQualified()
373                   : asV6().toFullyQualified();
374   }
375
376   // Address version (4 or 6)
377   uint8_t version() const {
378     return isV4() ? asV4().version()
379                   : asV6().version();
380   }
381
382   /**
383    * Access to address bytes, in network byte order.
384    */
385   const unsigned char* bytes() const {
386     return isV4() ? asV4().bytes() : asV6().bytes();
387   }
388
389  private:
390   typedef union IPAddressV46 {
391     IPAddressV4 ipV4Addr;
392     IPAddressV6 ipV6Addr;
393     // default constructor
394     IPAddressV46() {
395       std::memset(this, 0, sizeof(IPAddressV46));
396     }
397     explicit IPAddressV46(const IPAddressV4& addr): ipV4Addr(addr) {}
398     explicit IPAddressV46(const IPAddressV6& addr): ipV6Addr(addr) {}
399   } IPAddressV46;
400   IPAddressV46 addr_;
401   sa_family_t family_;
402 };
403
404 // boost::hash uses hash_value() so this allows boost::hash to work
405 // automatically for IPAddress
406 std::size_t hash_value(const IPAddress& addr);
407 std::ostream& operator<<(std::ostream& os, const IPAddress& addr);
408 // Define toAppend() to allow IPAddress to be used with folly::to<string>
409 void toAppend(IPAddress addr, std::string* result);
410 void toAppend(IPAddress addr, fbstring* result);
411
412 /**
413  * Return true if two addresses are equal.
414  *
415  * @note This takes into consideration V4 mapped addresses as well. If one
416  *       address is v4 mapped we compare the v4 addresses.
417  *
418  * @return true if the two addresses are equal.
419  */
420 bool operator==(const IPAddress& addr1, const IPAddress& addr2);
421 // Return true if addr1 < addr2
422 bool operator<(const IPAddress& addr1, const IPAddress& addr2);
423
424 }  // folly
425
426 namespace std {
427 template<>
428 struct hash<folly::IPAddress> {
429   size_t operator()(const folly::IPAddress& addr) const {
430     return addr.hash();
431   }
432 };
433 }  // std