Why /interface/vlan interface responds to IP address from bridge or different VLAN interface

I am trying to setup guest access point fully isolated from LAN. It is connected via switch to router, and I used VLAN ID 36 for the traffic from guest SSID to main router, the network address is 192.168.36.0/24 for L3/IP communication.

By full isolation I mean:

  • access allowed only to WAN (NATed),
  • no management access to router,
  • no network discovery or scanning access router (do not reply on non-VLAN networks),
  • no L2 access to anything else than VLAN36,
  • no L3 access to anything besides WAN and own 192.168.36.0/24 network.

What I don’t understand is, why router replies on dst-address=192.168.88.1 for packets received on interface=guest-vlan-36.

I know I’ve got firewall rule configured to accept incoming ICMP requests, and I want router to be ping-able on each interface (in own VLAN) to check connectivity stability - response time to router.

However, guest-vlan-36 interface doesn’t have 192.168.88.1 associated with it, but 192.168.36.1. It shouldn’t reply to that IP address via this interface. The same is true, if I try ping 192.168.31.1, which is address of guest-vlan-31 interface.

If I disable the final drop rule on input chain, the VLAN ID 36 can even access www router management interface on any of those IP addresses.

Packet sniff on access point:

 0 time=1.431 num=1 direction=rx src-mac=76:C1:DB:CF:E8:8C dst-mac=78:9A:18:13:2B:05 vlan=36 interface=guest-36-wlan1 src-address=192.168.36.2 dst-address=192.168.88.1 
   protocol=ip ip-protocol=icmp size=102 cpu=2 ip-packet-size=84 ip-header-size=20 dscp=0 identification=3597 fragment-offset=0 ttl=64 

 1 time=1.431 num=2 direction=tx src-mac=76:C1:DB:CF:E8:8C dst-mac=78:9A:18:13:2B:05 vlan=36 interface=ether1 src-address=192.168.36.2 dst-address=192.168.88.1 
   protocol=ip ip-protocol=icmp size=102 cpu=2 ip-packet-size=84 ip-header-size=20 dscp=0 identification=3597 fragment-offset=0 ttl=64 

 2 time=1.431 num=3 direction=rx src-mac=78:9A:18:13:2B:05 dst-mac=76:C1:DB:CF:E8:8C vlan=36 interface=ether1 src-address=192.168.88.1 dst-address=192.168.36.2 
   protocol=ip ip-protocol=icmp size=102 cpu=3 ip-packet-size=84 ip-header-size=20 dscp=0 identification=2984 fragment-offset=0 ttl=64 

 3 time=1.431 num=4 direction=tx src-mac=78:9A:18:13:2B:05 dst-mac=76:C1:DB:CF:E8:8C vlan=36 interface=guest-36-wlan1 src-address=192.168.88.1 dst-address=192.168.36.2 
   protocol=ip ip-protocol=icmp size=102 cpu=3 ip-packet-size=84 ip-header-size=20 dscp=0 identification=2984 fragment-offset=0 ttl=64

Packet sniff on router:

 0 time=3.554 num=1 direction=rx src-mac=76:C1:DB:CF:E8:8C dst-mac=78:9A:18:13:2B:05 vlan=36 interface=ether2 src-address=192.168.36.2 dst-address=192.168.88.1 
   protocol=ip ip-protocol=icmp size=102 cpu=0 ip-packet-size=84 ip-header-size=20 dscp=0 identification=3597 fragment-offset=0 ttl=64 

 1 time=3.554 num=2 direction=rx src-mac=76:C1:DB:CF:E8:8C dst-mac=78:9A:18:13:2B:05 vlan=36 interface=bridge src-address=192.168.36.2 dst-address=192.168.88.1 
   protocol=ip ip-protocol=icmp size=102 cpu=0 ip-packet-size=84 ip-header-size=20 dscp=0 identification=3597 fragment-offset=0 ttl=64 

 2 time=3.554 num=3 direction=rx src-mac=76:C1:DB:CF:E8:8C dst-mac=78:9A:18:13:2B:05 interface=guest-vlan-36 src-address=192.168.36.2 dst-address=192.168.88.1 
   protocol=ip ip-protocol=icmp size=98 cpu=0 ip-packet-size=84 ip-header-size=20 dscp=0 identification=3597 fragment-offset=0 ttl=64 

 3 time=3.554 num=4 direction=tx src-mac=78:9A:18:13:2B:05 dst-mac=76:C1:DB:CF:E8:8C interface=guest-vlan-36 src-address=192.168.88.1 dst-address=192.168.36.2 
   protocol=ip ip-protocol=icmp size=98 cpu=0 ip-packet-size=84 ip-header-size=20 dscp=0 identification=2984 fragment-offset=0 ttl=64 

 4 time=3.554 num=5 direction=tx src-mac=78:9A:18:13:2B:05 dst-mac=76:C1:DB:CF:E8:8C vlan=36 interface=bridge src-address=192.168.88.1 dst-address=192.168.36.2 
   protocol=ip ip-protocol=icmp size=102 cpu=0 ip-packet-size=84 ip-header-size=20 dscp=0 identification=2984 fragment-offset=0 ttl=64 

 5 time=3.554 num=6 direction=tx src-mac=78:9A:18:13:2B:05 dst-mac=76:C1:DB:CF:E8:8C vlan=36 interface=ether2 src-address=192.168.88.1 dst-address=192.168.36.2 
   protocol=ip ip-protocol=icmp size=102 cpu=0 ip-packet-size=84 ip-header-size=20 dscp=0 identification=2984 fragment-offset=0 ttl=64

