You captured traffic on the IPsec host, watched ESP packets leave, saw nothing come back, and concluded that the far side is broken. The capture does not support that conclusion. ESP protects one direction of a conversation and acknowledges nothing at the IP layer, so missing return ESP can mean the application had nothing to say just as easily as it can mean the tunnel is dead. Read the inner exchange and the receive-side state before you blame either end.

The myth: every protected packet earns a reply

ESP is not a request-response protocol. It encrypts and authenticates whatever the policy selects, and the receiver validates, decrypts and delivers that inner packet without generating a packet of its own. A UDP query that the destination ignores, or an ICMP echo that inbound policy discards, produces silence in both directions as the correct outcome. Treating that silence as a transport failure sends you hunting a network fault that was never there.

What a one-way capture actually proves is that the sender's stack encrypted something at that observation point. Nothing about arrival, and nothing about intent to answer. The useful question is not "why is there no reply" but "what should the inner conversation have produced".

Two SAs, two SPIs, one conversation

IPsec security associations are unidirectional, so a normal protected exchange runs an inbound association and an outbound association with separate identifiers and independent state. Hunting the return traffic for the outbound packet's SPI is therefore a category error, because any reply travels under the peer's own outbound SA with its own SPI. Match the pair by traffic selectors and peer addresses instead.

Rekeying complicates the picture for a few seconds at a time, since old and replacement state can overlap. If the symptom started around a rekey, collect association identifiers and timestamps together rather than only the connection name.

What the receiver has to do before anything replies

StageWhat to look atWrong conclusion if skipped
Sender encryptsoutbound SA packet counter"the tunnel is up"
Peer receivesinbound SA counter and replay window"the peer is down"
Inner deliverytarget host or service logs"routing is broken"
Application repliesthe app's own trace"the reply was dropped"
Protected returnthe peer's outbound SA"ESP only works one way"

Every row fails independently and each failure has a different owner, which is why a single capture cannot tell them apart. The inbound counter is the only direct evidence of arrival, because a packet that fails its authentication or replay check is discarded without any response. A peer whose inbound counter has not moved is therefore sending you no information about its policy at all.

Delivery is a separate step from decryption. State can be valid and the packet still dropped afterwards by an inbound policy or a route that does not include the inner destination, so check whether the target host saw plaintext rather than assuming a clean counter means the packet went where you wanted it.

Native ESP is not UDP

Native ESP is IP protocol 50, which is neither TCP nor UDP and has no ports whatsoever. A firewall rule permitting IKE on UDP 500 therefore says nothing about the data path, and a filter written around ports can let a tunnel negotiate and then drop everything carried inside it. Test the data path on its own, in the mode you actually observed.

Behind a NAT the shape changes: the protected payload travels inside UDP, commonly on port 4500, as RFC 3948 defines. Record the active mode before writing any rule, because a device on the path can treat native ESP and UDP-encapsulated ESP completely differently, and some middleboxes permit one while dropping the other.

Read counters that belong to this incident

On a strongSwan host, swanctl --list-sas reports per-association packet and byte counters in both directions, which is enough to separate "never arrived" from "arrived and was not answered". On Linux, /proc/net/xfrm_stat counts aggregate failures such as missing state, missing policy and protocol errors. Those totals accumulate from boot and belong to one network namespace, so a big number is not an attribution.

Take two readings around the incident window in the correct namespace and compare deltas, otherwise you will pin last week's errors on this afternoon's ticket. Put the namespace and both timestamps in the ticket so the next reader can reproduce the comparison instead of trusting a total.

Name the stage, not the suspect

A useful conclusion says where the packet stopped: never received, received and discarded, delivered but unanswered, or answered and lost on the way back. Each of those points at a different owner and a different next command. "No response from the VPN server" collapses four distinct faults into one sentence that the capture never justified.

Keep captures narrow, and keep raw kernel state out of tickets, since it can carry key material that has no business leaving the host. The counter deltas and the timestamps are the parts worth handing to the next person.

ХӀокхунах тера йаззамаш