2 This file is part of systemd.
4 Copyright 2013-2014 Tom Gundersen <teg@jklm.no>
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 #include <netinet/ether.h>
23 #include "alloc-util.h"
24 #include "dhcp-lease-internal.h"
25 #include "hostname-util.h"
26 #include "network-internal.h"
27 #include "networkd-link.h"
28 #include "networkd-manager.h"
29 #include "networkd-network.h"
31 static int dhcp4_route_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
,
33 _cleanup_link_unref_ Link
*link
= userdata
;
37 assert(link
->dhcp4_messages
> 0);
39 link
->dhcp4_messages
--;
41 r
= sd_netlink_message_get_errno(m
);
42 if (r
< 0 && r
!= -EEXIST
) {
43 log_link_error_errno(link
, r
, "Could not set DHCPv4 route: %m");
44 link_enter_failed(link
);
47 if (link
->dhcp4_messages
== 0) {
48 link
->dhcp4_configured
= true;
49 link_check_ready(link
);
55 static int route_scope_from_address(const Route
*route
, const struct in_addr
*self_addr
) {
59 if (in_addr_is_localhost(AF_INET
, &route
->dst
) ||
60 (self_addr
->s_addr
&& route
->dst
.in
.s_addr
== self_addr
->s_addr
))
62 else if (in4_addr_is_null(&route
->gw
.in
))
65 return RT_SCOPE_UNIVERSE
;
68 static int link_set_dhcp_routes(Link
*link
) {
69 struct in_addr gateway
, address
;
70 _cleanup_free_ sd_dhcp_route
**static_routes
= NULL
;
74 assert(link
->dhcp_lease
);
75 assert(link
->network
);
77 if (!link
->network
->dhcp_use_routes
)
80 r
= sd_dhcp_lease_get_address(link
->dhcp_lease
, &address
);
82 return log_link_warning_errno(link
, r
, "DHCP error: could not get address: %m");
84 r
= sd_dhcp_lease_get_router(link
->dhcp_lease
, &gateway
);
85 if (r
< 0 && r
!= -ENODATA
)
86 return log_link_warning_errno(link
, r
, "DHCP error: could not get gateway: %m");
89 _cleanup_route_free_ Route
*route
= NULL
;
90 _cleanup_route_free_ Route
*route_gw
= NULL
;
92 r
= route_new(&route
);
94 return log_link_error_errno(link
, r
, "Could not allocate route: %m");
96 route
->protocol
= RTPROT_DHCP
;
98 r
= route_new(&route_gw
);
100 return log_link_error_errno(link
, r
, "Could not allocate route: %m");
102 /* The dhcp netmask may mask out the gateway. Add an explicit
103 * route for the gw host so that we can route no matter the
104 * netmask or existing kernel route tables. */
105 route_gw
->family
= AF_INET
;
106 route_gw
->dst
.in
= gateway
;
107 route_gw
->dst_prefixlen
= 32;
108 route_gw
->prefsrc
.in
= address
;
109 route_gw
->scope
= RT_SCOPE_LINK
;
110 route_gw
->protocol
= RTPROT_DHCP
;
111 route_gw
->priority
= link
->network
->dhcp_route_metric
;
112 route_gw
->table
= link
->network
->dhcp_route_table
;
114 r
= route_configure(route_gw
, link
, dhcp4_route_handler
);
116 return log_link_warning_errno(link
, r
, "Could not set host route: %m");
118 link
->dhcp4_messages
++;
120 route
->family
= AF_INET
;
121 route
->gw
.in
= gateway
;
122 route
->prefsrc
.in
= address
;
123 route
->priority
= link
->network
->dhcp_route_metric
;
124 route
->table
= link
->network
->dhcp_route_table
;
126 r
= route_configure(route
, link
, dhcp4_route_handler
);
128 log_link_warning_errno(link
, r
, "Could not set routes: %m");
129 link_enter_failed(link
);
133 link
->dhcp4_messages
++;
136 n
= sd_dhcp_lease_get_routes(link
->dhcp_lease
, &static_routes
);
140 return log_link_warning_errno(link
, n
, "DHCP error: could not get routes: %m");
142 for (i
= 0; i
< n
; i
++) {
143 _cleanup_route_free_ Route
*route
= NULL
;
145 r
= route_new(&route
);
147 return log_link_error_errno(link
, r
, "Could not allocate route: %m");
149 route
->family
= AF_INET
;
150 route
->protocol
= RTPROT_DHCP
;
151 assert_se(sd_dhcp_route_get_gateway(static_routes
[i
], &route
->gw
.in
) >= 0);
152 assert_se(sd_dhcp_route_get_destination(static_routes
[i
], &route
->dst
.in
) >= 0);
153 assert_se(sd_dhcp_route_get_destination_prefix_length(static_routes
[i
], &route
->dst_prefixlen
) >= 0);
154 route
->priority
= link
->network
->dhcp_route_metric
;
155 route
->table
= link
->network
->dhcp_route_table
;
156 route
->scope
= route_scope_from_address(route
, &address
);
158 r
= route_configure(route
, link
, dhcp4_route_handler
);
160 return log_link_warning_errno(link
, r
, "Could not set host route: %m");
162 link
->dhcp4_messages
++;
168 static int dhcp_lease_lost(Link
*link
) {
169 _cleanup_address_free_ Address
*address
= NULL
;
171 struct in_addr netmask
;
172 struct in_addr gateway
;
173 unsigned prefixlen
= 0;
177 assert(link
->dhcp_lease
);
179 log_link_warning(link
, "DHCP lease lost");
181 if (link
->network
->dhcp_use_routes
) {
182 _cleanup_free_ sd_dhcp_route
**routes
= NULL
;
185 n
= sd_dhcp_lease_get_routes(link
->dhcp_lease
, &routes
);
187 for (i
= 0; i
< n
; i
++) {
188 _cleanup_route_free_ Route
*route
= NULL
;
190 r
= route_new(&route
);
192 route
->family
= AF_INET
;
193 assert_se(sd_dhcp_route_get_gateway(routes
[i
], &route
->gw
.in
) >= 0);
194 assert_se(sd_dhcp_route_get_destination(routes
[i
], &route
->dst
.in
) >= 0);
195 assert_se(sd_dhcp_route_get_destination_prefix_length(routes
[i
], &route
->dst_prefixlen
) >= 0);
197 route_remove(route
, link
,
198 link_route_remove_handler
);
204 r
= address_new(&address
);
206 r
= sd_dhcp_lease_get_router(link
->dhcp_lease
, &gateway
);
208 _cleanup_route_free_ Route
*route_gw
= NULL
;
209 _cleanup_route_free_ Route
*route
= NULL
;
211 r
= route_new(&route_gw
);
213 route_gw
->family
= AF_INET
;
214 route_gw
->dst
.in
= gateway
;
215 route_gw
->dst_prefixlen
= 32;
216 route_gw
->scope
= RT_SCOPE_LINK
;
218 route_remove(route_gw
, link
,
219 link_route_remove_handler
);
222 r
= route_new(&route
);
224 route
->family
= AF_INET
;
225 route
->gw
.in
= gateway
;
227 route_remove(route
, link
,
228 link_route_remove_handler
);
232 r
= sd_dhcp_lease_get_address(link
->dhcp_lease
, &addr
);
234 r
= sd_dhcp_lease_get_netmask(link
->dhcp_lease
, &netmask
);
236 prefixlen
= in_addr_netmask_to_prefixlen(&netmask
);
238 address
->family
= AF_INET
;
239 address
->in_addr
.in
= addr
;
240 address
->prefixlen
= prefixlen
;
242 address_remove(address
, link
, link_address_remove_handler
);
246 if (link
->network
->dhcp_use_mtu
) {
249 r
= sd_dhcp_lease_get_mtu(link
->dhcp_lease
, &mtu
);
250 if (r
>= 0 && link
->original_mtu
!= mtu
) {
251 r
= link_set_mtu(link
, link
->original_mtu
);
253 log_link_warning(link
,
254 "DHCP error: could not reset MTU");
255 link_enter_failed(link
);
261 if (link
->network
->dhcp_use_hostname
) {
262 const char *hostname
= NULL
;
264 if (link
->network
->dhcp_hostname
)
265 hostname
= link
->network
->dhcp_hostname
;
267 (void) sd_dhcp_lease_get_hostname(link
->dhcp_lease
, &hostname
);
270 /* If a hostname was set due to the lease, then unset it now. */
271 r
= manager_set_hostname(link
->manager
, NULL
);
273 log_link_warning_errno(link
, r
, "Failed to reset transient hostname: %m");
277 link
->dhcp_lease
= sd_dhcp_lease_unref(link
->dhcp_lease
);
279 link
->dhcp4_configured
= false;
284 static int dhcp4_address_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
,
286 _cleanup_link_unref_ Link
*link
= userdata
;
291 r
= sd_netlink_message_get_errno(m
);
292 if (r
< 0 && r
!= -EEXIST
) {
293 log_link_error_errno(link
, r
, "Could not set DHCPv4 address: %m");
294 link_enter_failed(link
);
296 manager_rtnl_process_address(rtnl
, m
, link
->manager
);
298 link_set_dhcp_routes(link
);
303 static int dhcp4_update_address(Link
*link
,
304 struct in_addr
*address
,
305 struct in_addr
*netmask
,
307 _cleanup_address_free_ Address
*addr
= NULL
;
315 prefixlen
= in_addr_netmask_to_prefixlen(netmask
);
317 r
= address_new(&addr
);
321 addr
->family
= AF_INET
;
322 addr
->in_addr
.in
.s_addr
= address
->s_addr
;
323 addr
->cinfo
.ifa_prefered
= lifetime
;
324 addr
->cinfo
.ifa_valid
= lifetime
;
325 addr
->prefixlen
= prefixlen
;
326 addr
->broadcast
.s_addr
= address
->s_addr
| ~netmask
->s_addr
;
328 /* allow reusing an existing address and simply update its lifetime
329 * in case it already exists */
330 r
= address_configure(addr
, link
, dhcp4_address_handler
, true);
337 static int dhcp_lease_renew(sd_dhcp_client
*client
, Link
*link
) {
338 sd_dhcp_lease
*lease
;
339 struct in_addr address
;
340 struct in_addr netmask
;
341 uint32_t lifetime
= CACHE_INFO_INFINITY_LIFE_TIME
;
346 assert(link
->network
);
348 r
= sd_dhcp_client_get_lease(client
, &lease
);
350 return log_link_warning_errno(link
, r
, "DHCP error: no lease: %m");
352 sd_dhcp_lease_unref(link
->dhcp_lease
);
353 link
->dhcp4_configured
= false;
354 link
->dhcp_lease
= sd_dhcp_lease_ref(lease
);
357 r
= sd_dhcp_lease_get_address(lease
, &address
);
359 return log_link_warning_errno(link
, r
, "DHCP error: no address: %m");
361 r
= sd_dhcp_lease_get_netmask(lease
, &netmask
);
363 return log_link_warning_errno(link
, r
, "DHCP error: no netmask: %m");
365 if (!link
->network
->dhcp_critical
) {
366 r
= sd_dhcp_lease_get_lifetime(link
->dhcp_lease
, &lifetime
);
368 return log_link_warning_errno(link
, r
, "DHCP error: no lifetime: %m");
371 r
= dhcp4_update_address(link
, &address
, &netmask
, lifetime
);
373 log_link_warning_errno(link
, r
, "Could not update IP address: %m");
374 link_enter_failed(link
);
381 static int dhcp_lease_acquired(sd_dhcp_client
*client
, Link
*link
) {
382 sd_dhcp_lease
*lease
;
383 struct in_addr address
;
384 struct in_addr netmask
;
385 struct in_addr gateway
;
387 uint32_t lifetime
= CACHE_INFO_INFINITY_LIFE_TIME
;
393 r
= sd_dhcp_client_get_lease(client
, &lease
);
395 return log_link_error_errno(link
, r
, "DHCP error: No lease: %m");
397 r
= sd_dhcp_lease_get_address(lease
, &address
);
399 return log_link_error_errno(link
, r
, "DHCP error: No address: %m");
401 r
= sd_dhcp_lease_get_netmask(lease
, &netmask
);
403 return log_link_error_errno(link
, r
, "DHCP error: No netmask: %m");
405 prefixlen
= in_addr_netmask_to_prefixlen(&netmask
);
407 r
= sd_dhcp_lease_get_router(lease
, &gateway
);
408 if (r
< 0 && r
!= -ENODATA
)
409 return log_link_error_errno(link
, r
, "DHCP error: Could not get gateway: %m");
413 LOG_LINK_INTERFACE(link
),
414 LOG_LINK_MESSAGE(link
, "DHCPv4 address %u.%u.%u.%u/%u via %u.%u.%u.%u",
415 ADDRESS_FMT_VAL(address
),
417 ADDRESS_FMT_VAL(gateway
)),
418 "ADDRESS=%u.%u.%u.%u", ADDRESS_FMT_VAL(address
),
419 "PREFIXLEN=%u", prefixlen
,
420 "GATEWAY=%u.%u.%u.%u", ADDRESS_FMT_VAL(gateway
),
424 LOG_LINK_INTERFACE(link
),
425 LOG_LINK_MESSAGE(link
, "DHCPv4 address %u.%u.%u.%u/%u",
426 ADDRESS_FMT_VAL(address
),
428 "ADDRESS=%u.%u.%u.%u", ADDRESS_FMT_VAL(address
),
429 "PREFIXLEN=%u", prefixlen
,
432 link
->dhcp_lease
= sd_dhcp_lease_ref(lease
);
435 if (link
->network
->dhcp_use_mtu
) {
438 r
= sd_dhcp_lease_get_mtu(lease
, &mtu
);
440 r
= link_set_mtu(link
, mtu
);
442 log_link_error_errno(link
, r
, "Failed to set MTU to %" PRIu16
": %m", mtu
);
446 if (link
->network
->dhcp_use_hostname
) {
447 const char *hostname
= NULL
;
449 if (link
->network
->dhcp_hostname
)
450 hostname
= link
->network
->dhcp_hostname
;
452 (void) sd_dhcp_lease_get_hostname(lease
, &hostname
);
455 r
= manager_set_hostname(link
->manager
, hostname
);
457 log_link_error_errno(link
, r
, "Failed to set transient hostname to '%s': %m", hostname
);
461 if (link
->network
->dhcp_use_timezone
) {
462 const char *tz
= NULL
;
464 (void) sd_dhcp_lease_get_timezone(link
->dhcp_lease
, &tz
);
467 r
= manager_set_timezone(link
->manager
, tz
);
469 log_link_error_errno(link
, r
, "Failed to set timezone to '%s': %m", tz
);
473 if (!link
->network
->dhcp_critical
) {
474 r
= sd_dhcp_lease_get_lifetime(link
->dhcp_lease
, &lifetime
);
476 log_link_warning_errno(link
, r
, "DHCP error: no lifetime: %m");
481 r
= dhcp4_update_address(link
, &address
, &netmask
, lifetime
);
483 log_link_warning_errno(link
, r
, "Could not update IP address: %m");
484 link_enter_failed(link
);
490 static void dhcp4_handler(sd_dhcp_client
*client
, int event
, void *userdata
) {
491 Link
*link
= userdata
;
495 assert(link
->network
);
496 assert(link
->manager
);
498 if (IN_SET(link
->state
, LINK_STATE_FAILED
, LINK_STATE_LINGER
))
502 case SD_DHCP_CLIENT_EVENT_EXPIRED
:
503 case SD_DHCP_CLIENT_EVENT_STOP
:
504 case SD_DHCP_CLIENT_EVENT_IP_CHANGE
:
505 if (link
->network
->dhcp_critical
) {
506 log_link_error(link
, "DHCPv4 connection considered system critical, ignoring request to reconfigure it.");
510 if (link
->dhcp_lease
) {
511 r
= dhcp_lease_lost(link
);
513 link_enter_failed(link
);
518 if (event
== SD_DHCP_CLIENT_EVENT_IP_CHANGE
) {
519 r
= dhcp_lease_acquired(client
, link
);
521 link_enter_failed(link
);
527 case SD_DHCP_CLIENT_EVENT_RENEW
:
528 r
= dhcp_lease_renew(client
, link
);
530 link_enter_failed(link
);
534 case SD_DHCP_CLIENT_EVENT_IP_ACQUIRE
:
535 r
= dhcp_lease_acquired(client
, link
);
537 link_enter_failed(link
);
543 log_link_warning_errno(link
, event
, "DHCP error: Client failed: %m");
545 log_link_warning(link
, "DHCP unknown event: %i", event
);
552 static int dhcp4_set_hostname(Link
*link
) {
553 _cleanup_free_
char *hostname
= NULL
;
559 if (!link
->network
->dhcp_send_hostname
)
561 else if (link
->network
->dhcp_hostname
)
562 hn
= link
->network
->dhcp_hostname
;
564 r
= gethostname_strict(&hostname
);
565 if (r
< 0 && r
!= -ENXIO
) /* ENXIO: no hostname set or hostname is "localhost" */
571 return sd_dhcp_client_set_hostname(link
->dhcp_client
, hn
);
574 int dhcp4_configure(Link
*link
) {
578 assert(link
->network
);
579 assert(link
->network
->dhcp
& ADDRESS_FAMILY_IPV4
);
581 if (!link
->dhcp_client
) {
582 r
= sd_dhcp_client_new(&link
->dhcp_client
);
587 r
= sd_dhcp_client_attach_event(link
->dhcp_client
, NULL
, 0);
591 r
= sd_dhcp_client_set_mac(link
->dhcp_client
,
592 (const uint8_t *) &link
->mac
,
593 sizeof (link
->mac
), ARPHRD_ETHER
);
597 r
= sd_dhcp_client_set_ifindex(link
->dhcp_client
, link
->ifindex
);
601 r
= sd_dhcp_client_set_callback(link
->dhcp_client
, dhcp4_handler
, link
);
605 r
= sd_dhcp_client_set_request_broadcast(link
->dhcp_client
,
606 link
->network
->dhcp_broadcast
);
611 r
= sd_dhcp_client_set_mtu(link
->dhcp_client
, link
->mtu
);
616 if (link
->network
->dhcp_use_mtu
) {
617 r
= sd_dhcp_client_set_request_option(link
->dhcp_client
,
618 SD_DHCP_OPTION_INTERFACE_MTU
);
623 if (link
->network
->dhcp_use_routes
) {
624 r
= sd_dhcp_client_set_request_option(link
->dhcp_client
,
625 SD_DHCP_OPTION_STATIC_ROUTE
);
628 r
= sd_dhcp_client_set_request_option(link
->dhcp_client
,
629 SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE
);
634 /* Always acquire the timezone and NTP */
635 r
= sd_dhcp_client_set_request_option(link
->dhcp_client
, SD_DHCP_OPTION_NTP_SERVER
);
639 r
= sd_dhcp_client_set_request_option(link
->dhcp_client
, SD_DHCP_OPTION_NEW_TZDB_TIMEZONE
);
643 r
= dhcp4_set_hostname(link
);
647 if (link
->network
->dhcp_vendor_class_identifier
) {
648 r
= sd_dhcp_client_set_vendor_class_identifier(link
->dhcp_client
,
649 link
->network
->dhcp_vendor_class_identifier
);
654 if (link
->network
->dhcp_client_port
) {
655 r
= sd_dhcp_client_set_client_port(link
->dhcp_client
, link
->network
->dhcp_client_port
);
660 switch (link
->network
->dhcp_client_identifier
) {
661 case DHCP_CLIENT_ID_DUID
: {
662 /* If configured, apply user specified DUID and/or IAID */
663 const DUID
*duid
= link_duid(link
);
665 r
= sd_dhcp_client_set_iaid_duid(link
->dhcp_client
,
668 duid
->raw_data_len
> 0 ? duid
->raw_data
: NULL
,
674 case DHCP_CLIENT_ID_MAC
:
675 r
= sd_dhcp_client_set_client_id(link
->dhcp_client
,
677 (const uint8_t *) &link
->mac
,
683 assert_not_reached("Unknown client identifier type.");