af55def4fa291ff0eff943190cf5b4e8e824065c
[folly.git] / folly / IPAddressV4.cpp
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 #include <folly/IPAddressV4.h>
18
19 #include <ostream>
20 #include <string>
21
22 #include <folly/Format.h>
23 #include <folly/IPAddress.h>
24 #include <folly/IPAddressV6.h>
25 #include <folly/detail/IPAddressSource.h>
26
27 using std::ostream;
28 using std::string;
29
30 namespace folly {
31
32 // free functions
33 size_t hash_value(const IPAddressV4& addr) {
34   return addr.hash();
35 }
36 ostream& operator<<(ostream& os, const IPAddressV4& addr) {
37   os << addr.str();
38   return os;
39 }
40 void toAppend(IPAddressV4 addr, string* result) {
41   result->append(addr.str());
42 }
43 void toAppend(IPAddressV4 addr, fbstring* result) {
44   result->append(addr.str());
45 }
46
47 bool IPAddressV4::validate(StringPiece ip) noexcept {
48   return tryFromString(ip).hasValue();
49 }
50
51 // public static
52 IPAddressV4 IPAddressV4::fromLong(uint32_t src) {
53   in_addr addr;
54   addr.s_addr = src;
55   return IPAddressV4(addr);
56 }
57
58 IPAddressV4 IPAddressV4::fromLongHBO(uint32_t src) {
59   in_addr addr;
60   addr.s_addr = htonl(src);
61   return IPAddressV4(addr);
62 }
63
64 // static public
65 uint32_t IPAddressV4::toLong(StringPiece ip) {
66   auto str = ip.str();
67   in_addr addr;
68   if (inet_pton(AF_INET, str.c_str(), &addr) != 1) {
69     throw IPAddressFormatException(
70         sformat("Can't convert invalid IP '{}' to long", ip));
71   }
72   return addr.s_addr;
73 }
74
75 // static public
76 uint32_t IPAddressV4::toLongHBO(StringPiece ip) {
77   return ntohl(IPAddressV4::toLong(ip));
78 }
79
80 // public default constructor
81 IPAddressV4::IPAddressV4() {}
82
83 // ByteArray4 constructor
84 IPAddressV4::IPAddressV4(const ByteArray4& src) noexcept : addr_(src) {}
85
86 // public string constructor
87 IPAddressV4::IPAddressV4(StringPiece addr) : addr_() {
88   auto maybeIp = tryFromString(addr);
89   if (maybeIp.hasError()) {
90     throw IPAddressFormatException(
91         to<std::string>("Invalid IPv4 address '", addr, "'"));
92   }
93   *this = std::move(maybeIp.value());
94 }
95
96 Expected<IPAddressV4, IPAddressFormatError> IPAddressV4::tryFromString(
97     StringPiece str) noexcept {
98   struct in_addr inAddr;
99   if (inet_pton(AF_INET, str.str().c_str(), &inAddr) != 1) {
100     return makeUnexpected(IPAddressFormatError::INVALID_IP);
101   }
102   return IPAddressV4(inAddr);
103 }
104
105 // in_addr constructor
106 IPAddressV4::IPAddressV4(const in_addr src) noexcept : addr_(src) {}
107
108 IPAddressV4 IPAddressV4::fromBinary(ByteRange bytes) {
109   auto maybeIp = tryFromBinary(bytes);
110   if (maybeIp.hasError()) {
111     throw IPAddressFormatException(to<std::string>(
112         "Invalid IPv4 binary data: length must be 4 bytes, got ",
113         bytes.size()));
114   }
115   return maybeIp.value();
116 }
117
118 Expected<IPAddressV4, IPAddressFormatError> IPAddressV4::tryFromBinary(
119     ByteRange bytes) noexcept {
120   IPAddressV4 addr;
121   auto setResult = addr.trySetFromBinary(bytes);
122   if (setResult.hasError()) {
123     return makeUnexpected(std::move(setResult.error()));
124   }
125   return addr;
126 }
127
128 Expected<Unit, IPAddressFormatError> IPAddressV4::trySetFromBinary(
129     ByteRange bytes) noexcept {
130   if (bytes.size() != 4) {
131     return makeUnexpected(IPAddressFormatError::INVALID_IP);
132   }
133   memcpy(&addr_.inAddr_.s_addr, bytes.data(), sizeof(in_addr));
134   return folly::unit;
135 }
136
137 // static
138 IPAddressV4 IPAddressV4::fromInverseArpaName(const std::string& arpaname) {
139   auto piece = StringPiece(arpaname);
140   // input must be something like 1.0.168.192.in-addr.arpa
141   if (!piece.removeSuffix(".in-addr.arpa")) {
142     throw IPAddressFormatException(
143         sformat("input does not end with '.in-addr.arpa': '{}'", arpaname));
144   }
145   std::vector<StringPiece> pieces;
146   split(".", piece, pieces);
147   if (pieces.size() != 4) {
148     throw IPAddressFormatException(sformat("Invalid input. Got {}", piece));
149   }
150   // reverse 1.0.168.192 -> 192.168.0.1
151   return IPAddressV4(join(".", pieces.rbegin(), pieces.rend()));
152 }
153 IPAddressV6 IPAddressV4::createIPv6() const {
154   ByteArray16 ba{};
155   ba[10] = 0xff;
156   ba[11] = 0xff;
157   std::memcpy(&ba[12], bytes(), 4);
158   return IPAddressV6(ba);
159 }
160
161 // public
162 IPAddressV6 IPAddressV4::getIPv6For6To4() const {
163   ByteArray16 ba{};
164   ba[0] = (uint8_t)((IPAddressV6::PREFIX_6TO4 & 0xFF00) >> 8);
165   ba[1] = (uint8_t)(IPAddressV6::PREFIX_6TO4 & 0x00FF);
166   std::memcpy(&ba[2], bytes(), 4);
167   return IPAddressV6(ba);
168 }
169
170 // public
171 string IPAddressV4::toJson() const {
172   return sformat("{{family:'AF_INET', addr:'{}', hash:{}}}", str(), hash());
173 }
174
175 // public
176 bool IPAddressV4::inSubnet(StringPiece cidrNetwork) const {
177   auto subnetInfo = IPAddress::createNetwork(cidrNetwork);
178   auto addr = subnetInfo.first;
179   if (!addr.isV4()) {
180     throw IPAddressFormatException(
181         sformat("Address '{}' is not a V4 address", addr.toJson()));
182   }
183   return inSubnetWithMask(addr.asV4(), fetchMask(subnetInfo.second));
184 }
185
186 // public
187 bool IPAddressV4::inSubnetWithMask(
188     const IPAddressV4& subnet,
189     const ByteArray4 cidrMask) const {
190   const auto mask = detail::Bytes::mask(toByteArray(), cidrMask);
191   const auto subMask = detail::Bytes::mask(subnet.toByteArray(), cidrMask);
192   return (mask == subMask);
193 }
194
195 // public
196 bool IPAddressV4::isLoopback() const {
197   static IPAddressV4 loopback_addr("127.0.0.0");
198   return inSubnetWithMask(loopback_addr, fetchMask(8));
199 }
200
201 // public
202 bool IPAddressV4::isLinkLocal() const {
203   static IPAddressV4 linklocal_addr("169.254.0.0");
204   return inSubnetWithMask(linklocal_addr, fetchMask(16));
205 }
206
207 // public
208 bool IPAddressV4::isNonroutable() const {
209   auto ip = toLongHBO();
210   return isPrivate() ||
211       (/* align */ true && ip <= 0x00FFFFFF) || // 0.0.0.0-0.255.255.255
212       (ip >= 0xC0000000 && ip <= 0xC00000FF) || // 192.0.0.0-192.0.0.255
213       (ip >= 0xC0000200 && ip <= 0xC00002FF) || // 192.0.2.0-192.0.2.255
214       (ip >= 0xC6120000 && ip <= 0xC613FFFF) || // 198.18.0.0-198.19.255.255
215       (ip >= 0xC6336400 && ip <= 0xC63364FF) || // 198.51.100.0-198.51.100.255
216       (ip >= 0xCB007100 && ip <= 0xCB0071FF) || // 203.0.113.0-203.0.113.255
217       (ip >= 0xE0000000 && ip <= 0xFFFFFFFF) || // 224.0.0.0-255.255.255.255
218       false;
219 }
220
221 // public
222 bool IPAddressV4::isPrivate() const {
223   auto ip = toLongHBO();
224   return // some ranges below
225       (ip >= 0x0A000000 && ip <= 0x0AFFFFFF) || // 10.0.0.0-10.255.255.255
226       (ip >= 0x7F000000 && ip <= 0x7FFFFFFF) || // 127.0.0.0-127.255.255.255
227       (ip >= 0xA9FE0000 && ip <= 0xA9FEFFFF) || // 169.254.0.0-169.254.255.255
228       (ip >= 0xAC100000 && ip <= 0xAC1FFFFF) || // 172.16.0.0-172.31.255.255
229       (ip >= 0xC0A80000 && ip <= 0xC0A8FFFF) || // 192.168.0.0-192.168.255.255
230       false;
231 }
232
233 // public
234 bool IPAddressV4::isMulticast() const {
235   return (toLongHBO() & 0xf0000000) == 0xe0000000;
236 }
237
238 // public
239 IPAddressV4 IPAddressV4::mask(size_t numBits) const {
240   static const auto bits = bitCount();
241   if (numBits > bits) {
242     throw IPAddressFormatException(
243         sformat("numBits({}) > bitsCount({})", numBits, bits));
244   }
245
246   ByteArray4 ba = detail::Bytes::mask(fetchMask(numBits), addr_.bytes_);
247   return IPAddressV4(ba);
248 }
249
250 // public
251 string IPAddressV4::str() const {
252   return detail::fastIpv4ToString(addr_.inAddr_);
253 }
254
255 // public
256 void IPAddressV4::toFullyQualifiedAppend(std::string& out) const {
257   detail::fastIpv4AppendToString(addr_.inAddr_, out);
258 }
259
260 // public
261 string IPAddressV4::toInverseArpaName() const {
262   return sformat(
263       "{}.{}.{}.{}.in-addr.arpa",
264       addr_.bytes_[3],
265       addr_.bytes_[2],
266       addr_.bytes_[1],
267       addr_.bytes_[0]);
268 }
269
270 // public
271 uint8_t IPAddressV4::getNthMSByte(size_t byteIndex) const {
272   const auto highestIndex = byteCount() - 1;
273   if (byteIndex > highestIndex) {
274     throw std::invalid_argument(sformat(
275         "Byte index must be <= {} for addresses of type: {}",
276         highestIndex,
277         detail::familyNameStr(AF_INET)));
278   }
279   return bytes()[byteIndex];
280 }
281 // protected
282 const ByteArray4 IPAddressV4::fetchMask(size_t numBits) {
283   static const size_t bits = bitCount();
284   if (numBits > bits) {
285     throw IPAddressFormatException("IPv4 addresses are 32 bits");
286   }
287   auto const val = Endian::big(uint32_t(~uint64_t(0) << (32 - numBits)));
288   ByteArray4 arr;
289   std::memcpy(arr.data(), &val, sizeof(val));
290   return arr;
291 }
292 // public static
293 CIDRNetworkV4 IPAddressV4::longestCommonPrefix(
294     const CIDRNetworkV4& one,
295     const CIDRNetworkV4& two) {
296   auto prefix = detail::Bytes::longestCommonPrefix(
297       one.first.addr_.bytes_, one.second, two.first.addr_.bytes_, two.second);
298   return {IPAddressV4(prefix.first), prefix.second};
299 }
300
301 } // namespace folly