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