Hyper-V internal network switch

I have two Hyper-V VMs on each of my Windows 10 machines, OpenBSD and Apline Linux. I've set the Hyper-V Default Switch to be Internal; it's used by both the VMs. The internal switch offers DHCP addresses and a forwarding DNS (with the domain name mshome.net).

The odd thing about the internal switch is that every time the host is rebooted, the address of the internal switch changes, switching between 172.0.0.0 and 192.168.0.0 addresses. This is not a problem when ssh'ing into the VMs using Powershell or CMD, as they use the internal switch DNS (it appears). However, WSL does not use the Hyper-V internal switch IP in name resolution, but whatever is defined for the real network interface. Makes sense, I suppose.

This was not an issue until I discovered that when ssh'ing from Powershell or CMD to either of the VMs, CTRL-SPACE was not sent. Why does this matter? Only if you use emacs.

When ssh'ing to the VMs from WSL, CTRL-SPACE is sent. However, the mshome.net names are not recognised, so you have to type in the VM DHCP address (different every time), or modify /etc/resolv.conf to specify the internal switch IP as the nameserver.

My clunky solution was to write a shell script in WSL that would determine the IP address allocated to the Hyper-V switch and update /etc/resolv.conf accordingly. This script is invoked by a BAT file when I login to the host. Seems to work.

hvswitch.sh

This is the WSL shell script:

  !/bin/sh
  # attempt to detect Hyper-V internal switch IP and use as WSL nameserver
  # to allow access to Hyper-V VMs
  HVSWITCH=$(arp.exe -a  | grep Interface | grep -v "192\.168\.0\." | cut -d' ' -f 2)
  sudo sed -i -e "s/nameserver .*/nameserver $HVSWITCH/" /etc/resolv.conf

rc-local.bat

The above script is then invoked through a BAT file, called by the Windows 10 Task Scheduler on login:

  wsl /mnt/c/Users/mark/Documents/bin/hvswitch.sh

Update: 2020-06-23

Since I upgraded to Windows 10 2004, it appears that WSL is re-writing the /etc/resolv.conf file every time bash is instantiated. Munging the file once at logon is no longer sufficient. Instead, as advised by the comments in the /etc/resolv.conf file, I've created an /etc/wsl.conf file with the following contents:

  [network]
  generateResolvConf = false

As the option name suggests, this stops WSL re-generating the /etc/resolv.conf file automatically.

Update: 2022-03-30

I've moved to WSL2. This does use the Hyper-V switch, an instance called WSL. I found I could use the WSL-generated /etc/resolv.conf and no longer needed the hvswitch.sh script. However, one thing missing from the WSL-generated file were the local search domains. I added a test to .bash_profile to add this line if required:

  if ! grep "search" /etc/resolv.conf; then
     sudo bash -c "echo search hydrus.org.uk mshome.net >> /etc/resolv.conf"
  fi

There is one additional step to take if you need to ssh to a 'real' Hyper-V VM. Forwarding must be turned-on otherwise VMs are inaccessible. Run these commands in an Administrator PowerShell window:

  Set-NetIPInterface -ifAlias "vEthernet (WSL)" -ForwardingEnabled
  Set-NetIPInterface -ifAlias "vEthernet (Default Switch)" -ForwardingEnabled

/etc/wsl.conf now looks like:

  [automount]
  enabled = true
  options = "metadata,umask=077,fmask=11,case=off"

  [network]
  generateResolvConf = true