Hairpin NAT with inter VLAN traffic filtered.

I am trying to configure Hairpin NAT together with VLAN filtering but with no luck. Previousle without intervlan traffic I had “trusted” address list with all VLAN IP ranges added and it was working fine.
Now I can’t use the same approach because it will bypass intervlan traffic filtering. I’ve been trying to create a new address list and then a rule to allow the traffic from 192.168.10.2, 3, 4 IPs to domain.com:8006 and domainx.com:8007 pointing to external 217.x.x.x address (pppoe) forwarding to 192.168.20.11 and .20, but that didn’t work either. What I am doing wrong?

/interface vlan
add interface=bridge name=vlan10 vlan-id=10
add interface=bridge name=vlan20 vlan-id=20
add interface=bridge name=vlan30 vlan-id=30
add interface=bridge name=vlan40 vlan-id=40
add interface=bridge name=vlan50 vlan-id=50
add interface=bridge name=vlan60 vlan-id=60
/interface list
add comment=defconf name=WAN
add comment=defconf name=LAN
/ip pool
add name=vlan10 ranges=192.168.10.10-192.168.10.254
add name=vlan20 ranges=192.168.20.30-192.168.20.254
add name=vlan30 ranges=192.168.30.50-192.168.30.254
add name=vlan40 ranges=192.168.40.10-192.168.40.254
add name=vlan50 ranges=192.168.50.10-192.168.50.254
add name=vlan60 ranges=192.168.60.10-192.168.60.254
/ip dhcp-server
add address-pool=vlan60 authoritative=after-2sec-delay interface=vlan60 lease-time=1d name=vlan60
add address-pool=vlan50 authoritative=after-2sec-delay interface=vlan50 lease-time=1d name=vlan50
add address-pool=vlan40 authoritative=after-2sec-delay interface=vlan40 lease-time=1d name=vlan40
add address-pool=vlan30 authoritative=after-2sec-delay interface=vlan30 lease-time=1d name=vlan30
add address-pool=vlan20 authoritative=after-2sec-delay interface=vlan20 lease-time=1d name=vlan20
add address-pool=vlan10 authoritative=after-2sec-delay interface=vlan10 lease-time=1d name=vlan10
/interface bridge port
add bridge=bridge comment=defconf interface=ether2
add bridge=bridge comment=defconf interface=ether3
add bridge=bridge comment=defconf interface=ether4
add bridge=bridge comment=defconf interface=ether5
add bridge=bridge comment=defconf interface=sfp1
/ip firewall connection tracking
set udp-timeout=10s
/interface bridge vlan
add bridge=bridge tagged=ether2,ether3,ether4,ether5,sfp1,bridge vlan-ids=10,20,30,40,50,60
/interface list member
add interface=bridge list=LAN
add interface=ether1 list=WAN
/ip address
add address=172.16.0.1/24 interface=wg-server network=172.16.0.0
add address=192.168.102.2/24 interface=wireguard-client-1 network=192.168.102.0
add address=10.0.1.2/24 interface=wireguard-client-2 network=10.0.1.0
add address=10.159.50.3/24 interface=wireguard-client-3 network=10.159.50.0
add address=217.x.x.x/29 comment=public interface=vlan20 network=217.x.x.x
add address=192.168.10.1/24 interface=vlan10 network=192.168.10.0
add address=192.168.20.1/24 interface=vlan20 network=192.168.20.0
add address=192.168.30.1/24 interface=vlan30 network=192.168.30.0
add address=192.168.40.1/24 interface=vlan40 network=192.168.40.0
add address=192.168.50.1/24 interface=vlan50 network=192.168.50.0
add address=192.168.60.1/24 interface=vlan60 network=192.168.60.0
/ip dhcp-server network
add address=192.168.10.0/24 comment=vlan10 dns-server=192.168.20.15 gateway=192.168.10.1
add address=192.168.20.0/24 comment=vlan20 dns-server=192.168.20.15 gateway=192.168.20.1
add address=192.168.30.0/24 comment=vlan30 dns-server=192.168.20.15 gateway=192.168.30.1
add address=192.168.40.0/24 comment=vlan40 dns-server=192.168.40.1 gateway=192.168.40.1
add address=192.168.50.0/24 comment=vlan50 dns-server=192.168.50.1 gateway=192.168.50.1
add address=192.168.60.0/24 comment=vlan60 dns-server=192.168.60.1 gateway=192.168.60.1
/ip firewall address-list
add address=46.x.x.x list=trusted
add address=46.x.x.x list=trusted
add address=193.x.x.x list=trusted
add address=31.x.x.x list=trusted
add address=46.x.x.x list=trusted
add address=192.168.10.0/24 list=local-vlans
add address=192.168.20.0/24 list=local-vlans
add address=192.168.30.0/24 list=local-vlans
add address=192.168.40.0/24 list=local-vlans
add address=192.168.50.0/24 list=local-vlans
add address=192.168.60.0/24 list=local-vlans
add address=192.168.20.15 list=trusted-local
add address=192.168.30.13 list=trusted-local
add address=192.168.10.2 list=hairpin-access
add address=192.168.10.3 list=hairpin-access
add address=192.168.10.4 list=hairpin-access
add address=192.168.13.15 list=hairpin-access
/ip firewall filter
add action=accept chain=input comment="allow Wireguard server" dst-port=13231protocol=udp
add action=accept chain=input comment="allow Wireguard server traffic" src-address=172.16.0.0/24
add action=accept chain=input comment="allow traffic from Wireguard vpn" dst-port=8443 protocol=udp
add action=fasttrack-connection chain=forward comment=fasttrack connection-state=established,related hw-offload=yes
add action=accept chain=forward comment="accept established,related" connection-state=established,related
add action=accept chain=input comment="echo reply" protocol=icmp
add action=accept chain=input comment="accept established,related" connection-state=established,related,untracked
add action=drop chain=input comment="drop all not coming from LAN" disabled=yes in-interface-list=!LAN
add action=accept chain=forward comment="allow selected local resources to all VLANs" dst-address-list=local-vlans src-address-list=trusted-local
add action=accept chain=forward comment="allow all VLANs to selected local resources" dst-address-list=trusted-local src-address-list=local-vlans
add action=accept chain=forward comment="allow all traffic from VLAN10 to VLAN20" in-interface=vlan10 out-interface=vlan20
add action=accept chain=forward comment="allow all traffic from VLAN20 to VLAN10" in-interface=vlan20 out-interface=vlan10
add action=accept chain=forward comment="accept IN ipsec policy" ipsec-policy=in,ipsec
add action=accept chain=forward comment="accept OUT ipsec policy" ipsec-policy=out,ipsec
add action=drop chain=forward comment="drop interVLAN traffic" connection-state="" dst-address-list=local-vlans src-address-list=local-vlans
add action=drop chain=forward comment="drop invalid - forward" connection-state=invalid
add action=drop chain=forward comment="Drop all from WAN not DSTNATed" connection-nat-state=!dstnat connection-state=new in-interface=pppoe-out1
add action=drop chain=input comment="drop invalid - input" connection-state="" in-interface=pppoe-out1
/ip firewall nat
add action=masquerade chain=srcnat comment="vlan10 masquerade" out-interface=pppoe-out1 src-address=192.168.10.0/24
add action=masquerade chain=srcnat comment="vlan20 masquerade" out-interface=pppoe-out1 src-address=192.168.20.0/24
add action=masquerade chain=srcnat comment="vlan30 masquerade" out-interface=pppoe-out1 src-address=192.168.30.0/24
add action=masquerade chain=srcnat comment="vlan40 masquerade" out-interface=pppoe-out1 src-address=192.168.40.0/24
add action=masquerade chain=srcnat comment="vlan50 masquerade" out-interface=pppoe-out1 src-address=192.168.50.0/24
add action=masquerade chain=srcnat comment="vlan60 masquerade" out-interface=pppoe-out1 src-address=192.168.60.0/24
add action=dst-nat chain=dstnat comment="Forward port 65000 to 192.168.20.4" disabled=yes dst-address=217.x.x.x dst-port=65000 protocol=tcp src-address-list=trusted to-addresses=192.168.20.4 to-ports=65000
add action=masquerade chain=srcnat comment="wg-server masquerade" out-interface=pppoe-out1 src-address=172.16.0.0/24
add action=masquerade chain=srcnat comment="wireguard client 1 masquerade" out-interface=wireguard-client-1
add action=masquerade chain=srcnat comment="wireguard client 3 masquerade" out-interface=wireguard-client-3
add action=masquerade chain=srcnat comment="wireguard client 2 masquerade" out-interface=wireguard-client-2
add action=dst-nat chain=dstnat comment="Forward port 443 to 192.168.20.16" dst-address=217.x.x.x dst-port=443 protocol=tcp to-addresses=192.168.20.16 to-ports=443
add action=dst-nat chain=dstnat comment="Forward port 8006 to 192.168.20.11" dst-address=217.x.x.x dst-port=8006 protocol=tcp src-address-list=trusted to-addresses=192.168.20.11 to-ports=8006
add action=dst-nat chain=dstnat comment="Forward port 8007 to 192.168.20.20" dst-address=217.x.x.x dst-port=8007 protocol=tcp src-address-list=trusted to-addresses=192.168.20.20 to-ports=8007
add action=masquerade chain=srcnat comment="HairpinNAT - 192.168.20.0/24" dst-address=192.168.20.0/24 out-interface=vlan20 protocol=tcp src-address=192.168.20.0/24
add action=dst-nat chain=dstnat comment="HairpinNAT - 192.168.20.11 (pve)" dst-address=217.x.x.x dst-port=8006 protocol=tcp src-address-list=trusted to-addresses=192.168.20.11 to-ports=8006
add action=dst-nat chain=dstnat comment="HairpinNAT - 192.168.20.16 (Nginx)" dst-address=217.x.x.x dst-port=443 protocol=tcp to-addresses=192.168.20.16 to-ports=443
add action=dst-nat chain=dstnat comment="HairpinNAT - 192.168.20.20 (pbs)" dst-address=217.x.x.x dst-port=8007 protocol=tcp src-address-list=trusted to-addresses=192.168.20.20 to-ports=8007
/ip route
add disabled=no distance=1 dst-address=0.0.0.0/0 gateway=192.168.102.1 routing-table=1 suppress-hw-offload=yes
add disabled=no distance=1 dst-address=0.0.0.0/0 gateway=wireguard-client-1 routing-table=1 suppress-hw-offload=yes
add disabled=no distance=1 dst-address=0.0.0.0/0 gateway=wireguard-client-2 routing-table=2 suppress-hw-offload=yes
add disabled=yes distance=1 dst-address=0.0.0.0/0 gateway=10.0.1.1 routing-table=2 suppress-hw-offload=no
add disabled=no distance=1 dst-address=0.0.0.0/0 gateway=10.159.50.1 routing-table=3 suppress-hw-offload=yes
add disabled=no distance=1 dst-address=0.0.0.0/0 gateway=wireguard-client-3 routing-table=3 suppress-hw-offload=yes

/interface list member
add interface=bridge list=LAN
add interface=ether1 list=WAN

TO:
/interface list member
add interface=ether1 list=WAN
add interface=vlan10 list=LAN
add interface=vlan20 list=LAN
add interface=vlan30 list=LAN
add interface=vlan40 list=LAN
add interface=vlan50 list=LAN
add interface=vlan60 list=LAN

add action=accept chain=input comment=“allow Wireguard server” dst-port=13231protocol=udp { missing space }
T0:
add action=accept chain=input comment=“allow Wireguard server” dst-port=13231 protocol=udp


Why two handshake ports for VPN and yet four addresses for VPN? It would appear that you have four, but three are going out to third party vpn or something, so still begs the question why the second wg interface in input chain rules?

Your two rules are very confusing
you allow one address on vlan20 and one address on vlan30 to access all local vlans
then you allow all local vlans to those two addresses??

Why? if the ideas is that those two addresses need that kind of access, fine, but you should know that all the return traffic will be permitted.
You do not need to make a firewall rule in the opposite direction. The opposite rule is if traffic ORIGINATED on all local vlans to those two addresses, and my guess is that is NOT the case.

No purpose to this rule…
add action=drop chain=input comment=“drop invalid - input” connection-state=“” in-interface=pppoe-out1


This rule is due to a backwards approach… get rid of it.
add action=drop chain=forward comment=“drop interVLAN traffic” connection-state=“” dst-address-list=local-vlans src-address-list=local-vlans

Replace the above rule, and this rule
add action=drop chain=forward comment=“Drop all from WAN not DSTNATed” connection-nat-state=!dstnat connection-state=new in-interface=pppoe-out1
With the following;
add action=accept chain=forward comment=“internet traffic” in-interface-list=LAN out-interface-list=WAN
add action=accept chain=forward comment=“port forwarding” connection-nat-state=dstnat
add action=drop chain=forward comment=“drop all else”

Replace all masquerade rules with one!
add action=masquerade chain=srcnat out-interface-list=WAN


What is the point of this rule?
add action=masquerade chain=srcnat comment=“wg-server masquerade” out-interface=pppoe-out1 src-address=172.16.0.0/24

Edit: Okay so that remote users can use internet of router so they need to go out wan, another option is allowing wg-server
to be a member of LAN list.

No context, you have routes with routing table, but no defined mangles or routing rules, so its like 1/2 of an equation…doesnt make sense???
Also duplicate tables using interface name and gateway IP… why?

add action=accept chain=input comment=“allow Wireguard server” dst-port=13231protocol=udp { missing space }

