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