dhcp/nettools: move nm_dhcp_lease_data_parse_search_list() to nm-dhcp-utils.c

This commit is contained in:
Thomas Haller 2021-02-10 16:50:34 +01:00
parent 67dd25a396
commit 6e0d2e5850
No known key found for this signature in database
GPG key ID: 29C2366E4DFC5728
4 changed files with 173 additions and 160 deletions

View file

@ -158,130 +158,6 @@ lease_option_consume_route(uint8_t ** datap,
/*****************************************************************************/
static gboolean
lease_option_print_label(GString *str, size_t n_label, uint8_t **datap, size_t *n_datap)
{
for (size_t i = 0; i < n_label; ++i) {
uint8_t c;
if (!lease_option_consume(datap, n_datap, &c, sizeof(c)))
return FALSE;
switch (c) {
case 'a' ... 'z':
case 'A' ... 'Z':
case '0' ... '9':
case '-':
case '_':
g_string_append_c(str, c);
break;
case '.':
case '\\':
g_string_append_printf(str, "\\%c", c);
break;
default:
g_string_append_printf(str, "\\%3d", c);
}
}
return TRUE;
}
static gboolean
lease_option_print_domain_name(GString * str,
uint8_t * cache,
size_t * n_cachep,
uint8_t **datap,
size_t * n_datap)
{
uint8_t * domain;
size_t n_domain, n_cache = *n_cachep;
uint8_t **domainp = datap;
size_t * n_domainp = n_datap;
gboolean first = TRUE;
uint8_t c;
/*
* We are given two adjacent memory regions. The @cache contains alreday parsed
* domain names, and the @datap contains the remaining data to parse.
*
* A domain name is formed from a sequence of labels. Each label start with
* a length byte, where the two most significant bits are unset. A zero-length
* label indicates the end of the domain name.
*
* Alternatively, a label can be followed by an offset (indicated by the two
* most significant bits being set in the next byte that is read). The offset
* is an offset into the cache, where the next label of the domain name can
* be found.
*
* Note, that each time a jump to an offset is performed, the size of the
* cache shrinks, so this is guaranteed to terminate.
*/
if (cache + n_cache != *datap)
return FALSE;
for (;;) {
if (!lease_option_consume(domainp, n_domainp, &c, sizeof(c)))
return FALSE;
switch (c & 0xC0) {
case 0x00: /* label length */
{
size_t n_label = c;
if (n_label == 0) {
/*
* We reached the final label of the domain name. Adjust
* the cache to include the consumed data, and return.
*/
*n_cachep = *datap - cache;
return TRUE;
}
if (!first)
g_string_append_c(str, '.');
else
first = FALSE;
if (!lease_option_print_label(str, n_label, domainp, n_domainp))
return FALSE;
break;
}
case 0xC0: /* back pointer */
{
size_t offset = (c & 0x3F) << 16;
/*
* The offset is given as two bytes (in big endian), where the
* two high bits are masked out.
*/
if (!lease_option_consume(domainp, n_domainp, &c, sizeof(c)))
return FALSE;
offset += c;
if (offset >= n_cache)
return FALSE;
domain = cache + offset;
n_domain = n_cache - offset;
n_cache = offset;
domainp = &domain;
n_domainp = &n_domain;
break;
}
default:
return FALSE;
}
}
}
/*****************************************************************************/
static gboolean
lease_parse_address(NDhcp4ClientLease *lease,
NMIP4Config * ip4_config,
@ -623,35 +499,6 @@ lease_parse_routes(NDhcp4ClientLease *lease,
/*****************************************************************************/
char **
nm_dhcp_parse_search_list(guint8 *data, size_t n_data)
{
GPtrArray *array = NULL;
guint8 * cache = data;
size_t n_cache = 0;
for (;;) {
nm_auto_free_gstring GString *domain = NULL;
nm_gstring_prepare(&domain);
if (!lease_option_print_domain_name(domain, cache, &n_cache, &data, &n_data))
break;
if (!array)
array = g_ptr_array_new();
g_ptr_array_add(array, g_string_free(domain, FALSE));
domain = NULL;
}
if (array) {
g_ptr_array_add(array, NULL);
return (char **) g_ptr_array_free(array, FALSE);
} else
return NULL;
}
static void
lease_parse_search_domains(NDhcp4ClientLease *lease, NMIP4Config *ip4_config, GHashTable *options)
{
@ -666,7 +513,7 @@ lease_parse_search_domains(NDhcp4ClientLease *lease, NMIP4Config *ip4_config, GH
if (r)
return;
domains = nm_dhcp_parse_search_list(data, n_data);
domains = nm_dhcp_lease_data_parse_search_list(data, n_data);
nm_gstring_prepare(&str);
for (i = 0; domains && domains[i]; i++) {

View file

@ -964,3 +964,158 @@ nm_dhcp_lease_data_parse_in_addr(const guint8 *data, gsize n_data, in_addr_t *ou
*out_val = unaligned_read_ne32(data);
return TRUE;
}
/*****************************************************************************/
static gboolean
lease_option_print_label(GString *str, size_t n_label, const uint8_t **datap, size_t *n_datap)
{
gsize i;
for (i = 0; i < n_label; ++i) {
uint8_t c = 0;
if (!nm_dhcp_lease_data_consume(datap, n_datap, &c, sizeof(c)))
return FALSE;
switch (c) {
case 'a' ... 'z':
case 'A' ... 'Z':
case '0' ... '9':
case '-':
case '_':
g_string_append_c(str, c);
break;
case '.':
case '\\':
g_string_append_printf(str, "\\%c", c);
break;
default:
g_string_append_printf(str, "\\%3d", c);
}
}
return TRUE;
}
static gboolean
lease_option_print_domain_name(GString * str,
const uint8_t * cache,
size_t * n_cachep,
const uint8_t **datap,
size_t * n_datap)
{
const uint8_t * domain;
size_t n_domain, n_cache = *n_cachep;
const uint8_t **domainp = datap;
size_t * n_domainp = n_datap;
gboolean first = TRUE;
uint8_t c;
/*
* We are given two adjacent memory regions. The @cache contains alreday parsed
* domain names, and the @datap contains the remaining data to parse.
*
* A domain name is formed from a sequence of labels. Each label start with
* a length byte, where the two most significant bits are unset. A zero-length
* label indicates the end of the domain name.
*
* Alternatively, a label can be followed by an offset (indicated by the two
* most significant bits being set in the next byte that is read). The offset
* is an offset into the cache, where the next label of the domain name can
* be found.
*
* Note, that each time a jump to an offset is performed, the size of the
* cache shrinks, so this is guaranteed to terminate.
*/
if (cache + n_cache != *datap)
return FALSE;
for (;;) {
if (!nm_dhcp_lease_data_consume(domainp, n_domainp, &c, sizeof(c)))
return FALSE;
switch (c & 0xC0) {
case 0x00: /* label length */
{
size_t n_label = c;
if (n_label == 0) {
/*
* We reached the final label of the domain name. Adjust
* the cache to include the consumed data, and return.
*/
*n_cachep = *datap - cache;
return TRUE;
}
if (!first)
g_string_append_c(str, '.');
else
first = FALSE;
if (!lease_option_print_label(str, n_label, domainp, n_domainp))
return FALSE;
break;
}
case 0xC0: /* back pointer */
{
size_t offset = (c & 0x3F) << 16;
/*
* The offset is given as two bytes (in big endian), where the
* two high bits are masked out.
*/
if (!nm_dhcp_lease_data_consume(domainp, n_domainp, &c, sizeof(c)))
return FALSE;
offset += c;
if (offset >= n_cache)
return FALSE;
domain = cache + offset;
n_domain = n_cache - offset;
n_cache = offset;
domainp = &domain;
n_domainp = &n_domain;
break;
}
default:
return FALSE;
}
}
}
char **
nm_dhcp_lease_data_parse_search_list(const guint8 *data, gsize n_data)
{
GPtrArray * array = NULL;
const guint8 *cache = data;
gsize n_cache = 0;
for (;;) {
nm_auto_free_gstring GString *domain = NULL;
nm_gstring_prepare(&domain);
if (!lease_option_print_domain_name(domain, cache, &n_cache, &data, &n_data))
break;
if (!array)
array = g_ptr_array_new();
g_ptr_array_add(array, g_string_free(domain, FALSE));
domain = NULL;
}
if (array) {
g_ptr_array_add(array, NULL);
return (char **) g_ptr_array_free(array, FALSE);
} else
return NULL;
}

View file

@ -36,12 +36,22 @@ gboolean nm_dhcp_utils_get_leasefile_path(int addr_family,
const char *uuid,
char ** out_leasefile_path);
char **nm_dhcp_parse_search_list(guint8 *data, size_t n_data);
char *nm_dhcp_utils_get_dhcp6_event_id(GHashTable *lease);
/*****************************************************************************/
static inline gboolean
nm_dhcp_lease_data_consume(const uint8_t **datap, size_t *n_datap, void *out, size_t n_out)
{
if (*n_datap < n_out)
return FALSE;
memcpy(out, *datap, n_out);
*datap += n_out;
*n_datap -= n_out;
return TRUE;
}
char *nm_dhcp_lease_data_parse_domain_validate(const char *str);
gboolean nm_dhcp_lease_data_parse_u16(const guint8 *data, gsize n_data, guint16 *out_val);
@ -49,5 +59,6 @@ gboolean nm_dhcp_lease_data_parse_mtu(const guint8 *data, gsize n_data, guint16
gboolean nm_dhcp_lease_data_parse_cstr(const guint8 *data, gsize n_data, gsize *out_new_len);
gboolean nm_dhcp_lease_data_parse_domain(const guint8 *data, gsize n_data, char **out_val);
gboolean nm_dhcp_lease_data_parse_in_addr(const guint8 *data, gsize n_data, in_addr_t *out_val);
char ** nm_dhcp_lease_data_parse_search_list(const guint8 *data, gsize n_data);
#endif /* __NETWORKMANAGER_DHCP_UTILS_H__ */

View file

@ -202,7 +202,7 @@ test_parse_search_list(void)
char ** domains;
data = (guint8[]){0x05, 'l', 'o', 'c', 'a', 'l', 0x00};
domains = nm_dhcp_parse_search_list(data, 7);
domains = nm_dhcp_lease_data_parse_search_list(data, 7);
g_assert(domains);
g_assert_cmpint(g_strv_length(domains), ==, 1);
g_assert_cmpstr(domains[0], ==, "local");
@ -211,7 +211,7 @@ test_parse_search_list(void)
data = (guint8[]){0x04, 't', 'e', 's', 't', 0x07, 'e', 'x', 'a', 'm', 'p', 'l',
'e', 0x03, 'c', 'o', 'm', 0x00, 0xc0, 0x05, 0x03, 'a', 'b', 'c',
0xc0, 0x0d, 0x06, 'f', 'o', 'o', 'b', 'a', 'r', 0x00};
domains = nm_dhcp_parse_search_list(data, 34);
domains = nm_dhcp_lease_data_parse_search_list(data, 34);
g_assert(domains);
g_assert_cmpint(g_strv_length(domains), ==, 4);
g_assert_cmpstr(domains[0], ==, "test.example.com");
@ -226,7 +226,7 @@ test_parse_search_list(void)
'a',
'd',
};
domains = nm_dhcp_parse_search_list(data, 4);
domains = nm_dhcp_lease_data_parse_search_list(data, 4);
g_assert(!domains);
data = (guint8[]){
@ -241,7 +241,7 @@ test_parse_search_list(void)
'a',
'd',
};
domains = nm_dhcp_parse_search_list(data, 10);
domains = nm_dhcp_lease_data_parse_search_list(data, 10);
g_assert(domains);
g_assert_cmpint(g_strv_length(domains), ==, 1);
g_assert_cmpstr(domains[0], ==, "okay");