Skip to content

Commit 6d1cc95

Browse files
KokaKiwimelekes
andauthored
Add IP filter to WebRTC SettingEngine and ICE AgentConfig (#306)
* Add IP filter to WebRTC SettingEngine and ICE AgentConfig When machine's network interface have more than one ip address and user don't want expose one of these ips to remote peer, interface filter can't work in this case, so add a ip filter for that * Update webrtc/src/api/setting_engine/mod.rs Co-authored-by: Anton Kaliaev <anton.kalyaev@gmail.com> * Add changelog entries Co-authored-by: Anton Kaliaev <anton.kalyaev@gmail.com>
1 parent d7064af commit 6d1cc95

File tree

10 files changed

+71
-13
lines changed

10 files changed

+71
-13
lines changed

ice/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# webrtc-ice changelog
22

33
## Unreleased
4+
* Add IP filter to ICE `AgentConfig` [#306](https://github.com/webrtc-rs/webrtc/pull/306)
45

56
## v0.8.1
67

ice/src/agent/agent_config.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use crate::url::*;
77

88
use util::vnet::net::*;
99

10+
use std::net::IpAddr;
1011
use std::time::Duration;
1112

1213
/// The interval at which the agent performs candidate checks in the connecting phase.
@@ -51,6 +52,7 @@ pub(crate) fn default_candidate_types() -> Vec<CandidateType> {
5152
}
5253

5354
pub type InterfaceFilterFn = Box<dyn (Fn(&str) -> bool) + Send + Sync>;
55+
pub type IpFilterFn = Box<dyn (Fn(IpAddr) -> bool) + Send + Sync>;
5456

5557
/// Collects the arguments to `ice::Agent` construction into a single structure, for
5658
/// future-proofness of the interface.
@@ -77,7 +79,7 @@ pub struct AgentConfig {
7779
/// Controls the hostname for this agent. If none is specified a random one will be generated.
7880
pub multicast_dns_host_name: String,
7981

80-
/// Control mDNS destination address
82+
/// Control mDNS destination address
8183
pub multicast_dns_dest_addr: String,
8284

8385
/// Defaults to 5 seconds when this property is nil.
@@ -143,6 +145,10 @@ pub struct AgentConfig {
143145
/// used to gather ICE candidates.
144146
pub interface_filter: Arc<Option<InterfaceFilterFn>>,
145147

148+
/// A function that you can use in order to whitelist or blacklist
149+
/// the ips which are used to gather ICE candidates.
150+
pub ip_filter: Arc<Option<IpFilterFn>>,
151+
146152
/// Controls if self-signed certificates are accepted when connecting to TURN servers via TLS or
147153
/// DTLS.
148154
pub insecure_skip_verify: bool,

ice/src/agent/agent_gather.rs

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ pub(crate) struct GatherCandidatesInternalParams {
2828
pub(crate) mdns_name: String,
2929
pub(crate) net: Arc<Net>,
3030
pub(crate) interface_filter: Arc<Option<InterfaceFilterFn>>,
31+
pub(crate) ip_filter: Arc<Option<IpFilterFn>>,
3132
pub(crate) ext_ip_mapper: Arc<Option<ExternalIpMapper>>,
3233
pub(crate) agent_internal: Arc<AgentInternal>,
3334
pub(crate) gathering_state: Arc<AtomicU8>,
@@ -40,6 +41,7 @@ struct GatherCandidatesLocalParams {
4041
mdns_mode: MulticastDnsMode,
4142
mdns_name: String,
4243
interface_filter: Arc<Option<InterfaceFilterFn>>,
44+
ip_filter: Arc<Option<IpFilterFn>>,
4345
ext_ip_mapper: Arc<Option<ExternalIpMapper>>,
4446
net: Arc<Net>,
4547
agent_internal: Arc<AgentInternal>,
@@ -48,6 +50,7 @@ struct GatherCandidatesLocalParams {
4850
struct GatherCandidatesLocalUDPMuxParams {
4951
network_types: Vec<NetworkType>,
5052
interface_filter: Arc<Option<InterfaceFilterFn>>,
53+
ip_filter: Arc<Option<IpFilterFn>>,
5154
ext_ip_mapper: Arc<Option<ExternalIpMapper>>,
5255
net: Arc<Net>,
5356
agent_internal: Arc<AgentInternal>,
@@ -92,6 +95,7 @@ impl Agent {
9295
mdns_mode: params.mdns_mode,
9396
mdns_name: params.mdns_name.clone(),
9497
interface_filter: Arc::clone(&params.interface_filter),
98+
ip_filter: Arc::clone(&params.ip_filter),
9599
ext_ip_mapper: Arc::clone(&params.ext_ip_mapper),
96100
net: Arc::clone(&params.net),
97101
agent_internal: Arc::clone(&params.agent_internal),
@@ -194,6 +198,7 @@ impl Agent {
194198
mdns_mode,
195199
mdns_name,
196200
interface_filter,
201+
ip_filter,
197202
ext_ip_mapper,
198203
net,
199204
agent_internal,
@@ -203,6 +208,7 @@ impl Agent {
203208
params.mdns_mode,
204209
params.mdns_name,
205210
params.interface_filter,
211+
params.ip_filter,
206212
params.ext_ip_mapper,
207213
params.net,
208214
params.agent_internal,
@@ -214,6 +220,7 @@ impl Agent {
214220
let result = Self::gather_candidates_local_udp_mux(GatherCandidatesLocalUDPMuxParams {
215221
network_types,
216222
interface_filter,
223+
ip_filter,
217224
ext_ip_mapper,
218225
net,
219226
agent_internal,
@@ -228,7 +235,7 @@ impl Agent {
228235
return;
229236
}
230237

231-
let ips = local_interfaces(&net, &*interface_filter, &network_types).await;
238+
let ips = local_interfaces(&net, &*interface_filter, &*ip_filter, &network_types).await;
232239
for ip in ips {
233240
let mut mapped_ip = ip;
234241

@@ -374,10 +381,19 @@ impl Agent {
374381
async fn gather_candidates_local_udp_mux(
375382
params: GatherCandidatesLocalUDPMuxParams,
376383
) -> Result<()> {
377-
let (udp_mux, agent_internal, interface_filter, ext_ip_mapper, net, network_types) = (
384+
let (
385+
udp_mux,
386+
agent_internal,
387+
interface_filter,
388+
ip_filter,
389+
ext_ip_mapper,
390+
net,
391+
network_types,
392+
) = (
378393
params.udp_mux,
379394
params.agent_internal,
380395
params.interface_filter,
396+
params.ip_filter,
381397
params.ext_ip_mapper,
382398
params.net,
383399
params.network_types,
@@ -389,7 +405,8 @@ impl Agent {
389405
let udp_mux = Arc::clone(&udp_mux);
390406

391407
// There's actually only one, but `local_interfaces` requires a slice.
392-
let local_ips = local_interfaces(&net, &interface_filter, &relevant_network_types).await;
408+
let local_ips =
409+
local_interfaces(&net, &interface_filter, &ip_filter, &relevant_network_types).await;
393410

394411
let candidate_ip = ext_ip_mapper
395412
.as_ref() // Arc

ice/src/agent/agent_gather_test.rs

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,13 @@ async fn test_vnet_gather_no_local_ip_address() -> Result<()> {
1818
})
1919
.await?;
2020

21-
let local_ips = local_interfaces(&vnet, &a.interface_filter, &[NetworkType::Udp4]).await;
21+
let local_ips = local_interfaces(
22+
&vnet,
23+
&a.interface_filter,
24+
&a.ip_filter,
25+
&[NetworkType::Udp4],
26+
)
27+
.await;
2228
assert!(local_ips.is_empty(), "should return no local IP");
2329

2430
a.close().await?;
@@ -44,7 +50,8 @@ async fn test_vnet_gather_dynamic_ip_address() -> Result<()> {
4450
})
4551
.await?;
4652

47-
let local_ips = local_interfaces(&nw, &a.interface_filter, &[NetworkType::Udp4]).await;
53+
let local_ips =
54+
local_interfaces(&nw, &a.interface_filter, &a.ip_filter, &[NetworkType::Udp4]).await;
4855
assert!(!local_ips.is_empty(), "should have one local IP");
4956

5057
for ip in &local_ips {
@@ -77,7 +84,8 @@ async fn test_vnet_gather_listen_udp() -> Result<()> {
7784
})
7885
.await?;
7986

80-
let local_ips = local_interfaces(&nw, &a.interface_filter, &[NetworkType::Udp4]).await;
87+
let local_ips =
88+
local_interfaces(&nw, &a.interface_filter, &a.ip_filter, &[NetworkType::Udp4]).await;
8189
assert!(!local_ips.is_empty(), "should have one local IP");
8290

8391
for ip in local_ips {
@@ -334,7 +342,8 @@ async fn test_vnet_gather_with_interface_filter() -> Result<()> {
334342
})
335343
.await?;
336344

337-
let local_ips = local_interfaces(&nw, &a.interface_filter, &[NetworkType::Udp4]).await;
345+
let local_ips =
346+
local_interfaces(&nw, &a.interface_filter, &a.ip_filter, &[NetworkType::Udp4]).await;
338347
assert!(
339348
local_ips.is_empty(),
340349
"InterfaceFilter should have excluded everything"
@@ -354,7 +363,8 @@ async fn test_vnet_gather_with_interface_filter() -> Result<()> {
354363
})
355364
.await?;
356365

357-
let local_ips = local_interfaces(&nw, &a.interface_filter, &[NetworkType::Udp4]).await;
366+
let local_ips =
367+
local_interfaces(&nw, &a.interface_filter, &a.ip_filter, &[NetworkType::Udp4]).await;
358368
assert_eq!(
359369
local_ips.len(),
360370
1,

ice/src/agent/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ pub struct Agent {
9797

9898
pub(crate) udp_network: UDPNetwork,
9999
pub(crate) interface_filter: Arc<Option<InterfaceFilterFn>>,
100+
pub(crate) ip_filter: Arc<Option<IpFilterFn>>,
100101
pub(crate) mdns_mode: MulticastDnsMode,
101102
pub(crate) mdns_name: String,
102103
pub(crate) mdns_conn: Option<Arc<DnsConn>>,
@@ -195,6 +196,7 @@ impl Agent {
195196
udp_network: config.udp_network,
196197
internal: Arc::new(ai),
197198
interface_filter: Arc::clone(&config.interface_filter),
199+
ip_filter: Arc::clone(&config.ip_filter),
198200
mdns_mode,
199201
mdns_name,
200202
mdns_conn,
@@ -462,6 +464,7 @@ impl Agent {
462464
mdns_name: self.mdns_name.clone(),
463465
net: Arc::clone(&self.net),
464466
interface_filter: self.interface_filter.clone(),
467+
ip_filter: self.ip_filter.clone(),
465468
ext_ip_mapper: Arc::clone(&self.ext_ip_mapper),
466469
agent_internal: Arc::clone(&self.internal),
467470
gathering_state: Arc::clone(&self.gathering_state),

ice/src/util/mod.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#[cfg(test)]
22
mod util_test;
33

4-
use crate::agent::agent_config::InterfaceFilterFn;
4+
use crate::agent::agent_config::{InterfaceFilterFn, IpFilterFn};
55
use crate::error::*;
66
use crate::network_type::*;
77

@@ -90,6 +90,7 @@ pub async fn stun_request(
9090
pub async fn local_interfaces(
9191
vnet: &Arc<Net>,
9292
interface_filter: &Option<InterfaceFilterFn>,
93+
ip_filter: &Option<IpFilterFn>,
9394
network_types: &[NetworkType],
9495
) -> HashSet<IpAddr> {
9596
let mut ips = HashSet::new();
@@ -114,11 +115,20 @@ pub async fn local_interfaces(
114115

115116
for ipnet in iface.addrs() {
116117
let ipaddr = ipnet.addr();
118+
117119
if !ipaddr.is_loopback()
118120
&& ((ipv4requested && ipaddr.is_ipv4()) || (ipv6requested && ipaddr.is_ipv6()))
119121
{
120-
ips.insert(ipaddr);
122+
continue;
121123
}
124+
125+
if let Some(filter) = ip_filter {
126+
if !filter(ipaddr) {
127+
continue;
128+
}
129+
}
130+
131+
ips.insert(ipaddr);
122132
}
123133
}
124134

ice/src/util/util_test.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use super::*;
44
async fn test_local_interfaces() -> Result<()> {
55
let vnet = Arc::new(Net::new(None));
66
let interfaces = vnet.get_interfaces().await;
7-
let ips = local_interfaces(&vnet, &None, &[NetworkType::Udp4, NetworkType::Udp6]).await;
7+
let ips = local_interfaces(&vnet, &None, &None, &[NetworkType::Udp4, NetworkType::Udp6]).await;
88
log::info!("interfaces: {:?}, ips: {:?}", interfaces, ips);
99
Ok(())
1010
}

webrtc/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
* Added more stats to `RemoteInboundRTPStats` and `RemoteOutboundRTPStats` [#282](https://github.com/webrtc-rs/webrtc/pull/282) by [@k0nserv](https://github.com/k0nserv).
66
* Don't register `video/rtx` codecs in `MediaEngine::register_default_codecs`. These weren't actually support and prevented RTX in the existing RTP stream from being used. Long term we should support RTX via this method, this is tracked in [#295](https://github.com/webrtc-rs/webrtc/issues/295). [#294 Remove video/rtx codecs](https://github.com/webrtc-rs/webrtc/pull/294) contributed by [k0nserv](https://github.com/k0nserv)
7+
* Add IP filter to WebRTC `SettingEngine` [#306](https://github.com/webrtc-rs/webrtc/pull/306)
78

89

910
## 0.5.1

webrtc/src/api/setting_engine/mod.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ mod setting_engine_test;
44
use crate::dtls_transport::dtls_role::DTLSRole;
55
use crate::ice_transport::ice_candidate_type::RTCIceCandidateType;
66
use dtls::extension::extension_use_srtp::SrtpProtectionProfile;
7-
use ice::agent::agent_config::InterfaceFilterFn;
7+
use ice::agent::agent_config::{InterfaceFilterFn, IpFilterFn};
88
use ice::mdns::MulticastDnsMode;
99
use ice::network_type::NetworkType;
1010
use ice::udp_network::UDPNetwork;
@@ -37,6 +37,7 @@ pub struct Candidates {
3737
pub ice_lite: bool,
3838
pub ice_network_types: Vec<NetworkType>,
3939
pub interface_filter: Arc<Option<InterfaceFilterFn>>,
40+
pub ip_filter: Arc<Option<IpFilterFn>>,
4041
pub nat_1to1_ips: Vec<String>,
4142
pub nat_1to1_ip_candidate_type: RTCIceCandidateType,
4243
pub multicast_dns_mode: MulticastDnsMode,
@@ -160,6 +161,14 @@ impl SettingEngine {
160161
self.candidates.interface_filter = Arc::new(Some(filter));
161162
}
162163

164+
/// set_ip_filter sets the filtering functions when gathering ICE candidates
165+
/// This can be used to exclude certain ip from ICE. Which may be
166+
/// useful if you know a certain ip will never succeed, or if you wish to reduce
167+
/// the amount of information you wish to expose to the remote peer
168+
pub fn set_ip_filter(&mut self, filter: IpFilterFn) {
169+
self.candidates.ip_filter = Arc::new(Some(filter));
170+
}
171+
163172
/// set_nat_1to1_ips sets a list of external IP addresses of 1:1 (D)NAT
164173
/// and a candidate type for which the external IP address is used.
165174
/// This is useful when you are host a server using Pion on an AWS EC2 instance

webrtc/src/ice_transport/ice_gatherer.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ impl RTCIceGatherer {
123123
prflx_acceptance_min_wait: self.setting_engine.timeout.ice_prflx_acceptance_min_wait,
124124
relay_acceptance_min_wait: self.setting_engine.timeout.ice_relay_acceptance_min_wait,
125125
interface_filter: self.setting_engine.candidates.interface_filter.clone(),
126+
ip_filter: self.setting_engine.candidates.ip_filter.clone(),
126127
nat_1to1_ips: self.setting_engine.candidates.nat_1to1_ips.clone(),
127128
nat_1to1_ip_candidate_type: nat_1to1_cand_type,
128129
net: self.setting_engine.vnet.clone(),

0 commit comments

Comments
 (0)