Create NAT Rules for the Hyper-V NAT Virtual Switch

hyper v abstract
In this post, I will show you how to create NAT rules for virtual machines that are connected to an NAT-enabled virtual switch on a Windows Server 2016 (WS2016) or Windows 10 Hyper-V host.
 

 
Before proceeding, you should read these recent posts to understand the solution:

A NAT switch on Windows 10 or Windows Server 2016 Hyper-V [Image Credit: Aidan Finn]
A NAT Switch on Windows 10 or Windows Server 2016 Hyper-V [Image Credit: Aidan Finn]

Understanding NAT Rules

By default, there is no inbound access from the LAN to the virtual machines that are connected to an NAT-enabled virtual switch. You might find a situation, where you need to enable inbound access. For example, you might want to enable RDP access to virtual machines in an otherwise isolated lab.
A NAT rule can be created and associated with your NAT configuration. The NAT rule pushes traffic from a source address. It then moves it forward to an address on the NAT-enabled virtual switch. We can create a rule with the following settings:

  • ExternalIPAddress: This is the IP address of the host that the traffic is addressed to. This can be the IP address of a specific physical NIC or it can be 0.0.0.0/0, which would cover all addresses on the host.
  • ExternalPort: This is the port that the incoming traffic is sent to. For example, web traffic would target port 80 or RDP traffic would be destined for 3389.
  • Protocol: This is either TCP or UDP.
  • InternalIPAddress: This is the address of the virtual machine on the NAT-enabled virtual switch that you want to send the traffic to.
  • InternalPort: Here, you specify the port on the virtual machine that the traffic should be directed to.

Simple NAT Rule

Let’s say that you want to deploy a web server on an NAT-enabled virtual switch. You also want this service to be available to the LAN. The virtual machine is using 192.168.0.4 on the virtual switch and the host’s LAN is configured with a network address of 10.101.2.0/24. You can create a simple NAT rule as follows:

  • ExternalIPAddress: 0.0.0.00
  • ExternalPort: 80
  • InternalIPAddress: 192.168.0.4
  • InternalPort: 80

We will associate the new rule with a previously created NetNat (NAT configuration) on the host. We can get the name of the NetNat using Get-NetNat.

Get-NetNat to retrieve the NAT configuration name [Image Credit: Aidan Finn]
Get-NetNat to Retrieve the NAT Configuration Name [Image Credit: Aidan Finn]
We can use the Name value from the results of the above command to create a new NAT rule.

Add-NetNatStaticMapping -ExternalIPAddress "0.0.0.0/24" -ExternalPort 80 -Protocol TCP -InternalIPAddress "192.168.0.4" -InternalPort 80 -NatName NATNetwork

NAT Access

Other machines on the LAN will be able to access your virtual machines. They will do so via the NAT rules that you created using Add-NetNatStaticMapping. However, the host that is running the virtual machines cannot access the virtual machines via NAT. That is not a problem because the NAT switch is an internal switch and the host. Therefore, it has a virtual NIC connection to the virtual switch and a private IP address on the NAT network. The host can talk directly to the virtual machines without using NAT.
If you want to test your NAT rules, then you will have to log into another physical machine. You can run your tests from there.

Port Forwarding

In the previous example, a NAT rule was created for TCP 80. It will limit the virtual switch to a single web server listening on TCP 80. That is not very scalable. We can use port translation to reveal services via different external ports. For example, let’s say that we have 3 virtual machines in a NAT network. We want to enable RDP access to these machines from the LAN. We can do this using port forwarding:

  • VM1 (192.168.0.2): ExternalPort = 50002
  • VM2 (192.168.0.3): ExternalPort = 50003
  • VM3 (192.168.0.4): ExternalPort = 50004

We will create one NAT rule for each virtual machine and we will forward the external port to TCP 3389 on the virtual machine.

Add-NetNatStaticMapping -ExternalIPAddress "0.0.0.0/24" -ExternalPort 50002 -Protocol TCP -InternalIPAddress "192.168.0.2" -InternalPort 3389 -NatName NATNetwork
Add-NetNatStaticMapping -ExternalIPAddress "0.0.0.0/24" -ExternalPort 50003 -Protocol TCP -InternalIPAddress "192.168.0.3" -InternalPort 3389 -NatName NATNetwork
Add-NetNatStaticMapping -ExternalIPAddress "0.0.0.0/24" -ExternalPort 50004 -Protocol TCP -InternalIPAddress "192.168.0.4" -InternalPort 3389 -NatName NATNetwork

If I run the Remote Desktop Connection client from another physical machine, I can connect to the IP address of the host (10.101.2.41). I can also specify the NAT ExternalPort for the required virtual machine. If I want to log into VM2, then I will connect to 10.101.2.41:50002. This is shown below:

Connecting to a NAT-enabled virtual machine using remote desktop [Image Credit: Aidan Finn]
Connecting to an NAT-enabled Virtual Machine Using Remote Desktop [Image Credit: Aidan Finn]

Getting Fancy

We can learn a lot from how we do NAT. This relates to our physical network’s connection, the Internet, or how we use NAT rules in the cloud (Microsoft Azure). Let’s say you deployed a virtual appliance to act as a reverse proxy, load balancer, or firewall. Then, you configured all traffic to pass through it. All NAT rules would point to the virtual appliance. The virtual appliance would then pass traffic to the other virtual machines on the virtual switch. Now your Hyper-V networking architecture can get very interesting!