Getting through.
The path is only as visible as the filters allow. LFT has a flag for each kind of filter — and it tells you which kind it found.
Adapt to firewalls
-E is adaptive mode: instead of committing to one kind of probe, LFT tries each in turn — a FIN, then a SYN-ACK, then a plain SYN — and keeps whichever one a given hop answers. A gateway that ignores a bare SYN may still reply to a FIN, and the reverse, so cycling the flags walks a trace past filters that any single method would stall on.
While it adapts, it names what it meets. When a nearer hop answers a FIN but the hop beyond it answers only once LFT escalates to SYN, a stateful inspector sits between them, and the trace prints [firewall] the next gateway may statefully inspect packets. A hop that passes just one flag combination is a flag-based state filter, and it is labelled too. Adaptive mode also carries on through administratively-prohibited and unreachable replies, so one blocked hop does not end the trace: it implies -i.
Send what the firewall expects
By default, LFT sends TCP SYN to port 443 — the one packet almost every border admits. -d or target:port picks another service, which also shows whether packets route differently by destination port.
Each hop in a one-shot trace uses its own source port, so a stateful firewall cannot treat the whole trace as one flow and rate-limit it; retries to a silent hop take a fresh port so same-flow duplicate suppression does not hide the hop.
-B (--realistic) adds a genuine client option block — MSS, SACK-permitted, timestamps, window scale — so SYN-scrubbing firewalls do not discard a bare SYN. It changes only the packets on the wire, not LFT's output.
Or send what it does not track
-F sends FIN probes; a filter with no state table forwards them as if a handshake had already happened — the building block adaptive mode reaches for first. -b is the NAT-tolerant TCP engine for when sequence numbers are being rewritten.
Read the result
The target line says [target open], [target closed] or [target filtered]. Silent near hops (TTL 1–3) no longer count toward the give-up threshold, so a quiet local edge does not stop a trace whose core and target answer. In the ASCII, SVG, GraphViz and Mermaid outputs, stateful and flag-based firewalls get their own glyph; in JSON, hops[].firewall is stateful, flag, bsd_bug or null.
A stateful inspector, found and named
[host]$ lft -S -E eggs.gnu.org:587 TTL LFT trace to eggs.gnu.org (209.51.188.92):587/tcp 1 192.0.2.1 0/1/1 ±0ms ** [neglected] no reply packets received from TTLs 2 through 4 5 nyiix-px.jfk01.twdx.net (198.32.160.208) 2/2/2 ±0ms 6 bbr02-ae-4-901.bos01.twdx.net (198.160.63.126) 7/7/7 ±0ms 7 dcr03-hu-0-8-0-0.bsn04.twdx.net (198.160.62.201) 7/7/7 ±0ms ** [firewall] the next gateway may statefully inspect packets 8 mass-ix.fsf.org (206.53.143.61) 7/7/7 ±0ms 9 [target open] eggs.gnu.org (209.51.188.92):587 7.4ms
A flag-based filter, and a closed port
[host]$ lft -S -E mit.edu:443 TTL LFT trace to a23-50-69-136.deploy.static.akamaitechnologies.com (23.50.69.136):443/tcp 1 192.0.2.1 0/0/0 ±0ms ** [neglected] no reply packets received from TTLs 2 through 4 5 198.32.160.147 2/2/2 ±0ms 6 192.168.225.129 2/2/2 ±0ms 7 192.168.238.169 2/2/2 ±0ms ** [firewall] the next gateway may implement a flag-based state filter 8 192.168.194.131 2/2/2 ±0ms 9 [target closed] a23-50-69-136.deploy.static.akamaitechnologies.com (23.50.69.136):443 12.0ms
"Such devices will forward the packet to its destination rather than filter it, assuming a handshake has already taken place." — lft(8), on -F
Firewalls get their own glyph.
Real --svg output from the two traces above. Blue is a stateful inspector; orange is a flag-based filter; the dashed card is the cloaked run of TTLs 2–4.
The troubleshooting ladder
- Nothing past hop 1? Your own edge counts the flow. Per-hop source ports are already the default; add
-Bso the SYN looks like a real client's. - Stalls at a border? Try
-E. It will cycle FIN, SYN-ACK and SYN and tell you what kind of filter it met. - Sequence numbers rewritten by NAT?
-b, the basic TCP engine, stops depending on them. - ICMP unreachables ending the trace?
-icontinues through codes 0, 1, 2, 3, 9, 10 and 13. - Still dark? Switch families with
-uor-pand compare which one the path admits.
What -B puts on the wire
A bare SYN looks fake to a normalizing firewall. With -B, LFT's SYN carries the option block a real client would send:
| MSS | Maximum segment size |
| SACK-permitted | Selective acknowledgement |
| Timestamps | TSval / TSecr |
| Window scale | Window scaling factor |
| NOP padding | Alignment, as real stacks emit |
Default and adaptive TCP engines only; ignored for -b, -u and -p. Off by default.