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 <sys/types.h>
20#include <cstddef>
21#include <iosfwd>
22#include <string>
23
24#include <folly/IPAddress.h>
25#include <folly/Portability.h>
26#include <folly/Range.h>
27#include <folly/net/NetworkSocket.h>
28#include <folly/portability/Sockets.h>
29
30namespace folly {
31
32class SocketAddress {
33 public:
34 SocketAddress() = default;
35
36 /**
37 * Construct a SocketAddress from a hostname and port.
38 *
39 * Note: If the host parameter is not a numeric IP address, hostname
40 * resolution will be performed, which can be quite slow.
41 *
42 * Raises std::system_error on error.
43 *
44 * @param host The IP address (or hostname, if allowNameLookup is true)
45 * @param port The port (in host byte order)
46 * @pram allowNameLookup If true, attempt to perform hostname lookup
47 * if the hostname does not appear to be a numeric IP address.
48 * This is potentially a very slow operation, so is disabled by
49 * default.
50 */
51 SocketAddress(const char* host, uint16_t port, bool allowNameLookup = false) {
52 // Initialize the address family first,
53 // since setFromHostPort() and setFromIpPort() will check it.
54
55 if (allowNameLookup) {
56 setFromHostPort(host, port);
57 } else {
58 setFromIpPort(host, port);
59 }
60 }
61
62 SocketAddress(
63 const std::string& host,
64 uint16_t port,
65 bool allowNameLookup = false) {
66 // Initialize the address family first,
67 // since setFromHostPort() and setFromIpPort() will check it.
68
69 if (allowNameLookup) {
70 setFromHostPort(host.c_str(), port);
71 } else {
72 setFromIpPort(host.c_str(), port);
73 }
74 }
75
76 SocketAddress(const IPAddress& ipAddr, uint16_t port) {
77 setFromIpAddrPort(ipAddr, port);
78 }
79
80 SocketAddress(const SocketAddress& addr) {
81 port_ = addr.port_;
82 if (addr.getFamily() == AF_UNIX) {
83 storage_.un.init(addr.storage_.un);
84 } else {
85 storage_ = addr.storage_;
86 }
87 external_ = addr.external_;
88 }
89
90 SocketAddress& operator=(const SocketAddress& addr) {
91 if (!external_) {
92 if (addr.getFamily() != AF_UNIX) {
93 storage_ = addr.storage_;
94 } else {
95 storage_ = addr.storage_;
96 storage_.un.init(addr.storage_.un);
97 }
98 } else {
99 if (addr.getFamily() == AF_UNIX) {
100 storage_.un.copy(addr.storage_.un);
101 } else {
102 storage_.un.free();
103 storage_ = addr.storage_;
104 }
105 }
106 port_ = addr.port_;
107 external_ = addr.external_;
108 return *this;
109 }
110
111 SocketAddress(SocketAddress&& addr) noexcept {
112 storage_ = addr.storage_;
113 port_ = addr.port_;
114 external_ = addr.external_;
115 addr.external_ = false;
116 }
117
118 SocketAddress& operator=(SocketAddress&& addr) {
119 std::swap(storage_, addr.storage_);
120 std::swap(port_, addr.port_);
121 std::swap(external_, addr.external_);
122 return *this;
123 }
124
125 ~SocketAddress() {
126 if (external_) {
127 storage_.un.free();
128 }
129 }
130
131 bool isInitialized() const {
132 return (getFamily() != AF_UNSPEC);
133 }
134
135 /**
136 * Return whether this address is within private network.
137 *
138 * According to RFC1918, the 10/8 prefix, 172.16/12 prefix, and 192.168/16
139 * prefix are reserved for private networks.
140 * fc00::/7 is the IPv6 version, defined in RFC4139. IPv6 link-local
141 * addresses (fe80::/10) are also considered private addresses.
142 *
143 * The loopback addresses 127/8 and ::1 are also regarded as private networks
144 * for the purpose of this function.
145 *
146 * Returns true if this is a private network address, and false otherwise.
147 */
148 bool isPrivateAddress() const;
149
150 /**
151 * Return whether this address is a loopback address.
152 */
153 bool isLoopbackAddress() const;
154
155 void reset() {
156 if (external_) {
157 storage_.un.free();
158 }
159 storage_.addr = folly::IPAddress();
160 external_ = false;
161 }
162
163 /**
164 * Initialize this SocketAddress from a hostname and port.
165 *
166 * Note: If the host parameter is not a numeric IP address, hostname
167 * resolution will be performed, which can be quite slow.
168 *
169 * If the hostname resolves to multiple addresses, only the first will be
170 * returned.
171 *
172 * Raises std::system_error on error.
173 *
174 * @param host The hostname or IP address
175 * @param port The port (in host byte order)
176 */
177 void setFromHostPort(const char* host, uint16_t port);
178
179 void setFromHostPort(const std::string& host, uint16_t port) {
180 setFromHostPort(host.c_str(), port);
181 }
182
183 /**
184 * Initialize this SocketAddress from an IP address and port.
185 *
186 * This is similar to setFromHostPort(), but only accepts numeric IP
187 * addresses. If the IP string does not look like an IP address, it throws a
188 * std::invalid_argument rather than trying to perform a hostname resolution.
189 *
190 * Raises std::system_error on error.
191 *
192 * @param ip The IP address, as a human-readable string.
193 * @param port The port (in host byte order)
194 */
195 void setFromIpPort(const char* ip, uint16_t port);
196
197 void setFromIpPort(const std::string& ip, uint16_t port) {
198 setFromIpPort(ip.c_str(), port);
199 }
200
201 /**
202 * Initialize this SocketAddress from an IPAddress struct and port.
203 *
204 * @param ip The IP address in IPAddress format
205 * @param port The port (in host byte order)
206 */
207 void setFromIpAddrPort(const IPAddress& ip, uint16_t port);
208
209 /**
210 * Initialize this SocketAddress from a local port number.
211 *
212 * This is intended to be used by server code to determine the address to
213 * listen on.
214 *
215 * If the current machine has any IPv6 addresses configured, an IPv6 address
216 * will be returned (since connections from IPv4 clients can be mapped to the
217 * IPv6 address). If the machine does not have any IPv6 addresses, an IPv4
218 * address will be returned.
219 */
220 void setFromLocalPort(uint16_t port);
221
222 /**
223 * Initialize this SocketAddress from a local port number.
224 *
225 * This version of setFromLocalPort() accepts the port as a string. A
226 * std::invalid_argument will be raised if the string does not refer to a port
227 * number. Non-numeric service port names are not accepted.
228 */
229 void setFromLocalPort(const char* port);
230 void setFromLocalPort(const std::string& port) {
231 return setFromLocalPort(port.c_str());
232 }
233
234 /**
235 * Initialize this SocketAddress from a local port number and optional IP
236 * address.
237 *
238 * The addressAndPort string may be specified either as "<ip>:<port>", or
239 * just as "<port>". If the IP is not specified, the address will be
240 * initialized to 0, so that a server socket bound to this address will
241 * accept connections on all local IP addresses.
242 *
243 * Both the IP address and port number must be numeric. DNS host names and
244 * non-numeric service port names are not accepted.
245 */
246 void setFromLocalIpPort(const char* addressAndPort);
247 void setFromLocalIpPort(const std::string& addressAndPort) {
248 return setFromLocalIpPort(addressAndPort.c_str());
249 }
250
251 /**
252 * Initialize this SocketAddress from an IP address and port number.
253 *
254 * The addressAndPort string must be of the form "<ip>:<port>". E.g.,
255 * "10.0.0.1:1234".
256 *
257 * Both the IP address and port number must be numeric. DNS host names and
258 * non-numeric service port names are not accepted.
259 */
260 void setFromIpPort(const char* addressAndPort);
261 void setFromIpPort(const std::string& addressAndPort) {
262 return setFromIpPort(addressAndPort.c_str());
263 }
264
265 /**
266 * Initialize this SocketAddress from a host name and port number.
267 *
268 * The addressAndPort string must be of the form "<host>:<port>". E.g.,
269 * "www.facebook.com:443".
270 *
271 * If the host name is not a numeric IP address, a DNS lookup will be
272 * performed. Beware that the DNS lookup may be very slow. The port number
273 * must be numeric; non-numeric service port names are not accepted.
274 */
275 void setFromHostPort(const char* hostAndPort);
276 void setFromHostPort(const std::string& hostAndPort) {
277 return setFromHostPort(hostAndPort.c_str());
278 }
279
280 /**
281 * Returns the port number from the given socketaddr structure.
282 *
283 * Currently only IPv4 and IPv6 are supported.
284 *
285 * Returns -1 for unsupported socket families.
286 */
287 static int getPortFrom(const struct sockaddr* address);
288
289 /**
290 * Returns the family name from the given socketaddr structure (e.g.: AF_INET6
291 * for IPv6).
292 *
293 * Returns `defaultResult` for unsupported socket families.
294 */
295 static const char* getFamilyNameFrom(
296 const struct sockaddr* address,
297 const char* defaultResult = nullptr);
298
299 /**
300 * Initialize this SocketAddress from a local unix path.
301 *
302 * Raises std::invalid_argument on error.
303 */
304 void setFromPath(StringPiece path);
305
306 void setFromPath(const char* path, size_t length) {
307 setFromPath(StringPiece{path, length});
308 }
309
310 /**
311 * Construct a SocketAddress from a local unix socket path.
312 *
313 * Raises std::invalid_argument on error.
314 *
315 * @param path The Unix domain socket path.
316 */
317 static SocketAddress makeFromPath(StringPiece path) {
318 SocketAddress addr;
319 addr.setFromPath(path);
320 return addr;
321 }
322
323 /**
324 * Initialize this SocketAddress from a socket's peer address.
325 *
326 * Raises std::system_error on error.
327 */
328 void setFromPeerAddress(NetworkSocket socket);
329
330 /**
331 * Initialize this SocketAddress from a socket's local address.
332 *
333 * Raises std::system_error on error.
334 */
335 void setFromLocalAddress(NetworkSocket socket);
336
337 /**
338 * Initialize this folly::SocketAddress from a struct sockaddr.
339 *
340 * Raises std::system_error on error.
341 *
342 * This method is not supported for AF_UNIX addresses. For unix addresses,
343 * the address length must be explicitly specified.
344 *
345 * @param address A struct sockaddr. The size of the address is implied
346 * from address->sa_family.
347 */
348 void setFromSockaddr(const struct sockaddr* address);
349
350 /**
351 * Initialize this SocketAddress from a struct sockaddr.
352 *
353 * Raises std::system_error on error.
354 *
355 * @param address A struct sockaddr.
356 * @param addrlen The length of address data available. This must be long
357 * enough for the full address type required by
358 * address->sa_family.
359 */
360 void setFromSockaddr(const struct sockaddr* address, socklen_t addrlen);
361
362 /**
363 * Initialize this SocketAddress from a struct sockaddr_in.
364 */
365 void setFromSockaddr(const struct sockaddr_in* address);
366
367 /**
368 * Initialize this SocketAddress from a struct sockaddr_in6.
369 */
370 void setFromSockaddr(const struct sockaddr_in6* address);
371
372 /**
373 * Initialize this SocketAddress from a struct sockaddr_un.
374 *
375 * Note that the addrlen parameter is necessary to properly detect anonymous
376 * addresses, which have 0 valid path bytes, and may not even have a NUL
377 * character at the start of the path.
378 *
379 * @param address A struct sockaddr_un.
380 * @param addrlen The length of address data. This should include all of
381 * the valid bytes of sun_path, not including any NUL
382 * terminator.
383 */
384 void setFromSockaddr(const struct sockaddr_un* address, socklen_t addrlen);
385
386 /**
387 * Fill in a given sockaddr_storage with the ip or unix address.
388 *
389 * Returns the actual size of the storage used.
390 */
391 socklen_t getAddress(sockaddr_storage* addr) const {
392 if (!external_) {
393 return storage_.addr.toSockaddrStorage(addr, htons(port_));
394 } else {
395 memcpy(addr, storage_.un.addr, sizeof(*storage_.un.addr));
396 return storage_.un.len;
397 }
398 }
399
400 const folly::IPAddress& getIPAddress() const;
401
402 // Deprecated: getAddress() above returns the same size as getActualSize()
403 socklen_t getActualSize() const;
404
405 sa_family_t getFamily() const {
406 DCHECK(external_ || AF_UNIX != storage_.addr.family());
407 return external_ ? sa_family_t(AF_UNIX) : storage_.addr.family();
408 }
409
410 bool empty() const {
411 return getFamily() == AF_UNSPEC;
412 }
413
414 /**
415 * Get a string representation of the IPv4 or IPv6 address.
416 *
417 * Raises std::invalid_argument if an error occurs (for example, if
418 * the address is not an IPv4 or IPv6 address).
419 */
420 std::string getAddressStr() const;
421
422 /**
423 * Get a string representation of the IPv4 or IPv6 address.
424 *
425 * Raises std::invalid_argument if an error occurs (for example, if
426 * the address is not an IPv4 or IPv6 address).
427 */
428 void getAddressStr(char* buf, size_t buflen) const;
429
430 /**
431 * Return true if it is a valid IPv4 or IPv6 address.
432 */
433 bool isFamilyInet() const;
434
435 /**
436 * For v4 & v6 addresses, return the fully qualified address string
437 */
438 std::string getFullyQualified() const;
439
440 /**
441 * Get the IPv4 or IPv6 port for this address.
442 *
443 * Raises std::invalid_argument if this is not an IPv4 or IPv6 address.
444 *
445 * @return Returns the port, in host byte order.
446 */
447 uint16_t getPort() const;
448
449 /**
450 * Set the IPv4 or IPv6 port for this address.
451 *
452 * Raises std::invalid_argument if this is not an IPv4 or IPv6 address.
453 */
454 void setPort(uint16_t port);
455
456 /**
457 * Return true if this is an IPv4-mapped IPv6 address.
458 */
459 bool isIPv4Mapped() const {
460 return (getFamily() == AF_INET6 && storage_.addr.isIPv4Mapped());
461 }
462
463 /**
464 * Convert an IPv4-mapped IPv6 address to an IPv4 address.
465 *
466 * Raises std::invalid_argument if this is not an IPv4-mapped IPv6 address.
467 */
468 void convertToIPv4();
469
470 /**
471 * Try to convert an address to IPv4.
472 *
473 * This attempts to convert an address to an IPv4 address if possible.
474 * If the address is an IPv4-mapped IPv6 address, it is converted to an IPv4
475 * address and true is returned. Otherwise nothing is done, and false is
476 * returned.
477 */
478 bool tryConvertToIPv4();
479
480 /**
481 * Convert an IPv4 address to IPv6 [::ffff:a.b.c.d]
482 */
483
484 bool mapToIPv6();
485
486 /**
487 * Get string representation of the host name (or IP address if the host name
488 * cannot be resolved).
489 *
490 * Warning: Using this method is strongly discouraged. It performs a
491 * DNS lookup, which may block for many seconds.
492 *
493 * Raises std::invalid_argument if an error occurs.
494 */
495 std::string getHostStr() const;
496
497 /**
498 * Get the path name for a Unix domain socket.
499 *
500 * Returns a std::string containing the path. For anonymous sockets, an
501 * empty string is returned.
502 *
503 * For addresses in the abstract namespace (Linux-specific), a std::string
504 * containing binary data is returned. In this case the first character will
505 * always be a NUL character.
506 *
507 * Raises std::invalid_argument if called on a non-Unix domain socket.
508 */
509 std::string getPath() const;
510
511 /**
512 * Get human-readable string representation of the address.
513 *
514 * This prints a string representation of the address, for human consumption.
515 * For IP addresses, the string is of the form "<IP>:<port>".
516 */
517 std::string describe() const;
518
519 bool operator==(const SocketAddress& other) const;
520 bool operator!=(const SocketAddress& other) const {
521 return !(*this == other);
522 }
523
524 /**
525 * Check whether the first N bits of this address match the first N
526 * bits of another address.
527 * @note returns false if the addresses are not from the same
528 * address family or if the family is neither IPv4 nor IPv6
529 */
530 bool prefixMatch(const SocketAddress& other, unsigned prefixLength) const;
531
532 /**
533 * Use this operator for storing maps based on SocketAddress.
534 */
535 bool operator<(const SocketAddress& other) const;
536
537 /**
538 * Compuate a hash of a SocketAddress.
539 */
540 size_t hash() const;
541
542 private:
543 /**
544 * Unix socket addresses require more storage than IPv4 and IPv6 addresses,
545 * and are comparatively little-used.
546 *
547 * Therefore SocketAddress' internal storage_ member variable doesn't
548 * contain room for a full unix address, to avoid wasting space in the common
549 * case. When we do need to store a Unix socket address, we use this
550 * ExternalUnixAddr structure to allocate a struct sockaddr_un separately on
551 * the heap.
552 */
553 struct ExternalUnixAddr {
554 struct sockaddr_un* addr;
555 socklen_t len;
556
557 socklen_t pathLength() const {
558 return socklen_t(len - offsetof(struct sockaddr_un, sun_path));
559 }
560
561 void init() {
562 addr = new struct sockaddr_un;
563 addr->sun_family = AF_UNIX;
564 len = 0;
565 }
566 void init(const ExternalUnixAddr& other) {
567 addr = new struct sockaddr_un;
568 len = other.len;
569 memcpy(addr, other.addr, size_t(len));
570 }
571 void copy(const ExternalUnixAddr& other) {
572 len = other.len;
573 memcpy(addr, other.addr, size_t(len));
574 }
575 void free() {
576 delete addr;
577 }
578 };
579
580 struct addrinfo* getAddrInfo(const char* host, uint16_t port, int flags);
581 struct addrinfo* getAddrInfo(const char* host, const char* port, int flags);
582 void setFromAddrInfo(const struct addrinfo* results);
583 void setFromLocalAddr(const struct addrinfo* results);
584 void setFromSocket(
585 NetworkSocket socket,
586 int (*fn)(NetworkSocket, struct sockaddr*, socklen_t*));
587 std::string getIpString(int flags) const;
588 void getIpString(char* buf, size_t buflen, int flags) const;
589
590 void updateUnixAddressLength(socklen_t addrlen);
591
592 /*
593 * storage_ contains room for a full IPv4 or IPv6 address, so they can be
594 * stored inline without a separate allocation on the heap.
595 *
596 * If we need to store a Unix socket address, ExternalUnixAddr is a shim to
597 * track a struct sockaddr_un allocated separately on the heap.
598 */
599 union AddrStorage {
600 folly::IPAddress addr;
601 ExternalUnixAddr un;
602 AddrStorage() : addr() {}
603 } storage_{};
604 // IPAddress class does nto save zone or port, and must be saved here
605 uint16_t port_;
606
607 bool external_{false};
608};
609
610/**
611 * Hash a SocketAddress object.
612 *
613 * boost::hash uses hash_value(), so this allows boost::hash to automatically
614 * work for SocketAddress.
615 */
616size_t hash_value(const SocketAddress& address);
617
618std::ostream& operator<<(std::ostream& os, const SocketAddress& addr);
619} // namespace folly
620
621namespace std {
622
623// Provide an implementation for std::hash<SocketAddress>
624template <>
625struct hash<folly::SocketAddress> {
626 size_t operator()(const folly::SocketAddress& addr) const {
627 return addr.hash();
628 }
629};
630} // namespace std
631