Skip to content

Trippy 0.11.0

Latest
Compare
Choose a tag to compare
@github-actions github-actions released this 11 Aug 12:28

Highlights

This release of Trippy adds NAT detection for IPv4/UDP/Dublin tracing, a new public API, reverse DNS lookup cache time-to-live, transient error handling for IPv4, a new ROFF manual page generator, several new columns, improved error messages and a revamped help dialog with settings tab hotkeys.

There are two breaking changes, a new initial sequence number is used which impacts the default behavior of UDP tracing and two configuration fields have been renamed and moved.

Finally, there are a handful of bug fixes and two new distribution packages, Chocolatey for Windows and an official PPA for Ubuntu and Debian based distributions.

NAT Detection for IPv4/UDP/Dublin

When tracing with the Dublin tracing strategy for IPv4/UDP, Trippy can now detect the presence of NAT (Network Address Translation) devices on the path.

RFC 3022 section 4.3 requires that "NAT to be completely transparent to the host" however in practice some fully compliant NAT devices leave behind a telltale sign that Trippy can use.

Trippy will indicate if a NAT device has been detected by adding [NAT] at the end of the hostname. There is also a new (hidden by default) column, Nat, which can be enabled to show the NAT status per hop.

NAT devices are detected by observing a difference in the expected and actual checksum of the UDP packet that is returned as the part of the Original Datagram in the ICMP Time Exceeded message. If they differ then it indicates that a NAT device has modified the packet. This happens because the NAT device must recalculate the UDP checksum after modifying the packet (i.e. translating the source port) and so the checksum in the UDP packet that is nested in the ICMP error may not, depending on the device, match the original checksum.

To help illustrate the technique, consider sending the following IPv4/UDP packet (note the UDP Checksum B here):

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ │             
|Version|  IHL  |Type of Service|          Total Length         | │             
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ │             
|         Identification        |Flags|     Fragment Offset     | │             
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ │             
|  Time to Live |    Protocol   |            Checksum A         | │ IPv4 Header 
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ │             
|                         Source Address                        | │             
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ │             
|                      Destination Address                      | │             
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ │             
                                                                                
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ │             
|          Source Port          |        Destination Port       | │             
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ │ UDP Header  
|             Length            |            Checksum B         | │             
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ │                                                                                             

Trippy expect to receive an IPv4/ICMP TimeExceeded (or other) error which contains the Original Datagram (OD) IPv4/UDP packet that was sent above with Checksum B' in the Original Datagram (OD) IPv4/UDP packet:

 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ │                                    
 |Version|  IHL  |Type of Service|          Total Length         | │                                    
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ │                                    
 |         Identification        |Flags|     Fragment Offset     | │                                    
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ │                                    
 |  Time to Live |    Protocol   |            Checksum C         | │ IPv4 Header                        
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ │                                    
 |                         Source Address                        | │                                    
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ │                                    
 |                      Destination Address                      | │                                    
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ │                                    
                                                                                                        
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ │                                    
 |      Type     |      Code     |            Checksum D         | │                                    
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ │ IPv4 Payload (ICMP TE Header)      
 |                             Unused                            | │                                    
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ │                                    
                                                                   │                                    
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ │ │                                  
 |Version|  IHL  |Type of Service|          Total Length         | │ │                                  
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ │ │                                  
 |         Identification        |Flags|     Fragment Offset     | │ │                                  
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ │ │                                  
 |  Time to Live |    Protocol   |            Checksum A'        | │ │ ICMP TE Payload (OD IPv4 Header) 
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ │ │                                  
 |                         Source Address                        | │ │                                  
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ │ │                                  
 |                      Destination Address                      | │ │                                  
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ │ │                                  
                                                                   │ │                                  
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ │ │ │                                
 |          Source Port          |        Destination Port       | │ │ │                                
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ │ │ │ OD IPv4 Payload (UDP header)   
 |             Length            |            Checksum B'        | │ │ │                                
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ │ │ │                                

If Checksum B' in the UDP packet nested in the ICMP error does not match Checksum B in the UDP packet that was sent then Trippy can infer that a NAT device is present.

This technique allows for the detection of NAT at the first hop. To detect multiple NAT devices along the path, Trippy must also check for changes in the observed checksum between consecutive hops, as changes to the UDP checksum will "carry forward" to subsequent hops. This requires taking care to account for hops that do not respond. This is only possible when using the Dublin tracing strategy, as it does not modify the UDP header per probe; therefore, the checksums are expected to remain constant, allowing changes in the checksum between hops to be detected.

Note that this method cannot detect all types of NAT devices and so should be used in conjunction with other methods where possible.

See the issue for more details.

Public API

Trippy has been designed primarily as a standalone tool, however it is built on top of a number of useful libraries, such as the core tracer, DNS resolver and more. These libraries have always existed but were tightly integrated into the tool and were not designed for use by third party crates.

This release introduces the Trippy public API which can be used to build custom tools on top of the Trippy libraries.

The full set of libraries exposed is:

Crate Description
trippy Common entrypoint crate
trippy-core The core Trippy tracing functionality
trippy-packet Packet wire formats and packet parsing functionality
trippy-dns Perform forward and reverse lazy DNS resolution
trippy-privilege Discover platform privileges
trippy-tui The Trippy terminal user interface

To use the Trippy public API you should add the common entrypoint trippy crate to your Cargo.toml file and then enable the desired features. Note that the trippy crate includes tui as a default feature and so you should disable default features when using it as a library. Alternatively, it is also possible to add the crates individually.

For example, to use the core Trippy tracing functionality you would add the trippy crate, disable default features and enable the core feature:

[dependencies]
trippy = { version = "0.11.0", default-features = false, features = ["core"] }

The hello-world example below demonstrates how to use the Trippy public API to perform a simple trace and print the results of each round:

use std::str::FromStr;
use trippy::core::Builder;

fn main() -> anyhow::Result<()> {
    let addr = std::net::IpAddr::from_str("1.1.1.1")?;
    Builder::new(addr)
        .build()?
        .run_with(|round| println!("{:?}", round))?;
    Ok(())
}

Whilst Trippy adheres to Semantic Versioning, the public API is not yet considered stable and may change in future releases.

See crates and the usage examples for more information.

New Initial Sequence

For UDP tracing, by default, Trippy uses a fixed source port and a variable destination port which is set from the sequence number, starting from an initial sequence of 33000 and incremented for each probe, eventually wrapping around.

By convention, many devices on the internet allow UDP probes to ports in the range 33434..=33534 and will return a DestinationUnreachable ICMP error, which can be used to confirm that the target has been reached. Since Trippy does not use destination ports in this range for UDP probes by default, the target host will typically not respond with an ICMP error, and so Trippy cannot know that the target was reached, and must therefore show the hop as unknown.

Another issue with this default setup is that the sequence number will eventually enter the range 33434..=33534 at which point the target will begin to respond with the DestinationUnreachable ICMP error. However, there is no guarantee that the probe sent for sequence 33434 (i.e., the first one for which the target host will be able to respond) will be for the minimum time-to-live (ttl) required to reach the target. This leads to confusing output, which is hard for users to interpret. See issue for more details.

These issues can be avoided today, either by changing the initial sequence number to be in the range 33434..=33534 by setting the --initial-sequence flag or by using a fixed destination port (and therefore a variable source port) in the same range by setting the --target-port flag.

In the following example, the initial sequence number is set to 33434:

trip example.com --udp --initial-sequence 33434

This can be made permanent by setting the initial-sequence value in the strategy section of the configuration file:

[strategy]
initial-sequence = 33434

In the following example, the destination port is set to 33434:

trip example.com --udp --target-port 33434

This can be made permanent by setting the target-port value in the strategy section of the configuration file:

