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