Illustrative people-free WIUNIX Academy network workspace with a teaching board linking TCP packet size, ICMP feedback and retransmission diagnosis

WIUNIX ACADEMY

TCP stalls on Linux: diagnose PMTU black holes and retransmissions

Connect the real IPv4 TCP flow, socket retransmissions and bounded size/ICMP observations. Distinguish a PMTU hypothesis from loss and TLS/application symptoms without blind network changes.

Advanced35 min readUpdated
Make this guide yours

YOUR SYSTEM. YOUR STEPS.

Where are you working?

Choose your OS and version. The prerequisites, commands and troubleshooting follow your environment.

Ubuntu 24.04 LTSReviewed against official documentation ·

USE YOUR OWN VALUES

Configure this tutorial

Set the example values for your environment; related explanations and copy panels update together. Never enter passwords, private keys or tokens. Values stay in this tab and are not sent to the server or share links. Check actual DNS, certificates and network policy before running commands.

Different IP addresses, domains or ports? Open the settings below, change the values and select “Apply to tutorial”, then copy the updated commands.

Set values for my environment6 editable values

THE OUTCOME

What will you have at the end?

Connect the real IPv4 TCP flow, socket retransmissions and bounded size/ICMP observations. Distinguish a PMTU hypothesis from loss and TLS/application symptoms without blind network changes.

Supported operating systems and versions

Tool paths documented on 2026-11-05 for Ubuntu 26.10 and 26.04/24.04 LTS, Debian 13/12, RHEL/Rocky/AlmaLinux 10/9 and rolling Arch/Manjaro. These panels are limited to IPv4 TCP in the client network namespace; no executed all-environment matrix is claimed.

Before you begin

  • Authorized access to the affected client, an agreed destination, real flow tuple and failure time window.
  • Reviewed distribution tools and separately approved active probes/header observation; skip a branch without the required permission.
  • An existing harmless public HTTPS endpoint that permits HEAD and direct access, only for the optional HTTPS panel.
  • Private evidence handling for endpoint/port metadata; no credentials or customer data in fields/commands.

A connection opens, then useful work stalls

A successful TCP handshake or a small ping does not prove that larger packets can cross the path. Start with one affected client, destination IPv4 address, TCP port and time window. This guide separates evidence of retransmission, size-dependent failure and a later TLS/application failure. It does not treat every timeout as a PMTU black hole.

The concrete path here is ordinary IPv4 TCP on an existing Linux client. QUIC/HTTP3 uses UDP and IPv6 uses different Packet Too Big signaling; neither is covered by these exact packet filters. VPNs, containers, proxies, NAT and load balancers can change the observed path. Choose the network namespace that actually originates the connection.

Read-only socket and interface inspection comes first. Active ICMP/UDP probes and one optional HTTPS HEAD request require an authorized target and a permitted traffic window. No private application payload is captured or written to a packet file, and no MTU, MSS, firewall, offload or kernel setting is changed.

Confirm the public examples before copying

Open the native values form and replace the documentation-only addresses with the authorized destination and the local source address already assigned to this client. Select the real egress interface; do not guess eth0. The HTTPS hostname is only for the optional HEAD check and must already present a valid certificate at that address and port.

Apply the values before copying. Invalid or unapplied edits disable copying; Reset restores examples. Settings remain in this tutorial’s current browser tab and selected environment. Enter no passwords, cookies, customer URL paths or private request bodies. Custom values are not connectivity tests or proof of permission.

01

LET’S BUILD

Check tools on the real client

The distribution packages below supply current local tools; they install no server. iproute2 supplies ip and ss on DEB/Arch, while the RPM package is named iproute. DEB separates iputils-ping and iputils-tracepath; RHEL and Arch families package both under iputils. Use the installed versions and their local help, not an assumed common build.

These identity checks install nothing. Stop if the selected distribution is wrong. A missing ping capability, capture privilege or proc/netlink visibility is a preparation limit. Keep existing SELinux/AppArmor and container capability restrictions; do not grant blanket capabilities or disable host protection for the exercise.

Ubuntu 26.10 is the interim path with shorter support; 26.04/24.04 are LTS alternatives. Use this release’s official repositories.

bash

Authorized client-host terminal in the affected network namespace

cat /etc/os-release
uname -r
dpkg-query -W iproute2 iputils-ping iputils-tracepath tcpdump curl coreutils
command -v ip ss ping tracepath tcpdump curl timeout date
ip -V
ss -V
ping -V
curl --version
How do I know it worked?

The correct host family and available tool versions are recorded; resolve missing tools or privileges before the affected optional branch.

02

LET’S BUILD

Optional: obtain missing client tools in a maintenance window

Skip this panel if tools are already installed. Review the transaction on an authorized lab or maintenance host and use only this distribution’s official enabled repositories. Do not replace the client’s network manager, add a packet-capture daemon or start a new service.

The packet observer later needs narrowly approved administrative capture access; the tool package alone does not grant permission. If local policy prohibits capture, keep the socket/probe evidence and ask the network owner for corresponding router-side observations.

bash

Authorized client-host terminal in the affected network namespace

sudo apt-get update
sudo apt-get install iproute2 iputils-ping iputils-tracepath tcpdump curl coreutils
command -v ip ss ping tracepath tcpdump curl timeout
How do I know it worked?

Required commands exist after the reviewed package transaction; no service or permanent packet-capture capability is enabled.

03

LET’S BUILD

Record the source, interface and route lookup

Run in the affected client’s network namespace. Confirm 192.0.2.10 is assigned on eth0, then inspect the route lookup for 198.51.100.20 and TCP port 443. The link MTU is a local ceiling, not the discovered end-to-end PMTU. Tunnel overhead can reduce the size usable by the inner packet.

A route lookup does not send a test packet or prove reachability. Policy rules, marks, proxying and ECMP hashing can make the actual application flow differ from this simplified lookup; compare the real socket tuple in the next step. If the lookup chooses another source or interface, reconcile that difference before probing.

bash

Authorized client-host terminal in the affected network namespace

ip -4 address show dev 'eth0'
ip link show dev 'eth0'
ip -4 route get '198.51.100.20' from '192.0.2.10' ipproto tcp dport '443'
ip -s link show dev 'eth0'
How do I know it worked?

The chosen local address, link MTU and route are recorded with their scope. Interface errors/drops are observations, not a remote-loss percentage.

04

LET’S BUILD

Watch the same TCP connection over a bounded interval

Observe an already authorized application operation during its failure window; this panel generates no traffic. Match the complete local/remote address and port tuple across samples. A short-lived socket may disappear, and a new connection has fresh counters; never subtract one connection’s counter from another’s.

Read pmtu, mss, RTT/RTO, retransmission information and acknowledged-byte progress when the installed kernel/tool exposes them. Retransmission can follow congestion, reordering, a lost ACK or a size-related drop. A rising counter is evidence of retransmission, not the location or cause of loss. Missing fields are unavailable evidence rather than zero.

bash

Authorized client-host terminal in the affected network namespace

for sample in 1 2 3; do
  date -u +%FT%TZ
  ss -4 -t -i -n 'dst 198.51.100.20 and dport = :443'
  if test "$sample" != 3; then sleep 3; fi
done
How do I know it worked?

Three timestamped observations show connection identity and available TCP progress/counters; any missing or replaced socket remains explicit.

Explore all tutorials ↗