dhcp: preserve DHCPv4 client ID for later use

If we can, read the existing client ID from the leasefile and preserve
it for later use.
This commit is contained in:
Dan Williams
2014-11-03 14:39:25 -06:00
parent 318a8c2d72
commit e43174f368
9 changed files with 327 additions and 83 deletions

View File

@@ -26,14 +26,14 @@
#include <arpa/inet.h>
#include "nm-dhcp-dhclient-utils.h"
#include "nm-dhcp-utils.h"
#include "nm-ip4-config.h"
#include "nm-utils.h"
#include "nm-platform.h"
#include "NetworkManagerUtils.h"
#include "gsystem-local-alloc.h"
#define CLIENTID_TAG "send dhcp-client-identifier"
#define CLIENTID_FORMAT CLIENTID_TAG " \"%s\"; # added by NetworkManager"
#define CLIENTID_FORMAT_OCTETS CLIENTID_TAG " %s; # added by NetworkManager"
#define HOSTNAME4_TAG "send host-name"
#define HOSTNAME4_FORMAT HOSTNAME4_TAG " \"%s\"; # added by NetworkManager"
@@ -73,40 +73,39 @@ add_hostname (GString *str, const char *format, const char *hostname)
}
static void
add_ip4_config (GString *str, const char *dhcp_client_id, const char *hostname)
add_ip4_config (GString *str, GBytes *client_id, const char *hostname)
{
if (dhcp_client_id && *dhcp_client_id) {
gboolean is_octets = TRUE;
int i = 0;
if (client_id) {
const char *p;
gsize l;
guint i;
while (dhcp_client_id[i]) {
if (!g_ascii_isxdigit (dhcp_client_id[i])) {
is_octets = FALSE;
p = g_bytes_get_data (client_id, &l);
g_assert (p);
/* Allow type 0 (non-hardware address) to be represented as a string
* as long as all the characters are printable.
*/
for (i = 1; (p[0] == 0) && i < l; i++) {
if (!g_ascii_isprint (p[i]))
break;
}
i++;
if (!dhcp_client_id[i])
break;
if (g_ascii_isxdigit (dhcp_client_id[i])) {
i++;
if (!dhcp_client_id[i])
break;
}
if (dhcp_client_id[i] != ':') {
is_octets = FALSE;
break;
}
i++;
}
/* If the client ID is just hex digits and : then don't use quotes,
* because dhclient expects either a quoted ASCII string, or a byte
* array formated as hex octets separated by :
*/
if (is_octets)
g_string_append_printf (str, CLIENTID_FORMAT_OCTETS "\n", dhcp_client_id);
else
g_string_append_printf (str, CLIENTID_FORMAT "\n", dhcp_client_id);
g_string_append (str, CLIENTID_TAG " ");
if (i < l) {
/* Unprintable; convert to a hex string */
for (i = 0; i < l; i++) {
if (i > 0)
g_string_append_c (str, ':');
g_string_append_printf (str, "%02x", (guint8) p[i]);
}
} else {
/* Printable; just add to the line minus the 'type' */
g_string_append_c (str, '"');
g_string_append_len (str, p + 1, l - 1);
g_string_append_c (str, '"');
}
g_string_append (str, "; # added by NetworkManager\n");
}
add_hostname (str, HOSTNAME4_FORMAT "\n", hostname);
@@ -134,14 +133,67 @@ add_ip6_config (GString *str, const char *hostname)
"send fqdn.server-update on;\n");
}
static GBytes *
read_client_id (const char *str)
{
gs_free char *s = NULL;
char *p;
g_assert (!strncmp (str, CLIENTID_TAG, STRLEN (CLIENTID_TAG)));
str += STRLEN (CLIENTID_TAG);
while (g_ascii_isspace (*str))
str++;
if (*str == '"') {
s = g_strdup (str + 1);
p = strrchr (s, '"');
if (p)
*p = '\0';
else
return NULL;
} else
s = g_strdup (str);
g_strchomp (s);
if (s[strlen (s) - 1] == ';')
s[strlen (s) - 1] = '\0';
return nm_dhcp_utils_client_id_string_to_bytes (s);
}
GBytes *
nm_dhcp_dhclient_get_client_id_from_config_file (const char *path)
{
gs_free char *contents = NULL;
gs_strfreev char **lines = NULL;
char **line;
g_return_val_if_fail (path != NULL, NULL);
if (!g_file_test (path, G_FILE_TEST_EXISTS))
return NULL;
if (!g_file_get_contents (path, &contents, NULL, NULL))
return NULL;
lines = g_strsplit_set (contents, "\n\r", 0);
for (line = lines; lines && *line; line++) {
if (!strncmp (*line, CLIENTID_TAG, STRLEN (CLIENTID_TAG)))
return read_client_id (*line);
}
return NULL;
}
char *
nm_dhcp_dhclient_create_config (const char *interface,
gboolean is_ip6,
const char *dhcp_client_id,
GBytes *client_id,
const char *anycast_addr,
const char *hostname,
const char *orig_path,
const char *orig_contents)
const char *orig_contents,
GBytes **out_new_client_id)
{
GString *new_contents;
GPtrArray *alsoreq;
@@ -165,11 +217,15 @@ nm_dhcp_dhclient_create_config (const char *interface,
if (!strlen (g_strstrip (p)))
continue;
/* Override config file "dhcp-client-id" and use one from the
* connection.
*/
if (dhcp_client_id && !strncmp (p, CLIENTID_TAG, strlen (CLIENTID_TAG)))
continue;
if (!strncmp (p, CLIENTID_TAG, strlen (CLIENTID_TAG))) {
/* Override config file "dhcp-client-id" and use one from the connection */
if (client_id)
continue;
/* Otherwise capture and return the existing client id */
if (out_new_client_id)
*out_new_client_id = read_client_id (p);
}
/* Override config file hostname and use one from the connection */
if (hostname) {
@@ -238,7 +294,7 @@ nm_dhcp_dhclient_create_config (const char *interface,
add_also_request (alsoreq, "dhcp6.domain-search");
add_also_request (alsoreq, "dhcp6.client-id");
} else {
add_ip4_config (new_contents, dhcp_client_id, hostname);
add_ip4_config (new_contents, client_id, hostname);
add_also_request (alsoreq, "rfc3442-classless-static-routes");
add_also_request (alsoreq, "ms-classless-static-routes");
add_also_request (alsoreq, "static-routes");