summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBeniamino Galvani <bgalvani@redhat.com>2015-05-13 17:17:06 +0200
committerBeniamino Galvani <bgalvani@redhat.com>2015-05-13 17:17:06 +0200
commita3b7bc9cc69f83781f2454270620eec6d3596112 (patch)
tree8e14bc2b5c88bc5d8c1922d55a905cbf53ae0cb4
parentf628d0ad5a7b6cd2d6dd084704fac294826be784 (diff)
parent58236b0ab2d2a48eb11e8267bb2fe038bb6f382c (diff)
downloadNetworkManager-a3b7bc9cc69f83781f2454270620eec6d3596112.tar.gz
dns: merge branch 'bg/dns-options-rh1200131'
https://bugzilla.redhat.com/show_bug.cgi?id=1200131
-rw-r--r--clients/cli/settings.c184
-rw-r--r--introspection/nm-ip4-config.xml7
-rw-r--r--introspection/nm-ip6-config.xml7
-rw-r--r--libnm-core/nm-setting-ip-config.c307
-rw-r--r--libnm-core/nm-setting-ip-config.h53
-rw-r--r--libnm-core/nm-utils-private.h6
-rw-r--r--libnm-core/nm-utils.c127
-rw-r--r--libnm-core/tests/test-general.c112
-rw-r--r--libnm/libnm.ver6
-rw-r--r--src/NetworkManagerUtils.c50
-rw-r--r--src/NetworkManagerUtils.h1
-rw-r--r--src/dns-manager/nm-dns-manager.c62
-rw-r--r--src/nm-ip4-config.c167
-rw-r--r--src/nm-ip4-config.h10
-rw-r--r--src/nm-ip6-config.c167
-rw-r--r--src/nm-ip6-config.h9
-rw-r--r--src/settings/plugins/ifcfg-rh/reader.c44
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-dns-options15
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c161
-rw-r--r--src/settings/plugins/ifcfg-rh/writer.c59
-rw-r--r--src/tests/test-resolvconf-capture.c102
21 files changed, 1530 insertions, 126 deletions
diff --git a/clients/cli/settings.c b/clients/cli/settings.c
index a255fb38a2..3c8a86c79e 100644
--- a/clients/cli/settings.c
+++ b/clients/cli/settings.c
@@ -259,23 +259,25 @@ NmcOutputField nmc_fields_setting_ip4_config[] = {
SETTING_FIELD (NM_SETTING_IP_CONFIG_METHOD, 10), /* 1 */
SETTING_FIELD (NM_SETTING_IP_CONFIG_DNS, 20), /* 2 */
SETTING_FIELD (NM_SETTING_IP_CONFIG_DNS_SEARCH, 15), /* 3 */
- SETTING_FIELD (NM_SETTING_IP_CONFIG_ADDRESSES, 20), /* 4 */
- SETTING_FIELD (NM_SETTING_IP_CONFIG_GATEWAY, 20), /* 5 */
- SETTING_FIELD (NM_SETTING_IP_CONFIG_ROUTES, 20), /* 6 */
- SETTING_FIELD (NM_SETTING_IP_CONFIG_ROUTE_METRIC, 15), /* 7 */
- SETTING_FIELD (NM_SETTING_IP_CONFIG_IGNORE_AUTO_ROUTES, 19), /* 8 */
- SETTING_FIELD (NM_SETTING_IP_CONFIG_IGNORE_AUTO_DNS, 16), /* 9 */
- SETTING_FIELD (NM_SETTING_IP4_CONFIG_DHCP_CLIENT_ID, 15), /* 10 */
- SETTING_FIELD (NM_SETTING_IP_CONFIG_DHCP_SEND_HOSTNAME, 19), /* 11 */
- SETTING_FIELD (NM_SETTING_IP_CONFIG_DHCP_HOSTNAME, 14), /* 12 */
- SETTING_FIELD (NM_SETTING_IP_CONFIG_NEVER_DEFAULT, 15), /* 13 */
- SETTING_FIELD (NM_SETTING_IP_CONFIG_MAY_FAIL, 12), /* 14 */
+ SETTING_FIELD (NM_SETTING_IP_CONFIG_DNS_OPTIONS, 15), /* 4 */
+ SETTING_FIELD (NM_SETTING_IP_CONFIG_ADDRESSES, 20), /* 5 */
+ SETTING_FIELD (NM_SETTING_IP_CONFIG_GATEWAY, 20), /* 6 */
+ SETTING_FIELD (NM_SETTING_IP_CONFIG_ROUTES, 20), /* 7 */
+ SETTING_FIELD (NM_SETTING_IP_CONFIG_ROUTE_METRIC, 15), /* 8 */
+ SETTING_FIELD (NM_SETTING_IP_CONFIG_IGNORE_AUTO_ROUTES, 19), /* 9 */
+ SETTING_FIELD (NM_SETTING_IP_CONFIG_IGNORE_AUTO_DNS, 16), /* 10 */
+ SETTING_FIELD (NM_SETTING_IP4_CONFIG_DHCP_CLIENT_ID, 15), /* 11 */
+ SETTING_FIELD (NM_SETTING_IP_CONFIG_DHCP_SEND_HOSTNAME, 19), /* 12 */
+ SETTING_FIELD (NM_SETTING_IP_CONFIG_DHCP_HOSTNAME, 14), /* 13 */
+ SETTING_FIELD (NM_SETTING_IP_CONFIG_NEVER_DEFAULT, 15), /* 14 */
+ SETTING_FIELD (NM_SETTING_IP_CONFIG_MAY_FAIL, 12), /* 15 */
{NULL, NULL, 0, NULL, FALSE, FALSE, 0}
};
#define NMC_FIELDS_SETTING_IP4_CONFIG_ALL "name"","\
NM_SETTING_IP_CONFIG_METHOD","\
NM_SETTING_IP_CONFIG_DNS","\
NM_SETTING_IP_CONFIG_DNS_SEARCH","\
+ NM_SETTING_IP_CONFIG_DNS_OPTIONS","\
NM_SETTING_IP_CONFIG_ADDRESSES","\
NM_SETTING_IP_CONFIG_GATEWAY","\
NM_SETTING_IP_CONFIG_ROUTES","\
@@ -295,23 +297,25 @@ NmcOutputField nmc_fields_setting_ip6_config[] = {
SETTING_FIELD (NM_SETTING_IP_CONFIG_METHOD, 10), /* 1 */
SETTING_FIELD (NM_SETTING_IP_CONFIG_DNS, 20), /* 2 */
SETTING_FIELD (NM_SETTING_IP_CONFIG_DNS_SEARCH, 15), /* 3 */
- SETTING_FIELD (NM_SETTING_IP_CONFIG_ADDRESSES, 20), /* 4 */
- SETTING_FIELD (NM_SETTING_IP_CONFIG_GATEWAY, 20), /* 5 */
- SETTING_FIELD (NM_SETTING_IP_CONFIG_ROUTES, 20), /* 6 */
- SETTING_FIELD (NM_SETTING_IP_CONFIG_ROUTE_METRIC, 15), /* 7 */
- SETTING_FIELD (NM_SETTING_IP_CONFIG_IGNORE_AUTO_ROUTES, 19), /* 8 */
- SETTING_FIELD (NM_SETTING_IP_CONFIG_IGNORE_AUTO_DNS, 16), /* 9 */
- SETTING_FIELD (NM_SETTING_IP_CONFIG_NEVER_DEFAULT, 15), /* 10 */
- SETTING_FIELD (NM_SETTING_IP_CONFIG_MAY_FAIL, 12), /* 11 */
- SETTING_FIELD (NM_SETTING_IP6_CONFIG_IP6_PRIVACY, 15), /* 12 */
- SETTING_FIELD (NM_SETTING_IP_CONFIG_DHCP_SEND_HOSTNAME, 19), /* 13 */
- SETTING_FIELD (NM_SETTING_IP_CONFIG_DHCP_HOSTNAME, 14), /* 14 */
+ SETTING_FIELD (NM_SETTING_IP_CONFIG_DNS_OPTIONS, 15), /* 4 */
+ SETTING_FIELD (NM_SETTING_IP_CONFIG_ADDRESSES, 20), /* 5 */
+ SETTING_FIELD (NM_SETTING_IP_CONFIG_GATEWAY, 20), /* 6 */
+ SETTING_FIELD (NM_SETTING_IP_CONFIG_ROUTES, 20), /* 7 */
+ SETTING_FIELD (NM_SETTING_IP_CONFIG_ROUTE_METRIC, 15), /* 8 */
+ SETTING_FIELD (NM_SETTING_IP_CONFIG_IGNORE_AUTO_ROUTES, 19), /* 9 */
+ SETTING_FIELD (NM_SETTING_IP_CONFIG_IGNORE_AUTO_DNS, 16), /* 10 */
+ SETTING_FIELD (NM_SETTING_IP_CONFIG_NEVER_DEFAULT, 15), /* 11 */
+ SETTING_FIELD (NM_SETTING_IP_CONFIG_MAY_FAIL, 12), /* 12 */
+ SETTING_FIELD (NM_SETTING_IP6_CONFIG_IP6_PRIVACY, 15), /* 13 */
+ SETTING_FIELD (NM_SETTING_IP_CONFIG_DHCP_SEND_HOSTNAME, 19), /* 14 */
+ SETTING_FIELD (NM_SETTING_IP_CONFIG_DHCP_HOSTNAME, 14), /* 15 */
{NULL, NULL, 0, NULL, FALSE, FALSE, 0}
};
#define NMC_FIELDS_SETTING_IP6_CONFIG_ALL "name"","\
NM_SETTING_IP_CONFIG_METHOD","\
NM_SETTING_IP_CONFIG_DNS","\
NM_SETTING_IP_CONFIG_DNS_SEARCH","\
+ NM_SETTING_IP_CONFIG_DNS_OPTIONS","\
NM_SETTING_IP_CONFIG_ADDRESSES","\
NM_SETTING_IP_CONFIG_GATEWAY","\
NM_SETTING_IP_CONFIG_ROUTES","\
@@ -1221,6 +1225,7 @@ DEFINE_GETTER (nmc_property_ib_get_parent, NM_SETTING_INFINIBAND_PARENT)
DEFINE_GETTER (nmc_property_ipv4_get_method, NM_SETTING_IP_CONFIG_METHOD)
DEFINE_GETTER (nmc_property_ipv4_get_dns, NM_SETTING_IP_CONFIG_DNS)
DEFINE_GETTER (nmc_property_ipv4_get_dns_search, NM_SETTING_IP_CONFIG_DNS_SEARCH)
+DEFINE_GETTER (nmc_property_ipv4_get_dns_options, NM_SETTING_IP_CONFIG_DNS_OPTIONS)
static char *
nmc_property_ip_get_addresses (NMSetting *setting)
@@ -1298,6 +1303,7 @@ DEFINE_GETTER (nmc_property_ipv4_get_may_fail, NM_SETTING_IP_CONFIG_MAY_FAIL)
DEFINE_GETTER (nmc_property_ipv6_get_method, NM_SETTING_IP_CONFIG_METHOD)
DEFINE_GETTER (nmc_property_ipv6_get_dns, NM_SETTING_IP_CONFIG_DNS)
DEFINE_GETTER (nmc_property_ipv6_get_dns_search, NM_SETTING_IP_CONFIG_DNS_SEARCH)
+DEFINE_GETTER (nmc_property_ipv6_get_dns_options, NM_SETTING_IP_CONFIG_DNS_OPTIONS)
static char *
nmc_property_ipv6_get_routes (NMSetting *setting)
@@ -3294,6 +3300,43 @@ DEFINE_REMOVER_INDEX_OR_VALUE (nmc_property_ipv4_remove_dns_search,
nm_setting_ip_config_remove_dns_search,
_validate_and_remove_ipv4_dns_search)
+/* 'dns-options' */
+static gboolean
+nmc_property_ipv4_set_dns_options (NMSetting *setting, const char *prop, const char *val, GError **error)
+{
+ char **strv = NULL;
+ guint i = 0;
+
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+ strv = nmc_strsplit_set (val, " \t,", 0);
+ while (strv && strv[i])
+ nm_setting_ip_config_add_dns_option (NM_SETTING_IP_CONFIG (setting), strv[i++]);
+ g_strfreev (strv);
+
+ return TRUE;
+}
+
+static gboolean
+_validate_and_remove_ipv4_dns_option (NMSettingIPConfig *setting,
+ const char *dns_option,
+ GError **error)
+{
+ gboolean ret;
+
+ ret = nm_setting_ip_config_remove_dns_option_by_value (setting, dns_option);
+ if (!ret)
+ g_set_error (error, 1, 0,
+ _("the property doesn't contain DNS option '%s'"),
+ dns_option);
+ return ret;
+}
+DEFINE_REMOVER_INDEX_OR_VALUE (nmc_property_ipv4_remove_dns_option,
+ NM_SETTING_IP_CONFIG,
+ nm_setting_ip_config_get_num_dns_options,
+ nm_setting_ip_config_remove_dns_option,
+ _validate_and_remove_ipv4_dns_option)
+
/* 'addresses' */
static NMIPAddress *
_parse_ipv4_address (const char *address, GError **error)
@@ -3601,6 +3644,43 @@ DEFINE_REMOVER_INDEX_OR_VALUE (nmc_property_ipv6_remove_dns_search,
nm_setting_ip_config_remove_dns_search,
_validate_and_remove_ipv6_dns_search)
+/* 'dns-options' */
+static gboolean
+nmc_property_ipv6_set_dns_options (NMSetting *setting, const char *prop, const char *val, GError **error)
+{
+ char **strv = NULL;
+ guint i = 0;
+
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+ strv = nmc_strsplit_set (val, " \t,", 0);
+ while (strv && strv[i])
+ nm_setting_ip_config_add_dns_option (NM_SETTING_IP_CONFIG (setting), strv[i++]);
+ g_strfreev (strv);
+
+ return TRUE;
+}
+
+static gboolean
+_validate_and_remove_ipv6_dns_option (NMSettingIPConfig *setting,
+ const char *dns_option,
+ GError **error)
+{
+ gboolean ret;
+
+ ret = nm_setting_ip_config_remove_dns_option_by_value (setting, dns_option);
+ if (!ret)
+ g_set_error (error, 1, 0,
+ _("the property doesn't contain DNS option '%s'"),
+ dns_option);
+ return ret;
+}
+DEFINE_REMOVER_INDEX_OR_VALUE (nmc_property_ipv6_remove_dns_option,
+ NM_SETTING_IP_CONFIG,
+ nm_setting_ip_config_get_num_dns_options,
+ nm_setting_ip_config_remove_dns_option,
+ _validate_and_remove_ipv6_dns_option)
+
/* 'addresses' */
static NMIPAddress *
_parse_ipv6_address (const char *address, GError **error)
@@ -5543,6 +5623,13 @@ nmc_properties_init (void)
NULL,
NULL,
NULL);
+ nmc_add_prop_funcs (GLUE_IP (4, DNS_OPTIONS),
+ nmc_property_ipv4_get_dns_options,
+ nmc_property_ipv4_set_dns_options,
+ nmc_property_ipv4_remove_dns_option,
+ NULL,
+ NULL,
+ NULL);
nmc_add_prop_funcs (GLUE_IP (4, ADDRESSES),
nmc_property_ip_get_addresses,
nmc_property_ipv4_set_addresses,
@@ -5643,6 +5730,13 @@ nmc_properties_init (void)
NULL,
NULL,
NULL);
+ nmc_add_prop_funcs (GLUE_IP (6, DNS_OPTIONS),
+ nmc_property_ipv6_get_dns_options,
+ nmc_property_ipv6_set_dns_options,
+ nmc_property_ipv6_remove_dns_option,
+ NULL,
+ NULL,
+ NULL);
nmc_add_prop_funcs (GLUE_IP (6, ADDRESSES),
nmc_property_ip_get_addresses,
nmc_property_ipv6_set_addresses,
@@ -6886,17 +6980,18 @@ setting_ip4_config_details (NMSetting *setting, NmCli *nmc, const char *one_pro
set_val_str (arr, 1, nmc_property_ipv4_get_method (setting));
set_val_str (arr, 2, nmc_property_ipv4_get_dns (setting));
set_val_str (arr, 3, nmc_property_ipv4_get_dns_search (setting));
- set_val_str (arr, 4, nmc_property_ip_get_addresses (setting));
- set_val_str (arr, 5, nmc_property_ipv4_get_gateway (setting));
- set_val_str (arr, 6, nmc_property_ipv4_get_routes (setting));
- set_val_str (arr, 7, nmc_property_ipv4_get_route_metric (setting));
- set_val_str (arr, 8, nmc_property_ipv4_get_ignore_auto_routes (setting));
- set_val_str (arr, 9, nmc_property_ipv4_get_ignore_auto_dns (setting));
- set_val_str (arr, 10, nmc_property_ipv4_get_dhcp_client_id (setting));
- set_val_str (arr, 11, nmc_property_ipv4_get_dhcp_send_hostname (setting));
- set_val_str (arr, 12, nmc_property_ipv4_get_dhcp_hostname (setting));
- set_val_str (arr, 13, nmc_property_ipv4_get_never_default (setting));
- set_val_str (arr, 14, nmc_property_ipv4_get_may_fail (setting));
+ set_val_str (arr, 4, nmc_property_ipv4_get_dns_options (setting));
+ set_val_str (arr, 5, nmc_property_ip_get_addresses (setting));
+ set_val_str (arr, 6, nmc_property_ipv4_get_gateway (setting));
+ set_val_str (arr, 7, nmc_property_ipv4_get_routes (setting));
+ set_val_str (arr, 8, nmc_property_ipv4_get_route_metric (setting));
+ set_val_str (arr, 9, nmc_property_ipv4_get_ignore_auto_routes (setting));
+ set_val_str (arr, 10, nmc_property_ipv4_get_ignore_auto_dns (setting));
+ set_val_str (arr, 11, nmc_property_ipv4_get_dhcp_client_id (setting));
+ set_val_str (arr, 12, nmc_property_ipv4_get_dhcp_send_hostname (setting));
+ set_val_str (arr, 13, nmc_property_ipv4_get_dhcp_hostname (setting));
+ set_val_str (arr, 14, nmc_property_ipv4_get_never_default (setting));
+ set_val_str (arr, 15, nmc_property_ipv4_get_may_fail (setting));
g_ptr_array_add (nmc->output_data, arr);
print_data (nmc); /* Print all data */
@@ -6925,17 +7020,18 @@ setting_ip6_config_details (NMSetting *setting, NmCli *nmc, const char *one_pro
set_val_str (arr, 1, nmc_property_ipv6_get_method (setting));
set_val_str (arr, 2, nmc_property_ipv6_get_dns (setting));
set_val_str (arr, 3, nmc_property_ipv6_get_dns_search (setting));
- set_val_str (arr, 4, nmc_property_ip_get_addresses (setting));
- set_val_str (arr, 5, nmc_property_ipv6_get_gateway (setting));
- set_val_str (arr, 6, nmc_property_ipv6_get_routes (setting));
- set_val_str (arr, 7, nmc_property_ipv6_get_route_metric (setting));
- set_val_str (arr, 8, nmc_property_ipv6_get_ignore_auto_routes (setting));
- set_val_str (arr, 9, nmc_property_ipv6_get_ignore_auto_dns (setting));
- set_val_str (arr, 10, nmc_property_ipv6_get_never_default (setting));
- set_val_str (arr, 11, nmc_property_ipv6_get_may_fail (setting));
- set_val_str (arr, 12, nmc_property_ipv6_get_ip6_privacy (setting));
- set_val_str (arr, 13, nmc_property_ipv6_get_dhcp_send_hostname (setting));
- set_val_str (arr, 14, nmc_property_ipv6_get_dhcp_hostname (setting));
+ set_val_str (arr, 4, nmc_property_ipv6_get_dns_options (setting));
+ set_val_str (arr, 5, nmc_property_ip_get_addresses (setting));
+ set_val_str (arr, 6, nmc_property_ipv6_get_gateway (setting));
+ set_val_str (arr, 7, nmc_property_ipv6_get_routes (setting));
+ set_val_str (arr, 8, nmc_property_ipv6_get_route_metric (setting));
+ set_val_str (arr, 9, nmc_property_ipv6_get_ignore_auto_routes (setting));
+ set_val_str (arr, 10, nmc_property_ipv6_get_ignore_auto_dns (setting));
+ set_val_str (arr, 11, nmc_property_ipv6_get_never_default (setting));
+ set_val_str (arr, 12, nmc_property_ipv6_get_may_fail (setting));
+ set_val_str (arr, 13, nmc_property_ipv6_get_ip6_privacy (setting));
+ set_val_str (arr, 14, nmc_property_ipv6_get_dhcp_send_hostname (setting));
+ set_val_str (arr, 15, nmc_property_ipv6_get_dhcp_hostname (setting));
g_ptr_array_add (nmc->output_data, arr);
print_data (nmc); /* Print all data */
diff --git a/introspection/nm-ip4-config.xml b/introspection/nm-ip4-config.xml
index 9807653495..5a9e8ea1c3 100644
--- a/introspection/nm-ip4-config.xml
+++ b/introspection/nm-ip4-config.xml
@@ -49,6 +49,13 @@
<property name="Searches" type="as" access="read">
<tp:docstring>A list of dns searches.</tp:docstring>
</property>
+ <property name="DnsOptions" type="as" access="read">
+ <tp:docstring>
+ A list of DNS options that modify the behavior of the DNS
+ resolver. See resolv.conf(5) manual page for the list of
+ supported options.
+ </tp:docstring>
+ </property>
<property name="WinsServers" type="au" access="read">
<tp:docstring>The Windows Internet Name Service servers associated with the connection. Each address is in network byte order.</tp:docstring>
</property>
diff --git a/introspection/nm-ip6-config.xml b/introspection/nm-ip6-config.xml
index 985dd2e331..f2ef386ba1 100644
--- a/introspection/nm-ip6-config.xml
+++ b/introspection/nm-ip6-config.xml
@@ -43,6 +43,13 @@
<property name="Searches" type="as" access="read">
<tp:docstring>A list of dns searches.</tp:docstring>
</property>
+ <property name="DnsOptions" type="as" access="read">
+ <tp:docstring>
+ A list of DNS options that modify the behavior of the DNS
+ resolver. See resolv.conf(5) manual page for the list of
+ supported options.
+ </tp:docstring>
+ </property>
<signal name="PropertiesChanged">
<arg name="properties" type="a{sv}" tp:type="String_Variant_Map">
diff --git a/libnm-core/nm-setting-ip-config.c b/libnm-core/nm-setting-ip-config.c
index a01f4409d1..281c0b9817 100644
--- a/libnm-core/nm-setting-ip-config.c
+++ b/libnm-core/nm-setting-ip-config.c
@@ -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,
@@ -1128,21 +1148,21 @@ nm_setting_ip_config_get_num_dns (NMSettingIPConfig *setting)
/**
* nm_setting_ip_config_get_dns:
* @setting: the #NMSettingIPConfig
- * @i: index number of the DNS server to return
+ * @idx: index number of the DNS server to return
*
- * Returns: the IP address of the DNS server at index @i
+ * Returns: the IP address of the DNS server at index @idx
**/
const char *
-nm_setting_ip_config_get_dns (NMSettingIPConfig *setting, int i)
+nm_setting_ip_config_get_dns (NMSettingIPConfig *setting, int idx)
{
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->len, NULL);
+ g_return_val_if_fail (idx < priv->dns->len, NULL);
- return priv->dns->pdata[i];
+ return priv->dns->pdata[idx];
}
/**
@@ -1184,21 +1204,21 @@ nm_setting_ip_config_add_dns (NMSettingIPConfig *setting, const char *dns)
/**
* nm_setting_ip_config_remove_dns:
* @setting: the #NMSettingIPConfig
- * @i: index number of the DNS server to remove
+ * @idx: index number of the DNS server to remove
*
- * Removes the DNS server at index @i.
+ * Removes the DNS server at index @idx.
**/
void
-nm_setting_ip_config_remove_dns (NMSettingIPConfig *setting, int i)
+nm_setting_ip_config_remove_dns (NMSettingIPConfig *setting, int idx)
{
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->len);
+ g_return_if_fail (idx < priv->dns->len);
- g_ptr_array_remove_index (priv->dns, i);
+ g_ptr_array_remove_index (priv->dns, idx);
g_object_notify (G_OBJECT (setting), NM_SETTING_IP_CONFIG_DNS);
}
@@ -1272,21 +1292,21 @@ nm_setting_ip_config_get_num_dns_searches (NMSettingIPConfig *setting)
/**
* nm_setting_ip_config_get_dns_search:
* @setting: the #NMSettingIPConfig
- * @i: index number of the DNS search domain to return
+ * @idx: index number of the DNS search domain to return
*
- * Returns: the DNS search domain at index @i
+ * Returns: the DNS search domain at index @idx
**/
const char *
-nm_setting_ip_config_get_dns_search (NMSettingIPConfig *setting, int i)
+nm_setting_ip_config_get_dns_search (NMSettingIPConfig *setting, int idx)
{
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_search->len, NULL);
+ g_return_val_if_fail (idx < priv->dns_search->len, NULL);
- return priv->dns_search->pdata[i];
+ return priv->dns_search->pdata[idx];
}
/**
@@ -1324,21 +1344,21 @@ nm_setting_ip_config_add_dns_search (NMSettingIPConfig *setting,
/**
* nm_setting_ip_config_remove_dns_search:
* @setting: the #NMSettingIPConfig
- * @i: index number of the DNS search domain
+ * @idx: index number of the DNS search domain
*
- * Removes the DNS search domain at index @i.
+ * Removes the DNS search domain at index @idx.
**/
void
-nm_setting_ip_config_remove_dns_search (NMSettingIPConfig *setting, int i)
+nm_setting_ip_config_remove_dns_search (NMSettingIPConfig *setting, int idx)
{
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_search->len);
+ g_return_if_fail (idx < priv->dns_search->len);
- g_ptr_array_remove_index (priv->dns_search, i);
+ g_ptr_array_remove_index (priv->dns_search, idx);
g_object_notify (G_OBJECT (setting), NM_SETTING_IP_CONFIG_DNS_SEARCH);
}
@@ -1394,6 +1414,182 @@ nm_setting_ip_config_clear_dns_searches (NMSettingIPConfig *setting)
}
/**
+ * 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
+ * @idx: index number of the DNS option
+ *
+ * Returns: the DNS option at index @idx
+ *
+ * Since: 1.2
+ **/
+const char *
+nm_setting_ip_config_get_dns_option (NMSettingIPConfig *setting, guint idx)
+{
+ 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 (idx < priv->dns_options->len, NULL);
+
+ return priv->dns_options->pdata[idx];
+}
+
+/**
+ * nm_setting_ip_config_next_valid_dns_option
+ * @setting: the #NMSettingIPConfig
+ * @idx: index to start the search from
+ *
+ * Returns: the index, greater or equal than @idx, 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 idx)
+{
+ NMSettingIPConfigPrivate *priv;
+
+ g_return_val_if_fail (NM_IS_SETTING_IP_CONFIG (setting), -1);
+
+ priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting);
+
+ for (; idx < priv->dns_options->len; idx++) {
+ if (_nm_utils_dns_option_validate (priv->dns_options->pdata[idx], NULL, NULL,
+ NM_IS_SETTING_IP6_CONFIG (setting),
+ dns_option_descs))
+ return idx;
+ }
+
+ 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
+ * @idx: index number of the DNS option
+ *
+ * Removes the DNS option at index @idx.
+ *
+ * Since: 1.2
+ **/
+void
+nm_setting_ip_config_remove_dns_option (NMSettingIPConfig *setting, int idx)
+{
+ NMSettingIPConfigPrivate *priv;
+
+ g_return_if_fail (NM_IS_SETTING_IP_CONFIG (setting));
+
+ priv = NM_SETTING_IP_CONFIG_GET_PRIVATE (setting);
+ g_return_if_fail (idx < priv->dns_options->len);
+
+ g_ptr_array_remove_index (priv->dns_options, idx);
+ 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
*
@@ -1410,21 +1606,21 @@ nm_setting_ip_config_get_num_addresses (NMSettingIPConfig *setting)
/**
* nm_setting_ip_config_get_address:
* @setting: the #NMSettingIPConfig
- * @i: index number of the address to return
+ * @idx: index number of the address to return
*
- * Returns: the address at index @i
+ * Returns: the address at index @idx
**/
NMIPAddress *
-nm_setting_ip_config_get_address (NMSettingIPConfig *setting, int i)
+nm_setting_ip_config_get_address (NMSettingIPConfig *setting, int idx)
{
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->addresses->len, NULL);
+ g_return_val_if_fail (idx < priv->addresses->len, NULL);
- return priv->addresses->pdata[i];
+ return priv->addresses->pdata[idx];
}
/**
@@ -1464,21 +1660,21 @@ nm_setting_ip_config_add_address (NMSettingIPConfig *setting,
/**
* nm_setting_ip_config_remove_address:
* @setting: the #NMSettingIPConfig
- * @i: index number of the address to remove
+ * @idx: index number of the address to remove
*
- * Removes the address at index @i.
+ * Removes the address at index @idx.
**/
void
-nm_setting_ip_config_remove_address (NMSettingIPConfig *setting, int i)
+nm_setting_ip_config_remove_address (NMSettingIPConfig *setting, int idx)
{
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->addresses->len);
+ g_return_if_fail (idx < priv->addresses->len);
- g_ptr_array_remove_index (priv->addresses, i);
+ g_ptr_array_remove_index (priv->addresses, idx);
g_object_notify (G_OBJECT (setting), NM_SETTING_IP_CONFIG_ADDRESSES);
}
@@ -1562,21 +1758,21 @@ nm_setting_ip_config_get_num_routes (NMSettingIPConfig *setting)
/**
* nm_setting_ip_config_get_route:
* @setting: the #NMSettingIPConfig
- * @i: index number of the route to return
+ * @idx: index number of the route to return
*
- * Returns: the route at index @i
+ * Returns: the route at index @idx
**/
NMIPRoute *
-nm_setting_ip_config_get_route (NMSettingIPConfig *setting, int i)
+nm_setting_ip_config_get_route (NMSettingIPConfig *setting, int idx)
{
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->routes->len, NULL);
+ g_return_val_if_fail (idx < priv->routes->len, NULL);
- return priv->routes->pdata[i];
+ return priv->routes->pdata[idx];
}
/**
@@ -1614,21 +1810,21 @@ nm_setting_ip_config_add_route (NMSettingIPConfig *setting,
/**
* nm_setting_ip_config_remove_route:
* @setting: the #NMSettingIPConfig
- * @i: index number of the route
+ * @idx: index number of the route
*
- * Removes the route at index @i.
+ * Removes the route at index @idx.
**/
void
-nm_setting_ip_config_remove_route (NMSettingIPConfig *setting, int i)
+nm_setting_ip_config_remove_route (NMSettingIPConfig *setting, int idx)
{
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->routes->len);
+ g_return_if_fail (idx < priv->routes->len);
- g_ptr_array_remove_index (priv->routes, i);
+ g_ptr_array_remove_index (priv->routes, idx);
g_object_notify (G_OBJECT (setting), NM_SETTING_IP_CONFIG_ROUTES);
}
@@ -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,
@@ -2185,6 +2398,20 @@ nm_setting_ip_config_class_init (NMSettingIPConfigClass *setting_class)
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:
*
* Array of IP addresses.
diff --git a/libnm-core/nm-setting-ip-config.h b/libnm-core/nm-setting-ip-config.h
index 12763fa857..1e88a8bfde 100644
--- a/libnm-core/nm-setting-ip-config.h
+++ b/libnm-core/nm-setting-ip-config.h
@@ -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;
};
@@ -161,33 +185,46 @@ const char *nm_setting_ip_config_get_method (NMSettingIPConfig
guint nm_setting_ip_config_get_num_dns (NMSettingIPConfig *setting);
const char *nm_setting_ip_config_get_dns (NMSettingIPConfig *setting,
- int i);
+ int idx);
gboolean nm_setting_ip_config_add_dns (NMSettingIPConfig *setting,
const char *dns);
void nm_setting_ip_config_remove_dns (NMSettingIPConfig *setting,
- int i);
+ int idx);
gboolean nm_setting_ip_config_remove_dns_by_value (NMSettingIPConfig *setting,
const char *dns);
void nm_setting_ip_config_clear_dns (NMSettingIPConfig *setting);
guint nm_setting_ip_config_get_num_dns_searches (NMSettingIPConfig *setting);
const char *nm_setting_ip_config_get_dns_search (NMSettingIPConfig *setting,
- int i);
+ int idx);
gboolean nm_setting_ip_config_add_dns_search (NMSettingIPConfig *setting,
const char *dns_search);
void nm_setting_ip_config_remove_dns_search (NMSettingIPConfig *setting,
- int i);
+ int idx);
gboolean nm_setting_ip_config_remove_dns_search_by_value (NMSettingIPConfig *setting,
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 idx);
+gint nm_setting_ip_config_next_valid_dns_option (NMSettingIPConfig *setting,
+ guint idx);
+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 idx);
+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);
+ int idx);
gboolean nm_setting_ip_config_add_address (NMSettingIPConfig *setting,
NMIPAddress *address);
void nm_setting_ip_config_remove_address (NMSettingIPConfig *setting,
- int i);
+ int idx);
gboolean nm_setting_ip_config_remove_address_by_value (NMSettingIPConfig *setting,
NMIPAddress *address);
void nm_setting_ip_config_clear_addresses (NMSettingIPConfig *setting);
@@ -196,11 +233,11 @@ const char *nm_setting_ip_config_get_gateway (NMSettingIPConfig
guint nm_setting_ip_config_get_num_routes (NMSettingIPConfig *setting);
NMIPRoute *nm_setting_ip_config_get_route (NMSettingIPConfig *setting,
- int i);
+ int idx);
gboolean nm_setting_ip_config_add_route (NMSettingIPConfig *setting,
NMIPRoute *route);
void nm_setting_ip_config_remove_route (NMSettingIPConfig *setting,
- int i);
+ int idx);
gboolean nm_setting_ip_config_remove_route_by_value (NMSettingIPConfig *setting,
NMIPRoute *route);
void nm_setting_ip_config_clear_routes (NMSettingIPConfig *setting);
diff --git a/libnm-core/nm-utils-private.h b/libnm-core/nm-utils-private.h
index 3854d67951..74e48dbee1 100644
--- a/libnm-core/nm-utils-private.h
+++ b/libnm-core/nm-utils-private.h
@@ -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);
diff --git a/libnm-core/nm-utils.c b/libnm-core/nm-utils.c
index 80fed00e9f..ad71e95b30 100644
--- a/libnm-core/nm-utils.c
+++ b/libnm-core/nm-utils.c
@@ -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;
+}
+
diff --git a/libnm-core/tests/test-general.c b/libnm-core/tests/test-general.c
index a417d3fe31..77009c2dcb 100644
--- a/libnm-core/tests/test-general.c
+++ b/libnm-core/tests/test-general.c
@@ -29,6 +29,7 @@
#include "nm-setting-private.h"
#include "nm-utils.h"
+#include "nm-utils-private.h"
#include "nm-core-internal.h"
#include "nm-setting-8021x.h"
@@ -1985,6 +1986,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 },
@@ -2842,7 +2844,7 @@ test_setting_ip4_changed_signal (void)
ASSERT_CHANGED (nm_setting_ip_config_add_dns (s_ip4, "11.22.0.0"));
ASSERT_CHANGED (nm_setting_ip_config_remove_dns (s_ip4, 0));
- g_test_expect_message ("libnm", G_LOG_LEVEL_CRITICAL, "*i < priv->dns->len*");
+ g_test_expect_message ("libnm", G_LOG_LEVEL_CRITICAL, "*idx < priv->dns->len*");
ASSERT_UNCHANGED (nm_setting_ip_config_remove_dns (s_ip4, 1));
g_test_assert_expected_messages ();
@@ -2852,7 +2854,7 @@ test_setting_ip4_changed_signal (void)
ASSERT_CHANGED (nm_setting_ip_config_add_dns_search (s_ip4, "foobar.com"));
ASSERT_CHANGED (nm_setting_ip_config_remove_dns_search (s_ip4, 0));
- g_test_expect_message ("libnm", G_LOG_LEVEL_CRITICAL, "*i < priv->dns_search->len*");
+ g_test_expect_message ("libnm", G_LOG_LEVEL_CRITICAL, "*idx < priv->dns_search->len*");
ASSERT_UNCHANGED (nm_setting_ip_config_remove_dns_search (s_ip4, 1));
g_test_assert_expected_messages ();
@@ -2864,7 +2866,7 @@ test_setting_ip4_changed_signal (void)
ASSERT_CHANGED (nm_setting_ip_config_add_address (s_ip4, addr));
ASSERT_CHANGED (nm_setting_ip_config_remove_address (s_ip4, 0));
- g_test_expect_message ("libnm", G_LOG_LEVEL_CRITICAL, "*i < priv->addresses->len*");
+ g_test_expect_message ("libnm", G_LOG_LEVEL_CRITICAL, "*idx < priv->addresses->len*");
ASSERT_UNCHANGED (nm_setting_ip_config_remove_address (s_ip4, 1));
g_test_assert_expected_messages ();
@@ -2877,13 +2879,20 @@ test_setting_ip4_changed_signal (void)
ASSERT_CHANGED (nm_setting_ip_config_add_route (s_ip4, route));
ASSERT_CHANGED (nm_setting_ip_config_remove_route (s_ip4, 0));
- g_test_expect_message ("libnm", G_LOG_LEVEL_CRITICAL, "*i < priv->routes->len*");
+ g_test_expect_message ("libnm", G_LOG_LEVEL_CRITICAL, "*idx < priv->routes->len*");
ASSERT_UNCHANGED (nm_setting_ip_config_remove_route (s_ip4, 1));
g_test_assert_expected_messages ();
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, "*idx < 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);
@@ -2911,7 +2920,7 @@ test_setting_ip6_changed_signal (void)
ASSERT_CHANGED (nm_setting_ip_config_add_dns (s_ip6, "1:2:3::4:5:6"));
ASSERT_CHANGED (nm_setting_ip_config_remove_dns (s_ip6, 0));
- g_test_expect_message ("libnm", G_LOG_LEVEL_CRITICAL, "*i < priv->dns->len*");
+ g_test_expect_message ("libnm", G_LOG_LEVEL_CRITICAL, "*idx < priv->dns->len*");
ASSERT_UNCHANGED (nm_setting_ip_config_remove_dns (s_ip6, 1));
g_test_assert_expected_messages ();
@@ -2921,7 +2930,7 @@ test_setting_ip6_changed_signal (void)
ASSERT_CHANGED (nm_setting_ip_config_add_dns_search (s_ip6, "foobar.com"));
ASSERT_CHANGED (nm_setting_ip_config_remove_dns_search (s_ip6, 0));
- g_test_expect_message ("libnm", G_LOG_LEVEL_CRITICAL, "*i < priv->dns_search->len*");
+ g_test_expect_message ("libnm", G_LOG_LEVEL_CRITICAL, "*idx < priv->dns_search->len*");
ASSERT_UNCHANGED (nm_setting_ip_config_remove_dns_search (s_ip6, 1));
g_test_assert_expected_messages ();
@@ -2934,7 +2943,7 @@ test_setting_ip6_changed_signal (void)
ASSERT_CHANGED (nm_setting_ip_config_add_address (s_ip6, addr));
ASSERT_CHANGED (nm_setting_ip_config_remove_address (s_ip6, 0));
- g_test_expect_message ("libnm", G_LOG_LEVEL_CRITICAL, "*i < priv->addresses->len*");
+ g_test_expect_message ("libnm", G_LOG_LEVEL_CRITICAL, "*idx < priv->addresses->len*");
ASSERT_UNCHANGED (nm_setting_ip_config_remove_address (s_ip6, 1));
g_test_assert_expected_messages ();
@@ -2947,7 +2956,7 @@ test_setting_ip6_changed_signal (void)
ASSERT_CHANGED (nm_setting_ip_config_add_route (s_ip6, route));
ASSERT_CHANGED (nm_setting_ip_config_remove_route (s_ip6, 0));
- g_test_expect_message ("libnm", G_LOG_LEVEL_CRITICAL, "*i < priv->routes->len*");
+ g_test_expect_message ("libnm", G_LOG_LEVEL_CRITICAL, "*idx < priv->routes->len*");
ASSERT_UNCHANGED (nm_setting_ip_config_remove_route (s_ip6, 1));
g_test_assert_expected_messages ();
@@ -4218,6 +4227,90 @@ test_nm_utils_ascii_str_to_int64 (void)
/******************************************************************************/
+static void
+test_nm_utils_dns_option_validate_do (char *option, gboolean ipv6, const DNSOptionDesc *descs,
+ gboolean exp_result, char *exp_name, gboolean exp_value)
+{
+ char *name;
+ long value = 0;
+ gboolean result;
+
+ result = _nm_utils_dns_option_validate (option, &name, &value, ipv6, descs);
+
+ g_assert (result == exp_result);
+ g_assert_cmpstr (name, ==, exp_name);
+ g_assert (value == exp_value);
+
+ g_free (name);
+}
+
+static const DNSOptionDesc opt_descs[] = {
+ /* name num ipv6 */
+ { "opt1", FALSE, FALSE },
+ { "opt2", TRUE, FALSE },
+ { "opt3", FALSE, TRUE },
+ { "opt4", TRUE, TRUE },
+ { NULL, FALSE, FALSE }
+};
+
+static void
+test_nm_utils_dns_option_validate (void)
+{
+ /* opt ipv6 descs result name value */
+ test_nm_utils_dns_option_validate_do ("", FALSE, NULL, FALSE, NULL, -1);
+ test_nm_utils_dns_option_validate_do (":", FALSE, NULL, FALSE, NULL, -1);
+ test_nm_utils_dns_option_validate_do (":1", FALSE, NULL, FALSE, NULL, -1);
+ test_nm_utils_dns_option_validate_do (":val", FALSE, NULL, FALSE, NULL, -1);
+ test_nm_utils_dns_option_validate_do ("opt", FALSE, NULL, TRUE, "opt", -1);
+ test_nm_utils_dns_option_validate_do ("opt:", FALSE, NULL, FALSE, NULL, -1);
+ test_nm_utils_dns_option_validate_do ("opt:12", FALSE, NULL, TRUE, "opt", 12);
+ test_nm_utils_dns_option_validate_do ("opt:12 ", FALSE, NULL, FALSE, NULL, -1);
+ test_nm_utils_dns_option_validate_do ("opt:val", FALSE, NULL, FALSE, NULL, -1);
+ test_nm_utils_dns_option_validate_do ("opt:2val", FALSE, NULL, FALSE, NULL, -1);
+ test_nm_utils_dns_option_validate_do ("opt:2:3", FALSE, NULL, FALSE, NULL, -1);
+ test_nm_utils_dns_option_validate_do ("opt-6", FALSE, NULL, TRUE, "opt-6", -1);
+
+ test_nm_utils_dns_option_validate_do ("opt1", FALSE, opt_descs, TRUE, "opt1", -1);
+ test_nm_utils_dns_option_validate_do ("opt1", TRUE, opt_descs, TRUE, "opt1", -1);
+ test_nm_utils_dns_option_validate_do ("opt1:3", FALSE, opt_descs, FALSE, NULL, -1);
+
+ test_nm_utils_dns_option_validate_do ("opt2", FALSE, opt_descs, FALSE, NULL, -1);
+ test_nm_utils_dns_option_validate_do ("opt2:5", FALSE, opt_descs, TRUE, "opt2", 5);
+
+ test_nm_utils_dns_option_validate_do ("opt3", FALSE, opt_descs, FALSE, NULL, -1);
+ test_nm_utils_dns_option_validate_do ("opt3", TRUE, opt_descs, TRUE, "opt3", -1);
+
+ test_nm_utils_dns_option_validate_do ("opt4", FALSE, opt_descs, FALSE, NULL, -1);
+ test_nm_utils_dns_option_validate_do ("opt4", TRUE, opt_descs, FALSE, NULL, -1);
+ test_nm_utils_dns_option_validate_do ("opt4:40", FALSE, opt_descs, FALSE, NULL, -1);
+ test_nm_utils_dns_option_validate_do ("opt4:40", TRUE, opt_descs, TRUE, "opt4", 40);
+}
+
+static void
+test_nm_utils_dns_option_find_idx (void)
+{
+ GPtrArray *options;
+
+ options = g_ptr_array_new ();
+
+ g_ptr_array_add (options, "debug");
+ g_ptr_array_add (options, "timeout:5");
+ g_ptr_array_add (options, "edns0");
+
+ g_assert_cmpint (_nm_utils_dns_option_find_idx (options, "debug"), ==, 0);
+ g_assert_cmpint (_nm_utils_dns_option_find_idx (options, "debug:1"), ==, 0);
+ g_assert_cmpint (_nm_utils_dns_option_find_idx (options, "timeout"), ==, 1);
+ g_assert_cmpint (_nm_utils_dns_option_find_idx (options, "timeout:5"), ==, 1);
+ g_assert_cmpint (_nm_utils_dns_option_find_idx (options, "timeout:2"), ==, 1);
+ g_assert_cmpint (_nm_utils_dns_option_find_idx (options, "edns0"), ==, 2);
+ g_assert_cmpint (_nm_utils_dns_option_find_idx (options, "rotate"), ==, -1);
+ g_assert_cmpint (_nm_utils_dns_option_find_idx (options, ""), ==, -1);
+
+ g_ptr_array_free (options, TRUE);
+}
+
+/******************************************************************************/
+
NMTST_DEFINE ();
int main (int argc, char **argv)
@@ -4319,6 +4412,9 @@ int main (int argc, char **argv)
g_test_add_func ("/core/general/_nm_utils_ascii_str_to_int64", test_nm_utils_ascii_str_to_int64);
+ g_test_add_func ("/core/general/_nm_utils_dns_option_validate", test_nm_utils_dns_option_validate);
+ g_test_add_func ("/core/general/_nm_utils_dns_option_find_idx", test_nm_utils_dns_option_find_idx);
+
return g_test_run ();
}
diff --git a/libnm/libnm.ver b/libnm/libnm.ver
index 1fe8e30d53..3c70c43840 100644
--- a/libnm/libnm.ver
+++ b/libnm/libnm.ver
@@ -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;
diff --git a/src/NetworkManagerUtils.c b/src/NetworkManagerUtils.c
index 368ceb3438..afcb88b84b 100644
--- a/src/NetworkManagerUtils.c
+++ b/src/NetworkManagerUtils.c
@@ -1473,6 +1473,56 @@ nm_utils_read_resolv_conf_nameservers (const char *rc_contents)
return nameservers;
}
+/**
+ * nm_utils_read_resolv_conf_dns_options():
+ * @rc_contents: contents of a resolv.conf; or %NULL to read /etc/resolv.conf
+ *
+ * Reads all dns options out of @rc_contents or /etc/resolv.conf and returns
+ * them.
+ *
+ * Returns: a #GPtrArray of 'char *' elements of each option
+ */
+GPtrArray *
+nm_utils_read_resolv_conf_dns_options (const char *rc_contents)
+{
+ GPtrArray *options = NULL;
+ char *contents = NULL;
+ char **lines, **line_iter;
+ char **tokens, **token_iter;
+ char *p;
+
+ if (rc_contents)
+ contents = g_strdup (rc_contents);
+ else {
+ if (!g_file_get_contents (_PATH_RESCONF, &contents, NULL, NULL))
+ return NULL;
+ }
+
+ options = g_ptr_array_new_full (3, g_free);
+
+ lines = g_strsplit_set (contents, "\r\n", -1);
+ for (line_iter = lines; *line_iter; line_iter++) {
+ if (!g_str_has_prefix (*line_iter, "options"))
+ continue;
+ p = *line_iter + strlen ("options");
+ if (!g_ascii_isspace (*p++))
+ continue;
+
+ tokens = g_strsplit (p, " ", 0);
+ for (token_iter = tokens; token_iter && *token_iter; token_iter++) {
+ g_strstrip (*token_iter);
+ if (!*token_iter[0])
+ continue;
+ g_ptr_array_add (options, g_strdup (*token_iter));
+ }
+ g_strfreev (tokens);
+ }
+ g_strfreev (lines);
+ g_free (contents);
+
+ return options;
+}
+
static GHashTable *
check_property_in_hash (GHashTable *hash,
const char *s_name,
diff --git a/src/NetworkManagerUtils.h b/src/NetworkManagerUtils.h
index 1e62ee7b62..fe88a7201b 100644
--- a/src/NetworkManagerUtils.h
+++ b/src/NetworkManagerUtils.h
@@ -123,6 +123,7 @@ void nm_utils_complete_generic (NMConnection *connection,
char *nm_utils_new_vlan_name (const char *parent_iface, guint32 vlan_id);
GPtrArray *nm_utils_read_resolv_conf_nameservers (const char *rc_contents);
+GPtrArray *nm_utils_read_resolv_conf_dns_options (const char *rc_contents);
typedef gboolean (NMUtilsMatchFilterFunc) (NMConnection *connection, gpointer user_data);
diff --git a/src/dns-manager/nm-dns-manager.c b/src/dns-manager/nm-dns-manager.c
index 430df122fa..caa1c2c69a 100644
--- a/src/dns-manager/nm-dns-manager.c
+++ b/src/dns-manager/nm-dns-manager.c
@@ -40,6 +40,7 @@
#include <glib/gi18n.h>
#include "nm-utils.h"
+#include "nm-utils-private.h"
#include "nm-dns-manager.h"
#include "nm-ip4-config.h"
#include "nm-ip6-config.h"
@@ -118,6 +119,7 @@ static guint signals[LAST_SIGNAL] = { 0 };
typedef struct {
GPtrArray *nameservers;
GPtrArray *searches;
+ GPtrArray *options;
const char *nis_domain;
GPtrArray *nis_servers;
} NMResolvConfData;
@@ -143,6 +145,13 @@ add_string_item (GPtrArray *array, const char *str)
}
static void
+add_dns_option_item (GPtrArray *array, const char *str, gboolean ipv6)
+{
+ if (_nm_utils_dns_option_find_idx (array, str) < 0)
+ g_ptr_array_add (array, g_strdup (str));
+}
+
+static void
merge_one_ip4_config (NMResolvConfData *rc, NMIP4Config *src)
{
guint32 num, num_domains, num_searches, i;
@@ -176,6 +185,14 @@ merge_one_ip4_config (NMResolvConfData *rc, NMIP4Config *src)
}
}
+ num = nm_ip4_config_get_num_dns_options (src);
+ for (i = 0; i < num; i++) {
+ const char *option;
+
+ option = nm_ip4_config_get_dns_option (src, i);
+ add_dns_option_item (rc->options, option, FALSE);
+ }
+
/* NIS stuff */
num = nm_ip4_config_get_num_nis_servers (src);
for (i = 0; i < num; i++) {
@@ -240,8 +257,15 @@ merge_one_ip6_config (NMResolvConfData *rc, NMIP6Config *src)
add_string_item (rc->searches, domain);
}
}
-}
+ num = nm_ip6_config_get_num_dns_options (src);
+ for (i = 0; i < num; i++) {
+ const char *option;
+
+ option = nm_ip6_config_get_dns_option (src, i);
+ add_dns_option_item (rc->options, option, TRUE);
+ }
+}
static GPid
run_netconfig (GError **error, gint *stdin_fd)
@@ -347,10 +371,12 @@ static gboolean
write_resolv_conf (FILE *f,
char **searches,
char **nameservers,
+ char **options,
GError **error)
{
char *searches_str = NULL;
char *nameservers_str = NULL;
+ char *options_str = NULL;
gboolean retval = FALSE;
char *tmp_str;
GString *str;
@@ -362,6 +388,12 @@ write_resolv_conf (FILE *f,
g_free (tmp_str);
}
+ if (options) {
+ tmp_str = g_strjoinv (" ", options);
+ options_str = g_strconcat ("option ", tmp_str, "\n", NULL);
+ g_free (tmp_str);
+ }
+
str = g_string_new ("");
if (nameservers) {
@@ -384,9 +416,10 @@ write_resolv_conf (FILE *f,
nameservers_str = g_string_free (str, FALSE);
- if (fprintf (f, "# Generated by NetworkManager\n%s%s",
+ if (fprintf (f, "# Generated by NetworkManager\n%s%s%s",
searches_str ? searches_str : "",
- nameservers_str) > 0)
+ nameservers_str,
+ options_str ? options_str : "") > 0)
retval = TRUE;
else {
g_set_error (error,
@@ -398,6 +431,7 @@ write_resolv_conf (FILE *f,
g_free (searches_str);
g_free (nameservers_str);
+ g_free (options_str);
return retval;
}
@@ -405,6 +439,7 @@ write_resolv_conf (FILE *f,
static gboolean
dispatch_resolvconf (char **searches,
char **nameservers,
+ char **options,
GError **error)
{
char *cmd;
@@ -431,7 +466,7 @@ dispatch_resolvconf (char **searches,
RESOLVCONF_PATH,
g_strerror (errno));
else {
- retval = write_resolv_conf (f, searches, nameservers, error);
+ retval = write_resolv_conf (f, searches, nameservers, options, error);
err = pclose (f);
if (err < 0) {
errnosv = errno;
@@ -462,6 +497,7 @@ dispatch_resolvconf (char **searches,
static gboolean
update_resolv_conf (char **searches,
char **nameservers,
+ char **options,
GError **error,
gboolean install_etc)
{
@@ -498,7 +534,7 @@ update_resolv_conf (char **searches,
return FALSE;
}
- write_resolv_conf (f, searches, nameservers, error);
+ write_resolv_conf (f, searches, nameservers, options, error);
if (fclose (f) < 0) {
if (*error == NULL) {
@@ -683,6 +719,7 @@ update_dns (NMDnsManager *self,
GSList *iter;
const char *nis_domain = NULL;
char **searches = NULL;
+ char **options = NULL;
char **nameservers = NULL;
char **nis_servers = NULL;
int num, i, len;
@@ -705,6 +742,7 @@ update_dns (NMDnsManager *self,
rc.nameservers = g_ptr_array_new ();
rc.searches = g_ptr_array_new ();
+ rc.options = g_ptr_array_new ();
rc.nis_domain = NULL;
rc.nis_servers = g_ptr_array_new ();
@@ -772,6 +810,12 @@ update_dns (NMDnsManager *self,
} else
g_ptr_array_free (rc.searches, TRUE);
+ if (rc.options->len) {
+ g_ptr_array_add (rc.options, NULL);
+ options = (char **) g_ptr_array_free (rc.options, FALSE);
+ } else
+ g_ptr_array_free (rc.options, TRUE);
+
if (rc.nameservers->len) {
g_ptr_array_add (rc.nameservers, NULL);
nameservers = (char **) g_ptr_array_free (rc.nameservers, FALSE);
@@ -838,10 +882,10 @@ update_dns (NMDnsManager *self,
if (update) {
switch (priv->rc_manager) {
case NM_DNS_MANAGER_RESOLV_CONF_MAN_NONE:
- success = update_resolv_conf (searches, nameservers, error, TRUE);
+ success = update_resolv_conf (searches, nameservers, options, error, TRUE);
break;
case NM_DNS_MANAGER_RESOLV_CONF_MAN_RESOLVCONF:
- success = dispatch_resolvconf (searches, nameservers, error);
+ success = dispatch_resolvconf (searches, nameservers, options, error);
break;
case NM_DNS_MANAGER_RESOLV_CONF_MAN_NETCONFIG:
success = dispatch_netconfig (searches, nameservers, nis_domain,
@@ -856,7 +900,7 @@ update_dns (NMDnsManager *self,
ignoring any errors */
if (!(update && priv->rc_manager == NM_DNS_MANAGER_RESOLV_CONF_MAN_NONE)) {
g_clear_error (error);
- update_resolv_conf (searches, nameservers, error, FALSE);
+ update_resolv_conf (searches, nameservers, options, error, FALSE);
}
/* signal that resolv.conf was changed */
@@ -865,6 +909,8 @@ update_dns (NMDnsManager *self,
if (searches)
g_strfreev (searches);
+ if (options)
+ g_strfreev (options);
if (nameservers)
g_strfreev (nameservers);
if (nis_servers)
diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c
index abc8af836a..e893351f6f 100644
--- a/src/nm-ip4-config.c
+++ b/src/nm-ip4-config.c
@@ -34,6 +34,7 @@
#include "NetworkManagerUtils.h"
#include "nm-core-internal.h"
#include "nm-route-manager.h"
+#include "nm-utils-private.h"
G_DEFINE_TYPE (NMIP4Config, nm_ip4_config, G_TYPE_OBJECT)
@@ -49,6 +50,7 @@ typedef struct {
GArray *nameservers;
GPtrArray *domains;
GPtrArray *searches;
+ GPtrArray *dns_options;
guint32 mss;
GArray *nis;
char *nis_domain;
@@ -73,6 +75,7 @@ enum {
PROP_NAMESERVERS,
PROP_DOMAINS,
PROP_SEARCHES,
+ PROP_DNS_OPTIONS,
PROP_WINS_SERVERS,
LAST_PROP
@@ -137,9 +140,10 @@ same_prefix (guint32 address1, guint32 address2, int plen)
*/
gboolean
nm_ip4_config_capture_resolv_conf (GArray *nameservers,
+ GPtrArray *dns_options,
const char *rc_contents)
{
- GPtrArray *read_ns;
+ GPtrArray *read_ns, *read_options;
guint i, j;
gboolean changed = FALSE;
@@ -167,8 +171,25 @@ nm_ip4_config_capture_resolv_conf (GArray *nameservers,
changed = TRUE;
}
}
-
g_ptr_array_unref (read_ns);
+
+ if (dns_options) {
+ read_options = nm_utils_read_resolv_conf_dns_options (rc_contents);
+ if (!read_options)
+ return changed;
+
+ for (i = 0; i < read_options->len; i++) {
+ const char *s = g_ptr_array_index (read_options, i);
+
+ if (_nm_utils_dns_option_validate (s, NULL, NULL, FALSE, dns_option_descs) &&
+ _nm_utils_dns_option_find_idx (dns_options, s) < 0) {
+ g_ptr_array_add (dns_options, g_strdup (s));
+ changed = TRUE;
+ }
+ }
+ g_ptr_array_unref (read_options);
+ }
+
return changed;
}
@@ -245,7 +266,7 @@ nm_ip4_config_capture (int ifindex, gboolean capture_resolv_conf)
* nameservers from /etc/resolv.conf.
*/
if (priv->addresses->len && has_gateway && capture_resolv_conf) {
- if (nm_ip4_config_capture_resolv_conf (priv->nameservers, NULL))
+ if (nm_ip4_config_capture_resolv_conf (priv->nameservers, priv->dns_options, NULL))
_NOTIFY (config, PROP_NAMESERVERS);
}
@@ -388,6 +409,12 @@ nm_ip4_config_merge_setting (NMIP4Config *config, NMSettingIPConfig *setting, gu
for (i = 0; i < nsearches; i++)
nm_ip4_config_add_search (config, nm_setting_ip_config_get_dns_search (setting, i));
+ i = 0;
+ while ((i = nm_setting_ip_config_next_valid_dns_option (setting, i)) >= 0) {
+ nm_ip4_config_add_dns_option (config, nm_setting_ip_config_get_dns_option (setting, i));
+ i++;
+ }
+
g_object_thaw_notify (G_OBJECT (config));
}
@@ -396,7 +423,7 @@ nm_ip4_config_create_setting (const NMIP4Config *config)
{
NMSettingIPConfig *s_ip4;
guint32 gateway;
- guint naddresses, nroutes, nnameservers, nsearches;
+ guint naddresses, nroutes, nnameservers, nsearches, noptions;
const char *method = NULL;
int i;
@@ -414,6 +441,7 @@ nm_ip4_config_create_setting (const NMIP4Config *config)
nroutes = nm_ip4_config_get_num_routes (config);
nnameservers = nm_ip4_config_get_num_nameservers (config);
nsearches = nm_ip4_config_get_num_searches (config);
+ noptions = nm_ip4_config_get_num_dns_options (config);
/* Addresses */
for (i = 0; i < naddresses; i++) {
@@ -484,6 +512,12 @@ nm_ip4_config_create_setting (const NMIP4Config *config)
nm_setting_ip_config_add_dns_search (s_ip4, search);
}
+ for (i = 0; i < noptions; i++) {
+ const char *option = nm_ip4_config_get_dns_option (config, i);
+
+ nm_setting_ip_config_add_dns_option (s_ip4, option);
+ }
+
return NM_SETTING (s_ip4);
}
@@ -523,6 +557,10 @@ nm_ip4_config_merge (NMIP4Config *dst, const NMIP4Config *src)
for (i = 0; i < nm_ip4_config_get_num_searches (src); i++)
nm_ip4_config_add_search (dst, nm_ip4_config_get_search (src, i));
+ /* dns options */
+ for (i = 0; i < nm_ip4_config_get_num_dns_options (src); i++)
+ nm_ip4_config_add_dns_option (dst, nm_ip4_config_get_dns_option (src, i));
+
/* MSS */
if (!nm_ip4_config_get_mss (dst))
nm_ip4_config_set_mss (dst, nm_ip4_config_get_mss (src));
@@ -626,6 +664,21 @@ _searches_get_index (const NMIP4Config *self, const char *search)
}
static int
+_dns_options_get_index (const NMIP4Config *self, const char *option)
+{
+ NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self);
+ guint i;
+
+ for (i = 0; i < priv->dns_options->len; i++) {
+ const char *s = g_ptr_array_index (priv->dns_options, i);
+
+ if (g_strcmp0 (option, s) == 0)
+ return (int) i;
+ }
+ return -1;
+}
+
+static int
_nis_servers_get_index (const NMIP4Config *self, guint32 nis_server)
{
NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self);
@@ -717,6 +770,13 @@ nm_ip4_config_subtract (NMIP4Config *dst, const NMIP4Config *src)
nm_ip4_config_del_search (dst, idx);
}
+ /* dns options */
+ for (i = 0; i < nm_ip4_config_get_num_dns_options (src); i++) {
+ idx = _dns_options_get_index (dst, nm_ip4_config_get_dns_option (src, i));
+ if (idx >= 0)
+ nm_ip4_config_del_dns_option (dst, idx);
+ }
+
/* MSS */
if (nm_ip4_config_get_mss (src) == nm_ip4_config_get_mss (dst))
nm_ip4_config_set_mss (dst, 0);
@@ -783,6 +843,7 @@ nm_ip4_config_intersect (NMIP4Config *dst, const NMIP4Config *src)
/* ignore domains */
/* ignore dns searches */
+ /* ignore dns options */
/* ignore NIS */
/* ignore WINS */
@@ -949,6 +1010,25 @@ nm_ip4_config_replace (NMIP4Config *dst, const NMIP4Config *src, gboolean *relev
has_relevant_changes = TRUE;
}
+ /* dns options */
+ num = nm_ip4_config_get_num_dns_options (src);
+ are_equal = num == nm_ip4_config_get_num_dns_options (dst);
+ if (are_equal) {
+ for (i = 0; i < num; i++ ) {
+ if (g_strcmp0 (nm_ip4_config_get_dns_option (src, i),
+ nm_ip4_config_get_dns_option (dst, i))) {
+ are_equal = FALSE;
+ break;
+ }
+ }
+ }
+ if (!are_equal) {
+ nm_ip4_config_reset_dns_options (dst);
+ for (i = 0; i < num; i++)
+ nm_ip4_config_add_dns_option (dst, nm_ip4_config_get_dns_option (src, i));
+ has_relevant_changes = TRUE;
+ }
+
/* mss */
if (src_priv->mss != dst_priv->mss) {
nm_ip4_config_set_mss (dst, src_priv->mss);
@@ -1055,6 +1135,11 @@ nm_ip4_config_dump (const NMIP4Config *config, const char *detail)
for (i = 0; i < nm_ip4_config_get_num_searches (config); i++)
g_message (" search: %s", nm_ip4_config_get_search (config, i));
+ /* dns options */
+ for (i = 0; i < nm_ip4_config_get_num_dns_options (config); i++)
+ g_message (" dnsopt: %s", nm_ip4_config_get_dns_option (config, i));
+
+
g_message (" mss: %"G_GUINT32_FORMAT, nm_ip4_config_get_mss (config));
g_message (" mtu: %"G_GUINT32_FORMAT, nm_ip4_config_get_mtu (config));
@@ -1553,6 +1638,63 @@ nm_ip4_config_get_search (const NMIP4Config *config, guint i)
/******************************************************************/
void
+nm_ip4_config_reset_dns_options (NMIP4Config *config)
+{
+ NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config);
+
+ if (priv->dns_options->len != 0) {
+ g_ptr_array_set_size (priv->dns_options, 0);
+ _NOTIFY (config, PROP_DNS_OPTIONS);
+ }
+}
+
+void
+nm_ip4_config_add_dns_option (NMIP4Config *config, const char *new)
+{
+ NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config);
+ int i;
+
+ g_return_if_fail (new != NULL);
+ g_return_if_fail (new[0] != '\0');
+
+ for (i = 0; i < priv->dns_options->len; i++)
+ if (!g_strcmp0 (g_ptr_array_index (priv->dns_options, i), new))
+ return;
+
+ g_ptr_array_add (priv->dns_options, g_strdup (new));
+ _NOTIFY (config, PROP_DNS_OPTIONS);
+}
+
+void
+nm_ip4_config_del_dns_option(NMIP4Config *config, guint i)
+{
+ NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config);
+
+ g_return_if_fail (i < priv->dns_options->len);
+
+ g_ptr_array_remove_index (priv->dns_options, i);
+ _NOTIFY (config, PROP_DNS_OPTIONS);
+}
+
+guint32
+nm_ip4_config_get_num_dns_options (const NMIP4Config *config)
+{
+ NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config);
+
+ return priv->dns_options->len;
+}
+
+const char *
+nm_ip4_config_get_dns_option (const NMIP4Config *config, guint i)
+{
+ NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config);
+
+ return g_ptr_array_index (priv->dns_options, i);
+}
+
+/******************************************************************/
+
+void
nm_ip4_config_set_mss (NMIP4Config *config, guint32 mss)
{
NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config);
@@ -1778,6 +1920,12 @@ nm_ip4_config_hash (const NMIP4Config *config, GChecksum *sum, gboolean dns_only
s = nm_ip4_config_get_search (config, i);
g_checksum_update (sum, (const guint8 *) s, strlen (s));
}
+
+ for (i = 0; i < nm_ip4_config_get_num_dns_options (config); i++) {
+ s = nm_ip4_config_get_dns_option (config, i);
+ g_checksum_update (sum, (const guint8 *) s, strlen (s));
+ }
+
}
/**
@@ -1832,6 +1980,7 @@ nm_ip4_config_init (NMIP4Config *config)
priv->nameservers = g_array_new (FALSE, FALSE, sizeof (guint32));
priv->domains = g_ptr_array_new_with_free_func (g_free);
priv->searches = g_ptr_array_new_with_free_func (g_free);
+ priv->dns_options = g_ptr_array_new_with_free_func (g_free);
priv->nis = g_array_new (FALSE, TRUE, sizeof (guint32));
priv->wins = g_array_new (FALSE, TRUE, sizeof (guint32));
}
@@ -1848,6 +1997,7 @@ finalize (GObject *object)
g_array_unref (priv->nameservers);
g_ptr_array_unref (priv->domains);
g_ptr_array_unref (priv->searches);
+ g_ptr_array_unref (priv->dns_options);
g_array_unref (priv->nis);
g_free (priv->nis_domain);
g_array_unref (priv->wins);
@@ -2015,6 +2165,9 @@ get_property (GObject *object, guint prop_id,
case PROP_SEARCHES:
g_value_set_boxed (value, priv->searches);
break;
+ case PROP_DNS_OPTIONS:
+ g_value_set_boxed (value, priv->dns_options);
+ break;
case PROP_WINS_SERVERS:
g_value_set_boxed (value, priv->wins);
break;
@@ -2099,6 +2252,12 @@ nm_ip4_config_class_init (NMIP4ConfigClass *config_class)
DBUS_TYPE_G_ARRAY_OF_STRING,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS);
+ obj_properties[PROP_DNS_OPTIONS] =
+ g_param_spec_boxed (NM_IP4_CONFIG_DNS_OPTIONS, "", "",
+ DBUS_TYPE_G_ARRAY_OF_STRING,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS);
+
obj_properties[PROP_WINS_SERVERS] =
g_param_spec_boxed (NM_IP4_CONFIG_WINS_SERVERS, "", "",
DBUS_TYPE_G_UINT_ARRAY,
diff --git a/src/nm-ip4-config.h b/src/nm-ip4-config.h
index 3e551950d3..a69af7e795 100644
--- a/src/nm-ip4-config.h
+++ b/src/nm-ip4-config.h
@@ -48,6 +48,7 @@ typedef struct {
#define NM_IP4_CONFIG_NAMESERVERS "nameservers"
#define NM_IP4_CONFIG_DOMAINS "domains"
#define NM_IP4_CONFIG_SEARCHES "searches"
+#define NM_IP4_CONFIG_DNS_OPTIONS "dns-options"
#define NM_IP4_CONFIG_WINS_SERVERS "wins-servers"
/* deprecated */
@@ -124,6 +125,13 @@ void nm_ip4_config_del_search (NMIP4Config *config, guint i);
guint32 nm_ip4_config_get_num_searches (const NMIP4Config *config);
const char * nm_ip4_config_get_search (const NMIP4Config *config, guint i);
+/* DNS options */
+void nm_ip4_config_reset_dns_options (NMIP4Config *config);
+void nm_ip4_config_add_dns_option (NMIP4Config *config, const char *option);
+void nm_ip4_config_del_dns_option (NMIP4Config *config, guint i);
+guint32 nm_ip4_config_get_num_dns_options (const NMIP4Config *config);
+const char * nm_ip4_config_get_dns_option (const NMIP4Config *config, guint i);
+
/* MSS */
void nm_ip4_config_set_mss (NMIP4Config *config, guint32 mss);
guint32 nm_ip4_config_get_mss (const NMIP4Config *config);
@@ -155,7 +163,7 @@ gboolean nm_ip4_config_equal (const NMIP4Config *a, const NMIP4Config *b);
/******************************************************/
/* Testing-only functions */
-gboolean nm_ip4_config_capture_resolv_conf (GArray *nameservers,
+gboolean nm_ip4_config_capture_resolv_conf (GArray *nameservers, GPtrArray *dns_options,
const char *rc_contents);
#endif /* __NETWORKMANAGER_IP4_CONFIG_H__ */
diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c
index 9d4bf47b20..df2952717c 100644
--- a/src/nm-ip6-config.c
+++ b/src/nm-ip6-config.c
@@ -33,6 +33,7 @@
#include "nm-dbus-glib-types.h"
#include "nm-ip6-config-glue.h"
#include "nm-route-manager.h"
+#include "nm-utils-private.h"
#include "NetworkManagerUtils.h"
G_DEFINE_TYPE (NMIP6Config, nm_ip6_config, G_TYPE_OBJECT)
@@ -49,6 +50,7 @@ typedef struct {
GArray *nameservers;
GPtrArray *domains;
GPtrArray *searches;
+ GPtrArray *dns_options;
guint32 mss;
int ifindex;
} NMIP6ConfigPrivate;
@@ -65,6 +67,7 @@ enum {
PROP_NAMESERVERS,
PROP_DOMAINS,
PROP_SEARCHES,
+ PROP_DNS_OPTIONS,
LAST_PROP
};
@@ -138,9 +141,10 @@ same_prefix (const struct in6_addr *address1, const struct in6_addr *address2, i
*/
gboolean
nm_ip6_config_capture_resolv_conf (GArray *nameservers,
+ GPtrArray *dns_options,
const char *rc_contents)
{
- GPtrArray *read_ns;
+ GPtrArray *read_ns, *read_options;
guint i, j;
gboolean changed = FALSE;
@@ -170,8 +174,25 @@ nm_ip6_config_capture_resolv_conf (GArray *nameservers,
changed = TRUE;
}
}
-
g_ptr_array_unref (read_ns);
+
+ if (dns_options) {
+ read_options = nm_utils_read_resolv_conf_dns_options (rc_contents);
+ if (!read_options)
+ return changed;
+
+ for (i = 0; i < read_options->len; i++) {
+ const char *s = g_ptr_array_index (read_options, i);
+
+ if (_nm_utils_dns_option_validate (s, NULL, NULL, TRUE, dns_option_descs) &&
+ _nm_utils_dns_option_find_idx (dns_options, s) < 0) {
+ g_ptr_array_add (dns_options, g_strdup (s));
+ changed = TRUE;
+ }
+ }
+ g_ptr_array_unref (read_options);
+ }
+
return changed;
}
@@ -359,7 +380,9 @@ nm_ip6_config_capture (int ifindex, gboolean capture_resolv_conf, NMSettingIP6Co
* nameservers from /etc/resolv.conf.
*/
if (priv->addresses->len && has_gateway && capture_resolv_conf)
- notify_nameservers = nm_ip6_config_capture_resolv_conf (priv->nameservers, NULL);
+ notify_nameservers = nm_ip6_config_capture_resolv_conf (priv->nameservers,
+ priv->dns_options,
+ NULL);
g_array_sort_with_data (priv->addresses, _addresses_sort_cmp, GINT_TO_POINTER (use_temporary));
@@ -499,6 +522,12 @@ nm_ip6_config_merge_setting (NMIP6Config *config, NMSettingIPConfig *setting, gu
for (i = 0; i < nsearches; i++)
nm_ip6_config_add_search (config, nm_setting_ip_config_get_dns_search (setting, i));
+ i = 0;
+ while ((i = nm_setting_ip_config_next_valid_dns_option (setting, i)) >= 0) {
+ nm_ip6_config_add_dns_option (config, nm_setting_ip_config_get_dns_option (setting, i));
+ i++;
+ }
+
g_object_thaw_notify (G_OBJECT (config));
}
@@ -507,7 +536,7 @@ nm_ip6_config_create_setting (const NMIP6Config *config)
{
NMSettingIPConfig *s_ip6;
const struct in6_addr *gateway;
- guint naddresses, nroutes, nnameservers, nsearches;
+ guint naddresses, nroutes, nnameservers, nsearches, noptions;
const char *method = NULL;
int i;
@@ -525,6 +554,7 @@ nm_ip6_config_create_setting (const NMIP6Config *config)
nroutes = nm_ip6_config_get_num_routes (config);
nnameservers = nm_ip6_config_get_num_nameservers (config);
nsearches = nm_ip6_config_get_num_searches (config);
+ noptions = nm_ip6_config_get_num_dns_options (config);
/* Addresses */
for (i = 0; i < naddresses; i++) {
@@ -602,6 +632,12 @@ nm_ip6_config_create_setting (const NMIP6Config *config)
nm_setting_ip_config_add_dns_search (s_ip6, search);
}
+ for (i = 0; i < noptions; i++) {
+ const char *option = nm_ip6_config_get_dns_option (config, i);
+
+ nm_setting_ip_config_add_dns_option (s_ip6, option);
+ }
+
return NM_SETTING (s_ip6);
}
@@ -642,6 +678,10 @@ nm_ip6_config_merge (NMIP6Config *dst, const NMIP6Config *src)
for (i = 0; i < nm_ip6_config_get_num_searches (src); i++)
nm_ip6_config_add_search (dst, nm_ip6_config_get_search (src, i));
+ /* dns options */
+ for (i = 0; i < nm_ip6_config_get_num_dns_options (src); i++)
+ nm_ip6_config_add_dns_option (dst, nm_ip6_config_get_dns_option (src, i));
+
if (!nm_ip6_config_get_mss (dst))
nm_ip6_config_set_mss (dst, nm_ip6_config_get_mss (src));
@@ -742,6 +782,21 @@ _searches_get_index (const NMIP6Config *self, const char *search)
return -1;
}
+static int
+_dns_options_get_index (const NMIP6Config *self, const char *option)
+{
+ NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self);
+ guint i;
+
+ for (i = 0; i < priv->dns_options->len; i++) {
+ const char *s = g_ptr_array_index (priv->dns_options, i);
+
+ if (g_strcmp0 (option, s) == 0)
+ return (int) i;
+ }
+ return -1;
+}
+
/*******************************************************************************/
/**
@@ -807,6 +862,13 @@ nm_ip6_config_subtract (NMIP6Config *dst, const NMIP6Config *src)
nm_ip6_config_del_search (dst, idx);
}
+ /* dns options */
+ for (i = 0; i < nm_ip6_config_get_num_dns_options (src); i++) {
+ idx = _dns_options_get_index (dst, nm_ip6_config_get_dns_option (src, i));
+ if (idx >= 0)
+ nm_ip6_config_del_dns_option (dst, idx);
+ }
+
if (nm_ip6_config_get_mss (src) == nm_ip6_config_get_mss (dst))
nm_ip6_config_set_mss (dst, 0);
@@ -857,6 +919,7 @@ nm_ip6_config_intersect (NMIP6Config *dst, const NMIP6Config *src)
/* ignore domains */
/* ignore dns searches */
+ /* ignome dns options */
g_object_thaw_notify (G_OBJECT (dst));
}
@@ -1021,6 +1084,25 @@ nm_ip6_config_replace (NMIP6Config *dst, const NMIP6Config *src, gboolean *relev
has_relevant_changes = TRUE;
}
+ /* dns options */
+ num = nm_ip6_config_get_num_dns_options (src);
+ are_equal = num == nm_ip6_config_get_num_dns_options (dst);
+ if (are_equal) {
+ for (i = 0; i < num; i++ ) {
+ if (g_strcmp0 (nm_ip6_config_get_dns_option (src, i),
+ nm_ip6_config_get_dns_option (dst, i))) {
+ are_equal = FALSE;
+ break;
+ }
+ }
+ }
+ if (!are_equal) {
+ nm_ip6_config_reset_dns_options (dst);
+ for (i = 0; i < num; i++)
+ nm_ip6_config_add_dns_option (dst, nm_ip6_config_get_dns_option (src, i));
+ has_relevant_changes = TRUE;
+ }
+
/* mss */
if (src_priv->mss != dst_priv->mss) {
nm_ip6_config_set_mss (dst, src_priv->mss);
@@ -1081,6 +1163,10 @@ nm_ip6_config_dump (const NMIP6Config *config, const char *detail)
for (i = 0; i < nm_ip6_config_get_num_searches (config); i++)
g_message (" search: %s", nm_ip6_config_get_search (config, i));
+ /* dns options */
+ for (i = 0; i < nm_ip6_config_get_num_dns_options (config); i++)
+ g_message (" dnsopt: %s", nm_ip6_config_get_dns_option (config, i));
+
g_message (" mss: %"G_GUINT32_FORMAT, nm_ip6_config_get_mss (config));
g_message (" n-dflt: %d", nm_ip6_config_get_never_default (config));
}
@@ -1564,6 +1650,63 @@ nm_ip6_config_get_search (const NMIP6Config *config, guint i)
/******************************************************************/
void
+nm_ip6_config_reset_dns_options (NMIP6Config *config)
+{
+ NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config);
+
+ if (priv->dns_options->len != 0) {
+ g_ptr_array_set_size (priv->dns_options, 0);
+ _NOTIFY (config, PROP_DNS_OPTIONS);
+ }
+}
+
+void
+nm_ip6_config_add_dns_option (NMIP6Config *config, const char *new)
+{
+ NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config);
+ int i;
+
+ g_return_if_fail (new != NULL);
+ g_return_if_fail (new[0] != '\0');
+
+ for (i = 0; i < priv->dns_options->len; i++)
+ if (!g_strcmp0 (g_ptr_array_index (priv->dns_options, i), new))
+ return;
+
+ g_ptr_array_add (priv->dns_options, g_strdup (new));
+ _NOTIFY (config, PROP_DNS_OPTIONS);
+}
+
+void
+nm_ip6_config_del_dns_option (NMIP6Config *config, guint i)
+{
+ NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config);
+
+ g_return_if_fail (i < priv->dns_options->len);
+
+ g_ptr_array_remove_index (priv->dns_options, i);
+ _NOTIFY (config, PROP_DNS_OPTIONS);
+}
+
+guint32
+nm_ip6_config_get_num_dns_options (const NMIP6Config *config)
+{
+ NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config);
+
+ return priv->dns_options->len;
+}
+
+const char *
+nm_ip6_config_get_dns_option (const NMIP6Config *config, guint i)
+{
+ NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config);
+
+ return g_ptr_array_index (priv->dns_options, i);
+}
+
+/******************************************************************/
+
+void
nm_ip6_config_set_mss (NMIP6Config *config, guint32 mss)
{
NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config);
@@ -1637,6 +1780,12 @@ nm_ip6_config_hash (const NMIP6Config *config, GChecksum *sum, gboolean dns_only
s = nm_ip6_config_get_search (config, i);
g_checksum_update (sum, (const guint8 *) s, strlen (s));
}
+
+ for (i = 0; i < nm_ip6_config_get_num_dns_options (config); i++) {
+ s = nm_ip6_config_get_dns_option (config, i);
+ g_checksum_update (sum, (const guint8 *) s, strlen (s));
+ }
+
}
/**
@@ -1691,6 +1840,7 @@ nm_ip6_config_init (NMIP6Config *config)
priv->nameservers = g_array_new (FALSE, TRUE, sizeof (struct in6_addr));
priv->domains = g_ptr_array_new_with_free_func (g_free);
priv->searches = g_ptr_array_new_with_free_func (g_free);
+ priv->dns_options = g_ptr_array_new_with_free_func (g_free);
}
static void
@@ -1705,6 +1855,7 @@ finalize (GObject *object)
g_array_unref (priv->nameservers);
g_ptr_array_unref (priv->domains);
g_ptr_array_unref (priv->searches);
+ g_ptr_array_unref (priv->dns_options);
G_OBJECT_CLASS (nm_ip6_config_parent_class)->finalize (object);
}
@@ -1926,6 +2077,9 @@ get_property (GObject *object, guint prop_id,
case PROP_SEARCHES:
g_value_set_boxed (value, priv->searches);
break;
+ case PROP_DNS_OPTIONS:
+ g_value_set_boxed (value, priv->dns_options);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -2009,6 +2163,11 @@ nm_ip6_config_class_init (NMIP6ConfigClass *config_class)
DBUS_TYPE_G_ARRAY_OF_STRING,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS);
+ obj_properties[PROP_DNS_OPTIONS] =
+ g_param_spec_boxed (NM_IP6_CONFIG_DNS_OPTIONS, "", "",
+ DBUS_TYPE_G_ARRAY_OF_STRING,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (object_class, LAST_PROP, obj_properties);
diff --git a/src/nm-ip6-config.h b/src/nm-ip6-config.h
index e0527e5e55..bf64fc26ac 100644
--- a/src/nm-ip6-config.h
+++ b/src/nm-ip6-config.h
@@ -49,6 +49,7 @@ typedef struct {
#define NM_IP6_CONFIG_NAMESERVERS "nameservers"
#define NM_IP6_CONFIG_DOMAINS "domains"
#define NM_IP6_CONFIG_SEARCHES "searches"
+#define NM_IP6_CONFIG_DNS_OPTIONS "dns-options"
/* deprecated */
#define NM_IP6_CONFIG_ADDRESSES "addresses"
@@ -126,6 +127,13 @@ void nm_ip6_config_del_search (NMIP6Config *config, guint i);
guint32 nm_ip6_config_get_num_searches (const NMIP6Config *config);
const char * nm_ip6_config_get_search (const NMIP6Config *config, guint i);
+/* DNS options */
+void nm_ip6_config_reset_dns_options (NMIP6Config *config);
+void nm_ip6_config_add_dns_option (NMIP6Config *config, const char *option);
+void nm_ip6_config_del_dns_option (NMIP6Config *config, guint i);
+guint32 nm_ip6_config_get_num_dns_options (const NMIP6Config *config);
+const char * nm_ip6_config_get_dns_option (const NMIP6Config *config, guint i);
+
/* MSS */
void nm_ip6_config_set_mss (NMIP6Config *config, guint32 mss);
guint32 nm_ip6_config_get_mss (const NMIP6Config *config);
@@ -137,6 +145,7 @@ gboolean nm_ip6_config_equal (const NMIP6Config *a, const NMIP6Config *b);
/* Testing-only functions */
gboolean nm_ip6_config_capture_resolv_conf (GArray *nameservers,
+ GPtrArray *dns_options,
const char *rc_contents);
#endif /* __NETWORKMANAGER_IP6_CONFIG_H__ */
diff --git a/src/settings/plugins/ifcfg-rh/reader.c b/src/settings/plugins/ifcfg-rh/reader.c
index 1081ab8f81..ed49f40e66 100644
--- a/src/settings/plugins/ifcfg-rh/reader.c
+++ b/src/settings/plugins/ifcfg-rh/reader.c
@@ -667,6 +667,29 @@ error:
return success;
}
+static void
+parse_dns_options (NMSettingIPConfig *ip_config, char *value)
+{
+ char **options = NULL;
+
+ g_return_if_fail (ip_config);
+
+ if (!value)
+ return;
+
+ options = g_strsplit (value, " ", 0);
+ if (options) {
+ char **item;
+ for (item = options; *item; item++) {
+ if (strlen (*item)) {
+ if (!nm_setting_ip_config_add_dns_option (ip_config, *item))
+ PARSE_WARNING ("can't add DNS option '%s'", *item);
+ }
+ }
+ g_strfreev (options);
+ }
+}
+
static gboolean
parse_full_ip6_address (shvarFile *ifcfg,
const char *network_file,
@@ -880,6 +903,7 @@ make_ip4_setting (shvarFile *ifcfg,
char *value = NULL;
char *route_path = NULL;
char *method;
+ char *dns_options = NULL;
gs_free char *gateway = NULL;
gint32 i;
shvarFile *network_ifcfg;
@@ -903,6 +927,7 @@ make_ip4_setting (shvarFile *ifcfg,
/* Get the connection ifcfg device name and the global gateway device */
value = svGetValue (ifcfg, "DEVICE", FALSE);
gatewaydev = svGetValue (network_ifcfg, "GATEWAYDEV", FALSE);
+ dns_options = svGetValue (network_ifcfg, "RES_OPTIONS", FALSE);
/* If there was a global gateway device specified, then only connections
* for that device can be the default connection.
@@ -1079,6 +1104,14 @@ make_ip4_setting (shvarFile *ifcfg,
g_free (value);
}
+ /* DNS options */
+ value = svGetValue (ifcfg, "RES_OPTIONS", FALSE);
+ parse_dns_options (s_ip4, value);
+ parse_dns_options (s_ip4, dns_options);
+ g_free (value);
+ g_free (dns_options);
+ dns_options = NULL;
+
/* Static routes - route-<name> file */
route_path = utils_get_route_path (ifcfg->fileName);
@@ -1135,6 +1168,7 @@ make_ip4_setting (shvarFile *ifcfg,
return NM_SETTING (s_ip4);
done:
+ g_free (dns_options);
g_free (route_path);
g_object_unref (s_ip4);
return NULL;
@@ -1251,6 +1285,7 @@ make_ip6_setting (shvarFile *ifcfg,
char *value = NULL;
char *str_value;
char *route6_path = NULL;
+ char *dns_options = NULL;
gboolean ipv6init, ipv6forwarding, ipv6_autoconf, dhcp6 = FALSE;
char *method = NM_SETTING_IP6_CONFIG_METHOD_MANUAL;
char *ipv6addr, *ipv6addr_secondaries;
@@ -1284,6 +1319,7 @@ make_ip6_setting (shvarFile *ifcfg,
value = svGetValue (ifcfg, "DEVICE", FALSE);
ipv6_defaultgw = svGetValue (network_ifcfg, "IPV6_DEFAULTGW", FALSE);
ipv6_defaultdev = svGetValue (network_ifcfg, "IPV6_DEFAULTDEV", FALSE);
+ dns_options = svGetValue (network_ifcfg, "RES_OPTIONS", FALSE);
if (ipv6_defaultgw) {
default_dev = strchr (ipv6_defaultgw, '%');
@@ -1480,9 +1516,17 @@ make_ip6_setting (shvarFile *ifcfg,
g_free (route6_path);
}
+ /* DNS options */
+ value = svGetValue (ifcfg, "RES_OPTIONS", FALSE);
+ parse_dns_options (s_ip6, value);
+ parse_dns_options (s_ip6, dns_options);
+ g_free (value);
+ g_free (dns_options);
+
return NM_SETTING (s_ip6);
error:
+ g_free (dns_options);
g_free (route6_path);
g_object_unref (s_ip6);
return NULL;
diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-dns-options b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-dns-options
new file mode 100644
index 0000000000..62e301e38c
--- /dev/null
+++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-dns-options
@@ -0,0 +1,15 @@
+TYPE=Ethernet
+DEVICE=eth2
+HWADDR=00:11:22:33:44:ee
+BOOTPROTO=dhcp
+ONBOOT=yes
+USERCTL=yes
+NM_CONTROLLED=yes
+PEERDNS=yes
+DNS1=10.2.0.4
+DOMAIN="lorem.com ipsum.org dolor.edu"
+RES_OPTIONS="ndots:3 single-request-reopen inet6"
+IPV6INIT=yes
+IPV6_AUTOCONF=no
+IPV6ADDR="1001:abba::1234/56"
+IPV6ADDR_SECONDARIES="2001:abba::2234/64 3001:abba::3234/96"
diff --git a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c
index 24b2f398e3..b1c50fef8e 100644
--- a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c
+++ b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c
@@ -2493,6 +2493,165 @@ test_read_wired_aliases_bad_2 (void)
test_read_wired_aliases_bad (TEST_IFCFG_ALIASES_BAD_2, "System aliasem2");
}
+#define TEST_IFCFG_DNS_OPTIONS TEST_IFCFG_DIR "/network-scripts/ifcfg-test-dns-options"
+
+static void
+test_read_dns_options (void)
+{
+ NMConnection *connection;
+ NMSettingIPConfig *s_ip4, *s_ip6;
+ char *unmanaged = NULL;
+ const char *option;
+ GError *error = NULL;
+ const char *options[] = { "ndots:3", "single-request-reopen", "inet6" };
+ guint32 i, options_len = sizeof (options) / sizeof (options[0]);
+
+ connection = connection_from_file_test (TEST_IFCFG_DNS_OPTIONS,
+ NULL,
+ TYPE_ETHERNET,
+ &unmanaged,
+ &error);
+ g_assert (connection);
+ g_assert (nm_connection_verify (connection, &error));
+ g_assert_cmpstr (unmanaged, ==, NULL);
+
+ s_ip4 = nm_connection_get_setting_ip4_config (connection);
+ g_assert (s_ip4);
+
+ s_ip6 = nm_connection_get_setting_ip6_config (connection);
+ g_assert (s_ip6);
+
+ i = nm_setting_ip_config_get_num_dns_options (s_ip4);
+ g_assert_cmpint (i, ==, options_len);
+
+ i = nm_setting_ip_config_get_num_dns_options (s_ip6);
+ g_assert_cmpint (i, ==, options_len);
+
+ for (i = 0; i < options_len; i++) {
+ option = nm_setting_ip_config_get_dns_option (s_ip4, i);
+ g_assert_cmpstr (options[i], ==, option);
+
+ option = nm_setting_ip_config_get_dns_option (s_ip6, i);
+ g_assert_cmpstr (options[i], ==, option);
+ }
+
+ g_object_unref (connection);
+}
+
+static void
+test_write_dns_options (void)
+{
+ NMConnection *connection;
+ NMConnection *reread;
+ NMSettingConnection *s_con;
+ NMSettingWired *s_wired;
+ NMSettingIPConfig *s_ip4;
+ NMSettingIPConfig *s_ip6;
+ static const char *mac = "31:33:33:37:be:cd";
+ guint32 mtu = 1492;
+ char *uuid;
+ NMIPAddress *addr;
+ NMIPAddress *addr6;
+ gboolean success;
+ GError *error = NULL;
+ char *testfile = NULL;
+
+ connection = nm_simple_connection_new ();
+
+ /* Connection setting */
+ s_con = (NMSettingConnection *) nm_setting_connection_new ();
+ nm_connection_add_setting (connection, NM_SETTING (s_con));
+
+ uuid = nm_utils_uuid_generate ();
+ g_object_set (s_con,
+ NM_SETTING_CONNECTION_ID, "Test DNS options",
+ NM_SETTING_CONNECTION_UUID, uuid,
+ NM_SETTING_CONNECTION_AUTOCONNECT, TRUE,
+ NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRED_SETTING_NAME,
+ NULL);
+ g_free (uuid);
+
+ /* Wired setting */
+ s_wired = (NMSettingWired *) nm_setting_wired_new ();
+ nm_connection_add_setting (connection, NM_SETTING (s_wired));
+
+ g_object_set (s_wired,
+ NM_SETTING_WIRED_MAC_ADDRESS, mac,
+ NM_SETTING_WIRED_MTU, mtu,
+ NULL);
+
+ /* IP4 setting */
+ s_ip4 = (NMSettingIPConfig *) nm_setting_ip4_config_new ();
+ nm_connection_add_setting (connection, NM_SETTING (s_ip4));
+
+ g_object_set (s_ip4,
+ NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_MANUAL,
+ NM_SETTING_IP_CONFIG_MAY_FAIL, TRUE,
+ NM_SETTING_IP_CONFIG_GATEWAY, "1.1.1.1",
+ NM_SETTING_IP_CONFIG_ROUTE_METRIC, (gint64) 204,
+ NULL);
+
+ addr = nm_ip_address_new (AF_INET, "1.1.1.3", 24, &error);
+ nm_setting_ip_config_add_address (s_ip4, addr);
+ nm_ip_address_unref (addr);
+
+ /* IP6 setting */
+ s_ip6 = (NMSettingIPConfig *) nm_setting_ip6_config_new ();
+ nm_connection_add_setting (connection, NM_SETTING (s_ip6));
+
+ g_object_set (s_ip6,
+ NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_MANUAL,
+ NM_SETTING_IP_CONFIG_MAY_FAIL, TRUE,
+ NM_SETTING_IP_CONFIG_ROUTE_METRIC, (gint64) 206,
+ NULL);
+
+ /* Add addresses */
+ addr6 = nm_ip_address_new (AF_INET6, "1003:1234:abcd::1", 11, &error);
+ nm_setting_ip_config_add_address (s_ip6, addr6);
+ nm_ip_address_unref (addr6);
+
+ nm_setting_ip_config_add_dns_option (s_ip4, "debug");
+ nm_setting_ip_config_add_dns_option (s_ip6, "timeout:3");
+
+ g_assert (nm_connection_verify (connection, &error));
+
+ /* Save the ifcfg */
+ success = writer_new_connection (connection,
+ TEST_SCRATCH_DIR "/network-scripts/",
+ &testfile,
+ &error);
+ g_assert (success);
+ g_assert (testfile);
+
+ /* reread will be normalized, so we must normalize connection too. */
+ nm_connection_normalize (connection, NULL, NULL, NULL);
+
+ /* re-read the connection for comparison */
+ reread = connection_from_file_test (testfile,
+ NULL,
+ TYPE_ETHERNET,
+ NULL,
+ &error);
+ unlink (testfile);
+
+ /* RES_OPTIONS is copied to both IPv4 and IPv6 settings */
+ nm_setting_ip_config_clear_dns_options (s_ip4);
+ nm_setting_ip_config_add_dns_option (s_ip4, "debug");
+ nm_setting_ip_config_add_dns_option (s_ip4, "timeout:3");
+
+ nm_setting_ip_config_clear_dns_options (s_ip6);
+ nm_setting_ip_config_add_dns_option (s_ip6, "debug");
+ nm_setting_ip_config_add_dns_option (s_ip6, "timeout:3");
+
+ g_assert (reread);
+ g_assert (nm_connection_verify (reread, &error));
+ g_assert (nm_connection_compare (connection, reread, NM_SETTING_COMPARE_FLAG_EXACT));
+
+ g_free (testfile);
+ g_object_unref (connection);
+ g_object_unref (reread);
+}
+
#define TEST_IFCFG_WIFI_OPEN TEST_IFCFG_DIR"/network-scripts/ifcfg-test-wifi-open"
static void
@@ -12461,6 +12620,7 @@ int main (int argc, char **argv)
g_test_add_data_func (TPATH "static-ip6-only-gw/::", "::", test_write_wired_static_ip6_only_gw);
g_test_add_data_func (TPATH "static-ip6-only-gw/2001:db8:8:4::2", "2001:db8:8:4::2", test_write_wired_static_ip6_only_gw);
g_test_add_data_func (TPATH "static-ip6-only-gw/::ffff:255.255.255.255", "::ffff:255.255.255.255", test_write_wired_static_ip6_only_gw);
+ g_test_add_func (TPATH "read-dns-options", test_read_dns_options);
test_read_wired_static (TEST_IFCFG_WIRED_STATIC, "System test-wired-static", TRUE);
test_read_wired_static (TEST_IFCFG_WIRED_STATIC_BOOTPROTO, "System test-wired-static-bootproto", FALSE);
@@ -12611,6 +12771,7 @@ int main (int argc, char **argv)
test_write_vlan ();
test_write_vlan_only_vlanid ();
test_write_ethernet_missing_ipv6 ();
+ g_test_add_func (TPATH "write-dns-options", test_write_dns_options);
/* iSCSI / ibft */
g_test_add_func (TPATH "ibft/ignored", test_read_ibft_ignored);
diff --git a/src/settings/plugins/ifcfg-rh/writer.c b/src/settings/plugins/ifcfg-rh/writer.c
index 75547641b1..0a54eaf643 100644
--- a/src/settings/plugins/ifcfg-rh/writer.c
+++ b/src/settings/plugins/ifcfg-rh/writer.c
@@ -42,6 +42,7 @@
#include <nm-setting-team-port.h>
#include "nm-core-internal.h"
#include <nm-utils.h>
+#include <nm-utils-private.h>
#include "nm-logging.h"
#include "gsystem-local-alloc.h"
@@ -2464,6 +2465,61 @@ error:
return FALSE;
}
+static void
+add_dns_option (GPtrArray *array, const char *option)
+{
+ if (_nm_utils_dns_option_find_idx (array, option) < 0)
+ g_ptr_array_add (array, (gpointer) option);
+}
+
+static gboolean
+write_res_options (NMConnection *connection, shvarFile *ifcfg, GError **error)
+{
+ NMSettingIPConfig *s_ip6;
+ NMSettingIPConfig *s_ip4;
+ const char *method;
+ int i, num_options;
+ GPtrArray *array;
+ GString *value;
+
+ s_ip4 = nm_connection_get_setting_ip4_config (connection);
+ s_ip6 = nm_connection_get_setting_ip6_config (connection);
+ array = g_ptr_array_new ();
+
+ if (s_ip4) {
+ method = nm_setting_ip_config_get_method (s_ip4);
+ if (g_strcmp0 (method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED)) {
+ num_options = nm_setting_ip_config_get_num_dns_options (s_ip4);
+ for (i = 0; i < num_options; i++)
+ add_dns_option (array, nm_setting_ip_config_get_dns_option (s_ip4, i));
+ }
+ }
+
+ if (s_ip6) {
+ method = nm_setting_ip_config_get_method (s_ip6);
+ if (g_strcmp0 (method, NM_SETTING_IP6_CONFIG_METHOD_IGNORE)) {
+ num_options = nm_setting_ip_config_get_num_dns_options (s_ip6);
+ for (i = 0; i < num_options; i++)
+ add_dns_option (array, nm_setting_ip_config_get_dns_option (s_ip6, i));
+ }
+ }
+
+ if (array->len > 0) {
+ value = g_string_new (NULL);
+ for (i = 0; i < array->len; i++) {
+ if (i > 0)
+ g_string_append_c (value, ' ');
+ g_string_append (value, array->pdata[i]);
+ }
+ svSetValue (ifcfg, "RES_OPTIONS", value->str, FALSE);
+ g_string_free (value, TRUE);
+ } else
+ svSetValue (ifcfg, "RES_OPTIONS", NULL, FALSE);
+
+ g_ptr_array_unref (array);
+ return TRUE;
+}
+
static char *
escape_id (const char *id)
{
@@ -2611,6 +2667,9 @@ write_connection (NMConnection *connection,
if (!write_ip6_setting (connection, ifcfg, error))
goto out;
+
+ if (!write_res_options (connection, ifcfg, error))
+ goto out;
}
write_connection_setting (s_con, ifcfg);
diff --git a/src/tests/test-resolvconf-capture.c b/src/tests/test-resolvconf-capture.c
index f5cb298b9f..bf0fff0b1d 100644
--- a/src/tests/test-resolvconf-capture.c
+++ b/src/tests/test-resolvconf-capture.c
@@ -35,10 +35,10 @@ test_capture_empty (void)
GArray *ns4 = g_array_new (FALSE, FALSE, sizeof (guint32));
GArray *ns6 = g_array_new (FALSE, FALSE, sizeof (struct in6_addr));
- g_assert (nm_ip4_config_capture_resolv_conf (ns4, "") == FALSE);
+ g_assert (nm_ip4_config_capture_resolv_conf (ns4, NULL, "") == FALSE);
g_assert_cmpint (ns4->len, ==, 0);
- g_assert (nm_ip6_config_capture_resolv_conf (ns6, "") == FALSE);
+ g_assert (nm_ip6_config_capture_resolv_conf (ns6, NULL, "") == FALSE);
g_assert_cmpint (ns6->len, ==, 0);
g_array_free (ns4, TRUE);
@@ -67,6 +67,12 @@ assert_dns6_entry (const GArray *a, guint i, const char *s)
}
static void
+assert_dns_option (GPtrArray *a, guint i, const char *s)
+{
+ g_assert_cmpstr (a->pdata[i], ==, s);
+}
+
+static void
test_capture_basic4 (void)
{
GArray *ns4 = g_array_new (FALSE, FALSE, sizeof (guint32));
@@ -77,7 +83,7 @@ test_capture_basic4 (void)
"nameserver 4.2.2.1\r\n"
"nameserver 4.2.2.2\r\n";
- g_assert (nm_ip4_config_capture_resolv_conf (ns4, rc));
+ g_assert (nm_ip4_config_capture_resolv_conf (ns4, NULL, rc));
g_assert_cmpint (ns4->len, ==, 2);
assert_dns4_entry (ns4, 0, "4.2.2.1");
assert_dns4_entry (ns4, 1, "4.2.2.2");
@@ -98,7 +104,7 @@ test_capture_dup4 (void)
"nameserver 4.2.2.2\r\n";
/* Check that duplicates are ignored */
- g_assert (nm_ip4_config_capture_resolv_conf (ns4, rc));
+ g_assert (nm_ip4_config_capture_resolv_conf (ns4, NULL, rc));
g_assert_cmpint (ns4->len, ==, 2);
assert_dns4_entry (ns4, 0, "4.2.2.1");
assert_dns4_entry (ns4, 1, "4.2.2.2");
@@ -117,7 +123,7 @@ test_capture_basic6 (void)
"nameserver 2001:4860:4860::8888\r\n"
"nameserver 2001:4860:4860::8844\r\n";
- g_assert (nm_ip6_config_capture_resolv_conf (ns6, rc));
+ g_assert (nm_ip6_config_capture_resolv_conf (ns6, NULL, rc));
g_assert_cmpint (ns6->len, ==, 2);
assert_dns6_entry (ns6, 0, "2001:4860:4860::8888");
assert_dns6_entry (ns6, 1, "2001:4860:4860::8844");
@@ -138,7 +144,7 @@ test_capture_dup6 (void)
"nameserver 2001:4860:4860::8844\r\n";
/* Check that duplicates are ignored */
- g_assert (nm_ip6_config_capture_resolv_conf (ns6, rc));
+ g_assert (nm_ip6_config_capture_resolv_conf (ns6, NULL, rc));
g_assert_cmpint (ns6->len, ==, 2);
assert_dns6_entry (ns6, 0, "2001:4860:4860::8888");
assert_dns6_entry (ns6, 1, "2001:4860:4860::8844");
@@ -158,7 +164,7 @@ test_capture_addr4_with_6 (void)
"nameserver 4.2.2.2\r\n"
"nameserver 2001:4860:4860::8888\r\n";
- g_assert (nm_ip4_config_capture_resolv_conf (ns4, rc));
+ g_assert (nm_ip4_config_capture_resolv_conf (ns4, NULL, rc));
g_assert_cmpint (ns4->len, ==, 2);
assert_dns4_entry (ns4, 0, "4.2.2.1");
assert_dns4_entry (ns4, 1, "4.2.2.2");
@@ -178,7 +184,7 @@ test_capture_addr6_with_4 (void)
"nameserver 2001:4860:4860::8888\r\n"
"nameserver 2001:4860:4860::8844\r\n";
- g_assert (nm_ip6_config_capture_resolv_conf (ns6, rc));
+ g_assert (nm_ip6_config_capture_resolv_conf (ns6, NULL, rc));
g_assert_cmpint (ns6->len, ==, 2);
assert_dns6_entry (ns6, 0, "2001:4860:4860::8888");
assert_dns6_entry (ns6, 1, "2001:4860:4860::8844");
@@ -197,7 +203,7 @@ test_capture_format (void)
"nameserver\t\t4.2.2.4\r\n" /* good */
"nameserver 4.2.2.5\t\t\r\n"; /* good */
- g_assert (nm_ip4_config_capture_resolv_conf (ns4, rc));
+ g_assert (nm_ip4_config_capture_resolv_conf (ns4, NULL, rc));
g_assert_cmpint (ns4->len, ==, 3);
assert_dns4_entry (ns4, 0, "4.2.2.3");
assert_dns4_entry (ns4, 1, "4.2.2.4");
@@ -206,6 +212,80 @@ test_capture_format (void)
g_array_free (ns4, TRUE);
}
+static void
+test_capture_dns_options (void)
+{
+ GArray *ns4 = g_array_new (FALSE, FALSE, sizeof (guint32));
+ GPtrArray *dns_options = g_ptr_array_new_with_free_func (g_free);
+ const char *rc =
+"nameserver 4.2.2.1\r\n"
+"options debug rotate timeout:5 \r\n"
+"options edns0\r\n";
+
+ g_assert (nm_ip4_config_capture_resolv_conf (ns4, dns_options, rc));
+ g_assert_cmpint (dns_options->len, ==, 4);
+ assert_dns_option (dns_options, 0, "debug");
+ assert_dns_option (dns_options, 1, "rotate");
+ assert_dns_option (dns_options, 2, "timeout:5");
+ assert_dns_option (dns_options, 3, "edns0");
+
+ g_array_free (ns4, TRUE);
+ g_ptr_array_free (dns_options, TRUE);
+}
+
+static void
+test_capture_dns_options_dup (void)
+{
+ GArray *ns4 = g_array_new (FALSE, FALSE, sizeof (guint32));
+ GPtrArray *dns_options = g_ptr_array_new_with_free_func (g_free);
+ const char *rc =
+"options debug rotate timeout:3\r\n"
+"options edns0 debug\r\n"
+"options timeout:5\r\n";
+
+ g_assert (nm_ip4_config_capture_resolv_conf (ns4, dns_options, rc));
+ g_assert_cmpint (dns_options->len, ==, 4);
+ assert_dns_option (dns_options, 0, "debug");
+ assert_dns_option (dns_options, 1, "rotate");
+ assert_dns_option (dns_options, 2, "timeout:3");
+ assert_dns_option (dns_options, 3, "edns0");
+
+ g_array_free (ns4, TRUE);
+ g_ptr_array_free (dns_options, TRUE);
+}
+
+static void
+test_capture_dns_options_valid4 (void)
+{
+ GArray *ns4 = g_array_new (FALSE, FALSE, sizeof (guint32));
+ GPtrArray *dns_options = g_ptr_array_new_with_free_func (g_free);
+ const char *rc =
+"options debug: rotate:yes edns0 foobar : inet6\r\n";
+
+ g_assert (nm_ip4_config_capture_resolv_conf (ns4, dns_options, rc));
+ g_assert_cmpint (dns_options->len, ==, 1);
+ assert_dns_option (dns_options, 0, "edns0");
+
+ g_array_free (ns4, TRUE);
+ g_ptr_array_free (dns_options, TRUE);
+}
+
+static void
+test_capture_dns_options_valid6 (void)
+{
+ GArray *ns6 = g_array_new (FALSE, FALSE, sizeof (guint32));
+ GPtrArray *dns_options = g_ptr_array_new_with_free_func (g_free);
+ const char *rc =
+"options inet6 debug foobar rotate:\r\n";
+
+ g_assert (nm_ip6_config_capture_resolv_conf (ns6, dns_options, rc));
+ g_assert_cmpint (dns_options->len, ==, 2);
+ assert_dns_option (dns_options, 0, "inet6");
+ assert_dns_option (dns_options, 1, "debug");
+
+ g_array_free (ns6, TRUE);
+ g_ptr_array_free (dns_options, TRUE);
+}
/*******************************************/
int
@@ -225,6 +305,10 @@ main (int argc, char **argv)
g_test_add_func ("/resolvconf-capture/addr4-with-6", test_capture_addr4_with_6);
g_test_add_func ("/resolvconf-capture/addr6-with-4", test_capture_addr6_with_4);
g_test_add_func ("/resolvconf-capture/format", test_capture_format);
+ g_test_add_func ("/resolvconf-capture/dns-options", test_capture_dns_options);
+ g_test_add_func ("/resolvconf-capture/dns-options-dup", test_capture_dns_options_dup);
+ g_test_add_func ("/resolvconf-capture/dns-options-valid4", test_capture_dns_options_valid4);
+ g_test_add_func ("/resolvconf-capture/dns-options-valid6", test_capture_dns_options_valid6);
return g_test_run ();
}