The edge router has following configuration:

/interface bridge
add admin-mac=11:22:33:44:55:66 auto-mac=no comment=defconf fast-forward=no name=bridge vlan-filtering=yes
/interface vlan
add interface=bridge name=guest-vlan-31 vlan-id=31
add interface=bridge name=guest-vlan-36 vlan-id=36
/interface list
add comment=defconf name=WAN
add comment=defconf name=LAN
/interface wifiwave2 datapath
add bridge=bridge client-isolation=yes name=guest vlan-id=31
/interface wifiwave2 security
add authentication-types=wpa2-psk,wpa3-psk disabled=no ft=yes name=private
add authentication-types=wpa2-psk,wpa3-psk disabled=no ft=yes name=guest
/interface wifiwave2
set [ find default-name=wifi1 ] channel.frequency=5500 .skip-dfs-channels=10min-cac .width=20/40/80mhz configuration.country=Slovakia .mode=ap .ssid=MY_NET_SSID-Private .tx-power=21 disabled=no security=private security.authentication-types=wpa2-psk,wpa3-psk .ft=yes
set [ find default-name=wifi2 ] channel.band=2ghz-ax .frequency=2412 .skip-dfs-channels=10min-cac .width=20mhz configuration.country=Slovakia .mode=ap .ssid=MY_NET_SSID-Private .tx-power=14 disabled=no security=private security.authentication-types=wpa2-psk,wpa3-psk .ft=\
    yes
add configuration.mode=ap .ssid=MY_NET_SSID datapath=guest disabled=no mac-address=11:22:33:44:55:66 master-interface=wifi1 name=wifi3 security=guest security.ft=yes
add configuration.mode=ap .ssid=MY_NET_SSID datapath=guest disabled=no mac-address=11:22:33:44:55:66 master-interface=wifi2 name=wifi4 security=guest security.ft=yes
/ip pool
add name=dhcp ranges=192.168.88.140-192.168.88.254
add name=dhcp-guest-31 ranges=192.168.31.2-192.168.31.254
add name=dhcp-guest-36 ranges=192.168.36.2-192.168.36.254
/ip dhcp-server
add address-pool=dhcp interface=bridge lease-time=10m name=defconf
add address-pool=dhcp-guest-31 interface=guest-vlan-31 name=dhcp-guest-31
add address-pool=dhcp-guest-36 interface=guest-vlan-36 name=dhcp-guest-36
/interface bridge filter
add action=drop chain=forward in-interface=wifi3
add action=drop chain=forward out-interface=wifi3
add action=drop chain=forward in-interface=wifi4
add action=drop chain=forward out-interface=wifi4
/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 edge=yes-discover interface=wifi1
add bridge=bridge comment=defconf edge=yes-discover interface=wifi2
add bridge=bridge edge=yes-discover interface=wifi3
add bridge=bridge edge=yes-discover interface=wifi4
/ip neighbor discovery-settings
set discover-interface-list=LAN
/interface bridge vlan
add bridge=bridge tagged=ether2,bridge vlan-ids=31
add bridge=bridge tagged=wifi3 vlan-ids=31
add bridge=bridge tagged=wifi4 vlan-ids=31
add bridge=bridge tagged=ether2,bridge vlan-ids=36
/interface dot1x server
add interface=LAN
/interface list member
add comment=defconf interface=bridge list=LAN
add comment=defconf interface=ether1 list=WAN
/interface wifiwave2 access-list
# REDACTED
/ip address
add address=192.168.88.1/24 comment=defconf interface=bridge network=192.168.88.0
add address=192.168.31.1/24 interface=guest-vlan-31 network=192.168.31.0
add address=192.168.36.1/24 interface=guest-vlan-36 network=192.168.36.0
/ip dhcp-client
add comment=defconf interface=ether1
/ip dhcp-server lease
# REDACTED
/ip dhcp-server network
add address=192.168.31.0/24 domain=lan-guest gateway=192.168.31.1
add address=192.168.36.0/24 domain=lan-guest-36 gateway=192.168.36.1
add address=192.168.88.0/24 comment=defconf dns-server=192.168.88.1 domain=lan gateway=192.168.88.1
/ip dns
set allow-remote-requests=yes
/ip dns static
# REDACTED
/ip firewall address-list
add address=192.168.88.2-192.168.88.254 list=allowed_to_router
/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 src-address-list=allowed_to_router
add action=drop chain=input
add action=accept chain=forward comment="defconf: accept in ipsec policy" ipsec-policy=in,ipsec
add action=accept chain=forward comment="defconf: accept out ipsec policy" ipsec-policy=out,ipsec
add action=fasttrack-connection chain=forward comment="defconf: fasttrack" connection-state=established,related hw-offload=yes
add action=accept chain=forward comment="defconf: accept established,related, untracked" connection-state=established,related,untracked
add action=drop chain=forward comment="defconf: drop invalid" connection-state=invalid
add action=drop chain=forward comment="defconf: drop all from WAN not DSTNATed" connection-nat-state=!dstnat connection-state=new in-interface-list=WAN
add action=accept chain=forward in-interface=guest-vlan-31 out-interface-list=WAN
add action=drop chain=forward out-interface=guest-vlan-31
add action=drop chain=forward in-interface=guest-vlan-31
add action=accept chain=forward in-interface=guest-vlan-36 out-interface-list=WAN
add action=drop chain=forward in-interface=guest-vlan-36
add action=drop chain=forward out-interface=guest-vlan-36
/ip firewall nat
add action=masquerade chain=srcnat comment="defconf: masquerade" ipsec-policy=out,none out-interface-list=WAN
/ip service
set telnet disabled=yes
set ftp disabled=yes
set api disabled=yes
set winbox disabled=yes
set api-ssl disabled=yes
/ipv6 firewall address-list
add address=::/128 comment="defconf: unspecified address" list=bad_ipv6
add address=::1/128 comment="defconf: lo" list=bad_ipv6
add address=fec0::/10 comment="defconf: site-local" list=bad_ipv6
add address=::ffff:0.0.0.0/96 comment="defconf: ipv4-mapped" list=bad_ipv6
add address=::/96 comment="defconf: ipv4 compat" list=bad_ipv6
add address=100::/64 comment="defconf: discard only " list=bad_ipv6
add address=2001:db8::/32 comment="defconf: documentation" list=bad_ipv6
add address=2001:10::/28 comment="defconf: ORCHID" list=bad_ipv6
add address=3ffe::/16 comment="defconf: 6bone" list=bad_ipv6
/ipv6 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 ICMPv6" protocol=icmpv6
add action=accept chain=input comment="defconf: accept UDP traceroute" port=33434-33534 protocol=udp
add action=accept chain=input comment="defconf: accept DHCPv6-Client prefix delegation." dst-port=546 protocol=udp src-address=fe80::/10
add action=accept chain=input comment="defconf: accept IKE" dst-port=500,4500 protocol=udp
add action=accept chain=input comment="defconf: accept ipsec AH" protocol=ipsec-ah
add action=accept chain=input comment="defconf: accept ipsec ESP" protocol=ipsec-esp
add action=accept chain=input comment="defconf: accept all that matches ipsec policy" ipsec-policy=in,ipsec
add action=drop chain=input comment="defconf: drop everything else not coming from LAN" in-interface-list=!LAN
add action=accept chain=forward comment="defconf: accept established,related,untracked" connection-state=established,related,untracked
add action=drop chain=forward comment="defconf: drop invalid" connection-state=invalid
add action=drop chain=forward comment="defconf: drop packets with bad src ipv6" src-address-list=bad_ipv6
add action=drop chain=forward comment="defconf: drop packets with bad dst ipv6" dst-address-list=bad_ipv6
add action=drop chain=forward comment="defconf: rfc4890 drop hop-limit=1" hop-limit=equal:1 protocol=icmpv6
add action=accept chain=forward comment="defconf: accept ICMPv6" protocol=icmpv6
add action=accept chain=forward comment="defconf: accept HIP" protocol=139
add action=accept chain=forward comment="defconf: accept IKE" dst-port=500,4500 protocol=udp
add action=accept chain=forward comment="defconf: accept ipsec AH" protocol=ipsec-ah
add action=accept chain=forward comment="defconf: accept ipsec ESP" protocol=ipsec-esp
add action=accept chain=forward comment="defconf: accept all that matches ipsec policy" ipsec-policy=in,ipsec
add action=drop chain=forward comment="defconf: drop everything else not coming from LAN" in-interface-list=!LAN

