Container isolated networks broken when Zone-Based Firewall and global-options state-policy are configured together (VyOS 1.5 regression)

Summary

Containers using isolated networks (set container network) are completely unreachable when Zone-Based Firewall (ZBF) and firewall global-options state-policy are configured together. ARP between the container and its bridge gateway is silently dropped, breaking all connectivity.

Steps to Reproduce

  1. Configure Zone-Based Firewall with at least two zones
  2. Configure a global state policy:
    set firewall global-options state-policy established action ‘accept’
    set firewall global-options state-policy invalid action ‘drop’
    set firewall global-options state-policy related action ‘accept’
  3. Configure a container with an isolated network:
    set container network npm prefix ‘172.20.0.0/24’
    set container name npm image ‘docker.io/jc21/nginx-proxy-manager
    set container name npm network npm address ‘172.20.0.2’
  4. Commit and attempt to reach the container:
    ping 172.20.0.2 # 100% packet loss

Expected Behavior

Container is reachable on its network address. ARP resolves the bridge gateway.

Actual Behavior

Container is completely unreachable. ARP requests from the container never receive a reply. The container cannot resolve its gateway MAC address.

Root Cause

VyOS 1.5’s ZBF implementation generates a VYOS_STATE_POLICY chain in table bridge vyos_filter and loads the nf_conntrack_bridge kernel module.
On VyOS 1.5 with ZBF, the bridge VYOS_STATE_POLICY hooks globally across every bridge on the system, including bridges dynamically created by the container runtime (e.g., pod-npm). ARP packets (EtherType 0x0806) traversing the container bridge are evaluated by nf_conntrack_bridge, marked as ct state invalid since ARP is not a trackable Layer 3 protocol, and dropped before the kernel ARP stack can generate a reply.

Evidence

VyOS 2026.03 with ZBF + global-options state-policy

$ lsmod | grep conntrack_bridge                                                                                                                                                                                                           
nf_conntrack_bridge    12288  3
                                                                                                                                                                                                                On VyOS 2026.03 with ZBF, VYOS_STATE_POLICY incorrectly appears in the bridge filter:

table bridge vyos_filter

  chain VYOS_INPUT_filter { 
      type filter hook input priority filter; policy accept;                                                                                                                                                                                
      jump VYOS_STATE_POLICY        #  applies to ALL bridges globally
  }                                                                    
  chain VYOS_STATE_POLICY {                                                                                                                                                                                                                 
      ct state established accept
      ct state invalid drop         #  drops ARP from container bridges                                                                                                                                                                    
      ct state related accept                                                                                                                                                                                                               
  }  

ARP requests leave the container and arrive at the host-side veth but receive no reply:

  $ tcpdump -i veth0 arp                                                                                                                                                                                                                    
  02:1f:f4:05:ce:00 > ff:ff:ff:ff:ff:ff, ARP Request who-has 172.20.0.1 tell 172.20.0.2                                                                                                                                                     
  02:1f:f4:05:ce:00 > ff:ff:ff:ff:ff:ff, ARP Request who-has 172.20.0.1 tell 172.20.0.2                                                                                                                                                     
  # No reply bridge drops the request before kernel ARP stack can respond                                                                                                                                                                 

Proposed Fix

The bridge VYOS_STATE_POLICY generated by VyOS 1.5’s ZBF implementation should be scoped to bridges that are members of a configured firewall zone, not applied as a global hook to every bridge. Container runtime bridges are created dynamically and should not be subject to the zone-based stateful filter.

Alternatively, an ARP exemption should be inserted before the ct state invalid drop in the bridge filter:

  chain VYOS_STATE_POLICY {
      ether type arp accept          # exempt ARP from conntrack evaluation                                                                                                                                                                 
      ct state established accept
      ct state invalid drop                                                                                                                                                                                                                 
      ct state related accept
  }         

Or maybe

  chain VYOS_STATE_POLICY {                                                                                                                                                                                                                 
      ether type != { ip, ip6 } return   # skip state check for non-IP traffic entirely
      ct state established accept                                                                                                                                                                                                           
      ct state invalid drop
      ct state related accept                                                                                                                                                                                                               
  } 

Testing Proposed Fix Results

Ningx proxy manager container:

vyos@vyos# curl http://localhost:81
<!DOCTYPE html>
<html lang="en">
        <head>
                <meta charset="utf-8" />
                <meta name="viewport" content="width=device-width, initial-scale=1" />
                <title>Nginx Proxy Manager</title>
                <meta name="description" content="In The Office Planner" />
                <link rel="preload" href="/images/logo-no-text.svg" as="image" type="image/svg+xml" fetchPriority="high">
                <link
                        rel="apple-touch-icon"
                        sizes="180x180"
                        href="/images/favicon/apple-touch-icon.png" />
                <link
                        rel="icon"
                        type="image/png"
                        sizes="32x32"
                        href="/images/favicon/favicon-32x32.png" />
                <link
                        rel="icon"
                        type="image/png"
                        sizes="16x16"
                        href="/images/favicon/favicon-16x16.png" />
                <link rel="manifest" href="/images/favicon/site.webmanifest" />
                <link
                        rel="mask-icon"
                        href="/images/favicon/safari-pinned-tab.svg"
                        color="#5bbad5" />
                <link rel="shortcut icon" href="/images/favicon/favicon.ico" />
                <meta name="msapplication-TileColor" content="#4a4a4a" />
                <meta
                        name="msapplication-config"
                        content="/images/favicon/browserconfig.xml" />
                <meta name="theme-color" content="#ffffff" />
                <script type="module" crossorigin src="/assets/index-BwxhCj6Q.js"></script>
                <link rel="stylesheet" crossorigin href="/assets/index-PuE7CNBN.css">
        </head>
        <body>
                <noscript>You need to enable JavaScript to run this app.</noscript>
                <div id="root"></div>
                <script>
                        if (global === undefined) {
                                var global = window;
                        }
                </script>
        </body>
</html>
[edit]

set firewall global-options apply-to-bridged-traffic accept-invalid ethernet-type 'arp'