@@ -25,7 +25,7 @@ use mullvad_types::{
25
25
OpenVpnConstraints , RelayConstraints , RelayOverride , RelaySettings , ResolvedBridgeSettings ,
26
26
SelectedObfuscation , WireguardConstraints ,
27
27
} ,
28
- relay_list:: { Relay , RelayList } ,
28
+ relay_list:: { Relay , RelayEndpointData , RelayList } ,
29
29
settings:: Settings ,
30
30
CustomTunnelEndpoint ,
31
31
} ;
@@ -201,8 +201,40 @@ pub enum GetRelay {
201
201
/// will actually be routed to the broader internet.
202
202
#[ derive( Clone , Debug ) ]
203
203
pub enum WireguardConfig {
204
- Singlehop { exit : Relay } ,
205
- Multihop { exit : Relay , entry : Relay } ,
204
+ /// Strongly prefer to instantiate this variant using [`WireguardConfig::singlehop`] as that
205
+ /// will assert that the relay is of the expected type.
206
+ Singlehop {
207
+ exit : Relay ,
208
+ } ,
209
+ Multihop {
210
+ exit : Relay ,
211
+ entry : Relay ,
212
+ } ,
213
+ }
214
+
215
+ impl WireguardConfig {
216
+ fn singlehop ( exit : Relay ) -> Self {
217
+ // FIXME: This assert would be better to encode at the type level.
218
+ assert ! ( matches!(
219
+ exit. endpoint_data,
220
+ RelayEndpointData :: Wireguard ( _)
221
+ ) ) ;
222
+ Self :: Singlehop { exit }
223
+ }
224
+
225
+ fn multihop ( exit : Relay , entry : Relay ) -> Self {
226
+ // FIXME: This assert would be better to encode at the type level.
227
+ assert ! ( matches!(
228
+ exit. endpoint_data,
229
+ RelayEndpointData :: Wireguard ( _)
230
+ ) ) ;
231
+ // FIXME: This assert would be better to encode at the type level.
232
+ assert ! ( matches!(
233
+ entry. endpoint_data,
234
+ RelayEndpointData :: Wireguard ( _)
235
+ ) ) ;
236
+ Self :: Multihop { exit, entry }
237
+ }
206
238
}
207
239
208
240
#[ derive( Clone , Debug ) ]
@@ -454,7 +486,7 @@ impl RelaySelector {
454
486
}
455
487
SpecializedSelectorConfig :: Normal ( pure_config) => {
456
488
let parsed_relays = & self . parsed_relays . lock ( ) . unwrap ( ) ;
457
- Self :: get_relay_inner ( & query, parsed_relays, & pure_config)
489
+ Self :: get_relay_inner ( query, parsed_relays, & pure_config)
458
490
}
459
491
}
460
492
}
@@ -522,7 +554,7 @@ impl RelaySelector {
522
554
runtime_params,
523
555
user_preferences,
524
556
) ;
525
- Self :: get_relay_inner ( & query, parsed_relays, & normal_config)
557
+ Self :: get_relay_inner ( query, parsed_relays, & normal_config)
526
558
}
527
559
}
528
560
}
@@ -568,7 +600,7 @@ impl RelaySelector {
568
600
/// * An `Err` if no suitable bridge is found
569
601
#[ cfg( not( target_os = "android" ) ) ]
570
602
fn get_relay_inner (
571
- query : & RelayQuery ,
603
+ query : RelayQuery ,
572
604
parsed_relays : & ParsedRelays ,
573
605
config : & NormalSelectorConfig < ' _ > ,
574
606
) -> Result < GetRelay , Error > {
@@ -585,7 +617,7 @@ impl RelaySelector {
585
617
let mut new_query = query. clone ( ) ;
586
618
new_query. tunnel_protocol = Constraint :: Only ( tunnel_type) ;
587
619
// If a suitable relay is found, short-circuit and return it
588
- if let Ok ( relay) = Self :: get_relay_inner ( & new_query, parsed_relays, config) {
620
+ if let Ok ( relay) = Self :: get_relay_inner ( new_query, parsed_relays, config) {
589
621
return Ok ( relay) ;
590
622
}
591
623
}
@@ -596,15 +628,24 @@ impl RelaySelector {
596
628
597
629
#[ cfg( target_os = "android" ) ]
598
630
fn get_relay_inner (
599
- query : & RelayQuery ,
631
+ mut query : RelayQuery ,
600
632
parsed_relays : & ParsedRelays ,
601
633
config : & NormalSelectorConfig < ' _ > ,
602
634
) -> Result < GetRelay , Error > {
635
+ // FIXME: A bit of defensive programming - calling `get_wiregurad_relay` with a query that doesn't
636
+ // specify Wireguard as the desired tunnel type is not valid and will lead to unwanted
637
+ // behavior. This should be seen as a workaround, and it would be nicer to lift this
638
+ // invariant to be checked by the type system instead.
639
+ query. tunnel_protocol = Constraint :: Only ( TunnelType :: Wireguard ) ;
603
640
Self :: get_wireguard_relay ( query, config, parsed_relays)
604
641
}
605
642
606
643
/// Derive a valid Wireguard relay configuration from `query`.
607
644
///
645
+ /// # Note
646
+ /// This function should *only* be called with a Wireguard query.
647
+ /// It will panic if the tunnel type is not specified as Wireguard.
648
+ ///
608
649
/// # Returns
609
650
/// * An `Err` if no exit relay can be chosen
610
651
/// * An `Err` if no entry relay can be chosen (if multihop is enabled on `query`)
@@ -613,18 +654,22 @@ impl RelaySelector {
613
654
///
614
655
/// [`MullvadEndpoint`]: mullvad_types::endpoint::MullvadEndpoint
615
656
fn get_wireguard_relay (
616
- query : & RelayQuery ,
657
+ query : RelayQuery ,
617
658
config : & NormalSelectorConfig < ' _ > ,
618
659
parsed_relays : & ParsedRelays ,
619
660
) -> Result < GetRelay , Error > {
661
+ assert_eq ! (
662
+ query. tunnel_protocol,
663
+ Constraint :: Only ( TunnelType :: Wireguard )
664
+ ) ;
620
665
let inner = if !query. wireguard_constraints . multihop ( ) {
621
- Self :: get_wireguard_singlehop_config ( query, config, parsed_relays) ?
666
+ Self :: get_wireguard_singlehop_config ( & query, config, parsed_relays) ?
622
667
} else {
623
- Self :: get_wireguard_multihop_config ( query, config, parsed_relays) ?
668
+ Self :: get_wireguard_multihop_config ( & query, config, parsed_relays) ?
624
669
} ;
625
- let endpoint = Self :: get_wireguard_endpoint ( query, parsed_relays, & inner) ?;
670
+ let endpoint = Self :: get_wireguard_endpoint ( & query, parsed_relays, & inner) ?;
626
671
let obfuscator =
627
- Self :: get_wireguard_obfuscator ( query, inner. clone ( ) , & endpoint, parsed_relays) ?;
672
+ Self :: get_wireguard_obfuscator ( & query, inner. clone ( ) , & endpoint, parsed_relays) ?;
628
673
629
674
Ok ( GetRelay :: Wireguard {
630
675
endpoint,
@@ -646,7 +691,8 @@ impl RelaySelector {
646
691
let candidates =
647
692
filter_matching_relay_list ( query, parsed_relays. relays ( ) , config. custom_lists ) ;
648
693
helpers:: pick_random_relay ( & candidates)
649
- . map ( |exit| WireguardConfig :: Singlehop { exit : exit. clone ( ) } )
694
+ . cloned ( )
695
+ . map ( WireguardConfig :: singlehop)
650
696
. ok_or ( Error :: NoRelay )
651
697
}
652
698
@@ -700,10 +746,7 @@ impl RelaySelector {
700
746
}
701
747
. ok_or ( Error :: NoRelay ) ?;
702
748
703
- Ok ( WireguardConfig :: Multihop {
704
- exit : exit. clone ( ) ,
705
- entry : entry. clone ( ) ,
706
- } )
749
+ Ok ( WireguardConfig :: multihop ( exit. clone ( ) , entry. clone ( ) ) )
707
750
}
708
751
709
752
/// Constructs a [`MullvadEndpoint`] with details for how to connect to `relay`.
@@ -754,6 +797,10 @@ impl RelaySelector {
754
797
755
798
/// Derive a valid OpenVPN relay configuration from `query`.
756
799
///
800
+ /// # Note
801
+ /// This function should *only* be called with an OpenVPN query.
802
+ /// It will panic if the tunnel type is not specified as OpenVPN.
803
+ ///
757
804
/// # Returns
758
805
/// * An `Err` if no exit relay can be chosen
759
806
/// * An `Err` if no entry bridge can be chosen (if bridge mode is enabled on `query`)
@@ -763,16 +810,19 @@ impl RelaySelector {
763
810
/// [`MullvadEndpoint`]: mullvad_types::endpoint::MullvadEndpoint
764
811
#[ cfg( not( target_os = "android" ) ) ]
765
812
fn get_openvpn_relay (
766
- query : & RelayQuery ,
813
+ query : RelayQuery ,
767
814
config : & NormalSelectorConfig < ' _ > ,
768
815
parsed_relays : & ParsedRelays ,
769
816
) -> Result < GetRelay , Error > {
817
+ assert_eq ! ( query. tunnel_protocol, Constraint :: Only ( TunnelType :: OpenVpn ) ) ;
770
818
let exit =
771
- Self :: choose_openvpn_relay ( query, config, parsed_relays) . ok_or ( Error :: NoRelay ) ?;
772
- let endpoint = Self :: get_openvpn_endpoint ( query, & exit, parsed_relays) ?;
819
+ Self :: choose_openvpn_relay ( & query, config, parsed_relays) . ok_or ( Error :: NoRelay ) ?;
820
+ let endpoint = Self :: get_openvpn_endpoint ( & query, & exit, parsed_relays) ?;
773
821
let bridge =
774
- Self :: get_openvpn_bridge ( query, & exit, & endpoint. protocol , parsed_relays, config) ?;
822
+ Self :: get_openvpn_bridge ( & query, & exit, & endpoint. protocol , parsed_relays, config) ?;
775
823
824
+ // FIXME: This assert would be better to encode at the type level.
825
+ assert ! ( matches!( exit. endpoint_data, RelayEndpointData :: Openvpn ) ) ;
776
826
Ok ( GetRelay :: OpenVpn {
777
827
endpoint,
778
828
exit,
@@ -964,6 +1014,7 @@ impl RelaySelector {
964
1014
965
1015
/// # Returns
966
1016
/// A randomly selected relay that meets the specified constraints, or `None` if no suitable relay is found.
1017
+ #[ cfg( not( target_os = "android" ) ) ]
967
1018
fn choose_openvpn_relay (
968
1019
query : & RelayQuery ,
969
1020
config : & NormalSelectorConfig < ' _ > ,
0 commit comments