mirror of https://github.com/grpc/grpc.git
parent
8327acd9a2
commit
690dde672a
30 changed files with 8518 additions and 156 deletions
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,627 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2017 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#include <grpc/grpc.h> |
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/host_port.h> |
||||
#include <grpc/support/log.h> |
||||
#include <grpc/support/string_util.h> |
||||
#include <grpc/support/sync.h> |
||||
#include <grpc/support/time.h> |
||||
#include <string.h> |
||||
|
||||
#include <arpa/inet.h> |
||||
#include <gflags/gflags.h> |
||||
#include <gmock/gmock.h> |
||||
#include <sys/socket.h> |
||||
#include <sys/types.h> |
||||
#include <vector> |
||||
|
||||
#include <address_sorting.h> |
||||
#include "test/cpp/util/subprocess.h" |
||||
#include "test/cpp/util/test_config.h" |
||||
|
||||
#include "src/core/ext/filters/client_channel/client_channel.h" |
||||
#include "src/core/ext/filters/client_channel/resolver.h" |
||||
#include "src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h" |
||||
#include "src/core/ext/filters/client_channel/resolver_registry.h" |
||||
#include "src/core/lib/channel/channel_args.h" |
||||
#include "src/core/lib/iomgr/combiner.h" |
||||
#include "src/core/lib/iomgr/executor.h" |
||||
#include "src/core/lib/iomgr/iomgr.h" |
||||
#include "src/core/lib/iomgr/resolve_address.h" |
||||
#include "src/core/lib/iomgr/sockaddr_utils.h" |
||||
#include "src/core/lib/support/env.h" |
||||
#include "src/core/lib/support/string.h" |
||||
#include "test/core/util/port.h" |
||||
#include "test/core/util/test_config.h" |
||||
|
||||
namespace { |
||||
|
||||
struct TestAddress { |
||||
std::string dest_addr; |
||||
int family; |
||||
}; |
||||
|
||||
grpc_resolved_address TestAddressToGrpcResolvedAddress(TestAddress test_addr) { |
||||
char* host; |
||||
char* port; |
||||
grpc_resolved_address resolved_addr; |
||||
gpr_split_host_port(test_addr.dest_addr.c_str(), &host, &port); |
||||
if (test_addr.family == AF_INET) { |
||||
sockaddr_in in_dest; |
||||
memset(&in_dest, 0, sizeof(sockaddr_in)); |
||||
in_dest.sin_port = htons(atoi(port)); |
||||
in_dest.sin_family = AF_INET; |
||||
GPR_ASSERT(inet_pton(AF_INET, host, &in_dest.sin_addr) == 1); |
||||
memcpy(&resolved_addr.addr, &in_dest, sizeof(sockaddr_in)); |
||||
resolved_addr.len = sizeof(sockaddr_in); |
||||
} else { |
||||
GPR_ASSERT(test_addr.family == AF_INET6); |
||||
sockaddr_in6 in6_dest; |
||||
memset(&in6_dest, 0, sizeof(sockaddr_in6)); |
||||
in6_dest.sin6_port = htons(atoi(port)); |
||||
in6_dest.sin6_family = AF_INET6; |
||||
GPR_ASSERT(inet_pton(AF_INET6, host, &in6_dest.sin6_addr) == 1); |
||||
memcpy(&resolved_addr.addr, &in6_dest, sizeof(sockaddr_in6)); |
||||
resolved_addr.len = sizeof(sockaddr_in6); |
||||
} |
||||
gpr_free(host); |
||||
gpr_free(port); |
||||
return resolved_addr; |
||||
} |
||||
|
||||
class MockSourceAddrFactory : public address_sorting_source_addr_factory { |
||||
public: |
||||
MockSourceAddrFactory( |
||||
bool ipv4_supported, bool ipv6_supported, |
||||
const std::map<std::string, TestAddress>& dest_addr_to_src_addr) |
||||
: ipv4_supported_(ipv4_supported), |
||||
ipv6_supported_(ipv6_supported), |
||||
dest_addr_to_src_addr_(dest_addr_to_src_addr) {} |
||||
|
||||
bool GetSourceAddr(const address_sorting_address* dest_addr, |
||||
address_sorting_address* source_addr) { |
||||
if ((address_sorting_abstract_get_family(dest_addr) == |
||||
ADDRESS_SORTING_AF_INET && |
||||
!ipv4_supported_) || |
||||
(address_sorting_abstract_get_family(dest_addr) == |
||||
ADDRESS_SORTING_AF_INET6 && |
||||
!ipv6_supported_)) { |
||||
return false; |
||||
} |
||||
char* ip_addr_str; |
||||
grpc_resolved_address dest_addr_as_resolved_addr; |
||||
memcpy(&dest_addr_as_resolved_addr.addr, dest_addr, dest_addr->len); |
||||
dest_addr_as_resolved_addr.len = dest_addr->len; |
||||
grpc_sockaddr_to_string(&ip_addr_str, &dest_addr_as_resolved_addr, |
||||
false /* normalize */); |
||||
auto it = dest_addr_to_src_addr_.find(ip_addr_str); |
||||
if (it == dest_addr_to_src_addr_.end()) { |
||||
gpr_log(GPR_DEBUG, "can't find |%s| in dest to src map", ip_addr_str); |
||||
gpr_free(ip_addr_str); |
||||
return false; |
||||
} |
||||
gpr_free(ip_addr_str); |
||||
grpc_resolved_address source_addr_as_resolved_addr = |
||||
TestAddressToGrpcResolvedAddress(it->second); |
||||
memcpy(source_addr->addr, &source_addr_as_resolved_addr.addr, |
||||
source_addr_as_resolved_addr.len); |
||||
source_addr->len = source_addr_as_resolved_addr.len; |
||||
return true; |
||||
} |
||||
|
||||
private: |
||||
// user provided test config
|
||||
bool ipv4_supported_; |
||||
bool ipv6_supported_; |
||||
std::map<std::string, TestAddress> dest_addr_to_src_addr_; |
||||
}; |
||||
|
||||
static bool mock_source_addr_factory_wrapper_get_source_addr( |
||||
address_sorting_source_addr_factory* factory, |
||||
const address_sorting_address* dest_addr, |
||||
address_sorting_address* source_addr) { |
||||
MockSourceAddrFactory* mock = |
||||
reinterpret_cast<MockSourceAddrFactory*>(factory); |
||||
return mock->GetSourceAddr(dest_addr, source_addr); |
||||
} |
||||
|
||||
void mock_source_addr_factory_wrapper_destroy( |
||||
address_sorting_source_addr_factory* factory) { |
||||
MockSourceAddrFactory* mock = |
||||
reinterpret_cast<MockSourceAddrFactory*>(factory); |
||||
delete mock; |
||||
} |
||||
|
||||
const address_sorting_source_addr_factory_vtable kMockSourceAddrFactoryVtable = |
||||
{ |
||||
mock_source_addr_factory_wrapper_get_source_addr, |
||||
mock_source_addr_factory_wrapper_destroy, |
||||
}; |
||||
|
||||
void OverrideAddressSortingSourceAddrFactory( |
||||
bool ipv4_supported, bool ipv6_supported, |
||||
const std::map<std::string, TestAddress>& dest_addr_to_src_addr) { |
||||
address_sorting_source_addr_factory* factory = new MockSourceAddrFactory( |
||||
ipv4_supported, ipv6_supported, dest_addr_to_src_addr); |
||||
factory->vtable = &kMockSourceAddrFactoryVtable; |
||||
address_sorting_override_source_addr_factory_for_testing(factory); |
||||
} |
||||
|
||||
grpc_lb_addresses* BuildLbAddrInputs(std::vector<TestAddress> test_addrs) { |
||||
grpc_lb_addresses* lb_addrs = grpc_lb_addresses_create(0, NULL); |
||||
lb_addrs->addresses = |
||||
(grpc_lb_address*)gpr_zalloc(sizeof(grpc_lb_address) * test_addrs.size()); |
||||
lb_addrs->num_addresses = test_addrs.size(); |
||||
for (size_t i = 0; i < test_addrs.size(); i++) { |
||||
lb_addrs->addresses[i].address = |
||||
TestAddressToGrpcResolvedAddress(test_addrs[i]); |
||||
} |
||||
return lb_addrs; |
||||
} |
||||
|
||||
void VerifyLbAddrOutputs(grpc_lb_addresses* lb_addrs, |
||||
std::vector<std::string> expected_addrs) { |
||||
EXPECT_EQ(lb_addrs->num_addresses, expected_addrs.size()); |
||||
for (size_t i = 0; i < lb_addrs->num_addresses; i++) { |
||||
char* ip_addr_str; |
||||
grpc_sockaddr_to_string(&ip_addr_str, &lb_addrs->addresses[i].address, |
||||
false /* normalize */); |
||||
EXPECT_EQ(expected_addrs[i], ip_addr_str); |
||||
gpr_free(ip_addr_str); |
||||
} |
||||
grpc_core::ExecCtx exec_ctx; |
||||
grpc_lb_addresses_destroy(lb_addrs); |
||||
} |
||||
|
||||
} // namespace
|
||||
|
||||
/* Tests for rule 1 */ |
||||
TEST(AddressSortingTest, TestDepriotizesUnreachableAddresses) { |
||||
bool ipv4_supported = true; |
||||
bool ipv6_supported = true; |
||||
OverrideAddressSortingSourceAddrFactory( |
||||
ipv4_supported, ipv6_supported, |
||||
{ |
||||
{"1.2.3.4:443", {"4.3.2.1:443", AF_INET}}, |
||||
}); |
||||
auto* lb_addrs = BuildLbAddrInputs({ |
||||
{"1.2.3.4:443", AF_INET}, |
||||
{"5.6.7.8:443", AF_INET}, |
||||
}); |
||||
grpc_cares_wrapper_address_sorting_sort(lb_addrs); |
||||
VerifyLbAddrOutputs(lb_addrs, { |
||||
"1.2.3.4:443", |
||||
"5.6.7.8:443", |
||||
}); |
||||
} |
||||
|
||||
TEST(AddressSortingTest, TestDepriotizesUnsupportedDomainIpv6) { |
||||
bool ipv4_supported = true; |
||||
bool ipv6_supported = false; |
||||
OverrideAddressSortingSourceAddrFactory( |
||||
ipv4_supported, ipv6_supported, |
||||
{ |
||||
{"1.2.3.4:443", {"4.3.2.1:0", AF_INET}}, |
||||
}); |
||||
auto lb_addrs = BuildLbAddrInputs({ |
||||
{"[2607:f8b0:400a:801::1002]:443", AF_INET6}, |
||||
{"1.2.3.4:443", AF_INET}, |
||||
}); |
||||
grpc_cares_wrapper_address_sorting_sort(lb_addrs); |
||||
VerifyLbAddrOutputs(lb_addrs, { |
||||
"1.2.3.4:443", |
||||
"[2607:f8b0:400a:801::1002]:443", |
||||
}); |
||||
} |
||||
|
||||
TEST(AddressSortingTest, TestDepriotizesUnsupportedDomainIpv4) { |
||||
bool ipv4_supported = false; |
||||
bool ipv6_supported = true; |
||||
OverrideAddressSortingSourceAddrFactory( |
||||
ipv4_supported, ipv6_supported, |
||||
{ |
||||
{"1.2.3.4:443", {"4.3.2.1:0", AF_INET}}, |
||||
{"[2607:f8b0:400a:801::1002]:443", {"[fec0::1234]:0", AF_INET6}}, |
||||
}); |
||||
grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ |
||||
{"[2607:f8b0:400a:801::1002]:443", AF_INET6}, |
||||
{"1.2.3.4:443", AF_INET}, |
||||
}); |
||||
grpc_cares_wrapper_address_sorting_sort(lb_addrs); |
||||
VerifyLbAddrOutputs(lb_addrs, { |
||||
"[2607:f8b0:400a:801::1002]:443", |
||||
"1.2.3.4:443", |
||||
}); |
||||
} |
||||
|
||||
/* Tests for rule 2 */ |
||||
|
||||
TEST(AddressSortingTest, TestDepriotizesNonMatchingScope) { |
||||
bool ipv4_supported = true; |
||||
bool ipv6_supported = true; |
||||
OverrideAddressSortingSourceAddrFactory( |
||||
ipv4_supported, ipv6_supported, |
||||
{ |
||||
{"[2000:f8b0:400a:801::1002]:443", |
||||
{"[fec0::1000]:0", AF_INET6}}, // global and site-local scope
|
||||
{"[fec0::5000]:443", |
||||
{"[fec0::5001]:0", AF_INET6}}, // site-local and site-local scope
|
||||
}); |
||||
grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ |
||||
{"[2000:f8b0:400a:801::1002]:443", AF_INET6}, |
||||
{"[fec0::5000]:443", AF_INET6}, |
||||
}); |
||||
grpc_cares_wrapper_address_sorting_sort(lb_addrs); |
||||
VerifyLbAddrOutputs(lb_addrs, { |
||||
"[fec0::5000]:443", |
||||
"[2000:f8b0:400a:801::1002]:443", |
||||
}); |
||||
} |
||||
|
||||
/* Tests for rule 5 */ |
||||
|
||||
TEST(AddressSortingTest, TestUsesLabelFromDefaultTable) { |
||||
bool ipv4_supported = true; |
||||
bool ipv6_supported = true; |
||||
OverrideAddressSortingSourceAddrFactory( |
||||
ipv4_supported, ipv6_supported, |
||||
{ |
||||
{"[2002::5001]:443", {"[2001::5002]:0", AF_INET6}}, |
||||
{"[2001::5001]:443", |
||||
{"[2001::5002]:0", AF_INET6}}, // matching labels
|
||||
}); |
||||
grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ |
||||
{"[2002::5001]:443", AF_INET6}, |
||||
{"[2001::5001]:443", AF_INET6}, |
||||
}); |
||||
grpc_cares_wrapper_address_sorting_sort(lb_addrs); |
||||
VerifyLbAddrOutputs(lb_addrs, { |
||||
"[2001::5001]:443", |
||||
"[2002::5001]:443", |
||||
}); |
||||
} |
||||
|
||||
/* Tests for rule 6 */ |
||||
|
||||
TEST(AddressSortingTest, |
||||
TestUsesDestinationWithHigherPrecedenceWithAnIpv4Address) { |
||||
bool ipv4_supported = true; |
||||
bool ipv6_supported = true; |
||||
OverrideAddressSortingSourceAddrFactory( |
||||
ipv4_supported, ipv6_supported, |
||||
{ |
||||
{"[3ffe::5001]:443", {"[3ffe::5002]:0", AF_INET6}}, |
||||
{"1.2.3.4:443", {"5.6.7.8:0", AF_INET}}, |
||||
}); |
||||
grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ |
||||
{"[3ffe::5001]:443", AF_INET6}, |
||||
{"1.2.3.4:443", AF_INET}, |
||||
}); |
||||
grpc_cares_wrapper_address_sorting_sort(lb_addrs); |
||||
VerifyLbAddrOutputs( |
||||
lb_addrs, { |
||||
// The AF_INET address should be IPv4-mapped by the sort,
|
||||
// and IPv4-mapped
|
||||
// addresses have higher precedence than 3ffe::/16 by spec.
|
||||
"1.2.3.4:443", |
||||
"[3ffe::5001]:443", |
||||
}); |
||||
} |
||||
|
||||
TEST(AddressSortingTest, |
||||
TestUsesDestinationWithHigherPrecedenceWith2000PrefixedAddress) { |
||||
bool ipv4_supported = true; |
||||
bool ipv6_supported = true; |
||||
OverrideAddressSortingSourceAddrFactory( |
||||
ipv4_supported, ipv6_supported, |
||||
{ |
||||
{"[2001::1234]:443", {"[2001::5678]:0", AF_INET6}}, |
||||
{"[2000::5001]:443", {"[2000::5002]:0", AF_INET6}}, |
||||
}); |
||||
grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ |
||||
{"[2001::1234]:443", AF_INET6}, |
||||
{"[2000::5001]:443", AF_INET6}, |
||||
}); |
||||
grpc_cares_wrapper_address_sorting_sort(lb_addrs); |
||||
VerifyLbAddrOutputs( |
||||
lb_addrs, { |
||||
// The 2000::/16 address should match the ::/0 prefix rule
|
||||
"[2000::5001]:443", |
||||
"[2001::1234]:443", |
||||
}); |
||||
} |
||||
|
||||
TEST( |
||||
AddressSortingTest, |
||||
TestUsesDestinationWithHigherPrecedenceWith2000PrefixedAddressEnsurePrefixMatchHasNoEffect) { |
||||
bool ipv4_supported = true; |
||||
bool ipv6_supported = true; |
||||
OverrideAddressSortingSourceAddrFactory( |
||||
ipv4_supported, ipv6_supported, |
||||
{ |
||||
{"[2001::1231]:443", {"[2001::1232]:0", AF_INET6}}, |
||||
{"[2000::5001]:443", {"[2000::5002]:0", AF_INET6}}, |
||||
}); |
||||
grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ |
||||
{"[2001::1231]:443", AF_INET6}, |
||||
{"[2000::5001]:443", AF_INET6}, |
||||
}); |
||||
grpc_cares_wrapper_address_sorting_sort(lb_addrs); |
||||
VerifyLbAddrOutputs(lb_addrs, { |
||||
"[2000::5001]:443", |
||||
"[2001::1231]:443", |
||||
}); |
||||
} |
||||
|
||||
TEST(AddressSortingTest, |
||||
TestUsesDestinationWithHigherPrecedenceWithLinkAndSiteLocalAddresses) { |
||||
bool ipv4_supported = true; |
||||
bool ipv6_supported = true; |
||||
OverrideAddressSortingSourceAddrFactory( |
||||
ipv4_supported, ipv6_supported, |
||||
{ |
||||
{"[fec0::1234]:443", {"[fec0::5678]:0", AF_INET6}}, |
||||
{"[fc00::5001]:443", {"[fc00::5002]:0", AF_INET6}}, |
||||
}); |
||||
grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ |
||||
{"[fec0::1234]:443", AF_INET6}, |
||||
{"[fc00::5001]:443", AF_INET6}, |
||||
}); |
||||
grpc_cares_wrapper_address_sorting_sort(lb_addrs); |
||||
VerifyLbAddrOutputs(lb_addrs, { |
||||
"[fc00::5001]:443", |
||||
"[fec0::1234]:443", |
||||
}); |
||||
} |
||||
|
||||
/* Tests for rule 8 */ |
||||
|
||||
TEST(AddressSortingTest, TestPrefersSmallerScope) { |
||||
bool ipv4_supported = true; |
||||
bool ipv6_supported = true; |
||||
OverrideAddressSortingSourceAddrFactory( |
||||
ipv4_supported, ipv6_supported, |
||||
{ |
||||
// Both of these destinations have the same precedence in default
|
||||
// policy
|
||||
// table.
|
||||
{"[fec0::1234]:443", {"[fec0::5678]:0", AF_INET6}}, |
||||
{"[3ffe::5001]:443", {"[3ffe::5002]:0", AF_INET6}}, |
||||
}); |
||||
grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ |
||||
{"[3ffe::5001]:443", AF_INET6}, |
||||
{"[fec0::1234]:443", AF_INET6}, |
||||
}); |
||||
grpc_cares_wrapper_address_sorting_sort(lb_addrs); |
||||
VerifyLbAddrOutputs(lb_addrs, { |
||||
"[fec0::1234]:443", |
||||
"[3ffe::5001]:443", |
||||
}); |
||||
} |
||||
|
||||
/* Tests for rule 9 */ |
||||
|
||||
TEST(AddressSortingTest, TestPrefersLongestMatchingSrcDstPrefix) { |
||||
bool ipv4_supported = true; |
||||
bool ipv6_supported = true; |
||||
OverrideAddressSortingSourceAddrFactory( |
||||
ipv4_supported, ipv6_supported, |
||||
{ |
||||
// Both of these destinations have the same precedence in default
|
||||
// policy
|
||||
// table.
|
||||
{"[3ffe:1234::]:443", {"[3ffe:1235::]:0", AF_INET6}}, |
||||
{"[3ffe:5001::]:443", {"[3ffe:4321::]:0", AF_INET6}}, |
||||
}); |
||||
grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ |
||||
{"[3ffe:5001::]:443", AF_INET6}, |
||||
{"[3ffe:1234::]:443", AF_INET6}, |
||||
}); |
||||
grpc_cares_wrapper_address_sorting_sort(lb_addrs); |
||||
VerifyLbAddrOutputs(lb_addrs, { |
||||
"[3ffe:1234::]:443", |
||||
"[3ffe:5001::]:443", |
||||
}); |
||||
} |
||||
|
||||
TEST(AddressSortingTest, |
||||
TestPrefersLongestMatchingSrcDstPrefixMatchesWholeAddress) { |
||||
bool ipv4_supported = true; |
||||
bool ipv6_supported = true; |
||||
OverrideAddressSortingSourceAddrFactory( |
||||
ipv4_supported, ipv6_supported, |
||||
{ |
||||
{"[3ffe::1234]:443", {"[3ffe::1235]:0", AF_INET6}}, |
||||
{"[3ffe::5001]:443", {"[3ffe::4321]:0", AF_INET6}}, |
||||
}); |
||||
grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ |
||||
{"[3ffe::5001]:443", AF_INET6}, |
||||
{"[3ffe::1234]:443", AF_INET6}, |
||||
}); |
||||
grpc_cares_wrapper_address_sorting_sort(lb_addrs); |
||||
VerifyLbAddrOutputs(lb_addrs, { |
||||
"[3ffe::1234]:443", |
||||
"[3ffe::5001]:443", |
||||
}); |
||||
} |
||||
|
||||
TEST(AddressSortingTest, TestPrefersLongestPrefixStressInnerBytePrefix) { |
||||
bool ipv4_supported = true; |
||||
bool ipv6_supported = true; |
||||
OverrideAddressSortingSourceAddrFactory( |
||||
ipv4_supported, ipv6_supported, |
||||
{ |
||||
{"[3ffe:8000::]:443", {"[3ffe:C000::]:0", AF_INET6}}, |
||||
{"[3ffe:2000::]:443", {"[3ffe:3000::]:0", AF_INET6}}, |
||||
}); |
||||
grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ |
||||
{"[3ffe:8000::]:443", AF_INET6}, |
||||
{"[3ffe:2000::]:443", AF_INET6}, |
||||
}); |
||||
grpc_cares_wrapper_address_sorting_sort(lb_addrs); |
||||
VerifyLbAddrOutputs(lb_addrs, { |
||||
"[3ffe:2000::]:443", |
||||
"[3ffe:8000::]:443", |
||||
}); |
||||
} |
||||
|
||||
TEST(AddressSortingTest, TestPrefersLongestPrefixDiffersOnHighestBitOfByte) { |
||||
bool ipv4_supported = true; |
||||
bool ipv6_supported = true; |
||||
OverrideAddressSortingSourceAddrFactory( |
||||
ipv4_supported, ipv6_supported, |
||||
{ |
||||
{"[3ffe:6::]:443", {"[3ffe:8::]:0", AF_INET6}}, |
||||
{"[3ffe:c::]:443", {"[3ffe:8::]:0", AF_INET6}}, |
||||
}); |
||||
grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ |
||||
{"[3ffe:6::]:443", AF_INET6}, |
||||
{"[3ffe:c::]:443", AF_INET6}, |
||||
}); |
||||
grpc_cares_wrapper_address_sorting_sort(lb_addrs); |
||||
VerifyLbAddrOutputs(lb_addrs, { |
||||
"[3ffe:c::]:443", |
||||
"[3ffe:6::]:443", |
||||
}); |
||||
} |
||||
|
||||
TEST(AddressSortingTest, TestPrefersLongestPrefixDiffersByLastBit) { |
||||
bool ipv4_supported = true; |
||||
bool ipv6_supported = true; |
||||
OverrideAddressSortingSourceAddrFactory( |
||||
ipv4_supported, ipv6_supported, |
||||
{ |
||||
{"[3ffe:1111:1111:1111::]:443", |
||||
{"[3ffe:1111:1111:1111::]:0", AF_INET6}}, |
||||
{"[3ffe:1111:1111:1110::]:443", |
||||
{"[3ffe:1111:1111:1111::]:0", AF_INET6}}, |
||||
}); |
||||
grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ |
||||
{"[3ffe:1111:1111:1110::]:443", AF_INET6}, |
||||
{"[3ffe:1111:1111:1111::]:443", AF_INET6}, |
||||
}); |
||||
grpc_cares_wrapper_address_sorting_sort(lb_addrs); |
||||
VerifyLbAddrOutputs(lb_addrs, { |
||||
"[3ffe:1111:1111:1111::]:443", |
||||
"[3ffe:1111:1111:1110::]:443", |
||||
}); |
||||
} |
||||
|
||||
/* Tests for rule 10 */ |
||||
|
||||
TEST(AddressSortingTest, TestStableSort) { |
||||
bool ipv4_supported = true; |
||||
bool ipv6_supported = true; |
||||
OverrideAddressSortingSourceAddrFactory( |
||||
ipv4_supported, ipv6_supported, |
||||
{ |
||||
{"[3ffe::1234]:443", {"[3ffe::1236]:0", AF_INET6}}, |
||||
{"[3ffe::1235]:443", {"[3ffe::1237]:0", AF_INET6}}, |
||||
}); |
||||
grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ |
||||
{"[3ffe::1234]:443", AF_INET6}, |
||||
{"[3ffe::1235]:443", AF_INET6}, |
||||
}); |
||||
grpc_cares_wrapper_address_sorting_sort(lb_addrs); |
||||
VerifyLbAddrOutputs(lb_addrs, { |
||||
"[3ffe::1234]:443", |
||||
"[3ffe::1235]:443", |
||||
}); |
||||
} |
||||
|
||||
TEST(AddressSortingTest, TestStableSortFiveElements) { |
||||
bool ipv4_supported = true; |
||||
bool ipv6_supported = true; |
||||
OverrideAddressSortingSourceAddrFactory( |
||||
ipv4_supported, ipv6_supported, |
||||
{ |
||||
{"[3ffe::1231]:443", {"[3ffe::1201]:0", AF_INET6}}, |
||||
{"[3ffe::1232]:443", {"[3ffe::1202]:0", AF_INET6}}, |
||||
{"[3ffe::1233]:443", {"[3ffe::1203]:0", AF_INET6}}, |
||||
{"[3ffe::1234]:443", {"[3ffe::1204]:0", AF_INET6}}, |
||||
{"[3ffe::1235]:443", {"[3ffe::1205]:0", AF_INET6}}, |
||||
}); |
||||
grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ |
||||
{"[3ffe::1231]:443", AF_INET6}, |
||||
{"[3ffe::1232]:443", AF_INET6}, |
||||
{"[3ffe::1233]:443", AF_INET6}, |
||||
{"[3ffe::1234]:443", AF_INET6}, |
||||
{"[3ffe::1235]:443", AF_INET6}, |
||||
}); |
||||
grpc_cares_wrapper_address_sorting_sort(lb_addrs); |
||||
VerifyLbAddrOutputs(lb_addrs, { |
||||
"[3ffe::1231]:443", |
||||
"[3ffe::1232]:443", |
||||
"[3ffe::1233]:443", |
||||
"[3ffe::1234]:443", |
||||
"[3ffe::1235]:443", |
||||
}); |
||||
} |
||||
|
||||
TEST(AddressSortingTest, TestStableSortNoSrcAddrsExist) { |
||||
bool ipv4_supported = true; |
||||
bool ipv6_supported = true; |
||||
OverrideAddressSortingSourceAddrFactory(ipv4_supported, ipv6_supported, {}); |
||||
grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ |
||||
{"[3ffe::1231]:443", AF_INET6}, |
||||
{"[3ffe::1232]:443", AF_INET6}, |
||||
{"[3ffe::1233]:443", AF_INET6}, |
||||
{"[3ffe::1234]:443", AF_INET6}, |
||||
{"[3ffe::1235]:443", AF_INET6}, |
||||
}); |
||||
grpc_cares_wrapper_address_sorting_sort(lb_addrs); |
||||
VerifyLbAddrOutputs(lb_addrs, { |
||||
"[3ffe::1231]:443", |
||||
"[3ffe::1232]:443", |
||||
"[3ffe::1233]:443", |
||||
"[3ffe::1234]:443", |
||||
"[3ffe::1235]:443", |
||||
}); |
||||
} |
||||
|
||||
TEST(AddressSortingTest, TestStableSortNoSrcAddrsExistWithIpv4) { |
||||
bool ipv4_supported = true; |
||||
bool ipv6_supported = true; |
||||
OverrideAddressSortingSourceAddrFactory(ipv4_supported, ipv6_supported, {}); |
||||
grpc_lb_addresses* lb_addrs = BuildLbAddrInputs({ |
||||
{"[::ffff:5.6.7.8]:443", AF_INET6}, |
||||
{"1.2.3.4:443", AF_INET}, |
||||
}); |
||||
grpc_cares_wrapper_address_sorting_sort(lb_addrs); |
||||
VerifyLbAddrOutputs(lb_addrs, { |
||||
"[::ffff:5.6.7.8]:443", |
||||
"1.2.3.4:443", |
||||
}); |
||||
} |
||||
|
||||
int main(int argc, char** argv) { |
||||
const char* resolver = gpr_getenv("GRPC_DNS_RESOLVER"); |
||||
if (resolver == NULL || strlen(resolver) == 0) { |
||||
gpr_setenv("GRPC_DNS_RESOLVER", "ares"); |
||||
} else if (strcmp("ares", resolver)) { |
||||
gpr_log(GPR_INFO, "GRPC_DNS_RESOLVER != ares: %s.", resolver); |
||||
} |
||||
grpc_test_init(argc, argv); |
||||
::testing::InitGoogleTest(&argc, argv); |
||||
grpc_init(); |
||||
auto result = RUN_ALL_TESTS(); |
||||
grpc_shutdown(); |
||||
return result; |
||||
} |
@ -0,0 +1,57 @@ |
||||
# $NetBSD: getaddrinfo.c,v 1.82 2006/03/25 12:09:40 rpaulo Exp $ */ |
||||
# $KAME: getaddrinfo.c,v 1.29 2000/08/31 17:26:57 itojun Exp $ */ |
||||
# |
||||
# Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. |
||||
# All rights reserved. |
||||
# |
||||
# Redistribution and use in source and binary forms, with or without |
||||
# modification, are permitted provided that the following conditions |
||||
# are met: |
||||
# 1. Redistributions of source code must retain the above copyright |
||||
# notice, this list of conditions and the following disclaimer. |
||||
# 2. Redistributions in binary form must reproduce the above copyright |
||||
# notice, this list of conditions and the following disclaimer in the |
||||
# documentation and/or other materials provided with the distribution. |
||||
# 3. Neither the name of the project nor the names of its contributors |
||||
# may be used to endorse or promote products derived from this software |
||||
# without specific prior written permission. |
||||
# |
||||
# THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND |
||||
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE |
||||
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
||||
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
||||
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
||||
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
||||
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
||||
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
||||
# SUCH DAMAGE. |
||||
|
||||
package( |
||||
default_visibility = ["//visibility:public"], |
||||
features = [ |
||||
"-layering_check", |
||||
"-parse_headers", |
||||
], |
||||
) |
||||
|
||||
licenses(["notice"]) # BSD |
||||
|
||||
exports_files(["LICENSE"]) |
||||
|
||||
cc_library( |
||||
name = "address_sorting", |
||||
srcs = [ |
||||
"address_sorting.c", |
||||
"address_sorting_posix.c", |
||||
"address_sorting_windows.c", |
||||
], |
||||
hdrs = [ |
||||
"address_sorting.h", |
||||
"address_sorting_internal.h", |
||||
], |
||||
includes = [ |
||||
".", |
||||
], |
||||
) |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,342 @@ |
||||
/* $NetBSD: getaddrinfo.c,v 1.82 2006/03/25 12:09:40 rpaulo Exp $ */ |
||||
/* $KAME: getaddrinfo.c,v 1.29 2000/08/31 17:26:57 itojun Exp $ */ |
||||
/*
|
||||
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions |
||||
* are met: |
||||
* 1. Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* 2. Redistributions in binary form must reproduce the above copyright |
||||
* notice, this list of conditions and the following disclaimer in the |
||||
* documentation and/or other materials provided with the distribution. |
||||
* 3. Neither the name of the project nor the names of its contributors |
||||
* may be used to endorse or promote products derived from this software |
||||
* without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND |
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE |
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
||||
* SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
/*
|
||||
* This is an adaptation of Android's implementation of RFC 6724 |
||||
* (in Android's getaddrinfo.c). It has some cosmetic differences |
||||
* from Android's getaddrinfo.c, but Android's getaddrinfo.c was |
||||
* used as a guide or example of a way to implement the RFC 6724 spec when |
||||
* this was written. |
||||
*/ |
||||
|
||||
#include "address_sorting_internal.h" |
||||
|
||||
#include <errno.h> |
||||
#include <inttypes.h> |
||||
#include <limits.h> |
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
#include <sys/types.h> |
||||
|
||||
// Scope values increase with increase in scope.
|
||||
static const int kIPv6AddrScopeLinkLocal = 1; |
||||
static const int kIPv6AddrScopeSiteLocal = 2; |
||||
static const int kIPv6AddrScopeGlobal = 3; |
||||
|
||||
static address_sorting_source_addr_factory* g_current_source_addr_factory = |
||||
NULL; |
||||
|
||||
static int address_sorting_get_source_addr(const address_sorting_address* dest, |
||||
address_sorting_address* source) { |
||||
return g_current_source_addr_factory->vtable->get_source_addr( |
||||
g_current_source_addr_factory, dest, source); |
||||
} |
||||
|
||||
static int ipv6_prefix_match_length(const struct sockaddr_in6* sa, |
||||
const struct sockaddr_in6* sb) { |
||||
unsigned char* a = (unsigned char*)&sa->sin6_addr; |
||||
unsigned char* b = (unsigned char*)&sb->sin6_addr; |
||||
int cur_bit = 0; |
||||
while (cur_bit < 128) { |
||||
int high_bit = 1 << (CHAR_BIT - 1); |
||||
int a_val = a[cur_bit / CHAR_BIT] & (high_bit >> (cur_bit % CHAR_BIT)); |
||||
int b_val = b[cur_bit / CHAR_BIT] & (high_bit >> (cur_bit % CHAR_BIT)); |
||||
if (a_val == b_val) { |
||||
cur_bit++; |
||||
} else { |
||||
break; |
||||
} |
||||
} |
||||
return cur_bit; |
||||
} |
||||
|
||||
static int in6_is_addr_6to4(const struct in6_addr* ipv6_address) { |
||||
uint8_t* bytes = (uint8_t*)ipv6_address; |
||||
return bytes[0] == 0x20 && bytes[1] == 0x02; |
||||
} |
||||
|
||||
static int in6_is_addr_ula(const struct in6_addr* ipv6_address) { |
||||
uint8_t* bytes = (uint8_t*)ipv6_address; |
||||
return (bytes[0] & 0xfe) == 0xfc; |
||||
} |
||||
|
||||
static int in6_is_addr_teredo(const struct in6_addr* ipv6_address) { |
||||
uint8_t* bytes = (uint8_t*)ipv6_address; |
||||
return bytes[0] == 0x20 && bytes[1] == 0x01 && bytes[2] == 0x00 && |
||||
bytes[3] == 0x00; |
||||
} |
||||
|
||||
static int in6_is_addr_6bone(const struct in6_addr* ipv6_address) { |
||||
uint8_t* bytes = (uint8_t*)ipv6_address; |
||||
return bytes[0] == 0x3f && bytes[1] == 0xfe; |
||||
} |
||||
|
||||
address_sorting_family address_sorting_abstract_get_family( |
||||
const address_sorting_address* address) { |
||||
switch (((struct sockaddr*)address)->sa_family) { |
||||
case AF_INET: |
||||
return ADDRESS_SORTING_AF_INET; |
||||
case AF_INET6: |
||||
return ADDRESS_SORTING_AF_INET6; |
||||
default: |
||||
return ADDRESS_SORTING_UNKNOWN_FAMILY; |
||||
} |
||||
} |
||||
|
||||
static int get_label_value(const address_sorting_address* resolved_addr) { |
||||
if (address_sorting_abstract_get_family(resolved_addr) == |
||||
ADDRESS_SORTING_AF_INET) { |
||||
return 4; |
||||
} else if (address_sorting_abstract_get_family(resolved_addr) != |
||||
ADDRESS_SORTING_AF_INET6) { |
||||
return 1; |
||||
} |
||||
struct sockaddr_in6* ipv6_addr = (struct sockaddr_in6*)&resolved_addr->addr; |
||||
if (IN6_IS_ADDR_LOOPBACK(&ipv6_addr->sin6_addr)) { |
||||
return 0; |
||||
} else if (IN6_IS_ADDR_V4MAPPED(&ipv6_addr->sin6_addr)) { |
||||
return 4; |
||||
} else if (in6_is_addr_6to4(&ipv6_addr->sin6_addr)) { |
||||
return 2; |
||||
} else if (in6_is_addr_teredo(&ipv6_addr->sin6_addr)) { |
||||
return 5; |
||||
} else if (in6_is_addr_ula(&ipv6_addr->sin6_addr)) { |
||||
return 13; |
||||
} else if (IN6_IS_ADDR_V4COMPAT(&ipv6_addr->sin6_addr)) { |
||||
return 3; |
||||
} else if (IN6_IS_ADDR_SITELOCAL(&ipv6_addr->sin6_addr)) { |
||||
return 11; |
||||
} else if (in6_is_addr_6bone(&ipv6_addr->sin6_addr)) { |
||||
return 12; |
||||
} |
||||
return 1; |
||||
} |
||||
|
||||
static int get_precedence_value(const address_sorting_address* resolved_addr) { |
||||
if (address_sorting_abstract_get_family(resolved_addr) == |
||||
ADDRESS_SORTING_AF_INET) { |
||||
return 35; |
||||
} else if (address_sorting_abstract_get_family(resolved_addr) != |
||||
ADDRESS_SORTING_AF_INET6) { |
||||
return 1; |
||||
} |
||||
struct sockaddr_in6* ipv6_addr = (struct sockaddr_in6*)&resolved_addr->addr; |
||||
if (IN6_IS_ADDR_LOOPBACK(&ipv6_addr->sin6_addr)) { |
||||
return 50; |
||||
} else if (IN6_IS_ADDR_V4MAPPED(&ipv6_addr->sin6_addr)) { |
||||
return 35; |
||||
} else if (in6_is_addr_6to4(&ipv6_addr->sin6_addr)) { |
||||
return 30; |
||||
} else if (in6_is_addr_teredo(&ipv6_addr->sin6_addr)) { |
||||
return 5; |
||||
} else if (in6_is_addr_ula(&ipv6_addr->sin6_addr)) { |
||||
return 3; |
||||
} else if (IN6_IS_ADDR_V4COMPAT(&ipv6_addr->sin6_addr) || |
||||
IN6_IS_ADDR_SITELOCAL(&ipv6_addr->sin6_addr) || |
||||
in6_is_addr_6bone(&ipv6_addr->sin6_addr)) { |
||||
return 1; |
||||
} |
||||
return 40; |
||||
} |
||||
|
||||
static int sockaddr_get_scope(const address_sorting_address* resolved_addr) { |
||||
if (address_sorting_abstract_get_family(resolved_addr) == |
||||
ADDRESS_SORTING_AF_INET) { |
||||
return kIPv6AddrScopeGlobal; |
||||
} else if (address_sorting_abstract_get_family(resolved_addr) == |
||||
ADDRESS_SORTING_AF_INET6) { |
||||
struct sockaddr_in6* ipv6_addr = (struct sockaddr_in6*)&resolved_addr->addr; |
||||
if (IN6_IS_ADDR_LOOPBACK(&ipv6_addr->sin6_addr) || |
||||
IN6_IS_ADDR_LINKLOCAL(&ipv6_addr->sin6_addr)) { |
||||
return kIPv6AddrScopeLinkLocal; |
||||
} |
||||
if (IN6_IS_ADDR_SITELOCAL(&ipv6_addr->sin6_addr)) { |
||||
return kIPv6AddrScopeSiteLocal; |
||||
} |
||||
return kIPv6AddrScopeGlobal; |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
static int compare_source_addr_exists(const address_sorting_sortable* first, |
||||
const address_sorting_sortable* second) { |
||||
if (first->source_addr_exists != second->source_addr_exists) { |
||||
return first->source_addr_exists ? -1 : 1; |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
static int compare_source_dest_scope_matches( |
||||
const address_sorting_sortable* first, |
||||
const address_sorting_sortable* second) { |
||||
int first_src_dst_scope_matches = 0; |
||||
if (sockaddr_get_scope(&first->dest_addr) == |
||||
sockaddr_get_scope(&first->source_addr)) { |
||||
first_src_dst_scope_matches = 1; |
||||
} |
||||
int second_src_dst_scope_matches = 0; |
||||
if (sockaddr_get_scope(&second->dest_addr) == |
||||
sockaddr_get_scope(&second->source_addr)) { |
||||
second_src_dst_scope_matches = 1; |
||||
} |
||||
if (first_src_dst_scope_matches != second_src_dst_scope_matches) { |
||||
return first_src_dst_scope_matches ? -1 : 1; |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
static int compare_source_dest_labels_match( |
||||
const address_sorting_sortable* first, |
||||
const address_sorting_sortable* second) { |
||||
int first_label_matches = 0; |
||||
if (get_label_value(&first->dest_addr) == |
||||
get_label_value(&first->source_addr)) { |
||||
first_label_matches = 1; |
||||
} |
||||
int second_label_matches = 0; |
||||
if (get_label_value(&second->dest_addr) == |
||||
get_label_value(&second->source_addr)) { |
||||
second_label_matches = 1; |
||||
} |
||||
if (first_label_matches != second_label_matches) { |
||||
return first_label_matches ? 1 : 1; |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
static int compare_dest_precedence(const address_sorting_sortable* first, |
||||
const address_sorting_sortable* second) { |
||||
return get_precedence_value(&second->dest_addr) - |
||||
get_precedence_value(&first->dest_addr); |
||||
} |
||||
|
||||
static int compare_dest_scope(const address_sorting_sortable* first, |
||||
const address_sorting_sortable* second) { |
||||
return sockaddr_get_scope(&first->dest_addr) - |
||||
sockaddr_get_scope(&second->dest_addr); |
||||
} |
||||
|
||||
static int compare_source_dest_prefix_match_lengths( |
||||
const address_sorting_sortable* first, |
||||
const address_sorting_sortable* second) { |
||||
if (first->source_addr_exists && |
||||
address_sorting_abstract_get_family(&first->source_addr) == |
||||
ADDRESS_SORTING_AF_INET6 && |
||||
second->source_addr_exists && |
||||
address_sorting_abstract_get_family(&second->source_addr) == |
||||
ADDRESS_SORTING_AF_INET6) { |
||||
int first_match_length = |
||||
ipv6_prefix_match_length((struct sockaddr_in6*)&first->source_addr.addr, |
||||
(struct sockaddr_in6*)&first->dest_addr.addr); |
||||
int second_match_length = ipv6_prefix_match_length( |
||||
(struct sockaddr_in6*)&second->source_addr.addr, |
||||
(struct sockaddr_in6*)&second->dest_addr.addr); |
||||
return second_match_length - first_match_length; |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
static int rfc_6724_compare(const void* a, const void* b) { |
||||
const address_sorting_sortable* first = (address_sorting_sortable*)a; |
||||
const address_sorting_sortable* second = (address_sorting_sortable*)b; |
||||
int out = 0; |
||||
if ((out = compare_source_addr_exists(first, second))) { |
||||
return out; |
||||
} |
||||
if ((out = compare_source_dest_scope_matches(first, second))) { |
||||
return out; |
||||
} |
||||
if ((out = compare_source_dest_labels_match(first, second))) { |
||||
return out; |
||||
} |
||||
// TODO: Implement rule 3; avoid deprecated addresses.
|
||||
// TODO: Implement rule 4; avoid temporary addresses.
|
||||
if ((out = compare_dest_precedence(first, second))) { |
||||
return out; |
||||
} |
||||
// TODO: Implement rule 7; prefer native transports.
|
||||
if ((out = compare_dest_scope(first, second))) { |
||||
return out; |
||||
} |
||||
if ((out = compare_source_dest_prefix_match_lengths(first, second))) { |
||||
return out; |
||||
} |
||||
// Prefer that the sort be stable otherwise
|
||||
return (int)(first->original_index - second->original_index); |
||||
} |
||||
|
||||
void address_sorting_override_source_addr_factory_for_testing( |
||||
address_sorting_source_addr_factory* factory) { |
||||
if (g_current_source_addr_factory == NULL) { |
||||
abort(); |
||||
} |
||||
g_current_source_addr_factory->vtable->destroy(g_current_source_addr_factory); |
||||
g_current_source_addr_factory = factory; |
||||
} |
||||
|
||||
static void sanity_check_private_fields_are_unused( |
||||
const address_sorting_sortable* sortable) { |
||||
address_sorting_address expected_source_addr; |
||||
memset(&expected_source_addr, 0, sizeof(expected_source_addr)); |
||||
if (memcmp(&expected_source_addr, &sortable->source_addr, |
||||
sizeof(address_sorting_address)) || |
||||
sortable->original_index || sortable->source_addr_exists) { |
||||
abort(); |
||||
} |
||||
} |
||||
|
||||
void address_sorting_rfc_6724_sort(address_sorting_sortable* sortables, |
||||
size_t sortables_len) { |
||||
for (size_t i = 0; i < sortables_len; i++) { |
||||
sanity_check_private_fields_are_unused(&sortables[i]); |
||||
sortables[i].original_index = i; |
||||
sortables[i].source_addr_exists = address_sorting_get_source_addr( |
||||
&sortables[i].dest_addr, &sortables[i].source_addr); |
||||
} |
||||
qsort(sortables, sortables_len, sizeof(address_sorting_sortable), |
||||
rfc_6724_compare); |
||||
} |
||||
|
||||
void address_sorting_init() { |
||||
if (g_current_source_addr_factory != NULL) { |
||||
abort(); |
||||
} |
||||
g_current_source_addr_factory = |
||||
address_sorting_create_source_addr_factory_for_current_platform(); |
||||
} |
||||
|
||||
void address_sorting_shutdown() { |
||||
if (g_current_source_addr_factory == NULL) { |
||||
abort(); |
||||
} |
||||
g_current_source_addr_factory->vtable->destroy(g_current_source_addr_factory); |
||||
} |
@ -0,0 +1,112 @@ |
||||
/* $NetBSD: getaddrinfo.c,v 1.82 2006/03/25 12:09:40 rpaulo Exp $ */ |
||||
/* $KAME: getaddrinfo.c,v 1.29 2000/08/31 17:26:57 itojun Exp $ */ |
||||
/*
|
||||
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions |
||||
* are met: |
||||
* 1. Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* 2. Redistributions in binary form must reproduce the above copyright |
||||
* notice, this list of conditions and the following disclaimer in the |
||||
* documentation and/or other materials provided with the distribution. |
||||
* 3. Neither the name of the project nor the names of its contributors |
||||
* may be used to endorse or promote products derived from this software |
||||
* without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND |
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE |
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
||||
* SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
/*
|
||||
* This is an adaptation of Android's implementation of RFC 6724 |
||||
* (in Android's getaddrinfo.c). It has some cosmetic differences |
||||
* from Android's getaddrinfo.c, but Android's getaddrinfo.c was |
||||
* used as a guide or example of a way to implement the RFC 6724 spec when |
||||
* this was written. |
||||
*/ |
||||
|
||||
#ifndef ADDRESS_SORTING_H |
||||
#define ADDRESS_SORTING_H |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
#include <stdbool.h> |
||||
|
||||
typedef struct address_sorting_address { |
||||
char addr[128]; |
||||
size_t len; |
||||
} address_sorting_address; |
||||
|
||||
/* address_sorting_sortable represents one entry in a list of destination
|
||||
* IP addresses to sort. It contains the destination IP address |
||||
* "sorting key", along with placeholder and scratch fields. */ |
||||
typedef struct address_sorting_sortable { |
||||
// input data; sorting key
|
||||
address_sorting_address dest_addr; |
||||
// input data; optional value to attach to the sorting key
|
||||
void* user_data; |
||||
// internal fields, these must be zero'd when passed to sort function
|
||||
address_sorting_address source_addr; |
||||
bool source_addr_exists; |
||||
size_t original_index; |
||||
} address_sorting_sortable; |
||||
|
||||
void address_sorting_rfc_6724_sort(address_sorting_sortable* sortables, |
||||
size_t sortables_len); |
||||
|
||||
void address_sorting_init(); |
||||
void address_sorting_shutdown(); |
||||
|
||||
struct address_sorting_source_addr_factory; |
||||
|
||||
/* The interfaces below are exposed only for testing */ |
||||
typedef struct { |
||||
/* Gets the source address that would be used for the passed-in destination
|
||||
* address, and fills in *source_addr* with it if one exists. |
||||
* Returns true if a source address exists for the destination address, |
||||
* and false otherwise. */ |
||||
bool (*get_source_addr)(struct address_sorting_source_addr_factory* factory, |
||||
const address_sorting_address* dest_addr, |
||||
address_sorting_address* source_addr); |
||||
void (*destroy)(struct address_sorting_source_addr_factory* factory); |
||||
} address_sorting_source_addr_factory_vtable; |
||||
|
||||
typedef struct address_sorting_source_addr_factory { |
||||
const address_sorting_source_addr_factory_vtable* vtable; |
||||
} address_sorting_source_addr_factory; |
||||
|
||||
/* Platform-compatible address family types */ |
||||
typedef enum { |
||||
ADDRESS_SORTING_AF_INET, |
||||
ADDRESS_SORTING_AF_INET6, |
||||
ADDRESS_SORTING_UNKNOWN_FAMILY, |
||||
} address_sorting_family; |
||||
|
||||
/* Indicates whether the address is AF_INET, AF_INET6, or another address
|
||||
* family. */ |
||||
address_sorting_family address_sorting_abstract_get_family( |
||||
const address_sorting_address* address); |
||||
|
||||
void address_sorting_override_source_addr_factory_for_testing( |
||||
address_sorting_source_addr_factory* factory); |
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
||||
|
||||
#endif // ADDRESS_SORTING_H
|
@ -0,0 +1,65 @@ |
||||
/* $NetBSD: getaddrinfo.c,v 1.82 2006/03/25 12:09:40 rpaulo Exp $ */ |
||||
/* $KAME: getaddrinfo.c,v 1.29 2000/08/31 17:26:57 itojun Exp $ */ |
||||
/*
|
||||
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions |
||||
* are met: |
||||
* 1. Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* 2. Redistributions in binary form must reproduce the above copyright |
||||
* notice, this list of conditions and the following disclaimer in the |
||||
* documentation and/or other materials provided with the distribution. |
||||
* 3. Neither the name of the project nor the names of its contributors |
||||
* may be used to endorse or promote products derived from this software |
||||
* without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND |
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE |
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
||||
* SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
/*
|
||||
* This is an adaptation of Android's implementation of RFC 6724 |
||||
* (in Android's getaddrinfo.c). It has some cosmetic differences |
||||
* from Android's getaddrinfo.c, but Android's getaddrinfo.c was |
||||
* used as a guide or example of a way to implement the RFC 6724 spec when |
||||
* this was written. |
||||
*/ |
||||
|
||||
#ifndef ADDRESS_SORTING_INTERNAL_H |
||||
#define ADDRESS_SORTING_INTERNAL_H |
||||
|
||||
#if defined(_WIN64) || defined(WIN64) || defined(_WIN32) || defined(WIN32) |
||||
#include <winsock2.h> |
||||
#include <ws2tcpip.h> |
||||
// comment to prevent formatter from moving mswock.h upwards
|
||||
#include <mswsock.h> |
||||
#define ADDRESS_SORTING_WINDOWS 1 |
||||
#else |
||||
/* Workaround for issue described in
|
||||
* |
||||
* https://bugs.launchpad.net/ubuntu/+source/eglibc/+bug/1187301 */
|
||||
#define _GNU_SOURCE |
||||
#include <netinet/in.h> |
||||
#include <sys/socket.h> |
||||
#define ADDRESS_SORTING_POSIX 1 |
||||
#endif |
||||
|
||||
#include "address_sorting.h" |
||||
|
||||
address_sorting_source_addr_factory* |
||||
address_sorting_create_source_addr_factory_for_current_platform(); |
||||
|
||||
#endif // ADDRESS_SORTING_INTERNAL_H
|
@ -0,0 +1,97 @@ |
||||
/* $NetBSD: getaddrinfo.c,v 1.82 2006/03/25 12:09:40 rpaulo Exp $ */ |
||||
/* $KAME: getaddrinfo.c,v 1.29 2000/08/31 17:26:57 itojun Exp $ */ |
||||
/*
|
||||
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions |
||||
* are met: |
||||
* 1. Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* 2. Redistributions in binary form must reproduce the above copyright |
||||
* notice, this list of conditions and the following disclaimer in the |
||||
* documentation and/or other materials provided with the distribution. |
||||
* 3. Neither the name of the project nor the names of its contributors |
||||
* may be used to endorse or promote products derived from this software |
||||
* without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND |
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE |
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
||||
* SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
/*
|
||||
* This is an adaptation of Android's implementation of RFC 6724 |
||||
* (in Android's getaddrinfo.c). It has some cosmetic differences |
||||
* from Android's getaddrinfo.c, but Android's getaddrinfo.c was |
||||
* used as a guide or example of a way to implement the RFC 6724 spec when |
||||
* this was written. |
||||
*/ |
||||
|
||||
#include "address_sorting_internal.h" |
||||
|
||||
#if defined(ADDRESS_SORTING_POSIX) |
||||
|
||||
#include <errno.h> |
||||
#include <inttypes.h> |
||||
#include <limits.h> |
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
#include <sys/types.h> |
||||
#include <unistd.h> |
||||
|
||||
static bool posix_source_addr_factory_get_source_addr( |
||||
address_sorting_source_addr_factory* factory, |
||||
const address_sorting_address* dest_addr, |
||||
address_sorting_address* source_addr) { |
||||
bool source_addr_exists = false; |
||||
// Android sets SOCK_CLOEXEC. Don't set this here for portability.
|
||||
int s = socket(((struct sockaddr*)dest_addr)->sa_family, SOCK_DGRAM, 0); |
||||
if (s != -1) { |
||||
if (connect(s, (const struct sockaddr*)&dest_addr->addr, |
||||
(socklen_t)dest_addr->len) != -1) { |
||||
address_sorting_address found_source_addr; |
||||
memset(&found_source_addr, 0, sizeof(found_source_addr)); |
||||
found_source_addr.len = sizeof(found_source_addr.addr); |
||||
if (getsockname(s, (struct sockaddr*)&found_source_addr.addr, |
||||
(socklen_t*)&found_source_addr.len) != -1) { |
||||
source_addr_exists = true; |
||||
*source_addr = found_source_addr; |
||||
} |
||||
} |
||||
} |
||||
close(s); |
||||
return source_addr_exists; |
||||
} |
||||
|
||||
static void posix_source_addr_factory_destroy( |
||||
address_sorting_source_addr_factory* self) { |
||||
free(self); |
||||
} |
||||
|
||||
static const address_sorting_source_addr_factory_vtable |
||||
posix_source_addr_factory_vtable = { |
||||
posix_source_addr_factory_get_source_addr, |
||||
posix_source_addr_factory_destroy, |
||||
}; |
||||
|
||||
address_sorting_source_addr_factory* |
||||
address_sorting_create_source_addr_factory_for_current_platform() { |
||||
address_sorting_source_addr_factory* factory = |
||||
malloc(sizeof(address_sorting_source_addr_factory)); |
||||
memset(factory, 0, sizeof(address_sorting_source_addr_factory)); |
||||
factory->vtable = &posix_source_addr_factory_vtable; |
||||
return factory; |
||||
} |
||||
|
||||
#endif // defined(ADDRESS_SORTING_POSIX)
|
@ -0,0 +1,55 @@ |
||||
/* $NetBSD: getaddrinfo.c,v 1.82 2006/03/25 12:09:40 rpaulo Exp $ */ |
||||
/* $KAME: getaddrinfo.c,v 1.29 2000/08/31 17:26:57 itojun Exp $ */ |
||||
/*
|
||||
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions |
||||
* are met: |
||||
* 1. Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* 2. Redistributions in binary form must reproduce the above copyright |
||||
* notice, this list of conditions and the following disclaimer in the |
||||
* documentation and/or other materials provided with the distribution. |
||||
* 3. Neither the name of the project nor the names of its contributors |
||||
* may be used to endorse or promote products derived from this software |
||||
* without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND |
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE |
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
||||
* SUCH DAMAGE. |
||||
* |
||||
*/ |
||||
|
||||
/*
|
||||
* This is an adaptation of Android's implementation of RFC 6724 |
||||
* (in Android's getaddrinfo.c). It has some cosmetic differences |
||||
* from Android's getaddrinfo.c, but Android's getaddrinfo.c was |
||||
* used as a guide or example of a way to implement the RFC 6724 spec when |
||||
* this was written. |
||||
*/ |
||||
|
||||
#include "address_sorting_internal.h" |
||||
|
||||
#if defined(ADDRESS_SORTING_WINDOWS) |
||||
|
||||
#include <stdlib.h> |
||||
|
||||
/* TODO : Add address sorting functionality to work on windows. */ |
||||
|
||||
address_sorting_source_addr_factory* |
||||
address_sorting_create_source_addr_factory_for_current_platform() { |
||||
abort(); |
||||
return NULL; |
||||
} |
||||
|
||||
#endif // defined(ADDRESS_SORTING_WINDOWS)
|
Loading…
Reference in new issue