dhcp/nettools: better track currently granted lease
When we accept/decline a lease, then that only works if we are in state GRANTED. n-dhcp4 API also requires us, to provide the exact lease, that we were announced earlier. As such, we need to make sure that we don't accept/decline in the wrong state. That means, to keep track of what we are doing more carefully. The functions _dhcp_client_accept()/_dhcp_client_decline() now take a l3cd argument, the one that we announced earlier. And we check that it still matches.
This commit is contained in:
@@ -73,11 +73,13 @@ G_DEFINE_ABSTRACT_TYPE(NMDhcpClient, nm_dhcp_client, G_TYPE_OBJECT)
|
|||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
static gboolean _dhcp_client_accept(NMDhcpClient *self, GError **error);
|
static gboolean _dhcp_client_accept(NMDhcpClient *self, const NML3ConfigData *l3cd, GError **error);
|
||||||
static gboolean _dhcp_client_can_accept(NMDhcpClient *self);
|
static gboolean _dhcp_client_can_accept(NMDhcpClient *self);
|
||||||
|
|
||||||
_nm_unused static gboolean
|
_nm_unused static gboolean _dhcp_client_decline(NMDhcpClient *self,
|
||||||
_dhcp_client_decline(NMDhcpClient *self, const char *error_message, GError **error);
|
const NML3ConfigData *l3cd,
|
||||||
|
const char *error_message,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
l3_cfg_notify_cb(NML3Cfg *l3cfg, const NML3ConfigNotifyData *notify_data, NMDhcpClient *self);
|
l3_cfg_notify_cb(NML3Cfg *l3cfg, const NML3ConfigNotifyData *notify_data, NMDhcpClient *self);
|
||||||
@@ -482,18 +484,19 @@ nm_dhcp_client_stop_watch_child(NMDhcpClient *self, pid_t pid)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
_dhcp_client_accept(NMDhcpClient *self, GError **error)
|
_dhcp_client_accept(NMDhcpClient *self, const NML3ConfigData *l3cd, GError **error)
|
||||||
{
|
{
|
||||||
NMDhcpClientPrivate *priv;
|
NMDhcpClientPrivate *priv;
|
||||||
|
|
||||||
g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), FALSE);
|
g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), FALSE);
|
||||||
|
nm_assert(l3cd);
|
||||||
|
|
||||||
priv = NM_DHCP_CLIENT_GET_PRIVATE(self);
|
priv = NM_DHCP_CLIENT_GET_PRIVATE(self);
|
||||||
|
|
||||||
g_return_val_if_fail(priv->l3cd, FALSE);
|
g_return_val_if_fail(priv->l3cd, FALSE);
|
||||||
|
|
||||||
if (NM_DHCP_CLIENT_GET_CLASS(self)->accept) {
|
if (NM_DHCP_CLIENT_GET_CLASS(self)->accept) {
|
||||||
return NM_DHCP_CLIENT_GET_CLASS(self)->accept(self, error);
|
return NM_DHCP_CLIENT_GET_CLASS(self)->accept(self, l3cd, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
@@ -514,18 +517,22 @@ _dhcp_client_can_accept(NMDhcpClient *self)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
_dhcp_client_decline(NMDhcpClient *self, const char *error_message, GError **error)
|
_dhcp_client_decline(NMDhcpClient *self,
|
||||||
|
const NML3ConfigData *l3cd,
|
||||||
|
const char *error_message,
|
||||||
|
GError **error)
|
||||||
{
|
{
|
||||||
NMDhcpClientPrivate *priv;
|
NMDhcpClientPrivate *priv;
|
||||||
|
|
||||||
g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), FALSE);
|
g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), FALSE);
|
||||||
|
nm_assert(l3cd);
|
||||||
|
|
||||||
priv = NM_DHCP_CLIENT_GET_PRIVATE(self);
|
priv = NM_DHCP_CLIENT_GET_PRIVATE(self);
|
||||||
|
|
||||||
g_return_val_if_fail(priv->l3cd, FALSE);
|
g_return_val_if_fail(priv->l3cd, FALSE);
|
||||||
|
|
||||||
if (NM_DHCP_CLIENT_GET_CLASS(self)->decline) {
|
if (NM_DHCP_CLIENT_GET_CLASS(self)->decline) {
|
||||||
return NM_DHCP_CLIENT_GET_CLASS(self)->decline(self, error_message, error);
|
return NM_DHCP_CLIENT_GET_CLASS(self)->decline(self, l3cd, error_message, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
@@ -650,9 +657,9 @@ l3_cfg_notify_cb(NML3Cfg *l3cfg, const NML3ConfigNotifyData *notify_data, NMDhcp
|
|||||||
priv->l3cfg_notify.wait_dhcp_commit = FALSE;
|
priv->l3cfg_notify.wait_dhcp_commit = FALSE;
|
||||||
l3_cfg_notify_check_connected(self);
|
l3_cfg_notify_check_connected(self);
|
||||||
|
|
||||||
_LOGD("accept address");
|
_LOGD("accept lease");
|
||||||
|
|
||||||
if (!_dhcp_client_accept(self, &error)) {
|
if (!_dhcp_client_accept(self, priv->l3cd, &error)) {
|
||||||
gs_free char *reason = g_strdup_printf("error accepting lease: %s", error->message);
|
gs_free char *reason = g_strdup_printf("error accepting lease: %s", error->message);
|
||||||
|
|
||||||
_emit_notify(self,
|
_emit_notify(self,
|
||||||
|
@@ -200,9 +200,12 @@ typedef struct {
|
|||||||
|
|
||||||
gboolean (*ip4_start)(NMDhcpClient *self, GError **error);
|
gboolean (*ip4_start)(NMDhcpClient *self, GError **error);
|
||||||
|
|
||||||
gboolean (*accept)(NMDhcpClient *self, GError **error);
|
gboolean (*accept)(NMDhcpClient *self, const NML3ConfigData *l3cd, GError **error);
|
||||||
|
|
||||||
gboolean (*decline)(NMDhcpClient *self, const char *error_message, GError **error);
|
gboolean (*decline)(NMDhcpClient *self,
|
||||||
|
const NML3ConfigData *l3cd,
|
||||||
|
const char *error_message,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
gboolean (*ip6_start)(NMDhcpClient *self, const struct in6_addr *ll_addr, GError **error);
|
gboolean (*ip6_start)(NMDhcpClient *self, const struct in6_addr *ll_addr, GError **error);
|
||||||
|
|
||||||
|
@@ -52,7 +52,12 @@ typedef struct _NMDhcpNettoolsClass NMDhcpNettoolsClass;
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
NDhcp4Client *client;
|
NDhcp4Client *client;
|
||||||
NDhcp4ClientProbe *probe;
|
NDhcp4ClientProbe *probe;
|
||||||
|
|
||||||
|
struct {
|
||||||
NDhcp4ClientLease *lease;
|
NDhcp4ClientLease *lease;
|
||||||
|
const NML3ConfigData *lease_l3cd;
|
||||||
|
} granted;
|
||||||
|
|
||||||
GSource *event_source;
|
GSource *event_source;
|
||||||
char *lease_file;
|
char *lease_file;
|
||||||
} NMDhcpNettoolsPrivate;
|
} NMDhcpNettoolsPrivate;
|
||||||
@@ -864,15 +869,19 @@ lease_save(NMDhcpNettools *self, NDhcp4ClientLease *lease, const char *lease_fil
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
bound4_handle(NMDhcpNettools *self, NDhcp4ClientLease *lease, gboolean extended)
|
bound4_handle(NMDhcpNettools *self, guint event, NDhcp4ClientLease *lease)
|
||||||
{
|
{
|
||||||
NMDhcpNettoolsPrivate *priv = NM_DHCP_NETTOOLS_GET_PRIVATE(self);
|
NMDhcpNettoolsPrivate *priv = NM_DHCP_NETTOOLS_GET_PRIVATE(self);
|
||||||
NMDhcpClient *client = NM_DHCP_CLIENT(self);
|
NMDhcpClient *client = NM_DHCP_CLIENT(self);
|
||||||
const NMDhcpClientConfig *client_config;
|
const NMDhcpClientConfig *client_config;
|
||||||
nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL;
|
nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL;
|
||||||
GError *error = NULL;
|
gs_free_error GError *error = NULL;
|
||||||
|
|
||||||
|
nm_assert(NM_IN_SET(event, N_DHCP4_CLIENT_EVENT_GRANTED, N_DHCP4_CLIENT_EVENT_EXTENDED));
|
||||||
|
nm_assert(lease);
|
||||||
|
|
||||||
|
_LOGT("lease available (%s)", (event == N_DHCP4_CLIENT_EVENT_GRANTED) ? "granted" : "extended");
|
||||||
|
|
||||||
_LOGT("lease available (%s)", extended ? "extended" : "new");
|
|
||||||
client_config = nm_dhcp_client_get_config(client);
|
client_config = nm_dhcp_client_get_config(client);
|
||||||
l3cd = lease_to_ip4_config(nm_dhcp_client_get_multi_idx(client),
|
l3cd = lease_to_ip4_config(nm_dhcp_client_get_multi_idx(client),
|
||||||
client_config->iface,
|
client_config->iface,
|
||||||
@@ -881,16 +890,24 @@ bound4_handle(NMDhcpNettools *self, NDhcp4ClientLease *lease, gboolean extended)
|
|||||||
&error);
|
&error);
|
||||||
if (!l3cd) {
|
if (!l3cd) {
|
||||||
_LOGW("failure to parse lease: %s", error->message);
|
_LOGW("failure to parse lease: %s", error->message);
|
||||||
g_clear_error(&error);
|
|
||||||
|
if (event == N_DHCP4_CLIENT_EVENT_GRANTED)
|
||||||
|
n_dhcp4_client_lease_decline(lease, "invalid lease");
|
||||||
|
|
||||||
_nm_dhcp_client_notify(NM_DHCP_CLIENT(self), NM_DHCP_CLIENT_EVENT_TYPE_FAIL, NULL);
|
_nm_dhcp_client_notify(NM_DHCP_CLIENT(self), NM_DHCP_CLIENT_EVENT_TYPE_FAIL, NULL);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (event == N_DHCP4_CLIENT_EVENT_GRANTED) {
|
||||||
|
priv->granted.lease = n_dhcp4_client_lease_ref(lease);
|
||||||
|
priv->granted.lease_l3cd = nm_l3_config_data_ref(l3cd);
|
||||||
|
} else
|
||||||
lease_save(self, lease, priv->lease_file);
|
lease_save(self, lease, priv->lease_file);
|
||||||
|
|
||||||
_nm_dhcp_client_notify(NM_DHCP_CLIENT(self),
|
_nm_dhcp_client_notify(NM_DHCP_CLIENT(self),
|
||||||
extended ? NM_DHCP_CLIENT_EVENT_TYPE_EXTENDED
|
event == N_DHCP4_CLIENT_EVENT_GRANTED
|
||||||
: NM_DHCP_CLIENT_EVENT_TYPE_BOUND,
|
? NM_DHCP_CLIENT_EVENT_TYPE_BOUND
|
||||||
|
: NM_DHCP_CLIENT_EVENT_TYPE_EXTENDED,
|
||||||
l3cd);
|
l3cd);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -906,6 +923,16 @@ dhcp4_event_handle(NMDhcpNettools *self, NDhcp4ClientEvent *event)
|
|||||||
_LOGT("client event %d", event->event);
|
_LOGT("client event %d", event->event);
|
||||||
client_config = nm_dhcp_client_get_config(NM_DHCP_CLIENT(self));
|
client_config = nm_dhcp_client_get_config(NM_DHCP_CLIENT(self));
|
||||||
|
|
||||||
|
if (!NM_IN_SET(event->event, N_DHCP4_CLIENT_EVENT_LOG)) {
|
||||||
|
/* In almost all events (even those that we don't expect below), we clear
|
||||||
|
* the currently granted lease. That is, because in GRANTED state we
|
||||||
|
* expect to follow up with accept/decline, and that only works while
|
||||||
|
* we are still in the same state. Transitioning away to another state
|
||||||
|
* (on most events) will invalidate that. */
|
||||||
|
nm_clear_pointer(&priv->granted.lease, n_dhcp4_client_lease_unref);
|
||||||
|
nm_clear_l3cd(&priv->granted.lease_l3cd);
|
||||||
|
}
|
||||||
|
|
||||||
switch (event->event) {
|
switch (event->event) {
|
||||||
case N_DHCP4_CLIENT_EVENT_OFFER:
|
case N_DHCP4_CLIENT_EVENT_OFFER:
|
||||||
r = n_dhcp4_client_lease_get_server_identifier(event->offer.lease, &server_id);
|
r = n_dhcp4_client_lease_get_server_identifier(event->offer.lease, &server_id);
|
||||||
@@ -934,11 +961,10 @@ dhcp4_event_handle(NMDhcpNettools *self, NDhcp4ClientEvent *event)
|
|||||||
_nm_dhcp_client_notify(NM_DHCP_CLIENT(self), NM_DHCP_CLIENT_EVENT_TYPE_FAIL, NULL);
|
_nm_dhcp_client_notify(NM_DHCP_CLIENT(self), NM_DHCP_CLIENT_EVENT_TYPE_FAIL, NULL);
|
||||||
break;
|
break;
|
||||||
case N_DHCP4_CLIENT_EVENT_GRANTED:
|
case N_DHCP4_CLIENT_EVENT_GRANTED:
|
||||||
priv->lease = n_dhcp4_client_lease_ref(event->granted.lease);
|
bound4_handle(self, event->event, event->granted.lease);
|
||||||
bound4_handle(self, event->granted.lease, FALSE);
|
|
||||||
break;
|
break;
|
||||||
case N_DHCP4_CLIENT_EVENT_EXTENDED:
|
case N_DHCP4_CLIENT_EVENT_EXTENDED:
|
||||||
bound4_handle(self, event->extended.lease, TRUE);
|
bound4_handle(self, event->event, event->extended.lease);
|
||||||
break;
|
break;
|
||||||
case N_DHCP4_CLIENT_EVENT_DOWN:
|
case N_DHCP4_CLIENT_EVENT_DOWN:
|
||||||
/* ignore down events, they are purely informational */
|
/* ignore down events, they are purely informational */
|
||||||
@@ -1098,46 +1124,65 @@ nettools_create(NMDhcpNettools *self, GError **error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
_accept(NMDhcpClient *client, GError **error)
|
_accept(NMDhcpClient *client, const NML3ConfigData *l3cd, GError **error)
|
||||||
{
|
{
|
||||||
NMDhcpNettools *self = NM_DHCP_NETTOOLS(client);
|
NMDhcpNettools *self = NM_DHCP_NETTOOLS(client);
|
||||||
NMDhcpNettoolsPrivate *priv = NM_DHCP_NETTOOLS_GET_PRIVATE(self);
|
NMDhcpNettoolsPrivate *priv = NM_DHCP_NETTOOLS_GET_PRIVATE(self);
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
g_return_val_if_fail(priv->lease, FALSE);
|
|
||||||
|
|
||||||
_LOGT("accept");
|
_LOGT("accept");
|
||||||
|
|
||||||
r = n_dhcp4_client_lease_accept(priv->lease);
|
g_return_val_if_fail(l3cd, FALSE);
|
||||||
|
|
||||||
|
if (priv->granted.lease_l3cd != l3cd) {
|
||||||
|
nm_utils_error_set(error, NM_UTILS_ERROR_UNKNOWN, "calling accept in unexpected state");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
nm_assert(priv->granted.lease);
|
||||||
|
|
||||||
|
r = n_dhcp4_client_lease_accept(priv->granted.lease);
|
||||||
|
|
||||||
|
nm_clear_pointer(&priv->granted.lease, n_dhcp4_client_lease_unref);
|
||||||
|
nm_clear_l3cd(&priv->granted.lease_l3cd);
|
||||||
|
|
||||||
if (r) {
|
if (r) {
|
||||||
set_error_nettools(error, r, "failed to accept lease");
|
set_error_nettools(error, r, "failed to accept lease");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
priv->lease = n_dhcp4_client_lease_unref(priv->lease);
|
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
decline(NMDhcpClient *client, const char *error_message, GError **error)
|
decline(NMDhcpClient *client, const NML3ConfigData *l3cd, const char *error_message, GError **error)
|
||||||
{
|
{
|
||||||
NMDhcpNettools *self = NM_DHCP_NETTOOLS(client);
|
NMDhcpNettools *self = NM_DHCP_NETTOOLS(client);
|
||||||
NMDhcpNettoolsPrivate *priv = NM_DHCP_NETTOOLS_GET_PRIVATE(self);
|
NMDhcpNettoolsPrivate *priv = NM_DHCP_NETTOOLS_GET_PRIVATE(self);
|
||||||
int r;
|
int r;
|
||||||
|
nm_auto(n_dhcp4_client_lease_unrefp) NDhcp4ClientLease *lease = NULL;
|
||||||
|
|
||||||
g_return_val_if_fail(priv->lease, FALSE);
|
_LOGT("decline (%s)", error_message);
|
||||||
|
|
||||||
_LOGT("dhcp4-client: decline (%s)", error_message);
|
g_return_val_if_fail(l3cd, FALSE);
|
||||||
|
|
||||||
|
if (priv->granted.lease_l3cd != l3cd) {
|
||||||
|
nm_utils_error_set(error, NM_UTILS_ERROR_UNKNOWN, "calling decline in unexpected state");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
nm_assert(priv->granted.lease);
|
||||||
|
|
||||||
|
lease = g_steal_pointer(&priv->granted.lease);
|
||||||
|
nm_clear_l3cd(&priv->granted.lease_l3cd);
|
||||||
|
|
||||||
|
r = n_dhcp4_client_lease_decline(lease, error_message);
|
||||||
|
|
||||||
r = n_dhcp4_client_lease_decline(priv->lease, error_message);
|
|
||||||
if (r) {
|
if (r) {
|
||||||
set_error_nettools(error, r, "failed to decline lease");
|
set_error_nettools(error, r, "failed to decline lease");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
priv->lease = n_dhcp4_client_lease_unref(priv->lease);
|
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1348,7 +1393,8 @@ dispose(GObject *object)
|
|||||||
|
|
||||||
nm_clear_g_free(&priv->lease_file);
|
nm_clear_g_free(&priv->lease_file);
|
||||||
nm_clear_g_source_inst(&priv->event_source);
|
nm_clear_g_source_inst(&priv->event_source);
|
||||||
nm_clear_pointer(&priv->lease, n_dhcp4_client_lease_unref);
|
nm_clear_pointer(&priv->granted.lease, n_dhcp4_client_lease_unref);
|
||||||
|
nm_clear_l3cd(&priv->granted.lease_l3cd);
|
||||||
nm_clear_pointer(&priv->probe, n_dhcp4_client_probe_free);
|
nm_clear_pointer(&priv->probe, n_dhcp4_client_probe_free);
|
||||||
nm_clear_pointer(&priv->client, n_dhcp4_client_unref);
|
nm_clear_pointer(&priv->client, n_dhcp4_client_unref);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user