summary refs log tree commit diff
path: root/src/core/dhcp/nm-dhcp-dhcpcanon.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/dhcp/nm-dhcp-dhcpcanon.c')
-rw-r--r--src/core/dhcp/nm-dhcp-dhcpcanon.c243
1 files changed, 243 insertions, 0 deletions
diff --git a/src/core/dhcp/nm-dhcp-dhcpcanon.c b/src/core/dhcp/nm-dhcp-dhcpcanon.c
new file mode 100644
index 00000000..3504a048
--- /dev/null
+++ b/src/core/dhcp/nm-dhcp-dhcpcanon.c
@@ -0,0 +1,243 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2017 juga <juga at riseup dot net>
+ */
+
+#include "src/core/nm-default-daemon.h"
+
+#if WITH_DHCPCANON
+
+    #include <stdlib.h>
+    #include <unistd.h>
+
+    #include "nm-utils.h"
+    #include "nm-dhcp-manager.h"
+    #include "NetworkManagerUtils.h"
+    #include "nm-dhcp-listener.h"
+    #include "nm-dhcp-client-logging.h"
+
+    #define NM_TYPE_DHCP_DHCPCANON (nm_dhcp_dhcpcanon_get_type())
+    #define NM_DHCP_DHCPCANON(obj) \
+        (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DHCP_DHCPCANON, NMDhcpDhcpcanon))
+    #define NM_DHCP_DHCPCANON_CLASS(klass) \
+        (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DHCP_DHCPCANON, NMDhcpDhcpcanonClass))
+    #define NM_IS_DHCP_DHCPCANON(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DHCP_DHCPCANON))
+    #define NM_IS_DHCP_DHCPCANON_CLASS(klass) \
+        (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_DHCP_DHCPCANON))
+    #define NM_DHCP_DHCPCANON_GET_CLASS(obj) \
+        (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_DHCP_DHCPCANON, NMDhcpDhcpcanonClass))
+
+typedef struct _NMDhcpDhcpcanon      NMDhcpDhcpcanon;
+typedef struct _NMDhcpDhcpcanonClass NMDhcpDhcpcanonClass;
+
+static GType nm_dhcp_dhcpcanon_get_type(void);
+
+/*****************************************************************************/
+
+typedef struct {
+    char *          conf_file;
+    const char *    def_leasefile;
+    char *          lease_file;
+    char *          pid_file;
+    NMDhcpListener *dhcp_listener;
+} NMDhcpDhcpcanonPrivate;
+
+struct _NMDhcpDhcpcanon {
+    NMDhcpClient           parent;
+    NMDhcpDhcpcanonPrivate _priv;
+};
+
+struct _NMDhcpDhcpcanonClass {
+    NMDhcpClientClass parent;
+};
+
+G_DEFINE_TYPE(NMDhcpDhcpcanon, nm_dhcp_dhcpcanon, NM_TYPE_DHCP_CLIENT)
+
+    #define NM_DHCP_DHCPCANON_GET_PRIVATE(self) \
+        _NM_GET_PRIVATE(self, NMDhcpDhcpcanon, NM_IS_DHCP_DHCPCANON)
+
+/*****************************************************************************/
+
+static const char *
+nm_dhcp_dhcpcanon_get_path(void)
+{
+    return nm_utils_find_helper("dhcpcanon", DHCPCANON_PATH, NULL);
+}
+
+static gboolean
+dhcpcanon_start(NMDhcpClient *client,
+                const char *  mode_opt,
+                GBytes *      duid,
+                gboolean      release,
+                pid_t *       out_pid,
+                guint         needed_prefixes,
+                GError **     error)
+{
+    NMDhcpDhcpcanon *       self      = NM_DHCP_DHCPCANON(client);
+    NMDhcpDhcpcanonPrivate *priv      = NM_DHCP_DHCPCANON_GET_PRIVATE(self);
+    gs_unref_ptrarray GPtrArray *argv = NULL;
+    pid_t                        pid;
+    gs_free_error GError *local = NULL;
+    const char *          iface;
+    const char *          system_bus_address;
+    const char *          dhcpcanon_path;
+    gs_free char *        binary_name            = NULL;
+    gs_free char *        pid_file               = NULL;
+    gs_free char *        system_bus_address_env = NULL;
+    int                   addr_family;
+
+    g_return_val_if_fail(!priv->pid_file, FALSE);
+
+    iface = nm_dhcp_client_get_iface(client);
+
+    addr_family = nm_dhcp_client_get_addr_family(client);
+
+    dhcpcanon_path = nm_dhcp_dhcpcanon_get_path();
+    if (!dhcpcanon_path) {
+        nm_utils_error_set_literal(error, NM_UTILS_ERROR_UNKNOWN, "dhcpcanon binary not found");
+        return FALSE;
+    }
+
+    _LOGD("dhcpcanon_path: %s", dhcpcanon_path);
+
+    pid_file = g_strdup_printf(RUNSTATEDIR "/dhcpcanon%c-%s.pid",
+                               nm_utils_addr_family_to_char(addr_family),
+                               iface);
+    _LOGD("pid_file: %s", pid_file);
+
+    /* Kill any existing dhcpcanon from the pidfile */
+    binary_name = g_path_get_basename(dhcpcanon_path);
+    nm_dhcp_client_stop_existing(pid_file, binary_name);
+
+    argv = g_ptr_array_new();
+    g_ptr_array_add(argv, (gpointer) dhcpcanon_path);
+
+    g_ptr_array_add(argv, (gpointer) "-sf"); /* Set script file */
+    g_ptr_array_add(argv, (gpointer) nm_dhcp_helper_path);
+
+    g_ptr_array_add(argv, (gpointer) "-pf"); /* Set pid file */
+    g_ptr_array_add(argv, (gpointer) pid_file);
+
+    if (priv->conf_file) {
+        g_ptr_array_add(argv, (gpointer) "-cf"); /* Set interface config file */
+        g_ptr_array_add(argv, (gpointer) priv->conf_file);
+    }
+
+    /* Usually the system bus address is well-known; but if it's supposed
+     * to be something else, we need to push it to dhcpcanon, since dhcpcanon
+     * sanitizes the environment it gives the action scripts.
+     */
+    system_bus_address = getenv("DBUS_SYSTEM_BUS_ADDRESS");
+    if (system_bus_address) {
+        system_bus_address_env = g_strdup_printf("DBUS_SYSTEM_BUS_ADDRESS=%s", system_bus_address);
+        g_ptr_array_add(argv, (gpointer) "-e");
+        g_ptr_array_add(argv, (gpointer) system_bus_address_env);
+    }
+
+    g_ptr_array_add(argv, (gpointer) iface);
+    g_ptr_array_add(argv, NULL);
+
+    if (!g_spawn_async(NULL,
+                       (char **) argv->pdata,
+                       NULL,
+                       G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_STDOUT_TO_DEV_NULL
+                           | G_SPAWN_STDERR_TO_DEV_NULL,
+                       nm_utils_setpgid,
+                       NULL,
+                       &pid,
+                       &local)) {
+        nm_utils_error_set(error,
+                           NM_UTILS_ERROR_UNKNOWN,
+                           "dhcpcanon failed to start: %s",
+                           local->message);
+        return FALSE;
+    }
+
+    nm_assert(pid > 0);
+    _LOGI("dhcpcanon started with pid %d", pid);
+    nm_dhcp_client_watch_child(client, pid);
+    priv->pid_file = g_steal_pointer(&pid_file);
+    return TRUE;
+}
+
+static gboolean
+ip4_start(NMDhcpClient *client,
+          const char *  dhcp_anycast_addr,
+          const char *  last_ip4_address,
+          GError **     error)
+{
+    return dhcpcanon_start(client, NULL, NULL, FALSE, NULL, 0, error);
+}
+
+static void
+stop(NMDhcpClient *client, gboolean release)
+{
+    NMDhcpDhcpcanon *       self = NM_DHCP_DHCPCANON(client);
+    NMDhcpDhcpcanonPrivate *priv = NM_DHCP_DHCPCANON_GET_PRIVATE(self);
+    int                     errsv;
+
+    NM_DHCP_CLIENT_CLASS(nm_dhcp_dhcpcanon_parent_class)->stop(client, release);
+
+    if (priv->pid_file) {
+        if (remove(priv->pid_file) == -1) {
+            errsv = errno;
+            _LOGD("could not remove dhcp pid file \"%s\": %d (%s)",
+                  priv->pid_file,
+                  errsv,
+                  nm_strerror_native(errsv));
+        }
+        g_free(priv->pid_file);
+        priv->pid_file = NULL;
+    }
+}
+
+/*****************************************************************************/
+
+static void
+nm_dhcp_dhcpcanon_init(NMDhcpDhcpcanon *self)
+{
+    NMDhcpDhcpcanonPrivate *priv = NM_DHCP_DHCPCANON_GET_PRIVATE(self);
+
+    priv->dhcp_listener = g_object_ref(nm_dhcp_listener_get());
+    g_signal_connect(priv->dhcp_listener,
+                     NM_DHCP_LISTENER_EVENT,
+                     G_CALLBACK(nm_dhcp_client_handle_event),
+                     self);
+}
+
+static void
+dispose(GObject *object)
+{
+    NMDhcpDhcpcanonPrivate *priv = NM_DHCP_DHCPCANON_GET_PRIVATE(object);
+
+    if (priv->dhcp_listener) {
+        g_signal_handlers_disconnect_by_func(priv->dhcp_listener,
+                                             G_CALLBACK(nm_dhcp_client_handle_event),
+                                             NM_DHCP_DHCPCANON(object));
+        g_clear_object(&priv->dhcp_listener);
+    }
+
+    nm_clear_g_free(&priv->pid_file);
+
+    G_OBJECT_CLASS(nm_dhcp_dhcpcanon_parent_class)->dispose(object);
+}
+
+static void
+nm_dhcp_dhcpcanon_class_init(NMDhcpDhcpcanonClass *dhcpcanon_class)
+{
+    NMDhcpClientClass *client_class = NM_DHCP_CLIENT_CLASS(dhcpcanon_class);
+    GObjectClass *     object_class = G_OBJECT_CLASS(dhcpcanon_class);
+
+    object_class->dispose = dispose;
+
+    client_class->ip4_start = ip4_start;
+    client_class->stop      = stop;
+}
+
+const NMDhcpClientFactory _nm_dhcp_client_factory_dhcpcanon = {
+    .name     = "dhcpcanon",
+    .get_type = nm_dhcp_dhcpcanon_get_type,
+    .get_path = nm_dhcp_dhcpcanon_get_path,
+};
+
+#endif /* WITH_DHCPCANON */