Killing all dnsmasq processes caused NetworkManager to detect its hotspot dnsmasq died and tear down the hotspot (AP appears briefly then disappears). Now leverage NM's built-in dnsmasq-shared.d config directory: write DNS hijack config before starting AP so NM's own dnsmasq picks it up. No separate dnsmasq process needed. Made-with: Cursor
62 lines
1.9 KiB
JavaScript
62 lines
1.9 KiB
JavaScript
'use strict';
|
||
|
||
const fs = require('fs');
|
||
const path = require('path');
|
||
const log = require('./logger');
|
||
|
||
const CAPTIVE_DOMAIN = 'ap.cutos.ai';
|
||
|
||
// NetworkManager 的 dnsmasq 共享配置目录
|
||
// NM 启动热点时会自动加载此目录下的 .conf 文件
|
||
const NM_DNSMASQ_DIR = '/etc/NetworkManager/dnsmasq-shared.d';
|
||
const CAPTIVE_CONF = path.join(NM_DNSMASQ_DIR, 'clawd-captive.conf');
|
||
|
||
/**
|
||
* 通过 NetworkManager 的 dnsmasq 配置实现 DNS 劫持。
|
||
*
|
||
* NM 在创建热点时自动启动 dnsmasq 并加载 dnsmasq-shared.d/ 下的配置。
|
||
* 我们只需在启动热点前写入 address=/#/gatewayIp,NM 的 dnsmasq 就会
|
||
* 把所有域名解析到网关 IP,触发 Captive Portal 检测。
|
||
*
|
||
* 不再自行管理 dnsmasq 进程,避免与 NM 冲突导致热点被拆除。
|
||
*/
|
||
class DnsHijack {
|
||
constructor() {
|
||
this._active = false;
|
||
}
|
||
|
||
/**
|
||
* 写入 DNS 劫持配置(需在 startAP 之前调用)
|
||
* @param {string} _iface - 接口名(保留参数,兼容调用)
|
||
* @param {string} gatewayIp - 网关 IP(如 10.42.0.1)
|
||
*/
|
||
start(_iface, gatewayIp) {
|
||
this.stop();
|
||
|
||
const conf = [
|
||
`# clawd captive portal DNS hijack`,
|
||
`# All DNS queries resolve to gateway to trigger captive portal`,
|
||
`address=/#/${gatewayIp}`,
|
||
].join('\n');
|
||
|
||
try {
|
||
fs.mkdirSync(NM_DNSMASQ_DIR, { recursive: true });
|
||
fs.writeFileSync(CAPTIVE_CONF, conf, 'utf8');
|
||
this._active = true;
|
||
log.info('dns', `DNS 劫持配置已写入: ${CAPTIVE_CONF} (${CAPTIVE_DOMAIN} → ${gatewayIp})`);
|
||
} catch (e) {
|
||
log.error('dns', `写入 DNS 劫持配置失败: ${e.message}`);
|
||
}
|
||
}
|
||
|
||
stop() {
|
||
if (this._active) {
|
||
try { fs.unlinkSync(CAPTIVE_CONF); } catch (_) {}
|
||
this._active = false;
|
||
log.info('dns', 'DNS 劫持配置已移除');
|
||
}
|
||
}
|
||
}
|
||
|
||
module.exports = { DnsHijack, CAPTIVE_DOMAIN };
|