Skip to content

Commit

Permalink
Fix dns6 option delegate
Browse files Browse the repository at this point in the history
  • Loading branch information
xinnige committed Nov 5, 2024
1 parent c80bfba commit 24f5a37
Show file tree
Hide file tree
Showing 7 changed files with 155 additions and 15 deletions.
1 change: 1 addition & 0 deletions core/event.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ module.exports = {
EVENT_WLAN_DOWN: "wlan_down",
EVENT_IP_CHANGE: "ipchange",
EVENT_IP6_CHANGE: "ip6change",
EVENT_DNS6_CHANGE: "dns6change",
EVENT_PD_CHANGE: "pdchange",
EVENT_PPPOE_IPV6_UP: "pppoe_ipv6_up",
EVENT_WAN_CONN_CHECK: "wan_conn_check",
Expand Down
31 changes: 30 additions & 1 deletion plugins/dhcp/dhcp6_plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
'use strict';

const pl = require('../plugin_loader.js');
const event = require('../../core/event.js');
const r = require('../../util/firerouter.js');
const fs = require('fs');
const Promise = require('bluebird');
Expand All @@ -40,7 +41,7 @@ class DHCP6Plugin extends DHCPPlugin {

async writeDHCPConfFile(iface, tags, type = "stateless", from, to, nameservers, prefixLen, leaseTime = 86400) {
tags = tags || [];
nameservers = nameservers || [];
nameservers = nameservers || await this.getDhcp6DnsServers();
let extraTags = "";
type = type || "stateless";
if (tags.length > 0) {
Expand Down Expand Up @@ -77,6 +78,20 @@ class DHCP6Plugin extends DHCPPlugin {
await fs.writeFileAsync(this._getConfFilePath(), content.join("\n"));
}

async getDhcp6DnsServers() {
const ifacePlugin = pl.getPluginInstance("interface", this.name);
if (!ifacePlugin || !await ifacePlugin.isInterfacePresent() || !ifacePlugin.isLAN()) {
return [];
}
const parentIface = ifacePlugin.networkConfig && ifacePlugin.networkConfig.ipv6DelegateFrom
if (parentIface) {
const parentIfacePlugin = pl.getPluginInstance("interface", parentIface);
const dns6 = await parentIfacePlugin.getDns6Nameservers();
return dns6.map( i => i.split('%')[0]);
}
return [];
}

async apply() {
let iface = this.name;
if (iface.includes(":")) {
Expand All @@ -97,6 +112,20 @@ class DHCP6Plugin extends DHCPPlugin {
this.networkConfig.prefixLen, this.networkConfig.lease);
this._restartService();
}

onEvent(e) {
if (!event.isLoggingSuppressed(e))
this.log.info(`Received event on ${this.name}`, e);
const eventType = event.getEventType(e);
switch (eventType) {
case event.EVENT_DNS6_CHANGE: {
this._reapplyNeeded = true;
pl.scheduleReapply();
break;
}
default:
}
}
}

module.exports = DHCP6Plugin;
11 changes: 11 additions & 0 deletions plugins/interface/intf_base_plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -1553,6 +1553,17 @@ class InterfaceBasePlugin extends Plugin {
}
break;
}
case event.EVENT_DNS6_CHANGE: {
const payload = event.getEventPayload(e);
if (payload.intf === this.name && this.isWAN()) {
// update DNS from DHCP
this.applyDnsSettings().then(() => this.updateRouteForDNS()).catch((err) => {
this.log.error(`Failed to apply DNS settings and update DNS route on ${this.name}`, err.message);
});
this.propagateConfigChanged(true);
}
break;
}
case event.EVENT_PD_CHANGE: {
const payload = event.getEventPayload(e);
const iface = payload.intf;
Expand Down
103 changes: 90 additions & 13 deletions plugins/routing/routing_plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,18 @@ class RoutingPlugin extends Plugin {
if (!af || af == 4) {
// remove DNS specific routes
if (_.isObject(this._dnsRoutes)) {
for (const dnsRoute of Object.keys(this._dnsRoutes).map(key => this._dnsRoutes[key]))
await routing.removeRouteFromTable(dnsRoute.dest, dnsRoute.gw, dnsRoute.viaIntf, dnsRoute.tableName ? dnsRoute.tableName :"main", 4).catch((err) => { });
}
this._dnsRoutes = {};
for (const dnsRoute of Object.keys(this._dnsRoutes).map(key => this._dnsRoutes[key]).filter(i => i.af == 4))
await routing.removeRouteFromTable(dnsRoute.dest, dnsRoute.gw, dnsRoute.viaIntf, dnsRoute.tableName ? dnsRoute.tableName :"main", dnsRoute.af).catch((err) => { });
this._dnsRoutes = Object.entries(this._dnsRoutes).reduce((routes, item) => { if (item[1].af == 6) routes[item[0]] = item[1]; return routes }, {});
} else { this._dnsRoutes = {} }
}
if (!af || af == 6) {
// remove DNS specific routes
if (_.isObject(this._dnsRoutes)) {
for (const dnsRoute of Object.keys(this._dnsRoutes).map(key => this._dnsRoutes[key]).filter(i => i.af == 6))
await routing.removeRouteFromTable(dnsRoute.dest, dnsRoute.gw, dnsRoute.viaIntf, dnsRoute.tableName ? dnsRoute.tableName :"main", dnsRoute.af).catch((err) => { });
this._dnsRoutes = Object.entries(this._dnsRoutes).reduce((routes, item) => { if (item[1].af != 6) routes[item[0]] = item[1]; return routes }, {});
} else {this._dnsRoutes = {}}
}
break;
}
Expand Down Expand Up @@ -224,7 +232,7 @@ class RoutingPlugin extends Plugin {
}
}

_updateDnsRouteCache(dnsIP, gw, viaIntf, metric, tableName="main") {
_updateDnsRouteCache(dnsIP, gw, viaIntf, metric, tableName="main", af=4) {
if (!this._dnsRoutes){
this._dnsRoutes = {}
}
Expand All @@ -237,7 +245,7 @@ class RoutingPlugin extends Plugin {
return;
}
}
this._dnsRoutes[viaIntf].push({dest: dnsIP, gw: gw, viaIntf: viaIntf, metric: metric, tableName: tableName});
this._dnsRoutes[viaIntf].push({dest: dnsIP, gw: gw, viaIntf: viaIntf, metric: metric, tableName: tableName, af:af});
}

async refreshGlobalIntfRoutes(intf, af = null) {
Expand Down Expand Up @@ -302,7 +310,7 @@ class RoutingPlugin extends Plugin {
}
}

const dns = await intfPlugin.getDNSNameservers();
const dns = await intfPlugin.getDns4Nameservers();
if (_.isArray(dns) && dns.length > 0) {
for (const dnsIP of dns) {
await routing.addRouteToTable(dnsIP, gw, intf, routing.RT_GLOBAL_DEFAULT, metric, 4).catch((err) => {
Expand All @@ -321,6 +329,18 @@ class RoutingPlugin extends Plugin {
if (gw6) {
await this.upsertRouteToTable("default", gw6, intf, routing.RT_GLOBAL_DEFAULT, metric, 6).catch((err) => { this.log.warn('fail to upsert route', err)});
await this.upsertRouteToTable("default", gw6, intf, "main", metric, 6).catch((err) => { this.log.warn('fail to upsert route', err)});

const dns6 = await intfPlugin.getDns6Nameservers();
if (_.isArray(dns6) && dns6.length > 0) {
for (const dns6IP of dns6) {
await routing.addRouteToTable(dns6IP, gw6, intf, routing.RT_GLOBAL_DEFAULT, metric, 6).catch((err) => {
this.log.warn(`fail to add route -6 ${dns6IP} via ${gw6} dev ${intf} table ${routing.RT_GLOBAL_DEFAULT}, err:`, err.message)});
await routing.addRouteToTable(dns6IP, gw6, intf, "main", metric, 6).then(() => {
this._updateDnsRouteCache(dns6IP, gw6, intf, metric, "main", 6);
}).catch((err) => {
this.log.warn(`fail to add route -6 ${dns6IP} via ${gw6} dev ${intf} table main, err:`, err.message)});
}
}
}
}
});
Expand Down Expand Up @@ -402,13 +422,24 @@ class RoutingPlugin extends Plugin {
if (!af || af == 4) {
// remove DNS specific routes
if (_.isObject(this._dnsRoutes)) {
for (const dnsRoute of Object.keys(this._dnsRoutes).map(key => this._dnsRoutes[key])) {
for (const dnsRoute of Object.keys(this._dnsRoutes).map(key => this._dnsRoutes[key]).filter(i => i.af == 4)) {
await routing.removeRouteFromTable(dnsRoute.dest, dnsRoute.gw, dnsRoute.viaIntf, dnsRoute.tableName ? dnsRoute.tableName : "main", 4).catch((err) => {
this.log.warn('fail to remove dns route from table main, err:', err.message)
});
}
}
this._dnsRoutes = {};
this._dnsRoutes = Object.entries(this._dnsRoutes).reduce((routes, item) => { if (item[1].af == 6) routes[item[0]] = item[1]; return routes }, {});
} else { this._dnsRoutes = {}}
}
if (!af || af == 6) {
// remove DNS specific routes
if (_.isObject(this._dnsRoutes)) {
for (const dnsRoute of Object.keys(this._dnsRoutes).map(key => this._dnsRoutes[key]).filter(i => i.af == 6)) {
await routing.removeRouteFromTable(dnsRoute.dest, dnsRoute.gw, dnsRoute.viaIntf, dnsRoute.tableName ? dnsRoute.tableName : "main", 6).catch((err) => {
this.log.warn('fail to remove dns route from table main, err:', err.message)
});
}
this._dnsRoutes = Object.entries(this._dnsRoutes).reduce((routes, item) => { if (item[1].af != 6) routes[item[0]] = item[1]; return routes }, {});
} else { this._dnsRoutes = {}}
}
}

Expand Down Expand Up @@ -479,7 +510,7 @@ class RoutingPlugin extends Plugin {
await this.upsertRouteToTable("default", gw, viaIntf, routing.RT_GLOBAL_DEFAULT, metric, 4).catch((err) => { });
await this.upsertRouteToTable("default", gw, viaIntf, "main", metric, 4).catch((err) => { });
// add route for DNS nameserver IP in global_default table
const dns = await viaIntfPlugin.getDNSNameservers();
const dns = await viaIntfPlugin.getDns4Nameservers();
if (_.isArray(dns) && dns.length !== 0) {
for (const dnsIP of dns) {
await this.upsertRouteToTable(dnsIP, gw, viaIntf, routing.RT_GLOBAL_DEFAULT, metric, 4).catch((err) => {
Expand All @@ -503,6 +534,22 @@ class RoutingPlugin extends Plugin {
if (gw6 && (ready || type === "single")) { // do not add IPv6 default route for inactive WAN under dual WAN setup, WAN connectivity check only uses IPv4
await this.upsertRouteToTable("default", gw6, viaIntf, routing.RT_GLOBAL_DEFAULT, metric, 6).catch((err) => { });
await this.upsertRouteToTable("default", gw6, viaIntf, "main", metric, 6).catch((err) => { });
// add route for ipv6 DNS nameserver IP in global_default table
const dns6 = await viaIntfPlugin.getDns6Nameservers();
if (_.isArray(dns6) && dns6.length !== 0 ){
for (const dns6IP of dns6) {
await this.upsertRouteToTable(dns6IP, gw6, viaIntf, routing.RT_GLOBAL_DEFAULT, metric, 6).catch((err) => {
this.log.error(`Failed to add route ipv6 to ${routing.RT_GLOBAL_DEFAULT} for dns ${dns6IP} via ${gw6} dev ${viaIntf}`, err.message);
});
// update all dns routes via the same interface but with new metrics in main table
await this.upsertRouteToTable(dns6IP, gw6, viaIntf, "main", metric, 6).then(() => {
this._updateDnsRouteCache(dns6IP, gw6, viaIntf, metric, "main", 6);
}).catch((err) => {
this.log.error(`Failed to add route to main for dns ${dns6IP} via ${gw6} dev ${viaIntf}`, err.message);
});
}
}

} else {
this.log.info("IPv6 gateway is not defined on global default interface " + viaIntf);
}
Expand Down Expand Up @@ -558,7 +605,7 @@ class RoutingPlugin extends Plugin {
await routing.addRouteToTable("default", gw, viaIntf, "main", metric, 4).catch((err) => { });
}
// add route for DNS nameserver IP in global_default table
const dns = await viaIntfPlugin.getDNSNameservers();
const dns = await viaIntfPlugin.getDns4Nameservers();
if (_.isArray(dns) && dns.length !== 0) {
for (const dnsIP of dns) {
await routing.addRouteToTable(dnsIP, gw, viaIntf, routing.RT_GLOBAL_DEFAULT, metric, 4, true).catch((err) => {
Expand All @@ -583,7 +630,7 @@ class RoutingPlugin extends Plugin {
if (!this._dnsRoutes[viaIntf]) {
this._dnsRoutes[viaIntf] = [];
}
this._dnsRoutes[viaIntf].push({dest: dnsIP, gw: gw, viaIntf: viaIntf, metric: metric, tableName: "main"});
this._dnsRoutes[viaIntf].push({dest: dnsIP, gw: gw, viaIntf: viaIntf, metric: metric, tableName: "main", af: af});
}
}
} else {
Expand All @@ -603,6 +650,35 @@ class RoutingPlugin extends Plugin {
await routing.addRouteToTable("default", gw6, viaIntf, "main", metric, 6).catch((err) => { });
*/
}
// add route for ipv6 DNS nameserver IP in global_default table
const dns6 = await viaIntfPlugin.getDns6Nameservers();
if (_.isArray(dns6) && dns6.length !== 0) {
for (const dns6IP of dns6) {
await routing.addRouteToTable(dns6IP, gw6, viaIntf, routing.RT_GLOBAL_DEFAULT, metric, 6, true).catch((err) => {
this.log.error(`Failed to add route to ${routing.RT_GLOBAL_DEFAULT} for dns ${dns6IP} via ${gw6} dev ${viaIntf}`, err.message);
});
let dnsRouteRemoved = false;
// remove all ipv6 dns routes via the same interface but with different metrics in main table
do {
await routing.removeRouteFromTable(dns6IP, gw6, viaIntf, "main", 6).then(() => {
dnsRouteRemoved = true;
}).catch((err) => {
dnsRouteRemoved = false;
})
} while (dnsRouteRemoved)
await routing.addRouteToTable(dns6IP, gw6, viaIntf, "main", metric, 6, true).catch((err) => {
this.log.error(`Failed to add route to main for dns ${dns6IP} via ${gw6} dev ${viaIntf}`, err.message);
});
if (!this._dnsRoutes){
log.warn("should init _dnsRoutes in load_balance mode");
this._dnsRoutes = {}
}
if (!this._dnsRoutes[viaIntf]) {
this._dnsRoutes[viaIntf] = [];
}
this._dnsRoutes[viaIntf].push({dest: dns6IP, gw: gw6, viaIntf: viaIntf, metric: metric, tableName: "main", af: af});
}
}
} else {
this.log.info("Failed to get IPv6 gateway of global default interface " + viaIntf);
}
Expand All @@ -616,6 +692,7 @@ class RoutingPlugin extends Plugin {
await routing.addMultiPathRouteToTable("default", routing.RT_GLOBAL_DEFAULT, 6, ...multiPathDesc6).catch((err) => { });
await routing.addMultiPathRouteToTable("default", "main", 6, ...multiPathDesc6).catch((err) => { });
}

break;
}
default:
Expand Down
18 changes: 18 additions & 0 deletions scripts/firerouter_dhcpcd_resolv_dns6
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ resolv_conf_file="/run/resolvconf/interface/$interface.dhcpcd"
NL="
"
: ${resolvconf:=resolvconf}
dns_changed=""
dns6_md5=""

# Extract any ND DNS options from the RA
# For now, we ignore the lifetime of the DNS options unless they
Expand Down Expand Up @@ -93,6 +95,7 @@ add_resolv_conf()
[ "$new_domain_name" = "$1" ] && warn=true
fi
fi

if [ -n "$new_domain_search" ]; then
if valid_domainname_list $new_domain_search; then
conf="${conf}search $new_domain_search$NL"
Expand All @@ -106,6 +109,10 @@ add_resolv_conf()
done

echo "${conf}" > $resolv_conf_file
new_dns6_md5=`md5sum $resolv_conf_file | cut -d" " -f1`
if [ "$dns6_md5" != "$new_dns6_md5" ];then
redis-cli -n 1 publish "dhcpcd6.dns_change" "$interface"
fi

if type "$resolvconf" >/dev/null 2>&1; then
[ -n "$ifmetric" ] && export IF_METRIC="$ifmetric"
Expand All @@ -120,8 +127,19 @@ remove_resolv_conf()
"$resolvconf" -d "$ifname" -f
fi
rm $resolv_conf_file
if [ -n "$dns6_md5" ]; then
redis-cli -n 1 publish "dhcpcd6.dns_change" "$interface"
fi
}

md5_resolv_conf()
{
if [ -s $resolv_conf_file ]; then
dns6_md5=`md5sum $resolv_conf_file | cut -d" " -f1`
fi
}

md5_resolv_conf
# For ease of use, map DHCP6 names onto our DHCP4 names
case "$reason" in
BOUND6|RENEW6|REBIND6|REBOOT6|INFORM6)
Expand Down
2 changes: 1 addition & 1 deletion scripts/firerouter_upgrade_check.sh
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ FIREROUTER_CANARY_SCRIPT="${FIREROUTER_HOME}/scripts/firerouter_upgrade_canary.s
FRCANARY_FLAG="/home/pi/.router/config/.no_upgrade_canary"

if [[ -e "$FIREROUTER_CANARY_SCRIPT" ]];then
$FIREROUTER_CANARY_SCRIPT &> /tmp/firerouter_upgrade_canary.log
bash $FIREROUTER_CANARY_SCRIPT &> /tmp/firerouter_upgrade_canary.log
fi

if [[ -e $FRCANARY_FLAG ]]; then
Expand Down
4 changes: 4 additions & 0 deletions sensors/ipchange_sensor.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ class IPChangeSensor extends Sensor {
case "dhcpcd6.pd_change":
eventType = event.EVENT_PD_CHANGE;
break;
case "dhcpcd6.dns_change":
eventType = event.EVENT_DNS6_CHANGE;
break;
case "pppoe.ipv6_up":
eventType = event.EVENT_PPPOE_IPV6_UP;
break;
Expand Down Expand Up @@ -68,6 +71,7 @@ class IPChangeSensor extends Sensor {
sclient.subscribe("pppoe.ip_change");
sclient.subscribe("dhcpcd6.ip_change");
sclient.subscribe("dhcpcd6.pd_change");
sclient.subscribe("dhcpcd6.dns_change");
sclient.subscribe("pppoe.ipv6_up");
}
}
Expand Down

0 comments on commit 24f5a37

Please sign in to comment.