RDP Port Forwarding Issue

Hello all! This is my first time posting here so please be gentle:)

We are running into an odd issue with port forwarding that I am going to try to describe clearly. If I leave anything out, please feel free to ask for more info.

We have many Mikrotiks all over the US deployed as gateway routers. At many of these locations we have internal resources that need accessed via RDP. For example we have a customer (we are an MSP) that has about 40 locations, each with a server. What we do is create a firewall rule that allows RDP on 3389, but only from specific source IP addresses. Something like this:

add chain=forward comment=“Allow RDP - 3389- Only From Approved List” dst-port=3389 in-interface=ether1 protocol=tcp src-address-list=“Allowed IP Addresses”

And then for good measure (at some locations, not all) we add a drop rule like this:

add chain=forward action=drop comment=“Block RDP - 3389- Not From Approved List” dst-port=3389 in-interface=ether1 protocol=tcp src-address-list=“!Allowed IP Addresses”

This works well to lock down RDP from the firewall to specific public IPs. We then keep an address list and just add to it as needed.

The problem we run into is we occasionally have users who need RDP access to internal resources from laptops in the field. When they need access their source IPs often change or are not consistent so adding to the address list is not very feasible. What we have tried to do to work around this, and what I am inquiring about today, is we have created another rule to allow inbound traffic on a different port and accept without the address list restrictions. So in order we will have something like this:

add chain=forward comment=“Allow RDP - 3391/TCP” dst-port=3391 in-interface=ether1 protocol=tcp
add chain=forward comment=“Allow RDP - 3389- Only From Approved List” dst-port=3389 in-interface=ether1 protocol=tcp src-address-list=“Allowed IP Addresses”
add chain=forward action=drop comment=“Block RDP - 3389- Not From Approved List” dst-port=3389 in-interface=ether1 protocol=tcp src-address-list=“!Allowed IP Addresses”

Then the user will try to RDP to publicIP:3391 to get to the internal resource. What we have found is that no matter what other port we use RDP is always picked up on the drop rule. We can move the 3391 rule to the top of the list but the traffic still hits the “Block RDP - 3389- Not From Approved List” rule.This is pretty clear when looking at traffic hitting the rule. On thing that is odd is that if a user specifics RDP on port 3391 and the drop rule for 3389 drops it, you can still see the traffic hit the NAT rule for 3391.

I suspect this has more to do with how RDP works in the backgroud than how the Mikrotik is handling the traffic. My guess is that RDP is passing some traffic on 3389 even if you explicitly tell it to use a different port. It is not a configuration error as I have set this up is many configurations and tested to validate what I was seeing. Even though I suspect this is an issue with how RDP handles specifying a port I was hoping to get some validation from someone much smarter than I and see if anyone else has a better solution. It makes it difficult to block RDP to our servers while allowing users to have access to other resources.

So how have we got around this so far… Good question!

What we have done is allow all RDP traffic through the firewall. Then create jump rules for the different external IP addresses. We then use one external IP for the servers and specify a source address list there. Then we have another jump rule that is wide open for users. There are a couple problems with this though. One, we have a few locations that would require a complete rebuild on the firewall/NAT to make this work. I really do not want to rebuild the NAT rules just so a user can RDP to their PC. Second, many locations only have one public IP. when that is the case it pretty much takes away the workaround. When this is the case we have had to setup a VPN for users to connect to. I know this is probably the better solution and may be the way we handle it moving forward but I would still like to get everyone’s input as this has been racking my brain for a while.

Anyways, advanced thanks to everyone! Any help will be appreciated.

If it’s really about port forwarding (dstnat from public to internal addresses), then it’s better to check access right in dstnat rule. There’s no reason to do dstnat only to stop the packet a little later.

If you do it like this:

/ip firewall nat
add action=dst-nat chain=dstnat dst-address=<public IP> dst-port=3389 protocol=tcp \
    to-addresses=<internal IP> src-address-list="Allowed IP Addresses"
add action=dst-nat chain=dstnat dst-address=<public IP> dst-port=3391 protocol=tcp \
    to-addresses=<internal IP> to-ports=3389

It will allow direct connections to 3389 only from allowed addresses and connections to 3391 from anywhere. And to actually allow it through router, you can use the magic rule:

/ip firewall filter
add action=accept chain=forward connection-nat-state=dstnat

It allows all forwarded ports (and only forwarded ports, so it’s safe to use).

Thank you for your response Sob.

Can you expand on the magic rule?

This is really very similar to how I mentioned we have been doing it. I was really hoping to get an explanation of why filtering at the firewall was not working as expected as well.

Just to verify, dstnat processes first, then filter rules correct? Could this be what the core problem is? If a packet comes in on 3391 and then is first NATed to 3389, and then hits the filter rules, it would be dropped by the 3389 rule because the destination is then 3389. Just trying to better understand what we are seeing.

That’s exactly it. Dstnat happens before forward. So when dstnat changes port to 3389, forward no longer knows about original port. You could mark connections to 3391 in prerouting and then use connection-mark matcher in forward rules, but I don’t see any good reason to complicate it that way.

Magic rule is very simple. When dstnat applies to connection, its “NAT state” reflects that. So later in forward, you can easily tell if connection was dstnatted or not. And if it was, you can let it pass, because that’s what you wanted when you added dstnat for it.

I sure do appreciate your answer. It provided clarification on something that has bugged me for a while. Thank you!

Hello guys,

So I have done what you said with dst-nat and RDP is working properly for my machine(192.168.0.3). I can connect to it from everywhere, but when I want to RDP from my machine or any other machine from my network, to VMs in Azure all 3389 port traffic is being redirected to ip address 192.168.0.3 from dst-nat. Now I have figured out how to avoid that but what would you suggest what is the best way?

I did not have the notifications setup for this forum, sorry. Did you get this squared away? Can you provide a little more clarification if not?

Hi, yes I did with adding one more rule in NAT section. I had simple rule for RDP forward into specific machine on my network, but when I try to RDP on some other machine somewhere outside of my network the packets get routed to that machine on my network.

Hi, i have a problem with RD configuration

Already I have a server with access through RD, but i want to know if i can add another one, I mean, setup another RD to other server in my organization.
PLEASE HELP

Yes you can, you just need to either use a different destination port or a different public IP address. The internal port can still be 3389. So create a NAT rule that says anything in the WAN with the destination of 3390 and have the action be dstnat to your internal IP on 3389.