v0.3.5
Discovery on Windows no longer lists devices that have left the network. The desktop app stays responsive with results of 20,000 rows, and its CSV export now makes control characters safe the way the CLI does. MCP clients see progress on long scans and can cancel them, and Windows names Felix Stubner as the desktop app publisher.
Added
- The terminal UI honours
NO_COLOR, and the CLI honoursTERM=dumbandCLICOLOR_FORCE. The CLI's tables already went plain forNO_COLORand for output that is not a terminal. The terminal UI ignoredNO_COLORand always drew in 24-bit colour. It now draws without colour whenNO_COLORis set, keeping bold, and shows the selected row in/configreversed instead of shaded. The CLI also stops colouring forTERM=dumb, andCLICOLOR_FORCE=1keeps colour when the output is piped, forless -Ror a CI log.netscli --helpnow lists these, andNETSCLI_HISTORY, at the end.
- The MCP server reports progress and can be cancelled. Discover, port scans and sweeps send progress notifications to clients that ask for them, so a long sweep no longer looks stuck. A client that cancels a call now stops the scan, instead of it running to the end and holding one of the server's sixteen request slots.
Changed
- History is off unless you set
NETSCLI_HISTORY=1. Everydiscover,scan,inspect,sweep,dns,reverseandpcaprun, from the command line and the terminal UI, kept its whole result in~/.netscli/netscli.dbfor good, and nothing reads it back. Every other command created the file too, just by starting,completionsandmanincluded. NetsCLI now opens and creates nothing until the variable is set. With it set, history works as before, and on Linux and macOS the folder and file it creates are readable by you alone. A database an earlier version made is left where it is, and deleting it is up to you. Where no home folder can be found, the database and the terminal UI's default export folder no longer fall back to a.netsclifolder in the current directory. They say there is no home instead.
- Exit codes follow what happened.
0means the command worked,1that it ran and failed, and2that the command line was wrong. Until nowpingexited 0 when nothing answered,traceexited 0 whentracertortraceroutehad failed,doctorexited 0 with a dependency missing, and asking for two output formats exited 1 like a failed scan.pingandtracenow exit 1 in those cases,doctorexits 1 when libpcap is missing from a build that has packet capture, and two output formats, orping -c 0, exit 2 before anything runs.ping -c 0used to printloss=0.0%for a ping that sent nothing. Adns --record ALLwhere only some record types have records still exits 0. A script that ignored the exit code ofpingortracewill start to see 1, and the CLI page lists every code.
netscli mcp-service --installno longer installs a systemd unit. The unit could not work.netscli servespeaks MCP over stdin and stdout and stops when its input closes, and systemd gives a service no input, so the server exited at once andRestart=alwaysstarted it again every five seconds. An MCP client starts the server itself. The command now says so, points to the MCP setup guide, and exits 1. It also wrote the unit on Windows and macOS, where nothing could read it.--uninstalland--statusstay, on every system, to find and remove a unit an earlier version left behind. Runningmcp-servicewith no flag is now a usage error instead of a hint and exit 0.
- The terminal UI's
/discoverlooks up hostnames only when you add--resolve. It always looked them up, with no way to turn that off, where the CLI, the desktop app, the MCP server and/sweepall leave it out unless asked. Its summary line says which it did. The help for/sweeplisted--no-resolve, which does nothing, and not--resolve, which does. It now lists--resolve.
netscli pcapdoes not replace an existing capture file unless you add--force. It writescapture.pcapin the current folder by default and used to overwrite whatever was there, so a second capture quietly destroyed the first. A script that captures to the same name every time now needs--force.
- Enter on half a command name in the terminal UI finishes the name instead of running it.
/ethen Enter ran/export, the first suggestion, which writes a file, when the user was heading for/exit, and/dstarted a discovery of the default subnet. The name is now completed, asTabdoes, and a second Enter runs it.
- The desktop app stays responsive with large results. It drew every row of a result and redrew all of them on every keypress or scroll, so a full 4,096-port scan took about a tenth of a second per arrow key, and a 20,000-row result such as a long packet capture over half a second. It now draws only the rows on screen, so 4,096 rows respond as fast as 100, and 20,000 in about a twentieth of a second. Progress updates from a running scan are also sent ten times a second instead of once per port.
- Windows lists the desktop app's publisher as Felix Stubner. Installed apps showed "netscli", a default taken from the app's internal identifier, while the code signature, winget and the Microsoft Store listing all say Felix Stubner. Upgrading from an earlier version leaves one entry, under the new name.
Fixed
- Text from the network could reorder or hide itself. The cleaning that makes a hostname, banner or
TXTvalue safe to print replaced control characters and let everything else through. That included right-to-left overrides, which make the text after them display backwards, and zero-width characters, which hide text or make two different names look the same. They are now replaced with.in the CLI's text, CSV and Markdown output, in service banners (which the desktop app and the MCP server share), in the computer name an SMB host reports, and in the terminal UI.--jsonand--yamlstill carry the text as it was received. A zero-width joiner inside an emoji in a name now shows as a dot as well.
- The terminal UI's
/export mdcould write an escape sequence into a file. The screen dropped control characters, but the export wrote the stored text as it was, so an mDNS name or aTXTvalue that carried an escape sequence ran when someone printed the file to a terminal. The text is now cleaned when a command's output is stored, and again when the file is written.
- The
scantable did not line up in a colour terminal. Rows were coloured first and padded second, and the colour codes count as characters, so a cell came out short and the rest of its row slid left. Output sent to a file or a pipe was always fine, which is why the tests never saw it.
- Pasting into the terminal UI on Linux and macOS ran commands. Typed in one key at a time, every pasted line break was a press of Enter, so pasting two lines ran the first and went on to the second. A paste now arrives as one piece of text with its line breaks turned into spaces. On Windows nothing changed, because the terminal library does not support it there.
- Terminal UI commands ignored words they could not read.
/ping host abcpinged four times,/mdns --timeout abcused 3000,/discover a bdropped theb, and/arp add 1.2.3.4with no MAC showed the ARP table. Each now answers with a usage error. Worst was/pcap eth0 --filter tcp port 80, which captured with the filtertcp, so every TCP packet, and said nothing./pcapnow reads quotes, as in--filter "tcp port 80", and says to use them when a filter has spaces and none./mdnsalso takes--timeout-ms, the CLI's name for it, and/arptakesdeleteas well asdel.
/export --outputin the terminal UI mangled Windows paths and ignored~. The path went through a splitter that treats a backslash as an escape, soC:\Users\me\out.mdbecameC:Usersmeout.md, a path relative to drive C. And~/scans/out.mdmade a folder named~. A backslash is now an ordinary character, and a leading~is your home folder.
- A crash in the terminal UI left no message. The panic message went to the alternate screen, which is thrown away when the UI closes, so a crash looked like the program closing by itself with exit code 101. The terminal is now put back first, so the message is where you can read it.
netscli ... | headended in a panic message. When the reader closed the pipe,scan 127.0.0.1 -p 1-4096 --json | headprintedfailed printing to stdoutand a panic, and exited 101. A reader that stops early now just ends the output, with exit 0, for the machine-readable formats and the large reports (scan,discover,sweep,inspectandpcap --read).
netscli servecould keep running for minutes after its client had gone. When the client closes its end, the server drops every request it was working on. A ping or capture already running on a blocking thread cannot be dropped, and the process waited for it, up to the request's own timeout, which the MCP tools allow to be ten minutes. The server now ends the process as soon as it has stopped, with every response already written.
netscli scan <name>did not say which address it scanned. A name can have several, the scan used the first, and nothing in the output said which. The text header now readsexample.com (93.184.216.34). The JSON is the same as before.
doctorsaid a standard build had libpcap installed. Standard builds have no packet capture, anddoctoris how people find that out, but it printed a tick. It now reports libpcap as not installed and not compiled in, and still exits 0.setupno longer offers to install it for such a build, where it could not help. Andsetup --print, which is meant to print only, no longer writes~/.netscli/config.json.
- Smaller things in what the CLI and the terminal UI print.
/inspectshowed the round-trip time as(RTT: Some(3)), left out a MAC address unless its maker was known, and never showed the host name.- The terminal UI's status line said
host n/ain most Linux and macOS terminals, because it read$HOSTNAME, which zsh does not export. It asks the system. - In the discover table a long vendor name pushed the hostname column out of line, a name with an accent was measured in bytes, and a single host was "1 hosts".
sweephad the same plural. mdns --timeout-ms 999999waits 30 seconds and then said nothing was found within 999999ms.--helpsaid-jdefaults to 256 when/configcan change that, gave_http._tcpas an mDNS type when only_http._tcp.local.works, and gave a PowerShell completions example that wrote to a file path that is not one.
- The CLI and terminal UI pages match the program. The CLI page showed scan output from before 0.3.4, and did not list the exit codes, the environment variables or the limits that cut a value to fit. The operations page said
inspectwith no ports is a host-only check, when it checks 22, 80 and 443. The terminal UI page described the real screen with an illustration that did not match it, and listed neither the keys nor/arp add.
- Discovery on Windows listed devices that had left the network. The Windows device table keeps an entry for a while after its device goes, and discovery reported those entries as devices. On one network that was 4 of 26, none of which answered anything afterwards. Devices found only in the table are now asked again directly, which can add about 2 seconds and only when the table holds such entries, and are listed only if they answer. Devices that ignore ping still answer, so they are still found.
- The desktop app's CSV export defuses control characters, as the CLI's does. A banner containing an escape sequence went into the file as it was, and a cell such as a tab followed by a number skipped the guard that stops a spreadsheet reading it as a formula. Both exports are now tested against the same list of cases.
- The desktop app no longer leaves a program running after looking for the CLI. To offer MCP setup it runs each
netscliit finds with--versionand gives up after 3 seconds. A program still running at that point was left behind. It is now stopped.
- MCP clients built on the official SDK can connect. Every reply the MCP server sent carried both a result and an error, one of them empty, which the protocol doesn't allow. The official TypeScript SDK drops a reply like that, so a client built on it waited for the answer to its first message and timed out. Replies now carry one or the other, and CI connects to the server with the SDK whenever the code changes.
- Cancelling an MCP call works when the server is busy. When a 17th call arrived with 16 running, the server stopped reading what the client sent until one finished. A cancel, which is how a client frees a slot, went unread, and so did the client closing the connection. The server now keeps reading. Up to 16 more calls wait for a slot, and any past that are refused at once with an error.
- Cancelling or disconnecting stops an MCP packet capture. A capture ran on after its call was cancelled, timed out or lost its client, for up to an hour, and gave its slot back straight away, so cancelling and restarting got past the limit of four captures. It now stops, and gives the slot back once it has. Background captures stop when the client goes too. In a test on Windows, a server whose client left mid-capture exited within 0.3 seconds, where before it was still running after 20. A
capture_pcapcall with onlymaxPacketscould also run for an hour. It now stops after the 10 seconds the tool advertises.
- mDNS discovery no longer leaves its listener running. A service type without its final dot, such as
_http._tcp.local, or a cancelled MCP call left the listener running in the background, its network sockets open and any searches it had started still repeating, until the program exited. It now always stops.
- An MCP result too large to send keeps its file path and counts. A result over 1 MiB that wasn't a plain list was replaced by an error, so a large packet capture lost its file name, packet count and job status along with its packets. Now only its longest list is cut to fit. A background capture also reports its file name as soon as it starts.
- Smaller MCP server fixes.
- The server answers
ping, which clients use to check that a server is alive. It answered with an error. - It agrees a protocol version it supports, instead of whatever version the client asked for.
- Text from scanned hosts in HTTP headers and mDNS records is cut to 256 characters, as banners already were.
discover_mdnstakes at most 32 service types, and browses each once.- An over-long request line no longer has its tail read as the next message.
- A request that reuses the id of one just answered can always be cancelled. A race could leave it impossible to cancel.
- The server answers
- Smaller scan fixes.
- A port behind a firewall that rejects connections with an ICMP message reads as filtered, as nmap reports it, instead of as an error.
- The HTTP probe sends IPv6 targets a valid
Hostheader, with the address in brackets. The old one was malformed, and a strict server can refuse it. - A stray
data/oui.jsonin the folder netscli ran from no longer replaces or empties the vendor list. - On a network wider than /16, the default /24 is the one around this machine's address on that network. It could come from another interface or fall back to 192.168.1.0/24.
- Windows discovery re-checks at most 64 devices at once. Checked all at once, a very long device table could drop devices that were there.
- The example in the
netscli-coreREADME compiles.
Security
- MCP packet captures never overwrite a file or follow a symlink.
capture_pcapwrotecapture.pcapin the server's working directory, often your project, and replaced any file of that name. On Linux and macOS, acapture.pcapsymlink in a repository could send the capture through to wherever it pointed, as root if the server ran as root. Captures now create a new file and refuse a name that is taken, symlinks included, and withoutoutputFileeach capture gets a new name.
- DNS lookups no longer go to Cloudflare behind your back. When your own DNS servers could not answer a lookup, including when a name simply had no records of the type asked for, NetsCLI asked Cloudflare's public resolver (1.1.1.1) the same question. That sent names you looked up to a third party, unencrypted and without saying so, and the privacy page said the opposite. It affected
dnsand every command that turns a host name into an address, in the CLI, the terminal UI, the desktop app and the MCP server. Lookups now go only to the DNS servers your computer is set up to use. Some home routers refuse record types other than A and AAAA, anddnsnow reports that refusal instead of quietly asking someone else.NETSCLI_DNS_FALLBACKno longer does anything. The privacy page now says what 0.3.4 and earlier did.