@@ -156,41 +156,48 @@ fn get_shadowsocks_obfuscator_inner<R: RangeBounds<u16> + Iterator<Item = u16> +
156
156
. unwrap_or ( wg_in_addr) ;
157
157
158
158
let selected_port = if extra_in_addrs. is_empty ( ) {
159
- desired_port_from_range ( wg_in_addr_port_ranges, desired_port)
159
+ desired_or_random_port_from_range ( wg_in_addr_port_ranges, desired_port)
160
160
} else {
161
- desired_port_from_range ( SHADOWSOCKS_EXTRA_PORT_RANGES , desired_port)
161
+ desired_or_random_port_from_range ( SHADOWSOCKS_EXTRA_PORT_RANGES , desired_port)
162
162
} ?;
163
163
164
164
Ok ( SocketAddr :: from ( ( in_ip, selected_port) ) )
165
165
}
166
166
167
- fn desired_port_from_range < R : RangeBounds < u16 > + Iterator < Item = u16 > + Clone > (
167
+ /// Return `desired_port` if it is specified and included in `port_ranges`.
168
+ /// If `desired_port` isn't specified, a random port from the ranges is returned.
169
+ /// If `desired_port` is specified but not in range, an error is returned.
170
+ pub fn desired_or_random_port_from_range < R : RangeBounds < u16 > + Iterator < Item = u16 > + Clone > (
168
171
port_ranges : & [ R ] ,
169
172
desired_port : Constraint < u16 > ,
170
173
) -> Result < u16 , Error > {
171
- match desired_port {
172
- // Selected a specific, in-range port
173
- Constraint :: Only ( port) if port_in_range ( port, port_ranges) => Ok ( port) ,
174
- // Selected a specific, out-of-range port
175
- Constraint :: Only ( _port) => Err ( Error :: NoMatchingPort ) ,
176
- // Selected no specific port
177
- Constraint :: Any => select_random_port ( port_ranges) ,
178
- }
174
+ desired_port
175
+ . map ( |port| port_if_in_range ( port_ranges, port) )
176
+ . unwrap_or_else ( || select_random_port ( port_ranges) )
177
+ }
178
+
179
+ /// Return `Ok(port)`, if and only if `port` is in `port_ranges`. Otherwise, return an error.
180
+ fn port_if_in_range < R : RangeBounds < u16 > > ( port_ranges : & [ R ] , port : u16 ) -> Result < u16 , Error > {
181
+ port_ranges
182
+ . iter ( )
183
+ . find_map ( |range| {
184
+ if range. contains ( & port) {
185
+ Some ( port)
186
+ } else {
187
+ None
188
+ }
189
+ } )
190
+ . ok_or ( Error :: NoMatchingPort )
179
191
}
180
192
181
193
/// Selects a random port number from a list of provided port ranges.
182
194
///
183
- /// This function iterates over a list of port ranges, each represented as a tuple (u16, u16)
184
- /// where the first element is the start of the range and the second is the end (inclusive),
185
- /// and selects a random port from the set of all ranges.
186
- ///
187
195
/// # Parameters
188
- /// - `port`: Constraint to apply to the port selection
189
- /// - `port_ranges`: A slice of tuples, each representing a range of valid port numbers.
196
+ /// - `port_ranges`: A slice of port numbers.
190
197
///
191
198
/// # Returns
192
- /// - A randomly selected port number within the given ranges.
193
- /// - An error if `port_ranges` is empty .
199
+ /// - On success, a randomly selected port number within the given ranges. Otherwise,
200
+ /// an error is returned .
194
201
pub fn select_random_port < R : RangeBounds < u16 > + Iterator < Item = u16 > + Clone > (
195
202
port_ranges : & [ R ] ,
196
203
) -> Result < u16 , Error > {
@@ -202,13 +209,11 @@ pub fn select_random_port<R: RangeBounds<u16> + Iterator<Item = u16> + Clone>(
202
209
. ok_or ( Error :: NoMatchingPort )
203
210
}
204
211
205
- pub fn port_in_range < R : RangeBounds < u16 > > ( port : u16 , port_ranges : & [ R ] ) -> bool {
206
- port_ranges. iter ( ) . any ( |range| range. contains ( & port) )
207
- }
208
-
209
212
#[ cfg( test) ]
210
213
mod tests {
211
- use super :: { get_shadowsocks_obfuscator_inner, port_in_range, SHADOWSOCKS_EXTRA_PORT_RANGES } ;
214
+ use super :: {
215
+ get_shadowsocks_obfuscator_inner, port_if_in_range, SHADOWSOCKS_EXTRA_PORT_RANGES ,
216
+ } ;
212
217
use mullvad_types:: constraints:: Constraint ;
213
218
use std:: { net:: IpAddr , ops:: RangeInclusive } ;
214
219
@@ -226,7 +231,7 @@ mod tests {
226
231
227
232
assert_eq ! ( selected_addr. ip( ) , wg_in_ip) ;
228
233
assert ! (
229
- port_in_range ( selected_addr. port( ) , PORT_RANGES ) ,
234
+ port_if_in_range ( PORT_RANGES , selected_addr. port( ) ) . is_ok ( ) ,
230
235
"expected port in port range"
231
236
) ;
232
237
@@ -240,7 +245,7 @@ mod tests {
240
245
241
246
assert_eq ! ( selected_addr. ip( ) , wg_in_ip) ;
242
247
assert ! (
243
- port_in_range ( selected_addr. port( ) , PORT_RANGES ) ,
248
+ port_if_in_range ( PORT_RANGES , selected_addr. port( ) ) . is_ok ( ) ,
244
249
"expected port in port range"
245
250
) ;
246
251
@@ -278,10 +283,7 @@ mod tests {
278
283
extra_in_addrs. contains( & selected_addr. ip( ) ) ,
279
284
"expected extra IP to be selected"
280
285
) ;
281
- assert ! ( port_in_range(
282
- selected_addr. port( ) ,
283
- SHADOWSOCKS_EXTRA_PORT_RANGES
284
- ) ) ;
286
+ assert ! ( port_if_in_range( SHADOWSOCKS_EXTRA_PORT_RANGES , selected_addr. port( ) , ) . is_ok( ) ) ;
285
287
286
288
let selected_addr = get_shadowsocks_obfuscator_inner (
287
289
wg_in_ip,
0 commit comments