networkd-dhcp4.c revision 6c861f0aeff9449ee1201bb56f89861921e41c45
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering This file is part of systemd.
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering Copyright 2013-2014 Tom Gundersen <teg@jklm.no>
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering systemd is free software; you can redistribute it and/or modify it
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering under the terms of the GNU Lesser General Public License as published by
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering the Free Software Foundation; either version 2.1 of the License, or
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering (at your option) any later version.
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering systemd is distributed in the hope that it will be useful, but
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering Lesser General Public License for more details.
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering You should have received a copy of the GNU Lesser General Public License
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
914d6c09f1a449c60c8495c179a8bbe012315ba2Tom Gundersenstatic int dhcp4_route_handler(sd_rtnl *rtnl, sd_rtnl_message *m,
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (r < 0 && r != -EEXIST) {
db73295accbec0c6513817f0a64a92018592bb26Lennart Poettering log_link_error(link, "could not set DHCPv4 route: %s",
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poetteringstatic int link_set_dhcp_routes(Link *link) {
914d6c09f1a449c60c8495c179a8bbe012315ba2Tom Gundersen r = sd_dhcp_lease_get_router(link->dhcp_lease, &gateway);
914d6c09f1a449c60c8495c179a8bbe012315ba2Tom Gundersen if (r < 0 && r != -ENOENT) {
732b7f39a2b3b1a2af90102c6262186ae71197acRonny Chevalier "DHCP error: could not get gateway: %s",
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering _cleanup_route_free_ Route *route_gw = NULL;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering r = sd_dhcp_lease_get_address(link->dhcp_lease, &address);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering "DHCP error: could not get address: %s",
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering r = route_new_dynamic(&route, RTPROT_DHCP);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering "Could not allocate route: %s",
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering r = route_new_dynamic(&route_gw, RTPROT_DHCP);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering "Could not allocate route: %s",
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering /* The dhcp netmask may mask out the gateway. Add an explicit
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * route for the gw host so that we can route no matter the
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * netmask or existing kernel route tables. */
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering route_gw->metrics = link->network->dhcp_route_metric;
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering r = route_configure(route_gw, link, &dhcp4_route_handler);
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering "could not set host route: %s",
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering route->metrics = link->network->dhcp_route_metric;
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering r = route_configure(route, link, &dhcp4_route_handler);
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering "could not set routes: %s",
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering n = sd_dhcp_lease_get_routes(link->dhcp_lease, &static_routes);
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering "DHCP error: could not get routes: %s",
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering for (i = 0; i < n; i++) {
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering _cleanup_route_free_ Route *route = NULL;
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering r = route_new_dynamic(&route, RTPROT_DHCP);
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering log_link_error(link, "Could not allocate route: %s",
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering route->in_addr.in = static_routes[i].gw_addr;
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering route->dst_addr.in = static_routes[i].dst_addr;
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering route->dst_prefixlen = static_routes[i].dst_prefixlen;
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering route->metrics = link->network->dhcp_route_metric;
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering r = route_configure(route, link, &dhcp4_route_handler);
d57c365bf8f09fbcc649e00f7060ff30809f67c2Lennart Poettering "could not set host route: %s",
d57c365bf8f09fbcc649e00f7060ff30809f67c2Lennart Poettering _cleanup_address_free_ Address *address = NULL;
d57c365bf8f09fbcc649e00f7060ff30809f67c2Lennart Poettering log_link_warning(link, "DHCP lease lost");
d57c365bf8f09fbcc649e00f7060ff30809f67c2Lennart Poettering n = sd_dhcp_lease_get_routes(link->dhcp_lease, &routes);
266b538958932e6fc27dfce4917336e70e17e29eTom Gundersen if (n >= 0) {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering for (i = 0; i < n; i++) {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering _cleanup_route_free_ Route *route = NULL;
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering r = route_new_dynamic(&route, RTPROT_UNSPEC);
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt route->dst_prefixlen = routes[i].dst_prefixlen;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering r = sd_dhcp_lease_get_router(link->dhcp_lease, &gateway);
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt if (r >= 0) {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering _cleanup_route_free_ Route *route = NULL;
3e3db0ee860025ad663b13b0ace4e6d627611332Lennart Poettering r = route_new_dynamic(&route_gw, RTPROT_UNSPEC);
df3fb561b2df486a495a5f0bcc83168bd1860533Lennart Poettering r = route_new_dynamic(&route, RTPROT_UNSPEC);
914d6c09f1a449c60c8495c179a8bbe012315ba2Tom Gundersen r = sd_dhcp_lease_get_address(link->dhcp_lease, &addr);
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering r = sd_dhcp_lease_get_netmask(link->dhcp_lease, &netmask);
3e3db0ee860025ad663b13b0ace4e6d627611332Lennart Poettering prefixlen = in_addr_netmask_to_prefixlen(&netmask);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering address_drop(address, link, &link_address_drop_handler);
81fd1dd3a2cf4cc90a6898d562c9bb0fb238cbd7Tom Gundersen r = sd_dhcp_lease_get_mtu(link->dhcp_lease, &mtu);
81fd1dd3a2cf4cc90a6898d562c9bb0fb238cbd7Tom Gundersen "DHCP error: could not reset MTU");
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen r = sd_dhcp_lease_get_hostname(link->dhcp_lease, &hostname);
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen if (r >= 0 && hostname) {
81fd1dd3a2cf4cc90a6898d562c9bb0fb238cbd7Tom Gundersen "Failed to reset transient hostname");
81fd1dd3a2cf4cc90a6898d562c9bb0fb238cbd7Tom Gundersen link->dhcp_lease = sd_dhcp_lease_unref(link->dhcp_lease);
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersenstatic int dhcp4_address_handler(sd_rtnl *rtnl, sd_rtnl_message *m,
69fb1176c403e437c4fba763ba242b540c73898fLennart Poettering _cleanup_link_unref_ Link *link = userdata;
69fb1176c403e437c4fba763ba242b540c73898fLennart Poettering if (r < 0 && r != -EEXIST) {
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen log_link_error(link, "could not set DHCPv4 address: %s",
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen } else if (r >= 0) {
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen /* calling handler directly so take a ref */
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen prefixlen = in_addr_netmask_to_prefixlen(netmask);
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen addr->broadcast.s_addr = address->s_addr | ~netmask->s_addr;
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen /* use update rather than configure so that we will update the
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen * lifetime of an existing address if it has already been configured */
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen r = address_update(addr, link, &dhcp4_address_handler);
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersenstatic int dhcp_lease_renew(sd_dhcp_client *client, Link *link) {
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen uint32_t lifetime = CACHE_INFO_INFINITY_LIFE_TIME;
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen log_link_warning(link, "DHCP error: no lease %s",
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen r = sd_dhcp_lease_get_address(lease, &address);
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen log_link_warning(link, "DHCP error: no address: %s",
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen r = sd_dhcp_lease_get_netmask(lease, &netmask);
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen log_link_warning(link, "DHCP error: no netmask: %s",
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen r = sd_dhcp_lease_get_lifetime(link->dhcp_lease,
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen "DHCP error: no lifetime: %s",
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen r = dhcp4_update_address(link, &address, &netmask, lifetime);
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen log_link_warning(link, "could not update IP address: %s",
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersenstatic int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) {
b6a3ca6d876ab59b4f29ed67f54ef87005177906Tom Gundersen uint32_t lifetime = CACHE_INFO_INFINITY_LIFE_TIME;
69fb1176c403e437c4fba763ba242b540c73898fLennart Poettering r = sd_dhcp_client_get_lease(client, &lease);
b6a3ca6d876ab59b4f29ed67f54ef87005177906Tom Gundersen log_link_warning(link, "DHCP error: no lease: %s",
1693a943ca581aca2beebb4c812ec6c9f17b8164Lennart Poettering r = sd_dhcp_lease_get_address(lease, &address);
b6a3ca6d876ab59b4f29ed67f54ef87005177906Tom Gundersen log_link_warning(link, "DHCP error: no address: %s",
1693a943ca581aca2beebb4c812ec6c9f17b8164Lennart Poettering r = sd_dhcp_lease_get_netmask(lease, &netmask);
1693a943ca581aca2beebb4c812ec6c9f17b8164Lennart Poettering log_link_warning(link, "DHCP error: no netmask: %s",
1693a943ca581aca2beebb4c812ec6c9f17b8164Lennart Poettering prefixlen = in_addr_netmask_to_prefixlen(&netmask);
1693a943ca581aca2beebb4c812ec6c9f17b8164Lennart Poettering r = sd_dhcp_lease_get_router(lease, &gateway);
1693a943ca581aca2beebb4c812ec6c9f17b8164Lennart Poettering if (r < 0 && r != -ENOENT) {
c09da72900b03fcddade06643f24c6357f3e0482Tom Gundersen log_link_warning(link, "DHCP error: could not get gateway: %s",
69fb1176c403e437c4fba763ba242b540c73898fLennart Poettering "MESSAGE=%-*s: DHCPv4 address %u.%u.%u.%u/%u via %u.%u.%u.%u",
1d050e1e0a7082e23ee9b31fa0b819cb332b3444Lennart Poettering "ADDRESS=%u.%u.%u.%u",
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering "PREFIXLEN=%u",
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering "GATEWAY=%u.%u.%u.%u",
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering "MESSAGE=%-*s: DHCPv4 address %u.%u.%u.%u/%u",
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering "ADDRESS=%u.%u.%u.%u",
1693a943ca581aca2beebb4c812ec6c9f17b8164Lennart Poettering "PREFIXLEN=%u",
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering log_link_error(link, "Failed to set MTU "
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering r = sd_dhcp_lease_get_hostname(lease, &hostname);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering "Failed to set transient hostname to '%s'",
6c03d27d9f7e831194dbd8bd6bcdeef9273edb6eThomas Hindoe Paaboel Andersen r = sd_dhcp_lease_get_lifetime(link->dhcp_lease,
373d9f173f910d547159917401c4b1f84af85736Tom Gundersen "DHCP error: no lifetime: %s",
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering r = dhcp4_update_address(link, &address, &netmask, lifetime);
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering log_link_warning(link, "could not update IP address: %s",
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poetteringstatic void dhcp4_handler(sd_dhcp_client *client, int event, void *userdata) {
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering "DHCPv4 connection considered system critical, ignoring request to reconfigure it.");
67272d157a35e5cda4e5c904eafdcc23d20541d1Tom Gundersen "DHCP error: client failed: %s",
67272d157a35e5cda4e5c904eafdcc23d20541d1Tom Gundersen "DHCP unknown event: %d",
914d6c09f1a449c60c8495c179a8bbe012315ba2Tom Gundersen assert(IN_SET(link->network->dhcp, DHCP_SUPPORT_BOTH, DHCP_SUPPORT_V4));
914d6c09f1a449c60c8495c179a8bbe012315ba2Tom Gundersen r = sd_dhcp_client_attach_event(link->dhcp_client, NULL, 0);
df3fb561b2df486a495a5f0bcc83168bd1860533Lennart Poettering r = sd_dhcp_client_set_index(link->dhcp_client, link->ifindex);
d57c365bf8f09fbcc649e00f7060ff30809f67c2Lennart Poettering r = sd_dhcp_client_set_callback(link->dhcp_client, dhcp4_handler, link);
0d4ad91dd4fc831c31a9775b0eadf97fea6cd7f6Alin Rauta r = sd_dhcp_client_set_request_broadcast(link->dhcp_client,
d57c365bf8f09fbcc649e00f7060ff30809f67c2Lennart Poettering r = sd_dhcp_client_set_mtu(link->dhcp_client, link->mtu);
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering r = sd_dhcp_client_set_request_option(link->dhcp_client,
db73295accbec0c6513817f0a64a92018592bb26Lennart Poettering r = sd_dhcp_client_set_request_option(link->dhcp_client,
888943fc6246b2917168fff59380b58b678ba157Lennart Poettering r = sd_dhcp_client_set_request_option(link->dhcp_client,
2301cb9fdb774d0a1b3d8f5e95c5d358721ccacbLennart Poettering r = sd_dhcp_client_set_hostname(link->dhcp_client,
0d4ad91dd4fc831c31a9775b0eadf97fea6cd7f6Alin Rauta if (link->network->dhcp_vendor_class_identifier) {