Skip to content

Commit 1184276

Browse files
author
Jacob Halsey
committed
Write docs, fix config options
1 parent a06d156 commit 1184276

File tree

5 files changed

+118
-57
lines changed

5 files changed

+118
-57
lines changed

README.md

Lines changed: 25 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -5,69 +5,42 @@
55
An agent that automatically patches your WSL2 DNS configuration when using Cisco AnyConnect (or similar VPNs that block
66
split-tunneling).
77

8-
## Prerequisite #1 - WSL2 Internet Access
8+
## How it works
99

10-
First you need to ensure your WSL2 distributions can access the internet. Before connecting to the VPN your routes for
11-
WSL2 will look something like (using the `Get-NetAdapter` command in powershell):
10+
1. The agent detects when you connect/disconnect from a VPN.
11+
2. The agent finds the highest priority DNS servers being used by Windows.
12+
3. The agent detects your WSL2 distributions, for each distribution it ensures that `generateResolvConf` is disabled,
13+
and then writes the DNS servers to `/etc/resolv.conf`.
1214

13-
```
14-
ifIndex DestinationPrefix NextHop RouteMetric ifMetric PolicyStore
15-
------- ----------------- ------- ----------- -------- -----------
16-
26 172.31.79.255/32 0.0.0.0 256 5000 ActiveStore
17-
26 172.31.64.1/32 0.0.0.0 256 5000 ActiveStore
18-
26 172.31.64.0/20 0.0.0.0 256 5000 ActiveStore
19-
```
20-
21-
But when you connect to the VPN, AnyConnect adds a non-functional route with a lower metric:
22-
23-
```
24-
26 172.31.79.255/32 0.0.0.0 256 5000 ActiveStore
25-
26 172.31.64.1/32 0.0.0.0 256 5000 ActiveStore
26-
56 172.31.64.0/20 10.17.104.1 1 1 ActiveStore
27-
26 172.31.64.0/20 0.0.0.0 256 5000 ActiveStore
28-
```
15+
## Usage
2916

