static GSList * nm_dhcp_systemd_get_lease_ip_configs (const char *iface, int ifindex, const char *uuid, gboolean ipv6, guint32 default_route_metric) { GSList *leases = NULL; gs_free char *path = NULL; sd_dhcp_lease *lease = NULL; NMIP4Config *ip4_config; int r; if (ipv6) return NULL; path = get_leasefile_path (iface, uuid, FALSE); r = dhcp_lease_load (&lease, path); if (r == 0 && lease) { ip4_config = lease_to_ip4_config (iface, ifindex, lease, NULL, default_route_metric, FALSE, NULL); if (ip4_config) leases = g_slist_append (leases, ip4_config); sd_dhcp_lease_unref (lease); } return leases; }
static void test_addr_acq_acquired(sd_dhcp_client *client, int event, void *userdata) { sd_event *e = userdata; sd_dhcp_lease *lease; struct in_addr addr; assert_se(client); assert_se(event == DHCP_EVENT_IP_ACQUIRE); assert_se(sd_dhcp_client_get_lease(client, &lease) >= 0); assert_se(lease); assert_se(sd_dhcp_lease_get_address(lease, &addr) >= 0); assert_se(memcmp(&addr.s_addr, &test_addr_acq_ack[44], sizeof(addr.s_addr)) == 0); assert_se(sd_dhcp_lease_get_netmask(lease, &addr) >= 0); assert_se(memcmp(&addr.s_addr, &test_addr_acq_ack[285], sizeof(addr.s_addr)) == 0); assert_se(sd_dhcp_lease_get_router(lease, &addr) >= 0); assert_se(memcmp(&addr.s_addr, &test_addr_acq_ack[308], sizeof(addr.s_addr)) == 0); if (verbose) printf(" DHCP address acquired\n"); sd_dhcp_lease_unref(lease); sd_event_exit(e, 0); }
static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack, size_t len) { _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL; int r; r = dhcp_lease_new(&lease); if (r < 0) return r; r = dhcp_option_parse(ack, len, dhcp_lease_parse_options, lease); if (r == DHCP_NAK) { log_dhcp_client(client, "NAK"); return DHCP_EVENT_NO_LEASE; } if (r != DHCP_ACK) { log_dhcp_client(client, "receieved message was not an ACK, ignoring"); return -ENOMSG; } lease->next_server = ack->siaddr; lease->address = ack->yiaddr; if (lease->address == INADDR_ANY || lease->server_address == INADDR_ANY || lease->lifetime == 0) { log_dhcp_client(client, "receieved lease lacks address, server " "address or lease lifetime, ignoring"); return -ENOMSG; } if (lease->subnet_mask == INADDR_ANY) { r = dhcp_lease_set_default_subnet_mask(lease); if (r < 0) { log_dhcp_client(client, "receieved lease lacks subnet " "mask, and a fallback one can not be " "generated, ignoring"); return -ENOMSG; } } r = DHCP_EVENT_IP_ACQUIRE; if (client->lease) { if (client->lease->address != lease->address || client->lease->subnet_mask != lease->subnet_mask || client->lease->router != lease->router) { r = DHCP_EVENT_IP_CHANGE; } client->lease = sd_dhcp_lease_unref(client->lease); } client->lease = lease; lease = NULL; log_dhcp_client(client, "ACK"); return r; }
static int client_stop(sd_dhcp_client *client, int error) { assert_return(client, -EINVAL); client->receive_message = sd_event_source_unref(client->receive_message); if (client->fd >= 0) close_nointr_nofail(client->fd); client->fd = -1; client->timeout_resend = sd_event_source_unref(client->timeout_resend); client->timeout_t1 = sd_event_source_unref(client->timeout_t1); client->timeout_t2 = sd_event_source_unref(client->timeout_t2); client->timeout_expire = sd_event_source_unref(client->timeout_expire); client->attempt = 1; client_notify(client, error); client->start_time = 0; client->secs = 0; client->state = DHCP_STATE_INIT; if (client->lease) client->lease = sd_dhcp_lease_unref(client->lease); log_dhcp_client(client, "STOPPED"); return 0; }
static int dhcp_lease_renew(sd_dhcp_client *client, Link *link) { sd_dhcp_lease *lease; struct in_addr address; struct in_addr netmask; uint32_t lifetime = CACHE_INFO_INFINITY_LIFE_TIME; int r; assert(link); assert(client); assert(link->network); r = sd_dhcp_client_get_lease(client, &lease); if (r < 0) { log_link_warning(link, "DHCP error: no lease %s", strerror(-r)); return r; } sd_dhcp_lease_unref(link->dhcp_lease); link->dhcp4_configured = false; link->dhcp_lease = sd_dhcp_lease_ref(lease); r = sd_dhcp_lease_get_address(lease, &address); if (r < 0) { log_link_warning(link, "DHCP error: no address: %s", strerror(-r)); return r; } r = sd_dhcp_lease_get_netmask(lease, &netmask); if (r < 0) { log_link_warning(link, "DHCP error: no netmask: %s", strerror(-r)); return r; } if (!link->network->dhcp_critical) { r = sd_dhcp_lease_get_lifetime(link->dhcp_lease, &lifetime); if (r < 0) { log_link_warning(link, "DHCP error: no lifetime: %s", strerror(-r)); return r; } } r = dhcp4_update_address(link, &address, &netmask, lifetime); if (r < 0) { log_link_warning(link, "could not update IP address: %s", strerror(-r)); link_enter_failed(link); return r; } return 0; }
static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer, size_t len) { _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL; int r; r = dhcp_lease_new(&lease); if (r < 0) return r; r = dhcp_option_parse(offer, len, dhcp_lease_parse_options, lease); if (r != DHCP_OFFER) { log_dhcp_client(client, "receieved message was not an OFFER, ignoring"); return -ENOMSG; } lease->next_server = offer->siaddr; lease->address = offer->yiaddr; if (lease->address == INADDR_ANY || lease->server_address == INADDR_ANY || lease->lifetime == 0) { log_dhcp_client(client, "receieved lease lacks address, server " "address or lease lifetime, ignoring"); return -ENOMSG; } if (lease->subnet_mask == INADDR_ANY) { r = dhcp_lease_set_default_subnet_mask(lease); if (r < 0) { log_dhcp_client(client, "receieved lease lacks subnet " "mask, and a fallback one can not be " "generated, ignoring"); return -ENOMSG; } } sd_dhcp_lease_unref(client->lease); client->lease = lease; lease = NULL; log_dhcp_client(client, "OFFER"); return 0; }
sd_dhcp_client *sd_dhcp_client_unref(sd_dhcp_client *client) { if (client && REFCNT_DEC(client->n_ref) <= 0) { log_dhcp_client(client, "UNREF"); client_initialize(client); client->receive_message = sd_event_source_unref(client->receive_message); sd_dhcp_client_detach_event(client); sd_dhcp_lease_unref(client->lease); free(client->req_opts); free(client); return NULL; } return client; }
static int client_initialize(sd_dhcp_client *client) { assert_return(client, -EINVAL); client->receive_message = sd_event_source_unref(client->receive_message); client->fd = asynchronous_close(client->fd); client->timeout_resend = sd_event_source_unref(client->timeout_resend); client->timeout_t1 = sd_event_source_unref(client->timeout_t1); client->timeout_t2 = sd_event_source_unref(client->timeout_t2); client->timeout_expire = sd_event_source_unref(client->timeout_expire); client->attempt = 1; client->state = DHCP_STATE_INIT; client->xid = 0; if (client->lease) client->lease = sd_dhcp_lease_unref(client->lease); return 0; }
static int dhcp_lease_lost(Link *link) { _cleanup_address_free_ Address *address = NULL; struct in_addr addr; struct in_addr netmask; struct in_addr gateway; unsigned prefixlen = 0; int r; assert(link); assert(link->dhcp_lease); log_link_warning(link, "DHCP lease lost"); if (link->network->dhcp_use_routes) { _cleanup_free_ sd_dhcp_route **routes = NULL; int n, i; n = sd_dhcp_lease_get_routes(link->dhcp_lease, &routes); if (n >= 0) { for (i = 0; i < n; i++) { _cleanup_route_free_ Route *route = NULL; r = route_new(&route); if (r >= 0) { route->family = AF_INET; assert_se(sd_dhcp_route_get_gateway(routes[i], &route->gw.in) >= 0); assert_se(sd_dhcp_route_get_destination(routes[i], &route->dst.in) >= 0); assert_se(sd_dhcp_route_get_destination_prefix_length(routes[i], &route->dst_prefixlen) >= 0); route_remove(route, link, link_route_remove_handler); } } } } r = address_new(&address); if (r >= 0) { r = sd_dhcp_lease_get_router(link->dhcp_lease, &gateway); if (r >= 0) { _cleanup_route_free_ Route *route_gw = NULL; _cleanup_route_free_ Route *route = NULL; r = route_new(&route_gw); if (r >= 0) { route_gw->family = AF_INET; route_gw->dst.in = gateway; route_gw->dst_prefixlen = 32; route_gw->scope = RT_SCOPE_LINK; route_remove(route_gw, link, link_route_remove_handler); } r = route_new(&route); if (r >= 0) { route->family = AF_INET; route->gw.in = gateway; route_remove(route, link, link_route_remove_handler); } } r = sd_dhcp_lease_get_address(link->dhcp_lease, &addr); if (r >= 0) { r = sd_dhcp_lease_get_netmask(link->dhcp_lease, &netmask); if (r >= 0) prefixlen = in_addr_netmask_to_prefixlen(&netmask); address->family = AF_INET; address->in_addr.in = addr; address->prefixlen = prefixlen; address_remove(address, link, link_address_remove_handler); } } if (link->network->dhcp_use_mtu) { uint16_t mtu; r = sd_dhcp_lease_get_mtu(link->dhcp_lease, &mtu); if (r >= 0 && link->original_mtu != mtu) { r = link_set_mtu(link, link->original_mtu); if (r < 0) { log_link_warning(link, "DHCP error: could not reset MTU"); link_enter_failed(link); return r; } } } if (link->network->dhcp_use_hostname) { const char *hostname = NULL; if (link->network->dhcp_hostname) hostname = link->network->dhcp_hostname; else (void) sd_dhcp_lease_get_hostname(link->dhcp_lease, &hostname); if (hostname) { /* If a hostname was set due to the lease, then unset it now. */ r = manager_set_hostname(link->manager, NULL); if (r < 0) log_link_warning_errno(link, r, "Failed to reset transient hostname: %m"); } } link->dhcp_lease = sd_dhcp_lease_unref(link->dhcp_lease); link_dirty(link); link->dhcp4_configured = false; return 0; }
static gboolean ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last_ip4_address) { NMDhcpSystemd *self = NM_DHCP_SYSTEMD (client); NMDhcpSystemdPrivate *priv = NM_DHCP_SYSTEMD_GET_PRIVATE (self); const char *iface = nm_dhcp_client_get_iface (client); const GByteArray *hwaddr; sd_dhcp_lease *lease = NULL; GBytes *override_client_id; const uint8_t *client_id = NULL; size_t client_id_len = 0; struct in_addr last_addr = { 0 }; const char *hostname, *fqdn; int r, i; gboolean success = FALSE; guint16 arp_type; g_assert (priv->client4 == NULL); g_assert (priv->client6 == NULL); g_free (priv->lease_file); priv->lease_file = get_leasefile_path (iface, nm_dhcp_client_get_uuid (client), FALSE); r = sd_dhcp_client_new (&priv->client4); if (r < 0) { _LOGW ("failed to create client (%d)", r); return FALSE; } _LOGT ("dhcp-client4: set %p", priv->client4); r = sd_dhcp_client_attach_event (priv->client4, NULL, 0); if (r < 0) { _LOGW ("failed to attach event (%d)", r); goto error; } hwaddr = nm_dhcp_client_get_hw_addr (client); if (hwaddr) { arp_type= get_arp_type (hwaddr); if (arp_type == ARPHRD_NONE) { _LOGW ("failed to determine ARP type"); goto error; } r = sd_dhcp_client_set_mac (priv->client4, hwaddr->data, hwaddr->len, arp_type); if (r < 0) { _LOGW ("failed to set MAC address (%d)", r); goto error; } } r = sd_dhcp_client_set_index (priv->client4, nm_dhcp_client_get_ifindex (client)); if (r < 0) { _LOGW ("failed to set ifindex (%d)", r); goto error; } r = sd_dhcp_client_set_callback (priv->client4, dhcp_event_cb, client); if (r < 0) { _LOGW ("failed to set callback (%d)", r); goto error; } r = sd_dhcp_client_set_request_broadcast (priv->client4, true); if (r < 0) { _LOGW ("failed to enable broadcast mode (%d)", r); goto error; } dhcp_lease_load (&lease, priv->lease_file); if (last_ip4_address) inet_pton (AF_INET, last_ip4_address, &last_addr); else if (lease) sd_dhcp_lease_get_address (lease, &last_addr); if (last_addr.s_addr) { r = sd_dhcp_client_set_request_address (priv->client4, &last_addr); if (r < 0) { _LOGW ("failed to set last IPv4 address (%d)", r); goto error; } } override_client_id = nm_dhcp_client_get_client_id (client); if (override_client_id) { client_id = g_bytes_get_data (override_client_id, &client_id_len); g_assert (client_id && client_id_len); sd_dhcp_client_set_client_id (priv->client4, client_id[0], client_id + 1, client_id_len - 1); } else if (lease) { r = sd_dhcp_lease_get_client_id (lease, (const void **) &client_id, &client_id_len); if (r == 0 && client_id_len) { sd_dhcp_client_set_client_id (priv->client4, client_id[0], client_id + 1, client_id_len - 1); _save_client_id (NM_DHCP_SYSTEMD (client), client_id[0], client_id + 1, client_id_len - 1); } } /* Add requested options */ for (i = 0; dhcp4_requests[i].name; i++) { if (dhcp4_requests[i].include) sd_dhcp_client_set_request_option (priv->client4, dhcp4_requests[i].num); } hostname = nm_dhcp_client_get_hostname (client); if (hostname) { char *prefix, *dot; prefix = strdup (hostname); dot = strchr (prefix, '.'); /* get rid of the domain */ if (dot) *dot = '\0'; r = sd_dhcp_client_set_hostname (priv->client4, prefix); free (prefix); if (r < 0) { _LOGW ("failed to set DHCP hostname (%d)", r); goto error; } } fqdn = nm_dhcp_client_get_fqdn (client); if (fqdn) { r = sd_dhcp_client_set_hostname (priv->client4, fqdn); if (r < 0) { _LOGW ("failed to set DHCP FQDN (%d)", r); goto error; } } r = sd_dhcp_client_start (priv->client4); if (r < 0) { _LOGW ("failed to start client (%d)", r); goto error; } nm_dhcp_client_start_timeout (client); success = TRUE; error: sd_dhcp_lease_unref (lease); if (!success) priv->client4 = sd_dhcp_client_unref (priv->client4); return success; }
static int dhcp_lease_lost(Link *link) { _cleanup_address_free_ Address *address = NULL; struct in_addr addr; struct in_addr netmask; struct in_addr gateway; unsigned prefixlen = 0; int r; assert(link); assert(link->dhcp_lease); log_link_warning(link, "DHCP lease lost"); if (link->network->dhcp_routes) { struct sd_dhcp_route *routes; int n, i; n = sd_dhcp_lease_get_routes(link->dhcp_lease, &routes); if (n >= 0) { for (i = 0; i < n; i++) { _cleanup_route_free_ Route *route = NULL; r = route_new_dynamic(&route, RTPROT_UNSPEC); if (r >= 0) { route->family = AF_INET; route->in_addr.in = routes[i].gw_addr; route->dst_addr.in = routes[i].dst_addr; route->dst_prefixlen = routes[i].dst_prefixlen; route_drop(route, link, &link_route_drop_handler); } } } } r = address_new_dynamic(&address); if (r >= 0) { r = sd_dhcp_lease_get_router(link->dhcp_lease, &gateway); if (r >= 0) { _cleanup_route_free_ Route *route_gw = NULL; _cleanup_route_free_ Route *route = NULL; r = route_new_dynamic(&route_gw, RTPROT_UNSPEC); if (r >= 0) { route_gw->family = AF_INET; route_gw->dst_addr.in = gateway; route_gw->dst_prefixlen = 32; route_gw->scope = RT_SCOPE_LINK; route_drop(route_gw, link, &link_route_drop_handler); } r = route_new_dynamic(&route, RTPROT_UNSPEC); if (r >= 0) { route->family = AF_INET; route->in_addr.in = gateway; route_drop(route, link, &link_route_drop_handler); } } r = sd_dhcp_lease_get_address(link->dhcp_lease, &addr); if (r >= 0) { r = sd_dhcp_lease_get_netmask(link->dhcp_lease, &netmask); if (r >= 0) prefixlen = in_addr_netmask_to_prefixlen(&netmask); address->family = AF_INET; address->in_addr.in = addr; address->prefixlen = prefixlen; address_drop(address, link, &link_address_drop_handler); } } if (link->network->dhcp_mtu) { uint16_t mtu; r = sd_dhcp_lease_get_mtu(link->dhcp_lease, &mtu); if (r >= 0 && link->original_mtu != mtu) { r = link_set_mtu(link, link->original_mtu); if (r < 0) { log_link_warning(link, "DHCP error: could not reset MTU"); link_enter_failed(link); return r; } } } if (link->network->dhcp_hostname) { const char *hostname = NULL; if (!link->network->hostname) r = sd_dhcp_lease_get_hostname(link->dhcp_lease, &hostname); else hostname = link->network->hostname; if (r >= 0 || hostname) { r = link_set_hostname(link, hostname); if (r < 0) log_link_error_errno(link, r, "Failed to set transient hostname to '%s': %m", hostname); } } link->dhcp_lease = sd_dhcp_lease_unref(link->dhcp_lease); link->dhcp4_configured = false; return 0; }
static gboolean ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last_ip4_address) { NMDhcpSystemdPrivate *priv = NM_DHCP_SYSTEMD_GET_PRIVATE (client); const char *iface = nm_dhcp_client_get_iface (client); const GByteArray *hwaddr; sd_dhcp_lease *lease = NULL; GBytes *override_client_id; const uint8_t *client_id = NULL; size_t client_id_len = 0; struct in_addr last_addr = { 0 }; const char *hostname; int r, i; gboolean success = FALSE; g_assert (priv->client4 == NULL); g_assert (priv->client6 == NULL); g_free (priv->lease_file); priv->lease_file = get_leasefile_path (iface, nm_dhcp_client_get_uuid (client), FALSE); r = sd_dhcp_client_new (&priv->client4); if (r < 0) { nm_log_warn (LOGD_DHCP4, "(%s): failed to create DHCPv4 client (%d)", iface, r); return FALSE; } r = sd_dhcp_client_attach_event (priv->client4, NULL, 0); if (r < 0) { nm_log_warn (LOGD_DHCP4, "(%s): failed to attach DHCP event (%d)", iface, r); goto error; } hwaddr = nm_dhcp_client_get_hw_addr (client); if (hwaddr) { r = sd_dhcp_client_set_mac (priv->client4, hwaddr->data, hwaddr->len, get_arp_type (hwaddr)); if (r < 0) { nm_log_warn (LOGD_DHCP4, "(%s): failed to set DHCP MAC address (%d)", iface, r); goto error; } } r = sd_dhcp_client_set_index (priv->client4, nm_dhcp_client_get_ifindex (client)); if (r < 0) { nm_log_warn (LOGD_DHCP4, "(%s): failed to set DHCP ifindex (%d)", iface, r); goto error; } r = sd_dhcp_client_set_callback (priv->client4, dhcp_event_cb, client); if (r < 0) { nm_log_warn (LOGD_DHCP4, "(%s): failed to set DHCP callback (%d)", iface, r); goto error; } r = sd_dhcp_client_set_request_broadcast (priv->client4, true); if (r < 0) { nm_log_warn (LOGD_DHCP4, "(%s): failed to set DHCP broadcast (%d)", iface, r); goto error; } dhcp_lease_load (&lease, priv->lease_file); if (last_ip4_address) inet_pton (AF_INET, last_ip4_address, &last_addr); else if (lease) sd_dhcp_lease_get_address (lease, &last_addr); if (last_addr.s_addr) { r = sd_dhcp_client_set_request_address (priv->client4, &last_addr); if (r < 0) { nm_log_warn (LOGD_DHCP4, "(%s): failed to set last IPv4 address (%d)", iface, r); goto error; } } override_client_id = nm_dhcp_client_get_client_id (client); if (override_client_id) { client_id = g_bytes_get_data (override_client_id, &client_id_len); g_assert (client_id && client_id_len); sd_dhcp_client_set_client_id (priv->client4, client_id[0], client_id + 1, client_id_len - 1); } else if (lease) { r = sd_dhcp_lease_get_client_id (lease, (const void **) &client_id, &client_id_len); if (r == 0 && client_id_len) { sd_dhcp_client_set_client_id (priv->client4, client_id[0], client_id + 1, client_id_len - 1); _save_client_id (NM_DHCP_SYSTEMD (client), client_id[0], client_id + 1, client_id_len - 1); } } /* Add requested options */ for (i = 0; dhcp4_requests[i].name; i++) { if (dhcp4_requests[i].include) sd_dhcp_client_set_request_option (priv->client4, dhcp4_requests[i].num); } hostname = nm_dhcp_client_get_hostname (client); if (hostname) { r = sd_dhcp_client_set_hostname (priv->client4, hostname); if (r < 0) { nm_log_warn (LOGD_DHCP4, "(%s): failed to set DHCP hostname (%d)", iface, r); goto error; } } r = sd_dhcp_client_start (priv->client4); if (r < 0) { nm_log_warn (LOGD_DHCP4, "(%s): failed to start DHCP (%d)", iface, r); goto error; } success = TRUE; error: sd_dhcp_lease_unref (lease); if (!success) priv->client4 = sd_dhcp_client_unref (priv->client4); return success; }