SocketAddress logging
[folly.git] / folly / SocketAddress.cpp
1 /*
2  * Copyright 2014 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 #ifndef __STDC_FORMAT_MACROS
18   #define __STDC_FORMAT_MACROS
19 #endif
20
21 #include <folly/SocketAddress.h>
22
23 #include <folly/Hash.h>
24
25 #include <boost/functional/hash.hpp>
26 #include <boost/static_assert.hpp>
27 #include <string.h>
28 #include <stdio.h>
29 #include <errno.h>
30 #include <sstream>
31 #include <string>
32 #include <execinfo.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35
36 namespace {
37
38 /**
39  * A structure to free a struct addrinfo when it goes out of scope.
40  */
41 struct ScopedAddrInfo {
42   explicit ScopedAddrInfo(struct addrinfo* info) : info(info) {}
43   ~ScopedAddrInfo() {
44     freeaddrinfo(info);
45   }
46
47   struct addrinfo* info;
48 };
49
50 /**
51  * A simple data structure for parsing a host-and-port string.
52  *
53  * Accepts a string of the form "<host>:<port>" or just "<port>",
54  * and contains two string pointers to the host and the port portion of the
55  * string.
56  *
57  * The HostAndPort may contain pointers into the original string.  It is
58  * responsible for the user to ensure that the input string is valid for the
59  * lifetime of the HostAndPort structure.
60  */
61 struct HostAndPort {
62   HostAndPort(const char* str, bool hostRequired)
63     : host(nullptr),
64       port(nullptr),
65       allocated(nullptr) {
66
67     // Look for the last colon
68     const char* colon = strrchr(str, ':');
69     if (colon == nullptr) {
70       // No colon, just a port number.
71       if (hostRequired) {
72         throw std::invalid_argument(
73           "expected a host and port string of the "
74           "form \"<host>:<port>\"");
75       }
76       port = str;
77       return;
78     }
79
80     // We have to make a copy of the string so we can modify it
81     // and change the colon to a NUL terminator.
82     allocated = strdup(str);
83     if (!allocated) {
84       throw std::bad_alloc();
85     }
86
87     char *allocatedColon = allocated + (colon - str);
88     *allocatedColon = '\0';
89     host = allocated;
90     port = allocatedColon + 1;
91     // bracketed IPv6 address, remove the brackets
92     // allocatedColon[-1] is fine, as allocatedColon >= host and
93     // *allocatedColon != *host therefore allocatedColon > host
94     if (*host == '[' && allocatedColon[-1] == ']') {
95       allocatedColon[-1] = '\0';
96       ++host;
97     }
98   }
99
100   ~HostAndPort() {
101     free(allocated);
102   }
103
104   const char* host;
105   const char* port;
106   char* allocated;
107 };
108
109 } // unnamed namespace
110
111 namespace folly {
112
113 bool SocketAddress::isPrivateAddress() const {
114   auto family = getFamily();
115   if (family == AF_INET || family == AF_INET6) {
116     return storage_.addr.isPrivate() ||
117       (storage_.addr.isV6() && storage_.addr.asV6().isLinkLocal());
118   } else if (external_) {
119     // Unix addresses are always local to a host.  Return true,
120     // since this conforms to the semantics of returning true for IP loopback
121     // addresses.
122     return true;
123   }
124   return false;
125 }
126
127 bool SocketAddress::isLoopbackAddress() const {
128   auto family = getFamily();
129   if (family == AF_INET || family == AF_INET6) {
130     return storage_.addr.isLoopback();
131   } else if (external_) {
132     // Return true for UNIX addresses, since they are always local to a host.
133     return true;
134   }
135   return false;
136 }
137
138 void SocketAddress::setFromHostPort(const char* host, uint16_t port) {
139   ScopedAddrInfo results(getAddrInfo(host, port, 0));
140   setFromAddrInfo(results.info);
141 }
142
143 void SocketAddress::setFromIpPort(const char* ip, uint16_t port) {
144   ScopedAddrInfo results(getAddrInfo(ip, port, AI_NUMERICHOST));
145   setFromAddrInfo(results.info);
146 }
147
148 void SocketAddress::setFromLocalPort(uint16_t port) {
149   ScopedAddrInfo results(getAddrInfo(nullptr, port, AI_ADDRCONFIG));
150   setFromLocalAddr(results.info);
151 }
152
153 void SocketAddress::setFromLocalPort(const char* port) {
154   ScopedAddrInfo results(getAddrInfo(nullptr, port, AI_ADDRCONFIG));
155   setFromLocalAddr(results.info);
156 }
157
158 void SocketAddress::setFromLocalIpPort(const char* addressAndPort) {
159   HostAndPort hp(addressAndPort, false);
160   ScopedAddrInfo results(getAddrInfo(hp.host, hp.port,
161                                      AI_NUMERICHOST | AI_ADDRCONFIG));
162   setFromLocalAddr(results.info);
163 }
164
165 void SocketAddress::setFromIpPort(const char* addressAndPort) {
166   HostAndPort hp(addressAndPort, true);
167   ScopedAddrInfo results(getAddrInfo(hp.host, hp.port, AI_NUMERICHOST));
168   setFromAddrInfo(results.info);
169 }
170
171 void SocketAddress::setFromHostPort(const char* hostAndPort) {
172   HostAndPort hp(hostAndPort, true);
173   ScopedAddrInfo results(getAddrInfo(hp.host, hp.port, 0));
174   setFromAddrInfo(results.info);
175 }
176
177 void SocketAddress::setFromPath(const char* path, size_t len) {
178   if (!external_) {
179     storage_.un.init();
180     external_ = true;
181   }
182
183   storage_.un.len = offsetof(struct sockaddr_un, sun_path) + len;
184   if (len > sizeof(storage_.un.addr->sun_path)) {
185     throw std::invalid_argument(
186       "socket path too large to fit into sockaddr_un");
187   } else if (len == sizeof(storage_.un.addr->sun_path)) {
188     // Note that there will be no terminating NUL in this case.
189     // We allow this since getsockname() and getpeername() may return
190     // Unix socket addresses with paths that fit exactly in sun_path with no
191     // terminating NUL.
192     memcpy(storage_.un.addr->sun_path, path, len);
193   } else {
194     memcpy(storage_.un.addr->sun_path, path, len + 1);
195   }
196 }
197
198 void SocketAddress::setFromPeerAddress(int socket) {
199   setFromSocket(socket, getpeername);
200 }
201
202 void SocketAddress::setFromLocalAddress(int socket) {
203   setFromSocket(socket, getsockname);
204 }
205
206 void SocketAddress::setFromSockaddr(const struct sockaddr* address) {
207   uint16_t port;
208
209   if (address->sa_family == AF_INET) {
210     port = ntohs(((sockaddr_in*)address)->sin_port);
211   } else if (address->sa_family == AF_INET6) {
212     port = ntohs(((sockaddr_in6*)address)->sin6_port);
213   } else if (address->sa_family == AF_UNIX) {
214     // We need an explicitly specified length for AF_UNIX addresses,
215     // to be able to distinguish anonymous addresses from addresses
216     // in Linux's abstract namespace.
217     throw std::invalid_argument(
218       "SocketAddress::setFromSockaddr(): the address "
219       "length must be explicitly specified when "
220       "setting AF_UNIX addresses");
221   } else {
222     throw std::invalid_argument(
223       "SocketAddress::setFromSockaddr() called "
224       "with unsupported address type");
225   }
226   if (external_) {
227     storage_.un.free();
228     external_ = false;
229   }
230   storage_.addr = folly::IPAddress(address);
231   port_ = port;
232 }
233
234 void SocketAddress::setFromSockaddr(const struct sockaddr* address,
235                                      socklen_t addrlen) {
236   // Check the length to make sure we can access address->sa_family
237   if (addrlen < (offsetof(struct sockaddr, sa_family) +
238                  sizeof(address->sa_family))) {
239     throw std::invalid_argument(
240       "SocketAddress::setFromSockaddr() called "
241       "with length too short for a sockaddr");
242   }
243
244   if (address->sa_family == AF_INET) {
245     if (addrlen < sizeof(struct sockaddr_in)) {
246       throw std::invalid_argument(
247         "SocketAddress::setFromSockaddr() called "
248         "with length too short for a sockaddr_in");
249     }
250     setFromSockaddr(reinterpret_cast<const struct sockaddr_in*>(address));
251   } else if (address->sa_family == AF_INET6) {
252     if (addrlen < sizeof(struct sockaddr_in6)) {
253       throw std::invalid_argument(
254         "SocketAddress::setFromSockaddr() called "
255         "with length too short for a sockaddr_in6");
256     }
257     setFromSockaddr(reinterpret_cast<const struct sockaddr_in6*>(address));
258   } else if (address->sa_family == AF_UNIX) {
259     setFromSockaddr(reinterpret_cast<const struct sockaddr_un*>(address),
260                     addrlen);
261   } else {
262     throw std::invalid_argument(
263       "SocketAddress::setFromSockaddr() called "
264       "with unsupported address type");
265   }
266 }
267
268 void SocketAddress::setFromSockaddr(const struct sockaddr_in* address) {
269   assert(address->sin_family == AF_INET);
270   setFromSockaddr((sockaddr*)address);
271 }
272
273 void SocketAddress::setFromSockaddr(const struct sockaddr_in6* address) {
274   assert(address->sin6_family == AF_INET6);
275   setFromSockaddr((sockaddr*)address);
276 }
277
278 void SocketAddress::setFromSockaddr(const struct sockaddr_un* address,
279                                      socklen_t addrlen) {
280   assert(address->sun_family == AF_UNIX);
281   if (addrlen > sizeof(struct sockaddr_un)) {
282     throw std::invalid_argument(
283       "SocketAddress::setFromSockaddr() called "
284       "with length too long for a sockaddr_un");
285   }
286
287   prepFamilyChange(AF_UNIX);
288   memcpy(storage_.un.addr, address, addrlen);
289   updateUnixAddressLength(addrlen);
290
291   // Fill the rest with 0s, just for safety
292   if (addrlen < sizeof(struct sockaddr_un)) {
293     char *p = reinterpret_cast<char*>(storage_.un.addr);
294     memset(p + addrlen, 0, sizeof(struct sockaddr_un) - addrlen);
295   }
296 }
297
298 const folly::IPAddress& SocketAddress::getIPAddress() const {
299   auto family = getFamily();
300   if (family != AF_INET && family != AF_INET6) {
301     throw InvalidAddressFamilyException(family);
302   }
303   return storage_.addr;
304 }
305
306 socklen_t SocketAddress::getActualSize() const {
307   if (external_) {
308     return storage_.un.len;
309   }
310   switch (getFamily()) {
311     case AF_UNSPEC:
312     case AF_INET:
313       return sizeof(struct sockaddr_in);
314     case AF_INET6:
315       return sizeof(struct sockaddr_in6);
316     default:
317       throw std::invalid_argument(
318         "SocketAddress::getActualSize() called "
319         "with unrecognized address family");
320   }
321 }
322
323 std::string SocketAddress::getFullyQualified() const {
324   auto family = getFamily();
325   if (family != AF_INET && family != AF_INET6) {
326     throw std::invalid_argument("Can't get address str for non ip address");
327   }
328   return storage_.addr.toFullyQualified();
329 }
330
331 std::string SocketAddress::getAddressStr() const {
332   char buf[INET6_ADDRSTRLEN];
333   getAddressStr(buf, sizeof(buf));
334   return buf;
335 }
336
337 void SocketAddress::getAddressStr(char* buf, size_t buflen) const {
338   auto family = getFamily();
339   if (family != AF_INET && family != AF_INET6) {
340     throw std::invalid_argument("Can't get address str for non ip address");
341   }
342   std::string ret = storage_.addr.str();
343   size_t len = std::min(buflen, ret.size());
344   memcpy(buf, ret.data(), len);
345   buf[len] = '\0';
346 }
347
348 uint16_t SocketAddress::getPort() const {
349   switch (getFamily()) {
350     case AF_INET:
351     case AF_INET6:
352       return port_;
353     default:
354       throw std::invalid_argument(
355         "SocketAddress::getPort() called on non-IP "
356         "address");
357   }
358 }
359
360 void SocketAddress::setPort(uint16_t port) {
361   switch (getFamily()) {
362     case AF_INET:
363     case AF_INET6:
364       port_ = port;
365       return;
366     default:
367       throw std::invalid_argument(
368         "SocketAddress::setPort() called on non-IP "
369         "address");
370   }
371 }
372
373 void SocketAddress::convertToIPv4() {
374   if (!tryConvertToIPv4()) {
375     throw std::invalid_argument(
376       "convertToIPv4() called on an addresse that is "
377       "not an IPv4-mapped address");
378   }
379 }
380
381 bool SocketAddress::tryConvertToIPv4() {
382   if (!isIPv4Mapped()) {
383     return false;
384   }
385
386   storage_.addr = folly::IPAddress::createIPv4(storage_.addr);
387   return true;
388 }
389
390 bool SocketAddress::mapToIPv6() {
391   if (getFamily() != AF_INET) {
392     return false;
393   }
394
395   storage_.addr = folly::IPAddress::createIPv6(storage_.addr);
396   return true;
397 }
398
399 std::string SocketAddress::getHostStr() const {
400   return getIpString(0);
401 }
402
403 std::string SocketAddress::getPath() const {
404   if (!external_) {
405     throw std::invalid_argument(
406       "SocketAddress: attempting to get path "
407       "for a non-Unix address");
408   }
409
410   if (storage_.un.pathLength() == 0) {
411     // anonymous address
412     return std::string();
413   }
414   if (storage_.un.addr->sun_path[0] == '\0') {
415     // abstract namespace
416     return std::string(storage_.un.addr->sun_path, storage_.un.pathLength());
417   }
418
419   return std::string(storage_.un.addr->sun_path,
420                      strnlen(storage_.un.addr->sun_path,
421                              storage_.un.pathLength()));
422 }
423
424 std::string SocketAddress::describe() const {
425   if (external_) {
426     if (storage_.un.pathLength() == 0) {
427       return "<anonymous unix address>";
428     }
429
430     if (storage_.un.addr->sun_path[0] == '\0') {
431       // Linux supports an abstract namespace for unix socket addresses
432       return "<abstract unix address>";
433     }
434
435     return std::string(storage_.un.addr->sun_path,
436                        strnlen(storage_.un.addr->sun_path,
437                                storage_.un.pathLength()));
438   }
439   switch (getFamily()) {
440     case AF_UNSPEC:
441       return "<uninitialized address>";
442     case AF_INET:
443     {
444       char buf[NI_MAXHOST + 16];
445       getAddressStr(buf, sizeof(buf));
446       size_t iplen = strlen(buf);
447       snprintf(buf + iplen, sizeof(buf) - iplen, ":%" PRIu16, getPort());
448       return buf;
449     }
450     case AF_INET6:
451     {
452       char buf[NI_MAXHOST + 18];
453       buf[0] = '[';
454       getAddressStr(buf + 1, sizeof(buf) - 1);
455       size_t iplen = strlen(buf);
456       snprintf(buf + iplen, sizeof(buf) - iplen, "]:%" PRIu16, getPort());
457       return buf;
458     }
459     default:
460     {
461       char buf[64];
462       snprintf(buf, sizeof(buf), "<unknown address family %d>",
463                getFamily());
464       return buf;
465     }
466   }
467 }
468
469 bool SocketAddress::operator==(const SocketAddress& other) const {
470   if (external_ != other.external_ || other.getFamily() != getFamily()) {
471     return false;
472   }
473   if (external_) {
474     // anonymous addresses are never equal to any other addresses
475     if (storage_.un.pathLength() == 0 ||
476         other.storage_.un.pathLength() == 0) {
477       return false;
478     }
479
480     if (storage_.un.len != other.storage_.un.len) {
481       return false;
482     }
483     int cmp = memcmp(storage_.un.addr->sun_path,
484                      other.storage_.un.addr->sun_path,
485                      storage_.un.pathLength());
486     return cmp == 0;
487   }
488
489   switch (getFamily()) {
490     case AF_INET:
491     case AF_INET6:
492       return (other.storage_.addr == storage_.addr) &&
493         (other.port_ == port_);
494     default:
495       throw std::invalid_argument(
496         "SocketAddress: unsupported address family "
497         "for comparison");
498   }
499 }
500
501 bool SocketAddress::prefixMatch(const SocketAddress& other,
502     unsigned prefixLength) const {
503   if (other.getFamily() != getFamily()) {
504     return false;
505   }
506   int mask_length = 128;
507   switch (getFamily()) {
508     case AF_INET:
509       mask_length = 32;
510       // fallthrough
511     case AF_INET6:
512     {
513       auto prefix = folly::IPAddress::longestCommonPrefix(
514         {storage_.addr, mask_length},
515         {other.storage_.addr, mask_length});
516       return prefix.second >= prefixLength;
517     }
518     default:
519       return false;
520   }
521 }
522
523
524 size_t SocketAddress::hash() const {
525   size_t seed = folly::hash::twang_mix64(getFamily());
526
527   if (external_) {
528     enum { kUnixPathMax = sizeof(storage_.un.addr->sun_path) };
529     const char *path = storage_.un.addr->sun_path;
530     size_t pathLength = storage_.un.pathLength();
531     // TODO: this probably could be made more efficient
532     for (unsigned int n = 0; n < pathLength; ++n) {
533       boost::hash_combine(seed, folly::hash::twang_mix64(path[n]));
534     }
535   }
536
537   switch (getFamily()) {
538     case AF_INET:
539     case AF_INET6: {
540       boost::hash_combine(seed, port_);
541       boost::hash_combine(seed, storage_.addr.hash());
542       break;
543     }
544     case AF_UNIX:
545       DCHECK(external_);
546       break;
547     case AF_UNSPEC:
548     default:
549       void *array[20];
550       size_t size;
551       // get void*'s for all entries on the stack
552       size = backtrace(array, 20);
553       // print out all the frames to stderr
554       fprintf(stderr, "Exception: \n");
555       backtrace_symbols_fd(array, size, STDERR_FILENO);
556       LOG(FATAL) << "Invalid ip address: " << describe();
557       throw std::invalid_argument(
558         "SocketAddress: unsupported address family "
559         "for hashing");
560   }
561
562   return seed;
563 }
564
565 struct addrinfo* SocketAddress::getAddrInfo(const char* host,
566                                              uint16_t port,
567                                              int flags) {
568   // getaddrinfo() requires the port number as a string
569   char portString[sizeof("65535")];
570   snprintf(portString, sizeof(portString), "%" PRIu16, port);
571
572   return getAddrInfo(host, portString, flags);
573 }
574
575 struct addrinfo* SocketAddress::getAddrInfo(const char* host,
576                                              const char* port,
577                                              int flags) {
578   struct addrinfo hints;
579   memset(&hints, 0, sizeof(hints));
580   hints.ai_family = AF_UNSPEC;
581   hints.ai_socktype = SOCK_STREAM;
582   hints.ai_flags = AI_PASSIVE | AI_NUMERICSERV | flags;
583
584   struct addrinfo *results;
585   int error = getaddrinfo(host, port, &hints, &results);
586   if (error != 0) {
587     auto os = folly::to<std::string>(
588       "Failed to resolve address for \"", host,  "\": ",
589       gai_strerror(error), " (error=", error,  ")");
590     throw std::system_error(error, std::generic_category(), os);
591   }
592
593   return results;
594 }
595
596 void SocketAddress::setFromAddrInfo(const struct addrinfo* info) {
597   setFromSockaddr(info->ai_addr, info->ai_addrlen);
598 }
599
600 void SocketAddress::setFromLocalAddr(const struct addrinfo* info) {
601   // If an IPv6 address is present, prefer to use it, since IPv4 addresses
602   // can be mapped into IPv6 space.
603   for (const struct addrinfo* ai = info; ai != nullptr; ai = ai->ai_next) {
604     if (ai->ai_family == AF_INET6) {
605       setFromSockaddr(ai->ai_addr, ai->ai_addrlen);
606       return;
607     }
608   }
609
610   // Otherwise, just use the first address in the list.
611   setFromSockaddr(info->ai_addr, info->ai_addrlen);
612 }
613
614 void SocketAddress::setFromSocket(int socket,
615                                   int (*fn)(int, sockaddr*, socklen_t*)) {
616   // Try to put the address into a local storage buffer.
617   sockaddr_storage tmp_sock;
618   socklen_t addrLen = sizeof(tmp_sock);
619   if (fn(socket, (sockaddr*)&tmp_sock, &addrLen) != 0) {
620     folly::throwSystemError("setFromSocket() failed");
621   }
622
623   setFromSockaddr((sockaddr*)&tmp_sock, addrLen);
624 }
625
626 std::string SocketAddress::getIpString(int flags) const {
627   char addrString[NI_MAXHOST];
628   getIpString(addrString, sizeof(addrString), flags);
629   return std::string(addrString);
630 }
631
632 void SocketAddress::getIpString(char *buf, size_t buflen, int flags) const {
633   auto family = getFamily();
634   if (family != AF_INET &&
635       family != AF_INET6) {
636     throw std::invalid_argument(
637       "SocketAddress: attempting to get IP address "
638       "for a non-IP address");
639   }
640
641   sockaddr_storage tmp_sock;
642   storage_.addr.toSockaddrStorage(&tmp_sock, port_);
643   int rc = getnameinfo((sockaddr*)&tmp_sock, sizeof(sockaddr_storage),
644                        buf, buflen, nullptr, 0, flags);
645   if (rc != 0) {
646     auto os = folly::to<std::string>(
647       "getnameinfo() failed in getIpString() error = ",
648       gai_strerror(rc));
649     throw std::system_error(rc, std::generic_category(), os);
650   }
651 }
652
653 void SocketAddress::updateUnixAddressLength(socklen_t addrlen) {
654   if (addrlen < offsetof(struct sockaddr_un, sun_path)) {
655     throw std::invalid_argument(
656       "SocketAddress: attempted to set a Unix socket "
657       "with a length too short for a sockaddr_un");
658   }
659
660   storage_.un.len = addrlen;
661   if (storage_.un.pathLength() == 0) {
662     // anonymous address
663     return;
664   }
665
666   if (storage_.un.addr->sun_path[0] == '\0') {
667     // abstract namespace.  honor the specified length
668   } else {
669     // Call strnlen(), just in case the length was overspecified.
670     socklen_t maxLength = addrlen - offsetof(struct sockaddr_un, sun_path);
671     size_t pathLength = strnlen(storage_.un.addr->sun_path, maxLength);
672     storage_.un.len = offsetof(struct sockaddr_un, sun_path) + pathLength;
673   }
674 }
675
676 bool SocketAddress::operator<(const SocketAddress& other) const {
677   if (getFamily() != other.getFamily()) {
678     return getFamily() < other.getFamily();
679   }
680
681   if (external_) {
682     // Anonymous addresses can't be compared to anything else.
683     // Return that they are never less than anything.
684     //
685     // Note that this still meets the requirements for a strict weak
686     // ordering, so we can use this operator<() with standard C++ containers.
687     size_t thisPathLength = storage_.un.pathLength();
688     if (thisPathLength == 0) {
689       return false;
690     }
691     size_t otherPathLength = other.storage_.un.pathLength();
692     if (otherPathLength == 0) {
693       return true;
694     }
695
696     // Compare based on path length first, for efficiency
697     if (thisPathLength != otherPathLength) {
698       return thisPathLength < otherPathLength;
699     }
700     int cmp = memcmp(storage_.un.addr->sun_path,
701                      other.storage_.un.addr->sun_path,
702                      thisPathLength);
703     return cmp < 0;
704   }
705   switch (getFamily()) {
706     case AF_INET:
707     case AF_INET6: {
708       if (port_ != other.port_) {
709         return port_ < other.port_;
710       }
711
712       return
713         storage_.addr < other.storage_.addr;
714     }
715     case AF_UNSPEC:
716     default:
717       throw std::invalid_argument(
718         "SocketAddress: unsupported address family for comparing");
719   }
720 }
721
722 size_t hash_value(const SocketAddress& address) {
723   return address.hash();
724 }
725
726 std::ostream& operator<<(std::ostream& os, const SocketAddress& addr) {
727   os << addr.describe();
728   return os;
729 }
730
731 } // folly