1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013-2014 Tom Gundersen <teg@jklm.no>
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
22 #include <netinet/ether.h>
25 #include "alloc-util.h"
26 #include "dhcp-lease-internal.h"
27 #include "hostname-util.h"
28 #include "network-internal.h"
29 #include "networkd-link.h"
31 static int dhcp4_route_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
,
33 _cleanup_link_unref_ Link
*link
= userdata
;
37 assert(link
->dhcp4_messages
);
39 link
->dhcp4_messages
--;
41 r
= sd_netlink_message_get_errno(m
);
42 if (r
< 0 && r
!= -EEXIST
) {
43 log_link_error_errno(link
, r
, "Could not set DHCPv4 route: %m");
44 link_enter_failed(link
);
47 if (!link
->dhcp4_messages
) {
48 link
->dhcp4_configured
= true;
49 link_check_ready(link
);
55 static int link_set_dhcp_routes(Link
*link
) {
56 struct in_addr gateway
;
57 struct sd_dhcp_route
*static_routes
;
61 assert(link
->dhcp_lease
);
63 r
= sd_dhcp_lease_get_router(link
->dhcp_lease
, &gateway
);
64 if (r
< 0 && r
!= -ENODATA
)
65 return log_link_warning_errno(link
, r
, "DHCP error: could not get gateway: %m");
68 struct in_addr address
;
69 _cleanup_route_free_ Route
*route
= NULL
;
70 _cleanup_route_free_ Route
*route_gw
= NULL
;
72 r
= sd_dhcp_lease_get_address(link
->dhcp_lease
, &address
);
74 return log_link_warning_errno(link
, r
, "DHCP error: could not get address: %m");
76 r
= route_new(&route
);
78 return log_link_error_errno(link
, r
, "Could not allocate route: %m");
80 route
->protocol
= RTPROT_DHCP
;
82 r
= route_new(&route_gw
);
84 return log_link_error_errno(link
, r
, "Could not allocate route: %m");
86 /* The dhcp netmask may mask out the gateway. Add an explicit
87 * route for the gw host so that we can route no matter the
88 * netmask or existing kernel route tables. */
89 route_gw
->family
= AF_INET
;
90 route_gw
->dst
.in
= gateway
;
91 route_gw
->dst_prefixlen
= 32;
92 route_gw
->prefsrc
.in
= address
;
93 route_gw
->scope
= RT_SCOPE_LINK
;
94 route_gw
->protocol
= RTPROT_DHCP
;
95 route_gw
->priority
= link
->network
->dhcp_route_metric
;
97 r
= route_configure(route_gw
, link
, &dhcp4_route_handler
);
99 return log_link_warning_errno(link
, r
, "Could not set host route: %m");
101 link
->dhcp4_messages
++;
103 route
->family
= AF_INET
;
104 route
->gw
.in
= gateway
;
105 route
->prefsrc
.in
= address
;
106 route
->priority
= link
->network
->dhcp_route_metric
;
108 r
= route_configure(route
, link
, &dhcp4_route_handler
);
110 log_link_warning_errno(link
, r
, "Could not set routes: %m");
111 link_enter_failed(link
);
115 link
->dhcp4_messages
++;
118 n
= sd_dhcp_lease_get_routes(link
->dhcp_lease
, &static_routes
);
122 return log_link_warning_errno(link
, n
, "DHCP error: could not get routes: %m");
124 for (i
= 0; i
< n
; i
++) {
125 _cleanup_route_free_ Route
*route
= NULL
;
127 r
= route_new(&route
);
129 return log_link_error_errno(link
, r
, "Could not allocate route: %m");
131 route
->family
= AF_INET
;
132 route
->protocol
= RTPROT_DHCP
;
133 route
->gw
.in
= static_routes
[i
].gw_addr
;
134 route
->dst
.in
= static_routes
[i
].dst_addr
;
135 route
->dst_prefixlen
= static_routes
[i
].dst_prefixlen
;
136 route
->priority
= link
->network
->dhcp_route_metric
;
138 r
= route_configure(route
, link
, &dhcp4_route_handler
);
140 return log_link_warning_errno(link
, r
, "Could not set host route: %m");
142 link
->dhcp4_messages
++;
148 static int dhcp_lease_lost(Link
*link
) {
149 _cleanup_address_free_ Address
*address
= NULL
;
151 struct in_addr netmask
;
152 struct in_addr gateway
;
153 unsigned prefixlen
= 0;
157 assert(link
->dhcp_lease
);
159 log_link_warning(link
, "DHCP lease lost");
161 if (link
->network
->dhcp_routes
) {
162 struct sd_dhcp_route
*routes
;
165 n
= sd_dhcp_lease_get_routes(link
->dhcp_lease
, &routes
);
167 for (i
= 0; i
< n
; i
++) {
168 _cleanup_route_free_ Route
*route
= NULL
;
170 r
= route_new(&route
);
172 route
->family
= AF_INET
;
173 route
->gw
.in
= routes
[i
].gw_addr
;
174 route
->dst
.in
= routes
[i
].dst_addr
;
175 route
->dst_prefixlen
= routes
[i
].dst_prefixlen
;
177 route_remove(route
, link
,
178 &link_route_remove_handler
);
184 r
= address_new(&address
);
186 r
= sd_dhcp_lease_get_router(link
->dhcp_lease
, &gateway
);
188 _cleanup_route_free_ Route
*route_gw
= NULL
;
189 _cleanup_route_free_ Route
*route
= NULL
;
191 r
= route_new(&route_gw
);
193 route_gw
->family
= AF_INET
;
194 route_gw
->dst
.in
= gateway
;
195 route_gw
->dst_prefixlen
= 32;
196 route_gw
->scope
= RT_SCOPE_LINK
;
198 route_remove(route_gw
, link
,
199 &link_route_remove_handler
);
202 r
= route_new(&route
);
204 route
->family
= AF_INET
;
205 route
->gw
.in
= gateway
;
207 route_remove(route
, link
,
208 &link_route_remove_handler
);
212 r
= sd_dhcp_lease_get_address(link
->dhcp_lease
, &addr
);
214 r
= sd_dhcp_lease_get_netmask(link
->dhcp_lease
, &netmask
);
216 prefixlen
= in_addr_netmask_to_prefixlen(&netmask
);
218 address
->family
= AF_INET
;
219 address
->in_addr
.in
= addr
;
220 address
->prefixlen
= prefixlen
;
222 address_remove(address
, link
, &link_address_remove_handler
);
226 if (link
->network
->dhcp_mtu
) {
229 r
= sd_dhcp_lease_get_mtu(link
->dhcp_lease
, &mtu
);
230 if (r
>= 0 && link
->original_mtu
!= mtu
) {
231 r
= link_set_mtu(link
, link
->original_mtu
);
233 log_link_warning(link
,
234 "DHCP error: could not reset MTU");
235 link_enter_failed(link
);
241 if (link
->network
->dhcp_hostname
) {
242 const char *hostname
= NULL
;
244 if (link
->network
->hostname
)
245 hostname
= link
->network
->hostname
;
247 (void) sd_dhcp_lease_get_hostname(link
->dhcp_lease
, &hostname
);
250 /* If a hostname was set due to the lease, then unset it now. */
251 r
= link_set_hostname(link
, NULL
);
253 log_link_warning_errno(link
, r
, "Failed to reset transient hostname: %m");
257 link
->dhcp_lease
= sd_dhcp_lease_unref(link
->dhcp_lease
);
258 link
->dhcp4_configured
= false;
263 static int dhcp4_address_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
,
265 _cleanup_link_unref_ Link
*link
= userdata
;
270 r
= sd_netlink_message_get_errno(m
);
271 if (r
< 0 && r
!= -EEXIST
) {
272 log_link_error_errno(link
, r
, "Could not set DHCPv4 address: %m");
273 link_enter_failed(link
);
275 manager_rtnl_process_address(rtnl
, m
, link
->manager
);
277 link_set_dhcp_routes(link
);
282 static int dhcp4_update_address(Link
*link
,
283 struct in_addr
*address
,
284 struct in_addr
*netmask
,
286 _cleanup_address_free_ Address
*addr
= NULL
;
294 prefixlen
= in_addr_netmask_to_prefixlen(netmask
);
296 r
= address_new(&addr
);
300 addr
->family
= AF_INET
;
301 addr
->in_addr
.in
.s_addr
= address
->s_addr
;
302 addr
->cinfo
.ifa_prefered
= lifetime
;
303 addr
->cinfo
.ifa_valid
= lifetime
;
304 addr
->prefixlen
= prefixlen
;
305 addr
->broadcast
.s_addr
= address
->s_addr
| ~netmask
->s_addr
;
307 /* allow reusing an existing address and simply update its lifetime
308 * in case it already exists */
309 r
= address_configure(addr
, link
, &dhcp4_address_handler
, true);
316 static int dhcp_lease_renew(sd_dhcp_client
*client
, Link
*link
) {
317 sd_dhcp_lease
*lease
;
318 struct in_addr address
;
319 struct in_addr netmask
;
320 uint32_t lifetime
= CACHE_INFO_INFINITY_LIFE_TIME
;
325 assert(link
->network
);
327 r
= sd_dhcp_client_get_lease(client
, &lease
);
329 return log_link_warning_errno(link
, r
, "DHCP error: no lease: %m");
331 sd_dhcp_lease_unref(link
->dhcp_lease
);
332 link
->dhcp4_configured
= false;
333 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
);
412 if (link
->network
->dhcp_mtu
) {
415 r
= sd_dhcp_lease_get_mtu(lease
, &mtu
);
417 r
= link_set_mtu(link
, mtu
);
419 log_link_error_errno(link
, r
, "Failed to set MTU to %" PRIu16
": %m", mtu
);
423 if (link
->network
->dhcp_hostname
) {
424 const char *hostname
= NULL
;
426 if (link
->network
->hostname
)
427 hostname
= link
->network
->hostname
;
429 (void) sd_dhcp_lease_get_hostname(lease
, &hostname
);
432 r
= link_set_hostname(link
, hostname
);
434 log_link_error_errno(link
, r
, "Failed to set transient hostname to '%s': %m", hostname
);
438 if (link
->network
->dhcp_timezone
) {
439 const char *tz
= NULL
;
441 (void) sd_dhcp_lease_get_timezone(link
->dhcp_lease
, &tz
);
444 r
= link_set_timezone(link
, tz
);
446 log_link_error_errno(link
, r
, "Failed to set timezone to '%s': %m", tz
);
450 if (!link
->network
->dhcp_critical
) {
451 r
= sd_dhcp_lease_get_lifetime(link
->dhcp_lease
, &lifetime
);
453 log_link_warning_errno(link
, r
, "DHCP error: no lifetime: %m");
458 r
= dhcp4_update_address(link
, &address
, &netmask
, lifetime
);
460 log_link_warning_errno(link
, r
, "Could not update IP address: %m");
461 link_enter_failed(link
);
467 static void dhcp4_handler(sd_dhcp_client
*client
, int event
, void *userdata
) {
468 Link
*link
= userdata
;
472 assert(link
->network
);
473 assert(link
->manager
);
475 if (IN_SET(link
->state
, LINK_STATE_FAILED
, LINK_STATE_LINGER
))
479 case SD_DHCP_CLIENT_EVENT_EXPIRED
:
480 case SD_DHCP_CLIENT_EVENT_STOP
:
481 case SD_DHCP_CLIENT_EVENT_IP_CHANGE
:
482 if (link
->network
->dhcp_critical
) {
483 log_link_error(link
, "DHCPv4 connection considered system critical, ignoring request to reconfigure it.");
487 if (link
->dhcp_lease
) {
488 r
= dhcp_lease_lost(link
);
490 link_enter_failed(link
);
495 if (event
== SD_DHCP_CLIENT_EVENT_IP_CHANGE
) {
496 r
= dhcp_lease_acquired(client
, link
);
498 link_enter_failed(link
);
504 case SD_DHCP_CLIENT_EVENT_RENEW
:
505 r
= dhcp_lease_renew(client
, link
);
507 link_enter_failed(link
);
511 case SD_DHCP_CLIENT_EVENT_IP_ACQUIRE
:
512 r
= dhcp_lease_acquired(client
, link
);
514 link_enter_failed(link
);
520 log_link_warning_errno(link
, event
, "DHCP error: Client failed: %m");
522 log_link_warning(link
, "DHCP unknown event: %i", event
);
529 int dhcp4_configure(Link
*link
) {
533 assert(link
->network
);
534 assert(link
->network
->dhcp
& ADDRESS_FAMILY_IPV4
);
536 if (!link
->dhcp_client
) {
537 r
= sd_dhcp_client_new(&link
->dhcp_client
);
542 r
= sd_dhcp_client_attach_event(link
->dhcp_client
, NULL
, 0);
546 r
= sd_dhcp_client_set_mac(link
->dhcp_client
,
547 (const uint8_t *) &link
->mac
,
548 sizeof (link
->mac
), ARPHRD_ETHER
);
552 r
= sd_dhcp_client_set_index(link
->dhcp_client
, link
->ifindex
);
556 r
= sd_dhcp_client_set_callback(link
->dhcp_client
, dhcp4_handler
, link
);
560 r
= sd_dhcp_client_set_request_broadcast(link
->dhcp_client
,
561 link
->network
->dhcp_broadcast
);
566 r
= sd_dhcp_client_set_mtu(link
->dhcp_client
, link
->mtu
);
571 if (link
->network
->dhcp_mtu
) {
572 r
= sd_dhcp_client_set_request_option(link
->dhcp_client
,
573 DHCP_OPTION_INTERFACE_MTU
);
578 if (link
->network
->dhcp_routes
) {
579 r
= sd_dhcp_client_set_request_option(link
->dhcp_client
,
580 DHCP_OPTION_STATIC_ROUTE
);
583 r
= sd_dhcp_client_set_request_option(link
->dhcp_client
,
584 DHCP_OPTION_CLASSLESS_STATIC_ROUTE
);
589 /* Always acquire the timezone and NTP*/
590 r
= sd_dhcp_client_set_request_option(link
->dhcp_client
, DHCP_OPTION_NTP_SERVER
);
594 r
= sd_dhcp_client_set_request_option(link
->dhcp_client
, DHCP_OPTION_NEW_TZDB_TIMEZONE
);
598 if (link
->network
->dhcp_sendhost
) {
599 _cleanup_free_
char *hostname
= NULL
;
600 const char *hn
= NULL
;
602 if (!link
->network
->hostname
) {
603 hostname
= gethostname_malloc();
609 hn
= link
->network
->hostname
;
611 if (!is_localhost(hn
)) {
612 r
= sd_dhcp_client_set_hostname(link
->dhcp_client
, hn
);
618 if (link
->network
->dhcp_vendor_class_identifier
) {
619 r
= sd_dhcp_client_set_vendor_class_identifier(link
->dhcp_client
,
620 link
->network
->dhcp_vendor_class_identifier
);
625 switch (link
->network
->dhcp_client_identifier
) {
626 case DHCP_CLIENT_ID_DUID
:
627 /* Library defaults to this. */
629 case DHCP_CLIENT_ID_MAC
:
630 r
= sd_dhcp_client_set_client_id(link
->dhcp_client
,
632 (const uint8_t *) &link
->mac
,
638 assert_not_reached("Unknown client identifier type.");