static int dhcp6_address_change(Link *link, struct in6_addr *ip6_addr, uint8_t prefixlen, uint32_t lifetime_preferred, uint32_t lifetime_valid) { int r; _cleanup_address_free_ Address *addr = NULL; r = address_new(&addr); if (r < 0) return r; addr->family = AF_INET6; memcpy(&addr->in_addr.in6, ip6_addr, sizeof(*ip6_addr)); addr->flags = IFA_F_NOPREFIXROUTE; addr->prefixlen = prefixlen; addr->cinfo.ifa_prefered = lifetime_preferred; addr->cinfo.ifa_valid = lifetime_valid; log_link_info(link, "DHCPv6 address "SD_ICMP6_ND_ADDRESS_FORMAT_STR"/%d timeout preferred %d valid %d", SD_ICMP6_ND_ADDRESS_FORMAT_VAL(addr->in_addr.in6), addr->prefixlen, lifetime_preferred, lifetime_valid); r = address_configure(addr, link, dhcp6_address_handler, true); if (r < 0) log_link_warning_errno(link, r, "Could not assign DHCPv6 address: %m"); return r; }
static int dhcp6_address_change( Link *link, struct in6_addr *ip6_addr, uint32_t lifetime_preferred, uint32_t lifetime_valid) { _cleanup_address_free_ Address *addr = NULL; char buffer[INET6_ADDRSTRLEN]; int r; r = address_new(&addr); if (r < 0) return r; addr->family = AF_INET6; memcpy(&addr->in_addr.in6, ip6_addr, sizeof(*ip6_addr)); addr->flags = IFA_F_NOPREFIXROUTE; addr->prefixlen = 128; addr->cinfo.ifa_prefered = lifetime_preferred; addr->cinfo.ifa_valid = lifetime_valid; log_link_info(link, "DHCPv6 address %s/%d timeout preferred %d valid %d", inet_ntop(AF_INET6, &addr->in_addr.in6, buffer, sizeof(buffer)), addr->prefixlen, lifetime_preferred, lifetime_valid); r = address_configure(addr, link, dhcp6_address_handler, true); if (r < 0) log_link_warning_errno(link, r, "Could not assign DHCPv6 address: %m"); return r; }
static int dhcp6_prefix_expired(Link *link) { int r; sd_dhcp6_lease *lease; struct in6_addr *expired_prefix, ip6_addr; uint8_t expired_prefixlen; uint32_t lifetime_preferred, lifetime_valid; r = sd_icmp6_ra_get_expired_prefix(link->icmp6_router_discovery, &expired_prefix, &expired_prefixlen); if (r < 0) return r; r = sd_dhcp6_client_get_lease(link->dhcp6_client, &lease); if (r < 0) return r; log_link_info(link, "IPv6 prefix "SD_ICMP6_ND_ADDRESS_FORMAT_STR"/%d expired", SD_ICMP6_ND_ADDRESS_FORMAT_VAL(*expired_prefix), expired_prefixlen); sd_dhcp6_lease_reset_address_iter(lease); while (sd_dhcp6_lease_get_address(lease, &ip6_addr, &lifetime_preferred, &lifetime_valid) >= 0) { r = sd_icmp6_prefix_match(expired_prefix, expired_prefixlen, &ip6_addr); if (r < 0) continue; log_link_info(link, "IPv6 prefix length updated "SD_ICMP6_ND_ADDRESS_FORMAT_STR"/%d", SD_ICMP6_ND_ADDRESS_FORMAT_VAL(ip6_addr), 128); dhcp6_address_change(link, &ip6_addr, 128, lifetime_preferred, lifetime_valid); } return 0; }
static int link_set_dhcp_routes(Link *link) { _cleanup_free_ sd_dhcp_route **static_routes = NULL; bool classless_route = false, static_route = false; const struct in_addr *router; struct in_addr address; int r, n, i; uint32_t table; assert(link); if (!link->dhcp_lease) /* link went down while we configured the IP addresses? */ return 0; if (!link->network) /* link went down while we configured the IP addresses? */ return 0; if (!link->network->dhcp_use_routes) return 0; table = link_get_dhcp_route_table(link); r = sd_dhcp_lease_get_address(link->dhcp_lease, &address); if (r < 0) return log_link_warning_errno(link, r, "DHCP error: could not get address: %m"); n = sd_dhcp_lease_get_routes(link->dhcp_lease, &static_routes); if (n == -ENODATA) log_link_debug_errno(link, n, "DHCP: No routes received from DHCP server: %m"); else if (n < 0) log_link_debug_errno(link, n, "DHCP error: could not get routes: %m"); for (i = 0; i < n; i++) { switch (sd_dhcp_route_get_option(static_routes[i])) { case SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE: classless_route = true; break; case SD_DHCP_OPTION_STATIC_ROUTE: static_route = true; break; } } for (i = 0; i < n; i++) { _cleanup_(route_freep) Route *route = NULL; /* if the DHCP server returns both a Classless Static Routes option and a Static Routes option, the DHCP client MUST ignore the Static Routes option. */ if (classless_route && sd_dhcp_route_get_option(static_routes[i]) != SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE) continue; r = route_new(&route); if (r < 0) return log_link_error_errno(link, r, "Could not allocate route: %m"); route->family = AF_INET; route->protocol = RTPROT_DHCP; assert_se(sd_dhcp_route_get_gateway(static_routes[i], &route->gw.in) >= 0); assert_se(sd_dhcp_route_get_destination(static_routes[i], &route->dst.in) >= 0); assert_se(sd_dhcp_route_get_destination_prefix_length(static_routes[i], &route->dst_prefixlen) >= 0); route->priority = link->network->dhcp_route_metric; route->table = table; route->scope = route_scope_from_address(route, &address); r = route_configure(route, link, dhcp4_route_handler); if (r < 0) return log_link_warning_errno(link, r, "Could not set host route: %m"); link->dhcp4_messages++; } r = sd_dhcp_lease_get_router(link->dhcp_lease, &router); if (IN_SET(r, 0, -ENODATA)) log_link_info(link, "DHCP: No gateway received from DHCP server."); else if (r < 0) log_link_warning_errno(link, r, "DHCP error: could not get gateway: %m"); else if (in4_addr_is_null(&router[0])) log_link_info(link, "DHCP: Received gateway is null."); /* According to RFC 3442: If the DHCP server returns both a Classless Static Routes option and a Router option, the DHCP client MUST ignore the Router option. */ if (classless_route && static_route) log_link_warning(link, "Classless static routes received from DHCP server: ignoring static-route option and router option"); if (r > 0 && !classless_route && !in4_addr_is_null(&router[0])) { _cleanup_(route_freep) Route *route = NULL, *route_gw = NULL; r = route_new(&route_gw); if (r < 0) return log_link_error_errno(link, r, "Could not allocate route: %m"); /* The dhcp netmask may mask out the gateway. Add an explicit * route for the gw host so that we can route no matter the * netmask or existing kernel route tables. */ route_gw->family = AF_INET; route_gw->dst.in = router[0]; route_gw->dst_prefixlen = 32; route_gw->prefsrc.in = address; route_gw->scope = RT_SCOPE_LINK; route_gw->protocol = RTPROT_DHCP; route_gw->priority = link->network->dhcp_route_metric; route_gw->table = table; r = route_configure(route_gw, link, dhcp4_route_handler); if (r < 0) return log_link_warning_errno(link, r, "Could not set host route: %m"); link->dhcp4_messages++; r = route_new(&route); if (r < 0) return log_link_error_errno(link, r, "Could not allocate route: %m"); route->family = AF_INET; route->gw.in = router[0]; route->prefsrc.in = address; route->protocol = RTPROT_DHCP; route->priority = link->network->dhcp_route_metric; route->table = table; r = route_configure(route, link, dhcp4_route_handler); if (r < 0) { log_link_warning_errno(link, r, "Could not set routes: %m"); link_enter_failed(link); return r; } link->dhcp4_messages++; } return 0; }