From 677cee0f232ac014b805af50e2010680c71f927e Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 24 Feb 2015 17:04:01 -0600 Subject: [PATCH] dhclient: use fqdn.fqdn for server DDNS updates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit dhclient only supports fqdn.fqdn for server DDNS updates with DHCPv6. And even though the underlying DHCP options that fqdn.fqdn controls allow non-qualified hostnames on the wire, dhclient does not. So we must require a fully-qualified name for DHCPv6. Second, while no-client-updates seems like it should be "off", doing that apparently makes dhclient set the "O" flag to 1 which appears to be a bug, and results in the server not doing the DDNS update. So we must stop setting that option too. Found by: Alexander Groß --- src/dhcp-manager/nm-dhcp-dhclient-utils.c | 29 ++++---- src/dhcp-manager/tests/test-dhcp-dhclient.c | 76 ++++++++++++++++++--- 2 files changed, 82 insertions(+), 23 deletions(-) diff --git a/src/dhcp-manager/nm-dhcp-dhclient-utils.c b/src/dhcp-manager/nm-dhcp-dhclient-utils.c index 13ec7a32a3..213d33a6a5 100644 --- a/src/dhcp-manager/nm-dhcp-dhclient-utils.c +++ b/src/dhcp-manager/nm-dhcp-dhclient-utils.c @@ -39,8 +39,8 @@ #define HOSTNAME4_TAG "send host-name" #define HOSTNAME4_FORMAT HOSTNAME4_TAG " \"%s\"; # added by NetworkManager" -#define HOSTNAME6_TAG "send fqdn.fqdn" -#define HOSTNAME6_FORMAT HOSTNAME6_TAG " \"%s\"; # added by NetworkManager" +#define FQDN_TAG "send fqdn.fqdn" +#define FQDN_FORMAT FQDN_TAG " \"%s\"; # added by NetworkManager" #define ALSOREQ_TAG "also request " @@ -57,7 +57,7 @@ add_also_request (GPtrArray *array, const char *item) } static void -add_hostname (GString *str, const char *format, const char *hostname) +add_hostname4 (GString *str, const char *format, const char *hostname) { char *plain_hostname, *dot; @@ -109,7 +109,7 @@ add_ip4_config (GString *str, GBytes *client_id, const char *hostname) g_string_append (str, "; # added by NetworkManager\n"); } - add_hostname (str, HOSTNAME4_FORMAT "\n", hostname); + add_hostname4 (str, HOSTNAME4_FORMAT "\n", hostname); g_string_append_c (str, '\n'); @@ -125,13 +125,18 @@ add_ip4_config (GString *str, GBytes *client_id, const char *hostname) } static void -add_ip6_config (GString *str, const char *hostname) +add_hostname6 (GString *str, const char *hostname) { - add_hostname (str, HOSTNAME6_FORMAT "\n", hostname); - g_string_append (str, - "send fqdn.encoded on;\n" - "send fqdn.no-client-update on;\n" - "send fqdn.server-update on;\n"); + /* dhclient only supports the fqdn.fqdn for DHCPv6 and requires a fully- + * qualified name for this option, so we must require one here too. + */ + if (hostname && strchr (hostname, '.')) { + g_string_append_printf (str, FQDN_FORMAT "\n", hostname); + g_string_append (str, + "send fqdn.encoded on;\n" + "send fqdn.server-update on;\n"); + g_string_append_c (str, '\n'); + } } static GBytes * @@ -232,7 +237,7 @@ nm_dhcp_dhclient_create_config (const char *interface, if (hostname) { if (strncmp (p, HOSTNAME4_TAG, strlen (HOSTNAME4_TAG)) == 0) continue; - if (strncmp (p, HOSTNAME6_TAG, strlen (HOSTNAME6_TAG)) == 0) + if (strncmp (p, FQDN_TAG, strlen (FQDN_TAG)) == 0) continue; } @@ -290,7 +295,7 @@ nm_dhcp_dhclient_create_config (const char *interface, g_string_append_c (new_contents, '\n'); if (is_ip6) { - add_ip6_config (new_contents, hostname); + add_hostname6 (new_contents, hostname); add_also_request (alsoreq, "dhcp6.name-servers"); add_also_request (alsoreq, "dhcp6.domain-search"); add_also_request (alsoreq, "dhcp6.client-id"); diff --git a/src/dhcp-manager/tests/test-dhcp-dhclient.c b/src/dhcp-manager/tests/test-dhcp-dhclient.c index 40f4f9e7ea..6e084579bd 100644 --- a/src/dhcp-manager/tests/test-dhcp-dhclient.c +++ b/src/dhcp-manager/tests/test-dhcp-dhclient.c @@ -39,6 +39,7 @@ static void test_config (const char *orig, const char *expected, + gboolean ipv6, const char *hostname, const char *dhcp_client_id, GBytes *expected_new_client_id, @@ -55,7 +56,7 @@ test_config (const char *orig, } new = nm_dhcp_dhclient_create_config (iface, - FALSE, + ipv6, client_id, anycast_addr, hostname, @@ -103,7 +104,7 @@ static const char *orig_missing_expected = \ static void test_orig_missing (void) { - test_config (NULL, orig_missing_expected, NULL, NULL, NULL, "eth0", NULL); + test_config (NULL, orig_missing_expected, FALSE, NULL, NULL, NULL, "eth0", NULL); } /*******************************************/ @@ -132,7 +133,7 @@ static void test_override_client_id (void) { test_config (override_client_id_orig, override_client_id_expected, - NULL, + FALSE, NULL, "11:22:33:44:55:66", NULL, "eth0", @@ -161,7 +162,7 @@ static void test_quote_client_id (void) { test_config (NULL, quote_client_id_expected, - NULL, + FALSE, NULL, "1234", NULL, "eth0", @@ -190,7 +191,7 @@ static void test_ascii_client_id (void) { test_config (NULL, ascii_client_id_expected, - NULL, + FALSE, NULL, "qb:cd:ef:12:34:56", NULL, "eth0", @@ -219,7 +220,7 @@ static void test_hex_single_client_id (void) { test_config (NULL, hex_single_client_id_expected, - NULL, + FALSE, NULL, "ab:cd:e:12:34:56", NULL, "eth0", @@ -256,7 +257,7 @@ test_existing_hex_client_id (void) new_client_id = g_bytes_new (bytes, sizeof (bytes)); test_config (existing_hex_client_id_orig, existing_hex_client_id_expected, - NULL, + FALSE, NULL, NULL, new_client_id, "eth0", @@ -296,7 +297,7 @@ test_existing_ascii_client_id (void) memcpy (buf + 1, EACID, STRLEN (EACID)); new_client_id = g_bytes_new (buf, sizeof (buf)); test_config (existing_ascii_client_id_orig, existing_ascii_client_id_expected, - NULL, + FALSE, NULL, NULL, new_client_id, "eth0", @@ -329,7 +330,58 @@ static void test_override_hostname (void) { test_config (override_hostname_orig, override_hostname_expected, - "blahblah", + FALSE, "blahblah", + NULL, + NULL, + "eth0", + NULL); +} + +/*******************************************/ + +static const char *override_hostname6_orig = \ + "send fqdn.fqdn \"foobar\";\n"; + +static const char *override_hostname6_expected = \ + "# Created by NetworkManager\n" + "# Merged from /path/to/dhclient.conf\n" + "\n" + "send fqdn.fqdn \"blahblah.local\"; # added by NetworkManager\n" + "send fqdn.encoded on;\n" + "send fqdn.server-update on;\n" + "\n" + "also request dhcp6.name-servers;\n" + "also request dhcp6.domain-search;\n" + "also request dhcp6.client-id;\n" + "\n"; + +static void +test_override_hostname6 (void) +{ + test_config (override_hostname6_orig, override_hostname6_expected, + TRUE, "blahblah.local", + NULL, + NULL, + "eth0", + NULL); +} + +/*******************************************/ + +static const char *nonfqdn_hostname6_expected = \ + "# Created by NetworkManager\n" + "\n" + "also request dhcp6.name-servers;\n" + "also request dhcp6.domain-search;\n" + "also request dhcp6.client-id;\n" + "\n"; + +static void +test_nonfqdn_hostname6 (void) +{ + /* Non-FQDN hostname can't be used with dhclient */ + test_config (NULL, nonfqdn_hostname6_expected, + TRUE, "blahblah", NULL, NULL, "eth0", @@ -364,7 +416,7 @@ static void test_existing_alsoreq (void) { test_config (existing_alsoreq_orig, existing_alsoreq_expected, - NULL, + FALSE, NULL, NULL, NULL, "eth0", @@ -403,7 +455,7 @@ static void test_existing_multiline_alsoreq (void) { test_config (existing_multiline_alsoreq_orig, existing_multiline_alsoreq_expected, - NULL, + FALSE, NULL, NULL, NULL, "eth0", @@ -721,6 +773,8 @@ main (int argc, char **argv) g_test_add_func ("/dhcp/dhclient/existing-hex-client-id", test_existing_hex_client_id); g_test_add_func ("/dhcp/dhclient/existing-ascii-client-id", test_existing_ascii_client_id); g_test_add_func ("/dhcp/dhclient/override_hostname", test_override_hostname); + g_test_add_func ("/dhcp/dhclient/override_hostname6", test_override_hostname6); + g_test_add_func ("/dhcp/dhclient/nonfqdn_hostname6", test_nonfqdn_hostname6); g_test_add_func ("/dhcp/dhclient/existing_alsoreq", test_existing_alsoreq); g_test_add_func ("/dhcp/dhclient/existing_multiline_alsoreq", test_existing_multiline_alsoreq); g_test_add_func ("/dhcp/dhclient/duids", test_duids);