@@ -30,6 +30,7 @@ use futures_timer::Delay;
30
30
use instant:: Instant ;
31
31
use libp2p_core:: {
32
32
connection:: { ConnectionId , ListenerId } ,
33
+ multiaddr:: Protocol ,
33
34
ConnectedPoint , Endpoint , Multiaddr , PeerId ,
34
35
} ;
35
36
use libp2p_request_response:: {
@@ -77,6 +78,11 @@ pub struct Config {
77
78
pub throttle_clients_peer_max : usize ,
78
79
/// Period for throttling clients requests.
79
80
pub throttle_clients_period : Duration ,
81
+ /// As a server reject probes for clients that are observed at a non-global ip address.
82
+ /// Correspondingly as a client only pick peers as server that are not observed at a
83
+ /// private ip address. Note that this does not apply for servers that are added via
84
+ /// [`Behaviour::add_server`].
85
+ pub only_global_ips : bool ,
80
86
}
81
87
82
88
impl Default for Config {
@@ -93,6 +99,7 @@ impl Default for Config {
93
99
throttle_clients_global_max : 30 ,
94
100
throttle_clients_peer_max : 3 ,
95
101
throttle_clients_period : Duration :: from_secs ( 1 ) ,
102
+ only_global_ips : true ,
96
103
}
97
104
}
98
105
}
@@ -188,7 +195,8 @@ pub struct Behaviour {
188
195
ongoing_outbound : HashMap < RequestId , ProbeId > ,
189
196
190
197
// Connected peers with the observed address of each connection.
191
- // If the endpoint of a connection is relayed, the observed address is `None`.
198
+ // If the endpoint of a connection is relayed or not global (in case of Config::only_global_ips),
199
+ // the observed address is `None`.
192
200
connected : HashMap < PeerId , HashMap < ConnectionId , Option < Multiaddr > > > ,
193
201
194
202
// Used servers in recent outbound probes that are throttled through Config::throttle_server_period.
@@ -313,12 +321,14 @@ impl NetworkBehaviour for Behaviour {
313
321
other_established,
314
322
) ;
315
323
let connections = self . connected . entry ( * peer) . or_default ( ) ;
316
- let addr = if endpoint. is_relayed ( ) {
317
- None
318
- } else {
319
- Some ( endpoint. get_remote_address ( ) . clone ( ) )
320
- } ;
321
- connections. insert ( * conn, addr) ;
324
+ let addr = endpoint. get_remote_address ( ) ;
325
+ let observed_addr =
326
+ if !endpoint. is_relayed ( ) && ( !self . config . only_global_ips || addr. is_global_ip ( ) ) {
327
+ Some ( addr. clone ( ) )
328
+ } else {
329
+ None
330
+ } ;
331
+ connections. insert ( * conn, observed_addr) ;
322
332
323
333
match endpoint {
324
334
ConnectedPoint :: Dialer {
@@ -386,12 +396,14 @@ impl NetworkBehaviour for Behaviour {
386
396
return ;
387
397
}
388
398
let connections = self . connected . get_mut ( peer) . expect ( "Peer is connected." ) ;
389
- let addr = if new. is_relayed ( ) {
390
- None
391
- } else {
392
- Some ( new. get_remote_address ( ) . clone ( ) )
393
- } ;
394
- connections. insert ( * conn, addr) ;
399
+ let addr = new. get_remote_address ( ) ;
400
+ let observed_addr =
401
+ if !new. is_relayed ( ) && ( !self . config . only_global_ips || addr. is_global_ip ( ) ) {
402
+ Some ( addr. clone ( ) )
403
+ } else {
404
+ None
405
+ } ;
406
+ connections. insert ( * conn, observed_addr) ;
395
407
}
396
408
397
409
fn inject_new_listen_addr ( & mut self , id : ListenerId , addr : & Multiaddr ) {
@@ -512,3 +524,119 @@ trait HandleInnerEvent {
512
524
event : RequestResponseEvent < DialRequest , DialResponse > ,
513
525
) -> ( VecDeque < Event > , Option < Action > ) ;
514
526
}
527
+
528
+ trait GlobalIp {
529
+ fn is_global_ip ( & self ) -> bool ;
530
+ }
531
+
532
+ impl GlobalIp for Multiaddr {
533
+ fn is_global_ip ( & self ) -> bool {
534
+ match self . iter ( ) . next ( ) {
535
+ Some ( Protocol :: Ip4 ( a) ) => a. is_global_ip ( ) ,
536
+ Some ( Protocol :: Ip6 ( a) ) => a. is_global_ip ( ) ,
537
+ _ => false ,
538
+ }
539
+ }
540
+ }
541
+
542
+ impl GlobalIp for std:: net:: Ipv4Addr {
543
+ // NOTE: The below logic is copied from `std::net::Ipv4Addr::is_global`, which is at the time of
544
+ // writing behind the unstable `ip` feature.
545
+ // See https://github.com/rust-lang/rust/issues/27709 for more info.
546
+ fn is_global_ip ( & self ) -> bool {
547
+ // Check if this address is 192.0.0.9 or 192.0.0.10. These addresses are the only two
548
+ // globally routable addresses in the 192.0.0.0/24 range.
549
+ if u32:: from_be_bytes ( self . octets ( ) ) == 0xc0000009
550
+ || u32:: from_be_bytes ( self . octets ( ) ) == 0xc000000a
551
+ {
552
+ return true ;
553
+ }
554
+
555
+ // Copied from the unstable method `std::net::Ipv4Addr::is_shared`.
556
+ fn is_shared ( addr : & std:: net:: Ipv4Addr ) -> bool {
557
+ addr. octets ( ) [ 0 ] == 100 && ( addr. octets ( ) [ 1 ] & 0b1100_0000 == 0b0100_0000 )
558
+ }
559
+
560
+ // Copied from the unstable method `std::net::Ipv4Addr::is_reserved`.
561
+ //
562
+ // **Warning**: As IANA assigns new addresses, this logic will be
563
+ // updated. This may result in non-reserved addresses being
564
+ // treated as reserved in code that relies on an outdated version
565
+ // of this method.
566
+ fn is_reserved ( addr : & std:: net:: Ipv4Addr ) -> bool {
567
+ addr. octets ( ) [ 0 ] & 240 == 240 && !addr. is_broadcast ( )
568
+ }
569
+
570
+ // Copied from the unstable method `std::net::Ipv4Addr::is_benchmarking`.
571
+ fn is_benchmarking ( addr : & std:: net:: Ipv4Addr ) -> bool {
572
+ addr. octets ( ) [ 0 ] == 198 && ( addr. octets ( ) [ 1 ] & 0xfe ) == 18
573
+ }
574
+
575
+ !self . is_private ( )
576
+ && !self . is_loopback ( )
577
+ && !self . is_link_local ( )
578
+ && !self . is_broadcast ( )
579
+ && !self . is_documentation ( )
580
+ && !is_shared ( self )
581
+ // addresses reserved for future protocols (`192.0.0.0/24`)
582
+ && !( self . octets ( ) [ 0 ] == 192 && self . octets ( ) [ 1 ] == 0 && self . octets ( ) [ 2 ] == 0 )
583
+ && !is_reserved ( self )
584
+ && !is_benchmarking ( self )
585
+ // Make sure the address is not in 0.0.0.0/8
586
+ && self . octets ( ) [ 0 ] != 0
587
+ }
588
+ }
589
+
590
+ impl GlobalIp for std:: net:: Ipv6Addr {
591
+ // NOTE: The below logic is copied from `std::net::Ipv6Addr::is_global`, which is at the time of
592
+ // writing behind the unstable `ip` feature.
593
+ // See https://github.com/rust-lang/rust/issues/27709 for more info.
594
+ //
595
+ // Note that contrary to `Ipv4Addr::is_global_ip` this currently checks for global scope
596
+ // rather than global reachability.
597
+ fn is_global_ip ( & self ) -> bool {
598
+ // Copied from the unstable method `std::net::Ipv6Addr::is_unicast`.
599
+ fn is_unicast ( addr : & std:: net:: Ipv6Addr ) -> bool {
600
+ !addr. is_multicast ( )
601
+ }
602
+ // Copied from the unstable method `std::net::Ipv6Addr::is_unicast_link_local`.
603
+ fn is_unicast_link_local ( addr : & std:: net:: Ipv6Addr ) -> bool {
604
+ ( addr. segments ( ) [ 0 ] & 0xffc0 ) == 0xfe80
605
+ }
606
+ // Copied from the unstable method `std::net::Ipv6Addr::is_unique_local`.
607
+ fn is_unique_local ( addr : & std:: net:: Ipv6Addr ) -> bool {
608
+ ( addr. segments ( ) [ 0 ] & 0xfe00 ) == 0xfc00
609
+ }
610
+ // Copied from the unstable method `std::net::Ipv6Addr::is_documentation`.
611
+ fn is_documentation ( addr : & std:: net:: Ipv6Addr ) -> bool {
612
+ ( addr. segments ( ) [ 0 ] == 0x2001 ) && ( addr. segments ( ) [ 1 ] == 0xdb8 )
613
+ }
614
+
615
+ // Copied from the unstable method `std::net::Ipv6Addr::is_unicast_global`.
616
+ fn is_unicast_global ( addr : & std:: net:: Ipv6Addr ) -> bool {
617
+ is_unicast ( addr)
618
+ && !addr. is_loopback ( )
619
+ && !is_unicast_link_local ( addr)
620
+ && !is_unique_local ( addr)
621
+ && !addr. is_unspecified ( )
622
+ && !is_documentation ( addr)
623
+ }
624
+
625
+ // Variation of unstable method [`std::net::Ipv6Addr::multicast_scope`] that instead of the
626
+ // `Ipv6MulticastScope` just returns if the scope is global or not.
627
+ // Equivalent to `Ipv6Addr::multicast_scope(..).map(|scope| matches!(scope, Ipv6MulticastScope::Global))`.
628
+ fn is_multicast_scope_global ( addr : & std:: net:: Ipv6Addr ) -> Option < bool > {
629
+ match addr. segments ( ) [ 0 ] & 0x000f {
630
+ 14 => Some ( true ) , // Global multicast scope.
631
+ 1 ..=5 | 8 => Some ( false ) , // Local multicast scope.
632
+ _ => None , // Unknown multicast scope.
633
+ }
634
+ }
635
+
636
+ match is_multicast_scope_global ( self ) {
637
+ Some ( true ) => true ,
638
+ None => is_unicast_global ( self ) ,
639
+ _ => false ,
640
+ }
641
+ }
642
+ }
0 commit comments