SRX security flow traceoptions record each decision the flow engine makes for matching packets: the session lookup, destination NAT, route lookup, zone pair, policy and source NAT. The line that ends the debate is usually packet dropped, denied by policy, or a missing return-direction line. But tracing is the expensive step. Run show security flow session, show security match-policies and, from Junos OS 21.1R1, monitor security packet-drop first.

Most "the SRX is dropping my traffic" tickets fall into one of three buckets: no matching policy, no return path, or NAT applied differently from what the policy assumes. The cheaper commands identify all three without a commit.

This guide is written against the Junos OS 23.4 train on the SRX300 line and SRX1500. We have not lab-tested every command on every release. Confirm each statement with ? completion, and remember that tracing adds load to a production firewall. Other SRX guides are in the Security and Firewalls hub.

How the SRX Decides: Why the Order Matters

The first packet of a flow takes the slow path. The SRX looks for an existing session and, finding none, starts first-path processing. It applies destination or static NAT, does a route lookup on the translated destination to find the egress interface and zone, and then runs the policy lookup. Source NAT comes after the policy.

That order explains most confusing drops. Because destination NAT runs first, the policy must match the translated, internal destination address. Because source NAT runs last, the policy must match the original source. Because the route lookup chooses the destination zone, a wrong route puts the traffic into the wrong zone pair. Your correct policy is then never consulted.

Every packet after the first matches the session and takes the fast path, so the trace for those packets is short. This is also why fixing a policy sometimes appears not to work. An existing session built before the change keeps its old behaviour until it expires or you clear it.

Cheaper Checks First: The Ordered Diagnostic

Work through these in order. The first five need no configuration change and cause no measurable load.

  1. Does a session exist? Run show security flow session destination-prefix 192.0.2.10 while the client retries.
  2. Do bytes flow both ways? In the session output, compare packet counters on the In and Out lines.
  3. Which policy would match? Run show security match-policies with the zone pair and five-tuple.
  4. Why is it being dropped? On 21.1R1 and later, run monitor security packet-drop with a prefix filter.
  5. Are screens dropping it? Run show security screen statistics zone untrust and check the log for screen messages.
  6. Only now, trace. Configure flow traceoptions with a tight packet filter, reproduce the failure once, then remove the trace.
user@srx> show security flow session destination-prefix 192.0.2.10
user@srx> show security match-policies from-zone untrust to-zone dmz source-ip 198.51.100.10 destination-ip 192.0.2.10 source-port 51515 destination-port 443 protocol tcp
user@srx> monitor security packet-drop destination-prefix 192.0.2.10 count 20
user@srx> show security screen statistics zone untrust
user@srx> show security flow statistics

Reading the session table

This is the output that answers most tickets. The example below is illustrative, and field layout varies slightly by release.

user@srx> show security flow session destination-prefix 192.0.2.10
Session ID: 41237, Policy name: ALLOW-WEB/5, Timeout: 16, Session State: Valid
  In: 198.51.100.10/51515 --> 192.0.2.10/443;tcp, Conn Tag: 0x0, If: ge-0/0/0.0, Pkts: 3, Bytes: 180,
  Out: 192.0.2.10/443 --> 198.51.100.10/51515;tcp, Conn Tag: 0x0, If: ge-0/0/2.0, Pkts: 0, Bytes: 0,
Total sessions: 1

A session exists and names the policy, so the policy permitted the traffic. Packets on In and zero on Out mean the server never answered through the SRX. That points at routing, the server gateway or a host firewall, not at SRX policy. This exact pattern ran for dozens of replies in an r/networking thread about an SRX not forwarding despite allow policies.

No session at all means the first packet was dropped before a session was created. That is typically policy, a screen, or the traffic never reaching the SRX.

match-policies and the global policy trap

The show security match-policies reference states that the first enabled policy listed is the one applied. Anything below it is shadowed. Use result-count, from 1 to 16, to see what sits behind the winner.

The command evaluates the context you give it. If you rely on global policies, you must query them separately with the global keyword and the matching zones. Zone-pair policies are evaluated before global policies. So a zone-pair deny will beat a global permit, and a zone-pair query will not show you the global rule.

monitor security packet-drop

From Junos OS 21.1R1, monitor security packet-drop prints drop records with a reason, without any commit. It accepts filters such as source-prefix, destination-prefix, destination-port and a count from 1 to 8,000, with a default of 50. Append records to a file with | append /var/log/drops.log. See the monitor security packet-drop reference for the full option list.

On a supported release, this command replaces traceoptions for most policy and screen drops. Juniper has a KB article on records that report an unknown reason, so an unhelpful reason is not the end of the investigation. When that happens, move on to the trace.

