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
> 0);
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
== 0) {
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 _cleanup_free_ sd_dhcp_route
**static_routes
= NULL
;
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 assert_se(sd_dhcp_route_get_gateway(static_routes
[i
], &route
->gw
.in
) >= 0);
134 assert_se(sd_dhcp_route_get_destination(static_routes
[i
], &route
->dst
.in
) >= 0);
135 assert_se(sd_dhcp_route_get_destination_prefix_length(static_routes
[i
], &route
->dst_prefixlen
) >= 0);
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 _cleanup_free_ sd_dhcp_route
**routes
= NULL
;
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 assert_se(sd_dhcp_route_get_gateway(routes
[i
], &route
->gw
.in
) >= 0);
174 assert_se(sd_dhcp_route_get_destination(routes
[i
], &route
->dst
.in
) >= 0);
175 assert_se(sd_dhcp_route_get_destination_prefix_length(routes
[i
], &route
->dst_prefixlen
) >= 0);
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
);
259 link
->dhcp4_configured
= false;
264 static int dhcp4_address_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
,
266 _cleanup_link_unref_ Link
*link
= userdata
;
271 r
= sd_netlink_message_get_errno(m
);
272 if (r
< 0 && r
!= -EEXIST
) {
273 log_link_error_errno(link
, r
, "Could not set DHCPv4 address: %m");
274 link_enter_failed(link
);
276 manager_rtnl_process_address(rtnl
, m
, link
->manager
);
278 link_set_dhcp_routes(link
);
283 static int dhcp4_update_address(Link
*link
,
284 struct in_addr
*address
,
285 struct in_addr
*netmask
,
287 _cleanup_address_free_ Address
*addr
= NULL
;
295 prefixlen
= in_addr_netmask_to_prefixlen(netmask
);
297 r
= address_new(&addr
);
301 addr
->family
= AF_INET
;
302 addr
->in_addr
.in
.s_addr
= address
->s_addr
;
303 addr
->cinfo
.ifa_prefered
= lifetime
;
304 addr
->cinfo
.ifa_valid
= lifetime
;
305 addr
->prefixlen
= prefixlen
;
306 addr
->broadcast
.s_addr
= address
->s_addr
| ~netmask
->s_addr
;
308 /* allow reusing an existing address and simply update its lifetime
309 * in case it already exists */
310 r
= address_configure(addr
, link
, &dhcp4_address_handler
, true);
317 static int dhcp_lease_renew(sd_dhcp_client
*client
, Link
*link
) {
318 sd_dhcp_lease
*lease
;
319 struct in_addr address
;
320 struct in_addr netmask
;
321 uint32_t lifetime
= CACHE_INFO_INFINITY_LIFE_TIME
;
326 assert(link
->network
);
328 r
= sd_dhcp_client_get_lease(client
, &lease
);
330 return log_link_warning_errno(link
, r
, "DHCP error: no lease: %m");
332 sd_dhcp_lease_unref(link
->dhcp_lease
);
333 link
->dhcp4_configured
= false;
334 link
->dhcp_lease
= sd_dhcp_lease_ref(lease
);
337 r
= sd_dhcp_lease_get_address(lease
, &address
);
339 return log_link_warning_errno(link
, r
, "DHCP error: no address: %m");
341 r
= sd_dhcp_lease_get_netmask(lease
, &netmask
);
343 return log_link_warning_errno(link
, r
, "DHCP error: no netmask: %m");
345 if (!link
->network
->dhcp_critical
) {
346 r
= sd_dhcp_lease_get_lifetime(link
->dhcp_lease
, &lifetime
);
348 return log_link_warning_errno(link
, r
, "DHCP error: no lifetime: %m");
351 r
= dhcp4_update_address(link
, &address
, &netmask
, lifetime
);
353 log_link_warning_errno(link
, r
, "Could not update IP address: %m");
354 link_enter_failed(link
);
361 static int dhcp_lease_acquired(sd_dhcp_client
*client
, Link
*link
) {
362 sd_dhcp_lease
*lease
;
363 struct in_addr address
;
364 struct in_addr netmask
;
365 struct in_addr gateway
;
367 uint32_t lifetime
= CACHE_INFO_INFINITY_LIFE_TIME
;
373 r
= sd_dhcp_client_get_lease(client
, &lease
);
375 return log_link_error_errno(link
, r
, "DHCP error: No lease: %m");
377 r
= sd_dhcp_lease_get_address(lease
, &address
);
379 return log_link_error_errno(link
, r
, "DHCP error: No address: %m");
381 r
= sd_dhcp_lease_get_netmask(lease
, &netmask
);
383 return log_link_error_errno(link
, r
, "DHCP error: No netmask: %m");
385 prefixlen
= in_addr_netmask_to_prefixlen(&netmask
);
387 r
= sd_dhcp_lease_get_router(lease
, &gateway
);
388 if (r
< 0 && r
!= -ENODATA
)
389 return log_link_error_errno(link
, r
, "DHCP error: Could not get gateway: %m");
393 LOG_LINK_INTERFACE(link
),
394 LOG_LINK_MESSAGE(link
, "DHCPv4 address %u.%u.%u.%u/%u via %u.%u.%u.%u",
395 ADDRESS_FMT_VAL(address
),
397 ADDRESS_FMT_VAL(gateway
)),
398 "ADDRESS=%u.%u.%u.%u", ADDRESS_FMT_VAL(address
),
399 "PREFIXLEN=%u", prefixlen
,
400 "GATEWAY=%u.%u.%u.%u", ADDRESS_FMT_VAL(gateway
),
404 LOG_LINK_INTERFACE(link
),
405 LOG_LINK_MESSAGE(link
, "DHCPv4 address %u.%u.%u.%u/%u",
406 ADDRESS_FMT_VAL(address
),
408 "ADDRESS=%u.%u.%u.%u", ADDRESS_FMT_VAL(address
),
409 "PREFIXLEN=%u", prefixlen
,
412 link
->dhcp_lease
= sd_dhcp_lease_ref(lease
);
415 if (link
->network
->dhcp_mtu
) {
418 r
= sd_dhcp_lease_get_mtu(lease
, &mtu
);
420 r
= link_set_mtu(link
, mtu
);
422 log_link_error_errno(link
, r
, "Failed to set MTU to %" PRIu16
": %m", mtu
);
426 if (link
->network
->dhcp_hostname
) {
427 const char *hostname
= NULL
;
429 if (link
->network
->hostname
)
430 hostname
= link
->network
->hostname
;
432 (void) sd_dhcp_lease_get_hostname(lease
, &hostname
);
435 r
= link_set_hostname(link
, hostname
);
437 log_link_error_errno(link
, r
, "Failed to set transient hostname to '%s': %m", hostname
);
441 if (link
->network
->dhcp_timezone
) {
442 const char *tz
= NULL
;
444 (void) sd_dhcp_lease_get_timezone(link
->dhcp_lease
, &tz
);
447 r
= link_set_timezone(link
, tz
);
449 log_link_error_errno(link
, r
, "Failed to set timezone to '%s': %m", tz
);
453 if (!link
->network
->dhcp_critical
) {
454 r
= sd_dhcp_lease_get_lifetime(link
->dhcp_lease
, &lifetime
);
456 log_link_warning_errno(link
, r
, "DHCP error: no lifetime: %m");
461 r
= dhcp4_update_address(link
, &address
, &netmask
, lifetime
);
463 log_link_warning_errno(link
, r
, "Could not update IP address: %m");
464 link_enter_failed(link
);
470 static void dhcp4_handler(sd_dhcp_client
*client
, int event
, void *userdata
) {
471 Link
*link
= userdata
;
475 assert(link
->network
);
476 assert(link
->manager
);
478 if (IN_SET(link
->state
, LINK_STATE_FAILED
, LINK_STATE_LINGER
))
482 case SD_DHCP_CLIENT_EVENT_EXPIRED
:
483 case SD_DHCP_CLIENT_EVENT_STOP
:
484 case SD_DHCP_CLIENT_EVENT_IP_CHANGE
:
485 if (link
->network
->dhcp_critical
) {
486 log_link_error(link
, "DHCPv4 connection considered system critical, ignoring request to reconfigure it.");
490 if (link
->dhcp_lease
) {
491 r
= dhcp_lease_lost(link
);
493 link_enter_failed(link
);
498 if (event
== SD_DHCP_CLIENT_EVENT_IP_CHANGE
) {
499 r
= dhcp_lease_acquired(client
, link
);
501 link_enter_failed(link
);
507 case SD_DHCP_CLIENT_EVENT_RENEW
:
508 r
= dhcp_lease_renew(client
, link
);
510 link_enter_failed(link
);
514 case SD_DHCP_CLIENT_EVENT_IP_ACQUIRE
:
515 r
= dhcp_lease_acquired(client
, link
);
517 link_enter_failed(link
);
523 log_link_warning_errno(link
, event
, "DHCP error: Client failed: %m");
525 log_link_warning(link
, "DHCP unknown event: %i", event
);
532 int dhcp4_configure(Link
*link
) {
536 assert(link
->network
);
537 assert(link
->network
->dhcp
& ADDRESS_FAMILY_IPV4
);
539 if (!link
->dhcp_client
) {
540 r
= sd_dhcp_client_new(&link
->dhcp_client
);
545 r
= sd_dhcp_client_attach_event(link
->dhcp_client
, NULL
, 0);
549 r
= sd_dhcp_client_set_mac(link
->dhcp_client
,
550 (const uint8_t *) &link
->mac
,
551 sizeof (link
->mac
), ARPHRD_ETHER
);
555 r
= sd_dhcp_client_set_index(link
->dhcp_client
, link
->ifindex
);
559 r
= sd_dhcp_client_set_callback(link
->dhcp_client
, dhcp4_handler
, link
);
563 r
= sd_dhcp_client_set_request_broadcast(link
->dhcp_client
,
564 link
->network
->dhcp_broadcast
);
569 r
= sd_dhcp_client_set_mtu(link
->dhcp_client
, link
->mtu
);
574 if (link
->network
->dhcp_mtu
) {
575 r
= sd_dhcp_client_set_request_option(link
->dhcp_client
,
576 SD_DHCP_OPTION_INTERFACE_MTU
);
581 if (link
->network
->dhcp_routes
) {
582 r
= sd_dhcp_client_set_request_option(link
->dhcp_client
,
583 SD_DHCP_OPTION_STATIC_ROUTE
);
586 r
= sd_dhcp_client_set_request_option(link
->dhcp_client
,
587 SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE
);
592 /* Always acquire the timezone and NTP*/
593 r
= sd_dhcp_client_set_request_option(link
->dhcp_client
, SD_DHCP_OPTION_NTP_SERVER
);
597 r
= sd_dhcp_client_set_request_option(link
->dhcp_client
, SD_DHCP_OPTION_NEW_TZDB_TIMEZONE
);
601 if (link
->network
->dhcp_sendhost
) {
602 _cleanup_free_
char *hostname
= NULL
;
603 const char *hn
= NULL
;
605 if (!link
->network
->hostname
) {
606 hostname
= gethostname_malloc();
612 hn
= link
->network
->hostname
;
614 if (!is_localhost(hn
)) {
615 r
= sd_dhcp_client_set_hostname(link
->dhcp_client
, hn
);
621 if (link
->network
->dhcp_vendor_class_identifier
) {
622 r
= sd_dhcp_client_set_vendor_class_identifier(link
->dhcp_client
,
623 link
->network
->dhcp_vendor_class_identifier
);
628 switch (link
->network
->dhcp_client_identifier
) {
629 case DHCP_CLIENT_ID_DUID
:
630 /* Library defaults to this. */
632 case DHCP_CLIENT_ID_MAC
:
633 r
= sd_dhcp_client_set_client_id(link
->dhcp_client
,
635 (const uint8_t *) &link
->mac
,
641 assert_not_reached("Unknown client identifier type.");