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