2020-12-23 22:21:36 +01:00
|
|
|
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
2019-09-25 13:13:40 +02:00
|
|
|
/*
|
2014-07-11 17:57:20 +02:00
|
|
|
* Copyright (C) 2011 Red Hat, Inc.
|
|
|
|
|
* Copyright (C) 2013 Thomas Bechtold <thomasbechtold@jpberlin.de>
|
|
|
|
|
*/
|
|
|
|
|
|
2021-02-04 18:04:13 +01:00
|
|
|
#include "src/core/nm-default-daemon.h"
|
2016-02-19 14:57:48 +01:00
|
|
|
|
2014-07-11 17:57:20 +02:00
|
|
|
#include "nm-config-data.h"
|
|
|
|
|
|
2015-01-07 14:30:14 +01:00
|
|
|
#include "nm-config.h"
|
2016-11-21 00:43:52 +01:00
|
|
|
#include "devices/nm-device.h"
|
2021-02-12 15:01:09 +01:00
|
|
|
#include "libnm-core-intern/nm-core-internal.h"
|
|
|
|
|
#include "libnm-core-intern/nm-keyfile-internal.h"
|
|
|
|
|
#include "libnm-core-intern/nm-keyfile-utils.h"
|
2015-05-15 11:36:28 +02:00
|
|
|
|
2016-09-29 13:49:01 +02:00
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2015-05-15 11:36:28 +02:00
|
|
|
typedef struct {
|
2021-11-09 13:28:54 +01:00
|
|
|
char *group_name;
|
2015-05-15 11:36:28 +02:00
|
|
|
gboolean stop_match;
|
|
|
|
|
struct {
|
|
|
|
|
/* have a separate boolean field @has, because a @spec with
|
|
|
|
|
* value %NULL does not necessarily mean, that the property
|
|
|
|
|
* "match-device" was unspecified. */
|
|
|
|
|
gboolean has;
|
2021-11-09 13:28:54 +01:00
|
|
|
GSList *spec;
|
2015-05-15 11:36:28 +02:00
|
|
|
} match_device;
|
2021-06-03 09:01:23 +02:00
|
|
|
union {
|
|
|
|
|
struct {
|
2021-11-09 13:28:54 +01:00
|
|
|
GSList *allowed_connections;
|
2021-06-03 09:01:23 +02:00
|
|
|
gboolean allowed_connections_has;
|
|
|
|
|
} device;
|
|
|
|
|
};
|
|
|
|
|
gboolean is_device;
|
|
|
|
|
|
|
|
|
|
/* List of key/value pairs in the section, sorted by key */
|
2021-06-16 09:50:39 +02:00
|
|
|
gsize lookup_len;
|
|
|
|
|
const NMUtilsNamedValue *lookup_idx;
|
2016-06-22 13:14:10 +02:00
|
|
|
} MatchSectionInfo;
|
2015-01-07 14:30:14 +01:00
|
|
|
|
2016-09-29 13:49:01 +02:00
|
|
|
struct _NMGlobalDnsDomain {
|
2021-11-09 13:28:54 +01:00
|
|
|
char *name;
|
2016-09-29 13:49:01 +02:00
|
|
|
char **servers;
|
|
|
|
|
char **options;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct _NMGlobalDnsConfig {
|
2025-01-08 11:21:46 +01:00
|
|
|
char **searches;
|
|
|
|
|
char **options;
|
|
|
|
|
GHashTable *domains;
|
|
|
|
|
const char **domain_list;
|
|
|
|
|
char *cert_authority;
|
|
|
|
|
NMDnsResolveMode resolve_mode;
|
dns: make [global-dns] to overwrite configs from connections
According to the documentation, settings from [global-dns] (searches and
options) are always merged with those from connections. However this was
not happening if no [global-dns-domain-*] exists, in which case
connections were ignored. This happened because in the past both global
sections must de defined or undefined. When this was changed to allow
defining only [global-dns], allowing it in the function that generates
the resolv.conf file was forgotten. Fix that now.
Anyway, merging these configs doesn't make much sense. The searches and
options defined in connections probably make sense only for the nameservers
defined in that same connection.
Because of this, make the following change: if global nameservers are
defined, use searches and options from [global-dns] only, because those
defined in connections may not make sense for the global nameservers. If
[global-dns] is missing, assume an empty [global-dns] section.
Also, if no global nameservers are defined, but [global-dns] is, make
that it overwrites the searches and options defined in connections. This
is not ideal, but none of the alternatives is better and at least this
is easy to remember.
So, the resulting rules from above are:
- If [global-dns] is defined, it always overwrite searches and options
from connections.
- If [global-dns-domain-*] is defined, it always overwrite nameservers
from connections. It overwrites searches and options too.
Fixes: 1f0d1d78d2a2 ('dns-manager: always apply options from [global-dns]')
Fixes: f57a848da5aa ('man: update documentation about global DNS configuration')
2025-08-25 08:58:21 +02:00
|
|
|
gboolean internal;
|
2016-09-29 13:49:01 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
NM_GOBJECT_PROPERTIES_DEFINE_BASE(PROP_CONFIG_MAIN_FILE,
|
|
|
|
|
PROP_CONFIG_DESCRIPTION,
|
|
|
|
|
PROP_KEYFILE_USER,
|
|
|
|
|
PROP_KEYFILE_INTERN,
|
2017-08-09 15:19:54 +08:00
|
|
|
PROP_CONNECTIVITY_ENABLED,
|
2016-09-29 13:49:01 +02:00
|
|
|
PROP_CONNECTIVITY_URI,
|
|
|
|
|
PROP_CONNECTIVITY_INTERVAL,
|
2024-06-12 14:20:21 -04:00
|
|
|
PROP_CONNECTIVITY_TIMEOUT,
|
2016-09-29 13:49:01 +02:00
|
|
|
PROP_CONNECTIVITY_RESPONSE,
|
|
|
|
|
PROP_NO_AUTO_DEFAULT, );
|
|
|
|
|
|
2014-07-11 17:57:20 +02:00
|
|
|
typedef struct {
|
2015-01-06 20:16:10 +01:00
|
|
|
char *config_main_file;
|
|
|
|
|
char *config_description;
|
|
|
|
|
|
2015-01-07 13:25:41 +01:00
|
|
|
GKeyFile *keyfile;
|
2015-06-24 20:11:42 +02:00
|
|
|
GKeyFile *keyfile_user;
|
|
|
|
|
GKeyFile *keyfile_intern;
|
2015-01-07 13:25:41 +01:00
|
|
|
|
2015-05-15 11:36:28 +02:00
|
|
|
/* A zero-terminated list of pre-processed information from the
|
|
|
|
|
* [connection] sections. This is to speed up lookup. */
|
2016-06-22 13:14:10 +02:00
|
|
|
MatchSectionInfo *connection_infos;
|
|
|
|
|
|
|
|
|
|
/* A zero-terminated list of pre-processed information from the
|
|
|
|
|
* [device] sections. This is to speed up lookup. */
|
|
|
|
|
MatchSectionInfo *device_infos;
|
2015-05-15 11:36:28 +02:00
|
|
|
|
2014-07-11 17:57:20 +02:00
|
|
|
struct {
|
2017-08-09 15:19:54 +08:00
|
|
|
gboolean enabled;
|
2021-11-09 13:28:54 +01:00
|
|
|
char *uri;
|
|
|
|
|
char *response;
|
2014-07-11 17:57:20 +02:00
|
|
|
guint interval;
|
2024-06-12 14:20:21 -04:00
|
|
|
guint timeout;
|
2014-07-11 17:57:20 +02:00
|
|
|
} connectivity;
|
2015-01-07 17:09:52 +01:00
|
|
|
|
2017-11-22 21:19:40 +01:00
|
|
|
int autoconnect_retries_default;
|
|
|
|
|
|
2015-01-07 17:09:52 +01:00
|
|
|
struct {
|
2019-09-26 09:52:23 +02:00
|
|
|
/* from /var/lib/NetworkManager/no-auto-default.state */
|
2021-11-09 13:28:54 +01:00
|
|
|
char **arr;
|
2015-01-07 17:09:52 +01:00
|
|
|
GSList *specs;
|
2019-09-26 09:52:23 +02:00
|
|
|
|
|
|
|
|
/* from main.no-auto-default setting in NetworkManager.conf. */
|
2015-01-07 17:09:52 +01:00
|
|
|
GSList *specs_config;
|
|
|
|
|
} no_auto_default;
|
2019-09-26 09:52:23 +02:00
|
|
|
|
|
|
|
|
GSList *ignore_carrier;
|
2015-06-07 23:27:01 +02:00
|
|
|
GSList *assume_ipv6ll_only;
|
2015-02-12 17:35:14 +01:00
|
|
|
|
|
|
|
|
char *dns_mode;
|
2015-04-17 13:54:32 +02:00
|
|
|
char *rc_manager;
|
|
|
|
|
|
2015-02-12 17:35:14 +01:00
|
|
|
NMGlobalDnsConfig *global_dns;
|
2015-07-08 19:24:49 +02:00
|
|
|
|
2018-12-01 16:01:46 +01:00
|
|
|
bool systemd_resolved : 1;
|
2020-11-27 16:15:41 +01:00
|
|
|
|
|
|
|
|
char *iwd_config_path;
|
2014-07-11 17:57:20 +02:00
|
|
|
} NMConfigDataPrivate;
|
|
|
|
|
|
2016-09-29 13:49:01 +02:00
|
|
|
struct _NMConfigData {
|
|
|
|
|
GObject parent;
|
|
|
|
|
NMConfigDataPrivate _priv;
|
2015-06-15 09:01:42 +02:00
|
|
|
};
|
2014-07-11 17:57:20 +02:00
|
|
|
|
2016-09-29 13:49:01 +02:00
|
|
|
struct _NMConfigDataClass {
|
|
|
|
|
GObjectClass parent;
|
2014-07-11 17:57:20 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
G_DEFINE_TYPE(NMConfigData, nm_config_data, G_TYPE_OBJECT)
|
|
|
|
|
|
2016-09-29 13:49:01 +02:00
|
|
|
#define NM_CONFIG_DATA_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMConfigData, NM_IS_CONFIG_DATA)
|
2014-07-11 17:57:20 +02:00
|
|
|
|
2016-10-02 18:22:50 +02:00
|
|
|
/*****************************************************************************/
|
2014-07-11 17:57:20 +02:00
|
|
|
|
2021-06-16 09:50:39 +02:00
|
|
|
static const char *
|
|
|
|
|
_match_section_info_get_str(const MatchSectionInfo *m, GKeyFile *keyfile, const char *property);
|
|
|
|
|
|
2023-06-12 16:34:40 +02:00
|
|
|
static const char *_config_data_get_device_config(const NMConfigData *self,
|
|
|
|
|
const char *property,
|
|
|
|
|
const NMMatchSpecDeviceData *match_data,
|
|
|
|
|
NMDevice *device,
|
|
|
|
|
gboolean *has_match);
|
|
|
|
|
|
2021-06-16 09:50:39 +02:00
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2015-01-06 20:16:10 +01:00
|
|
|
const char *
|
|
|
|
|
nm_config_data_get_config_main_file(const NMConfigData *self)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail(self, NULL);
|
|
|
|
|
|
|
|
|
|
return NM_CONFIG_DATA_GET_PRIVATE(self)->config_main_file;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char *
|
|
|
|
|
nm_config_data_get_config_description(const NMConfigData *self)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail(self, NULL);
|
|
|
|
|
|
|
|
|
|
return NM_CONFIG_DATA_GET_PRIVATE(self)->config_description;
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-11 23:43:29 +02:00
|
|
|
gboolean
|
|
|
|
|
nm_config_data_has_group(const NMConfigData *self, const char *group)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail(NM_IS_CONFIG_DATA(self), FALSE);
|
|
|
|
|
g_return_val_if_fail(group && *group, FALSE);
|
|
|
|
|
|
|
|
|
|
return g_key_file_has_group(NM_CONFIG_DATA_GET_PRIVATE(self)->keyfile, group);
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-07 13:25:41 +01:00
|
|
|
char *
|
2021-11-09 13:28:54 +01:00
|
|
|
nm_config_data_get_value(const NMConfigData *self,
|
|
|
|
|
const char *group,
|
|
|
|
|
const char *key,
|
2015-06-16 15:13:26 +02:00
|
|
|
NMConfigGetValueFlags flags)
|
2015-01-07 13:25:41 +01:00
|
|
|
{
|
2015-06-09 12:06:14 +02:00
|
|
|
g_return_val_if_fail(NM_IS_CONFIG_DATA(self), NULL);
|
2015-06-09 08:17:28 +02:00
|
|
|
g_return_val_if_fail(group && *group, NULL);
|
|
|
|
|
g_return_val_if_fail(key && *key, NULL);
|
2015-01-07 13:25:41 +01:00
|
|
|
|
2015-06-16 15:13:26 +02:00
|
|
|
return nm_config_keyfile_get_value(NM_CONFIG_DATA_GET_PRIVATE(self)->keyfile,
|
|
|
|
|
group,
|
|
|
|
|
key,
|
|
|
|
|
flags);
|
2015-01-07 13:25:41 +01:00
|
|
|
}
|
|
|
|
|
|
2015-06-11 23:43:29 +02:00
|
|
|
gboolean
|
2021-11-09 13:28:54 +01:00
|
|
|
nm_config_data_has_value(const NMConfigData *self,
|
|
|
|
|
const char *group,
|
|
|
|
|
const char *key,
|
2015-06-16 15:13:26 +02:00
|
|
|
NMConfigGetValueFlags flags)
|
2015-06-11 23:43:29 +02:00
|
|
|
{
|
|
|
|
|
gs_free char *value = NULL;
|
|
|
|
|
|
|
|
|
|
g_return_val_if_fail(NM_IS_CONFIG_DATA(self), FALSE);
|
|
|
|
|
g_return_val_if_fail(group && *group, FALSE);
|
|
|
|
|
g_return_val_if_fail(key && *key, FALSE);
|
|
|
|
|
|
2015-06-16 15:13:26 +02:00
|
|
|
value =
|
|
|
|
|
nm_config_keyfile_get_value(NM_CONFIG_DATA_GET_PRIVATE(self)->keyfile, group, key, flags);
|
2015-06-11 23:43:29 +02:00
|
|
|
return !!value;
|
|
|
|
|
}
|
|
|
|
|
|
all: don't use gchar/gshort/gint/glong but C types
We commonly don't use the glib typedefs for char/short/int/long,
but their C types directly.
$ git grep '\<g\(char\|short\|int\|long\|float\|double\)\>' | wc -l
587
$ git grep '\<\(char\|short\|int\|long\|float\|double\)\>' | wc -l
21114
One could argue that using the glib typedefs is preferable in
public API (of our glib based libnm library) or where it clearly
is related to glib, like during
g_object_set (obj, PROPERTY, (gint) value, NULL);
However, that argument does not seem strong, because in practice we don't
follow that argument today, and seldomly use the glib typedefs.
Also, the style guide for this would be hard to formalize, because
"using them where clearly related to a glib" is a very loose suggestion.
Also note that glib typedefs will always just be typedefs of the
underlying C types. There is no danger of glib changing the meaning
of these typedefs (because that would be a major API break of glib).
A simple style guide is instead: don't use these typedefs.
No manual actions, I only ran the bash script:
FILES=($(git ls-files '*.[hc]'))
sed -i \
-e 's/\<g\(char\|short\|int\|long\|float\|double\)\>\( [^ ]\)/\1\2/g' \
-e 's/\<g\(char\|short\|int\|long\|float\|double\)\> /\1 /g' \
-e 's/\<g\(char\|short\|int\|long\|float\|double\)\>/\1/g' \
"${FILES[@]}"
2018-07-11 07:40:19 +02:00
|
|
|
int
|
|
|
|
|
nm_config_data_get_value_boolean(const NMConfigData *self,
|
2021-11-09 13:28:54 +01:00
|
|
|
const char *group,
|
|
|
|
|
const char *key,
|
all: don't use gchar/gshort/gint/glong but C types
We commonly don't use the glib typedefs for char/short/int/long,
but their C types directly.
$ git grep '\<g\(char\|short\|int\|long\|float\|double\)\>' | wc -l
587
$ git grep '\<\(char\|short\|int\|long\|float\|double\)\>' | wc -l
21114
One could argue that using the glib typedefs is preferable in
public API (of our glib based libnm library) or where it clearly
is related to glib, like during
g_object_set (obj, PROPERTY, (gint) value, NULL);
However, that argument does not seem strong, because in practice we don't
follow that argument today, and seldomly use the glib typedefs.
Also, the style guide for this would be hard to formalize, because
"using them where clearly related to a glib" is a very loose suggestion.
Also note that glib typedefs will always just be typedefs of the
underlying C types. There is no danger of glib changing the meaning
of these typedefs (because that would be a major API break of glib).
A simple style guide is instead: don't use these typedefs.
No manual actions, I only ran the bash script:
FILES=($(git ls-files '*.[hc]'))
sed -i \
-e 's/\<g\(char\|short\|int\|long\|float\|double\)\>\( [^ ]\)/\1\2/g' \
-e 's/\<g\(char\|short\|int\|long\|float\|double\)\> /\1 /g' \
-e 's/\<g\(char\|short\|int\|long\|float\|double\)\>/\1/g' \
"${FILES[@]}"
2018-07-11 07:40:19 +02:00
|
|
|
int default_value)
|
2015-06-09 09:06:53 +02:00
|
|
|
{
|
|
|
|
|
char *str;
|
all: don't use gchar/gshort/gint/glong but C types
We commonly don't use the glib typedefs for char/short/int/long,
but their C types directly.
$ git grep '\<g\(char\|short\|int\|long\|float\|double\)\>' | wc -l
587
$ git grep '\<\(char\|short\|int\|long\|float\|double\)\>' | wc -l
21114
One could argue that using the glib typedefs is preferable in
public API (of our glib based libnm library) or where it clearly
is related to glib, like during
g_object_set (obj, PROPERTY, (gint) value, NULL);
However, that argument does not seem strong, because in practice we don't
follow that argument today, and seldomly use the glib typedefs.
Also, the style guide for this would be hard to formalize, because
"using them where clearly related to a glib" is a very loose suggestion.
Also note that glib typedefs will always just be typedefs of the
underlying C types. There is no danger of glib changing the meaning
of these typedefs (because that would be a major API break of glib).
A simple style guide is instead: don't use these typedefs.
No manual actions, I only ran the bash script:
FILES=($(git ls-files '*.[hc]'))
sed -i \
-e 's/\<g\(char\|short\|int\|long\|float\|double\)\>\( [^ ]\)/\1\2/g' \
-e 's/\<g\(char\|short\|int\|long\|float\|double\)\> /\1 /g' \
-e 's/\<g\(char\|short\|int\|long\|float\|double\)\>/\1/g' \
"${FILES[@]}"
2018-07-11 07:40:19 +02:00
|
|
|
int value = default_value;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2015-06-09 12:06:14 +02:00
|
|
|
g_return_val_if_fail(NM_IS_CONFIG_DATA(self), default_value);
|
|
|
|
|
g_return_val_if_fail(group && *group, default_value);
|
|
|
|
|
g_return_val_if_fail(key && *key, default_value);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2015-06-09 12:06:14 +02:00
|
|
|
/* when parsing the boolean, base it on the raw value from g_key_file_get_value(). */
|
2017-10-24 08:44:46 +02:00
|
|
|
str = nm_config_keyfile_get_value(NM_CONFIG_DATA_GET_PRIVATE(self)->keyfile,
|
|
|
|
|
group,
|
|
|
|
|
key,
|
|
|
|
|
NM_CONFIG_GET_VALUE_RAW);
|
2015-06-09 09:06:53 +02:00
|
|
|
if (str) {
|
|
|
|
|
value = nm_config_parse_boolean(str, default_value);
|
|
|
|
|
g_free(str);
|
|
|
|
|
}
|
|
|
|
|
return value;
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-24 08:44:46 +02:00
|
|
|
gint64
|
|
|
|
|
nm_config_data_get_value_int64(const NMConfigData *self,
|
2021-11-09 13:28:54 +01:00
|
|
|
const char *group,
|
|
|
|
|
const char *key,
|
2017-10-24 08:44:46 +02:00
|
|
|
guint base,
|
|
|
|
|
gint64 min,
|
|
|
|
|
gint64 max,
|
|
|
|
|
gint64 fallback)
|
|
|
|
|
{
|
|
|
|
|
int errsv;
|
|
|
|
|
gint64 val;
|
2021-11-09 13:28:54 +01:00
|
|
|
char *str;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-10-24 08:44:46 +02:00
|
|
|
g_return_val_if_fail(NM_IS_CONFIG_DATA(self), fallback);
|
|
|
|
|
g_return_val_if_fail(group && *group, fallback);
|
|
|
|
|
g_return_val_if_fail(key && *key, fallback);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-10-24 08:44:46 +02:00
|
|
|
str = nm_config_keyfile_get_value(NM_CONFIG_DATA_GET_PRIVATE(self)->keyfile,
|
|
|
|
|
group,
|
|
|
|
|
key,
|
|
|
|
|
NM_CONFIG_GET_VALUE_NONE);
|
|
|
|
|
val = _nm_utils_ascii_str_to_int64(str, base, min, max, fallback);
|
|
|
|
|
if (str) {
|
|
|
|
|
errsv = errno;
|
|
|
|
|
g_free(str);
|
|
|
|
|
errno = errsv;
|
|
|
|
|
}
|
|
|
|
|
return val;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-25 13:54:42 +01:00
|
|
|
char **
|
|
|
|
|
nm_config_data_get_plugins(const NMConfigData *self, gboolean allow_default)
|
|
|
|
|
{
|
2021-11-09 13:28:54 +01:00
|
|
|
gs_free_error GError *error = NULL;
|
2016-11-25 13:54:42 +01:00
|
|
|
const NMConfigDataPrivate *priv;
|
2021-11-09 13:28:54 +01:00
|
|
|
char **list;
|
2016-11-25 13:54:42 +01:00
|
|
|
|
|
|
|
|
g_return_val_if_fail(self, NULL);
|
|
|
|
|
|
|
|
|
|
priv = NM_CONFIG_DATA_GET_PRIVATE(self);
|
|
|
|
|
|
2020-05-05 08:28:04 +02:00
|
|
|
list = g_key_file_get_string_list(priv->keyfile,
|
|
|
|
|
NM_CONFIG_KEYFILE_GROUP_MAIN,
|
|
|
|
|
"plugins",
|
|
|
|
|
NULL,
|
|
|
|
|
&error);
|
|
|
|
|
if (nm_keyfile_error_is_not_found(error) && allow_default) {
|
2020-09-02 17:36:08 +02:00
|
|
|
nm_auto_unref_keyfile GKeyFile *kf = nm_config_create_keyfile();
|
2016-11-25 13:54:42 +01:00
|
|
|
|
2018-04-18 14:13:28 +02:00
|
|
|
/* let keyfile split the default string according to its own escaping rules. */
|
2016-11-25 14:17:30 +01:00
|
|
|
g_key_file_set_value(kf,
|
|
|
|
|
NM_CONFIG_KEYFILE_GROUP_MAIN,
|
|
|
|
|
"plugins",
|
|
|
|
|
NM_CONFIG_DEFAULT_MAIN_PLUGINS);
|
2016-11-25 13:54:42 +01:00
|
|
|
list = g_key_file_get_string_list(kf, NM_CONFIG_KEYFILE_GROUP_MAIN, "plugins", NULL, NULL);
|
|
|
|
|
}
|
2021-07-29 10:02:11 +02:00
|
|
|
return nm_strv_cleanup(list, TRUE, TRUE, TRUE);
|
2016-11-25 13:54:42 +01:00
|
|
|
}
|
|
|
|
|
|
2017-08-09 15:19:54 +08:00
|
|
|
gboolean
|
|
|
|
|
nm_config_data_get_connectivity_enabled(const NMConfigData *self)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail(self, FALSE);
|
|
|
|
|
|
|
|
|
|
return NM_CONFIG_DATA_GET_PRIVATE(self)->connectivity.enabled;
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-11 17:57:20 +02:00
|
|
|
const char *
|
|
|
|
|
nm_config_data_get_connectivity_uri(const NMConfigData *self)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail(self, NULL);
|
|
|
|
|
|
|
|
|
|
return NM_CONFIG_DATA_GET_PRIVATE(self)->connectivity.uri;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-06 18:28:56 +01:00
|
|
|
guint
|
2014-07-11 17:57:20 +02:00
|
|
|
nm_config_data_get_connectivity_interval(const NMConfigData *self)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail(self, 0);
|
|
|
|
|
|
2015-05-19 14:56:29 +02:00
|
|
|
return NM_CONFIG_DATA_GET_PRIVATE(self)->connectivity.interval;
|
2014-07-11 17:57:20 +02:00
|
|
|
}
|
|
|
|
|
|
2024-06-12 14:20:21 -04:00
|
|
|
guint
|
|
|
|
|
nm_config_data_get_connectivity_timeout(const NMConfigData *self)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail(self, 0);
|
|
|
|
|
|
|
|
|
|
return NM_CONFIG_DATA_GET_PRIVATE(self)->connectivity.timeout;
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-11 17:57:20 +02:00
|
|
|
const char *
|
|
|
|
|
nm_config_data_get_connectivity_response(const NMConfigData *self)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail(self != NULL, NULL);
|
|
|
|
|
|
|
|
|
|
return NM_CONFIG_DATA_GET_PRIVATE(self)->connectivity.response;
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-22 21:19:40 +01:00
|
|
|
int
|
|
|
|
|
nm_config_data_get_autoconnect_retries_default(const NMConfigData *self)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail(self, FALSE);
|
|
|
|
|
|
|
|
|
|
return NM_CONFIG_DATA_GET_PRIVATE(self)->autoconnect_retries_default;
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-07 17:09:52 +01:00
|
|
|
const char *const *
|
|
|
|
|
nm_config_data_get_no_auto_default(const NMConfigData *self)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail(self, FALSE);
|
|
|
|
|
|
|
|
|
|
return (const char *const *) NM_CONFIG_DATA_GET_PRIVATE(self)->no_auto_default.arr;
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-07 23:27:01 +02:00
|
|
|
gboolean
|
|
|
|
|
nm_config_data_get_no_auto_default_for_device(const NMConfigData *self, NMDevice *device)
|
2015-01-07 17:09:52 +01:00
|
|
|
{
|
2016-09-29 13:49:01 +02:00
|
|
|
const NMConfigDataPrivate *priv;
|
2015-06-07 23:27:01 +02:00
|
|
|
|
|
|
|
|
g_return_val_if_fail(NM_IS_CONFIG_DATA(self), FALSE);
|
|
|
|
|
g_return_val_if_fail(NM_IS_DEVICE(device), FALSE);
|
2015-01-07 17:09:52 +01:00
|
|
|
|
2015-06-07 23:27:01 +02:00
|
|
|
priv = NM_CONFIG_DATA_GET_PRIVATE(self);
|
|
|
|
|
return nm_device_spec_match_list(device, priv->no_auto_default.specs)
|
|
|
|
|
|| nm_device_spec_match_list(device, priv->no_auto_default.specs_config);
|
2015-01-07 17:09:52 +01:00
|
|
|
}
|
2014-07-11 17:57:20 +02:00
|
|
|
|
2015-02-12 17:35:14 +01:00
|
|
|
const char *
|
|
|
|
|
nm_config_data_get_dns_mode(const NMConfigData *self)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail(self, NULL);
|
|
|
|
|
|
|
|
|
|
return NM_CONFIG_DATA_GET_PRIVATE(self)->dns_mode;
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-20 11:11:32 +02:00
|
|
|
const char *
|
|
|
|
|
nm_config_data_get_rc_manager(const NMConfigData *self)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail(self, NULL);
|
|
|
|
|
|
|
|
|
|
return NM_CONFIG_DATA_GET_PRIVATE(self)->rc_manager;
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-03 14:35:32 +02:00
|
|
|
gboolean
|
|
|
|
|
nm_config_data_get_systemd_resolved(const NMConfigData *self)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail(self, FALSE);
|
|
|
|
|
|
|
|
|
|
return NM_CONFIG_DATA_GET_PRIVATE(self)->systemd_resolved;
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-27 16:15:41 +01:00
|
|
|
const char *
|
|
|
|
|
nm_config_data_get_iwd_config_path(const NMConfigData *self)
|
|
|
|
|
{
|
|
|
|
|
return NM_CONFIG_DATA_GET_PRIVATE(self)->iwd_config_path;
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-12 16:34:40 +02:00
|
|
|
gboolean
|
|
|
|
|
nm_config_data_get_ignore_carrier_for_port(const NMConfigData *self,
|
2024-05-27 17:58:08 +02:00
|
|
|
const char *controller,
|
2024-07-04 12:45:42 +02:00
|
|
|
const char *port_type)
|
2023-06-12 16:34:40 +02:00
|
|
|
{
|
|
|
|
|
const char *value;
|
|
|
|
|
gboolean has_match;
|
|
|
|
|
int m;
|
|
|
|
|
NMMatchSpecDeviceData match_data;
|
|
|
|
|
|
|
|
|
|
g_return_val_if_fail(NM_IS_CONFIG_DATA(self), FALSE);
|
|
|
|
|
|
2024-07-04 12:45:42 +02:00
|
|
|
if (!controller || !port_type)
|
2023-06-12 16:34:40 +02:00
|
|
|
goto out_default;
|
|
|
|
|
|
2024-05-27 17:58:08 +02:00
|
|
|
if (!nm_utils_ifname_valid_kernel(controller, NULL))
|
2023-06-12 16:34:40 +02:00
|
|
|
goto out_default;
|
|
|
|
|
|
2024-10-04 10:45:56 +02:00
|
|
|
match_data = (NMMatchSpecDeviceData) {
|
2024-05-27 17:58:08 +02:00
|
|
|
.interface_name = controller,
|
2024-07-04 12:45:42 +02:00
|
|
|
.device_type = port_type,
|
2023-06-12 16:34:40 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
value = _config_data_get_device_config(self,
|
|
|
|
|
NM_CONFIG_KEYFILE_KEY_DEVICE_IGNORE_CARRIER,
|
|
|
|
|
&match_data,
|
|
|
|
|
NULL,
|
|
|
|
|
&has_match);
|
|
|
|
|
if (has_match)
|
|
|
|
|
m = nm_config_parse_boolean(value, -1);
|
|
|
|
|
else {
|
|
|
|
|
NMMatchSpecMatchType x;
|
|
|
|
|
|
|
|
|
|
x = nm_match_spec_device(NM_CONFIG_DATA_GET_PRIVATE(self)->ignore_carrier, &match_data);
|
|
|
|
|
m = nm_match_spec_match_type_to_bool(x, -1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (NM_IN_SET(m, TRUE, FALSE))
|
|
|
|
|
return m;
|
|
|
|
|
|
|
|
|
|
out_default:
|
2024-05-27 17:58:08 +02:00
|
|
|
/* if ignore-carrier is not explicitly or detected for the controller, then we assume it's
|
2023-06-12 16:34:40 +02:00
|
|
|
* enabled. This is in line with nm_config_data_get_ignore_carrier_by_device(), where
|
|
|
|
|
* ignore-carrier is enabled based on nm_device_ignore_carrier_by_default().
|
|
|
|
|
*/
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-17 13:54:32 +02:00
|
|
|
gboolean
|
2023-06-12 16:35:39 +02:00
|
|
|
nm_config_data_get_ignore_carrier_by_device(const NMConfigData *self, NMDevice *device)
|
2015-04-17 13:54:32 +02:00
|
|
|
{
|
2021-06-16 09:50:46 +02:00
|
|
|
const char *value;
|
|
|
|
|
gboolean has_match;
|
|
|
|
|
int m;
|
config: make "ignore-carrier" a per-device configuration option
NetworkManager.conf already contains several per-device settings,
that is, settings that have a device-spec as argument.
main.ignore-carrier
main.no-auto-default
main.assume-ipv6ll-only
keyfile.unmanged-devices
Optimally, these settings should be moved to the new [device*]
section.
For now, only move main.ignore-carrier there. For the others
it may not make sense to do so:
- main.no-auto-default: is already merged with internal state
from /var/lib/NetworkManager/no-auto-default.state. While
NMConfig's write API would be fine to also persist and merge
the no-auto-default setting, we'd still have to read the old
file too. Thus, deprecating this setting gets quite cumbersome
to still handle the old state file.
Also, it seems a less useful setting to configure in the
global configuration aside setting main.no-auto-default=*.
- main.assume-ipv6ll-only: one day, I hope that we no longer
assume connections at all, and this setting becomes entirely
obsolete.
- keyfile.unmanged-devices: this sets NM_UNMANAGED_USER_SETTINGS,
which cannot be overruled via D-Bus. For a future device.managed
setting we want it it to be overwritable via D-Bus by an explicit
user action. Thus, a device.managed property should have a different
semantic, this should be more like a device.unmanaged-force setting,
which could be done.
2016-06-22 13:43:08 +02:00
|
|
|
|
2015-04-17 13:54:32 +02:00
|
|
|
g_return_val_if_fail(NM_IS_CONFIG_DATA(self), FALSE);
|
|
|
|
|
g_return_val_if_fail(NM_IS_DEVICE(device), FALSE);
|
|
|
|
|
|
2023-06-12 13:20:13 +02:00
|
|
|
value = nm_config_data_get_device_config_by_device(self,
|
|
|
|
|
NM_CONFIG_KEYFILE_KEY_DEVICE_IGNORE_CARRIER,
|
|
|
|
|
device,
|
|
|
|
|
&has_match);
|
config: make "ignore-carrier" a per-device configuration option
NetworkManager.conf already contains several per-device settings,
that is, settings that have a device-spec as argument.
main.ignore-carrier
main.no-auto-default
main.assume-ipv6ll-only
keyfile.unmanged-devices
Optimally, these settings should be moved to the new [device*]
section.
For now, only move main.ignore-carrier there. For the others
it may not make sense to do so:
- main.no-auto-default: is already merged with internal state
from /var/lib/NetworkManager/no-auto-default.state. While
NMConfig's write API would be fine to also persist and merge
the no-auto-default setting, we'd still have to read the old
file too. Thus, deprecating this setting gets quite cumbersome
to still handle the old state file.
Also, it seems a less useful setting to configure in the
global configuration aside setting main.no-auto-default=*.
- main.assume-ipv6ll-only: one day, I hope that we no longer
assume connections at all, and this setting becomes entirely
obsolete.
- keyfile.unmanged-devices: this sets NM_UNMANAGED_USER_SETTINGS,
which cannot be overruled via D-Bus. For a future device.managed
setting we want it it to be overwritable via D-Bus by an explicit
user action. Thus, a device.managed property should have a different
semantic, this should be more like a device.unmanaged-force setting,
which could be done.
2016-06-22 13:43:08 +02:00
|
|
|
if (has_match)
|
2017-06-01 22:38:51 +02:00
|
|
|
m = nm_config_parse_boolean(value, -1);
|
|
|
|
|
else
|
|
|
|
|
m = nm_device_spec_match_list_full(device,
|
|
|
|
|
NM_CONFIG_DATA_GET_PRIVATE(self)->ignore_carrier,
|
|
|
|
|
-1);
|
config: make "ignore-carrier" a per-device configuration option
NetworkManager.conf already contains several per-device settings,
that is, settings that have a device-spec as argument.
main.ignore-carrier
main.no-auto-default
main.assume-ipv6ll-only
keyfile.unmanged-devices
Optimally, these settings should be moved to the new [device*]
section.
For now, only move main.ignore-carrier there. For the others
it may not make sense to do so:
- main.no-auto-default: is already merged with internal state
from /var/lib/NetworkManager/no-auto-default.state. While
NMConfig's write API would be fine to also persist and merge
the no-auto-default setting, we'd still have to read the old
file too. Thus, deprecating this setting gets quite cumbersome
to still handle the old state file.
Also, it seems a less useful setting to configure in the
global configuration aside setting main.no-auto-default=*.
- main.assume-ipv6ll-only: one day, I hope that we no longer
assume connections at all, and this setting becomes entirely
obsolete.
- keyfile.unmanged-devices: this sets NM_UNMANAGED_USER_SETTINGS,
which cannot be overruled via D-Bus. For a future device.managed
setting we want it it to be overwritable via D-Bus by an explicit
user action. Thus, a device.managed property should have a different
semantic, this should be more like a device.unmanaged-force setting,
which could be done.
2016-06-22 13:43:08 +02:00
|
|
|
|
2017-06-01 22:38:51 +02:00
|
|
|
if (NM_IN_SET(m, TRUE, FALSE))
|
|
|
|
|
return m;
|
|
|
|
|
|
|
|
|
|
/* if ignore-carrier is not explicitly configed, then it depends on the device (type). */
|
|
|
|
|
return nm_device_ignore_carrier_by_default(device);
|
2015-04-17 13:54:32 +02:00
|
|
|
}
|
|
|
|
|
|
2015-05-20 11:36:37 +02:00
|
|
|
gboolean
|
|
|
|
|
nm_config_data_get_assume_ipv6ll_only(const NMConfigData *self, NMDevice *device)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail(NM_IS_CONFIG_DATA(self), FALSE);
|
|
|
|
|
g_return_val_if_fail(NM_IS_DEVICE(device), FALSE);
|
|
|
|
|
|
|
|
|
|
return nm_device_spec_match_list(device, NM_CONFIG_DATA_GET_PRIVATE(self)->assume_ipv6ll_only);
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-24 20:11:42 +02:00
|
|
|
GKeyFile *
|
|
|
|
|
nm_config_data_clone_keyfile_intern(const NMConfigData *self)
|
|
|
|
|
{
|
2016-09-29 13:49:01 +02:00
|
|
|
const NMConfigDataPrivate *priv;
|
2021-11-09 13:28:54 +01:00
|
|
|
GKeyFile *keyfile;
|
2015-06-24 20:11:42 +02:00
|
|
|
|
|
|
|
|
g_return_val_if_fail(NM_IS_CONFIG_DATA(self), FALSE);
|
|
|
|
|
|
|
|
|
|
priv = NM_CONFIG_DATA_GET_PRIVATE(self);
|
|
|
|
|
|
|
|
|
|
keyfile = nm_config_create_keyfile();
|
|
|
|
|
if (priv->keyfile_intern)
|
|
|
|
|
_nm_keyfile_copy(keyfile, priv->keyfile_intern);
|
|
|
|
|
return keyfile;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GKeyFile *
|
|
|
|
|
_nm_config_data_get_keyfile(const NMConfigData *self)
|
|
|
|
|
{
|
|
|
|
|
return NM_CONFIG_DATA_GET_PRIVATE(self)->keyfile;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GKeyFile *
|
|
|
|
|
_nm_config_data_get_keyfile_intern(const NMConfigData *self)
|
|
|
|
|
{
|
|
|
|
|
return NM_CONFIG_DATA_GET_PRIVATE(self)->keyfile_intern;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GKeyFile *
|
|
|
|
|
_nm_config_data_get_keyfile_user(const NMConfigData *self)
|
|
|
|
|
{
|
|
|
|
|
return NM_CONFIG_DATA_GET_PRIVATE(self)->keyfile_user;
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-02 18:22:50 +02:00
|
|
|
/*****************************************************************************/
|
2015-01-07 14:30:14 +01:00
|
|
|
|
2019-12-10 08:51:03 +01:00
|
|
|
static NMAuthPolkitMode
|
|
|
|
|
nm_auth_polkit_mode_from_string(const char *str)
|
|
|
|
|
{
|
|
|
|
|
int as_bool;
|
|
|
|
|
|
|
|
|
|
if (!str)
|
|
|
|
|
return NM_AUTH_POLKIT_MODE_UNKNOWN;
|
|
|
|
|
|
|
|
|
|
if (nm_streq(str, "root-only"))
|
|
|
|
|
return NM_AUTH_POLKIT_MODE_ROOT_ONLY;
|
|
|
|
|
|
|
|
|
|
as_bool = _nm_utils_ascii_str_to_bool(str, -1);
|
|
|
|
|
if (as_bool != -1) {
|
|
|
|
|
return as_bool ? NM_AUTH_POLKIT_MODE_USE_POLKIT : NM_AUTH_POLKIT_MODE_ALLOW_ALL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NM_AUTH_POLKIT_MODE_UNKNOWN;
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-11 11:40:22 +01:00
|
|
|
static NMAuthPolkitMode
|
|
|
|
|
_config_data_get_main_auth_polkit(const NMConfigData *self, gboolean *out_invalid_config)
|
2019-12-10 08:51:03 +01:00
|
|
|
{
|
|
|
|
|
NMAuthPolkitMode auth_polkit_mode;
|
2021-11-09 13:28:54 +01:00
|
|
|
gs_free char *str = NULL;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-12-10 08:51:03 +01:00
|
|
|
str = nm_config_data_get_value(self,
|
|
|
|
|
NM_CONFIG_KEYFILE_GROUP_MAIN,
|
|
|
|
|
NM_CONFIG_KEYFILE_KEY_MAIN_AUTH_POLKIT,
|
|
|
|
|
NM_CONFIG_GET_VALUE_STRIP | NM_CONFIG_GET_VALUE_NO_EMPTY);
|
|
|
|
|
auth_polkit_mode = nm_auth_polkit_mode_from_string(str);
|
|
|
|
|
if (auth_polkit_mode == NM_AUTH_POLKIT_MODE_UNKNOWN) {
|
2019-12-11 11:40:22 +01:00
|
|
|
NM_SET_OUT(out_invalid_config, (str != NULL));
|
2019-12-10 08:51:03 +01:00
|
|
|
auth_polkit_mode = nm_auth_polkit_mode_from_string(NM_CONFIG_DEFAULT_MAIN_AUTH_POLKIT);
|
|
|
|
|
if (auth_polkit_mode == NM_AUTH_POLKIT_MODE_UNKNOWN) {
|
|
|
|
|
nm_assert_not_reached();
|
|
|
|
|
auth_polkit_mode = NM_AUTH_POLKIT_MODE_ROOT_ONLY;
|
|
|
|
|
}
|
2019-12-11 11:40:22 +01:00
|
|
|
} else
|
|
|
|
|
NM_SET_OUT(out_invalid_config, FALSE);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-12-10 08:51:03 +01:00
|
|
|
return auth_polkit_mode;
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-11 11:40:22 +01:00
|
|
|
NMAuthPolkitMode
|
|
|
|
|
nm_config_data_get_main_auth_polkit(const NMConfigData *self)
|
|
|
|
|
{
|
|
|
|
|
return _config_data_get_main_auth_polkit(self, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-10 08:51:03 +01:00
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2015-06-11 23:43:29 +02:00
|
|
|
/**
|
|
|
|
|
* nm_config_data_get_groups:
|
|
|
|
|
* @self: the #NMConfigData instance
|
|
|
|
|
*
|
2016-02-24 17:12:39 +01:00
|
|
|
* Returns: (transfer full): the list of groups in the configuration. The order
|
2015-06-11 23:43:29 +02:00
|
|
|
* of the section is undefined, as the configuration gets merged from multiple
|
|
|
|
|
* sources.
|
|
|
|
|
*/
|
|
|
|
|
char **
|
|
|
|
|
nm_config_data_get_groups(const NMConfigData *self)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail(NM_IS_CONFIG_DATA(self), NULL);
|
|
|
|
|
|
|
|
|
|
return g_key_file_get_groups(NM_CONFIG_DATA_GET_PRIVATE(self)->keyfile, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char **
|
|
|
|
|
nm_config_data_get_keys(const NMConfigData *self, const char *group)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail(NM_IS_CONFIG_DATA(self), NULL);
|
|
|
|
|
g_return_val_if_fail(group && *group, NULL);
|
|
|
|
|
|
|
|
|
|
return g_key_file_get_keys(NM_CONFIG_DATA_GET_PRIVATE(self)->keyfile, group, NULL, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-10 11:59:46 +02:00
|
|
|
/**
|
|
|
|
|
* nm_config_data_is_intern_atomic_group:
|
|
|
|
|
* @self:
|
|
|
|
|
* @group: name of the group to check.
|
|
|
|
|
*
|
|
|
|
|
* whether a configuration group @group exists and is entirely overwritten
|
|
|
|
|
* by internal configuration, i.e. whether it is an atomic group that is
|
|
|
|
|
* overwritten.
|
|
|
|
|
*
|
|
|
|
|
* It doesn't say, that there actually is a user setting that was overwritten. That
|
|
|
|
|
* means there could be no corresponding section defined in user configuration
|
|
|
|
|
* that required overwriting.
|
|
|
|
|
*
|
|
|
|
|
* Returns: %TRUE if @group exists and is an atomic group set via internal configuration.
|
|
|
|
|
*/
|
|
|
|
|
gboolean
|
|
|
|
|
nm_config_data_is_intern_atomic_group(const NMConfigData *self, const char *group)
|
|
|
|
|
{
|
2016-09-29 13:49:01 +02:00
|
|
|
const NMConfigDataPrivate *priv;
|
2015-06-10 11:59:46 +02:00
|
|
|
|
|
|
|
|
g_return_val_if_fail(NM_IS_CONFIG_DATA(self), FALSE);
|
|
|
|
|
g_return_val_if_fail(group && *group, FALSE);
|
|
|
|
|
|
|
|
|
|
priv = NM_CONFIG_DATA_GET_PRIVATE(self);
|
|
|
|
|
|
|
|
|
|
if (!priv->keyfile_intern
|
|
|
|
|
|| !g_key_file_has_key(priv->keyfile_intern,
|
|
|
|
|
group,
|
|
|
|
|
NM_CONFIG_KEYFILE_KEY_ATOMIC_SECTION_WAS,
|
|
|
|
|
NULL))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
/* we have a .was entry for the section. That means that the section would be overwritten
|
|
|
|
|
* from user configuration. But it doesn't mean that the merged configuration contains this
|
|
|
|
|
* groups, because the internal setting could hide the user section.
|
|
|
|
|
* Only return TRUE, if we actually have such a group in the merged configuration.*/
|
|
|
|
|
return g_key_file_has_group(priv->keyfile, group);
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-02 18:22:50 +02:00
|
|
|
/*****************************************************************************/
|
2015-06-11 23:43:29 +02:00
|
|
|
|
2015-06-24 20:11:42 +02:00
|
|
|
static GKeyFile *
|
|
|
|
|
_merge_keyfiles(GKeyFile *keyfile_user, GKeyFile *keyfile_intern)
|
|
|
|
|
{
|
|
|
|
|
gs_strfreev char **groups = NULL;
|
|
|
|
|
guint g, k;
|
2021-11-09 13:28:54 +01:00
|
|
|
GKeyFile *keyfile;
|
2015-06-24 20:11:42 +02:00
|
|
|
gsize ngroups;
|
|
|
|
|
|
|
|
|
|
keyfile = nm_config_create_keyfile();
|
|
|
|
|
if (keyfile_user)
|
|
|
|
|
_nm_keyfile_copy(keyfile, keyfile_user);
|
|
|
|
|
if (!keyfile_intern)
|
|
|
|
|
return keyfile;
|
|
|
|
|
|
|
|
|
|
groups = g_key_file_get_groups(keyfile_intern, &ngroups);
|
|
|
|
|
if (!groups)
|
|
|
|
|
return keyfile;
|
|
|
|
|
|
|
|
|
|
/* we must reverse the order of the connection settings so that we
|
|
|
|
|
* have lowest priority last. */
|
|
|
|
|
_nm_config_sort_groups(groups, ngroups);
|
|
|
|
|
for (g = 0; groups[g]; g++) {
|
2021-11-09 13:28:54 +01:00
|
|
|
const char *group = groups[g];
|
2015-06-24 20:11:42 +02:00
|
|
|
gs_strfreev char **keys = NULL;
|
2015-06-10 11:59:46 +02:00
|
|
|
gboolean is_intern, is_atomic = FALSE;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2015-06-24 20:11:42 +02:00
|
|
|
keys = g_key_file_get_keys(keyfile_intern, group, NULL, NULL);
|
|
|
|
|
if (!keys)
|
|
|
|
|
continue;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2022-09-08 16:45:04 +02:00
|
|
|
is_intern = NM_STR_HAS_PREFIX(group, NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN);
|
2015-06-10 11:59:46 +02:00
|
|
|
if (!is_intern
|
|
|
|
|
&& g_key_file_has_key(keyfile_intern,
|
|
|
|
|
group,
|
|
|
|
|
NM_CONFIG_KEYFILE_KEY_ATOMIC_SECTION_WAS,
|
|
|
|
|
NULL)) {
|
|
|
|
|
/* the entire section is atomically overwritten by @keyfile_intern. */
|
|
|
|
|
g_key_file_remove_group(keyfile, group, NULL);
|
|
|
|
|
is_atomic = TRUE;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2015-06-24 20:11:42 +02:00
|
|
|
for (k = 0; keys[k]; k++) {
|
2021-11-09 13:28:54 +01:00
|
|
|
const char *key = keys[k];
|
2015-06-24 20:11:42 +02:00
|
|
|
gs_free char *value = NULL;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2021-03-22 09:37:43 +01:00
|
|
|
if (is_atomic && nm_streq(key, NM_CONFIG_KEYFILE_KEY_ATOMIC_SECTION_WAS))
|
2015-06-10 11:59:46 +02:00
|
|
|
continue;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2015-06-10 11:59:46 +02:00
|
|
|
if (!is_intern && !is_atomic
|
2020-05-06 08:23:18 +02:00
|
|
|
&& NM_STR_HAS_PREFIX_WITH_MORE(key, NM_CONFIG_KEYFILE_KEYPREFIX_WAS)) {
|
2016-02-12 12:34:43 +01:00
|
|
|
const char *key_base = &key[NM_STRLEN(NM_CONFIG_KEYFILE_KEYPREFIX_WAS)];
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2015-06-24 20:11:42 +02:00
|
|
|
if (!g_key_file_has_key(keyfile_intern, group, key_base, NULL))
|
|
|
|
|
g_key_file_remove_key(keyfile, group, key_base, NULL);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2020-05-06 08:23:18 +02:00
|
|
|
if (!is_intern && !is_atomic
|
|
|
|
|
&& NM_STR_HAS_PREFIX_WITH_MORE(key, NM_CONFIG_KEYFILE_KEYPREFIX_SET))
|
2015-06-24 20:11:42 +02:00
|
|
|
continue;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2015-06-24 20:11:42 +02:00
|
|
|
value = g_key_file_get_value(keyfile_intern, group, key, NULL);
|
|
|
|
|
g_key_file_set_value(keyfile, group, key, value);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return keyfile;
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-02 18:22:50 +02:00
|
|
|
/*****************************************************************************/
|
2015-06-24 20:11:42 +02:00
|
|
|
|
2015-06-09 09:59:18 +02:00
|
|
|
static int
|
|
|
|
|
_nm_config_data_log_sort(const char **pa, const char **pb, gpointer dummy)
|
|
|
|
|
{
|
|
|
|
|
gboolean a_is_connection, b_is_connection;
|
2016-06-22 13:14:10 +02:00
|
|
|
gboolean a_is_device, b_is_device;
|
2015-06-24 20:11:42 +02:00
|
|
|
gboolean a_is_intern, b_is_intern;
|
2016-10-06 23:01:46 +02:00
|
|
|
gboolean a_is_main, b_is_main;
|
2015-06-09 09:59:18 +02:00
|
|
|
const char *a = *pa;
|
|
|
|
|
const char *b = *pb;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
core/config: fix duplicate entires in `NetworkManager --print-config` output
_nm_config_data_log_sort() is used for sorting the groups in the
keyfile during nm_config_data_log(). The idea is to present the keyfile
in a defined, but useful order.
However, it is not a total order. That is, it will return c=0 (equal) for
certain groups, if the pre-existing order in the GKeyFile should be
honored. For example, we want to sort all [device*] sections close to
each other, but we want to preserve their relative order. In that case,
the function would return 0 although the group names differed.
Also, _nm_config_data_log_sort() does not expect to receive duplicate names.
It would return c!=0 for comparing "device" and "device".
This means, _nm_config_data_log_sort() is fine for sorting the input as
we have it. However, it cannot be used to binary search the groups. This
caused that some sections might be duplicated in the `NetworkManager
--print-config` output. Otherwise, it had no bad effects.
Fixes(no-backport): 78d34d7c2e00 ('config: fix printing default values for missing sections')
2022-09-08 16:56:16 +02:00
|
|
|
nm_assert(a && b && !nm_streq(a, b));
|
|
|
|
|
|
2015-06-24 20:11:42 +02:00
|
|
|
/* we sort intern groups to the end. */
|
2022-09-08 16:45:04 +02:00
|
|
|
a_is_intern = NM_STR_HAS_PREFIX(a, NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN);
|
|
|
|
|
b_is_intern = NM_STR_HAS_PREFIX(b, NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2015-06-24 20:11:42 +02:00
|
|
|
if (a_is_intern && b_is_intern)
|
|
|
|
|
return 0;
|
|
|
|
|
if (a_is_intern)
|
|
|
|
|
return 1;
|
|
|
|
|
if (b_is_intern)
|
|
|
|
|
return -1;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2015-06-09 09:59:18 +02:00
|
|
|
/* we sort connection groups before intern groups (to the end). */
|
2022-09-08 16:45:04 +02:00
|
|
|
a_is_connection = NM_STR_HAS_PREFIX(a, NM_CONFIG_KEYFILE_GROUPPREFIX_CONNECTION);
|
|
|
|
|
b_is_connection = NM_STR_HAS_PREFIX(b, NM_CONFIG_KEYFILE_GROUPPREFIX_CONNECTION);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2015-06-09 09:59:18 +02:00
|
|
|
if (a_is_connection && b_is_connection) {
|
|
|
|
|
/* if both are connection groups, we want the explicit [connection] group first. */
|
2016-02-12 12:34:43 +01:00
|
|
|
a_is_connection = a[NM_STRLEN(NM_CONFIG_KEYFILE_GROUPPREFIX_CONNECTION)] == '\0';
|
|
|
|
|
b_is_connection = b[NM_STRLEN(NM_CONFIG_KEYFILE_GROUPPREFIX_CONNECTION)] == '\0';
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2015-06-09 09:59:18 +02:00
|
|
|
if (a_is_connection != b_is_connection) {
|
|
|
|
|
if (a_is_connection)
|
|
|
|
|
return -1;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
/* the sections are ordered lowest-priority first. Reverse their order. */
|
|
|
|
|
return pa < pb ? 1 : -1;
|
|
|
|
|
}
|
|
|
|
|
if (a_is_connection && !b_is_connection)
|
|
|
|
|
return 1;
|
|
|
|
|
if (b_is_connection && !a_is_connection)
|
|
|
|
|
return -1;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2016-06-22 13:14:10 +02:00
|
|
|
/* we sort device groups before connection groups (to the end). */
|
2022-09-08 16:45:04 +02:00
|
|
|
a_is_device = NM_STR_HAS_PREFIX(a, NM_CONFIG_KEYFILE_GROUPPREFIX_DEVICE);
|
|
|
|
|
b_is_device = NM_STR_HAS_PREFIX(b, NM_CONFIG_KEYFILE_GROUPPREFIX_DEVICE);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2016-06-22 13:14:10 +02:00
|
|
|
if (a_is_device && b_is_device) {
|
|
|
|
|
/* if both are device groups, we want the explicit [device] group first. */
|
|
|
|
|
a_is_device = a[NM_STRLEN(NM_CONFIG_KEYFILE_GROUPPREFIX_DEVICE)] == '\0';
|
|
|
|
|
b_is_device = b[NM_STRLEN(NM_CONFIG_KEYFILE_GROUPPREFIX_DEVICE)] == '\0';
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2016-06-22 13:14:10 +02:00
|
|
|
if (a_is_device != b_is_device) {
|
|
|
|
|
if (a_is_device)
|
|
|
|
|
return -1;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
/* the sections are ordered lowest-priority first. Reverse their order. */
|
|
|
|
|
return pa < pb ? 1 : -1;
|
|
|
|
|
}
|
|
|
|
|
if (a_is_device && !b_is_device)
|
|
|
|
|
return 1;
|
|
|
|
|
if (b_is_device && !a_is_device)
|
|
|
|
|
return -1;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2016-10-06 23:01:46 +02:00
|
|
|
a_is_main = nm_streq0(a, "main");
|
|
|
|
|
b_is_main = nm_streq0(b, "main");
|
|
|
|
|
if (a_is_main != b_is_main)
|
|
|
|
|
return a_is_main ? -1 : 1;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2016-10-06 23:01:46 +02:00
|
|
|
return g_strcmp0(a, b);
|
2015-06-09 09:59:18 +02:00
|
|
|
}
|
|
|
|
|
|
2017-02-17 10:53:33 +01:00
|
|
|
static const struct {
|
2016-09-28 18:06:19 +02:00
|
|
|
const char *group;
|
|
|
|
|
const char *key;
|
|
|
|
|
const char *value;
|
|
|
|
|
} default_values[] = {
|
2016-11-25 14:39:59 +01:00
|
|
|
{NM_CONFIG_KEYFILE_GROUP_MAIN, "plugins", NM_CONFIG_DEFAULT_MAIN_PLUGINS},
|
|
|
|
|
{NM_CONFIG_KEYFILE_GROUP_MAIN, "rc-manager", NM_CONFIG_DEFAULT_MAIN_RC_MANAGER},
|
2023-07-24 14:20:04 +02:00
|
|
|
{NM_CONFIG_KEYFILE_GROUP_MAIN, "migrate-ifcfg-rh", NM_CONFIG_DEFAULT_MAIN_MIGRATE_IFCFG_RH},
|
2016-11-25 14:39:59 +01:00
|
|
|
{NM_CONFIG_KEYFILE_GROUP_MAIN,
|
|
|
|
|
NM_CONFIG_KEYFILE_KEY_MAIN_AUTH_POLKIT,
|
|
|
|
|
NM_CONFIG_DEFAULT_MAIN_AUTH_POLKIT},
|
2016-11-25 15:07:19 +01:00
|
|
|
{NM_CONFIG_KEYFILE_GROUP_MAIN, NM_CONFIG_KEYFILE_KEY_MAIN_DHCP, NM_CONFIG_DEFAULT_MAIN_DHCP},
|
2020-11-27 16:15:41 +01:00
|
|
|
{NM_CONFIG_KEYFILE_GROUP_MAIN, NM_CONFIG_KEYFILE_KEY_MAIN_IWD_CONFIG_PATH, ""},
|
2016-11-25 14:39:59 +01:00
|
|
|
{NM_CONFIG_KEYFILE_GROUP_LOGGING, "backend", NM_CONFIG_DEFAULT_LOGGING_BACKEND},
|
|
|
|
|
{NM_CONFIG_KEYFILE_GROUP_LOGGING, "audit", NM_CONFIG_DEFAULT_LOGGING_AUDIT},
|
2021-12-02 18:34:10 -07:00
|
|
|
{NM_CONFIG_KEYFILE_GROUPPREFIX_DEVICE,
|
|
|
|
|
NM_CONFIG_KEYFILE_KEY_DEVICE_WIFI_BACKEND,
|
|
|
|
|
NM_CONFIG_DEFAULT_WIFI_BACKEND},
|
2016-09-28 18:06:19 +02:00
|
|
|
};
|
|
|
|
|
|
2015-06-09 09:59:18 +02:00
|
|
|
void
|
2021-11-09 13:28:54 +01:00
|
|
|
nm_config_data_log(const NMConfigData *self,
|
|
|
|
|
const char *prefix,
|
|
|
|
|
const char *key_prefix,
|
|
|
|
|
const char *no_auto_default_file,
|
2015-11-20 17:52:54 +01:00
|
|
|
/* FILE* */ gpointer print_stream)
|
2015-06-09 09:59:18 +02:00
|
|
|
{
|
2021-11-09 13:28:54 +01:00
|
|
|
const NMConfigDataPrivate *priv;
|
|
|
|
|
gs_strfreev char **groups = NULL;
|
|
|
|
|
gsize ngroups;
|
|
|
|
|
guint g, k, i;
|
|
|
|
|
FILE *stream = print_stream;
|
2016-10-06 23:01:46 +02:00
|
|
|
gs_unref_ptrarray GPtrArray *groups_full = NULL;
|
|
|
|
|
gboolean print_default = !!stream;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2015-06-09 09:59:18 +02:00
|
|
|
g_return_if_fail(NM_IS_CONFIG_DATA(self));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2015-11-20 17:52:54 +01:00
|
|
|
if (!stream && !nm_logging_enabled(LOGL_DEBUG, LOGD_CORE))
|
2015-06-09 09:59:18 +02:00
|
|
|
return;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2015-06-09 09:59:18 +02:00
|
|
|
if (!prefix)
|
|
|
|
|
prefix = "";
|
2015-11-20 17:52:54 +01:00
|
|
|
if (!key_prefix)
|
|
|
|
|
key_prefix = "";
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2015-11-20 17:52:54 +01:00
|
|
|
#define _LOG(stream, prefix, ...) \
|
|
|
|
|
G_STMT_START \
|
|
|
|
|
{ \
|
|
|
|
|
if (!stream) \
|
2017-03-01 10:20:01 +00:00
|
|
|
_nm_log(LOGL_DEBUG, \
|
|
|
|
|
LOGD_CORE, \
|
|
|
|
|
0, \
|
|
|
|
|
NULL, \
|
|
|
|
|
NULL, \
|
2015-11-20 17:52:54 +01:00
|
|
|
"%s"_NM_UTILS_MACRO_FIRST(__VA_ARGS__) "%s", \
|
|
|
|
|
prefix _NM_UTILS_MACRO_REST(__VA_ARGS__), \
|
|
|
|
|
""); \
|
2020-09-28 16:03:33 +02:00
|
|
|
else \
|
2015-11-20 17:52:54 +01:00
|
|
|
fprintf(stream, \
|
2017-03-01 10:20:01 +00:00
|
|
|
"%s"_NM_UTILS_MACRO_FIRST(__VA_ARGS__) "%s", \
|
|
|
|
|
prefix _NM_UTILS_MACRO_REST(__VA_ARGS__), \
|
2015-11-20 17:52:54 +01:00
|
|
|
"\n"); \
|
|
|
|
|
} \
|
|
|
|
|
G_STMT_END
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2015-06-09 09:59:18 +02:00
|
|
|
priv = NM_CONFIG_DATA_GET_PRIVATE(self);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2015-06-09 09:59:18 +02:00
|
|
|
groups = g_key_file_get_groups(priv->keyfile, &ngroups);
|
|
|
|
|
if (!groups)
|
|
|
|
|
ngroups = 0;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2016-10-06 23:01:46 +02:00
|
|
|
groups_full = g_ptr_array_sized_new(ngroups + 5);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2016-10-06 23:01:46 +02:00
|
|
|
if (ngroups) {
|
core/config: fix duplicate entires in `NetworkManager --print-config` output
_nm_config_data_log_sort() is used for sorting the groups in the
keyfile during nm_config_data_log(). The idea is to present the keyfile
in a defined, but useful order.
However, it is not a total order. That is, it will return c=0 (equal) for
certain groups, if the pre-existing order in the GKeyFile should be
honored. For example, we want to sort all [device*] sections close to
each other, but we want to preserve their relative order. In that case,
the function would return 0 although the group names differed.
Also, _nm_config_data_log_sort() does not expect to receive duplicate names.
It would return c!=0 for comparing "device" and "device".
This means, _nm_config_data_log_sort() is fine for sorting the input as
we have it. However, it cannot be used to binary search the groups. This
caused that some sections might be duplicated in the `NetworkManager
--print-config` output. Otherwise, it had no bad effects.
Fixes(no-backport): 78d34d7c2e00 ('config: fix printing default values for missing sections')
2022-09-08 16:56:16 +02:00
|
|
|
/* g_key_file_get_groups() can return duplicates ( :( ), but the
|
|
|
|
|
* keyfile that we constructed should not have any. Assert for that. */
|
|
|
|
|
nm_assert(!nm_strv_has_duplicate((const char *const *) groups, ngroups, FALSE));
|
|
|
|
|
|
2016-10-06 23:01:46 +02:00
|
|
|
g_ptr_array_set_size(groups_full, ngroups);
|
|
|
|
|
memcpy(groups_full->pdata, groups, sizeof(groups[0]) * ngroups);
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2016-10-06 23:01:46 +02:00
|
|
|
if (print_default) {
|
|
|
|
|
for (g = 0; g < G_N_ELEMENTS(default_values); g++) {
|
|
|
|
|
const char *group = default_values[g].group;
|
core/config: fix duplicate entires in `NetworkManager --print-config` output
_nm_config_data_log_sort() is used for sorting the groups in the
keyfile during nm_config_data_log(). The idea is to present the keyfile
in a defined, but useful order.
However, it is not a total order. That is, it will return c=0 (equal) for
certain groups, if the pre-existing order in the GKeyFile should be
honored. For example, we want to sort all [device*] sections close to
each other, but we want to preserve their relative order. In that case,
the function would return 0 although the group names differed.
Also, _nm_config_data_log_sort() does not expect to receive duplicate names.
It would return c!=0 for comparing "device" and "device".
This means, _nm_config_data_log_sort() is fine for sorting the input as
we have it. However, it cannot be used to binary search the groups. This
caused that some sections might be duplicated in the `NetworkManager
--print-config` output. Otherwise, it had no bad effects.
Fixes(no-backport): 78d34d7c2e00 ('config: fix printing default values for missing sections')
2022-09-08 16:56:16 +02:00
|
|
|
guint g2;
|
|
|
|
|
|
|
|
|
|
if (g > 0) {
|
|
|
|
|
if (nm_streq(group, default_values[g - 1].group)) {
|
|
|
|
|
/* Repeated values. We already added this one. Skip */
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (NM_MORE_ASSERT_ONCE(20)) {
|
|
|
|
|
/* We require that the default values are grouped by their "group".
|
|
|
|
|
* That is, all default values for a certain "group" are close to
|
|
|
|
|
* each other in the list. Assert for that. */
|
2024-05-08 09:57:35 +02:00
|
|
|
for (g2 = g + 1; g2 < G_N_ELEMENTS(default_values); g2++) {
|
core/config: fix duplicate entires in `NetworkManager --print-config` output
_nm_config_data_log_sort() is used for sorting the groups in the
keyfile during nm_config_data_log(). The idea is to present the keyfile
in a defined, but useful order.
However, it is not a total order. That is, it will return c=0 (equal) for
certain groups, if the pre-existing order in the GKeyFile should be
honored. For example, we want to sort all [device*] sections close to
each other, but we want to preserve their relative order. In that case,
the function would return 0 although the group names differed.
Also, _nm_config_data_log_sort() does not expect to receive duplicate names.
It would return c!=0 for comparing "device" and "device".
This means, _nm_config_data_log_sort() is fine for sorting the input as
we have it. However, it cannot be used to binary search the groups. This
caused that some sections might be duplicated in the `NetworkManager
--print-config` output. Otherwise, it had no bad effects.
Fixes(no-backport): 78d34d7c2e00 ('config: fix printing default values for missing sections')
2022-09-08 16:56:16 +02:00
|
|
|
nm_assert(!nm_streq(default_values[g - 1].group, default_values[g2].group));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (g2 = 0; g2 < groups_full->len; g2++) {
|
|
|
|
|
if (nm_streq(group, groups_full->pdata[g2]))
|
|
|
|
|
goto next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g_ptr_array_add(groups_full, (gpointer) group);
|
|
|
|
|
|
|
|
|
|
next:
|
|
|
|
|
(void) 0;
|
2015-06-09 09:59:18 +02:00
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
}
|
|
|
|
|
|
core/config: fix duplicate entires in `NetworkManager --print-config` output
_nm_config_data_log_sort() is used for sorting the groups in the
keyfile during nm_config_data_log(). The idea is to present the keyfile
in a defined, but useful order.
However, it is not a total order. That is, it will return c=0 (equal) for
certain groups, if the pre-existing order in the GKeyFile should be
honored. For example, we want to sort all [device*] sections close to
each other, but we want to preserve their relative order. In that case,
the function would return 0 although the group names differed.
Also, _nm_config_data_log_sort() does not expect to receive duplicate names.
It would return c!=0 for comparing "device" and "device".
This means, _nm_config_data_log_sort() is fine for sorting the input as
we have it. However, it cannot be used to binary search the groups. This
caused that some sections might be duplicated in the `NetworkManager
--print-config` output. Otherwise, it had no bad effects.
Fixes(no-backport): 78d34d7c2e00 ('config: fix printing default values for missing sections')
2022-09-08 16:56:16 +02:00
|
|
|
g_ptr_array_sort_with_data(groups_full, (GCompareDataFunc) _nm_config_data_log_sort, NULL);
|
|
|
|
|
|
2015-11-20 17:52:54 +01:00
|
|
|
if (!stream)
|
2016-10-06 23:01:46 +02:00
|
|
|
_LOG(stream, prefix, "config-data[%p]: %u groups", self, groups_full->len);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2016-10-06 23:01:46 +02:00
|
|
|
for (g = 0; g < groups_full->len; g++) {
|
2021-11-09 13:28:54 +01:00
|
|
|
const char *group = groups_full->pdata[g];
|
2015-06-09 09:59:18 +02:00
|
|
|
gs_strfreev char **keys = NULL;
|
2015-06-10 11:59:46 +02:00
|
|
|
gboolean is_atomic;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2015-06-10 11:59:46 +02:00
|
|
|
is_atomic = nm_config_data_is_intern_atomic_group(self, group);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2015-11-20 17:52:54 +01:00
|
|
|
_LOG(stream, prefix, "");
|
|
|
|
|
_LOG(stream, prefix, "[%s]%s", group, is_atomic && !stream ? " # atomic section" : "");
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2016-09-28 18:06:19 +02:00
|
|
|
/* Print default values as comments */
|
2016-10-06 23:01:46 +02:00
|
|
|
if (print_default) {
|
|
|
|
|
for (i = 0; i < G_N_ELEMENTS(default_values); i++) {
|
|
|
|
|
if (nm_streq(default_values[i].group, group)
|
|
|
|
|
&& !g_key_file_has_key(priv->keyfile, group, default_values[i].key, NULL)) {
|
|
|
|
|
_LOG(stream,
|
|
|
|
|
prefix,
|
|
|
|
|
"%s# %s=%s",
|
|
|
|
|
key_prefix,
|
|
|
|
|
default_values[i].key,
|
|
|
|
|
default_values[i].value);
|
2016-09-28 18:06:19 +02:00
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-09 09:59:18 +02:00
|
|
|
keys = g_key_file_get_keys(priv->keyfile, group, NULL, NULL);
|
|
|
|
|
for (k = 0; keys && keys[k]; k++) {
|
2021-11-09 13:28:54 +01:00
|
|
|
const char *key = keys[k];
|
2015-06-09 09:59:18 +02:00
|
|
|
gs_free char *value = NULL;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2015-06-09 09:59:18 +02:00
|
|
|
value = g_key_file_get_value(priv->keyfile, group, key, NULL);
|
2015-11-20 17:52:54 +01:00
|
|
|
_LOG(stream, prefix, "%s%s=%s", key_prefix, key, value);
|
2015-06-09 09:59:18 +02:00
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
}
|
|
|
|
|
|
2019-09-26 09:52:23 +02:00
|
|
|
_LOG(stream, prefix, "");
|
|
|
|
|
_LOG(stream, prefix, "# no-auto-default file \"%s\"", no_auto_default_file);
|
|
|
|
|
{
|
|
|
|
|
gs_free char *msg = NULL;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-09-26 09:52:23 +02:00
|
|
|
msg = nm_utils_g_slist_strlist_join(priv->no_auto_default.specs, ",");
|
|
|
|
|
if (msg)
|
|
|
|
|
_LOG(stream, prefix, "# no-auto-default specs \"%s\"", msg);
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-13 17:32:37 +02:00
|
|
|
if (nm_config_kernel_command_line_nm_debug()) {
|
|
|
|
|
_LOG(stream,
|
|
|
|
|
prefix,
|
|
|
|
|
"# /proc/cmdline contains \"" NM_CONFIG_KERNEL_CMDLINE_NM_DEBUG
|
|
|
|
|
"\". Debug log enabled");
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-09 09:59:18 +02:00
|
|
|
#undef _LOG
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-02 18:22:50 +02:00
|
|
|
/*****************************************************************************/
|
2015-06-09 09:59:18 +02:00
|
|
|
|
dns: make [global-dns] to overwrite configs from connections
According to the documentation, settings from [global-dns] (searches and
options) are always merged with those from connections. However this was
not happening if no [global-dns-domain-*] exists, in which case
connections were ignored. This happened because in the past both global
sections must de defined or undefined. When this was changed to allow
defining only [global-dns], allowing it in the function that generates
the resolv.conf file was forgotten. Fix that now.
Anyway, merging these configs doesn't make much sense. The searches and
options defined in connections probably make sense only for the nameservers
defined in that same connection.
Because of this, make the following change: if global nameservers are
defined, use searches and options from [global-dns] only, because those
defined in connections may not make sense for the global nameservers. If
[global-dns] is missing, assume an empty [global-dns] section.
Also, if no global nameservers are defined, but [global-dns] is, make
that it overwrites the searches and options defined in connections. This
is not ideal, but none of the alternatives is better and at least this
is easy to remember.
So, the resulting rules from above are:
- If [global-dns] is defined, it always overwrite searches and options
from connections.
- If [global-dns-domain-*] is defined, it always overwrite nameservers
from connections. It overwrites searches and options too.
Fixes: 1f0d1d78d2a2 ('dns-manager: always apply options from [global-dns]')
Fixes: f57a848da5aa ('man: update documentation about global DNS configuration')
2025-08-25 08:58:21 +02:00
|
|
|
gboolean
|
|
|
|
|
nm_global_dns_has_global_dns_section(const NMGlobalDnsConfig *dns_config)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail(dns_config, FALSE);
|
|
|
|
|
|
2025-09-04 16:48:02 +02:00
|
|
|
return dns_config->searches != NULL || dns_config->options != NULL;
|
dns: make [global-dns] to overwrite configs from connections
According to the documentation, settings from [global-dns] (searches and
options) are always merged with those from connections. However this was
not happening if no [global-dns-domain-*] exists, in which case
connections were ignored. This happened because in the past both global
sections must de defined or undefined. When this was changed to allow
defining only [global-dns], allowing it in the function that generates
the resolv.conf file was forgotten. Fix that now.
Anyway, merging these configs doesn't make much sense. The searches and
options defined in connections probably make sense only for the nameservers
defined in that same connection.
Because of this, make the following change: if global nameservers are
defined, use searches and options from [global-dns] only, because those
defined in connections may not make sense for the global nameservers. If
[global-dns] is missing, assume an empty [global-dns] section.
Also, if no global nameservers are defined, but [global-dns] is, make
that it overwrites the searches and options defined in connections. This
is not ideal, but none of the alternatives is better and at least this
is easy to remember.
So, the resulting rules from above are:
- If [global-dns] is defined, it always overwrite searches and options
from connections.
- If [global-dns-domain-*] is defined, it always overwrite nameservers
from connections. It overwrites searches and options too.
Fixes: 1f0d1d78d2a2 ('dns-manager: always apply options from [global-dns]')
Fixes: f57a848da5aa ('man: update documentation about global DNS configuration')
2025-08-25 08:58:21 +02:00
|
|
|
}
|
|
|
|
|
|
2018-03-26 08:18:51 +02:00
|
|
|
const char *const *
|
2018-03-26 08:17:11 +02:00
|
|
|
nm_global_dns_config_get_searches(const NMGlobalDnsConfig *dns_config)
|
2015-06-15 09:01:42 +02:00
|
|
|
{
|
2018-03-26 08:17:11 +02:00
|
|
|
g_return_val_if_fail(dns_config, NULL);
|
2015-06-15 09:01:42 +02:00
|
|
|
|
2018-03-26 08:18:51 +02:00
|
|
|
return (const char *const *) dns_config->searches;
|
2015-06-15 09:01:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char *const *
|
2018-03-26 08:17:11 +02:00
|
|
|
nm_global_dns_config_get_options(const NMGlobalDnsConfig *dns_config)
|
2015-06-15 09:01:42 +02:00
|
|
|
{
|
2018-03-26 08:17:11 +02:00
|
|
|
g_return_val_if_fail(dns_config, NULL);
|
2015-06-15 09:01:42 +02:00
|
|
|
|
2018-03-26 08:18:51 +02:00
|
|
|
return (const char *const *) dns_config->options;
|
2015-06-15 09:01:42 +02:00
|
|
|
}
|
|
|
|
|
|
2025-01-08 11:21:46 +01:00
|
|
|
const char *
|
|
|
|
|
nm_global_dns_config_get_certification_authority(const NMGlobalDnsConfig *dns_config)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail(dns_config, NULL);
|
|
|
|
|
|
|
|
|
|
return (const char *) dns_config->cert_authority;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
guint
|
|
|
|
|
nm_global_dns_config_get_resolve_mode(const NMGlobalDnsConfig *dns_config)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail(dns_config, 0);
|
|
|
|
|
|
|
|
|
|
return dns_config->resolve_mode;
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-15 09:01:42 +02:00
|
|
|
guint
|
2018-03-26 08:17:11 +02:00
|
|
|
nm_global_dns_config_get_num_domains(const NMGlobalDnsConfig *dns_config)
|
2015-06-15 09:01:42 +02:00
|
|
|
{
|
2018-03-26 08:17:11 +02:00
|
|
|
g_return_val_if_fail(dns_config, 0);
|
2015-06-15 09:01:42 +02:00
|
|
|
|
2018-03-26 08:18:51 +02:00
|
|
|
return dns_config->domains ? g_hash_table_size(dns_config->domains) : 0;
|
2015-06-15 09:01:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NMGlobalDnsDomain *
|
2018-03-26 08:17:11 +02:00
|
|
|
nm_global_dns_config_get_domain(const NMGlobalDnsConfig *dns_config, guint i)
|
2015-06-15 09:01:42 +02:00
|
|
|
{
|
|
|
|
|
NMGlobalDnsDomain *domain;
|
|
|
|
|
|
2018-03-26 08:17:11 +02:00
|
|
|
g_return_val_if_fail(dns_config, NULL);
|
|
|
|
|
g_return_val_if_fail(dns_config->domains, NULL);
|
2018-03-26 08:18:51 +02:00
|
|
|
g_return_val_if_fail(i < g_hash_table_size(dns_config->domains), NULL);
|
|
|
|
|
|
|
|
|
|
nm_assert(NM_PTRARRAY_LEN(dns_config->domain_list) == g_hash_table_size(dns_config->domains));
|
2015-06-15 09:01:42 +02:00
|
|
|
|
2018-03-26 08:17:11 +02:00
|
|
|
domain = g_hash_table_lookup(dns_config->domains, dns_config->domain_list[i]);
|
2015-06-15 09:01:42 +02:00
|
|
|
|
2018-03-26 08:18:51 +02:00
|
|
|
nm_assert(domain);
|
2015-06-15 09:01:42 +02:00
|
|
|
return domain;
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-26 08:17:11 +02:00
|
|
|
NMGlobalDnsDomain *
|
|
|
|
|
nm_global_dns_config_lookup_domain(const NMGlobalDnsConfig *dns_config, const char *name)
|
2015-06-15 09:01:42 +02:00
|
|
|
{
|
2018-03-26 08:17:11 +02:00
|
|
|
g_return_val_if_fail(dns_config, NULL);
|
2015-06-15 09:01:42 +02:00
|
|
|
g_return_val_if_fail(name, NULL);
|
|
|
|
|
|
2018-03-26 08:18:51 +02:00
|
|
|
return dns_config->domains ? g_hash_table_lookup(dns_config->domains, name) : NULL;
|
2015-06-15 09:01:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char *
|
|
|
|
|
nm_global_dns_domain_get_name(const NMGlobalDnsDomain *domain)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail(domain, NULL);
|
|
|
|
|
|
|
|
|
|
return (const char *) domain->name;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char *const *
|
|
|
|
|
nm_global_dns_domain_get_servers(const NMGlobalDnsDomain *domain)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail(domain, NULL);
|
|
|
|
|
|
|
|
|
|
return (const char *const *) domain->servers;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char *const *
|
|
|
|
|
nm_global_dns_domain_get_options(const NMGlobalDnsDomain *domain)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail(domain, NULL);
|
2018-03-26 08:18:51 +02:00
|
|
|
|
2015-06-15 09:01:42 +02:00
|
|
|
return (const char *const *) domain->options;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gboolean
|
2018-03-26 08:17:11 +02:00
|
|
|
nm_global_dns_config_is_internal(const NMGlobalDnsConfig *dns_config)
|
2015-06-15 09:01:42 +02:00
|
|
|
{
|
2018-03-26 08:17:11 +02:00
|
|
|
return dns_config->internal;
|
2015-06-15 09:01:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gboolean
|
2018-03-26 08:17:11 +02:00
|
|
|
nm_global_dns_config_is_empty(const NMGlobalDnsConfig *dns_config)
|
2015-06-15 09:01:42 +02:00
|
|
|
{
|
2018-03-26 08:17:11 +02:00
|
|
|
g_return_val_if_fail(dns_config, TRUE);
|
2015-06-15 09:01:42 +02:00
|
|
|
|
2018-03-26 08:18:51 +02:00
|
|
|
return !dns_config->searches && !dns_config->options && !dns_config->domain_list;
|
2015-06-15 09:01:42 +02:00
|
|
|
}
|
|
|
|
|
|
2021-08-06 15:17:05 +02:00
|
|
|
int
|
|
|
|
|
nm_global_dns_config_cmp(const NMGlobalDnsConfig *a,
|
|
|
|
|
const NMGlobalDnsConfig *b,
|
|
|
|
|
gboolean check_internal)
|
2015-06-15 09:03:53 +02:00
|
|
|
{
|
2021-08-06 15:17:05 +02:00
|
|
|
guint i;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2021-08-06 15:17:05 +02:00
|
|
|
NM_CMP_SELF(a, b);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2021-08-06 15:17:05 +02:00
|
|
|
NM_CMP_RETURN(
|
|
|
|
|
nm_strv_cmp_n(a->searches ?: NM_STRV_EMPTY(), -1, b->searches ?: NM_STRV_EMPTY(), -1));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2021-08-06 15:17:05 +02:00
|
|
|
NM_CMP_RETURN(
|
|
|
|
|
nm_strv_cmp_n(a->options ?: NM_STRV_EMPTY(), -1, b->options ?: NM_STRV_EMPTY(), -1));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2021-08-06 15:17:05 +02:00
|
|
|
NM_CMP_RETURN(nm_strv_cmp_n(a->domain_list ?: NM_STRV_EMPTY_CC(),
|
|
|
|
|
-1,
|
|
|
|
|
b->domain_list ?: NM_STRV_EMPTY_CC(),
|
|
|
|
|
-1));
|
|
|
|
|
|
|
|
|
|
if (a->domain_list) {
|
|
|
|
|
for (i = 0; a->domain_list[i]; i++) {
|
|
|
|
|
const NMGlobalDnsDomain *domain_a;
|
|
|
|
|
const NMGlobalDnsDomain *domain_b;
|
|
|
|
|
|
|
|
|
|
nm_assert(nm_streq(a->domain_list[i], b->domain_list[i]));
|
|
|
|
|
|
|
|
|
|
domain_a = g_hash_table_lookup(a->domains, a->domain_list[i]);
|
|
|
|
|
nm_assert(domain_a);
|
|
|
|
|
|
|
|
|
|
domain_b = g_hash_table_lookup(b->domains, b->domain_list[i]);
|
|
|
|
|
nm_assert(domain_b);
|
|
|
|
|
|
|
|
|
|
NM_CMP_FIELD_STR0(domain_a, domain_b, name);
|
|
|
|
|
|
|
|
|
|
NM_CMP_RETURN(nm_strv_cmp_n(domain_a->servers ?: NM_STRV_EMPTY(),
|
|
|
|
|
-1,
|
|
|
|
|
domain_b->servers ?: NM_STRV_EMPTY(),
|
|
|
|
|
-1));
|
|
|
|
|
|
|
|
|
|
NM_CMP_RETURN(nm_strv_cmp_n(domain_a->options ?: NM_STRV_EMPTY(),
|
|
|
|
|
-1,
|
|
|
|
|
domain_b->options ?: NM_STRV_EMPTY(),
|
|
|
|
|
-1));
|
2018-03-26 08:18:51 +02:00
|
|
|
}
|
2015-06-15 09:03:53 +02:00
|
|
|
}
|
2021-08-06 15:17:05 +02:00
|
|
|
|
|
|
|
|
if (check_internal)
|
|
|
|
|
NM_CMP_FIELD(a, b, internal);
|
|
|
|
|
|
|
|
|
|
return 0;
|
2015-06-15 09:03:53 +02:00
|
|
|
}
|
|
|
|
|
|
2021-11-10 21:13:38 -05:00
|
|
|
void
|
|
|
|
|
nm_global_dns_config_update_checksum(const NMGlobalDnsConfig *dns_config, GChecksum *sum)
|
|
|
|
|
{
|
|
|
|
|
NMGlobalDnsDomain *domain;
|
|
|
|
|
guint i, j;
|
|
|
|
|
guint8 v8;
|
|
|
|
|
|
|
|
|
|
g_return_if_fail(dns_config);
|
|
|
|
|
g_return_if_fail(sum);
|
|
|
|
|
|
|
|
|
|
v8 = NM_HASH_COMBINE_BOOLS(guint8,
|
|
|
|
|
!dns_config->searches,
|
|
|
|
|
!dns_config->options,
|
|
|
|
|
!dns_config->domain_list);
|
|
|
|
|
g_checksum_update(sum, (guchar *) &v8, 1);
|
|
|
|
|
|
|
|
|
|
if (dns_config->searches) {
|
|
|
|
|
for (i = 0; dns_config->searches[i]; i++)
|
|
|
|
|
g_checksum_update(sum,
|
|
|
|
|
(guchar *) dns_config->searches[i],
|
|
|
|
|
strlen(dns_config->searches[i]) + 1);
|
|
|
|
|
}
|
|
|
|
|
if (dns_config->options) {
|
|
|
|
|
for (i = 0; dns_config->options[i]; i++)
|
|
|
|
|
g_checksum_update(sum,
|
|
|
|
|
(guchar *) dns_config->options[i],
|
|
|
|
|
strlen(dns_config->options[i]) + 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (dns_config->domain_list) {
|
|
|
|
|
for (i = 0; dns_config->domain_list[i]; i++) {
|
|
|
|
|
domain = g_hash_table_lookup(dns_config->domains, dns_config->domain_list[i]);
|
|
|
|
|
nm_assert(domain);
|
|
|
|
|
|
|
|
|
|
v8 = NM_HASH_COMBINE_BOOLS(guint8, !domain->servers, !domain->options);
|
|
|
|
|
g_checksum_update(sum, (guchar *) &v8, 1);
|
|
|
|
|
|
|
|
|
|
g_checksum_update(sum, (guchar *) domain->name, strlen(domain->name) + 1);
|
|
|
|
|
|
|
|
|
|
if (domain->servers) {
|
|
|
|
|
for (j = 0; domain->servers[j]; j++)
|
|
|
|
|
g_checksum_update(sum,
|
|
|
|
|
(guchar *) domain->servers[j],
|
|
|
|
|
strlen(domain->servers[j]) + 1);
|
|
|
|
|
}
|
|
|
|
|
if (domain->options) {
|
|
|
|
|
for (j = 0; domain->options[j]; j++)
|
|
|
|
|
g_checksum_update(sum,
|
|
|
|
|
(guchar *) domain->options[j],
|
|
|
|
|
strlen(domain->options[j]) + 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-15 09:01:42 +02:00
|
|
|
static void
|
|
|
|
|
global_dns_domain_free(NMGlobalDnsDomain *domain)
|
|
|
|
|
{
|
|
|
|
|
if (domain) {
|
|
|
|
|
g_free(domain->name);
|
|
|
|
|
g_strfreev(domain->servers);
|
|
|
|
|
g_strfreev(domain->options);
|
|
|
|
|
g_free(domain);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2018-03-26 08:17:11 +02:00
|
|
|
nm_global_dns_config_free(NMGlobalDnsConfig *dns_config)
|
|
|
|
|
{
|
|
|
|
|
if (dns_config) {
|
|
|
|
|
g_strfreev(dns_config->searches);
|
|
|
|
|
g_strfreev(dns_config->options);
|
|
|
|
|
g_free(dns_config->domain_list);
|
2018-03-26 08:18:51 +02:00
|
|
|
if (dns_config->domains)
|
|
|
|
|
g_hash_table_unref(dns_config->domains);
|
2025-01-08 11:21:46 +01:00
|
|
|
if (dns_config->cert_authority) {
|
|
|
|
|
g_free(dns_config->cert_authority);
|
|
|
|
|
}
|
2018-03-26 08:17:11 +02:00
|
|
|
g_free(dns_config);
|
2015-06-15 09:01:42 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NMGlobalDnsConfig *
|
|
|
|
|
nm_config_data_get_global_dns_config(const NMConfigData *self)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail(NM_IS_CONFIG_DATA(self), NULL);
|
|
|
|
|
|
|
|
|
|
return NM_CONFIG_DATA_GET_PRIVATE(self)->global_dns;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2018-03-26 08:18:51 +02:00
|
|
|
global_dns_config_seal_domains(NMGlobalDnsConfig *dns_config)
|
2015-06-15 09:01:42 +02:00
|
|
|
{
|
2018-03-26 08:18:51 +02:00
|
|
|
nm_assert(dns_config);
|
|
|
|
|
nm_assert(dns_config->domains);
|
|
|
|
|
nm_assert(!dns_config->domain_list);
|
2015-06-15 09:01:42 +02:00
|
|
|
|
2018-03-26 08:18:51 +02:00
|
|
|
if (g_hash_table_size(dns_config->domains) == 0)
|
|
|
|
|
nm_clear_pointer(&dns_config->domains, g_hash_table_unref);
|
|
|
|
|
else
|
2021-07-30 09:15:38 +02:00
|
|
|
dns_config->domain_list = nm_strdict_get_keys(dns_config->domains, TRUE, NULL);
|
2015-06-15 09:01:42 +02:00
|
|
|
}
|
|
|
|
|
|
2025-01-08 11:21:46 +01:00
|
|
|
static const char *
|
|
|
|
|
nm_dns_resolve_mode_to_string(const NMDnsResolveMode mode)
|
|
|
|
|
{
|
|
|
|
|
const char *to_string[3] = {"backup", "prefer", "exclusive"};
|
|
|
|
|
|
|
|
|
|
nm_assert(mode < _NM_NUM_DNS_RESOLVE_MODES);
|
|
|
|
|
|
|
|
|
|
return to_string[mode];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static NMDnsResolveMode
|
|
|
|
|
nm_dns_resolve_mode_from_string(const char *string)
|
|
|
|
|
{
|
|
|
|
|
if (nm_streq0(string, "backup")) {
|
|
|
|
|
return NM_DNS_RESOLVE_MODE_BACKUP;
|
|
|
|
|
} else if (nm_streq0(string, "prefer")) {
|
|
|
|
|
return NM_DNS_RESOLVE_MODE_PREFER;
|
|
|
|
|
} else if (nm_streq0(string, "exclusive")) {
|
|
|
|
|
return NM_DNS_RESOLVE_MODE_EXCLUSIVE;
|
|
|
|
|
}
|
|
|
|
|
return _NM_NUM_DNS_RESOLVE_MODES;
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-15 09:01:42 +02:00
|
|
|
static NMGlobalDnsConfig *
|
|
|
|
|
load_global_dns(GKeyFile *keyfile, gboolean internal)
|
|
|
|
|
{
|
2018-03-26 08:17:11 +02:00
|
|
|
NMGlobalDnsConfig *dns_config;
|
2021-11-09 13:28:54 +01:00
|
|
|
char *group, *domain_prefix;
|
2015-06-15 09:01:42 +02:00
|
|
|
gs_strfreev char **groups = NULL;
|
|
|
|
|
int g, i, j, domain_prefix_len;
|
|
|
|
|
gboolean default_found = FALSE;
|
2021-11-09 13:28:54 +01:00
|
|
|
char **strv;
|
2025-01-08 11:21:46 +01:00
|
|
|
gs_free char *cert_authority = NULL;
|
|
|
|
|
gs_free char *resolve_mode = NULL;
|
|
|
|
|
NMDnsResolveMode parsed_resolve_mode;
|
2025-09-04 16:48:02 +02:00
|
|
|
gboolean has_global_dns_section;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2022-09-12 13:47:35 +02:00
|
|
|
if (internal) {
|
|
|
|
|
group = NM_CONFIG_KEYFILE_GROUP_INTERN_GLOBAL_DNS;
|
|
|
|
|
domain_prefix = NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN_GLOBAL_DNS_DOMAIN;
|
|
|
|
|
} else {
|
|
|
|
|
group = NM_CONFIG_KEYFILE_GROUP_GLOBAL_DNS;
|
|
|
|
|
domain_prefix = NM_CONFIG_KEYFILE_GROUPPREFIX_GLOBAL_DNS_DOMAIN;
|
|
|
|
|
}
|
2015-06-15 09:01:42 +02:00
|
|
|
domain_prefix_len = strlen(domain_prefix);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2015-10-01 14:00:01 +02:00
|
|
|
if (!nm_config_keyfile_has_global_dns_config(keyfile, internal))
|
2015-06-15 09:01:42 +02:00
|
|
|
return NULL;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2025-01-08 11:21:46 +01:00
|
|
|
dns_config = g_malloc0(sizeof(NMGlobalDnsConfig));
|
|
|
|
|
|
|
|
|
|
cert_authority = g_key_file_get_string(keyfile,
|
|
|
|
|
group,
|
|
|
|
|
NM_CONFIG_KEYFILE_KEY_GLOBAL_DNS_CERTIFICATION_AUTHORITY,
|
|
|
|
|
NULL);
|
|
|
|
|
if (cert_authority) {
|
|
|
|
|
dns_config->cert_authority = g_steal_pointer(&cert_authority);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
resolve_mode =
|
|
|
|
|
g_key_file_get_string(keyfile, group, NM_CONFIG_KEYFILE_KEY_GLOBAL_DNS_RESOLVE_MODE, NULL);
|
|
|
|
|
|
|
|
|
|
if (resolve_mode) {
|
|
|
|
|
parsed_resolve_mode = nm_dns_resolve_mode_from_string(resolve_mode);
|
|
|
|
|
if (parsed_resolve_mode == _NM_NUM_DNS_RESOLVE_MODES) {
|
|
|
|
|
nm_log_dbg(LOGD_CORE,
|
|
|
|
|
"%s global DNS configuration has invalid value '%s', assuming backup",
|
|
|
|
|
internal ? "internal" : "user",
|
|
|
|
|
NM_CONFIG_KEYFILE_KEY_GLOBAL_DNS_RESOLVE_MODE);
|
|
|
|
|
} else {
|
|
|
|
|
dns_config->resolve_mode = parsed_resolve_mode;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-26 08:17:11 +02:00
|
|
|
dns_config->domains = g_hash_table_new_full(nm_str_hash,
|
|
|
|
|
g_str_equal,
|
|
|
|
|
g_free,
|
|
|
|
|
(GDestroyNotify) global_dns_domain_free);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-11-09 18:05:04 +01:00
|
|
|
strv = g_key_file_get_string_list(keyfile,
|
|
|
|
|
group,
|
|
|
|
|
NM_CONFIG_KEYFILE_KEY_GLOBAL_DNS_SEARCHES,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL);
|
2018-03-26 08:18:51 +02:00
|
|
|
if (strv) {
|
2021-07-29 10:02:11 +02:00
|
|
|
nm_strv_cleanup(strv, TRUE, TRUE, TRUE);
|
2018-03-26 08:18:51 +02:00
|
|
|
if (!strv[0])
|
|
|
|
|
g_free(strv);
|
|
|
|
|
else
|
|
|
|
|
dns_config->searches = strv;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-11-09 18:05:04 +01:00
|
|
|
strv = g_key_file_get_string_list(keyfile,
|
|
|
|
|
group,
|
|
|
|
|
NM_CONFIG_KEYFILE_KEY_GLOBAL_DNS_OPTIONS,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL);
|
2015-06-15 09:01:42 +02:00
|
|
|
if (strv) {
|
2021-07-29 10:02:11 +02:00
|
|
|
nm_strv_cleanup(strv, TRUE, TRUE, TRUE);
|
2015-06-15 09:01:42 +02:00
|
|
|
for (i = 0, j = 0; strv[i]; i++) {
|
2023-11-15 19:53:44 +01:00
|
|
|
if (_nm_utils_dns_option_validate(strv[i], NULL, NULL, AF_UNSPEC, NULL))
|
2015-06-15 09:01:42 +02:00
|
|
|
strv[j++] = strv[i];
|
|
|
|
|
else
|
|
|
|
|
g_free(strv[i]);
|
|
|
|
|
}
|
2018-03-26 08:18:51 +02:00
|
|
|
if (j == 0)
|
|
|
|
|
g_free(strv);
|
|
|
|
|
else {
|
|
|
|
|
strv[j] = NULL;
|
|
|
|
|
dns_config->options = strv;
|
|
|
|
|
}
|
2015-06-15 09:01:42 +02:00
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2015-06-15 09:01:42 +02:00
|
|
|
groups = g_key_file_get_groups(keyfile, NULL);
|
|
|
|
|
for (g = 0; groups[g]; g++) {
|
2021-11-09 13:28:54 +01:00
|
|
|
char *name;
|
|
|
|
|
char **servers = NULL, **options = NULL;
|
2015-06-15 09:01:42 +02:00
|
|
|
NMGlobalDnsDomain *domain;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2015-06-15 09:01:42 +02:00
|
|
|
if (!g_str_has_prefix(groups[g], domain_prefix) || !groups[g][domain_prefix_len])
|
|
|
|
|
continue;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-11-09 18:05:04 +01:00
|
|
|
strv = g_key_file_get_string_list(keyfile,
|
|
|
|
|
groups[g],
|
|
|
|
|
NM_CONFIG_KEYFILE_KEY_GLOBAL_DNS_DOMAIN_SERVERS,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL);
|
2015-06-15 09:01:42 +02:00
|
|
|
if (strv) {
|
2021-07-29 10:02:11 +02:00
|
|
|
nm_strv_cleanup(strv, TRUE, TRUE, TRUE);
|
2015-06-15 09:01:42 +02:00
|
|
|
for (i = 0, j = 0; strv[i]; i++) {
|
2024-12-05 09:59:06 +01:00
|
|
|
gs_free char *to_free = NULL;
|
|
|
|
|
|
|
|
|
|
if (nm_dns_uri_normalize(AF_UNSPEC, strv[i], &to_free)) {
|
|
|
|
|
if (to_free) {
|
|
|
|
|
g_free(strv[i]);
|
|
|
|
|
strv[j++] = g_steal_pointer(&to_free);
|
|
|
|
|
} else {
|
|
|
|
|
strv[j++] = strv[i];
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
nm_log_dbg(LOGD_CORE, "invalid global name server \"%s\"", strv[i]);
|
2015-06-15 09:01:42 +02:00
|
|
|
g_free(strv[i]);
|
2024-12-05 09:59:06 +01:00
|
|
|
}
|
2015-06-15 09:01:42 +02:00
|
|
|
}
|
2018-03-26 08:18:51 +02:00
|
|
|
if (j == 0)
|
|
|
|
|
g_free(strv);
|
|
|
|
|
else {
|
2015-06-15 09:01:42 +02:00
|
|
|
strv[j] = NULL;
|
|
|
|
|
servers = strv;
|
2020-09-28 16:03:33 +02:00
|
|
|
}
|
2015-06-15 09:01:42 +02:00
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2015-06-15 09:01:42 +02:00
|
|
|
if (!servers)
|
|
|
|
|
continue;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-11-09 18:05:04 +01:00
|
|
|
strv = g_key_file_get_string_list(keyfile,
|
|
|
|
|
groups[g],
|
|
|
|
|
NM_CONFIG_KEYFILE_KEY_GLOBAL_DNS_DOMAIN_OPTIONS,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL);
|
2018-03-26 08:18:51 +02:00
|
|
|
if (strv) {
|
2021-07-29 10:02:11 +02:00
|
|
|
options = nm_strv_cleanup(strv, TRUE, TRUE, TRUE);
|
2018-03-26 08:18:51 +02:00
|
|
|
if (!options[0])
|
|
|
|
|
nm_clear_g_free(&options);
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2015-06-15 09:01:42 +02:00
|
|
|
name = strdup(&groups[g][domain_prefix_len]);
|
|
|
|
|
domain = g_malloc0(sizeof(NMGlobalDnsDomain));
|
|
|
|
|
domain->name = name;
|
|
|
|
|
domain->servers = servers;
|
|
|
|
|
domain->options = options;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-03-26 08:17:11 +02:00
|
|
|
g_hash_table_insert(dns_config->domains, strdup(name), domain);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2021-03-22 09:37:43 +01:00
|
|
|
if (name[0] == '*' && name[1] == '\0')
|
2015-06-15 09:01:42 +02:00
|
|
|
default_found = TRUE;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2022-09-12 13:21:51 +02:00
|
|
|
if (!default_found && g_hash_table_size(dns_config->domains)) {
|
2015-06-15 09:01:42 +02:00
|
|
|
nm_log_dbg(LOGD_CORE,
|
|
|
|
|
"%s global DNS configuration is missing default domain, ignore it",
|
|
|
|
|
internal ? "internal" : "user");
|
2018-03-26 08:17:11 +02:00
|
|
|
nm_global_dns_config_free(dns_config);
|
2015-06-15 09:01:42 +02:00
|
|
|
return NULL;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
dns: make [global-dns] to overwrite configs from connections
According to the documentation, settings from [global-dns] (searches and
options) are always merged with those from connections. However this was
not happening if no [global-dns-domain-*] exists, in which case
connections were ignored. This happened because in the past both global
sections must de defined or undefined. When this was changed to allow
defining only [global-dns], allowing it in the function that generates
the resolv.conf file was forgotten. Fix that now.
Anyway, merging these configs doesn't make much sense. The searches and
options defined in connections probably make sense only for the nameservers
defined in that same connection.
Because of this, make the following change: if global nameservers are
defined, use searches and options from [global-dns] only, because those
defined in connections may not make sense for the global nameservers. If
[global-dns] is missing, assume an empty [global-dns] section.
Also, if no global nameservers are defined, but [global-dns] is, make
that it overwrites the searches and options defined in connections. This
is not ideal, but none of the alternatives is better and at least this
is easy to remember.
So, the resulting rules from above are:
- If [global-dns] is defined, it always overwrite searches and options
from connections.
- If [global-dns-domain-*] is defined, it always overwrite nameservers
from connections. It overwrites searches and options too.
Fixes: 1f0d1d78d2a2 ('dns-manager: always apply options from [global-dns]')
Fixes: f57a848da5aa ('man: update documentation about global DNS configuration')
2025-08-25 08:58:21 +02:00
|
|
|
/* Defining [global-dns-domain-*] implies defining [global-dns] too (maybe empty) */
|
|
|
|
|
if (default_found)
|
2025-09-04 16:48:02 +02:00
|
|
|
has_global_dns_section = TRUE;
|
dns: make [global-dns] to overwrite configs from connections
According to the documentation, settings from [global-dns] (searches and
options) are always merged with those from connections. However this was
not happening if no [global-dns-domain-*] exists, in which case
connections were ignored. This happened because in the past both global
sections must de defined or undefined. When this was changed to allow
defining only [global-dns], allowing it in the function that generates
the resolv.conf file was forgotten. Fix that now.
Anyway, merging these configs doesn't make much sense. The searches and
options defined in connections probably make sense only for the nameservers
defined in that same connection.
Because of this, make the following change: if global nameservers are
defined, use searches and options from [global-dns] only, because those
defined in connections may not make sense for the global nameservers. If
[global-dns] is missing, assume an empty [global-dns] section.
Also, if no global nameservers are defined, but [global-dns] is, make
that it overwrites the searches and options defined in connections. This
is not ideal, but none of the alternatives is better and at least this
is easy to remember.
So, the resulting rules from above are:
- If [global-dns] is defined, it always overwrite searches and options
from connections.
- If [global-dns-domain-*] is defined, it always overwrite nameservers
from connections. It overwrites searches and options too.
Fixes: 1f0d1d78d2a2 ('dns-manager: always apply options from [global-dns]')
Fixes: f57a848da5aa ('man: update documentation about global DNS configuration')
2025-08-25 08:58:21 +02:00
|
|
|
else
|
2025-09-04 16:48:02 +02:00
|
|
|
has_global_dns_section = g_key_file_has_group(keyfile, group);
|
|
|
|
|
|
|
|
|
|
/* If there exist a [global-dns] section, always initialize "searches" and "options" so
|
|
|
|
|
* they appear in D-Bus. Clients can use this to know if it's defined, so they can know
|
|
|
|
|
* if DNS configs from connections are relevant or not. */
|
|
|
|
|
if (has_global_dns_section) {
|
|
|
|
|
if (!dns_config->searches)
|
|
|
|
|
dns_config->searches = nm_strv_empty_new();
|
|
|
|
|
if (!dns_config->options)
|
|
|
|
|
dns_config->options = nm_strv_empty_new();
|
|
|
|
|
}
|
dns: make [global-dns] to overwrite configs from connections
According to the documentation, settings from [global-dns] (searches and
options) are always merged with those from connections. However this was
not happening if no [global-dns-domain-*] exists, in which case
connections were ignored. This happened because in the past both global
sections must de defined or undefined. When this was changed to allow
defining only [global-dns], allowing it in the function that generates
the resolv.conf file was forgotten. Fix that now.
Anyway, merging these configs doesn't make much sense. The searches and
options defined in connections probably make sense only for the nameservers
defined in that same connection.
Because of this, make the following change: if global nameservers are
defined, use searches and options from [global-dns] only, because those
defined in connections may not make sense for the global nameservers. If
[global-dns] is missing, assume an empty [global-dns] section.
Also, if no global nameservers are defined, but [global-dns] is, make
that it overwrites the searches and options defined in connections. This
is not ideal, but none of the alternatives is better and at least this
is easy to remember.
So, the resulting rules from above are:
- If [global-dns] is defined, it always overwrite searches and options
from connections.
- If [global-dns-domain-*] is defined, it always overwrite nameservers
from connections. It overwrites searches and options too.
Fixes: 1f0d1d78d2a2 ('dns-manager: always apply options from [global-dns]')
Fixes: f57a848da5aa ('man: update documentation about global DNS configuration')
2025-08-25 08:58:21 +02:00
|
|
|
|
2018-03-26 08:17:11 +02:00
|
|
|
dns_config->internal = internal;
|
2018-03-26 08:18:51 +02:00
|
|
|
global_dns_config_seal_domains(dns_config);
|
2018-03-26 08:17:11 +02:00
|
|
|
return dns_config;
|
2015-06-15 09:01:42 +02:00
|
|
|
}
|
|
|
|
|
|
2015-07-03 11:06:39 +02:00
|
|
|
void
|
2018-03-26 08:17:11 +02:00
|
|
|
nm_global_dns_config_to_dbus(const NMGlobalDnsConfig *dns_config, GValue *value)
|
2015-07-03 11:06:39 +02:00
|
|
|
{
|
|
|
|
|
GVariantBuilder conf_builder, domains_builder, domain_builder;
|
2018-03-26 08:18:51 +02:00
|
|
|
guint i;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2015-07-03 11:06:39 +02:00
|
|
|
g_variant_builder_init(&conf_builder, G_VARIANT_TYPE("a{sv}"));
|
2018-03-26 08:17:11 +02:00
|
|
|
if (!dns_config)
|
2015-07-03 11:06:39 +02:00
|
|
|
goto out;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-03-26 08:17:11 +02:00
|
|
|
if (dns_config->searches) {
|
2015-07-03 11:06:39 +02:00
|
|
|
g_variant_builder_add(&conf_builder,
|
|
|
|
|
"{sv}",
|
|
|
|
|
"searches",
|
2018-03-26 08:17:11 +02:00
|
|
|
g_variant_new_strv((const char *const *) dns_config->searches, -1));
|
2015-07-03 11:06:39 +02:00
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-03-26 08:17:11 +02:00
|
|
|
if (dns_config->options) {
|
2015-07-03 11:06:39 +02:00
|
|
|
g_variant_builder_add(&conf_builder,
|
|
|
|
|
"{sv}",
|
|
|
|
|
"options",
|
2018-03-26 08:17:11 +02:00
|
|
|
g_variant_new_strv((const char *const *) dns_config->options, -1));
|
2015-07-03 11:06:39 +02:00
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2025-01-08 11:21:46 +01:00
|
|
|
if (dns_config->cert_authority) {
|
|
|
|
|
g_variant_builder_add(&conf_builder,
|
|
|
|
|
"{sv}",
|
|
|
|
|
"certification-authority",
|
|
|
|
|
g_variant_new("s", dns_config->cert_authority));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (dns_config->resolve_mode) {
|
|
|
|
|
g_variant_builder_add(
|
|
|
|
|
&conf_builder,
|
|
|
|
|
"{sv}",
|
|
|
|
|
"resolve-mode",
|
|
|
|
|
g_variant_new("s", nm_dns_resolve_mode_to_string(dns_config->resolve_mode)));
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-03 11:06:39 +02:00
|
|
|
g_variant_builder_init(&domains_builder, G_VARIANT_TYPE("a{sv}"));
|
2018-03-26 08:18:51 +02:00
|
|
|
if (dns_config->domain_list) {
|
|
|
|
|
for (i = 0; dns_config->domain_list[i]; i++) {
|
|
|
|
|
NMGlobalDnsDomain *domain;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-03-26 08:18:51 +02:00
|
|
|
domain = g_hash_table_lookup(dns_config->domains, dns_config->domain_list[i]);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-03-26 08:18:51 +02:00
|
|
|
g_variant_builder_init(&domain_builder, G_VARIANT_TYPE("a{sv}"));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-03-26 08:18:51 +02:00
|
|
|
if (domain->servers) {
|
|
|
|
|
g_variant_builder_add(
|
|
|
|
|
&domain_builder,
|
|
|
|
|
"{sv}",
|
|
|
|
|
"servers",
|
|
|
|
|
g_variant_new_strv((const char *const *) domain->servers, -1));
|
|
|
|
|
}
|
|
|
|
|
if (domain->options) {
|
|
|
|
|
g_variant_builder_add(
|
|
|
|
|
&domain_builder,
|
|
|
|
|
"{sv}",
|
|
|
|
|
"options",
|
|
|
|
|
g_variant_new_strv((const char *const *) domain->options, -1));
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-03-26 08:18:51 +02:00
|
|
|
g_variant_builder_add(&domains_builder,
|
|
|
|
|
"{sv}",
|
|
|
|
|
domain->name,
|
|
|
|
|
g_variant_builder_end(&domain_builder));
|
2020-09-28 16:03:33 +02:00
|
|
|
}
|
2018-03-26 08:18:51 +02:00
|
|
|
}
|
2015-07-03 11:06:39 +02:00
|
|
|
g_variant_builder_add(&conf_builder,
|
|
|
|
|
"{sv}",
|
|
|
|
|
"domains",
|
|
|
|
|
g_variant_builder_end(&domains_builder));
|
2018-03-26 08:18:51 +02:00
|
|
|
|
2015-07-03 11:06:39 +02:00
|
|
|
out:
|
|
|
|
|
g_value_take_variant(value, g_variant_builder_end(&conf_builder));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static NMGlobalDnsDomain *
|
|
|
|
|
global_dns_domain_from_dbus(char *name, GVariant *variant)
|
|
|
|
|
{
|
|
|
|
|
NMGlobalDnsDomain *domain;
|
|
|
|
|
GVariantIter iter;
|
2021-11-09 13:28:54 +01:00
|
|
|
char **strv, *key;
|
|
|
|
|
GVariant *val;
|
2015-07-03 11:06:39 +02:00
|
|
|
int i, j;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2015-07-03 11:06:39 +02:00
|
|
|
if (!g_variant_is_of_type(variant, G_VARIANT_TYPE("a{sv}")))
|
|
|
|
|
return NULL;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2015-07-03 11:06:39 +02:00
|
|
|
domain = g_malloc0(sizeof(NMGlobalDnsDomain));
|
|
|
|
|
domain->name = g_strdup(name);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2015-07-03 11:06:39 +02:00
|
|
|
g_variant_iter_init(&iter, variant);
|
|
|
|
|
while (g_variant_iter_next(&iter, "{&sv}", &key, &val)) {
|
2021-03-22 09:37:43 +01:00
|
|
|
if (nm_streq0(key, "servers") && g_variant_is_of_type(val, G_VARIANT_TYPE("as"))) {
|
2015-07-03 11:06:39 +02:00
|
|
|
strv = g_variant_dup_strv(val, NULL);
|
2021-07-29 10:02:11 +02:00
|
|
|
nm_strv_cleanup(strv, TRUE, TRUE, TRUE);
|
2015-07-03 11:06:39 +02:00
|
|
|
for (i = 0, j = 0; strv && strv[i]; i++) {
|
glib-aux: rename IP address related helpers from "nm-inet-utils.h"
- name things related to `in_addr_t`, `struct in6_addr`, `NMIPAddr` as
`nm_ip4_addr_*()`, `nm_ip6_addr_*()`, `nm_ip_addr_*()`, respectively.
- we have a wrapper `nm_inet_ntop()` for `inet_ntop()`. This name
of our wrapper is chosen to be familiar with the libc underlying
function. With this, also name functions that are about string
representations of addresses `nm_inet_*()`, `nm_inet4_*()`,
`nm_inet6_*()`. For example, `nm_inet_parse_str()`,
`nm_inet_is_normalized()`.
<<<<
R() {
git grep -l "$1" | xargs sed -i "s/\<$1\>/$2/g"
}
R NM_CMP_DIRECT_IN4ADDR_SAME_PREFIX NM_CMP_DIRECT_IP4_ADDR_SAME_PREFIX
R NM_CMP_DIRECT_IN6ADDR_SAME_PREFIX NM_CMP_DIRECT_IP6_ADDR_SAME_PREFIX
R NM_UTILS_INET_ADDRSTRLEN NM_INET_ADDRSTRLEN
R _nm_utils_inet4_ntop nm_inet4_ntop
R _nm_utils_inet6_ntop nm_inet6_ntop
R _nm_utils_ip4_get_default_prefix nm_ip4_addr_get_default_prefix
R _nm_utils_ip4_get_default_prefix0 nm_ip4_addr_get_default_prefix0
R _nm_utils_ip4_netmask_to_prefix nm_ip4_addr_netmask_to_prefix
R _nm_utils_ip4_prefix_to_netmask nm_ip4_addr_netmask_from_prefix
R nm_utils_inet4_ntop_dup nm_inet4_ntop_dup
R nm_utils_inet6_ntop_dup nm_inet6_ntop_dup
R nm_utils_inet_ntop nm_inet_ntop
R nm_utils_inet_ntop_dup nm_inet_ntop_dup
R nm_utils_ip4_address_clear_host_address nm_ip4_addr_clear_host_address
R nm_utils_ip4_address_is_link_local nm_ip4_addr_is_link_local
R nm_utils_ip4_address_is_loopback nm_ip4_addr_is_loopback
R nm_utils_ip4_address_is_zeronet nm_ip4_addr_is_zeronet
R nm_utils_ip4_address_same_prefix nm_ip4_addr_same_prefix
R nm_utils_ip4_address_same_prefix_cmp nm_ip4_addr_same_prefix_cmp
R nm_utils_ip6_address_clear_host_address nm_ip6_addr_clear_host_address
R nm_utils_ip6_address_same_prefix nm_ip6_addr_same_prefix
R nm_utils_ip6_address_same_prefix_cmp nm_ip6_addr_same_prefix_cmp
R nm_utils_ip6_is_ula nm_ip6_addr_is_ula
R nm_utils_ip_address_same_prefix nm_ip_addr_same_prefix
R nm_utils_ip_address_same_prefix_cmp nm_ip_addr_same_prefix_cmp
R nm_utils_ip_is_site_local nm_ip_addr_is_site_local
R nm_utils_ipaddr_is_normalized nm_inet_is_normalized
R nm_utils_ipaddr_is_valid nm_inet_is_valid
R nm_utils_ipx_address_clear_host_address nm_ip_addr_clear_host_address
R nm_utils_parse_inaddr nm_inet_parse_str
R nm_utils_parse_inaddr_bin nm_inet_parse_bin
R nm_utils_parse_inaddr_bin_full nm_inet_parse_bin_full
R nm_utils_parse_inaddr_prefix nm_inet_parse_with_prefix_str
R nm_utils_parse_inaddr_prefix_bin nm_inet_parse_with_prefix_bin
R test_nm_utils_ip6_address_same_prefix test_nm_ip_addr_same_prefix
./contrib/scripts/nm-code-format.sh -F
2022-08-19 13:15:20 +02:00
|
|
|
if (nm_inet_is_valid(AF_INET, strv[i]) || nm_inet_is_valid(AF_INET6, strv[i]))
|
2015-07-03 11:06:39 +02:00
|
|
|
strv[j++] = strv[i];
|
|
|
|
|
else
|
|
|
|
|
g_free(strv[i]);
|
|
|
|
|
}
|
2018-03-26 08:18:51 +02:00
|
|
|
if (j == 0)
|
|
|
|
|
g_free(strv);
|
|
|
|
|
else {
|
2015-07-03 11:06:39 +02:00
|
|
|
strv[j] = NULL;
|
2018-03-26 08:18:51 +02:00
|
|
|
g_strfreev(domain->servers);
|
2015-07-03 11:06:39 +02:00
|
|
|
domain->servers = strv;
|
2018-03-26 08:18:51 +02:00
|
|
|
}
|
2021-03-22 09:37:43 +01:00
|
|
|
} else if (nm_streq0(key, "options") && g_variant_is_of_type(val, G_VARIANT_TYPE("as"))) {
|
2015-07-03 11:06:39 +02:00
|
|
|
strv = g_variant_dup_strv(val, NULL);
|
2018-03-26 08:18:51 +02:00
|
|
|
g_strfreev(domain->options);
|
2021-07-29 10:02:11 +02:00
|
|
|
domain->options = nm_strv_cleanup(strv, TRUE, TRUE, TRUE);
|
2018-03-26 08:18:51 +02:00
|
|
|
if (!domain->options[0])
|
|
|
|
|
nm_clear_g_free(&domain->options);
|
2015-07-03 11:06:39 +02:00
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2015-07-03 11:06:39 +02:00
|
|
|
g_variant_unref(val);
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2015-07-03 11:06:39 +02:00
|
|
|
/* At least one server is required */
|
|
|
|
|
if (!domain->servers) {
|
|
|
|
|
global_dns_domain_free(domain);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2015-07-03 11:06:39 +02:00
|
|
|
return domain;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NMGlobalDnsConfig *
|
|
|
|
|
nm_global_dns_config_from_dbus(const GValue *value, GError **error)
|
|
|
|
|
{
|
|
|
|
|
NMGlobalDnsConfig *dns_config;
|
2021-11-09 13:28:54 +01:00
|
|
|
GVariant *variant, *val;
|
2015-07-03 11:06:39 +02:00
|
|
|
GVariantIter iter;
|
2021-11-09 13:28:54 +01:00
|
|
|
char **strv, *key;
|
2015-07-03 11:06:39 +02:00
|
|
|
int i, j;
|
2025-01-08 11:21:46 +01:00
|
|
|
gs_free char *resolve_mode_buffer = NULL;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2015-07-03 11:06:39 +02:00
|
|
|
if (!G_VALUE_HOLDS_VARIANT(value)) {
|
|
|
|
|
g_set_error(error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED, "invalid value type");
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2015-07-03 11:06:39 +02:00
|
|
|
variant = g_value_get_variant(value);
|
|
|
|
|
if (!g_variant_is_of_type(variant, G_VARIANT_TYPE("a{sv}"))) {
|
|
|
|
|
g_set_error(error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED, "invalid variant type");
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2015-07-03 11:06:39 +02:00
|
|
|
dns_config = g_malloc0(sizeof(NMGlobalDnsConfig));
|
2017-10-13 16:12:35 +02:00
|
|
|
dns_config->domains = g_hash_table_new_full(nm_str_hash,
|
|
|
|
|
g_str_equal,
|
2015-07-03 11:06:39 +02:00
|
|
|
g_free,
|
|
|
|
|
(GDestroyNotify) global_dns_domain_free);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2015-07-03 11:06:39 +02:00
|
|
|
g_variant_iter_init(&iter, variant);
|
|
|
|
|
while (g_variant_iter_next(&iter, "{&sv}", &key, &val)) {
|
2021-03-22 09:37:43 +01:00
|
|
|
if (nm_streq0(key, "searches") && g_variant_is_of_type(val, G_VARIANT_TYPE("as"))) {
|
2015-07-03 11:06:39 +02:00
|
|
|
strv = g_variant_dup_strv(val, NULL);
|
2021-07-29 10:02:11 +02:00
|
|
|
dns_config->searches = nm_strv_cleanup(strv, TRUE, TRUE, TRUE);
|
2021-03-22 09:37:43 +01:00
|
|
|
} else if (nm_streq0(key, "options") && g_variant_is_of_type(val, G_VARIANT_TYPE("as"))) {
|
2015-07-03 11:06:39 +02:00
|
|
|
strv = g_variant_dup_strv(val, NULL);
|
2021-07-29 10:02:11 +02:00
|
|
|
nm_strv_cleanup(strv, TRUE, TRUE, TRUE);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2015-07-03 11:06:39 +02:00
|
|
|
for (i = 0, j = 0; strv && strv[i]; i++) {
|
2023-11-15 19:53:44 +01:00
|
|
|
if (_nm_utils_dns_option_validate(strv[i], NULL, NULL, AF_UNSPEC, NULL))
|
2015-07-03 11:06:39 +02:00
|
|
|
strv[j++] = strv[i];
|
|
|
|
|
else
|
|
|
|
|
g_free(strv[i]);
|
|
|
|
|
}
|
2018-03-26 08:18:51 +02:00
|
|
|
if (j == 0)
|
|
|
|
|
g_free(strv);
|
|
|
|
|
else {
|
2015-07-03 11:06:39 +02:00
|
|
|
strv[j] = NULL;
|
2018-03-26 08:18:51 +02:00
|
|
|
dns_config->options = strv;
|
|
|
|
|
}
|
2021-03-22 09:37:43 +01:00
|
|
|
} else if (nm_streq0(key, "domains")
|
2015-07-03 11:06:39 +02:00
|
|
|
&& g_variant_is_of_type(val, G_VARIANT_TYPE("a{sv}"))) {
|
|
|
|
|
NMGlobalDnsDomain *domain;
|
|
|
|
|
GVariantIter domain_iter;
|
2021-11-09 13:28:54 +01:00
|
|
|
GVariant *v;
|
|
|
|
|
char *k;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2015-07-03 11:06:39 +02:00
|
|
|
g_variant_iter_init(&domain_iter, val);
|
|
|
|
|
while (g_variant_iter_next(&domain_iter, "{&sv}", &k, &v)) {
|
|
|
|
|
if (k) {
|
|
|
|
|
domain = global_dns_domain_from_dbus(k, v);
|
|
|
|
|
if (domain)
|
|
|
|
|
g_hash_table_insert(dns_config->domains, strdup(k), domain);
|
|
|
|
|
}
|
|
|
|
|
g_variant_unref(v);
|
2020-09-28 16:03:33 +02:00
|
|
|
}
|
2025-01-08 11:21:46 +01:00
|
|
|
} else if (nm_streq0(key, "resolve-mode")
|
|
|
|
|
&& g_variant_is_of_type(val, G_VARIANT_TYPE("s"))) {
|
|
|
|
|
g_variant_get(val, "s", &resolve_mode_buffer);
|
|
|
|
|
dns_config->resolve_mode = nm_dns_resolve_mode_from_string(resolve_mode_buffer);
|
|
|
|
|
if (dns_config->resolve_mode == _NM_NUM_DNS_RESOLVE_MODES) {
|
|
|
|
|
g_set_error_literal(error,
|
|
|
|
|
NM_MANAGER_ERROR,
|
|
|
|
|
NM_MANAGER_ERROR_FAILED,
|
|
|
|
|
"Global DNS configuration contains invalid resolve-mode");
|
|
|
|
|
nm_global_dns_config_free(dns_config);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
} else if (nm_streq0(key, "certification-authority")
|
|
|
|
|
&& g_variant_is_of_type(val, G_VARIANT_TYPE("s"))) {
|
|
|
|
|
g_variant_get(val, "s", &dns_config->cert_authority);
|
2015-07-03 11:06:39 +02:00
|
|
|
}
|
2025-01-08 11:21:46 +01:00
|
|
|
|
2015-07-03 11:06:39 +02:00
|
|
|
g_variant_unref(val);
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-03-26 08:18:51 +02:00
|
|
|
global_dns_config_seal_domains(dns_config);
|
2015-07-03 11:06:39 +02:00
|
|
|
return dns_config;
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-15 09:01:42 +02:00
|
|
|
static gboolean
|
|
|
|
|
global_dns_equal(NMGlobalDnsConfig *old, NMGlobalDnsConfig *new)
|
|
|
|
|
{
|
|
|
|
|
NMGlobalDnsDomain *domain_old, *domain_new;
|
|
|
|
|
gpointer key, value_old, value_new;
|
|
|
|
|
GHashTableIter iter;
|
|
|
|
|
|
|
|
|
|
if (old == new)
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
|
|
if (!old || !new)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
2021-07-29 10:02:11 +02:00
|
|
|
if (!nm_strv_equal(old->options, new->options) || !nm_strv_equal(old->searches, new->searches))
|
2015-06-15 09:01:42 +02:00
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
if ((!old->domains || !new->domains) && old->domains != new->domains)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
core: fix crash when reloading global dns configuration
When reloading the configuration and there is a global DNS
configuration without domains, NM crashes in global_dns_equal()
because `old->domains` and `new->domains` are both NULL. Fix that.
Thread 1 "NetworkManager" received signal SIGTRAP, Trace/breakpoint trap.
0 g_logv (log_domain=0x7fe81a2110be "GLib", log_level=G_LOG_LEVEL_CRITICAL, format=<optimized out>, args=<optimized out>) at ../glib/gmessages.c:1433
1 g_log (log_domain=<optimized out>, log_level=<optimized out>, format=<optimized out>) at ../glib/gmessages.c:1471
2 g_hash_table_size (hash_table=<optimized out>) at ../glib/ghash.c:2183
3 g_hash_table_size (hash_table=<optimized out>) at ../glib/ghash.c:2181
4 global_dns_equal (new=0xecc540, old=0xe618e0) at ../src/core/nm-config-data.c:1466
5 nm_config_data_diff (old_data=old_data@entry=0xe60020, new_data=new_data@entry=0xe606a0) at ../src/core/nm-config-data.c:1946
6 _set_config_data (self=0xe45810, new_data=0xe606a0, reload_flags=NM_CONFIG_CHANGE_CAUSE_SIGHUP) at ../src/core/nm-config.c:2923
7 nm_config_reload (self=0xe45810, reload_flags=NM_CONFIG_CHANGE_CAUSE_SIGHUP, emit_warnings=emit_warnings@entry=1) at ../src/core/nm-config.c:2875
8 nm_main_config_reload (signal=<optimized out>) at ../src/core/main.c:141
9 sighup_handler (user_data=<optimized out>) at ../src/core/main-utils.c:26
10 g_main_dispatch (context=0xe619e0) at ../glib/gmain.c:3444
11 g_main_context_dispatch (context=0xe619e0) at ../glib/gmain.c:4162
12 g_main_context_iterate.constprop.0 (context=0xe619e0, block=1, dispatch=1, self=<optimized out>) at ../glib/gmain.c:4238
13 g_main_loop_run (loop=0xe5e310) at ../glib/gmain.c:4438
14 main (argc=<optimized out>, argv=<optimized out>) at ../src/core/main.c:515
Fixes: 1f0d1d78d2a2 ('dns-manager: always apply options from [global-dns]')
2023-03-06 11:58:28 +01:00
|
|
|
if (nm_g_hash_table_size(old->domains) != nm_g_hash_table_size(new->domains))
|
2015-06-15 09:01:42 +02:00
|
|
|
return FALSE;
|
|
|
|
|
|
core: fix crash when reloading global dns configuration
When reloading the configuration and there is a global DNS
configuration without domains, NM crashes in global_dns_equal()
because `old->domains` and `new->domains` are both NULL. Fix that.
Thread 1 "NetworkManager" received signal SIGTRAP, Trace/breakpoint trap.
0 g_logv (log_domain=0x7fe81a2110be "GLib", log_level=G_LOG_LEVEL_CRITICAL, format=<optimized out>, args=<optimized out>) at ../glib/gmessages.c:1433
1 g_log (log_domain=<optimized out>, log_level=<optimized out>, format=<optimized out>) at ../glib/gmessages.c:1471
2 g_hash_table_size (hash_table=<optimized out>) at ../glib/ghash.c:2183
3 g_hash_table_size (hash_table=<optimized out>) at ../glib/ghash.c:2181
4 global_dns_equal (new=0xecc540, old=0xe618e0) at ../src/core/nm-config-data.c:1466
5 nm_config_data_diff (old_data=old_data@entry=0xe60020, new_data=new_data@entry=0xe606a0) at ../src/core/nm-config-data.c:1946
6 _set_config_data (self=0xe45810, new_data=0xe606a0, reload_flags=NM_CONFIG_CHANGE_CAUSE_SIGHUP) at ../src/core/nm-config.c:2923
7 nm_config_reload (self=0xe45810, reload_flags=NM_CONFIG_CHANGE_CAUSE_SIGHUP, emit_warnings=emit_warnings@entry=1) at ../src/core/nm-config.c:2875
8 nm_main_config_reload (signal=<optimized out>) at ../src/core/main.c:141
9 sighup_handler (user_data=<optimized out>) at ../src/core/main-utils.c:26
10 g_main_dispatch (context=0xe619e0) at ../glib/gmain.c:3444
11 g_main_context_dispatch (context=0xe619e0) at ../glib/gmain.c:4162
12 g_main_context_iterate.constprop.0 (context=0xe619e0, block=1, dispatch=1, self=<optimized out>) at ../glib/gmain.c:4238
13 g_main_loop_run (loop=0xe5e310) at ../glib/gmain.c:4438
14 main (argc=<optimized out>, argv=<optimized out>) at ../src/core/main.c:515
Fixes: 1f0d1d78d2a2 ('dns-manager: always apply options from [global-dns]')
2023-03-06 11:58:28 +01:00
|
|
|
if (old->domains) {
|
|
|
|
|
g_hash_table_iter_init(&iter, old->domains);
|
|
|
|
|
while (g_hash_table_iter_next(&iter, &key, &value_old)) {
|
|
|
|
|
value_new = g_hash_table_lookup(new->domains, key);
|
|
|
|
|
if (!value_new)
|
|
|
|
|
return FALSE;
|
2015-06-15 09:01:42 +02:00
|
|
|
|
core: fix crash when reloading global dns configuration
When reloading the configuration and there is a global DNS
configuration without domains, NM crashes in global_dns_equal()
because `old->domains` and `new->domains` are both NULL. Fix that.
Thread 1 "NetworkManager" received signal SIGTRAP, Trace/breakpoint trap.
0 g_logv (log_domain=0x7fe81a2110be "GLib", log_level=G_LOG_LEVEL_CRITICAL, format=<optimized out>, args=<optimized out>) at ../glib/gmessages.c:1433
1 g_log (log_domain=<optimized out>, log_level=<optimized out>, format=<optimized out>) at ../glib/gmessages.c:1471
2 g_hash_table_size (hash_table=<optimized out>) at ../glib/ghash.c:2183
3 g_hash_table_size (hash_table=<optimized out>) at ../glib/ghash.c:2181
4 global_dns_equal (new=0xecc540, old=0xe618e0) at ../src/core/nm-config-data.c:1466
5 nm_config_data_diff (old_data=old_data@entry=0xe60020, new_data=new_data@entry=0xe606a0) at ../src/core/nm-config-data.c:1946
6 _set_config_data (self=0xe45810, new_data=0xe606a0, reload_flags=NM_CONFIG_CHANGE_CAUSE_SIGHUP) at ../src/core/nm-config.c:2923
7 nm_config_reload (self=0xe45810, reload_flags=NM_CONFIG_CHANGE_CAUSE_SIGHUP, emit_warnings=emit_warnings@entry=1) at ../src/core/nm-config.c:2875
8 nm_main_config_reload (signal=<optimized out>) at ../src/core/main.c:141
9 sighup_handler (user_data=<optimized out>) at ../src/core/main-utils.c:26
10 g_main_dispatch (context=0xe619e0) at ../glib/gmain.c:3444
11 g_main_context_dispatch (context=0xe619e0) at ../glib/gmain.c:4162
12 g_main_context_iterate.constprop.0 (context=0xe619e0, block=1, dispatch=1, self=<optimized out>) at ../glib/gmain.c:4238
13 g_main_loop_run (loop=0xe5e310) at ../glib/gmain.c:4438
14 main (argc=<optimized out>, argv=<optimized out>) at ../src/core/main.c:515
Fixes: 1f0d1d78d2a2 ('dns-manager: always apply options from [global-dns]')
2023-03-06 11:58:28 +01:00
|
|
|
domain_old = value_old;
|
|
|
|
|
domain_new = value_new;
|
2015-06-15 09:01:42 +02:00
|
|
|
|
core: fix crash when reloading global dns configuration
When reloading the configuration and there is a global DNS
configuration without domains, NM crashes in global_dns_equal()
because `old->domains` and `new->domains` are both NULL. Fix that.
Thread 1 "NetworkManager" received signal SIGTRAP, Trace/breakpoint trap.
0 g_logv (log_domain=0x7fe81a2110be "GLib", log_level=G_LOG_LEVEL_CRITICAL, format=<optimized out>, args=<optimized out>) at ../glib/gmessages.c:1433
1 g_log (log_domain=<optimized out>, log_level=<optimized out>, format=<optimized out>) at ../glib/gmessages.c:1471
2 g_hash_table_size (hash_table=<optimized out>) at ../glib/ghash.c:2183
3 g_hash_table_size (hash_table=<optimized out>) at ../glib/ghash.c:2181
4 global_dns_equal (new=0xecc540, old=0xe618e0) at ../src/core/nm-config-data.c:1466
5 nm_config_data_diff (old_data=old_data@entry=0xe60020, new_data=new_data@entry=0xe606a0) at ../src/core/nm-config-data.c:1946
6 _set_config_data (self=0xe45810, new_data=0xe606a0, reload_flags=NM_CONFIG_CHANGE_CAUSE_SIGHUP) at ../src/core/nm-config.c:2923
7 nm_config_reload (self=0xe45810, reload_flags=NM_CONFIG_CHANGE_CAUSE_SIGHUP, emit_warnings=emit_warnings@entry=1) at ../src/core/nm-config.c:2875
8 nm_main_config_reload (signal=<optimized out>) at ../src/core/main.c:141
9 sighup_handler (user_data=<optimized out>) at ../src/core/main-utils.c:26
10 g_main_dispatch (context=0xe619e0) at ../glib/gmain.c:3444
11 g_main_context_dispatch (context=0xe619e0) at ../glib/gmain.c:4162
12 g_main_context_iterate.constprop.0 (context=0xe619e0, block=1, dispatch=1, self=<optimized out>) at ../glib/gmain.c:4238
13 g_main_loop_run (loop=0xe5e310) at ../glib/gmain.c:4438
14 main (argc=<optimized out>, argv=<optimized out>) at ../src/core/main.c:515
Fixes: 1f0d1d78d2a2 ('dns-manager: always apply options from [global-dns]')
2023-03-06 11:58:28 +01:00
|
|
|
if (!nm_strv_equal(domain_old->options, domain_new->options)
|
|
|
|
|
|| !nm_strv_equal(domain_old->servers, domain_new->servers))
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
2015-06-15 09:01:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-02 18:22:50 +02:00
|
|
|
/*****************************************************************************/
|
2015-06-15 09:01:42 +02:00
|
|
|
|
2016-06-22 13:14:10 +02:00
|
|
|
static const MatchSectionInfo *
|
2023-06-12 12:43:03 +02:00
|
|
|
_match_section_infos_lookup(const MatchSectionInfo *match_section_infos,
|
|
|
|
|
GKeyFile *keyfile,
|
|
|
|
|
const char *property,
|
|
|
|
|
const NMMatchSpecDeviceData *match_data,
|
|
|
|
|
NMDevice *device,
|
|
|
|
|
const char **out_value)
|
2015-05-15 11:36:28 +02:00
|
|
|
{
|
2023-06-12 12:43:03 +02:00
|
|
|
NMMatchSpecDeviceData match_data_local;
|
|
|
|
|
|
|
|
|
|
/* Caller must either provide a "match_data" or a "device" (actually,
|
|
|
|
|
* neither is also fine, albeit unusual). */
|
|
|
|
|
nm_assert(!match_data || !device);
|
|
|
|
|
nm_assert(!device || NM_IS_DEVICE(device));
|
device: add "dhcp-plugin" match spec for device
The need for this is the following:
"ipv4.dhcp-client-id" can be specified via global connection defaults.
In absence of any configuration in NetworkManager, the default depends
on the DHCP client plugin. In case of "dhclient", the default further
depends on /etc/dhcp.
For "internal" plugin, we may very well want to change the default
client-id to "mac" by universally installing a configuration
snippet
[connection-use-mac-client-id]
ipv4.dhcp-client-id=mac
However, if we the user happens to enable "dhclient" plugin, this also
forces the client-id and overrules configuration from /etc/dhcp. The real
problem is, that dhclient can be configured via means outside of NetworkManager,
so our defaults shall not overwrite defaults from /etc/dhcp.
With the new device spec, we can avoid this issue:
[connection-dhcp-client-id]
match-device=except:dhcp-plugin:dhclient
ipv4.dhcp-client-id=mac
This will be part of the solution for rh#1640494. Note that merely
dropping a configuration snippet is not yet enough. More fixes for
DHCP will follow. Also, bug rh#1640494 may have alternative solutions
as well. The nice part of this new feature is that it is generally
useful for configuring connection defaults and not specifically for
the client-id issue.
Note that this match spec is per-device, although the plugin is selected
globally. That makes some sense, because in the future we may or may not
configure the DHCP plugin per-device or per address family.
https://bugzilla.redhat.com/show_bug.cgi?id=1640494
2018-10-24 08:43:45 +02:00
|
|
|
|
2016-06-22 13:14:10 +02:00
|
|
|
if (!match_section_infos)
|
2021-06-16 09:50:39 +02:00
|
|
|
goto out;
|
2015-05-15 11:36:28 +02:00
|
|
|
|
2016-06-22 13:14:10 +02:00
|
|
|
for (; match_section_infos->group_name; match_section_infos++) {
|
2021-06-16 09:50:39 +02:00
|
|
|
const char *value;
|
|
|
|
|
gboolean match;
|
2015-05-15 11:36:28 +02:00
|
|
|
|
2015-06-16 15:33:13 +02:00
|
|
|
/* FIXME: Here we use g_key_file_get_string(). This should be in sync with what keyfile-reader
|
|
|
|
|
* does.
|
|
|
|
|
*
|
|
|
|
|
* Unfortunately that is currently not possible because keyfile-reader does the two steps
|
|
|
|
|
* string_to_value(keyfile_to_string(keyfile)) in one. Optimally, keyfile library would
|
|
|
|
|
* expose both functions, and we would return here keyfile_to_string(keyfile).
|
|
|
|
|
* The caller then could convert the string to the proper value via string_to_value(value). */
|
2021-06-16 09:50:39 +02:00
|
|
|
value = _match_section_info_get_str(match_section_infos, keyfile, property);
|
2016-06-22 13:14:10 +02:00
|
|
|
if (!value && !match_section_infos->stop_match)
|
2015-05-15 11:36:28 +02:00
|
|
|
continue;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-12-13 15:33:33 +01:00
|
|
|
if (match_section_infos->match_device.has) {
|
2023-06-12 12:43:03 +02:00
|
|
|
NMMatchSpecMatchType m;
|
|
|
|
|
|
|
|
|
|
if (G_UNLIKELY(!match_data)) {
|
|
|
|
|
/* In most cases, we don't actually have any matches. So we "optimize"
|
|
|
|
|
* here by allowing the user to specify a NMDEvice directly, and only
|
|
|
|
|
* initialize the match-data when needed. */
|
|
|
|
|
match_data = nm_match_spec_device_data_init_from_device(&match_data_local, device);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m = nm_match_spec_device(match_section_infos->match_device.spec, match_data);
|
|
|
|
|
match = nm_match_spec_match_type_to_bool(m, FALSE);
|
2017-12-13 15:33:33 +01:00
|
|
|
} else
|
|
|
|
|
match = TRUE;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2016-06-22 13:14:10 +02:00
|
|
|
if (match) {
|
2021-06-03 09:01:23 +02:00
|
|
|
NM_SET_OUT(out_value, value);
|
2016-06-22 13:14:10 +02:00
|
|
|
return match_section_infos;
|
|
|
|
|
}
|
2015-05-15 11:36:28 +02:00
|
|
|
}
|
2021-06-16 09:50:39 +02:00
|
|
|
|
|
|
|
|
out:
|
2021-06-03 09:01:23 +02:00
|
|
|
NM_SET_OUT(out_value, NULL);
|
2015-05-15 11:36:28 +02:00
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-12 13:37:08 +02:00
|
|
|
static const char *
|
|
|
|
|
_config_data_get_device_config(const NMConfigData *self,
|
|
|
|
|
const char *property,
|
|
|
|
|
const NMMatchSpecDeviceData *match_data,
|
|
|
|
|
NMDevice *device,
|
|
|
|
|
gboolean *has_match)
|
2016-06-22 13:14:10 +02:00
|
|
|
{
|
2016-09-29 13:49:01 +02:00
|
|
|
const NMConfigDataPrivate *priv;
|
2021-11-09 13:28:54 +01:00
|
|
|
const MatchSectionInfo *connection_info;
|
|
|
|
|
const char *value;
|
2016-06-22 13:14:10 +02:00
|
|
|
|
2020-08-12 14:01:21 +02:00
|
|
|
NM_SET_OUT(has_match, FALSE);
|
|
|
|
|
|
2016-06-22 13:14:10 +02:00
|
|
|
g_return_val_if_fail(self, NULL);
|
|
|
|
|
g_return_val_if_fail(property && *property, NULL);
|
|
|
|
|
|
2023-06-12 13:37:08 +02:00
|
|
|
nm_assert(!match_data || !device);
|
|
|
|
|
nm_assert(!device || NM_IS_DEVICE(device));
|
|
|
|
|
|
2016-06-22 13:14:10 +02:00
|
|
|
priv = NM_CONFIG_DATA_GET_PRIVATE(self);
|
|
|
|
|
|
|
|
|
|
connection_info = _match_section_infos_lookup(&priv->device_infos[0],
|
|
|
|
|
priv->keyfile,
|
|
|
|
|
property,
|
2023-06-12 13:37:08 +02:00
|
|
|
match_data,
|
2023-06-12 12:43:03 +02:00
|
|
|
device,
|
2017-12-13 15:33:33 +01:00
|
|
|
&value);
|
|
|
|
|
NM_SET_OUT(has_match, !!connection_info);
|
|
|
|
|
return value;
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-12 13:37:08 +02:00
|
|
|
const char *
|
|
|
|
|
nm_config_data_get_device_config(const NMConfigData *self,
|
|
|
|
|
const char *property,
|
|
|
|
|
const NMMatchSpecDeviceData *match_data,
|
|
|
|
|
gboolean *has_match)
|
|
|
|
|
{
|
|
|
|
|
return _config_data_get_device_config(self, property, match_data, NULL, has_match);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char *
|
|
|
|
|
nm_config_data_get_device_config_by_device(const NMConfigData *self,
|
|
|
|
|
const char *property,
|
|
|
|
|
NMDevice *device,
|
|
|
|
|
gboolean *has_match)
|
|
|
|
|
{
|
|
|
|
|
return _config_data_get_device_config(self, property, NULL, device, has_match);
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-16 09:50:46 +02:00
|
|
|
const char *
|
2021-11-09 13:28:54 +01:00
|
|
|
nm_config_data_get_device_config_by_pllink(const NMConfigData *self,
|
|
|
|
|
const char *property,
|
2017-12-13 15:33:33 +01:00
|
|
|
const NMPlatformLink *pllink,
|
2021-11-09 13:28:54 +01:00
|
|
|
const char *match_device_type,
|
|
|
|
|
gboolean *has_match)
|
2017-12-13 15:33:33 +01:00
|
|
|
{
|
|
|
|
|
const NMConfigDataPrivate *priv;
|
2021-11-09 13:28:54 +01:00
|
|
|
const MatchSectionInfo *connection_info;
|
|
|
|
|
const char *value;
|
2023-06-12 12:43:03 +02:00
|
|
|
NMMatchSpecDeviceData match_data;
|
2017-12-13 15:33:33 +01:00
|
|
|
|
|
|
|
|
g_return_val_if_fail(self, NULL);
|
|
|
|
|
g_return_val_if_fail(property && *property, NULL);
|
|
|
|
|
|
|
|
|
|
priv = NM_CONFIG_DATA_GET_PRIVATE(self);
|
|
|
|
|
|
2023-06-12 12:43:03 +02:00
|
|
|
nm_match_spec_device_data_init_from_platform(&match_data,
|
|
|
|
|
pllink,
|
|
|
|
|
match_device_type,
|
|
|
|
|
nm_dhcp_manager_get_config(nm_dhcp_manager_get()));
|
|
|
|
|
|
2017-12-13 15:33:33 +01:00
|
|
|
connection_info = _match_section_infos_lookup(&priv->device_infos[0],
|
|
|
|
|
priv->keyfile,
|
|
|
|
|
property,
|
2023-06-12 12:43:03 +02:00
|
|
|
&match_data,
|
2017-12-13 15:33:33 +01:00
|
|
|
NULL,
|
2016-06-22 13:14:10 +02:00
|
|
|
&value);
|
|
|
|
|
NM_SET_OUT(has_match, !!connection_info);
|
|
|
|
|
return value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gboolean
|
2023-06-12 13:20:13 +02:00
|
|
|
nm_config_data_get_device_config_boolean_by_device(const NMConfigData *self,
|
|
|
|
|
const char *property,
|
|
|
|
|
NMDevice *device,
|
|
|
|
|
int val_no_match,
|
|
|
|
|
int val_invalid)
|
2016-06-22 13:14:10 +02:00
|
|
|
{
|
2021-06-16 09:50:46 +02:00
|
|
|
const char *value;
|
|
|
|
|
gboolean has_match;
|
2016-06-22 13:14:10 +02:00
|
|
|
|
2023-06-12 13:20:13 +02:00
|
|
|
value = nm_config_data_get_device_config_by_device(self, property, device, &has_match);
|
2016-06-22 13:14:10 +02:00
|
|
|
if (!has_match)
|
|
|
|
|
return val_no_match;
|
|
|
|
|
return nm_config_parse_boolean(value, val_invalid);
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-16 09:12:02 +02:00
|
|
|
gint64
|
2023-06-12 13:20:13 +02:00
|
|
|
nm_config_data_get_device_config_int64_by_device(const NMConfigData *self,
|
|
|
|
|
const char *property,
|
|
|
|
|
NMDevice *device,
|
|
|
|
|
int base,
|
|
|
|
|
gint64 min,
|
|
|
|
|
gint64 max,
|
|
|
|
|
gint64 val_no_match,
|
|
|
|
|
gint64 val_invalid)
|
2021-06-16 09:12:02 +02:00
|
|
|
{
|
2021-06-16 09:50:46 +02:00
|
|
|
const char *value;
|
|
|
|
|
gboolean has_match;
|
2021-06-16 09:12:02 +02:00
|
|
|
|
2023-06-12 13:20:13 +02:00
|
|
|
value = nm_config_data_get_device_config_by_device(self, property, device, &has_match);
|
2021-06-16 09:12:02 +02:00
|
|
|
if (!has_match) {
|
|
|
|
|
errno = ENOENT;
|
|
|
|
|
return val_no_match;
|
|
|
|
|
}
|
|
|
|
|
return _nm_utils_ascii_str_to_int64(value, base, min, max, val_invalid);
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-03 09:01:23 +02:00
|
|
|
const GSList *
|
|
|
|
|
nm_config_data_get_device_allowed_connections_specs(const NMConfigData *self,
|
2021-11-09 13:28:54 +01:00
|
|
|
NMDevice *device,
|
|
|
|
|
gboolean *has_match)
|
2021-06-03 09:01:23 +02:00
|
|
|
{
|
|
|
|
|
const NMConfigDataPrivate *priv;
|
2021-11-09 13:28:54 +01:00
|
|
|
const MatchSectionInfo *connection_info;
|
|
|
|
|
const GSList *ret = NULL;
|
2021-06-03 09:01:23 +02:00
|
|
|
|
|
|
|
|
g_return_val_if_fail(self, NULL);
|
|
|
|
|
|
|
|
|
|
priv = NM_CONFIG_DATA_GET_PRIVATE(self);
|
|
|
|
|
|
|
|
|
|
connection_info = _match_section_infos_lookup(&priv->device_infos[0],
|
|
|
|
|
priv->keyfile,
|
|
|
|
|
NM_CONFIG_KEYFILE_KEY_DEVICE_ALLOWED_CONNECTIONS,
|
|
|
|
|
NULL,
|
2023-06-12 12:43:03 +02:00
|
|
|
device,
|
2021-06-03 09:01:23 +02:00
|
|
|
NULL);
|
|
|
|
|
|
|
|
|
|
if (connection_info) {
|
|
|
|
|
nm_assert(connection_info->device.allowed_connections_has);
|
|
|
|
|
ret = connection_info->device.allowed_connections;
|
|
|
|
|
NM_SET_OUT(has_match, TRUE);
|
|
|
|
|
} else
|
|
|
|
|
NM_SET_OUT(has_match, FALSE);
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-16 09:50:46 +02:00
|
|
|
const char *
|
2016-06-22 13:14:10 +02:00
|
|
|
nm_config_data_get_connection_default(const NMConfigData *self,
|
2021-11-09 13:28:54 +01:00
|
|
|
const char *property,
|
|
|
|
|
NMDevice *device)
|
2016-06-22 13:14:10 +02:00
|
|
|
{
|
2016-09-29 13:49:01 +02:00
|
|
|
const NMConfigDataPrivate *priv;
|
2021-11-09 13:28:54 +01:00
|
|
|
const char *value;
|
2016-06-22 13:14:10 +02:00
|
|
|
|
|
|
|
|
g_return_val_if_fail(self, NULL);
|
|
|
|
|
g_return_val_if_fail(property && *property, NULL);
|
|
|
|
|
g_return_val_if_fail(strchr(property, '.'), NULL);
|
|
|
|
|
|
|
|
|
|
priv = NM_CONFIG_DATA_GET_PRIVATE(self);
|
|
|
|
|
|
2018-11-14 14:52:21 +01:00
|
|
|
#if NM_MORE_ASSERTS > 10
|
|
|
|
|
{
|
|
|
|
|
const char **ptr;
|
|
|
|
|
|
|
|
|
|
for (ptr = __start_connection_defaults; ptr < __stop_connection_defaults; ptr++) {
|
|
|
|
|
if (nm_streq(property, *ptr))
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nm_assert(ptr < __stop_connection_defaults);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2016-06-22 13:14:10 +02:00
|
|
|
_match_section_infos_lookup(&priv->connection_infos[0],
|
|
|
|
|
priv->keyfile,
|
|
|
|
|
property,
|
2017-12-27 09:30:49 +01:00
|
|
|
NULL,
|
2023-06-12 12:43:03 +02:00
|
|
|
device,
|
2016-06-22 13:14:10 +02:00
|
|
|
&value);
|
|
|
|
|
return value;
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-05 09:24:33 +02:00
|
|
|
gint64
|
|
|
|
|
nm_config_data_get_connection_default_int64(const NMConfigData *self,
|
2021-11-09 13:28:54 +01:00
|
|
|
const char *property,
|
|
|
|
|
NMDevice *device,
|
2018-09-05 09:24:33 +02:00
|
|
|
gint64 min,
|
|
|
|
|
gint64 max,
|
|
|
|
|
gint64 fallback)
|
|
|
|
|
{
|
2021-06-16 09:50:46 +02:00
|
|
|
const char *value;
|
2018-09-05 09:24:33 +02:00
|
|
|
|
|
|
|
|
value = nm_config_data_get_connection_default(self, property, device);
|
2022-08-10 10:03:19 +02:00
|
|
|
return _nm_utils_ascii_str_to_int64(value, 0, min, max, fallback);
|
2018-09-05 09:24:33 +02:00
|
|
|
}
|
|
|
|
|
|
2021-06-16 09:50:39 +02:00
|
|
|
static const char *
|
|
|
|
|
_match_section_info_get_str(const MatchSectionInfo *m, GKeyFile *keyfile, const char *property)
|
|
|
|
|
{
|
|
|
|
|
gssize idx;
|
|
|
|
|
const char *value;
|
|
|
|
|
|
|
|
|
|
idx = nm_utils_named_value_list_find(m->lookup_idx, m->lookup_len, property, TRUE);
|
|
|
|
|
value = idx >= 0 ? m->lookup_idx[idx].value_str : NULL;
|
|
|
|
|
|
|
|
|
|
#if NM_MORE_ASSERTS > 10
|
|
|
|
|
{
|
|
|
|
|
gs_free char *value2 = g_key_file_get_string(keyfile, m->group_name, property, NULL);
|
|
|
|
|
|
|
|
|
|
nm_assert(nm_streq0(value2, value));
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
return value;
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-25 13:02:10 +02:00
|
|
|
static void
|
2021-06-03 09:01:23 +02:00
|
|
|
_match_section_info_init(MatchSectionInfo *connection_info,
|
2021-11-09 13:28:54 +01:00
|
|
|
GKeyFile *keyfile,
|
|
|
|
|
char *group,
|
2021-06-03 09:01:23 +02:00
|
|
|
gboolean is_device)
|
2015-06-25 13:02:10 +02:00
|
|
|
{
|
2021-11-09 13:28:54 +01:00
|
|
|
char **keys = NULL;
|
2021-06-16 09:50:39 +02:00
|
|
|
gsize n_keys;
|
|
|
|
|
gsize i;
|
|
|
|
|
gsize j;
|
|
|
|
|
NMUtilsNamedValue *vals;
|
|
|
|
|
|
2015-06-25 13:02:10 +02:00
|
|
|
/* pass ownership of @group on... */
|
|
|
|
|
connection_info->group_name = group;
|
|
|
|
|
|
2015-10-01 10:50:14 +02:00
|
|
|
connection_info->match_device.spec =
|
|
|
|
|
nm_config_get_match_spec(keyfile,
|
|
|
|
|
group,
|
2018-11-09 18:05:04 +01:00
|
|
|
NM_CONFIG_KEYFILE_KEY_MATCH_DEVICE,
|
2015-10-01 10:50:14 +02:00
|
|
|
&connection_info->match_device.has);
|
2018-11-09 18:05:04 +01:00
|
|
|
connection_info->stop_match =
|
|
|
|
|
nm_config_keyfile_get_boolean(keyfile, group, NM_CONFIG_KEYFILE_KEY_STOP_MATCH, FALSE);
|
2021-06-16 09:50:39 +02:00
|
|
|
|
2021-06-03 09:01:23 +02:00
|
|
|
if (is_device) {
|
|
|
|
|
connection_info->device.allowed_connections =
|
|
|
|
|
nm_config_get_match_spec(keyfile,
|
|
|
|
|
group,
|
|
|
|
|
NM_CONFIG_KEYFILE_KEY_DEVICE_ALLOWED_CONNECTIONS,
|
|
|
|
|
&connection_info->device.allowed_connections_has);
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-16 09:50:39 +02:00
|
|
|
keys = g_key_file_get_keys(keyfile, group, &n_keys, NULL);
|
2021-07-29 10:02:11 +02:00
|
|
|
nm_strv_sort(keys, n_keys);
|
2021-06-16 09:50:39 +02:00
|
|
|
|
|
|
|
|
vals = g_new(NMUtilsNamedValue, n_keys);
|
|
|
|
|
|
|
|
|
|
for (i = 0, j = 0; i < n_keys; i++) {
|
|
|
|
|
gs_free char *key = g_steal_pointer(&keys[i]);
|
2021-11-09 13:28:54 +01:00
|
|
|
char *value;
|
2021-06-16 09:50:39 +02:00
|
|
|
|
|
|
|
|
if (NM_IN_STRSET(key, NM_CONFIG_KEYFILE_KEY_STOP_MATCH, NM_CONFIG_KEYFILE_KEY_MATCH_DEVICE))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (j > 0 && nm_streq(vals[j - 1].name, key))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
value = g_key_file_get_string(keyfile, group, key, NULL);
|
|
|
|
|
if (!value)
|
|
|
|
|
continue;
|
|
|
|
|
|
2024-10-04 10:45:56 +02:00
|
|
|
vals[j++] = (NMUtilsNamedValue) {
|
2021-06-16 09:50:39 +02:00
|
|
|
.name = g_steal_pointer(&key),
|
|
|
|
|
.value_str = value,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g_free(keys);
|
|
|
|
|
|
|
|
|
|
if (n_keys != j) {
|
|
|
|
|
gs_free NMUtilsNamedValue *vals2 = vals;
|
|
|
|
|
|
|
|
|
|
/* since this buffer will be kept around for a long time,
|
|
|
|
|
* get rid of the excess allocation. */
|
|
|
|
|
vals = nm_memdup(vals2, sizeof(NMUtilsNamedValue) * j);
|
|
|
|
|
n_keys = j;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (n_keys == 0)
|
|
|
|
|
nm_clear_g_free(&vals);
|
|
|
|
|
|
|
|
|
|
connection_info->lookup_idx = vals;
|
|
|
|
|
connection_info->lookup_len = n_keys;
|
2015-06-25 13:02:10 +02:00
|
|
|
}
|
|
|
|
|
|
2016-06-22 13:14:10 +02:00
|
|
|
static void
|
|
|
|
|
_match_section_infos_free(MatchSectionInfo *match_section_infos)
|
|
|
|
|
{
|
2021-06-16 09:50:39 +02:00
|
|
|
MatchSectionInfo *m;
|
|
|
|
|
gsize i;
|
2016-06-22 13:14:10 +02:00
|
|
|
|
|
|
|
|
if (!match_section_infos)
|
|
|
|
|
return;
|
2021-06-03 09:01:23 +02:00
|
|
|
|
2021-06-16 09:50:39 +02:00
|
|
|
for (m = match_section_infos; m->group_name; m++) {
|
|
|
|
|
g_free(m->group_name);
|
|
|
|
|
g_slist_free_full(m->match_device.spec, g_free);
|
2021-06-03 09:01:23 +02:00
|
|
|
if (m->is_device) {
|
|
|
|
|
g_slist_free_full(m->device.allowed_connections, g_free);
|
|
|
|
|
}
|
2021-06-16 09:50:39 +02:00
|
|
|
for (i = 0; i < m->lookup_len; i++) {
|
|
|
|
|
g_free(m->lookup_idx[i].name_mutable);
|
|
|
|
|
g_free(m->lookup_idx[i].value_str_mutable);
|
|
|
|
|
}
|
|
|
|
|
g_free((gpointer) m->lookup_idx);
|
2016-06-22 13:14:10 +02:00
|
|
|
}
|
|
|
|
|
g_free(match_section_infos);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static MatchSectionInfo *
|
2021-06-03 09:01:23 +02:00
|
|
|
_match_section_infos_construct(GKeyFile *keyfile, gboolean is_device)
|
2015-05-15 11:36:28 +02:00
|
|
|
{
|
2021-11-09 13:28:54 +01:00
|
|
|
char **groups;
|
2015-06-25 13:02:10 +02:00
|
|
|
gsize i, j, ngroups;
|
2026-02-12 12:49:12 +01:00
|
|
|
char *main_group = NULL;
|
2016-06-22 13:14:10 +02:00
|
|
|
MatchSectionInfo *match_section_infos = NULL;
|
2026-02-12 12:49:12 +01:00
|
|
|
const char *prefix, *prefix_intern;
|
2021-06-03 09:01:23 +02:00
|
|
|
|
|
|
|
|
prefix =
|
|
|
|
|
is_device ? NM_CONFIG_KEYFILE_GROUPPREFIX_DEVICE : NM_CONFIG_KEYFILE_GROUPPREFIX_CONNECTION;
|
2026-02-12 12:49:12 +01:00
|
|
|
prefix_intern =
|
|
|
|
|
is_device ? NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN NM_CONFIG_KEYFILE_GROUPPREFIX_DEVICE
|
|
|
|
|
: NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN NM_CONFIG_KEYFILE_GROUPPREFIX_CONNECTION;
|
2015-05-15 11:36:28 +02:00
|
|
|
|
2016-06-22 13:14:10 +02:00
|
|
|
/* get the list of existing [connection.\+]/[device.\+] sections.
|
2015-06-25 13:02:10 +02:00
|
|
|
*
|
|
|
|
|
* We expect the sections in their right order, with lowest priority
|
|
|
|
|
* first. Only exception is the (literal) [connection] section, which
|
|
|
|
|
* we will always reorder to the end. */
|
|
|
|
|
groups = g_key_file_get_groups(keyfile, &ngroups);
|
|
|
|
|
if (!groups)
|
2016-06-22 13:14:10 +02:00
|
|
|
return NULL;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2026-02-12 12:49:12 +01:00
|
|
|
for (i = 0, j = 0; i < ngroups; i++) {
|
|
|
|
|
if (nm_streq0(groups[i], prefix)) {
|
|
|
|
|
main_group = groups[i];
|
|
|
|
|
} else if (nm_streq0(groups[i], prefix_intern)) {
|
|
|
|
|
/* [.intern.connection] and [.intern.device] should not exist */
|
|
|
|
|
nm_assert_not_reached();
|
|
|
|
|
continue;
|
|
|
|
|
} else if (g_str_has_prefix(groups[i], prefix)) {
|
|
|
|
|
groups[j++] = groups[i];
|
|
|
|
|
} else if (g_str_has_prefix(groups[i], prefix_intern)) {
|
|
|
|
|
/* [.intern.connection-whatever] and [.intern.device-whatever] can exist*/
|
|
|
|
|
groups[j++] = groups[i];
|
|
|
|
|
} else {
|
|
|
|
|
g_free(groups[i]);
|
2015-06-25 13:02:10 +02:00
|
|
|
}
|
2015-05-15 11:36:28 +02:00
|
|
|
}
|
2026-02-12 12:49:12 +01:00
|
|
|
ngroups = j;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2026-02-12 12:49:12 +01:00
|
|
|
if (ngroups == 0 && !main_group) {
|
2016-06-22 13:14:10 +02:00
|
|
|
g_free(groups);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2026-02-12 12:49:12 +01:00
|
|
|
match_section_infos = g_new0(MatchSectionInfo, ngroups + 1 + (main_group ? 1 : 0));
|
2021-06-03 09:01:23 +02:00
|
|
|
match_section_infos->is_device = is_device;
|
2015-06-25 13:02:10 +02:00
|
|
|
for (i = 0; i < ngroups; i++) {
|
|
|
|
|
/* pass ownership of @group on... */
|
2021-06-03 09:01:23 +02:00
|
|
|
_match_section_info_init(&match_section_infos[i],
|
|
|
|
|
keyfile,
|
|
|
|
|
groups[ngroups - i - 1],
|
|
|
|
|
is_device);
|
2015-05-15 11:36:28 +02:00
|
|
|
}
|
2026-02-12 12:49:12 +01:00
|
|
|
if (main_group) {
|
|
|
|
|
/* pass ownership of @main_group on... */
|
|
|
|
|
_match_section_info_init(&match_section_infos[i], keyfile, main_group, is_device);
|
2015-05-15 11:36:28 +02:00
|
|
|
}
|
2015-06-25 13:02:10 +02:00
|
|
|
g_free(groups);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2016-06-22 13:14:10 +02:00
|
|
|
return match_section_infos;
|
2015-05-15 11:36:28 +02:00
|
|
|
}
|
|
|
|
|
|
2016-10-02 18:22:50 +02:00
|
|
|
/*****************************************************************************/
|
2015-05-15 11:36:28 +02:00
|
|
|
|
2015-01-21 12:58:32 +01:00
|
|
|
NMConfigChangeFlags
|
2015-01-07 14:30:14 +01:00
|
|
|
nm_config_data_diff(NMConfigData *old_data, NMConfigData *new_data)
|
|
|
|
|
{
|
2015-01-21 12:58:32 +01:00
|
|
|
NMConfigChangeFlags changes = NM_CONFIG_CHANGE_NONE;
|
2015-01-07 13:25:41 +01:00
|
|
|
NMConfigDataPrivate *priv_old, *priv_new;
|
2015-01-07 14:30:14 +01:00
|
|
|
|
2015-01-21 12:58:32 +01:00
|
|
|
g_return_val_if_fail(NM_IS_CONFIG_DATA(old_data), NM_CONFIG_CHANGE_NONE);
|
|
|
|
|
g_return_val_if_fail(NM_IS_CONFIG_DATA(new_data), NM_CONFIG_CHANGE_NONE);
|
2015-01-07 14:30:14 +01:00
|
|
|
|
2015-01-07 13:25:41 +01:00
|
|
|
priv_old = NM_CONFIG_DATA_GET_PRIVATE(old_data);
|
|
|
|
|
priv_new = NM_CONFIG_DATA_GET_PRIVATE(new_data);
|
|
|
|
|
|
2021-05-20 20:39:38 +02:00
|
|
|
if (!_nm_keyfile_equal(priv_old->keyfile_user, priv_new->keyfile_user, TRUE))
|
2015-06-24 20:11:42 +02:00
|
|
|
changes |= NM_CONFIG_CHANGE_VALUES | NM_CONFIG_CHANGE_VALUES_USER;
|
|
|
|
|
|
2021-05-20 20:39:38 +02:00
|
|
|
if (!_nm_keyfile_equal(priv_old->keyfile_intern, priv_new->keyfile_intern, TRUE))
|
2015-06-24 20:11:42 +02:00
|
|
|
changes |= NM_CONFIG_CHANGE_VALUES | NM_CONFIG_CHANGE_VALUES_INTERN;
|
2015-01-07 13:25:41 +01:00
|
|
|
|
2021-03-22 09:37:43 +01:00
|
|
|
if (!nm_streq0(nm_config_data_get_config_main_file(old_data),
|
|
|
|
|
nm_config_data_get_config_main_file(new_data))
|
|
|
|
|
|| !nm_streq0(nm_config_data_get_config_description(old_data),
|
|
|
|
|
nm_config_data_get_config_description(new_data)))
|
2015-01-21 12:58:32 +01:00
|
|
|
changes |= NM_CONFIG_CHANGE_CONFIG_FILES;
|
2015-01-07 14:30:14 +01:00
|
|
|
|
2017-08-09 15:19:54 +08:00
|
|
|
if (nm_config_data_get_connectivity_enabled(old_data)
|
|
|
|
|
!= nm_config_data_get_connectivity_enabled(new_data)
|
|
|
|
|
|| nm_config_data_get_connectivity_interval(old_data)
|
|
|
|
|
!= nm_config_data_get_connectivity_interval(new_data)
|
2024-06-12 14:20:21 -04:00
|
|
|
|| nm_config_data_get_connectivity_timeout(old_data)
|
|
|
|
|
!= nm_config_data_get_connectivity_timeout(new_data)
|
2021-03-22 09:37:43 +01:00
|
|
|
|| !nm_streq0(nm_config_data_get_connectivity_uri(old_data),
|
|
|
|
|
nm_config_data_get_connectivity_uri(new_data))
|
|
|
|
|
|| !nm_streq0(nm_config_data_get_connectivity_response(old_data),
|
|
|
|
|
nm_config_data_get_connectivity_response(new_data)))
|
2015-01-21 12:58:32 +01:00
|
|
|
changes |= NM_CONFIG_CHANGE_CONNECTIVITY;
|
2015-01-07 14:30:14 +01:00
|
|
|
|
2019-07-18 14:49:56 +02:00
|
|
|
if (nm_utils_g_slist_strlist_cmp(priv_old->no_auto_default.specs,
|
|
|
|
|
priv_new->no_auto_default.specs)
|
|
|
|
|
!= 0
|
|
|
|
|
|| nm_utils_g_slist_strlist_cmp(priv_old->no_auto_default.specs_config,
|
|
|
|
|
priv_new->no_auto_default.specs_config)
|
|
|
|
|
!= 0)
|
2015-01-21 12:58:32 +01:00
|
|
|
changes |= NM_CONFIG_CHANGE_NO_AUTO_DEFAULT;
|
2015-01-07 17:09:52 +01:00
|
|
|
|
2021-03-22 09:37:43 +01:00
|
|
|
if (!nm_streq0(nm_config_data_get_dns_mode(old_data), nm_config_data_get_dns_mode(new_data)))
|
2015-02-12 17:35:14 +01:00
|
|
|
changes |= NM_CONFIG_CHANGE_DNS_MODE;
|
|
|
|
|
|
2021-03-22 09:37:43 +01:00
|
|
|
if (!nm_streq0(nm_config_data_get_rc_manager(old_data),
|
|
|
|
|
nm_config_data_get_rc_manager(new_data)))
|
2015-04-20 11:11:32 +02:00
|
|
|
changes |= NM_CONFIG_CHANGE_RC_MANAGER;
|
|
|
|
|
|
2015-06-15 09:01:42 +02:00
|
|
|
if (!global_dns_equal(priv_old->global_dns, priv_new->global_dns))
|
|
|
|
|
changes |= NM_CONFIG_CHANGE_GLOBAL_DNS_CONFIG;
|
|
|
|
|
|
config: refactor change-flags to be a cause/reason which triggered the change
For the most part, this patch just renames some change-flags, but
doesn't change much about them. The new name should better express
what they are.
A config-change signal can be emitted for different reasons:
when we receive a signal (SIGHUP, SIGUSR1, SIGUSR2) or for internal
reasons like resetting of no-auto-default or setting internal
values.
Depending on the reason, we want to perform different actions.
For example:
- we reload the configuration from disk on SIGHUP, but not for
SIGUSR1.
- For SIGUSR1 and SIGHUP, we want to update-dns, but not for SIGUSR2.
Another part of the change-flags encodes which part of the configuration
actually changed. Often, these parts can only change when re-reading
from disk (e.g. a SIGUSR1 will not change any configuration inside
NMConfig).
Later, we will have more causes, and accordingly more fine-grained
effects of what should be done on reload.
2016-05-30 14:53:27 +02:00
|
|
|
nm_assert(!NM_FLAGS_ANY(changes, NM_CONFIG_CHANGE_CAUSES));
|
|
|
|
|
|
2015-01-07 14:30:14 +01:00
|
|
|
return changes;
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-02 18:22:50 +02:00
|
|
|
/*****************************************************************************/
|
2014-07-11 17:57:20 +02:00
|
|
|
|
2019-12-11 11:35:11 +01:00
|
|
|
void
|
|
|
|
|
nm_config_data_get_warnings(const NMConfigData *self, GPtrArray *warnings)
|
|
|
|
|
{
|
2019-12-11 11:40:22 +01:00
|
|
|
gboolean invalid;
|
|
|
|
|
|
|
|
|
|
nm_assert(NM_IS_CONFIG_DATA(self));
|
|
|
|
|
nm_assert(warnings);
|
|
|
|
|
|
|
|
|
|
_config_data_get_main_auth_polkit(self, &invalid);
|
|
|
|
|
if (invalid) {
|
|
|
|
|
g_ptr_array_add(
|
|
|
|
|
warnings,
|
|
|
|
|
g_strdup_printf(
|
|
|
|
|
"invalid setting for %s.%s (should be one of \"true\", \"false\", \"root-only\")",
|
|
|
|
|
NM_CONFIG_KEYFILE_GROUP_MAIN,
|
|
|
|
|
NM_CONFIG_KEYFILE_KEY_MAIN_AUTH_POLKIT));
|
|
|
|
|
}
|
2019-12-11 11:35:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2014-07-11 17:57:20 +02:00
|
|
|
static void
|
|
|
|
|
get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
|
|
|
|
|
{
|
|
|
|
|
NMConfigData *self = NM_CONFIG_DATA(object);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2014-07-11 17:57:20 +02:00
|
|
|
switch (prop_id) {
|
2015-01-06 20:16:10 +01:00
|
|
|
case PROP_CONFIG_MAIN_FILE:
|
|
|
|
|
g_value_set_string(value, nm_config_data_get_config_main_file(self));
|
|
|
|
|
break;
|
|
|
|
|
case PROP_CONFIG_DESCRIPTION:
|
|
|
|
|
g_value_set_string(value, nm_config_data_get_config_description(self));
|
|
|
|
|
break;
|
2017-08-09 15:19:54 +08:00
|
|
|
case PROP_CONNECTIVITY_ENABLED:
|
|
|
|
|
g_value_set_boolean(value, nm_config_data_get_connectivity_enabled(self));
|
|
|
|
|
break;
|
2014-07-11 17:57:20 +02:00
|
|
|
case PROP_CONNECTIVITY_URI:
|
|
|
|
|
g_value_set_string(value, nm_config_data_get_connectivity_uri(self));
|
|
|
|
|
break;
|
|
|
|
|
case PROP_CONNECTIVITY_INTERVAL:
|
|
|
|
|
g_value_set_uint(value, nm_config_data_get_connectivity_interval(self));
|
|
|
|
|
break;
|
2024-06-12 14:20:21 -04:00
|
|
|
case PROP_CONNECTIVITY_TIMEOUT:
|
|
|
|
|
g_value_set_uint(value, nm_config_data_get_connectivity_timeout(self));
|
|
|
|
|
break;
|
2014-07-11 17:57:20 +02:00
|
|
|
case PROP_CONNECTIVITY_RESPONSE:
|
|
|
|
|
g_value_set_string(value, nm_config_data_get_connectivity_response(self));
|
|
|
|
|
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)
|
|
|
|
|
{
|
2021-11-09 13:28:54 +01:00
|
|
|
NMConfigData *self = NM_CONFIG_DATA(object);
|
2014-07-11 17:57:20 +02:00
|
|
|
NMConfigDataPrivate *priv = NM_CONFIG_DATA_GET_PRIVATE(self);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2014-07-11 17:57:20 +02:00
|
|
|
switch (prop_id) {
|
2015-01-06 20:16:10 +01:00
|
|
|
case PROP_CONFIG_MAIN_FILE:
|
2017-03-08 13:43:56 +01:00
|
|
|
/* construct-only */
|
2015-01-06 20:16:10 +01:00
|
|
|
priv->config_main_file = g_value_dup_string(value);
|
|
|
|
|
break;
|
|
|
|
|
case PROP_CONFIG_DESCRIPTION:
|
2017-03-08 13:43:56 +01:00
|
|
|
/* construct-only */
|
2015-01-06 20:16:10 +01:00
|
|
|
priv->config_description = g_value_dup_string(value);
|
|
|
|
|
break;
|
2015-06-24 20:11:42 +02:00
|
|
|
case PROP_KEYFILE_USER:
|
2017-03-08 13:43:56 +01:00
|
|
|
/* construct-only */
|
2015-06-24 20:11:42 +02:00
|
|
|
priv->keyfile_user = g_value_dup_boxed(value);
|
|
|
|
|
if (priv->keyfile_user && !_nm_keyfile_has_values(priv->keyfile_user)) {
|
|
|
|
|
g_key_file_unref(priv->keyfile_user);
|
|
|
|
|
priv->keyfile_user = NULL;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case PROP_KEYFILE_INTERN:
|
2017-03-08 13:43:56 +01:00
|
|
|
/* construct-only */
|
2015-06-24 20:11:42 +02:00
|
|
|
priv->keyfile_intern = g_value_dup_boxed(value);
|
|
|
|
|
if (priv->keyfile_intern && !_nm_keyfile_has_values(priv->keyfile_intern)) {
|
|
|
|
|
g_key_file_unref(priv->keyfile_intern);
|
|
|
|
|
priv->keyfile_intern = NULL;
|
|
|
|
|
}
|
2014-07-11 17:57:20 +02:00
|
|
|
break;
|
2015-01-07 17:09:52 +01:00
|
|
|
case PROP_NO_AUTO_DEFAULT:
|
2017-03-08 13:43:56 +01:00
|
|
|
/* construct-only */
|
2015-06-07 23:27:01 +02:00
|
|
|
{
|
2021-11-09 13:28:54 +01:00
|
|
|
const char *const *value_arr_orig = g_value_get_boxed(value);
|
2019-07-19 10:10:35 +02:00
|
|
|
gs_free const char **value_arr = NULL;
|
2021-11-09 13:28:54 +01:00
|
|
|
GSList *specs = NULL;
|
2019-07-19 10:10:35 +02:00
|
|
|
gsize i, j;
|
2019-07-18 15:10:58 +02:00
|
|
|
gsize len;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-07-19 10:10:35 +02:00
|
|
|
len = NM_PTRARRAY_LEN(value_arr_orig);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-07-19 10:10:35 +02:00
|
|
|
/* sort entries, remove duplicates and empty words. */
|
|
|
|
|
value_arr =
|
|
|
|
|
len == 0 ? NULL : nm_memdup(value_arr_orig, sizeof(const char *) * (len + 1));
|
2021-07-29 10:02:11 +02:00
|
|
|
nm_strv_sort(value_arr, len);
|
|
|
|
|
nm_strv_cleanup((char **) value_arr, FALSE, TRUE, TRUE);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-07-19 10:10:35 +02:00
|
|
|
len = NM_PTRARRAY_LEN(value_arr);
|
|
|
|
|
j = 0;
|
2019-07-18 15:10:58 +02:00
|
|
|
for (i = 0; i < len; i++) {
|
|
|
|
|
const char *s = value_arr[i];
|
2019-07-18 15:42:37 +02:00
|
|
|
gboolean is_mac;
|
2021-11-09 13:28:54 +01:00
|
|
|
char *spec;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-07-18 15:42:37 +02:00
|
|
|
if (NM_STR_HAS_PREFIX(s, NM_MATCH_SPEC_INTERFACE_NAME_TAG "="))
|
|
|
|
|
is_mac = FALSE;
|
|
|
|
|
else if (nm_utils_hwaddr_valid(s, -1))
|
|
|
|
|
is_mac = TRUE;
|
|
|
|
|
else {
|
|
|
|
|
/* we drop all lines that we don't understand. */
|
2019-07-18 15:10:58 +02:00
|
|
|
continue;
|
2019-07-18 15:42:37 +02:00
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-07-19 10:10:35 +02:00
|
|
|
value_arr[j++] = s;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-07-18 15:42:37 +02:00
|
|
|
spec = is_mac ? g_strdup_printf(NM_MATCH_SPEC_MAC_TAG "%s", s) : g_strdup(s);
|
2019-07-19 10:10:35 +02:00
|
|
|
specs = g_slist_prepend(specs, spec);
|
2015-06-07 23:27:01 +02:00
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2021-07-29 10:02:11 +02:00
|
|
|
priv->no_auto_default.arr = nm_strv_dup(value_arr, j, TRUE);
|
2019-07-19 10:10:35 +02:00
|
|
|
priv->no_auto_default.specs = g_slist_reverse(specs);
|
2015-06-07 23:27:01 +02:00
|
|
|
}
|
2015-01-07 17:09:52 +01:00
|
|
|
break;
|
2014-07-11 17:57:20 +02:00
|
|
|
default:
|
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-29 13:49:01 +02:00
|
|
|
/*****************************************************************************/
|
2014-07-11 17:57:20 +02:00
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
nm_config_data_init(NMConfigData *self)
|
|
|
|
|
{}
|
|
|
|
|
|
2015-01-07 13:25:41 +01:00
|
|
|
static void
|
|
|
|
|
constructed(GObject *object)
|
|
|
|
|
{
|
2021-11-09 13:28:54 +01:00
|
|
|
NMConfigData *self = NM_CONFIG_DATA(object);
|
2015-01-07 13:25:41 +01:00
|
|
|
NMConfigDataPrivate *priv = NM_CONFIG_DATA_GET_PRIVATE(self);
|
2021-11-09 13:28:54 +01:00
|
|
|
char *str;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2015-06-24 20:11:42 +02:00
|
|
|
priv->keyfile = _merge_keyfiles(priv->keyfile_user, priv->keyfile_intern);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2021-06-03 09:01:23 +02:00
|
|
|
priv->connection_infos = _match_section_infos_construct(priv->keyfile, FALSE);
|
|
|
|
|
priv->device_infos = _match_section_infos_construct(priv->keyfile, TRUE);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-11-09 18:05:04 +01:00
|
|
|
priv->connectivity.enabled =
|
|
|
|
|
nm_config_keyfile_get_boolean(priv->keyfile,
|
|
|
|
|
NM_CONFIG_KEYFILE_GROUP_CONNECTIVITY,
|
|
|
|
|
NM_CONFIG_KEYFILE_KEY_CONNECTIVITY_ENABLED,
|
|
|
|
|
TRUE);
|
|
|
|
|
priv->connectivity.uri =
|
|
|
|
|
nm_strstrip(g_key_file_get_string(priv->keyfile,
|
|
|
|
|
NM_CONFIG_KEYFILE_GROUP_CONNECTIVITY,
|
|
|
|
|
NM_CONFIG_KEYFILE_KEY_CONNECTIVITY_URI,
|
|
|
|
|
NULL));
|
|
|
|
|
priv->connectivity.response = g_key_file_get_string(priv->keyfile,
|
|
|
|
|
NM_CONFIG_KEYFILE_GROUP_CONNECTIVITY,
|
|
|
|
|
NM_CONFIG_KEYFILE_KEY_CONNECTIVITY_RESPONSE,
|
|
|
|
|
NULL);
|
|
|
|
|
str = nm_config_keyfile_get_value(priv->keyfile,
|
|
|
|
|
NM_CONFIG_KEYFILE_GROUP_MAIN,
|
|
|
|
|
NM_CONFIG_KEYFILE_KEY_MAIN_AUTOCONNECT_RETRIES_DEFAULT,
|
|
|
|
|
NM_CONFIG_GET_VALUE_NONE);
|
2017-11-22 21:19:40 +01:00
|
|
|
priv->autoconnect_retries_default = _nm_utils_ascii_str_to_int64(str, 10, 0, G_MAXINT32, 4);
|
|
|
|
|
g_free(str);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2015-02-19 14:24:37 +01:00
|
|
|
/* On missing config value, fallback to 300. On invalid value, disable connectivity checking by setting
|
|
|
|
|
* the interval to zero. */
|
2018-11-09 18:05:04 +01:00
|
|
|
str = g_key_file_get_string(priv->keyfile,
|
|
|
|
|
NM_CONFIG_KEYFILE_GROUP_CONNECTIVITY,
|
|
|
|
|
NM_CONFIG_KEYFILE_KEY_CONNECTIVITY_INTERVAL,
|
|
|
|
|
NULL);
|
2017-11-22 21:19:40 +01:00
|
|
|
priv->connectivity.interval =
|
|
|
|
|
_nm_utils_ascii_str_to_int64(str,
|
|
|
|
|
10,
|
|
|
|
|
0,
|
|
|
|
|
G_MAXUINT,
|
|
|
|
|
NM_CONFIG_DEFAULT_CONNECTIVITY_INTERVAL);
|
|
|
|
|
g_free(str);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2024-06-12 14:20:21 -04:00
|
|
|
/* On missing or invalid config value, fallback to 20. */
|
|
|
|
|
str = g_key_file_get_string(priv->keyfile,
|
|
|
|
|
NM_CONFIG_KEYFILE_GROUP_CONNECTIVITY,
|
|
|
|
|
NM_CONFIG_KEYFILE_KEY_CONNECTIVITY_TIMEOUT,
|
|
|
|
|
NULL);
|
|
|
|
|
priv->connectivity.timeout =
|
|
|
|
|
_nm_utils_ascii_str_to_int64(str, 10, 0, G_MAXUINT, NM_CONFIG_DEFAULT_CONNECTIVITY_TIMEOUT);
|
|
|
|
|
g_free(str);
|
|
|
|
|
|
2018-11-09 18:05:04 +01:00
|
|
|
priv->dns_mode = nm_strstrip(g_key_file_get_string(priv->keyfile,
|
|
|
|
|
NM_CONFIG_KEYFILE_GROUP_MAIN,
|
|
|
|
|
NM_CONFIG_KEYFILE_KEY_MAIN_DNS,
|
|
|
|
|
NULL));
|
|
|
|
|
priv->rc_manager = nm_strstrip(g_key_file_get_string(priv->keyfile,
|
|
|
|
|
NM_CONFIG_KEYFILE_GROUP_MAIN,
|
|
|
|
|
NM_CONFIG_KEYFILE_KEY_MAIN_RC_MANAGER,
|
|
|
|
|
NULL));
|
|
|
|
|
priv->systemd_resolved =
|
|
|
|
|
nm_config_keyfile_get_boolean(priv->keyfile,
|
|
|
|
|
NM_CONFIG_KEYFILE_GROUP_MAIN,
|
|
|
|
|
NM_CONFIG_KEYFILE_KEY_MAIN_SYSTEMD_RESOLVED,
|
|
|
|
|
TRUE);
|
|
|
|
|
priv->ignore_carrier = nm_config_get_match_spec(priv->keyfile,
|
|
|
|
|
NM_CONFIG_KEYFILE_GROUP_MAIN,
|
|
|
|
|
NM_CONFIG_KEYFILE_KEY_MAIN_IGNORE_CARRIER,
|
|
|
|
|
NULL);
|
|
|
|
|
priv->assume_ipv6ll_only =
|
|
|
|
|
nm_config_get_match_spec(priv->keyfile,
|
|
|
|
|
NM_CONFIG_KEYFILE_GROUP_MAIN,
|
|
|
|
|
NM_CONFIG_KEYFILE_KEY_MAIN_ASSUME_IPV6LL_ONLY,
|
|
|
|
|
NULL);
|
|
|
|
|
priv->no_auto_default.specs_config =
|
|
|
|
|
nm_config_get_match_spec(priv->keyfile,
|
|
|
|
|
NM_CONFIG_KEYFILE_GROUP_MAIN,
|
|
|
|
|
NM_CONFIG_KEYFILE_KEY_MAIN_NO_AUTO_DEFAULT,
|
|
|
|
|
NULL);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2015-06-15 09:01:42 +02:00
|
|
|
priv->global_dns = load_global_dns(priv->keyfile_user, FALSE);
|
|
|
|
|
if (!priv->global_dns)
|
|
|
|
|
priv->global_dns = load_global_dns(priv->keyfile_intern, TRUE);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-11-27 16:15:41 +01:00
|
|
|
priv->iwd_config_path =
|
|
|
|
|
nm_strstrip(g_key_file_get_string(priv->keyfile,
|
|
|
|
|
NM_CONFIG_KEYFILE_GROUP_MAIN,
|
|
|
|
|
NM_CONFIG_KEYFILE_KEY_MAIN_IWD_CONFIG_PATH,
|
|
|
|
|
NULL));
|
|
|
|
|
|
2015-01-07 13:25:41 +01:00
|
|
|
G_OBJECT_CLASS(nm_config_data_parent_class)->constructed(object);
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-16 16:52:34 +01:00
|
|
|
NMConfigData *
|
2021-11-09 13:28:54 +01:00
|
|
|
nm_config_data_new(const char *config_main_file,
|
|
|
|
|
const char *config_description,
|
2015-01-07 17:09:52 +01:00
|
|
|
const char *const *no_auto_default,
|
2021-11-09 13:28:54 +01:00
|
|
|
GKeyFile *keyfile_user,
|
|
|
|
|
GKeyFile *keyfile_intern)
|
2014-12-16 16:52:34 +01:00
|
|
|
{
|
2015-01-07 13:25:41 +01:00
|
|
|
return g_object_new(NM_TYPE_CONFIG_DATA,
|
|
|
|
|
NM_CONFIG_DATA_CONFIG_MAIN_FILE,
|
|
|
|
|
config_main_file,
|
|
|
|
|
NM_CONFIG_DATA_CONFIG_DESCRIPTION,
|
|
|
|
|
config_description,
|
2015-06-24 20:11:42 +02:00
|
|
|
NM_CONFIG_DATA_KEYFILE_USER,
|
|
|
|
|
keyfile_user,
|
|
|
|
|
NM_CONFIG_DATA_KEYFILE_INTERN,
|
|
|
|
|
keyfile_intern,
|
2015-01-07 17:09:52 +01:00
|
|
|
NM_CONFIG_DATA_NO_AUTO_DEFAULT,
|
|
|
|
|
no_auto_default,
|
|
|
|
|
NULL);
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-24 20:11:42 +02:00
|
|
|
NMConfigData *
|
|
|
|
|
nm_config_data_new_update_keyfile_intern(const NMConfigData *base, GKeyFile *keyfile_intern)
|
|
|
|
|
{
|
2016-09-29 13:49:01 +02:00
|
|
|
const NMConfigDataPrivate *priv = NM_CONFIG_DATA_GET_PRIVATE(base);
|
2015-06-24 20:11:42 +02:00
|
|
|
|
|
|
|
|
return g_object_new(NM_TYPE_CONFIG_DATA,
|
|
|
|
|
NM_CONFIG_DATA_CONFIG_MAIN_FILE,
|
|
|
|
|
priv->config_main_file,
|
|
|
|
|
NM_CONFIG_DATA_CONFIG_DESCRIPTION,
|
|
|
|
|
priv->config_description,
|
|
|
|
|
NM_CONFIG_DATA_KEYFILE_USER,
|
|
|
|
|
priv->keyfile_user, /* the keyfile is unchanged. It's safe to share it. */
|
|
|
|
|
NM_CONFIG_DATA_KEYFILE_INTERN,
|
|
|
|
|
keyfile_intern,
|
|
|
|
|
NM_CONFIG_DATA_NO_AUTO_DEFAULT,
|
|
|
|
|
priv->no_auto_default.arr,
|
|
|
|
|
NULL);
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-07 17:09:52 +01:00
|
|
|
NMConfigData *
|
|
|
|
|
nm_config_data_new_update_no_auto_default(const NMConfigData *base,
|
2021-11-09 13:28:54 +01:00
|
|
|
const char *const *no_auto_default)
|
2015-01-07 17:09:52 +01:00
|
|
|
{
|
2016-09-29 13:49:01 +02:00
|
|
|
const NMConfigDataPrivate *priv = NM_CONFIG_DATA_GET_PRIVATE(base);
|
2015-01-07 17:09:52 +01:00
|
|
|
|
|
|
|
|
return g_object_new(NM_TYPE_CONFIG_DATA,
|
|
|
|
|
NM_CONFIG_DATA_CONFIG_MAIN_FILE,
|
|
|
|
|
priv->config_main_file,
|
|
|
|
|
NM_CONFIG_DATA_CONFIG_DESCRIPTION,
|
|
|
|
|
priv->config_description,
|
2015-06-24 20:11:42 +02:00
|
|
|
NM_CONFIG_DATA_KEYFILE_USER,
|
|
|
|
|
priv->keyfile_user, /* the keyfile is unchanged. It's safe to share it. */
|
|
|
|
|
NM_CONFIG_DATA_KEYFILE_INTERN,
|
|
|
|
|
priv->keyfile_intern,
|
2015-01-07 17:09:52 +01:00
|
|
|
NM_CONFIG_DATA_NO_AUTO_DEFAULT,
|
|
|
|
|
no_auto_default,
|
2015-01-07 13:25:41 +01:00
|
|
|
NULL);
|
2014-12-16 16:52:34 +01:00
|
|
|
}
|
|
|
|
|
|
2016-09-29 13:49:01 +02:00
|
|
|
static void
|
|
|
|
|
finalize(GObject *gobject)
|
|
|
|
|
{
|
2020-02-14 10:50:25 +01:00
|
|
|
NMConfigDataPrivate *priv = NM_CONFIG_DATA_GET_PRIVATE(gobject);
|
2016-09-29 13:49:01 +02:00
|
|
|
|
|
|
|
|
g_free(priv->config_main_file);
|
|
|
|
|
g_free(priv->config_description);
|
|
|
|
|
|
|
|
|
|
g_free(priv->connectivity.uri);
|
|
|
|
|
g_free(priv->connectivity.response);
|
|
|
|
|
|
|
|
|
|
g_slist_free_full(priv->no_auto_default.specs, g_free);
|
|
|
|
|
g_slist_free_full(priv->no_auto_default.specs_config, g_free);
|
|
|
|
|
g_strfreev(priv->no_auto_default.arr);
|
|
|
|
|
|
|
|
|
|
g_free(priv->dns_mode);
|
|
|
|
|
g_free(priv->rc_manager);
|
|
|
|
|
|
|
|
|
|
g_slist_free_full(priv->ignore_carrier, g_free);
|
|
|
|
|
g_slist_free_full(priv->assume_ipv6ll_only, g_free);
|
|
|
|
|
|
|
|
|
|
nm_global_dns_config_free(priv->global_dns);
|
|
|
|
|
|
2020-11-27 16:15:41 +01:00
|
|
|
g_free(priv->iwd_config_path);
|
|
|
|
|
|
2016-09-29 13:49:01 +02:00
|
|
|
_match_section_infos_free(priv->connection_infos);
|
|
|
|
|
_match_section_infos_free(priv->device_infos);
|
|
|
|
|
|
|
|
|
|
g_key_file_unref(priv->keyfile);
|
|
|
|
|
if (priv->keyfile_user)
|
|
|
|
|
g_key_file_unref(priv->keyfile_user);
|
|
|
|
|
if (priv->keyfile_intern)
|
|
|
|
|
g_key_file_unref(priv->keyfile_intern);
|
|
|
|
|
|
|
|
|
|
G_OBJECT_CLASS(nm_config_data_parent_class)->finalize(gobject);
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-11 17:57:20 +02:00
|
|
|
static void
|
|
|
|
|
nm_config_data_class_init(NMConfigDataClass *config_class)
|
|
|
|
|
{
|
|
|
|
|
GObjectClass *object_class = G_OBJECT_CLASS(config_class);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2015-01-07 13:25:41 +01:00
|
|
|
object_class->constructed = constructed;
|
2014-07-11 17:57:20 +02:00
|
|
|
object_class->finalize = finalize;
|
|
|
|
|
object_class->get_property = get_property;
|
|
|
|
|
object_class->set_property = set_property;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2016-09-29 13:49:01 +02:00
|
|
|
obj_properties[PROP_CONFIG_MAIN_FILE] =
|
2015-01-06 20:16:10 +01:00
|
|
|
g_param_spec_string(NM_CONFIG_DATA_CONFIG_MAIN_FILE,
|
|
|
|
|
"",
|
|
|
|
|
"",
|
|
|
|
|
NULL,
|
|
|
|
|
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2016-09-29 13:49:01 +02:00
|
|
|
obj_properties[PROP_CONFIG_DESCRIPTION] =
|
2015-01-06 20:16:10 +01:00
|
|
|
g_param_spec_string(NM_CONFIG_DATA_CONFIG_DESCRIPTION,
|
|
|
|
|
"",
|
|
|
|
|
"",
|
|
|
|
|
NULL,
|
|
|
|
|
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2016-09-29 13:49:01 +02:00
|
|
|
obj_properties[PROP_KEYFILE_USER] =
|
|
|
|
|
g_param_spec_boxed(NM_CONFIG_DATA_KEYFILE_USER,
|
|
|
|
|
"",
|
|
|
|
|
"",
|
|
|
|
|
G_TYPE_KEY_FILE,
|
|
|
|
|
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2016-09-29 13:49:01 +02:00
|
|
|
obj_properties[PROP_KEYFILE_INTERN] =
|
|
|
|
|
g_param_spec_boxed(NM_CONFIG_DATA_KEYFILE_INTERN,
|
|
|
|
|
"",
|
|
|
|
|
"",
|
|
|
|
|
G_TYPE_KEY_FILE,
|
|
|
|
|
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-08-09 15:19:54 +08:00
|
|
|
obj_properties[PROP_CONNECTIVITY_ENABLED] =
|
|
|
|
|
g_param_spec_string(NM_CONFIG_DATA_CONNECTIVITY_ENABLED,
|
|
|
|
|
"",
|
|
|
|
|
"",
|
|
|
|
|
NULL,
|
|
|
|
|
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2016-09-29 13:49:01 +02:00
|
|
|
obj_properties[PROP_CONNECTIVITY_URI] =
|
2014-07-11 17:57:20 +02:00
|
|
|
g_param_spec_string(NM_CONFIG_DATA_CONNECTIVITY_URI,
|
|
|
|
|
"",
|
|
|
|
|
"",
|
|
|
|
|
NULL,
|
2016-09-29 13:49:01 +02:00
|
|
|
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2016-09-29 13:49:01 +02:00
|
|
|
obj_properties[PROP_CONNECTIVITY_INTERVAL] =
|
2014-07-11 17:57:20 +02:00
|
|
|
g_param_spec_uint(NM_CONFIG_DATA_CONNECTIVITY_INTERVAL,
|
|
|
|
|
"",
|
|
|
|
|
"",
|
|
|
|
|
0,
|
|
|
|
|
G_MAXUINT,
|
|
|
|
|
0,
|
2016-09-29 13:49:01 +02:00
|
|
|
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2024-06-12 14:20:21 -04:00
|
|
|
obj_properties[PROP_CONNECTIVITY_TIMEOUT] =
|
|
|
|
|
g_param_spec_uint(NM_CONFIG_DATA_CONNECTIVITY_TIMEOUT,
|
|
|
|
|
"",
|
|
|
|
|
"",
|
|
|
|
|
0,
|
|
|
|
|
G_MAXUINT,
|
|
|
|
|
0,
|
|
|
|
|
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
|
|
|
|
|
|
2016-09-29 13:49:01 +02:00
|
|
|
obj_properties[PROP_CONNECTIVITY_RESPONSE] =
|
2014-07-11 17:57:20 +02:00
|
|
|
g_param_spec_string(NM_CONFIG_DATA_CONNECTIVITY_RESPONSE,
|
|
|
|
|
"",
|
|
|
|
|
"",
|
|
|
|
|
NULL,
|
2016-09-29 13:49:01 +02:00
|
|
|
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2016-09-29 13:49:01 +02:00
|
|
|
obj_properties[PROP_NO_AUTO_DEFAULT] =
|
2015-01-07 17:09:52 +01:00
|
|
|
g_param_spec_boxed(NM_CONFIG_DATA_NO_AUTO_DEFAULT,
|
|
|
|
|
"",
|
|
|
|
|
"",
|
|
|
|
|
G_TYPE_STRV,
|
2016-09-29 13:49:01 +02:00
|
|
|
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2016-09-29 13:49:01 +02:00
|
|
|
g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties);
|
2014-07-11 17:57:20 +02:00
|
|
|
}
|
2024-03-13 20:52:37 +08:00
|
|
|
|
|
|
|
|
static NMGlobalDnsDomain *
|
|
|
|
|
nm_global_dns_domain_clone(NMGlobalDnsDomain *old_domain)
|
|
|
|
|
{
|
|
|
|
|
if (old_domain) {
|
|
|
|
|
NMGlobalDnsDomain *new_domain = g_malloc0(sizeof(NMGlobalDnsDomain));
|
|
|
|
|
new_domain->name = g_strdup(old_domain->name);
|
|
|
|
|
new_domain->servers = (char **) nm_strv_dup(old_domain->servers, -1, TRUE);
|
|
|
|
|
new_domain->options = (char **) nm_strv_dup(old_domain->options, -1, TRUE);
|
|
|
|
|
return new_domain;
|
|
|
|
|
} else {
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NMGlobalDnsConfig *
|
|
|
|
|
nm_global_dns_config_clone(NMGlobalDnsConfig *old_dns_config)
|
|
|
|
|
{
|
|
|
|
|
NMGlobalDnsConfig *new_dns_config;
|
|
|
|
|
gpointer key, value;
|
|
|
|
|
NMGlobalDnsDomain *old_domain;
|
|
|
|
|
GHashTableIter iter;
|
|
|
|
|
|
|
|
|
|
new_dns_config = g_malloc0(sizeof(NMGlobalDnsConfig));
|
|
|
|
|
new_dns_config->internal = TRUE;
|
|
|
|
|
|
|
|
|
|
if (old_dns_config) {
|
|
|
|
|
new_dns_config->internal = old_dns_config->internal;
|
|
|
|
|
new_dns_config->searches = nm_strv_dup(old_dns_config->searches, -1, TRUE);
|
|
|
|
|
new_dns_config->options = nm_strv_dup(old_dns_config->options, -1, TRUE);
|
|
|
|
|
new_dns_config->domains = g_hash_table_new_full(nm_str_hash,
|
|
|
|
|
g_str_equal,
|
|
|
|
|
g_free,
|
|
|
|
|
(GDestroyNotify) global_dns_domain_free);
|
|
|
|
|
if (old_dns_config->domains) {
|
|
|
|
|
g_hash_table_iter_init(&iter, old_dns_config->domains);
|
|
|
|
|
while (g_hash_table_iter_next(&iter, &key, &value)) {
|
|
|
|
|
old_domain = value;
|
|
|
|
|
g_hash_table_insert(new_dns_config->domains,
|
|
|
|
|
g_strdup(key),
|
|
|
|
|
nm_global_dns_domain_clone(old_domain));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
global_dns_config_seal_domains(new_dns_config);
|
|
|
|
|
}
|
|
|
|
|
return new_dns_config;
|
|
|
|
|
}
|