OPNsenseXIV · VLANs and SegmentationInter-VLAN routing and east-west filtering
Inter-VLAN routing basics — when the firewall is the router
What you'll learn
- Explain that the firewall is the router for inter-VLAN traffic
- Trace a packet from one VLAN through the firewall to another VLAN
- Identify the rules that govern inter-VLAN traffic
- Recognise the failure modes of misconfigured inter-VLAN routing
Prerequisites
Verified against OPNsense 25.x · FreeBSD 14.x · PF (FreeBSD packet filter) FreeBSD 14.x · Unbound 1.20+ · Kea DHCP OPNsense 25.x plugin · WireGuard in-kernel + OPNsense plugin · strongSwan (IPsec plugin) OPNsense 25.x plugin · OpenVPN 2.6.x · Suricata 7.x · 2026-08-14
Every VLAN the firewall is attached to is a directly connected network. The firewall knows how to reach every IP on every directly attached VLAN because the route is implicit — the firewall has an interface on every VLAN and the kernel maintains a connected route for each. When a packet arrives on VLAN 10 destined for an IP on VLAN 20, the firewall does the routing decision and forwards the packet to VLAN 20. There is no separate router; the firewall is the router.
This lesson covers how inter-VLAN routing works in OPNsense, what the routing table looks like, what rules apply to inter-VLAN traffic, and the production failure modes that arise when the assumption that “the firewall routes between VLANs” is misunderstood.
The firewall as the router
A common production misunderstanding is that there must be a separate router between VLANs. In a small deployment, there is a separate router — the OPNsense firewall. Every VLAN interface on the firewall is a router interface; the firewall has an IP on every VLAN; the routing table has a connected route for every VLAN.
The proof is in the routing table:
$ netstat -rn | grep -v '::' | head -20Routing tables
Internet:
Destination Gateway Flags Netif Expire
default 198.51.100.1 UGS igb0
127.0.0.1 link#4 UH lo0
192.0.2.0/24 link#6 UC igb1_vlan10
198.51.100.0/24 link#5 UC igb0
203.0.113.0/24 link#7 UC igb1_vlan20Illustrative output
The connected routes tell the operator everything they need to know about what the firewall can reach directly. Every VLAN in the configuration appears as a connected route on its sub-interface.
How a packet crosses between VLANs
The packet flow for a host on VLAN 10 sending a packet to a host on VLAN 20:
- Host on VLAN 10 generates a packet destined for an IP on VLAN 20 (say,
203.0.113.50). The host’s default gateway is the firewall IP on VLAN 10 (192.0.2.1). - Host ARPs the gateway if no entry exists, gets the firewall’s MAC on
igb1_vlan10, sends the frame. - Frame arrives on
igb1_vlan10with destination MAC = firewall MAC and destination IP =203.0.113.50. - PF evaluates the rule set on
igb1_vlan10for the packet. The packet is destined for an IP on VLAN 20; the firewall’s source IP (in the rule context) is the host on VLAN 10. If a rule permits the traffic, PF creates state. - Routing decision. The kernel consults the routing table.
203.0.113.0/24is a connected route onigb1_vlan20. The egress interface isigb1_vlan20. - Egress interface rule check. For some flows, PF evaluates the rules on
igb1_vlan20. State-matched return traffic passes without rule evaluation. - ARP resolution. The kernel ARPs
203.0.113.50onigb1_vlan20if no entry exists, gets the destination host’s MAC, and forwards the frame.
The reverse path: a reply from 203.0.113.50 to a host on VLAN 10 follows the same path in reverse. The state table matches the reply on either interface; no rule evaluation happens for the reply.
Outbound NAT for inter-VLAN traffic
A common production question: does the firewall apply outbound NAT to inter-VLAN traffic? The answer is no, by default.
Outbound NAT in OPNsense rewrites the source IP of traffic leaving the WAN interface, so the firewall’s WAN IP appears as the source on the Internet. Inter-VLAN traffic does not leave the WAN; it leaves on another VLAN interface. The source IP is preserved (the host’s original VLAN IP), and the firewall does not translate.
The implication: the firewall’s outbound NAT rules (under Firewall → NAT → Outbound) apply only to traffic with the WAN as the egress interface. Inter-VLAN traffic bypasses outbound NAT unless the operator manually configures it.
$ pfctl -s state | grep -E '192.0.2.50|203.0.113.50'all tcp 192.0.2.50:51820 <- 203.0.113.50:443 0:0Illustrative output
The state entry shows the original source and destination IPs. No NAT — the firewall has forwarded the packet as-is between VLANs.
Rules for inter-VLAN traffic
The rules for inter-VLAN traffic live on the source VLAN interface. A packet from VLAN 10 to VLAN 20 enters the firewall on igb1_vlan10 and is evaluated against the rules on igb1_vlan10. The operator writes rules on igb1_vlan10 that say “permit from VLAN 10 to VLAN 20” or “block from VLAN 10 to VLAN 20”.
This is consistent with the lesson on interface rules and direction: rules apply on ingress. The egress interface (VLAN 20) has its own rules for traffic destined to it, but the typical pattern is to put the inter-VLAN rules on the source interface.
A simple rule set
For a VLAN pair where VLAN 10 (users) needs to reach a server on VLAN 20 (servers), the rules on VLAN 10 look like:
| Order | Action | Source | Destination | Ports | Notes |
|---|---|---|---|---|---|
| 1 | pass | 192.0.2.0/24 | 203.0.113.50 | 443 | Permit users to web server on servers VLAN |
| 2 | pass | 192.0.2.0/24 | 203.0.113.50 | 53 | Permit users to DNS server on servers VLAN |
| 3 | block | 192.0.2.0/24 | 203.0.113.0/24 | any | Default deny: no other user-to-server traffic |
The rule set is restrictive by default. The operator permits what is needed; everything else is blocked.
Automatic rules and the default deny
OPNsense generates automatic rules on every interface. The relevant automatic rules for inter-VLAN traffic:
- Anti-lockout rule on the LAN interface only — permits traffic from the LAN subnet to the firewall IP. This rule does not exist on other interfaces.
- Default deny on every interface — blocks traffic that does not match any explicit rule.
The default deny is the security foundation. Inter-VLAN traffic is blocked unless an explicit rule permits it. The operator who wants VLAN 10 and VLAN 20 to be able to talk writes the rule; the operator who does not write a rule has the default deny in place.
Connected routes vs static routes
Connected routes are automatic — every VLAN interface on the firewall gets a connected route. The operator does not need to configure them.
Static routes are for networks the firewall is not directly attached to but knows about. For example, if a remote site has a subnet 10.50.0.0/24 reached via a VPN, the operator adds a static route saying “to reach 10.50.0.0/24, send packets to the VPN gateway”.
For inter-VLAN routing on the firewall itself, no static routes are needed. The connected routes handle everything.
$ route -n get 203.0.113.50 route to: 203.0.113.50
destination: 203.0.113.0/24
interface: igb1_vlan20
flags: <UP,CONNECTED>
recvpipe sendpipe ssthresh rtt,msec rttapi hopcount mtu expire
0 0 0 0 0 0 1500Illustrative output
Tracing an inter-VLAN packet
The complete verification sequence for “VLAN 10 host cannot reach VLAN 20 host”:
- From the VLAN 10 host:
ping 203.0.113.50. The host ARPs the gateway (firewall IP on VLAN 10) and sends the ICMP echo. - On the firewall:
tcpdump -nei igb1_vlan10 icmpshows the echo arriving. - On the firewall:
pfctl -s rules | grep igb1_vlan10shows the rules on VLAN 10. - On the firewall:
tcpdump -nei igb1_vlan20 icmpshows the echo leaving on VLAN 20. - On the VLAN 20 host: the echo arrives.
If step 2 shows the packet arriving but step 3 has no matching rule, the default deny is blocking the traffic. If step 4 shows no outgoing echo, the rule matched but the routing decision failed (very unusual for directly attached VLANs). If step 5 shows no arrival, the firewall forwarded the packet but the destination host or its switch dropped it.
Failure modes
Three inter-VLAN routing failure modes recur.
Failure 1: Missing IP on a VLAN
The VLAN interface exists but has no IPv4 address. Hosts on the VLAN cannot ARP a gateway. The routing table does not show a connected route for the VLAN (because the kernel only creates a connected route when the interface has an IP).
The diagnostic: ifconfig igb1_vlan10 shows the interface is up but has no inet line. netstat -rn does not show a route for the VLAN’s subnet. The fix: configure the IPv4 address.
Failure 2: Wrong subnet on the gateway
The firewall IP on a VLAN is on a different subnet than the hosts. The hosts cannot ARP the gateway because the gateway is not on the same subnet as the source IP.
The diagnostic: ifconfig on the firewall shows inet 192.0.2.1/24, but the hosts are configured for 192.0.2.0/25 (a smaller subnet). The fix: align the gateway IP with the host subnet.
Failure 3: Default deny without explicit rules
The operator assumes VLANs can talk to each other. The default deny blocks inter-VLAN traffic. The operator does not know where to look.
The diagnostic: tcpdump on the source VLAN shows the packet arriving at the firewall, pfctl -s state shows no state created, and the firewall log shows the packet dropped by the default deny rule. The fix: write an explicit rule permitting the traffic.
Summary
- The firewall is the router for inter-VLAN traffic. Every VLAN is a connected route; no separate router exists.
- A packet from VLAN 10 to VLAN 20 enters on
igb1_vlan10, is evaluated against VLAN 10 rules, is routed toigb1_vlan20, and exits onigb1_vlan20. - Inter-VLAN traffic does not get outbound NAT by default. The source IP is preserved.
- The default deny blocks inter-VLAN traffic until the operator writes a rule. The discipline is to permit what is needed and rely on the default deny for the rest.
Knowledge check · 4 questions
Q1. A host on VLAN 10 (192.0.2.50) sends a packet to a host on VLAN 20 (203.0.113.50). The firewall has IP 192.0.2.1 on VLAN 10 and 203.0.113.1 on VLAN 20. There are no firewall rules between VLAN 10 and VLAN 20. What happens to the packet?
Q2. Inter-VLAN traffic in OPNsense is rewritten by outbound NAT by default.
Q3. Which of the following are valid ways to verify inter-VLAN routing is working? Select all that apply.
Q4. A host on VLAN 10 can ping the firewall IP on VLAN 10 but cannot ping a host on VLAN 20. tcpdump on the firewall shows the ICMP echo arriving on igb1_vlan10 but no ICMP echo leaving on igb1_vlan20. What is the most likely cause?
Passing score: 75%. Answers are checked in this browser.