copy/paste issue.

Why two handshake ports for VPN and yet four addresses for VPN? It would appear that you have four, but three are going out to third party vpn or something, so still begs the question why the second wg interface in input chain rules?

Not sure I am getting this right but I have WG server running on Mikrotik router and then three VPN site2site WG VPN links. All four togther using different address space and ports.

Your two rules are very confusing
you allow one address on vlan20 and one address on vlan30 to access all local vlans
then you allow all local vlans to those two addresses??

Why? if the ideas is that those two addresses need that kind of access, fine, but you should know that all the return traffic will be permitted.
You do not need to make a firewall rule in the opposite direction. The opposite rule is if traffic ORIGINATED on all local vlans to those two addresses, and my guess is that is NOT the case.

I allow all traffic between VLAN10 and VLAN20 on purpose and then all other VLANs to access 192.168.20.15 which is pi-hole in VLAN20 and 192.168.30.13 which is printer in VLAN30. Please see the images attached.

add action=drop chain=input comment=“drop invalid - input” connection-state=“” in-interface=pppoe-out1

Without that all Mikrotik services (api, winbox, ssh..) are open to the internet.

add action=drop chain=forward comment=“Drop all from WAN not DSTNATed” connection-nat-state=!dstnat connection-state=new in-interface=pppoe-out1

I removed that earlier, it is blocking traffic to public IPs in LAN (I have /29 from my ISP and some hosts in VLAN20 using public IP directly)

so how this:

Replace the above rule, and this rule
add action=drop chain=forward comment=“Drop all from WAN not DSTNATed” connection-nat-state=!dstnat connection-state=new in-interface=pppoe-out1
With the following;
add action=accept chain=forward comment=“internet traffic” in-interface-list=LAN out-interface-list=WAN
add action=accept chain=forward comment=“port forwarding” connection-nat-state=dstnat
add action=drop chain=forward comment=“drop all else”

is supposed to to fix Hairpin without breaking intervlan filtering

https://ibb.co/JdJHjyz
https://ibb.co/28BWg75
https://ibb.co/5GmdPqB

I allow all traffic between VLAN10 and VLAN20 on purpose and then all other VLANs to access 192.168.20.15 which is pi-hole in VLAN20 and 192.168.30.13 which is printer in VLAN30. Please see the images attached.

In this case, YOU ONLY need access from all devices to pi-hole and to printer not the other way around.
The printer and pi-hole RESPOND to incoming, they dont originate traffic to devices…
REMOVE: add action=accept chain=forward comment=“allow selected local resources to all VLANs” dst-address-list=local-vlans src-address-list=trusted-local
KEEP: add action=accept chain=forward comment=“allow all VLANs to selected local resources” dst-address-list=trusted-local src-address-list=local-vlans

