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 "parse-util.h"
28 #include "netdev/vrf.h"
29 #include "network-internal.h"
30 #include "networkd-link.h"
31 #include "networkd-manager.h"
32 #include "networkd-network.h"
33 #include "string-util.h"
34 #include "sysctl-util.h"
36 static int dhcp4_route_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
,
38 _cleanup_link_unref_ Link
*link
= userdata
;
42 assert(link
->dhcp4_messages
> 0);
44 link
->dhcp4_messages
--;
46 r
= sd_netlink_message_get_errno(m
);
47 if (r
< 0 && r
!= -EEXIST
) {
48 log_link_error_errno(link
, r
, "Could not set DHCPv4 route: %m");
49 link_enter_failed(link
);
52 if (link
->dhcp4_messages
== 0) {
53 link
->dhcp4_configured
= true;
54 link_check_ready(link
);
60 static int route_scope_from_address(const Route
*route
, const struct in_addr
*self_addr
) {
64 if (in_addr_is_localhost(AF_INET
, &route
->dst
) ||
65 (self_addr
->s_addr
&& route
->dst
.in
.s_addr
== self_addr
->s_addr
))
67 else if (in4_addr_is_null(&route
->gw
.in
))
70 return RT_SCOPE_UNIVERSE
;
73 static int link_set_dhcp_routes(Link
*link
) {
74 struct in_addr gateway
, address
;
75 _cleanup_free_ sd_dhcp_route
**static_routes
= NULL
;
81 if (!link
->dhcp_lease
) /* link went down while we configured the IP addresses? */
84 if (!link
->network
) /* link went down while we configured the IP addresses? */
87 if (!link
->network
->dhcp_use_routes
)
90 /* When the interface is part of an VRF use the VRFs routing table, unless
91 * there is a another table specified. */
92 table
= link
->network
->dhcp_route_table
;
93 if (!link
->network
->dhcp_route_table_set
&& link
->network
->vrf
!= NULL
)
94 table
= VRF(link
->network
->vrf
)->table
;
96 r
= sd_dhcp_lease_get_address(link
->dhcp_lease
, &address
);
98 return log_link_warning_errno(link
, r
, "DHCP error: could not get address: %m");
100 n
= sd_dhcp_lease_get_routes(link
->dhcp_lease
, &static_routes
);
102 log_link_debug_errno(link
, n
, "DHCP error: could not get routes: %m");
104 for (i
= 0; i
< n
; i
++) {
105 _cleanup_route_free_ Route
*route
= NULL
;
107 r
= route_new(&route
);
109 return log_link_error_errno(link
, r
, "Could not allocate route: %m");
111 route
->family
= AF_INET
;
112 route
->protocol
= RTPROT_DHCP
;
113 assert_se(sd_dhcp_route_get_gateway(static_routes
[i
], &route
->gw
.in
) >= 0);
114 assert_se(sd_dhcp_route_get_destination(static_routes
[i
], &route
->dst
.in
) >= 0);
115 assert_se(sd_dhcp_route_get_destination_prefix_length(static_routes
[i
], &route
->dst_prefixlen
) >= 0);
116 route
->priority
= link
->network
->dhcp_route_metric
;
117 route
->table
= table
;
118 route
->scope
= route_scope_from_address(route
, &address
);
120 r
= route_configure(route
, link
, dhcp4_route_handler
);
122 return log_link_warning_errno(link
, r
, "Could not set host route: %m");
124 link
->dhcp4_messages
++;
127 r
= sd_dhcp_lease_get_router(link
->dhcp_lease
, &gateway
);
129 log_link_info_errno(link
, r
, "DHCP: No routes received from DHCP server: %m");
131 log_link_warning_errno(link
, r
, "DHCP error: could not get gateway: %m");
133 /* According to RFC 3442: If the DHCP server returns both a Classless Static Routes option and
134 a Router option, the DHCP client MUST ignore the Router option. */
135 if (r
>= 0 && link
->dhcp4_messages
<= 0) {
136 _cleanup_route_free_ Route
*route
= NULL
;
137 _cleanup_route_free_ Route
*route_gw
= NULL
;
139 r
= route_new(&route
);
141 return log_link_error_errno(link
, r
, "Could not allocate route: %m");
143 route
->protocol
= RTPROT_DHCP
;
145 r
= route_new(&route_gw
);
147 return log_link_error_errno(link
, r
, "Could not allocate route: %m");
149 /* The dhcp netmask may mask out the gateway. Add an explicit
150 * route for the gw host so that we can route no matter the
151 * netmask or existing kernel route tables. */
152 route_gw
->family
= AF_INET
;
153 route_gw
->dst
.in
= gateway
;
154 route_gw
->dst_prefixlen
= 32;
155 route_gw
->prefsrc
.in
= address
;
156 route_gw
->scope
= RT_SCOPE_LINK
;
157 route_gw
->protocol
= RTPROT_DHCP
;
158 route_gw
->priority
= link
->network
->dhcp_route_metric
;
159 route_gw
->table
= table
;
161 r
= route_configure(route_gw
, link
, dhcp4_route_handler
);
163 return log_link_warning_errno(link
, r
, "Could not set host route: %m");
165 link
->dhcp4_messages
++;
167 route
->family
= AF_INET
;
168 route
->gw
.in
= gateway
;
169 route
->prefsrc
.in
= address
;
170 route
->priority
= link
->network
->dhcp_route_metric
;
171 route
->table
= table
;
173 r
= route_configure(route
, link
, dhcp4_route_handler
);
175 log_link_warning_errno(link
, r
, "Could not set routes: %m");
176 link_enter_failed(link
);
180 link
->dhcp4_messages
++;
186 static int dhcp_lease_lost(Link
*link
) {
187 _cleanup_address_free_ Address
*address
= NULL
;
189 struct in_addr netmask
;
190 struct in_addr gateway
;
191 unsigned prefixlen
= 0;
195 assert(link
->dhcp_lease
);
197 log_link_warning(link
, "DHCP lease lost");
199 if (link
->network
->dhcp_use_routes
) {
200 _cleanup_free_ sd_dhcp_route
**routes
= NULL
;
203 n
= sd_dhcp_lease_get_routes(link
->dhcp_lease
, &routes
);
205 for (i
= 0; i
< n
; i
++) {
206 _cleanup_route_free_ Route
*route
= NULL
;
208 r
= route_new(&route
);
210 route
->family
= AF_INET
;
211 assert_se(sd_dhcp_route_get_gateway(routes
[i
], &route
->gw
.in
) >= 0);
212 assert_se(sd_dhcp_route_get_destination(routes
[i
], &route
->dst
.in
) >= 0);
213 assert_se(sd_dhcp_route_get_destination_prefix_length(routes
[i
], &route
->dst_prefixlen
) >= 0);
215 route_remove(route
, link
,
216 link_route_remove_handler
);
222 r
= address_new(&address
);
224 r
= sd_dhcp_lease_get_router(link
->dhcp_lease
, &gateway
);
226 _cleanup_route_free_ Route
*route_gw
= NULL
;
227 _cleanup_route_free_ Route
*route
= NULL
;
229 r
= route_new(&route_gw
);
231 route_gw
->family
= AF_INET
;
232 route_gw
->dst
.in
= gateway
;
233 route_gw
->dst_prefixlen
= 32;
234 route_gw
->scope
= RT_SCOPE_LINK
;
236 route_remove(route_gw
, link
,
237 link_route_remove_handler
);
240 r
= route_new(&route
);
242 route
->family
= AF_INET
;
243 route
->gw
.in
= gateway
;
245 route_remove(route
, link
,
246 link_route_remove_handler
);
250 r
= sd_dhcp_lease_get_address(link
->dhcp_lease
, &addr
);
252 r
= sd_dhcp_lease_get_netmask(link
->dhcp_lease
, &netmask
);
254 prefixlen
= in4_addr_netmask_to_prefixlen(&netmask
);
256 address
->family
= AF_INET
;
257 address
->in_addr
.in
= addr
;
258 address
->prefixlen
= prefixlen
;
260 address_remove(address
, link
, link_address_remove_handler
);
264 if (link
->network
->dhcp_use_mtu
) {
267 r
= sd_dhcp_lease_get_mtu(link
->dhcp_lease
, &mtu
);
268 if (r
>= 0 && link
->original_mtu
!= mtu
) {
269 r
= link_set_mtu(link
, link
->original_mtu
);
271 log_link_warning(link
,
272 "DHCP error: could not reset MTU");
273 link_enter_failed(link
);
279 if (link
->network
->dhcp_use_hostname
) {
280 const char *hostname
= NULL
;
282 if (link
->network
->dhcp_hostname
)
283 hostname
= link
->network
->dhcp_hostname
;
285 (void) sd_dhcp_lease_get_hostname(link
->dhcp_lease
, &hostname
);
288 /* If a hostname was set due to the lease, then unset it now. */
289 r
= manager_set_hostname(link
->manager
, NULL
);
291 log_link_warning_errno(link
, r
, "Failed to reset transient hostname: %m");
295 link
->dhcp_lease
= sd_dhcp_lease_unref(link
->dhcp_lease
);
297 link
->dhcp4_configured
= false;
302 static int dhcp4_address_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
,
304 _cleanup_link_unref_ Link
*link
= userdata
;
309 r
= sd_netlink_message_get_errno(m
);
310 if (r
< 0 && r
!= -EEXIST
) {
311 log_link_error_errno(link
, r
, "Could not set DHCPv4 address: %m");
312 link_enter_failed(link
);
314 manager_rtnl_process_address(rtnl
, m
, link
->manager
);
316 link_set_dhcp_routes(link
);
321 static int dhcp4_update_address(Link
*link
,
322 struct in_addr
*address
,
323 struct in_addr
*netmask
,
325 _cleanup_address_free_ Address
*addr
= NULL
;
333 prefixlen
= in4_addr_netmask_to_prefixlen(netmask
);
335 r
= address_new(&addr
);
339 addr
->family
= AF_INET
;
340 addr
->in_addr
.in
.s_addr
= address
->s_addr
;
341 addr
->cinfo
.ifa_prefered
= lifetime
;
342 addr
->cinfo
.ifa_valid
= lifetime
;
343 addr
->prefixlen
= prefixlen
;
344 addr
->broadcast
.s_addr
= address
->s_addr
| ~netmask
->s_addr
;
346 /* allow reusing an existing address and simply update its lifetime
347 * in case it already exists */
348 r
= address_configure(addr
, link
, dhcp4_address_handler
, true);
355 static int dhcp_lease_renew(sd_dhcp_client
*client
, Link
*link
) {
356 sd_dhcp_lease
*lease
;
357 struct in_addr address
;
358 struct in_addr netmask
;
359 uint32_t lifetime
= CACHE_INFO_INFINITY_LIFE_TIME
;
364 assert(link
->network
);
366 r
= sd_dhcp_client_get_lease(client
, &lease
);
368 return log_link_warning_errno(link
, r
, "DHCP error: no lease: %m");
370 sd_dhcp_lease_unref(link
->dhcp_lease
);
371 link
->dhcp4_configured
= false;
372 link
->dhcp_lease
= sd_dhcp_lease_ref(lease
);
375 r
= sd_dhcp_lease_get_address(lease
, &address
);
377 return log_link_warning_errno(link
, r
, "DHCP error: no address: %m");
379 r
= sd_dhcp_lease_get_netmask(lease
, &netmask
);
381 return log_link_warning_errno(link
, r
, "DHCP error: no netmask: %m");
383 if (!link
->network
->dhcp_critical
) {
384 r
= sd_dhcp_lease_get_lifetime(link
->dhcp_lease
, &lifetime
);
386 return log_link_warning_errno(link
, r
, "DHCP error: no lifetime: %m");
389 r
= dhcp4_update_address(link
, &address
, &netmask
, lifetime
);
391 log_link_warning_errno(link
, r
, "Could not update IP address: %m");
392 link_enter_failed(link
);
399 static int dhcp_lease_acquired(sd_dhcp_client
*client
, Link
*link
) {
400 sd_dhcp_lease
*lease
;
401 struct in_addr address
;
402 struct in_addr netmask
;
403 struct in_addr gateway
;
405 uint32_t lifetime
= CACHE_INFO_INFINITY_LIFE_TIME
;
411 r
= sd_dhcp_client_get_lease(client
, &lease
);
413 return log_link_error_errno(link
, r
, "DHCP error: No lease: %m");
415 r
= sd_dhcp_lease_get_address(lease
, &address
);
417 return log_link_error_errno(link
, r
, "DHCP error: No address: %m");
419 r
= sd_dhcp_lease_get_netmask(lease
, &netmask
);
421 return log_link_error_errno(link
, r
, "DHCP error: No netmask: %m");
423 prefixlen
= in4_addr_netmask_to_prefixlen(&netmask
);
425 r
= sd_dhcp_lease_get_router(lease
, &gateway
);
426 if (r
< 0 && r
!= -ENODATA
)
427 return log_link_error_errno(link
, r
, "DHCP error: Could not get gateway: %m");
431 LOG_LINK_INTERFACE(link
),
432 LOG_LINK_MESSAGE(link
, "DHCPv4 address %u.%u.%u.%u/%u via %u.%u.%u.%u",
433 ADDRESS_FMT_VAL(address
),
435 ADDRESS_FMT_VAL(gateway
)),
436 "ADDRESS=%u.%u.%u.%u", ADDRESS_FMT_VAL(address
),
437 "PREFIXLEN=%u", prefixlen
,
438 "GATEWAY=%u.%u.%u.%u", ADDRESS_FMT_VAL(gateway
),
442 LOG_LINK_INTERFACE(link
),
443 LOG_LINK_MESSAGE(link
, "DHCPv4 address %u.%u.%u.%u/%u",
444 ADDRESS_FMT_VAL(address
),
446 "ADDRESS=%u.%u.%u.%u", ADDRESS_FMT_VAL(address
),
447 "PREFIXLEN=%u", prefixlen
,
450 link
->dhcp_lease
= sd_dhcp_lease_ref(lease
);
453 if (link
->network
->dhcp_use_mtu
) {
456 r
= sd_dhcp_lease_get_mtu(lease
, &mtu
);
458 r
= link_set_mtu(link
, mtu
);
460 log_link_error_errno(link
, r
, "Failed to set MTU to %" PRIu16
": %m", mtu
);
464 if (link
->network
->dhcp_use_hostname
) {
465 const char *hostname
= NULL
;
467 if (link
->network
->dhcp_hostname
)
468 hostname
= link
->network
->dhcp_hostname
;
470 (void) sd_dhcp_lease_get_hostname(lease
, &hostname
);
473 r
= manager_set_hostname(link
->manager
, hostname
);
475 log_link_error_errno(link
, r
, "Failed to set transient hostname to '%s': %m", hostname
);
479 if (link
->network
->dhcp_use_timezone
) {
480 const char *tz
= NULL
;
482 (void) sd_dhcp_lease_get_timezone(link
->dhcp_lease
, &tz
);
485 r
= manager_set_timezone(link
->manager
, tz
);
487 log_link_error_errno(link
, r
, "Failed to set timezone to '%s': %m", tz
);
491 if (!link
->network
->dhcp_critical
) {
492 r
= sd_dhcp_lease_get_lifetime(link
->dhcp_lease
, &lifetime
);
494 log_link_warning_errno(link
, r
, "DHCP error: no lifetime: %m");
499 r
= dhcp4_update_address(link
, &address
, &netmask
, lifetime
);
501 log_link_warning_errno(link
, r
, "Could not update IP address: %m");
502 link_enter_failed(link
);
508 static void dhcp4_handler(sd_dhcp_client
*client
, int event
, void *userdata
) {
509 Link
*link
= userdata
;
513 assert(link
->network
);
514 assert(link
->manager
);
516 if (IN_SET(link
->state
, LINK_STATE_FAILED
, LINK_STATE_LINGER
))
520 case SD_DHCP_CLIENT_EVENT_EXPIRED
:
521 case SD_DHCP_CLIENT_EVENT_STOP
:
522 case SD_DHCP_CLIENT_EVENT_IP_CHANGE
:
523 if (link
->network
->dhcp_critical
) {
524 log_link_error(link
, "DHCPv4 connection considered system critical, ignoring request to reconfigure it.");
528 if (link
->dhcp_lease
) {
529 r
= dhcp_lease_lost(link
);
531 link_enter_failed(link
);
536 if (event
== SD_DHCP_CLIENT_EVENT_IP_CHANGE
) {
537 r
= dhcp_lease_acquired(client
, link
);
539 link_enter_failed(link
);
545 case SD_DHCP_CLIENT_EVENT_RENEW
:
546 r
= dhcp_lease_renew(client
, link
);
548 link_enter_failed(link
);
552 case SD_DHCP_CLIENT_EVENT_IP_ACQUIRE
:
553 r
= dhcp_lease_acquired(client
, link
);
555 link_enter_failed(link
);
561 log_link_warning_errno(link
, event
, "DHCP error: Client failed: %m");
563 log_link_warning(link
, "DHCP unknown event: %i", event
);
570 static int dhcp4_set_hostname(Link
*link
) {
571 _cleanup_free_
char *hostname
= NULL
;
577 if (!link
->network
->dhcp_send_hostname
)
579 else if (link
->network
->dhcp_hostname
)
580 hn
= link
->network
->dhcp_hostname
;
582 r
= gethostname_strict(&hostname
);
583 if (r
< 0 && r
!= -ENXIO
) /* ENXIO: no hostname set or hostname is "localhost" */
589 return sd_dhcp_client_set_hostname(link
->dhcp_client
, hn
);
592 static bool promote_secondaries_enabled(const char *ifname
) {
593 _cleanup_free_
char *promote_secondaries_sysctl
= NULL
;
594 char *promote_secondaries_path
;
597 promote_secondaries_path
= strjoina("net/ipv4/conf/", ifname
, "/promote_secondaries");
598 r
= sysctl_read(promote_secondaries_path
, &promote_secondaries_sysctl
);
600 log_debug_errno(r
, "Cannot read sysctl %s", promote_secondaries_path
);
604 truncate_nl(promote_secondaries_sysctl
);
605 r
= parse_boolean(promote_secondaries_sysctl
);
607 log_warning_errno(r
, "Cannot parse sysctl %s with content %s as boolean", promote_secondaries_path
, promote_secondaries_sysctl
);
611 /* dhcp4_set_promote_secondaries will ensure this interface has
612 * the "promote_secondaries" option in the kernel set. If this sysctl
613 * is not set DHCP will work only as long as the IP address does not
614 * changes between leases. The kernel will remove all secondary IP
615 * addresses of an interface otherwise. The way systemd-network works
616 * is that the new IP of a lease is added as a secondary IP and when
617 * the primary one expires it relies on the kernel to promote the
618 * secondary IP. See also https://github.com/systemd/systemd/issues/7163
620 int dhcp4_set_promote_secondaries(Link
*link
) {
624 assert(link
->network
);
625 assert(link
->network
->dhcp
& ADDRESS_FAMILY_IPV4
);
627 /* check if the kernel has promote_secondaries enabled for our
628 * interface. If it is not globally enabled or enabled for the
629 * specific interface we must either enable it.
631 if (!(promote_secondaries_enabled("all") || promote_secondaries_enabled(link
->ifname
))) {
632 char *promote_secondaries_path
= NULL
;
634 log_link_debug(link
, "promote_secondaries is unset, setting it");
635 promote_secondaries_path
= strjoina("net/ipv4/conf/", link
->ifname
, "/promote_secondaries");
636 r
= sysctl_write(promote_secondaries_path
, "1");
638 log_link_warning_errno(link
, r
, "cannot set sysctl %s to 1", promote_secondaries_path
);
645 int dhcp4_configure(Link
*link
) {
649 assert(link
->network
);
650 assert(link
->network
->dhcp
& ADDRESS_FAMILY_IPV4
);
652 if (!link
->dhcp_client
) {
653 r
= sd_dhcp_client_new(&link
->dhcp_client
, link
->network
->dhcp_anonymize
);
658 r
= sd_dhcp_client_attach_event(link
->dhcp_client
, NULL
, 0);
662 r
= sd_dhcp_client_set_mac(link
->dhcp_client
,
663 (const uint8_t *) &link
->mac
,
664 sizeof (link
->mac
), ARPHRD_ETHER
);
668 r
= sd_dhcp_client_set_ifindex(link
->dhcp_client
, link
->ifindex
);
672 r
= sd_dhcp_client_set_callback(link
->dhcp_client
, dhcp4_handler
, link
);
676 r
= sd_dhcp_client_set_request_broadcast(link
->dhcp_client
,
677 link
->network
->dhcp_broadcast
);
682 r
= sd_dhcp_client_set_mtu(link
->dhcp_client
, link
->mtu
);
687 if (link
->network
->dhcp_use_mtu
) {
688 r
= sd_dhcp_client_set_request_option(link
->dhcp_client
,
689 SD_DHCP_OPTION_INTERFACE_MTU
);
694 /* NOTE: even if this variable is called "use", it also "sends" PRL
695 * options, maybe there should be a different configuration variable
696 * to send or not route options?. */
697 /* NOTE: when using Anonymize=yes, routes PRL options are sent
698 * by default, so they don't need to be added here. */
699 if (link
->network
->dhcp_use_routes
&& !link
->network
->dhcp_anonymize
) {
700 r
= sd_dhcp_client_set_request_option(link
->dhcp_client
,
701 SD_DHCP_OPTION_STATIC_ROUTE
);
704 r
= sd_dhcp_client_set_request_option(link
->dhcp_client
,
705 SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE
);
710 if (link
->network
->dhcp_use_ntp
) {
711 r
= sd_dhcp_client_set_request_option(link
->dhcp_client
, SD_DHCP_OPTION_NTP_SERVER
);
716 if (link
->network
->dhcp_use_timezone
) {
717 r
= sd_dhcp_client_set_request_option(link
->dhcp_client
, SD_DHCP_OPTION_NEW_TZDB_TIMEZONE
);
722 r
= dhcp4_set_hostname(link
);
726 if (link
->network
->dhcp_vendor_class_identifier
) {
727 r
= sd_dhcp_client_set_vendor_class_identifier(link
->dhcp_client
,
728 link
->network
->dhcp_vendor_class_identifier
);
733 if (link
->network
->dhcp_client_port
) {
734 r
= sd_dhcp_client_set_client_port(link
->dhcp_client
, link
->network
->dhcp_client_port
);
739 switch (link
->network
->dhcp_client_identifier
) {
740 case DHCP_CLIENT_ID_DUID
: {
741 /* If configured, apply user specified DUID and/or IAID */
742 const DUID
*duid
= link_duid(link
);
744 r
= sd_dhcp_client_set_iaid_duid(link
->dhcp_client
,
747 duid
->raw_data_len
> 0 ? duid
->raw_data
: NULL
,
753 case DHCP_CLIENT_ID_MAC
:
754 r
= sd_dhcp_client_set_client_id(link
->dhcp_client
,
756 (const uint8_t *) &link
->mac
,
762 assert_not_reached("Unknown client identifier type.");