#include "net/base/address_tracker_linux.h"
#include <linux/if.h>
#include <linux/rtnetlink.h>
#include <sched.h>
#include <array>
#include <memory>
#include <unordered_set>
#include <vector>
#include "base/command_line.h"
#include "base/containers/span.h"
#include "base/files/file_util.h"
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/memory/raw_ptr.h"
#include "base/strings/string_number_conversions.h"
#include "base/synchronization/waitable_event.h"
#include "base/test/bind.h"
#include "base/test/multiprocess_test.h"
#include "base/test/spin_wait.h"
#include "base/test/task_environment.h"
#include "base/test/test_simple_task_runner.h"
#include "base/threading/simple_thread.h"
#include "build/build_config.h"
#include "net/base/address_map_cache_linux.h"
#include "net/base/address_map_linux.h"
#include "net/base/address_tracker_linux_test_util.h"
#include "net/base/ip_address.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/multiprocess_func_list.h"
#if BUILDFLAG(IS_ANDROID)
#include "base/android/android_info.h"
#endif
#ifndef IFA_F_HOMEADDRESS
#define IFA_F_HOMEADDRESS 0x10
#endif
using net::internal::AddressTrackerLinux;
namespace net::test {
namespace {
const int kTestInterfaceEth = 1;
const int kTestInterfaceWifi = 2;
const int kTestInterfaceTun = 123;
const int kTestInterfaceAp = 456;
const char kIgnoredInterfaceName[] = "uap0";
std::string TestGetInterfaceName(int interface_index) {
switch (interface_index) {
case kTestInterfaceEth:
return "eth0";
case kTestInterfaceTun:
return "tun0";
case kTestInterfaceAp:
return kIgnoredInterfaceName;
default:
return std::string();
}
}
}
class AddressTrackerLinuxTest : public testing::Test {
protected:
AddressTrackerLinuxTest() = default;
void InitializeAddressTracker(bool tracking) {
tracking_ = tracking;
if (tracking) {
tracker_ = std::make_unique<AddressTrackerLinux>(
base::DoNothing(), base::DoNothing(), base::DoNothing(),
ignored_interfaces_);
#if BUILDFLAG(IS_LINUX)
const auto& [address_map, online_links] =
tracker_->GetInitialDataAndStartRecordingDiffs();
address_map_cache_.SetCachedInfo(address_map, online_links);
#endif
} else {
tracker_ = std::make_unique<AddressTrackerLinux>();
}
original_get_interface_name_ = tracker_->get_interface_name_;
tracker_->get_interface_name_ = TestGetInterfaceName;
}
bool HandleAddressMessage(const NetlinkBuffer& buf) {
NetlinkBuffer writable_buf = buf;
NetworkChangeNotifier::IPAddressChangeType address_change_type =
NetworkChangeNotifier::IP_ADDRESS_CHANGE_NONE;
bool link_changed = false;
bool tunnel_changed = false;
tracker_->HandleMessage(&writable_buf[0], buf.size(), &address_change_type,
&link_changed, &tunnel_changed);
UpdateCache();
EXPECT_FALSE(link_changed);
if (buf.size() < sizeof(nlmsghdr) + sizeof(ifaddrmsg)) {
ADD_FAILURE() << "Message too small to read flags";
return false;
}
const ifaddrmsg* msg = UNSAFE_BUFFERS(
reinterpret_cast<const ifaddrmsg*>(buf.data() + sizeof(nlmsghdr)));
bool ipv6_tempaddr_changed =
msg->ifa_family == AF_INET6 && msg->ifa_flags & IFA_F_TEMPORARY;
EXPECT_TRUE(address_change_type ==
NetworkChangeNotifier::IP_ADDRESS_CHANGE_NONE ||
(address_change_type ==
NetworkChangeNotifier::IP_ADDRESS_CHANGE_IPV6_TEMPADDR &&
ipv6_tempaddr_changed) ||
(address_change_type ==
NetworkChangeNotifier::IP_ADDRESS_CHANGE_NORMAL &&
!ipv6_tempaddr_changed));
return address_change_type != NetworkChangeNotifier::IP_ADDRESS_CHANGE_NONE;
}
bool HandleLinkMessage(const NetlinkBuffer& buf) {
NetlinkBuffer writable_buf = buf;
NetworkChangeNotifier::IPAddressChangeType address_change_type =
NetworkChangeNotifier::IP_ADDRESS_CHANGE_NONE;
bool link_changed = false;
bool tunnel_changed = false;
tracker_->HandleMessage(&writable_buf[0], buf.size(), &address_change_type,
&link_changed, &tunnel_changed);
UpdateCache();
EXPECT_TRUE(address_change_type ==
NetworkChangeNotifier::IP_ADDRESS_CHANGE_NONE);
return link_changed;
}
bool HandleTunnelMessage(const NetlinkBuffer& buf) {
NetlinkBuffer writable_buf = buf;
NetworkChangeNotifier::IPAddressChangeType address_change_type =
NetworkChangeNotifier::IP_ADDRESS_CHANGE_NONE;
bool link_changed = false;
bool tunnel_changed = false;
AddressMapOwnerLinux::AddressMapDiff address_map_diff_;
AddressMapOwnerLinux::OnlineLinksDiff online_links_diff_;
tracker_->HandleMessage(&writable_buf[0], buf.size(), &address_change_type,
&link_changed, &tunnel_changed);
UpdateCache();
EXPECT_TRUE(address_change_type ==
NetworkChangeNotifier::IP_ADDRESS_CHANGE_NONE);
return tunnel_changed;
}
AddressTrackerLinux::AddressMap GetAddressMap() {
return tracker_->GetAddressMap();
}
const std::unordered_set<int> GetOnlineLinks() const {
return tracker_->GetOnlineLinks();
}
void IgnoreInterface(const std::string& interface_name) {
ignored_interfaces_.insert(interface_name);
}
int GetThreadsWaitingForConnectionTypeInit() {
return tracker_->GetThreadsWaitingForConnectionTypeInitForTesting();
}
std::unordered_set<std::string> ignored_interfaces_;
std::unique_ptr<AddressTrackerLinux> tracker_;
AddressTrackerLinux::GetInterfaceNameFunction original_get_interface_name_;
private:
void UpdateCache() {
if (!tracking_) {
return;
}
#if BUILDFLAG(IS_LINUX)
address_map_cache_.ApplyDiffs(tracker_->address_map_diff_for_testing(),
tracker_->online_links_diff_for_testing());
EXPECT_EQ(address_map_cache_.GetAddressMap(), tracker_->GetAddressMap());
EXPECT_EQ(address_map_cache_.GetOnlineLinks(), tracker_->GetOnlineLinks());
tracker_->address_map_diff_for_testing().clear();
tracker_->online_links_diff_for_testing().clear();
#endif
}
#if BUILDFLAG(IS_LINUX)
AddressMapCacheLinux address_map_cache_;
#endif
bool tracking_;
};
namespace {
const unsigned char kAddress0[] = { 127, 0, 0, 1 };
const unsigned char kAddress1[] = { 10, 0, 0, 1 };
const unsigned char kAddress2[] = { 192, 168, 0, 1 };
const unsigned char kAddress3[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 1 };
const unsigned char kAddress4[] = {0xfd, 0x00, 0, 0, 0, 0,
0, 0, 0xe9, 0xb2, 0x0b, 0x84,
0xb3, 0xd5, 0xff, 0x0b};
TEST_F(AddressTrackerLinuxTest, NewAddress) {
InitializeAddressTracker(true);
const IPAddress kEmpty;
const IPAddress kAddr0(kAddress0);
const IPAddress kAddr1(kAddress1);
const IPAddress kAddr2(kAddress2);
const IPAddress kAddr3(kAddress3);
const IPAddress kAddr4(kAddress4);
NetlinkBuffer buffer;
MakeAddrMessage(RTM_NEWADDR, IFA_F_TEMPORARY, AF_INET, kTestInterfaceEth,
kAddr0, kEmpty, &buffer);
EXPECT_TRUE(HandleAddressMessage(buffer));
AddressTrackerLinux::AddressMap map = GetAddressMap();
EXPECT_EQ(1u, map.size());
EXPECT_EQ(1u, map.count(kAddr0));
EXPECT_EQ(IFA_F_TEMPORARY, map[kAddr0].ifa_flags);
buffer.clear();
MakeAddrMessage(RTM_NEWADDR, IFA_F_HOMEADDRESS, AF_INET, kTestInterfaceEth,
kAddr1, kAddr2, &buffer);
EXPECT_TRUE(HandleAddressMessage(buffer));
map = GetAddressMap();
EXPECT_EQ(2u, map.size());
EXPECT_EQ(1u, map.count(kAddr0));
EXPECT_EQ(1u, map.count(kAddr2));
EXPECT_EQ(IFA_F_HOMEADDRESS, map[kAddr2].ifa_flags);
buffer.clear();
MakeAddrMessage(RTM_NEWADDR, 0, AF_INET6, kTestInterfaceEth, kEmpty, kAddr3,
&buffer);
EXPECT_TRUE(HandleAddressMessage(buffer));
map = GetAddressMap();
EXPECT_EQ(3u, map.size());
EXPECT_EQ(1u, map.count(kAddr3));
buffer.clear();
MakeAddrMessage(RTM_NEWADDR, IFA_F_TEMPORARY, AF_INET6, kTestInterfaceEth,
kEmpty, kAddr4, &buffer);
EXPECT_TRUE(HandleAddressMessage(buffer));
map = GetAddressMap();
EXPECT_EQ(4u, map.size());
EXPECT_EQ(1u, map.count(kAddr4));
EXPECT_EQ(IFA_F_TEMPORARY, map[kAddr4].ifa_flags);
}
TEST_F(AddressTrackerLinuxTest, NewAddressChange) {
InitializeAddressTracker(true);
const IPAddress kEmpty;
const IPAddress kAddr0(kAddress0);
NetlinkBuffer buffer;
MakeAddrMessage(RTM_NEWADDR, IFA_F_TEMPORARY, AF_INET, kTestInterfaceEth,
kAddr0, kEmpty, &buffer);
EXPECT_TRUE(HandleAddressMessage(buffer));
AddressTrackerLinux::AddressMap map = GetAddressMap();
EXPECT_EQ(1u, map.size());
EXPECT_EQ(1u, map.count(kAddr0));
EXPECT_EQ(IFA_F_TEMPORARY, map[kAddr0].ifa_flags);
buffer.clear();
MakeAddrMessage(RTM_NEWADDR, IFA_F_HOMEADDRESS, AF_INET, kTestInterfaceEth,
kAddr0, kEmpty, &buffer);
EXPECT_TRUE(HandleAddressMessage(buffer));
map = GetAddressMap();
EXPECT_EQ(1u, map.size());
EXPECT_EQ(1u, map.count(kAddr0));
EXPECT_EQ(IFA_F_HOMEADDRESS, map[kAddr0].ifa_flags);
buffer.clear();
MakeAddrMessage(RTM_NEWADDR, IFA_F_TEMPORARY, AF_INET, kTestInterfaceEth,
kAddr0, kEmpty, &buffer);
MakeAddrMessage(RTM_NEWADDR, IFA_F_HOMEADDRESS, AF_INET, kTestInterfaceEth,
kAddr0, kEmpty, &buffer);
EXPECT_TRUE(HandleAddressMessage(buffer));
map = GetAddressMap();
EXPECT_EQ(1u, map.size());
EXPECT_EQ(IFA_F_HOMEADDRESS, map[kAddr0].ifa_flags);
}
TEST_F(AddressTrackerLinuxTest, NewAddressDuplicate) {
InitializeAddressTracker(true);
const IPAddress kAddr0(kAddress0);
NetlinkBuffer buffer;
MakeAddrMessage(RTM_NEWADDR, IFA_F_TEMPORARY, AF_INET, kTestInterfaceEth,
kAddr0, kAddr0, &buffer);
EXPECT_TRUE(HandleAddressMessage(buffer));
AddressTrackerLinux::AddressMap map = GetAddressMap();
EXPECT_EQ(1u, map.size());
EXPECT_EQ(1u, map.count(kAddr0));
EXPECT_EQ(IFA_F_TEMPORARY, map[kAddr0].ifa_flags);
EXPECT_FALSE(HandleAddressMessage(buffer));
map = GetAddressMap();
EXPECT_EQ(1u, map.size());
EXPECT_EQ(IFA_F_TEMPORARY, map[kAddr0].ifa_flags);
}
TEST_F(AddressTrackerLinuxTest, DeleteAddress) {
InitializeAddressTracker(true);
const IPAddress kEmpty;
const IPAddress kAddr0(kAddress0);
const IPAddress kAddr1(kAddress1);
const IPAddress kAddr2(kAddress2);
NetlinkBuffer buffer;
MakeAddrMessage(RTM_NEWADDR, 0, AF_INET, kTestInterfaceEth, kAddr0, kEmpty,
&buffer);
MakeAddrMessage(RTM_NEWADDR, 0, AF_INET, kTestInterfaceEth, kAddr1, kAddr2,
&buffer);
EXPECT_TRUE(HandleAddressMessage(buffer));
AddressTrackerLinux::AddressMap map = GetAddressMap();
EXPECT_EQ(2u, map.size());
buffer.clear();
MakeAddrMessage(RTM_DELADDR, 0, AF_INET, kTestInterfaceEth, kEmpty, kAddr0,
&buffer);
EXPECT_TRUE(HandleAddressMessage(buffer));
map = GetAddressMap();
EXPECT_EQ(1u, map.size());
EXPECT_EQ(0u, map.count(kAddr0));
EXPECT_EQ(1u, map.count(kAddr2));
buffer.clear();
MakeAddrMessage(RTM_DELADDR, 0, AF_INET, kTestInterfaceEth, kAddr2, kAddr1,
&buffer);
EXPECT_FALSE(HandleAddressMessage(buffer));
map = GetAddressMap();
EXPECT_EQ(1u, map.size());
buffer.clear();
MakeAddrMessage(RTM_DELADDR, 0, AF_INET, kTestInterfaceEth, kAddr2, kEmpty,
&buffer);
EXPECT_TRUE(HandleAddressMessage(buffer));
map = GetAddressMap();
EXPECT_EQ(0u, map.size());
}
TEST_F(AddressTrackerLinuxTest, DeprecatedLifetime) {
InitializeAddressTracker(true);
const IPAddress kEmpty;
const IPAddress kAddr3(kAddress3);
NetlinkBuffer buffer;
MakeAddrMessage(RTM_NEWADDR, 0, AF_INET6, kTestInterfaceEth, kEmpty, kAddr3,
&buffer);
EXPECT_TRUE(HandleAddressMessage(buffer));
AddressTrackerLinux::AddressMap map = GetAddressMap();
EXPECT_EQ(1u, map.size());
EXPECT_EQ(1u, map.count(kAddr3));
EXPECT_EQ(0, map[kAddr3].ifa_flags);
buffer.clear();
MakeAddrMessageWithCacheInfo(RTM_NEWADDR, 0, AF_INET6, kTestInterfaceEth,
kEmpty, kAddr3, 0, &buffer);
EXPECT_TRUE(HandleAddressMessage(buffer));
map = GetAddressMap();
EXPECT_EQ(1u, map.size());
EXPECT_EQ(IFA_F_DEPRECATED, map[kAddr3].ifa_flags);
buffer.clear();
MakeAddrMessageWithCacheInfo(RTM_NEWADDR, IFA_F_DEPRECATED, AF_INET6,
kTestInterfaceEth, kEmpty, kAddr3, 0, &buffer);
EXPECT_FALSE(HandleAddressMessage(buffer));
map = GetAddressMap();
EXPECT_EQ(1u, map.size());
EXPECT_EQ(IFA_F_DEPRECATED, map[kAddr3].ifa_flags);
buffer.clear();
MakeAddrMessageWithCacheInfo(RTM_NEWADDR, 0, AF_INET6, kTestInterfaceEth,
kEmpty, kAddr3, 0, &buffer);
EXPECT_FALSE(HandleAddressMessage(buffer));
map = GetAddressMap();
EXPECT_EQ(1u, map.size());
EXPECT_EQ(IFA_F_DEPRECATED, map[kAddr3].ifa_flags);
}
TEST_F(AddressTrackerLinuxTest, IgnoredMessage) {
InitializeAddressTracker(true);
const IPAddress kEmpty;
const IPAddress kAddr0(kAddress0);
const IPAddress kAddr3(kAddress3);
NetlinkBuffer buffer;
MakeAddrMessage(RTM_NEWADDR, 0, AF_UNSPEC, kTestInterfaceEth, kAddr3, kAddr0,
&buffer);
MakeAddrMessage(RTM_NEWADDR, 0, AF_INET, kTestInterfaceEth, kEmpty, kEmpty,
&buffer);
MakeAddrMessage(RTM_DELROUTE, 0, AF_INET6, kTestInterfaceEth, kAddr3, kEmpty,
&buffer);
EXPECT_FALSE(HandleAddressMessage(buffer));
EXPECT_TRUE(GetAddressMap().empty());
NetlinkMessage nlmsg(RTM_NEWADDR);
ifaddrmsg msg = {};
msg.ifa_family = AF_INET;
nlmsg.AddPayload(base::byte_span_from_ref(msg));
ifa_cacheinfo cache_info = {};
nlmsg.AddAttribute(IFA_CACHEINFO, base::byte_span_from_ref(cache_info));
nlmsg.AddAttribute(IFA_ADDRESS, kAddr0.bytes().span());
nlmsg.AppendTo(&buffer);
EXPECT_TRUE(HandleAddressMessage(buffer));
EXPECT_EQ(1u, GetAddressMap().size());
}
TEST_F(AddressTrackerLinuxTest, AddInterface) {
InitializeAddressTracker(true);
NetlinkBuffer buffer;
MakeLinkMessage(RTM_NEWLINK,
IFF_LOOPBACK | IFF_UP | IFF_LOWER_UP | IFF_RUNNING,
kTestInterfaceEth, &buffer);
EXPECT_FALSE(HandleLinkMessage(buffer));
EXPECT_TRUE(GetOnlineLinks().empty());
MakeLinkMessage(RTM_NEWLINK, IFF_UP | IFF_RUNNING, kTestInterfaceEth,
&buffer);
EXPECT_FALSE(HandleLinkMessage(buffer));
EXPECT_TRUE(GetOnlineLinks().empty());
MakeLinkMessage(RTM_DELLINK, IFF_UP | IFF_LOWER_UP | IFF_RUNNING,
kTestInterfaceEth, &buffer);
EXPECT_FALSE(HandleLinkMessage(buffer));
EXPECT_TRUE(GetOnlineLinks().empty());
MakeLinkMessage(RTM_NEWLINK, IFF_UP | IFF_LOWER_UP | IFF_RUNNING,
kTestInterfaceEth, &buffer);
EXPECT_TRUE(HandleLinkMessage(buffer));
EXPECT_EQ(1u, GetOnlineLinks().count(kTestInterfaceEth));
EXPECT_EQ(1u, GetOnlineLinks().size());
MakeLinkMessage(RTM_NEWLINK, IFF_UP | IFF_LOWER_UP | IFF_RUNNING,
kTestInterfaceEth, &buffer);
EXPECT_FALSE(HandleLinkMessage(buffer));
EXPECT_EQ(1u, GetOnlineLinks().count(kTestInterfaceEth));
EXPECT_EQ(1u, GetOnlineLinks().size());
MakeWirelessLinkMessage(RTM_NEWLINK, IFF_UP | IFF_LOWER_UP | IFF_RUNNING,
kTestInterfaceWifi, &buffer);
EXPECT_FALSE(HandleLinkMessage(buffer));
EXPECT_EQ(0u, GetOnlineLinks().count(kTestInterfaceWifi));
EXPECT_EQ(1u, GetOnlineLinks().size());
MakeLinkMessage(RTM_NEWLINK, IFF_UP | IFF_LOWER_UP | IFF_RUNNING, 2, &buffer);
EXPECT_TRUE(HandleLinkMessage(buffer));
EXPECT_EQ(1u, GetOnlineLinks().count(kTestInterfaceEth));
EXPECT_EQ(1u, GetOnlineLinks().count(2));
EXPECT_EQ(2u, GetOnlineLinks().size());
}
TEST_F(AddressTrackerLinuxTest, RemoveInterface) {
InitializeAddressTracker(true);
NetlinkBuffer buffer;
MakeLinkMessage(RTM_NEWLINK, IFF_UP | IFF_LOWER_UP | IFF_RUNNING,
kTestInterfaceEth, &buffer);
EXPECT_TRUE(HandleLinkMessage(buffer));
EXPECT_FALSE(GetOnlineLinks().empty());
MakeLinkMessage(RTM_NEWLINK, IFF_UP | IFF_RUNNING, kTestInterfaceEth,
&buffer);
EXPECT_TRUE(HandleLinkMessage(buffer));
EXPECT_TRUE(GetOnlineLinks().empty());
MakeLinkMessage(RTM_NEWLINK, IFF_UP | IFF_RUNNING, kTestInterfaceEth,
&buffer);
EXPECT_FALSE(HandleLinkMessage(buffer));
EXPECT_TRUE(GetOnlineLinks().empty());
MakeLinkMessage(RTM_DELLINK, IFF_UP | IFF_RUNNING, kTestInterfaceEth,
&buffer);
EXPECT_FALSE(HandleLinkMessage(buffer));
EXPECT_TRUE(GetOnlineLinks().empty());
MakeLinkMessage(RTM_NEWLINK, IFF_UP | IFF_LOWER_UP | IFF_RUNNING,
kTestInterfaceEth, &buffer);
EXPECT_TRUE(HandleLinkMessage(buffer));
EXPECT_FALSE(GetOnlineLinks().empty());
MakeLinkMessage(RTM_DELLINK, IFF_UP | IFF_LOWER_UP | IFF_RUNNING,
kTestInterfaceEth, &buffer);
EXPECT_TRUE(HandleLinkMessage(buffer));
EXPECT_TRUE(GetOnlineLinks().empty());
MakeLinkMessage(RTM_NEWLINK, IFF_UP | IFF_LOWER_UP | IFF_RUNNING,
kTestInterfaceWifi, &buffer);
EXPECT_TRUE(HandleLinkMessage(buffer));
EXPECT_FALSE(GetOnlineLinks().empty());
MakeWirelessLinkMessage(RTM_NEWLINK, IFF_UP | IFF_LOWER_UP,
kTestInterfaceWifi, &buffer);
EXPECT_FALSE(HandleLinkMessage(buffer));
EXPECT_FALSE(GetOnlineLinks().empty());
MakeLinkMessage(RTM_NEWLINK, IFF_UP | IFF_RUNNING, kTestInterfaceWifi,
&buffer);
EXPECT_TRUE(HandleLinkMessage(buffer));
EXPECT_TRUE(GetOnlineLinks().empty());
}
TEST_F(AddressTrackerLinuxTest, IgnoreInterface) {
IgnoreInterface(kIgnoredInterfaceName);
InitializeAddressTracker(true);
NetlinkBuffer buffer;
const IPAddress kEmpty;
const IPAddress kAddr0(kAddress0);
MakeAddrMessage(RTM_NEWADDR, IFA_F_TEMPORARY, AF_INET, kTestInterfaceAp,
kAddr0, kEmpty, &buffer);
EXPECT_FALSE(HandleAddressMessage(buffer));
AddressTrackerLinux::AddressMap map = GetAddressMap();
EXPECT_EQ(0u, map.size());
EXPECT_EQ(0u, map.count(kAddr0));
MakeLinkMessage(RTM_NEWLINK, IFF_UP | IFF_LOWER_UP | IFF_RUNNING,
kTestInterfaceAp, &buffer);
EXPECT_FALSE(HandleLinkMessage(buffer));
EXPECT_EQ(0u, GetOnlineLinks().count(kTestInterfaceAp));
EXPECT_EQ(0u, GetOnlineLinks().size());
}
TEST_F(AddressTrackerLinuxTest, IgnoreInterface_NonIgnoredInterface) {
IgnoreInterface(kIgnoredInterfaceName);
InitializeAddressTracker(true);
NetlinkBuffer buffer;
const IPAddress kEmpty;
const IPAddress kAddr0(kAddress0);
MakeAddrMessage(RTM_NEWADDR, IFA_F_TEMPORARY, AF_INET, kTestInterfaceEth,
kAddr0, kEmpty, &buffer);
EXPECT_TRUE(HandleAddressMessage(buffer));
AddressTrackerLinux::AddressMap map = GetAddressMap();
EXPECT_EQ(1u, map.size());
EXPECT_EQ(1u, map.count(kAddr0));
MakeLinkMessage(RTM_NEWLINK, IFF_UP | IFF_LOWER_UP | IFF_RUNNING,
kTestInterfaceEth, &buffer);
EXPECT_TRUE(HandleLinkMessage(buffer));
EXPECT_EQ(1u, GetOnlineLinks().count(kTestInterfaceEth));
EXPECT_EQ(1u, GetOnlineLinks().size());
}
TEST_F(AddressTrackerLinuxTest, TunnelInterface) {
InitializeAddressTracker(true);
NetlinkBuffer buffer;
MakeLinkMessage(RTM_NEWLINK,
IFF_UP | IFF_LOWER_UP | IFF_RUNNING | IFF_POINTOPOINT,
kTestInterfaceEth, &buffer);
EXPECT_FALSE(HandleTunnelMessage(buffer));
MakeLinkMessage(RTM_NEWLINK,
IFF_UP | IFF_LOWER_UP | IFF_RUNNING | IFF_POINTOPOINT,
kTestInterfaceTun, &buffer);
EXPECT_TRUE(HandleTunnelMessage(buffer));
MakeLinkMessage(RTM_NEWLINK,
IFF_UP | IFF_LOWER_UP | IFF_RUNNING | IFF_POINTOPOINT,
kTestInterfaceTun, &buffer);
EXPECT_FALSE(HandleTunnelMessage(buffer));
MakeLinkMessage(RTM_DELLINK,
IFF_UP | IFF_LOWER_UP | IFF_RUNNING | IFF_POINTOPOINT,
0, &buffer);
EXPECT_FALSE(HandleTunnelMessage(buffer));
MakeLinkMessage(RTM_DELLINK,
IFF_UP | IFF_LOWER_UP | IFF_RUNNING | IFF_POINTOPOINT,
kTestInterfaceTun, &buffer);
EXPECT_TRUE(HandleTunnelMessage(buffer));
MakeLinkMessage(RTM_DELLINK,
IFF_UP | IFF_LOWER_UP | IFF_RUNNING | IFF_POINTOPOINT,
kTestInterfaceTun, &buffer);
EXPECT_FALSE(HandleTunnelMessage(buffer));
}
TEST_F(AddressTrackerLinuxTest, GetInterfaceName) {
InitializeAddressTracker(true);
for (int i = 0; i < 10; i++) {
original_get_interface_name_(i);
}
}
TEST_F(AddressTrackerLinuxTest, NonTrackingMode) {
InitializeAddressTracker(false);
const IPAddress kEmpty;
const IPAddress kAddr0(kAddress0);
NetlinkBuffer buffer;
MakeAddrMessage(RTM_NEWADDR, IFA_F_TEMPORARY, AF_INET, kTestInterfaceEth,
kAddr0, kEmpty, &buffer);
EXPECT_TRUE(HandleAddressMessage(buffer));
AddressTrackerLinux::AddressMap map = GetAddressMap();
EXPECT_EQ(1u, map.size());
EXPECT_EQ(1u, map.count(kAddr0));
EXPECT_EQ(IFA_F_TEMPORARY, map[kAddr0].ifa_flags);
MakeLinkMessage(RTM_NEWLINK, IFF_UP | IFF_LOWER_UP | IFF_RUNNING, 1, &buffer);
EXPECT_TRUE(HandleLinkMessage(buffer));
EXPECT_EQ(1u, GetOnlineLinks().count(1));
EXPECT_EQ(1u, GetOnlineLinks().size());
}
TEST_F(AddressTrackerLinuxTest, NonTrackingModeInit) {
#if BUILDFLAG(IS_ANDROID)
if (base::android::android_info::sdk_int() >=
base::android::android_info::SDK_VERSION_P) {
return;
}
#endif
AddressTrackerLinux tracker;
tracker.Init();
}
class GetCurrentConnectionTypeRunner
: public base::DelegateSimpleThread::Delegate {
public:
explicit GetCurrentConnectionTypeRunner(AddressTrackerLinux* tracker,
const std::string& thread_name)
: tracker_(tracker),
done_(base::WaitableEvent::ResetPolicy::MANUAL,
base::WaitableEvent::InitialState::NOT_SIGNALED),
thread_(this, thread_name) {}
~GetCurrentConnectionTypeRunner() override = default;
void Run() override {
tracker_->GetCurrentConnectionType();
done_.Signal();
}
void Start() {
thread_.Start();
}
void VerifyCompletes() {
EXPECT_TRUE(done_.TimedWait(base::Seconds(5)));
thread_.Join();
}
private:
const raw_ptr<AddressTrackerLinux> tracker_;
base::WaitableEvent done_;
base::DelegateSimpleThread thread_;
};
TEST_F(AddressTrackerLinuxTest, BroadcastInit) {
#if BUILDFLAG(IS_ANDROID)
if (base::android::android_info::sdk_int() >=
base::android::android_info::SDK_VERSION_P) {
return;
}
#endif
base::test::TaskEnvironment task_environment(
base::test::TaskEnvironment::MainThreadType::IO);
InitializeAddressTracker(true);
GetCurrentConnectionTypeRunner runner1(tracker_.get(), "waiter_thread_1");
GetCurrentConnectionTypeRunner runner2(tracker_.get(), "waiter_thread_2");
runner1.Start();
runner2.Start();
SPIN_FOR_1_SECOND_OR_UNTIL_TRUE(
GetThreadsWaitingForConnectionTypeInit() == 2);
tracker_->Init();
runner1.VerifyCompletes();
runner2.VerifyCompletes();
}
TEST_F(AddressTrackerLinuxTest, TunnelInterfaceName) {
EXPECT_TRUE(AddressTrackerLinux::IsTunnelInterfaceName("tun0"));
EXPECT_FALSE(AddressTrackerLinux::IsTunnelInterfaceName("wlan0"));
}
}
}
namespace net::internal {
TEST(AddressTrackerLinuxNetlinkTest, TestInitializeTwoTrackers) {
#if BUILDFLAG(IS_ANDROID)
if (base::android::android_info::sdk_int() >=
base::android::android_info::SDK_VERSION_P) {
return;
}
#endif
base::test::TaskEnvironment task_env(
base::test::TaskEnvironment::MainThreadType::IO);
AddressTrackerLinux tracker1(base::DoNothing(), base::DoNothing(),
base::DoNothing(), {});
AddressTrackerLinux tracker2(base::DoNothing(), base::DoNothing(),
base::DoNothing(), {});
tracker1.Init();
tracker2.Init();
EXPECT_TRUE(tracker1.DidTrackingInitSucceedForTesting());
EXPECT_TRUE(tracker2.DidTrackingInitSucceedForTesting());
}
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
#if defined(CLONE_NEWUSER) && defined(CLONE_NEWPID)
namespace {
const char* const kSwitchParentWriteFd = "addresstrackerlinux_parent_write_fd";
const char* const kSwitchReadFd = "addresstrackerlinux_read_fd";
enum IPCMessage {
kChildInitializedAndWaiting,
kChildFailed,
kChildMayExit,
};
base::File GetSwitchValueFile(const base::CommandLine* command_line,
std::string_view name) {
std::string value = command_line->GetSwitchValueASCII(name);
int fd;
CHECK(base::StringToInt(value, &fd));
return base::File(fd);
}
}
TEST(AddressTrackerLinuxNetlinkTest, TestInitializeTwoTrackersInPidNamespaces) {
constexpr size_t kNumChildren = 2;
base::ScopedFD parent_read_fd, parent_write_fd;
ASSERT_TRUE(base::CreatePipe(&parent_read_fd, &parent_write_fd));
struct Child {
base::ScopedFD read_fd;
base::ScopedFD write_fd;
base::Process process;
} children[kNumChildren];
for (Child& child : children) {
ASSERT_TRUE(base::CreatePipe(&child.read_fd, &child.write_fd));
base::CommandLine command_line(
base::GetMultiProcessTestChildBaseCommandLine());
command_line.AppendSwitchASCII(kSwitchParentWriteFd,
base::NumberToString(parent_write_fd.get()));
command_line.AppendSwitchASCII(kSwitchReadFd,
base::NumberToString(child.read_fd.get()));
base::LaunchOptions options;
options.fds_to_remap = {{child.read_fd.get(), child.read_fd.get()},
{parent_write_fd.get(), parent_write_fd.get()}};
options.clone_flags = CLONE_NEWPID | CLONE_NEWUSER;
child.process = base::SpawnMultiProcessTestChild(
"ChildProcessInitializeTrackerForTesting", command_line, options);
}
base::File parent_reader(std::move(parent_read_fd));
for (const Child& child : children) {
ASSERT_TRUE(child.process.IsValid());
auto message = std::to_array<uint8_t>({0});
ASSERT_TRUE(parent_reader.ReadAtCurrentPosAndCheck(message));
ASSERT_EQ(message[0], kChildInitializedAndWaiting);
}
for (Child& child : children) {
base::File child_writer(std::move(child.write_fd));
const uint8_t kMessage[] = {kChildMayExit};
ASSERT_TRUE(child_writer.WriteAtCurrentPosAndCheck(kMessage));
int exit_code = 0;
ASSERT_TRUE(child.process.WaitForExit(&exit_code));
ASSERT_EQ(exit_code, 0);
}
}
MULTIPROCESS_TEST_MAIN(ChildProcessInitializeTrackerForTesting) {
base::test::TaskEnvironment task_env(
base::test::TaskEnvironment::MainThreadType::IO);
const base::CommandLine* command_line =
base::CommandLine::ForCurrentProcess();
base::File reader = GetSwitchValueFile(command_line, kSwitchReadFd);
base::File parent_writer =
GetSwitchValueFile(command_line, kSwitchParentWriteFd);
AddressTrackerLinux tracker(base::DoNothing(), base::DoNothing(),
base::DoNothing(), {});
tracker.Init();
if (!tracker.DidTrackingInitSucceedForTesting()) {
const uint8_t kMessage[] = {kChildFailed};
parent_writer.WriteAtCurrentPosAndCheck(kMessage);
return 1;
}
const uint8_t kMessage[] = {kChildInitializedAndWaiting};
if (!parent_writer.WriteAtCurrentPosAndCheck(kMessage))
return 1;
auto message = std::to_array<uint8_t>({0});
if (!reader.ReadAtCurrentPosAndCheck(message) || message[0] != kChildMayExit)
return 1;
return 0;
}
#endif
#endif
}