Yes this is weird, but its your config, if two vlans have full access to each other its a sign that you should combine them into one vlan, but as stated you probably have some logic.
add action=accept chain=forward comment=“allow all traffic from VLAN10 to VLAN20” in-interface=vlan10 out-interface=vlan20
add action=accept chain=forward comment=“allow all traffic from VLAN20 to VLAN10” in-interface=vlan20 out-interface=vlan10

For wireguard understand, one wireguard for yourself ( remote admin to access config and subnets, and maybe a few users to access lan )
Three other wireguards connectiong to 3rd party VPN servers…
Therefore there should be
FOUR wireguard interfaces established and only one input chain rule.

These two input chain rules, the first one is needed for handshake, the second is for admin access to config, they are logical!!
add action=accept chain=input comment=“allow Wireguard server” dst-port=13231protocol=udp
add action=accept chain=input comment=“allow Wireguard server traffic” src-address=172.16.0.0/24

This is the rule that stands out to NOT BELONG!! It makes no sense to me.
add action=accept chain=input comment=“allow traffic from Wireguard vpn” dst-port=8443 protocol=udp ???

Hairpin NAT has nothing to do with vlan to vlan traffic.
Hairpin NAT is sourcenat finessing required WHEN user are in the same subnet as the SERVER and the admin wants the users to use dyndns URL, domain name aka WANIP vice LANIP.
If the server is in a different subnet then the users, then hairpin nat is not required.

If you have servers and users of server (not using LANIP to access server) in the same subnet/vlan, the only rule you need is ( assuming vlan20 )
add chain=srcnat action=masquerade dst-address=192.168.20.0/24 src-address=192.168.20.0/24

Then just focus on needed dstnat rules as per usual.

THe forward chain rules cleaned up the confusion and lack of cohesion in rules.
The same can be said for input chain which should look like this ( proper order )
/ip firewall filter
add action=accept chain=input comment=
“defconf: accept established,related,untracked” connection-state=
established,related,untracked
add action=drop chain=input comment=“defconf: drop invalid” connection-state=
invalid
add action=accept chain=input comment=“defconf: accept ICMP” protocol=icmp
add action=accept chain=input comment=
“defconf: accept to local loopback (for CAPsMAN)” dst-address=127.0.0.1
add action=accept chain=input comment=“wireguard handshake” dst-port=13231 protocol=udp
add action=accept chain=input comment=“allow Admin remote WG” in-interface=wg-server src-address=172.16.0.0/24
add action=accept chain=input comment=“allow Admin local” in-interface-list=LAN src-address-list=LocalAdmin
add action=accept chain=input comment=“allow users to services” in-interface-list=LAN dst-port=53 protocol=udp
add action=accept chain=input comment=“allow users to services” in-interface-list=LAN dst-port=53 protocol=tcp
add action=drop chain=input comment=“drop all else”

However, there are other IP addresses the admin will use aka from the trusted LAN for example and perhaps consider both wired and wifi.
So I added another rule for local admin IPs. Preferably, what I do, is make one firewall address list for all admin IPs and thus one rule.

++++++++++++++++++++++++++++++++++++++

FIX all the items on the previous posts and POST the latest config.
This time stop the nonsense of not posting everything. AKA no mangles or routing rules anywhere???

/export file=anynameyouwish ( minus router serial number, any public WANIP information, vpn keys etc. )

PS. I dont open up files from third party sites.

REMOVE: add action=accept chain=forward comment=“allow selected local resources to all VLANs” dst-address-list=local-vlans src-address-list=trusted-local
KEEP: add action=accept chain=forward comment=“allow all VLANs to selected local resources” dst-address-list=trusted-local src-address-list=local-vlans

If I remove this, then it stops working. That’s why I have both in place.

This is the rule that stands out to NOT BELONG!! It makes no sense to me.
add action=accept chain=input comment=“allow traffic from Wireguard vpn” dst-port=8443 protocol=udp

This is one of the site2site VPNs (wireguard-client-1, 192.168.102.1/2), without this I can’t ping other end which is useful for monitoring purposes.

