Add support for manually configuring subnets as VPN
This patch adds support for manually setting subnets that should be handled as VPN, i.e be subject to VpnPreference, in case webrtc fails to auto-detect VPNs. Bug: webrtc:13097 Change-Id: I42514f0677a35cfe30ad053570fa9c2a5b4a856b Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/230122 Commit-Queue: Jonas Oreland <jonaso@webrtc.org> Reviewed-by: Harald Alvestrand <hta@webrtc.org> Cr-Commit-Position: refs/heads/main@{#34852}
This commit is contained in:
parent
c5cb7f1fad
commit
2ee0e64696
@ -661,6 +661,10 @@ class RTC_EXPORT PeerConnectionInterface : public rtc::RefCountInterface {
|
||||
// perfect, adherence to this preference cannot be guaranteed.
|
||||
VpnPreference vpn_preference = VpnPreference::kDefault;
|
||||
|
||||
// List of address/length subnets that should be treated like
|
||||
// VPN (in case webrtc fails to auto detect them).
|
||||
std::vector<rtc::NetworkMask> vpn_list;
|
||||
|
||||
//
|
||||
// Don't forget to update operator== if adding something.
|
||||
//
|
||||
|
||||
@ -406,6 +406,10 @@ class RTC_EXPORT PortAllocator : public sigslot::has_slots<> {
|
||||
vpn_preference_ = preference;
|
||||
}
|
||||
|
||||
// Set list of <ipaddress, mask> that shall be categorized as VPN.
|
||||
// Implemented by BasicPortAllocator.
|
||||
virtual void SetVpnList(const std::vector<rtc::NetworkMask>& vpn_list) {}
|
||||
|
||||
std::unique_ptr<PortAllocatorSession> CreateSession(
|
||||
const std::string& content_name,
|
||||
int component,
|
||||
|
||||
@ -1228,6 +1228,11 @@ void BasicPortAllocatorSession::PrunePortsAndRemoveCandidates(
|
||||
}
|
||||
}
|
||||
|
||||
void BasicPortAllocator::SetVpnList(
|
||||
const std::vector<rtc::NetworkMask>& vpn_list) {
|
||||
network_manager_->set_vpn_list(vpn_list);
|
||||
}
|
||||
|
||||
// AllocationSequence
|
||||
|
||||
AllocationSequence::AllocationSequence(
|
||||
|
||||
@ -74,6 +74,8 @@ class RTC_EXPORT BasicPortAllocator : public PortAllocator {
|
||||
return relay_port_factory_;
|
||||
}
|
||||
|
||||
void SetVpnList(const std::vector<rtc::NetworkMask>& vpn_list) override;
|
||||
|
||||
private:
|
||||
void OnIceRegathering(PortAllocatorSession* session,
|
||||
IceRegatheringReason reason);
|
||||
|
||||
@ -337,6 +337,7 @@ bool PeerConnectionInterface::RTCConfiguration::operator==(
|
||||
absl::optional<int> report_usage_pattern_delay_ms;
|
||||
absl::optional<int> stable_writable_connection_ping_interval_ms;
|
||||
webrtc::VpnPreference vpn_preference;
|
||||
std::vector<rtc::NetworkMask> vpn_list;
|
||||
};
|
||||
static_assert(sizeof(stuff_being_tested_for_equality) == sizeof(*this),
|
||||
"Did you add something to RTCConfiguration and forget to "
|
||||
@ -399,7 +400,7 @@ bool PeerConnectionInterface::RTCConfiguration::operator==(
|
||||
report_usage_pattern_delay_ms == o.report_usage_pattern_delay_ms &&
|
||||
stable_writable_connection_ping_interval_ms ==
|
||||
o.stable_writable_connection_ping_interval_ms &&
|
||||
vpn_preference == o.vpn_preference;
|
||||
vpn_preference == o.vpn_preference && vpn_list == o.vpn_list;
|
||||
}
|
||||
|
||||
bool PeerConnectionInterface::RTCConfiguration::operator!=(
|
||||
|
||||
@ -231,6 +231,7 @@ PeerConnectionFactory::CreatePeerConnectionOrError(
|
||||
}
|
||||
|
||||
dependencies.allocator->SetNetworkIgnoreMask(options().network_ignore_mask);
|
||||
dependencies.allocator->SetVpnList(configuration.vpn_list);
|
||||
|
||||
std::unique_ptr<RtcEventLog> event_log =
|
||||
worker_thread()->Invoke<std::unique_ptr<RtcEventLog>>(
|
||||
|
||||
@ -541,6 +541,7 @@ void BasicNetworkManager::ConvertIfAddrs(struct ifaddrs* interfaces,
|
||||
continue;
|
||||
}
|
||||
// Convert to InterfaceAddress.
|
||||
// TODO(webrtc:13114): Convert ConvertIfAddrs to use rtc::Netmask.
|
||||
if (!ifaddrs_converter->ConvertIfAddrsToIPAddress(cursor, &ip, &mask)) {
|
||||
continue;
|
||||
}
|
||||
@ -576,8 +577,16 @@ void BasicNetworkManager::ConvertIfAddrs(struct ifaddrs* interfaces,
|
||||
vpn_underlying_adapter_type =
|
||||
network_monitor_->GetVpnUnderlyingAdapterType(cursor->ifa_name);
|
||||
}
|
||||
|
||||
int prefix_length = CountIPMaskBits(mask);
|
||||
prefix = TruncateIP(ip, prefix_length);
|
||||
|
||||
if (adapter_type != ADAPTER_TYPE_VPN &&
|
||||
IsConfiguredVpn(prefix, prefix_length)) {
|
||||
vpn_underlying_adapter_type = adapter_type;
|
||||
adapter_type = ADAPTER_TYPE_VPN;
|
||||
}
|
||||
|
||||
std::string key =
|
||||
MakeNetworkKey(std::string(cursor->ifa_name), prefix, prefix_length);
|
||||
auto iter = current_networks.find(key);
|
||||
@ -766,8 +775,15 @@ bool BasicNetworkManager::CreateNetworks(bool include_ignored,
|
||||
adapter_type = ADAPTER_TYPE_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
auto vpn_underlying_adapter_type = ADAPTER_TYPE_UNKNOWN;
|
||||
if (adapter_type != ADAPTER_TYPE_VPN &&
|
||||
IsConfiguredVpn(prefix, prefix_length)) {
|
||||
vpn_underlying_adapter_type = adapter_type;
|
||||
adapter_type = ADAPTER_TYPE_VPN;
|
||||
}
|
||||
std::unique_ptr<Network> network(new Network(
|
||||
name, description, prefix, prefix_length, adapter_type));
|
||||
network->set_underlying_type_for_vpn(vpn_underlying_adapter_type);
|
||||
network->set_default_local_address_provider(this);
|
||||
network->set_mdns_responder_provider(this);
|
||||
network->set_scope_id(scope_id);
|
||||
@ -1118,4 +1134,26 @@ std::string Network::ToString() const {
|
||||
return ss.Release();
|
||||
}
|
||||
|
||||
void BasicNetworkManager::set_vpn_list(const std::vector<NetworkMask>& vpn) {
|
||||
if (thread_ == nullptr) {
|
||||
vpn_ = vpn;
|
||||
} else {
|
||||
thread_->Invoke<void>(RTC_FROM_HERE, [this, vpn] { vpn_ = vpn; });
|
||||
}
|
||||
}
|
||||
|
||||
bool BasicNetworkManager::IsConfiguredVpn(IPAddress prefix,
|
||||
int prefix_length) const {
|
||||
RTC_DCHECK_RUN_ON(thread_);
|
||||
for (const auto& vpn : vpn_) {
|
||||
if (prefix_length >= vpn.prefix_length()) {
|
||||
auto copy = TruncateIP(prefix, vpn.prefix_length());
|
||||
if (copy == vpn.address()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace rtc
|
||||
|
||||
@ -79,6 +79,25 @@ class MdnsResponderProvider {
|
||||
virtual webrtc::MdnsResponderInterface* GetMdnsResponder() const = 0;
|
||||
};
|
||||
|
||||
// Network/mask in CIDR representation.
|
||||
class NetworkMask {
|
||||
public:
|
||||
NetworkMask(const IPAddress& addr, int prefix_length)
|
||||
: address_(addr), prefix_length_(prefix_length) {}
|
||||
|
||||
const IPAddress& address() const { return address_; }
|
||||
int prefix_length() const { return prefix_length_; }
|
||||
|
||||
bool operator==(const NetworkMask& o) const {
|
||||
return address_ == o.address_ && prefix_length_ == o.prefix_length_;
|
||||
}
|
||||
|
||||
private:
|
||||
IPAddress address_;
|
||||
// Length of valid bits in address_ (for ipv4 valid range is 0-32)
|
||||
int prefix_length_;
|
||||
};
|
||||
|
||||
// Generic network manager interface. It provides list of local
|
||||
// networks.
|
||||
//
|
||||
@ -158,6 +177,8 @@ class RTC_EXPORT NetworkManager : public DefaultLocalAddressProvider,
|
||||
|
||||
// MdnsResponderProvider interface.
|
||||
webrtc::MdnsResponderInterface* GetMdnsResponder() const override;
|
||||
|
||||
virtual void set_vpn_list(const std::vector<NetworkMask>& vpn) {}
|
||||
};
|
||||
|
||||
// Base class for NetworkManager implementations.
|
||||
@ -249,6 +270,12 @@ class RTC_EXPORT BasicNetworkManager : public NetworkManagerBase,
|
||||
network_ignore_list_ = list;
|
||||
}
|
||||
|
||||
// Set a list of manually configured VPN's.
|
||||
void set_vpn_list(const std::vector<NetworkMask>& vpn) override;
|
||||
|
||||
// Check if |prefix| is configured as VPN.
|
||||
bool IsConfiguredVpn(IPAddress prefix, int prefix_length) const;
|
||||
|
||||
// Bind a socket to interface that ip address belong to.
|
||||
// Implementation look up interface name and calls
|
||||
// BindSocketToNetwork on NetworkMonitor.
|
||||
@ -305,6 +332,8 @@ class RTC_EXPORT BasicNetworkManager : public NetworkManagerBase,
|
||||
RTC_GUARDED_BY(thread_);
|
||||
bool allow_mac_based_ipv6_ RTC_GUARDED_BY(thread_) = false;
|
||||
bool bind_using_ifname_ RTC_GUARDED_BY(thread_) = false;
|
||||
|
||||
std::vector<NetworkMask> vpn_;
|
||||
};
|
||||
|
||||
// Represents a Unix-type network interface, with a name and single address.
|
||||
|
||||
@ -44,6 +44,12 @@ namespace rtc {
|
||||
|
||||
namespace {
|
||||
|
||||
IPAddress IPFromString(const std::string& str) {
|
||||
IPAddress ip;
|
||||
RTC_CHECK(IPFromString(str, &ip));
|
||||
return ip;
|
||||
}
|
||||
|
||||
class FakeNetworkMonitor : public NetworkMonitorInterface {
|
||||
public:
|
||||
void Start() override { started_ = true; }
|
||||
@ -1385,4 +1391,47 @@ TEST_F(NetworkTest, NetworkCostVpn_VpnMoreExpensive) {
|
||||
delete net2;
|
||||
}
|
||||
|
||||
TEST_F(NetworkTest, VpnList) {
|
||||
{
|
||||
BasicNetworkManager manager;
|
||||
manager.set_vpn_list({NetworkMask(IPFromString("192.168.0.0"), 16)});
|
||||
manager.StartUpdating();
|
||||
EXPECT_TRUE(manager.IsConfiguredVpn(IPFromString("192.168.1.1"), 32));
|
||||
EXPECT_TRUE(manager.IsConfiguredVpn(IPFromString("192.168.12.1"), 24));
|
||||
EXPECT_TRUE(manager.IsConfiguredVpn(IPFromString("192.168.0.0"), 16));
|
||||
EXPECT_TRUE(manager.IsConfiguredVpn(IPFromString("192.168.0.0"), 24));
|
||||
EXPECT_FALSE(manager.IsConfiguredVpn(IPFromString("192.133.1.1"), 32));
|
||||
EXPECT_FALSE(manager.IsConfiguredVpn(IPFromString("192.133.0.0"), 16));
|
||||
EXPECT_FALSE(manager.IsConfiguredVpn(IPFromString("192.168.0.0"), 15));
|
||||
}
|
||||
{
|
||||
BasicNetworkManager manager;
|
||||
manager.set_vpn_list({NetworkMask(IPFromString("192.168.0.0"), 24)});
|
||||
manager.StartUpdating();
|
||||
EXPECT_FALSE(manager.IsConfiguredVpn(IPFromString("192.168.1.1"), 32));
|
||||
EXPECT_TRUE(manager.IsConfiguredVpn(IPFromString("192.168.0.1"), 32));
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(WEBRTC_POSIX)
|
||||
// TODO(webrtc:13114): Implement the InstallIpv4Network for windows.
|
||||
TEST_F(NetworkTest, VpnListOverrideAdapterType) {
|
||||
BasicNetworkManager manager;
|
||||
manager.set_vpn_list({NetworkMask(IPFromString("192.168.0.0"), 16)});
|
||||
manager.StartUpdating();
|
||||
|
||||
char if_name[20] = "eth0";
|
||||
auto addr_list =
|
||||
InstallIpv4Network(if_name, "192.168.1.23", "255.255.255.255", manager);
|
||||
|
||||
BasicNetworkManager::NetworkList list;
|
||||
manager.GetNetworks(&list);
|
||||
ASSERT_EQ(1u, list.size());
|
||||
EXPECT_EQ(ADAPTER_TYPE_VPN, list[0]->type());
|
||||
EXPECT_EQ(ADAPTER_TYPE_ETHERNET, list[0]->underlying_type_for_vpn());
|
||||
ClearNetworks(manager);
|
||||
ReleaseIfAddrs(addr_list);
|
||||
}
|
||||
#endif // defined(WEBRTC_POSIX)
|
||||
|
||||
} // namespace rtc
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user