Add <new> header for placement new
[folly.git] / folly / IPAddressV6.h
1 /*
2  * Copyright 2016 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 <map>
22 #include <stdexcept>
23
24 #include <boost/operators.hpp>
25
26 #include <folly/Hash.h>
27 #include <folly/Range.h>
28 #include <folly/detail/IPAddress.h>
29
30 namespace folly {
31
32 class IPAddress;
33 class IPAddressV4;
34 class IPAddressV6;
35 class MacAddress;
36
37 /**
38  * Pair of IPAddressV6, netmask
39  */
40 typedef std::pair<IPAddressV6, uint8_t> CIDRNetworkV6;
41
42 /**
43  * Specialization for IPv6 addresses
44  */
45 typedef std::array<uint8_t, 16> ByteArray16;
46
47 /**
48  * IPv6 variation of IPAddress.
49  *
50  * Added methods: createIPv4, getIPv4For6To4, is6To4,
51  *                isTeredo, isIPv4Mapped, tryCreateIPv4, type
52  *
53  * @see IPAddress
54  *
55  * Notes on scope ID parsing:
56  *
57  * getaddrinfo() uses if_nametoindex() to convert interface names
58  * into a numerical index. For instance,
59  * "fe80::202:c9ff:fec1:ee08%eth0" may return scope ID 2 on some
60  * hosts, but other numbers on other hosts. It will fail entirely on
61  * hosts without an eth0 interface.
62  *
63  * Serializing / Deserializing IPAddressB6's on different hosts
64  * that use link-local scoping probably won't work.
65  */
66 class IPAddressV6 : boost::totally_ordered<IPAddressV6> {
67  public:
68   // V6 Address Type
69   enum Type {
70     TEREDO, T6TO4, NORMAL,
71   };
72   // A constructor parameter to indicate that we should create a link-local
73   // IPAddressV6.
74   enum LinkLocalTag {
75     LINK_LOCAL,
76   };
77   // Thrown when a type assertion fails
78   typedef std::runtime_error TypeError;
79
80   // Binary prefix for teredo networks
81   static const uint32_t PREFIX_TEREDO;
82   // Binary prefix for 6to4 networks
83   static const uint32_t PREFIX_6TO4;
84
85   // Size of std::string returned by toFullyQualified.
86   static constexpr size_t kToFullyQualifiedSize =
87     8 /*words*/ * 4 /*hex chars per word*/ + 7 /*separators*/;
88
89   static bool validate(StringPiece ip);
90
91   /**
92    * Create a new IPAddress instance from the provided binary data.
93    * @throws IPAddressFormatException if the input length is not 16 bytes.
94    */
95   static IPAddressV6 fromBinary(ByteRange bytes) {
96     IPAddressV6 addr;
97     addr.setFromBinary(bytes);
98     return addr;
99   }
100
101   /**
102    * Returns the address as a Range.
103    */
104   ByteRange toBinary() const {
105     return ByteRange((const unsigned char *) &addr_.in6Addr_.s6_addr, 16);
106   }
107
108   /**
109    * Default constructor for IPAddressV6.
110    *
111    * The address value will be ::0
112    */
113   IPAddressV6();
114
115   // Create an IPAddressV6 from a string
116   // @throws IPAddressFormatException
117   //
118   explicit IPAddressV6(StringPiece ip);
119
120   // ByteArray16 constructor
121   explicit IPAddressV6(const ByteArray16& src);
122
123   // in6_addr constructor
124   explicit IPAddressV6(const in6_addr& src);
125
126   // sockaddr_in6 constructor
127   explicit IPAddressV6(const sockaddr_in6& src);
128
129   /**
130    * Create a link-local IPAddressV6 from the specified ethernet MAC address.
131    */
132   IPAddressV6(LinkLocalTag tag, MacAddress mac);
133
134   // return the mapped V4 address
135   // @throws IPAddressFormatException if !isIPv4Mapped
136   IPAddressV4 createIPv4() const;
137
138   /**
139    * Return a V4 address if this is a 6To4 address.
140    * @throws TypeError if not a 6To4 address
141    */
142   IPAddressV4 getIPv4For6To4() const;
143
144   // Return true if a 6TO4 address
145   bool is6To4() const {
146     return type() == IPAddressV6::Type::T6TO4;
147   }
148
149   // Return true if a TEREDO address
150   bool isTeredo() const {
151     return type() == IPAddressV6::Type::TEREDO;
152   }
153
154   // return true if this is v4-to-v6-mapped
155   bool isIPv4Mapped() const;
156
157   // Return the V6 address type
158   Type type() const;
159
160   /**
161    * @see IPAddress#bitCount
162    * @returns 128
163    */
164   static size_t bitCount() { return 128; }
165
166   /**
167    * @see IPAddress#toJson
168    */
169   std::string toJson() const;
170
171   size_t hash() const;
172
173   // @see IPAddress#inSubnet
174   // @throws IPAddressFormatException if string doesn't contain a V6 address
175   bool inSubnet(StringPiece cidrNetwork) const;
176
177   // return true if address is in subnet
178   bool inSubnet(const IPAddressV6& subnet, uint8_t cidr) const {
179     return inSubnetWithMask(subnet, fetchMask(cidr));
180   }
181   bool inSubnetWithMask(const IPAddressV6& subnet,
182                         const ByteArray16& mask) const;
183
184   // @see IPAddress#isLoopback
185   bool isLoopback() const;
186
187   // @see IPAddress#isNonroutable
188   bool isNonroutable() const {
189     return !isRoutable();
190   }
191
192   /**
193    * Return true if this address is routable.
194    */
195   bool isRoutable() const;
196
197   // @see IPAddress#isPrivate
198   bool isPrivate() const;
199
200   /**
201    * Return true if this is a link-local IPv6 address.
202    *
203    * Note that this only returns true for addresses in the fe80::/10 range.
204    * It returns false for the loopback address (::1), even though this address
205    * is also effectively has link-local scope.  It also returns false for
206    * link-scope and interface-scope multicast addresses.
207    */
208   bool isLinkLocal() const;
209
210   /**
211    * Return true if this is a multicast address.
212    */
213   bool isMulticast() const;
214
215   /**
216    * Return the flags for a multicast address.
217    * This method may only be called on multicast addresses.
218    */
219   uint8_t getMulticastFlags() const;
220
221   /**
222    * Return the scope for a multicast address.
223    * This method may only be called on multicast addresses.
224    */
225   uint8_t getMulticastScope() const;
226
227   // @see IPAddress#isZero
228   bool isZero() const {
229     return detail::Bytes::isZero(bytes(), 16);
230   }
231
232   bool isLinkLocalBroadcast() const;
233
234   // @see IPAddress#mask
235   IPAddressV6 mask(size_t numBits) const;
236
237   // return underlying in6_addr structure
238   in6_addr toAddr() const { return addr_.in6Addr_; }
239
240   uint16_t getScopeId() const { return scope_; }
241   void setScopeId(uint16_t scope) {
242     scope_ = scope;
243   }
244
245   sockaddr_in6 toSockAddr() const {
246     sockaddr_in6 addr;
247     memset(&addr, 0, sizeof(sockaddr_in6));
248     addr.sin6_family = AF_INET6;
249     addr.sin6_scope_id = scope_;
250     memcpy(&addr.sin6_addr, &addr_.in6Addr_, sizeof(in6_addr));
251     return addr;
252   }
253
254   ByteArray16 toByteArray() const {
255     ByteArray16 ba{{0}};
256     std::memcpy(ba.data(), bytes(), 16);
257     return ba;
258   }
259
260   // @see IPAddress#toFullyQualified
261   std::string toFullyQualified() const;
262
263   // @see IPAddress#str
264   std::string str() const;
265
266   // @see IPAddress#version
267   size_t version() const { return 6; }
268
269   /**
270    * Return the solicited-node multicast address for this address.
271    */
272   IPAddressV6 getSolicitedNodeAddress() const;
273
274   /**
275    * Return the mask associated with the given number of bits.
276    * If for instance numBits was 24 (e.g. /24) then the V4 mask returned should
277    * be {0xff, 0xff, 0xff, 0x00}.
278    * @param [in] numBits bitmask to retrieve
279    * @throws abort if numBits == 0 or numBits > bitCount()
280    * @return mask associated with numBits
281    */
282   static const ByteArray16 fetchMask(size_t numBits);
283   // Given 2 IPAddressV6,mask pairs extract the longest common IPAddress,
284   // mask pair
285   static CIDRNetworkV6 longestCommonPrefix(const CIDRNetworkV6& one,
286                                            const CIDRNetworkV6& two) {
287     auto prefix = detail::Bytes::longestCommonPrefix(
288       one.first.addr_.bytes_, one.second,
289       two.first.addr_.bytes_, two.second);
290     return {IPAddressV6(prefix.first), prefix.second};
291   }
292   // Number of bytes in the address representation.
293   static constexpr size_t byteCount() { return 16; }
294
295   //get nth most significant bit - 0 indexed
296   bool getNthMSBit(size_t bitIndex) const {
297     return detail::getNthMSBitImpl(*this, bitIndex, AF_INET6);
298   }
299   //get nth most significant byte - 0 indexed
300   uint8_t getNthMSByte(size_t byteIndex) const;
301   //get nth bit - 0 indexed
302   bool getNthLSBit(size_t bitIndex) const {
303     return getNthMSBit(bitCount() - bitIndex - 1);
304   }
305   //get nth byte - 0 indexed
306   uint8_t getNthLSByte(size_t byteIndex) const {
307     return getNthMSByte(byteCount() - byteIndex - 1);
308   }
309
310   const unsigned char* bytes() const { return addr_.in6Addr_.s6_addr; }
311   protected:
312   /**
313    * Helper that returns true if the address is in the binary subnet specified
314    * by addr.
315    */
316   bool inBinarySubnet(const std::array<uint8_t, 2> addr,
317                       size_t numBits) const;
318
319  private:
320   union AddressStorage {
321     in6_addr in6Addr_;
322     ByteArray16 bytes_;
323     AddressStorage() {
324       std::memset(this, 0, sizeof(AddressStorage));
325     }
326     explicit AddressStorage(const ByteArray16& bytes): bytes_(bytes) {}
327     explicit AddressStorage(const in6_addr& addr): in6Addr_(addr) {}
328     explicit AddressStorage(MacAddress mac);
329   } addr_;
330
331   // Link-local scope id.  This should always be 0 for IPAddresses that
332   // are *not* link-local.
333   uint16_t scope_{0};
334
335   static const std::array<ByteArray16, 129> masks_;
336
337   /**
338    * Set the current IPAddressV6 object to have the address specified by bytes.
339    * @throws IPAddressFormatException if bytes.size() is not 16.
340    */
341   void setFromBinary(ByteRange bytes);
342 };
343
344 // boost::hash uses hash_value() so this allows boost::hash to work
345 // automatically for IPAddressV6
346 std::size_t hash_value(const IPAddressV6& addr);
347 std::ostream& operator<<(std::ostream& os, const IPAddressV6& addr);
348 // Define toAppend() to allow IPAddressV6 to be used with to<string>
349 void toAppend(IPAddressV6 addr, std::string* result);
350 void toAppend(IPAddressV6 addr, fbstring* result);
351
352 /**
353  * Return true if two addresses are equal.
354  */
355 inline bool operator==(const IPAddressV6& addr1, const IPAddressV6& addr2) {
356   return (std::memcmp(addr1.toAddr().s6_addr, addr2.toAddr().s6_addr, 16) == 0)
357     && addr1.getScopeId() == addr2.getScopeId();
358 }
359 // Return true if addr1 < addr2
360 inline bool operator<(const IPAddressV6& addr1, const IPAddressV6& addr2) {
361   auto cmp = std::memcmp(addr1.toAddr().s6_addr,
362                          addr2.toAddr().s6_addr, 16) < 0;
363   if (!cmp) {
364     return addr1.getScopeId() < addr2.getScopeId();
365   } else {
366     return cmp;
367   }
368 }
369
370 }  // folly
371
372 namespace std {
373 template<>
374 struct hash<folly::IPAddressV6> {
375   size_t operator()(const folly::IPAddressV6& addr) const {
376     return addr.hash();
377   }
378 };
379 }  // std