Configuring Flow Traceoptions Safely

Trace files are written to flash, and tracing unfiltered traffic costs CPU. Juniper warns that tracing can hurt scale and performance. Always use a packet filter, keep the file small, and remove the trace as soon as you have one clean reproduction. Use console or out-of-band access if the firewall is busy.

set security flow traceoptions file flow-debug size 2m files 3
set security flow traceoptions flag basic-datapath
set security flow traceoptions packet-filter FWD source-prefix 198.51.100.10/32 destination-prefix 203.0.113.10/32
set security flow traceoptions packet-filter REV source-prefix 192.0.2.10/32 destination-prefix 198.51.100.10/32
commit

Filters match packets as they arrive, before translation. In this example the client reaches the public address 203.0.113.10, which destination NAT maps to 192.0.2.10. The forward filter uses the public address, and the reverse filter uses the server's real address. Criteria inside one filter are combined with AND, and separate filters with OR. If you source NAT the client, the reverse filter must target the translated source address instead.

The commit-free alternative and its conflict

user@srx> monitor security flow file flow-mon
user@srx> monitor security flow filter F1 source-prefix 198.51.100.10/32 destination-prefix 203.0.113.10/32
user@srx> monitor security flow start
user@srx> show monitor security flow
user@srx> monitor security flow stop
user@srx> clear monitor security flow filter

If monitor security flow start returns There is another flow debugging session which is running, some flow traceoptions remain in the configuration. On the Juniper forum, even a leftover trace-level detail stanza with no filters was enough. Delete security flow traceoptions completely and try again.

Reading the Trace, Line by Line

The trace below shows a first packet dropped by policy. It is illustrative, uses documentation addresses, and is trimmed to the lines that matter. Exact wording varies by release and platform.

<198.51.100.10/51515->203.0.113.10/443;6> matched filter FWD:
 packet [60] ipid = 2210
 ge-0/0/0.0:198.51.100.10/51515->203.0.113.10/443, tcp, flag 2 syn
 find flow: table 0x..., sa 198.51.100.10, da 203.0.113.10, sp 51515, dp 443, proto 6
 no session found, start first path. in_tunnel - 0, from_cp_flag - 0
 flow_first_rule_dst_xlate: packet 198.51.100.10->203.0.113.10 nsp2 0.0.0.0->192.0.2.10.
 routed (x_dst_ip 192.0.2.10) from untrust (ge-0/0/0.0 in 0) to ge-0/0/2.0, Next-hop: 192.0.2.10
 policy search from zone untrust-> zone dmz
 packet dropped, denied by policy
 packet dropped, policy deny.

Read it from the top. The first line confirms which filter matched and the protocol number: 6 is TCP and 17 is UDP. The flag 2 syn line shows the first packet of the connection. no session found, start first path confirms first-path processing.

The dst_xlate line shows destination NAT to 192.0.2.10. The routed line shows the egress interface, which determines the destination zone. policy search from zone untrust-> zone dmz names the exact zone pair the SRX searched. The last two lines are the verdict.

In a permitted flow, you instead see the session being created and a line referencing the policy index. Map that index to a name with show security policies | find "Index: 5". For return traffic, look for flow got session and a session ID, which proves the reply matched the existing session.

When the trace shows no drop

A trace that shows the packet permitted and forwarded, yet the server never sees it, points past the flow engine. Check ARP for the next hop, the egress VLAN, and the server gateway. Juniper also notes that trace messages are delivered with lower priority than control traffic, so a missing line is weak evidence. Correlate with a packet capture on the server, using the IP ID from the trace.

Root Causes Ranked by Frequency

This ranking reflects our field experience and what repeats across r/Juniper, r/networking and the Juniper community forum. It is not a Juniper statistic.

1. No matching policy, or the wrong one matches first

Common variants include policies written for the public rather than the translated destination, and applications defined for UDP when the client uses TCP. One r/Juniper user chased an RDP failure until they noticed protocol 6 in the trace, while their policy allowed only UDP 3389. Another is two subnets in the same zone. Intra-zone traffic still needs a policy from that zone to itself, because the default policy denies it.

2. No return path

This is the In-only session pattern. The server's default gateway is not the SRX, the SRX lacks a route back to the client, or the return traffic takes another path. With asymmetric routing, the SRX drops non-SYN first packets because TCP SYN checking is on by default. Fix the routing rather than disabling the check.

3. NAT not doing what the policy assumes

