Shell: ping, nslookup, port, traceroute, ifconfig and arp (#90)
CI / build (pull_request) Successful in 1m38s
Site / build (pull_request) Successful in 11s

Network troubleshooting from the device itself, in the Shell and over both
consoles. ping, nslookup, port and traceroute each run on a task of their
own and print as they go, to the console that asked; one at a time, and
`cancel` stops it. ifconfig and arp answer at once: the interfaces (Wi-Fi
and the VPN), which is the default route, the DNS servers, the neighbours.

nslookup asks a DNS server itself, so it can say which server answered and
in how long, and ask another. A sized ping finds what a tunnel really
carries.

With a how-to, "When the network doesn't work", and the rest of the docs.
tls, ntp and netstat from the issue's list are not in this.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EhqxQ49eCju4CzKYNjZzwT
This commit is contained in:
2026-10-08 02:29:04 +02:00
co-authored by Claude Opus 5.5
parent 86172c0342
commit ed7abdcaf5
16 changed files with 969 additions and 6 deletions
+4
View File
@@ -39,6 +39,8 @@ install <path.ota> Update from SD
update check | update list | update status | update install <tag> the project's releases on Gitea
sd card | sd list | cat <path> | log <text> | burst | sound on|off | short | normal
Irc | Wifi | Gnss | Gemini | Lora | Storage | Notes | Shell | System | Settings open that App: a capital letter is an App, not a command
ping <host> [count] [size] | nslookup <name> [server] | port <host> <port> | traceroute <host> | cancel is it there, does its name resolve, is its port open, which way; one at a time
ifconfig | arp the interfaces (Wi-Fi and the VPN), their addresses, the default route and the DNS servers; the neighbours heard
vpn status | vpn up [seconds] | vpn down | vpn import [path] | vpn forget | vpn auto on|off the WireGuard tunnel (Settings > VPN); import reads /vpn/wg0.conf; with seconds, it goes down by itself
debug status | debug off [seconds] the Debug Console over Wi-Fi (Settings > Debug Console); with seconds, it comes back
debug on | debug token <16 to 64 characters> | debug token new (USB serial only) switch it on, set its token
@@ -110,6 +112,8 @@ In **Safe Mode** (see [Crashes and Safe Mode](/dev/debug/crashes/)) only a few r
| `coredump erase` | Forgets the core dump |
| `loop spin on` / `loop spin off` | Make the main loop spin without resting, to compare load and radio noise |
| `crash abort` / `crash wdt` | Crash on purpose, or hang the main loop until the watchdog fires |
| `ping <host> [count] [size]` / `nslookup <name> [server]` / `port <host> <port>` / `traceroute <host>` / `cancel` | Network troubleshooting (issue #90): does a host answer and how fast; a name's addresses, from which DNS server and in how long; is a TCP port open, refused or silent; the routers on the way. Each runs on a task of its own and prints as it goes, one at a time; `cancel` stops it |
| `ifconfig` / `arp` | The interfaces (Wi-Fi and the VPN) with their addresses, MTU, which is the default route, and the DNS servers; the neighbours heard on the Wi-Fi |
| `vpn status` / `vpn up [seconds]` / `vpn down` / `vpn import [path]` / `vpn forget` / `vpn auto on\|off` | The WireGuard tunnel: its state, on (for that many seconds, then off by itself: for trying a configuration from afar), off, read a `.conf` from the card (`/vpn/wg0.conf`), erase it, start with Wi-Fi. No key is ever printed |
| `debug status` / `debug off [seconds]` | The Debug Console: whether it's on, has a token and a client; switch it off. With a number of seconds, it comes back by itself after that long |
| `debug on` / `debug token <value>` / `debug token new` | USB serial only: switch it on (making a token if there's none), give it a token of 16 to 64 characters, or make a new one. The token is never printed |
+41 -1
View File
@@ -8,7 +8,7 @@ docs = true
source = "docs/milestones/N1.md"
tag = "N1"
+++
**Status:** in progress. The WireGuard tunnel (issue #8) shipped as **v0.19.0**. SSH (#2) is not started.
**Status:** in progress. The WireGuard tunnel (issue #8) shipped as **v0.19.0**. The network troubleshooting commands (issue #90) are built: `ping`, `nslookup`, `port`, `traceroute`, `ifconfig`, `arp`; `tls`, `ntp` and `netstat` are still to do. SSH (#2) is not started.
**Goal:** reach things from the device that aren't on the Wi-Fi it happens to be on, and keep its traffic private on a network that isn't yours.
@@ -89,3 +89,43 @@ The test keys were made for the purpose and deleted. Two rounds: first with the
**Taking the tunnel down reconnected Wi-Fi.** The first version gave DHCP's DNS servers back by asking for a new lease, which is how the Wi-Fi settings do it, and which drops every connection: the Debug Console session that had typed `vpn down` among them. The servers that were there are now simply remembered and put back.
**"What AllowedIPs say" was more than the network stack can do.** The design round promised split tunnels by AllowedIPs. lwIP has no routing table: it can send by an interface's subnet, or by default. So it is one subnet or everything, and the import tells which.
## Network troubleshooting commands (issue #90)
With a tunnel, fixed addresses and a file server on the device, "is it the network or is it me" needed another machine to answer.
### Decisions (2026-10-08; built on the issue's list, without a round of questions)
- **The familiar names:** `ping`, `nslookup`, `traceroute`, `ifconfig`, `arp`. `port <host> <port>` for "is that TCP port open", which has no single familiar name.
- **In this version:** those six. **Not yet:** `tls` (why a certificate fails), `ntp` (the clock's offset), `netstat` (what listens). The issue stays open for them.
- **Commands only,** in the Shell and over both consoles; no page in an App.
- **One line an answer, short:** a Shell line is 38 characters.
### As built
- **`lib/net/src/net_probe.h`** (host-tested, 5 tests): what was typed; the ICMP echo request and what answers it, a router's "time exceeded" included; the DNS query and its answer, with the pointers names are shortened by.
- **`NetTools`** (`src/services/net_tools`): `ping`, `nslookup`, `port` and `traceroute` each run on a task of their own, made for the command and gone after it, printing to the console that asked (the Shell shows only its own replies). One at a time; `cancel` stops it within a fifth of a second.
- **`ping`** and **`traceroute`** share a raw ICMP socket: a traceroute is echo requests allowed one hop, then two, then three, and the routers' complaints are the list.
- **`nslookup`** asks one server itself, over UDP, and so can say which server answered and how long it took, which the system's resolver doesn't; and it can ask a server that isn't the configured one.
- **`port`** is a connection attempt that is not waited for: open, refused, or five seconds of nothing.
- **`ifconfig`** and **`arp`** read lwIP's own lists, with its lock held.
- **Cost:** 12 KB of flash. A 6 KB task while a command runs (2.6 KB of it never used), nothing otherwise.
### Checks on the device (2026-10-08, with the VPN up and everything routed through it)
| Check | Result |
|---|---|
| `ifconfig` | `vpn 10.9.0.2/32 mtu 1420, up, default route`; `wifi ... gw ... mtu 1500, up`; the DNS server |
| `arp` | The gateway and one other machine |
| `ping` of a neighbour, of a name | 4 of 4 in 3 to 4 ms; 3 of 3 in about 50 ms |
| `ping 9.9.9.9 2 1392`, then `1393` | Both back; neither back: the tunnel carries 1420 bytes exactly |
| `nslookup` | The address, the server and the time; an alias followed; with another server; "there is no nope.invalid" |
| `port` | `open, 52 ms`; `refused`; "no answer in 5 s"; "doesn't resolve" |
| `traceroute 9.9.9.9` | Nine hops, the tunnel's server first, "arrived" |
| A second command while a ping runs | "another one is running: `cancel` stops it" |
| `cancel` | "stopped", with the count so far |
| In the Shell | Tab completes them; the lines appear there and only there |
**Not checked:** without the VPN (every check went through the tunnel, or to the local network); a network that drops ICMP; the commands in Safe Mode, where they are not offered.
**Found on the way:** a refused connection is reported by lwIP as "reset", not "refused"; the first version called it "no route". And the header for the tested half was first given the same name as the service's, which makes a file include itself: the same mistake as an hour before, in the same way.