Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 0 additions & 60 deletions source/common/network/address_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -220,65 +220,5 @@ int PipeInstance::socket(SocketType type) const {
return ::socket(AF_UNIX, flagsFromSocketType(type), 0);
}

InstanceConstSharedPtr parseInternetAddress(const std::string& ip_addr) {
sockaddr_in sa4;
if (inet_pton(AF_INET, ip_addr.c_str(), &sa4.sin_addr) == 1) {
sa4.sin_family = AF_INET;
sa4.sin_port = 0;
return std::make_shared<Ipv4Instance>(&sa4);
}
sockaddr_in6 sa6;
if (inet_pton(AF_INET6, ip_addr.c_str(), &sa6.sin6_addr) == 1) {
sa6.sin6_family = AF_INET6;
sa6.sin6_port = 0;
return std::make_shared<Ipv6Instance>(sa6);
}
return nullptr;
}

InstanceConstSharedPtr parseInternetAddressAndPort(const std::string& addr) {
if (addr.empty()) {
return nullptr;
}
if (addr[0] == '[') {
// Appears to be an IPv6 address. Find the "]:" that separates the address from the port.
auto pos = addr.rfind("]:");
if (pos == std::string::npos) {
return nullptr;
}
const auto ip_str = addr.substr(1, pos - 1);
const auto port_str = addr.substr(pos + 2);
uint64_t port64;
if (port_str.empty() || !StringUtil::atoul(port_str.c_str(), port64, 10) || port64 > 65535) {
return nullptr;
}
sockaddr_in6 sa6;
if (ip_str.empty() || inet_pton(AF_INET6, ip_str.c_str(), &sa6.sin6_addr) != 1) {
return nullptr;
}
sa6.sin6_family = AF_INET6;
sa6.sin6_port = htons(port64);
return std::make_shared<Ipv6Instance>(sa6);
}
// Treat it as an IPv4 address followed by a port.
auto pos = addr.rfind(":");
if (pos == std::string::npos) {
return nullptr;
}
const auto ip_str = addr.substr(0, pos);
const auto port_str = addr.substr(pos + 1);
uint64_t port64;
if (port_str.empty() || !StringUtil::atoul(port_str.c_str(), port64, 10) || port64 > 65535) {
return nullptr;
}
sockaddr_in sa4;
if (ip_str.empty() || inet_pton(AF_INET, ip_str.c_str(), &sa4.sin_addr) != 1) {
return nullptr;
}
sa4.sin_family = AF_INET;
sa4.sin_port = htons(port64);
return std::make_shared<Ipv4Instance>(&sa4);
}

} // Address
} // Network
17 changes: 0 additions & 17 deletions source/common/network/address_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -172,23 +172,6 @@ class Ipv6Instance : public InstanceBase {
IpHelper ip_;
};

/*
* Parse an internet host address (IPv4 or IPv6) and create an Instance from it.
* The address must not include a port number.
* @param ip_addr string to be parsed as an internet address.
* @return pointer to the Instance, or nullptr if unable to parse the address.
*/
InstanceConstSharedPtr parseInternetAddress(const std::string& ip_addr);

/*
* Parse an internet host address (IPv4 or IPv6) AND port, and create an Instance from it.
* @param ip_addr string to be parsed as an internet address and port. Examples:
* - "1.2.3.4:80"
* - "[1234:5678::9]:443"
* @return pointer to the Instance, or nullptr if unable to parse the address.
*/
InstanceConstSharedPtr parseInternetAddressAndPort(const std::string& ip_addr);

