1
1
use crate :: APP_NAME ;
2
- use backoff:: ExponentialBackoffBuilder ;
3
2
use itertools:: Itertools ;
4
- use std:: fmt:: { Display , Formatter } ;
5
3
use std:: mem:: transmute;
6
4
use std:: net:: IpAddr ;
7
5
use std:: ptr:: { null_mut, slice_from_raw_parts} ;
8
- use std:: time:: Duration ;
9
6
use thiserror:: Error ;
10
7
use win32_utils:: net:: ToStdSocket ;
11
8
use win32_utils:: str:: FromWin32Str ;
@@ -19,7 +16,6 @@ use windows::Win32::Networking::WinSock::AF_UNSPEC;
19
16
#[ derive( Debug ) ]
20
17
struct Route {
21
18
interface_index : u32 ,
22
- metric : u32 ,
23
19
destination_prefix_ip : IpAddr ,
24
20
destination_prefix_len : u8 ,
25
21
}
@@ -31,8 +27,8 @@ impl Route {
31
27
}
32
28
}
33
29
34
- /// Returns list of routes to 0.0.0.0/0 and ::/0
35
- fn get_internet_routes ( ) -> Result < Vec < Route > , Error > {
30
+ /// Returns a list of IPv4 and IPv6 routes
31
+ fn get_routes ( ) -> Result < Vec < Route > , Error > {
36
32
unsafe {
37
33
let mut ptr = null_mut :: < MIB_IPFORWARD_TABLE2 > ( ) ;
38
34
GetIpForwardTable2 ( AF_UNSPEC . 0 as u16 , & mut ptr) . map_err ( Error :: GetIpForwardTable2 ) ?;
@@ -46,11 +42,9 @@ fn get_internet_routes() -> Result<Vec<Route>, Error> {
46
42
. map ( |idx| & table[ idx as usize ] )
47
43
. map ( |row| Route {
48
44
interface_index : row. InterfaceIndex ,
49
- metric : row. Metric ,
50
45
destination_prefix_ip : row. DestinationPrefix . Prefix . to_std_socket_addr ( ) . ip ( ) ,
51
46
destination_prefix_len : row. DestinationPrefix . PrefixLength ,
52
47
} )
53
- . filter ( Route :: is_internet_route)
54
48
. collect :: < Vec < _ > > ( ) ;
55
49
FreeMibTable ( transmute ( ptr) ) ;
56
50
Ok ( res)
@@ -131,46 +125,15 @@ fn get_adapters() -> Result<Vec<Adapter>, Error> {
131
125
}
132
126
}
133
127
134
- #[ derive( Debug ) ]
135
- struct RouteAndAdapter < ' a > {
136
- route : & ' a Route ,
137
- adapter : & ' a Adapter ,
138
- }
139
-
140
- impl RouteAndAdapter < ' _ > {
141
- /// "the overall metric that is used to determine the interface preference is the sum of the
142
- /// route metric and the interface metric"
143
- fn metric_sum ( & self ) -> u32 {
144
- self . route . metric
145
- + match self . route . destination_prefix_ip {
146
- IpAddr :: V4 ( _) => self . adapter . ipv4_metric ,
147
- IpAddr :: V6 ( _) => self . adapter . ipv6_metric ,
148
- }
149
- }
150
- }
151
-
152
- impl Display for RouteAndAdapter < ' _ > {
153
- fn fmt ( & self , f : & mut Formatter < ' _ > ) -> std:: fmt:: Result {
154
- let m_sum = self . metric_sum ( ) ;
155
- let s = format ! (
156
- "{}/{}, interface index: {}, metric: {} ({} + {}), dns servers: {:?}, dns suffixes: {:?}" ,
157
- self . route. destination_prefix_ip,
158
- self . route. destination_prefix_len,
159
- self . route. interface_index,
160
- m_sum,
161
- self . route. metric,
162
- m_sum - self . route. metric,
163
- self . adapter. dns_servers,
164
- self . adapter. dns_suffixes
165
- ) ;
166
- f. write_str ( s. as_str ( ) )
128
+ impl Adapter {
129
+ // For the purposes of DNS, the interface metric is whichever one is lowest
130
+ fn interface_metric ( & self ) -> u32 {
131
+ std:: cmp:: min ( self . ipv4_metric , self . ipv6_metric )
167
132
}
168
133
}
169
134
170
135
#[ derive( Debug , Error ) ]
171
136
pub enum Error {
172
- #[ error( "Unable to find adapter for interface: {interface_index}" ) ]
173
- RouteInterfaceMismatch { interface_index : u32 } ,
174
137
#[ error( "Calls to GetAdaptersAddresses() returned different buffer sizes" ) ]
175
138
GetAdaptersAddressesOverflow ,
176
139
#[ error( "Call to GetIpForwardTable2() failed: {0}" ) ]
@@ -179,97 +142,47 @@ pub enum Error {
179
142
GetAdaptersAddresses ( #[ source] windows:: core:: Error ) ,
180
143
}
181
144
182
- impl Error {
183
- /// Some errors should be retried
184
- pub fn into_backoff ( self ) -> backoff:: Error < Self > {
185
- match & self {
186
- Error :: RouteInterfaceMismatch { .. } => self . into ( ) ,
187
- Error :: GetAdaptersAddressesOverflow { .. } => self . into ( ) ,
188
- _ => backoff:: Error :: Permanent ( self ) ,
189
- }
190
- }
191
- }
192
-
193
- impl From < backoff:: Error < Error > > for Error {
194
- fn from ( e : backoff:: Error < Error > ) -> Self {
195
- match e {
196
- backoff:: Error :: Permanent ( e) => e,
197
- backoff:: Error :: Transient { err, .. } => err,
198
- }
199
- }
200
- }
201
-
202
145
#[ derive( Debug , Default ) ]
203
146
pub struct DnsConfiguration {
204
147
servers : Vec < IpAddr > ,
205
148
suffixes : Vec < String > ,
206
149
}
207
150
208
151
pub fn get_configuration ( ) -> Result < DnsConfiguration , Error > {
209
- let op = || {
210
- {
211
- let routes = get_internet_routes ( ) ?;
212
- let adapters = get_adapters ( ) ?;
213
- // Match the route interface index with an adapter index
214
- let mut grouped = routes
152
+ // List of routes to the internet
153
+ let internet_routes = get_routes ( ) ?
154
+ . into_iter ( )
155
+ . filter ( Route :: is_internet_route)
156
+ . collect :: < Vec < _ > > ( ) ;
157
+
158
+ // DNS priority is determined by interface metric
159
+ // However we also want to exclude various system adapters such as WSL
160
+ // so we will filter out any adapters that have a route to the internet
161
+ let internet_adapters = get_adapters ( ) ?
162
+ . into_iter ( )
163
+ . filter ( |adapter| {
164
+ internet_routes
215
165
. iter ( )
216
- . map ( |r| {
217
- match r. destination_prefix_ip {
218
- IpAddr :: V4 ( _) => adapters
219
- . iter ( )
220
- . find ( |a| a. ipv4_interface_index . eq ( & r. interface_index ) ) ,
221
- IpAddr :: V6 ( _) => adapters
222
- . iter ( )
223
- . find ( |a| a. ipv6_interface_index . eq ( & r. interface_index ) ) ,
224
- }
225
- . ok_or ( Error :: RouteInterfaceMismatch {
226
- interface_index : r. interface_index ,
227
- } )
228
- . map ( |a| RouteAndAdapter {
229
- route : r,
230
- adapter : a,
231
- } )
166
+ . any ( |route| match route. destination_prefix_ip {
167
+ IpAddr :: V4 ( _) => route. interface_index == adapter. ipv4_interface_index ,
168
+ IpAddr :: V6 ( _) => route. interface_index == adapter. ipv6_interface_index ,
232
169
} )
233
- . collect :: < Result < Vec < _ > , Error > > ( ) ?;
234
- // Sort by the lowest route metrics
235
- grouped. sort_by_key ( |r| r. metric_sum ( ) ) ;
236
- // Get the best routes for IPv4 and IPv6 internets respectively
237
- let best_v4 = grouped
238
- . iter ( )
239
- . find ( |g| g. route . destination_prefix_ip . is_ipv4 ( ) ) ;
240
- if let Some ( best_v4) = best_v4 {
241
- log:: info!( "Best IPv4 Route: {}" , best_v4) ;
242
- }
243
- let best_v6 = grouped
244
- . iter ( )
245
- . find ( |g| g. route . destination_prefix_ip . is_ipv6 ( ) ) ;
246
- if let Some ( best_v6) = best_v6 {
247
- log:: info!( "Best IPv6 Route: {}" , best_v6) ;
248
- }
249
- // Collect the IPv4 and then IPv6 dns configurations
250
- let mut dns_servers = Vec :: new ( ) ;
251
- let mut dns_suffixes = Vec :: new ( ) ;
252
- best_v4. iter ( ) . chain ( best_v6. iter ( ) ) . for_each ( |g| {
253
- g. adapter . dns_servers . iter ( ) . for_each ( |d| {
254
- dns_servers. push ( d. to_owned ( ) ) ;
255
- } ) ;
256
- g. adapter . dns_suffixes . iter ( ) . for_each ( |d| {
257
- dns_suffixes. push ( d. to_owned ( ) ) ;
258
- } ) ;
259
- } ) ;
260
- // Ensure servers and suffixes are unique (preserving order)
261
- Ok ( DnsConfiguration {
262
- servers : dns_servers. into_iter ( ) . unique ( ) . collect ( ) ,
263
- suffixes : dns_suffixes. into_iter ( ) . unique ( ) . collect ( ) ,
264
- } )
265
- }
266
- . map_err ( Error :: into_backoff)
267
- } ;
268
- let b = ExponentialBackoffBuilder :: new ( )
269
- . with_initial_interval ( Duration :: from_millis ( 50 ) )
270
- . with_max_elapsed_time ( Some ( Duration :: from_secs ( 1 ) ) )
271
- . build ( ) ;
272
- backoff:: retry ( b, op) . map_err ( |e| e. into ( ) )
170
+ } )
171
+ . sorted_by_key ( Adapter :: interface_metric)
172
+ . collect :: < Vec < _ > > ( ) ;
173
+
174
+ let servers = internet_adapters
175
+ . iter ( )
176
+ . flat_map ( |adapter| adapter. dns_servers . clone ( ) )
177
+ . unique ( )
178
+ . collect :: < Vec < _ > > ( ) ;
179
+ let suffixes = internet_adapters
180
+ . iter ( )
181
+ . flat_map ( |adapter| adapter. dns_suffixes . clone ( ) )
182
+ . unique ( )
183
+ . collect :: < Vec < _ > > ( ) ;
184
+
185
+ Ok ( DnsConfiguration { servers, suffixes } )
273
186
}
274
187
275
188
impl DnsConfiguration {
0 commit comments