Commit b93fcddf authored by Beniamino Galvani's avatar Beniamino Galvani

merge: branch 'bg/nettools-fixes'

!368
parents 924c20bf 6af6f70d
Pipeline #91831 passed with stages
in 26 minutes and 45 seconds
......@@ -139,7 +139,19 @@ int n_dhcp4_c_connection_listen(NDhcp4CConnection *connection) {
_c_cleanup_(c_closep) int fd_packet = -1;
int r;
c_assert(connection->state == N_DHCP4_C_CONNECTION_STATE_INIT);
c_assert(connection->state == N_DHCP4_C_CONNECTION_STATE_INIT ||
connection->state == N_DHCP4_C_CONNECTION_STATE_DRAINING ||
connection->state == N_DHCP4_C_CONNECTION_STATE_UDP);
if (connection->fd_packet >= 0) {
epoll_ctl(connection->fd_epoll, EPOLL_CTL_DEL, connection->fd_packet, NULL);
connection->fd_packet = c_close(connection->fd_packet);
}
if (connection->fd_udp >= 0) {
epoll_ctl(connection->fd_epoll, EPOLL_CTL_DEL, connection->fd_udp, NULL);
connection->fd_udp = c_close(connection->fd_udp);
}
r = n_dhcp4_c_socket_packet_new(&fd_packet, connection->client_config->ifindex);
if (r)
......@@ -319,7 +331,6 @@ void n_dhcp4_c_connection_get_timeout(NDhcp4CConnection *connection,
switch (connection->request->userdata.type) {
case N_DHCP4_C_MESSAGE_DISCOVER:
case N_DHCP4_C_MESSAGE_SELECT:
case N_DHCP4_C_MESSAGE_REBOOT:
case N_DHCP4_C_MESSAGE_INFORM:
/*
* Resend with an exponential backoff and a one second random
......@@ -338,6 +349,7 @@ void n_dhcp4_c_connection_get_timeout(NDhcp4CConnection *connection,
break;
case N_DHCP4_C_MESSAGE_REBIND:
case N_DHCP4_C_MESSAGE_RENEW:
case N_DHCP4_C_MESSAGE_REBOOT:
/*
* Resend every sixty seconds with a one second random slack.
*
......@@ -992,6 +1004,7 @@ static int n_dhcp4_c_connection_send_request(NDhcp4CConnection *connection,
char server_addr[INET_ADDRSTRLEN];
char client_addr[INET_ADDRSTRLEN];
int r;
bool broadcast = false;
/*
* Increment the base time and reset the xid field,
......@@ -1026,12 +1039,14 @@ static int n_dhcp4_c_connection_send_request(NDhcp4CConnection *connection,
case N_DHCP4_C_MESSAGE_SELECT:
case N_DHCP4_C_MESSAGE_REBOOT:
case N_DHCP4_C_MESSAGE_DECLINE:
case N_DHCP4_C_MESSAGE_REBIND:
broadcast = true;
r = n_dhcp4_c_connection_packet_broadcast(connection, request);
if (r)
return r;
break;
case N_DHCP4_C_MESSAGE_INFORM:
case N_DHCP4_C_MESSAGE_REBIND:
broadcast = true;
r = n_dhcp4_c_connection_udp_broadcast(connection, request);
if (r)
return r;
......@@ -1052,6 +1067,8 @@ static int n_dhcp4_c_connection_send_request(NDhcp4CConnection *connection,
n_dhcp4_c_log(connection->client_config, LOG_INFO,
"sent %s to %s",
message_type_to_str(request->userdata.message_type),
broadcast ?
"255.255.255.255" :
inet_ntop(AF_INET, &connection->server_ip,
server_addr, sizeof(server_addr)));
} else {
......@@ -1060,6 +1077,8 @@ static int n_dhcp4_c_connection_send_request(NDhcp4CConnection *connection,
message_type_to_str(request->userdata.message_type),
inet_ntop(AF_INET, &request->userdata.client_addr,
client_addr, sizeof(client_addr)),
broadcast ?
"255.255.255.255" :
inet_ntop(AF_INET, &connection->server_ip,
server_addr, sizeof(server_addr)));
}
......
......@@ -170,8 +170,6 @@ _c_public_ void n_dhcp4_client_probe_config_set_inform_only(NDhcp4ClientProbeCon
* INIT-REBOOT path, as described by the DHCP specification. In most cases, you
* do not want this.
*
* XXX: This is currently not implemented, and setting the property has no effect.
*
* Background: The INIT-REBOOT path allows a DHCP client to skip
* server-discovery when rebooting/resuming their machine. The DHCP
* client simply re-requests the lease it had acquired before. This
......@@ -438,11 +436,17 @@ int n_dhcp4_client_probe_new(NDhcp4ClientProbe **probep,
if (r)
return r;
if (probe->config->init_reboot && probe->config->requested_ip.s_addr != INADDR_ANY)
probe->state = N_DHCP4_CLIENT_PROBE_STATE_INIT_REBOOT;
else
probe->state = N_DHCP4_CLIENT_PROBE_STATE_INIT;
if (active) {
/*
* Defer the sending of DISCOVER by a random amount (by default up to 9 seconds).
*/
probe->ns_deferred = ns_now + (n_dhcp4_client_probe_config_get_random(probe->config) % (probe->config->ms_start_delay * 1000000ULL));
if (probe->state == N_DHCP4_CLIENT_PROBE_STATE_INIT)
probe->ns_deferred = ns_now + (n_dhcp4_client_probe_config_get_random(probe->config) % (probe->config->ms_start_delay * 1000000ULL));
probe->client->current_probe = probe;
} else {
r = n_dhcp4_client_probe_raise(probe,
......@@ -575,6 +579,14 @@ void n_dhcp4_client_probe_get_timeout(NDhcp4ClientProbe *probe, uint64_t *timeou
n_dhcp4_c_connection_get_timeout(&probe->connection, &timeout);
switch (probe->state) {
case N_DHCP4_CLIENT_PROBE_STATE_INIT_REBOOT:
/* send DHCP request immediately */
timeout = 1;
break;
case N_DHCP4_CLIENT_PROBE_STATE_REBOOTING:
if (probe->ns_reinit && (!timeout || probe->ns_reinit < timeout))
timeout = probe->ns_reinit;
break;
case N_DHCP4_CLIENT_PROBE_STATE_INIT:
if (probe->ns_deferred && (!timeout || probe->ns_deferred < timeout))
timeout = probe->ns_deferred;
......@@ -626,6 +638,52 @@ static int n_dhcp4_client_probe_outgoing_append_options(NDhcp4ClientProbe *probe
return 0;
}
static int n_dhcp4_client_probe_transition_reboot(NDhcp4ClientProbe *probe, uint64_t ns_now) {
_c_cleanup_(n_dhcp4_outgoing_freep) NDhcp4Outgoing *request = NULL;
int r;
switch (probe->state) {
case N_DHCP4_CLIENT_PROBE_STATE_INIT_REBOOT:
r = n_dhcp4_c_connection_listen(&probe->connection);
if (r)
return r;
r = n_dhcp4_c_connection_reboot_new(&probe->connection, &request, &probe->config->requested_ip);
if (r)
return r;
r = n_dhcp4_client_probe_outgoing_append_options(probe, request);
if (r)
return r;
r = n_dhcp4_c_connection_start_request(&probe->connection, request, ns_now);
if (r)
return r;
else
request = NULL; /* consumed */
probe->state = N_DHCP4_CLIENT_PROBE_STATE_REBOOTING;
probe->ns_reinit = ns_now + 2000000000ULL;
break;
case N_DHCP4_CLIENT_PROBE_STATE_SELECTING:
case N_DHCP4_CLIENT_PROBE_STATE_INIT:
case N_DHCP4_CLIENT_PROBE_STATE_REBOOTING:
case N_DHCP4_CLIENT_PROBE_STATE_REQUESTING:
case N_DHCP4_CLIENT_PROBE_STATE_GRANTED:
case N_DHCP4_CLIENT_PROBE_STATE_BOUND:
case N_DHCP4_CLIENT_PROBE_STATE_RENEWING:
case N_DHCP4_CLIENT_PROBE_STATE_REBINDING:
case N_DHCP4_CLIENT_PROBE_STATE_EXPIRED:
default:
abort();
break;
}
return 0;
}
static int n_dhcp4_client_probe_transition_deferred(NDhcp4ClientProbe *probe, uint64_t ns_now) {
_c_cleanup_(n_dhcp4_outgoing_freep) NDhcp4Outgoing *request = NULL;
int r;
......@@ -635,12 +693,14 @@ static int n_dhcp4_client_probe_transition_deferred(NDhcp4ClientProbe *probe, ui
r = n_dhcp4_c_connection_listen(&probe->connection);
if (r)
return r;
/* fall-through */
case N_DHCP4_CLIENT_PROBE_STATE_REBOOTING:
r = n_dhcp4_c_connection_discover_new(&probe->connection, &request);
if (r)
return r;
if (probe->config->requested_ip.s_addr != INADDR_ANY) {
if (!probe->config->init_reboot && probe->config->requested_ip.s_addr != INADDR_ANY) {
r = n_dhcp4_outgoing_append_requested_ip(request, probe->config->requested_ip);
if (r)
return r;
......@@ -663,7 +723,6 @@ static int n_dhcp4_client_probe_transition_deferred(NDhcp4ClientProbe *probe, ui
case N_DHCP4_CLIENT_PROBE_STATE_SELECTING:
case N_DHCP4_CLIENT_PROBE_STATE_INIT_REBOOT:
case N_DHCP4_CLIENT_PROBE_STATE_REBOOTING:
case N_DHCP4_CLIENT_PROBE_STATE_REQUESTING:
case N_DHCP4_CLIENT_PROBE_STATE_GRANTED:
case N_DHCP4_CLIENT_PROBE_STATE_BOUND:
......@@ -726,6 +785,10 @@ static int n_dhcp4_client_probe_transition_t2(NDhcp4ClientProbe *probe, uint64_t
switch (probe->state) {
case N_DHCP4_CLIENT_PROBE_STATE_BOUND:
case N_DHCP4_CLIENT_PROBE_STATE_RENEWING:
r = n_dhcp4_c_connection_listen(&probe->connection);
if (r)
return r;
r = n_dhcp4_c_connection_rebind_new(&probe->connection, &request);
if (r)
return r;
......@@ -848,11 +911,22 @@ static int n_dhcp4_client_probe_transition_ack(NDhcp4ClientProbe *probe, NDhcp4I
_c_cleanup_(n_dhcp4_incoming_freep) NDhcp4Incoming *message = message_take;
_c_cleanup_(n_dhcp4_client_lease_unrefp) NDhcp4ClientLease *lease = NULL;
NDhcp4CEventNode *node;
struct in_addr client = {};
struct in_addr server = {};
int r;
switch (probe->state) {
case N_DHCP4_CLIENT_PROBE_STATE_RENEWING:
case N_DHCP4_CLIENT_PROBE_STATE_REBINDING:
n_dhcp4_incoming_get_yiaddr(message, &client);
r = n_dhcp4_incoming_query_server_identifier(message, &server);
if (r)
return r;
r = n_dhcp4_c_connection_connect(&probe->connection, &client, &server);
if (r)
return r;
/* fall-through */
case N_DHCP4_CLIENT_PROBE_STATE_RENEWING:
r = n_dhcp4_client_probe_raise(probe,
&node,
......@@ -876,6 +950,7 @@ static int n_dhcp4_client_probe_transition_ack(NDhcp4ClientProbe *probe, NDhcp4I
break;
case N_DHCP4_CLIENT_PROBE_STATE_REQUESTING:
case N_DHCP4_CLIENT_PROBE_STATE_REBOOTING:
r = n_dhcp4_client_probe_raise(probe,
&node,
......@@ -900,7 +975,6 @@ static int n_dhcp4_client_probe_transition_ack(NDhcp4ClientProbe *probe, NDhcp4I
case N_DHCP4_CLIENT_PROBE_STATE_INIT:
case N_DHCP4_CLIENT_PROBE_STATE_SELECTING:
case N_DHCP4_CLIENT_PROBE_STATE_INIT_REBOOT:
case N_DHCP4_CLIENT_PROBE_STATE_REBOOTING:
case N_DHCP4_CLIENT_PROBE_STATE_BOUND:
case N_DHCP4_CLIENT_PROBE_STATE_GRANTED:
case N_DHCP4_CLIENT_PROBE_STATE_EXPIRED:
......@@ -1079,6 +1153,19 @@ int n_dhcp4_client_probe_dispatch_timer(NDhcp4ClientProbe *probe, uint64_t ns_no
int r;
switch (probe->state) {
case N_DHCP4_CLIENT_PROBE_STATE_INIT_REBOOT:
r = n_dhcp4_client_probe_transition_reboot(probe, ns_now);
if (r)
return r;
break;
case N_DHCP4_CLIENT_PROBE_STATE_REBOOTING:
if (ns_now >= probe->ns_reinit) {
r = n_dhcp4_client_probe_transition_deferred(probe, ns_now);
if (r)
return r;
}
break;
case N_DHCP4_CLIENT_PROBE_STATE_INIT:
if (ns_now >= probe->ns_deferred) {
r = n_dhcp4_client_probe_transition_deferred(probe, ns_now);
......
......@@ -681,7 +681,12 @@ _c_public_ int n_dhcp4_client_dispatch(NDhcp4Client *client) {
/* continue normally */
} else if (r) {
c_assert(r < _N_DHCP4_E_INTERNAL);
if (r >= _N_DHCP4_E_INTERNAL) {
n_dhcp4_c_log(client->config, LOG_ERR,
"invalid internal error code %d after dispatch",
r);
return N_DHCP4_E_INTERNAL;
}
return r;
}
}
......
......@@ -351,6 +351,7 @@ struct NDhcp4ClientProbe {
unsigned int state; /* current probe state */
uint64_t ns_deferred; /* timeout for deferred action */
uint64_t ns_reinit;
NDhcp4ClientLease *current_lease; /* current lease */
NDhcp4CConnection connection; /* client connection wrapper */
......
......@@ -128,6 +128,7 @@ lease_option_next_route (struct in_addr *destp,
uint8_t *data = *datap;
size_t n_data = *n_datap;
uint8_t plen;
uint8_t bytes;
if (classless) {
if (!lease_option_consume (&plen, sizeof (plen), &data, &n_data))
......@@ -136,7 +137,9 @@ lease_option_next_route (struct in_addr *destp,
if (plen > 32)
return FALSE;
if (!lease_option_consume (&dest, plen / 8, &data, &n_data))
bytes = plen == 0 ? 0 : ((plen - 1) / 8) + 1;
if (!lease_option_consume (&dest, bytes, &data, &n_data))
return FALSE;
} else {
if (!lease_option_next_in_addr (&dest, &data, &n_data))
......@@ -775,34 +778,57 @@ lease_parse_domainname (NDhcp4ClientLease *lease,
str->str);
}
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)
{
nm_auto_free_gstring GString *str = NULL;
uint8_t *data, *cache;
size_t n_data, n_cache = 0;
uint8_t *data;
size_t n_data;
gs_strfreev char **domains = NULL;
guint i;
int r;
r = n_dhcp4_client_lease_query (lease, NM_DHCP_OPTION_DHCP4_DOMAIN_SEARCH_LIST, &data, &n_data);
if (r)
return;
cache = data;
domains = nm_dhcp_parse_search_list (data, n_data);
nm_gstring_prepare (&str);
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;
g_string_append (nm_gstring_add_space_delimiter (str), domain->str);
nm_ip4_config_add_search (ip4_config, domain->str);
for (i = 0; domains && domains[i]; i++) {
g_string_append (nm_gstring_add_space_delimiter (str), domains[i]);
nm_ip4_config_add_search (ip4_config, domains[i]);
}
nm_dhcp_option_add_option (options,
_nm_dhcp_option_dhcp4_options,
......@@ -1285,8 +1311,10 @@ ip4_start (NMDhcpClient *client,
sd_dhcp_lease_get_address (lease, &last_addr);
}
if (last_addr.s_addr)
if (last_addr.s_addr) {
n_dhcp4_client_probe_config_set_requested_ip (config, last_addr);
n_dhcp4_client_probe_config_set_init_reboot (config, TRUE);
}
/* Add requested options */
for (i = 0; _nm_dhcp_option_dhcp4_options[i].name; i++) {
......
......@@ -36,5 +36,7 @@ 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);
#endif /* __NETWORKMANAGER_DHCP_UTILS_H__ */
......@@ -199,6 +199,60 @@ test_vendor_option_metered (void)
g_hash_table_destroy (options);
}
static void
test_parse_search_list (void)
{
guint8 *data;
char **domains;
data = (guint8 []) {
0x05, 'l', 'o', 'c', 'a', 'l',
0x00
};
domains = nm_dhcp_parse_search_list (data, 7);
g_assert (domains);
g_assert_cmpint (g_strv_length (domains), ==, 1);
g_assert_cmpstr (domains[0], ==, "local");
g_strfreev (domains);
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);
g_assert (domains);
g_assert_cmpint (g_strv_length (domains), ==, 4);
g_assert_cmpstr (domains[0], ==, "test.example.com");
g_assert_cmpstr (domains[1], ==, "example.com");
g_assert_cmpstr (domains[2], ==, "abc.com");
g_assert_cmpstr (domains[3], ==, "foobar");
g_strfreev (domains);
data = (guint8 []) {
0x40, 'b', 'a', 'd',
};
domains = nm_dhcp_parse_search_list (data, 4);
g_assert (!domains);
data = (guint8 []) {
0x04, 'o', 'k', 'a', 'y',
0x00,
0x40, 'b', 'a', 'd',
};
domains = nm_dhcp_parse_search_list (data, 10);
g_assert (domains);
g_assert_cmpint (g_strv_length (domains), ==, 1);
g_assert_cmpstr (domains[0], ==, "okay");
g_strfreev (domains);
}
static void
ip4_test_route (NMIP4Config *ip4_config,
guint route_num,
......@@ -732,6 +786,7 @@ int main (int argc, char **argv)
g_test_add_func ("/dhcp/ip4-prefix-classless", test_ip4_prefix_classless);
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);
return g_test_run ();
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment