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