linux-ppp.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* RFC: support setting DNS for systemd-resolved via DBus
@ 2018-09-04 10:17 Tj
  2018-09-04 13:06 ` Michael Richardson
  2018-09-04 13:22 ` Marco d'Itri
  0 siblings, 2 replies; 3+ messages in thread
From: Tj @ 2018-09-04 10:17 UTC (permalink / raw)
  To: linux-ppp

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

^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: RFC: support setting DNS for systemd-resolved via DBus
  2018-09-04 10:17 RFC: support setting DNS for systemd-resolved via DBus Tj
@ 2018-09-04 13:06 ` Michael Richardson
  2018-09-04 13:22 ` Marco d'Itri
  1 sibling, 0 replies; 3+ messages in thread
From: Michael Richardson @ 2018-09-04 13:06 UTC (permalink / raw)
  To: linux-ppp

[-- Attachment #1: Type: text/plain, Size: 1104 bytes --]


Tj <linux@iam.tj> wrote:
    > 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).

...

    > 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 seems like if small is your goal that you ought to have the ppp client do
this directly.

    > It build-depends on libdbus but not systemd.

Cool.

    > 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 would add it to ppp, and I'd put it into src/dbusdns.c or some such named
code.

If standalone, then give it a new directory.

--
]               Never tell me the odds!                 | ipv6 mesh networks [
]   Michael Richardson, Sandelman Software Works        | network architect  [
]     mcr@sandelman.ca  http://www.sandelman.ca/        |   ruby on rails    [


[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 487 bytes --]

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: RFC: support setting DNS for systemd-resolved via DBus
  2018-09-04 10:17 RFC: support setting DNS for systemd-resolved via DBus Tj
  2018-09-04 13:06 ` Michael Richardson
@ 2018-09-04 13:22 ` Marco d'Itri
  1 sibling, 0 replies; 3+ messages in thread
From: Marco d'Itri @ 2018-09-04 13:22 UTC (permalink / raw)
  To: linux-ppp

[-- Attachment #1: Type: text/plain, Size: 336 bytes --]

On Sep 04, Tj <linux@iam.tj> wrote:

> 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.
Since this is not performance critical maybe you could just call busctl 
from a shell script?

-- 
ciao,
Marco

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 659 bytes --]

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2018-09-04 13:22 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-09-04 10:17 RFC: support setting DNS for systemd-resolved via DBus Tj
2018-09-04 13:06 ` Michael Richardson
2018-09-04 13:22 ` Marco d'Itri

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).