mirror of
https://github.com/mikecarper/MeshCore.git
synced 2026-10-22 23:31:24 +00:00
Merge observer DNS diagnostics and complete resolver restoration
This commit is contained in:
commit
7d0984cc90
6 files changed
+103
-1
No files matched your search
@@ -639,6 +639,7 @@ These settings apply across all MQTT slots:
|
||||
- `get wifi.ssid` - Get WiFi SSID
|
||||
- `get wifi.pwd` - Get WiFi password
|
||||
- `get wifi.status` - Get WiFi connection status, IP, RSSI, and uptime
|
||||
- `get link.dns` - Show the live DNS resolver list, the selected medium's gateway, and each medium's leased DNS servers (`-` means empty; `none` means never leased). Long lease lists may be truncated to fit the CLI reply.
|
||||
- `get wifi.powersave` - Get WiFi power save mode (none/min/max)
|
||||
|
||||
#### Set Commands
|
||||
|
||||
@@ -630,6 +630,7 @@ GETTERS = {
|
||||
"link.diag": lambda c: (
|
||||
"why:ethernet-not-enabled selected:wifi\n"
|
||||
"wifi:state:connected ip:192.168.1.42"),
|
||||
"link.dns": lambda c: "dns:192.168.1.1 gw:192.168.1.1 lease:192.168.1.1",
|
||||
"mqtt.status": lambda c: cli_mqtt_status(c),
|
||||
"mqtt.presets": lambda c: "\n".join(
|
||||
"%2d. %s%s" % (i + 1, n, "" if nd == "none" else " (needs %s)" % nd)
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "MQTTObserverValidation.h" // pure input validators (host-testable)
|
||||
#include <Utils.h>
|
||||
#ifdef ESP_PLATFORM
|
||||
#include "NetworkLink.h"
|
||||
#include <WiFi.h>
|
||||
#include <WiFiClientSecure.h>
|
||||
#include <esp_wifi.h>
|
||||
@@ -1031,6 +1032,8 @@ bool CommonCLI::handleObserverGetCmd(uint32_t sender_timestamp, const char* conf
|
||||
} else {
|
||||
strcpy(reply, _mqtt_prefs.wifi_password[0] ? "> ******** (local connection only)" : "> (not set)");
|
||||
}
|
||||
} else if (strcmp(config, "link.dns") == 0) {
|
||||
activeNetworkLink().formatDns(reply, 160);
|
||||
} else if (memcmp(config, "wifi.status", 11) == 0) {
|
||||
wl_status_t status = WiFi.status();
|
||||
const char* status_str;
|
||||
|
||||
@@ -34,6 +34,47 @@ extern void tcpipInit();
|
||||
|
||||
namespace {
|
||||
|
||||
// Trailing empty slots are dropped to keep remote replies short; "-" marks an
|
||||
// empty slot before a populated one, or a list with nothing in it.
|
||||
static void formatDnsList(char* out, size_t out_size, const ip_addr_t* servers, int count) {
|
||||
int last = count - 1;
|
||||
while (last >= 0 && ip_addr_isany_val(servers[last])) last--;
|
||||
out[0] = '\0';
|
||||
if (last < 0) {
|
||||
snprintf(out, out_size, "-");
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i <= last; i++) {
|
||||
size_t len = strlen(out);
|
||||
if (i > 0 && len + 1 < out_size) {
|
||||
out[len++] = ',';
|
||||
out[len] = '\0';
|
||||
}
|
||||
if (len + 1 >= out_size) return;
|
||||
if (ip_addr_isany_val(servers[i])) {
|
||||
snprintf(out + len, out_size - len, "-");
|
||||
} else {
|
||||
ipaddr_ntoa_r(&servers[i], out + len, (int)(out_size - len));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static esp_err_t readDnsServersOnTcpipThread(void* ctx) {
|
||||
ip_addr_t* servers = static_cast<ip_addr_t*>(ctx);
|
||||
for (int i = 0; i < DNS_MAX_SERVERS; i++) {
|
||||
const ip_addr_t* server = dns_getserver(i);
|
||||
servers[i] = (server != nullptr) ? *server : *IP_ADDR_ANY;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
// lwIP's server list is global, so this is what every socket resolves through.
|
||||
static void formatCurrentDnsServers(char* out, size_t out_size) {
|
||||
ip_addr_t servers[DNS_MAX_SERVERS] = {};
|
||||
esp_netif_tcpip_exec(readDnsServersOnTcpipThread, servers);
|
||||
formatDnsList(out, out_size, servers, DNS_MAX_SERVERS);
|
||||
}
|
||||
|
||||
class NetworkLinkBase : public NetworkLink {
|
||||
protected:
|
||||
std::atomic<uint64_t> _outage_bits{AlertFaultPolicy::packOutageSnapshot({false, 0, 0})};
|
||||
@@ -43,7 +84,7 @@ class NetworkLinkBase : public NetworkLink {
|
||||
bool _status_initialized = false;
|
||||
bool _last_connected = false;
|
||||
unsigned long _last_status_check = 0;
|
||||
static constexpr int kDnsServers = 2;
|
||||
static constexpr int kDnsServers = DNS_MAX_SERVERS;
|
||||
// Only ever touched on the lwIP thread (see snapshotDns()), so no atomics.
|
||||
ip_addr_t _dns_snapshot[kDnsServers] = {};
|
||||
bool _dns_captured = false;
|
||||
@@ -145,6 +186,35 @@ class NetworkLinkBase : public NetworkLink {
|
||||
public:
|
||||
void snapshotDns() { esp_netif_tcpip_exec(snapshotDnsOnTcpipThread, this); }
|
||||
|
||||
// "none" until this medium has held a lease that carried a resolver.
|
||||
void formatLeaseDns(char* out, size_t out_size) const {
|
||||
struct Copy {
|
||||
const NetworkLinkBase* self;
|
||||
ip_addr_t servers[kDnsServers];
|
||||
bool captured;
|
||||
} copy = {this, {}, false};
|
||||
esp_netif_tcpip_exec([](void* ctx) -> esp_err_t {
|
||||
Copy* c = static_cast<Copy*>(ctx);
|
||||
c->captured = c->self->_dns_captured;
|
||||
for (int i = 0; i < kDnsServers; i++) c->servers[i] = c->self->_dns_snapshot[i];
|
||||
return ESP_OK;
|
||||
}, ©);
|
||||
if (!copy.captured) {
|
||||
snprintf(out, out_size, "none");
|
||||
return;
|
||||
}
|
||||
formatDnsList(out, out_size, copy.servers, kDnsServers);
|
||||
}
|
||||
|
||||
void formatDnsFor(char* reply, size_t reply_size, IPAddress gateway) const {
|
||||
char current[64];
|
||||
char lease[64];
|
||||
formatCurrentDnsServers(current, sizeof(current));
|
||||
formatLeaseDns(lease, sizeof(lease));
|
||||
snprintf(reply, reply_size, "> dns:%s gw:%s lease:%s",
|
||||
current, gateway.toString().c_str(), lease);
|
||||
}
|
||||
|
||||
// A medium that has never held a lease with a resolver leaves the current one
|
||||
// alone rather than blanking it.
|
||||
void restoreDns() { esp_netif_tcpip_exec(restoreDnsOnTcpipThread, this); }
|
||||
@@ -325,6 +395,10 @@ class WiFiNetworkLink final : public NetworkLinkBase {
|
||||
statusName(),
|
||||
localIP().toString().c_str());
|
||||
}
|
||||
void formatDns(char* reply, size_t reply_size) const override {
|
||||
formatDnsFor(reply, reply_size, WiFi.gatewayIP());
|
||||
}
|
||||
IPAddress gatewayIP() const { return WiFi.gatewayIP(); }
|
||||
};
|
||||
|
||||
#if defined(NETWORK_PREFER_ETHERNET)
|
||||
@@ -472,6 +546,10 @@ class EthernetNetworkLink final : public NetworkLinkBase {
|
||||
snprintf(reply, reply_size, "> ethernet:%s ip=%s",
|
||||
statusName(), localIP().toString().c_str());
|
||||
}
|
||||
void formatDns(char* reply, size_t reply_size) const override {
|
||||
formatDnsFor(reply, reply_size, CH390.gatewayIP());
|
||||
}
|
||||
IPAddress gatewayIP() const { return CH390.gatewayIP(); }
|
||||
|
||||
EventState eventState() const {
|
||||
return static_cast<EventState>(
|
||||
@@ -937,6 +1015,22 @@ class AutomaticNetworkLink final : public NetworkLink {
|
||||
wifiConfigured() ? "yes" : "no", wifi_started ? "yes" : "no",
|
||||
(wifi_started && _wifi.isConnected()) ? "up" : "down");
|
||||
}
|
||||
void formatDns(char* reply, size_t reply_size) const override {
|
||||
const NetworkMedium selected = _selected.load(std::memory_order_acquire);
|
||||
char current[64];
|
||||
char eth_lease[64];
|
||||
char wifi_lease[64];
|
||||
formatCurrentDnsServers(current, sizeof(current));
|
||||
_ethernet.formatLeaseDns(eth_lease, sizeof(eth_lease));
|
||||
_wifi.formatLeaseDns(wifi_lease, sizeof(wifi_lease));
|
||||
const IPAddress gateway = selected == NetworkMedium::Ethernet ? _ethernet.gatewayIP()
|
||||
: selected == NetworkMedium::WiFi ? _wifi.gatewayIP()
|
||||
: IPAddress();
|
||||
snprintf(reply, reply_size,
|
||||
"> dns:%s selected:%s gw:%s\neth-lease:%s wifi-lease:%s",
|
||||
current, NetworkPolicy::mediumName(selected),
|
||||
gateway.toString().c_str(), eth_lease, wifi_lease);
|
||||
}
|
||||
unsigned long connectedAtMillis() const override {
|
||||
const NetworkMedium selected = _selected.load(std::memory_order_acquire);
|
||||
return selected == NetworkMedium::None
|
||||
|
||||
@@ -59,6 +59,8 @@ class NetworkLink {
|
||||
virtual int rssi() const = 0; // INT_MIN when the selected medium has no RSSI.
|
||||
virtual bool resolveHost(const char* hostname, IPAddress& address) const = 0;
|
||||
virtual void formatDiagnostics(char* reply, size_t reply_size) const = 0;
|
||||
// Live lwIP resolver list, gateway, and the DNS each medium's lease installed.
|
||||
virtual void formatDns(char* reply, size_t reply_size) const = 0;
|
||||
|
||||
virtual unsigned long connectedAtMillis() const = 0;
|
||||
virtual uint8_t lastDisconnectReason() const = 0;
|
||||
|
||||
@@ -1937,6 +1937,7 @@ var CLI_KEYS=[
|
||||
["wifi.powersave","WiFi power-save mode",0,"none|min|max"],
|
||||
["link.status","Selected network, IP, signal and uptime",1],
|
||||
["link.diag","Ethernet selection and fallback diagnostics",1],
|
||||
["link.dns","DNS servers, gateway and per-network lease DNS",1],
|
||||
["wifi.status","WiFi connection, IP, RSSI and uptime",1],
|
||||
["wifi.cli","Browser console",0,"on|off"],
|
||||
["webui","WiFi settings website",0,"on|off"],
|
||||
|
||||
Reference in new issue
Block a user