[strategy]
target-port = 33434

As the default behavior in Trippy leads to these confusing issues, this release modifies the default sequence number to 33434. This is a breaking change and will impact users who rely on the old default initial sequence number.

This change introduces a new problem, albeit a lesser one: UDP traces will now begin with a destination port of 33434 and so DestinationUnreachable ICMP errors will typically be returned by the target immediately. However, eventually the sequence number will move beyond the range 33434..=33534 and so the target host will stop responding with DestinationUnreachable ICMP errors. This leads to the appearance that the target has started dropping packets. While this is technically correct, this is not desirable behavior as the target has not really disappeared.

It is therefore recommended to always fix the target-port to be in the range 33434..=33534 for UDP tracing and allow the source port to vary instead. This may become the default behavior for UDP tracing in a future release; that would represent a significant difference in default behavior compared to most traditional Unix traceroute tools, which vary the destination port by default.

Reverse DNS Lookup Cache Time-to-live

Trippy performs a reverse DNS lookup for each host encountered during the trace and the resulting hostnames are cached indefinitely. This can lead to stale hostnames being displayed in the TUI if they change after the trace has begun.

Note that the DNS cache can be flushed manually by pressing ctrl+k (default key binding) in the TUI.

Starting from this release, the reverse DNS cache can be configured to expire after a certain time to live. By default this is set to be 5 minutes (300 seconds) and can be configured using the --dns-ttl flag or the dns-ttl configuration option.

The following example sets the DNS cache time-to-live to 30 seconds:

trip example.com --dns-ttl 30s

This can be made permanent by setting the dns-ttl value in the dns section of the configuration file:

[dns]
dns-ttl = "30s"

Transient Error Handling for IPv4

Trippy records the number of probes sent and the number of probes received for each hop and uses this information to calculate packet loss. Any probe that is successfully sent for which no response is received is considered lost.

Currently, if a probe cannot be sent for any reason, then Trippy will crash and show a BSOD. This is not typically an issue, as such failures imply a local issue with the host network configuration rather than an issue with the target or any intermediate hops.

However, it is possible that a probe may fail to send for a transient reason, such as a temporary local host issue, and so it would be useful to be able to handle such errors gracefully. A common example would be running Trippy on a host and during the trace disabling the network interface.

Starting from this release, Trippy will continue the trace even if a probe fails to send and will instead show a warning to the user in the TUI about the number of probe failures. A new column (hidden by default), Fail, has also been added to the TUI to show the number of probes that failed to send for each hop.

This has been implemented for macOS, Linux and Windows for IPv4 only. Support for IPv6 and other platforms will be added in future releases.

See the tracking issue for more details.

Generate ROFF Man Page

Trippy can now generate manual pages in ROFF format. This can be useful for users who wish to install Trippy on systems which do not have a package manager or for users who wish to install Trippy from source. It can also be used by package maintainers to generate manual pages for their distribution.

The following command generates a ROFF manual page for Trippy:

trip --generate-man > /path/to/man/pages/trip.1

New Columns

This release introduced several new columns, all of which are hidden by default. These are:

  • Type: The ICMP packet type for the last probe for the hop
  • Code: The ICMP packet code for the last probe for the hop
  • Nat: The NAT detection status for the hop
  • Fail: The number of probes which failed to send for the hop

The following shows the Type and Code columns:

See the Column Reference for a full list of all available columns.

Settings Dialog Tab Hotkeys

The settings dialog can be accessed by pressing s (default key binding) and users can navigate between the tabs using the left and right arrow keys (default key bindings). This release introduces hotkeys to allow users to jump directly to a specific tab by pressing 1-7 (default key bindings).

See the Key Bindings Reference for details.

Help Dialog Revamped

