diff --git a/src/nm-core-utils.c b/src/nm-core-utils.c index a56f4ccd9f..e39a568b26 100644 --- a/src/nm-core-utils.c +++ b/src/nm-core-utils.c @@ -1888,101 +1888,109 @@ nm_utils_new_infiniband_name (char *name, const char *parent_name, int p_key) return name; } -/** - * nm_utils_read_resolv_conf_nameservers(): - * @rc_contents: contents of a resolv.conf; or %NULL to read /etc/resolv.conf - * - * Reads all nameservers out of @rc_contents or /etc/resolv.conf and returns - * them. - * - * Returns: a #GPtrArray of 'char *' elements of each nameserver line from - * @contents or resolv.conf - */ -GPtrArray * -nm_utils_read_resolv_conf_nameservers (const char *rc_contents) +/*****************************************************************************/ + +gboolean +nm_utils_resolve_conf_parse (int addr_family, + const char *rc_contents, + GArray *nameservers, + GPtrArray *dns_options) { - GPtrArray *nameservers = NULL; - char *contents = NULL; - char **lines, **iter; - char *p; + guint i; + gboolean changed = FALSE; + gs_free const char **lines = NULL; + gsize l; - if (rc_contents) - contents = g_strdup (rc_contents); - else { - if (!g_file_get_contents (_PATH_RESCONF, &contents, NULL, NULL)) - return NULL; - } + g_return_val_if_fail (rc_contents, FALSE); + g_return_val_if_fail (nameservers, FALSE); + g_return_val_if_fail ( ( addr_family == AF_INET + && g_array_get_element_size (nameservers) == sizeof (in_addr_t)) + || ( addr_family == AF_INET6 + && g_array_get_element_size (nameservers) == sizeof (struct in6_addr)), FALSE); - nameservers = g_ptr_array_new_full (3, g_free); + lines = nm_utils_strsplit_set (rc_contents, "\r\n"); + if (!lines) + return FALSE; - lines = g_strsplit_set (contents, "\r\n", -1); - for (iter = lines; *iter; iter++) { - if (!g_str_has_prefix (*iter, "nameserver")) - continue; - p = *iter + strlen ("nameserver"); - if (!g_ascii_isspace (*p++)) - continue; - /* Skip intermediate whitespace */ - while (g_ascii_isspace (*p)) - p++; - g_strchomp (p); +/* like glibc's MATCH() macro in resolv/res_init.c. */ +#define RC_MATCH(line, option, out_arg) \ + ({ \ + const char *const _line = (line); \ + gboolean _match = FALSE; \ + \ + if ( (strncmp (_line, option, NM_STRLEN (option)) == 0) \ + && (NM_IN_SET (_line[NM_STRLEN (option)], ' ', '\t'))) { \ + _match = TRUE;\ + (out_arg) = &_line[NM_STRLEN (option) + 1]; \ + } \ + _match; \ + }) - g_ptr_array_add (nameservers, g_strdup (p)); - } - g_strfreev (lines); - g_free (contents); + for (l = 0; lines[l]; l++) { + const char *const line = lines[l]; + const char *s; - return nameservers; -} + if (RC_MATCH (line, "nameserver", s)) { + gs_free char *s_cpy = NULL; + NMIPAddr ns; -/** - * 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]) + s = nm_strstrip_avoid_copy (s, &s_cpy); + if (inet_pton (addr_family, s, &ns) != 1) continue; - g_ptr_array_add (options, g_strdup (*token_iter)); - } - g_strfreev (tokens); - } - g_strfreev (lines); - g_free (contents); - return options; + if (addr_family == AF_INET) { + if (!ns.addr4) + continue; + for (i = 0; i < nameservers->len; i++) { + if (g_array_index (nameservers, guint32, i) == ns.addr4) + break; + } + } else { + if (IN6_IS_ADDR_UNSPECIFIED (&ns.addr6)) + continue; + for (i = 0; i < nameservers->len; i++) { + struct in6_addr *t = &g_array_index (nameservers, struct in6_addr, i); + + if (IN6_ARE_ADDR_EQUAL (t, &ns.addr6)) + break; + } + } + + if (i == nameservers->len) { + g_array_append_val (nameservers, ns); + changed = TRUE; + } + continue; + } + + if (RC_MATCH (line, "options", s)) { + if (!dns_options) + continue; + + s = nm_str_skip_leading_spaces (s); + if (s[0]) { + gs_free const char **tokens = NULL; + gsize i_tokens; + + tokens = nm_utils_strsplit_set (s, " \t"); + nm_assert (tokens); + for (i_tokens = 0; tokens[i_tokens]; i_tokens++) { + gs_free char *t = g_strstrip (g_strdup (tokens[i_tokens])); + + if ( _nm_utils_dns_option_validate (t, NULL, NULL, + addr_family == AF_INET6, + _nm_utils_dns_option_descs) + && _nm_utils_dns_option_find_idx (dns_options, t) < 0) { + g_ptr_array_add (dns_options, g_steal_pointer (&t)); + changed = TRUE; + } + } + } + continue; + } + } + + return changed; } /*****************************************************************************/ diff --git a/src/nm-core-utils.h b/src/nm-core-utils.h index 5221822d96..d94fba9df0 100644 --- a/src/nm-core-utils.h +++ b/src/nm-core-utils.h @@ -224,8 +224,10 @@ gboolean nm_utils_connection_has_default_route (NMConnection *connection, char *nm_utils_new_vlan_name (const char *parent_iface, guint32 vlan_id); const char *nm_utils_new_infiniband_name (char *name, const char *parent_name, int p_key); -GPtrArray *nm_utils_read_resolv_conf_nameservers (const char *rc_contents); -GPtrArray *nm_utils_read_resolv_conf_dns_options (const char *rc_contents); +gboolean nm_utils_resolve_conf_parse (int addr_family, + const char *rc_contents, + GArray *nameservers, + GPtrArray *dns_options); int nm_utils_cmp_connection_by_autoconnect_priority (NMConnection *a, NMConnection *b); diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c index 91e72686a4..9727ace126 100644 --- a/src/nm-ip4-config.c +++ b/src/nm-ip4-config.c @@ -25,6 +25,7 @@ #include #include +#include #include "nm-utils/nm-dedup-multi.h" @@ -516,72 +517,6 @@ _notify_routes (NMIP4Config *self) /*****************************************************************************/ -/** - * nm_ip4_config_capture_resolv_conf(): - * @nameservers: array of guint32 - * @rc_contents: the contents of a resolv.conf or %NULL to read /etc/resolv.conf - * - * Reads all resolv.conf IPv4 nameservers and adds them to @nameservers. - * - * Returns: %TRUE if nameservers were added, %FALSE if @nameservers is unchanged - */ -gboolean -nm_ip4_config_capture_resolv_conf (GArray *nameservers, - GPtrArray *dns_options, - const char *rc_contents) -{ - GPtrArray *read_ns, *read_options; - guint i, j; - gboolean changed = FALSE; - - g_return_val_if_fail (nameservers != NULL, FALSE); - - read_ns = nm_utils_read_resolv_conf_nameservers (rc_contents); - if (!read_ns) - return FALSE; - - for (i = 0; i < read_ns->len; i++) { - const char *s = g_ptr_array_index (read_ns, i); - guint32 ns = 0; - - if (!inet_pton (AF_INET, s, (void *) &ns) || !ns) - continue; - - /* Ignore duplicates */ - for (j = 0; j < nameservers->len; j++) { - if (g_array_index (nameservers, guint32, j) == ns) - break; - } - - if (j == nameservers->len) { - g_array_append_val (nameservers, ns); - 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, _nm_utils_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; -} - -/*****************************************************************************/ - static gint _addresses_sort_cmp_get_prio (in_addr_t addr) { @@ -716,8 +651,15 @@ nm_ip4_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int i * nameservers from /etc/resolv.conf. */ if (has_addresses && priv->has_gateway && capture_resolv_conf) { - if (nm_ip4_config_capture_resolv_conf (priv->nameservers, priv->dns_options, NULL)) - _notify (self, PROP_NAMESERVERS); + gs_free char *rc_contents = NULL; + + if (g_file_get_contents (_PATH_RESCONF, &rc_contents, NULL, NULL)) { + if (nm_utils_resolve_conf_parse (AF_INET, + rc_contents, + priv->nameservers, + priv->dns_options)) + _notify (self, PROP_NAMESERVERS); + } } /* actually, nobody should be connected to the signal, just to be sure, notify */ diff --git a/src/nm-ip4-config.h b/src/nm-ip4-config.h index fcd04beaa5..a6df1e9db9 100644 --- a/src/nm-ip4-config.h +++ b/src/nm-ip4-config.h @@ -261,10 +261,4 @@ gboolean nm_ip4_config_nmpobj_remove (NMIP4Config *self, void nm_ip4_config_hash (const NMIP4Config *self, GChecksum *sum, gboolean dns_only); gboolean nm_ip4_config_equal (const NMIP4Config *a, const NMIP4Config *b); -/*****************************************************************************/ -/* Testing-only functions */ - -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 699c60d3b2..923d2da9bb 100644 --- a/src/nm-ip6-config.c +++ b/src/nm-ip6-config.c @@ -25,6 +25,7 @@ #include #include +#include #include "nm-utils/nm-dedup-multi.h" @@ -229,72 +230,6 @@ _notify_routes (NMIP6Config *self) /*****************************************************************************/ -/** - * nm_ip6_config_capture_resolv_conf(): - * @nameservers: array of struct in6_addr - * @rc_contents: the contents of a resolv.conf or %NULL to read /etc/resolv.conf - * - * Reads all resolv.conf IPv6 nameservers and adds them to @nameservers. - * - * Returns: %TRUE if nameservers were added, %FALSE if @nameservers is unchanged - */ -gboolean -nm_ip6_config_capture_resolv_conf (GArray *nameservers, - GPtrArray *dns_options, - const char *rc_contents) -{ - GPtrArray *read_ns, *read_options; - guint i, j; - gboolean changed = FALSE; - - g_return_val_if_fail (nameservers != NULL, FALSE); - - read_ns = nm_utils_read_resolv_conf_nameservers (rc_contents); - if (!read_ns) - return FALSE; - - for (i = 0; i < read_ns->len; i++) { - const char *s = g_ptr_array_index (read_ns, i); - struct in6_addr ns = IN6ADDR_ANY_INIT; - - if (!inet_pton (AF_INET6, s, (void *) &ns) || IN6_IS_ADDR_UNSPECIFIED (&ns)) - continue; - - /* Ignore duplicates */ - for (j = 0; j < nameservers->len; j++) { - struct in6_addr *t = &g_array_index (nameservers, struct in6_addr, j); - - if (IN6_ARE_ADDR_EQUAL (t, &ns)) - break; - } - - if (j == nameservers->len) { - g_array_append_val (nameservers, ns); - 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, _nm_utils_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; -} - static gint _addresses_sort_cmp_get_prio (const struct in6_addr *addr) { @@ -444,7 +379,6 @@ nm_ip6_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int i const NMDedupMultiHeadEntry *head_entry; NMDedupMultiIter iter; const NMPObject *plobj = NULL; - gboolean notify_nameservers = FALSE; gboolean has_addresses = FALSE; nm_assert (ifindex > 0); @@ -512,14 +446,19 @@ nm_ip6_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int i /* If the interface has the default route, and has IPv6 addresses, capture * nameservers from /etc/resolv.conf. */ - if (has_addresses && has_gateway && capture_resolv_conf) - notify_nameservers = nm_ip6_config_capture_resolv_conf (priv->nameservers, - priv->dns_options, - NULL); + if (has_addresses && has_gateway && capture_resolv_conf) { + gs_free char *rc_contents = NULL; + + if (g_file_get_contents (_PATH_RESCONF, &rc_contents, NULL, NULL)) { + if (nm_utils_resolve_conf_parse (AF_INET6, + rc_contents, + priv->nameservers, + priv->dns_options)) + _notify (self, PROP_NAMESERVERS); + } + } /* actually, nobody should be connected to the signal, just to be sure, notify */ - if (notify_nameservers) - _notify (self, PROP_NAMESERVERS); _notify_addresses (self); _notify_routes (self); if (!IN6_ARE_ADDR_EQUAL (&priv->gateway, &old_gateway)) diff --git a/src/nm-ip6-config.h b/src/nm-ip6-config.h index ef828d5c0d..f8365dfc84 100644 --- a/src/nm-ip6-config.h +++ b/src/nm-ip6-config.h @@ -215,11 +215,4 @@ void nm_ip6_config_reset_routes_ndisc (NMIP6Config *self, guint routes_n, guint32 metric); -/*****************************************************************************/ -/* 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/tests/test-resolvconf-capture.c b/src/tests/test-resolvconf-capture.c index dc77c06ac2..2c34ff74d9 100644 --- a/src/tests/test-resolvconf-capture.c +++ b/src/tests/test-resolvconf-capture.c @@ -36,10 +36,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, NULL, "") == FALSE); + g_assert (!nm_utils_resolve_conf_parse (AF_INET, "", ns4, NULL)); g_assert_cmpint (ns4->len, ==, 0); - g_assert (nm_ip6_config_capture_resolv_conf (ns6, NULL, "") == FALSE); + g_assert (!nm_utils_resolve_conf_parse (AF_INET6, "", ns6, NULL)); g_assert_cmpint (ns6->len, ==, 0); g_array_free (ns4, TRUE); @@ -66,7 +66,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, NULL, rc)); + g_assert (nm_utils_resolve_conf_parse (AF_INET, rc, ns4, NULL)); g_assert_cmpint (ns4->len, ==, 2); assert_dns4_entry (ns4, 0, "4.2.2.1"); assert_dns4_entry (ns4, 1, "4.2.2.2"); @@ -87,7 +87,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, NULL, rc)); + g_assert (nm_utils_resolve_conf_parse (AF_INET, rc, ns4, NULL)); g_assert_cmpint (ns4->len, ==, 2); assert_dns4_entry (ns4, 0, "4.2.2.1"); assert_dns4_entry (ns4, 1, "4.2.2.2"); @@ -106,7 +106,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, NULL, rc)); + g_assert (nm_utils_resolve_conf_parse (AF_INET6, rc, ns6, NULL)); g_assert_cmpint (ns6->len, ==, 2); assert_dns6_entry (ns6, 0, "2001:4860:4860::8888"); assert_dns6_entry (ns6, 1, "2001:4860:4860::8844"); @@ -127,7 +127,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, NULL, rc)); + g_assert (nm_utils_resolve_conf_parse (AF_INET6, rc, ns6, NULL)); g_assert_cmpint (ns6->len, ==, 2); assert_dns6_entry (ns6, 0, "2001:4860:4860::8888"); assert_dns6_entry (ns6, 1, "2001:4860:4860::8844"); @@ -147,7 +147,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, NULL, rc)); + g_assert (nm_utils_resolve_conf_parse (AF_INET, rc, ns4, NULL)); g_assert_cmpint (ns4->len, ==, 2); assert_dns4_entry (ns4, 0, "4.2.2.1"); assert_dns4_entry (ns4, 1, "4.2.2.2"); @@ -167,7 +167,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, NULL, rc)); + g_assert (nm_utils_resolve_conf_parse (AF_INET6, rc, ns6, NULL)); g_assert_cmpint (ns6->len, ==, 2); assert_dns6_entry (ns6, 0, "2001:4860:4860::8888"); assert_dns6_entry (ns6, 1, "2001:4860:4860::8844"); @@ -182,15 +182,17 @@ test_capture_format (void) const char *rc = " nameserver 4.2.2.1\r\n" /* bad */ "nameserver4.2.2.1\r\n" /* bad */ -"nameserver 4.2.2.3\r" /* good */ +"nameserver 4.2.2.3\r" /* good */ "nameserver\t\t4.2.2.4\r\n" /* good */ -"nameserver 4.2.2.5\t\t\r\n"; /* good */ +"nameserver 4.2.2.5\t\t\r\n" /* good */ +"nameserver 4.2.2.6 \r\n"; /* good */ - g_assert (nm_ip4_config_capture_resolv_conf (ns4, NULL, rc)); - g_assert_cmpint (ns4->len, ==, 3); + g_assert (nm_utils_resolve_conf_parse (AF_INET, rc, ns4, NULL)); + g_assert_cmpint (ns4->len, ==, 4); assert_dns4_entry (ns4, 0, "4.2.2.3"); assert_dns4_entry (ns4, 1, "4.2.2.4"); assert_dns4_entry (ns4, 2, "4.2.2.5"); + assert_dns4_entry (ns4, 3, "4.2.2.6"); g_array_free (ns4, TRUE); } @@ -205,7 +207,7 @@ test_capture_dns_options (void) "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 (nm_utils_resolve_conf_parse (AF_INET, rc, ns4, dns_options)); g_assert_cmpint (dns_options->len, ==, 4); assert_dns_option (dns_options, 0, "debug"); assert_dns_option (dns_options, 1, "rotate"); @@ -226,7 +228,7 @@ test_capture_dns_options_dup (void) "options edns0 debug\r\n" "options timeout:5\r\n"; - g_assert (nm_ip4_config_capture_resolv_conf (ns4, dns_options, rc)); + g_assert (nm_utils_resolve_conf_parse (AF_INET, rc, ns4, dns_options)); g_assert_cmpint (dns_options->len, ==, 4); assert_dns_option (dns_options, 0, "debug"); assert_dns_option (dns_options, 1, "rotate"); @@ -245,7 +247,7 @@ test_capture_dns_options_valid4 (void) 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 (nm_utils_resolve_conf_parse (AF_INET, rc, ns4, dns_options)); g_assert_cmpint (dns_options->len, ==, 1); assert_dns_option (dns_options, 0, "edns0"); @@ -256,12 +258,12 @@ test_capture_dns_options_valid4 (void) static void test_capture_dns_options_valid6 (void) { - GArray *ns6 = g_array_new (FALSE, FALSE, sizeof (guint32)); + GArray *ns6 = g_array_new (FALSE, FALSE, sizeof (struct in6_addr)); 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 (nm_utils_resolve_conf_parse (AF_INET6, rc, ns6, dns_options)); g_assert_cmpint (dns_options->len, ==, 2); assert_dns_option (dns_options, 0, "inet6"); assert_dns_option (dns_options, 1, "debug");