You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Asuswrt-Merlin: modernize dnsmasq/SDN integration and harden service lifecycle #342
The current Asuswrt-Merlin integration has several lifecycle/ownership assumptions that become fragile on newer Merlin 3006 firmware and when other addons or user scripts coexist with ctrld.
The most visible symptom is related to Guest Network Pro / SDN (see #229), but the underlying integration concerns are broader:
ctrld can manage shared Merlin hook files too aggressively instead of owning only its own clearly delimited content;
the historical dnsmasq integration relies on complete /jffs/configs/dnsmasq*.conf snapshots, which can freeze firmware-generated state and does not map cleanly to Merlin 3006 SDN instances;
Merlin 3006 provides dedicated supported SDN extension points such as dnsmasq-sdn.postconf;
interrupted setup/cleanup or concurrent addon/user changes need conservative, retryable ownership handling;
the generated Merlin service/startup lifecycle should not trust stale/reused PIDs, lose installed argv during self-upgrade, or leave partially published shared/private scripts.
Proposed direction
Shared dnsmasq hooks
own only an explicit ctrld block inside existing shared hooks;
preserve unrelated content, ordering, modes and existing hook ownership;
migrate the legacy ctrld-generated hook format without deleting surrounding user/addon content;
avoid terminating the enclosing shared hook with ctrld-owned exit 0;
update shared files atomically and revalidate them before replacement.
Merlin 3006 / SDN
use both dnsmasq.postconf and dnsmasq-sdn.postconf;
verify the generated runtime dnsmasq configuration after restart;
fail closed when unresolved included configuration could add alternate upstreams;
never create full dnsmasq-N.conf replacements for SDN instances;
keep a compatibility fallback only for the main dnsmasq when the supported hook demonstrably did not apply;
migrate old ctrld-created snapshots conservatively with crash/retry-safe ownership state.
Service lifecycle
publish/migrate ctrld.startup atomically without clobbering unrelated files;
preserve exact installed argument boundaries;
validate PID ownership through /proc/<pid>/cmdline before status/stop actions;
serialize Merlin start/stop/restart/uninstall and the real CLI upgrade restart transaction;
make self-upgrade migration execute from the newly launched binary;
keep shared services-start / service-event edits idempotent and ownership-safe;
validate the dnsmasq PID before the diskmon service-event signal path.
Scope
This is intended for the maintained v1.x router-support line.
The work is deliberately separated from unrelated router backends and preserves the v1.x dnsmasq package's existing template behavior.
Thanks for the issue and the subsequent PR. 🙏 There's lots of solid QoL improvements here.
I'll have a look at this after the upcoming 1.5.8 release is out and we'll go from there.
🖤 Thanks again!
Small real-world datapoint from today, now that v1.5.8 is tagged.
On Merlin 3006 I changed dhcp_staticlist (removed a few stale reservations and added a new one) and then ran the normal restart_dnsmasq path. NVRAM immediately reflected the new list, but the runtime /etc/dnsmasq.conf was still being sourced from ctrld's existing /jffs/configs/dnsmasq.conf snapshot, so it temporarily kept the deleted reservations and did not include the new one.
A later ctrld lifecycle pass refreshed the snapshot and the runtime config caught up.
So this ended up being a concrete example of the "complete dnsmasq snapshot can freeze firmware-generated state" problem described in this issue. The hook-based path in #343 should avoid that stale window by letting Merlin regenerate from the current NVRAM state first and then applying ctrld's changes.
No action needed from me here, just adding a real-world data point now that 1.5.8 is out. Thanks again!
On 1.5.8, a Network Map name like Name 2.5Gbps comes through as Name 2.
With your change, the full name shows up locally, is sent upstream, and the existing client shows the new name in the Control D dashboard.
#343: I haven't validated it on hardware yet, but we've gone through it and the approach makes a lot of sense.
Next steps: because of how our internal development works, we can't merge PRs here directly. Instead, we'll bring your changes in on our side, put them through our usual review and testing, and credit you in the commit and release notes. No ETA yet.
There's nothing more you need to do. If you want to follow along or weigh in as we go, you're very welcome to, but no pressure at all.
'ppreciate the help and all this is good work. I recognize your username from some other AsusWRT-Merlin bugs we've seen in the past, so we very much appreciate your efforts. 🖤
Activity
matrix8967 commentedon Sep 30, 2026
Heya,
Thanks for the issue and the subsequent PR. 🙏 There's lots of solid QoL improvements here.
I'll have a look at this after the upcoming 1.5.8 release is out and we'll go from there.
🖤 Thanks again!
maghuro commentedon Oct 7, 2026
Small real-world datapoint from today, now that v1.5.8 is tagged.
On Merlin 3006 I changed
dhcp_staticlist(removed a few stale reservations and added a new one) and then ran the normalrestart_dnsmasqpath. NVRAM immediately reflected the new list, but the runtime/etc/dnsmasq.confwas still being sourced from ctrld's existing/jffs/configs/dnsmasq.confsnapshot, so it temporarily kept the deleted reservations and did not include the new one.A later ctrld lifecycle pass refreshed the snapshot and the runtime config caught up.
So this ended up being a concrete example of the "complete dnsmasq snapshot can freeze firmware-generated state" problem described in this issue. The hook-based path in #343 should avoid that stale window by letting Merlin regenerate from the current NVRAM state first and then applying ctrld's changes.
No action needed from me here, just adding a real-world data point now that 1.5.8 is out. Thanks again!
matrix8967 commentedon Oct 19, 2026
Heya @maghuro,
Wanted to follow up properly. I spent some time on my own
GT-AX6000(Merlin 3006.102.9_0) going through everything here.Stale dnsmasq snapshot: reproduced on stock 1.5.8.
#347: tested on the same router.
#343: I haven't validated it on hardware yet, but we've gone through it and the approach makes a lot of sense.
Next steps: because of how our internal development works, we can't merge PRs here directly. Instead, we'll bring your changes in on our side, put them through our usual review and testing, and credit you in the commit and release notes. No ETA yet.
There's nothing more you need to do. If you want to follow along or weigh in as we go, you're very welcome to, but no pressure at all.
'ppreciate the help and all this is good work. I recognize your username from some other AsusWRT-Merlin bugs we've seen in the past, so we very much appreciate your efforts. 🖤
maghuro commentedon Oct 19, 2026
Hey @matrix8967,
Thank you so much for taking the time to test all of this on your own GT-AX6000 and for such a detailed follow-up. I really appreciate it!
It's especially encouraging to see both issues reproduced and the fixes heading towards an official release.
I completely understand the internal development process, and I'm more than happy to leave things in your hands from here.
And thanks for the kind words! It's always a pleasure to contribute, especially when it helps make things better for the Asuswrt-Merlin community.
Looking forward to seeing these improvements land!