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(link
, "could not set DHCPv4 route: %s",
44 link_enter_failed(link
);
47 if (!link
->dhcp4_messages
) {
48 link
->dhcp4_configured
= true;
49 link_client_handler(link
);
55 static int link_set_dhcp_routes(Link
*link
) {
56 struct in_addr gateway
;
57 struct sd_dhcp_route
*static_routes
;
61 assert(link
->dhcp_lease
);
63 r
= sd_dhcp_lease_get_router(link
->dhcp_lease
, &gateway
);
64 if (r
< 0 && r
!= -ENOENT
) {
65 log_link_warning(link
,
66 "DHCP error: could not get gateway: %s",
71 struct in_addr address
;
72 _cleanup_route_free_ Route
*route
= NULL
;
73 _cleanup_route_free_ Route
*route_gw
= NULL
;
75 r
= sd_dhcp_lease_get_address(link
->dhcp_lease
, &address
);
77 log_link_warning(link
,
78 "DHCP error: could not get address: %s",
83 r
= route_new_dynamic(&route
, RTPROT_DHCP
);
86 "Could not allocate route: %s",
91 r
= route_new_dynamic(&route_gw
, RTPROT_DHCP
);
94 "Could not allocate route: %s",
99 /* The dhcp netmask may mask out the gateway. Add an explicit
100 * route for the gw host so that we can route no matter the
101 * netmask or existing kernel route tables. */
102 route_gw
->family
= AF_INET
;
103 route_gw
->dst_addr
.in
= gateway
;
104 route_gw
->dst_prefixlen
= 32;
105 route_gw
->prefsrc_addr
.in
= address
;
106 route_gw
->scope
= RT_SCOPE_LINK
;
107 route_gw
->metrics
= link
->network
->dhcp_route_metric
;
109 r
= route_configure(route_gw
, link
, &dhcp4_route_handler
);
111 log_link_warning(link
,
112 "could not set host route: %s",
117 link
->dhcp4_messages
++;
119 route
->family
= AF_INET
;
120 route
->in_addr
.in
= gateway
;
121 route
->prefsrc_addr
.in
= address
;
122 route
->metrics
= link
->network
->dhcp_route_metric
;
124 r
= route_configure(route
, link
, &dhcp4_route_handler
);
126 log_link_warning(link
,
127 "could not set routes: %s",
129 link_enter_failed(link
);
133 link
->dhcp4_messages
++;
136 n
= sd_dhcp_lease_get_routes(link
->dhcp_lease
, &static_routes
);
140 log_link_warning(link
,
141 "DHCP error: could not get routes: %s",
147 for (i
= 0; i
< n
; i
++) {
148 _cleanup_route_free_ Route
*route
= NULL
;
150 r
= route_new_dynamic(&route
, RTPROT_DHCP
);
152 log_link_error(link
, "Could not allocate route: %s",
157 route
->family
= AF_INET
;
158 route
->in_addr
.in
= static_routes
[i
].gw_addr
;
159 route
->dst_addr
.in
= static_routes
[i
].dst_addr
;
160 route
->dst_prefixlen
= static_routes
[i
].dst_prefixlen
;
161 route
->metrics
= link
->network
->dhcp_route_metric
;
163 r
= route_configure(route
, link
, &dhcp4_route_handler
);
165 log_link_warning(link
,
166 "could not set host route: %s",
171 link
->dhcp4_messages
++;
177 static int dhcp_lease_lost(Link
*link
) {
178 _cleanup_address_free_ Address
*address
= NULL
;
180 struct in_addr netmask
;
181 struct in_addr gateway
;
182 unsigned prefixlen
= 0;
186 assert(link
->dhcp_lease
);
188 log_link_warning(link
, "DHCP lease lost");
190 if (link
->network
->dhcp_routes
) {
191 struct sd_dhcp_route
*routes
;
194 n
= sd_dhcp_lease_get_routes(link
->dhcp_lease
, &routes
);
196 for (i
= 0; i
< n
; i
++) {
197 _cleanup_route_free_ Route
*route
= NULL
;
199 r
= route_new_dynamic(&route
, RTPROT_UNSPEC
);
201 route
->family
= AF_INET
;
202 route
->in_addr
.in
= routes
[i
].gw_addr
;
203 route
->dst_addr
.in
= routes
[i
].dst_addr
;
204 route
->dst_prefixlen
= routes
[i
].dst_prefixlen
;
206 route_drop(route
, link
,
207 &link_route_drop_handler
);
213 r
= address_new_dynamic(&address
);
215 r
= sd_dhcp_lease_get_router(link
->dhcp_lease
, &gateway
);
217 _cleanup_route_free_ Route
*route_gw
= NULL
;
218 _cleanup_route_free_ Route
*route
= NULL
;
220 r
= route_new_dynamic(&route_gw
, RTPROT_UNSPEC
);
222 route_gw
->family
= AF_INET
;
223 route_gw
->dst_addr
.in
= gateway
;
224 route_gw
->dst_prefixlen
= 32;
225 route_gw
->scope
= RT_SCOPE_LINK
;
227 route_drop(route_gw
, link
,
228 &link_route_drop_handler
);
231 r
= route_new_dynamic(&route
, RTPROT_UNSPEC
);
233 route
->family
= AF_INET
;
234 route
->in_addr
.in
= gateway
;
236 route_drop(route
, link
,
237 &link_route_drop_handler
);
241 r
= sd_dhcp_lease_get_address(link
->dhcp_lease
, &addr
);
243 r
= sd_dhcp_lease_get_netmask(link
->dhcp_lease
, &netmask
);
245 prefixlen
= in_addr_netmask_to_prefixlen(&netmask
);
247 address
->family
= AF_INET
;
248 address
->in_addr
.in
= addr
;
249 address
->prefixlen
= prefixlen
;
251 address_drop(address
, link
, &link_address_drop_handler
);
255 if (link
->network
->dhcp_mtu
) {
258 r
= sd_dhcp_lease_get_mtu(link
->dhcp_lease
, &mtu
);
259 if (r
>= 0 && link
->original_mtu
!= mtu
) {
260 r
= link_set_mtu(link
, link
->original_mtu
);
262 log_link_warning(link
,
263 "DHCP error: could not reset MTU");
264 link_enter_failed(link
);
270 if (link
->network
->dhcp_hostname
) {
271 const char *hostname
= NULL
;
273 if (!link
->network
->hostname
)
274 r
= sd_dhcp_lease_get_hostname(link
->dhcp_lease
, &hostname
);
276 hostname
= link
->network
->hostname
;
278 if (r
>= 0 || hostname
) {
279 r
= link_set_hostname(link
, hostname
);
281 log_link_error_errno(link
, r
,
282 "Failed to set transient hostname to '%s': %m",
288 link
->dhcp_lease
= sd_dhcp_lease_unref(link
->dhcp_lease
);
289 link
->dhcp4_configured
= false;
294 static int dhcp4_address_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
,
296 _cleanup_link_unref_ Link
*link
= userdata
;
301 r
= sd_netlink_message_get_errno(m
);
302 if (r
< 0 && r
!= -EEXIST
) {
303 log_link_error(link
, "could not set DHCPv4 address: %s",
305 link_enter_failed(link
);
307 link_rtnl_process_address(rtnl
, m
, link
->manager
);
309 link_set_dhcp_routes(link
);
314 static int dhcp4_update_address(Link
*link
,
315 struct in_addr
*address
,
316 struct in_addr
*netmask
,
318 _cleanup_address_free_ Address
*addr
= NULL
;
326 prefixlen
= in_addr_netmask_to_prefixlen(netmask
);
328 r
= address_new_dynamic(&addr
);
332 addr
->family
= AF_INET
;
333 addr
->in_addr
.in
.s_addr
= address
->s_addr
;
334 addr
->cinfo
.ifa_prefered
= lifetime
;
335 addr
->cinfo
.ifa_valid
= lifetime
;
336 addr
->prefixlen
= prefixlen
;
337 addr
->broadcast
.s_addr
= address
->s_addr
| ~netmask
->s_addr
;
339 /* use update rather than configure so that we will update the
340 * lifetime of an existing address if it has already been configured */
341 r
= address_update(addr
, link
, &dhcp4_address_handler
);
348 static int dhcp_lease_renew(sd_dhcp_client
*client
, Link
*link
) {
349 sd_dhcp_lease
*lease
;
350 struct in_addr address
;
351 struct in_addr netmask
;
352 uint32_t lifetime
= CACHE_INFO_INFINITY_LIFE_TIME
;
357 assert(link
->network
);
359 r
= sd_dhcp_client_get_lease(client
, &lease
);
361 log_link_warning(link
, "DHCP error: no lease %s",
366 sd_dhcp_lease_unref(link
->dhcp_lease
);
367 link
->dhcp4_configured
= false;
368 link
->dhcp_lease
= lease
;
370 r
= sd_dhcp_lease_get_address(lease
, &address
);
372 log_link_warning(link
, "DHCP error: no address: %s",
377 r
= sd_dhcp_lease_get_netmask(lease
, &netmask
);
379 log_link_warning(link
, "DHCP error: no netmask: %s",
384 if (!link
->network
->dhcp_critical
) {
385 r
= sd_dhcp_lease_get_lifetime(link
->dhcp_lease
,
388 log_link_warning(link
,
389 "DHCP error: no lifetime: %s",
395 r
= dhcp4_update_address(link
, &address
, &netmask
, lifetime
);
397 log_link_warning(link
, "could not update IP address: %s",
399 link_enter_failed(link
);
406 static int dhcp_lease_acquired(sd_dhcp_client
*client
, Link
*link
) {
407 sd_dhcp_lease
*lease
;
408 struct in_addr address
;
409 struct in_addr netmask
;
410 struct in_addr gateway
;
412 uint32_t lifetime
= CACHE_INFO_INFINITY_LIFE_TIME
;
418 r
= sd_dhcp_client_get_lease(client
, &lease
);
420 return log_link_error_errno(link
, r
, "DHCP error: no lease: %m");
422 r
= sd_dhcp_lease_get_address(lease
, &address
);
424 return log_link_error_errno(link
, r
, "DHCP error: no address: %m");
426 r
= sd_dhcp_lease_get_netmask(lease
, &netmask
);
428 return log_link_error_errno(link
, r
, "DHCP error: no netmask: %m");
430 prefixlen
= in_addr_netmask_to_prefixlen(&netmask
);
432 r
= sd_dhcp_lease_get_router(lease
, &gateway
);
433 if (r
< 0 && r
!= -ENOENT
)
434 return log_link_error_errno(link
, r
, "DHCP error: could not get gateway: %m");
438 LOG_LINK_INTERFACE(link
),
439 LOG_LINK_MESSAGE(link
, "DHCPv4 address %u.%u.%u.%u/%u via %u.%u.%u.%u",
440 ADDRESS_FMT_VAL(address
),
442 ADDRESS_FMT_VAL(gateway
)),
443 "ADDRESS=%u.%u.%u.%u", ADDRESS_FMT_VAL(address
),
444 "PREFIXLEN=%u", prefixlen
,
445 "GATEWAY=%u.%u.%u.%u", ADDRESS_FMT_VAL(gateway
),
449 LOG_LINK_INTERFACE(link
),
450 LOG_LINK_MESSAGE(link
, "DHCPv4 address %u.%u.%u.%u/%u",
451 ADDRESS_FMT_VAL(address
),
453 "ADDRESS=%u.%u.%u.%u", ADDRESS_FMT_VAL(address
),
454 "PREFIXLEN=%u", prefixlen
,
457 link
->dhcp_lease
= lease
;
459 if (link
->network
->dhcp_mtu
) {
462 r
= sd_dhcp_lease_get_mtu(lease
, &mtu
);
464 r
= link_set_mtu(link
, mtu
);
466 log_link_error_errno(link
, r
, "Failed to set MTU to %" PRIu16
": %m", mtu
);
470 if (link
->network
->dhcp_hostname
) {
471 const char *hostname
= NULL
;
473 if (!link
->network
->hostname
)
474 r
= sd_dhcp_lease_get_hostname(lease
, &hostname
);
476 hostname
= link
->network
->hostname
;
478 if (r
>= 0 || hostname
) {
479 r
= link_set_hostname(link
, hostname
);
481 log_link_error_errno(link
, r
, "Failed to set transient hostname to '%s': %m", hostname
);
485 if (!link
->network
->dhcp_critical
) {
486 r
= sd_dhcp_lease_get_lifetime(link
->dhcp_lease
, &lifetime
);
488 log_link_warning_errno(link
, r
, "DHCP error: no lifetime: %m");
493 r
= dhcp4_update_address(link
, &address
, &netmask
, lifetime
);
495 log_link_warning_errno(link
, r
, "Could not update IP address: %m");
496 link_enter_failed(link
);
502 static void dhcp4_handler(sd_dhcp_client
*client
, int event
, void *userdata
) {
503 Link
*link
= userdata
;
507 assert(link
->network
);
508 assert(link
->manager
);
510 if (IN_SET(link
->state
, LINK_STATE_FAILED
, LINK_STATE_LINGER
))
514 case DHCP_EVENT_EXPIRED
:
515 case DHCP_EVENT_STOP
:
516 case DHCP_EVENT_IP_CHANGE
:
517 if (link
->network
->dhcp_critical
) {
519 "DHCPv4 connection considered system critical, ignoring request to reconfigure it.");
523 if (link
->dhcp_lease
) {
524 r
= dhcp_lease_lost(link
);
526 link_enter_failed(link
);
531 if (event
== DHCP_EVENT_IP_CHANGE
) {
532 r
= dhcp_lease_acquired(client
, link
);
534 link_enter_failed(link
);
540 case DHCP_EVENT_RENEW
:
541 r
= dhcp_lease_renew(client
, link
);
543 link_enter_failed(link
);
547 case DHCP_EVENT_IP_ACQUIRE
:
548 r
= dhcp_lease_acquired(client
, link
);
550 link_enter_failed(link
);
556 log_link_warning(link
,
557 "DHCP error: client failed: %s",
560 log_link_warning(link
,
561 "DHCP unknown event: %d",
569 int dhcp4_configure(Link
*link
) {
573 assert(link
->network
);
574 assert(link
->network
->dhcp
& ADDRESS_FAMILY_IPV4
);
576 r
= sd_dhcp_client_new(&link
->dhcp_client
);
580 r
= sd_dhcp_client_attach_event(link
->dhcp_client
, NULL
, 0);
584 r
= sd_dhcp_client_set_mac(link
->dhcp_client
,
585 (const uint8_t *) &link
->mac
,
586 sizeof (link
->mac
), ARPHRD_ETHER
);
590 r
= sd_dhcp_client_set_index(link
->dhcp_client
, link
->ifindex
);
594 r
= sd_dhcp_client_set_callback(link
->dhcp_client
, dhcp4_handler
, link
);
598 r
= sd_dhcp_client_set_request_broadcast(link
->dhcp_client
,
599 link
->network
->dhcp_broadcast
);
604 r
= sd_dhcp_client_set_mtu(link
->dhcp_client
, link
->mtu
);
609 if (link
->network
->dhcp_mtu
) {
610 r
= sd_dhcp_client_set_request_option(link
->dhcp_client
,
611 DHCP_OPTION_INTERFACE_MTU
);
616 if (link
->network
->dhcp_routes
) {
617 r
= sd_dhcp_client_set_request_option(link
->dhcp_client
,
618 DHCP_OPTION_STATIC_ROUTE
);
621 r
= sd_dhcp_client_set_request_option(link
->dhcp_client
,
622 DHCP_OPTION_CLASSLESS_STATIC_ROUTE
);
627 if (link
->network
->dhcp_sendhost
) {
628 _cleanup_free_
char *hostname
= NULL
;
629 const char *hn
= NULL
;
631 if (!link
->network
->hostname
) {
632 hostname
= gethostname_malloc();
638 hn
= link
->network
->hostname
;
640 if (!is_localhost(hn
)) {
641 r
= sd_dhcp_client_set_hostname(link
->dhcp_client
, hn
);
647 if (link
->network
->dhcp_vendor_class_identifier
) {
648 r
= sd_dhcp_client_set_vendor_class_identifier(link
->dhcp_client
,
649 link
->network
->dhcp_vendor_class_identifier
);
654 switch (link
->network
->dhcp_client_identifier
) {
655 case DHCP_CLIENT_ID_DUID
:
656 /* Library defaults to this. */
658 case DHCP_CLIENT_ID_MAC
:
659 r
= sd_dhcp_client_set_client_id(link
->dhcp_client
,
661 (const uint8_t *) &link
->mac
,
667 assert_not_reached("Unknown client identifier type.");