7
7
//
8
8
9
9
import Foundation
10
+ import MullvadSettings
10
11
import MullvadTypes
12
+ import Network
11
13
12
14
private let defaultPort : UInt16 = 53
13
15
@@ -19,15 +21,6 @@ public enum RelaySelector {
19
21
relays. bridge. shadowsocks. filter { $0. protocol == " tcp " } . randomElement ( )
20
22
}
21
23
22
- /// Return a random Shadowsocks bridge relay, or `nil` if no relay were found.
23
- ///
24
- /// Non `active` relays are filtered out.
25
- /// - Parameter relays: The list of relays to randomly select from.
26
- /// - Returns: A Shadowsocks relay or `nil` if no active relay were found.
27
- public static func shadowsocksRelay( from relaysResponse: REST . ServerRelaysResponse ) -> REST . BridgeRelay ? {
28
- relaysResponse. bridge. relays. filter { $0. active } . randomElement ( )
29
- }
30
-
31
24
/// Returns the closest Shadowsocks relay using the given `constraints`, or a random relay if `constraints` were
32
25
/// unsatisfiable.
33
26
///
@@ -41,7 +34,11 @@ public enum RelaySelector {
41
34
) -> REST . BridgeRelay ? {
42
35
let mappedBridges = mapRelays ( relays: relaysResponse. bridge. relays, locations: relaysResponse. locations)
43
36
let filteredRelays = applyConstraints ( constraints, relays: mappedBridges)
44
- guard filteredRelays. isEmpty == false else { return shadowsocksRelay ( from: relaysResponse) }
37
+
38
+ guard filteredRelays. isEmpty == false else {
39
+ let relay = shadowsocksRelay ( from: relaysResponse)
40
+ return relay. flatMap { applyIpOverrides ( to: $0) }
41
+ }
45
42
46
43
// Compute the midpoint location from all the filtered relays
47
44
// Take *either* the first five relays, OR the relays below maximum bridge distance
@@ -77,7 +74,8 @@ public enum RelaySelector {
77
74
UInt64 ( 1 + greatestDistance - relay. distance)
78
75
} )
79
76
80
- return randomRelay? . relay ?? filteredRelays. randomElement ( ) ? . relay
77
+ let relayToReturn = randomRelay? . relay ?? filteredRelays. randomElement ( ) ? . relay
78
+ return relayToReturn. flatMap { applyIpOverrides ( to: $0) }
81
79
}
82
80
83
81
/**
@@ -97,10 +95,15 @@ public enum RelaySelector {
97
95
numberOfFailedAttempts: numberOfFailedAttempts
98
96
)
99
97
100
- guard let relayWithLocation = pickRandomRelayByWeight ( relays: filteredRelays) , let port else {
98
+ guard var relayWithLocation = pickRandomRelayByWeight ( relays: filteredRelays) , let port else {
101
99
throw NoRelaysSatisfyingConstraintsError ( )
102
100
}
103
101
102
+ relayWithLocation = RelayWithLocation (
103
+ relay: applyIpOverrides ( to: relayWithLocation. relay) ,
104
+ serverLocation: relayWithLocation. serverLocation
105
+ )
106
+
104
107
let endpoint = MullvadEndpoint (
105
108
ipv4Relay: IPv4Endpoint (
106
109
ip: relayWithLocation. relay. ipv4AddrIn,
@@ -135,6 +138,15 @@ public enum RelaySelector {
135
138
}
136
139
}
137
140
141
+ /// Return a random Shadowsocks bridge relay, or `nil` if no relay were found.
142
+ ///
143
+ /// Non `active` relays are filtered out.
144
+ /// - Parameter relays: The list of relays to randomly select from.
145
+ /// - Returns: A Shadowsocks relay or `nil` if no active relay were found.
146
+ private static func shadowsocksRelay( from relaysResponse: REST . ServerRelaysResponse ) -> REST . BridgeRelay ? {
147
+ relaysResponse. bridge. relays. filter { $0. active } . randomElement ( )
148
+ }
149
+
138
150
/// Produce a list of `RelayWithLocation` items satisfying the given constraints
139
151
private static func applyConstraints< T: AnyRelay > (
140
152
_ constraints: RelayConstraints ,
@@ -194,6 +206,21 @@ public enum RelaySelector {
194
206
}
195
207
}
196
208
209
+ private static func applyIpOverrides< T: AnyRelay > ( to relay: T ) -> T {
210
+ let overrides = IPOverrideRepository ( ) . fetchAll ( )
211
+
212
+ if let override = overrides. first ( where: { host in
213
+ host. hostname == relay. hostname
214
+ } ) {
215
+ return relay. copyWith (
216
+ ipv4AddrIn: override. ipv4Address,
217
+ ipv6AddrIn: override. ipv6Address
218
+ )
219
+ }
220
+
221
+ return relay
222
+ }
223
+
197
224
private static func pickRandomRelayByWeight< T: AnyRelay > ( relays: [ RelayWithLocation < T > ] )
198
225
-> RelayWithLocation < T > ? {
199
226
rouletteSelection ( relays: relays, weightFunction: { relayWithLocation in relayWithLocation. relay. weight } )
@@ -314,10 +341,16 @@ public protocol AnyRelay {
314
341
var weight : UInt64 { get }
315
342
var active : Bool { get }
316
343
var includeInCountry : Bool { get }
344
+
345
+ func copyWith( ipv4AddrIn: IPv4Address ? , ipv6AddrIn: IPv6Address ? ) -> Self
317
346
}
318
347
319
348
extension REST . ServerRelay : AnyRelay { }
320
- extension REST . BridgeRelay : AnyRelay { }
349
+ extension REST . BridgeRelay : AnyRelay {
350
+ public func copyWith( ipv4AddrIn: IPv4Address ? , ipv6AddrIn: IPv6Address ? ) -> REST . BridgeRelay {
351
+ copyWith ( ipv4AddrIn: ipv4AddrIn)
352
+ }
353
+ }
321
354
322
355
private struct RelayWithLocation < T: AnyRelay > {
323
356
let relay : T
0 commit comments