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