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_client_handler(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
!= -ENOENT
)
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_dynamic(&route
, RTPROT_DHCP
);
77 return log_link_error_errno(link
, r
, "Could not allocate route: %m");
79 r
= route_new_dynamic(&route_gw
, RTPROT_DHCP
);
81 return log_link_error_errno(link
, r
, "Could not allocate route: %m");
83 /* The dhcp netmask may mask out the gateway. Add an explicit
84 * route for the gw host so that we can route no matter the
85 * netmask or existing kernel route tables. */
86 route_gw
->family
= AF_INET
;
87 route_gw
->dst_addr
.in
= gateway
;
88 route_gw
->dst_prefixlen
= 32;
89 route_gw
->prefsrc_addr
.in
= address
;
90 route_gw
->scope
= RT_SCOPE_LINK
;
91 route_gw
->metrics
= link
->network
->dhcp_route_metric
;
93 r
= route_configure(route_gw
, link
, &dhcp4_route_handler
);
95 return log_link_warning_errno(link
, r
, "Could not set host route: %m");
97 link
->dhcp4_messages
++;
99 route
->family
= AF_INET
;
100 route
->in_addr
.in
= gateway
;
101 route
->prefsrc_addr
.in
= address
;
102 route
->metrics
= link
->network
->dhcp_route_metric
;
104 r
= route_configure(route
, link
, &dhcp4_route_handler
);
106 log_link_warning_errno(link
, r
, "Could not set routes: %m");
107 link_enter_failed(link
);
111 link
->dhcp4_messages
++;
114 n
= sd_dhcp_lease_get_routes(link
->dhcp_lease
, &static_routes
);
118 return log_link_warning_errno(link
, n
, "DHCP error: could not get routes: %m");
120 for (i
= 0; i
< n
; i
++) {
121 _cleanup_route_free_ Route
*route
= NULL
;
123 r
= route_new_dynamic(&route
, RTPROT_DHCP
);
125 return log_link_error_errno(link
, r
, "Could not allocate route: %m");
127 route
->family
= AF_INET
;
128 route
->in_addr
.in
= static_routes
[i
].gw_addr
;
129 route
->dst_addr
.in
= static_routes
[i
].dst_addr
;
130 route
->dst_prefixlen
= static_routes
[i
].dst_prefixlen
;
131 route
->metrics
= link
->network
->dhcp_route_metric
;
133 r
= route_configure(route
, link
, &dhcp4_route_handler
);
135 return log_link_warning_errno(link
, r
, "Could not set host route: %m");
137 link
->dhcp4_messages
++;
143 static int dhcp_lease_lost(Link
*link
) {
144 _cleanup_address_free_ Address
*address
= NULL
;
146 struct in_addr netmask
;
147 struct in_addr gateway
;
148 unsigned prefixlen
= 0;
152 assert(link
->dhcp_lease
);
154 log_link_warning(link
, "DHCP lease lost");
156 if (link
->network
->dhcp_routes
) {
157 struct sd_dhcp_route
*routes
;
160 n
= sd_dhcp_lease_get_routes(link
->dhcp_lease
, &routes
);
162 for (i
= 0; i
< n
; i
++) {
163 _cleanup_route_free_ Route
*route
= NULL
;
165 r
= route_new_dynamic(&route
, RTPROT_UNSPEC
);
167 route
->family
= AF_INET
;
168 route
->in_addr
.in
= routes
[i
].gw_addr
;
169 route
->dst_addr
.in
= routes
[i
].dst_addr
;
170 route
->dst_prefixlen
= routes
[i
].dst_prefixlen
;
172 route_drop(route
, link
,
173 &link_route_drop_handler
);
179 r
= address_new_dynamic(&address
);
181 r
= sd_dhcp_lease_get_router(link
->dhcp_lease
, &gateway
);
183 _cleanup_route_free_ Route
*route_gw
= NULL
;
184 _cleanup_route_free_ Route
*route
= NULL
;
186 r
= route_new_dynamic(&route_gw
, RTPROT_UNSPEC
);
188 route_gw
->family
= AF_INET
;
189 route_gw
->dst_addr
.in
= gateway
;
190 route_gw
->dst_prefixlen
= 32;
191 route_gw
->scope
= RT_SCOPE_LINK
;
193 route_drop(route_gw
, link
,
194 &link_route_drop_handler
);
197 r
= route_new_dynamic(&route
, RTPROT_UNSPEC
);
199 route
->family
= AF_INET
;
200 route
->in_addr
.in
= gateway
;
202 route_drop(route
, link
,
203 &link_route_drop_handler
);
207 r
= sd_dhcp_lease_get_address(link
->dhcp_lease
, &addr
);
209 r
= sd_dhcp_lease_get_netmask(link
->dhcp_lease
, &netmask
);
211 prefixlen
= in_addr_netmask_to_prefixlen(&netmask
);
213 address
->family
= AF_INET
;
214 address
->in_addr
.in
= addr
;
215 address
->prefixlen
= prefixlen
;
217 address_drop(address
, link
, &link_address_drop_handler
);
221 if (link
->network
->dhcp_mtu
) {
224 r
= sd_dhcp_lease_get_mtu(link
->dhcp_lease
, &mtu
);
225 if (r
>= 0 && link
->original_mtu
!= mtu
) {
226 r
= link_set_mtu(link
, link
->original_mtu
);
228 log_link_warning(link
,
229 "DHCP error: could not reset MTU");
230 link_enter_failed(link
);
236 if (link
->network
->dhcp_hostname
) {
237 const char *hostname
= NULL
;
239 if (link
->network
->hostname
)
240 hostname
= link
->network
->hostname
;
242 (void) sd_dhcp_lease_get_hostname(link
->dhcp_lease
, &hostname
);
245 /* If a hostname was set due to the lease, then unset it now. */
246 r
= link_set_hostname(link
, NULL
);
248 log_link_warning_errno(link
, r
, "Failed to reset transient hostname: %m");
252 link
->dhcp_lease
= sd_dhcp_lease_unref(link
->dhcp_lease
);
253 link
->dhcp4_configured
= false;
258 static int dhcp4_address_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
,
260 _cleanup_link_unref_ Link
*link
= userdata
;
265 r
= sd_netlink_message_get_errno(m
);
266 if (r
< 0 && r
!= -EEXIST
) {
267 log_link_error_errno(link
, r
, "Could not set DHCPv4 address: %m");
268 link_enter_failed(link
);
270 link_rtnl_process_address(rtnl
, m
, link
->manager
);
272 link_set_dhcp_routes(link
);
277 static int dhcp4_update_address(Link
*link
,
278 struct in_addr
*address
,
279 struct in_addr
*netmask
,
281 _cleanup_address_free_ Address
*addr
= NULL
;
289 prefixlen
= in_addr_netmask_to_prefixlen(netmask
);
291 r
= address_new_dynamic(&addr
);
295 addr
->family
= AF_INET
;
296 addr
->in_addr
.in
.s_addr
= address
->s_addr
;
297 addr
->cinfo
.ifa_prefered
= lifetime
;
298 addr
->cinfo
.ifa_valid
= lifetime
;
299 addr
->prefixlen
= prefixlen
;
300 addr
->broadcast
.s_addr
= address
->s_addr
| ~netmask
->s_addr
;
302 /* use update rather than configure so that we will update the
303 * lifetime of an existing address if it has already been configured */
304 r
= address_update(addr
, link
, &dhcp4_address_handler
);
311 static int dhcp_lease_renew(sd_dhcp_client
*client
, Link
*link
) {
312 sd_dhcp_lease
*lease
;
313 struct in_addr address
;
314 struct in_addr netmask
;
315 uint32_t lifetime
= CACHE_INFO_INFINITY_LIFE_TIME
;
320 assert(link
->network
);
322 r
= sd_dhcp_client_get_lease(client
, &lease
);
324 return log_link_warning_errno(link
, r
, "DHCP error: no lease: %m");
326 sd_dhcp_lease_unref(link
->dhcp_lease
);
327 link
->dhcp4_configured
= false;
328 link
->dhcp_lease
= sd_dhcp_lease_ref(lease
);
330 r
= sd_dhcp_lease_get_address(lease
, &address
);
332 return log_link_warning_errno(link
, r
, "DHCP error: no address: %m");
334 r
= sd_dhcp_lease_get_netmask(lease
, &netmask
);
336 return log_link_warning_errno(link
, r
, "DHCP error: no netmask: %m");
338 if (!link
->network
->dhcp_critical
) {
339 r
= sd_dhcp_lease_get_lifetime(link
->dhcp_lease
, &lifetime
);
341 return log_link_warning_errno(link
, r
, "DHCP error: no lifetime: %m");
344 r
= dhcp4_update_address(link
, &address
, &netmask
, lifetime
);
346 log_link_warning_errno(link
, r
, "Could not update IP address: %m");
347 link_enter_failed(link
);
354 static int dhcp_lease_acquired(sd_dhcp_client
*client
, Link
*link
) {
355 sd_dhcp_lease
*lease
;
356 struct in_addr address
;
357 struct in_addr netmask
;
358 struct in_addr gateway
;
360 uint32_t lifetime
= CACHE_INFO_INFINITY_LIFE_TIME
;
366 r
= sd_dhcp_client_get_lease(client
, &lease
);
368 return log_link_error_errno(link
, r
, "DHCP error: No lease: %m");
370 r
= sd_dhcp_lease_get_address(lease
, &address
);
372 return log_link_error_errno(link
, r
, "DHCP error: No address: %m");
374 r
= sd_dhcp_lease_get_netmask(lease
, &netmask
);
376 return log_link_error_errno(link
, r
, "DHCP error: No netmask: %m");
378 prefixlen
= in_addr_netmask_to_prefixlen(&netmask
);
380 r
= sd_dhcp_lease_get_router(lease
, &gateway
);
381 if (r
< 0 && r
!= -ENOENT
)
382 return log_link_error_errno(link
, r
, "DHCP error: Could not get gateway: %m");
386 LOG_LINK_INTERFACE(link
),
387 LOG_LINK_MESSAGE(link
, "DHCPv4 address %u.%u.%u.%u/%u via %u.%u.%u.%u",
388 ADDRESS_FMT_VAL(address
),
390 ADDRESS_FMT_VAL(gateway
)),
391 "ADDRESS=%u.%u.%u.%u", ADDRESS_FMT_VAL(address
),
392 "PREFIXLEN=%u", prefixlen
,
393 "GATEWAY=%u.%u.%u.%u", ADDRESS_FMT_VAL(gateway
),
397 LOG_LINK_INTERFACE(link
),
398 LOG_LINK_MESSAGE(link
, "DHCPv4 address %u.%u.%u.%u/%u",
399 ADDRESS_FMT_VAL(address
),
401 "ADDRESS=%u.%u.%u.%u", ADDRESS_FMT_VAL(address
),
402 "PREFIXLEN=%u", prefixlen
,
405 link
->dhcp_lease
= sd_dhcp_lease_ref(lease
);
407 if (link
->network
->dhcp_mtu
) {
410 r
= sd_dhcp_lease_get_mtu(lease
, &mtu
);
412 r
= link_set_mtu(link
, mtu
);
414 log_link_error_errno(link
, r
, "Failed to set MTU to %" PRIu16
": %m", mtu
);
418 if (link
->network
->dhcp_hostname
) {
419 const char *hostname
= NULL
;
421 if (link
->network
->hostname
)
422 hostname
= link
->network
->hostname
;
424 (void) sd_dhcp_lease_get_hostname(lease
, &hostname
);
427 r
= link_set_hostname(link
, hostname
);
429 log_link_error_errno(link
, r
, "Failed to set transient hostname to '%s': %m", hostname
);
433 if (link
->network
->dhcp_timezone
) {
434 const char *tz
= NULL
;
436 (void) sd_dhcp_lease_get_timezone(link
->dhcp_lease
, &tz
);
439 r
= link_set_timezone(link
, tz
);
441 log_link_error_errno(link
, r
, "Failed to set timezone to '%s': %m", tz
);
445 if (!link
->network
->dhcp_critical
) {
446 r
= sd_dhcp_lease_get_lifetime(link
->dhcp_lease
, &lifetime
);
448 log_link_warning_errno(link
, r
, "DHCP error: no lifetime: %m");
453 r
= dhcp4_update_address(link
, &address
, &netmask
, lifetime
);
455 log_link_warning_errno(link
, r
, "Could not update IP address: %m");
456 link_enter_failed(link
);
462 static void dhcp4_handler(sd_dhcp_client
*client
, int event
, void *userdata
) {
463 Link
*link
= userdata
;
467 assert(link
->network
);
468 assert(link
->manager
);
470 if (IN_SET(link
->state
, LINK_STATE_FAILED
, LINK_STATE_LINGER
))
474 case DHCP_EVENT_EXPIRED
:
475 case DHCP_EVENT_STOP
:
476 case DHCP_EVENT_IP_CHANGE
:
477 if (link
->network
->dhcp_critical
) {
478 log_link_error(link
, "DHCPv4 connection considered system critical, ignoring request to reconfigure it.");
482 if (link
->dhcp_lease
) {
483 r
= dhcp_lease_lost(link
);
485 link_enter_failed(link
);
490 if (event
== DHCP_EVENT_IP_CHANGE
) {
491 r
= dhcp_lease_acquired(client
, link
);
493 link_enter_failed(link
);
499 case DHCP_EVENT_RENEW
:
500 r
= dhcp_lease_renew(client
, link
);
502 link_enter_failed(link
);
506 case DHCP_EVENT_IP_ACQUIRE
:
507 r
= dhcp_lease_acquired(client
, link
);
509 link_enter_failed(link
);
515 log_link_warning_errno(link
, event
, "DHCP error: Client failed: %m");
517 log_link_warning(link
, "DHCP unknown event: %i", event
);
524 int dhcp4_configure(Link
*link
) {
528 assert(link
->network
);
529 assert(link
->network
->dhcp
& ADDRESS_FAMILY_IPV4
);
531 r
= sd_dhcp_client_new(&link
->dhcp_client
);
535 r
= sd_dhcp_client_attach_event(link
->dhcp_client
, NULL
, 0);
539 r
= sd_dhcp_client_set_mac(link
->dhcp_client
,
540 (const uint8_t *) &link
->mac
,
541 sizeof (link
->mac
), ARPHRD_ETHER
);
545 r
= sd_dhcp_client_set_index(link
->dhcp_client
, link
->ifindex
);
549 r
= sd_dhcp_client_set_callback(link
->dhcp_client
, dhcp4_handler
, link
);
553 r
= sd_dhcp_client_set_request_broadcast(link
->dhcp_client
,
554 link
->network
->dhcp_broadcast
);
559 r
= sd_dhcp_client_set_mtu(link
->dhcp_client
, link
->mtu
);
564 if (link
->network
->dhcp_mtu
) {
565 r
= sd_dhcp_client_set_request_option(link
->dhcp_client
,
566 DHCP_OPTION_INTERFACE_MTU
);
571 if (link
->network
->dhcp_routes
) {
572 r
= sd_dhcp_client_set_request_option(link
->dhcp_client
,
573 DHCP_OPTION_STATIC_ROUTE
);
576 r
= sd_dhcp_client_set_request_option(link
->dhcp_client
,
577 DHCP_OPTION_CLASSLESS_STATIC_ROUTE
);
582 /* Always acquire the timezone and NTP*/
583 r
= sd_dhcp_client_set_request_option(link
->dhcp_client
, DHCP_OPTION_NTP_SERVER
);
587 r
= sd_dhcp_client_set_request_option(link
->dhcp_client
, DHCP_OPTION_NEW_TZDB_TIMEZONE
);
591 if (link
->network
->dhcp_sendhost
) {
592 _cleanup_free_
char *hostname
= NULL
;
593 const char *hn
= NULL
;
595 if (!link
->network
->hostname
) {
596 hostname
= gethostname_malloc();
602 hn
= link
->network
->hostname
;
604 if (!is_localhost(hn
)) {
605 r
= sd_dhcp_client_set_hostname(link
->dhcp_client
, hn
);
611 if (link
->network
->dhcp_vendor_class_identifier
) {
612 r
= sd_dhcp_client_set_vendor_class_identifier(link
->dhcp_client
,
613 link
->network
->dhcp_vendor_class_identifier
);
618 switch (link
->network
->dhcp_client_identifier
) {
619 case DHCP_CLIENT_ID_DUID
:
620 /* Library defaults to this. */
622 case DHCP_CLIENT_ID_MAC
:
623 r
= sd_dhcp_client_set_client_id(link
->dhcp_client
,
625 (const uint8_t *) &link
->mac
,
631 assert_not_reached("Unknown client identifier type.");