InfraRunBook
    Back to articles

    Juniper Firewall Filter Not Blocking Traffic

    Juniper
    Published: Apr 19, 2026
    Updated: Apr 19, 2026

    Step-by-step troubleshooting guide for Juniper firewall filters that refuse to block traffic, covering wrong direction, term ordering, overly specific match conditions, missing actions, and unattached filters.

    Juniper Firewall Filter Not Blocking Traffic

    Symptoms

    You commit a firewall filter to your Juniper router or switch, convinced it's going to block specific traffic — and then you pull up a packet capture or run a quick ping and watch the traffic sail right through. The filter is there in the configuration, committed without errors, and yet nothing gets blocked. This is one of those maddening situations that makes you question everything you think you know about Junos firewall filters.

    Common signs that your filter isn't doing what you expect include:

    • Traffic that should be dropped continues to reach the destination
    • show firewall log
      shows zero hits on the blocking term
    • A ping or telnet to an address that should be blocked succeeds
    • Filter counters remain at zero even after sustained traffic flows
    • No syslog messages appear even with logging configured on the term

    Before you tear the whole filter apart and start over, walk through the root causes below. In my experience it's almost always one of five or six specific mistakes — and most are quick to fix once you know what you're looking for.


    Root Cause 1: Filter Applied in the Wrong Direction

    Why It Happens

    This is the single most common mistake I see, and it catches experienced engineers just as often as newcomers. Junos firewall filters are strictly directional — you apply them as either input (traffic arriving on the interface) or output (traffic leaving through the interface). Getting the direction wrong means your filter is evaluated against a completely different traffic stream, so the packets you want to block never even encounter it.

    The confusion usually comes from thinking about traffic flow from the perspective of the end host rather than the router interface. If external hosts are sending traffic in through your WAN-facing interface, that's an input filter on that interface. If you're trying to block traffic leaving toward a particular server, that could be an output filter on the server-facing interface — or an input filter somewhere upstream depending on the topology. Getting this wrong is easy when you're moving fast.

    How to Identify It

    Dump the interface detail and look for where the filter is applied:

    infrarunbook-admin@sw-infrarunbook-01> show interfaces ge-0/0/1 detail | match filter
      Input Filter: none
      Output Filter: block-external

    If external traffic enters on ge-0/0/1 and you've applied the filter as output, it will never match ingressing packets. Here's the misconfigured state in the configuration tree:

    interfaces {
        ge-0/0/1 {
            unit 0 {
                family inet {
                    filter {
                        output block-external;  /* WRONG: traffic enters on this interface */
                    }
                }
            }
        }
    }

    How to Fix It

    Remove the incorrect application and add it in the right direction:

    infrarunbook-admin@sw-infrarunbook-01# delete interfaces ge-0/0/1 unit 0 family inet filter output block-external
    infrarunbook-admin@sw-infrarunbook-01# set interfaces ge-0/0/1 unit 0 family inet filter input block-external
    infrarunbook-admin@sw-infrarunbook-01# commit
    infrarunbook-admin@sw-infrarunbook-01> show interfaces ge-0/0/1 detail | match filter
      Input Filter: block-external
      Output Filter: none

    After the commit, immediately generate test traffic and watch

    show firewall log
    in real time to confirm hits are landing on the expected term. If you're unsure which direction to use, trace the packet path first with
    show route <destination>
    to understand egress interfaces, then reason backward.


    Root Cause 2: Term Order Is Wrong

    Why It Happens

    Junos evaluates firewall filter terms sequentially, top to bottom, and stops at the first match. This is fundamental and non-negotiable. If a broad permissive term appears earlier in the filter than your blocking term, the permissive term wins every time and your block term is never reached.

    I've watched this happen repeatedly when someone adds a "block specific host" term to an existing filter that already has a catch-all permit for a large address block. The permit matches first because it's higher in the term list, and the block term just sits there doing nothing.

    How to Identify It

    Dump the full filter and read the terms in order:

    infrarunbook-admin@sw-infrarunbook-01> show firewall filter block-external
    Filter: block-external
      Term: permit-management
        from:
          source-address: 10.0.0.0/8
        then:
          accept;
      Term: block-rogue-host
        from:
          source-address: 10.4.88.15/32
        then:
          discard;
      Term: default-permit
        then:
          accept;

    The problem is obvious once you see it laid out:

    permit-management
    matches all of 10.0.0.0/8 with an accept. Since 10.4.88.15 falls within that /8, every packet from that host is accepted at the first term. The
    block-rogue-host
    term never fires.

    How to Fix It

    Reorder the terms so more specific matches appear before broader ones. Junos provides the

    insert
    command for exactly this:

    infrarunbook-admin@sw-infrarunbook-01# edit firewall filter block-external
    infrarunbook-admin@sw-infrarunbook-01# insert term block-rogue-host before term permit-management
    infrarunbook-admin@sw-infrarunbook-01# commit
    infrarunbook-admin@sw-infrarunbook-01> show firewall filter block-external
    Filter: block-external
      Term: block-rogue-host
        from:
          source-address: 10.4.88.15/32
        then:
          discard;
      Term: permit-management
        from:
          source-address: 10.0.0.0/8
        then:
          accept;
      Term: default-permit
        then:
          accept;

    Now 10.4.88.15 hits the discard term before the broader permit-management term can accept it. As a general rule: always order terms from most specific to least specific when addresses or prefixes overlap.


    Root Cause 3: Match Condition Is Too Specific

    Why It Happens

    Every condition inside a Junos filter term's

    from
    block is ANDed together — all conditions must be simultaneously true for the term to match. If even one condition doesn't match the actual packet, the entire term is skipped, regardless of how well everything else aligns. This catches people who write multi-condition terms and then encounter traffic that satisfies most but not all of the conditions.

    The most common offender I see is combining protocol, destination-port, and an address prefix, then being confused when only some traffic gets blocked. Writing a term that matches TCP port 53 to a specific host will completely ignore UDP port 53 to that same host — and DNS is predominantly UDP.

    How to Identify It

    Consider this term:

    term block-dns {
        from {
            destination-address 10.99.1.10/32;
            protocol tcp;
            destination-port 53;
        }
        then discard;
    }

    Generate traffic to that destination using both TCP and UDP, then check the firewall log:

    infrarunbook-admin@sw-infrarunbook-01> show firewall log
    Log :
    Time      Filter         Action Interface  Protocol Src Addr        Dest Addr
    17:42:03  block-external D      ge-0/0/1   TCP      10.4.22.1       10.99.1.10
    17:42:05  block-external -      ge-0/0/1   UDP      10.4.22.1       10.99.1.10

    The D action means discard — TCP is being dropped correctly. The - means no action was logged, indicating the UDP packet didn't match any term and fell through to the implicit default accept. That's your problem. You can also confirm with a packet capture on the egress interface showing UDP packets reaching the destination.

    How to Fix It

    Either add a parallel term for UDP, or if the intent is to block all traffic to that host, drop the protocol and port conditions entirely:

    infrarunbook-admin@sw-infrarunbook-01# set firewall family inet filter block-external term block-dns-udp from destination-address 10.99.1.10/32
    infrarunbook-admin@sw-infrarunbook-01# set firewall family inet filter block-external term block-dns-udp from protocol udp
    infrarunbook-admin@sw-infrarunbook-01# set firewall family inet filter block-external term block-dns-udp from destination-port 53
    infrarunbook-admin@sw-infrarunbook-01# set firewall family inet filter block-external term block-dns-udp then discard
    infrarunbook-admin@sw-infrarunbook-01# insert term block-dns-udp before term block-dns
    infrarunbook-admin@sw-infrarunbook-01# commit

    If the intent was always to block everything to that host regardless of protocol or port, simplify the match to just the destination address and remove the protocol and port conditions. Simpler terms with fewer conditions are easier to reason about and far easier to debug later.


    Root Cause 4: Action Not Set in the Matching Term

    Why It Happens

    This one is subtle. In Junos, if a filter term has a

    from
    clause but no
    then
    clause, the default implicit action is accept. You wrote the term, defined the match conditions, and forgot the actual action — so Junos accepts the packet and moves on, never discarding anything.

    This typically happens when someone writes the

    from
    block first to test whether the match logic is correct, commits it, forgets to come back and add the
    then discard
    , and then closes the session. It also happens when copying configuration snippets where the action line got stripped out during editing.

    How to Identify It

    Use the

    display set
    option to see what was explicitly configured versus what Junos infers:

    infrarunbook-admin@sw-infrarunbook-01> show configuration firewall | display set
    set firewall family inet filter block-external term block-rogue-host from source-address 10.4.88.15/32
    set firewall family inet filter block-external term default-permit then accept

    Notice that

    block-rogue-host
    has a
    from
    condition but no
    then
    line at all. Now compare with the operational view:

    infrarunbook-admin@sw-infrarunbook-01> show firewall filter block-external
    Filter: block-external
      Term: block-rogue-host
        from:
          source-address: 10.4.88.15/32
        then:
          accept;    <-- implicit default, never explicitly configured
      Term: default-permit
        then:
          accept;

    Junos shows the implicit accept in the operational output. It won't appear in

    show configuration
    or
    display set
    because it was never configured — which makes it easy to miss on a config review. The firewall log also won't show action entries for these packets since there's nothing to log against.

    How to Fix It

    Add the intended action explicitly. Use

    discard
    to silently drop, or
    reject
    to drop and return an ICMP unreachable to the source. For security filtering,
    discard
    is generally preferred since it gives no feedback to a potential attacker:

    infrarunbook-admin@sw-infrarunbook-01# set firewall family inet filter block-external term block-rogue-host then discard
    infrarunbook-admin@sw-infrarunbook-01# set firewall family inet filter block-external term block-rogue-host then count rogue-host-drops
    infrarunbook-admin@sw-infrarunbook-01# set firewall family inet filter block-external term block-rogue-host then log
    infrarunbook-admin@sw-infrarunbook-01# commit

    Adding

    count
    and
    log
    alongside
    discard
    gives you visibility — the counter increments on every matched packet, and hits appear in
    show firewall log
    , which makes verifying the fix immediate and unambiguous.


    Root Cause 5: Filter Not Applied to Any Interface

    Why It Happens

    A firewall filter sitting unattached in the configuration does exactly nothing. You could have the most perfectly constructed filter with flawless term order, precise match conditions, and explicit discard actions — and if it's not applied to an interface, traffic flows through the router with no filtering whatsoever.

    This is embarrassingly easy to do. You create the filter, review the configuration, run

    commit check
    , everything looks clean, and you close the session. Applying the filter to the interface was the next step and it simply didn't happen. I've done this myself after a long change window.

    How to Identify It

    Search for the filter name anywhere in the interface configuration:

    infrarunbook-admin@sw-infrarunbook-01> show configuration | match block-external
    filter block-external;
    term block-rogue-host {
    term block-dns {

    If those matches only appear under the

    firewall { ... }
    stanza and nowhere under
    interfaces { ... }
    , the filter isn't applied anywhere. Cross-check a specific interface directly:

    infrarunbook-admin@sw-infrarunbook-01> show interfaces ge-0/0/1 detail | match filter
    [no output]

    No output means no filter applied. A correctly configured interface would show:

    infrarunbook-admin@sw-infrarunbook-01> show interfaces ge-0/0/1 detail | match filter
      Input Filter: block-external

    How to Fix It

    Determine which interface the relevant traffic transits and apply the filter in the correct direction. Use

    show route
    to find the egress path for traffic you want to intercept, then apply accordingly:

    infrarunbook-admin@sw-infrarunbook-01> show route 10.4.88.15
    inet.0: 14 destinations, 14 routes (14 active, 0 holddown, 0 hidden)
    + = Active Route, - = Last Active, * = Both
    
    10.4.88.0/24       *[Static/5] 00:12:34
                        > to 10.0.0.1 via ge-0/0/1
    
    infrarunbook-admin@sw-infrarunbook-01# set interfaces ge-0/0/1 unit 0 family inet filter input block-external
    infrarunbook-admin@sw-infrarunbook-01# commit
    infrarunbook-admin@sw-infrarunbook-01> show interfaces ge-0/0/1 detail | match filter
      Input Filter: block-external

    After applying, verify with

    show firewall log
    while generating test traffic. You should see hits immediately if the term match conditions are correct and the direction is right.


    Root Cause 6: Wrong Address Family

    Why It Happens

    Junos firewall filters are address-family specific. A filter defined under

    family inet
    only evaluates IPv4 packets. If the traffic you're trying to block is IPv6, you need a separate filter under
    family inet6
    . The families don't share filters, and there's no cross-family inheritance.

    This becomes a real problem when a network has dual-stack interfaces and an engineer creates a blocking filter only in the IPv4 family. IPv6 traffic from the same source walks straight through, and it can look like the filter isn't working when really it just doesn't apply to that protocol family.

    How to Identify It

    infrarunbook-admin@sw-infrarunbook-01> show configuration firewall
    family inet {
        filter block-external {
            term block-rogue-host {
                from {
                    source-address 10.4.88.15/32;
                }
                then discard;
            }
            term default-permit {
                then accept;
            }
        }
    }
    /* No family inet6 section -- IPv6 traffic is unfiltered */

    How to Fix It

    Create a parallel filter under

    family inet6
    for the equivalent IPv6 addresses and apply it to the same interface:

    infrarunbook-admin@sw-infrarunbook-01# set firewall family inet6 filter block-external-v6 term block-rogue-host from source-address 2001:db8:cafe::abcd/128
    infrarunbook-admin@sw-infrarunbook-01# set firewall family inet6 filter block-external-v6 term block-rogue-host then discard
    infrarunbook-admin@sw-infrarunbook-01# set firewall family inet6 filter block-external-v6 term default-permit then accept
    infrarunbook-admin@sw-infrarunbook-01# set interfaces ge-0/0/1 unit 0 family inet6 filter input block-external-v6
    infrarunbook-admin@sw-infrarunbook-01# commit

    After committing, verify both families are covered on the interface:

    infrarunbook-admin@sw-infrarunbook-01> show interfaces ge-0/0/1 detail | match filter
      Input Filter: block-external
      Input6 Filter: block-external-v6

    Root Cause 7: Implicit Default Accept at End of Filter

    Why It Happens

    Every Junos firewall filter has an implicit default accept at the very end if you don't define an explicit catch-all term. This is by design — Junos defaults to permitting unmatched traffic unless you explicitly say otherwise. If your filter only contains specific block terms and no explicit default, any traffic that doesn't match your block terms gets accepted silently with no log entry and no counter hit.

    This isn't always a problem — sometimes you want most traffic to pass and only block a handful of specific flows. But when the implicit default causes unexpected behavior, it's hard to spot because it leaves no trace in logs or counters.

    How to Identify It

    Check whether your filter has an explicit catch-all term at the end:

    infrarunbook-admin@sw-infrarunbook-01> show firewall filter block-external
    Filter: block-external
      Term: block-rogue-host
        from:
          source-address: 10.4.88.15/32
        then:
          discard;
      /* No explicit default term -- unmatched traffic accepted implicitly */

    If the last term in the filter is a blocking term with no subsequent catch-all, all non-matching traffic is accepted without any visibility into what's passing through.

    How to Fix It

    Always add an explicit default term as the last entry in the filter. This documents the intent, makes the behavior visible through counters, and removes any ambiguity:

    infrarunbook-admin@sw-infrarunbook-01# set firewall family inet filter block-external term default-accept then accept
    infrarunbook-admin@sw-infrarunbook-01# set firewall family inet filter block-external term default-accept then count all-accepted-traffic
    infrarunbook-admin@sw-infrarunbook-01# commit
    infrarunbook-admin@sw-infrarunbook-01> show firewall filter block-external
    Filter: block-external
      Term: block-rogue-host
        from:
          source-address: 10.4.88.15/32
        then:
          count rogue-host-drops;
          log;
          discard;
      Term: default-accept
        then:
          count all-accepted-traffic;
          accept;

    With explicit counters on both terms, you can tell at a glance exactly how much traffic is hitting each path. If

    rogue-host-drops
    is stuck at zero and
    all-accepted-traffic
    is climbing, you know the blocking term isn't matching — which sends you back to diagnose the match conditions.


    Prevention

    Most of these mistakes are preventable with a consistent commit workflow. Before declaring any new firewall filter done, run this validation sequence explicitly — don't skip it even when you're confident:

    infrarunbook-admin@sw-infrarunbook-01> show firewall filter block-external
    infrarunbook-admin@sw-infrarunbook-01> show interfaces ge-0/0/1 detail | match filter
    infrarunbook-admin@sw-infrarunbook-01> show firewall log
    infrarunbook-admin@sw-infrarunbook-01> show firewall filter block-external counter

    Put counters in every term, including accept terms. Counters cost nothing at scale and make troubleshooting dramatically faster. When you can see exactly how many packets hit each term, the diagnosis for every root cause above becomes a matter of reading a number rather than reasoning from indirect evidence.

    For critical filters, generate controlled test traffic before relying on the filter in production. Use a known source address, send traffic to a known destination, and watch the counters and logs in real time. This takes two minutes and eliminates any doubt about whether the filter is doing what you think.

    Document the intent of each filter in commit messages. When someone — including you, six months from now — reviews the configuration and wonders why a particular term exists, a commit message like "block 10.4.88.15 per security team request SR-4421 — host identified as compromised" is infinitely more useful than the filter definition alone.

    Finally, when building filters that need to handle both IPv4 and IPv6 traffic, make it a rule to always create both

    family inet
    and
    family inet6
    versions in the same change. Doing them together removes the risk of forgetting to come back and finish the IPv6 side later.

    Juniper firewall filters are deterministic and reliable once you understand the evaluation model. The behavior that looks like a bug is almost always a configuration mistake — and with the right diagnostic workflow, you can identify and fix every one of the root causes above in minutes rather than hours.

    Frequently Asked Questions

    Why does show firewall log show no hits on my blocking term?

    The most common reasons are that the filter is applied in the wrong direction (input vs output), the filter isn't applied to the interface at all, or a term earlier in the filter is matching the traffic first and accepting it before the blocking term is ever evaluated. Run 'show interfaces <iface> detail | match filter' to confirm the filter is applied and in the right direction, then review term order with 'show firewall filter <name>'.

    What is the default action in a Junos firewall filter term if I don't specify a 'then' clause?

    The default implicit action in Junos is accept. If you write a term with 'from' match conditions but no 'then' action, Junos will match the packet and accept it silently. You must explicitly configure 'then discard' or 'then reject' to drop traffic. This implicit accept won't appear in 'show configuration' output, making it easy to overlook during a config review.

    How do I check if a firewall filter is actually applied to an interface in Junos?

    Run 'show interfaces <interface-name> detail | match filter'. If the filter is applied as input you'll see 'Input Filter: <filter-name>', and for output you'll see 'Output Filter: <filter-name>'. No output from this command means no filter is attached to that interface. You can also run 'show configuration | match <filter-name>' and look for occurrences under the interfaces section.

    How do I reorder terms in a Juniper firewall filter without deleting and recreating them?

    Use the 'insert' command in configuration mode. For example: 'insert term block-specific before term permit-all' moves the block-specific term above the permit-all term. This reorders in place without losing the term configuration. After reordering, verify with 'show firewall filter <name>' to confirm the new sequence before committing.

    Does a Junos firewall filter under family inet also filter IPv6 traffic?

    No. Filters under 'family inet' only apply to IPv4 traffic. IPv6 traffic requires a separate filter defined under 'family inet6', applied to the interface with 'set interfaces <iface> unit 0 family inet6 filter input <filter-name>'. If your interface carries both IPv4 and IPv6 and you only have a family inet filter, IPv6 traffic passes completely unfiltered.

    Related Articles