Intervlan communication has to be blocked on firewall.

Better, configure the firewall what is allowed and block everything else (make sure you don’t block access to the router completely).

When firewall instance (in the router) starts processing received packet, one if first taks is to determine whether packet is targeting router itself or not. If dst-address matches any of router’s own addresses, then firewall uses chain=input for further processing … and ingress interface doesn’t make any difference. So if you wan’t to block communication with router via “non-native” interface, you have to add appropriate firewall filter rules to chain=input, such as this one:

/ip firewall filter
add chain=input action=drop dst-address=192.168.36.1 in-interface=!lan-guest-36

However, this doesn’t really add any security to the setup, it’s only cosmetics.

Concur just because you can ping an interface address does not mean you can access any devices on that subnet.
Some have to do it for company security optics but as mkx said its cosmetic.

Linux defaults. I don’t believe RouterOS exposes the necessary knobs to control this.

https://sysctl-explorer.net/net/ipv4/arp_ignore/
https://sysctl-explorer.net/net/ipv4/arp_filter/

Very obtuse vague answer there Rich.
In fact, you can set up input chain rules to prevent even the interface from responding to pings, so yes the KNOB is available, just have to turn it ;-PPP

Of course you can use firewall to block whatever you want but the root cause is arp replies from the “wrong” interface. No amount of firewalling in L3 can fix the underlying L2 issue.

What makes you think this is what happens? When client wants to send a packet to one of router’s “non-native” addresses, it has no idea it’s actually tge same device. So it uses gateway to send the packet out … and if it needs to use ARP who-has to find out gateway’s MAC address, it’ll ask about own gateway’s IP address.

I think a LAN host can request a non on-link IPv4 of the router via ARP (maliciously, due to misconfiguration or by being transitioned from one LAN to another) and get a reply.

Might be.

But the “cosmetic” issue about how firewall determines chain to use (input vs. forward) explains the behaviour and doesn’t need to resort to misconfigurations or malicious doings.
Besides: even if client does deliver IP packet to router by sending it to “non-native” MAC address (and even if that interface would accept it which my gut feeling doesn’t accept), it’ll enter the L3 processing path and at that stage MAC addresses don’t matter.

Yes. I've configured forward chain to allow packet coming in guest-vlan-31 to be forwarded out only to WAN, and drop else packets (besides established connections) that are going in or out guest-vlan-31 interrface.


This is the goal, and the issue on router-side. I didn't expect packet to reach input chain without being routed, because it is coming in different interface with different (gateway) IP address.

If I configured input chain to accept admin access on only allowed IP address - 192.168.88.1, which should be listening only on untagged traffic - LAN without VLANs, then it accepts connections coming in via guest interfaces with different IP addresses and IP networks.


Thanks, this explains why this issue happens. It doesn't check, that packet is coming in interface with different dst address than is the address of the interface, and therefore doesn't apply forward chain (routing) rules for it. It instead jumps straight to the input chain.

Is it possible to configure one rule, that would require dst address to equal address of the in-interface, i.e. allow guest-vlan-36 to access dst-address only of own network.

add action=drop chain=input dst-address=!192.168.36.0/24 in-interface=guest-vlan-36



Not fully cosmetics, because if there's rule to accept admin access on dst-address=192.168.88.1, then this accepts connections from guest vlans.

One would thought, that when dst-address is different that address of interface the packet came in, i.e. jump from 192.168.36.1 (interface=guest-vlan-36) to 192.168.88.1 (interface=bridge), would require routing between networks/interface. Because, the configuration says, that each interface has got different IP:

/ip address
add address=192.168.88.1/24 comment=defconf interface=bridge network=192.168.88.0
add address=192.168.31.1/24 interface=guest-vlan-31 network=192.168.31.0
add address=192.168.36.1/24 interface=guest-vlan-36 network=192.168.36.0

