Changelog¶
[Unreleased]¶
Added¶
- Screenshots in the README: real runs of
monitor,dnscheck,http,tlsandpropagation, rendered as SVG byscripts/screenshot.pyand refreshed by the manual Screenshots workflow.
Fixed¶
xping dnscheckscored a domain it could not query at all (every DNS query timed out) 100/100 EXCELLENT. It now reports an error, exits 1, and--min-score/ check files fail.- Section headers were one column wider than the terminal, so their rule
wrapped a
─onto the next line in terminals that wrap at the edge. - The Launchpad PPA release job installs the package's build dependencies
(
build-essential,pybuild-plugin-pyproject,python3-pytest), which the 1.6.0 upload lacked. scripts/release.pychecks PyPI with certifi's certificates when available, so it also runs with the python.org Python on macOS (which has no CA bundle until "Install Certificates" is run); a network error there is reported in one line instead of a traceback.
[1.6.0] - 2026-10-13¶
Added¶
- Fedora and EPEL 10:
sudo dnf copr enable mehaskari/xping && sudo dnf install xping, built automatically for every release. xping reportshows the 95th percentile, and--since 7d --comparecompares each target with the week before: uptime, median and p95 with the change marked green (better) or red (worse).xping monitor --install-service: keep monitoring in the background. The same monitor command runs as a per-user service, a LaunchAgent on macOS or a systemd user unit on Linux, started at login and restarted if it stops, with its output in~/.xping/monitor.log. The checks are validated before anything is installed.--service-statusshows whether it runs;--uninstall-serviceremoves it. No root needed.xping history --clear --older-than 30ddeletes only runs older than that and keeps the rest (files left empty are removed), so a monitor saving all day does not grow without bound.- VPN awareness.
xping netshows a VPN tunnel and whether internet traffic goes through it (found by asking the routing table how 1.1.1.1 is reached, since many VPNs leave the default route alone).xping doctornames the VPN next to the network interface and puts high latency down to the tunnel rather than to your network.--jsonhasinternet_interface,vpn_interfacesandvia_vpn.
Changed¶
- Releases reach the Snap Store's stable channel automatically (each architecture as soon as its build of the release is ready).
- Snap builds of unreleased commits are versioned
X.Y.Z+gitN.HASH; only the release commit itself isX.Y.Z. - Packaging held to the distributions' own tools: the Debian package
builds in Debian unstable with the tests running and no network, is
lintian-clean and passes autopkgtest; a Fedora spec (also used by COPR)
builds with
%check, passes rpmlint and installs. Both run in CI. xping monitorchange lines (in a log or pipe) line up: the check name and type columns are padded to the widest name, so the details start in the same column on every line.
[1.5.2] - 2026-10-07¶
Fixed¶
xping reportwith nothing saved says so plainly ("nothing saved yet") and suggestsxping monitor --save; a filter or--sincethat leaves nothing says "in this period" and points toxping history.xping reportcharts break the line where nothing was measured (e.g. while monitor was stopped) instead of drawing a straight line across.xping monitorand watch mode write each line at once when the output is a file or a pipe, sotail -fon a log follows them live (the output used to sit in a buffer until several kilobytes had accumulated).
[1.5.1] - 2026-10-06¶
Added¶
- A default check file,
~/.xping/checks.toml:xping checkandxping monitoruse it when no file is given, and say how to create it when it does not exist.xping check --initcreates it with checks that work anywhere (your router, 1.1.1.1, 8.8.8.8, DNS, HTTPS); it never overwrites an existing file. xping monitor HOST HOST:PORT URL…without a file: hosts are pinged,HOST:PORTgets a TCP connect, URLs an HTTP check.- Homebrew:
brew install mehaskari/tap/xping(man page and completion for bash, zsh and fish included). The tap follows PyPI releases on its own, after building and testing each new version on macOS. blocklistchecks IPv6 addresses too (nibble format) on the lists that publish IPv6 data, Spamhaus ZEN and DroneBL — both for an IPv6 address given directly and for a domain's IPv6 mail and web servers, which were previously listed as "not checked".xping report: the saved history as one HTML page. An overview of every target (state, uptime, outages, latest value), and per target the uptime, outages and downtime, latest and median value, a chart of the headline metric over time with failures and outages marked, and the list of outages. One self-contained file, no scripts, nothing loaded from the network, light and dark theme.-o FILE(or-for stdout),--since,--last,--title; narrow to one command or target.mtr --tcp/--port PORT: every probe is a TCP SYN to that port (443 by default), liketrace --tcp, so mtr works where ICMP is dropped. Also in check files (tcp = true,port).--fail-after Nand--recover-after Nfor watch mode (--watch/--until-upon ping, tcp, udp, http, health) andxping monitor(also per check:fail_after,recover_after). A target counts as DOWN only after N failed checks in a row and as UP again after N passing ones, so a single blip neither flips the state nor alerts anybody. Uptime still counts every check; outages, the "down at the end" verdict and alerts follow the confirmed state, and an outage is measured from its first failed check.--until-upwaits for N passes.ping --watchkeeps its 3-lost-pings rule as the default.xping monitormarks a check◐while its latest runs disagree with the confirmed state.
[1.5.0] - 2026-10-05¶
Deprecated¶
- Short options that meant something else in one command than in all the others. The old spelling still works until 2.0 and prints a warning on stderr:
trace -p N(probes;-pis--portselsewhere): use--probes N.propagation -t TYPE(-tis--timeoutelsewhere): use-r/--type.ping -w(-wis--workerselsewhere): use--watch.wifi -i NAME(-iis--intervalelsewhere): use-I/--interface.
Added¶
xping monitor FILE: a live dashboard for a check file. Every check runs again and again, each on its own schedule (everyin the file, or--every). In a terminal the state is a table redrawn in place: up or down, the latest value of the check's headline metric, a trend of the last 16 runs, uptime and how long the current state has lasted; narrow terminals drop the least important columns, then shorten check names, and hide the detail rather than show two letters of it. Elsewhere (cron, systemd, a pipe) it prints one line per state change.--notify/--webhookalert on every change,--savekeeps each result in the history under the same name as the single command,--rounds Nstops after N runs. Ctrl-C ends with a summary (uptime, outages, longest outage, average); the exit code says whether everything was up. Durations drop a zero remainder:1mrather than1m00s.ping --until-upand--every, liketcp,udp,httpandhealth: ping once per check until the host answers, then exit 0 (xping ping 10.0.0.1 --until-up -q && ssh 10.0.0.1).- Check files support
trace,mtr,wifi,doctorandspeedtest, with their thresholds (max_loss/max_latencyfor mtr,min_signalfor wifi,min_download/min_uploadfor speedtest). Speedtest checks run on their own after the parallel ones. xping check --savekeeps the whole report in the history, one history per check file.speedtest --min-download MBPSand--min-upload MBPS: exit 1 when the link is slower than that.
Changed¶
- Every terminal view is now tested with realistic results, with colour on and off: the layout must be identical either way (the cause of past column drift), and escape codes in remote text (whois, DNS, certificates) must never reach the terminal. Coverage rose from 79% to 82%, and the minimum from 75% to 80%.
- mypy now checks every module: the last three on the baseline
(
exporters/tables.py,verdict.py,diagnostics/speedtest.py) are typed, and the baseline is gone. ping --watchnow judges the whole session when you stop it:--max-loss/--max-latencyand the exit code apply (1 when every ping was lost), and--savekeeps the session in history. An unresolvable host now exits 1 instead of 0.- Python 3.13 and 3.14 are tested in CI (Linux and macOS) and listed as supported on PyPI. Python 3.10 stays supported: Ubuntu 22.04, which the PPA builds for, ships it.
--saveconfirms the save with the run number and thexping historycommand to use, except with-qor an export format, where the output has to stay clean.
Fixed¶
xping.diagnostics.checkcan be imported on its own (it failed with a circular-import error when it was the first xping module loaded, e.g. from a script using xping as a library). The pass/fail verdicts moved fromxping.cli.verdicttoxping.verdict, below the CLI layer; a test now imports every module standalone and keeps the lower layers free of CLI imports.xping historyno longer shows an empty trend line for a single run, and says "1 run" rather than "1 runs".
[1.4.9] - 2026-10-03¶
Added¶
- History:
--saveandxping history. --saveon ping, trace, mtr, health, tls, tcp, udp, http, smtp, dnscheck, blocklist, ntp, speedtest, wifi and doctor keeps the result in~/.xping/history/<command>/(or setsave = trueunder[defaults]in the config file).xping historylists what is recorded.xping history COMMAND TARGETshows the runs with the command's key metrics, a trend line, the pass rate, and the latest run against the median. It supports--last,--since 7d,--clear, and--json/--csv.- Nothing is recorded without
--save. The newest 500 runs per command and target are kept.
Changed¶
xping diffis easier to trust and to read.- Jitter and the maximum RTT get a 10% noise band; other metrics keep 3%.
- New notes warn when the two runs have different or small sample sizes.
- Notes also explain likely causes: a higher minimum RTT points to a route or ISP change, and higher jitter with an unchanged minimum points to a busy or weak local link.
- JSON output has a new
notesfield. xping wifinames two stronger access points when they are nearly equal, so the tip no longer flips between runs as signals fluctuate.
Development¶
- CI type-checks the code with mypy. Every module is checked except three
that need a larger rework, which are listed as a baseline in
pyproject.toml. Fixing the reported issues turned up a name that shadowed the colour helper inlookup, plus many missingNonechecks and annotations. -
The minimum test coverage rose from 55% to 75% (actual: 79%). The CI run page shows a coverage summary.
-
A documentation site at https://mehaskari.github.io/xping/, built with MkDocs (Material) from
docs/. It has search, dark mode and a table of contents. Every docs change is built in strict mode, so a broken link or section anchor fails the check. The site is published frommain.
[1.4.8] - 2026-09-27¶
Changed¶
xping wifidetects a clearly stronger access point nearby (8 dB or more, same security, same name where known). This is a device "stuck" on a far access point, and toggling Wi-Fi fixes it. 5/6 GHz access points are preferred.xping smtplists MX records one per line, showing the first three.smtpandtlsshow certificate names short ("Google Trust Services (WE2)" instead of the full distinguished name); JSON output keeps the full names.- CI and release workflows use current action versions, which run on Node.js 24 instead of the deprecated Node.js 20: checkout v7, setup-python v7, upload-artifact v7, download-artifact v8 (a hash mismatch now fails the download), action-gh-release v3 and CodeQL v4. All of them are still pinned to commit SHAs. Dependabot now proposes action updates as one grouped PR.
[1.4.7] - 2026-09-27¶
Security¶
- Terminal escape sequences and control characters from servers are removed before display and CSV/Markdown export. Before, a malicious server could move the cursor, overwrite output or write to the clipboard.
- The DNS parsers no longer hang on a compression pointer loop, which a malicious response could trigger.
- Raw DNS queries use a random transaction ID on a connected socket and drop mismatched replies, which makes spoofing hard.
diggets names through-q/-t, so a name such as-f/etc/passwdfrom a check file can no longer read local files.profile list --namesprints only valid names. Bash completion passes them tocompgen -W, which expands$(...).httpcounts the body instead of storing it, and stops at 100 MB. WHOIS responses are capped at 1 MB.- The completion rc block single-quotes the script path. CI and release workflows use read-only tokens and pass secrets as environment variables.
- Every GitHub Action in CI and release workflows is pinned to a commit SHA, so a moved or hijacked tag can't change what runs with release credentials. Dependabot keeps the pins current.
Added¶
xping smtp HOST— checks a mail server.- It checks the greeting, the EHLO extensions, STARTTLS (or implicit TLS on 465) and certificate verification for the server's name.
- It shows the AUTH mechanisms and size limit offered over TLS, and whether the server's reverse DNS resolves back.
- A mail domain is tested through its preferred MX;
--no-mxtests the host itself. - It ends with QUIT and never sends mail.
--port 25|587|465. Missing or invalid TLS is a warning unless--require-tlsis given.--min-dayschecks certificate expiry.- It is an
smtptype in check files. xping diff BEFORE AFTER— compare two--jsonresults of the same check. Either side can be-for stdin.- It recognises the kind of result and compares the numbers that matter, each with its "better" direction: RTT, jitter, loss, HTTP phases, TLS days, speed, clock offset, Wi-Fi signal and so on.
- It shows the route changes of
trace/mtr, added and removed DNS records, and status changes indnscheck/doctor/check/blocklist. - Changes under 3% count as noise.
--max-regression PCTexits 1 on a bigger regression or a worse status.xping wifi— Wi-Fi link quality.- It shows signal and noise (dBm) with a grade, the SNR, the channel, band and width, the link rate and MCS, the standard, the security, and how many nearby networks share (or on 2.4 GHz overlap) your channel.
- It gives advice: move closer, interference, switch to 5 GHz, or the least used of channels 1 / 6 / 11.
--nearbylists the networks around you.--min-signal DBMmakes it an alarm.- Data comes from
system_profiler(macOS),iw/nmcli(Linux) ornetsh wlan(Windows), with no root and no network traffic.
Changed¶
xping blocklistshows a compact summary instead of one row per list per address, which was 43 rows for a typical domain.- Each checked address or domain gets one row, e.g. "clean on 8/8 IP lists".
- Any result that is not clean is still shown in full.
--allrestores the full table.- The closing line now says "43 checks on 11 lists" instead of the misleading "43 lists".
xping ntpshows the measurement accuracy (± half the round trip), and says when the offset is within it. JSON output has a newuncertainty_msfield.xping udpandxping ntpno longer repeat the address on an "IP" line when the target already is an IP.
[1.4.6] - 2026-09-26¶
Added¶
xping udp HOST PORT— is a UDP service answering? Each probe is open (a reply came back), closed (ICMP port unreachable) or no response (filtered, or the service ignored the request). The request is chosen by port — a DNS root query for 53/5353, SNTP for 123, SNMPv2c GET sysDescr (communitypublic) for 161 — or set with--probe/--payload HEX. It supports--max-latency,--watch,--until-upand alerts, and is audptype in check files.xping blocklist IP|DOMAIN— checks spam blocklists (DNSBL).- An IP is checked on Spamhaus ZEN, SpamCop, Barracuda, PSBL, Mailspike, UCEPROTECT L1, DroneBL and s5h.
- A domain is checked on Spamhaus DBL, SURBL and URIBL, and the IPv4 addresses of its MX and A hosts are checked on the IP lists.
- Results are listed, policy (Spamhaus PBL end-user ranges, which don't fail), clean, refused (lists that refuse public resolvers) or error.
--zoneadds more lists. It is ablocklisttype in check files and exits 1 when the target is listed.- DNSSEC in
xping dnscheck. - Three queries to a validating resolver (1.1.1.1, then 8.8.8.8) with the DO flag: DS at the parent, a signed SOA and its AD flag, and a checking-disabled retry after SERVFAIL.
- Results: signed and validated (ok); broken "bogus" signatures, meaning validating resolvers cannot resolve the domain (fail); signed without DS, i.e. not active (warn); not signed (info).
- Answers are retried over TCP when truncated.
xping lookup --doh PROVIDER— DNS over HTTPS (RFC 8484 wire format) tocloudflare,google,quad9or anyhttps://URL. It gets past resolvers that filter, rewrite or hijack plain DNS. JSON output now includestransport(dig,udpordoh) andresolver.- Personal defaults in
~/.xping/config.toml. - A
[defaults]section applies to every command, and there is one section per command (e.g.[ping] count = 10,[lookup] doh = "cloudflare"). Keys are long option names. - The command line always wins. In mutually exclusive pairs, the flag
given on the command line drops the file's value for the other one
(
-6beatsipv4 = true). - Unknown sections, options or values are errors that name the file, section and key.
xping configshows the active settings or explains what is wrong, andxping config --exampleprints a starter file.XPING_CONFIGselects another file, andXPING_CONFIG=noneignores it.- The
xping HOSTshorthand uses the[ping]section. xping ntp [SERVER]— the system clock offset against an NTP server (defaultpool.ntp.org) over SNTP. It shows the offset, the delay, the stratum, the reference and whether the server is synchronised, using the lowest-delay of several samples.--max-offset MSmakes it an alarm. It is anntptype (thresholdmax_offset) in check files.
[1.4.5] - 2026-09-26¶
Added¶
xping doctor [host]— answers "why is my internet not working?". It checks, in order: network interface (and DHCP), default gateway, internet by IP (no DNS), DNS (your resolvers vs. a public one), connection quality, captive portal, HTTPS (interception and system clock), IPv6 and, optionally, a host (--port, default 443). It ends with one plain-language diagnosis and what to do. Exit code 1 when a step fails;--json,--csv(one row per step) and--markdownwork as usual.xping http: per-phase timing waterfall and security headers.- The TLS handshake is now timed separately from the TCP connect. The time to download the body and the time spent following redirects are timed too.
- The phases are drawn as a waterfall, like a browser's network tab.
- The TLS version and cipher are shown.
- A security-header audit covers HTTPS / http→https upgrade, HSTS
(max-age ≥ 180 days), CSP,
X-Content-Type-Options,X-Frame-Options(or CSPframe-ancestors),Referrer-Policy,Permissions-Policy, and version-revealingServer/X-Powered-Byheaders. It is informational only. -
New JSON fields:
tls_ms,transfer_ms,redirect_ms,tls_version,tls_cipher,security,security_missing. CSV / Markdown gain a "Security headers" table. -
xping trace --tcp/--port N— traceroute with TCP SYN probes to a real service port (443 by default;--portimplies--tcp). It gets through firewalls that drop ICMP, where a normal traceroute ends in* * *. No root needed: Linux reads the router from the TCP socket's error queue (IP_RECVERR), macOS from an unprivileged ICMP socket. IPv4 and IPv6; not available on Windows. -
Alerts in watch mode:
--notifyand--webhook URLonping --watchand on--watch/--until-upfortcp,httpandhealth. - An event fires on every DOWN / UP change, and the UP message includes how long the outage lasted.
--notifyuses Notification Center (macOS) ornotify-send(Linux), and the terminal bell elsewhere.--webhookPOSTs a JSON event withtext/contentfields that Slack, Discord, Mattermost and Google Chat display directly. It is sent in the background, and a failure is reported only once.ping --watchtreats three consecutive lost pings as an outage.
Changed¶
xping http:tcp_msis now the TCP connect time alone. It used to include the TLS handshake, which is now reported astls_ms.
Fixed¶
- The progress spinner (used by
doctor,http,trace,net, …) printed its message on one line per animation frame when the message was wider than the terminal. It is now cut to fit, with "…". - Misaligned columns in
http(timing, connection, security and response headers),trace(host column after the RTT) andall(summary). Padding counted the invisible colour codes, so columns drifted, especially with colour off (NO_COLOR, piped output). Coloured text is now padded by its visible width. - Summary tables (trace, ping, watch, speedtest, …) had a misaligned value column and uneven borders whenever a cell was coloured; the table renderer measured cells including their colour codes.
xping trace: the rule under the hop list was shorter than the rules around the column header; all rules now have the same width.xping traceprinted the separator line twice before its summary.xping http: the last line of the redirect chain always showed status 200, even when the final response was an error.- Project links pointed to
github.com/mehdiaskari/xping, which does not exist. The correct repository,github.com/mehaskari/xping, is now used in the PyPI metadata (pyproject.toml,setup.cfg),xping about, the man page, the snap and Debian metadata, README and CONTRIBUTING. - The WHOIS/RDAP bootstrap download (
data.iana.org) now uses the same TLS context as every other HTTPS request (certifi, TLS 1.2+), so it also works on Python builds without a usable system CA store.
Docs¶
- New user guide,
docs/guide.md. It covers every command with all options and defaults, what the output means, and how scores are computed (health,dnscheck,speedtest,osdetect). It also has the check-file reference, recipes, files/privacy, platform notes and a FAQ. It is linked from the README and the PyPI project links. A test fails if a command or long option is missing from it. - Man page:
--proto udpin thelistendescription rendered as--protoudp. - README: current install options (PPA for Ubuntu 24.04 and derivatives, Snap with stable/edge channels, PyPI with the completion step). The non-existent AUR package is removed. New sections for listening ports, OS fingerprint and "Files & privacy" (what is stored, which commands contact third parties), plus completion environment variables.
- CONTRIBUTING: PR workflow with branch protection, an up-to-date "add a new command" checklist (verdicts, CSV tables; completion is automatic), and notes on the real-shell completion tests.
- RELEASE: the PR-based release flow, macOS-compatible
sed, the current CI matrix, snap edge → stable promotion, and a correct rollback (PyPI yanking happens on the website;twine yankdoes not exist). - SECURITY: 1.4.x supported; the design section describes unprivileged
ICMP, strict TLS, which files are written, third-party contacts, and
shell-free subprocesses. The obsolete
--outputmention is removed. - PACKAGING: completion packaging, snap channels, six-file version checklist, and the corrected PPA series (noble).
- Man page: PRIVACY section, accurate DEPENDENCIES, completions in FILES.
- Debian: a real
README.Debianinstead of the template placeholder, and the unusedxping-docs.docsis dropped. The bug report template asks for the install method and shell.
[1.4.1] - 2026-09-25¶
Fixed¶
- Tab completion did not work (reported on macOS). There were three causes:
- the zsh script never registered itself when sourced;
- zsh's own
_hostscompletion also claims a command namedxpingand took over; - on macOS's bash 3.2, the documented
source <(xping completion bash)silently does nothing.
Completion scripts for bash, zsh and fish are rewritten and verified by pressing Tab in real shells (zsh via zpty, bash 3.2 and 5, fish 3.7).
Added¶
xping completion --install/--uninstall: sets up completion for your shell in one step. It writes the script and adds a marked, idempotent block to~/.zshrc,~/.bashrcor~/.bash_profile(bash on macOS); fish is set up via~/.config/fish/completions/.- Richer completion: option descriptions (zsh, fish), fixed-choice values
(
--proto,--type, shells), hostnames plus saved profile names wherever a host is expected,.toml/.jsonfiles forxping check, and profile names forprofile show/remove. In zsh, mutually exclusive options are not offered together. - The Debian/Ubuntu package installs completion for bash, zsh and fish automatically; the snap provides bash completion.
xping profile list --namesprints bare profile names (used by completion).
[1.4.0] - 2026-09-25¶
Added¶
- Exit codes you can script with: every command exits
0when its check passes and1when it fails (unreachable, closed port, HTTP ≥ 400, expired certificate, DNS error, …); invalid usage exits2, Ctrl-C130. Previously almost everything exited0. - Thresholds:
ping --max-loss/--max-latency,tcp --max-latency,mtr --max-loss/--max-latency,http --max-latency/--expect-status,tls --min-days,health/dnscheck --min-score. The reason a threshold failed is printed on stderr. -q/--quieton every diagnostic command: no output, exit code only.- IPv6: IPv6-only hosts now work, and
-4/-6force a family on ping, trace, mtr, tcp, portscan, tls, http, health, mtu, osdetect and all. System fallbacks useping -6/ping6,traceroute -6/traceroute6/tracert -6. - No root needed for ping, trace, mtr and health on macOS and Linux:
xping uses unprivileged ICMP ("ping") sockets, with raw sockets and the
system tools as fallbacks. Traceroute reads "time exceeded" replies
from the socket (macOS) or the IP_RECVERR error queue (Linux).
xping depsshows which mode is available. trace --asn/mtr --asn: the network operator (AS number and name) of every hop, via Team Cymru's DNS interface. Opt-in.xping net: interfaces (state, MTU, addresses), default gateways, DNS resolvers, local source addresses and public IPv4/IPv6 with country and Cloudflare colo.--no-publickeeps everything local.xping propagation: compare a record (A, AAAA, CNAME, MX, NS, TXT) across your resolver and six public ones;--expectmakes it a pass/fail propagation check.--watch/--until-upfortcp,httpandhealth: a live up/down log with downtime and an uptime summary, or "wait until it's up, then exit 0" for scripts. Thresholds apply in watch mode too.xping check <file>: run many ping/tcp/http/tls/lookup/dnscheck/ health/propagation checks from one TOML or JSON file in parallel, with one exit code.xping check --exampleprints a starter file.- Multi-connection speedtest (
-c/--connections, default 4;-d/--duration): a single stream under-reports fast links. Upload is timed after the TLS handshakes; the server row shows the Cloudflare colo.
Changed¶
--csvand--markdownare real tables now: one row per ping reply, hop (with per-probe columns), port, host, DNS record, check, … instead of Pythonrepr()of nested lists. Field-type results (tls, whois, http, health, speedtest, …) exportfield,valuerows. JSON is unchanged.--json,--csv,--markdownand--quietare mutually exclusive.- Shell completion is generated from the argument parser, so it always matches the real commands and flags.
xping httprecords the address it connected to (ip);mtuexports its headeroverhead(28 for IPv4, 48 for IPv6).
Fixed¶
speedtestwrote the download error message into theserverfield.- Parallel
healthchecks could corrupt~/.xping/health_history.json(history writes are now serialized). - Man page: the
healthoptions were listed under a duplicatedmtuheading,tracepromised a path tree it does not draw, and two invalid roff escapes broke rendering inmandoc.
[1.3.8] - 2026-09-25¶
Security¶
- Every TLS/HTTPS connection (
tls,http,whoisRDAP,speedtest) now goes through one shared context that verifies certificates and refuses anything older than TLS 1.2. whoisno longer retries RDAP with certificate verification turned off when the verified request fails.
Fixed¶
--jsonoutput dropped several values shown on screen:httpnow exportsdns_ms,tcp_ms,http_versionandh2_supported,healthexportshistory, andtlsexportschain.traceread the ICMP type at a fixed offset, misparsing replies whose IPv4 header carries options; the header length is now honoured.- The system
traceroute/tracertfallback ignored--timeout. tcpresolved the host, then connected by name (resolving again, and possibly to a different address than the one displayed).ping --watchsilently ignored--json/--csv/--markdown; the combination is now rejected with a clear error.osdetectcould crash on a TTL above 255; dead TTL tables removed.- Removed an unreachable
exceptbranch inwhoisand unused code intraceandspeedtest. httpfailed on every HTTP/2-capable HTTPS site: the request connection offeredh2via ALPN, buthttp.clientonly speaks HTTP/1.1, so servers that picked h2 rejected the request. The request now negotiates HTTP/1.1 only; HTTP/2 support is detected with a separate ALPN probe and shown as "HTTP/2 support".dnscheckalways failed DMARC: it looked for the record at the apex instead of_dmarc.<domain>. The policy is now read from thep=tag (sosp=rejectno longer masksp=none). DKIM is detected by probing common selectors at<selector>._domainkey.<domain>.listenfound nothing on macOS, and the netstat fallback mis-parsed Linux (0.0.0.0:22, state vs PID column) and dropped Windows UDP rows. macOS/BSD now usenetstat -anwithtcp4/tcp46and dot-separated ports supported.- Raw-UDP DNS fallback returned CNAME targets as IP addresses: answers are now filtered by the queried record type.
- DNS query failures were reported as missing records: SERVFAIL,
REFUSED and timeouts are now tracked separately (
query_errorsinlookupoutput).dnscheckmarks those checks "not verified" and leaves them out of the score instead of failing them. speedtestandosdetectnow accept--json/--csv/--markdown(osdetectreturns a proper result model).
Internal¶
- The command list is now defined once (
cli/main.py), and tests check that the parser, shell completion, and--helpstay in sync with it. - CI's version check now also covers
setup.cfg,snap/snapcraft.yamlanddebian/changelog; a non-blocking Windows test job was added. - Resolved the open CodeQL findings (empty
except,import *shims, unused imports/variables, asserts with side effects).
Docs¶
- Removed the nonexistent
--alarmand--outputflags from the man page, shell completion and snap description. README now names thecertifidependency and the correct PPA package (xping).--helplists every command.
[1.3.7] - 2026-09-21¶
Changed¶
- The ASCII-art banner now prints only when
xpingis run with no arguments at all. It no longer appears before the bare-host shorthand (xping 8.8.8.8) or before any explicit subcommand (xping ping ...,xping trace ..., etc.) — every real command now starts straight with its own output.
[1.3.6] - 2026-09-20¶
Fixed¶
- PPA rejected on upload: Launchpad refused the 1.3.5 source
package outright with
Rejected: Unable to find distroseries: unstable.debian/changelog's distribution field saidunstable(Debian terminology), but Launchpad PPAs only recognise real Ubuntu series codenames —noble,jammy, etc. Fixed by changing it tonoble(Ubuntu 24.04 LTS), matching the series this PPA has targeted since 1.3.0.
[1.3.5] - 2026-09-18¶
Fixes a second, distinct Launchpad PPA signing failure that only became visible after 1.3.4 fixed the first one and the workflow reached the actual signing step for the first time.
Fixed¶
- PPA GPG signing:
debsignwas failing withgpg: Sorry, we are in batchmode - can't get inputfor any signing key that has a passphrase — strict batch mode refuses to prompt for one under any circumstances. Fixed by writing the passphrase to a private file on the runner (via a newLAUNCHPAD_GPG_PASSPHRASEsecret — safe to leave empty if the key has none) and signing through agpg --passphrase-filewrapper passed todebuildvia its-p<command>option. This single mechanism now works whether or not the signing key has a passphrase, so there's no longer a "pick one setup or the other" decision to make. - Verified end-to-end locally before shipping, not just reasoned
about: generated a real, throwaway passphrase-protected GPG key and
ran
debsign -p<wrapper> --clearsignagainst it — the exact mechanismdebuild -S -sainvokes internally — and confirmed it signs with zero prompts and exit code 0.
Changed¶
PACKAGING.md: documented the newLAUNCHPAD_GPG_PASSPHRASEsecret requirement; removed the earlier passphrase-less-key requirement, which no longer applies.
[1.3.4] - 2026-09-13¶
This release fixes the actual root causes behind PPA and Snap builds repeatedly failing, verified by running the real build/test/lint tools locally rather than editing text and assuming it would work.
Fixed — data correctness¶
- Systemic export bug:
exporters/serialize.pyuseddataclasses.asdict(), which flattens nested dataclasses before computed@propertyfields can be attached. This silently dropped fields likeMtrHop.loss_pctinsideMtrResult.hops, and would have done the same forPingResult.avg_rttinsideHealthResult.ping, in every JSON/CSV/Markdown export. Rewritten to walk the real object graph so nested dataclasses at any depth keep their computed fields.
Fixed — silently broken features¶
render/views/http.pyandrender/views/portscan.pyeach contained two definitions of the same function (a leftover from an earlier edit that appended new code without removing the old). Python keeps the last definition, so the older, less capable version was silently running in production — the HTTP timing breakdown and theportscan --bannersoutput were both quietly disabled despite the correct code sitting right above, unreachable.render/latency.pyhad orphaned unreachable code (referencing undefined names) left over from a previous edit — harmless at runtime since it was unreachable, but removed for good.diagnostics/whois.pywas missing a top-levelimport ssl— masked by a local import inside one function, but referenced elsewhere as an unresolvable string type-annotation.
Fixed — CI pipeline¶
ruff.tomlhadline-length/target-versionnested under[lint]instead of top-level, which is invalid TOML for ruff's schema — this made the "Code Quality" job fail immediately on a config parse error, before linting a single file, on every run.- Actually ran
ruff checkandruff formatagainst the whole codebase for the first time and fixed every real finding (a missing import, an ambiguous variable name, an unused loop variable, azip()missingstrict=), then reformatted all 94 files for a consistent baseline. Two purely stylistic rules (E701/E702) are intentionally ignored — documented inline inruff.toml— because this codebase deliberately uses compact one-line guard clauses throughout, and mechanically rewriting ~50 of them risks introducing typos for zero functional benefit. - Coverage
fail_underlowered from an unreachable 85% to 55%, based on an actually-measured 63% on the current suite. - Fixed 5 real test failures, each verified individually and then as a full suite (222/222 passing):
TestMtr::test_mtr_result_to_dict,test_export_json_mtr— both resolved by the serialize.py fix above.test_lookup_with_dig_path— mock signature didn't match the real 3-argument_dig_query(host, rtype, server).test_lookup_socket_fallback— mocked a functionlookup()never actually calls, so the test silently fell through and made a real network query in CI.test_subprocess_trace_live_parses_hops— didn't mocktrace_tool()/trace_command(), so the result depended on whether thetraceroutebinary happened to be installed on the runner.
Fixed — Ubuntu PPA (Launchpad)¶
debian/controlstill listedpybuild-plugin-pyprojectinBuild-Depends, which does not exist on Ubuntu 22.04 (Jammy) — the exact series this PPA builds for. This alone faileddpkg-checkbuilddepsbefore the build could even start, on every single upload.- Added a
setup.pyshim and completedsetup.cfgmetadata sopybuildcan build via the classicdistutilsinterface without the pyproject-only plugin. debian/rulesswitched toPYBUILD_SYSTEM=distutils, skips tests during package build, and installs the man page.- GPG signing was failing with
Inappropriate ioctl for device—debsigntried to open a controlling terminal that does not exist on a GitHub-hosted runner. Fixed by configuringgpg.conf/gpg-agent.conffor batch mode with loopback pinentry andno-tty, the standard approach for headless package signing. SeePACKAGING.mdfor the requirement that the signing key have no passphrase. - Filled in
debian/copyright(was still the unfilled template).
Fixed — Snap Store¶
- Removed
.github/workflows/release-snap.ymlentirely. It duplicated the Snap Store's native GitHub integration (already authorized via Snapcraft.io → Builds → "build-snapcraft-io"), used aSNAPCRAFT_TOKENsecret that was never configured, and failed on every single run withlogin_data is empty— while the real, working publish path (the native integration) had been succeeding the whole time in parallel. Keeping a workflow that can never pass is worse than not having it: it manufactures a permanent false failure signal for something that already works.
Changed¶
- Author contact corrected to Mehdi Askari iorganamis@gmail.com
everywhere (was still
mehdiaskari@outlook.com/ "Meh Askari" in several files that earlier passes had missed).
[1.3.0] - 2026-07-08¶
Added¶
xping HOSTbare shorthand — auto-pings and shows follow-up suggestionsxping completion bash|zsh|fish— shell tab-completionxping speedtest— download/upload speed via Cloudflarexping listen [--proto tcp|udp]— local listening portsxping osdetect HOST— OS fingerprinting from ICMP TTLxping dnscheck DOMAIN— DNS health check: SPF, DMARC, DKIM, MX, NSxping portscan --banners— service banner grabbingxping lookup --server IP— custom DNS resolver- HTTP/2 detection via ALPN in
xping http - TLS certificate chain display in
xping tls
[1.2.5] - 2026-06-28¶
Fixed¶
- whois.py duplicate function definitions
- RDAP SSL error on macOS / HTTPS fallback for blocked port 43
[1.2.0] - 2026-06-25¶
Added¶
- rdns, tls, http, whois, health, profile, mtr, mtu commands
- ping --watch continuous live mode
- Network health score with history
- Saved target profiles