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 "hostname-util.h"
26 #include "networkd-link.h"
27 #include "network-internal.h"
28 #include "dhcp-lease-internal.h"
30 static int dhcp4_route_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
,
32 _cleanup_link_unref_ Link
*link
= userdata
;
36 assert(link
->dhcp4_messages
);
38 link
->dhcp4_messages
--;
40 r
= sd_netlink_message_get_errno(m
);
41 if (r
< 0 && r
!= -EEXIST
) {
42 log_link_error_errno(link
, r
, "Could not set DHCPv4 route: %m");
43 link_enter_failed(link
);
46 if (!link
->dhcp4_messages
) {
47 link
->dhcp4_configured
= true;
48 link_check_ready(link
);
54 static int link_set_dhcp_routes(Link
*link
) {
55 struct in_addr gateway
;
56 struct sd_dhcp_route
*static_routes
;
60 assert(link
->dhcp_lease
);
62 r
= sd_dhcp_lease_get_router(link
->dhcp_lease
, &gateway
);
63 if (r
< 0 && r
!= -ENODATA
)
64 return log_link_warning_errno(link
, r
, "DHCP error: could not get gateway: %m");
67 struct in_addr address
;
68 _cleanup_route_free_ Route
*route
= NULL
;
69 _cleanup_route_free_ Route
*route_gw
= NULL
;
71 r
= sd_dhcp_lease_get_address(link
->dhcp_lease
, &address
);
73 return log_link_warning_errno(link
, r
, "DHCP error: could not get address: %m");
75 r
= route_new(&route
);
77 return log_link_error_errno(link
, r
, "Could not allocate route: %m");
79 route
->protocol
= RTPROT_DHCP
;
81 r
= route_new(&route_gw
);
83 return log_link_error_errno(link
, r
, "Could not allocate route: %m");
85 /* The dhcp netmask may mask out the gateway. Add an explicit
86 * route for the gw host so that we can route no matter the
87 * netmask or existing kernel route tables. */
88 route_gw
->family
= AF_INET
;
89 route_gw
->dst_addr
.in
= gateway
;
90 route_gw
->dst_prefixlen
= 32;
91 route_gw
->prefsrc_addr
.in
= address
;
92 route_gw
->scope
= RT_SCOPE_LINK
;
93 route_gw
->protocol
= RTPROT_DHCP
;
94 route_gw
->metrics
= link
->network
->dhcp_route_metric
;
96 r
= route_configure(route_gw
, link
, &dhcp4_route_handler
);
98 return log_link_warning_errno(link
, r
, "Could not set host route: %m");
100 link
->dhcp4_messages
++;
102 route
->family
= AF_INET
;
103 route
->in_addr
.in
= gateway
;
104 route
->prefsrc_addr
.in
= address
;
105 route
->metrics
= link
->network
->dhcp_route_metric
;
107 r
= route_configure(route
, link
, &dhcp4_route_handler
);
109 log_link_warning_errno(link
, r
, "Could not set routes: %m");
110 link_enter_failed(link
);
114 link
->dhcp4_messages
++;
117 n
= sd_dhcp_lease_get_routes(link
->dhcp_lease
, &static_routes
);
121 return log_link_warning_errno(link
, n
, "DHCP error: could not get routes: %m");
123 for (i
= 0; i
< n
; i
++) {
124 _cleanup_route_free_ Route
*route
= NULL
;
126 r
= route_new(&route
);
128 return log_link_error_errno(link
, r
, "Could not allocate route: %m");
130 route
->family
= AF_INET
;
131 route
->protocol
= RTPROT_DHCP
;
132 route
->in_addr
.in
= static_routes
[i
].gw_addr
;
133 route
->dst_addr
.in
= static_routes
[i
].dst_addr
;
134 route
->dst_prefixlen
= static_routes
[i
].dst_prefixlen
;
135 route
->metrics
= link
->network
->dhcp_route_metric
;
137 r
= route_configure(route
, link
, &dhcp4_route_handler
);
139 return log_link_warning_errno(link
, r
, "Could not set host route: %m");
141 link
->dhcp4_messages
++;
147 static int dhcp_lease_lost(Link
*link
) {
148 _cleanup_address_free_ Address
*address
= NULL
;
150 struct in_addr netmask
;
151 struct in_addr gateway
;
152 unsigned prefixlen
= 0;
156 assert(link
->dhcp_lease
);
158 log_link_warning(link
, "DHCP lease lost");
160 if (link
->network
->dhcp_routes
) {
161 struct sd_dhcp_route
*routes
;
164 n
= sd_dhcp_lease_get_routes(link
->dhcp_lease
, &routes
);
166 for (i
= 0; i
< n
; i
++) {
167 _cleanup_route_free_ Route
*route
= NULL
;
169 r
= route_new(&route
);
171 route
->family
= AF_INET
;
172 route
->in_addr
.in
= routes
[i
].gw_addr
;
173 route
->dst_addr
.in
= routes
[i
].dst_addr
;
174 route
->dst_prefixlen
= routes
[i
].dst_prefixlen
;
176 route_remove(route
, link
,
177 &link_route_remove_handler
);
183 r
= address_new(&address
);
185 r
= sd_dhcp_lease_get_router(link
->dhcp_lease
, &gateway
);
187 _cleanup_route_free_ Route
*route_gw
= NULL
;
188 _cleanup_route_free_ Route
*route
= NULL
;
190 r
= route_new(&route_gw
);
192 route_gw
->family
= AF_INET
;
193 route_gw
->dst_addr
.in
= gateway
;
194 route_gw
->dst_prefixlen
= 32;
195 route_gw
->scope
= RT_SCOPE_LINK
;
197 route_remove(route_gw
, link
,
198 &link_route_remove_handler
);
201 r
= route_new(&route
);
203 route
->family
= AF_INET
;
204 route
->in_addr
.in
= gateway
;
206 route_remove(route
, link
,
207 &link_route_remove_handler
);
211 r
= sd_dhcp_lease_get_address(link
->dhcp_lease
, &addr
);
213 r
= sd_dhcp_lease_get_netmask(link
->dhcp_lease
, &netmask
);
215 prefixlen
= in_addr_netmask_to_prefixlen(&netmask
);
217 address
->family
= AF_INET
;
218 address
->in_addr
.in
= addr
;
219 address
->prefixlen
= prefixlen
;
221 address_remove(address
, link
, &link_address_remove_handler
);
225 if (link
->network
->dhcp_mtu
) {
228 r
= sd_dhcp_lease_get_mtu(link
->dhcp_lease
, &mtu
);
229 if (r
>= 0 && link
->original_mtu
!= mtu
) {
230 r
= link_set_mtu(link
, link
->original_mtu
);
232 log_link_warning(link
,
233 "DHCP error: could not reset MTU");
234 link_enter_failed(link
);
240 if (link
->network
->dhcp_hostname
) {
241 const char *hostname
= NULL
;
243 if (link
->network
->hostname
)
244 hostname
= link
->network
->hostname
;
246 (void) sd_dhcp_lease_get_hostname(link
->dhcp_lease
, &hostname
);
249 /* If a hostname was set due to the lease, then unset it now. */
250 r
= link_set_hostname(link
, NULL
);
252 log_link_warning_errno(link
, r
, "Failed to reset transient hostname: %m");
256 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
);
334 r
= sd_dhcp_lease_get_address(lease
, &address
);
336 return log_link_warning_errno(link
, r
, "DHCP error: no address: %m");
338 r
= sd_dhcp_lease_get_netmask(lease
, &netmask
);
340 return log_link_warning_errno(link
, r
, "DHCP error: no netmask: %m");
342 if (!link
->network
->dhcp_critical
) {
343 r
= sd_dhcp_lease_get_lifetime(link
->dhcp_lease
, &lifetime
);
345 return log_link_warning_errno(link
, r
, "DHCP error: no lifetime: %m");
348 r
= dhcp4_update_address(link
, &address
, &netmask
, lifetime
);
350 log_link_warning_errno(link
, r
, "Could not update IP address: %m");
351 link_enter_failed(link
);
358 static int dhcp_lease_acquired(sd_dhcp_client
*client
, Link
*link
) {
359 sd_dhcp_lease
*lease
;
360 struct in_addr address
;
361 struct in_addr netmask
;
362 struct in_addr gateway
;
364 uint32_t lifetime
= CACHE_INFO_INFINITY_LIFE_TIME
;
370 r
= sd_dhcp_client_get_lease(client
, &lease
);
372 return log_link_error_errno(link
, r
, "DHCP error: No lease: %m");
374 r
= sd_dhcp_lease_get_address(lease
, &address
);
376 return log_link_error_errno(link
, r
, "DHCP error: No address: %m");
378 r
= sd_dhcp_lease_get_netmask(lease
, &netmask
);
380 return log_link_error_errno(link
, r
, "DHCP error: No netmask: %m");
382 prefixlen
= in_addr_netmask_to_prefixlen(&netmask
);
384 r
= sd_dhcp_lease_get_router(lease
, &gateway
);
385 if (r
< 0 && r
!= -ENODATA
)
386 return log_link_error_errno(link
, r
, "DHCP error: Could not get gateway: %m");
390 LOG_LINK_INTERFACE(link
),
391 LOG_LINK_MESSAGE(link
, "DHCPv4 address %u.%u.%u.%u/%u via %u.%u.%u.%u",
392 ADDRESS_FMT_VAL(address
),
394 ADDRESS_FMT_VAL(gateway
)),
395 "ADDRESS=%u.%u.%u.%u", ADDRESS_FMT_VAL(address
),
396 "PREFIXLEN=%u", prefixlen
,
397 "GATEWAY=%u.%u.%u.%u", ADDRESS_FMT_VAL(gateway
),
401 LOG_LINK_INTERFACE(link
),
402 LOG_LINK_MESSAGE(link
, "DHCPv4 address %u.%u.%u.%u/%u",
403 ADDRESS_FMT_VAL(address
),
405 "ADDRESS=%u.%u.%u.%u", ADDRESS_FMT_VAL(address
),
406 "PREFIXLEN=%u", prefixlen
,
409 link
->dhcp_lease
= sd_dhcp_lease_ref(lease
);
411 if (link
->network
->dhcp_mtu
) {
414 r
= sd_dhcp_lease_get_mtu(lease
, &mtu
);
416 r
= link_set_mtu(link
, mtu
);
418 log_link_error_errno(link
, r
, "Failed to set MTU to %" PRIu16
": %m", mtu
);
422 if (link
->network
->dhcp_hostname
) {
423 const char *hostname
= NULL
;
425 if (link
->network
->hostname
)
426 hostname
= link
->network
->hostname
;
428 (void) sd_dhcp_lease_get_hostname(lease
, &hostname
);
431 r
= link_set_hostname(link
, hostname
);
433 log_link_error_errno(link
, r
, "Failed to set transient hostname to '%s': %m", hostname
);
437 if (link
->network
->dhcp_timezone
) {
438 const char *tz
= NULL
;
440 (void) sd_dhcp_lease_get_timezone(link
->dhcp_lease
, &tz
);
443 r
= link_set_timezone(link
, tz
);
445 log_link_error_errno(link
, r
, "Failed to set timezone to '%s': %m", tz
);
449 if (!link
->network
->dhcp_critical
) {
450 r
= sd_dhcp_lease_get_lifetime(link
->dhcp_lease
, &lifetime
);
452 log_link_warning_errno(link
, r
, "DHCP error: no lifetime: %m");
457 r
= dhcp4_update_address(link
, &address
, &netmask
, lifetime
);
459 log_link_warning_errno(link
, r
, "Could not update IP address: %m");
460 link_enter_failed(link
);
466 static void dhcp4_handler(sd_dhcp_client
*client
, int event
, void *userdata
) {
467 Link
*link
= userdata
;
471 assert(link
->network
);
472 assert(link
->manager
);
474 if (IN_SET(link
->state
, LINK_STATE_FAILED
, LINK_STATE_LINGER
))
478 case SD_DHCP_CLIENT_EVENT_EXPIRED
:
479 case SD_DHCP_CLIENT_EVENT_STOP
:
480 case SD_DHCP_CLIENT_EVENT_IP_CHANGE
:
481 if (link
->network
->dhcp_critical
) {
482 log_link_error(link
, "DHCPv4 connection considered system critical, ignoring request to reconfigure it.");
486 if (link
->dhcp_lease
) {
487 r
= dhcp_lease_lost(link
);
489 link_enter_failed(link
);
494 if (event
== SD_DHCP_CLIENT_EVENT_IP_CHANGE
) {
495 r
= dhcp_lease_acquired(client
, link
);
497 link_enter_failed(link
);
503 case SD_DHCP_CLIENT_EVENT_RENEW
:
504 r
= dhcp_lease_renew(client
, link
);
506 link_enter_failed(link
);
510 case SD_DHCP_CLIENT_EVENT_IP_ACQUIRE
:
511 r
= dhcp_lease_acquired(client
, link
);
513 link_enter_failed(link
);
519 log_link_warning_errno(link
, event
, "DHCP error: Client failed: %m");
521 log_link_warning(link
, "DHCP unknown event: %i", event
);
528 int dhcp4_configure(Link
*link
) {
532 assert(link
->network
);
533 assert(link
->network
->dhcp
& ADDRESS_FAMILY_IPV4
);
535 r
= sd_dhcp_client_new(&link
->dhcp_client
);
539 r
= sd_dhcp_client_attach_event(link
->dhcp_client
, NULL
, 0);
543 r
= sd_dhcp_client_set_mac(link
->dhcp_client
,
544 (const uint8_t *) &link
->mac
,
545 sizeof (link
->mac
), ARPHRD_ETHER
);
549 r
= sd_dhcp_client_set_index(link
->dhcp_client
, link
->ifindex
);
553 r
= sd_dhcp_client_set_callback(link
->dhcp_client
, dhcp4_handler
, link
);
557 r
= sd_dhcp_client_set_request_broadcast(link
->dhcp_client
,
558 link
->network
->dhcp_broadcast
);
563 r
= sd_dhcp_client_set_mtu(link
->dhcp_client
, link
->mtu
);
568 if (link
->network
->dhcp_mtu
) {
569 r
= sd_dhcp_client_set_request_option(link
->dhcp_client
,
570 DHCP_OPTION_INTERFACE_MTU
);
575 if (link
->network
->dhcp_routes
) {
576 r
= sd_dhcp_client_set_request_option(link
->dhcp_client
,
577 DHCP_OPTION_STATIC_ROUTE
);
580 r
= sd_dhcp_client_set_request_option(link
->dhcp_client
,
581 DHCP_OPTION_CLASSLESS_STATIC_ROUTE
);
586 /* Always acquire the timezone and NTP*/
587 r
= sd_dhcp_client_set_request_option(link
->dhcp_client
, DHCP_OPTION_NTP_SERVER
);
591 r
= sd_dhcp_client_set_request_option(link
->dhcp_client
, DHCP_OPTION_NEW_TZDB_TIMEZONE
);
595 if (link
->network
->dhcp_sendhost
) {
596 _cleanup_free_
char *hostname
= NULL
;
597 const char *hn
= NULL
;
599 if (!link
->network
->hostname
) {
600 hostname
= gethostname_malloc();
606 hn
= link
->network
->hostname
;
608 if (!is_localhost(hn
)) {
609 r
= sd_dhcp_client_set_hostname(link
->dhcp_client
, hn
);
615 if (link
->network
->dhcp_vendor_class_identifier
) {
616 r
= sd_dhcp_client_set_vendor_class_identifier(link
->dhcp_client
,
617 link
->network
->dhcp_vendor_class_identifier
);
622 switch (link
->network
->dhcp_client_identifier
) {
623 case DHCP_CLIENT_ID_DUID
:
624 /* Library defaults to this. */
626 case DHCP_CLIENT_ID_MAC
:
627 r
= sd_dhcp_client_set_client_id(link
->dhcp_client
,
629 (const uint8_t *) &link
->mac
,
635 assert_not_reached("Unknown client identifier type.");