Skip to content

Commit

Permalink
refactor
Browse files Browse the repository at this point in the history
Signed-off-by: chaoqin-li1123 <chaoqinli@google.com>
  • Loading branch information
chaoqin-li1123 committed May 5, 2021
1 parent e22e4a1 commit 8dba38f
Show file tree
Hide file tree
Showing 25 changed files with 480 additions and 141 deletions.
1 change: 1 addition & 0 deletions include/envoy/network/address.h
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ class Instance {
};

using InstanceConstSharedPtr = std::shared_ptr<const Instance>;
using InstanceConstPtr = std::unique_ptr<const Instance>;

} // namespace Address
} // namespace Network
Expand Down
2 changes: 2 additions & 0 deletions source/common/network/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ envoy_cc_library(
"//include/envoy/network:address_interface",
"//source/common/api:os_sys_calls_lib",
"//source/common/common:assert_lib",
"//source/common/common:statusor_lib",
"//source/common/common:thread_lib",
"//source/common/common:safe_memcpy_lib",
"//source/common/common:utility_lib",
],
Expand Down
253 changes: 226 additions & 27 deletions source/common/network/address_impl.cc

Large diffs are not rendered by default.

108 changes: 106 additions & 2 deletions source/common/network/address_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
#include "envoy/network/socket.h"

#include "common/common/assert.h"
#include "common/common/statusor.h"
#include "common/common/thread.h"