If you have servers and users of server (not using LANIP to access server) in the same subnet/vlan, the only rule you need is ( assuming vlan20 )
add chain=srcnat action=masquerade dst-address=192.168.20.0/24 src-address=192.168.20.0/24

it didn’t make any difference. What I have are servers:
192.168.20.11:8006 and 192.168.20.20:8007 with domain x.domain.com pointing to external IP 217.x.x.x and what I need is to be able to access them using domain (external IP) while being in VLAN, for example other than 20. his can be actually limited to few IPs in VLAN10 (or the whole VLAN10) and single IP in VLAN30 192.168.30.x.

/ip firewall filter
add action=accept chain=input comment=
“defconf: accept established,related,untracked” connection-state=
established,related,untracked
add action=drop chain=input comment=“defconf: drop invalid” connection-state=
invalid
add action=accept chain=input comment=“defconf: accept ICMP” protocol=icmp
add action=accept chain=input comment=
“defconf: accept to local loopback (for CAPsMAN)” dst-address=127.0.0.1
add action=accept chain=input comment=“wireguard handshake” dst-port=13231 protocol=udp
add action=accept chain=input comment=“allow Admin remote WG” in-interface=wg-server src-address=172.16.0.0/24
add action=accept chain=input comment=“allow Admin local” in-interface-list=LAN src-address-list=LocalAdmin
add action=accept chain=input comment=“allow users to services” in-interface-list=LAN dst-port=53 protocol=udp
add action=accept chain=input comment=“allow users to services” in-interface-list=LAN dst-port=53 protocol=tcp
add action=drop chain=input comment=“drop all else”

that broke almost everything (VPNs, interVLAN filtering)

The only mangle rules I have are:

[admin@RB760iGS] > /ip/firewall/mangle/print 
Flags: X - disabled, I - invalid; D - dynamic 
 0  D ;;; special dummy rule to show fasttrack counters
      chain=prerouting action=passthrough 

 1  D ;;; special dummy rule to show fasttrack counters
      chain=forward action=passthrough 

 2  D ;;; special dummy rule to show fasttrack counters
      chain=postrouting action=passthrough

and the routing rules:

[admin@RB760iGS] > /ip/route/print 
Flags: D - DYNAMIC; I - INACTIVE, A - ACTIVE; c - CONNECT, s - STATIC, d - DHCP, v - VPN; H - HW-OFFLOADED; + - ECMP
Columns: DST-ADDRESS, GATEWAY, DISTANCE
#       DST-ADDRESS        GATEWAY                 DISTANCE
  DIdH  0.0.0.0/0          217.xxx.xxx.1                  1
  DAv   0.0.0.0/0          pppoe-out1                     1
  DAc   10.0.1.0/24        wireguard-client-2         0
  DAc   10.159.50.0/24     wireguard-client-3         0
  DAc   172.16.0.0/24      wg-server                      0
  DAc   192.168.10.0/24    vlan10                         0
  DAc   192.168.20.0/24    vlan20                         0
  DAc   192.168.30.0/24    vlan30                         0
  DAc   192.168.40.0/24    vlan40                         0
  DAc   192.168.50.0/24    vlan50                         0
  DAc   192.168.60.0/24    vlan60                         0
  DAc   192.168.102.0/24   wireguard-client-1           0
  DAc   217.xxx.xx.120/32  pppoe-out1                     0
  DAc   217.xxx.xxx.24/29  vlan20                         0      ### this is to use public IPs in LAN directly
0  As + 0.0.0.0/0          192.168.102.1                  1
1  As + 0.0.0.0/0          wireguard-client-1           1
2  As + 0.0.0.0/0          10.159.50.1                    1
3  As + 0.0.0.0/0          wireguard-client-3         1
4  As + 0.0.0.0/0          wireguard-client-2         1
5  As + 0.0.0.0/0          10.0.1.1                       1

So the simplest solution so far is to add selected local IPs 192.168.10.2,3,4 to trusted address list… no need for creating Hairpin rules at all in this case. My other last resort solution was placing it behind Nginx reverse proxy and limit IP can access it in vhost configuration. Anyway thanks for your help and please let me know if you have better idea I could test.

If any of the users are in the same subnet as a server, that subnet will need a hairpin nat rule.