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 "netdev/vrf.h"
27 #include "network-internal.h"
28 #include "networkd-link.h"
29 #include "networkd-manager.h"
30 #include "networkd-network.h"
32 static int dhcp4_route_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
,
34 _cleanup_link_unref_ Link
*link
= userdata
;
38 assert(link
->dhcp4_messages
> 0);
40 link
->dhcp4_messages
--;
42 r
= sd_netlink_message_get_errno(m
);
43 if (r
< 0 && r
!= -EEXIST
) {
44 log_link_error_errno(link
, r
, "Could not set DHCPv4 route: %m");
45 link_enter_failed(link
);
48 if (link
->dhcp4_messages
== 0) {
49 link
->dhcp4_configured
= true;
50 link_check_ready(link
);
56 static int route_scope_from_address(const Route
*route
, const struct in_addr
*self_addr
) {
60 if (in_addr_is_localhost(AF_INET
, &route
->dst
) ||
61 (self_addr
->s_addr
&& route
->dst
.in
.s_addr
== self_addr
->s_addr
))
63 else if (in4_addr_is_null(&route
->gw
.in
))
66 return RT_SCOPE_UNIVERSE
;
69 static int link_set_dhcp_routes(Link
*link
) {
70 struct in_addr gateway
, address
;
71 _cleanup_free_ sd_dhcp_route
**static_routes
= NULL
;
77 if (!link
->dhcp_lease
) /* link went down while we configured the IP addresses? */
80 if (!link
->network
) /* link went down while we configured the IP addresses? */
83 if (!link
->network
->dhcp_use_routes
)
86 /* When the interface is part of an VRF use the VRFs routing table, unless
87 * there is a another table specified. */
88 table
= link
->network
->dhcp_route_table
;
89 if (!link
->network
->dhcp_route_table_set
&& link
->network
->vrf
!= NULL
)
90 table
= VRF(link
->network
->vrf
)->table
;
92 r
= sd_dhcp_lease_get_address(link
->dhcp_lease
, &address
);
94 return log_link_warning_errno(link
, r
, "DHCP error: could not get address: %m");
96 r
= sd_dhcp_lease_get_router(link
->dhcp_lease
, &gateway
);
97 if (r
< 0 && r
!= -ENODATA
)
98 return log_link_warning_errno(link
, r
, "DHCP error: could not get gateway: %m");
101 _cleanup_route_free_ Route
*route
= NULL
;
102 _cleanup_route_free_ Route
*route_gw
= NULL
;
104 r
= route_new(&route
);
106 return log_link_error_errno(link
, r
, "Could not allocate route: %m");
108 route
->protocol
= RTPROT_DHCP
;
110 r
= route_new(&route_gw
);
112 return log_link_error_errno(link
, r
, "Could not allocate route: %m");
114 /* The dhcp netmask may mask out the gateway. Add an explicit
115 * route for the gw host so that we can route no matter the
116 * netmask or existing kernel route tables. */
117 route_gw
->family
= AF_INET
;
118 route_gw
->dst
.in
= gateway
;
119 route_gw
->dst_prefixlen
= 32;
120 route_gw
->prefsrc
.in
= address
;
121 route_gw
->scope
= RT_SCOPE_LINK
;
122 route_gw
->protocol
= RTPROT_DHCP
;
123 route_gw
->priority
= link
->network
->dhcp_route_metric
;
124 route_gw
->table
= table
;
126 r
= route_configure(route_gw
, link
, dhcp4_route_handler
);
128 return log_link_warning_errno(link
, r
, "Could not set host route: %m");
130 link
->dhcp4_messages
++;
132 route
->family
= AF_INET
;
133 route
->gw
.in
= gateway
;
134 route
->prefsrc
.in
= address
;
135 route
->priority
= link
->network
->dhcp_route_metric
;
136 route
->table
= table
;
138 r
= route_configure(route
, link
, dhcp4_route_handler
);
140 log_link_warning_errno(link
, r
, "Could not set routes: %m");
141 link_enter_failed(link
);
145 link
->dhcp4_messages
++;
148 n
= sd_dhcp_lease_get_routes(link
->dhcp_lease
, &static_routes
);
152 return log_link_warning_errno(link
, n
, "DHCP error: could not get routes: %m");
154 for (i
= 0; i
< n
; i
++) {
155 _cleanup_route_free_ Route
*route
= NULL
;
157 r
= route_new(&route
);
159 return log_link_error_errno(link
, r
, "Could not allocate route: %m");
161 route
->family
= AF_INET
;
162 route
->protocol
= RTPROT_DHCP
;
163 assert_se(sd_dhcp_route_get_gateway(static_routes
[i
], &route
->gw
.in
) >= 0);
164 assert_se(sd_dhcp_route_get_destination(static_routes
[i
], &route
->dst
.in
) >= 0);
165 assert_se(sd_dhcp_route_get_destination_prefix_length(static_routes
[i
], &route
->dst_prefixlen
) >= 0);
166 route
->priority
= link
->network
->dhcp_route_metric
;
167 route
->table
= table
;
168 route
->scope
= route_scope_from_address(route
, &address
);
170 r
= route_configure(route
, link
, dhcp4_route_handler
);
172 return log_link_warning_errno(link
, r
, "Could not set host route: %m");
174 link
->dhcp4_messages
++;
180 static int dhcp_lease_lost(Link
*link
) {
181 _cleanup_address_free_ Address
*address
= NULL
;
183 struct in_addr netmask
;
184 struct in_addr gateway
;
185 unsigned prefixlen
= 0;
189 assert(link
->dhcp_lease
);
191 log_link_warning(link
, "DHCP lease lost");
193 if (link
->network
->dhcp_use_routes
) {
194 _cleanup_free_ sd_dhcp_route
**routes
= NULL
;
197 n
= sd_dhcp_lease_get_routes(link
->dhcp_lease
, &routes
);
199 for (i
= 0; i
< n
; i
++) {
200 _cleanup_route_free_ Route
*route
= NULL
;
202 r
= route_new(&route
);
204 route
->family
= AF_INET
;
205 assert_se(sd_dhcp_route_get_gateway(routes
[i
], &route
->gw
.in
) >= 0);
206 assert_se(sd_dhcp_route_get_destination(routes
[i
], &route
->dst
.in
) >= 0);
207 assert_se(sd_dhcp_route_get_destination_prefix_length(routes
[i
], &route
->dst_prefixlen
) >= 0);
209 route_remove(route
, link
,
210 link_route_remove_handler
);
216 r
= address_new(&address
);
218 r
= sd_dhcp_lease_get_router(link
->dhcp_lease
, &gateway
);
220 _cleanup_route_free_ Route
*route_gw
= NULL
;
221 _cleanup_route_free_ Route
*route
= NULL
;
223 r
= route_new(&route_gw
);
225 route_gw
->family
= AF_INET
;
226 route_gw
->dst
.in
= gateway
;
227 route_gw
->dst_prefixlen
= 32;
228 route_gw
->scope
= RT_SCOPE_LINK
;
230 route_remove(route_gw
, link
,
231 link_route_remove_handler
);
234 r
= route_new(&route
);
236 route
->family
= AF_INET
;
237 route
->gw
.in
= gateway
;
239 route_remove(route
, link
,
240 link_route_remove_handler
);
244 r
= sd_dhcp_lease_get_address(link
->dhcp_lease
, &addr
);
246 r
= sd_dhcp_lease_get_netmask(link
->dhcp_lease
, &netmask
);
248 prefixlen
= in4_addr_netmask_to_prefixlen(&netmask
);
250 address
->family
= AF_INET
;
251 address
->in_addr
.in
= addr
;
252 address
->prefixlen
= prefixlen
;
254 address_remove(address
, link
, link_address_remove_handler
);
258 if (link
->network
->dhcp_use_mtu
) {
261 r
= sd_dhcp_lease_get_mtu(link
->dhcp_lease
, &mtu
);
262 if (r
>= 0 && link
->original_mtu
!= mtu
) {
263 r
= link_set_mtu(link
, link
->original_mtu
);
265 log_link_warning(link
,
266 "DHCP error: could not reset MTU");
267 link_enter_failed(link
);
273 if (link
->network
->dhcp_use_hostname
) {
274 const char *hostname
= NULL
;
276 if (link
->network
->dhcp_hostname
)
277 hostname
= link
->network
->dhcp_hostname
;
279 (void) sd_dhcp_lease_get_hostname(link
->dhcp_lease
, &hostname
);
282 /* If a hostname was set due to the lease, then unset it now. */
283 r
= manager_set_hostname(link
->manager
, NULL
);
285 log_link_warning_errno(link
, r
, "Failed to reset transient hostname: %m");
289 link
->dhcp_lease
= sd_dhcp_lease_unref(link
->dhcp_lease
);
291 link
->dhcp4_configured
= false;
296 static int dhcp4_address_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
,
298 _cleanup_link_unref_ Link
*link
= userdata
;
303 r
= sd_netlink_message_get_errno(m
);
304 if (r
< 0 && r
!= -EEXIST
) {
305 log_link_error_errno(link
, r
, "Could not set DHCPv4 address: %m");
306 link_enter_failed(link
);
308 manager_rtnl_process_address(rtnl
, m
, link
->manager
);
310 link_set_dhcp_routes(link
);
315 static int dhcp4_update_address(Link
*link
,
316 struct in_addr
*address
,
317 struct in_addr
*netmask
,
319 _cleanup_address_free_ Address
*addr
= NULL
;
327 prefixlen
= in4_addr_netmask_to_prefixlen(netmask
);
329 r
= address_new(&addr
);
333 addr
->family
= AF_INET
;
334 addr
->in_addr
.in
.s_addr
= address
->s_addr
;
335 addr
->cinfo
.ifa_prefered
= lifetime
;
336 addr
->cinfo
.ifa_valid
= lifetime
;
337 addr
->prefixlen
= prefixlen
;
338 addr
->broadcast
.s_addr
= address
->s_addr
| ~netmask
->s_addr
;
340 /* allow reusing an existing address and simply update its lifetime
341 * in case it already exists */
342 r
= address_configure(addr
, link
, dhcp4_address_handler
, true);
349 static int dhcp_lease_renew(sd_dhcp_client
*client
, Link
*link
) {
350 sd_dhcp_lease
*lease
;
351 struct in_addr address
;
352 struct in_addr netmask
;
353 uint32_t lifetime
= CACHE_INFO_INFINITY_LIFE_TIME
;
358 assert(link
->network
);
360 r
= sd_dhcp_client_get_lease(client
, &lease
);
362 return log_link_warning_errno(link
, r
, "DHCP error: no lease: %m");
364 sd_dhcp_lease_unref(link
->dhcp_lease
);
365 link
->dhcp4_configured
= false;
366 link
->dhcp_lease
= sd_dhcp_lease_ref(lease
);
369 r
= sd_dhcp_lease_get_address(lease
, &address
);
371 return log_link_warning_errno(link
, r
, "DHCP error: no address: %m");
373 r
= sd_dhcp_lease_get_netmask(lease
, &netmask
);
375 return log_link_warning_errno(link
, r
, "DHCP error: no netmask: %m");
377 if (!link
->network
->dhcp_critical
) {
378 r
= sd_dhcp_lease_get_lifetime(link
->dhcp_lease
, &lifetime
);
380 return log_link_warning_errno(link
, r
, "DHCP error: no lifetime: %m");
383 r
= dhcp4_update_address(link
, &address
, &netmask
, lifetime
);
385 log_link_warning_errno(link
, r
, "Could not update IP address: %m");
386 link_enter_failed(link
);
393 static int dhcp_lease_acquired(sd_dhcp_client
*client
, Link
*link
) {
394 sd_dhcp_lease
*lease
;
395 struct in_addr address
;
396 struct in_addr netmask
;
397 struct in_addr gateway
;
399 uint32_t lifetime
= CACHE_INFO_INFINITY_LIFE_TIME
;
405 r
= sd_dhcp_client_get_lease(client
, &lease
);
407 return log_link_error_errno(link
, r
, "DHCP error: No lease: %m");
409 r
= sd_dhcp_lease_get_address(lease
, &address
);
411 return log_link_error_errno(link
, r
, "DHCP error: No address: %m");
413 r
= sd_dhcp_lease_get_netmask(lease
, &netmask
);
415 return log_link_error_errno(link
, r
, "DHCP error: No netmask: %m");
417 prefixlen
= in4_addr_netmask_to_prefixlen(&netmask
);
419 r
= sd_dhcp_lease_get_router(lease
, &gateway
);
420 if (r
< 0 && r
!= -ENODATA
)
421 return log_link_error_errno(link
, r
, "DHCP error: Could not get gateway: %m");
425 LOG_LINK_INTERFACE(link
),
426 LOG_LINK_MESSAGE(link
, "DHCPv4 address %u.%u.%u.%u/%u via %u.%u.%u.%u",
427 ADDRESS_FMT_VAL(address
),
429 ADDRESS_FMT_VAL(gateway
)),
430 "ADDRESS=%u.%u.%u.%u", ADDRESS_FMT_VAL(address
),
431 "PREFIXLEN=%u", prefixlen
,
432 "GATEWAY=%u.%u.%u.%u", ADDRESS_FMT_VAL(gateway
),
436 LOG_LINK_INTERFACE(link
),
437 LOG_LINK_MESSAGE(link
, "DHCPv4 address %u.%u.%u.%u/%u",
438 ADDRESS_FMT_VAL(address
),
440 "ADDRESS=%u.%u.%u.%u", ADDRESS_FMT_VAL(address
),
441 "PREFIXLEN=%u", prefixlen
,
444 link
->dhcp_lease
= sd_dhcp_lease_ref(lease
);
447 if (link
->network
->dhcp_use_mtu
) {
450 r
= sd_dhcp_lease_get_mtu(lease
, &mtu
);
452 r
= link_set_mtu(link
, mtu
);
454 log_link_error_errno(link
, r
, "Failed to set MTU to %" PRIu16
": %m", mtu
);
458 if (link
->network
->dhcp_use_hostname
) {
459 const char *hostname
= NULL
;
461 if (link
->network
->dhcp_hostname
)
462 hostname
= link
->network
->dhcp_hostname
;
464 (void) sd_dhcp_lease_get_hostname(lease
, &hostname
);
467 r
= manager_set_hostname(link
->manager
, hostname
);
469 log_link_error_errno(link
, r
, "Failed to set transient hostname to '%s': %m", hostname
);
473 if (link
->network
->dhcp_use_timezone
) {
474 const char *tz
= NULL
;
476 (void) sd_dhcp_lease_get_timezone(link
->dhcp_lease
, &tz
);
479 r
= manager_set_timezone(link
->manager
, tz
);
481 log_link_error_errno(link
, r
, "Failed to set timezone to '%s': %m", tz
);
485 if (!link
->network
->dhcp_critical
) {
486 r
= sd_dhcp_lease_get_lifetime(link
->dhcp_lease
, &lifetime
);
488 log_link_warning_errno(link
, r
, "DHCP error: no lifetime: %m");
493 r
= dhcp4_update_address(link
, &address
, &netmask
, lifetime
);
495 log_link_warning_errno(link
, r
, "Could not update IP address: %m");
496 link_enter_failed(link
);
502 static void dhcp4_handler(sd_dhcp_client
*client
, int event
, void *userdata
) {
503 Link
*link
= userdata
;
507 assert(link
->network
);
508 assert(link
->manager
);
510 if (IN_SET(link
->state
, LINK_STATE_FAILED
, LINK_STATE_LINGER
))
514 case SD_DHCP_CLIENT_EVENT_EXPIRED
:
515 case SD_DHCP_CLIENT_EVENT_STOP
:
516 case SD_DHCP_CLIENT_EVENT_IP_CHANGE
:
517 if (link
->network
->dhcp_critical
) {
518 log_link_error(link
, "DHCPv4 connection considered system critical, ignoring request to reconfigure it.");
522 if (link
->dhcp_lease
) {
523 r
= dhcp_lease_lost(link
);
525 link_enter_failed(link
);
530 if (event
== SD_DHCP_CLIENT_EVENT_IP_CHANGE
) {
531 r
= dhcp_lease_acquired(client
, link
);
533 link_enter_failed(link
);
539 case SD_DHCP_CLIENT_EVENT_RENEW
:
540 r
= dhcp_lease_renew(client
, link
);
542 link_enter_failed(link
);
546 case SD_DHCP_CLIENT_EVENT_IP_ACQUIRE
:
547 r
= dhcp_lease_acquired(client
, link
);
549 link_enter_failed(link
);
555 log_link_warning_errno(link
, event
, "DHCP error: Client failed: %m");
557 log_link_warning(link
, "DHCP unknown event: %i", event
);
564 static int dhcp4_set_hostname(Link
*link
) {
565 _cleanup_free_
char *hostname
= NULL
;
571 if (!link
->network
->dhcp_send_hostname
)
573 else if (link
->network
->dhcp_hostname
)
574 hn
= link
->network
->dhcp_hostname
;
576 r
= gethostname_strict(&hostname
);
577 if (r
< 0 && r
!= -ENXIO
) /* ENXIO: no hostname set or hostname is "localhost" */
583 return sd_dhcp_client_set_hostname(link
->dhcp_client
, hn
);
586 int dhcp4_configure(Link
*link
) {
590 assert(link
->network
);
591 assert(link
->network
->dhcp
& ADDRESS_FAMILY_IPV4
);
593 if (!link
->dhcp_client
) {
594 r
= sd_dhcp_client_new(&link
->dhcp_client
, link
->network
->dhcp_anonymize
);
599 r
= sd_dhcp_client_attach_event(link
->dhcp_client
, NULL
, 0);
603 r
= sd_dhcp_client_set_mac(link
->dhcp_client
,
604 (const uint8_t *) &link
->mac
,
605 sizeof (link
->mac
), ARPHRD_ETHER
);
609 r
= sd_dhcp_client_set_ifindex(link
->dhcp_client
, link
->ifindex
);
613 r
= sd_dhcp_client_set_callback(link
->dhcp_client
, dhcp4_handler
, link
);
617 r
= sd_dhcp_client_set_request_broadcast(link
->dhcp_client
,
618 link
->network
->dhcp_broadcast
);
623 r
= sd_dhcp_client_set_mtu(link
->dhcp_client
, link
->mtu
);
628 if (link
->network
->dhcp_use_mtu
) {
629 r
= sd_dhcp_client_set_request_option(link
->dhcp_client
,
630 SD_DHCP_OPTION_INTERFACE_MTU
);
635 /* NOTE: even if this variable is called "use", it also "sends" PRL
636 * options, maybe there should be a different configuration variable
637 * to send or not route options?. */
638 /* NOTE: when using Anonymize=yes, routes PRL options are sent
639 * by default, so they don't need to be added here. */
640 if (link
->network
->dhcp_use_routes
&& !link
->network
->dhcp_anonymize
) {
641 r
= sd_dhcp_client_set_request_option(link
->dhcp_client
,
642 SD_DHCP_OPTION_STATIC_ROUTE
);
645 r
= sd_dhcp_client_set_request_option(link
->dhcp_client
,
646 SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE
);
651 if (link
->network
->dhcp_use_ntp
) {
652 r
= sd_dhcp_client_set_request_option(link
->dhcp_client
, SD_DHCP_OPTION_NTP_SERVER
);
657 if (link
->network
->dhcp_use_timezone
) {
658 r
= sd_dhcp_client_set_request_option(link
->dhcp_client
, SD_DHCP_OPTION_NEW_TZDB_TIMEZONE
);
663 r
= dhcp4_set_hostname(link
);
667 if (link
->network
->dhcp_vendor_class_identifier
) {
668 r
= sd_dhcp_client_set_vendor_class_identifier(link
->dhcp_client
,
669 link
->network
->dhcp_vendor_class_identifier
);
674 if (link
->network
->dhcp_client_port
) {
675 r
= sd_dhcp_client_set_client_port(link
->dhcp_client
, link
->network
->dhcp_client_port
);
680 switch (link
->network
->dhcp_client_identifier
) {
681 case DHCP_CLIENT_ID_DUID
: {
682 /* If configured, apply user specified DUID and/or IAID */
683 const DUID
*duid
= link_duid(link
);
685 r
= sd_dhcp_client_set_iaid_duid(link
->dhcp_client
,
688 duid
->raw_data_len
> 0 ? duid
->raw_data
: NULL
,
694 case DHCP_CLIENT_ID_MAC
:
695 r
= sd_dhcp_client_set_client_id(link
->dhcp_client
,
697 (const uint8_t *) &link
->mac
,
703 assert_not_reached("Unknown client identifier type.");