2 * Copyright 2017 Facebook, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #ifndef __STDC_FORMAT_MACROS
18 #define __STDC_FORMAT_MACROS
21 #include <folly/SocketAddress.h>
28 #include <system_error>
30 #include <boost/functional/hash.hpp>
32 #include <folly/CppAttributes.h>
33 #include <folly/Exception.h>
34 #include <folly/Format.h>
35 #include <folly/Hash.h>
40 * A structure to free a struct addrinfo when it goes out of scope.
42 struct ScopedAddrInfo {
43 explicit ScopedAddrInfo(struct addrinfo* addrinfo) : info(addrinfo) {}
48 struct addrinfo* info;
52 * A simple data structure for parsing a host-and-port string.
54 * Accepts a string of the form "<host>:<port>" or just "<port>",
55 * and contains two string pointers to the host and the port portion of the
58 * The HostAndPort may contain pointers into the original string. It is
59 * responsible for the user to ensure that the input string is valid for the
60 * lifetime of the HostAndPort structure.
63 HostAndPort(const char* str, bool hostRequired)
68 // Look for the last colon
69 const char* colon = strrchr(str, ':');
70 if (colon == nullptr) {
71 // No colon, just a port number.
73 throw std::invalid_argument(
74 "expected a host and port string of the "
75 "form \"<host>:<port>\"");
81 // We have to make a copy of the string so we can modify it
82 // and change the colon to a NUL terminator.
83 allocated = strdup(str);
85 throw std::bad_alloc();
88 char *allocatedColon = allocated + (colon - str);
89 *allocatedColon = '\0';
91 port = allocatedColon + 1;
92 // bracketed IPv6 address, remove the brackets
93 // allocatedColon[-1] is fine, as allocatedColon >= host and
94 // *allocatedColon != *host therefore allocatedColon > host
95 if (*host == '[' && allocatedColon[-1] == ']') {
96 allocatedColon[-1] = '\0';
114 bool SocketAddress::isPrivateAddress() const {
115 auto family = getFamily();
116 if (family == AF_INET || family == AF_INET6) {
117 return storage_.addr.isPrivate() ||
118 (storage_.addr.isV6() && storage_.addr.asV6().isLinkLocal());
119 } else if (external_) {
120 // Unix addresses are always local to a host. Return true,
121 // since this conforms to the semantics of returning true for IP loopback
128 bool SocketAddress::isLoopbackAddress() const {
129 auto family = getFamily();
130 if (family == AF_INET || family == AF_INET6) {
131 return storage_.addr.isLoopback();
132 } else if (external_) {
133 // Return true for UNIX addresses, since they are always local to a host.
139 void SocketAddress::setFromHostPort(const char* host, uint16_t port) {
140 ScopedAddrInfo results(getAddrInfo(host, port, 0));
141 setFromAddrInfo(results.info);
144 void SocketAddress::setFromIpPort(const char* ip, uint16_t port) {
145 ScopedAddrInfo results(getAddrInfo(ip, port, AI_NUMERICHOST));
146 setFromAddrInfo(results.info);
149 void SocketAddress::setFromIpAddrPort(const IPAddress& ipAddr, uint16_t port) {
154 storage_.addr = ipAddr;
158 void SocketAddress::setFromLocalPort(uint16_t port) {
159 ScopedAddrInfo results(getAddrInfo(nullptr, port, AI_ADDRCONFIG));
160 setFromLocalAddr(results.info);
163 void SocketAddress::setFromLocalPort(const char* port) {
164 ScopedAddrInfo results(getAddrInfo(nullptr, port, AI_ADDRCONFIG));
165 setFromLocalAddr(results.info);
168 void SocketAddress::setFromLocalIpPort(const char* addressAndPort) {
169 HostAndPort hp(addressAndPort, false);
170 ScopedAddrInfo results(getAddrInfo(hp.host, hp.port,
171 AI_NUMERICHOST | AI_ADDRCONFIG));
172 setFromLocalAddr(results.info);
175 void SocketAddress::setFromIpPort(const char* addressAndPort) {
176 HostAndPort hp(addressAndPort, true);
177 ScopedAddrInfo results(getAddrInfo(hp.host, hp.port, AI_NUMERICHOST));
178 setFromAddrInfo(results.info);
181 void SocketAddress::setFromHostPort(const char* hostAndPort) {
182 HostAndPort hp(hostAndPort, true);
183 ScopedAddrInfo results(getAddrInfo(hp.host, hp.port, 0));
184 setFromAddrInfo(results.info);
187 int SocketAddress::getPortFrom(const struct sockaddr* address) {
188 switch (address->sa_family) {
190 return ntohs(((sockaddr_in*)address)->sin_port);
193 return ntohs(((sockaddr_in6*)address)->sin6_port);
200 const char* SocketAddress::getFamilyNameFrom(
201 const struct sockaddr* address,
202 const char* defaultResult) {
203 #define GETFAMILYNAMEFROM_IMPL(Family) \
207 switch (address->sa_family) {
208 GETFAMILYNAMEFROM_IMPL(AF_INET);
209 GETFAMILYNAMEFROM_IMPL(AF_INET6);
210 GETFAMILYNAMEFROM_IMPL(AF_UNIX);
211 GETFAMILYNAMEFROM_IMPL(AF_UNSPEC);
214 return defaultResult;
217 #undef GETFAMILYNAMEFROM_IMPL
220 void SocketAddress::setFromPath(StringPiece path) {
221 // Before we touch storage_, check to see if the length is too big.
222 // Note that "storage_.un.addr->sun_path" may not be safe to evaluate here,
223 // but sizeof() just uses its type, and does't evaluate it.
224 if (path.size() > sizeof(storage_.un.addr->sun_path)) {
225 throw std::invalid_argument(
226 "socket path too large to fit into sockaddr_un");
234 size_t len = path.size();
235 storage_.un.len = socklen_t(offsetof(struct sockaddr_un, sun_path) + len);
236 memcpy(storage_.un.addr->sun_path, path.data(), len);
237 // If there is room, put a terminating NUL byte in sun_path. In general the
238 // path should be NUL terminated, although getsockname() and getpeername()
239 // may return Unix socket addresses with paths that fit exactly in sun_path
240 // with no terminating NUL.
241 if (len < sizeof(storage_.un.addr->sun_path)) {
242 storage_.un.addr->sun_path[len] = '\0';
246 void SocketAddress::setFromPeerAddress(int socket) {
247 setFromSocket(socket, getpeername);
250 void SocketAddress::setFromLocalAddress(int socket) {
251 setFromSocket(socket, getsockname);
254 void SocketAddress::setFromSockaddr(const struct sockaddr* address) {
257 if (address->sa_family == AF_INET) {
258 port = ntohs(((sockaddr_in*)address)->sin_port);
259 } else if (address->sa_family == AF_INET6) {
260 port = ntohs(((sockaddr_in6*)address)->sin6_port);
261 } else if (address->sa_family == AF_UNIX) {
262 // We need an explicitly specified length for AF_UNIX addresses,
263 // to be able to distinguish anonymous addresses from addresses
264 // in Linux's abstract namespace.
265 throw std::invalid_argument(
266 "SocketAddress::setFromSockaddr(): the address "
267 "length must be explicitly specified when "
268 "setting AF_UNIX addresses");
270 throw std::invalid_argument(
271 "SocketAddress::setFromSockaddr() called "
272 "with unsupported address type");
275 setFromIpAddrPort(folly::IPAddress(address), port);
278 void SocketAddress::setFromSockaddr(const struct sockaddr* address,
280 // Check the length to make sure we can access address->sa_family
281 if (addrlen < (offsetof(struct sockaddr, sa_family) +
282 sizeof(address->sa_family))) {
283 throw std::invalid_argument(
284 "SocketAddress::setFromSockaddr() called "
285 "with length too short for a sockaddr");
288 if (address->sa_family == AF_INET) {
289 if (addrlen < sizeof(struct sockaddr_in)) {
290 throw std::invalid_argument(
291 "SocketAddress::setFromSockaddr() called "
292 "with length too short for a sockaddr_in");
294 setFromSockaddr(reinterpret_cast<const struct sockaddr_in*>(address));
295 } else if (address->sa_family == AF_INET6) {
296 if (addrlen < sizeof(struct sockaddr_in6)) {
297 throw std::invalid_argument(
298 "SocketAddress::setFromSockaddr() called "
299 "with length too short for a sockaddr_in6");
301 setFromSockaddr(reinterpret_cast<const struct sockaddr_in6*>(address));
302 } else if (address->sa_family == AF_UNIX) {
303 setFromSockaddr(reinterpret_cast<const struct sockaddr_un*>(address),
306 throw std::invalid_argument(
307 "SocketAddress::setFromSockaddr() called "
308 "with unsupported address type");
312 void SocketAddress::setFromSockaddr(const struct sockaddr_in* address) {
313 assert(address->sin_family == AF_INET);
314 setFromSockaddr((sockaddr*)address);
317 void SocketAddress::setFromSockaddr(const struct sockaddr_in6* address) {
318 assert(address->sin6_family == AF_INET6);
319 setFromSockaddr((sockaddr*)address);
322 void SocketAddress::setFromSockaddr(const struct sockaddr_un* address,
324 assert(address->sun_family == AF_UNIX);
325 if (addrlen > sizeof(struct sockaddr_un)) {
326 throw std::invalid_argument(
327 "SocketAddress::setFromSockaddr() called "
328 "with length too long for a sockaddr_un");
335 memcpy(storage_.un.addr, address, size_t(addrlen));
336 updateUnixAddressLength(addrlen);
338 // Fill the rest with 0s, just for safety
339 if (addrlen < sizeof(struct sockaddr_un)) {
340 char *p = reinterpret_cast<char*>(storage_.un.addr);
341 memset(p + addrlen, 0, sizeof(struct sockaddr_un) - addrlen);
345 const folly::IPAddress& SocketAddress::getIPAddress() const {
346 auto family = getFamily();
347 if (family != AF_INET && family != AF_INET6) {
348 throw InvalidAddressFamilyException(family);
350 return storage_.addr;
353 socklen_t SocketAddress::getActualSize() const {
355 return storage_.un.len;
357 switch (getFamily()) {
360 return sizeof(struct sockaddr_in);
362 return sizeof(struct sockaddr_in6);
364 throw std::invalid_argument(
365 "SocketAddress::getActualSize() called "
366 "with unrecognized address family");
370 std::string SocketAddress::getFullyQualified() const {
371 if (!isFamilyInet()) {
372 throw std::invalid_argument("Can't get address str for non ip address");
374 return storage_.addr.toFullyQualified();
377 std::string SocketAddress::getAddressStr() const {
378 if (!isFamilyInet()) {
379 throw std::invalid_argument("Can't get address str for non ip address");
381 return storage_.addr.str();
384 bool SocketAddress::isFamilyInet() const {
385 auto family = getFamily();
386 return family == AF_INET || family == AF_INET6;
389 void SocketAddress::getAddressStr(char* buf, size_t buflen) const {
390 auto ret = getAddressStr();
391 size_t len = std::min(buflen - 1, ret.size());
392 memcpy(buf, ret.data(), len);
396 uint16_t SocketAddress::getPort() const {
397 switch (getFamily()) {
402 throw std::invalid_argument(
403 "SocketAddress::getPort() called on non-IP "
408 void SocketAddress::setPort(uint16_t port) {
409 switch (getFamily()) {
415 throw std::invalid_argument(
416 "SocketAddress::setPort() called on non-IP "
421 void SocketAddress::convertToIPv4() {
422 if (!tryConvertToIPv4()) {
423 throw std::invalid_argument(
424 "convertToIPv4() called on an addresse that is "
425 "not an IPv4-mapped address");
429 bool SocketAddress::tryConvertToIPv4() {
430 if (!isIPv4Mapped()) {
434 storage_.addr = folly::IPAddress::createIPv4(storage_.addr);
438 bool SocketAddress::mapToIPv6() {
439 if (getFamily() != AF_INET) {
443 storage_.addr = folly::IPAddress::createIPv6(storage_.addr);
447 std::string SocketAddress::getHostStr() const {
448 return getIpString(0);
451 std::string SocketAddress::getPath() const {
453 throw std::invalid_argument(
454 "SocketAddress: attempting to get path "
455 "for a non-Unix address");
458 if (storage_.un.pathLength() == 0) {
460 return std::string();
462 if (storage_.un.addr->sun_path[0] == '\0') {
463 // abstract namespace
465 storage_.un.addr->sun_path, size_t(storage_.un.pathLength()));
469 storage_.un.addr->sun_path,
470 strnlen(storage_.un.addr->sun_path, size_t(storage_.un.pathLength())));
473 std::string SocketAddress::describe() const {
475 if (storage_.un.pathLength() == 0) {
476 return "<anonymous unix address>";
479 if (storage_.un.addr->sun_path[0] == '\0') {
480 // Linux supports an abstract namespace for unix socket addresses
481 return "<abstract unix address>";
485 storage_.un.addr->sun_path,
486 strnlen(storage_.un.addr->sun_path, size_t(storage_.un.pathLength())));
488 switch (getFamily()) {
490 return "<uninitialized address>";
493 char buf[NI_MAXHOST + 16];
494 getAddressStr(buf, sizeof(buf));
495 size_t iplen = strlen(buf);
496 snprintf(buf + iplen, sizeof(buf) - iplen, ":%" PRIu16, getPort());
501 char buf[NI_MAXHOST + 18];
503 getAddressStr(buf + 1, sizeof(buf) - 1);
504 size_t iplen = strlen(buf);
505 snprintf(buf + iplen, sizeof(buf) - iplen, "]:%" PRIu16, getPort());
511 snprintf(buf, sizeof(buf), "<unknown address family %d>",
518 bool SocketAddress::operator==(const SocketAddress& other) const {
519 if (external_ != other.external_ || other.getFamily() != getFamily()) {
523 // anonymous addresses are never equal to any other addresses
524 if (storage_.un.pathLength() == 0 ||
525 other.storage_.un.pathLength() == 0) {
529 if (storage_.un.len != other.storage_.un.len) {
533 storage_.un.addr->sun_path,
534 other.storage_.un.addr->sun_path,
535 size_t(storage_.un.pathLength()));
539 switch (getFamily()) {
542 return (other.storage_.addr == storage_.addr) &&
543 (other.port_ == port_);
545 throw std::invalid_argument(
546 "SocketAddress: unsupported address family "
551 bool SocketAddress::prefixMatch(const SocketAddress& other,
552 unsigned prefixLength) const {
553 if (other.getFamily() != getFamily()) {
556 uint8_t mask_length = 128;
557 switch (getFamily()) {
563 auto prefix = folly::IPAddress::longestCommonPrefix(
564 {storage_.addr, mask_length},
565 {other.storage_.addr, mask_length});
566 return prefix.second >= prefixLength;
574 size_t SocketAddress::hash() const {
575 size_t seed = folly::hash::twang_mix64(getFamily());
578 enum { kUnixPathMax = sizeof(storage_.un.addr->sun_path) };
579 const char *path = storage_.un.addr->sun_path;
580 auto pathLength = storage_.un.pathLength();
581 // TODO: this probably could be made more efficient
582 for (off_t n = 0; n < pathLength; ++n) {
583 boost::hash_combine(seed, folly::hash::twang_mix64(uint64_t(path[n])));
587 switch (getFamily()) {
590 boost::hash_combine(seed, port_);
591 boost::hash_combine(seed, storage_.addr.hash());
599 throw std::invalid_argument(
600 "SocketAddress: unsupported address family "
607 struct addrinfo* SocketAddress::getAddrInfo(const char* host,
610 // getaddrinfo() requires the port number as a string
611 char portString[sizeof("65535")];
612 snprintf(portString, sizeof(portString), "%" PRIu16, port);
614 return getAddrInfo(host, portString, flags);
617 struct addrinfo* SocketAddress::getAddrInfo(const char* host,
620 struct addrinfo hints;
621 memset(&hints, 0, sizeof(hints));
622 hints.ai_family = AF_UNSPEC;
623 hints.ai_socktype = SOCK_STREAM;
624 hints.ai_flags = AI_PASSIVE | AI_NUMERICSERV | flags;
626 struct addrinfo *results;
627 int error = getaddrinfo(host, port, &hints, &results);
629 auto os = folly::sformat(
630 "Failed to resolve address for '{}': {} (error={})",
634 throw std::system_error(error, std::generic_category(), os);
640 void SocketAddress::setFromAddrInfo(const struct addrinfo* info) {
641 setFromSockaddr(info->ai_addr, socklen_t(info->ai_addrlen));
644 void SocketAddress::setFromLocalAddr(const struct addrinfo* info) {
645 // If an IPv6 address is present, prefer to use it, since IPv4 addresses
646 // can be mapped into IPv6 space.
647 for (const struct addrinfo* ai = info; ai != nullptr; ai = ai->ai_next) {
648 if (ai->ai_family == AF_INET6) {
649 setFromSockaddr(ai->ai_addr, socklen_t(ai->ai_addrlen));
654 // Otherwise, just use the first address in the list.
655 setFromSockaddr(info->ai_addr, socklen_t(info->ai_addrlen));
658 void SocketAddress::setFromSocket(
660 int (*fn)(int, struct sockaddr*, socklen_t*)) {
661 // Try to put the address into a local storage buffer.
662 sockaddr_storage tmp_sock;
663 socklen_t addrLen = sizeof(tmp_sock);
664 if (fn(socket, (sockaddr*)&tmp_sock, &addrLen) != 0) {
665 folly::throwSystemError("setFromSocket() failed");
668 setFromSockaddr((sockaddr*)&tmp_sock, addrLen);
671 std::string SocketAddress::getIpString(int flags) const {
672 char addrString[NI_MAXHOST];
673 getIpString(addrString, sizeof(addrString), flags);
674 return std::string(addrString);
677 void SocketAddress::getIpString(char *buf, size_t buflen, int flags) const {
678 auto family = getFamily();
679 if (family != AF_INET &&
680 family != AF_INET6) {
681 throw std::invalid_argument(
682 "SocketAddress: attempting to get IP address "
683 "for a non-IP address");
686 sockaddr_storage tmp_sock;
687 storage_.addr.toSockaddrStorage(&tmp_sock, port_);
688 int rc = getnameinfo((sockaddr*)&tmp_sock, sizeof(sockaddr_storage),
689 buf, buflen, nullptr, 0, flags);
692 "getnameinfo() failed in getIpString() error = {}", gai_strerror(rc));
693 throw std::system_error(rc, std::generic_category(), os);
697 void SocketAddress::updateUnixAddressLength(socklen_t addrlen) {
698 if (addrlen < offsetof(struct sockaddr_un, sun_path)) {
699 throw std::invalid_argument(
700 "SocketAddress: attempted to set a Unix socket "
701 "with a length too short for a sockaddr_un");
704 storage_.un.len = addrlen;
705 if (storage_.un.pathLength() == 0) {
710 if (storage_.un.addr->sun_path[0] == '\0') {
711 // abstract namespace. honor the specified length
713 // Call strnlen(), just in case the length was overspecified.
714 size_t maxLength = addrlen - offsetof(struct sockaddr_un, sun_path);
715 size_t pathLength = strnlen(storage_.un.addr->sun_path, maxLength);
717 socklen_t(offsetof(struct sockaddr_un, sun_path) + pathLength);
721 bool SocketAddress::operator<(const SocketAddress& other) const {
722 if (getFamily() != other.getFamily()) {
723 return getFamily() < other.getFamily();
727 // Anonymous addresses can't be compared to anything else.
728 // Return that they are never less than anything.
730 // Note that this still meets the requirements for a strict weak
731 // ordering, so we can use this operator<() with standard C++ containers.
732 auto thisPathLength = storage_.un.pathLength();
733 if (thisPathLength == 0) {
736 auto otherPathLength = other.storage_.un.pathLength();
737 if (otherPathLength == 0) {
741 // Compare based on path length first, for efficiency
742 if (thisPathLength != otherPathLength) {
743 return thisPathLength < otherPathLength;
746 storage_.un.addr->sun_path,
747 other.storage_.un.addr->sun_path,
748 size_t(thisPathLength));
751 switch (getFamily()) {
754 if (port_ != other.port_) {
755 return port_ < other.port_;
759 storage_.addr < other.storage_.addr;
763 throw std::invalid_argument(
764 "SocketAddress: unsupported address family for comparing");
768 size_t hash_value(const SocketAddress& address) {
769 return address.hash();
772 std::ostream& operator<<(std::ostream& os, const SocketAddress& addr) {
773 os << addr.describe();