123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378 |
- // Copyright (c) 2012 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "net/dns/address_sorter_posix.h"
- #include <memory>
- #include <string>
- #include <vector>
- #include "base/bind.h"
- #include "base/check_op.h"
- #include "base/memory/raw_ptr.h"
- #include "base/notreached.h"
- #include "net/base/ip_address.h"
- #include "net/base/ip_endpoint.h"
- #include "net/base/net_errors.h"
- #include "net/base/test_completion_callback.h"
- #include "net/log/net_log_with_source.h"
- #include "net/socket/client_socket_factory.h"
- #include "net/socket/datagram_client_socket.h"
- #include "net/socket/socket_performance_watcher.h"
- #include "net/socket/ssl_client_socket.h"
- #include "net/socket/stream_socket.h"
- #include "net/test/test_with_task_environment.h"
- #include "net/traffic_annotation/network_traffic_annotation.h"
- #include "testing/gmock/include/gmock/gmock.h"
- #include "testing/gtest/include/gtest/gtest.h"
- namespace net {
- namespace {
- // Used to map destination address to source address.
- typedef std::map<IPAddress, IPAddress> AddressMapping;
- IPAddress ParseIP(const std::string& str) {
- IPAddress addr;
- CHECK(addr.AssignFromIPLiteral(str));
- return addr;
- }
- // A mock socket which binds to source address according to AddressMapping.
- class TestUDPClientSocket : public DatagramClientSocket {
- public:
- explicit TestUDPClientSocket(const AddressMapping* mapping)
- : mapping_(mapping) {}
- TestUDPClientSocket(const TestUDPClientSocket&) = delete;
- TestUDPClientSocket& operator=(const TestUDPClientSocket&) = delete;
- ~TestUDPClientSocket() override = default;
- int Read(IOBuffer*, int, CompletionOnceCallback) override {
- NOTIMPLEMENTED();
- return OK;
- }
- int Write(IOBuffer*,
- int,
- CompletionOnceCallback,
- const NetworkTrafficAnnotationTag& traffic_annotation) override {
- NOTIMPLEMENTED();
- return OK;
- }
- int SetReceiveBufferSize(int32_t) override { return OK; }
- int SetSendBufferSize(int32_t) override { return OK; }
- int SetDoNotFragment() override { return OK; }
- void Close() override {}
- int GetPeerAddress(IPEndPoint* address) const override {
- NOTIMPLEMENTED();
- return OK;
- }
- int GetLocalAddress(IPEndPoint* address) const override {
- if (!connected_)
- return ERR_UNEXPECTED;
- *address = local_endpoint_;
- return OK;
- }
- void UseNonBlockingIO() override {}
- int SetMulticastInterface(uint32_t interface_index) override {
- NOTIMPLEMENTED();
- return ERR_NOT_IMPLEMENTED;
- }
- int ConnectUsingNetwork(handles::NetworkHandle network,
- const IPEndPoint& address) override {
- NOTIMPLEMENTED();
- return ERR_NOT_IMPLEMENTED;
- }
- int ConnectUsingDefaultNetwork(const IPEndPoint& address) override {
- NOTIMPLEMENTED();
- return ERR_NOT_IMPLEMENTED;
- }
- handles::NetworkHandle GetBoundNetwork() const override {
- return handles::kInvalidNetworkHandle;
- }
- void ApplySocketTag(const SocketTag& tag) override {}
- void SetMsgConfirm(bool confirm) override {}
- int Connect(const IPEndPoint& remote) override {
- if (connected_)
- return ERR_UNEXPECTED;
- auto it = mapping_->find(remote.address());
- if (it == mapping_->end())
- return ERR_FAILED;
- connected_ = true;
- local_endpoint_ = IPEndPoint(it->second, 39874 /* arbitrary port */);
- return OK;
- }
- const NetLogWithSource& NetLog() const override { return net_log_; }
- private:
- NetLogWithSource net_log_;
- raw_ptr<const AddressMapping> mapping_;
- bool connected_ = false;
- IPEndPoint local_endpoint_;
- };
- // Creates TestUDPClientSockets and maintains an AddressMapping.
- class TestSocketFactory : public ClientSocketFactory {
- public:
- TestSocketFactory() = default;
- TestSocketFactory(const TestSocketFactory&) = delete;
- TestSocketFactory& operator=(const TestSocketFactory&) = delete;
- ~TestSocketFactory() override = default;
- std::unique_ptr<DatagramClientSocket> CreateDatagramClientSocket(
- DatagramSocket::BindType,
- NetLog*,
- const NetLogSource&) override {
- return std::make_unique<TestUDPClientSocket>(&mapping_);
- }
- std::unique_ptr<TransportClientSocket> CreateTransportClientSocket(
- const AddressList&,
- std::unique_ptr<SocketPerformanceWatcher>,
- net::NetworkQualityEstimator*,
- NetLog*,
- const NetLogSource&) override {
- NOTIMPLEMENTED();
- return nullptr;
- }
- std::unique_ptr<SSLClientSocket> CreateSSLClientSocket(
- SSLClientContext*,
- std::unique_ptr<StreamSocket>,
- const HostPortPair&,
- const SSLConfig&) override {
- NOTIMPLEMENTED();
- return nullptr;
- }
- void AddMapping(const IPAddress& dst, const IPAddress& src) {
- mapping_[dst] = src;
- }
- private:
- AddressMapping mapping_;
- };
- void OnSortComplete(std::vector<IPEndPoint>* sorted_buf,
- CompletionOnceCallback callback,
- bool success,
- std::vector<IPEndPoint> sorted) {
- EXPECT_TRUE(success);
- if (success)
- *sorted_buf = std::move(sorted);
- std::move(callback).Run(OK);
- }
- } // namespace
- // TaskEnvironment is required to register an IPAddressObserver from the
- // constructor of AddressSorterPosix.
- class AddressSorterPosixTest : public TestWithTaskEnvironment {
- protected:
- AddressSorterPosixTest() : sorter_(&socket_factory_) {}
- void AddMapping(const std::string& dst, const std::string& src) {
- socket_factory_.AddMapping(ParseIP(dst), ParseIP(src));
- }
- AddressSorterPosix::SourceAddressInfo* GetSourceInfo(
- const std::string& addr) {
- IPAddress address = ParseIP(addr);
- AddressSorterPosix::SourceAddressInfo* info = &sorter_.source_map_[address];
- if (info->scope == AddressSorterPosix::SCOPE_UNDEFINED)
- sorter_.FillPolicy(address, info);
- return info;
- }
- // Verify that NULL-terminated |addresses| matches (-1)-terminated |order|
- // after sorting.
- void Verify(const char* const addresses[], const int order[]) {
- std::vector<IPEndPoint> endpoints;
- for (const char* const* addr = addresses; *addr != nullptr; ++addr)
- endpoints.emplace_back(ParseIP(*addr), 80);
- for (size_t i = 0; order[i] >= 0; ++i)
- CHECK_LT(order[i], static_cast<int>(endpoints.size()));
- std::vector<IPEndPoint> sorted;
- TestCompletionCallback callback;
- sorter_.Sort(endpoints,
- base::BindOnce(&OnSortComplete, &sorted, callback.callback()));
- callback.WaitForResult();
- for (size_t i = 0; (i < sorted.size()) || (order[i] >= 0); ++i) {
- IPEndPoint expected = order[i] >= 0 ? endpoints[order[i]] : IPEndPoint();
- IPEndPoint actual = i < sorted.size() ? sorted[i] : IPEndPoint();
- EXPECT_TRUE(expected == actual)
- << "Endpoint out of order at position " << i << "\n"
- << " Actual: " << actual.ToString() << "\n"
- << "Expected: " << expected.ToString();
- }
- }
- TestSocketFactory socket_factory_;
- AddressSorterPosix sorter_;
- };
- // Rule 1: Avoid unusable destinations.
- TEST_F(AddressSorterPosixTest, Rule1) {
- AddMapping("10.0.0.231", "10.0.0.1");
- const char* const addresses[] = {"::1", "10.0.0.231", "127.0.0.1", nullptr};
- const int order[] = { 1, -1 };
- Verify(addresses, order);
- }
- // Rule 2: Prefer matching scope.
- TEST_F(AddressSorterPosixTest, Rule2) {
- AddMapping("3002::1", "4000::10"); // matching global
- AddMapping("ff32::1", "fe81::10"); // matching link-local
- AddMapping("fec1::1", "fec1::10"); // matching node-local
- AddMapping("3002::2", "::1"); // global vs. link-local
- AddMapping("fec1::2", "fe81::10"); // site-local vs. link-local
- AddMapping("8.0.0.1", "169.254.0.10"); // global vs. link-local
- // In all three cases, matching scope is preferred.
- const int order[] = { 1, 0, -1 };
- const char* const addresses1[] = {"3002::2", "3002::1", nullptr};
- Verify(addresses1, order);
- const char* const addresses2[] = {"fec1::2", "ff32::1", nullptr};
- Verify(addresses2, order);
- const char* const addresses3[] = {"8.0.0.1", "fec1::1", nullptr};
- Verify(addresses3, order);
- }
- // Rule 3: Avoid deprecated addresses.
- TEST_F(AddressSorterPosixTest, Rule3) {
- // Matching scope.
- AddMapping("3002::1", "4000::10");
- GetSourceInfo("4000::10")->deprecated = true;
- AddMapping("3002::2", "4000::20");
- const char* const addresses[] = {"3002::1", "3002::2", nullptr};
- const int order[] = { 1, 0, -1 };
- Verify(addresses, order);
- }
- // Rule 4: Prefer home addresses.
- TEST_F(AddressSorterPosixTest, Rule4) {
- AddMapping("3002::1", "4000::10");
- AddMapping("3002::2", "4000::20");
- GetSourceInfo("4000::20")->home = true;
- const char* const addresses[] = {"3002::1", "3002::2", nullptr};
- const int order[] = { 1, 0, -1 };
- Verify(addresses, order);
- }
- // Rule 5: Prefer matching label.
- TEST_F(AddressSorterPosixTest, Rule5) {
- AddMapping("::1", "::1"); // matching loopback
- AddMapping("::ffff:1234:1", "::ffff:1234:10"); // matching IPv4-mapped
- AddMapping("2001::1", "::ffff:1234:10"); // Teredo vs. IPv4-mapped
- AddMapping("2002::1", "2001::10"); // 6to4 vs. Teredo
- const int order[] = { 1, 0, -1 };
- {
- const char* const addresses[] = {"2001::1", "::1", nullptr};
- Verify(addresses, order);
- }
- {
- const char* const addresses[] = {"2002::1", "::ffff:1234:1", nullptr};
- Verify(addresses, order);
- }
- }
- // Rule 6: Prefer higher precedence.
- TEST_F(AddressSorterPosixTest, Rule6) {
- AddMapping("::1", "::1"); // loopback
- AddMapping("ff32::1", "fe81::10"); // multicast
- AddMapping("::ffff:1234:1", "::ffff:1234:10"); // IPv4-mapped
- AddMapping("2001::1", "2001::10"); // Teredo
- const char* const addresses[] = {"2001::1", "::ffff:1234:1", "ff32::1", "::1",
- nullptr};
- const int order[] = { 3, 2, 1, 0, -1 };
- Verify(addresses, order);
- }
- // Rule 7: Prefer native transport.
- TEST_F(AddressSorterPosixTest, Rule7) {
- AddMapping("3002::1", "4000::10");
- AddMapping("3002::2", "4000::20");
- GetSourceInfo("4000::20")->native = true;
- const char* const addresses[] = {"3002::1", "3002::2", nullptr};
- const int order[] = { 1, 0, -1 };
- Verify(addresses, order);
- }
- // Rule 8: Prefer smaller scope.
- TEST_F(AddressSorterPosixTest, Rule8) {
- // Matching scope. Should precede the others by Rule 2.
- AddMapping("fe81::1", "fe81::10"); // link-local
- AddMapping("3000::1", "4000::10"); // global
- // Mismatched scope.
- AddMapping("ff32::1", "4000::10"); // link-local
- AddMapping("ff35::1", "4000::10"); // site-local
- AddMapping("ff38::1", "4000::10"); // org-local
- const char* const addresses[] = {"ff38::1", "3000::1", "ff35::1",
- "ff32::1", "fe81::1", nullptr};
- const int order[] = { 4, 1, 3, 2, 0, -1 };
- Verify(addresses, order);
- }
- // Rule 9: Use longest matching prefix.
- TEST_F(AddressSorterPosixTest, Rule9) {
- AddMapping("3000::1", "3000:ffff::10"); // 16 bit match
- GetSourceInfo("3000:ffff::10")->prefix_length = 16;
- AddMapping("4000::1", "4000::10"); // 123 bit match, limited to 15
- GetSourceInfo("4000::10")->prefix_length = 15;
- AddMapping("4002::1", "4000::10"); // 14 bit match
- AddMapping("4080::1", "4000::10"); // 8 bit match
- const char* const addresses[] = {"4080::1", "4002::1", "4000::1", "3000::1",
- nullptr};
- const int order[] = { 3, 2, 1, 0, -1 };
- Verify(addresses, order);
- }
- // Rule 10: Leave the order unchanged.
- TEST_F(AddressSorterPosixTest, Rule10) {
- AddMapping("4000::1", "4000::10");
- AddMapping("4000::2", "4000::10");
- AddMapping("4000::3", "4000::10");
- const char* const addresses[] = {"4000::1", "4000::2", "4000::3", nullptr};
- const int order[] = { 0, 1, 2, -1 };
- Verify(addresses, order);
- }
- TEST_F(AddressSorterPosixTest, MultipleRules) {
- AddMapping("::1", "::1"); // loopback
- AddMapping("ff32::1", "fe81::10"); // link-local multicast
- AddMapping("ff3e::1", "4000::10"); // global multicast
- AddMapping("4000::1", "4000::10"); // global unicast
- AddMapping("ff32::2", "fe81::20"); // deprecated link-local multicast
- GetSourceInfo("fe81::20")->deprecated = true;
- const char* const addresses[] = {"ff3e::1", "ff32::2", "4000::1", "ff32::1",
- "::1", "8.0.0.1", nullptr};
- const int order[] = { 4, 3, 0, 2, 1, -1 };
- Verify(addresses, order);
- }
- TEST_F(AddressSorterPosixTest, InputPortsAreMaintained) {
- AddMapping("::1", "::1");
- AddMapping("::2", "::2");
- AddMapping("::3", "::3");
- IPEndPoint endpoint1(ParseIP("::1"), /*port=*/111);
- IPEndPoint endpoint2(ParseIP("::2"), /*port=*/222);
- IPEndPoint endpoint3(ParseIP("::3"), /*port=*/333);
- std::vector<IPEndPoint> input = {endpoint1, endpoint2, endpoint3};
- std::vector<IPEndPoint> sorted;
- TestCompletionCallback callback;
- sorter_.Sort(input,
- base::BindOnce(&OnSortComplete, &sorted, callback.callback()));
- callback.WaitForResult();
- EXPECT_THAT(sorted, testing::ElementsAre(endpoint1, endpoint2, endpoint3));
- }
- } // namespace net
|