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
17#pragma once
18
19#include <cstring>
20
21#include <array>
22#include <functional>
23#include <iosfwd>
24
25#include <folly/Expected.h>
26#include <folly/FBString.h>
27#include <folly/IPAddressException.h>
28#include <folly/Range.h>
29#include <folly/detail/IPAddress.h>
30#include <folly/hash/Hash.h>
31
32namespace folly {
33
34class IPAddress;
35class IPAddressV4;
36class IPAddressV6;
37
38/**
39 * Pair of IPAddressV4, netmask
40 */
41typedef std::pair<IPAddressV4, uint8_t> CIDRNetworkV4;
42
43/**
44 * Specialization for IPv4 addresses
45 */
46typedef std::array<uint8_t, 4> ByteArray4;
47
48/**
49 * IPv4 variation of IPAddress.
50 *
51 * Added methods: toLong, toLongHBO and createIPv6
52 *
53 * @note toLong/fromLong deal in network byte order, use toLongHBO/fromLongHBO
54 * if working in host byte order.
55 *
56 * @see IPAddress
57 */
58class IPAddressV4 {
59 public:
60 // Max size of std::string returned by toFullyQualified.
61 static constexpr size_t kMaxToFullyQualifiedSize =
62 4 /*words*/ * 3 /*max chars per word*/ + 3 /*separators*/;
63
64 // returns true iff the input string can be parsed as an ipv4-address
65 static bool validate(StringPiece ip) noexcept;
66
67 // create an IPAddressV4 instance from a uint32_t (network byte order)
68 static IPAddressV4 fromLong(uint32_t src);
69 // same as above but host byte order
70 static IPAddressV4 fromLongHBO(uint32_t src);
71
72 /**
73 * Create a new IPAddress instance from the provided binary data.
74 * @throws IPAddressFormatException if the input length is not 4 bytes.
75 */
76 static IPAddressV4 fromBinary(ByteRange bytes);
77
78 /**
79 * Non-throwing version of fromBinary().
80 * On failure returns IPAddressFormatError.
81 */
82 static Expected<IPAddressV4, IPAddressFormatError> tryFromBinary(
83 ByteRange bytes) noexcept;
84
85 /**
86 * Tries to create a new IPAddressV4 instance from provided string and
87 * returns it on success. Returns IPAddressFormatError on failure.
88 */
89 static Expected<IPAddressV4, IPAddressFormatError> tryFromString(
90 StringPiece str) noexcept;
91
92 /**
93 * Returns the address as a Range.
94 */
95 ByteRange toBinary() const {
96 return ByteRange((const unsigned char*)&addr_.inAddr_.s_addr, 4);
97 }
98
99 /**
100 * Create a new IPAddress instance from the in-addr.arpa representation.
101 * @throws IPAddressFormatException if the input is not a valid in-addr.arpa
102 * representation
103 */
104 static IPAddressV4 fromInverseArpaName(const std::string& arpaname);
105
106 /**
107 * Convert a IPv4 address string to a long in network byte order.
108 * @param [in] ip the address to convert
109 * @return the long representation of the address
110 */
111 static uint32_t toLong(StringPiece ip);
112 // Same as above, but in host byte order.
113 // This is slightly slower than toLong.
114 static uint32_t toLongHBO(StringPiece ip);
115
116 /**
117 * Default constructor for IPAddressV4.
118 *
119 * The address value will be 0.0.0.0
120 */
121 IPAddressV4();
122
123 // Create an IPAddressV4 from a string
124 // @throws IPAddressFormatException
125 explicit IPAddressV4(StringPiece ip);
126
127 // ByteArray4 constructor
128 explicit IPAddressV4(const ByteArray4& src) noexcept;
129
130 // in_addr constructor
131 explicit IPAddressV4(const in_addr src) noexcept;
132
133 // Return the V6 mapped representation of the address.
134 IPAddressV6 createIPv6() const;
135
136 /**
137 * Return a V6 address in the format of an 6To4 address.
138 */
139 IPAddressV6 getIPv6For6To4() const;
140
141 // Return the long (network byte order) representation of the address.
142 uint32_t toLong() const {
143 return toAddr().s_addr;
144 }
145
146 // Return the long (host byte order) representation of the address.
147 // This is slightly slower than toLong.
148 uint32_t toLongHBO() const {
149 return ntohl(toLong());
150 }
151
152 /**
153 * @see IPAddress#bitCount
154 * @returns 32
155 */
156 static constexpr size_t bitCount() {
157 return 32;
158 }
159
160 /**
161 * @See IPAddress#toJson
162 */
163 std::string toJson() const;
164
165 size_t hash() const {
166 static const uint32_t seed = AF_INET;
167 uint32_t hashed = hash::fnv32_buf(&addr_, 4);
168 return hash::hash_combine(seed, hashed);
169 }
170
171 // @see IPAddress#inSubnet
172 // @throws IPAddressFormatException if string doesn't contain a V4 address
173 bool inSubnet(StringPiece cidrNetwork) const;
174
175 // return true if address is in subnet
176 bool inSubnet(const IPAddressV4& subnet, uint8_t cidr) const {
177 return inSubnetWithMask(subnet, fetchMask(cidr));
178 }
179 bool inSubnetWithMask(const IPAddressV4& subnet, const ByteArray4 mask) const;
180
181 // @see IPAddress#isLoopback
182 bool isLoopback() const;
183
184 // @see IPAddress#isLinkLocal
185 bool isLinkLocal() const;
186
187 // @see IPAddress#isNonroutable
188 bool isNonroutable() const;
189
190 // @see IPAddress#isPrivate
191 bool isPrivate() const;
192
193 // @see IPAddress#isMulticast
194 bool isMulticast() const;
195
196 // @see IPAddress#isZero
197 bool isZero() const {
198 constexpr auto zero = ByteArray4{{}};
199 return 0 == std::memcmp(bytes(), zero.data(), zero.size());
200 }
201
202 bool isLinkLocalBroadcast() const {
203 return (INADDR_BROADCAST == toLongHBO());
204 }
205
206 // @see IPAddress#mask
207 IPAddressV4 mask(size_t numBits) const;
208
209 // @see IPAddress#str
210 std::string str() const;
211
212 std::string toInverseArpaName() const;
213
214 // return underlying in_addr structure
215 in_addr toAddr() const {
216 return addr_.inAddr_;
217 }
218
219 sockaddr_in toSockAddr() const {
220 sockaddr_in addr;
221 memset(&addr, 0, sizeof(sockaddr_in));
222 addr.sin_family = AF_INET;
223 memcpy(&addr.sin_addr, &addr_.inAddr_, sizeof(in_addr));
224 return addr;
225 }
226
227 ByteArray4 toByteArray() const {
228 ByteArray4 ba{{0}};
229 std::memcpy(ba.data(), bytes(), 4);
230 return ba;
231 }
232
233 // @see IPAddress#toFullyQualified
234 std::string toFullyQualified() const {
235 return str();
236 }
237
238 // @see IPAddress#toFullyQualifiedAppend
239 void toFullyQualifiedAppend(std::string& out) const;
240
241 // @see IPAddress#version
242 uint8_t version() const {
243 return 4;
244 }
245
246 /**
247 * Return the mask associated with the given number of bits.
248 * If for instance numBits was 24 (e.g. /24) then the V4 mask returned should
249 * be {0xff, 0xff, 0xff, 0x00}.
250 * @param [in] numBits bitmask to retrieve
251 * @throws abort if numBits == 0 or numBits > bitCount()
252 * @return mask associated with numBits
253 */
254 static const ByteArray4 fetchMask(size_t numBits);
255
256 // Given 2 IPAddressV4, mask pairs extract the longest common IPAddress,
257 // mask pair
258 static CIDRNetworkV4 longestCommonPrefix(
259 const CIDRNetworkV4& one,
260 const CIDRNetworkV4& two);
261 // Number of bytes in the address representation.
262 static size_t byteCount() {
263 return 4;
264 }
265 // get nth most significant bit - 0 indexed
266 bool getNthMSBit(size_t bitIndex) const {
267 return detail::getNthMSBitImpl(*this, bitIndex, AF_INET);
268 }
269 // get nth most significant byte - 0 indexed
270 uint8_t getNthMSByte(size_t byteIndex) const;
271 // get nth bit - 0 indexed
272 bool getNthLSBit(size_t bitIndex) const {
273 return getNthMSBit(bitCount() - bitIndex - 1);
274 }
275 // get nth byte - 0 indexed
276 uint8_t getNthLSByte(size_t byteIndex) const {
277 return getNthMSByte(byteCount() - byteIndex - 1);
278 }
279
280 const unsigned char* bytes() const {
281 return addr_.bytes_.data();
282 }
283
284 private:
285 union AddressStorage {
286 static_assert(
287 sizeof(in_addr) == sizeof(ByteArray4),
288 "size of in_addr and ByteArray4 are different");
289 in_addr inAddr_;
290 ByteArray4 bytes_;
291 AddressStorage() {
292 std::memset(this, 0, sizeof(AddressStorage));
293 }
294 explicit AddressStorage(const ByteArray4 bytes) : bytes_(bytes) {}
295 explicit AddressStorage(const in_addr addr) : inAddr_(addr) {}
296 } addr_;
297
298 /**
299 * Set the current IPAddressV4 object to have the address specified by bytes.
300 * Returns IPAddressFormatError if bytes.size() is not 4.
301 */
302 Expected<Unit, IPAddressFormatError> trySetFromBinary(
303 ByteRange bytes) noexcept;
304};
305
306// boost::hash uses hash_value() so this allows boost::hash to work
307// automatically for IPAddressV4
308size_t hash_value(const IPAddressV4& addr);
309std::ostream& operator<<(std::ostream& os, const IPAddressV4& addr);
310// Define toAppend() to allow IPAddressV4 to be used with to<string>
311void toAppend(IPAddressV4 addr, std::string* result);
312void toAppend(IPAddressV4 addr, fbstring* result);
313
314/**
315 * Return true if two addresses are equal.
316 */
317inline bool operator==(const IPAddressV4& addr1, const IPAddressV4& addr2) {
318 return (addr1.toLong() == addr2.toLong());
319}
320// Return true if addr1 < addr2
321inline bool operator<(const IPAddressV4& addr1, const IPAddressV4& addr2) {
322 return (addr1.toLongHBO() < addr2.toLongHBO());
323}
324// Derived operators
325inline bool operator!=(const IPAddressV4& a, const IPAddressV4& b) {
326 return !(a == b);
327}
328inline bool operator>(const IPAddressV4& a, const IPAddressV4& b) {
329 return b < a;
330}
331inline bool operator<=(const IPAddressV4& a, const IPAddressV4& b) {
332 return !(a > b);
333}
334inline bool operator>=(const IPAddressV4& a, const IPAddressV4& b) {
335 return !(a < b);
336}
337
338} // namespace folly
339
340namespace std {
341template <>
342struct hash<folly::IPAddressV4> {
343 size_t operator()(const folly::IPAddressV4 addr) const {
344 return addr.hash();
345 }
346};
347} // namespace std
348