1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2013-2014 Tom Gundersen <teg@jklm.no>
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
21 #include <netinet/ether.h>
24 #include "alloc-util.h"
25 #include "dhcp-lease-internal.h"
26 #include "hostname-util.h"
27 #include "netdev/vrf.h"
28 #include "network-internal.h"
29 #include "networkd-link.h"
30 #include "networkd-manager.h"
31 #include "networkd-network.h"
33 static int dhcp4_route_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
,
35 _cleanup_link_unref_ Link
*link
= userdata
;
39 assert(link
->dhcp4_messages
> 0);
41 link
->dhcp4_messages
--;
43 r
= sd_netlink_message_get_errno(m
);
44 if (r
< 0 && r
!= -EEXIST
) {
45 log_link_error_errno(link
, r
, "Could not set DHCPv4 route: %m");
46 link_enter_failed(link
);
49 if (link
->dhcp4_messages
== 0) {
50 link
->dhcp4_configured
= true;
51 link_check_ready(link
);
57 static int route_scope_from_address(const Route
*route
, const struct in_addr
*self_addr
) {
61 if (in_addr_is_localhost(AF_INET
, &route
->dst
) ||
62 (self_addr
->s_addr
&& route
->dst
.in
.s_addr
== self_addr
->s_addr
))
64 else if (in4_addr_is_null(&route
->gw
.in
))
67 return RT_SCOPE_UNIVERSE
;
70 static int link_set_dhcp_routes(Link
*link
) {
71 struct in_addr gateway
, address
;
72 _cleanup_free_ sd_dhcp_route
**static_routes
= NULL
;
78 if (!link
->dhcp_lease
) /* link went down while we configured the IP addresses? */
81 if (!link
->network
) /* link went down while we configured the IP addresses? */
84 if (!link
->network
->dhcp_use_routes
)
87 /* When the interface is part of an VRF use the VRFs routing table, unless
88 * there is a another table specified. */
89 table
= link
->network
->dhcp_route_table
;
90 if (!link
->network
->dhcp_route_table_set
&& link
->network
->vrf
!= NULL
)
91 table
= VRF(link
->network
->vrf
)->table
;
93 r
= sd_dhcp_lease_get_address(link
->dhcp_lease
, &address
);
95 return log_link_warning_errno(link
, r
, "DHCP error: could not get address: %m");
97 n
= sd_dhcp_lease_get_routes(link
->dhcp_lease
, &static_routes
);
101 return log_link_warning_errno(link
, n
, "DHCP error: could not get routes: %m");
103 for (i
= 0; i
< n
; i
++) {
104 _cleanup_route_free_ Route
*route
= NULL
;
106 r
= route_new(&route
);
108 return log_link_error_errno(link
, r
, "Could not allocate route: %m");
110 route
->family
= AF_INET
;
111 route
->protocol
= RTPROT_DHCP
;
112 assert_se(sd_dhcp_route_get_gateway(static_routes
[i
], &route
->gw
.in
) >= 0);
113 assert_se(sd_dhcp_route_get_destination(static_routes
[i
], &route
->dst
.in
) >= 0);
114 assert_se(sd_dhcp_route_get_destination_prefix_length(static_routes
[i
], &route
->dst_prefixlen
) >= 0);
115 route
->priority
= link
->network
->dhcp_route_metric
;
116 route
->table
= table
;
117 route
->scope
= route_scope_from_address(route
, &address
);
119 r
= route_configure(route
, link
, dhcp4_route_handler
);
121 return log_link_warning_errno(link
, r
, "Could not set host route: %m");
123 link
->dhcp4_messages
++;
126 r
= sd_dhcp_lease_get_router(link
->dhcp_lease
, &gateway
);
128 log_link_info_errno(link
, r
, "DHCP: No routes received from DHCP server: %m");
130 log_link_warning_errno(link
, r
, "DHCP error: could not get gateway: %m");
132 /* According to RFC 3442: If the DHCP server returns both a Classless Static Routes option and
133 a Router option, the DHCP client MUST ignore the Router option. */
134 if (r
>= 0 && link
->dhcp4_messages
<= 0) {
135 _cleanup_route_free_ Route
*route
= NULL
;
136 _cleanup_route_free_ Route
*route_gw
= NULL
;
138 r
= route_new(&route
);
140 return log_link_error_errno(link
, r
, "Could not allocate route: %m");
142 route
->protocol
= RTPROT_DHCP
;
144 r
= route_new(&route_gw
);
146 return log_link_error_errno(link
, r
, "Could not allocate route: %m");
148 /* The dhcp netmask may mask out the gateway. Add an explicit
149 * route for the gw host so that we can route no matter the
150 * netmask or existing kernel route tables. */
151 route_gw
->family
= AF_INET
;
152 route_gw
->dst
.in
= gateway
;
153 route_gw
->dst_prefixlen
= 32;
154 route_gw
->prefsrc
.in
= address
;
155 route_gw
->scope
= RT_SCOPE_LINK
;
156 route_gw
->protocol
= RTPROT_DHCP
;
157 route_gw
->priority
= link
->network
->dhcp_route_metric
;
158 route_gw
->table
= table
;
160 r
= route_configure(route_gw
, link
, dhcp4_route_handler
);
162 return log_link_warning_errno(link
, r
, "Could not set host route: %m");
164 link
->dhcp4_messages
++;
166 route
->family
= AF_INET
;
167 route
->gw
.in
= gateway
;
168 route
->prefsrc
.in
= address
;
169 route
->priority
= link
->network
->dhcp_route_metric
;
170 route
->table
= table
;
172 r
= route_configure(route
, link
, dhcp4_route_handler
);
174 log_link_warning_errno(link
, r
, "Could not set routes: %m");
175 link_enter_failed(link
);
179 link
->dhcp4_messages
++;
185 static int dhcp_lease_lost(Link
*link
) {
186 _cleanup_address_free_ Address
*address
= NULL
;
188 struct in_addr netmask
;
189 struct in_addr gateway
;
190 unsigned prefixlen
= 0;
194 assert(link
->dhcp_lease
);
196 log_link_warning(link
, "DHCP lease lost");
198 if (link
->network
->dhcp_use_routes
) {
199 _cleanup_free_ sd_dhcp_route
**routes
= NULL
;
202 n
= sd_dhcp_lease_get_routes(link
->dhcp_lease
, &routes
);
204 for (i
= 0; i
< n
; i
++) {
205 _cleanup_route_free_ Route
*route
= NULL
;
207 r
= route_new(&route
);
209 route
->family
= AF_INET
;
210 assert_se(sd_dhcp_route_get_gateway(routes
[i
], &route
->gw
.in
) >= 0);
211 assert_se(sd_dhcp_route_get_destination(routes
[i
], &route
->dst
.in
) >= 0);
212 assert_se(sd_dhcp_route_get_destination_prefix_length(routes
[i
], &route
->dst_prefixlen
) >= 0);
214 route_remove(route
, link
,
215 link_route_remove_handler
);
221 r
= address_new(&address
);
223 r
= sd_dhcp_lease_get_router(link
->dhcp_lease
, &gateway
);
225 _cleanup_route_free_ Route
*route_gw
= NULL
;
226 _cleanup_route_free_ Route
*route
= NULL
;
228 r
= route_new(&route_gw
);
230 route_gw
->family
= AF_INET
;
231 route_gw
->dst
.in
= gateway
;
232 route_gw
->dst_prefixlen
= 32;
233 route_gw
->scope
= RT_SCOPE_LINK
;
235 route_remove(route_gw
, link
,
236 link_route_remove_handler
);
239 r
= route_new(&route
);
241 route
->family
= AF_INET
;
242 route
->gw
.in
= gateway
;
244 route_remove(route
, link
,
245 link_route_remove_handler
);
249 r
= sd_dhcp_lease_get_address(link
->dhcp_lease
, &addr
);
251 r
= sd_dhcp_lease_get_netmask(link
->dhcp_lease
, &netmask
);
253 prefixlen
= in4_addr_netmask_to_prefixlen(&netmask
);
255 address
->family
= AF_INET
;
256 address
->in_addr
.in
= addr
;
257 address
->prefixlen
= prefixlen
;
259 address_remove(address
, link
, link_address_remove_handler
);
263 if (link
->network
->dhcp_use_mtu
) {
266 r
= sd_dhcp_lease_get_mtu(link
->dhcp_lease
, &mtu
);
267 if (r
>= 0 && link
->original_mtu
!= mtu
) {
268 r
= link_set_mtu(link
, link
->original_mtu
);
270 log_link_warning(link
,
271 "DHCP error: could not reset MTU");
272 link_enter_failed(link
);
278 if (link
->network
->dhcp_use_hostname
) {
279 const char *hostname
= NULL
;
281 if (link
->network
->dhcp_hostname
)
282 hostname
= link
->network
->dhcp_hostname
;
284 (void) sd_dhcp_lease_get_hostname(link
->dhcp_lease
, &hostname
);
287 /* If a hostname was set due to the lease, then unset it now. */
288 r
= manager_set_hostname(link
->manager
, NULL
);
290 log_link_warning_errno(link
, r
, "Failed to reset transient hostname: %m");
294 link
->dhcp_lease
= sd_dhcp_lease_unref(link
->dhcp_lease
);
296 link
->dhcp4_configured
= false;
301 static int dhcp4_address_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
,
303 _cleanup_link_unref_ Link
*link
= userdata
;
308 r
= sd_netlink_message_get_errno(m
);
309 if (r
< 0 && r
!= -EEXIST
) {
310 log_link_error_errno(link
, r
, "Could not set DHCPv4 address: %m");
311 link_enter_failed(link
);
313 manager_rtnl_process_address(rtnl
, m
, link
->manager
);
315 link_set_dhcp_routes(link
);
320 static int dhcp4_update_address(Link
*link
,
321 struct in_addr
*address
,
322 struct in_addr
*netmask
,
324 _cleanup_address_free_ Address
*addr
= NULL
;
332 prefixlen
= in4_addr_netmask_to_prefixlen(netmask
);
334 r
= address_new(&addr
);
338 addr
->family
= AF_INET
;
339 addr
->in_addr
.in
.s_addr
= address
->s_addr
;
340 addr
->cinfo
.ifa_prefered
= lifetime
;
341 addr
->cinfo
.ifa_valid
= lifetime
;
342 addr
->prefixlen
= prefixlen
;
343 addr
->broadcast
.s_addr
= address
->s_addr
| ~netmask
->s_addr
;
345 /* allow reusing an existing address and simply update its lifetime
346 * in case it already exists */
347 r
= address_configure(addr
, link
, dhcp4_address_handler
, true);
354 static int dhcp_lease_renew(sd_dhcp_client
*client
, Link
*link
) {
355 sd_dhcp_lease
*lease
;
356 struct in_addr address
;
357 struct in_addr netmask
;
358 uint32_t lifetime
= CACHE_INFO_INFINITY_LIFE_TIME
;
363 assert(link
->network
);
365 r
= sd_dhcp_client_get_lease(client
, &lease
);
367 return log_link_warning_errno(link
, r
, "DHCP error: no lease: %m");
369 sd_dhcp_lease_unref(link
->dhcp_lease
);
370 link
->dhcp4_configured
= false;
371 link
->dhcp_lease
= sd_dhcp_lease_ref(lease
);
374 r
= sd_dhcp_lease_get_address(lease
, &address
);
376 return log_link_warning_errno(link
, r
, "DHCP error: no address: %m");
378 r
= sd_dhcp_lease_get_netmask(lease
, &netmask
);
380 return log_link_warning_errno(link
, r
, "DHCP error: no netmask: %m");
382 if (!link
->network
->dhcp_critical
) {
383 r
= sd_dhcp_lease_get_lifetime(link
->dhcp_lease
, &lifetime
);
385 return log_link_warning_errno(link
, r
, "DHCP error: no lifetime: %m");
388 r
= dhcp4_update_address(link
, &address
, &netmask
, lifetime
);
390 log_link_warning_errno(link
, r
, "Could not update IP address: %m");
391 link_enter_failed(link
);
398 static int dhcp_lease_acquired(sd_dhcp_client
*client
, Link
*link
) {
399 sd_dhcp_lease
*lease
;
400 struct in_addr address
;
401 struct in_addr netmask
;
402 struct in_addr gateway
;
404 uint32_t lifetime
= CACHE_INFO_INFINITY_LIFE_TIME
;
410 r
= sd_dhcp_client_get_lease(client
, &lease
);
412 return log_link_error_errno(link
, r
, "DHCP error: No lease: %m");
414 r
= sd_dhcp_lease_get_address(lease
, &address
);
416 return log_link_error_errno(link
, r
, "DHCP error: No address: %m");
418 r
= sd_dhcp_lease_get_netmask(lease
, &netmask
);
420 return log_link_error_errno(link
, r
, "DHCP error: No netmask: %m");
422 prefixlen
= in4_addr_netmask_to_prefixlen(&netmask
);
424 r
= sd_dhcp_lease_get_router(lease
, &gateway
);
425 if (r
< 0 && r
!= -ENODATA
)
426 return log_link_error_errno(link
, r
, "DHCP error: Could not get gateway: %m");
430 LOG_LINK_INTERFACE(link
),
431 LOG_LINK_MESSAGE(link
, "DHCPv4 address %u.%u.%u.%u/%u via %u.%u.%u.%u",
432 ADDRESS_FMT_VAL(address
),
434 ADDRESS_FMT_VAL(gateway
)),
435 "ADDRESS=%u.%u.%u.%u", ADDRESS_FMT_VAL(address
),
436 "PREFIXLEN=%u", prefixlen
,
437 "GATEWAY=%u.%u.%u.%u", ADDRESS_FMT_VAL(gateway
),
441 LOG_LINK_INTERFACE(link
),
442 LOG_LINK_MESSAGE(link
, "DHCPv4 address %u.%u.%u.%u/%u",
443 ADDRESS_FMT_VAL(address
),
445 "ADDRESS=%u.%u.%u.%u", ADDRESS_FMT_VAL(address
),
446 "PREFIXLEN=%u", prefixlen
,
449 link
->dhcp_lease
= sd_dhcp_lease_ref(lease
);
452 if (link
->network
->dhcp_use_mtu
) {
455 r
= sd_dhcp_lease_get_mtu(lease
, &mtu
);
457 r
= link_set_mtu(link
, mtu
);
459 log_link_error_errno(link
, r
, "Failed to set MTU to %" PRIu16
": %m", mtu
);
463 if (link
->network
->dhcp_use_hostname
) {
464 const char *hostname
= NULL
;
466 if (link
->network
->dhcp_hostname
)
467 hostname
= link
->network
->dhcp_hostname
;
469 (void) sd_dhcp_lease_get_hostname(lease
, &hostname
);
472 r
= manager_set_hostname(link
->manager
, hostname
);
474 log_link_error_errno(link
, r
, "Failed to set transient hostname to '%s': %m", hostname
);
478 if (link
->network
->dhcp_use_timezone
) {
479 const char *tz
= NULL
;
481 (void) sd_dhcp_lease_get_timezone(link
->dhcp_lease
, &tz
);
484 r
= manager_set_timezone(link
->manager
, tz
);
486 log_link_error_errno(link
, r
, "Failed to set timezone to '%s': %m", tz
);
490 if (!link
->network
->dhcp_critical
) {
491 r
= sd_dhcp_lease_get_lifetime(link
->dhcp_lease
, &lifetime
);
493 log_link_warning_errno(link
, r
, "DHCP error: no lifetime: %m");
498 r
= dhcp4_update_address(link
, &address
, &netmask
, lifetime
);
500 log_link_warning_errno(link
, r
, "Could not update IP address: %m");
501 link_enter_failed(link
);
507 static void dhcp4_handler(sd_dhcp_client
*client
, int event
, void *userdata
) {
508 Link
*link
= userdata
;
512 assert(link
->network
);
513 assert(link
->manager
);
515 if (IN_SET(link
->state
, LINK_STATE_FAILED
, LINK_STATE_LINGER
))
519 case SD_DHCP_CLIENT_EVENT_EXPIRED
:
520 case SD_DHCP_CLIENT_EVENT_STOP
:
521 case SD_DHCP_CLIENT_EVENT_IP_CHANGE
:
522 if (link
->network
->dhcp_critical
) {
523 log_link_error(link
, "DHCPv4 connection considered system critical, ignoring request to reconfigure it.");
527 if (link
->dhcp_lease
) {
528 r
= dhcp_lease_lost(link
);
530 link_enter_failed(link
);
535 if (event
== SD_DHCP_CLIENT_EVENT_IP_CHANGE
) {
536 r
= dhcp_lease_acquired(client
, link
);
538 link_enter_failed(link
);
544 case SD_DHCP_CLIENT_EVENT_RENEW
:
545 r
= dhcp_lease_renew(client
, link
);
547 link_enter_failed(link
);
551 case SD_DHCP_CLIENT_EVENT_IP_ACQUIRE
:
552 r
= dhcp_lease_acquired(client
, link
);
554 link_enter_failed(link
);
560 log_link_warning_errno(link
, event
, "DHCP error: Client failed: %m");
562 log_link_warning(link
, "DHCP unknown event: %i", event
);
569 static int dhcp4_set_hostname(Link
*link
) {
570 _cleanup_free_
char *hostname
= NULL
;
576 if (!link
->network
->dhcp_send_hostname
)
578 else if (link
->network
->dhcp_hostname
)
579 hn
= link
->network
->dhcp_hostname
;
581 r
= gethostname_strict(&hostname
);
582 if (r
< 0 && r
!= -ENXIO
) /* ENXIO: no hostname set or hostname is "localhost" */
588 return sd_dhcp_client_set_hostname(link
->dhcp_client
, hn
);
591 int dhcp4_configure(Link
*link
) {
595 assert(link
->network
);
596 assert(link
->network
->dhcp
& ADDRESS_FAMILY_IPV4
);
598 if (!link
->dhcp_client
) {
599 r
= sd_dhcp_client_new(&link
->dhcp_client
, link
->network
->dhcp_anonymize
);
604 r
= sd_dhcp_client_attach_event(link
->dhcp_client
, NULL
, 0);
608 r
= sd_dhcp_client_set_mac(link
->dhcp_client
,
609 (const uint8_t *) &link
->mac
,
610 sizeof (link
->mac
), ARPHRD_ETHER
);
614 r
= sd_dhcp_client_set_ifindex(link
->dhcp_client
, link
->ifindex
);
618 r
= sd_dhcp_client_set_callback(link
->dhcp_client
, dhcp4_handler
, link
);
622 r
= sd_dhcp_client_set_request_broadcast(link
->dhcp_client
,
623 link
->network
->dhcp_broadcast
);
628 r
= sd_dhcp_client_set_mtu(link
->dhcp_client
, link
->mtu
);
633 if (link
->network
->dhcp_use_mtu
) {
634 r
= sd_dhcp_client_set_request_option(link
->dhcp_client
,
635 SD_DHCP_OPTION_INTERFACE_MTU
);
640 /* NOTE: even if this variable is called "use", it also "sends" PRL
641 * options, maybe there should be a different configuration variable
642 * to send or not route options?. */
643 /* NOTE: when using Anonymize=yes, routes PRL options are sent
644 * by default, so they don't need to be added here. */
645 if (link
->network
->dhcp_use_routes
&& !link
->network
->dhcp_anonymize
) {
646 r
= sd_dhcp_client_set_request_option(link
->dhcp_client
,
647 SD_DHCP_OPTION_STATIC_ROUTE
);
650 r
= sd_dhcp_client_set_request_option(link
->dhcp_client
,
651 SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE
);
656 if (link
->network
->dhcp_use_ntp
) {
657 r
= sd_dhcp_client_set_request_option(link
->dhcp_client
, SD_DHCP_OPTION_NTP_SERVER
);
662 if (link
->network
->dhcp_use_timezone
) {
663 r
= sd_dhcp_client_set_request_option(link
->dhcp_client
, SD_DHCP_OPTION_NEW_TZDB_TIMEZONE
);
668 r
= dhcp4_set_hostname(link
);
672 if (link
->network
->dhcp_vendor_class_identifier
) {
673 r
= sd_dhcp_client_set_vendor_class_identifier(link
->dhcp_client
,
674 link
->network
->dhcp_vendor_class_identifier
);
679 if (link
->network
->dhcp_client_port
) {
680 r
= sd_dhcp_client_set_client_port(link
->dhcp_client
, link
->network
->dhcp_client_port
);
685 switch (link
->network
->dhcp_client_identifier
) {
686 case DHCP_CLIENT_ID_DUID
: {
687 /* If configured, apply user specified DUID and/or IAID */
688 const DUID
*duid
= link_duid(link
);
690 r
= sd_dhcp_client_set_iaid_duid(link
->dhcp_client
,
693 duid
->raw_data_len
> 0 ? duid
->raw_data
: NULL
,
699 case DHCP_CLIENT_ID_MAC
:
700 r
= sd_dhcp_client_set_client_id(link
->dhcp_client
,
702 (const uint8_t *) &link
->mac
,
708 assert_not_reached("Unknown client identifier type.");