Commit 019943bb authored by Beniamino Galvani's avatar Beniamino Galvani

libnm-core: add dns-options property to NMSettingIPConfig

parent f628d0ad
......@@ -46,6 +46,24 @@
* related to IP addressing, routing, and Domain Name Service.
**/
const DNSOptionDesc dns_option_descs[] = {
{ NM_SETTING_DNS_OPTION_DEBUG, FALSE, FALSE },
{ NM_SETTING_DNS_OPTION_NDOTS, TRUE, FALSE },
{ NM_SETTING_DNS_OPTION_TIMEOUT, TRUE, FALSE },
{ NM_SETTING_DNS_OPTION_ATTEMPTS, TRUE, FALSE },
{ NM_SETTING_DNS_OPTION_ROTATE, FALSE, FALSE },
{ NM_SETTING_DNS_OPTION_NO_CHECK_NAMES, FALSE, FALSE },
{ NM_SETTING_DNS_OPTION_INET6, FALSE, TRUE },
{ NM_SETTING_DNS_OPTION_IP6_BYTESTRING, FALSE, TRUE },
{ NM_SETTING_DNS_OPTION_IP6_DOTINT, FALSE, TRUE },
{ NM_SETTING_DNS_OPTION_NO_IP6_DOTINT, FALSE, TRUE },
{ NM_SETTING_DNS_OPTION_EDNS0, FALSE, FALSE },
{ NM_SETTING_DNS_OPTION_SINGLE_REQUEST, FALSE, FALSE },
{ NM_SETTING_DNS_OPTION_SINGLE_REQUEST_REOPEN, FALSE, FALSE },
{ NM_SETTING_DNS_OPTION_NO_TLD_QUERY, FALSE, FALSE },
{ NULL, FALSE, FALSE }
};
static char *
canonicalize_ip (int family, const char *ip, gboolean null_any)
{
......@@ -1062,6 +1080,7 @@ typedef struct {
char *method;
GPtrArray *dns; /* array of IP address strings */
GPtrArray *dns_search; /* array of domain name strings */
GPtrArray *dns_options;/* array of DNS options */
GPtrArray *addresses; /* array of NMIPAddress */
GPtrArray *routes; /* array of NMIPRoute */
gint64 route_metric;
......@@ -1079,6 +1098,7 @@ enum {
PROP_METHOD,
PROP_DNS,
PROP_DNS_SEARCH,
PROP_DNS_OPTIONS,
PROP_ADDRESSES,
PROP_GATEWAY,
PROP_ROUTES,
......@@ -1393,6 +1413,182 @@ nm_setting_ip_config_clear_dns_searches (NMSettingIPConfig *setting)
g_object_notify (G_OBJECT (setting), NM_SETTING_IP_CONFIG_DNS_SEARCH);
}
/**
* nm_setting_ip_config_get_num_dns_options:
* @setting: the #NMSettingIPConfig
*
* Returns: the number of configured DNS options
*
* Since: 1.2
**/
guint
nm_setting_ip_config_get_num_dns_options (NMSettingIPConfig *setting)
{
g_return_val_if_fail (NM_IS_SETTING_IP_CONFIG (setting), 0);
return NM_SETTING_IP_CONFIG_GET_PRIVATE (setting)->dns_options->len;
}
/**
* nm_setting_ip_config_get_dns_option:
* @setting: the #NMSettingIPConfig
* @i: index number of the DNS option
*
* Returns: the DNS option at index @i
*
* Since: 1.2
**/
const char *
nm_setting_ip_config_get_dns_option (NMSettingIPConfig *setting, guint i)
{
NMSettingIPConfigPrivate *priv;
g_return_val_if_fail (NM_IS_SETTING_IP_CONFIG (setting), NULL);
priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting);
g_return_val_if_fail (i < priv->dns_options->len, NULL);
return priv->dns_options->pdata[i];
}
/**
* nm_setting_ip_config_next_valid_dns_option
* @setting: the #NMSettingIPConfig
* @i: index to start the search from
*
* Returns: the index, greater or equal than @i, of the first valid
* DNS option, or -1 if no valid option is found
*
* Since: 1.2
**/
gint
nm_setting_ip_config_next_valid_dns_option (NMSettingIPConfig *setting, guint i)
{
NMSettingIPConfigPrivate *priv;
g_return_val_if_fail (NM_IS_SETTING_IP_CONFIG (setting), -1);
priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting);
for (; i < priv->dns_options->len; i++) {
if (_nm_utils_dns_option_validate (priv->dns_options->pdata[i], NULL, NULL,
NM_IS_SETTING_IP6_CONFIG (setting),
dns_option_descs))
return i;
}
return -1;
}
/**
* nm_setting_ip_config_add_dns_option:
* @setting: the #NMSettingIPConfig
* @dns_option: the DNS option to add
*
* Adds a new DNS option to the setting.
*
* Returns: %TRUE if the DNS option was added; %FALSE otherwise
*
* Since: 1.2
**/
gboolean
nm_setting_ip_config_add_dns_option (NMSettingIPConfig *setting,
const char *dns_option)
{
NMSettingIPConfigPrivate *priv;
g_return_val_if_fail (NM_IS_SETTING_IP_CONFIG (setting), FALSE);
g_return_val_if_fail (dns_option != NULL, FALSE);
g_return_val_if_fail (dns_option[0] != '\0', FALSE);
if (!_nm_utils_dns_option_validate (dns_option, NULL, NULL, FALSE, NULL))
return FALSE;
priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting);
if (_nm_utils_dns_option_find_idx (priv->dns_options, dns_option) >= 0)
return FALSE;
g_ptr_array_add (priv->dns_options, g_strdup (dns_option));
g_object_notify (G_OBJECT (setting), NM_SETTING_IP_CONFIG_DNS_OPTIONS);
return TRUE;
}
/**
* nm_setting_ip_config_remove_dns_option:
* @setting: the #NMSettingIPConfig
* @i: index number of the DNS option
*
* Removes the DNS option at index @i.
*
* Since: 1.2
**/
void
nm_setting_ip_config_remove_dns_option (NMSettingIPConfig *setting, int i)
{
NMSettingIPConfigPrivate *priv;
g_return_if_fail (NM_IS_SETTING_IP_CONFIG (setting));
priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting);
g_return_if_fail (i < priv->dns_options->len);
g_ptr_array_remove_index (priv->dns_options, i);
g_object_notify (G_OBJECT (setting), NM_SETTING_IP_CONFIG_DNS_OPTIONS);
}
/**
* nm_setting_ip_config_remove_dns_option_by_value:
* @setting: the #NMSettingIPConfig
* @dns_option: the DNS option to remove
*
* Removes the DNS option @dns_option.
*
* Returns: %TRUE if the DNS option was found and removed; %FALSE if it was not.
*
* Since: 1.2
**/
gboolean
nm_setting_ip_config_remove_dns_option_by_value (NMSettingIPConfig *setting,
const char *dns_option)
{
NMSettingIPConfigPrivate *priv;
int i;
g_return_val_if_fail (NM_IS_SETTING_IP_CONFIG (setting), FALSE);
g_return_val_if_fail (dns_option != NULL, FALSE);
g_return_val_if_fail (dns_option[0] != '\0', FALSE);
priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting);
i = _nm_utils_dns_option_find_idx (priv->dns_options, dns_option);
if (i >= 0) {
g_ptr_array_remove_index (priv->dns_options, i);
g_object_notify (G_OBJECT (setting), NM_SETTING_IP_CONFIG_DNS_OPTIONS);
return TRUE;
}
return FALSE;
}
/**
* nm_setting_ip_config_clear_dns_options:
* @setting: the #NMSettingIPConfig
*
* Removes all configured DNS options.
*
* Since: 1.2
**/
void
nm_setting_ip_config_clear_dns_options (NMSettingIPConfig *setting)
{
NMSettingIPConfigPrivate *priv;
g_return_if_fail (NM_IS_SETTING_IP_CONFIG (setting));
priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting);
g_ptr_array_set_size (priv->dns_options, 0);
g_object_notify (G_OBJECT (setting), NM_SETTING_IP_CONFIG_DNS_OPTIONS);
}
/**
* nm_setting_ip_config_get_num_addresses:
* @setting: the #NMSettingIPConfig
......@@ -1959,6 +2155,7 @@ nm_setting_ip_config_init (NMSettingIPConfig *setting)
priv->dns = g_ptr_array_new_with_free_func (g_free);
priv->dns_search = g_ptr_array_new_with_free_func (g_free);
priv->dns_options = g_ptr_array_new_with_free_func (g_free);
priv->addresses = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_ip_address_unref);
priv->routes = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_ip_route_unref);
}
......@@ -1975,6 +2172,7 @@ finalize (GObject *object)
g_ptr_array_unref (priv->dns);
g_ptr_array_unref (priv->dns_search);
g_ptr_array_unref (priv->dns_options);
g_ptr_array_unref (priv->addresses);
g_ptr_array_unref (priv->routes);
......@@ -1988,6 +2186,8 @@ set_property (GObject *object, guint prop_id,
NMSettingIPConfig *setting = NM_SETTING_IP_CONFIG (object);
NMSettingIPConfigPrivate *priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting);
const char *gateway;
char **strv;
int i;
switch (prop_id) {
case PROP_METHOD:
......@@ -2002,6 +2202,16 @@ set_property (GObject *object, guint prop_id,
g_ptr_array_unref (priv->dns_search);
priv->dns_search = _nm_utils_strv_to_ptrarray (g_value_get_boxed (value));
break;
case PROP_DNS_OPTIONS:
strv = g_value_get_boxed (value);
g_ptr_array_unref (priv->dns_options);
priv->dns_options = g_ptr_array_new_with_free_func (g_free);
for (i = 0; strv && strv[i]; i++) {
if ( _nm_utils_dns_option_validate (strv[i], NULL, NULL, FALSE, NULL)
&& _nm_utils_dns_option_find_idx (priv->dns_options, strv[i]) < 0)
g_ptr_array_add (priv->dns_options, g_strdup (strv[i]));
}
break;
case PROP_ADDRESSES:
g_ptr_array_unref (priv->addresses);
priv->addresses = _nm_utils_copy_array (g_value_get_boxed (value),
......@@ -2065,6 +2275,9 @@ get_property (GObject *object, guint prop_id,
case PROP_DNS_SEARCH:
g_value_take_boxed (value, _nm_utils_ptrarray_to_strv (priv->dns_search));
break;
case PROP_DNS_OPTIONS:
g_value_take_boxed (value, _nm_utils_ptrarray_to_strv (priv->dns_options));
break;
case PROP_ADDRESSES:
g_value_take_boxed (value, _nm_utils_copy_array (priv->addresses,
(NMUtilsCopyFunc) nm_ip_address_dup,
......@@ -2184,6 +2397,20 @@ nm_setting_ip_config_class_init (NMSettingIPConfigClass *setting_class)
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS));
/**
* NMSettingIPConfig:dns-options:
*
* Array of DNS options.
*
* Since: 1.2
**/
g_object_class_install_property
(object_class, PROP_DNS_OPTIONS,
g_param_spec_boxed (NM_SETTING_IP_CONFIG_DNS_OPTIONS, "", "",
G_TYPE_STRV,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS));
/**
* NMSettingIPConfig:addresses:
*
......
......@@ -133,6 +133,7 @@ void nm_ip_route_set_attribute (NMIPRoute *route,
#define NM_SETTING_IP_CONFIG_METHOD "method"
#define NM_SETTING_IP_CONFIG_DNS "dns"
#define NM_SETTING_IP_CONFIG_DNS_SEARCH "dns-search"
#define NM_SETTING_IP_CONFIG_DNS_OPTIONS "dns-options"
#define NM_SETTING_IP_CONFIG_ADDRESSES "addresses"
#define NM_SETTING_IP_CONFIG_GATEWAY "gateway"
#define NM_SETTING_IP_CONFIG_ROUTES "routes"
......@@ -144,6 +145,29 @@ void nm_ip_route_set_attribute (NMIPRoute *route,
#define NM_SETTING_IP_CONFIG_NEVER_DEFAULT "never-default"
#define NM_SETTING_IP_CONFIG_MAY_FAIL "may-fail"
typedef struct {
const char *name;
gboolean numeric;
gboolean ipv6_only;
} DNSOptionDesc;
extern const DNSOptionDesc dns_option_descs[];
#define NM_SETTING_DNS_OPTION_DEBUG "debug"
#define NM_SETTING_DNS_OPTION_NDOTS "ndots"
#define NM_SETTING_DNS_OPTION_TIMEOUT "timeout"
#define NM_SETTING_DNS_OPTION_ATTEMPTS "attempts"
#define NM_SETTING_DNS_OPTION_ROTATE "rotate"
#define NM_SETTING_DNS_OPTION_NO_CHECK_NAMES "no-check-names"
#define NM_SETTING_DNS_OPTION_INET6 "inet6"
#define NM_SETTING_DNS_OPTION_IP6_BYTESTRING "ip6-bytestring"
#define NM_SETTING_DNS_OPTION_IP6_DOTINT "ip6-dotint"
#define NM_SETTING_DNS_OPTION_NO_IP6_DOTINT "no-ip6-dotint"
#define NM_SETTING_DNS_OPTION_EDNS0 "edns0"
#define NM_SETTING_DNS_OPTION_SINGLE_REQUEST "single-request"
#define NM_SETTING_DNS_OPTION_SINGLE_REQUEST_REOPEN "single-request-reopen"
#define NM_SETTING_DNS_OPTION_NO_TLD_QUERY "no-tld-query"
struct _NMSettingIPConfig {
NMSetting parent;
};
......@@ -181,6 +205,19 @@ gboolean nm_setting_ip_config_remove_dns_search_by_value (NMSettingIPConfig
const char *dns_search);
void nm_setting_ip_config_clear_dns_searches (NMSettingIPConfig *setting);
guint nm_setting_ip_config_get_num_dns_options (NMSettingIPConfig *setting);
const char *nm_setting_ip_config_get_dns_option (NMSettingIPConfig *setting,
guint i);
gint nm_setting_ip_config_next_valid_dns_option (NMSettingIPConfig *setting,
guint i);
gboolean nm_setting_ip_config_add_dns_option (NMSettingIPConfig *setting,
const char *dns_option);
void nm_setting_ip_config_remove_dns_option (NMSettingIPConfig *setting,
int i);
gboolean nm_setting_ip_config_remove_dns_option_by_value (NMSettingIPConfig *setting,
const char *dns_option);
void nm_setting_ip_config_clear_dns_options (NMSettingIPConfig *setting);
guint nm_setting_ip_config_get_num_addresses (NMSettingIPConfig *setting);
NMIPAddress *nm_setting_ip_config_get_address (NMSettingIPConfig *setting,
int i);
......
......@@ -22,10 +22,16 @@
#define __NM_UTILS_PRIVATE_H__
#include "nm-setting-private.h"
#include "nm-setting-ip-config.h"
gboolean _nm_utils_string_slist_validate (GSList *list,
const char **valid_values);
gboolean _nm_utils_dns_option_validate (const char *option, char **out_name,
long *out_value, gboolean ipv6,
const DNSOptionDesc *option_descs);
int _nm_utils_dns_option_find_idx (GPtrArray *array, const char *option);
/* D-Bus transform funcs */
GVariant * _nm_utils_hwaddr_to_dbus (const GValue *prop_value);
......
......@@ -3404,3 +3404,130 @@ _nm_utils_ascii_str_to_int64 (const char *str, guint base, gint64 min, gint64 ma
return v;
}
static gboolean
validate_dns_option (const char *name, gboolean numeric, gboolean ipv6,
const DNSOptionDesc *option_descs)
{
const DNSOptionDesc *desc;
if (!option_descs)
return !!*name;
for (desc = option_descs; desc->name; desc++) {
if (!strcmp (name, desc->name) &&
numeric == desc->numeric &&
(!desc->ipv6_only || ipv6))
return TRUE;
}
return FALSE;
}
/**
* _nm_utils_dns_option_validate
* @option: option string
* @out_name: (out) (allow-none) the option name
* @out_value: (out) (allow-none) the option value
* @ipv6: whether the option refers to a IPv6 configuration
* @option_descs: (allow-none) an array of DNSOptionDesc which describes the
* valid options
*
* Parses a DNS option in the form "name" or "name:number" and, if
* @option_descs is not NULL, checks that the option conforms to one
* of the provided descriptors. If @option_descs is NULL @ipv6 is
* not considered.
*
* Returns: %TRUE when the parsing was successful and the option is valid,
* %FALSE otherwise
*/
gboolean
_nm_utils_dns_option_validate (const char *option, char **out_name,
long *out_value, gboolean ipv6,
const DNSOptionDesc *option_descs)
{
char **tokens, *ptr;
gboolean ret = FALSE;
g_return_val_if_fail (option != NULL, FALSE);
if (out_name)
*out_name = NULL;
if (out_value)
*out_value = -1;
if (!option[0])
return FALSE;
tokens = g_strsplit (option, ":", 2);
if (g_strv_length (tokens) == 1) {
ret = validate_dns_option (tokens[0], FALSE, ipv6, option_descs);
if (ret && out_name)
*out_name = g_strdup (tokens[0]);
goto out;
}
if (!tokens[1][0]) {
ret = FALSE;
goto out;
}
for (ptr = tokens[1]; *ptr; ptr++) {
if (!g_ascii_isdigit (*ptr)) {
ret = FALSE;
goto out;
}
}
ret = FALSE;
if (validate_dns_option (tokens[0], TRUE, ipv6, option_descs)) {
int value = _nm_utils_ascii_str_to_int64 (tokens[1], 10, 0, G_MAXINT32, -1);
if (value >= 0) {
if (out_name)
*out_name = g_strdup (tokens[0]);
if (out_value)
*out_value = value;
ret = TRUE;
}
}
out:
g_strfreev (tokens);
return ret;
}
/**
* _nm_utils_dns_option_find_idx
* @array: an array of strings
* @option: a dns option string
*
* Searches for an option in an array of strings. The match is
* performed only the option name; the option value is ignored.
*
* Returns: the index of the option in the array or -1 if was not
* found.
*/
int _nm_utils_dns_option_find_idx (GPtrArray *array, const char *option)
{
gboolean ret;
char *option_name, *tmp_name;
int i;
if (!_nm_utils_dns_option_validate (option, &option_name, NULL, FALSE, NULL))
return -1;
for (i = 0; i < array->len; i++) {
if (_nm_utils_dns_option_validate (array->pdata[i], &tmp_name, NULL, FALSE, NULL)) {
ret = strcmp (tmp_name, option_name);
g_free (tmp_name);
if (!ret) {
g_free (option_name);
return i;
}
}
}
g_free (option_name);
return -1;
}
......@@ -1985,6 +1985,7 @@ test_connection_diff_a_only (void)
{ NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_DIFF_RESULT_IN_A },
{ NM_SETTING_IP_CONFIG_DNS, NM_SETTING_DIFF_RESULT_IN_A },
{ NM_SETTING_IP_CONFIG_DNS_SEARCH, NM_SETTING_DIFF_RESULT_IN_A },
{ NM_SETTING_IP_CONFIG_DNS_OPTIONS, NM_SETTING_DIFF_RESULT_IN_A },
{ NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_DIFF_RESULT_IN_A },
{ NM_SETTING_IP_CONFIG_GATEWAY, NM_SETTING_DIFF_RESULT_IN_A },
{ NM_SETTING_IP_CONFIG_ROUTES, NM_SETTING_DIFF_RESULT_IN_A },
......@@ -2884,6 +2885,13 @@ test_setting_ip4_changed_signal (void)
nm_setting_ip_config_add_route (s_ip4, route);
ASSERT_CHANGED (nm_setting_ip_config_clear_routes (s_ip4));
ASSERT_CHANGED (nm_setting_ip_config_add_dns_option (s_ip4, "debug"));
ASSERT_CHANGED (nm_setting_ip_config_remove_dns_option (s_ip4, 0));
g_test_expect_message ("libnm", G_LOG_LEVEL_CRITICAL, "*i < priv->dns_options->len*");
ASSERT_UNCHANGED (nm_setting_ip_config_remove_dns_option (s_ip4, 1));
g_test_assert_expected_messages ();
nm_ip_address_unref (addr);
nm_ip_route_unref (route);
g_object_unref (connection);
......
......@@ -552,16 +552,19 @@ global:
nm_setting_ip6_config_privacy_get_type;
nm_setting_ip_config_add_address;
nm_setting_ip_config_add_dns;
nm_setting_ip_config_add_dns_option;
nm_setting_ip_config_add_dns_search;
nm_setting_ip_config_add_route;
nm_setting_ip_config_clear_addresses;
nm_setting_ip_config_clear_dns;
nm_setting_ip_config_clear_dns_options;
nm_setting_ip_config_clear_dns_searches;
nm_setting_ip_config_clear_routes;
nm_setting_ip_config_get_address;
nm_setting_ip_config_get_dhcp_hostname;
nm_setting_ip_config_get_dhcp_send_hostname;
nm_setting_ip_config_get_dns;
nm_setting_ip_config_get_dns_option;
nm_setting_ip_config_get_dns_search;
nm_setting_ip_config_get_gateway;
nm_setting_ip_config_get_ignore_auto_dns;
......@@ -571,6 +574,7 @@ global:
nm_setting_ip_config_get_never_default;
nm_setting_ip_config_get_num_addresses;
nm_setting_ip_config_get_num_dns;
nm_setting_ip_config_get_num_dns_options;
nm_setting_ip_config_get_num_dns_searches;
nm_setting_ip_config_get_num_routes;
nm_setting_ip_config_get_route;
......@@ -580,6 +584,8 @@ global:
nm_setting_ip_config_remove_address_by_value;
nm_setting_ip_config_remove_dns;
nm_setting_ip_config_remove_dns_by_value;
nm_setting_ip_config_remove_dns_option;
nm_setting_ip_config_remove_dns_option_by_value;
nm_setting_ip_config_remove_dns_search;
nm_setting_ip_config_remove_dns_search_by_value;
nm_setting_ip_config_remove_route;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment