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 r
= sd_dhcp_lease_get_router(link
->dhcp_lease
, &gateway
);
98 if (r
< 0 && r
!= -ENODATA
)
99 return log_link_warning_errno(link
, r
, "DHCP error: could not get gateway: %m");
102 _cleanup_route_free_ Route
*route
= NULL
;
103 _cleanup_route_free_ Route
*route_gw
= NULL
;
105 r
= route_new(&route
);
107 return log_link_error_errno(link
, r
, "Could not allocate route: %m");
109 route
->protocol
= RTPROT_DHCP
;
111 r
= route_new(&route_gw
);
113 return log_link_error_errno(link
, r
, "Could not allocate route: %m");
115 /* The dhcp netmask may mask out the gateway. Add an explicit
116 * route for the gw host so that we can route no matter the
117 * netmask or existing kernel route tables. */
118 route_gw
->family
= AF_INET
;
119 route_gw
->dst
.in
= gateway
;
120 route_gw
->dst_prefixlen
= 32;
121 route_gw
->prefsrc
.in
= address
;
122 route_gw
->scope
= RT_SCOPE_LINK
;
123 route_gw
->protocol
= RTPROT_DHCP
;
124 route_gw
->priority
= link
->network
->dhcp_route_metric
;
125 route_gw
->table
= table
;
127 r
= route_configure(route_gw
, link
, dhcp4_route_handler
);
129 return log_link_warning_errno(link
, r
, "Could not set host route: %m");
131 link
->dhcp4_messages
++;
133 route
->family
= AF_INET
;
134 route
->gw
.in
= gateway
;
135 route
->prefsrc
.in
= address
;
136 route
->priority
= link
->network
->dhcp_route_metric
;
137 route
->table
= table
;
139 r
= route_configure(route
, link
, dhcp4_route_handler
);
141 log_link_warning_errno(link
, r
, "Could not set routes: %m");
142 link_enter_failed(link
);
146 link
->dhcp4_messages
++;
149 n
= sd_dhcp_lease_get_routes(link
->dhcp_lease
, &static_routes
);
153 return log_link_warning_errno(link
, n
, "DHCP error: could not get routes: %m");
155 for (i
= 0; i
< n
; i
++) {
156 _cleanup_route_free_ Route
*route
= NULL
;
158 r
= route_new(&route
);
160 return log_link_error_errno(link
, r
, "Could not allocate route: %m");
162 route
->family
= AF_INET
;
163 route
->protocol
= RTPROT_DHCP
;
164 assert_se(sd_dhcp_route_get_gateway(static_routes
[i
], &route
->gw
.in
) >= 0);
165 assert_se(sd_dhcp_route_get_destination(static_routes
[i
], &route
->dst
.in
) >= 0);
166 assert_se(sd_dhcp_route_get_destination_prefix_length(static_routes
[i
], &route
->dst_prefixlen
) >= 0);
167 route
->priority
= link
->network
->dhcp_route_metric
;
168 route
->table
= table
;
169 route
->scope
= route_scope_from_address(route
, &address
);
171 r
= route_configure(route
, link
, dhcp4_route_handler
);
173 return log_link_warning_errno(link
, r
, "Could not set host route: %m");
175 link
->dhcp4_messages
++;
181 static int dhcp_lease_lost(Link
*link
) {
182 _cleanup_address_free_ Address
*address
= NULL
;
184 struct in_addr netmask
;
185 struct in_addr gateway
;
186 unsigned prefixlen
= 0;
190 assert(link
->dhcp_lease
);
192 log_link_warning(link
, "DHCP lease lost");
194 if (link
->network
->dhcp_use_routes
) {
195 _cleanup_free_ sd_dhcp_route
**routes
= NULL
;
198 n
= sd_dhcp_lease_get_routes(link
->dhcp_lease
, &routes
);
200 for (i
= 0; i
< n
; i
++) {
201 _cleanup_route_free_ Route
*route
= NULL
;
203 r
= route_new(&route
);
205 route
->family
= AF_INET
;
206 assert_se(sd_dhcp_route_get_gateway(routes
[i
], &route
->gw
.in
) >= 0);
207 assert_se(sd_dhcp_route_get_destination(routes
[i
], &route
->dst
.in
) >= 0);
208 assert_se(sd_dhcp_route_get_destination_prefix_length(routes
[i
], &route
->dst_prefixlen
) >= 0);
210 route_remove(route
, link
,
211 link_route_remove_handler
);
217 r
= address_new(&address
);
219 r
= sd_dhcp_lease_get_router(link
->dhcp_lease
, &gateway
);
221 _cleanup_route_free_ Route
*route_gw
= NULL
;
222 _cleanup_route_free_ Route
*route
= NULL
;
224 r
= route_new(&route_gw
);
226 route_gw
->family
= AF_INET
;
227 route_gw
->dst
.in
= gateway
;
228 route_gw
->dst_prefixlen
= 32;
229 route_gw
->scope
= RT_SCOPE_LINK
;
231 route_remove(route_gw
, link
,
232 link_route_remove_handler
);
235 r
= route_new(&route
);
237 route
->family
= AF_INET
;
238 route
->gw
.in
= gateway
;
240 route_remove(route
, link
,
241 link_route_remove_handler
);
245 r
= sd_dhcp_lease_get_address(link
->dhcp_lease
, &addr
);
247 r
= sd_dhcp_lease_get_netmask(link
->dhcp_lease
, &netmask
);
249 prefixlen
= in4_addr_netmask_to_prefixlen(&netmask
);
251 address
->family
= AF_INET
;
252 address
->in_addr
.in
= addr
;
253 address
->prefixlen
= prefixlen
;
255 address_remove(address
, link
, link_address_remove_handler
);
259 if (link
->network
->dhcp_use_mtu
) {
262 r
= sd_dhcp_lease_get_mtu(link
->dhcp_lease
, &mtu
);
263 if (r
>= 0 && link
->original_mtu
!= mtu
) {
264 r
= link_set_mtu(link
, link
->original_mtu
);
266 log_link_warning(link
,
267 "DHCP error: could not reset MTU");
268 link_enter_failed(link
);
274 if (link
->network
->dhcp_use_hostname
) {
275 const char *hostname
= NULL
;
277 if (link
->network
->dhcp_hostname
)
278 hostname
= link
->network
->dhcp_hostname
;
280 (void) sd_dhcp_lease_get_hostname(link
->dhcp_lease
, &hostname
);
283 /* If a hostname was set due to the lease, then unset it now. */
284 r
= manager_set_hostname(link
->manager
, NULL
);
286 log_link_warning_errno(link
, r
, "Failed to reset transient hostname: %m");
290 link
->dhcp_lease
= sd_dhcp_lease_unref(link
->dhcp_lease
);
292 link
->dhcp4_configured
= false;
297 static int dhcp4_address_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
,
299 _cleanup_link_unref_ Link
*link
= userdata
;
304 r
= sd_netlink_message_get_errno(m
);
305 if (r
< 0 && r
!= -EEXIST
) {
306 log_link_error_errno(link
, r
, "Could not set DHCPv4 address: %m");
307 link_enter_failed(link
);
309 manager_rtnl_process_address(rtnl
, m
, link
->manager
);
311 link_set_dhcp_routes(link
);
316 static int dhcp4_update_address(Link
*link
,
317 struct in_addr
*address
,
318 struct in_addr
*netmask
,
320 _cleanup_address_free_ Address
*addr
= NULL
;
328 prefixlen
= in4_addr_netmask_to_prefixlen(netmask
);
330 r
= address_new(&addr
);
334 addr
->family
= AF_INET
;
335 addr
->in_addr
.in
.s_addr
= address
->s_addr
;
336 addr
->cinfo
.ifa_prefered
= lifetime
;
337 addr
->cinfo
.ifa_valid
= lifetime
;
338 addr
->prefixlen
= prefixlen
;
339 addr
->broadcast
.s_addr
= address
->s_addr
| ~netmask
->s_addr
;
341 /* allow reusing an existing address and simply update its lifetime
342 * in case it already exists */
343 r
= address_configure(addr
, link
, dhcp4_address_handler
, true);
350 static int dhcp_lease_renew(sd_dhcp_client
*client
, Link
*link
) {
351 sd_dhcp_lease
*lease
;
352 struct in_addr address
;
353 struct in_addr netmask
;
354 uint32_t lifetime
= CACHE_INFO_INFINITY_LIFE_TIME
;
359 assert(link
->network
);
361 r
= sd_dhcp_client_get_lease(client
, &lease
);
363 return log_link_warning_errno(link
, r
, "DHCP error: no lease: %m");
365 sd_dhcp_lease_unref(link
->dhcp_lease
);
366 link
->dhcp4_configured
= false;
367 link
->dhcp_lease
= sd_dhcp_lease_ref(lease
);
370 r
= sd_dhcp_lease_get_address(lease
, &address
);
372 return log_link_warning_errno(link
, r
, "DHCP error: no address: %m");
374 r
= sd_dhcp_lease_get_netmask(lease
, &netmask
);
376 return log_link_warning_errno(link
, r
, "DHCP error: no netmask: %m");
378 if (!link
->network
->dhcp_critical
) {
379 r
= sd_dhcp_lease_get_lifetime(link
->dhcp_lease
, &lifetime
);
381 return log_link_warning_errno(link
, r
, "DHCP error: no lifetime: %m");
384 r
= dhcp4_update_address(link
, &address
, &netmask
, lifetime
);
386 log_link_warning_errno(link
, r
, "Could not update IP address: %m");
387 link_enter_failed(link
);
394 static int dhcp_lease_acquired(sd_dhcp_client
*client
, Link
*link
) {
395 sd_dhcp_lease
*lease
;
396 struct in_addr address
;
397 struct in_addr netmask
;
398 struct in_addr gateway
;
400 uint32_t lifetime
= CACHE_INFO_INFINITY_LIFE_TIME
;
406 r
= sd_dhcp_client_get_lease(client
, &lease
);
408 return log_link_error_errno(link
, r
, "DHCP error: No lease: %m");
410 r
= sd_dhcp_lease_get_address(lease
, &address
);
412 return log_link_error_errno(link
, r
, "DHCP error: No address: %m");
414 r
= sd_dhcp_lease_get_netmask(lease
, &netmask
);
416 return log_link_error_errno(link
, r
, "DHCP error: No netmask: %m");
418 prefixlen
= in4_addr_netmask_to_prefixlen(&netmask
);
420 r
= sd_dhcp_lease_get_router(lease
, &gateway
);
421 if (r
< 0 && r
!= -ENODATA
)
422 return log_link_error_errno(link
, r
, "DHCP error: Could not get gateway: %m");
426 LOG_LINK_INTERFACE(link
),
427 LOG_LINK_MESSAGE(link
, "DHCPv4 address %u.%u.%u.%u/%u via %u.%u.%u.%u",
428 ADDRESS_FMT_VAL(address
),
430 ADDRESS_FMT_VAL(gateway
)),
431 "ADDRESS=%u.%u.%u.%u", ADDRESS_FMT_VAL(address
),
432 "PREFIXLEN=%u", prefixlen
,
433 "GATEWAY=%u.%u.%u.%u", ADDRESS_FMT_VAL(gateway
),
437 LOG_LINK_INTERFACE(link
),
438 LOG_LINK_MESSAGE(link
, "DHCPv4 address %u.%u.%u.%u/%u",
439 ADDRESS_FMT_VAL(address
),
441 "ADDRESS=%u.%u.%u.%u", ADDRESS_FMT_VAL(address
),
442 "PREFIXLEN=%u", prefixlen
,
445 link
->dhcp_lease
= sd_dhcp_lease_ref(lease
);
448 if (link
->network
->dhcp_use_mtu
) {
451 r
= sd_dhcp_lease_get_mtu(lease
, &mtu
);
453 r
= link_set_mtu(link
, mtu
);
455 log_link_error_errno(link
, r
, "Failed to set MTU to %" PRIu16
": %m", mtu
);
459 if (link
->network
->dhcp_use_hostname
) {
460 const char *hostname
= NULL
;
462 if (link
->network
->dhcp_hostname
)
463 hostname
= link
->network
->dhcp_hostname
;
465 (void) sd_dhcp_lease_get_hostname(lease
, &hostname
);
468 r
= manager_set_hostname(link
->manager
, hostname
);
470 log_link_error_errno(link
, r
, "Failed to set transient hostname to '%s': %m", hostname
);
474 if (link
->network
->dhcp_use_timezone
) {
475 const char *tz
= NULL
;
477 (void) sd_dhcp_lease_get_timezone(link
->dhcp_lease
, &tz
);
480 r
= manager_set_timezone(link
->manager
, tz
);
482 log_link_error_errno(link
, r
, "Failed to set timezone to '%s': %m", tz
);
486 if (!link
->network
->dhcp_critical
) {
487 r
= sd_dhcp_lease_get_lifetime(link
->dhcp_lease
, &lifetime
);
489 log_link_warning_errno(link
, r
, "DHCP error: no lifetime: %m");
494 r
= dhcp4_update_address(link
, &address
, &netmask
, lifetime
);
496 log_link_warning_errno(link
, r
, "Could not update IP address: %m");
497 link_enter_failed(link
);
503 static void dhcp4_handler(sd_dhcp_client
*client
, int event
, void *userdata
) {
504 Link
*link
= userdata
;
508 assert(link
->network
);
509 assert(link
->manager
);
511 if (IN_SET(link
->state
, LINK_STATE_FAILED
, LINK_STATE_LINGER
))
515 case SD_DHCP_CLIENT_EVENT_EXPIRED
:
516 case SD_DHCP_CLIENT_EVENT_STOP
:
517 case SD_DHCP_CLIENT_EVENT_IP_CHANGE
:
518 if (link
->network
->dhcp_critical
) {
519 log_link_error(link
, "DHCPv4 connection considered system critical, ignoring request to reconfigure it.");
523 if (link
->dhcp_lease
) {
524 r
= dhcp_lease_lost(link
);
526 link_enter_failed(link
);
531 if (event
== SD_DHCP_CLIENT_EVENT_IP_CHANGE
) {
532 r
= dhcp_lease_acquired(client
, link
);
534 link_enter_failed(link
);
540 case SD_DHCP_CLIENT_EVENT_RENEW
:
541 r
= dhcp_lease_renew(client
, link
);
543 link_enter_failed(link
);
547 case SD_DHCP_CLIENT_EVENT_IP_ACQUIRE
:
548 r
= dhcp_lease_acquired(client
, link
);
550 link_enter_failed(link
);
556 log_link_warning_errno(link
, event
, "DHCP error: Client failed: %m");
558 log_link_warning(link
, "DHCP unknown event: %i", event
);
565 static int dhcp4_set_hostname(Link
*link
) {
566 _cleanup_free_
char *hostname
= NULL
;
572 if (!link
->network
->dhcp_send_hostname
)
574 else if (link
->network
->dhcp_hostname
)
575 hn
= link
->network
->dhcp_hostname
;
577 r
= gethostname_strict(&hostname
);
578 if (r
< 0 && r
!= -ENXIO
) /* ENXIO: no hostname set or hostname is "localhost" */
584 return sd_dhcp_client_set_hostname(link
->dhcp_client
, hn
);
587 int dhcp4_configure(Link
*link
) {
591 assert(link
->network
);
592 assert(link
->network
->dhcp
& ADDRESS_FAMILY_IPV4
);
594 if (!link
->dhcp_client
) {
595 r
= sd_dhcp_client_new(&link
->dhcp_client
, link
->network
->dhcp_anonymize
);
600 r
= sd_dhcp_client_attach_event(link
->dhcp_client
, NULL
, 0);
604 r
= sd_dhcp_client_set_mac(link
->dhcp_client
,
605 (const uint8_t *) &link
->mac
,
606 sizeof (link
->mac
), ARPHRD_ETHER
);
610 r
= sd_dhcp_client_set_ifindex(link
->dhcp_client
, link
->ifindex
);
614 r
= sd_dhcp_client_set_callback(link
->dhcp_client
, dhcp4_handler
, link
);
618 r
= sd_dhcp_client_set_request_broadcast(link
->dhcp_client
,
619 link
->network
->dhcp_broadcast
);
624 r
= sd_dhcp_client_set_mtu(link
->dhcp_client
, link
->mtu
);
629 if (link
->network
->dhcp_use_mtu
) {
630 r
= sd_dhcp_client_set_request_option(link
->dhcp_client
,
631 SD_DHCP_OPTION_INTERFACE_MTU
);
636 /* NOTE: even if this variable is called "use", it also "sends" PRL
637 * options, maybe there should be a different configuration variable
638 * to send or not route options?. */
639 /* NOTE: when using Anonymize=yes, routes PRL options are sent
640 * by default, so they don't need to be added here. */
641 if (link
->network
->dhcp_use_routes
&& !link
->network
->dhcp_anonymize
) {
642 r
= sd_dhcp_client_set_request_option(link
->dhcp_client
,
643 SD_DHCP_OPTION_STATIC_ROUTE
);
646 r
= sd_dhcp_client_set_request_option(link
->dhcp_client
,
647 SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE
);
652 if (link
->network
->dhcp_use_ntp
) {
653 r
= sd_dhcp_client_set_request_option(link
->dhcp_client
, SD_DHCP_OPTION_NTP_SERVER
);
658 if (link
->network
->dhcp_use_timezone
) {
659 r
= sd_dhcp_client_set_request_option(link
->dhcp_client
, SD_DHCP_OPTION_NEW_TZDB_TIMEZONE
);
664 r
= dhcp4_set_hostname(link
);
668 if (link
->network
->dhcp_vendor_class_identifier
) {
669 r
= sd_dhcp_client_set_vendor_class_identifier(link
->dhcp_client
,
670 link
->network
->dhcp_vendor_class_identifier
);
675 if (link
->network
->dhcp_client_port
) {
676 r
= sd_dhcp_client_set_client_port(link
->dhcp_client
, link
->network
->dhcp_client_port
);
681 switch (link
->network
->dhcp_client_identifier
) {
682 case DHCP_CLIENT_ID_DUID
: {
683 /* If configured, apply user specified DUID and/or IAID */
684 const DUID
*duid
= link_duid(link
);
686 r
= sd_dhcp_client_set_iaid_duid(link
->dhcp_client
,
689 duid
->raw_data_len
> 0 ? duid
->raw_data
: NULL
,
695 case DHCP_CLIENT_ID_MAC
:
696 r
= sd_dhcp_client_set_client_id(link
->dhcp_client
,
698 (const uint8_t *) &link
->mac
,
704 assert_not_reached("Unknown client identifier type.");