30-
Unfortunately we cannot remove or modify this route because it will be automatically
31-
[replaced by AnyConnect](https://community.cisco.com/t5/vpn/enforcing-the-split-tunnel-only-access/m-p/4390557/highlight/true#M278089).
32-
However, Windows determines the best route by the lowest sum of interface metric + route metric. What we can do is
33-
increase the AnyConnect interface metric:
17+
**Ensure you have first fixed the route table for WSL2, and not broken the Windows DNS server priority in the process**.
18+
See the [guide](./docs/ROUTING.md) for how to do this.
3419

35-
```powershell
36-
Get-NetAdapter | Where-Object {$_.InterfaceDescription -Match "Cisco AnyConnect"} | Set-NetIPInterface -InterfaceMetric 6000
37-
```
20+
Simply download `wsl2-dns-agent.exe` from the [releases page](https://github.com/jacob-pro/wsl2-dns-agent/releases/latest)
3821

39-
Now the route table will allow WSL2's NAT connection to the Internet, because 5256 is a lower metric than 6001:
22+
Save it to your startup folder (`%APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup`).
4023

41-
```
42-
26 172.31.79.255/32 0.0.0.0 256 5000 ActiveStore
43-
26 172.31.64.1/32 0.0.0.0 256 5000 ActiveStore
44-
56 172.31.64.0/20 10.17.104.1 1 6000 ActiveStore
45-
26 172.31.64.0/20 0.0.0.0 256 5000 ActiveStore
46-
```
24+
Launch the application.
4725

48-
(Unfortunately we still cannot connect from Windows to WSL2 via its IP address because AnyConnect blocks this at the
49-
firewall level using Windows Filtering Platform)
26+
## Advanced options
5027

51-
## Prerequisite #2 - Working Windows DNS
28+
For advanced use cases you can edit the config file in `%APPDATA%\WSL2 DNS Agent\config.toml`
5229

53-
The above fix then leads to a problem for the Windows host, when we look at the routes to the internet the AnyConnect
54-
adapter (56) now has a higher metric than Wi-Fi (17) and Ethernet (13):
30+
Example config:
5531

5632
```
57-
56 0.0.0.0/0 10.17.104.1 1 6000 ActiveStore
58-
17 0.0.0.0/0 10.2.9.254 0 50 ActiveStore
59-
13 0.0.0.0/0 10.2.9.254 0 25 ActiveStore
60-
```
61-
62-
This will cause Windows to attempt to connect to the now inaccessible DNS servers on Ethernet and Wi-Fi first, causing
63-
up to a 10-second delay in DNS resolution. The solution is to manually update the network interfaces to have a higher
64-
metric than the AnyConnect interface.
33+
show_notifications = false
6534
66-
Set the Ethernet and Wi-Fi metrics to 6025 and 6050 to ensure they have lower priority than the AnyConnect route (6001)
67-
(Control Panel -> Network and Sharing Center -> Change adapter settings -> Ethernet Properties -> Internet Protocol Version 4 -> Advanced)
35+
# Default options for distributions
36+
[defaults]
37+
apply_dns = true
38+
patch_wsl_conf = true
39+
# If the distribution was previously Stopped, then shutdown once the DNS update is complete
40+
# Note: This option is usually not needed on Windows 11 (because vmIdleTimeout will do it for you)
41+
shutdown = false
6842
69-
```
70-
56 0.0.0.0/0 10.17.104.1 1 6000 ActiveStore
71-
17 0.0.0.0/0 10.2.9.254 0 6050 ActiveStore
72-
13 0.0.0.0/0 10.2.9.254 0 6025 ActiveStore
43+
# Set options for a specific distribution
44+
[distributions.Ubuntu]
45+
apply_dns = false
7346
```

docs/ROUTING.md

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
# Fixing Route Table for WSL2
2+
3+
## Step #1 - WSL2 Internet Access
4+
5+
First you need to ensure your WSL2 distributions can access the internet. Before connecting to the VPN your routes for
6+
WSL2 will look something like (using the `Get-NetAdapter` command in powershell):
7+
8+
```
9+
ifIndex DestinationPrefix NextHop RouteMetric ifMetric PolicyStore
10+
------- ----------------- ------- ----------- -------- -----------
11+
26 172.31.79.255/32 0.0.0.0 256 5000 ActiveStore
12+
26 172.31.64.1/32 0.0.0.0 256 5000 ActiveStore
13+
26 172.31.64.0/20 0.0.0.0 256 5000 ActiveStore
14+
```
15+
16+
But when you connect to the VPN, AnyConnect adds a non-functional route with a lower metric:
17+
18+
```
19+
26 172.31.79.255/32 0.0.0.0 256 5000 ActiveStore
20+
26 172.31.64.1/32 0.0.0.0 256 5000 ActiveStore
21+
56 172.31.64.0/20 10.17.104.1 1 1 ActiveStore
22+
26 172.31.64.0/20 0.0.0.0 256 5000 ActiveStore
23+
```
24+
25+
Unfortunately we cannot remove or modify this route because it will be automatically
26+
[replaced by AnyConnect](https://community.cisco.com/t5/vpn/enforcing-the-split-tunnel-only-access/m-p/4390557/highlight/true#M278089).
27+
However, Windows determines the best route by the lowest sum of interface metric + route metric. What we can do is
28+
increase the AnyConnect interface metric:
29+
30+
```powershell
31+
Get-NetAdapter | Where-Object {$_.InterfaceDescription -Match "Cisco AnyConnect"} | Set-NetIPInterface -InterfaceMetric 6000
32+
```
33+
34+
Now the route table will allow WSL2's NAT connection to the Internet, because 5256 is a lower metric than 6001:
35+
36+
```
37+
26 172.31.79.255/32 0.0.0.0 256 5000 ActiveStore
38+
26 172.31.64.1/32 0.0.0.0 256 5000 ActiveStore
39+
56 172.31.64.0/20 10.17.104.1 1 6000 ActiveStore
40+
26 172.31.64.0/20 0.0.0.0 256 5000 ActiveStore
41+
```
42+
43+
(Unfortunately we still cannot connect from Windows to WSL2 via its IP address because AnyConnect blocks this at the
44+
firewall level using Windows Filtering Platform)
45+
46+
## Step #2 - Automation
47+
48+
The AnyConnect metric will unfortunately be reset every time the VPN is started, so we need to automate this fix
49+
with task scheduler. Save the above [powershell command](./setCiscoVpnMetric.ps1?raw=true) as `setCiscoVpnMetric.ps1`
50+
51+
Open task scheduler and click "Create task":
52+
53+
- Name: "Update AnyConnect Adapter Interface Metric for WSL2"
54+
- Security options: Check "Run with highest privileges"
55+
- Triggers:
56+
- On an Event, Log: Cisco AnyConnect Secure Mobility Client, Source: acvpnagent, Event ID: 2039
57+
- On an Event, Log: Cisco AnyConnect Secure Mobility Client, Source: acvpnagent, Event ID: 2041
58+
- Actions: Start a program, Program/script: `powershell.exe`,
59+
Add arguments: `-WindowStyle Hidden -NonInteractive -ExecutionPolicy Bypass -File %HOMEPATH%\Documents\setCiscoVpnMetric.ps1`
60+
- Conditions: Uncheck "Start the task only if the computer is on AC power"
61+
62+
## Step #3 - Working Windows DNS
63+
64+
The above fix then leads to a problem for the Windows host, when we look at the routes to the internet the AnyConnect
65+
adapter (56) now has a higher metric than Wi-Fi (17) and Ethernet (13):
66+
67+
```
68+
56 0.0.0.0/0 10.17.104.1 1 6000 ActiveStore
69+
17 0.0.0.0/0 10.2.9.254 0 50 ActiveStore
70+
13 0.0.0.0/0 10.2.9.254 0 25 ActiveStore
71+
```
72+
73+
This will cause Windows to attempt to connect to the now inaccessible DNS servers on Ethernet and Wi-Fi first, causing
74+
up to a 10-second delay in DNS resolution. The solution is to manually update the network interfaces to have a higher
75+
metric than the AnyConnect interface.
76+
77+
Set the Ethernet and Wi-Fi metrics to 6025 and 6050 to ensure they have lower priority than the AnyConnect route (6001)
78+
(Control Panel -> Network and Sharing Center -> Change adapter settings -> Ethernet Properties -> Internet Protocol Version 4 -> Advanced)
79+
80+
```
81+
56 0.0.0.0/0 10.17.104.1 1 6000 ActiveStore
82+
17 0.0.0.0/0 10.2.9.254 0 6050 ActiveStore
83+
13 0.0.0.0/0 10.2.9.254 0 6025 ActiveStore
84+
```

docs/setCiscoVpnMetric.ps1

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Get-NetAdapter | Where-Object {$_.InterfaceDescription -Match "Cisco AnyConnect"} | Set-NetIPInterface -InterfaceMetric 6000

src/config.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ pub struct DistributionSetting {
2525
/// If the distribution was previously Stopped, then shutdown once the DNS update is complete
2626
/// Note: This option is probably not needed on Windows 11 (because of vmIdleTimeout)
2727
#[serde(default)]
28-
pub restore_state: bool,
28+
pub shutdown: bool,
2929
/// Automatically patch /etc/wsl.conf to disable generateResolvConf
3030
/// Note this will trigger a restart of the distribution
3131
#[serde(default = "r#true")]

src/runner.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,12 @@ fn update_dns(config: &Config) -> Result<(), Error> {
7474
.collect::<Vec<_>>();
7575
log::info!("Found {} WSL2 distributions", wsl.len());
7676
for d in wsl {
77-
log::info!("Updating DNS for {}", d.name);
78-
if let Err(e) = update_distribution(&d, config.get_distribution_setting(&d.name), &resolv) {
79-
log::error!("Failed to update DNS for {}, due to: {}", d.name, e);
77+
let dist_config = config.get_distribution_setting(&d.name);
78+
if dist_config.apply_dns {
79+
log::info!("Updating DNS for {}", d.name);
80+
if let Err(e) = update_distribution(&d, dist_config, &resolv) {
81+
log::error!("Failed to update DNS for {}, due to: {}", d.name, e);
82+
}
8083
}
8184
}
8285
Ok(())
@@ -119,7 +122,7 @@ fn update_distribution(
119122
distribution.set_read_only(RESOLV_CONF, true).ok();
120123

121124
// Optionally shutdown the WSL2 distribution once finished
122-
if config.restore_state && distribution.was_stopped() {
125+
if config.shutdown && distribution.was_stopped() {
123126
log::info!("Terminating {}", distribution.name);
124127
distribution.terminate()?;
125128
}

0 commit comments

Comments
 (0)