Public Access
Shell: ping, nslookup, port, traceroute, ifconfig and arp (#90)
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:
@@ -0,0 +1,71 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// The parts of the network troubleshooting commands (issue #90) that need no network: what was
|
||||
// asked, the packets to send, and what the answers mean. The sockets are src/services/net_tools.h (a different name on purpose: two headers of one name find themselves).
|
||||
namespace roro::net {
|
||||
|
||||
// --- what was typed
|
||||
|
||||
struct PingArgs {
|
||||
std::string host;
|
||||
int count = 4; // 1 to 100
|
||||
int size = 56; // bytes of payload, 0 to 1400: with its headers a ping is 28 more
|
||||
};
|
||||
// "ping <host> [count] [size]". "" or how to ask.
|
||||
std::string parsePing(const std::string& args, PingArgs& out);
|
||||
|
||||
struct PortArgs {
|
||||
std::string host;
|
||||
uint16_t port = 0;
|
||||
};
|
||||
// "port <host> <port>", or host:port.
|
||||
std::string parsePort(const std::string& args, PortArgs& out);
|
||||
|
||||
struct LookupArgs {
|
||||
std::string name, server; // server: an address, or "" for the one in use
|
||||
};
|
||||
std::string parseLookup(const std::string& args, LookupArgs& out);
|
||||
|
||||
// --- ICMP: ping and traceroute
|
||||
|
||||
uint16_t inetChecksum(const uint8_t* data, size_t len);
|
||||
// An echo request: 8 bytes of header and `payload` bytes after it. The length written, or 0 if
|
||||
// it doesn't fit.
|
||||
size_t buildEcho(uint8_t* out, size_t max, uint16_t id, uint16_t seq, size_t payload);
|
||||
|
||||
struct IcmpAnswer {
|
||||
enum class Kind { Other, Echo, TimeExceeded, Unreachable } kind = Kind::Other;
|
||||
uint16_t id = 0, seq = 0; // of the echo request it answers
|
||||
};
|
||||
// `packet` as a raw socket hands it over: the IP header first. A router's "time exceeded" and
|
||||
// "unreachable" carry the start of the packet they are about, which is where id and seq come from.
|
||||
IcmpAnswer parseIcmp(const uint8_t* packet, size_t len);
|
||||
|
||||
// What a run of pings came to: "3/4 back, 25% lost, 12/25/41 ms" (the least, the mean, the most).
|
||||
struct PingStats {
|
||||
int sent = 0, back = 0;
|
||||
uint32_t minMs = 0, maxMs = 0, sumMs = 0;
|
||||
void add(uint32_t ms);
|
||||
std::string summary() const;
|
||||
};
|
||||
|
||||
// --- DNS: nslookup
|
||||
|
||||
// A query for the IPv4 addresses of `name`. The length written, or 0 if that isn't a name.
|
||||
size_t buildDnsQuery(uint8_t* out, size_t max, uint16_t id, const std::string& name);
|
||||
|
||||
struct DnsAnswer {
|
||||
int rcode = 0; // 0: fine, 3: no such name
|
||||
bool truncated = false; // the answer didn't fit in one packet
|
||||
std::vector<uint32_t> addresses;
|
||||
std::string alias; // the last name a CNAME led to, if any
|
||||
};
|
||||
// False if it isn't the answer to query `id`, or is cut short.
|
||||
bool parseDnsAnswer(const uint8_t* message, size_t len, uint16_t id, DnsAnswer& out);
|
||||
|
||||
} // namespace roro::net
|
||||
Reference in New Issue
Block a user