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"
29 static int dhcp4_route_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
,
31 _cleanup_link_unref_ Link
*link
= userdata
;
35 assert(link
->dhcp4_messages
> 0);
37 link
->dhcp4_messages
--;
39 r
= sd_netlink_message_get_errno(m
);
40 if (r
< 0 && r
!= -EEXIST
) {
41 log_link_error_errno(link
, r
, "Could not set DHCPv4 route: %m");
42 link_enter_failed(link
);
45 if (link
->dhcp4_messages
== 0) {
46 link
->dhcp4_configured
= true;
47 link_check_ready(link
);
53 static int link_set_dhcp_routes(Link
*link
) {
54 struct in_addr gateway
;
55 _cleanup_free_ sd_dhcp_route
**static_routes
= NULL
;
59 assert(link
->dhcp_lease
);
61 r
= sd_dhcp_lease_get_router(link
->dhcp_lease
, &gateway
);
62 if (r
< 0 && r
!= -ENODATA
)
63 return log_link_warning_errno(link
, r
, "DHCP error: could not get gateway: %m");
66 struct in_addr address
;
67 _cleanup_route_free_ Route
*route
= NULL
;
68 _cleanup_route_free_ Route
*route_gw
= NULL
;
70 r
= sd_dhcp_lease_get_address(link
->dhcp_lease
, &address
);
72 return log_link_warning_errno(link
, r
, "DHCP error: could not get address: %m");
74 r
= route_new(&route
);
76 return log_link_error_errno(link
, r
, "Could not allocate route: %m");
78 route
->protocol
= RTPROT_DHCP
;
80 r
= route_new(&route_gw
);
82 return log_link_error_errno(link
, r
, "Could not allocate route: %m");
84 /* The dhcp netmask may mask out the gateway. Add an explicit
85 * route for the gw host so that we can route no matter the
86 * netmask or existing kernel route tables. */
87 route_gw
->family
= AF_INET
;
88 route_gw
->dst
.in
= gateway
;
89 route_gw
->dst_prefixlen
= 32;
90 route_gw
->prefsrc
.in
= address
;
91 route_gw
->scope
= RT_SCOPE_LINK
;
92 route_gw
->protocol
= RTPROT_DHCP
;
93 route_gw
->priority
= link
->network
->dhcp_route_metric
;
95 r
= route_configure(route_gw
, link
, &dhcp4_route_handler
);
97 return log_link_warning_errno(link
, r
, "Could not set host route: %m");
99 link
->dhcp4_messages
++;
101 route
->family
= AF_INET
;
102 route
->gw
.in
= gateway
;
103 route
->prefsrc
.in
= address
;
104 route
->priority
= link
->network
->dhcp_route_metric
;
106 r
= route_configure(route
, link
, &dhcp4_route_handler
);
108 log_link_warning_errno(link
, r
, "Could not set routes: %m");
109 link_enter_failed(link
);
113 link
->dhcp4_messages
++;
116 n
= sd_dhcp_lease_get_routes(link
->dhcp_lease
, &static_routes
);
120 return log_link_warning_errno(link
, n
, "DHCP error: could not get routes: %m");
122 for (i
= 0; i
< n
; i
++) {
123 _cleanup_route_free_ Route
*route
= NULL
;
125 r
= route_new(&route
);
127 return log_link_error_errno(link
, r
, "Could not allocate route: %m");
129 route
->family
= AF_INET
;
130 route
->protocol
= RTPROT_DHCP
;
131 assert_se(sd_dhcp_route_get_gateway(static_routes
[i
], &route
->gw
.in
) >= 0);
132 assert_se(sd_dhcp_route_get_destination(static_routes
[i
], &route
->dst
.in
) >= 0);
133 assert_se(sd_dhcp_route_get_destination_prefix_length(static_routes
[i
], &route
->dst_prefixlen
) >= 0);
134 route
->priority
= link
->network
->dhcp_route_metric
;
136 r
= route_configure(route
, link
, &dhcp4_route_handler
);
138 return log_link_warning_errno(link
, r
, "Could not set host route: %m");
140 link
->dhcp4_messages
++;
146 static int dhcp_lease_lost(Link
*link
) {
147 _cleanup_address_free_ Address
*address
= NULL
;
149 struct in_addr netmask
;
150 struct in_addr gateway
;
151 unsigned prefixlen
= 0;
155 assert(link
->dhcp_lease
);
157 log_link_warning(link
, "DHCP lease lost");
159 if (link
->network
->dhcp_use_routes
) {
160 _cleanup_free_ sd_dhcp_route
**routes
= NULL
;
163 n
= sd_dhcp_lease_get_routes(link
->dhcp_lease
, &routes
);
165 for (i
= 0; i
< n
; i
++) {
166 _cleanup_route_free_ Route
*route
= NULL
;
168 r
= route_new(&route
);
170 route
->family
= AF_INET
;
171 assert_se(sd_dhcp_route_get_gateway(routes
[i
], &route
->gw
.in
) >= 0);
172 assert_se(sd_dhcp_route_get_destination(routes
[i
], &route
->dst
.in
) >= 0);
173 assert_se(sd_dhcp_route_get_destination_prefix_length(routes
[i
], &route
->dst_prefixlen
) >= 0);
175 route_remove(route
, link
,
176 &link_route_remove_handler
);
182 r
= address_new(&address
);
184 r
= sd_dhcp_lease_get_router(link
->dhcp_lease
, &gateway
);
186 _cleanup_route_free_ Route
*route_gw
= NULL
;
187 _cleanup_route_free_ Route
*route
= NULL
;
189 r
= route_new(&route_gw
);
191 route_gw
->family
= AF_INET
;
192 route_gw
->dst
.in
= gateway
;
193 route_gw
->dst_prefixlen
= 32;
194 route_gw
->scope
= RT_SCOPE_LINK
;
196 route_remove(route_gw
, link
,
197 &link_route_remove_handler
);
200 r
= route_new(&route
);
202 route
->family
= AF_INET
;
203 route
->gw
.in
= gateway
;
205 route_remove(route
, link
,
206 &link_route_remove_handler
);
210 r
= sd_dhcp_lease_get_address(link
->dhcp_lease
, &addr
);
212 r
= sd_dhcp_lease_get_netmask(link
->dhcp_lease
, &netmask
);
214 prefixlen
= in_addr_netmask_to_prefixlen(&netmask
);
216 address
->family
= AF_INET
;
217 address
->in_addr
.in
= addr
;
218 address
->prefixlen
= prefixlen
;
220 address_remove(address
, link
, &link_address_remove_handler
);
224 if (link
->network
->dhcp_use_mtu
) {
227 r
= sd_dhcp_lease_get_mtu(link
->dhcp_lease
, &mtu
);
228 if (r
>= 0 && link
->original_mtu
!= mtu
) {
229 r
= link_set_mtu(link
, link
->original_mtu
);
231 log_link_warning(link
,
232 "DHCP error: could not reset MTU");
233 link_enter_failed(link
);
239 if (link
->network
->dhcp_use_hostname
) {
240 const char *hostname
= NULL
;
242 if (link
->network
->dhcp_hostname
)
243 hostname
= link
->network
->dhcp_hostname
;
245 (void) sd_dhcp_lease_get_hostname(link
->dhcp_lease
, &hostname
);
248 /* If a hostname was set due to the lease, then unset it now. */
249 r
= link_set_hostname(link
, NULL
);
251 log_link_warning_errno(link
, r
, "Failed to reset transient hostname: %m");
255 link
->dhcp_lease
= sd_dhcp_lease_unref(link
->dhcp_lease
);
257 link
->dhcp4_configured
= false;
262 static int dhcp4_address_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
,
264 _cleanup_link_unref_ Link
*link
= userdata
;
269 r
= sd_netlink_message_get_errno(m
);
270 if (r
< 0 && r
!= -EEXIST
) {
271 log_link_error_errno(link
, r
, "Could not set DHCPv4 address: %m");
272 link_enter_failed(link
);
274 manager_rtnl_process_address(rtnl
, m
, link
->manager
);
276 link_set_dhcp_routes(link
);
281 static int dhcp4_update_address(Link
*link
,
282 struct in_addr
*address
,
283 struct in_addr
*netmask
,
285 _cleanup_address_free_ Address
*addr
= NULL
;
293 prefixlen
= in_addr_netmask_to_prefixlen(netmask
);
295 r
= address_new(&addr
);
299 addr
->family
= AF_INET
;
300 addr
->in_addr
.in
.s_addr
= address
->s_addr
;
301 addr
->cinfo
.ifa_prefered
= lifetime
;
302 addr
->cinfo
.ifa_valid
= lifetime
;
303 addr
->prefixlen
= prefixlen
;
304 addr
->broadcast
.s_addr
= address
->s_addr
| ~netmask
->s_addr
;
306 /* allow reusing an existing address and simply update its lifetime
307 * in case it already exists */
308 r
= address_configure(addr
, link
, &dhcp4_address_handler
, true);
315 static int dhcp_lease_renew(sd_dhcp_client
*client
, Link
*link
) {
316 sd_dhcp_lease
*lease
;
317 struct in_addr address
;
318 struct in_addr netmask
;
319 uint32_t lifetime
= CACHE_INFO_INFINITY_LIFE_TIME
;
324 assert(link
->network
);
326 r
= sd_dhcp_client_get_lease(client
, &lease
);
328 return log_link_warning_errno(link
, r
, "DHCP error: no lease: %m");
330 sd_dhcp_lease_unref(link
->dhcp_lease
);
331 link
->dhcp4_configured
= false;
332 link
->dhcp_lease
= sd_dhcp_lease_ref(lease
);
335 r
= sd_dhcp_lease_get_address(lease
, &address
);
337 return log_link_warning_errno(link
, r
, "DHCP error: no address: %m");
339 r
= sd_dhcp_lease_get_netmask(lease
, &netmask
);
341 return log_link_warning_errno(link
, r
, "DHCP error: no netmask: %m");
343 if (!link
->network
->dhcp_critical
) {
344 r
= sd_dhcp_lease_get_lifetime(link
->dhcp_lease
, &lifetime
);
346 return log_link_warning_errno(link
, r
, "DHCP error: no lifetime: %m");
349 r
= dhcp4_update_address(link
, &address
, &netmask
, lifetime
);
351 log_link_warning_errno(link
, r
, "Could not update IP address: %m");
352 link_enter_failed(link
);
359 static int dhcp_lease_acquired(sd_dhcp_client
*client
, Link
*link
) {
360 sd_dhcp_lease
*lease
;
361 struct in_addr address
;
362 struct in_addr netmask
;
363 struct in_addr gateway
;
365 uint32_t lifetime
= CACHE_INFO_INFINITY_LIFE_TIME
;
371 r
= sd_dhcp_client_get_lease(client
, &lease
);
373 return log_link_error_errno(link
, r
, "DHCP error: No lease: %m");
375 r
= sd_dhcp_lease_get_address(lease
, &address
);
377 return log_link_error_errno(link
, r
, "DHCP error: No address: %m");
379 r
= sd_dhcp_lease_get_netmask(lease
, &netmask
);
381 return log_link_error_errno(link
, r
, "DHCP error: No netmask: %m");
383 prefixlen
= in_addr_netmask_to_prefixlen(&netmask
);
385 r
= sd_dhcp_lease_get_router(lease
, &gateway
);
386 if (r
< 0 && r
!= -ENODATA
)
387 return log_link_error_errno(link
, r
, "DHCP error: Could not get gateway: %m");
391 LOG_LINK_INTERFACE(link
),
392 LOG_LINK_MESSAGE(link
, "DHCPv4 address %u.%u.%u.%u/%u via %u.%u.%u.%u",
393 ADDRESS_FMT_VAL(address
),
395 ADDRESS_FMT_VAL(gateway
)),
396 "ADDRESS=%u.%u.%u.%u", ADDRESS_FMT_VAL(address
),
397 "PREFIXLEN=%u", prefixlen
,
398 "GATEWAY=%u.%u.%u.%u", ADDRESS_FMT_VAL(gateway
),
402 LOG_LINK_INTERFACE(link
),
403 LOG_LINK_MESSAGE(link
, "DHCPv4 address %u.%u.%u.%u/%u",
404 ADDRESS_FMT_VAL(address
),
406 "ADDRESS=%u.%u.%u.%u", ADDRESS_FMT_VAL(address
),
407 "PREFIXLEN=%u", prefixlen
,
410 link
->dhcp_lease
= sd_dhcp_lease_ref(lease
);
413 if (link
->network
->dhcp_use_mtu
) {
416 r
= sd_dhcp_lease_get_mtu(lease
, &mtu
);
418 r
= link_set_mtu(link
, mtu
);
420 log_link_error_errno(link
, r
, "Failed to set MTU to %" PRIu16
": %m", mtu
);
424 if (link
->network
->dhcp_use_hostname
) {
425 const char *hostname
= NULL
;
427 if (link
->network
->dhcp_hostname
)
428 hostname
= link
->network
->dhcp_hostname
;
430 (void) sd_dhcp_lease_get_hostname(lease
, &hostname
);
433 r
= link_set_hostname(link
, hostname
);
435 log_link_error_errno(link
, r
, "Failed to set transient hostname to '%s': %m", hostname
);
439 if (link
->network
->dhcp_use_timezone
) {
440 const char *tz
= NULL
;
442 (void) sd_dhcp_lease_get_timezone(link
->dhcp_lease
, &tz
);
445 r
= link_set_timezone(link
, tz
);
447 log_link_error_errno(link
, r
, "Failed to set timezone to '%s': %m", tz
);
451 if (!link
->network
->dhcp_critical
) {
452 r
= sd_dhcp_lease_get_lifetime(link
->dhcp_lease
, &lifetime
);
454 log_link_warning_errno(link
, r
, "DHCP error: no lifetime: %m");
459 r
= dhcp4_update_address(link
, &address
, &netmask
, lifetime
);
461 log_link_warning_errno(link
, r
, "Could not update IP address: %m");
462 link_enter_failed(link
);
468 static void dhcp4_handler(sd_dhcp_client
*client
, int event
, void *userdata
) {
469 Link
*link
= userdata
;
473 assert(link
->network
);
474 assert(link
->manager
);
476 if (IN_SET(link
->state
, LINK_STATE_FAILED
, LINK_STATE_LINGER
))
480 case SD_DHCP_CLIENT_EVENT_EXPIRED
:
481 case SD_DHCP_CLIENT_EVENT_STOP
:
482 case SD_DHCP_CLIENT_EVENT_IP_CHANGE
:
483 if (link
->network
->dhcp_critical
) {
484 log_link_error(link
, "DHCPv4 connection considered system critical, ignoring request to reconfigure it.");
488 if (link
->dhcp_lease
) {
489 r
= dhcp_lease_lost(link
);
491 link_enter_failed(link
);
496 if (event
== SD_DHCP_CLIENT_EVENT_IP_CHANGE
) {
497 r
= dhcp_lease_acquired(client
, link
);
499 link_enter_failed(link
);
505 case SD_DHCP_CLIENT_EVENT_RENEW
:
506 r
= dhcp_lease_renew(client
, link
);
508 link_enter_failed(link
);
512 case SD_DHCP_CLIENT_EVENT_IP_ACQUIRE
:
513 r
= dhcp_lease_acquired(client
, link
);
515 link_enter_failed(link
);
521 log_link_warning_errno(link
, event
, "DHCP error: Client failed: %m");
523 log_link_warning(link
, "DHCP unknown event: %i", event
);
530 int dhcp4_configure(Link
*link
) {
534 assert(link
->network
);
535 assert(link
->network
->dhcp
& ADDRESS_FAMILY_IPV4
);
537 if (!link
->dhcp_client
) {
538 r
= sd_dhcp_client_new(&link
->dhcp_client
);
543 r
= sd_dhcp_client_attach_event(link
->dhcp_client
, NULL
, 0);
547 r
= sd_dhcp_client_set_mac(link
->dhcp_client
,
548 (const uint8_t *) &link
->mac
,
549 sizeof (link
->mac
), ARPHRD_ETHER
);
553 r
= sd_dhcp_client_set_index(link
->dhcp_client
, link
->ifindex
);
557 r
= sd_dhcp_client_set_callback(link
->dhcp_client
, dhcp4_handler
, link
);
561 r
= sd_dhcp_client_set_request_broadcast(link
->dhcp_client
,
562 link
->network
->dhcp_broadcast
);
567 r
= sd_dhcp_client_set_mtu(link
->dhcp_client
, link
->mtu
);
572 if (link
->network
->dhcp_use_mtu
) {
573 r
= sd_dhcp_client_set_request_option(link
->dhcp_client
,
574 SD_DHCP_OPTION_INTERFACE_MTU
);
579 if (link
->network
->dhcp_use_routes
) {
580 r
= sd_dhcp_client_set_request_option(link
->dhcp_client
,
581 SD_DHCP_OPTION_STATIC_ROUTE
);
584 r
= sd_dhcp_client_set_request_option(link
->dhcp_client
,
585 SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE
);
590 /* Always acquire the timezone and NTP */
591 r
= sd_dhcp_client_set_request_option(link
->dhcp_client
, SD_DHCP_OPTION_NTP_SERVER
);
595 r
= sd_dhcp_client_set_request_option(link
->dhcp_client
, SD_DHCP_OPTION_NEW_TZDB_TIMEZONE
);
599 if (link
->network
->dhcp_send_hostname
) {
600 _cleanup_free_
char *hostname
= NULL
;
601 const char *hn
= NULL
;
603 if (!link
->network
->dhcp_hostname
) {
604 hostname
= gethostname_malloc();
610 hn
= link
->network
->dhcp_hostname
;
612 if (!is_localhost(hn
)) {
613 r
= sd_dhcp_client_set_hostname(link
->dhcp_client
, hn
);
619 if (link
->network
->dhcp_vendor_class_identifier
) {
620 r
= sd_dhcp_client_set_vendor_class_identifier(link
->dhcp_client
,
621 link
->network
->dhcp_vendor_class_identifier
);
626 switch (link
->network
->dhcp_client_identifier
) {
627 case DHCP_CLIENT_ID_DUID
:
628 /* If configured, apply user specified DUID and/or IAID */
629 if (link
->network
->duid_type
!= _DUID_TYPE_INVALID
)
630 r
= sd_dhcp_client_set_iaid_duid(link
->dhcp_client
,
632 link
->network
->dhcp_duid_type
,
633 link
->network
->dhcp_duid
,
634 link
->network
->dhcp_duid_len
);
636 r
= sd_dhcp_client_set_iaid_duid(link
->dhcp_client
,
638 link
->manager
->dhcp_duid_type
,
639 link
->manager
->dhcp_duid
,
640 link
->manager
->dhcp_duid_len
);
644 case DHCP_CLIENT_ID_MAC
:
645 r
= sd_dhcp_client_set_client_id(link
->dhcp_client
,
647 (const uint8_t *) &link
->mac
,
653 assert_not_reached("Unknown client identifier type.");