cloud_discovery: add standard FQDN fallback discovery

Add discovery method that attempts to resolve a standard FQDN when DHCP
discovery fails. This enables zero-touch provisioning in environments
where administrators configure DNS without modifying DHCP infrastructure.

The standard FQDN is configurable via STANDARD_FQDN constant (defaults
to "openwifi.network"). Administrators can configure their local DNS to
resolve this FQDN to their controller, allowing APs to discover the
controller automatically.

Discovery priority order:
1. EST enrollment (blocking)
2. DHCP discovery (Option 224/138)
3. Flash-based configuration
4. Standard FQDN resolution (NEW)
5. Cloud redirector service (internet-connected only)

The implementation uses the resolv module for DNS queries, performing
A record lookups. If resolution fails, discovery continues to the next
method. The standard FQDN method integrates with the existing discovery
block list mechanism to prevent repeated failed attempts.

Note: The boguspriv dnsmasq option may prevent FQDNs from resolving to
private IPs. Administrators should either use CG NAT Safe IP addresses
(100.64.0.0/10) or configure dnsmasq with rebind-domain-ok exceptions.

Signed-off-by: John Crispin <john@phrozen.org>
This commit is contained in:
John Crispin 2025-11-25 07:31:08 +01:00
parent b499eceebe
commit 90e2f3452d

View File

@ -3,6 +3,7 @@
'use strict';
import { ulog_open, ulog, ULOG_SYSLOG, ULOG_STDIO, LOG_DAEMON, LOG_INFO } from 'log';
import { query } from 'resolv';
import * as libubus from 'ubus';
import * as uloop from 'uloop';
import * as libuci from 'uci';
@ -17,8 +18,12 @@ const ORPHAN = 4;
const DISCOVER_DHCP = "DHCP";
const DISCOVER_FLASH = "FLASH";
const DISCOVER_FQDN = "STANDARD_FQDN";
const DISCOVER_LOOKUP = "OpenLAN";
const STANDARD_FQDN = "openwifi.network";
const STANDARD_FQDN_PORT = 15002;
let ubus = libubus.connect();
let uci = libuci.cursor();
let state = DISCOVER;
@ -229,6 +234,28 @@ function discover_flash() {
return 0;
}
function discover_standard_fqdn() {
ulog(LOG_INFO, `Trying standard FQDN: ${STANDARD_FQDN}\n`);
let result = query([STANDARD_FQDN], { type: ['A'] });
if (!result || !result[STANDARD_FQDN] || !result[STANDARD_FQDN].A) {
ulog(LOG_INFO, `Failed to resolve ${STANDARD_FQDN}\n`);
return false;
}
let address = result[STANDARD_FQDN].A[0];
ulog(LOG_INFO, `Resolved ${STANDARD_FQDN} to ${address}\n`);
if (gateway_write({ server: STANDARD_FQDN, port: STANDARD_FQDN_PORT, valid: false, hostname_validate: 1 })) {
ulog(LOG_INFO, `Discovered cloud via standard FQDN ${STANDARD_FQDN}\n`);
client_start();
set_state(VALIDATING);
return true;
}
return false;
}
function time_is_valid() {
let valid = !!fs.stat('/tmp/ntp.set');
if (!valid)
@ -269,7 +296,7 @@ function interval_handler() {
case DISCOVER:
ulog(LOG_INFO, 'Starting discover\n');
if (!time_is_valid())
return;
@ -284,6 +311,10 @@ function interval_handler() {
if (!is_discover_method_blacked() && !discover_flash())
return;
discovery_method = DISCOVER_FQDN;
if (!is_discover_method_blacked() && discover_standard_fqdn())
return;
discovery_method = DISCOVER_LOOKUP;
redirector_lookup();