Public Access
The rest of the issue's list. tls makes a handshake that checks nothing, then says the certificate in words: who it is for, who signed it, until when, and whether this device's roots and the name asked for accept it, with the reason when they don't. ntp compares a time server's clock with the device's. netstat lists what listens and what is connected. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EhqxQ49eCju4CzKYNjZzwT
99 lines
3.7 KiB
C++
99 lines
3.7 KiB
C++
#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);
|
|
|
|
// --- NTP: the clock's offset
|
|
|
|
constexpr size_t kNtpPacket = 48;
|
|
void buildNtpRequest(uint8_t out[kNtpPacket]);
|
|
struct NtpAnswer {
|
|
int stratum = 0; // 1: a reference clock; 2 and up: that many steps from one
|
|
int64_t seconds = 0; // the server's clock when it answered, UTC since 1970
|
|
uint32_t millis = 0; // and the part of a second
|
|
};
|
|
// False if it isn't a server's answer, or says the server has no time to give.
|
|
bool parseNtpAnswer(const uint8_t* packet, size_t len, NtpAnswer& out);
|
|
// "0.3 s ahead", "12 s behind", "right, to 0.1 s": this clock against the server's, both in ms.
|
|
std::string clockOffset(int64_t ownMs, int64_t serverMs);
|
|
|
|
// --- TLS: who a certificate is for
|
|
|
|
// The common name out of a certificate's subject or issuer as mbedTLS prints it
|
|
// ("C=US, O=Let's Encrypt, CN=R11"): the CN, else the O, else all of it.
|
|
std::string certName(const std::string& dn);
|
|
// Whole days from one date to another (negative: the second is earlier).
|
|
int daysBetween(int y1, int m1, int d1, int y2, int m2, int d2);
|
|
|
|
// --- netstat
|
|
|
|
// What listens on a port of this firmware, or "".
|
|
const char* portLabel(uint16_t port, bool tcp);
|
|
|
|
} // namespace roro::net
|