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