v0.3.1
The desktop app is redesigned around a denser diagnostic workspace, with reorderable tabs, right-click tab management and a refreshed icon. Port scans return richer status data on every interface, probe concurrency is configurable everywhere, and the website and docs were rebuilt alongside.
The headline is the desktop app. Everything listed under it is new to anyone upgrading from 0.2.6 — the old dashboard-style GUI is gone, and what replaces it is a different application rather than a revision of that one. The rest is additive work in the core, CLI and MCP server, and a long tail of fixes. The recurring theme in that tail is code that reported success while doing nothing.
Added
- The desktop app is a diagnostic workspace. NetsCLI Desktop replaces the earlier dashboard with a native-like shell built around operation tabs. It runs the same
netscli-coreoperations as the CLI, TUI and MCP server, so its results match the rest of the tool. What it does:- Operation tabs you can reorder by drag or keyboard, and close individually, to either side, or all at once from a right-click menu.
- Sortable and filterable result tables, row detail panes, and a preview of the CLI command each run is equivalent to.
- Save a whole workspace of results to a file and reopen it later; export CSV or JSON, whole or selection-only. Exported cells are escaped against spreadsheet formula injection, since banners and hostnames are chosen by the scanned host.
- Light and dark themes, and a settings dialog covering probe concurrency, default and traffic interfaces, IPv4/IPv6 display preference, history and save behaviour, and notification preferences.
- Full keyboard operation, and a refreshed icon matching the site's brand.
- Clear the ARP table, then discover. A chevron beside Run offers a cache-flushing variant on discover, sweep and the ARP tab — the tools where a stale neighbour entry changes the answer. Clearing needs administrator rights; when it fails the run is suppressed rather than quietly returning the stale entries it was meant to drop.
- Richer port scan results across every interface. Port scans now report additive status and detail fields (
open,closed,filtered,error, latency, banners, HTTP metadata, TLS metadata, and raw previews where available) while keeping the olderopen,port,service, anderrorfields intact for compatibility. - User-configurable probe concurrency. The CLI and MCP server already accepted concurrency limits; the desktop app and TUI settings now expose the same control, so probes can be reduced on fragile networks or raised within the core safety cap.
Changed
netscli scan --jsonnow reports every port, not just the open ones. Filtering to open ports made "all closed", "all filtered" and "every probe errored" the same empty array, so a script could not tell a clean scan from a host that refused every probe. Each entry carriesopenandstatus, so callers that want only open ports can filter for them.- The MCP server now scans only local networks by default. This is the one surface driven by a model rather than by the person at the keyboard, so the instruction to scan a third party can arrive from a web page or a file someone else wrote — and the packets leave from your machine and your IP. RFC1918, loopback, link-local and the carrier-grade NAT range overlay networks use are allowed; set
NETSCLI_MCP_ALLOW_PUBLIC_TARGETS=1to reach past them. - Scan results returned to a model are capped. The full probe response (
raw) is no longer included and banners are truncated, both being bytes chosen by the scanned host. - Tool failures are returned as MCP
isErrorresults rather than JSON-RPC errors, so a failed scan no longer reads to a client as a broken server. - CLI and TUI scan output reflects the richer status data. Human output stays concise, but scanned ports can show closed, filtered and error states with latency where available, instead of only emphasising open ports.
- Windows install guidance prefers Winget for the desktop app. Winget's manifest review and installer hash verification make it the recommended Windows path; direct GitHub Windows installers remain unsigned and may show warnings until code signing is added.
- Linux/macOS install docs clarified. mDNS is the default pure-Rust capability in published builds; packet capture remains the optional workflow depending on libpcap/Npcap.
- The website and docs were rebuilt. A consistent shell, unified code and table styling, clearer search, and a layout swept across six widths and both themes. The brand accent moved from a teal-green that read blue in small text to one that reads green at any size.
Fixed
- Pinging your own machine no longer reports 100% loss. On Windows,
ping 127.0.0.1— and the machine's own LAN address — timed out while the systempinganswered immediately. Raw ICMP sockets need administrator rights, so an ordinary run fell back to TCP probes on ports 80/443/22 and concluded a host was down when nothing answered; and a Windows raw socket does not observe traffic to an address the host owns. Windows now sends echoes through the IP Helper API, which needs no privileges and reaches local addresses. Discover and sweep both start from a ping sweep, so both returned nothing for any range covering this host. - IPv6 hosts can be pinged.
ping ::1reported total loss because IPv6 had no ICMP path at all and fell through to the same TCP probe. Windows now usesIcmp6SendEcho2. netscli arp --clear,--addand--deleteno longer claim to have changed the table when they have not. On Windows these print "The requested operation requires elevation" and then exit 0, so checking the exit status alone reported success while nothing was touched — an ordinary run printed "ARP entry added for 192.0.2.77", and"ok": truein JSON, having done nothing. All three now share one check and exit non-zero with the reason.--clearalso errors on platforms where it was never implemented, instead of reporting a cleared table.- Discover reports devices the OS already knows about. Results merge probe replies with the neighbour table, so a device that answers ARP but not ICMP is no longer missing. Each host records whether it was found by probe or by neighbour, since a stale neighbour entry can outlive the device.
- Safety limits were enforced in
Opsbut not in the engines. The scan, sweep, discover and inspect engines are public API re-exported at the crate root, and called directly they applied no subnet, port or concurrency cap —0.0.0.0/0collected 4,294,967,294 addresses into aVecbefore sending a packet. Every engine now enforces its own limits. (#198) - Safety limits that only one caller was applying.
SweepEngine::sweepvalidates its port list instead of trusting the caller and silently returning "no open ports"; mDNS browse duration,ping -cand packet captures given a packet count but no duration all gained the core-side ceiling they were documented to have. - Port 0 was rejected only by the MCP surface. Now rejected everywhere. (#164)
- MCP server handled one request at a time. The read loop awaited each handler before parsing the next line, so a slow scan blocked every other request on the connection, including cancellation. Handlers now run concurrently under a semaphore. (#169)
- Reading the ARP table blocked a runtime worker. On Windows and macOS it shells out to
arpand waits on the child process; three callers invoked it straight from async code. With MCP handlers capped at 16 concurrent, sixteen of these could stall every worker — including the one reading stdin, so no further request could even be parsed. Moved to a blocking thread. (#196) - Four ways an MCP client could wedge or kill the server: no overall request deadline, permits acquired after spawning rather than before, a single invalid UTF-8 byte on stdin terminating the process, and client disconnect cancelling nothing.
- The MCP server no longer says it returned everything while truncating. A capped result reported the byte count as its item count, so a 40,000-row scan that returned 11,518 rows said
returned: 40000, total: 40000besidetruncated: true. - Packet captures fetched as a background MCP job are bounded like every other result.
get_pcap_capture_resultwas routed before the limits that strip and truncate remote text, so the one result made entirely of bytes off the wire was the one that skipped them. - The concurrent packet-capture limit could be bypassed by calling the blocking capture tool, which never registered a job.
discover_networkwith no arguments failed on a host whose interface carries a /8, because the substituted default exceeded the /16 cap.- A database written by a newer netscli is refused rather than read. The version check treated a future schema as "already migrated", so an older build queried tables it had never seen.
netscli traceno longer prints router-supplied hostnames unsanitised. Hop names come from PTR records controlled by whoever runs those routers, and this was the last plain-text output path without the terminal-safety pass every other one had.- TUI mis-measured wide characters, so CJK and emoji in a remote-supplied hostname or banner pushed box borders out of alignment. (#173)
- Panic paths in the core, and silent corruption in the OUI generator. (#172)
- winget publishes the version number, not the tag. Both package manifests were passed the tag including its
v, which the action only strips when the input is left empty.v0.2.2throughv0.2.6are already in the public catalog that way, sowinget show netsclireports a version this project never issued. Upgrades still work — winget normalises a leadingvwhen comparing — and this release fixes what is displayed. The publish job now assertsMAJOR.MINOR.PATCHrather than trusting the strip, because winget-pkgs accepted all five without complaint and a merged manifest is permanent. - AUR packages are published against a re-hashed asset. Both AUR jobs took the published
.sha256sidecar on trust rather than downloading the asset and hashing it, which is the circular check the release scripts exist to prevent; the other registries already did this correctly. - The Windows installer verifies Npcap before running it.
install.ps1downloaded the Npcap installer from an overridable URL and launched it elevated with nothing checked; it now verifies the Authenticode signature and signer, and refuses to run an unsigned or unexpected binary. install.shno longer claims success before installing libpcap. A user who asked for capture support could read "Installed successfully" and get a binary that cannot capture.
Website
- Small grey text was unreadable on card surfaces. The docs footer, built-with row and mobile section labels use
--sl-color-gray-3, much of it at 12px. It had been raised once to clear 4.5:1 against the page background, but nothing checked it against the slightly darker card surface, where it sat at 4.44:1. - Muted text, and several status colours, were below the readability bar. Eight colour tokens failed WCAG AA (4.5:1) against surfaces they are actually painted on — the mint accent failed as text on every light surface, down to 3.85:1. All 84 foreground/surface combinations now clear 4.5:1, and a check keeps them there.
- The install guide has the verification steps the landing page promises. It advertised checksums and Sigstore signatures and linked to a page with none of them on it.
- The site claimed packet capture in builds that do not ship it, and advertised a version that was never released. (#194, #208)
- The interface coverage table no longer conflates separate things. Rows that merged setup with doctor, or reading the ARP table with changing it, are split, and dashes that meant "not applicable" say which.
- The FAQ answers two questions people actually search for, from Search Console data rather than guesswork: whether there is a
netscancommand, and whether this replaces nmap and has a terminal UI.