@@ -76,6 +76,19 @@ pub enum PeerType {
7676 Inbound ,
7777}
7878
79+ /// Defines how peer discovery operates regarding network interfaces.
80+ #[ derive( Debug , Clone , Default , PartialEq , Eq , Serialize , Deserialize ) ]
81+ #[ serde( rename_all = "camelCase" ) ]
82+ pub enum PeerDiscoveryMode {
83+ /// Discover peers on all qualifying interfaces (default behavior).
84+ #[ default]
85+ All ,
86+ /// Peer discovery is completely disabled.
87+ Disabled ,
88+ /// Only discover peers on interfaces whose names match the provided list.
89+ Filtered ( Vec < String > ) ,
90+ }
91+
7992/// Local info about a peer.
8093struct PeerInfo {
8194 /// Details how we found out about this peer.
@@ -186,7 +199,7 @@ where
186199 tcp_listen_port : u16 ,
187200 quic_listen_port : Option < u16 > ,
188201 peer_discovery_port : u16 ,
189- disable_peer_discovery : bool ,
202+ peer_discovery_mode : PeerDiscoveryMode ,
190203 private_network_config : Option < ( String , PrivateNetworkKey ) > ,
191204 metrics : M ,
192205 firewall_mark : Option < u32 > ,
@@ -266,16 +279,30 @@ where
266279 let handle = tokio:: spawn ( peer_manager. inner . clone ( ) . connect_to_peers ( ) ) ;
267280 peer_manager. abort_handles . push ( handle. abort_handle ( ) ) ;
268281
269- // Discover local peers, this does not actually connect to them. That is handle by the
282+ // Discover local peers, this does not actually connect to them. That is handled by the
270283 // connect_to_peers task.
271- if !disable_peer_discovery {
272- let handle = tokio:: spawn (
273- peer_manager
274- . inner
275- . clone ( )
276- . local_discovery ( peer_discovery_port) ,
277- ) ;
278- peer_manager. abort_handles . push ( handle. abort_handle ( ) ) ;
284+ match peer_discovery_mode {
285+ PeerDiscoveryMode :: Disabled => {
286+ // No discovery task spawned
287+ }
288+ PeerDiscoveryMode :: All => {
289+ let handle = tokio:: spawn (
290+ peer_manager
291+ . inner
292+ . clone ( )
293+ . local_discovery ( peer_discovery_port, None ) ,
294+ ) ;
295+ peer_manager. abort_handles . push ( handle. abort_handle ( ) ) ;
296+ }
297+ PeerDiscoveryMode :: Filtered ( interfaces) => {
298+ let handle = tokio:: spawn (
299+ peer_manager
300+ . inner
301+ . clone ( )
302+ . local_discovery ( peer_discovery_port, Some ( interfaces) ) ,
303+ ) ;
304+ peer_manager. abort_handles . push ( handle. abort_handle ( ) ) ;
305+ }
279306 }
280307
281308 Ok ( peer_manager)
@@ -1046,7 +1073,12 @@ where
10461073 }
10471074
10481075 /// Use multicast discovery to find local peers.
1049- async fn local_discovery ( self : Arc < Self > , peer_discovery_port : u16 ) {
1076+ /// When `allowed_interfaces` is provided, only join multicast groups on those interfaces.
1077+ async fn local_discovery (
1078+ self : Arc < Self > ,
1079+ peer_discovery_port : u16 ,
1080+ allowed_interfaces : Option < Vec < String > > ,
1081+ ) {
10501082 let rid = self . router . lock ( ) . unwrap ( ) . router_id ( ) ;
10511083
10521084 let multicast_destination = LL_PEER_DISCOVERY_GROUP
@@ -1077,7 +1109,7 @@ where
10771109 let mut joined_interfaces = HashSet :: new ( ) ;
10781110 // Join the multicast discovery group on newly detected interfaces.
10791111 let join_new_interfaces = |joined_interfaces : & mut HashSet < _ > | {
1080- let ipv6_nics = list_ipv6_interface_ids ( ) ?;
1112+ let ipv6_nics = list_ipv6_interface_ids ( allowed_interfaces . as_deref ( ) ) ?;
10811113 // Keep the existing interfaces, removing interface ids we previously joined but are no
10821114 // longer found when listing ids. We simply discard unknown ids, and assume if the
10831115 // interface is gone (or it's IPv6), that we also implicitly left the group (i.e. no
@@ -1356,7 +1388,10 @@ impl rustls::client::danger::ServerCertVerifier for SkipServerVerification {
13561388}
13571389
13581390/// Get a list of the interface identifiers of every network interface with a local IPv6 IP.
1359- fn list_ipv6_interface_ids ( ) -> Result < HashSet < u32 > , Box < dyn std:: error:: Error > > {
1391+ /// When `allowed_interfaces` is provided, only interfaces with matching names are returned.
1392+ fn list_ipv6_interface_ids (
1393+ allowed_interfaces : Option < & [ String ] > ,
1394+ ) -> Result < HashSet < u32 > , Box < dyn std:: error:: Error > > {
13601395 let mut nics = HashSet :: new ( ) ;
13611396 for nic in netdev:: get_interfaces ( )
13621397 . into_iter ( )
@@ -1368,6 +1403,12 @@ fn list_ipv6_interface_ids() -> Result<HashSet<u32>, Box<dyn std::error::Error>>
13681403 && nic. is_multicast ( )
13691404 && nic. is_up ( )
13701405 } )
1406+ // Apply name filter if provided
1407+ . filter ( |nic| {
1408+ allowed_interfaces
1409+ . map ( |names| names. iter ( ) . any ( |name| name == & nic. name ) )
1410+ . unwrap_or ( true )
1411+ } )
13711412 {
13721413 for addr in nic. ipv6 {
13731414 if addr. addr ( ) . segments ( ) [ ..4 ] == [ 0xfe80 , 0 , 0 , 0 ] {
0 commit comments