If static or destination NAT uses an address from the interface subnet, upstream routers need proxy ARP to reach it. Without it, packets never arrive, and nothing appears in the trace. Our NAT material in the Security and Firewalls hub goes deeper on rule-set order.

4. Screens and TCP state checks

Screens act on the ingress zone before the policy lookup. A malformed packet, a flood threshold or a session limit can drop legitimate traffic. The screen statistics command and the log show these drops. Juniper documents the drop due to firewall check message for session-limit screens.

5. Traffic to the SRX itself

Management traffic, ping to an interface address, IKE, BGP and OSPF need host-inbound-traffic on the zone or interface. Security policies do not control self traffic in the usual way. If the destination is the SRX, check host-inbound settings first. For tunnels, our SRX route-based IKEv2 VPN guide covers the IKE service requirement.

6. Permitted, then dropped by a service

IDP, content security and application identification can drop traffic after the policy has permitted it. The session appears, then dies. Newer releases include IDP signature information in packet-drop records. On a chassis cluster, confirm both nodes are healthy before blaming the flow engine; see our guide to an SRX chassis cluster node stuck in disabled.

Make Future Drops Visible

The default deny drops silently. An explicit final deny with logging turns every future drop into a log line you can search, and it costs far less than a trace.

set security policies from-zone untrust to-zone dmz policy DENY-LOG match source-address any
set security policies from-zone untrust to-zone dmz policy DENY-LOG match destination-address any
set security policies from-zone untrust to-zone dmz policy DENY-LOG match application any
set security policies from-zone untrust to-zone dmz policy DENY-LOG then deny
set security policies from-zone untrust to-zone dmz policy DENY-LOG then log session-init
commit confirmed 5

New policies are appended at the end of the zone pair. Place later permits above this rule with insert security policies from-zone untrust to-zone dmz policy NEW-RULE before policy DENY-LOG. Deny logging on a busy internet edge can be very noisy, so send it to a remote syslog server rather than local flash.

Verification and Cleanup

After the fix, a healthy session shows packets climbing on both the In and Out lines, and it names the policy you expect.

user@srx> show security flow session destination-prefix 192.0.2.10
Session ID: 41301, Policy name: ALLOW-WEB/5, Timeout: 1796, Session State: Valid
  In: 198.51.100.10/51520 --> 203.0.113.10/443;tcp, Conn Tag: 0x0, If: ge-0/0/0.0, Pkts: 14, Bytes: 2210,
  Out: 192.0.2.10/443 --> 198.51.100.10/51520;tcp, Conn Tag: 0x0, If: ge-0/0/2.0, Pkts: 12, Bytes: 9876,
Total sessions: 1

Then remove every trace. Leftover traceoptions keep writing to flash, and they block monitor security flow later.

delete security flow traceoptions
commit
run file delete /var/log/flow-debug

On the SRX4600, SRX4700 and SRX5000 line, Juniper provides data path debugging for captures at several points in the packet path. That is the high-end equivalent when flow traces are not enough. Branch SRX platforms use the packet-capture feature under forwarding-options instead.

Juniper, Junos, MX, SRX, EX and QFX are trademarks of Juniper Networks, Inc., now part of HPE. juniperclient.com is independent and unaffiliated.

Frequently Asked Questions

How do I interpret security flow traceoptions output?

Follow the first packet in order: matched filter, no session found, destination NAT, routed to an interface, policy search between two zones, then the verdict. The routed line tells you the destination zone, and the policy search line tells you which zone pair was checked. Check the protocol number too, where 6 is TCP and 17 is UDP.

Why is the Juniper SRX not forwarding traffic despite allow security policies?

If show security flow session shows packets on the In line and zero on the Out line, the policy worked and the reply never came back. Check the server default gateway, the SRX route back to the client, and asymmetric paths. A session that names your permit policy rules out policy as the cause.

Why does monitor security flow start say another flow debugging session is running?

Flow traceoptions still exist in the configuration, even a stanza with no filters. Remove them with delete security flow traceoptions and commit, then run monitor security flow start again. Check show monitor security flow to confirm the session is active.

How can I see why my SRX345 is dropping good traffic?

On Junos OS 21.1R1 or later, run monitor security packet-drop destination-prefix 192.0.2.10 count 50 while the problem occurs. It prints drop records with a reason and needs no commit. Pair it with show security flow statistics and screen statistics to spot a pattern.

Can the SRX notify the sender when a packet is dropped by a policy?

Yes, use then reject instead of then deny in the policy. For TCP the SRX sends a reset, and for UDP it returns an ICMP unreachable message. Use this on internal zones where fast failure helps users; on internet-facing zones, silent deny reveals less.