| LFT(8) | System Manager's Manual | LFT(8) |
lft — display the
route packets take to a network host/socket using one of several layer-4
protocols and methods; optionally show heuristic network information in
transitu
lft |
[-d dport]
[-s sport]
[-m retry min]
[-M retry max]
[-a ahead]
[-c scatter ms]
[-t timeout ms]
[-l min ttl]
[-H max ttl]
[-L length]
[-q ISN]
[-D device]
[-f device]
[-G icons path]
[-ACEINPRSTUVbeghinpruvxyzK]
[<gateway> <...>]
target:dport |
The Internet is a large and complex aggregation of network hardware, connected together by gateways. Tracking the route one's packets follow (or finding the miscreant gateway that's discarding your packets) can be difficult. (from traceroute(8))
lft was developed to automate a solution
to the above, taking into account that modern networks contain many
configurations of load balancers, proxies, and stateful firewalls.
lft implements numerous network tracing
methods and strategies. Generally, lft sends various
types of layer-4 probes utilizing the IP protocol `time to live' field and
attempts to elicit an ICMP `time exceeded in transit' response from each
gateway along the path to some host. RFC 1393 Traceroute Using an IP Option
is also available as one of several tracing methods.
lft additionally listens for various
messages along the way to assist network managers in ascertaining
per-protocol heuristic routing information. lft can
optionally retrieve various information about the networks it traverses
using a variety of sources such as registries, routing arbiters, etc.
The only mandatory parameter is the target host name or IP number. Options toggle the display of more interesting data or change the variables of the trace itself. The (-E/-e) adaptive option tries several combinations of TCP states (changing flags inside the probes it sends) in order to improve the chances of a successful trace and expose stateful packet filters.
Other options are:
-d
dport, --dport
dport-s
sport, --sport
sport-z,
--random-sport-m
min, --min-probes
min-M
max, --max-probes
max-a
ahead, --ahead
ahead-c
scatter ms, --scatter
scatter ms-t
timeout ms, --timeout
timeout ms-l
min ttl, --min-ttl
min ttl, --first-hop
min ttl-q
ISN, --isn
ISN-w
window, --tcp-window
window-L
length, --length
length, --bytes
length-K
is active; probe size is managed automatically by PMTUD.-K,
--mtu, --path-mtulft queries the local interface MTU via
ioctl(2) SIOCGIFMTU and starts
probing at that size (typically 1500 bytes for Ethernet, up to 9000 for
jumbo frames). All probes carry the DF (Don't Fragment) bit, which is
already lft's default.
When a router cannot forward a probe because it exceeds an
outbound link MTU, it returns an ICMP “fragmentation
needed” message (type 3, code 4) containing the
next-hop MTU. This class of message is colloquially called a
“PTB” (Packet Too Big), a term that strictly refers to
ICMPv6 Type 2 but is widely used for both IPv4 and IPv6.
lft records the MTU at the responding hop and
reduces subsequent probe sizes accordingly.
If a router silently drops an oversized DF probe without
returning an ICMP message (a PMTUD black hole),
lft flags the hop as “[MTU Limit]”
and steps down to the next RFC 1191 plateau value to continue
probing beyond the black hole.
PMTUD measures the forward-path MTU only; the return path may differ. Discovery stops at the first hop that limits the path MTU; hops beyond it see reduced-size probes that pass freely.
Probe
design and known limitations. lft
implements PMTUD by inflating the payload of its existing TCP, UDP, and
ICMP probes to the current MTU estimate. For TCP probes, strictly
speaking, SYN, FIN, and RST segments should carry no payload; some
deep-packet-inspection firewalls enforce this and will drop oversized
probes before they reach a bottleneck link. UDP datagrams and ICMP echo
requests may carry any payload size without protocol violation. This is
a known constraint of the technique for TCP mode.
An alternative approach — sending ICMP echo requests
exclusively for MTU probing, as ping(8) does with
-M do — was
considered but rejected. ICMP traffic is routinely deprioritized in
router control planes and discarded wholesale by enterprise firewalls,
making it a less faithful representation of real traffic and no more
likely to traverse a restricted path than a TCP probe.
The payload-inflation approach is preferred because it
exercises the same forwarding path as real application traffic. PTB
messages are generated by routers at the IP layer, before any TCP
inspection occurs, so the bottleneck is still correctly identified even
when the probe carries an atypical payload. On the public Internet
backbone — where MTU constraints most commonly arise —
core routers perform IP-layer forwarding without TCP payload inspection,
and the technique works reliably. Paths that traverse DPI firewalls
configured to reject TCP-with-payload would equally reject any active
PMTUD probing strategy; this is not a limitation specific to
lft.
-D
device, --device
device, --receive-device
devicelft will attempt to determine and acquire the
appropriate interface based on routing.-f
device, --from-device
device, --source-device
devicelft will attempt to determine and acquire the
appropriate interface based on routing. This serves to operate
lft in a passive mode where you may transmit from
a (potentially) spoofed IP address on one interface, yet receive on
another. This allows you to trace from a different IP address whose
traffic you can see in order to intercept replies.-H
ttl, --max-hops
ttl, --ttl-max
ttl-G
icons path, --graphviz-icons
icons path-I,
--minimize-delay-i,
--ignore-unreachables-E).-n,
--numeric-h,
--hostnames-only-E |
-e,
--adaptive-i
(--ignore-unreachables), allowing the trace to
continue through devices that send ICMP unreachable responses rather than
halting.-F,
--fin-u,
--udp-N,
--netname-PIn practice, no major router vendor — Cisco, Juniper, Nokia, Huawei, or any other — ever implemented RFC 1393 in their forwarding path. The mechanism suffered a chicken-and-egg problem: it required every router in the path to support the new IP option, whereas Van Jacobson's 1987 traceroute exploited TTL-expiry behavior already present in all routers and was universally deployed by the time RFC 1393 arrived. IP options processing also carries security risks, as options are handled in the router's slow path (control plane) and can be exploited for DoS amplification. Over time, ISPs and enterprises increasingly configured equipment to strip or drop packets carrying IP options entirely.
RFC 1393 never advanced beyond Experimental status. It was
formally deprecated by RFC 6814 in November 2012, which moved it to
Historic. RFC 7126 (February 2014) further recommends that routers
SHOULD drop packets containing the Traceroute IP option, noting zero
operational impact from doing so. This option is retained in
lft for completeness, but is unlikely to elicit
responses from any production network equipment.
-p,
--icmp-b,
--basic-tcp-A,
--asn-r,
--ripe-riswhois-C,
--cymru-R,
--radb-T,
--time-keeping-U,
--time-keeping-utc-S,
--quiet, --silent-x,
--xml-g,
--graphviz-o,
--ascii-A is used), network
name (when -N is used), round-trip time, and a
feature annotation line for seam, firewall, or target-state information.
In -n mode the IP address appears on
both the hostname and address lines for layout consistency. In
-h mode the IP address line is suppressed; TTL
information for cloaked hops moves to the AS number line so it shares a
row with AS data from other hops rather than occupying a mostly-blank
line of its own.
Cloaked hops, seam boundaries, firewall anomalies, and target state are each marked with a distinct feature label. In Unicode mode the labels are: ‘⇶ Stateful FW’ (stateful packet-inspecting firewall), ‘⚑ Flag FW’ (flag-based packet filter), ‘⇄ BSD Bug’ (errant TTL reuse anomaly), ‘╳ ASN Seam’ (autonomous system boundary crossing), ‘╳ NET Seam’ (network boundary crossing), ‘░cloaked░’ (no-reply hop), ‘[OPEN]’, ‘[FILTERED]’, and ‘[CLOSED]’ (target port state). Plain ASCII equivalents are used on terminals that do not support Unicode.
LFT automatically enables Unicode box-drawing characters and
ANSI color when the terminal supports them (detected via
TERM, COLORTERM, and
isatty(3)). Set NO_COLOR to
suppress color output. When the path is too wide for the terminal, the
diagram wraps onto additional rows.
-j
N, --stats
N-o). Each hop column renders a box-and-whisker
bar: the solid block marks the average RTT; the top cap (┬) and
bottom cap (┴) mark the maximum and minimum RTTs; the thin shaft
(│) between them shows the spread. Hops with no reply are rendered
as a full-width column of shade blocks (░). A Y-axis with labeled
RTT ticks appears at the left edge; the X-axis footer shows the end-to-end
RTT range derived from the target hop's own min/max samples and the
destination in
proto://address:port
format (e.g. ‘End-to-End RTT 15–81ms, 6 hops to
tcp://208.74.248.40:443’). If the target was not reached the footer
reads ‘N hops traced, target unreachable’. Columns with a
jitter spread exceeding 25 ms are highlighted in yellow with a
‘⚡ Nms Δ’ annotation.--no-ascii-chart,
--no-async-chart-j
while still collecting and displaying per-hop RTT statistics. Useful when
the terminal is too narrow for the chart, when output is piped to another
tool, or when only the numerical summary (min/avg/max/jitter) is needed.
Has no effect unless -j N is
also specified.-W
N,
--watch[=N,
--continuous[=N]]Subsequent cycles auto-tune the probe range and timeouts from the previously learned path; see Topology inheritance below.
View 1 (default) shows the
-o candlestick chart on the upper half of the
screen with a rolling statistics table below it.
View 2 replaces the chart with proportional RTT
bar columns. View 3 is a full-height statistics
table that shows more hops simultaneously. Switch views with
1,
2, or
3.
The statistics table columns are:
-h is active; see below).Intermediate hops that do not respond are shown as ‘*’ in the HOST column.
If -j is not specified, each cycle
collects 3 RTT samples per hop.
During each trace a live counter line is displayed showing (in order): replies received (↓N), probes sent (↑N), unique responding hops (⬡ N), and target reached status (✔ or ✗). Before ncurses initialises this line appears on the terminal directly; once ncurses is running it occupies the bottom status row of every view.
Keyboard controls:
1 –
3pp is pressed again.rcwhvx+ /
-qPath changes are detected automatically: when the set of responding hop addresses changes between cycles the change is highlighted in the status bar and held for three seconds.
For multi-cycle traces, watch mode preserves the per-protocol ECMP flow-identifier across cycles so every cycle traverses the same ECMP branch on multi-path networks: TCP source port, UDP IP-ID base, and the ICMP sequence-number anchor are all held constant for the life of the watch session. See lft(8) notes on ECMP flow-hash stability for the underlying mechanism.
Topology inheritance
After the first cycle, watch mode learns
the path length and RTT envelope and uses them to accelerate subsequent
cycles. Once the same number of hops has been observed for three
consecutive cycles, the TTL probe range narrows to
learned_num_hops
+ --learn-margin, the in-flight probe pipeline
widens to the full known path width (capped at 16), and the cloaked-hop
timeout drops to
max(8
× max_observed_rtt, 200 ms). A cycle that misses the
target or a change in probe protocol resets the learned state, reverting
to broad-scan defaults until the path stabilizes again.
--no-learn--learn-margin
NThis option requires ncurses support compiled into LFT. If
ncurses was not detected at build time, --watch
prints an explanatory error and exits. The minimum supported terminal
height is 24 rows. Superuser privileges (via sudo(8)
or a setuid-root installation) are required.
-y,
--verify-seam-V,
--verbose-v,
--version-Q,
--no-async-dns-Q flag reverts to the traditional synchronous
getnameinfo(3) path, which resolves each hop in sequence
after the trace completes. This flag is useful for debugging DNS issues or
for environments where parallel DNS queries are undesirable. If LFT was
built without c-ares, this flag is accepted but has no effect.--help--dport,
--min-probes,
--ignore-unreachables) are available for all short
options and are documented in this manual page alongside their short
counterparts.Any hosts listed after these options and before the final target
host will comprise a Loose Source and Record Route (LSRR).
lft encodes the specified intermediate addresses
into the IP options field of every probe, using option type 131 as defined
in RFC 791 (the original IPv4 specification).
LSRR on the modern Internet. The original purpose of source routing was to allow a sender to specify the path a packet should take through the network, useful in early research networks for debugging routing policy and deliberately routing around link failures. However, source routing can be exploited to bypass access controls, conduct reflective attacks, and probe otherwise-isolated network segments. As a consequence, virtually all ISPs and enterprise network operators block or silently strip packets carrying source route options at network ingress. RFC 7126 (February 2014) formally codified this practice, recommending that routers SHOULD drop packets containing LSRR or SSRR IP options, and noting zero operational impact from doing so because no production traffic legitimately uses them.
Why LSRR
is retained in lft. The feature remains for
controlled network environments where intermediate devices are
operator-managed and IP options processing is known to be enabled: lab
networks, private AS testing, research testbeds, and similar settings. In
such environments, specifying intermediate waypoints can verify specific
forwarding paths that are otherwise difficult to isolate. On any public
Internet path it will produce no additional hops in the output.
Caution:
accidental LSRR activation. Because -p (ICMP
probe mode) takes no argument, any extra token appearing between
-p and the target is silently parsed as an LSRR
intermediate hop rather than being flagged as an error. For example,
lft -p 192.168.1.1 target.example.com
would add 192.168.1.1 as a source route waypoint and embed a 12-byte LSRR IP option in every probe, almost certainly producing no responses from any modern router. The trace will appear to run normally but all hops will be cloaked. Verify command syntax carefully when using ICMP mode.
A sample use and output might be:
[edge.lax]$ lft -S 4.2.2.2 Hop LFT trace to vnsc-bak.sys.gtei.net (4.2.2.2):80/tcp 1 ln-gateway.centergate.com (206.117.161.1) 0.5ms 2 isi-acg.ln.net (130.152.136.1) 2.3ms 3 isi-1-lngw2-atm.ln.net (130.152.180.21) 2.5ms 4 gigabitethernet5-0.lsanca1-cr3.bbnplanet.net (4.24.4.249) 3.0ms 5 p6-0.lsanca1-cr6.bbnplanet.net (4.24.4.2) 3.4ms 6 p6-0.lsanca2-br1.bbnplanet.net (4.24.5.49) 3.3ms 7 p15-0.snjpca1-br1.bbnplanet.net (4.24.5.58) 10.9ms 8 so-3-0-0.mtvwca1-br1.bbnplanet.net (4.24.7.33) 11.1ms 9 p7-0.mtvwca1-dc-dbe1.bbnplanet.net (4.24.9.166) 11.0ms 10 vlan40.mtvwca1-dc1-dfa1-rc1.bbnplanet.net (128.11.193.67) 11.1ms ** [neglected] no reply packets received from TTLs 11 through 20 ** [4.2-3 BSD bug] the next gateway may errantly reply with reused TTLs 21 [target] vnsc-bak.sys.gtei.net (4.2.2.2) 11.2ms
The (-S) option was used to suppress the real-time status bar for clean output. LFT's "**" notifiers in between hops 10 and 21 represent additional useful information: the first is a "[neglected]" indicator that lets us know that none of the probes sent with the TTLs indicated elicited responses. This could be for a variety of reasons, but the cause of this specific occurrence is described in the next informative message which indicates that this is likely the result of a bug in the 4.[23] BSD network code (and its derivatives): BSD 4.x (x < 3) sends an unreachable message using whatever TTL remains in the original datagram. Since, for gateways, the remaining TTL is zero, the ICMP "time exceeded" is guaranteed to not make it back to us. LFT does its best to identify this condition rather than print lots and lots of hops that don't exist (trying to reach a high enough TTL).
Now, using the adaptive engine option:
[edge.lax]$ lft -E -S 4.2.2.1 Hop LFT trace to vnsc-pri.sys.gtei.net (4.2.2.1):80/tcp 1 ln-gateway.centergate.com (206.117.161.1) 0.5/0.5ms 2 isi-acg.ln.net (130.152.136.1) 2.1/2.3ms 3 isi-1-lngw2-atm.ln.net (130.152.180.21) 2.6/7.1ms 4 gigabitethernet5-0.lsanca1-cr3.bbnplanet.net (4.24.4.249) 6.1/3.9ms ** [firewall] the next gateway may statefully inspect packets 5 p0-0-0.lsanca1-csr1.bbnplanet.net (4.24.4.10) 155.4/3.7ms 6 [target] vnsc-pri.sys.gtei.net (4.2.2.1) 22.6/3.7/*/*/*/*/*ms
In the scenario above, the adaptive engine was able to identify a stateful, packet-inspecting firewall in the path. Another example with more options:
[edge.lax]$ lft -S -A -T -m 2 -d 80 -s 53 www.yahoo.com Hop LFT trace to w9.scd.yahoo.com (66.218.71.88):80/tcp 1 [226] ln-gateway.centergate.com (206.117.161.1) 1 ms 2 [226] isi-acg.ln.net (130.152.136.1) 2 ms 3 [226] isi-1-lngw2-atm.ln.net (130.152.180.21) 3 ms 4 [1] gigether5-0.lsanca1-cr3.bbnplanet.net (4.24.4.249) 3 ms 5 [1] p6-0.lsanca1-cr6.bbnplanet.net (4.24.4.2) 5 ms 6 [1] p6-0.lsanca2-br1.bbnplanet.net (4.24.5.49) 3 ms 7 [1] p1-0.lsanca2-cr2.bbnplanet.net (4.25.112.1) 3 ms 8 [16852] pos4-0.core1.LosAngeles1.Level3.net (209.0.227.57) 3 ms 9 [3356] so-4-0-0.mp1.LosAngeles1.Level3.net (209.247.10.193) 3 ms 10 [3356] so-3-0-0.mp2.SanJose1.Level3.net (64.159.1.130) 11 ms 11 [3356] gige10-0.ipcolo4.SanJose1.Level3.net (64.159.2.42) 11 ms 12 [3356] cust-int.level3.net (64.152.81.62) 52 ms 13 [10310] vl17.bas2.scd.yahoo.com (66.218.64.150) 53 ms 14 [10310] w9.scd.yahoo.com (66.218.71.88) [target] 54 ms LFT's trace took 5.23 seconds. Resolution required 3.58 seconds.
Note the -Ar above displays ASNs using the RADB as a whois source. A better option may have been to use the -A alone or perhaps -AC.
And why not request netblock lookups?
[edge.lax]$ lft -S -N www.microsoft.com Hop LFT trace to www.us.microsoft.com (207.46.197.113):80/tcp 1 [LOS-NETTOS-BLK4] ln-gateway.centergate.com (206.117.161.1) 2 ms 2 [LOS-NETTOS] isi-acg.ln.net (130.152.136.1) 3 ms 3 [LOS-NETTOS] isi-1-lngw2-pos.ln.net (130.152.80.30) 5 ms 4 [GNTY-4-0] gigether5-0.lsanca1-cr3.bbnplanet.net (4.24.4.249) 4 ms 5 [GNTY-4-0] p6-0.lsanca1-cr6.bbnplanet.net (4.24.4.2) 3 ms 6 [GNTY-4-0] p6-0.lsanca2-br1.bbnplanet.net (4.24.5.49) 3 ms 7 [GNTY-4-0] p15-0.snjpca1-br1.bbnplanet.net (4.24.5.58) 10 ms 8 [GNTY-4-0] p9-0.snjpca1-br2.bbnplanet.net (4.24.9.130) 11 ms 9 [GNTY-4-0] so-1-0-0.sttlwa2-br1.bbnplanet.net (4.0.3.229) 27 ms 10 [GNTY-4-0] so-0-0-0.sttlwa1-hcr1.bbnplanet.net (4.24.11.202) 28 ms 11 [GNTY-4-0] so-7-0-0.sttlwa1-hcr2.bbnplanet.net (4.24.10.234) 28 ms 12 [GNTY-4-0] p1-0.sttlwa1-cr2.bbnplanet.net (4.24.10.241) 29 ms 13 [GNTY-4-0] p2-0.msseattle.bbnplanet.net (4.25.89.6) 32 ms 14 [MICROSOFT-GLOBAL-NET] 207.46.154.9 32 ms 15 [MICROSOFT-GLOBAL-NET] 207.46.155.17 33 ms 16 [MICROSOFT-GLOBAL-NET] 207.46.129.51 [prohibited] 35 ms
If traces don't appear to go anywhere, there are a number of
things to try. If you are receiving an error related to permissions,
lft requires elevated privileges to open raw sockets
and capture packets via pcap(3). On Linux, the preferred
approach is to grant file capabilities rather than installing a setuid root
binary:
setcap cap_net_raw,cap_net_admin=eip
/usr/sbin/lftThis requires the libcap2-bin package on
Debian/Ubuntu or libcap on RHEL/Fedora. The
make install target attempts this automatically and
falls back to setuid root if setcap(8) is not available.
On FreeBSD, lft must be installed setuid root.
On macOS, lft must be
installed setuid root. This is because lft uses two
separate privilege paths: pcap(3) (via
/dev/bpf* devices) for
capturing
response packets, and a raw socket (SOCK_RAW) for
sending
probe packets. BPF device permissions (e.g., the ChmodBPF mechanism used by
Wireshark) only cover the capture side — they do not grant the
ability to create raw sockets, which on macOS requires root. Unlike Linux,
macOS has no setcap(8) equivalent to selectively grant raw
socket capability to a binary.
To install setuid root:
sudo chown root lft && sudo
chmod u+s lftmake install performs this step
automatically when run as root. This is standard practice for network
diagnostic tools on macOS; ping(8) and
traceroute(8) ship setuid root for the same reason.
If you do not receive permissions-related errors, but traces still don't go anywhere, first activate verbose output by adding -VV to your command line options. Then, reading the verbose output, if you see trace probes going out, but no replies being detected (as indicated by "RCVD" tags), you may: Use the TCP basic (-b) method if you wish to use TCP probes and you fear NAT may be causing your trace to fail. Alternatively, select a different trace method and protocol such as UDP (-u) or ICMP (-p).
If you are attempting to use RFC 1393 (-P) and your trace is failing, this is likely because network equipment somewhere in the path does not conform to RFC 1393. Your only option is to select an alternative tracing method or protocol.
If you are attempting to utilize adaptive mode (-E/-e) and traces fail, first try enabling NAT compatibility using TCP basic (-b). If traces still fail, the most likely reason is a close-proximity stateful firewall in your network, which prevents this feature from working.
Victor Oppleman, Eugene Antsilevitch, Sergey Kondryukov and other helpers around the world.
To report bugs, send e-mail to <lft@oppleman.com>
The lft command first appeared in 1998 as
'fft'. Renamed as a result of confusion with fast fourier transforms,
lft stands for 'layer four traceroute.' Thanks also
to Nils McCarthy for writing 'FFT', LFT's predecessor.
| April 7, 2026 | LFT |