The existing Trippy help dialog shows a hardcoded list of key bindings which may not reflect the actual key bindings the user has configured. Trippy shows the correct key bindings in the settings dialog which can be accessed by pressing s (default key binding) and navigating to the Bindings tab. Therefore, the key bindings in the help dialog are both potentially incorrect and redundant.

This release revamps the help dialog and includes instructions on how to access the key bindings from the settings dialog as well as some other useful information.

Improved Error Messages

Error reporting has been improved for parameters such as --min-round-duration (-i). Previously, if an invalid duration was provided, the following error would be reported:

$ trip example.com -i 0.05
Error: invalid character at 1

Starting from this release, such error will instead be shown as:

$ trip example.com -i 0.05
error: invalid value '0.05' for '--min-round-duration <MIN_ROUND_DURATION>': expected time unit (i.e. 100ms, 2s, 1000us)

For more information, try '--help'.

This covers all "duration" parameters, namely:

  • min_round_duration
  • max_round_duration
  • grace_duration
  • read_timeout
  • dns_timeout
  • tui_refresh_rate

Renamed Configuration

The following configuration fields have been renamed and moved from the [tui] to the [strategy] section in the configuration file:

  • tui-max-samples -> max-samples
  • tui-max-flows -> max-flows

This is a breaking change. Attempting to use the legacy field names will result in an error pointing to the new name.

The following example shows the error reported if the old names are used from the command line:

error: unexpected argument '--tui-max-samples' found

  tip: a similar argument exists: '--max-samples'

The following examples shows the error reported if the ld names are used from the configuration file:

Error: tui-max-samples in [tui] section is deprecated, use max-samples in [strategy] section instead

Bug Fixes

This release fixes a bug where DestinationUnreachable ICMP errors were assumed to have been sent by the target host, whereas they may also be sent by an intermediate hop.

Another fix addresses an issue where the TUI would calculate the maximum number of hops to display based on the maximum observed across all rounds rather than for the latest round.

Finally, a minor bug was fixed where AddressInUse and AddrNotAvailable errors were being conflated.

New Distribution Packages

Trippy has been added to the Chocolatey community repository (with thanks to @Aurocosh!):

Chocolatey package

choco install trippy

Trippy also has an official PPA for Ubuntu and Debian based distributions (with thanks to @zarkdav!):

Ubuntu PPA

sudo add-apt-repository ppa:fujiapple/trippy
sudo apt update && apt install trippy

You can find the full list of distributions in the documentation.

Thanks

My thanks to all Trippy contributors, package maintainers and community members.

Feel free to drop by the new Trippy Zulip room for a chat:

project chat

Happy Tracing!

Change Log

Added

  • Added NAT detection for IPv4/udp/dublin (#1104)
  • Added public API (#1192)
  • Added support for NAT detection (N) column (#1219)
  • Added support for last icmp packet type (T) column (#1105)
  • Added support for last icmp packet code (C) column (#1109)
  • Added support for the probe failure count (f) column (#1258)
  • Added settings dialog tab hotkeys (#1217)
  • Added --dns-ttl flag to allow refreshing the reverse DNS results (#1233)
  • Added --generate-man flag for generating ROFF man page (#85)
  • Added Ubuntu PPA package (#859)
  • Added Chocolatey package (#572)

Changed

  • [BREAKING CHANGE] Changed initial sequence to be 33434 (#1203)
  • [BREAKING CHANGE] Renamed tui-max-[samples|flows] as max-[samples|flows] (#1187)
  • Separated library and binary crates (#1141)
  • Record icmp packet code (#734)
  • Transient error handling for IPv4 on macOS, Linux & Windows (#1255)
  • Improved error messages (#1150)
  • Revamp the help dialog (#1260)

Fixed

  • Fixed DestinationUnreachable incorrectly assumed to come from target host (#1225)
  • Fixed incorrect target hop calculation (#1226)
  • Do not conflate AddressInUse and AddrNotAvailable errors (#1246)

See CHANGELOG.md for details.

Full Changelog: 0.10.0...0.11.0