Overview
The relay selector is responsible for choosing one or more Mullvad VPN relays from the available relay list, taking into account user-configurable criteria, availability, and connection requirements. It implements intelligent fallback strategies and supports advanced features like DAITA and multihop. Reference:mullvad-relay-selector/src/relay_selector.rs, docs/relay-selector.md
Core Concepts
Glossary
- Relay: A server that provides one or multiple tunnel endpoints, with an associated weight
- Endpoint: A combination of socket address and transport protocol
- Transport Protocol: TCP or UDP
- Obfuscation: Wrapping VPN traffic in protocols designed to circumvent censorship
- DAITA: Defense Against AI-guided Traffic Analysis - makes website fingerprinting harder
- Multihop: Routing traffic through two relays instead of one for enhanced privacy
docs/relay-selector.md:1-16
Selection Process
The relay selector operates in multiple phases:1. Constraint Application
Filter relays based on user-specified criteria:- Location constraints: Country, city, or specific hostname
- Provider constraints: Filter by hosting provider
- Ownership constraints: Mullvad-owned vs rented servers
- Protocol constraints: WireGuard port and IP version
- Feature requirements: DAITA, multihop, obfuscation
docs/relay-selector.md:32-44
2. Filtering Process
The selector iterates through each relay in the relay list:- Remove relays that don’t match location constraints
- Filter out relays not meeting protocol requirements
- Eliminate relays without required features (DAITA, etc.)
- Remove inactive/offline relays
- Filter by provider and ownership if specified
docs/relay-selector.md:26-30
3. Relay Selection
From the filtered set, select a single relay using roulette wheel selection:- Each relay has an assigned weight (from relay list)
- Higher weight = higher probability of selection
- This provides load balancing while respecting server capacity
- Once a relay is chosen, randomly select a matching endpoint
docs/relay-selector.md:82-87
4. Endpoint Selection
After selecting a relay, choose a specific endpoint:- Filter endpoints by protocol (TCP/UDP)
- Filter by port constraints
- Filter by IP version (IPv4/IPv6)
- Randomly select from remaining endpoints
Default Constraints
When users don’t specify explicit constraints, the selector applies progressive fallback strategies to maximize connection success.Desktop Default Strategy
- First attempt: Random port, IPv4, no obfuscation
- Second attempt: Random port, IPv6 (if available on host)
- Third attempt: Shadowsocks obfuscation, random port
- Fourth attempt: QUIC obfuscation, port 443
- Fifth attempt: UDP2TCP obfuscation, random port (80, 443, or 5001)
- Sixth attempt: UDP2TCP over IPv6 (if available)
- Seventh attempt: LWO (Lightweight WireGuard Obfuscation)
docs/relay-selector.md:45-52
iOS Default Strategy
iOS doesn’t support IPv6 connections, so the strategy is simplified:- First attempt: Random port, IPv4
- Second attempt: Shadowsocks obfuscation, random port
- Third attempt: QUIC obfuscation, port 443
- Fourth attempt: UDP2TCP obfuscation, port 443 or 80
docs/relay-selector.md:54-62
Obfuscation Ports
- UDP2TCP: Ports 80, 443, or 5001 (desktop); 80 or 443 (iOS)
- Shadowsocks: Random port from relay-defined range
- QUIC: Port 443
- LWO: Standard WireGuard ports
docs/relay-selector.md:64-73
Retry Behavior
If no tunnel is established after exhausting all attempts, the selector loops back to the first constraint and continues trying. This ensures persistent connection attempts with varying configurations. Reference:docs/relay-selector.md:75-80
DAITA-Compatible Selection
DAITA (Defense Against AI-guided Traffic Analysis) is not available on all relays, requiring special handling.Automatic Multihop
When DAITA is enabled but the desired exit relay doesn’t support it:- Selector finds a DAITA-compatible entry relay
- Implicitly configures multihop connection
- Entry relay provides DAITA functionality
- Exit relay honors user’s location constraint
docs/relay-selector.md:89-94
Direct-Only Mode
Users can disable automatic multihop with “Direct only” setting:- Only selects relays that directly support DAITA
- No implicit multihop configuration
- May result in fewer available relays
docs/relay-selector.md:96-97
Multihop Configuration
Multihop routes traffic through two relays for enhanced privacy.Selecting Entry and Exit
When multihop is enabled:- Exit relay selection: Apply user’s location/provider constraints
- Entry relay selection: Apply entry-specific constraints
- Conflict prevention: Ensure entry ≠ exit relay
- Compatibility check: Verify protocol compatibility between hops
Multihop with DAITA
When using DAITA with multihop, the entry relay must support DAITA since it’s the first hop handling the user’s traffic. Reference:docs/relay-selector.md:92-94
Constraint Types
Location Constraints
- Country only:
{ country: "se" }(any Swedish relay) - City:
{ country: "se", city: "got" }(Gothenburg, Sweden) - Hostname:
{ country: "se", city: "got", hostname: "se-got-wg-001" }(specific relay)
mullvad-management-interface/proto/management_interface.proto:402-413
WireGuard Constraints
- IP version (IPv4/IPv6)
- Allowed IPs (routing)
- Multihop enable/disable
- Entry relay constraints (for multihop)
mullvad-management-interface/proto/management_interface.proto:575-582
Obfuscation Constraints
AUTO: Use default obfuscation strategyOFF: No obfuscationWIREGUARD_PORT: Specific WireGuard portUDP2TCP,SHADOWSOCKS,QUIC,LWO: Specific obfuscation method
mullvad-management-interface/proto/management_interface.proto:415-433
Custom Lists
Users can create named collections of relay locations for quick access:- “Low latency”: Nearby cities
- “Streaming”: Specific countries
- “Trusted providers”: Mullvad-owned relays only
mullvad-management-interface/proto/management_interface.proto:435-439
Relay List Structure
Relay Definition
mullvad-management-interface/proto/management_interface.proto:689-713
Endpoint Data
Shared configuration for all WireGuard relays:mullvad-management-interface/proto/management_interface.proto:774-780
Implementation Details
Weighted Random Selection
The roulette wheel selection algorithm:mullvad-relay-selector/src/relay_selector.rs
Constraint Compatibility
Default constraints are filtered by user constraints:- If user specifies UDP-only, IPv6 attempts are skipped
- If user disables obfuscation, obfuscation attempts are skipped
- If user selects specific port, all random port attempts use that port
Relay Selector Service
A separate gRPC service provides relay selection analysis:mullvad-management-interface/proto/relay_selector.proto:11-22
Predicate Types
singlehop: Direct relay connectionautohop: Automatic multihop when needed (e.g., for DAITA)entry: Entry relay for explicit multihopexit: Exit relay for multihop
relay_selector.proto:24-45
Relay Partitions
The service returns two sets:- Available relays for current settings
- Why certain relays are unavailable
- What constraints need changing to access specific relays
relay_selector.proto:74-103
Incompatible Constraints
relay_selector.proto:105-129
Edge Cases and Special Handling
No Matching Relays
When no relays match constraints:- Error state entered with
NO_MATCHING_RELAYcause - Firewall blocks all traffic (security guarantee)
- User must adjust constraints or wait for relay list update
mullvad-management-interface/proto/management_interface.proto:238-245
Relay List Updates
The relay list is periodically updated from the API:- Automatic background updates
- Manual refresh via
UpdateRelayLocationsRPC - Cached locally to work offline
- Selection reevaluates on each connection attempt
mullvad-daemon/src/relay_list/
Offline Relays
Relays can be marked inactive in the relay list:- Inactive relays are filtered out during selection
- Temporary outages handled automatically
- No user intervention required
IPv6 Availability
IPv6 selection depends on host configuration:- Selector checks if host has IPv6 connectivity
- IPv6 attempts skipped if unavailable
- Prevents connection failures due to missing IPv6
Recent Relays
The system tracks recently used relay configurations:mullvad-management-interface/proto/management_interface.proto:532-544
Performance Considerations
Caching
- Relay list cached in memory
- Filtered results not cached (recomputed on demand)
- Ensures fresh selections on each connection
Selection Speed
Relay selection is fast:- Linear scan of relay list (typically <1000 relays)
- Simple constraint matching
- Completes in milliseconds
Load Balancing
Weighted selection distributes load:- High-capacity servers have higher weights
- Prevents overloading individual relays
- Provides good geographic distribution
Testing and Debugging
Relay Override
For testing, specific relays can be forced:mullvad-management-interface/proto/management_interface.proto:526-530
Disable/Enable Relays
Individual relays can be disabled for testing:mullvad-management-interface/proto/management_interface.proto:138-139
Related Documentation
- Mullvad vs Talpid Layers
- Management Interface
- API Communication
- Relay Selection Documentation (source repository)