Skip to content

Commit

Permalink
fix(wsl-pro-service): Find host address when NAT + DNS tunneling ON (#…
Browse files Browse the repository at this point in the history
…777)

WSL version 2.2.1 (pre-release) turns DNS tunneling ON by default
(again). With DNS tunneling activated, the Windows host IP no longer
matches the nameserver IP found in /etc/resolv.conf but still matches
the default gateway. When that was the case the nameserver IP would
contain a loopback address, but since that version it contains an IP
address of type 10.0.0.0/8 . Attempting to connect to such address
always fails. If that behavior remains, we should change the
wsl-pro-service IP selection to rely on the default gateway IP address
for all cases when networking mode is not “mirrored”, for which case it
must remain at 127.0.0.1 .
That’s of now the preferred method to find the host IP address as
documented in
https://learn.microsoft.com/en-us/windows/wsl/networking#accessing-windows-networking-apps-from-linux-host-ip

The gist is: we no longer need to read `/etc/resolv.conf`.

---
UDENG-2761
  • Loading branch information
CarlosNihelton authored May 29, 2024
2 parents cee0d8d + ac9a54b commit 4cf923d
Show file tree
Hide file tree
Showing 8 changed files with 9 additions and 106 deletions.
10 changes: 3 additions & 7 deletions docs/howto/set-up-up4w.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,8 @@ Sure:
wslinfo --networking-mode
```
- If it says `mirrored`, the relevant IP is `127.0.0.1`. Take note of this address.
- Otherwise, open file `/etc/resolv.conf` in the WSL instance named _Ubuntu-22.04_. Find the line starting with `nameserver` followed by an IP address.
- If the IP address does not start with `127`, take note of this address.
- Otherwise, run the command `ip route | grep ^default` and take note of the IP address that is printed.
3. Set up a Landscape Beta server:
- Otherwise, run the command `ip route | grep ^default` and take note of the IP address that is printed.
3. Set up a Landscape Beta server:
1. Start a shell in your _Ubuntu-22.04_ distro.
2. Install the Landscape (beta) following the steps in the Landscape Quickstart deployment with the following considerations:
- Make sure you install the beta version.
Expand Down Expand Up @@ -185,9 +183,7 @@ On your Windows host, in the Microsoft Store, search for the `Ubuntu-Preview` or
<!-- wslinfo --networking-mode -->
<!-- ``` -->
<!-- - If it says `mirrored`, the relevant IP is `127.0.0.1`. Take note of this address. -->
<!-- - Otherwise, open file `/etc/resolv.conf` in the WSL instance named _Ubuntu-22.04_. Find the line starting with `nameserver` followed by an IP address. -->
<!-- - If the IP address does not start with `127`, take note of this address. -->
<!-- - Otherwise, run the command `ip route | grep ^default` and take note of the IP address that is printed. -->
<!-- - Otherwise, run the command `ip route | grep ^default` and take note of the IP address that is printed. -->
<!-- 3. Set up a Landscape Beta server. -->
<!-- 1. Start a shell in your _Ubuntu-22.04_ distro. -->
<!-- 2. Install the Landscape (beta) following the steps in the Landscape Quickstart deployment with the following considerations: -->
Expand Down
63 changes: 0 additions & 63 deletions wsl-pro-service/internal/system/networking.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"bufio"
"context"
"encoding/binary"
"errors"
"fmt"
"net"
"os"
Expand All @@ -27,15 +26,6 @@ func (s *System) WindowsHostAddress(ctx context.Context) (ip net.IP, err error)
return net.IPv4(127, 0, 0, 1), nil
}

nameserver, err := s.nameServer()
if err != nil {
return nil, fmt.Errorf("could not find nameserver: %v", err)
}

if !nameserver.IsLoopback() {
return nameserver, nil
}

return s.defaultGateway()
}

Expand All @@ -50,59 +40,6 @@ func (s *System) networkingMode(ctx context.Context) (string, error) {
return strings.TrimSpace(string(out)), nil
}

// nameServer parses /etc/resolv.conf to get the IP address of the nameserver.
func (s *System) nameServer() (ip net.IP, err error) {
/*
We parse the IP address of the nameserver from /etc/resolv.conf. Here is an example
of what this file may look like:
# This file was automatically generated by WSL. To stop automatic generation of this file, add the following entry to /etc/wsl.conf:
# [network]
# generateResolvConf = false
nameserver 172.22.16.1
*/
const fileName = "/etc/resolv.conf"

r, err := os.Open(s.Path(fileName))
if err != nil {
// Error mesage already says could not open <filename>
return nil, err
}
defer r.Close()

var address string
var line int

sc := bufio.NewScanner(r)
for sc.Scan() {
line++

suffix, found := strings.CutPrefix(sc.Text(), "nameserver")
if !found {
continue
}
address = strings.TrimSpace(suffix)
break
}

defer decorate.OnError(&err, "could not parse %s", fileName)

if err := sc.Err(); err != nil {
return nil, fmt.Errorf("line %d: %v", line, err)
}

if address == "" {
return nil, errors.New("no line matches 'nameserver <IP>'")
}

ip = net.ParseIP(address)
if ip == nil {
return nil, fmt.Errorf("line %d: could not parse address %q", line, address)
}

return ip, nil
}

