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"
28 #include "networkd-manager.h"
29 #include "networkd-network.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 route_scope_from_address(const Route
*route
, const struct in_addr
*self_addr
) {
59 if (in_addr_is_localhost(AF_INET
, &route
->dst
) ||
60 (self_addr
->s_addr
&& route
->dst
.in
.s_addr
== self_addr
->s_addr
))
62 else if (in4_addr_is_null(&route
->gw
.in
))
65 return RT_SCOPE_UNIVERSE
;
68 static int link_set_dhcp_routes(Link
*link
) {
69 struct in_addr gateway
, address
;
70 _cleanup_free_ sd_dhcp_route
**static_routes
= NULL
;
75 if (!link
->dhcp_lease
) /* link went down while we configured the IP addresses? */
78 if (!link
->network
) /* link went down while we configured the IP addresses? */
81 if (!link
->network
->dhcp_use_routes
)
84 r
= sd_dhcp_lease_get_address(link
->dhcp_lease
, &address
);
86 return log_link_warning_errno(link
, r
, "DHCP error: could not get address: %m");
88 r
= sd_dhcp_lease_get_router(link
->dhcp_lease
, &gateway
);
89 if (r
< 0 && r
!= -ENODATA
)
90 return log_link_warning_errno(link
, r
, "DHCP error: could not get gateway: %m");
93 _cleanup_route_free_ Route
*route
= NULL
;
94 _cleanup_route_free_ Route
*route_gw
= NULL
;
96 r
= route_new(&route
);
98 return log_link_error_errno(link
, r
, "Could not allocate route: %m");
100 route
->protocol
= RTPROT_DHCP
;
102 r
= route_new(&route_gw
);
104 return log_link_error_errno(link
, r
, "Could not allocate route: %m");
106 /* The dhcp netmask may mask out the gateway. Add an explicit
107 * route for the gw host so that we can route no matter the
108 * netmask or existing kernel route tables. */
109 route_gw
->family
= AF_INET
;
110 route_gw
->dst
.in
= gateway
;
111 route_gw
->dst_prefixlen
= 32;
112 route_gw
->prefsrc
.in
= address
;
113 route_gw
->scope
= RT_SCOPE_LINK
;
114 route_gw
->protocol
= RTPROT_DHCP
;
115 route_gw
->priority
= link
->network
->dhcp_route_metric
;
116 route_gw
->table
= link
->network
->dhcp_route_table
;
118 r
= route_configure(route_gw
, link
, dhcp4_route_handler
);
120 return log_link_warning_errno(link
, r
, "Could not set host route: %m");
122 link
->dhcp4_messages
++;
124 route
->family
= AF_INET
;
125 route
->gw
.in
= gateway
;
126 route
->prefsrc
.in
= address
;
127 route
->priority
= link
->network
->dhcp_route_metric
;
128 route
->table
= link
->network
->dhcp_route_table
;
130 r
= route_configure(route
, link
, dhcp4_route_handler
);
132 log_link_warning_errno(link
, r
, "Could not set routes: %m");
133 link_enter_failed(link
);
137 link
->dhcp4_messages
++;
140 n
= sd_dhcp_lease_get_routes(link
->dhcp_lease
, &static_routes
);
144 return log_link_warning_errno(link
, n
, "DHCP error: could not get routes: %m");
146 for (i
= 0; i
< n
; i
++) {
147 _cleanup_route_free_ Route
*route
= NULL
;
149 r
= route_new(&route
);
151 return log_link_error_errno(link
, r
, "Could not allocate route: %m");
153 route
->family
= AF_INET
;
154 route
->protocol
= RTPROT_DHCP
;
155 assert_se(sd_dhcp_route_get_gateway(static_routes
[i
], &route
->gw
.in
) >= 0);
156 assert_se(sd_dhcp_route_get_destination(static_routes
[i
], &route
->dst
.in
) >= 0);
157 assert_se(sd_dhcp_route_get_destination_prefix_length(static_routes
[i
], &route
->dst_prefixlen
) >= 0);
158 route
->priority
= link
->network
->dhcp_route_metric
;
159 route
->table
= link
->network
->dhcp_route_table
;
160 route
->scope
= route_scope_from_address(route
, &address
);
162 r
= route_configure(route
, link
, dhcp4_route_handler
);
164 return log_link_warning_errno(link
, r
, "Could not set host route: %m");
166 link
->dhcp4_messages
++;
172 static int dhcp_lease_lost(Link
*link
) {
173 _cleanup_address_free_ Address
*address
= NULL
;
175 struct in_addr netmask
;
176 struct in_addr gateway
;
177 unsigned prefixlen
= 0;
181 assert(link
->dhcp_lease
);
183 log_link_warning(link
, "DHCP lease lost");
185 if (link
->network
->dhcp_use_routes
) {
186 _cleanup_free_ sd_dhcp_route
**routes
= NULL
;
189 n
= sd_dhcp_lease_get_routes(link
->dhcp_lease
, &routes
);
191 for (i
= 0; i
< n
; i
++) {
192 _cleanup_route_free_ Route
*route
= NULL
;
194 r
= route_new(&route
);
196 route
->family
= AF_INET
;
197 assert_se(sd_dhcp_route_get_gateway(routes
[i
], &route
->gw
.in
) >= 0);
198 assert_se(sd_dhcp_route_get_destination(routes
[i
], &route
->dst
.in
) >= 0);
199 assert_se(sd_dhcp_route_get_destination_prefix_length(routes
[i
], &route
->dst_prefixlen
) >= 0);
201 route_remove(route
, link
,
202 link_route_remove_handler
);
208 r
= address_new(&address
);
210 r
= sd_dhcp_lease_get_router(link
->dhcp_lease
, &gateway
);
212 _cleanup_route_free_ Route
*route_gw
= NULL
;
213 _cleanup_route_free_ Route
*route
= NULL
;
215 r
= route_new(&route_gw
);
217 route_gw
->family
= AF_INET
;
218 route_gw
->dst
.in
= gateway
;
219 route_gw
->dst_prefixlen
= 32;
220 route_gw
->scope
= RT_SCOPE_LINK
;
222 route_remove(route_gw
, link
,
223 link_route_remove_handler
);
226 r
= route_new(&route
);
228 route
->family
= AF_INET
;
229 route
->gw
.in
= gateway
;
231 route_remove(route
, link
,
232 link_route_remove_handler
);
236 r
= sd_dhcp_lease_get_address(link
->dhcp_lease
, &addr
);
238 r
= sd_dhcp_lease_get_netmask(link
->dhcp_lease
, &netmask
);
240 prefixlen
= in_addr_netmask_to_prefixlen(&netmask
);
242 address
->family
= AF_INET
;
243 address
->in_addr
.in
= addr
;
244 address
->prefixlen
= prefixlen
;
246 address_remove(address
, link
, link_address_remove_handler
);
250 if (link
->network
->dhcp_use_mtu
) {
253 r
= sd_dhcp_lease_get_mtu(link
->dhcp_lease
, &mtu
);
254 if (r
>= 0 && link
->original_mtu
!= mtu
) {
255 r
= link_set_mtu(link
, link
->original_mtu
);
257 log_link_warning(link
,
258 "DHCP error: could not reset MTU");
259 link_enter_failed(link
);
265 if (link
->network
->dhcp_use_hostname
) {
266 const char *hostname
= NULL
;
268 if (link
->network
->dhcp_hostname
)
269 hostname
= link
->network
->dhcp_hostname
;
271 (void) sd_dhcp_lease_get_hostname(link
->dhcp_lease
, &hostname
);
274 /* If a hostname was set due to the lease, then unset it now. */
275 r
= manager_set_hostname(link
->manager
, NULL
);
277 log_link_warning_errno(link
, r
, "Failed to reset transient hostname: %m");
281 link
->dhcp_lease
= sd_dhcp_lease_unref(link
->dhcp_lease
);
283 link
->dhcp4_configured
= false;
288 static int dhcp4_address_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
,
290 _cleanup_link_unref_ Link
*link
= userdata
;
295 r
= sd_netlink_message_get_errno(m
);
296 if (r
< 0 && r
!= -EEXIST
) {
297 log_link_error_errno(link
, r
, "Could not set DHCPv4 address: %m");
298 link_enter_failed(link
);
300 manager_rtnl_process_address(rtnl
, m
, link
->manager
);
302 link_set_dhcp_routes(link
);
307 static int dhcp4_update_address(Link
*link
,
308 struct in_addr
*address
,
309 struct in_addr
*netmask
,
311 _cleanup_address_free_ Address
*addr
= NULL
;
319 prefixlen
= in_addr_netmask_to_prefixlen(netmask
);
321 r
= address_new(&addr
);
325 addr
->family
= AF_INET
;
326 addr
->in_addr
.in
.s_addr
= address
->s_addr
;
327 addr
->cinfo
.ifa_prefered
= lifetime
;
328 addr
->cinfo
.ifa_valid
= lifetime
;
329 addr
->prefixlen
= prefixlen
;
330 addr
->broadcast
.s_addr
= address
->s_addr
| ~netmask
->s_addr
;
332 /* allow reusing an existing address and simply update its lifetime
333 * in case it already exists */
334 r
= address_configure(addr
, link
, dhcp4_address_handler
, true);
341 static int dhcp_lease_renew(sd_dhcp_client
*client
, Link
*link
) {
342 sd_dhcp_lease
*lease
;
343 struct in_addr address
;
344 struct in_addr netmask
;
345 uint32_t lifetime
= CACHE_INFO_INFINITY_LIFE_TIME
;
350 assert(link
->network
);
352 r
= sd_dhcp_client_get_lease(client
, &lease
);
354 return log_link_warning_errno(link
, r
, "DHCP error: no lease: %m");
356 sd_dhcp_lease_unref(link
->dhcp_lease
);
357 link
->dhcp4_configured
= false;
358 link
->dhcp_lease
= sd_dhcp_lease_ref(lease
);
361 r
= sd_dhcp_lease_get_address(lease
, &address
);
363 return log_link_warning_errno(link
, r
, "DHCP error: no address: %m");
365 r
= sd_dhcp_lease_get_netmask(lease
, &netmask
);
367 return log_link_warning_errno(link
, r
, "DHCP error: no netmask: %m");
369 if (!link
->network
->dhcp_critical
) {
370 r
= sd_dhcp_lease_get_lifetime(link
->dhcp_lease
, &lifetime
);
372 return log_link_warning_errno(link
, r
, "DHCP error: no lifetime: %m");
375 r
= dhcp4_update_address(link
, &address
, &netmask
, lifetime
);
377 log_link_warning_errno(link
, r
, "Could not update IP address: %m");
378 link_enter_failed(link
);
385 static int dhcp_lease_acquired(sd_dhcp_client
*client
, Link
*link
) {
386 sd_dhcp_lease
*lease
;
387 struct in_addr address
;
388 struct in_addr netmask
;
389 struct in_addr gateway
;
391 uint32_t lifetime
= CACHE_INFO_INFINITY_LIFE_TIME
;
397 r
= sd_dhcp_client_get_lease(client
, &lease
);
399 return log_link_error_errno(link
, r
, "DHCP error: No lease: %m");
401 r
= sd_dhcp_lease_get_address(lease
, &address
);
403 return log_link_error_errno(link
, r
, "DHCP error: No address: %m");
405 r
= sd_dhcp_lease_get_netmask(lease
, &netmask
);
407 return log_link_error_errno(link
, r
, "DHCP error: No netmask: %m");
409 prefixlen
= in_addr_netmask_to_prefixlen(&netmask
);
411 r
= sd_dhcp_lease_get_router(lease
, &gateway
);
412 if (r
< 0 && r
!= -ENODATA
)
413 return log_link_error_errno(link
, r
, "DHCP error: Could not get gateway: %m");
417 LOG_LINK_INTERFACE(link
),
418 LOG_LINK_MESSAGE(link
, "DHCPv4 address %u.%u.%u.%u/%u via %u.%u.%u.%u",
419 ADDRESS_FMT_VAL(address
),
421 ADDRESS_FMT_VAL(gateway
)),
422 "ADDRESS=%u.%u.%u.%u", ADDRESS_FMT_VAL(address
),
423 "PREFIXLEN=%u", prefixlen
,
424 "GATEWAY=%u.%u.%u.%u", ADDRESS_FMT_VAL(gateway
),
428 LOG_LINK_INTERFACE(link
),
429 LOG_LINK_MESSAGE(link
, "DHCPv4 address %u.%u.%u.%u/%u",
430 ADDRESS_FMT_VAL(address
),
432 "ADDRESS=%u.%u.%u.%u", ADDRESS_FMT_VAL(address
),
433 "PREFIXLEN=%u", prefixlen
,
436 link
->dhcp_lease
= sd_dhcp_lease_ref(lease
);
439 if (link
->network
->dhcp_use_mtu
) {
442 r
= sd_dhcp_lease_get_mtu(lease
, &mtu
);
444 r
= link_set_mtu(link
, mtu
);
446 log_link_error_errno(link
, r
, "Failed to set MTU to %" PRIu16
": %m", mtu
);
450 if (link
->network
->dhcp_use_hostname
) {
451 const char *hostname
= NULL
;
453 if (link
->network
->dhcp_hostname
)
454 hostname
= link
->network
->dhcp_hostname
;
456 (void) sd_dhcp_lease_get_hostname(lease
, &hostname
);
459 r
= manager_set_hostname(link
->manager
, hostname
);
461 log_link_error_errno(link
, r
, "Failed to set transient hostname to '%s': %m", hostname
);
465 if (link
->network
->dhcp_use_timezone
) {
466 const char *tz
= NULL
;
468 (void) sd_dhcp_lease_get_timezone(link
->dhcp_lease
, &tz
);
471 r
= manager_set_timezone(link
->manager
, tz
);
473 log_link_error_errno(link
, r
, "Failed to set timezone to '%s': %m", tz
);
477 if (!link
->network
->dhcp_critical
) {
478 r
= sd_dhcp_lease_get_lifetime(link
->dhcp_lease
, &lifetime
);
480 log_link_warning_errno(link
, r
, "DHCP error: no lifetime: %m");
485 r
= dhcp4_update_address(link
, &address
, &netmask
, lifetime
);
487 log_link_warning_errno(link
, r
, "Could not update IP address: %m");
488 link_enter_failed(link
);
494 static void dhcp4_handler(sd_dhcp_client
*client
, int event
, void *userdata
) {
495 Link
*link
= userdata
;
499 assert(link
->network
);
500 assert(link
->manager
);
502 if (IN_SET(link
->state
, LINK_STATE_FAILED
, LINK_STATE_LINGER
))
506 case SD_DHCP_CLIENT_EVENT_EXPIRED
:
507 case SD_DHCP_CLIENT_EVENT_STOP
:
508 case SD_DHCP_CLIENT_EVENT_IP_CHANGE
:
509 if (link
->network
->dhcp_critical
) {
510 log_link_error(link
, "DHCPv4 connection considered system critical, ignoring request to reconfigure it.");
514 if (link
->dhcp_lease
) {
515 r
= dhcp_lease_lost(link
);
517 link_enter_failed(link
);
522 if (event
== SD_DHCP_CLIENT_EVENT_IP_CHANGE
) {
523 r
= dhcp_lease_acquired(client
, link
);
525 link_enter_failed(link
);
531 case SD_DHCP_CLIENT_EVENT_RENEW
:
532 r
= dhcp_lease_renew(client
, link
);
534 link_enter_failed(link
);
538 case SD_DHCP_CLIENT_EVENT_IP_ACQUIRE
:
539 r
= dhcp_lease_acquired(client
, link
);
541 link_enter_failed(link
);
547 log_link_warning_errno(link
, event
, "DHCP error: Client failed: %m");
549 log_link_warning(link
, "DHCP unknown event: %i", event
);
556 static int dhcp4_set_hostname(Link
*link
) {
557 _cleanup_free_
char *hostname
= NULL
;
563 if (!link
->network
->dhcp_send_hostname
)
565 else if (link
->network
->dhcp_hostname
)
566 hn
= link
->network
->dhcp_hostname
;
568 r
= gethostname_strict(&hostname
);
569 if (r
< 0 && r
!= -ENXIO
) /* ENXIO: no hostname set or hostname is "localhost" */
575 return sd_dhcp_client_set_hostname(link
->dhcp_client
, hn
);
578 int dhcp4_configure(Link
*link
) {
582 assert(link
->network
);
583 assert(link
->network
->dhcp
& ADDRESS_FAMILY_IPV4
);
585 if (!link
->dhcp_client
) {
586 r
= sd_dhcp_client_new(&link
->dhcp_client
);
591 r
= sd_dhcp_client_attach_event(link
->dhcp_client
, NULL
, 0);
595 r
= sd_dhcp_client_set_mac(link
->dhcp_client
,
596 (const uint8_t *) &link
->mac
,
597 sizeof (link
->mac
), ARPHRD_ETHER
);
601 r
= sd_dhcp_client_set_ifindex(link
->dhcp_client
, link
->ifindex
);
605 r
= sd_dhcp_client_set_callback(link
->dhcp_client
, dhcp4_handler
, link
);
609 r
= sd_dhcp_client_set_request_broadcast(link
->dhcp_client
,
610 link
->network
->dhcp_broadcast
);
615 r
= sd_dhcp_client_set_mtu(link
->dhcp_client
, link
->mtu
);
620 if (link
->network
->dhcp_use_mtu
) {
621 r
= sd_dhcp_client_set_request_option(link
->dhcp_client
,
622 SD_DHCP_OPTION_INTERFACE_MTU
);
627 if (link
->network
->dhcp_use_routes
) {
628 r
= sd_dhcp_client_set_request_option(link
->dhcp_client
,
629 SD_DHCP_OPTION_STATIC_ROUTE
);
632 r
= sd_dhcp_client_set_request_option(link
->dhcp_client
,
633 SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE
);
638 /* Always acquire the timezone and NTP */
639 r
= sd_dhcp_client_set_request_option(link
->dhcp_client
, SD_DHCP_OPTION_NTP_SERVER
);
643 r
= sd_dhcp_client_set_request_option(link
->dhcp_client
, SD_DHCP_OPTION_NEW_TZDB_TIMEZONE
);
647 r
= dhcp4_set_hostname(link
);
651 if (link
->network
->dhcp_vendor_class_identifier
) {
652 r
= sd_dhcp_client_set_vendor_class_identifier(link
->dhcp_client
,
653 link
->network
->dhcp_vendor_class_identifier
);
658 if (link
->network
->dhcp_client_port
) {
659 r
= sd_dhcp_client_set_client_port(link
->dhcp_client
, link
->network
->dhcp_client_port
);
664 switch (link
->network
->dhcp_client_identifier
) {
665 case DHCP_CLIENT_ID_DUID
: {
666 /* If configured, apply user specified DUID and/or IAID */
667 const DUID
*duid
= link_duid(link
);
669 r
= sd_dhcp_client_set_iaid_duid(link
->dhcp_client
,
672 duid
->raw_data_len
> 0 ? duid
->raw_data
: NULL
,
678 case DHCP_CLIENT_ID_MAC
:
679 r
= sd_dhcp_client_set_client_id(link
->dhcp_client
,
681 (const uint8_t *) &link
->mac
,
687 assert_not_reached("Unknown client identifier type.");