Some of the hardest firewall tickets sound like ghost stories. A connection that works fine between two hosts dies the moment it crosses the ASA, both endpoints swear nothing is wrong, and there is no deny in any ACL. Nine times out of ten the culprit is TCP normalization, the ASA's silent enforcer of TCP correctness, and the only evidence it leaves is a counter most people never look at. This article is part of our Cisco ASA series, and it turns that ghost into something you can see, using a real tcp-map and the real accelerated-security-path drop counters from an ASAv 9.24 in CML.
TCP normalization is a set of checks the ASA runs on every TCP segment to make sure the connection behaves like a proper, in-order, standards-compliant TCP flow. Packets that fail those checks are dropped. That is a good thing when the packets really are malformed or part of an attack, and a maddening thing when an overly strict normalizer drops traffic the endpoints considered perfectly valid. Either way, the box is doing exactly what it was told, and learning to read its drop counters is how you tell the difference.
What the normalizer checks
The ASA normalizes TCP by default, and you can tune it with a tcp-map. The map is a bundle of individual checks, each of which can drop, clear, or allow a particular kind of anomaly. A few of the common ones:
- check-retransmission - verify that a retransmitted segment matches the original, catching retransmission-based evasion.
- exceed-mss - decide what to do with segments larger than the negotiated maximum segment size, either allow or drop them.
- urgent-flag - allow or clear the TCP URG pointer, which is frequently abused and rarely legitimately needed.
- tcp-options - control which TCP options are permitted, cleared, or cause a drop.
You bundle these into a named tcp-map and then apply it through the Modular Policy Framework, exactly like every other ASA feature from our MPF walkthrough. The map is the action; MPF is how it reaches the traffic.
Building and applying a tcp-map
Here is a small normalizer that checks retransmissions and drops oversized segments, applied globally to all traffic.
tcp-map PLZ-TCP-NORM
check-retransmission
exceed-mss drop
class-map PLZ-TCP-CLASS
match any
policy-map global_policy
class PLZ-TCP-CLASS
set connection advanced-options PLZ-TCP-NORMThe three layers are the ones you already know. The tcp-map defines the checks. The class-map with match any selects all traffic. The policy-map attaches the map to that class with set connection advanced-options, which is the specific action that plugs a tcp-map into MPF. Because we added it to global_policy, it now applies everywhere the global service-policy does.
Confirm it is live by reading the global service-policy and filtering to the connection settings.
FW1# show service-policy global | include Set connection|advanced
Set connection policy: drop 0 embryonic drop 0
Set connection advanced-options: PLZ-TCP-NORMThe line Set connection advanced-options: PLZ-TCP-NORM is the confirmation that our tcp-map is bound and active on the global policy. If that line is missing, the map exists in the config but is not doing anything, the same "defined but not applied" trap that catches every MPF feature.
The star command: show asp drop
Here is the command that solves the ghost stories. The accelerated security path (ASP) is the ASA's fast-path forwarding engine, and it keeps a running tally of every packet it drops and why. TCP normalization drops land here, alongside a long list of other fast-path discard reasons. On our lab box, after ambient traffic, the counters looked like this:
FW1# show asp drop
Invalid UDP Length (invalid-udp-length) 2
First TCP packet not SYN (tcp-not-syn) 10
TCP RST/FIN out of order (tcp-rstfin-ooo) 2Every one of those lines is a packet the ASA dropped without any ACL involved, and each names its reason in the parentheses. This is the single most useful "why did my packet vanish" command on the box, because it is the one place the firewall admits to dropping traffic that no ACL touched. When a connection fails and the ACLs are clean, this is where you look next.
Why each counter fired
Read the reasons, because they teach you how the stateful engine thinks.
tcp-not-syn (10) is the headline. The ASA is stateful, which means it expects a TCP connection to begin with a SYN so it can build a state entry for the flow. If the very first packet the firewall sees for a flow is not a SYN, the ASA has no state for that connection and, by default, drops it as tcp-not-syn. This happens constantly in the real world: a connection that was established before the firewall booted, an asymmetric path where the return traffic arrives on the ASA but the initial SYN went another way, or a flow that failed over from another device mid-stream. All of them look identical to the ASA, a first packet with no SYN and no state, and all of them get dropped. Ten such packets is completely ordinary ambient noise on any segment.
tcp-rstfin-ooo (2) catches RST or FIN segments that arrive out of order, outside the valid sequence window for the connection. Out-of-order teardown packets can be a sign of an evasion attempt or simply of a messy network, and the normalizer discards them rather than letting them tear down a connection they should not.
invalid-udp-length (2) is not TCP at all; it is the ASP dropping UDP datagrams whose declared length does not match reality, a basic malformed-packet check. It is in the same output because show asp drop is the catch-all for fast-path discards, which is exactly why it is so useful: one command, every silent drop reason, in one place.
tcp-not-syntcp-rstfin-oooinvalid-udp-lengthDefault normalizer versus a custom tcp-map
It is worth being clear that you get normalization whether or not you ever write a tcp-map. The ASA applies a default normalizer to every TCP connection, and that default is already responsible for the tcp-not-syn drops above; no configuration of ours caused them. What a custom tcp-map does is let you tighten or loosen specific checks beyond the defaults, for example adding check-retransmission or changing how oversized segments are handled.
This distinction matters when you are troubleshooting, because engineers often assume that with no tcp-map configured the ASA is not normalizing at all. It is. If you genuinely need the firewall to accept a mid-stream flow that begins with something other than a SYN, the answer is not to remove a tcp-map you never created; it is to configure TCP state bypass for that specific traffic, which tells the ASA to forward the flow without building or enforcing full TCP state. That is a deliberate, scoped exception, and it is the correct tool for asymmetric designs rather than weakening the normalizer for everything.
The silent connection killer
Now the part that makes this feature worth a whole article. Because normalization runs in the fast path and drops packets without generating a per-packet deny that shows up where people usually look, an over-aggressive tcp-map can quietly break connections that look completely healthy from both endpoints. The client sends, the server never sees it, and neither machine logs anything unusual because from their point of view the packet was simply lost. There is no deny message on a screen anyone is watching. The only evidence that the firewall did it is a number climbing in show asp drop.
This is why TCP normalization earns the nickname "silent connection killer". Turn on a strict option like dropping all segments that exceed MSS, or clearing an option some legitimate application actually depends on, and you can introduce failures that survive hours of endpoint troubleshooting because nobody is looking at the firewall's ASP counters. Even the default normalizer, before you configure a single custom option, drops tcp-not-syn packets, which is exactly why asymmetric-routing designs and firewall-insertion projects so often surface mysterious connection failures on day one.
The lesson is procedural. When a connection dies crossing the ASA and the ACLs are clean, run show asp drop before you do anything else. Note the counters, reproduce the failure, run it again, and see which counter moved. The counter that increments is your answer. If it is tcp-not-syn, you are looking at a state or asymmetry problem, not a policy problem, and the fix is on the routing or the TCP-state-bypass side, not in an ACL. If it is a normalization reason tied to a custom tcp-map option, you have found an over-strict setting, and you can relax that specific check rather than tearing the whole map out.
Tuning without breaking things
A tcp-map is a scalpel, so use it like one. Add checks one at a time and watch the corresponding show asp drop counter before and after, so you know exactly what each option is dropping in your environment. If a counter climbs faster than you expected, you have caught a legitimate flow in the net, and you can decide whether to loosen the option or fix the traffic that triggered it. The goal is a normalizer strict enough to catch genuinely malformed or evasive TCP, but not so strict that it drops the slightly-imperfect-but-harmless segments real applications routinely send.
Where this all sits in the ASA's processing order matters too, because normalization happens in the fast path after the connection is established, not at the ACL stage. That is precisely why an ACL check can pass while a packet still vanishes: the two live at different points in the flow. Our ASA packet flow article maps that ordering out, and it is the model that finally makes show asp drop feel predictable rather than mysterious.
Key Takeaways
- TCP normalization silently drops malformed or out-of-state TCP. It is on by default and tunable with a
tcp-mapapplied viaset connection advanced-options. show asp dropis the star command. It is the one place the ASA records fast-path drops that no ACL caused, the definitive "why did my packet vanish" tool.- Read the drop reasons.
tcp-not-syn 10means a first packet arrived with no SYN and no state (asymmetry or a pre-existing flow);tcp-rstfin-ooo 2caught out-of-order teardown;invalid-udp-length 2is a malformed UDP check. - The silent killer is real. An over-strict tcp-map drops packets that look fine to both endpoints, leaving no evidence except a climbing ASP counter.
- Diagnose by watching the counter move. Reproduce the failure and see which
show asp dropline increments; that reason is your root cause.
Once you know show asp drop exists, a whole category of "impossible" firewall problems becomes routine. Continue through the Cisco ASA series, and pair this with the ASA packet flow article to see exactly where in the processing order these silent drops happen.