// defaultGateway returns the default gateway of the machine.
func (s *System) defaultGateway() (ip net.IP, err error) {
/*
Expand Down
24 changes: 6 additions & 18 deletions wsl-pro-service/internal/system/system_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -468,7 +468,6 @@ func TestWindowsHostAddress(t *testing.T) {
fileNotExist
fileBroken
fileIPbroken
fileIPisLoopback
)

// copyFile is a helper that copies the appropriate version of a fixture to the desired destination.
Expand All @@ -487,8 +486,6 @@ func TestWindowsHostAddress(t *testing.T) {
suffix = ".bad"
case fileIPbroken:
suffix = ".bad-ip"
case fileIPisLoopback:
suffix = ".loopback"
}

from = from + suffix
Expand All @@ -501,36 +498,28 @@ func TestWindowsHostAddress(t *testing.T) {
// These are the addresses hard-coded on the fixtures labelled as "good"
const (
localhost = "127.0.0.1"
nameserver = "172.22.16.1"
degaultGway = "172.25.32.1"
defaultGway = "172.25.32.1"
)

testCases := map[string]struct {
networkNotNAT bool
breakWslInfo bool

etcResolv fileState
procNetRoute fileState

want string
wantErr bool
}{
"Success without NAT": {networkNotNAT: true, want: localhost},
"Success with NAT, nameserver is not loopback": {want: nameserver},
"Success with NAT, nameserver is loopback": {etcResolv: fileIPisLoopback, want: degaultGway},
"Without NAT": {networkNotNAT: true, want: localhost},
"With NAT": {want: defaultGway},

// WSL info errors
"Error when wslinfo returns an error": {breakWslInfo: true, wantErr: true},

// NAT errors with broken /etc/resolv.conf
"Error with NAT when /etc/resolv.conf does not exist": {etcResolv: fileNotExist, wantErr: true},
"Error with NAT when /etc/resolv.conf is ill-formed": {etcResolv: fileBroken, wantErr: true},
"Error with NAT when /etc/resolv.conf has an ill-formed IP": {etcResolv: fileIPbroken, wantErr: true},

// NAT errors with loopback nameserver and broken /proc/net/route
"Error with NAT when /proc/net/route does not exist": {etcResolv: fileIPisLoopback, procNetRoute: fileNotExist, wantErr: true},
"Error with NAT when /proc/net/route is ill-formed": {etcResolv: fileIPisLoopback, procNetRoute: fileBroken, wantErr: true},
"Error with NAT when /proc/net/route has an ill-formed IP": {etcResolv: fileIPisLoopback, procNetRoute: fileIPbroken, wantErr: true},
"Error with NAT when /proc/net/route does not exist": {procNetRoute: fileNotExist, wantErr: true},
"Error with NAT when /proc/net/route is ill-formed": {procNetRoute: fileBroken, wantErr: true},
"Error with NAT when /proc/net/route has an ill-formed IP": {procNetRoute: fileIPbroken, wantErr: true},
}

for name, tc := range testCases {
Expand All @@ -547,7 +536,6 @@ func TestWindowsHostAddress(t *testing.T) {
mock.SetControlArg(testutils.WslInfoIsNAT)
}

copyFile(t, tc.etcResolv, filepath.Join(commontestutils.TestFamilyPath(t), "etc-resolv.conf"), mock.Path("/etc/resolv.conf"))
copyFile(t, tc.procNetRoute, filepath.Join(commontestutils.TestFamilyPath(t), "proc-net-route"), mock.Path("/proc/net/route"))

got, err := sys.WindowsHostAddress(ctx)
Expand Down

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

6 changes: 0 additions & 6 deletions wsl-pro-service/internal/testutils/mock_executables.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,6 @@ var (
//go:embed filesystem_defaults/os-release
defaultOsReleaseContents []byte

//go:embed filesystem_defaults/resolv.conf
defaultResolvConfContents []byte

//go:embed filesystem_defaults/proc.mounts
defaultProcMountsContents []byte

Expand Down Expand Up @@ -655,9 +652,6 @@ func mockFilesystemRoot(t *testing.T) (rootDir string) {
err := os.MkdirAll(filepath.Join(rootDir, "etc"), 0750)
require.NoError(t, err, "Setup: could not create mock /etc/")

err = os.WriteFile(filepath.Join(rootDir, "etc/resolv.conf"), defaultResolvConfContents, 0600)
require.NoError(t, err, "Setup: could not write mock /etc/resolv.conf")

err = os.WriteFile(filepath.Join(rootDir, "etc/os-release"), defaultOsReleaseContents, 0600)
require.NoError(t, err, "Setup: could not write mock /etc/os-release")

Expand Down

0 comments on commit 4cf923d

Please sign in to comment.