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"
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
);
60 assert(link
->network
);
62 if (!link
->network
->dhcp_use_routes
)
65 r
= sd_dhcp_lease_get_router(link
->dhcp_lease
, &gateway
);
66 if (r
< 0 && r
!= -ENODATA
)
67 return log_link_warning_errno(link
, r
, "DHCP error: could not get gateway: %m");
70 struct in_addr address
;
71 _cleanup_route_free_ Route
*route
= NULL
;
72 _cleanup_route_free_ Route
*route_gw
= NULL
;
74 r
= sd_dhcp_lease_get_address(link
->dhcp_lease
, &address
);
76 return log_link_warning_errno(link
, r
, "DHCP error: could not get address: %m");
78 r
= route_new(&route
);
80 return log_link_error_errno(link
, r
, "Could not allocate route: %m");
82 route
->protocol
= RTPROT_DHCP
;
84 r
= route_new(&route_gw
);
86 return log_link_error_errno(link
, r
, "Could not allocate route: %m");
88 /* The dhcp netmask may mask out the gateway. Add an explicit
89 * route for the gw host so that we can route no matter the
90 * netmask or existing kernel route tables. */
91 route_gw
->family
= AF_INET
;
92 route_gw
->dst
.in
= gateway
;
93 route_gw
->dst_prefixlen
= 32;
94 route_gw
->prefsrc
.in
= address
;
95 route_gw
->scope
= RT_SCOPE_LINK
;
96 route_gw
->protocol
= RTPROT_DHCP
;
97 route_gw
->priority
= link
->network
->dhcp_route_metric
;
99 r
= route_configure(route_gw
, link
, dhcp4_route_handler
);
101 return log_link_warning_errno(link
, r
, "Could not set host route: %m");
103 link
->dhcp4_messages
++;
105 route
->family
= AF_INET
;
106 route
->gw
.in
= gateway
;
107 route
->prefsrc
.in
= address
;
108 route
->priority
= link
->network
->dhcp_route_metric
;
110 r
= route_configure(route
, link
, dhcp4_route_handler
);
112 log_link_warning_errno(link
, r
, "Could not set routes: %m");
113 link_enter_failed(link
);
117 link
->dhcp4_messages
++;
120 n
= sd_dhcp_lease_get_routes(link
->dhcp_lease
, &static_routes
);
124 return log_link_warning_errno(link
, n
, "DHCP error: could not get routes: %m");
126 for (i
= 0; i
< n
; i
++) {
127 _cleanup_route_free_ Route
*route
= NULL
;
129 r
= route_new(&route
);
131 return log_link_error_errno(link
, r
, "Could not allocate route: %m");
133 route
->family
= AF_INET
;
134 route
->protocol
= RTPROT_DHCP
;
135 assert_se(sd_dhcp_route_get_gateway(static_routes
[i
], &route
->gw
.in
) >= 0);
136 assert_se(sd_dhcp_route_get_destination(static_routes
[i
], &route
->dst
.in
) >= 0);
137 assert_se(sd_dhcp_route_get_destination_prefix_length(static_routes
[i
], &route
->dst_prefixlen
) >= 0);
138 route
->priority
= link
->network
->dhcp_route_metric
;
140 r
= route_configure(route
, link
, dhcp4_route_handler
);
142 return log_link_warning_errno(link
, r
, "Could not set host route: %m");
144 link
->dhcp4_messages
++;
150 static int dhcp_lease_lost(Link
*link
) {
151 _cleanup_address_free_ Address
*address
= NULL
;
153 struct in_addr netmask
;
154 struct in_addr gateway
;
155 unsigned prefixlen
= 0;
159 assert(link
->dhcp_lease
);
161 log_link_warning(link
, "DHCP lease lost");
163 if (link
->network
->dhcp_use_routes
) {
164 _cleanup_free_ sd_dhcp_route
**routes
= NULL
;
167 n
= sd_dhcp_lease_get_routes(link
->dhcp_lease
, &routes
);
169 for (i
= 0; i
< n
; i
++) {
170 _cleanup_route_free_ Route
*route
= NULL
;
172 r
= route_new(&route
);
174 route
->family
= AF_INET
;
175 assert_se(sd_dhcp_route_get_gateway(routes
[i
], &route
->gw
.in
) >= 0);
176 assert_se(sd_dhcp_route_get_destination(routes
[i
], &route
->dst
.in
) >= 0);
177 assert_se(sd_dhcp_route_get_destination_prefix_length(routes
[i
], &route
->dst_prefixlen
) >= 0);
179 route_remove(route
, link
,
180 link_route_remove_handler
);
186 r
= address_new(&address
);
188 r
= sd_dhcp_lease_get_router(link
->dhcp_lease
, &gateway
);
190 _cleanup_route_free_ Route
*route_gw
= NULL
;
191 _cleanup_route_free_ Route
*route
= NULL
;
193 r
= route_new(&route_gw
);
195 route_gw
->family
= AF_INET
;
196 route_gw
->dst
.in
= gateway
;
197 route_gw
->dst_prefixlen
= 32;
198 route_gw
->scope
= RT_SCOPE_LINK
;
200 route_remove(route_gw
, link
,
201 link_route_remove_handler
);
204 r
= route_new(&route
);
206 route
->family
= AF_INET
;
207 route
->gw
.in
= gateway
;
209 route_remove(route
, link
,
210 link_route_remove_handler
);
214 r
= sd_dhcp_lease_get_address(link
->dhcp_lease
, &addr
);
216 r
= sd_dhcp_lease_get_netmask(link
->dhcp_lease
, &netmask
);
218 prefixlen
= in_addr_netmask_to_prefixlen(&netmask
);
220 address
->family
= AF_INET
;
221 address
->in_addr
.in
= addr
;
222 address
->prefixlen
= prefixlen
;
224 address_remove(address
, link
, link_address_remove_handler
);
228 if (link
->network
->dhcp_use_mtu
) {
231 r
= sd_dhcp_lease_get_mtu(link
->dhcp_lease
, &mtu
);
232 if (r
>= 0 && link
->original_mtu
!= mtu
) {
233 r
= link_set_mtu(link
, link
->original_mtu
);
235 log_link_warning(link
,
236 "DHCP error: could not reset MTU");
237 link_enter_failed(link
);
243 if (link
->network
->dhcp_use_hostname
) {
244 const char *hostname
= NULL
;
246 if (link
->network
->dhcp_hostname
)
247 hostname
= link
->network
->dhcp_hostname
;
249 (void) sd_dhcp_lease_get_hostname(link
->dhcp_lease
, &hostname
);
252 /* If a hostname was set due to the lease, then unset it now. */
253 r
= link_set_hostname(link
, NULL
);
255 log_link_warning_errno(link
, r
, "Failed to reset transient hostname: %m");
259 link
->dhcp_lease
= sd_dhcp_lease_unref(link
->dhcp_lease
);
261 link
->dhcp4_configured
= false;
266 static int dhcp4_address_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
,
268 _cleanup_link_unref_ Link
*link
= userdata
;
273 r
= sd_netlink_message_get_errno(m
);
274 if (r
< 0 && r
!= -EEXIST
) {
275 log_link_error_errno(link
, r
, "Could not set DHCPv4 address: %m");
276 link_enter_failed(link
);
278 manager_rtnl_process_address(rtnl
, m
, link
->manager
);
280 link_set_dhcp_routes(link
);
285 static int dhcp4_update_address(Link
*link
,
286 struct in_addr
*address
,
287 struct in_addr
*netmask
,
289 _cleanup_address_free_ Address
*addr
= NULL
;
297 prefixlen
= in_addr_netmask_to_prefixlen(netmask
);
299 r
= address_new(&addr
);
303 addr
->family
= AF_INET
;
304 addr
->in_addr
.in
.s_addr
= address
->s_addr
;
305 addr
->cinfo
.ifa_prefered
= lifetime
;
306 addr
->cinfo
.ifa_valid
= lifetime
;
307 addr
->prefixlen
= prefixlen
;
308 addr
->broadcast
.s_addr
= address
->s_addr
| ~netmask
->s_addr
;
310 /* allow reusing an existing address and simply update its lifetime
311 * in case it already exists */
312 r
= address_configure(addr
, link
, dhcp4_address_handler
, true);
319 static int dhcp_lease_renew(sd_dhcp_client
*client
, Link
*link
) {
320 sd_dhcp_lease
*lease
;
321 struct in_addr address
;
322 struct in_addr netmask
;
323 uint32_t lifetime
= CACHE_INFO_INFINITY_LIFE_TIME
;
328 assert(link
->network
);
330 r
= sd_dhcp_client_get_lease(client
, &lease
);
332 return log_link_warning_errno(link
, r
, "DHCP error: no lease: %m");
334 sd_dhcp_lease_unref(link
->dhcp_lease
);
335 link
->dhcp4_configured
= false;
336 link
->dhcp_lease
= sd_dhcp_lease_ref(lease
);
339 r
= sd_dhcp_lease_get_address(lease
, &address
);
341 return log_link_warning_errno(link
, r
, "DHCP error: no address: %m");
343 r
= sd_dhcp_lease_get_netmask(lease
, &netmask
);
345 return log_link_warning_errno(link
, r
, "DHCP error: no netmask: %m");
347 if (!link
->network
->dhcp_critical
) {
348 r
= sd_dhcp_lease_get_lifetime(link
->dhcp_lease
, &lifetime
);
350 return log_link_warning_errno(link
, r
, "DHCP error: no lifetime: %m");
353 r
= dhcp4_update_address(link
, &address
, &netmask
, lifetime
);
355 log_link_warning_errno(link
, r
, "Could not update IP address: %m");
356 link_enter_failed(link
);
363 static int dhcp_lease_acquired(sd_dhcp_client
*client
, Link
*link
) {
364 sd_dhcp_lease
*lease
;
365 struct in_addr address
;
366 struct in_addr netmask
;
367 struct in_addr gateway
;
369 uint32_t lifetime
= CACHE_INFO_INFINITY_LIFE_TIME
;
375 r
= sd_dhcp_client_get_lease(client
, &lease
);
377 return log_link_error_errno(link
, r
, "DHCP error: No lease: %m");
379 r
= sd_dhcp_lease_get_address(lease
, &address
);
381 return log_link_error_errno(link
, r
, "DHCP error: No address: %m");
383 r
= sd_dhcp_lease_get_netmask(lease
, &netmask
);
385 return log_link_error_errno(link
, r
, "DHCP error: No netmask: %m");
387 prefixlen
= in_addr_netmask_to_prefixlen(&netmask
);
389 r
= sd_dhcp_lease_get_router(lease
, &gateway
);
390 if (r
< 0 && r
!= -ENODATA
)
391 return log_link_error_errno(link
, r
, "DHCP error: Could not get gateway: %m");
395 LOG_LINK_INTERFACE(link
),
396 LOG_LINK_MESSAGE(link
, "DHCPv4 address %u.%u.%u.%u/%u via %u.%u.%u.%u",
397 ADDRESS_FMT_VAL(address
),
399 ADDRESS_FMT_VAL(gateway
)),
400 "ADDRESS=%u.%u.%u.%u", ADDRESS_FMT_VAL(address
),
401 "PREFIXLEN=%u", prefixlen
,
402 "GATEWAY=%u.%u.%u.%u", ADDRESS_FMT_VAL(gateway
),
406 LOG_LINK_INTERFACE(link
),
407 LOG_LINK_MESSAGE(link
, "DHCPv4 address %u.%u.%u.%u/%u",
408 ADDRESS_FMT_VAL(address
),
410 "ADDRESS=%u.%u.%u.%u", ADDRESS_FMT_VAL(address
),
411 "PREFIXLEN=%u", prefixlen
,
414 link
->dhcp_lease
= sd_dhcp_lease_ref(lease
);
417 if (link
->network
->dhcp_use_mtu
) {
420 r
= sd_dhcp_lease_get_mtu(lease
, &mtu
);
422 r
= link_set_mtu(link
, mtu
);
424 log_link_error_errno(link
, r
, "Failed to set MTU to %" PRIu16
": %m", mtu
);
428 if (link
->network
->dhcp_use_hostname
) {
429 const char *hostname
= NULL
;
431 if (link
->network
->dhcp_hostname
)
432 hostname
= link
->network
->dhcp_hostname
;
434 (void) sd_dhcp_lease_get_hostname(lease
, &hostname
);
437 r
= link_set_hostname(link
, hostname
);
439 log_link_error_errno(link
, r
, "Failed to set transient hostname to '%s': %m", hostname
);
443 if (link
->network
->dhcp_use_timezone
) {
444 const char *tz
= NULL
;
446 (void) sd_dhcp_lease_get_timezone(link
->dhcp_lease
, &tz
);
449 r
= link_set_timezone(link
, tz
);
451 log_link_error_errno(link
, r
, "Failed to set timezone to '%s': %m", tz
);
455 if (!link
->network
->dhcp_critical
) {
456 r
= sd_dhcp_lease_get_lifetime(link
->dhcp_lease
, &lifetime
);
458 log_link_warning_errno(link
, r
, "DHCP error: no lifetime: %m");
463 r
= dhcp4_update_address(link
, &address
, &netmask
, lifetime
);
465 log_link_warning_errno(link
, r
, "Could not update IP address: %m");
466 link_enter_failed(link
);
472 static void dhcp4_handler(sd_dhcp_client
*client
, int event
, void *userdata
) {
473 Link
*link
= userdata
;
477 assert(link
->network
);
478 assert(link
->manager
);
480 if (IN_SET(link
->state
, LINK_STATE_FAILED
, LINK_STATE_LINGER
))
484 case SD_DHCP_CLIENT_EVENT_EXPIRED
:
485 case SD_DHCP_CLIENT_EVENT_STOP
:
486 case SD_DHCP_CLIENT_EVENT_IP_CHANGE
:
487 if (link
->network
->dhcp_critical
) {
488 log_link_error(link
, "DHCPv4 connection considered system critical, ignoring request to reconfigure it.");
492 if (link
->dhcp_lease
) {
493 r
= dhcp_lease_lost(link
);
495 link_enter_failed(link
);
500 if (event
== SD_DHCP_CLIENT_EVENT_IP_CHANGE
) {
501 r
= dhcp_lease_acquired(client
, link
);
503 link_enter_failed(link
);
509 case SD_DHCP_CLIENT_EVENT_RENEW
:
510 r
= dhcp_lease_renew(client
, link
);
512 link_enter_failed(link
);
516 case SD_DHCP_CLIENT_EVENT_IP_ACQUIRE
:
517 r
= dhcp_lease_acquired(client
, link
);
519 link_enter_failed(link
);
525 log_link_warning_errno(link
, event
, "DHCP error: Client failed: %m");
527 log_link_warning(link
, "DHCP unknown event: %i", event
);
534 int dhcp4_configure(Link
*link
) {
538 assert(link
->network
);
539 assert(link
->network
->dhcp
& ADDRESS_FAMILY_IPV4
);
541 if (!link
->dhcp_client
) {
542 r
= sd_dhcp_client_new(&link
->dhcp_client
);
547 r
= sd_dhcp_client_attach_event(link
->dhcp_client
, NULL
, 0);
551 r
= sd_dhcp_client_set_mac(link
->dhcp_client
,
552 (const uint8_t *) &link
->mac
,
553 sizeof (link
->mac
), ARPHRD_ETHER
);
557 r
= sd_dhcp_client_set_ifindex(link
->dhcp_client
, link
->ifindex
);
561 r
= sd_dhcp_client_set_callback(link
->dhcp_client
, dhcp4_handler
, link
);
565 r
= sd_dhcp_client_set_request_broadcast(link
->dhcp_client
,
566 link
->network
->dhcp_broadcast
);
571 r
= sd_dhcp_client_set_mtu(link
->dhcp_client
, link
->mtu
);
576 if (link
->network
->dhcp_use_mtu
) {
577 r
= sd_dhcp_client_set_request_option(link
->dhcp_client
,
578 SD_DHCP_OPTION_INTERFACE_MTU
);
583 if (link
->network
->dhcp_use_routes
) {
584 r
= sd_dhcp_client_set_request_option(link
->dhcp_client
,
585 SD_DHCP_OPTION_STATIC_ROUTE
);
588 r
= sd_dhcp_client_set_request_option(link
->dhcp_client
,
589 SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE
);
594 /* Always acquire the timezone and NTP */
595 r
= sd_dhcp_client_set_request_option(link
->dhcp_client
, SD_DHCP_OPTION_NTP_SERVER
);
599 r
= sd_dhcp_client_set_request_option(link
->dhcp_client
, SD_DHCP_OPTION_NEW_TZDB_TIMEZONE
);
603 if (link
->network
->dhcp_send_hostname
) {
604 _cleanup_free_
char *hostname
= NULL
;
605 const char *hn
= NULL
;
607 if (!link
->network
->dhcp_hostname
) {
608 hostname
= gethostname_malloc();
614 hn
= link
->network
->dhcp_hostname
;
616 if (!is_localhost(hn
)) {
617 r
= sd_dhcp_client_set_hostname(link
->dhcp_client
, hn
);
623 if (link
->network
->dhcp_vendor_class_identifier
) {
624 r
= sd_dhcp_client_set_vendor_class_identifier(link
->dhcp_client
,
625 link
->network
->dhcp_vendor_class_identifier
);
630 switch (link
->network
->dhcp_client_identifier
) {
631 case DHCP_CLIENT_ID_DUID
: {
632 /* If configured, apply user specified DUID and/or IAID */
633 const DUID
*duid
= link_duid(link
);
635 r
= sd_dhcp_client_set_iaid_duid(link
->dhcp_client
,
638 duid
->raw_data_len
> 0 ? duid
->raw_data
: NULL
,
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.");