From aec2514eae4a81459b5ab62a45747afa557f7cfd Mon Sep 17 00:00:00 2001 From: Joachim Wiberg Date: Mon, 27 Mar 2023 14:05:03 +0200 Subject: [PATCH] mech: add support for ietf-syste:system/dns-resolver This commit adds multi-nameserver support using openresolv (resolvconf) and dnsmasq. This means that a DHCP client (dhcpcd) or VPN client can be providers of nameservers to the system. Dnsmasq takes over as the system resolver, except when the user has set up static configuration. Static nameserver(s), as well as search and options, are always added first by openresolv to /etc/resolv.conf. Signed-off-by: Joachim Wiberg --- board/common/rootfs/etc/dnsmasq.conf | 14 +++ board/common/rootfs/etc/dnsmasq.d/.empty | 0 board/common/rootfs/etc/resolvconf.conf | 10 ++ .../rootfs/etc/resolvconf/interface-order | 1 + board/common/rootfs/lib/infix/clean-etc | 2 +- package/mech/clixon.conf | 1 + package/mech/tmpfiles.conf | 3 +- .../etc/finit.d/available/dnsmasq.conf | 2 +- patches/openresolv/3.12.0/finit-support.patch | 12 +++ .../openresolv/foo-3.12.0/finit-support.patch | 16 +++ src/mech/src/ietf-system/ietf-system.c | 97 +++++++++++++++++++ 11 files changed, 155 insertions(+), 3 deletions(-) create mode 100644 board/common/rootfs/etc/dnsmasq.conf create mode 100644 board/common/rootfs/etc/dnsmasq.d/.empty create mode 100644 board/common/rootfs/etc/resolvconf.conf create mode 100644 board/common/rootfs/etc/resolvconf/interface-order create mode 100644 patches/openresolv/3.12.0/finit-support.patch create mode 100644 patches/openresolv/foo-3.12.0/finit-support.patch diff --git a/board/common/rootfs/etc/dnsmasq.conf b/board/common/rootfs/etc/dnsmasq.conf new file mode 100644 index 00000000..f093056b --- /dev/null +++ b/board/common/rootfs/etc/dnsmasq.conf @@ -0,0 +1,14 @@ +# dnsmasq is the system resolver, the file /etc/resolv.conf is +# managed by openresolv. DHCP lease, VPN tunnel establishment, +# and similar events feed servers and configuration to dnsmasq. +domain-needed +#interface=lo +listen-address=127.0.0.1 +enable-dbus + +# Generated by openresolv +resolv-file=/var/lib/misc/resolv.conf + +# Include all files in a directory which end in .conf +conf-dir=/etc/dnsmasq.d/,*.conf + diff --git a/board/common/rootfs/etc/dnsmasq.d/.empty b/board/common/rootfs/etc/dnsmasq.d/.empty new file mode 100644 index 00000000..e69de29b diff --git a/board/common/rootfs/etc/resolvconf.conf b/board/common/rootfs/etc/resolvconf.conf new file mode 100644 index 00000000..d7055fee --- /dev/null +++ b/board/common/rootfs/etc/resolvconf.conf @@ -0,0 +1,10 @@ +# dnsmasq is the system resolver +name_servers="127.0.0.1" + +resolv_conf=/etc/resolv.conf +resolv_conf_options="edns0 trust-ad" + +# dnsmasq specific settings and list of +# nameservers in non-standard locations +dnsmasq_conf=/etc/dnsmasq.d/resolvconf.conf +dnsmasq_resolv=/var/lib/misc/resolv.conf diff --git a/board/common/rootfs/etc/resolvconf/interface-order b/board/common/rootfs/etc/resolvconf/interface-order new file mode 100644 index 00000000..75476e0f --- /dev/null +++ b/board/common/rootfs/etc/resolvconf/interface-order @@ -0,0 +1 @@ +lo diff --git a/board/common/rootfs/lib/infix/clean-etc b/board/common/rootfs/lib/infix/clean-etc index ab2a0ddc..0ced63a0 100755 --- a/board/common/rootfs/lib/infix/clean-etc +++ b/board/common/rootfs/lib/infix/clean-etc @@ -7,7 +7,7 @@ # ... except for some core services reserved() { - for svc in clixon getty lldpd nginx sysklogd; do + for svc in clixon dnsmasq getty lldpd nginx sysklogd; do [ "$1" = "${svc}.conf" ] && return 0 done diff --git a/package/mech/clixon.conf b/package/mech/clixon.conf index 4f497826..1fdd25d4 100644 --- a/package/mech/clixon.conf +++ b/package/mech/clixon.conf @@ -5,3 +5,4 @@ run if: name:clixon :boot log:prio:daemon.warning \ service if: name:clixon log:prio:daemon.warning \ [12345789] clixon_backend -F -l s -D 7 -s none -- Configuration daemon +task if: [12345789] resolvconf -u -- Update DNS configuration diff --git a/package/mech/tmpfiles.conf b/package/mech/tmpfiles.conf index 6356a630..6906299b 100644 --- a/package/mech/tmpfiles.conf +++ b/package/mech/tmpfiles.conf @@ -1 +1,2 @@ -d /run/clixon - - - +d /run/clixon - - - +d /run/resolvconf/interfaces - - - diff --git a/package/skeleton-init-finit/skeleton/etc/finit.d/available/dnsmasq.conf b/package/skeleton-init-finit/skeleton/etc/finit.d/available/dnsmasq.conf index 3b34dfe5..84562903 100644 --- a/package/skeleton-init-finit/skeleton/etc/finit.d/available/dnsmasq.conf +++ b/package/skeleton-init-finit/skeleton/etc/finit.d/available/dnsmasq.conf @@ -1 +1 @@ -service [2345] dnsmasq -k -- DHCP/DNS proxy +service [S12345789] dnsmasq -k -u root -- DHCP/DNS proxy diff --git a/patches/openresolv/3.12.0/finit-support.patch b/patches/openresolv/3.12.0/finit-support.patch new file mode 100644 index 00000000..6b9be23e --- /dev/null +++ b/patches/openresolv/3.12.0/finit-support.patch @@ -0,0 +1,12 @@ +diff -ru openresolv-3.12.0.orig/resolvconf.in openresolv-3.12.0/resolvconf.in +--- openresolv-3.12.0.orig/resolvconf.in 2020-12-27 19:05:10.000000000 +0100 ++++ openresolv-3.12.0/resolvconf.in 2023-03-27 00:19:03.365164029 +0200 +@@ -315,6 +315,8 @@ + then + /usr/bin/systemctl restart $1.service + fi' ++ elif [ -x /sbin/initctl ]; then ++ RESTARTCMD="/sbin/initctl -bnq restart \$1" + elif [ -x /sbin/rc-service ] && + { [ -s /libexec/rc/init.d/softlevel ] || + [ -s /run/openrc/softlevel ]; } diff --git a/patches/openresolv/foo-3.12.0/finit-support.patch b/patches/openresolv/foo-3.12.0/finit-support.patch new file mode 100644 index 00000000..1e1588df --- /dev/null +++ b/patches/openresolv/foo-3.12.0/finit-support.patch @@ -0,0 +1,16 @@ +diff -ru openresolv-3.12.0.orig/resolvconf.in openresolv-3.12.0/resolvconf.in +--- openresolv-3.12.0.orig/resolvconf.in 2020-12-27 19:05:10.000000000 +0100 ++++ openresolv-3.12.0/resolvconf.in 2023-03-27 00:19:03.365164029 +0200 +@@ -315,6 +315,12 @@ + then + /usr/bin/systemctl restart $1.service + fi' ++ elif [ -x /sbin/initctl ]; then ++ # Finit ++ RESTARTCMD=' ++ if /sbin/initctl -bq status $1; then ++ /sbin/initctl -bnq restart $1 ++ fi' + elif [ -x /sbin/rc-service ] && + { [ -s /libexec/rc/init.d/softlevel ] || + [ -s /run/openrc/softlevel ]; } diff --git a/src/mech/src/ietf-system/ietf-system.c b/src/mech/src/ietf-system/ietf-system.c index 69db9bc7..ce02ceba 100644 --- a/src/mech/src/ietf-system/ietf-system.c +++ b/src/mech/src/ietf-system/ietf-system.c @@ -89,6 +89,20 @@ static bool is_true(cxobj *xp, char *name) return false; } +static char *get_str(cxobj *xp, char *name) +{ + cxobj *obj; + + if (!xp || !name) + return NULL; + + obj = xml_find(xp, name); + if (obj) + return xml_body(obj); + + return NULL; +} + static int sys_reload_services(void) { return run("initctl -nbq touch sysklogd lldpd"); @@ -244,6 +258,83 @@ disable: return run("initctl -nbq disable chronyd"); } +/* + * dnsmasq is the resolver, it gets its nameservers from various + * sources: static, dhcp, vpn, via the resolvconf wrapper. + */ +int ietf_sys_tr_commit_dns(cxobj *src, cxobj *tgt) +{ + const char *fn = "/etc/resolv.conf.head"; + cxobj *obj, *opt = NULL, *srv = NULL; + int first = 1, valid = 0; + FILE *fp; + + clicon_log(LOG_ERR, "ietf-system: dns src %p tgt %p", src, tgt); + if (!tgt) + goto disable; + + fp = fopen(fn, "w"); + if (!fp) { + clicon_log(LOG_WARNING, "ietf-system: failed updating %s: %s", fn, strerror(errno)); + return -1; + } + + obj = xml_find(tgt, "options"); + if (obj) { + char *str; + + fprintf(fp, "options"); + str = get_str(obj, "timeout"); + if (str) + fprintf(fp, " timeout:%s", str); + str = get_str(obj, "attempts"); + if (str) + fprintf(fp, " attempts:%s ", str); + fprintf(fp, "\n"); + } + + while ((opt = xml_child_each(tgt, opt, CX_ELMNT))) { + if (strcmp(xml_name(opt), "search")) + continue; + + if (first) { + fprintf(fp, "search "); + first = 0; + } + fprintf(fp, "%s ", xml_body(opt)); + } + if (!first) + fprintf(fp, "\n"); + + while ((srv = xml_child_each(tgt, srv, CX_ELMNT))) { + cxobj *tmp; + + if (strcmp(xml_name(srv), "server")) + continue; + + tmp = xml_find(srv, "udp-and-tcp"); + if (tmp) { + obj = xml_find(tmp, "address"); + if (obj) { + fprintf(fp, "nameserver %s\n", xml_body(obj)); + valid++; + } + } + } + fclose(fp); +disable: + if (!valid) + remove(fn); + + if (run("initctl cond get hook/sys/up")) { + clicon_log(LOG_ERR, "ietf-system: failed cond get hook/sys/up"); + return 0; + } + + clicon_log(LOG_ERR, "ietf-status: calling resolvconf -u"); + return run("resolvconf -u"); +} + int ietf_sys_tr_commit(clicon_handle h, transaction_data td) { cxobj *src = transaction_src(td), *tgt = transaction_target(td); @@ -270,10 +361,16 @@ int ietf_sys_tr_commit(clicon_handle h, transaction_data td) tlen ? xml_find(tsys[0], "clock") : NULL); if (err) goto err; + err = ietf_sys_tr_commit_ntp(slen ? xml_find(ssys[0], "ntp") : NULL, tlen ? xml_find(tsys[0], "ntp") : NULL); if (err) goto err; + + err = ietf_sys_tr_commit_dns(slen ? xml_find(ssys[0], "dns-resolver") : NULL, + tlen ? xml_find(tsys[0], "dns-resolver") : NULL); + if (err) + goto err; err: err = err ? : aug_save(aug); return err;