@@ -61,6 +61,10 @@ pub enum Error {
61
61
/// There was an error listening for events from the Wireguard tunnel
62
62
#[ error( display = "Failed while listening for events from the Wireguard tunnel" ) ]
63
63
WireguardTunnelMonitoringError ( #[ error( source) ] wireguard:: Error ) ,
64
+
65
+ /// Could not detect and assign the correct mtu
66
+ #[ error( display = "Could not detect and assign a correct MTU for the Wireguard tunnel" ) ]
67
+ AssignMtuError ,
64
68
}
65
69
66
70
/// Possible events from the VPN tunnel and the child process managing it.
@@ -101,7 +105,7 @@ impl TunnelMonitor {
101
105
#[ cfg_attr( any( target_os = "android" , windows) , allow( unused_variables) ) ]
102
106
pub fn start < L > (
103
107
runtime : tokio:: runtime:: Handle ,
104
- tunnel_parameters : & TunnelParameters ,
108
+ tunnel_parameters : & mut TunnelParameters ,
105
109
log_dir : & Option < PathBuf > ,
106
110
resource_dir : & Path ,
107
111
on_event : L ,
@@ -134,9 +138,9 @@ impl TunnelMonitor {
134
138
#[ cfg( target_os = "android" ) ]
135
139
TunnelParameters :: OpenVpn ( _) => Err ( Error :: UnsupportedPlatform ) ,
136
140
137
- TunnelParameters :: Wireguard ( config) => Self :: start_wireguard_tunnel (
141
+ TunnelParameters :: Wireguard ( ref mut config) => Self :: start_wireguard_tunnel (
138
142
runtime,
139
- & config,
143
+ config,
140
144
log_file,
141
145
resource_dir,
142
146
on_event,
@@ -172,7 +176,7 @@ impl TunnelMonitor {
172
176
173
177
fn start_wireguard_tunnel < L > (
174
178
runtime : tokio:: runtime:: Handle ,
175
- params : & wireguard_types:: TunnelParameters ,
179
+ params : & mut wireguard_types:: TunnelParameters ,
176
180
log : Option < PathBuf > ,
177
181
resource_dir : & Path ,
178
182
on_event : L ,
@@ -188,11 +192,13 @@ impl TunnelMonitor {
188
192
+ Clone
189
193
+ ' static ,
190
194
{
191
- let config = wireguard:: config:: Config :: from_parameters ( & params) ?;
195
+ #[ cfg( target_os = "linux" ) ]
196
+ runtime. block_on ( Self :: assign_mtu ( & route_manager, params) ) ;
197
+ let config = wireguard:: config:: Config :: from_parameters ( params) ?;
192
198
let monitor = wireguard:: WireguardMonitor :: start (
193
199
runtime,
194
200
config,
195
- log. as_ref ( ) . map ( |p| p . as_path ( ) ) ,
201
+ log. as_deref ( ) ,
196
202
resource_dir,
197
203
on_event,
198
204
tun_provider,
@@ -205,6 +211,41 @@ impl TunnelMonitor {
205
211
} )
206
212
}
207
213
214
+ #[ cfg( target_os = "linux" ) ]
215
+ fn set_mtu ( params : & mut wireguard_types:: TunnelParameters , mtu : u16 ) {
216
+ const WIREGUARD_HEADER_SIZE : u16 = 80 ;
217
+ // The largest tunnel MTU that we allow. Standard MTU - Wireguard header
218
+ const MAX_TUNNEL_MTU : u16 = 1420 ;
219
+ // The minimum allowed MTU size for our tunnel in IPv6 is 1280
220
+ const MIN_IPV6_MTU : u16 = 1280 ;
221
+ const MIN_IPV4_MTU : u16 = 576 ;
222
+ let min_mtu = match params. generic_options . enable_ipv6 {
223
+ true => MIN_IPV6_MTU ,
224
+ false => MIN_IPV4_MTU ,
225
+ } ;
226
+ let mtu = std:: cmp:: max (
227
+ mtu. checked_sub ( WIREGUARD_HEADER_SIZE ) . unwrap_or ( min_mtu) ,
228
+ min_mtu,
229
+ ) ;
230
+ let upstream_mtu = std:: cmp:: min ( MAX_TUNNEL_MTU , mtu) ;
231
+ params. options . mtu = Some ( upstream_mtu) ;
232
+ }
233
+
234
+ #[ cfg( target_os = "linux" ) ]
235
+ async fn assign_mtu (
236
+ route_manager : & RouteManagerHandle ,
237
+ params : & mut wireguard_types:: TunnelParameters ,
238
+ ) {
239
+ // It is fine to leave the params untouched if getting the mtu for the route fails. In that
240
+ // case we will do our regular default.
241
+ if let Ok ( mtu) = route_manager
242
+ . get_mtu_for_route ( params. connection . peer . endpoint . ip ( ) )
243
+ . await
244
+ {
245
+ Self :: set_mtu ( params, mtu) ;
246
+ }
247
+ }
248
+
208
249
#[ cfg( not( target_os = "android" ) ) ]
209
250
async fn start_openvpn_tunnel < L > (
210
251
config : & openvpn_types:: TunnelParameters ,
0 commit comments