1 | /* |
2 | * Copyright (c) Facebook, Inc. and its affiliates. |
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/IPAddress.h> |
18 | |
19 | #include <limits> |
20 | #include <ostream> |
21 | #include <string> |
22 | #include <vector> |
23 | |
24 | #include <folly/Format.h> |
25 | #include <folly/String.h> |
26 | #include <folly/detail/IPAddressSource.h> |
27 | |
28 | using std::ostream; |
29 | using std::string; |
30 | using std::vector; |
31 | |
32 | namespace folly { |
33 | |
34 | // free functions |
35 | size_t hash_value(const IPAddress& addr) { |
36 | return addr.hash(); |
37 | } |
38 | ostream& operator<<(ostream& os, const IPAddress& addr) { |
39 | os << addr.str(); |
40 | return os; |
41 | } |
42 | void toAppend(IPAddress addr, string* result) { |
43 | result->append(addr.str()); |
44 | } |
45 | void toAppend(IPAddress addr, fbstring* result) { |
46 | result->append(addr.str()); |
47 | } |
48 | |
49 | bool IPAddress::validate(StringPiece ip) noexcept { |
50 | return IPAddressV4::validate(ip) || IPAddressV6::validate(ip); |
51 | } |
52 | |
53 | // public static |
54 | IPAddressV4 IPAddress::createIPv4(const IPAddress& addr) { |
55 | if (addr.isV4()) { |
56 | return addr.asV4(); |
57 | } else { |
58 | return addr.asV6().createIPv4(); |
59 | } |
60 | } |
61 | |
62 | // public static |
63 | IPAddressV6 IPAddress::createIPv6(const IPAddress& addr) { |
64 | if (addr.isV6()) { |
65 | return addr.asV6(); |
66 | } else { |
67 | return addr.asV4().createIPv6(); |
68 | } |
69 | } |
70 | |
71 | namespace { |
72 | vector<string> splitIpSlashCidr(StringPiece ipSlashCidr) { |
73 | vector<string> vec; |
74 | split("/" , ipSlashCidr, vec); |
75 | return vec; |
76 | } |
77 | } // namespace |
78 | |
79 | // public static |
80 | CIDRNetwork IPAddress::createNetwork( |
81 | StringPiece ipSlashCidr, |
82 | int defaultCidr, /* = -1 */ |
83 | bool applyMask /* = true */) { |
84 | auto const ret = |
85 | IPAddress::tryCreateNetwork(ipSlashCidr, defaultCidr, applyMask); |
86 | |
87 | if (ret.hasValue()) { |
88 | return ret.value(); |
89 | } |
90 | |
91 | if (ret.error() == CIDRNetworkError::INVALID_DEFAULT_CIDR) { |
92 | throw std::range_error("defaultCidr must be <= UINT8_MAX" ); |
93 | } |
94 | |
95 | if (ret.error() == CIDRNetworkError::INVALID_IP_SLASH_CIDR) { |
96 | throw IPAddressFormatException(sformat( |
97 | "Invalid ipSlashCidr specified. Expected IP/CIDR format, got '{}'" , |
98 | ipSlashCidr)); |
99 | } |
100 | |
101 | // Handler the remaining error cases. We re-parse the ip/mask pair |
102 | // to make error messages more meaningful |
103 | auto const vec = splitIpSlashCidr(ipSlashCidr); |
104 | |
105 | switch (ret.error()) { |
106 | case CIDRNetworkError::INVALID_IP: |
107 | CHECK_GE(vec.size(), 1); |
108 | throw IPAddressFormatException( |
109 | sformat("Invalid IP address {}" , vec.at(0))); |
110 | case CIDRNetworkError::INVALID_CIDR: |
111 | CHECK_GE(vec.size(), 2); |
112 | throw IPAddressFormatException( |
113 | sformat("Mask value '{}' not a valid mask" , vec.at(1))); |
114 | case CIDRNetworkError::CIDR_MISMATCH: { |
115 | auto const subnet = IPAddress::tryFromString(vec.at(0)).value(); |
116 | auto cidr = static_cast<uint8_t>( |
117 | (defaultCidr > -1) ? defaultCidr : (subnet.isV4() ? 32 : 128)); |
118 | |
119 | throw IPAddressFormatException(sformat( |
120 | "CIDR value '{}' is > network bit count '{}'" , |
121 | vec.size() == 2 ? vec.at(1) : to<string>(cidr), |
122 | subnet.bitCount())); |
123 | } |
124 | case CIDRNetworkError::INVALID_DEFAULT_CIDR: |
125 | case CIDRNetworkError::INVALID_IP_SLASH_CIDR: |
126 | default: |
127 | // unreachable |
128 | break; |
129 | } |
130 | |
131 | CHECK(0); |
132 | |
133 | return CIDRNetwork{}; |
134 | } |
135 | |
136 | // public static |
137 | Expected<CIDRNetwork, CIDRNetworkError> IPAddress::tryCreateNetwork( |
138 | StringPiece ipSlashCidr, |
139 | int defaultCidr, |
140 | bool applyMask) { |
141 | if (defaultCidr > std::numeric_limits<uint8_t>::max()) { |
142 | return makeUnexpected(CIDRNetworkError::INVALID_DEFAULT_CIDR); |
143 | } |
144 | |
145 | auto const vec = splitIpSlashCidr(ipSlashCidr); |
146 | auto const elemCount = vec.size(); |
147 | |
148 | if (elemCount == 0 || // weird invalid string |
149 | elemCount > 2) { // invalid string (IP/CIDR/extras) |
150 | return makeUnexpected(CIDRNetworkError::INVALID_IP_SLASH_CIDR); |
151 | } |
152 | |
153 | auto const subnet = IPAddress::tryFromString(vec.at(0)); |
154 | if (subnet.hasError()) { |
155 | return makeUnexpected(CIDRNetworkError::INVALID_IP); |
156 | } |
157 | |
158 | auto cidr = static_cast<uint8_t>( |
159 | (defaultCidr > -1) ? defaultCidr : (subnet.value().isV4() ? 32 : 128)); |
160 | |
161 | if (elemCount == 2) { |
162 | auto const maybeCidr = tryTo<uint8_t>(vec.at(1)); |
163 | if (maybeCidr.hasError()) { |
164 | return makeUnexpected(CIDRNetworkError::INVALID_CIDR); |
165 | } |
166 | cidr = maybeCidr.value(); |
167 | } |
168 | |
169 | if (cidr > subnet.value().bitCount()) { |
170 | return makeUnexpected(CIDRNetworkError::CIDR_MISMATCH); |
171 | } |
172 | |
173 | return std::make_pair( |
174 | applyMask ? subnet.value().mask(cidr) : subnet.value(), cidr); |
175 | } |
176 | |
177 | // public static |
178 | std::string IPAddress::networkToString(const CIDRNetwork& network) { |
179 | return sformat("{}/{}" , network.first.str(), network.second); |
180 | } |
181 | |
182 | // public static |
183 | IPAddress IPAddress::fromBinary(ByteRange bytes) { |
184 | if (bytes.size() == 4) { |
185 | return IPAddress(IPAddressV4::fromBinary(bytes)); |
186 | } else if (bytes.size() == 16) { |
187 | return IPAddress(IPAddressV6::fromBinary(bytes)); |
188 | } else { |
189 | string hexval = detail::Bytes::toHex(bytes.data(), bytes.size()); |
190 | throw IPAddressFormatException( |
191 | sformat("Invalid address with hex value '{}'" , hexval)); |
192 | } |
193 | } |
194 | |
195 | Expected<IPAddress, IPAddressFormatError> IPAddress::tryFromBinary( |
196 | ByteRange bytes) noexcept { |
197 | // Check IPv6 first since it's our main protocol. |
198 | if (bytes.size() == 16) { |
199 | return IPAddressV6::tryFromBinary(bytes); |
200 | } else if (bytes.size() == 4) { |
201 | return IPAddressV4::tryFromBinary(bytes); |
202 | } else { |
203 | return makeUnexpected(IPAddressFormatError::UNSUPPORTED_ADDR_FAMILY); |
204 | } |
205 | } |
206 | |
207 | // public static |
208 | IPAddress IPAddress::fromLong(uint32_t src) { |
209 | return IPAddress(IPAddressV4::fromLong(src)); |
210 | } |
211 | IPAddress IPAddress::fromLongHBO(uint32_t src) { |
212 | return IPAddress(IPAddressV4::fromLongHBO(src)); |
213 | } |
214 | |
215 | // default constructor |
216 | IPAddress::IPAddress() : addr_(), family_(AF_UNSPEC) {} |
217 | |
218 | // public string constructor |
219 | IPAddress::IPAddress(StringPiece str) : addr_(), family_(AF_UNSPEC) { |
220 | auto maybeIp = tryFromString(str); |
221 | if (maybeIp.hasError()) { |
222 | throw IPAddressFormatException( |
223 | to<std::string>("Invalid IP address '" , str, "'" )); |
224 | } |
225 | *this = std::move(maybeIp.value()); |
226 | } |
227 | |
228 | Expected<IPAddress, IPAddressFormatError> IPAddress::tryFromString( |
229 | StringPiece str) noexcept { |
230 | // need to check for V4 address second, since IPv4-mapped IPv6 addresses may |
231 | // contain a period |
232 | if (str.find(':') != string::npos) { |
233 | return IPAddressV6::tryFromString(str); |
234 | } else if (str.find('.') != string::npos) { |
235 | return IPAddressV4::tryFromString(str); |
236 | } else { |
237 | return makeUnexpected(IPAddressFormatError::UNSUPPORTED_ADDR_FAMILY); |
238 | } |
239 | } |
240 | |
241 | // public sockaddr constructor |
242 | IPAddress::IPAddress(const sockaddr* addr) : addr_(), family_(AF_UNSPEC) { |
243 | if (addr == nullptr) { |
244 | throw IPAddressFormatException("sockaddr == nullptr" ); |
245 | } |
246 | family_ = addr->sa_family; |
247 | switch (addr->sa_family) { |
248 | case AF_INET: { |
249 | auto v4addr = reinterpret_cast<const sockaddr_in*>(addr); |
250 | addr_.ipV4Addr = IPAddressV4(v4addr->sin_addr); |
251 | break; |
252 | } |
253 | case AF_INET6: { |
254 | auto v6addr = reinterpret_cast<const sockaddr_in6*>(addr); |
255 | addr_.ipV6Addr = IPAddressV6(*v6addr); |
256 | break; |
257 | } |
258 | default: |
259 | throw InvalidAddressFamilyException(addr->sa_family); |
260 | } |
261 | } |
262 | |
263 | // public ipv4 constructor |
264 | IPAddress::IPAddress(const IPAddressV4 ipV4Addr) noexcept |
265 | : addr_(ipV4Addr), family_(AF_INET) {} |
266 | |
267 | // public ipv4 constructor |
268 | IPAddress::IPAddress(const in_addr ipV4Addr) noexcept |
269 | : addr_(IPAddressV4(ipV4Addr)), family_(AF_INET) {} |
270 | |
271 | // public ipv6 constructor |
272 | IPAddress::IPAddress(const IPAddressV6& ipV6Addr) noexcept |
273 | : addr_(ipV6Addr), family_(AF_INET6) {} |
274 | |
275 | // public ipv6 constructor |
276 | IPAddress::IPAddress(const in6_addr& ipV6Addr) noexcept |
277 | : addr_(IPAddressV6(ipV6Addr)), family_(AF_INET6) {} |
278 | |
279 | // Assign from V4 address |
280 | IPAddress& IPAddress::operator=(const IPAddressV4& ipv4_addr) noexcept { |
281 | addr_ = IPAddressV46(ipv4_addr); |
282 | family_ = AF_INET; |
283 | return *this; |
284 | } |
285 | |
286 | // Assign from V6 address |
287 | IPAddress& IPAddress::operator=(const IPAddressV6& ipv6_addr) noexcept { |
288 | addr_ = IPAddressV46(ipv6_addr); |
289 | family_ = AF_INET6; |
290 | return *this; |
291 | } |
292 | |
293 | // public |
294 | bool IPAddress::inSubnet(StringPiece cidrNetwork) const { |
295 | auto subnetInfo = IPAddress::createNetwork(cidrNetwork); |
296 | return inSubnet(subnetInfo.first, subnetInfo.second); |
297 | } |
298 | |
299 | // public |
300 | bool IPAddress::inSubnet(const IPAddress& subnet, uint8_t cidr) const { |
301 | if (bitCount() == subnet.bitCount()) { |
302 | if (isV4()) { |
303 | return asV4().inSubnet(subnet.asV4(), cidr); |
304 | } else { |
305 | return asV6().inSubnet(subnet.asV6(), cidr); |
306 | } |
307 | } |
308 | // an IPv4 address can never belong in a IPv6 subnet unless the IPv6 is a 6to4 |
309 | // address and vice-versa |
310 | if (isV6()) { |
311 | const IPAddressV6& v6addr = asV6(); |
312 | const IPAddressV4& v4subnet = subnet.asV4(); |
313 | if (v6addr.is6To4()) { |
314 | return v6addr.getIPv4For6To4().inSubnet(v4subnet, cidr); |
315 | } |
316 | } else if (subnet.isV6()) { |
317 | const IPAddressV6& v6subnet = subnet.asV6(); |
318 | const IPAddressV4& v4addr = asV4(); |
319 | if (v6subnet.is6To4()) { |
320 | return v4addr.inSubnet(v6subnet.getIPv4For6To4(), cidr); |
321 | } |
322 | } |
323 | return false; |
324 | } |
325 | |
326 | // public |
327 | bool IPAddress::inSubnetWithMask(const IPAddress& subnet, ByteRange mask) |
328 | const { |
329 | auto mkByteArray4 = [&]() -> ByteArray4 { |
330 | ByteArray4 ba{{0}}; |
331 | std::memcpy(ba.data(), mask.begin(), std::min<size_t>(mask.size(), 4)); |
332 | return ba; |
333 | }; |
334 | |
335 | if (bitCount() == subnet.bitCount()) { |
336 | if (isV4()) { |
337 | return asV4().inSubnetWithMask(subnet.asV4(), mkByteArray4()); |
338 | } else { |
339 | ByteArray16 ba{{0}}; |
340 | std::memcpy(ba.data(), mask.begin(), std::min<size_t>(mask.size(), 16)); |
341 | return asV6().inSubnetWithMask(subnet.asV6(), ba); |
342 | } |
343 | } |
344 | |
345 | // an IPv4 address can never belong in a IPv6 subnet unless the IPv6 is a 6to4 |
346 | // address and vice-versa |
347 | if (isV6()) { |
348 | const IPAddressV6& v6addr = asV6(); |
349 | const IPAddressV4& v4subnet = subnet.asV4(); |
350 | if (v6addr.is6To4()) { |
351 | return v6addr.getIPv4For6To4().inSubnetWithMask(v4subnet, mkByteArray4()); |
352 | } |
353 | } else if (subnet.isV6()) { |
354 | const IPAddressV6& v6subnet = subnet.asV6(); |
355 | const IPAddressV4& v4addr = asV4(); |
356 | if (v6subnet.is6To4()) { |
357 | return v4addr.inSubnetWithMask(v6subnet.getIPv4For6To4(), mkByteArray4()); |
358 | } |
359 | } |
360 | return false; |
361 | } |
362 | |
363 | uint8_t IPAddress::getNthMSByte(size_t byteIndex) const { |
364 | const auto highestIndex = byteCount() - 1; |
365 | if (byteIndex > highestIndex) { |
366 | throw std::invalid_argument(sformat( |
367 | "Byte index must be <= {} for addresses of type: {}" , |
368 | highestIndex, |
369 | detail::familyNameStr(family()))); |
370 | } |
371 | if (isV4()) { |
372 | return asV4().bytes()[byteIndex]; |
373 | } |
374 | return asV6().bytes()[byteIndex]; |
375 | } |
376 | |
377 | // public |
378 | bool operator==(const IPAddress& addr1, const IPAddress& addr2) { |
379 | if (addr1.empty() || addr2.empty()) { |
380 | return addr1.empty() == addr2.empty(); |
381 | } |
382 | if (addr1.family() == addr2.family()) { |
383 | if (addr1.isV6()) { |
384 | return (addr1.asV6() == addr2.asV6()); |
385 | } else if (addr1.isV4()) { |
386 | return (addr1.asV4() == addr2.asV4()); |
387 | } else { |
388 | CHECK_EQ(addr1.family(), AF_UNSPEC); |
389 | // Two default initialized AF_UNSPEC addresses should be considered equal. |
390 | // AF_UNSPEC is the only other value for which an IPAddress can be |
391 | // created, in the default constructor case. |
392 | return true; |
393 | } |
394 | } |
395 | // addr1 is v4 mapped v6 address, addr2 is v4 |
396 | if (addr1.isIPv4Mapped() && addr2.isV4()) { |
397 | if (IPAddress::createIPv4(addr1) == addr2.asV4()) { |
398 | return true; |
399 | } |
400 | } |
401 | // addr2 is v4 mapped v6 address, addr1 is v4 |
402 | if (addr2.isIPv4Mapped() && addr1.isV4()) { |
403 | if (IPAddress::createIPv4(addr2) == addr1.asV4()) { |
404 | return true; |
405 | } |
406 | } |
407 | // we only compare IPv4 and IPv6 addresses |
408 | return false; |
409 | } |
410 | |
411 | bool operator<(const IPAddress& addr1, const IPAddress& addr2) { |
412 | if (addr1.empty() || addr2.empty()) { |
413 | return addr1.empty() < addr2.empty(); |
414 | } |
415 | if (addr1.family() == addr2.family()) { |
416 | if (addr1.isV6()) { |
417 | return (addr1.asV6() < addr2.asV6()); |
418 | } else if (addr1.isV4()) { |
419 | return (addr1.asV4() < addr2.asV4()); |
420 | } else { |
421 | CHECK_EQ(addr1.family(), AF_UNSPEC); |
422 | // Two default initialized AF_UNSPEC addresses can not be less than each |
423 | // other. AF_UNSPEC is the only other value for which an IPAddress can be |
424 | // created, in the default constructor case. |
425 | return false; |
426 | } |
427 | } |
428 | if (addr1.isV6()) { |
429 | // means addr2 is v4, convert it to a mapped v6 address and compare |
430 | return addr1.asV6() < addr2.asV4().createIPv6(); |
431 | } |
432 | if (addr2.isV6()) { |
433 | // means addr2 is v6, convert addr1 to v4 mapped and compare |
434 | return addr1.asV4().createIPv6() < addr2.asV6(); |
435 | } |
436 | return false; |
437 | } |
438 | |
439 | CIDRNetwork IPAddress::longestCommonPrefix( |
440 | const CIDRNetwork& one, |
441 | const CIDRNetwork& two) { |
442 | if (one.first.family() != two.first.family()) { |
443 | throw std::invalid_argument(sformat( |
444 | "Can't compute longest common prefix between addresses of different" |
445 | "families. Passed: {} and {}" , |
446 | detail::familyNameStr(one.first.family()), |
447 | detail::familyNameStr(two.first.family()))); |
448 | } |
449 | if (one.first.isV4()) { |
450 | auto prefix = IPAddressV4::longestCommonPrefix( |
451 | {one.first.asV4(), one.second}, {two.first.asV4(), two.second}); |
452 | return {IPAddress(prefix.first), prefix.second}; |
453 | } else if (one.first.isV6()) { |
454 | auto prefix = IPAddressV6::longestCommonPrefix( |
455 | {one.first.asV6(), one.second}, {two.first.asV6(), two.second}); |
456 | return {IPAddress(prefix.first), prefix.second}; |
457 | } else { |
458 | throw std::invalid_argument("Unknown address family" ); |
459 | } |
460 | } |
461 | |
462 | // clang-format off |
463 | [[noreturn]] void IPAddress::asV4Throw() const { |
464 | auto fam = detail::familyNameStr(family()); |
465 | throw InvalidAddressFamilyException( |
466 | sformat("Can't convert address with family {} to AF_INET address" , fam)); |
467 | } |
468 | |
469 | [[noreturn]] void IPAddress::asV6Throw() const { |
470 | auto fam = detail::familyNameStr(family()); |
471 | throw InvalidAddressFamilyException( |
472 | sformat("Can't convert address with family {} to AF_INET6 address" , fam)); |
473 | } |
474 | // clang-format on |
475 | |
476 | } // namespace folly |
477 | |