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