diff options
| author | Michael Biebl <biebl@debian.org> | 2021-02-11 18:11:46 +0100 |
|---|---|---|
| committer | Michael Biebl <biebl@debian.org> | 2021-02-11 18:11:46 +0100 |
| commit | 80ec1decc49c72efec2a8b87c06245c92c0ab807 (patch) | |
| tree | e3b229aa94e8dcf0590f2317664176e7b8f7607b /src/dhcp | |
| parent | 65f86e8f56267192d42f2b629fc6b0c99fb9cd0c (diff) | |
New upstream version 1.29.90 upstream/1.29.90
Diffstat (limited to 'src/dhcp')
26 files changed, 0 insertions, 11196 deletions
diff --git a/src/dhcp/meson.build b/src/dhcp/meson.build deleted file mode 100644 index 67f055d9..00000000 --- a/src/dhcp/meson.build +++ /dev/null @@ -1,23 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1+ - -name = 'nm-dhcp-helper' - -c_flags = [ - '-DG_LOG_DOMAIN="@0@"'.format(name), - '-DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_GLIB', -] - -executable( - name, - name + '.c', - dependencies: glib_nm_default_dep, - c_args: c_flags, - link_args: ldflags_linker_script_binary, - link_depends: linker_script_binary, - install: true, - install_dir: nm_libexecdir, -) - -if enable_tests - subdir('tests') -endif diff --git a/src/dhcp/nm-dhcp-client-logging.h b/src/dhcp/nm-dhcp-client-logging.h deleted file mode 100644 index ecbf5210..00000000 --- a/src/dhcp/nm-dhcp-client-logging.h +++ /dev/null @@ -1,87 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2016 Red Hat, Inc. - */ - -#ifndef __NETWORKMANAGER_DHCP_CLIENT_LOGGING_H__ -#define __NETWORKMANAGER_DHCP_CLIENT_LOGGING_H__ - -#include "nm-dhcp-client.h" - -static inline NMLogDomain -_nm_dhcp_client_get_domain(NMDhcpClient *self) -{ - if (self) { - switch (nm_dhcp_client_get_addr_family(self)) { - case AF_INET: - return LOGD_DHCP4; - case AF_INET6: - return LOGD_DHCP6; - default: - nm_assert_not_reached(); - break; - } - } - return LOGD_DHCP; -} - -#define _NMLOG_PREFIX_NAME "dhcp" -#define _NMLOG_DOMAIN LOGD_DHCP -#define _NMLOG(level, ...) \ - G_STMT_START \ - { \ - const NMLogLevel _level = (level); \ - \ - /* we check first for LOGD_DHCP instead of the correct domain. - * In the worst case, we guess wrong and enter the block. - * - * Same for the _NMLOG_ENABLED() macro. Probably it would be more - * expensive to determine the correct value then what we could - * safe. */ \ - if (nm_logging_enabled(_level, _NMLOG_DOMAIN)) { \ - NMDhcpClient * _self = (NMDhcpClient *) (self); \ - const char * __ifname = _self ? nm_dhcp_client_get_iface(_self) : NULL; \ - const NMLogDomain _domain = _nm_dhcp_client_get_domain(_self); \ - \ - nm_log(_level, \ - _domain, \ - __ifname, \ - NULL, \ - "%s%s%s%s%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ - _NMLOG_PREFIX_NAME, \ - (_domain == LOGD_DHCP4 ? "4" : (_domain == LOGD_DHCP6 ? "6" : "")), \ - NM_PRINT_FMT_QUOTED(__ifname, " (", __ifname, ")", "") \ - _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ - } \ - } \ - G_STMT_END - -#define _NMLOG2(level, domain, ifname, ...) \ - G_STMT_START \ - { \ - const NMLogLevel _level = (level); \ - const NMLogDomain _domain = (domain); \ - \ - /* we check first for LOGD_DHCP instead of the correct domain. - * In the worst case, we guess wrong and enter the block. - * - * Same for the _NMLOG_ENABLED() macro. Probably it would be more - * expensive to determine the correct value then what we could - * safe. */ \ - if (nm_logging_enabled(_level, _domain)) { \ - const char *__ifname = (ifname); \ - \ - nm_log(_level, \ - _domain, \ - __ifname, \ - NULL, \ - "%s%s%s%s%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ - _NMLOG_PREFIX_NAME, \ - (_domain == LOGD_DHCP4 ? "4" : (_domain == LOGD_DHCP6 ? "6" : "")), \ - NM_PRINT_FMT_QUOTED(__ifname, " (", __ifname, ")", "") \ - _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ - } \ - } \ - G_STMT_END - -#endif /* __NETWORKMANAGER_DHCP_CLIENT_LOGGING_H__ */ diff --git a/src/dhcp/nm-dhcp-client.c b/src/dhcp/nm-dhcp-client.c deleted file mode 100644 index 46ab4895..00000000 --- a/src/dhcp/nm-dhcp-client.c +++ /dev/null @@ -1,1337 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2005 - 2010 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include "nm-dhcp-client.h" - -#include <sys/types.h> -#include <sys/wait.h> -#include <unistd.h> -#include <stdio.h> -#include <stdlib.h> -#include <linux/rtnetlink.h> - -#include "nm-glib-aux/nm-dedup-multi.h" -#include "nm-glib-aux/nm-random-utils.h" - -#include "NetworkManagerUtils.h" -#include "nm-utils.h" -#include "nm-dhcp-utils.h" -#include "platform/nm-platform.h" - -#include "nm-dhcp-client-logging.h" - -/*****************************************************************************/ - -enum { SIGNAL_STATE_CHANGED, SIGNAL_PREFIX_DELEGATED, LAST_SIGNAL }; - -static guint signals[LAST_SIGNAL] = {0}; - -NM_GOBJECT_PROPERTIES_DEFINE(NMDhcpClient, - PROP_ADDR_FAMILY, - PROP_FLAGS, - PROP_HWADDR, - PROP_BROADCAST_HWADDR, - PROP_IFACE, - PROP_IFINDEX, - PROP_MULTI_IDX, - PROP_ROUTE_METRIC, - PROP_ROUTE_TABLE, - PROP_TIMEOUT, - PROP_UUID, - PROP_IAID, - PROP_IAID_EXPLICIT, - PROP_HOSTNAME, - PROP_HOSTNAME_FLAGS, - PROP_MUD_URL, - PROP_VENDOR_CLASS_IDENTIFIER, - PROP_REJECT_SERVERS, ); - -typedef struct _NMDhcpClientPrivate { - NMDedupMultiIndex * multi_idx; - char * iface; - GBytes * hwaddr; - GBytes * bcast_hwaddr; - char * uuid; - GBytes * client_id; - char * hostname; - const char ** reject_servers; - char * mud_url; - GBytes * vendor_class_identifier; - pid_t pid; - guint timeout_id; - guint watch_id; - int addr_family; - int ifindex; - guint32 route_table; - guint32 route_metric; - guint32 timeout; - guint32 iaid; - NMDhcpState state; - NMDhcpHostnameFlags hostname_flags; - bool info_only : 1; - bool use_fqdn : 1; - bool iaid_explicit : 1; -} NMDhcpClientPrivate; - -G_DEFINE_ABSTRACT_TYPE(NMDhcpClient, nm_dhcp_client, G_TYPE_OBJECT) - -#define NM_DHCP_CLIENT_GET_PRIVATE(self) _NM_GET_PRIVATE_PTR(self, NMDhcpClient, NM_IS_DHCP_CLIENT) - -/*****************************************************************************/ - -pid_t -nm_dhcp_client_get_pid(NMDhcpClient *self) -{ - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), -1); - - return NM_DHCP_CLIENT_GET_PRIVATE(self)->pid; -} - -NMDedupMultiIndex * -nm_dhcp_client_get_multi_idx(NMDhcpClient *self) -{ - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), NULL); - - return NM_DHCP_CLIENT_GET_PRIVATE(self)->multi_idx; -} - -const char * -nm_dhcp_client_get_iface(NMDhcpClient *self) -{ - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), NULL); - - return NM_DHCP_CLIENT_GET_PRIVATE(self)->iface; -} - -int -nm_dhcp_client_get_ifindex(NMDhcpClient *self) -{ - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), -1); - - return NM_DHCP_CLIENT_GET_PRIVATE(self)->ifindex; -} - -int -nm_dhcp_client_get_addr_family(NMDhcpClient *self) -{ - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), AF_UNSPEC); - - return NM_DHCP_CLIENT_GET_PRIVATE(self)->addr_family; -} - -const char * -nm_dhcp_client_get_uuid(NMDhcpClient *self) -{ - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), NULL); - - return NM_DHCP_CLIENT_GET_PRIVATE(self)->uuid; -} - -GBytes * -nm_dhcp_client_get_hw_addr(NMDhcpClient *self) -{ - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), NULL); - - return NM_DHCP_CLIENT_GET_PRIVATE(self)->hwaddr; -} - -GBytes * -nm_dhcp_client_get_broadcast_hw_addr(NMDhcpClient *self) -{ - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), NULL); - - return NM_DHCP_CLIENT_GET_PRIVATE(self)->bcast_hwaddr; -} - -guint32 -nm_dhcp_client_get_route_table(NMDhcpClient *self) -{ - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), RT_TABLE_MAIN); - - return NM_DHCP_CLIENT_GET_PRIVATE(self)->route_table; -} - -void -nm_dhcp_client_set_route_table(NMDhcpClient *self, guint32 route_table) -{ - NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); - - if (route_table != priv->route_table) { - priv->route_table = route_table; - _notify(self, PROP_ROUTE_TABLE); - } -} - -guint32 -nm_dhcp_client_get_route_metric(NMDhcpClient *self) -{ - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), G_MAXUINT32); - - return NM_DHCP_CLIENT_GET_PRIVATE(self)->route_metric; -} - -void -nm_dhcp_client_set_route_metric(NMDhcpClient *self, guint32 route_metric) -{ - NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); - - if (route_metric != priv->route_metric) { - priv->route_metric = route_metric; - _notify(self, PROP_ROUTE_METRIC); - } -} - -guint32 -nm_dhcp_client_get_timeout(NMDhcpClient *self) -{ - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), 0); - - return NM_DHCP_CLIENT_GET_PRIVATE(self)->timeout; -} - -guint32 -nm_dhcp_client_get_iaid(NMDhcpClient *self) -{ - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), 0); - - return NM_DHCP_CLIENT_GET_PRIVATE(self)->iaid; -} - -gboolean -nm_dhcp_client_get_iaid_explicit(NMDhcpClient *self) -{ - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), FALSE); - - return NM_DHCP_CLIENT_GET_PRIVATE(self)->iaid_explicit; -} - -GBytes * -nm_dhcp_client_get_client_id(NMDhcpClient *self) -{ - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), NULL); - - return NM_DHCP_CLIENT_GET_PRIVATE(self)->client_id; -} - -static void -_set_client_id(NMDhcpClient *self, GBytes *client_id, gboolean take) -{ - NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); - - nm_assert(!client_id || g_bytes_get_size(client_id) >= 2); - - if (priv->client_id == client_id - || (priv->client_id && client_id && g_bytes_equal(priv->client_id, client_id))) { - if (take && client_id) - g_bytes_unref(client_id); - return; - } - - if (priv->client_id) - g_bytes_unref(priv->client_id); - priv->client_id = client_id; - if (!take && client_id) - g_bytes_ref(client_id); - - { - gs_free char *s = NULL; - - _LOGT("%s: set %s", - nm_dhcp_client_get_addr_family(self) == AF_INET6 ? "duid" : "client-id", - priv->client_id ? (s = nm_dhcp_utils_duid_to_string(priv->client_id)) : "default"); - } -} - -void -nm_dhcp_client_set_client_id(NMDhcpClient *self, GBytes *client_id) -{ - g_return_if_fail(NM_IS_DHCP_CLIENT(self)); - g_return_if_fail(!client_id || g_bytes_get_size(client_id) >= 2); - - _set_client_id(self, client_id, FALSE); -} - -void -nm_dhcp_client_set_client_id_bin(NMDhcpClient *self, - guint8 type, - const guint8 *client_id, - gsize len) -{ - guint8 *buf; - GBytes *b; - - g_return_if_fail(NM_IS_DHCP_CLIENT(self)); - g_return_if_fail(client_id); - g_return_if_fail(len > 0); - - buf = g_malloc(len + 1); - buf[0] = type; - memcpy(buf + 1, client_id, len); - b = g_bytes_new_take(buf, len + 1); - _set_client_id(self, b, TRUE); -} - -const char * -nm_dhcp_client_get_hostname(NMDhcpClient *self) -{ - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), NULL); - - return NM_DHCP_CLIENT_GET_PRIVATE(self)->hostname; -} - -NMDhcpHostnameFlags -nm_dhcp_client_get_hostname_flags(NMDhcpClient *self) -{ - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), NM_DHCP_HOSTNAME_FLAG_NONE); - - return NM_DHCP_CLIENT_GET_PRIVATE(self)->hostname_flags; -} - -gboolean -nm_dhcp_client_get_info_only(NMDhcpClient *self) -{ - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), FALSE); - - return NM_DHCP_CLIENT_GET_PRIVATE(self)->info_only; -} - -gboolean -nm_dhcp_client_get_use_fqdn(NMDhcpClient *self) -{ - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), FALSE); - - return NM_DHCP_CLIENT_GET_PRIVATE(self)->use_fqdn; -} - -const char * -nm_dhcp_client_get_mud_url(NMDhcpClient *self) -{ - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), NULL); - - return NM_DHCP_CLIENT_GET_PRIVATE(self)->mud_url; -} - -GBytes * -nm_dhcp_client_get_vendor_class_identifier(NMDhcpClient *self) -{ - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), NULL); - - return NM_DHCP_CLIENT_GET_PRIVATE(self)->vendor_class_identifier; -} - -const char *const * -nm_dhcp_client_get_reject_servers(NMDhcpClient *self) -{ - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), NULL); - - return (const char *const *) NM_DHCP_CLIENT_GET_PRIVATE(self)->reject_servers; -} - -/*****************************************************************************/ - -static const char *state_table[NM_DHCP_STATE_MAX + 1] = { - [NM_DHCP_STATE_UNKNOWN] = "unknown", - [NM_DHCP_STATE_BOUND] = "bound", - [NM_DHCP_STATE_EXTENDED] = "extended", - [NM_DHCP_STATE_TIMEOUT] = "timeout", - [NM_DHCP_STATE_EXPIRE] = "expire", - [NM_DHCP_STATE_DONE] = "done", - [NM_DHCP_STATE_FAIL] = "fail", - [NM_DHCP_STATE_TERMINATED] = "terminated", -}; - -static const char * -state_to_string(NMDhcpState state) -{ - if ((gsize) state < G_N_ELEMENTS(state_table)) - return state_table[state]; - return NULL; -} - -static NMDhcpState -reason_to_state(NMDhcpClient *self, const char *iface, const char *reason) -{ - if (g_ascii_strcasecmp(reason, "bound") == 0 || g_ascii_strcasecmp(reason, "bound6") == 0) - return NM_DHCP_STATE_BOUND; - else if (g_ascii_strcasecmp(reason, "renew") == 0 || g_ascii_strcasecmp(reason, "renew6") == 0 - || g_ascii_strcasecmp(reason, "reboot") == 0 - || g_ascii_strcasecmp(reason, "rebind") == 0 - || g_ascii_strcasecmp(reason, "rebind6") == 0) - return NM_DHCP_STATE_EXTENDED; - else if (g_ascii_strcasecmp(reason, "timeout") == 0) - return NM_DHCP_STATE_TIMEOUT; - else if (g_ascii_strcasecmp(reason, "nak") == 0 || g_ascii_strcasecmp(reason, "expire") == 0 - || g_ascii_strcasecmp(reason, "expire6") == 0) - return NM_DHCP_STATE_EXPIRE; - else if (g_ascii_strcasecmp(reason, "end") == 0) - return NM_DHCP_STATE_DONE; - else if (g_ascii_strcasecmp(reason, "fail") == 0 || g_ascii_strcasecmp(reason, "abend") == 0) - return NM_DHCP_STATE_FAIL; - - _LOGD("unmapped DHCP state '%s'", reason); - return NM_DHCP_STATE_UNKNOWN; -} - -/*****************************************************************************/ - -static void -timeout_cleanup(NMDhcpClient *self) -{ - NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); - - nm_clear_g_source(&priv->timeout_id); -} - -static void -watch_cleanup(NMDhcpClient *self) -{ - NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); - - nm_clear_g_source(&priv->watch_id); -} - -void -nm_dhcp_client_stop_pid(pid_t pid, const char *iface) -{ - char *name = iface ? g_strdup_printf("dhcp-client-%s", iface) : NULL; - - g_return_if_fail(pid > 1); - - nm_utils_kill_child_sync(pid, - SIGTERM, - LOGD_DHCP, - name ?: "dhcp-client", - NULL, - 1000 / 2, - 1000 / 20); - g_free(name); -} - -static void -stop(NMDhcpClient *self, gboolean release) -{ - NMDhcpClientPrivate *priv; - - g_return_if_fail(NM_IS_DHCP_CLIENT(self)); - - priv = NM_DHCP_CLIENT_GET_PRIVATE(self); - - if (priv->pid > 0) { - /* Clean up the watch handler since we're explicitly killing the daemon */ - watch_cleanup(self); - nm_dhcp_client_stop_pid(priv->pid, priv->iface); - } - priv->pid = -1; -} - -void -nm_dhcp_client_set_state(NMDhcpClient *self, - NMDhcpState new_state, - NMIPConfig * ip_config, - GHashTable * options) -{ - NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); - gs_free char * event_id = NULL; - - if (NM_IN_SET(new_state, NM_DHCP_STATE_BOUND, NM_DHCP_STATE_EXTENDED)) { - g_return_if_fail(NM_IS_IP_CONFIG_ADDR_FAMILY(ip_config, priv->addr_family)); - g_return_if_fail(options); - } else { - g_return_if_fail(!ip_config); - g_return_if_fail(!options); - } - - if (new_state >= NM_DHCP_STATE_BOUND) - timeout_cleanup(self); - if (new_state >= NM_DHCP_STATE_TIMEOUT) - watch_cleanup(self); - - /* The client may send same-state transitions for RENEW/REBIND events and - * the lease may have changed, so handle same-state transitions for the - * EXTENDED and BOUND states. Ignore same-state transitions for other - * events since the lease won't have changed and the state was already handled. - */ - if ((priv->state == new_state) - && !NM_IN_SET(new_state, NM_DHCP_STATE_BOUND, NM_DHCP_STATE_EXTENDED)) - return; - - if (_LOGI_ENABLED()) { - gs_free const char **keys = NULL; - guint i, nkeys; - - keys = nm_utils_strdict_get_keys(options, TRUE, &nkeys); - for (i = 0; i < nkeys; i++) { - _LOGI("option %-20s => '%s'", keys[i], (char *) g_hash_table_lookup(options, keys[i])); - } - } - - if (priv->addr_family == AF_INET6) - event_id = nm_dhcp_utils_get_dhcp6_event_id(options); - - _LOGI("state changed %s -> %s%s%s%s", - state_to_string(priv->state), - state_to_string(new_state), - NM_PRINT_FMT_QUOTED(event_id, ", event ID=\"", event_id, "\"", "")); - - priv->state = new_state; - g_signal_emit(G_OBJECT(self), signals[SIGNAL_STATE_CHANGED], 0, new_state, ip_config, options); -} - -static gboolean -transaction_timeout(gpointer user_data) -{ - NMDhcpClient * self = NM_DHCP_CLIENT(user_data); - NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); - - priv->timeout_id = 0; - _LOGW("request timed out"); - nm_dhcp_client_set_state(self, NM_DHCP_STATE_TIMEOUT, NULL, NULL); - return G_SOURCE_REMOVE; -} - -static void -daemon_watch_cb(GPid pid, int status, gpointer user_data) -{ - NMDhcpClient * self = NM_DHCP_CLIENT(user_data); - NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); - - g_return_if_fail(priv->watch_id); - priv->watch_id = 0; - - if (WIFEXITED(status)) - _LOGI("client pid %d exited with status %d", pid, WEXITSTATUS(status)); - else if (WIFSIGNALED(status)) - _LOGI("client pid %d killed by signal %d", pid, WTERMSIG(status)); - else if (WIFSTOPPED(status)) - _LOGI("client pid %d stopped by signal %d", pid, WSTOPSIG(status)); - else if (WIFCONTINUED(status)) - _LOGI("client pid %d resumed (by SIGCONT)", pid); - else - _LOGW("client died abnormally"); - - priv->pid = -1; - - nm_dhcp_client_set_state(self, NM_DHCP_STATE_TERMINATED, NULL, NULL); -} - -void -nm_dhcp_client_start_timeout(NMDhcpClient *self) -{ - NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); - - g_return_if_fail(priv->timeout_id == 0); - - /* Set up a timeout on the transaction to kill it after the timeout */ - - if (priv->timeout == NM_DHCP_TIMEOUT_INFINITY) - return; - - priv->timeout_id = g_timeout_add_seconds(priv->timeout, transaction_timeout, self); -} - -void -nm_dhcp_client_watch_child(NMDhcpClient *self, pid_t pid) -{ - NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); - - g_return_if_fail(priv->pid == -1); - priv->pid = pid; - - nm_dhcp_client_start_timeout(self); - - g_return_if_fail(priv->watch_id == 0); - priv->watch_id = g_child_watch_add(pid, daemon_watch_cb, self); -} - -gboolean -nm_dhcp_client_start_ip4(NMDhcpClient *self, - GBytes * client_id, - const char * dhcp_anycast_addr, - const char * last_ip4_address, - GError ** error) -{ - NMDhcpClientPrivate *priv; - - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), FALSE); - - priv = NM_DHCP_CLIENT_GET_PRIVATE(self); - g_return_val_if_fail(priv->pid == -1, FALSE); - g_return_val_if_fail(priv->addr_family == AF_INET, FALSE); - g_return_val_if_fail(priv->uuid != NULL, FALSE); - - if (priv->timeout == NM_DHCP_TIMEOUT_INFINITY) - _LOGI("activation: beginning transaction (no timeout)"); - else - _LOGI("activation: beginning transaction (timeout in %u seconds)", (guint) priv->timeout); - - nm_dhcp_client_set_client_id(self, client_id); - - return NM_DHCP_CLIENT_GET_CLASS(self)->ip4_start(self, - dhcp_anycast_addr, - last_ip4_address, - error); -} - -gboolean -nm_dhcp_client_accept(NMDhcpClient *self, GError **error) -{ - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), FALSE); - - if (NM_DHCP_CLIENT_GET_CLASS(self)->accept) { - return NM_DHCP_CLIENT_GET_CLASS(self)->accept(self, error); - } - - return TRUE; -} - -gboolean -nm_dhcp_client_decline(NMDhcpClient *self, const char *error_message, GError **error) -{ - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), FALSE); - - if (NM_DHCP_CLIENT_GET_CLASS(self)->decline) { - return NM_DHCP_CLIENT_GET_CLASS(self)->decline(self, error_message, error); - } - - return TRUE; -} - -static GBytes * -get_duid(NMDhcpClient *self) -{ - return NULL; -} - -gboolean -nm_dhcp_client_start_ip6(NMDhcpClient * self, - GBytes * client_id, - gboolean enforce_duid, - const char * dhcp_anycast_addr, - const struct in6_addr * ll_addr, - NMSettingIP6ConfigPrivacy privacy, - guint needed_prefixes, - GError ** error) -{ - NMDhcpClientPrivate *priv; - gs_unref_bytes GBytes *own_client_id = NULL; - - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), FALSE); - g_return_val_if_fail(client_id, FALSE); - - priv = NM_DHCP_CLIENT_GET_PRIVATE(self); - - g_return_val_if_fail(priv->pid == -1, FALSE); - g_return_val_if_fail(priv->addr_family == AF_INET6, FALSE); - g_return_val_if_fail(priv->uuid != NULL, FALSE); - g_return_val_if_fail(!priv->client_id, FALSE); - - if (!enforce_duid) - own_client_id = NM_DHCP_CLIENT_GET_CLASS(self)->get_duid(self); - - _set_client_id(self, own_client_id ?: client_id, FALSE); - - if (priv->timeout == NM_DHCP_TIMEOUT_INFINITY) - _LOGI("activation: beginning transaction (no timeout)"); - else - _LOGI("activation: beginning transaction (timeout in %u seconds)", (guint) priv->timeout); - - return NM_DHCP_CLIENT_GET_CLASS(self) - ->ip6_start(self, dhcp_anycast_addr, ll_addr, privacy, needed_prefixes, error); -} - -void -nm_dhcp_client_stop_existing(const char *pid_file, const char *binary_name) -{ - guint64 start_time; - pid_t pid, ppid; - const char * exe; - char proc_path[NM_STRLEN("/proc/%lu/cmdline") + 100]; - gs_free char *pid_contents = NULL, *proc_contents = NULL; - - /* Check for an existing instance and stop it */ - if (!g_file_get_contents(pid_file, &pid_contents, NULL, NULL)) - return; - - pid = _nm_utils_ascii_str_to_int64(pid_contents, 10, 1, G_MAXINT64, 0); - if (pid <= 0) - goto out; - - start_time = nm_utils_get_start_time_for_pid(pid, NULL, &ppid); - if (start_time == 0) - goto out; - - nm_sprintf_buf(proc_path, "/proc/%lu/cmdline", (unsigned long) pid); - if (!g_file_get_contents(proc_path, &proc_contents, NULL, NULL)) - goto out; - - exe = strrchr(proc_contents, '/'); - if (exe) - exe++; - else - exe = proc_contents; - if (!nm_streq0(exe, binary_name)) - goto out; - - if (ppid == getpid()) { - /* the process is our own child. */ - nm_utils_kill_child_sync(pid, SIGTERM, LOGD_DHCP, "dhcp-client", NULL, 1000 / 2, 1000 / 20); - } else { - nm_utils_kill_process_sync(pid, - start_time, - SIGTERM, - LOGD_DHCP, - "dhcp-client", - 1000 / 2, - 1000 / 20, - 2000); - } - -out: - if (remove(pid_file) == -1) { - int errsv = errno; - - nm_log_dbg(LOGD_DHCP, - "dhcp: could not remove pid file \"%s\": %s (%d)", - pid_file, - nm_strerror_native(errsv), - errsv); - } -} - -void -nm_dhcp_client_stop(NMDhcpClient *self, gboolean release) -{ - NMDhcpClientPrivate *priv; - pid_t old_pid = 0; - - g_return_if_fail(NM_IS_DHCP_CLIENT(self)); - - priv = NM_DHCP_CLIENT_GET_PRIVATE(self); - - /* Kill the DHCP client */ - old_pid = priv->pid; - NM_DHCP_CLIENT_GET_CLASS(self)->stop(self, release); - if (old_pid > 0) - _LOGI("canceled DHCP transaction, DHCP client pid %d", old_pid); - else - _LOGI("canceled DHCP transaction"); - nm_assert(priv->pid == -1); - - nm_dhcp_client_set_state(self, NM_DHCP_STATE_DONE, NULL, NULL); -} - -/*****************************************************************************/ - -static char * -bytearray_variant_to_string(NMDhcpClient *self, GVariant *value, const char *key) -{ - const guint8 *array; - gsize length; - GString * str; - int i; - unsigned char c; - char * converted = NULL; - - g_return_val_if_fail(value != NULL, NULL); - - array = g_variant_get_fixed_array(value, &length, 1); - - /* Since the DHCP options come through environment variables, they should - * already be UTF-8 safe, but just make sure. - */ - str = g_string_sized_new(length); - for (i = 0; i < length; i++) { - c = array[i]; - - /* Convert NULLs to spaces and non-ASCII characters to ? */ - if (c == '\0') - c = ' '; - else if (c > 127) - c = '?'; - str = g_string_append_c(str, c); - } - str = g_string_append_c(str, '\0'); - - converted = str->str; - if (!g_utf8_validate(converted, -1, NULL)) - _LOGW("option '%s' couldn't be converted to UTF-8", key); - g_string_free(str, FALSE); - return converted; -} - -static int -label_is_unknown_xyz(const char *label) -{ - if (!NM_STR_HAS_PREFIX(label, "unknown_")) - return -EINVAL; - - label += NM_STRLEN("unknown_"); - if (label[0] != '2' || !g_ascii_isdigit(label[1]) || !g_ascii_isdigit(label[2]) - || label[3] != '\0') - return -EINVAL; - - return _nm_utils_ascii_str_to_int64(label, 10, 224, 254, -EINVAL); -} - -#define OLD_TAG "old_" -#define NEW_TAG "new_" - -static void -maybe_add_option(NMDhcpClient *self, GHashTable *hash, const char *key, GVariant *value) -{ - char *str_value = NULL; - - g_return_if_fail(g_variant_is_of_type(value, G_VARIANT_TYPE_BYTESTRING)); - - if (g_str_has_prefix(key, OLD_TAG)) - return; - - /* Filter out stuff that's not actually new DHCP options */ - if (NM_IN_STRSET(key, "interface", "pid", "reason", "dhcp_message_type")) - return; - - if (NM_STR_HAS_PREFIX(key, NEW_TAG)) - key += NM_STRLEN(NEW_TAG); - if (NM_STR_HAS_PREFIX(key, "private_") || !key[0]) - return; - - str_value = bytearray_variant_to_string(self, value, key); - if (str_value) { - int priv_opt_num; - - g_hash_table_insert(hash, g_strdup(key), str_value); - - /* dhclient has no special labels for private dhcp options: it uses "unknown_xyz" - * labels for that. We need to identify those to alias them to our "private_xyz" - * format unused in the internal dchp plugins. - */ - if ((priv_opt_num = label_is_unknown_xyz(key)) > 0) { - gs_free guint8 *check_val = NULL; - char * hex_str = NULL; - gsize len; - - /* dhclient passes values from dhcp private options in its own "string" format: - * if the raw values are printable as ascii strings, it will pass the string - * representation; if the values are not printable as an ascii string, it will - * pass a string displaying the hex values (hex string). Try to enforce passing - * always an hex string, converting string representation if needed. - */ - check_val = nm_utils_hexstr2bin_alloc(str_value, FALSE, TRUE, ":", 0, &len); - hex_str = nm_utils_bin2hexstr_full(check_val ?: (guint8 *) str_value, - check_val ? len : strlen(str_value), - ':', - FALSE, - NULL); - g_hash_table_insert(hash, g_strdup_printf("private_%d", priv_opt_num), hex_str); - } - } -} - -void -nm_dhcp_client_emit_ipv6_prefix_delegated(NMDhcpClient *self, const NMPlatformIP6Address *prefix) -{ - g_signal_emit(G_OBJECT(self), signals[SIGNAL_PREFIX_DELEGATED], 0, prefix); -} - -gboolean -nm_dhcp_client_handle_event(gpointer unused, - const char * iface, - int pid, - GVariant * options, - const char * reason, - NMDhcpClient *self) -{ - NMDhcpClientPrivate *priv; - guint32 old_state; - guint32 new_state; - gs_unref_hashtable GHashTable *str_options = NULL; - gs_unref_object NMIPConfig *ip_config = NULL; - NMPlatformIP6Address prefix = { - 0, - }; - - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), FALSE); - g_return_val_if_fail(iface != NULL, FALSE); - g_return_val_if_fail(pid > 0, FALSE); - g_return_val_if_fail(g_variant_is_of_type(options, G_VARIANT_TYPE_VARDICT), FALSE); - g_return_val_if_fail(reason != NULL, FALSE); - - priv = NM_DHCP_CLIENT_GET_PRIVATE(self); - - if (g_strcmp0(priv->iface, iface) != 0) - return FALSE; - if (priv->pid != pid) - return FALSE; - - old_state = priv->state; - new_state = reason_to_state(self, priv->iface, reason); - _LOGD("DHCP state '%s' -> '%s' (reason: '%s')", - state_to_string(old_state), - state_to_string(new_state), - reason); - - if (NM_IN_SET(new_state, NM_DHCP_STATE_BOUND, NM_DHCP_STATE_EXTENDED)) { - GVariantIter iter; - const char * name; - GVariant * value; - - /* Copy options */ - str_options = g_hash_table_new_full(nm_str_hash, g_str_equal, g_free, g_free); - g_variant_iter_init(&iter, options); - while (g_variant_iter_next(&iter, "{&sv}", &name, &value)) { - maybe_add_option(self, str_options, name, value); - g_variant_unref(value); - } - - /* Create the IP config */ - if (g_hash_table_size(str_options) > 0) { - if (priv->addr_family == AF_INET) { - ip_config = NM_IP_CONFIG_CAST( - nm_dhcp_utils_ip4_config_from_options(nm_dhcp_client_get_multi_idx(self), - priv->ifindex, - priv->iface, - str_options, - priv->route_table, - priv->route_metric)); - } else { - prefix = nm_dhcp_utils_ip6_prefix_from_options(str_options); - ip_config = NM_IP_CONFIG_CAST( - nm_dhcp_utils_ip6_config_from_options(nm_dhcp_client_get_multi_idx(self), - priv->ifindex, - priv->iface, - str_options, - priv->info_only)); - } - } else - g_warn_if_reached(); - } - - if (!IN6_IS_ADDR_UNSPECIFIED(&prefix.address)) { - /* If we got an IPv6 prefix to delegate, we don't change the state - * of the DHCP client instance. Instead, we just signal the prefix - * to the device. */ - nm_dhcp_client_emit_ipv6_prefix_delegated(self, &prefix); - } else { - /* Fail if no valid IP config was received */ - if (NM_IN_SET(new_state, NM_DHCP_STATE_BOUND, NM_DHCP_STATE_EXTENDED) && !ip_config) { - _LOGW("client bound but IP config not received"); - new_state = NM_DHCP_STATE_FAIL; - nm_clear_pointer(&str_options, g_hash_table_unref); - } - - nm_dhcp_client_set_state(self, new_state, ip_config, str_options); - } - - return TRUE; -} - -gboolean -nm_dhcp_client_server_id_is_rejected(NMDhcpClient *self, gconstpointer addr) -{ - NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); - in_addr_t addr4 = *(in_addr_t *) addr; - guint i; - - /* IPv6 not implemented yet */ - nm_assert(priv->addr_family == AF_INET); - - if (!priv->reject_servers || !priv->reject_servers[0]) - return FALSE; - - for (i = 0; priv->reject_servers[i]; i++) { - in_addr_t r_addr; - in_addr_t mask; - int r_prefix; - - if (!nm_utils_parse_inaddr_prefix_bin(AF_INET, - priv->reject_servers[i], - NULL, - &r_addr, - &r_prefix)) - nm_assert_not_reached(); - mask = _nm_utils_ip4_prefix_to_netmask(r_prefix < 0 ? 32 : r_prefix); - if ((addr4 & mask) == (r_addr & mask)) - return TRUE; - } - - return FALSE; -} - -/*****************************************************************************/ - -static void -get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) -{ - NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(object); - - switch (prop_id) { - case PROP_IFACE: - g_value_set_string(value, priv->iface); - break; - case PROP_IFINDEX: - g_value_set_int(value, priv->ifindex); - break; - case PROP_HWADDR: - g_value_set_boxed(value, priv->hwaddr); - break; - case PROP_BROADCAST_HWADDR: - g_value_set_boxed(value, priv->bcast_hwaddr); - break; - case PROP_ADDR_FAMILY: - g_value_set_int(value, priv->addr_family); - break; - case PROP_UUID: - g_value_set_string(value, priv->uuid); - break; - case PROP_IAID: - g_value_set_uint(value, priv->iaid); - break; - case PROP_IAID_EXPLICIT: - g_value_set_boolean(value, priv->iaid_explicit); - break; - case PROP_HOSTNAME: - g_value_set_string(value, priv->hostname); - break; - case PROP_ROUTE_METRIC: - g_value_set_uint(value, priv->route_metric); - break; - case PROP_ROUTE_TABLE: - g_value_set_uint(value, priv->route_table); - break; - case PROP_TIMEOUT: - g_value_set_uint(value, priv->timeout); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -static void -set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) -{ - NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(object); - guint flags; - - switch (prop_id) { - case PROP_FLAGS: - /* construct-only */ - flags = g_value_get_uint(value); - nm_assert( - (flags & ~((guint)(NM_DHCP_CLIENT_FLAGS_INFO_ONLY | NM_DHCP_CLIENT_FLAGS_USE_FQDN))) - == 0); - priv->info_only = NM_FLAGS_HAS(flags, NM_DHCP_CLIENT_FLAGS_INFO_ONLY); - priv->use_fqdn = NM_FLAGS_HAS(flags, NM_DHCP_CLIENT_FLAGS_USE_FQDN); - break; - case PROP_MULTI_IDX: - /* construct-only */ - priv->multi_idx = g_value_get_pointer(value); - if (!priv->multi_idx) - g_return_if_reached(); - nm_dedup_multi_index_ref(priv->multi_idx); - break; - case PROP_IFACE: - /* construct-only */ - priv->iface = g_value_dup_string(value); - g_return_if_fail(priv->iface); - nm_assert(nm_utils_ifname_valid_kernel(priv->iface, NULL)); - break; - case PROP_IFINDEX: - /* construct-only */ - priv->ifindex = g_value_get_int(value); - g_return_if_fail(priv->ifindex > 0); - break; - case PROP_HWADDR: - /* construct-only */ - priv->hwaddr = g_value_dup_boxed(value); - break; - case PROP_BROADCAST_HWADDR: - /* construct-only */ - priv->bcast_hwaddr = g_value_dup_boxed(value); - break; - case PROP_ADDR_FAMILY: - /* construct-only */ - priv->addr_family = g_value_get_int(value); - if (!NM_IN_SET(priv->addr_family, AF_INET, AF_INET6)) - g_return_if_reached(); - break; - case PROP_UUID: - /* construct-only */ - priv->uuid = g_value_dup_string(value); - break; - case PROP_IAID: - /* construct-only */ - priv->iaid = g_value_get_uint(value); - break; - case PROP_IAID_EXPLICIT: - /* construct-only */ - priv->iaid_explicit = g_value_get_boolean(value); - break; - case PROP_HOSTNAME: - /* construct-only */ - priv->hostname = g_value_dup_string(value); - break; - case PROP_HOSTNAME_FLAGS: - /* construct-only */ - priv->hostname_flags = g_value_get_uint(value); - break; - case PROP_MUD_URL: - /* construct-only */ - priv->mud_url = g_value_dup_string(value); - break; - case PROP_ROUTE_TABLE: - priv->route_table = g_value_get_uint(value); - break; - case PROP_ROUTE_METRIC: - priv->route_metric = g_value_get_uint(value); - break; - case PROP_TIMEOUT: - /* construct-only */ - priv->timeout = g_value_get_uint(value); - break; - case PROP_VENDOR_CLASS_IDENTIFIER: - /* construct-only */ - priv->vendor_class_identifier = g_value_dup_boxed(value); - break; - case PROP_REJECT_SERVERS: - /* construct-only */ - priv->reject_servers = nm_utils_strv_dup_packed(g_value_get_boxed(value), -1); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -/*****************************************************************************/ - -static void -nm_dhcp_client_init(NMDhcpClient *self) -{ - NMDhcpClientPrivate *priv; - - priv = G_TYPE_INSTANCE_GET_PRIVATE(self, NM_TYPE_DHCP_CLIENT, NMDhcpClientPrivate); - self->_priv = priv; - - c_list_init(&self->dhcp_client_lst); - - priv->pid = -1; -} - -static void -dispose(GObject *object) -{ - NMDhcpClient * self = NM_DHCP_CLIENT(object); - NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); - - /* Stopping the client is left up to the controlling device - * explicitly since we may want to quit NetworkManager but not terminate - * the DHCP client. - */ - - nm_assert(c_list_is_empty(&self->dhcp_client_lst)); - - watch_cleanup(self); - timeout_cleanup(self); - - nm_clear_g_free(&priv->iface); - nm_clear_g_free(&priv->hostname); - nm_clear_g_free(&priv->uuid); - nm_clear_g_free(&priv->mud_url); - nm_clear_g_free(&priv->reject_servers); - nm_clear_pointer(&priv->client_id, g_bytes_unref); - nm_clear_pointer(&priv->hwaddr, g_bytes_unref); - nm_clear_pointer(&priv->bcast_hwaddr, g_bytes_unref); - nm_clear_pointer(&priv->vendor_class_identifier, g_bytes_unref); - - G_OBJECT_CLASS(nm_dhcp_client_parent_class)->dispose(object); - - priv->multi_idx = nm_dedup_multi_index_unref(priv->multi_idx); -} - -static void -nm_dhcp_client_class_init(NMDhcpClientClass *client_class) -{ - GObjectClass *object_class = G_OBJECT_CLASS(client_class); - - g_type_class_add_private(client_class, sizeof(NMDhcpClientPrivate)); - - object_class->dispose = dispose; - object_class->get_property = get_property; - object_class->set_property = set_property; - - client_class->stop = stop; - client_class->get_duid = get_duid; - - obj_properties[PROP_MULTI_IDX] = - g_param_spec_pointer(NM_DHCP_CLIENT_MULTI_IDX, - "", - "", - G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_IFACE] = - g_param_spec_string(NM_DHCP_CLIENT_INTERFACE, - "", - "", - NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_IFINDEX] = - g_param_spec_int(NM_DHCP_CLIENT_IFINDEX, - "", - "", - -1, - G_MAXINT, - -1, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_HWADDR] = - g_param_spec_boxed(NM_DHCP_CLIENT_HWADDR, - "", - "", - G_TYPE_BYTES, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_BROADCAST_HWADDR] = - g_param_spec_boxed(NM_DHCP_CLIENT_BROADCAST_HWADDR, - "", - "", - G_TYPE_BYTES, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_ADDR_FAMILY] = - g_param_spec_int(NM_DHCP_CLIENT_ADDR_FAMILY, - "", - "", - 0, - G_MAXINT, - AF_UNSPEC, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_UUID] = - g_param_spec_string(NM_DHCP_CLIENT_UUID, - "", - "", - NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_IAID] = - g_param_spec_uint(NM_DHCP_CLIENT_IAID, - "", - "", - 0, - G_MAXUINT32, - 0, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_IAID_EXPLICIT] = - g_param_spec_boolean(NM_DHCP_CLIENT_IAID_EXPLICIT, - "", - "", - FALSE, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_HOSTNAME] = - g_param_spec_string(NM_DHCP_CLIENT_HOSTNAME, - "", - "", - NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_HOSTNAME_FLAGS] = - g_param_spec_uint(NM_DHCP_CLIENT_HOSTNAME_FLAGS, - "", - "", - 0, - G_MAXUINT32, - NM_DHCP_HOSTNAME_FLAG_NONE, - G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_MUD_URL] = - g_param_spec_string(NM_DHCP_CLIENT_MUD_URL, - "", - "", - NULL, - G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_ROUTE_TABLE] = - g_param_spec_uint(NM_DHCP_CLIENT_ROUTE_TABLE, - "", - "", - 0, - G_MAXUINT32, - RT_TABLE_MAIN, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_ROUTE_METRIC] = - g_param_spec_uint(NM_DHCP_CLIENT_ROUTE_METRIC, - "", - "", - 0, - G_MAXUINT32, - 0, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - - G_STATIC_ASSERT_EXPR(G_MAXINT32 == NM_DHCP_TIMEOUT_INFINITY); - obj_properties[PROP_TIMEOUT] = - g_param_spec_uint(NM_DHCP_CLIENT_TIMEOUT, - "", - "", - 1, - G_MAXINT32, - NM_DHCP_TIMEOUT_DEFAULT, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_FLAGS] = - g_param_spec_uint(NM_DHCP_CLIENT_FLAGS, - "", - "", - 0, - G_MAXUINT32, - 0, - G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_VENDOR_CLASS_IDENTIFIER] = - g_param_spec_boxed(NM_DHCP_CLIENT_VENDOR_CLASS_IDENTIFIER, - "", - "", - G_TYPE_BYTES, - G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_REJECT_SERVERS] = - g_param_spec_boxed(NM_DHCP_CLIENT_REJECT_SERVERS, - "", - "", - G_TYPE_STRV, - G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties); - - signals[SIGNAL_STATE_CHANGED] = g_signal_new(NM_DHCP_CLIENT_SIGNAL_STATE_CHANGED, - G_OBJECT_CLASS_TYPE(object_class), - G_SIGNAL_RUN_FIRST, - 0, - NULL, - NULL, - NULL, - G_TYPE_NONE, - 3, - G_TYPE_UINT, - G_TYPE_OBJECT, - G_TYPE_HASH_TABLE); - - signals[SIGNAL_PREFIX_DELEGATED] = g_signal_new(NM_DHCP_CLIENT_SIGNAL_PREFIX_DELEGATED, - G_OBJECT_CLASS_TYPE(object_class), - G_SIGNAL_RUN_FIRST, - 0, - NULL, - NULL, - NULL, - G_TYPE_NONE, - 1, - G_TYPE_POINTER); -} diff --git a/src/dhcp/nm-dhcp-client.h b/src/dhcp/nm-dhcp-client.h deleted file mode 100644 index 05faa9ea..00000000 --- a/src/dhcp/nm-dhcp-client.h +++ /dev/null @@ -1,230 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2005 - 2010 Red Hat, Inc. - */ - -#ifndef __NETWORKMANAGER_DHCP_CLIENT_H__ -#define __NETWORKMANAGER_DHCP_CLIENT_H__ - -#include "nm-setting-ip4-config.h" -#include "nm-setting-ip6-config.h" -#include "nm-ip4-config.h" -#include "nm-ip6-config.h" -#include "nm-dhcp-utils.h" - -#define NM_DHCP_TIMEOUT_DEFAULT ((guint32) 45) /* default DHCP timeout, in seconds */ -#define NM_DHCP_TIMEOUT_INFINITY ((guint32) G_MAXINT32) - -#define NM_TYPE_DHCP_CLIENT (nm_dhcp_client_get_type()) -#define NM_DHCP_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DHCP_CLIENT, NMDhcpClient)) -#define NM_DHCP_CLIENT_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DHCP_CLIENT, NMDhcpClientClass)) -#define NM_IS_DHCP_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DHCP_CLIENT)) -#define NM_IS_DHCP_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_DHCP_CLIENT)) -#define NM_DHCP_CLIENT_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_DHCP_CLIENT, NMDhcpClientClass)) - -#define NM_DHCP_CLIENT_ADDR_FAMILY "addr-family" -#define NM_DHCP_CLIENT_FLAGS "flags" -#define NM_DHCP_CLIENT_HWADDR "hwaddr" -#define NM_DHCP_CLIENT_BROADCAST_HWADDR "broadcast-hwaddr" -#define NM_DHCP_CLIENT_IFINDEX "ifindex" -#define NM_DHCP_CLIENT_INTERFACE "iface" -#define NM_DHCP_CLIENT_MULTI_IDX "multi-idx" -#define NM_DHCP_CLIENT_HOSTNAME "hostname" -#define NM_DHCP_CLIENT_MUD_URL "mud-url" -#define NM_DHCP_CLIENT_ROUTE_METRIC "route-metric" -#define NM_DHCP_CLIENT_ROUTE_TABLE "route-table" -#define NM_DHCP_CLIENT_TIMEOUT "timeout" -#define NM_DHCP_CLIENT_UUID "uuid" -#define NM_DHCP_CLIENT_IAID "iaid" -#define NM_DHCP_CLIENT_IAID_EXPLICIT "iaid-explicit" -#define NM_DHCP_CLIENT_HOSTNAME_FLAGS "hostname-flags" -#define NM_DHCP_CLIENT_VENDOR_CLASS_IDENTIFIER "vendor-class-identifier" -#define NM_DHCP_CLIENT_REJECT_SERVERS "reject-servers" - -#define NM_DHCP_CLIENT_SIGNAL_STATE_CHANGED "state-changed" -#define NM_DHCP_CLIENT_SIGNAL_PREFIX_DELEGATED "prefix-delegated" - -typedef enum { - NM_DHCP_STATE_UNKNOWN = 0, - NM_DHCP_STATE_BOUND, /* new lease */ - NM_DHCP_STATE_EXTENDED, /* lease extended */ - NM_DHCP_STATE_TIMEOUT, /* timed out contacting server */ - NM_DHCP_STATE_DONE, /* client quit or stopped */ - NM_DHCP_STATE_EXPIRE, /* lease expired or NAKed */ - NM_DHCP_STATE_FAIL, /* failed for some reason */ - NM_DHCP_STATE_TERMINATED, /* client is no longer running */ - __NM_DHCP_STATE_MAX, - NM_DHCP_STATE_MAX = __NM_DHCP_STATE_MAX - 1, -} NMDhcpState; - -struct _NMDhcpClientPrivate; - -typedef struct { - GObject parent; - struct _NMDhcpClientPrivate *_priv; - CList dhcp_client_lst; -} NMDhcpClient; - -typedef enum { - NM_DHCP_CLIENT_FLAGS_INFO_ONLY = (1LL << 0), - NM_DHCP_CLIENT_FLAGS_USE_FQDN = (1LL << 1), -} NMDhcpClientFlags; - -typedef struct { - GObjectClass parent; - - gboolean (*ip4_start)(NMDhcpClient *self, - const char * anycast_addr, - const char * last_ip4_address, - GError ** error); - - gboolean (*accept)(NMDhcpClient *self, GError **error); - - gboolean (*decline)(NMDhcpClient *self, const char *error_message, GError **error); - - gboolean (*ip6_start)(NMDhcpClient * self, - const char * anycast_addr, - const struct in6_addr * ll_addr, - NMSettingIP6ConfigPrivacy privacy, - guint needed_prefixes, - GError ** error); - - void (*stop)(NMDhcpClient *self, gboolean release); - - /** - * get_duid: - * @self: the #NMDhcpClient - * - * Attempts to find an existing DHCPv6 DUID for this client in the DHCP - * client's persistent configuration. Returned DUID should be the binary - * representation of the DUID. If no DUID is found, %NULL should be - * returned. - */ - GBytes *(*get_duid)(NMDhcpClient *self); -} NMDhcpClientClass; - -GType nm_dhcp_client_get_type(void); - -struct _NMDedupMultiIndex *nm_dhcp_client_get_multi_idx(NMDhcpClient *self); - -pid_t nm_dhcp_client_get_pid(NMDhcpClient *self); - -int nm_dhcp_client_get_addr_family(NMDhcpClient *self); - -const char *nm_dhcp_client_get_iface(NMDhcpClient *self); - -int nm_dhcp_client_get_ifindex(NMDhcpClient *self); - -const char *nm_dhcp_client_get_uuid(NMDhcpClient *self); - -GBytes *nm_dhcp_client_get_duid(NMDhcpClient *self); - -GBytes *nm_dhcp_client_get_hw_addr(NMDhcpClient *self); - -GBytes *nm_dhcp_client_get_broadcast_hw_addr(NMDhcpClient *self); - -guint32 nm_dhcp_client_get_route_table(NMDhcpClient *self); - -void nm_dhcp_client_set_route_table(NMDhcpClient *self, guint32 route_table); - -guint32 nm_dhcp_client_get_route_metric(NMDhcpClient *self); - -void nm_dhcp_client_set_route_metric(NMDhcpClient *self, guint32 route_metric); - -guint32 nm_dhcp_client_get_timeout(NMDhcpClient *self); - -guint32 nm_dhcp_client_get_iaid(NMDhcpClient *self); - -gboolean nm_dhcp_client_get_iaid_explicit(NMDhcpClient *self); - -GBytes *nm_dhcp_client_get_client_id(NMDhcpClient *self); - -const char * nm_dhcp_client_get_hostname(NMDhcpClient *self); -const char * nm_dhcp_client_get_mud_url(NMDhcpClient *self); -const char *const *nm_dhcp_client_get_reject_servers(NMDhcpClient *self); - -NMDhcpHostnameFlags nm_dhcp_client_get_hostname_flags(NMDhcpClient *self); - -gboolean nm_dhcp_client_get_info_only(NMDhcpClient *self); - -gboolean nm_dhcp_client_get_use_fqdn(NMDhcpClient *self); - -GBytes *nm_dhcp_client_get_vendor_class_identifier(NMDhcpClient *self); - -gboolean nm_dhcp_client_start_ip4(NMDhcpClient *self, - GBytes * client_id, - const char * dhcp_anycast_addr, - const char * last_ip4_address, - GError ** error); - -gboolean nm_dhcp_client_start_ip6(NMDhcpClient * self, - GBytes * client_id, - gboolean enforce_duid, - const char * dhcp_anycast_addr, - const struct in6_addr * ll_addr, - NMSettingIP6ConfigPrivacy privacy, - guint needed_prefixes, - GError ** error); - -gboolean nm_dhcp_client_accept(NMDhcpClient *self, GError **error); - -gboolean nm_dhcp_client_decline(NMDhcpClient *self, const char *error_message, GError **error); - -void nm_dhcp_client_stop(NMDhcpClient *self, gboolean release); - -/* Backend helpers for subclasses */ -void nm_dhcp_client_stop_existing(const char *pid_file, const char *binary_name); - -void nm_dhcp_client_stop_pid(pid_t pid, const char *iface); - -void nm_dhcp_client_start_timeout(NMDhcpClient *self); - -void nm_dhcp_client_watch_child(NMDhcpClient *self, pid_t pid); - -void nm_dhcp_client_set_state(NMDhcpClient *self, - NMDhcpState new_state, - NMIPConfig * ip_config, - GHashTable * options); /* str:str hash */ - -gboolean nm_dhcp_client_handle_event(gpointer unused, - const char * iface, - int pid, - GVariant * options, - const char * reason, - NMDhcpClient *self); - -void nm_dhcp_client_set_client_id(NMDhcpClient *self, GBytes *client_id); -void nm_dhcp_client_set_client_id_bin(NMDhcpClient *self, - guint8 type, - const guint8 *client_id, - gsize len); - -void nm_dhcp_client_emit_ipv6_prefix_delegated(NMDhcpClient * self, - const NMPlatformIP6Address *prefix); - -gboolean nm_dhcp_client_server_id_is_rejected(NMDhcpClient *self, gconstpointer addr); - -/***************************************************************************** - * Client data - *****************************************************************************/ - -typedef struct { - GType (*get_type)(void); - GType (*get_type_per_addr_family)(int addr_family); - const char *name; - const char *(*get_path)(void); - bool experimental : 1; -} NMDhcpClientFactory; - -GType nm_dhcp_nettools_get_type(void); - -extern const NMDhcpClientFactory _nm_dhcp_client_factory_dhcpcanon; -extern const NMDhcpClientFactory _nm_dhcp_client_factory_dhclient; -extern const NMDhcpClientFactory _nm_dhcp_client_factory_dhcpcd; -extern const NMDhcpClientFactory _nm_dhcp_client_factory_internal; -extern const NMDhcpClientFactory _nm_dhcp_client_factory_systemd; -extern const NMDhcpClientFactory _nm_dhcp_client_factory_nettools; - -#endif /* __NETWORKMANAGER_DHCP_CLIENT_H__ */ diff --git a/src/dhcp/nm-dhcp-dhclient-utils.c b/src/dhcp/nm-dhcp-dhclient-utils.c deleted file mode 100644 index f0eed6f5..00000000 --- a/src/dhcp/nm-dhcp-dhclient-utils.c +++ /dev/null @@ -1,713 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2011 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include "nm-dhcp-dhclient-utils.h" - -#include <ctype.h> -#include <arpa/inet.h> -#include <net/if.h> - -#include "nm-glib-aux/nm-dedup-multi.h" - -#include "nm-dhcp-utils.h" -#include "nm-ip4-config.h" -#include "nm-utils.h" -#include "platform/nm-platform.h" -#include "NetworkManagerUtils.h" - -#define TIMEOUT_TAG "timeout " -#define RETRY_TAG "retry " -#define CLIENTID_TAG "send dhcp-client-identifier" - -#define HOSTNAME4_TAG "send host-name" -#define HOSTNAME4_FORMAT HOSTNAME4_TAG " \"%s\"; # added by NetworkManager" - -#define FQDN_TAG_PREFIX "send fqdn." -#define FQDN_TAG FQDN_TAG_PREFIX "fqdn" -#define FQDN_FORMAT FQDN_TAG " \"%s\"; # added by NetworkManager" - -#define ALSOREQ_TAG "also request " -#define REQ_TAG "request " - -#define MUDURLv4_DEF "option mudurl code 161 = text;\n" -#define MUDURLv4_FMT "send mudurl \"%s\";\n" - -#define MUDURLv6_DEF "option dhcp6.mudurl code 112 = text;\n" -#define MUDURLv6_FMT "send dhcp6.mudurl \"%s\";\n" - -static void -add_request(GPtrArray *array, const char *item) -{ - guint i; - - for (i = 0; i < array->len; i++) { - if (nm_streq(array->pdata[i], item)) - return; - } - g_ptr_array_add(array, g_strdup(item)); -} - -static gboolean -grab_request_options(GPtrArray *store, const char *line) -{ - gs_free const char **line_v = NULL; - gsize i; - - /* Grab each 'request' or 'also request' option and save for later */ - line_v = nm_utils_strsplit_set(line, "\t ,"); - for (i = 0; line_v && line_v[i]; i++) { - const char *ss = nm_str_skip_leading_spaces(line_v[i]); - gsize l; - gboolean end = FALSE; - - if (!ss[0]) - continue; - if (ss[0] == ';') { - /* all done */ - return TRUE; - } - - if (!g_ascii_isalnum(ss[0])) - continue; - - l = strlen(ss); - - while (l > 0 && g_ascii_isspace(ss[l - 1])) { - ((char *) ss)[l - 1] = '\0'; - l--; - } - if (l > 0 && ss[l - 1] == ';') { - /* Remove the EOL marker */ - ((char *) ss)[l - 1] = '\0'; - end = TRUE; - } - - if (ss[0]) - add_request(store, ss); - - if (end) - return TRUE; - } - - return FALSE; -} - -static void -add_ip4_config(GString * str, - GBytes * client_id, - const char * hostname, - gboolean use_fqdn, - NMDhcpHostnameFlags hostname_flags) -{ - if (client_id) { - const char *p; - gsize l; - guint i; - - p = g_bytes_get_data(client_id, &l); - nm_assert(p); - - /* Allow type 0 (non-hardware address) to be represented as a string - * as long as all the characters are printable. - */ - for (i = 1; (p[0] == 0) && i < l; i++) { - if (!g_ascii_isprint(p[i]) || p[i] == '\\' || p[i] == '"') - break; - } - - g_string_append(str, CLIENTID_TAG " "); - if (i < l) { - /* Unprintable; convert to a hex string */ - for (i = 0; i < l; i++) { - if (i > 0) - g_string_append_c(str, ':'); - g_string_append_printf(str, "%02x", (guint8) p[i]); - } - } else { - /* Printable; just add to the line with type 0 */ - g_string_append_c(str, '"'); - g_string_append(str, "\\x00"); - g_string_append_len(str, p + 1, l - 1); - g_string_append_c(str, '"'); - } - g_string_append(str, "; # added by NetworkManager\n"); - } - - if (hostname) { - if (use_fqdn) { - g_string_append_printf(str, FQDN_FORMAT "\n", hostname); - - g_string_append_printf(str, - FQDN_TAG_PREFIX "encoded %s;\n", - (hostname_flags & NM_DHCP_HOSTNAME_FLAG_FQDN_ENCODED) ? "on" - : "off"); - - g_string_append_printf( - str, - FQDN_TAG_PREFIX "server-update %s;\n", - (hostname_flags & NM_DHCP_HOSTNAME_FLAG_FQDN_SERV_UPDATE) ? "on" : "off"); - - g_string_append_printf(str, - FQDN_TAG_PREFIX "no-client-update %s;\n", - (hostname_flags & NM_DHCP_HOSTNAME_FLAG_FQDN_NO_UPDATE) ? "on" - : "off"); - } else - g_string_append_printf(str, HOSTNAME4_FORMAT "\n", hostname); - } - - g_string_append_c(str, '\n'); - - /* Define options for classless static routes */ - g_string_append( - str, - "option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;\n"); - g_string_append(str, - "option ms-classless-static-routes code 249 = array of unsigned integer 8;\n"); - /* Web Proxy Auto-Discovery option (bgo #368423) */ - g_string_append(str, "option wpad code 252 = string;\n"); - - g_string_append_c(str, '\n'); -} - -static void -add_hostname6(GString *str, const char *hostname, NMDhcpHostnameFlags hostname_flags) -{ - if (hostname) { - g_string_append_printf(str, FQDN_FORMAT "\n", hostname); - if (hostname_flags & NM_DHCP_HOSTNAME_FLAG_FQDN_SERV_UPDATE) - g_string_append(str, FQDN_TAG_PREFIX "server-update on;\n"); - if (hostname_flags & NM_DHCP_HOSTNAME_FLAG_FQDN_NO_UPDATE) - g_string_append(str, FQDN_TAG_PREFIX "no-client-update on;\n"); - g_string_append_c(str, '\n'); - } -} - -static void -add_mud_url_config(GString *str, const char *mud_url, int addr_family) -{ - if (mud_url) { - if (addr_family == AF_INET) { - g_string_append(str, MUDURLv4_DEF); - g_string_append_printf(str, MUDURLv4_FMT, mud_url); - } else { - g_string_append(str, MUDURLv6_DEF); - g_string_append_printf(str, MUDURLv6_FMT, mud_url); - } - } -} - -static GBytes * -read_client_id(const char *str) -{ - gs_free char *s = NULL; - char * p; - int i = 0, j = 0; - - nm_assert(!strncmp(str, CLIENTID_TAG, NM_STRLEN(CLIENTID_TAG))); - str += NM_STRLEN(CLIENTID_TAG); - - if (!g_ascii_isspace(*str)) - return NULL; - while (g_ascii_isspace(*str)) - str++; - - if (*str == '"') { - /* Parse string literal with escape sequences */ - s = g_strdup(str + 1); - p = strrchr(s, '"'); - if (p) - *p = '\0'; - else - return NULL; - - if (!s[0]) - return NULL; - - while (s[i]) { - if (s[i] == '\\' && s[i + 1] == 'x' && g_ascii_isxdigit(s[i + 2]) - && g_ascii_isxdigit(s[i + 3])) { - s[j++] = (g_ascii_xdigit_value(s[i + 2]) << 4) + g_ascii_xdigit_value(s[i + 3]); - i += 4; - continue; - } - if (s[i] == '\\' && s[i + 1] >= '0' && s[i + 1] <= '7' && s[1 + 2] >= '0' - && s[i + 2] <= '7' && s[1 + 3] >= '0' && s[i + 3] <= '7') { - s[j++] = ((s[i + 1] - '0') << 6) + ((s[i + 2] - '0') << 3) + (s[i + 3] - '0'); - i += 4; - continue; - } - s[j++] = s[i++]; - } - return g_bytes_new_take(g_steal_pointer(&s), j); - } - - /* Otherwise, try to read a hexadecimal sequence */ - s = g_strdup(str); - g_strchomp(s); - if (s[strlen(s) - 1] == ';') - s[strlen(s) - 1] = '\0'; - - return nm_utils_hexstr2bin(s); -} - -static gboolean -read_interface(const char *line, char *interface, guint size) -{ - gs_free char *dup = g_strdup(line + NM_STRLEN("interface")); - char * ptr = dup, *end; - - while (g_ascii_isspace(*ptr)) - ptr++; - - if (*ptr == '"') { - ptr++; - end = strchr(ptr, '"'); - if (!end) - return FALSE; - *end = '\0'; - } else { - end = strchr(ptr, ' '); - if (!end) - end = strchr(ptr, '{'); - if (!end) - return FALSE; - *end = '\0'; - } - - if (ptr[0] == '\0' || strlen(ptr) + 1 > size) - return FALSE; - - snprintf(interface, size, "%s", ptr); - - return TRUE; -} - -char * -nm_dhcp_dhclient_create_config(const char * interface, - int addr_family, - GBytes * client_id, - const char * anycast_addr, - const char * hostname, - guint32 timeout, - gboolean use_fqdn, - NMDhcpHostnameFlags hostname_flags, - const char * mud_url, - const char *const * reject_servers, - const char * orig_path, - const char * orig_contents, - GBytes ** out_new_client_id) -{ - nm_auto_free_gstring GString *new_contents = NULL; - gs_unref_ptrarray GPtrArray *fqdn_opts = NULL; - gs_unref_ptrarray GPtrArray *reqs = NULL; - gboolean reset_reqlist = FALSE; - int i; - - g_return_val_if_fail(!anycast_addr || nm_utils_hwaddr_valid(anycast_addr, ETH_ALEN), NULL); - g_return_val_if_fail(NM_IN_SET(addr_family, AF_INET, AF_INET6), NULL); - g_return_val_if_fail(!reject_servers || addr_family == AF_INET, NULL); - nm_assert(!out_new_client_id || !*out_new_client_id); - - new_contents = g_string_new(_("# Created by NetworkManager\n")); - reqs = g_ptr_array_new_full(5, g_free); - - if (orig_contents) { - gs_free const char **lines = NULL; - gsize line_i; - nm_auto_free_gstring GString *blocks_stack = NULL; - guint blocks_skip = 0; - gboolean in_alsoreq = FALSE; - gboolean in_req = FALSE; - char intf[IFNAMSIZ]; - - blocks_stack = g_string_new(NULL); - g_string_append_printf(new_contents, _("# Merged from %s\n\n"), orig_path); - intf[0] = '\0'; - - lines = nm_utils_strsplit_set(orig_contents, "\n\r"); - for (line_i = 0; lines && lines[line_i]; line_i++) { - const char *line = nm_str_skip_leading_spaces(lines[line_i]); - const char *p; - - if (line[0] == '\0') - continue; - - g_strchomp((char *) line); - - p = line; - if (in_req) { - /* pass */ - } else if (strchr(p, '{')) { - if (NM_STR_HAS_PREFIX(p, "lease") || NM_STR_HAS_PREFIX(p, "alias") - || NM_STR_HAS_PREFIX(p, "interface") || NM_STR_HAS_PREFIX(p, "pseudo")) { - /* skip over these blocks, except 'interface' when it - * matches the current interface */ - blocks_skip++; - g_string_append_c(blocks_stack, 'b'); - if (!intf[0] && NM_STR_HAS_PREFIX(p, "interface")) { - if (read_interface(p, intf, sizeof(intf))) - continue; - } - } else { - /* allow other blocks (conditionals) */ - if (!strchr(p, '}')) /* '} else {' */ - g_string_append_c(blocks_stack, 'c'); - } - } else if (strchr(p, '}')) { - if (blocks_stack->len > 0) { - if (blocks_stack->str[blocks_stack->len - 1] == 'b') { - g_string_truncate(blocks_stack, blocks_stack->len - 1); - nm_assert(blocks_skip > 0); - blocks_skip--; - intf[0] = '\0'; - continue; - } - g_string_truncate(blocks_stack, blocks_stack->len - 1); - } - } - - if (blocks_skip > 0 && !intf[0]) - continue; - - if (intf[0] && !nm_streq(intf, interface)) - continue; - - /* Some timing parameters in dhclient should not be imported (timeout, retry). - * The retry parameter will be simply not used as we will exit on first failure. - * The timeout one instead may affect NetworkManager behavior: if the timeout - * elapses before dhcp-timeout dhclient will report failure and cause NM to - * fail the dhcp process before dhcp-timeout. So, always skip importing timeout - * as we will need to add one greater than dhcp-timeout. - */ - if (!strncmp(p, TIMEOUT_TAG, strlen(TIMEOUT_TAG)) - || !strncmp(p, RETRY_TAG, strlen(RETRY_TAG))) - continue; - - if (!strncmp(p, CLIENTID_TAG, strlen(CLIENTID_TAG))) { - /* Override config file "dhcp-client-id" and use one from the connection */ - if (client_id) - continue; - - /* Otherwise, capture and return the existing client id */ - if (out_new_client_id) - nm_clear_pointer(out_new_client_id, g_bytes_unref); - NM_SET_OUT(out_new_client_id, read_client_id(p)); - } - - /* Override config file hostname and use one from the connection */ - if (hostname) { - if (strncmp(p, HOSTNAME4_TAG, strlen(HOSTNAME4_TAG)) == 0) - continue; - if (strncmp(p, FQDN_TAG, strlen(FQDN_TAG)) == 0) - continue; - } - - /* To let user's FQDN options (except "fqdn.fqdn") override the - * default ones set by NM, add them later - */ - if (!strncmp(p, FQDN_TAG_PREFIX, NM_STRLEN(FQDN_TAG_PREFIX))) { - if (!fqdn_opts) - fqdn_opts = g_ptr_array_new_full(5, g_free); - g_ptr_array_add(fqdn_opts, g_strdup(p + NM_STRLEN(FQDN_TAG_PREFIX))); - continue; - } - - /* Ignore 'script' since we pass our own */ - if (g_str_has_prefix(p, "script ")) - continue; - - /* Check for "request" */ - if (!strncmp(p, REQ_TAG, strlen(REQ_TAG))) { - in_req = TRUE; - p += strlen(REQ_TAG); - g_ptr_array_set_size(reqs, 0); - reset_reqlist = TRUE; - } - - /* Save all request options for later use */ - if (in_req) { - in_req = !grab_request_options(reqs, p); - continue; - } - - /* Check for "also require" */ - if (!strncmp(p, ALSOREQ_TAG, strlen(ALSOREQ_TAG))) { - in_alsoreq = TRUE; - p += strlen(ALSOREQ_TAG); - } - - if (in_alsoreq) { - in_alsoreq = !grab_request_options(reqs, p); - continue; - } - - /* Existing configuration line is OK, add it to new configuration */ - g_string_append(new_contents, line); - g_string_append_c(new_contents, '\n'); - } - } else - g_string_append_c(new_contents, '\n'); - - /* ensure dhclient timeout is greater than dhcp-timeout: as dhclient timeout default value is - * 60 seconds, we need this only if dhcp-timeout is greater than 60. - */ - if (timeout >= 60) { - timeout = timeout < G_MAXINT32 ? timeout + 1 : G_MAXINT32; - g_string_append_printf(new_contents, "timeout %u;\n", timeout); - } - - add_mud_url_config(new_contents, mud_url, addr_family); - - if (reject_servers && reject_servers[0]) { - g_string_append(new_contents, "reject "); - for (i = 0; reject_servers[i]; i++) { - if (i != 0) - g_string_append(new_contents, ", "); - g_string_append(new_contents, reject_servers[i]); - } - g_string_append(new_contents, ";\n"); - } - - if (addr_family == AF_INET) { - add_ip4_config(new_contents, client_id, hostname, use_fqdn, hostname_flags); - add_request(reqs, "rfc3442-classless-static-routes"); - add_request(reqs, "ms-classless-static-routes"); - add_request(reqs, "static-routes"); - add_request(reqs, "wpad"); - add_request(reqs, "ntp-servers"); - add_request(reqs, "root-path"); - } else { - add_hostname6(new_contents, hostname, hostname_flags); - add_request(reqs, "dhcp6.name-servers"); - add_request(reqs, "dhcp6.domain-search"); - - /* FIXME: internal client does not support requesting client-id option. Does this even work? */ - add_request(reqs, "dhcp6.client-id"); - } - - if (reset_reqlist) - g_string_append(new_contents, "request; # override dhclient defaults\n"); - /* And add it to the dhclient configuration */ - for (i = 0; i < reqs->len; i++) - g_string_append_printf(new_contents, "also request %s;\n", (char *) reqs->pdata[i]); - - if (fqdn_opts) { - for (i = 0; i < fqdn_opts->len; i++) { - const char *t = fqdn_opts->pdata[i]; - - if (i == 0) - g_string_append_printf(new_contents, "\n# FQDN options from %s\n", orig_path); - g_string_append_printf(new_contents, FQDN_TAG_PREFIX "%s\n", t); - } - } - - g_string_append_c(new_contents, '\n'); - - if (anycast_addr) { - g_string_append_printf(new_contents, - "interface \"%s\" {\n" - " initial-interval 1; \n" - " anycast-mac ethernet %s;\n" - "}\n", - interface, - anycast_addr); - } - - return g_string_free(g_steal_pointer(&new_contents), FALSE); -} - -/* Roughly follow what dhclient's quotify_buf() and pretty_escape() functions do */ -char * -nm_dhcp_dhclient_escape_duid(GBytes *duid) -{ - char * escaped; - const guint8 *s, *s0; - gsize len; - char * d; - - g_return_val_if_fail(duid, NULL); - - s0 = g_bytes_get_data(duid, &len); - s = s0; - - d = escaped = g_malloc((len * 4) + 1); - while (s < (s0 + len)) { - if (!g_ascii_isprint(*s)) { - *d++ = '\\'; - *d++ = '0' + ((*s >> 6) & 0x7); - *d++ = '0' + ((*s >> 3) & 0x7); - *d++ = '0' + (*s++ & 0x7); - } else if (*s == '"' || *s == '\'' || *s == '$' || *s == '`' || *s == '\\' || *s == '|' - || *s == '&') { - *d++ = '\\'; - *d++ = *s++; - } else - *d++ = *s++; - } - *d++ = '\0'; - return escaped; -} - -static gboolean -isoctal(const guint8 *p) -{ - return (p[0] >= '0' && p[0] <= '3' && p[1] >= '0' && p[1] <= '7' && p[2] >= '0' && p[2] <= '7'); -} - -GBytes * -nm_dhcp_dhclient_unescape_duid(const char *duid) -{ - GByteArray * unescaped; - const guint8 *p = (const guint8 *) duid; - guint i, len; - guint8 octal; - - /* FIXME: it's wrong to have an "unescape-duid" function. dhclient - * defines a file format with escaping. So we need a general unescape - * function that can handle dhclient syntax. */ - - len = strlen(duid); - unescaped = g_byte_array_sized_new(len); - for (i = 0; i < len; i++) { - if (p[i] == '\\') { - i++; - if (isdigit(p[i])) { - /* Octal escape sequence */ - if (i + 2 >= len || !isoctal(p + i)) - goto error; - octal = ((p[i] - '0') << 6) + ((p[i + 1] - '0') << 3) + (p[i + 2] - '0'); - g_byte_array_append(unescaped, &octal, 1); - i += 2; - } else { - /* FIXME: don't warn on untrusted data. Either signal an error, or accept - * it silently. */ - - /* One of ", ', $, `, \, |, or & */ - g_warn_if_fail(p[i] == '"' || p[i] == '\'' || p[i] == '$' || p[i] == '`' - || p[i] == '\\' || p[i] == '|' || p[i] == '&'); - g_byte_array_append(unescaped, &p[i], 1); - } - } else - g_byte_array_append(unescaped, &p[i], 1); - } - - return g_byte_array_free_to_bytes(unescaped); - -error: - g_byte_array_free(unescaped, TRUE); - return NULL; -} - -#define DUID_PREFIX "default-duid \"" - -/* Beware: @error may be unset even if the function returns %NULL. */ -GBytes * -nm_dhcp_dhclient_read_duid(const char *leasefile, GError **error) -{ - gs_free char * contents = NULL; - gs_free const char **contents_v = NULL; - gsize i; - - if (!g_file_test(leasefile, G_FILE_TEST_EXISTS)) - return NULL; - - if (!g_file_get_contents(leasefile, &contents, NULL, error)) - return NULL; - - contents_v = nm_utils_strsplit_set(contents, "\n\r"); - for (i = 0; contents_v && contents_v[i]; i++) { - const char *p = nm_str_skip_leading_spaces(contents_v[i]); - GBytes * duid; - - if (!NM_STR_HAS_PREFIX(p, DUID_PREFIX)) - continue; - - p += NM_STRLEN(DUID_PREFIX); - - g_strchomp((char *) p); - - if (!NM_STR_HAS_SUFFIX(p, "\";")) - continue; - - ((char *) p)[strlen(p) - 2] = '\0'; - - duid = nm_dhcp_dhclient_unescape_duid(p); - if (duid) - return duid; - } - - return NULL; -} - -gboolean -nm_dhcp_dhclient_save_duid(const char *leasefile, GBytes *duid, GError **error) -{ - gs_free char * escaped_duid = NULL; - gs_free const char **lines = NULL; - nm_auto_free_gstring GString *s = NULL; - const char *const * iter; - gsize len = 0; - - g_return_val_if_fail(leasefile != NULL, FALSE); - if (!duid) { - nm_utils_error_set_literal(error, NM_UTILS_ERROR_UNKNOWN, "missing duid"); - g_return_val_if_reached(FALSE); - } - - escaped_duid = nm_dhcp_dhclient_escape_duid(duid); - nm_assert(escaped_duid); - - if (g_file_test(leasefile, G_FILE_TEST_EXISTS)) { - gs_free char *contents = NULL; - - if (!g_file_get_contents(leasefile, &contents, &len, error)) { - g_prefix_error(error, "failed to read lease file %s: ", leasefile); - return FALSE; - } - - lines = nm_utils_strsplit_set_with_empty(contents, "\n\r"); - } - - s = g_string_sized_new(len + 50); - g_string_append_printf(s, DUID_PREFIX "%s\";\n", escaped_duid); - - /* Preserve existing leasefile contents */ - if (lines) { - for (iter = lines; *iter; iter++) { - const char *str = *iter; - const char *l; - - /* If we find an uncommented DUID in the file, check if - * equal to the one we are going to write: if so, no need - * to update the lease file, otherwise skip the old DUID. - */ - l = nm_str_skip_leading_spaces(str); - if (g_str_has_prefix(l, DUID_PREFIX)) { - gs_strfreev char **split = NULL; - - split = g_strsplit(l, "\"", -1); - if (split[0] && nm_streq0(split[1], escaped_duid)) - return TRUE; - - continue; - } - - if (str) - g_string_append(s, str); - /* avoid to add an extra '\n' at the end of file */ - if ((iter[1]) != NULL) - g_string_append_c(s, '\n'); - } - } - - if (!g_file_set_contents(leasefile, s->str, -1, error)) { - g_prefix_error(error, "failed to set DUID in lease file %s: ", leasefile); - return FALSE; - } - - return TRUE; -} diff --git a/src/dhcp/nm-dhcp-dhclient-utils.h b/src/dhcp/nm-dhcp-dhclient-utils.h deleted file mode 100644 index 3e524ee0..00000000 --- a/src/dhcp/nm-dhcp-dhclient-utils.h +++ /dev/null @@ -1,34 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2010 Red Hat, Inc. - */ - -#ifndef __NETWORKMANAGER_DHCP_DHCLIENT_UTILS_H__ -#define __NETWORKMANAGER_DHCP_DHCLIENT_UTILS_H__ - -#include "nm-setting-ip4-config.h" -#include "nm-setting-ip6-config.h" - -char *nm_dhcp_dhclient_create_config(const char * interface, - int addr_family, - GBytes * client_id, - const char * anycast_addr, - const char * hostname, - guint32 timeout, - gboolean use_fqdn, - NMDhcpHostnameFlags hostname_flags, - const char * mud_url, - const char *const * reject_servers, - const char * orig_path, - const char * orig_contents, - GBytes ** out_new_client_id); - -char *nm_dhcp_dhclient_escape_duid(GBytes *duid); - -GBytes *nm_dhcp_dhclient_unescape_duid(const char *duid); - -GBytes *nm_dhcp_dhclient_read_duid(const char *leasefile, GError **error); - -gboolean nm_dhcp_dhclient_save_duid(const char *leasefile, GBytes *duid, GError **error); - -#endif /* __NETWORKMANAGER_DHCP_DHCLIENT_UTILS_H__ */ diff --git a/src/dhcp/nm-dhcp-dhclient.c b/src/dhcp/nm-dhcp-dhclient.c deleted file mode 100644 index 260f400e..00000000 --- a/src/dhcp/nm-dhcp-dhclient.c +++ /dev/null @@ -1,727 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2005 - 2012 Red Hat, Inc. - */ - -#include <config.h> -#define __CONFIG_H__ - -#define _XOPEN_SOURCE -#include <time.h> -#undef _XOPEN_SOURCE - -#include "nm-default.h" - -#if WITH_DHCLIENT - - #include <stdlib.h> - #include <unistd.h> - #include <stdio.h> - #include <netinet/in.h> - #include <arpa/inet.h> - #include <ctype.h> - - #include "nm-glib-aux/nm-dedup-multi.h" - - #include "nm-utils.h" - #include "nm-dhcp-dhclient-utils.h" - #include "nm-dhcp-manager.h" - #include "NetworkManagerUtils.h" - #include "nm-dhcp-listener.h" - #include "nm-dhcp-client-logging.h" - -/*****************************************************************************/ - -static const char * -_addr_family_to_path_part(int addr_family) -{ - nm_assert(NM_IN_SET(addr_family, AF_INET, AF_INET6)); - return (addr_family == AF_INET6) ? "6" : ""; -} - -/*****************************************************************************/ - - #define NM_TYPE_DHCP_DHCLIENT (nm_dhcp_dhclient_get_type()) - #define NM_DHCP_DHCLIENT(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DHCP_DHCLIENT, NMDhcpDhclient)) - #define NM_DHCP_DHCLIENT_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DHCP_DHCLIENT, NMDhcpDhclientClass)) - #define NM_IS_DHCP_DHCLIENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DHCP_DHCLIENT)) - #define NM_IS_DHCP_DHCLIENT_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_DHCP_DHCLIENT)) - #define NM_DHCP_DHCLIENT_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_DHCP_DHCLIENT, NMDhcpDhclientClass)) - -typedef struct _NMDhcpDhclient NMDhcpDhclient; -typedef struct _NMDhcpDhclientClass NMDhcpDhclientClass; - -static GType nm_dhcp_dhclient_get_type(void); - -/*****************************************************************************/ - -typedef struct { - char * conf_file; - const char * def_leasefile; - char * lease_file; - char * pid_file; - NMDhcpListener *dhcp_listener; -} NMDhcpDhclientPrivate; - -struct _NMDhcpDhclient { - NMDhcpClient parent; - NMDhcpDhclientPrivate _priv; -}; - -struct _NMDhcpDhclientClass { - NMDhcpClientClass parent; -}; - -G_DEFINE_TYPE(NMDhcpDhclient, nm_dhcp_dhclient, NM_TYPE_DHCP_CLIENT) - - #define NM_DHCP_DHCLIENT_GET_PRIVATE(self) \ - _NM_GET_PRIVATE(self, NMDhcpDhclient, NM_IS_DHCP_DHCLIENT) - -/*****************************************************************************/ - -static const char * -nm_dhcp_dhclient_get_path(void) -{ - return nm_utils_find_helper("dhclient", DHCLIENT_PATH, NULL); -} - -/** - * get_dhclient_leasefile(): - * @addr_family: AF_INET or AF_INET6 - * @iface: the interface name of the device on which DHCP will be done - * @uuid: the connection UUID to which the returned lease should belong - * @out_preferred_path: on return, the "most preferred" leasefile path - * - * Returns the path of an existing leasefile (if any) for this interface and - * connection UUID. Also returns the "most preferred" leasefile path, which - * may be different than any found leasefile. - * - * Returns: an existing leasefile, or %NULL if no matching leasefile could be found - */ -static char * -get_dhclient_leasefile(int addr_family, - const char *iface, - const char *uuid, - char ** out_preferred_path) -{ - gs_free char *path = NULL; - - if (nm_dhcp_utils_get_leasefile_path(addr_family, "dhclient", iface, uuid, &path)) { - NM_SET_OUT(out_preferred_path, g_strdup(path)); - return g_steal_pointer(&path); - } - - NM_SET_OUT(out_preferred_path, g_steal_pointer(&path)); - - /* If the leasefile we're looking for doesn't exist yet in the new location - * (eg, /var/lib/NetworkManager) then look in old locations to maintain - * backwards compatibility with external tools (like dracut) that put - * leasefiles there. - */ - - /* Old Debian, SUSE, and Mandriva location */ - g_free(path); - path = g_strdup_printf(LOCALSTATEDIR "/lib/dhcp/dhclient%s-%s-%s.lease", - _addr_family_to_path_part(addr_family), - uuid, - iface); - if (g_file_test(path, G_FILE_TEST_EXISTS)) - return g_steal_pointer(&path); - - /* Old Red Hat and Fedora location */ - g_free(path); - path = g_strdup_printf(LOCALSTATEDIR "/lib/dhclient/dhclient%s-%s-%s.lease", - _addr_family_to_path_part(addr_family), - uuid, - iface); - if (g_file_test(path, G_FILE_TEST_EXISTS)) - return g_steal_pointer(&path); - - /* Fail */ - return NULL; -} - -static gboolean -merge_dhclient_config(NMDhcpDhclient * self, - int addr_family, - const char * iface, - const char * conf_file, - GBytes * client_id, - const char * anycast_addr, - const char * hostname, - guint32 timeout, - gboolean use_fqdn, - NMDhcpHostnameFlags hostname_flags, - const char * mud_url, - const char *const * reject_servers, - const char * orig_path, - GBytes ** out_new_client_id, - GError ** error) -{ - gs_free char *orig = NULL; - gs_free char *new = NULL; - - g_return_val_if_fail(iface, FALSE); - g_return_val_if_fail(conf_file, FALSE); - - if (orig_path && g_file_test(orig_path, G_FILE_TEST_EXISTS)) { - GError *read_error = NULL; - - if (!g_file_get_contents(orig_path, &orig, NULL, &read_error)) { - _LOGW("error reading dhclient configuration %s: %s", orig_path, read_error->message); - g_error_free(read_error); - } - } - - new = nm_dhcp_dhclient_create_config(iface, - addr_family, - client_id, - anycast_addr, - hostname, - timeout, - use_fqdn, - hostname_flags, - mud_url, - reject_servers, - orig_path, - orig, - out_new_client_id); - nm_assert(new); - - return g_file_set_contents(conf_file, new, -1, error); -} - -static char * -find_existing_config(NMDhcpDhclient *self, int addr_family, const char *iface, const char *uuid) -{ - char *path; - - /* NetworkManager-overridden configuration can be used to ship DHCP config - * with NetworkManager itself. It can be uuid-specific, device-specific - * or generic. - */ - if (uuid) { - path = g_strdup_printf(NMCONFDIR "/dhclient%s-%s.conf", - _addr_family_to_path_part(addr_family), - uuid); - _LOGD("looking for existing config %s", path); - if (g_file_test(path, G_FILE_TEST_EXISTS)) - return path; - g_free(path); - } - - path = g_strdup_printf(NMCONFDIR "/dhclient%s-%s.conf", - _addr_family_to_path_part(addr_family), - iface); - _LOGD("looking for existing config %s", path); - if (g_file_test(path, G_FILE_TEST_EXISTS)) - return path; - g_free(path); - - path = g_strdup_printf(NMCONFDIR "/dhclient%s.conf", _addr_family_to_path_part(addr_family)); - _LOGD("looking for existing config %s", path); - if (g_file_test(path, G_FILE_TEST_EXISTS)) - return path; - g_free(path); - - /* Distribution's dhclient configuration is used so that we can use - * configuration shipped with dhclient (if any). - * - * This replaces conditional compilation based on distribution name. Fedora - * and Debian store the configs in /etc/dhcp while upstream defaults to /etc - * which is then used by many other distributions. Some distributions - * (including Fedora) don't even provide a default configuration file. - */ - path = g_strdup_printf(SYSCONFDIR "/dhcp/dhclient%s-%s.conf", - _addr_family_to_path_part(addr_family), - iface); - _LOGD("looking for existing config %s", path); - if (g_file_test(path, G_FILE_TEST_EXISTS)) - return path; - g_free(path); - - path = g_strdup_printf(SYSCONFDIR "/dhclient%s-%s.conf", - _addr_family_to_path_part(addr_family), - iface); - _LOGD("looking for existing config %s", path); - if (g_file_test(path, G_FILE_TEST_EXISTS)) - return path; - g_free(path); - - path = - g_strdup_printf(SYSCONFDIR "/dhcp/dhclient%s.conf", _addr_family_to_path_part(addr_family)); - _LOGD("looking for existing config %s", path); - if (g_file_test(path, G_FILE_TEST_EXISTS)) - return path; - g_free(path); - - path = g_strdup_printf(SYSCONFDIR "/dhclient%s.conf", _addr_family_to_path_part(addr_family)); - _LOGD("looking for existing config %s", path); - if (g_file_test(path, G_FILE_TEST_EXISTS)) - return path; - g_free(path); - - return NULL; -} - -/* NM provides interface-specific options; thus the same dhclient config - * file cannot be used since DHCP transactions can happen in parallel. - * Since some distros don't have default per-interface dhclient config files, - * read their single config file and merge that into a custom per-interface - * config file along with the NM options. - */ -static char * -create_dhclient_config(NMDhcpDhclient * self, - int addr_family, - const char * iface, - const char * uuid, - GBytes * client_id, - const char * dhcp_anycast_addr, - const char * hostname, - guint32 timeout, - gboolean use_fqdn, - NMDhcpHostnameFlags hostname_flags, - const char * mud_url, - const char *const * reject_servers, - GBytes ** out_new_client_id) -{ - gs_free char *orig = NULL; - char *new = NULL; - GError *error = NULL; - - g_return_val_if_fail(iface != NULL, NULL); - - new = g_strdup_printf(NMSTATEDIR "/dhclient%s-%s.conf", - _addr_family_to_path_part(addr_family), - iface); - - _LOGD("creating composite dhclient config %s", new); - - orig = find_existing_config(self, addr_family, iface, uuid); - if (orig) - _LOGD("merging existing dhclient config %s", orig); - else - _LOGD("no existing dhclient configuration to merge"); - - if (!merge_dhclient_config(self, - addr_family, - iface, - new, - client_id, - dhcp_anycast_addr, - hostname, - timeout, - use_fqdn, - hostname_flags, - mud_url, - reject_servers, - orig, - out_new_client_id, - &error)) { - _LOGW("error creating dhclient configuration: %s", error->message); - g_clear_error(&error); - } - - return new; -} - -static gboolean -dhclient_start(NMDhcpClient *client, - const char * mode_opt, - gboolean release, - pid_t * out_pid, - int prefixes, - GError ** error) -{ - NMDhcpDhclient * self = NM_DHCP_DHCLIENT(client); - NMDhcpDhclientPrivate *priv = NM_DHCP_DHCLIENT_GET_PRIVATE(self); - gs_unref_ptrarray GPtrArray *argv = NULL; - pid_t pid; - gs_free_error GError *local = NULL; - const char * iface; - const char * uuid; - const char * system_bus_address; - const char * dhclient_path; - char * binary_name; - gs_free char * cmd_str = NULL; - gs_free char * pid_file = NULL; - gs_free char * system_bus_address_env = NULL; - gs_free char * preferred_leasefile_path = NULL; - const int addr_family = nm_dhcp_client_get_addr_family(client); - - g_return_val_if_fail(!priv->pid_file, FALSE); - - NM_SET_OUT(out_pid, 0); - - dhclient_path = nm_dhcp_dhclient_get_path(); - if (!dhclient_path) { - nm_utils_error_set_literal(error, NM_UTILS_ERROR_UNKNOWN, "dhclient binary not found"); - return FALSE; - } - - iface = nm_dhcp_client_get_iface(client); - uuid = nm_dhcp_client_get_uuid(client); - - pid_file = g_strdup_printf(NMRUNDIR "/dhclient%s-%s.pid", - _addr_family_to_path_part(addr_family), - iface); - - /* Kill any existing dhclient from the pidfile */ - binary_name = g_path_get_basename(dhclient_path); - nm_dhcp_client_stop_existing(pid_file, binary_name); - g_free(binary_name); - - if (release) { - /* release doesn't use the pidfile after killing an old client */ - nm_clear_g_free(&pid_file); - } - - g_free(priv->lease_file); - priv->lease_file = get_dhclient_leasefile(addr_family, iface, uuid, &preferred_leasefile_path); - nm_assert(preferred_leasefile_path); - if (!priv->lease_file) { - /* No existing leasefile, dhclient will create one at the preferred path */ - priv->lease_file = g_steal_pointer(&preferred_leasefile_path); - } else if (!nm_streq0(priv->lease_file, preferred_leasefile_path)) { - gs_unref_object GFile *src = g_file_new_for_path(priv->lease_file); - gs_unref_object GFile *dst = g_file_new_for_path(preferred_leasefile_path); - - /* Try to copy the existing leasefile to the preferred location */ - if (!g_file_copy(src, dst, G_FILE_COPY_OVERWRITE, NULL, NULL, NULL, &local)) { - gs_free char *s_path = NULL; - gs_free char *d_path = NULL; - - /* Failure; just use the existing leasefile */ - _LOGW("failed to copy leasefile %s to %s: %s", - (s_path = g_file_get_path(src)), - (d_path = g_file_get_path(dst)), - local->message); - g_clear_error(&local); - } else { - /* Success; use the preferred leasefile path */ - g_free(priv->lease_file); - priv->lease_file = g_file_get_path(dst); - } - } - - /* Save the DUID to the leasefile dhclient will actually use */ - if (addr_family == AF_INET6) { - if (!nm_dhcp_dhclient_save_duid(priv->lease_file, - nm_dhcp_client_get_client_id(client), - &local)) { - nm_utils_error_set(error, - NM_UTILS_ERROR_UNKNOWN, - "failed to save DUID to '%s': %s", - priv->lease_file, - local->message); - return FALSE; - } - } - - argv = g_ptr_array_new(); - g_ptr_array_add(argv, (gpointer) dhclient_path); - - g_ptr_array_add(argv, (gpointer) "-d"); - - /* Be quiet. dhclient logs to syslog anyway. And we duplicate the syslog - * to stderr in case of NM running with --debug. - */ - g_ptr_array_add(argv, (gpointer) "-q"); - - if (release) - g_ptr_array_add(argv, (gpointer) "-r"); - - if (addr_family == AF_INET6) { - g_ptr_array_add(argv, (gpointer) "-6"); - if (mode_opt) - g_ptr_array_add(argv, (gpointer) mode_opt); - while (prefixes--) - g_ptr_array_add(argv, (gpointer) "-P"); - } - g_ptr_array_add(argv, (gpointer) "-sf"); /* Set script file */ - g_ptr_array_add(argv, (gpointer) nm_dhcp_helper_path); - - if (pid_file) { - g_ptr_array_add(argv, (gpointer) "-pf"); /* Set pid file */ - g_ptr_array_add(argv, (gpointer) pid_file); - } - - g_ptr_array_add(argv, (gpointer) "-lf"); /* Set lease file */ - g_ptr_array_add(argv, (gpointer) priv->lease_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 dhclient, since dhclient - * 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); - - _LOGD("running: %s", (cmd_str = g_strjoinv(" ", (char **) argv->pdata))); - - 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, - "dhclient failed to start: %s", - local->message); - return FALSE; - } - - _LOGI("dhclient started with pid %lld", (long long int) pid); - - if (!release) - nm_dhcp_client_watch_child(client, pid); - - priv->pid_file = g_steal_pointer(&pid_file); - - NM_SET_OUT(out_pid, pid); - return TRUE; -} - -static gboolean -ip4_start(NMDhcpClient *client, - const char * dhcp_anycast_addr, - const char * last_ip4_address, - GError ** error) -{ - NMDhcpDhclient * self = NM_DHCP_DHCLIENT(client); - NMDhcpDhclientPrivate *priv = NM_DHCP_DHCLIENT_GET_PRIVATE(self); - GBytes * client_id; - gs_unref_bytes GBytes *new_client_id = NULL; - - client_id = nm_dhcp_client_get_client_id(client); - - priv->conf_file = create_dhclient_config(self, - AF_INET, - nm_dhcp_client_get_iface(client), - nm_dhcp_client_get_uuid(client), - client_id, - dhcp_anycast_addr, - nm_dhcp_client_get_hostname(client), - nm_dhcp_client_get_timeout(client), - nm_dhcp_client_get_use_fqdn(client), - nm_dhcp_client_get_hostname_flags(client), - nm_dhcp_client_get_mud_url(client), - nm_dhcp_client_get_reject_servers(client), - &new_client_id); - if (!priv->conf_file) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_UNKNOWN, - "error creating dhclient configuration file"); - return FALSE; - } - - if (new_client_id) { - nm_assert(!client_id); - nm_dhcp_client_set_client_id(client, new_client_id); - } - return dhclient_start(client, NULL, FALSE, NULL, 0, error); -} - -static gboolean -ip6_start(NMDhcpClient * client, - const char * dhcp_anycast_addr, - const struct in6_addr * ll_addr, - NMSettingIP6ConfigPrivacy privacy, - guint needed_prefixes, - GError ** error) -{ - NMDhcpDhclient * self = NM_DHCP_DHCLIENT(client); - NMDhcpDhclientPrivate *priv = NM_DHCP_DHCLIENT_GET_PRIVATE(self); - - if (nm_dhcp_client_get_iaid_explicit(client)) - _LOGW("dhclient does not support specifying an IAID for DHCPv6, it will be ignored"); - - priv->conf_file = create_dhclient_config(self, - AF_INET6, - nm_dhcp_client_get_iface(client), - nm_dhcp_client_get_uuid(client), - NULL, - dhcp_anycast_addr, - nm_dhcp_client_get_hostname(client), - nm_dhcp_client_get_timeout(client), - TRUE, - nm_dhcp_client_get_hostname_flags(client), - nm_dhcp_client_get_mud_url(client), - NULL, - NULL); - if (!priv->conf_file) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_UNKNOWN, - "error creating dhclient configuration file"); - return FALSE; - } - - return dhclient_start(client, - nm_dhcp_client_get_info_only(NM_DHCP_CLIENT(self)) ? "-S" : "-N", - FALSE, - NULL, - needed_prefixes, - error); -} - -static void -stop(NMDhcpClient *client, gboolean release) -{ - NMDhcpDhclient * self = NM_DHCP_DHCLIENT(client); - NMDhcpDhclientPrivate *priv = NM_DHCP_DHCLIENT_GET_PRIVATE(self); - int errsv; - - NM_DHCP_CLIENT_CLASS(nm_dhcp_dhclient_parent_class)->stop(client, release); - - if (priv->conf_file) - if (remove(priv->conf_file) == -1) { - errsv = errno; - _LOGD("could not remove dhcp config file \"%s\": %d (%s)", - priv->conf_file, - errsv, - nm_strerror_native(errsv)); - } - if (priv->pid_file) { - if (remove(priv->pid_file) == -1) { - errsv = errno; - _LOGD("could not remove dhcp pid file \"%s\": %s (%d)", - priv->pid_file, - nm_strerror_native(errsv), - errsv); - } - nm_clear_g_free(&priv->pid_file); - } - - if (release) { - pid_t rpid = -1; - - if (dhclient_start(client, NULL, TRUE, &rpid, 0, NULL)) { - /* Wait a few seconds for the release to happen */ - nm_dhcp_client_stop_pid(rpid, nm_dhcp_client_get_iface(client)); - } - } -} - -static GBytes * -get_duid(NMDhcpClient *client) -{ - NMDhcpDhclient * self = NM_DHCP_DHCLIENT(client); - NMDhcpDhclientPrivate *priv = NM_DHCP_DHCLIENT_GET_PRIVATE(self); - GBytes * duid = NULL; - gs_free char * leasefile = NULL; - GError * error = NULL; - - /* Look in interface-specific leasefile first for backwards compat */ - leasefile = get_dhclient_leasefile(AF_INET6, - nm_dhcp_client_get_iface(client), - nm_dhcp_client_get_uuid(client), - NULL); - if (leasefile) { - _LOGD("looking for DUID in '%s'", leasefile); - duid = nm_dhcp_dhclient_read_duid(leasefile, &error); - if (error) { - _LOGW("failed to read leasefile '%s': %s", leasefile, error->message); - g_clear_error(&error); - } - if (duid) - return duid; - } - - /* Otherwise, read the default machine-wide DUID */ - _LOGD("looking for default DUID in '%s'", priv->def_leasefile); - duid = nm_dhcp_dhclient_read_duid(priv->def_leasefile, &error); - if (error) { - _LOGW("failed to read leasefile '%s': %s", priv->def_leasefile, error->message); - g_clear_error(&error); - } - - return duid; -} - -/*****************************************************************************/ - -static void -nm_dhcp_dhclient_init(NMDhcpDhclient *self) -{ - static const char *const FILES[] = { - SYSCONFDIR "/dhclient6.leases", /* default */ - LOCALSTATEDIR "/lib/dhcp/dhclient6.leases", - LOCALSTATEDIR "/lib/dhclient/dhclient6.leases", - }; - NMDhcpDhclientPrivate *priv = NM_DHCP_DHCLIENT_GET_PRIVATE(self); - int i; - - priv->def_leasefile = FILES[0]; - for (i = 0; i < G_N_ELEMENTS(FILES); i++) { - if (g_file_test(FILES[i], G_FILE_TEST_EXISTS)) { - priv->def_leasefile = FILES[i]; - break; - } - } - - 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) -{ - NMDhcpDhclientPrivate *priv = NM_DHCP_DHCLIENT_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_DHCLIENT(object)); - g_clear_object(&priv->dhcp_listener); - } - - nm_clear_g_free(&priv->pid_file); - nm_clear_g_free(&priv->conf_file); - nm_clear_g_free(&priv->lease_file); - - G_OBJECT_CLASS(nm_dhcp_dhclient_parent_class)->dispose(object); -} - -static void -nm_dhcp_dhclient_class_init(NMDhcpDhclientClass *dhclient_class) -{ - NMDhcpClientClass *client_class = NM_DHCP_CLIENT_CLASS(dhclient_class); - GObjectClass * object_class = G_OBJECT_CLASS(dhclient_class); - - object_class->dispose = dispose; - - client_class->ip4_start = ip4_start; - client_class->ip6_start = ip6_start; - client_class->stop = stop; - client_class->get_duid = get_duid; -} - -const NMDhcpClientFactory _nm_dhcp_client_factory_dhclient = { - .name = "dhclient", - .get_type = nm_dhcp_dhclient_get_type, - .get_path = nm_dhcp_dhclient_get_path, -}; - -#endif /* WITH_DHCLIENT */ diff --git a/src/dhcp/nm-dhcp-dhcpcanon.c b/src/dhcp/nm-dhcp-dhcpcanon.c deleted file mode 100644 index 8e61b6e5..00000000 --- a/src/dhcp/nm-dhcp-dhcpcanon.c +++ /dev/null @@ -1,243 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2017 juga <juga at riseup dot net> - */ - -#include "nm-default.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 */ diff --git a/src/dhcp/nm-dhcp-dhcpcd.c b/src/dhcp/nm-dhcp-dhcpcd.c deleted file mode 100644 index b2b5d28b..00000000 --- a/src/dhcp/nm-dhcp-dhcpcd.c +++ /dev/null @@ -1,240 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2008 Roy Marples - * Copyright (C) 2010 Dan Williams <dcbw@redhat.com> - */ - -#include "nm-default.h" - -#if WITH_DHCPCD - - #include <stdlib.h> - #include <unistd.h> - #include <stdio.h> - #include <netinet/in.h> - #include <arpa/inet.h> - - #include "nm-dhcp-manager.h" - #include "nm-utils.h" - #include "NetworkManagerUtils.h" - #include "nm-dhcp-listener.h" - #include "nm-dhcp-client-logging.h" - -/*****************************************************************************/ - - #define NM_TYPE_DHCP_DHCPCD (nm_dhcp_dhcpcd_get_type()) - #define NM_DHCP_DHCPCD(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DHCP_DHCPCD, NMDhcpDhcpcd)) - #define NM_DHCP_DHCPCD_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DHCP_DHCPCD, NMDhcpDhcpcdClass)) - #define NM_IS_DHCP_DHCPCD(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DHCP_DHCPCD)) - #define NM_IS_DHCP_DHCPCD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_DHCP_DHCPCD)) - #define NM_DHCP_DHCPCD_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_DHCP_DHCPCD, NMDhcpDhcpcdClass)) - -typedef struct _NMDhcpDhcpcd NMDhcpDhcpcd; -typedef struct _NMDhcpDhcpcdClass NMDhcpDhcpcdClass; - -static GType nm_dhcp_dhcpcd_get_type(void); - -/*****************************************************************************/ - -typedef struct { - char * pid_file; - NMDhcpListener *dhcp_listener; -} NMDhcpDhcpcdPrivate; - -struct _NMDhcpDhcpcd { - NMDhcpClient parent; - NMDhcpDhcpcdPrivate _priv; -}; - -struct _NMDhcpDhcpcdClass { - NMDhcpClientClass parent; -}; - -G_DEFINE_TYPE(NMDhcpDhcpcd, nm_dhcp_dhcpcd, NM_TYPE_DHCP_CLIENT) - - #define NM_DHCP_DHCPCD_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMDhcpDhcpcd, NM_IS_DHCP_DHCPCD) - -/*****************************************************************************/ - -static const char * -nm_dhcp_dhcpcd_get_path(void) -{ - return nm_utils_find_helper("dhcpcd", DHCPCD_PATH, NULL); -} - -static gboolean -ip4_start(NMDhcpClient *client, - const char * dhcp_anycast_addr, - const char * last_ip4_address, - GError ** error) -{ - NMDhcpDhcpcd * self = NM_DHCP_DHCPCD(client); - NMDhcpDhcpcdPrivate *priv = NM_DHCP_DHCPCD_GET_PRIVATE(self); - gs_unref_ptrarray GPtrArray *argv = NULL; - pid_t pid = -1; - GError * local = NULL; - gs_free char * cmd_str = NULL; - gs_free char * binary_name = NULL; - const char * iface; - const char * dhcpcd_path; - const char * hostname; - - g_return_val_if_fail(priv->pid_file == NULL, FALSE); - - iface = nm_dhcp_client_get_iface(client); - - /* dhcpcd does not allow custom pidfiles; the pidfile is always - * RUNSTATEDIR "dhcpcd-<ifname>.pid". - */ - priv->pid_file = g_strdup_printf(RUNSTATEDIR "/dhcpcd-%s.pid", iface); - - dhcpcd_path = nm_dhcp_dhcpcd_get_path(); - if (!dhcpcd_path) { - nm_utils_error_set_literal(error, NM_UTILS_ERROR_UNKNOWN, "dhcpcd binary not found"); - return FALSE; - } - - /* Kill any existing dhcpcd from the pidfile */ - binary_name = g_path_get_basename(dhcpcd_path); - nm_dhcp_client_stop_existing(priv->pid_file, binary_name); - - argv = g_ptr_array_new(); - g_ptr_array_add(argv, (gpointer) dhcpcd_path); - - g_ptr_array_add(argv, (gpointer) "-B"); /* Don't background on lease (disable fork()) */ - - g_ptr_array_add(argv, (gpointer) "-K"); /* Disable built-in carrier detection */ - - g_ptr_array_add(argv, (gpointer) "-L"); /* Disable built-in IPv4LL */ - - /* --noarp. Don't request or claim the address by ARP; this also disables IPv4LL. */ - g_ptr_array_add(argv, (gpointer) "-A"); - - g_ptr_array_add(argv, (gpointer) "-G"); /* Let NM handle routing */ - - g_ptr_array_add(argv, (gpointer) "-c"); /* Set script file */ - g_ptr_array_add(argv, (gpointer) nm_dhcp_helper_path); - - /* IPv4-only for now. NetworkManager knows better than dhcpcd when to - * run IPv6, and dhcpcd's automatic Router Solicitations cause problems - * with devices that don't expect them. - */ - g_ptr_array_add(argv, (gpointer) "-4"); - - hostname = nm_dhcp_client_get_hostname(client); - - if (hostname) { - if (nm_dhcp_client_get_use_fqdn(client)) { - g_ptr_array_add(argv, (gpointer) "-h"); - g_ptr_array_add(argv, (gpointer) hostname); - g_ptr_array_add(argv, (gpointer) "-F"); - g_ptr_array_add(argv, (gpointer) "both"); - } else { - g_ptr_array_add(argv, (gpointer) "-h"); - g_ptr_array_add(argv, (gpointer) hostname); - } - } - - g_ptr_array_add(argv, (gpointer) iface); - g_ptr_array_add(argv, NULL); - - _LOGD("running: %s", (cmd_str = g_strjoinv(" ", (char **) argv->pdata))); - - 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, - "dhcpcd failed to start: %s", - local->message); - g_error_free(local); - return FALSE; - } - - nm_assert(pid > 0); - _LOGI("dhcpcd started with pid %d", pid); - nm_dhcp_client_watch_child(client, pid); - return TRUE; -} - -static void -stop(NMDhcpClient *client, gboolean release) -{ - NMDhcpDhcpcd * self = NM_DHCP_DHCPCD(client); - NMDhcpDhcpcdPrivate *priv = NM_DHCP_DHCPCD_GET_PRIVATE(self); - int errsv; - - NM_DHCP_CLIENT_CLASS(nm_dhcp_dhcpcd_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)); - } - } - - /* FIXME: implement release... */ -} - -/*****************************************************************************/ - -static void -nm_dhcp_dhcpcd_init(NMDhcpDhcpcd *self) -{ - NMDhcpDhcpcdPrivate *priv = NM_DHCP_DHCPCD_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) -{ - NMDhcpDhcpcdPrivate *priv = NM_DHCP_DHCPCD_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_DHCPCD(object)); - g_clear_object(&priv->dhcp_listener); - } - - nm_clear_g_free(&priv->pid_file); - - G_OBJECT_CLASS(nm_dhcp_dhcpcd_parent_class)->dispose(object); -} - -static void -nm_dhcp_dhcpcd_class_init(NMDhcpDhcpcdClass *dhcpcd_class) -{ - NMDhcpClientClass *client_class = NM_DHCP_CLIENT_CLASS(dhcpcd_class); - GObjectClass * object_class = G_OBJECT_CLASS(dhcpcd_class); - - object_class->dispose = dispose; - - client_class->ip4_start = ip4_start; - client_class->stop = stop; -} - -const NMDhcpClientFactory _nm_dhcp_client_factory_dhcpcd = { - .name = "dhcpcd", - .get_type = nm_dhcp_dhcpcd_get_type, - .get_path = nm_dhcp_dhcpcd_get_path, -}; - -#endif /* WITH_DHCPCD */ diff --git a/src/dhcp/nm-dhcp-helper-api.h b/src/dhcp/nm-dhcp-helper-api.h deleted file mode 100644 index aa1d203a..00000000 --- a/src/dhcp/nm-dhcp-helper-api.h +++ /dev/null @@ -1,20 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ -/* - * Copyright (C) 2016 Red Hat, Inc. - */ - -#ifndef __NM_DHCP_HELPER_API_H__ -#define __NM_DHCP_HELPER_API_H__ - -/*****************************************************************************/ - -#define NM_DHCP_CLIENT_DBUS_IFACE "org.freedesktop.nm_dhcp_client" - -#define NM_DHCP_HELPER_SERVER_BUS_NAME "org.freedesktop.nm_dhcp_server" -#define NM_DHCP_HELPER_SERVER_OBJECT_PATH "/org/freedesktop/nm_dhcp_server" -#define NM_DHCP_HELPER_SERVER_INTERFACE_NAME "org.freedesktop.nm_dhcp_server" -#define NM_DHCP_HELPER_SERVER_METHOD_NOTIFY "Notify" - -/*****************************************************************************/ - -#endif /* __NM_DHCP_HELPER_API_H__ */ diff --git a/src/dhcp/nm-dhcp-helper.c b/src/dhcp/nm-dhcp-helper.c deleted file mode 100644 index 84fa859d..00000000 --- a/src/dhcp/nm-dhcp-helper.c +++ /dev/null @@ -1,242 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2007 - 2013 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include <unistd.h> -#include <stdlib.h> -#include <signal.h> - -#include "nm-utils/nm-vpn-plugin-macros.h" - -#include "nm-dhcp-helper-api.h" - -/*****************************************************************************/ - -#if NM_MORE_LOGGING - #define _NMLOG_ENABLED(level) TRUE -#else - #define _NMLOG_ENABLED(level) ((level) <= LOG_ERR) -#endif - -#define _NMLOG(always_enabled, level, ...) \ - G_STMT_START \ - { \ - if ((always_enabled) || _NMLOG_ENABLED(level)) { \ - GTimeVal _tv; \ - \ - g_get_current_time(&_tv); \ - g_print( \ - "nm-dhcp-helper[%ld] %-7s [%ld.%04ld] " _NM_UTILS_MACRO_FIRST(__VA_ARGS__) "\n", \ - (long) getpid(), \ - nm_utils_syslog_to_str(level), \ - _tv.tv_sec, \ - _tv.tv_usec / 100 _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ - } \ - } \ - G_STMT_END - -#define _LOGD(...) _NMLOG(TRUE, LOG_INFO, __VA_ARGS__) -#define _LOGI(...) _NMLOG(TRUE, LOG_NOTICE, __VA_ARGS__) -#define _LOGW(...) _NMLOG(TRUE, LOG_WARNING, __VA_ARGS__) -#define _LOGE(...) _NMLOG(TRUE, LOG_ERR, __VA_ARGS__) - -#define _LOGd(...) _NMLOG(FALSE, LOG_INFO, __VA_ARGS__) -#define _LOGi(...) _NMLOG(FALSE, LOG_NOTICE, __VA_ARGS__) -#define _LOGw(...) _NMLOG(FALSE, LOG_WARNING, __VA_ARGS__) - -/*****************************************************************************/ - -static GVariant * -build_signal_parameters(void) -{ - const char *const *environ_iter; - GVariantBuilder builder; - - g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT); - - /* List environment and format for dbus dict */ - for (environ_iter = (const char *const *) environ; *environ_iter; environ_iter++) { - static const char *const ignore_with_prefix_list[] = - {"PATH", "SHLVL", "_", "PWD", "dhc_dbus", NULL}; - const char * item = *environ_iter; - gs_free char * name = NULL; - const char * val; - const char *const *p; - - val = strchr(item, '='); - if (!val || item == val) - continue; - - name = g_strndup(item, val - item); - val += 1; - - /* Ignore non-DHCP-related environment variables */ - for (p = ignore_with_prefix_list; *p; p++) { - if (strncmp(name, *p, strlen(*p)) == 0) - goto next; - } - - if (!g_utf8_validate(name, -1, NULL)) - continue; - - /* Value passed as a byte array rather than a string, because there are - * no character encoding guarantees with DHCP, and D-Bus requires - * strings to be UTF-8. - * - * Note that we can't use g_variant_new_bytestring() here, because that - * includes the trailing '\0'. (??!?) - */ - g_variant_builder_add(&builder, - "{sv}", - name, - g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, val, strlen(val), 1)); - -next:; - } - - return g_variant_ref_sink(g_variant_new("(a{sv})", &builder)); -} - -static void -kill_pid(void) -{ - const char *pid_str; - pid_t pid = 0; - - pid_str = getenv("pid"); - if (pid_str) - pid = strtol(pid_str, NULL, 10); - if (pid) { - _LOGI("a fatal error occurred, kill dhclient instance with pid %d", pid); - kill(pid, SIGTERM); - } -} - -int -main(int argc, char *argv[]) -{ - gs_unref_object GDBusConnection *connection = NULL; - gs_free_error GError *error = NULL; - gs_unref_variant GVariant *parameters = NULL; - gs_unref_variant GVariant *result = NULL; - gboolean success = FALSE; - guint try_count; - gint64 time_start; - gint64 time_end; - - /* Connecting to the unix socket can fail with EAGAIN if there are too - * many pending connections and the server can't accept them in time - * before reaching backlog capacity. Ideally the server should increase - * the backlog length, but GLib doesn't provide a way to change it for a - * GDBus server. Retry for up to 5 seconds in case of failure. */ - time_start = g_get_monotonic_time(); - time_end = time_start + (5000 * 1000L); - try_count = 0; - -do_connect: - try_count++; - connection = - g_dbus_connection_new_for_address_sync("unix:path=" NMRUNDIR "/private-dhcp", - G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT, - NULL, - NULL, - &error); - if (!connection) { - if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) { - gint64 time_remaining = time_end - g_get_monotonic_time(); - gint64 interval; - - if (time_remaining > 0) { - _LOGi("failure to connect: %s (retry %u, waited %lld ms)", - error->message, - try_count, - (long long) (time_end - time_remaining - time_start) / 1000); - interval = NM_CLAMP((gint64)(100L * (1L << NM_MIN(try_count, 31))), 5000, 100000); - g_usleep(NM_MIN(interval, time_remaining)); - g_clear_error(&error); - goto do_connect; - } - } - - g_dbus_error_strip_remote_error(error); - _LOGE("could not connect to NetworkManager D-Bus socket: %s", error->message); - goto out; - } - - parameters = build_signal_parameters(); - time_end = g_get_monotonic_time() + (200 * 1000L); /* retry for at most 200 milliseconds */ - try_count = 0; - -do_notify: - try_count++; - result = g_dbus_connection_call_sync(connection, - NULL, - NM_DHCP_HELPER_SERVER_OBJECT_PATH, - NM_DHCP_HELPER_SERVER_INTERFACE_NAME, - NM_DHCP_HELPER_SERVER_METHOD_NOTIFY, - parameters, - NULL, - G_DBUS_CALL_FLAGS_NONE, - 1000, - NULL, - &error); - - if (!result) { - gs_free char *s_err = NULL; - - s_err = g_dbus_error_get_remote_error(error); - if (NM_IN_STRSET(s_err, "org.freedesktop.DBus.Error.UnknownMethod")) { - gint64 remaining_time = time_end - g_get_monotonic_time(); - gint64 interval; - - /* I am not sure that a race can actually happen, as we register the object - * on the server side during GDBusServer:new-connection signal. - * - * However, there was also a race for subscribing to an event, so let's just - * do some retry. */ - if (remaining_time > 0) { - _LOGi("failure to call notify: %s (retry %u)", error->message, try_count); - interval = NM_CLAMP((gint64)(100L * (1L << NM_MIN(try_count, 31))), 5000, 25000); - g_usleep(NM_MIN(interval, remaining_time)); - g_clear_error(&error); - goto do_notify; - } - } - _LOGW("failure to call notify: %s (try signal via Event)", error->message); - g_clear_error(&error); - - /* for backward compatibility, try to emit the signal. There is no stable - * API between the dhcp-helper and NetworkManager. However, while upgrading - * the NetworkManager package, a newer helper might want to notify an - * older server, which still uses the "Event". */ - if (!g_dbus_connection_emit_signal(connection, - NULL, - "/", - NM_DHCP_CLIENT_DBUS_IFACE, - "Event", - parameters, - &error)) { - g_dbus_error_strip_remote_error(error); - _LOGE("could not send DHCP Event signal: %s", error->message); - goto out; - } - /* We were able to send the asynchronous Event. Consider that a success. */ - success = TRUE; - } else - success = TRUE; - - if (!g_dbus_connection_flush_sync(connection, NULL, &error)) { - g_dbus_error_strip_remote_error(error); - _LOGE("could not flush D-Bus connection: %s", error->message); - success = FALSE; - goto out; - } - -out: - if (!success) - kill_pid(); - return success ? EXIT_SUCCESS : EXIT_FAILURE; -} diff --git a/src/dhcp/nm-dhcp-listener.c b/src/dhcp/nm-dhcp-listener.c deleted file mode 100644 index c90590d5..00000000 --- a/src/dhcp/nm-dhcp-listener.c +++ /dev/null @@ -1,318 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2014 - 2016 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include "nm-dhcp-listener.h" - -#include <sys/socket.h> -#include <sys/wait.h> -#include <signal.h> -#include <stdlib.h> -#include <unistd.h> - -#include "nm-dhcp-helper-api.h" -#include "nm-dhcp-client.h" -#include "nm-dhcp-manager.h" -#include "nm-core-internal.h" -#include "nm-dbus-manager.h" -#include "NetworkManagerUtils.h" - -#define PRIV_SOCK_PATH NMRUNDIR "/private-dhcp" -#define PRIV_SOCK_TAG "dhcp" - -/*****************************************************************************/ - -const NMDhcpClientFactory *const _nm_dhcp_manager_factories[6] = { -/* the order here matters, as we will try the plugins in this order to find - * the first available plugin. */ - -#if WITH_DHCPCANON - &_nm_dhcp_client_factory_dhcpcanon, -#endif -#if WITH_DHCLIENT - &_nm_dhcp_client_factory_dhclient, -#endif -#if WITH_DHCPCD - &_nm_dhcp_client_factory_dhcpcd, -#endif - &_nm_dhcp_client_factory_internal, - &_nm_dhcp_client_factory_systemd, - &_nm_dhcp_client_factory_nettools, -}; - -/*****************************************************************************/ - -typedef struct { - NMDBusManager *dbus_mgr; - gulong new_conn_id; - gulong dis_conn_id; - GHashTable * connections; -} NMDhcpListenerPrivate; - -struct _NMDhcpListener { - GObject parent; - NMDhcpListenerPrivate _priv; -}; - -struct _NMDhcpListenerClass { - GObjectClass parent; -}; - -enum { EVENT, LAST_SIGNAL }; -static guint signals[LAST_SIGNAL] = {0}; - -G_DEFINE_TYPE(NMDhcpListener, nm_dhcp_listener, G_TYPE_OBJECT) - -#define NM_DHCP_LISTENER_GET_PRIVATE(self) \ - _NM_GET_PRIVATE(self, NMDhcpListener, NM_IS_DHCP_LISTENER) - -NM_DEFINE_SINGLETON_GETTER(NMDhcpListener, nm_dhcp_listener_get, NM_TYPE_DHCP_LISTENER); - -/*****************************************************************************/ - -#define _NMLOG_PREFIX_NAME "dhcp-listener" -#define _NMLOG_DOMAIN LOGD_DHCP -#define _NMLOG(level, ...) \ - G_STMT_START \ - { \ - const NMDhcpListener *_self = (self); \ - char _prefix[64]; \ - \ - nm_log((level), \ - (_NMLOG_DOMAIN), \ - NULL, \ - NULL, \ - "%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ - (_self != singleton_instance \ - ? nm_sprintf_buf(_prefix, "%s[%p]", _NMLOG_PREFIX_NAME, _self) \ - : _NMLOG_PREFIX_NAME) _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ - } \ - G_STMT_END - -/*****************************************************************************/ - -static char * -get_option(GVariant *options, const char *key) -{ - GVariant * value; - const guchar *bytes, *s; - gsize len; - char * converted, *d; - - if (!g_variant_lookup(options, key, "@ay", &value)) - return NULL; - - bytes = g_variant_get_fixed_array(value, &len, 1); - - /* Since the DHCP options come through environment variables, they should - * already be UTF-8 safe, but just make sure. - */ - converted = g_malloc(len + 1); - for (s = bytes, d = converted; s < bytes + len; s++, d++) { - /* Convert NULLs to spaces and non-ASCII characters to ? */ - if (*s == '\0') - *d = ' '; - else if (*s > 127) - *d = '?'; - else - *d = *s; - } - *d = '\0'; - g_variant_unref(value); - - return converted; -} - -static void -_method_call_handle(NMDhcpListener *self, GVariant *parameters) -{ - gs_free char * iface = NULL; - gs_free char * pid_str = NULL; - gs_free char * reason = NULL; - gs_unref_variant GVariant *options = NULL; - int pid; - gboolean handled = FALSE; - - g_variant_get(parameters, "(@a{sv})", &options); - - iface = get_option(options, "interface"); - if (iface == NULL) { - _LOGW("dhcp-event: didn't have associated interface."); - return; - } - - pid_str = get_option(options, "pid"); - pid = _nm_utils_ascii_str_to_int64(pid_str, 10, 0, G_MAXINT32, -1); - if (pid == -1) { - _LOGW("dhcp-event: couldn't convert PID '%s' to an integer", pid_str ?: "(null)"); - return; - } - - reason = get_option(options, "reason"); - if (reason == NULL) { - _LOGW("dhcp-event: (pid %d) DHCP event didn't have a reason", pid); - return; - } - - g_signal_emit(self, signals[EVENT], 0, iface, pid, options, reason, &handled); - if (!handled) { - if (g_ascii_strcasecmp(reason, "RELEASE") == 0) { - /* Ignore event when the dhcp client gets killed and we receive its last message */ - _LOGD("dhcp-event: (pid %d) unhandled RELEASE DHCP event for interface %s", pid, iface); - } else - _LOGW("dhcp-event: (pid %d) unhandled DHCP event for interface %s", pid, iface); - } -} - -static void -_method_call(GDBusConnection * connection, - const char * sender, - const char * object_path, - const char * interface_name, - const char * method_name, - GVariant * parameters, - GDBusMethodInvocation *invocation, - gpointer user_data) -{ - NMDhcpListener *self = NM_DHCP_LISTENER(user_data); - - if (!nm_streq(interface_name, NM_DHCP_HELPER_SERVER_INTERFACE_NAME) - || !nm_streq(method_name, NM_DHCP_HELPER_SERVER_METHOD_NOTIFY)) { - g_dbus_method_invocation_return_error(invocation, - G_DBUS_ERROR, - G_DBUS_ERROR_UNKNOWN_METHOD, - "Unknown method %s", - method_name); - return; - } - - _method_call_handle(self, parameters); - g_dbus_method_invocation_return_value(invocation, NULL); -} - -static GDBusInterfaceInfo *const interface_info = NM_DEFINE_GDBUS_INTERFACE_INFO( - NM_DHCP_HELPER_SERVER_INTERFACE_NAME, - .methods = NM_DEFINE_GDBUS_METHOD_INFOS( - NM_DEFINE_GDBUS_METHOD_INFO(NM_DHCP_HELPER_SERVER_METHOD_NOTIFY, - .in_args = NM_DEFINE_GDBUS_ARG_INFOS( - NM_DEFINE_GDBUS_ARG_INFO("data", "a{sv}"), ), ), ), ); - -static guint -_dbus_connection_register_object(NMDhcpListener *self, GDBusConnection *connection, GError **error) -{ - static const GDBusInterfaceVTable interface_vtable = { - .method_call = _method_call, - }; - - return g_dbus_connection_register_object( - connection, - NM_DHCP_HELPER_SERVER_OBJECT_PATH, - interface_info, - NM_UNCONST_PTR(GDBusInterfaceVTable, &interface_vtable), - self, - NULL, - error); -} - -static void -new_connection_cb(NMDBusManager * mgr, - GDBusConnection * connection, - GDBusObjectManager *manager, - NMDhcpListener * self) -{ - NMDhcpListenerPrivate *priv = NM_DHCP_LISTENER_GET_PRIVATE(self); - guint registration_id; - GError * error = NULL; - - /* it is important to register the object during the new-connection signal, - * as this avoids races with the connecting object. */ - registration_id = _dbus_connection_register_object(self, connection, &error); - if (!registration_id) { - _LOGE("failure to register %s for connection %p: %s", - NM_DHCP_HELPER_SERVER_OBJECT_PATH, - connection, - error->message); - g_error_free(error); - return; - } - - g_hash_table_insert(priv->connections, connection, GUINT_TO_POINTER(registration_id)); -} - -static void -dis_connection_cb(NMDBusManager *mgr, GDBusConnection *connection, NMDhcpListener *self) -{ - NMDhcpListenerPrivate *priv = NM_DHCP_LISTENER_GET_PRIVATE(self); - guint id; - - id = GPOINTER_TO_UINT(g_hash_table_lookup(priv->connections, connection)); - if (id) { - g_dbus_connection_unregister_object(connection, id); - g_hash_table_remove(priv->connections, connection); - } -} - -/*****************************************************************************/ - -static void -nm_dhcp_listener_init(NMDhcpListener *self) -{ - NMDhcpListenerPrivate *priv = NM_DHCP_LISTENER_GET_PRIVATE(self); - - /* Maps GDBusConnection :: signal-id */ - priv->connections = g_hash_table_new(nm_direct_hash, NULL); - - priv->dbus_mgr = g_object_ref(nm_dbus_manager_get()); - - /* Register the socket our DHCP clients will return lease info on */ - nm_dbus_manager_private_server_register(priv->dbus_mgr, PRIV_SOCK_PATH, PRIV_SOCK_TAG); - priv->new_conn_id = g_signal_connect(priv->dbus_mgr, - NM_DBUS_MANAGER_PRIVATE_CONNECTION_NEW "::" PRIV_SOCK_TAG, - G_CALLBACK(new_connection_cb), - self); - priv->dis_conn_id = - g_signal_connect(priv->dbus_mgr, - NM_DBUS_MANAGER_PRIVATE_CONNECTION_DISCONNECTED "::" PRIV_SOCK_TAG, - G_CALLBACK(dis_connection_cb), - self); -} - -static void -dispose(GObject *object) -{ - NMDhcpListenerPrivate *priv = NM_DHCP_LISTENER_GET_PRIVATE(object); - - nm_clear_g_signal_handler(priv->dbus_mgr, &priv->new_conn_id); - nm_clear_g_signal_handler(priv->dbus_mgr, &priv->dis_conn_id); - - nm_clear_pointer(&priv->connections, g_hash_table_destroy); - - g_clear_object(&priv->dbus_mgr); - - G_OBJECT_CLASS(nm_dhcp_listener_parent_class)->dispose(object); -} - -static void -nm_dhcp_listener_class_init(NMDhcpListenerClass *listener_class) -{ - GObjectClass *object_class = G_OBJECT_CLASS(listener_class); - - object_class->dispose = dispose; - - signals[EVENT] = g_signal_new(NM_DHCP_LISTENER_EVENT, - G_OBJECT_CLASS_TYPE(object_class), - G_SIGNAL_RUN_LAST, - 0, - g_signal_accumulator_true_handled, - NULL, - NULL, - G_TYPE_BOOLEAN, /* listeners return TRUE if handled */ - 4, - G_TYPE_STRING, /* iface */ - G_TYPE_INT, /* pid */ - G_TYPE_VARIANT, /* options */ - G_TYPE_STRING); /* reason */ -} diff --git a/src/dhcp/nm-dhcp-listener.h b/src/dhcp/nm-dhcp-listener.h deleted file mode 100644 index 57d3b0fc..00000000 --- a/src/dhcp/nm-dhcp-listener.h +++ /dev/null @@ -1,25 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2014 Red Hat, Inc. - */ - -#ifndef __NETWORKMANAGER_DHCP_LISTENER_H__ -#define __NETWORKMANAGER_DHCP_LISTENER_H__ - -#define NM_TYPE_DHCP_LISTENER (nm_dhcp_listener_get_type()) -#define NM_DHCP_LISTENER(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DHCP_LISTENER, NMDhcpListener)) -#define NM_IS_DHCP_LISTENER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DHCP_LISTENER)) -#define NM_DHCP_LISTENER_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_DHCP_LISTENER, NMDhcpListenerClass)) - -#define NM_DHCP_LISTENER_EVENT "event" - -typedef struct _NMDhcpListener NMDhcpListener; -typedef struct _NMDhcpListenerClass NMDhcpListenerClass; - -GType nm_dhcp_listener_get_type(void); - -NMDhcpListener *nm_dhcp_listener_get(void); - -#endif /* __NETWORKMANAGER_DHCP_LISTENER_H__ */ diff --git a/src/dhcp/nm-dhcp-manager.c b/src/dhcp/nm-dhcp-manager.c deleted file mode 100644 index 665944d7..00000000 --- a/src/dhcp/nm-dhcp-manager.c +++ /dev/null @@ -1,682 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2005 - 2013 Red Hat, Inc. - * Copyright (C) 2006 - 2008 Novell, Inc. - */ - -#include "nm-default.h" - -#include "nm-dhcp-manager.h" - -#include <sys/socket.h> -#include <sys/wait.h> -#include <signal.h> -#include <stdlib.h> -#include <unistd.h> -#include <fcntl.h> -#include <stdio.h> - -#include "nm-glib-aux/nm-dedup-multi.h" -#include "systemd/nm-sd-utils-shared.h" - -#include "nm-config.h" -#include "NetworkManagerUtils.h" - -/*****************************************************************************/ - -typedef struct { - const NMDhcpClientFactory *client_factory; - char * default_hostname; - CList dhcp_client_lst_head; -} NMDhcpManagerPrivate; - -struct _NMDhcpManager { - GObject parent; - NMDhcpManagerPrivate _priv; -}; - -struct _NMDhcpManagerClass { - GObjectClass parent; -}; - -G_DEFINE_TYPE(NMDhcpManager, nm_dhcp_manager, G_TYPE_OBJECT) - -#define NM_DHCP_MANAGER_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMDhcpManager, NM_IS_DHCP_MANAGER) - -/*****************************************************************************/ - -static void client_state_changed(NMDhcpClient * client, - NMDhcpState state, - GObject * ip_config, - GVariant * options, - NMDhcpManager *self); - -/*****************************************************************************/ - -/* default to installed helper, but can be modified for testing */ -const char *nm_dhcp_helper_path = LIBEXECDIR "/nm-dhcp-helper"; - -/*****************************************************************************/ - -static const NMDhcpClientFactory * -_client_factory_find_by_name(const char *name) -{ - int i; - - g_return_val_if_fail(name, NULL); - - for (i = 0; i < G_N_ELEMENTS(_nm_dhcp_manager_factories); i++) { - const NMDhcpClientFactory *f = _nm_dhcp_manager_factories[i]; - - if (f && nm_streq(f->name, name)) - return f; - } - return NULL; -} - -static const NMDhcpClientFactory * -_client_factory_available(const NMDhcpClientFactory *client_factory) -{ - if (client_factory && (!client_factory->get_path || client_factory->get_path())) - return client_factory; - return NULL; -} - -static GType -_client_factory_get_gtype(const NMDhcpClientFactory *client_factory, int addr_family) -{ - GType gtype; - nm_auto_unref_gtypeclass NMDhcpClientClass *klass = NULL; - - nm_assert(client_factory); - nm_assert_addr_family(addr_family); - - /* currently, the chosen DHCP plugin for IPv4 and IPv6 is configured in NetworkManager.conf - * and cannot be reloaded. It would be nice to configure the plugin per address family - * or to be able to reload it. - * - * Note that certain options in NetworkManager.conf depend on the chosen DHCP plugin. - * See "dhcp-plugin:" in "Device List Format" (`man NetworkManager.conf`). - * Supporting reloading the plugin would also require to re-evalate the decisions from - * the "Device List Format". Likewise, having per-address family plugins would make the - * "main.dhcp" setting and "dhcp-plugin:" match non-sensical because these configurations - * currently are address family independent. - * - * So actually, we don't want that complexity. We want to phase out all plugins in favor - * of the internal plugin. - * However, certain existing plugins are well known to not support an address family. - * In those cases, we should just silently fallback to the internal plugin. - * - * This could be a problem with forward compatibility if we ever intended to add IPv6 support - * to those plugins. But we don't intend to do so. The internal plugin is the way forward and - * not extending other plugins. */ - - if (client_factory->get_type_per_addr_family) - gtype = client_factory->get_type_per_addr_family(addr_family); - else - gtype = client_factory->get_type(); - - if (client_factory == &_nm_dhcp_client_factory_internal) { - /* we are already using the internal plugin. Nothing to do. */ - goto out; - } - - klass = g_type_class_ref(gtype); - - nm_assert(NM_IS_DHCP_CLIENT_CLASS(klass)); - - if (addr_family == AF_INET6) { - if (!klass->ip6_start) - gtype = _client_factory_get_gtype(&_nm_dhcp_client_factory_internal, addr_family); - } else { - if (!klass->ip4_start) - gtype = _client_factory_get_gtype(&_nm_dhcp_client_factory_internal, addr_family); - } - -out: - nm_assert(g_type_is_a(gtype, NM_TYPE_DHCP_CLIENT)); - nm_assert(({ - nm_auto_unref_gtypeclass NMDhcpClientClass *k = g_type_class_ref(gtype); - - (addr_family == AF_INET6 && k->ip6_start) || (addr_family == AF_INET && k->ip4_start); - })); - - return gtype; -} - -/*****************************************************************************/ - -static NMDhcpClient * -get_client_for_ifindex(NMDhcpManager *manager, int addr_family, int ifindex) -{ - NMDhcpManagerPrivate *priv; - NMDhcpClient * client; - - g_return_val_if_fail(NM_IS_DHCP_MANAGER(manager), NULL); - g_return_val_if_fail(ifindex > 0, NULL); - - priv = NM_DHCP_MANAGER_GET_PRIVATE(manager); - - c_list_for_each_entry (client, &priv->dhcp_client_lst_head, dhcp_client_lst) { - if (nm_dhcp_client_get_ifindex(client) == ifindex - && nm_dhcp_client_get_addr_family(client) == addr_family) - return client; - } - - return NULL; -} - -static void -remove_client(NMDhcpManager *self, NMDhcpClient *client) -{ - g_signal_handlers_disconnect_by_func(client, client_state_changed, self); - c_list_unlink(&client->dhcp_client_lst); - - /* Stopping the client is left up to the controlling device - * explicitly since we may want to quit NetworkManager but not terminate - * the DHCP client. - */ -} - -static void -remove_client_unref(NMDhcpManager *self, NMDhcpClient *client) -{ - remove_client(self, client); - g_object_unref(client); -} - -static void -client_state_changed(NMDhcpClient * client, - NMDhcpState state, - GObject * ip_config, - GVariant * options, - NMDhcpManager *self) -{ - if (state >= NM_DHCP_STATE_TIMEOUT) - remove_client_unref(self, client); -} - -static NMDhcpClient * -client_start(NMDhcpManager * self, - int addr_family, - NMDedupMultiIndex * multi_idx, - const char * iface, - int ifindex, - GBytes * hwaddr, - GBytes * bcast_hwaddr, - const char * uuid, - guint32 route_table, - guint32 route_metric, - const struct in6_addr * ipv6_ll_addr, - GBytes * dhcp_client_id, - gboolean enforce_duid, - guint32 iaid, - gboolean iaid_explicit, - guint32 timeout, - const char * dhcp_anycast_addr, - const char * hostname, - gboolean hostname_use_fqdn, - NMDhcpHostnameFlags hostname_flags, - const char * mud_url, - gboolean info_only, - NMSettingIP6ConfigPrivacy privacy, - const char * last_ip4_address, - guint needed_prefixes, - GBytes * vendor_class_identifier, - const char *const * reject_servers, - GError ** error) -{ - NMDhcpManagerPrivate *priv; - NMDhcpClient * client; - gboolean success = FALSE; - gsize hwaddr_len; - GType gtype; - - g_return_val_if_fail(NM_IS_DHCP_MANAGER(self), NULL); - g_return_val_if_fail(iface, NULL); - g_return_val_if_fail(ifindex > 0, NULL); - g_return_val_if_fail(uuid != NULL, NULL); - g_return_val_if_fail(!dhcp_client_id || g_bytes_get_size(dhcp_client_id) >= 2, NULL); - g_return_val_if_fail(!vendor_class_identifier - || g_bytes_get_size(vendor_class_identifier) <= 255, - NULL); - g_return_val_if_fail(!error || !*error, NULL); - - if (addr_family == AF_INET) { - if (!hwaddr || !bcast_hwaddr) { - nm_utils_error_set(error, - NM_UTILS_ERROR_UNKNOWN, - "missing %s address", - hwaddr ? "broadcast" : "MAC"); - return NULL; - } - - hwaddr_len = g_bytes_get_size(hwaddr); - if (hwaddr_len == 0 || hwaddr_len > NM_UTILS_HWADDR_LEN_MAX) { - nm_utils_error_set(error, NM_UTILS_ERROR_UNKNOWN, "invalid MAC address"); - g_return_val_if_reached(NULL); - } - nm_assert(g_bytes_get_size(hwaddr) == g_bytes_get_size(bcast_hwaddr)); - } else { - hwaddr = NULL; - bcast_hwaddr = NULL; - } - - if (hostname) { - if ((hostname_use_fqdn && !nm_sd_dns_name_is_valid(hostname)) - || (!hostname_use_fqdn && !nm_sd_hostname_is_valid(hostname, FALSE))) { - nm_log_warn(LOGD_DHCP, - "dhcp%c: %s '%s' is invalid, will be ignored", - nm_utils_addr_family_to_char(addr_family), - hostname_use_fqdn ? "FQDN" : "hostname", - hostname); - hostname = NULL; - } - } - - priv = NM_DHCP_MANAGER_GET_PRIVATE(self); - - /* Kill any old client instance */ - client = get_client_for_ifindex(self, addr_family, ifindex); - if (client) { - /* FIXME: we cannot just call synchronously "stop()" and forget about the client. - * We need to wait for the client to be fully stopped because most/all clients - * cannot quit right away. - * - * FIXME(shutdown): also fix this during shutdown, to wait for all DHCP clients - * to be fully stopped. */ - remove_client(self, client); - nm_dhcp_client_stop(client, FALSE); - g_object_unref(client); - } - - gtype = _client_factory_get_gtype(priv->client_factory, addr_family); - - nm_log_trace(LOGD_DHCP, - "dhcp%c: creating IPv%c DHCP client of type %s", - nm_utils_addr_family_to_char(addr_family), - nm_utils_addr_family_to_char(addr_family), - g_type_name(gtype)); - - client = g_object_new(gtype, - NM_DHCP_CLIENT_MULTI_IDX, - multi_idx, - NM_DHCP_CLIENT_ADDR_FAMILY, - addr_family, - NM_DHCP_CLIENT_INTERFACE, - iface, - NM_DHCP_CLIENT_IFINDEX, - ifindex, - NM_DHCP_CLIENT_HWADDR, - hwaddr, - NM_DHCP_CLIENT_BROADCAST_HWADDR, - bcast_hwaddr, - NM_DHCP_CLIENT_UUID, - uuid, - NM_DHCP_CLIENT_IAID, - (guint) iaid, - NM_DHCP_CLIENT_IAID_EXPLICIT, - iaid_explicit, - NM_DHCP_CLIENT_HOSTNAME, - hostname, - NM_DHCP_CLIENT_MUD_URL, - mud_url, - NM_DHCP_CLIENT_ROUTE_TABLE, - (guint) route_table, - NM_DHCP_CLIENT_ROUTE_METRIC, - (guint) route_metric, - NM_DHCP_CLIENT_TIMEOUT, - (guint) timeout, - NM_DHCP_CLIENT_HOSTNAME_FLAGS, - (guint) hostname_flags, - NM_DHCP_CLIENT_VENDOR_CLASS_IDENTIFIER, - vendor_class_identifier, - NM_DHCP_CLIENT_REJECT_SERVERS, - reject_servers, - NM_DHCP_CLIENT_FLAGS, - (guint)(0 | (hostname_use_fqdn ? NM_DHCP_CLIENT_FLAGS_USE_FQDN : 0) - | (info_only ? NM_DHCP_CLIENT_FLAGS_INFO_ONLY : 0)), - NULL); - nm_assert(client && c_list_is_empty(&client->dhcp_client_lst)); - c_list_link_tail(&priv->dhcp_client_lst_head, &client->dhcp_client_lst); - g_signal_connect(client, - NM_DHCP_CLIENT_SIGNAL_STATE_CHANGED, - G_CALLBACK(client_state_changed), - self); - - /* unfortunately, our implementations work differently per address-family regarding client-id/DUID. - * - * - for IPv4, the calling code may determine a client-id (from NM's connection profile). - * If present, it is taken. If not present, the DHCP plugin uses a plugin specific default. - * - for "internal" plugin, the default is just "mac". - * - for "dhclient", we try to get the configuration from dhclient's /etc/dhcp or fallback - * to whatever dhclient uses by default. - * We do it this way, because for dhclient the user may configure a default - * outside of NM, and we want to honor that. Worse, dhclient could be a wapper - * script where the wrapper script overwrites the client-id. We need to distinguish - * between: force a particular client-id and leave it unspecified to whatever dhclient - * wants. - * - * - for IPv6, the calling code always determines a client-id. It also specifies @enforce_duid, - * to determine whether the given client-id must be used. - * - for "internal" plugin @enforce_duid doesn't matter and the given client-id is - * always used. - * - for "dhclient", @enforce_duid FALSE means to first try to load the DUID from the - * lease file, and only otherwise fallback to the given client-id. - * - other plugins don't support DHCPv6. - * It's done this way, so that existing dhclient setups don't change behavior on upgrade. - * - * This difference is cumbersome and only exists because of "dhclient" which supports hacking the - * default outside of NetworkManager API. - */ - - if (addr_family == AF_INET) { - success = nm_dhcp_client_start_ip4(client, - dhcp_client_id, - dhcp_anycast_addr, - last_ip4_address, - error); - } else { - success = nm_dhcp_client_start_ip6(client, - dhcp_client_id, - enforce_duid, - dhcp_anycast_addr, - ipv6_ll_addr, - privacy, - needed_prefixes, - error); - } - - if (!success) { - remove_client_unref(self, client); - return NULL; - } - - return g_object_ref(client); -} - -/* Caller owns a reference to the NMDhcpClient on return */ -NMDhcpClient * -nm_dhcp_manager_start_ip4(NMDhcpManager * self, - NMDedupMultiIndex * multi_idx, - const char * iface, - int ifindex, - GBytes * hwaddr, - GBytes * bcast_hwaddr, - const char * uuid, - guint32 route_table, - guint32 route_metric, - gboolean send_hostname, - const char * dhcp_hostname, - const char * dhcp_fqdn, - NMDhcpHostnameFlags hostname_flags, - const char * mud_url, - GBytes * dhcp_client_id, - guint32 timeout, - const char * dhcp_anycast_addr, - const char * last_ip_address, - GBytes * vendor_class_identifier, - const char *const * reject_servers, - GError ** error) -{ - NMDhcpManagerPrivate *priv; - const char * hostname = NULL; - gs_free char * hostname_tmp = NULL; - gboolean use_fqdn = FALSE; - char * dot; - - g_return_val_if_fail(NM_IS_DHCP_MANAGER(self), NULL); - priv = NM_DHCP_MANAGER_GET_PRIVATE(self); - - if (send_hostname) { - /* Use, in order of preference: - * 1. FQDN from configuration - * 2. hostname from configuration - * 3. system hostname (only host part) - */ - if (dhcp_fqdn) { - hostname = dhcp_fqdn; - use_fqdn = TRUE; - } else if (dhcp_hostname) - hostname = dhcp_hostname; - else { - hostname = priv->default_hostname; - if (hostname) { - hostname_tmp = g_strdup(hostname); - dot = strchr(hostname_tmp, '.'); - if (dot) - *dot = '\0'; - hostname = hostname_tmp; - } - } - } - - return client_start(self, - AF_INET, - multi_idx, - iface, - ifindex, - hwaddr, - bcast_hwaddr, - uuid, - route_table, - route_metric, - NULL, - dhcp_client_id, - FALSE, - 0, - FALSE, - timeout, - dhcp_anycast_addr, - hostname, - use_fqdn, - hostname_flags, - mud_url, - FALSE, - 0, - last_ip_address, - 0, - vendor_class_identifier, - reject_servers, - error); -} - -/* Caller owns a reference to the NMDhcpClient on return */ -NMDhcpClient * -nm_dhcp_manager_start_ip6(NMDhcpManager * self, - NMDedupMultiIndex * multi_idx, - const char * iface, - int ifindex, - const struct in6_addr * ll_addr, - const char * uuid, - guint32 route_table, - guint32 route_metric, - gboolean send_hostname, - const char * dhcp_hostname, - NMDhcpHostnameFlags hostname_flags, - const char * mud_url, - GBytes * duid, - gboolean enforce_duid, - guint32 iaid, - gboolean iaid_explicit, - guint32 timeout, - const char * dhcp_anycast_addr, - gboolean info_only, - NMSettingIP6ConfigPrivacy privacy, - guint needed_prefixes, - GError ** error) -{ - NMDhcpManagerPrivate *priv; - const char * hostname = NULL; - - g_return_val_if_fail(NM_IS_DHCP_MANAGER(self), NULL); - priv = NM_DHCP_MANAGER_GET_PRIVATE(self); - - if (send_hostname) { - /* Always prefer the explicit dhcp-hostname if given */ - hostname = dhcp_hostname ?: priv->default_hostname; - } - return client_start(self, - AF_INET6, - multi_idx, - iface, - ifindex, - NULL, - NULL, - uuid, - route_table, - route_metric, - ll_addr, - duid, - enforce_duid, - iaid, - iaid_explicit, - timeout, - dhcp_anycast_addr, - hostname, - TRUE, - hostname_flags, - mud_url, - info_only, - privacy, - NULL, - needed_prefixes, - NULL, - NULL, - error); -} - -void -nm_dhcp_manager_set_default_hostname(NMDhcpManager *manager, const char *hostname) -{ - NMDhcpManagerPrivate *priv = NM_DHCP_MANAGER_GET_PRIVATE(manager); - - nm_clear_g_free(&priv->default_hostname); - - /* Never send 'localhost'-type names to the DHCP server */ - if (!nm_utils_is_specific_hostname(hostname)) - return; - - priv->default_hostname = g_strdup(hostname); -} - -const char * -nm_dhcp_manager_get_config(NMDhcpManager *self) -{ - const NMDhcpClientFactory *factory; - - g_return_val_if_fail(NM_IS_DHCP_MANAGER(self), NULL); - - factory = NM_DHCP_MANAGER_GET_PRIVATE(self)->client_factory; - return factory ? factory->name : NULL; -} - -/*****************************************************************************/ - -NM_DEFINE_SINGLETON_GETTER(NMDhcpManager, nm_dhcp_manager_get, NM_TYPE_DHCP_MANAGER); - -void -nmtst_dhcp_manager_unget(gpointer self) -{ - _nmtst_nm_dhcp_manager_get_reset(self); -} - -static void -nm_dhcp_manager_init(NMDhcpManager *self) -{ - NMDhcpManagerPrivate * priv = NM_DHCP_MANAGER_GET_PRIVATE(self); - NMConfig * config = nm_config_get(); - gs_free char * client_free = NULL; - const char * client; - int i; - const NMDhcpClientFactory *client_factory = NULL; - - c_list_init(&priv->dhcp_client_lst_head); - - for (i = 0; i < G_N_ELEMENTS(_nm_dhcp_manager_factories); i++) { - const NMDhcpClientFactory *f = _nm_dhcp_manager_factories[i]; - - if (!f) - continue; - - nm_log_dbg(LOGD_DHCP, - "dhcp-init: enabled DHCP client '%s'%s%s", - f->name, - _client_factory_available(f) ? "" : " (not available)", - f->experimental ? " (undocumented internal plugin)" : ""); - } - - /* Client-specific setup */ - client_free = - nm_config_data_get_value(nm_config_get_data_orig(config), - NM_CONFIG_KEYFILE_GROUP_MAIN, - NM_CONFIG_KEYFILE_KEY_MAIN_DHCP, - NM_CONFIG_GET_VALUE_STRIP | NM_CONFIG_GET_VALUE_NO_EMPTY); - client = client_free; - if (nm_config_get_configure_and_quit(config) == NM_CONFIG_CONFIGURE_AND_QUIT_ENABLED) { - client_factory = &_nm_dhcp_client_factory_internal; - if (client && !nm_streq(client, client_factory->name)) - nm_log_info(LOGD_DHCP, - "dhcp-init: Using internal DHCP client since configure-and-quit is set."); - } else { - if (client) { - client_factory = _client_factory_available(_client_factory_find_by_name(client)); - if (!client_factory) - nm_log_warn(LOGD_DHCP, "dhcp-init: DHCP client '%s' not available", client); - } - if (!client_factory) { - client_factory = _client_factory_find_by_name("" NM_CONFIG_DEFAULT_MAIN_DHCP); - if (!client_factory) - nm_log_err(LOGD_DHCP, - "dhcp-init: default DHCP client '%s' is not installed", - NM_CONFIG_DEFAULT_MAIN_DHCP); - else { - client_factory = _client_factory_available(client_factory); - if (!client_factory) - nm_log_info(LOGD_DHCP, - "dhcp-init: default DHCP client '%s' is not available", - NM_CONFIG_DEFAULT_MAIN_DHCP); - } - } - if (!client_factory) { - for (i = 0; i < G_N_ELEMENTS(_nm_dhcp_manager_factories); i++) { - client_factory = _client_factory_available(_nm_dhcp_manager_factories[i]); - if (client_factory) - break; - } - } - } - - g_return_if_fail(client_factory); - - nm_log_info(LOGD_DHCP, "dhcp-init: Using DHCP client '%s'", client_factory->name); - - /* NOTE: currently the DHCP plugin is chosen once at start. It's not - * possible to reload that configuration. If that ever becomes possible, - * beware that the "dhcp-plugin" device spec made decisions based on - * the previous plugin and may need reevaluation. */ - priv->client_factory = client_factory; -} - -static void -dispose(GObject *object) -{ - NMDhcpManager * self = NM_DHCP_MANAGER(object); - NMDhcpManagerPrivate *priv = NM_DHCP_MANAGER_GET_PRIVATE(self); - NMDhcpClient * client, *client_safe; - - c_list_for_each_entry_safe (client, client_safe, &priv->dhcp_client_lst_head, dhcp_client_lst) - remove_client_unref(self, client); - - G_OBJECT_CLASS(nm_dhcp_manager_parent_class)->dispose(object); - - nm_clear_g_free(&priv->default_hostname); -} - -static void -nm_dhcp_manager_class_init(NMDhcpManagerClass *manager_class) -{ - GObjectClass *object_class = G_OBJECT_CLASS(manager_class); - - object_class->dispose = dispose; -} diff --git a/src/dhcp/nm-dhcp-manager.h b/src/dhcp/nm-dhcp-manager.h deleted file mode 100644 index 729d6d4e..00000000 --- a/src/dhcp/nm-dhcp-manager.h +++ /dev/null @@ -1,87 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2005 - 2010 Red Hat, Inc. - * Copyright (C) 2006 - 2008 Novell, Inc. - */ - -#ifndef __NETWORKMANAGER_DHCP_MANAGER_H__ -#define __NETWORKMANAGER_DHCP_MANAGER_H__ - -#include "nm-dhcp-client.h" -#include "nm-ip4-config.h" -#include "nm-dhcp-config.h" - -#define NM_TYPE_DHCP_MANAGER (nm_dhcp_manager_get_type()) -#define NM_DHCP_MANAGER(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DHCP_MANAGER, NMDhcpManager)) -#define NM_DHCP_MANAGER_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DHCP_MANAGER, NMDhcpManagerClass)) -#define NM_IS_DHCP_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DHCP_MANAGER)) -#define NM_IS_DHCP_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_DHCP_MANAGER)) -#define NM_DHCP_MANAGER_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_DHCP_MANAGER, NMDhcpManagerClass)) - -typedef struct _NMDhcpManager NMDhcpManager; -typedef struct _NMDhcpManagerClass NMDhcpManagerClass; - -GType nm_dhcp_manager_get_type(void); - -NMDhcpManager *nm_dhcp_manager_get(void); - -const char *nm_dhcp_manager_get_config(NMDhcpManager *self); - -void nm_dhcp_manager_set_default_hostname(NMDhcpManager *manager, const char *hostname); - -NMDhcpClient *nm_dhcp_manager_start_ip4(NMDhcpManager * manager, - struct _NMDedupMultiIndex *multi_idx, - const char * iface, - int ifindex, - GBytes * hwaddr, - GBytes * bcast_hwaddr, - const char * uuid, - guint32 route_table, - guint32 route_metric, - gboolean send_hostname, - const char * dhcp_hostname, - const char * dhcp_fqdn, - NMDhcpHostnameFlags hostname_flags, - const char * mud_url, - GBytes * dhcp_client_id, - guint32 timeout, - const char * dhcp_anycast_addr, - const char * last_ip_address, - GBytes * vendor_class_identifier, - const char *const * reject_servers, - GError ** error); - -NMDhcpClient *nm_dhcp_manager_start_ip6(NMDhcpManager * manager, - struct _NMDedupMultiIndex *multi_idx, - const char * iface, - int ifindex, - const struct in6_addr * ll_addr, - const char * uuid, - guint32 route_table, - guint32 route_metric, - gboolean send_hostname, - const char * dhcp_hostname, - NMDhcpHostnameFlags hostname_flags, - const char * mud_url, - GBytes * duid, - gboolean enforce_duid, - guint32 iaid, - gboolean iaid_explicit, - guint32 timeout, - const char * dhcp_anycast_addr, - gboolean info_only, - NMSettingIP6ConfigPrivacy privacy, - guint needed_prefixes, - GError ** error); - -/* For testing only */ -extern const char *nm_dhcp_helper_path; - -extern const NMDhcpClientFactory *const _nm_dhcp_manager_factories[6]; - -void nmtst_dhcp_manager_unget(gpointer singleton_instance); - -#endif /* __NETWORKMANAGER_DHCP_MANAGER_H__ */ diff --git a/src/dhcp/nm-dhcp-nettools.c b/src/dhcp/nm-dhcp-nettools.c deleted file mode 100644 index 7b4e4605..00000000 --- a/src/dhcp/nm-dhcp-nettools.c +++ /dev/null @@ -1,1533 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ -/* - * Copyright (C) 2014 - 2019 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include <stdlib.h> -#include <unistd.h> -#include <stdio.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#include <ctype.h> -#include <net/if_arp.h> - -#include "nm-sd-adapt-shared.h" - -#include "nm-glib-aux/nm-dedup-multi.h" -#include "nm-std-aux/unaligned.h" - -#include "nm-utils.h" -#include "nm-config.h" -#include "nm-dhcp-utils.h" -#include "nm-dhcp-options.h" -#include "nm-core-utils.h" -#include "NetworkManagerUtils.h" -#include "platform/nm-platform.h" -#include "nm-dhcp-client-logging.h" -#include "n-dhcp4/src/n-dhcp4.h" -#include "systemd/nm-sd-utils-shared.h" -#include "systemd/nm-sd-utils-dhcp.h" - -/*****************************************************************************/ - -#define NM_TYPE_DHCP_NETTOOLS (nm_dhcp_nettools_get_type()) -#define NM_DHCP_NETTOOLS(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DHCP_NETTOOLS, NMDhcpNettools)) -#define NM_DHCP_NETTOOLS_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DHCP_NETTOOLS, NMDhcpNettoolsClass)) -#define NM_IS_DHCP_NETTOOLS(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DHCP_NETTOOLS)) -#define NM_IS_DHCP_NETTOOLS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_DHCP_NETTOOLS)) -#define NM_DHCP_NETTOOLS_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_DHCP_NETTOOLS, NMDhcpNettoolsClass)) - -typedef struct _NMDhcpNettools NMDhcpNettools; -typedef struct _NMDhcpNettoolsClass NMDhcpNettoolsClass; - -/*****************************************************************************/ - -typedef struct { - NDhcp4Client * client; - NDhcp4ClientProbe *probe; - NDhcp4ClientLease *lease; - GSource * event_source; - char * lease_file; -} NMDhcpNettoolsPrivate; - -struct _NMDhcpNettools { - NMDhcpClient parent; - NMDhcpNettoolsPrivate _priv; -}; - -struct _NMDhcpNettoolsClass { - NMDhcpClientClass parent; -}; - -G_DEFINE_TYPE(NMDhcpNettools, nm_dhcp_nettools, NM_TYPE_DHCP_CLIENT) - -#define NM_DHCP_NETTOOLS_GET_PRIVATE(self) \ - _NM_GET_PRIVATE(self, NMDhcpNettools, NM_IS_DHCP_NETTOOLS) - -/*****************************************************************************/ - -static void -set_error_nettools(GError **error, int r, const char *message) -{ - /* the error code returned from n_dhcp4_* API is either a negative - * errno, or a positive internal error code. Generate different messages - * for these. */ - if (r < 0) - nm_utils_error_set_errno(error, r, "%s: %s", message); - else - nm_utils_error_set(error, r, "%s (code %d)", message, r); -} - -/*****************************************************************************/ - -#define DHCP_MAX_FQDN_LENGTH 255 - -enum { - NM_IN_ADDR_CLASS_A, - NM_IN_ADDR_CLASS_B, - NM_IN_ADDR_CLASS_C, - NM_IN_ADDR_CLASS_INVALID, -}; - -static int -in_addr_class(struct in_addr addr) -{ - switch (ntohl(addr.s_addr) >> 24) { - case 0 ... 127: - return NM_IN_ADDR_CLASS_A; - case 128 ... 191: - return NM_IN_ADDR_CLASS_B; - case 192 ... 223: - return NM_IN_ADDR_CLASS_C; - default: - return NM_IN_ADDR_CLASS_INVALID; - } -} - -static gboolean -lease_option_consume(void *out, size_t n_out, uint8_t **datap, size_t *n_datap) -{ - if (*n_datap < n_out) - return FALSE; - - memcpy(out, *datap, n_out); - *datap += n_out; - *n_datap -= n_out; - return TRUE; -} - -static gboolean -lease_option_next_in_addr(struct in_addr *addrp, uint8_t **datap, size_t *n_datap) -{ - return lease_option_consume(addrp, sizeof(struct in_addr), datap, n_datap); -} - -static gboolean -lease_option_next_route(struct in_addr *destp, - uint8_t * plenp, - struct in_addr *gatewayp, - gboolean classless, - uint8_t ** datap, - size_t * n_datap) -{ - struct in_addr dest = {}, gateway; - uint8_t * data = *datap; - size_t n_data = *n_datap; - uint8_t plen; - uint8_t bytes; - - if (classless) { - if (!lease_option_consume(&plen, sizeof(plen), &data, &n_data)) - return FALSE; - - if (plen > 32) - return FALSE; - - bytes = plen == 0 ? 0 : ((plen - 1) / 8) + 1; - - if (!lease_option_consume(&dest, bytes, &data, &n_data)) - return FALSE; - } else { - if (!lease_option_next_in_addr(&dest, &data, &n_data)) - return FALSE; - - switch (in_addr_class(dest)) { - case NM_IN_ADDR_CLASS_A: - plen = 8; - break; - case NM_IN_ADDR_CLASS_B: - plen = 16; - break; - case NM_IN_ADDR_CLASS_C: - plen = 24; - break; - case NM_IN_ADDR_CLASS_INVALID: - return FALSE; - } - } - - dest.s_addr = nm_utils_ip4_address_clear_host_address(dest.s_addr, plen); - - if (!lease_option_next_in_addr(&gateway, &data, &n_data)) - return FALSE; - - *destp = dest; - *plenp = plen; - *gatewayp = gateway; - *datap = data; - *n_datap = n_data; - return TRUE; -} - -static gboolean -lease_option_print_label(GString *str, size_t n_label, uint8_t **datap, size_t *n_datap) -{ - for (size_t i = 0; i < n_label; ++i) { - uint8_t c; - - if (!lease_option_consume(&c, sizeof(c), datap, n_datap)) - return FALSE; - - switch (c) { - case 'a' ... 'z': - case 'A' ... 'Z': - case '0' ... '9': - case '-': - case '_': - g_string_append_c(str, c); - break; - case '.': - case '\\': - g_string_append_printf(str, "\\%c", c); - break; - default: - g_string_append_printf(str, "\\%3d", c); - } - } - - return TRUE; -} - -static gboolean -lease_option_print_domain_name(GString * str, - uint8_t * cache, - size_t * n_cachep, - uint8_t **datap, - size_t * n_datap) -{ - uint8_t * domain; - size_t n_domain, n_cache = *n_cachep; - uint8_t **domainp = datap; - size_t * n_domainp = n_datap; - gboolean first = TRUE; - uint8_t c; - - /* - * We are given two adjacent memory regions. The @cache contains alreday parsed - * domain names, and the @datap contains the remaining data to parse. - * - * A domain name is formed from a sequence of labels. Each label start with - * a length byte, where the two most significant bits are unset. A zero-length - * label indicates the end of the domain name. - * - * Alternatively, a label can be followed by an offset (indicated by the two - * most significant bits being set in the next byte that is read). The offset - * is an offset into the cache, where the next label of the domain name can - * be found. - * - * Note, that each time a jump to an offset is performed, the size of the - * cache shrinks, so this is guaranteed to terminate. - */ - if (cache + n_cache != *datap) - return FALSE; - - for (;;) { - if (!lease_option_consume(&c, sizeof(c), domainp, n_domainp)) - return FALSE; - - switch (c & 0xC0) { - case 0x00: /* label length */ - { - size_t n_label = c; - - if (n_label == 0) { - /* - * We reached the final label of the domain name. Adjust - * the cache to include the consumed data, and return. - */ - *n_cachep = *datap - cache; - return TRUE; - } - - if (!first) - g_string_append_c(str, '.'); - else - first = FALSE; - - if (!lease_option_print_label(str, n_label, domainp, n_domainp)) - return FALSE; - - break; - } - case 0xC0: /* back pointer */ - { - size_t offset = (c & 0x3F) << 16; - - /* - * The offset is given as two bytes (in big endian), where the - * two high bits are masked out. - */ - - if (!lease_option_consume(&c, sizeof(c), domainp, n_domainp)) - return FALSE; - - offset += c; - - if (offset >= n_cache) - return FALSE; - - domain = cache + offset; - n_domain = n_cache - offset; - n_cache = offset; - - domainp = &domain; - n_domainp = &n_domain; - - break; - } - default: - return FALSE; - } - } -} - -static gboolean -lease_get_in_addr(NDhcp4ClientLease *lease, guint8 option, struct in_addr *addrp) -{ - struct in_addr addr; - uint8_t * data; - size_t n_data; - int r; - - r = n_dhcp4_client_lease_query(lease, option, &data, &n_data); - if (r) - return FALSE; - - if (!lease_option_next_in_addr(&addr, &data, &n_data)) - return FALSE; - - if (n_data != 0) - return FALSE; - - *addrp = addr; - return TRUE; -} - -static gboolean -lease_get_u16(NDhcp4ClientLease *lease, uint8_t option, uint16_t *u16p) -{ - uint8_t *data; - size_t n_data; - uint16_t be16; - int r; - - r = n_dhcp4_client_lease_query(lease, option, &data, &n_data); - if (r) - return FALSE; - - if (n_data != sizeof(be16)) - return FALSE; - - memcpy(&be16, data, sizeof(be16)); - - *u16p = ntohs(be16); - return TRUE; -} - -static gboolean -lease_parse_address(NDhcp4ClientLease *lease, - NMIP4Config * ip4_config, - GHashTable * options, - GError ** error) -{ - char addr_str[NM_UTILS_INET_ADDRSTRLEN]; - struct in_addr a_address; - struct in_addr a_netmask; - struct in_addr a_next_server; - guint32 a_plen; - guint64 nettools_lifetime; - guint32 a_lifetime; - guint32 a_timestamp; - guint64 a_expiry; - - n_dhcp4_client_lease_get_yiaddr(lease, &a_address); - if (a_address.s_addr == INADDR_ANY) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_UNKNOWN, - "could not get address from lease"); - return FALSE; - } - - n_dhcp4_client_lease_get_lifetime(lease, &nettools_lifetime); - - if (nettools_lifetime == G_MAXUINT64) { - a_timestamp = 0; - a_lifetime = NM_PLATFORM_LIFETIME_PERMANENT; - a_expiry = G_MAXUINT64; - } else { - guint64 nettools_basetime; - guint64 lifetime; - gint64 ts; - - n_dhcp4_client_lease_get_basetime(lease, &nettools_basetime); - - /* usually we shouldn't assert against external libraries like n-dhcp4. - * Here we still do it... it seems safe enough. */ - nm_assert(nettools_basetime > 0); - nm_assert(nettools_lifetime >= nettools_basetime); - nm_assert(((nettools_lifetime - nettools_basetime) % NM_UTILS_NSEC_PER_SEC) == 0); - nm_assert((nettools_lifetime - nettools_basetime) / NM_UTILS_NSEC_PER_SEC <= G_MAXUINT32); - - if (nettools_lifetime <= nettools_basetime) { - /* A lease time of 0 is allowed on some dhcp servers, so, let's accept it. */ - lifetime = 0; - } else { - lifetime = nettools_lifetime - nettools_basetime; - - /* we "ceil" the value to the next second. In practice, we don't expect any sub-second values - * from n-dhcp4 anyway, so this should have no effect. */ - lifetime += NM_UTILS_NSEC_PER_SEC - 1; - } - - ts = nm_utils_monotonic_timestamp_from_boottime(nettools_basetime, 1); - - /* the timestamp must be positive, because we only started nettools DHCP client - * after obtaining the first monotonic timestamp. Hence, the lease must have been - * received afterwards. */ - nm_assert(ts >= NM_UTILS_NSEC_PER_SEC); - - a_timestamp = ts / NM_UTILS_NSEC_PER_SEC; - a_lifetime = NM_MIN(lifetime / NM_UTILS_NSEC_PER_SEC, NM_PLATFORM_LIFETIME_PERMANENT - 1); - a_expiry = time(NULL) - + ((lifetime - (nm_utils_clock_gettime_nsec(CLOCK_BOOTTIME) - nettools_basetime)) - / NM_UTILS_NSEC_PER_SEC); - } - - if (!lease_get_in_addr(lease, NM_DHCP_OPTION_DHCP4_SUBNET_MASK, &a_netmask)) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_UNKNOWN, - "could not get netmask from lease"); - return FALSE; - } - - _nm_utils_inet4_ntop(a_address.s_addr, addr_str); - a_plen = nm_utils_ip4_netmask_to_prefix(a_netmask.s_addr); - - nm_dhcp_option_add_option(options, - _nm_dhcp_option_dhcp4_options, - NM_DHCP_OPTION_DHCP4_NM_IP_ADDRESS, - addr_str); - nm_dhcp_option_add_option(options, - _nm_dhcp_option_dhcp4_options, - NM_DHCP_OPTION_DHCP4_SUBNET_MASK, - _nm_utils_inet4_ntop(a_netmask.s_addr, addr_str)); - - nm_dhcp_option_add_option_u64(options, - _nm_dhcp_option_dhcp4_options, - NM_DHCP_OPTION_DHCP4_IP_ADDRESS_LEASE_TIME, - (guint64) a_lifetime); - - if (a_expiry != G_MAXUINT64) { - nm_dhcp_option_add_option_u64(options, - _nm_dhcp_option_dhcp4_options, - NM_DHCP_OPTION_DHCP4_NM_EXPIRY, - a_expiry); - } - - n_dhcp4_client_lease_get_siaddr(lease, &a_next_server); - if (a_next_server.s_addr != INADDR_ANY) { - _nm_utils_inet4_ntop(a_next_server.s_addr, addr_str); - nm_dhcp_option_add_option(options, - _nm_dhcp_option_dhcp4_options, - NM_DHCP_OPTION_DHCP4_NM_NEXT_SERVER, - addr_str); - } - - nm_ip4_config_add_address(ip4_config, - &((const NMPlatformIP4Address){ - .address = a_address.s_addr, - .peer_address = a_address.s_addr, - .plen = a_plen, - .addr_source = NM_IP_CONFIG_SOURCE_DHCP, - .timestamp = a_timestamp, - .lifetime = a_lifetime, - .preferred = a_lifetime, - })); - - return TRUE; -} - -static void -lease_parse_address_list(NDhcp4ClientLease * lease, - NMIP4Config * ip4_config, - NMDhcpOptionDhcp4Options option, - GHashTable * options) -{ - nm_auto_free_gstring GString *str = NULL; - char addr_str[NM_UTILS_INET_ADDRSTRLEN]; - struct in_addr addr; - uint8_t * data; - size_t n_data; - int r; - - r = n_dhcp4_client_lease_query(lease, option, &data, &n_data); - if (r) - return; - - nm_gstring_prepare(&str); - - while (lease_option_next_in_addr(&addr, &data, &n_data)) { - _nm_utils_inet4_ntop(addr.s_addr, addr_str); - g_string_append(nm_gstring_add_space_delimiter(str), addr_str); - - switch (option) { - case NM_DHCP_OPTION_DHCP4_DOMAIN_NAME_SERVER: - if (addr.s_addr == 0 || nm_ip4_addr_is_localhost(addr.s_addr)) { - /* Skip localhost addresses, like also networkd does. - * See https://github.com/systemd/systemd/issues/4524. */ - continue; - } - nm_ip4_config_add_nameserver(ip4_config, addr.s_addr); - break; - case NM_DHCP_OPTION_DHCP4_NIS_SERVERS: - nm_ip4_config_add_nis_server(ip4_config, addr.s_addr); - break; - case NM_DHCP_OPTION_DHCP4_NETBIOS_NAMESERVER: - nm_ip4_config_add_wins(ip4_config, addr.s_addr); - break; - default: - nm_assert_not_reached(); - } - } - - nm_dhcp_option_add_option(options, _nm_dhcp_option_dhcp4_options, option, str->str); -} - -static void -lease_parse_routes(NDhcp4ClientLease *lease, - NMIP4Config * ip4_config, - GHashTable * options, - guint32 route_table, - guint32 route_metric) -{ - nm_auto_free_gstring GString *str = NULL; - char dest_str[NM_UTILS_INET_ADDRSTRLEN]; - char gateway_str[NM_UTILS_INET_ADDRSTRLEN]; - const char * s; - struct in_addr dest, gateway; - uint8_t plen; - guint32 m; - gboolean has_router_from_classless = FALSE, has_classless = FALSE; - guint32 default_route_metric = route_metric; - uint8_t * data; - size_t n_data; - int r; - - r = n_dhcp4_client_lease_query(lease, - NM_DHCP_OPTION_DHCP4_CLASSLESS_STATIC_ROUTE, - &data, - &n_data); - if (!r) { - nm_gstring_prepare(&str); - - has_classless = TRUE; - - while (lease_option_next_route(&dest, &plen, &gateway, TRUE, &data, &n_data)) { - _nm_utils_inet4_ntop(dest.s_addr, dest_str); - _nm_utils_inet4_ntop(gateway.s_addr, gateway_str); - - g_string_append_printf(nm_gstring_add_space_delimiter(str), - "%s/%d %s", - dest_str, - (int) plen, - gateway_str); - - if (plen == 0) { - /* if there are multiple default routes, we add them with differing - * metrics. */ - m = default_route_metric; - if (default_route_metric < G_MAXUINT32) - default_route_metric++; - - has_router_from_classless = TRUE; - } else { - m = route_metric; - } - - nm_ip4_config_add_route( - ip4_config, - &((const NMPlatformIP4Route){ - .network = dest.s_addr, - .plen = plen, - .gateway = gateway.s_addr, - .rt_source = NM_IP_CONFIG_SOURCE_DHCP, - .metric = m, - .table_coerced = nm_platform_route_table_coerce(route_table), - }), - NULL); - } - nm_dhcp_option_add_option(options, - _nm_dhcp_option_dhcp4_options, - NM_DHCP_OPTION_DHCP4_CLASSLESS_STATIC_ROUTE, - str->str); - } - - r = n_dhcp4_client_lease_query(lease, NM_DHCP_OPTION_DHCP4_STATIC_ROUTE, &data, &n_data); - if (!r) { - nm_gstring_prepare(&str); - - while (lease_option_next_route(&dest, &plen, &gateway, FALSE, &data, &n_data)) { - _nm_utils_inet4_ntop(dest.s_addr, dest_str); - _nm_utils_inet4_ntop(gateway.s_addr, gateway_str); - - g_string_append_printf(nm_gstring_add_space_delimiter(str), - "%s/%d %s", - dest_str, - (int) plen, - gateway_str); - - if (has_classless) { - /* RFC 3443: if the DHCP server returns both a Classless Static Routes - * option and a Static Routes option, the DHCP client MUST ignore the - * Static Routes option. */ - continue; - } - - if (plen == 0) { - /* for option 33 (static route), RFC 2132 says: - * - * The default route (0.0.0.0) is an illegal destination for a static - * route. */ - continue; - } - - nm_ip4_config_add_route( - ip4_config, - &((const NMPlatformIP4Route){ - .network = dest.s_addr, - .plen = plen, - .gateway = gateway.s_addr, - .rt_source = NM_IP_CONFIG_SOURCE_DHCP, - .metric = route_metric, - .table_coerced = nm_platform_route_table_coerce(route_table), - }), - NULL); - } - nm_dhcp_option_add_option(options, - _nm_dhcp_option_dhcp4_options, - NM_DHCP_OPTION_DHCP4_STATIC_ROUTE, - str->str); - } - - r = n_dhcp4_client_lease_query(lease, NM_DHCP_OPTION_DHCP4_ROUTER, &data, &n_data); - if (!r) { - nm_gstring_prepare(&str); - - while (lease_option_next_in_addr(&gateway, &data, &n_data)) { - s = _nm_utils_inet4_ntop(gateway.s_addr, gateway_str); - g_string_append(nm_gstring_add_space_delimiter(str), s); - - if (gateway.s_addr == 0) { - /* silently skip 0.0.0.0 */ - continue; - } - - if (has_router_from_classless) { - /* If the DHCP server returns both a Classless Static Routes option and a - * Router option, the DHCP client MUST ignore the Router option [RFC 3442]. - * - * Be more lenient and ignore the Router option only if Classless Static - * Routes contain a default gateway (as other DHCP backends do). - */ - continue; - } - - /* if there are multiple default routes, we add them with differing - * metrics. */ - m = default_route_metric; - if (default_route_metric < G_MAXUINT32) - default_route_metric++; - - nm_ip4_config_add_route( - ip4_config, - &((const NMPlatformIP4Route){ - .rt_source = NM_IP_CONFIG_SOURCE_DHCP, - .gateway = gateway.s_addr, - .table_coerced = nm_platform_route_table_coerce(route_table), - .metric = m, - }), - NULL); - } - nm_dhcp_option_add_option(options, - _nm_dhcp_option_dhcp4_options, - NM_DHCP_OPTION_DHCP4_ROUTER, - str->str); - } -} - -static void -lease_parse_mtu(NDhcp4ClientLease *lease, NMIP4Config *ip4_config, GHashTable *options) -{ - uint16_t mtu; - - if (!lease_get_u16(lease, NM_DHCP_OPTION_DHCP4_INTERFACE_MTU, &mtu)) - return; - - if (mtu < 68) - return; - - nm_dhcp_option_add_option_u64(options, - _nm_dhcp_option_dhcp4_options, - NM_DHCP_OPTION_DHCP4_INTERFACE_MTU, - mtu); - nm_ip4_config_set_mtu(ip4_config, mtu, NM_IP_CONFIG_SOURCE_DHCP); -} - -static void -lease_parse_metered(NDhcp4ClientLease *lease, NMIP4Config *ip4_config, GHashTable *options) -{ - gboolean metered = FALSE; - uint8_t *data; - size_t n_data; - int r; - - r = n_dhcp4_client_lease_query(lease, NM_DHCP_OPTION_DHCP4_VENDOR_SPECIFIC, &data, &n_data); - if (r) - metered = FALSE; - else - metered = !!memmem(data, n_data, "ANDROID_METERED", NM_STRLEN("ANDROID_METERED")); - - /* TODO: expose the vendor specific option when present */ - nm_ip4_config_set_metered(ip4_config, metered); -} - -static void -lease_parse_ntps(NDhcp4ClientLease *lease, GHashTable *options) -{ - nm_auto_free_gstring GString *str = NULL; - char addr_str[NM_UTILS_INET_ADDRSTRLEN]; - struct in_addr addr; - uint8_t * data; - size_t n_data; - int r; - - r = n_dhcp4_client_lease_query(lease, NM_DHCP_OPTION_DHCP4_NTP_SERVER, &data, &n_data); - if (r) - return; - - nm_gstring_prepare(&str); - - while (lease_option_next_in_addr(&addr, &data, &n_data)) { - _nm_utils_inet4_ntop(addr.s_addr, addr_str); - g_string_append(nm_gstring_add_space_delimiter(str), addr_str); - } - - nm_dhcp_option_add_option(options, - _nm_dhcp_option_dhcp4_options, - NM_DHCP_OPTION_DHCP4_NTP_SERVER, - str->str); -} - -static void -lease_parse_hostname(NDhcp4ClientLease *lease, GHashTable *options) -{ - nm_auto_free_gstring GString *str = NULL; - uint8_t * data; - size_t n_data; - int r; - - r = n_dhcp4_client_lease_query(lease, NM_DHCP_OPTION_DHCP4_HOST_NAME, &data, &n_data); - if (r) - return; - - str = g_string_new_len((char *) data, n_data); - - if (nm_utils_is_localhost(str->str)) - return; - - nm_dhcp_option_add_option(options, - _nm_dhcp_option_dhcp4_options, - NM_DHCP_OPTION_DHCP4_HOST_NAME, - str->str); -} - -static void -lease_parse_domainname(NDhcp4ClientLease *lease, NMIP4Config *ip4_config, GHashTable *options) -{ - nm_auto_free_gstring GString *str = NULL; - gs_strfreev char ** domains = NULL; - uint8_t * data; - size_t n_data; - int r; - - r = n_dhcp4_client_lease_query(lease, NM_DHCP_OPTION_DHCP4_DOMAIN_NAME, &data, &n_data); - if (r) - return; - - str = g_string_new_len((char *) data, n_data); - - /* Multiple domains sometimes stuffed into option 15 "Domain Name". */ - domains = g_strsplit(str->str, " ", 0); - nm_gstring_prepare(&str); - - for (char **d = domains; *d; d++) { - if (nm_utils_is_localhost(*d)) - return; - - g_string_append(nm_gstring_add_space_delimiter(str), *d); - nm_ip4_config_add_domain(ip4_config, *d); - } - nm_dhcp_option_add_option(options, - _nm_dhcp_option_dhcp4_options, - NM_DHCP_OPTION_DHCP4_DOMAIN_NAME, - str->str); -} - -char ** -nm_dhcp_parse_search_list(guint8 *data, size_t n_data) -{ - GPtrArray *array = NULL; - guint8 * cache = data; - size_t n_cache = 0; - - for (;;) { - nm_auto_free_gstring GString *domain = NULL; - - nm_gstring_prepare(&domain); - - if (!lease_option_print_domain_name(domain, cache, &n_cache, &data, &n_data)) - break; - - if (!array) - array = g_ptr_array_new(); - - g_ptr_array_add(array, g_string_free(domain, FALSE)); - domain = NULL; - } - - if (array) { - g_ptr_array_add(array, NULL); - return (char **) g_ptr_array_free(array, FALSE); - } else - return NULL; -} - -static void -lease_parse_search_domains(NDhcp4ClientLease *lease, NMIP4Config *ip4_config, GHashTable *options) -{ - nm_auto_free_gstring GString *str = NULL; - uint8_t * data; - size_t n_data; - gs_strfreev char ** domains = NULL; - guint i; - int r; - - r = n_dhcp4_client_lease_query(lease, NM_DHCP_OPTION_DHCP4_DOMAIN_SEARCH_LIST, &data, &n_data); - if (r) - return; - - domains = nm_dhcp_parse_search_list(data, n_data); - nm_gstring_prepare(&str); - - for (i = 0; domains && domains[i]; i++) { - g_string_append(nm_gstring_add_space_delimiter(str), domains[i]); - nm_ip4_config_add_search(ip4_config, domains[i]); - } - nm_dhcp_option_add_option(options, - _nm_dhcp_option_dhcp4_options, - NM_DHCP_OPTION_DHCP4_DOMAIN_SEARCH_LIST, - str->str); -} - -static void -lease_parse_root_path(NDhcp4ClientLease *lease, GHashTable *options) -{ - nm_auto_free_gstring GString *str = NULL; - uint8_t * data; - size_t n_data; - int r; - - r = n_dhcp4_client_lease_query(lease, NM_DHCP_OPTION_DHCP4_ROOT_PATH, &data, &n_data); - if (r) - return; - - str = g_string_new_len((char *) data, n_data); - nm_dhcp_option_add_option(options, - _nm_dhcp_option_dhcp4_options, - NM_DHCP_OPTION_DHCP4_ROOT_PATH, - str->str); -} - -static void -lease_parse_wpad(NDhcp4ClientLease *lease, GHashTable *options) -{ - gs_free char *wpad = NULL; - uint8_t * data; - size_t n_data; - int r; - - r = n_dhcp4_client_lease_query(lease, - NM_DHCP_OPTION_DHCP4_PRIVATE_PROXY_AUTODISCOVERY, - &data, - &n_data); - if (r) - return; - - nm_utils_buf_utf8safe_escape((char *) data, n_data, 0, &wpad); - if (wpad == NULL) - wpad = g_strndup((char *) data, n_data); - - nm_dhcp_option_add_option(options, - _nm_dhcp_option_dhcp4_options, - NM_DHCP_OPTION_DHCP4_PRIVATE_PROXY_AUTODISCOVERY, - wpad); -} - -static void -lease_parse_nis_domain(NDhcp4ClientLease *lease, NMIP4Config *ip4_config, GHashTable *options) -{ - gs_free char *str_free = NULL; - const char * str; - uint8_t * data; - size_t n_data; - guint i; - int r; - - r = n_dhcp4_client_lease_query(lease, NM_DHCP_OPTION_DHCP4_NIS_DOMAIN, &data, &n_data); - if (r) - return; - - for (i = 0; i < n_data; i++) { - if (!nm_is_ascii((char) data[i])) - return; - } - - str = nm_strndup_a(300, (const char *) data, n_data, &str_free); - nm_dhcp_option_add_option(options, - _nm_dhcp_option_dhcp4_options, - NM_DHCP_OPTION_DHCP4_NIS_DOMAIN, - str); - nm_ip4_config_set_nis_domain(ip4_config, str); -} - -static void -lease_parse_private_options(NDhcp4ClientLease *lease, GHashTable *options) -{ - int i; - - for (i = NM_DHCP_OPTION_DHCP4_PRIVATE_224; i <= NM_DHCP_OPTION_DHCP4_PRIVATE_254; i++) { - gs_free char *option_string = NULL; - guint8 * data; - gsize n_data; - int r; - - /* We manage private options 249 (private classless static route) and 252 (wpad) in a special - * way, so skip them as we here just manage all (the other) private options as raw data */ - if (NM_IN_SET(i, - NM_DHCP_OPTION_DHCP4_PRIVATE_CLASSLESS_STATIC_ROUTE, - NM_DHCP_OPTION_DHCP4_PRIVATE_PROXY_AUTODISCOVERY)) - continue; - - r = n_dhcp4_client_lease_query(lease, i, &data, &n_data); - if (r) - continue; - - option_string = nm_utils_bin2hexstr_full(data, n_data, ':', FALSE, NULL); - nm_dhcp_option_take_option(options, - _nm_dhcp_option_dhcp4_options, - i, - g_steal_pointer(&option_string)); - } -} - -static NMIP4Config * -lease_to_ip4_config(NMDedupMultiIndex *multi_idx, - const char * iface, - int ifindex, - NDhcp4ClientLease *lease, - guint32 route_table, - guint32 route_metric, - GHashTable ** out_options, - GError ** error) -{ - gs_unref_object NMIP4Config *ip4_config = NULL; - gs_unref_hashtable GHashTable *options = NULL; - - g_return_val_if_fail(lease != NULL, NULL); - - ip4_config = nm_ip4_config_new(multi_idx, ifindex); - options = nm_dhcp_option_create_options_dict(); - - if (!lease_parse_address(lease, ip4_config, options, error)) - return NULL; - - lease_parse_routes(lease, ip4_config, options, route_table, route_metric); - lease_parse_address_list(lease, ip4_config, NM_DHCP_OPTION_DHCP4_DOMAIN_NAME_SERVER, options); - lease_parse_domainname(lease, ip4_config, options); - lease_parse_search_domains(lease, ip4_config, options); - lease_parse_mtu(lease, ip4_config, options); - lease_parse_metered(lease, ip4_config, options); - - lease_parse_hostname(lease, options); - lease_parse_ntps(lease, options); - lease_parse_root_path(lease, options); - lease_parse_wpad(lease, options); - lease_parse_nis_domain(lease, ip4_config, options); - lease_parse_address_list(lease, ip4_config, NM_DHCP_OPTION_DHCP4_NIS_SERVERS, options); - lease_parse_address_list(lease, ip4_config, NM_DHCP_OPTION_DHCP4_NETBIOS_NAMESERVER, options); - lease_parse_private_options(lease, options); - - NM_SET_OUT(out_options, g_steal_pointer(&options)); - return g_steal_pointer(&ip4_config); -} - -/*****************************************************************************/ - -static void -lease_save(NMDhcpNettools *self, NDhcp4ClientLease *lease, const char *lease_file) -{ - struct in_addr a_address; - nm_auto_free_gstring GString *new_contents = NULL; - char sbuf[NM_UTILS_INET_ADDRSTRLEN]; - gs_free_error GError *error = NULL; - - nm_assert(lease); - nm_assert(lease_file); - - new_contents = g_string_new("# This is private data. Do not parse.\n"); - - n_dhcp4_client_lease_get_yiaddr(lease, &a_address); - if (a_address.s_addr == INADDR_ANY) - return; - - g_string_append_printf(new_contents, - "ADDRESS=%s\n", - _nm_utils_inet4_ntop(a_address.s_addr, sbuf)); - - if (!g_file_set_contents(lease_file, new_contents->str, -1, &error)) - _LOGW("error saving lease to %s: %s", lease_file, error->message); -} - -static void -bound4_handle(NMDhcpNettools *self, NDhcp4ClientLease *lease, gboolean extended) -{ - NMDhcpNettoolsPrivate *priv = NM_DHCP_NETTOOLS_GET_PRIVATE(self); - const char * iface = nm_dhcp_client_get_iface(NM_DHCP_CLIENT(self)); - gs_unref_object NMIP4Config *ip4_config = NULL; - gs_unref_hashtable GHashTable *options = NULL; - GError * error = NULL; - - _LOGT("lease available (%s)", extended ? "extended" : "new"); - - ip4_config = lease_to_ip4_config(nm_dhcp_client_get_multi_idx(NM_DHCP_CLIENT(self)), - iface, - nm_dhcp_client_get_ifindex(NM_DHCP_CLIENT(self)), - lease, - nm_dhcp_client_get_route_table(NM_DHCP_CLIENT(self)), - nm_dhcp_client_get_route_metric(NM_DHCP_CLIENT(self)), - &options, - &error); - if (!ip4_config) { - _LOGW("%s", error->message); - g_clear_error(&error); - nm_dhcp_client_set_state(NM_DHCP_CLIENT(self), NM_DHCP_STATE_FAIL, NULL, NULL); - return; - } - - nm_dhcp_option_add_requests_to_options(options, _nm_dhcp_option_dhcp4_options); - lease_save(self, lease, priv->lease_file); - - nm_dhcp_client_set_state(NM_DHCP_CLIENT(self), - extended ? NM_DHCP_STATE_EXTENDED : NM_DHCP_STATE_BOUND, - NM_IP_CONFIG_CAST(ip4_config), - options); -} - -static void -dhcp4_event_handle(NMDhcpNettools *self, NDhcp4ClientEvent *event) -{ - NMDhcpNettoolsPrivate *priv = NM_DHCP_NETTOOLS_GET_PRIVATE(self); - struct in_addr server_id; - char addr_str[INET_ADDRSTRLEN]; - int r; - - _LOGT("client event %d", event->event); - - switch (event->event) { - case N_DHCP4_CLIENT_EVENT_OFFER: - r = n_dhcp4_client_lease_get_server_identifier(event->offer.lease, &server_id); - if (r) { - _LOGW("selecting lease failed: %d", r); - return; - } - - if (nm_dhcp_client_server_id_is_rejected(NM_DHCP_CLIENT(self), &server_id)) { - _LOGD("server-id %s is in the reject-list, ignoring", - nm_utils_inet_ntop(AF_INET, &server_id, addr_str)); - return; - } - - r = n_dhcp4_client_lease_select(event->offer.lease); - if (r) { - _LOGW("selecting lease failed: %d", r); - return; - } - break; - case N_DHCP4_CLIENT_EVENT_RETRACTED: - case N_DHCP4_CLIENT_EVENT_EXPIRED: - nm_dhcp_client_set_state(NM_DHCP_CLIENT(self), NM_DHCP_STATE_EXPIRE, NULL, NULL); - break; - case N_DHCP4_CLIENT_EVENT_CANCELLED: - nm_dhcp_client_set_state(NM_DHCP_CLIENT(self), NM_DHCP_STATE_FAIL, NULL, NULL); - break; - case N_DHCP4_CLIENT_EVENT_GRANTED: - priv->lease = n_dhcp4_client_lease_ref(event->granted.lease); - bound4_handle(self, event->granted.lease, FALSE); - break; - case N_DHCP4_CLIENT_EVENT_EXTENDED: - bound4_handle(self, event->extended.lease, TRUE); - break; - case N_DHCP4_CLIENT_EVENT_DOWN: - /* ignore down events, they are purely informational */ - break; - case N_DHCP4_CLIENT_EVENT_LOG: - { - NMLogLevel nm_level; - - nm_level = nm_log_level_from_syslog(event->log.level); - if (nm_logging_enabled(nm_level, LOGD_DHCP4)) { - nm_log(nm_level, - LOGD_DHCP4, - NULL, - NULL, - "dhcp4 (%s): %s", - nm_dhcp_client_get_iface(NM_DHCP_CLIENT(self)), - event->log.message); - } - } break; - default: - _LOGW("unhandled DHCP event %d", event->event); - break; - } -} - -static gboolean -dhcp4_event_cb(int fd, GIOCondition condition, gpointer data) -{ - NMDhcpNettools * self = data; - NMDhcpNettoolsPrivate *priv = NM_DHCP_NETTOOLS_GET_PRIVATE(self); - NDhcp4ClientEvent * event; - int r; - - r = n_dhcp4_client_dispatch(priv->client); - if (r < 0) { - /* FIXME: if any operation (e.g. send()) fails during the - * dispatch, n-dhcp4 returns an error without arming timers - * or progressing state, so the only reasonable thing to do - * is to move to failed state so that the client will be - * restarted. Ideally n-dhcp4 should retry failed operations - * a predefined number of times (possibly infinite). - */ - _LOGE("error %d dispatching events", r); - nm_clear_g_source_inst(&priv->event_source); - nm_dhcp_client_set_state(NM_DHCP_CLIENT(self), NM_DHCP_STATE_FAIL, NULL, NULL); - return G_SOURCE_REMOVE; - } - - while (!n_dhcp4_client_pop_event(priv->client, &event) && event) { - dhcp4_event_handle(self, event); - } - - return G_SOURCE_CONTINUE; -} - -static gboolean -nettools_create(NMDhcpNettools *self, const char *dhcp_anycast_addr, GError **error) -{ - NMDhcpNettoolsPrivate *priv = NM_DHCP_NETTOOLS_GET_PRIVATE(self); - nm_auto(n_dhcp4_client_config_freep) NDhcp4ClientConfig *config = NULL; - nm_auto(n_dhcp4_client_unrefp) NDhcp4Client * client = NULL; - GBytes * hwaddr; - GBytes * bcast_hwaddr; - const uint8_t * hwaddr_arr; - const uint8_t * bcast_hwaddr_arr; - gsize hwaddr_len; - gsize bcast_hwaddr_len; - GBytes * client_id; - gs_unref_bytes GBytes *client_id_new = NULL; - const uint8_t * client_id_arr; - size_t client_id_len; - int r, fd, arp_type, transport; - - g_return_val_if_fail(!priv->client, FALSE); - - hwaddr = nm_dhcp_client_get_hw_addr(NM_DHCP_CLIENT(self)); - if (!hwaddr || !(hwaddr_arr = g_bytes_get_data(hwaddr, &hwaddr_len)) - || (arp_type = nm_utils_arp_type_detect_from_hwaddrlen(hwaddr_len)) < 0) { - nm_utils_error_set_literal(error, NM_UTILS_ERROR_UNKNOWN, "invalid MAC address"); - return FALSE; - } - - bcast_hwaddr = nm_dhcp_client_get_broadcast_hw_addr(NM_DHCP_CLIENT(self)); - bcast_hwaddr_arr = g_bytes_get_data(bcast_hwaddr, &bcast_hwaddr_len); - - switch (arp_type) { - case ARPHRD_ETHER: - transport = N_DHCP4_TRANSPORT_ETHERNET; - break; - case ARPHRD_INFINIBAND: - transport = N_DHCP4_TRANSPORT_INFINIBAND; - break; - default: - nm_utils_error_set_literal(error, NM_UTILS_ERROR_UNKNOWN, "unsupported ARP type"); - return FALSE; - } - - /* Note that we always set a client-id. In particular for infiniband that is necessary, - * see https://tools.ietf.org/html/rfc4390#section-2.1 . */ - client_id = nm_dhcp_client_get_client_id(NM_DHCP_CLIENT(self)); - if (!client_id) { - client_id_new = nm_utils_dhcp_client_id_mac(arp_type, hwaddr_arr, hwaddr_len); - client_id = client_id_new; - } - - if (!(client_id_arr = g_bytes_get_data(client_id, &client_id_len)) || client_id_len < 2) { - /* invalid client-ids are not expected. */ - nm_assert_not_reached(); - - nm_utils_error_set_literal(error, NM_UTILS_ERROR_UNKNOWN, "no valid IPv4 client-id"); - return FALSE; - } - - r = n_dhcp4_client_config_new(&config); - if (r) { - set_error_nettools(error, r, "failed to create client-config"); - return FALSE; - } - - n_dhcp4_client_config_set_ifindex(config, nm_dhcp_client_get_ifindex(NM_DHCP_CLIENT(self))); - n_dhcp4_client_config_set_transport(config, transport); - n_dhcp4_client_config_set_mac(config, hwaddr_arr, hwaddr_len); - n_dhcp4_client_config_set_broadcast_mac(config, bcast_hwaddr_arr, bcast_hwaddr_len); - r = n_dhcp4_client_config_set_client_id(config, - client_id_arr, - NM_MIN(client_id_len, 1 + _NM_SD_MAX_CLIENT_ID_LEN)); - if (r) { - set_error_nettools(error, r, "failed to set client-id"); - return FALSE; - } - - r = n_dhcp4_client_new(&client, config); - if (r) { - set_error_nettools(error, r, "failed to create client"); - return FALSE; - } - - priv->client = client; - client = NULL; - - n_dhcp4_client_set_log_level(priv->client, - nm_log_level_to_syslog(nm_logging_get_level(LOGD_DHCP4))); - - n_dhcp4_client_get_fd(priv->client, &fd); - - priv->event_source = - nm_g_unix_fd_source_new(fd, G_IO_IN, G_PRIORITY_DEFAULT, dhcp4_event_cb, self, NULL); - g_source_attach(priv->event_source, NULL); - - return TRUE; -} - -static gboolean -_accept(NMDhcpClient *client, GError **error) -{ - NMDhcpNettools * self = NM_DHCP_NETTOOLS(client); - NMDhcpNettoolsPrivate *priv = NM_DHCP_NETTOOLS_GET_PRIVATE(self); - int r; - - g_return_val_if_fail(priv->lease, FALSE); - - _LOGT("accept"); - - r = n_dhcp4_client_lease_accept(priv->lease); - if (r) { - set_error_nettools(error, r, "failed to accept lease"); - return FALSE; - } - - priv->lease = n_dhcp4_client_lease_unref(priv->lease); - - return TRUE; -} - -static gboolean -decline(NMDhcpClient *client, const char *error_message, GError **error) -{ - NMDhcpNettools * self = NM_DHCP_NETTOOLS(client); - NMDhcpNettoolsPrivate *priv = NM_DHCP_NETTOOLS_GET_PRIVATE(self); - int r; - - g_return_val_if_fail(priv->lease, FALSE); - - _LOGT("dhcp4-client: decline"); - - r = n_dhcp4_client_lease_decline(priv->lease, error_message); - if (r) { - set_error_nettools(error, r, "failed to decline lease"); - return FALSE; - } - - priv->lease = n_dhcp4_client_lease_unref(priv->lease); - - return TRUE; -} - -static guint8 -fqdn_flags_to_wire(NMDhcpHostnameFlags flags) -{ - guint r = 0; - - /* RFC 4702 section 2.1 */ - if (flags & NM_DHCP_HOSTNAME_FLAG_FQDN_SERV_UPDATE) - r |= (1 << 0); - if (flags & NM_DHCP_HOSTNAME_FLAG_FQDN_ENCODED) - r |= (1 << 2); - if (flags & NM_DHCP_HOSTNAME_FLAG_FQDN_NO_UPDATE) - r |= (1 << 3); - - return r; -} - -static gboolean -ip4_start(NMDhcpClient *client, - const char * dhcp_anycast_addr, - const char * last_ip4_address, - GError ** error) -{ - nm_auto(n_dhcp4_client_probe_config_freep) NDhcp4ClientProbeConfig *config = NULL; - NMDhcpNettools * self = NM_DHCP_NETTOOLS(client); - NMDhcpNettoolsPrivate *priv = NM_DHCP_NETTOOLS_GET_PRIVATE(self); - gs_free char * lease_file = NULL; - struct in_addr last_addr = {0}; - const char * hostname; - const char * mud_url; - GBytes * vendor_class_identifier; - int r, i; - - g_return_val_if_fail(!priv->probe, FALSE); - - if (!nettools_create(self, dhcp_anycast_addr, error)) - return FALSE; - - r = n_dhcp4_client_probe_config_new(&config); - if (r) { - set_error_nettools(error, r, "failed to create dhcp-client-probe-config"); - return FALSE; - } - - /* - * FIXME: - * Select, or configure, a reasonable start delay, to protect poor servers being flooded. - */ - n_dhcp4_client_probe_config_set_start_delay(config, 1); - - nm_dhcp_utils_get_leasefile_path(AF_INET, - "internal", - nm_dhcp_client_get_iface(client), - nm_dhcp_client_get_uuid(client), - &lease_file); - - if (last_ip4_address) - inet_pton(AF_INET, last_ip4_address, &last_addr); - else { - /* - * TODO: we stick to the systemd-networkd lease file format. Quite easy for now to - * just use the functions in systemd code. Anyway, as in the end we just use the - * ip address from all the options found in the lease, write a function that parses - * the lease file just for the assigned address and returns it in &last_address. - * Then drop reference to systemd-networkd structures and functions. - */ - nm_auto(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL; - - dhcp_lease_load(&lease, lease_file); - if (lease) - sd_dhcp_lease_get_address(lease, &last_addr); - } - - if (last_addr.s_addr) { - n_dhcp4_client_probe_config_set_requested_ip(config, last_addr); - n_dhcp4_client_probe_config_set_init_reboot(config, TRUE); - } - - /* Add requested options */ - for (i = 0; _nm_dhcp_option_dhcp4_options[i].name; i++) { - if (_nm_dhcp_option_dhcp4_options[i].include) { - nm_assert(_nm_dhcp_option_dhcp4_options[i].option_num <= 255); - n_dhcp4_client_probe_config_request_option(config, - _nm_dhcp_option_dhcp4_options[i].option_num); - } - } - - mud_url = nm_dhcp_client_get_mud_url(client); - if (mud_url) { - r = n_dhcp4_client_probe_config_append_option(config, - NM_DHCP_OPTION_DHCP4_MUD_URL, - mud_url, - strlen(mud_url)); - if (r) { - set_error_nettools(error, r, "failed to set MUD URL"); - return FALSE; - } - } - hostname = nm_dhcp_client_get_hostname(client); - if (hostname) { - if (nm_dhcp_client_get_use_fqdn(client)) { - uint8_t buffer[255]; - NMDhcpHostnameFlags flags; - size_t fqdn_len; - - flags = nm_dhcp_client_get_hostname_flags(client); - buffer[0] = fqdn_flags_to_wire(flags); - buffer[1] = 0; /* RCODE1 (deprecated) */ - buffer[2] = 0; /* RCODE2 (deprecated) */ - - if (flags & NM_DHCP_HOSTNAME_FLAG_FQDN_ENCODED) { - r = nm_sd_dns_name_to_wire_format(hostname, buffer + 3, sizeof(buffer) - 3, FALSE); - if (r <= 0) { - if (r < 0) - nm_utils_error_set_errno(error, r, "failed to convert DHCP FQDN: %s"); - else - nm_utils_error_set(error, r, "failed to convert DHCP FQDN"); - return FALSE; - } - fqdn_len = r; - } else { - fqdn_len = strlen(hostname); - if (fqdn_len > sizeof(buffer) - 3) { - nm_utils_error_set(error, r, "failed to set DHCP FQDN: name too long"); - return FALSE; - } - memcpy(buffer + 3, hostname, fqdn_len); - } - - r = n_dhcp4_client_probe_config_append_option(config, - NM_DHCP_OPTION_DHCP4_CLIENT_FQDN, - buffer, - 3 + fqdn_len); - if (r) { - set_error_nettools(error, r, "failed to set DHCP FQDN"); - return FALSE; - } - } else { - r = n_dhcp4_client_probe_config_append_option(config, - NM_DHCP_OPTION_DHCP4_HOST_NAME, - hostname, - strlen(hostname)); - if (r) { - set_error_nettools(error, r, "failed to set DHCP hostname"); - return FALSE; - } - } - } - - vendor_class_identifier = nm_dhcp_client_get_vendor_class_identifier(client); - if (vendor_class_identifier) { - const void *option_data; - gsize option_size; - - option_data = g_bytes_get_data(vendor_class_identifier, &option_size); - nm_assert(option_data); - nm_assert(option_size <= 255); - - r = n_dhcp4_client_probe_config_append_option(config, - NM_DHCP_OPTION_DHCP4_VENDOR_CLASS_IDENTIFIER, - option_data, - option_size); - if (r) { - set_error_nettools(error, r, "failed to set vendor class identifier"); - return FALSE; - } - } - - g_free(priv->lease_file); - priv->lease_file = g_steal_pointer(&lease_file); - - r = n_dhcp4_client_probe(priv->client, &priv->probe, config); - if (r) { - set_error_nettools(error, r, "failed to start DHCP client"); - return FALSE; - } - - _LOGT("dhcp-client4: start %p", (gpointer) priv->client); - - nm_dhcp_client_start_timeout(client); - return TRUE; -} - -static void -stop(NMDhcpClient *client, gboolean release) -{ - NMDhcpNettools * self = NM_DHCP_NETTOOLS(client); - NMDhcpNettoolsPrivate *priv = NM_DHCP_NETTOOLS_GET_PRIVATE(self); - - NM_DHCP_CLIENT_CLASS(nm_dhcp_nettools_parent_class)->stop(client, release); - - _LOGT("dhcp-client4: stop %p", (gpointer) priv->client); - - priv->probe = n_dhcp4_client_probe_free(priv->probe); -} - -/*****************************************************************************/ - -static void -nm_dhcp_nettools_init(NMDhcpNettools *self) -{} - -static void -dispose(GObject *object) -{ - NMDhcpNettoolsPrivate *priv = NM_DHCP_NETTOOLS_GET_PRIVATE(object); - - nm_clear_g_free(&priv->lease_file); - nm_clear_g_source_inst(&priv->event_source); - nm_clear_pointer(&priv->lease, n_dhcp4_client_lease_unref); - nm_clear_pointer(&priv->probe, n_dhcp4_client_probe_free); - nm_clear_pointer(&priv->client, n_dhcp4_client_unref); - - G_OBJECT_CLASS(nm_dhcp_nettools_parent_class)->dispose(object); -} - -static void -nm_dhcp_nettools_class_init(NMDhcpNettoolsClass *class) -{ - NMDhcpClientClass *client_class = NM_DHCP_CLIENT_CLASS(class); - GObjectClass * object_class = G_OBJECT_CLASS(class); - - object_class->dispose = dispose; - - client_class->ip4_start = ip4_start; - client_class->accept = _accept; - client_class->decline = decline; - client_class->stop = stop; -} - -const NMDhcpClientFactory _nm_dhcp_client_factory_nettools = { - .name = "nettools", - .get_type = nm_dhcp_nettools_get_type, - .experimental = TRUE, -}; diff --git a/src/dhcp/nm-dhcp-options.c b/src/dhcp/nm-dhcp-options.c deleted file mode 100644 index 58d38201..00000000 --- a/src/dhcp/nm-dhcp-options.c +++ /dev/null @@ -1,271 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ -/* - * Copyright (C) 2019 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include "nm-dhcp-options.h" - -#define REQPREFIX "requested_" - -#define REQ(_num, _name, _include) \ - { \ - .name = REQPREFIX ""_name, .option_num = _num, .include = _include, \ - } - -const NMDhcpOption _nm_dhcp_option_dhcp4_options[] = { - REQ(NM_DHCP_OPTION_DHCP4_SUBNET_MASK, "subnet_mask", TRUE), - REQ(NM_DHCP_OPTION_DHCP4_TIME_OFFSET, "time_offset", TRUE), - REQ(NM_DHCP_OPTION_DHCP4_DOMAIN_NAME_SERVER, "domain_name_servers", TRUE), - REQ(NM_DHCP_OPTION_DHCP4_HOST_NAME, "host_name", TRUE), - REQ(NM_DHCP_OPTION_DHCP4_DOMAIN_NAME, "domain_name", TRUE), - REQ(NM_DHCP_OPTION_DHCP4_INTERFACE_MTU, "interface_mtu", TRUE), - REQ(NM_DHCP_OPTION_DHCP4_BROADCAST, "broadcast_address", TRUE), - /* RFC 3442: The Classless Static Routes option code MUST appear in the parameter - * request list prior to both the Router option code and the Static - * Routes option code, if present. */ - REQ(NM_DHCP_OPTION_DHCP4_CLASSLESS_STATIC_ROUTE, "rfc3442_classless_static_routes", TRUE), - REQ(NM_DHCP_OPTION_DHCP4_ROUTER, "routers", TRUE), - REQ(NM_DHCP_OPTION_DHCP4_STATIC_ROUTE, "static_routes", TRUE), - REQ(NM_DHCP_OPTION_DHCP4_NIS_DOMAIN, "nis_domain", TRUE), - REQ(NM_DHCP_OPTION_DHCP4_NIS_SERVERS, "nis_servers", TRUE), - REQ(NM_DHCP_OPTION_DHCP4_NTP_SERVER, "ntp_servers", TRUE), - REQ(NM_DHCP_OPTION_DHCP4_SERVER_ID, "dhcp_server_identifier", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_DOMAIN_SEARCH_LIST, "domain_search", TRUE), - REQ(NM_DHCP_OPTION_DHCP4_PRIVATE_CLASSLESS_STATIC_ROUTE, "ms_classless_static_routes", TRUE), - REQ(NM_DHCP_OPTION_DHCP4_PRIVATE_PROXY_AUTODISCOVERY, "wpad", TRUE), - REQ(NM_DHCP_OPTION_DHCP4_ROOT_PATH, "root_path", TRUE), - - REQ(NM_DHCP_OPTION_DHCP4_TIME_SERVERS, "time_servers", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_IEN116_NAME_SERVERS, "ien116_name_servers", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_LOG_SERVERS, "log_servers", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_COOKIE_SERVERS, "cookie_servers", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_LPR_SERVERS, "lpr_servers", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_IMPRESS_SERVERS, "impress_servers", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_RESOURCE_LOCATION_SERVERS, "resource_location_servers", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_BOOT_FILE_SIZE, "boot_size", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_MERIT_DUMP, "merit_dump", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_SWAP_SERVER, "swap_server", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_EXTENSIONS_PATH, "extensions_path", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_ENABLE_IP_FORWARDING, "ip_forwarding", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_ENABLE_SRC_ROUTING, "non_local_source_routing", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_POLICY_FILTER, "policy_filter", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_INTERFACE_MDR, "max_dgram_reassembly", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_INTERFACE_TTL, "default_ip_ttl", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_INTERFACE_MTU_AGING_TIMEOUT, "path_mtu_aging_timeout", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_PATH_MTU_PLATEAU_TABLE, "path_mtu_plateau_table", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_ALL_SUBNETS_LOCAL, "all_subnets_local", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_PERFORM_MASK_DISCOVERY, "perform_mask_discovery", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_MASK_SUPPLIER, "mask_supplier", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_ROUTER_DISCOVERY, "router_discovery", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_ROUTER_SOLICITATION_ADDR, "router_solicitation_address", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_TRAILER_ENCAPSULATION, "trailer_encapsulation", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_ARP_CACHE_TIMEOUT, "arp_cache_timeout", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_IEEE802_3_ENCAPSULATION, "ieee802_3_encapsulation", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_DEFAULT_TCP_TTL, "default_tcp_ttl", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_TCP_KEEPALIVE_INTERVAL, "tcp_keepalive_internal", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_TCP_KEEPALIVE_GARBAGE, "tcp_keepalive_garbage", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_VENDOR_SPECIFIC, "vendor_encapsulated_options", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_NETBIOS_NAMESERVER, "netbios_name_servers", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_NETBIOS_DD_SERVER, "netbios_dd_server", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_FONT_SERVERS, "font_servers", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_X_DISPLAY_MANAGER, "x_display_manager", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_IP_ADDRESS_LEASE_TIME, "dhcp_lease_time", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_RENEWAL_T1_TIME, "dhcp_renewal_time", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_REBINDING_T2_TIME, "dhcp_rebinding_time", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_CLIENT_ID, "dhcp_client_identifier", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_NEW_TZDB_TIMEZONE, "tcode", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_NWIP_DOMAIN, "nwip_domain", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_NWIP_SUBOPTIONS, "nwip_suboptions", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_NISPLUS_DOMAIN, "nisplus_domain", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_NISPLUS_SERVERS, "nisplus_servers", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_TFTP_SERVER_NAME, "tftp_server_name", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_BOOTFILE_NAME, "bootfile_name", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_MOBILE_IP_HOME_AGENT, "mobile_ip_home_agent", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_SMTP_SERVER, "smtp_server", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_POP_SERVER, "pop_server", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_NNTP_SERVER, "nntp_server", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_WWW_SERVER, "www_server", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_FINGER_SERVER, "finger_server", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_IRC_SERVER, "irc_server", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_STREETTALK_SERVER, "streettalk_server", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_STREETTALK_DIR_ASSIST_SERVER, - "streettalk_directory_assistance_server", - FALSE), - REQ(NM_DHCP_OPTION_DHCP4_SLP_DIRECTORY_AGENT, "slp_directory_agent", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_SLP_SERVICE_SCOPE, "slp_service_scope", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_CLIENT_FQDN, "fqdn", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_RELAY_AGENT_INFORMATION, "relay_agent_information", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_NDS_SERVERS, "nds_servers", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_NDS_TREE_NAME, "nds_tree_name", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_NDS_CONTEXT, "nds_context", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_BCMS_CONTROLLER_NAMES, "bcms_controller_names", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_BCMS_CONTROLLER_ADDRESS, "bcms_controller_address", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_CLIENT_LAST_TRANSACTION, "client_last_transaction_time", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_ASSOCIATED_IP, "associated_ip", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_PXE_SYSTEM_TYPE, "pxe_system_type", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_PXE_INTERFACE_ID, "pxe_interface_id", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_PXE_CLIENT_ID, "pxe_client_id", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_UAP_SERVERS, "uap_servers", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_GEOCONF_CIVIC, "geoconf_civic", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_NETINFO_SERVER_ADDRESS, "netinfo_server_address", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_NETINFO_SERVER_TAG, "netinfo_server_tag", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_DEFAULT_URL, "default_url", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_AUTO_CONFIG, "auto_config", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_NAME_SERVICE_SEARCH, "name_service_search", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_SUBNET_SELECTION, "subnet_selection", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_VIVCO, "vivco", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_VIVSO, "vivso", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_PANA_AGENT, "pana_agent", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_V4_LOST, "v4_lost", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_SIP_UA_CS_DOMAINS, "sip_ua_cs_domains", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_IPV4_ADDRESS_ANDSF, "ipv4_address_andsf", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_RDNSS_SELECTION, "rndss_selection", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_TFTP_SERVER_ADDRESS, "tftp_server_address", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_V4_PORTPARAMS, "v4_portparams", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_V4_CAPTIVE_PORTAL, "v4_captive_portal", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_MUD_URL, "mud_url", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_LOADER_CONFIGFILE, "loader_configfile", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_LOADER_PATHPREFIX, "loader_pathprefix", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_LOADER_REBOOTTIME, "loader_reboottime", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_OPTION_6RD, "option_6rd", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_V4_ACCESS_DOMAIN, "v4_access_domain", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_PRIVATE_224, "private_224", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_PRIVATE_225, "private_225", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_PRIVATE_226, "private_226", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_PRIVATE_227, "private_227", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_PRIVATE_228, "private_228", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_PRIVATE_229, "private_229", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_PRIVATE_230, "private_230", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_PRIVATE_231, "private_231", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_PRIVATE_232, "private_232", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_PRIVATE_233, "private_233", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_PRIVATE_234, "private_234", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_PRIVATE_235, "private_235", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_PRIVATE_236, "private_236", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_PRIVATE_237, "private_237", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_PRIVATE_238, "private_238", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_PRIVATE_239, "private_239", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_PRIVATE_240, "private_240", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_PRIVATE_241, "private_241", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_PRIVATE_242, "private_242", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_PRIVATE_243, "private_243", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_PRIVATE_244, "private_244", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_PRIVATE_245, "private_245", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_PRIVATE_246, "private_246", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_PRIVATE_247, "private_247", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_PRIVATE_248, "private_248", FALSE), - /* NM_DHCP_OPTION_DHCP4_PRIVATE_CLASSLESS_STATIC_ROUTE */ - REQ(NM_DHCP_OPTION_DHCP4_PRIVATE_250, "private_250", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_PRIVATE_251, "private_251", FALSE), - /* NM_DHCP_OPTION_DHCP4_PRIVATE_PROXY_AUTODISCOVERY */ - REQ(NM_DHCP_OPTION_DHCP4_PRIVATE_253, "private_253", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_PRIVATE_254, "private_254", FALSE), - - /* Internal values */ - REQ(NM_DHCP_OPTION_DHCP4_NM_IP_ADDRESS, "ip_address", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_NM_EXPIRY, "expiry", FALSE), - REQ(NM_DHCP_OPTION_DHCP4_NM_NEXT_SERVER, "next_server", FALSE), - - {0}}; - -const NMDhcpOption _nm_dhcp_option_dhcp6_options[] = { - REQ(NM_DHCP_OPTION_DHCP6_CLIENTID, "dhcp6_client_id", FALSE), - - /* Don't request server ID by default; some servers don't reply to - * Information Requests that request the Server ID. - */ - REQ(NM_DHCP_OPTION_DHCP6_SERVERID, "dhcp6_server_id", FALSE), - - REQ(NM_DHCP_OPTION_DHCP6_DNS_SERVERS, "dhcp6_name_servers", TRUE), - REQ(NM_DHCP_OPTION_DHCP6_DOMAIN_LIST, "dhcp6_domain_search", TRUE), - REQ(NM_DHCP_OPTION_DHCP6_SNTP_SERVERS, "dhcp6_sntp_servers", TRUE), - REQ(NM_DHCP_OPTION_DHCP6_FQDN, "fqdn_fqdn", FALSE), - REQ(NM_DHCP_OPTION_DHCP6_MUD_URL, "dhcp6_mud_url", FALSE), - - /* Internal values */ - REQ(NM_DHCP_OPTION_DHCP6_NM_IP_ADDRESS, "ip6_address", FALSE), - REQ(NM_DHCP_OPTION_DHCP6_NM_PREFIXLEN, "ip6_prefixlen", FALSE), - REQ(NM_DHCP_OPTION_DHCP6_NM_PREFERRED_LIFE, "preferred_life", FALSE), - REQ(NM_DHCP_OPTION_DHCP6_NM_MAX_LIFE, "max_life", FALSE), - REQ(NM_DHCP_OPTION_DHCP6_NM_STARTS, "starts", FALSE), - REQ(NM_DHCP_OPTION_DHCP6_NM_LIFE_STARTS, "life_starts", FALSE), - REQ(NM_DHCP_OPTION_DHCP6_NM_RENEW, "renew", FALSE), - REQ(NM_DHCP_OPTION_DHCP6_NM_REBIND, "rebind", FALSE), - REQ(NM_DHCP_OPTION_DHCP6_NM_IAID, "iaid", FALSE), - - {0}}; - -const char * -nm_dhcp_option_request_string(const NMDhcpOption *requests, guint option) -{ - guint i = 0; - - while (requests[i].name) { - if (requests[i].option_num == option) - return requests[i].name + NM_STRLEN(REQPREFIX); - i++; - } - - /* Option should always be found */ - nm_assert_not_reached(); - return NULL; -} - -void -nm_dhcp_option_take_option(GHashTable * options, - const NMDhcpOption *requests, - guint option, - char * value) -{ - nm_assert(options); - nm_assert(requests); - nm_assert(value); - nm_assert(g_utf8_validate(value, -1, NULL)); - - g_hash_table_insert(options, (gpointer) nm_dhcp_option_request_string(requests, option), value); -} - -void -nm_dhcp_option_add_option(GHashTable * options, - const NMDhcpOption *requests, - guint option, - const char * value) -{ - if (options) - nm_dhcp_option_take_option(options, requests, option, g_strdup(value)); -} - -void -nm_dhcp_option_add_option_u64(GHashTable * options, - const NMDhcpOption *requests, - guint option, - guint64 value) -{ - if (options) - nm_dhcp_option_take_option(options, - requests, - option, - g_strdup_printf("%" G_GUINT64_FORMAT, value)); -} - -void -nm_dhcp_option_add_requests_to_options(GHashTable *options, const NMDhcpOption *requests) -{ - guint i; - - if (!options) - return; - - for (i = 0; requests[i].name; i++) { - if (requests[i].include) - g_hash_table_insert(options, (gpointer) requests[i].name, g_strdup("1")); - } -} - -GHashTable * -nm_dhcp_option_create_options_dict(void) -{ - return g_hash_table_new_full(nm_str_hash, g_str_equal, NULL, g_free); -} diff --git a/src/dhcp/nm-dhcp-options.h b/src/dhcp/nm-dhcp-options.h deleted file mode 100644 index 6c867c40..00000000 --- a/src/dhcp/nm-dhcp-options.h +++ /dev/null @@ -1,205 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ -/* - * Copyright (C) 2019 Red Hat, Inc. - */ - -#ifndef __NM_DHCP_OPTIONS_H__ -#define __NM_DHCP_OPTIONS_H__ - -typedef enum { - NM_DHCP_OPTION_DHCP4_PAD = 0, - NM_DHCP_OPTION_DHCP4_SUBNET_MASK = 1, - NM_DHCP_OPTION_DHCP4_TIME_OFFSET = 2, - NM_DHCP_OPTION_DHCP4_ROUTER = 3, - NM_DHCP_OPTION_DHCP4_TIME_SERVERS = 4, - NM_DHCP_OPTION_DHCP4_IEN116_NAME_SERVERS = 5, - NM_DHCP_OPTION_DHCP4_DOMAIN_NAME_SERVER = 6, - NM_DHCP_OPTION_DHCP4_LOG_SERVERS = 7, - NM_DHCP_OPTION_DHCP4_COOKIE_SERVERS = 8, - NM_DHCP_OPTION_DHCP4_LPR_SERVERS = 9, - NM_DHCP_OPTION_DHCP4_IMPRESS_SERVERS = 10, - NM_DHCP_OPTION_DHCP4_RESOURCE_LOCATION_SERVERS = 11, - NM_DHCP_OPTION_DHCP4_HOST_NAME = 12, - NM_DHCP_OPTION_DHCP4_BOOT_FILE_SIZE = 13, - NM_DHCP_OPTION_DHCP4_MERIT_DUMP = 14, - NM_DHCP_OPTION_DHCP4_DOMAIN_NAME = 15, - NM_DHCP_OPTION_DHCP4_SWAP_SERVER = 16, - NM_DHCP_OPTION_DHCP4_ROOT_PATH = 17, - NM_DHCP_OPTION_DHCP4_EXTENSIONS_PATH = 18, - NM_DHCP_OPTION_DHCP4_ENABLE_IP_FORWARDING = 19, - NM_DHCP_OPTION_DHCP4_ENABLE_SRC_ROUTING = 20, - NM_DHCP_OPTION_DHCP4_POLICY_FILTER = 21, - NM_DHCP_OPTION_DHCP4_INTERFACE_MDR = 22, - NM_DHCP_OPTION_DHCP4_INTERFACE_TTL = 23, - NM_DHCP_OPTION_DHCP4_INTERFACE_MTU_AGING_TIMEOUT = 24, - NM_DHCP_OPTION_DHCP4_PATH_MTU_PLATEAU_TABLE = 25, - NM_DHCP_OPTION_DHCP4_INTERFACE_MTU = 26, - NM_DHCP_OPTION_DHCP4_ALL_SUBNETS_LOCAL = 27, - NM_DHCP_OPTION_DHCP4_BROADCAST = 28, - NM_DHCP_OPTION_DHCP4_PERFORM_MASK_DISCOVERY = 29, - NM_DHCP_OPTION_DHCP4_MASK_SUPPLIER = 30, - NM_DHCP_OPTION_DHCP4_ROUTER_DISCOVERY = 31, - NM_DHCP_OPTION_DHCP4_ROUTER_SOLICITATION_ADDR = 32, - NM_DHCP_OPTION_DHCP4_STATIC_ROUTE = 33, - NM_DHCP_OPTION_DHCP4_TRAILER_ENCAPSULATION = 34, - NM_DHCP_OPTION_DHCP4_ARP_CACHE_TIMEOUT = 35, - NM_DHCP_OPTION_DHCP4_IEEE802_3_ENCAPSULATION = 36, - NM_DHCP_OPTION_DHCP4_DEFAULT_TCP_TTL = 37, - NM_DHCP_OPTION_DHCP4_TCP_KEEPALIVE_INTERVAL = 38, - NM_DHCP_OPTION_DHCP4_TCP_KEEPALIVE_GARBAGE = 39, - NM_DHCP_OPTION_DHCP4_NIS_DOMAIN = 40, - NM_DHCP_OPTION_DHCP4_NIS_SERVERS = 41, - NM_DHCP_OPTION_DHCP4_NTP_SERVER = 42, - NM_DHCP_OPTION_DHCP4_VENDOR_SPECIFIC = 43, - NM_DHCP_OPTION_DHCP4_NETBIOS_NAMESERVER = 44, - NM_DHCP_OPTION_DHCP4_NETBIOS_DD_SERVER = 45, - NM_DHCP_OPTION_DHCP4_FONT_SERVERS = 48, - NM_DHCP_OPTION_DHCP4_X_DISPLAY_MANAGER = 49, - NM_DHCP_OPTION_DHCP4_IP_ADDRESS_LEASE_TIME = 51, - NM_DHCP_OPTION_DHCP4_SERVER_ID = 54, - NM_DHCP_OPTION_DHCP4_RENEWAL_T1_TIME = 58, - NM_DHCP_OPTION_DHCP4_REBINDING_T2_TIME = 59, - NM_DHCP_OPTION_DHCP4_VENDOR_CLASS_IDENTIFIER = 60, - NM_DHCP_OPTION_DHCP4_CLIENT_ID = 61, - NM_DHCP_OPTION_DHCP4_NWIP_DOMAIN = 62, - NM_DHCP_OPTION_DHCP4_NWIP_SUBOPTIONS = 63, - NM_DHCP_OPTION_DHCP4_NISPLUS_DOMAIN = 64, - NM_DHCP_OPTION_DHCP4_NISPLUS_SERVERS = 65, - NM_DHCP_OPTION_DHCP4_TFTP_SERVER_NAME = 66, - NM_DHCP_OPTION_DHCP4_BOOTFILE_NAME = 67, - NM_DHCP_OPTION_DHCP4_MOBILE_IP_HOME_AGENT = 68, - NM_DHCP_OPTION_DHCP4_SMTP_SERVER = 69, - NM_DHCP_OPTION_DHCP4_POP_SERVER = 70, - NM_DHCP_OPTION_DHCP4_NNTP_SERVER = 71, - NM_DHCP_OPTION_DHCP4_WWW_SERVER = 72, - NM_DHCP_OPTION_DHCP4_FINGER_SERVER = 73, - NM_DHCP_OPTION_DHCP4_IRC_SERVER = 74, - NM_DHCP_OPTION_DHCP4_STREETTALK_SERVER = 75, - NM_DHCP_OPTION_DHCP4_STREETTALK_DIR_ASSIST_SERVER = 76, - NM_DHCP_OPTION_DHCP4_SLP_DIRECTORY_AGENT = 78, - NM_DHCP_OPTION_DHCP4_SLP_SERVICE_SCOPE = 79, - NM_DHCP_OPTION_DHCP4_CLIENT_FQDN = 81, - NM_DHCP_OPTION_DHCP4_RELAY_AGENT_INFORMATION = 82, - NM_DHCP_OPTION_DHCP4_NDS_SERVERS = 85, - NM_DHCP_OPTION_DHCP4_NDS_TREE_NAME = 86, - NM_DHCP_OPTION_DHCP4_NDS_CONTEXT = 87, - NM_DHCP_OPTION_DHCP4_BCMS_CONTROLLER_NAMES = 88, - NM_DHCP_OPTION_DHCP4_BCMS_CONTROLLER_ADDRESS = 89, - NM_DHCP_OPTION_DHCP4_CLIENT_LAST_TRANSACTION = 91, - NM_DHCP_OPTION_DHCP4_ASSOCIATED_IP = 92, - NM_DHCP_OPTION_DHCP4_PXE_SYSTEM_TYPE = 93, - NM_DHCP_OPTION_DHCP4_PXE_INTERFACE_ID = 94, - NM_DHCP_OPTION_DHCP4_PXE_CLIENT_ID = 97, - NM_DHCP_OPTION_DHCP4_UAP_SERVERS = 98, - NM_DHCP_OPTION_DHCP4_GEOCONF_CIVIC = 99, - NM_DHCP_OPTION_DHCP4_NEW_TZDB_TIMEZONE = 101, - NM_DHCP_OPTION_DHCP4_NETINFO_SERVER_ADDRESS = 112, - NM_DHCP_OPTION_DHCP4_NETINFO_SERVER_TAG = 113, - NM_DHCP_OPTION_DHCP4_DEFAULT_URL = 114, - NM_DHCP_OPTION_DHCP4_AUTO_CONFIG = 116, - NM_DHCP_OPTION_DHCP4_NAME_SERVICE_SEARCH = 117, - NM_DHCP_OPTION_DHCP4_SUBNET_SELECTION = 118, - NM_DHCP_OPTION_DHCP4_DOMAIN_SEARCH_LIST = 119, - NM_DHCP_OPTION_DHCP4_CLASSLESS_STATIC_ROUTE = 121, - NM_DHCP_OPTION_DHCP4_VIVCO = 124, - NM_DHCP_OPTION_DHCP4_VIVSO = 125, - NM_DHCP_OPTION_DHCP4_PANA_AGENT = 136, - NM_DHCP_OPTION_DHCP4_V4_LOST = 137, - NM_DHCP_OPTION_DHCP4_SIP_UA_CS_DOMAINS = 141, - NM_DHCP_OPTION_DHCP4_IPV4_ADDRESS_ANDSF = 142, - NM_DHCP_OPTION_DHCP4_RDNSS_SELECTION = 146, - NM_DHCP_OPTION_DHCP4_TFTP_SERVER_ADDRESS = 150, - NM_DHCP_OPTION_DHCP4_V4_PORTPARAMS = 159, - NM_DHCP_OPTION_DHCP4_V4_CAPTIVE_PORTAL = 160, - NM_DHCP_OPTION_DHCP4_MUD_URL = 161, - NM_DHCP_OPTION_DHCP4_LOADER_CONFIGFILE = 209, - NM_DHCP_OPTION_DHCP4_LOADER_PATHPREFIX = 210, - NM_DHCP_OPTION_DHCP4_LOADER_REBOOTTIME = 211, - NM_DHCP_OPTION_DHCP4_OPTION_6RD = 212, - NM_DHCP_OPTION_DHCP4_V4_ACCESS_DOMAIN = 213, - NM_DHCP_OPTION_DHCP4_PRIVATE_224 = 224, - NM_DHCP_OPTION_DHCP4_PRIVATE_225 = 225, - NM_DHCP_OPTION_DHCP4_PRIVATE_226 = 226, - NM_DHCP_OPTION_DHCP4_PRIVATE_227 = 227, - NM_DHCP_OPTION_DHCP4_PRIVATE_228 = 228, - NM_DHCP_OPTION_DHCP4_PRIVATE_229 = 229, - NM_DHCP_OPTION_DHCP4_PRIVATE_230 = 230, - NM_DHCP_OPTION_DHCP4_PRIVATE_231 = 231, - NM_DHCP_OPTION_DHCP4_PRIVATE_232 = 232, - NM_DHCP_OPTION_DHCP4_PRIVATE_233 = 233, - NM_DHCP_OPTION_DHCP4_PRIVATE_234 = 234, - NM_DHCP_OPTION_DHCP4_PRIVATE_235 = 235, - NM_DHCP_OPTION_DHCP4_PRIVATE_236 = 236, - NM_DHCP_OPTION_DHCP4_PRIVATE_237 = 237, - NM_DHCP_OPTION_DHCP4_PRIVATE_238 = 238, - NM_DHCP_OPTION_DHCP4_PRIVATE_239 = 239, - NM_DHCP_OPTION_DHCP4_PRIVATE_240 = 240, - NM_DHCP_OPTION_DHCP4_PRIVATE_241 = 241, - NM_DHCP_OPTION_DHCP4_PRIVATE_242 = 242, - NM_DHCP_OPTION_DHCP4_PRIVATE_243 = 243, - NM_DHCP_OPTION_DHCP4_PRIVATE_244 = 244, - NM_DHCP_OPTION_DHCP4_PRIVATE_245 = 245, - NM_DHCP_OPTION_DHCP4_PRIVATE_246 = 246, - NM_DHCP_OPTION_DHCP4_PRIVATE_247 = 247, - NM_DHCP_OPTION_DHCP4_PRIVATE_248 = 248, - NM_DHCP_OPTION_DHCP4_PRIVATE_CLASSLESS_STATIC_ROUTE = 249, - NM_DHCP_OPTION_DHCP4_PRIVATE_250 = 250, - NM_DHCP_OPTION_DHCP4_PRIVATE_251 = 251, - NM_DHCP_OPTION_DHCP4_PRIVATE_PROXY_AUTODISCOVERY = 252, - NM_DHCP_OPTION_DHCP4_PRIVATE_253 = 253, - NM_DHCP_OPTION_DHCP4_PRIVATE_254 = 254, - NM_DHCP_OPTION_DHCP4_END = 255, - /* Internal values */ - NM_DHCP_OPTION_DHCP4_NM_IP_ADDRESS = 1024, - NM_DHCP_OPTION_DHCP4_NM_EXPIRY = 1025, - NM_DHCP_OPTION_DHCP4_NM_NEXT_SERVER = 1026, -} NMDhcpOptionDhcp4Options; - -typedef enum { - NM_DHCP_OPTION_DHCP6_CLIENTID = 1, - NM_DHCP_OPTION_DHCP6_SERVERID = 2, - NM_DHCP_OPTION_DHCP6_DNS_SERVERS = 23, - NM_DHCP_OPTION_DHCP6_DOMAIN_LIST = 24, - NM_DHCP_OPTION_DHCP6_SNTP_SERVERS = 31, - NM_DHCP_OPTION_DHCP6_FQDN = 39, - NM_DHCP_OPTION_DHCP6_MUD_URL = 112, - - /* Internal values */ - NM_DHCP_OPTION_DHCP6_NM_IP_ADDRESS = 1026, - NM_DHCP_OPTION_DHCP6_NM_PREFIXLEN = 1027, - NM_DHCP_OPTION_DHCP6_NM_PREFERRED_LIFE = 1028, - NM_DHCP_OPTION_DHCP6_NM_MAX_LIFE = 1029, - NM_DHCP_OPTION_DHCP6_NM_STARTS = 1030, - NM_DHCP_OPTION_DHCP6_NM_LIFE_STARTS = 1031, - NM_DHCP_OPTION_DHCP6_NM_RENEW = 1032, - NM_DHCP_OPTION_DHCP6_NM_REBIND = 1033, - NM_DHCP_OPTION_DHCP6_NM_IAID = 1034, - -} NMDhcpOptionDhcp6Options; - -typedef struct { - const char *name; - uint16_t option_num; - bool include; -} NMDhcpOption; - -extern const NMDhcpOption _nm_dhcp_option_dhcp4_options[]; -extern const NMDhcpOption _nm_dhcp_option_dhcp6_options[]; - -const char *nm_dhcp_option_request_string(const NMDhcpOption *requests, guint option); -void nm_dhcp_option_take_option(GHashTable * options, - const NMDhcpOption *requests, - guint option, - char * value); -void nm_dhcp_option_add_option(GHashTable * options, - const NMDhcpOption *requests, - guint option, - const char * value); -void nm_dhcp_option_add_option_u64(GHashTable * options, - const NMDhcpOption *requests, - guint option, - guint64 value); -void nm_dhcp_option_add_requests_to_options(GHashTable *options, const NMDhcpOption *requests); -GHashTable *nm_dhcp_option_create_options_dict(void); - -#endif /* __NM_DHCP_OPTIONS_H__ */ diff --git a/src/dhcp/nm-dhcp-systemd.c b/src/dhcp/nm-dhcp-systemd.c deleted file mode 100644 index f9297223..00000000 --- a/src/dhcp/nm-dhcp-systemd.c +++ /dev/null @@ -1,1152 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ -/* - * Copyright (C) 2014 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include <stdlib.h> -#include <unistd.h> -#include <stdio.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#include <ctype.h> -#include <net/if_arp.h> - -#include "nm-glib-aux/nm-dedup-multi.h" -#include "nm-std-aux/unaligned.h" - -#include "nm-utils.h" -#include "nm-dhcp-utils.h" -#include "nm-dhcp-options.h" -#include "nm-core-utils.h" -#include "NetworkManagerUtils.h" -#include "platform/nm-platform.h" -#include "nm-dhcp-client-logging.h" -#include "systemd/nm-sd.h" -#include "systemd/nm-sd-utils-dhcp.h" - -/*****************************************************************************/ - -#define NM_TYPE_DHCP_SYSTEMD (nm_dhcp_systemd_get_type()) -#define NM_DHCP_SYSTEMD(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DHCP_SYSTEMD, NMDhcpSystemd)) -#define NM_DHCP_SYSTEMD_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DHCP_SYSTEMD, NMDhcpSystemdClass)) -#define NM_IS_DHCP_SYSTEMD(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DHCP_SYSTEMD)) -#define NM_IS_DHCP_SYSTEMD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_DHCP_SYSTEMD)) -#define NM_DHCP_SYSTEMD_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_DHCP_SYSTEMD, NMDhcpSystemdClass)) - -typedef struct _NMDhcpSystemd NMDhcpSystemd; -typedef struct _NMDhcpSystemdClass NMDhcpSystemdClass; - -static GType nm_dhcp_systemd_get_type(void); - -/*****************************************************************************/ - -typedef struct { - sd_dhcp_client * client4; - sd_dhcp6_client *client6; - char * lease_file; - - guint request_count; - - bool privacy : 1; -} NMDhcpSystemdPrivate; - -struct _NMDhcpSystemd { - NMDhcpClient parent; - NMDhcpSystemdPrivate _priv; -}; - -struct _NMDhcpSystemdClass { - NMDhcpClientClass parent; -}; - -G_DEFINE_TYPE(NMDhcpSystemd, nm_dhcp_systemd, NM_TYPE_DHCP_CLIENT) - -#define NM_DHCP_SYSTEMD_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMDhcpSystemd, NM_IS_DHCP_SYSTEMD) - -/*****************************************************************************/ - -static NMIP4Config * -lease_to_ip4_config(NMDedupMultiIndex *multi_idx, - const char * iface, - int ifindex, - sd_dhcp_lease * lease, - guint32 route_table, - guint32 route_metric, - GHashTable ** out_options, - GError ** error) -{ - gs_unref_object NMIP4Config *ip4_config = NULL; - gs_unref_hashtable GHashTable *options = NULL; - const struct in_addr * addr_list; - char addr_str[NM_UTILS_INET_ADDRSTRLEN]; - const char * s; - nm_auto_free_gstring GString *str = NULL; - gs_free sd_dhcp_route **routes = NULL; - const char *const * search_domains = NULL; - guint16 mtu; - int i, num; - const void * data; - gsize data_len; - gboolean metered = FALSE; - gboolean has_router_from_classless = FALSE; - gboolean has_classless_route = FALSE; - gboolean has_static_route = FALSE; - const gint32 ts = nm_utils_get_monotonic_timestamp_sec(); - gint64 ts_time = time(NULL); - struct in_addr a_address; - struct in_addr a_netmask; - struct in_addr a_next_server; - struct in_addr server_id; - struct in_addr broadcast; - const struct in_addr * a_router; - guint32 a_plen; - guint32 a_lifetime; - guint32 renewal; - guint32 rebinding; - gs_free nm_sd_dhcp_option *private_options = NULL; - - nm_assert(lease != NULL); - - if (sd_dhcp_lease_get_address(lease, &a_address) < 0) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_UNKNOWN, - "could not get address from lease"); - return NULL; - } - - if (sd_dhcp_lease_get_netmask(lease, &a_netmask) < 0) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_UNKNOWN, - "could not get netmask from lease"); - return NULL; - } - - if (sd_dhcp_lease_get_lifetime(lease, &a_lifetime) < 0) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_UNKNOWN, - "could not get lifetime from lease"); - return NULL; - } - - ip4_config = nm_ip4_config_new(multi_idx, ifindex); - - options = out_options ? nm_dhcp_option_create_options_dict() : NULL; - - _nm_utils_inet4_ntop(a_address.s_addr, addr_str); - nm_dhcp_option_add_option(options, - _nm_dhcp_option_dhcp4_options, - NM_DHCP_OPTION_DHCP4_NM_IP_ADDRESS, - addr_str); - - a_plen = nm_utils_ip4_netmask_to_prefix(a_netmask.s_addr); - nm_dhcp_option_add_option(options, - _nm_dhcp_option_dhcp4_options, - NM_DHCP_OPTION_DHCP4_SUBNET_MASK, - _nm_utils_inet4_ntop(a_netmask.s_addr, addr_str)); - - nm_dhcp_option_add_option_u64(options, - _nm_dhcp_option_dhcp4_options, - NM_DHCP_OPTION_DHCP4_IP_ADDRESS_LEASE_TIME, - a_lifetime); - nm_dhcp_option_add_option_u64(options, - _nm_dhcp_option_dhcp4_options, - NM_DHCP_OPTION_DHCP4_NM_EXPIRY, - (guint64)(ts_time + a_lifetime)); - - if (sd_dhcp_lease_get_next_server(lease, &a_next_server) == 0) { - _nm_utils_inet4_ntop(a_next_server.s_addr, addr_str); - nm_dhcp_option_add_option(options, - _nm_dhcp_option_dhcp4_options, - NM_DHCP_OPTION_DHCP4_NM_NEXT_SERVER, - addr_str); - } - - nm_ip4_config_add_address(ip4_config, - &((const NMPlatformIP4Address){ - .address = a_address.s_addr, - .peer_address = a_address.s_addr, - .plen = a_plen, - .addr_source = NM_IP_CONFIG_SOURCE_DHCP, - .timestamp = ts, - .lifetime = a_lifetime, - .preferred = a_lifetime, - })); - - if (sd_dhcp_lease_get_server_identifier(lease, &server_id) >= 0) { - _nm_utils_inet4_ntop(server_id.s_addr, addr_str); - nm_dhcp_option_add_option(options, - _nm_dhcp_option_dhcp4_options, - NM_DHCP_OPTION_DHCP4_SERVER_ID, - addr_str); - } - - if (sd_dhcp_lease_get_broadcast(lease, &broadcast) >= 0) { - _nm_utils_inet4_ntop(broadcast.s_addr, addr_str); - nm_dhcp_option_add_option(options, - _nm_dhcp_option_dhcp4_options, - NM_DHCP_OPTION_DHCP4_BROADCAST, - addr_str); - } - - num = sd_dhcp_lease_get_dns(lease, &addr_list); - if (num > 0) { - nm_gstring_prepare(&str); - for (i = 0; i < num; i++) { - _nm_utils_inet4_ntop(addr_list[i].s_addr, addr_str); - g_string_append(nm_gstring_add_space_delimiter(str), addr_str); - - if (addr_list[i].s_addr == 0 || nm_ip4_addr_is_localhost(addr_list[i].s_addr)) { - /* Skip localhost addresses, like also networkd does. - * See https://github.com/systemd/systemd/issues/4524. */ - continue; - } - nm_ip4_config_add_nameserver(ip4_config, addr_list[i].s_addr); - } - nm_dhcp_option_add_option(options, - _nm_dhcp_option_dhcp4_options, - NM_DHCP_OPTION_DHCP4_DOMAIN_NAME_SERVER, - str->str); - } - - num = sd_dhcp_lease_get_search_domains(lease, (char ***) &search_domains); - if (num > 0) { - nm_gstring_prepare(&str); - for (i = 0; i < num; i++) { - g_string_append(nm_gstring_add_space_delimiter(str), search_domains[i]); - nm_ip4_config_add_search(ip4_config, search_domains[i]); - } - nm_dhcp_option_add_option(options, - _nm_dhcp_option_dhcp4_options, - NM_DHCP_OPTION_DHCP4_DOMAIN_SEARCH_LIST, - str->str); - } - - if (sd_dhcp_lease_get_domainname(lease, &s) >= 0) { - gs_strfreev char **domains = NULL; - char ** d; - - nm_dhcp_option_add_option(options, - _nm_dhcp_option_dhcp4_options, - NM_DHCP_OPTION_DHCP4_DOMAIN_NAME, - s); - - /* Multiple domains sometimes stuffed into option 15 "Domain Name". - * As systemd escapes such characters, split them at \\032. */ - domains = g_strsplit(s, "\\032", 0); - for (d = domains; *d; d++) - nm_ip4_config_add_domain(ip4_config, *d); - } - - if (sd_dhcp_lease_get_hostname(lease, &s) >= 0) { - nm_dhcp_option_add_option(options, - _nm_dhcp_option_dhcp4_options, - NM_DHCP_OPTION_DHCP4_HOST_NAME, - s); - } - - num = sd_dhcp_lease_get_routes(lease, &routes); - if (num > 0) { - nm_auto_free_gstring GString *str_classless = NULL; - nm_auto_free_gstring GString *str_static = NULL; - guint32 default_route_metric = route_metric; - - for (i = 0; i < num; i++) { - switch (sd_dhcp_route_get_option(routes[i])) { - case NM_DHCP_OPTION_DHCP4_CLASSLESS_STATIC_ROUTE: - has_classless_route = TRUE; - break; - case NM_DHCP_OPTION_DHCP4_STATIC_ROUTE: - has_static_route = TRUE; - break; - } - } - - if (has_classless_route) - str_classless = g_string_sized_new(30); - if (has_static_route) - str_static = g_string_sized_new(30); - - for (i = 0; i < num; i++) { - char network_net_str[NM_UTILS_INET_ADDRSTRLEN]; - char gateway_str[NM_UTILS_INET_ADDRSTRLEN]; - guint8 r_plen; - struct in_addr r_network; - struct in_addr r_gateway; - in_addr_t network_net; - int option; - guint32 m; - - option = sd_dhcp_route_get_option(routes[i]); - if (!NM_IN_SET(option, - NM_DHCP_OPTION_DHCP4_CLASSLESS_STATIC_ROUTE, - NM_DHCP_OPTION_DHCP4_STATIC_ROUTE)) - continue; - - if (sd_dhcp_route_get_destination(routes[i], &r_network) < 0) - continue; - if (sd_dhcp_route_get_destination_prefix_length(routes[i], &r_plen) < 0 || r_plen > 32) - continue; - if (sd_dhcp_route_get_gateway(routes[i], &r_gateway) < 0) - continue; - - network_net = nm_utils_ip4_address_clear_host_address(r_network.s_addr, r_plen); - _nm_utils_inet4_ntop(network_net, network_net_str); - _nm_utils_inet4_ntop(r_gateway.s_addr, gateway_str); - - g_string_append_printf( - nm_gstring_add_space_delimiter(option == NM_DHCP_OPTION_DHCP4_CLASSLESS_STATIC_ROUTE - ? str_classless - : str_static), - "%s/%d %s", - network_net_str, - (int) r_plen, - gateway_str); - - if (option == NM_DHCP_OPTION_DHCP4_STATIC_ROUTE && has_classless_route) { - /* RFC 3443: if the DHCP server returns both a Classless Static Routes - * option and a Static Routes option, the DHCP client MUST ignore the - * Static Routes option. */ - continue; - } - - if (r_plen == 0 && option == NM_DHCP_OPTION_DHCP4_STATIC_ROUTE) { - /* for option 33 (static route), RFC 2132 says: - * - * The default route (0.0.0.0) is an illegal destination for a static - * route. */ - continue; - } - - if (r_plen == 0) { - /* if there are multiple default routes, we add them with differing - * metrics. */ - m = default_route_metric; - if (default_route_metric < G_MAXUINT32) - default_route_metric++; - - has_router_from_classless = TRUE; - } else - m = route_metric; - - nm_ip4_config_add_route( - ip4_config, - &((const NMPlatformIP4Route){ - .network = network_net, - .plen = r_plen, - .gateway = r_gateway.s_addr, - .rt_source = NM_IP_CONFIG_SOURCE_DHCP, - .metric = m, - .table_coerced = nm_platform_route_table_coerce(route_table), - }), - NULL); - } - - if (str_classless && str_classless->len > 0) - nm_dhcp_option_add_option(options, - _nm_dhcp_option_dhcp4_options, - NM_DHCP_OPTION_DHCP4_CLASSLESS_STATIC_ROUTE, - str_classless->str); - if (str_static && str_static->len > 0) - nm_dhcp_option_add_option(options, - _nm_dhcp_option_dhcp4_options, - NM_DHCP_OPTION_DHCP4_STATIC_ROUTE, - str_static->str); - } - - num = sd_dhcp_lease_get_router(lease, &a_router); - if (num > 0) { - guint32 default_route_metric = route_metric; - - nm_gstring_prepare(&str); - for (i = 0; i < num; i++) { - guint32 m; - - s = _nm_utils_inet4_ntop(a_router[i].s_addr, addr_str); - g_string_append(nm_gstring_add_space_delimiter(str), s); - - if (a_router[i].s_addr == 0) { - /* silently skip 0.0.0.0 */ - continue; - } - - if (has_router_from_classless) { - /* If the DHCP server returns both a Classless Static Routes option and a - * Router option, the DHCP client MUST ignore the Router option [RFC 3442]. - * - * Be more lenient and ignore the Router option only if Classless Static - * Routes contain a default gateway (as other DHCP backends do). - */ - continue; - } - - /* if there are multiple default routes, we add them with differing - * metrics. */ - m = default_route_metric; - if (default_route_metric < G_MAXUINT32) - default_route_metric++; - - nm_ip4_config_add_route( - ip4_config, - &((const NMPlatformIP4Route){ - .rt_source = NM_IP_CONFIG_SOURCE_DHCP, - .gateway = a_router[i].s_addr, - .table_coerced = nm_platform_route_table_coerce(route_table), - .metric = m, - }), - NULL); - } - nm_dhcp_option_add_option(options, - _nm_dhcp_option_dhcp4_options, - NM_DHCP_OPTION_DHCP4_ROUTER, - str->str); - } - - if (sd_dhcp_lease_get_mtu(lease, &mtu) >= 0 && mtu) { - nm_dhcp_option_add_option_u64(options, - _nm_dhcp_option_dhcp4_options, - NM_DHCP_OPTION_DHCP4_INTERFACE_MTU, - mtu); - nm_ip4_config_set_mtu(ip4_config, mtu, NM_IP_CONFIG_SOURCE_DHCP); - } - - num = sd_dhcp_lease_get_ntp(lease, &addr_list); - if (num > 0) { - nm_gstring_prepare(&str); - for (i = 0; i < num; i++) { - _nm_utils_inet4_ntop(addr_list[i].s_addr, addr_str); - g_string_append(nm_gstring_add_space_delimiter(str), addr_str); - } - nm_dhcp_option_add_option(options, - _nm_dhcp_option_dhcp4_options, - NM_DHCP_OPTION_DHCP4_NTP_SERVER, - str->str); - } - - if (sd_dhcp_lease_get_root_path(lease, &s) >= 0) { - nm_dhcp_option_add_option(options, - _nm_dhcp_option_dhcp4_options, - NM_DHCP_OPTION_DHCP4_ROOT_PATH, - s); - } - - if (sd_dhcp_lease_get_t1(lease, &renewal) >= 0) { - nm_dhcp_option_add_option_u64(options, - _nm_dhcp_option_dhcp4_options, - NM_DHCP_OPTION_DHCP4_RENEWAL_T1_TIME, - renewal); - } - - if (sd_dhcp_lease_get_t2(lease, &rebinding) >= 0) { - nm_dhcp_option_add_option_u64(options, - _nm_dhcp_option_dhcp4_options, - NM_DHCP_OPTION_DHCP4_REBINDING_T2_TIME, - rebinding); - } - - if (sd_dhcp_lease_get_timezone(lease, &s) >= 0) { - nm_dhcp_option_add_option(options, - _nm_dhcp_option_dhcp4_options, - NM_DHCP_OPTION_DHCP4_NEW_TZDB_TIMEZONE, - s); - } - - if (sd_dhcp_lease_get_vendor_specific(lease, &data, &data_len) >= 0) - metered = !!memmem(data, data_len, "ANDROID_METERED", NM_STRLEN("ANDROID_METERED")); - nm_ip4_config_set_metered(ip4_config, metered); - - num = nm_sd_dhcp_lease_get_private_options(lease, &private_options); - if (num > 0) { - for (i = 0; i < num; i++) { - char *option_string; - - option_string = nm_utils_bin2hexstr_full(private_options[i].data, - private_options[i].data_len, - ':', - FALSE, - NULL); - if (!options) { - g_free(option_string); - continue; - } - nm_dhcp_option_take_option(options, - _nm_dhcp_option_dhcp4_options, - private_options[i].code, - option_string); - } - } - NM_SET_OUT(out_options, g_steal_pointer(&options)); - return g_steal_pointer(&ip4_config); -} - -/*****************************************************************************/ - -static void -bound4_handle(NMDhcpSystemd *self, gboolean extended) -{ - NMDhcpSystemdPrivate *priv = NM_DHCP_SYSTEMD_GET_PRIVATE(self); - const char * iface = nm_dhcp_client_get_iface(NM_DHCP_CLIENT(self)); - gs_unref_object NMIP4Config *ip4_config = NULL; - gs_unref_hashtable GHashTable *options = NULL; - sd_dhcp_lease * lease = NULL; - GError * error = NULL; - - if (sd_dhcp_client_get_lease(priv->client4, &lease) < 0 || !lease) { - _LOGW("no lease!"); - nm_dhcp_client_set_state(NM_DHCP_CLIENT(self), NM_DHCP_STATE_FAIL, NULL, NULL); - return; - } - - _LOGD("lease available"); - - ip4_config = lease_to_ip4_config(nm_dhcp_client_get_multi_idx(NM_DHCP_CLIENT(self)), - iface, - nm_dhcp_client_get_ifindex(NM_DHCP_CLIENT(self)), - lease, - nm_dhcp_client_get_route_table(NM_DHCP_CLIENT(self)), - nm_dhcp_client_get_route_metric(NM_DHCP_CLIENT(self)), - &options, - &error); - if (!ip4_config) { - _LOGW("%s", error->message); - g_clear_error(&error); - nm_dhcp_client_set_state(NM_DHCP_CLIENT(self), NM_DHCP_STATE_FAIL, NULL, NULL); - return; - } - - nm_dhcp_option_add_requests_to_options(options, _nm_dhcp_option_dhcp4_options); - dhcp_lease_save(lease, priv->lease_file); - - nm_dhcp_client_set_state(NM_DHCP_CLIENT(self), - extended ? NM_DHCP_STATE_EXTENDED : NM_DHCP_STATE_BOUND, - NM_IP_CONFIG_CAST(ip4_config), - options); -} - -static int -dhcp_event_cb(sd_dhcp_client *client, int event, gpointer user_data) -{ - NMDhcpSystemd * self = NM_DHCP_SYSTEMD(user_data); - NMDhcpSystemdPrivate *priv = NM_DHCP_SYSTEMD_GET_PRIVATE(self); - char addr_str[INET_ADDRSTRLEN]; - sd_dhcp_lease * lease = NULL; - struct in_addr addr; - int r; - - nm_assert(priv->client4 == client); - - _LOGD("client event %d", event); - - switch (event) { - case SD_DHCP_CLIENT_EVENT_EXPIRED: - nm_dhcp_client_set_state(NM_DHCP_CLIENT(user_data), NM_DHCP_STATE_EXPIRE, NULL, NULL); - break; - case SD_DHCP_CLIENT_EVENT_STOP: - nm_dhcp_client_set_state(NM_DHCP_CLIENT(user_data), NM_DHCP_STATE_FAIL, NULL, NULL); - break; - case SD_DHCP_CLIENT_EVENT_RENEW: - case SD_DHCP_CLIENT_EVENT_IP_CHANGE: - bound4_handle(self, TRUE); - break; - case SD_DHCP_CLIENT_EVENT_IP_ACQUIRE: - bound4_handle(self, FALSE); - break; - case SD_DHCP_CLIENT_EVENT_SELECTING: - r = sd_dhcp_client_get_lease(priv->client4, &lease); - if (r < 0) - return r; - r = sd_dhcp_lease_get_server_identifier(lease, &addr); - if (r < 0) - return r; - if (nm_dhcp_client_server_id_is_rejected(NM_DHCP_CLIENT(user_data), &addr)) { - _LOGD("server-id %s is in the reject-list, ignoring", - nm_utils_inet_ntop(AF_INET, &addr, addr_str)); - return -ENOMSG; - } - break; - default: - _LOGW("unhandled DHCP event %d", event); - break; - } - - return 0; -} - -static gboolean -ip4_start(NMDhcpClient *client, - const char * dhcp_anycast_addr, - const char * last_ip4_address, - GError ** error) -{ - nm_auto(sd_dhcp_client_unrefp) sd_dhcp_client *sd_client = NULL; - NMDhcpSystemd * self = NM_DHCP_SYSTEMD(client); - NMDhcpSystemdPrivate * priv = NM_DHCP_SYSTEMD_GET_PRIVATE(self); - gs_free char * lease_file = NULL; - GBytes * hwaddr; - const uint8_t * hwaddr_arr; - gsize hwaddr_len; - int arp_type; - GBytes * client_id; - gs_unref_bytes GBytes *client_id_new = NULL; - GBytes * vendor_class_identifier; - const uint8_t * client_id_arr; - size_t client_id_len; - struct in_addr last_addr = {0}; - const char * hostname; - const char * mud_url; - int r, i; - - g_return_val_if_fail(!priv->client4, FALSE); - g_return_val_if_fail(!priv->client6, FALSE); - - r = sd_dhcp_client_new(&sd_client, FALSE); - if (r < 0) { - nm_utils_error_set_errno(error, r, "failed to create dhcp-client: %s"); - return FALSE; - } - - _LOGT("dhcp-client4: set %p", sd_client); - - r = sd_dhcp_client_attach_event(sd_client, NULL, 0); - if (r < 0) { - nm_utils_error_set_errno(error, r, "failed to attach event: %s"); - return FALSE; - } - - hwaddr = nm_dhcp_client_get_hw_addr(client); - if (!hwaddr || !(hwaddr_arr = g_bytes_get_data(hwaddr, &hwaddr_len)) - || (arp_type = nm_utils_arp_type_detect_from_hwaddrlen(hwaddr_len)) < 0) { - nm_utils_error_set_literal(error, NM_UTILS_ERROR_UNKNOWN, "invalid MAC address"); - return FALSE; - } - r = sd_dhcp_client_set_mac(sd_client, hwaddr_arr, hwaddr_len, (guint16) arp_type); - if (r < 0) { - nm_utils_error_set_errno(error, r, "failed to set MAC address: %s"); - return FALSE; - } - - r = sd_dhcp_client_set_ifindex(sd_client, nm_dhcp_client_get_ifindex(client)); - if (r < 0) { - nm_utils_error_set_errno(error, r, "failed to set ifindex: %s"); - return FALSE; - } - - nm_dhcp_utils_get_leasefile_path(AF_INET, - "internal", - nm_dhcp_client_get_iface(client), - nm_dhcp_client_get_uuid(client), - &lease_file); - - if (last_ip4_address) - inet_pton(AF_INET, last_ip4_address, &last_addr); - else { - nm_auto(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL; - - dhcp_lease_load(&lease, lease_file); - if (lease) - sd_dhcp_lease_get_address(lease, &last_addr); - } - - if (last_addr.s_addr) { - r = sd_dhcp_client_set_request_address(sd_client, &last_addr); - if (r < 0) { - nm_utils_error_set_errno(error, r, "failed to set last IPv4 address: %s"); - return FALSE; - } - } - - client_id = nm_dhcp_client_get_client_id(client); - if (!client_id) { - client_id_new = nm_utils_dhcp_client_id_mac(arp_type, hwaddr_arr, hwaddr_len); - client_id = client_id_new; - } - - if (!(client_id_arr = g_bytes_get_data(client_id, &client_id_len)) || client_id_len < 2) { - /* invalid client-ids are not expected. */ - nm_assert_not_reached(); - - nm_utils_error_set_literal(error, NM_UTILS_ERROR_UNKNOWN, "no valid IPv4 client-id"); - return FALSE; - } - - /* Note that we always set a client-id. In particular for infiniband that is necessary, - * see https://tools.ietf.org/html/rfc4390#section-2.1 . */ - r = sd_dhcp_client_set_client_id(sd_client, - client_id_arr[0], - client_id_arr + 1, - NM_MIN(client_id_len - 1, _NM_SD_MAX_CLIENT_ID_LEN)); - if (r < 0) { - nm_utils_error_set_errno(error, r, "failed to set IPv4 client-id: %s"); - return FALSE; - } - - /* Add requested options */ - for (i = 0; _nm_dhcp_option_dhcp4_options[i].name; i++) { - if (_nm_dhcp_option_dhcp4_options[i].include) { - nm_assert(_nm_dhcp_option_dhcp4_options[i].option_num <= 255); - r = sd_dhcp_client_set_request_option(sd_client, - _nm_dhcp_option_dhcp4_options[i].option_num); - nm_assert(r >= 0 || r == -EEXIST); - } - } - - hostname = nm_dhcp_client_get_hostname(client); - if (hostname) { - /* FIXME: sd-dhcp decides which hostname/FQDN option to send (12 or 81) - * only based on whether the hostname has a domain part or not. At the - * moment there is no way to force one or another. - */ - r = sd_dhcp_client_set_hostname(sd_client, hostname); - if (r < 0) { - nm_utils_error_set_errno(error, r, "failed to set DHCP hostname: %s"); - return FALSE; - } - } - - mud_url = nm_dhcp_client_get_mud_url(client); - if (mud_url) { - r = sd_dhcp_client_set_mud_url(sd_client, mud_url); - if (r < 0) { - nm_utils_error_set_errno(error, r, "failed to set DHCP MUDURL: %s"); - return FALSE; - } - } - - vendor_class_identifier = nm_dhcp_client_get_vendor_class_identifier(client); - if (vendor_class_identifier) { - const char *option_data; - gsize len; - - option_data = g_bytes_get_data(vendor_class_identifier, &len); - nm_assert(option_data); - nm_assert(len <= 255); - - option_data = nm_strndup_a(300, option_data, len, NULL); - - r = sd_dhcp_client_set_vendor_class_identifier(sd_client, option_data); - if (r < 0) { - nm_utils_error_set_errno(error, r, "failed to set DHCP vendor class identifier: %s"); - return FALSE; - } - } - - r = sd_dhcp_client_set_callback(sd_client, dhcp_event_cb, client); - if (r < 0) { - nm_utils_error_set_errno(error, r, "failed to set callback: %s"); - return FALSE; - } - - priv->client4 = g_steal_pointer(&sd_client); - - g_free(priv->lease_file); - priv->lease_file = g_steal_pointer(&lease_file); - - nm_dhcp_client_set_client_id(client, client_id); - - r = sd_dhcp_client_start(priv->client4); - if (r < 0) { - sd_dhcp_client_set_callback(priv->client4, NULL, NULL); - nm_clear_pointer(&priv->client4, sd_dhcp_client_unref); - nm_utils_error_set_errno(error, r, "failed to start DHCP client: %s"); - return FALSE; - } - - nm_dhcp_client_start_timeout(client); - return TRUE; -} - -static NMIP6Config * -lease_to_ip6_config(NMDedupMultiIndex *multi_idx, - const char * iface, - int ifindex, - sd_dhcp6_lease * lease, - gboolean info_only, - GHashTable ** out_options, - gint32 ts, - GError ** error) -{ - gs_unref_object NMIP6Config *ip6_config = NULL; - gs_unref_hashtable GHashTable *options = NULL; - struct in6_addr tmp_addr; - const struct in6_addr * dns; - uint32_t lft_pref, lft_valid; - char addr_str[NM_UTILS_INET_ADDRSTRLEN]; - char ** domains; - const char * s; - nm_auto_free_gstring GString *str = NULL; - int num, i; - - nm_assert(lease); - - ip6_config = nm_ip6_config_new(multi_idx, ifindex); - - options = out_options ? nm_dhcp_option_create_options_dict() : NULL; - - sd_dhcp6_lease_reset_address_iter(lease); - nm_gstring_prepare(&str); - while (sd_dhcp6_lease_get_address(lease, &tmp_addr, &lft_pref, &lft_valid) >= 0) { - const NMPlatformIP6Address address = { - .plen = 128, - .address = tmp_addr, - .timestamp = ts, - .lifetime = lft_valid, - .preferred = lft_pref, - .addr_source = NM_IP_CONFIG_SOURCE_DHCP, - }; - - nm_ip6_config_add_address(ip6_config, &address); - - _nm_utils_inet6_ntop(&tmp_addr, addr_str); - g_string_append(nm_gstring_add_space_delimiter(str), addr_str); - }; - if (str->len) - nm_dhcp_option_add_option(options, - _nm_dhcp_option_dhcp6_options, - NM_DHCP_OPTION_DHCP6_NM_IP_ADDRESS, - str->str); - - if (!info_only && nm_ip6_config_get_num_addresses(ip6_config) == 0) { - g_set_error_literal(error, - NM_MANAGER_ERROR, - NM_MANAGER_ERROR_FAILED, - "no address received in managed mode"); - return NULL; - } - - num = sd_dhcp6_lease_get_dns(lease, &dns); - if (num > 0) { - nm_gstring_prepare(&str); - for (i = 0; i < num; i++) { - _nm_utils_inet6_ntop(&dns[i], addr_str); - g_string_append(nm_gstring_add_space_delimiter(str), addr_str); - nm_ip6_config_add_nameserver(ip6_config, &dns[i]); - } - nm_dhcp_option_add_option(options, - _nm_dhcp_option_dhcp6_options, - NM_DHCP_OPTION_DHCP6_DNS_SERVERS, - str->str); - } - - num = sd_dhcp6_lease_get_domains(lease, &domains); - if (num > 0) { - nm_gstring_prepare(&str); - for (i = 0; i < num; i++) { - g_string_append(nm_gstring_add_space_delimiter(str), domains[i]); - nm_ip6_config_add_search(ip6_config, domains[i]); - } - nm_dhcp_option_add_option(options, - _nm_dhcp_option_dhcp6_options, - NM_DHCP_OPTION_DHCP6_DOMAIN_LIST, - str->str); - } - - if (sd_dhcp6_lease_get_fqdn(lease, &s) >= 0) { - nm_dhcp_option_add_option(options, - _nm_dhcp_option_dhcp6_options, - NM_DHCP_OPTION_DHCP6_FQDN, - s); - } - - NM_SET_OUT(out_options, g_steal_pointer(&options)); - return g_steal_pointer(&ip6_config); -} - -static void -bound6_handle(NMDhcpSystemd *self) -{ - NMDhcpSystemdPrivate *priv = NM_DHCP_SYSTEMD_GET_PRIVATE(self); - const gint32 ts = nm_utils_get_monotonic_timestamp_sec(); - const char * iface = nm_dhcp_client_get_iface(NM_DHCP_CLIENT(self)); - gs_unref_object NMIP6Config *ip6_config = NULL; - gs_unref_hashtable GHashTable *options = NULL; - gs_free_error GError *error = NULL; - NMPlatformIP6Address prefix = {0}; - sd_dhcp6_lease * lease = NULL; - - if (sd_dhcp6_client_get_lease(priv->client6, &lease) < 0 || !lease) { - _LOGW(" no lease!"); - nm_dhcp_client_set_state(NM_DHCP_CLIENT(self), NM_DHCP_STATE_FAIL, NULL, NULL); - return; - } - - _LOGD("lease available"); - - ip6_config = lease_to_ip6_config(nm_dhcp_client_get_multi_idx(NM_DHCP_CLIENT(self)), - iface, - nm_dhcp_client_get_ifindex(NM_DHCP_CLIENT(self)), - lease, - nm_dhcp_client_get_info_only(NM_DHCP_CLIENT(self)), - &options, - ts, - &error); - - if (!ip6_config) { - _LOGW("%s", error->message); - nm_dhcp_client_set_state(NM_DHCP_CLIENT(self), NM_DHCP_STATE_FAIL, NULL, NULL); - return; - } - - nm_dhcp_client_set_state(NM_DHCP_CLIENT(self), - NM_DHCP_STATE_BOUND, - NM_IP_CONFIG_CAST(ip6_config), - options); - - sd_dhcp6_lease_reset_pd_prefix_iter(lease); - while (!sd_dhcp6_lease_get_pd(lease, - &prefix.address, - &prefix.plen, - &prefix.preferred, - &prefix.lifetime)) { - prefix.timestamp = ts; - nm_dhcp_client_emit_ipv6_prefix_delegated(NM_DHCP_CLIENT(self), &prefix); - } -} - -static void -dhcp6_event_cb(sd_dhcp6_client *client, int event, gpointer user_data) -{ - NMDhcpSystemd * self = NM_DHCP_SYSTEMD(user_data); - NMDhcpSystemdPrivate *priv = NM_DHCP_SYSTEMD_GET_PRIVATE(self); - - nm_assert(priv->client6 == client); - - _LOGD("client event %d", event); - - switch (event) { - case SD_DHCP6_CLIENT_EVENT_RETRANS_MAX: - nm_dhcp_client_set_state(NM_DHCP_CLIENT(user_data), NM_DHCP_STATE_TIMEOUT, NULL, NULL); - break; - case SD_DHCP6_CLIENT_EVENT_RESEND_EXPIRE: - case SD_DHCP6_CLIENT_EVENT_STOP: - nm_dhcp_client_set_state(NM_DHCP_CLIENT(user_data), NM_DHCP_STATE_FAIL, NULL, NULL); - break; - case SD_DHCP6_CLIENT_EVENT_IP_ACQUIRE: - case SD_DHCP6_CLIENT_EVENT_INFORMATION_REQUEST: - bound6_handle(self); - break; - default: - _LOGW("unhandled event %d", event); - break; - } -} - -static gboolean -ip6_start(NMDhcpClient * client, - const char * dhcp_anycast_addr, - const struct in6_addr * ll_addr, - NMSettingIP6ConfigPrivacy privacy, - guint needed_prefixes, - GError ** error) -{ - NMDhcpSystemd * self = NM_DHCP_SYSTEMD(client); - NMDhcpSystemdPrivate * priv = NM_DHCP_SYSTEMD_GET_PRIVATE(self); - nm_auto(sd_dhcp6_client_unrefp) sd_dhcp6_client *sd_client = NULL; - const char * hostname; - const char * mud_url; - int r, i; - const guint8 * duid_arr; - gsize duid_len; - GBytes * duid; - - g_return_val_if_fail(!priv->client4, FALSE); - g_return_val_if_fail(!priv->client6, FALSE); - - if (!(duid = nm_dhcp_client_get_client_id(client)) - || !(duid_arr = g_bytes_get_data(duid, &duid_len)) || duid_len < 2) { - nm_utils_error_set_literal(error, NM_UTILS_ERROR_UNKNOWN, "missing DUID"); - g_return_val_if_reached(FALSE); - } - - r = sd_dhcp6_client_new(&sd_client); - if (r < 0) { - nm_utils_error_set_errno(error, r, "failed to create dhcp-client: %s"); - return FALSE; - } - - _LOGT("dhcp-client6: set %p", sd_client); - - if (nm_dhcp_client_get_info_only(client)) - sd_dhcp6_client_set_information_request(sd_client, 1); - - r = sd_dhcp6_client_set_iaid(sd_client, nm_dhcp_client_get_iaid(client)); - if (r < 0) { - nm_utils_error_set_errno(error, r, "failed to set IAID: %s"); - return FALSE; - } - - r = sd_dhcp6_client_set_duid(sd_client, - unaligned_read_be16(&duid_arr[0]), - &duid_arr[2], - duid_len - 2); - if (r < 0) { - nm_utils_error_set_errno(error, r, "failed to set DUID: %s"); - return FALSE; - } - - r = sd_dhcp6_client_attach_event(sd_client, NULL, 0); - if (r < 0) { - nm_utils_error_set_errno(error, r, "failed to attach event: %s"); - return FALSE; - } - - r = sd_dhcp6_client_set_ifindex(sd_client, nm_dhcp_client_get_ifindex(client)); - if (r < 0) { - nm_utils_error_set_errno(error, r, "failed to set ifindex: %s"); - return FALSE; - } - - /* Add requested options */ - for (i = 0; _nm_dhcp_option_dhcp6_options[i].name; i++) { - if (_nm_dhcp_option_dhcp6_options[i].include) { - r = sd_dhcp6_client_set_request_option(sd_client, - _nm_dhcp_option_dhcp6_options[i].option_num); - nm_assert(r >= 0 || r == -EEXIST); - } - } - - mud_url = nm_dhcp_client_get_mud_url(client); - if (mud_url) { - r = sd_dhcp6_client_set_request_mud_url(sd_client, mud_url); - if (r < 0) { - nm_utils_error_set_errno(error, r, "failed to set mud-url: %s"); - return FALSE; - } - } - - if (needed_prefixes > 0) { - if (needed_prefixes > 1) - _LOGW("dhcp-client6: only one prefix request is supported"); - /* FIXME: systemd-networkd API only allows to request a - * single prefix */ - r = sd_dhcp6_client_set_prefix_delegation(sd_client, TRUE); - if (r < 0) { - nm_utils_error_set_errno(error, r, "failed to enable prefix delegation: %s"); - return FALSE; - } - } - - r = sd_dhcp6_client_set_local_address(sd_client, ll_addr); - if (r < 0) { - nm_utils_error_set_errno(error, r, "failed to set local address: %s"); - return FALSE; - } - - hostname = nm_dhcp_client_get_hostname(client); - r = sd_dhcp6_client_set_fqdn(sd_client, hostname); - if (r < 0) { - nm_utils_error_set_errno(error, r, "failed to set DHCP hostname: %s"); - return FALSE; - } - - r = sd_dhcp6_client_set_callback(sd_client, dhcp6_event_cb, client); - if (r < 0) { - nm_utils_error_set_errno(error, r, "failed to set callback: %s"); - return FALSE; - } - - priv->client6 = g_steal_pointer(&sd_client); - - r = sd_dhcp6_client_start(priv->client6); - if (r < 0) { - sd_dhcp6_client_set_callback(priv->client6, NULL, NULL); - nm_clear_pointer(&priv->client6, sd_dhcp6_client_unref); - nm_utils_error_set_errno(error, r, "failed to start client: %s"); - return FALSE; - } - - nm_dhcp_client_start_timeout(client); - return TRUE; -} - -static void -stop(NMDhcpClient *client, gboolean release) -{ - NMDhcpSystemd * self = NM_DHCP_SYSTEMD(client); - NMDhcpSystemdPrivate *priv = NM_DHCP_SYSTEMD_GET_PRIVATE(self); - int r = 0; - - NM_DHCP_CLIENT_CLASS(nm_dhcp_systemd_parent_class)->stop(client, release); - - _LOGT("dhcp-client%d: stop %p", - priv->client4 ? '4' : '6', - priv->client4 ? (gpointer) priv->client4 : (gpointer) priv->client6); - - if (priv->client4) { - sd_dhcp_client_set_callback(priv->client4, NULL, NULL); - r = sd_dhcp_client_stop(priv->client4); - } else if (priv->client6) { - sd_dhcp6_client_set_callback(priv->client6, NULL, NULL); - r = sd_dhcp6_client_stop(priv->client6); - } - - if (r) - _LOGW("failed to stop client (%d)", r); -} - -/*****************************************************************************/ - -static void -nm_dhcp_systemd_init(NMDhcpSystemd *self) -{} - -static void -dispose(GObject *object) -{ - NMDhcpSystemdPrivate *priv = NM_DHCP_SYSTEMD_GET_PRIVATE(object); - - nm_clear_g_free(&priv->lease_file); - - if (priv->client4) { - sd_dhcp_client_stop(priv->client4); - sd_dhcp_client_unref(priv->client4); - priv->client4 = NULL; - } - - if (priv->client6) { - sd_dhcp6_client_stop(priv->client6); - sd_dhcp6_client_unref(priv->client6); - priv->client6 = NULL; - } - - G_OBJECT_CLASS(nm_dhcp_systemd_parent_class)->dispose(object); -} - -static void -nm_dhcp_systemd_class_init(NMDhcpSystemdClass *sdhcp_class) -{ - NMDhcpClientClass *client_class = NM_DHCP_CLIENT_CLASS(sdhcp_class); - GObjectClass * object_class = G_OBJECT_CLASS(sdhcp_class); - - object_class->dispose = dispose; - - client_class->ip4_start = ip4_start; - client_class->ip6_start = ip6_start; - client_class->stop = stop; -} - -const NMDhcpClientFactory _nm_dhcp_client_factory_systemd = { - .name = "systemd", - .get_type = nm_dhcp_systemd_get_type, - .experimental = TRUE, -}; - -/*****************************************************************************/ - -static GType -_get_type_per_addr_family(int addr_family) -{ - nm_assert_addr_family(addr_family); - - if (addr_family == AF_INET) - return nm_dhcp_nettools_get_type(); - return nm_dhcp_systemd_get_type(); -} - -const NMDhcpClientFactory _nm_dhcp_client_factory_internal = { - .name = "internal", - .get_type_per_addr_family = _get_type_per_addr_family, -}; diff --git a/src/dhcp/nm-dhcp-utils.c b/src/dhcp/nm-dhcp-utils.c deleted file mode 100644 index bf10e2b5..00000000 --- a/src/dhcp/nm-dhcp-utils.c +++ /dev/null @@ -1,836 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2005 - 2010 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include <unistd.h> -#include <arpa/inet.h> - -#include "nm-glib-aux/nm-dedup-multi.h" - -#include "nm-dhcp-utils.h" -#include "nm-utils.h" -#include "nm-config.h" -#include "NetworkManagerUtils.h" -#include "platform/nm-platform.h" -#include "nm-dhcp-client-logging.h" -#include "nm-core-internal.h" - -/*****************************************************************************/ - -static gboolean -ip4_process_dhcpcd_rfc3442_routes(const char * iface, - const char * str, - guint32 route_table, - guint32 route_metric, - NMIP4Config *ip4_config, - guint32 * gwaddr) -{ - gs_free const char **routes = NULL; - const char ** r; - gboolean have_routes = FALSE; - - routes = nm_utils_strsplit_set(str, " "); - if (!routes) - return FALSE; - - if ((NM_PTRARRAY_LEN(routes) % 2) != 0) { - _LOG2W(LOGD_DHCP4, iface, " classless static routes provided, but invalid"); - return FALSE; - } - - for (r = routes; *r; r += 2) { - char * slash; - NMPlatformIP4Route route; - int rt_cidr = 32; - guint32 rt_addr, rt_route; - - slash = strchr(*r, '/'); - if (slash) { - *slash = '\0'; - errno = 0; - rt_cidr = strtol(slash + 1, NULL, 10); - if (errno || rt_cidr > 32) { - _LOG2W(LOGD_DHCP4, - iface, - "DHCP provided invalid classless static route cidr: '%s'", - slash + 1); - continue; - } - } - if (inet_pton(AF_INET, *r, &rt_addr) <= 0) { - _LOG2W(LOGD_DHCP4, - iface, - "DHCP provided invalid classless static route address: '%s'", - *r); - continue; - } - if (inet_pton(AF_INET, *(r + 1), &rt_route) <= 0) { - _LOG2W(LOGD_DHCP4, - iface, - "DHCP provided invalid classless static route gateway: '%s'", - *(r + 1)); - continue; - } - - have_routes = TRUE; - if (rt_cidr == 0 && rt_addr == 0) { - /* FIXME: how to handle multiple routers? */ - *gwaddr = rt_route; - } else { - _LOG2I(LOGD_DHCP4, - iface, - " classless static route %s/%d gw %s", - *r, - rt_cidr, - *(r + 1)); - memset(&route, 0, sizeof(route)); - route.network = nm_utils_ip4_address_clear_host_address(rt_addr, rt_cidr); - route.plen = rt_cidr; - route.gateway = rt_route; - route.rt_source = NM_IP_CONFIG_SOURCE_DHCP; - route.metric = route_metric; - route.table_coerced = nm_platform_route_table_coerce(route_table); - nm_ip4_config_add_route(ip4_config, &route, NULL); - } - } - - return have_routes; -} - -static gboolean -process_dhclient_rfc3442_route(const char *const **p_octets, NMPlatformIP4Route *route) -{ - const char *const *o = *p_octets; - gs_free char * next_hop = NULL; - int addr_len; - int v_plen; - in_addr_t tmp_addr; - in_addr_t v_network = 0; - - v_plen = _nm_utils_ascii_str_to_int64(*o, 10, 0, 32, -1); - if (v_plen == -1) - return FALSE; - o++; - - addr_len = v_plen > 0 ? ((v_plen - 1) / 8) + 1 : 0; - - /* ensure there's at least the address + next hop left */ - if (NM_PTRARRAY_LEN(o) < addr_len + 4) - return FALSE; - - if (v_plen > 0) { - const char * addr[4] = {"0", "0", "0", "0"}; - gs_free char *str_addr = NULL; - int i; - - for (i = 0; i < addr_len; i++) - addr[i] = *o++; - - str_addr = g_strjoin(".", addr[0], addr[1], addr[2], addr[3], NULL); - if (inet_pton(AF_INET, str_addr, &tmp_addr) <= 0) - return FALSE; - v_network = nm_utils_ip4_address_clear_host_address(tmp_addr, v_plen); - } - - next_hop = g_strjoin(".", o[0], o[1], o[2], o[3], NULL); - o += 4; - if (inet_pton(AF_INET, next_hop, &tmp_addr) <= 0) - return FALSE; - - *route = (NMPlatformIP4Route){ - .network = v_network, - .plen = v_plen, - .gateway = tmp_addr, - }; - *p_octets = o; - return TRUE; -} - -static gboolean -ip4_process_dhclient_rfc3442_routes(const char * iface, - const char * str, - guint32 route_table, - guint32 route_metric, - NMIP4Config *ip4_config, - guint32 * gwaddr) -{ - gs_free const char **octets = NULL; - const char *const * o; - gboolean have_routes = FALSE; - - octets = nm_utils_strsplit_set_with_empty(str, " ."); - if (NM_PTRARRAY_LEN(octets) < 5) { - _LOG2W(LOGD_DHCP4, iface, "ignoring invalid classless static routes '%s'", str); - return FALSE; - } - - o = octets; - while (*o) { - NMPlatformIP4Route route; - - if (!process_dhclient_rfc3442_route(&o, &route)) { - _LOG2W(LOGD_DHCP4, iface, "ignoring invalid classless static routes"); - return have_routes; - } - - have_routes = TRUE; - if (!route.plen) { - /* gateway passed as classless static route */ - *gwaddr = route.gateway; - } else { - char b1[INET_ADDRSTRLEN]; - char b2[INET_ADDRSTRLEN]; - - /* normal route */ - route.rt_source = NM_IP_CONFIG_SOURCE_DHCP; - route.metric = route_metric; - route.table_coerced = nm_platform_route_table_coerce(route_table); - nm_ip4_config_add_route(ip4_config, &route, NULL); - - _LOG2I(LOGD_DHCP4, - iface, - " classless static route %s/%d gw %s", - _nm_utils_inet4_ntop(route.network, b1), - route.plen, - _nm_utils_inet4_ntop(route.gateway, b2)); - } - } - - return have_routes; -} - -static gboolean -ip4_process_classless_routes(const char * iface, - GHashTable * options, - guint32 route_table, - guint32 route_metric, - NMIP4Config *ip4_config, - guint32 * gwaddr) -{ - const char *str, *p; - - g_return_val_if_fail(options != NULL, FALSE); - g_return_val_if_fail(ip4_config != NULL, FALSE); - - *gwaddr = 0; - - /* dhcpd/dhclient in Fedora has support for rfc3442 implemented using a - * slightly different format: - * - * option classless-static-routes = array of (destination-descriptor ip-address); - * - * which results in: - * - * 0 192.168.0.113 25.129.210.177.132 192.168.0.113 7.2 10.34.255.6 - * - * dhcpcd supports classless static routes natively and uses this same - * option identifier with the following format: - * - * 192.168.10.0/24 192.168.1.1 10.0.0.0/8 10.17.66.41 - */ - str = g_hash_table_lookup(options, "classless_static_routes"); - - /* dhclient doesn't have actual support for rfc3442 classless static routes - * upstream. Thus, people resort to defining the option in dhclient.conf - * and using arbitrary formats like so: - * - * option rfc3442-classless-static-routes code 121 = array of unsigned integer 8; - * - * See https://lists.isc.org/pipermail/dhcp-users/2008-December/007629.html - */ - if (!str) - str = g_hash_table_lookup(options, "rfc3442_classless_static_routes"); - - /* Microsoft version; same as rfc3442 but with a different option # (249) */ - if (!str) - str = g_hash_table_lookup(options, "ms_classless_static_routes"); - - if (!str || !strlen(str)) - return FALSE; - - p = str; - while (*p) { - if (!g_ascii_isdigit(*p) && (*p != ' ') && (*p != '.') && (*p != '/')) { - _LOG2W(LOGD_DHCP4, iface, "ignoring invalid classless static routes '%s'", str); - return FALSE; - } - p++; - }; - - if (strchr(str, '/')) { - /* dhcpcd format */ - return ip4_process_dhcpcd_rfc3442_routes(iface, - str, - route_table, - route_metric, - ip4_config, - gwaddr); - } - - return ip4_process_dhclient_rfc3442_routes(iface, - str, - route_table, - route_metric, - ip4_config, - gwaddr); -} - -static void -process_classful_routes(const char * iface, - GHashTable * options, - guint32 route_table, - guint32 route_metric, - NMIP4Config *ip4_config) -{ - gs_free const char **searches = NULL; - const char ** s; - const char * str; - - str = g_hash_table_lookup(options, "static_routes"); - if (!str) - return; - - searches = nm_utils_strsplit_set(str, " "); - if (!searches) - return; - - if ((NM_PTRARRAY_LEN(searches) % 2) != 0) { - _LOG2I(LOGD_DHCP, iface, " static routes provided, but invalid"); - return; - } - - for (s = searches; *s; s += 2) { - NMPlatformIP4Route route; - guint32 rt_addr, rt_route; - - if (inet_pton(AF_INET, *s, &rt_addr) <= 0) { - _LOG2W(LOGD_DHCP, iface, "DHCP provided invalid static route address: '%s'", *s); - continue; - } - if (inet_pton(AF_INET, *(s + 1), &rt_route) <= 0) { - _LOG2W(LOGD_DHCP, iface, "DHCP provided invalid static route gateway: '%s'", *(s + 1)); - continue; - } - - // FIXME: ensure the IP address and route are sane - - memset(&route, 0, sizeof(route)); - route.network = rt_addr; - /* RFC 2132, updated by RFC 3442: - * The Static Routes option (option 33) does not provide a subnet mask - * for each route - it is assumed that the subnet mask is implicit in - * whatever network number is specified in each route entry */ - route.plen = _nm_utils_ip4_get_default_prefix(rt_addr); - if (rt_addr & ~_nm_utils_ip4_prefix_to_netmask(route.plen)) { - /* RFC 943: target not "this network"; using host routing */ - route.plen = 32; - } - route.gateway = rt_route; - route.rt_source = NM_IP_CONFIG_SOURCE_DHCP; - route.metric = route_metric; - route.table_coerced = nm_platform_route_table_coerce(route_table); - - route.network = nm_utils_ip4_address_clear_host_address(route.network, route.plen); - - nm_ip4_config_add_route(ip4_config, &route, NULL); - _LOG2I(LOGD_DHCP, - iface, - " static route %s", - nm_platform_ip4_route_to_string(&route, NULL, 0)); - } -} - -static void -process_domain_search(const char *iface, const char *str, GFunc add_func, gpointer user_data) -{ - gs_free const char **searches = NULL; - gs_free char * unescaped = NULL; - const char ** s; - char * p; - int i; - - g_return_if_fail(str != NULL); - g_return_if_fail(add_func != NULL); - - unescaped = g_strdup(str); - - p = unescaped; - do { - p = strstr(p, "\\032"); - if (!p) - break; - - /* Clear the escaped space with real spaces */ - for (i = 0; i < 4; i++) - *p++ = ' '; - } while (*p++); - - if (strchr(unescaped, '\\')) { - _LOG2W(LOGD_DHCP, iface, " invalid domain search: '%s'", unescaped); - return; - } - - searches = nm_utils_strsplit_set(unescaped, " "); - for (s = searches; searches && *s; s++) { - _LOG2I(LOGD_DHCP, iface, " domain search '%s'", *s); - add_func((gpointer) *s, user_data); - } -} - -static void -ip4_add_domain_search(gpointer data, gpointer user_data) -{ - nm_ip4_config_add_search(NM_IP4_CONFIG(user_data), (const char *) data); -} - -NMIP4Config * -nm_dhcp_utils_ip4_config_from_options(NMDedupMultiIndex *multi_idx, - int ifindex, - const char * iface, - GHashTable * options, - guint32 route_table, - guint32 route_metric) -{ - gs_unref_object NMIP4Config *ip4_config = NULL; - guint32 tmp_addr; - in_addr_t addr; - NMPlatformIP4Address address; - char * str = NULL; - gboolean gateway_has = FALSE; - guint32 gateway = 0; - guint8 plen = 0; - char sbuf[NM_UTILS_INET_ADDRSTRLEN]; - - g_return_val_if_fail(options != NULL, NULL); - - ip4_config = nm_ip4_config_new(multi_idx, ifindex); - memset(&address, 0, sizeof(address)); - address.timestamp = nm_utils_get_monotonic_timestamp_sec(); - - str = g_hash_table_lookup(options, "ip_address"); - if (str && (inet_pton(AF_INET, str, &addr) > 0)) - _LOG2I(LOGD_DHCP4, iface, " address %s", str); - else - return NULL; - - str = g_hash_table_lookup(options, "subnet_mask"); - if (str && (inet_pton(AF_INET, str, &tmp_addr) > 0)) { - plen = nm_utils_ip4_netmask_to_prefix(tmp_addr); - _LOG2I(LOGD_DHCP4, iface, " plen %d (%s)", plen, str); - } else { - /* Get default netmask for the IP according to appropriate class. */ - plen = _nm_utils_ip4_get_default_prefix(addr); - _LOG2I(LOGD_DHCP4, iface, " plen %d (default)", plen); - } - nm_platform_ip4_address_set_addr(&address, addr, plen); - - /* Routes: if the server returns classless static routes, we MUST ignore - * the 'static_routes' option. - */ - if (!ip4_process_classless_routes(iface, - options, - route_table, - route_metric, - ip4_config, - &gateway)) - process_classful_routes(iface, options, route_table, route_metric, ip4_config); - - if (gateway) { - _LOG2I(LOGD_DHCP4, iface, " gateway %s", _nm_utils_inet4_ntop(gateway, sbuf)); - gateway_has = TRUE; - } else { - /* If the gateway wasn't provided as a classless static route with a - * subnet length of 0, try to find it using the old-style 'routers' option. - */ - str = g_hash_table_lookup(options, "routers"); - if (str) { - gs_free const char **routers = nm_utils_strsplit_set(str, " "); - const char ** s; - - for (s = routers; routers && *s; s++) { - /* FIXME: how to handle multiple routers? */ - if (inet_pton(AF_INET, *s, &gateway) > 0) { - _LOG2I(LOGD_DHCP4, iface, " gateway %s", *s); - gateway_has = TRUE; - break; - } else - _LOG2W(LOGD_DHCP4, iface, "ignoring invalid gateway '%s'", *s); - } - } - } - - if (gateway_has) { - const NMPlatformIP4Route r = { - .rt_source = NM_IP_CONFIG_SOURCE_DHCP, - .gateway = gateway, - .table_coerced = nm_platform_route_table_coerce(route_table), - .metric = route_metric, - }; - - nm_ip4_config_add_route(ip4_config, &r, NULL); - } - - str = g_hash_table_lookup(options, "dhcp_lease_time"); - if (str) { - address.lifetime = address.preferred = strtoul(str, NULL, 10); - _LOG2I(LOGD_DHCP4, iface, " lease time %u", address.lifetime); - } - - address.addr_source = NM_IP_CONFIG_SOURCE_DHCP; - nm_ip4_config_add_address(ip4_config, &address); - - str = g_hash_table_lookup(options, "host_name"); - if (str) - _LOG2I(LOGD_DHCP4, iface, " hostname '%s'", str); - - str = g_hash_table_lookup(options, "domain_name_servers"); - if (str) { - gs_free const char **dns = nm_utils_strsplit_set(str, " "); - const char ** s; - - for (s = dns; dns && *s; s++) { - if (inet_pton(AF_INET, *s, &tmp_addr) > 0) { - if (tmp_addr) { - nm_ip4_config_add_nameserver(ip4_config, tmp_addr); - _LOG2I(LOGD_DHCP4, iface, " nameserver '%s'", *s); - } - } else - _LOG2W(LOGD_DHCP4, iface, "ignoring invalid nameserver '%s'", *s); - } - } - - str = g_hash_table_lookup(options, "domain_name"); - if (str) { - gs_free const char **domains = nm_utils_strsplit_set(str, " "); - const char ** s; - - for (s = domains; domains && *s; s++) { - _LOG2I(LOGD_DHCP4, iface, " domain name '%s'", *s); - nm_ip4_config_add_domain(ip4_config, *s); - } - } - - str = g_hash_table_lookup(options, "domain_search"); - if (str) - process_domain_search(iface, str, ip4_add_domain_search, ip4_config); - - str = g_hash_table_lookup(options, "netbios_name_servers"); - if (str) { - gs_free const char **nbns = nm_utils_strsplit_set(str, " "); - const char ** s; - - for (s = nbns; nbns && *s; s++) { - if (inet_pton(AF_INET, *s, &tmp_addr) > 0) { - if (tmp_addr) { - nm_ip4_config_add_wins(ip4_config, tmp_addr); - _LOG2I(LOGD_DHCP4, iface, " wins '%s'", *s); - } - } else - _LOG2W(LOGD_DHCP4, iface, "ignoring invalid WINS server '%s'", *s); - } - } - - str = g_hash_table_lookup(options, "interface_mtu"); - if (str) { - int int_mtu; - - errno = 0; - int_mtu = strtol(str, NULL, 10); - if (NM_IN_SET(errno, EINVAL, ERANGE)) - return NULL; - - if (int_mtu > 576) - nm_ip4_config_set_mtu(ip4_config, int_mtu, NM_IP_CONFIG_SOURCE_DHCP); - } - - str = g_hash_table_lookup(options, "nis_domain"); - if (str) { - _LOG2I(LOGD_DHCP4, iface, " NIS domain '%s'", str); - nm_ip4_config_set_nis_domain(ip4_config, str); - } - - str = g_hash_table_lookup(options, "nis_servers"); - if (str) { - gs_free const char **nis = nm_utils_strsplit_set(str, " "); - const char ** s; - - for (s = nis; nis && *s; s++) { - if (inet_pton(AF_INET, *s, &tmp_addr) > 0) { - if (tmp_addr) { - nm_ip4_config_add_nis_server(ip4_config, tmp_addr); - _LOG2I(LOGD_DHCP4, iface, " nis '%s'", *s); - } - } else - _LOG2W(LOGD_DHCP4, iface, "ignoring invalid NIS server '%s'", *s); - } - } - - str = g_hash_table_lookup(options, "vendor_encapsulated_options"); - nm_ip4_config_set_metered(ip4_config, str && strstr(str, "ANDROID_METERED")); - - return g_steal_pointer(&ip4_config); -} - -/*****************************************************************************/ - -static void -ip6_add_domain_search(gpointer data, gpointer user_data) -{ - nm_ip6_config_add_search(NM_IP6_CONFIG(user_data), (const char *) data); -} - -NMPlatformIP6Address -nm_dhcp_utils_ip6_prefix_from_options(GHashTable *options) -{ - gs_strfreev char ** split_addr = NULL; - NMPlatformIP6Address address = { - 0, - }; - struct in6_addr tmp_addr; - char * str = NULL; - int prefix; - - g_return_val_if_fail(options != NULL, address); - - str = g_hash_table_lookup(options, "ip6_prefix"); - if (!str) - return address; - - split_addr = g_strsplit(str, "/", 2); - if (split_addr[0] == NULL && split_addr[1] == NULL) { - nm_log_warn(LOGD_DHCP6, "DHCP returned prefix without length '%s'", str); - return address; - } - - if (!inet_pton(AF_INET6, split_addr[0], &tmp_addr)) { - nm_log_warn(LOGD_DHCP6, "DHCP returned invalid prefix '%s'", str); - return address; - } - - prefix = _nm_utils_ascii_str_to_int64(split_addr[1], 10, 0, 128, -1); - if (prefix < 0) { - nm_log_warn(LOGD_DHCP6, "DHCP returned prefix with invalid length '%s'", str); - return address; - } - - address.address = tmp_addr; - address.addr_source = NM_IP_CONFIG_SOURCE_DHCP; - address.plen = prefix; - address.timestamp = nm_utils_get_monotonic_timestamp_sec(); - - str = g_hash_table_lookup(options, "max_life"); - if (str) - address.lifetime = strtoul(str, NULL, 10); - - str = g_hash_table_lookup(options, "preferred_life"); - if (str) - address.preferred = strtoul(str, NULL, 10); - - return address; -} - -NMIP6Config * -nm_dhcp_utils_ip6_config_from_options(NMDedupMultiIndex *multi_idx, - int ifindex, - const char * iface, - GHashTable * options, - gboolean info_only) -{ - gs_unref_object NMIP6Config *ip6_config = NULL; - struct in6_addr tmp_addr; - NMPlatformIP6Address address; - char * str = NULL; - - g_return_val_if_fail(options != NULL, NULL); - - memset(&address, 0, sizeof(address)); - address.plen = 128; - address.timestamp = nm_utils_get_monotonic_timestamp_sec(); - - ip6_config = nm_ip6_config_new(multi_idx, ifindex); - - str = g_hash_table_lookup(options, "max_life"); - if (str) { - address.lifetime = strtoul(str, NULL, 10); - _LOG2I(LOGD_DHCP6, iface, " valid_lft %u", address.lifetime); - } - - str = g_hash_table_lookup(options, "preferred_life"); - if (str) { - address.preferred = strtoul(str, NULL, 10); - _LOG2I(LOGD_DHCP6, iface, " preferred_lft %u", address.preferred); - } - - str = g_hash_table_lookup(options, "ip6_address"); - if (str) { - if (!inet_pton(AF_INET6, str, &tmp_addr)) { - _LOG2W(LOGD_DHCP6, iface, "(%s): DHCP returned invalid address '%s'", iface, str); - return NULL; - } - - address.address = tmp_addr; - address.addr_source = NM_IP_CONFIG_SOURCE_DHCP; - nm_ip6_config_add_address(ip6_config, &address); - _LOG2I(LOGD_DHCP6, iface, " address %s", str); - } else if (info_only == FALSE) { - /* No address in Managed mode is a hard error */ - return NULL; - } - - str = g_hash_table_lookup(options, "host_name"); - if (str) - _LOG2I(LOGD_DHCP6, iface, " hostname '%s'", str); - - str = g_hash_table_lookup(options, "dhcp6_name_servers"); - if (str) { - gs_free const char **dns = nm_utils_strsplit_set(str, " "); - const char ** s; - - for (s = dns; dns && *s; s++) { - if (inet_pton(AF_INET6, *s, &tmp_addr) > 0) { - if (!IN6_IS_ADDR_UNSPECIFIED(&tmp_addr)) { - nm_ip6_config_add_nameserver(ip6_config, &tmp_addr); - _LOG2I(LOGD_DHCP6, iface, " nameserver '%s'", *s); - } - } else - _LOG2W(LOGD_DHCP6, iface, "ignoring invalid nameserver '%s'", *s); - } - } - - str = g_hash_table_lookup(options, "dhcp6_domain_search"); - if (str) - process_domain_search(iface, str, ip6_add_domain_search, ip6_config); - - return g_steal_pointer(&ip6_config); -} - -char * -nm_dhcp_utils_duid_to_string(GBytes *duid) -{ - gconstpointer data; - gsize len; - - g_return_val_if_fail(duid, NULL); - - data = g_bytes_get_data(duid, &len); - return nm_utils_bin2hexstr_full(data, len, ':', FALSE, NULL); -} - -/** - * nm_dhcp_utils_client_id_string_to_bytes: - * @client_id: the client ID string - * - * Accepts either a hex string ("aa:bb:cc") representing a binary client ID - * (the first byte is assumed to be the 'type' field per RFC 2132 section 9.14), - * or a string representing a non-hardware-address client ID, in which case - * the 'type' field is set to 0. - * - * Returns: the binary client ID suitable for sending over the wire - * to the DHCP server. - */ -GBytes * -nm_dhcp_utils_client_id_string_to_bytes(const char *client_id) -{ - GBytes *bytes = NULL; - guint len; - char * c; - - g_return_val_if_fail(client_id && client_id[0], NULL); - - /* Try as hex encoded */ - if (strchr(client_id, ':')) { - bytes = nm_utils_hexstr2bin(client_id); - - /* the result must be at least two bytes long, - * because @client_id contains a delimiter - * but nm_utils_hexstr2bin() does not allow - * leading nor trailing delimiters. */ - nm_assert(!bytes || g_bytes_get_size(bytes) >= 2); - } - if (!bytes) { - /* Fall back to string */ - len = strlen(client_id); - c = g_malloc(len + 1); - c[0] = 0; /* type: non-hardware address per RFC 2132 section 9.14 */ - memcpy(c + 1, client_id, len); - bytes = g_bytes_new_take(c, len + 1); - } - - return bytes; -} - -/** - * nm_dhcp_utils_get_leasefile_path: - * @addr_family: the IP address family - * @plugin_name: the name of the plugin part of the lease file name - * @iface: the interface name to which the lease relates to - * @uuid: uuid of the connection to which the lease relates to - * @out_leasefile_path: will store the computed lease file path - * - * Constructs the lease file name on the basis of the calling plugin, - * interface name and connection uuid. Then returns in @out_leasefile_path - * the full path of the lease filename. - * - * Returns: TRUE if the lease file already exists, FALSE otherwise. - */ -gboolean -nm_dhcp_utils_get_leasefile_path(int addr_family, - const char *plugin_name, - const char *iface, - const char *uuid, - char ** out_leasefile_path) -{ - gs_free char *rundir_path = NULL; - gs_free char *statedir_path = NULL; - - rundir_path = g_strdup_printf(NMRUNDIR "/%s%s-%s-%s.lease", - plugin_name, - addr_family == AF_INET6 ? "6" : "", - uuid, - iface); - - if (g_file_test(rundir_path, G_FILE_TEST_EXISTS)) { - *out_leasefile_path = g_steal_pointer(&rundir_path); - return TRUE; - } - - statedir_path = g_strdup_printf(NMSTATEDIR "/%s%s-%s-%s.lease", - plugin_name, - addr_family == AF_INET6 ? "6" : "", - uuid, - iface); - - if (g_file_test(statedir_path, G_FILE_TEST_EXISTS)) { - *out_leasefile_path = g_steal_pointer(&statedir_path); - return TRUE; - } - - if (nm_config_get_configure_and_quit(nm_config_get()) == NM_CONFIG_CONFIGURE_AND_QUIT_INITRD) - *out_leasefile_path = g_steal_pointer(&rundir_path); - else - *out_leasefile_path = g_steal_pointer(&statedir_path); - return FALSE; -} - -char * -nm_dhcp_utils_get_dhcp6_event_id(GHashTable *lease) -{ - const char *start; - const char *iaid; - - if (!lease) - return NULL; - - iaid = g_hash_table_lookup(lease, "iaid"); - if (!iaid) - return NULL; - - start = g_hash_table_lookup(lease, "life_starts"); - if (!start) - return NULL; - - return g_strdup_printf("%s|%s", iaid, start); -} diff --git a/src/dhcp/nm-dhcp-utils.h b/src/dhcp/nm-dhcp-utils.h deleted file mode 100644 index c72d9617..00000000 --- a/src/dhcp/nm-dhcp-utils.h +++ /dev/null @@ -1,43 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2014 Red Hat, Inc. - */ - -#ifndef __NETWORKMANAGER_DHCP_UTILS_H__ -#define __NETWORKMANAGER_DHCP_UTILS_H__ - -#include <stdlib.h> - -#include "nm-ip4-config.h" -#include "nm-ip6-config.h" - -NMIP4Config *nm_dhcp_utils_ip4_config_from_options(struct _NMDedupMultiIndex *multi_idx, - int ifindex, - const char * iface, - GHashTable * options, - guint32 route_table, - guint32 route_metric); - -NMIP6Config *nm_dhcp_utils_ip6_config_from_options(struct _NMDedupMultiIndex *multi_idx, - int ifindex, - const char * iface, - GHashTable * options, - gboolean info_only); - -NMPlatformIP6Address nm_dhcp_utils_ip6_prefix_from_options(GHashTable *options); - -char *nm_dhcp_utils_duid_to_string(GBytes *duid); - -GBytes *nm_dhcp_utils_client_id_string_to_bytes(const char *client_id); - -gboolean nm_dhcp_utils_get_leasefile_path(int addr_family, - const char *plugin_name, - const char *iface, - const char *uuid, - char ** out_leasefile_path); - -char **nm_dhcp_parse_search_list(guint8 *data, size_t n_data); - -char *nm_dhcp_utils_get_dhcp6_event_id(GHashTable *lease); - -#endif /* __NETWORKMANAGER_DHCP_UTILS_H__ */ diff --git a/src/dhcp/tests/meson.build b/src/dhcp/tests/meson.build deleted file mode 100644 index 59a647cc..00000000 --- a/src/dhcp/tests/meson.build +++ /dev/null @@ -1,22 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1+ - -test_units = [ - 'test-dhcp-dhclient', - 'test-dhcp-utils', -] - -foreach test_unit: test_units - exe = executable( - test_unit, - test_unit + '.c', - dependencies: libnetwork_manager_test_dep, - c_args: test_c_flags, - ) - - test( - 'dhcp/' + test_unit, - test_script, - args: test_args + [exe.full_path()], - timeout: default_test_timeout, - ) -endforeach diff --git a/src/dhcp/tests/test-dhclient-commented-duid.leases b/src/dhcp/tests/test-dhclient-commented-duid.leases deleted file mode 100644 index 3e46ae7d..00000000 --- a/src/dhcp/tests/test-dhclient-commented-duid.leases +++ /dev/null @@ -1,2 +0,0 @@ -#default-duid "\000\001\000\001\030y\246\023`g \354Lp"; - diff --git a/src/dhcp/tests/test-dhclient-duid.leases b/src/dhcp/tests/test-dhclient-duid.leases deleted file mode 100644 index 229331d4..00000000 --- a/src/dhcp/tests/test-dhclient-duid.leases +++ /dev/null @@ -1,2 +0,0 @@ -default-duid "\000\001\000\001\030y\246\023`g \354Lp"; - diff --git a/src/dhcp/tests/test-dhcp-dhclient.c b/src/dhcp/tests/test-dhcp-dhclient.c deleted file mode 100644 index da24f3c5..00000000 --- a/src/dhcp/tests/test-dhcp-dhclient.c +++ /dev/null @@ -1,1341 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2010 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include <unistd.h> -#include <arpa/inet.h> -#include <linux/rtnetlink.h> - -#include "nm-glib-aux/nm-dedup-multi.h" - -#include "NetworkManagerUtils.h" -#include "dhcp/nm-dhcp-dhclient-utils.h" -#include "dhcp/nm-dhcp-utils.h" -#include "nm-utils.h" -#include "nm-ip4-config.h" -#include "platform/nm-platform.h" - -#include "nm-test-utils-core.h" - -#define TEST_DIR NM_BUILD_SRCDIR "/src/dhcp/tests" -#define TEST_MUDURL "https://example.com/mud.json" - -static void -test_config(const char * orig, - const char * expected, - int addr_family, - const char * hostname, - guint32 timeout, - gboolean use_fqdn, - NMDhcpHostnameFlags hostname_flags, - const char * dhcp_client_id, - GBytes * expected_new_client_id, - const char * iface, - const char * anycast_addr, - const char * mud_url) -{ - gs_free char *new = NULL; - gs_unref_bytes GBytes *client_id = NULL; - gs_unref_bytes GBytes *new_client_id = NULL; - - if (dhcp_client_id) { - client_id = nm_dhcp_utils_client_id_string_to_bytes(dhcp_client_id); - g_assert(client_id); - } - - new = nm_dhcp_dhclient_create_config(iface, - addr_family, - client_id, - anycast_addr, - hostname, - timeout, - use_fqdn, - hostname_flags, - mud_url, - NULL, - "/path/to/dhclient.conf", - orig, - &new_client_id); - g_assert(new != NULL); - - if (!nm_streq(new, expected)) { - g_message("\n* OLD ---------------------------------\n" - "%s" - "\n- NEW -----------------------------------\n" - "%s" - "\n+ EXPECTED ++++++++++++++++++++++++++++++\n" - "%s" - "\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", - orig, - new, - expected); - } - g_assert_cmpstr(new, ==, expected); - - if (expected_new_client_id) { - g_assert(new_client_id); - g_assert(g_bytes_equal(new_client_id, expected_new_client_id)); - } else - g_assert(new_client_id == NULL); -} - -/*****************************************************************************/ - -static const char *orig_missing_expected = - "# Created by NetworkManager\n" - "\n\n" - "option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;\n" - "option ms-classless-static-routes code 249 = array of unsigned integer 8;\n" - "option wpad code 252 = string;\n" - "\n" - "also request rfc3442-classless-static-routes;\n" - "also request ms-classless-static-routes;\n" - "also request static-routes;\n" - "also request wpad;\n" - "also request ntp-servers;\n" - "also request root-path;\n" - "\n"; - -static void -test_orig_missing(void) -{ - test_config(NULL, - orig_missing_expected, - AF_INET, - NULL, - 0, - FALSE, - NM_DHCP_HOSTNAME_FLAG_NONE, - NULL, - NULL, - "eth0", - NULL, - NULL); -} - -/*****************************************************************************/ - -static const char *orig_missing_add_mud_url_expected = - "# Created by NetworkManager\n" - "\n" - "option mudurl code 161 = text;\n" - "send mudurl \"https://example.com/mud.json\";\n\n" - "option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;\n" - "option ms-classless-static-routes code 249 = array of unsigned integer 8;\n" - "option wpad code 252 = string;\n" - "\n" - "also request rfc3442-classless-static-routes;\n" - "also request ms-classless-static-routes;\n" - "also request static-routes;\n" - "also request wpad;\n" - "also request ntp-servers;\n" - "also request root-path;\n" - "\n"; - -static void -test_orig_missing_add_mud_url(void) -{ - test_config(NULL, - orig_missing_add_mud_url_expected, - AF_INET, - NULL, - 0, - FALSE, - NM_DHCP_HOSTNAME_FLAG_NONE, - NULL, - NULL, - "eth0", - NULL, - TEST_MUDURL); -} - -/*****************************************************************************/ - -static const char *override_client_id_orig = "send dhcp-client-identifier 00:30:04:20:7A:08;\n"; - -static const char *override_client_id_expected = - "# Created by NetworkManager\n" - "# Merged from /path/to/dhclient.conf\n" - "\n" - "send dhcp-client-identifier 11:22:33:44:55:66; # added by NetworkManager\n" - "\n" - "option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;\n" - "option ms-classless-static-routes code 249 = array of unsigned integer 8;\n" - "option wpad code 252 = string;\n" - "\n" - "also request rfc3442-classless-static-routes;\n" - "also request ms-classless-static-routes;\n" - "also request static-routes;\n" - "also request wpad;\n" - "also request ntp-servers;\n" - "also request root-path;\n" - "\n"; - -static void -test_override_client_id(void) -{ - test_config(override_client_id_orig, - override_client_id_expected, - AF_INET, - NULL, - 0, - FALSE, - NM_DHCP_HOSTNAME_FLAG_NONE, - "11:22:33:44:55:66", - NULL, - "eth0", - NULL, - NULL); -} - -/*****************************************************************************/ - -static const char *quote_client_id_expected = - "# Created by NetworkManager\n" - "\n" - "send dhcp-client-identifier \"\\x00abcd\"; # added by NetworkManager\n" - "\n" - "option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;\n" - "option ms-classless-static-routes code 249 = array of unsigned integer 8;\n" - "option wpad code 252 = string;\n" - "\n" - "also request rfc3442-classless-static-routes;\n" - "also request ms-classless-static-routes;\n" - "also request static-routes;\n" - "also request wpad;\n" - "also request ntp-servers;\n" - "also request root-path;\n" - "\n"; - -static void -test_quote_client_id(void) -{ - test_config(NULL, - quote_client_id_expected, - AF_INET, - NULL, - 0, - FALSE, - NM_DHCP_HOSTNAME_FLAG_NONE, - "abcd", - NULL, - "eth0", - NULL, - NULL); -} - -/*****************************************************************************/ - -static const char *quote_client_id_expected_2 = - "# Created by NetworkManager\n" - "\n" - "send dhcp-client-identifier 00:61:5c:62:63; # added by NetworkManager\n" - "\n" - "option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;\n" - "option ms-classless-static-routes code 249 = array of unsigned integer 8;\n" - "option wpad code 252 = string;\n" - "\n" - "also request rfc3442-classless-static-routes;\n" - "also request ms-classless-static-routes;\n" - "also request static-routes;\n" - "also request wpad;\n" - "also request ntp-servers;\n" - "also request root-path;\n" - "\n"; - -static void -test_quote_client_id_2(void) -{ - test_config(NULL, - quote_client_id_expected_2, - AF_INET, - NULL, - 0, - FALSE, - NM_DHCP_HOSTNAME_FLAG_NONE, - "a\\bc", - NULL, - "eth0", - NULL, - NULL); -} - -/*****************************************************************************/ - -static const char *hex_zero_client_id_expected = - "# Created by NetworkManager\n" - "\n" - "send dhcp-client-identifier 00:11:22:33; # added by NetworkManager\n" - "\n" - "option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;\n" - "option ms-classless-static-routes code 249 = array of unsigned integer 8;\n" - "option wpad code 252 = string;\n" - "\n" - "also request rfc3442-classless-static-routes;\n" - "also request ms-classless-static-routes;\n" - "also request static-routes;\n" - "also request wpad;\n" - "also request ntp-servers;\n" - "also request root-path;\n" - "\n"; - -static void -test_hex_zero_client_id(void) -{ - test_config(NULL, - hex_zero_client_id_expected, - AF_INET, - NULL, - 0, - FALSE, - NM_DHCP_HOSTNAME_FLAG_NONE, - "00:11:22:33", - NULL, - "eth0", - NULL, - NULL); -} - -/*****************************************************************************/ - -static const char *ascii_client_id_expected = - "# Created by NetworkManager\n" - "\n" - "send dhcp-client-identifier \"\\x00qb:cd:ef:12:34:56\"; # added by NetworkManager\n" - "\n" - "option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;\n" - "option ms-classless-static-routes code 249 = array of unsigned integer 8;\n" - "option wpad code 252 = string;\n" - "\n" - "also request rfc3442-classless-static-routes;\n" - "also request ms-classless-static-routes;\n" - "also request static-routes;\n" - "also request wpad;\n" - "also request ntp-servers;\n" - "also request root-path;\n" - "\n"; - -static void -test_ascii_client_id(void) -{ - test_config(NULL, - ascii_client_id_expected, - AF_INET, - NULL, - 0, - FALSE, - NM_DHCP_HOSTNAME_FLAG_NONE, - "qb:cd:ef:12:34:56", - NULL, - "eth0", - NULL, - NULL); -} - -/*****************************************************************************/ - -static const char *hex_single_client_id_expected = - "# Created by NetworkManager\n" - "\n" - "send dhcp-client-identifier ab:cd:0e:12:34:56; # added by NetworkManager\n" - "\n" - "option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;\n" - "option ms-classless-static-routes code 249 = array of unsigned integer 8;\n" - "option wpad code 252 = string;\n" - "\n" - "also request rfc3442-classless-static-routes;\n" - "also request ms-classless-static-routes;\n" - "also request static-routes;\n" - "also request wpad;\n" - "also request ntp-servers;\n" - "also request root-path;\n" - "\n"; - -static void -test_hex_single_client_id(void) -{ - test_config(NULL, - hex_single_client_id_expected, - AF_INET, - NULL, - 0, - FALSE, - NM_DHCP_HOSTNAME_FLAG_NONE, - "ab:cd:e:12:34:56", - NULL, - "eth0", - NULL, - NULL); -} - -/*****************************************************************************/ - -static const char *existing_hex_client_id_orig = "send dhcp-client-identifier 10:30:04:20:7A:08;\n"; - -static const char *existing_hex_client_id_expected = - "# Created by NetworkManager\n" - "# Merged from /path/to/dhclient.conf\n" - "\n" - "send dhcp-client-identifier 10:30:04:20:7A:08;\n" - "\n" - "option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;\n" - "option ms-classless-static-routes code 249 = array of unsigned integer 8;\n" - "option wpad code 252 = string;\n" - "\n" - "also request rfc3442-classless-static-routes;\n" - "also request ms-classless-static-routes;\n" - "also request static-routes;\n" - "also request wpad;\n" - "also request ntp-servers;\n" - "also request root-path;\n" - "\n"; - -static void -test_existing_hex_client_id(void) -{ - gs_unref_bytes GBytes *new_client_id = NULL; - const guint8 bytes[] = {0x10, 0x30, 0x04, 0x20, 0x7A, 0x08}; - - new_client_id = g_bytes_new(bytes, sizeof(bytes)); - test_config(existing_hex_client_id_orig, - existing_hex_client_id_expected, - AF_INET, - NULL, - 0, - FALSE, - NM_DHCP_HOSTNAME_FLAG_NONE, - NULL, - new_client_id, - "eth0", - NULL, - NULL); -} - -/*****************************************************************************/ - -static const char *existing_escaped_client_id_orig = - "send dhcp-client-identifier \"\\044test\\xfe\";\n"; - -static const char *existing_escaped_client_id_expected = - "# Created by NetworkManager\n" - "# Merged from /path/to/dhclient.conf\n" - "\n" - "send dhcp-client-identifier \"\\044test\\xfe\";\n" - "\n" - "option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;\n" - "option ms-classless-static-routes code 249 = array of unsigned integer 8;\n" - "option wpad code 252 = string;\n" - "\n" - "also request rfc3442-classless-static-routes;\n" - "also request ms-classless-static-routes;\n" - "also request static-routes;\n" - "also request wpad;\n" - "also request ntp-servers;\n" - "also request root-path;\n" - "\n"; - -static void -test_existing_escaped_client_id(void) -{ - gs_unref_bytes GBytes *new_client_id = NULL; - - new_client_id = g_bytes_new("$test\xfe", 6); - test_config(existing_escaped_client_id_orig, - existing_escaped_client_id_expected, - AF_INET, - NULL, - 0, - FALSE, - NM_DHCP_HOSTNAME_FLAG_NONE, - NULL, - new_client_id, - "eth0", - NULL, - NULL); -} - -/*****************************************************************************/ - -#define EACID "qb:cd:ef:12:34:56" - -static const char *existing_ascii_client_id_orig = - "send dhcp-client-identifier \"\\x00" EACID "\";\n"; - -static const char *existing_ascii_client_id_expected = - "# Created by NetworkManager\n" - "# Merged from /path/to/dhclient.conf\n" - "\n" - "send dhcp-client-identifier \"\\x00" EACID "\";\n" - "\n" - "option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;\n" - "option ms-classless-static-routes code 249 = array of unsigned integer 8;\n" - "option wpad code 252 = string;\n" - "\n" - "also request rfc3442-classless-static-routes;\n" - "also request ms-classless-static-routes;\n" - "also request static-routes;\n" - "also request wpad;\n" - "also request ntp-servers;\n" - "also request root-path;\n" - "\n"; - -static void -test_existing_ascii_client_id(void) -{ - gs_unref_bytes GBytes *new_client_id = NULL; - char buf[NM_STRLEN(EACID) + 1] = {0}; - - memcpy(buf + 1, EACID, NM_STRLEN(EACID)); - new_client_id = g_bytes_new(buf, sizeof(buf)); - test_config(existing_ascii_client_id_orig, - existing_ascii_client_id_expected, - AF_INET, - NULL, - 0, - FALSE, - NM_DHCP_HOSTNAME_FLAG_NONE, - NULL, - new_client_id, - "eth0", - NULL, - NULL); -} -/*****************************************************************************/ - -static const char *fqdn_expected = - "# Created by NetworkManager\n" - "\n" - "send fqdn.fqdn \"foo.bar.com\"; # added by NetworkManager\n" - "send fqdn.encoded on;\n" - "send fqdn.server-update off;\n" - "send fqdn.no-client-update on;\n" - "\n" - "option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;\n" - "option ms-classless-static-routes code 249 = array of unsigned integer 8;\n" - "option wpad code 252 = string;\n" - "\n" - "also request rfc3442-classless-static-routes;\n" - "also request ms-classless-static-routes;\n" - "also request static-routes;\n" - "also request wpad;\n" - "also request ntp-servers;\n" - "also request root-path;\n\n"; - -static void -test_fqdn(void) -{ - test_config(NULL, - fqdn_expected, - AF_INET, - "foo.bar.com", - 0, - TRUE, - NM_DHCP_HOSTNAME_FLAG_FQDN_ENCODED | NM_DHCP_HOSTNAME_FLAG_FQDN_NO_UPDATE, - NULL, - NULL, - "eth0", - NULL, - NULL); -} - -static const char *fqdn_options_override_orig = - "\n" - "send fqdn.fqdn \"foobar.com\"\n" /* NM must ignore this ... */ - "send fqdn.encoded off;\n" /* ... and honor these */ - "send fqdn.server-update off;\n"; - -static const char *fqdn_options_override_expected = - "# Created by NetworkManager\n" - "# Merged from /path/to/dhclient.conf\n" - "\n" - "send fqdn.fqdn \"example2.com\"; # added by NetworkManager\n" - "send fqdn.encoded off;\n" - "send fqdn.server-update on;\n" - "send fqdn.no-client-update off;\n" - "\n" - "option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;\n" - "option ms-classless-static-routes code 249 = array of unsigned integer 8;\n" - "option wpad code 252 = string;\n" - "\n" - "also request rfc3442-classless-static-routes;\n" - "also request ms-classless-static-routes;\n" - "also request static-routes;\n" - "also request wpad;\n" - "also request ntp-servers;\n" - "also request root-path;\n" - "\n" - "# FQDN options from /path/to/dhclient.conf\n" - "send fqdn.encoded off;\n" - "send fqdn.server-update off;\n\n"; - -static void -test_fqdn_options_override(void) -{ - test_config(fqdn_options_override_orig, - fqdn_options_override_expected, - AF_INET, - "example2.com", - 0, - NM_DHCP_HOSTNAME_FLAG_FQDN_SERV_UPDATE, - TRUE, - NULL, - NULL, - "eth0", - NULL, - NULL); -} - -/*****************************************************************************/ - -static const char *override_hostname_orig = "send host-name \"foobar\";\n"; - -static const char *override_hostname_expected = - "# Created by NetworkManager\n" - "# Merged from /path/to/dhclient.conf\n" - "\n" - "send host-name \"blahblah\"; # added by NetworkManager\n" - "\n" - "option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;\n" - "option ms-classless-static-routes code 249 = array of unsigned integer 8;\n" - "option wpad code 252 = string;\n" - "\n" - "also request rfc3442-classless-static-routes;\n" - "also request ms-classless-static-routes;\n" - "also request static-routes;\n" - "also request wpad;\n" - "also request ntp-servers;\n" - "also request root-path;\n" - "\n"; - -static void -test_override_hostname(void) -{ - test_config(override_hostname_orig, - override_hostname_expected, - AF_INET, - "blahblah", - 0, - FALSE, - NM_DHCP_HOSTNAME_FLAG_NONE, - NULL, - NULL, - "eth0", - NULL, - NULL); -} - -/*****************************************************************************/ - -static const char *override_hostname6_orig = "send fqdn.fqdn \"foobar\";\n"; - -static const char *override_hostname6_expected = - "# Created by NetworkManager\n" - "# Merged from /path/to/dhclient.conf\n" - "\n" - "send fqdn.fqdn \"blahblah.local\"; # added by NetworkManager\n" - "send fqdn.server-update on;\n" - "\n" - "also request dhcp6.name-servers;\n" - "also request dhcp6.domain-search;\n" - "also request dhcp6.client-id;\n" - "\n"; - -static void -test_override_hostname6(void) -{ - test_config(override_hostname6_orig, - override_hostname6_expected, - AF_INET6, - "blahblah.local", - 0, - TRUE, - NM_DHCP_HOSTNAME_FLAG_FQDN_SERV_UPDATE, - NULL, - NULL, - "eth0", - NULL, - NULL); -} - -/*****************************************************************************/ - -static const char *nonfqdn_hostname6_expected = - "# Created by NetworkManager\n" - "\n" - "send fqdn.fqdn \"blahblah\"; # added by NetworkManager\n" - "send fqdn.no-client-update on;\n" - "\n" - "also request dhcp6.name-servers;\n" - "also request dhcp6.domain-search;\n" - "also request dhcp6.client-id;\n" - "\n"; - -static void -test_nonfqdn_hostname6(void) -{ - /* Non-FQDN hostname can now be used with dhclient */ - test_config(NULL, - nonfqdn_hostname6_expected, - AF_INET6, - "blahblah", - 0, - TRUE, - NM_DHCP_HOSTNAME_FLAG_FQDN_NO_UPDATE, - NULL, - NULL, - "eth0", - NULL, - NULL); -} - -/*****************************************************************************/ - -static const char *existing_alsoreq_orig = "also request something;\n" - "also request another-thing;\n"; - -static const char *existing_alsoreq_expected = - "# Created by NetworkManager\n" - "# Merged from /path/to/dhclient.conf\n" - "\n\n" - "option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;\n" - "option ms-classless-static-routes code 249 = array of unsigned integer 8;\n" - "option wpad code 252 = string;\n" - "\n" - "also request something;\n" - "also request another-thing;\n" - "also request rfc3442-classless-static-routes;\n" - "also request ms-classless-static-routes;\n" - "also request static-routes;\n" - "also request wpad;\n" - "also request ntp-servers;\n" - "also request root-path;\n" - "\n"; - -static void -test_existing_alsoreq(void) -{ - test_config(existing_alsoreq_orig, - existing_alsoreq_expected, - AF_INET, - NULL, - 0, - FALSE, - NM_DHCP_HOSTNAME_FLAG_NONE, - NULL, - NULL, - "eth0", - NULL, - NULL); -} - -/*****************************************************************************/ - -static const char *existing_req_orig = "request something;\n" - "also request some-other-thing;\n" - "request another-thing;\n" - "also request yet-another-thing;\n"; - -static const char *existing_req_expected = - "# Created by NetworkManager\n" - "# Merged from /path/to/dhclient.conf\n" - "\n\n" - "option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;\n" - "option ms-classless-static-routes code 249 = array of unsigned integer 8;\n" - "option wpad code 252 = string;\n" - "\n" - "request; # override dhclient defaults\n" - "also request another-thing;\n" - "also request yet-another-thing;\n" - "also request rfc3442-classless-static-routes;\n" - "also request ms-classless-static-routes;\n" - "also request static-routes;\n" - "also request wpad;\n" - "also request ntp-servers;\n" - "also request root-path;\n" - "\n"; - -static void -test_existing_req(void) -{ - test_config(existing_req_orig, - existing_req_expected, - AF_INET, - NULL, - 0, - FALSE, - NM_DHCP_HOSTNAME_FLAG_NONE, - NULL, - NULL, - "eth0", - NULL, - NULL); -} - -/*****************************************************************************/ - -static const char *existing_multiline_alsoreq_orig = - "also request something another-thing yet-another-thing\n" - " foobar baz blah;\n"; - -static const char *existing_multiline_alsoreq_expected = - "# Created by NetworkManager\n" - "# Merged from /path/to/dhclient.conf\n" - "\n\n" - "option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;\n" - "option ms-classless-static-routes code 249 = array of unsigned integer 8;\n" - "option wpad code 252 = string;\n" - "\n" - "also request something;\n" - "also request another-thing;\n" - "also request yet-another-thing;\n" - "also request foobar;\n" - "also request baz;\n" - "also request blah;\n" - "also request rfc3442-classless-static-routes;\n" - "also request ms-classless-static-routes;\n" - "also request static-routes;\n" - "also request wpad;\n" - "also request ntp-servers;\n" - "also request root-path;\n" - "\n"; - -static void -test_existing_multiline_alsoreq(void) -{ - test_config(existing_multiline_alsoreq_orig, - existing_multiline_alsoreq_expected, - AF_INET, - NULL, - 0, - FALSE, - NM_DHCP_HOSTNAME_FLAG_NONE, - NULL, - NULL, - "eth0", - NULL, - NULL); -} - -/*****************************************************************************/ - -static void -test_one_duid(const char *escaped, const guint8 *unescaped, guint len) -{ - gs_unref_bytes GBytes *t1 = NULL; - gs_unref_bytes GBytes *t2 = NULL; - gs_free char * w = NULL; - - t1 = nm_dhcp_dhclient_unescape_duid(escaped); - g_assert(t1); - g_assert(nm_utils_gbytes_equal_mem(t1, unescaped, len)); - - t2 = g_bytes_new(unescaped, len); - w = nm_dhcp_dhclient_escape_duid(t2); - g_assert(w); - g_assert_cmpstr(escaped, ==, w); -} - -static void -test_duids(void) -{ - const guint8 test1_u[] = - {0x00, 0x01, 0x00, 0x01, 0x13, 0x6f, 0x13, 0x6e, 0x00, 0x22, 0xfa, 0x8c, 0xd6, 0xc2}; - const char *test1_s = "\\000\\001\\000\\001\\023o\\023n\\000\\\"\\372\\214\\326\\302"; - - const guint8 test2_u[] = - {0x00, 0x01, 0x00, 0x01, 0x17, 0x57, 0xee, 0x39, 0x00, 0x23, 0x15, 0x08, 0x7E, 0xac}; - const char *test2_s = "\\000\\001\\000\\001\\027W\\3569\\000#\\025\\010~\\254"; - - const guint8 test3_u[] = - {0x00, 0x01, 0x00, 0x01, 0x17, 0x58, 0xe8, 0x58, 0x00, 0x23, 0x15, 0x08, 0x7e, 0xac}; - const char *test3_s = "\\000\\001\\000\\001\\027X\\350X\\000#\\025\\010~\\254"; - - const guint8 test4_u[] = - {0x00, 0x01, 0x00, 0x01, 0x15, 0xd5, 0x31, 0x97, 0x00, 0x16, 0xeb, 0x04, 0x45, 0x18}; - const char *test4_s = "\\000\\001\\000\\001\\025\\3251\\227\\000\\026\\353\\004E\\030"; - - const char *bad_s = "\\000\\001\\000\\001\\425\\3251\\227\\000\\026\\353\\004E\\030"; - - test_one_duid(test1_s, test1_u, sizeof(test1_u)); - test_one_duid(test2_s, test2_u, sizeof(test2_u)); - test_one_duid(test3_s, test3_u, sizeof(test3_u)); - test_one_duid(test4_s, test4_u, sizeof(test4_u)); - - /* Invalid octal digit */ - g_assert(nm_dhcp_dhclient_unescape_duid(bad_s) == NULL); -} - -static void -test_read_duid_from_leasefile(void) -{ - const guint8 expected[] = - {0x00, 0x01, 0x00, 0x01, 0x18, 0x79, 0xa6, 0x13, 0x60, 0x67, 0x20, 0xec, 0x4c, 0x70}; - gs_unref_bytes GBytes *duid = NULL; - GError * error = NULL; - - duid = nm_dhcp_dhclient_read_duid(TEST_DIR "/test-dhclient-duid.leases", &error); - nmtst_assert_success(duid, error); - - g_assert(nm_utils_gbytes_equal_mem(duid, expected, G_N_ELEMENTS(expected))); -} - -static void -test_read_commented_duid_from_leasefile(void) -{ - GBytes *duid; - GError *error = NULL; - - duid = nm_dhcp_dhclient_read_duid(TEST_DIR "/test-dhclient-commented-duid.leases", &error); - g_assert_no_error(error); - g_assert(duid == NULL); -} - -/*****************************************************************************/ - -static void -_save_duid(const char *path, const guint8 *duid_bin, gsize duid_len) -{ - gs_unref_bytes GBytes *duid = NULL; - GError * error = NULL; - gboolean success; - - g_assert(path); - g_assert(duid_bin); - g_assert(duid_len > 0); - - duid = g_bytes_new(duid_bin, duid_len); - success = nm_dhcp_dhclient_save_duid(path, duid, &error); - nmtst_assert_success(success, error); -} - -static void -test_write_duid(void) -{ - const guint8 duid[] = {000, 001, 000, 001, 027, 'X', 0350, 'X', 0, '#', 025, 010, '~', 0254}; - const char * expected_contents = - "default-duid \"\\000\\001\\000\\001\\027X\\350X\\000#\\025\\010~\\254\";\n"; - GError * error = NULL; - gs_free char *contents = NULL; - gboolean success; - const char * path = "test-dhclient-write-duid.leases"; - - _save_duid(path, duid, G_N_ELEMENTS(duid)); - - success = g_file_get_contents(path, &contents, NULL, &error); - nmtst_assert_success(success, error); - - unlink(path); - - g_assert_cmpstr(expected_contents, ==, contents); -} - -static void -test_write_existing_duid(void) -{ - const guint8 duid[] = - {000, 001, 000, 001, 023, 'o', 023, 'n', 000, '"', 0372, 0214, 0326, 0302}; - const char *original_contents = - "default-duid \"\\000\\001\\000\\001\\027X\\350X\\000#\\025\\010~\\254\";\n"; - const char *expected_contents = - "default-duid \"\\000\\001\\000\\001\\023o\\023n\\000\\\"\\372\\214\\326\\302\";\n"; - GError * error = NULL; - gs_free char *contents = NULL; - gboolean success; - const char * path = "test-dhclient-write-existing-duid.leases"; - - success = g_file_set_contents(path, original_contents, -1, &error); - nmtst_assert_success(success, error); - - /* Save other DUID; should be overwritten */ - _save_duid(path, duid, G_N_ELEMENTS(duid)); - - /* reread original contents */ - success = g_file_get_contents(path, &contents, NULL, &error); - nmtst_assert_success(success, error); - - unlink(path); - g_assert_cmpstr(expected_contents, ==, contents); -} - -static const guint8 DUID_BIN[] = - {000, 001, 000, 001, 023, 'o', 023, 'n', 000, '"', 0372, 0214, 0326, 0302}; -#define DUID "\\000\\001\\000\\001\\023o\\023n\\000\\\"\\372\\214\\326\\302" - -static void -test_write_existing_commented_duid(void) -{ -#define ORIG_CONTENTS "#default-duid \"\\000\\001\\000\\001\\027X\\350X\\000#\\025\\010~\\254\";\n" - const char * expected_contents = "default-duid \"" DUID "\";\n" ORIG_CONTENTS; - GError * error = NULL; - gs_free char *contents = NULL; - gboolean success; - const char * path = "test-dhclient-write-existing-commented-duid.leases"; - - success = g_file_set_contents(path, ORIG_CONTENTS, -1, &error); - nmtst_assert_success(success, error); - - /* Save other DUID; should be saved on top */ - _save_duid(path, DUID_BIN, G_N_ELEMENTS(DUID_BIN)); - - /* reread original contents */ - success = g_file_get_contents(path, &contents, NULL, &error); - nmtst_assert_success(success, error); - - unlink(path); - g_assert_cmpstr(expected_contents, ==, contents); -#undef ORIG_CONTENTS -} - -static void -test_write_existing_multiline_duid(void) -{ -#define ORIG_CONTENTS \ - "### Commented old DUID ###\n" \ - "#default-duid \"\\000\\001\\000\\001\\027X\\350X\\000#\\025\\010~\\254\";\n" - const char * expected_contents = "default-duid \"" DUID "\";\n" ORIG_CONTENTS; - GError * error = NULL; - gs_free char * contents = NULL; - gboolean success; - nmtst_auto_unlinkfile char *path = - g_strdup("test-dhclient-write-existing-multiline-duid.leases"); - - success = g_file_set_contents(path, ORIG_CONTENTS, -1, &error); - nmtst_assert_success(success, error); - - _save_duid(path, DUID_BIN, G_N_ELEMENTS(DUID_BIN)); - - success = g_file_get_contents(path, &contents, NULL, &error); - nmtst_assert_success(success, error); - - g_assert_cmpstr(expected_contents, ==, contents); -#undef ORIG_CONTENTS -} - -/*****************************************************************************/ - -static const char *interface1_orig = "interface \"eth0\" {\n" - "\talso request my-option;\n" - "\tinitial-delay 5;\n" - "}\n" - "interface \"eth1\" {\n" - "\talso request another-option;\n" - "\tinitial-delay 0;\n" - "}\n" - "\n" - "also request yet-another-option;\n"; - -static const char *interface1_expected = - "# Created by NetworkManager\n" - "# Merged from /path/to/dhclient.conf\n" - "\n" - "initial-delay 5;\n" - "\n" - "option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;\n" - "option ms-classless-static-routes code 249 = array of unsigned integer 8;\n" - "option wpad code 252 = string;\n" - "\n" - "also request my-option;\n" - "also request yet-another-option;\n" - "also request rfc3442-classless-static-routes;\n" - "also request ms-classless-static-routes;\n" - "also request static-routes;\n" - "also request wpad;\n" - "also request ntp-servers;\n" - "also request root-path;\n" - "\n"; - -static void -test_interface1(void) -{ - test_config(interface1_orig, - interface1_expected, - AF_INET, - NULL, - 0, - FALSE, - NM_DHCP_HOSTNAME_FLAG_NONE, - NULL, - NULL, - "eth0", - NULL, - NULL); -} - -/*****************************************************************************/ - -static const char *interface2_orig = "interface eth0 {\n" - "\talso request my-option;\n" - "\tinitial-delay 5;\n" - " }\n" - "interface eth1 {\n" - "\tinitial-delay 0;\n" - "\trequest another-option;\n" - " } \n" - "\n" - "also request yet-another-option;\n"; - -static const char *interface2_expected = - "# Created by NetworkManager\n" - "# Merged from /path/to/dhclient.conf\n" - "\n" - "initial-delay 0;\n" - "\n" - "option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;\n" - "option ms-classless-static-routes code 249 = array of unsigned integer 8;\n" - "option wpad code 252 = string;\n" - "\n" - "request; # override dhclient defaults\n" - "also request another-option;\n" - "also request yet-another-option;\n" - "also request rfc3442-classless-static-routes;\n" - "also request ms-classless-static-routes;\n" - "also request static-routes;\n" - "also request wpad;\n" - "also request ntp-servers;\n" - "also request root-path;\n" - "\n"; - -static void -test_interface2(void) -{ - test_config(interface2_orig, - interface2_expected, - AF_INET, - NULL, - 0, - FALSE, - NM_DHCP_HOSTNAME_FLAG_NONE, - NULL, - NULL, - "eth1", - NULL, - NULL); -} - -static void -test_structured(void) -{ - gs_unref_bytes GBytes *new_client_id = NULL; - const guint8 bytes[] = "sad-and-useless"; - - static const char *const orig = - "interface \"eth0\" { \n" - " send host-name \"useless.example.com\";\n" - " hardware ethernet de:ad:80:86:ba:be;\n" - " send dhcp-client-identifier \"sad-and-useless\";\n" - " script \"/bin/useless\";\n" - " send dhcp-lease-time 8086;\n" - " request subnet-mask, broadcast-address, time-offset, routers,\n" - " domain-search, domain-name, host-name;\n" - " require subnet-mask;\n" - "} \n" - "\n" - " interface \"eth1\" { \n" - " send host-name \"sad.example.com\";\n" - " hardware ethernet de:ca:f6:66:ca:fe;\n" - " send dhcp-client-identifier \"useless-and-miserable\";\n" - " script \"/bin/miserable\";\n" - " send dhcp-lease-time 1337;\n" - " request subnet-mask, broadcast-address, time-offset, routers,\n" - " domain-search, domain-name, domain-name-servers, host-name;\n" - " require subnet-mask, domain-name-servers;\n" - " if not option domain-name = \"example.org\" {\n" - " prepend domain-name-servers 127.0.0.1;\n" - " } else {\n" - " prepend domain-name-servers 127.0.0.2;\n" - " } \n" - " } \n" - "\n" - "pseudo \"secondary\" \"eth0\" { \n" - " send dhcp-client-identifier \"sad-useless-and-secondary\";\n" - " script \"/bin/secondary\";\n" - " send host-name \"secondary.useless.example.com\";\n" - " send dhcp-lease-time 666;\n" - " request routers;\n" - " require routers;\n" - " } \n" - "\n" - " pseudo \"tertiary\" \"eth0\" { \n" - " send dhcp-client-identifier \"sad-useless-and-tertiary\";\n" - " script \"/bin/tertiary\";\n" - " send host-name \"tertiary.useless.example.com\";\n" - "} \n" - "\n" - " alias{ \n" - " interface \"eth0\";\n" - " fixed-address 192.0.2.1;\n" - " option subnet-mask 255.255.255.0;\n" - " } \n" - " lease { \n" - " interface \"eth0\";\n" - " fixed-address 192.0.2.2;\n" - " option subnet-mask 255.255.255.0;\n" - " } \n" - "if not option domain-name = \"example.org\" {\n" - " prepend domain-name-servers 127.0.0.1;\n" - " if not option domain-name = \"useless.example.com\" {\n" - " prepend domain-name-servers 127.0.0.2;\n" - " }\n" - "}\n"; - - static const char *const expected = - "# Created by NetworkManager\n" - "# Merged from /path/to/dhclient.conf\n" - "\n" - "send host-name \"useless.example.com\";\n" - "hardware ethernet de:ad:80:86:ba:be;\n" - "send dhcp-client-identifier \"sad-and-useless\";\n" - "send dhcp-lease-time 8086;\n" - "require subnet-mask;\n" - "if not option domain-name = \"example.org\" {\n" - "prepend domain-name-servers 127.0.0.1;\n" - "if not option domain-name = \"useless.example.com\" {\n" - "prepend domain-name-servers 127.0.0.2;\n" - "}\n" - "}\n" - "\n" - "option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;\n" - "option ms-classless-static-routes code 249 = array of unsigned integer 8;\n" - "option wpad code 252 = string;\n" - "\n" - "request; # override dhclient defaults\n" - "also request subnet-mask;\n" - "also request broadcast-address;\n" - "also request time-offset;\n" - "also request routers;\n" - "also request domain-search;\n" - "also request domain-name;\n" - "also request host-name;\n" - "also request rfc3442-classless-static-routes;\n" - "also request ms-classless-static-routes;\n" - "also request static-routes;\n" - "also request wpad;\n" - "also request ntp-servers;\n" - "also request root-path;\n" - "\n"; - - new_client_id = g_bytes_new(bytes, sizeof(bytes) - 1); - test_config(orig, - expected, - AF_INET, - NULL, - 0, - FALSE, - NM_DHCP_HOSTNAME_FLAG_NONE, - NULL, - new_client_id, - "eth0", - NULL, - NULL); -} - -static void -test_config_req_intf(void) -{ - static const char *const orig = "request subnet-mask, broadcast-address, routers,\n" - "\trfc3442-classless-static-routes,\n" - "\tinterface-mtu, host-name, domain-name, domain-search,\n" - "\tdomain-name-servers, nis-domain, nis-servers,\n" - "\tnds-context, nds-servers, nds-tree-name,\n" - "\tnetbios-name-servers, netbios-dd-server,\n" - "\tnetbios-node-type, netbios-scope, ntp-servers;\n" - ""; - static const char *const expected = - "# Created by NetworkManager\n" - "# Merged from /path/to/dhclient.conf\n" - "\n" - "\n" - "option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;\n" - "option ms-classless-static-routes code 249 = array of unsigned integer 8;\n" - "option wpad code 252 = string;\n" - "\n" - "request; # override dhclient defaults\n" - "also request subnet-mask;\n" - "also request broadcast-address;\n" - "also request routers;\n" - "also request rfc3442-classless-static-routes;\n" - "also request interface-mtu;\n" - "also request host-name;\n" - "also request domain-name;\n" - "also request domain-search;\n" - "also request domain-name-servers;\n" - "also request nis-domain;\n" - "also request nis-servers;\n" - "also request nds-context;\n" - "also request nds-servers;\n" - "also request nds-tree-name;\n" - "also request netbios-name-servers;\n" - "also request netbios-dd-server;\n" - "also request netbios-node-type;\n" - "also request netbios-scope;\n" - "also request ntp-servers;\n" - "also request ms-classless-static-routes;\n" - "also request static-routes;\n" - "also request wpad;\n" - "also request root-path;\n" - "\n"; - - test_config(orig, - expected, - AF_INET, - NULL, - 0, - FALSE, - NM_DHCP_HOSTNAME_FLAG_NONE, - NULL, - NULL, - "eth0", - NULL, - NULL); -} - -/*****************************************************************************/ - -NMTST_DEFINE(); - -int -main(int argc, char **argv) -{ - nmtst_init_with_logging(&argc, &argv, NULL, "DEFAULT"); - - g_test_add_func("/dhcp/dhclient/orig_missing", test_orig_missing); - g_test_add_func("/dhcp/dhclient/orig_missing_add_mud_url", test_orig_missing_add_mud_url); - g_test_add_func("/dhcp/dhclient/override_client_id", test_override_client_id); - g_test_add_func("/dhcp/dhclient/quote_client_id/1", test_quote_client_id); - g_test_add_func("/dhcp/dhclient/quote_client_id/2", test_quote_client_id_2); - g_test_add_func("/dhcp/dhclient/hex_zero_client_id", test_hex_zero_client_id); - g_test_add_func("/dhcp/dhclient/ascii_client_id", test_ascii_client_id); - g_test_add_func("/dhcp/dhclient/hex_single_client_id", test_hex_single_client_id); - g_test_add_func("/dhcp/dhclient/existing-hex-client-id", test_existing_hex_client_id); - g_test_add_func("/dhcp/dhclient/existing-client-id", test_existing_escaped_client_id); - g_test_add_func("/dhcp/dhclient/existing-ascii-client-id", test_existing_ascii_client_id); - g_test_add_func("/dhcp/dhclient/fqdn", test_fqdn); - g_test_add_func("/dhcp/dhclient/fqdn_options_override", test_fqdn_options_override); - g_test_add_func("/dhcp/dhclient/override_hostname", test_override_hostname); - g_test_add_func("/dhcp/dhclient/override_hostname6", test_override_hostname6); - g_test_add_func("/dhcp/dhclient/nonfqdn_hostname6", test_nonfqdn_hostname6); - g_test_add_func("/dhcp/dhclient/existing_req", test_existing_req); - g_test_add_func("/dhcp/dhclient/existing_alsoreq", test_existing_alsoreq); - g_test_add_func("/dhcp/dhclient/existing_multiline_alsoreq", test_existing_multiline_alsoreq); - g_test_add_func("/dhcp/dhclient/duids", test_duids); - g_test_add_func("/dhcp/dhclient/interface/1", test_interface1); - g_test_add_func("/dhcp/dhclient/interface/2", test_interface2); - g_test_add_func("/dhcp/dhclient/config/req_intf", test_config_req_intf); - g_test_add_func("/dhcp/dhclient/structured", test_structured); - - g_test_add_func("/dhcp/dhclient/read_duid_from_leasefile", test_read_duid_from_leasefile); - g_test_add_func("/dhcp/dhclient/read_commented_duid_from_leasefile", - test_read_commented_duid_from_leasefile); - - g_test_add_func("/dhcp/dhclient/write_duid", test_write_duid); - g_test_add_func("/dhcp/dhclient/write_existing_duid", test_write_existing_duid); - g_test_add_func("/dhcp/dhclient/write_existing_commented_duid", - test_write_existing_commented_duid); - g_test_add_func("/dhcp/dhclient/write_existing_multiline_duid", - test_write_existing_multiline_duid); - - return g_test_run(); -} diff --git a/src/dhcp/tests/test-dhcp-utils.c b/src/dhcp/tests/test-dhcp-utils.c deleted file mode 100644 index 50245c79..00000000 --- a/src/dhcp/tests/test-dhcp-utils.c +++ /dev/null @@ -1,781 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2008 - 2014 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include <netinet/in.h> -#include <arpa/inet.h> -#include <linux/rtnetlink.h> - -#include "nm-glib-aux/nm-dedup-multi.h" -#include "nm-utils.h" - -#include "dhcp/nm-dhcp-utils.h" -#include "platform/nm-platform.h" - -#include "nm-test-utils-core.h" - -static NMIP4Config * -_ip4_config_from_options(int ifindex, const char *iface, GHashTable *options, guint32 route_metric) -{ - nm_auto_unref_dedup_multi_index NMDedupMultiIndex *multi_idx = nm_dedup_multi_index_new(); - NMIP4Config * config; - - config = nm_dhcp_utils_ip4_config_from_options(multi_idx, - ifindex, - iface, - options, - RT_TABLE_MAIN, - route_metric); - g_assert(config); - return config; -} - -typedef struct { - const char *name; - const char *value; -} Option; - -static GHashTable * -fill_table(const Option *test_options, GHashTable *table) -{ - const Option *opt; - - if (!table) - table = g_hash_table_new_full(nm_str_hash, g_str_equal, NULL, NULL); - for (opt = test_options; opt->name; opt++) - g_hash_table_insert(table, (gpointer) opt->name, (gpointer) opt->value); - return table; -} - -static const Option generic_options[] = { - {"subnet_mask", "255.255.255.0"}, - {"ip_address", "192.168.1.106"}, - {"network_number", "192.168.1.0"}, - {"expiry", "1232324877"}, - {"dhcp_lease_time", "3600"}, - {"dhcp_server_identifier", "192.168.1.1"}, - {"routers", "192.168.1.1"}, - {"domain_name_servers", "216.254.95.2 216.231.41.2"}, - {"dhcp_message_type", "5"}, - {"broadcast_address", "192.168.1.255"}, - {"domain_search", "foobar.com blah.foobar.com"}, - {"host_name", "nmreallywhipsthe"}, - {"domain_name", "lamasass.com"}, - {"interface_mtu", "987"}, - {"static_routes", "10.1.1.5 10.1.1.1 100.99.88.56 10.1.1.1"}, - {NULL, NULL}}; - -static void -test_generic_options(void) -{ - GHashTable * options; - gs_unref_object NMIP4Config *ip4_config = NULL; - const NMPlatformIP4Address * address; - const NMPlatformIP4Route * route; - guint32 tmp; - const char * expected_addr = "192.168.1.106"; - const char * expected_gw = "192.168.1.1"; - const char * expected_dns1 = "216.254.95.2"; - const char * expected_dns2 = "216.231.41.2"; - const char * expected_search1 = "foobar.com"; - const char * expected_search2 = "blah.foobar.com"; - const char * expected_route1_dest = "10.1.1.5"; - const char * expected_route1_gw = "10.1.1.1"; - const char * expected_route2_dest = "100.99.88.56"; - const char * expected_route2_gw = "10.1.1.1"; - - options = fill_table(generic_options, NULL); - ip4_config = _ip4_config_from_options(1, "eth0", options, 0); - - /* IP4 address */ - g_assert_cmpint(nm_ip4_config_get_num_addresses(ip4_config), ==, 1); - address = _nmtst_ip4_config_get_address(ip4_config, 0); - g_assert(inet_pton(AF_INET, expected_addr, &tmp) > 0); - g_assert(address->address == tmp); - g_assert(address->peer_address == tmp); - g_assert_cmpint(address->plen, ==, 24); - - /* Gateway */ - g_assert(inet_pton(AF_INET, expected_gw, &tmp) > 0); - g_assert(nmtst_ip4_config_get_gateway(ip4_config) == tmp); - - g_assert_cmpint(nm_ip4_config_get_num_wins(ip4_config), ==, 0); - - g_assert_cmpint(nm_ip4_config_get_mtu(ip4_config), ==, 987); - - /* Domain searches */ - g_assert_cmpint(nm_ip4_config_get_num_searches(ip4_config), ==, 2); - g_assert_cmpstr(nm_ip4_config_get_search(ip4_config, 0), ==, expected_search1); - g_assert_cmpstr(nm_ip4_config_get_search(ip4_config, 1), ==, expected_search2); - - /* DNS servers */ - g_assert_cmpint(nm_ip4_config_get_num_nameservers(ip4_config), ==, 2); - g_assert(inet_pton(AF_INET, expected_dns1, &tmp) > 0); - g_assert(nm_ip4_config_get_nameserver(ip4_config, 0) == tmp); - g_assert(inet_pton(AF_INET, expected_dns2, &tmp) > 0); - g_assert(nm_ip4_config_get_nameserver(ip4_config, 1) == tmp); - - /* Routes */ - g_assert_cmpint(nm_ip4_config_get_num_routes(ip4_config), ==, 3); - - /* Route #1 */ - route = _nmtst_ip4_config_get_route(ip4_config, 0); - g_assert(inet_pton(AF_INET, expected_route1_dest, &tmp) > 0); - g_assert(route->network == tmp); - g_assert(inet_pton(AF_INET, expected_route1_gw, &tmp) > 0); - g_assert(route->gateway == tmp); - g_assert_cmpint(route->plen, ==, 32); - g_assert_cmpint(route->metric, ==, 0); - - /* Route #2 */ - route = _nmtst_ip4_config_get_route(ip4_config, 1); - g_assert(route->network == nmtst_inet4_from_string(expected_route2_dest)); - g_assert(route->gateway == nmtst_inet4_from_string(expected_route2_gw)); - g_assert_cmpint(route->plen, ==, 32); - g_assert_cmpint(route->metric, ==, 0); - - route = _nmtst_ip4_config_get_route(ip4_config, 2); - g_assert(route->network == nmtst_inet4_from_string("0.0.0.0")); - g_assert(route->gateway == nmtst_inet4_from_string("192.168.1.1")); - g_assert_cmpint(route->plen, ==, 0); - g_assert_cmpint(route->metric, ==, 0); - - g_hash_table_destroy(options); -} - -static void -test_wins_options(void) -{ - GHashTable * options; - gs_unref_object NMIP4Config *ip4_config = NULL; - const NMPlatformIP4Address * address; - guint32 tmp; - const char * expected_wins1 = "63.12.199.5"; - const char * expected_wins2 = "150.4.88.120"; - static const Option data[] = {{"netbios_name_servers", "63.12.199.5 150.4.88.120"}, - {NULL, NULL}}; - - options = fill_table(generic_options, NULL); - options = fill_table(data, options); - ip4_config = _ip4_config_from_options(1, "eth0", options, 0); - - /* IP4 address */ - g_assert_cmpint(nm_ip4_config_get_num_addresses(ip4_config), ==, 1); - address = _nmtst_ip4_config_get_address(ip4_config, 0); - g_assert(address); - g_assert_cmpint(nm_ip4_config_get_num_wins(ip4_config), ==, 2); - g_assert(inet_pton(AF_INET, expected_wins1, &tmp) > 0); - g_assert(nm_ip4_config_get_wins(ip4_config, 0) == tmp); - g_assert(inet_pton(AF_INET, expected_wins2, &tmp) > 0); - g_assert(nm_ip4_config_get_wins(ip4_config, 1) == tmp); - - g_hash_table_destroy(options); -} - -static void -test_vendor_option_metered(void) -{ - GHashTable * options; - gs_unref_object NMIP4Config *ip4_config = NULL; - static const Option data[] = {{"vendor_encapsulated_options", "ANDROID_METERED"}, {NULL, NULL}}; - - options = fill_table(generic_options, NULL); - ip4_config = _ip4_config_from_options(1, "eth0", options, 0); - g_assert(nm_ip4_config_get_metered(ip4_config) == FALSE); - g_hash_table_destroy(options); - g_clear_object(&ip4_config); - - options = fill_table(generic_options, NULL); - options = fill_table(data, options); - ip4_config = _ip4_config_from_options(1, "eth0", options, 0); - g_assert(nm_ip4_config_get_metered(ip4_config) == TRUE); - g_hash_table_destroy(options); -} - -static void -test_parse_search_list(void) -{ - guint8 *data; - char ** domains; - - data = (guint8[]){0x05, 'l', 'o', 'c', 'a', 'l', 0x00}; - domains = nm_dhcp_parse_search_list(data, 7); - g_assert(domains); - g_assert_cmpint(g_strv_length(domains), ==, 1); - g_assert_cmpstr(domains[0], ==, "local"); - g_strfreev(domains); - - data = (guint8[]){0x04, 't', 'e', 's', 't', 0x07, 'e', 'x', 'a', 'm', 'p', 'l', - 'e', 0x03, 'c', 'o', 'm', 0x00, 0xc0, 0x05, 0x03, 'a', 'b', 'c', - 0xc0, 0x0d, 0x06, 'f', 'o', 'o', 'b', 'a', 'r', 0x00}; - domains = nm_dhcp_parse_search_list(data, 34); - g_assert(domains); - g_assert_cmpint(g_strv_length(domains), ==, 4); - g_assert_cmpstr(domains[0], ==, "test.example.com"); - g_assert_cmpstr(domains[1], ==, "example.com"); - g_assert_cmpstr(domains[2], ==, "abc.com"); - g_assert_cmpstr(domains[3], ==, "foobar"); - g_strfreev(domains); - - data = (guint8[]){ - 0x40, - 'b', - 'a', - 'd', - }; - domains = nm_dhcp_parse_search_list(data, 4); - g_assert(!domains); - - data = (guint8[]){ - 0x04, - 'o', - 'k', - 'a', - 'y', - 0x00, - 0x40, - 'b', - 'a', - 'd', - }; - domains = nm_dhcp_parse_search_list(data, 10); - g_assert(domains); - g_assert_cmpint(g_strv_length(domains), ==, 1); - g_assert_cmpstr(domains[0], ==, "okay"); - g_strfreev(domains); -} - -static void -ip4_test_route(NMIP4Config *ip4_config, - guint route_num, - const char * expected_dest, - const char * expected_gw, - guint expected_prefix) -{ - const NMPlatformIP4Route *route; - guint32 tmp; - - g_assert(expected_prefix <= 32); - - route = _nmtst_ip4_config_get_route(ip4_config, route_num); - g_assert(inet_pton(AF_INET, expected_dest, &tmp) > 0); - g_assert(route->network == tmp); - g_assert(inet_pton(AF_INET, expected_gw, &tmp) > 0); - g_assert(route->gateway == tmp); - g_assert_cmpint(route->plen, ==, expected_prefix); - g_assert_cmpint(route->metric, ==, 0); -} - -static void -ip4_test_gateway(NMIP4Config *ip4_config, const char *expected_gw) -{ - guint32 tmp; - - g_assert_cmpint(nm_ip4_config_get_num_addresses(ip4_config), ==, 1); - g_assert(inet_pton(AF_INET, expected_gw, &tmp) > 0); - g_assert(nmtst_ip4_config_get_gateway(ip4_config) == tmp); -} - -static void -test_classless_static_routes_1(void) -{ - GHashTable * options; - gs_unref_object NMIP4Config *ip4_config = NULL; - const char * expected_route1_dest = "192.168.10.0"; - const char * expected_route1_gw = "192.168.1.1"; - const char * expected_route2_dest = "10.0.0.0"; - const char * expected_route2_gw = "10.17.66.41"; - static const Option data[] = { - /* dhclient custom format */ - {"rfc3442_classless_static_routes", "24 192 168 10 192 168 1 1 8 10 10 17 66 41"}, - {NULL, NULL}}; - - options = fill_table(generic_options, NULL); - options = fill_table(data, options); - ip4_config = _ip4_config_from_options(1, "eth0", options, 0); - - /* IP4 routes */ - g_assert_cmpint(nm_ip4_config_get_num_routes(ip4_config), ==, 3); - ip4_test_route(ip4_config, 0, expected_route1_dest, expected_route1_gw, 24); - ip4_test_route(ip4_config, 1, expected_route2_dest, expected_route2_gw, 8); - ip4_test_route(ip4_config, 2, "0.0.0.0", "192.168.1.1", 0); - - g_hash_table_destroy(options); -} - -static void -test_classless_static_routes_2(void) -{ - GHashTable * options; - gs_unref_object NMIP4Config *ip4_config = NULL; - const char * expected_route1_dest = "192.168.10.0"; - const char * expected_route1_gw = "192.168.1.1"; - const char * expected_route2_dest = "10.0.0.0"; - const char * expected_route2_gw = "10.17.66.41"; - static const Option data[] = { - /* dhcpcd format */ - {"classless_static_routes", "192.168.10.0/24 192.168.1.1 10.0.0.0/8 10.17.66.41"}, - {NULL, NULL}}; - - options = fill_table(generic_options, NULL); - options = fill_table(data, options); - ip4_config = _ip4_config_from_options(1, "eth0", options, 0); - - /* IP4 routes */ - g_assert_cmpint(nm_ip4_config_get_num_routes(ip4_config), ==, 3); - ip4_test_route(ip4_config, 0, expected_route1_dest, expected_route1_gw, 24); - ip4_test_route(ip4_config, 1, expected_route2_dest, expected_route2_gw, 8); - ip4_test_route(ip4_config, 2, "0.0.0.0", expected_route1_gw, 0); - - g_hash_table_destroy(options); -} - -static void -test_fedora_dhclient_classless_static_routes(void) -{ - GHashTable * options; - gs_unref_object NMIP4Config *ip4_config = NULL; - const char * expected_route1_dest = "129.210.177.128"; - const char * expected_route1_gw = "192.168.0.113"; - const char * expected_route2_dest = "2.0.0.0"; - const char * expected_route2_gw = "10.34.255.6"; - const char * expected_gateway = "192.168.0.113"; - static const Option data[] = { - /* Fedora dhclient format */ - {"classless_static_routes", - "0 192.168.0.113 25.129.210.177.132 192.168.0.113 7.2 10.34.255.6"}, - {NULL, NULL}}; - - options = fill_table(generic_options, NULL); - options = fill_table(data, options); - ip4_config = _ip4_config_from_options(1, "eth0", options, 0); - - /* IP4 routes */ - g_assert_cmpint(nm_ip4_config_get_num_routes(ip4_config), ==, 3); - ip4_test_route(ip4_config, 0, expected_route1_dest, expected_route1_gw, 25); - ip4_test_route(ip4_config, 1, expected_route2_dest, expected_route2_gw, 7); - ip4_test_route(ip4_config, 2, "0.0.0.0", expected_route1_gw, 0); - - /* Gateway */ - ip4_test_gateway(ip4_config, expected_gateway); - - g_hash_table_destroy(options); -} - -static void -test_dhclient_invalid_classless_routes_1(void) -{ - GHashTable * options; - gs_unref_object NMIP4Config *ip4_config = NULL; - const char * expected_route1_dest = "192.168.10.0"; - const char * expected_route1_gw = "192.168.1.1"; - static const Option data[] = { - /* dhclient format */ - {"rfc3442_classless_static_routes", "24 192 168 10 192 168 1 1 45 10 17 66 41"}, - {NULL, NULL}}; - - options = fill_table(generic_options, NULL); - options = fill_table(data, options); - - NMTST_EXPECT_NM_WARN("*ignoring invalid classless static routes*"); - ip4_config = _ip4_config_from_options(1, "eth0", options, 0); - g_test_assert_expected_messages(); - - /* IP4 routes */ - g_assert_cmpint(nm_ip4_config_get_num_routes(ip4_config), ==, 2); - ip4_test_route(ip4_config, 0, expected_route1_dest, expected_route1_gw, 24); - ip4_test_route(ip4_config, 1, "0.0.0.0", expected_route1_gw, 0); - - g_hash_table_destroy(options); -} - -static void -test_dhcpcd_invalid_classless_routes_1(void) -{ - GHashTable * options; - gs_unref_object NMIP4Config *ip4_config = NULL; - const char * expected_route1_dest = "10.1.1.5"; - const char * expected_route1_gw = "10.1.1.1"; - const char * expected_route2_dest = "100.99.88.56"; - const char * expected_route2_gw = "10.1.1.1"; - static const Option data[] = { - /* dhcpcd format */ - {"classless_static_routes", "192.168.10.0/24 192.168.1.1 10.0.adfadf/44 10.17.66.41"}, - {NULL, NULL}}; - - options = fill_table(generic_options, NULL); - options = fill_table(data, options); - - NMTST_EXPECT_NM_WARN("*ignoring invalid classless static routes*"); - ip4_config = _ip4_config_from_options(1, "eth0", options, 0); - g_test_assert_expected_messages(); - - /* Test falling back to old-style static routes if the classless static - * routes are invalid. - */ - g_assert_cmpint(nm_ip4_config_get_num_routes(ip4_config), ==, 3); - ip4_test_route(ip4_config, 0, expected_route1_dest, expected_route1_gw, 32); - ip4_test_route(ip4_config, 1, expected_route2_dest, expected_route2_gw, 32); - ip4_test_route(ip4_config, 2, "0.0.0.0", "192.168.1.1", 0); - - g_hash_table_destroy(options); -} - -static void -test_dhclient_invalid_classless_routes_2(void) -{ - GHashTable * options; - gs_unref_object NMIP4Config *ip4_config = NULL; - const char * expected_route1_dest = "10.1.1.5"; - const char * expected_route1_gw = "10.1.1.1"; - const char * expected_route2_dest = "100.99.88.56"; - const char * expected_route2_gw = "10.1.1.1"; - static const Option data[] = { - {"rfc3442_classless_static_routes", "45 10 17 66 41 24 192 168 10 192 168 1 1"}, - {NULL, NULL}}; - - options = fill_table(generic_options, NULL); - options = fill_table(data, options); - - NMTST_EXPECT_NM_WARN("*ignoring invalid classless static routes*"); - ip4_config = _ip4_config_from_options(1, "eth0", options, 0); - g_test_assert_expected_messages(); - - /* Test falling back to old-style static routes if the classless static - * routes are invalid. - */ - g_assert_cmpint(nm_ip4_config_get_num_routes(ip4_config), ==, 3); - ip4_test_route(ip4_config, 0, expected_route1_dest, expected_route1_gw, 32); - ip4_test_route(ip4_config, 1, expected_route2_dest, expected_route2_gw, 32); - ip4_test_route(ip4_config, 2, "0.0.0.0", "192.168.1.1", 0); - - g_hash_table_destroy(options); -} - -static void -test_dhcpcd_invalid_classless_routes_2(void) -{ - GHashTable * options; - gs_unref_object NMIP4Config *ip4_config = NULL; - const char * expected_route1_dest = "10.1.1.5"; - const char * expected_route1_gw = "10.1.1.1"; - const char * expected_route2_dest = "100.99.88.56"; - const char * expected_route2_gw = "10.1.1.1"; - static const Option data[] = { - {"classless_static_routes", "10.0.adfadf/44 10.17.66.41 192.168.10.0/24 192.168.1.1"}, - {NULL, NULL}}; - - options = fill_table(generic_options, NULL); - options = fill_table(data, options); - - NMTST_EXPECT_NM_WARN("*ignoring invalid classless static routes*"); - ip4_config = _ip4_config_from_options(1, "eth0", options, 0); - g_test_assert_expected_messages(); - - /* Test falling back to old-style static routes if the classless static - * routes are invalid. - */ - - /* Routes */ - g_assert_cmpint(nm_ip4_config_get_num_routes(ip4_config), ==, 3); - ip4_test_route(ip4_config, 0, expected_route1_dest, expected_route1_gw, 32); - ip4_test_route(ip4_config, 1, expected_route2_dest, expected_route2_gw, 32); - ip4_test_route(ip4_config, 2, "0.0.0.0", "192.168.1.1", 0); - - g_hash_table_destroy(options); -} - -static void -test_dhclient_invalid_classless_routes_3(void) -{ - GHashTable * options; - gs_unref_object NMIP4Config *ip4_config = NULL; - const char * expected_route1_dest = "192.168.10.0"; - const char * expected_route1_gw = "192.168.1.1"; - static const Option data[] = { - {"rfc3442_classless_static_routes", "24 192 168 10 192 168 1 1 32 128 10 17 66 41"}, - {NULL, NULL}}; - - options = fill_table(generic_options, NULL); - options = fill_table(data, options); - - NMTST_EXPECT_NM_WARN("*ignoring invalid classless static routes*"); - ip4_config = _ip4_config_from_options(1, "eth0", options, 0); - g_test_assert_expected_messages(); - - /* IP4 routes */ - g_assert_cmpint(nm_ip4_config_get_num_routes(ip4_config), ==, 2); - ip4_test_route(ip4_config, 0, expected_route1_dest, expected_route1_gw, 24); - ip4_test_route(ip4_config, 1, "0.0.0.0", expected_route1_gw, 0); - - g_hash_table_destroy(options); -} - -static void -test_dhcpcd_invalid_classless_routes_3(void) -{ - GHashTable * options; - gs_unref_object NMIP4Config *ip4_config = NULL; - const char * expected_route1_dest = "192.168.10.0"; - const char * expected_route1_gw = "192.168.1.1"; - static Option data[] = { - {"classless_static_routes", "192.168.10.0/24 192.168.1.1 128/32 10.17.66.41"}, - {NULL, NULL}}; - - options = fill_table(generic_options, NULL); - options = fill_table(data, options); - - NMTST_EXPECT_NM_WARN("*DHCP provided invalid classless static route*"); - ip4_config = _ip4_config_from_options(1, "eth0", options, 0); - g_test_assert_expected_messages(); - - /* IP4 routes */ - g_assert_cmpint(nm_ip4_config_get_num_routes(ip4_config), ==, 2); - ip4_test_route(ip4_config, 0, expected_route1_dest, expected_route1_gw, 24); - ip4_test_route(ip4_config, 1, "0.0.0.0", expected_route1_gw, 0); - - g_hash_table_destroy(options); -} - -static void -test_dhclient_gw_in_classless_routes(void) -{ - GHashTable * options; - gs_unref_object NMIP4Config *ip4_config = NULL; - const char * expected_route1_dest = "192.168.10.0"; - const char * expected_route1_gw = "192.168.1.1"; - const char * expected_gateway = "192.2.3.4"; - static Option data[] = { - {"rfc3442_classless_static_routes", "24 192 168 10 192 168 1 1 0 192 2 3 4"}, - {NULL, NULL}}; - - options = fill_table(generic_options, NULL); - options = fill_table(data, options); - ip4_config = _ip4_config_from_options(1, "eth0", options, 0); - - /* IP4 routes */ - g_assert_cmpint(nm_ip4_config_get_num_routes(ip4_config), ==, 2); - ip4_test_route(ip4_config, 0, expected_route1_dest, expected_route1_gw, 24); - ip4_test_route(ip4_config, 1, "0.0.0.0", "192.2.3.4", 0); - - /* Gateway */ - ip4_test_gateway(ip4_config, expected_gateway); - - g_hash_table_destroy(options); -} - -static void -test_dhcpcd_gw_in_classless_routes(void) -{ - GHashTable * options; - gs_unref_object NMIP4Config *ip4_config = NULL; - const char * expected_route1_dest = "192.168.10.0"; - const char * expected_route1_gw = "192.168.1.1"; - const char * expected_gateway = "192.2.3.4"; - static Option data[] = { - {"classless_static_routes", "192.168.10.0/24 192.168.1.1 0.0.0.0/0 192.2.3.4"}, - {NULL, NULL}}; - - options = fill_table(generic_options, NULL); - options = fill_table(data, options); - ip4_config = _ip4_config_from_options(1, "eth0", options, 0); - - /* IP4 routes */ - g_assert_cmpint(nm_ip4_config_get_num_routes(ip4_config), ==, 2); - ip4_test_route(ip4_config, 0, expected_route1_dest, expected_route1_gw, 24); - ip4_test_route(ip4_config, 1, "0.0.0.0", "192.2.3.4", 0); - - /* Gateway */ - ip4_test_gateway(ip4_config, expected_gateway); - - g_hash_table_destroy(options); -} - -static void -test_escaped_domain_searches(void) -{ - GHashTable * options; - gs_unref_object NMIP4Config *ip4_config = NULL; - const char * expected_search0 = "host1"; - const char * expected_search1 = "host2"; - const char * expected_search2 = "host3"; - static const Option data[] = {{"domain_search", "host1\\032host2\\032host3"}, {NULL, NULL}}; - - options = fill_table(generic_options, NULL); - options = fill_table(data, options); - ip4_config = _ip4_config_from_options(1, "eth0", options, 0); - - /* domain searches */ - g_assert_cmpint(nm_ip4_config_get_num_searches(ip4_config), ==, 3); - g_assert_cmpstr(nm_ip4_config_get_search(ip4_config, 0), ==, expected_search0); - g_assert_cmpstr(nm_ip4_config_get_search(ip4_config, 1), ==, expected_search1); - g_assert_cmpstr(nm_ip4_config_get_search(ip4_config, 2), ==, expected_search2); - - g_hash_table_destroy(options); -} - -static void -test_invalid_escaped_domain_searches(void) -{ - GHashTable * options; - gs_unref_object NMIP4Config *ip4_config = NULL; - static const Option data[] = {{"domain_search", "host1\\aahost2\\032host3"}, {NULL, NULL}}; - - options = fill_table(generic_options, NULL); - options = fill_table(data, options); - - NMTST_EXPECT_NM_WARN("*invalid domain search*"); - ip4_config = _ip4_config_from_options(1, "eth0", options, 0); - g_test_assert_expected_messages(); - - /* domain searches */ - g_assert_cmpint(nm_ip4_config_get_num_searches(ip4_config), ==, 0); - - g_hash_table_destroy(options); -} - -static void -test_ip4_missing_prefix(const char *ip, guint32 expected_prefix) -{ - GHashTable * options; - gs_unref_object NMIP4Config *ip4_config = NULL; - const NMPlatformIP4Address * address; - - options = fill_table(generic_options, NULL); - g_hash_table_insert(options, "ip_address", (gpointer) ip); - g_hash_table_remove(options, "subnet_mask"); - - ip4_config = _ip4_config_from_options(1, "eth0", options, 0); - - g_assert_cmpint(nm_ip4_config_get_num_addresses(ip4_config), ==, 1); - address = _nmtst_ip4_config_get_address(ip4_config, 0); - g_assert(address); - g_assert_cmpint(address->plen, ==, expected_prefix); - - g_hash_table_destroy(options); -} - -static void -test_ip4_missing_prefix_24(void) -{ - test_ip4_missing_prefix("192.168.1.10", 24); -} - -static void -test_ip4_missing_prefix_16(void) -{ - test_ip4_missing_prefix("172.16.54.50", 16); -} - -static void -test_ip4_missing_prefix_8(void) -{ - test_ip4_missing_prefix("10.1.2.3", 8); -} - -static void -test_ip4_prefix_classless(void) -{ - GHashTable * options; - gs_unref_object NMIP4Config *ip4_config = NULL; - const NMPlatformIP4Address * address; - - /* Ensure that the missing-subnet-mask handler doesn't mangle classless - * subnet masks at all. The handler should trigger only if the server - * doesn't send the subnet mask. - */ - - options = fill_table(generic_options, NULL); - g_hash_table_insert(options, "ip_address", "172.16.54.22"); - g_hash_table_insert(options, "subnet_mask", "255.255.252.0"); - - ip4_config = _ip4_config_from_options(1, "eth0", options, 0); - - g_assert_cmpint(nm_ip4_config_get_num_addresses(ip4_config), ==, 1); - address = _nmtst_ip4_config_get_address(ip4_config, 0); - g_assert(address); - g_assert_cmpint(address->plen, ==, 22); - - g_hash_table_destroy(options); -} - -#define COMPARE_ID(src, is_str, expected, expected_len) \ - G_STMT_START \ - { \ - gs_unref_bytes GBytes *b = NULL; \ - const char * p; \ - gsize l; \ - \ - b = nm_dhcp_utils_client_id_string_to_bytes(src); \ - g_assert(b); \ - p = g_bytes_get_data(b, &l); \ - if (is_str) { \ - g_assert_cmpint(l, ==, expected_len + 1); \ - g_assert_cmpint(((const char *) p)[0], ==, 0); \ - g_assert(memcmp(p + 1, expected, expected_len) == 0); \ - } else { \ - g_assert_cmpint(l, ==, expected_len); \ - g_assert(memcmp(p, expected, expected_len) == 0); \ - } \ - } \ - G_STMT_END - -static void -test_client_id_from_string(void) -{ - const char * nothex = "asdfasdfasdfasdfasdfasdfasdf"; - const char * allhex = "00:11:22:33:4:55:66:77:88"; - const guint8 allhex_bin[] = {0x00, 0x11, 0x22, 0x33, 0x04, 0x55, 0x66, 0x77, 0x88}; - const char * somehex = "00:11:22:33:44:55:asdfasdfasdf:99:10"; - const char * nocolons = "0011223344559910"; - const char * endcolon = "00:11:22:33:44:55:"; - - COMPARE_ID(nothex, TRUE, nothex, strlen(nothex)); - COMPARE_ID(allhex, FALSE, allhex_bin, sizeof(allhex_bin)); - COMPARE_ID(somehex, TRUE, somehex, strlen(somehex)); - COMPARE_ID(nocolons, TRUE, nocolons, strlen(nocolons)); - COMPARE_ID(endcolon, TRUE, endcolon, strlen(endcolon)); -} - -NMTST_DEFINE(); - -int -main(int argc, char **argv) -{ - nmtst_init_assert_logging(&argc, &argv, "WARN", "DEFAULT"); - - g_test_add_func("/dhcp/generic-options", test_generic_options); - g_test_add_func("/dhcp/wins-options", test_wins_options); - g_test_add_func("/dhcp/classless-static-routes-1", test_classless_static_routes_1); - g_test_add_func("/dhcp/classless-static-routes-2", test_classless_static_routes_2); - g_test_add_func("/dhcp/fedora-dhclient-classless-static-routes", - test_fedora_dhclient_classless_static_routes); - g_test_add_func("/dhcp/dhclient-invalid-classless-routes-1", - test_dhclient_invalid_classless_routes_1); - g_test_add_func("/dhcp/dhcpcd-invalid-classless-routes-1", - test_dhcpcd_invalid_classless_routes_1); - g_test_add_func("/dhcp/dhclient-invalid-classless-routes-2", - test_dhclient_invalid_classless_routes_2); - g_test_add_func("/dhcp/dhcpcd-invalid-classless-routes-2", - test_dhcpcd_invalid_classless_routes_2); - g_test_add_func("/dhcp/dhclient-invalid-classless-routes-3", - test_dhclient_invalid_classless_routes_3); - g_test_add_func("/dhcp/dhcpcd-invalid-classless-routes-3", - test_dhcpcd_invalid_classless_routes_3); - g_test_add_func("/dhcp/dhclient-gw-in-classless-routes", test_dhclient_gw_in_classless_routes); - g_test_add_func("/dhcp/dhcpcd-gw-in-classless-routes", test_dhcpcd_gw_in_classless_routes); - g_test_add_func("/dhcp/escaped-domain-searches", test_escaped_domain_searches); - g_test_add_func("/dhcp/invalid-escaped-domain-searches", test_invalid_escaped_domain_searches); - g_test_add_func("/dhcp/ip4-missing-prefix-24", test_ip4_missing_prefix_24); - g_test_add_func("/dhcp/ip4-missing-prefix-16", test_ip4_missing_prefix_16); - g_test_add_func("/dhcp/ip4-missing-prefix-8", test_ip4_missing_prefix_8); - g_test_add_func("/dhcp/ip4-prefix-classless", test_ip4_prefix_classless); - g_test_add_func("/dhcp/client-id-from-string", test_client_id_from_string); - g_test_add_func("/dhcp/vendor-option-metered", test_vendor_option_metered); - g_test_add_func("/dhcp/parse-search-list", test_parse_search_list); - - return g_test_run(); -} |