/**
* Implementation of a pipe address (unix domain socket on unix).
*/
Expand Down
6 changes: 3 additions & 3 deletions source/common/network/cidr_range.cc
Original file line number Diff line number Diff line change
Expand Up @@ -106,15 +106,15 @@ CidrRange CidrRange::create(InstanceConstSharedPtr address, int length) {

// static
CidrRange CidrRange::create(const std::string& address, int length) {
return create(parseInternetAddress(address), length);
return create(Utility::parseInternetAddress(address), length);
}

// static
CidrRange CidrRange::create(const std::string& range) {
std::vector<std::string> parts = StringUtil::split(range, '/');
if (parts.size() == 2) {
InstanceConstSharedPtr ptr = parseInternetAddress(parts[0]);
if (ptr != nullptr && ptr->type() == Type::Ip) {
InstanceConstSharedPtr ptr = Utility::parseInternetAddress(parts[0]);
if (ptr->type() == Type::Ip) {
uint64_t length64;
if (StringUtil::atoul(parts[1].c_str(), length64, 10)) {
if ((ptr->ip()->version() == IpVersion::v6 && length64 <= 128) ||
Expand Down
68 changes: 67 additions & 1 deletion source/common/network/utility.cc
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ const std::string Utility::UNIX_SCHEME = "unix://";

Address::InstanceConstSharedPtr Utility::resolveUrl(const std::string& url) {
if (url.find(TCP_SCHEME) == 0) {
return Address::parseInternetAddressAndPort(url.substr(TCP_SCHEME.size()));
return parseInternetAddressAndPort(url.substr(TCP_SCHEME.size()));
} else if (url.find(UNIX_SCHEME) == 0) {
return Address::InstanceConstSharedPtr{
new Address::PipeInstance(url.substr(UNIX_SCHEME.size()))};
Expand Down Expand Up @@ -129,6 +129,72 @@ uint32_t Utility::portFromTcpUrl(const std::string& url) {
}
}

Address::InstanceConstSharedPtr Utility::parseInternetAddress(const std::string& ip_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 = 0;
return std::make_shared<Address::Ipv4Instance>(&sa4);
}
sockaddr_in6 sa6;
if (inet_pton(AF_INET6, ip_address.c_str(), &sa6.sin6_addr) == 1) {
sa6.sin6_family = AF_INET6;
sa6.sin6_port = 0;
return std::make_shared<Address::Ipv6Instance>(sa6);
}
throwWithMalformedIp(ip_address);
NOT_REACHED;
}

Address::InstanceConstSharedPtr
Utility::parseInternetAddressAndPort(const std::string& ip_address) {
if (ip_address.empty()) {
throwWithMalformedIp(ip_address);
}
if (ip_address[0] == '[') {
// Appears to be an IPv6 address. Find the "]:" that separates the address from the port.
auto pos = ip_address.rfind("]:");
if (pos == std::string::npos) {
throwWithMalformedIp(ip_address);
}
const auto ip_str = ip_address.substr(1, pos - 1);
const auto port_str = ip_address.substr(pos + 2);
uint64_t port64 = 0;
if (port_str.empty() || !StringUtil::atoul(port_str.c_str(), port64, 10) || port64 > 65535) {
throwWithMalformedIp(ip_address);
}
sockaddr_in6 sa6;
if (ip_str.empty() || inet_pton(AF_INET6, ip_str.c_str(), &sa6.sin6_addr) != 1) {
throwWithMalformedIp(ip_address);
}
sa6.sin6_family = AF_INET6;
sa6.sin6_port = htons(port64);
return std::make_shared<Address::Ipv6Instance>(sa6);
}
// Treat it as an IPv4 address followed by a port.
auto pos = ip_address.rfind(":");
if (pos == std::string::npos) {
throwWithMalformedIp(ip_address);
}
const auto ip_str = ip_address.substr(0, pos);
const auto port_str = ip_address.substr(pos + 1);
uint64_t port64 = 0;
if (port_str.empty() || !StringUtil::atoul(port_str.c_str(), port64, 10) || port64 > 65535) {
throwWithMalformedIp(ip_address);
}
sockaddr_in sa4;
if (ip_str.empty() || inet_pton(AF_INET, ip_str.c_str(), &sa4.sin_addr) != 1) {
throwWithMalformedIp(ip_address);
}
sa4.sin_family = AF_INET;
sa4.sin_port = htons(port64);
return std::make_shared<Address::Ipv4Instance>(&sa4);
}

void Utility::throwWithMalformedIp(const std::string& ip_address) {
throw EnvoyException(fmt::format("malformed IP address: {}", ip_address));
}

// TODO(hennna): Currently getLocalAddress does not support choosing between
// multiple interfaces and addresses not returned by getifaddrs. In additon,
// the default is to return a loopback address of type version. This function may
Expand Down
21 changes: 21 additions & 0 deletions source/common/network/utility.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,24 @@ class Utility {
*/
static uint32_t portFromTcpUrl(const std::string& url);

/*
* Parse an internet host address (IPv4 or IPv6) and create an Instance from it. Throw
* an exception if unable to parse the address. The address must not include a port number.
* @param ip_address string to be parsed as an internet address.
* @return pointer to the Instance, or nullptr if unable to parse the address.
*/
static Address::InstanceConstSharedPtr parseInternetAddress(const std::string& ip_address);

/*
* Parse an internet host address (IPv4 or IPv6) AND port, and create an Instance from it.
* @throws an exception if unable to parse the address.
* @param ip_addr string to be parsed as an internet address and port. Examples:
* - "1.2.3.4:80"
* - "[1234:5678::9]:443"
* @return pointer to the Instance.
*/
static Address::InstanceConstSharedPtr parseInternetAddressAndPort(const std::string& ip_address);

/**
* Get the local address of the first interface address that is of type
* version and is not a loopback address. If no matches are found, return the
Expand Down Expand Up @@ -153,6 +171,9 @@ class Utility {
* @return whether the port appears in at least one of the ranges in the list
*/
static bool portInRangeList(const Address::Instance& address, const std::list<PortRange>& list);

private:
static void throwWithMalformedIp(const std::string& ip_address);
};

} // Network
1 change: 1 addition & 0 deletions test/common/network/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ envoy_cc_test(
srcs = ["address_impl_test.cc"],
deps = [
"//source/common/network:address_lib",
"//source/common/network:utility_lib",
"//test/test_common:environment_lib",
"//test/test_common:network_utility_lib",
"//test/test_common:utility_lib",
Expand Down
73 changes: 11 additions & 62 deletions test/common/network/address_impl_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

#include "common/common/utility.h"
#include "common/network/address_impl.h"
#include "common/network/utility.h"

#include "test/test_common/environment.h"
#include "test/test_common/network_utility.h"
Expand All @@ -36,7 +37,7 @@ void makeFdBlocking(int fd) {
}

void testSocketBindAndConnect(const std::string& addr_port_str) {
auto addr_port = parseInternetAddressAndPort(addr_port_str);
auto addr_port = Network::Utility::parseInternetAddressAndPort(addr_port_str);
ASSERT_NE(addr_port, nullptr);
if (addr_port->ip()->port() == 0) {
addr_port = Network::Test::findOrCheckFreePort(addr_port, SocketType::Stream);
Expand Down Expand Up @@ -106,7 +107,7 @@ TEST(Ipv4InstanceTest, SocketAddress) {
EXPECT_EQ("1.2.3.4", address.ip()->addressAsString());
EXPECT_EQ(6502U, address.ip()->port());
EXPECT_EQ(IpVersion::v4, address.ip()->version());
EXPECT_TRUE(addressesEqual(parseInternetAddress("1.2.3.4"), address));
EXPECT_TRUE(addressesEqual(Network::Utility::parseInternetAddress("1.2.3.4"), address));
}

TEST(Ipv4InstanceTest, AddressOnly) {
Expand All @@ -116,7 +117,7 @@ TEST(Ipv4InstanceTest, AddressOnly) {
EXPECT_EQ("3.4.5.6", address.ip()->addressAsString());
EXPECT_EQ(0U, address.ip()->port());
EXPECT_EQ(IpVersion::v4, address.ip()->version());
EXPECT_TRUE(addressesEqual(parseInternetAddress("3.4.5.6"), address));
EXPECT_TRUE(addressesEqual(Network::Utility::parseInternetAddress("3.4.5.6"), address));
}

TEST(Ipv4InstanceTest, AddressAndPort) {
Expand All @@ -127,7 +128,7 @@ TEST(Ipv4InstanceTest, AddressAndPort) {
EXPECT_FALSE(address.ip()->isAnyAddress());
EXPECT_EQ(80U, address.ip()->port());
EXPECT_EQ(IpVersion::v4, address.ip()->version());
EXPECT_TRUE(addressesEqual(parseInternetAddress("127.0.0.1"), address));
EXPECT_TRUE(addressesEqual(Network::Utility::parseInternetAddress("127.0.0.1"), address));
}

TEST(Ipv4InstanceTest, PortOnly) {
Expand All @@ -138,37 +139,12 @@ TEST(Ipv4InstanceTest, PortOnly) {
EXPECT_TRUE(address.ip()->isAnyAddress());
EXPECT_EQ(443U, address.ip()->port());
EXPECT_EQ(IpVersion::v4, address.ip()->version());
EXPECT_TRUE(addressesEqual(parseInternetAddress("0.0.0.0"), address));
EXPECT_TRUE(addressesEqual(Network::Utility::parseInternetAddress("0.0.0.0"), address));
}

TEST(Ipv4InstanceTest, BadAddress) {
EXPECT_THROW(Ipv4Instance("foo"), EnvoyException);
EXPECT_THROW(Ipv4Instance("bar", 1), EnvoyException);
EXPECT_EQ(parseInternetAddress(""), nullptr);
EXPECT_EQ(parseInternetAddress("1.2.3"), nullptr);
EXPECT_EQ(parseInternetAddress("1.2.3.4.5"), nullptr);
EXPECT_EQ(parseInternetAddress("1.2.3.256"), nullptr);
EXPECT_EQ(parseInternetAddress("foo"), nullptr);
}

TEST(Ipv4InstanceTest, ParseInternetAddressAndPort) {
EXPECT_EQ(nullptr, parseInternetAddressAndPort("1.2.3.4"));
EXPECT_EQ(nullptr, parseInternetAddressAndPort("1.2.3.4:"));
EXPECT_EQ(nullptr, parseInternetAddressAndPort("1.2.3.4::1"));
EXPECT_EQ(nullptr, parseInternetAddressAndPort("1.2.3.4:-1"));
EXPECT_EQ(nullptr, parseInternetAddressAndPort(":1"));
EXPECT_EQ(nullptr, parseInternetAddressAndPort(" :1"));
EXPECT_EQ(nullptr, parseInternetAddressAndPort("1.2.3:1"));
EXPECT_EQ(nullptr, parseInternetAddressAndPort("1.2.3.4]:2"));
EXPECT_EQ(nullptr, parseInternetAddressAndPort("1.2.3.4:65536"));

auto ptr = parseInternetAddressAndPort("0.0.0.0:0");
ASSERT_NE(ptr, nullptr);
EXPECT_EQ(ptr->asString(), "0.0.0.0:0");

ptr = parseInternetAddressAndPort("255.255.255.255:65535");
ASSERT_NE(ptr, nullptr);
EXPECT_EQ(ptr->asString(), "255.255.255.255:65535");
}

TEST(Ipv6InstanceTest, SocketAddress) {
Expand All @@ -184,7 +160,7 @@ TEST(Ipv6InstanceTest, SocketAddress) {
EXPECT_FALSE(address.ip()->isAnyAddress());
EXPECT_EQ(32000U, address.ip()->port());
EXPECT_EQ(IpVersion::v6, address.ip()->version());
EXPECT_TRUE(addressesEqual(parseInternetAddress("1:0023::0Ef"), address));
EXPECT_TRUE(addressesEqual(Network::Utility::parseInternetAddress("1:0023::0Ef"), address));
}

TEST(Ipv6InstanceTest, AddressOnly) {
Expand All @@ -194,7 +170,8 @@ TEST(Ipv6InstanceTest, AddressOnly) {
EXPECT_EQ("2001:db8:85a3::8a2e:370:7334", address.ip()->addressAsString());
EXPECT_EQ(0U, address.ip()->port());
EXPECT_EQ(IpVersion::v6, address.ip()->version());
EXPECT_TRUE(addressesEqual(parseInternetAddress("2001:db8:85a3::8a2e:0370:7334"), address));
EXPECT_TRUE(addressesEqual(
Network::Utility::parseInternetAddress("2001:db8:85a3::8a2e:0370:7334"), address));
}

TEST(Ipv6InstanceTest, AddressAndPort) {
Expand All @@ -204,7 +181,7 @@ TEST(Ipv6InstanceTest, AddressAndPort) {
EXPECT_EQ("::1", address.ip()->addressAsString());
EXPECT_EQ(80U, address.ip()->port());
EXPECT_EQ(IpVersion::v6, address.ip()->version());
EXPECT_TRUE(addressesEqual(parseInternetAddress("0:0:0:0:0:0:0:1"), address));
EXPECT_TRUE(addressesEqual(Network::Utility::parseInternetAddress("0:0:0:0:0:0:0:1"), address));
}

TEST(Ipv6InstanceTest, PortOnly) {
Expand All @@ -215,40 +192,12 @@ TEST(Ipv6InstanceTest, PortOnly) {
EXPECT_TRUE(address.ip()->isAnyAddress());
EXPECT_EQ(443U, address.ip()->port());
EXPECT_EQ(IpVersion::v6, address.ip()->version());
EXPECT_TRUE(addressesEqual(parseInternetAddress("::0000"), address));
EXPECT_TRUE(addressesEqual(Network::Utility::parseInternetAddress("::0000"), address));
}

TEST(Ipv6InstanceTest, BadAddress) {
EXPECT_THROW(Ipv6Instance("foo"), EnvoyException);
EXPECT_THROW(Ipv6Instance("bar", 1), EnvoyException);
EXPECT_EQ(parseInternetAddress("0:0:0:0"), nullptr);
EXPECT_EQ(parseInternetAddress("fffff::"), nullptr);
EXPECT_EQ(parseInternetAddress("/foo"), nullptr);
}

TEST(Ipv6InstanceTest, ParseInternetAddressAndPort) {
EXPECT_EQ(nullptr, parseInternetAddressAndPort(""));
EXPECT_EQ(nullptr, parseInternetAddressAndPort("::1"));
EXPECT_EQ(nullptr, parseInternetAddressAndPort("::"));
EXPECT_EQ(nullptr, parseInternetAddressAndPort("[[::]]:1"));
EXPECT_EQ(nullptr, parseInternetAddressAndPort("[::]:1]:2"));
EXPECT_EQ(nullptr, parseInternetAddressAndPort("]:[::1]:2"));
EXPECT_EQ(nullptr, parseInternetAddressAndPort("[1.2.3.4:0"));
EXPECT_EQ(nullptr, parseInternetAddressAndPort("[1.2.3.4]:0"));
EXPECT_EQ(nullptr, parseInternetAddressAndPort("[::]:"));
EXPECT_EQ(nullptr, parseInternetAddressAndPort("[::]:-1"));
EXPECT_EQ(nullptr, parseInternetAddressAndPort("[::]:bogus"));

auto ptr = parseInternetAddressAndPort("[::]:0");
ASSERT_NE(ptr, nullptr);
EXPECT_EQ(ptr->asString(), "[::]:0");

ptr = parseInternetAddressAndPort("[1::1]:65535");
ASSERT_NE(ptr, nullptr);
EXPECT_EQ(ptr->asString(), "[1::1]:65535");

EXPECT_EQ(nullptr, parseInternetAddressAndPort("[::]:-1"));
EXPECT_EQ(nullptr, parseInternetAddressAndPort("[1::1]:65536"));
}

TEST(PipeInstanceTest, Basic) {
Expand Down
Loading