namespace Envoy {
namespace Network {
Expand All @@ -25,8 +27,8 @@ namespace Address {
* @param v6only disable IPv4-IPv6 mapping for IPv6 addresses?
* @return InstanceConstSharedPtr the address.
*/
InstanceConstSharedPtr addressFromSockAddr(const sockaddr_storage& ss, socklen_t len,
bool v6only = true);
StatusOr<InstanceConstSharedPtr> addressFromSockAddr(const sockaddr_storage& ss, socklen_t len,
bool v6only = true);

/**
* Base class for all address types.
Expand All @@ -53,6 +55,37 @@ class InstanceBase : public Instance {
const Type type_;
};

class InstanceFactory {
public:
template <typename InstanceType, typename... Args>
static StatusOr<InstanceConstPtr> createInstancePtr(Args&&... args) {
absl::Status status;
status = InstanceType::validateProtocolSupported();
if (!status.ok()) {
return status;
}
std::unique_ptr<InstanceType> instance(new InstanceType(status, std::forward<Args>(args)...));
if (!status.ok()) {
return status;
}
return instance;
}

template <typename InstanceType, typename... Args>
static StatusOr<InstanceType> createInstance(Args&&... args) {
absl::Status status;
status = InstanceType::validateProtocolSupported();
if (!status.ok()) {
return status;
}
InstanceType instance(status, std::forward<Args>(args)...);
if (!status.ok()) {
return status;
}
return instance;
}
};

/**
* Implementation of an IPv4 address.
*/
Expand Down Expand Up @@ -82,6 +115,31 @@ class Ipv4Instance : public InstanceBase {
*/
explicit Ipv4Instance(uint32_t port, const SocketInterface* sock_interface = nullptr);

/**
* Construct from an existing unix IPv4 socket address (IP v4 address and port).
*/
explicit Ipv4Instance(absl::Status& error, const sockaddr_in* address,
const SocketInterface* sock_interface = nullptr);

/**
* Construct from a string IPv4 address such as "1.2.3.4". Port will be unset/0.
*/
explicit Ipv4Instance(absl::Status& error, const std::string& address,
const SocketInterface* sock_interface = nullptr);

/**
* Construct from a string IPv4 address such as "1.2.3.4" as well as a port.
*/
Ipv4Instance(absl::Status& error, const std::string& address, uint32_t port,
const SocketInterface* sock_interface = nullptr);

/**
* Construct from a port. The IPv4 address will be set to "any" and is suitable for binding
* a port to any available address.
*/
explicit Ipv4Instance(absl::Status& error, uint32_t port,
const SocketInterface* sock_interface = nullptr);

// Network::Address::Instance
bool operator==(const Instance& rhs) const override;
const Ip* ip() const override { return &ip_; }
Expand All @@ -100,6 +158,10 @@ class Ipv4Instance : public InstanceBase {
*/
static std::string sockaddrToString(const sockaddr_in& addr);

// Validate that IPv4 is supported on this platform, raise an exception for the
// given address if not.
static absl::Status validateProtocolSupported();

private:
struct Ipv4Helper : public Ipv4 {
uint32_t address() const override { return address_.sin_addr.s_addr; }
Expand Down Expand Up @@ -156,6 +218,31 @@ class Ipv6Instance : public InstanceBase {
*/
explicit Ipv6Instance(uint32_t port, const SocketInterface* sock_interface = nullptr);

/**
* Construct from an existing unix IPv6 socket address (IP v6 address and port).
*/
Ipv6Instance(absl::Status& error, const sockaddr_in6& address, bool v6only = true,
const SocketInterface* sock_interface = nullptr);

/**
* Construct from a string IPv6 address such as "12:34::5". Port will be unset/0.
*/
explicit Ipv6Instance(absl::Status& error, const std::string& address,
const SocketInterface* sock_interface = nullptr);

/**
* Construct from a string IPv6 address such as "12:34::5" as well as a port.
*/
Ipv6Instance(absl::Status& error, const std::string& address, uint32_t port,
const SocketInterface* sock_interface = nullptr);

/**
* Construct from a port. The IPv6 address will be set to "any" and is suitable for binding
* a port to any available address.
*/
explicit Ipv6Instance(absl::Status& error, uint32_t port,
const SocketInterface* sock_interface = nullptr);

// Network::Address::Instance
bool operator==(const Instance& rhs) const override;
const Ip* ip() const override { return &ip_; }
Expand All @@ -166,6 +253,9 @@ class Ipv6Instance : public InstanceBase {
}
socklen_t sockAddrLen() const override { return sizeof(sockaddr_in6); }

// Validate that IPv6 is supported on this platform
static absl::Status validateProtocolSupported();

private:
struct Ipv6Helper : public Ipv6 {
Ipv6Helper() { memset(&address_, 0, sizeof(address_)); }
Expand Down Expand Up @@ -219,6 +309,20 @@ class PipeInstance : public InstanceBase {
explicit PipeInstance(const std::string& pipe_path, mode_t mode = 0,
const SocketInterface* sock_interface = nullptr);

/**
* Construct from an existing unix address.
*/
explicit PipeInstance(absl::Status& error, const sockaddr_un* address, socklen_t ss_len,
mode_t mode = 0, const SocketInterface* sock_interface = nullptr);

/**
* Construct from a string pipe path.
*/
explicit PipeInstance(absl::Status& error, const std::string& pipe_path, mode_t mode = 0,
const SocketInterface* sock_interface = nullptr);

static absl::Status validateProtocolSupported() { return absl::OkStatus(); }

// Network::Address::Instance
bool operator==(const Instance& rhs) const override;
const Ip* ip() const override { return nullptr; }
Expand Down
39 changes: 21 additions & 18 deletions source/common/network/io_socket_handle_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#include "absl/container/fixed_array.h"
#include "absl/types/optional.h"
#include "source/common/common/_virtual_includes/statusor_lib/common/common/statusor.h"

using Envoy::Api::SysCallIntResult;
using Envoy::Api::SysCallSizeResult;
Expand Down Expand Up @@ -277,22 +278,20 @@ Api::IoCallUint64Result IoSocketHandleImpl::sendmsg(const Buffer::RawSlice* slic

Address::InstanceConstSharedPtr getAddressFromSockAddrOrDie(const sockaddr_storage& ss,
socklen_t ss_len, os_fd_t fd) {
// TODO(chaoqin-li1123): remove exception catching and make Address::addressFromSockAddr return
// null on error.
TRY_NEEDS_AUDIT {
// Set v6only to false so that mapped-v6 address can be normalize to v4
// address. Though dual stack may be disabled, it's still okay to assume the
// address is from a dual stack socket. This is because mapped-v6 address
// must come from a dual stack socket. An actual v6 address can come from
// both dual stack socket and v6 only socket. If |peer_addr| is an actual v6
// address and the socket is actually v6 only, the returned address will be
// regarded as a v6 address from dual stack socket. However, this address is not going to be
// used to create socket. Wrong knowledge of dual stack support won't hurt.
return Address::addressFromSockAddr(ss, ss_len, /*v6only=*/false);
}
catch (const EnvoyException& e) {
PANIC(fmt::format("Invalid address for fd: {}, error: {}", fd, e.what()));
}
// Set v6only to false so that mapped-v6 address can be normalize to v4
// address. Though dual stack may be disabled, it's still okay to assume the
// address is from a dual stack socket. This is because mapped-v6 address
// must come from a dual stack socket. An actual v6 address can come from
// both dual stack socket and v6 only socket. If |peer_addr| is an actual v6
// address and the socket is actually v6 only, the returned address will be
// regarded as a v6 address from dual stack socket. However, this address is not going to be
// used to create socket. Wrong knowledge of dual stack support won't hurt.
StatusOr<Address::InstanceConstSharedPtr> error_or_addr =
Address::addressFromSockAddr(ss, ss_len, /*v6only=*/false);
if (!error_or_addr.ok()) {
PANIC(fmt::format("Invalid address for fd: {}", fd));
}
return *error_or_addr;
}

Address::InstanceConstSharedPtr maybeGetDstAddressFromHeader(const cmsghdr& cmsg,
Expand Down Expand Up @@ -605,7 +604,9 @@ Address::InstanceConstSharedPtr IoSocketHandleImpl::localAddress() {
throw EnvoyException(fmt::format("getsockname failed for '{}': ({}) {}", fd_, result.errno_,
errorDetails(result.errno_)));
}
return Address::addressFromSockAddr(ss, ss_len, socket_v6only_);
StatusOr<Address::InstanceConstSharedPtr> error_or_address = Address::addressFromSockAddr(ss, ss_len, socket_v6only_);
ASSERT(error_or_address.ok());
return *error_or_address;
}

Address::InstanceConstSharedPtr IoSocketHandleImpl::peerAddress() {
Expand All @@ -630,7 +631,9 @@ Address::InstanceConstSharedPtr IoSocketHandleImpl::peerAddress() {
fmt::format("getsockname failed for '{}': {}", fd_, errorDetails(result.errno_)));
}
}
return Address::addressFromSockAddr(ss, ss_len);
StatusOr<Address::InstanceConstSharedPtr> error_or_address = Address::addressFromSockAddr(ss, ss_len);
ASSERT(error_or_address.ok());
return *error_or_address;
}

void IoSocketHandleImpl::initializeFileEvent(Event::Dispatcher& dispatcher, Event::FileReadyCb cb,
Expand Down
15 changes: 9 additions & 6 deletions source/common/network/tcp_listener_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -82,12 +82,15 @@ void TcpListenerImpl::onSocketEvent(short flags) {
// Pass the 'v6only' parameter as true if the local_address is an IPv6 address. This has no
// effect if the socket is a v4 socket, but for v6 sockets this will create an IPv4 remote
// address if an IPv4 local_address was created from an IPv6 mapped IPv4 address.
const Address::InstanceConstSharedPtr& remote_address =
(remote_addr.ss_family == AF_UNIX)
? io_handle->peerAddress()
: Address::addressFromSockAddr(remote_addr, remote_addr_len,
local_address->ip()->version() ==
Address::IpVersion::v6);
Address::InstanceConstSharedPtr remote_address;
if (remote_addr.ss_family == AF_UNIX) {
remote_address = io_handle->peerAddress();
} else {
StatusOr<Address::InstanceConstSharedPtr> error_or_address = Address::addressFromSockAddr(
remote_addr, remote_addr_len, local_address->ip()->version() == Address::IpVersion::v6);
ASSERT(error_or_address.ok());
remote_address = *error_or_address;
}

cb_.onAccept(
std::make_unique<AcceptedSocketImpl>(std::move(io_handle), local_address, remote_address));
Expand Down
53 changes: 43 additions & 10 deletions source/common/network/utility.cc
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "envoy/common/exception.h"
#include "envoy/common/platform.h"
#include "envoy/config/core/v3/address.pb.h"
#include "envoy/network/address.h"
#include "envoy/network/connection.h"

#include "common/api/os_sys_calls_impl.h"
Expand All @@ -27,6 +28,7 @@
#include "absl/container/fixed_array.h"
#include "absl/strings/match.h"
#include "absl/strings/string_view.h"
#include "source/common/common/_virtual_includes/statusor_lib/common/common/statusor.h"

namespace Envoy {
namespace Network {
Expand Down Expand Up @@ -128,18 +130,25 @@ uint32_t Utility::portFromUdpUrl(const std::string& url) {

Address::InstanceConstSharedPtr Utility::parseInternetAddressNoThrow(const std::string& ip_address,
uint16_t port, bool v6only) {
Address::InstanceConstSharedPtr address;
sockaddr_in sa4;
if (inet_pton(AF_INET, ip_address.c_str(), &sa4.sin_addr) == 1) {
sa4.sin_family = AF_INET;
sa4.sin_port = htons(port);
return std::make_shared<Address::Ipv4Instance>(&sa4);
StatusOr<Address::InstanceConstSharedPtr> error_or_address =
Address::InstanceFactory::createInstancePtr<Address::Ipv4Instance>(&sa4);
ASSERT(error_or_address.ok());
return *error_or_address;
}
sockaddr_in6 sa6;
memset(&sa6, 0, sizeof(sa6));
if (inet_pton(AF_INET6, ip_address.c_str(), &sa6.sin6_addr) == 1) {
sa6.sin6_family = AF_INET6;
sa6.sin6_port = htons(port);
return std::make_shared<Address::Ipv6Instance>(sa6, v6only);
StatusOr<Address::InstanceConstSharedPtr> error_or_address =
Address::InstanceFactory::createInstancePtr<Address::Ipv6Instance>(sa6, v6only);
ASSERT(error_or_address.ok());
return *error_or_address;
}
return nullptr;
}
Expand Down Expand Up @@ -178,7 +187,10 @@ Utility::parseInternetAddressAndPortNoThrow(const std::string& ip_address, bool
}
sa6.sin6_family = AF_INET6;
sa6.sin6_port = htons(port64);
return std::make_shared<Address::Ipv6Instance>(sa6, v6only);
StatusOr<Address::InstanceConstSharedPtr> error_or_address =
Address::InstanceFactory::createInstancePtr<Address::Ipv6Instance>(sa6, v6only);
ASSERT(error_or_address.ok());
return *error_or_address;
}
// Treat it as an IPv4 address followed by a port.
const auto pos = ip_address.rfind(':');
Expand All @@ -198,7 +210,10 @@ Utility::parseInternetAddressAndPortNoThrow(const std::string& ip_address, bool
}
sa4.sin_family = AF_INET;
sa4.sin_port = htons(port64);
return std::make_shared<Address::Ipv4Instance>(&sa4);
StatusOr<Address::InstanceConstSharedPtr> error_or_address =
Address::InstanceFactory::createInstancePtr<Address::Ipv4Instance>(&sa4);
ASSERT(error_or_address.ok());
return *error_or_address;
}

Address::InstanceConstSharedPtr Utility::parseInternetAddressAndPort(const std::string& ip_address,
Expand Down Expand Up @@ -246,8 +261,10 @@ Address::InstanceConstSharedPtr Utility::getLocalAddress(const Address::IpVersio
(ifa->ifa_addr->sa_family == AF_INET6 && version == Address::IpVersion::v6)) {
const struct sockaddr_storage* addr =
reinterpret_cast<const struct sockaddr_storage*>(ifa->ifa_addr);
ret = Address::addressFromSockAddr(
StatusOr<Address::InstanceConstSharedPtr> error_or_instance = Address::addressFromSockAddr(
*addr, (version == Address::IpVersion::v4) ? sizeof(sockaddr_in) : sizeof(sockaddr_in6));
ASSERT(error_or_instance.ok());
ret = *error_or_instance;
if (!isLoopbackAddress(*ret)) {
break;
}
Expand Down Expand Up @@ -366,17 +383,28 @@ const std::string& Utility::getIpv6CidrCatchAllAddress() {
CONSTRUCT_ON_FIRST_USE(std::string, "::/0");
}

Address::InstanceConstSharedPtr Utility::getAddressWithPort(const Address::Instance& address,
uint32_t port) {
StatusOr<Address::InstanceConstSharedPtr>
Utility::getAddressWithPort(const Address::Instance& address, uint32_t port) {
switch (address.ip()->version()) {
case Address::IpVersion::v4:
return std::make_shared<Address::Ipv4Instance>(address.ip()->addressAsString(), port);
return Address::InstanceFactory::createInstancePtr<Address::Ipv4Instance>(
address.ip()->addressAsString(), port);
case Address::IpVersion::v6:
return std::make_shared<Address::Ipv6Instance>(address.ip()->addressAsString(), port);
return Address::InstanceFactory::createInstancePtr<Address::Ipv6Instance>(
address.ip()->addressAsString(), port);
}
NOT_REACHED_GCOVR_EXCL_LINE;
}

Address::InstanceConstSharedPtr Utility::getAddressWithPortOrThrow(const Address::Instance& address,
uint32_t port) {
StatusOr<Address::InstanceConstSharedPtr> error_or_address = getAddressWithPort(address, port);
if (!error_or_address.ok()) {
throw EnvoyException(error_or_address.status().ToString());
}
return *error_or_address;
}

Address::InstanceConstSharedPtr Utility::getOriginalDst(Socket& sock) {
#ifdef SOL_IP

Expand Down Expand Up @@ -404,7 +432,12 @@ Address::InstanceConstSharedPtr Utility::getOriginalDst(Socket& sock) {
return nullptr;
}

return Address::addressFromSockAddr(orig_addr, 0, true /* default for v6 constructor */);
StatusOr<Address::InstanceConstSharedPtr> error_or_address =
Address::addressFromSockAddr(orig_addr, 0, true /* default for v6 constructor */);
if (!error_or_address.ok()) {
throw EnvoyException(error_or_address.status().ToString());
}
return *error_or_address;
#else
// TODO(zuercher): determine if connection redirection is possible under macOS (c.f. pfctl and
// divert), and whether it's possible to find the learn destination address.
Expand Down
Loading

0 comments on commit 8dba38f

Please sign in to comment.