diff options
author | Beniamino Galvani <bgalvani@redhat.com> | 2019-12-23 16:42:17 +0100 |
---|---|---|
committer | Beniamino Galvani <bgalvani@redhat.com> | 2019-12-23 16:42:17 +0100 |
commit | b93fcddfdfa97d2690524a9ab3c681a2caf5996a (patch) | |
tree | 2983cbf06137e202a1f64974ccfe6b91eba41f7f | |
parent | 924c20bf552a97b39671ef310acc195575dae4ff (diff) | |
parent | 6af6f70d812249bdbc27d63fbd9544c57c33d04d (diff) | |
download | NetworkManager-b93fcddfdfa97d2690524a9ab3c681a2caf5996a.tar.gz |
merge: branch 'bg/nettools-fixes'
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/merge_requests/368
-rw-r--r-- | shared/n-dhcp4/src/n-dhcp4-c-connection.c | 25 | ||||
-rw-r--r-- | shared/n-dhcp4/src/n-dhcp4-c-probe.c | 101 | ||||
-rw-r--r-- | shared/n-dhcp4/src/n-dhcp4-client.c | 7 | ||||
-rw-r--r-- | shared/n-dhcp4/src/n-dhcp4-private.h | 1 | ||||
-rw-r--r-- | src/dhcp/nm-dhcp-nettools.c | 60 | ||||
-rw-r--r-- | src/dhcp/nm-dhcp-utils.h | 2 | ||||
-rw-r--r-- | src/dhcp/tests/test-dhcp-utils.c | 55 |
7 files changed, 224 insertions, 27 deletions
diff --git a/shared/n-dhcp4/src/n-dhcp4-c-connection.c b/shared/n-dhcp4/src/n-dhcp4-c-connection.c index 8a2ddb3636..e51a3e3249 100644 --- a/shared/n-dhcp4/src/n-dhcp4-c-connection.c +++ b/shared/n-dhcp4/src/n-dhcp4-c-connection.c @@ -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))); } diff --git a/shared/n-dhcp4/src/n-dhcp4-c-probe.c b/shared/n-dhcp4/src/n-dhcp4-c-probe.c index 2bced4cf8a..4fb7d3892a 100644 --- a/shared/n-dhcp4/src/n-dhcp4-c-probe.c +++ b/shared/n-dhcp4/src/n-dhcp4-c-probe.c @@ -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); diff --git a/shared/n-dhcp4/src/n-dhcp4-client.c b/shared/n-dhcp4/src/n-dhcp4-client.c index 0bfe48ee95..4fa3d65daa 100644 --- a/shared/n-dhcp4/src/n-dhcp4-client.c +++ b/shared/n-dhcp4/src/n-dhcp4-client.c @@ -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; } } diff --git a/shared/n-dhcp4/src/n-dhcp4-private.h b/shared/n-dhcp4/src/n-dhcp4-private.h index 1cf5f25e55..fcfb0f35b8 100644 --- a/shared/n-dhcp4/src/n-dhcp4-private.h +++ b/shared/n-dhcp4/src/n-dhcp4-private.h @@ -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 */ diff --git a/src/dhcp/nm-dhcp-nettools.c b/src/dhcp/nm-dhcp-nettools.c index 2cb7c51b61..30820c615a 100644 --- a/src/dhcp/nm-dhcp-nettools.c +++ b/src/dhcp/nm-dhcp-nettools.c @@ -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++) { diff --git a/src/dhcp/nm-dhcp-utils.h b/src/dhcp/nm-dhcp-utils.h index e4c3331478..ecb91809be 100644 --- a/src/dhcp/nm-dhcp-utils.h +++ b/src/dhcp/nm-dhcp-utils.h @@ -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__ */ diff --git a/src/dhcp/tests/test-dhcp-utils.c b/src/dhcp/tests/test-dhcp-utils.c index d038906964..e601534eb2 100644 --- a/src/dhcp/tests/test-dhcp-utils.c +++ b/src/dhcp/tests/test-dhcp-utils.c @@ -200,6 +200,60 @@ test_vendor_option_metered (void) } 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, const char *expected_dest, @@ -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 (); } |