Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add lan dhcp6 dns delegate #1411

Merged
merged 2 commits into from
Nov 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
4 changes: 2 additions & 2 deletions plugins/dhcp/dhcp6_plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ class DHCP6Plugin extends DHCPPlugin {

if (nameservers.length > 0){
content.push(`dhcp-option=tag:${iface},option6:dns-server,${nameservers.map(a => `[${a}]`).join(",")}`);
} else { // return router's link-local address as RDNSS option in ra
content.push(`dhcp-option=tag:${iface},option6:dns-server,[fe80::]`);
} else { // return global address as RDNSS option in ra
content.push(`dhcp-option=tag:${iface},option6:dns-server,[::]`);
}

switch (type) {
Expand Down
17 changes: 17 additions & 0 deletions plugins/interface/intf_base_plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -643,10 +643,14 @@ class InterfaceBasePlugin extends Plugin {
let dnsservers = [];
if (this.networkConfig.nameservers && this.networkConfig.nameservers.length > 0 && this.networkConfig.nameservers.some(s => new Address4(s).isValid())) {
dnsservers = this.networkConfig.nameservers.filter(s => new Address4(s).isValid());
} else {
dnsservers = await this.getOrigDNSNameservers();
}

if (this.networkConfig.dns6Servers && this.networkConfig.dns6Servers.some(s => new Address6(s).isValid())) {
dnsservers = dnsservers.concat(this.networkConfig.dns6Servers.filter(s => new Address6(s).isValid()));
} else {
dnsservers = dnsservers.concat(await this.getOrigDNS6Nameservers());
}
if (dnsservers.length > 0) {
let nameservers = dnsservers.map((nameserver) => `nameserver ${nameserver}`).join("\n") + "\n";
Expand Down Expand Up @@ -1553,6 +1557,19 @@ 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
pl.acquireApplyLock(async () => {
await 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
Loading