|
Packit Service |
b23acc |
// SPDX-License-Identifier: GPL-2.0+
|
|
Packit Service |
b23acc |
/*
|
|
Packit Service |
b23acc |
* Copyright (C) 2005 - 2013 Red Hat, Inc.
|
|
Packit Service |
b23acc |
* Copyright (C) 2006 - 2008 Novell, Inc.
|
|
Packit Service |
b23acc |
*/
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
#include "nm-default.h"
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
#include "nm-dhcp-manager.h"
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
#include <sys/socket.h>
|
|
Packit Service |
b23acc |
#include <sys/wait.h>
|
|
Packit Service |
b23acc |
#include <signal.h>
|
|
Packit Service |
b23acc |
#include <stdlib.h>
|
|
Packit Service |
b23acc |
#include <unistd.h>
|
|
Packit Service |
b23acc |
#include <fcntl.h>
|
|
Packit Service |
b23acc |
#include <stdio.h>
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
#include "nm-glib-aux/nm-dedup-multi.h"
|
|
Packit Service |
b23acc |
#include "systemd/nm-sd-utils-shared.h"
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
#include "nm-config.h"
|
|
Packit Service |
b23acc |
#include "NetworkManagerUtils.h"
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
/*****************************************************************************/
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
typedef struct {
|
|
Packit Service |
b23acc |
const NMDhcpClientFactory *client_factory;
|
|
Packit Service |
b23acc |
char *default_hostname;
|
|
Packit Service |
b23acc |
CList dhcp_client_lst_head;
|
|
Packit Service |
b23acc |
} NMDhcpManagerPrivate;
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
struct _NMDhcpManager {
|
|
Packit Service |
b23acc |
GObject parent;
|
|
Packit Service |
b23acc |
NMDhcpManagerPrivate _priv;
|
|
Packit Service |
b23acc |
};
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
struct _NMDhcpManagerClass {
|
|
Packit Service |
b23acc |
GObjectClass parent;
|
|
Packit Service |
b23acc |
};
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
G_DEFINE_TYPE (NMDhcpManager, nm_dhcp_manager, G_TYPE_OBJECT)
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
#define NM_DHCP_MANAGER_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMDhcpManager, NM_IS_DHCP_MANAGER)
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
/*****************************************************************************/
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
/* default to installed helper, but can be modified for testing */
|
|
Packit Service |
b23acc |
const char *nm_dhcp_helper_path = LIBEXECDIR "/nm-dhcp-helper";
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
/*****************************************************************************/
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
static const NMDhcpClientFactory *
|
|
Packit Service |
b23acc |
_client_factory_find_by_name (const char *name)
|
|
Packit Service |
b23acc |
{
|
|
Packit Service |
b23acc |
int i;
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
g_return_val_if_fail (name, NULL);
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
for (i = 0; i < G_N_ELEMENTS (_nm_dhcp_manager_factories); i++) {
|
|
Packit Service |
b23acc |
const NMDhcpClientFactory *f = _nm_dhcp_manager_factories[i];
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
if (f && nm_streq (f->name, name))
|
|
Packit Service |
b23acc |
return f;
|
|
Packit Service |
b23acc |
}
|
|
Packit Service |
b23acc |
return NULL;
|
|
Packit Service |
b23acc |
}
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
static const NMDhcpClientFactory *
|
|
Packit Service |
b23acc |
_client_factory_available (const NMDhcpClientFactory *client_factory)
|
|
Packit Service |
b23acc |
{
|
|
Packit Service |
b23acc |
if ( client_factory
|
|
Packit Service |
b23acc |
&& (!client_factory->get_path || client_factory->get_path ()))
|
|
Packit Service |
b23acc |
return client_factory;
|
|
Packit Service |
b23acc |
return NULL;
|
|
Packit Service |
b23acc |
}
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
static GType
|
|
Packit Service |
b23acc |
_client_factory_get_gtype (const NMDhcpClientFactory *client_factory,
|
|
Packit Service |
b23acc |
int addr_family)
|
|
Packit Service |
b23acc |
{
|
|
Packit Service |
b23acc |
GType gtype;
|
|
Packit Service |
b23acc |
nm_auto_unref_gtypeclass NMDhcpClientClass *klass = NULL;
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
nm_assert (client_factory);
|
|
Packit Service |
b23acc |
nm_assert_addr_family (addr_family);
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
/* currently, the chosen DHCP plugin for IPv4 and IPv6 is configured in NetworkManager.conf
|
|
Packit Service |
b23acc |
* and cannot be reloaded. It would be nice to configure the plugin per address family
|
|
Packit Service |
b23acc |
* or to be able to reload it.
|
|
Packit Service |
b23acc |
*
|
|
Packit Service |
b23acc |
* Note that certain options in NetworkManager.conf depend on the chosen DHCP plugin.
|
|
Packit Service |
b23acc |
* See "dhcp-plugin:" in "Device List Format" (`man NetworkManager.conf`).
|
|
Packit Service |
b23acc |
* Supporting reloading the plugin would also require to re-evalate the decisions from
|
|
Packit Service |
b23acc |
* the "Device List Format". Likewise, having per-address family plugins would make the
|
|
Packit Service |
b23acc |
* "main.dhcp" setting and "dhcp-plugin:" match non-sensical because these configurations
|
|
Packit Service |
b23acc |
* currently are address family independet.
|
|
Packit Service |
b23acc |
*
|
|
Packit Service |
b23acc |
* So actually, we don't want that complexity. We want to phase out all plugins in favor
|
|
Packit Service |
b23acc |
* of the internal plugin.
|
|
Packit Service |
b23acc |
* However, certain existing plugins are well known to not support an address family.
|
|
Packit Service |
b23acc |
* In those cases, we should just silently fallback to the internal plugin.
|
|
Packit Service |
b23acc |
*
|
|
Packit Service |
b23acc |
* This could be a problem with forward compatibility if we ever intended to add IPv6 support
|
|
Packit Service |
b23acc |
* to those plugins. But we don't intend to do so. The internal plugin is the way forward and
|
|
Packit Service |
b23acc |
* not extending other plugins. */
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
if (client_factory->get_type_per_addr_family)
|
|
Packit Service |
b23acc |
gtype = client_factory->get_type_per_addr_family (addr_family);
|
|
Packit Service |
b23acc |
else
|
|
Packit Service |
b23acc |
gtype = client_factory->get_type ();
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
if (client_factory == &_nm_dhcp_client_factory_internal) {
|
|
Packit Service |
b23acc |
/* we are already using the internal plugin. Nothing to do. */
|
|
Packit Service |
b23acc |
goto out;
|
|
Packit Service |
b23acc |
}
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
klass = g_type_class_ref (gtype);
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
nm_assert (NM_IS_DHCP_CLIENT_CLASS (klass));
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
if (addr_family == AF_INET6) {
|
|
Packit Service |
b23acc |
if (!klass->ip6_start)
|
|
Packit Service |
b23acc |
gtype = _client_factory_get_gtype (&_nm_dhcp_client_factory_internal, addr_family);
|
|
Packit Service |
b23acc |
} else {
|
|
Packit Service |
b23acc |
if (!klass->ip4_start)
|
|
Packit Service |
b23acc |
gtype = _client_factory_get_gtype (&_nm_dhcp_client_factory_internal, addr_family);
|
|
Packit Service |
b23acc |
}
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
out:
|
|
Packit Service |
b23acc |
nm_assert (g_type_is_a (gtype, NM_TYPE_DHCP_CLIENT));
|
|
Packit Service |
b23acc |
nm_assert (({
|
|
Packit Service |
b23acc |
nm_auto_unref_gtypeclass NMDhcpClientClass *k = g_type_class_ref (gtype);
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
(addr_family == AF_INET6 && k->ip6_start)
|
|
Packit Service |
b23acc |
|| (addr_family == AF_INET && k->ip4_start);
|
|
Packit Service |
b23acc |
}));
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
return gtype;
|
|
Packit Service |
b23acc |
}
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
/*****************************************************************************/
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
static NMDhcpClient *
|
|
Packit Service |
b23acc |
get_client_for_ifindex (NMDhcpManager *manager, int addr_family, int ifindex)
|
|
Packit Service |
b23acc |
{
|
|
Packit Service |
b23acc |
NMDhcpManagerPrivate *priv;
|
|
Packit Service |
b23acc |
NMDhcpClient *client;
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
g_return_val_if_fail (NM_IS_DHCP_MANAGER (manager), NULL);
|
|
Packit Service |
b23acc |
g_return_val_if_fail (ifindex > 0, NULL);
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
priv = NM_DHCP_MANAGER_GET_PRIVATE (manager);
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
c_list_for_each_entry (client, &priv->dhcp_client_lst_head, dhcp_client_lst) {
|
|
Packit Service |
b23acc |
if ( nm_dhcp_client_get_ifindex (client) == ifindex
|
|
Packit Service |
b23acc |
&& nm_dhcp_client_get_addr_family (client) == addr_family)
|
|
Packit Service |
b23acc |
return client;
|
|
Packit Service |
b23acc |
}
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
return NULL;
|
|
Packit Service |
b23acc |
}
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
static void client_state_changed (NMDhcpClient *client,
|
|
Packit Service |
b23acc |
NMDhcpState state,
|
|
Packit Service |
b23acc |
GObject *ip_config,
|
|
Packit Service |
b23acc |
GVariant *options,
|
|
Packit Service |
b23acc |
const char *event_id,
|
|
Packit Service |
b23acc |
NMDhcpManager *self);
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
static void
|
|
Packit Service |
b23acc |
remove_client (NMDhcpManager *self, NMDhcpClient *client)
|
|
Packit Service |
b23acc |
{
|
|
Packit Service |
b23acc |
g_signal_handlers_disconnect_by_func (client, client_state_changed, self);
|
|
Packit Service |
b23acc |
c_list_unlink (&client->dhcp_client_lst);
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
/* Stopping the client is left up to the controlling device
|
|
Packit Service |
b23acc |
* explicitly since we may want to quit NetworkManager but not terminate
|
|
Packit Service |
b23acc |
* the DHCP client.
|
|
Packit Service |
b23acc |
*/
|
|
Packit Service |
b23acc |
}
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
static void
|
|
Packit Service |
b23acc |
remove_client_unref (NMDhcpManager *self, NMDhcpClient *client)
|
|
Packit Service |
b23acc |
{
|
|
Packit Service |
b23acc |
remove_client (self, client);
|
|
Packit Service |
b23acc |
g_object_unref (client);
|
|
Packit Service |
b23acc |
}
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
static void
|
|
Packit Service |
b23acc |
client_state_changed (NMDhcpClient *client,
|
|
Packit Service |
b23acc |
NMDhcpState state,
|
|
Packit Service |
b23acc |
GObject *ip_config,
|
|
Packit Service |
b23acc |
GVariant *options,
|
|
Packit Service |
b23acc |
const char *event_id,
|
|
Packit Service |
b23acc |
NMDhcpManager *self)
|
|
Packit Service |
b23acc |
{
|
|
Packit Service |
b23acc |
if (state >= NM_DHCP_STATE_TIMEOUT)
|
|
Packit Service |
b23acc |
remove_client_unref (self, client);
|
|
Packit Service |
b23acc |
}
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
static NMDhcpClient *
|
|
Packit Service |
b23acc |
client_start (NMDhcpManager *self,
|
|
Packit Service |
b23acc |
int addr_family,
|
|
Packit Service |
b23acc |
NMDedupMultiIndex *multi_idx,
|
|
Packit Service |
b23acc |
const char *iface,
|
|
Packit Service |
b23acc |
int ifindex,
|
|
Packit Service |
b23acc |
GBytes *hwaddr,
|
|
Packit Service |
b23acc |
GBytes *bcast_hwaddr,
|
|
Packit Service |
b23acc |
const char *uuid,
|
|
Packit Service |
b23acc |
guint32 route_table,
|
|
Packit Service |
b23acc |
guint32 route_metric,
|
|
Packit Service |
b23acc |
const struct in6_addr *ipv6_ll_addr,
|
|
Packit Service |
b23acc |
GBytes *dhcp_client_id,
|
|
Packit Service |
b23acc |
gboolean enforce_duid,
|
|
Packit Service |
b23acc |
guint32 iaid,
|
|
Packit Service |
b23acc |
gboolean iaid_explicit,
|
|
Packit Service |
b23acc |
guint32 timeout,
|
|
Packit Service |
b23acc |
const char *dhcp_anycast_addr,
|
|
Packit Service |
b23acc |
const char *hostname,
|
|
Packit Service |
b23acc |
gboolean hostname_use_fqdn,
|
|
Packit Service |
b23acc |
NMDhcpHostnameFlags hostname_flags,
|
|
Packit Service |
b23acc |
const char *mud_url,
|
|
Packit Service |
b23acc |
gboolean info_only,
|
|
Packit Service |
b23acc |
NMSettingIP6ConfigPrivacy privacy,
|
|
Packit Service |
b23acc |
const char *last_ip4_address,
|
|
Packit Service |
b23acc |
guint needed_prefixes,
|
|
Packit Service |
cd42c1 |
GBytes *vendor_class_identifier,
|
|
Packit Service |
b23acc |
GError **error)
|
|
Packit Service |
b23acc |
{
|
|
Packit Service |
b23acc |
NMDhcpManagerPrivate *priv;
|
|
Packit Service |
b23acc |
NMDhcpClient *client;
|
|
Packit Service |
b23acc |
gboolean success = FALSE;
|
|
Packit Service |
b23acc |
gsize hwaddr_len;
|
|
Packit Service |
b23acc |
GType gtype;
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
g_return_val_if_fail (NM_IS_DHCP_MANAGER (self), NULL);
|
|
Packit Service |
b23acc |
g_return_val_if_fail (iface, NULL);
|
|
Packit Service |
b23acc |
g_return_val_if_fail (ifindex > 0, NULL);
|
|
Packit Service |
b23acc |
g_return_val_if_fail (uuid != NULL, NULL);
|
|
Packit Service |
b23acc |
g_return_val_if_fail (!dhcp_client_id || g_bytes_get_size (dhcp_client_id) >= 2, NULL);
|
|
Packit Service |
cd42c1 |
g_return_val_if_fail ( !vendor_class_identifier
|
|
Packit Service |
cd42c1 |
|| g_bytes_get_size (vendor_class_identifier) <= 255,
|
|
Packit Service |
cd42c1 |
NULL);
|
|
Packit Service |
b23acc |
g_return_val_if_fail (!error || !*error, NULL);
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
if (!hwaddr || !bcast_hwaddr) {
|
|
Packit Service |
b23acc |
nm_utils_error_set (error,
|
|
Packit Service |
b23acc |
NM_UTILS_ERROR_UNKNOWN,
|
|
Packit Service |
b23acc |
"missing %s address",
|
|
Packit Service |
b23acc |
hwaddr ? "broadcast" : "MAC");
|
|
Packit Service |
b23acc |
return NULL;
|
|
Packit Service |
b23acc |
}
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
hwaddr_len = g_bytes_get_size (hwaddr);
|
|
Packit Service |
b23acc |
if ( hwaddr_len == 0
|
|
Packit Service |
b23acc |
|| hwaddr_len > NM_UTILS_HWADDR_LEN_MAX) {
|
|
Packit Service |
b23acc |
nm_utils_error_set (error,
|
|
Packit Service |
b23acc |
NM_UTILS_ERROR_UNKNOWN,
|
|
Packit Service |
b23acc |
"invalid MAC address");
|
|
Packit Service |
b23acc |
g_return_val_if_reached (NULL) ;
|
|
Packit Service |
b23acc |
}
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
if (hostname) {
|
|
Packit Service |
b23acc |
if ( (hostname_use_fqdn && !nm_sd_dns_name_is_valid (hostname))
|
|
Packit Service |
b23acc |
|| (!hostname_use_fqdn && !nm_sd_hostname_is_valid (hostname, FALSE))) {
|
|
Packit Service |
b23acc |
nm_log_warn (LOGD_DHCP , "dhcp%c: %s '%s' is invalid, will be ignored",
|
|
Packit Service |
b23acc |
nm_utils_addr_family_to_char (addr_family),
|
|
Packit Service |
b23acc |
hostname_use_fqdn ? "FQDN" : "hostname",
|
|
Packit Service |
b23acc |
hostname);
|
|
Packit Service |
b23acc |
hostname = NULL;
|
|
Packit Service |
b23acc |
}
|
|
Packit Service |
b23acc |
}
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
nm_assert (g_bytes_get_size (hwaddr) == g_bytes_get_size (bcast_hwaddr));
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
priv = NM_DHCP_MANAGER_GET_PRIVATE (self);
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
/* Kill any old client instance */
|
|
Packit Service |
b23acc |
client = get_client_for_ifindex (self, addr_family, ifindex);
|
|
Packit Service |
b23acc |
if (client) {
|
|
Packit Service |
b23acc |
/* FIXME: we cannot just call synchronously "stop()" and forget about the client.
|
|
Packit Service |
b23acc |
* We need to wait for the client to be fully stopped because most/all clients
|
|
Packit Service |
b23acc |
* cannot quit right away.
|
|
Packit Service |
b23acc |
*
|
|
Packit Service |
b23acc |
* FIXME(shutdown): also fix this during shutdown, to wait for all DHCP clients
|
|
Packit Service |
b23acc |
* to be fully stopped. */
|
|
Packit Service |
b23acc |
remove_client (self, client);
|
|
Packit Service |
b23acc |
nm_dhcp_client_stop (client, FALSE);
|
|
Packit Service |
b23acc |
g_object_unref (client);
|
|
Packit Service |
b23acc |
}
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
gtype = _client_factory_get_gtype (priv->client_factory, addr_family);
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
nm_log_trace (LOGD_DHCP , "dhcp%c: creating IPv%c DHCP client of type %s",
|
|
Packit Service |
b23acc |
nm_utils_addr_family_to_char (addr_family),
|
|
Packit Service |
b23acc |
nm_utils_addr_family_to_char (addr_family),
|
|
Packit Service |
b23acc |
g_type_name (gtype));
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
client = g_object_new (gtype,
|
|
Packit Service |
b23acc |
NM_DHCP_CLIENT_MULTI_IDX, multi_idx,
|
|
Packit Service |
b23acc |
NM_DHCP_CLIENT_ADDR_FAMILY, addr_family,
|
|
Packit Service |
b23acc |
NM_DHCP_CLIENT_INTERFACE, iface,
|
|
Packit Service |
b23acc |
NM_DHCP_CLIENT_IFINDEX, ifindex,
|
|
Packit Service |
b23acc |
NM_DHCP_CLIENT_HWADDR, hwaddr,
|
|
Packit Service |
b23acc |
NM_DHCP_CLIENT_BROADCAST_HWADDR, bcast_hwaddr,
|
|
Packit Service |
b23acc |
NM_DHCP_CLIENT_UUID, uuid,
|
|
Packit Service |
b23acc |
NM_DHCP_CLIENT_IAID, (guint) iaid,
|
|
Packit Service |
b23acc |
NM_DHCP_CLIENT_IAID_EXPLICIT, iaid_explicit,
|
|
Packit Service |
b23acc |
NM_DHCP_CLIENT_HOSTNAME, hostname,
|
|
Packit Service |
b23acc |
NM_DHCP_CLIENT_MUD_URL, mud_url,
|
|
Packit Service |
b23acc |
NM_DHCP_CLIENT_ROUTE_TABLE, (guint) route_table,
|
|
Packit Service |
b23acc |
NM_DHCP_CLIENT_ROUTE_METRIC, (guint) route_metric,
|
|
Packit Service |
b23acc |
NM_DHCP_CLIENT_TIMEOUT, (guint) timeout,
|
|
Packit Service |
b23acc |
NM_DHCP_CLIENT_HOSTNAME_FLAGS, (guint) hostname_flags,
|
|
Packit Service |
cd42c1 |
NM_DHCP_CLIENT_VENDOR_CLASS_IDENTIFIER, vendor_class_identifier,
|
|
Packit Service |
b23acc |
NM_DHCP_CLIENT_FLAGS, (guint) (0
|
|
Packit Service |
b23acc |
| (hostname_use_fqdn ? NM_DHCP_CLIENT_FLAGS_USE_FQDN : 0)
|
|
Packit Service |
b23acc |
| (info_only ? NM_DHCP_CLIENT_FLAGS_INFO_ONLY : 0)
|
|
Packit Service |
b23acc |
),
|
|
Packit Service |
b23acc |
NULL);
|
|
Packit Service |
b23acc |
nm_assert (client && c_list_is_empty (&client->dhcp_client_lst));
|
|
Packit Service |
b23acc |
c_list_link_tail (&priv->dhcp_client_lst_head, &client->dhcp_client_lst);
|
|
Packit Service |
b23acc |
g_signal_connect (client, NM_DHCP_CLIENT_SIGNAL_STATE_CHANGED, G_CALLBACK (client_state_changed), self);
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
/* unfortunately, our implementations work differently per address-family regarding client-id/DUID.
|
|
Packit Service |
b23acc |
*
|
|
Packit Service |
b23acc |
* - for IPv4, the calling code may determine a client-id (from NM's connection profile).
|
|
Packit Service |
b23acc |
* If present, it is taken. If not present, the DHCP plugin uses a plugin specific default.
|
|
Packit Service |
b23acc |
* - for "internal" plugin, the default is just "mac".
|
|
Packit Service |
b23acc |
* - for "dhclient", we try to get the configuration from dhclient's /etc/dhcp or fallback
|
|
Packit Service |
b23acc |
* to whatever dhclient uses by default.
|
|
Packit Service |
b23acc |
* We do it this way, because for dhclient the user may configure a default
|
|
Packit Service |
b23acc |
* outside of NM, and we want to honor that. Worse, dhclient could be a wapper
|
|
Packit Service |
b23acc |
* script where the wrapper script overwrites the client-id. We need to distinguish
|
|
Packit Service |
b23acc |
* between: force a particular client-id and leave it unspecified to whatever dhclient
|
|
Packit Service |
b23acc |
* wants.
|
|
Packit Service |
b23acc |
*
|
|
Packit Service |
b23acc |
* - for IPv6, the calling code always determines a client-id. It also specifies @enforce_duid,
|
|
Packit Service |
b23acc |
* to determine whether the given client-id must be used.
|
|
Packit Service |
b23acc |
* - for "internal" plugin @enforce_duid doesn't matter and the given client-id is
|
|
Packit Service |
b23acc |
* always used.
|
|
Packit Service |
b23acc |
* - for "dhclient", @enforce_duid FALSE means to first try to load the DUID from the
|
|
Packit Service |
b23acc |
* lease file, and only otherwise fallback to the given client-id.
|
|
Packit Service |
b23acc |
* - other plugins don't support DHCPv6.
|
|
Packit Service |
b23acc |
* It's done this way, so that existing dhclient setups don't change behavior on upgrade.
|
|
Packit Service |
b23acc |
*
|
|
Packit Service |
b23acc |
* This difference is cumbersome and only exists because of "dhclient" which supports hacking the
|
|
Packit Service |
b23acc |
* default outside of NetworkManager API.
|
|
Packit Service |
b23acc |
*/
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
if (addr_family == AF_INET) {
|
|
Packit Service |
b23acc |
success = nm_dhcp_client_start_ip4 (client,
|
|
Packit Service |
b23acc |
dhcp_client_id,
|
|
Packit Service |
b23acc |
dhcp_anycast_addr,
|
|
Packit Service |
b23acc |
last_ip4_address,
|
|
Packit Service |
b23acc |
error);
|
|
Packit Service |
b23acc |
} else {
|
|
Packit Service |
b23acc |
success = nm_dhcp_client_start_ip6 (client,
|
|
Packit Service |
b23acc |
dhcp_client_id,
|
|
Packit Service |
b23acc |
enforce_duid,
|
|
Packit Service |
b23acc |
dhcp_anycast_addr,
|
|
Packit Service |
b23acc |
ipv6_ll_addr,
|
|
Packit Service |
b23acc |
privacy,
|
|
Packit Service |
b23acc |
needed_prefixes,
|
|
Packit Service |
b23acc |
error);
|
|
Packit Service |
b23acc |
}
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
if (!success) {
|
|
Packit Service |
b23acc |
remove_client_unref (self, client);
|
|
Packit Service |
b23acc |
return NULL;
|
|
Packit Service |
b23acc |
}
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
return g_object_ref (client);
|
|
Packit Service |
b23acc |
}
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
/* Caller owns a reference to the NMDhcpClient on return */
|
|
Packit Service |
b23acc |
NMDhcpClient *
|
|
Packit Service |
b23acc |
nm_dhcp_manager_start_ip4 (NMDhcpManager *self,
|
|
Packit Service |
b23acc |
NMDedupMultiIndex *multi_idx,
|
|
Packit Service |
b23acc |
const char *iface,
|
|
Packit Service |
b23acc |
int ifindex,
|
|
Packit Service |
b23acc |
GBytes *hwaddr,
|
|
Packit Service |
b23acc |
GBytes *bcast_hwaddr,
|
|
Packit Service |
b23acc |
const char *uuid,
|
|
Packit Service |
b23acc |
guint32 route_table,
|
|
Packit Service |
b23acc |
guint32 route_metric,
|
|
Packit Service |
b23acc |
gboolean send_hostname,
|
|
Packit Service |
b23acc |
const char *dhcp_hostname,
|
|
Packit Service |
b23acc |
const char *dhcp_fqdn,
|
|
Packit Service |
b23acc |
NMDhcpHostnameFlags hostname_flags,
|
|
Packit Service |
b23acc |
const char *mud_url,
|
|
Packit Service |
b23acc |
GBytes *dhcp_client_id,
|
|
Packit Service |
b23acc |
guint32 timeout,
|
|
Packit Service |
b23acc |
const char *dhcp_anycast_addr,
|
|
Packit Service |
b23acc |
const char *last_ip_address,
|
|
Packit Service |
cd42c1 |
GBytes *vendor_class_identifier,
|
|
Packit Service |
b23acc |
GError **error)
|
|
Packit Service |
b23acc |
{
|
|
Packit Service |
b23acc |
NMDhcpManagerPrivate *priv;
|
|
Packit Service |
b23acc |
const char *hostname = NULL;
|
|
Packit Service |
b23acc |
gs_free char *hostname_tmp = NULL;
|
|
Packit Service |
b23acc |
gboolean use_fqdn = FALSE;
|
|
Packit Service |
b23acc |
char *dot;
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
g_return_val_if_fail (NM_IS_DHCP_MANAGER (self), NULL);
|
|
Packit Service |
b23acc |
priv = NM_DHCP_MANAGER_GET_PRIVATE (self);
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
if (send_hostname) {
|
|
Packit Service |
b23acc |
/* Use, in order of preference:
|
|
Packit Service |
b23acc |
* 1. FQDN from configuration
|
|
Packit Service |
b23acc |
* 2. hostname from configuration
|
|
Packit Service |
b23acc |
* 3. system hostname (only host part)
|
|
Packit Service |
b23acc |
*/
|
|
Packit Service |
b23acc |
if (dhcp_fqdn) {
|
|
Packit Service |
b23acc |
hostname = dhcp_fqdn;
|
|
Packit Service |
b23acc |
use_fqdn = TRUE;
|
|
Packit Service |
b23acc |
} else if (dhcp_hostname)
|
|
Packit Service |
b23acc |
hostname = dhcp_hostname;
|
|
Packit Service |
b23acc |
else {
|
|
Packit Service |
b23acc |
hostname = priv->default_hostname;
|
|
Packit Service |
b23acc |
if (hostname) {
|
|
Packit Service |
b23acc |
hostname_tmp = g_strdup (hostname);
|
|
Packit Service |
b23acc |
dot = strchr (hostname_tmp, '.');
|
|
Packit Service |
b23acc |
if (dot)
|
|
Packit Service |
b23acc |
*dot = '\0';
|
|
Packit Service |
b23acc |
hostname = hostname_tmp;
|
|
Packit Service |
b23acc |
}
|
|
Packit Service |
b23acc |
}
|
|
Packit Service |
b23acc |
}
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
return client_start (self,
|
|
Packit Service |
b23acc |
AF_INET,
|
|
Packit Service |
b23acc |
multi_idx,
|
|
Packit Service |
b23acc |
iface,
|
|
Packit Service |
b23acc |
ifindex,
|
|
Packit Service |
b23acc |
hwaddr,
|
|
Packit Service |
b23acc |
bcast_hwaddr,
|
|
Packit Service |
b23acc |
uuid,
|
|
Packit Service |
b23acc |
route_table,
|
|
Packit Service |
b23acc |
route_metric,
|
|
Packit Service |
b23acc |
NULL,
|
|
Packit Service |
b23acc |
dhcp_client_id,
|
|
Packit Service |
b23acc |
FALSE,
|
|
Packit Service |
b23acc |
0,
|
|
Packit Service |
b23acc |
FALSE,
|
|
Packit Service |
b23acc |
timeout,
|
|
Packit Service |
b23acc |
dhcp_anycast_addr,
|
|
Packit Service |
b23acc |
hostname,
|
|
Packit Service |
b23acc |
use_fqdn,
|
|
Packit Service |
b23acc |
hostname_flags,
|
|
Packit Service |
b23acc |
mud_url,
|
|
Packit Service |
b23acc |
FALSE,
|
|
Packit Service |
b23acc |
0,
|
|
Packit Service |
b23acc |
last_ip_address,
|
|
Packit Service |
b23acc |
0,
|
|
Packit Service |
cd42c1 |
vendor_class_identifier,
|
|
Packit Service |
b23acc |
error);
|
|
Packit Service |
b23acc |
}
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
/* Caller owns a reference to the NMDhcpClient on return */
|
|
Packit Service |
b23acc |
NMDhcpClient *
|
|
Packit Service |
b23acc |
nm_dhcp_manager_start_ip6 (NMDhcpManager *self,
|
|
Packit Service |
b23acc |
NMDedupMultiIndex *multi_idx,
|
|
Packit Service |
b23acc |
const char *iface,
|
|
Packit Service |
b23acc |
int ifindex,
|
|
Packit Service |
b23acc |
GBytes *hwaddr,
|
|
Packit Service |
b23acc |
GBytes *bcast_hwaddr,
|
|
Packit Service |
b23acc |
const struct in6_addr *ll_addr,
|
|
Packit Service |
b23acc |
const char *uuid,
|
|
Packit Service |
b23acc |
guint32 route_table,
|
|
Packit Service |
b23acc |
guint32 route_metric,
|
|
Packit Service |
b23acc |
gboolean send_hostname,
|
|
Packit Service |
b23acc |
const char *dhcp_hostname,
|
|
Packit Service |
b23acc |
NMDhcpHostnameFlags hostname_flags,
|
|
Packit Service |
b23acc |
const char *mud_url,
|
|
Packit Service |
b23acc |
GBytes *duid,
|
|
Packit Service |
b23acc |
gboolean enforce_duid,
|
|
Packit Service |
b23acc |
guint32 iaid,
|
|
Packit Service |
b23acc |
gboolean iaid_explicit,
|
|
Packit Service |
b23acc |
guint32 timeout,
|
|
Packit Service |
b23acc |
const char *dhcp_anycast_addr,
|
|
Packit Service |
b23acc |
gboolean info_only,
|
|
Packit Service |
b23acc |
NMSettingIP6ConfigPrivacy privacy,
|
|
Packit Service |
b23acc |
guint needed_prefixes,
|
|
Packit Service |
b23acc |
GError **error)
|
|
Packit Service |
b23acc |
{
|
|
Packit Service |
b23acc |
NMDhcpManagerPrivate *priv;
|
|
Packit Service |
b23acc |
const char *hostname = NULL;
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
g_return_val_if_fail (NM_IS_DHCP_MANAGER (self), NULL);
|
|
Packit Service |
b23acc |
priv = NM_DHCP_MANAGER_GET_PRIVATE (self);
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
if (send_hostname) {
|
|
Packit Service |
b23acc |
/* Always prefer the explicit dhcp-hostname if given */
|
|
Packit Service |
b23acc |
hostname = dhcp_hostname ?: priv->default_hostname;
|
|
Packit Service |
b23acc |
}
|
|
Packit Service |
b23acc |
return client_start (self,
|
|
Packit Service |
b23acc |
AF_INET6,
|
|
Packit Service |
b23acc |
multi_idx,
|
|
Packit Service |
b23acc |
iface,
|
|
Packit Service |
b23acc |
ifindex,
|
|
Packit Service |
b23acc |
hwaddr,
|
|
Packit Service |
b23acc |
bcast_hwaddr,
|
|
Packit Service |
b23acc |
uuid,
|
|
Packit Service |
b23acc |
route_table,
|
|
Packit Service |
b23acc |
route_metric,
|
|
Packit Service |
b23acc |
ll_addr,
|
|
Packit Service |
b23acc |
duid,
|
|
Packit Service |
b23acc |
enforce_duid,
|
|
Packit Service |
b23acc |
iaid,
|
|
Packit Service |
b23acc |
iaid_explicit,
|
|
Packit Service |
b23acc |
timeout,
|
|
Packit Service |
b23acc |
dhcp_anycast_addr,
|
|
Packit Service |
b23acc |
hostname,
|
|
Packit Service |
b23acc |
TRUE,
|
|
Packit Service |
b23acc |
hostname_flags,
|
|
Packit Service |
b23acc |
mud_url,
|
|
Packit Service |
b23acc |
info_only,
|
|
Packit Service |
b23acc |
privacy,
|
|
Packit Service |
b23acc |
NULL,
|
|
Packit Service |
b23acc |
needed_prefixes,
|
|
Packit Service |
cd42c1 |
NULL,
|
|
Packit Service |
b23acc |
error);
|
|
Packit Service |
b23acc |
}
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
void
|
|
Packit Service |
b23acc |
nm_dhcp_manager_set_default_hostname (NMDhcpManager *manager, const char *hostname)
|
|
Packit Service |
b23acc |
{
|
|
Packit Service |
b23acc |
NMDhcpManagerPrivate *priv = NM_DHCP_MANAGER_GET_PRIVATE (manager);
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
nm_clear_g_free (&priv->default_hostname);
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
/* Never send 'localhost'-type names to the DHCP server */
|
|
Packit Service |
b23acc |
if (!nm_utils_is_specific_hostname (hostname))
|
|
Packit Service |
b23acc |
return;
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
priv->default_hostname = g_strdup (hostname);
|
|
Packit Service |
b23acc |
}
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
const char *
|
|
Packit Service |
b23acc |
nm_dhcp_manager_get_config (NMDhcpManager *self)
|
|
Packit Service |
b23acc |
{
|
|
Packit Service |
b23acc |
const NMDhcpClientFactory *factory;
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
g_return_val_if_fail (NM_IS_DHCP_MANAGER (self), NULL);
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
factory = NM_DHCP_MANAGER_GET_PRIVATE (self)->client_factory;
|
|
Packit Service |
b23acc |
return factory ? factory->name : NULL;
|
|
Packit Service |
b23acc |
}
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
/*****************************************************************************/
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
NM_DEFINE_SINGLETON_GETTER (NMDhcpManager, nm_dhcp_manager_get, NM_TYPE_DHCP_MANAGER);
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
void
|
|
Packit Service |
b23acc |
nmtst_dhcp_manager_unget (gpointer self)
|
|
Packit Service |
b23acc |
{
|
|
Packit Service |
b23acc |
_nmtst_nm_dhcp_manager_get_reset (self);
|
|
Packit Service |
b23acc |
}
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
static void
|
|
Packit Service |
b23acc |
nm_dhcp_manager_init (NMDhcpManager *self)
|
|
Packit Service |
b23acc |
{
|
|
Packit Service |
b23acc |
NMDhcpManagerPrivate *priv = NM_DHCP_MANAGER_GET_PRIVATE (self);
|
|
Packit Service |
b23acc |
NMConfig *config = nm_config_get ();
|
|
Packit Service |
b23acc |
gs_free char *client_free = NULL;
|
|
Packit Service |
b23acc |
const char *client;
|
|
Packit Service |
b23acc |
int i;
|
|
Packit Service |
b23acc |
const NMDhcpClientFactory *client_factory = NULL;
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
c_list_init (&priv->dhcp_client_lst_head);
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
for (i = 0; i < G_N_ELEMENTS (_nm_dhcp_manager_factories); i++) {
|
|
Packit Service |
b23acc |
const NMDhcpClientFactory *f = _nm_dhcp_manager_factories[i];
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
if (!f)
|
|
Packit Service |
b23acc |
continue;
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
nm_log_dbg (LOGD_DHCP, "dhcp-init: enabled DHCP client '%s'%s%s",
|
|
Packit Service |
b23acc |
f->name,
|
|
Packit Service |
b23acc |
_client_factory_available (f) ? "" : " (not available)",
|
|
Packit Service |
b23acc |
f->experimental ? " (undocumented internal plugin)" : "");
|
|
Packit Service |
b23acc |
}
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
/* Client-specific setup */
|
|
Packit Service |
b23acc |
client_free = nm_config_data_get_value (nm_config_get_data_orig (config),
|
|
Packit Service |
b23acc |
NM_CONFIG_KEYFILE_GROUP_MAIN,
|
|
Packit Service |
b23acc |
NM_CONFIG_KEYFILE_KEY_MAIN_DHCP,
|
|
Packit Service |
b23acc |
NM_CONFIG_GET_VALUE_STRIP | NM_CONFIG_GET_VALUE_NO_EMPTY);
|
|
Packit Service |
b23acc |
client = client_free;
|
|
Packit Service |
b23acc |
if (nm_config_get_configure_and_quit (config) == NM_CONFIG_CONFIGURE_AND_QUIT_ENABLED) {
|
|
Packit Service |
b23acc |
client_factory = &_nm_dhcp_client_factory_internal;
|
|
Packit Service |
b23acc |
if (client && !nm_streq (client, client_factory->name))
|
|
Packit Service |
b23acc |
nm_log_info (LOGD_DHCP, "dhcp-init: Using internal DHCP client since configure-and-quit is set.");
|
|
Packit Service |
b23acc |
} else {
|
|
Packit Service |
b23acc |
if (client) {
|
|
Packit Service |
b23acc |
client_factory = _client_factory_available (_client_factory_find_by_name (client));
|
|
Packit Service |
b23acc |
if (!client_factory)
|
|
Packit Service |
b23acc |
nm_log_warn (LOGD_DHCP, "dhcp-init: DHCP client '%s' not available", client);
|
|
Packit Service |
b23acc |
}
|
|
Packit Service |
b23acc |
if (!client_factory) {
|
|
Packit Service |
b23acc |
client_factory = _client_factory_find_by_name (""NM_CONFIG_DEFAULT_MAIN_DHCP);
|
|
Packit Service |
b23acc |
if (!client_factory)
|
|
Packit Service |
b23acc |
nm_log_err (LOGD_DHCP, "dhcp-init: default DHCP client '%s' is not installed", NM_CONFIG_DEFAULT_MAIN_DHCP);
|
|
Packit Service |
b23acc |
else {
|
|
Packit Service |
b23acc |
client_factory = _client_factory_available (client_factory);
|
|
Packit Service |
b23acc |
if (!client_factory)
|
|
Packit Service |
b23acc |
nm_log_info (LOGD_DHCP, "dhcp-init: default DHCP client '%s' is not available", NM_CONFIG_DEFAULT_MAIN_DHCP);
|
|
Packit Service |
b23acc |
}
|
|
Packit Service |
b23acc |
}
|
|
Packit Service |
b23acc |
if (!client_factory) {
|
|
Packit Service |
b23acc |
for (i = 0; i < G_N_ELEMENTS (_nm_dhcp_manager_factories); i++) {
|
|
Packit Service |
b23acc |
client_factory = _client_factory_available (_nm_dhcp_manager_factories[i]);
|
|
Packit Service |
b23acc |
if (client_factory)
|
|
Packit Service |
b23acc |
break;
|
|
Packit Service |
b23acc |
}
|
|
Packit Service |
b23acc |
}
|
|
Packit Service |
b23acc |
}
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
g_return_if_fail (client_factory);
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
nm_log_info (LOGD_DHCP, "dhcp-init: Using DHCP client '%s'", client_factory->name);
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
/* NOTE: currently the DHCP plugin is chosen once at start. It's not
|
|
Packit Service |
b23acc |
* possible to reload that configuration. If that ever becomes possible,
|
|
Packit Service |
b23acc |
* beware that the "dhcp-plugin" device spec made decisions based on
|
|
Packit Service |
b23acc |
* the previous plugin and may need reevaluation. */
|
|
Packit Service |
b23acc |
priv->client_factory = client_factory;
|
|
Packit Service |
b23acc |
}
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
static void
|
|
Packit Service |
b23acc |
dispose (GObject *object)
|
|
Packit Service |
b23acc |
{
|
|
Packit Service |
b23acc |
NMDhcpManager *self = NM_DHCP_MANAGER (object);
|
|
Packit Service |
b23acc |
NMDhcpManagerPrivate *priv = NM_DHCP_MANAGER_GET_PRIVATE (self);
|
|
Packit Service |
b23acc |
NMDhcpClient *client, *client_safe;
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
c_list_for_each_entry_safe (client, client_safe, &priv->dhcp_client_lst_head, dhcp_client_lst)
|
|
Packit Service |
b23acc |
remove_client_unref (self, client);
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
G_OBJECT_CLASS (nm_dhcp_manager_parent_class)->dispose (object);
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
nm_clear_g_free (&priv->default_hostname);
|
|
Packit Service |
b23acc |
}
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
static void
|
|
Packit Service |
b23acc |
nm_dhcp_manager_class_init (NMDhcpManagerClass *manager_class)
|
|
Packit Service |
b23acc |
{
|
|
Packit Service |
b23acc |
GObjectClass *object_class = G_OBJECT_CLASS (manager_class);
|
|
Packit Service |
b23acc |
|
|
Packit Service |
b23acc |
object_class->dispose = dispose;
|
|
Packit Service |
b23acc |
}
|