mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-02-04 15:20:28 +01:00
dhcp: merge branch 'th/dhcp-nettools-lease-parse'
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/750
This commit is contained in:
commit
a21fdd4237
15 changed files with 1047 additions and 819 deletions
|
|
@ -3623,7 +3623,8 @@ nm_utils_file_search_in_paths(const char * progname,
|
|||
if (!path[0])
|
||||
continue;
|
||||
|
||||
nm_str_buf_reset(&strbuf, path);
|
||||
nm_str_buf_reset(&strbuf);
|
||||
nm_str_buf_append(&strbuf, path);
|
||||
nm_str_buf_ensure_trailing_c(&strbuf, '/');
|
||||
s = nm_str_buf_append0(&strbuf, progname);
|
||||
|
||||
|
|
|
|||
|
|
@ -786,27 +786,27 @@ nm_utils_ip6_address_same_prefix_cmp(const struct in6_addr *addr_a,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* _nm_utils_ip4_get_default_prefix:
|
||||
* @ip: an IPv4 address (in network byte order)
|
||||
*
|
||||
* When the Internet was originally set up, various ranges of IP addresses were
|
||||
* segmented into three network classes: A, B, and C. This function will return
|
||||
* a prefix that is associated with the IP address specified defining where it
|
||||
* falls in the predefined classes.
|
||||
*
|
||||
* Returns: the default class prefix for the given IP
|
||||
**/
|
||||
/* The function is originally from ipcalc.c of Red Hat's initscripts. */
|
||||
guint32
|
||||
_nm_utils_ip4_get_default_prefix(guint32 ip)
|
||||
{
|
||||
if (((ntohl(ip) & 0xFF000000) >> 24) <= 127)
|
||||
return 8; /* Class A - 255.0.0.0 */
|
||||
else if (((ntohl(ip) & 0xFF000000) >> 24) <= 191)
|
||||
return 16; /* Class B - 255.255.0.0 */
|
||||
/*****************************************************************************/
|
||||
|
||||
return 24; /* Class C - 255.255.255.0 */
|
||||
guint32
|
||||
_nm_utils_ip4_get_default_prefix0(in_addr_t ip)
|
||||
{
|
||||
/* The function is originally from ipcalc.c of Red Hat's initscripts. */
|
||||
switch (ntohl(ip) >> 24) {
|
||||
case 0 ... 127:
|
||||
return 8; /* Class A */
|
||||
case 128 ... 191:
|
||||
return 16; /* Class B */
|
||||
case 192 ... 223:
|
||||
return 24; /* Class C */
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
guint32
|
||||
_nm_utils_ip4_get_default_prefix(in_addr_t ip)
|
||||
{
|
||||
return _nm_utils_ip4_get_default_prefix0(ip) ?: 24;
|
||||
}
|
||||
|
||||
gboolean
|
||||
|
|
|
|||
|
|
@ -699,7 +699,8 @@ nm_utils_escaped_tokens_options_escape_val(const char *val, char **out_to_free)
|
|||
/*****************************************************************************/
|
||||
|
||||
guint32 _nm_utils_ip4_prefix_to_netmask(guint32 prefix);
|
||||
guint32 _nm_utils_ip4_get_default_prefix(guint32 ip);
|
||||
guint32 _nm_utils_ip4_get_default_prefix0(in_addr_t ip);
|
||||
guint32 _nm_utils_ip4_get_default_prefix(in_addr_t ip);
|
||||
|
||||
gconstpointer
|
||||
nm_utils_ipx_address_clear_host_address(int family, gpointer dst, gconstpointer src, guint8 plen);
|
||||
|
|
|
|||
|
|
@ -292,8 +292,10 @@ nm_str_buf_append_c_len(NMStrBuf *strbuf, char ch, gsize len)
|
|||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
nm_str_buf_reset(NMStrBuf *strbuf, const char *str)
|
||||
/*****************************************************************************/
|
||||
|
||||
static inline NMStrBuf *
|
||||
nm_str_buf_reset(NMStrBuf *strbuf)
|
||||
{
|
||||
_nm_str_buf_assert(strbuf);
|
||||
|
||||
|
|
@ -305,8 +307,7 @@ nm_str_buf_reset(NMStrBuf *strbuf, const char *str)
|
|||
strbuf->_priv_len = 0;
|
||||
}
|
||||
|
||||
if (str)
|
||||
nm_str_buf_append(strbuf, str);
|
||||
return strbuf;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
|
|||
|
|
@ -93,6 +93,24 @@ nm_sd_hostname_is_valid(const char *s, bool allow_trailing_dot)
|
|||
: (ValidHostnameFlags) 0);
|
||||
}
|
||||
|
||||
char *
|
||||
nm_sd_dns_name_normalize(const char *s)
|
||||
{
|
||||
nm_auto_free char *n = NULL;
|
||||
int r;
|
||||
|
||||
r = dns_name_normalize(s, 0, &n);
|
||||
if (r < 0)
|
||||
return NULL;
|
||||
|
||||
nm_assert(n);
|
||||
|
||||
/* usually we try not to mix malloc/g_malloc and free/g_free. In practice,
|
||||
* they are the same. So here we return a buffer allocated with malloc(),
|
||||
* and the caller should free it with g_free(). */
|
||||
return g_steal_pointer(&n);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static gboolean
|
||||
|
|
|
|||
|
|
@ -28,6 +28,8 @@ nm_sd_dns_name_to_wire_format(const char *domain, guint8 *buffer, size_t len, gb
|
|||
int nm_sd_dns_name_is_valid(const char *s);
|
||||
gboolean nm_sd_hostname_is_valid(const char *s, bool allow_trailing_dot);
|
||||
|
||||
char *nm_sd_dns_name_normalize(const char *s);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
gboolean nm_sd_http_url_is_valid_https(const char *url);
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
#include "NetworkManagerUtils.h"
|
||||
#include "nm-utils.h"
|
||||
#include "nm-dhcp-utils.h"
|
||||
#include "nm-dhcp-options.h"
|
||||
#include "platform/nm-platform.h"
|
||||
|
||||
#include "nm-dhcp-client-logging.h"
|
||||
|
|
@ -437,8 +438,7 @@ nm_dhcp_client_set_state(NMDhcpClient *self,
|
|||
NMIPConfig * ip_config,
|
||||
GHashTable * options)
|
||||
{
|
||||
NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self);
|
||||
gs_free char * event_id = NULL;
|
||||
NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self);
|
||||
|
||||
if (NM_IN_SET(new_state, NM_DHCP_STATE_BOUND, NM_DHCP_STATE_EXTENDED)) {
|
||||
g_return_if_fail(NM_IS_IP_CONFIG_ADDR_FAMILY(ip_config, priv->addr_family));
|
||||
|
|
@ -462,23 +462,36 @@ nm_dhcp_client_set_state(NMDhcpClient *self,
|
|||
&& !NM_IN_SET(new_state, NM_DHCP_STATE_BOUND, NM_DHCP_STATE_EXTENDED))
|
||||
return;
|
||||
|
||||
if (_LOGI_ENABLED()) {
|
||||
if (_LOGD_ENABLED()) {
|
||||
gs_free const char **keys = NULL;
|
||||
guint i, nkeys;
|
||||
|
||||
keys = nm_utils_strdict_get_keys(options, TRUE, &nkeys);
|
||||
for (i = 0; i < nkeys; i++) {
|
||||
_LOGI("option %-20s => '%s'", keys[i], (char *) g_hash_table_lookup(options, keys[i]));
|
||||
_LOGD("option %-20s => '%s'", keys[i], (char *) g_hash_table_lookup(options, keys[i]));
|
||||
}
|
||||
}
|
||||
|
||||
if (priv->addr_family == AF_INET6)
|
||||
event_id = nm_dhcp_utils_get_dhcp6_event_id(options);
|
||||
if (_LOGT_ENABLED() && priv->addr_family == AF_INET6) {
|
||||
gs_free char *event_id = NULL;
|
||||
|
||||
_LOGI("state changed %s -> %s%s%s%s",
|
||||
state_to_string(priv->state),
|
||||
state_to_string(new_state),
|
||||
NM_PRINT_FMT_QUOTED(event_id, ", event ID=\"", event_id, "\"", ""));
|
||||
event_id = nm_dhcp_utils_get_dhcp6_event_id(options);
|
||||
if (event_id)
|
||||
_LOGT("event-id: \"%s\"", event_id);
|
||||
}
|
||||
|
||||
if (_LOGI_ENABLED()) {
|
||||
const char *req_str =
|
||||
NM_IS_IPv4(priv->addr_family)
|
||||
? nm_dhcp_option_request_string(AF_INET, NM_DHCP_OPTION_DHCP4_NM_IP_ADDRESS)
|
||||
: nm_dhcp_option_request_string(AF_INET6, NM_DHCP_OPTION_DHCP6_NM_IP_ADDRESS);
|
||||
const char *addr = nm_g_hash_table_lookup(options, req_str);
|
||||
|
||||
_LOGI("state changed %s -> %s%s%s%s",
|
||||
state_to_string(priv->state),
|
||||
state_to_string(new_state),
|
||||
NM_PRINT_FMT_QUOTED(addr, ", address=", addr, "", ""));
|
||||
}
|
||||
|
||||
priv->state = new_state;
|
||||
g_signal_emit(G_OBJECT(self), signals[SIGNAL_STATE_CHANGED], 0, new_state, ip_config, options);
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -7,11 +7,13 @@
|
|||
|
||||
#include "nm-dhcp-options.h"
|
||||
|
||||
#define REQPREFIX "requested_"
|
||||
#include "nm-glib-aux/nm-str-buf.h"
|
||||
|
||||
#define REQ(_num, _name, _include) \
|
||||
{ \
|
||||
.name = REQPREFIX ""_name, .option_num = _num, .include = _include, \
|
||||
/*****************************************************************************/
|
||||
|
||||
#define REQ(_num, _name, _include) \
|
||||
{ \
|
||||
.name = NM_DHCP_OPTION_REQPREFIX ""_name, .option_num = _num, .include = _include, \
|
||||
}
|
||||
|
||||
const NMDhcpOption _nm_dhcp_option_dhcp4_options[] = {
|
||||
|
|
@ -167,8 +169,24 @@ const NMDhcpOption _nm_dhcp_option_dhcp4_options[] = {
|
|||
REQ(NM_DHCP_OPTION_DHCP4_NM_IP_ADDRESS, "ip_address", FALSE),
|
||||
REQ(NM_DHCP_OPTION_DHCP4_NM_EXPIRY, "expiry", FALSE),
|
||||
REQ(NM_DHCP_OPTION_DHCP4_NM_NEXT_SERVER, "next_server", FALSE),
|
||||
};
|
||||
|
||||
{0}};
|
||||
static const NMDhcpOption *const _sorted_options_4[G_N_ELEMENTS(_nm_dhcp_option_dhcp4_options)] = {
|
||||
#define A(idx) (&_nm_dhcp_option_dhcp4_options[(idx)])
|
||||
A(0), A(1), A(8), A(18), A(19), A(2), A(20), A(21), A(22), A(23), A(24), A(3),
|
||||
A(25), A(26), A(4), A(27), A(17), A(28), A(29), A(30), A(31), A(32), A(33), A(34),
|
||||
A(35), A(5), A(36), A(6), A(37), A(38), A(39), A(40), A(9), A(41), A(42), A(43),
|
||||
A(44), A(45), A(46), A(10), A(11), A(12), A(47), A(48), A(49), A(50), A(51), A(52),
|
||||
A(13), A(53), A(54), A(55), A(57), A(58), A(59), A(60), A(61), A(62), A(63), A(64),
|
||||
A(65), A(66), A(67), A(68), A(69), A(70), A(71), A(72), A(73), A(74), A(75), A(76),
|
||||
A(77), A(78), A(79), A(80), A(81), A(82), A(83), A(84), A(85), A(86), A(87), A(56),
|
||||
A(88), A(89), A(90), A(91), A(92), A(93), A(14), A(7), A(94), A(95), A(96), A(97),
|
||||
A(98), A(99), A(100), A(101), A(102), A(103), A(104), A(105), A(106), A(107), A(108), A(109),
|
||||
A(110), A(111), A(112), A(113), A(114), A(115), A(116), A(117), A(118), A(119), A(120), A(121),
|
||||
A(122), A(123), A(124), A(125), A(126), A(127), A(128), A(129), A(130), A(131), A(132), A(133),
|
||||
A(134), A(15), A(135), A(136), A(16), A(137), A(138), A(139), A(140), A(141),
|
||||
#undef A
|
||||
};
|
||||
|
||||
const NMDhcpOption _nm_dhcp_option_dhcp6_options[] = {
|
||||
REQ(NM_DHCP_OPTION_DHCP6_CLIENTID, "dhcp6_client_id", FALSE),
|
||||
|
|
@ -194,73 +212,235 @@ const NMDhcpOption _nm_dhcp_option_dhcp6_options[] = {
|
|||
REQ(NM_DHCP_OPTION_DHCP6_NM_RENEW, "renew", FALSE),
|
||||
REQ(NM_DHCP_OPTION_DHCP6_NM_REBIND, "rebind", FALSE),
|
||||
REQ(NM_DHCP_OPTION_DHCP6_NM_IAID, "iaid", FALSE),
|
||||
};
|
||||
|
||||
{0}};
|
||||
#undef REQ
|
||||
|
||||
const char *
|
||||
nm_dhcp_option_request_string(const NMDhcpOption *requests, guint option)
|
||||
static const NMDhcpOption *const _sorted_options_6[G_N_ELEMENTS(_nm_dhcp_option_dhcp6_options)] = {
|
||||
#define A(idx) (&_nm_dhcp_option_dhcp6_options[(idx)])
|
||||
A(0),
|
||||
A(1),
|
||||
A(2),
|
||||
A(3),
|
||||
A(4),
|
||||
A(5),
|
||||
A(6),
|
||||
A(7),
|
||||
A(8),
|
||||
A(9),
|
||||
A(10),
|
||||
A(11),
|
||||
A(12),
|
||||
A(13),
|
||||
A(14),
|
||||
A(15),
|
||||
#undef A
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static int
|
||||
_sorted_options_generate_sort(gconstpointer pa, gconstpointer pb, gpointer user_data)
|
||||
{
|
||||
guint i = 0;
|
||||
const NMDhcpOption *const *a = pa;
|
||||
const NMDhcpOption *const *b = pb;
|
||||
|
||||
while (requests[i].name) {
|
||||
if (requests[i].option_num == option)
|
||||
return requests[i].name + NM_STRLEN(REQPREFIX);
|
||||
i++;
|
||||
NM_CMP_DIRECT((*a)->option_num, (*b)->option_num);
|
||||
return nm_assert_unreachable_val(0);
|
||||
}
|
||||
|
||||
static char *
|
||||
_sorted_options_generate(const NMDhcpOption *base, const NMDhcpOption *const *sorted, guint n)
|
||||
{
|
||||
gs_free const NMDhcpOption **sort2 = NULL;
|
||||
NMStrBuf sbuf = NM_STR_BUF_INIT(0, FALSE);
|
||||
guint i;
|
||||
|
||||
sort2 = nm_memdup(sorted, n * sizeof(sorted[0]));
|
||||
|
||||
g_qsort_with_data(sort2, n, sizeof(sort2[0]), _sorted_options_generate_sort, NULL);
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
if (i > 0)
|
||||
nm_str_buf_append(&sbuf, ", ");
|
||||
nm_str_buf_append_printf(&sbuf, "A(%d)", (int) (sort2[i] - base));
|
||||
}
|
||||
|
||||
return nm_str_buf_finalize(&sbuf, NULL);
|
||||
}
|
||||
|
||||
_nm_unused static void
|
||||
_ASSERT_sorted(int IS_IPv4, const NMDhcpOption *const *const sorted, int n)
|
||||
|
||||
{
|
||||
const NMDhcpOption *const options =
|
||||
IS_IPv4 ? _nm_dhcp_option_dhcp4_options : _nm_dhcp_option_dhcp6_options;
|
||||
int i;
|
||||
int j;
|
||||
gs_free char *sorted_msg = NULL;
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
const NMDhcpOption *opt = sorted[i];
|
||||
|
||||
g_assert(opt);
|
||||
g_assert(opt >= options);
|
||||
g_assert(opt < &options[n]);
|
||||
|
||||
for (j = 0; j < i; j++) {
|
||||
const NMDhcpOption *opt2 = sorted[j];
|
||||
|
||||
if (opt == opt2) {
|
||||
g_error("%s:%d: the _sorted_options_%c at [%d] (opt=%u, %s) is duplicated at "
|
||||
"[%d] (SORT: %s)",
|
||||
__FILE__,
|
||||
__LINE__,
|
||||
IS_IPv4 ? '4' : '6',
|
||||
i,
|
||||
opt->option_num,
|
||||
opt->name,
|
||||
j,
|
||||
(sorted_msg = _sorted_options_generate(options, sorted, n)));
|
||||
}
|
||||
}
|
||||
|
||||
if (i > 0) {
|
||||
const NMDhcpOption *opt2 = sorted[i - 1];
|
||||
|
||||
if (opt2->option_num >= opt->option_num) {
|
||||
g_error("%s:%d: the _sorted_options_%c at [%d] (opt=%u, %s) should come before "
|
||||
"[%d] (opt=%u, %s) (SORT: %s)",
|
||||
__FILE__,
|
||||
__LINE__,
|
||||
IS_IPv4 ? '4' : '6',
|
||||
i,
|
||||
opt->option_num,
|
||||
opt->name,
|
||||
i - 1,
|
||||
opt2->option_num,
|
||||
opt2->name,
|
||||
(sorted_msg = _sorted_options_generate(options, sorted, n)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
const NMDhcpOption *
|
||||
nm_dhcp_option_find(int addr_family, guint option)
|
||||
{
|
||||
const int IS_IPv4 = NM_IS_IPv4(addr_family);
|
||||
const NMDhcpOption *const *const sorted = IS_IPv4 ? _sorted_options_4 : _sorted_options_6;
|
||||
const int n = IS_IPv4 ? G_N_ELEMENTS(_nm_dhcp_option_dhcp4_options)
|
||||
: G_N_ELEMENTS(_nm_dhcp_option_dhcp6_options);
|
||||
int imin = 0;
|
||||
int imax = n - 1;
|
||||
int imid = (n - 1) / 2;
|
||||
|
||||
#if NM_MORE_ASSERTS > 10
|
||||
nm_assert(n < G_MAXINT / 2);
|
||||
if (IS_IPv4 && !NM_MORE_ASSERT_ONCE(10)) {
|
||||
/* already checked */
|
||||
} else if (!IS_IPv4 && !NM_MORE_ASSERT_ONCE(10)) {
|
||||
/* already checked */
|
||||
} else
|
||||
_ASSERT_sorted(IS_IPv4, sorted, n);
|
||||
#endif
|
||||
|
||||
for (;;) {
|
||||
const guint o = sorted[imid]->option_num;
|
||||
|
||||
if (G_UNLIKELY(o == option))
|
||||
return sorted[imid];
|
||||
|
||||
if (o < option)
|
||||
imin = imid + 1;
|
||||
else
|
||||
imax = imid - 1;
|
||||
|
||||
if (G_UNLIKELY(imin > imax))
|
||||
break;
|
||||
|
||||
imid = (imin + imax) / 2;
|
||||
}
|
||||
|
||||
/* Option should always be found */
|
||||
nm_assert_not_reached();
|
||||
return NULL;
|
||||
return nm_assert_unreachable_val(NULL);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void
|
||||
nm_dhcp_option_take_option(GHashTable * options,
|
||||
const NMDhcpOption *requests,
|
||||
guint option,
|
||||
char * value)
|
||||
nm_dhcp_option_take_option(GHashTable *options, int addr_family, guint option, char *value)
|
||||
{
|
||||
nm_assert(options);
|
||||
nm_assert(requests);
|
||||
nm_assert_addr_family(addr_family);
|
||||
nm_assert(value);
|
||||
nm_assert(g_utf8_validate(value, -1, NULL));
|
||||
|
||||
g_hash_table_insert(options, (gpointer) nm_dhcp_option_request_string(requests, option), value);
|
||||
}
|
||||
|
||||
void
|
||||
nm_dhcp_option_add_option(GHashTable * options,
|
||||
const NMDhcpOption *requests,
|
||||
guint option,
|
||||
const char * value)
|
||||
{
|
||||
if (options)
|
||||
nm_dhcp_option_take_option(options, requests, option, g_strdup(value));
|
||||
}
|
||||
|
||||
void
|
||||
nm_dhcp_option_add_option_u64(GHashTable * options,
|
||||
const NMDhcpOption *requests,
|
||||
guint option,
|
||||
guint64 value)
|
||||
{
|
||||
if (options)
|
||||
nm_dhcp_option_take_option(options,
|
||||
requests,
|
||||
option,
|
||||
g_strdup_printf("%" G_GUINT64_FORMAT, value));
|
||||
}
|
||||
|
||||
void
|
||||
nm_dhcp_option_add_requests_to_options(GHashTable *options, const NMDhcpOption *requests)
|
||||
{
|
||||
guint i;
|
||||
|
||||
if (!options)
|
||||
if (!options) {
|
||||
nm_assert_not_reached();
|
||||
g_free(value);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; requests[i].name; i++) {
|
||||
if (requests[i].include)
|
||||
g_hash_table_insert(options, (gpointer) requests[i].name, g_strdup("1"));
|
||||
g_hash_table_insert(options,
|
||||
(gpointer) nm_dhcp_option_request_string(addr_family, option),
|
||||
value);
|
||||
}
|
||||
|
||||
void
|
||||
nm_dhcp_option_add_option(GHashTable *options, int addr_family, guint option, const char *value)
|
||||
{
|
||||
nm_dhcp_option_take_option(options, addr_family, option, g_strdup(value));
|
||||
}
|
||||
|
||||
void
|
||||
nm_dhcp_option_add_option_utf8safe_escape(GHashTable * options,
|
||||
int addr_family,
|
||||
guint option,
|
||||
const guint8 *data,
|
||||
gsize n_data)
|
||||
{
|
||||
gs_free char *to_free = NULL;
|
||||
const char * escaped;
|
||||
|
||||
escaped = nm_utils_buf_utf8safe_escape((char *) data, n_data, 0, &to_free);
|
||||
nm_dhcp_option_add_option(options, addr_family, option, escaped ?: "");
|
||||
}
|
||||
|
||||
void
|
||||
nm_dhcp_option_add_option_u64(GHashTable *options, int addr_family, guint option, guint64 value)
|
||||
{
|
||||
nm_dhcp_option_take_option(options,
|
||||
addr_family,
|
||||
option,
|
||||
g_strdup_printf("%" G_GUINT64_FORMAT, value));
|
||||
}
|
||||
|
||||
void
|
||||
nm_dhcp_option_add_option_in_addr(GHashTable *options,
|
||||
int addr_family,
|
||||
guint option,
|
||||
in_addr_t value)
|
||||
{
|
||||
char sbuf[NM_UTILS_INET_ADDRSTRLEN];
|
||||
|
||||
nm_dhcp_option_add_option(options, addr_family, option, _nm_utils_inet4_ntop(value, sbuf));
|
||||
}
|
||||
|
||||
void
|
||||
nm_dhcp_option_add_requests_to_options(GHashTable *options, int addr_family)
|
||||
{
|
||||
const int IS_IPv4 = NM_IS_IPv4(addr_family);
|
||||
const NMDhcpOption *const all_options =
|
||||
IS_IPv4 ? _nm_dhcp_option_dhcp4_options : _nm_dhcp_option_dhcp6_options;
|
||||
int n_options = IS_IPv4 ? G_N_ELEMENTS(_nm_dhcp_option_dhcp4_options)
|
||||
: G_N_ELEMENTS(_nm_dhcp_option_dhcp6_options);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < n_options; i++) {
|
||||
if (all_options[i].include)
|
||||
g_hash_table_insert(options, (gpointer) all_options[i].name, g_strdup("1"));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -177,29 +177,50 @@ typedef enum {
|
|||
|
||||
} NMDhcpOptionDhcp6Options;
|
||||
|
||||
#define NM_DHCP_OPTION_REQPREFIX "requested_"
|
||||
|
||||
typedef struct {
|
||||
const char *name;
|
||||
uint16_t option_num;
|
||||
bool include;
|
||||
} NMDhcpOption;
|
||||
|
||||
extern const NMDhcpOption _nm_dhcp_option_dhcp4_options[];
|
||||
extern const NMDhcpOption _nm_dhcp_option_dhcp6_options[];
|
||||
extern const NMDhcpOption _nm_dhcp_option_dhcp4_options[142];
|
||||
extern const NMDhcpOption _nm_dhcp_option_dhcp6_options[16];
|
||||
|
||||
const char *nm_dhcp_option_request_string(const NMDhcpOption *requests, guint option);
|
||||
void nm_dhcp_option_take_option(GHashTable * options,
|
||||
const NMDhcpOption *requests,
|
||||
guint option,
|
||||
char * value);
|
||||
void nm_dhcp_option_add_option(GHashTable * options,
|
||||
const NMDhcpOption *requests,
|
||||
guint option,
|
||||
const char * value);
|
||||
void nm_dhcp_option_add_option_u64(GHashTable * options,
|
||||
const NMDhcpOption *requests,
|
||||
guint option,
|
||||
guint64 value);
|
||||
void nm_dhcp_option_add_requests_to_options(GHashTable *options, const NMDhcpOption *requests);
|
||||
static inline const char *
|
||||
nm_dhcp_option_get_name(const NMDhcpOption *option)
|
||||
{
|
||||
nm_assert(option);
|
||||
nm_assert(option->name);
|
||||
nm_assert(NM_STR_HAS_PREFIX(option->name, NM_DHCP_OPTION_REQPREFIX));
|
||||
|
||||
return &option->name[NM_STRLEN(NM_DHCP_OPTION_REQPREFIX)];
|
||||
}
|
||||
|
||||
const NMDhcpOption *nm_dhcp_option_find(int addr_family, guint option);
|
||||
|
||||
static inline const char *
|
||||
nm_dhcp_option_request_string(int addr_family, guint option)
|
||||
{
|
||||
return nm_dhcp_option_get_name(nm_dhcp_option_find(addr_family, option));
|
||||
}
|
||||
|
||||
void nm_dhcp_option_take_option(GHashTable *options, int addr_family, guint option, char *value);
|
||||
void
|
||||
nm_dhcp_option_add_option(GHashTable *options, int addr_family, guint option, const char *value);
|
||||
void nm_dhcp_option_add_option_utf8safe_escape(GHashTable * options,
|
||||
int addr_family,
|
||||
guint option,
|
||||
const guint8 *data,
|
||||
gsize n_data);
|
||||
void nm_dhcp_option_add_option_in_addr(GHashTable *options,
|
||||
int addr_family,
|
||||
guint option,
|
||||
in_addr_t value);
|
||||
void
|
||||
nm_dhcp_option_add_option_u64(GHashTable *options, int addr_family, guint option, guint64 value);
|
||||
void nm_dhcp_option_add_requests_to_options(GHashTable *options, int addr_family);
|
||||
GHashTable *nm_dhcp_option_create_options_dict(void);
|
||||
|
||||
#endif /* __NM_DHCP_OPTIONS_H__ */
|
||||
|
|
|
|||
|
|
@ -138,32 +138,26 @@ lease_to_ip4_config(NMDedupMultiIndex *multi_idx,
|
|||
options = out_options ? nm_dhcp_option_create_options_dict() : NULL;
|
||||
|
||||
_nm_utils_inet4_ntop(a_address.s_addr, addr_str);
|
||||
nm_dhcp_option_add_option(options,
|
||||
_nm_dhcp_option_dhcp4_options,
|
||||
NM_DHCP_OPTION_DHCP4_NM_IP_ADDRESS,
|
||||
addr_str);
|
||||
nm_dhcp_option_add_option(options, AF_INET, NM_DHCP_OPTION_DHCP4_NM_IP_ADDRESS, addr_str);
|
||||
|
||||
a_plen = nm_utils_ip4_netmask_to_prefix(a_netmask.s_addr);
|
||||
nm_dhcp_option_add_option(options,
|
||||
_nm_dhcp_option_dhcp4_options,
|
||||
AF_INET,
|
||||
NM_DHCP_OPTION_DHCP4_SUBNET_MASK,
|
||||
_nm_utils_inet4_ntop(a_netmask.s_addr, addr_str));
|
||||
|
||||
nm_dhcp_option_add_option_u64(options,
|
||||
_nm_dhcp_option_dhcp4_options,
|
||||
AF_INET,
|
||||
NM_DHCP_OPTION_DHCP4_IP_ADDRESS_LEASE_TIME,
|
||||
a_lifetime);
|
||||
nm_dhcp_option_add_option_u64(options,
|
||||
_nm_dhcp_option_dhcp4_options,
|
||||
AF_INET,
|
||||
NM_DHCP_OPTION_DHCP4_NM_EXPIRY,
|
||||
(guint64)(ts_time + a_lifetime));
|
||||
|
||||
if (sd_dhcp_lease_get_next_server(lease, &a_next_server) == 0) {
|
||||
_nm_utils_inet4_ntop(a_next_server.s_addr, addr_str);
|
||||
nm_dhcp_option_add_option(options,
|
||||
_nm_dhcp_option_dhcp4_options,
|
||||
NM_DHCP_OPTION_DHCP4_NM_NEXT_SERVER,
|
||||
addr_str);
|
||||
nm_dhcp_option_add_option(options, AF_INET, NM_DHCP_OPTION_DHCP4_NM_NEXT_SERVER, addr_str);
|
||||
}
|
||||
|
||||
nm_ip4_config_add_address(ip4_config,
|
||||
|
|
@ -179,18 +173,12 @@ lease_to_ip4_config(NMDedupMultiIndex *multi_idx,
|
|||
|
||||
if (sd_dhcp_lease_get_server_identifier(lease, &server_id) >= 0) {
|
||||
_nm_utils_inet4_ntop(server_id.s_addr, addr_str);
|
||||
nm_dhcp_option_add_option(options,
|
||||
_nm_dhcp_option_dhcp4_options,
|
||||
NM_DHCP_OPTION_DHCP4_SERVER_ID,
|
||||
addr_str);
|
||||
nm_dhcp_option_add_option(options, AF_INET, NM_DHCP_OPTION_DHCP4_SERVER_ID, addr_str);
|
||||
}
|
||||
|
||||
if (sd_dhcp_lease_get_broadcast(lease, &broadcast) >= 0) {
|
||||
_nm_utils_inet4_ntop(broadcast.s_addr, addr_str);
|
||||
nm_dhcp_option_add_option(options,
|
||||
_nm_dhcp_option_dhcp4_options,
|
||||
NM_DHCP_OPTION_DHCP4_BROADCAST,
|
||||
addr_str);
|
||||
nm_dhcp_option_add_option(options, AF_INET, NM_DHCP_OPTION_DHCP4_BROADCAST, addr_str);
|
||||
}
|
||||
|
||||
num = sd_dhcp_lease_get_dns(lease, &addr_list);
|
||||
|
|
@ -208,7 +196,7 @@ lease_to_ip4_config(NMDedupMultiIndex *multi_idx,
|
|||
nm_ip4_config_add_nameserver(ip4_config, addr_list[i].s_addr);
|
||||
}
|
||||
nm_dhcp_option_add_option(options,
|
||||
_nm_dhcp_option_dhcp4_options,
|
||||
AF_INET,
|
||||
NM_DHCP_OPTION_DHCP4_DOMAIN_NAME_SERVER,
|
||||
str->str);
|
||||
}
|
||||
|
|
@ -221,7 +209,7 @@ lease_to_ip4_config(NMDedupMultiIndex *multi_idx,
|
|||
nm_ip4_config_add_search(ip4_config, search_domains[i]);
|
||||
}
|
||||
nm_dhcp_option_add_option(options,
|
||||
_nm_dhcp_option_dhcp4_options,
|
||||
AF_INET,
|
||||
NM_DHCP_OPTION_DHCP4_DOMAIN_SEARCH_LIST,
|
||||
str->str);
|
||||
}
|
||||
|
|
@ -230,10 +218,7 @@ lease_to_ip4_config(NMDedupMultiIndex *multi_idx,
|
|||
gs_strfreev char **domains = NULL;
|
||||
char ** d;
|
||||
|
||||
nm_dhcp_option_add_option(options,
|
||||
_nm_dhcp_option_dhcp4_options,
|
||||
NM_DHCP_OPTION_DHCP4_DOMAIN_NAME,
|
||||
s);
|
||||
nm_dhcp_option_add_option(options, AF_INET, NM_DHCP_OPTION_DHCP4_DOMAIN_NAME, s);
|
||||
|
||||
/* Multiple domains sometimes stuffed into option 15 "Domain Name".
|
||||
* As systemd escapes such characters, split them at \\032. */
|
||||
|
|
@ -243,10 +228,7 @@ lease_to_ip4_config(NMDedupMultiIndex *multi_idx,
|
|||
}
|
||||
|
||||
if (sd_dhcp_lease_get_hostname(lease, &s) >= 0) {
|
||||
nm_dhcp_option_add_option(options,
|
||||
_nm_dhcp_option_dhcp4_options,
|
||||
NM_DHCP_OPTION_DHCP4_HOST_NAME,
|
||||
s);
|
||||
nm_dhcp_option_add_option(options, AF_INET, NM_DHCP_OPTION_DHCP4_HOST_NAME, s);
|
||||
}
|
||||
|
||||
num = sd_dhcp_lease_get_routes(lease, &routes);
|
||||
|
|
@ -348,12 +330,12 @@ lease_to_ip4_config(NMDedupMultiIndex *multi_idx,
|
|||
|
||||
if (str_classless && str_classless->len > 0)
|
||||
nm_dhcp_option_add_option(options,
|
||||
_nm_dhcp_option_dhcp4_options,
|
||||
AF_INET,
|
||||
NM_DHCP_OPTION_DHCP4_CLASSLESS_STATIC_ROUTE,
|
||||
str_classless->str);
|
||||
if (str_static && str_static->len > 0)
|
||||
nm_dhcp_option_add_option(options,
|
||||
_nm_dhcp_option_dhcp4_options,
|
||||
AF_INET,
|
||||
NM_DHCP_OPTION_DHCP4_STATIC_ROUTE,
|
||||
str_static->str);
|
||||
}
|
||||
|
|
@ -400,17 +382,11 @@ lease_to_ip4_config(NMDedupMultiIndex *multi_idx,
|
|||
}),
|
||||
NULL);
|
||||
}
|
||||
nm_dhcp_option_add_option(options,
|
||||
_nm_dhcp_option_dhcp4_options,
|
||||
NM_DHCP_OPTION_DHCP4_ROUTER,
|
||||
str->str);
|
||||
nm_dhcp_option_add_option(options, AF_INET, NM_DHCP_OPTION_DHCP4_ROUTER, str->str);
|
||||
}
|
||||
|
||||
if (sd_dhcp_lease_get_mtu(lease, &mtu) >= 0 && mtu) {
|
||||
nm_dhcp_option_add_option_u64(options,
|
||||
_nm_dhcp_option_dhcp4_options,
|
||||
NM_DHCP_OPTION_DHCP4_INTERFACE_MTU,
|
||||
mtu);
|
||||
nm_dhcp_option_add_option_u64(options, AF_INET, NM_DHCP_OPTION_DHCP4_INTERFACE_MTU, mtu);
|
||||
nm_ip4_config_set_mtu(ip4_config, mtu, NM_IP_CONFIG_SOURCE_DHCP);
|
||||
}
|
||||
|
||||
|
|
@ -421,38 +397,29 @@ lease_to_ip4_config(NMDedupMultiIndex *multi_idx,
|
|||
_nm_utils_inet4_ntop(addr_list[i].s_addr, addr_str);
|
||||
g_string_append(nm_gstring_add_space_delimiter(str), addr_str);
|
||||
}
|
||||
nm_dhcp_option_add_option(options,
|
||||
_nm_dhcp_option_dhcp4_options,
|
||||
NM_DHCP_OPTION_DHCP4_NTP_SERVER,
|
||||
str->str);
|
||||
nm_dhcp_option_add_option(options, AF_INET, NM_DHCP_OPTION_DHCP4_NTP_SERVER, str->str);
|
||||
}
|
||||
|
||||
if (sd_dhcp_lease_get_root_path(lease, &s) >= 0) {
|
||||
nm_dhcp_option_add_option(options,
|
||||
_nm_dhcp_option_dhcp4_options,
|
||||
NM_DHCP_OPTION_DHCP4_ROOT_PATH,
|
||||
s);
|
||||
nm_dhcp_option_add_option(options, AF_INET, NM_DHCP_OPTION_DHCP4_ROOT_PATH, s);
|
||||
}
|
||||
|
||||
if (sd_dhcp_lease_get_t1(lease, &renewal) >= 0) {
|
||||
nm_dhcp_option_add_option_u64(options,
|
||||
_nm_dhcp_option_dhcp4_options,
|
||||
AF_INET,
|
||||
NM_DHCP_OPTION_DHCP4_RENEWAL_T1_TIME,
|
||||
renewal);
|
||||
}
|
||||
|
||||
if (sd_dhcp_lease_get_t2(lease, &rebinding) >= 0) {
|
||||
nm_dhcp_option_add_option_u64(options,
|
||||
_nm_dhcp_option_dhcp4_options,
|
||||
AF_INET,
|
||||
NM_DHCP_OPTION_DHCP4_REBINDING_T2_TIME,
|
||||
rebinding);
|
||||
}
|
||||
|
||||
if (sd_dhcp_lease_get_timezone(lease, &s) >= 0) {
|
||||
nm_dhcp_option_add_option(options,
|
||||
_nm_dhcp_option_dhcp4_options,
|
||||
NM_DHCP_OPTION_DHCP4_NEW_TZDB_TIMEZONE,
|
||||
s);
|
||||
nm_dhcp_option_add_option(options, AF_INET, NM_DHCP_OPTION_DHCP4_NEW_TZDB_TIMEZONE, s);
|
||||
}
|
||||
|
||||
if (sd_dhcp_lease_get_vendor_specific(lease, &data, &data_len) >= 0)
|
||||
|
|
@ -473,10 +440,7 @@ lease_to_ip4_config(NMDedupMultiIndex *multi_idx,
|
|||
g_free(option_string);
|
||||
continue;
|
||||
}
|
||||
nm_dhcp_option_take_option(options,
|
||||
_nm_dhcp_option_dhcp4_options,
|
||||
private_options[i].code,
|
||||
option_string);
|
||||
nm_dhcp_option_take_option(options, AF_INET, private_options[i].code, option_string);
|
||||
}
|
||||
}
|
||||
NM_SET_OUT(out_options, g_steal_pointer(&options));
|
||||
|
|
@ -518,7 +482,7 @@ bound4_handle(NMDhcpSystemd *self, gboolean extended)
|
|||
return;
|
||||
}
|
||||
|
||||
nm_dhcp_option_add_requests_to_options(options, _nm_dhcp_option_dhcp4_options);
|
||||
nm_dhcp_option_add_requests_to_options(options, AF_INET);
|
||||
dhcp_lease_save(lease, priv->lease_file);
|
||||
|
||||
nm_dhcp_client_set_state(NM_DHCP_CLIENT(self),
|
||||
|
|
@ -702,7 +666,7 @@ ip4_start(NMDhcpClient *client,
|
|||
}
|
||||
|
||||
/* Add requested options */
|
||||
for (i = 0; _nm_dhcp_option_dhcp4_options[i].name; i++) {
|
||||
for (i = 0; i < (int) G_N_ELEMENTS(_nm_dhcp_option_dhcp4_options); i++) {
|
||||
if (_nm_dhcp_option_dhcp4_options[i].include) {
|
||||
nm_assert(_nm_dhcp_option_dhcp4_options[i].option_num <= 255);
|
||||
r = sd_dhcp_client_set_request_option(sd_client,
|
||||
|
|
@ -821,10 +785,7 @@ lease_to_ip6_config(NMDedupMultiIndex *multi_idx,
|
|||
g_string_append(nm_gstring_add_space_delimiter(str), addr_str);
|
||||
};
|
||||
if (str->len)
|
||||
nm_dhcp_option_add_option(options,
|
||||
_nm_dhcp_option_dhcp6_options,
|
||||
NM_DHCP_OPTION_DHCP6_NM_IP_ADDRESS,
|
||||
str->str);
|
||||
nm_dhcp_option_add_option(options, AF_INET6, NM_DHCP_OPTION_DHCP6_NM_IP_ADDRESS, str->str);
|
||||
|
||||
if (!info_only && nm_ip6_config_get_num_addresses(ip6_config) == 0) {
|
||||
g_set_error_literal(error,
|
||||
|
|
@ -842,10 +803,7 @@ lease_to_ip6_config(NMDedupMultiIndex *multi_idx,
|
|||
g_string_append(nm_gstring_add_space_delimiter(str), addr_str);
|
||||
nm_ip6_config_add_nameserver(ip6_config, &dns[i]);
|
||||
}
|
||||
nm_dhcp_option_add_option(options,
|
||||
_nm_dhcp_option_dhcp6_options,
|
||||
NM_DHCP_OPTION_DHCP6_DNS_SERVERS,
|
||||
str->str);
|
||||
nm_dhcp_option_add_option(options, AF_INET6, NM_DHCP_OPTION_DHCP6_DNS_SERVERS, str->str);
|
||||
}
|
||||
|
||||
num = sd_dhcp6_lease_get_domains(lease, &domains);
|
||||
|
|
@ -855,17 +813,11 @@ lease_to_ip6_config(NMDedupMultiIndex *multi_idx,
|
|||
g_string_append(nm_gstring_add_space_delimiter(str), domains[i]);
|
||||
nm_ip6_config_add_search(ip6_config, domains[i]);
|
||||
}
|
||||
nm_dhcp_option_add_option(options,
|
||||
_nm_dhcp_option_dhcp6_options,
|
||||
NM_DHCP_OPTION_DHCP6_DOMAIN_LIST,
|
||||
str->str);
|
||||
nm_dhcp_option_add_option(options, AF_INET6, NM_DHCP_OPTION_DHCP6_DOMAIN_LIST, str->str);
|
||||
}
|
||||
|
||||
if (sd_dhcp6_lease_get_fqdn(lease, &s) >= 0) {
|
||||
nm_dhcp_option_add_option(options,
|
||||
_nm_dhcp_option_dhcp6_options,
|
||||
NM_DHCP_OPTION_DHCP6_FQDN,
|
||||
s);
|
||||
nm_dhcp_option_add_option(options, AF_INET6, NM_DHCP_OPTION_DHCP6_FQDN, s);
|
||||
}
|
||||
|
||||
NM_SET_OUT(out_options, g_steal_pointer(&options));
|
||||
|
|
@ -1020,7 +972,7 @@ ip6_start(NMDhcpClient * client,
|
|||
}
|
||||
|
||||
/* Add requested options */
|
||||
for (i = 0; _nm_dhcp_option_dhcp6_options[i].name; i++) {
|
||||
for (i = 0; i < (int) G_N_ELEMENTS(_nm_dhcp_option_dhcp6_options); i++) {
|
||||
if (_nm_dhcp_option_dhcp6_options[i].include) {
|
||||
r = sd_dhcp6_client_set_request_option(sd_client,
|
||||
_nm_dhcp_option_dhcp6_options[i].option_num);
|
||||
|
|
|
|||
|
|
@ -8,7 +8,10 @@
|
|||
#include <unistd.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "nm-std-aux/unaligned.h"
|
||||
#include "nm-glib-aux/nm-dedup-multi.h"
|
||||
#include "nm-glib-aux/nm-str-buf.h"
|
||||
#include "systemd/nm-sd-utils-shared.h"
|
||||
|
||||
#include "nm-dhcp-utils.h"
|
||||
#include "nm-utils.h"
|
||||
|
|
@ -834,3 +837,285 @@ nm_dhcp_utils_get_dhcp6_event_id(GHashTable *lease)
|
|||
|
||||
return g_strdup_printf("%s|%s", iaid, start);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
gboolean
|
||||
nm_dhcp_lease_data_parse_u16(const guint8 *data, gsize n_data, uint16_t *out_val)
|
||||
{
|
||||
if (n_data != 2)
|
||||
return FALSE;
|
||||
|
||||
*out_val = unaligned_read_be16(data);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_dhcp_lease_data_parse_mtu(const guint8 *data, gsize n_data, uint16_t *out_val)
|
||||
{
|
||||
uint16_t mtu;
|
||||
|
||||
if (!nm_dhcp_lease_data_parse_u16(data, n_data, &mtu))
|
||||
return FALSE;
|
||||
|
||||
if (mtu < 68) {
|
||||
/* https://tools.ietf.org/html/rfc2132#section-5.1:
|
||||
*
|
||||
* The minimum legal value for the MTU is 68. */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*out_val = mtu;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_dhcp_lease_data_parse_cstr(const guint8 *data, gsize n_data, gsize *out_new_len)
|
||||
{
|
||||
/* WARNING: this function only validates that the string does not contain
|
||||
* NUL characters (and ignores trailing NULs). It does not check character
|
||||
* encoding! */
|
||||
|
||||
while (n_data > 0 && data[n_data - 1] == '\0')
|
||||
n_data--;
|
||||
|
||||
if (n_data > 0) {
|
||||
if (memchr(data, n_data, '\0')) {
|
||||
/* we accept trailing NUL, but none in between.
|
||||
*
|
||||
* https://tools.ietf.org/html/rfc2132#section-2
|
||||
* https://github.com/systemd/systemd/issues/1337 */
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
NM_SET_OUT(out_new_len, n_data);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
char *
|
||||
nm_dhcp_lease_data_parse_domain_validate(const char *str)
|
||||
{
|
||||
gs_free char *s = NULL;
|
||||
|
||||
s = nm_sd_dns_name_normalize(str);
|
||||
if (!s)
|
||||
return NULL;
|
||||
|
||||
if (nm_str_is_empty(s) || (s[0] == '.' && s[1] == '\0')) {
|
||||
/* root domains are not allowed. */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (nm_utils_is_localhost(s))
|
||||
return NULL;
|
||||
|
||||
if (!g_utf8_validate(s, -1, NULL)) {
|
||||
/* the result must be valid UTF-8. */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return g_steal_pointer(&s);
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_dhcp_lease_data_parse_domain(const guint8 *data, gsize n_data, char **out_val)
|
||||
{
|
||||
gs_free char *str1_free = NULL;
|
||||
const char * str1;
|
||||
gs_free char *s = NULL;
|
||||
|
||||
/* this is mostly the same as systemd's lease_parse_domain(). */
|
||||
|
||||
if (!nm_dhcp_lease_data_parse_cstr(data, n_data, &n_data))
|
||||
return FALSE;
|
||||
|
||||
if (n_data == 0) {
|
||||
/* empty domains are rejected. See
|
||||
* https://tools.ietf.org/html/rfc2132#section-3.14
|
||||
* https://tools.ietf.org/html/rfc2132#section-3.17
|
||||
*
|
||||
* Its minimum length is 1.
|
||||
*
|
||||
* Note that this is *after* we potentially stripped trailing NULs.
|
||||
*/
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
str1 = nm_strndup_a(300, (char *) data, n_data, &str1_free);
|
||||
|
||||
s = nm_dhcp_lease_data_parse_domain_validate(str1);
|
||||
if (!s)
|
||||
return FALSE;
|
||||
|
||||
*out_val = g_steal_pointer(&s);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_dhcp_lease_data_parse_in_addr(const guint8 *data, gsize n_data, in_addr_t *out_val)
|
||||
{
|
||||
/* - option 1, https://tools.ietf.org/html/rfc2132#section-3.3
|
||||
* - option 28, https://tools.ietf.org/html/rfc2132#section-5.3
|
||||
*/
|
||||
|
||||
if (n_data != 4)
|
||||
return FALSE;
|
||||
|
||||
*out_val = unaligned_read_ne32(data);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static gboolean
|
||||
lease_option_print_label(NMStrBuf *sbuf, 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 '_':
|
||||
nm_str_buf_append_c(sbuf, c);
|
||||
break;
|
||||
case '.':
|
||||
case '\\':
|
||||
nm_str_buf_append_c2(sbuf, '\\', c);
|
||||
break;
|
||||
default:
|
||||
nm_str_buf_append_printf(sbuf, "\\%3d", c);
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static char *
|
||||
lease_option_print_domain_name(const uint8_t * cache,
|
||||
size_t * n_cachep,
|
||||
const uint8_t **datap,
|
||||
size_t * n_datap)
|
||||
{
|
||||
nm_auto_str_buf NMStrBuf sbuf = NM_STR_BUF_INIT(NM_UTILS_GET_NEXT_REALLOC_SIZE_40, FALSE);
|
||||
const uint8_t * domain;
|
||||
size_t n_domain;
|
||||
size_t 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 NULL;
|
||||
|
||||
for (;;) {
|
||||
if (!nm_dhcp_lease_data_consume(domainp, n_domainp, &c, sizeof(c)))
|
||||
return NULL;
|
||||
|
||||
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 nm_str_buf_finalize(&sbuf, NULL);
|
||||
}
|
||||
|
||||
if (!first)
|
||||
nm_str_buf_append_c(&sbuf, '.');
|
||||
else
|
||||
first = FALSE;
|
||||
|
||||
if (!lease_option_print_label(&sbuf, n_label, domainp, n_domainp))
|
||||
return NULL;
|
||||
|
||||
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 NULL;
|
||||
|
||||
offset += c;
|
||||
|
||||
if (offset >= n_cache)
|
||||
return NULL;
|
||||
|
||||
domain = cache + offset;
|
||||
n_domain = n_cache - offset;
|
||||
n_cache = offset;
|
||||
|
||||
domainp = &domain;
|
||||
n_domainp = &n_domain;
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 (;;) {
|
||||
gs_free char *s = NULL;
|
||||
|
||||
s = lease_option_print_domain_name(cache, &n_cache, &data, &n_data);
|
||||
if (!s)
|
||||
break;
|
||||
|
||||
if (!array)
|
||||
array = g_ptr_array_new();
|
||||
|
||||
g_ptr_array_add(array, g_steal_pointer(&s));
|
||||
}
|
||||
|
||||
if (!array)
|
||||
return NULL;
|
||||
|
||||
g_ptr_array_add(array, NULL);
|
||||
return (char **) g_ptr_array_free(array, FALSE);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,8 +36,35 @@ 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;
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
nm_dhcp_lease_data_consume_in_addr(const uint8_t **datap, size_t *n_datap, in_addr_t *addrp)
|
||||
{
|
||||
return nm_dhcp_lease_data_consume(datap, n_datap, addrp, sizeof(struct in_addr));
|
||||
}
|
||||
|
||||
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);
|
||||
gboolean nm_dhcp_lease_data_parse_mtu(const guint8 *data, gsize n_data, guint16 *out_val);
|
||||
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__ */
|
||||
|
|
|
|||
|
|
@ -13,10 +13,13 @@
|
|||
#include "nm-utils.h"
|
||||
|
||||
#include "dhcp/nm-dhcp-utils.h"
|
||||
#include "dhcp/nm-dhcp-options.h"
|
||||
#include "platform/nm-platform.h"
|
||||
|
||||
#include "nm-test-utils-core.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static NMIP4Config *
|
||||
_ip4_config_from_options(int ifindex, const char *iface, GHashTable *options, guint32 route_metric)
|
||||
{
|
||||
|
|
@ -202,7 +205,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 +214,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 +229,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 +244,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");
|
||||
|
|
@ -740,6 +743,46 @@ test_client_id_from_string(void)
|
|||
COMPARE_ID(endcolon, TRUE, endcolon, strlen(endcolon));
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void
|
||||
test_dhcp_opt_list(gconstpointer test_data)
|
||||
{
|
||||
const gboolean IS_IPv4 = (GPOINTER_TO_INT(test_data) == 0);
|
||||
const int addr_family = IS_IPv4 ? AF_INET : AF_INET6;
|
||||
const NMDhcpOption *const options =
|
||||
IS_IPv4 ? _nm_dhcp_option_dhcp4_options : _nm_dhcp_option_dhcp6_options;
|
||||
const guint n = (IS_IPv4 ? G_N_ELEMENTS(_nm_dhcp_option_dhcp4_options)
|
||||
: G_N_ELEMENTS(_nm_dhcp_option_dhcp6_options));
|
||||
guint i;
|
||||
guint j;
|
||||
|
||||
g_assert(options);
|
||||
g_assert(n > 0);
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
const NMDhcpOption *const opt = &options[i];
|
||||
|
||||
g_assert_cmpstr(opt->name, !=, NULL);
|
||||
g_assert(NM_STR_HAS_PREFIX(opt->name, NM_DHCP_OPTION_REQPREFIX));
|
||||
|
||||
for (j = 0; j < i; j++) {
|
||||
const NMDhcpOption *const opt2 = &options[j];
|
||||
|
||||
g_assert_cmpstr(opt->name, !=, opt2->name);
|
||||
g_assert_cmpint(opt->option_num, !=, opt2->option_num);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
const NMDhcpOption *const opt = &options[i];
|
||||
|
||||
g_assert(opt == nm_dhcp_option_find(addr_family, opt->option_num));
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
NMTST_DEFINE();
|
||||
|
||||
int
|
||||
|
|
@ -776,6 +819,8 @@ main(int argc, char **argv)
|
|||
g_test_add_func("/dhcp/client-id-from-string", test_client_id_from_string);
|
||||
g_test_add_func("/dhcp/vendor-option-metered", test_vendor_option_metered);
|
||||
g_test_add_func("/dhcp/parse-search-list", test_parse_search_list);
|
||||
g_test_add_data_func("/dhcp/test_dhcp_opt_list/IPv4", GINT_TO_POINTER(0), test_dhcp_opt_list);
|
||||
g_test_add_data_func("/dhcp/test_dhcp_opt_list/IPv6", GINT_TO_POINTER(1), test_dhcp_opt_list);
|
||||
|
||||
return g_test_run();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -474,7 +474,7 @@ dns_servers_done:
|
|||
gsize padding;
|
||||
gsize len;
|
||||
|
||||
nm_str_buf_reset(&sbuf, NULL);
|
||||
nm_str_buf_reset(&sbuf);
|
||||
|
||||
for (i = 0; i < rdata->dns_domains->len; i++) {
|
||||
const NMNDiscDNSDomain *dns_domain =
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue