From: Tj <linux@iam.tj> To: linux-ppp@vger.kernel.org Subject: RFC: support setting DNS for systemd-resolved via DBus Date: Tue, 04 Sep 2018 10:17:03 +0000 [thread overview] Message-ID: <e5fa9fe1-073c-e9c5-c774-21bc5487fe7e@iam.tj> (raw) I've recently been building an embedded device to do (kernel-mode) PPPoE which uses only systemd-networkd + systemd-resolved (PC Engines APU2 with Ubuntu 18.04 - amd64). I discovered the ip-up.d/0000usepeerdns script doesn't support systemd-resolved. In this case /etc/resolv.conf was over-written since resolvconf is not installed but is a symlink to ../run/systemd/resolve/stub-resolv.conf. After some experimentation I've put together a small C helper program that reads DNS[12]= from the helper environment and uses DBus calls to set the per-link nameservers. It build-depends on libdbus but not systemd. I'm looking for feedback on whether this would be acceptable as an addition to the ppp project, and if so where in the source tree would be appropriate. I'd assume it'd be controlled by a ./configure switch (due to introducing a dependency on libdbus) but as the current ./configure isn't generated by autoconf maybe there is some other way to do this? If not considered to be part of ppp what would be the best distribution method? Usually the tool is silent but with internal 'debug=1' stderr reports progress thus: ./ppp-systemd-resolved-set-nameservers wlp11s0 Interface index: 4 DNS2\x1011:1213:1415:1617::A0A1:A2A3 == 1011:1213:1415:1617::A0A1:A2A3 DNS1=1.2.3.4 == 1.2.3.4 Dbus SetLinkDNS() Protocol: 10 Address: 1011:1213:1415:1617::a0a1:a2a3 Dbus SetLinkDNS() Protocol: 2 Address: 1.2.3.4 I'm including a patch for the tool alone (outside of the ppp repository). -- 2 files changed, 130 insertions(+) diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..e2dc6cc --- /dev/null +++ b/Makefile @@ -0,0 +1,9 @@ +# hard coded for now + +PROG=ppp_systemd-resolved_set_nameservers +all: + gcc -g -o0 -I/usr/include/dbus-1.0 -I/usr/lib/x86_64-linux-gnu/dbus-1.0/include -o $(PROG) $(PROG).c -ldbus-1 + +clean: + rm $(PROG) + diff --git a/ppp_systemd-resolved_set_nameservers.c b/ppp_systemd-resolved_set_nameservers.c new file mode 100644 index 0000000..10d13c0 --- /dev/null +++ b/ppp_systemd-resolved_set_nameservers.c @@ -0,0 +1,121 @@ +/* + * Set DNS nameservers provided via PPP env-vars using systemd-resolved + * (c) Copyright 2018 Tj <hacker@iam.tj> + * Licenced on the terms of the GNU General Public Licence version 3 + */ + +#include <stdio.h> +#include <string.h> +#include <net/if.h> +#include <arpa/inet.h> +#include <dbus/dbus.h> + +const char * const dbus_resolve1_name = "org.freedesktop.resolve1"; +const char * const dbus_resolve1_object = "/org/freedesktop/resolve1"; +static const unsigned int debug = 1; + +int main(int argc, char **argv, char **env) +{ + dbus_int32_t ifindex = -1; + unsigned int dns_count = 0; + char *dns_fmt = "DNS%d="; + char dns[6]; + ssize_t ssize_in6 = sizeof(struct in6_addr); + unsigned char nameservers[2][ssize_in6 + 1]; // last byte stores protocol (AF_INET/AF_INET6) + + nameservers[0][0] = nameservers[1][0] = 0; + + if (argc > 1) + { + ifindex = if_nametoindex(argv[1]); + if (ifindex) { + if (debug) fprintf(stderr, "Interface index: %d\n", ifindex); + for (char **p = env; *p && dns_count < 2; p++) { // search the environment + for (int i = 1; i <= 2; i++) { // pppd passes up to 2 DNS IP addresses + snprintf(dns, 6, dns_fmt, i); + if (strncmp(dns, *p, 5) = 0) { + if (debug) fprintf(stderr, "%s == %s\n", *p, (*p + 5)); + if (inet_pton(AF_INET, (*p + 5), (void *)nameservers[dns_count]) != 1) + if (inet_pton(AF_INET6, (*p + 5), (void *)nameservers[dns_count]) != 1) + fprintf(stderr, "unable to decode %s\n", *p); + else { + nameservers[dns_count++][ssize_in6] = AF_INET6; + } + else { + nameservers[dns_count++][ssize_in6] = AF_INET; + } + } + } + } + if (dns_count > 0) { // at least 1 DNS nameserver found + char buffer[128]; + buffer[0] = 0; + dbus_uint32_t dbus_serial = 1; + DBusError dbus_err; + dbus_error_init(&dbus_err); + DBusMessageIter dbus_iter0, dbus_iter1, dbus_iter2, dbus_iter3; + DBusConnection *dbus_connection = dbus_bus_get(DBUS_BUS_SYSTEM, &dbus_err); + if (dbus_connection = NULL) + fprintf(stderr, "%s\n", dbus_err.message); + else { + DBusMessage *set_link_dns = dbus_message_new_method_call(dbus_resolve1_name, + dbus_resolve1_object, + dbus_resolve1_name, + "SetLinkDNS"); + if (set_link_dns = NULL) + fprintf(stderr, "%s\n", "Unable to allocate memory for dbus_message_new_method_call()"); + else { + // dbus argument signature: in i ifindex, in a(iay) addresses + if (!dbus_message_append_args(set_link_dns, DBUS_TYPE_INT32, &ifindex)) + fprintf(stderr, "%s\n", "dbus_message_append_args(ifindex) failed"); + dbus_message_iter_init_append(set_link_dns, &dbus_iter0); + if (!dbus_message_iter_open_container(&dbus_iter0, DBUS_TYPE_ARRAY, "(iay)", &dbus_iter1)) + fprintf(stderr, "%s\n", "dbus_message_iter_open_container(ARRAY, '(iay)') failed"); + else { + for(int i = 0; i < dns_count; i++) { + if(!dbus_message_iter_open_container(&dbus_iter1, DBUS_TYPE_STRUCT, NULL, &dbus_iter2)) + fprintf(stderr, "%s\n", "dbus_message_iter_open_container(STRUCT, NULL) failed"); + else { + dbus_int32_t len = nameservers[i][ssize_in6] = AF_INET ? 4 : 16; + dbus_int32_t af = nameservers[i][ssize_in6]; + unsigned char *p_nameserver = nameservers[i]; + if (!dbus_message_iter_append_basic(&dbus_iter2, DBUS_TYPE_INT32, &af)) + fprintf(stderr, "%s\n", "dbus_message_iter_append_basic(INT32, af) failed"); + if (!dbus_message_iter_open_container(&dbus_iter2, DBUS_TYPE_ARRAY, "y", &dbus_iter3)) + fprintf(stderr, "%s\n", "dbus_message_iter_open_container(ARRAY, 'y') failed"); + else { + dbus_message_iter_append_fixed_array(&dbus_iter3, DBUS_TYPE_BYTE, &p_nameserver, len); + } + if( !dbus_message_iter_close_container(&dbus_iter2, &dbus_iter3)) + fprintf(stderr, "%s\n", "dbus_message_iter_close_container(iter3) failed"); + if (!dbus_message_iter_close_container(&dbus_iter1, &dbus_iter2)) + fprintf(stderr, "%s\n", "dbus_message_iter_close_container(iter2) failed"); + } + + inet_ntop(nameservers[i][ssize_in6], (void *)nameservers[i], buffer, sizeof(buffer)); + printf("Dbus SetLinkDNS() Protocol: %d Address: %s\n", nameservers[i][ssize_in6], buffer); + } + } + if (!dbus_message_iter_close_container(&dbus_iter0, &dbus_iter1)) + fprintf(stderr, "%s\n", "dbus_message_iter_close_container(iter3) failed"); + if (!dbus_message_append_args(set_link_dns, DBUS_TYPE_INVALID)) + fprintf(stderr, "%s\n", "dbus_message_append_args(INVALID) failed"); + + if (!dbus_connection_send(dbus_connection, set_link_dns, &dbus_serial)) { + fprintf(stderr, "%s\n", "Failed to send DBus message"); + } + dbus_connection_flush(dbus_connection); + dbus_connection_unref(dbus_connection); + dbus_message_unref(set_link_dns); + } + } + } + } + else + perror("Cannot find interface"); + } + else + fprintf(stderr, "usage: %s INTERFACE_NAME\n", argv[0]); + + return ifindex; +} -- 2.17.1
next reply other threads:[~2018-09-04 10:17 UTC|newest] Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top 2018-09-04 10:17 Tj [this message] 2018-09-04 13:06 ` Michael Richardson 2018-09-04 13:22 ` Marco d'Itri
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=e5fa9fe1-073c-e9c5-c774-21bc5487fe7e@iam.tj \ --to=linux@iam.tj \ --cc=linux-ppp@vger.kernel.org \ --subject='Re: RFC: support setting DNS for systemd-resolved via DBus' \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: link
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).