From above configuration, there's nothing indicating, that guest-vlan-36 should be accepting packets coming to 192.168.88.1 straight on input chain.

IMO, This is quite misleading behaviour.

It is more, than just a cosmetic issue. If there’s a rule to accept admin access / packets (incoming connections) on 192.168.88.1, which is assigned to bridge interface (not vlan interfaces), then this allows admin access also from guest vlans, that have no business accessing admin.

This behavior of passing packets straight to input chain, in situations when it is received on interface with different IP address that is assigned to different interface of the router, would possibly lead to severe security issue - granting a way to admin, and possibly allowing brute-force attacks.

Access to login and services can be controlled by IP though.

What behavior is recommended by RFCs? Perhaps there is a requirement for router to behave like this by default.

Well, protection against connnecting management interface can be done in various ways and the way you chose prooves to be problematic in ROS. Another way is to limit according to in-interface (or in-interface-list) which can work for any type (physical ports, VLANs, various VPN interfaces). And in that case actually used dst-address doesn’t matter.


In this case, to me it would then make sense that firewall would have to run two srts of rules: first chain=firward for passing packet from one subnet to another and then chain=input because packet is targeting router.


Anyway, there are two, relatively independent, functions in your device: 1) router which shuffles packets between different interfaces (and thus needs several IP addresses) and 2) firewall which drops (or alters in case of NAT) passing packets (and doesn’t need any of IP addresses). They do have some interleaving which allow better performance and flexibility but conceptually that’s it.
The need for router to have multiple IP addresses is to allow for ARP who-has to work (normal hosts in some subnet use it to discover gateway’s MAC address) and from router’s point of view that’s most of it (it’s also used if router has to send back some ICMP message, like time exceeded). And management can be done completely OOB (e.g. via serial console cable). Traditionally routers did not provide any auxiliary services, like DHCP or some such. So router’s CPU providing services (and management access) could be considered as another interface but without own IP address. But it’s fairly simple for router to determine whether a packet should be delivered via this “address-less” interface: if dst-address is one of router’s addresses, then that’s it. After the routing decission is made (that egress interface of “routing engine” is management interface), theoretically ingress interface is not known any more. Practically it is because firewall and router are interleaved to certain extent anyway.

Your proposal (to first push packet via forward chain and only later via input chain) might be compated to first pushing a packet into another interface’s transmit buffer but then to fetch it from there and push it into managenent port … it just doesn’t make much sense from technical point of view. And I’m affraid you’ll just have to learn that this is the way things are, wheter it makes sense to you or not.

Well, it is what it is.

Administrators just must be aware of the issue, and mustn’t rely on dst-address when working with input chain, because if dst-address of the incoming packet matches any IP address assigned to any of router’s interfaces, then it will go straight to input chain. Even on mismatch of IP address assigned to in-interface and dst-address.

However, one should always verify security assumptions by testing - trying to hack it. So, just learning the way it works, and accommodate input chain rules to it.

Its clear to me, interfaces are considered part of the input chain and thus pingable by anybody on the router.
This has no bearing whether data can flow between LAN members as that is the domain of the forward chain.
Hence any concern that Lan members are not secure from other LAN members, guest or not is hogwash.
Its all about optics.
Most of us dont care, for some businesses its not acceptable and mainly because someone in the IT food chain may not understand how RoS works/

As for input chain rules, first and foremost, the only person(s) with full access should be the admin and even that can be limited to port/protocol but most dont.
Easily accomplished using some combination of interface list and source address list for example.

For example.. vlanX,vlanY, and vlanZ from not being able to ping each others interface address, that is easily accomplished as well but really does nothing practical.
/ip firewall address-list
add 192.168.20.1/32 list=blockping
add 192.168.40.1/32 list=blockping
add 192.168.60.1/32 list=blockping

Standard rules… order. Note since the stupid admin thinks he needs to block interfaces from responding he should probably also add a rule to make sure he still can LOL LOL LOL
add chain=input action=accept src-address-list=AdminIPs dst-address-list=blockping protocol=icmp
add chain=input action=drop in-interface-list=LAN dst-address-list=blockping protocol=icmp icmp-type=8/0 comment=“block echo requests to interfaces”
add chain=input action=accept procotol=ICMP comment=“allow all other ICMP traffic as per normal”


.,…
add chain=input action=drop comment=“drop all else”[/i]

That’s the point, this rule must not rely on dst-address, because RouterOS passes packets straight to input chain from all interfaces, if dst-address is any IP address assigned to any router interface.